summaryrefslogtreecommitdiffstats
path: root/chromium/ui
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/ui
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ui')
-rw-r--r--chromium/ui/accessibility/BUILD.gn61
-rw-r--r--chromium/ui/accessibility/accessibility.gyp46
-rw-r--r--chromium/ui/accessibility/ax_enums.h124
-rw-r--r--chromium/ui/accessibility/ax_enums.idl356
-rw-r--r--chromium/ui/accessibility/ax_generated_tree_unittest.cc243
-rw-r--r--chromium/ui/accessibility/ax_node.cc13
-rw-r--r--chromium/ui/accessibility/ax_node.h15
-rw-r--r--chromium/ui/accessibility/ax_node_data.cc356
-rw-r--r--chromium/ui/accessibility/ax_node_data.h167
-rw-r--r--chromium/ui/accessibility/ax_serializable_tree.cc29
-rw-r--r--chromium/ui/accessibility/ax_serializable_tree.h2
-rw-r--r--chromium/ui/accessibility/ax_text_utils.cc88
-rw-r--r--chromium/ui/accessibility/ax_text_utils.h54
-rw-r--r--chromium/ui/accessibility/ax_tree.cc122
-rw-r--r--chromium/ui/accessibility/ax_tree.h78
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer.h149
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer_unittest.cc8
-rw-r--r--chromium/ui/accessibility/ax_tree_source.h44
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc142
-rw-r--r--chromium/ui/accessibility/ax_tree_update.cc27
-rw-r--r--chromium/ui/accessibility/ax_tree_update.h3
-rw-r--r--chromium/ui/accessibility/ax_view_state.cc27
-rw-r--r--chromium/ui/accessibility/ax_view_state.h81
-rw-r--r--chromium/ui/android/OWNERS1
-rw-r--r--chromium/ui/android/ui_android.gyp27
-rw-r--r--chromium/ui/app_list/DEPS15
-rw-r--r--chromium/ui/app_list/OWNERS4
-rw-r--r--chromium/ui/app_list/app_list.gyp111
-rw-r--r--chromium/ui/app_list/app_list_constants.cc48
-rw-r--r--chromium/ui/app_list/app_list_constants.h46
-rw-r--r--chromium/ui/app_list/app_list_export.h33
-rw-r--r--chromium/ui/app_list/app_list_folder_item.cc183
-rw-r--r--chromium/ui/app_list/app_list_folder_item.h67
-rw-r--r--chromium/ui/app_list/app_list_item_list.cc224
-rw-r--r--chromium/ui/app_list/app_list_item_list.h103
-rw-r--r--chromium/ui/app_list/app_list_item_list_observer.h34
-rw-r--r--chromium/ui/app_list/app_list_item_list_unittest.cc319
-rw-r--r--chromium/ui/app_list/app_list_item_model.cc99
-rw-r--r--chromium/ui/app_list/app_list_item_model.h102
-rw-r--r--chromium/ui/app_list/app_list_item_model_observer.h35
-rw-r--r--chromium/ui/app_list/app_list_menu.cc99
-rw-r--r--chromium/ui/app_list/app_list_menu.h51
-rw-r--r--chromium/ui/app_list/app_list_model.cc42
-rw-r--r--chromium/ui/app_list/app_list_model.h62
-rw-r--r--chromium/ui/app_list/app_list_model_observer.h23
-rw-r--r--chromium/ui/app_list/app_list_model_unittest.cc277
-rw-r--r--chromium/ui/app_list/app_list_switches.cc20
-rw-r--r--chromium/ui/app_list/app_list_switches.h20
-rw-r--r--chromium/ui/app_list/app_list_view_delegate.cc15
-rw-r--r--chromium/ui/app_list/app_list_view_delegate.h140
-rw-r--r--chromium/ui/app_list/app_list_view_delegate_observer.h24
-rw-r--r--chromium/ui/app_list/cocoa/app_list_pager_view.h43
-rw-r--r--chromium/ui/app_list/cocoa/app_list_pager_view.mm167
-rw-r--r--chromium/ui/app_list/cocoa/app_list_view_controller.h73
-rw-r--r--chromium/ui/app_list/cocoa/app_list_view_controller.mm354
-rw-r--r--chromium/ui/app_list/cocoa/app_list_view_controller_unittest.mm128
-rw-r--r--chromium/ui/app_list/cocoa/app_list_window_controller.h26
-rw-r--r--chromium/ui/app_list/cocoa/app_list_window_controller.mm69
-rw-r--r--chromium/ui/app_list/cocoa/app_list_window_controller_unittest.mm95
-rw-r--r--chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.h64
-rw-r--r--chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.mm263
-rw-r--r--chromium/ui/app_list/cocoa/apps_grid_controller.h122
-rw-r--r--chromium/ui/app_list/cocoa/apps_grid_controller.mm675
-rw-r--r--chromium/ui/app_list/cocoa/apps_grid_controller_unittest.mm989
-rw-r--r--chromium/ui/app_list/cocoa/apps_grid_view_item.h55
-rw-r--r--chromium/ui/app_list/cocoa/apps_grid_view_item.mm468
-rw-r--r--chromium/ui/app_list/cocoa/apps_pagination_model_observer.h26
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_box_controller.h67
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_box_controller.mm396
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_box_controller_unittest.mm265
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_results_controller.h59
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_results_controller.mm463
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_results_controller_unittest.mm316
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_results_model_bridge.h50
-rw-r--r--chromium/ui/app_list/cocoa/apps_search_results_model_bridge.mm137
-rw-r--r--chromium/ui/app_list/cocoa/item_drag_controller.h44
-rw-r--r--chromium/ui/app_list/cocoa/item_drag_controller.mm184
-rw-r--r--chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h30
-rw-r--r--chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm99
-rw-r--r--chromium/ui/app_list/cocoa/signin_view_controller.h32
-rw-r--r--chromium/ui/app_list/cocoa/signin_view_controller.mm198
-rw-r--r--chromium/ui/app_list/cocoa/signin_view_controller_unittest.mm115
-rw-r--r--chromium/ui/app_list/pagination_model.cc272
-rw-r--r--chromium/ui/app_list/pagination_model.h144
-rw-r--r--chromium/ui/app_list/pagination_model_observer.h32
-rw-r--r--chromium/ui/app_list/pagination_model_unittest.cc434
-rw-r--r--chromium/ui/app_list/search_box_model.cc80
-rw-r--r--chromium/ui/app_list/search_box_model.h77
-rw-r--r--chromium/ui/app_list/search_box_model_observer.h36
-rw-r--r--chromium/ui/app_list/search_result.cc85
-rw-r--r--chromium/ui/app_list/search_result.h134
-rw-r--r--chromium/ui/app_list/search_result_observer.h38
-rw-r--r--chromium/ui/app_list/signin_delegate.cc13
-rw-r--r--chromium/ui/app_list/signin_delegate.h36
-rw-r--r--chromium/ui/app_list/speech_ui_model.cc54
-rw-r--r--chromium/ui/app_list/speech_ui_model.h47
-rw-r--r--chromium/ui/app_list/speech_ui_model_observer.h39
-rw-r--r--chromium/ui/app_list/views/DEPS3
-rw-r--r--chromium/ui/app_list/views/app_list_background.cc79
-rw-r--r--chromium/ui/app_list/views/app_list_background.h39
-rw-r--r--chromium/ui/app_list/views/app_list_drag_and_drop_host.h63
-rw-r--r--chromium/ui/app_list/views/app_list_folder_view.cc103
-rw-r--r--chromium/ui/app_list/views/app_list_folder_view.h71
-rw-r--r--chromium/ui/app_list/views/app_list_item_view.cc466
-rw-r--r--chromium/ui/app_list/views/app_list_item_view.h142
-rw-r--r--chromium/ui/app_list/views/app_list_main_view.cc258
-rw-r--r--chromium/ui/app_list/views/app_list_main_view.h116
-rw-r--r--chromium/ui/app_list/views/app_list_main_view_unittest.cc90
-rw-r--r--chromium/ui/app_list/views/app_list_menu_views.cc44
-rw-r--r--chromium/ui/app_list/views/app_list_menu_views.h44
-rw-r--r--chromium/ui/app_list/views/app_list_view.cc472
-rw-r--r--chromium/ui/app_list/views/app_list_view.h154
-rw-r--r--chromium/ui/app_list/views/app_list_view_observer.h24
-rw-r--r--chromium/ui/app_list/views/apps_container_view.cc100
-rw-r--r--chromium/ui/app_list/views/apps_container_view.h67
-rw-r--r--chromium/ui/app_list/views/apps_grid_view.cc1671
-rw-r--r--chromium/ui/app_list/views/apps_grid_view.h421
-rw-r--r--chromium/ui/app_list/views/apps_grid_view_delegate.h39
-rw-r--r--chromium/ui/app_list/views/apps_grid_view_unittest.cc464
-rw-r--r--chromium/ui/app_list/views/cached_label.cc35
-rw-r--r--chromium/ui/app_list/views/cached_label.h41
-rw-r--r--chromium/ui/app_list/views/contents_view.cc263
-rw-r--r--chromium/ui/app_list/views/contents_view.h98
-rw-r--r--chromium/ui/app_list/views/folder_header_view.cc176
-rw-r--r--chromium/ui/app_list/views/folder_header_view.h76
-rw-r--r--chromium/ui/app_list/views/folder_header_view_delegate.h27
-rw-r--r--chromium/ui/app_list/views/page_switcher.cc267
-rw-r--r--chromium/ui/app_list/views/page_switcher.h61
-rw-r--r--chromium/ui/app_list/views/progress_bar_view.cc62
-rw-r--r--chromium/ui/app_list/views/progress_bar_view.h37
-rw-r--r--chromium/ui/app_list/views/pulsing_block_view.cc106
-rw-r--r--chromium/ui/app_list/views/pulsing_block_view.h40
-rw-r--r--chromium/ui/app_list/views/search_box_view.cc243
-rw-r--r--chromium/ui/app_list/views/search_box_view.h105
-rw-r--r--chromium/ui/app_list/views/search_box_view_delegate.h25
-rw-r--r--chromium/ui/app_list/views/search_result_actions_view.cc106
-rw-r--r--chromium/ui/app_list/views/search_result_actions_view.h51
-rw-r--r--chromium/ui/app_list/views/search_result_actions_view_delegate.h22
-rw-r--r--chromium/ui/app_list/views/search_result_list_view.cc188
-rw-r--r--chromium/ui/app_list/views/search_result_list_view.h78
-rw-r--r--chromium/ui/app_list/views/search_result_list_view_delegate.h40
-rw-r--r--chromium/ui/app_list/views/search_result_view.cc356
-rw-r--r--chromium/ui/app_list/views/search_result_view.h114
-rw-r--r--chromium/ui/app_list/views/search_result_view_delegate.h36
-rw-r--r--chromium/ui/app_list/views/signin_view.cc135
-rw-r--r--chromium/ui/app_list/views/signin_view.h52
-rw-r--r--chromium/ui/app_list/views/speech_view.cc227
-rw-r--r--chromium/ui/app_list/views/speech_view.h64
-rw-r--r--chromium/ui/aura/BUILD.gn303
-rw-r--r--chromium/ui/aura/DEPS3
-rw-r--r--chromium/ui/aura/aura.gyp150
-rw-r--r--chromium/ui/aura/aura_export.h6
-rw-r--r--chromium/ui/aura/bench/DEPS2
-rw-r--r--chromium/ui/aura/bench/bench_main.cc157
-rw-r--r--chromium/ui/aura/client/activation_change_observer.cc29
-rw-r--r--chromium/ui/aura/client/activation_change_observer.h45
-rw-r--r--chromium/ui/aura/client/activation_client.cc38
-rw-r--r--chromium/ui/aura/client/activation_client.h77
-rw-r--r--chromium/ui/aura/client/activation_delegate.cc27
-rw-r--r--chromium/ui/aura/client/activation_delegate.h37
-rw-r--r--chromium/ui/aura/client/animation_host.cc32
-rw-r--r--chromium/ui/aura/client/animation_host.h48
-rw-r--r--chromium/ui/aura/client/capture_client.cc2
-rw-r--r--chromium/ui/aura/client/cursor_client.h13
-rw-r--r--chromium/ui/aura/client/default_activation_client.cc128
-rw-r--r--chromium/ui/aura/client/default_activation_client.h69
-rw-r--r--chromium/ui/aura/client/default_capture_client.cc5
-rw-r--r--chromium/ui/aura/client/dispatcher_client.cc29
-rw-r--r--chromium/ui/aura/client/dispatcher_client.h31
-rw-r--r--chromium/ui/aura/client/drag_drop_client.cc31
-rw-r--r--chromium/ui/aura/client/drag_drop_client.h62
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.cc27
-rw-r--r--chromium/ui/aura/client/drag_drop_delegate.h51
-rw-r--r--chromium/ui/aura/client/event_client.cc2
-rw-r--r--chromium/ui/aura/client/focus_client.cc2
-rw-r--r--chromium/ui/aura/client/screen_position_client.cc2
-rw-r--r--chromium/ui/aura/client/tooltip_client.cc42
-rw-r--r--chromium/ui/aura/client/tooltip_client.h38
-rw-r--r--chromium/ui/aura/client/user_action_client.cc30
-rw-r--r--chromium/ui/aura/client/user_action_client.h37
-rw-r--r--chromium/ui/aura/client/visibility_client.cc2
-rw-r--r--chromium/ui/aura/client/window_move_client.cc28
-rw-r--r--chromium/ui/aura/client/window_move_client.h56
-rw-r--r--chromium/ui/aura/client/window_stacking_client.cc3
-rw-r--r--chromium/ui/aura/client/window_stacking_client.h19
-rw-r--r--chromium/ui/aura/client/window_tree_client.cc2
-rw-r--r--chromium/ui/aura/client/window_types.h36
-rw-r--r--chromium/ui/aura/demo/DEPS3
-rw-r--r--chromium/ui/aura/demo/demo_main.cc71
-rw-r--r--chromium/ui/aura/device_list_updater_aurax11.cc32
-rw-r--r--chromium/ui/aura/device_list_updater_aurax11.h32
-rw-r--r--chromium/ui/aura/dispatcher_win.cc33
-rw-r--r--chromium/ui/aura/env.cc114
-rw-r--r--chromium/ui/aura/env.h70
-rw-r--r--chromium/ui/aura/env_observer.h10
-rw-r--r--chromium/ui/aura/gestures/gesture_recognizer_unittest.cc1584
-rw-r--r--chromium/ui/aura/remote_root_window_host_win.cc732
-rw-r--r--chromium/ui/aura/remote_root_window_host_win.h298
-rw-r--r--chromium/ui/aura/remote_window_tree_host_win.cc525
-rw-r--r--chromium/ui/aura/remote_window_tree_host_win.h194
-rw-r--r--chromium/ui/aura/root_window.cc1172
-rw-r--r--chromium/ui/aura/root_window.h401
-rw-r--r--chromium/ui/aura/root_window_host_ozone.cc133
-rw-r--r--chromium/ui/aura/root_window_host_ozone.h59
-rw-r--r--chromium/ui/aura/root_window_host_win.cc309
-rw-r--r--chromium/ui/aura/root_window_host_win.h96
-rw-r--r--chromium/ui/aura/root_window_host_x11.cc1060
-rw-r--r--chromium/ui/aura/root_window_host_x11.h152
-rw-r--r--chromium/ui/aura/root_window_host_x11_unittest.cc290
-rw-r--r--chromium/ui/aura/root_window_observer.h41
-rw-r--r--chromium/ui/aura/root_window_transformer.h45
-rw-r--r--chromium/ui/aura/root_window_unittest.cc1530
-rw-r--r--chromium/ui/aura/scoped_window_targeter.cc29
-rw-r--r--chromium/ui/aura/scoped_window_targeter.h46
-rw-r--r--chromium/ui/aura/window.cc566
-rw-r--r--chromium/ui/aura/window.h161
-rw-r--r--chromium/ui/aura/window_delegate.h15
-rw-r--r--chromium/ui/aura/window_event_dispatcher.cc861
-rw-r--r--chromium/ui/aura/window_event_dispatcher.h265
-rw-r--r--chromium/ui/aura/window_event_dispatcher_unittest.cc2219
-rw-r--r--chromium/ui/aura/window_observer.cc31
-rw-r--r--chromium/ui/aura/window_observer.h34
-rw-r--r--chromium/ui/aura/window_targeter.cc93
-rw-r--r--chromium/ui/aura/window_targeter.h17
-rw-r--r--chromium/ui/aura/window_targeter_unittest.cc125
-rw-r--r--chromium/ui/aura/window_tree_host.cc256
-rw-r--r--chromium/ui/aura/window_tree_host.h203
-rw-r--r--chromium/ui/aura/window_tree_host_delegate.h67
-rw-r--r--chromium/ui/aura/window_tree_host_mac.h61
-rw-r--r--chromium/ui/aura/window_tree_host_mac.mm114
-rw-r--r--chromium/ui/aura/window_tree_host_observer.h36
-rw-r--r--chromium/ui/aura/window_tree_host_ozone.cc118
-rw-r--r--chromium/ui/aura/window_tree_host_ozone.h58
-rw-r--r--chromium/ui/aura/window_tree_host_win.cc238
-rw-r--r--chromium/ui/aura/window_tree_host_win.h93
-rw-r--r--chromium/ui/aura/window_tree_host_x11.cc744
-rw-r--r--chromium/ui/aura/window_tree_host_x11.h118
-rw-r--r--chromium/ui/aura/window_unittest.cc807
-rw-r--r--chromium/ui/base/BUILD.gn556
-rw-r--r--chromium/ui/base/DEPS1
-rw-r--r--chromium/ui/base/accelerators/accelerator.cc48
-rw-r--r--chromium/ui/base/accelerators/accelerator.h11
-rw-r--r--chromium/ui/base/accelerators/accelerator_manager.h4
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h10
-rw-r--r--chromium/ui/base/accelerators/platform_accelerator.h4
-rw-r--r--chromium/ui/base/accelerators/platform_accelerator_cocoa.h5
-rw-r--r--chromium/ui/base/accelerators/platform_accelerator_gtk.cc93
-rw-r--r--chromium/ui/base/accelerators/platform_accelerator_gtk.h48
-rw-r--r--chromium/ui/base/accessibility/OWNERS1
-rw-r--r--chromium/ui/base/accessibility/accessibility_types.h110
-rw-r--r--chromium/ui/base/accessibility/accessible_text_utils.cc92
-rw-r--r--chromium/ui/base/accessibility/accessible_text_utils.h53
-rw-r--r--chromium/ui/base/accessibility/accessible_view_state.cc19
-rw-r--r--chromium/ui/base/accessibility/accessible_view_state.h73
-rw-r--r--chromium/ui/base/android/view_android.cc2
-rw-r--r--chromium/ui/base/android/view_android.h6
-rw-r--r--chromium/ui/base/android/window_android.cc62
-rw-r--r--chromium/ui/base/android/window_android.h26
-rw-r--r--chromium/ui/base/android/window_android_compositor.h32
-rw-r--r--chromium/ui/base/android/window_android_observer.h7
-rw-r--r--chromium/ui/base/base_window.h2
-rw-r--r--chromium/ui/base/clipboard/clipboard.cc2
-rw-r--r--chromium/ui/base/clipboard/clipboard.h80
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.cc16
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.cc56
-rw-r--r--chromium/ui/base/clipboard/clipboard_aurax11.cc182
-rw-r--r--chromium/ui/base/clipboard/clipboard_gtk.cc676
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.mm32
-rw-r--r--chromium/ui/base/clipboard/clipboard_types.h3
-rw-r--r--chromium/ui/base/clipboard/clipboard_unittest.cc140
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.cc55
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.h24
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.cc54
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper.cc2
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper.h28
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper_linux.cc1
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper_mac.mm4
-rw-r--r--chromium/ui/base/clipboard/custom_data_helper_unittest.cc40
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.cc10
-rw-r--r--chromium/ui/base/clipboard/scoped_clipboard_writer.h4
-rw-r--r--chromium/ui/base/cocoa/appkit_utils.h17
-rw-r--r--chromium/ui/base/cocoa/base_view.h8
-rw-r--r--chromium/ui/base/cocoa/base_view_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/cocoa_base_utils.h31
-rw-r--r--chromium/ui/base/cocoa/cocoa_base_utils.mm22
-rw-r--r--chromium/ui/base/cocoa/cocoa_base_utils_unittest.mm68
-rw-r--r--chromium/ui/base/cocoa/cocoa_event_utils.h42
-rw-r--r--chromium/ui/base/cocoa/cocoa_event_utils.mm70
-rw-r--r--chromium/ui/base/cocoa/cocoa_event_utils_unittest.mm128
-rw-r--r--chromium/ui/base/cocoa/controls/blue_label_button.h4
-rw-r--r--chromium/ui/base/cocoa/controls/blue_label_button.mm39
-rw-r--r--chromium/ui/base/cocoa/controls/blue_label_button_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/controls/hover_image_menu_button.h4
-rw-r--r--chromium/ui/base/cocoa/controls/hover_image_menu_button_cell.h4
-rw-r--r--chromium/ui/base/cocoa/controls/hover_image_menu_button_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/controls/hyperlink_button_cell.h4
-rw-r--r--chromium/ui/base/cocoa/controls/hyperlink_button_cell_unittest.mm4
-rw-r--r--chromium/ui/base/cocoa/events_mac_unittest.mm299
-rw-r--r--chromium/ui/base/cocoa/find_pasteboard.h8
-rw-r--r--chromium/ui/base/cocoa/find_pasteboard.mm2
-rw-r--r--chromium/ui/base/cocoa/flipped_view.h4
-rw-r--r--chromium/ui/base/cocoa/focus_tracker.h4
-rw-r--r--chromium/ui/base/cocoa/focus_tracker_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/focus_window_set.h15
-rw-r--r--chromium/ui/base/cocoa/focus_window_set.mm85
-rw-r--r--chromium/ui/base/cocoa/fullscreen_window_manager.h4
-rw-r--r--chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/hover_button.h4
-rw-r--r--chromium/ui/base/cocoa/hover_image_button.h4
-rw-r--r--chromium/ui/base/cocoa/hover_image_button_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/menu_controller.h8
-rw-r--r--chromium/ui/base/cocoa/menu_controller.mm24
-rw-r--r--chromium/ui/base/cocoa/menu_controller_unittest.mm44
-rw-r--r--chromium/ui/base/cocoa/nib_loading.h4
-rw-r--r--chromium/ui/base/cocoa/nsgraphics_context_additions.mm11
-rw-r--r--chromium/ui/base/cocoa/nsgraphics_context_additions_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/tracking_area.h6
-rw-r--r--chromium/ui/base/cocoa/tracking_area_unittest.mm2
-rw-r--r--chromium/ui/base/cocoa/underlay_opengl_hosting_window.h4
-rw-r--r--chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm16
-rw-r--r--chromium/ui/base/cocoa/window_size_constants.h4
-rw-r--r--chromium/ui/base/cursor/DEPS3
-rw-r--r--chromium/ui/base/cursor/cursor.h4
-rw-r--r--chromium/ui/base/cursor/cursor_android.cc19
-rw-r--r--chromium/ui/base/cursor/cursor_loader.h22
-rw-r--r--chromium/ui/base/cursor/cursor_loader_null.cc25
-rw-r--r--chromium/ui/base/cursor/cursor_loader_null.h36
-rw-r--r--chromium/ui/base/cursor/cursor_loader_ozone.cc68
-rw-r--r--chromium/ui/base/cursor/cursor_loader_ozone.h41
-rw-r--r--chromium/ui/base/cursor/cursor_loader_win.cc16
-rw-r--r--chromium/ui/base/cursor/cursor_loader_win.h6
-rw-r--r--chromium/ui/base/cursor/cursor_loader_x11.cc63
-rw-r--r--chromium/ui/base/cursor/cursor_loader_x11.h15
-rw-r--r--chromium/ui/base/cursor/cursor_loader_x11_unittest.cc2
-rw-r--r--chromium/ui/base/cursor/cursor_null.cc15
-rw-r--r--chromium/ui/base/cursor/cursor_ozone.cc21
-rw-r--r--chromium/ui/base/cursor/cursor_util.cc60
-rw-r--r--chromium/ui/base/cursor/cursor_util.h27
-rw-r--r--chromium/ui/base/cursor/cursors_aura.h27
-rw-r--r--chromium/ui/base/cursor/image_cursors.cc150
-rw-r--r--chromium/ui/base/cursor/image_cursors.h52
-rw-r--r--chromium/ui/base/cursor/ozone/OWNERS2
-rw-r--r--chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc73
-rw-r--r--chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h75
-rw-r--r--chromium/ui/base/default_theme_provider.cc18
-rw-r--r--chromium/ui/base/default_theme_provider.h7
-rw-r--r--chromium/ui/base/device_form_factor.h4
-rw-r--r--chromium/ui/base/device_form_factor_android.cc17
-rw-r--r--chromium/ui/base/device_form_factor_android.h18
-rw-r--r--chromium/ui/base/dragdrop/cocoa_dnd_util.h14
-rw-r--r--chromium/ui/base/dragdrop/download_file_interface.h6
-rw-r--r--chromium/ui/base/dragdrop/drag_drop_types.h8
-rw-r--r--chromium/ui/base/dragdrop/drag_source_win.h4
-rw-r--r--chromium/ui/base/dragdrop/drag_utils.cc50
-rw-r--r--chromium/ui/base/dragdrop/drag_utils.h40
-rw-r--r--chromium/ui/base/dragdrop/drag_utils_aura.cc1
-rw-r--r--chromium/ui/base/dragdrop/drag_utils_mac.mm23
-rw-r--r--chromium/ui/base/dragdrop/drag_utils_win.cc15
-rw-r--r--chromium/ui/base/dragdrop/drop_target_event.h2
-rw-r--r--chromium/ui/base/dragdrop/drop_target_win.h4
-rw-r--r--chromium/ui/base/dragdrop/file_info.cc17
-rw-r--r--chromium/ui/base/dragdrop/file_info.h25
-rw-r--r--chromium/ui/base/dragdrop/gtk_dnd_util.cc275
-rw-r--r--chromium/ui/base/dragdrop/gtk_dnd_util.h92
-rw-r--r--chromium/ui/base/dragdrop/gtk_dnd_util_unittest.cc81
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.cc56
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.h57
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc22
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h15
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc249
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h38
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc93
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h50
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm116
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc58
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.h20
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_unittest.cc28
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc24
-rw-r--r--chromium/ui/base/gtk/OWNERS2
-rw-r--r--chromium/ui/base/gtk/event_synthesis_gtk.cc90
-rw-r--r--chromium/ui/base/gtk/event_synthesis_gtk.h37
-rw-r--r--chromium/ui/base/gtk/focus_store_gtk.cc55
-rw-r--r--chromium/ui/base/gtk/focus_store_gtk.h46
-rw-r--r--chromium/ui/base/gtk/g_object_destructor_filo.cc89
-rw-r--r--chromium/ui/base/gtk/g_object_destructor_filo.h91
-rw-r--r--chromium/ui/base/gtk/gtk_expanded_container.cc195
-rw-r--r--chromium/ui/base/gtk/gtk_expanded_container.h74
-rw-r--r--chromium/ui/base/gtk/gtk_expanded_container_unittest.cc164
-rw-r--r--chromium/ui/base/gtk/gtk_floating_container.cc322
-rw-r--r--chromium/ui/base/gtk/gtk_floating_container.h89
-rw-r--r--chromium/ui/base/gtk/gtk_hig_constants.h54
-rw-r--r--chromium/ui/base/gtk/gtk_screen_util.cc58
-rw-r--r--chromium/ui/base/gtk/gtk_screen_util.h34
-rw-r--r--chromium/ui/base/gtk/gtk_signal.h68
-rw-r--r--chromium/ui/base/gtk/gtk_signal_registrar.cc98
-rw-r--r--chromium/ui/base/gtk/gtk_signal_registrar.h75
-rw-r--r--chromium/ui/base/gtk/gtk_windowing.cc48
-rw-r--r--chromium/ui/base/gtk/gtk_windowing.h19
-rw-r--r--chromium/ui/base/gtk/owned_widget_gtk.cc45
-rw-r--r--chromium/ui/base/gtk/owned_widget_gtk.h95
-rw-r--r--chromium/ui/base/gtk/scoped_region.cc41
-rw-r--r--chromium/ui/base/gtk/scoped_region.h40
-rw-r--r--chromium/ui/base/ime/DEPS2
-rw-r--r--chromium/ui/base/ime/OWNERS13
-rw-r--r--chromium/ui/base/ime/candidate_window.cc103
-rw-r--r--chromium/ui/base/ime/candidate_window.h131
-rw-r--r--chromium/ui/base/ime/candidate_window_unittest.cc262
-rw-r--r--chromium/ui/base/ime/chromeos/character_composer.cc46
-rw-r--r--chromium/ui/base/ime/chromeos/character_composer.h14
-rw-r--r--chromium/ui/base/ime/chromeos/character_composer_unittest.cc100
-rw-r--r--chromium/ui/base/ime/chromeos/ibus_bridge.cc128
-rw-r--r--chromium/ui/base/ime/chromeos/ibus_bridge.h211
-rw-r--r--chromium/ui/base/ime/chromeos/ime_bridge.cc107
-rw-r--r--chromium/ui/base/ime/chromeos/ime_bridge.h191
-rw-r--r--chromium/ui/base/ime/chromeos/ime_keymap.cc180
-rw-r--r--chromium/ui/base/ime/chromeos/ime_keymap.h20
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc21
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h33
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_engine_handler.cc7
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_engine_handler.h6
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.cc15
-rw-r--r--chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.h22
-rw-r--r--chromium/ui/base/ime/composition_text.h4
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango.cc13
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango.h4
-rw-r--r--chromium/ui/base/ime/composition_text_util_pango_unittest.cc113
-rw-r--r--chromium/ui/base/ime/composition_underline.h44
-rw-r--r--chromium/ui/base/ime/dummy_input_method.cc7
-rw-r--r--chromium/ui/base/ime/dummy_input_method.h3
-rw-r--r--chromium/ui/base/ime/dummy_input_method_delegate.cc9
-rw-r--r--chromium/ui/base/ime/dummy_input_method_delegate.h14
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.cc28
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.h20
-rw-r--r--chromium/ui/base/ime/ime.gypi51
-rw-r--r--chromium/ui/base/ime/ime_test_support.gypi10
-rw-r--r--chromium/ui/base/ime/ime_unittests.gypi6
-rw-r--r--chromium/ui/base/ime/infolist_entry.cc22
-rw-r--r--chromium/ui/base/ime/infolist_entry.h26
-rw-r--r--chromium/ui/base/ime/input_method.h12
-rw-r--r--chromium/ui/base/ime/input_method_auralinux.cc96
-rw-r--r--chromium/ui/base/ime/input_method_auralinux.h34
-rw-r--r--chromium/ui/base/ime/input_method_base.cc30
-rw-r--r--chromium/ui/base/ime/input_method_base.h5
-rw-r--r--chromium/ui/base/ime/input_method_base_unittest.cc45
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.cc661
-rw-r--r--chromium/ui/base/ime/input_method_chromeos.h158
-rw-r--r--chromium/ui/base/ime/input_method_chromeos_unittest.cc1071
-rw-r--r--chromium/ui/base/ime/input_method_delegate.h18
-rw-r--r--chromium/ui/base/ime/input_method_factory.cc107
-rw-r--r--chromium/ui/base/ime/input_method_factory.h93
-rw-r--r--chromium/ui/base/ime/input_method_ibus.cc665
-rw-r--r--chromium/ui/base/ime/input_method_ibus.h170
-rw-r--r--chromium/ui/base/ime/input_method_ibus_unittest.cc1027
-rw-r--r--chromium/ui/base/ime/input_method_imm32.cc299
-rw-r--r--chromium/ui/base/ime/input_method_imm32.h87
-rw-r--r--chromium/ui/base/ime/input_method_initializer.cc66
-rw-r--r--chromium/ui/base/ime/input_method_initializer.h10
-rw-r--r--chromium/ui/base/ime/input_method_mac.h38
-rw-r--r--chromium/ui/base/ime/input_method_mac.mm49
-rw-r--r--chromium/ui/base/ime/input_method_minimal.cc4
-rw-r--r--chromium/ui/base/ime/input_method_minimal.h3
-rw-r--r--chromium/ui/base/ime/input_method_observer.h8
-rw-r--r--chromium/ui/base/ime/input_method_tsf.cc158
-rw-r--r--chromium/ui/base/ime/input_method_tsf.h58
-rw-r--r--chromium/ui/base/ime/input_method_win.cc375
-rw-r--r--chromium/ui/base/ime/input_method_win.h87
-rw-r--r--chromium/ui/base/ime/linux/fake_input_method_context.cc5
-rw-r--r--chromium/ui/base/ime/linux/fake_input_method_context.h1
-rw-r--r--chromium/ui/base/ime/linux/linux_input_method_context.h10
-rw-r--r--chromium/ui/base/ime/linux/linux_input_method_context_factory.h4
-rw-r--r--chromium/ui/base/ime/mock_input_method.cc17
-rw-r--r--chromium/ui/base/ime/mock_input_method.h6
-rw-r--r--chromium/ui/base/ime/remote_input_method_delegate_win.h4
-rw-r--r--chromium/ui/base/ime/remote_input_method_win.cc60
-rw-r--r--chromium/ui/base/ime/remote_input_method_win.h13
-rw-r--r--chromium/ui/base/ime/remote_input_method_win_unittest.cc106
-rw-r--r--chromium/ui/base/ime/text_input_client.h25
-rw-r--r--chromium/ui/base/ime/text_input_focus_manager.cc41
-rw-r--r--chromium/ui/base/ime/text_input_focus_manager.h47
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.cc35
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.h16
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.cc83
-rw-r--r--chromium/ui/base/ime/win/mock_tsf_bridge.h100
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc558
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.h97
-rw-r--r--chromium/ui/base/ime/win/tsf_event_router.cc307
-rw-r--r--chromium/ui/base/ime/win/tsf_event_router.h81
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.cc4
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.h13
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc923
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.h297
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc1302
-rw-r--r--chromium/ui/base/l10n/formatter.cc327
-rw-r--r--chromium/ui/base/l10n/formatter.h114
-rw-r--r--chromium/ui/base/l10n/l10n_font_util.h14
-rw-r--r--chromium/ui/base/l10n/l10n_util.cc31
-rw-r--r--chromium/ui/base/l10n/l10n_util.h139
-rw-r--r--chromium/ui/base/l10n/l10n_util_android.cc25
-rw-r--r--chromium/ui/base/l10n/l10n_util_android.h13
-rw-r--r--chromium/ui/base/l10n/l10n_util_collator.h8
-rw-r--r--chromium/ui/base/l10n/l10n_util_mac.h75
-rw-r--r--chromium/ui/base/l10n/l10n_util_mac.mm52
-rw-r--r--chromium/ui/base/l10n/l10n_util_mac_unittest.mm2
-rw-r--r--chromium/ui/base/l10n/l10n_util_unittest.cc32
-rw-r--r--chromium/ui/base/l10n/l10n_util_win.cc15
-rw-r--r--chromium/ui/base/l10n/l10n_util_win.h21
-rw-r--r--chromium/ui/base/l10n/time_format.cc396
-rw-r--r--chromium/ui/base/l10n/time_format.h72
-rw-r--r--chromium/ui/base/l10n/time_format_unittest.cc352
-rw-r--r--chromium/ui/base/layout.cc78
-rw-r--r--chromium/ui/base/layout.h41
-rw-r--r--chromium/ui/base/layout_mac.mm4
-rw-r--r--chromium/ui/base/layout_unittest.cc21
-rw-r--r--chromium/ui/base/models/button_menu_item_model.h6
-rw-r--r--chromium/ui/base/models/combobox_model.h4
-rw-r--r--chromium/ui/base/models/combobox_model_observer.h10
-rw-r--r--chromium/ui/base/models/dialog_model.h4
-rw-r--r--chromium/ui/base/models/list_model_observer.h4
-rw-r--r--chromium/ui/base/models/list_selection_model.h4
-rw-r--r--chromium/ui/base/models/menu_model.cc2
-rw-r--r--chromium/ui/base/models/menu_model.h12
-rw-r--r--chromium/ui/base/models/simple_combobox_model.cc33
-rw-r--r--chromium/ui/base/models/simple_combobox_model.h35
-rw-r--r--chromium/ui/base/models/simple_menu_model.h9
-rw-r--r--chromium/ui/base/models/table_model.h6
-rw-r--r--chromium/ui/base/models/table_model_observer.h4
-rw-r--r--chromium/ui/base/models/tree_model.h6
-rw-r--r--chromium/ui/base/models/tree_node_model.h2
-rw-r--r--chromium/ui/base/models/tree_node_model_unittest.cc2
-rw-r--r--chromium/ui/base/nine_image_painter_factory.cc32
-rw-r--r--chromium/ui/base/nine_image_painter_factory.h40
-rw-r--r--chromium/ui/base/resource/data_pack.cc28
-rw-r--r--chromium/ui/base/resource/data_pack.h8
-rw-r--r--chromium/ui/base/resource/data_pack_literal.cc16
-rw-r--r--chromium/ui/base/resource/data_pack_unittest.cc55
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc163
-rw-r--r--chromium/ui/base/resource/resource_bundle.h19
-rw-r--r--chromium/ui/base/resource/resource_bundle_auralinux.cc2
-rw-r--r--chromium/ui/base/resource/resource_bundle_gtk.cc112
-rw-r--r--chromium/ui/base/resource/resource_bundle_ios.mm10
-rw-r--r--chromium/ui/base/resource/resource_bundle_unittest.cc64
-rw-r--r--chromium/ui/base/resource/resource_bundle_win.cc40
-rw-r--r--chromium/ui/base/resource/resource_bundle_win.h6
-rw-r--r--chromium/ui/base/resource/resource_data_dll_win.cc3
-rw-r--r--chromium/ui/base/resource/resource_handle.h4
-rw-r--r--chromium/ui/base/strings/app_locale_settings.grd263
-rw-r--r--chromium/ui/base/strings/app_locale_settings_am.xtb8
-rw-r--r--chromium/ui/base/strings/app_locale_settings_ar.xtb9
-rw-r--r--chromium/ui/base/strings/app_locale_settings_bn.xtb20
-rw-r--r--chromium/ui/base/strings/app_locale_settings_hi.xtb11
-rw-r--r--chromium/ui/base/strings/app_locale_settings_ja.xtb22
-rw-r--r--chromium/ui/base/strings/app_locale_settings_kn.xtb13
-rw-r--r--chromium/ui/base/strings/app_locale_settings_ko.xtb19
-rw-r--r--chromium/ui/base/strings/app_locale_settings_ml.xtb19
-rw-r--r--chromium/ui/base/strings/app_locale_settings_mr.xtb11
-rw-r--r--chromium/ui/base/strings/app_locale_settings_ta.xtb8
-rw-r--r--chromium/ui/base/strings/app_locale_settings_te.xtb13
-rw-r--r--chromium/ui/base/strings/app_locale_settings_th.xtb16
-rw-r--r--chromium/ui/base/strings/app_locale_settings_zh-CN.xtb19
-rw-r--r--chromium/ui/base/strings/app_locale_settings_zh-TW.xtb19
-rw-r--r--chromium/ui/base/strings/ui_strings.grd1616
-rw-r--r--chromium/ui/base/strings/ui_strings.gyp89
-rw-r--r--chromium/ui/base/strings/ui_strings_am.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ar.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_bg.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_bn.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ca.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_cs.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_da.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_de.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_el.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_en-GB.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_es-419.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_es.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_et.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_fa.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_fi.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_fil.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_fr.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_gu.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_hi.xtb194
-rw-r--r--chromium/ui/base/strings/ui_strings_hr.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_hu.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_id.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_it.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_iw.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ja.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_kn.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ko.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_lt.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_lv.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ml.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_mr.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ms.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_nl.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_no.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_pl.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_pt-BR.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_pt-PT.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ro.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ru.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_sk.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_sl.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_sr.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_sv.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_sw.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_ta.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_te.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_th.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_tr.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_uk.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_vi.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_zh-CN.xtb192
-rw-r--r--chromium/ui/base/strings/ui_strings_zh-TW.xtb192
-rw-r--r--chromium/ui/base/text/bytes_formatting.h14
-rw-r--r--chromium/ui/base/text/bytes_formatting_unittest.cc4
-rw-r--r--chromium/ui/base/theme_provider.h23
-rw-r--r--chromium/ui/base/touch/touch_device.h20
-rw-r--r--chromium/ui/base/touch/touch_device_android.cc20
-rw-r--r--chromium/ui/base/touch/touch_editing_controller.h24
-rw-r--r--chromium/ui/base/touch/touch_enabled.h4
-rw-r--r--chromium/ui/base/ui_base.gyp644
-rw-r--r--chromium/ui/base/ui_base_export.h37
-rw-r--r--chromium/ui/base/ui_base_paths.cc16
-rw-r--r--chromium/ui/base/ui_base_paths.h12
-rw-r--r--chromium/ui/base/ui_base_switches.cc50
-rw-r--r--chromium/ui/base/ui_base_switches.h35
-rw-r--r--chromium/ui/base/ui_base_switches_util.cc7
-rw-r--r--chromium/ui/base/ui_base_switches_util.h8
-rw-r--r--chromium/ui/base/ui_base_types.h5
-rw-r--r--chromium/ui/base/ui_export.h32
-rw-r--r--chromium/ui/base/view_prop.h6
-rw-r--r--chromium/ui/base/webui/jstemplate_builder.h39
-rw-r--r--chromium/ui/base/webui/web_ui_util.cc19
-rw-r--r--chromium/ui/base/webui/web_ui_util.h29
-rw-r--r--chromium/ui/base/webui/web_ui_util_unittest.cc29
-rw-r--r--chromium/ui/base/win/accessibility_misc_utils.cc10
-rw-r--r--chromium/ui/base/win/accessibility_misc_utils.h16
-rw-r--r--chromium/ui/base/win/dpi_setup.cc1
-rw-r--r--chromium/ui/base/win/dpi_setup.h4
-rw-r--r--chromium/ui/base/win/foreground_helper.cc10
-rw-r--r--chromium/ui/base/win/foreground_helper.h12
-rw-r--r--chromium/ui/base/win/hidden_window.cc6
-rw-r--r--chromium/ui/base/win/hidden_window.h4
-rw-r--r--chromium/ui/base/win/hwnd_subclass.cc7
-rw-r--r--chromium/ui/base/win/hwnd_subclass.h8
-rw-r--r--chromium/ui/base/win/internal_constants.cc13
-rw-r--r--chromium/ui/base/win/internal_constants.h20
-rw-r--r--chromium/ui/base/win/lock_state.h4
-rw-r--r--chromium/ui/base/win/message_box_win.cc8
-rw-r--r--chromium/ui/base/win/message_box_win.h10
-rw-r--r--chromium/ui/base/win/mouse_wheel_util.h9
-rw-r--r--chromium/ui/base/win/scoped_ole_initializer.h4
-rw-r--r--chromium/ui/base/win/shell.cc44
-rw-r--r--chromium/ui/base/win/shell.h44
-rw-r--r--chromium/ui/base/win/touch_input.cc8
-rw-r--r--chromium/ui/base/win/touch_input.h10
-rw-r--r--chromium/ui/base/win/window_event_target.cc16
-rw-r--r--chromium/ui/base/win/window_event_target.h71
-rw-r--r--chromium/ui/base/window_open_disposition.h14
-rw-r--r--chromium/ui/base/window_open_disposition_list.h2
-rw-r--r--chromium/ui/base/work_area_watcher_observer.h4
-rw-r--r--chromium/ui/base/x/active_window_watcher_x.cc99
-rw-r--r--chromium/ui/base/x/active_window_watcher_x.h60
-rw-r--r--chromium/ui/base/x/active_window_watcher_x_observer.h25
-rw-r--r--chromium/ui/base/x/root_window_property_watcher_x.cc59
-rw-r--r--chromium/ui/base/x/root_window_property_watcher_x.h41
-rw-r--r--chromium/ui/base/x/selection_owner.cc148
-rw-r--r--chromium/ui/base/x/selection_owner.h16
-rw-r--r--chromium/ui/base/x/selection_requestor.cc106
-rw-r--r--chromium/ui/base/x/selection_requestor.h41
-rw-r--r--chromium/ui/base/x/selection_utils.cc47
-rw-r--r--chromium/ui/base/x/selection_utils.h38
-rw-r--r--chromium/ui/base/x/work_area_watcher_x.cc53
-rw-r--r--chromium/ui/base/x/work_area_watcher_x.h55
-rw-r--r--chromium/ui/base/x/x11_menu_list.cc46
-rw-r--r--chromium/ui/base/x/x11_menu_list.h48
-rw-r--r--chromium/ui/base/x/x11_util.cc536
-rw-r--r--chromium/ui/base/x/x11_util.h245
-rw-r--r--chromium/ui/base/x/x11_util_internal.h21
-rw-r--r--chromium/ui/base/x/x11_util_unittest.cc25
-rw-r--r--chromium/ui/chromeos/ui_chromeos.gyp31
-rw-r--r--chromium/ui/compositor/BUILD.gn153
-rw-r--r--chromium/ui/compositor/DEPS1
-rw-r--r--chromium/ui/compositor/PRESUBMIT.py8
-rw-r--r--chromium/ui/compositor/compositor.cc370
-rw-r--r--chromium/ui/compositor/compositor.gyp65
-rw-r--r--chromium/ui/compositor/compositor.h155
-rw-r--r--chromium/ui/compositor/compositor_observer.h5
-rw-r--r--chromium/ui/compositor/compositor_switches.cc35
-rw-r--r--chromium/ui/compositor/compositor_switches.h19
-rw-r--r--chromium/ui/compositor/compositor_vsync_manager.cc63
-rw-r--r--chromium/ui/compositor/compositor_vsync_manager.h71
-rw-r--r--chromium/ui/compositor/debug_utils.cc6
-rw-r--r--chromium/ui/compositor/debug_utils.h2
-rw-r--r--chromium/ui/compositor/dip_util.cc10
-rw-r--r--chromium/ui/compositor/layer.cc345
-rw-r--r--chromium/ui/compositor/layer.h130
-rw-r--r--chromium/ui/compositor/layer_animation_delegate.h3
-rw-r--r--chromium/ui/compositor/layer_animation_element.cc125
-rw-r--r--chromium/ui/compositor/layer_animation_element.h27
-rw-r--r--chromium/ui/compositor/layer_animation_element_unittest.cc11
-rw-r--r--chromium/ui/compositor/layer_animation_observer.cc13
-rw-r--r--chromium/ui/compositor/layer_animation_sequence.cc27
-rw-r--r--chromium/ui/compositor/layer_animation_sequence.h4
-rw-r--r--chromium/ui/compositor/layer_animation_sequence_unittest.cc74
-rw-r--r--chromium/ui/compositor/layer_animator.cc130
-rw-r--r--chromium/ui/compositor/layer_animator.h25
-rw-r--r--chromium/ui/compositor/layer_animator_collection.cc56
-rw-r--r--chromium/ui/compositor/layer_animator_collection.h56
-rw-r--r--chromium/ui/compositor/layer_animator_unittest.cc444
-rw-r--r--chromium/ui/compositor/layer_owner.cc72
-rw-r--r--chromium/ui/compositor/layer_owner.h24
-rw-r--r--chromium/ui/compositor/layer_owner_delegate.h27
-rw-r--r--chromium/ui/compositor/layer_owner_unittest.cc33
-rw-r--r--chromium/ui/compositor/layer_tree_owner.cc34
-rw-r--r--chromium/ui/compositor/layer_tree_owner.h38
-rw-r--r--chromium/ui/compositor/layer_unittest.cc296
-rw-r--r--chromium/ui/compositor/scoped_layer_animation_settings.cc12
-rw-r--r--chromium/ui/compositor/scoped_layer_animation_settings.h4
-rw-r--r--chromium/ui/compositor/test/test_compositor_host_ozone.cc20
-rw-r--r--chromium/ui/compositor/transform_animation_curve_adapter.cc28
-rw-r--r--chromium/ui/compositor/transform_animation_curve_adapter.h6
-rw-r--r--chromium/ui/display/DEPS4
-rw-r--r--chromium/ui/display/OWNERS3
-rw-r--r--chromium/ui/display/display.gyp162
-rw-r--r--chromium/ui/display/display_export.h37
-rw-r--r--chromium/ui/display/display_switches.cc16
-rw-r--r--chromium/ui/display/display_switches.h21
-rw-r--r--chromium/ui/display/display_unittests.gypi34
-rw-r--r--chromium/ui/display/types/DEPS5
-rw-r--r--chromium/ui/display/types/chromeos/display_mode.cc28
-rw-r--r--chromium/ui/display/types/chromeos/display_mode.h39
-rw-r--r--chromium/ui/display/types/chromeos/display_snapshot.cc34
-rw-r--r--chromium/ui/display/types/chromeos/display_snapshot.h90
-rw-r--r--chromium/ui/display/types/chromeos/native_display_delegate.h95
-rw-r--r--chromium/ui/display/types/chromeos/native_display_observer.h23
-rw-r--r--chromium/ui/display/types/chromeos/touchscreen_device.cc19
-rw-r--r--chromium/ui/display/types/chromeos/touchscreen_device.h31
-rw-r--r--chromium/ui/display/types/chromeos/touchscreen_device_manager.h27
-rw-r--r--chromium/ui/display/types/display_constants.h52
-rw-r--r--chromium/ui/display/types/display_types_export.h37
-rw-r--r--chromium/ui/display/util/display_util.cc71
-rw-r--r--chromium/ui/display/util/display_util.h26
-rw-r--r--chromium/ui/display/util/display_util_export.h37
-rw-r--r--chromium/ui/display/util/display_util_unittest.cc53
-rw-r--r--chromium/ui/display/util/edid_parser.cc197
-rw-r--r--chromium/ui/display/util/edid_parser.h42
-rw-r--r--chromium/ui/display/util/edid_parser_unittest.cc229
-rw-r--r--chromium/ui/display/util/x11/DEPS3
-rw-r--r--chromium/ui/display/util/x11/edid_parser_x11.cc122
-rw-r--r--chromium/ui/display/util/x11/edid_parser_x11.h40
-rw-r--r--chromium/ui/events/BUILD.gn311
-rw-r--r--chromium/ui/events/PRESUBMIT.py26
-rw-r--r--chromium/ui/events/cocoa/cocoa_event_utils.h26
-rw-r--r--chromium/ui/events/cocoa/cocoa_event_utils.mm55
-rw-r--r--chromium/ui/events/cocoa/events_mac.mm261
-rw-r--r--chromium/ui/events/cocoa/events_mac_unittest.mm315
-rw-r--r--chromium/ui/events/event.cc264
-rw-r--r--chromium/ui/events/event.h144
-rw-r--r--chromium/ui/events/event_constants.h46
-rw-r--r--chromium/ui/events/event_dispatcher.cc28
-rw-r--r--chromium/ui/events/event_dispatcher.h4
-rw-r--r--chromium/ui/events/event_dispatcher_unittest.cc62
-rw-r--r--chromium/ui/events/event_processor.cc16
-rw-r--r--chromium/ui/events/event_processor.h4
-rw-r--r--chromium/ui/events/event_processor_unittest.cc219
-rw-r--r--chromium/ui/events/event_rewriter.h68
-rw-r--r--chromium/ui/events/event_rewriter_unittest.cc231
-rw-r--r--chromium/ui/events/event_source.cc65
-rw-r--r--chromium/ui/events/event_source.h24
-rw-r--r--chromium/ui/events/event_switches.cc17
-rw-r--r--chromium/ui/events/event_switches.h8
-rw-r--r--chromium/ui/events/event_target.h4
-rw-r--r--chromium/ui/events/event_targeter.cc24
-rw-r--r--chromium/ui/events/event_targeter.h37
-rw-r--r--chromium/ui/events/event_unittest.cc132
-rw-r--r--chromium/ui/events/event_utils.cc63
-rw-r--r--chromium/ui/events/event_utils.h44
-rw-r--r--chromium/ui/events/events.gyp221
-rw-r--r--chromium/ui/events/events_stub.cc29
-rw-r--r--chromium/ui/events/gesture_detection/OWNERS2
-rw-r--r--chromium/ui/events/gesture_detection/bitset_32.h128
-rw-r--r--chromium/ui/events/gesture_detection/bitset_32_unittest.cc100
-rw-r--r--chromium/ui/events/gesture_detection/filtered_gesture_provider.cc77
-rw-r--r--chromium/ui/events/gesture_detection/filtered_gesture_provider.h61
-rw-r--r--chromium/ui/events/gesture_detection/gesture_config_helper.cc17
-rw-r--r--chromium/ui/events/gesture_detection/gesture_config_helper.h20
-rw-r--r--chromium/ui/events/gesture_detection/gesture_config_helper_android.cc73
-rw-r--r--chromium/ui/events/gesture_detection/gesture_config_helper_aura.cc73
-rw-r--r--chromium/ui/events/gesture_detection/gesture_detection_export.h29
-rw-r--r--chromium/ui/events/gesture_detection/gesture_detector.cc553
-rw-r--r--chromium/ui/events/gesture_detection/gesture_detector.h214
-rw-r--r--chromium/ui/events/gesture_detection/gesture_event_data.cc50
-rw-r--r--chromium/ui/events/gesture_detection/gesture_event_data.h48
-rw-r--r--chromium/ui/events/gesture_detection/gesture_event_data_packet.cc96
-rw-r--r--chromium/ui/events/gesture_detection/gesture_event_data_packet.h68
-rw-r--r--chromium/ui/events/gesture_detection/gesture_provider.cc810
-rw-r--r--chromium/ui/events/gesture_detection/gesture_provider.h136
-rw-r--r--chromium/ui/events/gesture_detection/gesture_provider_unittest.cc2298
-rw-r--r--chromium/ui/events/gesture_detection/mock_motion_event.cc204
-rw-r--r--chromium/ui/events/gesture_detection/mock_motion_event.h86
-rw-r--r--chromium/ui/events/gesture_detection/motion_event.h73
-rw-r--r--chromium/ui/events/gesture_detection/scale_gesture_detector.cc383
-rw-r--r--chromium/ui/events/gesture_detection/scale_gesture_detector.h158
-rw-r--r--chromium/ui/events/gesture_detection/snap_scroll_controller.cc106
-rw-r--r--chromium/ui/events/gesture_detection/snap_scroll_controller.h60
-rw-r--r--chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc400
-rw-r--r--chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.h108
-rw-r--r--chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc1059
-rw-r--r--chromium/ui/events/gesture_detection/velocity_tracker.cc805
-rw-r--r--chromium/ui/events/gesture_detection/velocity_tracker.h150
-rw-r--r--chromium/ui/events/gesture_detection/velocity_tracker_state.cc105
-rw-r--r--chromium/ui/events/gesture_detection/velocity_tracker_state.h50
-rw-r--r--chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc193
-rw-r--r--chromium/ui/events/gesture_event_details.cc71
-rw-r--r--chromium/ui/events/gesture_event_details.h171
-rw-r--r--chromium/ui/events/gestures/OWNERS1
-rw-r--r--chromium/ui/events/gestures/gesture_configuration.cc17
-rw-r--r--chromium/ui/events/gestures/gesture_configuration.h29
-rw-r--r--chromium/ui/events/gestures/gesture_point.cc85
-rw-r--r--chromium/ui/events/gestures/gesture_point.h47
-rw-r--r--chromium/ui/events/gestures/gesture_provider_aura.cc142
-rw-r--r--chromium/ui/events/gestures/gesture_provider_aura.h59
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer.h24
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl.cc216
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl.h29
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc64
-rw-r--r--chromium/ui/events/gestures/gesture_sequence.cc268
-rw-r--r--chromium/ui/events/gestures/gesture_sequence.h35
-rw-r--r--chromium/ui/events/gestures/gesture_types.cc105
-rw-r--r--chromium/ui/events/gestures/gesture_types.h167
-rw-r--r--chromium/ui/events/gestures/gesture_util.cc23
-rw-r--r--chromium/ui/events/gestures/gesture_util.h26
-rw-r--r--chromium/ui/events/gestures/gestures.dot5
-rw-r--r--chromium/ui/events/gestures/motion_event_aura.cc255
-rw-r--r--chromium/ui/events/gestures/motion_event_aura.h106
-rw-r--r--chromium/ui/events/gestures/motion_event_aura_unittest.cc323
-rw-r--r--chromium/ui/events/gestures/unified_gesture_detector_enabled.cc37
-rw-r--r--chromium/ui/events/gestures/unified_gesture_detector_enabled.h17
-rw-r--r--chromium/ui/events/gestures/velocity_calculator.cc2
-rw-r--r--chromium/ui/events/gestures/velocity_calculator.h6
-rw-r--r--chromium/ui/events/gestures/velocity_calculator_unittest.cc2
-rw-r--r--chromium/ui/events/ipc/BUILD.gn17
-rw-r--r--chromium/ui/events/ipc/OWNERS13
-rw-r--r--chromium/ui/events/ipc/events_ipc.gyp29
-rw-r--r--chromium/ui/events/ipc/latency_info_param_traits.cc26
-rw-r--r--chromium/ui/events/ipc/latency_info_param_traits.h30
-rw-r--r--chromium/ui/events/keycodes/DEPS11
-rw-r--r--chromium/ui/events/keycodes/dom4/DEPS3
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_gtk.cc85
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_gtk.h58
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_mac.h4
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm12
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_x.cc899
-rw-r--r--chromium/ui/events/keycodes/keyboard_code_conversion_x.h5
-rw-r--r--chromium/ui/events/latency_info.cc51
-rw-r--r--chromium/ui/events/latency_info.h35
-rw-r--r--chromium/ui/events/latency_info_nacl.gyp78
-rw-r--r--chromium/ui/events/latency_info_unittest.cc80
-rw-r--r--chromium/ui/events/linux/text_edit_command_auralinux.cc124
-rw-r--r--chromium/ui/events/linux/text_edit_command_auralinux.h82
-rw-r--r--chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.cc23
-rw-r--r--chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.h43
-rw-r--r--chromium/ui/events/ozone/BUILD.gn101
-rw-r--r--chromium/ui/events/ozone/DEPS4
-rw-r--r--chromium/ui/events/ozone/OWNERS1
-rw-r--r--chromium/ui/events/ozone/device/device_event.cc16
-rw-r--r--chromium/ui/events/ozone/device/device_event.h43
-rw-r--r--chromium/ui/events/ozone/device/device_event_observer.h24
-rw-r--r--chromium/ui/events/ozone/device/device_manager.cc23
-rw-r--r--chromium/ui/events/ozone/device/device_manager.h36
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.cc33
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.h29
-rw-r--r--chromium/ui/events/ozone/device/udev/device_manager_udev.cc186
-rw-r--r--chromium/ui/events/ozone/device/udev/device_manager_udev.h51
-rw-r--r--chromium/ui/events/ozone/evdev/cursor_delegate_evdev.h31
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev.cc23
-rw-r--r--chromium/ui/events/ozone/evdev/event_converter_evdev.h46
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.cc63
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.h19
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory.cc83
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory.h31
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory_evdev.cc242
-rw-r--r--chromium/ui/events/ozone/evdev/event_factory_evdev.h82
-rw-r--r--chromium/ui/events/ozone/evdev/event_modifiers.cc74
-rw-r--r--chromium/ui/events/ozone/evdev/event_modifiers.h74
-rw-r--r--chromium/ui/events/ozone/evdev/event_modifiers_evdev.cc79
-rw-r--r--chromium/ui/events/ozone/evdev/event_modifiers_evdev.h77
-rw-r--r--chromium/ui/events/ozone/evdev/events_ozone_evdev_export.h29
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter.cc248
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter.h46
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter_evdev.cc271
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter_evdev.h60
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter_evdev_unittest.cc347
-rw-r--r--chromium/ui/events/ozone/evdev/key_event_converter_unittest.cc325
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc107
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h78
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc274
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h82
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.cc32
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.h15
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.cc72
-rw-r--r--chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h16
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter.cc197
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter.h82
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc307
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h118
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc481
-rw-r--r--chromium/ui/events/ozone/evdev/touch_event_converter_unittest.cc398
-rw-r--r--chromium/ui/events/ozone/event_converter_ozone.cc33
-rw-r--r--chromium/ui/events/ozone/event_converter_ozone.h40
-rw-r--r--chromium/ui/events/ozone/event_factory_ozone.cc61
-rw-r--r--chromium/ui/events/ozone/event_factory_ozone.h62
-rw-r--r--chromium/ui/events/ozone/events_ozone.cc24
-rw-r--r--chromium/ui/events/ozone/events_ozone.gyp97
-rw-r--r--chromium/ui/events/ozone/events_ozone_export.h29
-rw-r--r--chromium/ui/events/platform/BUILD.gn32
-rw-r--r--chromium/ui/events/platform/events_platform.gyp36
-rw-r--r--chromium/ui/events/platform/platform_event_dispatcher.h43
-rw-r--r--chromium/ui/events/platform/platform_event_observer.h29
-rw-r--r--chromium/ui/events/platform/platform_event_source.cc111
-rw-r--r--chromium/ui/events/platform/platform_event_source.h102
-rw-r--r--chromium/ui/events/platform/platform_event_source_stub.cc13
-rw-r--r--chromium/ui/events/platform/platform_event_source_unittest.cc787
-rw-r--r--chromium/ui/events/platform/platform_event_types.h14
-rw-r--r--chromium/ui/events/platform/scoped_event_dispatcher.cc21
-rw-r--r--chromium/ui/events/platform/scoped_event_dispatcher.h40
-rw-r--r--chromium/ui/events/platform/x11/BUILD.gn42
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.cc149
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.h64
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source_glib.cc101
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source_libevent.cc68
-rw-r--r--chromium/ui/events/platform/x11/x11_events_platform.gyp43
-rw-r--r--chromium/ui/events/win/events_win.cc29
-rw-r--r--chromium/ui/events/x/device_data_manager.cc89
-rw-r--r--chromium/ui/events/x/device_data_manager.h29
-rw-r--r--chromium/ui/events/x/events_x.cc136
-rw-r--r--chromium/ui/events/x/events_x_unittest.cc237
-rw-r--r--chromium/ui/events/x/touch_factory_x11.cc58
-rw-r--r--chromium/ui/events/x/touch_factory_x11.h12
-rw-r--r--chromium/ui/file_manager/file_manager.gyp52
-rw-r--r--chromium/ui/gfx/BUILD.gn445
-rw-r--r--chromium/ui/gfx/DEPS4
-rw-r--r--chromium/ui/gfx/OWNERS9
-rw-r--r--chromium/ui/gfx/android/OWNERS4
-rw-r--r--chromium/ui/gfx/android/bitmap_config_list.h15
-rw-r--r--chromium/ui/gfx/android/device_display_info.cc12
-rw-r--r--chromium/ui/gfx/android/device_display_info.h17
-rw-r--r--chromium/ui/gfx/android/java_bitmap.cc99
-rw-r--r--chromium/ui/gfx/android/java_bitmap.h40
-rw-r--r--chromium/ui/gfx/android/scroller.cc439
-rw-r--r--chromium/ui/gfx/android/scroller.h148
-rw-r--r--chromium/ui/gfx/android/scroller_unittest.cc167
-rw-r--r--chromium/ui/gfx/android/shared_device_display_info.cc57
-rw-r--r--chromium/ui/gfx/android/shared_device_display_info.h17
-rw-r--r--chromium/ui/gfx/android/view_configuration.cc196
-rw-r--r--chromium/ui/gfx/android/view_configuration.h8
-rw-r--r--chromium/ui/gfx/animation/animation.cc3
-rw-r--r--chromium/ui/gfx/animation/animation_delegate.h5
-rw-r--r--chromium/ui/gfx/animation/tween.cc10
-rw-r--r--chromium/ui/gfx/animation/tween.h25
-rw-r--r--chromium/ui/gfx/animation/tween_unittest.cc9
-rw-r--r--chromium/ui/gfx/blit.cc21
-rw-r--r--chromium/ui/gfx/box_f.cc70
-rw-r--r--chromium/ui/gfx/box_f.h157
-rw-r--r--chromium/ui/gfx/box_unittest.cc176
-rw-r--r--chromium/ui/gfx/canvas.cc301
-rw-r--r--chromium/ui/gfx/canvas.h145
-rw-r--r--chromium/ui/gfx/canvas_paint_gtk.cc107
-rw-r--r--chromium/ui/gfx/canvas_paint_gtk.h102
-rw-r--r--chromium/ui/gfx/canvas_skia.cc99
-rw-r--r--chromium/ui/gfx/canvas_skia_paint.h4
-rw-r--r--chromium/ui/gfx/canvas_unittest.cc16
-rw-r--r--chromium/ui/gfx/codec/png_codec.cc100
-rw-r--r--chromium/ui/gfx/codec/png_codec.h21
-rw-r--r--chromium/ui/gfx/codec/png_codec_unittest.cc51
-rw-r--r--chromium/ui/gfx/color_analysis.cc74
-rw-r--r--chromium/ui/gfx/color_analysis.h48
-rw-r--r--chromium/ui/gfx/color_analysis_unittest.cc140
-rw-r--r--chromium/ui/gfx/color_profile.cc7
-rw-r--r--chromium/ui/gfx/color_profile.h15
-rw-r--r--chromium/ui/gfx/color_profile_mac.cc27
-rw-r--r--chromium/ui/gfx/color_profile_mac.mm32
-rw-r--r--chromium/ui/gfx/color_profile_win.cc98
-rw-r--r--chromium/ui/gfx/color_profile_win_unittest.cc32
-rw-r--r--chromium/ui/gfx/color_utils.cc32
-rw-r--r--chromium/ui/gfx/color_utils.h14
-rw-r--r--chromium/ui/gfx/color_utils_unittest.cc75
-rw-r--r--chromium/ui/gfx/display.cc45
-rw-r--r--chromium/ui/gfx/display.h2
-rw-r--r--chromium/ui/gfx/display_observer.h16
-rw-r--r--chromium/ui/gfx/font.cc16
-rw-r--r--chromium/ui/gfx/font.h20
-rw-r--r--chromium/ui/gfx/font_fallback_win.cc13
-rw-r--r--chromium/ui/gfx/font_list.cc267
-rw-r--r--chromium/ui/gfx/font_list.h97
-rw-r--r--chromium/ui/gfx/font_list_impl.cc248
-rw-r--r--chromium/ui/gfx/font_list_impl.h123
-rw-r--r--chromium/ui/gfx/font_list_unittest.cc112
-rw-r--r--chromium/ui/gfx/font_render_params_linux.cc81
-rw-r--r--chromium/ui/gfx/font_smoothing_win.cc2
-rw-r--r--chromium/ui/gfx/font_unittest.cc46
-rw-r--r--chromium/ui/gfx/gdi_util.cc4
-rw-r--r--chromium/ui/gfx/gdk_compat.h27
-rw-r--r--chromium/ui/gfx/geometry/BUILD.gn62
-rw-r--r--chromium/ui/gfx/geometry/box_f.cc70
-rw-r--r--chromium/ui/gfx/geometry/box_f.h160
-rw-r--r--chromium/ui/gfx/geometry/box_unittest.cc176
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier.cc128
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier.h36
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier_unittest.cc140
-rw-r--r--chromium/ui/gfx/geometry/insets.cc25
-rw-r--r--chromium/ui/gfx/geometry/insets.h50
-rw-r--r--chromium/ui/gfx/geometry/insets_base.h80
-rw-r--r--chromium/ui/gfx/geometry/insets_f.cc25
-rw-r--r--chromium/ui/gfx/geometry/insets_f.h33
-rw-r--r--chromium/ui/gfx/geometry/insets_unittest.cc66
-rw-r--r--chromium/ui/gfx/geometry/matrix3_f.cc237
-rw-r--r--chromium/ui/gfx/geometry/matrix3_f.h108
-rw-r--r--chromium/ui/gfx/geometry/matrix3_unittest.cc148
-rw-r--r--chromium/ui/gfx/geometry/point.cc54
-rw-r--r--chromium/ui/gfx/geometry/point.h90
-rw-r--r--chromium/ui/gfx/geometry/point3_f.cc40
-rw-r--r--chromium/ui/gfx/geometry/point3_f.h120
-rw-r--r--chromium/ui/gfx/geometry/point3_unittest.cc69
-rw-r--r--chromium/ui/gfx/geometry/point_base.h87
-rw-r--r--chromium/ui/gfx/geometry/point_conversions.cc30
-rw-r--r--chromium/ui/gfx/geometry/point_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/point_f.cc24
-rw-r--r--chromium/ui/gfx/geometry/point_f.h75
-rw-r--r--chromium/ui/gfx/geometry/point_unittest.cc173
-rw-r--r--chromium/ui/gfx/geometry/quad_f.cc123
-rw-r--r--chromium/ui/gfx/geometry/quad_f.h109
-rw-r--r--chromium/ui/gfx/geometry/quad_unittest.cc359
-rw-r--r--chromium/ui/gfx/geometry/r_tree.h182
-rw-r--r--chromium/ui/gfx/geometry/r_tree_base.cc658
-rw-r--r--chromium/ui/gfx/geometry/r_tree_base.h309
-rw-r--r--chromium/ui/gfx/geometry/r_tree_unittest.cc1025
-rw-r--r--chromium/ui/gfx/geometry/rect.cc97
-rw-r--r--chromium/ui/gfx/geometry/rect.h139
-rw-r--r--chromium/ui/gfx/geometry/rect_base.h174
-rw-r--r--chromium/ui/gfx/geometry/rect_base_impl.h354
-rw-r--r--chromium/ui/gfx/geometry/rect_conversions.cc82
-rw-r--r--chromium/ui/gfx/geometry/rect_conversions.h36
-rw-r--r--chromium/ui/gfx/geometry/rect_f.cc60
-rw-r--r--chromium/ui/gfx/geometry/rect_f.h113
-rw-r--r--chromium/ui/gfx/geometry/rect_unittest.cc925
-rw-r--r--chromium/ui/gfx/geometry/safe_integer_conversions.h54
-rw-r--r--chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc109
-rw-r--r--chromium/ui/gfx/geometry/size.cc46
-rw-r--r--chromium/ui/gfx/geometry/size.h67
-rw-r--r--chromium/ui/gfx/geometry/size_base.h69
-rw-r--r--chromium/ui/gfx/geometry/size_conversions.cc30
-rw-r--r--chromium/ui/gfx/geometry/size_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/size_f.cc23
-rw-r--r--chromium/ui/gfx/geometry/size_f.h54
-rw-r--r--chromium/ui/gfx/geometry/size_unittest.cc127
-rw-r--r--chromium/ui/gfx/geometry/vector2d.cc39
-rw-r--r--chromium/ui/gfx/geometry/vector2d.h91
-rw-r--r--chromium/ui/gfx/geometry/vector2d_conversions.cc30
-rw-r--r--chromium/ui/gfx/geometry/vector2d_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/vector2d_f.cc60
-rw-r--r--chromium/ui/gfx/geometry/vector2d_f.h112
-rw-r--r--chromium/ui/gfx/geometry/vector2d_unittest.cc250
-rw-r--r--chromium/ui/gfx/geometry/vector3d_f.cc88
-rw-r--r--chromium/ui/gfx/geometry/vector3d_f.h124
-rw-r--r--chromium/ui/gfx/geometry/vector3d_unittest.cc264
-rw-r--r--chromium/ui/gfx/gfx.gyp259
-rw-r--r--chromium/ui/gfx/gfx_tests.gyp146
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.cc14
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.h76
-rw-r--r--chromium/ui/gfx/gtk_compat.h97
-rw-r--r--chromium/ui/gfx/gtk_native_view_id_manager.cc254
-rw-r--r--chromium/ui/gfx/gtk_native_view_id_manager.h138
-rw-r--r--chromium/ui/gfx/gtk_preserve_window.cc264
-rw-r--r--chromium/ui/gfx/gtk_preserve_window.h74
-rw-r--r--chromium/ui/gfx/gtk_util.cc190
-rw-r--r--chromium/ui/gfx/gtk_util.h52
-rw-r--r--chromium/ui/gfx/icon_util.cc31
-rw-r--r--chromium/ui/gfx/icon_util_unittest.cc34
-rw-r--r--chromium/ui/gfx/icon_util_unittests.icobin0 -> 53740 bytes
-rw-r--r--chromium/ui/gfx/icon_util_unittests.rc36
-rw-r--r--chromium/ui/gfx/icon_util_unittests_resource.h5
-rw-r--r--chromium/ui/gfx/image/OWNERS2
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.cc109
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.h84
-rw-r--r--chromium/ui/gfx/image/image.cc393
-rw-r--r--chromium/ui/gfx/image/image.h24
-rw-r--r--chromium/ui/gfx/image/image_skia.cc94
-rw-r--r--chromium/ui/gfx/image/image_skia.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.cc19
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.h16
-rw-r--r--chromium/ui/gfx/image/image_skia_unittest.cc185
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.mm6
-rw-r--r--chromium/ui/gfx/image/image_unittest.cc53
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.cc31
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.h2
-rw-r--r--chromium/ui/gfx/image/image_util.cc57
-rw-r--r--chromium/ui/gfx/image/image_util.h17
-rw-r--r--chromium/ui/gfx/image/image_util_unittest.cc78
-rw-r--r--chromium/ui/gfx/insets.cc38
-rw-r--r--chromium/ui/gfx/insets.h51
-rw-r--r--chromium/ui/gfx/insets_base.h80
-rw-r--r--chromium/ui/gfx/insets_f.cc25
-rw-r--r--chromium/ui/gfx/insets_f.h32
-rw-r--r--chromium/ui/gfx/insets_unittest.cc66
-rw-r--r--chromium/ui/gfx/linux_font_delegate.cc23
-rw-r--r--chromium/ui/gfx/linux_font_delegate.h49
-rw-r--r--chromium/ui/gfx/matrix3_f.cc237
-rw-r--r--chromium/ui/gfx/matrix3_f.h107
-rw-r--r--chromium/ui/gfx/matrix3_unittest.cc148
-rw-r--r--chromium/ui/gfx/native_widget_types.h80
-rw-r--r--chromium/ui/gfx/nine_image_painter.cc157
-rw-r--r--chromium/ui/gfx/nine_image_painter.h42
-rw-r--r--chromium/ui/gfx/overlay_transform.h24
-rw-r--r--chromium/ui/gfx/ozone/OWNERS1
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_skbitmap.cc208
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_skbitmap.h57
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface.cc113
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface.h168
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory.cc317
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory.h75
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc292
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc212
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc32
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_vsync_provider.h29
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_wrapper.cc93
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_wrapper.h86
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller.cc129
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller.h190
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc301
-rw-r--r--chromium/ui/gfx/ozone/impl/file_surface_factory.cc96
-rw-r--r--chromium/ui/gfx/ozone/impl/file_surface_factory.h49
-rw-r--r--chromium/ui/gfx/ozone/surface_factory_ozone.cc92
-rw-r--r--chromium/ui/gfx/ozone/surface_factory_ozone.h147
-rw-r--r--chromium/ui/gfx/pango_util.cc14
-rw-r--r--chromium/ui/gfx/path.h2
-rw-r--r--chromium/ui/gfx/path_gtk.cc55
-rw-r--r--chromium/ui/gfx/path_win.cc4
-rw-r--r--chromium/ui/gfx/path_x11.cc6
-rw-r--r--chromium/ui/gfx/path_x11.h5
-rw-r--r--chromium/ui/gfx/platform_font.h7
-rw-r--r--chromium/ui/gfx/platform_font_ios.h2
-rw-r--r--chromium/ui/gfx/platform_font_ios.mm9
-rw-r--r--chromium/ui/gfx/platform_font_mac.h2
-rw-r--r--chromium/ui/gfx/platform_font_mac.mm9
-rw-r--r--chromium/ui/gfx/platform_font_mac_unittest.mm8
-rw-r--r--chromium/ui/gfx/platform_font_pango.cc56
-rw-r--r--chromium/ui/gfx/platform_font_pango.h3
-rw-r--r--chromium/ui/gfx/platform_font_win.cc17
-rw-r--r--chromium/ui/gfx/platform_font_win.h2
-rw-r--r--chromium/ui/gfx/platform_font_win_unittest.cc8
-rw-r--r--chromium/ui/gfx/point.cc54
-rw-r--r--chromium/ui/gfx/point.h89
-rw-r--r--chromium/ui/gfx/point3_f.cc40
-rw-r--r--chromium/ui/gfx/point3_f.h119
-rw-r--r--chromium/ui/gfx/point3_unittest.cc70
-rw-r--r--chromium/ui/gfx/point_base.h87
-rw-r--r--chromium/ui/gfx/point_conversions.cc30
-rw-r--r--chromium/ui/gfx/point_conversions.h23
-rw-r--r--chromium/ui/gfx/point_f.cc24
-rw-r--r--chromium/ui/gfx/point_f.h74
-rw-r--r--chromium/ui/gfx/point_unittest.cc174
-rw-r--r--chromium/ui/gfx/quad_f.cc127
-rw-r--r--chromium/ui/gfx/quad_f.h108
-rw-r--r--chromium/ui/gfx/quad_unittest.cc360
-rw-r--r--chromium/ui/gfx/rect.cc110
-rw-r--r--chromium/ui/gfx/rect.h144
-rw-r--r--chromium/ui/gfx/rect_base.h174
-rw-r--r--chromium/ui/gfx/rect_base_impl.h355
-rw-r--r--chromium/ui/gfx/rect_conversions.cc82
-rw-r--r--chromium/ui/gfx/rect_conversions.h35
-rw-r--r--chromium/ui/gfx/rect_f.cc60
-rw-r--r--chromium/ui/gfx/rect_f.h112
-rw-r--r--chromium/ui/gfx/rect_unittest.cc936
-rw-r--r--chromium/ui/gfx/render_text.cc395
-rw-r--r--chromium/ui/gfx/render_text.h132
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc1010
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.h130
-rw-r--r--chromium/ui/gfx/render_text_mac.cc22
-rw-r--r--chromium/ui/gfx/render_text_mac.h2
-rw-r--r--chromium/ui/gfx/render_text_ozone.cc2
-rw-r--r--chromium/ui/gfx/render_text_pango.cc56
-rw-r--r--chromium/ui/gfx/render_text_pango.h2
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc336
-rw-r--r--chromium/ui/gfx/render_text_win.cc95
-rw-r--r--chromium/ui/gfx/render_text_win.h2
-rw-r--r--chromium/ui/gfx/safe_integer_conversions.h53
-rw-r--r--chromium/ui/gfx/safe_integer_conversions_unittest.cc109
-rw-r--r--chromium/ui/gfx/scoped_gobject.h34
-rw-r--r--chromium/ui/gfx/screen_android.cc1
-rw-r--r--chromium/ui/gfx/screen_gtk.cc210
-rw-r--r--chromium/ui/gfx/screen_ios.mm3
-rw-r--r--chromium/ui/gfx/screen_mac.mm7
-rw-r--r--chromium/ui/gfx/screen_win.cc33
-rw-r--r--chromium/ui/gfx/selection_model.h11
-rw-r--r--chromium/ui/gfx/size.cc46
-rw-r--r--chromium/ui/gfx/size.h66
-rw-r--r--chromium/ui/gfx/size_base.h69
-rw-r--r--chromium/ui/gfx/size_conversions.cc30
-rw-r--r--chromium/ui/gfx/size_conversions.h23
-rw-r--r--chromium/ui/gfx/size_f.cc23
-rw-r--r--chromium/ui/gfx/size_f.h53
-rw-r--r--chromium/ui/gfx/size_unittest.cc128
-rw-r--r--chromium/ui/gfx/skbitmap_operations.cc78
-rw-r--r--chromium/ui/gfx/skia_util.cc43
-rw-r--r--chromium/ui/gfx/skia_util.h7
-rw-r--r--chromium/ui/gfx/skia_utils_gtk.cc32
-rw-r--r--chromium/ui/gfx/skia_utils_gtk.h23
-rw-r--r--chromium/ui/gfx/skrect_conversion_unittest.cc26
-rw-r--r--chromium/ui/gfx/switches.cc13
-rw-r--r--chromium/ui/gfx/switches.h4
-rw-r--r--chromium/ui/gfx/sys_color_change_listener.cc3
-rw-r--r--chromium/ui/gfx/text_constants.h41
-rw-r--r--chromium/ui/gfx/text_elider.cc526
-rw-r--r--chromium/ui/gfx/text_elider.h128
-rw-r--r--chromium/ui/gfx/text_elider_unittest.cc481
-rw-r--r--chromium/ui/gfx/text_utils_unittest.cc31
-rw-r--r--chromium/ui/gfx/transform.h8
-rw-r--r--chromium/ui/gfx/utf16_indexing_unittest.cc5
-rw-r--r--chromium/ui/gfx/vector2d.cc39
-rw-r--r--chromium/ui/gfx/vector2d.h90
-rw-r--r--chromium/ui/gfx/vector2d_conversions.cc30
-rw-r--r--chromium/ui/gfx/vector2d_conversions.h23
-rw-r--r--chromium/ui/gfx/vector2d_f.cc60
-rw-r--r--chromium/ui/gfx/vector2d_f.h111
-rw-r--r--chromium/ui/gfx/vector2d_unittest.cc250
-rw-r--r--chromium/ui/gfx/vector3d_f.cc88
-rw-r--r--chromium/ui/gfx/vector3d_f.h123
-rw-r--r--chromium/ui/gfx/vector3d_unittest.cc264
-rw-r--r--chromium/ui/gfx/win/dpi.cc159
-rw-r--r--chromium/ui/gfx/win/dpi.h27
-rw-r--r--chromium/ui/gfx/win/hwnd_util.cc19
-rw-r--r--chromium/ui/gfx/win/hwnd_util.h4
-rw-r--r--chromium/ui/gfx/win/msg_util.h2283
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd.cc3
-rw-r--r--chromium/ui/gfx/win/window_impl.cc10
-rw-r--r--chromium/ui/gfx/win/window_impl.h6
-rw-r--r--chromium/ui/gfx/x/BUILD.gn32
-rw-r--r--chromium/ui/gfx/x/gfx_x11.gyp38
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.cc11
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.h18
-rw-r--r--chromium/ui/gfx/x/x11_connection.cc17
-rw-r--r--chromium/ui/gfx/x/x11_connection.h18
-rw-r--r--chromium/ui/gfx/x/x11_error_tracker.cc45
-rw-r--r--chromium/ui/gfx/x/x11_error_tracker.h36
-rw-r--r--chromium/ui/gfx/x/x11_switches.cc15
-rw-r--r--chromium/ui/gfx/x/x11_switches.h18
-rw-r--r--chromium/ui/gfx/x/x11_types.cc17
-rw-r--r--chromium/ui/gfx/x/x11_types.h3
-rw-r--r--chromium/ui/gl/BUILD.gn341
-rw-r--r--chromium/ui/gl/DEPS1
-rw-r--r--chromium/ui/gl/OWNERS1
-rw-r--r--chromium/ui/gl/PRESUBMIT.py18
-rw-r--r--chromium/ui/gl/android/OWNERS1
-rw-r--r--chromium/ui/gl/android/surface_texture.cc32
-rw-r--r--chromium/ui/gl/android/surface_texture.h19
-rw-r--r--chromium/ui/gl/android/surface_texture_listener.cc2
-rw-r--r--chromium/ui/gl/android/surface_texture_tracker.cc26
-rw-r--r--chromium/ui/gl/android/surface_texture_tracker.h32
-rwxr-xr-xchromium/ui/gl/generate_bindings.py721
-rw-r--r--chromium/ui/gl/gl.gyp78
-rw-r--r--chromium/ui/gl/gl_bindings.h56
-rw-r--r--chromium/ui/gl/gl_bindings_skia_in_process.cc279
-rw-r--r--chromium/ui/gl/gl_context.cc76
-rw-r--r--chromium/ui/gl/gl_context.h58
-rw-r--r--chromium/ui/gl/gl_context_android.cc49
-rw-r--r--chromium/ui/gl/gl_context_cgl.cc7
-rw-r--r--chromium/ui/gl/gl_context_egl.cc5
-rw-r--r--chromium/ui/gl/gl_context_glx.cc20
-rw-r--r--chromium/ui/gl/gl_context_mac.mm10
-rw-r--r--chromium/ui/gl/gl_context_nsview.h48
-rw-r--r--chromium/ui/gl/gl_context_nsview.mm100
-rw-r--r--chromium/ui/gl/gl_context_osmesa.cc6
-rw-r--r--chromium/ui/gl/gl_context_stub.cc5
-rw-r--r--chromium/ui/gl/gl_context_stub.h1
-rw-r--r--chromium/ui/gl/gl_context_stub_with_extensions.cc30
-rw-r--r--chromium/ui/gl/gl_context_stub_with_extensions.h37
-rw-r--r--chromium/ui/gl/gl_context_wgl.cc5
-rw-r--r--chromium/ui/gl/gl_egl_api_implementation.cc8
-rw-r--r--chromium/ui/gl/gl_egl_api_implementation.h10
-rw-r--r--chromium/ui/gl/gl_fence.cc105
-rw-r--r--chromium/ui/gl/gl_fence.h11
-rw-r--r--chromium/ui/gl/gl_gl_api_implementation.cc199
-rw-r--r--chromium/ui/gl/gl_gl_api_implementation.h45
-rw-r--r--chromium/ui/gl/gl_glx_api_implementation.cc9
-rw-r--r--chromium/ui/gl/gl_glx_api_implementation.h10
-rw-r--r--chromium/ui/gl/gl_image.cc17
-rw-r--r--chromium/ui/gl/gl_image.h14
-rw-r--r--chromium/ui/gl/gl_image_android.cc16
-rw-r--r--chromium/ui/gl/gl_image_android_native_buffer.cc118
-rw-r--r--chromium/ui/gl/gl_image_android_native_buffer.h40
-rw-r--r--chromium/ui/gl/gl_image_egl.cc115
-rw-r--r--chromium/ui/gl/gl_image_egl.h20
-rw-r--r--chromium/ui/gl/gl_image_glx.cc78
-rw-r--r--chromium/ui/gl/gl_image_glx.h8
-rw-r--r--chromium/ui/gl/gl_image_io_surface.cc54
-rw-r--r--chromium/ui/gl/gl_image_io_surface.h19
-rw-r--r--chromium/ui/gl/gl_image_shm.cc104
-rw-r--r--chromium/ui/gl/gl_image_shm.h14
-rw-r--r--chromium/ui/gl/gl_image_stub.cc27
-rw-r--r--chromium/ui/gl/gl_image_stub.h12
-rw-r--r--chromium/ui/gl/gl_image_surface_texture.cc75
-rw-r--r--chromium/ui/gl/gl_image_surface_texture.h45
-rw-r--r--chromium/ui/gl/gl_implementation.cc47
-rw-r--r--chromium/ui/gl/gl_implementation.h49
-rw-r--r--chromium/ui/gl/gl_implementation_android.cc64
-rw-r--r--chromium/ui/gl/gl_implementation_linux.cc63
-rw-r--r--chromium/ui/gl/gl_implementation_linux.h14
-rw-r--r--chromium/ui/gl/gl_implementation_mac.cc31
-rw-r--r--chromium/ui/gl/gl_implementation_osmesa.cc64
-rw-r--r--chromium/ui/gl/gl_implementation_osmesa.h19
-rw-r--r--chromium/ui/gl/gl_implementation_ozone.cc43
-rw-r--r--chromium/ui/gl/gl_implementation_win.cc86
-rw-r--r--chromium/ui/gl/gl_implementation_x11.cc68
-rw-r--r--chromium/ui/gl/gl_interface.cc20
-rw-r--r--chromium/ui/gl/gl_interface.h35
-rw-r--r--chromium/ui/gl/gl_mock.cc6
-rw-r--r--chromium/ui/gl/gl_mock.h26
-rw-r--r--chromium/ui/gl/gl_osmesa_api_implementation.cc8
-rw-r--r--chromium/ui/gl/gl_osmesa_api_implementation.h10
-rw-r--r--chromium/ui/gl/gl_state_restorer.h3
-rw-r--r--chromium/ui/gl/gl_surface.cc122
-rw-r--r--chromium/ui/gl/gl_surface.h21
-rw-r--r--chromium/ui/gl/gl_surface_android.cc90
-rw-r--r--chromium/ui/gl/gl_surface_cgl.cc106
-rw-r--r--chromium/ui/gl/gl_surface_cgl.h56
-rw-r--r--chromium/ui/gl/gl_surface_egl.cc234
-rw-r--r--chromium/ui/gl/gl_surface_egl.h14
-rw-r--r--chromium/ui/gl/gl_surface_glx.cc276
-rw-r--r--chromium/ui/gl/gl_surface_glx.h40
-rw-r--r--chromium/ui/gl/gl_surface_mac.cc91
-rw-r--r--chromium/ui/gl/gl_surface_nsview.h47
-rw-r--r--chromium/ui/gl/gl_surface_nsview.mm47
-rw-r--r--chromium/ui/gl/gl_surface_osmesa.cc14
-rw-r--r--chromium/ui/gl/gl_surface_osmesa.h17
-rw-r--r--chromium/ui/gl/gl_surface_ozone.cc143
-rw-r--r--chromium/ui/gl/gl_surface_wgl.cc28
-rw-r--r--chromium/ui/gl/gl_surface_win.cc33
-rw-r--r--chromium/ui/gl/gl_surface_x11.cc102
-rw-r--r--chromium/ui/gl/gl_switches.cc28
-rw-r--r--chromium/ui/gl/gl_switches.h14
-rw-r--r--chromium/ui/gl/gl_version_info.cc42
-rw-r--r--chromium/ui/gl/gl_version_info.h36
-rw-r--r--chromium/ui/gl/gl_wgl_api_implementation.cc8
-rw-r--r--chromium/ui/gl/gl_wgl_api_implementation.h10
-rw-r--r--chromium/ui/gl/gpu_preference.h3
-rw-r--r--chromium/ui/gl/io_surface_support_mac.cc379
-rw-r--r--chromium/ui/gl/io_surface_support_mac.h83
-rw-r--r--chromium/ui/gl/scoped_binders.cc2
-rw-r--r--chromium/ui/gl/scoped_cgl.cc27
-rw-r--r--chromium/ui/gl/scoped_cgl.h56
-rw-r--r--chromium/ui/gl/sync_control_vsync_provider.cc37
-rw-r--r--chromium/ui/gl/sync_control_vsync_provider.h1
-rw-r--r--chromium/ui/keyboard/DEPS3
-rw-r--r--chromium/ui/keyboard/keyboard.cc63
-rw-r--r--chromium/ui/keyboard/keyboard.gyp20
-rw-r--r--chromium/ui/keyboard/keyboard.h10
-rw-r--r--chromium/ui/keyboard/keyboard_constants.cc4
-rw-r--r--chromium/ui/keyboard/keyboard_constants.h8
-rw-r--r--chromium/ui/keyboard/keyboard_controller.cc411
-rw-r--r--chromium/ui/keyboard/keyboard_controller.h61
-rw-r--r--chromium/ui/keyboard/keyboard_controller_proxy.cc146
-rw-r--r--chromium/ui/keyboard/keyboard_controller_proxy.h78
-rw-r--r--chromium/ui/keyboard/keyboard_controller_unittest.cc427
-rw-r--r--chromium/ui/keyboard/keyboard_layout_manager.cc63
-rw-r--r--chromium/ui/keyboard/keyboard_layout_manager.h43
-rw-r--r--chromium/ui/keyboard/keyboard_resources.grd43
-rw-r--r--chromium/ui/keyboard/keyboard_switches.cc11
-rw-r--r--chromium/ui/keyboard/keyboard_switches.h20
-rw-r--r--chromium/ui/keyboard/keyboard_ui_controller.cc116
-rw-r--r--chromium/ui/keyboard/keyboard_ui_controller.h29
-rw-r--r--chromium/ui/keyboard/keyboard_ui_handler.cc142
-rw-r--r--chromium/ui/keyboard/keyboard_ui_handler.h45
-rw-r--r--chromium/ui/keyboard/keyboard_util.cc222
-rw-r--r--chromium/ui/keyboard/keyboard_util.h72
-rw-r--r--chromium/ui/keyboard/resources/api_adapter.js31
-rw-r--r--chromium/ui/keyboard/resources/constants.js100
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-container.html29
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-container.js35
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-data.html124
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-data.js126
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-set.html12
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey-set.js10
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey.html72
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-altkey.js52
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-base.html231
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-base.js228
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-codes.html225
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-codes.js227
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-import.html19
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-import.js22
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-sequence.html61
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key-sequence.js60
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key.html255
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-key.js114
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-keyboard.html970
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-keyboard.js977
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-keyset.html74
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-keyset.js104
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-modifier-key.html133
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-modifier-key.js135
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-options-menu.html111
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-row.html31
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-row.js8
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-shift-key.html275
-rw-r--r--chromium/ui/keyboard/resources/elements/kb-shift-key.js246
-rw-r--r--chromium/ui/keyboard/resources/images/back.svg2
-rw-r--r--chromium/ui/keyboard/resources/images/backspace.pngbin0 -> 494 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/down.svg2
-rw-r--r--chromium/ui/keyboard/resources/images/hide-keyboard.pngbin0 -> 395 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/left.svg2
-rw-r--r--chromium/ui/keyboard/resources/images/return.pngbin0 -> 423 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/right.svg2
-rw-r--r--chromium/ui/keyboard/resources/images/search.pngbin0 -> 707 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/search.svg14
-rw-r--r--chromium/ui/keyboard/resources/images/shift.pngbin0 -> 463 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/tab.pngbin0 -> 656 bytes
-rw-r--r--chromium/ui/keyboard/resources/images/up.svg2
-rw-r--r--chromium/ui/keyboard/resources/index.html48
-rw-r--r--chromium/ui/keyboard/resources/keyboard.js26
-rw-r--r--chromium/ui/keyboard/resources/layouts/dvorak.html10
-rw-r--r--chromium/ui/keyboard/resources/layouts/function-key-row.html32
-rw-r--r--chromium/ui/keyboard/resources/layouts/latin-accents.js2
-rw-r--r--chromium/ui/keyboard/resources/layouts/numeric.html43
-rw-r--r--chromium/ui/keyboard/resources/layouts/qwerty.html279
-rw-r--r--chromium/ui/keyboard/resources/layouts/spacebar-row.html2
-rw-r--r--chromium/ui/keyboard/resources/layouts/symbol-altkeys.js2
-rw-r--r--chromium/ui/keyboard/resources/layouts/system-qwerty.html208
-rw-r--r--chromium/ui/keyboard/resources/layouts/webui_qwerty.html122
-rw-r--r--chromium/ui/keyboard/resources/main.css66
-rw-r--r--chromium/ui/keyboard/resources/main.js635
-rw-r--r--chromium/ui/keyboard/resources/polymer_loader.js10
-rw-r--r--chromium/ui/keyboard/resources/roboto_bold.ttfbin0 -> 135820 bytes
-rw-r--r--chromium/ui/keyboard/resources/sounds/keypress-delete.wavbin0 -> 56208 bytes
-rw-r--r--chromium/ui/keyboard/resources/sounds/keypress-return.wavbin0 -> 13544 bytes
-rw-r--r--chromium/ui/keyboard/resources/sounds/keypress-spacebar.wavbin0 -> 20880 bytes
-rw-r--r--chromium/ui/keyboard/resources/sounds/keypress-standard.wavbin0 -> 21352 bytes
-rw-r--r--chromium/ui/keyboard/resources/touch_fuzzing.js449
-rw-r--r--chromium/ui/keyboard/resources/webui/api_adapter.js89
-rw-r--r--chromium/ui/keyboard/resources/webui/constants.js26
-rw-r--r--chromium/ui/keyboard/resources/webui/main.css172
-rw-r--r--chromium/ui/keyboard/resources/webui_index.html45
-rw-r--r--chromium/ui/message_center/DEPS2
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller.h4
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller.mm236
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller_unittest.mm153
-rw-r--r--chromium/ui/message_center/cocoa/opaque_views.h36
-rw-r--r--chromium/ui/message_center/cocoa/opaque_views.mm63
-rw-r--r--chromium/ui/message_center/cocoa/popup_collection.mm9
-rw-r--r--chromium/ui/message_center/cocoa/popup_collection_unittest.mm66
-rw-r--r--chromium/ui/message_center/cocoa/popup_controller.mm7
-rw-r--r--chromium/ui/message_center/cocoa/popup_controller_unittest.mm6
-rw-r--r--chromium/ui/message_center/cocoa/settings_controller.h5
-rw-r--r--chromium/ui/message_center/cocoa/settings_controller.mm28
-rw-r--r--chromium/ui/message_center/cocoa/settings_controller_unittest.mm2
-rw-r--r--chromium/ui/message_center/cocoa/settings_entry_view.mm24
-rw-r--r--chromium/ui/message_center/cocoa/status_item_view.h8
-rw-r--r--chromium/ui/message_center/cocoa/status_item_view.mm6
-rw-r--r--chromium/ui/message_center/cocoa/status_item_view_unittest.mm2
-rw-r--r--chromium/ui/message_center/cocoa/tray_controller_unittest.mm2
-rw-r--r--chromium/ui/message_center/cocoa/tray_view_controller.h8
-rw-r--r--chromium/ui/message_center/cocoa/tray_view_controller.mm82
-rw-r--r--chromium/ui/message_center/cocoa/tray_view_controller_unittest.mm60
-rw-r--r--chromium/ui/message_center/dummy_message_center.cc6
-rw-r--r--chromium/ui/message_center/fake_message_center.cc16
-rw-r--r--chromium/ui/message_center/fake_message_center.h8
-rw-r--r--chromium/ui/message_center/fake_message_center_tray_delegate.cc56
-rw-r--r--chromium/ui/message_center/fake_message_center_tray_delegate.h50
-rw-r--r--chromium/ui/message_center/fake_notifier_settings_provider.cc4
-rw-r--r--chromium/ui/message_center/message_center.gyp64
-rw-r--r--chromium/ui/message_center/message_center.h33
-rw-r--r--chromium/ui/message_center/message_center_impl.cc134
-rw-r--r--chromium/ui/message_center/message_center_impl.h26
-rw-r--r--chromium/ui/message_center/message_center_impl_unittest.cc161
-rw-r--r--chromium/ui/message_center/message_center_observer.h4
-rw-r--r--chromium/ui/message_center/message_center_style.cc28
-rw-r--r--chromium/ui/message_center/message_center_style.h16
-rw-r--r--chromium/ui/message_center/message_center_switches.cc17
-rw-r--r--chromium/ui/message_center/message_center_switches.h31
-rw-r--r--chromium/ui/message_center/message_center_tray.cc90
-rw-r--r--chromium/ui/message_center/message_center_tray.h14
-rw-r--r--chromium/ui/message_center/message_center_tray_delegate.h3
-rw-r--r--chromium/ui/message_center/message_center_tray_unittest.cc73
-rw-r--r--chromium/ui/message_center/message_center_types.h10
-rw-r--r--chromium/ui/message_center/message_center_util.cc39
-rw-r--r--chromium/ui/message_center/message_center_util.h24
-rw-r--r--chromium/ui/message_center/notification.cc18
-rw-r--r--chromium/ui/message_center/notification.h68
-rw-r--r--chromium/ui/message_center/notification_delegate.cc32
-rw-r--r--chromium/ui/message_center/notification_delegate.h26
-rw-r--r--chromium/ui/message_center/notification_delegate_unittest.cc71
-rw-r--r--chromium/ui/message_center/notification_list.cc19
-rw-r--r--chromium/ui/message_center/notification_list.h28
-rw-r--r--chromium/ui/message_center/notification_list_unittest.cc8
-rw-r--r--chromium/ui/message_center/notifier_settings.cc6
-rw-r--r--chromium/ui/message_center/notifier_settings.h24
-rw-r--r--chromium/ui/message_center/views/bounded_label.cc73
-rw-r--r--chromium/ui/message_center/views/bounded_label.h20
-rw-r--r--chromium/ui/message_center/views/bounded_label_unittest.cc18
-rw-r--r--chromium/ui/message_center/views/constants.h3
-rw-r--r--chromium/ui/message_center/views/group_view.cc280
-rw-r--r--chromium/ui/message_center/views/group_view.h77
-rw-r--r--chromium/ui/message_center/views/message_bubble_base.cc1
-rw-r--r--chromium/ui/message_center/views/message_center_bubble.cc15
-rw-r--r--chromium/ui/message_center/views/message_center_bubble.h2
-rw-r--r--chromium/ui/message_center/views/message_center_button_bar.cc51
-rw-r--r--chromium/ui/message_center/views/message_center_button_bar.h12
-rw-r--r--chromium/ui/message_center/views/message_center_controller.h15
-rw-r--r--chromium/ui/message_center/views/message_center_view.cc387
-rw-r--r--chromium/ui/message_center/views/message_center_view.h38
-rw-r--r--chromium/ui/message_center/views/message_center_view_unittest.cc67
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.cc142
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.h24
-rw-r--r--chromium/ui/message_center/views/message_popup_collection_unittest.cc10
-rw-r--r--chromium/ui/message_center/views/message_view.cc209
-rw-r--r--chromium/ui/message_center/views/message_view.h35
-rw-r--r--chromium/ui/message_center/views/message_view_context_menu_controller.cc45
-rw-r--r--chromium/ui/message_center/views/message_view_context_menu_controller.h34
-rw-r--r--chromium/ui/message_center/views/notification_button.cc20
-rw-r--r--chromium/ui/message_center/views/notification_button.h8
-rw-r--r--chromium/ui/message_center/views/notification_view.cc614
-rw-r--r--chromium/ui/message_center/views/notification_view.h49
-rw-r--r--chromium/ui/message_center/views/notification_view_unittest.cc323
-rw-r--r--chromium/ui/message_center/views/notifier_settings_view.cc66
-rw-r--r--chromium/ui/message_center/views/notifier_settings_view.h8
-rw-r--r--chromium/ui/message_center/views/padded_button.cc4
-rw-r--r--chromium/ui/message_center/views/padded_button.h4
-rw-r--r--chromium/ui/message_center/views/proportional_image_view.cc73
-rw-r--r--chromium/ui/message_center/views/proportional_image_view.h9
-rw-r--r--chromium/ui/message_center/views/toast_contents_view.cc96
-rw-r--r--chromium/ui/message_center/views/toast_contents_view.h21
-rw-r--r--chromium/ui/metro_viewer/BUILD.gn17
-rw-r--r--chromium/ui/metro_viewer/OWNERS6
-rw-r--r--chromium/ui/metro_viewer/ime_types.h2
-rw-r--r--chromium/ui/metro_viewer/metro_viewer_messages.h51
-rw-r--r--chromium/ui/native_theme/BUILD.gn56
-rw-r--r--chromium/ui/native_theme/common_theme.cc46
-rw-r--r--chromium/ui/native_theme/common_theme.h13
-rw-r--r--chromium/ui/native_theme/fallback_theme.cc112
-rw-r--r--chromium/ui/native_theme/native_theme.cc15
-rw-r--r--chromium/ui/native_theme/native_theme.gyp11
-rw-r--r--chromium/ui/native_theme/native_theme.h63
-rw-r--r--chromium/ui/native_theme/native_theme_android.cc2
-rw-r--r--chromium/ui/native_theme/native_theme_aura.cc380
-rw-r--r--chromium/ui/native_theme/native_theme_aura.h86
-rw-r--r--chromium/ui/native_theme/native_theme_aurawin.cc86
-rw-r--r--chromium/ui/native_theme/native_theme_aurawin.h37
-rw-r--r--chromium/ui/native_theme/native_theme_base.cc114
-rw-r--r--chromium/ui/native_theme/native_theme_base.h32
-rw-r--r--chromium/ui/native_theme/native_theme_gtk.cc108
-rw-r--r--chromium/ui/native_theme/native_theme_gtk.h28
-rw-r--r--chromium/ui/native_theme/native_theme_mac.h6
-rw-r--r--chromium/ui/native_theme/native_theme_mac.mm3
-rw-r--r--chromium/ui/native_theme/native_theme_observer.cc11
-rw-r--r--chromium/ui/native_theme/native_theme_observer.h27
-rw-r--r--chromium/ui/native_theme/native_theme_switches.cc31
-rw-r--r--chromium/ui/native_theme/native_theme_switches.h25
-rw-r--r--chromium/ui/native_theme/native_theme_win.cc129
-rw-r--r--chromium/ui/native_theme/native_theme_win.h9
-rw-r--r--chromium/ui/native_theme/native_theme_win_unittest.cc15
-rw-r--r--chromium/ui/oak/DEPS10
-rw-r--r--chromium/ui/oak/oak.gyp48
-rw-r--r--chromium/ui/oak/oak.h17
-rw-r--r--chromium/ui/oak/oak_aura_window_display.cc164
-rw-r--r--chromium/ui/oak/oak_aura_window_display.h37
-rw-r--r--chromium/ui/oak/oak_details_model.h33
-rw-r--r--chromium/ui/oak/oak_export.h32
-rw-r--r--chromium/ui/oak/oak_pretty_print.cc43
-rw-r--r--chromium/ui/oak/oak_pretty_print.h31
-rw-r--r--chromium/ui/oak/oak_tree_model.cc39
-rw-r--r--chromium/ui/oak/oak_tree_model.h26
-rw-r--r--chromium/ui/oak/oak_window.cc159
-rw-r--r--chromium/ui/oak/oak_window.h67
-rw-r--r--chromium/ui/ozone/BUILD.gn56
-rw-r--r--chromium/ui/ozone/DEPS2
-rw-r--r--chromium/ui/ozone/OWNERS1
-rw-r--r--chromium/ui/ozone/common/README2
-rw-r--r--chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.cc95
-rw-r--r--chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.h51
-rw-r--r--chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.cc20
-rw-r--r--chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h27
-rwxr-xr-xchromium/ui/ozone/generate_constructor_list.py169
-rwxr-xr-xchromium/ui/ozone/generate_ozone_platform_list.py142
-rw-r--r--chromium/ui/ozone/ozone.gni18
-rw-r--r--chromium/ui/ozone/ozone.gyp164
-rw-r--r--chromium/ui/ozone/ozone_base_export.h29
-rw-r--r--chromium/ui/ozone/ozone_platform.cc76
-rw-r--r--chromium/ui/ozone/ozone_platform.h37
-rw-r--r--chromium/ui/ozone/ozone_platform_list.h25
-rw-r--r--chromium/ui/ozone/platform/README2
-rw-r--r--chromium/ui/ozone/platform/caca/DEPS3
-rw-r--r--chromium/ui/ozone/platform/caca/OWNERS1
-rw-r--r--chromium/ui/ozone/platform/caca/caca.gypi45
-rw-r--r--chromium/ui/ozone/platform/caca/caca_connection.cc40
-rw-r--r--chromium/ui/ozone/platform/caca/caca_connection.h47
-rw-r--r--chromium/ui/ozone/platform/caca/caca_event_factory.cc232
-rw-r--r--chromium/ui/ozone/platform/caca/caca_event_factory.h54
-rw-r--r--chromium/ui/ozone/platform/caca/caca_surface_factory.cc147
-rw-r--r--chromium/ui/ozone/platform/caca/caca_surface_factory.h46
-rw-r--r--chromium/ui/ozone/platform/caca/ozone_platform_caca.cc77
-rw-r--r--chromium/ui/ozone/platform/caca/ozone_platform_caca.h17
-rw-r--r--chromium/ui/ozone/platform/dri/DEPS4
-rw-r--r--chromium/ui/ozone/platform/dri/OWNERS1
-rw-r--r--chromium/ui/ozone/platform/dri/buffer_data.cc71
-rw-r--r--chromium/ui/ozone/platform/dri/buffer_data.h53
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/DEPS3
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.cc17
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.h33
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.cc127
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.h47
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.cc189
-rw-r--r--chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h78
-rw-r--r--chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.cc67
-rw-r--r--chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.h58
-rw-r--r--chromium/ui/ozone/platform/dri/dri.gypi97
-rw-r--r--chromium/ui/ozone/platform/dri/dri_buffer.cc140
-rw-r--r--chromium/ui/ozone/platform/dri/dri_buffer.h57
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface.cc80
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface.h64
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface_factory.cc252
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface_factory.h85
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface_factory_unittest.cc202
-rw-r--r--chromium/ui/ozone/platform/dri/dri_surface_unittest.cc118
-rw-r--r--chromium/ui/ozone/platform/dri/dri_util.cc125
-rw-r--r--chromium/ui/ozone/platform/dri/dri_util.h44
-rw-r--r--chromium/ui/ozone/platform/dri/dri_vsync_provider.cc38
-rw-r--r--chromium/ui/ozone/platform/dri/dri_vsync_provider.h30
-rw-r--r--chromium/ui/ozone/platform/dri/dri_wrapper.cc164
-rw-r--r--chromium/ui/ozone/platform/dri/dri_wrapper.h127
-rw-r--r--chromium/ui/ozone/platform/dri/gbm.gypi43
-rw-r--r--chromium/ui/ozone/platform/dri/gbm_surface.cc112
-rw-r--r--chromium/ui/ozone/platform/dri/gbm_surface.h75
-rw-r--r--chromium/ui/ozone/platform/dri/gbm_surface_factory.cc187
-rw-r--r--chromium/ui/ozone/platform/dri/gbm_surface_factory.h42
-rw-r--r--chromium/ui/ozone/platform/dri/hardware_display_controller.cc168
-rw-r--r--chromium/ui/ozone/platform/dri/hardware_display_controller.h182
-rw-r--r--chromium/ui/ozone/platform/dri/hardware_display_controller_unittest.cc112
-rw-r--r--chromium/ui/ozone/platform/dri/ozone_platform_dri.cc112
-rw-r--r--chromium/ui/ozone/platform/dri/ozone_platform_dri.h23
-rw-r--r--chromium/ui/ozone/platform/dri/ozone_platform_gbm.cc146
-rw-r--r--chromium/ui/ozone/platform/dri/ozone_platform_gbm.h17
-rw-r--r--chromium/ui/ozone/platform/dri/scanout_surface.h84
-rw-r--r--chromium/ui/ozone/platform/dri/screen_manager.cc137
-rw-r--r--chromium/ui/ozone/platform/dri/screen_manager.h83
-rw-r--r--chromium/ui/ozone/platform/dri/screen_manager_unittest.cc116
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_dri_surface.cc53
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_dri_surface.h45
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.cc113
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.h85
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_surface_generator.cc18
-rw-r--r--chromium/ui/ozone/platform/dri/test/mock_surface_generator.h40
-rw-r--r--chromium/ui/ozone/platform/dri/virtual_terminal_manager.cc75
-rw-r--r--chromium/ui/ozone/platform/dri/virtual_terminal_manager.h31
-rw-r--r--chromium/ui/ozone/platform/egltest/eglplatform_shim.h58
-rw-r--r--chromium/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc106
-rw-r--r--chromium/ui/ozone/platform/egltest/egltest.gypi107
-rw-r--r--chromium/ui/ozone/platform/egltest/ozone_platform_egltest.cc304
-rw-r--r--chromium/ui/ozone/platform/egltest/ozone_platform_egltest.h17
-rw-r--r--chromium/ui/ozone/platform/test/DEPS3
-rw-r--r--chromium/ui/ozone/platform/test/file_surface_factory.cc98
-rw-r--r--chromium/ui/ozone/platform/test/file_surface_factory.h38
-rw-r--r--chromium/ui/ozone/platform/test/ozone_platform_test.cc75
-rw-r--r--chromium/ui/ozone/platform/test/ozone_platform_test.h23
-rw-r--r--chromium/ui/ozone/platform/test/test.gypi35
-rw-r--r--chromium/ui/ozone/platform_constructor_list.h21
-rw-r--r--chromium/ui/ozone/platform_object.h34
-rw-r--r--chromium/ui/ozone/platform_object_internal.h31
-rw-r--r--chromium/ui/ozone/platform_selection.cc52
-rw-r--r--chromium/ui/ozone/platform_selection.h21
-rw-r--r--chromium/ui/ozone/public/DEPS3
-rw-r--r--chromium/ui/ozone/public/README2
-rw-r--r--chromium/ui/ozone/public/cursor_factory_ozone.cc59
-rw-r--r--chromium/ui/ozone/public/cursor_factory_ozone.h59
-rw-r--r--chromium/ui/ozone/public/event_factory_ozone.cc34
-rw-r--r--chromium/ui/ozone/public/event_factory_ozone.h50
-rw-r--r--chromium/ui/ozone/public/gpu_platform_support.cc34
-rw-r--r--chromium/ui/ozone/public/gpu_platform_support.h31
-rw-r--r--chromium/ui/ozone/public/gpu_platform_support_host.cc37
-rw-r--r--chromium/ui/ozone/public/gpu_platform_support_host.h40
-rw-r--r--chromium/ui/ozone/public/overlay_candidates_ozone.cc28
-rw-r--r--chromium/ui/ozone/public/overlay_candidates_ozone.h56
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.cc75
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.h163
-rw-r--r--chromium/ui/ozone/public/surface_ozone_canvas.h56
-rw-r--r--chromium/ui/ozone/public/surface_ozone_egl.h49
-rw-r--r--chromium/ui/ozone/run_all_unittests.cc45
-rw-r--r--chromium/ui/resources/BUILD.gn15
-rw-r--r--chromium/ui/resources/default_100_percent/ash/status_network.pngbin437 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/ash/status_volume.pngbin388 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/app_list_apps_icon.pngbin0 -> 108 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/app_list_experimental_icon.pngbin0 -> 523 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/app_list_notifications_icon.pngbin0 -> 305 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/app_list_search_icon.pngbin0 -> 866 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/app_list_user_indicator.png (renamed from chromium/ui/resources/default_100_percent/win/app_list_user_indicator.png)bin143 -> 143 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_center.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_center.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_center.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_center.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.pngbin0 -> 75 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_center.pngbin0 -> 69 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_left.pngbin0 -> 70 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_right.pngbin0 -> 70 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.pngbin0 -> 67 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_left.pngbin0 -> 67 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_right.pngbin0 -> 67 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top.pngbin0 -> 67 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_center.pngbin0 -> 74 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_left.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_right.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_left.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_center.pngbin0 -> 74 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_left.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_right.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_left.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_center.pngbin0 -> 74 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_left.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_right.pngbin0 -> 76 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_left.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_right.pngbin0 -> 77 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/back_arrow.pngbin0 -> 1402 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/buy_with_google_button.pngbin1815 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/buy_with_google_button_hover.pngbin1815 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/buy_with_google_button_pressed.pngbin1811 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/forward_arrow.pngbin0 -> 1409 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/menu_overflow_down.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/menu_overflow_up.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_bubble_close.pngbin0 -> 139 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_bubble_close_hover.pngbin0 -> 214 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_bubble_close_pressed.pngbin0 -> 214 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_expand.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_expand_hover.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_expand_pressed.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/pointers/xterm.pngbin165 -> 166 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.pngbin179 -> 164 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/text_selection_handle.pngbin1650 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_center.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_left.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_right.pngbin80 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_bottom.pngbin80 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_center.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_top.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.pngbin110 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.pngbin106 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_top.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_top.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.pngbin106 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/oak.pngbin165 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/radialmenu_back.pngbin599 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/radialmenu_forward.pngbin588 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/radialmenu_options.pngbin407 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/radialmenu_reload.pngbin854 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/app_list_apps_icon.pngbin0 -> 137 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/app_list_experimental_icon.pngbin0 -> 707 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/app_list_notifications_icon.pngbin0 -> 550 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/app_list_search_icon.pngbin0 -> 2208 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/app_list_user_indicator.png (renamed from chromium/ui/resources/default_200_percent/win/app_list_user_indicator.png)bin465 -> 465 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_center.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_center.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_center.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_center.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_left.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_right.pngbin0 -> 72 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.pngbin0 -> 73 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.pngbin0 -> 83 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_center.pngbin0 -> 73 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_left.pngbin0 -> 73 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_right.pngbin0 -> 73 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top.pngbin0 -> 73 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.pngbin0 -> 84 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.pngbin0 -> 85 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.pngbin0 -> 95 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.pngbin0 -> 97 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_left.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_right.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top.pngbin0 -> 71 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.pngbin0 -> 94 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.pngbin0 -> 94 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_center.pngbin0 -> 75 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_right.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_left.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_right.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_center.pngbin0 -> 75 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_right.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_left.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_right.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.pngbin0 -> 80 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_center.pngbin0 -> 75 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_left.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_right.pngbin0 -> 78 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_left.pngbin0 -> 81 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_right.pngbin0 -> 79 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/back_arrow.pngbin0 -> 4934 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/buy_with_google_button.pngbin5121 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/buy_with_google_button_hover.pngbin5123 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/buy_with_google_button_pressed.pngbin5183 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/forward_arrow.pngbin0 -> 4976 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/menu_overflow_down.pngbin143 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/menu_overflow_up.pngbin137 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_bubble_close.pngbin0 -> 205 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_bubble_close_hover.pngbin0 -> 380 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_bubble_close_pressed.pngbin0 -> 379 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_expand.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_expand_hover.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_expand_pressed.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/pointers/xterm.pngbin285 -> 295 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.pngbin298 -> 369 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/text_selection_handle.pngbin4156 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_center.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_left.pngbin101 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_right.pngbin89 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_bottom.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_center.pngbin378 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_top.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_bottom.pngbin80 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_top.pngbin74 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.pngbin116 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.pngbin139 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.pngbin132 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.pngbin119 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.pngbin147 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.pngbin133 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.pngbin139 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.pngbin140 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.pngbin138 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_center.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_top.pngbin134 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.pngbin141 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_center.pngbin128 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_top.pngbin134 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.pngbin137 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.pngbin134 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom.pngbin83 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.pngbin109 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.pngbin110 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_center.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_left.pngbin148 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_right.pngbin144 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_top.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_left.pngbin102 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_right.pngbin101 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_center.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_left.pngbin118 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_right.pngbin117 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.pngbin107 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.pngbin104 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_center.pngbin169 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_left.pngbin97 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right.pngbin101 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right_fix.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_center.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_left.pngbin78 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_right.pngbin78 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_hover_edge.pngbin153 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_normal_edge.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom_fix.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_center.pngbin176 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_top.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_bottom.pngbin77 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_center.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_top.pngbin72 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_left.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_left.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_center.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_left.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_bottom.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_top.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_bottom.pngbin113 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_top.pngbin106 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_bottom.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_center.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_top.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_bottom.pngbin83 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_left.pngbin104 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_right.pngbin110 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_center.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_left.pngbin141 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_right.pngbin131 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_top.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_top_left.pngbin97 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_hover_top_right.pngbin102 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_left.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_center.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_left.pngbin118 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_right.pngbin117 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_top.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_top_left.pngbin107 -> 0 bytes
-rw-r--r--chromium/ui/resources/touch_100_percent/textbutton_pressed_top_right.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/resources/ui_resources.grd684
-rw-r--r--chromium/ui/resources/ui_resources.gyp65
-rw-r--r--chromium/ui/shell_dialogs/DEPS1
-rw-r--r--chromium/ui/shell_dialogs/base_shell_dialog_win.cc4
-rw-r--r--chromium/ui/shell_dialogs/gtk/OWNERS2
-rw-r--r--chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.cc92
-rw-r--r--chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.h89
-rw-r--r--chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_gtk.cc596
-rw-r--r--chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_kde.cc485
-rw-r--r--chromium/ui/shell_dialogs/print_settings_dialog_win.cc58
-rw-r--r--chromium/ui/shell_dialogs/print_settings_dialog_win.h83
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog.cc13
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_android.cc9
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_android.h3
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.cc74
-rw-r--r--chromium/ui/shell_dialogs/shell_dialogs.gyp33
-rw-r--r--chromium/ui/snapshot/BUILD.gn95
-rw-r--r--chromium/ui/snapshot/DEPS3
-rw-r--r--chromium/ui/snapshot/snapshot.gyp26
-rw-r--r--chromium/ui/snapshot/snapshot.h42
-rw-r--r--chromium/ui/snapshot/snapshot_android.cc75
-rw-r--r--chromium/ui/snapshot/snapshot_async.cc103
-rw-r--r--chromium/ui/snapshot/snapshot_async.h42
-rw-r--r--chromium/ui/snapshot/snapshot_aura.cc108
-rw-r--r--chromium/ui/snapshot/snapshot_aura_unittest.cc120
-rw-r--r--chromium/ui/snapshot/snapshot_gtk.cc85
-rw-r--r--chromium/ui/snapshot/snapshot_ios.mm27
-rw-r--r--chromium/ui/snapshot/snapshot_mac.mm29
-rw-r--r--chromium/ui/snapshot/snapshot_win.cc29
-rw-r--r--chromium/ui/strings/BUILD.gn22
-rw-r--r--chromium/ui/strings/OWNERS (renamed from chromium/ui/base/strings/OWNERS)0
-rw-r--r--chromium/ui/strings/app_locale_settings.grd263
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_am.xtb8
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ar.xtb9
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_bg.xtb (renamed from chromium/ui/base/strings/app_locale_settings_bg.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_bn.xtb20
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ca.xtb (renamed from chromium/ui/base/strings/app_locale_settings_ca.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_cs.xtb (renamed from chromium/ui/base/strings/app_locale_settings_cs.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_da.xtb (renamed from chromium/ui/base/strings/app_locale_settings_da.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_de.xtb (renamed from chromium/ui/base/strings/app_locale_settings_de.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_el.xtb (renamed from chromium/ui/base/strings/app_locale_settings_el.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_en-GB.xtb (renamed from chromium/ui/base/strings/app_locale_settings_en-GB.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_es-419.xtb (renamed from chromium/ui/base/strings/app_locale_settings_es-419.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_es.xtb (renamed from chromium/ui/base/strings/app_locale_settings_es.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_et.xtb (renamed from chromium/ui/base/strings/app_locale_settings_et.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_fa.xtb (renamed from chromium/ui/base/strings/app_locale_settings_fa.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_fi.xtb (renamed from chromium/ui/base/strings/app_locale_settings_fi.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_fil.xtb (renamed from chromium/ui/base/strings/app_locale_settings_fil.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_fr.xtb (renamed from chromium/ui/base/strings/app_locale_settings_fr.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_gu.xtb (renamed from chromium/ui/base/strings/app_locale_settings_gu.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_he.xtb (renamed from chromium/ui/base/strings/app_locale_settings_he.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_hi.xtb11
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_hr.xtb (renamed from chromium/ui/base/strings/app_locale_settings_hr.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_hu.xtb (renamed from chromium/ui/base/strings/app_locale_settings_hu.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_id.xtb (renamed from chromium/ui/base/strings/app_locale_settings_id.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_it.xtb (renamed from chromium/ui/base/strings/app_locale_settings_it.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ja.xtb22
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_kn.xtb13
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ko.xtb19
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_lt.xtb (renamed from chromium/ui/base/strings/app_locale_settings_lt.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_lv.xtb (renamed from chromium/ui/base/strings/app_locale_settings_lv.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ml.xtb19
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_mr.xtb11
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ms.xtb (renamed from chromium/ui/base/strings/app_locale_settings_ms.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_nb.xtb (renamed from chromium/ui/base/strings/app_locale_settings_nb.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_nl.xtb (renamed from chromium/ui/base/strings/app_locale_settings_nl.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_pl.xtb (renamed from chromium/ui/base/strings/app_locale_settings_pl.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_pt-BR.xtb (renamed from chromium/ui/base/strings/app_locale_settings_pt-BR.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_pt-PT.xtb (renamed from chromium/ui/base/strings/app_locale_settings_pt-PT.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ro.xtb (renamed from chromium/ui/base/strings/app_locale_settings_ro.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ru.xtb (renamed from chromium/ui/base/strings/app_locale_settings_ru.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_sk.xtb (renamed from chromium/ui/base/strings/app_locale_settings_sk.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_sl.xtb (renamed from chromium/ui/base/strings/app_locale_settings_sl.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_sr.xtb (renamed from chromium/ui/base/strings/app_locale_settings_sr.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_sv.xtb (renamed from chromium/ui/base/strings/app_locale_settings_sv.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_sw.xtb (renamed from chromium/ui/base/strings/app_locale_settings_sw.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_ta.xtb8
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_te.xtb13
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_th.xtb16
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_tr.xtb (renamed from chromium/ui/base/strings/app_locale_settings_tr.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_uk.xtb (renamed from chromium/ui/base/strings/app_locale_settings_uk.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_vi.xtb (renamed from chromium/ui/base/strings/app_locale_settings_vi.xtb)0
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_zh-CN.xtb19
-rw-r--r--chromium/ui/strings/translations/app_locale_settings_zh-TW.xtb19
-rw-r--r--chromium/ui/strings/translations/ui_strings_am.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ar.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_bg.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_bn.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ca.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_cs.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_da.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_de.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_el.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_en-GB.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_es-419.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_es.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_et.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_fa.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_fi.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_fil.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_gu.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_hi.xtb223
-rw-r--r--chromium/ui/strings/translations/ui_strings_hr.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_hu.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_id.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_it.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_iw.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ja.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_kn.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ko.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_lt.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_lv.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ml.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_mr.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ms.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_nl.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_no.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_pl.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-BR.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-PT.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ro.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_sk.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_sl.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_sv.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_sw.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_ta.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_te.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_th.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_tr.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_uk.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_vi.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-CN.xtb221
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-TW.xtb221
-rw-r--r--chromium/ui/strings/ui_strings.grd2198
-rw-r--r--chromium/ui/strings/ui_strings.gyp40
-rw-r--r--chromium/ui/surface/BUILD.gn32
-rw-r--r--chromium/ui/surface/DEPS1
-rw-r--r--chromium/ui/surface/accelerated_surface_mac.cc33
-rw-r--r--chromium/ui/surface/accelerated_surface_mac.h3
-rw-r--r--chromium/ui/surface/accelerated_surface_transformer_win.cc736
-rw-r--r--chromium/ui/surface/accelerated_surface_transformer_win.h228
-rw-r--r--chromium/ui/surface/accelerated_surface_transformer_win.hlsl300
-rw-r--r--chromium/ui/surface/accelerated_surface_transformer_win_unittest.cc895
-rw-r--r--chromium/ui/surface/accelerated_surface_win.cc1108
-rw-r--r--chromium/ui/surface/accelerated_surface_win.h222
-rw-r--r--chromium/ui/surface/compile_hlsl.py160
-rw-r--r--chromium/ui/surface/d3d9_utils_win.cc168
-rw-r--r--chromium/ui/surface/d3d9_utils_win.h87
-rw-r--r--chromium/ui/surface/surface.gyp92
-rw-r--r--chromium/ui/surface/surface_switches.cc19
-rw-r--r--chromium/ui/surface/surface_switches.h19
-rw-r--r--chromium/ui/surface/transport_dib.h74
-rw-r--r--chromium/ui/surface/transport_dib_gtk.cc158
-rw-r--r--chromium/ui/surface/transport_dib_posix.cc6
-rw-r--r--chromium/ui/ui.gyp702
-rw-r--r--chromium/ui/ui_unittests.gyp234
-rw-r--r--chromium/ui/ui_unittests.isolate3
-rw-r--r--chromium/ui/ui_unittests_bundle.gypi55
-rw-r--r--chromium/ui/v2/OWNERS2
-rw-r--r--chromium/ui/v2/src/v2_unittest.cc16
-rw-r--r--chromium/ui/v2/src/v2_unittests.cc16
-rw-r--r--chromium/ui/v2/v2.gyp4
-rw-r--r--chromium/ui/views/DEPS9
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc130
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.h83
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_wrapper.h43
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc91
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.h38
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc55
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h44
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc64
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h42
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility.h4
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_win.cc297
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_win.h57
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc112
-rw-r--r--chromium/ui/views/accessible_pane_view.cc6
-rw-r--r--chromium/ui/views/accessible_pane_view.h2
-rw-r--r--chromium/ui/views/accessible_pane_view_unittest.cc4
-rw-r--r--chromium/ui/views/animation/bounds_animator.cc15
-rw-r--r--chromium/ui/views/animation/bounds_animator.h27
-rw-r--r--chromium/ui/views/animation/bounds_animator_unittest.cc15
-rw-r--r--chromium/ui/views/background.cc5
-rw-r--r--chromium/ui/views/border.cc39
-rw-r--r--chromium/ui/views/border.h33
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc3
-rw-r--r--chromium/ui/views/bubble/bubble_border.h8
-rw-r--r--chromium/ui/views/bubble/bubble_delegate.cc117
-rw-r--r--chromium/ui/views/bubble/bubble_delegate.h42
-rw-r--r--chromium/ui/views/bubble/bubble_delegate_unittest.cc75
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc101
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h19
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc3
-rw-r--r--chromium/ui/views/bubble/bubble_window_targeter.cc30
-rw-r--r--chromium/ui/views/bubble/bubble_window_targeter.h33
-rw-r--r--chromium/ui/views/bubble/bubble_window_targeter_unittest.cc116
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.cc44
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.h19
-rw-r--r--chromium/ui/views/button_drag_utils.cc27
-rw-r--r--chromium/ui/views/button_drag_utils.h15
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.h33
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.mm50
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.h62
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.mm78
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm117
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc31
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.h2
-rw-r--r--chromium/ui/views/controls/button/blue_button.cc83
-rw-r--r--chromium/ui/views/controls/button/blue_button.h1
-rw-r--r--chromium/ui/views/controls/button/blue_button_unittest.cc59
-rw-r--r--chromium/ui/views/controls/button/button.cc28
-rw-r--r--chromium/ui/views/controls/button/button.h16
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc14
-rw-r--r--chromium/ui/views/controls/button/checkbox.h4
-rw-r--r--chromium/ui/views/controls/button/custom_button.cc15
-rw-r--r--chromium/ui/views/controls/button/custom_button.h6
-rw-r--r--chromium/ui/views/controls/button/custom_button_unittest.cc24
-rw-r--r--chromium/ui/views/controls/button/image_button.cc23
-rw-r--r--chromium/ui/views/controls/button/image_button.h17
-rw-r--r--chromium/ui/views/controls/button/image_button_unittest.cc25
-rw-r--r--chromium/ui/views/controls/button/label_button.cc161
-rw-r--r--chromium/ui/views/controls/button/label_button.h54
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc50
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc53
-rw-r--r--chromium/ui/views/controls/button/menu_button.cc62
-rw-r--r--chromium/ui/views/controls/button/menu_button.h18
-rw-r--r--chromium/ui/views/controls/button/menu_button_unittest.cc199
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc10
-rw-r--r--chromium/ui/views/controls/button/radio_button.h6
-rw-r--r--chromium/ui/views/controls/button/text_button.cc185
-rw-r--r--chromium/ui/views/controls/button/text_button.h72
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc244
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h53
-rw-r--r--chromium/ui/views/controls/combobox/combobox_listener.h21
-rw-r--r--chromium/ui/views/controls/combobox/combobox_unittest.cc244
-rw-r--r--chromium/ui/views/controls/image_view.cc42
-rw-r--r--chromium/ui/views/controls/image_view.h16
-rw-r--r--chromium/ui/views/controls/label.cc261
-rw-r--r--chromium/ui/views/controls/label.h169
-rw-r--r--chromium/ui/views/controls/label_unittest.cc477
-rw-r--r--chromium/ui/views/controls/link.cc115
-rw-r--r--chromium/ui/views/controls/link.h26
-rw-r--r--chromium/ui/views/controls/menu/display_change_listener_mac.cc16
-rw-r--r--chromium/ui/views/controls/menu/menu.cc26
-rw-r--r--chromium/ui/views/controls/menu/menu.h30
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc13
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h17
-rw-r--r--chromium/ui/views/controls/menu/menu_config_aura.cc62
-rw-r--r--chromium/ui/views/controls/menu/menu_config_mac.cc26
-rw-r--r--chromium/ui/views/controls/menu/menu_config_views.cc66
-rw-r--r--chromium/ui/views/controls/menu/menu_config_win.cc21
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc376
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h63
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_aura.cc115
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc267
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_win.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc29
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h34
-rw-r--r--chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc91
-rw-r--r--chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h32
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc20
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.cc9
-rw-r--r--chromium/ui/views/controls/menu/menu_image_util.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc238
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h98
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop.h57
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.cc202
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.h52
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.cc51
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.h35
-rw-r--r--chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc95
-rw-r--r--chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h36
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc32
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.h7
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc11
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.cc32
-rw-r--r--chromium/ui/views/controls/menu/menu_runner.h15
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_handler.h4
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc43
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.h11
-rw-r--r--chromium/ui/views/controls/menu/menu_separator.h6
-rw-r--r--chromium/ui/views/controls/menu/menu_separator_views.cc4
-rw-r--r--chromium/ui/views/controls/menu/menu_separator_win.cc11
-rw-r--r--chromium/ui/views/controls/menu/menu_types.h26
-rw-r--r--chromium/ui/views/controls/menu/menu_win.cc572
-rw-r--r--chromium/ui/views/controls/menu/menu_win.h139
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc40
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.h4
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc68
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h30
-rw-r--r--chromium/ui/views/controls/message_box_view.cc43
-rw-r--r--chromium/ui/views/controls/message_box_view.h14
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc20
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h6
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc7
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.h1
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura_unittest.cc19
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.cc18
-rw-r--r--chromium/ui/views/controls/native/native_view_host_unittest.cc15
-rw-r--r--chromium/ui/views/controls/native/native_view_host_win.cc157
-rw-r--r--chromium/ui/views/controls/native/native_view_host_win.h47
-rw-r--r--chromium/ui/views/controls/native/native_view_host_wrapper.h4
-rw-r--r--chromium/ui/views/controls/native_control.cc389
-rw-r--r--chromium/ui/views/controls/native_control.h126
-rw-r--r--chromium/ui/views/controls/native_control_win.cc226
-rw-r--r--chromium/ui/views/controls/native_control_win.h99
-rw-r--r--chromium/ui/views/controls/prefix_delegate.h2
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc25
-rw-r--r--chromium/ui/views/controls/prefix_selector.h15
-rw-r--r--chromium/ui/views/controls/prefix_selector_unittest.cc6
-rw-r--r--chromium/ui/views/controls/progress_bar.cc21
-rw-r--r--chromium/ui/views/controls/progress_bar.h10
-rw-r--r--chromium/ui/views/controls/progress_bar_unittest.cc16
-rw-r--r--chromium/ui/views/controls/resize_area.cc22
-rw-r--r--chromium/ui/views/controls/resize_area.h2
-rw-r--r--chromium/ui/views/controls/scroll_view.cc54
-rw-r--r--chromium/ui/views/controls/scroll_view.h15
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc103
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.cc39
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.h10
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc5
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc309
-rw-r--r--chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h91
-rw-r--r--chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc6
-rw-r--r--chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar.cc7
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc10
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc16
-rw-r--r--chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar.cc6
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc11
-rw-r--r--chromium/ui/views/controls/separator.cc10
-rw-r--r--chromium/ui/views/controls/separator.h7
-rw-r--r--chromium/ui/views/controls/single_split_view.cc28
-rw-r--r--chromium/ui/views/controls/single_split_view.h8
-rw-r--r--chromium/ui/views/controls/single_split_view_listener.h4
-rw-r--r--chromium/ui/views/controls/single_split_view_unittest.cc58
-rw-r--r--chromium/ui/views/controls/slide_out_view.cc26
-rw-r--r--chromium/ui/views/controls/slider.cc77
-rw-r--r--chromium/ui/views/controls/slider.h26
-rw-r--r--chromium/ui/views/controls/slider_unittest.cc382
-rw-r--r--chromium/ui/views/controls/styled_label.cc147
-rw-r--r--chromium/ui/views/controls/styled_label.h29
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc161
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc42
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.h8
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h4
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc4
-rw-r--r--chromium/ui/views/controls/table/table_grouper.h6
-rw-r--r--chromium/ui/views/controls/table/table_header.cc33
-rw-r--r--chromium/ui/views/controls/table/table_header.h8
-rw-r--r--chromium/ui/views/controls/table/table_utils.cc25
-rw-r--r--chromium/ui/views/controls/table/table_utils.h18
-rw-r--r--chromium/ui/views/controls/table/table_utils_unittest.cc70
-rw-r--r--chromium/ui/views/controls/table/table_view.cc31
-rw-r--r--chromium/ui/views/controls/table/table_view.h10
-rw-r--r--chromium/ui/views/controls/table/table_view_observer.h3
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc23
-rw-r--r--chromium/ui/views/controls/table/test_table_model.cc6
-rw-r--r--chromium/ui/views/controls/table/test_table_model.h2
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_views.cc1545
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_views.h345
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc1992
-rw-r--r--chromium/ui/views/controls/textfield/native_textfield_wrapper.h188
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc1817
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h450
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.cc16
-rw-r--r--chromium/ui/views/controls/textfield/textfield_controller.h24
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc771
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.h292
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc1482
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.cc30
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.h43
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc2012
-rw-r--r--chromium/ui/views/controls/textfield/textfield_views_model.cc799
-rw-r--r--chromium/ui/views/controls/textfield/textfield_views_model.h313
-rw-r--r--chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc1516
-rw-r--r--chromium/ui/views/controls/throbber.cc2
-rw-r--r--chromium/ui/views/controls/throbber.h2
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc44
-rw-r--r--chromium/ui/views/controls/tree/tree_view.h21
-rw-r--r--chromium/ui/views/controls/tree/tree_view_unittest.cc14
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc4
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc44
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h20
-rw-r--r--chromium/ui/views/controls/webview/webview.cc236
-rw-r--r--chromium/ui/views/controls/webview/webview.gyp3
-rw-r--r--chromium/ui/views/controls/webview/webview.h51
-rw-r--r--chromium/ui/views/controls/webview/webview_interactive_uitest.cc82
-rw-r--r--chromium/ui/views/controls/webview/webview_tests.gyp38
-rw-r--r--chromium/ui/views/corewm/DEPS61
-rw-r--r--chromium/ui/views/corewm/base_focus_rules.cc196
-rw-r--r--chromium/ui/views/corewm/base_focus_rules.h47
-rw-r--r--chromium/ui/views/corewm/capture_controller.cc145
-rw-r--r--chromium/ui/views/corewm/capture_controller.h88
-rw-r--r--chromium/ui/views/corewm/capture_controller_unittest.cc82
-rw-r--r--chromium/ui/views/corewm/compound_event_filter.cc279
-rw-r--r--chromium/ui/views/corewm/compound_event_filter.h93
-rw-r--r--chromium/ui/views/corewm/compound_event_filter_unittest.cc205
-rw-r--r--chromium/ui/views/corewm/corewm_switches.cc21
-rw-r--r--chromium/ui/views/corewm/corewm_switches.h27
-rw-r--r--chromium/ui/views/corewm/cursor_height_provider_win.cc146
-rw-r--r--chromium/ui/views/corewm/cursor_height_provider_win.h21
-rw-r--r--chromium/ui/views/corewm/cursor_manager.cc235
-rw-r--r--chromium/ui/views/corewm/cursor_manager.h92
-rw-r--r--chromium/ui/views/corewm/cursor_manager_unittest.cc353
-rw-r--r--chromium/ui/views/corewm/desktop_capture_controller_unittest.cc60
-rw-r--r--chromium/ui/views/corewm/focus_controller.cc365
-rw-r--r--chromium/ui/views/corewm/focus_controller.h130
-rw-r--r--chromium/ui/views/corewm/focus_controller_unittest.cc1110
-rw-r--r--chromium/ui/views/corewm/focus_rules.h68
-rw-r--r--chromium/ui/views/corewm/image_grid.cc308
-rw-r--r--chromium/ui/views/corewm/image_grid.h228
-rw-r--r--chromium/ui/views/corewm/image_grid_unittest.cc341
-rw-r--r--chromium/ui/views/corewm/input_method_event_filter.cc81
-rw-r--r--chromium/ui/views/corewm/input_method_event_filter.h58
-rw-r--r--chromium/ui/views/corewm/input_method_event_filter_unittest.cc91
-rw-r--r--chromium/ui/views/corewm/native_cursor_manager.h67
-rw-r--r--chromium/ui/views/corewm/native_cursor_manager_delegate.h36
-rw-r--r--chromium/ui/views/corewm/shadow.cc195
-rw-r--r--chromium/ui/views/corewm/shadow.h88
-rw-r--r--chromium/ui/views/corewm/shadow_controller.cc273
-rw-r--r--chromium/ui/views/corewm/shadow_controller.h71
-rw-r--r--chromium/ui/views/corewm/shadow_controller_unittest.cc214
-rw-r--r--chromium/ui/views/corewm/shadow_types.cc25
-rw-r--r--chromium/ui/views/corewm/shadow_types.h36
-rw-r--r--chromium/ui/views/corewm/tooltip.h2
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.cc130
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.h22
-rw-r--r--chromium/ui/views/corewm/tooltip_aura_unittest.cc70
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.cc61
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.h10
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_test_helper.cc4
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_test_helper.h10
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc452
-rw-r--r--chromium/ui/views/corewm/tooltip_win.cc30
-rw-r--r--chromium/ui/views/corewm/tooltip_win.h2
-rw-r--r--chromium/ui/views/corewm/transient_window_stacking_client.cc95
-rw-r--r--chromium/ui/views/corewm/transient_window_stacking_client.h32
-rw-r--r--chromium/ui/views/corewm/transient_window_stacking_client_unittest.cc175
-rw-r--r--chromium/ui/views/corewm/visibility_controller.cc87
-rw-r--r--chromium/ui/views/corewm/visibility_controller.h75
-rw-r--r--chromium/ui/views/corewm/visibility_controller_unittest.cc57
-rw-r--r--chromium/ui/views/corewm/window_animations.cc573
-rw-r--r--chromium/ui/views/corewm/window_animations.h101
-rw-r--r--chromium/ui/views/corewm/window_animations_unittest.cc143
-rw-r--r--chromium/ui/views/corewm/window_modality_controller.cc196
-rw-r--r--chromium/ui/views/corewm/window_modality_controller.h73
-rw-r--r--chromium/ui/views/corewm/window_util.cc141
-rw-r--r--chromium/ui/views/corewm/window_util.h53
-rw-r--r--chromium/ui/views/corewm/window_util_unittest.cc117
-rw-r--r--chromium/ui/views/cull_set.cc26
-rw-r--r--chromium/ui/views/cull_set.h47
-rw-r--r--chromium/ui/views/debug_utils.cc6
-rw-r--r--chromium/ui/views/drag_utils.cc43
-rw-r--r--chromium/ui/views/drag_utils_aura.cc27
-rw-r--r--chromium/ui/views/event_utils.h31
-rw-r--r--chromium/ui/views/event_utils_aura.cc60
-rw-r--r--chromium/ui/views/event_utils_win.cc64
-rw-r--r--chromium/ui/views/examples/DEPS2
-rw-r--r--chromium/ui/views/examples/bubble_example.cc15
-rw-r--r--chromium/ui/views/examples/bubble_example.h7
-rw-r--r--chromium/ui/views/examples/button_example.cc17
-rw-r--r--chromium/ui/views/examples/button_example.h10
-rw-r--r--chromium/ui/views/examples/checkbox_example.cc2
-rw-r--r--chromium/ui/views/examples/checkbox_example.h5
-rw-r--r--chromium/ui/views/examples/combobox_example.cc8
-rw-r--r--chromium/ui/views/examples/combobox_example.h18
-rw-r--r--chromium/ui/views/examples/content_client/DEPS4
-rw-r--r--chromium/ui/views/examples/content_client/examples_browser_main_parts.cc95
-rw-r--r--chromium/ui/views/examples/content_client/examples_browser_main_parts.h57
-rw-r--r--chromium/ui/views/examples/content_client/examples_content_browser_client.cc36
-rw-r--r--chromium/ui/views/examples/content_client/examples_content_browser_client.h44
-rw-r--r--chromium/ui/views/examples/content_client/examples_main.cc25
-rw-r--r--chromium/ui/views/examples/content_client/examples_main_delegate.cc80
-rw-r--r--chromium/ui/views/examples/content_client/examples_main_delegate.h43
-rw-r--r--chromium/ui/views/examples/double_split_view_example.cc6
-rw-r--r--chromium/ui/views/examples/double_split_view_example.h7
-rw-r--r--chromium/ui/views/examples/example_base.cc3
-rw-r--r--chromium/ui/views/examples/example_base.h5
-rw-r--r--chromium/ui/views/examples/example_combobox_model.cc4
-rw-r--r--chromium/ui/views/examples/example_combobox_model.h7
-rw-r--r--chromium/ui/views/examples/examples.gyp187
-rw-r--r--chromium/ui/views/examples/examples_main.cc84
-rw-r--r--chromium/ui/views/examples/examples_window.cc182
-rw-r--r--chromium/ui/views/examples/examples_window.h18
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.cc210
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.h6
-rw-r--r--chromium/ui/views/examples/examples_with_content_main_exe.cc49
-rw-r--r--chromium/ui/views/examples/label_example.cc43
-rw-r--r--chromium/ui/views/examples/label_example.h7
-rw-r--r--chromium/ui/views/examples/link_example.cc2
-rw-r--r--chromium/ui/views/examples/link_example.h10
-rw-r--r--chromium/ui/views/examples/menu_example.cc30
-rw-r--r--chromium/ui/views/examples/menu_example.h7
-rw-r--r--chromium/ui/views/examples/message_box_example.cc2
-rw-r--r--chromium/ui/views/examples/message_box_example.h10
-rw-r--r--chromium/ui/views/examples/multiline_example.cc56
-rw-r--r--chromium/ui/views/examples/multiline_example.h14
-rw-r--r--chromium/ui/views/examples/progress_bar_example.cc4
-rw-r--r--chromium/ui/views/examples/progress_bar_example.h10
-rw-r--r--chromium/ui/views/examples/radio_button_example.cc6
-rw-r--r--chromium/ui/views/examples/radio_button_example.h10
-rw-r--r--chromium/ui/views/examples/scroll_view_example.cc4
-rw-r--r--chromium/ui/views/examples/scroll_view_example.h10
-rw-r--r--chromium/ui/views/examples/single_split_view_example.cc10
-rw-r--r--chromium/ui/views/examples/single_split_view_example.h11
-rw-r--r--chromium/ui/views/examples/slider_example.cc2
-rw-r--r--chromium/ui/views/examples/slider_example.h10
-rw-r--r--chromium/ui/views/examples/tabbed_pane_example.cc4
-rw-r--r--chromium/ui/views/examples/tabbed_pane_example.h9
-rw-r--r--chromium/ui/views/examples/table_example.cc14
-rw-r--r--chromium/ui/views/examples/table_example.h15
-rw-r--r--chromium/ui/views/examples/text_example.cc218
-rw-r--r--chromium/ui/views/examples/text_example.h17
-rw-r--r--chromium/ui/views/examples/textfield_example.cc14
-rw-r--r--chromium/ui/views/examples/textfield_example.h12
-rw-r--r--chromium/ui/views/examples/throbber_example.cc2
-rw-r--r--chromium/ui/views/examples/throbber_example.h7
-rw-r--r--chromium/ui/views/examples/tree_view_example.cc12
-rw-r--r--chromium/ui/views/examples/tree_view_example.h14
-rw-r--r--chromium/ui/views/examples/webview_example.cc3
-rw-r--r--chromium/ui/views/examples/webview_example.h5
-rw-r--r--chromium/ui/views/examples/widget_example.cc8
-rw-r--r--chromium/ui/views/examples/widget_example.h10
-rw-r--r--chromium/ui/views/focus/accelerator_handler.h46
-rw-r--r--chromium/ui/views/focus/accelerator_handler_aura.cc26
-rw-r--r--chromium/ui/views/focus/accelerator_handler_win.cc55
-rw-r--r--chromium/ui/views/focus/focus_manager.cc70
-rw-r--r--chromium/ui/views/focus/focus_manager.h11
-rw-r--r--chromium/ui/views/focus/focus_manager_test.cc18
-rw-r--r--chromium/ui/views/focus/focus_manager_test.h9
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc131
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest_win.cc281
-rw-r--r--chromium/ui/views/focus/focus_traversal_unittest.cc38
-rw-r--r--chromium/ui/views/focus/view_storage.h2
-rw-r--r--chromium/ui/views/ime/OWNERS6
-rw-r--r--chromium/ui/views/ime/input_method.h9
-rw-r--r--chromium/ui/views/ime/input_method_bridge.cc27
-rw-r--r--chromium/ui/views/ime/input_method_bridge.h10
-rw-r--r--chromium/ui/views/ime/mock_input_method.cc21
-rw-r--r--chromium/ui/views/ime/mock_input_method.h8
-rw-r--r--chromium/ui/views/ime/null_input_method.cc62
-rw-r--r--chromium/ui/views/ime/null_input_method.h50
-rw-r--r--chromium/ui/views/layout/box_layout.cc93
-rw-r--r--chromium/ui/views/layout/box_layout.h52
-rw-r--r--chromium/ui/views/layout/box_layout_unittest.cc114
-rw-r--r--chromium/ui/views/layout/fill_layout.cc4
-rw-r--r--chromium/ui/views/layout/fill_layout.h5
-rw-r--r--chromium/ui/views/layout/grid_layout.cc52
-rw-r--r--chromium/ui/views/layout/grid_layout.h28
-rw-r--r--chromium/ui/views/layout/grid_layout_unittest.cc33
-rw-r--r--chromium/ui/views/layout/layout_manager.cc3
-rw-r--r--chromium/ui/views/layout/layout_manager.h4
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.cc3
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.gyp2
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h52
-rw-r--r--chromium/ui/views/linux_ui/status_icon_linux.h2
-rw-r--r--chromium/ui/views/linux_ui/window_button_order_provider.cc83
-rw-r--r--chromium/ui/views/masked_view_targeter.cc46
-rw-r--r--chromium/ui/views/masked_view_targeter.h46
-rw-r--r--chromium/ui/views/metrics_aura.cc1
-rw-r--r--chromium/ui/views/metrics_mac.cc25
-rw-r--r--chromium/ui/views/metrics_win.cc22
-rw-r--r--chromium/ui/views/mouse_watcher.cc213
-rw-r--r--chromium/ui/views/mouse_watcher_aura.cc125
-rw-r--r--chromium/ui/views/native_cursor.h21
-rw-r--r--chromium/ui/views/native_cursor_aura.cc31
-rw-r--r--chromium/ui/views/native_cursor_mac.mm39
-rw-r--r--chromium/ui/views/painter.cc100
-rw-r--r--chromium/ui/views/painter.h6
-rw-r--r--chromium/ui/views/run_all_unittests.cc13
-rw-r--r--chromium/ui/views/touchui/touch_editing_menu.cc44
-rw-r--r--chromium/ui/views/touchui/touch_editing_menu.h8
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc207
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.h37
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc454
-rw-r--r--chromium/ui/views/view.cc477
-rw-r--r--chromium/ui/views/view.h123
-rw-r--r--chromium/ui/views/view_aura.cc33
-rw-r--r--chromium/ui/views/view_constants_aura.cc2
-rw-r--r--chromium/ui/views/view_constants_aura.h4
-rw-r--r--chromium/ui/views/view_model.cc5
-rw-r--r--chromium/ui/views/view_targeter.cc79
-rw-r--r--chromium/ui/views/view_targeter.h51
-rw-r--r--chromium/ui/views/view_targeter_unittest.cc386
-rw-r--r--chromium/ui/views/view_unittest.cc979
-rw-r--r--chromium/ui/views/view_unittest_aura.cc160
-rw-r--r--chromium/ui/views/view_win.cc28
-rw-r--r--chromium/ui/views/views.gyp678
-rw-r--r--chromium/ui/views/views_delegate.cc81
-rw-r--r--chromium/ui/views/views_delegate.h87
-rw-r--r--chromium/ui/views/views_switches.cc9
-rw-r--r--chromium/ui/views/views_switches.h4
-rw-r--r--chromium/ui/views/views_touch_selection_controller_factory.h25
-rw-r--r--chromium/ui/views/views_touch_selection_controller_factory_aura.cc22
-rw-r--r--chromium/ui/views/views_touch_selection_controller_factory_mac.cc17
-rw-r--r--chromium/ui/views/widget/aero_tooltip_manager.cc115
-rw-r--r--chromium/ui/views/widget/aero_tooltip_manager.h59
-rw-r--r--chromium/ui/views/widget/child_window_message_processor.cc28
-rw-r--r--chromium/ui/views/widget/child_window_message_processor.h47
-rw-r--r--chromium/ui/views/widget/desktop_aura/OWNERS5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc37
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc556
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h101
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc679
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc58
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc51
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h48
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc494
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h117
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc306
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h158
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h29
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc992
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h278
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win_unittest.cc55
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc1544
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h291
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc50
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc16
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc158
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc272
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h163
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h29
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_ozone.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc960
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h276
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc1838
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h345
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc448
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc116
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h27
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc53
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h19
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_scoped_capture.cc31
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_scoped_capture.h29
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc97
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h53
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_unittest.cc389
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc244
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h45
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc162
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h29
-rw-r--r--chromium/ui/views/widget/drop_target_win.cc63
-rw-r--r--chromium/ui/views/widget/drop_target_win.h55
-rw-r--r--chromium/ui/views/widget/monitor_win.cc19
-rw-r--r--chromium/ui/views/widget/monitor_win.h10
-rw-r--r--chromium/ui/views/widget/native_widget.h7
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc228
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h34
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc249
-rw-r--r--chromium/ui/views/widget/native_widget_delegate.h13
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h117
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm448
-rw-r--r--chromium/ui/views/widget/native_widget_private.h19
-rw-r--r--chromium/ui/views/widget/native_widget_unittest.cc1
-rw-r--r--chromium/ui/views/widget/native_widget_win.cc1068
-rw-r--r--chromium/ui/views/widget/native_widget_win.h278
-rw-r--r--chromium/ui/views/widget/native_widget_win_unittest.cc83
-rw-r--r--chromium/ui/views/widget/root_view.cc624
-rw-r--r--chromium/ui/views/widget/root_view.h46
-rw-r--r--chromium/ui/views/widget/root_view_test_helper.h33
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc198
-rw-r--r--chromium/ui/views/widget/tooltip_manager_aura.cc16
-rw-r--r--chromium/ui/views/widget/tooltip_manager_aura.h2
-rw-r--r--chromium/ui/views/widget/tooltip_manager_win.cc357
-rw-r--r--chromium/ui/views/widget/tooltip_manager_win.h135
-rw-r--r--chromium/ui/views/widget/widget.cc298
-rw-r--r--chromium/ui/views/widget/widget.h129
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.cc16
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.h4
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc16
-rw-r--r--chromium/ui/views/widget/widget_delegate.h15
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.cc14
-rw-r--r--chromium/ui/views/widget/widget_hwnd_utils.h3
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc288
-rw-r--r--chromium/ui/views/widget/widget_observer.h1
-rw-r--r--chromium/ui/views/widget/widget_removals_observer.h30
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc826
-rw-r--r--chromium/ui/views/widget/window_reorderer_unittest.cc2
-rw-r--r--chromium/ui/views/win/DEPS2
-rw-r--r--chromium/ui/views/win/appbar.cc88
-rw-r--r--chromium/ui/views/win/appbar.h70
-rw-r--r--chromium/ui/views/win/fullscreen_handler.cc4
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc774
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h257
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h16
-rw-r--r--chromium/ui/views/win/hwnd_util_aurawin.cc13
-rw-r--r--chromium/ui/views/win/hwnd_util_win.cc39
-rw-r--r--chromium/ui/views/window/client_view.cc12
-rw-r--r--chromium/ui/views/window/client_view.h8
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc245
-rw-r--r--chromium/ui/views/window/custom_frame_view.h33
-rw-r--r--chromium/ui/views/window/custom_frame_view_unittest.cc252
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc61
-rw-r--r--chromium/ui/views/window/dialog_client_view.h3
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc68
-rw-r--r--chromium/ui/views/window/dialog_delegate.h25
-rw-r--r--chromium/ui/views/window/dialog_delegate_unittest.cc40
-rw-r--r--chromium/ui/views/window/frame_background.cc39
-rw-r--r--chromium/ui/views/window/frame_background.h15
-rw-r--r--chromium/ui/views/window/native_frame_view.cc37
-rw-r--r--chromium/ui/views/window/native_frame_view.h9
-rw-r--r--chromium/ui/views/window/non_client_view.cc54
-rw-r--r--chromium/ui/views/window/non_client_view.h40
-rw-r--r--chromium/ui/views/window/window_button_order_provider.cc41
-rw-r--r--chromium/ui/views/window/window_button_order_provider.h56
-rw-r--r--chromium/ui/views_content_client/DEPS9
-rw-r--r--chromium/ui/views_content_client/README.chromium3
-rw-r--r--chromium/ui/views_content_client/views_content_browser_client.cc39
-rw-r--r--chromium/ui/views_content_client/views_content_browser_client.h43
-rw-r--r--chromium/ui/views_content_client/views_content_client.cc41
-rw-r--r--chromium/ui/views_content_client/views_content_client.gyp60
-rw-r--r--chromium/ui/views_content_client/views_content_client.h83
-rw-r--r--chromium/ui/views_content_client/views_content_client_export.h32
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.cc40
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.h64
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_aura.cc33
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_aura.h37
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_chromeos.cc102
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc57
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts_mac.mm55
-rw-r--r--chromium/ui/views_content_client/views_content_main_delegate.cc79
-rw-r--r--chromium/ui/views_content_client/views_content_main_delegate.h38
-rw-r--r--chromium/ui/web_dialogs/DEPS1
-rw-r--r--chromium/ui/web_dialogs/web_dialog_delegate.cc4
-rw-r--r--chromium/ui/web_dialogs/web_dialog_delegate.h6
-rw-r--r--chromium/ui/web_dialogs/web_dialog_ui.cc4
-rw-r--r--chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc10
-rw-r--r--chromium/ui/web_dialogs/web_dialog_web_contents_delegate.h4
-rw-r--r--chromium/ui/webui/DEPS2
-rw-r--r--chromium/ui/webui/OWNERS3
-rw-r--r--chromium/ui/webui/resources/BUILD.gn10
-rw-r--r--chromium/ui/webui/resources/css/bubble_button.css3
-rw-r--r--chromium/ui/webui/resources/css/chrome_shared.css2
-rw-r--r--chromium/ui/webui/resources/css/overlay.css2
-rw-r--r--chromium/ui/webui/resources/css/table.css6
-rw-r--r--chromium/ui/webui/resources/images/1.5x/laptop.pngbin266 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/1.5x/phone.pngbin259 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/1.5x/tablet.pngbin270 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/2x/apps/button_butter_bar_close_pressed.pngbin159 -> 158 bytes
-rw-r--r--chromium/ui/webui/resources/images/2x/laptop.pngbin346 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/2x/phone.pngbin317 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/2x/tablet.pngbin303 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/apps/button_butter_bar_close_hover.pngbin113 -> 112 bytes
-rw-r--r--chromium/ui/webui/resources/images/gear.pngbin313 -> 311 bytes
-rw-r--r--chromium/ui/webui/resources/images/laptop.pngbin219 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/phone.pngbin199 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/images/plus.pngbin235 -> 234 bytes
-rw-r--r--chromium/ui/webui/resources/images/tablet.pngbin204 -> 0 bytes
-rw-r--r--chromium/ui/webui/resources/js/cr/promise.js214
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/array_data_model.js45
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js7
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/dialogs.js10
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/focus_manager.js2
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list.js31
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/overlay.js3
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/tree.js20
-rw-r--r--chromium/ui/webui/resources/js/util.js62
-rw-r--r--chromium/ui/webui/resources/webui_resources.grd14
-rw-r--r--chromium/ui/wm/DEPS5
-rw-r--r--chromium/ui/wm/core/DEPS16
-rw-r--r--chromium/ui/wm/core/accelerator_delegate.h33
-rw-r--r--chromium/ui/wm/core/accelerator_filter.cc80
-rw-r--r--chromium/ui/wm/core/accelerator_filter.h40
-rw-r--r--chromium/ui/wm/core/base_focus_rules.cc195
-rw-r--r--chromium/ui/wm/core/base_focus_rules.h45
-rw-r--r--chromium/ui/wm/core/capture_controller.cc145
-rw-r--r--chromium/ui/wm/core/capture_controller.h86
-rw-r--r--chromium/ui/wm/core/compound_event_filter.cc263
-rw-r--r--chromium/ui/wm/core/compound_event_filter.h93
-rw-r--r--chromium/ui/wm/core/compound_event_filter_unittest.cc250
-rw-r--r--chromium/ui/wm/core/cursor_manager.cc217
-rw-r--r--chromium/ui/wm/core/cursor_manager.h93
-rw-r--r--chromium/ui/wm/core/cursor_manager_unittest.cc330
-rw-r--r--chromium/ui/wm/core/default_activation_client.cc157
-rw-r--r--chromium/ui/wm/core/default_activation_client.h73
-rw-r--r--chromium/ui/wm/core/easy_resize_window_targeter.cc62
-rw-r--r--chromium/ui/wm/core/easy_resize_window_targeter.h53
-rw-r--r--chromium/ui/wm/core/focus_controller.cc368
-rw-r--r--chromium/ui/wm/core/focus_controller.h128
-rw-r--r--chromium/ui/wm/core/focus_controller_unittest.cc1285
-rw-r--r--chromium/ui/wm/core/focus_rules.h66
-rw-r--r--chromium/ui/wm/core/image_grid.cc338
-rw-r--r--chromium/ui/wm/core/image_grid.h221
-rw-r--r--chromium/ui/wm/core/image_grid_unittest.cc340
-rw-r--r--chromium/ui/wm/core/input_method_event_filter.cc105
-rw-r--r--chromium/ui/wm/core/input_method_event_filter.h50
-rw-r--r--chromium/ui/wm/core/input_method_event_filter_unittest.cc143
-rw-r--r--chromium/ui/wm/core/masked_window_targeter.cc43
-rw-r--r--chromium/ui/wm/core/masked_window_targeter.h40
-rw-r--r--chromium/ui/wm/core/native_cursor_manager.h61
-rw-r--r--chromium/ui/wm/core/native_cursor_manager_delegate.h33
-rw-r--r--chromium/ui/wm/core/nested_accelerator_controller.cc57
-rw-r--r--chromium/ui/wm/core/nested_accelerator_controller.h47
-rw-r--r--chromium/ui/wm/core/nested_accelerator_controller_unittest.cc205
-rw-r--r--chromium/ui/wm/core/nested_accelerator_delegate.h34
-rw-r--r--chromium/ui/wm/core/nested_accelerator_dispatcher.cc21
-rw-r--r--chromium/ui/wm/core/nested_accelerator_dispatcher.h55
-rw-r--r--chromium/ui/wm/core/nested_accelerator_dispatcher_linux.cc104
-rw-r--r--chromium/ui/wm/core/nested_accelerator_dispatcher_win.cc74
-rw-r--r--chromium/ui/wm/core/shadow.cc193
-rw-r--r--chromium/ui/wm/core/shadow.h86
-rw-r--r--chromium/ui/wm/core/shadow_controller.cc272
-rw-r--r--chromium/ui/wm/core/shadow_controller.h69
-rw-r--r--chromium/ui/wm/core/shadow_controller_unittest.cc219
-rw-r--r--chromium/ui/wm/core/shadow_types.cc23
-rw-r--r--chromium/ui/wm/core/shadow_types.h34
-rw-r--r--chromium/ui/wm/core/transient_window_controller.cc40
-rw-r--r--chromium/ui/wm/core/transient_window_controller.h36
-rw-r--r--chromium/ui/wm/core/transient_window_manager.cc182
-rw-r--r--chromium/ui/wm/core/transient_window_manager.h91
-rw-r--r--chromium/ui/wm/core/transient_window_manager_unittest.cc666
-rw-r--r--chromium/ui/wm/core/transient_window_observer.h32
-rw-r--r--chromium/ui/wm/core/transient_window_stacking_client.cc131
-rw-r--r--chromium/ui/wm/core/transient_window_stacking_client.h37
-rw-r--r--chromium/ui/wm/core/transient_window_stacking_client_unittest.cc215
-rw-r--r--chromium/ui/wm/core/user_activity_detector.cc112
-rw-r--r--chromium/ui/wm/core/user_activity_detector.h81
-rw-r--r--chromium/ui/wm/core/user_activity_detector_unittest.cc200
-rw-r--r--chromium/ui/wm/core/user_activity_observer.h35
-rw-r--r--chromium/ui/wm/core/visibility_controller.cc89
-rw-r--r--chromium/ui/wm/core/visibility_controller.h74
-rw-r--r--chromium/ui/wm/core/visibility_controller_unittest.cc56
-rw-r--r--chromium/ui/wm/core/window_animations.cc658
-rw-r--r--chromium/ui/wm/core/window_animations.h117
-rw-r--r--chromium/ui/wm/core/window_animations_unittest.cc291
-rw-r--r--chromium/ui/wm/core/window_modality_controller.cc201
-rw-r--r--chromium/ui/wm/core/window_modality_controller.h71
-rw-r--r--chromium/ui/wm/core/window_util.cc129
-rw-r--r--chromium/ui/wm/core/window_util.h67
-rw-r--r--chromium/ui/wm/core/window_util_unittest.cc52
-rw-r--r--chromium/ui/wm/core/wm_core_switches.cc16
-rw-r--r--chromium/ui/wm/core/wm_core_switches.h24
-rw-r--r--chromium/ui/wm/core/wm_state.cc30
-rw-r--r--chromium/ui/wm/core/wm_state.h32
-rw-r--r--chromium/ui/wm/public/DEPS9
-rw-r--r--chromium/ui/wm/public/activation_change_observer.cc29
-rw-r--r--chromium/ui/wm/public/activation_change_observer.h45
-rw-r--r--chromium/ui/wm/public/activation_client.cc38
-rw-r--r--chromium/ui/wm/public/activation_client.h77
-rw-r--r--chromium/ui/wm/public/activation_delegate.cc27
-rw-r--r--chromium/ui/wm/public/activation_delegate.h37
-rw-r--r--chromium/ui/wm/public/animation_host.cc28
-rw-r--r--chromium/ui/wm/public/animation_host.h48
-rw-r--r--chromium/ui/wm/public/dispatcher_client.cc52
-rw-r--r--chromium/ui/wm/public/dispatcher_client.h59
-rw-r--r--chromium/ui/wm/public/drag_drop_client.cc31
-rw-r--r--chromium/ui/wm/public/drag_drop_client.h62
-rw-r--r--chromium/ui/wm/public/drag_drop_delegate.cc27
-rw-r--r--chromium/ui/wm/public/drag_drop_delegate.h51
-rw-r--r--chromium/ui/wm/public/scoped_tooltip_disabler.cc43
-rw-r--r--chromium/ui/wm/public/scoped_tooltip_disabler.h39
-rw-r--r--chromium/ui/wm/public/tooltip_client.cc52
-rw-r--r--chromium/ui/wm/public/tooltip_client.h51
-rw-r--r--chromium/ui/wm/public/transient_window_client.cc25
-rw-r--r--chromium/ui/wm/public/transient_window_client.h47
-rw-r--r--chromium/ui/wm/public/window_move_client.cc28
-rw-r--r--chromium/ui/wm/public/window_move_client.h56
-rw-r--r--chromium/ui/wm/public/window_types.h36
-rw-r--r--chromium/ui/wm/wm.gyp125
-rw-r--r--chromium/ui/wm/wm_export.h32
2907 files changed, 141349 insertions, 123681 deletions
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn
new file mode 100644
index 00000000000..66a04da74f9
--- /dev/null
+++ b/chromium/ui/accessibility/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//extensions/generated_extensions_api.gni")
+
+component("accessibility") {
+ sources = [
+ "ax_node.cc",
+ "ax_node.h",
+ "ax_node_data.cc",
+ "ax_node_data.h",
+ "ax_serializable_tree.cc",
+ "ax_serializable_tree.h",
+ "ax_text_utils.cc",
+ "ax_text_utils.h",
+ "ax_tree.cc",
+ "ax_tree.h",
+ "ax_tree_serializer.cc",
+ "ax_tree_serializer.h",
+ "ax_tree_source.h",
+ "ax_tree_update.cc",
+ "ax_tree_update.h",
+ "ax_view_state.cc",
+ "ax_view_state.h",
+ ]
+
+ defines = [ "ACCESSIBILITY_IMPLEMENTATION" ]
+
+ forward_dependent_configs_from = [ ":ax_gen" ]
+
+ deps = [
+ ":ax_gen",
+ "//base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
+
+test("accessibility_unittests") {
+ sources = [
+ "ax_generated_tree_unittest.cc",
+ "ax_tree_serializer_unittest.cc",
+ "ax_tree_unittest.cc",
+ ]
+
+ deps = [
+ ":accessibility",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
+
+generated_extensions_api("ax_gen") {
+ sources = [ "ax_enums.idl" ]
+ root_namespace = ""
+ impl_dir = "."
+}
diff --git a/chromium/ui/accessibility/accessibility.gyp b/chromium/ui/accessibility/accessibility.gyp
index 1402d3b9758..bdc42128dc3 100644
--- a/chromium/ui/accessibility/accessibility.gyp
+++ b/chromium/ui/accessibility/accessibility.gyp
@@ -11,22 +11,29 @@
{
'target_name': 'accessibility',
'type': '<(component)',
+ 'export_dependent_settings': [
+ 'ax_gen',
+ ],
+ 'hard_dependency': 1,
'dependencies': [
'../../base/base.gyp:base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ 'ax_gen',
],
'defines': [
'ACCESSIBILITY_IMPLEMENTATION',
],
'sources': [
# All .cc, .h under accessibility, except unittests
- 'ax_enums.h',
'ax_node.cc',
+ 'ax_node.h',
'ax_node_data.cc',
'ax_node_data.h',
- 'ax_node.h',
'ax_serializable_tree.cc',
'ax_serializable_tree.h',
+ 'ax_text_utils.cc',
+ 'ax_text_utils.h',
'ax_tree.cc',
'ax_tree.h',
'ax_tree_serializer.cc',
@@ -34,6 +41,8 @@
'ax_tree_source.h',
'ax_tree_update.cc',
'ax_tree_update.h',
+ 'ax_view_state.cc',
+ 'ax_view_state.h',
]
},
{
@@ -43,12 +52,45 @@
'../../base/base.gyp:base',
'../../base/base.gyp:run_all_unittests',
'../../testing/gtest.gyp:gtest',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'accessibility',
+ 'ax_gen',
],
'sources': [
+ 'ax_generated_tree_unittest.cc',
'ax_tree_serializer_unittest.cc',
'ax_tree_unittest.cc',
]
},
+ {
+ 'target_name': 'ax_gen',
+ 'type': 'static_library',
+ # This target exports a hard dependency because dependent targets may
+ # include ax_enums.h, a generated header.
+ 'hard_dependency': 1,
+ 'dependencies': [
+ '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations'
+ ],
+ 'sources': [
+ '<@(schema_files)',
+ ],
+ 'msvs_disabled_warnings': [ 4267 ],
+ 'includes': [
+ '../../build/json_schema_bundle_compile.gypi',
+ '../../build/json_schema_compile.gypi',
+ ],
+ 'variables': {
+ 'chromium_code': 1,
+ 'schema_files': [
+ 'ax_enums.idl',
+ ],
+ 'non_compiled_schema_files': [],
+ 'cc_dir': 'ui/accessibility',
+ # TODO(dtseng): Change this once all files under ui/accessibility
+ # namespaced under ui::ax.
+ 'root_namespace': '',
+ },
+ },
],
}
diff --git a/chromium/ui/accessibility/ax_enums.h b/chromium/ui/accessibility/ax_enums.h
deleted file mode 100644
index 7f543ed4aab..00000000000
--- a/chromium/ui/accessibility/ax_enums.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ACCESSIBILITY_AX_ROLES_H_
-#define UI_ACCESSIBILITY_AX_ROLES_H_
-
-// These should be kept in sync with third_party/WebKit/public/web/WebAXEnums.h
-// until the Chromium and Blink trees are merged.
-enum AXRole {
- AX_ROLE_ALERT_DIALOG = 1,
- AX_ROLE_ALERT,
- AX_ROLE_ANNOTATION,
- AX_ROLE_APPLICATION,
- AX_ROLE_ARTICLE,
- AX_ROLE_BANNER,
- AX_ROLE_BROWSER,
- AX_ROLE_BUSY_INDICATOR,
- AX_ROLE_BUTTON,
- AX_ROLE_CANVAS,
- AX_ROLE_CELL,
- AX_ROLE_CHECK_BOX,
- AX_ROLE_COLOR_WELL,
- AX_ROLE_COLUMN_HEADER,
- AX_ROLE_COLUMN,
- AX_ROLE_COMBO_BOX,
- AX_ROLE_COMPLEMENTARY,
- AX_ROLE_CONTENT_INFO,
- AX_ROLE_DEFINITION,
- AX_ROLE_DESCRIPTION_LIST_DETAIL,
- AX_ROLE_DESCRIPTION_LIST_TERM,
- AX_ROLE_DIALOG,
- AX_ROLE_DIRECTORY,
- AX_ROLE_DISCLOSURE_TRIANGLE,
- AX_ROLE_DIV,
- AX_ROLE_DOCUMENT,
- AX_ROLE_DRAWER,
- AX_ROLE_EDITABLE_TEXT,
- AX_ROLE_FOOTER,
- AX_ROLE_FORM,
- AX_ROLE_GRID,
- AX_ROLE_GROUP,
- AX_ROLE_GROW_AREA,
- AX_ROLE_HEADING,
- AX_ROLE_HELP_TAG,
- AX_ROLE_HORIZONTAL_RULE,
- AX_ROLE_IGNORED,
- AX_ROLE_IMAGE_MAP_LINK,
- AX_ROLE_IMAGE_MAP,
- AX_ROLE_IMAGE,
- AX_ROLE_INCREMENTOR,
- AX_ROLE_INLINE_TEXT_BOX,
- AX_ROLE_LABEL,
- AX_ROLE_LEGEND,
- AX_ROLE_LINK,
- AX_ROLE_LIST_BOX_OPTION,
- AX_ROLE_LIST_BOX,
- AX_ROLE_LIST_ITEM,
- AX_ROLE_LIST_MARKER,
- AX_ROLE_LIST,
- AX_ROLE_LOG,
- AX_ROLE_MAIN,
- AX_ROLE_MARQUEE,
- AX_ROLE_MATH_ELEMENT,
- AX_ROLE_MATH,
- AX_ROLE_MATTE,
- AX_ROLE_MENU_BAR,
- AX_ROLE_MENU_BUTTON,
- AX_ROLE_MENU_ITEM,
- AX_ROLE_MENU_LIST_OPTION,
- AX_ROLE_MENU_LIST_POPUP,
- AX_ROLE_MENU,
- AX_ROLE_NAVIGATION,
- AX_ROLE_NOTE,
- AX_ROLE_OUTLINE,
- AX_ROLE_PARAGRAPH,
- AX_ROLE_POP_UP_BUTTON,
- AX_ROLE_PRESENTATIONAL,
- AX_ROLE_PROGRESS_INDICATOR,
- AX_ROLE_RADIO_BUTTON,
- AX_ROLE_RADIO_GROUP,
- AX_ROLE_REGION,
- AX_ROLE_ROOT_WEB_AREA,
- AX_ROLE_ROW_HEADER,
- AX_ROLE_ROW,
- AX_ROLE_RULER_MARKER,
- AX_ROLE_RULER,
- AX_ROLE_SVG_ROOT,
- AX_ROLE_SCROLL_AREA,
- AX_ROLE_SCROLL_BAR,
- AX_ROLE_SEAMLESS_WEB_AREA,
- AX_ROLE_SEARCH,
- AX_ROLE_SHEET,
- AX_ROLE_SLIDER,
- AX_ROLE_SLIDER_THUMB,
- AX_ROLE_SPIN_BUTTON_PART,
- AX_ROLE_SPIN_BUTTON,
- AX_ROLE_SPLIT_GROUP,
- AX_ROLE_SPLITTER,
- AX_ROLE_STATIC_TEXT,
- AX_ROLE_STATUS,
- AX_ROLE_SYSTEM_WIDE,
- AX_ROLE_TAB_GROUP,
- AX_ROLE_TAB_LIST,
- AX_ROLE_TAB_PANEL,
- AX_ROLE_TAB,
- AX_ROLE_TABLE_HEADER_CONTAINER,
- AX_ROLE_TABLE,
- AX_ROLE_TEXT_AREA,
- AX_ROLE_TEXT_FIELD,
- AX_ROLE_TIMER,
- AX_ROLE_TOGGLE_BUTTON,
- AX_ROLE_TOOLBAR,
- AX_ROLE_TREE_GRID,
- AX_ROLE_TREE_ITEM,
- AX_ROLE_TREE,
- AX_ROLE_UNKNOWN,
- AX_ROLE_USER_INTERFACE_TOOLTIP,
- AX_ROLE_VALUE_INDICATOR,
- AX_ROLE_WEB_AREA,
- AX_ROLE_WINDOW
-};
-
-#endif // UI_ACCESSIBILITY_AX_ROLES_H_
diff --git a/chromium/ui/accessibility/ax_enums.idl b/chromium/ui/accessibility/ax_enums.idl
new file mode 100644
index 00000000000..ef3b5e6c895
--- /dev/null
+++ b/chromium/ui/accessibility/ax_enums.idl
@@ -0,0 +1,356 @@
+// 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.
+
+// These should be kept in sync with third_party/WebKit/public/web/WebAXEnums.h
+// until the Chromium and Blink trees are merged.
+[camel_case_enum_to_string=true] namespace ui {
+
+ // For new entries to the following three enums, also add to
+ // chrome/common/extensions/apis/automation.idl.
+ enum AXEvent {
+ activedescendantchanged,
+ alert,
+ aria_attribute_changed,
+ autocorrection_occured,
+ blur,
+ checked_state_changed,
+ children_changed,
+ focus,
+ hide,
+ hover,
+ invalid_status_changed,
+ layout_complete,
+ live_region_changed,
+ load_complete,
+ location_changed,
+ menu_end,
+ menu_list_item_selected,
+ menu_list_value_changed,
+ menu_popup_end,
+ menu_popup_start,
+ menu_start,
+ row_collapsed,
+ row_count_changed,
+ row_expanded,
+ scroll_position_changed,
+ scrolled_to_anchor,
+ selected_children_changed,
+ selected_text_changed,
+ selection_changed,
+ show,
+ text_changed,
+ text_inserted,
+ text_removed,
+ value_changed
+ };
+
+ enum AXRole {
+ alert_dialog,
+ alert,
+ annotation,
+ application,
+ article,
+ banner,
+ browser,
+ busy_indicator,
+ button,
+ button_drop_down,
+ canvas,
+ cell,
+ check_box,
+ client,
+ color_well,
+ column_header,
+ column,
+ combo_box,
+ complementary,
+ content_info,
+ definition,
+ description_list_detail,
+ description_list_term,
+ desktop,
+ dialog,
+ directory,
+ disclosure_triangle,
+ div,
+ document,
+ drawer,
+ editable_text,
+ embedded_object,
+ footer,
+ form,
+ grid,
+ group,
+ grow_area,
+ heading,
+ help_tag,
+ horizontal_rule,
+ iframe,
+ ignored,
+ image_map_link,
+ image_map,
+ image,
+ incrementor,
+ inline_text_box,
+ label_text,
+ legend,
+ link,
+ list_box_option,
+ list_box,
+ list_item,
+ list_marker,
+ list,
+ location_bar,
+ log,
+ main,
+ marquee,
+ math_element,
+ math,
+ matte,
+ menu_bar,
+ menu_button,
+ menu_item,
+ menu_list_option,
+ menu_list_popup,
+ menu,
+ navigation,
+ note,
+ outline,
+ pane,
+ paragraph,
+ pop_up_button,
+ presentational,
+ progress_indicator,
+ radio_button,
+ radio_group,
+ region,
+ root_web_area,
+ row_header,
+ row,
+ ruler_marker,
+ ruler,
+ svg_root,
+ scroll_area,
+ scroll_bar,
+ seamless_web_area,
+ search,
+ sheet,
+ slider,
+ slider_thumb,
+ spin_button_part,
+ spin_button,
+ split_group,
+ splitter,
+ static_text,
+ status,
+ system_wide,
+ tab_group,
+ tab_list,
+ tab_panel,
+ tab,
+ table_header_container,
+ table,
+ text_area,
+ text_field,
+ timer,
+ title_bar,
+ toggle_button,
+ toolbar,
+ tree_grid,
+ tree_item,
+ tree,
+ unknown,
+ tooltip,
+ value_indicator,
+ web_area,
+ window
+ };
+
+ // TODO(dmazzoni): switch content/ to use AX_STATE_DISABLED instead of
+ // !AX_STATE_ENABLED, and AX_STATE_EDITABLE instead of !AX_STATE_READONLY.
+ enum AXState {
+ busy,
+ checked,
+ collapsed,
+ default,
+ disabled, // ui/views only
+ editable, // ui/views only
+ enabled, // content only
+ expanded,
+ focusable,
+ focused,
+ haspopup,
+ hovered,
+ indeterminate,
+ invisible,
+ linked,
+ multiselectable,
+ offscreen,
+ pressed,
+ protected,
+ read_only,
+ required,
+ selectable,
+ selected,
+ vertical,
+ visited
+ };
+
+ [cpp_enum_prefix_override="ax_attr"] enum AXStringAttribute {
+ // Document attributes.
+ doc_url,
+ doc_title,
+ doc_mimetype,
+ doc_doctype,
+
+ // Attributes that could apply to any node.
+ access_key,
+ action,
+ container_live_relevant,
+ container_live_status,
+ description,
+ display,
+ help,
+ html_tag,
+ name,
+ live_relevant,
+ live_status,
+ role,
+ shortcut,
+ url,
+ value
+ };
+
+ [cpp_enum_prefix_override="ax_attr"] enum AXIntAttribute {
+ // Scrollable container attributes.
+ scroll_x,
+ scroll_x_min,
+ scroll_x_max,
+ scroll_y,
+ scroll_y_min,
+ scroll_y_max,
+
+ // Editable text attributes.
+ text_sel_start,
+ text_sel_end,
+
+ // Table attributes.
+ table_row_count,
+ table_column_count,
+ table_header_id,
+
+ // Table row attributes.
+ table_row_index,
+ table_row_header_id,
+
+ // Table column attributes.
+ table_column_index,
+ table_column_header_id,
+
+ // Table cell attributes.
+ table_cell_column_index,
+ table_cell_column_span,
+ table_cell_row_index,
+ table_cell_row_span,
+
+ // Tree control attributes.
+ hierarchical_level,
+
+ // Relationships between this element and other elements.
+ title_ui_element,
+ activedescendant_id,
+
+ // Color value for AX_ROLE_COLOR_WELL, each component is 0..255
+ color_value_red,
+ color_value_green,
+ color_value_blue,
+
+ // Inline text attributes.
+ text_direction
+ };
+
+ [cpp_enum_prefix_override="ax_attr"] enum AXFloatAttribute {
+ // Document attributes.
+ doc_loading_progress,
+
+ // Range attributes.
+ value_for_range,
+ min_value_for_range,
+ max_value_for_range
+ };
+
+ [cpp_enum_prefix_override="ax_attr"] enum AXBoolAttribute {
+ // Document attributes.
+ doc_loaded,
+
+ // True if a checkbox or radio button is in the "mixed" state.
+ button_mixed,
+
+ // Live region attributes.
+ container_live_atomic,
+ container_live_busy,
+ live_atomic,
+ live_busy,
+
+ // ARIA readonly flag.
+ aria_readonly,
+
+ // Writeable attributes
+ can_set_value,
+
+ // If this is set, all of the other fields in this struct should
+ // be ignored and only the locations should change.
+ update_location_only,
+
+ // Set on a canvas element if it has fallback content.
+ canvas_has_fallback
+ };
+
+ [cpp_enum_prefix_override="ax_attr"] enum AXIntListAttribute {
+ // Ids of nodes that are children of this node logically, but are
+ // not children of this node in the tree structure. As an example,
+ // a table cell is a child of a row, and an 'indirect' child of a
+ // column.
+ indirect_child_ids,
+
+ // Relationships between this element and other elements.
+ controls_ids,
+ describedby_ids,
+ flowto_ids,
+ labelledby_ids,
+ owns_ids,
+
+ // Character indices where line breaks occur.
+ line_breaks,
+
+ // For a table, the cell ids in row-major order, with duplicate entries
+ // when there's a rowspan or colspan, and with -1 for missing cells.
+ // There are always exactly rows * columns entries.
+ cell_ids,
+
+ // For a table, the unique cell ids in row-major order of their first
+ // occurrence.
+ unique_cell_ids,
+
+ // For inline text. This is the pixel position of the end of this
+ // character within the bounding rectangle of this object, in the
+ // direction given by AX_ATTR_TEXT_DIRECTION. For example, for left-to-right
+ // text, the first offset is the right coordinate of the first character
+ // within the object's bounds, the second offset is the right coordinate
+ // of the second character, and so on.
+ character_offsets,
+
+ // For inline text. These int lists must be the same size; they represent
+ // the start and end character index of each word within this text.
+ word_starts,
+ word_ends
+ };
+
+ [cpp_enum_prefix_override="ax"] enum AXTextDirection {
+ text_direction_lr,
+ text_direction_rl,
+ text_direction_tb,
+ text_direction_bt
+ };
+};
diff --git a/chromium/ui/accessibility/ax_generated_tree_unittest.cc b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
new file mode 100644
index 00000000000..835200cb27a
--- /dev/null
+++ b/chromium/ui/accessibility/ax_generated_tree_unittest.cc
@@ -0,0 +1,243 @@
+// 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 "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_serializable_tree.h"
+#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+
+namespace ui {
+namespace {
+
+// A function to turn a tree into a string, capturing only the node ids
+// and their relationship to one another.
+//
+// The string format is kind of like an S-expression, with each expression
+// being either a node id, or a node id followed by a subexpression
+// representing its children.
+//
+// Examples:
+//
+// (1) is a tree with a single node with id 1.
+// (1 (2 3)) is a tree with 1 as the root, and 2 and 3 as its children.
+// (1 (2 (3))) has 1 as the root, 2 as its child, and then 3 as the child of 2.
+void TreeToStringHelper(const AXNode* node, std::string* out_result) {
+ *out_result += base::IntToString(node->id());
+ if (node->child_count() != 0) {
+ *out_result += " (";
+ for (int i = 0; i < node->child_count(); ++i) {
+ if (i != 0)
+ *out_result += " ";
+ TreeToStringHelper(node->ChildAtIndex(i), out_result);
+ }
+ *out_result += ")";
+ }
+}
+
+std::string TreeToString(const AXTree& tree) {
+ std::string result;
+ TreeToStringHelper(tree.GetRoot(), &result);
+ return "(" + result + ")";
+}
+
+} // anonymous namespace
+
+// A class to create all possible trees with <n> nodes and the ids [1...n].
+//
+// There are two parts to the algorithm:
+//
+// The tree structure is formed as follows: without loss of generality,
+// the first node becomes the root and the second node becomes its
+// child. Thereafter, choose every possible parent for every other node.
+//
+// So for node i in (3...n), there are (i - 1) possible choices for its
+// parent, for a total of (n-1)! (n minus 1 factorial) possible trees.
+//
+// The second part is the assignment of ids to the nodes in the tree.
+// There are exactly n! (n factorial) permutations of the sequence 1...n,
+// and each of these is assigned to every node in every possible tree.
+//
+// The total number of trees returned for a given <n>, then, is
+// n! * (n-1)!
+//
+// n = 2: 2 trees
+// n = 3: 12 trees
+// n = 4: 144 trees
+// n = 5: 2880 trees
+//
+// This grows really fast! Luckily it's very unlikely that there'd be
+// bugs that affect trees with >4 nodes that wouldn't affect a smaller tree
+// too.
+class TreeGenerator {
+ public:
+ TreeGenerator(int node_count)
+ : node_count_(node_count),
+ unique_tree_count_(1) {
+ // (n-1)! for the possible trees.
+ for (int i = 2; i < node_count_; i++)
+ unique_tree_count_ *= i;
+ // n! for the permutations of ids.
+ for (int i = 2; i <= node_count_; i++)
+ unique_tree_count_ *= i;
+ }
+
+ int UniqueTreeCount() {
+ return unique_tree_count_;
+ }
+
+ void BuildUniqueTree(int tree_index, AXTree* out_tree) {
+ std::vector<int> indices;
+ std::vector<int> permuted;
+ CHECK(tree_index <= unique_tree_count_);
+
+ // Use the first few bits of |tree_index| to permute
+ // the indices.
+ for (int i = 0; i < node_count_; i++)
+ indices.push_back(i + 1);
+ for (int i = 0; i < node_count_; i++) {
+ int p = (node_count_ - i);
+ int index = tree_index % p;
+ tree_index /= p;
+ permuted.push_back(indices[index]);
+ indices.erase(indices.begin() + index);
+ }
+
+ // Build an AXTreeUpdate. The first two nodes of the tree always
+ // go in the same place.
+ AXTreeUpdate update;
+ update.nodes.resize(node_count_);
+ update.nodes[0].id = permuted[0];
+ update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
+ update.nodes[0].child_ids.push_back(permuted[1]);
+ update.nodes[1].id = permuted[1];
+
+ // The remaining nodes are assigned based on their parent
+ // selected from the next bits from |tree_index|.
+ for (int i = 2; i < node_count_; i++) {
+ update.nodes[i].id = permuted[i];
+ int parent_index = (tree_index % i);
+ tree_index /= i;
+ update.nodes[parent_index].child_ids.push_back(permuted[i]);
+ }
+
+ // Unserialize the tree update into the destination tree.
+ CHECK(out_tree->Unserialize(update));
+ }
+
+ private:
+ int node_count_;
+ int unique_tree_count_;
+};
+
+// Test the TreeGenerator class by building all possible trees with
+// 3 nodes and the ids [1...3].
+TEST(AXGeneratedTreeTest, TestTreeGenerator) {
+ int tree_size = 3;
+ TreeGenerator generator(tree_size);
+ const char* EXPECTED_TREES[] = {
+ "(1 (2 3))",
+ "(2 (1 3))",
+ "(3 (1 2))",
+ "(1 (3 2))",
+ "(2 (3 1))",
+ "(3 (2 1))",
+ "(1 (2 (3)))",
+ "(2 (1 (3)))",
+ "(3 (1 (2)))",
+ "(1 (3 (2)))",
+ "(2 (3 (1)))",
+ "(3 (2 (1)))",
+ };
+
+ int n = generator.UniqueTreeCount();
+ ASSERT_EQ(static_cast<int>(arraysize(EXPECTED_TREES)), n);
+
+ for (int i = 0; i < n; i++) {
+ AXTree tree;
+ generator.BuildUniqueTree(i, &tree);
+ std::string str = TreeToString(tree);
+ EXPECT_EQ(EXPECTED_TREES[i], str);
+ }
+}
+
+// Test mutating every possible tree with <n> nodes to every other possible
+// tree with <n> nodes, where <n> is 4 in release mode and 3 in debug mode
+// (for speed). For each possible combination of trees, we also vary which
+// node we serialize first.
+//
+// For every possible scenario, we check that the AXTreeUpdate is valid,
+// that the destination tree can unserialize it and create a valid tree,
+// and that after updating all nodes the resulting tree now matches the
+// intended tree.
+TEST(AXGeneratedTreeTest, SerializeGeneratedTrees) {
+ // Do a more exhaustive test in release mode. If you're modifying
+ // the algorithm you may want to try even larger tree sizes if you
+ // can afford the time.
+#ifdef NDEBUG
+ int tree_size = 4;
+#else
+ LOG(WARNING) << "Debug build, only testing trees with 3 nodes and not 4.";
+ int tree_size = 3;
+#endif
+
+ TreeGenerator generator(tree_size);
+ int n = generator.UniqueTreeCount();
+
+ for (int i = 0; i < n; i++) {
+ // Build the first tree, tree0.
+ AXSerializableTree tree0;
+ generator.BuildUniqueTree(i, &tree0);
+ SCOPED_TRACE("tree0 is " + TreeToString(tree0));
+
+ for (int j = 0; j < n; j++) {
+ // Build the second tree, tree1.
+ AXSerializableTree tree1;
+ generator.BuildUniqueTree(j, &tree1);
+ SCOPED_TRACE("tree1 is " + TreeToString(tree0));
+
+ // Now iterate over which node to update first, |k|.
+ for (int k = 0; k < tree_size; k++) {
+ SCOPED_TRACE("i=" + base::IntToString(i) +
+ " j=" + base::IntToString(j) +
+ " k=" + base::IntToString(k));
+
+ // Start by serializing tree0 and unserializing it into a new
+ // empty tree |dst_tree|.
+ scoped_ptr<AXTreeSource<const AXNode*> > tree0_source(
+ tree0.CreateTreeSource());
+ AXTreeSerializer<const AXNode*> serializer(tree0_source.get());
+ AXTreeUpdate update0;
+ serializer.SerializeChanges(tree0.GetRoot(), &update0);
+
+ AXTree dst_tree;
+ ASSERT_TRUE(dst_tree.Unserialize(update0));
+
+ // At this point, |dst_tree| should now be identical to |tree0|.
+ EXPECT_EQ(TreeToString(tree0), TreeToString(dst_tree));
+
+ // Next, pretend that tree0 turned into tree1, and serialize
+ // a sequence of updates to |dst_tree| to match.
+ scoped_ptr<AXTreeSource<const AXNode*> > tree1_source(
+ tree1.CreateTreeSource());
+ serializer.ChangeTreeSourceForTesting(tree1_source.get());
+
+ for (int k_index = 0; k_index < tree_size; ++k_index) {
+ int id = 1 + (k + k_index) % tree_size;
+ AXTreeUpdate update;
+ serializer.SerializeChanges(tree1.GetFromId(id), &update);
+ ASSERT_TRUE(dst_tree.Unserialize(update));
+ }
+
+ // After the sequence of updates, |dst_tree| should now be
+ // identical to |tree1|.
+ EXPECT_EQ(TreeToString(tree1), TreeToString(dst_tree));
+ }
+ }
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc
index 8adb9409051..587f7375d74 100644
--- a/chromium/ui/accessibility/ax_node.cc
+++ b/chromium/ui/accessibility/ax_node.cc
@@ -19,6 +19,10 @@ void AXNode::SetData(const AXNodeData& src) {
data_ = src;
}
+void AXNode::SetLocation(const gfx::Rect& new_location) {
+ data_.location = new_location;
+}
+
void AXNode::SetIndexInParent(int index_in_parent) {
index_in_parent_ = index_in_parent;
}
@@ -31,4 +35,13 @@ void AXNode::Destroy() {
delete this;
}
+bool AXNode::IsDescendantOf(AXNode* ancestor) {
+ if (this == ancestor)
+ return true;
+ else if (parent())
+ return parent()->IsDescendantOf(ancestor);
+
+ return false;
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node.h b/chromium/ui/accessibility/ax_node.h
index b7e31257b96..5da73401c53 100644
--- a/chromium/ui/accessibility/ax_node.h
+++ b/chromium/ui/accessibility/ax_node.h
@@ -24,27 +24,36 @@ class AX_EXPORT AXNode {
int child_count() const { return static_cast<int>(children_.size()); }
const AXNodeData& data() const { return data_; }
const std::vector<AXNode*>& children() const { return children_; }
+ int index_in_parent() const { return index_in_parent_; }
// Get the child at the given index.
AXNode* ChildAtIndex(int index) const { return children_[index]; }
// Set the node's accessibility data. This may be done during initial
// initialization or later when the node data changes.
- virtual void SetData(const AXNodeData& src);
+ void SetData(const AXNodeData& src);
+
+ // Update this node's location. This is separate from SetData just because
+ // changing only the location is common and should be more efficient than
+ // re-copying all of the data.
+ void SetLocation(const gfx::Rect& new_location);
// Set the index in parent, for example if siblings were inserted or deleted.
void SetIndexInParent(int index_in_parent);
// Swap the internal children vector with |children|. This instance
// now owns all of the passed children.
- virtual void SwapChildren(std::vector<AXNode*>& children);
+ void SwapChildren(std::vector<AXNode*>& children);
// This is called when the AXTree no longer includes this node in the
// tree. Reference counting is used on some platforms because the
// operating system may hold onto a reference to an AXNode
// object even after we're through with it, so this may decrement the
// reference count and clear out the object's data.
- virtual void Destroy();
+ void Destroy();
+
+ // Return true if this object is equal to or a descendant of |ancestor|.
+ bool IsDescendantOf(AXNode* ancestor);
private:
int index_in_parent_;
diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc
index 1655fe84524..78987ef6e18 100644
--- a/chromium/ui/accessibility/ax_node_data.cc
+++ b/chromium/ui/accessibility/ax_node_data.cc
@@ -6,7 +6,6 @@
#include <set>
-#include "base/containers/hash_tables.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -16,6 +15,20 @@ using base::IntToString;
namespace ui {
+namespace {
+
+std::string IntVectorToString(const std::vector<int>& items) {
+ std::string str;
+ for (size_t i = 0; i < items.size(); ++i) {
+ if (i > 0)
+ str += ",";
+ str += IntToString(items[i]);
+ }
+ return str;
+}
+
+} // Anonymous namespace
+
AXNodeData::AXNodeData()
: id(-1),
role(AX_ROLE_UNKNOWN),
@@ -26,36 +39,363 @@ AXNodeData::~AXNodeData() {
}
void AXNodeData::AddStringAttribute(
- StringAttribute attribute, const std::string& value) {
+ AXStringAttribute attribute, const std::string& value) {
string_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddIntAttribute(
- IntAttribute attribute, int value) {
+ AXIntAttribute attribute, int value) {
int_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddFloatAttribute(
- FloatAttribute attribute, float value) {
+ AXFloatAttribute attribute, float value) {
float_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddBoolAttribute(
- BoolAttribute attribute, bool value) {
+ AXBoolAttribute attribute, bool value) {
bool_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::AddIntListAttribute(
- IntListAttribute attribute, const std::vector<int32>& value) {
+ AXIntListAttribute attribute, const std::vector<int32>& value) {
intlist_attributes.push_back(std::make_pair(attribute, value));
}
void AXNodeData::SetName(std::string name) {
- string_attributes.push_back(std::make_pair(ATTR_NAME, name));
+ string_attributes.push_back(std::make_pair(AX_ATTR_NAME, name));
}
void AXNodeData::SetValue(std::string value) {
- string_attributes.push_back(std::make_pair(ATTR_VALUE, value));
+ string_attributes.push_back(std::make_pair(AX_ATTR_VALUE, value));
+}
+
+std::string AXNodeData::ToString() const {
+ std::string result;
+
+ result += "id=" + IntToString(id);
+ result += " " + ui::ToString(role);
+
+ if (state & (1 << ui::AX_STATE_BUSY))
+ result += " BUSY";
+ if (state & (1 << ui::AX_STATE_CHECKED))
+ result += " CHECKED";
+ if (state & (1 << ui::AX_STATE_COLLAPSED))
+ result += " COLLAPSED";
+ if (state & (1 << ui::AX_STATE_EXPANDED))
+ result += " EXPANDED";
+ if (state & (1 << ui::AX_STATE_FOCUSABLE))
+ result += " FOCUSABLE";
+ if (state & (1 << ui::AX_STATE_FOCUSED))
+ result += " FOCUSED";
+ if (state & (1 << ui::AX_STATE_HASPOPUP))
+ result += " HASPOPUP";
+ if (state & (1 << ui::AX_STATE_HOVERED))
+ result += " HOVERED";
+ if (state & (1 << ui::AX_STATE_INDETERMINATE))
+ result += " INDETERMINATE";
+ if (state & (1 << ui::AX_STATE_INVISIBLE))
+ result += " INVISIBLE";
+ if (state & (1 << ui::AX_STATE_LINKED))
+ result += " LINKED";
+ if (state & (1 << ui::AX_STATE_MULTISELECTABLE))
+ result += " MULTISELECTABLE";
+ if (state & (1 << ui::AX_STATE_OFFSCREEN))
+ result += " OFFSCREEN";
+ if (state & (1 << ui::AX_STATE_PRESSED))
+ result += " PRESSED";
+ if (state & (1 << ui::AX_STATE_PROTECTED))
+ result += " PROTECTED";
+ if (state & (1 << ui::AX_STATE_READ_ONLY))
+ result += " READONLY";
+ if (state & (1 << ui::AX_STATE_REQUIRED))
+ result += " REQUIRED";
+ if (state & (1 << ui::AX_STATE_SELECTABLE))
+ result += " SELECTABLE";
+ if (state & (1 << ui::AX_STATE_SELECTED))
+ result += " SELECTED";
+ if (state & (1 << ui::AX_STATE_VERTICAL))
+ result += " VERTICAL";
+ if (state & (1 << ui::AX_STATE_VISITED))
+ result += " VISITED";
+
+ result += " (" + IntToString(location.x()) + ", " +
+ IntToString(location.y()) + ")-(" +
+ IntToString(location.width()) + ", " +
+ IntToString(location.height()) + ")";
+
+ for (size_t i = 0; i < int_attributes.size(); ++i) {
+ std::string value = IntToString(int_attributes[i].second);
+ switch (int_attributes[i].first) {
+ case AX_ATTR_SCROLL_X:
+ result += " scroll_x=" + value;
+ break;
+ case AX_ATTR_SCROLL_X_MIN:
+ result += " scroll_x_min=" + value;
+ break;
+ case AX_ATTR_SCROLL_X_MAX:
+ result += " scroll_x_max=" + value;
+ break;
+ case AX_ATTR_SCROLL_Y:
+ result += " scroll_y=" + value;
+ break;
+ case AX_ATTR_SCROLL_Y_MIN:
+ result += " scroll_y_min=" + value;
+ break;
+ case AX_ATTR_SCROLL_Y_MAX:
+ result += " scroll_y_max=" + value;
+ break;
+ case AX_ATTR_HIERARCHICAL_LEVEL:
+ result += " level=" + value;
+ break;
+ case AX_ATTR_TEXT_SEL_START:
+ result += " sel_start=" + value;
+ break;
+ case AX_ATTR_TEXT_SEL_END:
+ result += " sel_end=" + value;
+ break;
+ case AX_ATTR_TABLE_ROW_COUNT:
+ result += " rows=" + value;
+ break;
+ case AX_ATTR_TABLE_COLUMN_COUNT:
+ result += " cols=" + value;
+ break;
+ case AX_ATTR_TABLE_CELL_COLUMN_INDEX:
+ result += " col=" + value;
+ break;
+ case AX_ATTR_TABLE_CELL_ROW_INDEX:
+ result += " row=" + value;
+ break;
+ case AX_ATTR_TABLE_CELL_COLUMN_SPAN:
+ result += " colspan=" + value;
+ break;
+ case AX_ATTR_TABLE_CELL_ROW_SPAN:
+ result += " rowspan=" + value;
+ break;
+ case AX_ATTR_TABLE_COLUMN_HEADER_ID:
+ result += " column_header_id=" + value;
+ break;
+ case AX_ATTR_TABLE_COLUMN_INDEX:
+ result += " column_index=" + value;
+ break;
+ case AX_ATTR_TABLE_HEADER_ID:
+ result += " header_id=" + value;
+ break;
+ case AX_ATTR_TABLE_ROW_HEADER_ID:
+ result += " row_header_id=" + value;
+ break;
+ case AX_ATTR_TABLE_ROW_INDEX:
+ result += " row_index=" + value;
+ break;
+ case AX_ATTR_TITLE_UI_ELEMENT:
+ result += " title_elem=" + value;
+ break;
+ case AX_ATTR_ACTIVEDESCENDANT_ID:
+ result += " activedescendant=" + value;
+ break;
+ case AX_ATTR_COLOR_VALUE_RED:
+ result += " color_value_red=" + value;
+ break;
+ case AX_ATTR_COLOR_VALUE_GREEN:
+ result += " color_value_green=" + value;
+ break;
+ case AX_ATTR_COLOR_VALUE_BLUE:
+ result += " color_value_blue=" + value;
+ break;
+ case AX_ATTR_TEXT_DIRECTION:
+ switch (int_attributes[i].second) {
+ case AX_TEXT_DIRECTION_LR:
+ default:
+ result += " text_direction=lr";
+ break;
+ case AX_TEXT_DIRECTION_RL:
+ result += " text_direction=rl";
+ break;
+ case AX_TEXT_DIRECTION_TB:
+ result += " text_direction=tb";
+ break;
+ case AX_TEXT_DIRECTION_BT:
+ result += " text_direction=bt";
+ break;
+ }
+ break;
+ case AX_INT_ATTRIBUTE_NONE:
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < string_attributes.size(); ++i) {
+ std::string value = string_attributes[i].second;
+ switch (string_attributes[i].first) {
+ case AX_ATTR_DOC_URL:
+ result += " doc_url=" + value;
+ break;
+ case AX_ATTR_DOC_TITLE:
+ result += " doc_title=" + value;
+ break;
+ case AX_ATTR_DOC_MIMETYPE:
+ result += " doc_mimetype=" + value;
+ break;
+ case AX_ATTR_DOC_DOCTYPE:
+ result += " doc_doctype=" + value;
+ break;
+ case AX_ATTR_ACCESS_KEY:
+ result += " access_key=" + value;
+ break;
+ case AX_ATTR_ACTION:
+ result += " action=" + value;
+ break;
+ case AX_ATTR_DESCRIPTION:
+ result += " description=" + value;
+ break;
+ case AX_ATTR_DISPLAY:
+ result += " display=" + value;
+ break;
+ case AX_ATTR_HELP:
+ result += " help=" + value;
+ break;
+ case AX_ATTR_HTML_TAG:
+ result += " html_tag=" + value;
+ break;
+ case AX_ATTR_LIVE_RELEVANT:
+ result += " relevant=" + value;
+ break;
+ case AX_ATTR_LIVE_STATUS:
+ result += " live=" + value;
+ break;
+ case AX_ATTR_CONTAINER_LIVE_RELEVANT:
+ result += " container_relevant=" + value;
+ break;
+ case AX_ATTR_CONTAINER_LIVE_STATUS:
+ result += " container_live=" + value;
+ break;
+ case AX_ATTR_ROLE:
+ result += " role=" + value;
+ break;
+ case AX_ATTR_SHORTCUT:
+ result += " shortcut=" + value;
+ break;
+ case AX_ATTR_URL:
+ result += " url=" + value;
+ break;
+ case AX_ATTR_NAME:
+ result += " name=" + value;
+ break;
+ case AX_ATTR_VALUE:
+ result += " value=" + value;
+ break;
+ case AX_STRING_ATTRIBUTE_NONE:
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < float_attributes.size(); ++i) {
+ std::string value = DoubleToString(float_attributes[i].second);
+ switch (float_attributes[i].first) {
+ case AX_ATTR_DOC_LOADING_PROGRESS:
+ result += " doc_progress=" + value;
+ break;
+ case AX_ATTR_VALUE_FOR_RANGE:
+ result += " value_for_range=" + value;
+ break;
+ case AX_ATTR_MAX_VALUE_FOR_RANGE:
+ result += " max_value=" + value;
+ break;
+ case AX_ATTR_MIN_VALUE_FOR_RANGE:
+ result += " min_value=" + value;
+ break;
+ case AX_FLOAT_ATTRIBUTE_NONE:
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < bool_attributes.size(); ++i) {
+ std::string value = bool_attributes[i].second ? "true" : "false";
+ switch (bool_attributes[i].first) {
+ case AX_ATTR_DOC_LOADED:
+ result += " doc_loaded=" + value;
+ break;
+ case AX_ATTR_BUTTON_MIXED:
+ result += " mixed=" + value;
+ break;
+ case AX_ATTR_LIVE_ATOMIC:
+ result += " atomic=" + value;
+ break;
+ case AX_ATTR_LIVE_BUSY:
+ result += " busy=" + value;
+ break;
+ case AX_ATTR_CONTAINER_LIVE_ATOMIC:
+ result += " container_atomic=" + value;
+ break;
+ case AX_ATTR_CONTAINER_LIVE_BUSY:
+ result += " container_busy=" + value;
+ break;
+ case AX_ATTR_ARIA_READONLY:
+ result += " aria_readonly=" + value;
+ break;
+ case AX_ATTR_CAN_SET_VALUE:
+ result += " can_set_value=" + value;
+ break;
+ case AX_ATTR_UPDATE_LOCATION_ONLY:
+ result += " update_location_only=" + value;
+ break;
+ case AX_ATTR_CANVAS_HAS_FALLBACK:
+ result += " has_fallback=" + value;
+ break;
+ case AX_BOOL_ATTRIBUTE_NONE:
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < intlist_attributes.size(); ++i) {
+ const std::vector<int32>& values = intlist_attributes[i].second;
+ switch (intlist_attributes[i].first) {
+ case AX_ATTR_INDIRECT_CHILD_IDS:
+ result += " indirect_child_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_CONTROLS_IDS:
+ result += " controls_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_DESCRIBEDBY_IDS:
+ result += " describedby_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_FLOWTO_IDS:
+ result += " flowto_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_LABELLEDBY_IDS:
+ result += " labelledby_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_OWNS_IDS:
+ result += " owns_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_LINE_BREAKS:
+ result += " line_breaks=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_CELL_IDS:
+ result += " cell_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_UNIQUE_CELL_IDS:
+ result += " unique_cell_ids=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_CHARACTER_OFFSETS:
+ result += " character_offsets=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_WORD_STARTS:
+ result += " word_starts=" + IntVectorToString(values);
+ break;
+ case AX_ATTR_WORD_ENDS:
+ result += " word_ends=" + IntVectorToString(values);
+ break;
+ case AX_INT_LIST_ATTRIBUTE_NONE:
+ break;
+ }
+ }
+
+ if (!child_ids.empty())
+ result += " child_ids=" + IntVectorToString(child_ids);
+
+ return result;
}
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h
index 1c5defb8b48..cd30fbb2c06 100644
--- a/chromium/ui/accessibility/ax_node_data.h
+++ b/chromium/ui/accessibility/ax_node_data.h
@@ -20,159 +20,15 @@ namespace ui {
// single web object, in a form that can be serialized and sent from
// one process to another.
struct AX_EXPORT AXNodeData {
- // Additional optional attributes that can be optionally attached to
- // a node.
- enum StringAttribute {
- // Document attributes.
- ATTR_DOC_URL,
- ATTR_DOC_TITLE,
- ATTR_DOC_MIMETYPE,
- ATTR_DOC_DOCTYPE,
-
- // Attributes that could apply to any node.
- ATTR_ACCESS_KEY,
- ATTR_ACTION,
- ATTR_CONTAINER_LIVE_RELEVANT,
- ATTR_CONTAINER_LIVE_STATUS,
- ATTR_DESCRIPTION,
- ATTR_DISPLAY,
- ATTR_HELP,
- ATTR_HTML_TAG,
- ATTR_NAME,
- ATTR_LIVE_RELEVANT,
- ATTR_LIVE_STATUS,
- ATTR_ROLE,
- ATTR_SHORTCUT,
- ATTR_URL,
- ATTR_VALUE,
- };
-
- enum IntAttribute {
- // Scrollable container attributes.
- ATTR_SCROLL_X,
- ATTR_SCROLL_X_MIN,
- ATTR_SCROLL_X_MAX,
- ATTR_SCROLL_Y,
- ATTR_SCROLL_Y_MIN,
- ATTR_SCROLL_Y_MAX,
-
- // Editable text attributes.
- ATTR_TEXT_SEL_START,
- ATTR_TEXT_SEL_END,
-
- // Table attributes.
- ATTR_TABLE_ROW_COUNT,
- ATTR_TABLE_COLUMN_COUNT,
- ATTR_TABLE_HEADER_ID,
-
- // Table row attributes.
- ATTR_TABLE_ROW_INDEX,
- ATTR_TABLE_ROW_HEADER_ID,
-
- // Table column attributes.
- ATTR_TABLE_COLUMN_INDEX,
- ATTR_TABLE_COLUMN_HEADER_ID,
-
- // Table cell attributes.
- ATTR_TABLE_CELL_COLUMN_INDEX,
- ATTR_TABLE_CELL_COLUMN_SPAN,
- ATTR_TABLE_CELL_ROW_INDEX,
- ATTR_TABLE_CELL_ROW_SPAN,
-
- // Tree control attributes.
- ATTR_HIERARCHICAL_LEVEL,
-
- // Relationships between this element and other elements.
- ATTR_TITLE_UI_ELEMENT,
-
- // Color value for AX_ROLE_COLOR_WELL, each component is 0..255
- ATTR_COLOR_VALUE_RED,
- ATTR_COLOR_VALUE_GREEN,
- ATTR_COLOR_VALUE_BLUE,
-
- // Inline text attributes.
- ATTR_TEXT_DIRECTION
- };
-
- enum FloatAttribute {
- // Document attributes.
- ATTR_DOC_LOADING_PROGRESS,
-
- // Range attributes.
- ATTR_VALUE_FOR_RANGE,
- ATTR_MIN_VALUE_FOR_RANGE,
- ATTR_MAX_VALUE_FOR_RANGE,
- };
-
- enum BoolAttribute {
- // Document attributes.
- ATTR_DOC_LOADED,
-
- // True if a checkbox or radio button is in the "mixed" state.
- ATTR_BUTTON_MIXED,
-
- // Live region attributes.
- ATTR_CONTAINER_LIVE_ATOMIC,
- ATTR_CONTAINER_LIVE_BUSY,
- ATTR_LIVE_ATOMIC,
- ATTR_LIVE_BUSY,
-
- // ARIA readonly flag.
- ATTR_ARIA_READONLY,
-
- // Writeable attributes
- ATTR_CAN_SET_VALUE,
-
- // If this is set, all of the other fields in this struct should
- // be ignored and only the locations should change.
- ATTR_UPDATE_LOCATION_ONLY,
-
- // Set on a canvas element if it has fallback content.
- ATTR_CANVAS_HAS_FALLBACK,
- };
-
- enum IntListAttribute {
- // Ids of nodes that are children of this node logically, but are
- // not children of this node in the tree structure. As an example,
- // a table cell is a child of a row, and an 'indirect' child of a
- // column.
- ATTR_INDIRECT_CHILD_IDS,
-
- // Character indices where line breaks occur.
- ATTR_LINE_BREAKS,
-
- // For a table, the cell ids in row-major order, with duplicate entries
- // when there's a rowspan or colspan, and with -1 for missing cells.
- // There are always exactly rows * columns entries.
- ATTR_CELL_IDS,
-
- // For a table, the unique cell ids in row-major order of their first
- // occurrence.
- ATTR_UNIQUE_CELL_IDS,
-
- // For inline text. This is the pixel position of the end of this
- // character within the bounding rectangle of this object, in the
- // direction given by ATTR_TEXT_DIRECTION. For example, for left-to-right
- // text, the first offset is the right coordinate of the first character
- // within the object's bounds, the second offset is the right coordinate
- // of the second character, and so on.
- ATTR_CHARACTER_OFFSETS,
-
- // For inline text. These int lists must be the same size; they represent
- // the start and end character index of each word within this text.
- ATTR_WORD_STARTS,
- ATTR_WORD_ENDS,
- };
-
AXNodeData();
virtual ~AXNodeData();
- void AddStringAttribute(StringAttribute attribute,
+ void AddStringAttribute(AXStringAttribute attribute,
const std::string& value);
- void AddIntAttribute(IntAttribute attribute, int value);
- void AddFloatAttribute(FloatAttribute attribute, float value);
- void AddBoolAttribute(BoolAttribute attribute, bool value);
- void AddIntListAttribute(IntListAttribute attribute,
+ void AddIntAttribute(AXIntAttribute attribute, int value);
+ void AddFloatAttribute(AXFloatAttribute attribute, float value);
+ void AddBoolAttribute(AXBoolAttribute attribute, bool value);
+ void AddIntListAttribute(AXIntListAttribute attribute,
const std::vector<int32>& value);
// Convenience functions, mainly for writing unit tests.
@@ -181,17 +37,20 @@ struct AX_EXPORT AXNodeData {
// Equivalent to AddStringAttribute(ATTR_VALUE, value).
void SetValue(std::string value);
+ // Return a string representation of this data, for debugging.
+ std::string ToString() const;
+
// This is a simple serializable struct. All member variables should be
// public and copyable.
int32 id;
AXRole role;
uint32 state;
gfx::Rect location;
- std::vector<std::pair<StringAttribute, std::string> > string_attributes;
- std::vector<std::pair<IntAttribute, int32> > int_attributes;
- std::vector<std::pair<FloatAttribute, float> > float_attributes;
- std::vector<std::pair<BoolAttribute, bool> > bool_attributes;
- std::vector<std::pair<IntListAttribute, std::vector<int32> > >
+ std::vector<std::pair<AXStringAttribute, std::string> > string_attributes;
+ std::vector<std::pair<AXIntAttribute, int32> > int_attributes;
+ std::vector<std::pair<AXFloatAttribute, float> > float_attributes;
+ std::vector<std::pair<AXBoolAttribute, bool> > bool_attributes;
+ std::vector<std::pair<AXIntListAttribute, std::vector<int32> > >
intlist_attributes;
std::vector<std::pair<std::string, std::string> > html_attributes;
std::vector<int32> child_ids;
diff --git a/chromium/ui/accessibility/ax_serializable_tree.cc b/chromium/ui/accessibility/ax_serializable_tree.cc
index ca52ab39a23..4e4da834d80 100644
--- a/chromium/ui/accessibility/ax_serializable_tree.cc
+++ b/chromium/ui/accessibility/ax_serializable_tree.cc
@@ -14,7 +14,7 @@ namespace ui {
// AXTreeSource abstraction and doesn't need to actually know about
// AXTree directly. Another AXTreeSource is used to abstract the Blink
// accessibility tree.
-class AX_EXPORT AXTreeSourceAdapter : public AXTreeSource<AXNode> {
+class AX_EXPORT AXTreeSourceAdapter : public AXTreeSource<const AXNode*> {
public:
AXTreeSourceAdapter(AXTree* tree) : tree_(tree) {}
virtual ~AXTreeSourceAdapter() {}
@@ -32,19 +32,30 @@ class AX_EXPORT AXTreeSourceAdapter : public AXTreeSource<AXNode> {
return node->id();
}
- virtual int GetChildCount(const AXNode* node) const OVERRIDE {
- return node->child_count();
- }
-
- virtual AXNode* GetChildAtIndex(const AXNode* node, int index)
- const OVERRIDE {
- return node->ChildAtIndex(index);
+ virtual void GetChildren(
+ const AXNode* node,
+ std::vector<const AXNode*>* out_children) const OVERRIDE {
+ for (int i = 0; i < node->child_count(); ++i)
+ out_children->push_back(node->ChildAtIndex(i));
}
virtual AXNode* GetParent(const AXNode* node) const OVERRIDE {
return node->parent();
}
+ virtual bool IsValid(const AXNode* node) const OVERRIDE {
+ return node != NULL;
+ }
+
+ virtual bool IsEqual(const AXNode* node1,
+ const AXNode* node2) const OVERRIDE {
+ return node1 == node2;
+ }
+
+ virtual const AXNode* GetNull() const OVERRIDE {
+ return NULL;
+ }
+
virtual void SerializeNode(
const AXNode* node, AXNodeData* out_data) const OVERRIDE {
*out_data = node->data();
@@ -64,7 +75,7 @@ AXSerializableTree::AXSerializableTree(const AXTreeUpdate& initial_state)
AXSerializableTree::~AXSerializableTree() {
}
-AXTreeSource<AXNode>* AXSerializableTree::CreateTreeSource() {
+AXTreeSource<const AXNode*>* AXSerializableTree::CreateTreeSource() {
return new AXTreeSourceAdapter(this);
}
diff --git a/chromium/ui/accessibility/ax_serializable_tree.h b/chromium/ui/accessibility/ax_serializable_tree.h
index c070565a8d1..994be7d1c28 100644
--- a/chromium/ui/accessibility/ax_serializable_tree.h
+++ b/chromium/ui/accessibility/ax_serializable_tree.h
@@ -18,7 +18,7 @@ class AX_EXPORT AXSerializableTree : public AXTree {
// Create a TreeSource adapter for this tree. The client gets ownership
// of the return value and should delete it when done.
- virtual AXTreeSource<AXNode>* CreateTreeSource();
+ virtual AXTreeSource<const AXNode*>* CreateTreeSource();
};
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_text_utils.cc b/chromium/ui/accessibility/ax_text_utils.cc
new file mode 100644
index 00000000000..08cd562ecd0
--- /dev/null
+++ b/chromium/ui/accessibility/ax_text_utils.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/ax_text_utils.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace ui {
+
+size_t FindAccessibleTextBoundary(const base::string16& text,
+ const std::vector<int>& line_breaks,
+ TextBoundaryType boundary,
+ size_t start_offset,
+ TextBoundaryDirection direction) {
+ size_t text_size = text.size();
+ DCHECK(start_offset <= text_size);
+
+ if (boundary == CHAR_BOUNDARY) {
+ if (direction == FORWARDS_DIRECTION && start_offset < text_size)
+ return start_offset + 1;
+ else
+ return start_offset;
+ } else if (boundary == LINE_BOUNDARY) {
+ if (direction == FORWARDS_DIRECTION) {
+ for (size_t j = 0; j < line_breaks.size(); ++j) {
+ size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0;
+ if (line_break > start_offset)
+ return line_break;
+ }
+ return text_size;
+ } else {
+ for (size_t j = line_breaks.size(); j != 0; --j) {
+ size_t line_break = line_breaks[j - 1] >= 0 ? line_breaks[j - 1] : 0;
+ if (line_break <= start_offset)
+ return line_break;
+ }
+ return 0;
+ }
+ }
+
+ size_t result = start_offset;
+ for (;;) {
+ size_t pos;
+ if (direction == FORWARDS_DIRECTION) {
+ if (result >= text_size)
+ return text_size;
+ pos = result;
+ } else {
+ if (result == 0)
+ return 0;
+ pos = result - 1;
+ }
+
+ switch (boundary) {
+ case CHAR_BOUNDARY:
+ case LINE_BOUNDARY:
+ NOTREACHED(); // These are handled above.
+ break;
+ case WORD_BOUNDARY:
+ if (IsWhitespace(text[pos]))
+ return result;
+ break;
+ case PARAGRAPH_BOUNDARY:
+ if (text[pos] == '\n')
+ return result;
+ break;
+ case SENTENCE_BOUNDARY:
+ if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') &&
+ (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) {
+ return result;
+ }
+ break;
+ case ALL_BOUNDARY:
+ default:
+ break;
+ }
+
+ if (direction == FORWARDS_DIRECTION) {
+ result++;
+ } else {
+ result--;
+ }
+ }
+}
+
+} // Namespace ui
diff --git a/chromium/ui/accessibility/ax_text_utils.h b/chromium/ui/accessibility/ax_text_utils.h
new file mode 100644
index 00000000000..2dc2d2f03ee
--- /dev/null
+++ b/chromium/ui/accessibility/ax_text_utils.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_TEXT_UTILS_H_
+#define UI_ACCESSIBILITY_AX_TEXT_UTILS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+// Boundaries that can be passed to FindAccessibleTextBoundary,
+// representing various visual boundaries in (potentially multi-line)
+// text. This is used by assistive technology in order to, for example,
+// retrieve the nearest word to the cursor, or retrieve all of the
+// text from the current cursor position to the end of the line.
+// These should be self-explanatory; "line" here refers to the visual
+// line as currently displayed (possibly affected by wrapping).
+enum TextBoundaryType {
+ CHAR_BOUNDARY,
+ WORD_BOUNDARY,
+ LINE_BOUNDARY,
+ SENTENCE_BOUNDARY,
+ PARAGRAPH_BOUNDARY,
+ ALL_BOUNDARY
+};
+
+// A direction when searching for the next boundary.
+enum TextBoundaryDirection {
+ // Search forwards for the next boundary past the starting position.
+ FORWARDS_DIRECTION,
+ // Search backwards for the previous boundary before the starting position.
+ BACKWARDS_DIRECTION
+};
+
+// Convenience method needed to implement platform-specific text
+// accessibility APIs like IAccessible2. Search forwards or backwards
+// (depending on |direction|) from the given |start_offset| until the
+// given boundary is found, and return the offset of that boundary,
+// using the vector of line break character offsets in |line_breaks|.
+size_t AX_EXPORT
+ FindAccessibleTextBoundary(const base::string16& text,
+ const std::vector<int>& line_breaks,
+ TextBoundaryType boundary,
+ size_t start_offset,
+ TextBoundaryDirection direction);
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TEXT_UTILS_H_
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index 5edb649ae85..359c8e2fe1d 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -12,10 +12,40 @@
namespace ui {
+namespace {
+
+std::string TreeToStringHelper(AXNode* node, int indent) {
+ std::string result = std::string(2 * indent, ' ');
+ result += node->data().ToString() + "\n";
+ for (int i = 0; i < node->child_count(); ++i)
+ result += TreeToStringHelper(node->ChildAtIndex(i), indent + 1);
+ return result;
+}
+
+} // anonymous namespace
+
+// Intermediate state to keep track of during a tree update.
+struct AXTreeUpdateState {
+ // During an update, this keeps track of all nodes that have been
+ // implicitly referenced as part of this update, but haven't been
+ // updated yet. It's an error if there are any pending nodes at the
+ // end of Unserialize.
+ std::set<AXNode*> pending_nodes;
+
+ // Keeps track of new nodes created during this update.
+ std::set<AXNode*> new_nodes;
+};
+
+AXTreeDelegate::AXTreeDelegate() {
+}
+
+AXTreeDelegate::~AXTreeDelegate() {
+}
+
AXTree::AXTree()
- : root_(NULL) {
+ : delegate_(NULL), root_(NULL) {
AXNodeData root;
- root.id = 0;
+ root.id = -1;
root.role = AX_ROLE_ROOT_WEB_AREA;
AXTreeUpdate initial_state;
@@ -24,7 +54,7 @@ AXTree::AXTree()
}
AXTree::AXTree(const AXTreeUpdate& initial_state)
- : root_(NULL) {
+ : delegate_(NULL), root_(NULL) {
CHECK(Unserialize(initial_state)) << error();
}
@@ -33,6 +63,10 @@ AXTree::~AXTree() {
DestroyNodeAndSubtree(root_);
}
+void AXTree::SetDelegate(AXTreeDelegate* delegate) {
+ delegate_ = delegate;
+}
+
AXNode* AXTree::GetRoot() const {
return root_;
}
@@ -43,7 +77,8 @@ AXNode* AXTree::GetFromId(int32 id) const {
}
bool AXTree::Unserialize(const AXTreeUpdate& update) {
- std::set<AXNode*> pending_nodes;
+ AXTreeUpdateState update_state;
+ int32 old_root_id = root_ ? root_->id() : 0;
if (update.node_id_to_clear != 0) {
AXNode* node = GetFromId(update.node_id_to_clear);
@@ -60,33 +95,56 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
DestroyNodeAndSubtree(node->ChildAtIndex(i));
std::vector<AXNode*> children;
node->SwapChildren(children);
- pending_nodes.insert(node);
+ update_state.pending_nodes.insert(node);
}
}
for (size_t i = 0; i < update.nodes.size(); ++i) {
- if (!UpdateNode(update.nodes[i], &pending_nodes))
+ if (!UpdateNode(update.nodes[i], &update_state))
return false;
}
- if (!pending_nodes.empty()) {
+ if (!update_state.pending_nodes.empty()) {
error_ = "Nodes left pending by the update:";
- for (std::set<AXNode*>::iterator iter = pending_nodes.begin();
- iter != pending_nodes.end(); ++iter) {
+ for (std::set<AXNode*>::iterator iter = update_state.pending_nodes.begin();
+ iter != update_state.pending_nodes.end(); ++iter) {
error_ += base::StringPrintf(" %d", (*iter)->id());
}
return false;
}
+ if (delegate_) {
+ for (size_t i = 0; i < update.nodes.size(); ++i) {
+ AXNode* node = GetFromId(update.nodes[i].id);
+ if (update_state.new_nodes.find(node) != update_state.new_nodes.end()) {
+ delegate_->OnNodeCreationFinished(node);
+ update_state.new_nodes.erase(node);
+ } else {
+ delegate_->OnNodeChangeFinished(node);
+ }
+ }
+ if (root_->id() != old_root_id)
+ delegate_->OnRootChanged(root_);
+ }
+
return true;
}
-AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) {
- return new AXNode(parent, id, index_in_parent);
+std::string AXTree::ToString() const {
+ return TreeToStringHelper(root_, 0);
+}
+
+AXNode* AXTree::CreateNode(
+ AXNode* parent, int32 id, int32 index_in_parent) {
+ AXNode* new_node = new AXNode(parent, id, index_in_parent);
+ id_map_[new_node->id()] = new_node;
+ if (delegate_)
+ delegate_->OnNodeCreated(new_node);
+ return new_node;
}
bool AXTree::UpdateNode(
- const AXNodeData& src, std::set<AXNode*>* pending_nodes) {
+ const AXNodeData& src, AXTreeUpdateState* update_state) {
// This method updates one node in the tree based on serialized data
// received in an AXTreeUpdate. See AXTreeUpdate for pre and post
// conditions.
@@ -95,30 +153,38 @@ bool AXTree::UpdateNode(
// of the tree is being swapped, or we're out of sync with the source
// and this is a serious error.
AXNode* node = GetFromId(src.id);
+ AXNode* new_node = NULL;
if (node) {
- pending_nodes->erase(node);
+ update_state->pending_nodes.erase(node);
+ node->SetData(src);
} else {
if (src.role != AX_ROLE_ROOT_WEB_AREA) {
error_ = base::StringPrintf(
"%d is not in the tree and not the new root", src.id);
return false;
}
- node = CreateAndInitializeNode(NULL, src.id, 0);
+ new_node = CreateNode(NULL, src.id, 0);
+ node = new_node;
+ update_state->new_nodes.insert(node);
+ node->SetData(src);
}
- // Set the node's data.
- node->SetData(src);
+ if (delegate_)
+ delegate_->OnNodeChanged(node);
// First, delete nodes that used to be children of this node but aren't
// anymore.
- if (!DeleteOldChildren(node, src.child_ids))
+ if (!DeleteOldChildren(node, src.child_ids)) {
+ if (new_node)
+ DestroyNodeAndSubtree(new_node);
return false;
+ }
// Now build a new children vector, reusing nodes when possible,
// and swap it in.
std::vector<AXNode*> new_children;
bool success = CreateNewChildVector(
- node, src.child_ids, &new_children, pending_nodes);
+ node, src.child_ids, &new_children, update_state);
node->SwapChildren(new_children);
// Update the root of the tree if needed.
@@ -127,26 +193,17 @@ bool AXTree::UpdateNode(
if (root_)
DestroyNodeAndSubtree(root_);
root_ = node;
- OnRootChanged();
}
return success;
}
-void AXTree::OnRootChanged() {
-}
-
-AXNode* AXTree::CreateAndInitializeNode(
- AXNode* parent, int32 id, int32 index_in_parent) {
- AXNode* node = CreateNode(parent, id, index_in_parent);
- id_map_[node->id()] = node;
- return node;
-}
-
void AXTree::DestroyNodeAndSubtree(AXNode* node) {
id_map_.erase(node->id());
for (int i = 0; i < node->child_count(); ++i)
DestroyNodeAndSubtree(node->ChildAtIndex(i));
+ if (delegate_)
+ delegate_->OnNodeWillBeDeleted(node);
node->Destroy();
}
@@ -178,7 +235,7 @@ bool AXTree::DeleteOldChildren(AXNode* node,
bool AXTree::CreateNewChildVector(AXNode* node,
const std::vector<int32> new_child_ids,
std::vector<AXNode*>* new_children,
- std::set<AXNode*>* pending_nodes) {
+ AXTreeUpdateState* update_state) {
bool success = true;
for (size_t i = 0; i < new_child_ids.size(); ++i) {
int32 child_id = new_child_ids[i];
@@ -199,8 +256,9 @@ bool AXTree::CreateNewChildVector(AXNode* node,
}
child->SetIndexInParent(index_in_parent);
} else {
- child = CreateAndInitializeNode(node, child_id, index_in_parent);
- pending_nodes->insert(child);
+ child = CreateNode(node, child_id, index_in_parent);
+ update_state->pending_nodes.insert(child);
+ update_state->new_nodes.insert(child);
}
new_children->push_back(child);
}
diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h
index 773a773adf5..b4baac460cc 100644
--- a/chromium/ui/accessibility/ax_tree.h
+++ b/chromium/ui/accessibility/ax_tree.h
@@ -9,12 +9,57 @@
#include "base/containers/hash_tables.h"
#include "ui/accessibility/ax_export.h"
-#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_update.h"
namespace ui {
class AXNode;
+struct AXTreeUpdateState;
+
+// Used when you want to be notified when changes happen to the tree.
+//
+// Some of the notifications are called in the middle of an update operation.
+// Be careful, as the tree may be in an inconsistent state at this time;
+// don't walk the parents and children at this time:
+// OnNodeWillBeDeleted
+// OnNodeCreated
+// OnNodeChanged
+//
+// Other notifications are called at the end of an atomic update operation.
+// From these, it's safe to walk the tree and do any initialization that
+// assumes the tree is in a consistent state.
+// OnNodeCreationFinished
+// OnNodeChangeFinished
+// OnRootChanged
+class AX_EXPORT AXTreeDelegate {
+ public:
+ AXTreeDelegate();
+ virtual ~AXTreeDelegate();
+
+ // Called just before a node is deleted. Its id and data will be valid,
+ // but its links to parents and children are invalid. This is called
+ // in the middle of an update, the tree may be in an invalid state!
+ virtual void OnNodeWillBeDeleted(AXNode* node) = 0;
+
+ // Called immediately after a new node is created. The tree may be in
+ // the middle of an update, don't walk the parents and children now.
+ virtual void OnNodeCreated(AXNode* node) = 0;
+
+ // Called when a node changes its data or children. The tree may be in
+ // the middle of an update, don't walk the parents and children now.
+ virtual void OnNodeChanged(AXNode* node) = 0;
+
+ // Called for each new node at the end of an update operation,
+ // when the tree is in a consistent state.
+ virtual void OnNodeCreationFinished(AXNode* node) = 0;
+
+ // Called for each existing node that changed at the end of an update
+ // operation, when the tree is in a consistent state.
+ virtual void OnNodeChangeFinished(AXNode* node) = 0;
+
+ // Called at the end of an update operation when the root node changes.
+ virtual void OnRootChanged(AXNode* new_root) = 0;
+};
// AXTree is a live, managed tree of AXNode objects that can receive
// updates from another AXTreeSource via AXTreeUpdates, and it can be
@@ -27,6 +72,8 @@ class AX_EXPORT AXTree {
explicit AXTree(const AXTreeUpdate& initial_state);
virtual ~AXTree();
+ virtual void SetDelegate(AXTreeDelegate* delegate);
+
virtual AXNode* GetRoot() const;
virtual AXNode* GetFromId(int32 id) const;
@@ -35,29 +82,20 @@ class AX_EXPORT AXTree {
// should not be trusted any longer.
virtual bool Unserialize(const AXTreeUpdate& update);
+ // Return a multi-line indented string representation, for logging.
+ std::string ToString() const;
+
// A string describing the error from an unsuccessful Unserialize,
// for testing and debugging.
const std::string& error() { return error_; }
- protected:
- // Subclasses can override this to use a subclass of AXNode.
- virtual AXNode* CreateNode(AXNode* parent, int32 id, int32 index_in_parent);
+ private:
+ AXNode* CreateNode(AXNode* parent, int32 id, int32 index_in_parent);
// This is called from within Unserialize(), it returns true on success.
- // Subclasses can override this to do additional processing. |pending_nodes|
- // is updated to contain all nodes that have been implicitly referenced
- // as part of this update, but haven't been updated yet. It's an error if
- // there are any pending nodes at the end of Unserialize.
- virtual bool UpdateNode(const AXNodeData& src,
- std::set<AXNode*>* pending_nodes);
-
- // Subclasses can override this to do special behavior when the root changes.
- virtual void OnRootChanged();
+ bool UpdateNode(const AXNodeData& src, AXTreeUpdateState* update_state);
- private:
- // Convenience function to create a node and call Initialize on it.
- AXNode* CreateAndInitializeNode(
- AXNode* parent, int32 id, int32 index_in_parent);
+ void OnRootChanged();
// Call Destroy() on |node|, and delete it from the id map, and then
// call recursively on all nodes in its subtree.
@@ -73,13 +111,13 @@ class AX_EXPORT AXTree {
// pointers to child nodes, reusing existing nodes already in the tree
// if they exist, and creating otherwise. Reparenting is disallowed, so
// if the id already exists as the child of another node, that's an
- // error. Returns true on success, false on fatal error. See
- // UpdateNode, above, for an explanation of |pending_nodes|.
+ // error. Returns true on success, false on fatal error.
bool CreateNewChildVector(AXNode* node,
const std::vector<int32> new_child_ids,
std::vector<AXNode*>* new_children,
- std::set<AXNode*>* pending_nodes);
+ AXTreeUpdateState* update_state);
+ AXTreeDelegate* delegate_;
AXNode* root_;
base::hash_map<int32, AXNode*> id_map_;
std::string error_;
diff --git a/chromium/ui/accessibility/ax_tree_serializer.h b/chromium/ui/accessibility/ax_tree_serializer.h
index e6049964c76..f1cbfcea105 100644
--- a/chromium/ui/accessibility/ax_tree_serializer.h
+++ b/chromium/ui/accessibility/ax_tree_serializer.h
@@ -51,7 +51,7 @@ struct ClientTreeNode;
// because AXTreeSerializer always keeps track of what updates it's sent,
// it will never send an invalid update and the client tree will not break,
// it just may not contain all of the changes.
-template<class AXSourceNode>
+template<typename AXSourceNode>
class AXTreeSerializer {
public:
explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
@@ -63,9 +63,13 @@ class AXTreeSerializer {
void Reset();
// Serialize all changes to |node| and append them to |out_update|.
- void SerializeChanges(const AXSourceNode* node,
+ void SerializeChanges(AXSourceNode node,
AXTreeUpdate* out_update);
+ // Delete the client subtree for this node, ensuring that the subtree
+ // is re-serialized.
+ void DeleteClientSubtree(AXSourceNode node);
+
// Only for unit testing. Normally this class relies on getting a call
// to SerializeChanges() every time the source tree changes. For unit
// testing, it's convenient to create a static AXTree for the initial
@@ -107,21 +111,21 @@ class AXTreeSerializer {
// LCA(source node 5, client node 5) is node 1.
// It's not node 5, because the two trees disagree on the parent of
// node 4, so the LCA is the first ancestor both trees agree on.
- const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node,
- ClientTreeNode* client_node);
+ AXSourceNode LeastCommonAncestor(AXSourceNode node,
+ ClientTreeNode* client_node);
// Return the least common ancestor of |node| that's in the client tree.
// This just walks up the ancestors of |node| until it finds a node that's
// also in the client tree, and then calls LeastCommonAncestor on the
// source node and client node.
- const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node);
+ AXSourceNode LeastCommonAncestor(AXSourceNode node);
// Walk the subtree rooted at |node| and return true if any nodes that
- // would be updated are being reparented. If so, update |lca| to point
+ // would be updated are being reparented. If so, update |out_lca| to point
// to the least common ancestor of the previous LCA and the previous
// parent of the node being reparented.
- bool AnyDescendantWasReparented(const AXSourceNode* node,
- const AXSourceNode** lca);
+ bool AnyDescendantWasReparented(AXSourceNode node,
+ AXSourceNode* out_lca);
ClientTreeNode* ClientTreeNodeById(int32 id);
@@ -130,7 +134,7 @@ class AXTreeSerializer {
void DeleteClientSubtree(ClientTreeNode* client_node);
// Helper function, called recursively with each new node to serialize.
- void SerializeChangedNodes(const AXSourceNode* node,
+ void SerializeChangedNodes(AXSourceNode node,
AXTreeUpdate* out_update);
// The tree source.
@@ -154,40 +158,43 @@ struct AX_EXPORT ClientTreeNode {
std::vector<ClientTreeNode*> children;
};
-template<class AXSourceNode>
+template<typename AXSourceNode>
AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
AXTreeSource<AXSourceNode>* tree)
: tree_(tree),
client_root_(NULL) {
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
Reset();
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
void AXTreeSerializer<AXSourceNode>::Reset() {
- if (client_root_) {
- DeleteClientSubtree(client_root_);
- client_root_ = NULL;
- }
+ if (!client_root_)
+ return;
+
+ DeleteClientSubtree(client_root_);
+ client_id_map_.erase(client_root_->id);
+ delete client_root_;
+ client_root_ = NULL;
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting(
AXTreeSource<AXSourceNode>* new_tree) {
tree_ = new_tree;
}
-template<class AXSourceNode>
-const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
- const AXSourceNode* node, ClientTreeNode* client_node) {
- if (node == NULL || client_node == NULL)
- return NULL;
+template<typename AXSourceNode>
+AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
+ AXSourceNode node, ClientTreeNode* client_node) {
+ if (!tree_->IsValid(node) || client_node == NULL)
+ return tree_->GetNull();
- std::vector<const AXSourceNode*> ancestors;
- while (node) {
+ std::vector<AXSourceNode> ancestors;
+ while (tree_->IsValid(node)) {
ancestors.push_back(node);
node = tree_->GetParent(node);
}
@@ -201,7 +208,7 @@ const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
// Start at the root. Keep going until the source ancestor chain and
// client ancestor chain disagree. The last node before they disagree
// is the LCA.
- const AXSourceNode* lca = NULL;
+ AXSourceNode lca = tree_->GetNull();
int source_index = static_cast<int>(ancestors.size() - 1);
int client_index = static_cast<int>(client_ancestors.size() - 1);
while (source_index >= 0 && client_index >= 0) {
@@ -216,40 +223,41 @@ const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
return lca;
}
-template<class AXSourceNode>
-const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
- const AXSourceNode* node) {
+template<typename AXSourceNode>
+AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
+ AXSourceNode node) {
// Walk up the tree until the source node's id also exists in the
// client tree, then call LeastCommonAncestor on those two nodes.
ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
- while (node && !client_node) {
+ while (tree_->IsValid(node) && !client_node) {
node = tree_->GetParent(node);
- if (node)
+ if (tree_->IsValid(node))
client_node = ClientTreeNodeById(tree_->GetId(node));
}
return LeastCommonAncestor(node, client_node);
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
- const AXSourceNode* node, const AXSourceNode** lca) {
+ AXSourceNode node, AXSourceNode* out_lca) {
bool result = false;
int id = tree_->GetId(node);
- int child_count = tree_->GetChildCount(node);
- for (int i = 0; i < child_count; ++i) {
- const AXSourceNode* child = tree_->GetChildAtIndex(node, i);
+ std::vector<AXSourceNode> children;
+ tree_->GetChildren(node, &children);
+ for (size_t i = 0; i < children.size(); ++i) {
+ AXSourceNode& child = children[i];
int child_id = tree_->GetId(child);
ClientTreeNode* client_child = ClientTreeNodeById(child_id);
if (client_child) {
if (!client_child->parent) {
// If the client child has no parent, it must have been the
// previous root node, so there is no LCA and we can exit early.
- *lca = NULL;
+ *out_lca = tree_->GetNull();
return true;
} else if (client_child->parent->id != id) {
// If the client child's parent is not this node, update the LCA
// and return true (reparenting was found).
- *lca = LeastCommonAncestor(*lca, client_child);
+ *out_lca = LeastCommonAncestor(*out_lca, client_child);
result = true;
} else {
// This child is already in the client tree, we won't
@@ -260,13 +268,13 @@ bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
}
// This is a new child or reparented child, check it recursively.
- if (AnyDescendantWasReparented(child, lca))
+ if (AnyDescendantWasReparented(child, out_lca))
result = true;
}
return result;
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) {
base::hash_map<int32, ClientTreeNode*>::iterator iter =
client_id_map_.find(id);
@@ -276,19 +284,17 @@ ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) {
return NULL;
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
void AXTreeSerializer<AXSourceNode>::SerializeChanges(
- const AXSourceNode* node,
+ AXSourceNode node,
AXTreeUpdate* out_update) {
// If the node isn't in the client tree, we need to serialize starting
// with the LCA.
- const AXSourceNode* lca = LeastCommonAncestor(node);
+ AXSourceNode lca = LeastCommonAncestor(node);
if (client_root_) {
- // If the LCA is anything other than the node itself, tell the
- // client to first delete the subtree rooted at the LCA.
- bool need_delete = (lca != node);
- if (lca) {
+ bool need_delete = false;
+ if (tree_->IsValid(lca)) {
// Check for any reparenting within this subtree - if there is
// any, we need to delete and reserialize the whole subtree
// that contains the old and new parents of the reparented node.
@@ -296,13 +302,11 @@ void AXTreeSerializer<AXSourceNode>::SerializeChanges(
need_delete = true;
}
- if (lca == NULL) {
+ if (!tree_->IsValid(lca)) {
// If there's no LCA, just tell the client to destroy the whole
// tree and then we'll serialize everything from the new root.
out_update->node_id_to_clear = client_root_->id;
- DeleteClientSubtree(client_root_);
- client_id_map_.erase(client_root_->id);
- client_root_ = NULL;
+ Reset();
} else if (need_delete) {
// Otherwise, if we need to reserialize a subtree, first we need
// to delete those nodes in our client tree so that
@@ -313,30 +317,39 @@ void AXTreeSerializer<AXSourceNode>::SerializeChanges(
for (size_t i = 0; i < client_lca->children.size(); ++i) {
client_id_map_.erase(client_lca->children[i]->id);
DeleteClientSubtree(client_lca->children[i]);
+ delete client_lca->children[i];
}
client_lca->children.clear();
}
}
// Serialize from the LCA, or from the root if there isn't one.
- if (!lca)
+ if (!tree_->IsValid(lca))
lca = tree_->GetRoot();
SerializeChangedNodes(lca, out_update);
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(AXSourceNode node) {
+ ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
+ if (client_node)
+ DeleteClientSubtree(client_node);
+}
+
+template<typename AXSourceNode>
void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
ClientTreeNode* client_node) {
for (size_t i = 0; i < client_node->children.size(); ++i) {
client_id_map_.erase(client_node->children[i]->id);
DeleteClientSubtree(client_node->children[i]);
+ delete client_node->children[i];
}
client_node->children.clear();
}
-template<class AXSourceNode>
+template<typename AXSourceNode>
void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
- const AXSourceNode* node,
+ AXSourceNode node,
AXTreeUpdate* out_update) {
// This method has three responsibilities:
// 1. Serialize |node| into an AXNodeData, and append it to
@@ -353,10 +366,7 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
int id = tree_->GetId(node);
ClientTreeNode* client_node = ClientTreeNodeById(id);
if (!client_node) {
- if (client_root_) {
- client_id_map_.erase(client_root_->id);
- DeleteClientSubtree(client_root_);
- }
+ Reset();
client_root_ = new ClientTreeNode();
client_node = client_root_;
client_node->id = id;
@@ -368,9 +378,10 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
// Create a set of the child ids so we can quickly look
// up which children are new and which ones were there before.
base::hash_set<int32> new_child_ids;
- int child_count = tree_->GetChildCount(node);
- for (int i = 0; i < child_count; ++i) {
- AXSourceNode* child = tree_->GetChildAtIndex(node, i);
+ std::vector<AXSourceNode> children;
+ tree_->GetChildren(node, &children);
+ for (size_t i = 0; i < children.size(); ++i) {
+ AXSourceNode& child = children[i];
int new_child_id = tree_->GetId(child);
new_child_ids.insert(new_child_id);
@@ -395,6 +406,7 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
client_id_map_.erase(old_child_id);
DeleteClientSubtree(old_child);
+ delete old_child;
} else {
client_child_id_map[old_child_id] = old_child;
}
@@ -405,17 +417,22 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
out_update->nodes.push_back(AXNodeData());
AXNodeData* serialized_node = &out_update->nodes.back();
tree_->SerializeNode(node, serialized_node);
- if (serialized_node->id == client_root_->id)
+ // TODO(dmazzoni/dtseng): Make the serializer not depend on roles to identify
+ // the root.
+ if (serialized_node->id == client_root_->id &&
+ (serialized_node->role != AX_ROLE_ROOT_WEB_AREA &&
+ serialized_node->role != AX_ROLE_DESKTOP)) {
serialized_node->role = AX_ROLE_ROOT_WEB_AREA;
+ }
serialized_node->child_ids.clear();
// Iterate over the children, make note of the ones that are new
// and need to be serialized, and update the ClientTreeNode
// data structure to reflect the new tree.
- std::vector<AXSourceNode*> children_to_serialize;
- client_node->children.reserve(child_count);
- for (int i = 0; i < child_count; ++i) {
- AXSourceNode* child = tree_->GetChildAtIndex(node, i);
+ std::vector<AXSourceNode> children_to_serialize;
+ client_node->children.reserve(children.size());
+ for (size_t i = 0; i < children.size(); ++i) {
+ AXSourceNode& child = children[i];
int child_id = tree_->GetId(child);
// No need to do anything more with children that aren't new;
diff --git a/chromium/ui/accessibility/ax_tree_serializer_unittest.cc b/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
index 3ec8de71f4f..a0c0fb76b1b 100644
--- a/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_serializer_unittest.cc
@@ -30,9 +30,9 @@ class AXTreeSerializerTest : public testing::Test {
AXTreeUpdate treedata1_;
scoped_ptr<AXSerializableTree> tree0_;
scoped_ptr<AXSerializableTree> tree1_;
- scoped_ptr<AXTreeSource<AXNode> > tree0_source_;
- scoped_ptr<AXTreeSource<AXNode> > tree1_source_;
- scoped_ptr<AXTreeSerializer<AXNode> > serializer_;
+ scoped_ptr<AXTreeSource<const AXNode*> > tree0_source_;
+ scoped_ptr<AXTreeSource<const AXNode*> > tree1_source_;
+ scoped_ptr<AXTreeSerializer<const AXNode*> > serializer_;
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSerializerTest);
@@ -48,7 +48,7 @@ void AXTreeSerializerTest::CreateTreeSerializer() {
// Serialize tree0 so that AXTreeSerializer thinks that its client
// is totally in sync.
tree0_source_.reset(tree0_->CreateTreeSource());
- serializer_.reset(new AXTreeSerializer<AXNode>(tree0_source_.get()));
+ serializer_.reset(new AXTreeSerializer<const AXNode*>(tree0_source_.get()));
AXTreeUpdate unused_update;
serializer_->SerializeChanges(tree0_->GetRoot(), &unused_update);
diff --git a/chromium/ui/accessibility/ax_tree_source.h b/chromium/ui/accessibility/ax_tree_source.h
index 35bdbb711c8..1f13d8f59f5 100644
--- a/chromium/ui/accessibility/ax_tree_source.h
+++ b/chromium/ui/accessibility/ax_tree_source.h
@@ -5,6 +5,8 @@
#ifndef UI_ACCESSIBILITY_AX_TREE_SOURCE_H_
#define UI_ACCESSIBILITY_AX_TREE_SOURCE_H_
+#include <vector>
+
#include "ui/accessibility/ax_node_data.h"
namespace ui {
@@ -17,21 +19,41 @@ namespace ui {
// as an AXNodeData. This is the primary interface to use when
// an accessibility tree will be sent over an IPC before being
// consumed.
-template<class AXNodeSource>
-class AX_EXPORT AXTreeSource {
+template<typename AXNodeSource>
+class AXTreeSource {
public:
virtual ~AXTreeSource() {}
- virtual AXNodeSource* GetRoot() const = 0;
- virtual AXNodeSource* GetFromId(int32 id) const = 0;
- virtual int32 GetId(const AXNodeSource* node) const = 0;
- virtual int GetChildCount(const AXNodeSource* node) const = 0;
- virtual AXNodeSource* GetChildAtIndex(const AXNodeSource* node, int index)
- const = 0;
- virtual AXNodeSource* GetParent(const AXNodeSource* node) const = 0;
+
+ // Get the root of the tree.
+ virtual AXNodeSource GetRoot() const = 0;
+
+ // Get a node by its id. If no node by that id exists in the tree, return a
+ // null node, i.e. one that will return false if you call IsValid on it.
+ virtual AXNodeSource GetFromId(int32 id) const = 0;
+
+ // Return the id of a node. All ids must be positive integers.
+ virtual int32 GetId(AXNodeSource node) const = 0;
+
+ // Append all children of |node| to |out_children|.
+ virtual void GetChildren(AXNodeSource node,
+ std::vector<AXNodeSource>* out_children) const = 0;
+
+ // Get the parent of |node|.
+ virtual AXNodeSource GetParent(AXNodeSource node) const = 0;
+
+ // Returns true if |node| is valid, and false if it's a null pointer or a
+ // node object representing the null pointer.
+ virtual bool IsValid(AXNodeSource node) const = 0;
+
+ // Returns true if two nodes are equal.
+ virtual bool IsEqual(AXNodeSource node1,
+ AXNodeSource node2) const = 0;
+
+ // Return a AXNodeSource representing null.
+ virtual AXNodeSource GetNull() const = 0;
// Serialize one node in the tree.
- virtual void SerializeNode(
- const AXNodeSource* node, AXNodeData* out_data) const = 0;
+ virtual void SerializeNode(AXNodeSource node, AXNodeData* out_data) const = 0;
protected:
AXTreeSource() {}
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 9e21280a066..05369de316b 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -12,10 +12,58 @@
namespace ui {
+namespace {
+
+class FakeAXTreeDelegate : public AXTreeDelegate {
+ public:
+ virtual void OnNodeWillBeDeleted(AXNode* node) OVERRIDE {
+ deleted_ids_.push_back(node->id());
+ }
+
+ virtual void OnNodeCreated(AXNode* node) OVERRIDE {
+ created_ids_.push_back(node->id());
+ }
+
+ virtual void OnNodeChanged(AXNode* node) OVERRIDE {
+ changed_ids_.push_back(node->id());
+ }
+
+ virtual void OnNodeCreationFinished(AXNode* node) OVERRIDE {
+ creation_finished_ids_.push_back(node->id());
+ }
+
+ virtual void OnNodeChangeFinished(AXNode* node) OVERRIDE {
+ change_finished_ids_.push_back(node->id());
+ }
+
+ virtual void OnRootChanged(AXNode* new_root) OVERRIDE {
+ new_root_ids_.push_back(new_root->id());
+ }
+
+ const std::vector<int32>& deleted_ids() { return deleted_ids_; }
+ const std::vector<int32>& created_ids() { return created_ids_; }
+ const std::vector<int32>& creation_finished_ids() {
+ return creation_finished_ids_;
+ }
+ const std::vector<int32>& new_root_ids() { return new_root_ids_; }
+
+ private:
+ std::vector<int32> deleted_ids_;
+ std::vector<int32> created_ids_;
+ std::vector<int32> creation_finished_ids_;
+ std::vector<int32> changed_ids_;
+ std::vector<int32> change_finished_ids_;
+ std::vector<int32> new_root_ids_;
+};
+
+} // namespace
+
TEST(AXTreeTest, SerializeSimpleAXTree) {
AXNodeData root;
root.id = 1;
root.role = AX_ROLE_ROOT_WEB_AREA;
+ root.state = (1 << AX_STATE_FOCUSABLE) | (1 << AX_STATE_FOCUSED);
+ root.location = gfx::Rect(0, 0, 800, 600);
root.child_ids.push_back(2);
root.child_ids.push_back(3);
@@ -23,10 +71,13 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
button.id = 2;
button.role = AX_ROLE_BUTTON;
button.state = 0;
+ button.location = gfx::Rect(20, 20, 200, 30);
AXNodeData checkbox;
checkbox.id = 3;
checkbox.role = AX_ROLE_CHECK_BOX;
+ checkbox.state = 0;
+ checkbox.location = gfx::Rect(20, 50, 200, 30);
AXTreeUpdate initial_state;
initial_state.nodes.push_back(root);
@@ -34,29 +85,73 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
initial_state.nodes.push_back(checkbox);
AXSerializableTree src_tree(initial_state);
- scoped_ptr<AXTreeSource<AXNode> > tree_source(
+ scoped_ptr<AXTreeSource<const AXNode*> > tree_source(
src_tree.CreateTreeSource());
- AXTreeSerializer<AXNode> serializer(tree_source.get());
+ AXTreeSerializer<const AXNode*> serializer(tree_source.get());
AXTreeUpdate update;
serializer.SerializeChanges(src_tree.GetRoot(), &update);
AXTree dst_tree;
ASSERT_TRUE(dst_tree.Unserialize(update));
- AXNode* root_node = dst_tree.GetRoot();
+ const AXNode* root_node = dst_tree.GetRoot();
ASSERT_TRUE(root_node != NULL);
EXPECT_EQ(root.id, root_node->id());
EXPECT_EQ(root.role, root_node->data().role);
ASSERT_EQ(2, root_node->child_count());
- AXNode* button_node = root_node->ChildAtIndex(0);
+ const AXNode* button_node = root_node->ChildAtIndex(0);
EXPECT_EQ(button.id, button_node->id());
EXPECT_EQ(button.role, button_node->data().role);
- AXNode* checkbox_node = root_node->ChildAtIndex(1);
+ const AXNode* checkbox_node = root_node->ChildAtIndex(1);
EXPECT_EQ(checkbox.id, checkbox_node->id());
EXPECT_EQ(checkbox.role, checkbox_node->data().role);
+
+ EXPECT_EQ(
+ "id=1 rootWebArea FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
+ " id=2 button (20, 20)-(200, 30)\n"
+ " id=3 checkBox (20, 50)-(200, 30)\n",
+ dst_tree.ToString());
+}
+
+TEST(AXTreeTest, SerializeAXTreeUpdate) {
+ AXNodeData list;
+ list.id = 3;
+ list.role = AX_ROLE_LIST;
+ list.state = 0;
+ list.child_ids.push_back(4);
+ list.child_ids.push_back(5);
+ list.child_ids.push_back(6);
+
+ AXNodeData list_item_2;
+ list_item_2.id = 5;
+ list_item_2.role = AX_ROLE_LIST_ITEM;
+ list_item_2.state = 0;
+
+ AXNodeData list_item_3;
+ list_item_3.id = 6;
+ list_item_3.role = AX_ROLE_LIST_ITEM;
+ list_item_3.state = 0;
+
+ AXNodeData button;
+ button.id = 7;
+ button.role = AX_ROLE_BUTTON;
+ button.state = 0;
+
+ AXTreeUpdate update;
+ update.nodes.push_back(list);
+ update.nodes.push_back(list_item_2);
+ update.nodes.push_back(list_item_3);
+ update.nodes.push_back(button);
+
+ EXPECT_EQ(
+ "id=3 list (0, 0)-(0, 0) child_ids=4,5,6\n"
+ " id=5 listItem (0, 0)-(0, 0)\n"
+ " id=6 listItem (0, 0)-(0, 0)\n"
+ "id=7 button (0, 0)-(0, 0)\n",
+ update.ToString());
}
TEST(AXTreeTest, DeleteUnknownSubtreeFails) {
@@ -163,4 +258,41 @@ TEST(AXTreeTest, InvalidReparentingFails) {
ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
}
+TEST(AXTreeTest, TreeDelegateIsCalled) {
+ AXTreeUpdate initial_state;
+ initial_state.nodes.resize(1);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
+
+ AXTree tree(initial_state);
+ AXTreeUpdate update;
+ update.node_id_to_clear = 1;
+ update.nodes.resize(2);
+ update.nodes[0].id = 2;
+ update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
+ update.nodes[0].child_ids.push_back(3);
+ update.nodes[1].id = 3;
+
+ FakeAXTreeDelegate fake_delegate;
+ tree.SetDelegate(&fake_delegate);
+
+ EXPECT_TRUE(tree.Unserialize(update));
+
+ ASSERT_EQ(1U, fake_delegate.deleted_ids().size());
+ EXPECT_EQ(1, fake_delegate.deleted_ids()[0]);
+
+ ASSERT_EQ(2U, fake_delegate.created_ids().size());
+ EXPECT_EQ(2, fake_delegate.created_ids()[0]);
+ EXPECT_EQ(3, fake_delegate.created_ids()[1]);
+
+ ASSERT_EQ(2U, fake_delegate.creation_finished_ids().size());
+ EXPECT_EQ(2, fake_delegate.creation_finished_ids()[0]);
+ EXPECT_EQ(3, fake_delegate.creation_finished_ids()[1]);
+
+ ASSERT_EQ(1U, fake_delegate.new_root_ids().size());
+ EXPECT_EQ(2, fake_delegate.new_root_ids()[0]);
+
+ tree.SetDelegate(NULL);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update.cc b/chromium/ui/accessibility/ax_tree_update.cc
index dc785d9e06e..8e9d019349f 100644
--- a/chromium/ui/accessibility/ax_tree_update.cc
+++ b/chromium/ui/accessibility/ax_tree_update.cc
@@ -4,6 +4,9 @@
#include "ui/accessibility/ax_tree_update.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/string_number_conversions.h"
+
namespace ui {
AXTreeUpdate::AXTreeUpdate() : node_id_to_clear(0) {
@@ -12,4 +15,28 @@ AXTreeUpdate::AXTreeUpdate() : node_id_to_clear(0) {
AXTreeUpdate::~AXTreeUpdate() {
}
+std::string AXTreeUpdate::ToString() const {
+ std::string result;
+ if (node_id_to_clear != 0) {
+ result += "AXTreeUpdate: clear node " +
+ base::IntToString(node_id_to_clear) + "\n";
+ }
+
+ // The challenge here is that we want to indent the nodes being updated
+ // so that parent/child relationships are clear, but we don't have access
+ // to the rest of the tree for context, so we have to try to show the
+ // relative indentation of child nodes in this update relative to their
+ // parents.
+ base::hash_map<int32, int> id_to_indentation;
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ int indent = id_to_indentation[nodes[i].id];
+ result += std::string(2 * indent, ' ');
+ result += nodes[i].ToString() + "\n";
+ for (size_t j = 0; j < nodes[i].child_ids.size(); ++j)
+ id_to_indentation[nodes[i].child_ids[j]] = indent + 1;
+ }
+
+ return result;
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree_update.h b/chromium/ui/accessibility/ax_tree_update.h
index 0280efe6449..314a78f823a 100644
--- a/chromium/ui/accessibility/ax_tree_update.h
+++ b/chromium/ui/accessibility/ax_tree_update.h
@@ -50,6 +50,9 @@ struct AX_EXPORT AXTreeUpdate {
// A vector of nodes to update, according to the rules above.
std::vector<AXNodeData> nodes;
+ // Return a multi-line indented string representation, for logging.
+ std::string ToString() const;
+
// TODO(dmazzoni): location changes
};
diff --git a/chromium/ui/accessibility/ax_view_state.cc b/chromium/ui/accessibility/ax_view_state.cc
new file mode 100644
index 00000000000..11044bc16dd
--- /dev/null
+++ b/chromium/ui/accessibility/ax_view_state.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/ax_view_state.h"
+
+namespace ui {
+
+AXViewState::AXViewState()
+ : role(AX_ROLE_CLIENT),
+ selection_start(-1),
+ selection_end(-1),
+ index(-1),
+ count(-1),
+ state_(0) { }
+
+AXViewState::~AXViewState() { }
+
+void AXViewState::AddStateFlag(ui::AXState state_flag) {
+ state_ |= (1 << state_flag);
+}
+
+bool AXViewState::HasStateFlag(ui::AXState state_flag) const {
+ return 0 != (state_ & (1 << state_flag));
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_view_state.h b/chromium/ui/accessibility/ax_view_state.h
new file mode 100644
index 00000000000..2f1aab09333
--- /dev/null
+++ b/chromium/ui/accessibility/ax_view_state.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_VIEW_STATE_H_
+#define UI_ACCESSIBILITY_AX_VIEW_STATE_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// AXViewState
+//
+// A cross-platform struct for storing the core accessibility information
+// that should be provided about any UI view to assistive technology (AT).
+//
+////////////////////////////////////////////////////////////////////////////////
+struct AX_EXPORT AXViewState {
+ public:
+ AXViewState();
+ ~AXViewState();
+
+ // Set or check bits in |state_|.
+ void AddStateFlag(ui::AXState state);
+ bool HasStateFlag(ui::AXState state) const;
+
+ // The view's state, a bitmask containing fields such as checked
+ // (for a checkbox) and protected (for a password text box). This "state"
+ // should not be confused with the class's name.
+ uint32 state() { return state_; }
+
+ // The view's role, like button or list box.
+ AXRole role;
+
+ // The view's name / label.
+ base::string16 name;
+
+ // The view's value, for example the text content.
+ base::string16 value;
+
+ // The name of the default action if the user clicks on this view.
+ base::string16 default_action;
+
+ // The keyboard shortcut to activate this view, if any.
+ base::string16 keyboard_shortcut;
+
+ // The selection start and end. Only applies to views with text content,
+ // such as a text box or combo box; start and end should be -1 otherwise.
+ int selection_start;
+ int selection_end;
+
+ // The selected item's index and the count of the number of items.
+ // Only applies to views with multiple choices like a listbox; both
+ // index and count should be -1 otherwise.
+ int index;
+ int count;
+
+ // An optional callback that can be used by accessibility clients to
+ // set the string value of this view. This only applies to roles where
+ // setting the value makes sense, like a text box. Not often used by
+ // screen readers, but often used by automation software to script
+ // things like logging into portals or filling forms.
+ //
+ // This callback is only valid for the lifetime of the view, and should
+ // be a safe no-op if the view is deleted. Typically, accessible views
+ // should use a WeakPtr when binding the callback.
+ base::Callback<void(const base::string16&)> set_value_callback;
+
+ private:
+ uint32 state_;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_VIEW_STATE_H_
diff --git a/chromium/ui/android/OWNERS b/chromium/ui/android/OWNERS
index 9535813add3..0ba7f742c3e 100644
--- a/chromium/ui/android/OWNERS
+++ b/chromium/ui/android/OWNERS
@@ -1,4 +1,5 @@
bulach@chromium.org
+miguelg@chromium.org
tedchoc@chromium.org
yfriedman@chromium.org
newt@chromium.org
diff --git a/chromium/ui/android/ui_android.gyp b/chromium/ui/android/ui_android.gyp
index b9e3d6990ae..dc9761fcd77 100644
--- a/chromium/ui/android/ui_android.gyp
+++ b/chromium/ui/android/ui_android.gyp
@@ -20,6 +20,18 @@
'includes': [ '../../build/android/java_cpp_template.gypi' ],
},
{
+ 'target_name': 'bitmap_format_java',
+ 'type': 'none',
+ 'sources': [
+ 'java/BitmapFormat.template',
+ ],
+ 'variables': {
+ 'package_name': 'org/chromium/ui/gfx',
+ 'template_deps': ['../gfx/android/bitmap_config_list.h'],
+ },
+ 'includes': [ '../../build/android/java_cpp_template.gypi' ],
+ },
+ {
'target_name': 'ui_java',
'type': 'none',
'variables': {
@@ -27,13 +39,26 @@
'has_java_resources': 1,
'R_package': 'org.chromium.ui',
'R_package_relpath': 'org/chromium/ui',
- 'java_strings_grd': 'android_ui_strings.grd',
},
'dependencies': [
'../../base/base.gyp:base_java',
+ 'bitmap_format_java',
+ 'ui_strings_grd',
'window_open_disposition_java',
],
'includes': [ '../../build/java.gypi' ],
},
+ {
+ 'target_name': 'ui_strings_grd',
+ # The android_webview/Android.mk file depends on this target directly.
+ 'android_unmangled_name': 1,
+ 'type': 'none',
+ 'variables': {
+ 'grd_file': '../../ui/android/java/strings/android_ui_strings.grd',
+ },
+ 'includes': [
+ '../../build/java_strings_grd.gypi',
+ ],
+ },
],
}
diff --git a/chromium/ui/app_list/DEPS b/chromium/ui/app_list/DEPS
deleted file mode 100644
index bd3bf143bdb..00000000000
--- a/chromium/ui/app_list/DEPS
+++ /dev/null
@@ -1,15 +0,0 @@
-include_rules = [
- "+grit/ui_resources.h",
- "+grit/ui_strings.h",
- "+skia",
- "+sync",
- "+third_party/skia",
- # Allow inclusion of third-party code:
- "+third_party/GTM", # Google Toolbox for Mac.
- "+ui/aura",
- "+ui/base",
- "+ui/compositor",
- "+ui/events",
- "+ui/gfx",
- "+ui/views",
-]
diff --git a/chromium/ui/app_list/OWNERS b/chromium/ui/app_list/OWNERS
deleted file mode 100644
index 30a4512f999..00000000000
--- a/chromium/ui/app_list/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-benwells@chromium.org
-koz@chromium.org
-tapted@chromium.org
-xiyuan@chromium.org
diff --git a/chromium/ui/app_list/app_list.gyp b/chromium/ui/app_list/app_list.gyp
index e766c218085..96c0dab90ef 100644
--- a/chromium/ui/app_list/app_list.gyp
+++ b/chromium/ui/app_list/app_list.gyp
@@ -15,11 +15,13 @@
'../../base/base.gyp:base_i18n',
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../../skia/skia.gyp:skia',
- '../base/strings/ui_strings.gyp:ui_strings',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
+ '../events/events.gyp:events_base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../strings/ui_strings.gyp:ui_strings',
],
'defines': [
'APP_LIST_IMPLEMENTATION',
@@ -30,12 +32,12 @@
'app_list_export.h',
'app_list_folder_item.cc',
'app_list_folder_item.h',
+ 'app_list_item.cc',
+ 'app_list_item.h',
+ 'app_list_item_observer.h',
'app_list_item_list.cc',
'app_list_item_list.h',
'app_list_item_list_observer.h',
- 'app_list_item_model.cc',
- 'app_list_item_model.h',
- 'app_list_item_model_observer.h',
'app_list_menu.cc',
'app_list_menu.h',
'app_list_model.cc',
@@ -68,18 +70,16 @@
'cocoa/item_drag_controller.mm',
'cocoa/scroll_view_with_no_scrollbars.h',
'cocoa/scroll_view_with_no_scrollbars.mm',
- 'cocoa/signin_view_controller.h',
- 'cocoa/signin_view_controller.mm',
'pagination_model.cc',
'pagination_model.h',
'pagination_model_observer.h',
'search_box_model.cc',
'search_box_model.h',
'search_box_model_observer.h',
+ 'search_provider.cc',
+ 'search_provider.h',
'search_result.cc',
'search_result.h',
- 'signin_delegate.cc',
- 'signin_delegate.h',
'speech_ui_model.cc',
'speech_ui_model.h',
'speech_ui_model_observer.h',
@@ -102,10 +102,15 @@
'views/apps_grid_view.cc',
'views/apps_grid_view.h',
'views/apps_grid_view_delegate.h',
+ 'views/apps_grid_view_folder_delegate.h',
'views/cached_label.cc',
'views/cached_label.h',
+ 'views/contents_switcher_view.cc',
+ 'views/contents_switcher_view.h',
'views/contents_view.cc',
'views/contents_view.h',
+ 'views/folder_background_view.cc',
+ 'views/folder_background_view.h',
'views/folder_header_view.cc',
'views/folder_header_view.h',
'views/folder_header_view_delegate.h',
@@ -125,24 +130,25 @@
'views/search_result_list_view_delegate.h',
'views/search_result_view.cc',
'views/search_result_view.h',
- 'views/search_result_view_delegate.h',
- 'views/signin_view.cc',
- 'views/signin_view.h',
'views/speech_view.cc',
'views/speech_view.h',
+ 'views/start_page_view.cc',
+ 'views/start_page_view.h',
+ 'views/tile_item_view.cc',
+ 'views/tile_item_view.h',
+ 'views/top_icon_animation_view.cc',
+ 'views/top_icon_animation_view.h',
],
'conditions': [
['use_aura==1', {
'dependencies': [
'../aura/aura.gyp:aura',
+ '../wm/wm.gyp:wm',
],
}],
['toolkit_views==1', {
'dependencies': [
- '../../content/content.gyp:content',
- '../../content/content.gyp:content_browser',
'../events/events.gyp:events',
- '../views/controls/webview/webview.gyp:webview',
'../views/views.gyp:views',
],
}, { # toolkit_views==0
@@ -152,10 +158,7 @@
}],
['OS=="mac"', {
'dependencies': [
- '../ui.gyp:ui_cocoa_third_party_toolkits',
- ],
- 'include_dirs': [
- '../../third_party/GTM',
+ '../../third_party/google_toolbox_for_mac/google_toolbox_for_mac.gyp:google_toolbox_for_mac',
],
'link_settings': {
'libraries': [
@@ -177,6 +180,8 @@
'dependencies': [
'../../base/base.gyp:base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../resources/ui_resources.gyp:ui_resources',
'app_list',
],
'sources': [
@@ -192,14 +197,12 @@
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
- # TODO: Remove this dependency. See comment for views_unittests.
- '../../chrome/chrome_resources.gyp:packed_resources',
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:run_ui_unittests',
+ '../resources/ui_resources.gyp:ui_test_pak',
'app_list',
'app_list_test_support',
],
@@ -212,11 +215,16 @@
'cocoa/apps_grid_controller_unittest.mm',
'cocoa/apps_search_box_controller_unittest.mm',
'cocoa/apps_search_results_controller_unittest.mm',
- 'cocoa/signin_view_controller_unittest.mm',
'cocoa/test/apps_grid_controller_test_helper.h',
'cocoa/test/apps_grid_controller_test_helper.mm',
+ 'test/run_all_unittests.cc',
'views/app_list_main_view_unittest.cc',
+ 'views/app_list_view_unittest.cc',
'views/apps_grid_view_unittest.cc',
+ 'views/folder_header_view_unittest.cc',
+ 'views/search_box_view_unittest.cc',
+ 'views/search_result_list_view_unittest.cc',
+ 'views/speech_view_unittest.cc',
'views/test/apps_grid_view_test_api.cc',
'views/test/apps_grid_view_test_api.h',
],
@@ -225,8 +233,6 @@
'dependencies': [
'../views/views.gyp:views',
'../views/views.gyp:views_test_support',
- '../../content/content.gyp:content',
- '../../content/content.gyp:content_browser',
],
}, { # toolkit_views==0
'sources/': [
@@ -235,7 +241,8 @@
}],
['OS=="mac"', {
'dependencies': [
- '../ui_unittests.gyp:ui_test_support',
+ '../events/events.gyp:events_test_support',
+ '../gfx/gfx.gyp:gfx_test_support',
],
'conditions': [
['component=="static_library"', {
@@ -248,20 +255,14 @@
['exclude', 'cocoa/'],
],
}],
- ['desktop_linux == 1 or chromeos == 1 or OS == "ios"', {
- 'dependencies': [
- '../base/strings/ui_strings.gyp:ui_unittest_strings',
- ],
- }],
# See http://crbug.com/162998#c4 for why this is needed.
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
'../../base/allocator/allocator.gyp:allocator',
# The following two dependencies provide the missing
# symbol HeapProfilerStart in Linux component builds.
# They probably can be removed after http://crbug.com/263316
'../../webkit/child/webkit_child.gyp:webkit_child',
- '../../webkit/glue/webkit_glue.gyp:glue',
],
}],
['OS=="win" and win_use_allocator_shim==1', {
@@ -274,4 +275,46 @@
'msvs_disabled_warnings': [ 4267, ],
},
],
+ 'conditions': [
+ ['toolkit_views==1', {
+ 'targets': [
+ {
+ 'target_name': 'app_list_demo',
+ 'type': 'executable',
+ 'sources': [
+ '../../content/app/startup_helper_win.cc',
+ 'demo/app_list_demo_views.cc',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../content/content.gyp:content',
+ '../../content/content.gyp:content_browser',
+ '../../skia/skia.gyp:skia',
+ '../../url/url.gyp:url_lib',
+ '../base/ui_base.gyp:ui_base',
+ '../events/events.gyp:events',
+ '../resources/ui_resources.gyp:ui_resources',
+ '../resources/ui_resources.gyp:ui_test_pak',
+ '../views/controls/webview/webview.gyp:webview',
+ '../views/views.gyp:views',
+ '../views_content_client/views_content_client.gyp:views_content_client',
+ 'app_list',
+ 'app_list_test_support',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
+ },
+ },
+ 'dependencies': [
+ '../../sandbox/sandbox.gyp:sandbox',
+ ],
+ }],
+ ],
+ },
+ ],
+ }], # toolkit_views==1
+ ],
}
diff --git a/chromium/ui/app_list/app_list_constants.cc b/chromium/ui/app_list/app_list_constants.cc
deleted file mode 100644
index 14f77506060..00000000000
--- a/chromium/ui/app_list/app_list_constants.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_constants.h"
-
-namespace app_list {
-
-const SkColor kContentsBackgroundColor = SkColorSetRGB(0xFB, 0xFB, 0xFB);
-const SkColor kSearchBoxBackground = SK_ColorWHITE;
-const SkColor kTopSeparatorColor = SkColorSetRGB(0xE5, 0xE5, 0xE5);
-
-// 6% black over kContentsBackgroundColor
-const SkColor kHighlightedColor = SkColorSetRGB(0xE6, 0xE6, 0xE6);
-// 10% black over kContentsBackgroundColor
-const SkColor kSelectedColor = SkColorSetRGB(0xF1, 0xF1, 0xF1);
-
-const SkColor kPagerHoverColor = SkColorSetRGB(0xB4, 0xB4, 0xB4);
-const SkColor kPagerNormalColor = SkColorSetRGB(0xE2, 0xE2, 0xE2);
-const SkColor kPagerSelectedColor = SkColorSetRGB(0x46, 0x8F, 0xFC);
-
-const SkColor kResultBorderColor = SkColorSetRGB(0xE5, 0xE5, 0xE5);
-const SkColor kResultDefaultTextColor = SkColorSetRGB(0x33, 0x33, 0x33);
-const SkColor kResultDimmedTextColor = SkColorSetRGB(0x96, 0x96, 0x96);
-const SkColor kResultURLTextColor = SkColorSetRGB(0x00, 0x99, 0x33);
-
-const SkColor kGridTitleColor = SkColorSetRGB(0x5A, 0x5A, 0x5A);
-const SkColor kGridTitleHoverColor = SkColorSetRGB(0x3C, 0x3C, 0x3C);
-
-// Color of the folder ink bubble.
-const SkColor kFolderBubbleColor = SkColorSetRGB(0xD7, 0xD7, 0xD7);
-
-// Duration in milliseconds for page transition.
-const int kPageTransitionDurationInMs = 180;
-
-// Duration in milliseconds for over scroll page transition.
-const int kOverscrollPageTransitionDurationMs = 50;
-
-// Preferred number of columns and rows in apps grid.
-const int kPreferredCols = 4;
-const int kPreferredRows = 4;
-const int kPreferredIconDimension = 48;
-
-// Font style for app item labels.
-const ui::ResourceBundle::FontStyle kItemTextFontStyle =
- ui::ResourceBundle::SmallBoldFont;
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_constants.h b/chromium/ui/app_list/app_list_constants.h
deleted file mode 100644
index f48671fd49a..00000000000
--- a/chromium/ui/app_list/app_list_constants.h
+++ /dev/null
@@ -1,46 +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_APP_LIST_APP_LIST_CONSTANTS_H_
-#define UI_APP_LIST_APP_LIST_CONSTANTS_H_
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace app_list {
-
-APP_LIST_EXPORT extern const SkColor kContentsBackgroundColor;
-APP_LIST_EXPORT extern const SkColor kSearchBoxBackground;
-APP_LIST_EXPORT extern const SkColor kTopSeparatorColor;
-
-APP_LIST_EXPORT extern const SkColor kHighlightedColor;
-APP_LIST_EXPORT extern const SkColor kSelectedColor;
-
-APP_LIST_EXPORT extern const SkColor kPagerHoverColor;
-APP_LIST_EXPORT extern const SkColor kPagerNormalColor;
-APP_LIST_EXPORT extern const SkColor kPagerSelectedColor;
-
-APP_LIST_EXPORT extern const SkColor kResultBorderColor;
-APP_LIST_EXPORT extern const SkColor kResultDefaultTextColor;
-APP_LIST_EXPORT extern const SkColor kResultDimmedTextColor;
-APP_LIST_EXPORT extern const SkColor kResultURLTextColor;
-
-APP_LIST_EXPORT extern const SkColor kGridTitleColor;
-APP_LIST_EXPORT extern const SkColor kGridTitleHoverColor;
-
-APP_LIST_EXPORT extern const SkColor kFolderBubbleColor;
-
-APP_LIST_EXPORT extern const int kPageTransitionDurationInMs;
-APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs;
-
-APP_LIST_EXPORT extern const int kPreferredCols;
-APP_LIST_EXPORT extern const int kPreferredRows;
-APP_LIST_EXPORT extern const int kPreferredIconDimension;
-
-APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle;
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_CONSTANTS_H_
diff --git a/chromium/ui/app_list/app_list_export.h b/chromium/ui/app_list/app_list_export.h
deleted file mode 100644
index cb5ece92c53..00000000000
--- a/chromium/ui/app_list/app_list_export.h
+++ /dev/null
@@ -1,33 +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_APP_LIST_APP_LIST_EXPORT_H_
-#define UI_APP_LIST_APP_LIST_EXPORT_H_
-
-// Defines APP_LIST_EXPORT so that functionality implemented by the app_list
-// module can be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(APP_LIST_IMPLEMENTATION)
-#define APP_LIST_EXPORT __declspec(dllexport)
-#else
-#define APP_LIST_EXPORT __declspec(dllimport)
-#endif // defined(APP_LIST_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(APP_LIST_IMPLEMENTATION)
-#define APP_LIST_EXPORT __attribute__((visibility("default")))
-#else
-#define APP_LIST_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define APP_LIST_EXPORT
-#endif
-
-#endif // UI_APP_LIST_APP_LIST_EXPORT_H_
-
diff --git a/chromium/ui/app_list/app_list_folder_item.cc b/chromium/ui/app_list/app_list_folder_item.cc
deleted file mode 100644
index b256f990076..00000000000
--- a/chromium/ui/app_list/app_list_folder_item.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_folder_item.h"
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item_list.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/canvas_image_source.h"
-#include "ui/gfx/image/image_skia_operations.h"
-
-namespace app_list {
-
-namespace {
-
-const int kIconDimension = 48;
-const size_t kNumTopApps = 4;
-const int kItemIconDimension = 16;
-
-// Generates the folder icon with the top 4 child item icons laid in 2x2 tile.
-class FolderImageSource : public gfx::CanvasImageSource {
- public:
- typedef std::vector<gfx::ImageSkia> Icons;
-
- FolderImageSource(const Icons& icons, const gfx::Size& size)
- : gfx::CanvasImageSource(size, false),
- icons_(icons),
- size_(size) {
- DCHECK(icons.size() <= kNumTopApps);
- }
-
- virtual ~FolderImageSource() {}
-
- private:
- void DrawIcon(gfx::Canvas* canvas,
- const gfx::ImageSkia& icon,
- const gfx::Size icon_size,
- int x, int y) {
- gfx::ImageSkia resized(
- gfx::ImageSkiaOperations::CreateResizedImage(
- icon, skia::ImageOperations::RESIZE_BEST, icon_size));
- canvas->DrawImageInt(resized, 0, 0, resized.width(), resized.height(),
- x, y, resized.width(), resized.height(), true);
- }
-
- // gfx::CanvasImageSource overrides:
- virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
- // Draw folder circle.
- gfx::Point center = gfx::Point(size().width() / 2 , size().height() / 2);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAntiAlias(true);
- paint.setColor(kFolderBubbleColor);
- canvas->DrawCircle(center, size().width() / 2, paint);
-
- if (icons_.size() == 0)
- return;
-
- // Tiled icon coordinates.
- const int delta_to_center = 1;
- const gfx::Size item_icon_size =
- gfx::Size(kItemIconDimension, kItemIconDimension);
- int left_x = center.x() - item_icon_size.width() - delta_to_center;
- int top_y = center.y() - item_icon_size.height() - delta_to_center;
- int right_x = center.x() + delta_to_center;
- int bottom_y = center.y() + delta_to_center;
-
- // top left icon
- size_t i = 0;
- DrawIcon(canvas, icons_[i++], item_icon_size, left_x, top_y);
-
- // top right icon
- if (i < icons_.size())
- DrawIcon(canvas, icons_[i++], item_icon_size, right_x, top_y);
-
- // left bottm icon
- if (i < icons_.size())
- DrawIcon(canvas, icons_[i++], item_icon_size, left_x, bottom_y);
-
- // right bottom icon
- if (i < icons_.size())
- DrawIcon(canvas, icons_[i], item_icon_size, right_x, bottom_y);
- }
-
- Icons icons_;
- gfx::Size size_;
-
- DISALLOW_COPY_AND_ASSIGN(FolderImageSource);
-};
-
-} // namespace
-
-AppListFolderItem::AppListFolderItem(const std::string& id)
- : AppListItemModel(id),
- item_list_(new AppListItemList) {
- item_list_->AddObserver(this);
-}
-
-AppListFolderItem::~AppListFolderItem() {
- for (size_t i = 0; i < top_items_.size(); ++i)
- top_items_[i]->RemoveObserver(this);
- item_list_->RemoveObserver(this);
-}
-
-void AppListFolderItem::UpdateIcon() {
- FolderImageSource::Icons top_icons;
- for (size_t i = 0; i < top_items_.size(); ++i)
- top_icons.push_back(top_items_[i]->icon());
-
- const gfx::Size icon_size = gfx::Size(kIconDimension, kIconDimension);
- gfx::ImageSkia icon = gfx::ImageSkia(
- new FolderImageSource(top_icons, icon_size),
- icon_size);
- SetIcon(icon, false);
-}
-
-void AppListFolderItem::Activate(int event_flags) {
- // Folder handling is implemented by the View, so do nothing.
-}
-
-// static
-const char AppListFolderItem::kAppType[] = "FolderItem";
-
-const char* AppListFolderItem::GetAppType() const {
- return AppListFolderItem::kAppType;
-}
-
-ui::MenuModel* AppListFolderItem::GetContextMenuModel() {
- // TODO(stevenjb/jennyz): Implement.
- return NULL;
-}
-
-void AppListFolderItem::ItemIconChanged() {
- UpdateIcon();
-}
-
-void AppListFolderItem::ItemTitleChanged() {
-}
-
-void AppListFolderItem::ItemHighlightedChanged() {
-}
-
-void AppListFolderItem::ItemIsInstallingChanged() {
-}
-
-void AppListFolderItem::ItemPercentDownloadedChanged() {
-}
-
-void AppListFolderItem::OnListItemAdded(size_t index,
- AppListItemModel* item) {
- if (index <= kNumTopApps)
- UpdateTopItems();
-}
-
-void AppListFolderItem::OnListItemRemoved(size_t index,
- AppListItemModel* item) {
- if (index <= kNumTopApps)
- UpdateTopItems();
-}
-
-void AppListFolderItem::OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) {
- if (from_index <= kNumTopApps || to_index <= kNumTopApps)
- UpdateTopItems();
-}
-
-void AppListFolderItem::UpdateTopItems() {
- for (size_t i = 0; i < top_items_.size(); ++i)
- top_items_[i]->RemoveObserver(this);
- top_items_.clear();
-
- for (size_t i = 0;
- i < kNumTopApps && i < item_list_->item_count(); ++i) {
- AppListItemModel* item = item_list_->item_at(i);
- item->AddObserver(this);
- top_items_.push_back(item);
- }
- UpdateIcon();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_folder_item.h b/chromium/ui/app_list/app_list_folder_item.h
deleted file mode 100644
index 696c9d15d36..00000000000
--- a/chromium/ui/app_list/app_list_folder_item.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_APP_LIST_FOLDER_ITEM_H_
-#define UI_APP_LIST_APP_LIST_FOLDER_ITEM_H_
-
-#include <string>
-#include <vector>
-
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_item_list_observer.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_item_model_observer.h"
-
-namespace app_list {
-
-class AppListItemList;
-
-// AppListFolderItem implements the model/controller for folders.
-class APP_LIST_EXPORT AppListFolderItem : public AppListItemModel,
- public AppListItemListObserver,
- public AppListItemModelObserver {
- public:
- explicit AppListFolderItem(const std::string& id);
- virtual ~AppListFolderItem();
-
- // Updates the folder's icon.
- void UpdateIcon();
-
- AppListItemList* item_list() { return item_list_.get(); }
-
- static const char kAppType[];
-
- private:
- // AppListItemModel
- virtual void Activate(int event_flags) OVERRIDE;
- virtual const char* GetAppType() const OVERRIDE;
- virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
-
- // AppListItemModelObserver
- virtual void ItemIconChanged() OVERRIDE;
- virtual void ItemTitleChanged() OVERRIDE;
- virtual void ItemHighlightedChanged() OVERRIDE;
- virtual void ItemIsInstallingChanged() OVERRIDE;
- virtual void ItemPercentDownloadedChanged() OVERRIDE;
-
- // AppListItemListObserver
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
- virtual void OnListItemRemoved(size_t index,
- AppListItemModel* item) OVERRIDE;;
- virtual void OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) OVERRIDE;
-
- void UpdateTopItems();
-
- scoped_ptr<AppListItemList> item_list_;
- // Top items for generating folder icon.
- std::vector<AppListItemModel*> top_items_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListFolderItem);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_FOLDER_ITEM_H_
diff --git a/chromium/ui/app_list/app_list_item_list.cc b/chromium/ui/app_list/app_list_item_list.cc
deleted file mode 100644
index 5f88b2d2ea8..00000000000
--- a/chromium/ui/app_list/app_list_item_list.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_item_list.h"
-
-#include "ui/app_list/app_list_item_model.h"
-
-namespace app_list {
-
-AppListItemList::AppListItemList() {
-}
-
-AppListItemList::~AppListItemList() {
-}
-
-void AppListItemList::AddObserver(AppListItemListObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-AppListItemModel* AppListItemList::FindItem(const std::string& id) {
- for (size_t i = 0; i < app_list_items_.size(); ++i) {
- AppListItemModel* item = app_list_items_[i];
- if (item->id() == id)
- return item;
- }
- return NULL;
-}
-
-bool AppListItemList::FindItemIndex(const std::string& id, size_t* index) {
- for (size_t i = 0; i < app_list_items_.size(); ++i) {
- AppListItemModel* item = app_list_items_[i];
- if (item->id() == id) {
- *index = i;
- return true;
- }
- }
- return false;
-}
-
-size_t AppListItemList::AddItem(AppListItemModel* item) {
- CHECK(std::find(app_list_items_.begin(), app_list_items_.end(), item)
- == app_list_items_.end());
- EnsureValidItemPosition(item);
- size_t index = GetItemSortOrderIndex(item->position(), item->id());
- app_list_items_.insert(app_list_items_.begin() + index, item);
- FOR_EACH_OBSERVER(AppListItemListObserver,
- observers_,
- OnListItemAdded(index, item));
- return index;
-}
-
-void AppListItemList::InsertItemAt(AppListItemModel* item, size_t index) {
- DCHECK_LE(index, item_count());
- if (item_count() == 0) {
- AddItem(item);
- return;
- }
-
- AppListItemModel* prev =
- index > 0 ? app_list_items_[index - 1] : NULL;
- AppListItemModel* next = index <= app_list_items_.size() - 1 ?
- app_list_items_[index] : NULL;
- CHECK_NE(prev, next);
-
- if (prev && next && prev->position().Equals(next->position()))
- prev = NULL;
-
- if (!prev)
- item->set_position(next->position().CreateBefore());
- else if (!next)
- item->set_position(prev->position().CreateAfter());
- else
- item->set_position(prev->position().CreateBetween(next->position()));
-
- app_list_items_.insert(app_list_items_.begin() + index, item);
-
- FOR_EACH_OBSERVER(AppListItemListObserver,
- observers_,
- OnListItemAdded(index, item));
-}
-
-void AppListItemList::DeleteItem(const std::string& id) {
- scoped_ptr<AppListItemModel> item = RemoveItem(id);
- // |item| will be deleted on destruction.
-}
-
-void AppListItemList::DeleteItemsByType(const char* type) {
- for (int i = static_cast<int>(app_list_items_.size()) - 1;
- i >= 0; --i) {
- AppListItemModel* item = app_list_items_[i];
- if (!type || item->GetAppType() == type)
- DeleteItemAt(i);
- }
-}
-
-scoped_ptr<AppListItemModel> AppListItemList::RemoveItem(
- const std::string& id) {
- size_t index;
- if (FindItemIndex(id, &index))
- return RemoveItemAt(index);
-
- return scoped_ptr<AppListItemModel>();
-}
-
-scoped_ptr<AppListItemModel> AppListItemList::RemoveItemAt(size_t index) {
- DCHECK_LT(index, item_count());
- AppListItemModel* item = app_list_items_[index];
- app_list_items_.weak_erase(app_list_items_.begin() + index);
- FOR_EACH_OBSERVER(AppListItemListObserver,
- observers_,
- OnListItemRemoved(index, item));
- return make_scoped_ptr<AppListItemModel>(item);
-}
-
-void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
- DCHECK_LT(from_index, item_count());
- DCHECK_LT(to_index, item_count());
- if (from_index == to_index)
- return;
-
- AppListItemModel* target_item = app_list_items_[from_index];
- app_list_items_.weak_erase(app_list_items_.begin() + from_index);
- app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
-
- // Update position
- AppListItemModel* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
- AppListItemModel* next = to_index < app_list_items_.size() - 1 ?
- app_list_items_[to_index + 1] : NULL;
- CHECK_NE(prev, next);
-
- // It is possible that items were added with the same ordinal. Rather than
- // resolving a potentially complicated chain of conflicts, just set the
- // ordinal before |next| (which will place it before both items).
- if (prev && next && prev->position().Equals(next->position()))
- prev = NULL;
-
- syncer::StringOrdinal new_position;
- if (!prev)
- new_position = next->position().CreateBefore();
- else if (!next)
- new_position = prev->position().CreateAfter();
- else
- new_position = prev->position().CreateBetween(next->position());
- VLOG(2) << "Move: " << target_item->position().ToDebugString()
- << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
- << " Next: " << (next ? next->position().ToDebugString() : "(none)")
- << " -> " << new_position.ToDebugString();
- target_item->set_position(new_position);
- FOR_EACH_OBSERVER(AppListItemListObserver,
- observers_,
- OnListItemMoved(from_index, to_index, target_item));
-}
-
-void AppListItemList::SetItemPosition(
- AppListItemModel* item,
- const syncer::StringOrdinal& new_position) {
- DCHECK(item);
- size_t from_index;
- if (!FindItemIndex(item->id(), &from_index)) {
- LOG(ERROR) << "SetItemPosition: Not in list: " << item->id().substr(0, 8);
- return;
- }
- DCHECK(app_list_items_[from_index] == item);
- // First check if the order would remain the same, in which case just update
- // the position.
- size_t to_index = GetItemSortOrderIndex(new_position, item->id());
- if (to_index == from_index) {
- VLOG(2) << "SetItemPosition: No change: " << item->id().substr(0, 8);
- item->set_position(new_position);
- return;
- }
- // Remove the item and get the updated to index.
- app_list_items_.weak_erase(app_list_items_.begin() + from_index);
- to_index = GetItemSortOrderIndex(new_position, item->id());
- VLOG(2) << "SetItemPosition: " << item->id().substr(0, 8)
- << " -> " << new_position.ToDebugString()
- << " From: " << from_index << " To: " << to_index;
- item->set_position(new_position);
- app_list_items_.insert(app_list_items_.begin() + to_index, item);
- FOR_EACH_OBSERVER(AppListItemListObserver,
- observers_,
- OnListItemMoved(from_index, to_index, item));
-}
-
-// AppListItemList private
-
-void AppListItemList::DeleteItemAt(size_t index) {
- scoped_ptr<AppListItemModel> item = RemoveItemAt(index);
- // |item| will be deleted on destruction.
-}
-
-void AppListItemList::EnsureValidItemPosition(AppListItemModel* item) {
- syncer::StringOrdinal position = item->position();
- if (position.IsValid())
- return;
- size_t nitems = app_list_items_.size();
- if (nitems == 0) {
- position = syncer::StringOrdinal::CreateInitialOrdinal();
- } else {
- position = app_list_items_[nitems - 1]->position().CreateAfter();
- }
- item->set_position(position);
-}
-
-size_t AppListItemList::GetItemSortOrderIndex(
- const syncer::StringOrdinal& position,
- const std::string& id) {
- DCHECK(position.IsValid());
- for (size_t index = 0; index < app_list_items_.size(); ++index) {
- if (position.LessThan(app_list_items_[index]->position()) ||
- (position.Equals(app_list_items_[index]->position()) &&
- (id < app_list_items_[index]->id()))) {
- return index;
- }
- }
- return app_list_items_.size();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_item_list.h b/chromium/ui/app_list/app_list_item_list.h
deleted file mode 100644
index 9e7407461e1..00000000000
--- a/chromium/ui/app_list/app_list_item_list.h
+++ /dev/null
@@ -1,103 +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_APP_LIST_APP_LIST_ITEM_LIST_H_
-#define UI_APP_LIST_APP_LIST_ITEM_LIST_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/observer_list.h"
-#include "sync/api/string_ordinal.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_item_list_observer.h"
-
-namespace app_list {
-
-class AppListItemModel;
-
-// Class to manage items in the app list. Used both by AppListModel and
-// AppListFolderItem. Manages the position ordinal of items in the list, and
-// notifies observers when items in the list are added / deleted / moved.
-class APP_LIST_EXPORT AppListItemList {
- public:
- AppListItemList();
- virtual ~AppListItemList();
-
- void AddObserver(AppListItemListObserver* observer);
- void RemoveObserver(AppListItemListObserver* observer);
-
- // Finds item matching |id|. NOTE: Requires a linear search.
- AppListItemModel* FindItem(const std::string& id);
-
- // Finds the |index| of the the item matching |id| in |app_list_items_|.
- // Returns true if the matching item is found.
- // Note: Requires a linear search.
- bool FindItemIndex(const std::string& id, size_t* index);
-
- // Adds |item| to the end of |app_list_items_|. Takes ownership of |item|.
- // Triggers observers_.OnListItemAdded(). Returns the index of the added item.
- size_t AddItem(AppListItemModel* item);
-
- // Inserts |item| at the |index| into |app_list_items_|. Takes ownership of
- // |item|. Triggers observers_.OnListItemAdded().
- void InsertItemAt(AppListItemModel* item, size_t index);
-
- // Finds item matching |id| in |app_list_items_| (linear search) and deletes
- // it. Triggers observers_.OnListItemRemoved() after removing the item from
- // the list and before deleting it.
- void DeleteItem(const std::string& id);
-
- // Deletes all items matching |type| which must be a statically defined
- // type descriptor, e.g. AppListFolderItem::kAppType. If |type| is NULL,
- // deletes all items. Triggers observers_.OnListItemRemoved() for each item
- // as for DeleteItem.
- void DeleteItemsByType(const char* type);
-
- // Removes the item with matching |id| in |app_list_items_| without deleting
- // it. Returns a scoped pointer containing the removed item.
- scoped_ptr<AppListItemModel> RemoveItem(const std::string& id);
-
- // Removes the item at |index| from |app_list_items_| without deleting it.
- // Returns a scoped pointer containing the removed item.
- scoped_ptr<AppListItemModel> RemoveItemAt(size_t index);
-
- // Moves item at |from_index| to |to_index|.
- // Triggers observers_.OnListItemMoved().
- void MoveItem(size_t from_index, size_t to_index);
-
- // Sets the position of |item| which is expected to be a member of
- // |app_list_items_| and sorts the list accordingly.
- void SetItemPosition(AppListItemModel* item,
- const syncer::StringOrdinal& new_position);
-
- AppListItemModel* item_at(size_t index) {
- DCHECK_LT(index, app_list_items_.size());
- return app_list_items_[index];
- }
- size_t item_count() const { return app_list_items_.size(); }
-
- private:
- // Deletes item at |index| and signals observers.
- void DeleteItemAt(size_t index);
-
- // If |item|->position() is not a valid ordinal, sets |item|->position()
- // to a valid ordinal after the last item in the list.
- void EnsureValidItemPosition(AppListItemModel* item);
-
- // Returns the index at which to insert an item in |app_list_items_| based on
- // |position| (which must be valid) and |id| (if the positions are equal).
- size_t GetItemSortOrderIndex(const syncer::StringOrdinal& position,
- const std::string& id);
-
- ScopedVector<AppListItemModel> app_list_items_;
- ObserverList<AppListItemListObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListItemList);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_ITEM_LIST_H_
diff --git a/chromium/ui/app_list/app_list_item_list_observer.h b/chromium/ui/app_list/app_list_item_list_observer.h
deleted file mode 100644
index bca7e90d700..00000000000
--- a/chromium/ui/app_list/app_list_item_list_observer.h
+++ /dev/null
@@ -1,34 +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_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
-#define UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
-
-#include "base/basictypes.h"
-
-namespace app_list {
-
-class AppListItemModel;
-
-class APP_LIST_EXPORT AppListItemListObserver {
- public:
- // Triggered after |item| has been added to the list at |index|.
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) {}
-
- // Triggered after an item has been removed from the list at |index|, just
- // before the item is deleted.
- virtual void OnListItemRemoved(size_t index, AppListItemModel* item) {}
-
- // Triggered after |item| has been moved from |from_index| to |to_index|.
- virtual void OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) {}
-
- protected:
- virtual ~AppListItemListObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
diff --git a/chromium/ui/app_list/app_list_item_list_unittest.cc b/chromium/ui/app_list/app_list_item_list_unittest.cc
deleted file mode 100644
index 2dbc6284321..00000000000
--- a/chromium/ui/app_list/app_list_item_list_unittest.cc
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_item_list.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/app_list_item_list_observer.h"
-#include "ui/app_list/app_list_item_model.h"
-
-namespace app_list {
-
-namespace {
-
-class TestObserver : public AppListItemListObserver {
- public:
- TestObserver()
- : items_added_(0),
- items_removed_(0) {
- }
-
- virtual ~TestObserver() {
- }
-
- // AppListItemListObserver overriden:
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
- ++items_added_;
- }
-
- virtual void OnListItemRemoved(size_t index,
- AppListItemModel* item) OVERRIDE {
- ++items_removed_;
- }
-
- size_t items_added() const { return items_added_; }
- size_t items_removed() const { return items_removed_; }
-
- private:
- size_t items_added_;
- size_t items_removed_;
-
- DISALLOW_COPY_AND_ASSIGN(TestObserver);
-};
-
-std::string GetItemName(int id) {
- return base::StringPrintf("Item %d", id);
-}
-
-} // namespace
-
-class AppListItemListTest : public testing::Test {
- public:
- AppListItemListTest() {}
- virtual ~AppListItemListTest() {}
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- item_list_.AddObserver(&observer_);
- }
-
- virtual void TearDown() OVERRIDE {
- item_list_.RemoveObserver(&observer_);
- }
-
- protected:
- AppListItemModel* CreateItem(const std::string& title,
- const std::string& full_name) {
- AppListItemModel* item = new AppListItemModel(title);
- size_t nitems = item_list_.item_count();
- syncer::StringOrdinal position;
- if (nitems == 0)
- position = syncer::StringOrdinal::CreateInitialOrdinal();
- else
- position = item_list_.item_at(nitems - 1)->position().CreateAfter();
- item->set_position(position);
- item->SetTitleAndFullName(title, full_name);
- return item;
- }
-
- AppListItemModel* CreateAndAddItem(const std::string& title,
- const std::string& full_name) {
- AppListItemModel* item = CreateItem(title, full_name);
- item_list_.AddItem(item);
- return item;
- }
-
- bool VerifyItemListOrdinals() {
- bool res = true;
- for (size_t i = 1; i < item_list_.item_count(); ++i) {
- res &= (item_list_.item_at(i - 1)->position().LessThan(
- item_list_.item_at(i)->position()));
- }
- if (!res)
- PrintItems();
- return res;
- }
-
- bool VerifyItemOrder4(size_t a, size_t b, size_t c, size_t d) {
- if ((GetItemName(a) == item_list_.item_at(0)->id()) &&
- (GetItemName(b) == item_list_.item_at(1)->id()) &&
- (GetItemName(c) == item_list_.item_at(2)->id()) &&
- (GetItemName(d) == item_list_.item_at(3)->id()))
- return true;
- PrintItems();
- return false;
- }
-
- void PrintItems() {
- VLOG(1) << "ITEMS:";
- for (size_t i = 0; i < item_list_.item_count(); ++i)
- VLOG(1) << " " << item_list_.item_at(i)->ToDebugString();
- }
-
- AppListItemList item_list_;
- TestObserver observer_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppListItemListTest);
-};
-
-TEST_F(AppListItemListTest, FindItemIndex) {
- AppListItemModel* item_0 = CreateAndAddItem(GetItemName(0), GetItemName(0));
- AppListItemModel* item_1 = CreateAndAddItem(GetItemName(1), GetItemName(1));
- AppListItemModel* item_2 = CreateAndAddItem(GetItemName(2), GetItemName(2));
- EXPECT_EQ(observer_.items_added(), 3u);
- EXPECT_EQ(item_list_.item_count(), 3u);
- EXPECT_EQ(item_0, item_list_.item_at(0));
- EXPECT_EQ(item_1, item_list_.item_at(1));
- EXPECT_EQ(item_2, item_list_.item_at(2));
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- size_t index;
- EXPECT_TRUE(item_list_.FindItemIndex(item_0->id(), &index));
- EXPECT_EQ(index, 0u);
- EXPECT_TRUE(item_list_.FindItemIndex(item_1->id(), &index));
- EXPECT_EQ(index, 1u);
- EXPECT_TRUE(item_list_.FindItemIndex(item_2->id(), &index));
- EXPECT_EQ(index, 2u);
-
- scoped_ptr<AppListItemModel> item_3(
- CreateItem(GetItemName(3), GetItemName(3)));
- EXPECT_FALSE(item_list_.FindItemIndex(item_3->id(), &index));
-}
-
-TEST_F(AppListItemListTest, RemoveItemAt) {
- AppListItemModel* item_0 = CreateAndAddItem(GetItemName(0), GetItemName(0));
- AppListItemModel* item_1 = CreateAndAddItem(GetItemName(1), GetItemName(1));
- AppListItemModel* item_2 = CreateAndAddItem(GetItemName(2), GetItemName(2));
- EXPECT_EQ(item_list_.item_count(), 3u);
- EXPECT_EQ(observer_.items_added(), 3u);
- size_t index;
- EXPECT_TRUE(item_list_.FindItemIndex(item_1->id(), &index));
- EXPECT_EQ(index, 1u);
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- scoped_ptr<AppListItemModel> item_removed = item_list_.RemoveItemAt(1);
- EXPECT_EQ(item_removed, item_1);
- EXPECT_FALSE(item_list_.FindItem(item_1->id()));
- EXPECT_EQ(item_list_.item_count(), 2u);
- EXPECT_EQ(observer_.items_removed(), 1u);
- EXPECT_EQ(item_list_.item_at(0), item_0);
- EXPECT_EQ(item_list_.item_at(1), item_2);
- EXPECT_TRUE(VerifyItemListOrdinals());
-}
-
-TEST_F(AppListItemListTest, RemoveItem) {
- AppListItemModel* item_0 = CreateAndAddItem(GetItemName(0), GetItemName(0));
- AppListItemModel* item_1 = CreateAndAddItem(GetItemName(1), GetItemName(1));
- AppListItemModel* item_2 = CreateAndAddItem(GetItemName(2), GetItemName(2));
- EXPECT_EQ(item_list_.item_count(), 3u);
- EXPECT_EQ(observer_.items_added(), 3u);
- EXPECT_EQ(item_0, item_list_.item_at(0));
- EXPECT_EQ(item_1, item_list_.item_at(1));
- EXPECT_EQ(item_2, item_list_.item_at(2));
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- size_t index;
- EXPECT_TRUE(item_list_.FindItemIndex(item_1->id(), &index));
- EXPECT_EQ(index, 1u);
-
- scoped_ptr<AppListItemModel> item_removed =
- item_list_.RemoveItem(item_1->id());
- EXPECT_EQ(item_removed, item_1);
- EXPECT_FALSE(item_list_.FindItem(item_1->id()));
- EXPECT_EQ(item_list_.item_count(), 2u);
- EXPECT_EQ(observer_.items_removed(), 1u);
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- scoped_ptr<AppListItemModel> not_found_item = item_list_.RemoveItem("Bogus");
- EXPECT_FALSE(not_found_item.get());
-}
-
-TEST_F(AppListItemListTest, InsertItemAt) {
- AppListItemModel* item_0 = CreateAndAddItem(GetItemName(0), GetItemName(0));
- AppListItemModel* item_1 = CreateAndAddItem(GetItemName(1), GetItemName(1));
- EXPECT_EQ(item_list_.item_count(), 2u);
- EXPECT_EQ(observer_.items_added(), 2u);
- EXPECT_EQ(item_list_.item_at(0), item_0);
- EXPECT_EQ(item_list_.item_at(1), item_1);
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- // Insert an item at the beginning of the item_list_.
- AppListItemModel* item_2 = CreateItem(GetItemName(2), GetItemName(2));
- item_list_.InsertItemAt(item_2, 0);
- EXPECT_EQ(item_list_.item_count(), 3u);
- EXPECT_EQ(observer_.items_added(), 3u);
- EXPECT_EQ(item_list_.item_at(0), item_2);
- EXPECT_EQ(item_list_.item_at(1), item_0);
- EXPECT_EQ(item_list_.item_at(2), item_1);
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- // Insert an item at the end of the item_list_.
- AppListItemModel* item_3 = CreateItem(GetItemName(3), GetItemName(3));
- item_list_.InsertItemAt(item_3, item_list_.item_count());
- EXPECT_EQ(item_list_.item_count(), 4u);
- EXPECT_EQ(observer_.items_added(), 4u);
- EXPECT_EQ(item_list_.item_at(0), item_2);
- EXPECT_EQ(item_list_.item_at(1), item_0);
- EXPECT_EQ(item_list_.item_at(2), item_1);
- EXPECT_EQ(item_list_.item_at(3), item_3);
- EXPECT_TRUE(VerifyItemListOrdinals());
-
- // Insert an item at the 2nd item of the item_list_.
- AppListItemModel* item_4 = CreateItem(GetItemName(4), GetItemName(4));
- item_list_.InsertItemAt(item_4, 1);
- EXPECT_EQ(item_list_.item_count(), 5u);
- EXPECT_EQ(observer_.items_added(), 5u);
- EXPECT_EQ(item_list_.item_at(0), item_2);
- EXPECT_EQ(item_list_.item_at(1), item_4);
- EXPECT_EQ(item_list_.item_at(2), item_0);
- EXPECT_EQ(item_list_.item_at(3), item_1);
- EXPECT_EQ(item_list_.item_at(4), item_3);
- EXPECT_TRUE(VerifyItemListOrdinals());
-}
-
-TEST_F(AppListItemListTest, InsertItemAtEmptyList) {
- AppListItemModel* item_0 = CreateItem(GetItemName(0), GetItemName(0));
- EXPECT_EQ(item_list_.item_count(), 0u);
- item_list_.InsertItemAt(item_0, 0);
- EXPECT_EQ(item_list_.item_count(), 1u);
- EXPECT_EQ(observer_.items_added(), 1u);
- EXPECT_EQ(item_list_.item_at(0), item_0);
- EXPECT_TRUE(VerifyItemListOrdinals());
-}
-
-TEST_F(AppListItemListTest, MoveItem) {
- CreateAndAddItem(GetItemName(0), GetItemName(0));
- CreateAndAddItem(GetItemName(1), GetItemName(1));
- CreateAndAddItem(GetItemName(2), GetItemName(2));
- CreateAndAddItem(GetItemName(3), GetItemName(3));
- EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
-
- item_list_.MoveItem(0, 1);
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
-
- item_list_.MoveItem(1, 2);
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
-
- item_list_.MoveItem(2, 3);
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 2, 3, 0));
-
- item_list_.MoveItem(3, 0);
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
-
- item_list_.MoveItem(0, 3);
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 2, 3, 0));
-}
-
-TEST_F(AppListItemListTest, SetItemPosition) {
- CreateAndAddItem(GetItemName(0), GetItemName(0));
- CreateAndAddItem(GetItemName(1), GetItemName(1));
- CreateAndAddItem(GetItemName(2), GetItemName(2));
- CreateAndAddItem(GetItemName(3), GetItemName(3));
- EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
-
- // No change to position.
- item_list_.SetItemPosition(item_list_.item_at(0),
- item_list_.item_at(0)->position());
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
- // No order change.
- item_list_.SetItemPosition(item_list_.item_at(0),
- item_list_.item_at(0)->position().CreateBetween(
- item_list_.item_at(1)->position()));
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
- // 0 -> 1
- item_list_.SetItemPosition(item_list_.item_at(0),
- item_list_.item_at(1)->position().CreateBetween(
- item_list_.item_at(2)->position()));
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
- // 1 -> 2
- item_list_.SetItemPosition(item_list_.item_at(1),
- item_list_.item_at(2)->position().CreateBetween(
- item_list_.item_at(3)->position()));
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
- // 0 -> last
- item_list_.SetItemPosition(item_list_.item_at(0),
- item_list_.item_at(3)->position().CreateAfter());
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
- // last -> last
- item_list_.SetItemPosition(item_list_.item_at(3),
- item_list_.item_at(3)->position().CreateAfter());
- EXPECT_TRUE(VerifyItemListOrdinals());
- EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_item_model.cc b/chromium/ui/app_list/app_list_item_model.cc
deleted file mode 100644
index 8a71a0ca948..00000000000
--- a/chromium/ui/app_list/app_list_item_model.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_item_model.h"
-
-#include "base/logging.h"
-#include "ui/app_list/app_list_item_model_observer.h"
-
-namespace app_list {
-
-AppListItemModel::AppListItemModel(const std::string& id)
- : id_(id),
- highlighted_(false),
- is_installing_(false),
- percent_downloaded_(-1) {
-}
-
-AppListItemModel::~AppListItemModel() {
-}
-
-void AppListItemModel::SetIcon(const gfx::ImageSkia& icon, bool has_shadow) {
- icon_ = icon;
- has_shadow_ = has_shadow;
- FOR_EACH_OBSERVER(AppListItemModelObserver, observers_, ItemIconChanged());
-}
-
-void AppListItemModel::SetTitleAndFullName(const std::string& title,
- const std::string& full_name) {
- if (title_ == title && full_name_ == full_name)
- return;
-
- title_ = title;
- full_name_ = full_name;
- FOR_EACH_OBSERVER(AppListItemModelObserver, observers_, ItemTitleChanged());
-}
-
-void AppListItemModel::SetHighlighted(bool highlighted) {
- if (highlighted_ == highlighted)
- return;
-
- highlighted_ = highlighted;
- FOR_EACH_OBSERVER(AppListItemModelObserver,
- observers_,
- ItemHighlightedChanged());
-}
-
-void AppListItemModel::SetIsInstalling(bool is_installing) {
- if (is_installing_ == is_installing)
- return;
-
- is_installing_ = is_installing;
- FOR_EACH_OBSERVER(AppListItemModelObserver,
- observers_,
- ItemIsInstallingChanged());
-}
-
-void AppListItemModel::SetPercentDownloaded(int percent_downloaded) {
- if (percent_downloaded_ == percent_downloaded)
- return;
-
- percent_downloaded_ = percent_downloaded;
- FOR_EACH_OBSERVER(AppListItemModelObserver,
- observers_,
- ItemPercentDownloadedChanged());
-}
-
-void AppListItemModel::AddObserver(AppListItemModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void AppListItemModel::RemoveObserver(AppListItemModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void AppListItemModel::Activate(int event_flags) {
-}
-
-const char* AppListItemModel::GetAppType() const {
- static const char* app_type = "";
- return app_type;
-}
-
-ui::MenuModel* AppListItemModel::GetContextMenuModel() {
- return NULL;
-}
-
-bool AppListItemModel::CompareForTest(const AppListItemModel* other) const {
- return id_ == other->id_ &&
- title_ == other->title_ &&
- position_.Equals(other->position_);
-}
-
-std::string AppListItemModel::ToDebugString() const {
- return id_.substr(0, 8) + " '" + title_ + "'"
- + " [" + position_.ToDebugString() + "]";
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_item_model.h b/chromium/ui/app_list/app_list_item_model.h
deleted file mode 100644
index 1ffc6c02867..00000000000
--- a/chromium/ui/app_list/app_list_item_model.h
+++ /dev/null
@@ -1,102 +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_APP_LIST_APP_LIST_ITEM_MODEL_H_
-#define UI_APP_LIST_APP_LIST_ITEM_MODEL_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "sync/api/string_ordinal.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/gfx/image/image_skia.h"
-
-namespace ui {
-class MenuModel;
-}
-
-namespace app_list {
-
-class AppListItemList;
-class AppListItemListTest;
-class AppListItemModelObserver;
-
-// AppListItemModel provides icon and title to be shown in a AppListItemView
-// and action to be executed when the AppListItemView is activated.
-class APP_LIST_EXPORT AppListItemModel {
- public:
- explicit AppListItemModel(const std::string& id);
- virtual ~AppListItemModel();
-
- void SetIcon(const gfx::ImageSkia& icon, bool has_shadow);
- const gfx::ImageSkia& icon() const { return icon_; }
- bool has_shadow() const { return has_shadow_; }
-
- void SetTitleAndFullName(const std::string& title,
- const std::string& full_name);
- const std::string& title() const { return title_; }
- const std::string& full_name() const { return full_name_; }
-
- void SetHighlighted(bool highlighted);
- bool highlighted() const { return highlighted_; }
-
- void SetIsInstalling(bool is_installing);
- bool is_installing() const { return is_installing_; }
-
- void SetPercentDownloaded(int percent_downloaded);
- int percent_downloaded() const { return percent_downloaded_; }
-
- const std::string& id() const { return id_; }
- const syncer::StringOrdinal& position() const { return position_; }
-
- void AddObserver(AppListItemModelObserver* observer);
- void RemoveObserver(AppListItemModelObserver* observer);
-
- // Activates (opens) the item. Does nothing by default.
- virtual void Activate(int event_flags);
-
- // Returns a static const char* identifier for the subclass (defaults to "").
- // Pointers can be compared for quick type checking.
- virtual const char* GetAppType() const;
-
- // Returns the context menu model for this item, or NULL if there is currently
- // no menu for the item (e.g. during install).
- // Note the returned menu model is owned by this item.
- virtual ui::MenuModel* GetContextMenuModel();
-
- // Utility functions for sync integration tests.
- virtual bool CompareForTest(const AppListItemModel* other) const;
- virtual std::string ToDebugString() const;
-
- protected:
- friend class AppListItemList;
- friend class AppListItemListTest;
-
- void set_position(const syncer::StringOrdinal& new_position) {
- DCHECK(new_position.IsValid());
- position_ = new_position;
- }
-
- private:
- friend class AppListModelTest;
-
- const std::string id_;
- syncer::StringOrdinal position_;
- gfx::ImageSkia icon_;
- bool has_shadow_;
- std::string title_;
- std::string full_name_;
- bool highlighted_;
- bool is_installing_;
- int percent_downloaded_;
-
- ObserverList<AppListItemModelObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListItemModel);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_ITEM_MODEL_H_
diff --git a/chromium/ui/app_list/app_list_item_model_observer.h b/chromium/ui/app_list/app_list_item_model_observer.h
deleted file mode 100644
index 80abb3989b5..00000000000
--- a/chromium/ui/app_list/app_list_item_model_observer.h
+++ /dev/null
@@ -1,35 +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_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
-#define UI_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT AppListItemModelObserver {
- public:
- // Invoked after item's icon is changed.
- virtual void ItemIconChanged() = 0;
-
- // Invoked after item's title is changed.
- virtual void ItemTitleChanged() = 0;
-
- // Invoked after item's highlighted state is changed.
- virtual void ItemHighlightedChanged() = 0;
-
- // Invoked after item begins or finishes installing.
- virtual void ItemIsInstallingChanged() = 0;
-
- // Invoked after item's download percentage changes.
- virtual void ItemPercentDownloadedChanged() = 0;
-
- protected:
- virtual ~AppListItemModelObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/app_list_menu.cc b/chromium/ui/app_list/app_list_menu.cc
deleted file mode 100644
index 8c0727c2c8f..00000000000
--- a/chromium/ui/app_list/app_list_menu.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_menu.h"
-
-#include "grit/ui_resources.h"
-#include "grit/ui_strings.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/models/menu_separator_types.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace app_list {
-
-AppListMenu::AppListMenu(AppListViewDelegate* delegate)
- : menu_model_(this),
- delegate_(delegate),
- users_(delegate->GetUsers()) {
- InitMenu();
-}
-
-AppListMenu::~AppListMenu() {}
-
-void AppListMenu::InitMenu() {
- // User selector menu section. We don't show the user selector if there is
- // only 1 user.
- if (users_.size() > 1) {
- for (size_t i = 0; i < users_.size(); ++i) {
-#if defined(OS_MACOSX)
- menu_model_.AddRadioItem(SELECT_PROFILE + i,
- users_[i].email.empty() ? users_[i].name
- : users_[i].email,
- 0 /* group_id */);
-#elif defined(OS_WIN)
- menu_model_.AddItem(SELECT_PROFILE + i, users_[i].name);
- int menu_index = menu_model_.GetIndexOfCommandId(SELECT_PROFILE + i);
- menu_model_.SetSublabel(menu_index, users_[i].email);
- // Use custom check mark.
- if (users_[i].active) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- menu_model_.SetIcon(menu_index, gfx::Image(*rb.GetImageSkiaNamed(
- IDR_APP_LIST_USER_INDICATOR)));
- }
-#endif
- }
- menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
- }
-
- menu_model_.AddItem(SHOW_SETTINGS, l10n_util::GetStringUTF16(
- IDS_APP_LIST_OPEN_SETTINGS));
-
- menu_model_.AddItem(SHOW_HELP, l10n_util::GetStringUTF16(
- IDS_APP_LIST_HELP));
-
- menu_model_.AddItem(SHOW_FEEDBACK, l10n_util::GetStringUTF16(
- IDS_APP_LIST_OPEN_FEEDBACK));
-}
-
-bool AppListMenu::IsCommandIdChecked(int command_id) const {
-#if defined(OS_MACOSX)
- DCHECK_LT(static_cast<unsigned>(command_id) - SELECT_PROFILE, users_.size());
- return users_[command_id - SELECT_PROFILE].active;
-#else
- return false;
-#endif
-}
-
-bool AppListMenu::IsCommandIdEnabled(int command_id) const {
- return true;
-}
-
-bool AppListMenu::GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) {
- return false;
-}
-
-void AppListMenu::ExecuteCommand(int command_id, int event_flags) {
- if (command_id >= SELECT_PROFILE) {
- delegate_->ShowForProfileByPath(
- users_[command_id - SELECT_PROFILE].profile_path);
- return;
- }
- switch (command_id) {
- case SHOW_SETTINGS:
- delegate_->OpenSettings();
- break;
- case SHOW_HELP:
- delegate_->OpenHelp();
- break;
- case SHOW_FEEDBACK:
- delegate_->OpenFeedback();
- break;
- default:
- NOTREACHED();
- }
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_menu.h b/chromium/ui/app_list/app_list_menu.h
deleted file mode 100644
index 6520e1d5904..00000000000
--- a/chromium/ui/app_list/app_list_menu.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_APP_LIST_MENU_H_
-#define UI_APP_LIST_APP_LIST_MENU_H_
-
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/base/models/simple_menu_model.h"
-
-namespace app_list {
-
-// Menu for the app list. This is shown in the top right hand corner of the
-// app list.
-// TODO(benwells): We should consider moving this into Chrome.
-class AppListMenu : public ui::SimpleMenuModel::Delegate {
- public:
- enum AppListMenuCommands {
- SHOW_SETTINGS,
- SHOW_HELP,
- SHOW_FEEDBACK,
- // |SELECT_PROFILE| must remain the last enum because values greater than
- // |SELECT_PROFILE| are used to indicate a profile index.
- SELECT_PROFILE,
- };
-
- explicit AppListMenu(AppListViewDelegate* delegate);
- virtual ~AppListMenu();
-
- ui::SimpleMenuModel* menu_model() { return &menu_model_; }
-
- private:
- void InitMenu();
-
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- ui::SimpleMenuModel menu_model_;
- AppListViewDelegate* delegate_;
- AppListViewDelegate::Users users_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListMenu);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_MENU_H_
diff --git a/chromium/ui/app_list/app_list_model.cc b/chromium/ui/app_list/app_list_model.cc
deleted file mode 100644
index b37ec610e45..00000000000
--- a/chromium/ui/app_list/app_list_model.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_model.h"
-
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/search_result.h"
-
-namespace app_list {
-
-AppListModel::AppListModel()
- : item_list_(new AppListItemList),
- search_box_(new SearchBoxModel),
- results_(new SearchResults),
- status_(STATUS_NORMAL) {
-}
-
-AppListModel::~AppListModel() {
-}
-
-void AppListModel::AddObserver(AppListModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void AppListModel::RemoveObserver(AppListModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void AppListModel::SetStatus(Status status) {
- if (status_ == status)
- return;
-
- status_ = status;
- FOR_EACH_OBSERVER(AppListModelObserver,
- observers_,
- OnAppListModelStatusChanged());
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_model.h b/chromium/ui/app_list/app_list_model.h
deleted file mode 100644
index a0d2a39ec62..00000000000
--- a/chromium/ui/app_list/app_list_model.h
+++ /dev/null
@@ -1,62 +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_APP_LIST_APP_LIST_MODEL_H_
-#define UI_APP_LIST_APP_LIST_MODEL_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_item_list.h"
-#include "ui/base/models/list_model.h"
-
-namespace app_list {
-
-class AppListItemList;
-class AppListItemModel;
-class AppListModelObserver;
-class SearchBoxModel;
-class SearchResult;
-
-// Master model of app list that consists of three sub models: AppListItemList,
-// SearchBoxModel and SearchResults. The AppListItemList sub model owns a list
-// of AppListItemModel and is displayed in the grid view. SearchBoxModel is
-// the model for SearchBoxView. SearchResults owns a list of SearchResult.
-class APP_LIST_EXPORT AppListModel {
- public:
- enum Status {
- STATUS_NORMAL,
- STATUS_SYNCING, // Syncing apps or installing synced apps.
- };
-
- typedef ui::ListModel<SearchResult> SearchResults;
-
- AppListModel();
- ~AppListModel();
-
- void AddObserver(AppListModelObserver* observer);
- void RemoveObserver(AppListModelObserver* observer);
-
- void SetStatus(Status status);
-
- AppListItemList* item_list() { return item_list_.get(); }
- SearchBoxModel* search_box() { return search_box_.get(); }
- SearchResults* results() { return results_.get(); }
- Status status() const { return status_; }
-
- private:
- scoped_ptr<AppListItemList> item_list_;
- scoped_ptr<SearchBoxModel> search_box_;
- scoped_ptr<SearchResults> results_;
-
- Status status_;
- ObserverList<AppListModelObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListModel);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_MODEL_H_
diff --git a/chromium/ui/app_list/app_list_model_observer.h b/chromium/ui/app_list/app_list_model_observer.h
deleted file mode 100644
index 8810c821c56..00000000000
--- a/chromium/ui/app_list/app_list_model_observer.h
+++ /dev/null
@@ -1,23 +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_APP_LIST_APP_LIST_MODEL_OBSERVER_H_
-#define UI_APP_LIST_APP_LIST_MODEL_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT AppListModelObserver {
- public:
- // Invoked when AppListModel's status has changed.
- virtual void OnAppListModelStatusChanged() {}
-
- protected:
- virtual ~AppListModelObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/app_list_model_unittest.cc b/chromium/ui/app_list/app_list_model_unittest.cc
deleted file mode 100644
index 9ddbecf764b..00000000000
--- a/chromium/ui/app_list/app_list_model_unittest.cc
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_model.h"
-
-#include <map>
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/base/models/list_model_observer.h"
-
-namespace app_list {
-
-namespace {
-
-class TestObserver : public AppListModelObserver,
- public AppListItemListObserver {
- public:
- TestObserver()
- : status_changed_count_(0),
- items_added_(0),
- items_removed_(0),
- items_moved_(0) {
- }
- virtual ~TestObserver() {
- }
-
- // AppListModelObserver
- virtual void OnAppListModelStatusChanged() OVERRIDE {
- ++status_changed_count_;
- }
-
- // AppListItemListObserver
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
- items_added_++;
- }
-
- virtual void OnListItemRemoved(size_t index,
- AppListItemModel* item) OVERRIDE {
- items_removed_++;
- }
-
- virtual void OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) OVERRIDE {
- items_moved_++;
- }
-
- int status_changed_count() const { return status_changed_count_; }
- int signin_changed_count() const { return signin_changed_count_; }
- size_t items_added() { return items_added_; }
- size_t items_removed() { return items_removed_; }
- size_t items_moved() { return items_moved_; }
-
- void ResetCounts() {
- status_changed_count_ = 0;
- signin_changed_count_ = 0;
- items_added_ = 0;
- items_removed_ = 0;
- items_moved_ = 0;
- }
-
- private:
- int status_changed_count_;
- int signin_changed_count_;
- size_t items_added_;
- size_t items_removed_;
- size_t items_moved_;
-
- DISALLOW_COPY_AND_ASSIGN(TestObserver);
-};
-
-} // namespace
-
-class AppListModelTest : public testing::Test {
- public:
- AppListModelTest() {}
- virtual ~AppListModelTest() {}
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- model_.AddObserver(&observer_);
- model_.item_list()->AddObserver(&observer_);
- }
- virtual void TearDown() OVERRIDE {
- model_.RemoveObserver(&observer_);
- model_.item_list()->RemoveObserver(&observer_);
- }
-
- protected:
- bool ItemObservedByFolder(AppListFolderItem* folder,
- AppListItemModel* item) {
- return item->observers_.HasObserver(folder);
- }
-
- test::AppListTestModel model_;
- TestObserver observer_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppListModelTest);
-};
-
-TEST_F(AppListModelTest, SetStatus) {
- EXPECT_EQ(AppListModel::STATUS_NORMAL, model_.status());
- model_.SetStatus(AppListModel::STATUS_SYNCING);
- EXPECT_EQ(1, observer_.status_changed_count());
- EXPECT_EQ(AppListModel::STATUS_SYNCING, model_.status());
- model_.SetStatus(AppListModel::STATUS_NORMAL);
- EXPECT_EQ(2, observer_.status_changed_count());
- // Set the same status, no change is expected.
- model_.SetStatus(AppListModel::STATUS_NORMAL);
- EXPECT_EQ(2, observer_.status_changed_count());
-}
-
-TEST_F(AppListModelTest, AppsObserver) {
- const size_t num_apps = 2;
- model_.PopulateApps(num_apps);
- EXPECT_EQ(num_apps, observer_.items_added());
-}
-
-TEST_F(AppListModelTest, ModelGetItem) {
- const size_t num_apps = 2;
- model_.PopulateApps(num_apps);
- AppListItemModel* item0 = model_.item_list()->item_at(0);
- ASSERT_TRUE(item0);
- EXPECT_EQ(model_.GetItemName(0), item0->id());
- AppListItemModel* item1 = model_.item_list()->item_at(1);
- ASSERT_TRUE(item1);
- EXPECT_EQ(model_.GetItemName(1), item1->id());
-}
-
-TEST_F(AppListModelTest, ModelFindItem) {
- const size_t num_apps = 2;
- model_.PopulateApps(num_apps);
- std::string item_name0 = model_.GetItemName(0);
- AppListItemModel* item0 = model_.item_list()->FindItem(item_name0);
- ASSERT_TRUE(item0);
- EXPECT_EQ(item_name0, item0->id());
- std::string item_name1 = model_.GetItemName(1);
- AppListItemModel* item1 = model_.item_list()->FindItem(item_name1);
- ASSERT_TRUE(item1);
- EXPECT_EQ(item_name1, item1->id());
-}
-
-TEST_F(AppListModelTest, ModelAddItem) {
- const size_t num_apps = 2;
- model_.PopulateApps(num_apps);
- // Adding another item will add it to the end.
- model_.CreateAndAddItem("Added Item 1");
- ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
- EXPECT_EQ("Added Item 1", model_.item_list()->item_at(num_apps)->id());
- // Add an item between items 0 and 1.
- AppListItemModel* item0 = model_.item_list()->item_at(0);
- ASSERT_TRUE(item0);
- AppListItemModel* item1 = model_.item_list()->item_at(1);
- ASSERT_TRUE(item1);
- AppListItemModel* item2 = model_.CreateItem("Added Item 2", "Added Item 2");
- model_.item_list()->AddItem(item2);
- model_.item_list()->SetItemPosition(
- item2, item0->position().CreateBetween(item1->position()));
- EXPECT_EQ(num_apps + 2, model_.item_list()->item_count());
- EXPECT_EQ("Added Item 2", model_.item_list()->item_at(1)->id());
-}
-
-TEST_F(AppListModelTest, ModelMoveItem) {
- const size_t num_apps = 3;
- model_.PopulateApps(num_apps);
- // Adding another item will add it to the end.
- model_.CreateAndAddItem("Inserted Item");
- ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
- // Move it to the position 1.
- model_.item_list()->MoveItem(num_apps, 1);
- AppListItemModel* item = model_.item_list()->item_at(1);
- ASSERT_TRUE(item);
- EXPECT_EQ("Inserted Item", item->id());
-}
-
-TEST_F(AppListModelTest, ModelRemoveItem) {
- const size_t num_apps = 4;
- model_.PopulateApps(num_apps);
- // Remove an item in the middle.
- model_.item_list()->DeleteItem(model_.GetItemName(1));
- EXPECT_EQ(num_apps - 1, model_.item_list()->item_count());
- EXPECT_EQ(1u, observer_.items_removed());
- // Remove the first item in the list.
- model_.item_list()->DeleteItem(model_.GetItemName(0));
- EXPECT_EQ(num_apps - 2, model_.item_list()->item_count());
- EXPECT_EQ(2u, observer_.items_removed());
- // Remove the last item in the list.
- model_.item_list()->DeleteItem(model_.GetItemName(num_apps - 1));
- EXPECT_EQ(num_apps - 3, model_.item_list()->item_count());
- EXPECT_EQ(3u, observer_.items_removed());
- // Ensure that the first item is the expected one
- AppListItemModel* item0 = model_.item_list()->item_at(0);
- ASSERT_TRUE(item0);
- EXPECT_EQ(model_.GetItemName(2), item0->id());
-}
-
-TEST_F(AppListModelTest, ModelRemoveItemByType) {
- const size_t num_apps = 4;
- model_.PopulateApps(num_apps);
- model_.item_list()->AddItem(new AppListFolderItem("folder1"));
- model_.item_list()->AddItem(new AppListFolderItem("folder2"));
- model_.item_list()->DeleteItemsByType(test::AppListTestModel::kAppType);
- EXPECT_EQ(num_apps, observer_.items_removed());
- EXPECT_EQ(2u, model_.item_list()->item_count());
- model_.item_list()->DeleteItemsByType(AppListFolderItem::kAppType);
- EXPECT_EQ(num_apps + 2, observer_.items_removed());
- EXPECT_EQ(0u, model_.item_list()->item_count());
- // Delete all items
- observer_.ResetCounts();
- model_.PopulateApps(num_apps);
- model_.item_list()->AddItem(new AppListFolderItem("folder1"));
- model_.item_list()->AddItem(new AppListFolderItem("folder2"));
- model_.item_list()->DeleteItemsByType(NULL /* all items */);
- EXPECT_EQ(num_apps + 2, observer_.items_removed());
- EXPECT_EQ(0u, model_.item_list()->item_count());
-}
-
-TEST_F(AppListModelTest, AppOrder) {
- const size_t num_apps = 5;
- model_.PopulateApps(num_apps);
- // Ensure order is preserved.
- for (size_t i = 1; i < num_apps; ++i) {
- EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
- model_.item_list()->item_at(i - 1)->position()));
- }
- // Move an app
- model_.item_list()->MoveItem(num_apps - 1, 1);
- // Ensure order is preserved.
- for (size_t i = 1; i < num_apps; ++i) {
- EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
- model_.item_list()->item_at(i - 1)->position()));
- }
-}
-
-TEST_F(AppListModelTest, FolderItem) {
- scoped_ptr<AppListFolderItem> folder(new AppListFolderItem("folder1"));
- const size_t num_folder_apps = 8;
- const size_t num_observed_apps = 4;
- for (int i = 0; static_cast<size_t>(i) < num_folder_apps; ++i) {
- std::string name = model_.GetItemName(i);
- folder->item_list()->AddItem(model_.CreateItem(name, name));
- }
- // Check that items 0 and 3 are observed.
- EXPECT_TRUE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(0)));
- EXPECT_TRUE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(num_observed_apps - 1)));
- // Check that item 4 is not observed.
- EXPECT_FALSE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(num_observed_apps)));
- folder->item_list()->MoveItem(num_observed_apps, 0);
- // Confirm that everything was moved where expected.
- EXPECT_EQ(model_.GetItemName(num_observed_apps),
- folder->item_list()->item_at(0)->id());
- EXPECT_EQ(model_.GetItemName(0),
- folder->item_list()->item_at(1)->id());
- EXPECT_EQ(model_.GetItemName(num_observed_apps - 1),
- folder->item_list()->item_at(num_observed_apps)->id());
- // Check that items 0 and 3 are observed.
- EXPECT_TRUE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(0)));
- EXPECT_TRUE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(num_observed_apps - 1)));
- // Check that item 4 is not observed.
- EXPECT_FALSE(ItemObservedByFolder(
- folder.get(), folder->item_list()->item_at(num_observed_apps)));
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_switches.cc b/chromium/ui/app_list/app_list_switches.cc
deleted file mode 100644
index fb75287d82d..00000000000
--- a/chromium/ui/app_list/app_list_switches.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_switches.h"
-
-#include "base/command_line.h"
-
-namespace app_list {
-namespace switches {
-
-// If set, folder will be enabled in app list UI.
-const char kEnableFolderUI[] = "enable-app-list-folder-ui";
-
-bool IsFolderUIEnabled() {
- return CommandLine::ForCurrentProcess()->HasSwitch(kEnableFolderUI);
-}
-
-} // namespcae switches
-} // namespace app_list
diff --git a/chromium/ui/app_list/app_list_switches.h b/chromium/ui/app_list/app_list_switches.h
deleted file mode 100644
index 70ea2b4b738..00000000000
--- a/chromium/ui/app_list/app_list_switches.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_APP_LIST_SWITCHES_H_
-#define UI_APP_LIST_APP_LIST_SWITCHES_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-namespace switches {
-
-APP_LIST_EXPORT extern const char kEnableFolderUI[];
-
-bool IsFolderUIEnabled();
-
-} // namespace switches
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_SWITCHES_H_
diff --git a/chromium/ui/app_list/app_list_view_delegate.cc b/chromium/ui/app_list/app_list_view_delegate.cc
deleted file mode 100644
index 2156cf5065e..00000000000
--- a/chromium/ui/app_list/app_list_view_delegate.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/app_list_view_delegate.h"
-
-namespace app_list {
-
-AppListViewDelegate::User::User() : active(false) {
-}
-
-AppListViewDelegate::User::~User() {
-}
-
-} // app_list
diff --git a/chromium/ui/app_list/app_list_view_delegate.h b/chromium/ui/app_list/app_list_view_delegate.h
deleted file mode 100644
index 235e126b510..00000000000
--- a/chromium/ui/app_list/app_list_view_delegate.h
+++ /dev/null
@@ -1,140 +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_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
-#define UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/files/file_path.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace content {
-class WebContents;
-}
-
-namespace gfx {
-class ImageSkia;
-}
-
-namespace app_list {
-
-class AppListItemModel;
-class AppListModel;
-class AppListViewDelegateObserver;
-class SearchResult;
-class SigninDelegate;
-class SpeechUIModel;
-
-class APP_LIST_EXPORT AppListViewDelegate {
- public:
- // A user of the app list.
- struct APP_LIST_EXPORT User {
- User();
- ~User();
-
- // Whether or not this user is the current user of the app list.
- bool active;
-
- // The name of this user.
- base::string16 name;
-
- // The email address of this user.
- base::string16 email;
-
- // The path to this user's profile directory.
- base::FilePath profile_path;
- };
- typedef std::vector<User> Users;
-
- // AppListView owns the delegate.
- virtual ~AppListViewDelegate() {}
-
- // Whether to force the use of a native desktop widget when the app list
- // window is first created.
- virtual bool ForceNativeDesktop() const = 0;
-
- // Sets the delegate to use the profile at |profile_path|. This is currently
- // only used by non-Ash Windows.
- virtual void SetProfileByPath(const base::FilePath& profile_path) = 0;
-
- // Gets the model associated with the view delegate. The model may be owned
- // by the delegate, or owned elsewhere (e.g. a profile keyed service).
- virtual AppListModel* GetModel() = 0;
-
- // Gets the SigninDelegate for the app list. Owned by the AppListViewDelegate.
- virtual SigninDelegate* GetSigninDelegate() = 0;
-
- // Gets the SpeechUIModel for the app list. Owned by the AppListViewDelegate.
- virtual SpeechUIModel* GetSpeechUI() = 0;
-
- // Gets a path to a shortcut for the given app. Returns asynchronously as the
- // shortcut may not exist yet.
- virtual void GetShortcutPathForApp(
- const std::string& app_id,
- const base::Callback<void(const base::FilePath&)>& callback) = 0;
-
- // Invoked to start a new search. Delegate collects query input from
- // SearchBoxModel and populates SearchResults. Both models are sub models
- // of AppListModel.
- virtual void StartSearch() = 0;
-
- // Invoked to stop the current search.
- virtual void StopSearch() = 0;
-
- // Invoked to open the search result.
- virtual void OpenSearchResult(SearchResult* result, int event_flags) = 0;
-
- // Called to invoke a custom action on |result|. |action_index| corresponds
- // to the index of an icon in |result.action_icons()|.
- virtual void InvokeSearchResultAction(SearchResult* result,
- int action_index,
- int event_flags) = 0;
-
- // Invoked to dismiss app list. This may leave the view open but hidden from
- // the user.
- virtual void Dismiss() = 0;
-
- // Invoked when the app list is closing.
- virtual void ViewClosing() = 0;
-
- // Returns the icon to be displayed in the window and taskbar.
- virtual gfx::ImageSkia GetWindowIcon() = 0;
-
- // Open the settings UI.
- virtual void OpenSettings() = 0;
-
- // Open the help UI.
- virtual void OpenHelp() = 0;
-
- // Open the feedback UI.
- virtual void OpenFeedback() = 0;
-
- // Invoked to toggle the status of speech recognition.
- virtual void ToggleSpeechRecognition() = 0;
-
- // Shows the app list for the profile specified by |profile_path|.
- virtual void ShowForProfileByPath(const base::FilePath& profile_path) = 0;
-
- // Get the start page web contents. Owned by the AppListViewDelegate.
- virtual content::WebContents* GetStartPageContents() = 0;
-
- // Returns the list of users (for AppListMenu).
- virtual const Users& GetUsers() const = 0;
-
- // Adds/removes an observer for profile changes.
- virtual void AddObserver(AppListViewDelegateObserver* observer) {}
- virtual void RemoveObserver(AppListViewDelegateObserver* observer) {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/app_list_view_delegate_observer.h b/chromium/ui/app_list/app_list_view_delegate_observer.h
deleted file mode 100644
index a612334e69e..00000000000
--- a/chromium/ui/app_list/app_list_view_delegate_observer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_APP_LIST_VIEW_DELEGATE_OBSERVER_H_
-#define UI_APP_LIST_APP_LIST_VIEW_DELEGATE_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT AppListViewDelegateObserver {
- public:
- // Invoked when the Profiles shown on the app list change, or the active
- // profile changes its signin status.
- virtual void OnProfilesChanged() = 0;
-
- protected:
- virtual ~AppListViewDelegateObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_APP_LIST_VIEW_DELEGATE_OBSERVER_H_
diff --git a/chromium/ui/app_list/cocoa/app_list_pager_view.h b/chromium/ui/app_list/cocoa/app_list_pager_view.h
deleted file mode 100644
index 0dcc44d9712..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_pager_view.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
-#define UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/cocoa/tracking_area.h"
-
-@class AppListPagerView;
-
-// Delegate to obtain the visible portion of a page and respond to clicks.
-@protocol AppListPagerDelegate<NSObject>
-
-// Returns the portion of a page that is visible, in the range (-1.0, 1.0].
-// Positive indicates the left side is visible, negative indicates the right.
-- (CGFloat)visiblePortionOfPage:(int)page;
-
-// Invoked when the pager is clicked.
-- (void)onPagerClicked:(AppListPagerView*)sender;
-
-@end
-
-// AppListPagerView draws a button strip with buttons representing pages, and a
-// highlight that mirrors the visible portion of the page.
-@interface AppListPagerView : NSSegmentedControl {
- @private
- // Used to auto-select a segment on hover.
- ui::ScopedCrTrackingArea trackingArea_;
-
- // The segment currently highlighted with a mouse hover, or -1 for none.
- NSInteger hoveredSegment_;
-}
-
-// Returns -1 if |locationInWindow| is not over a segment. Otherwise returns the
-// segment index and highlights it.
-- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
diff --git a/chromium/ui/app_list/cocoa/app_list_pager_view.mm b/chromium/ui/app_list/cocoa/app_list_pager_view.mm
deleted file mode 100644
index fc7f68cabb5..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_pager_view.mm
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-
-#include "base/mac/mac_util.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-const CGFloat kButtonHeight = 6;
-const CGFloat kButtonCornerRadius = 2;
-const CGFloat kButtonStripPadding = 20;
-
-} // namespace
-
-@interface AppListPagerView ()
-
-@property(assign, nonatomic) NSInteger hoveredSegment;
-
-- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow;
-
-@end
-
-@interface AppListPagerCell : NSSegmentedCell;
-@end
-
-@implementation AppListPagerView
-
-@synthesize hoveredSegment = hoveredSegment_;
-
-+ (Class)cellClass {
- return [AppListPagerCell class];
-}
-
-- (id)init {
- if ((self = [super initWithFrame:NSZeroRect])) {
- trackingArea_.reset(
- [[CrTrackingArea alloc] initWithRect:NSZeroRect
- options:NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveInKeyWindow
- owner:self
- userInfo:nil]);
- [self addTrackingArea:trackingArea_.get()];
- hoveredSegment_ = -1;
- }
- return self;
-}
-
-- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow {
- NSInteger segment = [self segmentUnderLocation:locationInWindow];
- [self setHoveredSegment:segment];
- return segment;
-}
-
-- (void)setHoveredSegment:(NSInteger)segment {
- if (segment == hoveredSegment_)
- return;
-
- hoveredSegment_ = segment;
- [self setNeedsDisplay:YES];
- return;
-}
-
-- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow {
- if ([self segmentCount] == 0)
- return -1;
-
- NSPoint pointInView = [self convertPoint:locationInWindow
- fromView:nil];
- if (![self mouse:pointInView inRect:[self bounds]])
- return -1;
-
- CGFloat segmentWidth = [self bounds].size.width / [self segmentCount];
- return pointInView.x / segmentWidth;
-}
-
-- (BOOL)isHoveredForSegment:(NSInteger)segment {
- return segment == hoveredSegment_;
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- [self setHoveredSegment:-1];
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- // Temporarily clear the highlight to give feedback.
- [self setHoveredSegment:-1];
-}
-
-// The stock NSSegmentedControl ignores any clicks outside the non-default
-// control height, so process all clicks here.
-- (void)mouseUp:(NSEvent*)theEvent {
- [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
- if (hoveredSegment_ < 0)
- return;
-
- [self setSelectedSegment:hoveredSegment_];
- [[self target] performSelector:[self action]
- withObject:self];
-}
-
-@end
-
-@implementation AppListPagerCell
-
-- (void)drawWithFrame:(NSRect)cellFrame
- inView:(NSView*)controlView {
- // Draw nothing if there are less than two segments.
- if ([self segmentCount] < 2)
- return;
-
- cellFrame.size.width /= [self segmentCount];
- for (NSInteger i = 0; i < [self segmentCount]; ++i) {
- [self drawSegment:i
- inFrame:cellFrame
- withView:controlView];
- cellFrame.origin.x += cellFrame.size.width;
- }
-}
-
-- (void)drawSegment:(NSInteger)segment
- inFrame:(NSRect)frame
- withView:(NSView*)controlView {
- gfx::ScopedNSGraphicsContextSaveGState context;
- NSRect clipRect = NSMakeRect(
- frame.origin.x + kButtonStripPadding / 2,
- floor(frame.origin.y + (frame.size.height - kButtonHeight) / 2),
- frame.size.width - kButtonStripPadding,
- kButtonHeight);
- [[NSBezierPath bezierPathWithRoundedRect:clipRect
- xRadius:kButtonCornerRadius
- yRadius:kButtonCornerRadius] addClip];
-
- AppListPagerView* pagerControl =
- base::mac::ObjCCastStrict<AppListPagerView>(controlView);
- SkColor backgroundColor = [pagerControl hoveredSegment] == segment ?
- app_list::kPagerHoverColor :
- app_list::kPagerNormalColor;
-
- [gfx::SkColorToSRGBNSColor(backgroundColor) set];
- NSRectFill(frame);
-
- if (![[self target] conformsToProtocol:@protocol(AppListPagerDelegate)])
- return;
-
- CGFloat selectedRatio = [[self target] visiblePortionOfPage:segment];
- if (selectedRatio == 0.0)
- return;
-
- [gfx::SkColorToSRGBNSColor(app_list::kPagerSelectedColor) set];
- if (selectedRatio < 0)
- frame.origin.x += frame.size.width + frame.size.width * selectedRatio;
- frame.size.width *= fabs(selectedRatio);
- NSRectFill(frame);
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/app_list_view_controller.h b/chromium/ui/app_list/cocoa/app_list_view_controller.h
deleted file mode 100644
index e4ffcbcb6d3..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_view_controller.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_export.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-namespace app_list {
-class AppListViewDelegate;
-class AppListModel;
-class AppListModelObserverBridge;
-}
-
-@class AppListPagerView;
-@class AppsGridController;
-@class SigninViewController;
-
-// Controller for the top-level view of the app list UI. It creates and hosts an
-// AppsGridController (displaying an AppListModel), pager control to navigate
-// between pages in the grid, and search entry box with a pop up menu.
-APP_LIST_EXPORT
-@interface AppListViewController : NSViewController<AppsPaginationModelObserver,
- AppsSearchBoxDelegate,
- AppsSearchResultsDelegate> {
- @private
- base::scoped_nsobject<AppsGridController> appsGridController_;
- base::scoped_nsobject<AppListPagerView> pagerControl_;
- base::scoped_nsobject<AppsSearchBoxController> appsSearchBoxController_;
- base::scoped_nsobject<AppsSearchResultsController>
- appsSearchResultsController_;
- base::scoped_nsobject<SigninViewController> signinViewController_;
-
- // Subview for drawing the background. Hidden when the signin view is visible.
- base::scoped_nsobject<NSView> backgroundView_;
-
- // Subview of |backgroundView_| that slides out when search results are shown.
- base::scoped_nsobject<NSView> contentsView_;
-
- scoped_ptr<app_list::AppListViewDelegate> delegate_;
- scoped_ptr<app_list::AppListModelObserverBridge>
- app_list_model_observer_bridge_;
- BOOL showingSearchResults_;
-}
-
-@property(readonly, nonatomic) AppsSearchBoxController*
- searchBoxController;
-
-- (app_list::AppListViewDelegate*)delegate;
-- (void)setDelegate:(scoped_ptr<app_list::AppListViewDelegate>)newDelegate;
-- (void)onProfilesChanged;
-
-@end
-
-@interface AppListViewController (TestingAPI)
-
-@property(nonatomic, readonly) BOOL showingSearchResults;
-
-- (AppsGridController*)appsGridController;
-- (NSSegmentedControl*)pagerControl;
-- (NSView*)backgroundView;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/app_list_view_controller.mm b/chromium/ui/app_list/cocoa/app_list_view_controller.mm
deleted file mode 100644
index ad73540f6e9..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_view_controller.mm
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/app_list_view_delegate_observer.h"
-#include "ui/app_list/signin_delegate.h"
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/signin_view_controller.h"
-#import "ui/base/cocoa/flipped_view.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-// The roundedness of the corners of the bubble.
-const CGFloat kBubbleCornerRadius = 3;
-
-// Height of the pager.
-const CGFloat kPagerPreferredHeight = 57;
-
-// Height of separator line drawn between the searchbox and grid view.
-const CGFloat kTopSeparatorSize = 1;
-
-// Height of the search input.
-const CGFloat kSearchInputHeight = 48;
-
-// Minimum margin on either side of the pager. If the pager grows beyond this,
-// the segment size is reduced.
-const CGFloat kMinPagerMargin = 40;
-// Maximum width of a single segment.
-const CGFloat kMaxSegmentWidth = 80;
-
-// Duration of the animation for sliding in and out search results.
-const NSTimeInterval kResultsAnimationDuration = 0.2;
-
-} // namespace
-
-@interface BackgroundView : FlippedView;
-@end
-
-@implementation BackgroundView
-
-- (void)drawRect:(NSRect)dirtyRect {
- gfx::ScopedNSGraphicsContextSaveGState context;
- NSRect boundsRect = [self bounds];
- NSRect searchAreaRect = NSMakeRect(0, 0,
- NSWidth(boundsRect), kSearchInputHeight);
- NSRect separatorRect = NSMakeRect(0, NSMaxY(searchAreaRect),
- NSWidth(boundsRect), kTopSeparatorSize);
-
- [[NSBezierPath bezierPathWithRoundedRect:boundsRect
- xRadius:kBubbleCornerRadius
- yRadius:kBubbleCornerRadius] addClip];
-
- [gfx::SkColorToSRGBNSColor(app_list::kContentsBackgroundColor) set];
- NSRectFill(boundsRect);
- [gfx::SkColorToSRGBNSColor(app_list::kSearchBoxBackground) set];
- NSRectFill(searchAreaRect);
- [gfx::SkColorToSRGBNSColor(app_list::kTopSeparatorColor) set];
- NSRectFill(separatorRect);
-}
-
-@end
-
-@interface AppListViewController ()
-
-- (void)loadAndSetView;
-- (void)revealSearchResults:(BOOL)show;
-
-@end
-
-namespace app_list {
-
-class AppListModelObserverBridge : public AppListViewDelegateObserver {
- public:
- AppListModelObserverBridge(AppListViewController* parent);
- virtual ~AppListModelObserverBridge();
-
- private:
- // Overridden from app_list::AppListViewDelegateObserver:
- virtual void OnProfilesChanged() OVERRIDE;
-
- AppListViewController* parent_; // Weak. Owns us.
-
- DISALLOW_COPY_AND_ASSIGN(AppListModelObserverBridge);
-};
-
-AppListModelObserverBridge::AppListModelObserverBridge(
- AppListViewController* parent)
- : parent_(parent) {
- [parent_ delegate]->AddObserver(this);
-}
-
-AppListModelObserverBridge::~AppListModelObserverBridge() {
- [parent_ delegate]->RemoveObserver(this);
-}
-
-void AppListModelObserverBridge::OnProfilesChanged() {
- [parent_ onProfilesChanged];
-}
-
-} // namespace app_list
-
-@implementation AppListViewController
-
-- (id)init {
- if ((self = [super init])) {
- appsGridController_.reset([[AppsGridController alloc] init]);
- [self loadAndSetView];
-
- [self totalPagesChanged];
- [self selectedPageChanged:0];
- [appsGridController_ setPaginationObserver:self];
- }
- return self;
-}
-
-- (void)dealloc {
- // Ensure that setDelegate(NULL) has been called before destruction, because
- // dealloc can be called at odd times, and Objective C destruction order does
- // not properly tear down these dependencies.
- DCHECK(delegate_ == NULL);
- [appsGridController_ setPaginationObserver:nil];
- [super dealloc];
-}
-
-- (AppsSearchBoxController*)searchBoxController {
- return appsSearchBoxController_;
-}
-
-- (BOOL)showingSearchResults {
- return showingSearchResults_;
-}
-
-- (AppsGridController*)appsGridController {
- return appsGridController_;
-}
-
-- (NSSegmentedControl*)pagerControl {
- return pagerControl_;
-}
-
-- (NSView*)backgroundView {
- return backgroundView_;
-}
-
-- (app_list::AppListViewDelegate*)delegate {
- return delegate_.get();
-}
-
-- (void)setDelegate:(scoped_ptr<app_list::AppListViewDelegate>)newDelegate {
- if (delegate_) {
- // First clean up, in reverse order.
- app_list_model_observer_bridge_.reset();
- [appsSearchResultsController_ setDelegate:nil];
- [appsSearchBoxController_ setDelegate:nil];
- [appsGridController_ setDelegate:nil];
- }
- delegate_.reset(newDelegate.release());
- if (!delegate_)
- return;
- [appsGridController_ setDelegate:delegate_.get()];
- [appsSearchBoxController_ setDelegate:self];
- [appsSearchResultsController_ setDelegate:self];
- app_list_model_observer_bridge_.reset(
- new app_list::AppListModelObserverBridge(self));
- [self onProfilesChanged];
-}
-
--(void)loadAndSetView {
- pagerControl_.reset([[AppListPagerView alloc] init]);
- [pagerControl_ setTarget:appsGridController_];
- [pagerControl_ setAction:@selector(onPagerClicked:)];
-
- NSRect gridFrame = [[appsGridController_ view] frame];
- NSRect contentsRect = NSMakeRect(0, kSearchInputHeight + kTopSeparatorSize,
- NSWidth(gridFrame), NSHeight(gridFrame) + kPagerPreferredHeight -
- [AppsGridController scrollerPadding]);
-
- contentsView_.reset([[FlippedView alloc] initWithFrame:contentsRect]);
- backgroundView_.reset(
- [[BackgroundView alloc] initWithFrame:
- NSMakeRect(0, 0, NSMaxX(contentsRect), NSMaxY(contentsRect))]);
- appsSearchBoxController_.reset(
- [[AppsSearchBoxController alloc] initWithFrame:
- NSMakeRect(0, 0, NSWidth(contentsRect), kSearchInputHeight)]);
- appsSearchResultsController_.reset(
- [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
- [contentsView_ bounds].size]);
- base::scoped_nsobject<NSView> containerView(
- [[NSView alloc] initWithFrame:[backgroundView_ frame]]);
-
- [contentsView_ addSubview:[appsGridController_ view]];
- [contentsView_ addSubview:pagerControl_];
- [backgroundView_ addSubview:contentsView_];
- [backgroundView_ addSubview:[appsSearchResultsController_ view]];
- [backgroundView_ addSubview:[appsSearchBoxController_ view]];
- [containerView addSubview:backgroundView_];
- [self setView:containerView];
-}
-
-- (void)revealSearchResults:(BOOL)show {
- if (show == showingSearchResults_)
- return;
-
- showingSearchResults_ = show;
- NSSize contentsSize = [contentsView_ frame].size;
- NSRect resultsTargetRect = NSMakeRect(
- 0, kSearchInputHeight + kTopSeparatorSize,
- contentsSize.width, contentsSize.height);
- NSRect contentsTargetRect = resultsTargetRect;
-
- // Shows results by sliding the grid and pager down to the bottom of the view.
- // Hides results by collapsing the search results container to a height of 0.
- if (show)
- contentsTargetRect.origin.y += NSHeight(contentsTargetRect);
- else
- resultsTargetRect.size.height = 0;
-
- [[NSAnimationContext currentContext] setDuration:kResultsAnimationDuration];
- [[contentsView_ animator] setFrame:contentsTargetRect];
- [[[appsSearchResultsController_ view] animator] setFrame:resultsTargetRect];
-}
-
-- (void)totalPagesChanged {
- size_t pageCount = [appsGridController_ pageCount];
- [pagerControl_ setSegmentCount:pageCount];
-
- NSRect viewFrame = [[pagerControl_ superview] bounds];
- CGFloat segmentWidth = std::min(
- kMaxSegmentWidth,
- (viewFrame.size.width - 2 * kMinPagerMargin) / pageCount);
-
- for (size_t i = 0; i < pageCount; ++i) {
- [pagerControl_ setWidth:segmentWidth
- forSegment:i];
- [[pagerControl_ cell] setTag:i
- forSegment:i];
- }
-
- // Center in view.
- [pagerControl_ sizeToFit];
- [pagerControl_ setFrame:
- NSMakeRect(NSMidX(viewFrame) - NSMidX([pagerControl_ bounds]),
- viewFrame.size.height - kPagerPreferredHeight,
- [pagerControl_ bounds].size.width,
- kPagerPreferredHeight)];
-}
-
-- (void)selectedPageChanged:(int)newSelected {
- [pagerControl_ selectSegmentWithTag:newSelected];
-}
-
-- (void)pageVisibilityChanged {
- [pagerControl_ setNeedsDisplay:YES];
-}
-
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
- return [pagerControl_ findAndHighlightSegmentAtLocation:locationInWindow];
-}
-
-- (app_list::SearchBoxModel*)searchBoxModel {
- app_list::AppListModel* appListModel = [appsGridController_ model];
- return appListModel ? appListModel->search_box() : NULL;
-}
-
-- (app_list::AppListViewDelegate*)appListDelegate {
- return [self delegate];
-}
-
-- (BOOL)control:(NSControl*)control
- textView:(NSTextView*)textView
- doCommandBySelector:(SEL)command {
- if (showingSearchResults_)
- return [appsSearchResultsController_ handleCommandBySelector:command];
-
- // If anything has been written, let the search view handle it.
- if ([[control stringValue] length] > 0)
- return NO;
-
- // Handle escape.
- if (command == @selector(complete:) ||
- command == @selector(cancel:) ||
- command == @selector(cancelOperation:)) {
- if (delegate_)
- delegate_->Dismiss();
- return YES;
- }
-
- // Possibly handle grid navigation.
- return [appsGridController_ handleCommandBySelector:command];
-}
-
-- (void)modelTextDidChange {
- app_list::SearchBoxModel* searchBoxModel = [self searchBoxModel];
- if (!searchBoxModel || !delegate_)
- return;
-
- base::string16 query;
- TrimWhitespace(searchBoxModel->text(), TRIM_ALL, &query);
- BOOL shouldShowSearch = !query.empty();
- [self revealSearchResults:shouldShowSearch];
- if (shouldShowSearch)
- delegate_->StartSearch();
- else
- delegate_->StopSearch();
-}
-
-- (app_list::AppListModel*)appListModel {
- return [appsGridController_ model];
-}
-
-- (void)openResult:(app_list::SearchResult*)result {
- if (delegate_)
- delegate_->OpenSearchResult(result, 0 /* event flags */);
-}
-
-- (void)redoSearch {
- [self modelTextDidChange];
-}
-
-- (void)onProfilesChanged {
- [appsSearchBoxController_ rebuildMenu];
- app_list::SigninDelegate* signinDelegate =
- delegate_ ? delegate_->GetSigninDelegate() : NULL;
- BOOL showSigninView = signinDelegate && signinDelegate->NeedSignin();
-
- [[signinViewController_ view] removeFromSuperview];
- signinViewController_.reset();
-
- if (!showSigninView) {
- [backgroundView_ setHidden:NO];
- return;
- }
-
- [backgroundView_ setHidden:YES];
- signinViewController_.reset(
- [[SigninViewController alloc] initWithFrame:[backgroundView_ frame]
- cornerRadius:kBubbleCornerRadius
- delegate:signinDelegate]);
- [[self view] addSubview:[signinViewController_ view]];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/app_list_view_controller_unittest.mm b/chromium/ui/app_list/cocoa/app_list_view_controller_unittest.mm
deleted file mode 100644
index 0a7d82b1faa..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_view_controller_unittest.mm
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/scoped_nsobject.h"
-#import "testing/gtest_mac.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-
-namespace app_list {
-namespace test {
-
-class AppListViewControllerTest : public AppsGridControllerTestHelper {
- public:
- AppListViewControllerTest() {}
-
- virtual void SetUp() OVERRIDE {
- app_list_view_controller_.reset([[AppListViewController alloc] init]);
- scoped_ptr<AppListTestViewDelegate> delegate(new AppListTestViewDelegate);
- delegate->SetSignedIn(true);
- [app_list_view_controller_
- setDelegate:delegate.PassAs<app_list::AppListViewDelegate>()];
- SetUpWithGridController([app_list_view_controller_ appsGridController]);
- [[test_window() contentView] addSubview:[app_list_view_controller_ view]];
- }
-
- virtual void TearDown() OVERRIDE {
- [app_list_view_controller_
- setDelegate:scoped_ptr<app_list::AppListViewDelegate>()];
- app_list_view_controller_.reset();
- AppsGridControllerTestHelper::TearDown();
- }
-
- void ReplaceTestModel(int item_count) {
- [app_list_view_controller_
- setDelegate:scoped_ptr<app_list::AppListViewDelegate>()];
- scoped_ptr<AppListTestViewDelegate> delegate(new AppListTestViewDelegate);
- delegate->ReplaceTestModel(item_count);
- [app_list_view_controller_
- setDelegate:delegate.PassAs<app_list::AppListViewDelegate>()];
- }
-
- AppListTestViewDelegate* delegate() {
- return static_cast<AppListTestViewDelegate*>(
- [app_list_view_controller_ delegate]);
- }
-
- AppListTestModel* model() {
- return delegate()->GetTestModel();
- }
-
- protected:
- base::scoped_nsobject<AppListViewController> app_list_view_controller_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppListViewControllerTest);
-};
-
-TEST_VIEW(AppListViewControllerTest, [app_list_view_controller_ view]);
-
-// Test that adding and removing pages updates the pager.
-TEST_F(AppListViewControllerTest, PagerSegmentCounts) {
- NSSegmentedControl* pager = [app_list_view_controller_ pagerControl];
- EXPECT_EQ(1, [pager segmentCount]);
-
- ReplaceTestModel(kItemsPerPage * 2);
- EXPECT_EQ(2, [pager segmentCount]);
- model()->PopulateApps(1);
- EXPECT_EQ(3, [pager segmentCount]);
-
- ReplaceTestModel(1);
- EXPECT_EQ(1, [pager segmentCount]);
-}
-
-// Test that clicking the pager changes pages.
-TEST_F(AppListViewControllerTest, PagerChangingPage) {
- NSSegmentedControl* pager = [app_list_view_controller_ pagerControl];
- ReplaceTestModel(kItemsPerPage * 3);
- EXPECT_EQ(3, [pager segmentCount]);
-
- EXPECT_EQ(0, [pager selectedSegment]);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
- // Emulate a click on the second segment to navigate to the second page.
- [pager setSelectedSegment:1];
- [[pager target] performSelector:[pager action]
- withObject:pager];
-
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(1, [pager selectedSegment]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
- // Replace with a single page model, and ensure we go back to the first page.
- ReplaceTestModel(1);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(0, [pager selectedSegment]);
- EXPECT_EQ(1, [pager segmentCount]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-}
-
-// Test the view when the user is already signed in.
-TEST_F(AppListViewControllerTest, SignedIn) {
- // There should be just 1, visible subview when signed in.
- EXPECT_EQ(1u, [[[app_list_view_controller_ view] subviews] count]);
- EXPECT_FALSE([[app_list_view_controller_ backgroundView] isHidden]);
-}
-
-// Test the view when signin is required.
-TEST_F(AppListViewControllerTest, NeedsSignin) {
- // Begin the test with a signed out app list.
- delegate()->SetSignedIn(false);
- EXPECT_EQ(2u, [[[app_list_view_controller_ view] subviews] count]);
- EXPECT_TRUE([[app_list_view_controller_ backgroundView] isHidden]);
-
- // Simulate signing in, should enter the SignedIn state.
- delegate()->SetSignedIn(true);
- EXPECT_EQ(1u, [[[app_list_view_controller_ view] subviews] count]);
- EXPECT_FALSE([[app_list_view_controller_ backgroundView] isHidden]);
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/cocoa/app_list_window_controller.h b/chromium/ui/app_list/cocoa/app_list_window_controller.h
deleted file mode 100644
index 052682fff56..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_window_controller.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-
-@class AppListViewController;
-
-// Controller for the app list NSWindow.
-APP_LIST_EXPORT
-@interface AppListWindowController : NSWindowController<NSWindowDelegate> {
- @private
- base::scoped_nsobject<AppListViewController> appListViewController_;
-}
-
-- (AppListViewController*)appListViewController;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/app_list_window_controller.mm b/chromium/ui/app_list/cocoa/app_list_window_controller.mm
deleted file mode 100644
index 9d359029460..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_window_controller.mm
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-#include "ui/base/cocoa/window_size_constants.h"
-
-@interface AppListWindow : NSWindow;
-@end
-
-@implementation AppListWindow
-
-// If we initialize a window with NSBorderlessWindowMask, it will not accept key
-// events (among other things) unless canBecomeKeyWindow is overridden.
-- (BOOL)canBecomeKeyWindow {
- return YES;
-}
-
-- (BOOL)canBecomeMainWindow {
- return YES;
-}
-
-@end
-
-@implementation AppListWindowController;
-
-- (id)init {
- base::scoped_nsobject<NSWindow> controlledWindow(
- [[AppListWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [controlledWindow setReleasedWhenClosed:NO];
- [controlledWindow setBackgroundColor:[NSColor clearColor]];
- [controlledWindow setOpaque:NO];
- [controlledWindow setHasShadow:YES];
- [controlledWindow setLevel:NSDockWindowLevel];
- [controlledWindow
- setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace];
-
- if ((self = [super initWithWindow:controlledWindow])) {
- appListViewController_.reset([[AppListViewController alloc] init]);
- [[self window] setFrame:[[appListViewController_ view] bounds]
- display:NO];
- [[self window] setContentView:[appListViewController_ view]];
- [[self window] setDelegate:self];
- }
- return self;
-}
-
-- (AppListViewController*)appListViewController {
- return appListViewController_;
-}
-
-- (void)windowDidResignMain:(NSNotification*)notification {
- if ([appListViewController_ delegate])
- [appListViewController_ delegate]->Dismiss();
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- [[appListViewController_ searchBoxController] clearSearch];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/app_list_window_controller_unittest.mm b/chromium/ui/app_list/cocoa/app_list_window_controller_unittest.mm
deleted file mode 100644
index 0f766917750..00000000000
--- a/chromium/ui/app_list/cocoa/app_list_window_controller_unittest.mm
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-
-namespace {
-
-class AppListWindowControllerTest : public ui::CocoaTest {
- public:
- AppListWindowControllerTest();
-
- protected:
- virtual void TearDown() OVERRIDE;
-
- base::scoped_nsobject<AppListWindowController> controller_;
-
- app_list::test::AppListTestViewDelegate* delegate() {
- return static_cast<app_list::test::AppListTestViewDelegate*>(
- [[controller_ appListViewController] delegate]);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppListWindowControllerTest);
-};
-
-AppListWindowControllerTest::AppListWindowControllerTest() {
- Init();
- scoped_ptr<app_list::AppListViewDelegate> delegate(
- new app_list::test::AppListTestViewDelegate);
- controller_.reset([[AppListWindowController alloc] init]);
- [[controller_ appListViewController] setDelegate:delegate.Pass()];
-}
-
-void AppListWindowControllerTest::TearDown() {
- EXPECT_TRUE(controller_.get());
- [[controller_ window] close];
- [[controller_ appListViewController]
- setDelegate:scoped_ptr<app_list::AppListViewDelegate>()];
- controller_.reset();
- ui::CocoaTest::TearDown();
-}
-
-} // namespace
-
-// Test showing, hiding and closing the app list window.
-TEST_F(AppListWindowControllerTest, ShowHideCloseRelease) {
- EXPECT_TRUE([controller_ window]);
- [[controller_ window] makeKeyAndOrderFront:nil];
- EXPECT_TRUE([[controller_ window] isVisible]);
- EXPECT_TRUE([[[controller_ window] contentView] superview]);
- [[controller_ window] close]; // Hide.
- EXPECT_FALSE([[controller_ window] isVisible]);
- [[controller_ window] makeKeyAndOrderFront:nil];
-}
-
-// Test that the key bound to cancel (usually Escape) asks the controller to
-// dismiss the window.
-TEST_F(AppListWindowControllerTest, DismissWithEscape) {
- [[controller_ window] makeKeyAndOrderFront:nil];
- EXPECT_EQ(0, delegate()->dismiss_count());
- [[controller_ window] cancelOperation:controller_];
- EXPECT_EQ(1, delegate()->dismiss_count());
-}
-
-// Test that search results are cleared when the window closes, not when a
-// search result is selected. If cleared upon selection, the animation showing
-// the results sliding away is seen as the window closes, which looks weird.
-TEST_F(AppListWindowControllerTest, CloseClearsSearch) {
- [[controller_ window] makeKeyAndOrderFront:nil];
- app_list::SearchBoxModel* model = delegate()->GetModel()->search_box();
- AppListViewController* view_controller = [controller_ appListViewController];
-
- EXPECT_FALSE([view_controller showingSearchResults]);
-
- const base::string16 search_text(ASCIIToUTF16("test"));
- model->SetText(search_text);
- EXPECT_TRUE([view_controller showingSearchResults]);
-
- EXPECT_EQ(0, delegate()->open_search_result_count());
- [view_controller openResult:nil];
- EXPECT_EQ(1, delegate()->open_search_result_count());
-
- EXPECT_TRUE([view_controller showingSearchResults]);
- [[controller_ window] close]; // Hide.
- EXPECT_FALSE([view_controller showingSearchResults]);
-}
diff --git a/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.h b/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.h
deleted file mode 100644
index e8b5caf0079..00000000000
--- a/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
-#define UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-
-@class AppsGridController;
-@class ItemDragController;
-
-// Manager for the state associated with dragging an NSCollectionViewItem in the
-// AppsGridController. It is also a factory for the NSCollectionView pages in
-// the grid, allowing items to be dragged between pages.
-APP_LIST_EXPORT
-@interface AppsCollectionViewDragManager : NSObject {
- @private
- base::scoped_nsobject<ItemDragController> itemDragController_;
- AppsGridController* gridController_; // Weak. Owns us.
-
- NSSize cellSize_;
- size_t rows_;
- size_t columns_;
-
- // Index of the last known position of the item currently being dragged.
- size_t itemDragIndex_;
-
- // Model index of the item being dragged, or NSNotFound if nothing was hit on
- // the last mouseDown.
- size_t itemHitIndex_;
-
- // Location in the window of the last mouseDown event.
- NSPoint mouseDownLocation_;
-
- // Whether the current mouse action has converted into an item drag.
- BOOL dragging_;
-}
-
-- (id)initWithCellSize:(NSSize)cellSize
- rows:(size_t)rows
- columns:(size_t)columns
- gridController:(AppsGridController*)gridController;
-
-// Make an empty NSCollectionView with draggable items in the given |pageFrame|.
-- (NSCollectionView*)makePageWithFrame:(NSRect)pageFrame;
-
-- (void)cancelDrag;
-
-@end
-
-@interface AppsCollectionViewDragManager (TestingAPI)
-
-- (void)onMouseDownInPage:(NSCollectionView*)page
- withEvent:(NSEvent*)theEvent;
-- (void)onMouseDragged:(NSEvent*)theEvent;
-- (void)onMouseUp:(NSEvent*)theEvent;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
diff --git a/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.mm b/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
deleted file mode 100644
index 74e23c4e0ec..00000000000
--- a/chromium/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/item_drag_controller.h"
-
-namespace {
-
-// Distance cursor must travel in either x or y direction to start a drag.
-const CGFloat kDragThreshold = 5;
-
-} // namespace
-
-@interface AppsCollectionViewDragManager ()
-
-// Returns the item index that |theEvent| would hit in the page at |pageIndex|
-// or NSNotFound if no item is hit.
-- (size_t)itemIndexForPage:(size_t)pageIndex
- hitWithEvent:(NSEvent*)theEvent;
-
-- (void)initiateDrag:(NSEvent*)theEvent;
-- (void)updateDrag:(NSEvent*)theEvent;
-- (void)completeDrag;
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent
- inPage:(NSCollectionView*)page;
-
-@end
-
-// An NSCollectionView that forwards mouse events to the factory they share.
-@interface GridCollectionView : NSCollectionView {
- @private
- AppsCollectionViewDragManager* factory_;
-}
-
-@property(assign, nonatomic) AppsCollectionViewDragManager* factory;
-
-@end
-
-@implementation AppsCollectionViewDragManager
-
-- (id)initWithCellSize:(NSSize)cellSize
- rows:(size_t)rows
- columns:(size_t)columns
- gridController:(AppsGridController*)gridController {
- if ((self = [super init])) {
- cellSize_ = cellSize;
- rows_ = rows;
- columns_ = columns;
- gridController_ = gridController;
- }
- return self;
-}
-
-- (NSCollectionView*)makePageWithFrame:(NSRect)pageFrame {
- base::scoped_nsobject<GridCollectionView> itemCollectionView(
- [[GridCollectionView alloc] initWithFrame:pageFrame]);
- [itemCollectionView setFactory:self];
- [itemCollectionView setMaxNumberOfRows:rows_];
- [itemCollectionView setMinItemSize:cellSize_];
- [itemCollectionView setMaxItemSize:cellSize_];
- [itemCollectionView setSelectable:YES];
- [itemCollectionView setFocusRingType:NSFocusRingTypeNone];
- [itemCollectionView setBackgroundColors:
- [NSArray arrayWithObject:[NSColor clearColor]]];
- [itemCollectionView setDelegate:gridController_];
-
- base::scoped_nsobject<AppsGridViewItem> itemPrototype(
- [[AppsGridViewItem alloc] initWithSize:cellSize_]);
- [[itemPrototype button] setTarget:gridController_];
- [[itemPrototype button] setAction:@selector(onItemClicked:)];
-
- [itemCollectionView setItemPrototype:itemPrototype];
- return itemCollectionView.autorelease();
-}
-
-- (void)onMouseDownInPage:(NSCollectionView*)page
- withEvent:(NSEvent*)theEvent {
- size_t pageIndex = [gridController_ pageIndexForCollectionView:page];
- itemHitIndex_ = [self itemIndexForPage:pageIndex
- hitWithEvent:theEvent];
- if (itemHitIndex_ == NSNotFound)
- return;
-
- mouseDownLocation_ = [theEvent locationInWindow];
- [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseDown:theEvent];
-}
-
-- (void)onMouseDragged:(NSEvent*)theEvent {
- if (itemHitIndex_ == NSNotFound)
- return;
-
- if (dragging_) {
- [self updateDrag:theEvent];
- return;
- }
-
- NSPoint mouseLocation = [theEvent locationInWindow];
- CGFloat deltaX = mouseLocation.x - mouseDownLocation_.x;
- CGFloat deltaY = mouseLocation.y - mouseDownLocation_.y;
- if (deltaX * deltaX + deltaY * deltaY > kDragThreshold * kDragThreshold) {
- [self initiateDrag:theEvent];
- return;
- }
-
- [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseDragged:theEvent];
-}
-
-- (void)onMouseUp:(NSEvent*)theEvent {
- if (itemHitIndex_ == NSNotFound)
- return;
-
- if (dragging_) {
- [self completeDrag];
- return;
- }
-
- [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseUp:theEvent];
-}
-
-- (size_t)itemIndexForPage:(size_t)pageIndex
- hitWithEvent:(NSEvent*)theEvent {
- NSCollectionView* page =
- [gridController_ collectionViewAtPageIndex:pageIndex];
- NSPoint pointInView = [page convertPoint:[theEvent locationInWindow]
- fromView:nil];
-
- const size_t itemsInPage = [[page content] count];
- for (size_t indexInPage = 0; indexInPage < itemsInPage; ++indexInPage) {
- if ([page mouse:pointInView
- inRect:[page frameForItemAtIndex:indexInPage]]) {
- return indexInPage + pageIndex * rows_ * columns_;
- }
- }
-
- return NSNotFound;
-}
-
-- (void)initiateDrag:(NSEvent*)theEvent {
- DCHECK_LT(itemHitIndex_, [gridController_ itemCount]);
- dragging_ = YES;
-
- if (!itemDragController_) {
- itemDragController_.reset(
- [[ItemDragController alloc] initWithGridCellSize:cellSize_]);
- [[[gridController_ view] superview] addSubview:[itemDragController_ view]];
- }
-
- [itemDragController_ initiate:[gridController_ itemAtIndex:itemHitIndex_]
- mouseDownLocation:mouseDownLocation_
- currentLocation:[theEvent locationInWindow]
- timestamp:[theEvent timestamp]];
-
- itemDragIndex_ = itemHitIndex_;
- [self updateDrag:theEvent];
-}
-
-- (void)updateDrag:(NSEvent*)theEvent {
- [itemDragController_ update:[theEvent locationInWindow]
- timestamp:[theEvent timestamp]];
- [gridController_ maybeChangePageForPoint:[theEvent locationInWindow]];
-
- size_t visiblePage = [gridController_ visiblePage];
- size_t itemIndexOver = [self itemIndexForPage:visiblePage
- hitWithEvent:theEvent];
- DCHECK_NE(0u, [gridController_ itemCount]);
- if (itemIndexOver == NSNotFound) {
- if (visiblePage != [gridController_ pageCount] - 1)
- return;
-
- // If nothing was hit, but the last page is shown, move to the end.
- itemIndexOver = [gridController_ itemCount] - 1;
- }
-
- if (itemDragIndex_ == itemIndexOver)
- return;
-
- [gridController_ moveItemInView:itemDragIndex_
- toItemIndex:itemIndexOver];
- // A new item may be created when moving between pages. Ensure it is hidden.
- [[[gridController_ itemAtIndex:itemIndexOver] button] setHidden:YES];
- itemDragIndex_ = itemIndexOver;
-}
-
-- (void)cancelDrag {
- if (!dragging_)
- return;
-
- [gridController_ moveItemInView:itemDragIndex_
- toItemIndex:itemHitIndex_];
- itemDragIndex_ = itemHitIndex_;
- [self completeDrag];
- itemHitIndex_ = NSNotFound; // Ignore future mouse events for this drag.
-}
-
-- (void)completeDrag {
- DCHECK_GE(itemDragIndex_, 0u);
- [gridController_ cancelScrollTimer];
- AppsGridViewItem* item = [gridController_ itemAtIndex:itemDragIndex_];
-
- // The item could still be animating in the NSCollectionView, so ask it where
- // it would place the item.
- NSCollectionView* pageView = base::mac::ObjCCastStrict<NSCollectionView>(
- [[item view] superview]);
- size_t indexInPage = itemDragIndex_ % (rows_ * columns_);
- NSPoint targetOrigin = [[[itemDragController_ view] superview]
- convertPoint:[pageView frameForItemAtIndex:indexInPage].origin
- fromView:pageView];
-
- [itemDragController_ complete:item
- targetOrigin:targetOrigin];
- [gridController_ moveItemWithIndex:itemHitIndex_
- toModelIndex:itemDragIndex_];
-
- dragging_ = NO;
-}
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent
- inPage:(NSCollectionView*)page {
- size_t pageIndex = [gridController_ pageIndexForCollectionView:page];
- size_t itemIndex = [self itemIndexForPage:pageIndex
- hitWithEvent:theEvent];
- if (itemIndex == NSNotFound)
- return nil;
-
- return [[gridController_ itemAtIndex:itemIndex] contextMenu];
-}
-
-@end
-
-@implementation GridCollectionView
-
-@synthesize factory = factory_;
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent {
- return [factory_ menuForEvent:theEvent
- inPage:self];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- [factory_ onMouseDownInPage:self
- withEvent:theEvent];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- [factory_ onMouseDragged:theEvent];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- [factory_ onMouseUp:theEvent];
-}
-
-- (BOOL)acceptsFirstResponder {
- return NO;
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/apps_grid_controller.h b/chromium/ui/app_list/cocoa/apps_grid_controller.h
deleted file mode 100644
index e56533110a9..00000000000
--- a/chromium/ui/app_list/cocoa/apps_grid_controller.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_export.h"
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-#import "ui/app_list/cocoa/scroll_view_with_no_scrollbars.h"
-
-namespace app_list {
-class AppListModel;
-class AppListViewDelegate;
-class AppsGridDelegateBridge;
-}
-
-@class AppsGridViewItem;
-@protocol AppsPaginationModelObserver;
-@class AppsCollectionViewDragManager;
-
-// Controls a grid of views, representing AppListItemList sub models.
-APP_LIST_EXPORT
-@interface AppsGridController : NSViewController<GestureScrollDelegate,
- AppListPagerDelegate,
- NSCollectionViewDelegate> {
- @private
- app_list::AppListViewDelegate* delegate_; // Weak. Owned by view controller.
- scoped_ptr<app_list::AppsGridDelegateBridge> bridge_;
-
- base::scoped_nsobject<AppsCollectionViewDragManager> dragManager_;
- base::scoped_nsobject<NSMutableArray> pages_;
- base::scoped_nsobject<NSMutableArray> items_;
- base::scoped_nsobject<NSTimer> scrollWhileDraggingTimer_;
-
- id<AppsPaginationModelObserver> paginationObserver_;
-
- // Index of the currently visible page.
- size_t visiblePage_;
- // The page to which the view is currently animating a scroll.
- size_t targetScrollPage_;
- // The page to start scrolling to when the timer expires.
- size_t scheduledScrollPage_;
-
- // Whether we are currently animating a scroll to the nearest page.
- BOOL animatingScroll_;
-}
-
-@property(assign, nonatomic) id<AppsPaginationModelObserver> paginationObserver;
-
-+ (void)setScrollAnimationDuration:(NSTimeInterval)duration;
-
-// The amount the grid view has been extended to hold the sometimes present
-// invisible scroller that allows for gesture scrolling.
-+ (CGFloat)scrollerPadding;
-
-- (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex;
-- (size_t)pageIndexForCollectionView:(NSCollectionView*)page;
-
-- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex;
-
-- (app_list::AppListModel*)model;
-
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate;
-
-- (size_t)visiblePage;
-
-// Calls item->Activate for the currently selected item by simulating a click.
-- (void)activateSelection;
-
-// Return the number of pages of icons in the grid.
-- (size_t)pageCount;
-
-// Return the number of items over all pages in the grid.
-- (size_t)itemCount;
-
-// Scroll to a page in the grid view with an animation.
-- (void)scrollToPage:(size_t)pageIndex;
-
-// Start a timer to scroll to a new page, if |locationInWindow| is to the left
-// or the right of the view, or if it is over a pager segment. Cancels any
-// existing timer if the target page changes.
-- (void)maybeChangePageForPoint:(NSPoint)locationInWindow;
-
-// Cancel a timer that may have been set by maybeChangePageForPoint().
-- (void)cancelScrollTimer;
-
-// Moves an item within the view only, for dragging or in response to model
-// changes.
-- (void)moveItemInView:(size_t)fromIndex
- toItemIndex:(size_t)toIndex;
-
-// Moves an item in the item model. Does not adjust the view.
-- (void)moveItemWithIndex:(size_t)itemIndex
- toModelIndex:(size_t)modelIndex;
-
-// Return the index of the selected item.
-- (NSUInteger)selectedItemIndex;
-
-// Moves the selection to the given index.
-- (void)selectItemAtIndex:(NSUInteger)index;
-
-// Handle key actions. Similar to doCommandBySelector from NSResponder but that
-// requires this class to be in the responder chain. Instead this method is
-// invoked by the AppListViewController.
-// Returns YES if this handled navigation or launched an app.
-- (BOOL)handleCommandBySelector:(SEL)command;
-
-@end
-
-@interface AppsGridController(TestingAPI)
-
-- (AppsCollectionViewDragManager*)dragManager;
-- (size_t)scheduledScrollPage;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/apps_grid_controller.mm b/chromium/ui/app_list/cocoa/apps_grid_controller.mm
deleted file mode 100644
index dc5145cf441..00000000000
--- a/chromium/ui/app_list/cocoa/apps_grid_controller.mm
+++ /dev/null
@@ -1,675 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#include "ui/base/models/list_model_observer.h"
-
-namespace {
-
-// OSX app list has hardcoded rows and columns for now.
-const int kFixedRows = 4;
-const int kFixedColumns = 4;
-const int kItemsPerPage = kFixedRows * kFixedColumns;
-
-// Padding space in pixels for fixed layout.
-const CGFloat kGridTopPadding = 1;
-const CGFloat kLeftRightPadding = 21;
-const CGFloat kScrollerPadding = 16;
-
-// Preferred tile size when showing in fixed layout. These should be even
-// numbers to ensure that if they are grown 50% they remain integers.
-const CGFloat kPreferredTileWidth = 88;
-const CGFloat kPreferredTileHeight = 98;
-
-const CGFloat kViewWidth =
- kFixedColumns * kPreferredTileWidth + 2 * kLeftRightPadding;
-const CGFloat kViewHeight = kFixedRows * kPreferredTileHeight;
-
-const NSTimeInterval kScrollWhileDraggingDelay = 1.0;
-NSTimeInterval g_scroll_duration = 0.18;
-
-} // namespace
-
-@interface AppsGridController ()
-
-- (void)scrollToPageWithTimer:(size_t)targetPage;
-- (void)onTimer:(NSTimer*)theTimer;
-
-// Cancel a currently running scroll animation.
-- (void)cancelScrollAnimation;
-
-// Index of the page with the most content currently visible.
-- (size_t)nearestPageIndex;
-
-// Bootstrap the views this class controls.
-- (void)loadAndSetView;
-
-- (void)boundsDidChange:(NSNotification*)notification;
-
-// Action for buttons in the grid.
-- (void)onItemClicked:(id)sender;
-
-- (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
- indexInPage:(size_t)indexInPage;
-
-// Return the button of the selected item.
-- (NSButton*)selectedButton;
-
-// The scroll view holding the grid pages.
-- (NSScrollView*)gridScrollView;
-
-- (NSView*)pagesContainerView;
-
-// Create any new pages after updating |items_|.
-- (void)updatePages:(size_t)startItemIndex;
-
-- (void)updatePageContent:(size_t)pageIndex
- resetModel:(BOOL)resetModel;
-
-// Bridged methods for AppListItemListObserver.
-- (void)listItemAdded:(size_t)index
- item:(app_list::AppListItemModel*)item;
-
-- (void)listItemRemoved:(size_t)index;
-
-- (void)listItemMovedFromIndex:(size_t)fromIndex
- toModelIndex:(size_t)toIndex;
-
-// Moves the selection by |indexDelta| items.
-- (BOOL)moveSelectionByDelta:(int)indexDelta;
-
-@end
-
-namespace app_list {
-
-class AppsGridDelegateBridge : public AppListItemListObserver {
- public:
- AppsGridDelegateBridge(AppsGridController* parent) : parent_(parent) {}
-
- private:
- // Overridden from AppListItemListObserver:
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
- [parent_ listItemAdded:index
- item:item];
- }
- virtual void OnListItemRemoved(size_t index,
- AppListItemModel* item) OVERRIDE {
- [parent_ listItemRemoved:index];
- }
- virtual void OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) OVERRIDE {
- [parent_ listItemMovedFromIndex:from_index
- toModelIndex:to_index];
- }
-
- AppsGridController* parent_; // Weak, owns us.
-
- DISALLOW_COPY_AND_ASSIGN(AppsGridDelegateBridge);
-};
-
-} // namespace app_list
-
-@interface PageContainerView : NSView;
-@end
-
-// The container view needs to flip coordinates so that it is laid out
-// correctly whether or not there is a horizontal scrollbar.
-@implementation PageContainerView
-
-- (BOOL)isFlipped {
- return YES;
-}
-
-@end
-
-@implementation AppsGridController
-
-+ (void)setScrollAnimationDuration:(NSTimeInterval)duration {
- g_scroll_duration = duration;
-}
-
-+ (CGFloat)scrollerPadding {
- return kScrollerPadding;
-}
-
-@synthesize paginationObserver = paginationObserver_;
-
-- (id)init {
- if ((self = [super init])) {
- bridge_.reset(new app_list::AppsGridDelegateBridge(self));
- NSSize cellSize = NSMakeSize(kPreferredTileWidth, kPreferredTileHeight);
- dragManager_.reset(
- [[AppsCollectionViewDragManager alloc] initWithCellSize:cellSize
- rows:kFixedRows
- columns:kFixedColumns
- gridController:self]);
- pages_.reset([[NSMutableArray alloc] init]);
- items_.reset([[NSMutableArray alloc] init]);
- [self loadAndSetView];
- [self updatePages:0];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex {
- return [pages_ objectAtIndex:pageIndex];
-}
-
-- (size_t)pageIndexForCollectionView:(NSCollectionView*)page {
- for (size_t pageIndex = 0; pageIndex < [pages_ count]; ++pageIndex) {
- if (page == [self collectionViewAtPageIndex:pageIndex])
- return pageIndex;
- }
- return NSNotFound;
-}
-
-- (app_list::AppListModel*)model {
- return delegate_ ? delegate_->GetModel() : NULL;
-}
-
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
- if (delegate_) {
- app_list::AppListModel* oldModel = delegate_->GetModel();
- if (oldModel)
- oldModel->item_list()->RemoveObserver(bridge_.get());
- }
-
- // Since the old model may be getting deleted, and the AppKit objects might
- // be sitting in an NSAutoreleasePool, ensure there are no references to
- // the model.
- for (size_t i = 0; i < [items_ count]; ++i)
- [[self itemAtIndex:i] setModel:NULL];
-
- [items_ removeAllObjects];
- [self updatePages:0];
- [self scrollToPage:0];
-
- delegate_ = newDelegate;
- if (!delegate_)
- return;
-
- app_list::AppListModel* newModel = delegate_->GetModel();
- if (!newModel)
- return;
-
- newModel->item_list()->AddObserver(bridge_.get());
- for (size_t i = 0; i < newModel->item_list()->item_count(); ++i) {
- app_list::AppListItemModel* itemModel = newModel->item_list()->item_at(i);
- [items_ insertObject:[NSValue valueWithPointer:itemModel]
- atIndex:i];
- }
- [self updatePages:0];
-}
-
-- (size_t)visiblePage {
- return visiblePage_;
-}
-
-- (void)activateSelection {
- [[self selectedButton] performClick:self];
-}
-
-- (size_t)pageCount {
- return [pages_ count];
-}
-
-- (size_t)itemCount {
- return [items_ count];
-}
-
-- (void)scrollToPage:(size_t)pageIndex {
- NSClipView* clipView = [[self gridScrollView] contentView];
- NSPoint newOrigin = [clipView bounds].origin;
-
- // Scrolling outside of this range is edge elasticity, which animates
- // automatically.
- if ((pageIndex == 0 && (newOrigin.x <= 0)) ||
- (pageIndex + 1 == [self pageCount] &&
- newOrigin.x >= pageIndex * kViewWidth)) {
- return;
- }
-
- // Clear any selection on the current page (unless it has been removed).
- if (visiblePage_ < [pages_ count]) {
- [[self collectionViewAtPageIndex:visiblePage_]
- setSelectionIndexes:[NSIndexSet indexSet]];
- }
-
- newOrigin.x = pageIndex * kViewWidth;
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:g_scroll_duration];
- [[clipView animator] setBoundsOrigin:newOrigin];
- [NSAnimationContext endGrouping];
- animatingScroll_ = YES;
- targetScrollPage_ = pageIndex;
- [self cancelScrollTimer];
-}
-
-- (void)maybeChangePageForPoint:(NSPoint)locationInWindow {
- NSPoint pointInView = [[self view] convertPoint:locationInWindow
- fromView:nil];
- // Check if the point is outside the view on the left or right.
- if (pointInView.x <= 0 || pointInView.x >= NSWidth([[self view] bounds])) {
- size_t targetPage = visiblePage_;
- if (pointInView.x <= 0)
- targetPage -= targetPage != 0 ? 1 : 0;
- else
- targetPage += targetPage < [pages_ count] - 1 ? 1 : 0;
- [self scrollToPageWithTimer:targetPage];
- return;
- }
-
- if (paginationObserver_) {
- NSInteger segment =
- [paginationObserver_ pagerSegmentAtLocation:locationInWindow];
- if (segment >= 0 && static_cast<size_t>(segment) != targetScrollPage_) {
- [self scrollToPageWithTimer:segment];
- return;
- }
- }
-
- // Otherwise the point may have moved back into the view.
- [self cancelScrollTimer];
-}
-
-- (void)cancelScrollTimer {
- scheduledScrollPage_ = targetScrollPage_;
- [scrollWhileDraggingTimer_ invalidate];
-}
-
-- (void)scrollToPageWithTimer:(size_t)targetPage {
- if (targetPage == targetScrollPage_) {
- [self cancelScrollTimer];
- return;
- }
-
- if (targetPage == scheduledScrollPage_)
- return;
-
- scheduledScrollPage_ = targetPage;
- [scrollWhileDraggingTimer_ invalidate];
- scrollWhileDraggingTimer_.reset(
- [[NSTimer scheduledTimerWithTimeInterval:kScrollWhileDraggingDelay
- target:self
- selector:@selector(onTimer:)
- userInfo:nil
- repeats:NO] retain]);
-}
-
-- (void)onTimer:(NSTimer*)theTimer {
- if (scheduledScrollPage_ == targetScrollPage_)
- return; // Already animating scroll.
-
- [self scrollToPage:scheduledScrollPage_];
-}
-
-- (void)cancelScrollAnimation {
- NSClipView* clipView = [[self gridScrollView] contentView];
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:0];
- [[clipView animator] setBoundsOrigin:[clipView bounds].origin];
- [NSAnimationContext endGrouping];
- animatingScroll_ = NO;
-}
-
-- (size_t)nearestPageIndex {
- return lround(
- NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth);
-}
-
-- (void)userScrolling:(BOOL)isScrolling {
- if (isScrolling) {
- if (animatingScroll_)
- [self cancelScrollAnimation];
- } else {
- [self scrollToPage:[self nearestPageIndex]];
- }
-}
-
-- (void)loadAndSetView {
- base::scoped_nsobject<PageContainerView> pagesContainer(
- [[PageContainerView alloc] initWithFrame:NSZeroRect]);
-
- NSRect scrollFrame = NSMakeRect(0, kGridTopPadding, kViewWidth,
- kViewHeight + kScrollerPadding);
- base::scoped_nsobject<ScrollViewWithNoScrollbars> scrollView(
- [[ScrollViewWithNoScrollbars alloc] initWithFrame:scrollFrame]);
- [scrollView setBorderType:NSNoBorder];
- [scrollView setLineScroll:kViewWidth];
- [scrollView setPageScroll:kViewWidth];
- [scrollView setDelegate:self];
- [scrollView setDocumentView:pagesContainer];
- [scrollView setDrawsBackground:NO];
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(boundsDidChange:)
- name:NSViewBoundsDidChangeNotification
- object:[scrollView contentView]];
-
- [self setView:scrollView];
-}
-
-- (void)boundsDidChange:(NSNotification*)notification {
- size_t newPage = [self nearestPageIndex];
- if (newPage == visiblePage_) {
- [paginationObserver_ pageVisibilityChanged];
- return;
- }
-
- visiblePage_ = newPage;
- [paginationObserver_ selectedPageChanged:newPage];
- [paginationObserver_ pageVisibilityChanged];
-}
-
-- (void)onItemClicked:(id)sender {
- for (size_t i = 0; i < [items_ count]; ++i) {
- AppsGridViewItem* item = [self itemAtIndex:i];
- if ([[item button] isEqual:sender])
- [item model]->Activate(0);
- }
-}
-
-- (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
- indexInPage:(size_t)indexInPage {
- return base::mac::ObjCCastStrict<AppsGridViewItem>(
- [[self collectionViewAtPageIndex:pageIndex] itemAtIndex:indexInPage]);
-}
-
-- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex {
- const size_t pageIndex = itemIndex / kItemsPerPage;
- return [self itemAtPageIndex:pageIndex
- indexInPage:itemIndex - pageIndex * kItemsPerPage];
-}
-
-- (NSUInteger)selectedItemIndex {
- NSCollectionView* page = [self collectionViewAtPageIndex:visiblePage_];
- NSUInteger indexOnPage = [[page selectionIndexes] firstIndex];
- if (indexOnPage == NSNotFound)
- return NSNotFound;
-
- return indexOnPage + visiblePage_ * kItemsPerPage;
-}
-
-- (NSButton*)selectedButton {
- NSUInteger index = [self selectedItemIndex];
- if (index == NSNotFound)
- return nil;
-
- return [[self itemAtIndex:index] button];
-}
-
-- (NSScrollView*)gridScrollView {
- return base::mac::ObjCCastStrict<NSScrollView>([self view]);
-}
-
-- (NSView*)pagesContainerView {
- return [[self gridScrollView] documentView];
-}
-
-- (void)updatePages:(size_t)startItemIndex {
- // Note there is always at least one page.
- size_t targetPages = 1;
- if ([items_ count] != 0)
- targetPages = ([items_ count] - 1) / kItemsPerPage + 1;
-
- const size_t currentPages = [self pageCount];
- // First see if the number of pages have changed.
- if (targetPages != currentPages) {
- if (targetPages < currentPages) {
- // Pages need to be removed.
- [pages_ removeObjectsInRange:NSMakeRange(targetPages,
- currentPages - targetPages)];
- } else {
- // Pages need to be added.
- for (size_t i = currentPages; i < targetPages; ++i) {
- NSRect pageFrame = NSMakeRect(
- kLeftRightPadding + kViewWidth * i, 0,
- kViewWidth, kViewHeight);
- [pages_ addObject:[dragManager_ makePageWithFrame:pageFrame]];
- }
- }
-
- [[self pagesContainerView] setSubviews:pages_];
- NSSize pagesSize = NSMakeSize(kViewWidth * targetPages, kViewHeight);
- [[self pagesContainerView] setFrameSize:pagesSize];
- [paginationObserver_ totalPagesChanged];
- }
-
- const size_t startPage = startItemIndex / kItemsPerPage;
- // All pages on or after |startPage| may need items added or removed.
- for (size_t pageIndex = startPage; pageIndex < targetPages; ++pageIndex) {
- [self updatePageContent:pageIndex
- resetModel:YES];
- }
-}
-
-- (void)updatePageContent:(size_t)pageIndex
- resetModel:(BOOL)resetModel {
- NSCollectionView* pageView = [self collectionViewAtPageIndex:pageIndex];
- if (resetModel) {
- // Clear the models first, otherwise removed items could be autoreleased at
- // an unknown point in the future, when the model owner may have gone away.
- for (size_t i = 0; i < [[pageView content] count]; ++i) {
- AppsGridViewItem* item = base::mac::ObjCCastStrict<AppsGridViewItem>(
- [pageView itemAtIndex:i]);
- [item setModel:NULL];
- }
- }
-
- NSRange inPageRange = NSIntersectionRange(
- NSMakeRange(pageIndex * kItemsPerPage, kItemsPerPage),
- NSMakeRange(0, [items_ count]));
- NSArray* pageContent = [items_ subarrayWithRange:inPageRange];
- [pageView setContent:pageContent];
- if (!resetModel)
- return;
-
- for (size_t i = 0; i < [pageContent count]; ++i) {
- AppsGridViewItem* item = base::mac::ObjCCastStrict<AppsGridViewItem>(
- [pageView itemAtIndex:i]);
- [item setModel:static_cast<app_list::AppListItemModel*>(
- [[pageContent objectAtIndex:i] pointerValue])];
- }
-}
-
-- (void)moveItemInView:(size_t)fromIndex
- toItemIndex:(size_t)toIndex {
- base::scoped_nsobject<NSValue> item(
- [[items_ objectAtIndex:fromIndex] retain]);
- [items_ removeObjectAtIndex:fromIndex];
- [items_ insertObject:item
- atIndex:toIndex];
-
- size_t fromPageIndex = fromIndex / kItemsPerPage;
- size_t toPageIndex = toIndex / kItemsPerPage;
- if (fromPageIndex == toPageIndex) {
- [self updatePageContent:fromPageIndex
- resetModel:NO]; // Just reorder items.
- return;
- }
-
- if (fromPageIndex > toPageIndex)
- std::swap(fromPageIndex, toPageIndex);
-
- for (size_t i = fromPageIndex; i <= toPageIndex; ++i) {
- [self updatePageContent:i
- resetModel:YES];
- }
-}
-
-// Compare with views implementation in AppsGridView::MoveItemInModel().
-- (void)moveItemWithIndex:(size_t)itemIndex
- toModelIndex:(size_t)modelIndex {
- // Ingore no-op moves. Note that this is always the case when canceled.
- if (itemIndex == modelIndex)
- return;
-
- app_list::AppListItemList* itemList = [self model]->item_list();
- itemList->RemoveObserver(bridge_.get());
- itemList->MoveItem(itemIndex, modelIndex);
- itemList->AddObserver(bridge_.get());
-}
-
-- (AppsCollectionViewDragManager*)dragManager {
- return dragManager_;
-}
-
-- (size_t)scheduledScrollPage {
- return scheduledScrollPage_;
-}
-
-- (void)listItemAdded:(size_t)index
- item:(app_list::AppListItemModel*)itemModel {
- // Cancel any drag, to ensure the model stays consistent.
- [dragManager_ cancelDrag];
-
- [items_ insertObject:[NSValue valueWithPointer:itemModel]
- atIndex:index];
-
- [self updatePages:index];
-}
-
-- (void)listItemRemoved:(size_t)index {
- [dragManager_ cancelDrag];
-
- // Clear the models explicitly to avoid surprises from autorelease.
- [[self itemAtIndex:index] setModel:NULL];
-
- [items_ removeObjectsInRange:NSMakeRange(index, 1)];
- [self updatePages:index];
-}
-
-- (void)listItemMovedFromIndex:(size_t)fromIndex
- toModelIndex:(size_t)toIndex {
- [dragManager_ cancelDrag];
- [self moveItemInView:fromIndex
- toItemIndex:toIndex];
-}
-
-- (CGFloat)visiblePortionOfPage:(int)page {
- CGFloat scrollOffsetOfPage =
- NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth - page;
- if (scrollOffsetOfPage <= -1.0 || scrollOffsetOfPage >= 1.0)
- return 0.0;
-
- if (scrollOffsetOfPage <= 0.0)
- return scrollOffsetOfPage + 1.0;
-
- return -1.0 + scrollOffsetOfPage;
-}
-
-- (void)onPagerClicked:(AppListPagerView*)sender {
- int selectedSegment = [sender selectedSegment];
- if (selectedSegment < 0)
- return; // No selection.
-
- int pageIndex = [[sender cell] tagForSegment:selectedSegment];
- if (pageIndex >= 0)
- [self scrollToPage:pageIndex];
-}
-
-- (BOOL)moveSelectionByDelta:(int)indexDelta {
- if (indexDelta == 0)
- return NO;
-
- NSUInteger oldIndex = [self selectedItemIndex];
-
- // If nothing is currently selected, select the first item on the page.
- if (oldIndex == NSNotFound) {
- [self selectItemAtIndex:visiblePage_ * kItemsPerPage];
- return YES;
- }
-
- // Can't select a negative index.
- if (indexDelta < 0 && static_cast<NSUInteger>(-indexDelta) > oldIndex)
- return NO;
-
- // Can't select an index greater or equal to the number of items.
- if (oldIndex + indexDelta >= [items_ count]) {
- if (visiblePage_ == [pages_ count] - 1)
- return NO;
-
- // If we're not on the last page, then select the last item.
- [self selectItemAtIndex:[items_ count] - 1];
- return YES;
- }
-
- [self selectItemAtIndex:oldIndex + indexDelta];
- return YES;
-}
-
-- (void)selectItemAtIndex:(NSUInteger)index {
- if (index >= [items_ count])
- return;
-
- if (index / kItemsPerPage != visiblePage_)
- [self scrollToPage:index / kItemsPerPage];
-
- [[self itemAtIndex:index] setSelected:YES];
-}
-
-- (BOOL)handleCommandBySelector:(SEL)command {
- if (command == @selector(insertNewline:) ||
- command == @selector(insertLineBreak:)) {
- [self activateSelection];
- return YES;
- }
-
- NSUInteger oldIndex = [self selectedItemIndex];
- // If nothing is currently selected, select the first item on the page.
- if (oldIndex == NSNotFound) {
- [self selectItemAtIndex:visiblePage_ * kItemsPerPage];
- return YES;
- }
-
- if (command == @selector(moveLeft:)) {
- return oldIndex % kFixedColumns == 0 ?
- [self moveSelectionByDelta:-kItemsPerPage + kFixedColumns - 1] :
- [self moveSelectionByDelta:-1];
- }
-
- if (command == @selector(moveRight:)) {
- return oldIndex % kFixedColumns == kFixedColumns - 1 ?
- [self moveSelectionByDelta:+kItemsPerPage - kFixedColumns + 1] :
- [self moveSelectionByDelta:1];
- }
-
- if (command == @selector(moveUp:)) {
- return oldIndex / kFixedColumns % kFixedRows == 0 ?
- NO : [self moveSelectionByDelta:-kFixedColumns];
- }
-
- if (command == @selector(moveDown:)) {
- return oldIndex / kFixedColumns % kFixedRows == kFixedRows - 1 ?
- NO : [self moveSelectionByDelta:kFixedColumns];
- }
-
- if (command == @selector(pageUp:) ||
- command == @selector(scrollPageUp:))
- return [self moveSelectionByDelta:-kItemsPerPage];
-
- if (command == @selector(pageDown:) ||
- command == @selector(scrollPageDown:))
- return [self moveSelectionByDelta:kItemsPerPage];
-
- return NO;
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/chromium/ui/app_list/cocoa/apps_grid_controller_unittest.mm
deleted file mode 100644
index 5969b203a1b..00000000000
--- a/chromium/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ /dev/null
@@ -1,989 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/utf_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item_model.h"
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#include "ui/base/models/simple_menu_model.h"
-#import "ui/base/test/cocoa_test_event_utils.h"
-
-@interface TestPaginationObserver : NSObject<AppsPaginationModelObserver> {
- @private
- NSInteger hoveredSegmentForTest_;
- int totalPagesChangedCount_;
- int selectedPageChangedCount_;
- int lastNewSelectedPage_;
- bool visibilityDidChange_;
-}
-
-@property(assign, nonatomic) NSInteger hoveredSegmentForTest;
-@property(assign, nonatomic) int totalPagesChangedCount;
-@property(assign, nonatomic) int selectedPageChangedCount;
-@property(assign, nonatomic) int lastNewSelectedPage;
-
-- (bool)readVisibilityDidChange;
-
-@end
-
-@implementation TestPaginationObserver
-
-@synthesize hoveredSegmentForTest = hoveredSegmentForTest_;
-@synthesize totalPagesChangedCount = totalPagesChangedCount_;
-@synthesize selectedPageChangedCount = selectedPageChangedCount_;
-@synthesize lastNewSelectedPage = lastNewSelectedPage_;
-
-- (id)init {
- if ((self = [super init]))
- hoveredSegmentForTest_ = -1;
-
- return self;
-}
-
-- (bool)readVisibilityDidChange {
- bool truth = visibilityDidChange_;
- visibilityDidChange_ = false;
- return truth;
-}
-
-- (void)totalPagesChanged {
- ++totalPagesChangedCount_;
-}
-
-- (void)selectedPageChanged:(int)newSelected {
- ++selectedPageChangedCount_;
- lastNewSelectedPage_ = newSelected;
-}
-
-- (void)pageVisibilityChanged {
- visibilityDidChange_ = true;
-}
-
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
- return hoveredSegmentForTest_;
-}
-
-@end
-
-namespace app_list {
-namespace test {
-
-namespace {
-
-class AppsGridControllerTest : public AppsGridControllerTestHelper {
- public:
- AppsGridControllerTest() {}
-
- AppListTestViewDelegate* delegate() {
- return owned_delegate_.get();
- }
-
- NSColor* ButtonTitleColorAt(size_t index) {
- NSDictionary* attributes =
- [[[GetItemViewAt(index) cell] attributedTitle] attributesAtIndex:0
- effectiveRange:NULL];
- return [attributes objectForKey:NSForegroundColorAttributeName];
- }
-
- virtual void SetUp() OVERRIDE {
- owned_apps_grid_controller_.reset([[AppsGridController alloc] init]);
- owned_delegate_.reset(new AppListTestViewDelegate);
- [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
- AppsGridControllerTestHelper::SetUpWithGridController(
- owned_apps_grid_controller_.get());
-
- [[test_window() contentView] addSubview:[apps_grid_controller_ view]];
- [test_window() makePretendKeyWindowAndSetFirstResponder:
- [apps_grid_controller_ collectionViewAtPageIndex:0]];
- }
-
- virtual void TearDown() OVERRIDE {
- [owned_apps_grid_controller_ setDelegate:NULL];
- owned_apps_grid_controller_.reset();
- AppsGridControllerTestHelper::TearDown();
- }
-
- void ReplaceTestModel(int item_count) {
- // Clear the delegate before reseting and destroying the model.
- [owned_apps_grid_controller_ setDelegate:NULL];
-
- owned_delegate_->ReplaceTestModel(item_count);
- [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
- }
-
- AppListTestModel* model() { return owned_delegate_->GetTestModel(); }
-
- private:
- base::scoped_nsobject<AppsGridController> owned_apps_grid_controller_;
- scoped_ptr<AppListTestViewDelegate> owned_delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTest);
-};
-
-class AppListItemWithMenu : public AppListItemModel {
- public:
- explicit AppListItemWithMenu(const std::string& title)
- : AppListItemModel(title),
- menu_model_(NULL),
- menu_ready_(true) {
- SetTitleAndFullName(title, title);
- menu_model_.AddItem(0, UTF8ToUTF16("Menu For: " + title));
- }
-
- void SetMenuReadyForTesting(bool ready) {
- menu_ready_ = ready;
- }
-
- virtual ui::MenuModel* GetContextMenuModel() OVERRIDE {
- if (!menu_ready_)
- return NULL;
-
- return &menu_model_;
- }
-
- private:
- ui::SimpleMenuModel menu_model_;
- bool menu_ready_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListItemWithMenu);
-};
-
-// Generate a mouse event at the centre of the view in |page| with the given
-// |index_in_page| that can be used to initiate, update and complete drag
-// operations.
-NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
- NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
- NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
- NSPoint point_in_window = [page convertPoint:point_in_view
- toView:nil];
- return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-NSEvent* MouseEventForScroll(NSView* view, CGFloat relative_x) {
- NSRect view_rect = [view frame];
- NSPoint point_in_view = NSMakePoint(NSMidX(view_rect), NSMidY(view_rect));
- point_in_view.x += point_in_view.x * relative_x;
- NSPoint point_in_window = [view convertPoint:point_in_view
- toView:nil];
- return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-} // namespace
-
-TEST_VIEW(AppsGridControllerTest, [apps_grid_controller_ view]);
-
-// Test showing with an empty model.
-TEST_F(AppsGridControllerTest, EmptyModelAndShow) {
- EXPECT_TRUE([[apps_grid_controller_ view] superview]);
-
- // First page should always exist, even if empty.
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
- EXPECT_TRUE([GetPageAt(0) superview]); // The pages container.
- EXPECT_TRUE([[GetPageAt(0) superview] superview]);
-}
-
-// Test with a single item.
-// This test is disabled in builders until the delay to wait for the collection
-// view to load subviews can be removed, or some other solution is found.
-TEST_F(AppsGridControllerTest, DISABLED_SingleEntryModel) {
- // We need to "wake up" the NSCollectionView, otherwise it does not
- // immediately update its subviews later in this function.
- // When this test is run by itself, it's enough just to send a keypress (and
- // this delay is not needed).
- DelayForCollectionView();
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
-
- model()->PopulateApps(1);
- SinkEvents();
- EXPECT_FALSE([GetPageAt(0) animations]);
-
- EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
- NSArray* subviews = [GetPageAt(0) subviews];
- EXPECT_EQ(1u, [subviews count]);
-
- // Note that using GetItemViewAt(0) here also works, and returns non-nil even
- // without the delay, but a "click" on it does not register without the delay.
- NSView* subview = [subviews objectAtIndex:0];
-
- // Launch the item.
- SimulateClick(subview);
- SinkEvents();
- EXPECT_EQ(1, model()->activate_count());
- ASSERT_TRUE(model()->last_activated());
- EXPECT_EQ(std::string("Item 0"), model()->last_activated()->title());
-}
-
-// Test activating an item on the second page (the 17th item).
-TEST_F(AppsGridControllerTest, DISABLED_TwoPageModel) {
- DelayForCollectionView();
- ReplaceTestModel(kItemsPerPage * 2);
- [apps_grid_controller_ scrollToPage:1];
-
- // The NSScrollView animator ignores the duration configured on the
- // NSAnimationContext (set by CocoaTest::Init), so we need to delay here.
- DelayForCollectionView();
- NSArray* subviews = [GetPageAt(1) subviews];
- NSView* subview = [subviews objectAtIndex:0];
- // Launch the item.
- SimulateClick(subview);
- SinkEvents();
- EXPECT_EQ(1, model()->activate_count());
- ASSERT_TRUE(model()->last_activated());
- EXPECT_EQ(std::string("Item 16"), model()->last_activated()->title());
-}
-
-// Test setModel.
-TEST_F(AppsGridControllerTest, ReplaceModel) {
- const size_t kOrigItems = 1;
- const size_t kNewItems = 2;
-
- model()->PopulateApps(kOrigItems);
- EXPECT_EQ(kOrigItems, [[GetPageAt(0) content] count]);
-
- ReplaceTestModel(kNewItems);
- EXPECT_EQ(kNewItems, [[GetPageAt(0) content] count]);
-}
-
-// Test pagination.
-TEST_F(AppsGridControllerTest, Pagination) {
- model()->PopulateApps(1);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
-
- ReplaceTestModel(kItemsPerPage);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
-
- // Test adding an item onto the next page.
- model()->PopulateApps(1); // Now 17 items.
- EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
- EXPECT_EQ(1u, [[GetPageAt(1) content] count]);
-
- // Test N pages with the last page having one empty spot.
- const size_t kPagesToTest = 3;
- ReplaceTestModel(kPagesToTest * kItemsPerPage - 1);
- EXPECT_EQ(kPagesToTest, [apps_grid_controller_ pageCount]);
- for (size_t page_index = 0; page_index < kPagesToTest - 1; ++page_index) {
- EXPECT_EQ(kItemsPerPage, [[GetPageAt(page_index) content] count]);
- }
- EXPECT_EQ(kItemsPerPage - 1, [[GetPageAt(kPagesToTest - 1) content] count]);
-
- // Test removing pages.
- ReplaceTestModel(1);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
-}
-
-// Tests that selecting an item changes the text color correctly.
-TEST_F(AppsGridControllerTest, SelectionChangesTextColor) {
- model()->PopulateApps(2);
- [apps_grid_controller_ selectItemAtIndex:0];
- EXPECT_NSEQ(ButtonTitleColorAt(0),
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor));
- EXPECT_NSEQ(ButtonTitleColorAt(1),
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor));
-
- [apps_grid_controller_ selectItemAtIndex:1];
- EXPECT_NSEQ(ButtonTitleColorAt(0),
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor));
- EXPECT_NSEQ(ButtonTitleColorAt(1),
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor));
-}
-
-// Tests basic keyboard navigation on the first page.
-TEST_F(AppsGridControllerTest, FirstPageKeyboardNavigation) {
- model()->PopulateApps(kItemsPerPage - 2);
- EXPECT_EQ(kItemsPerPage - 2, [[GetPageAt(0) content] count]);
-
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(1u, [apps_grid_controller_ selectedItemIndex]);
-
- SimulateKeyAction(@selector(moveDown:));
- EXPECT_EQ(5u, [apps_grid_controller_ selectedItemIndex]);
-
- SimulateKeyAction(@selector(moveLeft:));
- EXPECT_EQ(4u, [apps_grid_controller_ selectedItemIndex]);
-
- SimulateKeyAction(@selector(moveUp:));
- EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
- // Go to the third item, and launch it.
- SimulateKeyAction(@selector(moveRight:));
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(2u, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(insertNewline:));
- EXPECT_EQ(1, model()->activate_count());
- ASSERT_TRUE(model()->last_activated());
- EXPECT_EQ(std::string("Item 2"), model()->last_activated()->title());
-}
-
-// Tests keyboard navigation across pages.
-TEST_F(AppsGridControllerTest, CrossPageKeyboardNavigation) {
- model()->PopulateApps(kItemsPerPage + 10);
- EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
- EXPECT_EQ(10u, [[GetPageAt(1) content] count]);
-
- // Moving Left, Up, or PageUp from the top-left corner of the first page does
- // nothing.
- [apps_grid_controller_ selectItemAtIndex:0];
- SimulateKeyAction(@selector(moveLeft:));
- EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(moveUp:));
- EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(scrollPageUp:));
- EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
- // Moving Right from the right side goes to the next page. Moving Left goes
- // back to the first page.
- [apps_grid_controller_ selectItemAtIndex:3];
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(moveLeft:));
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(3u, [apps_grid_controller_ selectedItemIndex]);
-
- // Moving Down from the bottom does nothing.
- [apps_grid_controller_ selectItemAtIndex:13];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- SimulateKeyAction(@selector(moveDown:));
- EXPECT_EQ(13u, [apps_grid_controller_ selectedItemIndex]);
-
- // Moving Right into a non-existent square on the next page will select the
- // last item.
- [apps_grid_controller_ selectItemAtIndex:15];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
- // PageDown and PageUp switches pages while maintaining the same selection
- // position.
- [apps_grid_controller_ selectItemAtIndex:6];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- SimulateKeyAction(@selector(scrollPageDown:));
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(kItemsPerPage + 6, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(scrollPageUp:));
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(6u, [apps_grid_controller_ selectedItemIndex]);
-
- // PageDown into a non-existent square on the next page will select the last
- // item.
- [apps_grid_controller_ selectItemAtIndex:11];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- SimulateKeyAction(@selector(scrollPageDown:));
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
- // Moving Right, Down, or PageDown from the bottom-right corner of the last
- // page (not the last item) does nothing.
- [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 9];
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- SimulateKeyAction(@selector(moveRight:));
- EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(moveDown:));
- EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(scrollPageDown:));
- EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
- // After page switch, arrow keys select first item on current page.
- [apps_grid_controller_ scrollToPage:0];
- [apps_grid_controller_ scrollToPage:1];
- EXPECT_EQ(NSNotFound, [apps_grid_controller_ selectedItemIndex]);
- SimulateKeyAction(@selector(moveUp:));
- EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
-}
-
-// Highlighting an item should cause the page it's on to be visible.
-TEST_F(AppsGridControllerTest, EnsureHighlightedVisible) {
- model()->PopulateApps(3 * kItemsPerPage);
- EXPECT_EQ(kItemsPerPage, [[GetPageAt(2) content] count]);
-
- // First and last items of first page.
- [apps_grid_controller_ selectItemAtIndex:0];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- [apps_grid_controller_ selectItemAtIndex:kItemsPerPage - 1];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
- // First item of second page.
- [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 1];
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
- // Last item in model.
- [apps_grid_controller_ selectItemAtIndex:3 * kItemsPerPage - 1];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-}
-
-// Test runtime updates: adding items, removing items, and moving items (e.g. in
-// response to app install, uninstall, and chrome sync changes. Also test
-// changing titles and icons.
-TEST_F(AppsGridControllerTest, ModelUpdate) {
- model()->PopulateApps(2);
- EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
- EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
- // Add an item (PopulateApps will create a new "Item 2").
- model()->PopulateApps(1);
- EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
- NSButton* button = GetItemViewAt(2);
- EXPECT_NSEQ(@"Item 2", [button title]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
- // Update the title via the ItemModelObserver.
- app_list::AppListItemModel* item_model = model()->item_list()->item_at(2);
- item_model->SetTitleAndFullName("UpdatedItem", "UpdatedItem");
- EXPECT_NSEQ(@"UpdatedItem", [button title]);
- EXPECT_EQ(std::string("|Item 0,Item 1,UpdatedItem|"), GetViewContent());
-
- // Test icon updates through the model observer by ensuring the icon changes.
- NSSize icon_size = [[button image] size];
- EXPECT_EQ(0, icon_size.width);
- EXPECT_EQ(0, icon_size.height);
-
- SkBitmap bitmap;
- const int kTestImageSize = 10;
- const int kTargetImageSize = 48;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, kTestImageSize, kTestImageSize);
- item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), false);
- icon_size = [[button image] size];
- // Icon should always be resized to 48x48.
- EXPECT_EQ(kTargetImageSize, icon_size.width);
- EXPECT_EQ(kTargetImageSize, icon_size.height);
-}
-
-TEST_F(AppsGridControllerTest, ModelAdd) {
- model()->PopulateApps(2);
- EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
- EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
- app_list::AppListItemList* item_list = model()->item_list();
-
- model()->CreateAndAddItem("Item 2");
- ASSERT_EQ(3u, item_list->item_count());
- EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
- // Test adding an item whose position is in the middle.
- app_list::AppListItemModel* item0 = item_list->item_at(0);
- app_list::AppListItemModel* item1 = item_list->item_at(1);
- app_list::AppListItemModel* item3 =
- model()->CreateItem("Item Three", "Item Three");
- item_list->AddItem(item3);
- item_list->SetItemPosition(
- item3, item0->position().CreateBetween(item1->position()));
- EXPECT_EQ(4u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item Three,Item 1,Item 2|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelMove) {
- model()->PopulateApps(3);
- EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
- // Test swapping items (e.g. rearranging via sync).
- model()->item_list()->MoveItem(1, 2);
- EXPECT_EQ(std::string("|Item 0,Item 2,Item 1|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemove) {
- model()->PopulateApps(3);
- EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
- // Test removing an item at the end.
- model()->item_list()->DeleteItem("Item 2");
- EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
- // Test removing in the middle.
- model()->CreateAndAddItem("Item 2");
- EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
- model()->item_list()->DeleteItem("Item 1");
- EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item 2|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemoveAlll) {
- model()->PopulateApps(3);
- EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
- EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
- // Test removing multiple items via the model.
- model()->item_list()->DeleteItemsByType(NULL /* all items */);
- EXPECT_EQ(0u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("||"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemovePage) {
- app_list::AppListItemList* item_list = model()->item_list();
-
- model()->PopulateApps(kItemsPerPage + 1);
- ASSERT_EQ(kItemsPerPage + 1, item_list->item_count());
- EXPECT_EQ(kItemsPerPage + 1, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-
- // Test removing the last item when there is one item on the second page.
- app_list::AppListItemModel* last_item = item_list->item_at(kItemsPerPage);
- item_list->DeleteItem(last_item->id());
- EXPECT_EQ(kItemsPerPage, item_list->item_count());
- EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-}
-
-// Test install progress bars, and install flow with item highlighting.
-TEST_F(AppsGridControllerTest, ItemInstallProgress) {
- ReplaceTestModel(kItemsPerPage + 1);
- EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- app_list::AppListItemModel* item_model =
- model()->item_list()->item_at(kItemsPerPage);
-
- // Highlighting an item should activate the page it is on.
- item_model->SetHighlighted(true);
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
- // Clearing a highlight stays on the current page.
- [apps_grid_controller_ scrollToPage:0];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- item_model->SetHighlighted(false);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
- // Starting install should add a progress bar, and temporarily clear the
- // button title.
- NSButton* button = GetItemViewAt(kItemsPerPage);
- NSView* containerView = [button superview];
- EXPECT_EQ(1u, [[containerView subviews] count]);
- EXPECT_NSEQ(@"Item 16", [button title]);
- item_model->SetHighlighted(true);
- item_model->SetIsInstalling(true);
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
- EXPECT_EQ(2u, [[containerView subviews] count]);
- EXPECT_NSEQ(@"", [button title]);
- NSProgressIndicator* progressIndicator =
- [[containerView subviews] objectAtIndex:1];
- EXPECT_FALSE([progressIndicator isIndeterminate]);
- EXPECT_EQ(0.0, [progressIndicator doubleValue]);
-
- // Updating the progress in the model should update the progress bar.
- item_model->SetPercentDownloaded(50);
- EXPECT_EQ(50.0, [progressIndicator doubleValue]);
-
- // Two things can be installing simultaneously. When one starts or completes
- // the model builder will ask for the item to be highlighted.
- app_list::AppListItemModel* alternate_item_model =
- model()->item_list()->item_at(0);
- item_model->SetHighlighted(false);
- alternate_item_model->SetHighlighted(true);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
- // Update the first item (page doesn't change on updates).
- item_model->SetPercentDownloaded(100);
- EXPECT_EQ(100.0, [progressIndicator doubleValue]);
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
- // A percent of -1 indicates the download is complete and the unpack/install
- // process has started.
- item_model->SetPercentDownloaded(-1);
- EXPECT_TRUE([progressIndicator isIndeterminate]);
-
- // Completing install removes the progress bar, and restores the title.
- // ExtensionAppModelBuilder will reload the ExtensionAppItem, which also
- // highlights. Do the same here.
- alternate_item_model->SetHighlighted(false);
- item_model->SetHighlighted(true);
- item_model->SetIsInstalling(false);
- EXPECT_EQ(1u, [[containerView subviews] count]);
- EXPECT_NSEQ(@"Item 16", [button title]);
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
- // Things should cleanup OK with |alternate_item_model| left installing.
-}
-
-// Test mouseover selection.
-TEST_F(AppsGridControllerTest, MouseoverSelects) {
- model()->PopulateApps(2);
- EXPECT_EQ(nil, GetSelectedView());
-
- // Test entering and exiting the first item.
- SimulateMouseEnterItemAt(0);
- EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
- SimulateMouseExitItemAt(0);
- EXPECT_EQ(nil, GetSelectedView());
-
- // AppKit doesn't guarantee the order, so test moving between items.
- SimulateMouseEnterItemAt(0);
- EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
- SimulateMouseEnterItemAt(1);
- EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
- SimulateMouseExitItemAt(0);
- EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
- SimulateMouseExitItemAt(1);
- EXPECT_EQ(nil, GetSelectedView());
-}
-
-// Test AppsGridPaginationObserver totalPagesChanged().
-TEST_F(AppsGridControllerTest, PaginationObserverPagesChanged) {
- base::scoped_nsobject<TestPaginationObserver> observer(
- [[TestPaginationObserver alloc] init]);
- [apps_grid_controller_ setPaginationObserver:observer];
-
- // Test totalPagesChanged.
- model()->PopulateApps(kItemsPerPage);
- EXPECT_EQ(0, [observer totalPagesChangedCount]);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- model()->PopulateApps(1);
- EXPECT_EQ(1, [observer totalPagesChangedCount]);
- EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
- ReplaceTestModel(0);
- EXPECT_EQ(2, [observer totalPagesChangedCount]);
- EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
- ReplaceTestModel(kItemsPerPage * 3 + 1);
- EXPECT_EQ(3, [observer totalPagesChangedCount]);
- EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
-
- EXPECT_FALSE([observer readVisibilityDidChange]);
- EXPECT_EQ(0, [observer selectedPageChangedCount]);
-
- [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-// Test AppsGridPaginationObserver selectedPageChanged().
-TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
- base::scoped_nsobject<TestPaginationObserver> observer(
- [[TestPaginationObserver alloc] init]);
- [apps_grid_controller_ setPaginationObserver:observer];
- EXPECT_EQ(0, [[NSAnimationContext currentContext] duration]);
-
- ReplaceTestModel(kItemsPerPage * 3 + 1);
- EXPECT_EQ(1, [observer totalPagesChangedCount]);
- EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
-
- EXPECT_FALSE([observer readVisibilityDidChange]);
- EXPECT_EQ(0, [observer selectedPageChangedCount]);
-
- [apps_grid_controller_ scrollToPage:1];
- EXPECT_EQ(1, [observer selectedPageChangedCount]);
- EXPECT_EQ(1, [observer lastNewSelectedPage]);
- EXPECT_TRUE([observer readVisibilityDidChange]);
- EXPECT_FALSE([observer readVisibilityDidChange]); // Testing test behaviour.
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:1]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:2]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:3]);
-
- [apps_grid_controller_ scrollToPage:0];
- EXPECT_EQ(2, [observer selectedPageChangedCount]);
- EXPECT_EQ(0, [observer lastNewSelectedPage]);
- EXPECT_TRUE([observer readVisibilityDidChange]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
- [apps_grid_controller_ scrollToPage:3];
- // Note: with no animations, there is only a single page change. However, with
- // animations we expect multiple updates depending on the rate that the scroll
- // view updates and sends out NSViewBoundsDidChangeNotification.
- EXPECT_EQ(3, [observer selectedPageChangedCount]);
- EXPECT_EQ(3, [observer lastNewSelectedPage]);
- EXPECT_TRUE([observer readVisibilityDidChange]);
- EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
- EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:3]);
-
- [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-// Test basic item moves with two items; swapping them around, dragging outside
-// of the view bounds, and dragging on the background.
-TEST_F(AppsGridControllerTest, DragAndDropSimple) {
- model()->PopulateApps(2);
- NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
- NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
- NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
- NSEvent* mouse_at_page_centre = MouseEventInCell(page, 6);
- NSEvent* mouse_off_page = MouseEventInCell(page, kItemsPerPage * 2);
-
- const std::string kOrdered = "Item 0,Item 1";
- const std::string kSwapped = "Item 1,Item 0";
- const std::string kOrderedView = "|Item 0,Item 1|";
- const std::string kSwappedView = "|Item 1,Item 0|";
-
- EXPECT_EQ(kOrdered, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
- AppsCollectionViewDragManager* drag_manager =
- [apps_grid_controller_ dragManager];
-
- // Drag first item over the second item and release.
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_0];
- [drag_manager onMouseDragged:mouse_at_cell_1];
- EXPECT_EQ(kOrdered, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent()); // View swaps first.
- [drag_manager onMouseUp:mouse_at_cell_1];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
-
- // Drag item back.
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_1];
- [drag_manager onMouseDragged:mouse_at_cell_0];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
- [drag_manager onMouseUp:mouse_at_cell_0];
- EXPECT_EQ(kOrdered, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
-
- // Drag first item to centre of view (should put in last place).
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_0];
- [drag_manager onMouseDragged:mouse_at_page_centre];
- EXPECT_EQ(kOrdered, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
- [drag_manager onMouseUp:mouse_at_page_centre];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
-
- // Drag item to centre again (should leave it in the last place).
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_1];
- [drag_manager onMouseDragged:mouse_at_page_centre];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
- [drag_manager onMouseUp:mouse_at_page_centre];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
-
- // Drag starting in the centre of the view, should do nothing.
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_page_centre];
- [drag_manager onMouseDragged:mouse_at_cell_0];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
- [drag_manager onMouseUp:mouse_at_cell_0];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
-
- // Click off page.
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_off_page];
- [drag_manager onMouseDragged:mouse_at_cell_0];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
- [drag_manager onMouseUp:mouse_at_cell_0];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kSwappedView, GetViewContent());
-
- // Drag to first over second item, then off page.
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_0];
- [drag_manager onMouseDragged:mouse_at_cell_1];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
- [drag_manager onMouseDragged:mouse_off_page];
- EXPECT_EQ(kSwapped, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
- [drag_manager onMouseUp:mouse_off_page];
- EXPECT_EQ(kOrdered, model()->GetModelContent());
- EXPECT_EQ(kOrderedView, GetViewContent());
-
- // Replace with an empty model, and ensure we do not break.
- ReplaceTestModel(0);
- EXPECT_EQ(std::string(), model()->GetModelContent());
- EXPECT_EQ(std::string("||"), GetViewContent());
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_0];
- [drag_manager onMouseDragged:mouse_at_cell_1];
- [drag_manager onMouseUp:mouse_at_cell_1];
- EXPECT_EQ(std::string(), model()->GetModelContent());
- EXPECT_EQ(std::string("||"), GetViewContent());
-}
-
-// Test item moves between pages.
-TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
- const size_t kPagesToTest = 3;
- // Put one item on the last page to hit more edge cases.
- ReplaceTestModel(kItemsPerPage * (kPagesToTest - 1) + 1);
- NSCollectionView* page[kPagesToTest];
- for (size_t i = 0; i < kPagesToTest; ++i)
- page[i] = [apps_grid_controller_ collectionViewAtPageIndex:i];
-
- const std::string kSecondItemMovedToSecondPage =
- "|Item 0,Item 2,Item 3,Item 4,Item 5,Item 6,Item 7,Item 8,"
- "Item 9,Item 10,Item 11,Item 12,Item 13,Item 14,Item 15,Item 16|"
- "|Item 17,Item 1,Item 18,Item 19,Item 20,Item 21,Item 22,Item 23,"
- "Item 24,Item 25,Item 26,Item 27,Item 28,Item 29,Item 30,Item 31|"
- "|Item 32|";
-
- NSEvent* mouse_at_cell_0 = MouseEventInCell(page[0], 0);
- NSEvent* mouse_at_cell_1 = MouseEventInCell(page[0], 1);
- AppsCollectionViewDragManager* drag_manager =
- [apps_grid_controller_ dragManager];
- [drag_manager onMouseDownInPage:page[0]
- withEvent:mouse_at_cell_1];
-
- // Initiate dragging before changing pages.
- [drag_manager onMouseDragged:mouse_at_cell_0];
-
- // Scroll to the second page.
- [apps_grid_controller_ scrollToPage:1];
- [drag_manager onMouseDragged:mouse_at_cell_1];
-
- // Do one exhaustive check, and then spot-check corner cases.
- EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
- EXPECT_EQ(0u, GetPageIndexForItem(0));
- EXPECT_EQ(1u, GetPageIndexForItem(1));
- EXPECT_EQ(0u, GetPageIndexForItem(2));
- EXPECT_EQ(0u, GetPageIndexForItem(16));
- EXPECT_EQ(1u, GetPageIndexForItem(17));
- EXPECT_EQ(1u, GetPageIndexForItem(31));
- EXPECT_EQ(2u, GetPageIndexForItem(32));
-
- // Scroll to the third page and drag some more.
- [apps_grid_controller_ scrollToPage:2];
- [drag_manager onMouseDragged:mouse_at_cell_1];
- EXPECT_EQ(2u, GetPageIndexForItem(1));
- EXPECT_EQ(1u, GetPageIndexForItem(31));
- EXPECT_EQ(1u, GetPageIndexForItem(32));
-
- // Scroll backwards.
- [apps_grid_controller_ scrollToPage:1];
- [drag_manager onMouseDragged:mouse_at_cell_1];
- EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
- EXPECT_EQ(1u, GetPageIndexForItem(1));
- EXPECT_EQ(1u, GetPageIndexForItem(31));
- EXPECT_EQ(2u, GetPageIndexForItem(32));
-
- // Simulate installing an item while dragging (or have it appear during sync).
- model()->PopulateAppWithId(33);
- // Item should go back to its position before the drag.
- EXPECT_EQ(0u, GetPageIndexForItem(1));
- EXPECT_EQ(1u, GetPageIndexForItem(31));
- EXPECT_EQ(2u, GetPageIndexForItem(32));
- // New item should appear at end.
- EXPECT_EQ(2u, GetPageIndexForItem(33));
-
- // Scroll to end again, and keep dragging (should be ignored).
- [apps_grid_controller_ scrollToPage:2];
- [drag_manager onMouseDragged:mouse_at_cell_0];
- EXPECT_EQ(0u, GetPageIndexForItem(1));
- [drag_manager onMouseUp:mouse_at_cell_0];
- EXPECT_EQ(0u, GetPageIndexForItem(1));
-}
-
-// Test scrolling when dragging past edge or over the pager.
-TEST_F(AppsGridControllerTest, ScrollingWhileDragging) {
- base::scoped_nsobject<TestPaginationObserver> observer(
- [[TestPaginationObserver alloc] init]);
- [apps_grid_controller_ setPaginationObserver:observer];
-
- ReplaceTestModel(kItemsPerPage * 3);
- // Start on the middle page.
- [apps_grid_controller_ scrollToPage:1];
- NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:1];
- NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
-
- NSEvent* at_center = MouseEventForScroll([apps_grid_controller_ view], 0.0);
- NSEvent* at_left = MouseEventForScroll([apps_grid_controller_ view], -1.1);
- NSEvent* at_right = MouseEventForScroll([apps_grid_controller_ view], 1.1);
-
- AppsCollectionViewDragManager* drag_manager =
- [apps_grid_controller_ dragManager];
- [drag_manager onMouseDownInPage:page
- withEvent:mouse_at_cell_0];
- [drag_manager onMouseDragged:at_center];
-
- // Nothing should be scheduled: target page is visible page.
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
-
- // Drag to the left, should go to first page and no further.
- [drag_manager onMouseDragged:at_left];
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
- [apps_grid_controller_ scrollToPage:0]; // Commit without timer for testing.
- [drag_manager onMouseDragged:at_left];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
-
- // Drag to the right, should go to last page and no futher.
- [drag_manager onMouseDragged:at_right];
- EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
- [apps_grid_controller_ scrollToPage:1];
- [drag_manager onMouseDragged:at_right];
- EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
- [apps_grid_controller_ scrollToPage:2];
- [drag_manager onMouseDragged:at_right];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
- // Simulate a hover over the first pager segment.
- [observer setHoveredSegmentForTest:0];
- [drag_manager onMouseDragged:at_center];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
-
- // Drag it back, should cancel schedule.
- [observer setHoveredSegmentForTest:-1];
- [drag_manager onMouseDragged:at_center];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
- // Hover again, now over middle segment, and ensure a release also cancels.
- [observer setHoveredSegmentForTest:1];
- [drag_manager onMouseDragged:at_center];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
- [drag_manager onMouseUp:at_center];
- EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
- EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
- [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-TEST_F(AppsGridControllerTest, ContextMenus) {
- AppListItemWithMenu* item_two_model = new AppListItemWithMenu("Item Two");
- model()->item_list()->AddItem(new AppListItemWithMenu("Item One"));
- model()->item_list()->AddItem(item_two_model);
- EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
-
- NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
- NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
- NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
-
- NSMenu* menu = [page menuForEvent:mouse_at_cell_0];
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"Menu For: Item One", [[menu itemAtIndex:0] title]);
-
- // Test a context menu request while the item is still installing.
- item_two_model->SetMenuReadyForTesting(false);
- menu = [page menuForEvent:mouse_at_cell_1];
- EXPECT_EQ(nil, menu);
-
- item_two_model->SetMenuReadyForTesting(true);
- menu = [page menuForEvent:mouse_at_cell_1];
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"Menu For: Item Two", [[menu itemAtIndex:0] title]);
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/cocoa/apps_grid_view_item.h b/chromium/ui/app_list/cocoa/apps_grid_view_item.h
deleted file mode 100644
index b42eec18761..00000000000
--- a/chromium/ui/app_list/cocoa/apps_grid_view_item.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
-#define UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_export.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-namespace app_list {
-class AppListItemModel;
-class ItemModelObserverBridge;
-}
-
-// AppsGridViewItem is the controller for an NSButton representing an app item
-// on an NSCollectionView controlled by an AppsGridController.
-APP_LIST_EXPORT
-@interface AppsGridViewItem : NSCollectionViewItem {
- @private
- scoped_ptr<app_list::ItemModelObserverBridge> observerBridge_;
- base::scoped_nsobject<NSProgressIndicator> progressIndicator_;
-
- // Used to highlight the background on hover.
- ui::ScopedCrTrackingArea trackingArea_;
-}
-
-@property(readonly, nonatomic) NSProgressIndicator* progressIndicator;
-
-// Designated initializer. |tileSize| is the size of tiles in the grid.
-- (id)initWithSize:(NSSize)tileSize;
-
-// Set the represented model, updating views. Clears if |itemModel| is NULL.
-- (void)setModel:(app_list::AppListItemModel*)itemModel;
-
-// Model accessor, via the |observerBridge_|.
-- (app_list::AppListItemModel*)model;
-
-// Return the button portion of the item, showing the icon and title.
-- (NSButton*)button;
-
-// Generate and return a context menu, populated using the represented model.
-- (NSMenu*)contextMenu;
-
-// Take a snapshot of the grid cell with correct layout, then hide the button.
-// If |isRestore| is true, the snapshot includes the label and items hidden for
-// the initial snapshot are restored.
-- (NSBitmapImageRep*)dragRepresentationForRestore:(BOOL)isRestore;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
diff --git a/chromium/ui/app_list/cocoa/apps_grid_view_item.mm b/chromium/ui/app_list/cocoa/apps_grid_view_item.mm
deleted file mode 100644
index 08304da155c..00000000000
--- a/chromium/ui/app_list/cocoa/apps_grid_view_item.mm
+++ /dev/null
@@ -1,468 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_item_model_observer.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/base/cocoa/menu_controller.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-// Padding from the top of the tile to the top of the app icon.
-const CGFloat kTileTopPadding = 10;
-
-const CGFloat kIconSize = 48;
-
-const CGFloat kProgressBarHorizontalPadding = 8;
-const CGFloat kProgressBarVerticalPadding = 13;
-
-// On Mac, fonts of the same enum from ResourceBundle are larger. The smallest
-// enum is already used, so it needs to be reduced further to match Windows.
-const int kMacFontSizeDelta = -1;
-
-} // namespace
-
-@class AppsGridItemBackgroundView;
-
-@interface AppsGridViewItem ()
-
-// Typed accessor for the root view.
-- (AppsGridItemBackgroundView*)itemBackgroundView;
-
-// Bridged methods from app_list::AppListItemModelObserver:
-// Update the title, correctly setting the color if the button is highlighted.
-- (void)updateButtonTitle;
-
-// Update the button image after ensuring its dimensions are |kIconSize|.
-- (void)updateButtonImage;
-
-// Ensure the page this item is on is the visible page in the grid.
-- (void)ensureVisible;
-
-// Add or remove a progress bar from the view.
-- (void)setItemIsInstalling:(BOOL)isInstalling;
-
-// Update the progress bar to represent |percent|, or make it indeterminate if
-// |percent| is -1, when unpacking begins.
-- (void)setPercentDownloaded:(int)percent;
-
-@end
-
-namespace app_list {
-
-class ItemModelObserverBridge : public app_list::AppListItemModelObserver {
- public:
- ItemModelObserverBridge(AppsGridViewItem* parent, AppListItemModel* model);
- virtual ~ItemModelObserverBridge();
-
- AppListItemModel* model() { return model_; }
- NSMenu* GetContextMenu();
-
- virtual void ItemIconChanged() OVERRIDE;
- virtual void ItemTitleChanged() OVERRIDE;
- virtual void ItemHighlightedChanged() OVERRIDE;
- virtual void ItemIsInstallingChanged() OVERRIDE;
- virtual void ItemPercentDownloadedChanged() OVERRIDE;
-
- private:
- AppsGridViewItem* parent_; // Weak. Owns us.
- AppListItemModel* model_; // Weak. Owned by AppListModel.
- base::scoped_nsobject<MenuController> context_menu_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(ItemModelObserverBridge);
-};
-
-ItemModelObserverBridge::ItemModelObserverBridge(AppsGridViewItem* parent,
- AppListItemModel* model)
- : parent_(parent),
- model_(model) {
- model_->AddObserver(this);
-}
-
-ItemModelObserverBridge::~ItemModelObserverBridge() {
- model_->RemoveObserver(this);
-}
-
-NSMenu* ItemModelObserverBridge::GetContextMenu() {
- if (!context_menu_controller_) {
- ui::MenuModel* menu_model = model_->GetContextMenuModel();
- if (!menu_model)
- return nil;
-
- context_menu_controller_.reset(
- [[MenuController alloc] initWithModel:menu_model
- useWithPopUpButtonCell:NO]);
- }
- return [context_menu_controller_ menu];
-}
-
-void ItemModelObserverBridge::ItemIconChanged() {
- [parent_ updateButtonImage];
-}
-
-void ItemModelObserverBridge::ItemTitleChanged() {
- [parent_ updateButtonTitle];
-}
-
-void ItemModelObserverBridge::ItemHighlightedChanged() {
- if (model_->highlighted())
- [parent_ ensureVisible];
-}
-
-void ItemModelObserverBridge::ItemIsInstallingChanged() {
- [parent_ setItemIsInstalling:model_->is_installing()];
-}
-
-void ItemModelObserverBridge::ItemPercentDownloadedChanged() {
- [parent_ setPercentDownloaded:model_->percent_downloaded()];
-}
-
-} // namespace app_list
-
-// Container for an NSButton to allow proper alignment of the icon in the apps
-// grid, and to draw with a highlight when selected.
-@interface AppsGridItemBackgroundView : NSView {
- @private
- BOOL selected_;
-}
-
-- (NSButton*)button;
-
-- (void)setSelected:(BOOL)flag;
-
-@end
-
-@interface AppsGridItemButtonCell : NSButtonCell {
- @private
- BOOL hasShadow_;
-}
-
-@property(assign, nonatomic) BOOL hasShadow;
-
-@end
-
-@interface AppsGridItemButton : NSButton;
-@end
-
-@implementation AppsGridItemBackgroundView
-
-- (NSButton*)button {
- // These views are part of a prototype NSCollectionViewItem, copied with an
- // NSCoder. Rather than encoding additional members, the following relies on
- // the button always being the first item added to AppsGridItemBackgroundView.
- return base::mac::ObjCCastStrict<NSButton>([[self subviews] objectAtIndex:0]);
-}
-
-- (void)setSelected:(BOOL)flag {
- DCHECK(selected_ != flag);
- selected_ = flag;
- [self setNeedsDisplay:YES];
-}
-
-// Ignore all hit tests. The grid controller needs to be the owner of any drags.
-- (NSView*)hitTest:(NSPoint)aPoint {
- return nil;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- if (!selected_)
- return;
-
- [gfx::SkColorToSRGBNSColor(app_list::kSelectedColor) set];
- NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- [[[self button] cell] setHighlighted:YES];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- BOOL isInView = [self mouse:pointInView inRect:[self bounds]];
- [[[self button] cell] setHighlighted:isInView];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- if (![self mouse:pointInView inRect:[self bounds]])
- return;
-
- [[self button] performClick:self];
-}
-
-@end
-
-@implementation AppsGridViewItem
-
-- (id)initWithSize:(NSSize)tileSize {
- if ((self = [super init])) {
- base::scoped_nsobject<AppsGridItemButton> prototypeButton(
- [[AppsGridItemButton alloc] initWithFrame:NSMakeRect(
- 0, 0, tileSize.width, tileSize.height - kTileTopPadding)]);
-
- // This NSButton style always positions the icon at the very top of the
- // button frame. AppsGridViewItem uses an enclosing view so that it is
- // visually correct.
- [prototypeButton setImagePosition:NSImageAbove];
- [prototypeButton setButtonType:NSMomentaryChangeButton];
- [prototypeButton setBordered:NO];
-
- base::scoped_nsobject<AppsGridItemBackgroundView> prototypeButtonBackground(
- [[AppsGridItemBackgroundView alloc]
- initWithFrame:NSMakeRect(0, 0, tileSize.width, tileSize.height)]);
- [prototypeButtonBackground addSubview:prototypeButton];
- [self setView:prototypeButtonBackground];
- }
- return self;
-}
-
-- (NSProgressIndicator*)progressIndicator {
- return progressIndicator_;
-}
-
-- (void)updateButtonTitle {
- if (progressIndicator_)
- return;
-
- base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
- [[NSMutableParagraphStyle alloc] init]);
- [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
- [paragraphStyle setAlignment:NSCenterTextAlignment];
- NSDictionary* titleAttributes = @{
- NSParagraphStyleAttributeName : paragraphStyle,
- NSFontAttributeName : ui::ResourceBundle::GetSharedInstance()
- .GetFont(app_list::kItemTextFontStyle)
- .DeriveFont(kMacFontSizeDelta)
- .GetNativeFont(),
- NSForegroundColorAttributeName : [self isSelected] ?
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor) :
- gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor)
- };
- NSString* buttonTitle = base::SysUTF8ToNSString([self model]->title());
- base::scoped_nsobject<NSAttributedString> attributedTitle(
- [[NSAttributedString alloc] initWithString:buttonTitle
- attributes:titleAttributes]);
- [[self button] setAttributedTitle:attributedTitle];
-
- // If the app does not specify a distinct short name manifest property, check
- // whether the title would be truncted in the NSButton. If it would be
- // truncated, add a tooltip showing the full name.
- NSRect titleRect =
- [[[self button] cell] titleRectForBounds:[[self button] bounds]];
- if ([self model]->title() == [self model]->full_name() &&
- [attributedTitle size].width < NSWidth(titleRect)) {
- [[self view] removeAllToolTips];
- } else {
- [[self view] setToolTip:base::SysUTF8ToNSString([self model]->full_name())];
- }
-}
-
-- (void)updateButtonImage {
- const gfx::Size iconSize = gfx::Size(kIconSize, kIconSize);
- gfx::ImageSkia icon = [self model]->icon();
- if (icon.size() != iconSize) {
- icon = gfx::ImageSkiaOperations::CreateResizedImage(
- icon, skia::ImageOperations::RESIZE_BEST, iconSize);
- }
- NSImage* buttonImage = gfx::NSImageFromImageSkiaWithColorSpace(
- icon, base::mac::GetSRGBColorSpace());
- [[self button] setImage:buttonImage];
- [[[self button] cell] setHasShadow:[self model]->has_shadow()];
-}
-
-- (void)setModel:(app_list::AppListItemModel*)itemModel {
- [trackingArea_.get() clearOwner];
- if (!itemModel) {
- observerBridge_.reset();
- return;
- }
-
- observerBridge_.reset(new app_list::ItemModelObserverBridge(self, itemModel));
- [self updateButtonTitle];
- [self updateButtonImage];
-
- if (trackingArea_.get())
- [[self view] removeTrackingArea:trackingArea_.get()];
-
- trackingArea_.reset(
- [[CrTrackingArea alloc] initWithRect:NSZeroRect
- options:NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInKeyWindow
- owner:self
- userInfo:nil]);
- [[self view] addTrackingArea:trackingArea_.get()];
-}
-
-- (app_list::AppListItemModel*)model {
- return observerBridge_->model();
-}
-
-- (NSButton*)button {
- return [[self itemBackgroundView] button];
-}
-
-- (NSMenu*)contextMenu {
- [self setSelected:YES];
- return observerBridge_->GetContextMenu();
-}
-
-- (NSBitmapImageRep*)dragRepresentationForRestore:(BOOL)isRestore {
- NSButton* button = [self button];
- NSView* itemView = [self view];
-
- // The snapshot is never drawn as if it was selected. Also remove the cell
- // highlight on the button image, added when it was clicked.
- [button setHidden:NO];
- [[button cell] setHighlighted:NO];
- [self setSelected:NO];
- [progressIndicator_ setHidden:YES];
- if (isRestore)
- [self updateButtonTitle];
- else
- [button setTitle:@""];
-
- NSBitmapImageRep* imageRep =
- [itemView bitmapImageRepForCachingDisplayInRect:[itemView visibleRect]];
- [itemView cacheDisplayInRect:[itemView visibleRect]
- toBitmapImageRep:imageRep];
-
- if (isRestore) {
- [progressIndicator_ setHidden:NO];
- [self setSelected:YES];
- }
- // Button is always hidden until the drag animation completes.
- [button setHidden:YES];
- return imageRep;
-}
-
-- (void)ensureVisible {
- NSCollectionView* collectionView = [self collectionView];
- AppsGridController* gridController =
- base::mac::ObjCCastStrict<AppsGridController>([collectionView delegate]);
- size_t pageIndex = [gridController pageIndexForCollectionView:collectionView];
- [gridController scrollToPage:pageIndex];
-}
-
-- (void)setItemIsInstalling:(BOOL)isInstalling {
- if (!isInstalling == !progressIndicator_)
- return;
-
- [self ensureVisible];
- if (!isInstalling) {
- [progressIndicator_ removeFromSuperview];
- progressIndicator_.reset();
- [self updateButtonTitle];
- [self setSelected:YES];
- return;
- }
-
- NSRect rect = NSMakeRect(
- kProgressBarHorizontalPadding,
- kProgressBarVerticalPadding,
- NSWidth([[self view] bounds]) - 2 * kProgressBarHorizontalPadding,
- NSProgressIndicatorPreferredAquaThickness);
- [[self button] setTitle:@""];
- progressIndicator_.reset([[NSProgressIndicator alloc] initWithFrame:rect]);
- [progressIndicator_ setIndeterminate:NO];
- [progressIndicator_ setControlSize:NSSmallControlSize];
- [[self view] addSubview:progressIndicator_];
-}
-
-- (void)setPercentDownloaded:(int)percent {
- // In a corner case, items can be installing when they are first added. For
- // those, the icon will start desaturated. Wait for a progress update before
- // showing the progress bar.
- [self setItemIsInstalling:YES];
- if (percent != -1) {
- [progressIndicator_ setDoubleValue:percent];
- return;
- }
-
- // Otherwise, fully downloaded and waiting for install to complete.
- [progressIndicator_ setIndeterminate:YES];
- [progressIndicator_ startAnimation:self];
-}
-
-- (AppsGridItemBackgroundView*)itemBackgroundView {
- return base::mac::ObjCCastStrict<AppsGridItemBackgroundView>([self view]);
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- [self setSelected:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- [self setSelected:NO];
-}
-
-- (void)setSelected:(BOOL)flag {
- if ([self isSelected] == flag)
- return;
-
- [[self itemBackgroundView] setSelected:flag];
- [super setSelected:flag];
- [self updateButtonTitle];
-}
-
-@end
-
-@implementation AppsGridItemButton
-
-+ (Class)cellClass {
- return [AppsGridItemButtonCell class];
-}
-
-@end
-
-@implementation AppsGridItemButtonCell
-
-@synthesize hasShadow = hasShadow_;
-
-- (void)drawImage:(NSImage*)image
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- if (!hasShadow_) {
- [super drawImage:image
- withFrame:frame
- inView:controlView];
- return;
- }
-
- base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- gfx::ScopedNSGraphicsContextSaveGState context;
- [shadow setShadowOffset:NSMakeSize(0, -2)];
- [shadow setShadowBlurRadius:2.0];
- [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0
- alpha:0.14]];
- [shadow set];
-
- [super drawImage:image
- withFrame:frame
- inView:controlView];
-}
-
-// Workaround for http://crbug.com/324365: AppKit in Mavericks tries to call
-// - [NSButtonCell item] when inspecting accessibility. Without this, an
-// unrecognized selector exception is thrown inside AppKit, crashing Chrome.
-- (id)item {
- return nil;
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/apps_pagination_model_observer.h b/chromium/ui/app_list/cocoa/apps_pagination_model_observer.h
deleted file mode 100644
index a2f463f9dab..00000000000
--- a/chromium/ui/app_list/cocoa/apps_pagination_model_observer.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
-#define UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
-
-// Observer protocol for page changes. Compare with
-// app_list::PaginationModelObserver.
-@protocol AppsPaginationModelObserver
-
-// Invoked when the total number of pages has changed.
-- (void)totalPagesChanged;
-
-// Invoked when the selected page index is changed.
-- (void)selectedPageChanged:(int)newSelected;
-
-// Invoked when the portion of pages that are visible have changed.
-- (void)pageVisibilityChanged;
-
-// Return a pager segment at |locationInWindow| or -1 if there is none.
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/cocoa/apps_search_box_controller.h b/chromium/ui/app_list/cocoa/apps_search_box_controller.h
deleted file mode 100644
index b8a86e57f7b..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_box_controller.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-class AppListMenu;
-class AppListModel;
-class AppListViewDelegate;
-class SearchBoxModel;
-class SearchBoxModelObserverBridge;
-}
-
-@class AppListMenuController;
-@class HoverImageMenuButton;
-@class SearchTextField;
-
-@protocol AppsSearchBoxDelegate<NSTextFieldDelegate>
-
-- (app_list::AppListViewDelegate*)appListDelegate;
-- (app_list::SearchBoxModel*)searchBoxModel;
-- (app_list::AppListModel*)appListModel;
-- (void)modelTextDidChange;
-
-@end
-
-// Controller for the search box in the topmost portion of the app list.
-APP_LIST_EXPORT
-@interface AppsSearchBoxController : NSViewController<NSTextFieldDelegate> {
- @private
- base::scoped_nsobject<SearchTextField> searchTextField_;
- base::scoped_nsobject<NSImageView> searchImageView_;
- base::scoped_nsobject<HoverImageMenuButton> menuButton_;
- base::scoped_nsobject<AppListMenuController> menuController_;
- scoped_ptr<app_list::SearchBoxModelObserverBridge> bridge_;
- scoped_ptr<app_list::AppListMenu> appListMenu_;
-
- id<AppsSearchBoxDelegate> delegate_; // Weak. Owns us.
-}
-
-@property(assign, nonatomic) id<AppsSearchBoxDelegate> delegate;
-
-- (id)initWithFrame:(NSRect)frame;
-- (void)clearSearch;
-
-// Rebuild the menu due to changes from the AppListViewDelegate.
-- (void)rebuildMenu;
-
-@end
-
-@interface AppsSearchBoxController (TestingAPI)
-
-- (NSTextField*)searchTextField;
-- (NSPopUpButton*)menuControl;
-- (app_list::AppListMenu*)appListMenu;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/apps_search_box_controller.mm b/chromium/ui/app_list/cocoa/apps_search_box_controller.mm
deleted file mode 100644
index b937c4c4c18..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_box_controller.mm
+++ /dev/null
@@ -1,396 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "grit/ui_resources.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-#include "ui/app_list/app_list_menu.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/search_box_model_observer.h"
-#import "ui/base/cocoa/controls/hover_image_menu_button.h"
-#import "ui/base/cocoa/controls/hover_image_menu_button_cell.h"
-#import "ui/base/cocoa/menu_controller.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-
-namespace {
-
-// Padding either side of the search icon and menu button.
-const CGFloat kPadding = 14;
-
-// Size of the search icon.
-const CGFloat kSearchIconDimension = 32;
-
-// Size of the menu button on the right.
-const CGFloat kMenuButtonDimension = 29;
-
-// Menu offset relative to the bottom-right corner of the menu button.
-const CGFloat kMenuYOffsetFromButton = -4;
-const CGFloat kMenuXOffsetFromButton = -7;
-
-}
-
-@interface AppsSearchBoxController ()
-
-- (NSImageView*)searchImageView;
-- (void)addSubviews;
-
-@end
-
-namespace app_list {
-
-class SearchBoxModelObserverBridge : public SearchBoxModelObserver {
- public:
- SearchBoxModelObserverBridge(AppsSearchBoxController* parent);
- virtual ~SearchBoxModelObserverBridge();
-
- void SetSearchText(const base::string16& text);
-
- virtual void IconChanged() OVERRIDE;
- virtual void SpeechRecognitionButtonPropChanged() OVERRIDE;
- virtual void HintTextChanged() OVERRIDE;
- virtual void SelectionModelChanged() OVERRIDE;
- virtual void TextChanged() OVERRIDE;
-
- private:
- SearchBoxModel* GetModel();
-
- AppsSearchBoxController* parent_; // Weak. Owns us.
-
- DISALLOW_COPY_AND_ASSIGN(SearchBoxModelObserverBridge);
-};
-
-SearchBoxModelObserverBridge::SearchBoxModelObserverBridge(
- AppsSearchBoxController* parent)
- : parent_(parent) {
- IconChanged();
- HintTextChanged();
- GetModel()->AddObserver(this);
-}
-
-SearchBoxModelObserverBridge::~SearchBoxModelObserverBridge() {
- GetModel()->RemoveObserver(this);
-}
-
-SearchBoxModel* SearchBoxModelObserverBridge::GetModel() {
- SearchBoxModel* searchBoxModel = [[parent_ delegate] searchBoxModel];
- DCHECK(searchBoxModel);
- return searchBoxModel;
-}
-
-void SearchBoxModelObserverBridge::SetSearchText(const base::string16& text) {
- SearchBoxModel* model = GetModel();
- model->RemoveObserver(this);
- model->SetText(text);
- // TODO(tapted): See if this should call SetSelectionModel here.
- model->AddObserver(this);
-}
-
-void SearchBoxModelObserverBridge::IconChanged() {
- [[parent_ searchImageView] setImage:gfx::NSImageFromImageSkiaWithColorSpace(
- GetModel()->icon(), base::mac::GetSRGBColorSpace())];
-}
-
-void SearchBoxModelObserverBridge::SpeechRecognitionButtonPropChanged() {
- // TODO(mukai): implement.
- NOTIMPLEMENTED();
-}
-
-void SearchBoxModelObserverBridge::HintTextChanged() {
- [[[parent_ searchTextField] cell] setPlaceholderString:
- base::SysUTF16ToNSString(GetModel()->hint_text())];
-}
-
-void SearchBoxModelObserverBridge::SelectionModelChanged() {
- // TODO(tapted): See if anything needs to be done here for RTL.
-}
-
-void SearchBoxModelObserverBridge::TextChanged() {
- // Currently the model text is only changed when we are not observing it, or
- // it is changed in tests to establish a particular state.
- [[parent_ searchTextField]
- setStringValue:base::SysUTF16ToNSString(GetModel()->text())];
- [[parent_ delegate] modelTextDidChange];
-}
-
-} // namespace app_list
-
-@interface SearchTextField : NSTextField {
- @private
- NSRect textFrameInset_;
-}
-
-@property(readonly, nonatomic) NSRect textFrameInset;
-
-- (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
- rightMargin:(CGFloat)rightMargin;
-
-@end
-
-@interface AppListMenuController : MenuController {
- @private
- AppsSearchBoxController* searchBoxController_; // Weak. Owns us.
-}
-
-- (id)initWithSearchBoxController:(AppsSearchBoxController*)parent;
-
-@end
-
-@implementation AppsSearchBoxController
-
-@synthesize delegate = delegate_;
-
-- (id)initWithFrame:(NSRect)frame {
- if ((self = [super init])) {
- base::scoped_nsobject<NSView> containerView(
- [[NSView alloc] initWithFrame:frame]);
- [self setView:containerView];
- [self addSubviews];
- }
- return self;
-}
-
-- (void)clearSearch {
- [searchTextField_ setStringValue:@""];
- [self controlTextDidChange:nil];
-}
-
-- (void)rebuildMenu {
- if (![delegate_ appListDelegate])
- return;
-
- menuController_.reset();
- appListMenu_.reset(
- new app_list::AppListMenu([delegate_ appListDelegate]));
- menuController_.reset([[AppListMenuController alloc]
- initWithSearchBoxController:self]);
- [menuButton_ setMenu:[menuController_ menu]]; // Menu will populate here.
-}
-
-- (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate {
- [[menuButton_ menu] removeAllItems];
- menuController_.reset();
- appListMenu_.reset();
- bridge_.reset(); // Ensure observers are cleared before updating |delegate_|.
- delegate_ = delegate;
- if (!delegate_)
- return;
-
- bridge_.reset(new app_list::SearchBoxModelObserverBridge(self));
- [self rebuildMenu];
-}
-
-- (NSTextField*)searchTextField {
- return searchTextField_;
-}
-
-- (NSPopUpButton*)menuControl {
- return menuButton_;
-}
-
-- (app_list::AppListMenu*)appListMenu {
- return appListMenu_.get();
-}
-
-- (NSImageView*)searchImageView {
- return searchImageView_;
-}
-
-- (void)addSubviews {
- NSRect viewBounds = [[self view] bounds];
- searchImageView_.reset([[NSImageView alloc] initWithFrame:NSMakeRect(
- kPadding, 0, kSearchIconDimension, NSHeight(viewBounds))]);
-
- searchTextField_.reset([[SearchTextField alloc] initWithFrame:viewBounds]);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- [searchTextField_ setDelegate:self];
- [searchTextField_ setFont:rb.GetFont(
- ui::ResourceBundle::MediumFont).GetNativeFont()];
- [searchTextField_
- setMarginsWithLeftMargin:NSMaxX([searchImageView_ frame]) + kPadding
- rightMargin:kMenuButtonDimension + 2 * kPadding];
-
- // Add the drop-down menu, with a custom button.
- NSRect buttonFrame = NSMakeRect(
- NSWidth(viewBounds) - kMenuButtonDimension - kPadding,
- floor(NSMidY(viewBounds) - kMenuButtonDimension / 2),
- kMenuButtonDimension,
- kMenuButtonDimension);
- menuButton_.reset([[HoverImageMenuButton alloc] initWithFrame:buttonFrame
- pullsDown:YES]);
- [[menuButton_ hoverImageMenuButtonCell] setDefaultImage:
- rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_NORMAL).AsNSImage()];
- [[menuButton_ hoverImageMenuButtonCell] setAlternateImage:
- rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_PRESSED).AsNSImage()];
- [[menuButton_ hoverImageMenuButtonCell] setHoverImage:
- rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_HOVER).AsNSImage()];
-
- [[self view] addSubview:searchImageView_];
- [[self view] addSubview:searchTextField_];
- [[self view] addSubview:menuButton_];
-}
-
-- (BOOL)control:(NSControl*)control
- textView:(NSTextView*)textView
- doCommandBySelector:(SEL)command {
- // Forward the message first, to handle grid or search results navigation.
- BOOL handled = [delegate_ control:control
- textView:textView
- doCommandBySelector:command];
- if (handled)
- return YES;
-
- // If the delegate did not handle the escape key, it means the window was not
- // dismissed because there were search results. Clear them.
- if (command == @selector(complete:)) {
- [self clearSearch];
- return YES;
- }
-
- return NO;
-}
-
-- (void)controlTextDidChange:(NSNotification*)notification {
- if (bridge_) {
- bridge_->SetSearchText(
- base::SysNSStringToUTF16([searchTextField_ stringValue]));
- }
-
- [delegate_ modelTextDidChange];
-}
-
-@end
-
-@interface SearchTextFieldCell : NSTextFieldCell;
-
-- (NSRect)textFrameForFrameInternal:(NSRect)cellFrame;
-
-@end
-
-@implementation SearchTextField
-
-@synthesize textFrameInset = textFrameInset_;
-
-+ (Class)cellClass {
- return [SearchTextFieldCell class];
-}
-
-- (id)initWithFrame:(NSRect)theFrame {
- if ((self = [super initWithFrame:theFrame])) {
- [self setFocusRingType:NSFocusRingTypeNone];
- [self setDrawsBackground:NO];
- [self setBordered:NO];
- }
- return self;
-}
-
-- (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
- rightMargin:(CGFloat)rightMargin {
- // Find the preferred height for the current text properties, and center.
- NSRect viewBounds = [self bounds];
- [self sizeToFit];
- NSRect textBounds = [self bounds];
- textFrameInset_.origin.x = leftMargin;
- textFrameInset_.origin.y = floor(NSMidY(viewBounds) - NSMidY(textBounds));
- textFrameInset_.size.width = leftMargin + rightMargin;
- textFrameInset_.size.height = NSHeight(viewBounds) - NSHeight(textBounds);
- [self setFrame:viewBounds];
-}
-
-@end
-
-@implementation SearchTextFieldCell
-
-- (NSRect)textFrameForFrameInternal:(NSRect)cellFrame {
- SearchTextField* searchTextField =
- base::mac::ObjCCastStrict<SearchTextField>([self controlView]);
- NSRect insetRect = [searchTextField textFrameInset];
- cellFrame.origin.x += insetRect.origin.x;
- cellFrame.origin.y += insetRect.origin.y;
- cellFrame.size.width -= insetRect.size.width;
- cellFrame.size.height -= insetRect.size.height;
- return cellFrame;
-}
-
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
- return [self textFrameForFrameInternal:cellFrame];
-}
-
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
- return [self textFrameForFrameInternal:cellFrame];
-}
-
-- (void)resetCursorRect:(NSRect)cellFrame
- inView:(NSView*)controlView {
- [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
- inView:controlView];
-}
-
-- (NSRect)drawingRectForBounds:(NSRect)theRect {
- return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
-}
-
-- (void)editWithFrame:(NSRect)cellFrame
- inView:(NSView*)controlView
- editor:(NSText*)editor
- delegate:(id)delegate
- event:(NSEvent*)event {
- [super editWithFrame:[self textFrameForFrame:cellFrame]
- inView:controlView
- editor:editor
- delegate:delegate
- event:event];
-}
-
-- (void)selectWithFrame:(NSRect)cellFrame
- inView:(NSView*)controlView
- editor:(NSText*)editor
- delegate:(id)delegate
- start:(NSInteger)start
- length:(NSInteger)length {
- [super selectWithFrame:[self textFrameForFrame:cellFrame]
- inView:controlView
- editor:editor
- delegate:delegate
- start:start
- length:length];
-}
-
-@end
-
-@implementation AppListMenuController
-
-- (id)initWithSearchBoxController:(AppsSearchBoxController*)parent {
- // Need to initialze super with a NULL model, otherwise it will immediately
- // try to populate, which can't be done until setting the parent.
- if ((self = [super initWithModel:NULL
- useWithPopUpButtonCell:YES])) {
- searchBoxController_ = parent;
- [super setModel:[parent appListMenu]->menu_model()];
- }
- return self;
-}
-
-- (NSRect)confinementRectForMenu:(NSMenu*)menu
- onScreen:(NSScreen*)screen {
- NSPopUpButton* menuButton = [searchBoxController_ menuControl];
- // Ensure the menu comes up below the menu button by trimming the window frame
- // to a point anchored below the bottom right of the button.
- NSRect anchorRect = [menuButton convertRect:[menuButton bounds]
- toView:nil];
- NSPoint anchorPoint = [[menuButton window] convertBaseToScreen:NSMakePoint(
- NSMaxX(anchorRect) + kMenuXOffsetFromButton,
- NSMinY(anchorRect) - kMenuYOffsetFromButton)];
- NSRect confinementRect = [[menuButton window] frame];
- confinementRect.size = NSMakeSize(anchorPoint.x - NSMinX(confinementRect),
- anchorPoint.y - NSMinY(confinementRect));
- return confinementRect;
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/apps_search_box_controller_unittest.mm b/chromium/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
deleted file mode 100644
index bbe7ce626a5..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_menu.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#import "ui/base/cocoa/menu_controller.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-
-@interface TestAppsSearchBoxDelegate : NSObject<AppsSearchBoxDelegate> {
- @private
- app_list::SearchBoxModel searchBoxModel_;
- app_list::test::AppListTestViewDelegate appListDelegate_;
- app_list::test::AppListTestModel appListModel_;
- int textChangeCount_;
-}
-
-@property(assign, nonatomic) int textChangeCount;
-
-@end
-
-@implementation TestAppsSearchBoxDelegate
-
-@synthesize textChangeCount = textChangeCount_;
-
-- (id)init {
- if ((self = [super init])) {
- app_list::AppListViewDelegate::Users users(2);
- users[0].name = ASCIIToUTF16("user1");
- users[1].name = ASCIIToUTF16("user2");
- users[1].email = ASCIIToUTF16("user2@chromium.org");
- users[1].active = true;
- appListDelegate_.SetUsers(users);
- }
- return self;
-}
-
-- (app_list::SearchBoxModel*)searchBoxModel {
- return &searchBoxModel_;
-}
-
-- (app_list::AppListViewDelegate*)appListDelegate {
- return &appListDelegate_;
-}
-
-- (app_list::test::AppListTestViewDelegate*)appListTestViewDelegate {
- return &appListDelegate_;
-}
-
-
-- (BOOL)control:(NSControl*)control
- textView:(NSTextView*)textView
- doCommandBySelector:(SEL)command {
- return NO;
-}
-
-- (void)modelTextDidChange {
- ++textChangeCount_;
-}
-
-- (CGFloat)bubbleCornerRadius {
- return 3;
-}
-
-- (app_list::AppListModel*)appListModel {
- return &appListModel_;
-}
-
-@end
-
-namespace app_list {
-namespace test {
-
-class AppsSearchBoxControllerTest : public ui::CocoaTest {
- public:
- AppsSearchBoxControllerTest() {
- Init();
- }
-
- virtual void SetUp() OVERRIDE {
- apps_search_box_controller_.reset(
- [[AppsSearchBoxController alloc] initWithFrame:
- NSMakeRect(0, 0, 400, 100)]);
- delegate_.reset([[TestAppsSearchBoxDelegate alloc] init]);
- [apps_search_box_controller_ setDelegate:delegate_];
-
- ui::CocoaTest::SetUp();
- [[test_window() contentView] addSubview:[apps_search_box_controller_ view]];
- }
-
- virtual void TearDown() OVERRIDE {
- [apps_search_box_controller_ setDelegate:nil];
- ui::CocoaTest::TearDown();
- }
-
- void SimulateKeyAction(SEL c) {
- NSControl* control = [apps_search_box_controller_ searchTextField];
- [apps_search_box_controller_ control:control
- textView:nil
- doCommandBySelector:c];
- }
-
- protected:
- base::scoped_nsobject<TestAppsSearchBoxDelegate> delegate_;
- base::scoped_nsobject<AppsSearchBoxController> apps_search_box_controller_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppsSearchBoxControllerTest);
-};
-
-TEST_VIEW(AppsSearchBoxControllerTest, [apps_search_box_controller_ view]);
-
-// Test the search box initialization, and search input and clearing.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxModel) {
- app_list::SearchBoxModel* model = [delegate_ searchBoxModel];
- // Usually localized "Search".
- const base::string16 hit_text(ASCIIToUTF16("hint"));
- model->SetHintText(hit_text);
- EXPECT_NSEQ(base::SysUTF16ToNSString(hit_text),
- [[[apps_search_box_controller_ searchTextField] cell] placeholderString]);
-
- const base::string16 search_text(ASCIIToUTF16("test"));
- model->SetText(search_text);
- EXPECT_NSEQ(base::SysUTF16ToNSString(search_text),
- [[apps_search_box_controller_ searchTextField] stringValue]);
- // Updates coming via the model should notify the delegate.
- EXPECT_EQ(1, [delegate_ textChangeCount]);
-
- // Updates from the view should update the model and notify the delegate.
- [apps_search_box_controller_ clearSearch];
- EXPECT_EQ(base::string16(), model->text());
- EXPECT_NSEQ([NSString string],
- [[apps_search_box_controller_ searchTextField] stringValue]);
- EXPECT_EQ(2, [delegate_ textChangeCount]);
-
- // Test pressing escape clears the search. First add some text.
- model->SetText(search_text);
- EXPECT_EQ(3, [delegate_ textChangeCount]);
-
- EXPECT_NSEQ(base::SysUTF16ToNSString(search_text),
- [[apps_search_box_controller_ searchTextField] stringValue]);
- SimulateKeyAction(@selector(complete:));
- EXPECT_NSEQ([NSString string],
- [[apps_search_box_controller_ searchTextField] stringValue]);
- EXPECT_EQ(4, [delegate_ textChangeCount]);
-}
-
-// Test the popup menu items when there is only one user..
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuSingleUser) {
- // Set a single user. We need to set the delegate again because the
- // AppListModel observer isn't hooked up in these tests.
- [delegate_ appListTestViewDelegate]->SetUsers(
- app_list::AppListViewDelegate::Users(1));
- [apps_search_box_controller_ setDelegate:delegate_];
-
- NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
- EXPECT_TRUE([apps_search_box_controller_ appListMenu]);
- ui::MenuModel* menu_model
- = [apps_search_box_controller_ appListMenu]->menu_model();
- // Add one to the item count to account for the blank, first item that Cocoa
- // has in its popup menus.
- EXPECT_EQ(menu_model->GetItemCount() + 1,
- [[menu_control menu] numberOfItems]);
-
- // All command ids should be less than |SELECT_PROFILE| as no user menu items
- // are being shown.
- for (int i = 0; i < menu_model->GetItemCount(); ++i)
- EXPECT_LT(menu_model->GetCommandIdAt(i), AppListMenu::SELECT_PROFILE);
-
- // The number of items should match the index that starts profile items.
- EXPECT_EQ(AppListMenu::SELECT_PROFILE, menu_model->GetItemCount());
-}
-
-// Test the popup menu items for the multi-profile case.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenu) {
- const app_list::AppListViewDelegate::Users& users =
- [delegate_ appListDelegate]->GetUsers();
- NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
- EXPECT_TRUE([apps_search_box_controller_ appListMenu]);
- ui::MenuModel* menu_model
- = [apps_search_box_controller_ appListMenu]->menu_model();
- // Add one to the item count to account for the blank, first item that Cocoa
- // has in its popup menus.
- EXPECT_EQ(menu_model->GetItemCount() + 1,
- [[menu_control menu] numberOfItems]);
-
- ui::MenuModel* found_menu_model = menu_model;
- int index;
- MenuController* controller = [[menu_control menu] delegate];
-
- // The first user item is an unchecked label.
- EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
- AppListMenu::SELECT_PROFILE, &menu_model, &index));
- EXPECT_EQ(found_menu_model, menu_model);
- NSMenuItem* unchecked_user_item = [[menu_control menu] itemAtIndex:index + 1];
- [controller validateUserInterfaceItem:unchecked_user_item];
- // The profile name should be shown if there is no email available.
- EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
- [unchecked_user_item title]);
- EXPECT_EQ(NSOffState, [unchecked_user_item state]);
-
- // The second user item is a checked label because it is the active profile.
- EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
- AppListMenu::SELECT_PROFILE + 1, &menu_model, &index));
- EXPECT_EQ(found_menu_model, menu_model);
- NSMenuItem* checked_user_item = [[menu_control menu] itemAtIndex:index + 1];
- [controller validateUserInterfaceItem:checked_user_item];
- // The email is shown when available.
- EXPECT_NSEQ(base::SysUTF16ToNSString(users[1].email),
- [checked_user_item title]);
- EXPECT_EQ(NSOnState, [checked_user_item state]);
-
- // A regular item should have just the label.
- EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
- AppListMenu::SHOW_SETTINGS, &menu_model, &index));
- EXPECT_EQ(found_menu_model, menu_model);
- NSMenuItem* settings_item = [[menu_control menu] itemAtIndex:index + 1];
- EXPECT_FALSE([settings_item view]);
- EXPECT_NSEQ(base::SysUTF16ToNSString(menu_model->GetLabelAt(index)),
- [settings_item title]);
-}
-
-// Test adding another user, and changing an existing one.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuChangingUsers) {
- app_list::AppListViewDelegate::Users users =
- [delegate_ appListDelegate]->GetUsers();
- EXPECT_EQ(2u, users.size());
- ui::MenuModel* menu_model
- = [apps_search_box_controller_ appListMenu]->menu_model();
- // Adding one to account for the empty item at index 0 in Cocoa popup menus.
- int non_user_items = menu_model->GetItemCount() - users.size() + 1;
-
- NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
- EXPECT_EQ(2, [[menu_control menu] numberOfItems] - non_user_items);
- EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
- [[[menu_control menu] itemAtIndex:1] title]);
-
- users[0].name = ASCIIToUTF16("renamed user");
- app_list::AppListViewDelegate::User new_user;
- new_user.name = ASCIIToUTF16("user3");
- users.push_back(new_user);
- [delegate_ appListTestViewDelegate]->SetUsers(users);
- // Note: menu does not automatically get rebuilt. Force a rebuild (which
- // would normally occur when the UI is closed / re-opend).
- [apps_search_box_controller_ rebuildMenu];
-
- // Should now be an extra item, and it should have correct titles.
- EXPECT_EQ(3, [[menu_control menu] numberOfItems] - non_user_items);
- EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
- [[[menu_control menu] itemAtIndex:1] title]);
- EXPECT_NSEQ(base::SysUTF16ToNSString(new_user.name),
- [[[menu_control menu] itemAtIndex:3] title]);
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/cocoa/apps_search_results_controller.h b/chromium/ui/app_list/cocoa/apps_search_results_controller.h
deleted file mode 100644
index 52290c7824c..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_results_controller.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-namespace app_list {
-class AppsSearchResultsModelBridge;
-class SearchResult;
-}
-
-@class AppsSearchResultsCell;
-
-@protocol AppsSearchResultsDelegate<NSObject>
-
-- (app_list::AppListModel*)appListModel;
-- (void)openResult:(app_list::SearchResult*)result;
-- (void)redoSearch;
-
-@end
-
-// Controller for the search results displayed when a user types in the app list
-// search box. Results display in an NSTableView with a single column. Each row
-// has an icon on the left, and one or two lines of formatted text describing
-// the result.
-APP_LIST_EXPORT
-@interface AppsSearchResultsController
- : NSViewController<NSTableViewDelegate, NSTableViewDataSource> {
- @private
- base::scoped_nsobject<NSTableView> tableView_;
- ui::ScopedCrTrackingArea trackingArea_;
- NSPoint lastMouseDownInView_;
- NSInteger hoveredRowIndex_;
- scoped_ptr<app_list::AppsSearchResultsModelBridge> bridge_;
- NSObject<AppsSearchResultsDelegate>* delegate_; // Weak. Owns us.
-}
-
-@property(assign, nonatomic) NSObject<AppsSearchResultsDelegate>* delegate;
-@property(readonly, nonatomic) app_list::AppListModel::SearchResults* results;
-@property(readonly, nonatomic) NSTableView* tableView;
-
-- (id)initWithAppsSearchResultsFrameSize:(NSSize)size;
-
-// Returns true when handling Enter, to activate the highlighted search result,
-// or up/down to navigate results.
-- (BOOL)handleCommandBySelector:(SEL)command;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/apps_search_results_controller.mm b/chromium/ui/app_list/cocoa/apps_search_results_controller.mm
deleted file mode 100644
index 314f079e8ad..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_results_controller.mm
+++ /dev/null
@@ -1,463 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
-#include "ui/app_list/search_result.h"
-#import "ui/base/cocoa/flipped_view.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-
-namespace {
-
-const CGFloat kPreferredRowHeight = 52;
-const CGFloat kIconDimension = 32;
-const CGFloat kIconPadding = 14;
-const CGFloat kIconViewWidth = kIconDimension + 2 * kIconPadding;
-const CGFloat kTextTrailPadding = kIconPadding;
-
-// Map background styles to represent selection and hover in the results list.
-const NSBackgroundStyle kBackgroundNormal = NSBackgroundStyleLight;
-const NSBackgroundStyle kBackgroundSelected = NSBackgroundStyleDark;
-const NSBackgroundStyle kBackgroundHovered = NSBackgroundStyleRaised;
-
-} // namespace
-
-@interface AppsSearchResultsController ()
-
-- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size;
-- (void)mouseDown:(NSEvent*)theEvent;
-- (void)tableViewClicked:(id)sender;
-- (app_list::AppListModel::SearchResults*)searchResults;
-- (void)activateSelection;
-- (BOOL)moveSelectionByDelta:(NSInteger)delta;
-- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex;
-
-@end
-
-@interface AppsSearchResultsCell : NSTextFieldCell
-@end
-
-// Immutable class representing a search result in the NSTableView.
-@interface AppsSearchResultRep : NSObject<NSCopying> {
- @private
- base::scoped_nsobject<NSAttributedString> attributedStringValue_;
- base::scoped_nsobject<NSImage> resultIcon_;
-}
-
-@property(readonly, nonatomic) NSAttributedString* attributedStringValue;
-@property(readonly, nonatomic) NSImage* resultIcon;
-
-- (id)initWithSearchResult:(app_list::SearchResult*)result;
-
-- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
- tags:(const app_list::SearchResult::Tags&)tags;
-
-- (NSAttributedString*)createResultsAttributedStringWithModel
- :(app_list::SearchResult*)result;
-
-@end
-
-// Simple extension to NSTableView that passes mouseDown events to the
-// delegate so that drag events can be detected, and forwards requests for
-// context menus.
-@interface AppsSearchResultsTableView : NSTableView
-
-- (AppsSearchResultsController*)controller;
-
-@end
-
-@implementation AppsSearchResultsController
-
-@synthesize delegate = delegate_;
-
-- (id)initWithAppsSearchResultsFrameSize:(NSSize)size {
- if ((self = [super init])) {
- hoveredRowIndex_ = -1;
- [self loadAndSetViewWithResultsFrameSize:size];
- }
- return self;
-}
-
-- (app_list::AppListModel::SearchResults*)results {
- DCHECK([delegate_ appListModel]);
- return [delegate_ appListModel]->results();
-}
-
-- (NSTableView*)tableView {
- return tableView_;
-}
-
-- (void)setDelegate:(id<AppsSearchResultsDelegate>)newDelegate {
- bridge_.reset();
- delegate_ = newDelegate;
- app_list::AppListModel* appListModel = [delegate_ appListModel];
- if (!appListModel || !appListModel->results()) {
- [tableView_ reloadData];
- return;
- }
-
- bridge_.reset(new app_list::AppsSearchResultsModelBridge(self));
- [tableView_ reloadData];
-}
-
-- (BOOL)handleCommandBySelector:(SEL)command {
- if (command == @selector(insertNewline:) ||
- command == @selector(insertLineBreak:)) {
- [self activateSelection];
- return YES;
- }
-
- if (command == @selector(moveUp:))
- return [self moveSelectionByDelta:-1];
-
- if (command == @selector(moveDown:))
- return [self moveSelectionByDelta:1];
-
- return NO;
-}
-
-- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size {
- tableView_.reset(
- [[AppsSearchResultsTableView alloc] initWithFrame:NSZeroRect]);
- // Refuse first responder so that focus stays with the search text field.
- [tableView_ setRefusesFirstResponder:YES];
- [tableView_ setRowHeight:kPreferredRowHeight];
- [tableView_ setGridStyleMask:NSTableViewSolidHorizontalGridLineMask];
- [tableView_ setGridColor:
- gfx::SkColorToSRGBNSColor(app_list::kResultBorderColor)];
- [tableView_ setBackgroundColor:[NSColor clearColor]];
- [tableView_ setAction:@selector(tableViewClicked:)];
- [tableView_ setDelegate:self];
- [tableView_ setDataSource:self];
- [tableView_ setTarget:self];
-
- // Tracking to highlight an individual row on mouseover.
- trackingArea_.reset(
- [[CrTrackingArea alloc] initWithRect:NSZeroRect
- options:NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveInKeyWindow
- owner:self
- userInfo:nil]);
- [tableView_ addTrackingArea:trackingArea_.get()];
-
- base::scoped_nsobject<NSTableColumn> resultsColumn(
- [[NSTableColumn alloc] initWithIdentifier:@""]);
- base::scoped_nsobject<NSCell> resultsDataCell(
- [[AppsSearchResultsCell alloc] initTextCell:@""]);
- [resultsColumn setDataCell:resultsDataCell];
- [resultsColumn setWidth:size.width];
- [tableView_ addTableColumn:resultsColumn];
-
- // An NSTableView is normally put in a NSScrollView, but scrolling is not
- // used for the app list. Instead, place it in a container with the desired
- // size; flipped so the table is anchored to the top-left.
- base::scoped_nsobject<FlippedView> containerView([[FlippedView alloc]
- initWithFrame:NSMakeRect(0, 0, size.width, size.height)]);
-
- // The container is then anchored in an un-flipped view, initially hidden,
- // so that |containerView| slides in from the top when showing results.
- base::scoped_nsobject<NSView> clipView(
- [[NSView alloc] initWithFrame:NSMakeRect(0, 0, size.width, 0)]);
-
- [containerView addSubview:tableView_];
- [clipView addSubview:containerView];
- [self setView:clipView];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- lastMouseDownInView_ = [tableView_ convertPoint:[theEvent locationInWindow]
- fromView:nil];
-}
-
-- (void)tableViewClicked:(id)sender {
- const CGFloat kDragThreshold = 5;
- // If the user clicked and then dragged elsewhere, ignore the click.
- NSEvent* event = [[tableView_ window] currentEvent];
- NSPoint pointInView = [tableView_ convertPoint:[event locationInWindow]
- fromView:nil];
- CGFloat deltaX = pointInView.x - lastMouseDownInView_.x;
- CGFloat deltaY = pointInView.y - lastMouseDownInView_.y;
- if (deltaX * deltaX + deltaY * deltaY <= kDragThreshold * kDragThreshold)
- [self activateSelection];
-
- // Mouse tracking is suppressed by the NSTableView during a drag, so ensure
- // any hover state is cleaned up.
- [self mouseMoved:event];
-}
-
-- (app_list::AppListModel::SearchResults*)searchResults {
- app_list::AppListModel* appListModel = [delegate_ appListModel];
- DCHECK(bridge_);
- DCHECK(appListModel);
- DCHECK(appListModel->results());
- return appListModel->results();
-}
-
-- (void)activateSelection {
- NSInteger selectedRow = [tableView_ selectedRow];
- if (!bridge_ || selectedRow < 0)
- return;
-
- [delegate_ openResult:[self searchResults]->GetItemAt(selectedRow)];
-}
-
-- (BOOL)moveSelectionByDelta:(NSInteger)delta {
- NSInteger rowCount = [tableView_ numberOfRows];
- if (rowCount <= 0)
- return NO;
-
- NSInteger selectedRow = [tableView_ selectedRow];
- NSInteger targetRow;
- if (selectedRow == -1) {
- // No selection. Select first or last, based on direction.
- targetRow = delta > 0 ? 0 : rowCount - 1;
- } else {
- targetRow = (selectedRow + delta) % rowCount;
- if (targetRow < 0)
- targetRow += rowCount;
- }
-
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:targetRow]
- byExtendingSelection:NO];
- return YES;
-}
-
-- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex {
- DCHECK(bridge_);
- if (rowIndex < 0)
- return nil;
-
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex]
- byExtendingSelection:NO];
- return bridge_->MenuForItem(rowIndex);
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTableView {
- return bridge_ ? [self searchResults]->item_count() : 0;
-}
-
-- (id)tableView:(NSTableView*)aTableView
- objectValueForTableColumn:(NSTableColumn*)aTableColumn
- row:(NSInteger)rowIndex {
- // When the results were previously cleared, nothing will be selected. For
- // that case, select the first row when it appears.
- if (rowIndex == 0 && [tableView_ selectedRow] == -1) {
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
- byExtendingSelection:NO];
- }
-
- base::scoped_nsobject<AppsSearchResultRep> resultRep(
- [[AppsSearchResultRep alloc]
- initWithSearchResult:[self searchResults]->GetItemAt(rowIndex)]);
- return resultRep.autorelease();
-}
-
-- (void)tableView:(NSTableView*)tableView
- willDisplayCell:(id)cell
- forTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)rowIndex {
- if (rowIndex == [tableView selectedRow])
- [cell setBackgroundStyle:kBackgroundSelected];
- else if (rowIndex == hoveredRowIndex_)
- [cell setBackgroundStyle:kBackgroundHovered];
- else
- [cell setBackgroundStyle:kBackgroundNormal];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- if (hoveredRowIndex_ == -1)
- return;
-
- [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
- hoveredRowIndex_ = -1;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- NSPoint pointInView = [tableView_ convertPoint:[theEvent locationInWindow]
- fromView:nil];
- NSInteger newIndex = [tableView_ rowAtPoint:pointInView];
- if (newIndex == hoveredRowIndex_)
- return;
-
- if (newIndex != -1)
- [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:newIndex]];
- if (hoveredRowIndex_ != -1)
- [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
- hoveredRowIndex_ = newIndex;
-}
-
-@end
-
-@implementation AppsSearchResultRep
-
-- (NSAttributedString*)attributedStringValue {
- return attributedStringValue_;
-}
-
-- (NSImage*)resultIcon {
- return resultIcon_;
-}
-
-- (id)initWithSearchResult:(app_list::SearchResult*)result {
- if ((self = [super init])) {
- attributedStringValue_.reset(
- [[self createResultsAttributedStringWithModel:result] retain]);
- if (!result->icon().isNull()) {
- resultIcon_.reset([gfx::NSImageFromImageSkiaWithColorSpace(
- result->icon(), base::mac::GetSRGBColorSpace()) retain]);
- }
- }
- return self;
-}
-
-- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
- tags:(const app_list::SearchResult::Tags&)tags {
- NSFont* boldFont = nil;
- base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
- [[NSMutableParagraphStyle alloc] init]);
- [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
- NSDictionary* defaultAttributes = @{
- NSForegroundColorAttributeName:
- gfx::SkColorToSRGBNSColor(app_list::kResultDefaultTextColor),
- NSParagraphStyleAttributeName: paragraphStyle
- };
-
- base::scoped_nsobject<NSMutableAttributedString> text(
- [[NSMutableAttributedString alloc]
- initWithString:base::SysUTF16ToNSString(content)
- attributes:defaultAttributes]);
-
- for (app_list::SearchResult::Tags::const_iterator it = tags.begin();
- it != tags.end(); ++it) {
- if (it->styles == app_list::SearchResult::Tag::NONE)
- continue;
-
- if (it->styles & app_list::SearchResult::Tag::MATCH) {
- if (!boldFont) {
- NSFontManager* fontManager = [NSFontManager sharedFontManager];
- boldFont = [fontManager convertFont:[NSFont controlContentFontOfSize:0]
- toHaveTrait:NSBoldFontMask];
- }
- [text addAttribute:NSFontAttributeName
- value:boldFont
- range:it->range.ToNSRange()];
- }
-
- if (it->styles & app_list::SearchResult::Tag::DIM) {
- NSColor* dimmedColor =
- gfx::SkColorToSRGBNSColor(app_list::kResultDimmedTextColor);
- [text addAttribute:NSForegroundColorAttributeName
- value:dimmedColor
- range:it->range.ToNSRange()];
- } else if (it->styles & app_list::SearchResult::Tag::URL) {
- NSColor* urlColor =
- gfx::SkColorToSRGBNSColor(app_list::kResultURLTextColor);
- [text addAttribute:NSForegroundColorAttributeName
- value:urlColor
- range:it->range.ToNSRange()];
- }
- }
-
- return text.autorelease();
-}
-
-- (NSAttributedString*)createResultsAttributedStringWithModel
- :(app_list::SearchResult*)result {
- NSMutableAttributedString* titleText =
- [self createRenderText:result->title()
- tags:result->title_tags()];
- if (!result->details().empty()) {
- NSMutableAttributedString* detailText =
- [self createRenderText:result->details()
- tags:result->details_tags()];
- base::scoped_nsobject<NSAttributedString> lineBreak(
- [[NSAttributedString alloc] initWithString:@"\n"]);
- [titleText appendAttributedString:lineBreak];
- [titleText appendAttributedString:detailText];
- }
- return titleText;
-}
-
-- (id)copyWithZone:(NSZone*)zone {
- return [self retain];
-}
-
-@end
-
-@implementation AppsSearchResultsTableView
-
-- (AppsSearchResultsController*)controller {
- return base::mac::ObjCCastStrict<AppsSearchResultsController>(
- [self delegate]);
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- [[self controller] mouseDown:theEvent];
- [super mouseDown:theEvent];
-}
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent {
- NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- return [[self controller] contextMenuForRow:[self rowAtPoint:pointInView]];
-}
-
-@end
-
-@implementation AppsSearchResultsCell
-
-- (void)drawWithFrame:(NSRect)cellFrame
- inView:(NSView*)controlView {
- if ([self backgroundStyle] != kBackgroundNormal) {
- if ([self backgroundStyle] == kBackgroundSelected)
- [gfx::SkColorToSRGBNSColor(app_list::kSelectedColor) set];
- else
- [gfx::SkColorToSRGBNSColor(app_list::kHighlightedColor) set];
-
- // Extend up by one pixel to draw over cell border.
- NSRect backgroundRect = cellFrame;
- backgroundRect.origin.y -= 1;
- backgroundRect.size.height += 1;
- NSRectFill(backgroundRect);
- }
-
- NSAttributedString* titleText = [self attributedStringValue];
- NSRect titleRect = cellFrame;
- titleRect.size.width -= kTextTrailPadding + kIconViewWidth;
- titleRect.origin.x += kIconViewWidth;
- titleRect.origin.y +=
- floor(NSHeight(cellFrame) / 2 - [titleText size].height / 2);
- // Ensure no drawing occurs outside of the cell.
- titleRect = NSIntersectionRect(titleRect, cellFrame);
-
- [titleText drawInRect:titleRect];
-
- NSImage* resultIcon = [[self objectValue] resultIcon];
- if (!resultIcon)
- return;
-
- NSSize iconSize = [resultIcon size];
- NSRect iconRect = NSMakeRect(
- floor(NSMinX(cellFrame) + kIconViewWidth / 2 - iconSize.width / 2),
- floor(NSMinY(cellFrame) + kPreferredRowHeight / 2 - iconSize.height / 2),
- std::min(iconSize.width, kIconDimension),
- std::min(iconSize.height, kIconDimension));
- [resultIcon drawInRect:iconRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0
- respectFlipped:YES
- hints:nil];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/apps_search_results_controller_unittest.mm b/chromium/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
deleted file mode 100644
index 27e04e9311f..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/search_result.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/base/models/simple_menu_model.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#import "ui/base/test/cocoa_test_event_utils.h"
-
-@interface TestAppsSearchResultsDelegate : NSObject<AppsSearchResultsDelegate> {
- @private
- app_list::test::AppListTestModel appListModel_;
- app_list::SearchResult* lastOpenedResult_;
- int redoSearchCount_;
-}
-
-@property(readonly, nonatomic) app_list::SearchResult* lastOpenedResult;
-@property(readonly, nonatomic) int redoSearchCount;
-
-- (void)quitMessageLoop;
-
-@end
-
-@implementation TestAppsSearchResultsDelegate
-
-@synthesize lastOpenedResult = lastOpenedResult_;
-@synthesize redoSearchCount = redoSearchCount_;
-
-- (app_list::AppListModel*)appListModel {
- return &appListModel_;
-}
-
-- (void)openResult:(app_list::SearchResult*)result {
- lastOpenedResult_ = result;
-}
-
-- (void)redoSearch {
- ++redoSearchCount_;
-}
-
-- (void)quitMessageLoop {
- base::MessageLoop::current()->QuitNow();
-}
-
-@end
-
-namespace app_list {
-namespace test {
-namespace {
-
-const int kDefaultResultsCount = 3;
-
-class SearchResultWithMenu : public SearchResult {
- public:
- SearchResultWithMenu(const std::string& title, const std::string& details)
- : menu_model_(NULL),
- menu_ready_(true) {
- set_title(ASCIIToUTF16(title));
- set_details(ASCIIToUTF16(details));
- menu_model_.AddItem(0, UTF8ToUTF16("Menu For: " + title));
- }
-
- void SetMenuReadyForTesting(bool ready) {
- menu_ready_ = ready;
- }
-
- virtual ui::MenuModel* GetContextMenuModel() OVERRIDE {
- if (!menu_ready_)
- return NULL;
-
- return &menu_model_;
- }
-
- private:
- ui::SimpleMenuModel menu_model_;
- bool menu_ready_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchResultWithMenu);
-};
-
-class AppsSearchResultsControllerTest : public ui::CocoaTest {
- public:
- AppsSearchResultsControllerTest() {}
-
- void AddTestResultAtIndex(size_t index,
- const std::string& title,
- const std::string& details) {
- scoped_ptr<SearchResult> result(new SearchResultWithMenu(title, details));
- AppListModel::SearchResults* results = [delegate_ appListModel]->results();
- results->AddAt(index, result.release());
- }
-
- SearchResult* ModelResultAt(size_t index) {
- return [delegate_ appListModel]->results()->GetItemAt(index);
- }
-
- NSCell* ViewResultAt(NSInteger index) {
- NSTableView* table_view = [apps_search_results_controller_ tableView];
- return [table_view preparedCellAtColumn:0
- row:index];
- }
-
- void SetMenuReadyAt(size_t index, bool ready) {
- SearchResultWithMenu* result =
- static_cast<SearchResultWithMenu*>(ModelResultAt(index));
- result->SetMenuReadyForTesting(ready);
- }
-
- BOOL SimulateKeyAction(SEL c) {
- return [apps_search_results_controller_ handleCommandBySelector:c];
- }
-
- void ExpectConsistent();
-
- // ui::CocoaTest overrides:
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
-
- protected:
- base::scoped_nsobject<TestAppsSearchResultsDelegate> delegate_;
- base::scoped_nsobject<AppsSearchResultsController>
- apps_search_results_controller_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsControllerTest);
-};
-
-void AppsSearchResultsControllerTest::ExpectConsistent() {
- NSInteger item_count = [delegate_ appListModel]->results()->item_count();
- ASSERT_EQ(item_count,
- [[apps_search_results_controller_ tableView] numberOfRows]);
-
- // Compare content strings to ensure the order of items is consistent, and any
- // model data that should have been reloaded has been reloaded in the view.
- for (NSInteger i = 0; i < item_count; ++i) {
- SearchResult* result = ModelResultAt(i);
- base::string16 string_in_model = result->title();
- if (!result->details().empty())
- string_in_model += ASCIIToUTF16("\n") + result->details();
- EXPECT_NSEQ(base::SysUTF16ToNSString(string_in_model),
- [[ViewResultAt(i) attributedStringValue] string]);
- }
-}
-
-void AppsSearchResultsControllerTest::SetUp() {
- apps_search_results_controller_.reset(
- [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
- NSMakeSize(400, 400)]);
- // The view is initially hidden. Give it a non-zero height so it draws.
- [[apps_search_results_controller_ view] setFrameSize:NSMakeSize(400, 400)];
-
- delegate_.reset([[TestAppsSearchResultsDelegate alloc] init]);
-
- // Populate with some results so that TEST_VIEW does something non-trivial.
- for (int i = 0; i < kDefaultResultsCount; ++i)
- AddTestResultAtIndex(i, base::StringPrintf("Result %d", i), "ItemDetail");
-
- SearchResult::Tags test_tags;
- // Apply markup to the substring "Result" in the first item.
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::NONE, 0, 1));
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::URL, 1, 2));
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH, 2, 3));
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::DIM, 3, 4));
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
- SearchResult::Tag::URL, 4, 5));
- test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
- SearchResult::Tag::DIM, 5, 6));
-
- SearchResult* result = ModelResultAt(0);
- result->SetIcon(gfx::ImageSkiaFromNSImage(
- [NSImage imageNamed:NSImageNameStatusAvailable]));
- result->set_title_tags(test_tags);
-
- [apps_search_results_controller_ setDelegate:delegate_];
-
- ui::CocoaTest::SetUp();
- [[test_window() contentView] addSubview:
- [apps_search_results_controller_ view]];
-}
-
-void AppsSearchResultsControllerTest::TearDown() {
- [apps_search_results_controller_ setDelegate:nil];
- ui::CocoaTest::TearDown();
-}
-
-NSEvent* MouseEventInRow(NSTableView* table_view, NSInteger row_index) {
- NSRect row_rect = [table_view rectOfRow:row_index];
- NSPoint point_in_view = NSMakePoint(NSMidX(row_rect), NSMidY(row_rect));
- NSPoint point_in_window = [table_view convertPoint:point_in_view
- toView:nil];
- return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-} // namespace
-
-TEST_VIEW(AppsSearchResultsControllerTest,
- [apps_search_results_controller_ view]);
-
-TEST_F(AppsSearchResultsControllerTest, ModelObservers) {
- NSTableView* table_view = [apps_search_results_controller_ tableView];
- ExpectConsistent();
-
- EXPECT_EQ(1, [table_view numberOfColumns]);
- EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
-
- // Insert at start.
- AddTestResultAtIndex(0, "One", std::string());
- EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
- ExpectConsistent();
-
- // Remove from end.
- [delegate_ appListModel]->results()->DeleteAt(kDefaultResultsCount);
- EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
- ExpectConsistent();
-
- // Insert at end.
- AddTestResultAtIndex(kDefaultResultsCount, "Four", std::string());
- EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
- ExpectConsistent();
-
- // Delete from start.
- [delegate_ appListModel]->results()->DeleteAt(0);
- EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
- ExpectConsistent();
-
- // Test clearing results.
- [delegate_ appListModel]->results()->DeleteAll();
- EXPECT_EQ(0, [table_view numberOfRows]);
- ExpectConsistent();
-}
-
-TEST_F(AppsSearchResultsControllerTest, KeyboardSelectAndActivate) {
- NSTableView* table_view = [apps_search_results_controller_ tableView];
- EXPECT_EQ(-1, [table_view selectedRow]);
-
- // Pressing up when nothing is selected should select the last item.
- EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
- EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
- [table_view deselectAll:nil];
- EXPECT_EQ(-1, [table_view selectedRow]);
-
- // Pressing down when nothing is selected should select the first item.
- EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
- EXPECT_EQ(0, [table_view selectedRow]);
-
- // Pressing up should wrap around.
- EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
- EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
-
- // Down should now also wrap, since the selection is at the end.
- EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
- EXPECT_EQ(0, [table_view selectedRow]);
-
- // Regular down and up movement, ensuring the cells have correct backgrounds.
- EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
- EXPECT_EQ(1, [table_view selectedRow]);
- EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(1) backgroundStyle]);
- EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(0) backgroundStyle]);
-
- EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
- EXPECT_EQ(0, [table_view selectedRow]);
- EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(0) backgroundStyle]);
- EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(1) backgroundStyle]);
-
- // Test activating items.
- EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
- EXPECT_EQ(ModelResultAt(0), [delegate_ lastOpenedResult]);
- EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
- EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
- EXPECT_EQ(ModelResultAt(1), [delegate_ lastOpenedResult]);
-}
-
-TEST_F(AppsSearchResultsControllerTest, ContextMenus) {
- NSTableView* table_view = [apps_search_results_controller_ tableView];
- NSEvent* mouse_in_row_0 = MouseEventInRow(table_view, 0);
- NSEvent* mouse_in_row_1 = MouseEventInRow(table_view, 1);
-
- NSMenu* menu = [table_view menuForEvent:mouse_in_row_0];
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"Menu For: Result 0", [[menu itemAtIndex:0] title]);
-
- // Test a context menu request while the item is still installing.
- SetMenuReadyAt(1, false);
- menu = [table_view menuForEvent:mouse_in_row_1];
- EXPECT_EQ(nil, menu);
-
- SetMenuReadyAt(1, true);
- menu = [table_view menuForEvent:mouse_in_row_1];
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"Menu For: Result 1", [[menu itemAtIndex:0] title]);
-}
-
-// Test that observing a search result item uninstall performs the search again.
-TEST_F(AppsSearchResultsControllerTest, UninstallReperformsSearch) {
- base::MessageLoopForUI message_loop;
- EXPECT_EQ(0, [delegate_ redoSearchCount]);
- ModelResultAt(0)->NotifyItemUninstalled();
- [delegate_ performSelector:@selector(quitMessageLoop)
- withObject:nil
- afterDelay:0];
- message_loop.Run();
- EXPECT_EQ(1, [delegate_ redoSearchCount]);
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.h b/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.h
deleted file mode 100644
index 8939d260efb..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/base/models/list_model_observer.h"
-
-@class NSMenu;
-@class AppsSearchResultsController;
-
-namespace app_list {
-
-// Bridge observing the ListModel representing search results in the app list,
-// and updating the NSTableView where they are displayed.
-class AppsSearchResultsModelBridge : public ui::ListModelObserver {
- public:
- explicit AppsSearchResultsModelBridge(
- AppsSearchResultsController* results_controller);
- virtual ~AppsSearchResultsModelBridge();
-
- // Returns the context menu for the item at |index| in the search results
- // model. A menu will be generated if it hasn't been previously requested.
- NSMenu* MenuForItem(size_t index);
-
- private:
- // Lightweight observer to react to icon updates on individual results.
- class ItemObserver;
-
- void UpdateItemObservers();
- void ReloadDataForItems(size_t start, size_t count) const;
-
- // Overridden from ui::ListModelObserver:
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
- virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
-
- AppsSearchResultsController* parent_; // Weak. Owns us.
- ScopedVector<ItemObserver> item_observers_;
-
- DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsModelBridge);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
diff --git a/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.mm b/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.mm
deleted file mode 100644
index 69a3205ef06..00000000000
--- a/chromium/ui/app_list/cocoa/apps_search_results_model_bridge.mm
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/strings/sys_string_conversions.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-#include "ui/app_list/search_result.h"
-#include "ui/app_list/search_result_observer.h"
-#import "ui/base/cocoa/menu_controller.h"
-
-namespace app_list {
-
-class AppsSearchResultsModelBridge::ItemObserver : public SearchResultObserver {
- public:
- ItemObserver(AppsSearchResultsModelBridge* bridge, size_t index)
- : bridge_(bridge), row_in_view_(index) {
- // Cache the result, because the results array is updated before notifying
- // observers (which happens before deleting the SearchResult).
- result_ = [bridge_->parent_ results]->GetItemAt(index);
- result_->AddObserver(this);
- }
-
- virtual ~ItemObserver() {
- result_->RemoveObserver(this);
- }
-
- NSMenu* GetContextMenu() {
- if (!context_menu_controller_) {
- ui::MenuModel* menu_model = result_->GetContextMenuModel();
- if (!menu_model)
- return nil;
-
- context_menu_controller_.reset(
- [[MenuController alloc] initWithModel:menu_model
- useWithPopUpButtonCell:NO]);
- }
- return [context_menu_controller_ menu];
- }
-
- // SearchResultObserver overrides:
- virtual void OnIconChanged() OVERRIDE {
- bridge_->ReloadDataForItems(row_in_view_, 1);
- }
- virtual void OnActionsChanged() OVERRIDE {}
- virtual void OnIsInstallingChanged() OVERRIDE {}
- virtual void OnPercentDownloadedChanged() OVERRIDE {}
- virtual void OnItemInstalled() OVERRIDE {}
- virtual void OnItemUninstalled() OVERRIDE;
-
- private:
- AppsSearchResultsModelBridge* bridge_; // Weak. Owns us.
- SearchResult* result_; // Weak. Owned by AppListModel::SearchResults.
- size_t row_in_view_;
- base::scoped_nsobject<MenuController> context_menu_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(ItemObserver);
-};
-
-void AppsSearchResultsModelBridge::ItemObserver::OnItemUninstalled() {
- // Performing the search again will destroy |this|, so post a task. This also
- // ensures that the AppSearchProvider has observed the uninstall before
- // performing the search again, otherwise it will provide a NULL result.
- [[bridge_->parent_ delegate] performSelector:@selector(redoSearch)
- withObject:nil
- afterDelay:0];
-}
-
-AppsSearchResultsModelBridge::AppsSearchResultsModelBridge(
- AppsSearchResultsController* results_controller)
- : parent_(results_controller) {
- UpdateItemObservers();
- [parent_ results]->AddObserver(this);
-}
-
-AppsSearchResultsModelBridge::~AppsSearchResultsModelBridge() {
- [parent_ results]->RemoveObserver(this);
-}
-
-NSMenu* AppsSearchResultsModelBridge::MenuForItem(size_t index) {
- DCHECK_LT(index, item_observers_.size());
- return item_observers_[index]->GetContextMenu();
-}
-
-void AppsSearchResultsModelBridge::UpdateItemObservers() {
- DCHECK(item_observers_.empty());
- const size_t itemCount = [parent_ results]->item_count();
- for (size_t i = 0 ; i < itemCount; ++i)
- item_observers_.push_back(new ItemObserver(this, i));
-}
-
-void AppsSearchResultsModelBridge::ReloadDataForItems(
- size_t start, size_t count) const {
- NSIndexSet* column = [NSIndexSet indexSetWithIndex:0];
- NSIndexSet* rows =
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(start, count)];
- [[parent_ tableView] reloadDataForRowIndexes:rows
- columnIndexes:column];
-}
-
-void AppsSearchResultsModelBridge::ListItemsAdded(
- size_t start, size_t count) {
- item_observers_.clear();
- if (start == static_cast<size_t>([[parent_ tableView] numberOfRows]))
- [[parent_ tableView] noteNumberOfRowsChanged];
- else
- [[parent_ tableView] reloadData];
- UpdateItemObservers();
-}
-
-void AppsSearchResultsModelBridge::ListItemsRemoved(
- size_t start, size_t count) {
- item_observers_.clear();
- if (start == [parent_ results]->item_count())
- [[parent_ tableView] noteNumberOfRowsChanged];
- else
- [[parent_ tableView] reloadData];
- UpdateItemObservers();
-}
-
-void AppsSearchResultsModelBridge::ListItemMoved(
- size_t index, size_t target_index) {
- NOTREACHED();
-}
-
-void AppsSearchResultsModelBridge::ListItemsChanged(
- size_t start, size_t count) {
- item_observers_.clear();
- ReloadDataForItems(start, count);
- UpdateItemObservers();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/cocoa/item_drag_controller.h b/chromium/ui/app_list/cocoa/item_drag_controller.h
deleted file mode 100644
index 3e5b045b72e..00000000000
--- a/chromium/ui/app_list/cocoa/item_drag_controller.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-@class AppsGridViewItem;
-
-// Controller to manage the animations and transient views that are used when
-// dragging an app list item around the app list grid. When initiated, the item
-// image (only) is grown in an animation, and sticks to the mouse cursor. When
-// released, the label is added to the image and it shrinks and moves to the
-// item location in the grid.
-@interface ItemDragController : NSViewController {
- @private
- base::scoped_nsobject<CALayer> dragLayer_;
- base::scoped_nsobject<NSButton> buttonToRestore_;
- NSPoint mouseOffset_;
- NSTimeInterval growStart_;
- BOOL shrinking_;
-}
-
-- (id)initWithGridCellSize:(NSSize)size;
-
-- (void)initiate:(AppsGridViewItem*)item
- mouseDownLocation:(NSPoint)mouseDownLocation
- currentLocation:(NSPoint)currentLocation
- timestamp:(NSTimeInterval)eventTimestamp;
-
-- (void)update:(NSPoint)currentLocation
- timestamp:(NSTimeInterval)eventTimestamp;
-
-- (void)complete:(AppsGridViewItem*)item
- targetOrigin:(NSPoint)targetOrigin;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/item_drag_controller.mm b/chromium/ui/app_list/cocoa/item_drag_controller.mm
deleted file mode 100644
index 1de425b97d5..00000000000
--- a/chromium/ui/app_list/cocoa/item_drag_controller.mm
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/item_drag_controller.h"
-
-#include "base/logging.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#include "ui/base/cocoa/window_size_constants.h"
-
-// Scale to transform the grid cell when a drag starts. Note that 1.5 ensures
-// that integers are used for the layer bounds when the grid cell dimensions
-// are even.
-const CGFloat kDraggingIconScale = 1.5;
-
-const NSTimeInterval kAnimationDuration = 0.2;
-
-
-@interface ItemDragController ()
-
-- (void)animateTransformFrom:(CATransform3D)fromValue
- useDelegate:(BOOL)useDelegate;
-
-- (void)clearAnimations;
-
-@end
-
-@implementation ItemDragController
-
-- (id)initWithGridCellSize:(NSSize)size {
- if ((self = [super init])) {
- NSRect frameRect = NSMakeRect(0,
- 0,
- size.width * kDraggingIconScale,
- size.height * kDraggingIconScale);
- base::scoped_nsobject<NSView> dragView(
- [[NSView alloc] initWithFrame:frameRect]);
- [dragView setWantsLayer:YES];
- [dragView setHidden:YES];
-
- dragLayer_.reset([[CALayer layer] retain]);
- [dragLayer_ setFrame:NSRectToCGRect(frameRect)];
- [[dragView layer] addSublayer:dragLayer_];
-
- [self setView:dragView];
- }
- return self;
-}
-
-- (void)initiate:(AppsGridViewItem*)item
- mouseDownLocation:(NSPoint)mouseDownLocation
- currentLocation:(NSPoint)currentLocation
- timestamp:(NSTimeInterval)eventTimestamp {
- [self clearAnimations];
- NSView* itemView = [item view];
- NSPoint pointInGridCell = [itemView convertPoint:mouseDownLocation
- fromView:nil];
- mouseOffset_ = NSMakePoint(pointInGridCell.x - NSMidX([itemView bounds]),
- NSMidY([itemView bounds]) - pointInGridCell.y);
-
- NSBitmapImageRep* imageRep = [item dragRepresentationForRestore:NO];
- [dragLayer_ setContents:reinterpret_cast<id>([imageRep CGImage])];
- [dragLayer_ setTransform:CATransform3DIdentity];
-
- // Add a grow animation to the layer.
- CATransform3D growFrom = CATransform3DScale(CATransform3DIdentity,
- 1.0 / kDraggingIconScale,
- 1.0 / kDraggingIconScale,
- 1.0);
- [self animateTransformFrom:growFrom
- useDelegate:NO];
-
- growStart_ = eventTimestamp;
- [[self view] setHidden:NO];
-}
-
-- (void)update:(NSPoint)currentLocation
- timestamp:(NSTimeInterval)eventTimestamp {
- NSPoint pointInSuperview = [[[self view] superview]
- convertPoint:currentLocation
- fromView:nil];
- NSRect rect = [[self view] bounds];
- NSPoint anchor = NSMakePoint(NSMidX(rect), NSMidY(rect));
-
- // If the grow animation is still in progress, make the point of the image
- // that was clicked appear stuck to the mouse cursor.
- CGFloat progress = (eventTimestamp - growStart_) / kAnimationDuration;
- CGFloat currentIconScale = progress < 1.0 ?
- 1.0 + (kDraggingIconScale - 1.0) * progress :
- kDraggingIconScale;
-
- pointInSuperview.x -= (mouseOffset_.x * currentIconScale + anchor.x);
- pointInSuperview.y -= (mouseOffset_.y * currentIconScale + anchor.y);
- [[self view] setFrameOrigin:pointInSuperview];
-}
-
-- (void)complete:(AppsGridViewItem*)item
- targetOrigin:(NSPoint)targetOrigin {
- [self clearAnimations];
-
- NSView* itemView = [item view];
- NSBitmapImageRep* imageRep = [item dragRepresentationForRestore:YES];
-
- [dragLayer_ setContents:reinterpret_cast<id>([imageRep CGImage])];
- [dragLayer_ setTransform:CATransform3DScale(CATransform3DIdentity,
- 1.0 / kDraggingIconScale,
- 1.0 / kDraggingIconScale,
- 1.0)];
-
- // Retain the button so it can be unhidden when the animation completes. Note
- // that the |item| and corresponding button can differ from the |item| passed
- // to initiate(), if it moved to a new page during the drag. At this point the
- // destination page is known, so retain the button.
- buttonToRestore_.reset([[item button] retain]);
-
- // Add the shrink animation for the layer.
- [self animateTransformFrom:CATransform3DIdentity
- useDelegate:YES];
- shrinking_ = YES;
-
- // Also animate the translation, on the view.
- // TODO(tapted): This should be merged into the scale transform, instead of
- // using a separate NSViewAnimation.
- NSRect startRect = [[self view] frame];
-
- // The final position needs to be adjusted since it shrinks from each side.
- NSRect targetRect = NSMakeRect(
- targetOrigin.x - NSMidX([itemView bounds]) * (kDraggingIconScale - 1),
- targetOrigin.y - NSMidY([itemView bounds]) * (kDraggingIconScale - 1),
- startRect.size.width,
- startRect.size.height);
-
- NSDictionary* animationDict = @{
- NSViewAnimationTargetKey: [self view],
- NSViewAnimationStartFrameKey: [NSValue valueWithRect:startRect],
- NSViewAnimationEndFrameKey: [NSValue valueWithRect:targetRect]
- };
-
- base::scoped_nsobject<NSViewAnimation> translate([[NSViewAnimation alloc]
- initWithViewAnimations:[NSArray arrayWithObject:animationDict]]);
- [translate setDuration:kAnimationDuration];
- [translate startAnimation];
-}
-
-- (void)animateTransformFrom:(CATransform3D)fromValue
- useDelegate:(BOOL)useDelegate {
- CABasicAnimation* animation =
- [CABasicAnimation animationWithKeyPath:@"transform"];
- [animation setFromValue:[NSValue valueWithCATransform3D:fromValue]];
- if (useDelegate)
- [animation setDelegate:self];
-
- [animation setDuration:kAnimationDuration];
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithFloat:kAnimationDuration]
- forKey:kCATransactionAnimationDuration];
- [dragLayer_ addAnimation:animation
- forKey:@"transform"];
- [CATransaction commit];
-}
-
-- (void)clearAnimations {
- [dragLayer_ removeAllAnimations];
- if (!shrinking_)
- return;
-
- DCHECK(buttonToRestore_);
- [buttonToRestore_ setHidden:NO];
- buttonToRestore_.reset();
- shrinking_ = NO;
-}
-
-- (void)animationDidStop:(CAAnimation*)anim
- finished:(BOOL)finished {
- if (!finished)
- return;
-
- DCHECK(shrinking_);
- [self clearAnimations];
- [dragLayer_ setContents:nil];
- [[self view] setHidden:YES];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h b/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h
deleted file mode 100644
index 0697e24046f..00000000000
--- a/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
-#define UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
-
-#include <Cocoa/Cocoa.h>
-
-// Delegate to notify when a user interaction to scroll completes.
-@protocol GestureScrollDelegate
-
-// Called when a scroll gesture is observed, or when it completes.
-- (void)userScrolling:(BOOL)isScrolling;
-
-@end
-
-// NSScrollView has a quirk when created programatically that causes gesture
-// scrolling to fail if it does not have a scroll bar. This provides a scroll
-// view using custom scrollers that are not visible.
-@interface ScrollViewWithNoScrollbars : NSScrollView {
- @private
- id<GestureScrollDelegate> delegate_;
-}
-
-@property(assign, nonatomic) id<GestureScrollDelegate> delegate;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
diff --git a/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm b/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm
deleted file mode 100644
index b8d2da8bc81..00000000000
--- a/chromium/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/cocoa/scroll_view_with_no_scrollbars.h"
-
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
-
-#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
-enum {
- NSEventPhaseNone = 0,
- NSEventPhaseBegan = 0x1 << 0,
- NSEventPhaseStationary = 0x1 << 1,
- NSEventPhaseChanged = 0x1 << 2,
- NSEventPhaseEnded = 0x1 << 3,
- NSEventPhaseCancelled = 0x1 << 4,
-};
-typedef NSUInteger NSEventPhase;
-
-@interface NSEvent (LionAPI)
-
-- (NSEventPhase)momentumPhase;
-- (NSEventPhase)phase;
-
-@end
-
-#endif // 10.7
-
-@interface InvisibleScroller : NSScroller;
-@end
-
-@implementation InvisibleScroller
-
-// Makes it non-interactive (and invisible) on Lion with both 10.6 and 10.7
-// SDKs. TODO(tapted): Find a way to make it non-interactive on Snow Leopard.
-// TODO(tapted): Find a way to make it take up no space on Lion with a 10.6 SDK.
-- (NSRect)rectForPart:(NSScrollerPart)aPart {
- return NSZeroRect;
-}
-
-@end
-
-@implementation ScrollViewWithNoScrollbars
-
-@synthesize delegate = delegate_;
-
-- (id)initWithFrame:(NSRect)frame {
- if ((self = [super initWithFrame:frame])) {
- [self setHasHorizontalScroller:base::mac::IsOSLionOrLater()];
- NSRect horizontalScrollerRect = [self bounds];
- horizontalScrollerRect.size.height = 0;
- base::scoped_nsobject<InvisibleScroller> horizontalScroller(
- [[InvisibleScroller alloc] initWithFrame:horizontalScrollerRect]);
- [self setHorizontalScroller:horizontalScroller];
- }
- return self;
-}
-
-- (void)endGestureWithEvent:(NSEvent*)event {
- [super endGestureWithEvent:event];
- if (!base::mac::IsOSLionOrLater())
- [delegate_ userScrolling:NO];
-}
-
-- (void)scrollWheel:(NSEvent*)event {
- if ([event subtype] == NSMouseEventSubtype) {
- // Since the scroll view has no vertical scroller, regular up and down mouse
- // wheel events would be ignored. This maps mouse wheel events to a
- // horizontal scroll event of one line, to turn pages.
- BOOL downOrRight;
- if ([event deltaX] != 0)
- downOrRight = [event deltaX] > 0;
- else if ([event deltaY] != 0)
- downOrRight = [event deltaY] > 0;
- else
- return;
-
- base::ScopedCFTypeRef<CGEventRef> cgEvent(CGEventCreateScrollWheelEvent(
- NULL, kCGScrollEventUnitLine, 2, 0, downOrRight ? 1 : -1));
- [super scrollWheel:[NSEvent eventWithCGEvent:cgEvent]];
- return;
- }
-
- [super scrollWheel:event];
- if (![event respondsToSelector:@selector(momentumPhase)])
- return;
-
- BOOL scrollComplete = [event momentumPhase] == NSEventPhaseEnded ||
- ([event momentumPhase] == NSEventPhaseNone &&
- [event phase] == NSEventPhaseEnded);
-
- [delegate_ userScrolling:!scrollComplete];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/signin_view_controller.h b/chromium/ui/app_list/cocoa/signin_view_controller.h
deleted file mode 100644
index b03ac41799d..00000000000
--- a/chromium/ui/app_list/cocoa/signin_view_controller.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_COCOA_SIGNIN_VIEW_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_SIGNIN_VIEW_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-class SigninDelegate;
-}
-
-// Controller for the app list signin page. The signin view shows a blue button
-// that opens a browser window to conduct the signin flow. The delegate also
-// provides UI text and actions for the view, including "Learn More" and
-// "Settings" links.
-APP_LIST_EXPORT
-@interface SigninViewController : NSViewController {
- @private
- app_list::SigninDelegate* delegate_; // Weak. Owned by AppListViewDelegate.
-}
-
-- (id)initWithFrame:(NSRect)frame
- cornerRadius:(CGFloat)cornerRadius
- delegate:(app_list::SigninDelegate*)delegate;
-
-@end
-
-#endif // UI_APP_LIST_COCOA_SIGNIN_VIEW_CONTROLLER_H_
diff --git a/chromium/ui/app_list/cocoa/signin_view_controller.mm b/chromium/ui/app_list/cocoa/signin_view_controller.mm
deleted file mode 100644
index 39309586014..00000000000
--- a/chromium/ui/app_list/cocoa/signin_view_controller.mm
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/signin_view_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/signin_delegate.h"
-#import "ui/base/cocoa/controls/blue_label_button.h"
-#import "ui/base/cocoa/controls/hyperlink_button_cell.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace {
-
-const CGFloat kTopPadding = 40;
-const CGFloat kBottomPadding = 40;
-const CGFloat kLeftPadding = 40;
-const CGFloat kRightPadding = 40;
-const CGFloat kHeadingPadding = 30;
-const CGFloat kButtonPadding = 40;
-
-const CGFloat kTitleFontSizeDelta = 5;
-const SkColor kLinkColor = SkColorSetRGB(0x11, 0x55, 0xcc);
-const SkColor kTextColor = SkColorSetRGB(0x33, 0x33, 0x33);
-
-// Padding on the left of the text in the NSTextField and HyperlinkButtonCell.
-const CGFloat kTextFieldPadding = 2;
-
-} // namespace
-
-@interface SigninViewController ()
-
-- (void)onLearnMoreButtonClick:(id)sender;
-- (void)onSettingsButtonClick:(id)sender;
-- (void)onSigninButtonClick:(id)sender;
-- (NSButton*)makeLinkButtonWithTitle:(NSString*)title
- origin:(NSPoint)origin
- action:(SEL)action;
-- (NSTextField*)makeTextFieldWithText:(NSString*)text
- font:(NSFont*)font
- frame:(NSRect)frame;
-- (void)populateAndLayoutView;
-
-@end
-
-@interface AppsSigninView : NSView {
- @private
- CGFloat cornerRadius_;
-}
-
-@property(assign, nonatomic) CGFloat cornerRadius;
-
-@end
-
-@implementation SigninViewController;
-
-- (id)initWithFrame:(NSRect)frame
- cornerRadius:(CGFloat)cornerRadius
- delegate:(app_list::SigninDelegate*)delegate {
- if ((self = [super init])) {
- base::scoped_nsobject<AppsSigninView> appsSigninView(
- [[AppsSigninView alloc] initWithFrame:frame]);
- [appsSigninView setCornerRadius:cornerRadius];
- delegate_ = delegate;
- [self setView:appsSigninView];
- [self populateAndLayoutView];
- }
- return self;
-}
-
-- (void)onLearnMoreButtonClick:(id)sender {
- delegate_->OpenLearnMore();
-}
-
-- (void)onSettingsButtonClick:(id)sender {
- delegate_->OpenSettings();
-}
-
-- (void)onSigninButtonClick:(id)sender {
- delegate_->ShowSignin();
-}
-
-- (NSButton*)makeLinkButtonWithTitle:(NSString*)title
- origin:(NSPoint)origin
- action:(SEL)action {
- base::scoped_nsobject<NSButton> button(
- [[HyperlinkButtonCell buttonWithString:title] retain]);
- [[button cell] setShouldUnderline:NO];
- [[button cell] setTextColor:gfx::SkColorToSRGBNSColor(kLinkColor)];
- [button sizeToFit];
- origin.x -= kTextFieldPadding;
- [button setFrameOrigin:origin];
- [button setTarget:self];
- [button setAction:action];
- return button.autorelease();
-}
-
-- (NSTextField*)makeTextFieldWithText:(NSString*)text
- font:(NSFont*)font
- frame:(NSRect)frame {
- base::scoped_nsobject<NSTextField> textField(
- [[NSTextField alloc] initWithFrame:frame]);
- [textField setEditable:NO];
- [textField setSelectable:NO];
- [textField setDrawsBackground:NO];
- [textField setBezeled:NO];
-
- NSDictionary* textAttributes = @{
- NSFontAttributeName : font,
- NSForegroundColorAttributeName : gfx::SkColorToSRGBNSColor(kTextColor)
- };
- base::scoped_nsobject<NSAttributedString> attributedText(
- [[NSAttributedString alloc] initWithString:text
- attributes:textAttributes]);
- [textField setAttributedStringValue:attributedText];
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
- NSPoint origin = [textField frame].origin;
- origin.x -= kTextFieldPadding;
- origin.y -= NSHeight([textField bounds]);
- [textField setFrameOrigin:origin];
- return textField.autorelease();
-}
-
-- (void)populateAndLayoutView {
- NSView* signinView = [self view];
- NSRect frame = [signinView frame];
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- gfx::Font baseFont = rb.GetFont(ui::ResourceBundle::BaseFont);
-
- NSString* titleText = base::SysUTF16ToNSString(delegate_->GetSigninHeading());
- NSFont* titleFont = baseFont.DeriveFont(kTitleFontSizeDelta).GetNativeFont();
- NSRect rect = NSMakeRect(kLeftPadding, NSHeight(frame) - kTopPadding,
- NSWidth(frame) - kLeftPadding - kRightPadding, 0);
- NSTextField* titleTextView = [self makeTextFieldWithText:titleText
- font:titleFont
- frame:rect];
- [signinView addSubview:titleTextView];
-
- NSString* signinText = base::SysUTF16ToNSString(delegate_->GetSigninText());
- rect.origin.y = floor(
- NSMinY([titleTextView frame]) + [titleFont descender] - kHeadingPadding);
- NSFont* signinTextFont = baseFont.GetNativeFont();
- NSTextField* signinTextView = [self makeTextFieldWithText:signinText
- font:signinTextFont
- frame:rect];
- [signinView addSubview:signinTextView];
-
- base::scoped_nsobject<BlueLabelButton> button(
- [[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
- [button setTitle:base::SysUTF16ToNSString(delegate_->GetSigninButtonText())];
- [button setKeyEquivalent:@"\r"];
- [button setTarget:self];
- [button setAction:@selector(onSigninButtonClick:)];
- [button sizeToFit];
- NSPoint buttonOrigin = NSMakePoint(kLeftPadding, floor(
- NSMinY([signinTextView frame]) - [signinTextFont descender] -
- NSHeight([button frame]) - kButtonPadding));
- [button setFrameOrigin:buttonOrigin];
- [signinView addSubview:button];
-
- NSString* settingsLinkText =
- base::SysUTF16ToNSString(delegate_->GetSettingsLinkText());
- NSButton* settingsLink =
- [self makeLinkButtonWithTitle:settingsLinkText
- origin:NSMakePoint(kLeftPadding, kBottomPadding)
- action:@selector(onSettingsButtonClick:)];
- NSPoint origin = NSMakePoint(kLeftPadding,
- NSMaxY([settingsLink frame]));
- NSString* learnMoreLinkText =
- base::SysUTF16ToNSString(delegate_->GetLearnMoreLinkText());
- NSButton* learnMoreLink =
- [self makeLinkButtonWithTitle:learnMoreLinkText
- origin:origin
- action:@selector(onLearnMoreButtonClick:)];
- [signinView addSubview:learnMoreLink];
- [signinView addSubview:settingsLink];
-}
-
-@end
-
-@implementation AppsSigninView
-
-@synthesize cornerRadius = cornerRadius_;
-
-- (void)drawRect:(NSRect)dirtyRect {
- [gfx::SkColorToSRGBNSColor(app_list::kContentsBackgroundColor) set];
- [[NSBezierPath bezierPathWithRoundedRect:[self bounds]
- xRadius:cornerRadius_
- yRadius:cornerRadius_] fill];
-}
-
-@end
diff --git a/chromium/ui/app_list/cocoa/signin_view_controller_unittest.mm b/chromium/ui/app_list/cocoa/signin_view_controller_unittest.mm
deleted file mode 100644
index 70845df5d17..00000000000
--- a/chromium/ui/app_list/cocoa/signin_view_controller_unittest.mm
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/app_list/cocoa/signin_view_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/signin_delegate.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-
-@class TestSigninViewDelegate;
-
-namespace {
-
-// Helper function to cycle through the responder chain created implicitly
-// from subviews, without having to interact with the event system.
-NSControl* NextControl(NSControl* control) {
- NSArray* siblings = [[control superview] subviews];
- for (NSUInteger index = [siblings indexOfObject:control] + 1;
- index < [siblings count] ; ++index) {
- if ([[siblings objectAtIndex:index] acceptsFirstResponder])
- return [siblings objectAtIndex:index];
- }
- return nil;
-}
-
-} // namespace
-
-namespace app_list {
-namespace test {
-
-class SigninViewControllerTest : public ui::CocoaTest,
- public SigninDelegate {
- public:
- SigninViewControllerTest()
- : test_text_(ASCIIToUTF16("Sign in")),
- needs_signin_(true),
- show_signin_count_(0),
- open_learn_more_count_(0),
- open_settings_count_(0) {}
-
- // ui::CocoaTest override:
- virtual void SetUp() OVERRIDE;
-
- // SigninDelegate overrides:
- virtual bool NeedSignin() OVERRIDE { return needs_signin_; }
- virtual void ShowSignin() OVERRIDE { ++show_signin_count_; }
- virtual void OpenLearnMore() OVERRIDE { ++open_learn_more_count_; }
- virtual void OpenSettings() OVERRIDE { ++open_settings_count_; }
-
- virtual base::string16 GetSigninHeading() OVERRIDE { return test_text_; }
- virtual base::string16 GetSigninText() OVERRIDE { return test_text_; }
- virtual base::string16 GetSigninButtonText() OVERRIDE { return test_text_; }
- virtual base::string16 GetLearnMoreLinkText() OVERRIDE { return test_text_; }
- virtual base::string16 GetSettingsLinkText() OVERRIDE { return test_text_; }
-
- protected:
- const base::string16 test_text_;
- base::scoped_nsobject<SigninViewController> signin_view_controller_;
- bool needs_signin_;
- int show_signin_count_;
- int open_learn_more_count_;
- int open_settings_count_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SigninViewControllerTest);
-};
-
-void SigninViewControllerTest::SetUp() {
- NSRect frame = NSMakeRect(0, 0, 400, 500);
- signin_view_controller_.reset(
- [[SigninViewController alloc] initWithFrame:frame
- cornerRadius:3
- delegate:this]);
-
- ui::CocoaTest::SetUp();
- [[test_window() contentView] addSubview:[signin_view_controller_ view]];
-}
-
-TEST_VIEW(SigninViewControllerTest, [signin_view_controller_ view]);
-
-TEST_F(SigninViewControllerTest, NotSignedIn) {
- NSArray* content_subviews = [[test_window() contentView] subviews];
- EXPECT_EQ(1u, [content_subviews count]);
- NSArray* subviews = [[content_subviews objectAtIndex:0] subviews];
- EXPECT_LT(0u, [subviews count]);
-
- // The first subview that acceptFirstResponder should be the signin button,
- // and performing its action should show the signin dialog. Then "Learn more",
- // followed by "Settings".
- NSControl* control = NextControl([subviews objectAtIndex:0]);
- EXPECT_EQ(0, show_signin_count_);
- EXPECT_TRUE([[control target] performSelector:[control action]
- withObject:control]);
- EXPECT_EQ(1, show_signin_count_);
-
- control = NextControl(control);
- EXPECT_EQ(0, open_learn_more_count_);
- EXPECT_TRUE([[control target] performSelector:[control action]
- withObject:control]);
- EXPECT_EQ(1, open_learn_more_count_);
-
- control = NextControl(control);
- EXPECT_EQ(0, open_settings_count_);
- EXPECT_TRUE([[control target] performSelector:[control action]
- withObject:control]);
- EXPECT_EQ(1, open_settings_count_);
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/pagination_model.cc b/chromium/ui/app_list/pagination_model.cc
deleted file mode 100644
index 5e8d655a375..00000000000
--- a/chromium/ui/app_list/pagination_model.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/pagination_model.h"
-
-#include <algorithm>
-
-#include "ui/app_list/pagination_model_observer.h"
-#include "ui/gfx/animation/slide_animation.h"
-
-namespace app_list {
-
-PaginationModel::PaginationModel()
- : total_pages_(-1),
- selected_page_(-1),
- transition_(-1, 0),
- pending_selected_page_(-1),
- transition_duration_ms_(0),
- overscroll_transition_duration_ms_(0),
- last_overscroll_target_page_(0) {
-}
-
-PaginationModel::~PaginationModel() {
-}
-
-void PaginationModel::SetTotalPages(int total_pages) {
- if (total_pages == total_pages_)
- return;
-
- total_pages_ = total_pages;
- if (selected_page_ < 0)
- SelectPage(0, false /* animate */);
- if (selected_page_ >= total_pages_)
- SelectPage(std::max(total_pages_ - 1, 0), false /* animate */);
- FOR_EACH_OBSERVER(PaginationModelObserver, observers_, TotalPagesChanged());
-}
-
-void PaginationModel::SelectPage(int page, bool animate) {
- if (animate) {
- // -1 and |total_pages_| are valid target page for animation.
- DCHECK(page >= -1 && page <= total_pages_);
-
- if (!transition_animation_) {
- if (page == selected_page_)
- return;
-
- // Suppress over scroll animation if the same one happens too fast.
- if (!is_valid_page(page)) {
- const base::TimeTicks now = base::TimeTicks::Now();
-
- if (page == last_overscroll_target_page_) {
- const int kMinOverScrollTimeGapInMs = 500;
- const base::TimeDelta time_elapsed =
- now - last_overscroll_animation_start_time_;
- if (time_elapsed.InMilliseconds() < kMinOverScrollTimeGapInMs)
- return;
- }
-
- last_overscroll_target_page_ = page;
- last_overscroll_animation_start_time_ = now;
- }
-
- // Creates an animation if there is not one.
- StartTransitionAnimation(Transition(page, 0));
- return;
- } else {
- const bool showing = transition_animation_->IsShowing();
- const int from_page = showing ? selected_page_ : transition_.target_page;
- const int to_page = showing ? transition_.target_page : selected_page_;
-
- if (from_page == page) {
- if (showing)
- transition_animation_->Hide();
- else
- transition_animation_->Show();
- pending_selected_page_ = -1;
- } else if (to_page != page) {
- pending_selected_page_ = page;
- } else {
- pending_selected_page_ = -1;
- }
- }
- } else {
- DCHECK(total_pages_ == 0 || (page >= 0 && page < total_pages_));
-
- if (page == selected_page_)
- return;
-
- ResetTransitionAnimation();
-
- int old_selected = selected_page_;
- selected_page_ = page;
- NotifySelectedPageChanged(old_selected, selected_page_);
- }
-}
-
-void PaginationModel::SelectPageRelative(int delta, bool animate) {
- SelectPage(CalculateTargetPage(delta), animate);
-}
-
-void PaginationModel::SetTransition(const Transition& transition) {
- // -1 and |total_pages_| is a valid target page, which means user is at
- // the end and there is no target page for this scroll.
- DCHECK(transition.target_page >= -1 &&
- transition.target_page <= total_pages_);
- DCHECK(transition.progress >= 0 && transition.progress <= 1);
-
- if (transition_.Equals(transition))
- return;
-
- transition_ = transition;
- NotifyTransitionChanged();
-}
-
-void PaginationModel::SetTransitionDurations(int duration_ms,
- int overscroll_duration_ms) {
- transition_duration_ms_ = duration_ms;
- overscroll_transition_duration_ms_ = overscroll_duration_ms;
-}
-
-void PaginationModel::StartScroll() {
- // Cancels current transition animation (if any).
- transition_animation_.reset();
-}
-
-void PaginationModel::UpdateScroll(double delta) {
- // Translates scroll delta to desired page change direction.
- int page_change_dir = delta > 0 ? -1 : 1;
-
- // Initializes a transition if there is none.
- if (!has_transition())
- transition_.target_page = CalculateTargetPage(page_change_dir);
-
- // Updates transition progress.
- int transition_dir = transition_.target_page > selected_page_ ? 1 : -1;
- double progress = transition_.progress +
- fabs(delta) * page_change_dir * transition_dir;
-
- if (progress < 0) {
- if (transition_.progress) {
- transition_.progress = 0;
- NotifyTransitionChanged();
- }
- clear_transition();
- } else if (progress > 1) {
- if (is_valid_page(transition_.target_page)) {
- SelectPage(transition_.target_page, false);
- clear_transition();
- }
- } else {
- transition_.progress = progress;
- NotifyTransitionChanged();
- }
-}
-
-void PaginationModel::EndScroll(bool cancel) {
- if (!has_transition())
- return;
-
- StartTransitionAnimation(transition_);
-
- if (cancel)
- transition_animation_->Hide();
-}
-
-bool PaginationModel::IsRevertingCurrentTransition() const {
- // Use !IsShowing() so that we return true at the end of hide animation.
- return transition_animation_ && !transition_animation_->IsShowing();
-}
-
-void PaginationModel::AddObserver(PaginationModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void PaginationModel::RemoveObserver(PaginationModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void PaginationModel::NotifySelectedPageChanged(int old_selected,
- int new_selected) {
- FOR_EACH_OBSERVER(PaginationModelObserver,
- observers_,
- SelectedPageChanged(old_selected, new_selected));
-}
-
-void PaginationModel::NotifyTransitionStarted() {
- FOR_EACH_OBSERVER(PaginationModelObserver, observers_, TransitionStarted());
-}
-
-void PaginationModel::NotifyTransitionChanged() {
- FOR_EACH_OBSERVER(PaginationModelObserver, observers_, TransitionChanged());
-}
-
-int PaginationModel::CalculateTargetPage(int delta) const {
- DCHECK_GT(total_pages_, 0);
-
- int current_page = selected_page_;
- if (transition_animation_ && transition_animation_->IsShowing()) {
- current_page = pending_selected_page_ >= 0 ?
- pending_selected_page_ : transition_.target_page;
- }
-
- const int target_page = current_page + delta;
-
- int start_page = 0;
- int end_page = total_pages_ - 1;
-
- // Use invalid page when |selected_page_| is at ends.
- if (target_page < start_page && selected_page_ == start_page)
- start_page = -1;
- else if (target_page > end_page && selected_page_ == end_page)
- end_page = total_pages_;
-
- return std::max(start_page, std::min(end_page, target_page));
-}
-
-void PaginationModel::StartTransitionAnimation(const Transition& transition) {
- DCHECK(selected_page_ != transition.target_page);
-
- NotifyTransitionStarted();
- SetTransition(transition);
-
- transition_animation_.reset(new gfx::SlideAnimation(this));
- transition_animation_->SetTweenType(gfx::Tween::LINEAR);
- transition_animation_->Reset(transition_.progress);
-
- const int duration = is_valid_page(transition_.target_page) ?
- transition_duration_ms_ : overscroll_transition_duration_ms_;
- if (duration)
- transition_animation_->SetSlideDuration(duration);
-
- transition_animation_->Show();
-}
-
-void PaginationModel::ResetTransitionAnimation() {
- transition_animation_.reset();
- transition_.target_page = -1;
- transition_.progress = 0;
- pending_selected_page_ = -1;
-}
-
-void PaginationModel::AnimationProgressed(const gfx::Animation* animation) {
- transition_.progress = transition_animation_->GetCurrentValue();
- NotifyTransitionChanged();
-}
-
-void PaginationModel::AnimationEnded(const gfx::Animation* animation) {
- // Save |pending_selected_page_| because SelectPage resets it.
- int next_target = pending_selected_page_;
-
- if (transition_animation_->GetCurrentValue() == 1) {
- // Showing animation ends.
- if (!is_valid_page(transition_.target_page)) {
- // If target page is not in valid range, reverse the animation.
- transition_animation_->Hide();
- return;
- }
-
- // Otherwise, change page and finish the transition.
- DCHECK(selected_page_ != transition_.target_page);
- SelectPage(transition_.target_page, false /* animate */);
- } else if (transition_animation_->GetCurrentValue() == 0) {
- // Hiding animation ends. No page change should happen.
- ResetTransitionAnimation();
- }
-
- if (next_target >= 0)
- SelectPage(next_target, true);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/pagination_model.h b/chromium/ui/app_list/pagination_model.h
deleted file mode 100644
index 0546adc4bf8..00000000000
--- a/chromium/ui/app_list/pagination_model.h
+++ /dev/null
@@ -1,144 +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_APP_LIST_PAGINATION_MODEL_H_
-#define UI_APP_LIST_PAGINATION_MODEL_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "base/time/time.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/gfx/animation/animation_delegate.h"
-
-namespace gfx {
-class SlideAnimation;
-}
-
-namespace app_list {
-
-class PaginationModelObserver;
-
-// A simple pagination model that consists of two numbers: the total pages and
-// the currently selected page. The model is a single selection model that at
-// the most one page can become selected at any time.
-class APP_LIST_EXPORT PaginationModel : public gfx::AnimationDelegate {
- public:
- // Holds info for transition animation and touch scroll.
- struct Transition {
- Transition(int target_page, double progress)
- : target_page(target_page),
- progress(progress) {
- }
-
- bool Equals(const Transition& rhs) const {
- return target_page == rhs.target_page && progress == rhs.progress;
- }
-
- // Target page for the transition or -1 if there is no target page. For
- // page switcher, this is the target selected page. For touch scroll,
- // this is usually the previous or next page (or -1 when there is no
- // previous or next page).
- int target_page;
-
- // A [0, 1] progress indicates how much of the current page is being
- // transitioned.
- double progress;
- };
-
- PaginationModel();
- virtual ~PaginationModel();
-
- void SetTotalPages(int total_pages);
-
- // Selects a page. |animate| is true if the transition should be animated.
- void SelectPage(int page, bool animate);
-
- // Selects a page by relative |delta|.
- void SelectPageRelative(int delta, bool animate);
-
- void SetTransition(const Transition& transition);
- void SetTransitionDurations(int duration_ms, int overscroll_duration_ms);
-
- // Starts a scroll transition. If there is a running transition animation,
- // cancels it but keeps the transition info.
- void StartScroll();
-
- // Updates transition progress from |delta|. |delta| > 0 means transit to
- // previous page (moving pages to the right). |delta| < 0 means transit
- // to next page (moving pages to the left).
- void UpdateScroll(double delta);
-
- // Finishes the current scroll transition if |cancel| is false. Otherwise,
- // reverses it.
- void EndScroll(bool cancel);
-
- // Returns true if current transition is being reverted.
- bool IsRevertingCurrentTransition() const;
-
- void AddObserver(PaginationModelObserver* observer);
- void RemoveObserver(PaginationModelObserver* observer);
-
- int total_pages() const { return total_pages_; }
- int selected_page() const { return selected_page_; }
- const Transition& transition() const { return transition_; }
-
- bool is_valid_page(int page) const {
- return page >= 0 && page < total_pages_;
- }
-
- bool has_transition() const {
- return transition_.target_page != -1 || transition_.progress != 0;
- }
-
- private:
- void NotifySelectedPageChanged(int old_selected, int new_selected);
- void NotifyTransitionStarted();
- void NotifyTransitionChanged();
-
- void clear_transition() {
- SetTransition(Transition(-1, 0));
- }
-
- // Calculates a target page number by combining current page and |delta|.
- // When there is no transition, current page is the currently selected page.
- // If there is a transition, current page is the transition target page or the
- // pending transition target page. When current page + |delta| goes beyond
- // valid range and |selected_page_| is at the range ends, invalid page number
- // -1 or |total_pages_| is returned to indicate the situation.
- int CalculateTargetPage(int delta) const;
-
- void StartTransitionAnimation(const Transition& transition);
- void ResetTransitionAnimation();
-
- // gfx::AnimationDelegate overrides:
- virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
- virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
-
- int total_pages_;
- int selected_page_;
-
- Transition transition_;
-
- // Pending selected page when SelectedPage is called during a transition. If
- // multiple SelectPage is called while a transition is in progress, only the
- // last target page is remembered here.
- int pending_selected_page_;
-
- scoped_ptr<gfx::SlideAnimation> transition_animation_;
- int transition_duration_ms_; // Transition duration in millisecond.
- int overscroll_transition_duration_ms_;
-
- int last_overscroll_target_page_;
- base::TimeTicks last_overscroll_animation_start_time_;
-
- ObserverList<PaginationModelObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(PaginationModel);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_PAGINATION_MODEL_H_
diff --git a/chromium/ui/app_list/pagination_model_observer.h b/chromium/ui/app_list/pagination_model_observer.h
deleted file mode 100644
index ee594eca893..00000000000
--- a/chromium/ui/app_list/pagination_model_observer.h
+++ /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.
-
-#ifndef UI_APP_LIST_PAGINATION_MODEL_OBSERVER_H_
-#define UI_APP_LIST_PAGINATION_MODEL_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT PaginationModelObserver {
- public:
- // Invoked when the total number of page is changed.
- virtual void TotalPagesChanged() = 0;
-
- // Invoked when the selected page index is changed.
- virtual void SelectedPageChanged(int old_selected, int new_selected) = 0;
-
- // Invoked when a transition starts.
- virtual void TransitionStarted() = 0;
-
- // Invoked when the transition data is changed.
- virtual void TransitionChanged() = 0;
-
- protected:
- virtual ~PaginationModelObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_PAGINATION_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/pagination_model_unittest.cc b/chromium/ui/app_list/pagination_model_unittest.cc
deleted file mode 100644
index 391ed871f6e..00000000000
--- a/chromium/ui/app_list/pagination_model_unittest.cc
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/pagination_model.h"
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/pagination_model_observer.h"
-
-namespace app_list {
-namespace test {
-
-class TestPaginationModelObserver : public PaginationModelObserver {
- public:
- TestPaginationModelObserver()
- : model_(NULL),
- expected_page_selection_(0),
- expected_transition_start_(0),
- expected_transition_end_(0),
- transition_page_(-1) {
- Reset();
- }
- virtual ~TestPaginationModelObserver() {}
-
- void Reset() {
- selection_count_ = 0;
- transition_start_count_ = 0;
- transition_end_count_ = 0;
- selected_pages_.clear();
- }
-
- void set_model(PaginationModel* model) { model_ = model; }
-
- void set_expected_page_selection(int expected_page_selection) {
- expected_page_selection_ = expected_page_selection;
- }
- void set_expected_transition_start(int expected_transition_start) {
- expected_transition_start_ = expected_transition_start;
- }
- void set_expected_transition_end(int expected_transition_end) {
- expected_transition_end_ = expected_transition_end;
- }
- void set_transition_page(int page) { transition_page_ = page; }
-
- const std::string& selected_pages() const { return selected_pages_; }
- int selection_count() const { return selection_count_; }
- int transition_start_count() const { return transition_start_count_; }
- int transition_end_count() const { return transition_end_count_; }
-
- private:
- void AppendSelectedPage(int page) {
- if (selected_pages_.length())
- selected_pages_.append(std::string(" "));
- selected_pages_.append(base::StringPrintf("%d", page));
- }
-
- // PaginationModelObserver overrides:
- virtual void TotalPagesChanged() OVERRIDE {}
- virtual void SelectedPageChanged(int old_selected,
- int new_selected) OVERRIDE {
- AppendSelectedPage(new_selected);
- ++selection_count_;
- if (expected_page_selection_ &&
- selection_count_ == expected_page_selection_) {
- base::MessageLoop::current()->Quit();
- }
- }
-
- virtual void TransitionStarted() OVERRIDE {
- }
-
- virtual void TransitionChanged() OVERRIDE {
- if (transition_page_ == -1 ||
- model_->transition().target_page == transition_page_) {
- if (model_->transition().progress == 0)
- ++transition_start_count_;
- if (model_->transition().progress == 1)
- ++transition_end_count_;
- }
-
- if ((expected_transition_start_ &&
- transition_start_count_ == expected_transition_start_) ||
- (expected_transition_end_ &&
- transition_end_count_ == expected_transition_end_)) {
- base::MessageLoop::current()->Quit();
- }
- }
-
- PaginationModel* model_;
-
- int expected_page_selection_;
- int expected_transition_start_;
- int expected_transition_end_;
-
- int selection_count_;
- int transition_start_count_;
- int transition_end_count_;
-
- // Indicate which page index should be counted for |transition_start_count_|
- // and |transition_end_count_|. -1 means all the pages should be counted.
- int transition_page_;
-
- std::string selected_pages_;
-
- DISALLOW_COPY_AND_ASSIGN(TestPaginationModelObserver);
-};
-
-class PaginationModelTest : public testing::Test {
- public:
- PaginationModelTest() {}
- virtual ~PaginationModelTest() {}
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- pagination_.SetTotalPages(5);
- pagination_.SetTransitionDurations(1, 1);
- observer_.set_model(&pagination_);
- pagination_.AddObserver(&observer_);
- }
- virtual void TearDown() OVERRIDE {
- pagination_.RemoveObserver(&observer_);
- observer_.set_model(NULL);
- }
-
- protected:
- void SetStartPageAndExpects(int start_page,
- int expected_selection,
- int expected_transition_start,
- int expected_transition_end) {
- observer_.set_expected_page_selection(0);
- pagination_.SelectPage(start_page, false /* animate */);
- observer_.Reset();
- observer_.set_expected_page_selection(expected_selection);
- observer_.set_expected_transition_start(expected_transition_start);
- observer_.set_expected_transition_end(expected_transition_end);
- }
-
- PaginationModel pagination_;
- TestPaginationModelObserver observer_;
-
- private:
- base::MessageLoopForUI message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(PaginationModelTest);
-};
-
-TEST_F(PaginationModelTest, SelectPage) {
- pagination_.SelectPage(2, false /* animate */);
- pagination_.SelectPage(4, false /* animate */);
- pagination_.SelectPage(3, false /* animate */);
- pagination_.SelectPage(1, false /* animate */);
-
- EXPECT_EQ(0, observer_.transition_start_count());
- EXPECT_EQ(0, observer_.transition_end_count());
- EXPECT_EQ(4, observer_.selection_count());
- EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages());
-
- // Nothing happens if select the same page.
- pagination_.SelectPage(1, false /* animate */);
- EXPECT_EQ(4, observer_.selection_count());
- EXPECT_EQ(std::string("2 4 3 1"), observer_.selected_pages());
-}
-
-TEST_F(PaginationModelTest, SelectPageAnimated) {
- const int kStartPage = 0;
-
- // One transition.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SelectPage(1, true /* animate */);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.transition_start_count());
- EXPECT_EQ(1, observer_.transition_end_count());
- EXPECT_EQ(1, observer_.selection_count());
- EXPECT_EQ(std::string("1"), observer_.selected_pages());
-
- // Two transitions in a row.
- SetStartPageAndExpects(kStartPage, 2, 0, 0);
- pagination_.SelectPage(1, true /* animate */);
- pagination_.SelectPage(3, true /* animate */);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(2, observer_.transition_start_count());
- EXPECT_EQ(2, observer_.transition_end_count());
- EXPECT_EQ(2, observer_.selection_count());
- EXPECT_EQ(std::string("1 3"), observer_.selected_pages());
-
- // Transition to same page twice and only one should happen.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SelectPage(1, true /* animate */);
- pagination_.SelectPage(1, true /* animate */); // Ignored.
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.transition_start_count());
- EXPECT_EQ(1, observer_.transition_end_count());
- EXPECT_EQ(1, observer_.selection_count());
- EXPECT_EQ(std::string("1"), observer_.selected_pages());
-
- // More than two transitions and only the first and last would happen.
- SetStartPageAndExpects(kStartPage, 2, 0, 0);
- pagination_.SelectPage(1, true /* animate */);
- pagination_.SelectPage(3, true /* animate */); // Ignored
- pagination_.SelectPage(4, true /* animate */); // Ignored
- pagination_.SelectPage(2, true /* animate */);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(2, observer_.transition_start_count());
- EXPECT_EQ(2, observer_.transition_end_count());
- EXPECT_EQ(2, observer_.selection_count());
- EXPECT_EQ(std::string("1 2"), observer_.selected_pages());
-
- // Multiple transitions with one transition that goes back to the original
- // and followed by a new transition. Two transitions would happen. The first
- // one will be reversed by the kStart transition and the second one will be
- // finished.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SelectPage(1, true /* animate */);
- pagination_.SelectPage(2, true /* animate */); // Ignored
- pagination_.SelectPage(kStartPage, true /* animate */);
- pagination_.SelectPage(3, true /* animate */);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(std::string("3"), observer_.selected_pages());
-}
-
-TEST_F(PaginationModelTest, SimpleScroll) {
- const int kStartPage = 2;
-
- // Scroll to the next page (negative delta) and finish it.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- pagination_.EndScroll(false); // Finish transition
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-
- // Scroll to the previous page (positive delta) and finish it.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- pagination_.EndScroll(false); // Finish transition
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-
- // Scroll to the next page (negative delta) and cancel it.
- SetStartPageAndExpects(kStartPage, 0, 1, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- pagination_.EndScroll(true); // Cancel transition
- base::MessageLoop::current()->Run();
- EXPECT_EQ(0, observer_.selection_count());
-
- // Scroll to the previous page (position delta) and cancel it.
- SetStartPageAndExpects(kStartPage, 0, 1, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- pagination_.EndScroll(true); // Cancel transition
- base::MessageLoop::current()->Run();
- EXPECT_EQ(0, observer_.selection_count());
-}
-
-TEST_F(PaginationModelTest, ScrollWithTransition) {
- const int kStartPage = 2;
-
- // Scroll to the next page (negative delta) with a transition in the same
- // direction.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- EXPECT_EQ(0.6, pagination_.transition().progress);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-
- // Scroll to the next page (negative delta) with a transition in a different
- // direction.
- SetStartPageAndExpects(kStartPage, 0, 1, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- EXPECT_EQ(0.4, pagination_.transition().progress);
- pagination_.EndScroll(true);
-
- // Scroll to the previous page (positive delta) with a transition in the same
- // direction.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- EXPECT_EQ(0.6, pagination_.transition().progress);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-
- // Scroll to the previous page (positive delta) with a transition in a
- // different direction.
- SetStartPageAndExpects(kStartPage, 0, 1, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- EXPECT_EQ(0.4, pagination_.transition().progress);
- pagination_.EndScroll(true);
-}
-
-TEST_F(PaginationModelTest, LongScroll) {
- const int kStartPage = 2;
-
- // Scroll to the next page (negative delta) with a transition in the same
- // direction. And scroll enough to change page twice.
- SetStartPageAndExpects(kStartPage, 2, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- EXPECT_EQ(0.6, pagination_.transition().progress);
- pagination_.UpdateScroll(-0.5);
- EXPECT_EQ(1, observer_.selection_count());
- pagination_.UpdateScroll(-0.5);
- EXPECT_EQ(kStartPage + 2, pagination_.transition().target_page);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(2, observer_.selection_count());
-
- // Scroll to the next page (negative delta) with a transition in a different
- // direction. And scroll enough to revert it and switch page once.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- EXPECT_EQ(0.4, pagination_.transition().progress);
- pagination_.UpdateScroll(-0.5); // This clears the transition.
- pagination_.UpdateScroll(-0.5); // This starts a new transition.
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-
- // Similar cases as above but in the opposite direction.
- // Scroll to the previous page (positive delta) with a transition in the same
- // direction. And scroll enough to change page twice.
- SetStartPageAndExpects(kStartPage, 2, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage - 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- EXPECT_EQ(0.6, pagination_.transition().progress);
- pagination_.UpdateScroll(0.5);
- EXPECT_EQ(1, observer_.selection_count());
- pagination_.UpdateScroll(0.5);
- EXPECT_EQ(kStartPage - 2, pagination_.transition().target_page);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(2, observer_.selection_count());
-
- // Scroll to the previous page (positive delta) with a transition in a
- // different direction. And scroll enough to revert it and switch page once.
- SetStartPageAndExpects(kStartPage, 1, 0, 0);
- pagination_.SetTransition(PaginationModel::Transition(kStartPage + 1, 0.5));
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
- EXPECT_EQ(kStartPage + 1, pagination_.transition().target_page);
- EXPECT_EQ(0.4, pagination_.transition().progress);
- pagination_.UpdateScroll(0.5); // This clears the transition.
- pagination_.UpdateScroll(0.5); // This starts a new transition.
- EXPECT_EQ(kStartPage - 1, pagination_.transition().target_page);
- pagination_.EndScroll(false);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(1, observer_.selection_count());
-}
-
-TEST_F(PaginationModelTest, FireTransitionZero) {
- const int kStartPage = 2;
-
- // Scroll to next page then revert the scroll and make sure transition
- // progress 0 is fired when previous scroll is cleared.
- SetStartPageAndExpects(kStartPage, 0, 0, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(-0.1);
-
- int target_page = kStartPage + 1;
- EXPECT_EQ(target_page, pagination_.transition().target_page);
- observer_.set_transition_page(target_page);
-
- pagination_.UpdateScroll(0.2); // This clears the transition.
- EXPECT_EQ(1, observer_.transition_start_count());
- pagination_.EndScroll(true); // Cancel transition.
-
- // Similar to above but in the other direction.
- SetStartPageAndExpects(kStartPage, 0, 0, 0);
- pagination_.StartScroll();
- pagination_.UpdateScroll(0.1);
-
- target_page = kStartPage - 1;
- EXPECT_EQ(target_page, pagination_.transition().target_page);
- observer_.set_transition_page(target_page);
-
- pagination_.UpdateScroll(-0.2); // This clears the transition.
- EXPECT_EQ(1, observer_.transition_start_count());
- pagination_.EndScroll(true); // Cancel transition.
-}
-
-TEST_F(PaginationModelTest, SelectedPageIsLost) {
- pagination_.SetTotalPages(2);
- // The selected page is set to 0 once the total number of pages are set.
- EXPECT_EQ(0, pagination_.selected_page());
-
- pagination_.SelectPage(1, false /* animate */);
- EXPECT_EQ(1, pagination_.selected_page());
-
- // The selected page is unchanged if it's still valid.
- pagination_.SetTotalPages(3);
- EXPECT_EQ(1, pagination_.selected_page());
- pagination_.SetTotalPages(2);
- EXPECT_EQ(1, pagination_.selected_page());
-
- // But if the currently selected_page exceeds the total number of pages,
- // it automatically switches to the last page.
- pagination_.SetTotalPages(1);
- EXPECT_EQ(0, pagination_.selected_page());
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/search_box_model.cc b/chromium/ui/app_list/search_box_model.cc
deleted file mode 100644
index cd884a7d20d..00000000000
--- a/chromium/ui/app_list/search_box_model.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/search_box_model.h"
-
-#include "base/metrics/histogram.h"
-#include "ui/app_list/search_box_model_observer.h"
-
-namespace app_list {
-
-SearchBoxModel::ButtonProperty::ButtonProperty(
- const gfx::ImageSkia& icon,
- const base::string16& tooltip)
- : icon(icon),
- tooltip(tooltip) {
-}
-
-SearchBoxModel::ButtonProperty::~ButtonProperty() {
-}
-
-SearchBoxModel::SearchBoxModel() {
-}
-
-SearchBoxModel::~SearchBoxModel() {
-}
-
-void SearchBoxModel::SetIcon(const gfx::ImageSkia& icon) {
- icon_ = icon;
- FOR_EACH_OBSERVER(SearchBoxModelObserver, observers_, IconChanged());
-}
-
-void SearchBoxModel::SetSpeechRecognitionButton(
- scoped_ptr<SearchBoxModel::ButtonProperty> speech_button) {
- speech_button_ = speech_button.Pass();
- FOR_EACH_OBSERVER(SearchBoxModelObserver,
- observers_,
- SpeechRecognitionButtonPropChanged());
-}
-
-void SearchBoxModel::SetHintText(const base::string16& hint_text) {
- if (hint_text_ == hint_text)
- return;
-
- hint_text_ = hint_text;
- FOR_EACH_OBSERVER(SearchBoxModelObserver, observers_, HintTextChanged());
-}
-
-void SearchBoxModel::SetSelectionModel(const gfx::SelectionModel& sel) {
- if (selection_model_ == sel)
- return;
-
- selection_model_ = sel;
- FOR_EACH_OBSERVER(SearchBoxModelObserver,
- observers_,
- SelectionModelChanged());
-}
-
-void SearchBoxModel::SetText(const base::string16& text) {
- if (text_ == text)
- return;
-
- // Log that a new search has been commenced whenever the text box text
- // transitions from empty to non-empty.
- if (text_.empty() && !text.empty()) {
- UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchCommenced", 1, 2);
- }
- text_ = text;
- FOR_EACH_OBSERVER(SearchBoxModelObserver, observers_, TextChanged());
-}
-
-void SearchBoxModel::AddObserver(SearchBoxModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void SearchBoxModel::RemoveObserver(SearchBoxModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/search_box_model.h b/chromium/ui/app_list/search_box_model.h
deleted file mode 100644
index 1c174819bf5..00000000000
--- a/chromium/ui/app_list/search_box_model.h
+++ /dev/null
@@ -1,77 +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_APP_LIST_SEARCH_BOX_MODEL_H_
-#define UI_APP_LIST_SEARCH_BOX_MODEL_H_
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/selection_model.h"
-
-namespace app_list {
-
-class SearchBoxModelObserver;
-
-// SearchBoxModel consisits of an icon, a hint text, a user text and a selection
-// model. The icon is rendered to the side of the query editor. The hint text
-// is used as query edit control's placeholder text and displayed when there is
-// no user text in the control. The selection model and the text represents the
-// text, cursor position and selected text in edit control.
-class APP_LIST_EXPORT SearchBoxModel {
- public:
- // The properties of the button.
- struct APP_LIST_EXPORT ButtonProperty {
- ButtonProperty(const gfx::ImageSkia& icon, const base::string16& tooltip);
- ~ButtonProperty();
-
- gfx::ImageSkia icon;
- base::string16 tooltip;
- };
-
- SearchBoxModel();
- ~SearchBoxModel();
-
- // Sets/gets the icon on the left side of edit box.
- void SetIcon(const gfx::ImageSkia& icon);
- const gfx::ImageSkia& icon() const { return icon_; }
-
- // Sets/gets the properties for the button of speech recognition.
- void SetSpeechRecognitionButton(scoped_ptr<ButtonProperty> speech_button);
- const ButtonProperty* speech_button() const { return speech_button_.get(); }
-
- // Sets/gets the hint text to display when there is in input.
- void SetHintText(const base::string16& hint_text);
- const base::string16& hint_text() const { return hint_text_; }
-
- // Sets/gets the selection model for the search box's Textfield.
- void SetSelectionModel(const gfx::SelectionModel& sel);
- const gfx::SelectionModel& selection_model() const {
- return selection_model_;
- }
-
- // Sets/gets the text for the search box's Textfield.
- void SetText(const base::string16& text);
- const base::string16& text() const { return text_; }
-
- void AddObserver(SearchBoxModelObserver* observer);
- void RemoveObserver(SearchBoxModelObserver* observer);
-
- private:
- gfx::ImageSkia icon_;
- scoped_ptr<ButtonProperty> speech_button_;
- base::string16 hint_text_;
- gfx::SelectionModel selection_model_;
- base::string16 text_;
-
- ObserverList<SearchBoxModelObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchBoxModel);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SEARCH_BOX_MODEL_H_
diff --git a/chromium/ui/app_list/search_box_model_observer.h b/chromium/ui/app_list/search_box_model_observer.h
deleted file mode 100644
index a903dbc03cf..00000000000
--- a/chromium/ui/app_list/search_box_model_observer.h
+++ /dev/null
@@ -1,36 +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_APP_LIST_SEARCH_BOX_MODEL_OBSERVER_H_
-#define UI_APP_LIST_SEARCH_BOX_MODEL_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT SearchBoxModelObserver {
- public:
- // Invoked when icon is changed.
- virtual void IconChanged() = 0;
-
- // Invoked when the some properties of the speech recognition button is
- // changed.
- virtual void SpeechRecognitionButtonPropChanged() = 0;
-
- // Invoked when hint text is changed.
- virtual void HintTextChanged() = 0;
-
- // Invoked when selection model is changed.
- virtual void SelectionModelChanged() = 0;
-
- // Invoked when text is changed.
- virtual void TextChanged() = 0;
-
- protected:
- virtual ~SearchBoxModelObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SEARCH_BOX_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/search_result.cc b/chromium/ui/app_list/search_result.cc
deleted file mode 100644
index cf908300ea3..00000000000
--- a/chromium/ui/app_list/search_result.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/search_result.h"
-
-#include "ui/app_list/search_result_observer.h"
-
-namespace app_list {
-
-SearchResult::Action::Action(const gfx::ImageSkia& base_image,
- const gfx::ImageSkia& hover_image,
- const gfx::ImageSkia& pressed_image,
- const base::string16& tooltip_text)
- : base_image(base_image),
- hover_image(hover_image),
- pressed_image(pressed_image),
- tooltip_text(tooltip_text) {}
-
-SearchResult::Action::Action(const base::string16& label_text,
- const base::string16& tooltip_text)
- : tooltip_text(tooltip_text),
- label_text(label_text) {}
-
-SearchResult::Action::~Action() {}
-
-SearchResult::SearchResult() : is_installing_(false), percent_downloaded_(0) {}
-
-SearchResult::~SearchResult() {}
-
-void SearchResult::SetIcon(const gfx::ImageSkia& icon) {
- icon_ = icon;
- FOR_EACH_OBSERVER(SearchResultObserver,
- observers_,
- OnIconChanged());
-}
-
-void SearchResult::SetActions(const Actions& sets) {
- actions_ = sets;
- FOR_EACH_OBSERVER(SearchResultObserver,
- observers_,
- OnActionsChanged());
-}
-
-void SearchResult::SetIsInstalling(bool is_installing) {
- if (is_installing_ == is_installing)
- return;
-
- is_installing_ = is_installing;
- FOR_EACH_OBSERVER(SearchResultObserver,
- observers_,
- OnIsInstallingChanged());
-}
-
-void SearchResult::SetPercentDownloaded(int percent_downloaded) {
- if (percent_downloaded_ == percent_downloaded)
- return;
-
- percent_downloaded_ = percent_downloaded;
- FOR_EACH_OBSERVER(SearchResultObserver,
- observers_,
- OnPercentDownloadedChanged());
-}
-
-void SearchResult::NotifyItemInstalled() {
- FOR_EACH_OBSERVER(SearchResultObserver, observers_, OnItemInstalled());
-}
-
-void SearchResult::NotifyItemUninstalled() {
- FOR_EACH_OBSERVER(SearchResultObserver, observers_, OnItemUninstalled());
-}
-
-void SearchResult::AddObserver(SearchResultObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void SearchResult::RemoveObserver(SearchResultObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-ui::MenuModel* SearchResult::GetContextMenuModel() {
- return NULL;
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/search_result.h b/chromium/ui/app_list/search_result.h
deleted file mode 100644
index 6064ffb797c..00000000000
--- a/chromium/ui/app_list/search_result.h
+++ /dev/null
@@ -1,134 +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_APP_LIST_SEARCH_RESULT_H_
-#define UI_APP_LIST_SEARCH_RESULT_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/range/range.h"
-
-namespace ui {
-class MenuModel;
-}
-
-namespace app_list {
-
-class SearchResultObserver;
-
-// SearchResult consists of an icon, title text and details text. Title and
-// details text can have tagged ranges that are displayed differently from
-// default style.
-class APP_LIST_EXPORT SearchResult {
- public:
- // A tagged range in search result text.
- struct APP_LIST_EXPORT Tag {
- // Similar to ACMatchClassification::Style, the style values are not
- // mutually exclusive.
- enum Style {
- NONE = 0,
- URL = 1 << 0,
- MATCH = 1 << 1,
- DIM = 1 << 2,
- };
-
- Tag(int styles, size_t start, size_t end)
- : styles(styles),
- range(start, end) {
- }
-
- int styles;
- gfx::Range range;
- };
- typedef std::vector<Tag> Tags;
-
- // Data representing an action that can be performed on this search result.
- // An action could be represented as an icon set or as a blue button with
- // a label. Icon set is chosen if label text is empty. Otherwise, a blue
- // button with the label text will be used.
- struct APP_LIST_EXPORT Action {
- Action(const gfx::ImageSkia& base_image,
- const gfx::ImageSkia& hover_image,
- const gfx::ImageSkia& pressed_image,
- const base::string16& tooltip_text);
- Action(const base::string16& label_text,
- const base::string16& tooltip_text);
- ~Action();
-
- gfx::ImageSkia base_image;
- gfx::ImageSkia hover_image;
- gfx::ImageSkia pressed_image;
-
- base::string16 tooltip_text;
- base::string16 label_text;
- };
- typedef std::vector<Action> Actions;
-
- SearchResult();
- virtual ~SearchResult();
-
- const gfx::ImageSkia& icon() const { return icon_; }
- void SetIcon(const gfx::ImageSkia& icon);
-
- const base::string16& title() const { return title_; }
- void set_title(const base::string16& title) { title_ = title;}
-
- const Tags& title_tags() const { return title_tags_; }
- void set_title_tags(const Tags& tags) { title_tags_ = tags; }
-
- const base::string16& details() const { return details_; }
- void set_details(const base::string16& details) { details_ = details; }
-
- const Tags& details_tags() const { return details_tags_; }
- void set_details_tags(const Tags& tags) { details_tags_ = tags; }
-
- const Actions& actions() const {
- return actions_;
- }
- void SetActions(const Actions& sets);
-
- bool is_installing() const { return is_installing_; }
- void SetIsInstalling(bool is_installing);
-
- int percent_downloaded() const { return percent_downloaded_; }
- void SetPercentDownloaded(int percent_downloaded);
-
- void NotifyItemInstalled();
- void NotifyItemUninstalled();
-
- void AddObserver(SearchResultObserver* observer);
- void RemoveObserver(SearchResultObserver* observer);
-
- // Returns the context menu model for this item, or NULL if there is currently
- // no menu for the item (e.g. during install).
- // Note the returned menu model is owned by this item.
- virtual ui::MenuModel* GetContextMenuModel();
-
- private:
- gfx::ImageSkia icon_;
-
- base::string16 title_;
- Tags title_tags_;
-
- base::string16 details_;
- Tags details_tags_;
-
- Actions actions_;
-
- bool is_installing_;
- int percent_downloaded_;
-
- ObserverList<SearchResultObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchResult);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SEARCH_RESULT_H_
diff --git a/chromium/ui/app_list/search_result_observer.h b/chromium/ui/app_list/search_result_observer.h
deleted file mode 100644
index bef7564d45a..00000000000
--- a/chromium/ui/app_list/search_result_observer.h
+++ /dev/null
@@ -1,38 +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_APP_LIST_SEARCH_RESULT_OBSERVER_H_
-#define UI_APP_LIST_SEARCH_RESULT_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT SearchResultObserver {
- public:
- // Invoked when the SearchResult's icon has changed.
- virtual void OnIconChanged() = 0;
-
- // Invoked when the SearchResult's actions have changed.
- virtual void OnActionsChanged() = 0;
-
- // Invoked when the SearchResult's is_installing flag has changed.
- virtual void OnIsInstallingChanged() = 0;
-
- // Invoked when the download percentage has changed.
- virtual void OnPercentDownloadedChanged() = 0;
-
- // Invoked when the item represented by the SearchResult is installed.
- virtual void OnItemInstalled() = 0;
-
- // Invoked when the item represented by the SearchResult is uninstalled.
- virtual void OnItemUninstalled() = 0;
-
- protected:
- virtual ~SearchResultObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SEARCH_RESULT_OBSERVER_H_
diff --git a/chromium/ui/app_list/signin_delegate.cc b/chromium/ui/app_list/signin_delegate.cc
deleted file mode 100644
index b0dd7e67590..00000000000
--- a/chromium/ui/app_list/signin_delegate.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/signin_delegate.h"
-
-namespace app_list {
-
-SigninDelegate::SigninDelegate() {}
-
-SigninDelegate::~SigninDelegate() {}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/signin_delegate.h b/chromium/ui/app_list/signin_delegate.h
deleted file mode 100644
index 54f59179de9..00000000000
--- a/chromium/ui/app_list/signin_delegate.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_SIGNIN_DELEGATE_H_
-#define UI_APP_LIST_SIGNIN_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class APP_LIST_EXPORT SigninDelegate {
- public:
- SigninDelegate();
- virtual ~SigninDelegate();
-
- virtual bool NeedSignin() = 0;
- virtual void ShowSignin() = 0;
- virtual void OpenLearnMore() = 0;
- virtual void OpenSettings() = 0;
-
- virtual base::string16 GetSigninHeading() = 0;
- virtual base::string16 GetSigninText() = 0;
- virtual base::string16 GetSigninButtonText() = 0;
- virtual base::string16 GetLearnMoreLinkText() = 0;
- virtual base::string16 GetSettingsLinkText() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SigninDelegate);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SIGNIN_DELEGATE_H_
diff --git a/chromium/ui/app_list/speech_ui_model.cc b/chromium/ui/app_list/speech_ui_model.cc
deleted file mode 100644
index 86955511930..00000000000
--- a/chromium/ui/app_list/speech_ui_model.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/speech_ui_model.h"
-
-namespace app_list {
-
-SpeechUIModel::SpeechUIModel() {}
-
-SpeechUIModel::~SpeechUIModel() {}
-
-void SpeechUIModel::SetSpeechResult(const base::string16& result,
- bool is_final) {
- if (result_ == result && is_final_ == is_final)
- return;
-
- result_ = result;
- is_final_ = is_final;
- FOR_EACH_OBSERVER(SpeechUIModelObserver,
- observers_,
- OnSpeechResult(result, is_final));
-}
-
-void SpeechUIModel::UpdateSoundLevel(int16 level) {
- if (sound_level_ == level)
- return;
-
- sound_level_ = level;
- FOR_EACH_OBSERVER(SpeechUIModelObserver,
- observers_,
- OnSpeechSoundLevelChanged(level));
-}
-
-void SpeechUIModel::SetSpeechRecognitionState(
- SpeechRecognitionState new_state) {
- if (state_ == new_state)
- return;
-
- state_ = new_state;
- FOR_EACH_OBSERVER(SpeechUIModelObserver,
- observers_,
- OnSpeechRecognitionStateChanged(new_state));
-}
-
-void SpeechUIModel::AddObserver(SpeechUIModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void SpeechUIModel::RemoveObserver(SpeechUIModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/speech_ui_model.h b/chromium/ui/app_list/speech_ui_model.h
deleted file mode 100644
index 1d3f7502cf1..00000000000
--- a/chromium/ui/app_list/speech_ui_model.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_SPEECH_UI_MODEL_H_
-#define UI_APP_LIST_SPEECH_UI_MODEL_H_
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/speech_ui_model_observer.h"
-
-namespace app_list {
-
-// SpeechUIModel provides the interface to update the UI for speech recognition.
-class APP_LIST_EXPORT SpeechUIModel {
- public:
- SpeechUIModel();
- virtual ~SpeechUIModel();
-
- void SetSpeechResult(const base::string16& result, bool is_final);
- void UpdateSoundLevel(int16 level);
- void SetSpeechRecognitionState(SpeechRecognitionState new_state);
-
- void AddObserver(SpeechUIModelObserver* observer);
- void RemoveObserver(SpeechUIModelObserver* observer);
-
- const base::string16& result() const { return result_; }
- bool is_final() const { return is_final_; }
- int16 sound_level() const { return sound_level_; }
- SpeechRecognitionState state() const { return state_; }
-
- private:
- base::string16 result_;
- bool is_final_;
- int16 sound_level_;
- SpeechRecognitionState state_;
-
- ObserverList<SpeechUIModelObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(SpeechUIModel);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SPEECH_UI_MODEL_H_
diff --git a/chromium/ui/app_list/speech_ui_model_observer.h b/chromium/ui/app_list/speech_ui_model_observer.h
deleted file mode 100644
index 39fdd269203..00000000000
--- a/chromium/ui/app_list/speech_ui_model_observer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_SPEECH_UI_MODEL_OBSERVER_H_
-#define UI_APP_LIST_SPEECH_UI_MODEL_OBSERVER_H_
-
-#include "base/basictypes.h"
-#include "base/strings/string16.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-enum SpeechRecognitionState {
- SPEECH_RECOGNITION_NOT_STARTED = 0,
- SPEECH_RECOGNITION_ON,
- SPEECH_RECOGNITION_IN_SPEECH,
-};
-
-class APP_LIST_EXPORT SpeechUIModelObserver {
- public:
- // Invoked when sound level for the speech recognition has changed.
- virtual void OnSpeechSoundLevelChanged(int16 level) {}
-
- // Invoked when a speech result arrives. |is_final| is true only when the
- // speech result is final.
- virtual void OnSpeechResult(const base::string16& result, bool is_final) {}
-
- // Invoked when the state of speech recognition is changed.
- virtual void OnSpeechRecognitionStateChanged(
- SpeechRecognitionState new_state) {}
-
- protected:
- virtual ~SpeechUIModelObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_SPEECH_UI_MODEL_OBSERVER_H_
diff --git a/chromium/ui/app_list/views/DEPS b/chromium/ui/app_list/views/DEPS
deleted file mode 100644
index fe7bb13183f..00000000000
--- a/chromium/ui/app_list/views/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+content/public",
-]
diff --git a/chromium/ui/app_list/views/app_list_background.cc b/chromium/ui/app_list/views/app_list_background.cc
deleted file mode 100644
index cc55b5b9202..00000000000
--- a/chromium/ui/app_list/views/app_list_background.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_background.h"
-
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/search_box_view.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/view.h"
-
-namespace {
-
-// Size of top separator between searchbox and grid view.
-const int kTopSeparatorSize = 1;
-
-} // namespace
-
-namespace app_list {
-
-AppListBackground::AppListBackground(int corner_radius,
- AppListMainView* main_view)
- : corner_radius_(corner_radius),
- main_view_(main_view) {
-}
-
-AppListBackground::~AppListBackground() {
-}
-
-void AppListBackground::Paint(gfx::Canvas* canvas,
- views::View* view) const {
- gfx::Rect bounds = view->GetContentsBounds();
-
- canvas->Save();
- SkPath path;
- // Contents corner radius is 1px smaller than border corner radius.
- SkScalar radius = SkIntToScalar(corner_radius_ - 1);
- path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius);
- canvas->ClipPath(path);
-
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
-
- int contents_top = bounds.y();
- if (main_view_->visible()) {
- views::View* search_box_view = main_view_->search_box_view();
- const gfx::Rect search_box_view_bounds =
- search_box_view->ConvertRectToWidget(search_box_view->GetLocalBounds());
- gfx::Rect search_box_rect(bounds.x(),
- bounds.y(),
- bounds.width(),
- search_box_view_bounds.bottom() - bounds.y());
-
- paint.setColor(kSearchBoxBackground);
- canvas->DrawRect(search_box_rect, paint);
-
- gfx::Rect seperator_rect(search_box_rect);
- seperator_rect.set_y(seperator_rect.bottom());
- seperator_rect.set_height(kTopSeparatorSize);
- canvas->FillRect(seperator_rect, kTopSeparatorColor);
- contents_top = seperator_rect.bottom();
- }
-
- gfx::Rect contents_rect(bounds.x(),
- contents_top,
- bounds.width(),
- bounds.bottom() - contents_top);
-
- paint.setColor(kContentsBackgroundColor);
- canvas->DrawRect(contents_rect, paint);
- canvas->Restore();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_background.h b/chromium/ui/app_list/views/app_list_background.h
deleted file mode 100644
index 900e698f119..00000000000
--- a/chromium/ui/app_list/views/app_list_background.h
+++ /dev/null
@@ -1,39 +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_APP_LIST_VIEWS_APP_LIST_BACKGROUND_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_BACKGROUND_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/views/background.h"
-
-namespace views {
-class View;
-}
-
-namespace app_list {
-
-class AppListMainView;
-
-// A class to paint bubble background.
-class AppListBackground : public views::Background {
- public:
- AppListBackground(int corner_radius,
- AppListMainView* main_view);
- virtual ~AppListBackground();
-
- private:
- // views::Background overrides:
- virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE;
-
- const int corner_radius_;
- const AppListMainView* main_view_; // Owned by views hierarchy.
-
- DISALLOW_COPY_AND_ASSIGN(AppListBackground);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_BACKGROUND_H_
diff --git a/chromium/ui/app_list/views/app_list_drag_and_drop_host.h b/chromium/ui/app_list/views/app_list_drag_and_drop_host.h
deleted file mode 100644
index 7774f949699..00000000000
--- a/chromium/ui/app_list/views/app_list_drag_and_drop_host.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
-
-#include <string>
-
-namespace gfx {
-class Point;
-class Vector2d;
-} // namespace gfx
-
-namespace app_list {
-
-// This class will get used by the AppListView to drag and drop Application
-// shortcuts onto another host (the launcher).
-class ApplicationDragAndDropHost {
- public:
- // Create an OS dependent drag proxy icon which can escape the given view.
- // The proxy should get created using the |icon| with a magnification of
- // |scale_factor| at a center location of |location_in_screen_coordinates.
- // Use |replaced_view| to find the screen which is used.
- // The |cursor_offset_from_center| is the offset from the mouse cursor to
- // the center of the item.
- virtual void CreateDragIconProxy(
- const gfx::Point& location_in_screen_coordinates,
- const gfx::ImageSkia& icon,
- views::View* replaced_view,
- const gfx::Vector2d& cursor_offset_from_center,
- float scale_factor) = 0;
-
- // Update the screen location of the Drag icon proxy.
- virtual void UpdateDragIconProxy(
- const gfx::Point& location_in_screen_coordinates) = 0;
-
- // Remove the OS dependent drag proxy from the screen.
- virtual void DestroyDragIconProxy() = 0;
-
- // A drag operation could get started. The recipient has to return true if
- // he wants to take it - e.g. |location_in_screen_poordinates| is over a
- // target area. The passed |app_id| identifies the application which should
- // get dropped.
- virtual bool StartDrag(const std::string& app_id,
- const gfx::Point& location_in_screen_coordinates) = 0;
-
- // This gets only called when the |StartDrag| function returned true and it
- // dispatches the mouse coordinate change accordingly. When the function
- // returns false it requests that the operation be aborted since the event
- // location is out of bounds.
- // Note that this function does not update the drag proxy's screen position.
- virtual bool Drag(const gfx::Point& location_in_screen_coordinates) = 0;
-
- // Once |StartDrag| returned true, this function is guaranteed to be called
- // when the mouse / touch events stop. If |cancel| is set, the drag operation
- // was aborted, otherwise the change should be kept.
- virtual void EndDrag(bool cancel) = 0;
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
diff --git a/chromium/ui/app_list/views/app_list_folder_view.cc b/chromium/ui/app_list/views/app_list_folder_view.cc
deleted file mode 100644
index 10171ffa8b4..00000000000
--- a/chromium/ui/app_list/views/app_list_folder_view.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_folder_view.h"
-
-#include <algorithm>
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/apps_container_view.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/app_list/views/contents_view.h"
-#include "ui/app_list/views/folder_header_view.h"
-#include "ui/events/event.h"
-#include "ui/views/view_model.h"
-#include "ui/views/view_model_utils.h"
-
-namespace app_list {
-
-namespace {
-
-// Indexes of interesting views in ViewModel of AppListFolderView.
-const int kIndexFolderHeader = 0;
-const int kIndexChildItems = 1;
-
-} // namespace
-
-AppListFolderView::AppListFolderView(AppsContainerView* container_view,
- AppListModel* model,
- AppListMainView* app_list_main_view,
- content::WebContents* start_page_contents)
- : container_view_(container_view),
- folder_header_view_(new FolderHeaderView(this)),
- view_model_(new views::ViewModel),
- folder_item_(NULL),
- pagination_model_(new PaginationModel) {
- AddChildView(folder_header_view_);
- view_model_->Add(folder_header_view_, kIndexFolderHeader);
-
- items_grid_view_ = new AppsGridView(
- app_list_main_view, pagination_model_.get(), NULL);
- items_grid_view_->set_is_root_level(false);
- items_grid_view_->SetLayout(kPreferredIconDimension,
- kPreferredCols,
- kPreferredRows);
- items_grid_view_->SetModel(model);
- AddChildView(items_grid_view_);
- view_model_->Add(items_grid_view_, kIndexChildItems);
-}
-
-AppListFolderView::~AppListFolderView() {
- // Make sure |items_grid_view_| is deleted before |pagination_model_|.
- RemoveAllChildViews(true);
-}
-
-void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) {
- folder_item_ = folder;
- items_grid_view_->SetItemList(folder_item_->item_list());
- folder_header_view_->SetFolderItem(folder_item_);
-}
-
-gfx::Size AppListFolderView::GetPreferredSize() {
- const gfx::Size header_size = folder_header_view_->GetPreferredSize();
- const gfx::Size grid_size = items_grid_view_->GetPreferredSize();
- int width = std::max(header_size.width(), grid_size.width());
- int height = header_size.height() + grid_size.height();
- return gfx::Size(width, height);
-}
-
-void AppListFolderView::Layout() {
- CalculateIdealBounds();
- views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
-}
-
-bool AppListFolderView::OnKeyPressed(const ui::KeyEvent& event) {
- return items_grid_view_->OnKeyPressed(event);
-}
-
-void AppListFolderView::CalculateIdealBounds() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect header_frame(rect);
- gfx::Size size = folder_header_view_->GetPreferredSize();
- header_frame.set_height(size.height());
- view_model_->set_ideal_bounds(kIndexFolderHeader, header_frame);
-
- gfx::Rect grid_frame(rect);
- grid_frame.set_y(header_frame.height());
- view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
-}
-
-void AppListFolderView::NavigateBack(AppListFolderItem* item,
- const ui::Event& event_flags) {
- container_view_->ShowApps();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_folder_view.h b/chromium/ui/app_list/views/app_list_folder_view.h
deleted file mode 100644
index 85400696bfb..00000000000
--- a/chromium/ui/app_list/views/app_list_folder_view.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
-
-#include "ui/app_list/views/folder_header_view.h"
-#include "ui/app_list/views/folder_header_view_delegate.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace views {
-class ViewModel;
-}
-
-namespace app_list {
-
-class AppsContainerView;
-class AppsGridView;
-class AppListFolderItem;
-class AppListMainView;
-class AppListModel;
-class FolderHeaderView;
-class PaginationModel;
-
-class AppListFolderView : public views::View,
- public FolderHeaderViewDelegate {
- public:
- AppListFolderView(AppsContainerView* container_view,
- AppListModel* model,
- AppListMainView* app_list_main_view,
- content::WebContents* start_page_contents);
- virtual ~AppListFolderView();
-
- void SetAppListFolderItem(AppListFolderItem* folder);
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
-
- private:
- void CalculateIdealBounds();
-
- // Overridden from FolderHeaderViewDelegate:
- virtual void NavigateBack(AppListFolderItem* item,
- const ui::Event& event_flags) OVERRIDE;
-
- AppsContainerView* container_view_; // Not owned.
- FolderHeaderView* folder_header_view_; // Owned by views hierarchy.
- AppsGridView* items_grid_view_; // Owned by the views hierarchy.
-
- scoped_ptr<views::ViewModel> view_model_;
-
- AppListFolderItem* folder_item_; // Not owned.
-
- scoped_ptr<PaginationModel> pagination_model_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListFolderView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_
-
-
diff --git a/chromium/ui/app_list/views/app_list_item_view.cc b/chromium/ui/app_list/views/app_list_item_view.cc
deleted file mode 100644
index f2e9c64b6c6..00000000000
--- a/chromium/ui/app_list/views/app_list_item_view.cc
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_item_view.h"
-
-#include <algorithm>
-
-#include "base/strings/utf_string_conversions.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/app_list/views/cached_label.h"
-#include "ui/app_list/views/progress_bar_view.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/base/dragdrop/drag_utils.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/animation/throb_animation.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/transform_util.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/drag_controller.h"
-
-namespace app_list {
-
-namespace {
-
-const int kTopPadding = 20;
-const int kIconTitleSpacing = 7;
-const int kProgressBarHorizontalPadding = 12;
-
-// Radius of the folder dropping preview circle.
-const int kFolderPreviewRadius = 40;
-
-const int kLeftRightPaddingChars = 1;
-
-// Scale to transform the icon when a drag starts.
-const float kDraggingIconScale = 1.5f;
-
-// Delay in milliseconds of when the dragging UI should be shown for mouse drag.
-const int kMouseDragUIDelayInMs = 100;
-
-} // namespace
-
-// static
-const char AppListItemView::kViewClassName[] = "ui/app_list/AppListItemView";
-
-AppListItemView::AppListItemView(AppsGridView* apps_grid_view,
- AppListItemModel* model)
- : CustomButton(apps_grid_view),
- model_(model),
- apps_grid_view_(apps_grid_view),
- icon_(new views::ImageView),
- title_(new CachedLabel),
- progress_bar_(new ProgressBarView),
- ui_state_(UI_STATE_NORMAL),
- touch_dragging_(false) {
- icon_->set_interactive(false);
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- title_->SetBackgroundColor(0);
- title_->SetAutoColorReadabilityEnabled(false);
- title_->SetEnabledColor(kGridTitleColor);
- title_->SetFont(rb.GetFont(kItemTextFontStyle));
- title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- title_->SetVisible(!model_->is_installing());
- title_->Invalidate();
-
- const gfx::ShadowValue kIconShadows[] = {
- gfx::ShadowValue(gfx::Point(0, 2), 2, SkColorSetARGB(0x24, 0, 0, 0)),
- };
- icon_shadows_.assign(kIconShadows, kIconShadows + arraysize(kIconShadows));
-
- AddChildView(icon_);
- AddChildView(title_);
- AddChildView(progress_bar_);
-
- ItemIconChanged();
- ItemTitleChanged();
- ItemIsInstallingChanged();
- model_->AddObserver(this);
-
- set_context_menu_controller(this);
- set_request_focus_on_press(false);
-
- SetAnimationDuration(0);
-}
-
-AppListItemView::~AppListItemView() {
- model_->RemoveObserver(this);
-}
-
-void AppListItemView::SetIconSize(const gfx::Size& size) {
- if (icon_size_ == size)
- return;
-
- icon_size_ = size;
- UpdateIcon();
-}
-
-void AppListItemView::UpdateIcon() {
- // Skip if |icon_size_| has not been determined.
- if (icon_size_.IsEmpty())
- return;
-
- gfx::ImageSkia icon = model_->icon();
- // Clear icon and bail out if model icon is empty.
- if (icon.isNull()) {
- icon_->SetImage(NULL);
- return;
- }
-
- gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(icon,
- skia::ImageOperations::RESIZE_BEST, icon_size_));
- if (model_->has_shadow()) {
- gfx::ImageSkia shadow(
- gfx::ImageSkiaOperations::CreateImageWithDropShadow(resized,
- icon_shadows_));
- icon_->SetImage(shadow);
- return;
- };
-
- icon_->SetImage(resized);
-}
-
-void AppListItemView::UpdateTooltip() {
- title_->SetTooltipText(model_->title() == model_->full_name() ?
- string16() : UTF8ToUTF16(model_->full_name()));
-}
-
-void AppListItemView::SetUIState(UIState state) {
- if (ui_state_ == state)
- return;
-
- ui_state_ = state;
-
-#if defined(USE_AURA)
- switch (ui_state_) {
- case UI_STATE_NORMAL:
- title_->SetVisible(!model_->is_installing());
- progress_bar_->SetVisible(model_->is_installing());
- break;
- case UI_STATE_DRAGGING:
- title_->SetVisible(false);
- progress_bar_->SetVisible(false);
- break;
- case UI_STATE_DROPPING_IN_FOLDER:
- break;
- }
-#if !defined(OS_WIN)
- ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
- switch (ui_state_) {
- case UI_STATE_NORMAL:
- layer()->SetTransform(gfx::Transform());
- break;
- case UI_STATE_DRAGGING: {
- const gfx::Rect bounds(layer()->bounds().size());
- layer()->SetTransform(gfx::GetScaleTransform(
- bounds.CenterPoint(),
- kDraggingIconScale));
- break;
- }
- case UI_STATE_DROPPING_IN_FOLDER:
- break;
- }
-
- SchedulePaint();
-#endif // !OS_WIN
-#endif // USE_AURA
-}
-
-void AppListItemView::SetTouchDragging(bool touch_dragging) {
- if (touch_dragging_ == touch_dragging)
- return;
-
- touch_dragging_ = touch_dragging;
- SetUIState(touch_dragging_ ? UI_STATE_DRAGGING : UI_STATE_NORMAL);
-}
-
-void AppListItemView::OnMouseDragTimer() {
- DCHECK(apps_grid_view_->IsDraggedView(this));
- SetUIState(UI_STATE_DRAGGING);
-}
-
-void AppListItemView::Prerender() {
- title_->PaintToBackingImage();
-}
-
-void AppListItemView::CancelContextMenu() {
- if (context_menu_runner_)
- context_menu_runner_->Cancel();
-}
-
-gfx::ImageSkia AppListItemView::GetDragImage() {
- return icon_->GetImage();
-}
-
-void AppListItemView::OnDragEnded() {
- mouse_drag_timer_.Stop();
- SetUIState(UI_STATE_NORMAL);
-}
-
-gfx::Point AppListItemView::GetDragImageOffset() {
- gfx::Point image = icon_->GetImageBounds().origin();
- return gfx::Point(icon_->x() + image.x(), icon_->y() + image.y());
-}
-
-void AppListItemView::SetAsAttemptedFolderTarget(bool is_target_folder) {
- if (is_target_folder)
- SetUIState(UI_STATE_DROPPING_IN_FOLDER);
- else
- SetUIState(UI_STATE_NORMAL);
-}
-
-void AppListItemView::ItemIconChanged() {
- UpdateIcon();
-}
-
-void AppListItemView::ItemTitleChanged() {
- title_->SetText(UTF8ToUTF16(model_->title()));
- title_->Invalidate();
- UpdateTooltip();
- Layout();
-}
-
-void AppListItemView::ItemHighlightedChanged() {
- apps_grid_view_->EnsureViewVisible(this);
- SchedulePaint();
-}
-
-void AppListItemView::ItemIsInstallingChanged() {
- if (model_->is_installing())
- apps_grid_view_->EnsureViewVisible(this);
- title_->SetVisible(!model_->is_installing());
- progress_bar_->SetVisible(model_->is_installing());
- SchedulePaint();
-}
-
-void AppListItemView::ItemPercentDownloadedChanged() {
- // A percent_downloaded() of -1 can mean it's not known how much percent is
- // completed, or the download hasn't been marked complete, as is the case
- // while an extension is being installed after being downloaded.
- if (model_->percent_downloaded() == -1)
- return;
- progress_bar_->SetValue(model_->percent_downloaded() / 100.0);
-}
-
-const char* AppListItemView::GetClassName() const {
- return kViewClassName;
-}
-
-void AppListItemView::Layout() {
- gfx::Rect rect(GetContentsBounds());
-
- const int left_right_padding = kLeftRightPaddingChars *
- title_->font().GetAverageCharacterWidth();
- rect.Inset(left_right_padding, kTopPadding, left_right_padding, 0);
- const int y = rect.y();
-
- gfx::Rect icon_bounds(rect.x(), y, rect.width(), icon_size_.height());
- icon_bounds.Inset(gfx::ShadowValue::GetMargin(icon_shadows_));
- icon_->SetBoundsRect(icon_bounds);
-
- const gfx::Size title_size = title_->GetPreferredSize();
- gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2,
- y + icon_size_.height() + kIconTitleSpacing,
- title_size.width(),
- title_size.height());
- title_bounds.Intersect(rect);
- title_->SetBoundsRect(title_bounds);
-
- gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize());
- progress_bar_bounds.set_x(GetContentsBounds().x() +
- kProgressBarHorizontalPadding);
- progress_bar_bounds.set_y(title_bounds.y());
- progress_bar_->SetBoundsRect(progress_bar_bounds);
-}
-
-void AppListItemView::OnPaint(gfx::Canvas* canvas) {
- if (apps_grid_view_->IsDraggedView(this))
- return;
-
- gfx::Rect rect(GetContentsBounds());
- if (model_->highlighted() && !model_->is_installing()) {
- canvas->FillRect(rect, kHighlightedColor);
- return;
- } else if (apps_grid_view_->IsSelectedView(this)) {
- canvas->FillRect(rect, kSelectedColor);
- }
-
- if (!switches::IsFolderUIEnabled()) {
- if (apps_grid_view_->IsSelectedView(this)) {
- canvas->FillRect(rect, kSelectedColor);
- } else if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
- canvas->FillRect(rect, kHighlightedColor);
- }
- } else if (ui_state_ == UI_STATE_DROPPING_IN_FOLDER) {
- // Draw folder dropping preview circle.
- gfx::Point center = gfx::Point(icon_->x() + icon_->size().width() / 2,
- icon_->y() + icon_->size().height() / 2);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAntiAlias(true);
- paint.setColor(kFolderBubbleColor);
- canvas->DrawCircle(center, kFolderPreviewRadius, paint);
- }
-}
-
-void AppListItemView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
- state->name = UTF8ToUTF16(model_->title());
-}
-
-void AppListItemView::ShowContextMenuForView(views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) {
- ui::MenuModel* menu_model = model_->GetContextMenuModel();
- if (!menu_model)
- return;
-
- context_menu_runner_.reset(new views::MenuRunner(menu_model));
- if (context_menu_runner_->RunMenuAt(
- GetWidget(), NULL, gfx::Rect(point, gfx::Size()),
- views::MenuItemView::TOPLEFT, source_type,
- views::MenuRunner::HAS_MNEMONICS) ==
- views::MenuRunner::MENU_DELETED)
- return;
-}
-
-void AppListItemView::StateChanged() {
- const bool is_folder_ui_enabled = switches::IsFolderUIEnabled();
- if (is_folder_ui_enabled)
- apps_grid_view_->ClearAnySelectedView();
-
- if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
- if (!is_folder_ui_enabled)
- apps_grid_view_->SetSelectedView(this);
- title_->SetEnabledColor(kGridTitleHoverColor);
- } else {
- if (!is_folder_ui_enabled)
- apps_grid_view_->ClearSelectedView(this);
- model_->SetHighlighted(false);
- title_->SetEnabledColor(kGridTitleColor);
- }
- title_->Invalidate();
-}
-
-bool AppListItemView::ShouldEnterPushedState(const ui::Event& event) {
- // Don't enter pushed state for ET_GESTURE_TAP_DOWN so that hover gray
- // background does not show up during scroll.
- if (event.type() == ui::ET_GESTURE_TAP_DOWN)
- return false;
-
- return views::CustomButton::ShouldEnterPushedState(event);
-}
-
-bool AppListItemView::OnMousePressed(const ui::MouseEvent& event) {
- CustomButton::OnMousePressed(event);
-
- if (!ShouldEnterPushedState(event))
- return true;
-
- apps_grid_view_->InitiateDrag(this, AppsGridView::MOUSE, event);
-
- if (apps_grid_view_->IsDraggedView(this)) {
- mouse_drag_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kMouseDragUIDelayInMs),
- this, &AppListItemView::OnMouseDragTimer);
- }
- return true;
-}
-
-bool AppListItemView::OnKeyPressed(const ui::KeyEvent& event) {
- // Disable space key to press the button. The keyboard events received
- // by this view are forwarded from a Textfield (SearchBoxView) and key
- // released events are not forwarded. This leaves the button in pressed
- // state.
- if (event.key_code() == ui::VKEY_SPACE)
- return false;
-
- return CustomButton::OnKeyPressed(event);
-}
-
-void AppListItemView::OnMouseReleased(const ui::MouseEvent& event) {
- CustomButton::OnMouseReleased(event);
- apps_grid_view_->EndDrag(false);
-}
-
-void AppListItemView::OnMouseCaptureLost() {
- // We don't cancel the dag on mouse capture lost for windows as entering a
- // synchronous drag causes mouse capture to be lost and pressing escape
- // dismisses the app list anyway.
-#if !defined(OS_WIN)
- CustomButton::OnMouseCaptureLost();
- apps_grid_view_->EndDrag(true);
-#endif
-}
-
-bool AppListItemView::OnMouseDragged(const ui::MouseEvent& event) {
- CustomButton::OnMouseDragged(event);
- if (apps_grid_view_->IsDraggedView(this))
- apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, event);
-
- // Shows dragging UI when it's confirmed without waiting for the timer.
- if (ui_state_ != UI_STATE_DRAGGING &&
- apps_grid_view_->dragging() &&
- apps_grid_view_->IsDraggedView(this)) {
- mouse_drag_timer_.Stop();
- SetUIState(UI_STATE_DRAGGING);
- }
- return true;
-}
-
-void AppListItemView::OnGestureEvent(ui::GestureEvent* event) {
- switch (event->type()) {
- case ui::ET_GESTURE_SCROLL_BEGIN:
- if (touch_dragging_) {
- apps_grid_view_->InitiateDrag(this, AppsGridView::TOUCH, *event);
- event->SetHandled();
- }
- break;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- if (touch_dragging_ && apps_grid_view_->IsDraggedView(this)) {
- apps_grid_view_->UpdateDragFromItem(AppsGridView::TOUCH, *event);
- event->SetHandled();
- }
- break;
- case ui::ET_GESTURE_SCROLL_END:
- case ui::ET_SCROLL_FLING_START:
- if (touch_dragging_) {
- SetTouchDragging(false);
- apps_grid_view_->EndDrag(false);
- event->SetHandled();
- }
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- if (!apps_grid_view_->has_dragged_view())
- SetTouchDragging(true);
- event->SetHandled();
- break;
- case ui::ET_GESTURE_LONG_TAP:
- case ui::ET_GESTURE_END:
- if (touch_dragging_)
- SetTouchDragging(false);
- break;
- default:
- break;
- }
- if (!event->handled())
- CustomButton::OnGestureEvent(event);
-}
-
-void AppListItemView::OnSyncDragEnd() {
- SetUIState(UI_STATE_NORMAL);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_item_view.h b/chromium/ui/app_list/views/app_list_item_view.h
deleted file mode 100644
index 2d41461578c..00000000000
--- a/chromium/ui/app_list/views/app_list_item_view.h
+++ /dev/null
@@ -1,142 +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_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_
-
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/timer/timer.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_item_model_observer.h"
-#include "ui/app_list/views/cached_label.h"
-#include "ui/gfx/shadow_value.h"
-#include "ui/views/context_menu_controller.h"
-#include "ui/views/controls/button/custom_button.h"
-
-class SkBitmap;
-
-namespace views {
-class ImageView;
-class Label;
-class MenuRunner;
-}
-
-namespace app_list {
-
-class AppListItemModel;
-class AppsGridView;
-class ProgressBarView;
-
-class APP_LIST_EXPORT AppListItemView : public views::CustomButton,
- public views::ContextMenuController,
- public AppListItemModelObserver {
- public:
- // Internal class name.
- static const char kViewClassName[];
-
- AppListItemView(AppsGridView* apps_grid_view, AppListItemModel* model);
- virtual ~AppListItemView();
-
- void SetIconSize(const gfx::Size& size);
-
- void Prerender();
-
- void CancelContextMenu();
-
- gfx::ImageSkia GetDragImage();
- void OnDragEnded();
- gfx::Point GetDragImageOffset();
-
- void SetAsAttemptedFolderTarget(bool is_target_folder);
-
- AppListItemModel* model() const { return model_; }
-
- const views::Label* title() const { return title_; }
-
- // In a synchronous drag the item view isn't informed directly of the drag
- // ending, so the runner of the drag should call this.
- void OnSyncDragEnd();
-
- private:
- enum UIState {
- UI_STATE_NORMAL, // Normal UI (icon + label)
- UI_STATE_DRAGGING, // Dragging UI (scaled icon only)
- UI_STATE_DROPPING_IN_FOLDER, // Folder dropping preview UI
- };
-
- // Get icon from model and schedule background processing.
- void UpdateIcon();
-
- // Update the tooltip text from the model.
- void UpdateTooltip();
-
- void SetUIState(UIState state);
-
- // Sets |touch_dragging_| flag and updates UI.
- void SetTouchDragging(bool touch_dragging);
-
- // Invoked when |mouse_drag_timer_| fires to show dragging UI.
- void OnMouseDragTimer();
-
- // AppListItemModelObserver overrides:
- virtual void ItemIconChanged() OVERRIDE;
- virtual void ItemTitleChanged() OVERRIDE;
- virtual void ItemHighlightedChanged() OVERRIDE;
- virtual void ItemIsInstallingChanged() OVERRIDE;
- virtual void ItemPercentDownloadedChanged() OVERRIDE;
-
- // views::View overrides:
- virtual const char* GetClassName() const OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-
- // views::ContextMenuController overrides:
- virtual void ShowContextMenuForView(views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) OVERRIDE;
-
- // views::CustomButton overrides:
- virtual void StateChanged() OVERRIDE;
- virtual bool ShouldEnterPushedState(const ui::Event& event) OVERRIDE;
-
- // views::View overrides:
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnMouseCaptureLost() OVERRIDE;
- virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
-
- // ui::EventHandler overrides:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
- AppListItemModel* model_; // Owned by AppListModel.
-
- AppsGridView* apps_grid_view_; // Owned by views hierarchy.
- views::ImageView* icon_; // Owned by views hierarchy.
- CachedLabel* title_; // Owned by views hierarchy.
- ProgressBarView* progress_bar_; // Owned by views hierarchy.
-
- scoped_ptr<views::MenuRunner> context_menu_runner_;
-
- gfx::Size icon_size_;
- gfx::ShadowValues icon_shadows_;
-
- UIState ui_state_;
-
- // True if scroll gestures should contribute to dragging.
- bool touch_dragging_;
-
- // A timer to defer showing drag UI when mouse is pressed.
- base::OneShotTimer<AppListItemView> mouse_drag_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListItemView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_
diff --git a/chromium/ui/app_list/views/app_list_main_view.cc b/chromium/ui/app_list/views/app_list_main_view.cc
deleted file mode 100644
index e6f7a7c8a5d..00000000000
--- a/chromium/ui/app_list/views/app_list_main_view.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_main_view.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/views/app_list_item_view.h"
-#include "ui/app_list/views/contents_view.h"
-#include "ui/app_list/views/search_box_view.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/widget/widget.h"
-
-namespace app_list {
-
-namespace {
-
-// Inner padding space in pixels of bubble contents.
-const int kInnerPadding = 1;
-
-// The maximum allowed time to wait for icon loading in milliseconds.
-const int kMaxIconLoadingWaitTimeInMs = 50;
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// AppListMainView::IconLoader
-
-class AppListMainView::IconLoader : public AppListItemModelObserver {
- public:
- IconLoader(AppListMainView* owner,
- AppListItemModel* item,
- float scale)
- : owner_(owner),
- item_(item) {
- item_->AddObserver(this);
-
- // Triggers icon loading for given |scale_factor|.
- item_->icon().GetRepresentation(scale);
- }
-
- virtual ~IconLoader() {
- item_->RemoveObserver(this);
- }
-
- private:
- // AppListItemModelObserver overrides:
- virtual void ItemIconChanged() OVERRIDE {
- owner_->OnItemIconLoaded(this);
- // Note that IconLoader is released here.
- }
- virtual void ItemTitleChanged() OVERRIDE {}
- virtual void ItemHighlightedChanged() OVERRIDE {}
- virtual void ItemIsInstallingChanged() OVERRIDE {}
- virtual void ItemPercentDownloadedChanged() OVERRIDE {}
-
- AppListMainView* owner_;
- AppListItemModel* item_;
-
- DISALLOW_COPY_AND_ASSIGN(IconLoader);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// AppListMainView:
-
-AppListMainView::AppListMainView(AppListViewDelegate* delegate,
- PaginationModel* pagination_model,
- gfx::NativeView parent)
- : delegate_(delegate),
- pagination_model_(pagination_model),
- model_(delegate->GetModel()),
- search_box_view_(NULL),
- contents_view_(NULL),
- weak_ptr_factory_(this) {
- // Starts icon loading early.
- PreloadIcons(parent);
-
- SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
- kInnerPadding,
- kInnerPadding,
- kInnerPadding));
-
- search_box_view_ = new SearchBoxView(this, delegate);
- AddChildView(search_box_view_);
- AddContentsView();
-}
-
-void AppListMainView::AddContentsView() {
- contents_view_ =
- new ContentsView(this,
- pagination_model_,
- model_,
- delegate_ ? delegate_->GetStartPageContents() : NULL);
- AddChildView(contents_view_);
-
- search_box_view_->set_contents_view(contents_view_);
-
-#if defined(USE_AURA)
- contents_view_->SetPaintToLayer(true);
- contents_view_->SetFillsBoundsOpaquely(false);
- contents_view_->layer()->SetMasksToBounds(true);
-#endif
-}
-
-AppListMainView::~AppListMainView() {
- pending_icon_loaders_.clear();
-}
-
-void AppListMainView::ShowAppListWhenReady() {
- if (pending_icon_loaders_.empty()) {
- icon_loading_wait_timer_.Stop();
- GetWidget()->Show();
- return;
- }
-
- if (icon_loading_wait_timer_.IsRunning())
- return;
-
- icon_loading_wait_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs),
- this, &AppListMainView::OnIconLoadingWaitTimer);
-}
-
-void AppListMainView::Close() {
- icon_loading_wait_timer_.Stop();
- contents_view_->CancelDrag();
-}
-
-void AppListMainView::Prerender() {
- contents_view_->Prerender();
-}
-
-void AppListMainView::ModelChanged() {
- pending_icon_loaders_.clear();
- model_ = delegate_->GetModel();
- search_box_view_->ModelChanged();
- delete contents_view_;
- contents_view_ = NULL;
- pagination_model_->SelectPage(0, false /* animate */);
- AddContentsView();
- Layout();
-}
-
-void AppListMainView::SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host) {
- contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
-}
-
-void AppListMainView::PreloadIcons(gfx::NativeView parent) {
- ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P;
- if (parent)
- scale_factor = ui::GetScaleFactorForNativeView(parent);
-
- float scale = ui::GetImageScale(scale_factor);
- // |pagination_model| could have -1 as the initial selected page and
- // assumes first page (i.e. index 0) will be used in this case.
- const int selected_page = std::max(0, pagination_model_->selected_page());
-
- const int tiles_per_page = kPreferredCols * kPreferredRows;
- const int start_model_index = selected_page * tiles_per_page;
- const int end_model_index = std::min(
- static_cast<int>(model_->item_list()->item_count()),
- start_model_index + tiles_per_page);
-
- pending_icon_loaders_.clear();
- for (int i = start_model_index; i < end_model_index; ++i) {
- AppListItemModel* item = model_->item_list()->item_at(i);
- if (item->icon().HasRepresentation(scale))
- continue;
-
- pending_icon_loaders_.push_back(new IconLoader(this, item, scale));
- }
-}
-
-void AppListMainView::OnIconLoadingWaitTimer() {
- GetWidget()->Show();
-}
-
-void AppListMainView::OnItemIconLoaded(IconLoader* loader) {
- ScopedVector<IconLoader>::iterator it = std::find(
- pending_icon_loaders_.begin(), pending_icon_loaders_.end(), loader);
- DCHECK(it != pending_icon_loaders_.end());
- pending_icon_loaders_.erase(it);
-
- if (pending_icon_loaders_.empty() && icon_loading_wait_timer_.IsRunning()) {
- icon_loading_wait_timer_.Stop();
- GetWidget()->Show();
- }
-}
-
-void AppListMainView::ActivateApp(AppListItemModel* item, int event_flags) {
- // TODO(jennyz): Activate the folder via AppListModel notification.
- if (item->GetAppType() == AppListFolderItem::kAppType)
- contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
- else
- item->Activate(event_flags);
-}
-
-void AppListMainView::GetShortcutPathForApp(
- const std::string& app_id,
- const base::Callback<void(const base::FilePath&)>& callback) {
- delegate_->GetShortcutPathForApp(app_id, callback);
-}
-
-void AppListMainView::QueryChanged(SearchBoxView* sender) {
- base::string16 query;
- TrimWhitespace(model_->search_box()->text(), TRIM_ALL, &query);
- bool should_show_search = !query.empty();
- contents_view_->ShowSearchResults(should_show_search);
-
- if (should_show_search)
- delegate_->StartSearch();
- else
- delegate_->StopSearch();
-}
-
-void AppListMainView::OpenResult(SearchResult* result, int event_flags) {
- delegate_->OpenSearchResult(result, event_flags);
-}
-
-void AppListMainView::InvokeResultAction(SearchResult* result,
- int action_index,
- int event_flags) {
- delegate_->InvokeSearchResultAction(result, action_index, event_flags);
-}
-
-void AppListMainView::OnResultInstalled(SearchResult* result) {
- // Clears the search to show the apps grid. The last installed app
- // should be highlighted and made visible already.
- search_box_view_->ClearSearch();
-}
-
-void AppListMainView::OnResultUninstalled(SearchResult* result) {
- // Resubmit the query via a posted task so that all observers for the
- // uninstall notification are notified.
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&AppListMainView::QueryChanged,
- weak_ptr_factory_.GetWeakPtr(),
- search_box_view_));
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_main_view.h b/chromium/ui/app_list/views/app_list_main_view.h
deleted file mode 100644
index 1e119aa0b86..00000000000
--- a/chromium/ui/app_list/views/app_list_main_view.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APP_LIST_MAIN_VIEW_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_MAIN_VIEW_H_
-
-#include <string>
-
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/views/apps_grid_view_delegate.h"
-#include "ui/app_list/views/search_box_view_delegate.h"
-#include "ui/app_list/views/search_result_list_view_delegate.h"
-#include "ui/views/view.h"
-
-namespace views {
-class Widget;
-}
-
-namespace app_list {
-
-class ApplicationDragAndDropHost;
-class AppListModel;
-class AppListItemModel;
-class AppListViewDelegate;
-class ContentsView;
-class PaginationModel;
-class SearchBoxView;
-
-// AppListMainView contains the normal view of the app list, which is shown
-// when the user is signed in.
-class APP_LIST_EXPORT AppListMainView : public views::View,
- public AppsGridViewDelegate,
- public SearchBoxViewDelegate,
- public SearchResultListViewDelegate {
- public:
- // Takes ownership of |delegate|.
- explicit AppListMainView(AppListViewDelegate* delegate,
- PaginationModel* pagination_model,
- gfx::NativeView parent);
- virtual ~AppListMainView();
-
- void ShowAppListWhenReady();
-
- void Close();
-
- void Prerender();
-
- void ModelChanged();
-
- SearchBoxView* search_box_view() const { return search_box_view_; }
-
- // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
- // operations outside the application list.
- void SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host);
-
- ContentsView* contents_view() { return contents_view_; }
-
- private:
- class IconLoader;
-
- void AddContentsView();
-
- // Loads icon image for the apps in the selected page of |pagination_model_|.
- // |parent| is used to determine the image scale factor to use.
- void PreloadIcons(gfx::NativeView parent);
-
- // Invoked when |icon_loading_wait_timer_| fires.
- void OnIconLoadingWaitTimer();
-
- // Invoked from an IconLoader when icon loading is finished.
- void OnItemIconLoaded(IconLoader* loader);
-
- // Overridden from AppsGridViewDelegate:
- virtual void ActivateApp(AppListItemModel* item, int event_flags) OVERRIDE;
- virtual void GetShortcutPathForApp(
- const std::string& app_id,
- const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE;
-
- // Overridden from SearchBoxViewDelegate:
- virtual void QueryChanged(SearchBoxView* sender) OVERRIDE;
-
- // Overridden from SearchResultListViewDelegate:
- virtual void OpenResult(SearchResult* result,
- int event_flags) OVERRIDE;
- virtual void InvokeResultAction(SearchResult* result,
- int action_index,
- int event_flags) OVERRIDE;
- virtual void OnResultInstalled(SearchResult* result) OVERRIDE;
- virtual void OnResultUninstalled(SearchResult* result) OVERRIDE;
-
- AppListViewDelegate* delegate_; // Owned by parent view (AppListView).
- PaginationModel* pagination_model_; // Owned by AppListController.
- AppListModel* model_; // Unowned; ownership is handled by |delegate_|.
-
- SearchBoxView* search_box_view_; // Owned by views hierarchy.
- ContentsView* contents_view_; // Owned by views hierarchy.
-
- // A timer that fires when maximum allowed time to wait for icon loading has
- // passed.
- base::OneShotTimer<AppListMainView> icon_loading_wait_timer_;
-
- ScopedVector<IconLoader> pending_icon_loaders_;
-
- base::WeakPtrFactory<AppListMainView> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListMainView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_MAIN_VIEW_H_
diff --git a/chromium/ui/app_list/views/app_list_main_view_unittest.cc b/chromium/ui/app_list/views/app_list_main_view_unittest.cc
deleted file mode 100644
index 6ca1820ef44..00000000000
--- a/chromium/ui/app_list/views/app_list_main_view_unittest.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_main_view.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#include "ui/app_list/views/apps_container_view.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/app_list/views/contents_view.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/view_model.h"
-#include "ui/views/widget/widget.h"
-
-namespace app_list {
-namespace test {
-
-namespace {
-
-const int kInitialItems = 2;
-
-class AppListMainViewTest : public views::ViewsTestBase {
- public:
- AppListMainViewTest()
- : widget_(NULL),
- main_view_(NULL) {}
-
- virtual ~AppListMainViewTest() {}
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- views::ViewsTestBase::SetUp();
- delegate_.reset(new AppListTestViewDelegate);
- delegate_->GetTestModel()->PopulateApps(kInitialItems);
-
- main_view_ =
- new AppListMainView(delegate_.get(), &pagination_model_, GetContext());
- main_view_->SetPaintToLayer(true);
-
- widget_ = new views::Widget;
- views::Widget::InitParams params =
- CreateParams(views::Widget::InitParams::TYPE_POPUP);
- params.bounds.set_size(main_view_->GetPreferredSize());
- widget_->Init(params);
-
- widget_->SetContentsView(main_view_);
- }
-
- virtual void TearDown() OVERRIDE {
- widget_->Close();
- views::ViewsTestBase::TearDown();
- delegate_.reset();
- }
-
- const views::ViewModel* ViewModel() {
- return main_view_->contents_view()->apps_container_view()->apps_grid_view()
- ->view_model_for_test();
- }
-
- protected:
- views::Widget* widget_; // Owned by native window.
- AppListMainView* main_view_; // Owned by |widget_|.
- PaginationModel pagination_model_;
- scoped_ptr<AppListTestViewDelegate> delegate_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppListMainViewTest);
-};
-
-} // namespace
-
-// Tests changing the AppListModel when switching profiles.
-TEST_F(AppListMainViewTest, ModelChanged) {
- EXPECT_EQ(kInitialItems, ViewModel()->view_size());
-
- // The model is owned by a profile keyed service, which is never destroyed
- // until after profile switching.
- scoped_ptr<AppListModel> old_model(delegate_->ReleaseTestModel());
-
- const int kReplacementItems = 5;
- delegate_->ReplaceTestModel(kReplacementItems);
- main_view_->ModelChanged();
- EXPECT_EQ(kReplacementItems, ViewModel()->view_size());
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_menu_views.cc b/chromium/ui/app_list/views/app_list_menu_views.cc
deleted file mode 100644
index ee3e3e85cc0..00000000000
--- a/chromium/ui/app_list/views/app_list_menu_views.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_menu_views.h"
-
-#include "grit/ui_resources.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/menu/menu_config.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/submenu_view.h"
-#include "ui/views/layout/grid_layout.h"
-
-using views::MenuItemView;
-
-namespace app_list {
-
-AppListMenuViews::AppListMenuViews(AppListViewDelegate* delegate)
- : AppListMenu(delegate) {
- menu_delegate_.reset(new views::MenuModelAdapter(menu_model()));
- menu_ = new MenuItemView(menu_delegate_.get());
- menu_runner_.reset(new views::MenuRunner(menu_));
- menu_delegate_->BuildMenu(menu_);
-}
-
-AppListMenuViews::~AppListMenuViews() {}
-
-void AppListMenuViews::RunMenuAt(views::MenuButton* button,
- const gfx::Point& point) {
- ignore_result(menu_runner_->RunMenuAt(button->GetWidget(), button,
- gfx::Rect(point, gfx::Size()),
- MenuItemView::TOPRIGHT,
- ui::MENU_SOURCE_NONE, 0));
-}
-
-void AppListMenuViews::Cancel() {
- menu_runner_->Cancel();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_menu_views.h b/chromium/ui/app_list/views/app_list_menu_views.h
deleted file mode 100644
index 32efc3ac14f..00000000000
--- a/chromium/ui/app_list/views/app_list_menu_views.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APP_LIST_MENU_VIEWS_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_MENU_VIEWS_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/app_list_menu.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
-#include "ui/views/controls/menu/menu_runner.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace views {
-class MenuButton;
-}
-
-namespace app_list {
-
-// Views implementation of the app list menu.
-// TODO(benwells): We should consider moving this into Chrome.
-class AppListMenuViews : public AppListMenu {
- public:
- explicit AppListMenuViews(AppListViewDelegate* delegate);
- virtual ~AppListMenuViews();
-
- void RunMenuAt(views::MenuButton* button, const gfx::Point& point);
- void Cancel();
-
- private:
- // The context menu itself and its contents.
- scoped_ptr<views::MenuModelAdapter> menu_delegate_;
- views::MenuItemView* menu_; // Owned by menu_runner_.
- scoped_ptr<views::MenuRunner> menu_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListMenuViews);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_MENU_VIEWS_H_
diff --git a/chromium/ui/app_list/views/app_list_view.cc b/chromium/ui/app_list/views/app_list_view.cc
deleted file mode 100644
index fc15fc58d2a..00000000000
--- a/chromium/ui/app_list/views/app_list_view.cc
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/app_list_view.h"
-
-#include "base/command_line.h"
-#include "base/strings/string_util.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/signin_delegate.h"
-#include "ui/app_list/speech_ui_model.h"
-#include "ui/app_list/views/app_list_background.h"
-#include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/app_list_view_observer.h"
-#include "ui/app_list/views/search_box_view.h"
-#include "ui/app_list/views/signin_view.h"
-#include "ui/app_list/views/speech_view.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/bubble/bubble_frame_view.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#include "ui/aura/root_window.h"
-#if defined(OS_WIN)
-#include "ui/base/win/shell.h"
-#endif
-#if !defined(OS_CHROMEOS)
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#endif
-#endif // defined(USE_AURA)
-
-namespace app_list {
-
-namespace {
-
-void (*g_next_paint_callback)();
-
-// The margin from the edge to the speech UI.
-const int kSpeechUIMargin = 12;
-
-// The vertical position for the appearing animation of the speech UI.
-const float kSpeechUIApearingPosition =12;
-
-// The distance between the arrow tip and edge of the anchor view.
-const int kArrowOffset = 10;
-
-#if defined(OS_LINUX)
-// The WM_CLASS name for the app launcher window on Linux.
-const char* kAppListWMClass = "chrome_app_list";
-#endif
-
-// Determines whether the current environment supports shadows bubble borders.
-bool SupportsShadow() {
-#if defined(USE_AURA) && defined(OS_WIN)
- // Shadows are not supported on Windows Aura without Aero Glass.
- if (!ui::win::IsAeroGlassEnabled() ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableDwmComposition)) {
- return false;
- }
-#elif defined(OS_LINUX) && !defined(USE_ASH)
- // Shadows are not supported on (non-ChromeOS) Linux.
- return false;
-#endif
- return true;
-}
-
-} // namespace
-
-// An animation observer to hide the view at the end of the animation.
-class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
- public:
- HideViewAnimationObserver() : target_(NULL) {
- }
-
- virtual ~HideViewAnimationObserver() {
- if (target_)
- StopObservingImplicitAnimations();
- }
-
- void SetTarget(views::View* target) {
- if (!target_)
- StopObservingImplicitAnimations();
- target_ = target;
- }
-
- private:
- // Overridden from ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE {
- if (target_) {
- target_->SetVisible(false);
- target_ = NULL;
- }
- }
-
- views::View* target_;
-
- DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// AppListView:
-
-AppListView::AppListView(AppListViewDelegate* delegate)
- : delegate_(delegate),
- app_list_main_view_(NULL),
- signin_view_(NULL),
- speech_view_(NULL),
- animation_observer_(new HideViewAnimationObserver()) {
- CHECK(delegate);
-
- delegate_->AddObserver(this);
- delegate_->GetSpeechUI()->AddObserver(this);
-}
-
-AppListView::~AppListView() {
- delegate_->GetSpeechUI()->RemoveObserver(this);
- delegate_->RemoveObserver(this);
- animation_observer_.reset();
- // Remove child views first to ensure no remaining dependencies on delegate_.
- RemoveAllChildViews(true);
-}
-
-void AppListView::InitAsBubbleAttachedToAnchor(
- gfx::NativeView parent,
- PaginationModel* pagination_model,
- views::View* anchor,
- const gfx::Vector2d& anchor_offset,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events) {
- SetAnchorView(anchor);
- InitAsBubbleInternal(
- parent, pagination_model, arrow, border_accepts_events, anchor_offset);
-}
-
-void AppListView::InitAsBubbleAtFixedLocation(
- gfx::NativeView parent,
- PaginationModel* pagination_model,
- const gfx::Point& anchor_point_in_screen,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events) {
- SetAnchorView(NULL);
- SetAnchorRect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
- InitAsBubbleInternal(
- parent, pagination_model, arrow, border_accepts_events, gfx::Vector2d());
-}
-
-void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
- GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
- SizeToContents(); // Recalcuates with new border.
- GetBubbleFrameView()->SchedulePaint();
-}
-
-void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
- SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
-}
-
-void AppListView::SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host) {
- app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
-}
-
-void AppListView::ShowWhenReady() {
- app_list_main_view_->ShowAppListWhenReady();
-}
-
-void AppListView::Close() {
- app_list_main_view_->Close();
- delegate_->Dismiss();
-}
-
-void AppListView::UpdateBounds() {
- SizeToContents();
-}
-
-gfx::Size AppListView::GetPreferredSize() {
- return app_list_main_view_->GetPreferredSize();
-}
-
-void AppListView::Paint(gfx::Canvas* canvas) {
- views::BubbleDelegateView::Paint(canvas);
- if (g_next_paint_callback) {
- g_next_paint_callback();
- g_next_paint_callback = NULL;
- }
-}
-
-bool AppListView::ShouldHandleSystemCommands() const {
- return true;
-}
-
-void AppListView::Prerender() {
- app_list_main_view_->Prerender();
-}
-
-void AppListView::OnProfilesChanged() {
- SigninDelegate* signin_delegate =
- delegate_ ? delegate_->GetSigninDelegate() : NULL;
- bool show_signin_view = signin_delegate && signin_delegate->NeedSignin();
-
- signin_view_->SetVisible(show_signin_view);
- app_list_main_view_->SetVisible(!show_signin_view);
- app_list_main_view_->search_box_view()->InvalidateMenu();
-}
-
-void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
- delegate_->SetProfileByPath(profile_path);
- app_list_main_view_->ModelChanged();
-}
-
-void AppListView::AddObserver(AppListViewObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void AppListView::RemoveObserver(AppListViewObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-// static
-void AppListView::SetNextPaintCallback(void (*callback)()) {
- g_next_paint_callback = callback;
-}
-
-#if defined(OS_WIN)
-HWND AppListView::GetHWND() const {
-#if defined(USE_AURA)
- gfx::NativeWindow window =
- GetWidget()->GetTopLevelWidget()->GetNativeWindow();
- return window->GetDispatcher()->host()->GetAcceleratedWidget();
-#else
- return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
-#endif
-}
-#endif
-
-void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
- PaginationModel* pagination_model,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events,
- const gfx::Vector2d& anchor_offset) {
- app_list_main_view_ = new AppListMainView(delegate_.get(),
- pagination_model,
- parent);
- AddChildView(app_list_main_view_);
-#if defined(USE_AURA)
- app_list_main_view_->SetPaintToLayer(true);
- app_list_main_view_->SetFillsBoundsOpaquely(false);
- app_list_main_view_->layer()->SetMasksToBounds(true);
-#endif
-
- signin_view_ =
- new SigninView(delegate_->GetSigninDelegate(),
- app_list_main_view_->GetPreferredSize().width());
- AddChildView(signin_view_);
-
- // Speech recognition is available only when the start page exists.
- if (delegate_ && delegate_->GetStartPageContents()) {
- speech_view_ = new SpeechView(delegate_.get());
- speech_view_->SetVisible(false);
-#if defined(USE_AURA)
- speech_view_->SetPaintToLayer(true);
- speech_view_->SetFillsBoundsOpaquely(false);
- speech_view_->layer()->SetOpacity(0.0f);
-#endif
- AddChildView(speech_view_);
- }
-
- OnProfilesChanged();
- set_color(kContentsBackgroundColor);
- set_margins(gfx::Insets());
- set_move_with_anchor(true);
- set_parent_window(parent);
- set_close_on_deactivate(false);
- set_close_on_esc(false);
- set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
- kArrowOffset + anchor_offset.x(),
- kArrowOffset - anchor_offset.y(),
- kArrowOffset - anchor_offset.x()));
- set_border_accepts_events(border_accepts_events);
- set_shadow(SupportsShadow() ? views::BubbleBorder::BIG_SHADOW
- : views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
- views::BubbleDelegateView::CreateBubble(this);
- SetBubbleArrow(arrow);
-
-#if defined(USE_AURA)
- GetWidget()->GetNativeWindow()->layer()->SetMasksToBounds(true);
- GetBubbleFrameView()->set_background(new AppListBackground(
- GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
- app_list_main_view_));
- set_background(NULL);
-#else
- set_background(new AppListBackground(
- GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
- app_list_main_view_));
-
- // On non-aura the bubble has two widgets, and it's possible for the border
- // to be shown independently in odd situations. Explicitly hide the bubble
- // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
- // window manager do not have the SWP_SHOWWINDOW flag set which would cause
- // the border to be shown. See http://crbug.com/231687 .
- GetWidget()->Hide();
-#endif
-}
-
-void AppListView::OnBeforeBubbleWidgetInit(
- views::Widget::InitParams* params,
- views::Widget* widget) const {
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
- if (delegate_ && delegate_->ForceNativeDesktop())
- params->native_widget = new views::DesktopNativeWidgetAura(widget);
-#endif
-#if defined(OS_LINUX)
- // Set up a custom WM_CLASS for the app launcher window. This allows task
- // switchers in X11 environments to distinguish it from main browser windows.
- params->wm_class_name = kAppListWMClass;
-#endif
-}
-
-views::View* AppListView::GetInitiallyFocusedView() {
- return app_list_main_view_->search_box_view()->search_box();
-}
-
-gfx::ImageSkia AppListView::GetWindowIcon() {
- if (delegate_)
- return delegate_->GetWindowIcon();
-
- return gfx::ImageSkia();
-}
-
-bool AppListView::WidgetHasHitTestMask() const {
- return true;
-}
-
-void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
- DCHECK(mask);
- mask->addRect(gfx::RectToSkRect(
- GetBubbleFrameView()->GetContentsBounds()));
-}
-
-bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
- // The accelerator is added by BubbleDelegateView.
- if (accelerator.key_code() == ui::VKEY_ESCAPE) {
- if (app_list_main_view_->search_box_view()->HasSearch()) {
- app_list_main_view_->search_box_view()->ClearSearch();
- } else {
- GetWidget()->Deactivate();
- Close();
- }
- return true;
- }
-
- return false;
-}
-
-void AppListView::Layout() {
- const gfx::Rect contents_bounds = GetContentsBounds();
- app_list_main_view_->SetBoundsRect(contents_bounds);
- signin_view_->SetBoundsRect(contents_bounds);
-
- if (speech_view_) {
- gfx::Rect speech_bounds = contents_bounds;
- int preferred_height = speech_view_->GetPreferredSize().height();
- speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
- speech_bounds.set_height(std::min(speech_bounds.height(),
- preferred_height));
- speech_bounds.Inset(-speech_view_->GetInsets());
- speech_view_->SetBoundsRect(speech_bounds);
- }
-}
-
-void AppListView::OnWidgetDestroying(views::Widget* widget) {
- BubbleDelegateView::OnWidgetDestroying(widget);
- if (delegate_ && widget == GetWidget())
- delegate_->ViewClosing();
-}
-
-void AppListView::OnWidgetActivationChanged(views::Widget* widget,
- bool active) {
- // Do not called inherited function as the bubble delegate auto close
- // functionality is not used.
- if (widget == GetWidget())
- FOR_EACH_OBSERVER(AppListViewObserver, observers_,
- OnActivationChanged(widget, active));
-}
-
-void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
- bool visible) {
- BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
-
- if (widget != GetWidget())
- return;
-
- // We clear the search when hiding so the next time the app list appears it is
- // not showing search results.
- if (!visible)
- app_list_main_view_->search_box_view()->ClearSearch();
-
- // Whether we need to signin or not may have changed since last time we were
- // shown.
- Layout();
-}
-
-void AppListView::OnSpeechRecognitionStateChanged(
- SpeechRecognitionState new_state) {
- DCHECK(!signin_view_->visible());
-
- bool recognizing = new_state != SPEECH_RECOGNITION_NOT_STARTED;
- // No change for this class.
- if (speech_view_->visible() == recognizing)
- return;
-
- if (recognizing)
- speech_view_->Reset();
-
-#if defined(USE_AURA)
- gfx::Transform speech_transform;
- speech_transform.Translate(
- 0, SkFloatToMScalar(kSpeechUIApearingPosition));
- if (recognizing)
- speech_view_->layer()->SetTransform(speech_transform);
-
- {
- ui::ScopedLayerAnimationSettings main_settings(
- app_list_main_view_->layer()->GetAnimator());
- if (recognizing) {
- animation_observer_->SetTarget(app_list_main_view_);
- main_settings.AddObserver(animation_observer_.get());
- }
- app_list_main_view_->layer()->SetOpacity(recognizing ? 0.0f : 1.0f);
- }
-
- {
- ui::ScopedLayerAnimationSettings speech_settings(
- speech_view_->layer()->GetAnimator());
- if (!recognizing) {
- animation_observer_->SetTarget(speech_view_);
- speech_settings.AddObserver(animation_observer_.get());
- }
-
- speech_view_->layer()->SetOpacity(recognizing ? 1.0f : 0.0f);
- if (recognizing)
- speech_view_->layer()->SetTransform(gfx::Transform());
- else
- speech_view_->layer()->SetTransform(speech_transform);
- }
-
- if (recognizing)
- speech_view_->SetVisible(true);
- else
- app_list_main_view_->SetVisible(true);
-#else
- speech_view_->SetVisible(recognizing);
- app_list_main_view_->SetVisible(!recognizing);
-#endif
-
- // Needs to schedule paint of AppListView itself, to repaint the background.
- SchedulePaint();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/app_list_view.h b/chromium/ui/app_list/views/app_list_view.h
deleted file mode 100644
index fb03c2dd84b..00000000000
--- a/chromium/ui/app_list/views/app_list_view.h
+++ /dev/null
@@ -1,154 +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_APP_LIST_VIEWS_APP_LIST_VIEW_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_VIEW_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_view_delegate_observer.h"
-#include "ui/app_list/speech_ui_model_observer.h"
-#include "ui/views/bubble/bubble_delegate.h"
-#include "ui/views/widget/widget.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace app_list {
-class ApplicationDragAndDropHost;
-class AppListMainView;
-class AppListModel;
-class AppListViewDelegate;
-class AppListViewObserver;
-class HideViewAnimationObserver;
-class PaginationModel;
-class SigninDelegate;
-class SigninView;
-class SpeechView;
-
-// AppListView is the top-level view and controller of app list UI. It creates
-// and hosts a AppsGridView and passes AppListModel to it for display.
-class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
- public AppListViewDelegateObserver,
- public SpeechUIModelObserver {
- public:
-
- // Takes ownership of |delegate|.
- explicit AppListView(AppListViewDelegate* delegate);
- virtual ~AppListView();
-
- // Initializes the widget and use a given |anchor| plus an |anchor_offset| for
- // positioning.
- void InitAsBubbleAttachedToAnchor(gfx::NativeView parent,
- PaginationModel* pagination_model,
- views::View* anchor,
- const gfx::Vector2d& anchor_offset,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events);
-
- // Initializes the widget and use a fixed |anchor_point_in_screen| for
- // positioning.
- void InitAsBubbleAtFixedLocation(gfx::NativeView parent,
- PaginationModel* pagination_model,
- const gfx::Point& anchor_point_in_screen,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events);
-
- void SetBubbleArrow(views::BubbleBorder::Arrow arrow);
-
- void SetAnchorPoint(const gfx::Point& anchor_point);
-
- // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
- // operations outside the application list. This has to be called after
- // InitAsBubble was called since the app list object needs to exist so that
- // it can set the host.
- void SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host);
-
- // Shows the UI when there are no pending icon loads. Otherwise, starts a
- // timer to show the UI when a maximum allowed wait time has expired.
- void ShowWhenReady();
-
- void Close();
-
- void UpdateBounds();
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
-
- // WidgetDelegate overrides:
- virtual bool ShouldHandleSystemCommands() const OVERRIDE;
-
- // Overridden from AppListViewDelegateObserver:
- virtual void OnProfilesChanged() OVERRIDE;
-
- void Prerender();
-
- void SetProfileByPath(const base::FilePath& profile_path);
-
- void AddObserver(AppListViewObserver* observer);
- void RemoveObserver(AppListViewObserver* observer);
-
- // Set a callback to be called the next time any app list paints.
- static void SetNextPaintCallback(void (*callback)());
-
-#if defined(OS_WIN)
- HWND GetHWND() const;
-#endif
-
- AppListMainView* app_list_main_view() { return app_list_main_view_; }
-
- private:
- void InitAsBubbleInternal(gfx::NativeView parent,
- PaginationModel* pagination_model,
- views::BubbleBorder::Arrow arrow,
- bool border_accepts_events,
- const gfx::Vector2d& anchor_offset);
-
- // Overridden from views::BubbleDelegateView:
- virtual void OnBeforeBubbleWidgetInit(
- views::Widget::InitParams* params,
- views::Widget* widget) const OVERRIDE;
-
- // Overridden from views::WidgetDelegateView:
- virtual views::View* GetInitiallyFocusedView() OVERRIDE;
- virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
- virtual bool WidgetHasHitTestMask() const OVERRIDE;
- virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE;
-
- // Overridden from views::View:
- virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
- virtual void Layout() OVERRIDE;
-
- // Overridden from views::WidgetObserver:
- virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE;
- virtual void OnWidgetVisibilityChanged(
- views::Widget* widget, bool visible) OVERRIDE;
- virtual void OnWidgetActivationChanged(
- views::Widget* widget, bool active) OVERRIDE;
-
- // Overridden from SpeechUIModelObserver:
- virtual void OnSpeechRecognitionStateChanged(
- SpeechRecognitionState new_state) OVERRIDE;
-
- SigninDelegate* GetSigninDelegate();
-
- scoped_ptr<AppListViewDelegate> delegate_;
-
- AppListMainView* app_list_main_view_;
- SigninView* signin_view_;
- SpeechView* speech_view_;
-
- ObserverList<AppListViewObserver> observers_;
- scoped_ptr<HideViewAnimationObserver> animation_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(AppListView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_VIEW_H_
diff --git a/chromium/ui/app_list/views/app_list_view_observer.h b/chromium/ui/app_list/views/app_list_view_observer.h
deleted file mode 100644
index f9fb61c819d..00000000000
--- a/chromium/ui/app_list/views/app_list_view_observer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APP_LIST_VIEW_OBSERVER_H_
-#define UI_APP_LIST_VIEWS_APP_LIST_VIEW_OBSERVER_H_
-
-namespace views {
-class Widget;
-}
-
-namespace app_list {
-
-class AppListViewObserver {
- public:
- virtual void OnActivationChanged(views::Widget* widget, bool active) = 0;
-
- protected:
- virtual ~AppListViewObserver() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APP_LIST_VIEW_OBSERVER_H_
diff --git a/chromium/ui/app_list/views/apps_container_view.cc b/chromium/ui/app_list/views/apps_container_view.cc
deleted file mode 100644
index 6b3054d1a47..00000000000
--- a/chromium/ui/app_list/views/apps_container_view.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/apps_container_view.h"
-
-#include <algorithm>
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/views/app_list_folder_view.h"
-#include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/events/event.h"
-
-namespace app_list {
-
-AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
- PaginationModel* pagination_model,
- AppListModel* model,
- content::WebContents* start_page_contents)
- : model_(model),
- show_state_(SHOW_APPS) {
- apps_grid_view_ = new AppsGridView(
- app_list_main_view, pagination_model, start_page_contents);
- apps_grid_view_->SetLayout(kPreferredIconDimension,
- kPreferredCols,
- kPreferredRows);
- AddChildView(apps_grid_view_);
-
- app_list_folder_view_ = new AppListFolderView(
- this,
- model,
- app_list_main_view,
- start_page_contents);
- AddChildView(app_list_folder_view_);
-
- apps_grid_view_->SetModel(model_);
- apps_grid_view_->SetItemList(model_->item_list());
-}
-
-AppsContainerView::~AppsContainerView() {
-}
-
-void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
- app_list_folder_view_->SetAppListFolderItem(folder_item);
- SetShowState(SHOW_ACTIVE_FOLDER);
-}
-
-void AppsContainerView::ShowApps() {
- SetShowState(SHOW_APPS);
-}
-
-gfx::Size AppsContainerView::GetPreferredSize() {
- const gfx::Size grid_size = apps_grid_view_->GetPreferredSize();
- const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize();
-
- int width = std::max(grid_size.width(), folder_view_size.width());
- int height = std::max(grid_size.height(), folder_view_size.height());
- return gfx::Size(width, height);
-}
-
-void AppsContainerView::Layout() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- switch (show_state_) {
- case SHOW_APPS:
- app_list_folder_view_->SetVisible(false);
- apps_grid_view_->SetBoundsRect(rect);
- apps_grid_view_->SetVisible(true);
- break;
- case SHOW_ACTIVE_FOLDER:
- apps_grid_view_->SetVisible(false);
- app_list_folder_view_->SetBoundsRect(rect);
- app_list_folder_view_->SetVisible(true);
- break;
- default:
- NOTREACHED();
- }
-}
-
-bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
- if (show_state_ == SHOW_APPS)
- return apps_grid_view_->OnKeyPressed(event);
- else
- return app_list_folder_view_->OnKeyPressed(event);
-}
-
-void AppsContainerView::SetShowState(ShowState show_state) {
- if (show_state_ == show_state)
- return;
-
- show_state_ = show_state;
- Layout();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/apps_container_view.h b/chromium/ui/app_list/views/apps_container_view.h
deleted file mode 100644
index 802f033efc2..00000000000
--- a/chromium/ui/app_list/views/apps_container_view.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
-#define UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
-
-#include "ui/views/view.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace app_list {
-
-class AppsGridView;
-class AppListFolderItem;
-class AppListFolderView;
-class AppListMainView;
-class AppListModel;
-class ContentsView;
-class PaginationModel;
-
-// AppsContainerView contains a root level AppsGridView to render the root level
-// app items, and a AppListFolderView to render the app items inside the
-// active folder. Only one if them is visible to user at any time.
-class AppsContainerView : public views::View {
- public:
- AppsContainerView(AppListMainView* app_list_main_view,
- PaginationModel* pagination_model,
- AppListModel* model,
- content::WebContents* start_page_contents);
- virtual ~AppsContainerView();
-
- // Shows the active folder content specified by |folder_item|.
- void ShowActiveFolder(AppListFolderItem* folder_item);
-
- // Shows the apps list from root.
- void ShowApps();
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
-
- AppsGridView* apps_grid_view() { return apps_grid_view_; }
-
- private:
- enum ShowState {
- SHOW_APPS,
- SHOW_ACTIVE_FOLDER,
- };
-
- void SetShowState(ShowState show_state);
-
- AppListModel* model_;
- AppsGridView* apps_grid_view_; // Owned by views hierarchy.
- AppListFolderView* app_list_folder_view_; // Owned by views hierarchy.
- ShowState show_state_;
-
- DISALLOW_COPY_AND_ASSIGN(AppsContainerView);
-};
-
-} // namespace app_list
-
-
-#endif // UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
diff --git a/chromium/ui/app_list/views/apps_grid_view.cc b/chromium/ui/app_list/views/apps_grid_view.cc
deleted file mode 100644
index 242501db78e..00000000000
--- a/chromium/ui/app_list/views/apps_grid_view.cc
+++ /dev/null
@@ -1,1671 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/apps_grid_view.h"
-
-#include <algorithm>
-#include <set>
-#include <string>
-
-#include "base/guid.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/views/app_list_drag_and_drop_host.h"
-#include "ui/app_list/views/app_list_item_view.h"
-#include "ui/app_list/views/apps_grid_view_delegate.h"
-#include "ui/app_list/views/page_switcher.h"
-#include "ui/app_list/views/pulsing_block_view.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
-#include "ui/gfx/animation/animation.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/view_model_utils.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#if defined(OS_WIN)
-#include "ui/views/win/hwnd_util.h"
-#endif // defined(OS_WIN)
-#endif // defined(USE_AURA)
-
-#if defined(OS_WIN)
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/win/shortcut.h"
-#include "ui/base/dragdrop/drag_utils.h"
-#include "ui/base/dragdrop/drop_target_win.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-#endif
-
-namespace app_list {
-
-namespace {
-
-// Distance a drag needs to be from the app grid to be considered 'outside', at
-// which point we rearrange the apps to their pre-drag configuration, as a drop
-// then would be canceled. We have a buffer to make it easier to drag apps to
-// other pages.
-const int kDragBufferPx = 20;
-
-// Padding space in pixels for fixed layout.
-const int kLeftRightPadding = 20;
-const int kTopPadding = 1;
-
-// Padding space in pixels between pages.
-const int kPagePadding = 40;
-
-// Preferred tile size when showing in fixed layout.
-const int kPreferredTileWidth = 88;
-const int kPreferredTileHeight = 98;
-
-// Width in pixels of the area on the sides that triggers a page flip.
-const int kPageFlipZoneSize = 40;
-
-// Delay in milliseconds to do the page flip.
-const int kPageFlipDelayInMs = 1000;
-
-// How many pages on either side of the selected one we prerender.
-const int kPrerenderPages = 1;
-
-// The drag and drop proxy should get scaled by this factor.
-const float kDragAndDropProxyScale = 1.5f;
-
-// Delays in milliseconds to show folder dropping preview circle.
-const int kFolderDroppingDelay = 250;
-
-// Delays in milliseconds to show re-order preview.
-const int kReorderDelay = 50;
-
-// Radius of the circle, in which if entered, show folder dropping preview
-// UI.
-const int kFolderDroppingCircleRadius = 15;
-
-// Radius of the circle, in which if entered, show re-order preview.
-const int kReorderDroppingCircleRadius = 30;
-
-// Max items allowed in a folder.
-size_t kMaxFolderItems = 16;
-
-// RowMoveAnimationDelegate is used when moving an item into a different row.
-// Before running the animation, the item's layer is re-created and kept in
-// the original position, then the item is moved to just before its target
-// position and opacity set to 0. When the animation runs, this delegate moves
-// the layer and fades it out while fading in the item at the same time.
-class RowMoveAnimationDelegate
- : public views::BoundsAnimator::OwnedAnimationDelegate {
- public:
- RowMoveAnimationDelegate(views::View* view,
- ui::Layer* layer,
- const gfx::Rect& layer_target)
- : view_(view),
- layer_(layer),
- layer_start_(layer ? layer->bounds() : gfx::Rect()),
- layer_target_(layer_target) {
- }
- virtual ~RowMoveAnimationDelegate() {}
-
- // gfx::AnimationDelegate overrides:
- virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE {
- view_->layer()->SetOpacity(animation->GetCurrentValue());
- view_->layer()->ScheduleDraw();
-
- if (layer_) {
- layer_->SetOpacity(1 - animation->GetCurrentValue());
- layer_->SetBounds(animation->CurrentValueBetween(layer_start_,
- layer_target_));
- layer_->ScheduleDraw();
- }
- }
- virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE {
- view_->layer()->SetOpacity(1.0f);
- view_->layer()->ScheduleDraw();
- }
- virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
- view_->layer()->SetOpacity(1.0f);
- view_->layer()->ScheduleDraw();
- }
-
- private:
- // The view that needs to be wrapped. Owned by views hierarchy.
- views::View* view_;
-
- scoped_ptr<ui::Layer> layer_;
- const gfx::Rect layer_start_;
- const gfx::Rect layer_target_;
-
- DISALLOW_COPY_AND_ASSIGN(RowMoveAnimationDelegate);
-};
-
-// ItemRemoveAnimationDelegate is used to show animation for removing an item.
-// This happens when user drags an item into a folder. The dragged item will
-// be removed from the original list after it is dropped into the folder.
-class ItemRemoveAnimationDelegate
- : public views::BoundsAnimator::OwnedAnimationDelegate {
- public:
- explicit ItemRemoveAnimationDelegate(views::View* view)
- : view_(view) {
- }
-
- virtual ~ItemRemoveAnimationDelegate() {
- }
-
- // gfx::AnimationDelegate overrides:
- virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE {
- view_->layer()->SetOpacity(1 - animation->GetCurrentValue());
- view_->layer()->ScheduleDraw();
- }
-
- private:
- scoped_ptr<views::View> view_;
-
- DISALLOW_COPY_AND_ASSIGN(ItemRemoveAnimationDelegate);
-};
-
-// Gets the distance between the centers of the |rect_1| and |rect_2|.
-int GetDistanceBetweenRects(gfx::Rect rect_1,
- gfx::Rect rect_2) {
- return (rect_1.CenterPoint() - rect_2.CenterPoint()).Length();
-}
-
-// Returns true if the |item| is an folder item.
-bool IsFolderItem(AppListItemModel* item) {
- return (item->GetAppType() == AppListFolderItem::kAppType);
-}
-
-// Merges |source_item| into the folder containing the target item specified
-// by |target_item_id|. Both |source_item| and target item belongs to
-// |item_list|.
-// Returns the index of the target folder.
-size_t MergeItems(AppListItemList* item_list,
- const std::string& target_item_id,
- AppListItemModel* source_item) {
- scoped_ptr<AppListItemModel> source_item_ptr =
- item_list->RemoveItem(source_item->id());
- DCHECK_EQ(source_item, source_item_ptr.get());
- size_t target_index;
- bool found_target_item = item_list->FindItemIndex(target_item_id,
- &target_index);
- DCHECK(found_target_item);
- AppListItemModel* target_item = item_list->item_at(target_index);
- if (IsFolderItem(target_item)) {
- AppListFolderItem* target_folder =
- static_cast<AppListFolderItem*>(target_item);
- target_folder->item_list()->AddItem(source_item_ptr.release());
- } else {
- scoped_ptr<AppListItemModel> target_item_ptr =
- item_list->RemoveItemAt(target_index);
- DCHECK_EQ(target_item, target_item_ptr.get());
- AppListFolderItem* new_folder =
- new AppListFolderItem(base::GenerateGUID());
- new_folder->item_list()->AddItem(target_item_ptr.release());
- new_folder->item_list()->AddItem(source_item_ptr.release());
- item_list->InsertItemAt(new_folder, target_index);
- }
-
- return target_index;
-}
-
-} // namespace
-
-#if defined(OS_WIN)
-// Interprets drag events sent from Windows via the drag/drop API and forwards
-// them to AppsGridView.
-// On Windows, in order to have the OS perform the drag properly we need to
-// provide it with a shortcut file which may or may not exist at the time the
-// drag is started. Therefore while waiting for that shortcut to be located we
-// just do a regular "internal" drag and transition into the synchronous drag
-// when the shortcut is found/created. Hence a synchronous drag is an optional
-// phase of a regular drag and non-Windows platforms drags are equivalent to a
-// Windows drag that never enters the synchronous drag phase.
-class SynchronousDrag : public ui::DragSourceWin {
- public:
- SynchronousDrag(AppsGridView* grid_view,
- AppListItemView* drag_view,
- const gfx::Point& drag_view_offset)
- : grid_view_(grid_view),
- drag_view_(drag_view),
- drag_view_offset_(drag_view_offset),
- has_shortcut_path_(false),
- running_(false),
- canceled_(false) {}
-
- void set_shortcut_path(const base::FilePath& shortcut_path) {
- has_shortcut_path_ = true;
- shortcut_path_ = shortcut_path;
- }
-
- bool CanRun() {
- return has_shortcut_path_ && !running_;
- }
-
- void Run() {
- DCHECK(CanRun());
- running_ = true;
-
- ui::OSExchangeData data;
- SetupExchangeData(&data);
-
- // Hide the dragged view because the OS is going to create its own.
- const gfx::Size drag_view_size = drag_view_->size();
- drag_view_->SetSize(gfx::Size(0, 0));
-
- // Blocks until the drag is finished. Calls into the ui::DragSourceWin
- // methods.
- DWORD effects;
- DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data),
- this, DROPEFFECT_MOVE | DROPEFFECT_LINK, &effects);
-
- // Restore the dragged view to its original size.
- drag_view_->SetSize(drag_view_size);
- drag_view_->OnSyncDragEnd();
-
- grid_view_->EndDrag(canceled_ || !IsCursorWithinGridView());
- }
-
- private:
- // Overridden from ui::DragSourceWin.
- virtual void OnDragSourceCancel() OVERRIDE {
- canceled_ = true;
- }
-
- virtual void OnDragSourceDrop() OVERRIDE {
- }
-
- virtual void OnDragSourceMove() OVERRIDE {
- grid_view_->UpdateDrag(AppsGridView::MOUSE, GetCursorInGridViewCoords());
- }
-
- void SetupExchangeData(ui::OSExchangeData* data) {
- data->SetFilename(shortcut_path_);
- gfx::ImageSkia image(drag_view_->GetDragImage());
- gfx::Size image_size(image.size());
- drag_utils::SetDragImageOnDataObject(
- image,
- image.size(),
- drag_view_offset_ - drag_view_->GetDragImageOffset(),
- data);
- }
-
- HWND GetGridViewHWND() {
- return views::HWNDForView(grid_view_);
- }
-
- bool IsCursorWithinGridView() {
- POINT p;
- GetCursorPos(&p);
- return GetGridViewHWND() == WindowFromPoint(p);
- }
-
- gfx::Point GetCursorInGridViewCoords() {
- POINT p;
- GetCursorPos(&p);
- ScreenToClient(GetGridViewHWND(), &p);
- gfx::Point grid_view_pt(p.x, p.y);
- views::View::ConvertPointFromWidget(grid_view_, &grid_view_pt);
- return grid_view_pt;
- }
-
- AppsGridView* grid_view_;
- AppListItemView* drag_view_;
- gfx::Point drag_view_offset_;
- bool has_shortcut_path_;
- base::FilePath shortcut_path_;
- bool running_;
- bool canceled_;
-
- DISALLOW_COPY_AND_ASSIGN(SynchronousDrag);
-};
-#endif // defined(OS_WIN)
-
-AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
- PaginationModel* pagination_model,
- content::WebContents* start_page_contents)
- : model_(NULL),
- item_list_(NULL),
- delegate_(delegate),
- pagination_model_(pagination_model),
- page_switcher_view_(new PageSwitcher(pagination_model)),
- start_page_view_(NULL),
- cols_(0),
- rows_per_page_(0),
- selected_view_(NULL),
- drag_view_(NULL),
- drag_start_page_(-1),
- drag_pointer_(NONE),
- drop_attempt_(DROP_FOR_NONE),
- drag_and_drop_host_(NULL),
- forward_events_to_drag_and_drop_host_(false),
- page_flip_target_(-1),
- page_flip_delay_in_ms_(kPageFlipDelayInMs),
- bounds_animator_(this),
- is_root_level_(true) {
- pagination_model_->AddObserver(this);
- AddChildView(page_switcher_view_);
-
- if (start_page_contents) {
- start_page_view_ =
- new views::WebView(start_page_contents->GetBrowserContext());
- start_page_view_->SetWebContents(start_page_contents);
- AddChildView(start_page_view_);
- start_page_contents->GetWebUI()->CallJavascriptFunction(
- "appList.startPage.onAppListShown");
- }
-}
-
-AppsGridView::~AppsGridView() {
- // Coming here |drag_view_| should already be canceled since otherwise the
- // drag would disappear after the app list got animated away and closed,
- // which would look odd.
- DCHECK(!drag_view_);
- if (drag_view_)
- EndDrag(true);
-
- if (model_)
- model_->RemoveObserver(this);
- pagination_model_->RemoveObserver(this);
-
- if (item_list_)
- item_list_->RemoveObserver(this);
-
- if (start_page_view_) {
- start_page_view_->GetWebContents()->GetWebUI()->CallJavascriptFunction(
- "appList.startPage.onAppListHidden");
- }
-}
-
-void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) {
- icon_size_.SetSize(icon_size, icon_size);
- cols_ = cols;
- rows_per_page_ = rows_per_page;
-
- set_border(views::Border::CreateEmptyBorder(kTopPadding,
- kLeftRightPadding,
- 0,
- kLeftRightPadding));
-}
-
-void AppsGridView::SetModel(AppListModel* model) {
- if (model_)
- model_->RemoveObserver(this);
-
- model_ = model;
- if (model_)
- model_->AddObserver(this);
-
- Update();
-}
-
-void AppsGridView::SetItemList(AppListItemList* item_list) {
- if (item_list_)
- item_list_->RemoveObserver(this);
-
- item_list_ = item_list;
- item_list_->AddObserver(this);
- Update();
-}
-
-void AppsGridView::SetSelectedView(views::View* view) {
- if (IsSelectedView(view) || IsDraggedView(view))
- return;
-
- Index index = GetIndexOfView(view);
- if (IsValidIndex(index))
- SetSelectedItemByIndex(index);
-}
-
-void AppsGridView::ClearSelectedView(views::View* view) {
- if (view && IsSelectedView(view)) {
- selected_view_->SchedulePaint();
- selected_view_ = NULL;
- }
-}
-
-void AppsGridView::ClearAnySelectedView() {
- if (selected_view_) {
- selected_view_->SchedulePaint();
- selected_view_ = NULL;
- }
-}
-
-bool AppsGridView::IsSelectedView(const views::View* view) const {
- return selected_view_ == view;
-}
-
-void AppsGridView::EnsureViewVisible(const views::View* view) {
- if (pagination_model_->has_transition())
- return;
-
- Index index = GetIndexOfView(view);
- if (IsValidIndex(index))
- pagination_model_->SelectPage(index.page, false);
-}
-
-void AppsGridView::InitiateDrag(AppListItemView* view,
- Pointer pointer,
- const ui::LocatedEvent& event) {
- DCHECK(view);
- if (drag_view_ || pulsing_blocks_model_.view_size())
- return;
-
- drag_view_ = view;
- drag_view_offset_ = event.location();
- drag_start_page_ = pagination_model_->selected_page();
- ExtractDragLocation(event, &drag_start_grid_view_);
- drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y());
-}
-
-void AppsGridView::OnGotShortcutPath(const base::FilePath& path) {
-#if defined(OS_WIN)
- // Drag may have ended before we get the shortcut path.
- if (!synchronous_drag_)
- return;
- // Setting the shortcut path here means the next time we hit UpdateDrag()
- // we'll enter the synchronous drag.
- // NOTE we don't Run() the drag here because that causes animations not to
- // update for some reason.
- synchronous_drag_->set_shortcut_path(path);
- DCHECK(synchronous_drag_->CanRun());
-#endif
-}
-
-void AppsGridView::StartSettingUpSynchronousDrag() {
-#if defined(OS_WIN)
- if (!delegate_)
- return;
-
- // Favor the drag and drop host over native win32 drag. For the Win8/ash
- // launcher we want to have ashes drag and drop over win32's.
- if (drag_and_drop_host_)
- return;
-
- delegate_->GetShortcutPathForApp(
- drag_view_->model()->id(),
- base::Bind(&AppsGridView::OnGotShortcutPath, base::Unretained(this)));
- synchronous_drag_ = new SynchronousDrag(this, drag_view_, drag_view_offset_);
-#endif
-}
-
-bool AppsGridView::RunSynchronousDrag() {
-#if defined(OS_WIN)
- if (synchronous_drag_ && synchronous_drag_->CanRun()) {
- synchronous_drag_->Run();
- synchronous_drag_ = NULL;
- return true;
- }
-#endif
- return false;
-}
-
-void AppsGridView::CleanUpSynchronousDrag() {
-#if defined(OS_WIN)
- synchronous_drag_ = NULL;
-#endif
-}
-
-void AppsGridView::UpdateDragFromItem(Pointer pointer,
- const ui::LocatedEvent& event) {
- DCHECK(drag_view_);
-
- gfx::Point drag_point_in_grid_view;
- ExtractDragLocation(event, &drag_point_in_grid_view);
- UpdateDrag(pointer, drag_point_in_grid_view);
- if (!dragging())
- return;
-
- // If a drag and drop host is provided, see if the drag operation needs to be
- // forwarded.
- gfx::Point location_in_screen = drag_point_in_grid_view;
- views::View::ConvertPointToScreen(this, &location_in_screen);
- DispatchDragEventToDragAndDropHost(location_in_screen);
- if (drag_and_drop_host_)
- drag_and_drop_host_->UpdateDragIconProxy(location_in_screen);
-}
-
-void AppsGridView::UpdateDrag(Pointer pointer, const gfx::Point& point) {
- // EndDrag was called before if |drag_view_| is NULL.
- if (!drag_view_)
- return;
-
- if (RunSynchronousDrag())
- return;
-
- gfx::Vector2d drag_vector(point - drag_start_grid_view_);
- if (!dragging() && ExceededDragThreshold(drag_vector)) {
- drag_pointer_ = pointer;
- // Move the view to the front so that it appears on top of other views.
- ReorderChildView(drag_view_, -1);
- bounds_animator_.StopAnimatingView(drag_view_);
- StartSettingUpSynchronousDrag();
- StartDragAndDropHostDrag(point);
- }
-
- if (drag_pointer_ != pointer)
- return;
-
- last_drag_point_ = point;
- const Index last_drop_target = drop_target_;
- DropAttempt last_drop_attempt = drop_attempt_;
- CalculateDropTarget(last_drag_point_, false);
-
- if (IsPointWithinDragBuffer(last_drag_point_))
- MaybeStartPageFlipTimer(last_drag_point_);
- else
- StopPageFlipTimer();
-
- gfx::Point page_switcher_point(last_drag_point_);
- views::View::ConvertPointToTarget(this, page_switcher_view_,
- &page_switcher_point);
- page_switcher_view_->UpdateUIForDragPoint(page_switcher_point);
-
- if (!EnableFolderDragDropUI()) {
- if (last_drop_target != drop_target_)
- AnimateToIdealBounds();
- drag_view_->SetPosition(drag_view_start_ + drag_vector);
- return;
- }
-
- // Update drag with folder UI enabled.
- if (last_drop_target != drop_target_ ||
- last_drop_attempt != drop_attempt_) {
- if (drop_attempt_ == DROP_FOR_REORDER) {
- folder_dropping_timer_.Stop();
- reorder_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kReorderDelay),
- this, &AppsGridView::OnReorderTimer);
- } else if (drop_attempt_ == DROP_FOR_FOLDER) {
- reorder_timer_.Stop();
- folder_dropping_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kFolderDroppingDelay),
- this, &AppsGridView::OnFolderDroppingTimer);
- }
-
- // Reset the previous drop target.
- SetAsFolderDroppingTarget(last_drop_target, false);
- }
-
- drag_view_->SetPosition(drag_view_start_ + drag_vector);
-}
-
-void AppsGridView::EndDrag(bool cancel) {
- // EndDrag was called before if |drag_view_| is NULL.
- if (!drag_view_)
- return;
- // Coming here a drag and drop was in progress.
- bool landed_in_drag_and_drop_host = forward_events_to_drag_and_drop_host_;
- if (forward_events_to_drag_and_drop_host_) {
- forward_events_to_drag_and_drop_host_ = false;
- drag_and_drop_host_->EndDrag(cancel);
- } else if (!cancel && dragging()) {
- CalculateDropTarget(last_drag_point_, true);
- if (IsValidIndex(drop_target_)) {
- if (!EnableFolderDragDropUI()) {
- MoveItemInModel(drag_view_, drop_target_);
- } else {
- if (drop_attempt_ == DROP_FOR_REORDER)
- MoveItemInModel(drag_view_, drop_target_);
- else if (drop_attempt_ == DROP_FOR_FOLDER)
- MoveItemToFolder(drag_view_, drop_target_);
- }
- }
- }
-
- if (drag_and_drop_host_) {
- // If we had a drag and drop proxy icon, we delete it and make the real
- // item visible again.
- drag_and_drop_host_->DestroyDragIconProxy();
- if (landed_in_drag_and_drop_host) {
- // Move the item directly to the target location, avoiding the "zip back"
- // animation if the user was pinning it to the shelf.
- int i = drop_target_.slot;
- gfx::Rect bounds = view_model_.ideal_bounds(i);
- drag_view_->SetBoundsRect(bounds);
- }
- // Fade in slowly if it landed in the shelf.
- SetViewHidden(drag_view_,
- false /* hide */,
- !landed_in_drag_and_drop_host /* animate */);
- }
-
- // The drag can be ended after the synchronous drag is created but before it
- // is Run().
- CleanUpSynchronousDrag();
-
- SetAsFolderDroppingTarget(drop_target_, false);
- drop_attempt_ = DROP_FOR_NONE;
- drag_pointer_ = NONE;
- drop_target_ = Index();
- drag_view_->OnDragEnded();
- drag_view_ = NULL;
- drag_start_grid_view_ = gfx::Point();
- drag_start_page_ = -1;
- drag_view_offset_ = gfx::Point();
- AnimateToIdealBounds();
-
- StopPageFlipTimer();
-}
-
-void AppsGridView::StopPageFlipTimer() {
- page_flip_timer_.Stop();
- page_flip_target_ = -1;
-}
-
-bool AppsGridView::IsDraggedView(const views::View* view) const {
- return drag_view_ == view;
-}
-
-void AppsGridView::SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host) {
- drag_and_drop_host_ = drag_and_drop_host;
-}
-
-void AppsGridView::Prerender(int page_index) {
- Layout();
- int start = std::max(0, (page_index - kPrerenderPages) * tiles_per_page());
- int end = std::min(view_model_.view_size(),
- (page_index + 1 + kPrerenderPages) * tiles_per_page());
- for (int i = start; i < end; i++) {
- AppListItemView* v = static_cast<AppListItemView*>(view_model_.view_at(i));
- v->Prerender();
- }
-}
-
-gfx::Size AppsGridView::GetPreferredSize() {
- const gfx::Insets insets(GetInsets());
- const gfx::Size tile_size = gfx::Size(kPreferredTileWidth,
- kPreferredTileHeight);
- const int page_switcher_height =
- page_switcher_view_->GetPreferredSize().height();
- return gfx::Size(
- tile_size.width() * cols_ + insets.width(),
- tile_size.height() * rows_per_page_ +
- page_switcher_height + insets.height());
-}
-
-bool AppsGridView::GetDropFormats(
- int* formats,
- std::set<OSExchangeData::CustomFormat>* custom_formats) {
- // TODO(koz): Only accept a specific drag type for app shortcuts.
- *formats = OSExchangeData::FILE_NAME;
- return true;
-}
-
-bool AppsGridView::CanDrop(const OSExchangeData& data) {
- return true;
-}
-
-int AppsGridView::OnDragUpdated(const ui::DropTargetEvent& event) {
- return ui::DragDropTypes::DRAG_MOVE;
-}
-
-void AppsGridView::Layout() {
- if (bounds_animator_.IsAnimating())
- bounds_animator_.Cancel();
-
- CalculateIdealBounds();
- for (int i = 0; i < view_model_.view_size(); ++i) {
- views::View* view = view_model_.view_at(i);
- if (view != drag_view_)
- view->SetBoundsRect(view_model_.ideal_bounds(i));
- }
- views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
-
- const int page_switcher_height =
- page_switcher_view_->GetPreferredSize().height();
- gfx::Rect rect(GetContentsBounds());
- rect.set_y(rect.bottom() - page_switcher_height);
- rect.set_height(page_switcher_height);
- page_switcher_view_->SetBoundsRect(rect);
-
- LayoutStartPage();
-}
-
-bool AppsGridView::OnKeyPressed(const ui::KeyEvent& event) {
- bool handled = false;
- if (selected_view_)
- handled = selected_view_->OnKeyPressed(event);
-
- if (!handled) {
- const int forward_dir = base::i18n::IsRTL() ? -1 : 1;
- switch (event.key_code()) {
- case ui::VKEY_LEFT:
- MoveSelected(0, -forward_dir, 0);
- return true;
- case ui::VKEY_RIGHT:
- MoveSelected(0, forward_dir, 0);
- return true;
- case ui::VKEY_UP:
- MoveSelected(0, 0, -1);
- return true;
- case ui::VKEY_DOWN:
- MoveSelected(0, 0, 1);
- return true;
- case ui::VKEY_PRIOR: {
- MoveSelected(-1, 0, 0);
- return true;
- }
- case ui::VKEY_NEXT: {
- MoveSelected(1, 0, 0);
- return true;
- }
- default:
- break;
- }
- }
-
- return handled;
-}
-
-bool AppsGridView::OnKeyReleased(const ui::KeyEvent& event) {
- bool handled = false;
- if (selected_view_)
- handled = selected_view_->OnKeyReleased(event);
-
- return handled;
-}
-
-void AppsGridView::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (!details.is_add && details.parent == this) {
- if (selected_view_ == details.child)
- selected_view_ = NULL;
-
- if (drag_view_ == details.child)
- EndDrag(true);
-
- bounds_animator_.StopAnimatingView(details.child);
- }
-}
-
-void AppsGridView::Update() {
- DCHECK(!selected_view_ && !drag_view_);
- if (!item_list_)
- return;
-
- view_model_.Clear();
- if (!item_list_->item_count())
- return;
- for (size_t i = 0; i < item_list_->item_count(); ++i) {
- views::View* view = CreateViewForItemAtIndex(i);
- view_model_.Add(view, i);
- AddChildView(view);
- }
- UpdatePaging();
- UpdatePulsingBlockViews();
- Layout();
- SchedulePaint();
-}
-
-void AppsGridView::UpdatePaging() {
- int total_page = start_page_view_ ? 1 : 0;
- if (view_model_.view_size() && tiles_per_page())
- total_page += (view_model_.view_size() - 1) / tiles_per_page() + 1;
-
- pagination_model_->SetTotalPages(total_page);
-}
-
-void AppsGridView::UpdatePulsingBlockViews() {
- const int existing_items = item_list_ ? item_list_->item_count() : 0;
- const int available_slots =
- tiles_per_page() - existing_items % tiles_per_page();
- const int desired = model_->status() == AppListModel::STATUS_SYNCING ?
- available_slots : 0;
-
- if (pulsing_blocks_model_.view_size() == desired)
- return;
-
- while (pulsing_blocks_model_.view_size() > desired) {
- views::View* view = pulsing_blocks_model_.view_at(0);
- pulsing_blocks_model_.Remove(0);
- delete view;
- }
-
- while (pulsing_blocks_model_.view_size() < desired) {
- views::View* view = new PulsingBlockView(
- gfx::Size(kPreferredTileWidth, kPreferredTileHeight), true);
- pulsing_blocks_model_.Add(view, 0);
- AddChildView(view);
- }
-}
-
-views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) {
- // The drag_view_ might be pending for deletion, therefore view_model_
- // may have one more item than item_list_.
- DCHECK_LE(index, item_list_->item_count());
- AppListItemView* view = new AppListItemView(this,
- item_list_->item_at(index));
- view->SetIconSize(icon_size_);
-#if defined(USE_AURA)
- view->SetPaintToLayer(true);
- view->SetFillsBoundsOpaquely(false);
-#endif
- return view;
-}
-
-AppsGridView::Index AppsGridView::GetIndexFromModelIndex(
- int model_index) const {
- int page = model_index / tiles_per_page();
- if (start_page_view_)
- ++page;
-
- return Index(page, model_index % tiles_per_page());
-}
-
-int AppsGridView::GetModelIndexFromIndex(const Index& index) const {
- int model_index = index.page * tiles_per_page() + index.slot;
- if (start_page_view_)
- model_index -= tiles_per_page();
-
- return model_index;
-}
-
-void AppsGridView::SetSelectedItemByIndex(const Index& index) {
- if (GetIndexOfView(selected_view_) == index)
- return;
-
- views::View* new_selection = GetViewAtIndex(index);
- if (!new_selection)
- return; // Keep current selection.
-
- if (selected_view_)
- selected_view_->SchedulePaint();
-
- EnsureViewVisible(new_selection);
- selected_view_ = new_selection;
- selected_view_->SchedulePaint();
- selected_view_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
-}
-
-bool AppsGridView::IsValidIndex(const Index& index) const {
- const int item_page_start = start_page_view_ ? 1 : 0;
- return index.page >= item_page_start &&
- index.page < pagination_model_->total_pages() &&
- index.slot >= 0 &&
- index.slot < tiles_per_page() &&
- GetModelIndexFromIndex(index) < view_model_.view_size();
-}
-
-AppsGridView::Index AppsGridView::GetIndexOfView(
- const views::View* view) const {
- const int model_index = view_model_.GetIndexOfView(view);
- if (model_index == -1)
- return Index();
-
- return GetIndexFromModelIndex(model_index);
-}
-
-views::View* AppsGridView::GetViewAtIndex(const Index& index) const {
- if (!IsValidIndex(index))
- return NULL;
-
- const int model_index = GetModelIndexFromIndex(index);
- return view_model_.view_at(model_index);
-}
-
-void AppsGridView::MoveSelected(int page_delta,
- int slot_x_delta,
- int slot_y_delta) {
- if (!selected_view_)
- return SetSelectedItemByIndex(Index(pagination_model_->selected_page(), 0));
-
- const Index& selected = GetIndexOfView(selected_view_);
- int target_slot = selected.slot + slot_x_delta + slot_y_delta * cols_;
-
- if (selected.slot % cols_ == 0 && slot_x_delta == -1) {
- if (selected.page > 0) {
- page_delta = -1;
- target_slot = selected.slot + cols_ - 1;
- } else {
- target_slot = selected.slot;
- }
- }
-
- if (selected.slot % cols_ == cols_ - 1 && slot_x_delta == 1) {
- if (selected.page < pagination_model_->total_pages() - 1) {
- page_delta = 1;
- target_slot = selected.slot - cols_ + 1;
- } else {
- target_slot = selected.slot;
- }
- }
-
- // Clamp the target slot to the last item if we are moving to the last page
- // but our target slot is past the end of the item list.
- if (page_delta &&
- selected.page + page_delta == pagination_model_->total_pages() - 1) {
- int last_item_slot = (view_model_.view_size() - 1) % tiles_per_page();
- if (last_item_slot < target_slot) {
- target_slot = last_item_slot;
- }
- }
-
- int target_page = std::min(pagination_model_->total_pages() - 1,
- std::max(selected.page + page_delta, 0));
- SetSelectedItemByIndex(Index(target_page, target_slot));
-}
-
-void AppsGridView::CalculateIdealBounds() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Size tile_size(kPreferredTileWidth, kPreferredTileHeight);
-
- gfx::Rect grid_rect(gfx::Size(tile_size.width() * cols_,
- tile_size.height() * rows_per_page_));
- grid_rect.Intersect(rect);
-
- // Page width including padding pixels. A tile.x + page_width means the same
- // tile slot in the next page.
- const int page_width = grid_rect.width() + kPagePadding;
-
- // If there is a transition, calculates offset for current and target page.
- const int current_page = pagination_model_->selected_page();
- const PaginationModel::Transition& transition =
- pagination_model_->transition();
- const bool is_valid =
- pagination_model_->is_valid_page(transition.target_page);
-
- // Transition to right means negative offset.
- const int dir = transition.target_page > current_page ? -1 : 1;
- const int transition_offset = is_valid ?
- transition.progress * page_width * dir : 0;
-
- const int total_views =
- view_model_.view_size() + pulsing_blocks_model_.view_size();
- int slot_index = 0;
- for (int i = 0; i < total_views; ++i) {
- if (i < view_model_.view_size() && view_model_.view_at(i) == drag_view_) {
- if (EnableFolderDragDropUI() && drop_attempt_ == DROP_FOR_FOLDER)
- ++slot_index;
- continue;
- }
-
- Index view_index = GetIndexFromModelIndex(slot_index);
-
- if (drop_target_ == view_index) {
- if (EnableFolderDragDropUI() && drop_attempt_ == DROP_FOR_FOLDER) {
- view_index = GetIndexFromModelIndex(slot_index);
- } else {
- ++slot_index;
- view_index = GetIndexFromModelIndex(slot_index);
- }
- }
-
- // Decides an x_offset for current item.
- int x_offset = 0;
- if (view_index.page < current_page)
- x_offset = -page_width;
- else if (view_index.page > current_page)
- x_offset = page_width;
-
- if (is_valid) {
- if (view_index.page == current_page ||
- view_index.page == transition.target_page) {
- x_offset += transition_offset;
- }
- }
-
- const int row = view_index.slot / cols_;
- const int col = view_index.slot % cols_;
- gfx::Rect tile_slot(
- gfx::Point(grid_rect.x() + col * tile_size.width() + x_offset,
- grid_rect.y() + row * tile_size.height()),
- tile_size);
- if (i < view_model_.view_size()) {
- view_model_.set_ideal_bounds(i, tile_slot);
- } else {
- pulsing_blocks_model_.set_ideal_bounds(i - view_model_.view_size(),
- tile_slot);
- }
-
- ++slot_index;
- }
-}
-
-void AppsGridView::AnimateToIdealBounds() {
- const gfx::Rect visible_bounds(GetVisibleBounds());
-
- CalculateIdealBounds();
- for (int i = 0; i < view_model_.view_size(); ++i) {
- views::View* view = view_model_.view_at(i);
- if (view == drag_view_)
- continue;
-
- const gfx::Rect& target = view_model_.ideal_bounds(i);
- if (bounds_animator_.GetTargetBounds(view) == target)
- continue;
-
- const gfx::Rect& current = view->bounds();
- const bool current_visible = visible_bounds.Intersects(current);
- const bool target_visible = visible_bounds.Intersects(target);
- const bool visible = current_visible || target_visible;
-
- const int y_diff = target.y() - current.y();
- if (visible && y_diff && y_diff % kPreferredTileHeight == 0) {
- AnimationBetweenRows(view,
- current_visible,
- current,
- target_visible,
- target);
- } else {
- bounds_animator_.AnimateViewTo(view, target);
- }
- }
-}
-
-void AppsGridView::AnimationBetweenRows(views::View* view,
- bool animate_current,
- const gfx::Rect& current,
- bool animate_target,
- const gfx::Rect& target) {
- // Determine page of |current| and |target|. -1 means in the left invisible
- // page, 0 is the center visible page and 1 means in the right invisible page.
- const int current_page = current.x() < 0 ? -1 :
- current.x() >= width() ? 1 : 0;
- const int target_page = target.x() < 0 ? -1 :
- target.x() >= width() ? 1 : 0;
-
- const int dir = current_page < target_page ||
- (current_page == target_page && current.y() < target.y()) ? 1 : -1;
-
-#if defined(USE_AURA)
- scoped_ptr<ui::Layer> layer;
- if (animate_current) {
- layer.reset(view->RecreateLayer());
- layer->SuppressPaint();
-
- view->SetFillsBoundsOpaquely(false);
- view->layer()->SetOpacity(0.f);
- }
-
- gfx::Rect current_out(current);
- current_out.Offset(dir * kPreferredTileWidth, 0);
-#endif
-
- gfx::Rect target_in(target);
- if (animate_target)
- target_in.Offset(-dir * kPreferredTileWidth, 0);
- view->SetBoundsRect(target_in);
- bounds_animator_.AnimateViewTo(view, target);
-
-#if defined(USE_AURA)
- bounds_animator_.SetAnimationDelegate(
- view,
- new RowMoveAnimationDelegate(view, layer.release(), current_out),
- true);
-#endif
-}
-
-void AppsGridView::ExtractDragLocation(const ui::LocatedEvent& event,
- gfx::Point* drag_point) {
-#if defined(USE_AURA) && !defined(OS_WIN)
- // Use root location of |event| instead of location in |drag_view_|'s
- // coordinates because |drag_view_| has a scale transform and location
- // could have integer round error and causes jitter.
- *drag_point = event.root_location();
-
- // GetWidget() could be NULL for tests.
- if (GetWidget()) {
- aura::Window::ConvertPointToTarget(
- GetWidget()->GetNativeWindow()->GetRootWindow(),
- GetWidget()->GetNativeWindow(),
- drag_point);
- }
-
- views::View::ConvertPointFromWidget(this, drag_point);
-#else
- // For non-aura, root location is not clearly defined but |drag_view_| does
- // not have the scale transform. So no round error would be introduced and
- // it's okay to use View::ConvertPointToTarget.
- *drag_point = event.location();
- views::View::ConvertPointToTarget(drag_view_, this, drag_point);
-#endif
-}
-
-void AppsGridView::CalculateDropTarget(const gfx::Point& drag_point,
- bool use_page_button_hovering) {
- if (EnableFolderDragDropUI()) {
- CalculateDropTargetWithFolderEnabled(drag_point, use_page_button_hovering);
- return;
- }
-
- int current_page = pagination_model_->selected_page();
- gfx::Point point(drag_point);
- if (!IsPointWithinDragBuffer(drag_point)) {
- point = drag_start_grid_view_;
- current_page = drag_start_page_;
- }
-
- if (use_page_button_hovering &&
- page_switcher_view_->bounds().Contains(point)) {
- gfx::Point page_switcher_point(point);
- views::View::ConvertPointToTarget(this, page_switcher_view_,
- &page_switcher_point);
- int page = page_switcher_view_->GetPageForPoint(page_switcher_point);
- if (pagination_model_->is_valid_page(page)) {
- drop_target_.page = page;
- drop_target_.slot = tiles_per_page() - 1;
- }
- } else {
- gfx::Rect bounds(GetContentsBounds());
- const int drop_row = (point.y() - bounds.y()) / kPreferredTileHeight;
- const int drop_col = std::min(cols_ - 1,
- (point.x() - bounds.x()) / kPreferredTileWidth);
-
- drop_target_.page = current_page;
- drop_target_.slot = std::max(0, std::min(
- tiles_per_page() - 1,
- drop_row * cols_ + drop_col));
- }
-
- // Limits to the last possible slot on last page.
- if (drop_target_.page == pagination_model_->total_pages() - 1) {
- drop_target_.slot = std::min(
- (view_model_.view_size() - 1) % tiles_per_page(),
- drop_target_.slot);
- }
-}
-
-
-void AppsGridView::CalculateDropTargetWithFolderEnabled(
- const gfx::Point& drag_point,
- bool use_page_button_hovering) {
- gfx::Point point(drag_point);
- if (!IsPointWithinDragBuffer(drag_point)) {
- point = drag_start_grid_view_;
- }
-
- if (use_page_button_hovering &&
- page_switcher_view_->bounds().Contains(point)) {
- gfx::Point page_switcher_point(point);
- views::View::ConvertPointToTarget(this, page_switcher_view_,
- &page_switcher_point);
- int page = page_switcher_view_->GetPageForPoint(page_switcher_point);
- if (pagination_model_->is_valid_page(page)) {
- drop_target_.page = page;
- drop_target_.slot = tiles_per_page() - 1;
- }
- if (drop_target_.page == pagination_model_->total_pages() - 1) {
- drop_target_.slot = std::min(
- (view_model_.view_size() - 1) % tiles_per_page(),
- drop_target_.slot);
- }
- drop_attempt_ = DROP_FOR_REORDER;
- } else {
- DCHECK(drag_view_);
- // Try to find the nearest target for folder dropping or re-ordering.
- drop_target_ = GetNearestTileForDragView();
- }
-}
-
-void AppsGridView::OnReorderTimer() {
- if (drop_attempt_ == DROP_FOR_REORDER)
- AnimateToIdealBounds();
-}
-
-void AppsGridView::OnFolderDroppingTimer() {
- if (drop_attempt_ == DROP_FOR_FOLDER)
- SetAsFolderDroppingTarget(drop_target_, true);
-}
-
-void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) {
- // When a drag and drop host is given, the item can be dragged out of the app
- // list window. In that case a proxy widget needs to be used.
- // Note: This code has very likely to be changed for Windows (non metro mode)
- // when a |drag_and_drop_host_| gets implemented.
- if (!drag_view_ || !drag_and_drop_host_)
- return;
-
- gfx::Point screen_location = grid_location;
- views::View::ConvertPointToScreen(this, &screen_location);
-
- // Determine the mouse offset to the center of the icon so that the drag and
- // drop host follows this layer.
- gfx::Vector2d delta = drag_view_offset_ -
- drag_view_->GetLocalBounds().CenterPoint();
- delta.set_y(delta.y() + drag_view_->title()->size().height() / 2);
-
- // We have to hide the original item since the drag and drop host will do
- // the OS dependent code to "lift off the dragged item".
- drag_and_drop_host_->CreateDragIconProxy(screen_location,
- drag_view_->model()->icon(),
- drag_view_,
- delta,
- kDragAndDropProxyScale);
- SetViewHidden(drag_view_,
- true /* hide */,
- true /* no animation */);
-}
-
-void AppsGridView::DispatchDragEventToDragAndDropHost(
- const gfx::Point& location_in_screen_coordinates) {
- if (!drag_view_ || !drag_and_drop_host_)
- return;
- if (bounds().Contains(last_drag_point_)) {
- // The event was issued inside the app menu and we should get all events.
- if (forward_events_to_drag_and_drop_host_) {
- // The DnD host was previously called and needs to be informed that the
- // session returns to the owner.
- forward_events_to_drag_and_drop_host_ = false;
- drag_and_drop_host_->EndDrag(true);
- }
- } else {
- // The event happened outside our app menu and we might need to dispatch.
- if (forward_events_to_drag_and_drop_host_) {
- // Dispatch since we have already started.
- if (!drag_and_drop_host_->Drag(location_in_screen_coordinates)) {
- // The host is not active any longer and we cancel the operation.
- forward_events_to_drag_and_drop_host_ = false;
- drag_and_drop_host_->EndDrag(true);
- }
- } else {
- if (drag_and_drop_host_->StartDrag(drag_view_->model()->id(),
- location_in_screen_coordinates)) {
- // From now on we forward the drag events.
- forward_events_to_drag_and_drop_host_ = true;
- // Any flip operations are stopped.
- StopPageFlipTimer();
- }
- }
- }
-}
-
-void AppsGridView::MaybeStartPageFlipTimer(const gfx::Point& drag_point) {
- if (!IsPointWithinDragBuffer(drag_point))
- StopPageFlipTimer();
- int new_page_flip_target = -1;
-
- if (page_switcher_view_->bounds().Contains(drag_point)) {
- gfx::Point page_switcher_point(drag_point);
- views::View::ConvertPointToTarget(this, page_switcher_view_,
- &page_switcher_point);
- new_page_flip_target =
- page_switcher_view_->GetPageForPoint(page_switcher_point);
- }
-
- // TODO(xiyuan): Fix this for RTL.
- if (new_page_flip_target == -1 && drag_point.x() < kPageFlipZoneSize)
- new_page_flip_target = pagination_model_->selected_page() - 1;
-
- if (new_page_flip_target == -1 &&
- drag_point.x() > width() - kPageFlipZoneSize) {
- new_page_flip_target = pagination_model_->selected_page() + 1;
- }
-
- if (new_page_flip_target == page_flip_target_)
- return;
-
- StopPageFlipTimer();
- if (pagination_model_->is_valid_page(new_page_flip_target)) {
- page_flip_target_ = new_page_flip_target;
-
- if (page_flip_target_ != pagination_model_->selected_page()) {
- page_flip_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(page_flip_delay_in_ms_),
- this, &AppsGridView::OnPageFlipTimer);
- }
- }
-}
-
-void AppsGridView::OnPageFlipTimer() {
- DCHECK(pagination_model_->is_valid_page(page_flip_target_));
- pagination_model_->SelectPage(page_flip_target_, true);
-}
-
-void AppsGridView::MoveItemInModel(views::View* item_view,
- const Index& target) {
- int current_model_index = view_model_.GetIndexOfView(item_view);
- DCHECK_GE(current_model_index, 0);
-
- int target_model_index = GetModelIndexFromIndex(target);
- if (target_model_index == current_model_index)
- return;
-
- item_list_->RemoveObserver(this);
- item_list_->MoveItem(current_model_index, target_model_index);
- view_model_.Move(current_model_index, target_model_index);
- item_list_->AddObserver(this);
-
- if (pagination_model_->selected_page() != target.page)
- pagination_model_->SelectPage(target.page, false);
-}
-
-void AppsGridView::MoveItemToFolder(views::View* item_view,
- const Index& target) {
- AppListItemModel* source_item =
- static_cast<AppListItemView*>(item_view)->model();
- AppListItemView* target_view =
- static_cast<AppListItemView*>(GetViewAtSlotOnCurrentPage(target.slot));
- AppListItemModel* target_item = target_view->model();
- bool target_is_folder = IsFolderItem(target_item);
-
- // Make change to data model.
- item_list_->RemoveObserver(this);
- int folder_index = MergeItems(item_list_, target_item->id(), source_item);
- item_list_->AddObserver(this);
-
- if (!target_is_folder) {
- // Change view_model_ to replace the old target view with new folder
- // item view.
- int target_index = view_model_.GetIndexOfView(target_view);
- view_model_.Remove(target_index);
- delete target_view;
-
- views::View* target_folder_view = CreateViewForItemAtIndex(folder_index);
- view_model_.Add(target_folder_view, target_index);
- AddChildView(target_folder_view);
- }
-
- // Fade out the drag_view_ and delete it when animation ends.
- int drag_view_index = view_model_.GetIndexOfView(drag_view_);
- view_model_.Remove(drag_view_index);
- bounds_animator_.AnimateViewTo(drag_view_, drag_view_->bounds());
- bounds_animator_.SetAnimationDelegate(
- drag_view_, new ItemRemoveAnimationDelegate(drag_view_), true);
-
- UpdatePaging();
-}
-
-void AppsGridView::CancelContextMenusOnCurrentPage() {
- int start = pagination_model_->selected_page() * tiles_per_page();
- int end = std::min(view_model_.view_size(), start + tiles_per_page());
- for (int i = start; i < end; ++i) {
- AppListItemView* view =
- static_cast<AppListItemView*>(view_model_.view_at(i));
- view->CancelContextMenu();
- }
-}
-
-bool AppsGridView::IsPointWithinDragBuffer(const gfx::Point& point) const {
- gfx::Rect rect(GetLocalBounds());
- rect.Inset(-kDragBufferPx, -kDragBufferPx, -kDragBufferPx, -kDragBufferPx);
- return rect.Contains(point);
-}
-
-void AppsGridView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (dragging())
- return;
-
- if (strcmp(sender->GetClassName(), AppListItemView::kViewClassName))
- return;
-
- if (delegate_) {
- delegate_->ActivateApp(static_cast<AppListItemView*>(sender)->model(),
- event.flags());
- }
-}
-
-void AppsGridView::LayoutStartPage() {
- if (!start_page_view_)
- return;
-
- gfx::Rect start_page_bounds(GetLocalBounds());
- start_page_bounds.set_height(start_page_bounds.height() -
- page_switcher_view_->height());
-
- const int page_width = width() + kPagePadding;
- const int current_page = pagination_model_->selected_page();
- if (current_page > 0)
- start_page_bounds.Offset(-page_width, 0);
-
- const PaginationModel::Transition& transition =
- pagination_model_->transition();
- if (current_page == 0 || transition.target_page == 0) {
- const int dir = transition.target_page > current_page ? -1 : 1;
- start_page_bounds.Offset(transition.progress * page_width * dir, 0);
- }
-
- start_page_view_->SetBoundsRect(start_page_bounds);
-}
-
-void AppsGridView::OnListItemAdded(size_t index, AppListItemModel* item) {
- EndDrag(true);
-
- views::View* view = CreateViewForItemAtIndex(index);
- view_model_.Add(view, index);
- AddChildView(view);
-
- UpdatePaging();
- UpdatePulsingBlockViews();
- Layout();
- SchedulePaint();
-}
-
-void AppsGridView::OnListItemRemoved(size_t index, AppListItemModel* item) {
- EndDrag(true);
-
- views::View* view = view_model_.view_at(index);
- view_model_.Remove(index);
- delete view;
-
- UpdatePaging();
- UpdatePulsingBlockViews();
- Layout();
- SchedulePaint();
-}
-
-void AppsGridView::OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) {
- EndDrag(true);
- view_model_.Move(from_index, to_index);
-
- UpdatePaging();
- AnimateToIdealBounds();
-}
-
-void AppsGridView::TotalPagesChanged() {
-}
-
-void AppsGridView::SelectedPageChanged(int old_selected, int new_selected) {
- if (dragging()) {
- CalculateDropTarget(last_drag_point_, true);
- Layout();
- MaybeStartPageFlipTimer(last_drag_point_);
- } else {
- ClearSelectedView(selected_view_);
- Layout();
- }
-}
-
-void AppsGridView::TransitionStarted() {
- CancelContextMenusOnCurrentPage();
-}
-
-void AppsGridView::TransitionChanged() {
- // Update layout for valid page transition only since over-scroll no longer
- // animates app icons.
- const PaginationModel::Transition& transition =
- pagination_model_->transition();
- if (pagination_model_->is_valid_page(transition.target_page))
- Layout();
-}
-
-void AppsGridView::OnAppListModelStatusChanged() {
- UpdatePulsingBlockViews();
- Layout();
- SchedulePaint();
-}
-
-void AppsGridView::SetViewHidden(views::View* view, bool hide, bool immediate) {
-#if defined(USE_AURA)
- ui::ScopedLayerAnimationSettings animator(view->layer()->GetAnimator());
- animator.SetPreemptionStrategy(
- immediate ? ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET :
- ui::LayerAnimator::BLEND_WITH_CURRENT_ANIMATION);
- view->layer()->SetOpacity(hide ? 0 : 1);
-#endif
-}
-
-bool AppsGridView::EnableFolderDragDropUI() {
- // Enable drag and drop folder UI only if it is at the app list root level
- // and the switch is on and the target folder can still accept new items.
- return switches::IsFolderUIEnabled() && is_root_level_ &&
- CanDropIntoTarget(drop_target_);
-}
-
-bool AppsGridView::CanDropIntoTarget(const Index& drop_target) {
- views::View* target_view = GetViewAtSlotOnCurrentPage(drop_target.slot);
- if (!target_view)
- return true;
-
- AppListItemModel* target_item =
- static_cast<AppListItemView*>(target_view)->model();
- if (!IsFolderItem(target_item))
- return true;
-
- return static_cast<AppListFolderItem*>(target_item)->item_list()->
- item_count() < kMaxFolderItems;
-}
-
-// TODO(jennyz): Optimize the calculation for finding nearest tile.
-AppsGridView::Index AppsGridView::GetNearestTileForDragView() {
- Index nearest_tile;
- nearest_tile.page = -1;
- nearest_tile.slot = -1;
- int d_min = -1;
-
- // Calculate the top left tile |drag_view| intersects.
- gfx::Point pt = drag_view_->bounds().origin();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the top right tile |drag_view| intersects.
- pt = drag_view_->bounds().top_right();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the bottom left tile |drag_view| intersects.
- pt = drag_view_->bounds().bottom_left();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the bottom right tile |drag_view| intersects.
- pt = drag_view_->bounds().bottom_right();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- const int d_folder_dropping =
- kFolderDroppingCircleRadius + kPreferredIconDimension / 2;
- const int d_reorder =
- kReorderDroppingCircleRadius + kPreferredIconDimension / 2;
-
- if (IsValidIndex(nearest_tile)) {
- if (d_min < d_folder_dropping) {
- views::View* target_view = GetViewAtSlotOnCurrentPage(nearest_tile.slot);
- if (target_view &&
- !IsFolderItem(static_cast<AppListItemView*>(drag_view_)->model())) {
- // If a non-folder item is dragged to the target slot with an item
- // sitting on it, attempt to drop the dragged item into the folder
- // containing the item on nearest_tile.
- drop_attempt_ = DROP_FOR_FOLDER;
- return nearest_tile;
- } else {
- // If the target slot is blank, or the dragged item is a folder, attempt
- // to re-order.
- drop_attempt_ = DROP_FOR_REORDER;
- return nearest_tile;
- }
- } else if (d_min < d_reorder) {
- // Entering the re-order circle of the slot.
- drop_attempt_ = DROP_FOR_REORDER;
- return nearest_tile;
- }
- }
-
- // If |drag_view| is not entering the re-order or fold dropping region of
- // any items, cancel any previous re-order or folder dropping timer, and
- // return itself.
- drop_attempt_ = DROP_FOR_NONE;
- reorder_timer_.Stop();
- folder_dropping_timer_.Stop();
- return GetIndexOfView(drag_view_);
-}
-
-void AppsGridView::CalculateNearestTileForVertex(const gfx::Point& vertex,
- Index* nearest_tile,
- int* d_min) {
- Index target_index;
- gfx::Rect target_bounds = GetTileBoundsForPoint(vertex, &target_index);
-
- if (target_bounds.IsEmpty() || target_index == *nearest_tile)
- return;
-
- int d_center = GetDistanceBetweenRects(drag_view_->bounds(), target_bounds);
- if (*d_min < 0 || d_center < *d_min) {
- *d_min = d_center;
- *nearest_tile = target_index;
- }
-}
-
-gfx::Rect AppsGridView::GetTileBoundsForPoint(const gfx::Point& point,
- Index *tile_index) {
- // Check if |point| is outside of contents bounds.
- gfx::Rect bounds(GetContentsBounds());
- if (!bounds.Contains(point))
- return gfx::Rect();
-
- // Calculate which tile |point| is enclosed in.
- int x = point.x();
- int y = point.y();
- int col = (x - bounds.x()) / kPreferredTileWidth;
- int row = (y - bounds.y()) / kPreferredTileHeight;
- gfx::Rect tile_rect = GetTileBounds(row, col);
-
- // Check if |point| is outside a valid item's tile.
- Index index(pagination_model_->selected_page(), row * cols_ + col);
- if (!IsValidIndex(index))
- return gfx::Rect();
-
- // |point| is inside of the valid item's tile.
- *tile_index = index;
- return tile_rect;
-}
-
-gfx::Rect AppsGridView::GetTileBounds(int row, int col) const {
- gfx::Rect bounds(GetContentsBounds());
- gfx::Size tile_size(kPreferredTileWidth, kPreferredTileHeight);
- gfx::Rect grid_rect(gfx::Size(tile_size.width() * cols_,
- tile_size.height() * rows_per_page_));
- grid_rect.Intersect(bounds);
- gfx::Rect tile_rect(
- gfx::Point(grid_rect.x() + col * tile_size.width(),
- grid_rect.y() + row * tile_size.height()),
- tile_size);
- return tile_rect;
-}
-
-views::View* AppsGridView::GetViewAtSlotOnCurrentPage(int slot) {
- if (slot < 0)
- return NULL;
-
- // Calculate the original bound of the tile at |index|.
- int row = slot / cols_;
- int col = slot % cols_;
- gfx::Rect tile_rect = GetTileBounds(row, col);
-
- for (int i = 0; i < view_model_.view_size(); ++i) {
- views::View* view = view_model_.view_at(i);
- if (view->bounds() == tile_rect)
- return view;
- }
- return NULL;
-}
-
-void AppsGridView::SetAsFolderDroppingTarget(const Index& target_index,
- bool is_target_folder) {
- AppListItemView* target_view =
- static_cast<AppListItemView*>(
- GetViewAtSlotOnCurrentPage(target_index.slot));
- if (target_view)
- target_view->SetAsAttemptedFolderTarget(is_target_folder);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/apps_grid_view.h b/chromium/ui/app_list/views/apps_grid_view.h
deleted file mode 100644
index 043f6facb38..00000000000
--- a/chromium/ui/app_list/views/apps_grid_view.h
+++ /dev/null
@@ -1,421 +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_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
-#define UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/timer/timer.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/pagination_model_observer.h"
-#include "ui/base/models/list_model_observer.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-#include "ui/views/view_model.h"
-
-#if defined(OS_WIN)
-#include "ui/base/dragdrop/drag_source_win.h"
-#endif
-
-namespace content {
-class WebContents;
-}
-
-namespace views {
-class ButtonListener;
-class DragImageView;
-class WebView;
-}
-
-namespace app_list {
-
-#if defined(OS_WIN)
-class SynchronousDrag;
-#endif
-
-namespace test {
-class AppsGridViewTestApi;
-}
-
-class ApplicationDragAndDropHost;
-class AppListItemView;
-class AppsGridViewDelegate;
-class PageSwitcher;
-class PaginationModel;
-
-// AppsGridView displays a grid for AppListItemList sub model.
-class APP_LIST_EXPORT AppsGridView : public views::View,
- public views::ButtonListener,
- public AppListItemListObserver,
- public PaginationModelObserver,
- public AppListModelObserver {
- public:
- enum Pointer {
- NONE,
- MOUSE,
- TOUCH,
- };
-
- // Constructs the app icon grid view. |delegate| is the delegate of this
- // view, which usually is the hosting AppListView. |pagination_model| is
- // the paging info shared within the launcher UI. |start_page_contents| is
- // the contents for the launcher start page. It could be NULL if the start
- // page is not available.
- AppsGridView(AppsGridViewDelegate* delegate,
- PaginationModel* pagination_model,
- content::WebContents* start_page_contents);
- virtual ~AppsGridView();
-
- // Sets fixed layout parameters. After setting this, CalculateLayout below
- // is no longer called to dynamically choosing those layout params.
- void SetLayout(int icon_size, int cols, int rows_per_page);
-
- // Sets |model| to use. Note this does not take ownership of |model|.
- void SetModel(AppListModel* model);
-
- // Sets the |item_list| to render. Note this does not take ownership of
- // |item_list|.
- void SetItemList(AppListItemList* item_list);
-
- void SetSelectedView(views::View* view);
- void ClearSelectedView(views::View* view);
- void ClearAnySelectedView();
- bool IsSelectedView(const views::View* view) const;
-
- // Ensures the view is visible. Note that if there is a running page
- // transition, this does nothing.
- void EnsureViewVisible(const views::View* view);
-
- void InitiateDrag(AppListItemView* view,
- Pointer pointer,
- const ui::LocatedEvent& event);
-
- // Called from AppListItemView when it receives a drag event.
- void UpdateDragFromItem(Pointer pointer,
- const ui::LocatedEvent& event);
-
- // Called when the user is dragging an app. |point| is in grid view
- // coordinates.
- void UpdateDrag(Pointer pointer, const gfx::Point& point);
- void EndDrag(bool cancel);
- bool IsDraggedView(const views::View* view) const;
-
- void StartSettingUpSynchronousDrag();
- bool RunSynchronousDrag();
- void CleanUpSynchronousDrag();
- void OnGotShortcutPath(const base::FilePath& path);
-
- // Set the drag and drop host for application links.
- void SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host);
-
- // Prerenders the icons on and around |page_index|.
- void Prerender(int page_index);
-
- bool has_dragged_view() const { return drag_view_ != NULL; }
- bool dragging() const { return drag_pointer_ != NONE; }
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual bool GetDropFormats(
- int* formats,
- std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
- virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
-
- // Stops the timer that triggers a page flip during a drag.
- void StopPageFlipTimer();
-
- // Return the view model for test purposes.
- const views::ViewModel* view_model_for_test() const { return &view_model_; }
-
- // For test: Return if the drag and drop handler was set.
- bool has_drag_and_drop_host_for_test() { return NULL != drag_and_drop_host_; }
-
- // For test: Return if the drag and drop operation gets dispatched.
- bool forward_events_to_drag_and_drop_host_for_test() {
- return forward_events_to_drag_and_drop_host_;
- }
-
- void set_is_root_level(bool value) { is_root_level_ = value; }
-
- private:
- friend class test::AppsGridViewTestApi;
-
- enum DropAttempt {
- DROP_FOR_NONE,
- DROP_FOR_REORDER,
- DROP_FOR_FOLDER,
- };
-
- // Represents the index to an item view in the grid.
- struct Index {
- Index() : page(-1), slot(-1) {}
- Index(int page, int slot) : page(page), slot(slot) {}
-
- bool operator==(const Index& other) const {
- return page == other.page && slot == other.slot;
- }
- bool operator!=(const Index& other) const {
- return page != other.page || slot != other.slot;
- }
-
- int page; // Which page an item view is on.
- int slot; // Which slot in the page an item view is in.
- };
-
- int tiles_per_page() const { return cols_ * rows_per_page_; }
-
- // Updates from model.
- void Update();
-
- // Updates page splits for item views.
- void UpdatePaging();
-
- // Updates the number of pulsing block views based on AppListModel status and
- // number of apps.
- void UpdatePulsingBlockViews();
-
- views::View* CreateViewForItemAtIndex(size_t index);
-
- // Convert between the model index and the visual index. The model index
- // is the index of the item in AppListModel. The visual index is the Index
- // struct above with page/slot info of where to display the item.
- Index GetIndexFromModelIndex(int model_index) const;
- int GetModelIndexFromIndex(const Index& index) const;
-
- void SetSelectedItemByIndex(const Index& index);
- bool IsValidIndex(const Index& index) const;
-
- Index GetIndexOfView(const views::View* view) const;
- views::View* GetViewAtIndex(const Index& index) const;
-
- void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta);
-
- void CalculateIdealBounds();
- void AnimateToIdealBounds();
-
- // Invoked when the given |view|'s current bounds and target bounds are on
- // different rows. To avoid moving diagonally, |view| would be put into a
- // slot prior |target| and fade in while moving to |target|. In the meanwhile,
- // a layer copy of |view| would start at |current| and fade out while moving
- // to succeeding slot of |current|. |animate_current| controls whether to run
- // fading out animation from |current|. |animate_target| controls whether to
- // run fading in animation to |target|.
- void AnimationBetweenRows(views::View* view,
- bool animate_current,
- const gfx::Rect& current,
- bool animate_target,
- const gfx::Rect& target);
-
- // Extracts drag location info from |event| into |drag_point|.
- void ExtractDragLocation(const ui::LocatedEvent& event,
- gfx::Point* drag_point);
-
- // Calculates |drop_target_| based on |drag_point|. |drag_point| is in the
- // grid view's coordinates. When |use_page_button_hovering| is true and
- // |drag_point| is hovering on a page button, use the last slot on that page
- // as drop target.
- void CalculateDropTarget(const gfx::Point& drag_point,
- bool use_page_button_hovering);
-
- // Same as CalculateDropTarget, but with folder UI enabled. The |drop_target_|
- // can be either a target for re-ordering, or a target folder to move the
- // dragged item into if |drag_view_| enters its re-ordering or folder
- // dropping circle.
- void CalculateDropTargetWithFolderEnabled(const gfx::Point& drag_point,
- bool use_page_button_hovering);
-
- // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains
- // the drag point in this grid view's coordinates.
- void StartDragAndDropHostDrag(const gfx::Point& grid_location);
-
- // Dispatch the drag and drop update event to the dnd host (if needed).
- void DispatchDragEventToDragAndDropHost(
- const gfx::Point& location_in_screen_coordinates);
-
- // Starts the page flip timer if |drag_point| is in left/right side page flip
- // zone or is over page switcher.
- void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
-
- // Invoked when |page_flip_timer_| fires.
- void OnPageFlipTimer();
-
- // Updates |model_| to move item represented by |item_view| to |target| slot.
- void MoveItemInModel(views::View* item_view, const Index& target);
-
- // Updates |model_| to move item represented by |item_view| into a folder
- // containing item located at |target| slot, also update |view_model_| for
- // the related view changes.
- void MoveItemToFolder(views::View* item_view, const Index& target);
-
- // Cancels any context menus showing for app items on the current page.
- void CancelContextMenusOnCurrentPage();
-
- // Returnes true if |point| lies within the bounds of this grid view plus a
- // buffer area surrounding it.
- bool IsPointWithinDragBuffer(const gfx::Point& point) const;
-
- // Handles start page layout and transition animation.
- void LayoutStartPage();
-
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from AppListItemListObserver:
- virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
- virtual void OnListItemRemoved(size_t index, AppListItemModel* item) OVERRIDE;
- virtual void OnListItemMoved(size_t from_index,
- size_t to_index,
- AppListItemModel* item) OVERRIDE;
-
- // Overridden from PaginationModelObserver:
- virtual void TotalPagesChanged() OVERRIDE;
- virtual void SelectedPageChanged(int old_selected, int new_selected) OVERRIDE;
- virtual void TransitionStarted() OVERRIDE;
- virtual void TransitionChanged() OVERRIDE;
-
- // Overridden from AppListModelObserver:
- virtual void OnAppListModelStatusChanged() OVERRIDE;
-
- // Hide a given view temporarily without losing (mouse) events and / or
- // changing the size of it. If |immediate| is set the change will be
- // immediately applied - otherwise it will change gradually.
- // If |hide| is set the view will get hidden, otherwise it gets shown.
- void SetViewHidden(views::View* view, bool hide, bool immediate);
-
- // Whether the folder drag-and-drop UI should be enabled.
- bool EnableFolderDragDropUI();
-
- // Whether target specified by |drap_target| can accept more items to be
- // dropped into it.
- bool CanDropIntoTarget(const Index& drop_target);
-
- // Returns the visual index of the nearest tile in which |drag_view_| enters
- // either its re-ordering or folder dropping circle.
- Index GetNearestTileForDragView();
-
- // Calculates |nearest_tile| in which |vertex| of the |drag_view| is
- // enclosed.
- // *|nearest_tile| and *|d_min| will be updated based on the calculation.
- // *|d_min| is the distance between |nearest_tile| and |drag_view_|.
- void CalculateNearestTileForVertex(
- const gfx::Point& vertex, Index* nearest_tile, int* d_min);
-
- // Returns the bounds of the tile in which |point| is enclosed if there
- // is a valid item sits on the tile.
- gfx::Rect GetTileBoundsForPoint(const gfx::Point& point, Index* tile_index);
-
- // Gets the bounds of the tile located at |row| and |col| on current page.
- gfx::Rect GetTileBounds(int row, int col) const;
-
- // Gets the item view located at |slot| on the current page. If there is
- // no item located at |slot|, returns NULL.
- views::View* GetViewAtSlotOnCurrentPage(int slot);
-
- // Sets state of the view with |target_index| to |is_target_folder| for
- // dropping |drag_view_|.
- void SetAsFolderDroppingTarget(const Index& target_index,
- bool is_target_folder);
-
- // Invoked when |reorder_timer_| fires to show re-order preview UI.
- void OnReorderTimer();
-
- // Invoked when |folder_dropping_timer_| fires to show folder dropping
- // preview UI.
- void OnFolderDroppingTimer();
-
- AppListModel* model_; // Owned by AppListView.
- AppListItemList* item_list_; // Not owned.
- AppsGridViewDelegate* delegate_;
- PaginationModel* pagination_model_; // Owned by AppListController.
- PageSwitcher* page_switcher_view_; // Owned by views hierarchy.
- views::WebView* start_page_view_; // Owned by views hierarchy.
-
- gfx::Size icon_size_;
- int cols_;
- int rows_per_page_;
-
- // Tracks app item views. There is a view per item in |model_|.
- views::ViewModel view_model_;
-
- // Tracks pulsing block views.
- views::ViewModel pulsing_blocks_model_;
-
- views::View* selected_view_;
-
- AppListItemView* drag_view_;
-
- // The point where the drag started in AppListItemView coordinates.
- gfx::Point drag_view_offset_;
-
- // The point where the drag started in GridView coordinates.
- gfx::Point drag_start_grid_view_;
-
- // The location of |drag_view_| when the drag started.
- gfx::Point drag_view_start_;
-
- // Page the drag started on.
- int drag_start_page_;
-
-#if defined(OS_WIN)
- // Created when a drag is started (ie: drag exceeds the drag threshold), but
- // not Run() until supplied with a shortcut path.
- scoped_refptr<SynchronousDrag> synchronous_drag_;
-#endif
-
- Pointer drag_pointer_;
- Index drop_target_;
- DropAttempt drop_attempt_;
-
- // Timer for re-ordering the |drop_target_| and |drag_view_|.
- base::OneShotTimer<AppsGridView> reorder_timer_;
-
- // Timer for dropping |drag_view_| into the folder containing
- // the |drop_target_|.
- base::OneShotTimer<AppsGridView> folder_dropping_timer_;
-
- // An application target drag and drop host which accepts dnd operations.
- ApplicationDragAndDropHost* drag_and_drop_host_;
-
- // The drag operation is currently inside the dnd host and events get
- // forwarded.
- bool forward_events_to_drag_and_drop_host_;
-
- // Last mouse drag location in this view's coordinates.
- gfx::Point last_drag_point_;
-
- // Timer to auto flip page when dragging an item near the left/right edges.
- base::OneShotTimer<AppsGridView> page_flip_timer_;
-
- // Target page to switch to when |page_flip_timer_| fires.
- int page_flip_target_;
-
- // Delay in milliseconds of when |page_flip_timer_| should fire after user
- // drags an item near the edges.
- int page_flip_delay_in_ms_;
-
- views::BoundsAnimator bounds_animator_;
-
- // If true, AppsGridView is rending items at the root level of the app list.
- bool is_root_level_;
-
- DISALLOW_COPY_AND_ASSIGN(AppsGridView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
diff --git a/chromium/ui/app_list/views/apps_grid_view_delegate.h b/chromium/ui/app_list/views/apps_grid_view_delegate.h
deleted file mode 100644
index 8174222308d..00000000000
--- a/chromium/ui/app_list/views/apps_grid_view_delegate.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace app_list {
-
-class AppListItemModel;
-
-class APP_LIST_EXPORT AppsGridViewDelegate {
- public:
- // Invoked when an item is activated on the grid view. |event_flags| contains
- // the flags of the keyboard/mouse event that triggers the activation request.
- virtual void ActivateApp(AppListItemModel* item, int event_flags) = 0;
-
- // Gets the path to a shortcut for the app represented by |item|. |callback|
- // may be run immediately.
- virtual void GetShortcutPathForApp(
- const std::string& app_id,
- const base::Callback<void(const base::FilePath&)>& callback) = 0;
-
- protected:
- virtual ~AppsGridViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/apps_grid_view_unittest.cc b/chromium/ui/app_list/views/apps_grid_view_unittest.cc
deleted file mode 100644
index 34c0c779657..00000000000
--- a/chromium/ui/app_list/views/apps_grid_view_unittest.cc
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/apps_grid_view.h"
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/timer/timer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/views/app_list_item_view.h"
-#include "ui/app_list/views/test/apps_grid_view_test_api.h"
-#include "ui/views/test/views_test_base.h"
-
-namespace app_list {
-namespace test {
-
-namespace {
-
-const int kIconDimension = 48;
-const int kCols = 2;
-const int kRows = 2;
-const int kTilesPerPage = kCols * kRows;
-
-const int kWidth = 320;
-const int kHeight = 240;
-
-class PageFlipWaiter : public PaginationModelObserver {
- public:
- PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model)
- : ui_loop_(ui_loop), model_(model), wait_(false), page_changed_(false) {
- model_->AddObserver(this);
- }
-
- virtual ~PageFlipWaiter() {
- model_->RemoveObserver(this);
- }
-
- bool Wait(int time_out_ms) {
- DCHECK(!wait_);
- wait_ = true;
- page_changed_ = false;
-
- if (time_out_ms) {
- wait_timer_.Stop();
- wait_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(time_out_ms),
- this, &PageFlipWaiter::OnWaitTimeOut);
- }
-
- ui_loop_->Run();
- wait_ = false;
- return page_changed_;
- }
-
- private:
- void OnWaitTimeOut() {
- ui_loop_->Quit();
- }
-
- // PaginationModelObserver overrides:
- virtual void TotalPagesChanged() OVERRIDE {
- }
- virtual void SelectedPageChanged(int old_selected,
- int new_selected) OVERRIDE {
- page_changed_ = true;
- if (wait_)
- ui_loop_->Quit();
- }
- virtual void TransitionStarted() OVERRIDE {
- }
- virtual void TransitionChanged() OVERRIDE {
- }
-
- base::MessageLoopForUI* ui_loop_;
- PaginationModel* model_;
- bool wait_;
- bool page_changed_;
- base::OneShotTimer<PageFlipWaiter> wait_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
-};
-
-} // namespace
-
-class AppsGridViewTest : public views::ViewsTestBase {
- public:
- AppsGridViewTest() {}
- virtual ~AppsGridViewTest() {}
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- views::ViewsTestBase::SetUp();
- model_.reset(new AppListTestModel);
- pagination_model_.reset(new PaginationModel);
-
- apps_grid_view_.reset(
- new AppsGridView(NULL, pagination_model_.get(), NULL));
- apps_grid_view_->SetLayout(kIconDimension, kCols, kRows);
- apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
- apps_grid_view_->SetModel(model_.get());
- apps_grid_view_->SetItemList(model_->item_list());
-
- test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
- }
- virtual void TearDown() OVERRIDE {
- apps_grid_view_.reset(); // Release apps grid view before models.
- views::ViewsTestBase::TearDown();
- }
-
- protected:
- AppListItemView* GetItemViewAt(int index) {
- return static_cast<AppListItemView*>(
- test_api_->GetViewAtModelIndex(index));
- }
-
- AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
- for (size_t i = 0; i < model_->item_list()->item_count(); ++i) {
- AppListItemView* view = GetItemViewAt(i);
- if (view->bounds().Contains(point))
- return view;
- }
- return NULL;
- }
-
- gfx::Rect GetItemTileRectAt(int row, int col) {
- DCHECK_GT(model_->item_list()->item_count(), 0u);
-
- gfx::Insets insets(apps_grid_view_->GetInsets());
- gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
- GetItemViewAt(0)->bounds().size());
- rect.Offset(col * rect.width(), row * rect.height());
- return rect;
- }
-
- // Points are in |apps_grid_view_|'s coordinates.
- void SimulateDrag(AppsGridView::Pointer pointer,
- const gfx::Point& from,
- const gfx::Point& to) {
- AppListItemView* view = GetItemViewForPoint(from);
- DCHECK(view);
-
- gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
- from - view->bounds().origin());
- gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
- to - view->bounds().origin());
-
- ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED,
- translated_from, from, 0);
- apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
-
- ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
- translated_to, to, 0);
- apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
- }
-
- void SimulateKeyPress(ui::KeyboardCode key_code) {
- ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, 0, false);
- apps_grid_view_->OnKeyPressed(key_event);
- }
-
- scoped_ptr<AppListTestModel> model_;
- scoped_ptr<PaginationModel> pagination_model_;
- scoped_ptr<AppsGridView> apps_grid_view_;
- scoped_ptr<AppsGridViewTestApi> test_api_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
-};
-
-TEST_F(AppsGridViewTest, CreatePage) {
- // Fully populates a page.
- const int kPages = 1;
- model_->PopulateApps(kPages * kTilesPerPage);
- EXPECT_EQ(kPages, pagination_model_->total_pages());
-
- // Adds one more and gets a new page created.
- model_->CreateAndAddItem("Extra");
- EXPECT_EQ(kPages + 1, pagination_model_->total_pages());
-}
-
-TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
- const int kPages = 3;
- model_->PopulateApps(kPages * kTilesPerPage);
- EXPECT_EQ(kPages, pagination_model_->total_pages());
- EXPECT_EQ(0, pagination_model_->selected_page());
-
- // Highlight first one and last one one first page and first page should be
- // selected.
- model_->HighlightItemAt(0);
- EXPECT_EQ(0, pagination_model_->selected_page());
- model_->HighlightItemAt(kTilesPerPage - 1);
- EXPECT_EQ(0, pagination_model_->selected_page());
-
- // Highlight first one on 2nd page and 2nd page should be selected.
- model_->HighlightItemAt(kTilesPerPage + 1);
- EXPECT_EQ(1, pagination_model_->selected_page());
-
- // Highlight last one in the model and last page should be selected.
- model_->HighlightItemAt(model_->item_list()->item_count() - 1);
- EXPECT_EQ(kPages - 1, pagination_model_->selected_page());
-}
-
-TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
- const int kTotalItems = 2;
- const int kLastItemIndex = kTotalItems - 1;
-
- model_->PopulateApps(kTotalItems);
-
- AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
- apps_grid_view_->SetSelectedView(last_view);
- model_->item_list()->DeleteItem(model_->GetItemName(kLastItemIndex));
-
- EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
-
- // No crash happens.
- AppListItemView* view = GetItemViewAt(0);
- apps_grid_view_->SetSelectedView(view);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
-}
-
-TEST_F(AppsGridViewTest, MouseDrag) {
- const int kTotalItems = 4;
- model_->PopulateApps(kTotalItems);
- EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
- model_->GetModelContent());
-
- gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
- gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
-
- // Dragging changes model order.
- SimulateDrag(AppsGridView::MOUSE, from, to);
- apps_grid_view_->EndDrag(false);
- EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-
- // Canceling drag should keep existing order.
- SimulateDrag(AppsGridView::MOUSE, from, to);
- apps_grid_view_->EndDrag(true);
- EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-
- // Deleting an item keeps remaining intact.
- SimulateDrag(AppsGridView::MOUSE, from, to);
- model_->item_list()->DeleteItem(model_->GetItemName(0));
- apps_grid_view_->EndDrag(false);
- EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-
- // Adding a launcher item cancels the drag and respects the order.
- SimulateDrag(AppsGridView::MOUSE, from, to);
- model_->CreateAndAddItem("Extra");
- apps_grid_view_->EndDrag(false);
- EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-}
-
-TEST_F(AppsGridViewTest, MouseDragFlipPage) {
- test_api_->SetPageFlipDelay(10);
- pagination_model_->SetTransitionDurations(10, 10);
-
- PageFlipWaiter page_flip_waiter(message_loop(),
- pagination_model_.get());
-
- const int kPages = 3;
- model_->PopulateApps(kPages * kTilesPerPage);
- EXPECT_EQ(kPages, pagination_model_->total_pages());
- EXPECT_EQ(0, pagination_model_->selected_page());
-
- gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
- gfx::Point to = gfx::Point(apps_grid_view_->width(),
- apps_grid_view_->height() / 2);
-
- // Drag to right edge.
- SimulateDrag(AppsGridView::MOUSE, from, to);
-
- // Page should be flipped after sometime.
- EXPECT_TRUE(page_flip_waiter.Wait(0));
- EXPECT_EQ(1, pagination_model_->selected_page());
-
- // Stay there and page should be flipped again.
- EXPECT_TRUE(page_flip_waiter.Wait(0));
- EXPECT_EQ(2, pagination_model_->selected_page());
-
- // Stay there longer and no page flip happen since we are at the last page.
- EXPECT_FALSE(page_flip_waiter.Wait(100));
- EXPECT_EQ(2, pagination_model_->selected_page());
-
- apps_grid_view_->EndDrag(true);
-
- // Now drag to the left edge and test the other direction.
- to.set_x(0);
-
- SimulateDrag(AppsGridView::MOUSE, from, to);
-
- EXPECT_TRUE(page_flip_waiter.Wait(0));
- EXPECT_EQ(1, pagination_model_->selected_page());
-
- EXPECT_TRUE(page_flip_waiter.Wait(0));
- EXPECT_EQ(0, pagination_model_->selected_page());
-
- EXPECT_FALSE(page_flip_waiter.Wait(100));
- EXPECT_EQ(0, pagination_model_->selected_page());
- apps_grid_view_->EndDrag(true);
-}
-
-TEST_F(AppsGridViewTest, SimultaneousDrag) {
- const int kTotalItems = 4;
- model_->PopulateApps(kTotalItems);
- EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
- model_->GetModelContent());
-
- gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
- gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
-
- gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
- gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
-
- // Starts a mouse drag first then a touch drag.
- SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
- SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
- // Finishes the drag and mouse drag wins.
- apps_grid_view_->EndDrag(false);
- EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-
- // Starts a touch drag first then a mouse drag.
- SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
- SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
- // Finishes the drag and touch drag wins.
- apps_grid_view_->EndDrag(false);
- EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
- model_->GetModelContent());
- test_api_->LayoutToIdealBounds();
-}
-
-TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
- const int kPages = 3;
- const int kItems = (kPages - 1) * kTilesPerPage + 1;
- model_->PopulateApps(kItems);
-
- const int first_index = 0;
- const int last_index = kItems - 1;
- const int last_index_on_page1_first_row = kRows - 1;
- const int last_index_on_page1 = kTilesPerPage - 1;
- const int first_index_on_page2 = kTilesPerPage;
- const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
- const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
-
- // Try moving off the item beyond the first one.
- apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
- SimulateKeyPress(ui::VKEY_UP);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
- SimulateKeyPress(ui::VKEY_LEFT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
-
- // Move to the last item and try to go past it.
- apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
- SimulateKeyPress(ui::VKEY_DOWN);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
- SimulateKeyPress(ui::VKEY_RIGHT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
-
- // Move right on last item on page 1 should get to first item on page 2's last
- // row and vice versa.
- apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
- SimulateKeyPress(ui::VKEY_RIGHT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- first_index_on_page2_last_row)));
- SimulateKeyPress(ui::VKEY_LEFT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- last_index_on_page1)));
-
- // Up/down on page boundary does nothing.
- apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
- SimulateKeyPress(ui::VKEY_DOWN);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- last_index_on_page1)));
- apps_grid_view_->SetSelectedView(
- GetItemViewAt(first_index_on_page2_last_row));
- apps_grid_view_->
- SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
- SimulateKeyPress(ui::VKEY_UP);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- last_index_on_page1_first_row)));
-
- // Page up and down should go to the same item on the next and last page.
- apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
- SimulateKeyPress(ui::VKEY_PRIOR);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- first_index)));
- SimulateKeyPress(ui::VKEY_NEXT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- first_index_on_page2)));
-
- // Moving onto a a page with too few apps to support the expected index snaps
- // to the last available index.
- apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
- SimulateKeyPress(ui::VKEY_RIGHT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- last_index)));
- apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
- SimulateKeyPress(ui::VKEY_NEXT);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- last_index)));
-
-
-
- // After page switch, arrow keys select first item on current page.
- apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
- pagination_model_->SelectPage(1, false);
- SimulateKeyPress(ui::VKEY_UP);
- EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
- first_index_on_page2)));
-}
-
-TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
- // If the app's full name and short name differ, the title label's tooltip
- // should always be the full name of the app.
- std::string expected_text("xyz");
- std::string expected_tooltip("tooltip");
- model_->CreateAndAddItem(expected_text, expected_tooltip);
-
- string16 actual_tooltip;
- AppListItemView* item_view = GetItemViewAt(0);
- ASSERT_TRUE(item_view);
- const views::Label* title_label = item_view->title();
- EXPECT_TRUE(title_label->GetTooltipText(
- title_label->bounds().CenterPoint(), &actual_tooltip));
- EXPECT_EQ(expected_tooltip, UTF16ToUTF8(actual_tooltip));
- EXPECT_EQ(expected_text, UTF16ToUTF8(title_label->text()));
-}
-
-TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
- // If the app's full name and short name are the same, use the default tooltip
- // behavior of the label (only show a tooltip if the title is truncated).
- std::string title("a");
- model_->CreateAndAddItem(title, title);
-
- string16 actual_tooltip;
- AppListItemView* item_view = GetItemViewAt(0);
- ASSERT_TRUE(item_view);
- const views::Label* title_label = item_view->title();
- EXPECT_FALSE(title_label->GetTooltipText(
- title_label->bounds().CenterPoint(), &actual_tooltip));
- EXPECT_EQ(title, UTF16ToUTF8(title_label->text()));
-}
-
-} // namespace test
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/cached_label.cc b/chromium/ui/app_list/views/cached_label.cc
deleted file mode 100644
index a7d9e27e9e3..00000000000
--- a/chromium/ui/app_list/views/cached_label.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/cached_label.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-
-namespace app_list {
-
-CachedLabel::CachedLabel()
- : needs_repaint_(true) {
-}
-
-void CachedLabel::PaintToBackingImage() {
- if (image_.size() == size() && !needs_repaint_)
- return;
- gfx::Canvas canvas(size(), 1.0f, false /* is_opaque */);
- canvas.FillRect(GetLocalBounds(), SkColorSetARGB(0, 0, 0, 0),
- SkXfermode::kSrc_Mode);
- Label::OnPaint(&canvas);
- image_ = gfx::ImageSkia(canvas.ExtractImageRep());
- needs_repaint_ = false;
-}
-
-#if defined(OS_WIN)
-void CachedLabel::OnPaint(gfx::Canvas* canvas) {
- PaintToBackingImage();
- canvas->DrawImageInt(image_, 0, 0);
-}
-#endif
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/cached_label.h b/chromium/ui/app_list/views/cached_label.h
deleted file mode 100644
index bdf269795a1..00000000000
--- a/chromium/ui/app_list/views/cached_label.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_CACHED_LABEL_H_
-#define UI_APP_LIST_VIEWS_CACHED_LABEL_H_
-
-#include "ui/gfx/image/image_skia.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/view.h"
-
-namespace gfx {
-class Canvas;
-}
-
-namespace app_list {
-
-// Subclass of views::Label that caches the rendered text in an ImageSkia.
-class CachedLabel : public views::Label {
- public:
- CachedLabel();
-
- // Have the next call to OnPaint() update the backing image.
- void Invalidate() { needs_repaint_ = true; }
-
- // Calls the base label's OnPaint() to paint into a backing image.
- void PaintToBackingImage();
-
-#if defined(OS_WIN)
- // views::View overrides.
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-#endif
-
- private:
- bool needs_repaint_;
- gfx::ImageSkia image_;
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_CACHED_LABEL_H_
diff --git a/chromium/ui/app_list/views/contents_view.cc b/chromium/ui/app_list/views/contents_view.cc
deleted file mode 100644
index 225c119729c..00000000000
--- a/chromium/ui/app_list/views/contents_view.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/contents_view.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/apps_container_view.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/app_list/views/search_result_list_view.h"
-#include "ui/events/event.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/view_model.h"
-#include "ui/views/view_model_utils.h"
-
-namespace app_list {
-
-namespace {
-
-// Indexes of interesting views in ViewModel of ContentsView.
-const int kIndexAppsContainer = 0;
-const int kIndexSearchResults = 1;
-
-const int kMinMouseWheelToSwitchPage = 20;
-const int kMinScrollToSwitchPage = 20;
-const int kMinHorizVelocityToSwitchPage = 800;
-
-const double kFinishTransitionThreshold = 0.33;
-
-AppsContainerView* GetAppsContainerView(views::ViewModel* model) {
- return static_cast<AppsContainerView*>(model->view_at(kIndexAppsContainer));
-}
-
-SearchResultListView* GetSearchResultListView(views::ViewModel* model) {
- return static_cast<SearchResultListView*>(
- model->view_at(kIndexSearchResults));
-}
-
-} // namespace
-
-ContentsView::ContentsView(AppListMainView* app_list_main_view,
- PaginationModel* pagination_model,
- AppListModel* model,
- content::WebContents* start_page_contents)
- : show_state_(SHOW_APPS),
- pagination_model_(pagination_model),
- view_model_(new views::ViewModel),
- bounds_animator_(new views::BoundsAnimator(this)) {
- DCHECK(model);
- pagination_model_->SetTransitionDurations(
- kPageTransitionDurationInMs,
- kOverscrollPageTransitionDurationMs);
-
- apps_container_view_ = new AppsContainerView(
- app_list_main_view, pagination_model, model, start_page_contents);
- AddChildView(apps_container_view_);
- view_model_->Add(apps_container_view_, kIndexAppsContainer);
-
- SearchResultListView* search_results_view = new SearchResultListView(
- app_list_main_view);
- AddChildView(search_results_view);
- view_model_->Add(search_results_view, kIndexSearchResults);
-
- GetSearchResultListView(view_model_.get())->SetResults(model->results());
-}
-
-ContentsView::~ContentsView() {
-}
-
-void ContentsView::CancelDrag() {
- if (apps_container_view_->apps_grid_view()->has_dragged_view())
- apps_container_view_->apps_grid_view()->EndDrag(true);
-}
-
-void ContentsView::SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host) {
- apps_container_view_->apps_grid_view()->
- SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
-}
-
-void ContentsView::SetShowState(ShowState show_state) {
- if (show_state_ == show_state)
- return;
-
- show_state_ = show_state;
- ShowStateChanged();
-}
-
-void ContentsView::ShowStateChanged() {
- if (show_state_ == SHOW_SEARCH_RESULTS) {
- // TODO(xiyuan): Highlight default match instead of the first.
- SearchResultListView* results_view =
- GetSearchResultListView(view_model_.get());
- if (results_view->visible())
- results_view->SetSelectedIndex(0);
- }
-
- AnimateToIdealBounds();
-}
-
-void ContentsView::CalculateIdealBounds() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect container_frame(rect);
- gfx::Rect results_frame(rect);
-
- // Offsets apps grid and result list based on |show_state_|.
- // SearchResultListView is on top of apps grid. Visible view is left in
- // visible area and invisible ones is put out of the visible area.
- int contents_area_height = rect.height();
- switch (show_state_) {
- case SHOW_APPS:
- results_frame.Offset(0, -contents_area_height);
- break;
- case SHOW_SEARCH_RESULTS:
- container_frame.Offset(0, contents_area_height);
- break;
- default:
- NOTREACHED() << "Unknown show_state_ " << show_state_;
- break;
- }
-
- view_model_->set_ideal_bounds(kIndexAppsContainer, container_frame);
- view_model_->set_ideal_bounds(kIndexSearchResults, results_frame);
-}
-
-void ContentsView::AnimateToIdealBounds() {
- CalculateIdealBounds();
- for (int i = 0; i < view_model_->view_size(); ++i) {
- bounds_animator_->AnimateViewTo(view_model_->view_at(i),
- view_model_->ideal_bounds(i));
- }
-}
-
-void ContentsView::ShowSearchResults(bool show) {
- SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS);
-}
-
-void ContentsView::ShowFolderContent(AppListFolderItem* item) {
- apps_container_view_->ShowActiveFolder(item);
-}
-
-void ContentsView::Prerender() {
- const int selected_page = std::max(0, pagination_model_->selected_page());
- apps_container_view_->apps_grid_view()->Prerender(selected_page);
-}
-
-gfx::Size ContentsView::GetPreferredSize() {
- const gfx::Size container_size = GetAppsContainerView(view_model_.get())->
- apps_grid_view()->GetPreferredSize();
- const gfx::Size results_size =
- GetSearchResultListView(view_model_.get())->GetPreferredSize();
-
- int width = std::max(container_size.width(), results_size.width());
- int height = std::max(container_size.height(), results_size.height());
- return gfx::Size(width, height);
-}
-
-void ContentsView::Layout() {
- CalculateIdealBounds();
- views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
-}
-
-bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
- switch (show_state_) {
- case SHOW_APPS:
- return GetAppsContainerView(view_model_.get())->OnKeyPressed(event);
- case SHOW_SEARCH_RESULTS:
- return GetSearchResultListView(view_model_.get())->OnKeyPressed(event);
- default:
- NOTREACHED() << "Unknown show state " << show_state_;
- }
- return false;
-}
-
-bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
- if (show_state_ != SHOW_APPS)
- return false;
-
- int offset;
- if (abs(event.x_offset()) > abs(event.y_offset()))
- offset = event.x_offset();
- else
- offset = event.y_offset();
-
- if (abs(offset) > kMinMouseWheelToSwitchPage) {
- if (!pagination_model_->has_transition()) {
- pagination_model_->SelectPageRelative(
- offset > 0 ? -1 : 1, true);
- }
- return true;
- }
-
- return false;
-}
-
-void ContentsView::OnGestureEvent(ui::GestureEvent* event) {
- if (show_state_ != SHOW_APPS)
- return;
-
- switch (event->type()) {
- case ui::ET_GESTURE_SCROLL_BEGIN:
- pagination_model_->StartScroll();
- event->SetHandled();
- return;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- // event->details.scroll_x() > 0 means moving contents to right. That is,
- // transitioning to previous page.
- pagination_model_->UpdateScroll(
- event->details().scroll_x() / GetContentsBounds().width());
- event->SetHandled();
- return;
- case ui::ET_GESTURE_SCROLL_END:
- pagination_model_->EndScroll(pagination_model_->
- transition().progress < kFinishTransitionThreshold);
- event->SetHandled();
- return;
- case ui::ET_SCROLL_FLING_START: {
- pagination_model_->EndScroll(true);
- if (fabs(event->details().velocity_x()) > kMinHorizVelocityToSwitchPage) {
- pagination_model_->SelectPageRelative(
- event->details().velocity_x() < 0 ? 1 : -1,
- true);
- }
- event->SetHandled();
- return;
- }
- default:
- break;
- }
-}
-
-void ContentsView::OnScrollEvent(ui::ScrollEvent* event) {
- if (show_state_ != SHOW_APPS ||
- event->type() == ui::ET_SCROLL_FLING_CANCEL) {
- return;
- }
-
- float offset;
- if (abs(event->x_offset()) > abs(event->y_offset()))
- offset = event->x_offset();
- else
- offset = event->y_offset();
-
- if (abs(offset) > kMinScrollToSwitchPage) {
- if (!pagination_model_->has_transition()) {
- pagination_model_->SelectPageRelative(offset > 0 ? -1 : 1,
- true);
- }
- event->SetHandled();
- event->StopPropagation();
- }
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/contents_view.h b/chromium/ui/app_list/views/contents_view.h
deleted file mode 100644
index beb0a91afc6..00000000000
--- a/chromium/ui/app_list/views/contents_view.h
+++ /dev/null
@@ -1,98 +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_APP_LIST_VIEWS_CONTENTS_VIEW_H_
-#define UI_APP_LIST_VIEWS_CONTENTS_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/views/view.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace views {
-class BoundsAnimator;
-class ViewModel;
-}
-
-namespace app_list {
-
-class AppsGridView;
-class ApplicationDragAndDropHost;
-class AppListFolderItem;
-class AppListMainView;
-class AppListModel;
-class AppListViewDelegate;
-class AppsContainerView;
-class PaginationModel;
-
-// A view to manage sub views under the search box (apps grid view + page
-// switcher and search results). The two sets of sub views are mutually
-// exclusive. ContentsView manages a show state to choose one set to show
-// and animates the transition between show states.
-class ContentsView : public views::View {
- public:
- ContentsView(AppListMainView* app_list_main_view,
- PaginationModel* pagination_model,
- AppListModel* model,
- content::WebContents* start_page_contents);
- virtual ~ContentsView();
-
- // The app list gets closed and drag and drop operations need to be cancelled.
- void CancelDrag();
-
- // If |drag_and_drop| is not NULL it will be called upon drag and drop
- // operations outside the application list.
- void SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host);
-
- void ShowSearchResults(bool show);
- void ShowFolderContent(AppListFolderItem* folder);
-
- void Prerender();
-
- AppsContainerView* apps_container_view() { return apps_container_view_; }
-
- private:
- enum ShowState {
- SHOW_APPS,
- SHOW_SEARCH_RESULTS,
- };
-
- // Sets show state.
- void SetShowState(ShowState show_state);
-
- // Invoked when show state is changed.
- void ShowStateChanged();
-
- void CalculateIdealBounds();
- void AnimateToIdealBounds();
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
-
- // Overridden from ui::EventHandler:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
-
- ShowState show_state_;
- PaginationModel* pagination_model_; // Owned by AppListController.
-
- AppsContainerView* apps_container_view_; // Owned by the views hierarchy.
-
- scoped_ptr<views::ViewModel> view_model_;
- scoped_ptr<views::BoundsAnimator> bounds_animator_;
-
- DISALLOW_COPY_AND_ASSIGN(ContentsView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_CONTENTS_VIEW_H_
diff --git a/chromium/ui/app_list/views/folder_header_view.cc b/chromium/ui/app_list/views/folder_header_view.cc
deleted file mode 100644
index 9699e8febf0..00000000000
--- a/chromium/ui/app_list/views/folder_header_view.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/folder_header_view.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_resources.h"
-#include "grit/ui_strings.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_folder_item.h"
-#include "ui/app_list/views/app_list_folder_view.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/painter.h"
-
-namespace app_list {
-
-namespace {
-
-const int kPreferredWidth = 360;
-const int kPreferredHeight = 48;
-const int kIconDimension = 24;
-const int kPadding = 14;
-const int kFolderNameWidth = 150;
-const int kFolderNameHeight = 30;
-const int kBottomSeparatorWidth = 380;
-const int kBottomSeparatorHeight = 1;
-
-const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
-
-} // namespace
-
-class FolderHeaderView::FolderNameView : public views::Textfield {
- public:
- FolderNameView() {
- set_border(views::Border::CreateEmptyBorder(1, 1, 1, 1));
- const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250);
- SetFocusPainter(views::Painter::CreateSolidFocusPainter(
- kFocusBorderColor,
- gfx::Insets(0, 0, 1, 1)));
- }
-
- virtual ~FolderNameView() {
- }
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
- return gfx::Size(kFolderNameWidth, kFolderNameHeight);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FolderNameView);
-};
-
-FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate)
- : folder_item_(NULL),
- back_button_(new views::ImageButton(this)),
- folder_name_view_(new FolderNameView),
- delegate_(delegate) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- back_button_->SetImage(views::ImageButton::STATE_NORMAL,
- rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
- back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
- views::ImageButton::ALIGN_MIDDLE);
- AddChildView(back_button_);
-
- folder_name_view_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
- folder_name_view_->set_placeholder_text_color(kHintTextColor);
- folder_name_view_->set_placeholder_text(
- rb.GetLocalizedString(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER));
- folder_name_view_->RemoveBorder();
- folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
- folder_name_view_->SetController(this);
- AddChildView(folder_name_view_);
-}
-
-FolderHeaderView::~FolderHeaderView() {
- if (folder_item_)
- folder_item_->RemoveObserver(this);
-}
-
-void FolderHeaderView::SetFolderItem(AppListFolderItem* folder_item) {
- if (folder_item_)
- folder_item_->RemoveObserver(this);
-
- folder_item_ = folder_item;
- if (!folder_item_)
- return;
- folder_item_->AddObserver(this);
-
- Update();
-}
-
-void FolderHeaderView::Update() {
- if (!folder_item_)
- return;
-
- folder_name_view_->SetText(UTF8ToUTF16(folder_item_->title()));
-}
-
-gfx::Size FolderHeaderView::GetPreferredSize() {
- return gfx::Size(kPreferredWidth, kPreferredHeight);
-}
-
-void FolderHeaderView::Layout() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect back_bounds(rect);
- back_bounds.set_width(kIconDimension + 2 * kPadding);
- back_button_->SetBoundsRect(back_bounds);
-
- gfx::Rect text_bounds(rect);
- int text_width = folder_name_view_->GetPreferredSize().width();
- text_bounds.set_x(back_bounds.x() + (rect.width() - text_width) / 2);
- text_bounds.set_width(text_width);
- text_bounds.ClampToCenteredSize(gfx::Size(text_bounds.width(),
- folder_name_view_->GetPreferredSize().height()));
- folder_name_view_->SetBoundsRect(text_bounds);
-}
-
-void FolderHeaderView::OnPaint(gfx::Canvas* canvas) {
- views::View::OnPaint(canvas);
-
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- // Draw bottom separator line.
- rect.set_x((rect.width() - kBottomSeparatorWidth) / 2 + rect.x());
- rect.set_y(rect.y() + rect.height() - kBottomSeparatorHeight);
- rect.set_width(kBottomSeparatorWidth);
- rect.set_height(kBottomSeparatorHeight);
- canvas->FillRect(rect, kTopSeparatorColor);
-}
-
-void FolderHeaderView::ContentsChanged(views::Textfield* sender,
- const base::string16& new_contents) {
- // Temporarily remove from observer to ignore data change caused by us.
- if (!folder_item_)
- return;
-
- folder_item_->RemoveObserver(this);
- std::string name = UTF16ToUTF8(folder_name_view_->text());
- folder_item_->SetTitleAndFullName(name, name);
- folder_item_->AddObserver(this);
-}
-
-void FolderHeaderView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- delegate_->NavigateBack(folder_item_, event);
-}
-
-void FolderHeaderView::ItemIconChanged() {
-}
-
-void FolderHeaderView::ItemTitleChanged() {
- Update();
-}
-
-void FolderHeaderView::ItemHighlightedChanged() {
-}
-
-void FolderHeaderView::ItemIsInstallingChanged() {
-}
-
-void FolderHeaderView::ItemPercentDownloadedChanged() {
-}
-
-} // namespace app_list
-
diff --git a/chromium/ui/app_list/views/folder_header_view.h b/chromium/ui/app_list/views/folder_header_view.h
deleted file mode 100644
index f8d471ba09b..00000000000
--- a/chromium/ui/app_list/views/folder_header_view.h
+++ /dev/null
@@ -1,76 +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_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
-#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
-
-#include <string>
-
-#include "ui/app_list/app_list_item_model_observer.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/view.h"
-
-namespace views {
-class ImageButton;
-} // namespace views
-
-namespace app_list {
-
-class AppListFolderItem;
-class AppListFolderView;
-class FolderHeaderViewDelegate;
-
-// FolderHeaderView contains a back button and an editable folder name field.
-class FolderHeaderView : public views::View,
- public views::TextfieldController,
- public views::ButtonListener,
- public AppListItemModelObserver {
- public:
- explicit FolderHeaderView(FolderHeaderViewDelegate* delegate);
- virtual ~FolderHeaderView();
-
- void SetFolderItem(AppListFolderItem* folder_item);
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
-
- private:
- class FolderNameView;
-
- // Updates UI.
- void Update();
-
- // Overriden from views::View:
- virtual void Layout() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- // Overridden from views::TextfieldController:
- virtual void ContentsChanged(views::Textfield* sender,
- const base::string16& new_contents) OVERRIDE;
-
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from AppListItemModelObserver:
- virtual void ItemIconChanged() OVERRIDE;
- virtual void ItemTitleChanged() OVERRIDE;
- virtual void ItemHighlightedChanged() OVERRIDE;
- virtual void ItemIsInstallingChanged() OVERRIDE;
- virtual void ItemPercentDownloadedChanged() OVERRIDE;
-
- AppListFolderItem* folder_item_; // Not owned.
-
- views::ImageButton* back_button_; // Owned by views hierarchy.
- FolderNameView* folder_name_view_; // Owned by views hierarchy.
-
- FolderHeaderViewDelegate* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(FolderHeaderView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_
diff --git a/chromium/ui/app_list/views/folder_header_view_delegate.h b/chromium/ui/app_list/views/folder_header_view_delegate.h
deleted file mode 100644
index e8591b611ed..00000000000
--- a/chromium/ui/app_list/views/folder_header_view_delegate.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
-
-namespace app_list {
-
-class AppListFolderItem;
-
-class FolderHeaderViewDelegate {
- public:
- // Invoked when the back button on the folder header view is clicked.
- // |item| is the folder item which FolderHeaderview represents.
- // |event_flags| contains the flags of the keyboard/mouse event that triggers
- // the request.
- virtual void NavigateBack(AppListFolderItem* item,
- const ui::Event& event_flags) = 0;
-
- protected:
- virtual ~FolderHeaderViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/page_switcher.cc b/chromium/ui/app_list/views/page_switcher.cc
deleted file mode 100644
index 99e9749d154..00000000000
--- a/chromium/ui/app_list/views/page_switcher.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/page_switcher.h"
-
-#include <algorithm>
-
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/pagination_model.h"
-#include "ui/gfx/animation/throb_animation.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/controls/button/custom_button.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace app_list {
-
-namespace {
-
-const int kPreferredHeight = 57;
-
-const int kMaxButtonSpacing = 18;
-const int kMinButtonSpacing = 4;
-const int kMaxButtonWidth = 68;
-const int kMinButtonWidth = 28;
-const int kButtonHeight = 6;
-const int kButtonCornerRadius = 2;
-const int kButtonStripPadding = 20;
-
-class PageSwitcherButton : public views::CustomButton {
- public:
- explicit PageSwitcherButton(views::ButtonListener* listener)
- : views::CustomButton(listener),
- button_width_(kMaxButtonWidth),
- selected_range_(0) {
- }
- virtual ~PageSwitcherButton() {}
-
- void SetSelectedRange(double selected_range) {
- if (selected_range_ == selected_range)
- return;
-
- selected_range_ = selected_range;
- SchedulePaint();
- }
-
- void set_button_width(int button_width) { button_width_ = button_width; }
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
- return gfx::Size(button_width_, kButtonHeight);
- }
-
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- if (state() == STATE_HOVERED)
- PaintButton(canvas, kPagerHoverColor);
- else
- PaintButton(canvas, kPagerNormalColor);
- }
-
- private:
- // Paints a button that has two rounded corner at bottom.
- void PaintButton(gfx::Canvas* canvas, SkColor base_color) {
- gfx::Rect rect(GetContentsBounds());
- rect.ClampToCenteredSize(gfx::Size(button_width_, kButtonHeight));
-
- SkPath path;
- path.addRoundRect(gfx::RectToSkRect(rect),
- SkIntToScalar(kButtonCornerRadius),
- SkIntToScalar(kButtonCornerRadius));
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(base_color);
- canvas->DrawPath(path, paint);
-
- int selected_start_x = 0;
- int selected_width = 0;
- if (selected_range_ > 0) {
- selected_width = selected_range_ * rect.width();
- } else if (selected_range_ < 0) {
- selected_width = -selected_range_ * rect.width();
- selected_start_x = rect.right() - selected_width;
- }
-
- if (selected_width) {
- gfx::Rect selected_rect(rect);
- selected_rect.set_x(selected_start_x);
- selected_rect.set_width(selected_width);
-
- SkPath selected_path;
- selected_path.addRoundRect(gfx::RectToSkRect(selected_rect),
- SkIntToScalar(kButtonCornerRadius),
- SkIntToScalar(kButtonCornerRadius));
- paint.setColor(kPagerSelectedColor);
- canvas->DrawPath(selected_path, paint);
- }
- }
-
- int button_width_;
-
- // [-1, 1] range that represents the portion of the button that should be
- // painted with kSelectedColor. Positive range starts from left side and
- // negative range starts from the right side.
- double selected_range_;
-
- DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton);
-};
-
-// Gets PageSwitcherButton at |index| in |buttons|.
-PageSwitcherButton* GetButtonByIndex(views::View* buttons, int index) {
- return static_cast<PageSwitcherButton*>(buttons->child_at(index));
-}
-
-} // namespace
-
-PageSwitcher::PageSwitcher(PaginationModel* model)
- : model_(model),
- buttons_(new views::View) {
- AddChildView(buttons_);
-
- TotalPagesChanged();
- SelectedPageChanged(-1, model->selected_page());
- model_->AddObserver(this);
-}
-
-PageSwitcher::~PageSwitcher() {
- model_->RemoveObserver(this);
-}
-
-int PageSwitcher::GetPageForPoint(const gfx::Point& point) const {
- if (!buttons_->bounds().Contains(point))
- return -1;
-
- gfx::Point buttons_point(point);
- views::View::ConvertPointToTarget(this, buttons_, &buttons_point);
-
- for (int i = 0; i < buttons_->child_count(); ++i) {
- const views::View* button = buttons_->child_at(i);
- if (button->bounds().Contains(buttons_point))
- return i;
- }
-
- return -1;
-}
-
-void PageSwitcher::UpdateUIForDragPoint(const gfx::Point& point) {
- int page = GetPageForPoint(point);
-
- const int button_count = buttons_->child_count();
- if (page >= 0 && page < button_count) {
- PageSwitcherButton* button =
- static_cast<PageSwitcherButton*>(buttons_->child_at(page));
- button->SetState(views::CustomButton::STATE_HOVERED);
- return;
- }
-
- for (int i = 0; i < button_count; ++i) {
- PageSwitcherButton* button =
- static_cast<PageSwitcherButton*>(buttons_->child_at(i));
- button->SetState(views::CustomButton::STATE_NORMAL);
- }
-}
-
-gfx::Size PageSwitcher::GetPreferredSize() {
- // Always return a size with correct height so that container resize is not
- // needed when more pages are added.
- return gfx::Size(buttons_->GetPreferredSize().width(),
- kPreferredHeight);
-}
-
-void PageSwitcher::Layout() {
- gfx::Rect rect(GetContentsBounds());
-
- CalculateButtonWidthAndSpacing(rect.width());
-
- // Makes |buttons_| horizontally center and vertically fill.
- gfx::Size buttons_size(buttons_->GetPreferredSize());
- gfx::Rect buttons_bounds(rect.CenterPoint().x() - buttons_size.width() / 2,
- rect.y(),
- buttons_size.width(),
- rect.height());
- buttons_->SetBoundsRect(gfx::IntersectRects(rect, buttons_bounds));
-}
-
-void PageSwitcher::CalculateButtonWidthAndSpacing(int contents_width) {
- const int button_count = buttons_->child_count();
- if (!button_count)
- return;
-
- contents_width -= 2 * kButtonStripPadding;
-
- int button_width = kMinButtonWidth;
- int button_spacing = kMinButtonSpacing;
- if (button_count > 1) {
- button_spacing = (contents_width - button_width * button_count) /
- (button_count - 1);
- button_spacing = std::min(kMaxButtonSpacing,
- std::max(kMinButtonSpacing, button_spacing));
- }
-
- button_width = (contents_width - (button_count - 1) * button_spacing) /
- button_count;
- button_width = std::min(kMaxButtonWidth,
- std::max(kMinButtonWidth, button_width));
-
- buttons_->SetLayoutManager(new views::BoxLayout(
- views::BoxLayout::kHorizontal, kButtonStripPadding, 0, button_spacing));
- for (int i = 0; i < button_count; ++i) {
- PageSwitcherButton* button =
- static_cast<PageSwitcherButton*>(buttons_->child_at(i));
- button->set_button_width(button_width);
- }
-}
-
-void PageSwitcher::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- for (int i = 0; i < buttons_->child_count(); ++i) {
- if (sender == static_cast<views::Button*>(buttons_->child_at(i))) {
- model_->SelectPage(i, true /* animate */);
- break;
- }
- }
-}
-
-void PageSwitcher::TotalPagesChanged() {
- buttons_->RemoveAllChildViews(true);
- for (int i = 0; i < model_->total_pages(); ++i) {
- PageSwitcherButton* button = new PageSwitcherButton(this);
- button->SetSelectedRange(i == model_->selected_page() ? 1 : 0);
- buttons_->AddChildView(button);
- }
- buttons_->SetVisible(model_->total_pages() > 1);
- Layout();
-}
-
-void PageSwitcher::SelectedPageChanged(int old_selected, int new_selected) {
- if (old_selected >= 0 && old_selected < buttons_->child_count())
- GetButtonByIndex(buttons_, old_selected)->SetSelectedRange(0);
- if (new_selected >= 0 && new_selected < buttons_->child_count())
- GetButtonByIndex(buttons_, new_selected)->SetSelectedRange(1);
-}
-
-void PageSwitcher::TransitionStarted() {
-}
-
-void PageSwitcher::TransitionChanged() {
- const int current_page = model_->selected_page();
- const int target_page = model_->transition().target_page;
-
- double progress = model_->transition().progress;
- double remaining = progress - 1;
-
- if (current_page > target_page) {
- remaining = -remaining;
- progress = -progress;
- }
-
- GetButtonByIndex(buttons_, current_page)->SetSelectedRange(remaining);
- if (model_->is_valid_page(target_page))
- GetButtonByIndex(buttons_, target_page)->SetSelectedRange(progress);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/page_switcher.h b/chromium/ui/app_list/views/page_switcher.h
deleted file mode 100644
index b05da99ee09..00000000000
--- a/chromium/ui/app_list/views/page_switcher.h
+++ /dev/null
@@ -1,61 +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_APP_LIST_VIEWS_PAGE_SWITCHER_H_
-#define UI_APP_LIST_VIEWS_PAGE_SWITCHER_H_
-
-#include "base/basictypes.h"
-#include "ui/app_list/pagination_model_observer.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace app_list {
-
-class PaginationModel;
-
-// PageSwitcher represents its underlying PaginationModel with a button strip.
-// Each page in the PageinationModel has a button in the strip and when the
-// button is clicked, the corresponding page becomes selected.
-class PageSwitcher : public views::View,
- public views::ButtonListener,
- public PaginationModelObserver {
- public:
- explicit PageSwitcher(PaginationModel* model);
- virtual ~PageSwitcher();
-
- // Returns the page index of the page switcher button under the point. If no
- // page switcher button is under the point, -1 is return. |point| is in
- // PageSwitcher's coordinates.
- int GetPageForPoint(const gfx::Point& point) const;
-
- // Shows hover for button under the point. |point| is in PageSwitcher's
- // coordinates.
- void UpdateUIForDragPoint(const gfx::Point& point);
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
-
- private:
- void CalculateButtonWidthAndSpacing(int contents_width);
-
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from PaginationModelObserver:
- virtual void TotalPagesChanged() OVERRIDE;
- virtual void SelectedPageChanged(int old_selected, int new_selected) OVERRIDE;
- virtual void TransitionStarted() OVERRIDE;
- virtual void TransitionChanged() OVERRIDE;
-
- PaginationModel* model_; // Owned by AppListController.
- views::View* buttons_; // Owned by views hierarchy.
-
- DISALLOW_COPY_AND_ASSIGN(PageSwitcher);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_PAGE_SWITCHER_H_
diff --git a/chromium/ui/app_list/views/progress_bar_view.cc b/chromium/ui/app_list/views/progress_bar_view.cc
deleted file mode 100644
index aaf52c0f6fb..00000000000
--- a/chromium/ui/app_list/views/progress_bar_view.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/progress_bar_view.h"
-
-#include <algorithm>
-
-#include "grit/ui_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/insets.h"
-#include "ui/views/painter.h"
-
-namespace app_list {
-
-namespace {
-
-// Image assets for the bar part.
-const int kProgressBarImages[] = {
- IDR_APP_LIST_ITEM_PROGRESS_LEFT,
- IDR_APP_LIST_ITEM_PROGRESS_CENTER,
- IDR_APP_LIST_ITEM_PROGRESS_RIGHT
-};
-
-} // namespace
-
-ProgressBarView::ProgressBarView()
- : background_painter_(views::Painter::CreateImagePainter(
- *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
- IDR_APP_LIST_ITEM_PROGRESS_BACKGROUND),
- gfx::Insets(2, 2, 2, 2))),
- bar_painter_(new views::HorizontalPainter(kProgressBarImages)) {}
-
-ProgressBarView::~ProgressBarView() {}
-
-gfx::Size ProgressBarView::GetPreferredSize() {
- return background_painter_->GetMinimumSize();
-}
-
-void ProgressBarView::OnPaint(gfx::Canvas* canvas) {
- gfx::Size paint_size = size();
-
- const gfx::Size min_size(background_painter_->GetMinimumSize());
- if (paint_size.width() < min_size.width() ||
- paint_size.height() < min_size.height()) {
- return;
- }
-
- background_painter_->Paint(canvas, paint_size);
-
- const int kBarEndWidth = 4;
- const int bar_width = paint_size.width() - kBarEndWidth;
- DCHECK_GE(bar_width, 0);
-
- // Map normalized value in [0,1] to the pixel width in
- // [kBarEndWidth, view_size.width()].
- paint_size.set_width(kBarEndWidth + bar_width * GetNormalizedValue());
- bar_painter_->Paint(canvas, paint_size);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/progress_bar_view.h b/chromium/ui/app_list/views/progress_bar_view.h
deleted file mode 100644
index 220eb8d0b1a..00000000000
--- a/chromium/ui/app_list/views/progress_bar_view.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_PROGRESS_BAR_VIEW_H_
-#define UI_APP_LIST_VIEWS_PROGRESS_BAR_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/views/controls/progress_bar.h"
-
-namespace views {
-class Painter;
-}
-
-namespace app_list {
-
-// ProgressBarView implements an image-based progress bar for app launcher.
-class ProgressBarView : public views::ProgressBar {
- public:
- ProgressBarView();
- virtual ~ProgressBarView();
-
- // views::View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- private:
- scoped_ptr<views::Painter> background_painter_;
- scoped_ptr<views::Painter> bar_painter_;
-
- DISALLOW_COPY_AND_ASSIGN(ProgressBarView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_PROGRESS_BAR_VIEW_H_
diff --git a/chromium/ui/app_list/views/pulsing_block_view.cc b/chromium/ui/app_list/views/pulsing_block_view.cc
deleted file mode 100644
index aa2c2733a33..00000000000
--- a/chromium/ui/app_list/views/pulsing_block_view.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/pulsing_block_view.h"
-
-#include <vector>
-
-#include "base/rand_util.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_element.h"
-#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/transform_util.h"
-
-namespace {
-
-const SkColor kBlockColor = SkColorSetRGB(225, 225, 225);
-const int kBlockSize = 64;
-
-const int kAnimationDurationInMs = 600;
-const float kAnimationOpacity[] = { 0.4f, 0.8f, 0.4f };
-const float kAnimationScale[] = { 0.8f, 1.0f, 0.8f };
-
-void SchedulePulsingAnimation(ui::Layer* layer) {
- DCHECK(layer);
- DCHECK_EQ(arraysize(kAnimationOpacity), arraysize(kAnimationScale));
-
- scoped_ptr<ui::LayerAnimationSequence> opacity_sequence(
- new ui::LayerAnimationSequence());
- scoped_ptr<ui::LayerAnimationSequence> transform_sequence(
- new ui::LayerAnimationSequence());
-
- // The animations loop infinitely.
- opacity_sequence->set_is_cyclic(true);
- transform_sequence->set_is_cyclic(true);
-
- const gfx::Rect local_bounds(layer->bounds().size());
- for (size_t i = 0; i < arraysize(kAnimationOpacity); ++i) {
- opacity_sequence->AddElement(
- ui::LayerAnimationElement::CreateOpacityElement(
- kAnimationOpacity[i],
- base::TimeDelta::FromMilliseconds(kAnimationDurationInMs)));
- transform_sequence->AddElement(
- ui::LayerAnimationElement::CreateTransformElement(
- gfx::GetScaleTransform(local_bounds.CenterPoint(),
- kAnimationScale[i]),
- base::TimeDelta::FromMilliseconds(kAnimationDurationInMs)));
- }
-
- ui::LayerAnimationElement::AnimatableProperties opacity_properties;
- opacity_properties.insert(ui::LayerAnimationElement::OPACITY);
- opacity_sequence->AddElement(
- ui::LayerAnimationElement::CreatePauseElement(
- opacity_properties,
- base::TimeDelta::FromMilliseconds(kAnimationDurationInMs)));
-
- ui::LayerAnimationElement::AnimatableProperties transform_properties;
- transform_properties.insert(ui::LayerAnimationElement::TRANSFORM);
- transform_sequence->AddElement(
- ui::LayerAnimationElement::CreatePauseElement(
- transform_properties,
- base::TimeDelta::FromMilliseconds(kAnimationDurationInMs)));
-
- std::vector<ui::LayerAnimationSequence*> animations;
- animations.push_back(opacity_sequence.release());
- animations.push_back(transform_sequence.release());
- layer->GetAnimator()->ScheduleTogether(animations);
-}
-
-} // namespace
-
-namespace app_list {
-
-PulsingBlockView::PulsingBlockView(const gfx::Size& size, bool start_delay) {
-#if defined(USE_AURA)
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(false);
-
- const int max_delay = kAnimationDurationInMs * arraysize(kAnimationOpacity);
- const int delay = start_delay ? base::RandInt(0, max_delay) : 0;
- start_delay_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(delay),
- this, &PulsingBlockView::OnStartDelayTimer);
-#else
- NOTREACHED() << "Pulsing animation is not supported on Windows";
-#endif
-}
-
-PulsingBlockView::~PulsingBlockView() {
-}
-
-void PulsingBlockView::OnStartDelayTimer() {
- SchedulePulsingAnimation(layer());
-}
-
-void PulsingBlockView::OnPaint(gfx::Canvas* canvas) {
- gfx::Rect rect(GetContentsBounds());
- rect.ClampToCenteredSize(gfx::Size(kBlockSize, kBlockSize));
- canvas->FillRect(rect, kBlockColor);
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/pulsing_block_view.h b/chromium/ui/app_list/views/pulsing_block_view.h
deleted file mode 100644
index 22bbec24d51..00000000000
--- a/chromium/ui/app_list/views/pulsing_block_view.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_APP_LIST_VIEWS_PULSING_BLOCK_VIEW_H_
-#define UI_APP_LIST_VIEWS_PULSING_BLOCK_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/timer/timer.h"
-#include "ui/views/view.h"
-
-namespace gfx {
-class Size;
-}
-
-namespace app_list {
-
-// PulsingBlockView shows a pulsing white block via layer animation.
-class PulsingBlockView : public views::View {
- public:
- // Constructs a PulsingBlockView of |size|. If |start_delay| is true,
- // starts the pulsing animation after a random delay.
- PulsingBlockView(const gfx::Size& size, bool start_delay);
- virtual ~PulsingBlockView();
-
- private:
- void OnStartDelayTimer();
-
- // views::View overrides:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- base::OneShotTimer<PulsingBlockView> start_delay_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(PulsingBlockView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_PULSING_BLOCK_VIEW_H_
diff --git a/chromium/ui/app_list/views/search_box_view.cc b/chromium/ui/app_list/views/search_box_view.cc
deleted file mode 100644
index c9751777778..00000000000
--- a/chromium/ui/app_list/views/search_box_view.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/search_box_view.h"
-
-#include <algorithm>
-
-#include "grit/ui_resources.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/views/app_list_menu_views.h"
-#include "ui/app_list/views/search_box_view_delegate.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/events/event.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/textfield/textfield.h"
-
-namespace app_list {
-
-namespace {
-
-const int kPadding = 14;
-const int kIconDimension = 32;
-const int kPreferredWidth = 360;
-const int kPreferredHeight = 48;
-#if !defined(OS_CHROMEOS)
-const int kMenuButtonDimension = 29;
-#endif
-
-const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
-
-// Menu offset relative to the bottom-right corner of the menu button.
-const int kMenuYOffsetFromButton = -4;
-const int kMenuXOffsetFromButton = -7;
-
-} // namespace
-
-SearchBoxView::SearchBoxView(SearchBoxViewDelegate* delegate,
- AppListViewDelegate* view_delegate)
- : delegate_(delegate),
- view_delegate_(view_delegate),
- model_(NULL),
- icon_view_(new views::ImageView),
- speech_button_(NULL),
- search_box_(new views::Textfield),
- contents_view_(NULL) {
- AddChildView(icon_view_);
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
-#if !defined(OS_CHROMEOS)
- menu_button_ = new views::MenuButton(NULL, base::string16(), this, false);
- menu_button_->set_border(NULL);
- menu_button_->SetIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_NORMAL));
- menu_button_->SetHoverIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_HOVER));
- menu_button_->SetPushedIcon(*rb.GetImageSkiaNamed(
- IDR_APP_LIST_TOOLS_PRESSED));
- AddChildView(menu_button_);
-#endif
-
- search_box_->RemoveBorder();
- search_box_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
- search_box_->set_placeholder_text_color(kHintTextColor);
- search_box_->SetController(this);
- AddChildView(search_box_);
-
- ModelChanged();
-}
-
-SearchBoxView::~SearchBoxView() {
- model_->search_box()->RemoveObserver(this);
-}
-
-void SearchBoxView::ModelChanged() {
- if (model_)
- model_->search_box()->RemoveObserver(this);
-
- model_ = view_delegate_->GetModel();
- DCHECK(model_);
- model_->search_box()->AddObserver(this);
- IconChanged();
- SpeechRecognitionButtonPropChanged();
- HintTextChanged();
-}
-
-bool SearchBoxView::HasSearch() const {
- return !search_box_->text().empty();
-}
-
-void SearchBoxView::ClearSearch() {
- search_box_->SetText(base::string16());
- // Updates model and fires query changed manually because SetText() above
- // does not generate ContentsChanged() notification.
- UpdateModel();
- NotifyQueryChanged();
-}
-
-void SearchBoxView::InvalidateMenu() {
- menu_.reset();
-}
-
-gfx::Size SearchBoxView::GetPreferredSize() {
- return gfx::Size(kPreferredWidth, kPreferredHeight);
-}
-
-void SearchBoxView::Layout() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect icon_frame(rect);
- icon_frame.set_width(kIconDimension + 2 * kPadding);
- icon_view_->SetBoundsRect(icon_frame);
-
- // Places |speech_button_| if exists. |speech_button_frame| holds its bounds
- // to calculate the search box bounds.
- gfx::Rect speech_button_frame;
- if (speech_button_) {
- speech_button_frame = icon_frame;
- speech_button_frame.set_x(rect.right() - icon_frame.width());
- gfx::Size button_size = speech_button_->GetPreferredSize();
- gfx::Point button_origin = speech_button_frame.CenterPoint();
- button_origin.Offset(-button_size.width() / 2, -button_size.height() / 2);
- speech_button_->SetBoundsRect(gfx::Rect(button_origin, button_size));
- }
-
- gfx::Rect menu_button_frame(rect);
-#if !defined(OS_CHROMEOS)
- menu_button_frame.set_width(kMenuButtonDimension);
- menu_button_frame.set_x(rect.right() - menu_button_frame.width() - kPadding);
- menu_button_frame.ClampToCenteredSize(gfx::Size(menu_button_frame.width(),
- kMenuButtonDimension));
- menu_button_->SetBoundsRect(menu_button_frame);
-#else
- menu_button_frame.set_width(0);
-#endif
-
- gfx::Rect edit_frame(rect);
- edit_frame.set_x(icon_frame.right());
- int edit_frame_width =
- rect.width() - icon_frame.width() - kPadding - menu_button_frame.width();
- if (!speech_button_frame.IsEmpty())
- edit_frame_width -= speech_button_frame.width() + kPadding;
- edit_frame.set_width(edit_frame_width);
- edit_frame.ClampToCenteredSize(
- gfx::Size(edit_frame.width(), search_box_->GetPreferredSize().height()));
- search_box_->SetBoundsRect(edit_frame);
-}
-
-bool SearchBoxView::OnMouseWheel(const ui::MouseWheelEvent& event) {
- if (contents_view_)
- return contents_view_->OnMouseWheel(event);
-
- return false;
-}
-
-void SearchBoxView::UpdateModel() {
- // Temporarily remove from observer to ignore notifications caused by us.
- model_->search_box()->RemoveObserver(this);
- model_->search_box()->SetText(search_box_->text());
- model_->search_box()->SetSelectionModel(search_box_->GetSelectionModel());
- model_->search_box()->AddObserver(this);
-}
-
-void SearchBoxView::NotifyQueryChanged() {
- DCHECK(delegate_);
- delegate_->QueryChanged(this);
-}
-
-void SearchBoxView::ContentsChanged(views::Textfield* sender,
- const base::string16& new_contents) {
- UpdateModel();
- NotifyQueryChanged();
-}
-
-bool SearchBoxView::HandleKeyEvent(views::Textfield* sender,
- const ui::KeyEvent& key_event) {
- bool handled = false;
- if (contents_view_ && contents_view_->visible())
- handled = contents_view_->OnKeyPressed(key_event);
-
- return handled;
-}
-
-void SearchBoxView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- DCHECK(!speech_button_ && sender == speech_button_);
- view_delegate_->ToggleSpeechRecognition();
-}
-
-void SearchBoxView::OnMenuButtonClicked(View* source, const gfx::Point& point) {
- if (!menu_)
- menu_.reset(new AppListMenuViews(view_delegate_));
-
- const gfx::Point menu_location =
- menu_button_->GetBoundsInScreen().bottom_right() +
- gfx::Vector2d(kMenuXOffsetFromButton, kMenuYOffsetFromButton);
- menu_->RunMenuAt(menu_button_, menu_location);
-}
-
-void SearchBoxView::IconChanged() {
- icon_view_->SetImage(model_->search_box()->icon());
-}
-
-void SearchBoxView::SpeechRecognitionButtonPropChanged() {
- const SearchBoxModel::ButtonProperty* speech_button_prop =
- model_->search_box()->speech_button();
- if (speech_button_prop) {
- if (!speech_button_) {
- speech_button_ = new views::ImageButton(this);
- AddChildView(speech_button_);
- }
- speech_button_->SetImage(views::Button::STATE_NORMAL,
- &speech_button_prop->icon);
- speech_button_->SetTooltipText(speech_button_prop->tooltip);
- } else {
- if (speech_button_) {
- // Deleting a view will detach it from its parent.
- delete speech_button_;
- speech_button_ = NULL;
- }
- }
-}
-
-void SearchBoxView::HintTextChanged() {
- search_box_->set_placeholder_text(model_->search_box()->hint_text());
-}
-
-void SearchBoxView::SelectionModelChanged() {
- search_box_->SelectSelectionModel(model_->search_box()->selection_model());
-}
-
-void SearchBoxView::TextChanged() {
- search_box_->SetText(model_->search_box()->text());
- NotifyQueryChanged();
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/search_box_view.h b/chromium/ui/app_list/views/search_box_view.h
deleted file mode 100644
index 440ffba7425..00000000000
--- a/chromium/ui/app_list/views/search_box_view.h
+++ /dev/null
@@ -1,105 +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_APP_LIST_VIEWS_SEARCH_BOX_VIEW_H_
-#define UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_H_
-
-#include <string>
-
-#include "ui/app_list/search_box_model_observer.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/button/menu_button_listener.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/view.h"
-
-namespace views {
-class ImageView;
-class MenuButton;
-class Textfield;
-} // namespace views
-
-namespace app_list {
-
-class AppListMenuViews;
-class AppListModel;
-class AppListViewDelegate;
-class SearchBoxModel;
-class SearchBoxViewDelegate;
-
-// SearchBoxView consists of an icon and a Textfield. SearchBoxModel is its data
-// model that controls what icon to display, what placeholder text to use for
-// Textfield. The text and selection model part could be set to change the
-// contents and selection model of the Textfield.
-class SearchBoxView : public views::View,
- public views::TextfieldController,
- public views::ButtonListener,
- public views::MenuButtonListener,
- public SearchBoxModelObserver {
- public:
- SearchBoxView(SearchBoxViewDelegate* delegate,
- AppListViewDelegate* view_delegate);
- virtual ~SearchBoxView();
-
- void ModelChanged();
- bool HasSearch() const;
- void ClearSearch();
- void InvalidateMenu();
-
- views::Textfield* search_box() { return search_box_; }
-
- void set_contents_view(View* contents_view) {
- contents_view_ = contents_view;
- }
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
-
- private:
- // Updates model text and selection model with current Textfield info.
- void UpdateModel();
-
- // Fires query change notification.
- void NotifyQueryChanged();
-
- // Overridden from views::TextfieldController:
- virtual void ContentsChanged(views::Textfield* sender,
- const base::string16& new_contents) OVERRIDE;
- virtual bool HandleKeyEvent(views::Textfield* sender,
- const ui::KeyEvent& key_event) OVERRIDE;
-
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from views::MenuButtonListener:
- virtual void OnMenuButtonClicked(View* source,
- const gfx::Point& point) OVERRIDE;
-
- // Overridden from SearchBoxModelObserver:
- virtual void IconChanged() OVERRIDE;
- virtual void SpeechRecognitionButtonPropChanged() OVERRIDE;
- virtual void HintTextChanged() OVERRIDE;
- virtual void SelectionModelChanged() OVERRIDE;
- virtual void TextChanged() OVERRIDE;
-
- SearchBoxViewDelegate* delegate_; // Not owned.
- AppListViewDelegate* view_delegate_; // Not owned.
- AppListModel* model_; // Owned by the profile-keyed service.
-
- scoped_ptr<AppListMenuViews> menu_;
-
- views::ImageView* icon_view_; // Owned by views hierarchy.
- views::ImageButton* speech_button_; // Owned by views hierarchy.
- views::MenuButton* menu_button_; // Owned by views hierarchy.
- views::Textfield* search_box_; // Owned by views hierarchy.
- views::View* contents_view_; // Owned by views hierarchy.
-
- DISALLOW_COPY_AND_ASSIGN(SearchBoxView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_H_
diff --git a/chromium/ui/app_list/views/search_box_view_delegate.h b/chromium/ui/app_list/views/search_box_view_delegate.h
deleted file mode 100644
index cdbf23878bb..00000000000
--- a/chromium/ui/app_list/views/search_box_view_delegate.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class SearchBoxView;
-
-class APP_LIST_EXPORT SearchBoxViewDelegate {
- public:
- // Invoked when query text has changed by the user.
- virtual void QueryChanged(SearchBoxView* sender) = 0;
-
- protected:
- virtual ~SearchBoxViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/search_result_actions_view.cc b/chromium/ui/app_list/views/search_result_actions_view.cc
deleted file mode 100644
index 2c6abcfe22c..00000000000
--- a/chromium/ui/app_list/views/search_result_actions_view.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/search_result_actions_view.h"
-
-#include "ui/app_list/views/search_result_actions_view_delegate.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/blue_button.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace app_list {
-
-SearchResultActionsView::SearchResultActionsView(
- SearchResultActionsViewDelegate* delegate)
- : delegate_(delegate),
- selected_action_(-1) {
- SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 10, 0));
-}
-
-SearchResultActionsView::~SearchResultActionsView() {}
-
-void SearchResultActionsView::SetActions(const SearchResult::Actions& actions) {
- RemoveAllChildViews(true);
-
- for (size_t i = 0; i < actions.size(); ++i) {
- const SearchResult::Action& action = actions.at(i);
- if (action.label_text.empty())
- CreateImageButton(action);
- else
- CreateBlueButton(action);
- }
-
- PreferredSizeChanged();
- SetSelectedAction(-1);
-}
-
-void SearchResultActionsView::SetSelectedAction(int action_index) {
- // Clamp |action_index| in [-1, child_count()].
- action_index = std::min(child_count(), std::max(-1, action_index));
-
- if (selected_action_ == action_index)
- return;
-
- selected_action_ = action_index;
- SchedulePaint();
-
- if (IsValidActionIndex(selected_action_)) {
- child_at(selected_action_)->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
- }
-}
-
-bool SearchResultActionsView::IsValidActionIndex(int action_index) const {
- return action_index >= 0 && action_index < child_count();
-}
-
-void SearchResultActionsView::CreateImageButton(
- const SearchResult::Action& action) {
- views::ImageButton* button = new views::ImageButton(this);
- button->set_border(views::Border::CreateEmptyBorder(0, 9, 0, 9));
- button->SetAccessibleName(action.tooltip_text);
- button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
- views::ImageButton::ALIGN_MIDDLE);
- button->SetImage(views::CustomButton::STATE_NORMAL, &action.base_image);
- button->SetImage(views::CustomButton::STATE_HOVERED, &action.hover_image);
- button->SetImage(views::CustomButton::STATE_PRESSED, &action.pressed_image);
- button->SetTooltipText(action.tooltip_text);
- AddChildView(button);
-}
-
-void SearchResultActionsView::CreateBlueButton(
- const SearchResult::Action& action) {
- views::BlueButton* button = new views::BlueButton(this, action.label_text);
- button->SetAccessibleName(action.label_text);
- button->SetTooltipText(action.tooltip_text);
- button->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
- ui::ResourceBundle::SmallBoldFont));
- button->SetFocusable(false);
- AddChildView(button);
-}
-
-void SearchResultActionsView::OnPaint(gfx::Canvas* canvas) {
- if (!IsValidActionIndex(selected_action_))
- return;
-
- const gfx::Rect active_action_bounds(child_at(selected_action_)->bounds());
- const SkColor kActiveActionBackground = SkColorSetRGB(0xA0, 0xA0, 0xA0);
- canvas->FillRect(active_action_bounds, kActiveActionBackground);
-}
-
-void SearchResultActionsView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (!delegate_)
- return;
-
- const int index = GetIndexOf(sender);
- DCHECK_NE(-1, index);
- delegate_->OnSearchResultActionActivated(index, event.flags());
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/search_result_actions_view.h b/chromium/ui/app_list/views/search_result_actions_view.h
deleted file mode 100644
index 7e5fa75fa15..00000000000
--- a/chromium/ui/app_list/views/search_result_actions_view.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_H_
-
-#include "base/basictypes.h"
-#include "ui/app_list/search_result.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace app_list {
-
-class SearchResultActionsViewDelegate;
-
-// SearchResultActionsView displays a SearchResult::Actions in a button
-// strip. Each action is presented as a button and horizontally laid out.
-class SearchResultActionsView : public views::View,
- public views::ButtonListener {
- public:
- explicit SearchResultActionsView(SearchResultActionsViewDelegate* delegate);
- virtual ~SearchResultActionsView();
-
- void SetActions(const SearchResult::Actions& actions);
-
- void SetSelectedAction(int action_index);
- int selected_action() const { return selected_action_; }
-
- bool IsValidActionIndex(int action_index) const;
-
- private:
- void CreateImageButton(const SearchResult::Action& action);
- void CreateBlueButton(const SearchResult::Action& action);
-
- // views::View overrides:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- // views::ButtonListener overrides:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- SearchResultActionsViewDelegate* delegate_; // Not owned.
- int selected_action_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchResultActionsView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_H_
diff --git a/chromium/ui/app_list/views/search_result_actions_view_delegate.h b/chromium/ui/app_list/views/search_result_actions_view_delegate.h
deleted file mode 100644
index 2aedbccf7b8..00000000000
--- a/chromium/ui/app_list/views/search_result_actions_view_delegate.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_DELEGATE_H_
-
-namespace app_list {
-
-class SearchResultActionsViewDelegate {
- public:
- // Invoked when the action button represent the action at |index| is pressed
- // in SearchResultActionsView.
- virtual void OnSearchResultActionActivated(size_t index, int event_flags) = 0;
-
- protected:
- virtual ~SearchResultActionsViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_ACTIONS_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/search_result_list_view.cc b/chromium/ui/app_list/views/search_result_list_view.cc
deleted file mode 100644
index 84b13da1739..00000000000
--- a/chromium/ui/app_list/views/search_result_list_view.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/search_result_list_view.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/app_list/views/search_result_list_view_delegate.h"
-#include "ui/app_list/views/search_result_view.h"
-#include "ui/events/event.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace {
-
-const int kMaxResults = 6;
-
-} // namespace
-
-namespace app_list {
-
-SearchResultListView::SearchResultListView(
- SearchResultListViewDelegate* delegate)
- : delegate_(delegate),
- results_(NULL),
- last_visible_index_(0),
- selected_index_(-1),
- update_factory_(this) {
- SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
- for (int i = 0; i < kMaxResults; ++i)
- AddChildView(new SearchResultView(this, this));
-}
-
-SearchResultListView::~SearchResultListView() {
- if (results_)
- results_->RemoveObserver(this);
-}
-
-void SearchResultListView::SetResults(AppListModel::SearchResults* results) {
- if (results_)
- results_->RemoveObserver(this);
-
- results_ = results;
- if (results_)
- results_->AddObserver(this);
-
- Update();
-}
-
-void SearchResultListView::SetSelectedIndex(int selected_index) {
- if (selected_index_ == selected_index)
- return;
-
- if (selected_index_ >= 0) {
- SearchResultView* selected_view = GetResultViewAt(selected_index_);
- selected_view->ClearSelectedAction();
- selected_view->SchedulePaint();
- }
-
- selected_index_ = selected_index;
-
- if (selected_index_ >= 0) {
- SearchResultView* selected_view = GetResultViewAt(selected_index_);
- selected_view->ClearSelectedAction();
- selected_view->SchedulePaint();
- selected_view->NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS,
- true);
- }
-}
-
-bool SearchResultListView::IsResultViewSelected(
- const SearchResultView* result_view) const {
- if (selected_index_ < 0)
- return false;
-
- return static_cast<const SearchResultView*>(child_at(selected_index_)) ==
- result_view;
-}
-
-bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) {
- if (selected_index_ >= 0 && child_at(selected_index_)->OnKeyPressed(event))
- return true;
-
- switch (event.key_code()) {
- case ui::VKEY_TAB:
- if (event.IsShiftDown())
- SetSelectedIndex(std::max(selected_index_ - 1, 0));
- else
- SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_));
- return true;
- case ui::VKEY_UP:
- SetSelectedIndex(std::max(selected_index_ - 1, 0));
- return true;
- case ui::VKEY_DOWN:
- SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_));
- return true;
- default:
- break;
- }
- return false;
-}
-
-SearchResultView* SearchResultListView::GetResultViewAt(int index) {
- DCHECK(index >= 0 && index < child_count());
- return static_cast<SearchResultView*>(child_at(index));
-}
-
-void SearchResultListView::Update() {
- last_visible_index_ = 0;
- for (size_t i = 0; i < static_cast<size_t>(child_count()); ++i) {
- SearchResultView* result_view = GetResultViewAt(i);
- if (i < results_->item_count()) {
- result_view->SetResult(results_->GetItemAt(i));
- result_view->SetVisible(true);
- last_visible_index_ = i;
- } else {
- result_view->SetResult(NULL);
- result_view->SetVisible(false);
- }
- }
- if (selected_index_ > last_visible_index_)
- SetSelectedIndex(last_visible_index_);
-
- Layout();
- update_factory_.InvalidateWeakPtrs();
-}
-
-void SearchResultListView::ScheduleUpdate() {
- // When search results are added one by one, each addition generates an update
- // request. Consolidates those update requests into one Update call.
- if (!update_factory_.HasWeakPtrs()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&SearchResultListView::Update,
- update_factory_.GetWeakPtr()));
- }
-}
-
-void SearchResultListView::ListItemsAdded(size_t start, size_t count) {
- ScheduleUpdate();
-}
-
-void SearchResultListView::ListItemsRemoved(size_t start, size_t count) {
- size_t last = std::min(start + count, static_cast<size_t>(child_count()));
- for (size_t i = start; i < last; ++i)
- GetResultViewAt(i)->ClearResultNoRepaint();
-
- ScheduleUpdate();
-}
-
-void SearchResultListView::ListItemMoved(size_t index, size_t target_index) {
- NOTREACHED();
-}
-
-void SearchResultListView::ListItemsChanged(size_t start, size_t count) {
- ScheduleUpdate();
-}
-
-void SearchResultListView::SearchResultActivated(SearchResultView* view,
- int event_flags) {
- if (delegate_ && view->result())
- delegate_->OpenResult(view->result(), event_flags);
-}
-
-void SearchResultListView::SearchResultActionActivated(SearchResultView* view,
- size_t action_index,
- int event_flags) {
- if (delegate_ && view->result()) {
- delegate_->InvokeResultAction(
- view->result(), action_index, event_flags);
- }
-}
-
-void SearchResultListView::OnSearchResultInstalled(SearchResultView* view) {
- if (delegate_ && view->result())
- delegate_->OnResultInstalled(view->result());
-}
-
-void SearchResultListView::OnSearchResultUninstalled(SearchResultView* view) {
- if (delegate_ && view->result())
- delegate_->OnResultUninstalled(view->result());
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/search_result_list_view.h b/chromium/ui/app_list/views/search_result_list_view.h
deleted file mode 100644
index 8228ebd2c71..00000000000
--- a/chromium/ui/app_list/views/search_result_list_view.h
+++ /dev/null
@@ -1,78 +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_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/views/search_result_view_delegate.h"
-#include "ui/base/models/list_model_observer.h"
-#include "ui/views/view.h"
-
-namespace app_list {
-
-class SearchResultListViewDelegate;
-class SearchResultView;
-
-// SearchResultListView displays AppListModel::SearchResults with a list of
-// SearchResultView.
-class SearchResultListView : public views::View,
- public ui::ListModelObserver,
- public SearchResultViewDelegate {
- public:
- explicit SearchResultListView(SearchResultListViewDelegate* delegate);
- virtual ~SearchResultListView();
-
- void SetResults(AppListModel::SearchResults* results);
-
- void SetSelectedIndex(int selected_index);
-
- bool IsResultViewSelected(const SearchResultView* result_view) const;
-
- // Overridden from views::View:
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
-
- private:
- // Helper function to get SearchResultView at given |index|.
- SearchResultView* GetResultViewAt(int index);
-
- // Updates UI with model.
- void Update();
-
- // Schedules an Update call using |update_factory_|. Do nothing if there is a
- // pending call.
- void ScheduleUpdate();
-
- // Overridden from ListModelObserver:
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
- virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
-
- // Overridden from SearchResultViewDelegate:
- virtual void SearchResultActivated(SearchResultView* view,
- int event_flags) OVERRIDE;
- virtual void SearchResultActionActivated(SearchResultView* view,
- size_t action_index,
- int event_flags) OVERRIDE;
- virtual void OnSearchResultInstalled(SearchResultView* view) OVERRIDE;
- virtual void OnSearchResultUninstalled(SearchResultView* view) OVERRIDE;
-
- SearchResultListViewDelegate* delegate_; // Not owned.
- AppListModel::SearchResults* results_; // Owned by AppListModel.
-
- int last_visible_index_;
- int selected_index_;
-
- // The factory that consolidates multiple Update calls into one.
- base::WeakPtrFactory<SearchResultListView> update_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchResultListView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_H_
diff --git a/chromium/ui/app_list/views/search_result_list_view_delegate.h b/chromium/ui/app_list/views/search_result_list_view_delegate.h
deleted file mode 100644
index 405094b31a5..00000000000
--- a/chromium/ui/app_list/views/search_result_list_view_delegate.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class SearchResult;
-
-class APP_LIST_EXPORT SearchResultListViewDelegate {
- public:
- // Invoked to open given |result|. |event_flags| contains the flags of the
- // keyboard/mouse event that triggers the "open" request. Delegate could use
- // the |event_flags| information to choose different ways to open the result.
- virtual void OpenResult(SearchResult* result,
- int event_flags) = 0;
-
- // Called to invoke a custom action on |result|. |action_index| corresponds
- // to the index of the icon in |result.action_icons()| that was activated.
- virtual void InvokeResultAction(SearchResult* result,
- int action_index,
- int event_flags) = 0;
-
- // Called when the app represented by |result| is installed.
- virtual void OnResultInstalled(SearchResult* result) = 0;
-
- // Called when the app represented by |result| is uninstalled.
- virtual void OnResultUninstalled(SearchResult* result) = 0;
-
- protected:
- virtual ~SearchResultListViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/search_result_view.cc b/chromium/ui/app_list/views/search_result_view.cc
deleted file mode 100644
index 5ba5a2083bd..00000000000
--- a/chromium/ui/app_list/views/search_result_view.cc
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/search_result_view.h"
-
-#include <algorithm>
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/search_result.h"
-#include "ui/app_list/views/progress_bar_view.h"
-#include "ui/app_list/views/search_result_actions_view.h"
-#include "ui/app_list/views/search_result_list_view.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/render_text.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_runner.h"
-
-namespace app_list {
-
-namespace {
-
-const int kPreferredWidth = 300;
-const int kPreferredHeight = 52;
-const int kIconDimension = 32;
-const int kIconPadding = 14;
-const int kIconViewWidth = kIconDimension + 2 * kIconPadding;
-const int kTextTrailPadding = kIconPadding;
-const int kBorderSize = 1;
-
-// Extra margin at the right of the rightmost action icon.
-const int kActionButtonRightMargin = 8;
-
-// Creates a RenderText of given |text| and |styles|. Caller takes ownership
-// of returned RenderText.
-gfx::RenderText* CreateRenderText(const base::string16& text,
- const SearchResult::Tags& tags) {
- gfx::RenderText* render_text = gfx::RenderText::CreateInstance();
- render_text->SetText(text);
- render_text->SetColor(kResultDefaultTextColor);
-
- for (SearchResult::Tags::const_iterator it = tags.begin();
- it != tags.end();
- ++it) {
- // NONE means default style so do nothing.
- if (it->styles == SearchResult::Tag::NONE)
- continue;
-
- if (it->styles & SearchResult::Tag::MATCH)
- render_text->ApplyStyle(gfx::BOLD, true, it->range);
- if (it->styles & SearchResult::Tag::DIM)
- render_text->ApplyColor(kResultDimmedTextColor, it->range);
- else if (it->styles & SearchResult::Tag::URL)
- render_text->ApplyColor(kResultURLTextColor, it->range);
- }
-
- return render_text;
-}
-
-} // namespace
-
-// static
-const char SearchResultView::kViewClassName[] = "ui/app_list/SearchResultView";
-
-SearchResultView::SearchResultView(SearchResultListView* list_view,
- SearchResultViewDelegate* delegate)
- : views::CustomButton(this),
- result_(NULL),
- list_view_(list_view),
- delegate_(delegate),
- icon_(new views::ImageView),
- actions_view_(new SearchResultActionsView(this)),
- progress_bar_(new ProgressBarView) {
- icon_->set_interactive(false);
-
- AddChildView(icon_);
- AddChildView(actions_view_);
- AddChildView(progress_bar_);
- set_context_menu_controller(this);
-}
-
-SearchResultView::~SearchResultView() {
- ClearResultNoRepaint();
-}
-
-void SearchResultView::SetResult(SearchResult* result) {
- ClearResultNoRepaint();
-
- result_ = result;
- if (result_)
- result_->AddObserver(this);
-
- OnIconChanged();
- OnActionsChanged();
- UpdateTitleText();
- UpdateDetailsText();
- OnIsInstallingChanged();
- SchedulePaint();
-}
-
-void SearchResultView::ClearResultNoRepaint() {
- if (result_)
- result_->RemoveObserver(this);
- result_ = NULL;
-}
-
-void SearchResultView::ClearSelectedAction() {
- actions_view_->SetSelectedAction(-1);
-}
-
-void SearchResultView::UpdateTitleText() {
- if (!result_ || result_->title().empty()) {
- title_text_.reset();
- SetAccessibleName(base::string16());
- } else {
- title_text_.reset(CreateRenderText(result_->title(),
- result_->title_tags()));
- SetAccessibleName(result_->title());
- }
-}
-
-void SearchResultView::UpdateDetailsText() {
- if (!result_ || result_->details().empty()) {
- details_text_.reset();
- } else {
- details_text_.reset(CreateRenderText(result_->details(),
- result_->details_tags()));
- }
-}
-
-const char* SearchResultView::GetClassName() const {
- return kViewClassName;
-}
-
-gfx::Size SearchResultView::GetPreferredSize() {
- return gfx::Size(kPreferredWidth, kPreferredHeight);
-}
-
-void SearchResultView::Layout() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect icon_bounds(rect);
- icon_bounds.set_width(kIconViewWidth);
- icon_bounds.Inset(kIconPadding, (rect.height() - kIconDimension) / 2);
- icon_bounds.Intersect(rect);
- icon_->SetBoundsRect(icon_bounds);
-
- const int max_actions_width =
- (rect.right() - kActionButtonRightMargin - icon_bounds.right()) / 2;
- int actions_width = std::min(max_actions_width,
- actions_view_->GetPreferredSize().width());
-
- gfx::Rect actions_bounds(rect);
- actions_bounds.set_x(rect.right() - kActionButtonRightMargin - actions_width);
- actions_bounds.set_width(actions_width);
- actions_view_->SetBoundsRect(actions_bounds);
-
- const int progress_width = rect.width() / 5;
- const int progress_height = progress_bar_->GetPreferredSize().height();
- const gfx::Rect progress_bounds(
- rect.right() - kActionButtonRightMargin - progress_width,
- rect.y() + (rect.height() - progress_height) / 2,
- progress_width,
- progress_height);
- progress_bar_->SetBoundsRect(progress_bounds);
-}
-
-bool SearchResultView::OnKeyPressed(const ui::KeyEvent& event) {
- // |result_| could be NULL when result list is changing.
- if (!result_)
- return false;
-
- switch (event.key_code()) {
- case ui::VKEY_TAB: {
- int new_selected = actions_view_->selected_action()
- + (event.IsShiftDown() ? -1 : 1);
- actions_view_->SetSelectedAction(new_selected);
- return actions_view_->IsValidActionIndex(new_selected);
- }
- case ui::VKEY_RETURN: {
- int selected = actions_view_->selected_action();
- if (actions_view_->IsValidActionIndex(selected)) {
- OnSearchResultActionActivated(selected, event.flags());
- } else {
- delegate_->SearchResultActivated(this, event.flags());
- }
- return true;
- }
- default:
- break;
- }
-
- return false;
-}
-
-void SearchResultView::ChildPreferredSizeChanged(views::View* child) {
- Layout();
-}
-
-void SearchResultView::OnPaint(gfx::Canvas* canvas) {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
-
- gfx::Rect content_rect(rect);
- content_rect.set_height(rect.height() - kBorderSize);
-
- const bool selected = list_view_->IsResultViewSelected(this);
- const bool hover = state() == STATE_HOVERED || state() == STATE_PRESSED;
- if (selected)
- canvas->FillRect(content_rect, kSelectedColor);
- else if (hover)
- canvas->FillRect(content_rect, kHighlightedColor);
- else
- canvas->FillRect(content_rect, kContentsBackgroundColor);
-
- gfx::Rect border_bottom = gfx::SubtractRects(rect, content_rect);
- canvas->FillRect(border_bottom, kResultBorderColor);
-
- gfx::Rect text_bounds(rect);
- text_bounds.set_x(kIconViewWidth);
- if (actions_view_->visible()) {
- text_bounds.set_width(
- rect.width() - kIconViewWidth - kTextTrailPadding -
- actions_view_->bounds().width() -
- (actions_view_->has_children() ? kActionButtonRightMargin : 0));
- } else {
- text_bounds.set_width(
- rect.width() - kIconViewWidth - kTextTrailPadding -
- progress_bar_->bounds().width() - kActionButtonRightMargin);
- }
- text_bounds.set_x(GetMirroredXWithWidthInView(text_bounds.x(),
- text_bounds.width()));
-
- if (title_text_ && details_text_) {
- gfx::Size title_size(text_bounds.width(),
- title_text_->GetStringSize().height());
- gfx::Size details_size(text_bounds.width(),
- details_text_->GetStringSize().height());
- int total_height = title_size.height() + + details_size.height();
- int y = text_bounds.y() + (text_bounds.height() - total_height) / 2;
-
- title_text_->SetDisplayRect(gfx::Rect(gfx::Point(text_bounds.x(), y),
- title_size));
- title_text_->Draw(canvas);
-
- y += title_size.height();
- details_text_->SetDisplayRect(gfx::Rect(gfx::Point(text_bounds.x(), y),
- details_size));
- details_text_->Draw(canvas);
- } else if (title_text_) {
- gfx::Size title_size(text_bounds.width(),
- title_text_->GetStringSize().height());
- gfx::Rect centered_title_rect(text_bounds);
- centered_title_rect.ClampToCenteredSize(title_size);
- title_text_->SetDisplayRect(centered_title_rect);
- title_text_->Draw(canvas);
- }
-}
-
-void SearchResultView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- DCHECK(sender == this);
-
- delegate_->SearchResultActivated(this, event.flags());
-}
-
-void SearchResultView::OnIconChanged() {
- gfx::ImageSkia image(result_ ? result_->icon() : gfx::ImageSkia());
- // Note this might leave the view with an old icon. But it is needed to avoid
- // flash when a SearchResult's icon is loaded asynchronously. In this case, it
- // looks nicer to keep the stale icon for a little while on screen instead of
- // clearing it out. It should work correctly as long as the SearchResult does
- // not forget to SetIcon when it's ready.
- if (image.isNull())
- return;
-
- // Scales down big icons but leave small ones unchanged.
- if (image.width() > kIconDimension || image.height() > kIconDimension) {
- image = gfx::ImageSkiaOperations::CreateResizedImage(
- image,
- skia::ImageOperations::RESIZE_BEST,
- gfx::Size(kIconDimension, kIconDimension));
- } else {
- icon_->ResetImageSize();
- }
-
- // Set the image to an empty image before we reset the image because
- // since we're using the same backing store for our images, sometimes
- // ImageView won't detect that we have a new image set due to the pixel
- // buffer pointers remaining the same despite the image changing.
- icon_->SetImage(gfx::ImageSkia());
- icon_->SetImage(image);
-}
-
-void SearchResultView::OnActionsChanged() {
- actions_view_->SetActions(result_ ? result_->actions()
- : SearchResult::Actions());
-}
-
-void SearchResultView::OnIsInstallingChanged() {
- const bool is_installing = result_ && result_->is_installing();
- actions_view_->SetVisible(!is_installing);
- progress_bar_->SetVisible(is_installing);
-}
-
-void SearchResultView::OnPercentDownloadedChanged() {
- progress_bar_->SetValue(result_ ? result_->percent_downloaded() / 100.0 : 0);
-}
-
-void SearchResultView::OnItemInstalled() {
- delegate_->OnSearchResultInstalled(this);
-}
-
-void SearchResultView::OnItemUninstalled() {
- delegate_->OnSearchResultUninstalled(this);
-}
-
-void SearchResultView::OnSearchResultActionActivated(size_t index,
- int event_flags) {
- // |result_| could be NULL when result list is changing.
- if (!result_)
- return;
-
- DCHECK_LT(index, result_->actions().size());
-
- delegate_->SearchResultActionActivated(this, index, event_flags);
-}
-
-void SearchResultView::ShowContextMenuForView(views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) {
- // |result_| could be NULL when result list is changing.
- if (!result_)
- return;
-
- ui::MenuModel* menu_model = result_->GetContextMenuModel();
- if (!menu_model)
- return;
-
- context_menu_runner_.reset(new views::MenuRunner(menu_model));
- if (context_menu_runner_->RunMenuAt(
- GetWidget(), NULL, gfx::Rect(point, gfx::Size()),
- views::MenuItemView::TOPLEFT, source_type,
- views::MenuRunner::HAS_MNEMONICS) ==
- views::MenuRunner::MENU_DELETED)
- return;
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/search_result_view.h b/chromium/ui/app_list/views/search_result_view.h
deleted file mode 100644
index d9cd9078ff9..00000000000
--- a/chromium/ui/app_list/views/search_result_view.h
+++ /dev/null
@@ -1,114 +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_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/app_list/search_result_observer.h"
-#include "ui/app_list/views/search_result_actions_view_delegate.h"
-#include "ui/views/context_menu_controller.h"
-#include "ui/views/controls/button/custom_button.h"
-
-namespace gfx {
-class RenderText;
-}
-
-namespace views {
-class ImageButton;
-class ImageView;
-class MenuRunner;
-}
-
-namespace app_list {
-
-class ProgressBarView;
-class SearchResult;
-class SearchResultListView;
-class SearchResultViewDelegate;
-class SearchResultActionsView;
-
-// SearchResultView displays a SearchResult.
-class SearchResultView : public views::CustomButton,
- public views::ButtonListener,
- public views::ContextMenuController,
- public SearchResultObserver,
- public SearchResultActionsViewDelegate {
- public:
- // Internal class name.
- static const char kViewClassName[];
-
- SearchResultView(SearchResultListView* list_view,
- SearchResultViewDelegate* delegate);
- virtual ~SearchResultView();
-
- // Sets/gets SearchResult displayed by this view.
- void SetResult(SearchResult* result);
- SearchResult* result() { return result_; }
-
- // Clears reference to SearchResult but don't schedule repaint.
- void ClearResultNoRepaint();
-
- // Clears the selected action.
- void ClearSelectedAction();
-
- private:
- void UpdateTitleText();
- void UpdateDetailsText();
-
- // views::View overrides:
- virtual const char* GetClassName() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- // views::ButtonListener overrides:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // views::ContextMenuController overrides:
- virtual void ShowContextMenuForView(views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) OVERRIDE;
-
- // SearchResultObserver overrides:
- virtual void OnIconChanged() OVERRIDE;
- virtual void OnActionsChanged() OVERRIDE;
- virtual void OnIsInstallingChanged() OVERRIDE;
- virtual void OnPercentDownloadedChanged() OVERRIDE;
- virtual void OnItemInstalled() OVERRIDE;
- virtual void OnItemUninstalled() OVERRIDE;
-
- // SearchResultActionsViewDelegate overrides:
- virtual void OnSearchResultActionActivated(size_t index,
- int event_flags) OVERRIDE;
-
- SearchResult* result_; // Owned by AppListModel::SearchResults.
-
- // Parent list view. Owned by views hierarchy.
- SearchResultListView* list_view_;
-
- // Not owned by us.
- SearchResultViewDelegate* delegate_;
-
- views::ImageView* icon_; // Owned by views hierarchy.
- scoped_ptr<gfx::RenderText> title_text_;
- scoped_ptr<gfx::RenderText> details_text_;
- SearchResultActionsView* actions_view_; // Owned by the views hierarchy.
- ProgressBarView* progress_bar_; // Owned by views hierarchy.
-
- scoped_ptr<views::MenuRunner> context_menu_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchResultView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_H_
diff --git a/chromium/ui/app_list/views/search_result_view_delegate.h b/chromium/ui/app_list/views/search_result_view_delegate.h
deleted file mode 100644
index e86ccc89c99..00000000000
--- a/chromium/ui/app_list/views/search_result_view_delegate.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_DELEGATE_H_
-
-namespace app_list {
-
-class SearchResultView;
-
-class SearchResultViewDelegate {
- public:
- // Called when the search result is activated.
- virtual void SearchResultActivated(SearchResultView* view,
- int event_flags) = 0;
-
- // Called when one of the search result's optional action icons is activated.
- // |action_index| contains the 0-based index of the action.
- virtual void SearchResultActionActivated(SearchResultView* view,
- size_t action_index,
- int event_flags) = 0;
-
- // Called when the app represented by the search result is installed.
- virtual void OnSearchResultInstalled(SearchResultView* view) = 0;
-
- // Called when the app represented by the search result is uninstalled.
- virtual void OnSearchResultUninstalled(SearchResultView* view) = 0;
-
- protected:
- virtual ~SearchResultViewDelegate() {}
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_VIEW_DELEGATE_H_
diff --git a/chromium/ui/app_list/views/signin_view.cc b/chromium/ui/app_list/views/signin_view.cc
deleted file mode 100644
index 74724e73462..00000000000
--- a/chromium/ui/app_list/views/signin_view.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/signin_view.h"
-
-#include "ui/app_list/signin_delegate.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/button/blue_button.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/link.h"
-#include "ui/views/layout/grid_layout.h"
-
-namespace {
-
-const int kTopPadding = 40;
-const int kBottomPadding = 40;
-const int kLeftPadding = 40;
-const int kRightPadding = 40;
-const int kHeadingPadding = 30;
-const int kButtonPadding = 40;
-
-const int kTitleFontSize = 18;
-const int kTextFontSize = 13;
-const int kButtonFontSize = 12;
-
-} // namespace
-
-namespace app_list {
-
-SigninView::SigninView(SigninDelegate* delegate, int width)
- : delegate_(delegate) {
- if (!delegate_)
- return;
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- const gfx::Font& base_font = rb.GetFont(ui::ResourceBundle::BaseFont);
- title_font_.reset(new gfx::Font(base_font.GetFontName(), kTitleFontSize));
- text_font_.reset(new gfx::Font(base_font.GetFontName(), kTextFontSize));
- button_font_.reset(new gfx::Font(base_font.GetFontName(), kButtonFontSize));
-
- int title_descender = title_font_->GetHeight() - title_font_->GetBaseline();
- int text_descender = text_font_->GetHeight() - text_font_->GetBaseline();
-
- views::GridLayout* layout = new views::GridLayout(this);
- layout->SetInsets(kTopPadding, kLeftPadding, kBottomPadding - text_descender,
- kRightPadding);
- SetLayoutManager(layout);
-
- const int kNormalSetId = 0;
- views::ColumnSet* columns = layout->AddColumnSet(kNormalSetId);
- columns->AddColumn(views::GridLayout::FILL,
- views::GridLayout::FILL,
- 1,
- views::GridLayout::USE_PREF,
- 0,
- 0);
-
- const int kButtonSetId = 1;
- columns = layout->AddColumnSet(kButtonSetId);
- columns->AddColumn(views::GridLayout::LEADING,
- views::GridLayout::FILL,
- 1,
- views::GridLayout::USE_PREF,
- 0,
- 0);
-
- views::Label* heading = new views::Label(delegate_->GetSigninHeading());
- heading->SetFont(*title_font_);
- heading->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-
- layout->StartRow(0, kNormalSetId);
- layout->AddView(heading);
-
- views::Label* text = new views::Label(delegate_->GetSigninText());
- text->SetFont(*text_font_);
- text->SetMultiLine(true);
- text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- layout->StartRowWithPadding(0, kNormalSetId, 0,
- kHeadingPadding - title_descender);
- layout->AddView(text);
-
- views::BlueButton* signin_button = new views::BlueButton(
- this,
- delegate_->GetSigninButtonText());
- signin_button->SetFont(*button_font_);
- layout->StartRowWithPadding(0, kButtonSetId, 0,
- kButtonPadding - text_descender);
- layout->AddView(signin_button);
-
- layout->StartRow(1, kNormalSetId);
- learn_more_link_ = new views::Link(delegate_->GetLearnMoreLinkText());
- learn_more_link_->set_listener(this);
- learn_more_link_->SetFont(*text_font_);
- learn_more_link_->SetUnderline(false);
- layout->AddView(learn_more_link_,
- 1,
- 1,
- views::GridLayout::LEADING,
- views::GridLayout::TRAILING);
-
- layout->StartRow(0, kNormalSetId);
- settings_link_ = new views::Link(delegate_->GetSettingsLinkText());
- settings_link_->set_listener(this);
- settings_link_->SetFont(*text_font_);
- settings_link_->SetUnderline(false);
- layout->AddView(settings_link_,
- 1,
- 1,
- views::GridLayout::LEADING,
- views::GridLayout::TRAILING);
-}
-
-SigninView::~SigninView() {
-}
-
-void SigninView::ButtonPressed(views::Button* sender, const ui::Event& event) {
- if (delegate_)
- delegate_->ShowSignin();
-}
-
-void SigninView::LinkClicked(views::Link* source, int event_flags) {
- if (delegate_) {
- if (source == learn_more_link_)
- delegate_->OpenLearnMore();
- else if (source == settings_link_)
- delegate_->OpenSettings();
- else
- NOTREACHED();
- }
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/signin_view.h b/chromium/ui/app_list/views/signin_view.h
deleted file mode 100644
index 47a107b3329..00000000000
--- a/chromium/ui/app_list/views/signin_view.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SIGNIN_VIEW_H_
-#define UI_APP_LIST_VIEWS_SIGNIN_VIEW_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/link_listener.h"
-#include "ui/views/view.h"
-
-namespace gfx {
-class Font;
-}
-
-namespace app_list {
-
-class SigninDelegate;
-
-// The SigninView is shown in the app list when the user needs to sign in.
-class SigninView : public views::View,
- public views::ButtonListener,
- public views::LinkListener {
- public:
- SigninView(SigninDelegate* delegate, int width);
- virtual ~SigninView();
-
- private:
- // views::ButtonListener overrides:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // views::LinkListener overrides:
- virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
-
- views::Link* learn_more_link_;
- views::Link* settings_link_;
- scoped_ptr<gfx::Font> title_font_;
- scoped_ptr<gfx::Font> text_font_;
- scoped_ptr<gfx::Font> button_font_;
-
- SigninDelegate* delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(SigninView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SIGNIN_VIEW_H_
diff --git a/chromium/ui/app_list/views/speech_view.cc b/chromium/ui/app_list/views/speech_view.cc
deleted file mode 100644
index d3c64be9b3a..00000000000
--- a/chromium/ui/app_list/views/speech_view.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/speech_view.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_resources.h"
-#include "grit/ui_strings.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/speech_ui_model.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/shadow_border.h"
-
-namespace app_list {
-
-namespace {
-
-const int kShadowOffset = 1;
-const int kShadowBlur = 4;
-const int kSpeechViewMaxHeight = 300;
-const int kTextSize = 20;
-const int kMicButtonMargin = 12;
-const int kTextMargin = 32;
-const int kIndicatorRadiusMax = 100;
-const int kIndicatorAnimationDuration = 100;
-const SkColor kShadowColor = SkColorSetARGB(0.3 * 255, 0, 0, 0);
-const SkColor kHintTextColor = SkColorSetRGB(119, 119, 119);
-const SkColor kResultTextColor = SkColorSetRGB(178, 178, 178);
-const SkColor kSoundLevelIndicatorColor = SkColorSetRGB(219, 219, 219);
-
-// TODO(mukai): check with multiple devices to make sure these limits.
-const int16 kSoundLevelMin = 50;
-const int16 kSoundLevelMax = 210;
-
-class SoundLevelIndicator : public views::View {
- public:
- SoundLevelIndicator();
- virtual ~SoundLevelIndicator();
-
- private:
- // Overridden from views::View:
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(SoundLevelIndicator);
-};
-
-SoundLevelIndicator::SoundLevelIndicator() {}
-
-SoundLevelIndicator::~SoundLevelIndicator() {}
-
-void SoundLevelIndicator::Paint(gfx::Canvas* canvas) {
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(kSoundLevelIndicatorColor);
- canvas->DrawCircle(bounds().CenterPoint(), width() / 2, paint);
-}
-
-// MicButton is an image button with circular hit area.
-class MicButton : public views::ImageButton {
- public:
- explicit MicButton(views::ButtonListener* listener);
- virtual ~MicButton();
-
- private:
- // Overridden from views::View:
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(MicButton);
-};
-
-MicButton::MicButton(views::ButtonListener* listener)
- : views::ImageButton(listener) {}
-
-MicButton::~MicButton() {}
-
-bool MicButton::HitTestRect(const gfx::Rect& rect) const {
- if (!views::ImageButton::HitTestRect(rect))
- return false;
-
- gfx::Rect local_bounds = GetLocalBounds();
- int radius = local_bounds.width() / 2;
- return (rect.origin() - local_bounds.CenterPoint()).LengthSquared() <
- radius * radius;
-}
-
-} // namespace
-
-// static
-
-SpeechView::SpeechView(AppListViewDelegate* delegate)
- : delegate_(delegate) {
- set_border(new views::ShadowBorder(
- kShadowBlur,
- kShadowColor,
- kShadowOffset, // Vertical offset.
- 0));
-
- // To keep the painting order of the border and the background, this class
- // actually has a single child of 'container' which has white background and
- // contains all components.
- views::View* container = new views::View();
- container->set_background(
- views::Background::CreateSolidBackground(SK_ColorWHITE));
-
- // TODO(mukai): add Google logo.
- indicator_ = new SoundLevelIndicator();
- indicator_->SetVisible(false);
- container->AddChildView(indicator_);
-
- mic_button_ = new MicButton(this);
- container->AddChildView(mic_button_);
-
- // TODO(mukai): use BoundedLabel to cap 2 lines.
- speech_result_ = new views::Label();
- speech_result_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- const gfx::FontList& font_list = speech_result_->font_list();
- speech_result_->SetFontList(font_list.DeriveFontListWithSize(kTextSize));
- speech_result_->SetMultiLine(true);
- container->AddChildView(speech_result_);
-
- AddChildView(container);
-
- delegate_->GetSpeechUI()->AddObserver(this);
- indicator_animator_.reset(new views::BoundsAnimator(container));
- indicator_animator_->SetAnimationDuration(kIndicatorAnimationDuration);
- indicator_animator_->set_tween_type(gfx::Tween::LINEAR);
-
- Reset();
-}
-
-SpeechView::~SpeechView() {
- delegate_->GetSpeechUI()->RemoveObserver(this);
-}
-
-void SpeechView::Reset() {
- ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
- speech_result_->SetText(l10n_util::GetStringUTF16(
- IDS_APP_LIST_SPEECH_HINT_TEXT));
- speech_result_->SetEnabledColor(kHintTextColor);
- mic_button_->SetImage(views::Button::STATE_NORMAL, bundle.GetImageSkiaNamed(
- IDR_APP_LIST_SPEECH_MIC_ON));
-}
-
-int SpeechView::GetIndicatorRadius(int16 level) {
- level = std::min(std::max(level, kSoundLevelMin), kSoundLevelMax);
- int radius_min = mic_button_->width() / 2;
- return (level - kSoundLevelMin) * (kIndicatorRadiusMax - radius_min) /
- (kSoundLevelMax - kSoundLevelMin) + radius_min;
-}
-
-void SpeechView::Layout() {
- views::View* container = child_at(0);
- container->SetBoundsRect(GetContentsBounds());
-
- // Because container is a pure View, this class should layout its children.
- // TODO(mukai): arrange Google logo.
- const gfx::Rect contents_bounds = container->GetContentsBounds();
- gfx::Size mic_size = mic_button_->GetPreferredSize();
- gfx::Point mic_origin(
- contents_bounds.right() - kMicButtonMargin - mic_size.width(),
- contents_bounds.y() + kMicButtonMargin);
- mic_button_->SetBoundsRect(gfx::Rect(mic_origin, mic_size));
-
- int speech_width = contents_bounds.width() - kTextMargin * 2;
- speech_result_->SizeToFit(speech_width);
- int speech_height = speech_result_->GetHeightForWidth(speech_width);
- speech_result_->SetBounds(
- contents_bounds.x() + kTextMargin,
- contents_bounds.bottom() - kTextMargin - speech_height,
- speech_width,
- speech_height);
-}
-
-gfx::Size SpeechView::GetPreferredSize() {
- return gfx::Size(0, kSpeechViewMaxHeight);
-}
-
-void SpeechView::ButtonPressed(views::Button* sender, const ui::Event& event) {
- delegate_->ToggleSpeechRecognition();
-}
-
-void SpeechView::OnSpeechSoundLevelChanged(int16 level) {
- if (!visible())
- return;
-
- gfx::Point origin = mic_button_->bounds().CenterPoint();
- int radius = GetIndicatorRadius(level);
- origin.Offset(-radius, -radius);
- gfx::Rect indicator_bounds =
- gfx::Rect(origin, gfx::Size(radius * 2, radius * 2));
- if (indicator_->visible()) {
- indicator_animator_->AnimateViewTo(indicator_, indicator_bounds);
- } else {
- indicator_->SetVisible(true);
- indicator_->SetBoundsRect(indicator_bounds);
- }
-}
-
-void SpeechView::OnSpeechResult(const base::string16& result,
- bool is_final) {
- speech_result_->SetText(result);
- speech_result_->SetEnabledColor(kResultTextColor);
-}
-
-void SpeechView::OnSpeechRecognitionStateChanged(
- SpeechRecognitionState new_state) {
- int resource_id = IDR_APP_LIST_SPEECH_MIC_OFF;
- if (new_state == SPEECH_RECOGNITION_ON)
- resource_id = IDR_APP_LIST_SPEECH_MIC_ON;
- else if (new_state == SPEECH_RECOGNITION_IN_SPEECH)
- resource_id = IDR_APP_LIST_SPEECH_MIC_RECORDING;
-
- ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
- mic_button_->SetImage(views::Button::STATE_NORMAL, bundle.GetImageSkiaNamed(
- resource_id));
-}
-
-} // namespace app_list
diff --git a/chromium/ui/app_list/views/speech_view.h b/chromium/ui/app_list/views/speech_view.h
deleted file mode 100644
index 18644daa828..00000000000
--- a/chromium/ui/app_list/views/speech_view.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
-#define UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
-
-#include "ui/app_list/speech_ui_model_observer.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace views {
-class BoundsAnimator;
-class ImageButton;
-class Label;
-}
-
-namespace app_list {
-
-class AppListViewDelegate;
-class SpeechCardView;
-
-// SpeechView provides the card-like UI for the search-by-speech.
-class SpeechView : public views::View,
- public views::ButtonListener,
- public SpeechUIModelObserver {
- public:
- explicit SpeechView(AppListViewDelegate* delegate);
- virtual ~SpeechView();
-
- // Reset to the original state.
- void Reset();
-
- // Overridden from views::View:
- virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
-
- private:
- int GetIndicatorRadius(int16 level);
-
- // Overridden from views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from SpeechUIModelObserver:
- virtual void OnSpeechSoundLevelChanged(int16 level) OVERRIDE;
- virtual void OnSpeechResult(const base::string16& result,
- bool is_final) OVERRIDE;
- virtual void OnSpeechRecognitionStateChanged(
- SpeechRecognitionState new_state) OVERRIDE;
-
- AppListViewDelegate* delegate_;
-
- views::View* indicator_;
- views::ImageButton* mic_button_;
- views::Label* speech_result_;
- scoped_ptr<views::BoundsAnimator> indicator_animator_;
-
- DISALLOW_COPY_AND_ASSIGN(SpeechView);
-};
-
-} // namespace app_list
-
-#endif // UI_APP_LIST_VIEWS_SPEECH_VIEW_H_
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn
new file mode 100644
index 00000000000..5f177e979a9
--- /dev/null
+++ b/chromium/ui/aura/BUILD.gn
@@ -0,0 +1,303 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import ("//build/config/ui.gni")
+
+component("aura") {
+ sources = [
+ "client/aura_constants.cc",
+ "client/aura_constants.h",
+ "client/capture_client.cc",
+ "client/capture_client.h",
+ "client/capture_delegate.h",
+ "client/cursor_client.cc",
+ "client/cursor_client.h",
+ "client/cursor_client_observer.h",
+ "client/cursor_client_observer.cc",
+ "client/default_capture_client.cc",
+ "client/default_capture_client.h",
+ "client/event_client.cc",
+ "client/event_client.h",
+ "client/focus_change_observer.cc",
+ "client/focus_change_observer.h",
+ "client/focus_client.cc",
+ "client/focus_client.h",
+ "client/screen_position_client.cc",
+ "client/screen_position_client.h",
+ "client/visibility_client.cc",
+ "client/visibility_client.h",
+ "client/window_stacking_client.cc",
+ "client/window_stacking_client.h",
+ "client/window_tree_client.cc",
+ "client/window_tree_client.h",
+ "env.cc",
+ "env.h",
+ "env_observer.h",
+ "input_state_lookup.cc",
+ "input_state_lookup.h",
+ "input_state_lookup_win.cc",
+ "input_state_lookup_win.h",
+ "layout_manager.cc",
+ "layout_manager.h",
+ "remote_window_tree_host_win.cc",
+ "remote_window_tree_host_win.h",
+ "scoped_window_targeter.cc",
+ "scoped_window_targeter.h",
+ "window.cc",
+ "window.h",
+ "window_event_dispatcher.cc",
+ "window_event_dispatcher.h",
+ "window_delegate.h",
+ "window_layer_type.h",
+ "window_observer.h",
+ "window_targeter.cc",
+ "window_targeter.h",
+ "window_tracker.cc",
+ "window_tracker.h",
+ "window_tree_host.cc",
+ "window_tree_host.h",
+ "window_tree_host_mac.mm",
+ "window_tree_host_mac.h",
+ "window_tree_host_observer.h",
+ "window_tree_host_win.cc",
+ "window_tree_host_win.h",
+ "window_tree_host_x11.cc",
+ "window_tree_host_x11.h",
+ "../wm/public/activation_change_observer.h",
+ "../wm/public/activation_change_observer.cc",
+ "../wm/public/activation_client.cc",
+ "../wm/public/activation_client.h",
+ "../wm/public/activation_delegate.cc",
+ "../wm/public/activation_delegate.h",
+ "../wm/public/animation_host.cc",
+ "../wm/public/animation_host.h",
+ "../wm/public/dispatcher_client.cc",
+ "../wm/public/dispatcher_client.h",
+ "../wm/public/drag_drop_client.cc",
+ "../wm/public/drag_drop_client.h",
+ "../wm/public/drag_drop_delegate.cc",
+ "../wm/public/drag_drop_delegate.h",
+ "../wm/public/scoped_tooltip_disabler.cc",
+ "../wm/public/scoped_tooltip_disabler.h",
+ "../wm/public/tooltip_client.cc",
+ "../wm/public/tooltip_client.h",
+ "../wm/public/transient_window_client.cc",
+ "../wm/public/transient_window_client.h",
+ "../wm/public/window_move_client.cc",
+ "../wm/public/window_move_client.h",
+ ]
+
+ defines = [
+ "AURA_IMPLEMENTATION",
+ ]
+
+ deps = [
+ "//base",
+ "//base:i18n",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/base",
+ "//ui/compositor",
+ "//ui/events",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ if (use_x11) {
+ configs += [
+ "//build/config/linux:x11",
+ "//build/config/linux:xrandr",
+ ]
+ deps += [
+ "//ui/events/platform/x11",
+ ]
+ }
+
+ if (is_win) {
+ sources -= [
+ "input_state_lookup.cc",
+ ]
+
+ deps += [
+ "//ui/metro_viewer",
+ "//ipc",
+ ]
+ }
+
+ if (use_ozone) {
+ sources += [
+ "window_tree_host_ozone.cc",
+ "window_tree_host_ozone.h",
+ ]
+
+ # TODO(GYP) enable when these targets exist.
+ #deps += [
+ # "//ui/events/ozone",
+ # "//ui/ozone",
+ #]
+ }
+}
+
+source_set("aura_test_support") {
+ sources = [
+ "test/aura_test_base.cc",
+ "test/aura_test_base.h",
+ "test/aura_test_helper.cc",
+ "test/aura_test_helper.h",
+ "test/aura_test_utils.cc",
+ "test/aura_test_utils.h",
+ "test/env_test_helper.h",
+ "test/event_generator.cc",
+ "test/event_generator.h",
+ "test/test_cursor_client.cc",
+ "test/test_cursor_client.h",
+ "test/test_focus_client.cc",
+ "test/test_focus_client.h",
+ "test/test_screen.cc",
+ "test/test_screen.h",
+ "test/test_window_tree_client.cc",
+ "test/test_window_tree_client.h",
+ "test/test_windows.cc",
+ "test/test_windows.h",
+ "test/test_window_delegate.cc",
+ "test/test_window_delegate.h",
+ "test/ui_controls_factory_aura.h",
+ "test/window_test_api.cc",
+ "test/window_test_api.h",
+ ]
+
+ deps = [
+ ":aura",
+ "//skia",
+ "//testing/gtest",
+ "//ui/base",
+ "//ui/base:ui_base_test_support",
+ "//ui/compositor:test_support",
+ "//ui/events",
+ "//ui/events:events_base",
+ "//ui/events:events_test_support",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ if (is_win) {
+ cflags = [
+ "/wd4267", # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ ]
+ }
+
+ if (use_aura) {
+ if (is_win) {
+ sources += [
+ "test/ui_controls_factory_aurawin.cc",
+ ]
+ }
+
+ if (use_x11) {
+ sources += [
+ "test/ui_controls_factory_aurax11.cc",
+ ]
+ }
+ }
+}
+
+#TODO(GYP): Enable this when everything it depends links.
+#executable("aura_demo") {
+# sources = [
+# "demo/demo_main.cc",
+# ]
+#
+# deps = [
+# ":aura",
+# ":aura_test_support",
+# "//base",
+# "//base:i18n",
+# "//skia",
+# "//third_party/icu",
+# "//ui/base",
+# "//ui/compositor",
+# "//ui/compositor:test_support",
+# "//ui/events",
+# "//ui/gfx",
+# "//ui/gfx/geometry",
+# ]
+#
+# if (use_x11) {
+# deps += [
+# "//ui/gfx/x",
+# ]
+# }
+#}
+
+#TODO(GYP): Enable this when everything it depends links.
+#executable("aura_bench") {
+# sources = [
+# "bench/bench_main.cc",
+# ]
+#
+# deps = [
+# ":aura",
+# ":aura_test_support",
+# "//base",
+# "//base:i18n",
+# "//cc",
+# "//skia",
+# "//third_party/icu",
+# "//ui/base",
+# "//ui/compositor",
+# "//ui/compositor:test_support",
+# "//ui/events",
+# "//ui/gfx",
+# "//ui/gfx/geometry",
+# ]
+#
+# if (use_x11) {
+# deps += [
+# "//ui/gfx/x",
+# ]
+# }
+#}
+
+#TODO(GYP): Enable this when everything it depends links.
+#test("aura_unittests") {
+# sources = [
+# "gestures/gesture_recognizer_unittest.cc",
+# "test/run_all_unittests.cc",
+# "window_event_dispatcher_unittest.cc",
+# "window_targeter_unittest.cc",
+# "window_unittest.cc",
+# ]
+#
+# deps = [
+# ":aura",
+# ":aura_test_support",
+# "//base/test:test_support",
+# "//skia",
+# "//testing/gtest",
+# "//ui/base",
+# "//ui/base:ui_base_test_support",
+# "//ui/compositor",
+# "//ui/compositor:test_support",
+# "//ui/events",
+# "//ui/events:events_base",
+# "//ui/events:gesture_detection",
+# "//ui/gfx",
+# "//ui/gfx/geometry",
+# "//ui/gl",
+# ]
+#
+# if (is_linux) {
+# deps += [
+# #"<(DEPTH)/third_party/mesa/mesa.gyp:osmesa",
+# ]
+# }
+#
+# if (is_linux) { # && use_allocator != "none") {
+# deps += [
+# # See http://crbug.com/162998#c4 for why this is needed.
+# "//base/allocator",
+# ]
+# }
+#}
diff --git a/chromium/ui/aura/DEPS b/chromium/ui/aura/DEPS
index c2522180289..f8d111d6eab 100644
--- a/chromium/ui/aura/DEPS
+++ b/chromium/ui/aura/DEPS
@@ -1,6 +1,4 @@
include_rules = [
- "+grit/ui_resources.h",
- "+grit/ui_strings.h",
"+skia/ext",
"+third_party/skia",
"+ui/base",
@@ -10,5 +8,6 @@ include_rules = [
"+ui/metro_viewer", # TODO(beng): investigate moving remote_root_window_host
# to ui/metro_viewer.
"+ui/ozone",
+ "+ui/wm/public",
]
diff --git a/chromium/ui/aura/aura.gyp b/chromium/ui/aura/aura.gyp
index 68164d4321a..56ef7987b44 100644
--- a/chromium/ui/aura/aura.gyp
+++ b/chromium/ui/aura/aura.gyp
@@ -14,28 +14,19 @@
'../../base/base.gyp:base',
'../../base/base.gyp:base_i18n',
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../../cc/cc.gyp:cc',
- '../../gpu/gpu.gyp:gpu',
'../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../events/events.gyp:events',
'../events/events.gyp:events_base',
+ '../events/platform/events_platform.gyp:events_platform',
'../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
],
'defines': [
'AURA_IMPLEMENTATION',
],
'sources': [
- 'client/activation_change_observer.h',
- 'client/activation_change_observer.cc',
- 'client/activation_client.cc',
- 'client/activation_client.h',
- 'client/activation_delegate.cc',
- 'client/activation_delegate.h',
- 'client/animation_host.cc',
- 'client/animation_host.h',
'client/aura_constants.cc',
'client/aura_constants.h',
'client/capture_client.cc',
@@ -45,16 +36,8 @@
'client/cursor_client.h',
'client/cursor_client_observer.h',
'client/cursor_client_observer.cc',
- 'client/default_activation_client.cc',
- 'client/default_activation_client.h',
'client/default_capture_client.cc',
'client/default_capture_client.h',
- 'client/dispatcher_client.cc',
- 'client/dispatcher_client.h',
- 'client/drag_drop_client.cc',
- 'client/drag_drop_client.h',
- 'client/drag_drop_delegate.cc',
- 'client/drag_drop_delegate.h',
'client/event_client.cc',
'client/event_client.h',
'client/focus_change_observer.cc',
@@ -63,22 +46,12 @@
'client/focus_client.h',
'client/screen_position_client.cc',
'client/screen_position_client.h',
- 'client/tooltip_client.cc',
- 'client/tooltip_client.h',
- 'client/user_action_client.cc',
- 'client/user_action_client.h',
'client/visibility_client.cc',
'client/visibility_client.h',
- 'client/window_move_client.cc',
- 'client/window_move_client.h',
'client/window_stacking_client.cc',
'client/window_stacking_client.h',
'client/window_tree_client.cc',
'client/window_tree_client.h',
- 'client/window_types.h',
- 'device_list_updater_aurax11.cc',
- 'device_list_updater_aurax11.h',
- 'dispatcher_win.cc',
'env.cc',
'env.h',
'env_observer.h',
@@ -88,40 +61,64 @@
'input_state_lookup_win.h',
'layout_manager.cc',
'layout_manager.h',
- 'remote_root_window_host_win.cc',
- 'remote_root_window_host_win.h',
- 'root_window_host_ozone.cc',
- 'root_window_host_ozone.h',
- 'root_window_host_win.cc',
- 'root_window_host_win.h',
- 'root_window_host_x11.cc',
- 'root_window_host_x11.h',
- 'root_window_transformer.h',
- 'root_window.cc',
- 'root_window.h',
+ 'remote_window_tree_host_win.cc',
+ 'remote_window_tree_host_win.h',
+ 'scoped_window_targeter.cc',
+ 'scoped_window_targeter.h',
'window.cc',
'window.h',
- 'window_targeter.cc',
- 'window_targeter.h',
+ 'window_event_dispatcher.cc',
+ 'window_event_dispatcher.h',
'window_delegate.h',
'window_layer_type.h',
+ 'window_observer.cc',
'window_observer.h',
+ 'window_targeter.cc',
+ 'window_targeter.h',
'window_tracker.cc',
'window_tracker.h',
'window_tree_host.cc',
'window_tree_host.h',
- 'window_tree_host_delegate.h',
+ 'window_tree_host_mac.mm',
+ 'window_tree_host_mac.h',
+ 'window_tree_host_observer.h',
+ 'window_tree_host_ozone.cc',
+ 'window_tree_host_ozone.h',
+ 'window_tree_host_win.cc',
+ 'window_tree_host_win.h',
+ 'window_tree_host_x11.cc',
+ 'window_tree_host_x11.h',
+ '../wm/public/activation_change_observer.h',
+ '../wm/public/activation_change_observer.cc',
+ '../wm/public/activation_client.cc',
+ '../wm/public/activation_client.h',
+ '../wm/public/activation_delegate.cc',
+ '../wm/public/activation_delegate.h',
+ '../wm/public/animation_host.cc',
+ '../wm/public/animation_host.h',
+ '../wm/public/dispatcher_client.cc',
+ '../wm/public/dispatcher_client.h',
+ '../wm/public/drag_drop_client.cc',
+ '../wm/public/drag_drop_client.h',
+ '../wm/public/drag_drop_delegate.cc',
+ '../wm/public/drag_drop_delegate.h',
+ '../wm/public/scoped_tooltip_disabler.cc',
+ '../wm/public/scoped_tooltip_disabler.h',
+ '../wm/public/tooltip_client.cc',
+ '../wm/public/tooltip_client.h',
+ '../wm/public/transient_window_client.cc',
+ '../wm/public/transient_window_client.h',
+ '../wm/public/window_move_client.cc',
+ '../wm/public/window_move_client.h',
],
'conditions': [
['use_x11==1', {
- 'link_settings': {
- 'libraries': [
- '-lX11',
- '-lXi',
- '-lXfixes',
- '-lXrandr',
- ],
- },
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:xrandr',
+ '../../build/linux/system.gyp:xi',
+ '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
+ ],
}],
['OS=="win"', {
'dependencies': [
@@ -134,6 +131,7 @@
}],
['use_ozone==1', {
'dependencies': [
+ '../events/ozone/events_ozone.gyp:events_ozone',
'../ozone/ozone.gyp:ozone',
],
}],
@@ -145,13 +143,14 @@
'dependencies': [
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
+ '../base/ui_base.gyp:ui_base',
+ '../base/ui_base.gyp:ui_base_test_support',
'../compositor/compositor.gyp:compositor_test_support',
'../events/events.gyp:events',
'../events/events.gyp:events_base',
'../events/events.gyp:events_test_support',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:ui_test_support',
+ '../gfx/gfx.gyp:gfx_geometry',
'aura',
],
'include_dirs': [
@@ -162,13 +161,13 @@
'test/aura_test_base.h',
'test/aura_test_helper.cc',
'test/aura_test_helper.h',
+ 'test/aura_test_utils.cc',
+ 'test/aura_test_utils.h',
'test/env_test_helper.h',
'test/event_generator.cc',
'test/event_generator.h',
'test/test_cursor_client.cc',
'test/test_cursor_client.h',
- 'test/test_event_handler.cc',
- 'test/test_event_handler.h',
'test/test_focus_client.cc',
'test/test_focus_client.h',
'test/test_screen.cc',
@@ -197,12 +196,12 @@
'../../skia/skia.gyp:skia',
'../../third_party/icu/icu.gyp:icui18n',
'../../third_party/icu/icu.gyp:icuuc',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../compositor/compositor.gyp:compositor_test_support',
'../events/events.gyp:events',
'../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
'aura',
'aura_test_support',
],
@@ -212,6 +211,13 @@
'sources': [
'demo/demo_main.cc',
],
+ 'conditions': [
+ ['use_x11==1', {
+ 'dependencies': [
+ '../gfx/x/gfx_x11.gyp:gfx_x11',
+ ],
+ }],
+ ]
},
{
'target_name': 'aura_bench',
@@ -219,15 +225,17 @@
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:base_i18n',
+ '../../cc/cc.gyp:cc',
+ '../../gpu/gpu.gyp:gles2_implementation',
'../../skia/skia.gyp:skia',
'../../third_party/icu/icu.gyp:icui18n',
'../../third_party/icu/icu.gyp:icuuc',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../compositor/compositor.gyp:compositor_test_support',
'../events/events.gyp:events',
'../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
'aura',
'aura_test_support',
],
@@ -237,24 +245,31 @@
'sources': [
'bench/bench_main.cc',
],
+ 'conditions': [
+ ['use_x11==1', {
+ 'dependencies': [
+ '../gfx/x/gfx_x11.gyp:gfx_x11',
+ ],
+ }],
+ ]
},
{
'target_name': 'aura_unittests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:test_support_base',
- '../../chrome/chrome_resources.gyp:packed_resources',
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
+ '../base/ui_base.gyp:ui_base',
+ '../base/ui_base.gyp:ui_base_test_support',
'../compositor/compositor.gyp:compositor',
'../compositor/compositor.gyp:compositor_test_support',
'../events/events.gyp:events',
'../events/events.gyp:events_base',
+ '../events/events.gyp:gesture_detection',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../gl/gl.gyp:gl',
- '../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:ui_test_support',
'aura_test_support',
'aura',
],
@@ -263,11 +278,8 @@
],
'sources': [
'gestures/gesture_recognizer_unittest.cc',
- 'root_window_host_x11_unittest.cc',
- 'root_window_unittest.cc',
+ 'window_event_dispatcher_unittest.cc',
'test/run_all_unittests.cc',
- 'test/test_suite.cc',
- 'test/test_suite.h',
'window_targeter_unittest.cc',
'window_unittest.cc',
],
@@ -278,7 +290,7 @@
'<(DEPTH)/third_party/mesa/mesa.gyp:osmesa',
],
}],
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
# See http://crbug.com/162998#c4 for why this is needed.
'../../base/allocator/allocator.gyp:allocator',
diff --git a/chromium/ui/aura/aura_export.h b/chromium/ui/aura/aura_export.h
index 9db662bbf7e..1093040a0c1 100644
--- a/chromium/ui/aura/aura_export.h
+++ b/chromium/ui/aura/aura_export.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_AURA_AURA_EXPORT_H
-#define UI_AURA_AURA_EXPORT_H
+#ifndef UI_AURA_AURA_EXPORT_H_
+#define UI_AURA_AURA_EXPORT_H_
// Defines AURA_EXPORT so that functionality implemented by the aura module
// can be exported to consumers.
@@ -29,4 +29,4 @@
#define AURA_EXPORT
#endif
-#endif // UI_AURA_AURA_EXPORT_H
+#endif // UI_AURA_AURA_EXPORT_H_
diff --git a/chromium/ui/aura/bench/DEPS b/chromium/ui/aura/bench/DEPS
index 70bd71ca290..7fa58f955ec 100644
--- a/chromium/ui/aura/bench/DEPS
+++ b/chromium/ui/aura/bench/DEPS
@@ -1,5 +1,7 @@
include_rules = [
"+cc",
+ "-cc/surfaces",
"+gpu/command_buffer/client/gles2_interface.h",
"+third_party/khronos",
+ "+ui/gl/gl_surface.h", # To initialize GL bindings.
]
diff --git a/chromium/ui/aura/bench/bench_main.cc b/chromium/ui/aura/bench/bench_main.cc
index 3f6717c80ce..b5dd3e75d3d 100644
--- a/chromium/ui/aura/bench/bench_main.cc
+++ b/chromium/ui/aura/bench/bench_main.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#endif
+
#include "base/at_exit.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -16,35 +20,31 @@
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/test_focus_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/debug_utils.h"
#include "ui/compositor/layer.h"
-#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/x/x11_connection.h"
+#include "ui/gl/gl_surface.h"
+
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES 1
#endif
#include "third_party/khronos/GLES2/gl2ext.h"
-#if defined(USE_X11)
-#include "base/message_loop/message_pump_x11.h"
-#endif
-
using base::TimeTicks;
using ui::Compositor;
using ui::Layer;
using ui::LayerDelegate;
-using blink::WebGraphicsContext3D;
namespace {
@@ -123,11 +123,6 @@ class BenchCompositorObserver : public ui::CompositorObserver {
virtual void OnCompositingLockStateChanged(
Compositor* compositor) OVERRIDE {}
- virtual void OnUpdateVSyncParameters(ui::Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE {
- }
-
virtual void Draw() {}
int frames() const { return frames_; }
@@ -140,46 +135,27 @@ class BenchCompositorObserver : public ui::CompositorObserver {
DISALLOW_COPY_AND_ASSIGN(BenchCompositorObserver);
};
-class WebGLTexture : public ui::Texture {
- public:
- WebGLTexture(gpu::gles2::GLES2Interface* gl, const gfx::Size& size)
- : ui::Texture(false, size, 1.0f),
- gl_(gl),
- texture_id_(0u) {
- gl->GenTextures(1, &texture_id_);
- gl->BindTexture(GL_TEXTURE_2D, texture_id_);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(),
- 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- }
-
- virtual unsigned int PrepareTexture() OVERRIDE {
- return texture_id_;
- }
-
- private:
- virtual ~WebGLTexture() {
- gl_->DeleteTextures(1, &texture_id_);
- }
-
- gpu::gles2::GLES2Interface* gl_;
- GLuint texture_id_;
-
- DISALLOW_COPY_AND_ASSIGN(WebGLTexture);
-};
+void ReturnMailbox(scoped_refptr<cc::ContextProvider> context_provider,
+ GLuint texture,
+ GLuint sync_point,
+ bool is_lost) {
+ gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
+ gl->WaitSyncPointCHROMIUM(sync_point);
+ gl->DeleteTextures(1, &texture);
+ gl->ShallowFlushCHROMIUM();
+}
// A benchmark that adds a texture layer that is updated every frame.
class WebGLBench : public BenchCompositorObserver {
public:
- WebGLBench(Layer* parent, Compositor* compositor, int max_frames)
+ WebGLBench(ui::ContextFactory* context_factory,
+ Layer* parent,
+ Compositor* compositor,
+ int max_frames)
: BenchCompositorObserver(max_frames),
parent_(parent),
webgl_(ui::LAYER_TEXTURED),
compositor_(compositor),
- texture_(),
fbo_(0),
do_draw_(true) {
CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -204,26 +180,49 @@ class WebGLBench : public BenchCompositorObserver {
webgl_.SetBounds(bounds);
parent_->Add(&webgl_);
- context_provider_ =
- ui::ContextFactory::GetInstance()->SharedMainThreadContextProvider();
+ context_provider_ = context_factory->SharedMainThreadContextProvider();
gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- texture_ = new WebGLTexture(gl, bounds.size());
+ GLuint texture = 0;
+ gl->GenTextures(1, &texture);
+ gl->BindTexture(GL_TEXTURE_2D, texture);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl->TexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ width,
+ height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
+ gpu::Mailbox mailbox;
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+
gl->GenFramebuffers(1, &fbo_);
- compositor->AddObserver(this);
- webgl_.SetExternalTexture(texture_.get());
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
gl->FramebufferTexture2D(
- GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture_->PrepareTexture(), 0);
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
gl->ClearColor(0.f, 1.f, 0.f, 1.f);
gl->Clear(GL_COLOR_BUFFER_BIT);
gl->Flush();
+
+ GLuint sync_point = gl->InsertSyncPointCHROMIUM();
+ webgl_.SetTextureMailbox(
+ cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
+ cc::SingleReleaseCallback::Create(
+ base::Bind(ReturnMailbox, context_provider_, texture)),
+ bounds.size());
+ compositor->AddObserver(this);
}
virtual ~WebGLBench() {
- context_provider_->ContextGL()->DeleteFramebuffers(1, &fbo_);
webgl_.SetShowPaintedContent();
- texture_ = NULL;
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->DeleteFramebuffers(1, &fbo_);
compositor_->RemoveObserver(this);
}
@@ -234,7 +233,6 @@ class WebGLBench : public BenchCompositorObserver {
gl->Clear(GL_COLOR_BUFFER_BIT);
gl->Flush();
}
- webgl_.SetExternalTexture(texture_.get());
webgl_.SchedulePaint(gfx::Rect(webgl_.bounds().size()));
compositor_->ScheduleDraw();
}
@@ -244,7 +242,6 @@ class WebGLBench : public BenchCompositorObserver {
Layer webgl_;
Compositor* compositor_;
scoped_refptr<cc::ContextProvider> context_provider_;
- scoped_refptr<WebGLTexture> texture_;
// The FBO that is used to render to the texture.
unsigned int fbo_;
@@ -293,33 +290,40 @@ int main(int argc, char** argv) {
base::AtExitManager exit_manager;
+#if defined(USE_X11)
+ // This demo uses InProcessContextFactory which uses X on a separate Gpu
+ // thread.
+ gfx::InitializeThreadedX11();
+#endif
+
+ gfx::GLSurface::InitializeOneOff();
+
// The ContextFactory must exist before any Compositors are created.
- bool allow_test_contexts = false;
- ui::InitializeContextFactoryForTests(allow_test_contexts);
+ scoped_ptr<ui::InProcessContextFactory> context_factory(
+ new ui::InProcessContextFactory());
- ui::RegisterPathProvider();
base::i18n::InitializeICU();
- ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
- base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
- aura::Env::CreateInstance();
+ base::MessageLoopForUI message_loop;
+ aura::Env::CreateInstance(true);
+ aura::Env::GetInstance()->set_context_factory(context_factory.get());
scoped_ptr<aura::TestScreen> test_screen(
aura::TestScreen::CreateFullscreen());
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
- scoped_ptr<aura::RootWindow> root_window(
- test_screen->CreateRootWindowForPrimaryDisplay());
+ scoped_ptr<aura::WindowTreeHost> host(
+ test_screen->CreateHostForPrimaryDisplay());
aura::client::SetCaptureClient(
- root_window->window(),
- new aura::client::DefaultCaptureClient(root_window->window()));
+ host->window(),
+ new aura::client::DefaultCaptureClient(host->window()));
scoped_ptr<aura::client::FocusClient> focus_client(
new aura::test::TestFocusClient);
- aura::client::SetFocusClient(root_window->window(), focus_client.get());
+ aura::client::SetFocusClient(host->window(), focus_client.get());
// add layers
ColoredLayer background(SK_ColorRED);
- background.SetBounds(root_window->window()->bounds());
- root_window->window()->layer()->Add(&background);
+ background.SetBounds(host->window()->bounds());
+ host->window()->layer()->Add(&background);
ColoredLayer window(SK_ColorBLUE);
window.SetBounds(gfx::Rect(background.bounds().size()));
@@ -344,22 +348,23 @@ int main(int argc, char** argv) {
if (command_line->HasSwitch("bench-software-scroll")) {
bench.reset(new SoftwareScrollBench(&page_background,
- root_window->compositor(),
+ host->compositor(),
frames));
} else {
- bench.reset(new WebGLBench(&page_background,
- root_window->compositor(),
+ bench.reset(new WebGLBench(context_factory.get(),
+ &page_background,
+ host->compositor(),
frames));
}
#ifndef NDEBUG
- ui::PrintLayerHierarchy(root_window->window()->layer(), gfx::Point(100, 100));
+ ui::PrintLayerHierarchy(host->window()->layer(), gfx::Point(100, 100));
#endif
- root_window->host()->Show();
+ host->Show();
base::MessageLoopForUI::current()->Run();
focus_client.reset();
- root_window.reset();
+ host.reset();
return 0;
}
diff --git a/chromium/ui/aura/client/activation_change_observer.cc b/chromium/ui/aura/client/activation_change_observer.cc
deleted file mode 100644
index db9f332cfae..00000000000
--- a/chromium/ui/aura/client/activation_change_observer.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/activation_change_observer.h"
-
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationChangeObserver*)
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- ActivationChangeObserver*, kActivationChangeObserverKey, NULL);
-
-void SetActivationChangeObserver(
- Window* window,
- ActivationChangeObserver* observer) {
- window->SetProperty(kActivationChangeObserverKey, observer);
-}
-
-ActivationChangeObserver* GetActivationChangeObserver(Window* window) {
- return window ? window->GetProperty(kActivationChangeObserverKey) : NULL;
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/activation_change_observer.h b/chromium/ui/aura/client/activation_change_observer.h
deleted file mode 100644
index 2f247db04b3..00000000000
--- a/chromium/ui/aura/client/activation_change_observer.h
+++ /dev/null
@@ -1,45 +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_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_
-#define UI_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace aura {
-class Window;
-
-namespace client {
-
-class AURA_EXPORT ActivationChangeObserver {
- public:
- // Called when |active| gains focus, or there is no active window
- // (|active| is NULL in this case.) |old_active| refers to the
- // previous active window or NULL if there was no previously active
- // window.
- virtual void OnWindowActivated(Window* gained_active,
- Window* lost_active) = 0;
-
- // Called when during window activation the currently active window is
- // selected for activation. This can happen when a window requested for
- // activation cannot be activated because a system modal window is active.
- virtual void OnAttemptToReactivateWindow(aura::Window* request_active,
- aura::Window* actual_active) {}
-
- protected:
- virtual ~ActivationChangeObserver() {}
-};
-
-// Gets/Sets the ActivationChangeObserver for a specific window. This observer
-// is notified after the ActivationClient notifies all registered observers.
-AURA_EXPORT void SetActivationChangeObserver(
- Window* window,
- ActivationChangeObserver* observer);
-AURA_EXPORT ActivationChangeObserver* GetActivationChangeObserver(
- Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_
diff --git a/chromium/ui/aura/client/activation_client.cc b/chromium/ui/aura/client/activation_client.cc
deleted file mode 100644
index b4633aec5ab..00000000000
--- a/chromium/ui/aura/client/activation_client.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/activation_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, aura::Window*)
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationClient*)
-
-namespace aura {
-namespace client {
-
-DEFINE_WINDOW_PROPERTY_KEY(
- ActivationClient*, kRootWindowActivationClientKey, NULL);
-DEFINE_WINDOW_PROPERTY_KEY(bool, kHideOnDeactivate, false);
-
-void SetActivationClient(Window* root_window, ActivationClient* client) {
- root_window->SetProperty(kRootWindowActivationClientKey, client);
-}
-
-ActivationClient* GetActivationClient(Window* root_window) {
- return root_window ?
- root_window->GetProperty(kRootWindowActivationClientKey) : NULL;
-}
-
-void SetHideOnDeactivate(Window* window, bool hide_on_deactivate) {
- window->SetProperty(kHideOnDeactivate, hide_on_deactivate);
-}
-
-bool GetHideOnDeactivate(Window* window) {
- return window->GetProperty(kHideOnDeactivate);
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/activation_client.h b/chromium/ui/aura/client/activation_client.h
deleted file mode 100644
index 054829ec2aa..00000000000
--- a/chromium/ui/aura/client/activation_client.h
+++ /dev/null
@@ -1,77 +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_AURA_CLIENT_ACTIVATION_CLIENT_H_
-#define UI_AURA_CLIENT_ACTIVATION_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace ui {
-class Event;
-}
-
-namespace aura {
-class Window;
-
-namespace client {
-class ActivationChangeObserver;
-
-// An interface implemented by an object that manages window activation.
-class AURA_EXPORT ActivationClient {
- public:
- // Adds/Removes ActivationChangeObservers.
- virtual void AddObserver(ActivationChangeObserver* observer) = 0;
- virtual void RemoveObserver(ActivationChangeObserver* observer) = 0;
-
- // Activates |window|. If |window| is NULL, nothing happens.
- virtual void ActivateWindow(Window* window) = 0;
-
- // Deactivates |window|. What (if anything) is activated next is up to the
- // client. If |window| is NULL, nothing happens.
- virtual void DeactivateWindow(Window* window) = 0;
-
- // Retrieves the active window, or NULL if there is none.
- virtual Window* GetActiveWindow() = 0;
-
- // Retrieves the activatable window for |window|, or NULL if there is none.
- // Note that this is often but not always the toplevel window (see
- // GetToplevelWindow() below), as the toplevel window may not be activatable
- // (for example it may be blocked by a modal transient, or some other
- // condition).
- virtual Window* GetActivatableWindow(Window* window) = 0;
-
- // Retrieves the toplevel window for |window|, or NULL if there is none.
- virtual Window* GetToplevelWindow(Window* window) = 0;
-
- // Invoked prior to |window| getting focus as a result of the |event|. |event|
- // may be NULL. Returning false blocks |window| from getting focus.
- virtual bool OnWillFocusWindow(Window* window, const ui::Event* event) = 0;
-
- // Returns true if |window| can be activated, false otherwise. If |window| has
- // a modal child it can not be activated.
- virtual bool CanActivateWindow(Window* window) const = 0;
-
- protected:
- virtual ~ActivationClient() {}
-};
-
-// Sets/Gets the activation client on the root Window.
-AURA_EXPORT void SetActivationClient(Window* root_window,
- ActivationClient* client);
-AURA_EXPORT ActivationClient* GetActivationClient(Window* root_window);
-
-// Some types of transient window are only visible when active.
-// The transient parents of these windows may have visual appearance properties
-// that differ from transient parents that can be deactivated.
-// The presence of this property implies these traits.
-// TODO(beng): currently the UI framework (views) implements the actual
-// close-on-deactivate component of this feature but it should be
-// possible to implement in the aura client.
-AURA_EXPORT void SetHideOnDeactivate(Window* window, bool hide_on_deactivate);
-AURA_EXPORT bool GetHideOnDeactivate(Window* window);
-
-} // namespace clients
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_ACTIVATION_CLIENT_H_
diff --git a/chromium/ui/aura/client/activation_delegate.cc b/chromium/ui/aura/client/activation_delegate.cc
deleted file mode 100644
index 51b22b00a61..00000000000
--- a/chromium/ui/aura/client/activation_delegate.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/activation_delegate.h"
-
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationDelegate*)
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- ActivationDelegate*, kActivationDelegateKey, NULL);
-
-void SetActivationDelegate(Window* window, ActivationDelegate* delegate) {
- window->SetProperty(kActivationDelegateKey, delegate);
-}
-
-ActivationDelegate* GetActivationDelegate(Window* window) {
- return window->GetProperty(kActivationDelegateKey);
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/activation_delegate.h b/chromium/ui/aura/client/activation_delegate.h
deleted file mode 100644
index 0ce86388f52..00000000000
--- a/chromium/ui/aura/client/activation_delegate.h
+++ /dev/null
@@ -1,37 +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_AURA_CLIENT_ACTIVATION_DELEGATE_H_
-#define UI_AURA_CLIENT_ACTIVATION_DELEGATE_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace ui {
-class Event;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-// An interface implemented by an object that configures and responds to changes
-// to a window's activation state.
-class AURA_EXPORT ActivationDelegate {
- public:
- // Returns true if the window should be activated.
- virtual bool ShouldActivate() const = 0;
-
- protected:
- virtual ~ActivationDelegate() {}
-};
-
-// Sets/Gets the ActivationDelegate on the Window. No ownership changes.
-AURA_EXPORT void SetActivationDelegate(Window* window,
- ActivationDelegate* delegate);
-AURA_EXPORT ActivationDelegate* GetActivationDelegate(Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_ACTIVATION_DELEGATE_H_
diff --git a/chromium/ui/aura/client/animation_host.cc b/chromium/ui/aura/client/animation_host.cc
deleted file mode 100644
index 5df22babc62..00000000000
--- a/chromium/ui/aura/client/animation_host.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/animation_host.h"
-
-#include "base/compiler_specific.h"
-#include "ui/aura/aura_export.h"
-
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::AnimationHost*)
-
-namespace aura {
-namespace client {
-
-DEFINE_WINDOW_PROPERTY_KEY(AnimationHost*, kRootWindowAnimationHostKey, NULL);
-
-void SetAnimationHost(Window* window, AnimationHost* animation_host) {
- DCHECK(window);
- window->SetProperty(kRootWindowAnimationHostKey, animation_host);
-}
-
-AnimationHost* GetAnimationHost(Window* window) {
- DCHECK(window);
- return window->GetProperty(kRootWindowAnimationHostKey);
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/animation_host.h b/chromium/ui/aura/client/animation_host.h
deleted file mode 100644
index c433b6d63dc..00000000000
--- a/chromium/ui/aura/client/animation_host.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_AURA_CLIENT_ANIMATION_HOST_H_
-#define UI_AURA_CLIENT_ANIMATION_HOST_H_
-
-#include "base/compiler_specific.h"
-#include "ui/aura/aura_export.h"
-
-namespace gfx {
-class Vector2d;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-// Interface for top level window host of animation. Communicates additional
-// bounds required for animation as well as animation completion for deferring
-// window closes on hide.
-class AURA_EXPORT AnimationHost {
- public:
- // Ensure the host window is at least this large so that transitions have
- // sufficient space.
- // The |top_left_delta| parameter contains the offset to be subtracted from
- // the window bounds for the top left corner.
- // The |bottom_right_delta| parameter contains the offset to be added to the
- // window bounds for the bottom right.
- virtual void SetHostTransitionOffsets(
- const gfx::Vector2d& top_left_delta,
- const gfx::Vector2d& bottom_right_delta) = 0;
-
- // Called after the window has faded out on a hide.
- virtual void OnWindowHidingAnimationCompleted() = 0;
-
- protected:
- virtual ~AnimationHost() {}
-};
-
-AURA_EXPORT void SetAnimationHost(Window* window,
- AnimationHost* animation_host);
-AURA_EXPORT AnimationHost* GetAnimationHost(Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_ANIMATION_HOST_H_
diff --git a/chromium/ui/aura/client/capture_client.cc b/chromium/ui/aura/client/capture_client.cc
index cbcabd7393f..6d78c88d155 100644
--- a/chromium/ui/aura/client/capture_client.cc
+++ b/chromium/ui/aura/client/capture_client.cc
@@ -4,7 +4,7 @@
#include "ui/aura/client/capture_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_WINDOW_PROPERTY_TYPE(aura::client::CaptureClient*)
diff --git a/chromium/ui/aura/client/cursor_client.h b/chromium/ui/aura/client/cursor_client.h
index 99d9b6a1a1c..fc48e036107 100644
--- a/chromium/ui/aura/client/cursor_client.h
+++ b/chromium/ui/aura/client/cursor_client.h
@@ -14,6 +14,10 @@ namespace gfx {
class Display;
}
+namespace ui {
+class KeyEvent;
+}
+
namespace aura {
class Window;
namespace client {
@@ -35,12 +39,6 @@ class AURA_EXPORT CursorClient {
// invisible.
virtual void HideCursor() = 0;
- // Sets the scale of the mouse cursor icon.
- virtual void SetScale(float scale) = 0;
-
- // Gets the current scale of the mouse cursor icon.
- virtual float GetScale() const = 0;
-
// Sets the type of the mouse cursor icon.
virtual void SetCursorSet(ui::CursorSetType cursor_set) = 0;
@@ -80,6 +78,9 @@ class AURA_EXPORT CursorClient {
virtual void AddObserver(CursorClientObserver* observer) = 0;
virtual void RemoveObserver(CursorClientObserver* observer) = 0;
+ // Returns true if the mouse cursor should be hidden on |event|.
+ virtual bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) const = 0;
+
protected:
virtual ~CursorClient() {}
};
diff --git a/chromium/ui/aura/client/default_activation_client.cc b/chromium/ui/aura/client/default_activation_client.cc
deleted file mode 100644
index ccb660b81f4..00000000000
--- a/chromium/ui/aura/client/default_activation_client.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/default_activation_client.h"
-
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/window.h"
-
-namespace aura {
-namespace client {
-
-////////////////////////////////////////////////////////////////////////////////
-// DefaultActivationClient, public:
-
-DefaultActivationClient::DefaultActivationClient(Window* root_window)
- : last_active_(NULL) {
- client::SetActivationClient(root_window, this);
-}
-
-DefaultActivationClient::~DefaultActivationClient() {
- for (unsigned int i = 0; i < active_windows_.size(); ++i) {
- active_windows_[i]->RemoveObserver(this);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DefaultActivationClient, client::ActivationClient implementation:
-
-void DefaultActivationClient::AddObserver(
- client::ActivationChangeObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void DefaultActivationClient::RemoveObserver(
- client::ActivationChangeObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void DefaultActivationClient::ActivateWindow(Window* window) {
- Window* last_active = GetActiveWindow();
- if (last_active == window)
- return;
-
- last_active_ = last_active;
- RemoveActiveWindow(window);
- active_windows_.push_back(window);
- window->parent()->StackChildAtTop(window);
- window->AddObserver(this);
-
- FOR_EACH_OBSERVER(client::ActivationChangeObserver,
- observers_,
- OnWindowActivated(window, last_active));
-
- aura::client::ActivationChangeObserver* observer =
- aura::client::GetActivationChangeObserver(last_active);
- if (observer)
- observer->OnWindowActivated(window, last_active);
- observer = aura::client::GetActivationChangeObserver(window);
- if (observer)
- observer->OnWindowActivated(window, last_active);
-}
-
-void DefaultActivationClient::DeactivateWindow(Window* window) {
- aura::client::ActivationChangeObserver* observer =
- aura::client::GetActivationChangeObserver(window);
- if (observer)
- observer->OnWindowActivated(NULL, window);
- if (last_active_)
- ActivateWindow(last_active_);
-}
-
-Window* DefaultActivationClient::GetActiveWindow() {
- if (active_windows_.empty())
- return NULL;
- return active_windows_.back();
-}
-
-Window* DefaultActivationClient::GetActivatableWindow(Window* window) {
- return NULL;
-}
-
-Window* DefaultActivationClient::GetToplevelWindow(Window* window) {
- return NULL;
-}
-
-bool DefaultActivationClient::OnWillFocusWindow(Window* window,
- const ui::Event* event) {
- return true;
-}
-
-bool DefaultActivationClient::CanActivateWindow(Window* window) const {
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DefaultActivationClient, WindowObserver implementation:
-
-void DefaultActivationClient::OnWindowDestroyed(Window* window) {
- if (window == last_active_)
- last_active_ = NULL;
-
- if (window == GetActiveWindow()) {
- active_windows_.pop_back();
- Window* next_active = GetActiveWindow();
- if (next_active && aura::client::GetActivationChangeObserver(next_active)) {
- aura::client::GetActivationChangeObserver(next_active)->OnWindowActivated(
- next_active, NULL);
- }
- return;
- }
-
- RemoveActiveWindow(window);
-}
-
-void DefaultActivationClient::RemoveActiveWindow(Window* window) {
- for (unsigned int i = 0; i < active_windows_.size(); ++i) {
- if (active_windows_[i] == window) {
- active_windows_.erase(active_windows_.begin() + i);
- window->RemoveObserver(this);
- return;
- }
- }
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/default_activation_client.h b/chromium/ui/aura/client/default_activation_client.h
deleted file mode 100644
index 842ee909d62..00000000000
--- a/chromium/ui/aura/client/default_activation_client.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_
-#define UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/observer_list.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/window_observer.h"
-
-namespace aura {
-namespace client {
-class ActivationChangeObserver;
-}
-
-namespace client {
-
-// Simple ActivationClient implementation for use by tests and other targets
-// that just need basic behavior (e.g. activate windows whenever requested,
-// restack windows at the top when they're activated, etc.).
-class AURA_EXPORT DefaultActivationClient : public client::ActivationClient,
- public WindowObserver {
- public:
- explicit DefaultActivationClient(Window* root_window);
- virtual ~DefaultActivationClient();
-
- // Overridden from client::ActivationClient:
- virtual void AddObserver(client::ActivationChangeObserver* observer) OVERRIDE;
- virtual void RemoveObserver(
- client::ActivationChangeObserver* observer) OVERRIDE;
- virtual void ActivateWindow(Window* window) OVERRIDE;
- virtual void DeactivateWindow(Window* window) OVERRIDE;
- virtual Window* GetActiveWindow() OVERRIDE;
- virtual Window* GetActivatableWindow(Window* window) OVERRIDE;
- virtual Window* GetToplevelWindow(Window* window) OVERRIDE;
- virtual bool OnWillFocusWindow(Window* window,
- const ui::Event* event) OVERRIDE;
- virtual bool CanActivateWindow(Window* window) const OVERRIDE;
-
- // Overridden from WindowObserver:
- virtual void OnWindowDestroyed(Window* window) OVERRIDE;
-
- private:
- void RemoveActiveWindow(Window* window);
-
- // This class explicitly does NOT store the active window in a window property
- // to make sure that ActivationChangeObserver is not treated as part of the
- // aura API. Assumptions to that end will cause tests that use this client to
- // fail.
- std::vector<Window*> active_windows_;
-
- // The window which was active before the currently active one.
- Window* last_active_;
-
- ObserverList<client::ActivationChangeObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultActivationClient);
-};
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_
diff --git a/chromium/ui/aura/client/default_capture_client.cc b/chromium/ui/aura/client/default_capture_client.cc
index df6a1b09745..69632d8a5be 100644
--- a/chromium/ui/aura/client/default_capture_client.cc
+++ b/chromium/ui/aura/client/default_capture_client.cc
@@ -4,8 +4,9 @@
#include "ui/aura/client/default_capture_client.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
namespace aura {
namespace client {
@@ -31,7 +32,7 @@ void DefaultCaptureClient::SetCapture(Window* window) {
Window* old_capture_window = capture_window_;
capture_window_ = window;
- CaptureDelegate* capture_delegate = root_window_->GetDispatcher();
+ CaptureDelegate* capture_delegate = root_window_->GetHost()->dispatcher();
if (capture_window_)
capture_delegate->SetNativeCapture();
else
diff --git a/chromium/ui/aura/client/dispatcher_client.cc b/chromium/ui/aura/client/dispatcher_client.cc
deleted file mode 100644
index a9e1a7d4cd5..00000000000
--- a/chromium/ui/aura/client/dispatcher_client.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/dispatcher_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DispatcherClient*);
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(DispatcherClient*, kDispatcherClientKey, NULL);
-
-void SetDispatcherClient(Window* root_window, DispatcherClient* client) {
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- root_window->SetProperty(kDispatcherClientKey, client);
-}
-
-DispatcherClient* GetDispatcherClient(Window* root_window) {
- if (root_window)
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- return root_window ? root_window->GetProperty(kDispatcherClientKey) : NULL;
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/dispatcher_client.h b/chromium/ui/aura/client/dispatcher_client.h
deleted file mode 100644
index f2d1ff8bcb3..00000000000
--- a/chromium/ui/aura/client/dispatcher_client.h
+++ /dev/null
@@ -1,31 +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_AURA_CLIENT_DISPATCHER_CLIENT_H_
-#define UI_AURA_CLIENT_DISPATCHER_CLIENT_H_
-
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/window.h"
-
-namespace aura {
-class Window;
-namespace client {
-
-// An interface implemented by an object which handles nested dispatchers.
-class AURA_EXPORT DispatcherClient {
- public:
- virtual void RunWithDispatcher(base::MessageLoop::Dispatcher* dispatcher,
- aura::Window* associated_window,
- bool nestable_tasks_allowed) = 0;
-};
-
-AURA_EXPORT void SetDispatcherClient(Window* root_window,
- DispatcherClient* client);
-AURA_EXPORT DispatcherClient* GetDispatcherClient(Window* root_window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_DISPATCHER_CLIENT_H_
diff --git a/chromium/ui/aura/client/drag_drop_client.cc b/chromium/ui/aura/client/drag_drop_client.cc
deleted file mode 100644
index abf5879e578..00000000000
--- a/chromium/ui/aura/client/drag_drop_client.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/drag_drop_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropClient*)
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- DragDropClient*, kRootWindowDragDropClientKey, NULL);
-
-void SetDragDropClient(Window* root_window, DragDropClient* client) {
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- root_window->SetProperty(kRootWindowDragDropClientKey, client);
-}
-
-DragDropClient* GetDragDropClient(Window* root_window) {
- if (root_window)
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- return root_window ?
- root_window->GetProperty(kRootWindowDragDropClientKey) : NULL;
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/drag_drop_client.h b/chromium/ui/aura/client/drag_drop_client.h
deleted file mode 100644
index 7277d6b3839..00000000000
--- a/chromium/ui/aura/client/drag_drop_client.h
+++ /dev/null
@@ -1,62 +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_AURA_CLIENT_DRAG_DROP_CLIENT_H_
-#define UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class LocatedEvent;
-class OSExchangeData;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-// An interface implemented by an object that controls a drag and drop session.
-class AURA_EXPORT DragDropClient {
- public:
- virtual ~DragDropClient() {}
-
- // Initiates a drag and drop session. Returns the drag operation that was
- // applied at the end of the drag drop session. |root_location| is in the
- // root Window's coordinate system.
- virtual int StartDragAndDrop(const ui::OSExchangeData& data,
- aura::Window* root_window,
- aura::Window* source_window,
- const gfx::Point& root_location,
- int operation,
- ui::DragDropTypes::DragEventSource source) = 0;
-
- // Called when mouse is dragged during a drag and drop.
- virtual void DragUpdate(aura::Window* target,
- const ui::LocatedEvent& event) = 0;
-
- // Called when mouse is released during a drag and drop.
- virtual void Drop(aura::Window* target,
- const ui::LocatedEvent& event) = 0;
-
- // Called when a drag and drop session is cancelled.
- virtual void DragCancel() = 0;
-
- // Returns true if a drag and drop session is in progress.
- virtual bool IsDragDropInProgress() = 0;
-};
-
-AURA_EXPORT void SetDragDropClient(Window* root_window,
- DragDropClient* client);
-AURA_EXPORT DragDropClient* GetDragDropClient(Window* root_window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_
diff --git a/chromium/ui/aura/client/drag_drop_delegate.cc b/chromium/ui/aura/client/drag_drop_delegate.cc
deleted file mode 100644
index 92d986be8da..00000000000
--- a/chromium/ui/aura/client/drag_drop_delegate.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/drag_drop_delegate.h"
-
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropDelegate*)
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- DragDropDelegate*, kDragDropDelegateKey, NULL);
-
-void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) {
- window->SetProperty(kDragDropDelegateKey, delegate);
-}
-
-DragDropDelegate* GetDragDropDelegate(Window* window) {
- return window->GetProperty(kDragDropDelegateKey);
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/drag_drop_delegate.h b/chromium/ui/aura/client/drag_drop_delegate.h
deleted file mode 100644
index dde7f32ec73..00000000000
--- a/chromium/ui/aura/client/drag_drop_delegate.h
+++ /dev/null
@@ -1,51 +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_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
-#define UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace ui {
-class DropTargetEvent;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-// Delegate interface for drag and drop actions on aura::Window.
-class AURA_EXPORT DragDropDelegate {
- public:
- // OnDragEntered is invoked when the mouse enters this window during a drag &
- // drop session. This is immediately followed by an invocation of
- // OnDragUpdated, and eventually one of OnDragExited or OnPerformDrop.
- virtual void OnDragEntered(const ui::DropTargetEvent& event) = 0;
-
- // Invoked during a drag and drop session while the mouse is over the window.
- // This should return a bitmask of the DragDropTypes::DragOperation supported
- // based on the location of the event. Return 0 to indicate the drop should
- // not be accepted.
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) = 0;
-
- // Invoked during a drag and drop session when the mouse exits the window, or
- // when the drag session was canceled and the mouse was over the window.
- virtual void OnDragExited() = 0;
-
- // Invoked during a drag and drop session when OnDragUpdated returns a valid
- // operation and the user release the mouse.
- virtual int OnPerformDrop(const ui::DropTargetEvent& event) = 0;
-
- protected:
- virtual ~DragDropDelegate() {}
-};
-
-AURA_EXPORT void SetDragDropDelegate(Window* window,
- DragDropDelegate* delegate);
-AURA_EXPORT DragDropDelegate* GetDragDropDelegate(Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_
diff --git a/chromium/ui/aura/client/event_client.cc b/chromium/ui/aura/client/event_client.cc
index c6699741b3c..d6da07e4245 100644
--- a/chromium/ui/aura/client/event_client.cc
+++ b/chromium/ui/aura/client/event_client.cc
@@ -4,7 +4,7 @@
#include "ui/aura/client/event_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_WINDOW_PROPERTY_TYPE(aura::client::EventClient*)
diff --git a/chromium/ui/aura/client/focus_client.cc b/chromium/ui/aura/client/focus_client.cc
index 0769b0dfac0..1f24a802cbc 100644
--- a/chromium/ui/aura/client/focus_client.cc
+++ b/chromium/ui/aura/client/focus_client.cc
@@ -4,7 +4,7 @@
#include "ui/aura/client/focus_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, aura::Window*)
diff --git a/chromium/ui/aura/client/screen_position_client.cc b/chromium/ui/aura/client/screen_position_client.cc
index 1fb75217bcb..8601005e4ea 100644
--- a/chromium/ui/aura/client/screen_position_client.cc
+++ b/chromium/ui/aura/client/screen_position_client.cc
@@ -4,7 +4,7 @@
#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ScreenPositionClient*)
diff --git a/chromium/ui/aura/client/tooltip_client.cc b/chromium/ui/aura/client/tooltip_client.cc
deleted file mode 100644
index f018f262812..00000000000
--- a/chromium/ui/aura/client/tooltip_client.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/tooltip_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::TooltipClient*)
-DECLARE_WINDOW_PROPERTY_TYPE(base::string16*)
-
-namespace aura {
-namespace client {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- TooltipClient*, kRootWindowTooltipClientKey, NULL);
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(base::string16*, kTooltipTextKey, NULL);
-
-void SetTooltipClient(Window* root_window, TooltipClient* client) {
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- root_window->SetProperty(kRootWindowTooltipClientKey, client);
-}
-
-TooltipClient* GetTooltipClient(Window* root_window) {
- if (root_window)
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- return root_window ?
- root_window->GetProperty(kRootWindowTooltipClientKey) : NULL;
-}
-
-void SetTooltipText(Window* window, base::string16* tooltip_text) {
- window->SetProperty(kTooltipTextKey, tooltip_text);
-}
-
-const base::string16 GetTooltipText(Window* window) {
- base::string16* string_ptr = window->GetProperty(kTooltipTextKey);
- return string_ptr ? *string_ptr : base::string16();
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/tooltip_client.h b/chromium/ui/aura/client/tooltip_client.h
deleted file mode 100644
index c280b8a8b75..00000000000
--- a/chromium/ui/aura/client/tooltip_client.h
+++ /dev/null
@@ -1,38 +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_AURA_CLIENT_TOOLTIP_CLIENT_H_
-#define UI_AURA_CLIENT_TOOLTIP_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-#include "ui/gfx/font.h"
-
-namespace aura {
-class Window;
-namespace client {
-
-class AURA_EXPORT TooltipClient {
- public:
- // Informs the shell tooltip manager of change in tooltip for window |target|.
- virtual void UpdateTooltip(Window* target) = 0;
-
- // Sets the time after which the tooltip is hidden for Window |target|. If
- // |timeout_in_ms| is <= 0, the tooltip is shown indefinitely.
- virtual void SetTooltipShownTimeout(Window* target, int timeout_in_ms) = 0;
-
- // Enables/Disables tooltips.
- virtual void SetTooltipsEnabled(bool enable) = 0;
-};
-
-AURA_EXPORT void SetTooltipClient(Window* root_window,
- TooltipClient* client);
-AURA_EXPORT TooltipClient* GetTooltipClient(Window* root_window);
-
-AURA_EXPORT void SetTooltipText(Window* window, base::string16* tooltip_text);
-AURA_EXPORT const base::string16 GetTooltipText(Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_TOOLTIP_CLIENT_H_
diff --git a/chromium/ui/aura/client/user_action_client.cc b/chromium/ui/aura/client/user_action_client.cc
deleted file mode 100644
index 3dab666660c..00000000000
--- a/chromium/ui/aura/client/user_action_client.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/user_action_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-
-namespace aura {
-namespace client {
-
-DEFINE_WINDOW_PROPERTY_KEY(UserActionClient*,
- kRootWindowUserActionClientKey,
- NULL);
-
-void SetUserActionClient(Window* root_window, UserActionClient* client) {
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- root_window->SetProperty(kRootWindowUserActionClientKey, client);
-}
-
-UserActionClient* GetUserActionClient(Window* root_window) {
- if (root_window)
- DCHECK_EQ(root_window->GetRootWindow(), root_window);
- return root_window ?
- root_window->GetProperty(kRootWindowUserActionClientKey) : NULL;
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/user_action_client.h b/chromium/ui/aura/client/user_action_client.h
deleted file mode 100644
index 738a8d5fba1..00000000000
--- a/chromium/ui/aura/client/user_action_client.h
+++ /dev/null
@@ -1,37 +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_AURA_CLIENT_USER_ACTION_CLIENT_H_
-#define UI_AURA_CLIENT_USER_ACTION_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace aura {
-class Window;
-namespace client {
-
-// An interface for handling a user action that isn't handled by the standard
-// event path.
-class AURA_EXPORT UserActionClient {
- public:
- enum Command {
- BACK = 0,
- FORWARD,
- };
-
- // Returns true if the command was handled and false otherwise.
- virtual bool OnUserAction(Command command) = 0;
-
- virtual ~UserActionClient() {}
-};
-
-// Sets/gets the client for handling user action on the specified root window.
-AURA_EXPORT void SetUserActionClient(Window* root_window,
- UserActionClient* client);
-AURA_EXPORT UserActionClient* GetUserActionClient(Window* root_window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_USER_ACTION_CLIENT_H_
diff --git a/chromium/ui/aura/client/visibility_client.cc b/chromium/ui/aura/client/visibility_client.cc
index 5fc7beed7c1..853c034951f 100644
--- a/chromium/ui/aura/client/visibility_client.cc
+++ b/chromium/ui/aura/client/visibility_client.cc
@@ -4,7 +4,7 @@
#include "ui/aura/client/visibility_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_WINDOW_PROPERTY_TYPE(aura::client::VisibilityClient*)
diff --git a/chromium/ui/aura/client/window_move_client.cc b/chromium/ui/aura/client/window_move_client.cc
deleted file mode 100644
index c65452db607..00000000000
--- a/chromium/ui/aura/client/window_move_client.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/client/window_move_client.h"
-
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowMoveClient*)
-
-namespace aura {
-namespace client {
-
-// A property key to store a client that handles window moves.
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
- WindowMoveClient*, kWindowMoveClientKey, NULL);
-
-void SetWindowMoveClient(Window* window, WindowMoveClient* client) {
- window->SetProperty(kWindowMoveClientKey, client);
-}
-
-WindowMoveClient* GetWindowMoveClient(Window* window) {
- return window->GetProperty(kWindowMoveClientKey);
-}
-
-} // namespace client
-} // namespace aura
diff --git a/chromium/ui/aura/client/window_move_client.h b/chromium/ui/aura/client/window_move_client.h
deleted file mode 100644
index 15e4245757b..00000000000
--- a/chromium/ui/aura/client/window_move_client.h
+++ /dev/null
@@ -1,56 +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_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_
-#define UI_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_
-
-#include "ui/aura/aura_export.h"
-#include "ui/gfx/vector2d.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace aura {
-class Window;
-namespace client {
-
-enum WindowMoveResult {
- MOVE_SUCCESSFUL, // Moving window was successful.
- MOVE_CANCELED // Moving window was canceled.
-};
-
-enum WindowMoveSource {
- WINDOW_MOVE_SOURCE_MOUSE,
- WINDOW_MOVE_SOURCE_TOUCH,
-};
-
-// An interface implemented by an object that manages programatically keyed
-// window moving.
-class AURA_EXPORT WindowMoveClient {
- public:
- // Starts a nested message loop for moving the window. |drag_offset| is the
- // offset from the window origin to the cursor when the drag was started.
- // Returns MOVE_SUCCESSFUL if the move has completed successfully, or
- // MOVE_CANCELED otherwise.
- virtual WindowMoveResult RunMoveLoop(Window* window,
- const gfx::Vector2d& drag_offset,
- WindowMoveSource source) = 0;
-
- // Ends a previously started move loop.
- virtual void EndMoveLoop() = 0;
-
- protected:
- virtual ~WindowMoveClient() {}
-};
-
-// Sets/Gets the activation client for the specified window.
-AURA_EXPORT void SetWindowMoveClient(Window* window,
- WindowMoveClient* client);
-AURA_EXPORT WindowMoveClient* GetWindowMoveClient(Window* window);
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_
diff --git a/chromium/ui/aura/client/window_stacking_client.cc b/chromium/ui/aura/client/window_stacking_client.cc
index 81da8d1ea6f..8f909766d64 100644
--- a/chromium/ui/aura/client/window_stacking_client.cc
+++ b/chromium/ui/aura/client/window_stacking_client.cc
@@ -14,11 +14,10 @@ WindowStackingClient* instance = NULL;
} // namespace
void SetWindowStackingClient(WindowStackingClient* client) {
- delete instance;
instance = client;
}
-AURA_EXPORT WindowStackingClient* GetWindowStackingClient() {
+WindowStackingClient* GetWindowStackingClient() {
return instance;
}
diff --git a/chromium/ui/aura/client/window_stacking_client.h b/chromium/ui/aura/client/window_stacking_client.h
index 35772ed71c4..848260397cb 100644
--- a/chromium/ui/aura/client/window_stacking_client.h
+++ b/chromium/ui/aura/client/window_stacking_client.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_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
-#define UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
+#ifndef UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_
+#define UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
@@ -15,20 +15,25 @@ namespace client {
class AURA_EXPORT WindowStackingClient {
public:
- virtual ~WindowStackingClient() {}
-
// Invoked from the various Window stacking functions. Allows the
// WindowStackingClient to alter the source, target and/or direction to stack.
- virtual void AdjustStacking(Window** child,
+ // Returns true if stacking should continue; false if the stacking should not
+ // happen.
+ virtual bool AdjustStacking(Window** child,
Window** target,
Window::StackDirection* direction) = 0;
+
+ protected:
+ virtual ~WindowStackingClient() {}
};
-// Sets/gets the WindowStackingClient. The setter takes ownership of |client|.
+// Sets/gets the WindowStackingClient. This does *not* take ownership of
+// |client|. It is assumed the caller will invoke SetWindowStackingClient(NULL)
+// before deleting |client|.
AURA_EXPORT void SetWindowStackingClient(WindowStackingClient* client);
AURA_EXPORT WindowStackingClient* GetWindowStackingClient();
} // namespace client
} // namespace aura
-#endif // UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
+#endif // UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_
diff --git a/chromium/ui/aura/client/window_tree_client.cc b/chromium/ui/aura/client/window_tree_client.cc
index de1ece561d0..1b263c3e756 100644
--- a/chromium/ui/aura/client/window_tree_client.cc
+++ b/chromium/ui/aura/client/window_tree_client.cc
@@ -5,7 +5,7 @@
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowTreeClient*)
diff --git a/chromium/ui/aura/client/window_types.h b/chromium/ui/aura/client/window_types.h
deleted file mode 100644
index f0a7b777a8f..00000000000
--- a/chromium/ui/aura/client/window_types.h
+++ /dev/null
@@ -1,36 +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_AURA_WINDOW_TYPES_H_
-#define UI_AURA_WINDOW_TYPES_H_
-
-namespace aura {
-namespace client {
-
-// This isn't a property because it can't change after the window has been
-// initialized. It's in client because the Aura Client application derives
-// meaning from these values, not Aura itself.
-enum WindowType {
- WINDOW_TYPE_UNKNOWN = 0,
-
- // Regular windows that should be laid out by the client.
- WINDOW_TYPE_NORMAL,
-
- // Miscellaneous windows that should not be laid out by the shell.
- WINDOW_TYPE_POPUP,
-
- // A window intended as a control. Not laid out by the shell.
- WINDOW_TYPE_CONTROL,
-
- // Always on top windows aligned to bottom right of screen.
- WINDOW_TYPE_PANEL,
-
- WINDOW_TYPE_MENU,
- WINDOW_TYPE_TOOLTIP,
-};
-
-} // namespace client
-} // namespace aura
-
-#endif // UI_AURA_WINDOW_TYPES_H_
diff --git a/chromium/ui/aura/demo/DEPS b/chromium/ui/aura/demo/DEPS
new file mode 100644
index 00000000000..07d824381a5
--- /dev/null
+++ b/chromium/ui/aura/demo/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/gl/gl_surface.h", # To initialize GL bindings.
+]
diff --git a/chromium/ui/aura/demo/demo_main.cc b/chromium/ui/aura/demo/demo_main.cc
index 4dfd347577b..f531cd31c2e 100644
--- a/chromium/ui/aura/demo/demo_main.cc
+++ b/chromium/ui/aura/demo/demo_main.cc
@@ -11,21 +11,24 @@
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/test_focus_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
+#include "ui/gl/gl_surface.h"
#if defined(USE_X11)
-#include "base/message_loop/message_pump_x11.h"
+#include "ui/gfx/x/x11_connection.h"
+#endif
+
+#if defined(OS_WIN)
+#include "ui/gfx/win/dpi.h"
#endif
namespace {
@@ -63,13 +66,11 @@ class DemoWindowDelegate : public aura::WindowDelegate {
canvas->DrawColor(color_, SkXfermode::kSrc_Mode);
}
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
- virtual void OnWindowDestroying() OVERRIDE {}
- virtual void OnWindowDestroyed() OVERRIDE {}
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {}
virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
virtual bool HasHitTestMask() const OVERRIDE { return false; }
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
- virtual void DidRecreateLayer(ui::Layer* old_layer,
- ui::Layer* new_layer) OVERRIDE {}
private:
SkColor color_;
@@ -107,51 +108,63 @@ class DemoWindowTreeClient : public aura::client::WindowTreeClient {
};
int DemoMain() {
- // Create the message-loop here before creating the root window.
- base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+#if defined(USE_X11)
+ // This demo uses InProcessContextFactory which uses X on a separate Gpu
+ // thread.
+ gfx::InitializeThreadedX11();
+#endif
+
+ gfx::GLSurface::InitializeOneOff();
+
+#if defined(OS_WIN)
+ gfx::InitDeviceScaleFactor(1.0f);
+#endif
// The ContextFactory must exist before any Compositors are created.
- bool allow_test_contexts = false;
- ui::InitializeContextFactoryForTests(allow_test_contexts);
+ scoped_ptr<ui::InProcessContextFactory> context_factory(
+ new ui::InProcessContextFactory());
+
+ // Create the message-loop here before creating the root window.
+ base::MessageLoopForUI message_loop;
- aura::Env::CreateInstance();
- scoped_ptr<aura::TestScreen> test_screen(aura::TestScreen::Create());
+ aura::Env::CreateInstance(true);
+ aura::Env::GetInstance()->set_context_factory(context_factory.get());
+ scoped_ptr<aura::TestScreen> test_screen(
+ aura::TestScreen::Create(gfx::Size()));
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
- scoped_ptr<aura::RootWindow> root_window(
- test_screen->CreateRootWindowForPrimaryDisplay());
- scoped_ptr<DemoWindowTreeClient> window_tree_client(new DemoWindowTreeClient(
- root_window->window()));
+ scoped_ptr<aura::WindowTreeHost> host(
+ test_screen->CreateHostForPrimaryDisplay());
+ scoped_ptr<DemoWindowTreeClient> window_tree_client(
+ new DemoWindowTreeClient(host->window()));
aura::test::TestFocusClient focus_client;
- aura::client::SetFocusClient(root_window->window(), &focus_client);
+ aura::client::SetFocusClient(host->window(), &focus_client);
// Create a hierarchy of test windows.
DemoWindowDelegate window_delegate1(SK_ColorBLUE);
aura::Window window1(&window_delegate1);
window1.set_id(1);
- window1.Init(ui::LAYER_TEXTURED);
+ window1.Init(aura::WINDOW_LAYER_TEXTURED);
window1.SetBounds(gfx::Rect(100, 100, 400, 400));
window1.Show();
- aura::client::ParentWindowWithContext(
- &window1, root_window->window(), gfx::Rect());
+ aura::client::ParentWindowWithContext(&window1, host->window(), gfx::Rect());
DemoWindowDelegate window_delegate2(SK_ColorRED);
aura::Window window2(&window_delegate2);
window2.set_id(2);
- window2.Init(ui::LAYER_TEXTURED);
+ window2.Init(aura::WINDOW_LAYER_TEXTURED);
window2.SetBounds(gfx::Rect(200, 200, 350, 350));
window2.Show();
- aura::client::ParentWindowWithContext(
- &window2, root_window->window(), gfx::Rect());
+ aura::client::ParentWindowWithContext(&window2, host->window(), gfx::Rect());
DemoWindowDelegate window_delegate3(SK_ColorGREEN);
aura::Window window3(&window_delegate3);
window3.set_id(3);
- window3.Init(ui::LAYER_TEXTURED);
+ window3.Init(aura::WINDOW_LAYER_TEXTURED);
window3.SetBounds(gfx::Rect(10, 10, 50, 50));
window3.Show();
window2.AddChild(&window3);
- root_window->host()->Show();
+ host->Show();
base::MessageLoopForUI::current()->Run();
return 0;
@@ -165,9 +178,7 @@ int main(int argc, char** argv) {
// The exit manager is in charge of calling the dtors of singleton objects.
base::AtExitManager exit_manager;
- ui::RegisterPathProvider();
base::i18n::InitializeICU();
- ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
return DemoMain();
}
diff --git a/chromium/ui/aura/device_list_updater_aurax11.cc b/chromium/ui/aura/device_list_updater_aurax11.cc
deleted file mode 100644
index 8240cb495c3..00000000000
--- a/chromium/ui/aura/device_list_updater_aurax11.cc
+++ /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.
-
-#include "ui/aura/device_list_updater_aurax11.h"
-
-#include <X11/extensions/XInput2.h>
-
-#include "ui/events/event_utils.h"
-
-namespace aura {
-
-DeviceListUpdaterAuraX11::DeviceListUpdaterAuraX11() {}
-
-DeviceListUpdaterAuraX11::~DeviceListUpdaterAuraX11() {}
-
-base::EventStatus DeviceListUpdaterAuraX11::WillProcessEvent(
- const base::NativeEvent& event) {
- // XI_HierarchyChanged events are special. There is no window associated with
- // these events. So process them directly from here.
- if (event->type == GenericEvent &&
- event->xgeneric.evtype == XI_HierarchyChanged) {
- ui::UpdateDeviceList();
- }
-
- return base::EVENT_CONTINUE;
-}
-
-void DeviceListUpdaterAuraX11::DidProcessEvent(const base::NativeEvent& event) {
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/device_list_updater_aurax11.h b/chromium/ui/aura/device_list_updater_aurax11.h
deleted file mode 100644
index cb8c884fe85..00000000000
--- a/chromium/ui/aura/device_list_updater_aurax11.h
+++ /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.
-
-#ifndef UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_
-#define UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_pump_observer.h"
-
-namespace aura {
-
-// Filters out global XInput notifications and updates the DeviceList.
-class DeviceListUpdaterAuraX11 : public base::MessagePumpObserver {
- public:
- DeviceListUpdaterAuraX11();
- virtual ~DeviceListUpdaterAuraX11();
-
- // Overridden from base::MessagePumpObserver:
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE;
- virtual void DidProcessEvent(
- const base::NativeEvent& event) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeviceListUpdaterAuraX11);
-};
-
-} // namespace aura
-
-#endif // UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_
diff --git a/chromium/ui/aura/dispatcher_win.cc b/chromium/ui/aura/dispatcher_win.cc
deleted file mode 100644
index 7160dc7771d..00000000000
--- a/chromium/ui/aura/dispatcher_win.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-
-namespace aura {
-
-class DispatcherWin : public base::MessageLoop::Dispatcher {
- public:
- DispatcherWin() {}
- virtual ~DispatcherWin() {}
-
- // Overridden from MessageLoop::Dispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DispatcherWin);
-};
-
-bool DispatcherWin::Dispatch(const base::NativeEvent& msg) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return true;
-}
-
-base::MessageLoop::Dispatcher* CreateDispatcher() {
- return new DispatcherWin;
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc
index 0982d91ad26..71a43c9c5ae 100644
--- a/chromium/ui/aura/env.cc
+++ b/chromium/ui/aura/env.cc
@@ -4,62 +4,47 @@
#include "ui/aura/env.h"
-#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/input_state_lookup.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/compositor.h"
-#include "ui/compositor/compositor_switches.h"
#include "ui/events/event_target_iterator.h"
+#include "ui/events/platform/platform_event_source.h"
-#if defined(USE_X11)
-#include "base/message_loop/message_pump_x11.h"
+#if defined(USE_OZONE)
+#include "ui/ozone/ozone_platform.h"
#endif
namespace aura {
-// static
-Env* Env::instance_ = NULL;
-
-////////////////////////////////////////////////////////////////////////////////
-// Env, public:
-
-Env::Env()
- : mouse_button_flags_(0),
- is_touch_down_(false),
- input_state_lookup_(InputStateLookup::Create().Pass()) {
-}
+namespace {
-Env::~Env() {
-#if defined(USE_X11)
- base::MessagePumpX11::Current()->RemoveObserver(
- &device_list_updater_aurax11_);
-#endif
+// Env is thread local so that aura may be used on multiple threads.
+base::LazyInstance<base::ThreadLocalPointer<Env> >::Leaky lazy_tls_ptr =
+ LAZY_INSTANCE_INITIALIZER;
- FOR_EACH_OBSERVER(EnvObserver, observers_, OnWillDestroyEnv());
+} // namespace
- ui::Compositor::Terminate();
-}
+////////////////////////////////////////////////////////////////////////////////
+// Env, public:
-//static
-void Env::CreateInstance() {
- if (!instance_) {
- instance_ = new Env;
- instance_->Init();
- }
+// static
+void Env::CreateInstance(bool create_event_source) {
+ if (!lazy_tls_ptr.Pointer()->Get())
+ (new Env())->Init(create_event_source);
}
// static
Env* Env::GetInstance() {
- DCHECK(instance_) << "Env::CreateInstance must be called before getting "
- "the instance of Env.";
- return instance_;
+ Env* env = lazy_tls_ptr.Pointer()->Get();
+ DCHECK(env) << "Env::CreateInstance must be called before getting the "
+ "instance of Env.";
+ return env;
}
// static
void Env::DeleteInstance() {
- delete instance_;
- instance_ = NULL;
+ delete lazy_tls_ptr.Pointer()->Get();
}
void Env::AddObserver(EnvObserver* observer) {
@@ -75,47 +60,44 @@ bool Env::IsMouseButtonDown() const {
mouse_button_flags_ != 0;
}
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
- !defined(USE_GTK_MESSAGE_PUMP)
-base::MessageLoop::Dispatcher* Env::GetDispatcher() {
-#if defined(USE_X11)
- return base::MessagePumpX11::Current();
-#else
- return dispatcher_.get();
-#endif
-}
-#endif
+////////////////////////////////////////////////////////////////////////////////
+// Env, private:
-void Env::RootWindowActivated(RootWindow* root_window) {
- FOR_EACH_OBSERVER(EnvObserver, observers_,
- OnRootWindowActivated(root_window));
+Env::Env()
+ : mouse_button_flags_(0),
+ is_touch_down_(false),
+ input_state_lookup_(InputStateLookup::Create().Pass()),
+ context_factory_(NULL) {
+ DCHECK(lazy_tls_ptr.Pointer()->Get() == NULL);
+ lazy_tls_ptr.Pointer()->Set(this);
}
-////////////////////////////////////////////////////////////////////////////////
-// Env, private:
+Env::~Env() {
+ FOR_EACH_OBSERVER(EnvObserver, observers_, OnWillDestroyEnv());
+ DCHECK_EQ(this, lazy_tls_ptr.Pointer()->Get());
+ lazy_tls_ptr.Pointer()->Set(NULL);
+}
-void Env::Init() {
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11) && \
- !defined(USE_OZONE)
- dispatcher_.reset(CreateDispatcher());
-#endif
-#if defined(USE_X11)
- // We can't do this with a root window listener because XI_HierarchyChanged
- // messages don't have a target window.
- base::MessagePumpX11::Current()->AddObserver(
- &device_list_updater_aurax11_);
+void Env::Init(bool create_event_source) {
+#if defined(USE_OZONE)
+ // The ozone platform can provide its own event source. So initialize the
+ // platform before creating the default event source.
+ ui::OzonePlatform::InitializeForUI();
#endif
- ui::Compositor::Initialize();
+ if (create_event_source && !ui::PlatformEventSource::GetInstance())
+ event_source_ = ui::PlatformEventSource::CreateDefault();
}
void Env::NotifyWindowInitialized(Window* window) {
FOR_EACH_OBSERVER(EnvObserver, observers_, OnWindowInitialized(window));
}
-void Env::NotifyRootWindowInitialized(RootWindow* root_window) {
- FOR_EACH_OBSERVER(EnvObserver,
- observers_,
- OnRootWindowInitialized(root_window));
+void Env::NotifyHostInitialized(WindowTreeHost* host) {
+ FOR_EACH_OBSERVER(EnvObserver, observers_, OnHostInitialized(host));
+}
+
+void Env::NotifyHostActivated(WindowTreeHost* host) {
+ FOR_EACH_OBSERVER(EnvObserver, observers_, OnHostActivated(host));
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h
index e326781264f..a4f67668482 100644
--- a/chromium/ui/aura/env.h
+++ b/chromium/ui/aura/env.h
@@ -6,17 +6,17 @@
#define UI_AURA_ENV_H_
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
+#include "base/supports_user_data.h"
#include "ui/aura/aura_export.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_target.h"
#include "ui/gfx/point.h"
-#if defined(USE_X11)
-#include "ui/aura/device_list_updater_aurax11.h"
-#endif
-
+namespace ui {
+class ContextFactory;
+class PlatformEventSource;
+}
namespace aura {
namespace test {
@@ -25,28 +25,24 @@ class EnvTestHelper;
class EnvObserver;
class InputStateLookup;
-class RootWindow;
class Window;
-
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11)
-// Creates a platform-specific native event dispatcher.
-base::MessageLoop::Dispatcher* CreateDispatcher();
-#endif
+class WindowTreeHost;
// A singleton object that tracks general state within Aura.
-// TODO(beng): manage RootWindows.
-class AURA_EXPORT Env : public ui::EventTarget {
+class AURA_EXPORT Env : public ui::EventTarget, public base::SupportsUserData {
public:
- Env();
- virtual ~Env();
-
- static void CreateInstance();
+ // Creates the single Env instance (if it hasn't been created yet). If
+ // |create_event_source| is true a PlatformEventSource is created.
+ // TODO(sky): nuke |create_event_source|. Only necessary while mojo's
+ // nativeviewportservice lives in the same process as the viewmanager.
+ static void CreateInstance(bool create_event_source);
static Env* GetInstance();
static void DeleteInstance();
void AddObserver(EnvObserver* observer);
void RemoveObserver(EnvObserver* observer);
+ const int mouse_button_flags() const { return mouse_button_flags_; }
void set_mouse_button_flags(int mouse_button_flags) {
mouse_button_flags_ = mouse_button_flags;
}
@@ -65,29 +61,30 @@ class AURA_EXPORT Env : public ui::EventTarget {
bool is_touch_down() const { return is_touch_down_; }
void set_touch_down(bool value) { is_touch_down_ = value; }
- // Returns the native event dispatcher. The result should only be passed to
- // base::RunLoop(dispatcher), or used to dispatch an event by
- // |Dispatch(const NativeEvent&)| on it. It must never be stored.
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
- !defined(USE_GTK_MESSAGE_PUMP)
- base::MessageLoop::Dispatcher* GetDispatcher();
-#endif
-
- // Invoked by RootWindow when its host is activated.
- void RootWindowActivated(RootWindow* root_window);
+ void set_context_factory(ui::ContextFactory* context_factory) {
+ context_factory_ = context_factory;
+ }
+ ui::ContextFactory* context_factory() { return context_factory_; }
private:
friend class test::EnvTestHelper;
friend class Window;
- friend class RootWindow;
+ friend class WindowTreeHost;
+
+ Env();
+ virtual ~Env();
- void Init();
+ // See description of CreateInstance() for deatils of |create_event_source|.
+ void Init(bool create_event_source);
// Called by the Window when it is initialized. Notifies observers.
void NotifyWindowInitialized(Window* window);
- // Called by the RootWindow when it is initialized. Notifies observers.
- void NotifyRootWindowInitialized(RootWindow* root_window);
+ // Called by the WindowTreeHost when it is initialized. Notifies observers.
+ void NotifyHostInitialized(WindowTreeHost* host);
+
+ // Invoked by WindowTreeHost when it is activated. Notifies observers.
+ void NotifyHostActivated(WindowTreeHost* host);
// Overridden from ui::EventTarget:
virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE;
@@ -96,21 +93,16 @@ class AURA_EXPORT Env : public ui::EventTarget {
virtual ui::EventTargeter* GetEventTargeter() OVERRIDE;
ObserverList<EnvObserver> observers_;
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11)
- scoped_ptr<base::MessageLoop::Dispatcher> dispatcher_;
-#endif
- static Env* instance_;
int mouse_button_flags_;
// Location of last mouse event, in screen coordinates.
gfx::Point last_mouse_location_;
bool is_touch_down_;
-#if defined(USE_X11)
- DeviceListUpdaterAuraX11 device_list_updater_aurax11_;
-#endif
-
scoped_ptr<InputStateLookup> input_state_lookup_;
+ scoped_ptr<ui::PlatformEventSource> event_source_;
+
+ ui::ContextFactory* context_factory_;
DISALLOW_COPY_AND_ASSIGN(Env);
};
diff --git a/chromium/ui/aura/env_observer.h b/chromium/ui/aura/env_observer.h
index b624f91b6ec..51a69466b32 100644
--- a/chromium/ui/aura/env_observer.h
+++ b/chromium/ui/aura/env_observer.h
@@ -9,19 +9,19 @@
namespace aura {
-class RootWindow;
class Window;
+class WindowTreeHost;
class AURA_EXPORT EnvObserver {
public:
// Called when |window| has been initialized.
virtual void OnWindowInitialized(Window* window) = 0;
- // Called when |root_window| has been initialized.
- virtual void OnRootWindowInitialized(RootWindow* root_window) {};
+ // Called when a WindowTreeHost is initialized.
+ virtual void OnHostInitialized(WindowTreeHost* host) {};
- // Called when a RootWindow's host is activated.
- virtual void OnRootWindowActivated(RootWindow* root_window) {}
+ // Called when a WindowTreeHost is activated.
+ virtual void OnHostActivated(WindowTreeHost* host) {}
// Called right before Env is destroyed.
virtual void OnWillDestroyEnv() {}
diff --git a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
index 3a18d1fffc4..596cb1f40cb 100644
--- a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -9,12 +9,12 @@
#include "base/timer/timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event.h"
@@ -93,15 +93,11 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
scroll_velocity_y_(0),
velocity_x_(0),
velocity_y_(0),
- scroll_x_ordinal_(0),
- scroll_y_ordinal_(0),
- scroll_velocity_x_ordinal_(0),
- scroll_velocity_y_ordinal_(0),
- velocity_x_ordinal_(0),
- velocity_y_ordinal_(0),
+ scroll_x_hint_(0),
+ scroll_y_hint_(0),
tap_count_(0),
- wait_until_event_(ui::ET_UNKNOWN) {
- }
+ flags_(0),
+ wait_until_event_(ui::ET_UNKNOWN) {}
virtual ~GestureEventConsumeDelegate() {}
@@ -129,6 +125,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
scroll_begin_position_.SetPoint(0, 0);
tap_location_.SetPoint(0, 0);
+ gesture_end_location_.SetPoint(0, 0);
scroll_x_ = 0;
scroll_y_ = 0;
@@ -136,13 +133,12 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
scroll_velocity_y_ = 0;
velocity_x_ = 0;
velocity_y_ = 0;
- scroll_x_ordinal_ = 0;
- scroll_y_ordinal_ = 0;
- scroll_velocity_x_ordinal_ = 0;
- scroll_velocity_y_ordinal_ = 0;
- velocity_x_ordinal_ = 0;
- velocity_y_ordinal_ = 0;
+ scroll_x_hint_ = 0;
+ scroll_y_hint_ = 0;
tap_count_ = 0;
+ scale_ = 0;
+ flags_ = 0;
+ latency_info_.Clear();
}
const std::vector<ui::EventType>& events() const { return events_; };
@@ -168,40 +164,43 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
bool swipe_up() const { return swipe_up_; }
bool swipe_down() const { return swipe_down_; }
- const gfx::Point scroll_begin_position() const {
+ const gfx::Point& scroll_begin_position() const {
return scroll_begin_position_;
}
- const gfx::Point tap_location() const {
+ const gfx::Point& tap_location() const {
return tap_location_;
}
+ const gfx::Point& gesture_end_location() const {
+ return gesture_end_location_;
+ }
+
float scroll_x() const { return scroll_x_; }
float scroll_y() const { return scroll_y_; }
float scroll_velocity_x() const { return scroll_velocity_x_; }
float scroll_velocity_y() const { return scroll_velocity_y_; }
float velocity_x() const { return velocity_x_; }
float velocity_y() const { return velocity_y_; }
- float scroll_x_ordinal() const { return scroll_x_ordinal_; }
- float scroll_y_ordinal() const { return scroll_y_ordinal_; }
- float scroll_velocity_x_ordinal() const { return scroll_velocity_x_ordinal_; }
- float scroll_velocity_y_ordinal() const { return scroll_velocity_y_ordinal_; }
- float velocity_x_ordinal() const { return velocity_x_ordinal_; }
- float velocity_y_ordinal() const { return velocity_y_ordinal_; }
- int touch_id() const { return touch_id_; }
+ float scroll_x_hint() const { return scroll_x_hint_; }
+ float scroll_y_hint() const { return scroll_y_hint_; }
+ float scale() const { return scale_; }
const gfx::Rect& bounding_box() const { return bounding_box_; }
int tap_count() const { return tap_count_; }
+ int flags() const { return flags_; }
+ const ui::LatencyInfo& latency_info() const { return latency_info_; }
void WaitUntilReceivedGesture(ui::EventType type) {
wait_until_event_ = type;
- run_loop_.reset(new base::RunLoop(
- Env::GetInstance()->GetDispatcher()));
+ run_loop_.reset(new base::RunLoop());
run_loop_->Run();
}
virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
events_.push_back(gesture->type());
bounding_box_ = gesture->details().bounding_box();
+ flags_ = gesture->flags();
+ latency_info_ = *gesture->latency();
switch (gesture->type()) {
case ui::ET_GESTURE_TAP:
tap_location_ = gesture->location();
@@ -219,21 +218,18 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
break;
case ui::ET_GESTURE_END:
end_ = true;
+ gesture_end_location_ = gesture->location();
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
scroll_begin_ = true;
scroll_begin_position_ = gesture->location();
+ scroll_x_hint_ = gesture->details().scroll_x_hint();
+ scroll_y_hint_ = gesture->details().scroll_y_hint();
break;
case ui::ET_GESTURE_SCROLL_UPDATE:
scroll_update_ = true;
scroll_x_ += gesture->details().scroll_x();
scroll_y_ += gesture->details().scroll_y();
- scroll_velocity_x_ = gesture->details().velocity_x();
- scroll_velocity_y_ = gesture->details().velocity_y();
- scroll_x_ordinal_ += gesture->details().scroll_x_ordinal();
- scroll_y_ordinal_ += gesture->details().scroll_y_ordinal();
- scroll_velocity_x_ordinal_ = gesture->details().velocity_x_ordinal();
- scroll_velocity_y_ordinal_ = gesture->details().velocity_y_ordinal();
break;
case ui::ET_GESTURE_SCROLL_END:
EXPECT_TRUE(velocity_x_ == 0 && velocity_y_ == 0);
@@ -244,13 +240,13 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
break;
case ui::ET_GESTURE_PINCH_UPDATE:
pinch_update_ = true;
+ scale_ = gesture->details().scale();
break;
case ui::ET_GESTURE_PINCH_END:
pinch_end_ = true;
break;
case ui::ET_GESTURE_LONG_PRESS:
long_press_ = true;
- touch_id_ = gesture->details().touch_id();
break;
case ui::ET_GESTURE_LONG_TAP:
long_tap_ = true;
@@ -262,8 +258,6 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
fling_ = true;
velocity_x_ = gesture->details().velocity_x();
velocity_y_ = gesture->details().velocity_y();
- velocity_x_ordinal_ = gesture->details().velocity_x_ordinal();
- velocity_y_ordinal_ = gesture->details().velocity_y_ordinal();
break;
case ui::ET_GESTURE_TWO_FINGER_TAP:
two_finger_tap_ = true;
@@ -271,12 +265,15 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
case ui::ET_GESTURE_SHOW_PRESS:
show_press_ = true;
break;
- case ui::ET_GESTURE_MULTIFINGER_SWIPE:
+ case ui::ET_GESTURE_SWIPE:
swipe_left_ = gesture->details().swipe_left();
swipe_right_ = gesture->details().swipe_right();
swipe_up_ = gesture->details().swipe_up();
swipe_down_ = gesture->details().swipe_down();
break;
+ case ui::ET_SCROLL_FLING_CANCEL:
+ // Only used in unified gesture detection.
+ break;
default:
NOTREACHED();
}
@@ -314,6 +311,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
gfx::Point scroll_begin_position_;
gfx::Point tap_location_;
+ gfx::Point gesture_end_location_;
float scroll_x_;
float scroll_y_;
@@ -321,15 +319,13 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
float scroll_velocity_y_;
float velocity_x_;
float velocity_y_;
- float scroll_x_ordinal_;
- float scroll_y_ordinal_;
- float scroll_velocity_x_ordinal_;
- float scroll_velocity_y_ordinal_;
- float velocity_x_ordinal_;
- float velocity_y_ordinal_;
- int touch_id_;
+ float scroll_x_hint_;
+ float scroll_y_hint_;
+ float scale_;
gfx::Rect bounding_box_;
int tap_count_;
+ int flags_;
+ ui::LatencyInfo latency_info_;
ui::EventType wait_until_event_;
@@ -338,9 +334,9 @@ class GestureEventConsumeDelegate : public TestWindowDelegate {
class QueueTouchEventDelegate : public GestureEventConsumeDelegate {
public:
- explicit QueueTouchEventDelegate(RootWindow* root_window)
+ explicit QueueTouchEventDelegate(WindowEventDispatcher* dispatcher)
: window_(NULL),
- root_window_(root_window),
+ dispatcher_(dispatcher),
queue_events_(true) {
}
virtual ~QueueTouchEventDelegate() {
@@ -371,14 +367,14 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate {
private:
void ReceivedAckImpl(bool prevent_defaulted) {
scoped_ptr<ui::TouchEvent> event(queue_.front());
- root_window_->ProcessedTouchEvent(event.get(), window_,
+ dispatcher_->ProcessedTouchEvent(event.get(), window_,
prevent_defaulted ? ui::ER_HANDLED : ui::ER_UNHANDLED);
queue_.pop();
}
std::queue<ui::TouchEvent*> queue_;
Window* window_;
- RootWindow* root_window_;
+ WindowEventDispatcher* dispatcher_;
bool queue_events_;
DISALLOW_COPY_AND_ASSIGN(QueueTouchEventDelegate);
@@ -543,7 +539,9 @@ class TimedEvents {
int simulated_now_;
public:
- TimedEvents() : simulated_now_(0) {
+ // Use a non-zero start time to pass DCHECKs which ensure events have had a
+ // time assigned.
+ TimedEvents() : simulated_now_(1) {
}
base::TimeDelta Now() {
@@ -561,9 +559,9 @@ class TimedEvents {
return base::TimeDelta::FromMilliseconds(simulated_now_ + time_in_millis);
}
- void SendScrollEvents(RootWindow* root_window,
- int x_start,
- int y_start,
+ void SendScrollEvents(ui::EventProcessor* dispatcher,
+ float x_start,
+ float y_start,
int dx,
int dy,
int touch_id,
@@ -576,24 +574,26 @@ class TimedEvents {
for (int i = 0; i < num_steps; i++) {
x += dx;
y += dy;
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::PointF(x, y),
touch_id,
base::TimeDelta::FromMilliseconds(simulated_now_));
- root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move);
+ ASSERT_FALSE(details.dispatcher_destroyed);
simulated_now_ += time_step;
}
}
- void SendScrollEvent(RootWindow* root_window,
- int x,
- int y,
+ void SendScrollEvent(ui::EventProcessor* dispatcher,
+ float x,
+ float y,
int touch_id,
GestureEventConsumeDelegate* delegate) {
delegate->Reset();
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::PointF(x, y),
touch_id,
base::TimeDelta::FromMilliseconds(simulated_now_));
- root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move);
+ ASSERT_FALSE(details.dispatcher_destroyed);
simulated_now_++;
}
};
@@ -601,8 +601,9 @@ class TimedEvents {
// An event handler to keep track of events.
class TestEventHandler : public ui::EventHandler {
public:
- TestEventHandler() : touch_released_count_(0), touch_pressed_count_(0),
- touch_moved_count_(0), touch_stationary_count_(0),
+ TestEventHandler() : touch_released_count_(0),
+ touch_pressed_count_(0),
+ touch_moved_count_(0),
touch_cancelled_count_(0) {
}
@@ -619,9 +620,6 @@ class TestEventHandler : public ui::EventHandler {
case ui::ET_TOUCH_MOVED:
touch_moved_count_++;
break;
- case ui::ET_TOUCH_STATIONARY:
- touch_stationary_count_++;
- break;
case ui::ET_TOUCH_CANCELLED:
touch_cancelled_count_++;
break;
@@ -634,21 +632,18 @@ class TestEventHandler : public ui::EventHandler {
touch_released_count_ = 0;
touch_pressed_count_ = 0;
touch_moved_count_ = 0;
- touch_stationary_count_ = 0;
touch_cancelled_count_ = 0;
}
int touch_released_count() const { return touch_released_count_; }
int touch_pressed_count() const { return touch_pressed_count_; }
int touch_moved_count() const { return touch_moved_count_; }
- int touch_stationary_count() const { return touch_stationary_count_; }
int touch_cancelled_count() const { return touch_cancelled_count_; }
private:
int touch_released_count_;
int touch_pressed_count_;
int touch_moved_count_;
- int touch_stationary_count_;
int touch_cancelled_count_;
DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
@@ -679,21 +674,34 @@ class RemoveOnTouchCancelHandler : public TestEventHandler {
} // namespace
-class GestureRecognizerTest : public AuraTestBase {
+class GestureRecognizerTest : public AuraTestBase,
+ public ::testing::WithParamInterface<bool> {
public:
GestureRecognizerTest() {}
+ bool UsingUnifiedGR() {
+ return GetParam();
+ }
+
virtual void SetUp() OVERRIDE {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableScrollPrediction);
+ // TODO(tdresser): Once unified GR has landed, only run these tests once.
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kUnifiedGestureDetector,
+ UsingUnifiedGR() ? switches::kUnifiedGestureDetectorEnabled
+ : switches::kUnifiedGestureDetectorDisabled);
+
AuraTestBase::SetUp();
+ ui::GestureConfiguration::set_min_touch_down_duration_in_seconds_for_click(
+ 0.001);
+ ui::GestureConfiguration::set_show_press_delay_in_ms(2);
+ ui::GestureConfiguration::set_long_press_time_in_seconds(0.003);
}
DISALLOW_COPY_AND_ASSIGN(GestureRecognizerTest);
};
// Check that appropriate touch events generate tap gesture events.
-TEST_F(GestureRecognizerTest, GestureEventTap) {
+TEST_P(GestureRecognizerTest, GestureEventTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -707,7 +715,7 @@ TEST_F(GestureRecognizerTest, GestureEventTap) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->show_press());
EXPECT_TRUE(delegate->tap_down());
@@ -729,7 +737,7 @@ TEST_F(GestureRecognizerTest, GestureEventTap) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -744,7 +752,12 @@ TEST_F(GestureRecognizerTest, GestureEventTap) {
// Check that appropriate touch events generate tap gesture events
// when information about the touch radii are provided.
-TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
+TEST_P(GestureRecognizerTest, GestureEventTapRegion) {
+ // TODO(tdresser): enable this test with unified GR once we resolve the
+ // bounding box differences. See crbug.com/366641.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -762,7 +775,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.Now());
press.set_radius_x(5);
press.set_radius_y(12);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -780,7 +793,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
release.set_radius_x(5);
release.set_radius_y(12);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -805,7 +818,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.Now());
press.set_radius_x(8);
press.set_radius_y(14);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -821,7 +834,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
release.set_radius_x(20);
release.set_radius_y(13);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -846,7 +859,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.Now());
press.set_radius_x(6);
press.set_radius_y(10);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -862,7 +875,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.LeapForward(50));
move.set_radius_x(8);
move.set_radius_y(12);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -878,7 +891,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
release.set_radius_x(4);
release.set_radius_y(8);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -903,7 +916,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.Now());
press.set_radius_x(7);
press.set_radius_y(10);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -918,7 +931,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.LeapForward(50));
move.set_radius_x(13);
move.set_radius_y(12);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -933,7 +946,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.LeapForward(50));
move1.set_radius_x(16);
move1.set_radius_y(16);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+ DispatchEventUsingWindowDispatcher(&move1);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -948,7 +961,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
kTouchId, tes.LeapForward(50));
move2.set_radius_x(14);
move2.set_radius_y(10);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -964,7 +977,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
release.set_radius_x(8);
release.set_radius_y(9);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -984,7 +997,12 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) {
}
// Check that appropriate touch events generate scroll gesture events.
-TEST_F(GestureRecognizerTest, GestureEventScroll) {
+TEST_P(GestureRecognizerTest, GestureEventScroll) {
+ // We'll start by moving the touch point by (10.5, 10.5). We want 5 dips of
+ // that distance to be consumed by the slop, so we set the slop radius to
+ // sqrt(5 * 5 + 5 * 5).
+ ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(
+ sqrt(static_cast<double>(5 * 5 + 5 * 5)));
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -998,7 +1016,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_TAP_DOWN);
@@ -1007,13 +1025,15 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
// should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
// The first movement is diagonal, to ensure that we have a free scroll,
// and not a rail scroll.
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 111.5, 211.5, kTouchId,
+ delegate.get());
EXPECT_3_EVENTS(delegate->events(),
ui::ET_GESTURE_TAP_CANCEL,
ui::ET_GESTURE_SCROLL_BEGIN,
ui::ET_GESTURE_SCROLL_UPDATE);
- EXPECT_EQ(29, delegate->scroll_x());
- EXPECT_EQ(29, delegate->scroll_y());
+ // The slop consumed 5 dips
+ EXPECT_FLOAT_EQ(5.5, delegate->scroll_x());
+ EXPECT_FLOAT_EQ(5.5, delegate->scroll_y());
EXPECT_EQ(gfx::Point(1, 1).ToString(),
delegate->scroll_begin_position().ToString());
@@ -1021,14 +1041,15 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
// be empty, since it's a single point and the radius for testing is zero.
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
- // Move some more to generate a few more scroll updates.
- tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get());
+ // Move some more to generate a few more scroll updates. Make sure that we get
+ // out of the snap channel for the unified GR.
+ tes.SendScrollEvent(event_processor(), 20, 120, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
- EXPECT_EQ(-20, delegate->scroll_x());
- EXPECT_EQ(-19, delegate->scroll_y());
+ EXPECT_FLOAT_EQ(-91.5, delegate->scroll_x());
+ EXPECT_FLOAT_EQ(-91.5, delegate->scroll_y());
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
- tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 50, 124, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
EXPECT_EQ(30, delegate->scroll_x());
EXPECT_EQ(4, delegate->scroll_y());
@@ -1039,7 +1060,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId,
tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_SCROLL_FLING_START,
ui::ET_GESTURE_END);
@@ -1047,16 +1068,22 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) {
}
// Check that predicted scroll update positions are correct.
-TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) {
+TEST_P(GestureRecognizerTest, GestureEventScrollPrediction) {
const double prediction_interval = 0.03;
ui::GestureConfiguration::set_scroll_prediction_seconds(prediction_interval);
+ // We'll start by moving the touch point by (5, 5). We want all of that
+ // distance to be consumed by the slop, so we set the slop radius to
+ // sqrt(5 * 5 + 5 * 5).
+ ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(
+ sqrt(static_cast<double>(5 * 5 + 5 * 5)));
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId = 5;
- gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+ gfx::Rect bounds(95, 195, kWindowWidth, kWindowHeight);
scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
delegate.get(), -1234, bounds, root_window()));
@@ -1064,63 +1091,59 @@ TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) {
// Tracks the total scroll since we want to verify that the correct position
// will be scrolled to throughout the prediction.
gfx::Vector2dF total_scroll;
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(96, 196),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_TAP_DOWN);
+ delegate->Reset();
+
+ // Get rid of touch slop.
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(111, 211),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ EXPECT_3_EVENTS(delegate->events(),
+ ui::ET_GESTURE_TAP_CANCEL,
+ ui::ET_GESTURE_SCROLL_BEGIN,
+ ui::ET_GESTURE_SCROLL_UPDATE);
+ total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
+ total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
// Move the touch-point enough so that it is considered as a scroll. This
// should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
// The first movement is diagonal, to ensure that we have a free scroll,
// and not a rail scroll.
tes.LeapForward(30);
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
- EXPECT_3_EVENTS(delegate->events(),
- ui::ET_GESTURE_TAP_CANCEL,
- ui::ET_GESTURE_SCROLL_BEGIN,
- ui::ET_GESTURE_SCROLL_UPDATE);
- EXPECT_GT(delegate->scroll_velocity_x(), 0);
- EXPECT_GT(delegate->scroll_velocity_y(), 0);
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
+ EXPECT_1_EVENT(delegate->events(),
+ ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
- EXPECT_EQ((int)(29 + delegate->scroll_velocity_x() * prediction_interval),
- (int)(total_scroll.x()));
- EXPECT_EQ((int)(29 + delegate->scroll_velocity_y() * prediction_interval),
- (int)(total_scroll.y()));
// Move some more to generate a few more scroll updates.
tes.LeapForward(30);
- tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
- EXPECT_EQ((int)(9 + delegate->scroll_velocity_x() * prediction_interval),
- (int)(total_scroll.x()));
- EXPECT_EQ((int)(10 + delegate->scroll_velocity_y() * prediction_interval),
- (int)(total_scroll.y()));
tes.LeapForward(30);
- tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get());
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
total_scroll.set_y(total_scroll.y() + delegate->scroll_y());
- EXPECT_EQ((int)(39 + delegate->scroll_velocity_x() * prediction_interval),
- (int)(total_scroll.x()));
- EXPECT_EQ((int)(14 + delegate->scroll_velocity_y() * prediction_interval),
- (int)(total_scroll.y()));
// Release the touch. This should end the scroll.
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId,
tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
}
// Check that the bounding box during a scroll event is correct.
-TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
+TEST_P(GestureRecognizerTest, GestureEventScrollBoundingBox) {
TimedEvents tes;
for (int radius = 1; radius <= 10; ++radius) {
ui::GestureConfiguration::set_default_radius(radius);
@@ -1140,7 +1163,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
gfx::Point(kPositionX, kPositionY),
kTouchId,
tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_EQ(gfx::Rect(kPositionX - radius,
kPositionY - radius,
radius * 2,
@@ -1148,7 +1171,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
delegate->bounding_box().ToString());
const int kScrollAmount = 50;
- tes.SendScrollEvents(dispatcher(), kPositionX, kPositionY,
+ tes.SendScrollEvents(event_processor(), kPositionX, kPositionY,
1, 1, kTouchId, 1, kScrollAmount, delegate.get());
EXPECT_EQ(gfx::Point(1, 1).ToString(),
delegate->scroll_begin_position().ToString());
@@ -1165,7 +1188,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
kPositionY + kScrollAmount),
kTouchId, press.time_stamp() +
base::TimeDelta::FromMilliseconds(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_EQ(gfx::Rect(kPositionX + kScrollAmount - radius,
kPositionY + kScrollAmount - radius,
radius * 2,
@@ -1177,7 +1200,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) {
// Check Scroll End Events report correct velocities
// if the user was on a horizontal rail
-TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) {
+TEST_P(GestureRecognizerTest, GestureEventHorizontalRailFling) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1188,30 +1211,31 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
+
+ // Get rid of touch slop.
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 0),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->Reset();
+
// Move the touch-point horizontally enough that it is considered a
// horizontal scroll.
- tes.SendScrollEvent(dispatcher(), 20, 1, kTouchId, delegate.get());
- EXPECT_EQ(0, delegate->scroll_y());
- EXPECT_EQ(1, delegate->scroll_y_ordinal());
- EXPECT_EQ(20, delegate->scroll_x());
- EXPECT_EQ(20, delegate->scroll_x_ordinal());
+ tes.SendScrollEvent(event_processor(), 30, 1, kTouchId, delegate.get());
+ EXPECT_FLOAT_EQ(0, delegate->scroll_y());
+ EXPECT_FLOAT_EQ(20, delegate->scroll_x());
// Get a high x velocity, while still staying on the rail
- tes.SendScrollEvents(dispatcher(), 1, 1,
+ tes.SendScrollEvents(event_processor(), 1, 1,
100, 10, kTouchId, 1,
ui::GestureConfiguration::points_buffered_for_velocity(),
delegate.get());
- // The y-velocity during the scroll should be 0 since this is in a horizontal
- // rail scroll.
- EXPECT_GT(delegate->scroll_velocity_x(), 0);
- EXPECT_EQ(0, delegate->scroll_velocity_y());
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->fling());
EXPECT_FALSE(delegate->scroll_end());
@@ -1221,7 +1245,7 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) {
// Check Scroll End Events report correct velocities
// if the user was on a vertical rail
-TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) {
+TEST_P(GestureRecognizerTest, GestureEventVerticalRailFling) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1232,30 +1256,32 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
+
+ // Get rid of touch slop.
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 10),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->Reset();
// Move the touch-point vertically enough that it is considered a
// vertical scroll.
- tes.SendScrollEvent(dispatcher(), 1, 20, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 1, 30, kTouchId, delegate.get());
EXPECT_EQ(20, delegate->scroll_y());
- EXPECT_EQ(20, delegate->scroll_y_ordinal());
EXPECT_EQ(0, delegate->scroll_x());
- EXPECT_EQ(1, delegate->scroll_x_ordinal());
EXPECT_EQ(0, delegate->scroll_velocity_x());
- EXPECT_GT(delegate->scroll_velocity_x_ordinal(), 0);
// Get a high y velocity, while still staying on the rail
- tes.SendScrollEvents(dispatcher(), 1, 1,
+ tes.SendScrollEvents(event_processor(), 1, 6,
10, 100, kTouchId, 1,
ui::GestureConfiguration::points_buffered_for_velocity(),
delegate.get());
EXPECT_EQ(0, delegate->scroll_velocity_x());
- EXPECT_GT(delegate->scroll_velocity_y(), 0);
delegate->Reset();
- ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 206),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->fling());
EXPECT_FALSE(delegate->scroll_end());
@@ -1263,9 +1289,10 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) {
EXPECT_GT(delegate->velocity_y(), 0);
}
-// Check Scroll End Events reports zero velocities
-// if the user is not on a rail
-TEST_F(GestureRecognizerTest, GestureEventNonRailFling) {
+// Check Scroll End Events report non-zero velocities if the user is not on a
+// rail
+TEST_P(GestureRecognizerTest, GestureEventNonRailFling) {
+ ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(0);
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1276,14 +1303,15 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
- // Move the touch-point such that a non-rail scroll begins
- tes.SendScrollEvent(dispatcher(), 20, 20, kTouchId, delegate.get());
- EXPECT_EQ(20, delegate->scroll_y());
- EXPECT_EQ(20, delegate->scroll_x());
+ // Move the touch-point such that a non-rail scroll begins, and we're outside
+ // the snap channel for the unified GR.
+ tes.SendScrollEvent(event_processor(), 50, 50, kTouchId, delegate.get());
+ EXPECT_EQ(50, delegate->scroll_y());
+ EXPECT_EQ(50, delegate->scroll_x());
- tes.SendScrollEvents(dispatcher(), 1, 1,
+ tes.SendScrollEvents(event_processor(), 1, 1,
10, 100, kTouchId, 1,
ui::GestureConfiguration::points_buffered_for_velocity(),
delegate.get());
@@ -1291,7 +1319,7 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->fling());
EXPECT_FALSE(delegate->scroll_end());
@@ -1300,10 +1328,12 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) {
}
// Check that appropriate touch events generate long press events
-TEST_F(GestureRecognizerTest, GestureEventLongPress) {
+TEST_P(GestureRecognizerTest, GestureEventLongPress) {
+ ui::GestureConfiguration::set_max_touch_down_duration_in_seconds_for_click(
+ 0.0025);
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
- TimedEvents tes;
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId = 2;
@@ -1318,9 +1348,11 @@ TEST_F(GestureRecognizerTest, GestureEventLongPress) {
ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
- ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
- kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
+ gfx::Point(101, 201),
+ kTouchId,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
EXPECT_TRUE(delegate->begin());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1331,25 +1363,26 @@ TEST_F(GestureRecognizerTest, GestureEventLongPress) {
// Wait until the timer runs out
delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
EXPECT_TRUE(delegate->long_press());
- EXPECT_EQ(0, delegate->touch_id());
EXPECT_FALSE(delegate->tap_cancel());
delegate->Reset();
- ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
- kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ ui::TouchEvent release1(ui::ET_TOUCH_RELEASED,
+ gfx::Point(101, 201),
+ kTouchId,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->long_press());
- // Note the tap down isn't cancelled until the release
+ // Note the tap cancel isn't dispatched until the release
EXPECT_TRUE(delegate->tap_cancel());
+ EXPECT_FALSE(delegate->tap());
}
// Check that scrolling cancels a long press
-TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
+TEST_P(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
- ui::GestureConfiguration::set_long_press_time_in_seconds(.01);
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId = 6;
@@ -1369,7 +1402,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
// We haven't pressed long enough for a long press to occur
@@ -1377,7 +1410,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
EXPECT_FALSE(delegate->tap_cancel());
// Scroll around, to cancel the long press
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
// Wait until the timer runs out
gesture_sequence->ForceTimeout();
EXPECT_FALSE(delegate->long_press());
@@ -1386,16 +1419,17 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(10));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->long_press());
EXPECT_FALSE(delegate->tap_cancel());
}
// Check that appropriate touch events generate long tap events
-TEST_F(GestureRecognizerTest, GestureEventLongTap) {
+TEST_P(GestureRecognizerTest, GestureEventLongTap) {
+ ui::GestureConfiguration::set_max_touch_down_duration_in_seconds_for_click(
+ 0.0025);
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
- TimedEvents tes;
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId = 2;
@@ -1410,9 +1444,11 @@ TEST_F(GestureRecognizerTest, GestureEventLongTap) {
ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
- ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
- kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
+ gfx::Point(101, 201),
+ kTouchId,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
EXPECT_TRUE(delegate->begin());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1423,26 +1459,27 @@ TEST_F(GestureRecognizerTest, GestureEventLongTap) {
// Wait until the timer runs out
delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
EXPECT_TRUE(delegate->long_press());
- EXPECT_EQ(0, delegate->touch_id());
EXPECT_FALSE(delegate->tap_cancel());
delegate->Reset();
- ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
- kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ ui::TouchEvent release1(ui::ET_TOUCH_RELEASED,
+ gfx::Point(101, 201),
+ kTouchId,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->long_press());
EXPECT_TRUE(delegate->long_tap());
- // Note the tap down isn't cancelled until the release
+ // Note the tap cancel isn't dispatched until the release
EXPECT_TRUE(delegate->tap_cancel());
+ EXPECT_FALSE(delegate->tap());
}
// Check that second tap cancels a long press
-TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
+TEST_P(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
- ui::GestureConfiguration::set_long_press_time_in_seconds(.01);
const int kWindowWidth = 300;
const int kWindowHeight = 400;
const int kTouchId1 = 8;
@@ -1462,7 +1499,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_TRUE(delegate->tap_down());
EXPECT_TRUE(delegate->begin());
@@ -1473,7 +1510,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap.
EXPECT_TRUE(delegate->tap_cancel());
EXPECT_TRUE(delegate->begin());
@@ -1487,7 +1524,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->long_press());
EXPECT_TRUE(delegate->two_finger_tap());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1495,7 +1532,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) {
// Check that horizontal scroll gestures cause scrolls on horizontal rails.
// Also tests that horizontal rails can be broken.
-TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
+TEST_P(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1506,15 +1543,22 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
+
+ // Get rid of touch slop.
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(5, 0),
+ kTouchId, tes.Now());
+
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->Reset();
// Move the touch-point horizontally enough that it is considered a
// horizontal scroll.
- tes.SendScrollEvent(dispatcher(), 20, 1, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 25, 0, kTouchId, delegate.get());
EXPECT_EQ(0, delegate->scroll_y());
EXPECT_EQ(20, delegate->scroll_x());
- tes.SendScrollEvent(dispatcher(), 25, 6, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 30, 6, kTouchId, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
EXPECT_EQ(5, delegate->scroll_x());
// y shouldn't change, as we're on a horizontal rail.
@@ -1522,17 +1566,13 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
// Send enough information that a velocity can be calculated for the gesture,
// and we can break the rail
- tes.SendScrollEvents(dispatcher(), 1, 1,
- 1, 100, kTouchId, 1,
+ tes.SendScrollEvents(event_processor(), 1, 1,
+ 6, 100, kTouchId, 1,
ui::GestureConfiguration::points_buffered_for_velocity(),
delegate.get());
- // Since the scroll is not longer railing, the velocity should be set for both
- // axis.
- EXPECT_GT(delegate->scroll_velocity_x(), 0);
- EXPECT_GT(delegate->scroll_velocity_y(), 0);
- tes.SendScrollEvent(dispatcher(), 0, 0, kTouchId, delegate.get());
- tes.SendScrollEvent(dispatcher(), 5, 5, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 5, 0, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 10, 5, kTouchId, delegate.get());
// The rail should be broken
EXPECT_TRUE(delegate->scroll_update());
@@ -1542,7 +1582,7 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) {
// Check that vertical scroll gestures cause scrolls on vertical rails.
// Also tests that vertical rails can be broken.
-TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
+TEST_P(GestureRecognizerTest, GestureEventVerticalRailScroll) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1553,15 +1593,21 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
+
+ // Get rid of touch slop.
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 5),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->Reset();
// Move the touch-point vertically enough that it is considered a
// vertical scroll.
- tes.SendScrollEvent(dispatcher(), 1, 20, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 0, 25, kTouchId, delegate.get());
EXPECT_EQ(0, delegate->scroll_x());
EXPECT_EQ(20, delegate->scroll_y());
- tes.SendScrollEvent(dispatcher(), 6, 25, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 6, 30, kTouchId, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
EXPECT_EQ(5, delegate->scroll_y());
// x shouldn't change, as we're on a vertical rail.
@@ -1570,15 +1616,13 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
// Send enough information that a velocity can be calculated for the gesture,
// and we can break the rail
- tes.SendScrollEvents(dispatcher(), 1, 1,
+ tes.SendScrollEvents(event_processor(), 1, 6,
100, 1, kTouchId, 1,
ui::GestureConfiguration::points_buffered_for_velocity(),
delegate.get());
- EXPECT_GT(delegate->scroll_velocity_x(), 0);
- EXPECT_GT(delegate->scroll_velocity_y(), 0);
- tes.SendScrollEvent(dispatcher(), 0, 0, kTouchId, delegate.get());
- tes.SendScrollEvent(dispatcher(), 5, 5, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 0, 5, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 5, 10, kTouchId, delegate.get());
// The rail should be broken
EXPECT_TRUE(delegate->scroll_update());
@@ -1586,7 +1630,13 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) {
EXPECT_EQ(5, delegate->scroll_y());
}
-TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
+TEST_P(GestureRecognizerTest, GestureTapFollowedByScroll) {
+ // We'll start by moving the touch point by (5, 5). We want all of that
+ // distance to be consumed by the slop, so we set the slop radius to
+ // sqrt(5 * 5 + 5 * 5).
+ ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(
+ sqrt(static_cast<double>(5 * 5 + 5 * 5)));
+
// First, tap. Then, do a scroll using the same touch-id.
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
@@ -1601,7 +1651,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1614,7 +1664,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1627,7 +1677,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(1000));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1635,28 +1685,40 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
EXPECT_FALSE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
+ // Get rid of touch slop.
+ ui::TouchEvent move_remove_slop(ui::ET_TOUCH_MOVED, gfx::Point(116, 216),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move_remove_slop);
+ EXPECT_TRUE(delegate->tap_cancel());
+ EXPECT_TRUE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_update());
+ EXPECT_EQ(15, delegate->scroll_x_hint());
+ EXPECT_EQ(15, delegate->scroll_y_hint());
+
+ delegate->Reset();
+
// Move the touch-point enough so that it is considered as a scroll. This
// should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
// The first movement is diagonal, to ensure that we have a free scroll,
// and not a rail scroll.
delegate->Reset();
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 230),
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(135, 235),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
- EXPECT_TRUE(delegate->tap_cancel());
- EXPECT_TRUE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->tap_cancel());
+ EXPECT_FALSE(delegate->scroll_begin());
EXPECT_TRUE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
- EXPECT_EQ(29, delegate->scroll_x());
- EXPECT_EQ(29, delegate->scroll_y());
+ EXPECT_EQ(19, delegate->scroll_x());
+ EXPECT_EQ(19, delegate->scroll_y());
// Move some more to generate a few more scroll updates.
delegate->Reset();
- ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(110, 211),
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(115, 216),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+ DispatchEventUsingWindowDispatcher(&move1);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1665,11 +1727,13 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
EXPECT_FALSE(delegate->scroll_end());
EXPECT_EQ(-20, delegate->scroll_x());
EXPECT_EQ(-19, delegate->scroll_y());
+ EXPECT_EQ(0, delegate->scroll_x_hint());
+ EXPECT_EQ(0, delegate->scroll_y_hint());
delegate->Reset();
- ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(140, 215),
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(145, 220),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1683,7 +1747,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1693,9 +1757,9 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) {
EXPECT_TRUE(delegate->fling());
}
-TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
+TEST_P(GestureRecognizerTest, AsynchronousGestureRecognition) {
scoped_ptr<QueueTouchEventDelegate> queued_delegate(
- new QueueTouchEventDelegate(dispatcher()));
+ new QueueTouchEventDelegate(host()->dispatcher()));
const int kWindowWidth = 123;
const int kWindowHeight = 45;
const int kTouchId1 = 6;
@@ -1710,7 +1774,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
queued_delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(queued_delegate->tap());
EXPECT_FALSE(queued_delegate->tap_down());
EXPECT_FALSE(queued_delegate->tap_cancel());
@@ -1725,7 +1789,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, press.time_stamp() +
base::TimeDelta::FromMilliseconds(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(queued_delegate->tap());
EXPECT_FALSE(queued_delegate->tap_down());
EXPECT_FALSE(queued_delegate->tap_cancel());
@@ -1744,7 +1808,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 20),
kTouchId2, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1756,7 +1820,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20),
kTouchId2, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
// Process the first queued event.
queued_delegate->Reset();
@@ -1787,7 +1851,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
queued_delegate->Reset();
ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3);
+ DispatchEventUsingWindowDispatcher(&press3);
EXPECT_FALSE(queued_delegate->tap());
EXPECT_FALSE(queued_delegate->tap_down());
EXPECT_FALSE(queued_delegate->tap_cancel());
@@ -1803,7 +1867,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
delegate->Reset();
ui::TouchEvent press4(ui::ET_TOUCH_PRESSED, gfx::Point(103, 203),
kTouchId2, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press4);
+ DispatchEventUsingWindowDispatcher(&press4);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1826,9 +1890,9 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
queued_delegate->Reset();
delegate->Reset();
int x_move = ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(103 + x_move, 203),
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(203 + x_move, 303),
kTouchId2, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -1877,7 +1941,8 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
EXPECT_FALSE(queued_delegate->begin());
EXPECT_FALSE(queued_delegate->end());
EXPECT_TRUE(queued_delegate->scroll_begin());
- EXPECT_FALSE(queued_delegate->scroll_update());
+ // TODO(tdresser): uncomment once we've switched to the unified GR.
+ // EXPECT_TRUE(queued_delegate->scroll_update());
EXPECT_FALSE(queued_delegate->scroll_end());
EXPECT_TRUE(queued_delegate->pinch_begin());
EXPECT_FALSE(queued_delegate->pinch_update());
@@ -1885,7 +1950,12 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) {
}
// Check that appropriate touch events generate pinch gesture events.
-TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
+TEST_P(GestureRecognizerTest, GestureEventPinchFromScroll) {
+ // Disabled for unified GR due to differences in when pinch begin is sent. The
+ // Aura GR sends it earlier than is necessary.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1897,12 +1967,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
delegate.get(), -1234, bounds, root_window()));
- aura::RootWindow* root = dispatcher();
-
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_TAP_DOWN);
@@ -1912,7 +1980,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 301),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_3_EVENTS(delegate->events(),
ui::ET_GESTURE_TAP_CANCEL,
ui::ET_GESTURE_SCROLL_BEGIN,
@@ -1923,7 +1991,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_PINCH_BEGIN);
@@ -1934,7 +2002,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(95, 201),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3);
+ DispatchEventUsingWindowDispatcher(&move3);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_PINCH_UPDATE,
ui::ET_GESTURE_SCROLL_UPDATE);
@@ -1945,7 +2013,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4);
+ DispatchEventUsingWindowDispatcher(&move4);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_PINCH_UPDATE,
ui::ET_GESTURE_SCROLL_UPDATE);
@@ -1956,7 +2024,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_PINCH_END,
ui::ET_GESTURE_END);
@@ -1967,12 +2035,12 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) {
delegate->Reset();
ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move5);
+ DispatchEventUsingWindowDispatcher(&move5);
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
}
-TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) {
+TEST_P(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -1986,20 +2054,20 @@ scoped_ptr<GestureEventConsumeDelegate> delegate(
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->pinch_begin());
// Touch move triggers pinch begin.
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get());
EXPECT_TRUE(delegate->pinch_begin());
EXPECT_FALSE(delegate->pinch_update());
// Touch move triggers pinch update.
- tes.SendScrollEvent(dispatcher(), 160, 200, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 160, 200, kTouchId1, delegate.get());
EXPECT_FALSE(delegate->pinch_begin());
EXPECT_TRUE(delegate->pinch_update());
@@ -2007,29 +2075,33 @@ scoped_ptr<GestureEventConsumeDelegate> delegate(
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_TRUE(delegate->pinch_end());
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId2, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId2, delegate.get());
EXPECT_TRUE(delegate->scroll_update());
// Pinch again
delegate->Reset();
ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3);
+ DispatchEventUsingWindowDispatcher(&press3);
// Now the touch points are close. So we will go into two finger tap.
// Move the touch-point enough to break two-finger-tap and enter pinch.
- ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 202),
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 50),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_TRUE(delegate->pinch_begin());
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 350, 350, kTouchId1, delegate.get());
EXPECT_TRUE(delegate->pinch_update());
}
-TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
+TEST_P(GestureRecognizerTest, GestureEventPinchFromTap) {
+ // TODO(tdresser): enable this test with unified GR once two finger tap.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -2041,12 +2113,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
delegate.get(), -1234, bounds, root_window()));
- aura::RootWindow* root = dispatcher();
-
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_TAP_DOWN);
@@ -2056,7 +2126,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_TAP_CANCEL,
ui::ET_GESTURE_BEGIN);
@@ -2067,10 +2137,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
delegate->Reset();
ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(65, 201),
kTouchId1, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3);
+ DispatchEventUsingWindowDispatcher(&move3);
EXPECT_2_EVENTS(delegate->events(),
- ui::ET_GESTURE_PINCH_BEGIN,
- ui::ET_GESTURE_SCROLL_BEGIN);
+ ui::ET_GESTURE_SCROLL_BEGIN,
+ ui::ET_GESTURE_PINCH_BEGIN);
EXPECT_EQ(gfx::Rect(10, 10, 55, 191).ToString(),
delegate->bounding_box().ToString());
@@ -2078,7 +2148,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
delegate->Reset();
ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4);
+ DispatchEventUsingWindowDispatcher(&move4);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_PINCH_UPDATE,
ui::ET_GESTURE_SCROLL_UPDATE);
@@ -2089,7 +2159,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.LeapForward(10));
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_2_EVENTS(delegate->events(),
ui::ET_GESTURE_PINCH_END,
ui::ET_GESTURE_END);
@@ -2100,26 +2170,26 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) {
delegate->Reset();
ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10),
kTouchId2, tes.Now());
- root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move5);
+ DispatchEventUsingWindowDispatcher(&move5);
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
}
-TEST_F(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) {
+TEST_P(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
6, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
}
// Check that a touch is locked to the window of the closest current touch
// within max_separation_for_gesture_touches_in_pixels
-TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
+TEST_P(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
ui::GestureRecognizer* gesture_recognizer = new ui::GestureRecognizerImpl();
TimedEvents tes;
ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
@@ -2150,50 +2220,50 @@ TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
windows[i]->set_id(i);
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, window_bounds[i].origin(),
i, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
}
// Touches should now be associated with the closest touch within
// ui::GestureConfiguration::max_separation_for_gesture_touches_in_pixels
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 11));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 11), -1);
EXPECT_EQ("0", WindowIDAsString(target));
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 11));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 11), -1);
EXPECT_EQ("1", WindowIDAsString(target));
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 511));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 511), -1);
EXPECT_EQ("2", WindowIDAsString(target));
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 511));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 511), -1);
EXPECT_EQ("3", WindowIDAsString(target));
// Add a touch in the middle associated with windows[2]
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 500),
kNumWindows, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(250, 250),
kNumWindows, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(250, 250));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(250, 250), -1);
EXPECT_EQ("2", WindowIDAsString(target));
// Make sure that ties are broken by distance to a current touch
// Closer to the point in the bottom right.
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(380, 380));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(380, 380), -1);
EXPECT_EQ("3", WindowIDAsString(target));
// This touch is closer to the point in the middle
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(300, 300));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(300, 300), -1);
EXPECT_EQ("2", WindowIDAsString(target));
// A touch too far from other touches won't be locked to anything
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000), -1);
EXPECT_TRUE(target == NULL);
// Move a touch associated with windows[2] to 1000, 1000
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(1000, 1000),
kNumWindows, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
- target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000));
+ target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000), -1);
EXPECT_EQ("2", WindowIDAsString(target));
for (int i = 0; i < kNumWindows; ++i) {
@@ -2203,9 +2273,43 @@ TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) {
}
}
+// Check that a touch's target will not be effected by a touch on a different
+// screen.
+TEST_P(GestureRecognizerTest, GestureEventTouchLockIgnoresOtherScreens) {
+ scoped_ptr<GestureEventConsumeDelegate> delegate(
+ new GestureEventConsumeDelegate());
+ gfx::Rect bounds(0, 0, 10, 10);
+ scoped_ptr<aura::Window> window(
+ CreateTestWindowWithDelegate(delegate.get(), 0, bounds, root_window()));
+
+ const int kTouchId1 = 8;
+ const int kTouchId2 = 2;
+ TimedEvents tes;
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(5, 5),
+ kTouchId1, tes.Now());
+ press1.set_source_device_id(1);
+ DispatchEventUsingWindowDispatcher(&press1);
+
+ ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20),
+ kTouchId2, tes.Now());
+ press2.set_source_device_id(2);
+ DispatchEventUsingWindowDispatcher(&press2);
+
+ // The second press should not have been locked to the same target as the
+ // first, as they occured on different displays.
+ EXPECT_NE(
+ ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1),
+ ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2));
+}
+
// Check that touch events outside the root window are still handled
// by the root window's gesture sequence.
-TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
+TEST_P(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
+ // TODO(tdresser): write a version of this test for the unified GR.
+ if (UsingUnifiedGR())
+ return;
+
TestGestureRecognizer* gesture_recognizer =
new TestGestureRecognizer();
TimedEvents tes;
@@ -2222,11 +2326,11 @@ TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
gfx::Point pos1(-10, -10);
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, pos1, 0, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
gfx::Point pos2(1000, 1000);
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, pos2, 1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
// As these presses were outside the root window, they should be
// associated with the root window.
@@ -2234,9 +2338,9 @@ TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
EXPECT_EQ(2, root_window_gesture_sequence->point_count());
}
-TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) {
+TEST_P(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) {
scoped_ptr<QueueTouchEventDelegate> delegate(
- new QueueTouchEventDelegate(dispatcher()));
+ new QueueTouchEventDelegate(host()->dispatcher()));
TimedEvents tes;
const int kTouchId = 2;
gfx::Rect bounds(100, 200, 100, 100);
@@ -2247,10 +2351,10 @@ TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
delegate->Reset();
delegate->ReceivedAck();
@@ -2261,9 +2365,14 @@ TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) {
EXPECT_TRUE(delegate->tap_cancel());
}
-TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) {
+TEST_P(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) {
+ // Disabled for unified GR due to differences in when pinch begin is sent. The
+ // Aura GR sends it earlier than is necessary.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<QueueTouchEventDelegate> delegate(
- new QueueTouchEventDelegate(dispatcher()));
+ new QueueTouchEventDelegate(host()->dispatcher()));
TimedEvents tes;
const int kTouchId1 = 7;
const int kTouchId2 = 5;
@@ -2280,9 +2389,9 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) {
tes.LeapForward(200));
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(15, 25), kTouchId1,
tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&press);
+ DispatchEventUsingWindowDispatcher(&move);
+ DispatchEventUsingWindowDispatcher(&release);
delegate->Reset();
// Ack the press event.
@@ -2316,12 +2425,12 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) {
tes.LeapForward(14));
// Do a pinch.
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&press);
+ DispatchEventUsingWindowDispatcher(&move);
+ DispatchEventUsingWindowDispatcher(&press2);
+ DispatchEventUsingWindowDispatcher(&move2);
+ DispatchEventUsingWindowDispatcher(&release);
+ DispatchEventUsingWindowDispatcher(&release2);
// Ack the press and move events.
delegate->Reset();
@@ -2355,7 +2464,25 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) {
EXPECT_TRUE(delegate->end());
}
-TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd) {
+TEST_P(GestureRecognizerTest, GestureEndLocation) {
+ GestureEventConsumeDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, -1234, gfx::Rect(10, 10, 300, 300), root_window()));
+ EventGenerator generator(root_window(), window.get());
+ const gfx::Point begin(20, 20);
+ const gfx::Point end(150, 150);
+ const gfx::Vector2d window_offset =
+ window->bounds().origin().OffsetFromOrigin();
+ generator.GestureScrollSequence(begin, end,
+ base::TimeDelta::FromMilliseconds(20),
+ 10);
+ EXPECT_EQ((begin - window_offset).ToString(),
+ delegate.scroll_begin_position().ToString());
+ EXPECT_EQ((end - window_offset).ToString(),
+ delegate.gesture_end_location().ToString());
+}
+
+TEST_P(GestureRecognizerTest, CaptureSendsGestureEnd) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TestGestureRecognizer* gesture_recognizer =
@@ -2384,7 +2511,7 @@ TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd) {
// Check that previous touch actions that are completely finished (either
// released or cancelled), do not receive extra synthetic cancels upon change of
// capture.
-TEST_F(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) {
+TEST_P(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
scoped_ptr<TestEventHandler> handler(new TestEventHandler);
@@ -2437,7 +2564,8 @@ TEST_F(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) {
root_window()->RemovePreTargetHandler(handler.get());
}
-TEST_F(GestureRecognizerTest, PressDoesNotCrash) {
+// Tests that a press with the same touch id as an existing touch is ignored.
+TEST_P(GestureRecognizerTest, PressDoesNotCrash) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TestGestureRecognizer* gesture_recognizer =
@@ -2450,14 +2578,14 @@ TEST_F(GestureRecognizerTest, PressDoesNotCrash) {
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(45, 45), 7, tes.Now());
press.set_radius_x(40);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_TRUE(delegate->tap_down());
EXPECT_EQ(gfx::Rect(5, 5, 80, 80).ToString(),
delegate->bounding_box().ToString());
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(55, 45), 7, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
// This new press should not generate a tap-down.
EXPECT_FALSE(delegate->begin());
@@ -2466,7 +2594,12 @@ TEST_F(GestureRecognizerTest, PressDoesNotCrash) {
EXPECT_FALSE(delegate->scroll_begin());
}
-TEST_F(GestureRecognizerTest, TwoFingerTap) {
+TEST_P(GestureRecognizerTest, TwoFingerTap) {
+ // TODO(tdresser): enable this test with unified GR once two finger tap is
+ // supported. See crbug.com/354396.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2481,7 +2614,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2494,7 +2627,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap.
EXPECT_TRUE(delegate->tap_cancel());
@@ -2508,10 +2641,10 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
delegate->Reset();
ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(102, 202),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+ DispatchEventUsingWindowDispatcher(&move1);
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(131, 202),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2527,11 +2660,11 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
- EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_begin());
EXPECT_FALSE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
EXPECT_TRUE(delegate->two_finger_tap());
@@ -2543,7 +2676,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2554,7 +2687,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) {
EXPECT_FALSE(delegate->two_finger_tap());
}
-TEST_F(GestureRecognizerTest, TwoFingerTapExpired) {
+TEST_P(GestureRecognizerTest, TwoFingerTapExpired) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2569,19 +2702,19 @@ TEST_F(GestureRecognizerTest, TwoFingerTapExpired) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
// Send release event after sufficient delay so that two finger time expires.
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.LeapForward(1000));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->two_finger_tap());
// Lift second finger.
@@ -2591,11 +2724,11 @@ TEST_F(GestureRecognizerTest, TwoFingerTapExpired) {
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_FALSE(delegate->two_finger_tap());
}
-TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
+TEST_P(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2613,14 +2746,14 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 230, 330, kTouchId1, delegate.get());
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_begin());
@@ -2630,7 +2763,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_end());
}
@@ -2644,14 +2777,14 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
- tes.SendScrollEvent(dispatcher(), 101, 230, kTouchId2, delegate.get());
+ tes.SendScrollEvent(event_processor(), 301, 230, kTouchId2, delegate.get());
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_begin());
@@ -2661,13 +2794,18 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_end());
}
}
-TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) {
+TEST_P(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) {
+ // Disabled for unified GR due to differences in when pinch begin is sent. The
+ // Aura GR sends it earlier than is necessary.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2683,13 +2821,13 @@ TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get());
+ DispatchEventUsingWindowDispatcher(&press1);
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get());
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_TRUE(delegate->pinch_begin());
@@ -2699,12 +2837,12 @@ TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->two_finger_tap());
EXPECT_TRUE(delegate->pinch_end());
}
-TEST_F(GestureRecognizerTest, MultiFingerSwipe) {
+TEST_P(GestureRecognizerTest, MultiFingerSwipe) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2725,26 +2863,33 @@ TEST_F(GestureRecognizerTest, MultiFingerSwipe) {
aura::test::EventGenerator generator(root_window(), window.get());
+ // The unified gesture recognizer assumes a finger has stopped if it hasn't
+ // moved for too long. See ui/events/gesture_detection/velocity_tracker.cc's
+ // kAssumePointerStoppedTimeMs.
for (int count = 2; count <= kTouchPoints; ++count) {
- generator.GestureMultiFingerScroll(count, points, 15, kSteps, 0, -150);
+ generator.GestureMultiFingerScroll(
+ count, points, 10, kSteps, 0, -11 * kSteps);
EXPECT_TRUE(delegate->swipe_up());
delegate->Reset();
- generator.GestureMultiFingerScroll(count, points, 15, kSteps, 0, 150);
+ generator.GestureMultiFingerScroll(
+ count, points, 10, kSteps, 0, 11 * kSteps);
EXPECT_TRUE(delegate->swipe_down());
delegate->Reset();
- generator.GestureMultiFingerScroll(count, points, 15, kSteps, -150, 0);
+ generator.GestureMultiFingerScroll(
+ count, points, 10, kSteps, -11 * kSteps, 0);
EXPECT_TRUE(delegate->swipe_left());
delegate->Reset();
- generator.GestureMultiFingerScroll(count, points, 15, kSteps, 150, 0);
+ generator.GestureMultiFingerScroll(
+ count, points, 10, kSteps, 11 * kSteps, 0);
EXPECT_TRUE(delegate->swipe_right());
delegate->Reset();
}
}
-TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) {
+TEST_P(GestureRecognizerTest, TwoFingerTapCancelled) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -2762,17 +2907,17 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
delegate->Reset();
ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&cancel);
+ DispatchEventUsingWindowDispatcher(&cancel);
EXPECT_FALSE(delegate->two_finger_tap());
// Make sure there is enough delay before the touch is released so that it
@@ -2781,7 +2926,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->two_finger_tap());
}
@@ -2794,17 +2939,17 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
delegate->Reset();
ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&cancel);
+ DispatchEventUsingWindowDispatcher(&cancel);
EXPECT_FALSE(delegate->two_finger_tap());
// Make sure there is enough delay before the touch is released so that it
@@ -2813,12 +2958,18 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) {
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId1, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->two_finger_tap());
}
}
-TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
+TEST_P(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
+ // Disabled for unified GR due to differences in when scroll update is
+ // sent. The Aura GR will never send a ScrollUpdate with a ScrollBegin, but
+ // the unified GR will.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 523;
@@ -2833,7 +2984,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2846,7 +2997,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
delegate->Reset();
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(430, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap.
EXPECT_TRUE(delegate->tap_cancel());
@@ -2860,7 +3011,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
delegate->Reset();
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(530, 301),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2875,7 +3026,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) {
// Verifies if a window is the target of multiple touch-ids and we hide the
// window everything is cleaned up correctly.
-TEST_F(GestureRecognizerTest, FlushAllOnHide) {
+TEST_P(GestureRecognizerTest, FlushAllOnHide) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
gfx::Rect bounds(0, 0, 200, 200);
@@ -2887,10 +3038,10 @@ TEST_F(GestureRecognizerTest, FlushAllOnHide) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
window->Hide();
EXPECT_EQ(NULL,
ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1));
@@ -2898,9 +3049,13 @@ TEST_F(GestureRecognizerTest, FlushAllOnHide) {
ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2));
}
-TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
+TEST_P(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
+ // TODO(tdresser): write a version of this test for the unified GR.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<QueueTouchEventDelegate> delegate(
- new QueueTouchEventDelegate(dispatcher()));
+ new QueueTouchEventDelegate(host()->dispatcher()));
const int kTouchId = 2;
gfx::Rect bounds(100, 200, 100, 100);
scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
@@ -2919,9 +3074,9 @@ TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
// Scroll around, to cancel the long press
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
delegate->Reset();
delegate->ReceivedAck();
@@ -2958,7 +3113,7 @@ class ConsumesTouchMovesDelegate : public GestureEventConsumeDelegate {
// Same as GestureEventScroll, but tests that the behavior is the same
// even if all the touch-move events are consumed.
-TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
+TEST_P(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
scoped_ptr<ConsumesTouchMovesDelegate> delegate(
new ConsumesTouchMovesDelegate());
const int kWindowWidth = 123;
@@ -2972,7 +3127,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -2984,7 +3139,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
// Move the touch-point enough so that it would normally be considered a
// scroll. But since the touch-moves will be consumed, the scroll should not
// start.
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -2998,7 +3153,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(130, 230),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3010,7 +3165,12 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) {
}
// Tests the behavior of 2F scroll when all the touch-move events are consumed.
-TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
+TEST_P(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
+ // TODO(tdresser): enable this test with unified GR once two finger tap is
+ // supported. See crbug.com/354396.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<ConsumesTouchMovesDelegate> delegate(
new ConsumesTouchMovesDelegate());
const int kWindowWidth = 123;
@@ -3026,8 +3186,8 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
delegate->Reset();
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
- tes.SendScrollEvent(dispatcher(), 131, 231, kTouchId1, delegate.get());
+ DispatchEventUsingWindowDispatcher(&press1);
+ tes.SendScrollEvent(event_processor(), 131, 231, kTouchId1, delegate.get());
// First finger touches down and moves.
EXPECT_FALSE(delegate->tap());
@@ -3039,8 +3199,8 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
// Second finger touches down and moves.
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
kTouchId2, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
- tes.SendScrollEvent(dispatcher(), 161, 231, kTouchId2, delegate.get());
+ DispatchEventUsingWindowDispatcher(&press2);
+ tes.SendScrollEvent(event_processor(), 161, 231, kTouchId2, delegate.get());
// PinchBegin & ScrollBegin were not sent if the touch-move events were
// consumed.
@@ -3058,7 +3218,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
delegate->Reset();
// Moves First finger again, no PinchUpdate & ScrollUpdate.
- tes.SendScrollEvent(dispatcher(), 161, 261, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 161, 261, kTouchId1, delegate.get());
EXPECT_FALSE(delegate->pinch_update());
EXPECT_FALSE(delegate->pinch_end());
@@ -3070,7 +3230,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
delegate->Reset();
// Making a pinch gesture.
- tes.SendScrollEvent(dispatcher(), 161, 251, kTouchId1, delegate.get());
+ tes.SendScrollEvent(event_processor(), 161, 251, kTouchId1, delegate.get());
// If touch moves are ever consumed, we should not see PinchBegin/Update
// even touch moves become not consumed.
EXPECT_FALSE(delegate->scroll_begin());
@@ -3082,7 +3242,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
EXPECT_FALSE(delegate->pinch_end());
delegate->Reset();
- tes.SendScrollEvent(dispatcher(), 161, 241, kTouchId2, delegate.get());
+ tes.SendScrollEvent(event_processor(), 161, 241, kTouchId2, delegate.get());
EXPECT_FALSE(delegate->scroll_begin());
EXPECT_FALSE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
@@ -3096,17 +3256,18 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
kTouchId1, tes.Now());
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
kTouchId2, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release1);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_FALSE(delegate->tap());
// Touch release is not consumed, so we still see two finger tap.
EXPECT_TRUE(delegate->two_finger_tap());
- // Should not see PinchEnd & ScrollEnd.
- EXPECT_FALSE(delegate->scroll_begin());
+ // Should not see PinchEnd.
+ EXPECT_TRUE(delegate->scroll_begin());
EXPECT_FALSE(delegate->scroll_update());
EXPECT_FALSE(delegate->scroll_end());
+ EXPECT_TRUE(delegate->fling());
EXPECT_FALSE(delegate->pinch_begin());
EXPECT_FALSE(delegate->pinch_update());
@@ -3116,7 +3277,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) {
// Like as GestureEventTouchMoveConsumed but tests the different behavior
// depending on whether the events were consumed before or after the scroll
// started.
-TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
+TEST_P(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
scoped_ptr<ConsumesTouchMovesDelegate> delegate(
new ConsumesTouchMovesDelegate());
const int kWindowWidth = 123;
@@ -3130,7 +3291,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
delegate->Reset();
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3142,7 +3303,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
// Move the touch-point enough so that it would normally be considered a
// scroll. But since the touch-moves will be consumed, the scroll should not
// start.
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3153,7 +3314,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
// Now, stop consuming touch-move events, and move the touch-point again.
delegate->set_consume_touch_move(false);
- tes.SendScrollEvent(dispatcher(), 159, 259, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 159, 259, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3171,7 +3332,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
delegate->set_consume_touch_move(true);
// Move some more to generate a few more scroll updates.
- tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3182,7 +3343,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
EXPECT_EQ(0, delegate->scroll_x());
EXPECT_EQ(0, delegate->scroll_y());
- tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3197,7 +3358,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
delegate->Reset();
ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3210,7 +3371,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) {
}
// Check that appropriate touch events generate double tap gesture events.
-TEST_F(GestureRecognizerTest, GestureEventDoubleTap) {
+TEST_P(GestureRecognizerTest, GestureEventDoubleTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -3224,19 +3385,19 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) {
// First tap (tested in GestureEventTap)
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
delegate->Reset();
// Second tap
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203),
kTouchId, tes.LeapForward(200));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_TRUE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
@@ -3251,7 +3412,7 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) {
}
// Check that appropriate touch events generate triple tap gesture events.
-TEST_F(GestureRecognizerTest, GestureEventTripleTap) {
+TEST_P(GestureRecognizerTest, GestureEventTripleTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -3265,10 +3426,10 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) {
// First tap (tested in GestureEventTap)
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_EQ(1, delegate->tap_count());
delegate->Reset();
@@ -3276,10 +3437,10 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) {
// Second tap (tested in GestureEventDoubleTap)
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203),
kTouchId, tes.LeapForward(200));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_EQ(2, delegate->tap_count());
delegate->Reset();
@@ -3287,26 +3448,44 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) {
// Third tap
ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(200));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3);
+ DispatchEventUsingWindowDispatcher(&press3);
ui::TouchEvent release3(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release3);
-
-
- EXPECT_TRUE(delegate->tap());
- EXPECT_TRUE(delegate->tap_down());
- EXPECT_FALSE(delegate->tap_cancel());
- EXPECT_TRUE(delegate->begin());
- EXPECT_TRUE(delegate->end());
- EXPECT_FALSE(delegate->scroll_begin());
- EXPECT_FALSE(delegate->scroll_update());
- EXPECT_FALSE(delegate->scroll_end());
-
- EXPECT_EQ(3, delegate->tap_count());
+ DispatchEventUsingWindowDispatcher(&release3);
+
+ // Third, Fourth and Fifth Taps. Taps after the third should have their
+ // |tap_count| wrap around back to 1.
+ for (int i = 3; i < 5; ++i) {
+ ui::TouchEvent press3(ui::ET_TOUCH_PRESSED,
+ gfx::Point(102, 206),
+ kTouchId,
+ tes.LeapForward(200));
+ DispatchEventUsingWindowDispatcher(&press3);
+ ui::TouchEvent release3(ui::ET_TOUCH_RELEASED,
+ gfx::Point(102, 206),
+ kTouchId,
+ tes.LeapForward(50));
+ DispatchEventUsingWindowDispatcher(&release3);
+
+ EXPECT_TRUE(delegate->tap());
+ EXPECT_TRUE(delegate->tap_down());
+ EXPECT_FALSE(delegate->tap_cancel());
+ EXPECT_TRUE(delegate->begin());
+ EXPECT_TRUE(delegate->end());
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_FALSE(delegate->scroll_end());
+
+ // The behavior for the Aura GR is incorrect.
+ if (UsingUnifiedGR())
+ EXPECT_EQ(1 + (i % 3), delegate->tap_count());
+ else
+ EXPECT_EQ(3, delegate->tap_count());
+ }
}
// Check that we don't get a double tap when the two taps are far apart.
-TEST_F(GestureRecognizerTest, TwoTapsFarApart) {
+TEST_P(GestureRecognizerTest, TwoTapsFarApart) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -3320,19 +3499,19 @@ TEST_F(GestureRecognizerTest, TwoTapsFarApart) {
// First tap (tested in GestureEventTap)
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
delegate->Reset();
// Second tap, close in time but far in distance
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(201, 201),
kTouchId, tes.LeapForward(200));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(201, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_TRUE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
@@ -3348,7 +3527,7 @@ TEST_F(GestureRecognizerTest, TwoTapsFarApart) {
// Check that we don't get a double tap when the two taps have a long enough
// delay in between.
-TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) {
+TEST_P(GestureRecognizerTest, TwoTapsWithDelayBetween) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 123;
@@ -3362,19 +3541,19 @@ TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) {
// First tap (tested in GestureEventTap)
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
delegate->Reset();
// Second tap, close in distance but after some delay
ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(2000));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2);
+ DispatchEventUsingWindowDispatcher(&release2);
EXPECT_TRUE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
@@ -3391,7 +3570,12 @@ TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) {
// Checks that if the bounding-box of a gesture changes because of change in
// radius of a touch-point, and not because of change in position, then there
// are not gesture events from that.
-TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
+TEST_P(GestureRecognizerTest, BoundingBoxRadiusChange) {
+ // TODO(tdresser): enable this test with unified GR when (if?) bounding box
+ // behavior is unified.
+ if (UsingUnifiedGR())
+ return;
+
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
const int kWindowWidth = 234;
@@ -3404,7 +3588,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
ui::TouchEvent press1(
ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->bounding_box().IsEmpty());
delegate->Reset();
@@ -3413,7 +3597,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
ui::ET_TOUCH_PRESSED, gfx::Point(201, 201), kTouchId2,
tes.LeapForward(400));
press2.set_radius_x(5);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_FALSE(delegate->pinch_begin());
EXPECT_EQ(gfx::Rect(101, 201, 100, 0).ToString(),
delegate->bounding_box().ToString());
@@ -3422,7 +3606,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(141, 201), kTouchId,
tes.LeapForward(40));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+ DispatchEventUsingWindowDispatcher(&move1);
EXPECT_TRUE(delegate->pinch_begin());
EXPECT_EQ(gfx::Rect(141, 201, 60, 0).ToString(),
delegate->bounding_box().ToString());
@@ -3434,7 +3618,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
tes.LeapForward(40));
move2.set_radius_x(50);
move2.set_radius_y(60);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_cancel());
EXPECT_FALSE(delegate->scroll_update());
@@ -3445,7 +3629,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) {
// Checks that slow scrolls deliver the correct deltas.
// In particular, fix for http;//crbug.com/150573.
-TEST_F(GestureRecognizerTest, NoDriftInScroll) {
+TEST_P(GestureRecognizerTest, NoDriftInScroll) {
ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(3);
ui::GestureConfiguration::set_min_scroll_delta_squared(9);
scoped_ptr<GestureEventConsumeDelegate> delegate(
@@ -3460,38 +3644,40 @@ TEST_F(GestureRecognizerTest, NoDriftInScroll) {
ui::TouchEvent press1(
ui::ET_TOUCH_PRESSED, gfx::Point(101, 208), kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->begin());
delegate->Reset();
ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(101, 206), kTouchId,
tes.LeapForward(40));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
+ DispatchEventUsingWindowDispatcher(&move1);
EXPECT_FALSE(delegate->scroll_begin());
delegate->Reset();
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId,
tes.LeapForward(40));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_TRUE(delegate->tap_cancel());
EXPECT_TRUE(delegate->scroll_begin());
EXPECT_TRUE(delegate->scroll_update());
- EXPECT_EQ(-4, delegate->scroll_y());
+ // 3 px consumed by touch slop region.
+ EXPECT_EQ(-1, delegate->scroll_y());
+ EXPECT_EQ(-4, delegate->scroll_y_hint());
delegate->Reset();
ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId,
tes.LeapForward(40));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3);
+ DispatchEventUsingWindowDispatcher(&move3);
EXPECT_FALSE(delegate->scroll_update());
delegate->Reset();
ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(101, 203), kTouchId,
tes.LeapForward(40));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4);
+ DispatchEventUsingWindowDispatcher(&move4);
EXPECT_TRUE(delegate->scroll_update());
EXPECT_EQ(-1, delegate->scroll_y());
@@ -3501,7 +3687,7 @@ TEST_F(GestureRecognizerTest, NoDriftInScroll) {
// Ensure that move events which are preventDefaulted will cause a tap
// cancel gesture event to be fired if the move would normally cause a
// scroll. See bug http://crbug.com/146397.
-TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) {
+TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) {
scoped_ptr<ConsumesTouchMovesDelegate> delegate(
new ConsumesTouchMovesDelegate());
const int kTouchId = 5;
@@ -3515,13 +3701,13 @@ TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) {
kTouchId, tes.Now());
delegate->set_consume_touch_move(false);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
delegate->set_consume_touch_move(true);
delegate->Reset();
// Move the touch-point enough so that it would normally be considered a
// scroll. But since the touch-moves will be consumed, the scroll should not
// start.
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
EXPECT_FALSE(delegate->tap());
EXPECT_FALSE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3531,7 +3717,7 @@ TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) {
EXPECT_FALSE(delegate->scroll_end());
}
-TEST_F(GestureRecognizerTest,
+TEST_P(GestureRecognizerTest,
TransferEventDispatchesTouchCancel) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
@@ -3552,8 +3738,8 @@ TEST_F(GestureRecognizerTest,
ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
ui::TouchEvent p2(ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 1, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p2);
+ DispatchEventUsingWindowDispatcher(&press);
+ DispatchEventUsingWindowDispatcher(&p2);
EXPECT_FALSE(delegate->tap());
EXPECT_TRUE(delegate->tap_down());
EXPECT_TRUE(delegate->tap_cancel());
@@ -3574,7 +3760,7 @@ TEST_F(GestureRecognizerTest,
}
// Check that appropriate touch events generate show press events
-TEST_F(GestureRecognizerTest, GestureEventShowPress) {
+TEST_P(GestureRecognizerTest, GestureEventShowPress) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -3594,7 +3780,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPress) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
EXPECT_TRUE(delegate->begin());
EXPECT_FALSE(delegate->tap_cancel());
@@ -3610,15 +3796,16 @@ TEST_F(GestureRecognizerTest, GestureEventShowPress) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->long_press());
- // Note the tap down isn't cancelled until the release
- EXPECT_TRUE(delegate->tap_cancel());
+ // Note the tap isn't dispatched until the release
+ EXPECT_FALSE(delegate->tap_cancel());
+ EXPECT_TRUE(delegate->tap());
}
// Check that scrolling cancels a show press
-TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
+TEST_P(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -3642,7 +3829,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
// We haven't pressed long enough for a show press to occur
@@ -3650,7 +3837,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
EXPECT_FALSE(delegate->tap_cancel());
// Scroll around, to cancel the show press
- tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get());
+ tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
// Wait until the timer runs out
gesture_sequence->ForceTimeout();
EXPECT_FALSE(delegate->show_press());
@@ -3659,13 +3846,13 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(10));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_FALSE(delegate->show_press());
EXPECT_FALSE(delegate->tap_cancel());
}
// Test that show press events are sent immediately on tap
-TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) {
+TEST_P(GestureRecognizerTest, GestureEventShowPressSentOnTap) {
scoped_ptr<GestureEventConsumeDelegate> delegate(
new GestureEventConsumeDelegate());
TimedEvents tes;
@@ -3680,7 +3867,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) {
ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
kTouchId, tes.Now());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
+ DispatchEventUsingWindowDispatcher(&press1);
EXPECT_TRUE(delegate->tap_down());
// We haven't pressed long enough for a show press to occur
@@ -3690,11 +3877,516 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) {
delegate->Reset();
ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
kTouchId, tes.LeapForward(50));
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1);
+ DispatchEventUsingWindowDispatcher(&release1);
EXPECT_TRUE(delegate->show_press());
EXPECT_FALSE(delegate->tap_cancel());
EXPECT_TRUE(delegate->tap());
}
+// Test that consuming the first move touch event prevents a scroll.
+TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveScrollTest) {
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kTouchId = 7;
+ gfx::Rect bounds(0, 0, 1000, 1000);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press);
+ delegate->ReceivedAck();
+
+ // A touch move within the slop region is never consumed in web contents. The
+ // unified GR won't prevent scroll if a touch move within the slop region is
+ // consumed, so make sure this touch move exceeds the slop region.
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(10, 10),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move1);
+ delegate->ReceivedAckPreventDefaulted();
+
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move2);
+ delegate->ReceivedAck();
+
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+}
+
+// Test that consuming the first touch move event of a touch point doesn't
+// prevent pinching once an additional touch has been pressed.
+TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMovePinchTest) {
+ // Consuming moves within the touch slop and the the disposition handling of
+ // pinch events behave differently between the Unified GR and the Aura GR.
+ if (UsingUnifiedGR())
+ return;
+
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kTouchId1 = 7;
+ const int kTouchId2 = 4;
+ gfx::Rect bounds(0, 0, 1000, 1000);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
+ kTouchId1, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press1);
+ delegate->ReceivedAck();
+
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(2, 2),
+ kTouchId1, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move1);
+ delegate->ReceivedAckPreventDefaulted();
+
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20),
+ kTouchId1, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move2);
+ delegate->ReceivedAck();
+
+ // We can't scroll, because a move has been consumed.
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_FALSE(delegate->pinch_begin());
+
+ // An additional press will allow us to pinch.
+ ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
+ kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press2);
+ delegate->ReceivedAck();
+
+ ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(20, 20),
+ kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move3);
+ delegate->ReceivedAck();
+
+ EXPECT_TRUE(delegate->pinch_begin());
+ EXPECT_FALSE(delegate->pinch_update());
+
+ delegate->Reset();
+
+ ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(40, 40),
+ kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move4);
+ delegate->ReceivedAck();
+
+ EXPECT_TRUE(delegate->pinch_update());
+ EXPECT_EQ(10, delegate->scroll_x());
+ EXPECT_EQ(10, delegate->scroll_y());
+}
+
+// Test that consuming the first move touch doesn't prevent a tap.
+TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveTapTest) {
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kTouchId = 7;
+ gfx::Rect bounds(0, 0, 1000, 1000);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press);
+ delegate->ReceivedAck();
+
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(2, 2),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->ReceivedAckPreventDefaulted();
+
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(2, 2),
+ kTouchId, tes.LeapForward(50));
+ DispatchEventUsingWindowDispatcher(&release);
+ delegate->ReceivedAck();
+
+ EXPECT_TRUE(delegate->tap());
+}
+
+// Test that consuming the first move touch doesn't prevent a long press.
+TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveLongPressTest) {
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kWindowWidth = 123;
+ const int kWindowHeight = 45;
+ const int kTouchId = 2;
+ gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ delegate->Reset();
+
+ TimerTestGestureRecognizer* gesture_recognizer =
+ new TimerTestGestureRecognizer();
+
+ ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press1);
+ delegate->ReceivedAck();
+
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(103, 203),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move);
+ delegate->ReceivedAckPreventDefaulted();
+
+ // Wait until the timer runs out
+ delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
+ EXPECT_TRUE(delegate->long_press());
+}
+
+// Tests that the deltas are correct when leaving the slop region very slowly.
+TEST_P(GestureRecognizerTest, TestExceedingSlopSlowly) {
+ // Disabled for unified GR due to subtle differences in touch slop handling.
+ if (UsingUnifiedGR())
+ return;
+
+ ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(3);
+ scoped_ptr<GestureEventConsumeDelegate> delegate(
+ new GestureEventConsumeDelegate());
+ const int kWindowWidth = 234;
+ const int kWindowHeight = 345;
+ const int kTouchId = 5;
+ TimedEvents tes;
+ gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press);
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ delegate->Reset();
+
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(11, 10), kTouchId,
+ tes.LeapForward(40));
+ DispatchEventUsingWindowDispatcher(&move1);
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_EQ(0, delegate->scroll_x());
+ EXPECT_EQ(0, delegate->scroll_x_hint());
+ delegate->Reset();
+
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(12, 10), kTouchId,
+ tes.LeapForward(40));
+ DispatchEventUsingWindowDispatcher(&move2);
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_EQ(0, delegate->scroll_x());
+ EXPECT_EQ(0, delegate->scroll_x_hint());
+ delegate->Reset();
+
+
+ ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(13, 10), kTouchId,
+ tes.LeapForward(40));
+ DispatchEventUsingWindowDispatcher(&move3);
+ EXPECT_TRUE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_EQ(0, delegate->scroll_x());
+ EXPECT_EQ(3, delegate->scroll_x_hint());
+ delegate->Reset();
+
+
+ ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(14, 10), kTouchId,
+ tes.LeapForward(40));
+ DispatchEventUsingWindowDispatcher(&move4);
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_update());
+ EXPECT_EQ(1, delegate->scroll_x());
+ EXPECT_EQ(0, delegate->scroll_x_hint());
+ delegate->Reset();
+}
+
+TEST_P(GestureRecognizerTest, ScrollAlternatelyConsumedTest) {
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kWindowWidth = 3000;
+ const int kWindowHeight = 3000;
+ const int kTouchId = 2;
+ gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ delegate->Reset();
+
+ int x = 0;
+ int y = 0;
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press1);
+ delegate->ReceivedAck();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ delegate->Reset();
+
+ x += 100;
+ y += 100;
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move1);
+ delegate->ReceivedAck();
+ EXPECT_TRUE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_update());
+ delegate->Reset();
+
+ for (int i = 0; i < 3; ++i) {
+ x += 10;
+ y += 10;
+ ui::TouchEvent move2(
+ ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move2);
+ delegate->ReceivedAck();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_update());
+ EXPECT_EQ(10, delegate->scroll_x());
+ EXPECT_EQ(10, delegate->scroll_y());
+ delegate->Reset();
+
+ x += 20;
+ y += 20;
+ ui::TouchEvent move3(
+ ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move3);
+ delegate->ReceivedAckPreventDefaulted();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ delegate->Reset();
+ }
+}
+
+TEST_P(GestureRecognizerTest, PinchAlternatelyConsumedTest) {
+ // Disabled for unified GR due to differences in when scroll update is
+ // sent. The Aura GR will never send a ScrollUpdate with a ScrollBegin, but
+ // the unified GR will.
+ if (UsingUnifiedGR())
+ return;
+
+ scoped_ptr<QueueTouchEventDelegate> delegate(
+ new QueueTouchEventDelegate(host()->dispatcher()));
+ TimedEvents tes;
+ const int kWindowWidth = 3000;
+ const int kWindowHeight = 3000;
+ const int kTouchId1 = 5;
+ const int kTouchId2 = 7;
+ gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ delegate->Reset();
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
+ kTouchId1, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press1);
+ delegate->ReceivedAck();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ delegate->Reset();
+
+ int x = 0;
+ int y = 0;
+
+ ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
+ kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press2);
+ delegate->ReceivedAck();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_FALSE(delegate->pinch_begin());
+ EXPECT_FALSE(delegate->pinch_update());
+
+ delegate->Reset();
+
+ x += 100;
+ y += 100;
+ ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
+ kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move1);
+ delegate->ReceivedAck();
+ EXPECT_TRUE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_TRUE(delegate->pinch_begin());
+ EXPECT_FALSE(delegate->pinch_update());
+ delegate->Reset();
+
+ const float expected_scales[] = {1.5f, 1.2f, 1.125f};
+
+ for (int i = 0; i < 3; ++i) {
+ x += 50;
+ y += 50;
+ ui::TouchEvent move2(
+ ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move2);
+ delegate->ReceivedAck();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_TRUE(delegate->scroll_update());
+ EXPECT_FALSE(delegate->scroll_end());
+ EXPECT_FALSE(delegate->pinch_begin());
+ EXPECT_TRUE(delegate->pinch_update());
+ EXPECT_FALSE(delegate->pinch_end());
+ EXPECT_EQ(25, delegate->scroll_x());
+ EXPECT_EQ(25, delegate->scroll_y());
+ EXPECT_FLOAT_EQ(expected_scales[i], delegate->scale());
+ delegate->Reset();
+
+ x += 100;
+ y += 100;
+ ui::TouchEvent move3(
+ ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now());
+ DispatchEventUsingWindowDispatcher(&move3);
+ delegate->ReceivedAckPreventDefaulted();
+ EXPECT_FALSE(delegate->scroll_begin());
+ EXPECT_FALSE(delegate->scroll_update());
+ EXPECT_FALSE(delegate->scroll_end());
+ EXPECT_FALSE(delegate->pinch_begin());
+ EXPECT_FALSE(delegate->pinch_update());
+ EXPECT_FALSE(delegate->pinch_end());
+ delegate->Reset();
+ }
+}
+
+// Test that touch event flags are passed through to the gesture event.
+TEST_P(GestureRecognizerTest, GestureEventFlagsPassedFromTouchEvent) {
+ scoped_ptr<GestureEventConsumeDelegate> delegate(
+ new GestureEventConsumeDelegate());
+ TimedEvents tes;
+ const int kWindowWidth = 123;
+ const int kWindowHeight = 45;
+ const int kTouchId = 6;
+ gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ delegate->Reset();
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+ kTouchId, tes.Now());
+ DispatchEventUsingWindowDispatcher(&press1);
+ EXPECT_TRUE(delegate->tap_down());
+
+ int default_flags = delegate->flags();
+
+ ui::TouchEvent move1(
+ ui::ET_TOUCH_MOVED, gfx::Point(397, 149), kTouchId, tes.LeapForward(50));
+ move1.set_flags(992);
+
+ DispatchEventUsingWindowDispatcher(&move1);
+ EXPECT_NE(default_flags, delegate->flags());
+}
+
+// Test that latency info is passed through to the gesture event.
+TEST_P(GestureRecognizerTest, LatencyPassedFromTouchEvent) {
+ scoped_ptr<GestureEventConsumeDelegate> delegate(
+ new GestureEventConsumeDelegate());
+ TimedEvents tes;
+ const int kWindowWidth = 123;
+ const int kWindowHeight = 45;
+ const int kTouchId = 6;
+
+ const base::TimeTicks time_original = base::TimeTicks::FromInternalValue(100);
+ const base::TimeTicks time_ui = base::TimeTicks::FromInternalValue(200);
+ const base::TimeTicks time_acked = base::TimeTicks::FromInternalValue(300);
+
+ gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ delegate.get(), -1234, bounds, root_window()));
+
+ delegate->Reset();
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
+ kTouchId, tes.Now());
+
+ // Ensure the only components around are the ones we add.
+ press1.latency()->Clear();
+
+ press1.latency()->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, time_original, 1);
+
+ press1.latency()->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0, time_ui, 1);
+
+ press1.latency()->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT, 0, 0, time_acked, 1);
+
+ DispatchEventUsingWindowDispatcher(&press1);
+ EXPECT_TRUE(delegate->tap_down());
+
+ ui::LatencyInfo::LatencyComponent component;
+
+ EXPECT_EQ(3U, delegate->latency_info().latency_components.size());
+ ASSERT_TRUE(delegate->latency_info().FindLatency(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &component));
+ EXPECT_EQ(time_original, component.event_time);
+
+ ASSERT_TRUE(delegate->latency_info().FindLatency(
+ ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component));
+ EXPECT_EQ(time_ui, component.event_time);
+
+ ASSERT_TRUE(delegate->latency_info().FindLatency(
+ ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT, 0, &component));
+ EXPECT_EQ(time_acked, component.event_time);
+
+ delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
+ EXPECT_TRUE(delegate->show_press());
+ EXPECT_EQ(0U, delegate->latency_info().latency_components.size());
+}
+
+// A delegate that deletes a window on long press.
+class GestureEventDeleteWindowOnLongPress : public GestureEventConsumeDelegate {
+ public:
+ GestureEventDeleteWindowOnLongPress()
+ : window_(NULL) {}
+
+ void set_window(aura::Window** window) { window_ = window; }
+
+ virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
+ GestureEventConsumeDelegate::OnGestureEvent(gesture);
+ if (gesture->type() != ui::ET_GESTURE_LONG_PRESS)
+ return;
+ ui::GestureRecognizer::Get()->CleanupStateForConsumer(*window_);
+ delete *window_;
+ *window_ = NULL;
+ }
+
+ private:
+ aura::Window** window_;
+ DISALLOW_COPY_AND_ASSIGN(GestureEventDeleteWindowOnLongPress);
+};
+
+// Check that deleting the window in response to a long press gesture doesn't
+// crash.
+TEST_P(GestureRecognizerTest, GestureEventLongPressDeletingWindow) {
+ GestureEventDeleteWindowOnLongPress delegate;
+ const int kWindowWidth = 123;
+ const int kWindowHeight = 45;
+ const int kTouchId = 2;
+ gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
+ aura::Window* window(CreateTestWindowWithDelegate(
+ &delegate, -1234, bounds, root_window()));
+ delegate.set_window(&window);
+
+ ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
+ gfx::Point(101, 201),
+ kTouchId,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press1);
+ EXPECT_TRUE(window != NULL);
+
+ // Wait until the timer runs out.
+ delegate.WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
+ EXPECT_EQ(NULL, window);
+}
+
+INSTANTIATE_TEST_CASE_P(GestureRecognizer,
+ GestureRecognizerTest,
+ ::testing::Bool());
+
} // namespace test
} // namespace aura
diff --git a/chromium/ui/aura/remote_root_window_host_win.cc b/chromium/ui/aura/remote_root_window_host_win.cc
deleted file mode 100644
index 3dba26aacc4..00000000000
--- a/chromium/ui/aura/remote_root_window_host_win.cc
+++ /dev/null
@@ -1,732 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/remote_root_window_host_win.h"
-
-#include <windows.h>
-
-#include <algorithm>
-
-#include "base/message_loop/message_loop.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_sender.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/cursor/cursor_loader_win.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/remote_input_method_win.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/base/view_prop.h"
-#include "ui/gfx/insets.h"
-#include "ui/metro_viewer/metro_viewer_messages.h"
-
-namespace aura {
-
-namespace {
-
-const char* kRootWindowHostWinKey = "__AURA_REMOTE_ROOT_WINDOW_HOST_WIN__";
-
-// Sets the keystate for the virtual key passed in to down or up.
-void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) {
- DCHECK(key_states);
-
- if (key_down)
- key_states[virtual_key_code] |= 0x80;
- else
- key_states[virtual_key_code] &= 0x7F;
-}
-
-// Sets the keyboard states for the Shift/Control/Alt/Caps lock keys.
-void SetVirtualKeyStates(uint32 flags) {
- uint8 keyboard_state[256] = {0};
- ::GetKeyboardState(keyboard_state);
-
- SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT);
- SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL);
- SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU);
- SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_DOWN), VK_CAPITAL);
- SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON);
- SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON),
- VK_RBUTTON);
- SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON),
- VK_MBUTTON);
-
- ::SetKeyboardState(keyboard_state);
-}
-
-void FillCompositionText(
- const string16& text,
- int32 selection_start,
- int32 selection_end,
- const std::vector<metro_viewer::UnderlineInfo>& underlines,
- ui::CompositionText* composition_text) {
- composition_text->Clear();
- composition_text->text = text;
- composition_text->selection.set_start(selection_start);
- composition_text->selection.set_end(selection_end);
- composition_text->underlines.resize(underlines.size());
- for (size_t i = 0; i < underlines.size(); ++i) {
- composition_text->underlines[i].start_offset = underlines[i].start_offset;
- composition_text->underlines[i].end_offset = underlines[i].end_offset;
- composition_text->underlines[i].color = SK_ColorBLACK;
- composition_text->underlines[i].thick = underlines[i].thick;
- }
-}
-
-} // namespace
-
-void HandleOpenFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenFileCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleOpenFile(title,
- default_path,
- filter,
- on_success,
- on_failure);
-}
-
-void HandleOpenMultipleFiles(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenMultipleFilesCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleOpenMultipleFiles(
- title,
- default_path,
- filter,
- on_success,
- on_failure);
-}
-
-void HandleSaveFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- int filter_index,
- const base::string16& default_extension,
- const SaveFileCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleSaveFile(title,
- default_path,
- filter,
- filter_index,
- default_extension,
- on_success,
- on_failure);
-}
-
-void HandleSelectFolder(const base::string16& title,
- const SelectFolderCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleSelectFolder(title,
- on_success,
- on_failure);
-}
-
-void HandleActivateDesktop(const base::FilePath& shortcut,
- bool ash_exit) {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleActivateDesktop(shortcut,
- ash_exit);
-}
-
-void HandleMetroExit() {
- DCHECK(aura::RemoteRootWindowHostWin::Instance());
- aura::RemoteRootWindowHostWin::Instance()->HandleMetroExit();
-}
-
-RemoteRootWindowHostWin* g_instance = NULL;
-
-RemoteRootWindowHostWin* RemoteRootWindowHostWin::Instance() {
- if (g_instance)
- return g_instance;
- return Create(gfx::Rect());
-}
-
-RemoteRootWindowHostWin* RemoteRootWindowHostWin::Create(
- const gfx::Rect& bounds) {
- g_instance = g_instance ? g_instance : new RemoteRootWindowHostWin(bounds);
- return g_instance;
-}
-
-RemoteRootWindowHostWin::RemoteRootWindowHostWin(const gfx::Rect& bounds)
- : remote_window_(NULL),
- host_(NULL),
- ignore_mouse_moves_until_set_cursor_ack_(false),
- event_flags_(0),
- window_size_(aura::RootWindowHost::GetNativeScreenSize()) {
- prop_.reset(new ui::ViewProp(NULL, kRootWindowHostWinKey, this));
-}
-
-RemoteRootWindowHostWin::~RemoteRootWindowHostWin() {
- g_instance = NULL;
-}
-
-void RemoteRootWindowHostWin::Connected(IPC::Sender* host, HWND remote_window) {
- CHECK(host_ == NULL);
- host_ = host;
- remote_window_ = remote_window;
-}
-
-void RemoteRootWindowHostWin::Disconnected() {
- // Don't CHECK here, Disconnected is called on a channel error which can
- // happen before we're successfully Connected.
- if (!host_)
- return;
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (remote_input_method_private)
- remote_input_method_private->SetRemoteDelegate(NULL);
- host_ = NULL;
- remote_window_ = NULL;
-}
-
-bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(RemoteRootWindowHostWin, message)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated,
- OnWindowActivated)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown,
- OnTouchDown)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp,
- OnTouchUp)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved,
- OnTouchMoved)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone,
- OnFileSaveAsDone)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone,
- OnFileOpenDone)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone,
- OnMultiFileOpenDone)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone,
- OnSelectFolderDone)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck,
- OnSetCursorPosAck)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged,
- OnImeCandidatePopupChanged)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCompositionChanged,
- OnImeCompositionChanged)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted,
- OnImeTextCommitted)
- IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged,
- OnImeInputSourceChanged)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void RemoteRootWindowHostWin::HandleOpenURLOnDesktop(
- const base::FilePath& shortcut,
- const base::string16& url) {
- if (!host_)
- return;
- host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url));
-}
-
-void RemoteRootWindowHostWin::HandleActivateDesktop(
- const base::FilePath& shortcut,
- bool ash_exit) {
- if (!host_)
- return;
- host_->Send(new MetroViewerHostMsg_ActivateDesktop(shortcut, ash_exit));
-}
-
-void RemoteRootWindowHostWin::HandleMetroExit() {
- if (!host_)
- return;
- host_->Send(new MetroViewerHostMsg_MetroExit());
-}
-
-void RemoteRootWindowHostWin::HandleOpenFile(
- const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenFileCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- if (!host_)
- return;
-
- // Can only have one of these operations in flight.
- DCHECK(file_open_completion_callback_.is_null());
- DCHECK(failure_callback_.is_null());
-
- file_open_completion_callback_ = on_success;
- failure_callback_ = on_failure;
-
- host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
- filter,
- default_path,
- false));
-}
-
-void RemoteRootWindowHostWin::HandleOpenMultipleFiles(
- const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenMultipleFilesCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- if (!host_)
- return;
-
- // Can only have one of these operations in flight.
- DCHECK(multi_file_open_completion_callback_.is_null());
- DCHECK(failure_callback_.is_null());
- multi_file_open_completion_callback_ = on_success;
- failure_callback_ = on_failure;
-
- host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
- filter,
- default_path,
- true));
-}
-
-void RemoteRootWindowHostWin::HandleSaveFile(
- const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- int filter_index,
- const base::string16& default_extension,
- const SaveFileCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- if (!host_)
- return;
-
- MetroViewerHostMsg_SaveAsDialogParams params;
- params.title = title;
- params.default_extension = default_extension;
- params.filter = filter;
- params.filter_index = filter_index;
- params.suggested_name = default_path;
-
- // Can only have one of these operations in flight.
- DCHECK(file_saveas_completion_callback_.is_null());
- DCHECK(failure_callback_.is_null());
- file_saveas_completion_callback_ = on_success;
- failure_callback_ = on_failure;
-
- host_->Send(new MetroViewerHostMsg_DisplayFileSaveAs(params));
-}
-
-void RemoteRootWindowHostWin::HandleSelectFolder(
- const base::string16& title,
- const SelectFolderCompletion& on_success,
- const FileSelectionCanceled& on_failure) {
- if (!host_)
- return;
-
- // Can only have one of these operations in flight.
- DCHECK(select_folder_completion_callback_.is_null());
- DCHECK(failure_callback_.is_null());
- select_folder_completion_callback_ = on_success;
- failure_callback_ = on_failure;
-
- host_->Send(new MetroViewerHostMsg_DisplaySelectFolder(title));
-}
-
-void RemoteRootWindowHostWin::HandleWindowSizeChanged(uint32 width,
- uint32 height) {
- SetBounds(gfx::Rect(0, 0, width, height));
-}
-
-bool RemoteRootWindowHostWin::IsForegroundWindow() {
- return ::GetForegroundWindow() == remote_window_;
-}
-
-Window* RemoteRootWindowHostWin::GetAshWindow() {
- return GetRootWindow()->window();
-}
-
-RootWindow* RemoteRootWindowHostWin::GetRootWindow() {
- return delegate_->AsRootWindow();
-}
-
-gfx::AcceleratedWidget RemoteRootWindowHostWin::GetAcceleratedWidget() {
- if (remote_window_)
- return remote_window_;
- // Getting here should only happen for ash_unittests.exe and related code.
- return ::GetDesktopWindow();
-}
-
-void RemoteRootWindowHostWin::Show() {
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (remote_input_method_private)
- remote_input_method_private->SetRemoteDelegate(this);
-}
-
-void RemoteRootWindowHostWin::Hide() {
- NOTIMPLEMENTED();
-}
-
-void RemoteRootWindowHostWin::ToggleFullScreen() {
-}
-
-gfx::Rect RemoteRootWindowHostWin::GetBounds() const {
- return gfx::Rect(window_size_);
-}
-
-void RemoteRootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
- window_size_ = bounds.size();
- delegate_->OnHostResized(bounds.size());
-}
-
-gfx::Insets RemoteRootWindowHostWin::GetInsets() const {
- return gfx::Insets();
-}
-
-void RemoteRootWindowHostWin::SetInsets(const gfx::Insets& insets) {
-}
-
-gfx::Point RemoteRootWindowHostWin::GetLocationOnNativeScreen() const {
- return gfx::Point(0, 0);
-}
-
-void RemoteRootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) {
- if (!host_)
- return;
- host_->Send(
- new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform())));
-}
-
-void RemoteRootWindowHostWin::SetCapture() {
-}
-
-void RemoteRootWindowHostWin::ReleaseCapture() {
-}
-
-bool RemoteRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(GetRootWindow()->window());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
- *location_return = gfx::Point(0, 0);
- return false;
- }
- POINT pt;
- GetCursorPos(&pt);
- *location_return =
- gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y));
- return true;
-}
-
-bool RemoteRootWindowHostWin::ConfineCursorToRootWindow() {
- return true;
-}
-
-void RemoteRootWindowHostWin::UnConfineCursor() {
-}
-
-void RemoteRootWindowHostWin::OnCursorVisibilityChanged(bool show) {
- NOTIMPLEMENTED();
-}
-
-void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
- VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y();
- if (!host_)
- return;
-
- // This function can be called in cases like when the mouse cursor is
- // restricted within a viewport (For e.g. LockCursor) which assumes that
- // subsequent mouse moves would be received starting with the new cursor
- // coordinates. This is a challenge for Windows ASH for the reasons
- // outlined below.
- // Other cases which don't expect this behavior should continue to work
- // without issues.
-
- // The mouse events are received by the viewer process and sent to the
- // browser. If we invoke the SetCursor API here we continue to receive
- // mouse messages from the viewer which were posted before the SetCursor
- // API executes which messes up the state in the browser. To workaround
- // this we invoke the SetCursor API in the viewer process and ignore
- // mouse messages until we received an ACK from the viewer indicating that
- // the SetCursor operation completed.
- ignore_mouse_moves_until_set_cursor_ack_ = true;
- VLOG(1) << "In MoveCursorTo. Sending IPC";
- host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y()));
-}
-
-void RemoteRootWindowHostWin::PostNativeEvent(
- const base::NativeEvent& native_event) {
-}
-
-void RemoteRootWindowHostWin::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
- NOTIMPLEMENTED();
-}
-
-void RemoteRootWindowHostWin::PrepareForShutdown() {
-}
-
-void RemoteRootWindowHostWin::CancelComposition() {
- host_->Send(new MetroViewerHostMsg_ImeCancelComposition);
-}
-
-void RemoteRootWindowHostWin::OnTextInputClientUpdated(
- const std::vector<int32>& input_scopes,
- const std::vector<gfx::Rect>& composition_character_bounds) {
- std::vector<metro_viewer::CharacterBounds> character_bounds;
- for (size_t i = 0; i < composition_character_bounds.size(); ++i) {
- const gfx::Rect& rect = composition_character_bounds[i];
- metro_viewer::CharacterBounds bounds;
- bounds.left = rect.x();
- bounds.top = rect.y();
- bounds.right = rect.right();
- bounds.bottom = rect.bottom();
- character_bounds.push_back(bounds);
- }
- host_->Send(new MetroViewerHostMsg_ImeTextInputClientUpdated(
- input_scopes, character_bounds));
-}
-
-void RemoteRootWindowHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) {
- if (ignore_mouse_moves_until_set_cursor_ack_)
- return;
-
- gfx::Point location(x, y);
- ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags);
- delegate_->OnHostMouseEvent(&event);
-}
-
-void RemoteRootWindowHostWin::OnMouseButton(
- int32 x,
- int32 y,
- int32 extra,
- ui::EventType type,
- ui::EventFlags flags) {
- gfx::Point location(x, y);
- ui::MouseEvent mouse_event(type, location, location, flags);
-
- SetEventFlags(flags | key_event_flags());
- if (type == ui::ET_MOUSEWHEEL) {
- ui::MouseWheelEvent wheel_event(mouse_event, 0, extra);
- delegate_->OnHostMouseEvent(&wheel_event);
- } else if (type == ui::ET_MOUSE_PRESSED) {
- // TODO(shrikant): Ideally modify code in event.cc by adding automatic
- // tracking of double clicks in synthetic MouseEvent constructor code.
- // Non-synthetic MouseEvent constructor code does automatically track
- // this. Need to use some caution while modifying synthetic constructor
- // as many tests and other code paths depend on it and apparently
- // specifically depend on non implicit tracking of previous mouse event.
- if (last_mouse_click_event_ &&
- ui::MouseEvent::IsRepeatedClickEvent(mouse_event,
- *last_mouse_click_event_)) {
- mouse_event.SetClickCount(2);
- } else {
- mouse_event.SetClickCount(1);
- }
- last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event));
- delegate_->OnHostMouseEvent(&mouse_event);
- } else {
- delegate_->OnHostMouseEvent(&mouse_event);
- }
-}
-
-void RemoteRootWindowHostWin::OnKeyDown(uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags) {
- DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code,
- flags, false);
-}
-
-void RemoteRootWindowHostWin::OnKeyUp(uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags) {
- DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code,
- flags, false);
-}
-
-void RemoteRootWindowHostWin::OnChar(uint32 key_code,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags) {
- DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count,
- scan_code, flags, true);
-}
-
-void RemoteRootWindowHostWin::OnWindowActivated() {
- delegate_->OnHostActivated();
-}
-
-void RemoteRootWindowHostWin::OnTouchDown(int32 x,
- int32 y,
- uint64 timestamp,
- uint32 pointer_id) {
- ui::TouchEvent event(ui::ET_TOUCH_PRESSED,
- gfx::Point(x, y),
- pointer_id,
- base::TimeDelta::FromMicroseconds(timestamp));
- delegate_->OnHostTouchEvent(&event);
-}
-
-void RemoteRootWindowHostWin::OnTouchUp(int32 x,
- int32 y,
- uint64 timestamp,
- uint32 pointer_id) {
- ui::TouchEvent event(ui::ET_TOUCH_RELEASED,
- gfx::Point(x, y),
- pointer_id,
- base::TimeDelta::FromMicroseconds(timestamp));
- delegate_->OnHostTouchEvent(&event);
-}
-
-void RemoteRootWindowHostWin::OnTouchMoved(int32 x,
- int32 y,
- uint64 timestamp,
- uint32 pointer_id) {
- ui::TouchEvent event(ui::ET_TOUCH_MOVED,
- gfx::Point(x, y),
- pointer_id,
- base::TimeDelta::FromMicroseconds(timestamp));
- delegate_->OnHostTouchEvent(&event);
-}
-
-void RemoteRootWindowHostWin::OnFileSaveAsDone(bool success,
- const base::FilePath& filename,
- int filter_index) {
- if (success)
- file_saveas_completion_callback_.Run(filename, filter_index, NULL);
- else
- failure_callback_.Run(NULL);
- file_saveas_completion_callback_.Reset();
- failure_callback_.Reset();
-}
-
-
-void RemoteRootWindowHostWin::OnFileOpenDone(bool success,
- const base::FilePath& filename) {
- if (success)
- file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL);
- else
- failure_callback_.Run(NULL);
- file_open_completion_callback_.Reset();
- failure_callback_.Reset();
-}
-
-void RemoteRootWindowHostWin::OnMultiFileOpenDone(
- bool success,
- const std::vector<base::FilePath>& files) {
- if (success)
- multi_file_open_completion_callback_.Run(files, NULL);
- else
- failure_callback_.Run(NULL);
- multi_file_open_completion_callback_.Reset();
- failure_callback_.Reset();
-}
-
-void RemoteRootWindowHostWin::OnSelectFolderDone(
- bool success,
- const base::FilePath& folder) {
- if (success)
- select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL);
- else
- failure_callback_.Run(NULL);
- select_folder_completion_callback_.Reset();
- failure_callback_.Reset();
-}
-
-void RemoteRootWindowHostWin::OnSetCursorPosAck() {
- DCHECK(ignore_mouse_moves_until_set_cursor_ack_);
- ignore_mouse_moves_until_set_cursor_ack_ = false;
-}
-
-ui::RemoteInputMethodPrivateWin*
-RemoteRootWindowHostWin::GetRemoteInputMethodPrivate() {
- ui::InputMethod* input_method = GetAshWindow()->GetProperty(
- aura::client::kRootWindowInputMethodKey);
- return ui::RemoteInputMethodPrivateWin::Get(input_method);
-}
-
-void RemoteRootWindowHostWin::OnImeCandidatePopupChanged(bool visible) {
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (!remote_input_method_private)
- return;
- remote_input_method_private->OnCandidatePopupChanged(visible);
-}
-
-void RemoteRootWindowHostWin::OnImeCompositionChanged(
- const string16& text,
- int32 selection_start,
- int32 selection_end,
- const std::vector<metro_viewer::UnderlineInfo>& underlines) {
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (!remote_input_method_private)
- return;
- ui::CompositionText composition_text;
- FillCompositionText(
- text, selection_start, selection_end, underlines, &composition_text);
- remote_input_method_private->OnCompositionChanged(composition_text);
-}
-
-void RemoteRootWindowHostWin::OnImeTextCommitted(const string16& text) {
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (!remote_input_method_private)
- return;
- remote_input_method_private->OnTextCommitted(text);
-}
-
-void RemoteRootWindowHostWin::OnImeInputSourceChanged(uint16 language_id,
- bool is_ime) {
- ui::RemoteInputMethodPrivateWin* remote_input_method_private =
- GetRemoteInputMethodPrivate();
- if (!remote_input_method_private)
- return;
- remote_input_method_private->OnInputSourceChanged(language_id, is_ime);
-}
-
-void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type,
- uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags,
- bool is_character) {
- SetEventFlags(flags | mouse_event_flags());
- if (base::MessageLoop::current()->IsNested()) {
- int index = (flags & ui::EF_ALT_DOWN) ? 1 : 0;
- const int char_message[] = {WM_CHAR, WM_SYSCHAR};
- const int keydown_message[] = {WM_KEYDOWN, WM_SYSKEYDOWN};
- const int keyup_message[] = {WM_KEYUP, WM_SYSKEYUP};
- uint32 message = is_character
- ? char_message[index]
- : (type == ui::ET_KEY_PRESSED ? keydown_message[index]
- : keyup_message[index]);
- ::PostThreadMessage(::GetCurrentThreadId(),
- message,
- vkey,
- repeat_count | scan_code >> 15);
- } else {
- ui::KeyEvent event(type,
- ui::KeyboardCodeForWindowsKeyCode(vkey),
- flags,
- is_character);
- delegate_->OnHostKeyEvent(&event);
- }
-}
-
-void RemoteRootWindowHostWin::SetEventFlags(uint32 flags) {
- if (flags == event_flags_)
- return;
- event_flags_ = flags;
- SetVirtualKeyStates(event_flags_);
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/remote_root_window_host_win.h b/chromium/ui/aura/remote_root_window_host_win.h
deleted file mode 100644
index 5c1066f80fa..00000000000
--- a/chromium/ui/aura/remote_root_window_host_win.h
+++ /dev/null
@@ -1,298 +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_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_
-#define UI_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/ime/remote_input_method_delegate_win.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/metro_viewer/ime_types.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace ui {
-class RemoteInputMethodPrivateWin;
-class ViewProp;
-}
-
-namespace IPC {
-class Message;
-class Sender;
-}
-
-namespace aura {
-
-typedef base::Callback<void(const base::FilePath&, int, void*)>
- OpenFileCompletion;
-
-typedef base::Callback<void(const std::vector<base::FilePath>&, void*)>
- OpenMultipleFilesCompletion;
-
-typedef base::Callback<void(const base::FilePath&, int, void*)>
- SaveFileCompletion;
-
-typedef base::Callback<void(const base::FilePath&, int, void*)>
- SelectFolderCompletion;
-
-typedef base::Callback<void(void*)> FileSelectionCanceled;
-
-// Handles the open file operation for Metro Chrome Ash. The on_success
-// callback passed in is invoked when we receive the opened file name from
-// the metro viewer. The on failure callback is invoked on failure.
-AURA_EXPORT void HandleOpenFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenFileCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
-// Handles the open multiple file operation for Metro Chrome Ash. The
-// on_success callback passed in is invoked when we receive the opened file
-// names from the metro viewer. The on failure callback is invoked on failure.
-AURA_EXPORT void HandleOpenMultipleFiles(
- const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenMultipleFilesCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
-// Handles the save file operation for Metro Chrome Ash. The on_success
-// callback passed in is invoked when we receive the saved file name from
-// the metro viewer. The on failure callback is invoked on failure.
-AURA_EXPORT void HandleSaveFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- int filter_index,
- const base::string16& default_extension,
- const SaveFileCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
-// Handles the select folder for Metro Chrome Ash. The on_success
-// callback passed in is invoked when we receive the folder name from the
-// metro viewer. The on failure callback is invoked on failure.
-AURA_EXPORT void HandleSelectFolder(const base::string16& title,
- const SelectFolderCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
-// Handles the activate desktop command for Metro Chrome Ash. The |ash_exit|
-// parameter indicates whether the Ash process would be shutdown after
-// activating the desktop.
-AURA_EXPORT void HandleActivateDesktop(
- const base::FilePath& shortcut,
- bool ash_exit);
-
-// Handles the metro exit command. Notifies the metro viewer to shutdown
-// gracefully.
-AURA_EXPORT void HandleMetroExit();
-
-// RootWindowHost implementaton that receives events from a different
-// process. In the case of Windows this is the Windows 8 (aka Metro)
-// frontend process, which forwards input events to this class.
-class AURA_EXPORT RemoteRootWindowHostWin
- : public RootWindowHost,
- public ui::internal::RemoteInputMethodDelegateWin {
- public:
- // Returns the only RemoteRootWindowHostWin, if this is the first time
- // this function is called, it will call Create() wiht empty bounds.
- static RemoteRootWindowHostWin* Instance();
- static RemoteRootWindowHostWin* Create(const gfx::Rect& bounds);
-
- // Called when the remote process has established its IPC connection.
- // The |host| can be used when we need to send a message to it and
- // |remote_window| is the actual window owned by the viewer process.
- void Connected(IPC::Sender* host, HWND remote_window);
- // Called when the remote process has closed its IPC connection.
- void Disconnected();
-
- // Called when we have a message from the remote process.
- bool OnMessageReceived(const IPC::Message& message);
-
- void HandleOpenURLOnDesktop(const base::FilePath& shortcut,
- const base::string16& url);
-
- // The |ash_exit| parameter indicates whether the Ash process would be
- // shutdown after activating the desktop.
- void HandleActivateDesktop(const base::FilePath& shortcut, bool ash_exit);
-
- // Notify the metro viewer that it should shut itself down.
- void HandleMetroExit();
-
- void HandleOpenFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenFileCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
- void HandleOpenMultipleFiles(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- const OpenMultipleFilesCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
- void HandleSaveFile(const base::string16& title,
- const base::FilePath& default_path,
- const base::string16& filter,
- int filter_index,
- const base::string16& default_extension,
- const SaveFileCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
- void HandleSelectFolder(const base::string16& title,
- const SelectFolderCompletion& on_success,
- const FileSelectionCanceled& on_failure);
-
- void HandleWindowSizeChanged(uint32 width, uint32 height);
-
- // Returns the active ASH root window.
- Window* GetAshWindow();
-
- // Returns true if the remote window is the foreground window according to the
- // OS.
- bool IsForegroundWindow();
-
- private:
- explicit RemoteRootWindowHostWin(const gfx::Rect& bounds);
- virtual ~RemoteRootWindowHostWin();
-
- // IPC message handing methods:
- void OnMouseMoved(int32 x, int32 y, int32 flags);
- void OnMouseButton(int32 x,
- int32 y,
- int32 extra,
- ui::EventType type,
- ui::EventFlags flags);
- void OnKeyDown(uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags);
- void OnKeyUp(uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags);
- void OnChar(uint32 key_code,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags);
- void OnWindowActivated();
- void OnTouchDown(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
- void OnTouchUp(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
- void OnTouchMoved(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
- void OnFileSaveAsDone(bool success,
- const base::FilePath& filename,
- int filter_index);
- void OnFileOpenDone(bool success, const base::FilePath& filename);
- void OnMultiFileOpenDone(bool success,
- const std::vector<base::FilePath>& files);
- void OnSelectFolderDone(bool success, const base::FilePath& folder);
- void OnSetCursorPosAck();
-
- // For Input Method support:
- ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate();
- void OnImeCandidatePopupChanged(bool visible);
- void OnImeCompositionChanged(
- const string16& text,
- int32 selection_start,
- int32 selection_end,
- const std::vector<metro_viewer::UnderlineInfo>& underlines);
- void OnImeTextCommitted(const string16& text);
- void OnImeInputSourceChanged(uint16 language_id, bool is_ime);
-
- // RootWindowHost overrides:
- virtual RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
- // ui::internal::RemoteInputMethodDelegateWin overrides:
- virtual void CancelComposition() OVERRIDE;
- virtual void OnTextInputClientUpdated(
- const std::vector<int32>& input_scopes,
- const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE;
-
- // Helper function to dispatch a keyboard message to the desired target.
- // The default target is the RootWindowHostDelegate. For nested message loop
- // invocations we post a synthetic keyboard message directly into the message
- // loop. The dispatcher for the nested loop would then decide how this
- // message is routed.
- void DispatchKeyboardMessage(ui::EventType type,
- uint32 vkey,
- uint32 repeat_count,
- uint32 scan_code,
- uint32 flags,
- bool is_character);
-
- // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a
- // change the system virtual key state is updated as well. This way if chrome
- // queries for key state it matches that of event being dispatched.
- void SetEventFlags(uint32 flags);
-
- uint32 mouse_event_flags() const {
- return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON |
- ui::EF_MIDDLE_MOUSE_BUTTON |
- ui::EF_RIGHT_MOUSE_BUTTON);
- }
-
- uint32 key_event_flags() const {
- return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
- ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_DOWN);
- }
-
- HWND remote_window_;
- IPC::Sender* host_;
- scoped_ptr<ui::ViewProp> prop_;
-
- // Saved callbacks which inform the caller about the result of the open file/
- // save file/select operations.
- OpenFileCompletion file_open_completion_callback_;
- OpenMultipleFilesCompletion multi_file_open_completion_callback_;
- SaveFileCompletion file_saveas_completion_callback_;
- SelectFolderCompletion select_folder_completion_callback_;
- FileSelectionCanceled failure_callback_;
-
- // Set to true if we need to ignore mouse messages until the SetCursorPos
- // operation is acked by the viewer.
- bool ignore_mouse_moves_until_set_cursor_ack_;
-
- // Tracking last click event for synthetically generated mouse events.
- scoped_ptr<ui::MouseEvent> last_mouse_click_event_;
-
- // State of the keyboard/mouse at the time of the last input event. See
- // description of SetEventFlags().
- uint32 event_flags_;
-
- // Current size of this root window.
- gfx::Size window_size_;
-
- DISALLOW_COPY_AND_ASSIGN(RemoteRootWindowHostWin);
-};
-
-} // namespace aura
-
-#endif // UI_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_
diff --git a/chromium/ui/aura/remote_window_tree_host_win.cc b/chromium/ui/aura/remote_window_tree_host_win.cc
new file mode 100644
index 00000000000..0cd5ee878e9
--- /dev/null
+++ b/chromium/ui/aura/remote_window_tree_host_win.cc
@@ -0,0 +1,525 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/remote_window_tree_host_win.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "base/message_loop/message_loop.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_sender.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/ime/composition_text.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/remote_input_method_win.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/view_prop.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/win/dpi.h"
+#include "ui/metro_viewer/metro_viewer_messages.h"
+
+namespace aura {
+
+namespace {
+
+const char* kWindowTreeHostWinKey = "__AURA_REMOTE_WINDOW_TREE_HOST_WIN__";
+
+// Sets the keystate for the virtual key passed in to down or up.
+void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) {
+ DCHECK(key_states);
+
+ if (key_down)
+ key_states[virtual_key_code] |= 0x80;
+ else
+ key_states[virtual_key_code] &= 0x7F;
+}
+
+// Sets the keyboard states for the Shift/Control/Alt/Caps lock keys.
+void SetVirtualKeyStates(uint32 flags) {
+ uint8 keyboard_state[256] = {0};
+ ::GetKeyboardState(keyboard_state);
+
+ SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_DOWN), VK_CAPITAL);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON),
+ VK_RBUTTON);
+ SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON),
+ VK_MBUTTON);
+
+ ::SetKeyboardState(keyboard_state);
+}
+
+void FillCompositionText(
+ const base::string16& text,
+ int32 selection_start,
+ int32 selection_end,
+ const std::vector<metro_viewer::UnderlineInfo>& underlines,
+ ui::CompositionText* composition_text) {
+ composition_text->Clear();
+ composition_text->text = text;
+ composition_text->selection.set_start(selection_start);
+ composition_text->selection.set_end(selection_end);
+ composition_text->underlines.resize(underlines.size());
+ for (size_t i = 0; i < underlines.size(); ++i) {
+ composition_text->underlines[i].start_offset = underlines[i].start_offset;
+ composition_text->underlines[i].end_offset = underlines[i].end_offset;
+ composition_text->underlines[i].color = SK_ColorBLACK;
+ composition_text->underlines[i].thick = underlines[i].thick;
+ composition_text->underlines[i].background_color = SK_ColorTRANSPARENT;
+ }
+}
+
+} // namespace
+
+RemoteWindowTreeHostWin* g_instance = NULL;
+
+// static
+RemoteWindowTreeHostWin* RemoteWindowTreeHostWin::Instance() {
+ return g_instance;
+}
+
+RemoteWindowTreeHostWin::RemoteWindowTreeHostWin()
+ : remote_window_(NULL),
+ host_(NULL),
+ ignore_mouse_moves_until_set_cursor_ack_(false),
+ event_flags_(0),
+ window_size_(aura::WindowTreeHost::GetNativeScreenSize()) {
+ CHECK(!g_instance);
+ g_instance = this;
+ prop_.reset(new ui::ViewProp(NULL, kWindowTreeHostWinKey, this));
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+RemoteWindowTreeHostWin::~RemoteWindowTreeHostWin() {
+ DestroyCompositor();
+ DestroyDispatcher();
+ DCHECK_EQ(g_instance, this);
+ g_instance = NULL;
+}
+
+// static
+bool RemoteWindowTreeHostWin::IsValid() {
+ return Instance()->remote_window_ != NULL;
+}
+
+void RemoteWindowTreeHostWin::SetRemoteWindowHandle(HWND remote_window) {
+ remote_window_ = remote_window;
+}
+
+void RemoteWindowTreeHostWin::Connected(IPC::Sender* host) {
+ CHECK(host_ == NULL);
+ DCHECK(remote_window_);
+ host_ = host;
+ // Recreate the compositor for the target surface represented by the
+ // remote_window HWND.
+ CreateCompositor(remote_window_);
+ InitCompositor();
+}
+
+void RemoteWindowTreeHostWin::Disconnected() {
+ // Don't CHECK here, Disconnected is called on a channel error which can
+ // happen before we're successfully Connected.
+ if (!host_)
+ return;
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (remote_input_method_private)
+ remote_input_method_private->SetRemoteDelegate(NULL);
+ host_ = NULL;
+ remote_window_ = NULL;
+}
+
+bool RemoteWindowTreeHostWin::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RemoteWindowTreeHostWin, message)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated,
+ OnWindowActivated)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_EdgeGesture, OnEdgeGesture)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown,
+ OnTouchDown)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp,
+ OnTouchUp)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved,
+ OnTouchMoved)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck,
+ OnSetCursorPosAck)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged,
+ OnImeCandidatePopupChanged)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCompositionChanged,
+ OnImeCompositionChanged)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted,
+ OnImeTextCommitted)
+ IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged,
+ OnImeInputSourceChanged)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void RemoteWindowTreeHostWin::HandleOpenURLOnDesktop(
+ const base::FilePath& shortcut,
+ const base::string16& url) {
+ if (!host_)
+ return;
+ host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url));
+}
+
+void RemoteWindowTreeHostWin::HandleWindowSizeChanged(uint32 width,
+ uint32 height) {
+ SetBounds(gfx::Rect(0, 0, width, height));
+}
+
+bool RemoteWindowTreeHostWin::IsForegroundWindow() {
+ return ::GetForegroundWindow() == remote_window_;
+}
+
+Window* RemoteWindowTreeHostWin::GetAshWindow() {
+ return window();
+}
+
+ui::EventSource* RemoteWindowTreeHostWin::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget RemoteWindowTreeHostWin::GetAcceleratedWidget() {
+ if (remote_window_)
+ return remote_window_;
+ // Getting here should only happen for ash_unittests.exe and related code.
+ return ::GetDesktopWindow();
+}
+
+void RemoteWindowTreeHostWin::Show() {
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (remote_input_method_private)
+ remote_input_method_private->SetRemoteDelegate(this);
+}
+
+void RemoteWindowTreeHostWin::Hide() {
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect RemoteWindowTreeHostWin::GetBounds() const {
+ return gfx::Rect(window_size_);
+}
+
+void RemoteWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) {
+ window_size_ = bounds.size();
+ OnHostResized(bounds.size());
+}
+
+gfx::Point RemoteWindowTreeHostWin::GetLocationOnNativeScreen() const {
+ return gfx::Point(0, 0);
+}
+
+void RemoteWindowTreeHostWin::SetCapture() {
+}
+
+void RemoteWindowTreeHostWin::ReleaseCapture() {
+}
+
+void RemoteWindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) {
+ if (!host_)
+ return;
+ host_->Send(
+ new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform())));
+}
+
+void RemoteWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) {
+ VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y();
+ if (!host_)
+ return;
+
+ // This function can be called in cases like when the mouse cursor is
+ // restricted within a viewport (For e.g. LockCursor) which assumes that
+ // subsequent mouse moves would be received starting with the new cursor
+ // coordinates. This is a challenge for Windows ASH for the reasons
+ // outlined below.
+ // Other cases which don't expect this behavior should continue to work
+ // without issues.
+
+ // The mouse events are received by the viewer process and sent to the
+ // browser. If we invoke the SetCursor API here we continue to receive
+ // mouse messages from the viewer which were posted before the SetCursor
+ // API executes which messes up the state in the browser. To workaround
+ // this we invoke the SetCursor API in the viewer process and ignore
+ // mouse messages until we received an ACK from the viewer indicating that
+ // the SetCursor operation completed.
+ ignore_mouse_moves_until_set_cursor_ack_ = true;
+ VLOG(1) << "In MoveCursorTo. Sending IPC";
+ host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y()));
+}
+
+void RemoteWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
+ NOTIMPLEMENTED();
+}
+
+void RemoteWindowTreeHostWin::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+}
+
+void RemoteWindowTreeHostWin::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+ NOTIMPLEMENTED();
+}
+
+ui::EventProcessor* RemoteWindowTreeHostWin::GetEventProcessor() {
+ return dispatcher();
+}
+
+void RemoteWindowTreeHostWin::CancelComposition() {
+ if (!host_)
+ return;
+ host_->Send(new MetroViewerHostMsg_ImeCancelComposition);
+}
+
+void RemoteWindowTreeHostWin::OnTextInputClientUpdated(
+ const std::vector<int32>& input_scopes,
+ const std::vector<gfx::Rect>& composition_character_bounds) {
+ if (!host_)
+ return;
+ std::vector<metro_viewer::CharacterBounds> character_bounds;
+ for (size_t i = 0; i < composition_character_bounds.size(); ++i) {
+ const gfx::Rect& rect = composition_character_bounds[i];
+ metro_viewer::CharacterBounds bounds;
+ bounds.left = rect.x();
+ bounds.top = rect.y();
+ bounds.right = rect.right();
+ bounds.bottom = rect.bottom();
+ character_bounds.push_back(bounds);
+ }
+ host_->Send(new MetroViewerHostMsg_ImeTextInputClientUpdated(
+ input_scopes, character_bounds));
+}
+
+gfx::Point PointFromNativeEvent(int32 x, int32 y) {
+ static float scale_factor = gfx::GetDPIScale();
+ gfx::Point result( x * scale_factor, y * scale_factor);
+ return result;
+}
+
+void RemoteWindowTreeHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) {
+ if (ignore_mouse_moves_until_set_cursor_ack_)
+ return;
+
+ gfx::Point location = PointFromNativeEvent(x, y);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags, 0);
+ SendEventToProcessor(&event);
+}
+
+void RemoteWindowTreeHostWin::OnMouseButton(
+ const MetroViewerHostMsg_MouseButtonParams& params) {
+ gfx::Point location = PointFromNativeEvent(params.x, params.y);
+ ui::MouseEvent mouse_event(params.event_type, location, location,
+ static_cast<int>(params.flags),
+ static_cast<int>(params.changed_button));
+
+ SetEventFlags(params.flags | key_event_flags());
+ if (params.event_type == ui::ET_MOUSEWHEEL) {
+ int x_offset = params.is_horizontal_wheel ? params.extra : 0;
+ int y_offset = !params.is_horizontal_wheel ? params.extra : 0;
+ ui::MouseWheelEvent wheel_event(mouse_event, x_offset, y_offset);
+ SendEventToProcessor(&wheel_event);
+ } else if (params.event_type == ui::ET_MOUSE_PRESSED) {
+ // TODO(shrikant): Ideally modify code in event.cc by adding automatic
+ // tracking of double clicks in synthetic MouseEvent constructor code.
+ // Non-synthetic MouseEvent constructor code does automatically track
+ // this. Need to use some caution while modifying synthetic constructor
+ // as many tests and other code paths depend on it and apparently
+ // specifically depend on non implicit tracking of previous mouse event.
+ if (last_mouse_click_event_ &&
+ ui::MouseEvent::IsRepeatedClickEvent(mouse_event,
+ *last_mouse_click_event_)) {
+ mouse_event.SetClickCount(2);
+ } else {
+ mouse_event.SetClickCount(1);
+ }
+ last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event));
+ SendEventToProcessor(&mouse_event);
+ } else {
+ SendEventToProcessor(&mouse_event);
+ }
+}
+
+void RemoteWindowTreeHostWin::OnKeyDown(uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags) {
+ DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code,
+ flags, false);
+}
+
+void RemoteWindowTreeHostWin::OnKeyUp(uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags) {
+ DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code,
+ flags, false);
+}
+
+void RemoteWindowTreeHostWin::OnChar(uint32 key_code,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags) {
+ DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count,
+ scan_code, flags, true);
+}
+
+void RemoteWindowTreeHostWin::OnWindowActivated() {
+ OnHostActivated();
+}
+
+void RemoteWindowTreeHostWin::OnEdgeGesture() {
+ ui::GestureEvent event(
+ ui::ET_GESTURE_WIN8_EDGE_SWIPE,
+ 0,
+ 0,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE, 0, 0),
+ 0);
+ SendEventToProcessor(&event);
+}
+
+void RemoteWindowTreeHostWin::OnTouchDown(int32 x,
+ int32 y,
+ uint64 timestamp,
+ uint32 pointer_id) {
+ gfx::Point location = PointFromNativeEvent(x, y);
+ ui::TouchEvent event(ui::ET_TOUCH_PRESSED,
+ location,
+ pointer_id,
+ base::TimeDelta::FromMicroseconds(timestamp));
+ SendEventToProcessor(&event);
+}
+
+void RemoteWindowTreeHostWin::OnTouchUp(int32 x,
+ int32 y,
+ uint64 timestamp,
+ uint32 pointer_id) {
+ gfx::Point location = PointFromNativeEvent(x, y);
+ ui::TouchEvent event(ui::ET_TOUCH_RELEASED,
+ location,
+ pointer_id,
+ base::TimeDelta::FromMicroseconds(timestamp));
+ SendEventToProcessor(&event);
+}
+
+void RemoteWindowTreeHostWin::OnTouchMoved(int32 x,
+ int32 y,
+ uint64 timestamp,
+ uint32 pointer_id) {
+ gfx::Point location = PointFromNativeEvent(x, y);
+ ui::TouchEvent event(ui::ET_TOUCH_MOVED,
+ location,
+ pointer_id,
+ base::TimeDelta::FromMicroseconds(timestamp));
+ SendEventToProcessor(&event);
+}
+
+void RemoteWindowTreeHostWin::OnSetCursorPosAck() {
+ DCHECK(ignore_mouse_moves_until_set_cursor_ack_);
+ ignore_mouse_moves_until_set_cursor_ack_ = false;
+}
+
+ui::RemoteInputMethodPrivateWin*
+RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() {
+ ui::InputMethod* input_method = GetAshWindow()->GetProperty(
+ aura::client::kRootWindowInputMethodKey);
+ return ui::RemoteInputMethodPrivateWin::Get(input_method);
+}
+
+void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) {
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (!remote_input_method_private)
+ return;
+ remote_input_method_private->OnCandidatePopupChanged(visible);
+}
+
+void RemoteWindowTreeHostWin::OnImeCompositionChanged(
+ const base::string16& text,
+ int32 selection_start,
+ int32 selection_end,
+ const std::vector<metro_viewer::UnderlineInfo>& underlines) {
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (!remote_input_method_private)
+ return;
+ ui::CompositionText composition_text;
+ FillCompositionText(
+ text, selection_start, selection_end, underlines, &composition_text);
+ remote_input_method_private->OnCompositionChanged(composition_text);
+}
+
+void RemoteWindowTreeHostWin::OnImeTextCommitted(const base::string16& text) {
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (!remote_input_method_private)
+ return;
+ remote_input_method_private->OnTextCommitted(text);
+}
+
+void RemoteWindowTreeHostWin::OnImeInputSourceChanged(uint16 language_id,
+ bool is_ime) {
+ ui::RemoteInputMethodPrivateWin* remote_input_method_private =
+ GetRemoteInputMethodPrivate();
+ if (!remote_input_method_private)
+ return;
+ remote_input_method_private->OnInputSourceChanged(language_id, is_ime);
+}
+
+void RemoteWindowTreeHostWin::DispatchKeyboardMessage(ui::EventType type,
+ uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags,
+ bool is_character) {
+ SetEventFlags(flags | mouse_event_flags());
+ if (base::MessageLoop::current()->IsNested()) {
+ int index = (flags & ui::EF_ALT_DOWN) ? 1 : 0;
+ const int char_message[] = {WM_CHAR, WM_SYSCHAR};
+ const int keydown_message[] = {WM_KEYDOWN, WM_SYSKEYDOWN};
+ const int keyup_message[] = {WM_KEYUP, WM_SYSKEYUP};
+ uint32 message = is_character
+ ? char_message[index]
+ : (type == ui::ET_KEY_PRESSED ? keydown_message[index]
+ : keyup_message[index]);
+ ::PostThreadMessage(::GetCurrentThreadId(),
+ message,
+ vkey,
+ repeat_count | scan_code >> 15);
+ } else {
+ ui::KeyEvent event(type,
+ ui::KeyboardCodeForWindowsKeyCode(vkey),
+ flags,
+ is_character);
+ SendEventToProcessor(&event);
+ }
+}
+
+void RemoteWindowTreeHostWin::SetEventFlags(uint32 flags) {
+ if (flags == event_flags_)
+ return;
+ event_flags_ = flags;
+ SetVirtualKeyStates(event_flags_);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/remote_window_tree_host_win.h b/chromium/ui/aura/remote_window_tree_host_win.h
new file mode 100644
index 00000000000..ae63b744715
--- /dev/null
+++ b/chromium/ui/aura/remote_window_tree_host_win.h
@@ -0,0 +1,194 @@
+// 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_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
+#define UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/remote_input_method_delegate_win.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_source.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/metro_viewer/ime_types.h"
+
+struct MetroViewerHostMsg_MouseButtonParams;
+
+namespace base {
+class FilePath;
+}
+
+namespace ui {
+class RemoteInputMethodPrivateWin;
+class ViewProp;
+}
+
+namespace IPC {
+class Message;
+class Sender;
+}
+
+namespace aura {
+
+// WindowTreeHost implementaton that receives events from a different
+// process. In the case of Windows this is the Windows 8 (aka Metro)
+// frontend process, which forwards input events to this class.
+class AURA_EXPORT RemoteWindowTreeHostWin
+ : public WindowTreeHost,
+ public ui::EventSource,
+ public ui::internal::RemoteInputMethodDelegateWin {
+ public:
+ // Returns the current RemoteWindowTreeHostWin. This does *not* create a
+ // RemoteWindowTreeHostWin.
+ static RemoteWindowTreeHostWin* Instance();
+
+ // Returns true if there is a RemoteWindowTreeHostWin and it has a valid
+ // HWND. A return value of false typically indicates we're not in metro mode.
+ static bool IsValid();
+
+ // Sets the handle to the remote window. The |remote_window| is the actual
+ // window owned by the viewer process. Call this before Connected() for some
+ // customers like input method initialization which needs the handle.
+ void SetRemoteWindowHandle(HWND remote_window);
+ HWND remote_window() { return remote_window_; }
+
+ // The |host| can be used when we need to send a message to it.
+ void Connected(IPC::Sender* host);
+ // Called when the remote process has closed its IPC connection.
+ void Disconnected();
+
+ // Called when we have a message from the remote process.
+ bool OnMessageReceived(const IPC::Message& message);
+
+ void HandleOpenURLOnDesktop(const base::FilePath& shortcut,
+ const base::string16& url);
+
+ void HandleWindowSizeChanged(uint32 width, uint32 height);
+
+ // Returns the active ASH root window.
+ Window* GetAshWindow();
+
+ // Returns true if the remote window is the foreground window according to the
+ // OS.
+ bool IsForegroundWindow();
+
+ protected:
+ RemoteWindowTreeHostWin();
+ virtual ~RemoteWindowTreeHostWin();
+
+ private:
+ // IPC message handing methods:
+ void OnMouseMoved(int32 x, int32 y, int32 flags);
+ void OnMouseButton(const MetroViewerHostMsg_MouseButtonParams& params);
+ void OnKeyDown(uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags);
+ void OnKeyUp(uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags);
+ void OnChar(uint32 key_code,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags);
+ void OnWindowActivated();
+ void OnEdgeGesture();
+ void OnTouchDown(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
+ void OnTouchUp(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
+ void OnTouchMoved(int32 x, int32 y, uint64 timestamp, uint32 pointer_id);
+ void OnSetCursorPosAck();
+
+ // For Input Method support:
+ ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate();
+ void OnImeCandidatePopupChanged(bool visible);
+ void OnImeCompositionChanged(
+ const base::string16& text,
+ int32 selection_start,
+ int32 selection_end,
+ const std::vector<metro_viewer::UnderlineInfo>& underlines);
+ void OnImeTextCommitted(const base::string16& text);
+ void OnImeInputSourceChanged(uint16 language_id, bool is_ime);
+
+ // WindowTreeHost overrides:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+
+ // ui::EventSource:
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ // ui::internal::RemoteInputMethodDelegateWin overrides:
+ virtual void CancelComposition() OVERRIDE;
+ virtual void OnTextInputClientUpdated(
+ const std::vector<int32>& input_scopes,
+ const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE;
+
+ // Helper function to dispatch a keyboard message to the desired target.
+ // The default target is the WindowEventDispatcher. For nested message loop
+ // invocations we post a synthetic keyboard message directly into the message
+ // loop. The dispatcher for the nested loop would then decide how this
+ // message is routed.
+ void DispatchKeyboardMessage(ui::EventType type,
+ uint32 vkey,
+ uint32 repeat_count,
+ uint32 scan_code,
+ uint32 flags,
+ bool is_character);
+
+ // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a
+ // change the system virtual key state is updated as well. This way if chrome
+ // queries for key state it matches that of event being dispatched.
+ void SetEventFlags(uint32 flags);
+
+ uint32 mouse_event_flags() const {
+ return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON |
+ ui::EF_MIDDLE_MOUSE_BUTTON |
+ ui::EF_RIGHT_MOUSE_BUTTON);
+ }
+
+ uint32 key_event_flags() const {
+ return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
+ ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_DOWN);
+ }
+
+ HWND remote_window_;
+ IPC::Sender* host_;
+ scoped_ptr<ui::ViewProp> prop_;
+
+ // Set to true if we need to ignore mouse messages until the SetCursorPos
+ // operation is acked by the viewer.
+ bool ignore_mouse_moves_until_set_cursor_ack_;
+
+ // Tracking last click event for synthetically generated mouse events.
+ scoped_ptr<ui::MouseEvent> last_mouse_click_event_;
+
+ // State of the keyboard/mouse at the time of the last input event. See
+ // description of SetEventFlags().
+ uint32 event_flags_;
+
+ // Current size of this root window.
+ gfx::Size window_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteWindowTreeHostWin);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_
diff --git a/chromium/ui/aura/root_window.cc b/chromium/ui/aura/root_window.cc
deleted file mode 100644
index 58790da1c36..00000000000
--- a/chromium/ui/aura/root_window.cc
+++ /dev/null
@@ -1,1172 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/root_window.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/event_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window_observer.h"
-#include "ui/aura/root_window_transformer.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/aura/window_targeter.h"
-#include "ui/aura/window_tracker.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/hit_test.h"
-#include "ui/base/view_prop.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/events/event.h"
-#include "ui/events/gestures/gesture_recognizer.h"
-#include "ui/events/gestures/gesture_types.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/point3_f.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
-
-using std::vector;
-
-typedef ui::EventDispatchDetails DispatchDetails;
-
-namespace aura {
-
-namespace {
-
-const char kRootWindowForAcceleratedWidget[] =
- "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__";
-
-// Returns true if |target| has a non-client (frame) component at |location|,
-// in window coordinates.
-bool IsNonClientLocation(Window* target, const gfx::Point& location) {
- if (!target->delegate())
- return false;
- int hit_test_code = target->delegate()->GetNonClientComponent(location);
- return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE;
-}
-
-float GetDeviceScaleFactorFromDisplay(Window* window) {
- gfx::Display display = gfx::Screen::GetScreenFor(window)->
- GetDisplayNearestWindow(window);
- DCHECK(display.is_valid());
- return display.device_scale_factor();
-}
-
-Window* ConsumerToWindow(ui::GestureConsumer* consumer) {
- return consumer ? static_cast<Window*>(consumer) : NULL;
-}
-
-void SetLastMouseLocation(const Window* root_window,
- const gfx::Point& location_in_root) {
- client::ScreenPositionClient* client =
- client::GetScreenPositionClient(root_window);
- if (client) {
- gfx::Point location_in_screen = location_in_root;
- client->ConvertPointToScreen(root_window, &location_in_screen);
- Env::GetInstance()->set_last_mouse_location(location_in_screen);
- } else {
- Env::GetInstance()->set_last_mouse_location(location_in_root);
- }
-}
-
-RootWindowHost* CreateHost(RootWindow* root_window,
- const RootWindow::CreateParams& params) {
- RootWindowHost* host = params.host ?
- params.host : RootWindowHost::Create(params.initial_bounds);
- host->set_delegate(root_window);
- return host;
-}
-
-bool IsUsingEventProcessorForDispatch(const ui::Event& event) {
- return event.IsKeyEvent() ||
- event.IsScrollEvent();
-}
-
-class SimpleRootWindowTransformer : public RootWindowTransformer {
- public:
- SimpleRootWindowTransformer(const Window* root_window,
- const gfx::Transform& transform)
- : root_window_(root_window),
- transform_(transform) {
- }
-
- // RootWindowTransformer overrides:
- virtual gfx::Transform GetTransform() const OVERRIDE {
- return transform_;
- }
-
- virtual gfx::Transform GetInverseTransform() const OVERRIDE {
- gfx::Transform invert;
- if (!transform_.GetInverse(&invert))
- return transform_;
- return invert;
- }
-
- virtual gfx::Rect GetRootWindowBounds(
- const gfx::Size& host_size) const OVERRIDE {
- gfx::Rect bounds(host_size);
- gfx::RectF new_bounds(ui::ConvertRectToDIP(root_window_->layer(), bounds));
- transform_.TransformRect(&new_bounds);
- return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
- }
-
- virtual gfx::Insets GetHostInsets() const OVERRIDE {
- return gfx::Insets();
- }
-
- private:
- virtual ~SimpleRootWindowTransformer() {}
-
- const Window* root_window_;
- const gfx::Transform transform_;
-
- DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer);
-};
-
-} // namespace
-
-RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds)
- : initial_bounds(a_initial_bounds),
- host(NULL) {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, public:
-
-RootWindow::RootWindow(const CreateParams& params)
- : window_(new Window(NULL)),
- host_(CreateHost(this, params)),
- touch_ids_down_(0),
- last_cursor_(ui::kCursorNull),
- mouse_pressed_handler_(NULL),
- mouse_moved_handler_(NULL),
- event_dispatch_target_(NULL),
- old_dispatch_target_(NULL),
- synthesize_mouse_move_(false),
- move_hold_count_(0),
- dispatching_held_event_(false),
- repost_event_factory_(this),
- held_event_factory_(this) {
- window()->set_dispatcher(this);
- window()->SetName("RootWindow");
- window()->set_event_targeter(
- scoped_ptr<ui::EventTargeter>(new WindowTargeter()));
-
- compositor_.reset(new ui::Compositor(host_->GetAcceleratedWidget()));
- DCHECK(compositor_.get());
-
- prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(),
- kRootWindowForAcceleratedWidget,
- this));
- ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
-}
-
-RootWindow::~RootWindow() {
- TRACE_EVENT0("shutdown", "RootWindow::Destructor");
-
- ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
-
- // Make sure to destroy the compositor before terminating so that state is
- // cleared and we don't hit asserts.
- compositor_.reset();
-
- // An observer may have been added by an animation on the RootWindow.
- window()->layer()->GetAnimator()->RemoveObserver(this);
-
- // Destroy child windows while we're still valid. This is also done by
- // ~Window, but by that time any calls to virtual methods overriden here (such
- // as GetRootWindow()) result in Window's implementation. By destroying here
- // we ensure GetRootWindow() still returns this.
- window()->RemoveOrDestroyChildren();
-
- // Destroying/removing child windows may try to access |host_| (eg.
- // GetAcceleratedWidget())
- host_.reset(NULL);
-
- window()->set_dispatcher(NULL);
-}
-
-// static
-RootWindow* RootWindow::GetForAcceleratedWidget(
- gfx::AcceleratedWidget widget) {
- return reinterpret_cast<RootWindow*>(
- ui::ViewProp::GetValue(widget, kRootWindowForAcceleratedWidget));
-}
-
-void RootWindow::Init() {
- compositor()->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
- host_->GetBounds().size());
- window()->Init(ui::LAYER_NOT_DRAWN);
- compositor()->SetRootLayer(window()->layer());
- transformer_.reset(
- new SimpleRootWindowTransformer(window(), gfx::Transform()));
- UpdateRootWindowSize(host_->GetBounds().size());
- Env::GetInstance()->NotifyRootWindowInitialized(this);
- window()->Show();
-}
-
-void RootWindow::PrepareForShutdown() {
- host_->PrepareForShutdown();
- // discard synthesize event request as well.
- synthesize_mouse_move_ = false;
-}
-
-void RootWindow::RepostEvent(const ui::LocatedEvent& event) {
- DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
- event.type() == ui::ET_GESTURE_TAP_DOWN);
- // We allow for only one outstanding repostable event. This is used
- // in exiting context menus. A dropped repost request is allowed.
- if (event.type() == ui::ET_MOUSE_PRESSED) {
- held_repostable_event_.reset(
- new ui::MouseEvent(
- static_cast<const ui::MouseEvent&>(event),
- static_cast<aura::Window*>(event.target()),
- window()));
- base::MessageLoop::current()->PostNonNestableTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&RootWindow::DispatchHeldEvents),
- repost_event_factory_.GetWeakPtr()));
- } else {
- DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
- held_repostable_event_.reset();
- // TODO(rbyers): Reposing of gestures is tricky to get
- // right, so it's not yet supported. crbug.com/170987.
- }
-}
-
-RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() {
- return this;
-}
-
-void RootWindow::SetHostSize(const gfx::Size& size_in_pixel) {
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return;
- gfx::Rect bounds = host_->GetBounds();
- bounds.set_size(size_in_pixel);
- host_->SetBounds(bounds);
-
- // Requery the location to constrain it within the new root window size.
- gfx::Point point;
- if (host_->QueryMouseLocation(&point)) {
- SetLastMouseLocation(window(),
- ui::ConvertPointToDIP(window()->layer(), point));
- }
-
- synthesize_mouse_move_ = false;
-}
-
-void RootWindow::SetHostBounds(const gfx::Rect& bounds_in_pixel) {
- DCHECK(!bounds_in_pixel.IsEmpty());
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return;
- host_->SetBounds(bounds_in_pixel);
- synthesize_mouse_move_ = false;
-}
-
-void RootWindow::SetCursor(gfx::NativeCursor cursor) {
- last_cursor_ = cursor;
- // A lot of code seems to depend on NULL cursors actually showing an arrow,
- // so just pass everything along to the host.
- host_->SetCursor(cursor);
-}
-
-void RootWindow::OnCursorVisibilityChanged(bool show) {
- // Clear any existing mouse hover effects when the cursor becomes invisible.
- // Note we do not need to dispatch a mouse enter when the cursor becomes
- // visible because that can only happen in response to a mouse event, which
- // will trigger its own mouse enter.
- if (!show)
- DispatchMouseExitAtPoint(GetLastMouseLocationInRoot());
-
- host_->OnCursorVisibilityChanged(show);
-}
-
-void RootWindow::OnMouseEventsEnableStateChanged(bool enabled) {
- // Send entered / exited so that visual state can be updated to match
- // mouse events state.
- PostMouseMoveEventAfterWindowChange();
- // TODO(mazda): Add code to disable mouse events when |enabled| == false.
-}
-
-void RootWindow::MoveCursorTo(const gfx::Point& location_in_dip) {
- gfx::Point host_location(location_in_dip);
- ConvertPointToHost(&host_location);
- MoveCursorToInternal(location_in_dip, host_location);
-}
-
-void RootWindow::MoveCursorToHostLocation(const gfx::Point& host_location) {
- gfx::Point root_location(host_location);
- ConvertPointFromHost(&root_location);
- MoveCursorToInternal(root_location, host_location);
-}
-
-void RootWindow::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
- compositor_->ScheduleRedrawRect(damage_rect);
-}
-
-Window* RootWindow::GetGestureTarget(ui::GestureEvent* event) {
- Window* target = NULL;
- if (!event->IsEndingEvent()) {
- // The window that received the start event (e.g. scroll begin) needs to
- // receive the end event (e.g. scroll end).
- target = client::GetCaptureWindow(window());
- }
- if (!target) {
- target = ConsumerToWindow(
- ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event));
- }
-
- return target;
-}
-
-void RootWindow::DispatchGestureEvent(ui::GestureEvent* event) {
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return;
-
- Window* target = GetGestureTarget(event);
- if (target) {
- event->ConvertLocationToTarget(window(), target);
- DispatchDetails details = DispatchEvent(target, event);
- if (details.dispatcher_destroyed)
- return;
- }
-}
-
-void RootWindow::OnWindowDestroying(Window* window) {
- DispatchMouseExitToHidingWindow(window);
- OnWindowHidden(window, WINDOW_DESTROYED);
-
- if (window->IsVisible() &&
- window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
- PostMouseMoveEventAfterWindowChange();
- }
-}
-
-void RootWindow::OnWindowBoundsChanged(Window* window,
- bool contained_mouse_point) {
- if (contained_mouse_point ||
- (window->IsVisible() &&
- window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
- PostMouseMoveEventAfterWindowChange();
- }
-}
-
-void RootWindow::DispatchMouseExitToHidingWindow(Window* window) {
- // The mouse capture is intentionally ignored. Think that a mouse enters
- // to a window, the window sets the capture, the mouse exits the window,
- // and then it releases the capture. In that case OnMouseExited won't
- // be called. So it is natural not to emit OnMouseExited even though
- // |window| is the capture window.
- gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
- if (window->Contains(mouse_moved_handler_) &&
- window->ContainsPointInRoot(last_mouse_location))
- DispatchMouseExitAtPoint(last_mouse_location);
-}
-
-void RootWindow::DispatchMouseExitAtPoint(const gfx::Point& point) {
- ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE);
- DispatchDetails details =
- DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
- if (details.dispatcher_destroyed)
- return;
-}
-
-void RootWindow::OnWindowVisibilityChanged(Window* window, bool is_visible) {
- if (!is_visible)
- OnWindowHidden(window, WINDOW_HIDDEN);
-
- if (window->ContainsPointInRoot(GetLastMouseLocationInRoot()))
- PostMouseMoveEventAfterWindowChange();
-}
-
-void RootWindow::OnWindowTransformed(Window* window, bool contained_mouse) {
- if (contained_mouse ||
- (window->IsVisible() &&
- window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
- PostMouseMoveEventAfterWindowChange();
- }
-}
-
-void RootWindow::OnKeyboardMappingChanged() {
- FOR_EACH_OBSERVER(RootWindowObserver, observers_,
- OnKeyboardMappingChanged(this));
-}
-
-void RootWindow::OnRootWindowHostCloseRequested() {
- FOR_EACH_OBSERVER(RootWindowObserver, observers_,
- OnRootWindowHostCloseRequested(this));
-}
-
-void RootWindow::AddRootWindowObserver(RootWindowObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void RootWindow::RemoveRootWindowObserver(RootWindowObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void RootWindow::ConvertPointToHost(gfx::Point* point) const {
- gfx::Point3F point_3f(*point);
- GetRootTransform().TransformPoint(&point_3f);
- *point = gfx::ToFlooredPoint(point_3f.AsPointF());
-}
-
-void RootWindow::ConvertPointFromHost(gfx::Point* point) const {
- gfx::Point3F point_3f(*point);
- GetInverseRootTransform().TransformPoint(&point_3f);
- *point = gfx::ToFlooredPoint(point_3f.AsPointF());
-}
-
-void RootWindow::ProcessedTouchEvent(ui::TouchEvent* event,
- Window* window,
- ui::EventResult result) {
- scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
- gestures.reset(ui::GestureRecognizer::Get()->
- ProcessTouchEventForGesture(*event, result, window));
- DispatchDetails details = ProcessGestures(gestures.get());
- if (details.dispatcher_destroyed)
- return;
-}
-
-void RootWindow::HoldPointerMoves() {
- if (!move_hold_count_)
- held_event_factory_.InvalidateWeakPtrs();
- ++move_hold_count_;
- TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this);
-}
-
-void RootWindow::ReleasePointerMoves() {
- --move_hold_count_;
- DCHECK_GE(move_hold_count_, 0);
- if (!move_hold_count_ && held_move_event_) {
- // We don't want to call DispatchHeldEvents directly, because this might be
- // called from a deep stack while another event, in which case dispatching
- // another one may not be safe/expected. Instead we post a task, that we
- // may cancel if HoldPointerMoves is called again before it executes.
- base::MessageLoop::current()->PostNonNestableTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&RootWindow::DispatchHeldEvents),
- held_event_factory_.GetWeakPtr()));
- }
- TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this);
-}
-
-gfx::Point RootWindow::GetLastMouseLocationInRoot() const {
- gfx::Point location = Env::GetInstance()->last_mouse_location();
- client::ScreenPositionClient* client =
- client::GetScreenPositionClient(window());
- if (client)
- client->ConvertPointFromScreen(window(), &location);
- return location;
-}
-
-void RootWindow::SetRootWindowTransformer(
- scoped_ptr<RootWindowTransformer> transformer) {
- transformer_ = transformer.Pass();
- host_->SetInsets(transformer_->GetHostInsets());
- window()->SetTransform(transformer_->GetTransform());
- // If the layer is not animating, then we need to update the root window
- // size immediately.
- if (!window()->layer()->GetAnimator()->is_animating())
- UpdateRootWindowSize(host_->GetBounds().size());
-}
-
-gfx::Transform RootWindow::GetRootTransform() const {
- float scale = ui::GetDeviceScaleFactor(window()->layer());
- gfx::Transform transform;
- transform.Scale(scale, scale);
- transform *= transformer_->GetTransform();
- return transform;
-}
-
-void RootWindow::SetTransform(const gfx::Transform& transform) {
- scoped_ptr<RootWindowTransformer> transformer(
- new SimpleRootWindowTransformer(window(), transform));
- SetRootWindowTransformer(transformer.Pass());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, private:
-
-void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent* event) {
- event->UpdateForRootTransform(GetInverseRootTransform());
-}
-
-void RootWindow::MoveCursorToInternal(const gfx::Point& root_location,
- const gfx::Point& host_location) {
- host_->MoveCursorTo(host_location);
- SetLastMouseLocation(window(), root_location);
- client::CursorClient* cursor_client = client::GetCursorClient(window());
- if (cursor_client) {
- const gfx::Display& display =
- gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
- cursor_client->SetDisplay(display);
- }
- synthesize_mouse_move_ = false;
-}
-
-ui::EventDispatchDetails RootWindow::DispatchMouseEnterOrExit(
- const ui::MouseEvent& event,
- ui::EventType type) {
- if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate())
- return DispatchDetails();
-
- ui::MouseEvent translated_event(event,
- window(),
- mouse_moved_handler_,
- type,
- event.flags() | ui::EF_IS_SYNTHESIZED);
- return DispatchEvent(mouse_moved_handler_, &translated_event);
-}
-
-ui::EventDispatchDetails RootWindow::ProcessGestures(
- ui::GestureRecognizer::Gestures* gestures) {
- DispatchDetails details;
- if (!gestures || gestures->empty())
- return details;
-
- Window* target = GetGestureTarget(gestures->get().at(0));
- for (size_t i = 0; i < gestures->size(); ++i) {
- ui::GestureEvent* event = gestures->get().at(i);
- event->ConvertLocationToTarget(window(), target);
- details = DispatchEvent(target, event);
- if (details.dispatcher_destroyed || details.target_destroyed)
- break;
- }
- return details;
-}
-
-void RootWindow::OnWindowAddedToRootWindow(Window* attached) {
- if (attached->IsVisible() &&
- attached->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
- PostMouseMoveEventAfterWindowChange();
- }
-}
-
-void RootWindow::OnWindowRemovedFromRootWindow(Window* detached,
- Window* new_root) {
- DCHECK(aura::client::GetCaptureWindow(window()) != window());
-
- DispatchMouseExitToHidingWindow(detached);
- OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN);
-
- if (detached->IsVisible() &&
- detached->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
- PostMouseMoveEventAfterWindowChange();
- }
-}
-
-void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) {
- // Do not clear the capture, and the |event_dispatch_target_| if the
- // window is moving across root windows, because the target itself
- // is actually still visible and clearing them stops further event
- // processing, which can cause unexpected behaviors. See
- // crbug.com/157583
- if (reason != WINDOW_MOVING) {
- Window* capture_window = aura::client::GetCaptureWindow(window());
- // If the ancestor of the capture window is hidden,
- // release the capture.
- if (invisible->Contains(capture_window) && invisible != window())
- capture_window->ReleaseCapture();
-
- if (invisible->Contains(event_dispatch_target_))
- event_dispatch_target_ = NULL;
-
- if (invisible->Contains(old_dispatch_target_))
- old_dispatch_target_ = NULL;
- }
-
- // If the ancestor of any event handler windows are invisible, release the
- // pointer to those windows.
- if (invisible->Contains(mouse_pressed_handler_))
- mouse_pressed_handler_ = NULL;
- if (invisible->Contains(mouse_moved_handler_))
- mouse_moved_handler_ = NULL;
-
- CleanupGestureState(invisible);
-}
-
-void RootWindow::CleanupGestureState(Window* window) {
- ui::GestureRecognizer::Get()->CancelActiveTouches(window);
- ui::GestureRecognizer::Get()->CleanupStateForConsumer(window);
- const Window::Windows& windows = window->children();
- for (Window::Windows::const_iterator iter = windows.begin();
- iter != windows.end();
- ++iter) {
- CleanupGestureState(*iter);
- }
-}
-
-void RootWindow::UpdateRootWindowSize(const gfx::Size& host_size) {
- window()->SetBounds(transformer_->GetRootWindowBounds(host_size));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, aura::client::CaptureDelegate implementation:
-
-void RootWindow::UpdateCapture(Window* old_capture,
- Window* new_capture) {
- // |mouse_moved_handler_| may have been set to a Window in a different root
- // (see below). Clear it here to ensure we don't end up referencing a stale
- // Window.
- if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_))
- mouse_moved_handler_ = NULL;
-
- if (old_capture && old_capture->GetRootWindow() == window() &&
- old_capture->delegate()) {
- // Send a capture changed event with bogus location data.
- ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
- gfx::Point(), 0);
-
- DispatchDetails details = DispatchEvent(old_capture, &event);
- if (details.dispatcher_destroyed)
- return;
-
- old_capture->delegate()->OnCaptureLost();
- }
-
- if (new_capture) {
- // Make all subsequent mouse events go to the capture window. We shouldn't
- // need to send an event here as OnCaptureLost() should take care of that.
- if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown())
- mouse_moved_handler_ = new_capture;
- } else {
- // Make sure mouse_moved_handler gets updated.
- DispatchDetails details = SynthesizeMouseMoveEvent();
- if (details.dispatcher_destroyed)
- return;
- }
- mouse_pressed_handler_ = NULL;
-}
-
-void RootWindow::OnOtherRootGotCapture() {
- mouse_moved_handler_ = NULL;
- mouse_pressed_handler_ = NULL;
-}
-
-void RootWindow::SetNativeCapture() {
- host_->SetCapture();
-}
-
-void RootWindow::ReleaseNativeCapture() {
- host_->ReleaseCapture();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, ui::EventProcessor implementation:
-ui::EventTarget* RootWindow::GetRootTarget() {
- return window();
-}
-
-void RootWindow::PrepareEventForDispatch(ui::Event* event) {
- if (event->IsMouseEvent() ||
- event->IsScrollEvent() ||
- event->IsTouchEvent() ||
- event->IsGestureEvent()) {
- TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event));
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, ui::EventDispatcherDelegate implementation:
-
-bool RootWindow::CanDispatchToTarget(ui::EventTarget* target) {
- return event_dispatch_target_ == target;
-}
-
-ui::EventDispatchDetails RootWindow::PreDispatchEvent(ui::EventTarget* target,
- ui::Event* event) {
- if (!dispatching_held_event_ && IsUsingEventProcessorForDispatch(*event)) {
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed || details.target_destroyed)
- return details;
-
- Window* target_window = static_cast<Window*>(target);
- if (event->IsScrollEvent()) {
- PreDispatchLocatedEvent(target_window,
- static_cast<ui::ScrollEvent*>(event));
- }
- }
- old_dispatch_target_ = event_dispatch_target_;
- event_dispatch_target_ = static_cast<Window*>(target);
- return DispatchDetails();
-}
-
-ui::EventDispatchDetails RootWindow::PostDispatchEvent(ui::EventTarget* target,
- const ui::Event& event) {
- DispatchDetails details;
- if (target != event_dispatch_target_)
- details.target_destroyed = true;
- event_dispatch_target_ = old_dispatch_target_;
- old_dispatch_target_ = NULL;
-#ifndef NDEBUG
- DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_));
-#endif
- return details;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, ui::GestureEventHelper implementation:
-
-bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer* consumer) {
- Window* consumer_window = ConsumerToWindow(consumer);;
- return (consumer_window && consumer_window->GetRootWindow() == window());
-}
-
-void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent* event) {
- DispatchGestureEvent(event);
-}
-
-void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) {
- OnHostTouchEvent(event);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, ui::LayerAnimationObserver implementation:
-
-void RootWindow::OnLayerAnimationEnded(
- ui::LayerAnimationSequence* animation) {
- UpdateRootWindowSize(host_->GetBounds().size());
-}
-
-void RootWindow::OnLayerAnimationScheduled(
- ui::LayerAnimationSequence* animation) {
-}
-
-void RootWindow::OnLayerAnimationAborted(
- ui::LayerAnimationSequence* animation) {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, RootWindowHostDelegate implementation:
-
-bool RootWindow::OnHostKeyEvent(ui::KeyEvent* event) {
- DispatchDetails details = OnEventFromSource(event);
- if (details.dispatcher_destroyed)
- event->SetHandled();
- return event->handled();
-}
-
-bool RootWindow::OnHostMouseEvent(ui::MouseEvent* event) {
- DispatchDetails details = OnHostMouseEventImpl(event);
- return event->handled() || details.dispatcher_destroyed;
-}
-
-bool RootWindow::OnHostScrollEvent(ui::ScrollEvent* event) {
- DispatchDetails details = OnEventFromSource(event);
- if (details.dispatcher_destroyed)
- event->SetHandled();
- return event->handled();
-}
-
-bool RootWindow::OnHostTouchEvent(ui::TouchEvent* event) {
- if ((event->type() == ui::ET_TOUCH_MOVED)) {
- if (move_hold_count_) {
- Window* null_window = static_cast<Window*>(NULL);
- held_move_event_.reset(
- new ui::TouchEvent(*event, null_window, null_window));
- return true;
- } else {
- // We may have a held event for a period between the time move_hold_count_
- // fell to 0 and the DispatchHeldEvents executes. Since we're going to
- // dispatch the new event directly below, we can reset the old one.
- held_move_event_.reset();
- }
- }
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return false;
- details = DispatchTouchEventImpl(event);
- if (details.dispatcher_destroyed)
- return true;
- return event->handled();
-}
-
-void RootWindow::OnHostCancelMode() {
- ui::CancelModeEvent event;
- Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow();
- DispatchDetails details =
- DispatchEvent(focused_window ? focused_window : window(), &event);
- if (details.dispatcher_destroyed)
- return;
-}
-
-void RootWindow::OnHostActivated() {
- Env::GetInstance()->RootWindowActivated(this);
-}
-
-void RootWindow::OnHostLostWindowCapture() {
- Window* capture_window = client::GetCaptureWindow(window());
- if (capture_window && capture_window->GetRootWindow() == window())
- capture_window->ReleaseCapture();
-}
-
-void RootWindow::OnHostLostMouseGrab() {
- mouse_pressed_handler_ = NULL;
- mouse_moved_handler_ = NULL;
-}
-
-void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) {
- compositor_->ScheduleRedrawRect(damage_rect);
-}
-
-void RootWindow::OnHostMoved(const gfx::Point& origin) {
- TRACE_EVENT1("ui", "RootWindow::OnHostMoved",
- "origin", origin.ToString());
-
- FOR_EACH_OBSERVER(RootWindowObserver, observers_,
- OnRootWindowHostMoved(this, origin));
-}
-
-void RootWindow::OnHostResized(const gfx::Size& size) {
- TRACE_EVENT1("ui", "RootWindow::OnHostResized",
- "size", size.ToString());
-
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return;
- // 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(GetDeviceScaleFactorFromDisplay(window()), size);
-
- // The layer, and the observers should be notified of the
- // transformed size of the root window.
- UpdateRootWindowSize(host_->GetBounds().size());
- FOR_EACH_OBSERVER(RootWindowObserver, observers_,
- OnRootWindowHostResized(this));
-}
-
-float RootWindow::GetDeviceScaleFactor() {
- return compositor()->device_scale_factor();
-}
-
-RootWindow* RootWindow::AsRootWindow() {
- return this;
-}
-
-const RootWindow* RootWindow::AsRootWindow() const {
- return this;
-}
-
-ui::EventProcessor* RootWindow::GetEventProcessor() {
- return this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindow, private:
-
-ui::EventDispatchDetails RootWindow::OnHostMouseEventImpl(
- ui::MouseEvent* event) {
- if (event->type() == ui::ET_MOUSE_DRAGGED ||
- (event->flags() & ui::EF_IS_SYNTHESIZED)) {
- if (move_hold_count_) {
- Window* null_window = static_cast<Window*>(NULL);
- held_move_event_.reset(
- new ui::MouseEvent(*event, null_window, null_window));
- event->SetHandled();
- return DispatchDetails();
- } else {
- // We may have a held event for a period between the time move_hold_count_
- // fell to 0 and the DispatchHeldEvents executes. Since we're going to
- // dispatch the new event directly below, we can reset the old one.
- held_move_event_.reset();
- }
- }
- DispatchDetails details = DispatchHeldEvents();
- if (details.dispatcher_destroyed)
- return details;
- return DispatchMouseEventImpl(event);
-}
-
-ui::EventDispatchDetails RootWindow::DispatchMouseEventImpl(
- ui::MouseEvent* event) {
- TransformEventForDeviceScaleFactor(event);
- Window* target = mouse_pressed_handler_ ?
- mouse_pressed_handler_ : client::GetCaptureWindow(window());
- if (!target)
- target = window()->GetEventHandlerForPoint(event->location());
- return DispatchMouseEventToTarget(event, target);
-}
-
-ui::EventDispatchDetails RootWindow::DispatchMouseEventRepost(
- ui::MouseEvent* event) {
- if (event->type() != ui::ET_MOUSE_PRESSED)
- return DispatchDetails();
- Window* target = client::GetCaptureWindow(window());
- WindowEventDispatcher* dispatcher = this;
- if (!target) {
- target = window()->GetEventHandlerForPoint(event->location());
- } else {
- dispatcher = target->GetDispatcher();
- CHECK(dispatcher); // Capture window better be in valid root.
- }
- dispatcher->mouse_pressed_handler_ = NULL;
- return dispatcher->DispatchMouseEventToTarget(event, target);
-}
-
-ui::EventDispatchDetails RootWindow::DispatchMouseEventToTarget(
- ui::MouseEvent* event,
- Window* target) {
- client::CursorClient* cursor_client = client::GetCursorClient(window());
- if (cursor_client &&
- !cursor_client->IsMouseEventsEnabled() &&
- (event->flags() & ui::EF_IS_SYNTHESIZED))
- return DispatchDetails();
-
- static const int kMouseButtonFlagMask =
- ui::EF_LEFT_MOUSE_BUTTON |
- ui::EF_MIDDLE_MOUSE_BUTTON |
- ui::EF_RIGHT_MOUSE_BUTTON;
- // WARNING: because of nested message loops |this| may be deleted after
- // dispatching any event. Do not use AutoReset or the like here.
- SetLastMouseLocation(window(), event->location());
- synthesize_mouse_move_ = false;
- switch (event->type()) {
- case ui::ET_MOUSE_EXITED:
- if (!target) {
- DispatchDetails details =
- DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
- if (details.dispatcher_destroyed)
- return details;
- mouse_moved_handler_ = NULL;
- }
- break;
- case ui::ET_MOUSE_MOVED:
- // Send an exit to the current |mouse_moved_handler_| and an enter to
- // |target|. Take care that both us and |target| aren't destroyed during
- // dispatch.
- if (target != mouse_moved_handler_) {
- aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
- WindowTracker destroyed_tracker;
- if (target)
- destroyed_tracker.Add(target);
- DispatchDetails details =
- DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
- if (details.dispatcher_destroyed)
- return details;
- // If the |mouse_moved_handler_| changes out from under us, assume a
- // nested message loop ran and we don't need to do anything.
- if (mouse_moved_handler_ != old_mouse_moved_handler)
- return DispatchDetails();
- if (destroyed_tracker.Contains(target)) {
- destroyed_tracker.Remove(target);
- mouse_moved_handler_ = target;
- DispatchDetails details =
- DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED);
- if (details.dispatcher_destroyed)
- return details;
- } else {
- mouse_moved_handler_ = NULL;
- return DispatchDetails();
- }
- }
- break;
- case ui::ET_MOUSE_PRESSED:
- // Don't set the mouse pressed handler for non client mouse down events.
- // These are only sent by Windows and are not always followed with non
- // client mouse up events which causes subsequent mouse events to be
- // sent to the wrong target.
- if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_)
- mouse_pressed_handler_ = target;
- Env::GetInstance()->set_mouse_button_flags(
- event->flags() & kMouseButtonFlagMask);
- break;
- case ui::ET_MOUSE_RELEASED:
- mouse_pressed_handler_ = NULL;
- Env::GetInstance()->set_mouse_button_flags(event->flags() &
- kMouseButtonFlagMask & ~event->changed_button_flags());
- break;
- default:
- break;
- }
- if (target) {
- event->ConvertLocationToTarget(window(), target);
- if (IsNonClientLocation(target, event->location()))
- event->set_flags(event->flags() | ui::EF_IS_NON_CLIENT);
- return DispatchEvent(target, event);
- }
- return DispatchDetails();
-}
-
-ui::EventDispatchDetails RootWindow::DispatchTouchEventImpl(
- ui::TouchEvent* event) {
- switch (event->type()) {
- case ui::ET_TOUCH_PRESSED:
- touch_ids_down_ |= (1 << event->touch_id());
- Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
- break;
-
- // Handle ET_TOUCH_CANCELLED only if it has a native event.
- case ui::ET_TOUCH_CANCELLED:
- if (!event->HasNativeEvent())
- break;
- // fallthrough
- case ui::ET_TOUCH_RELEASED:
- touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^
- (1 << event->touch_id());
- Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
- break;
-
- default:
- break;
- }
- TransformEventForDeviceScaleFactor(event);
- Window* target = client::GetCaptureWindow(window());
- if (!target) {
- target = ConsumerToWindow(
- ui::GestureRecognizer::Get()->GetTouchLockedTarget(*event));
- if (!target) {
- target = ConsumerToWindow(ui::GestureRecognizer::Get()->
- GetTargetForLocation(event->location()));
- }
- }
-
- // The gesture recognizer processes touch events in the system coordinates. So
- // keep a copy of the touch event here before possibly converting the event to
- // a window's local coordinate system.
- ui::TouchEvent event_for_gr(*event);
-
- ui::EventResult result = ui::ER_UNHANDLED;
- if (!target && !window()->bounds().Contains(event->location())) {
- // If the initial touch is outside the root window, target the root.
- target = window();
- DispatchDetails details = DispatchEvent(target ? target : NULL, event);
- if (details.dispatcher_destroyed)
- return details;
- result = event->result();
- } else {
- // We only come here when the first contact was within the root window.
- if (!target) {
- target = window()->GetEventHandlerForPoint(event->location());
- if (!target)
- return DispatchDetails();
- }
-
- event->ConvertLocationToTarget(window(), target);
- DispatchDetails details = DispatchEvent(target, event);
- if (details.dispatcher_destroyed)
- return details;
- result = event->result();
- }
-
- // Get the list of GestureEvents from GestureRecognizer.
- scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
- gestures.reset(ui::GestureRecognizer::Get()->
- ProcessTouchEventForGesture(event_for_gr, result, target));
-
- return ProcessGestures(gestures.get());
-}
-
-ui::EventDispatchDetails RootWindow::DispatchHeldEvents() {
- if (!held_repostable_event_ && !held_move_event_)
- return DispatchDetails();
-
- CHECK(!dispatching_held_event_);
- dispatching_held_event_ = true;
-
- DispatchDetails dispatch_details;
- if (held_repostable_event_) {
- if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
- scoped_ptr<ui::MouseEvent> mouse_event(
- static_cast<ui::MouseEvent*>(held_repostable_event_.release()));
- dispatch_details = DispatchMouseEventRepost(mouse_event.get());
- } else {
- // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
- NOTREACHED();
- }
- if (dispatch_details.dispatcher_destroyed)
- return dispatch_details;
- }
-
- if (held_move_event_ && held_move_event_->IsMouseEvent()) {
- // If a mouse move has been synthesized, the target location is suspect,
- // so drop the held event.
- if (!synthesize_mouse_move_) {
- dispatch_details = DispatchMouseEventImpl(
- static_cast<ui::MouseEvent*>(held_move_event_.get()));
- }
- if (!dispatch_details.dispatcher_destroyed)
- held_move_event_.reset();
- } else if (held_move_event_ && held_move_event_->IsTouchEvent()) {
- dispatch_details = DispatchTouchEventImpl(
- static_cast<ui::TouchEvent*>(held_move_event_.get()));
- if (!dispatch_details.dispatcher_destroyed)
- held_move_event_.reset();
- }
-
- if (!dispatch_details.dispatcher_destroyed)
- dispatching_held_event_ = false;
- return dispatch_details;
-}
-
-void RootWindow::PostMouseMoveEventAfterWindowChange() {
- if (synthesize_mouse_move_)
- return;
- synthesize_mouse_move_ = true;
- base::MessageLoop::current()->PostNonNestableTask(
- FROM_HERE,
- base::Bind(&RootWindow::SynthesizeMouseMoveEventAsync,
- held_event_factory_.GetWeakPtr()));
-}
-
-ui::EventDispatchDetails RootWindow::SynthesizeMouseMoveEvent() {
- DispatchDetails details;
- if (!synthesize_mouse_move_)
- return details;
- synthesize_mouse_move_ = false;
- gfx::Point root_mouse_location = GetLastMouseLocationInRoot();
- if (!window()->bounds().Contains(root_mouse_location))
- return details;
- gfx::Point host_mouse_location = root_mouse_location;
- ConvertPointToHost(&host_mouse_location);
-
- ui::MouseEvent event(ui::ET_MOUSE_MOVED,
- host_mouse_location,
- host_mouse_location,
- ui::EF_IS_SYNTHESIZED);
- return OnHostMouseEventImpl(&event);
-}
-
-void RootWindow::SynthesizeMouseMoveEventAsync() {
- DispatchDetails details = SynthesizeMouseMoveEvent();
- if (details.dispatcher_destroyed)
- return;
-}
-
-gfx::Transform RootWindow::GetInverseRootTransform() const {
- float scale = ui::GetDeviceScaleFactor(window()->layer());
- gfx::Transform transform;
- transform.Scale(1.0f / scale, 1.0f / scale);
- return transformer_->GetInverseTransform() * transform;
-}
-
-void RootWindow::PreDispatchLocatedEvent(Window* target,
- ui::LocatedEvent* event) {
- int flags = event->flags();
- if (IsNonClientLocation(target, event->location()))
- flags |= ui::EF_IS_NON_CLIENT;
- event->set_flags(flags);
-
- if (!dispatching_held_event_) {
- SetLastMouseLocation(window(), event->location());
- synthesize_mouse_move_ = false;
- }
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/root_window.h b/chromium/ui/aura/root_window.h
deleted file mode 100644
index e6b46d0f132..00000000000
--- a/chromium/ui/aura/root_window.h
+++ /dev/null
@@ -1,401 +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_AURA_ROOT_WINDOW_H_
-#define UI_AURA_ROOT_WINDOW_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/client/capture_delegate.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/aura/window_tree_host_delegate.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/compositor/compositor.h"
-#include "ui/compositor/layer_animation_observer.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/event_processor.h"
-#include "ui/events/event_targeter.h"
-#include "ui/events/gestures/gesture_recognizer.h"
-#include "ui/events/gestures/gesture_types.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/transform.h"
-
-namespace gfx {
-class Size;
-class Transform;
-}
-
-namespace ui {
-class GestureEvent;
-class GestureRecognizer;
-class KeyEvent;
-class LayerAnimationSequence;
-class MouseEvent;
-class ScrollEvent;
-class TouchEvent;
-class ViewProp;
-}
-
-namespace aura {
-class RootWindow;
-class RootWindowHost;
-class RootWindowObserver;
-class RootWindowTransformer;
-class TestScreen;
-class WindowTargeter;
-
-// RootWindow is responsible for hosting a set of windows.
-class AURA_EXPORT RootWindow : public ui::EventProcessor,
- public ui::GestureEventHelper,
- public ui::LayerAnimationObserver,
- public aura::client::CaptureDelegate,
- public aura::RootWindowHostDelegate {
- public:
- struct AURA_EXPORT CreateParams {
- // CreateParams with initial_bounds and default host in pixel.
- explicit CreateParams(const gfx::Rect& initial_bounds);
- ~CreateParams() {}
-
- gfx::Rect initial_bounds;
-
- // A host to use in place of the default one that RootWindow will create.
- // NULL by default.
- RootWindowHost* host;
- };
-
- explicit RootWindow(const CreateParams& params);
- virtual ~RootWindow();
-
- // Returns the RootWindowHost for the specified accelerated widget, or NULL
- // if there is none associated.
- static RootWindow* GetForAcceleratedWidget(gfx::AcceleratedWidget widget);
-
- Window* window() {
- return const_cast<Window*>(const_cast<const RootWindow*>(this)->window());
- }
- const Window* window() const { return window_.get(); }
- RootWindowHost* host() {
- return const_cast<RootWindowHost*>(
- const_cast<const RootWindow*>(this)->host());
- }
- const RootWindowHost* host() const { return host_.get(); }
- ui::Compositor* compositor() { return compositor_.get(); }
- gfx::NativeCursor last_cursor() const { return last_cursor_; }
- Window* mouse_pressed_handler() { return mouse_pressed_handler_; }
- Window* mouse_moved_handler() { return mouse_moved_handler_; }
-
- // Initializes the root window.
- void Init();
-
- // Stop listening events in preparation for shutdown.
- void PrepareForShutdown();
-
- // Repost event for re-processing. Used when exiting context menus.
- // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event
- // types (although the latter is currently a no-op).
- void RepostEvent(const ui::LocatedEvent& event);
-
- RootWindowHostDelegate* AsRootWindowHostDelegate();
-
- // Gets/sets the size of the host window.
- void SetHostSize(const gfx::Size& size_in_pixel);
-
- // Sets the bounds of the host window.
- void SetHostBounds(const gfx::Rect& size_in_pizel);
-
- // Sets the currently-displayed cursor. If the cursor was previously hidden
- // via ShowCursor(false), it will remain hidden until ShowCursor(true) is
- // called, at which point the cursor that was last set via SetCursor() will be
- // used.
- void SetCursor(gfx::NativeCursor cursor);
-
- // Invoked when the cursor's visibility has changed.
- void OnCursorVisibilityChanged(bool visible);
-
- // Invoked when the mouse events get enabled or disabled.
- void OnMouseEventsEnableStateChanged(bool enabled);
-
- // Moves the cursor to the specified location relative to the root window.
- void MoveCursorTo(const gfx::Point& location);
-
- // Moves the cursor to the |host_location| given in host coordinates.
- void MoveCursorToHostLocation(const gfx::Point& host_location);
-
- // Draw the damage_rect.
- void ScheduleRedrawRect(const gfx::Rect& damage_rect);
-
- // Returns a target window for the given gesture event.
- Window* GetGestureTarget(ui::GestureEvent* event);
-
- // Handles a gesture event. Returns true if handled. Unlike the other
- // event-dispatching function (e.g. for touch/mouse/keyboard events), gesture
- // events are dispatched from GestureRecognizer instead of RootWindowHost.
- void DispatchGestureEvent(ui::GestureEvent* event);
-
- // Invoked when |window| is being destroyed.
- void OnWindowDestroying(Window* window);
-
- // Invoked when |window|'s bounds have changed. |contained_mouse| indicates if
- // the bounds before change contained the |last_moust_location()|.
- void OnWindowBoundsChanged(Window* window, bool contained_mouse);
-
- // Dispatches OnMouseExited to the |window| which is hiding if nessessary.
- void DispatchMouseExitToHidingWindow(Window* window);
-
- // Dispatches a ui::ET_MOUSE_EXITED event at |point|.
- void DispatchMouseExitAtPoint(const gfx::Point& point);
-
- // Invoked when |window|'s visibility has changed.
- void OnWindowVisibilityChanged(Window* window, bool is_visible);
-
- // Invoked when |window|'s tranfrom has changed. |contained_mouse|
- // indicates if the bounds before change contained the
- // |last_moust_location()|.
- void OnWindowTransformed(Window* window, bool contained_mouse);
-
- // Invoked when the keyboard mapping (in X11 terms: the mapping between
- // keycodes and keysyms) has changed.
- void OnKeyboardMappingChanged();
-
- // The system windowing system has sent a request that we close our window.
- void OnRootWindowHostCloseRequested();
-
- // Add/remove observer. There is no need to remove the observer if
- // the root window is being deleted. In particular, you SHOULD NOT remove
- // in |WindowObserver::OnWindowDestroying| of the observer observing
- // the root window because it is too late to remove it.
- void AddRootWindowObserver(RootWindowObserver* observer);
- void RemoveRootWindowObserver(RootWindowObserver* observer);
-
- // Converts |point| from the root window's coordinate system to the
- // host window's.
- void ConvertPointToHost(gfx::Point* point) const;
-
- // Converts |point| from the host window's coordinate system to the
- // root window's.
- void ConvertPointFromHost(gfx::Point* point) const;
-
- // Gesture Recognition -------------------------------------------------------
-
- // When a touch event is dispatched to a Window, it may want to process the
- // touch event asynchronously. In such cases, the window should consume the
- // event during the event dispatch. Once the event is properly processed, the
- // window should let the RootWindow know about the result of the event
- // processing, so that gesture events can be properly created and dispatched.
- void ProcessedTouchEvent(ui::TouchEvent* event,
- Window* window,
- ui::EventResult result);
-
- // These methods are used to defer the processing of mouse/touch events
- // related to resize. A client (typically a RenderWidgetHostViewAura) can call
- // HoldPointerMoves when an resize is initiated and then ReleasePointerMoves
- // once the resize is completed.
- //
- // More than one hold can be invoked and each hold must be cancelled by a
- // release before we resume normal operation.
- void HoldPointerMoves();
- void ReleasePointerMoves();
-
- // Gets the last location seen in a mouse event in this root window's
- // coordinates. This may return a point outside the root window's bounds.
- gfx::Point GetLastMouseLocationInRoot() const;
-
- void SetRootWindowTransformer(scoped_ptr<RootWindowTransformer> transformer);
- gfx::Transform GetRootTransform() const;
-
- void SetTransform(const gfx::Transform& transform);
-
- private:
- FRIEND_TEST_ALL_PREFIXES(RootWindowTest, KeepTranslatedEventInRoot);
-
- friend class Window;
- friend class TestScreen;
-
- // The parameter for OnWindowHidden() to specify why window is hidden.
- enum WindowHiddenReason {
- WINDOW_DESTROYED, // Window is destroyed.
- WINDOW_HIDDEN, // Window is hidden.
- WINDOW_MOVING, // Window is temporarily marked as hidden due to move
- // across root windows.
- };
-
- // Updates the event with the appropriate transform for the device scale
- // factor. The RootWindowHostDelegate dispatches events in the physical pixel
- // coordinate. But the event processing from RootWindow onwards happen in
- // device-independent pixel coordinate. So it is necessary to update the event
- // received from the host.
- void TransformEventForDeviceScaleFactor(ui::LocatedEvent* event);
-
- // Moves the cursor to the specified location. This method is internally used
- // by MoveCursorTo() and MoveCursorToHostLocation().
- void MoveCursorToInternal(const gfx::Point& root_location,
- const gfx::Point& host_location);
-
- // Dispatches the specified event type (intended for enter/exit) to the
- // |mouse_moved_handler_|.
- ui::EventDispatchDetails DispatchMouseEnterOrExit(
- const ui::MouseEvent& event,
- ui::EventType type) WARN_UNUSED_RESULT;
- ui::EventDispatchDetails ProcessGestures(
- ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT;
-
- // Called when a Window is attached or detached from the RootWindow.
- void OnWindowAddedToRootWindow(Window* window);
- void OnWindowRemovedFromRootWindow(Window* window, Window* new_root);
-
- // Called when a window becomes invisible, either by being removed
- // from root window hierarchy, via SetVisible(false) or being destroyed.
- // |reason| specifies what triggered the hiding.
- void OnWindowHidden(Window* invisible, WindowHiddenReason reason);
-
- // Cleans up the state of gestures for all windows in |window| (including
- // |window| itself). This includes cancelling active touch points.
- void CleanupGestureState(Window* window);
-
- // Updates the root window's size using |host_size|, current
- // transform and insets.
- void UpdateRootWindowSize(const gfx::Size& host_size);
-
- // Overridden from aura::client::CaptureDelegate:
- virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE;
- virtual void OnOtherRootGotCapture() OVERRIDE;
- virtual void SetNativeCapture() OVERRIDE;
- virtual void ReleaseNativeCapture() OVERRIDE;
-
- // Overridden from ui::EventProcessor:
- virtual ui::EventTarget* GetRootTarget() OVERRIDE;
- virtual void PrepareEventForDispatch(ui::Event* event) OVERRIDE;
-
- // Overridden from ui::EventDispatcherDelegate.
- virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE;
- virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target,
- ui::Event* event) OVERRIDE;
- virtual ui::EventDispatchDetails PostDispatchEvent(
- ui::EventTarget* target, const ui::Event& event) OVERRIDE;
-
- // Overridden from ui::GestureEventHelper.
- virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
- virtual void DispatchPostponedGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
-
- // Overridden from ui::LayerAnimationObserver:
- virtual void OnLayerAnimationEnded(
- ui::LayerAnimationSequence* animation) OVERRIDE;
- virtual void OnLayerAnimationScheduled(
- ui::LayerAnimationSequence* animation) OVERRIDE;
- virtual void OnLayerAnimationAborted(
- ui::LayerAnimationSequence* animation) OVERRIDE;
-
- // Overridden from aura::RootWindowHostDelegate:
- virtual bool OnHostKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual bool OnHostMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual bool OnHostScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual bool OnHostTouchEvent(ui::TouchEvent* event) OVERRIDE;
- virtual void OnHostCancelMode() OVERRIDE;
- virtual void OnHostActivated() OVERRIDE;
- virtual void OnHostLostWindowCapture() OVERRIDE;
- virtual void OnHostLostMouseGrab() OVERRIDE;
- virtual void OnHostPaint(const gfx::Rect& damage_rect) OVERRIDE;
- virtual void OnHostMoved(const gfx::Point& origin) OVERRIDE;
- virtual void OnHostResized(const gfx::Size& size) OVERRIDE;
- virtual float GetDeviceScaleFactor() OVERRIDE;
- virtual RootWindow* AsRootWindow() OVERRIDE;
- virtual const RootWindow* AsRootWindow() const OVERRIDE;
- virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
-
- ui::EventDispatchDetails OnHostMouseEventImpl(ui::MouseEvent* event)
- WARN_UNUSED_RESULT;
-
- // We hold and aggregate mouse drags and touch moves as a way of throttling
- // resizes when HoldMouseMoves() is called. The following methods are used to
- // dispatch held and newly incoming mouse and touch events, typically when an
- // event other than one of these needs dispatching or a matching
- // ReleaseMouseMoves()/ReleaseTouchMoves() is called. NOTE: because these
- // methods dispatch events from RootWindowHost the coordinates are in terms of
- // the root.
- ui::EventDispatchDetails DispatchMouseEventImpl(ui::MouseEvent* event)
- WARN_UNUSED_RESULT;
- ui::EventDispatchDetails DispatchMouseEventRepost(ui::MouseEvent* event)
- WARN_UNUSED_RESULT;
- ui::EventDispatchDetails DispatchMouseEventToTarget(ui::MouseEvent* event,
- Window* target)
- WARN_UNUSED_RESULT;
- ui::EventDispatchDetails DispatchTouchEventImpl(ui::TouchEvent* event)
- WARN_UNUSED_RESULT;
- ui::EventDispatchDetails DispatchHeldEvents() WARN_UNUSED_RESULT;
- // Creates and dispatches synthesized mouse move event using the
- // current mouse location.
- ui::EventDispatchDetails SynthesizeMouseMoveEvent() WARN_UNUSED_RESULT;
-
- void SynthesizeMouseMoveEventAsync();
-
- // Posts a task to send synthesized mouse move event if there
- // is no a pending task.
- void PostMouseMoveEventAfterWindowChange();
-
- gfx::Transform GetInverseRootTransform() const;
-
- void PreDispatchLocatedEvent(Window* target, ui::LocatedEvent* event);
-
- // TODO(beng): evaluate the ideal ownership model.
- scoped_ptr<Window> window_;
-
- scoped_ptr<ui::Compositor> compositor_;
-
- scoped_ptr<RootWindowHost> host_;
-
- // Touch ids that are currently down.
- uint32 touch_ids_down_;
-
- // Last cursor set. Used for testing.
- gfx::NativeCursor last_cursor_;
-
- ObserverList<RootWindowObserver> observers_;
-
- Window* mouse_pressed_handler_;
- Window* mouse_moved_handler_;
- Window* event_dispatch_target_;
- Window* old_dispatch_target_;
-
- bool synthesize_mouse_move_;
- bool waiting_on_compositing_end_;
- bool draw_on_compositing_end_;
-
- bool defer_draw_scheduling_;
-
- // How many move holds are outstanding. We try to defer dispatching
- // touch/mouse moves while the count is > 0.
- int move_hold_count_;
- scoped_ptr<ui::LocatedEvent> held_move_event_;
-
- // Allowing for reposting of events. Used when exiting context menus.
- scoped_ptr<ui::LocatedEvent> held_repostable_event_;
-
- // Set when dispatching a held event.
- bool dispatching_held_event_;
-
- scoped_ptr<ui::ViewProp> prop_;
-
- scoped_ptr<RootWindowTransformer> transformer_;
-
- // Used to schedule reposting an event.
- base::WeakPtrFactory<RootWindow> repost_event_factory_;
-
- // Used to schedule DispatchHeldEvents() when |move_hold_count_| goes to 0.
- base::WeakPtrFactory<RootWindow> held_event_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(RootWindow);
-};
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_H_
diff --git a/chromium/ui/aura/root_window_host_ozone.cc b/chromium/ui/aura/root_window_host_ozone.cc
deleted file mode 100644
index 937b70f65be..00000000000
--- a/chromium/ui/aura/root_window_host_ozone.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/root_window_host_ozone.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/events/ozone/event_factory_ozone.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-#include "ui/ozone/ozone_platform.h"
-
-namespace aura {
-
-RootWindowHostOzone::RootWindowHostOzone(const gfx::Rect& bounds)
- : widget_(0),
- bounds_(bounds) {
- ui::OzonePlatform::Initialize();
-
- // EventFactoryOzone creates converters that obtain input events from the
- // underlying input system and dispatch them as |ui::Event| instances into
- // Aura.
- ui::EventFactoryOzone::GetInstance()->StartProcessingEvents();
-
- gfx::SurfaceFactoryOzone* surface_factory =
- gfx::SurfaceFactoryOzone::GetInstance();
- widget_ = surface_factory->GetAcceleratedWidget();
-
- surface_factory->AttemptToResizeAcceleratedWidget(widget_, bounds_);
-
- base::MessagePumpOzone::Current()->AddDispatcherForRootWindow(this);
-}
-
-RootWindowHostOzone::~RootWindowHostOzone() {
- base::MessagePumpOzone::Current()->RemoveDispatcherForRootWindow(0);
-}
-
-bool RootWindowHostOzone::Dispatch(const base::NativeEvent& ne) {
- ui::Event* event = static_cast<ui::Event*>(ne);
- if (event->IsTouchEvent()) {
- ui::TouchEvent* touchev = static_cast<ui::TouchEvent*>(ne);
- delegate_->OnHostTouchEvent(touchev);
- } else if (event->IsKeyEvent()) {
- ui::KeyEvent* keyev = static_cast<ui::KeyEvent*>(ne);
- delegate_->OnHostKeyEvent(keyev);
- } else if (event->IsMouseEvent()) {
- ui::MouseEvent* mouseev = static_cast<ui::MouseEvent*>(ne);
- delegate_->OnHostMouseEvent(mouseev);
- }
- return true;
-}
-
-RootWindow* RootWindowHostOzone::GetRootWindow() {
- return delegate_->AsRootWindow();
-}
-
-gfx::AcceleratedWidget RootWindowHostOzone::GetAcceleratedWidget() {
- return widget_;
-}
-
-void RootWindowHostOzone::Show() { NOTIMPLEMENTED(); }
-
-void RootWindowHostOzone::Hide() { NOTIMPLEMENTED(); }
-
-void RootWindowHostOzone::ToggleFullScreen() { NOTIMPLEMENTED(); }
-
-gfx::Rect RootWindowHostOzone::GetBounds() const { return bounds_; }
-
-void RootWindowHostOzone::SetBounds(const gfx::Rect& bounds) {
- NOTIMPLEMENTED();
-}
-
-gfx::Insets RootWindowHostOzone::GetInsets() const { return gfx::Insets(); }
-
-void RootWindowHostOzone::SetInsets(const gfx::Insets& insets) {
- NOTIMPLEMENTED();
-}
-
-gfx::Point RootWindowHostOzone::GetLocationOnNativeScreen() const {
- return bounds_.origin();
-}
-
-void RootWindowHostOzone::SetCapture() { NOTIMPLEMENTED(); }
-
-void RootWindowHostOzone::ReleaseCapture() { NOTIMPLEMENTED(); }
-
-void RootWindowHostOzone::SetCursor(gfx::NativeCursor cursor) {
- NOTIMPLEMENTED();
-}
-
-bool RootWindowHostOzone::QueryMouseLocation(gfx::Point* location_return) {
- NOTIMPLEMENTED();
- return false;
-}
-
-bool RootWindowHostOzone::ConfineCursorToRootWindow() {
- NOTIMPLEMENTED();
- return false;
-}
-
-void RootWindowHostOzone::UnConfineCursor() { NOTIMPLEMENTED(); }
-
-void RootWindowHostOzone::OnCursorVisibilityChanged(bool show) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostOzone::MoveCursorTo(const gfx::Point& location) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostOzone::PostNativeEvent(
- const base::NativeEvent& native_event) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostOzone::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostOzone::PrepareForShutdown() { NOTIMPLEMENTED(); }
-
-// static
-RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) {
- return new RootWindowHostOzone(bounds);
-}
-
-// static
-gfx::Size RootWindowHost::GetNativeScreenSize() {
- NOTIMPLEMENTED();
- return gfx::Size();
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/root_window_host_ozone.h b/chromium/ui/aura/root_window_host_ozone.h
deleted file mode 100644
index 41f6a8e181f..00000000000
--- a/chromium/ui/aura/root_window_host_ozone.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_AURA_ROOT_WINDOW_HOST_OZONE_H_
-#define UI_AURA_ROOT_WINDOW_HOST_OZONE_H_
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect.h"
-
-namespace aura {
-
-class RootWindowHostOzone : public RootWindowHost,
- public base::MessageLoop::Dispatcher {
- public:
- explicit RootWindowHostOzone(const gfx::Rect& bounds);
- virtual ~RootWindowHostOzone();
-
- private:
- // Overridden from Dispatcher overrides:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- // RootWindowHost Overrides.
- virtual RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& bounds) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
- gfx::AcceleratedWidget widget_;
- gfx::Rect bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(RootWindowHostOzone);
-};
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_HOST_OZONE_H_
diff --git a/chromium/ui/aura/root_window_host_win.cc b/chromium/ui/aura/root_window_host_win.cc
deleted file mode 100644
index 931c11e5179..00000000000
--- a/chromium/ui/aura/root_window_host_win.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/root_window_host_win.h"
-
-#include <windows.h>
-
-#include <algorithm>
-
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/base/cursor/cursor_loader_win.h"
-#include "ui/events/event.h"
-#include "ui/base/view_prop.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/screen.h"
-
-using std::max;
-using std::min;
-
-namespace aura {
-namespace {
-
-bool use_popup_as_root_window_for_test = false;
-
-} // namespace
-
-// static
-RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) {
- return new RootWindowHostWin(bounds);
-}
-
-// static
-gfx::Size RootWindowHost::GetNativeScreenSize() {
- return gfx::Size(GetSystemMetrics(SM_CXSCREEN),
- GetSystemMetrics(SM_CYSCREEN));
-}
-
-RootWindowHostWin::RootWindowHostWin(const gfx::Rect& bounds)
- : fullscreen_(false),
- has_capture_(false),
- saved_window_style_(0),
- saved_window_ex_style_(0) {
- if (use_popup_as_root_window_for_test)
- set_window_style(WS_POPUP);
- Init(NULL, bounds);
- SetWindowText(hwnd(), L"aura::RootWindow!");
-}
-
-RootWindowHostWin::~RootWindowHostWin() {
- DestroyWindow(hwnd());
-}
-
-RootWindow* RootWindowHostWin::GetRootWindow() {
- return delegate_->AsRootWindow();
-}
-
-gfx::AcceleratedWidget RootWindowHostWin::GetAcceleratedWidget() {
- return hwnd();
-}
-
-void RootWindowHostWin::Show() {
- ShowWindow(hwnd(), SW_SHOWNORMAL);
-}
-
-void RootWindowHostWin::Hide() {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostWin::ToggleFullScreen() {
- gfx::Rect target_rect;
- if (!fullscreen_) {
- fullscreen_ = true;
- saved_window_style_ = GetWindowLong(hwnd(), GWL_STYLE);
- saved_window_ex_style_ = GetWindowLong(hwnd(), GWL_EXSTYLE);
- GetWindowRect(hwnd(), &saved_window_rect_);
- SetWindowLong(hwnd(), GWL_STYLE,
- saved_window_style_ & ~(WS_CAPTION | WS_THICKFRAME));
- SetWindowLong(hwnd(), GWL_EXSTYLE,
- saved_window_ex_style_ & ~(WS_EX_DLGMODALFRAME |
- WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
-
- MONITORINFO mi;
- mi.cbSize = sizeof(mi);
- GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi);
- target_rect = gfx::Rect(mi.rcMonitor);
- } else {
- fullscreen_ = false;
- SetWindowLong(hwnd(), GWL_STYLE, saved_window_style_);
- SetWindowLong(hwnd(), GWL_EXSTYLE, saved_window_ex_style_);
- target_rect = gfx::Rect(saved_window_rect_);
- }
- SetWindowPos(hwnd(),
- NULL,
- target_rect.x(),
- target_rect.y(),
- target_rect.width(),
- target_rect.height(),
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
-}
-
-gfx::Rect RootWindowHostWin::GetBounds() const {
- RECT r;
- GetClientRect(hwnd(), &r);
- return gfx::Rect(r);
-}
-
-void RootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
- if (fullscreen_) {
- saved_window_rect_.right = saved_window_rect_.left + bounds.width();
- saved_window_rect_.bottom = saved_window_rect_.top + bounds.height();
- return;
- }
- RECT window_rect;
- window_rect.left = bounds.x();
- window_rect.top = bounds.y();
- window_rect.right = bounds.right() ;
- window_rect.bottom = bounds.bottom();
- AdjustWindowRectEx(&window_rect,
- GetWindowLong(hwnd(), GWL_STYLE),
- FALSE,
- GetWindowLong(hwnd(), GWL_EXSTYLE));
- SetWindowPos(
- hwnd(),
- NULL,
- window_rect.left,
- window_rect.top,
- window_rect.right - window_rect.left,
- window_rect.bottom - window_rect.top,
- SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION);
-
- // Explicity call OnHostResized when the scale has changed because
- // the window size may not have changed.
- float current_scale = delegate_->GetDeviceScaleFactor();
- float new_scale = gfx::Screen::GetScreenFor(
- delegate_->AsRootWindow()->window())->GetDisplayNearestWindow(
- delegate_->AsRootWindow()->window()).device_scale_factor();
- if (current_scale != new_scale)
- delegate_->OnHostResized(bounds.size());
-}
-
-gfx::Insets RootWindowHostWin::GetInsets() const {
- return gfx::Insets();
-}
-
-void RootWindowHostWin::SetInsets(const gfx::Insets& insets) {
-}
-
-gfx::Point RootWindowHostWin::GetLocationOnNativeScreen() const {
- RECT r;
- GetClientRect(hwnd(), &r);
- return gfx::Point(r.left, r.top);
-}
-
-
-void RootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) {
- // Custom web cursors are handled directly.
- if (native_cursor == ui::kCursorCustom)
- return;
-
- ui::CursorLoaderWin cursor_loader;
- cursor_loader.SetPlatformCursor(&native_cursor);
- ::SetCursor(native_cursor.platform());
-}
-
-void RootWindowHostWin::SetCapture() {
- if (!has_capture_) {
- has_capture_ = true;
- ::SetCapture(hwnd());
- }
-}
-
-void RootWindowHostWin::ReleaseCapture() {
- if (has_capture_) {
- has_capture_ = false;
- ::ReleaseCapture();
- }
-}
-
-bool RootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
- client::CursorClient* cursor_client =
- client::GetCursorClient(GetRootWindow()->window());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
- *location_return = gfx::Point(0, 0);
- return false;
- }
-
- POINT pt;
- GetCursorPos(&pt);
- ScreenToClient(hwnd(), &pt);
- const gfx::Size size = GetBounds().size();
- *location_return =
- gfx::Point(max(0, min(size.width(), static_cast<int>(pt.x))),
- max(0, min(size.height(), static_cast<int>(pt.y))));
- return (pt.x >= 0 && static_cast<int>(pt.x) < size.width() &&
- pt.y >= 0 && static_cast<int>(pt.y) < size.height());
-}
-
-bool RootWindowHostWin::ConfineCursorToRootWindow() {
- RECT window_rect;
- GetWindowRect(hwnd(), &window_rect);
- return ClipCursor(&window_rect) != 0;
-}
-
-void RootWindowHostWin::UnConfineCursor() {
- ClipCursor(NULL);
-}
-
-void RootWindowHostWin::OnCursorVisibilityChanged(bool show) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
- // Deliberately not implemented.
-}
-
-void RootWindowHostWin::PostNativeEvent(const base::NativeEvent& native_event) {
- ::PostMessage(
- hwnd(), native_event.message, native_event.wParam, native_event.lParam);
-}
-
-void RootWindowHostWin::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostWin::PrepareForShutdown() {
- NOTIMPLEMENTED();
-}
-
-void RootWindowHostWin::OnClose() {
- // TODO: this obviously shouldn't be here.
- base::MessageLoopForUI::current()->Quit();
-}
-
-LRESULT RootWindowHostWin::OnKeyEvent(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- MSG msg = { hwnd(), message, w_param, l_param };
- ui::KeyEvent keyev(msg, message == WM_CHAR);
- SetMsgHandled(delegate_->OnHostKeyEvent(&keyev));
- return 0;
-}
-
-LRESULT RootWindowHostWin::OnMouseRange(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- MSG msg = { hwnd(), message, w_param, l_param, 0,
- { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } };
- ui::MouseEvent event(msg);
- bool handled = false;
- if (!(event.flags() & ui::EF_IS_NON_CLIENT))
- handled = delegate_->OnHostMouseEvent(&event);
- SetMsgHandled(handled);
- return 0;
-}
-
-LRESULT RootWindowHostWin::OnCaptureChanged(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- if (has_capture_) {
- has_capture_ = false;
- delegate_->OnHostLostWindowCapture();
- }
- return 0;
-}
-
-LRESULT RootWindowHostWin::OnNCActivate(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- if (!!w_param)
- delegate_->OnHostActivated();
- return DefWindowProc(hwnd(), message, w_param, l_param);
-}
-
-void RootWindowHostWin::OnMove(const CPoint& point) {
- if (delegate_)
- delegate_->OnHostMoved(gfx::Point(point.x, point.y));
-}
-
-void RootWindowHostWin::OnPaint(HDC dc) {
- gfx::Rect damage_rect;
- RECT update_rect = {0};
- if (GetUpdateRect(hwnd(), &update_rect, FALSE))
- damage_rect = gfx::Rect(update_rect);
- delegate_->OnHostPaint(damage_rect);
- ValidateRect(hwnd(), NULL);
-}
-
-void RootWindowHostWin::OnSize(UINT param, const CSize& size) {
- // Minimizing resizes the window to 0x0 which causes our layout to go all
- // screwy, so we just ignore it.
- if (delegate_ && param != SIZE_MINIMIZED)
- delegate_->OnHostResized(gfx::Size(size.cx, size.cy));
-}
-
-namespace test {
-
-// static
-void SetUsePopupAsRootWindowForTest(bool use) {
- use_popup_as_root_window_for_test = use;
-}
-
-} // namespace test
-
-} // namespace aura
diff --git a/chromium/ui/aura/root_window_host_win.h b/chromium/ui/aura/root_window_host_win.h
deleted file mode 100644
index 3d99821400a..00000000000
--- a/chromium/ui/aura/root_window_host_win.h
+++ /dev/null
@@ -1,96 +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_AURA_ROOT_WINDOW_HOST_WIN_H_
-#define UI_AURA_ROOT_WINDOW_HOST_WIN_H_
-
-#include "base/compiler_specific.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/gfx/win/window_impl.h"
-
-namespace aura {
-
-class RootWindowHostWin : public RootWindowHost, public gfx::WindowImpl {
- public:
- RootWindowHostWin(const gfx::Rect& bounds);
- virtual ~RootWindowHostWin();
- // RootWindowHost:
- virtual RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
- private:
- BEGIN_MSG_MAP_EX(RootWindowHostWin)
- // Range handlers must go first!
- MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
- MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
-
- // Mouse capture events.
- MESSAGE_HANDLER_EX(WM_CAPTURECHANGED, OnCaptureChanged)
-
- // Key events.
- MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_CHAR, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_SYSCHAR, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_IME_CHAR, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate)
-
- MSG_WM_CLOSE(OnClose)
- MSG_WM_MOVE(OnMove)
- MSG_WM_PAINT(OnPaint)
- MSG_WM_SIZE(OnSize)
- END_MSG_MAP()
-
- void OnClose();
- LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param);
- LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
- LRESULT OnCaptureChanged(UINT message, WPARAM w_param, LPARAM l_param);
- LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param);
- void OnMove(const CPoint& point);
- void OnPaint(HDC dc);
- void OnSize(UINT param, const CSize& size);
-
- bool fullscreen_;
- bool has_capture_;
- RECT saved_window_rect_;
- DWORD saved_window_style_;
- DWORD saved_window_ex_style_;
-
- DISALLOW_COPY_AND_ASSIGN(RootWindowHostWin);
-};
-
-namespace test {
-
-// Set true to let RootWindowHostWin use a popup window
-// with no frame/title so that the window size and test's
-// expectations matches.
-AURA_EXPORT void SetUsePopupAsRootWindowForTest(bool use);
-
-} // namespace
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_HOST_WIN_H_
diff --git a/chromium/ui/aura/root_window_host_x11.cc b/chromium/ui/aura/root_window_host_x11.cc
deleted file mode 100644
index 4fb00471332..00000000000
--- a/chromium/ui/aura/root_window_host_x11.cc
+++ /dev/null
@@ -1,1060 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/root_window_host_x11.h"
-
-#include <strings.h>
-#include <X11/cursorfont.h>
-#include <X11/extensions/Xfixes.h>
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/Xrandr.h>
-#include <X11/Xatom.h>
-#include <X11/Xcursor/Xcursor.h>
-#include <X11/Xlib.h>
-
-#include <algorithm>
-#include <limits>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_x11.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/user_action_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/base/view_prop.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/events/x/device_data_manager.h"
-#include "ui/events/x/device_list_cache_x.h"
-#include "ui/events/x/touch_factory_x11.h"
-#include "ui/gfx/screen.h"
-
-using std::max;
-using std::min;
-
-namespace aura {
-
-namespace {
-
-// Standard Linux mouse buttons for going back and forward.
-const int kBackMouseButton = 8;
-const int kForwardMouseButton = 9;
-
-const char* kAtomsToCache[] = {
- "WM_DELETE_WINDOW",
- "_NET_WM_PING",
- "_NET_WM_PID",
- "WM_S0",
-#if defined(OS_CHROMEOS)
- "Tap Paused", // Defined in the gestures library.
-#endif
- NULL
-};
-
-::Window FindEventTarget(const base::NativeEvent& xev) {
- ::Window target = xev->xany.window;
- if (xev->type == GenericEvent)
- target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
- return target;
-}
-
-#if defined(USE_XI2_MT)
-bool IsSideBezelsEnabled() {
- static bool side_bezels_enabled =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kTouchSideBezels) != "0";
- return side_bezels_enabled;
-}
-#endif
-
-void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) {
- CHECK(ui::IsXInput2Available());
- unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {};
- memset(mask, 0, sizeof(mask));
-
- XISetMask(mask, XI_HierarchyChanged);
- XISetMask(mask, XI_KeyPress);
- XISetMask(mask, XI_KeyRelease);
-
- XIEventMask evmask;
- evmask.deviceid = XIAllDevices;
- evmask.mask_len = sizeof(mask);
- evmask.mask = mask;
- XISelectEvents(display, root_window, &evmask, 1);
-
-#if defined(OS_CHROMEOS)
- if (base::SysInfo::IsRunningOnChromeOS()) {
- // It is necessary to listen for touch events on the root window for proper
- // touch event calibration on Chrome OS, but this is not currently necessary
- // on the desktop. This seems to fail in some cases (e.g. when logging
- // in incognito). So select for non-touch events first, and then select for
- // touch-events (but keep the other events in the mask, i.e. do not memset
- // |mask| back to 0).
- // TODO(sad): Figure out why this happens. http://crbug.com/153976
- XISetMask(mask, XI_TouchBegin);
- XISetMask(mask, XI_TouchUpdate);
- XISetMask(mask, XI_TouchEnd);
- XISelectEvents(display, root_window, &evmask, 1);
- }
-#endif
-}
-
-bool default_override_redirect = false;
-
-} // namespace
-
-namespace internal {
-
-// Accomplishes 2 tasks concerning touch event calibration:
-// 1. Being a message-pump observer,
-// routes all the touch events to the X root window,
-// where they can be calibrated later.
-// 2. Has the Calibrate method that does the actual bezel calibration,
-// when invoked from X root window's event dispatcher.
-class TouchEventCalibrate : public base::MessagePumpObserver {
- public:
- TouchEventCalibrate()
- : left_(0),
- right_(0),
- top_(0),
- bottom_(0) {
- base::MessageLoopForUI::current()->AddObserver(this);
-#if defined(USE_XI2_MT)
- std::vector<std::string> parts;
- if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kTouchCalibration), ",", &parts) >= 4) {
- if (!base::StringToInt(parts[0], &left_))
- DLOG(ERROR) << "Incorrect left border calibration value passed.";
- if (!base::StringToInt(parts[1], &right_))
- DLOG(ERROR) << "Incorrect right border calibration value passed.";
- if (!base::StringToInt(parts[2], &top_))
- DLOG(ERROR) << "Incorrect top border calibration value passed.";
- if (!base::StringToInt(parts[3], &bottom_))
- DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
- }
-#endif // defined(USE_XI2_MT)
- }
-
- virtual ~TouchEventCalibrate() {
- base::MessageLoopForUI::current()->RemoveObserver(this);
- }
-
-#if defined(USE_XI2_MT)
- bool IsEventOnSideBezels(
- const base::NativeEvent& xev,
- const gfx::Rect& bounds) {
- if (!left_ && !right_)
- return false;
-
- gfx::Point location = ui::EventLocationFromNative(xev);
- int x = location.x();
- return x < left_ || x > bounds.width() - right_;
- }
-#endif // defined(USE_XI2_MT)
-
- // Modify the location of the |event|,
- // expanding it from |bounds| to (|bounds| + bezels).
- // Required when touchscreen is bigger than screen (i.e. has bezels),
- // because we receive events in touchscreen coordinates,
- // which need to be expanded when converting to screen coordinates,
- // so that location on bezels will be outside of screen area.
- void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
-#if defined(USE_XI2_MT)
- int x = event->x();
- int y = event->y();
-
- if (!left_ && !right_ && !top_ && !bottom_)
- return;
-
- const int resolution_x = bounds.width();
- const int resolution_y = bounds.height();
- // The "grace area" (10% in this case) is to make it easier for the user to
- // navigate to the corner.
- const double kGraceAreaFraction = 0.1;
- if (left_ || right_) {
- // Offset the x position to the real
- x -= left_;
- // Check if we are in the grace area of the left side.
- // Note: We might not want to do this when the gesture is locked?
- if (x < 0 && x > -left_ * kGraceAreaFraction)
- x = 0;
- // Check if we are in the grace area of the right side.
- // Note: We might not want to do this when the gesture is locked?
- if (x > resolution_x - left_ &&
- x < resolution_x - left_ + right_ * kGraceAreaFraction)
- x = resolution_x - left_;
- // Scale the screen area back to the full resolution of the screen.
- x = (x * resolution_x) / (resolution_x - (right_ + left_));
- }
- if (top_ || bottom_) {
- // When there is a top bezel we add our border,
- y -= top_;
-
- // Check if we are in the grace area of the top side.
- // Note: We might not want to do this when the gesture is locked?
- if (y < 0 && y > -top_ * kGraceAreaFraction)
- y = 0;
-
- // Check if we are in the grace area of the bottom side.
- // Note: We might not want to do this when the gesture is locked?
- if (y > resolution_y - top_ &&
- y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
- y = resolution_y - top_;
- // Scale the screen area back to the full resolution of the screen.
- y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
- }
-
- // Set the modified coordinate back to the event.
- if (event->root_location() == event->location()) {
- // Usually those will be equal,
- // if not, I am not sure what the correct value should be.
- event->set_root_location(gfx::Point(x, y));
- }
- event->set_location(gfx::Point(x, y));
-#endif // defined(USE_XI2_MT)
- }
-
- private:
- // Overridden from base::MessagePumpObserver:
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE {
-#if defined(USE_XI2_MT)
- if (event->type == GenericEvent &&
- (event->xgeneric.evtype == XI_TouchBegin ||
- event->xgeneric.evtype == XI_TouchUpdate ||
- event->xgeneric.evtype == XI_TouchEnd)) {
- XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
- xievent->event = xievent->root;
- xievent->event_x = xievent->root_x;
- xievent->event_y = xievent->root_y;
- }
-#endif // defined(USE_XI2_MT)
- return base::EVENT_CONTINUE;
- }
-
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
- }
-
- // The difference in screen's native resolution pixels between
- // the border of the touchscreen and the border of the screen,
- // aka bezel sizes.
- int left_;
- int right_;
- int top_;
- int bottom_;
-
- DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
-};
-
-} // namespace internal
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindowHostX11::MouseMoveFilter filters out the move events that
-// jump back and forth between two points. This happens when sub pixel mouse
-// move is enabled and mouse move events could be jumping between two neighbor
-// pixels, e.g. move(0,0), move(1,0), move(0,0), move(1,0) and on and on.
-// The filtering is done by keeping track of the last two event locations and
-// provides a Filter method to find out whether a mouse event is in a different
-// location and should be processed.
-
-class RootWindowHostX11::MouseMoveFilter {
- public:
- MouseMoveFilter() : insert_index_(0) {
- for (size_t i = 0; i < kMaxEvents; ++i) {
- const int int_max = std::numeric_limits<int>::max();
- recent_locations_[i] = gfx::Point(int_max, int_max);
- }
- }
- ~MouseMoveFilter() {}
-
- // Returns true if |event| is known and should be ignored.
- bool Filter(const base::NativeEvent& event) {
- const gfx::Point& location = ui::EventLocationFromNative(event);
- for (size_t i = 0; i < kMaxEvents; ++i) {
- if (location == recent_locations_[i])
- return true;
- }
-
- recent_locations_[insert_index_] = location;
- insert_index_ = (insert_index_ + 1) % kMaxEvents;
- return false;
- }
-
- private:
- static const size_t kMaxEvents = 2;
-
- gfx::Point recent_locations_[kMaxEvents];
- size_t insert_index_;
-
- DISALLOW_COPY_AND_ASSIGN(MouseMoveFilter);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// RootWindowHostX11
-
-RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds)
- : xdisplay_(gfx::GetXDisplay()),
- xwindow_(0),
- x_root_window_(DefaultRootWindow(xdisplay_)),
- current_cursor_(ui::kCursorNull),
- window_mapped_(false),
- bounds_(bounds),
- is_internal_display_(false),
- touch_calibrate_(new internal::TouchEventCalibrate),
- mouse_move_filter_(new MouseMoveFilter),
- atom_cache_(xdisplay_, kAtomsToCache),
- bezel_tracking_ids_(0) {
- XSetWindowAttributes swa;
- memset(&swa, 0, sizeof(swa));
- swa.background_pixmap = None;
- swa.override_redirect = default_override_redirect;
- xwindow_ = XCreateWindow(
- xdisplay_, x_root_window_,
- bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- 0, // border width
- CopyFromParent, // depth
- InputOutput,
- CopyFromParent, // visual
- CWBackPixmap | CWOverrideRedirect,
- &swa);
- base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
- base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
-
- long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
- KeyPressMask | KeyReleaseMask |
- EnterWindowMask | LeaveWindowMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask | PropertyChangeMask |
- PointerMotionMask;
- XSelectInput(xdisplay_, xwindow_, event_mask);
- XFlush(xdisplay_);
-
- if (ui::IsXInput2Available()) {
- ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
- SelectXInput2EventsForRootWindow(xdisplay_, x_root_window_);
- }
-
- // TODO(erg): We currently only request window deletion events. We also
- // should listen for activation events and anything else that GTK+ listens
- // for, and do something useful.
- ::Atom protocols[2];
- protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
- protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
- XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
-
- // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
- // the desktop environment.
- XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
-
- // Likewise, the X server needs to know this window's pid so it knows which
- // program to kill if the window hangs.
- // XChangeProperty() expects "pid" to be long.
- COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
- long pid = getpid();
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_PID"),
- XA_CARDINAL,
- 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&pid), 1);
-
- XRRSelectInput(xdisplay_, x_root_window_,
- RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
- Env::GetInstance()->AddObserver(this);
-}
-
-RootWindowHostX11::~RootWindowHostX11() {
- Env::GetInstance()->RemoveObserver(this);
- base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
-
- UnConfineCursor();
-
- XDestroyWindow(xdisplay_, xwindow_);
-}
-
-bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) {
- XEvent* xev = event;
-
- if (FindEventTarget(event) == x_root_window_)
- return DispatchEventForRootWindow(event);
-
- switch (xev->type) {
- case EnterNotify: {
- aura::Window* root_window = GetRootWindow()->window();
- client::CursorClient* cursor_client =
- client::GetCursorClient(root_window);
- if (cursor_client) {
- const gfx::Display display = gfx::Screen::GetScreenFor(root_window)->
- GetDisplayNearestWindow(root_window);
- cursor_client->SetDisplay(display);
- }
- ui::MouseEvent mouse_event(xev);
- // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not
- // real mouse move event.
- mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
- TranslateAndDispatchMouseEvent(&mouse_event);
- break;
- }
- case LeaveNotify: {
- ui::MouseEvent mouse_event(xev);
- TranslateAndDispatchMouseEvent(&mouse_event);
- break;
- }
- case Expose: {
- gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
- xev->xexpose.width, xev->xexpose.height);
- delegate_->AsRootWindow()->ScheduleRedrawRect(damage_rect);
- break;
- }
- case KeyPress: {
- ui::KeyEvent keydown_event(xev, false);
- delegate_->OnHostKeyEvent(&keydown_event);
- break;
- }
- case KeyRelease: {
- ui::KeyEvent keyup_event(xev, false);
- delegate_->OnHostKeyEvent(&keyup_event);
- break;
- }
- case ButtonPress: {
- if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
- static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
- client::UserActionClient* gesture_client =
- client::GetUserActionClient(delegate_->AsRootWindow()->window());
- if (gesture_client) {
- gesture_client->OnUserAction(
- static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
- client::UserActionClient::BACK :
- client::UserActionClient::FORWARD);
- }
- break;
- }
- } // fallthrough
- case ButtonRelease: {
- switch (ui::EventTypeFromNative(xev)) {
- case ui::ET_MOUSEWHEEL: {
- ui::MouseWheelEvent mouseev(xev);
- TranslateAndDispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED: {
- ui::MouseEvent mouseev(xev);
- TranslateAndDispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_UNKNOWN:
- // No event is created for X11-release events for mouse-wheel buttons.
- break;
- default:
- NOTREACHED();
- }
- break;
- }
- case FocusOut:
- if (xev->xfocus.mode != NotifyGrab)
- delegate_->OnHostLostWindowCapture();
- break;
- case ConfigureNotify: {
- DCHECK_EQ(xwindow_, xev->xconfigure.event);
- DCHECK_EQ(xwindow_, xev->xconfigure.window);
- // It's possible that the X window may be resized by some other means
- // than from within aura (e.g. the X window manager can change the
- // size). Make sure the root window size is maintained properly.
- gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
- xev->xconfigure.width, xev->xconfigure.height);
- bool size_changed = bounds_.size() != bounds.size();
- bool origin_changed = bounds_.origin() != bounds.origin();
- bounds_ = bounds;
- UpdateIsInternalDisplay();
- // Always update barrier and mouse location because |bounds_| might
- // have already been updated in |SetBounds|.
- if (pointer_barriers_) {
- UnConfineCursor();
- ConfineCursorToRootWindow();
- }
- if (size_changed)
- delegate_->OnHostResized(bounds.size());
- if (origin_changed)
- delegate_->OnHostMoved(bounds_.origin());
- break;
- }
- case GenericEvent:
- DispatchXI2Event(event);
- break;
- case ClientMessage: {
- Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
- if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
- // We have received a close message from the window manager.
- delegate_->AsRootWindow()->OnRootWindowHostCloseRequested();
- } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
- XEvent reply_event = *xev;
- reply_event.xclient.window = x_root_window_;
-
- XSendEvent(xdisplay_,
- reply_event.xclient.window,
- False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- &reply_event);
- }
- break;
- }
- case MappingNotify: {
- switch (xev->xmapping.request) {
- case MappingModifier:
- case MappingKeyboard:
- XRefreshKeyboardMapping(&xev->xmapping);
- delegate_->AsRootWindow()->OnKeyboardMappingChanged();
- break;
- case MappingPointer:
- ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
- break;
- default:
- NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
- break;
- }
- break;
- }
- case MotionNotify: {
- // Discard all but the most recent motion event that targets the same
- // window with unchanged state.
- XEvent last_event;
- while (XPending(xev->xany.display)) {
- XEvent next_event;
- XPeekEvent(xev->xany.display, &next_event);
- if (next_event.type == MotionNotify &&
- next_event.xmotion.window == xev->xmotion.window &&
- next_event.xmotion.subwindow == xev->xmotion.subwindow &&
- next_event.xmotion.state == xev->xmotion.state) {
- XNextEvent(xev->xany.display, &last_event);
- xev = &last_event;
- } else {
- break;
- }
- }
-
- ui::MouseEvent mouseev(xev);
- TranslateAndDispatchMouseEvent(&mouseev);
- break;
- }
- }
- return true;
-}
-
-RootWindow* RootWindowHostX11::GetRootWindow() {
- return delegate_->AsRootWindow();
-}
-
-gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() {
- return xwindow_;
-}
-
-void RootWindowHostX11::Show() {
- if (!window_mapped_) {
- // Before we map the window, set size hints. Otherwise, some window managers
- // will ignore toplevel XMoveWindow commands.
- XSizeHints size_hints;
- size_hints.flags = PPosition | PWinGravity;
- size_hints.x = bounds_.x();
- size_hints.y = bounds_.y();
- // Set StaticGravity so that the window position is not affected by the
- // frame width when running with window manager.
- size_hints.win_gravity = StaticGravity;
- XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
-
- XMapWindow(xdisplay_, xwindow_);
-
- // We now block until our window is mapped. Some X11 APIs will crash and
- // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
- // asynchronous.
- base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
- window_mapped_ = true;
- }
-}
-
-void RootWindowHostX11::Hide() {
- if (window_mapped_) {
- XWithdrawWindow(xdisplay_, xwindow_, 0);
- window_mapped_ = false;
- }
-}
-
-void RootWindowHostX11::ToggleFullScreen() {
- NOTIMPLEMENTED();
-}
-
-gfx::Rect RootWindowHostX11::GetBounds() const {
- return bounds_;
-}
-
-void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
- // Even if the host window's size doesn't change, aura's root window
- // size, which is in DIP, changes when the scale changes.
- float current_scale = delegate_->GetDeviceScaleFactor();
- float new_scale = gfx::Screen::GetScreenFor(
- delegate_->AsRootWindow()->window())->GetDisplayNearestWindow(
- delegate_->AsRootWindow()->window()).device_scale_factor();
- bool origin_changed = bounds_.origin() != bounds.origin();
- bool size_changed = bounds_.size() != bounds.size();
- XWindowChanges changes = {0};
- unsigned value_mask = 0;
-
- if (size_changed) {
- changes.width = bounds.width();
- changes.height = bounds.height();
- value_mask = CWHeight | CWWidth;
- }
-
- if (origin_changed) {
- changes.x = bounds.x();
- changes.y = bounds.y();
- value_mask |= CWX | CWY;
- }
- if (value_mask)
- XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
-
- // Assume that the resize will go through as requested, which should be the
- // case if we're running without a window manager. If there's a window
- // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
- // (possibly synthetic) ConfigureNotify about the actual size and correct
- // |bounds_| later.
- bounds_ = bounds;
- UpdateIsInternalDisplay();
- if (origin_changed)
- delegate_->OnHostMoved(bounds.origin());
- if (size_changed || current_scale != new_scale) {
- delegate_->OnHostResized(bounds.size());
- } else {
- delegate_->AsRootWindow()->window()->SchedulePaintInRect(
- delegate_->AsRootWindow()->window()->bounds());
- }
-}
-
-gfx::Insets RootWindowHostX11::GetInsets() const {
- return insets_;
-}
-
-void RootWindowHostX11::SetInsets(const gfx::Insets& insets) {
- insets_ = insets;
- if (pointer_barriers_) {
- UnConfineCursor();
- ConfineCursorToRootWindow();
- }
-}
-
-gfx::Point RootWindowHostX11::GetLocationOnNativeScreen() const {
- return bounds_.origin();
-}
-
-void RootWindowHostX11::SetCapture() {
- // TODO(oshima): Grab x input.
-}
-
-void RootWindowHostX11::ReleaseCapture() {
- // TODO(oshima): Release x input.
-}
-
-void RootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
- if (cursor == current_cursor_)
- return;
- current_cursor_ = cursor;
- SetCursorInternal(cursor);
-}
-
-bool RootWindowHostX11::QueryMouseLocation(gfx::Point* location_return) {
- client::CursorClient* cursor_client =
- client::GetCursorClient(GetRootWindow()->window());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
- *location_return = gfx::Point(0, 0);
- return false;
- }
-
- ::Window root_return, child_return;
- int root_x_return, root_y_return, win_x_return, win_y_return;
- unsigned int mask_return;
- XQueryPointer(xdisplay_,
- xwindow_,
- &root_return,
- &child_return,
- &root_x_return, &root_y_return,
- &win_x_return, &win_y_return,
- &mask_return);
- *location_return = gfx::Point(max(0, min(bounds_.width(), win_x_return)),
- max(0, min(bounds_.height(), win_y_return)));
- return (win_x_return >= 0 && win_x_return < bounds_.width() &&
- win_y_return >= 0 && win_y_return < bounds_.height());
-}
-
-bool RootWindowHostX11::ConfineCursorToRootWindow() {
-#if XFIXES_MAJOR >= 5
- DCHECK(!pointer_barriers_.get());
- if (pointer_barriers_)
- return false;
- pointer_barriers_.reset(new XID[4]);
- gfx::Rect bounds(bounds_);
- bounds.Inset(insets_);
- // Horizontal, top barriers.
- pointer_barriers_[0] = XFixesCreatePointerBarrier(
- xdisplay_, x_root_window_,
- bounds.x(), bounds.y(), bounds.right(), bounds.y(),
- BarrierPositiveY,
- 0, XIAllDevices);
- // Horizontal, bottom barriers.
- pointer_barriers_[1] = XFixesCreatePointerBarrier(
- xdisplay_, x_root_window_,
- bounds.x(), bounds.bottom(), bounds.right(), bounds.bottom(),
- BarrierNegativeY,
- 0, XIAllDevices);
- // Vertical, left barriers.
- pointer_barriers_[2] = XFixesCreatePointerBarrier(
- xdisplay_, x_root_window_,
- bounds.x(), bounds.y(), bounds.x(), bounds.bottom(),
- BarrierPositiveX,
- 0, XIAllDevices);
- // Vertical, right barriers.
- pointer_barriers_[3] = XFixesCreatePointerBarrier(
- xdisplay_, x_root_window_,
- bounds.right(), bounds.y(), bounds.right(), bounds.bottom(),
- BarrierNegativeX,
- 0, XIAllDevices);
-#endif
- return true;
-}
-
-void RootWindowHostX11::UnConfineCursor() {
-#if XFIXES_MAJOR >= 5
- if (pointer_barriers_) {
- XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[0]);
- XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[1]);
- XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[2]);
- XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[3]);
- pointer_barriers_.reset();
- }
-#endif
-}
-
-void RootWindowHostX11::OnCursorVisibilityChanged(bool show) {
- SetCrOSTapPaused(!show);
-}
-
-void RootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
- XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
- bounds_.x() + location.x(),
- bounds_.y() + location.y());
-}
-
-void RootWindowHostX11::PostNativeEvent(
- const base::NativeEvent& native_event) {
- DCHECK(xwindow_);
- DCHECK(xdisplay_);
- XEvent xevent = *native_event;
- xevent.xany.display = xdisplay_;
- xevent.xany.window = xwindow_;
-
- switch (xevent.type) {
- case EnterNotify:
- case LeaveNotify:
- case MotionNotify:
- case KeyPress:
- case KeyRelease:
- case ButtonPress:
- case ButtonRelease: {
- // The fields used below are in the same place for all of events
- // above. Using xmotion from XEvent's unions to avoid repeating
- // the code.
- xevent.xmotion.root = x_root_window_;
- xevent.xmotion.time = CurrentTime;
-
- gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
- delegate_->AsRootWindow()->host()->ConvertPointToNativeScreen(&point);
- xevent.xmotion.x_root = point.x();
- xevent.xmotion.y_root = point.y();
- }
- default:
- break;
- }
- XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
-}
-
-void RootWindowHostX11::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
-}
-
-void RootWindowHostX11::PrepareForShutdown() {
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
-}
-
-void RootWindowHostX11::OnWindowInitialized(Window* window) {
-}
-
-void RootWindowHostX11::OnRootWindowInitialized(RootWindow* root_window) {
- // UpdateIsInternalDisplay relies on:
- // 1. delegate_ pointing to RootWindow - available after SetDelegate.
- // 2. RootWindow's kDisplayIdKey property set - available by the time
- // RootWindow::Init is called.
- // (set in DisplayManager::CreateRootWindowForDisplay)
- // Ready when NotifyRootWindowInitialized is called from RootWindow::Init.
- if (!delegate_ || root_window != GetRootWindow())
- return;
- UpdateIsInternalDisplay();
-
- // We have to enable Tap-to-click by default because the cursor is set to
- // visible in Shell::InitRootWindowController.
- SetCrOSTapPaused(false);
-}
-
-ui::EventProcessor* RootWindowHostX11::GetEventProcessor() {
- return delegate_->GetEventProcessor();
-}
-
-bool RootWindowHostX11::DispatchEventForRootWindow(
- const base::NativeEvent& event) {
- switch (event->type) {
- case GenericEvent:
- DispatchXI2Event(event);
- break;
- }
-
- return true;
-}
-
-void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) {
- ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
- XEvent* xev = event;
- if (!factory->ShouldProcessXI2Event(xev))
- return;
-
- TRACE_EVENT1("input", "RootWindowHostX11::DispatchXI2Event",
- "event_latency_us",
- (ui::EventTimeForNow() - ui::EventTimeFromNative(event)).
- InMicroseconds());
-
- ui::EventType type = ui::EventTypeFromNative(xev);
- XEvent last_event;
- int num_coalesced = 0;
-
- switch (type) {
- case ui::ET_TOUCH_MOVED:
- case ui::ET_TOUCH_PRESSED:
- case ui::ET_TOUCH_CANCELLED:
- case ui::ET_TOUCH_RELEASED: {
-#if defined(OS_CHROMEOS)
- // Bail out early before generating a ui::TouchEvent if this event
- // is not within the range of this RootWindow. Converting an xevent
- // to ui::TouchEvent might change the state of the global touch tracking
- // state, e.g. touch release event can remove the touch id from the
- // record, and doing this multiple time when there are multiple
- // RootWindow will cause problem. So only generate the ui::TouchEvent
- // when we are sure it belongs to this RootWindow.
- if (base::SysInfo::IsRunningOnChromeOS() &&
- !bounds_.Contains(ui::EventLocationFromNative(xev)))
- break;
-#endif // defined(OS_CHROMEOS)
- ui::TouchEvent touchev(xev);
-#if defined(USE_XI2_MT)
- // Ignore touch events with touch press happening on the side bezel.
- if (!IsSideBezelsEnabled()) {
- uint32 tracking_id = (1 << touchev.touch_id());
- if (type == ui::ET_TOUCH_PRESSED &&
- touch_calibrate_->IsEventOnSideBezels(xev, bounds_))
- bezel_tracking_ids_ |= tracking_id;
- if (bezel_tracking_ids_ & tracking_id) {
- if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED)
- bezel_tracking_ids_ =
- (bezel_tracking_ids_ | tracking_id) ^ tracking_id;
- return;
- }
- }
-#endif // defined(USE_XI2_MT)
-#if defined(OS_CHROMEOS)
- if (base::SysInfo::IsRunningOnChromeOS()) {
- // X maps the touch-surface to the size of the X root-window.
- // In multi-monitor setup, Coordinate Transformation Matrix
- // repositions the touch-surface onto part of X root-window
- // containing aura root-window corresponding to the touchscreen.
- // However, if aura root-window has non-zero origin,
- // we need to relocate the event into aura root-window coordinates.
- touchev.Relocate(bounds_.origin());
-#if defined(USE_XI2_MT)
- if (is_internal_display_)
- touch_calibrate_->Calibrate(&touchev, bounds_);
-#endif // defined(USE_XI2_MT)
- }
-#endif // defined(OS_CHROMEOS)
- delegate_->OnHostTouchEvent(&touchev);
- break;
- }
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED:
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- case ui::ET_MOUSE_ENTERED:
- case ui::ET_MOUSE_EXITED: {
- if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
- // If this is a motion event, we want to coalesce all pending motion
- // events that are at the top of the queue.
- num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
- if (num_coalesced > 0)
- xev = &last_event;
-
- if (mouse_move_filter_ && mouse_move_filter_->Filter(xev))
- break;
- } else if (type == ui::ET_MOUSE_PRESSED ||
- type == ui::ET_MOUSE_RELEASED) {
- XIDeviceEvent* xievent =
- static_cast<XIDeviceEvent*>(xev->xcookie.data);
- int button = xievent->detail;
- if (button == kBackMouseButton || button == kForwardMouseButton) {
- if (type == ui::ET_MOUSE_RELEASED)
- break;
- client::UserActionClient* gesture_client =
- client::GetUserActionClient(delegate_->AsRootWindow()->window());
- if (gesture_client) {
- bool reverse_direction =
- ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
- gesture_client->OnUserAction(
- (button == kBackMouseButton && !reverse_direction) ||
- (button == kForwardMouseButton && reverse_direction) ?
- client::UserActionClient::BACK :
- client::UserActionClient::FORWARD);
- }
- break;
- }
- }
- ui::MouseEvent mouseev(xev);
- TranslateAndDispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_MOUSEWHEEL: {
- ui::MouseWheelEvent mouseev(xev);
- TranslateAndDispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_SCROLL_FLING_START:
- case ui::ET_SCROLL_FLING_CANCEL:
- case ui::ET_SCROLL: {
- ui::ScrollEvent scrollev(xev);
- delegate_->OnHostScrollEvent(&scrollev);
- break;
- }
- case ui::ET_UMA_DATA:
- break;
- case ui::ET_UNKNOWN:
- break;
- default:
- NOTREACHED();
- }
-
- // If we coalesced an event we need to free its cookie.
- if (num_coalesced > 0)
- XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
-}
-
-bool RootWindowHostX11::IsWindowManagerPresent() {
- // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
- // of WM_Sn selections (where n is a screen number).
- return XGetSelectionOwner(
- xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
-}
-
-void RootWindowHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
- XDefineCursor(xdisplay_, xwindow_, cursor.platform());
-}
-
-void RootWindowHostX11::TranslateAndDispatchMouseEvent(
- ui::MouseEvent* event) {
- Window* root_window = GetRootWindow()->window();
- client::ScreenPositionClient* screen_position_client =
- client::GetScreenPositionClient(root_window);
- gfx::Rect local(bounds_.size());
-
- if (screen_position_client && !local.Contains(event->location())) {
- gfx::Point location(event->location());
- // In order to get the correct point in screen coordinates
- // during passive grab, we first need to find on which host window
- // the mouse is on, and find out the screen coordinates on that
- // host window, then convert it back to this host window's coordinate.
- screen_position_client->ConvertHostPointToScreen(root_window, &location);
- screen_position_client->ConvertPointFromScreen(root_window, &location);
- root_window->GetDispatcher()->ConvertPointToHost(&location);
- event->set_location(location);
- event->set_root_location(location);
- }
- delegate_->OnHostMouseEvent(event);
-}
-
-void RootWindowHostX11::UpdateIsInternalDisplay() {
- Window* root_window = GetRootWindow()->window();
- gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window);
- gfx::Display display = screen->GetDisplayNearestWindow(root_window);
- is_internal_display_ = display.IsInternal();
-}
-
-void RootWindowHostX11::SetCrOSTapPaused(bool state) {
-#if defined(OS_CHROMEOS)
- if (!ui::IsXInput2Available())
- return;
- // Temporarily pause tap-to-click when the cursor is hidden.
- Atom prop = atom_cache_.GetAtom("Tap Paused");
- unsigned char value = state;
- XIDeviceList dev_list =
- ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_);
-
- // Only slave pointer devices could possibly have tap-paused property.
- for (int i = 0; i < dev_list.count; i++) {
- if (dev_list[i].use == XISlavePointer) {
- Atom old_type;
- int old_format;
- unsigned long old_nvalues, bytes;
- unsigned char* data;
- int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0,
- False, AnyPropertyType, &old_type, &old_format,
- &old_nvalues, &bytes, &data);
- if (result != Success)
- continue;
- XFree(data);
- XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8,
- PropModeReplace, &value, 1);
- }
- }
-#endif
-}
-
-// static
-RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) {
- return new RootWindowHostX11(bounds);
-}
-
-// static
-gfx::Size RootWindowHost::GetNativeScreenSize() {
- ::XDisplay* xdisplay = gfx::GetXDisplay();
- return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
-}
-
-namespace test {
-
-void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
- default_override_redirect = override_redirect;
-}
-
-} // namespace test
-} // namespace aura
diff --git a/chromium/ui/aura/root_window_host_x11.h b/chromium/ui/aura/root_window_host_x11.h
deleted file mode 100644
index d4b35186a8b..00000000000
--- a/chromium/ui/aura/root_window_host_x11.h
+++ /dev/null
@@ -1,152 +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_AURA_ROOT_WINDOW_HOST_X11_H_
-#define UI_AURA_ROOT_WINDOW_HOST_X11_H_
-
-#include <X11/Xlib.h>
-
-#include <vector>
-
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/aura/aura_export.h"
-#include "ui/aura/env_observer.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/events/event_source.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/x/x11_atom_cache.h"
-
-namespace ui {
-class MouseEvent;
-}
-
-namespace aura {
-
-namespace internal {
-class TouchEventCalibrate;
-}
-
-class AURA_EXPORT RootWindowHostX11 : public RootWindowHost,
- public base::MessageLoop::Dispatcher,
- public ui::EventSource,
- public EnvObserver {
- public:
- explicit RootWindowHostX11(const gfx::Rect& bounds);
- virtual ~RootWindowHostX11();
-
- // Overridden from Dispatcher overrides:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- // RootWindowHost Overrides.
- virtual RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
- // EnvObserver overrides.
- virtual void OnWindowInitialized(Window* window) OVERRIDE;
- virtual void OnRootWindowInitialized(RootWindow* root_window) OVERRIDE;
-
- // ui::EventSource overrides.
- virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
-
- private:
- class MouseMoveFilter;
-
- bool DispatchEventForRootWindow(const base::NativeEvent& event);
-
- // Dispatches XI2 events. Note that some events targetted for the X root
- // window are dispatched to the aura root window (e.g. touch events after
- // calibration).
- void DispatchXI2Event(const base::NativeEvent& event);
-
- // Returns true if there's an X window manager present... in most cases. Some
- // window managers (notably, ion3) don't implement enough of ICCCM for us to
- // detect that they're there.
- bool IsWindowManagerPresent();
-
- // Sets the cursor on |xwindow_| to |cursor|. Does not check or update
- // |current_cursor_|.
- void SetCursorInternal(gfx::NativeCursor cursor);
-
- // Translates the native mouse location into screen coordinates and and
- // dispatches the event to RootWindowHostDelegate.
- void TranslateAndDispatchMouseEvent(ui::MouseEvent* event);
-
- // Update is_internal_display_ based on delegate_ state
- void UpdateIsInternalDisplay();
-
- // Set the CrOS touchpad "tap paused" property. It is used to temporarily
- // turn off the Tap-to-click feature when the mouse pointer is invisible.
- void SetCrOSTapPaused(bool state);
-
- // The display and the native X window hosting the root window.
- XDisplay* xdisplay_;
- ::Window xwindow_;
-
- // The native root window.
- ::Window x_root_window_;
-
- // Current Aura cursor.
- gfx::NativeCursor current_cursor_;
-
- // Is the window mapped to the screen?
- bool window_mapped_;
-
- // The bounds of |xwindow_|.
- gfx::Rect bounds_;
-
- // The insets that specifies the effective area within the |window_|.
- gfx::Insets insets_;
-
- // True if the root host resides on the internal display
- bool is_internal_display_;
-
- scoped_ptr<XID[]> pointer_barriers_;
-
- scoped_ptr<internal::TouchEventCalibrate> touch_calibrate_;
-
- scoped_ptr<MouseMoveFilter> mouse_move_filter_;
-
- ui::X11AtomCache atom_cache_;
-
- // Touch ids of which the touch press happens at side bezel region.
- uint32 bezel_tracking_ids_;
-
- DISALLOW_COPY_AND_ASSIGN(RootWindowHostX11);
-};
-
-namespace test {
-
-// Set the default value of the override redirect flag used to
-// create a X window for RootWindowHostX11.
-AURA_EXPORT void SetUseOverrideRedirectWindowByDefault(bool override_redirect);
-
-} // namespace test
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_HOST_X11_H_
diff --git a/chromium/ui/aura/root_window_host_x11_unittest.cc b/chromium/ui/aura/root_window_host_x11_unittest.cc
deleted file mode 100644
index 576707a09c7..00000000000
--- a/chromium/ui/aura/root_window_host_x11_unittest.cc
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-#include "base/sys_info.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/root_window_host_x11.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/window_tree_host_delegate.h"
-#include "ui/events/event_processor.h"
-#include "ui/events/event_target.h"
-#include "ui/events/event_target_iterator.h"
-#include "ui/events/test/events_test_utils_x11.h"
-
-namespace {
-class TestRootWindowHostDelegate : public aura::RootWindowHostDelegate,
- public ui::EventProcessor,
- public ui::EventTarget {
- public:
- TestRootWindowHostDelegate() : last_touch_type_(ui::ET_UNKNOWN),
- last_touch_id_(-1),
- last_touch_location_(0, 0) {
- }
- virtual ~TestRootWindowHostDelegate() {}
-
- // aura::RootWindowHostDelegate:
- virtual bool OnHostKeyEvent(ui::KeyEvent* event) OVERRIDE {
- return true;
- }
- virtual bool OnHostMouseEvent(ui::MouseEvent* event) OVERRIDE {
- return true;
- }
- virtual bool OnHostScrollEvent(ui::ScrollEvent* event) OVERRIDE {
- return true;
- }
- virtual bool OnHostTouchEvent(ui::TouchEvent* event) OVERRIDE {
- last_touch_id_ = event->touch_id();
- last_touch_type_ = event->type();
- last_touch_location_ = event->location();
- return true;
- }
-
- virtual void OnHostCancelMode() OVERRIDE {}
- virtual void OnHostActivated() OVERRIDE {}
- virtual void OnHostLostWindowCapture() OVERRIDE {}
- virtual void OnHostLostMouseGrab() OVERRIDE {}
- virtual void OnHostPaint(const gfx::Rect& damage_rect) OVERRIDE {}
- virtual void OnHostMoved(const gfx::Point& origin) OVERRIDE {}
- virtual void OnHostResized(const gfx::Size& size) OVERRIDE {}
- virtual float GetDeviceScaleFactor() OVERRIDE { return 1.0f; }
- virtual aura::RootWindow* AsRootWindow() OVERRIDE { return NULL; }
- virtual const aura::RootWindow* AsRootWindow() const OVERRIDE { return NULL; }
- virtual ui::EventProcessor* GetEventProcessor() OVERRIDE {
- return this;
- }
-
- // ui::EventProcessor:
- virtual ui::EventTarget* GetRootTarget() OVERRIDE { return this; }
- virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE {
- return true;
- }
-
- // ui::EventHandler:
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
- last_touch_id_ = event->touch_id();
- last_touch_type_ = event->type();
- last_touch_location_ = event->location();
- }
-
- // ui::EventTarget:
- virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE {
- return true;
- }
- virtual ui::EventTarget* GetParentTarget() OVERRIDE { return NULL; }
- virtual scoped_ptr<ui::EventTargetIterator>
- GetChildIterator() const OVERRIDE {
- return scoped_ptr<ui::EventTargetIterator>();
- }
- virtual ui::EventTargeter* GetEventTargeter() OVERRIDE { return &targeter_; }
-
- ui::EventType last_touch_type() {
- return last_touch_type_;
- }
-
- int last_touch_id() {
- return last_touch_id_;
- }
-
- gfx::Point last_touch_location() {
- return last_touch_location_;
- }
-
- private:
- ui::EventType last_touch_type_;
- int last_touch_id_;
- gfx::Point last_touch_location_;
- ui::EventTargeter targeter_;
-
- DISALLOW_COPY_AND_ASSIGN(TestRootWindowHostDelegate);
-};
-
-} // namespace
-
-namespace aura {
-
-typedef test::AuraTestBase RootWindowHostX11Test;
-
-// Send X touch events to one RootWindowHost. The RootWindowHost's
-// delegate will get corresponding ui::TouchEvent if the touch events
-// are winthin the bound of the RootWindowHost.
-TEST_F(RootWindowHostX11Test, DispatchTouchEventToOneRootWindow) {
-#if defined(OS_CHROMEOS)
- // Fake a ChromeOS running env.
- const char* kLsbRelease = "CHROMEOS_RELEASE_NAME=Chromium OS\n";
- base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-#endif // defined(OS_CHROMEOS)
-
- scoped_ptr<RootWindowHostX11> root_window_host(
- new RootWindowHostX11(gfx::Rect(0, 0, 2560, 1700)));
- scoped_ptr<TestRootWindowHostDelegate> delegate(
- new TestRootWindowHostDelegate());
- root_window_host->set_delegate(delegate.get());
-
- std::vector<unsigned int> devices;
- devices.push_back(0);
- ui::SetUpTouchDevicesForTest(devices);
- std::vector<ui::Valuator> valuators;
-
- EXPECT_EQ(ui::ET_UNKNOWN, delegate->last_touch_type());
- EXPECT_EQ(-1, delegate->last_touch_id());
-
- ui::ScopedXI2Event scoped_xevent;
-#if defined(OS_CHROMEOS)
- // This touch is out of bounds.
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchBegin, 5, gfx::Point(1500, 2500), valuators);
- root_window_host->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate->last_touch_type());
- EXPECT_EQ(-1, delegate->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate->last_touch_location());
-#endif // defined(OS_CHROMEOS)
-
- // Following touchs are within bounds and are passed to delegate.
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchBegin, 5, gfx::Point(1500, 1500), valuators);
- root_window_host->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate->last_touch_type());
- EXPECT_EQ(0, delegate->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 1500), delegate->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchUpdate, 5, gfx::Point(1500, 1600), valuators);
- root_window_host->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate->last_touch_type());
- EXPECT_EQ(0, delegate->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 1600), delegate->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchEnd, 5, gfx::Point(1500, 1600), valuators);
- root_window_host->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate->last_touch_type());
- EXPECT_EQ(0, delegate->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 1600), delegate->last_touch_location());
-
- // Revert the CrOS testing env otherwise the following non-CrOS aura
- // tests will fail.
-#if defined(OS_CHROMEOS)
- // Fake a ChromeOS running env.
- kLsbRelease = "";
- base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-#endif // defined(OS_CHROMEOS)
-}
-
-// Send X touch events to two RootWindowHost. The RootWindowHost which is
-// the event target of the X touch events should generate the corresponding
-// ui::TouchEvent for its delegate.
-#if defined(OS_CHROMEOS)
-TEST_F(RootWindowHostX11Test, DispatchTouchEventToTwoRootWindow) {
- // Fake a ChromeOS running env.
- const char* kLsbRelease = "CHROMEOS_RELEASE_NAME=Chromium OS\n";
- base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-
- scoped_ptr<RootWindowHostX11> root_window_host1(
- new RootWindowHostX11(gfx::Rect(0, 0, 2560, 1700)));
- scoped_ptr<TestRootWindowHostDelegate> delegate1(
- new TestRootWindowHostDelegate());
- root_window_host1->set_delegate(delegate1.get());
-
- int host2_y_offset = 1700;
- scoped_ptr<RootWindowHostX11> root_window_host2(
- new RootWindowHostX11(gfx::Rect(0, host2_y_offset, 1920, 1080)));
- scoped_ptr<TestRootWindowHostDelegate> delegate2(
- new TestRootWindowHostDelegate());
- root_window_host2->set_delegate(delegate2.get());
-
- std::vector<unsigned int> devices;
- devices.push_back(0);
- ui::SetUpTouchDevicesForTest(devices);
- std::vector<ui::Valuator> valuators;
-
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(ui::ET_UNKNOWN, delegate2->last_touch_type());
- EXPECT_EQ(-1, delegate2->last_touch_id());
-
- // 2 Touch events are targeted at the second RootWindowHost.
- ui::ScopedXI2Event scoped_xevent;
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchBegin, 5, gfx::Point(1500, 2500), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate2->last_touch_type());
- EXPECT_EQ(0, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 2500 - host2_y_offset),
- delegate2->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchBegin, 6, gfx::Point(1600, 2600), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate2->last_touch_type());
- EXPECT_EQ(1, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1600, 2600 - host2_y_offset),
- delegate2->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchUpdate, 5, gfx::Point(1500, 2550), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate2->last_touch_type());
- EXPECT_EQ(0, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 2550 - host2_y_offset),
- delegate2->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchUpdate, 6, gfx::Point(1600, 2650), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate2->last_touch_type());
- EXPECT_EQ(1, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1600, 2650 - host2_y_offset),
- delegate2->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchEnd, 5, gfx::Point(1500, 2550), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate2->last_touch_type());
- EXPECT_EQ(0, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1500, 2550 - host2_y_offset),
- delegate2->last_touch_location());
-
- scoped_xevent.InitTouchEvent(
- 0, XI_TouchEnd, 6, gfx::Point(1600, 2650), valuators);
- root_window_host1->Dispatch(scoped_xevent);
- root_window_host2->Dispatch(scoped_xevent);
- EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type());
- EXPECT_EQ(-1, delegate1->last_touch_id());
- EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location());
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate2->last_touch_type());
- EXPECT_EQ(1, delegate2->last_touch_id());
- EXPECT_EQ(gfx::Point(1600, 2650 - host2_y_offset),
- delegate2->last_touch_location());
-
- // Revert the CrOS testing env otherwise the following non-CrOS aura
- // tests will fail.
- // Fake a ChromeOS running env.
- kLsbRelease = "";
- base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-}
-#endif // defined(OS_CHROMEOS)
-
-} // namespace aura
diff --git a/chromium/ui/aura/root_window_observer.h b/chromium/ui/aura/root_window_observer.h
deleted file mode 100644
index bfb8e65c518..00000000000
--- a/chromium/ui/aura/root_window_observer.h
+++ /dev/null
@@ -1,41 +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_AURA_ROOT_WINDOW_OBSERVER_H_
-#define UI_AURA_ROOT_WINDOW_OBSERVER_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace gfx {
-class Point;
-class Size;
-}
-
-namespace aura {
-class RootWindow;
-class Window;
-
-class AURA_EXPORT RootWindowObserver {
- public:
- // Invoked after the RootWindow's host has been resized.
- virtual void OnRootWindowHostResized(const RootWindow* root) {}
-
- // Invoked after the RootWindow's host has been moved on screen.
- virtual void OnRootWindowHostMoved(const RootWindow* root,
- const gfx::Point& new_origin) {}
-
- // Invoked when the native windowing system sends us a request to close our
- // window.
- virtual void OnRootWindowHostCloseRequested(const RootWindow* root) {}
-
- // Invoked when the keyboard mapping has changed.
- virtual void OnKeyboardMappingChanged(const RootWindow* root) {}
-
- protected:
- virtual ~RootWindowObserver() {}
-};
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_OBSERVER_H_
diff --git a/chromium/ui/aura/root_window_transformer.h b/chromium/ui/aura/root_window_transformer.h
deleted file mode 100644
index 89d67f28e6d..00000000000
--- a/chromium/ui/aura/root_window_transformer.h
+++ /dev/null
@@ -1,45 +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_AURA_ROOT_WINDOW_TRANSFORMER_H_
-#define UI_AURA_ROOT_WINDOW_TRANSFORMER_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace gfx {
-class Insets;
-class Rect;
-class Size;
-class Transform;
-}
-
-namespace aura {
-
-// RootWindowTransformer controls how RootWindow should be placed and
-// transformed inside the host window.
-class AURA_EXPORT RootWindowTransformer {
- public:
- virtual ~RootWindowTransformer() {}
-
- // Returns the transform the root window in DIP.
- virtual gfx::Transform GetTransform() const = 0;
-
- // Returns the inverse of the transform above. This method is to
- // provie an accurate inverse of the transform because the result of
- // |gfx::Transform::GetInverse| may contains computational error.
- virtual gfx::Transform GetInverseTransform() const = 0;
-
- // Returns the root window's bounds for given host window size in DIP.
- // This is necessary to handle the case where the root window's size
- // is bigger than the host window. (Screen magnifier for example).
- virtual gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const = 0;
-
- // Returns the insets that specifies the effective area of
- // the host window.
- virtual gfx::Insets GetHostInsets() const = 0;
-};
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_TRANSFORMER_H_
diff --git a/chromium/ui/aura/root_window_unittest.cc b/chromium/ui/aura/root_window_unittest.cc
deleted file mode 100644
index 2d135249bc8..00000000000
--- a/chromium/ui/aura/root_window_unittest.cc
+++ /dev/null
@@ -1,1530 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/root_window.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/client/event_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/test/test_cursor_client.h"
-#include "ui/aura/test/test_event_handler.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tracker.h"
-#include "ui/base/hit_test.h"
-#include "ui/events/event.h"
-#include "ui/events/event_handler.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/gestures/gesture_configuration.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/transform.h"
-
-namespace aura {
-namespace {
-
-// A delegate that always returns a non-client component for hit tests.
-class NonClientDelegate : public test::TestWindowDelegate {
- public:
- NonClientDelegate()
- : non_client_count_(0),
- mouse_event_count_(0),
- mouse_event_flags_(0x0) {
- }
- virtual ~NonClientDelegate() {}
-
- int non_client_count() const { return non_client_count_; }
- gfx::Point non_client_location() const { return non_client_location_; }
- int mouse_event_count() const { return mouse_event_count_; }
- gfx::Point mouse_event_location() const { return mouse_event_location_; }
- int mouse_event_flags() const { return mouse_event_flags_; }
-
- virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE {
- NonClientDelegate* self = const_cast<NonClientDelegate*>(this);
- self->non_client_count_++;
- self->non_client_location_ = location;
- return HTTOPLEFT;
- }
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- mouse_event_count_++;
- mouse_event_location_ = event->location();
- mouse_event_flags_ = event->flags();
- event->SetHandled();
- }
-
- private:
- int non_client_count_;
- gfx::Point non_client_location_;
- int mouse_event_count_;
- gfx::Point mouse_event_location_;
- int mouse_event_flags_;
-
- DISALLOW_COPY_AND_ASSIGN(NonClientDelegate);
-};
-
-// A simple event handler that consumes key events.
-class ConsumeKeyHandler : public test::TestEventHandler {
- public:
- ConsumeKeyHandler() {}
- virtual ~ConsumeKeyHandler() {}
-
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
- test::TestEventHandler::OnKeyEvent(event);
- event->StopPropagation();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler);
-};
-
-bool IsFocusedWindow(aura::Window* window) {
- return client::GetFocusClient(window)->GetFocusedWindow() == window;
-}
-
-} // namespace
-
-typedef test::AuraTestBase RootWindowTest;
-
-TEST_F(RootWindowTest, OnHostMouseEvent) {
- // Create two non-overlapping windows so we don't have to worry about which
- // is on top.
- scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate());
- scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate());
- const int kWindowWidth = 123;
- const int kWindowHeight = 45;
- gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight);
- gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight);
- scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate(
- delegate1.get(), -1234, bounds1, root_window()));
- scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate(
- delegate2.get(), -5678, bounds2, root_window()));
-
- // Send a mouse event to window1.
- gfx::Point point(101, 201);
- ui::MouseEvent event1(
- ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&event1);
-
- // Event was tested for non-client area for the target window.
- EXPECT_EQ(1, delegate1->non_client_count());
- EXPECT_EQ(0, delegate2->non_client_count());
- // The non-client component test was in local coordinates.
- EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
- // Mouse event was received by target window.
- EXPECT_EQ(1, delegate1->mouse_event_count());
- EXPECT_EQ(0, delegate2->mouse_event_count());
- // Event was in local coordinates.
- EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location());
- // Non-client flag was set.
- EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT);
-}
-
-TEST_F(RootWindowTest, RepostEvent) {
- // Test RepostEvent in RootWindow. It only works for Mouse Press.
- EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
- gfx::Point point(10, 10);
- ui::MouseEvent event(
- ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON);
- dispatcher()->RepostEvent(event);
- RunAllPendingInMessageLoop();
- EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
-}
-
-// Check that we correctly track the state of the mouse buttons in response to
-// button press and release events.
-TEST_F(RootWindowTest, MouseButtonState) {
- EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
-
- gfx::Point location;
- scoped_ptr<ui::MouseEvent> event;
-
- // Press the left button.
- event.reset(new ui::MouseEvent(
- ui::ET_MOUSE_PRESSED,
- location,
- location,
- ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get());
- EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
-
- // Additionally press the right.
- event.reset(new ui::MouseEvent(
- ui::ET_MOUSE_PRESSED,
- location,
- location,
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON));
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get());
- EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
-
- // Release the left button.
- event.reset(new ui::MouseEvent(
- ui::ET_MOUSE_RELEASED,
- location,
- location,
- ui::EF_RIGHT_MOUSE_BUTTON));
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get());
- EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
-
- // Release the right button. We should ignore the Shift-is-down flag.
- event.reset(new ui::MouseEvent(
- ui::ET_MOUSE_RELEASED,
- location,
- location,
- ui::EF_SHIFT_DOWN));
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get());
- EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
-
- // Press the middle button.
- event.reset(new ui::MouseEvent(
- ui::ET_MOUSE_PRESSED,
- location,
- location,
- ui::EF_MIDDLE_MOUSE_BUTTON));
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get());
- EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
-}
-
-TEST_F(RootWindowTest, TranslatedEvent) {
- scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1,
- gfx::Rect(50, 50, 100, 100), root_window()));
-
- gfx::Point origin(100, 100);
- ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0);
-
- EXPECT_EQ("100,100", root.location().ToString());
- EXPECT_EQ("100,100", root.root_location().ToString());
-
- ui::MouseEvent translated_event(
- root, static_cast<Window*>(root_window()), w1.get(),
- ui::ET_MOUSE_ENTERED, root.flags());
- EXPECT_EQ("50,50", translated_event.location().ToString());
- EXPECT_EQ("100,100", translated_event.root_location().ToString());
-}
-
-namespace {
-
-class TestEventClient : public client::EventClient {
- public:
- static const int kNonLockWindowId = 100;
- static const int kLockWindowId = 200;
-
- explicit TestEventClient(Window* root_window)
- : root_window_(root_window),
- lock_(false) {
- client::SetEventClient(root_window_, this);
- Window* lock_window =
- test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
- lock_window->set_id(kLockWindowId);
- Window* non_lock_window =
- test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
- non_lock_window->set_id(kNonLockWindowId);
- }
- virtual ~TestEventClient() {
- client::SetEventClient(root_window_, NULL);
- }
-
- // Starts/stops locking. Locking prevents windows other than those inside
- // the lock container from receiving events, getting focus etc.
- void Lock() {
- lock_ = true;
- }
- void Unlock() {
- lock_ = false;
- }
-
- Window* GetLockWindow() {
- return const_cast<Window*>(
- static_cast<const TestEventClient*>(this)->GetLockWindow());
- }
- const Window* GetLockWindow() const {
- return root_window_->GetChildById(kLockWindowId);
- }
- Window* GetNonLockWindow() {
- return root_window_->GetChildById(kNonLockWindowId);
- }
-
- private:
- // Overridden from client::EventClient:
- virtual bool CanProcessEventsWithinSubtree(
- const Window* window) const OVERRIDE {
- return lock_ ?
- window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) :
- true;
- }
-
- virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE {
- return NULL;
- }
-
- Window* root_window_;
- bool lock_;
-
- DISALLOW_COPY_AND_ASSIGN(TestEventClient);
-};
-
-} // namespace
-
-TEST_F(RootWindowTest, CanProcessEventsWithinSubtree) {
- TestEventClient client(root_window());
- test::TestWindowDelegate d;
-
- test::TestEventHandler* nonlock_ef = new test::TestEventHandler;
- test::TestEventHandler* lock_ef = new test::TestEventHandler;
- client.GetNonLockWindow()->SetEventFilter(nonlock_ef);
- client.GetLockWindow()->SetEventFilter(lock_ef);
-
- Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20),
- client.GetNonLockWindow());
- w1->set_id(1);
- Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20),
- client.GetNonLockWindow());
- w2->set_id(2);
- scoped_ptr<Window> w3(
- test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20),
- client.GetLockWindow()));
-
- w1->Focus();
- EXPECT_TRUE(IsFocusedWindow(w1));
-
- client.Lock();
-
- // Since we're locked, the attempt to focus w2 will be ignored.
- w2->Focus();
- EXPECT_TRUE(IsFocusedWindow(w1));
- EXPECT_FALSE(IsFocusedWindow(w2));
-
- {
- // Attempting to send a key event to w1 (not in the lock container) should
- // cause focus to be reset.
- test::EventGenerator generator(root_window());
- generator.PressKey(ui::VKEY_SPACE, 0);
- EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow());
- }
-
- {
- // Events sent to a window not in the lock container will not be processed.
- // i.e. never sent to the non-lock container's event filter.
- test::EventGenerator generator(root_window(), w1);
- generator.PressLeftButton();
- EXPECT_EQ(0, nonlock_ef->num_mouse_events());
-
- // Events sent to a window in the lock container will be processed.
- test::EventGenerator generator3(root_window(), w3.get());
- generator3.PressLeftButton();
- EXPECT_EQ(1, lock_ef->num_mouse_events());
- }
-
- // Prevent w3 from being deleted by the hierarchy since its delegate is owned
- // by this scope.
- w3->parent()->RemoveChild(w3.get());
-}
-
-TEST_F(RootWindowTest, IgnoreUnknownKeys) {
- test::TestEventHandler* filter = new ConsumeKeyHandler;
- root_window()->SetEventFilter(filter); // passes ownership
-
- ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false);
- EXPECT_FALSE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(
- &unknown_event));
- EXPECT_EQ(0, filter->num_key_events());
-
- ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
- EXPECT_TRUE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(
- &known_event));
- EXPECT_EQ(1, filter->num_key_events());
-}
-
-TEST_F(RootWindowTest, NoDelegateWindowReceivesKeyEvents) {
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
- w1->Show();
- w1->Focus();
-
- test::TestEventHandler handler;
- w1->AddPreTargetHandler(&handler);
- ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
- EXPECT_TRUE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(
- &key_press));
- EXPECT_EQ(1, handler.num_key_events());
-
- w1->RemovePreTargetHandler(&handler);
-}
-
-// Tests that touch-events that are beyond the bounds of the root-window do get
-// propagated to the event filters correctly with the root as the target.
-TEST_F(RootWindowTest, TouchEventsOutsideBounds) {
- test::TestEventHandler* filter = new test::TestEventHandler;
- root_window()->SetEventFilter(filter); // passes ownership
-
- gfx::Point position = root_window()->bounds().origin();
- position.Offset(-10, -10);
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
- EXPECT_EQ(1, filter->num_touch_events());
-
- position = root_window()->bounds().origin();
- position.Offset(root_window()->bounds().width() + 10,
- root_window()->bounds().height() + 10);
- ui::TouchEvent release(ui::ET_TOUCH_RELEASED, position, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
- EXPECT_EQ(2, filter->num_touch_events());
-}
-
-// Tests that scroll events are dispatched correctly.
-TEST_F(RootWindowTest, ScrollEventDispatch) {
- base::TimeDelta now = ui::EventTimeForNow();
- test::TestEventHandler* filter = new test::TestEventHandler;
- root_window()->SetEventFilter(filter);
-
- test::TestWindowDelegate delegate;
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
- w1->SetBounds(gfx::Rect(20, 20, 40, 40));
-
- // A scroll event on the root-window itself is dispatched.
- ui::ScrollEvent scroll1(ui::ET_SCROLL,
- gfx::Point(10, 10),
- now,
- 0,
- 0, -10,
- 0, -10,
- 2);
- dispatcher()->AsRootWindowHostDelegate()->OnHostScrollEvent(&scroll1);
- EXPECT_EQ(1, filter->num_scroll_events());
-
- // Scroll event on a window should be dispatched properly.
- ui::ScrollEvent scroll2(ui::ET_SCROLL,
- gfx::Point(25, 30),
- now,
- 0,
- -10, 0,
- -10, 0,
- 2);
- dispatcher()->AsRootWindowHostDelegate()->OnHostScrollEvent(&scroll2);
- EXPECT_EQ(2, filter->num_scroll_events());
-}
-
-namespace {
-
-// FilterFilter that tracks the types of events it's seen.
-class EventFilterRecorder : public ui::EventHandler {
- public:
- typedef std::vector<ui::EventType> Events;
- typedef std::vector<gfx::Point> MouseEventLocations;
-
- EventFilterRecorder() {}
-
- Events& events() { return events_; }
-
- MouseEventLocations& mouse_locations() { return mouse_locations_; }
- gfx::Point mouse_location(int i) const { return mouse_locations_[i]; }
-
-Events GetAndResetEvents() {
- Events events = events_;
- events_.clear();
- return events;
- }
-
- // ui::EventHandler overrides:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
- events_.push_back(event->type());
- }
-
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- events_.push_back(event->type());
- mouse_locations_.push_back(event->location());
- }
-
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
- events_.push_back(event->type());
- }
-
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
- events_.push_back(event->type());
- }
-
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
- events_.push_back(event->type());
- }
-
- private:
- Events events_;
- MouseEventLocations mouse_locations_;
-
- DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder);
-};
-
-// Converts an EventType to a string.
-std::string EventTypeToString(ui::EventType type) {
- switch (type) {
- case ui::ET_TOUCH_RELEASED:
- return "TOUCH_RELEASED";
-
- case ui::ET_TOUCH_CANCELLED:
- return "TOUCH_CANCELLED";
-
- case ui::ET_TOUCH_PRESSED:
- return "TOUCH_PRESSED";
-
- case ui::ET_TOUCH_MOVED:
- return "TOUCH_MOVED";
-
- case ui::ET_MOUSE_PRESSED:
- return "MOUSE_PRESSED";
-
- case ui::ET_MOUSE_DRAGGED:
- return "MOUSE_DRAGGED";
-
- case ui::ET_MOUSE_RELEASED:
- return "MOUSE_RELEASED";
-
- case ui::ET_MOUSE_MOVED:
- return "MOUSE_MOVED";
-
- case ui::ET_MOUSE_ENTERED:
- return "MOUSE_ENTERED";
-
- case ui::ET_MOUSE_EXITED:
- return "MOUSE_EXITED";
-
- case ui::ET_GESTURE_SCROLL_BEGIN:
- return "GESTURE_SCROLL_BEGIN";
-
- case ui::ET_GESTURE_SCROLL_END:
- return "GESTURE_SCROLL_END";
-
- case ui::ET_GESTURE_SCROLL_UPDATE:
- return "GESTURE_SCROLL_UPDATE";
-
- case ui::ET_GESTURE_PINCH_BEGIN:
- return "GESTURE_PINCH_BEGIN";
-
- case ui::ET_GESTURE_PINCH_END:
- return "GESTURE_PINCH_END";
-
- case ui::ET_GESTURE_PINCH_UPDATE:
- return "GESTURE_PINCH_UPDATE";
-
- case ui::ET_GESTURE_TAP:
- return "GESTURE_TAP";
-
- case ui::ET_GESTURE_TAP_DOWN:
- return "GESTURE_TAP_DOWN";
-
- case ui::ET_GESTURE_TAP_CANCEL:
- return "GESTURE_TAP_CANCEL";
-
- case ui::ET_GESTURE_SHOW_PRESS:
- return "GESTURE_SHOW_PRESS";
-
- case ui::ET_GESTURE_BEGIN:
- return "GESTURE_BEGIN";
-
- case ui::ET_GESTURE_END:
- return "GESTURE_END";
-
- default:
- // We should explicitly require each event type.
- NOTREACHED();
- break;
- }
- return "";
-}
-
-std::string EventTypesToString(const EventFilterRecorder::Events& events) {
- std::string result;
- for (size_t i = 0; i < events.size(); ++i) {
- if (i != 0)
- result += " ";
- result += EventTypeToString(events[i]);
- }
- return result;
-}
-
-} // namespace
-
-// Verifies a repost mouse event targets the window with capture (if there is
-// one).
-TEST_F(RootWindowTest, RepostTargetsCaptureWindow) {
- // Set capture on |window| generate a mouse event (that is reposted) and not
- // over |window| and verify |window| gets it (|window| gets it because it has
- // capture).
- EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
- scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL));
- window->SetBounds(gfx::Rect(20, 20, 40, 30));
- EventFilterRecorder* recorder = new EventFilterRecorder;
- window->SetEventFilter(recorder); // Takes ownership.
- window->SetCapture();
- const ui::MouseEvent press_event(
- ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- dispatcher()->RepostEvent(press_event);
- RunAllPendingInMessageLoop(); // Necessitated by RepostEvent().
- // Mouse moves/enters may be generated. We only care about a pressed.
- EXPECT_TRUE(EventTypesToString(recorder->events()).find("MOUSE_PRESSED") !=
- std::string::npos) << EventTypesToString(recorder->events());
-}
-
-TEST_F(RootWindowTest, MouseMovesHeld) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
- gfx::Point(0, 0), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_move_event);
- // Discard MOUSE_ENTER.
- filter->events().clear();
-
- dispatcher()->HoldPointerMoves();
-
- // Check that we don't immediately dispatch the MOUSE_DRAGGED event.
- ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0),
- gfx::Point(0, 0), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event);
- EXPECT_TRUE(filter->events().empty());
-
- // Check that we do dispatch the held MOUSE_DRAGGED event before another type
- // of event.
- ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
- gfx::Point(0, 0), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_pressed_event);
- EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
- EventTypesToString(filter->events()));
- filter->events().clear();
-
- // Check that we coalesce held MOUSE_DRAGGED events.
- ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1),
- gfx::Point(1, 1), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event2);
- EXPECT_TRUE(filter->events().empty());
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_pressed_event);
- EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
- EventTypesToString(filter->events()));
- filter->events().clear();
-
- // Check that on ReleasePointerMoves, held events are not dispatched
- // immediately, but posted instead.
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event);
- dispatcher()->ReleasePointerMoves();
- EXPECT_TRUE(filter->events().empty());
- RunAllPendingInMessageLoop();
- EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events()));
- filter->events().clear();
-
- // However if another message comes in before the dispatch of the posted
- // event, check that the posted event is dispatched before this new event.
- dispatcher()->HoldPointerMoves();
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event);
- dispatcher()->ReleasePointerMoves();
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_pressed_event);
- EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
- EventTypesToString(filter->events()));
- filter->events().clear();
- RunAllPendingInMessageLoop();
- EXPECT_TRUE(filter->events().empty());
-
- // Check that if the other message is another MOUSE_DRAGGED, we still coalesce
- // them.
- dispatcher()->HoldPointerMoves();
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event);
- dispatcher()->ReleasePointerMoves();
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_dragged_event2);
- EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events()));
- filter->events().clear();
- RunAllPendingInMessageLoop();
- EXPECT_TRUE(filter->events().empty());
-}
-
-TEST_F(RootWindowTest, TouchMovesHeld) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- // Starting the touch and throwing out the first few events, since the system
- // is going to generate synthetic mouse events that are not relevant to the
- // test.
- ui::TouchEvent touch_pressed_event(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
- 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
- &touch_pressed_event);
- RunAllPendingInMessageLoop();
- filter->events().clear();
-
- dispatcher()->HoldPointerMoves();
-
- // Check that we don't immediately dispatch the TOUCH_MOVED event.
- ui::TouchEvent touch_moved_event(ui::ET_TOUCH_MOVED, gfx::Point(0, 0),
- 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
- &touch_moved_event);
- EXPECT_TRUE(filter->events().empty());
-
- // Check that on ReleasePointerMoves, held events are not dispatched
- // immediately, but posted instead.
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
- &touch_moved_event);
- dispatcher()->ReleasePointerMoves();
- EXPECT_TRUE(filter->events().empty());
- RunAllPendingInMessageLoop();
- EXPECT_EQ("TOUCH_MOVED", EventTypesToString(filter->events()));
- filter->events().clear();
-
- // If another touch event occurs then the held touch should be dispatched
- // immediately before it.
- ui::TouchEvent touch_released_event(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0),
- 0, base::TimeDelta());
- filter->events().clear();
- dispatcher()->HoldPointerMoves();
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
- &touch_moved_event);
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(
- &touch_released_event);
- EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP_CANCEL GESTURE_END",
- EventTypesToString(filter->events()));
- filter->events().clear();
- dispatcher()->ReleasePointerMoves();
- RunAllPendingInMessageLoop();
- EXPECT_TRUE(filter->events().empty());
-}
-
-// Tests that synthetic mouse events are ignored when mouse
-// events are disabled.
-TEST_F(RootWindowTest, DispatchSyntheticMouseEvents) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
- window->Show();
- window->SetCapture();
-
- test::TestCursorClient cursor_client(root_window());
-
- // Dispatch a non-synthetic mouse event when mouse events are enabled.
- ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse1);
- EXPECT_FALSE(filter->events().empty());
- filter->events().clear();
-
- // Dispatch a synthetic mouse event when mouse events are enabled.
- ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse2);
- EXPECT_FALSE(filter->events().empty());
- filter->events().clear();
-
- // Dispatch a synthetic mouse event when mouse events are disabled.
- cursor_client.DisableMouseEvents();
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse2);
- EXPECT_TRUE(filter->events().empty());
-}
-
-// Tests that a mouse exit is dispatched to the last known cursor location
-// when the cursor becomes invisible.
-TEST_F(RootWindowTest, DispatchMouseExitWhenCursorHidden) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- gfx::Point window_origin(7, 18);
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1234, gfx::Rect(window_origin,
- gfx::Size(100, 100)), root_window()));
- window->Show();
-
- // Dispatch a mouse move event into the window.
- gfx::Point mouse_location(gfx::Point(15, 25));
- ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
- mouse_location, 0);
- EXPECT_TRUE(filter->events().empty());
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse1);
- EXPECT_FALSE(filter->events().empty());
- filter->events().clear();
-
- // Hide the cursor and verify a mouse exit was dispatched.
- dispatcher()->OnCursorVisibilityChanged(false);
- EXPECT_FALSE(filter->events().empty());
- EXPECT_EQ("MOUSE_EXITED", EventTypesToString(filter->events()));
-
- // Verify the mouse exit was dispatched at the correct location
- // (in the correct coordinate space).
- int translated_x = mouse_location.x() - window_origin.x();
- int translated_y = mouse_location.y() - window_origin.y();
- gfx::Point translated_point(translated_x, translated_y);
- EXPECT_EQ(filter->mouse_location(0).ToString(), translated_point.ToString());
-}
-
-class DeletingEventFilter : public ui::EventHandler {
- public:
- DeletingEventFilter()
- : delete_during_pre_handle_(false) {}
- virtual ~DeletingEventFilter() {}
-
- void Reset(bool delete_during_pre_handle) {
- delete_during_pre_handle_ = delete_during_pre_handle;
- }
-
- private:
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
- if (delete_during_pre_handle_)
- delete event->target();
- }
-
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- if (delete_during_pre_handle_)
- delete event->target();
- }
-
- bool delete_during_pre_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter);
-};
-
-class DeletingWindowDelegate : public test::TestWindowDelegate {
- public:
- DeletingWindowDelegate()
- : window_(NULL),
- delete_during_handle_(false),
- got_event_(false) {}
- virtual ~DeletingWindowDelegate() {}
-
- void Reset(Window* window, bool delete_during_handle) {
- window_ = window;
- delete_during_handle_ = delete_during_handle;
- got_event_ = false;
- }
- bool got_event() const { return got_event_; }
-
- private:
- // Overridden from WindowDelegate:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
- if (delete_during_handle_)
- delete window_;
- got_event_ = true;
- }
-
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- if (delete_during_handle_)
- delete window_;
- got_event_ = true;
- }
-
- Window* window_;
- bool delete_during_handle_;
- bool got_event_;
-
- DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate);
-};
-
-TEST_F(RootWindowTest, DeleteWindowDuringDispatch) {
- // Verifies that we can delete a window during each phase of event handling.
- // Deleting the window should not cause a crash, only prevent further
- // processing from occurring.
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
- DeletingWindowDelegate d11;
- Window* w11 = CreateNormalWindow(11, w1.get(), &d11);
- WindowTracker tracker;
- DeletingEventFilter* w1_filter = new DeletingEventFilter;
- w1->SetEventFilter(w1_filter);
- client::GetFocusClient(w1.get())->FocusWindow(w11);
-
- test::EventGenerator generator(root_window(), w11);
-
- // First up, no one deletes anything.
- tracker.Add(w11);
- d11.Reset(w11, false);
-
- generator.PressLeftButton();
- EXPECT_TRUE(tracker.Contains(w11));
- EXPECT_TRUE(d11.got_event());
- generator.ReleaseLeftButton();
-
- // Delegate deletes w11. This will prevent the post-handle step from applying.
- w1_filter->Reset(false);
- d11.Reset(w11, true);
- generator.PressKey(ui::VKEY_A, 0);
- EXPECT_FALSE(tracker.Contains(w11));
- EXPECT_TRUE(d11.got_event());
-
- // Pre-handle step deletes w11. This will prevent the delegate and the post-
- // handle steps from applying.
- w11 = CreateNormalWindow(11, w1.get(), &d11);
- w1_filter->Reset(true);
- d11.Reset(w11, false);
- generator.PressLeftButton();
- EXPECT_FALSE(tracker.Contains(w11));
- EXPECT_FALSE(d11.got_event());
-}
-
-namespace {
-
-// A window delegate that detaches the parent of the target's parent window when
-// it receives a tap event.
-class DetachesParentOnTapDelegate : public test::TestWindowDelegate {
- public:
- DetachesParentOnTapDelegate() {}
- virtual ~DetachesParentOnTapDelegate() {}
-
- private:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
- if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
- event->SetHandled();
- return;
- }
-
- if (event->type() == ui::ET_GESTURE_TAP) {
- Window* parent = static_cast<Window*>(event->target())->parent();
- parent->parent()->RemoveChild(parent);
- event->SetHandled();
- }
- }
-
- DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate);
-};
-
-} // namespace
-
-// Tests that the gesture recognizer is reset for all child windows when a
-// window hides. No expectations, just checks that the test does not crash.
-TEST_F(RootWindowTest, GestureRecognizerResetsTargetWhenParentHides) {
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
- DetachesParentOnTapDelegate delegate;
- scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL));
- Window* child = CreateNormalWindow(11, parent.get(), &delegate);
- test::EventGenerator generator(root_window(), child);
- generator.GestureTapAt(gfx::Point(40, 40));
-}
-
-namespace {
-
-// A window delegate that processes nested gestures on tap.
-class NestedGestureDelegate : public test::TestWindowDelegate {
- public:
- NestedGestureDelegate(test::EventGenerator* generator,
- const gfx::Point tap_location)
- : generator_(generator),
- tap_location_(tap_location),
- gesture_end_count_(0) {}
- virtual ~NestedGestureDelegate() {}
-
- int gesture_end_count() const { return gesture_end_count_; }
-
- private:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
- switch (event->type()) {
- case ui::ET_GESTURE_TAP_DOWN:
- event->SetHandled();
- break;
- case ui::ET_GESTURE_TAP:
- if (generator_)
- generator_->GestureTapAt(tap_location_);
- event->SetHandled();
- break;
- case ui::ET_GESTURE_END:
- ++gesture_end_count_;
- break;
- default:
- break;
- }
- }
-
- test::EventGenerator* generator_;
- const gfx::Point tap_location_;
- int gesture_end_count_;
- DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate);
-};
-
-} // namespace
-
-// Tests that gesture end is delivered after nested gesture processing.
-TEST_F(RootWindowTest, GestureEndDeliveredAfterNestedGestures) {
- NestedGestureDelegate d1(NULL, gfx::Point());
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1));
- w1->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- test::EventGenerator nested_generator(root_window(), w1.get());
- NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint());
- scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2));
- w2->SetBounds(gfx::Rect(100, 0, 100, 100));
-
- // Tap on w2 which triggers nested gestures for w1.
- test::EventGenerator generator(root_window(), w2.get());
- generator.GestureTapAt(w2->bounds().CenterPoint());
-
- // Both windows should get their gesture end events.
- EXPECT_EQ(1, d1.gesture_end_count());
- EXPECT_EQ(1, d2.gesture_end_count());
-}
-
-// Tests whether we can repost the Tap down gesture event.
-TEST_F(RootWindowTest, RepostTapdownGestureTest) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f);
- gfx::Point point(10, 10);
- ui::GestureEvent event(
- ui::ET_GESTURE_TAP_DOWN,
- point.x(),
- point.y(),
- 0,
- ui::EventTimeForNow(),
- details,
- 0);
- dispatcher()->RepostEvent(event);
- RunAllPendingInMessageLoop();
- // TODO(rbyers): Currently disabled - crbug.com/170987
- EXPECT_FALSE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") !=
- std::string::npos);
- filter->events().clear();
-}
-
-// This class inherits from the EventFilterRecorder class which provides a
-// facility to record events. This class additionally provides a facility to
-// repost the ET_GESTURE_TAP_DOWN gesture to the target window and records
-// events after that.
-class RepostGestureEventRecorder : public EventFilterRecorder {
- public:
- RepostGestureEventRecorder(aura::Window* repost_source,
- aura::Window* repost_target)
- : repost_source_(repost_source),
- repost_target_(repost_target),
- reposted_(false),
- done_cleanup_(false) {}
-
- virtual ~RepostGestureEventRecorder() {}
-
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
- if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) {
- done_cleanup_ = true;
- events().clear();
- }
- EventFilterRecorder::OnTouchEvent(event);
- }
-
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
- EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target());
- if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
- if (!reposted_) {
- EXPECT_NE(repost_target_, event->target());
- reposted_ = true;
- repost_target_->GetDispatcher()->RepostEvent(*event);
- // Ensure that the reposted gesture event above goes to the
- // repost_target_;
- repost_source_->GetRootWindow()->RemoveChild(repost_source_);
- return;
- }
- }
- EventFilterRecorder::OnGestureEvent(event);
- }
-
- // Ignore mouse events as they don't fire at all times. This causes
- // the GestureRepostEventOrder test to fail randomly.
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {}
-
- private:
- aura::Window* repost_source_;
- aura::Window* repost_target_;
- // set to true if we reposted the ET_GESTURE_TAP_DOWN event.
- bool reposted_;
- // set true if we're done cleaning up after hiding repost_source_;
- bool done_cleanup_;
- DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder);
-};
-
-// Tests whether events which are generated after the reposted gesture event
-// are received after that. In this case the scroll sequence events should
-// be received after the reposted gesture event.
-TEST_F(RootWindowTest, GestureRepostEventOrder) {
- // Expected events at the end for the repost_target window defined below.
- const char kExpectedTargetEvents[] =
- // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039.
- // "GESTURE_BEGIN GESTURE_TAP_DOWN "
- "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
- "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED "
- "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
- "GESTURE_SCROLL_END GESTURE_END";
- // We create two windows.
- // The first window (repost_source) is the one to which the initial tap
- // gesture is sent. It reposts this event to the second window
- // (repost_target).
- // We then generate the scroll sequence for repost_target and look for two
- // ET_GESTURE_TAP_DOWN events in the event list at the end.
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window()));
-
- RepostGestureEventRecorder* repost_event_recorder =
- new RepostGestureEventRecorder(repost_source.get(), repost_target.get());
- root_window()->SetEventFilter(repost_event_recorder); // passes ownership
-
- // Generate a tap down gesture for the repost_source. This will be reposted
- // to repost_target.
- test::EventGenerator repost_generator(root_window(), repost_source.get());
- repost_generator.GestureTapAt(gfx::Point(40, 40));
- RunAllPendingInMessageLoop();
-
- test::EventGenerator scroll_generator(root_window(), repost_target.get());
- scroll_generator.GestureScrollSequence(
- gfx::Point(80, 80),
- gfx::Point(100, 100),
- base::TimeDelta::FromMilliseconds(100),
- 3);
- RunAllPendingInMessageLoop();
-
- int tap_down_count = 0;
- for (size_t i = 0; i < repost_event_recorder->events().size(); ++i) {
- if (repost_event_recorder->events()[i] == ui::ET_GESTURE_TAP_DOWN)
- ++tap_down_count;
- }
-
- // We expect two tap down events. One from the repost and the other one from
- // the scroll sequence posted above.
- // TODO(rbyers): Currently disabled - crbug.com/170987
- EXPECT_EQ(1, tap_down_count);
-
- EXPECT_EQ(kExpectedTargetEvents,
- EventTypesToString(repost_event_recorder->events()));
-}
-
-class OnMouseExitDeletingEventFilter : public EventFilterRecorder {
- public:
- OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {}
- virtual ~OnMouseExitDeletingEventFilter() {}
-
- void set_window_to_delete(Window* window_to_delete) {
- window_to_delete_ = window_to_delete;
- }
-
- private:
- // Overridden from ui::EventHandler:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- EventFilterRecorder::OnMouseEvent(event);
- if (window_to_delete_) {
- delete window_to_delete_;
- window_to_delete_ = NULL;
- }
- }
-
- Window* window_to_delete_;
-
- DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter);
-};
-
-// Tests that RootWindow drops mouse-moved event that is supposed to be sent to
-// a child, but the child is destroyed because of the synthesized mouse-exit
-// event generated on the previous mouse_moved_handler_.
-TEST_F(RootWindowTest, DeleteWindowDuringMouseMovedDispatch) {
- // Create window 1 and set its event filter. Window 1 will take ownership of
- // the event filter.
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
- OnMouseExitDeletingEventFilter* w1_filter =
- new OnMouseExitDeletingEventFilter();
- w1->SetEventFilter(w1_filter);
- w1->SetBounds(gfx::Rect(20, 20, 60, 60));
- EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler());
-
- test::EventGenerator generator(root_window(), w1.get());
-
- // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the
- // root window.
- generator.MoveMouseTo(51, 51);
- EXPECT_EQ(w1.get(), dispatcher()->mouse_moved_handler());
-
- // Create window 2 under the mouse cursor and stack it above window 1.
- Window* w2 = CreateNormalWindow(2, root_window(), NULL);
- w2->SetBounds(gfx::Rect(30, 30, 40, 40));
- root_window()->StackChildAbove(w2, w1.get());
-
- // Set window 2 as the window that is to be deleted when a mouse-exited event
- // happens on window 1.
- w1_filter->set_window_to_delete(w2);
-
- // Move mosue over window 2. This should generate a mouse-exited event for
- // window 1 resulting in deletion of window 2. The original mouse-moved event
- // that was targeted to window 2 should be dropped since window 2 is
- // destroyed. This test passes if no crash happens.
- generator.MoveMouseTo(52, 52);
- EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler());
-
- // Check events received by window 1.
- EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED",
- EventTypesToString(w1_filter->events()));
-}
-
-namespace {
-
-// Used to track if OnWindowDestroying() is invoked and if there is a valid
-// RootWindow at such time.
-class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver {
- public:
- ValidRootDuringDestructionWindowObserver(bool* got_destroying,
- bool* has_valid_root)
- : got_destroying_(got_destroying),
- has_valid_root_(has_valid_root) {
- }
-
- // WindowObserver:
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- *got_destroying_ = true;
- *has_valid_root_ = (window->GetRootWindow() != NULL);
- }
-
- private:
- bool* got_destroying_;
- bool* has_valid_root_;
-
- DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver);
-};
-
-} // namespace
-
-#if defined(USE_OZONE)
-// Creating multiple RootWindowHostOzone instances is broken.
-#define MAYBE_ValidRootDuringDestruction DISABLED_ValidRootDuringDestruction
-#else
-#define MAYBE_ValidRootDuringDestruction ValidRootDuringDestruction
-#endif
-
-// Verifies GetRootWindow() from ~Window returns a valid root.
-TEST_F(RootWindowTest, MAYBE_ValidRootDuringDestruction) {
- bool got_destroying = false;
- bool has_valid_root = false;
- ValidRootDuringDestructionWindowObserver observer(&got_destroying,
- &has_valid_root);
- {
- scoped_ptr<RootWindow> root_window(
- new RootWindow(RootWindow::CreateParams(gfx::Rect(0, 0, 100, 100))));
- root_window->Init();
- // Owned by RootWindow.
- Window* w1 = CreateNormalWindow(1, root_window->window(), NULL);
- w1->AddObserver(&observer);
- }
- EXPECT_TRUE(got_destroying);
- EXPECT_TRUE(has_valid_root);
-}
-
-namespace {
-
-// See description above DontResetHeldEvent for details.
-class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {
- public:
- explicit DontResetHeldEventWindowDelegate(aura::Window* root)
- : root_(root),
- mouse_event_count_(0) {}
- virtual ~DontResetHeldEventWindowDelegate() {}
-
- int mouse_event_count() const { return mouse_event_count_; }
-
- // TestWindowDelegate:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
- mouse_event_count_++ == 0) {
- ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
- gfx::Point(10, 10), gfx::Point(10, 10),
- ui::EF_SHIFT_DOWN);
- root_->GetDispatcher()->RepostEvent(mouse_event);
- }
- }
-
- private:
- Window* root_;
- int mouse_event_count_;
-
- DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate);
-};
-
-} // namespace
-
-// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
-// dispatching. This is done by using DontResetHeldEventWindowDelegate, which
-// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
-// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
-// schedule another reposted event.
-TEST_F(RootWindowTest, DontResetHeldEvent) {
- DontResetHeldEventWindowDelegate delegate(root_window());
- scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
- RootWindowHostDelegate* root_window_delegate =
- static_cast<RootWindowHostDelegate*>(root_window()->GetDispatcher());
- w1->SetBounds(gfx::Rect(0, 0, 40, 40));
- ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
- gfx::Point(10, 10), gfx::Point(10, 10),
- ui::EF_SHIFT_DOWN);
- root_window()->GetDispatcher()->RepostEvent(pressed);
- ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED,
- gfx::Point(10, 10), gfx::Point(10, 10), 0);
- // Invoke OnHostMouseEvent() to flush event scheduled by way of RepostEvent().
- root_window_delegate->OnHostMouseEvent(&pressed2);
- // Delegate should have seen reposted event (identified by way of
- // EF_SHIFT_DOWN). Invoke OnHostMouseEvent() to flush the second
- // RepostedEvent().
- EXPECT_EQ(1, delegate.mouse_event_count());
- root_window_delegate->OnHostMouseEvent(&pressed2);
- EXPECT_EQ(2, delegate.mouse_event_count());
-}
-
-namespace {
-
-// See description above DeleteRootFromHeldMouseEvent for details.
-class DeleteRootFromHeldMouseEventDelegate : public test::TestWindowDelegate {
- public:
- explicit DeleteRootFromHeldMouseEventDelegate(aura::RootWindow* root)
- : root_(root),
- got_mouse_event_(false),
- got_destroy_(false) {
- }
- virtual ~DeleteRootFromHeldMouseEventDelegate() {}
-
- bool got_mouse_event() const { return got_mouse_event_; }
- bool got_destroy() const { return got_destroy_; }
-
- // TestWindowDelegate:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) {
- got_mouse_event_ = true;
- delete root_;
- }
- }
- virtual void OnWindowDestroyed() OVERRIDE {
- got_destroy_ = true;
- }
-
- private:
- RootWindow* root_;
- bool got_mouse_event_;
- bool got_destroy_;
-
- DISALLOW_COPY_AND_ASSIGN(DeleteRootFromHeldMouseEventDelegate);
-};
-
-} // namespace
-
-#if defined(USE_OZONE)
-// Creating multiple RootWindowHostOzone instances is broken.
-#define MAYBE_DeleteRootFromHeldMouseEvent DISABLED_DeleteRootFromHeldMouseEvent
-#else
-#define MAYBE_DeleteRootFromHeldMouseEvent DeleteRootFromHeldMouseEvent
-#endif
-
-// Verifies if a RootWindow is deleted from dispatching a held mouse event we
-// don't crash.
-TEST_F(RootWindowTest, MAYBE_DeleteRootFromHeldMouseEvent) {
- // Should be deleted by |delegate|.
- RootWindow* r2 =
- new RootWindow(RootWindow::CreateParams(gfx::Rect(0, 0, 100, 100)));
- r2->Init();
- DeleteRootFromHeldMouseEventDelegate delegate(r2);
- // Owned by |r2|.
- Window* w1 = CreateNormalWindow(1, r2->window(), &delegate);
- w1->SetBounds(gfx::Rect(0, 0, 40, 40));
- ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
- gfx::Point(10, 10), gfx::Point(10, 10),
- ui::EF_SHIFT_DOWN);
- r2->RepostEvent(pressed);
- // RunAllPendingInMessageLoop() to make sure the |pressed| is run.
- RunAllPendingInMessageLoop();
- EXPECT_TRUE(delegate.got_mouse_event());
- EXPECT_TRUE(delegate.got_destroy());
-}
-
-TEST_F(RootWindowTest, WindowHideCancelsActiveTouches) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- gfx::Point position1 = root_window()->bounds().origin();
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
-
- EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN",
- EventTypesToString(filter->GetAndResetEvents()));
-
- window->Hide();
-
- EXPECT_EQ("TOUCH_CANCELLED GESTURE_TAP_CANCEL GESTURE_END",
- EventTypesToString(filter->events()));
-}
-
-TEST_F(RootWindowTest, WindowHideCancelsActiveGestures) {
- EventFilterRecorder* filter = new EventFilterRecorder;
- root_window()->SetEventFilter(filter); // passes ownership
-
- test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
- &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
-
- gfx::Point position1 = root_window()->bounds().origin();
- gfx::Point position2 = root_window()->bounds().CenterPoint();
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
-
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
-
- ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, position1, 1, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
-
- EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
- "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
- "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN",
- EventTypesToString(filter->GetAndResetEvents()));
-
- window->Hide();
-
- EXPECT_EQ("TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED "
- "GESTURE_SCROLL_END GESTURE_END",
- EventTypesToString(filter->events()));
-}
-
-// Places two windows side by side. Presses down on one window, and starts a
-// scroll. Sets capture on the other window and ensures that the "ending" events
-// aren't sent to the window which gained capture.
-TEST_F(RootWindowTest, EndingEventDoesntRetarget) {
- scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL));
- window1->SetBounds(gfx::Rect(0, 0, 40, 40));
-
- scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL));
- window2->SetBounds(gfx::Rect(40, 0, 40, 40));
-
- EventFilterRecorder* filter1 = new EventFilterRecorder();
- window1->SetEventFilter(filter1); // passes ownership
- EventFilterRecorder* filter2 = new EventFilterRecorder();
- window2->SetEventFilter(filter2); // passes ownership
-
- gfx::Point position = window1->bounds().origin();
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
-
- gfx::Point position2 = window1->bounds().CenterPoint();
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
-
- window2->SetCapture();
-
- EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
- "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
- "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END",
- EventTypesToString(filter1->events()));
-
- EXPECT_TRUE(filter2->events().empty());
-}
-
-class ExitMessageLoopOnMousePress : public test::TestEventHandler {
- public:
- ExitMessageLoopOnMousePress() {}
- virtual ~ExitMessageLoopOnMousePress() {}
-
- protected:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- test::TestEventHandler::OnMouseEvent(event);
- if (event->type() == ui::ET_MOUSE_PRESSED)
- base::MessageLoopForUI::current()->Quit();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress);
-};
-
-class RootWindowTestWithMessageLoop : public RootWindowTest {
- public:
- RootWindowTestWithMessageLoop() {}
- virtual ~RootWindowTestWithMessageLoop() {}
-
- void RunTest() {
- // Start a nested message-loop, post an event to be dispatched, and then
- // terminate the message-loop. When the message-loop unwinds and gets back,
- // the reposted event should not have fired.
- ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10),
- gfx::Point(10, 10), ui::EF_NONE);
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&RootWindow::RepostEvent,
- base::Unretained(dispatcher()),
- mouse));
- message_loop()->PostTask(FROM_HERE,
- message_loop()->QuitClosure());
-
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop());
- base::RunLoop loop;
- loop.Run();
- EXPECT_EQ(0, handler_.num_mouse_events());
-
- // Let the current message-loop run. The event-handler will terminate the
- // message-loop when it receives the reposted event.
- }
-
- base::MessageLoop* message_loop() {
- return base::MessageLoopForUI::current();
- }
-
- protected:
- virtual void SetUp() OVERRIDE {
- RootWindowTest::SetUp();
- window_.reset(CreateNormalWindow(1, root_window(), NULL));
- window_->AddPreTargetHandler(&handler_);
- }
-
- virtual void TearDown() OVERRIDE {
- window_.reset();
- RootWindowTest::TearDown();
- }
-
- private:
- scoped_ptr<Window> window_;
- ExitMessageLoopOnMousePress handler_;
-
- DISALLOW_COPY_AND_ASSIGN(RootWindowTestWithMessageLoop);
-};
-
-TEST_F(RootWindowTestWithMessageLoop, EventRepostedInNonNestedLoop) {
- CHECK(!message_loop()->is_running());
- // Perform the test in a callback, so that it runs after the message-loop
- // starts.
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&RootWindowTestWithMessageLoop::RunTest,
- base::Unretained(this)));
- message_loop()->Run();
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/scoped_window_targeter.cc b/chromium/ui/aura/scoped_window_targeter.cc
new file mode 100644
index 00000000000..96355246245
--- /dev/null
+++ b/chromium/ui/aura/scoped_window_targeter.cc
@@ -0,0 +1,29 @@
+// 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/aura/scoped_window_targeter.h"
+
+#include "ui/aura/window.h"
+
+namespace aura {
+
+ScopedWindowTargeter::ScopedWindowTargeter(
+ Window* window,
+ scoped_ptr<ui::EventTargeter> new_targeter)
+ : window_(window),
+ old_targeter_(window->SetEventTargeter(new_targeter.Pass())) {
+}
+
+ScopedWindowTargeter::~ScopedWindowTargeter() {
+ if (window_)
+ window_->SetEventTargeter(old_targeter_.Pass());
+}
+
+void ScopedWindowTargeter::OnWindowDestroyed(Window* window) {
+ CHECK_EQ(window_, window);
+ window_ = NULL;
+ old_targeter_.reset();
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/scoped_window_targeter.h b/chromium/ui/aura/scoped_window_targeter.h
new file mode 100644
index 00000000000..f8546c57d0e
--- /dev/null
+++ b/chromium/ui/aura/scoped_window_targeter.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SCOPED_WINDOW_TARGETER_H_
+#define UI_AURA_SCOPED_WINDOW_TARGETER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+
+namespace ui {
+class EventTargeter;
+}
+
+namespace aura {
+
+class Window;
+
+// ScopedWindowTargeter is used to temporarily replace the event-targeter for a
+// window. Upon construction, it installs a new targeter on the window, and upon
+// destruction, it restores the previous event-targeter on the window.
+class AURA_EXPORT ScopedWindowTargeter : public WindowObserver {
+ public:
+ ScopedWindowTargeter(Window* window,
+ scoped_ptr<ui::EventTargeter> new_targeter);
+
+ virtual ~ScopedWindowTargeter();
+
+ ui::EventTargeter* old_targeter() {
+ return old_targeter_.get();
+ }
+
+ private:
+ // WindowObserver:
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE;
+
+ Window* window_;
+ scoped_ptr<ui::EventTargeter> old_targeter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedWindowTargeter);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_SCOPED_WINDOW_TARGETER_H_
diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc
index 4836a15aae0..35b29245800 100644
--- a/chromium/ui/aura/window.cc
+++ b/chromium/ui/aura/window.cc
@@ -10,7 +10,6 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -23,15 +22,14 @@
#include "ui/aura/client/window_stacking_client.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/events/event_target_iterator.h"
-#include "ui/gfx/animation/multi_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
@@ -41,19 +39,6 @@ namespace aura {
namespace {
-WindowLayerType UILayerTypeToWindowLayerType(ui::LayerType layer_type) {
- switch (layer_type) {
- case ui::LAYER_NOT_DRAWN:
- return WINDOW_LAYER_NOT_DRAWN;
- case ui::LAYER_TEXTURED:
- return WINDOW_LAYER_TEXTURED;
- case ui::LAYER_SOLID_COLOR:
- return WINDOW_LAYER_SOLID_COLOR;
- }
- NOTREACHED();
- return WINDOW_LAYER_NOT_DRAWN;
-}
-
ui::LayerType WindowLayerTypeToUILayerType(WindowLayerType window_layer_type) {
switch (window_layer_type) {
case WINDOW_LAYER_NONE:
@@ -176,7 +161,7 @@ class ScopedCursorHider {
explicit ScopedCursorHider(Window* window)
: window_(window),
hid_cursor_(false) {
- if (!window_->HasDispatcher())
+ if (!window_->IsRootWindow())
return;
const bool cursor_is_in_bounds = window_->GetBoundsInScreen().Contains(
Env::GetInstance()->last_mouse_location());
@@ -188,7 +173,7 @@ class ScopedCursorHider {
}
}
~ScopedCursorHider() {
- if (!window_->HasDispatcher())
+ if (!window_->IsRootWindow())
return;
// Update the device scale factor of the cursor client only when the last
@@ -213,12 +198,11 @@ class ScopedCursorHider {
};
Window::Window(WindowDelegate* delegate)
- : dispatcher_(NULL),
- type_(client::WINDOW_TYPE_UNKNOWN),
+ : host_(NULL),
+ type_(ui::wm::WINDOW_TYPE_UNKNOWN),
owned_by_parent_(true),
delegate_(delegate),
parent_(NULL),
- transient_parent_(NULL),
visible_(false),
id_(-1),
transparent_(false),
@@ -232,43 +216,46 @@ Window::Window(WindowDelegate* delegate)
}
Window::~Window() {
- // |layer_| can be NULL during tests, or if this Window is layerless.
- if (layer_)
- layer_->SuppressPaint();
+ // |layer()| can be NULL during tests, or if this Window is layerless.
+ if (layer()) {
+ if (layer()->owner() == this)
+ layer()->CompleteAllAnimations();
+ layer()->SuppressPaint();
+ }
// Let the delegate know we're in the processing of destroying.
if (delegate_)
- delegate_->OnWindowDestroying();
+ delegate_->OnWindowDestroying(this);
FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
- // Let the root know so that it can remove any references to us.
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->OnWindowDestroying(this);
+ // TODO(beng): See comment in window_event_dispatcher.h. This shouldn't be
+ // necessary but unfortunately is right now due to ordering
+ // peculiarities. WED must be notified _after_ other observers
+ // are notified of pending teardown but before the hierarchy
+ // is actually torn down.
+ WindowTreeHost* host = GetHost();
+ if (host)
+ host->dispatcher()->OnPostNotifiedWindowDestroying(this);
+
+ // The window should have already had its state cleaned up in
+ // WindowEventDispatcher::OnWindowHidden(), but there have been some crashes
+ // involving windows being destroyed without being hidden first. See
+ // crbug.com/342040. This should help us debug the issue. TODO(tdresser):
+ // remove this once we determine why we have windows that are destroyed
+ // without being hidden.
+ bool window_incorrectly_cleaned_up = CleanupGestureState();
+ CHECK(!window_incorrectly_cleaned_up);
// Then destroy the children.
RemoveOrDestroyChildren();
- // Removes ourselves from our transient parent (if it hasn't been done by the
- // RootWindow).
- if (transient_parent_)
- transient_parent_->RemoveTransientChild(this);
-
// The window needs to be removed from the parent before calling the
// WindowDestroyed callbacks of delegate and the observers.
if (parent_)
parent_->RemoveChild(this);
- // Destroy transient children, only after we've removed ourselves from our
- // parent, as destroying an active transient child may otherwise attempt to
- // refocus us.
- Windows transient_children(transient_children_);
- STLDeleteElements(&transient_children);
- DCHECK(transient_children_.empty());
-
- // Delegate and observers need to be notified after transients are deleted.
if (delegate_)
- delegate_->OnWindowDestroyed();
+ delegate_->OnWindowDestroyed(this);
ObserverListBase<WindowObserver>::Iterator iter(observers_);
WindowObserver* observer;
while ((observer = iter.GetNext())) {
@@ -288,83 +275,45 @@ Window::~Window() {
// If we have layer it will either be destroyed by |layer_owner_|'s dtor, or
// by whoever acquired it. We don't have a layer if Init() wasn't invoked or
// we are layerless.
- if (layer_) {
- layer_->set_delegate(NULL);
- layer_ = NULL;
- }
-}
-
-void Window::Init(ui::LayerType layer_type) {
- InitWithWindowLayerType(UILayerTypeToWindowLayerType(layer_type));
+ if (layer())
+ layer()->set_delegate(NULL);
+ DestroyLayer();
}
-void Window::InitWithWindowLayerType(WindowLayerType window_layer_type) {
+void Window::Init(WindowLayerType window_layer_type) {
if (window_layer_type != WINDOW_LAYER_NONE) {
- layer_ = new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type));
- layer_owner_.reset(layer_);
- layer_->SetVisible(false);
- layer_->set_delegate(this);
- UpdateLayerName(name_);
- layer_->SetFillsBoundsOpaquely(!transparent_);
+ SetLayer(new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type)));
+ layer()->SetVisible(false);
+ layer()->set_delegate(this);
+ UpdateLayerName();
+ layer()->SetFillsBoundsOpaquely(!transparent_);
}
Env::GetInstance()->NotifyWindowInitialized(this);
}
-ui::Layer* Window::RecreateLayer() {
- // Disconnect the old layer, but don't delete it.
- ui::Layer* old_layer = AcquireLayer();
- if (!old_layer)
- return NULL;
-
- old_layer->set_delegate(NULL);
-
- layer_ = new ui::Layer(old_layer->type());
- layer_owner_.reset(layer_);
- layer_->SetVisible(old_layer->visible());
- layer_->set_scale_content(old_layer->scale_content());
- layer_->set_delegate(this);
- layer_->SetMasksToBounds(old_layer->GetMasksToBounds());
-
- if (delegate_)
- delegate_->DidRecreateLayer(old_layer, layer_);
-
- UpdateLayerName(name_);
- layer_->SetFillsBoundsOpaquely(!transparent_);
- // Install new layer as a sibling of the old layer, stacked below it.
- if (old_layer->parent()) {
- old_layer->parent()->Add(layer_);
- old_layer->parent()->StackBelow(layer_, old_layer);
- }
- // Migrate all the child layers over to the new layer. Copy the list because
- // the items are removed during iteration.
- std::vector<ui::Layer*> children_copy = old_layer->children();
- for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin();
- it != children_copy.end();
- ++it) {
- ui::Layer* child = *it;
- layer_->Add(child);
- }
- return old_layer;
-}
-
-void Window::SetType(client::WindowType type) {
+void Window::SetType(ui::wm::WindowType type) {
// Cannot change type after the window is initialized.
- DCHECK(!layer_);
+ DCHECK(!layer());
type_ = type;
}
void Window::SetName(const std::string& name) {
name_ = name;
- if (layer_)
- UpdateLayerName(name_);
+ if (layer())
+ UpdateLayerName();
}
void Window::SetTransparent(bool transparent) {
transparent_ = transparent;
- if (layer_)
- layer_->SetFillsBoundsOpaquely(!transparent_);
+ if (layer())
+ layer()->SetFillsBoundsOpaquely(!transparent_);
+}
+
+void Window::SetFillsBoundsCompletely(bool fills_bounds) {
+ if (layer())
+ layer()->SetFillsBoundsCompletely(fills_bounds);
}
Window* Window::GetRootWindow() {
@@ -373,30 +322,33 @@ Window* Window::GetRootWindow() {
}
const Window* Window::GetRootWindow() const {
- return dispatcher_ ? this : parent_ ? parent_->GetRootWindow() : NULL;
+ return IsRootWindow() ? this : parent_ ? parent_->GetRootWindow() : NULL;
}
-WindowEventDispatcher* Window::GetDispatcher() {
- return const_cast<WindowEventDispatcher*>(const_cast<const Window*>(this)->
- GetDispatcher());
+WindowTreeHost* Window::GetHost() {
+ return const_cast<WindowTreeHost*>(const_cast<const Window*>(this)->
+ GetHost());
}
-const WindowEventDispatcher* Window::GetDispatcher() const {
+const WindowTreeHost* Window::GetHost() const {
const Window* root_window = GetRootWindow();
- return root_window ? root_window->dispatcher_ : NULL;
+ return root_window ? root_window->host_ : NULL;
}
void Window::Show() {
+ if (layer()) {
+ DCHECK_EQ(visible_, layer()->GetTargetVisibility());
+ // It is not allowed that a window is visible but the layers alpha is fully
+ // transparent since the window would still be considered to be active but
+ // could not be seen.
+ DCHECK(!(visible_ && layer()->GetTargetOpacity() == 0.0f));
+ }
SetVisible(true);
}
void Window::Hide() {
- for (Windows::iterator it = transient_children_.begin();
- it != transient_children_.end(); ++it) {
- (*it)->Hide();
- }
+ // RootWindow::OnVisibilityChanged will call ReleaseCapture.
SetVisible(false);
- ReleaseCapture();
}
bool Window::IsVisible() const {
@@ -407,8 +359,8 @@ bool Window::IsVisible() const {
for (const Window* window = this; window; window = window->parent()) {
if (!window->visible_)
return false;
- if (window->layer_)
- return window->layer_->IsDrawn();
+ if (window->layer())
+ return window->layer()->IsDrawn();
}
return false;
}
@@ -440,17 +392,16 @@ gfx::Rect Window::GetBoundsInScreen() const {
}
void Window::SetTransform(const gfx::Transform& transform) {
- if (!layer_) {
+ if (!layer()) {
// Transforms aren't supported on layerless windows.
NOTREACHED();
return;
}
- WindowEventDispatcher* dispatcher = GetDispatcher();
- bool contained_mouse = IsVisible() && dispatcher &&
- ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
- layer_->SetTransform(transform);
- if (dispatcher)
- dispatcher->OnWindowTransformed(this, contained_mouse);
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowTransforming(this));
+ layer()->SetTransform(transform);
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowTransformed(this));
}
void Window::SetLayoutManager(LayoutManager* layout_manager) {
@@ -467,11 +418,27 @@ void Window::SetLayoutManager(LayoutManager* layout_manager) {
layout_manager_->OnWindowAddedToLayout(*it);
}
+scoped_ptr<ui::EventTargeter>
+Window::SetEventTargeter(scoped_ptr<ui::EventTargeter> targeter) {
+ scoped_ptr<ui::EventTargeter> old_targeter = targeter_.Pass();
+ targeter_ = targeter.Pass();
+ return old_targeter.Pass();
+}
+
void Window::SetBounds(const gfx::Rect& new_bounds) {
if (parent_ && parent_->layout_manager())
parent_->layout_manager()->SetChildBounds(this, new_bounds);
- else
- SetBoundsInternal(new_bounds);
+ else {
+ // Ensure we don't go smaller than our minimum bounds.
+ gfx::Rect final_bounds(new_bounds);
+ if (delegate_) {
+ const gfx::Size& min_size = delegate_->GetMinimumSize();
+ final_bounds.set_width(std::max(min_size.width(), final_bounds.width()));
+ final_bounds.set_height(std::max(min_size.height(),
+ final_bounds.height()));
+ }
+ SetBoundsInternal(final_bounds);
+ }
}
void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen,
@@ -488,11 +455,11 @@ void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen,
}
gfx::Rect Window::GetTargetBounds() const {
- if (!layer_)
+ if (!layer())
return bounds();
- if (!parent_ || parent_->layer_)
- return layer_->GetTargetBounds();
+ if (!parent_ || parent_->layer())
+ return layer()->GetTargetBounds();
// We have a layer but our parent (who is valid) doesn't. This means the
// coordinates of the layer are relative to the first ancestor with a layer;
@@ -501,15 +468,15 @@ gfx::Rect Window::GetTargetBounds() const {
const aura::Window* ancestor_with_layer =
parent_->GetAncestorWithLayer(&offset);
if (!ancestor_with_layer)
- return layer_->GetTargetBounds();
+ return layer()->GetTargetBounds();
- gfx::Rect layer_target_bounds = layer_->GetTargetBounds();
+ gfx::Rect layer_target_bounds = layer()->GetTargetBounds();
layer_target_bounds -= offset;
return layer_target_bounds;
}
void Window::SchedulePaintInRect(const gfx::Rect& rect) {
- if (!layer_ && parent_) {
+ if (!layer() && parent_) {
// Notification of paint scheduled happens for the window with a layer.
gfx::Rect parent_rect(bounds().size());
parent_rect.Intersect(rect);
@@ -517,7 +484,7 @@ void Window::SchedulePaintInRect(const gfx::Rect& rect) {
parent_rect.Offset(bounds().origin().OffsetFromOrigin());
parent_->SchedulePaintInRect(parent_rect);
}
- } else if (layer_ && layer_->SchedulePaint(rect)) {
+ } else if (layer() && layer()->SchedulePaint(rect)) {
FOR_EACH_OBSERVER(
WindowObserver, observers_, OnWindowPaintScheduled(this, rect));
}
@@ -560,13 +527,14 @@ void Window::AddChild(Window* child) {
gfx::Vector2d offset;
aura::Window* ancestor_with_layer = GetAncestorWithLayer(&offset);
+
+ child->parent_ = this;
+
if (ancestor_with_layer) {
offset += child->bounds().OffsetFromOrigin();
child->ReparentLayers(ancestor_with_layer->layer(), offset);
}
- child->parent_ = this;
-
children_.push_back(child);
if (layout_manager_)
layout_manager_->OnWindowAddedToLayout(child);
@@ -575,7 +543,7 @@ void Window::AddChild(Window* child) {
Window* root_window = GetRootWindow();
if (root_window && old_root != root_window) {
- root_window->GetDispatcher()->OnWindowAddedToRootWindow(child);
+ root_window->GetHost()->dispatcher()->OnWindowAddedToRootWindow(child);
child->NotifyAddedToRootWindow();
}
@@ -605,28 +573,6 @@ bool Window::Contains(const Window* other) const {
return false;
}
-void Window::AddTransientChild(Window* child) {
- if (child->transient_parent_)
- child->transient_parent_->RemoveTransientChild(child);
- DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
- child) == transient_children_.end());
- transient_children_.push_back(child);
- child->transient_parent_ = this;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnAddTransientChild(this, child));
-}
-
-void Window::RemoveTransientChild(Window* child) {
- Windows::iterator i =
- std::find(transient_children_.begin(), transient_children_.end(), child);
- DCHECK(i != transient_children_.end());
- transient_children_.erase(i);
- if (child->transient_parent_ == this)
- child->transient_parent_ = NULL;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnRemoveTransientChild(this, child));
-}
-
Window* Window::GetChildById(int id) {
return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id));
}
@@ -652,53 +598,61 @@ void Window::ConvertPointToTarget(const Window* source,
if (source->GetRootWindow() != target->GetRootWindow()) {
client::ScreenPositionClient* source_client =
client::GetScreenPositionClient(source->GetRootWindow());
- source_client->ConvertPointToScreen(source, point);
+ // |source_client| can be NULL in tests.
+ if (source_client)
+ source_client->ConvertPointToScreen(source, point);
client::ScreenPositionClient* target_client =
client::GetScreenPositionClient(target->GetRootWindow());
- target_client->ConvertPointFromScreen(target, point);
- } else if ((source != target) && (!source->layer_ || !target->layer_)) {
- if (!source->layer_) {
+ // |target_client| can be NULL in tests.
+ if (target_client)
+ target_client->ConvertPointFromScreen(target, point);
+ } else if ((source != target) && (!source->layer() || !target->layer())) {
+ if (!source->layer()) {
gfx::Vector2d offset_to_layer;
source = source->GetAncestorWithLayer(&offset_to_layer);
*point += offset_to_layer;
}
- if (!target->layer_) {
+ if (!target->layer()) {
gfx::Vector2d offset_to_layer;
target = target->GetAncestorWithLayer(&offset_to_layer);
*point -= offset_to_layer;
}
- ui::Layer::ConvertPointToLayer(source->layer_, target->layer_, point);
+ ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point);
} else {
- ui::Layer::ConvertPointToLayer(source->layer_, target->layer_, point);
+ ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point);
}
}
+// static
+void Window::ConvertRectToTarget(const Window* source,
+ const Window* target,
+ gfx::Rect* rect) {
+ DCHECK(rect);
+ gfx::Point origin = rect->origin();
+ ConvertPointToTarget(source, target, &origin);
+ rect->set_origin(origin);
+}
+
void Window::MoveCursorTo(const gfx::Point& point_in_window) {
Window* root_window = GetRootWindow();
DCHECK(root_window);
gfx::Point point_in_root(point_in_window);
ConvertPointToTarget(this, root_window, &point_in_root);
- root_window->GetDispatcher()->MoveCursorTo(point_in_root);
+ root_window->GetHost()->MoveCursorTo(point_in_root);
}
gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const {
return delegate_ ? delegate_->GetCursor(point) : gfx::kNullCursor;
}
-void Window::SetEventFilter(ui::EventHandler* event_filter) {
- if (event_filter_)
- RemovePreTargetHandler(event_filter_.get());
- event_filter_.reset(event_filter);
- if (event_filter)
- AddPreTargetHandler(event_filter);
-}
-
void Window::AddObserver(WindowObserver* observer) {
+ observer->OnObservingWindow(this);
observers_.AddObserver(observer);
}
void Window::RemoveObserver(WindowObserver* observer) {
+ observer->OnUnobservingWindow(this);
observers_.RemoveObserver(observer);
}
@@ -719,28 +673,6 @@ bool Window::ContainsPoint(const gfx::Point& local_point) const {
return gfx::Rect(bounds().size()).Contains(local_point);
}
-bool Window::HitTest(const gfx::Point& local_point) {
- // Expand my bounds for hit testing (override is usually zero but it's
- // probably cheaper to do the math every time than to branch).
- gfx::Rect local_bounds(gfx::Point(), bounds().size());
- local_bounds.Inset(aura::Env::GetInstance()->is_touch_down() ?
- hit_test_bounds_override_outer_touch_ :
- hit_test_bounds_override_outer_mouse_);
-
- if (!delegate_ || !delegate_->HasHitTestMask())
- return local_bounds.Contains(local_point);
-
- gfx::Path mask;
- delegate_->GetHitTestMask(&mask);
-
- SkRegion clip_region;
- clip_region.setRect(local_bounds.x(), local_bounds.y(),
- local_bounds.width(), local_bounds.height());
- SkRegion mask_region;
- return mask_region.setPath(mask, clip_region) &&
- mask_region.contains(local_point.x(), local_point.y());
-}
-
Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) {
return GetWindowForPoint(local_point, true, true);
}
@@ -776,7 +708,7 @@ bool Window::HasFocus() const {
}
bool Window::CanFocus() const {
- if (dispatcher_)
+ if (IsRootWindow())
return IsVisible();
// NOTE: as part of focusing the window the ActivationClient may make the
@@ -795,7 +727,7 @@ bool Window::CanFocus() const {
}
bool Window::CanReceiveEvents() const {
- if (dispatcher_)
+ if (IsRootWindow())
return IsVisible();
// The client may forbid certain windows from receiving events at a given
@@ -833,8 +765,8 @@ bool Window::HasCapture() {
}
void Window::SuppressPaint() {
- if (layer_)
- layer_->SuppressPaint();
+ if (layer())
+ layer()->SuppressPaint();
}
// {Set,Get,Clear}Property are implemented in window_property.h.
@@ -850,8 +782,8 @@ void* Window::GetNativeWindowProperty(const char* key) const {
void Window::OnDeviceScaleFactorChanged(float device_scale_factor) {
ScopedCursorHider hider(this);
- if (dispatcher_)
- dispatcher_->host()->OnDeviceScaleFactorChanged(device_scale_factor);
+ if (IsRootWindow())
+ host_->OnDeviceScaleFactorChanged(device_scale_factor);
if (delegate_)
delegate_->OnDeviceScaleFactorChanged(device_scale_factor);
}
@@ -863,10 +795,10 @@ std::string Window::GetDebugInfo() const {
name().empty() ? "Unknown" : name().c_str(), id(),
bounds().x(), bounds().y(), bounds().width(), bounds().height(),
visible_ ? "WindowVisible" : "WindowHidden",
- layer_ ?
- (layer_->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") :
+ layer() ?
+ (layer()->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") :
"NoLayer",
- layer_ ? layer_->opacity() : 1.0f);
+ layer() ? layer()->opacity() : 1.0f);
}
void Window::PrintWindowHierarchy(int depth) const {
@@ -928,63 +860,65 @@ int64 Window::GetPropertyInternal(const void* key,
return iter->second.value;
}
-void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
- gfx::Rect actual_new_bounds(new_bounds);
+bool Window::HitTest(const gfx::Point& local_point) {
+ gfx::Rect local_bounds(bounds().size());
+ if (!delegate_ || !delegate_->HasHitTestMask())
+ return local_bounds.Contains(local_point);
- // Ensure we don't go smaller than our minimum bounds.
- if (delegate_) {
- const gfx::Size& min_size = delegate_->GetMinimumSize();
- actual_new_bounds.set_width(
- std::max(min_size.width(), actual_new_bounds.width()));
- actual_new_bounds.set_height(
- std::max(min_size.height(), actual_new_bounds.height()));
- }
+ gfx::Path mask;
+ delegate_->GetHitTestMask(&mask);
+ SkRegion clip_region;
+ clip_region.setRect(local_bounds.x(), local_bounds.y(),
+ local_bounds.width(), local_bounds.height());
+ SkRegion mask_region;
+ return mask_region.setPath(mask, clip_region) &&
+ mask_region.contains(local_point.x(), local_point.y());
+}
+
+void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
+ gfx::Rect actual_new_bounds(new_bounds);
gfx::Rect old_bounds = GetTargetBounds();
// Always need to set the layer's bounds -- even if it is to the same thing.
// This may cause important side effects such as stopping animation.
- if (!layer_) {
+ if (!layer()) {
const gfx::Vector2d origin_delta = new_bounds.OffsetFromOrigin() -
bounds_.OffsetFromOrigin();
bounds_ = new_bounds;
OffsetLayerBounds(origin_delta);
} else {
- if (parent_ && !parent_->layer_) {
+ if (parent_ && !parent_->layer()) {
gfx::Vector2d offset;
const aura::Window* ancestor_with_layer =
parent_->GetAncestorWithLayer(&offset);
if (ancestor_with_layer)
actual_new_bounds.Offset(offset);
}
- layer_->SetBounds(actual_new_bounds);
+ layer()->SetBounds(actual_new_bounds);
}
// If we are currently not the layer's delegate, we will not get bounds
// changed notification from the layer (this typically happens after animating
// hidden). We must notify ourselves.
- if (!layer_ || layer_->delegate() != this)
- OnWindowBoundsChanged(old_bounds, ContainsMouse());
+ if (!layer() || layer()->delegate() != this)
+ OnWindowBoundsChanged(old_bounds);
}
void Window::SetVisible(bool visible) {
- if ((layer_ && visible == layer_->GetTargetVisibility()) ||
- (!layer_ && visible == visible_))
+ if ((layer() && visible == layer()->GetTargetVisibility()) ||
+ (!layer() && visible == visible_))
return; // No change.
FOR_EACH_OBSERVER(WindowObserver, observers_,
OnWindowVisibilityChanging(this, visible));
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->DispatchMouseExitToHidingWindow(this);
-
client::VisibilityClient* visibility_client =
client::GetVisibilityClient(this);
if (visibility_client)
visibility_client->UpdateLayerVisibility(this, visible);
- else if (layer_)
- layer_->SetVisible(visible);
+ else if (layer())
+ layer()->SetVisible(visible);
visible_ = visible;
SchedulePaint();
if (parent_ && parent_->layout_manager_)
@@ -994,9 +928,6 @@ void Window::SetVisible(bool visible) {
delegate_->OnWindowTargetVisibilityChanged(visible);
NotifyWindowVisibilityChanged(this, visible);
-
- if (dispatcher)
- dispatcher->OnWindowVisibilityChanged(this, visible);
}
void Window::SchedulePaint() {
@@ -1012,9 +943,10 @@ void Window::Paint(gfx::Canvas* canvas) {
void Window::PaintLayerlessChildren(gfx::Canvas* canvas) {
for (size_t i = 0, count = children_.size(); i < count; ++i) {
Window* child = children_[i];
- if (!child->layer_ && child->visible_) {
+ if (!child->layer() && child->visible_) {
gfx::ScopedCanvas scoped_canvas(canvas);
- if (canvas->ClipRect(child->bounds())) {
+ canvas->ClipRect(child->bounds());
+ if (!canvas->IsClipEmpty()) {
canvas->Translate(child->bounds().OffsetFromOrigin());
child->Paint(canvas);
}
@@ -1083,15 +1015,12 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) {
FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child));
Window* root_window = child->GetRootWindow();
Window* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL;
- if (root_window && root_window != new_root_window) {
- root_window->GetDispatcher()->OnWindowRemovedFromRootWindow(
- child, new_root_window);
- child->NotifyRemovingFromRootWindow();
- }
+ if (root_window && root_window != new_root_window)
+ child->NotifyRemovingFromRootWindow(new_root_window);
gfx::Vector2d offset;
GetAncestorWithLayer(&offset);
- child->UnparentLayers(!layer_, offset);
+ child->UnparentLayers(!layer(), offset);
child->parent_ = NULL;
Windows::iterator i = std::find(children_.begin(), children_.end(), child);
DCHECK(i != children_.end());
@@ -1103,7 +1032,7 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) {
void Window::UnparentLayers(bool has_layerless_ancestor,
const gfx::Vector2d& offset) {
- if (!layer_) {
+ if (!layer()) {
const gfx::Vector2d new_offset = offset + bounds().OffsetFromOrigin();
for (size_t i = 0; i < children_.size(); ++i) {
children_[i]->UnparentLayers(true, new_offset);
@@ -1112,14 +1041,14 @@ void Window::UnparentLayers(bool has_layerless_ancestor,
// Only remove the layer if we still own it. Someone else may have acquired
// ownership of it via AcquireLayer() and may expect the hierarchy to go
// unchanged as the Window is destroyed.
- if (layer_owner_) {
- if (layer_->parent())
- layer_->parent()->Remove(layer_);
+ if (OwnsLayer()) {
+ if (layer()->parent())
+ layer()->parent()->Remove(layer());
if (has_layerless_ancestor) {
const gfx::Rect real_bounds(bounds_);
- gfx::Rect layer_bounds(layer_->bounds());
+ gfx::Rect layer_bounds(layer()->bounds());
layer_bounds.Offset(-offset);
- layer_->SetBounds(layer_bounds);
+ layer()->SetBounds(layer_bounds);
bounds_ = real_bounds;
}
}
@@ -1128,7 +1057,7 @@ void Window::UnparentLayers(bool has_layerless_ancestor,
void Window::ReparentLayers(ui::Layer* parent_layer,
const gfx::Vector2d& offset) {
- if (!layer_) {
+ if (!layer()) {
for (size_t i = 0; i < children_.size(); ++i) {
children_[i]->ReparentLayers(
parent_layer,
@@ -1136,22 +1065,22 @@ void Window::ReparentLayers(ui::Layer* parent_layer,
}
} else {
const gfx::Rect real_bounds(bounds());
- parent_layer->Add(layer_);
- gfx::Rect layer_bounds(layer_->bounds().size());
+ parent_layer->Add(layer());
+ gfx::Rect layer_bounds(layer()->bounds().size());
layer_bounds += offset;
- layer_->SetBounds(layer_bounds);
+ layer()->SetBounds(layer_bounds);
bounds_ = real_bounds;
}
}
void Window::OffsetLayerBounds(const gfx::Vector2d& offset) {
- if (!layer_) {
+ if (!layer()) {
for (size_t i = 0; i < children_.size(); ++i)
children_[i]->OffsetLayerBounds(offset);
} else {
- gfx::Rect layer_bounds(layer_->bounds());
+ gfx::Rect layer_bounds(layer()->bounds());
layer_bounds += offset;
- layer_->SetBounds(layer_bounds);
+ layer()->SetBounds(layer_bounds);
}
}
@@ -1160,34 +1089,6 @@ void Window::OnParentChanged() {
WindowObserver, observers_, OnWindowParentChanged(this, parent_));
}
-bool Window::HasTransientAncestor(const Window* ancestor) const {
- if (transient_parent_ == ancestor)
- return true;
- return transient_parent_ ?
- transient_parent_->HasTransientAncestor(ancestor) : false;
-}
-
-void Window::SkipNullDelegatesForStacking(StackDirection direction,
- Window** target) const {
- DCHECK_EQ(this, (*target)->parent());
- size_t target_i =
- std::find(children_.begin(), children_.end(), *target) -
- children_.begin();
-
- // By convention we don't stack on top of windows with layers with NULL
- // delegates. Walk backward to find a valid target window.
- // See tests WindowTest.StackingMadrigal and StackOverClosingTransient
- // for an explanation of this.
- while (target_i > 0) {
- const size_t index = direction == STACK_ABOVE ? target_i : target_i - 1;
- if (!children_[index]->layer_ ||
- children_[index]->layer_->delegate() != NULL)
- break;
- --target_i;
- }
- *target = children_[target_i];
-}
-
void Window::StackChildRelativeTo(Window* child,
Window* target,
StackDirection direction) {
@@ -1199,47 +1100,10 @@ void Window::StackChildRelativeTo(Window* child,
client::WindowStackingClient* stacking_client =
client::GetWindowStackingClient();
- if (stacking_client)
- stacking_client->AdjustStacking(&child, &target, &direction);
-
- SkipNullDelegatesForStacking(direction, &target);
-
- // If we couldn't find a valid target position, don't move anything.
- if (direction == STACK_ABOVE &&
- (target->layer_ && target->layer_->delegate() == NULL))
+ if (stacking_client &&
+ !stacking_client->AdjustStacking(&child, &target, &direction))
return;
- // Don't try to stack a child above itself.
- if (child == target)
- return;
-
- // Move the child.
- StackChildRelativeToImpl(child, target, direction);
-
- // Stack any transient children that share the same parent to be in front of
- // 'child'. Preserve the existing stacking order by iterating in the order
- // those children appear in children_ array.
- Window* last_transient = child;
- Windows children(children_);
- for (Windows::iterator it = children.begin(); it != children.end(); ++it) {
- Window* transient_child = *it;
- if (transient_child != last_transient &&
- transient_child->HasTransientAncestor(child)) {
- StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE);
- last_transient = transient_child;
- }
- }
-}
-
-void Window::StackChildRelativeToImpl(Window* child,
- Window* target,
- StackDirection direction) {
- DCHECK_NE(child, target);
- DCHECK(child);
- DCHECK(target);
- DCHECK_EQ(this, child->parent());
- DCHECK_EQ(this, target->parent());
-
const size_t child_i =
std::find(children_.begin(), children_.end(), child) - children_.begin();
const size_t target_i =
@@ -1271,11 +1135,11 @@ void Window::StackChildLayerRelativeTo(Window* child,
if (!ancestor_layer)
return;
- if (child->layer_ && target->layer_) {
+ if (child->layer() && target->layer()) {
if (direction == STACK_ABOVE)
- ancestor_layer->StackAbove(child->layer_, target->layer_);
+ ancestor_layer->StackAbove(child->layer(), target->layer());
else
- ancestor_layer->StackBelow(child->layer_, target->layer_);
+ ancestor_layer->StackBelow(child->layer(), target->layer());
return;
}
typedef std::vector<ui::Layer*> Layers;
@@ -1295,8 +1159,8 @@ void Window::StackChildLayerRelativeTo(Window* child,
if (!target_layer) {
if (direction == STACK_ABOVE) {
- for (Layers::const_reverse_iterator i = layers.rbegin();
- i != layers.rend(); ++i) {
+ for (Layers::const_reverse_iterator i = layers.rbegin(),
+ rend = layers.rend(); i != rend; ++i) {
ancestor_layer->StackAtBottom(*i);
}
} else {
@@ -1307,8 +1171,8 @@ void Window::StackChildLayerRelativeTo(Window* child,
}
if (direction == STACK_ABOVE) {
- for (Layers::const_reverse_iterator i = layers.rbegin();
- i != layers.rend(); ++i) {
+ for (Layers::const_reverse_iterator i = layers.rbegin(),
+ rend = layers.rend(); i != rend; ++i) {
ancestor_layer->StackAbove(*i, target_layer);
}
} else {
@@ -1321,12 +1185,12 @@ void Window::OnStackingChanged() {
FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowStackingChanged(this));
}
-void Window::NotifyRemovingFromRootWindow() {
+void Window::NotifyRemovingFromRootWindow(Window* new_root) {
FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowRemovingFromRootWindow(this));
+ OnWindowRemovingFromRootWindow(this, new_root));
for (Window::Windows::const_iterator it = children_.begin();
it != children_.end(); ++it) {
- (*it)->NotifyRemovingFromRootWindow();
+ (*it)->NotifyRemovingFromRootWindow(new_root);
}
}
@@ -1443,11 +1307,10 @@ void Window::NotifyWindowVisibilityChangedUp(aura::Window* target,
}
}
-void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds,
- bool contained_mouse) {
- if (layer_) {
- bounds_ = layer_->bounds();
- if (parent_ && !parent_->layer_) {
+void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds) {
+ if (layer()) {
+ bounds_ = layer()->bounds();
+ if (parent_ && !parent_->layer()) {
gfx::Vector2d offset;
aura::Window* ancestor_with_layer =
parent_->GetAncestorWithLayer(&offset);
@@ -1463,9 +1326,19 @@ void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds,
FOR_EACH_OBSERVER(WindowObserver,
observers_,
OnWindowBoundsChanged(this, old_bounds, bounds()));
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->OnWindowBoundsChanged(this, contained_mouse);
+}
+
+bool Window::CleanupGestureState() {
+ bool state_modified = false;
+ state_modified |= ui::GestureRecognizer::Get()->CancelActiveTouches(this);
+ state_modified |=
+ ui::GestureRecognizer::Get()->CleanupStateForConsumer(this);
+ for (Window::Windows::iterator iter = children_.begin();
+ iter != children_.end();
+ ++iter) {
+ state_modified |= (*iter)->CleanupGestureState();
+ }
+ return state_modified;
}
void Window::OnPaintLayer(gfx::Canvas* canvas) {
@@ -1474,7 +1347,7 @@ void Window::OnPaintLayer(gfx::Canvas* canvas) {
base::Closure Window::PrepareForLayerBoundsChange() {
return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this),
- bounds(), ContainsMouse());
+ bounds());
}
bool Window::CanAcceptEvent(const ui::Event& event) {
@@ -1498,13 +1371,14 @@ bool Window::CanAcceptEvent(const ui::Event& event) {
return true;
// For located events (i.e. mouse, touch etc.), an assumption is made that
- // windows that don't have a delegate cannot process the event (see more in
- // GetWindowForPoint()). This assumption is not made for key events.
- return event.IsKeyEvent() || delegate_;
+ // windows that don't have a default event-handler cannot process the event
+ // (see more in GetWindowForPoint()). This assumption is not made for key
+ // events.
+ return event.IsKeyEvent() || target_handler();
}
ui::EventTarget* Window::GetParentTarget() {
- if (dispatcher_) {
+ if (IsRootWindow()) {
return client::GetEventClient(this) ?
client::GetEventClient(this)->GetToplevelEventTarget() :
Env::GetInstance();
@@ -1527,9 +1401,9 @@ void Window::ConvertEventToTarget(ui::EventTarget* target,
static_cast<Window*>(target));
}
-void Window::UpdateLayerName(const std::string& name) {
+void Window::UpdateLayerName() {
#if !defined(NDEBUG)
- DCHECK(layer_);
+ DCHECK(layer());
std::string layer_name(name_);
if (layer_name.empty())
@@ -1538,23 +1412,23 @@ void Window::UpdateLayerName(const std::string& name) {
if (id_ != -1)
layer_name += " " + base::IntToString(id_);
- layer_->set_name(layer_name);
+ layer()->set_name(layer_name);
#endif
}
bool Window::ContainsMouse() {
bool contains_mouse = false;
if (IsVisible()) {
- WindowEventDispatcher* dispatcher = GetDispatcher();
- contains_mouse = dispatcher &&
- ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
+ WindowTreeHost* host = GetHost();
+ contains_mouse = host &&
+ ContainsPointInRoot(host->dispatcher()->GetLastMouseLocationInRoot());
}
return contains_mouse;
}
const Window* Window::GetAncestorWithLayer(gfx::Vector2d* offset) const {
for (const aura::Window* window = this; window; window = window->parent()) {
- if (window->layer_)
+ if (window->layer())
return window;
if (offset)
*offset += window->bounds().OffsetFromOrigin();
diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h
index d69d88e0089..bc970f4a1f5 100644
--- a/chromium/ui/aura/window.h
+++ b/chromium/ui/aura/window.h
@@ -15,13 +15,11 @@
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "ui/aura/aura_export.h"
-#include "ui/aura/client/window_types.h"
#include "ui/aura/window_layer_type.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
-#include "ui/compositor/layer_type.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_target.h"
#include "ui/events/event_targeter.h"
@@ -29,6 +27,7 @@
#include "ui/gfx/insets.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
+#include "ui/wm/public/window_types.h"
namespace gfx {
class Display;
@@ -45,12 +44,9 @@ class Texture;
namespace aura {
class LayoutManager;
-class RootWindow;
class WindowDelegate;
class WindowObserver;
-
-// TODO(beng): remove once RootWindow is renamed.
-typedef RootWindow WindowEventDispatcher;
+class WindowTreeHost;
// Defined in window_property.h (which we do not include)
template<typename T>
@@ -80,17 +76,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
virtual ~Window();
// Initializes the window. This creates the window's layer.
- void Init(ui::LayerType layer_type);
-
- // TODO(sky): replace other Init() with this once m32 is more baked.
- void InitWithWindowLayerType(WindowLayerType layer_type);
-
- // Creates a new layer for the window. Erases the layer-owned bounds, so the
- // caller may wish to set new bounds and other state on the window/layer.
- // Returns the old layer, which can be used for animations. Caller owns the
- // memory for the returned layer and must delete it when animation completes.
- // Returns NULL and does not recreate layer if window does not own its layer.
- ui::Layer* RecreateLayer() WARN_UNUSED_RESULT;
+ void Init(WindowLayerType layer_type);
void set_owned_by_parent(bool owned_by_parent) {
owned_by_parent_ = owned_by_parent;
@@ -100,8 +86,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// A type is used to identify a class of Windows and customize behavior such
// as event handling and parenting. This field should only be consumed by the
// shell -- Aura itself shouldn't contain type-specific logic.
- client::WindowType type() const { return type_; }
- void SetType(client::WindowType type);
+ ui::wm::WindowType type() const { return type_; }
+ void SetType(ui::wm::WindowType type);
int id() const { return id_; }
void set_id(int id) { id_ = id; }
@@ -115,6 +101,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
bool transparent() const { return transparent_; }
void SetTransparent(bool transparent);
+ // See description in Layer::SetFillsBoundsCompletely.
+ void SetFillsBoundsCompletely(bool fills_bounds);
+
WindowDelegate* delegate() { return delegate_; }
const WindowDelegate* delegate() const { return delegate_; }
@@ -127,15 +116,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// defined as the Window that has a dispatcher. These functions return NULL if
// the Window is contained in a hierarchy that does not have a dispatcher at
// its root.
- virtual Window* GetRootWindow();
- virtual const Window* GetRootWindow() const;
+ Window* GetRootWindow();
+ const Window* GetRootWindow() const;
- WindowEventDispatcher* GetDispatcher();
- const WindowEventDispatcher* GetDispatcher() const;
- void set_dispatcher(WindowEventDispatcher* dispatcher) {
- dispatcher_ = dispatcher;
- }
- bool HasDispatcher() const { return !!dispatcher_; }
+ WindowTreeHost* GetHost();
+ const WindowTreeHost* GetHost() const;
+ void set_host(WindowTreeHost* host) { host_ = host; }
+ bool IsRootWindow() const { return !!host_; }
// The Window does not own this object.
void set_user_data(void* user_data) { user_data_ = user_data; }
@@ -160,16 +147,17 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// |aura::client::ScreenPositionClient| interface.
gfx::Rect GetBoundsInScreen() const;
- virtual void SetTransform(const gfx::Transform& transform);
+ void SetTransform(const gfx::Transform& transform);
// Assigns a LayoutManager to size and place child windows.
// The Window takes ownership of the LayoutManager.
void SetLayoutManager(LayoutManager* layout_manager);
LayoutManager* layout_manager() { return layout_manager_.get(); }
- void set_event_targeter(scoped_ptr<ui::EventTargeter> targeter) {
- targeter_ = targeter.Pass();
- }
+ // Sets a new event-targeter for the window, and returns the previous
+ // event-targeter.
+ scoped_ptr<ui::EventTargeter> SetEventTargeter(
+ scoped_ptr<ui::EventTargeter> targeter);
// Changes the bounds of the window. If present, the window's parent's
// LayoutManager may adjust the bounds.
@@ -211,22 +199,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Returns true if this Window contains |other| somewhere in its children.
bool Contains(const Window* other) const;
- // Adds or removes |child| as a transient child of this window. Transient
- // children get the following behavior:
- // . The transient parent destroys any transient children when it is
- // destroyed. This means a transient child is destroyed if either its parent
- // or transient parent is destroyed.
- // . If a transient child and its transient parent share the same parent, then
- // transient children are always ordered above the transient parent.
- // Transient windows are typically used for popups and menus.
- void AddTransientChild(Window* child);
- void RemoveTransientChild(Window* child);
-
- const Windows& transient_children() const { return transient_children_; }
-
- Window* transient_parent() { return transient_parent_; }
- const Window* transient_parent() const { return transient_parent_; }
-
// Retrieves the first-level child with the specified id, or NULL if no first-
// level child is found matching |id|.
Window* GetChildById(int id);
@@ -238,19 +210,16 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
static void ConvertPointToTarget(const Window* source,
const Window* target,
gfx::Point* point);
+ static void ConvertRectToTarget(const Window* source,
+ const Window* target,
+ gfx::Rect* rect);
// Moves the cursor to the specified location relative to the window.
- virtual void MoveCursorTo(const gfx::Point& point_in_window);
+ void MoveCursorTo(const gfx::Point& point_in_window);
// Returns the cursor for the specified point, in window coordinates.
gfx::NativeCursor GetCursor(const gfx::Point& point) const;
- // Sets an 'event filter' for the window. An 'event filter' for a Window is
- // a pre-target event handler, where the window owns the handler. A window
- // can have only one such event filter. Setting a new filter removes and
- // destroys any previously installed filter.
- void SetEventFilter(ui::EventHandler* event_filter);
-
// Add/remove observer.
void AddObserver(WindowObserver* observer);
void RemoveObserver(WindowObserver* observer);
@@ -259,24 +228,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
void set_ignore_events(bool ignore_events) { ignore_events_ = ignore_events; }
bool ignore_events() const { return ignore_events_; }
- // Sets the window to grab hits for mouse and touch to an area extending
- // -|mouse_insets| and -|touch_insets| pixels outside its bounds. This can be
- // used to create an invisible non-client area, for example if your windows
- // have no visible frames but still need to have resize edges.
- void SetHitTestBoundsOverrideOuter(const gfx::Insets& mouse_insets,
- const gfx::Insets& touch_insets) {
- hit_test_bounds_override_outer_mouse_ = mouse_insets;
- hit_test_bounds_override_outer_touch_ = touch_insets;
- }
-
- gfx::Insets hit_test_bounds_override_outer_touch() const {
- return hit_test_bounds_override_outer_touch_;
- }
-
- gfx::Insets hit_test_bounds_override_outer_mouse() const {
- return hit_test_bounds_override_outer_mouse_;
- }
-
// Sets the window to grab hits for an area extending |insets| pixels inside
// its bounds (even if that inner region overlaps a child window). This can be
// used to create an invisible non-client area that overlaps the client area.
@@ -296,13 +247,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// within this Window's bounds.
bool ContainsPoint(const gfx::Point& local_point) const;
- // Returns true if the mouse pointer at relative-to-this-Window's-origin
- // |local_point| can trigger an event for this Window.
- // TODO(beng): A Window can supply a hit-test mask to cause some portions of
- // itself to not trigger events, causing the events to fall through to the
- // Window behind.
- bool HitTest(const gfx::Point& local_point);
-
// Returns the Window that most closely encloses |local_point| for the
// purposes of event targeting.
Window* GetEventHandlerForPoint(const gfx::Point& local_point);
@@ -322,10 +266,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
bool HasFocus() const;
// Returns true if the Window can be focused.
- virtual bool CanFocus() const;
+ bool CanFocus() const;
// Returns true if the Window can receive events.
- virtual bool CanReceiveEvents() const;
+ bool CanReceiveEvents() const;
// Does a capture on the window. This does nothing if the window isn't showing
// (VISIBILITY_SHOWN) or isn't contained in a valid window hierarchy.
@@ -376,6 +320,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
void PrintWindowHierarchy(int depth) const;
#endif
+ // Returns true if there was state needing to be cleaned up.
+ bool CleanupGestureState();
+
protected:
// Deletes (or removes if not owned by parent) all child windows. Intended for
// use from the destructor.
@@ -384,7 +331,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
private:
friend class test::WindowTestApi;
friend class LayoutManager;
- friend class RootWindow;
friend class WindowTargeter;
// Called by the public {Set,Get,Clear}Property functions.
@@ -395,6 +341,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
int64 default_value);
int64 GetPropertyInternal(const void* key, int64 default_value) const;
+ // Returns true if the mouse pointer at relative-to-this-Window's-origin
+ // |local_point| can trigger an event for this Window.
+ // TODO(beng): A Window can supply a hit-test mask to cause some portions of
+ // itself to not trigger events, causing the events to fall through to the
+ // Window behind.
+ bool HitTest(const gfx::Point& local_point);
+
// Changes the bounds of the window without condition.
void SetBoundsInternal(const gfx::Rect& new_bounds);
@@ -445,26 +398,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Called when this window's parent has changed.
void OnParentChanged();
- // Returns true when |ancestor| is a transient ancestor of |this|.
- bool HasTransientAncestor(const Window* ancestor) const;
-
- // Adjusts |target| so that we don't attempt to stack on top of a window with
- // a NULL delegate. See implementation for details.
- void SkipNullDelegatesForStacking(StackDirection direction,
- Window** target) const;
-
- // Determines the real location for stacking |child| and invokes
- // StackChildRelativeToImpl().
+ // The various stacking functions call into this to do the actual stacking.
void StackChildRelativeTo(Window* child,
Window* target,
StackDirection direction);
- // Implementation of StackChildRelativeTo().
- void StackChildRelativeToImpl(Window* child,
- Window* target,
- StackDirection direction);
-
- // Invoked from StackChildRelativeToImpl() to stack the layers appropriately
+ // Invoked from StackChildRelativeTo() to stack the layers appropriately
// when stacking |child| relative to |target|.
void StackChildLayerRelativeTo(Window* child,
Window* target,
@@ -475,7 +414,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Notifies observers registered with this Window (and its subtree) when the
// Window has been added or is about to be removed from a RootWindow.
- void NotifyRemovingFromRootWindow();
+ void NotifyRemovingFromRootWindow(Window* new_root);
void NotifyAddedToRootWindow();
// Methods implementing hierarchy change notifications. See WindowObserver for
@@ -508,10 +447,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Invoked when the bounds of the window changes. This may be invoked directly
// by us, or from the closure returned by PrepareForLayerBoundsChange() after
- // the bounds of the layer has changed. |old_bounds| is the previous bounds,
- // and |contained_mouse| is true if the mouse was previously within the
- // window's bounds.
- void OnWindowBoundsChanged(const gfx::Rect& old_bounds, bool contained_mouse);
+ // the bounds of the layer has changed. |old_bounds| is the previous bounds.
+ void OnWindowBoundsChanged(const gfx::Rect& old_bounds);
// Overridden from ui::LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
@@ -525,8 +462,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
virtual void ConvertEventToTarget(ui::EventTarget* target,
ui::LocatedEvent* event) OVERRIDE;
- // Updates the layer name with a name based on the window's name and id.
- void UpdateLayerName(const std::string& name);
+ // Updates the layer name based on the window's name and id.
+ void UpdateLayerName();
// Returns true if the mouse is currently within our bounds.
bool ContainsMouse();
@@ -546,9 +483,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// is relative to the parent Window.
gfx::Rect bounds_;
- WindowEventDispatcher* dispatcher_;
+ WindowTreeHost* host_;
- client::WindowType type_;
+ ui::wm::WindowType type_;
// True if the Window is owned by its parent - i.e. it will be deleted by its
// parent during its parents destruction. True is the default.
@@ -562,11 +499,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Child windows. Topmost is last.
Windows children_;
- // Transient windows.
- Windows transient_children_;
-
- Window* transient_parent_;
-
// The visibility state of the window as set by Show()/Hide(). This may differ
// from the visibility of the underlying layer, which may remain visible after
// the window is hidden (e.g. to animate its disappearance).
@@ -580,7 +512,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Whether layer is initialized as non-opaque.
bool transparent_;
- scoped_ptr<ui::EventHandler> event_filter_;
scoped_ptr<LayoutManager> layout_manager_;
scoped_ptr<ui::EventTargeter> targeter_;
@@ -589,9 +520,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Makes the window pass all events through to any windows behind it.
bool ignore_events_;
- // See set_hit_test_outer_override().
- gfx::Insets hit_test_bounds_override_outer_mouse_;
- gfx::Insets hit_test_bounds_override_outer_touch_;
+ // See set_hit_test_bounds_override_inner().
gfx::Insets hit_test_bounds_override_inner_;
ObserverList<WindowObserver, true> observers_;
diff --git a/chromium/ui/aura/window_delegate.h b/chromium/ui/aura/window_delegate.h
index ff941ef95b3..90e978a39c2 100644
--- a/chromium/ui/aura/window_delegate.h
+++ b/chromium/ui/aura/window_delegate.h
@@ -73,13 +73,17 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler {
// Called from Window's destructor before OnWindowDestroyed and before the
// children have been destroyed and the window has been removed from its
// parent.
- virtual void OnWindowDestroying() = 0;
+ // This method takes the window because the delegate implementation may no
+ // longer have a route back to the window by the time this method is called.
+ virtual void OnWindowDestroying(Window* window) = 0;
// Called when the Window has been destroyed (i.e. from its destructor). This
// is called after OnWindowDestroying and after the children have been
// deleted and the window has been removed from its parent.
// The delegate can use this as an opportunity to delete itself if necessary.
- virtual void OnWindowDestroyed() = 0;
+ // This method takes the window because the delegate implementation may no
+ // longer have a route back to the window by the time this method is called.
+ virtual void OnWindowDestroyed(Window* window) = 0;
// Called when the TargetVisibility() of a Window changes. |visible|
// corresponds to the target visibility of the window. See
@@ -96,13 +100,6 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler {
// above returns true.
virtual void GetHitTestMask(gfx::Path* mask) const = 0;
- // Called from RecreateLayer() after the new layer was created. old_layer is
- // the layer that will be returned to the caller of RecreateLayer, new_layer
- // will be the layer now used on the Window. The implementation only has to do
- // anything if the layer has external content (SetExternalTexture /
- // SetTextureMailbox / SetDelegatedFrame was called).
- virtual void DidRecreateLayer(ui::Layer* old_layer, ui::Layer* new_layer) = 0;
-
protected:
virtual ~WindowDelegate() {}
};
diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc
new file mode 100644
index 00000000000..87d25b1cfd8
--- /dev/null
+++ b/chromium/ui/aura/window_event_dispatcher.cc
@@ -0,0 +1,861 @@
+// 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/aura/window_event_dispatcher.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/event_client.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_targeter.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/hit_test.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_types.h"
+
+typedef ui::EventDispatchDetails DispatchDetails;
+
+namespace aura {
+
+namespace {
+
+// Returns true if |target| has a non-client (frame) component at |location|,
+// in window coordinates.
+bool IsNonClientLocation(Window* target, const gfx::Point& location) {
+ if (!target->delegate())
+ return false;
+ int hit_test_code = target->delegate()->GetNonClientComponent(location);
+ return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE;
+}
+
+Window* ConsumerToWindow(ui::GestureConsumer* consumer) {
+ return consumer ? static_cast<Window*>(consumer) : NULL;
+}
+
+void SetLastMouseLocation(const Window* root_window,
+ const gfx::Point& location_in_root) {
+ client::ScreenPositionClient* client =
+ client::GetScreenPositionClient(root_window);
+ if (client) {
+ gfx::Point location_in_screen = location_in_root;
+ client->ConvertPointToScreen(root_window, &location_in_screen);
+ Env::GetInstance()->set_last_mouse_location(location_in_screen);
+ } else {
+ Env::GetInstance()->set_last_mouse_location(location_in_root);
+ }
+}
+
+bool IsEventCandidateForHold(const ui::Event& event) {
+ if (event.type() == ui::ET_TOUCH_MOVED)
+ return true;
+ if (event.type() == ui::ET_MOUSE_DRAGGED)
+ return true;
+ if (event.IsMouseEvent() && (event.flags() & ui::EF_IS_SYNTHESIZED))
+ return true;
+ return false;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, public:
+
+WindowEventDispatcher::WindowEventDispatcher(WindowTreeHost* host)
+ : host_(host),
+ touch_ids_down_(0),
+ mouse_pressed_handler_(NULL),
+ mouse_moved_handler_(NULL),
+ event_dispatch_target_(NULL),
+ old_dispatch_target_(NULL),
+ synthesize_mouse_move_(false),
+ move_hold_count_(0),
+ dispatching_held_event_(false),
+ observer_manager_(this),
+ repost_event_factory_(this),
+ held_event_factory_(this) {
+ ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
+ Env::GetInstance()->AddObserver(this);
+}
+
+WindowEventDispatcher::~WindowEventDispatcher() {
+ TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor");
+ Env::GetInstance()->RemoveObserver(this);
+ ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
+}
+
+void WindowEventDispatcher::RepostEvent(const ui::LocatedEvent& event) {
+ DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
+ event.type() == ui::ET_GESTURE_TAP_DOWN);
+ // We allow for only one outstanding repostable event. This is used
+ // in exiting context menus. A dropped repost request is allowed.
+ if (event.type() == ui::ET_MOUSE_PRESSED) {
+ held_repostable_event_.reset(
+ new ui::MouseEvent(
+ static_cast<const ui::MouseEvent&>(event),
+ static_cast<aura::Window*>(event.target()),
+ window()));
+ base::MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE, base::Bind(
+ base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
+ repost_event_factory_.GetWeakPtr()));
+ } else {
+ DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
+ held_repostable_event_.reset();
+ // TODO(rbyers): Reposing of gestures is tricky to get
+ // right, so it's not yet supported. crbug.com/170987.
+ }
+}
+
+void WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) {
+ // Send entered / exited so that visual state can be updated to match
+ // mouse events state.
+ PostSynthesizeMouseMove();
+ // TODO(mazda): Add code to disable mouse events when |enabled| == false.
+}
+
+void WindowEventDispatcher::DispatchCancelModeEvent() {
+ ui::CancelModeEvent event;
+ Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow();
+ if (focused_window && !window()->Contains(focused_window))
+ focused_window = NULL;
+ DispatchDetails details =
+ DispatchEvent(focused_window ? focused_window : window(), &event);
+ if (details.dispatcher_destroyed)
+ return;
+}
+
+void WindowEventDispatcher::DispatchGestureEvent(ui::GestureEvent* event) {
+ DispatchDetails details = DispatchHeldEvents();
+ if (details.dispatcher_destroyed)
+ return;
+
+ Window* target = GetGestureTarget(event);
+ if (target) {
+ event->ConvertLocationToTarget(window(), target);
+ DispatchDetails details = DispatchEvent(target, event);
+ if (details.dispatcher_destroyed)
+ return;
+ }
+}
+
+void WindowEventDispatcher::DispatchMouseExitAtPoint(const gfx::Point& point) {
+ ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE,
+ ui::EF_NONE);
+ DispatchDetails details =
+ DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
+ if (details.dispatcher_destroyed)
+ return;
+}
+
+void WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event,
+ Window* window,
+ ui::EventResult result) {
+ scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
+ gestures.reset(ui::GestureRecognizer::Get()->
+ ProcessTouchEventForGesture(*event, result, window));
+ DispatchDetails details = ProcessGestures(gestures.get());
+ if (details.dispatcher_destroyed)
+ return;
+}
+
+void WindowEventDispatcher::HoldPointerMoves() {
+ if (!move_hold_count_)
+ held_event_factory_.InvalidateWeakPtrs();
+ ++move_hold_count_;
+ TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves",
+ this);
+}
+
+void WindowEventDispatcher::ReleasePointerMoves() {
+ --move_hold_count_;
+ DCHECK_GE(move_hold_count_, 0);
+ if (!move_hold_count_ && held_move_event_) {
+ // We don't want to call DispatchHeldEvents directly, because this might be
+ // called from a deep stack while another event, in which case dispatching
+ // another one may not be safe/expected. Instead we post a task, that we
+ // may cancel if HoldPointerMoves is called again before it executes.
+ base::MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE, base::Bind(
+ base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents),
+ held_event_factory_.GetWeakPtr()));
+ }
+ TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this);
+}
+
+gfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const {
+ gfx::Point location = Env::GetInstance()->last_mouse_location();
+ client::ScreenPositionClient* client =
+ client::GetScreenPositionClient(window());
+ if (client)
+ client->ConvertPointFromScreen(window(), &location);
+ return location;
+}
+
+void WindowEventDispatcher::OnHostLostMouseGrab() {
+ mouse_pressed_handler_ = NULL;
+ mouse_moved_handler_ = NULL;
+}
+
+void WindowEventDispatcher::OnCursorMovedToRootLocation(
+ const gfx::Point& root_location) {
+ SetLastMouseLocation(window(), root_location);
+ synthesize_mouse_move_ = false;
+}
+
+void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) {
+ OnWindowHidden(window, WINDOW_DESTROYED);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, private:
+
+Window* WindowEventDispatcher::window() {
+ return host_->window();
+}
+
+const Window* WindowEventDispatcher::window() const {
+ return host_->window();
+}
+
+void WindowEventDispatcher::TransformEventForDeviceScaleFactor(
+ ui::LocatedEvent* event) {
+ event->UpdateForRootTransform(host_->GetInverseRootTransform());
+}
+
+void WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) {
+ // The mouse capture is intentionally ignored. Think that a mouse enters
+ // to a window, the window sets the capture, the mouse exits the window,
+ // and then it releases the capture. In that case OnMouseExited won't
+ // be called. So it is natural not to emit OnMouseExited even though
+ // |window| is the capture window.
+ gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
+ if (window->Contains(mouse_moved_handler_) &&
+ window->ContainsPointInRoot(last_mouse_location))
+ DispatchMouseExitAtPoint(last_mouse_location);
+}
+
+ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit(
+ const ui::MouseEvent& event,
+ ui::EventType type) {
+ if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED &&
+ !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
+ SetLastMouseLocation(window(), event.root_location());
+ }
+
+ if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() ||
+ !window()->Contains(mouse_moved_handler_))
+ return DispatchDetails();
+
+ // |event| may be an event in the process of being dispatched to a target (in
+ // which case its locations will be in the event's target's coordinate
+ // system), or a synthetic event created in root-window (in which case, the
+ // event's target will be NULL, and the event will be in the root-window's
+ // coordinate system.
+ aura::Window* target = static_cast<Window*>(event.target());
+ if (!target)
+ target = window();
+ ui::MouseEvent translated_event(event,
+ target,
+ mouse_moved_handler_,
+ type,
+ event.flags() | ui::EF_IS_SYNTHESIZED);
+ return DispatchEvent(mouse_moved_handler_, &translated_event);
+}
+
+ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures(
+ ui::GestureRecognizer::Gestures* gestures) {
+ DispatchDetails details;
+ if (!gestures || gestures->empty())
+ return details;
+
+ Window* target = GetGestureTarget(gestures->get().at(0));
+ for (size_t i = 0; i < gestures->size(); ++i) {
+ ui::GestureEvent* event = gestures->get().at(i);
+ event->ConvertLocationToTarget(window(), target);
+ details = DispatchEvent(target, event);
+ if (details.dispatcher_destroyed || details.target_destroyed)
+ break;
+ }
+ return details;
+}
+
+void WindowEventDispatcher::OnWindowHidden(Window* invisible,
+ WindowHiddenReason reason) {
+ // If the window the mouse was pressed in becomes invisible, it should no
+ // longer receive mouse events.
+ if (invisible->Contains(mouse_pressed_handler_))
+ mouse_pressed_handler_ = NULL;
+ if (invisible->Contains(mouse_moved_handler_))
+ mouse_moved_handler_ = NULL;
+
+ // If events are being dispatched from a nested message-loop, and the target
+ // of the outer loop is hidden or moved to another dispatcher during
+ // dispatching events in the inner loop, then reset the target for the outer
+ // loop.
+ if (invisible->Contains(old_dispatch_target_))
+ old_dispatch_target_ = NULL;
+
+ invisible->CleanupGestureState();
+
+ // Do not clear the capture, and the |event_dispatch_target_| if the
+ // window is moving across hosts, because the target itself is actually still
+ // visible and clearing them stops further event processing, which can cause
+ // unexpected behaviors. See crbug.com/157583
+ if (reason != WINDOW_MOVING) {
+ // We don't ask |invisible| here, because invisible may have been removed
+ // from the window hierarchy already by the time this function is called
+ // (OnWindowDestroyed).
+ client::CaptureClient* capture_client =
+ client::GetCaptureClient(host_->window());
+ Window* capture_window =
+ capture_client ? capture_client->GetCaptureWindow() : NULL;
+
+ if (invisible->Contains(event_dispatch_target_))
+ event_dispatch_target_ = NULL;
+
+ // If the ancestor of the capture window is hidden, release the capture.
+ // Note that this may delete the window so do not use capture_window
+ // after this.
+ if (invisible->Contains(capture_window) && invisible != window())
+ capture_window->ReleaseCapture();
+ }
+}
+
+Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) {
+ Window* target = NULL;
+ if (!event->IsEndingEvent()) {
+ // The window that received the start event (e.g. scroll begin) needs to
+ // receive the end event (e.g. scroll end).
+ target = client::GetCaptureWindow(window());
+ }
+ if (!target) {
+ target = ConsumerToWindow(
+ ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event));
+ }
+
+ return target;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, aura::client::CaptureDelegate implementation:
+
+void WindowEventDispatcher::UpdateCapture(Window* old_capture,
+ Window* new_capture) {
+ // |mouse_moved_handler_| may have been set to a Window in a different root
+ // (see below). Clear it here to ensure we don't end up referencing a stale
+ // Window.
+ if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_))
+ mouse_moved_handler_ = NULL;
+
+ if (old_capture && old_capture->GetRootWindow() == window() &&
+ old_capture->delegate()) {
+ // Send a capture changed event with bogus location data.
+ ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
+ gfx::Point(), 0, 0);
+
+ DispatchDetails details = DispatchEvent(old_capture, &event);
+ if (details.dispatcher_destroyed)
+ return;
+
+ old_capture->delegate()->OnCaptureLost();
+ }
+
+ if (new_capture) {
+ // Make all subsequent mouse events go to the capture window. We shouldn't
+ // need to send an event here as OnCaptureLost() should take care of that.
+ if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown())
+ mouse_moved_handler_ = new_capture;
+ } else {
+ // Make sure mouse_moved_handler gets updated.
+ DispatchDetails details = SynthesizeMouseMoveEvent();
+ if (details.dispatcher_destroyed)
+ return;
+ }
+ mouse_pressed_handler_ = NULL;
+}
+
+void WindowEventDispatcher::OnOtherRootGotCapture() {
+ mouse_moved_handler_ = NULL;
+ mouse_pressed_handler_ = NULL;
+}
+
+void WindowEventDispatcher::SetNativeCapture() {
+ host_->SetCapture();
+}
+
+void WindowEventDispatcher::ReleaseNativeCapture() {
+ host_->ReleaseCapture();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, ui::EventProcessor implementation:
+ui::EventTarget* WindowEventDispatcher::GetRootTarget() {
+ return window();
+}
+
+void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) {
+ if (dispatching_held_event_) {
+ // The held events are already in |window()|'s coordinate system. So it is
+ // not necessary to apply the transform to convert from the host's
+ // coordinate system to |window()|'s coordinate system.
+ return;
+ }
+ if (event->IsMouseEvent() ||
+ event->IsScrollEvent() ||
+ event->IsTouchEvent() ||
+ event->IsGestureEvent()) {
+ TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, ui::EventDispatcherDelegate implementation:
+
+bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) {
+ return event_dispatch_target_ == target;
+}
+
+ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent(
+ ui::EventTarget* target,
+ ui::Event* event) {
+ Window* target_window = static_cast<Window*>(target);
+ CHECK(window()->Contains(target_window));
+
+ if (!dispatching_held_event_) {
+ bool can_be_held = IsEventCandidateForHold(*event);
+ if (!move_hold_count_ || !can_be_held) {
+ if (can_be_held)
+ held_move_event_.reset();
+ DispatchDetails details = DispatchHeldEvents();
+ if (details.dispatcher_destroyed || details.target_destroyed)
+ return details;
+ }
+ }
+
+ if (event->IsMouseEvent()) {
+ PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event));
+ } else if (event->IsScrollEvent()) {
+ PreDispatchLocatedEvent(target_window,
+ static_cast<ui::ScrollEvent*>(event));
+ } else if (event->IsTouchEvent()) {
+ PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event));
+ }
+ old_dispatch_target_ = event_dispatch_target_;
+ event_dispatch_target_ = static_cast<Window*>(target);
+ return DispatchDetails();
+}
+
+ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent(
+ ui::EventTarget* target,
+ const ui::Event& event) {
+ DispatchDetails details;
+ if (!target || target != event_dispatch_target_)
+ details.target_destroyed = true;
+ event_dispatch_target_ = old_dispatch_target_;
+ old_dispatch_target_ = NULL;
+#ifndef NDEBUG
+ DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_));
+#endif
+
+ if (event.IsTouchEvent() && !details.target_destroyed) {
+ // Do not let 'held' touch events contribute to any gestures unless it is
+ // being dispatched.
+ if (dispatching_held_event_ || !held_move_event_ ||
+ !held_move_event_->IsTouchEvent()) {
+ ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event),
+ static_cast<Window*>(event.target()), window());
+ // Get the list of GestureEvents from GestureRecognizer.
+ scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
+ gestures.reset(ui::GestureRecognizer::Get()->
+ ProcessTouchEventForGesture(orig_event, event.result(),
+ static_cast<Window*>(target)));
+ return ProcessGestures(gestures.get());
+ }
+ }
+
+ return details;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, ui::GestureEventHelper implementation:
+
+bool WindowEventDispatcher::CanDispatchToConsumer(
+ ui::GestureConsumer* consumer) {
+ Window* consumer_window = ConsumerToWindow(consumer);
+ return (consumer_window && consumer_window->GetRootWindow() == window());
+}
+
+void WindowEventDispatcher::DispatchCancelTouchEvent(ui::TouchEvent* event) {
+ DispatchDetails details = OnEventFromSource(event);
+ if (details.dispatcher_destroyed)
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, WindowObserver implementation:
+
+void WindowEventDispatcher::OnWindowDestroying(Window* window) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ DispatchMouseExitToHidingWindow(window);
+ SynthesizeMouseMoveAfterChangeToWindow(window);
+}
+
+void WindowEventDispatcher::OnWindowDestroyed(Window* window) {
+ // We observe all windows regardless of what root Window (if any) they're
+ // attached to.
+ observer_manager_.Remove(window);
+}
+
+void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) {
+ if (!observer_manager_.IsObserving(attached))
+ observer_manager_.Add(attached);
+
+ if (!host_->window()->Contains(attached))
+ return;
+
+ SynthesizeMouseMoveAfterChangeToWindow(attached);
+}
+
+void WindowEventDispatcher::OnWindowRemovingFromRootWindow(Window* detached,
+ Window* new_root) {
+ if (!host_->window()->Contains(detached))
+ return;
+
+ DCHECK(client::GetCaptureWindow(window()) != window());
+
+ DispatchMouseExitToHidingWindow(detached);
+ SynthesizeMouseMoveAfterChangeToWindow(detached);
+
+ // Hiding the window releases capture which can implicitly destroy the window
+ // so the window may no longer be valid after this call.
+ OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN);
+}
+
+void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window,
+ bool visible) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ DispatchMouseExitToHidingWindow(window);
+}
+
+void WindowEventDispatcher::OnWindowVisibilityChanged(Window* window,
+ bool visible) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ if (window->ContainsPointInRoot(GetLastMouseLocationInRoot()))
+ PostSynthesizeMouseMove();
+
+ // Hiding the window releases capture which can implicitly destroy the window
+ // so the window may no longer be valid after this call.
+ if (!visible)
+ OnWindowHidden(window, WINDOW_HIDDEN);
+}
+
+void WindowEventDispatcher::OnWindowBoundsChanged(Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ if (window == host_->window()) {
+ TRACE_EVENT1("ui", "WindowEventDispatcher::OnWindowBoundsChanged(root)",
+ "size", new_bounds.size().ToString());
+
+ DispatchDetails details = DispatchHeldEvents();
+ if (details.dispatcher_destroyed)
+ return;
+
+ synthesize_mouse_move_ = false;
+ }
+
+ if (window->IsVisible() && !window->ignore_events()) {
+ gfx::Rect old_bounds_in_root = old_bounds, new_bounds_in_root = new_bounds;
+ Window::ConvertRectToTarget(window->parent(), host_->window(),
+ &old_bounds_in_root);
+ Window::ConvertRectToTarget(window->parent(), host_->window(),
+ &new_bounds_in_root);
+ gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
+ if (old_bounds_in_root.Contains(last_mouse_location) !=
+ new_bounds_in_root.Contains(last_mouse_location)) {
+ PostSynthesizeMouseMove();
+ }
+ }
+}
+
+void WindowEventDispatcher::OnWindowTransforming(Window* window) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ SynthesizeMouseMoveAfterChangeToWindow(window);
+}
+
+void WindowEventDispatcher::OnWindowTransformed(Window* window) {
+ if (!host_->window()->Contains(window))
+ return;
+
+ SynthesizeMouseMoveAfterChangeToWindow(window);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, EnvObserver implementation:
+
+void WindowEventDispatcher::OnWindowInitialized(Window* window) {
+ observer_manager_.Add(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowEventDispatcher, private:
+
+ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() {
+ if (!held_repostable_event_ && !held_move_event_)
+ return DispatchDetails();
+
+ CHECK(!dispatching_held_event_);
+ dispatching_held_event_ = true;
+
+ DispatchDetails dispatch_details;
+ if (held_repostable_event_) {
+ if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
+ scoped_ptr<ui::MouseEvent> mouse_event(
+ static_cast<ui::MouseEvent*>(held_repostable_event_.release()));
+ dispatch_details = OnEventFromSource(mouse_event.get());
+ } else {
+ // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
+ NOTREACHED();
+ }
+ if (dispatch_details.dispatcher_destroyed)
+ return dispatch_details;
+ }
+
+ if (held_move_event_) {
+ // If a mouse move has been synthesized, the target location is suspect,
+ // so drop the held mouse event.
+ if (held_move_event_->IsTouchEvent() ||
+ (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) {
+ dispatch_details = OnEventFromSource(held_move_event_.get());
+ }
+ if (!dispatch_details.dispatcher_destroyed)
+ held_move_event_.reset();
+ }
+
+ if (!dispatch_details.dispatcher_destroyed)
+ dispatching_held_event_ = false;
+ return dispatch_details;
+}
+
+void WindowEventDispatcher::PostSynthesizeMouseMove() {
+ if (synthesize_mouse_move_)
+ return;
+ synthesize_mouse_move_ = true;
+ base::MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(
+ &WindowEventDispatcher::SynthesizeMouseMoveEvent),
+ held_event_factory_.GetWeakPtr()));
+}
+
+void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow(
+ Window* window) {
+ if (window->IsVisible() &&
+ window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
+ PostSynthesizeMouseMove();
+ }
+}
+
+ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent() {
+ DispatchDetails details;
+ if (!synthesize_mouse_move_)
+ return details;
+ synthesize_mouse_move_ = false;
+
+ // If one of the mouse buttons is currently down, then do not synthesize a
+ // mouse-move event. In such cases, aura could synthesize a DRAGGED event
+ // instead of a MOVED event, but in multi-display/multi-host scenarios, the
+ // DRAGGED event can be synthesized in the incorrect host. So avoid
+ // synthesizing any events at all.
+ if (Env::GetInstance()->mouse_button_flags())
+ return details;
+
+ gfx::Point root_mouse_location = GetLastMouseLocationInRoot();
+ if (!window()->bounds().Contains(root_mouse_location))
+ return details;
+ gfx::Point host_mouse_location = root_mouse_location;
+ host_->ConvertPointToHost(&host_mouse_location);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED,
+ host_mouse_location,
+ host_mouse_location,
+ ui::EF_IS_SYNTHESIZED,
+ 0);
+ return OnEventFromSource(&event);
+}
+
+void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target,
+ ui::LocatedEvent* event) {
+ int flags = event->flags();
+ if (IsNonClientLocation(target, event->location()))
+ flags |= ui::EF_IS_NON_CLIENT;
+ event->set_flags(flags);
+
+ if (!dispatching_held_event_ &&
+ (event->IsMouseEvent() || event->IsScrollEvent()) &&
+ !(event->flags() & ui::EF_IS_SYNTHESIZED)) {
+ if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
+ SetLastMouseLocation(window(), event->root_location());
+ synthesize_mouse_move_ = false;
+ }
+}
+
+void WindowEventDispatcher::PreDispatchMouseEvent(Window* target,
+ ui::MouseEvent* event) {
+ client::CursorClient* cursor_client = client::GetCursorClient(window());
+ // We allow synthesized mouse exit events through even if mouse events are
+ // disabled. This ensures that hover state, etc on controls like buttons is
+ // cleared.
+ if (cursor_client &&
+ !cursor_client->IsMouseEventsEnabled() &&
+ (event->flags() & ui::EF_IS_SYNTHESIZED) &&
+ (event->type() != ui::ET_MOUSE_EXITED)) {
+ event->SetHandled();
+ return;
+ }
+
+ if (IsEventCandidateForHold(*event) && !dispatching_held_event_) {
+ if (move_hold_count_) {
+ if (!(event->flags() & ui::EF_IS_SYNTHESIZED) &&
+ event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
+ SetLastMouseLocation(window(), event->root_location());
+ }
+ held_move_event_.reset(new ui::MouseEvent(*event, target, window()));
+ event->SetHandled();
+ return;
+ } else {
+ // We may have a held event for a period between the time move_hold_count_
+ // fell to 0 and the DispatchHeldEvents executes. Since we're going to
+ // dispatch the new event directly below, we can reset the old one.
+ held_move_event_.reset();
+ }
+ }
+
+ const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON |
+ ui::EF_MIDDLE_MOUSE_BUTTON |
+ ui::EF_RIGHT_MOUSE_BUTTON;
+ switch (event->type()) {
+ case ui::ET_MOUSE_EXITED:
+ if (!target || target == window()) {
+ DispatchDetails details =
+ DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
+ if (details.dispatcher_destroyed) {
+ event->SetHandled();
+ return;
+ }
+ mouse_moved_handler_ = NULL;
+ }
+ break;
+ case ui::ET_MOUSE_MOVED:
+ // Send an exit to the current |mouse_moved_handler_| and an enter to
+ // |target|. Take care that both us and |target| aren't destroyed during
+ // dispatch.
+ if (target != mouse_moved_handler_) {
+ aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
+ WindowTracker live_window;
+ live_window.Add(target);
+ DispatchDetails details =
+ DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
+ if (details.dispatcher_destroyed) {
+ event->SetHandled();
+ return;
+ }
+ // If the |mouse_moved_handler_| changes out from under us, assume a
+ // nested message loop ran and we don't need to do anything.
+ if (mouse_moved_handler_ != old_mouse_moved_handler) {
+ event->SetHandled();
+ return;
+ }
+ if (!live_window.Contains(target) || details.target_destroyed) {
+ mouse_moved_handler_ = NULL;
+ event->SetHandled();
+ return;
+ }
+ live_window.Remove(target);
+
+ mouse_moved_handler_ = target;
+ details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED);
+ if (details.dispatcher_destroyed || details.target_destroyed) {
+ event->SetHandled();
+ return;
+ }
+ }
+ break;
+ case ui::ET_MOUSE_PRESSED:
+ // Don't set the mouse pressed handler for non client mouse down events.
+ // These are only sent by Windows and are not always followed with non
+ // client mouse up events which causes subsequent mouse events to be
+ // sent to the wrong target.
+ if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_)
+ mouse_pressed_handler_ = target;
+ Env::GetInstance()->set_mouse_button_flags(
+ event->flags() & kMouseButtonFlagMask);
+ break;
+ case ui::ET_MOUSE_RELEASED:
+ mouse_pressed_handler_ = NULL;
+ Env::GetInstance()->set_mouse_button_flags(event->flags() &
+ kMouseButtonFlagMask & ~event->changed_button_flags());
+ break;
+ default:
+ break;
+ }
+
+ PreDispatchLocatedEvent(target, event);
+}
+
+void WindowEventDispatcher::PreDispatchTouchEvent(Window* target,
+ ui::TouchEvent* event) {
+ switch (event->type()) {
+ case ui::ET_TOUCH_PRESSED:
+ touch_ids_down_ |= (1 << event->touch_id());
+ Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
+ break;
+
+ // Handle ET_TOUCH_CANCELLED only if it has a native event.
+ case ui::ET_TOUCH_CANCELLED:
+ if (!event->HasNativeEvent())
+ break;
+ // fallthrough
+ case ui::ET_TOUCH_RELEASED:
+ touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^
+ (1 << event->touch_id());
+ Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
+ break;
+
+ case ui::ET_TOUCH_MOVED:
+ if (move_hold_count_ && !dispatching_held_event_) {
+ held_move_event_.reset(new ui::TouchEvent(*event, target, window()));
+ event->SetHandled();
+ return;
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+ PreDispatchLocatedEvent(target, event);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_event_dispatcher.h b/chromium/ui/aura/window_event_dispatcher.h
new file mode 100644
index 00000000000..79ba3c7b2cb
--- /dev/null
+++ b/chromium/ui/aura/window_event_dispatcher.h
@@ -0,0 +1,265 @@
+// 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_AURA_WINDOW_EVENT_DISPATCHER_H_
+#define UI_AURA_WINDOW_EVENT_DISPATCHER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/client/capture_delegate.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_processor.h"
+#include "ui/events/event_targeter.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_types.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+
+namespace gfx {
+class Size;
+class Transform;
+}
+
+namespace ui {
+class GestureEvent;
+class GestureRecognizer;
+class KeyEvent;
+class MouseEvent;
+class ScrollEvent;
+class TouchEvent;
+}
+
+namespace aura {
+class TestScreen;
+class WindowTargeter;
+class WindowTreeHost;
+
+// WindowEventDispatcher orchestrates event dispatch within a window tree
+// owned by WindowTreeHost. WTH also owns the WED.
+// TODO(beng): In progress, remove functionality not directly related to
+// event dispatch.
+class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor,
+ public ui::GestureEventHelper,
+ public client::CaptureDelegate,
+ public WindowObserver,
+ public EnvObserver {
+ public:
+ explicit WindowEventDispatcher(WindowTreeHost* host);
+ virtual ~WindowEventDispatcher();
+
+ Window* mouse_pressed_handler() { return mouse_pressed_handler_; }
+ Window* mouse_moved_handler() { return mouse_moved_handler_; }
+
+ // Repost event for re-processing. Used when exiting context menus.
+ // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event
+ // types (although the latter is currently a no-op).
+ void RepostEvent(const ui::LocatedEvent& event);
+
+ // Invoked when the mouse events get enabled or disabled.
+ void OnMouseEventsEnableStateChanged(bool enabled);
+
+ void DispatchCancelModeEvent();
+
+ // Dispatches a ui::ET_MOUSE_EXITED event at |point|.
+ // TODO(beng): needed only for WTH::OnCursorVisibilityChanged().
+ void DispatchMouseExitAtPoint(const gfx::Point& point);
+
+ // Gesture Recognition -------------------------------------------------------
+
+ // When a touch event is dispatched to a Window, it may want to process the
+ // touch event asynchronously. In such cases, the window should consume the
+ // event during the event dispatch. Once the event is properly processed, the
+ // window should let the WindowEventDispatcher know about the result of the
+ // event processing, so that gesture events can be properly created and
+ // dispatched.
+ void ProcessedTouchEvent(ui::TouchEvent* event,
+ Window* window,
+ ui::EventResult result);
+
+ // These methods are used to defer the processing of mouse/touch events
+ // related to resize. A client (typically a RenderWidgetHostViewAura) can call
+ // HoldPointerMoves when an resize is initiated and then ReleasePointerMoves
+ // once the resize is completed.
+ //
+ // More than one hold can be invoked and each hold must be cancelled by a
+ // release before we resume normal operation.
+ void HoldPointerMoves();
+ void ReleasePointerMoves();
+
+ // Gets the last location seen in a mouse event in this root window's
+ // coordinates. This may return a point outside the root window's bounds.
+ gfx::Point GetLastMouseLocationInRoot() const;
+
+ void OnHostLostMouseGrab();
+ void OnCursorMovedToRootLocation(const gfx::Point& root_location);
+
+ // TODO(beng): This is only needed because this cleanup needs to happen after
+ // all other observers are notified of OnWindowDestroying() but
+ // before OnWindowDestroyed() is sent (i.e. while the window
+ // hierarchy is still intact). This didn't seem worth adding a
+ // generic notification for as only this class needs to implement
+ // it. I would however like to find a way to do this via an
+ // observer.
+ void OnPostNotifiedWindowDestroying(Window* window);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WindowEventDispatcherTest,
+ KeepTranslatedEventInRoot);
+
+ friend class Window;
+ friend class TestScreen;
+
+ // The parameter for OnWindowHidden() to specify why window is hidden.
+ enum WindowHiddenReason {
+ WINDOW_DESTROYED, // Window is destroyed.
+ WINDOW_HIDDEN, // Window is hidden.
+ WINDOW_MOVING, // Window is temporarily marked as hidden due to move
+ // across root windows.
+ };
+
+ Window* window();
+ const Window* window() const;
+
+ // Updates the event with the appropriate transform for the device scale
+ // factor. The WindowEventDispatcher dispatches events in the physical pixel
+ // coordinate. But the event processing from WindowEventDispatcher onwards
+ // happen in device-independent pixel coordinate. So it is necessary to update
+ // the event received from the host.
+ void TransformEventForDeviceScaleFactor(ui::LocatedEvent* event);
+
+ // Dispatches OnMouseExited to the |window| which is hiding if necessary.
+ void DispatchMouseExitToHidingWindow(Window* window);
+
+ // Dispatches the specified event type (intended for enter/exit) to the
+ // |mouse_moved_handler_|.
+ ui::EventDispatchDetails DispatchMouseEnterOrExit(
+ const ui::MouseEvent& event,
+ ui::EventType type) WARN_UNUSED_RESULT;
+ ui::EventDispatchDetails ProcessGestures(
+ ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT;
+
+ // Called when a window becomes invisible, either by being removed
+ // from root window hierarchy, via SetVisible(false) or being destroyed.
+ // |reason| specifies what triggered the hiding. Note that becoming invisible
+ // will cause a window to lose capture and some windows may destroy themselves
+ // on capture (like DragDropTracker).
+ void OnWindowHidden(Window* invisible, WindowHiddenReason reason);
+
+ // Returns a target window for the given gesture event.
+ Window* GetGestureTarget(ui::GestureEvent* event);
+
+ // Overridden from aura::client::CaptureDelegate:
+ virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE;
+ virtual void OnOtherRootGotCapture() OVERRIDE;
+ virtual void SetNativeCapture() OVERRIDE;
+ virtual void ReleaseNativeCapture() OVERRIDE;
+
+ // Overridden from ui::EventProcessor:
+ virtual ui::EventTarget* GetRootTarget() OVERRIDE;
+ virtual void PrepareEventForDispatch(ui::Event* event) OVERRIDE;
+
+ // Overridden from ui::EventDispatcherDelegate.
+ virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE;
+ virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target,
+ ui::Event* event) OVERRIDE;
+ virtual ui::EventDispatchDetails PostDispatchEvent(
+ ui::EventTarget* target, const ui::Event& event) OVERRIDE;
+
+ // Overridden from ui::GestureEventHelper.
+ virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
+ virtual void DispatchGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
+
+ // Overridden from WindowObserver:
+ virtual void OnWindowDestroying(Window* window) OVERRIDE;
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE;
+ virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE;
+ virtual void OnWindowRemovingFromRootWindow(Window* window,
+ Window* new_root) OVERRIDE;
+ virtual void OnWindowVisibilityChanging(Window* window,
+ bool visible) OVERRIDE;
+ virtual void OnWindowVisibilityChanged(Window* window, bool visible) OVERRIDE;
+ virtual void OnWindowBoundsChanged(Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE;
+ virtual void OnWindowTransforming(Window* window) OVERRIDE;
+ virtual void OnWindowTransformed(Window* window) OVERRIDE;
+
+ // Overridden from EnvObserver:
+ virtual void OnWindowInitialized(Window* window) OVERRIDE;
+
+ // We hold and aggregate mouse drags and touch moves as a way of throttling
+ // resizes when HoldMouseMoves() is called. The following methods are used to
+ // dispatch held and newly incoming mouse and touch events, typically when an
+ // event other than one of these needs dispatching or a matching
+ // ReleaseMouseMoves()/ReleaseTouchMoves() is called. NOTE: because these
+ // methods dispatch events from WindowTreeHost the coordinates are in terms of
+ // the root.
+ ui::EventDispatchDetails DispatchHeldEvents() WARN_UNUSED_RESULT;
+
+ // Posts a task to send synthesized mouse move event if there is no a pending
+ // task.
+ void PostSynthesizeMouseMove();
+
+ // Creates and dispatches synthesized mouse move event using the current mouse
+ // location.
+ ui::EventDispatchDetails SynthesizeMouseMoveEvent() WARN_UNUSED_RESULT;
+
+ // Calls SynthesizeMouseMove() if |window| is currently visible and contains
+ // the mouse cursor.
+ void SynthesizeMouseMoveAfterChangeToWindow(Window* window);
+
+ void PreDispatchLocatedEvent(Window* target, ui::LocatedEvent* event);
+ void PreDispatchMouseEvent(Window* target, ui::MouseEvent* event);
+ void PreDispatchTouchEvent(Window* target, ui::TouchEvent* event);
+
+ WindowTreeHost* host_;
+
+ // Touch ids that are currently down.
+ uint32 touch_ids_down_;
+
+ Window* mouse_pressed_handler_;
+ Window* mouse_moved_handler_;
+ Window* event_dispatch_target_;
+ Window* old_dispatch_target_;
+
+ bool synthesize_mouse_move_;
+
+ // How many move holds are outstanding. We try to defer dispatching
+ // touch/mouse moves while the count is > 0.
+ int move_hold_count_;
+ // The location of |held_move_event_| is in |window_|'s coordinate.
+ scoped_ptr<ui::LocatedEvent> held_move_event_;
+
+ // Allowing for reposting of events. Used when exiting context menus.
+ scoped_ptr<ui::LocatedEvent> held_repostable_event_;
+
+ // Set when dispatching a held event.
+ bool dispatching_held_event_;
+
+ ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+
+ // Used to schedule reposting an event.
+ base::WeakPtrFactory<WindowEventDispatcher> repost_event_factory_;
+
+ // Used to schedule DispatchHeldEvents() when |move_hold_count_| goes to 0.
+ base::WeakPtrFactory<WindowEventDispatcher> held_event_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcher);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_EVENT_DISPATCHER_H_
diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc
new file mode 100644
index 00000000000..11eeaa0d2c4
--- /dev/null
+++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc
@@ -0,0 +1,2219 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/window_event_dispatcher.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/event_client.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/env_test_helper.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_cursor_client.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/base/hit_test.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/gestures/gesture_configuration.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/test/test_event_handler.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/transform.h"
+
+namespace aura {
+namespace {
+
+// A delegate that always returns a non-client component for hit tests.
+class NonClientDelegate : public test::TestWindowDelegate {
+ public:
+ NonClientDelegate()
+ : non_client_count_(0),
+ mouse_event_count_(0),
+ mouse_event_flags_(0x0) {
+ }
+ virtual ~NonClientDelegate() {}
+
+ int non_client_count() const { return non_client_count_; }
+ gfx::Point non_client_location() const { return non_client_location_; }
+ int mouse_event_count() const { return mouse_event_count_; }
+ gfx::Point mouse_event_location() const { return mouse_event_location_; }
+ int mouse_event_flags() const { return mouse_event_flags_; }
+
+ virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE {
+ NonClientDelegate* self = const_cast<NonClientDelegate*>(this);
+ self->non_client_count_++;
+ self->non_client_location_ = location;
+ return HTTOPLEFT;
+ }
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ mouse_event_count_++;
+ mouse_event_location_ = event->location();
+ mouse_event_flags_ = event->flags();
+ event->SetHandled();
+ }
+
+ private:
+ int non_client_count_;
+ gfx::Point non_client_location_;
+ int mouse_event_count_;
+ gfx::Point mouse_event_location_;
+ int mouse_event_flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonClientDelegate);
+};
+
+// A simple event handler that consumes key events.
+class ConsumeKeyHandler : public ui::test::TestEventHandler {
+ public:
+ ConsumeKeyHandler() {}
+ virtual ~ConsumeKeyHandler() {}
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ ui::test::TestEventHandler::OnKeyEvent(event);
+ event->StopPropagation();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler);
+};
+
+bool IsFocusedWindow(aura::Window* window) {
+ return client::GetFocusClient(window)->GetFocusedWindow() == window;
+}
+
+} // namespace
+
+typedef test::AuraTestBase WindowEventDispatcherTest;
+
+TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) {
+ // Create two non-overlapping windows so we don't have to worry about which
+ // is on top.
+ scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate());
+ scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate());
+ const int kWindowWidth = 123;
+ const int kWindowHeight = 45;
+ gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight);
+ gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight);
+ scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate(
+ delegate1.get(), -1234, bounds1, root_window()));
+ scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate(
+ delegate2.get(), -5678, bounds2, root_window()));
+
+ // Send a mouse event to window1.
+ gfx::Point point(101, 201);
+ ui::MouseEvent event1(
+ ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ DispatchEventUsingWindowDispatcher(&event1);
+
+ // Event was tested for non-client area for the target window.
+ EXPECT_EQ(1, delegate1->non_client_count());
+ EXPECT_EQ(0, delegate2->non_client_count());
+ // The non-client component test was in local coordinates.
+ EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
+ // Mouse event was received by target window.
+ EXPECT_EQ(1, delegate1->mouse_event_count());
+ EXPECT_EQ(0, delegate2->mouse_event_count());
+ // Event was in local coordinates.
+ EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location());
+ // Non-client flag was set.
+ EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT);
+}
+
+TEST_F(WindowEventDispatcherTest, RepostEvent) {
+ // Test RepostEvent in RootWindow. It only works for Mouse Press.
+ EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
+ gfx::Point point(10, 10);
+ ui::MouseEvent event(
+ ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ host()->dispatcher()->RepostEvent(event);
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
+}
+
+// Check that we correctly track the state of the mouse buttons in response to
+// button press and release events.
+TEST_F(WindowEventDispatcherTest, MouseButtonState) {
+ EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
+
+ gfx::Point location;
+ scoped_ptr<ui::MouseEvent> event;
+
+ // Press the left button.
+ event.reset(new ui::MouseEvent(
+ ui::ET_MOUSE_PRESSED,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON));
+ DispatchEventUsingWindowDispatcher(event.get());
+ EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
+
+ // Additionally press the right.
+ event.reset(new ui::MouseEvent(
+ ui::ET_MOUSE_PRESSED,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
+ ui::EF_RIGHT_MOUSE_BUTTON));
+ DispatchEventUsingWindowDispatcher(event.get());
+ EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
+
+ // Release the left button.
+ event.reset(new ui::MouseEvent(
+ ui::ET_MOUSE_RELEASED,
+ location,
+ location,
+ ui::EF_RIGHT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON));
+ DispatchEventUsingWindowDispatcher(event.get());
+ EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
+
+ // Release the right button. We should ignore the Shift-is-down flag.
+ event.reset(new ui::MouseEvent(
+ ui::ET_MOUSE_RELEASED,
+ location,
+ location,
+ ui::EF_SHIFT_DOWN,
+ ui::EF_RIGHT_MOUSE_BUTTON));
+ DispatchEventUsingWindowDispatcher(event.get());
+ EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
+
+ // Press the middle button.
+ event.reset(new ui::MouseEvent(
+ ui::ET_MOUSE_PRESSED,
+ location,
+ location,
+ ui::EF_MIDDLE_MOUSE_BUTTON,
+ ui::EF_MIDDLE_MOUSE_BUTTON));
+ DispatchEventUsingWindowDispatcher(event.get());
+ EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
+}
+
+TEST_F(WindowEventDispatcherTest, TranslatedEvent) {
+ scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1,
+ gfx::Rect(50, 50, 100, 100), root_window()));
+
+ gfx::Point origin(100, 100);
+ ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0, 0);
+
+ EXPECT_EQ("100,100", root.location().ToString());
+ EXPECT_EQ("100,100", root.root_location().ToString());
+
+ ui::MouseEvent translated_event(
+ root, static_cast<Window*>(root_window()), w1.get(),
+ ui::ET_MOUSE_ENTERED, root.flags());
+ EXPECT_EQ("50,50", translated_event.location().ToString());
+ EXPECT_EQ("100,100", translated_event.root_location().ToString());
+}
+
+namespace {
+
+class TestEventClient : public client::EventClient {
+ public:
+ static const int kNonLockWindowId = 100;
+ static const int kLockWindowId = 200;
+
+ explicit TestEventClient(Window* root_window)
+ : root_window_(root_window),
+ lock_(false) {
+ client::SetEventClient(root_window_, this);
+ Window* lock_window =
+ test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
+ lock_window->set_id(kLockWindowId);
+ Window* non_lock_window =
+ test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
+ non_lock_window->set_id(kNonLockWindowId);
+ }
+ virtual ~TestEventClient() {
+ client::SetEventClient(root_window_, NULL);
+ }
+
+ // Starts/stops locking. Locking prevents windows other than those inside
+ // the lock container from receiving events, getting focus etc.
+ void Lock() {
+ lock_ = true;
+ }
+ void Unlock() {
+ lock_ = false;
+ }
+
+ Window* GetLockWindow() {
+ return const_cast<Window*>(
+ static_cast<const TestEventClient*>(this)->GetLockWindow());
+ }
+ const Window* GetLockWindow() const {
+ return root_window_->GetChildById(kLockWindowId);
+ }
+ Window* GetNonLockWindow() {
+ return root_window_->GetChildById(kNonLockWindowId);
+ }
+
+ private:
+ // Overridden from client::EventClient:
+ virtual bool CanProcessEventsWithinSubtree(
+ const Window* window) const OVERRIDE {
+ return lock_ ?
+ window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) :
+ true;
+ }
+
+ virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE {
+ return NULL;
+ }
+
+ Window* root_window_;
+ bool lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestEventClient);
+};
+
+} // namespace
+
+TEST_F(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) {
+ TestEventClient client(root_window());
+ test::TestWindowDelegate d;
+
+ ui::test::TestEventHandler nonlock_ef;
+ ui::test::TestEventHandler lock_ef;
+ client.GetNonLockWindow()->AddPreTargetHandler(&nonlock_ef);
+ client.GetLockWindow()->AddPreTargetHandler(&lock_ef);
+
+ Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20),
+ client.GetNonLockWindow());
+ w1->set_id(1);
+ Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20),
+ client.GetNonLockWindow());
+ w2->set_id(2);
+ scoped_ptr<Window> w3(
+ test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20),
+ client.GetLockWindow()));
+
+ w1->Focus();
+ EXPECT_TRUE(IsFocusedWindow(w1));
+
+ client.Lock();
+
+ // Since we're locked, the attempt to focus w2 will be ignored.
+ w2->Focus();
+ EXPECT_TRUE(IsFocusedWindow(w1));
+ EXPECT_FALSE(IsFocusedWindow(w2));
+
+ {
+ // Attempting to send a key event to w1 (not in the lock container) should
+ // cause focus to be reset.
+ test::EventGenerator generator(root_window());
+ generator.PressKey(ui::VKEY_SPACE, 0);
+ EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow());
+ EXPECT_FALSE(IsFocusedWindow(w1));
+ }
+
+ {
+ // Events sent to a window not in the lock container will not be processed.
+ // i.e. never sent to the non-lock container's event filter.
+ test::EventGenerator generator(root_window(), w1);
+ generator.ClickLeftButton();
+ EXPECT_EQ(0, nonlock_ef.num_mouse_events());
+
+ // Events sent to a window in the lock container will be processed.
+ test::EventGenerator generator3(root_window(), w3.get());
+ generator3.PressLeftButton();
+ EXPECT_EQ(1, lock_ef.num_mouse_events());
+ }
+
+ // Prevent w3 from being deleted by the hierarchy since its delegate is owned
+ // by this scope.
+ w3->parent()->RemoveChild(w3.get());
+}
+
+TEST_F(WindowEventDispatcherTest, IgnoreUnknownKeys) {
+ ConsumeKeyHandler handler;
+ root_window()->AddPreTargetHandler(&handler);
+
+ ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false);
+ DispatchEventUsingWindowDispatcher(&unknown_event);
+ EXPECT_FALSE(unknown_event.handled());
+ EXPECT_EQ(0, handler.num_key_events());
+
+ handler.Reset();
+ ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
+ DispatchEventUsingWindowDispatcher(&known_event);
+ EXPECT_TRUE(known_event.handled());
+ EXPECT_EQ(1, handler.num_key_events());
+
+ handler.Reset();
+ ui::KeyEvent ime_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
+ ui::EF_IME_FABRICATED_KEY, false);
+ DispatchEventUsingWindowDispatcher(&ime_event);
+ EXPECT_TRUE(ime_event.handled());
+ EXPECT_EQ(1, handler.num_key_events());
+
+ handler.Reset();
+ ui::KeyEvent unknown_key_with_char_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
+ 0, false);
+ unknown_key_with_char_event.set_character(0x00e4 /* "ä" */);
+ DispatchEventUsingWindowDispatcher(&unknown_key_with_char_event);
+ EXPECT_TRUE(unknown_key_with_char_event.handled());
+ EXPECT_EQ(1, handler.num_key_events());
+}
+
+TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) {
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
+ w1->Show();
+ w1->Focus();
+
+ ui::test::TestEventHandler handler;
+ w1->AddPreTargetHandler(&handler);
+ ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
+ DispatchEventUsingWindowDispatcher(&key_press);
+ EXPECT_TRUE(key_press.handled());
+ EXPECT_EQ(1, handler.num_key_events());
+
+ w1->RemovePreTargetHandler(&handler);
+}
+
+// Tests that touch-events that are beyond the bounds of the root-window do get
+// propagated to the event filters correctly with the root as the target.
+TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) {
+ ui::test::TestEventHandler handler;
+ root_window()->AddPreTargetHandler(&handler);
+
+ gfx::Point position = root_window()->bounds().origin();
+ position.Offset(-10, -10);
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press);
+ EXPECT_EQ(1, handler.num_touch_events());
+
+ position = root_window()->bounds().origin();
+ position.Offset(root_window()->bounds().width() + 10,
+ root_window()->bounds().height() + 10);
+ ui::TouchEvent release(
+ ui::ET_TOUCH_RELEASED, position, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&release);
+ EXPECT_EQ(2, handler.num_touch_events());
+}
+
+// Tests that scroll events are dispatched correctly.
+TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) {
+ base::TimeDelta now = ui::EventTimeForNow();
+ ui::test::TestEventHandler handler;
+ root_window()->AddPreTargetHandler(&handler);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
+ w1->SetBounds(gfx::Rect(20, 20, 40, 40));
+
+ // A scroll event on the root-window itself is dispatched.
+ ui::ScrollEvent scroll1(ui::ET_SCROLL,
+ gfx::Point(10, 10),
+ now,
+ 0,
+ 0, -10,
+ 0, -10,
+ 2);
+ DispatchEventUsingWindowDispatcher(&scroll1);
+ EXPECT_EQ(1, handler.num_scroll_events());
+
+ // Scroll event on a window should be dispatched properly.
+ ui::ScrollEvent scroll2(ui::ET_SCROLL,
+ gfx::Point(25, 30),
+ now,
+ 0,
+ -10, 0,
+ -10, 0,
+ 2);
+ DispatchEventUsingWindowDispatcher(&scroll2);
+ EXPECT_EQ(2, handler.num_scroll_events());
+ root_window()->RemovePreTargetHandler(&handler);
+}
+
+namespace {
+
+// FilterFilter that tracks the types of events it's seen.
+class EventFilterRecorder : public ui::EventHandler {
+ public:
+ typedef std::vector<ui::EventType> Events;
+ typedef std::vector<gfx::Point> EventLocations;
+ typedef std::vector<int> EventFlags;
+
+ EventFilterRecorder()
+ : wait_until_event_(ui::ET_UNKNOWN) {
+ }
+
+ const Events& events() const { return events_; }
+
+ const EventLocations& mouse_locations() const { return mouse_locations_; }
+ gfx::Point mouse_location(int i) const { return mouse_locations_[i]; }
+ const EventLocations& touch_locations() const { return touch_locations_; }
+ const EventFlags& mouse_event_flags() const { return mouse_event_flags_; }
+
+ void WaitUntilReceivedEvent(ui::EventType type) {
+ wait_until_event_ = type;
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
+ }
+
+ Events GetAndResetEvents() {
+ Events events = events_;
+ Reset();
+ return events;
+ }
+
+ void Reset() {
+ events_.clear();
+ mouse_locations_.clear();
+ touch_locations_.clear();
+ mouse_event_flags_.clear();
+ }
+
+ // ui::EventHandler overrides:
+ virtual void OnEvent(ui::Event* event) OVERRIDE {
+ ui::EventHandler::OnEvent(event);
+ events_.push_back(event->type());
+ if (wait_until_event_ == event->type() && run_loop_) {
+ run_loop_->Quit();
+ wait_until_event_ = ui::ET_UNKNOWN;
+ }
+ }
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ mouse_locations_.push_back(event->location());
+ mouse_event_flags_.push_back(event->flags());
+ }
+
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
+ touch_locations_.push_back(event->location());
+ }
+
+ bool HasReceivedEvent(ui::EventType type) {
+ return std::find(events_.begin(), events_.end(), type) != events_.end();
+ }
+
+ private:
+ scoped_ptr<base::RunLoop> run_loop_;
+ ui::EventType wait_until_event_;
+
+ Events events_;
+ EventLocations mouse_locations_;
+ EventLocations touch_locations_;
+ EventFlags mouse_event_flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder);
+};
+
+// Converts an EventType to a string.
+std::string EventTypeToString(ui::EventType type) {
+ switch (type) {
+ case ui::ET_TOUCH_RELEASED:
+ return "TOUCH_RELEASED";
+
+ case ui::ET_TOUCH_CANCELLED:
+ return "TOUCH_CANCELLED";
+
+ case ui::ET_TOUCH_PRESSED:
+ return "TOUCH_PRESSED";
+
+ case ui::ET_TOUCH_MOVED:
+ return "TOUCH_MOVED";
+
+ case ui::ET_MOUSE_PRESSED:
+ return "MOUSE_PRESSED";
+
+ case ui::ET_MOUSE_DRAGGED:
+ return "MOUSE_DRAGGED";
+
+ case ui::ET_MOUSE_RELEASED:
+ return "MOUSE_RELEASED";
+
+ case ui::ET_MOUSE_MOVED:
+ return "MOUSE_MOVED";
+
+ case ui::ET_MOUSE_ENTERED:
+ return "MOUSE_ENTERED";
+
+ case ui::ET_MOUSE_EXITED:
+ return "MOUSE_EXITED";
+
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ return "GESTURE_SCROLL_BEGIN";
+
+ case ui::ET_GESTURE_SCROLL_END:
+ return "GESTURE_SCROLL_END";
+
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ return "GESTURE_SCROLL_UPDATE";
+
+ case ui::ET_GESTURE_PINCH_BEGIN:
+ return "GESTURE_PINCH_BEGIN";
+
+ case ui::ET_GESTURE_PINCH_END:
+ return "GESTURE_PINCH_END";
+
+ case ui::ET_GESTURE_PINCH_UPDATE:
+ return "GESTURE_PINCH_UPDATE";
+
+ case ui::ET_GESTURE_TAP:
+ return "GESTURE_TAP";
+
+ case ui::ET_GESTURE_TAP_DOWN:
+ return "GESTURE_TAP_DOWN";
+
+ case ui::ET_GESTURE_TAP_CANCEL:
+ return "GESTURE_TAP_CANCEL";
+
+ case ui::ET_GESTURE_SHOW_PRESS:
+ return "GESTURE_SHOW_PRESS";
+
+ case ui::ET_GESTURE_BEGIN:
+ return "GESTURE_BEGIN";
+
+ case ui::ET_GESTURE_END:
+ return "GESTURE_END";
+
+ default:
+ // We should explicitly require each event type.
+ NOTREACHED() << "Received unexpected event: " << type;
+ break;
+ }
+ return "";
+}
+
+std::string EventTypesToString(const EventFilterRecorder::Events& events) {
+ std::string result;
+ for (size_t i = 0; i < events.size(); ++i) {
+ if (i != 0)
+ result += " ";
+ result += EventTypeToString(events[i]);
+ }
+ return result;
+}
+
+} // namespace
+
+// Verifies a repost mouse event targets the window with capture (if there is
+// one).
+TEST_F(WindowEventDispatcherTest, RepostTargetsCaptureWindow) {
+ // Set capture on |window| generate a mouse event (that is reposted) and not
+ // over |window| and verify |window| gets it (|window| gets it because it has
+ // capture).
+ EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
+ EventFilterRecorder recorder;
+ scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL));
+ window->SetBounds(gfx::Rect(20, 20, 40, 30));
+ window->AddPreTargetHandler(&recorder);
+ window->SetCapture();
+ const ui::MouseEvent press_event(
+ ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ host()->dispatcher()->RepostEvent(press_event);
+ RunAllPendingInMessageLoop(); // Necessitated by RepostEvent().
+ // Mouse moves/enters may be generated. We only care about a pressed.
+ EXPECT_TRUE(EventTypesToString(recorder.events()).find("MOUSE_PRESSED") !=
+ std::string::npos) << EventTypesToString(recorder.events());
+}
+
+TEST_F(WindowEventDispatcherTest, MouseMovesHeld) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
+ gfx::Point(0, 0), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse_move_event);
+ // Discard MOUSE_ENTER.
+ recorder.Reset();
+
+ host()->dispatcher()->HoldPointerMoves();
+
+ // Check that we don't immediately dispatch the MOUSE_DRAGGED event.
+ ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0),
+ gfx::Point(0, 0), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ EXPECT_TRUE(recorder.events().empty());
+
+ // Check that we do dispatch the held MOUSE_DRAGGED event before another type
+ // of event.
+ ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
+ gfx::Point(0, 0), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
+ EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
+ EventTypesToString(recorder.events()));
+ recorder.Reset();
+
+ // Check that we coalesce held MOUSE_DRAGGED events.
+ ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
+ EXPECT_TRUE(recorder.events().empty());
+ DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
+ EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
+ EventTypesToString(recorder.events()));
+ recorder.Reset();
+
+ // Check that on ReleasePointerMoves, held events are not dispatched
+ // immediately, but posted instead.
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ host()->dispatcher()->ReleasePointerMoves();
+ EXPECT_TRUE(recorder.events().empty());
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events()));
+ recorder.Reset();
+
+ // However if another message comes in before the dispatch of the posted
+ // event, check that the posted event is dispatched before this new event.
+ host()->dispatcher()->HoldPointerMoves();
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ host()->dispatcher()->ReleasePointerMoves();
+ DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
+ EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
+ EventTypesToString(recorder.events()));
+ recorder.Reset();
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+
+ // Check that if the other message is another MOUSE_DRAGGED, we still coalesce
+ // them.
+ host()->dispatcher()->HoldPointerMoves();
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ host()->dispatcher()->ReleasePointerMoves();
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
+ EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events()));
+ recorder.Reset();
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+
+ // Check that synthetic mouse move event has a right location when issued
+ // while holding pointer moves.
+ ui::MouseEvent mouse_dragged_event3(ui::ET_MOUSE_DRAGGED, gfx::Point(28, 28),
+ gfx::Point(28, 28), 0, 0);
+ host()->dispatcher()->HoldPointerMoves();
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
+ window->SetBounds(gfx::Rect(15, 15, 80, 80));
+ DispatchEventUsingWindowDispatcher(&mouse_dragged_event3);
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+ host()->dispatcher()->ReleasePointerMoves();
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ("MOUSE_MOVED", EventTypesToString(recorder.events()));
+ EXPECT_EQ(gfx::Point(13, 13), recorder.mouse_location(0));
+ recorder.Reset();
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+TEST_F(WindowEventDispatcherTest, TouchMovesHeld) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
+
+ const gfx::Point touch_location(60, 60);
+ // Starting the touch and throwing out the first few events, since the system
+ // is going to generate synthetic mouse events that are not relevant to the
+ // test.
+ ui::TouchEvent touch_pressed_event(
+ ui::ET_TOUCH_PRESSED, touch_location, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&touch_pressed_event);
+ recorder.WaitUntilReceivedEvent(ui::ET_GESTURE_SHOW_PRESS);
+ recorder.Reset();
+
+ host()->dispatcher()->HoldPointerMoves();
+
+ // Check that we don't immediately dispatch the TOUCH_MOVED event.
+ ui::TouchEvent touch_moved_event(
+ ui::ET_TOUCH_MOVED, touch_location, 0, ui::EventTimeForNow());
+ ui::TouchEvent touch_moved_event2 = touch_moved_event;
+ ui::TouchEvent touch_moved_event3 = touch_moved_event;
+
+ DispatchEventUsingWindowDispatcher(&touch_moved_event);
+ EXPECT_TRUE(recorder.events().empty());
+
+ // Check that on ReleasePointerMoves, held events are not dispatched
+ // immediately, but posted instead.
+ DispatchEventUsingWindowDispatcher(&touch_moved_event2);
+ host()->dispatcher()->ReleasePointerMoves();
+ EXPECT_TRUE(recorder.events().empty());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ("TOUCH_MOVED", EventTypesToString(recorder.events()));
+ recorder.Reset();
+
+ // If another touch event occurs then the held touch should be dispatched
+ // immediately before it.
+ ui::TouchEvent touch_released_event(
+ ui::ET_TOUCH_RELEASED, touch_location, 0, ui::EventTimeForNow());
+ recorder.Reset();
+ host()->dispatcher()->HoldPointerMoves();
+ DispatchEventUsingWindowDispatcher(&touch_moved_event3);
+ DispatchEventUsingWindowDispatcher(&touch_released_event);
+ EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP GESTURE_END",
+ EventTypesToString(recorder.events()));
+ recorder.Reset();
+ host()->dispatcher()->ReleasePointerMoves();
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+}
+
+// This event handler requests the dispatcher to start holding pointer-move
+// events when it receives the first scroll-update gesture.
+class HoldPointerOnScrollHandler : public ui::test::TestEventHandler {
+ public:
+ HoldPointerOnScrollHandler(WindowEventDispatcher* dispatcher,
+ EventFilterRecorder* filter)
+ : dispatcher_(dispatcher),
+ filter_(filter),
+ holding_moves_(false) {}
+ virtual ~HoldPointerOnScrollHandler() {}
+
+ private:
+ // ui::test::TestEventHandler:
+ virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
+ if (!holding_moves_ && gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+ holding_moves_ = true;
+ dispatcher_->HoldPointerMoves();
+ filter_->Reset();
+ } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
+ dispatcher_->ReleasePointerMoves();
+ holding_moves_ = false;
+ }
+ }
+
+ WindowEventDispatcher* dispatcher_;
+ EventFilterRecorder* filter_;
+ bool holding_moves_;
+
+ DISALLOW_COPY_AND_ASSIGN(HoldPointerOnScrollHandler);
+};
+
+// Tests that touch-move events don't contribute to an in-progress scroll
+// gesture if touch-move events are being held by the dispatcher.
+TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+ test::TestWindowDelegate delegate;
+ HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
+ window->AddPreTargetHandler(&handler);
+
+ test::EventGenerator generator(root_window());
+ generator.GestureScrollSequence(
+ gfx::Point(60, 60), gfx::Point(10, 60),
+ base::TimeDelta::FromMilliseconds(100), 25);
+
+ // |handler| will have reset |filter| and started holding the touch-move
+ // events when scrolling started. At the end of the scroll (i.e. upon
+ // touch-release), the held touch-move event will have been dispatched first,
+ // along with the subsequent events (i.e. touch-release, scroll-end, and
+ // gesture-end).
+ const EventFilterRecorder::Events& events = recorder.events();
+ EXPECT_EQ(
+ "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
+ "GESTURE_SCROLL_END GESTURE_END",
+ EventTypesToString(events));
+ ASSERT_EQ(2u, recorder.touch_locations().size());
+ EXPECT_EQ(gfx::Point(-40, 10).ToString(),
+ recorder.touch_locations()[0].ToString());
+ EXPECT_EQ(gfx::Point(-40, 10).ToString(),
+ recorder.touch_locations()[1].ToString());
+}
+
+// Tests that a 'held' touch-event does contribute to gesture event when it is
+// dispatched.
+TEST_F(WindowEventDispatcherTest, HeldTouchMoveContributesToGesture) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ const gfx::Point location(20, 20);
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, location, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press);
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_PRESSED));
+ recorder.Reset();
+
+ host()->dispatcher()->HoldPointerMoves();
+
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED,
+ location + gfx::Vector2d(100, 100),
+ 0,
+ ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&move);
+ EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
+ EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN));
+ recorder.Reset();
+
+ host()->dispatcher()->ReleasePointerMoves();
+ EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_UPDATE));
+
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// Tests that synthetic mouse events are ignored when mouse
+// events are disabled.
+TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+ window->SetCapture();
+
+ test::TestCursorClient cursor_client(root_window());
+
+ // Dispatch a non-synthetic mouse event when mouse events are enabled.
+ ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse1);
+ EXPECT_FALSE(recorder.events().empty());
+ recorder.Reset();
+
+ // Dispatch a synthetic mouse event when mouse events are enabled.
+ ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED, 0);
+ DispatchEventUsingWindowDispatcher(&mouse2);
+ EXPECT_FALSE(recorder.events().empty());
+ recorder.Reset();
+
+ // Dispatch a synthetic mouse event when mouse events are disabled.
+ cursor_client.DisableMouseEvents();
+ DispatchEventUsingWindowDispatcher(&mouse2);
+ EXPECT_TRUE(recorder.events().empty());
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// Tests that a mouse-move event is not synthesized when a mouse-button is down.
+TEST_F(WindowEventDispatcherTest, DoNotSynthesizeWhileButtonDown) {
+ EventFilterRecorder recorder;
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+
+ window->AddPreTargetHandler(&recorder);
+ // Dispatch a non-synthetic mouse event when mouse events are enabled.
+ ui::MouseEvent mouse1(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10),
+ gfx::Point(10, 10), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ DispatchEventUsingWindowDispatcher(&mouse1);
+ ASSERT_EQ(1u, recorder.events().size());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.events()[0]);
+ window->RemovePreTargetHandler(&recorder);
+ recorder.Reset();
+
+ // Move |window| away from underneath the cursor.
+ root_window()->AddPreTargetHandler(&recorder);
+ window->SetBounds(gfx::Rect(30, 30, 100, 100));
+ EXPECT_TRUE(recorder.events().empty());
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// Tests synthetic mouse events generated when window bounds changes such that
+// the cursor previously outside the window becomes inside, or vice versa.
+// Do not synthesize events if the window ignores events or is invisible.
+TEST_F(WindowEventDispatcherTest, SynthesizeMouseEventsOnWindowBoundsChanged) {
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+ window->SetCapture();
+
+ EventFilterRecorder recorder;
+ window->AddPreTargetHandler(&recorder);
+
+ // Dispatch a non-synthetic mouse event to place cursor inside window bounds.
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse);
+ EXPECT_FALSE(recorder.events().empty());
+ recorder.Reset();
+
+ // Update the window bounds so that cursor is now outside the window.
+ // This should trigger a synthetic MOVED event.
+ gfx::Rect bounds1(20, 20, 100, 100);
+ window->SetBounds(bounds1);
+ RunAllPendingInMessageLoop();
+ ASSERT_FALSE(recorder.events().empty());
+ ASSERT_FALSE(recorder.mouse_event_flags().empty());
+ EXPECT_EQ(ui::ET_MOUSE_MOVED, recorder.events().back());
+ EXPECT_EQ(ui::EF_IS_SYNTHESIZED, recorder.mouse_event_flags().back());
+ recorder.Reset();
+
+ // Set window to ignore events.
+ window->set_ignore_events(true);
+
+ // Update the window bounds so that cursor is back inside the window.
+ // This should not trigger a synthetic event.
+ gfx::Rect bounds2(5, 5, 100, 100);
+ window->SetBounds(bounds2);
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+ recorder.Reset();
+
+ // Set window to accept events but invisible.
+ window->set_ignore_events(false);
+ window->Hide();
+ recorder.Reset();
+
+ // Update the window bounds so that cursor is outside the window.
+ // This should not trigger a synthetic event.
+ window->SetBounds(bounds1);
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(recorder.events().empty());
+}
+
+// Tests that a mouse exit is dispatched to the last known cursor location
+// when the cursor becomes invisible.
+TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ gfx::Point window_origin(7, 18);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)),
+ root_window()));
+ window->Show();
+
+ // Dispatch a mouse move event into the window.
+ gfx::Point mouse_location(gfx::Point(15, 25));
+ ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
+ mouse_location, 0, 0);
+ EXPECT_TRUE(recorder.events().empty());
+ DispatchEventUsingWindowDispatcher(&mouse1);
+ EXPECT_FALSE(recorder.events().empty());
+ recorder.Reset();
+
+ // Hide the cursor and verify a mouse exit was dispatched.
+ host()->OnCursorVisibilityChanged(false);
+ EXPECT_FALSE(recorder.events().empty());
+ EXPECT_EQ("MOUSE_EXITED", EventTypesToString(recorder.events()));
+
+ // Verify the mouse exit was dispatched at the correct location
+ // (in the correct coordinate space).
+ int translated_x = mouse_location.x() - window_origin.x();
+ int translated_y = mouse_location.y() - window_origin.y();
+ gfx::Point translated_point(translated_x, translated_y);
+ EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString());
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// Tests that a synthetic mouse exit is dispatched to the last known cursor
+// location after mouse events are disabled on the cursor client.
+TEST_F(WindowEventDispatcherTest,
+ DispatchSyntheticMouseExitAfterMouseEventsDisabled) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ gfx::Point window_origin(7, 18);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)),
+ root_window()));
+ window->Show();
+
+ // Dispatch a mouse move event into the window.
+ gfx::Point mouse_location(gfx::Point(15, 25));
+ ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
+ mouse_location, 0, 0);
+ EXPECT_TRUE(recorder.events().empty());
+ DispatchEventUsingWindowDispatcher(&mouse1);
+ EXPECT_FALSE(recorder.events().empty());
+ recorder.Reset();
+
+ test::TestCursorClient cursor_client(root_window());
+ cursor_client.DisableMouseEvents();
+
+ gfx::Point mouse_exit_location(gfx::Point(150, 150));
+ ui::MouseEvent mouse2(ui::ET_MOUSE_EXITED, gfx::Point(150, 150),
+ gfx::Point(150, 150), ui::EF_IS_SYNTHESIZED, 0);
+ DispatchEventUsingWindowDispatcher(&mouse2);
+
+ EXPECT_FALSE(recorder.events().empty());
+ // We get the mouse exited event twice in our filter. Once during the
+ // predispatch phase and during the actual dispatch.
+ EXPECT_EQ("MOUSE_EXITED MOUSE_EXITED", EventTypesToString(recorder.events()));
+
+ // Verify the mouse exit was dispatched at the correct location
+ // (in the correct coordinate space).
+ int translated_x = mouse_exit_location.x() - window_origin.x();
+ int translated_y = mouse_exit_location.y() - window_origin.y();
+ gfx::Point translated_point(translated_x, translated_y);
+ EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString());
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+class DeletingEventFilter : public ui::EventHandler {
+ public:
+ DeletingEventFilter()
+ : delete_during_pre_handle_(false) {}
+ virtual ~DeletingEventFilter() {}
+
+ void Reset(bool delete_during_pre_handle) {
+ delete_during_pre_handle_ = delete_during_pre_handle;
+ }
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ if (delete_during_pre_handle_)
+ delete event->target();
+ }
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ if (delete_during_pre_handle_)
+ delete event->target();
+ }
+
+ bool delete_during_pre_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter);
+};
+
+class DeletingWindowDelegate : public test::TestWindowDelegate {
+ public:
+ DeletingWindowDelegate()
+ : window_(NULL),
+ delete_during_handle_(false),
+ got_event_(false) {}
+ virtual ~DeletingWindowDelegate() {}
+
+ void Reset(Window* window, bool delete_during_handle) {
+ window_ = window;
+ delete_during_handle_ = delete_during_handle;
+ got_event_ = false;
+ }
+ bool got_event() const { return got_event_; }
+
+ private:
+ // Overridden from WindowDelegate:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ if (delete_during_handle_)
+ delete window_;
+ got_event_ = true;
+ }
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ if (delete_during_handle_)
+ delete window_;
+ got_event_ = true;
+ }
+
+ Window* window_;
+ bool delete_during_handle_;
+ bool got_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate);
+};
+
+TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) {
+ // Verifies that we can delete a window during each phase of event handling.
+ // Deleting the window should not cause a crash, only prevent further
+ // processing from occurring.
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
+ DeletingWindowDelegate d11;
+ Window* w11 = CreateNormalWindow(11, w1.get(), &d11);
+ WindowTracker tracker;
+ DeletingEventFilter w1_filter;
+ w1->AddPreTargetHandler(&w1_filter);
+ client::GetFocusClient(w1.get())->FocusWindow(w11);
+
+ test::EventGenerator generator(root_window(), w11);
+
+ // First up, no one deletes anything.
+ tracker.Add(w11);
+ d11.Reset(w11, false);
+
+ generator.PressLeftButton();
+ EXPECT_TRUE(tracker.Contains(w11));
+ EXPECT_TRUE(d11.got_event());
+ generator.ReleaseLeftButton();
+
+ // Delegate deletes w11. This will prevent the post-handle step from applying.
+ w1_filter.Reset(false);
+ d11.Reset(w11, true);
+ generator.PressKey(ui::VKEY_A, 0);
+ EXPECT_FALSE(tracker.Contains(w11));
+ EXPECT_TRUE(d11.got_event());
+
+ // Pre-handle step deletes w11. This will prevent the delegate and the post-
+ // handle steps from applying.
+ w11 = CreateNormalWindow(11, w1.get(), &d11);
+ w1_filter.Reset(true);
+ d11.Reset(w11, false);
+ generator.PressLeftButton();
+ EXPECT_FALSE(tracker.Contains(w11));
+ EXPECT_FALSE(d11.got_event());
+}
+
+namespace {
+
+// A window delegate that detaches the parent of the target's parent window when
+// it receives a tap event.
+class DetachesParentOnTapDelegate : public test::TestWindowDelegate {
+ public:
+ DetachesParentOnTapDelegate() {}
+ virtual ~DetachesParentOnTapDelegate() {}
+
+ private:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+ event->SetHandled();
+ return;
+ }
+
+ if (event->type() == ui::ET_GESTURE_TAP) {
+ Window* parent = static_cast<Window*>(event->target())->parent();
+ parent->parent()->RemoveChild(parent);
+ event->SetHandled();
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate);
+};
+
+} // namespace
+
+// Tests that the gesture recognizer is reset for all child windows when a
+// window hides. No expectations, just checks that the test does not crash.
+TEST_F(WindowEventDispatcherTest,
+ GestureRecognizerResetsTargetWhenParentHides) {
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
+ DetachesParentOnTapDelegate delegate;
+ scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL));
+ Window* child = CreateNormalWindow(11, parent.get(), &delegate);
+ test::EventGenerator generator(root_window(), child);
+ generator.GestureTapAt(gfx::Point(40, 40));
+}
+
+namespace {
+
+// A window delegate that processes nested gestures on tap.
+class NestedGestureDelegate : public test::TestWindowDelegate {
+ public:
+ NestedGestureDelegate(test::EventGenerator* generator,
+ const gfx::Point tap_location)
+ : generator_(generator),
+ tap_location_(tap_location),
+ gesture_end_count_(0) {}
+ virtual ~NestedGestureDelegate() {}
+
+ int gesture_end_count() const { return gesture_end_count_; }
+
+ private:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_TAP:
+ if (generator_)
+ generator_->GestureTapAt(tap_location_);
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_END:
+ ++gesture_end_count_;
+ break;
+ default:
+ break;
+ }
+ }
+
+ test::EventGenerator* generator_;
+ const gfx::Point tap_location_;
+ int gesture_end_count_;
+ DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate);
+};
+
+} // namespace
+
+// Tests that gesture end is delivered after nested gesture processing.
+TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) {
+ NestedGestureDelegate d1(NULL, gfx::Point());
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1));
+ w1->SetBounds(gfx::Rect(0, 0, 100, 100));
+
+ test::EventGenerator nested_generator(root_window(), w1.get());
+ NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint());
+ scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2));
+ w2->SetBounds(gfx::Rect(100, 0, 100, 100));
+
+ // Tap on w2 which triggers nested gestures for w1.
+ test::EventGenerator generator(root_window(), w2.get());
+ generator.GestureTapAt(w2->bounds().CenterPoint());
+
+ // Both windows should get their gesture end events.
+ EXPECT_EQ(1, d1.gesture_end_count());
+ EXPECT_EQ(1, d2.gesture_end_count());
+}
+
+// Tests whether we can repost the Tap down gesture event.
+TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f);
+ gfx::Point point(10, 10);
+ ui::GestureEvent event(ui::ET_GESTURE_TAP_DOWN,
+ point.x(),
+ point.y(),
+ 0,
+ ui::EventTimeForNow(),
+ details,
+ 0);
+ host()->dispatcher()->RepostEvent(event);
+ RunAllPendingInMessageLoop();
+ // TODO(rbyers): Currently disabled - crbug.com/170987
+ EXPECT_FALSE(EventTypesToString(recorder.events()).find("GESTURE_TAP_DOWN") !=
+ std::string::npos);
+ recorder.Reset();
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// This class inherits from the EventFilterRecorder class which provides a
+// facility to record events. This class additionally provides a facility to
+// repost the ET_GESTURE_TAP_DOWN gesture to the target window and records
+// events after that.
+class RepostGestureEventRecorder : public EventFilterRecorder {
+ public:
+ RepostGestureEventRecorder(aura::Window* repost_source,
+ aura::Window* repost_target)
+ : repost_source_(repost_source),
+ repost_target_(repost_target),
+ reposted_(false),
+ done_cleanup_(false) {}
+
+ virtual ~RepostGestureEventRecorder() {}
+
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
+ if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) {
+ done_cleanup_ = true;
+ Reset();
+ }
+ EventFilterRecorder::OnTouchEvent(event);
+ }
+
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target());
+ if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+ if (!reposted_) {
+ EXPECT_NE(repost_target_, event->target());
+ reposted_ = true;
+ repost_target_->GetHost()->dispatcher()->RepostEvent(*event);
+ // Ensure that the reposted gesture event above goes to the
+ // repost_target_;
+ repost_source_->GetRootWindow()->RemoveChild(repost_source_);
+ return;
+ }
+ }
+ EventFilterRecorder::OnGestureEvent(event);
+ }
+
+ // Ignore mouse events as they don't fire at all times. This causes
+ // the GestureRepostEventOrder test to fail randomly.
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {}
+
+ private:
+ aura::Window* repost_source_;
+ aura::Window* repost_target_;
+ // set to true if we reposted the ET_GESTURE_TAP_DOWN event.
+ bool reposted_;
+ // set true if we're done cleaning up after hiding repost_source_;
+ bool done_cleanup_;
+ DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder);
+};
+
+// Tests whether events which are generated after the reposted gesture event
+// are received after that. In this case the scroll sequence events should
+// be received after the reposted gesture event.
+TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) {
+ // Expected events at the end for the repost_target window defined below.
+ const char kExpectedTargetEvents[] =
+ // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039.
+ // "GESTURE_BEGIN GESTURE_TAP_DOWN "
+ "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
+ "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED "
+ "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
+ "GESTURE_SCROLL_END GESTURE_END";
+ // We create two windows.
+ // The first window (repost_source) is the one to which the initial tap
+ // gesture is sent. It reposts this event to the second window
+ // (repost_target).
+ // We then generate the scroll sequence for repost_target and look for two
+ // ET_GESTURE_TAP_DOWN events in the event list at the end.
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window()));
+
+ RepostGestureEventRecorder repost_event_recorder(repost_source.get(),
+ repost_target.get());
+ root_window()->AddPreTargetHandler(&repost_event_recorder);
+
+ // Generate a tap down gesture for the repost_source. This will be reposted
+ // to repost_target.
+ test::EventGenerator repost_generator(root_window(), repost_source.get());
+ repost_generator.GestureTapAt(gfx::Point(40, 40));
+ RunAllPendingInMessageLoop();
+
+ test::EventGenerator scroll_generator(root_window(), repost_target.get());
+ scroll_generator.GestureScrollSequence(
+ gfx::Point(80, 80),
+ gfx::Point(100, 100),
+ base::TimeDelta::FromMilliseconds(100),
+ 3);
+ RunAllPendingInMessageLoop();
+
+ int tap_down_count = 0;
+ for (size_t i = 0; i < repost_event_recorder.events().size(); ++i) {
+ if (repost_event_recorder.events()[i] == ui::ET_GESTURE_TAP_DOWN)
+ ++tap_down_count;
+ }
+
+ // We expect two tap down events. One from the repost and the other one from
+ // the scroll sequence posted above.
+ // TODO(rbyers): Currently disabled - crbug.com/170987
+ EXPECT_EQ(1, tap_down_count);
+
+ EXPECT_EQ(kExpectedTargetEvents,
+ EventTypesToString(repost_event_recorder.events()));
+ root_window()->RemovePreTargetHandler(&repost_event_recorder);
+}
+
+class OnMouseExitDeletingEventFilter : public EventFilterRecorder {
+ public:
+ OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {}
+ virtual ~OnMouseExitDeletingEventFilter() {}
+
+ void set_window_to_delete(Window* window_to_delete) {
+ window_to_delete_ = window_to_delete;
+ }
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ EventFilterRecorder::OnMouseEvent(event);
+ if (window_to_delete_) {
+ delete window_to_delete_;
+ window_to_delete_ = NULL;
+ }
+ }
+
+ Window* window_to_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter);
+};
+
+// Tests that RootWindow drops mouse-moved event that is supposed to be sent to
+// a child, but the child is destroyed because of the synthesized mouse-exit
+// event generated on the previous mouse_moved_handler_.
+TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {
+ // Create window 1 and set its event filter. Window 1 will take ownership of
+ // the event filter.
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
+ OnMouseExitDeletingEventFilter w1_filter;
+ w1->AddPreTargetHandler(&w1_filter);
+ w1->SetBounds(gfx::Rect(20, 20, 60, 60));
+ EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler());
+
+ test::EventGenerator generator(root_window(), w1.get());
+
+ // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the
+ // root window.
+ generator.MoveMouseTo(51, 51);
+ EXPECT_EQ(w1.get(), host()->dispatcher()->mouse_moved_handler());
+
+ // Create window 2 under the mouse cursor and stack it above window 1.
+ Window* w2 = CreateNormalWindow(2, root_window(), NULL);
+ w2->SetBounds(gfx::Rect(30, 30, 40, 40));
+ root_window()->StackChildAbove(w2, w1.get());
+
+ // Set window 2 as the window that is to be deleted when a mouse-exited event
+ // happens on window 1.
+ w1_filter.set_window_to_delete(w2);
+
+ // Move mosue over window 2. This should generate a mouse-exited event for
+ // window 1 resulting in deletion of window 2. The original mouse-moved event
+ // that was targeted to window 2 should be dropped since window 2 is
+ // destroyed. This test passes if no crash happens.
+ generator.MoveMouseTo(52, 52);
+ EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler());
+
+ // Check events received by window 1.
+ EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED",
+ EventTypesToString(w1_filter.events()));
+}
+
+namespace {
+
+// Used to track if OnWindowDestroying() is invoked and if there is a valid
+// RootWindow at such time.
+class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver {
+ public:
+ ValidRootDuringDestructionWindowObserver(bool* got_destroying,
+ bool* has_valid_root)
+ : got_destroying_(got_destroying),
+ has_valid_root_(has_valid_root) {
+ }
+
+ // WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ *got_destroying_ = true;
+ *has_valid_root_ = (window->GetRootWindow() != NULL);
+ }
+
+ private:
+ bool* got_destroying_;
+ bool* has_valid_root_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver);
+};
+
+} // namespace
+
+// Verifies GetRootWindow() from ~Window returns a valid root.
+TEST_F(WindowEventDispatcherTest, ValidRootDuringDestruction) {
+ bool got_destroying = false;
+ bool has_valid_root = false;
+ ValidRootDuringDestructionWindowObserver observer(&got_destroying,
+ &has_valid_root);
+ {
+ scoped_ptr<WindowTreeHost> host(
+ WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100)));
+ host->InitHost();
+ // Owned by WindowEventDispatcher.
+ Window* w1 = CreateNormalWindow(1, host->window(), NULL);
+ w1->AddObserver(&observer);
+ }
+ EXPECT_TRUE(got_destroying);
+ EXPECT_TRUE(has_valid_root);
+}
+
+namespace {
+
+// See description above DontResetHeldEvent for details.
+class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {
+ public:
+ explicit DontResetHeldEventWindowDelegate(aura::Window* root)
+ : root_(root),
+ mouse_event_count_(0) {}
+ virtual ~DontResetHeldEventWindowDelegate() {}
+
+ int mouse_event_count() const { return mouse_event_count_; }
+
+ // TestWindowDelegate:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
+ mouse_event_count_++ == 0) {
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
+ gfx::Point(10, 10), gfx::Point(10, 10),
+ ui::EF_SHIFT_DOWN, 0);
+ root_->GetHost()->dispatcher()->RepostEvent(mouse_event);
+ }
+ }
+
+ private:
+ Window* root_;
+ int mouse_event_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate);
+};
+
+} // namespace
+
+// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
+// dispatching. This is done by using DontResetHeldEventWindowDelegate, which
+// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
+// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
+// schedule another reposted event.
+TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) {
+ DontResetHeldEventWindowDelegate delegate(root_window());
+ scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
+ w1->SetBounds(gfx::Rect(0, 0, 40, 40));
+ ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+ gfx::Point(10, 10), gfx::Point(10, 10),
+ ui::EF_SHIFT_DOWN, 0);
+ root_window()->GetHost()->dispatcher()->RepostEvent(pressed);
+ ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED,
+ gfx::Point(10, 10), gfx::Point(10, 10), 0, 0);
+ // Dispatch an event to flush event scheduled by way of RepostEvent().
+ DispatchEventUsingWindowDispatcher(&pressed2);
+ // Delegate should have seen reposted event (identified by way of
+ // EF_SHIFT_DOWN). Dispatch another event to flush the second
+ // RepostedEvent().
+ EXPECT_EQ(1, delegate.mouse_event_count());
+ DispatchEventUsingWindowDispatcher(&pressed2);
+ EXPECT_EQ(2, delegate.mouse_event_count());
+}
+
+namespace {
+
+// See description above DeleteHostFromHeldMouseEvent for details.
+class DeleteHostFromHeldMouseEventDelegate
+ : public test::TestWindowDelegate {
+ public:
+ explicit DeleteHostFromHeldMouseEventDelegate(WindowTreeHost* host)
+ : host_(host),
+ got_mouse_event_(false),
+ got_destroy_(false) {
+ }
+ virtual ~DeleteHostFromHeldMouseEventDelegate() {}
+
+ bool got_mouse_event() const { return got_mouse_event_; }
+ bool got_destroy() const { return got_destroy_; }
+
+ // TestWindowDelegate:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) {
+ got_mouse_event_ = true;
+ delete host_;
+ }
+ }
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
+ got_destroy_ = true;
+ }
+
+ private:
+ WindowTreeHost* host_;
+ bool got_mouse_event_;
+ bool got_destroy_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteHostFromHeldMouseEventDelegate);
+};
+
+} // namespace
+
+// Verifies if a WindowTreeHost is deleted from dispatching a held mouse event
+// we don't crash.
+TEST_F(WindowEventDispatcherTest, DeleteHostFromHeldMouseEvent) {
+ // Should be deleted by |delegate|.
+ WindowTreeHost* h2 = WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100));
+ h2->InitHost();
+ DeleteHostFromHeldMouseEventDelegate delegate(h2);
+ // Owned by |h2|.
+ Window* w1 = CreateNormalWindow(1, h2->window(), &delegate);
+ w1->SetBounds(gfx::Rect(0, 0, 40, 40));
+ ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+ gfx::Point(10, 10), gfx::Point(10, 10),
+ ui::EF_SHIFT_DOWN, 0);
+ h2->dispatcher()->RepostEvent(pressed);
+ // RunAllPendingInMessageLoop() to make sure the |pressed| is run.
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(delegate.got_mouse_event());
+ EXPECT_TRUE(delegate.got_destroy());
+}
+
+TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ gfx::Point position1 = root_window()->bounds().origin();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press);
+
+ EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN",
+ EventTypesToString(recorder.GetAndResetEvents()));
+
+ window->Hide();
+
+ EXPECT_EQ(ui::ET_TOUCH_CANCELLED, recorder.events()[0]);
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_TAP_CANCEL));
+ EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_END));
+ EXPECT_EQ(3U, recorder.events().size());
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+ gfx::Point position1 = root_window()->bounds().origin();
+ gfx::Point position2 = root_window()->bounds().CenterPoint();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press);
+
+ ui::TouchEvent move(
+ ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&move);
+
+ ui::TouchEvent press2(
+ ui::ET_TOUCH_PRESSED, position1, 1, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press2);
+
+ // TODO(tdresser): once the unified Gesture Recognizer has stuck, remove the
+ // special casing here. See crbug.com/332418 for details.
+ std::string expected =
+ "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
+ "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
+ "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN";
+
+ std::string expected_ugr =
+ "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
+ "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
+ "TOUCH_PRESSED GESTURE_BEGIN";
+
+ std::string events_string = EventTypesToString(recorder.GetAndResetEvents());
+ EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string));
+
+ window->Hide();
+
+ expected =
+ "TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED "
+ "GESTURE_SCROLL_END GESTURE_END";
+ expected_ugr =
+ "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END GESTURE_END "
+ "TOUCH_CANCELLED";
+
+ events_string = EventTypesToString(recorder.GetAndResetEvents());
+ EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string));
+
+ root_window()->RemovePreTargetHandler(&recorder);
+}
+
+// Places two windows side by side. Presses down on one window, and starts a
+// scroll. Sets capture on the other window and ensures that the "ending" events
+// aren't sent to the window which gained capture.
+TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) {
+ EventFilterRecorder recorder1;
+ EventFilterRecorder recorder2;
+ scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL));
+ window1->SetBounds(gfx::Rect(0, 0, 40, 40));
+
+ scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL));
+ window2->SetBounds(gfx::Rect(40, 0, 40, 40));
+
+ window1->AddPreTargetHandler(&recorder1);
+ window2->AddPreTargetHandler(&recorder2);
+
+ gfx::Point position = window1->bounds().origin();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&press);
+
+ gfx::Point position2 = window1->bounds().CenterPoint();
+ ui::TouchEvent move(
+ ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow());
+ DispatchEventUsingWindowDispatcher(&move);
+
+ window2->SetCapture();
+
+ EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
+ "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
+ "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END",
+ EventTypesToString(recorder1.events()));
+
+ EXPECT_TRUE(recorder2.events().empty());
+}
+
+namespace {
+
+// This class creates and manages a window which is destroyed as soon as
+// capture is lost. This is the case for the drag and drop capture window.
+class CaptureWindowTracker : public test::TestWindowDelegate {
+ public:
+ CaptureWindowTracker() {}
+ virtual ~CaptureWindowTracker() {}
+
+ void CreateCaptureWindow(aura::Window* root_window) {
+ capture_window_.reset(test::CreateTestWindowWithDelegate(
+ this, -1234, gfx::Rect(20, 20, 20, 20), root_window));
+ capture_window_->SetCapture();
+ }
+
+ void reset() {
+ capture_window_.reset();
+ }
+
+ virtual void OnCaptureLost() OVERRIDE {
+ capture_window_.reset();
+ }
+
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
+ TestWindowDelegate::OnWindowDestroyed(window);
+ capture_window_.reset();
+ }
+
+ aura::Window* capture_window() { return capture_window_.get(); }
+
+ private:
+ scoped_ptr<aura::Window> capture_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(CaptureWindowTracker);
+};
+
+}
+
+// Verifies handling loss of capture by the capture window being hidden.
+TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) {
+ CaptureWindowTracker capture_window_tracker;
+ capture_window_tracker.CreateCaptureWindow(root_window());
+ capture_window_tracker.capture_window()->Hide();
+ EXPECT_EQ(NULL, capture_window_tracker.capture_window());
+}
+
+// Verifies handling loss of capture by the capture window being destroyed.
+TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) {
+ CaptureWindowTracker capture_window_tracker;
+ capture_window_tracker.CreateCaptureWindow(root_window());
+ capture_window_tracker.reset();
+ EXPECT_EQ(NULL, capture_window_tracker.capture_window());
+}
+
+class ExitMessageLoopOnMousePress : public ui::test::TestEventHandler {
+ public:
+ ExitMessageLoopOnMousePress() {}
+ virtual ~ExitMessageLoopOnMousePress() {}
+
+ protected:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ ui::test::TestEventHandler::OnMouseEvent(event);
+ if (event->type() == ui::ET_MOUSE_PRESSED)
+ base::MessageLoopForUI::current()->Quit();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress);
+};
+
+class WindowEventDispatcherTestWithMessageLoop
+ : public WindowEventDispatcherTest {
+ public:
+ WindowEventDispatcherTestWithMessageLoop() {}
+ virtual ~WindowEventDispatcherTestWithMessageLoop() {}
+
+ void RunTest() {
+ // Reset any event the window may have received when bringing up the window
+ // (e.g. mouse-move events if the mouse cursor is over the window).
+ handler_.Reset();
+
+ // Start a nested message-loop, post an event to be dispatched, and then
+ // terminate the message-loop. When the message-loop unwinds and gets back,
+ // the reposted event should not have fired.
+ scoped_ptr<ui::MouseEvent> mouse(new ui::MouseEvent(ui::ET_MOUSE_PRESSED,
+ gfx::Point(10, 10),
+ gfx::Point(10, 10),
+ ui::EF_NONE,
+ ui::EF_NONE));
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&WindowEventDispatcherTestWithMessageLoop::RepostEventHelper,
+ host()->dispatcher(),
+ base::Passed(&mouse)));
+ message_loop()->PostTask(FROM_HERE, message_loop()->QuitClosure());
+
+ base::MessageLoop::ScopedNestableTaskAllower allow(message_loop());
+ base::RunLoop loop;
+ loop.Run();
+ EXPECT_EQ(0, handler_.num_mouse_events());
+
+ // Let the current message-loop run. The event-handler will terminate the
+ // message-loop when it receives the reposted event.
+ }
+
+ base::MessageLoop* message_loop() {
+ return base::MessageLoopForUI::current();
+ }
+
+ protected:
+ virtual void SetUp() OVERRIDE {
+ WindowEventDispatcherTest::SetUp();
+ window_.reset(CreateNormalWindow(1, root_window(), NULL));
+ window_->AddPreTargetHandler(&handler_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ window_.reset();
+ WindowEventDispatcherTest::TearDown();
+ }
+
+ private:
+ // Used to avoid a copying |event| when binding to a closure.
+ static void RepostEventHelper(WindowEventDispatcher* dispatcher,
+ scoped_ptr<ui::MouseEvent> event) {
+ dispatcher->RepostEvent(*event);
+ }
+
+ scoped_ptr<Window> window_;
+ ExitMessageLoopOnMousePress handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcherTestWithMessageLoop);
+};
+
+TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {
+ CHECK(!message_loop()->is_running());
+ // Perform the test in a callback, so that it runs after the message-loop
+ // starts.
+ message_loop()->PostTask(
+ FROM_HERE, base::Bind(
+ &WindowEventDispatcherTestWithMessageLoop::RunTest,
+ base::Unretained(this)));
+ message_loop()->Run();
+}
+
+class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest {
+ public:
+ WindowEventDispatcherTestInHighDPI() {}
+ virtual ~WindowEventDispatcherTestInHighDPI() {}
+
+ protected:
+ virtual void SetUp() OVERRIDE {
+ WindowEventDispatcherTest::SetUp();
+ test_screen()->SetDeviceScaleFactor(2.f);
+ }
+};
+
+TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) {
+ test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> child(test::CreateTestWindowWithDelegate(&delegate,
+ 1234, gfx::Rect(20, 20, 100, 100), root_window()));
+ child->Show();
+
+ ui::test::TestEventHandler handler_child;
+ ui::test::TestEventHandler handler_root;
+ root_window()->AddPreTargetHandler(&handler_root);
+ child->AddPreTargetHandler(&handler_child);
+
+ {
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED,
+ gfx::Point(30, 30), gfx::Point(30, 30),
+ ui::EF_NONE, ui::EF_NONE);
+ DispatchEventUsingWindowDispatcher(&move);
+ EXPECT_EQ(0, handler_child.num_mouse_events());
+ EXPECT_EQ(1, handler_root.num_mouse_events());
+ }
+
+ {
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED,
+ gfx::Point(50, 50), gfx::Point(50, 50),
+ ui::EF_NONE, ui::EF_NONE);
+ DispatchEventUsingWindowDispatcher(&move);
+ // The child receives an ENTER, and a MOVED event.
+ EXPECT_EQ(2, handler_child.num_mouse_events());
+ // The root receives both the ENTER and the MOVED events dispatched to
+ // |child|, as well as an EXIT event.
+ EXPECT_EQ(3, handler_root.num_mouse_events());
+ }
+
+ child->RemovePreTargetHandler(&handler_child);
+ root_window()->RemovePreTargetHandler(&handler_root);
+}
+
+TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) {
+ EventFilterRecorder recorder;
+ root_window()->AddPreTargetHandler(&recorder);
+ test::TestWindowDelegate delegate;
+ HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder);
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
+ window->AddPreTargetHandler(&handler);
+
+ test::EventGenerator generator(root_window());
+ generator.GestureScrollSequence(
+ gfx::Point(120, 120), gfx::Point(20, 120),
+ base::TimeDelta::FromMilliseconds(100), 25);
+
+ // |handler| will have reset |filter| and started holding the touch-move
+ // events when scrolling started. At the end of the scroll (i.e. upon
+ // touch-release), the held touch-move event will have been dispatched first,
+ // along with the subsequent events (i.e. touch-release, scroll-end, and
+ // gesture-end).
+ const EventFilterRecorder::Events& events = recorder.events();
+ EXPECT_EQ(
+ "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
+ "GESTURE_SCROLL_END GESTURE_END",
+ EventTypesToString(events));
+ ASSERT_EQ(2u, recorder.touch_locations().size());
+ EXPECT_EQ(gfx::Point(-40, 10).ToString(),
+ recorder.touch_locations()[0].ToString());
+ EXPECT_EQ(gfx::Point(-40, 10).ToString(),
+ recorder.touch_locations()[1].ToString());
+}
+
+class SelfDestructDelegate : public test::TestWindowDelegate {
+ public:
+ SelfDestructDelegate() {}
+ virtual ~SelfDestructDelegate() {}
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ window_.reset();
+ }
+
+ void set_window(scoped_ptr<aura::Window> window) {
+ window_ = window.Pass();
+ }
+ bool has_window() const { return !!window_.get(); }
+
+ private:
+ scoped_ptr<aura::Window> window_;
+ DISALLOW_COPY_AND_ASSIGN(SelfDestructDelegate);
+};
+
+TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) {
+ test::EventGenerator generator(root_window());
+ generator.MoveMouseTo(10, 10);
+ EXPECT_EQ("10,10",
+ Env::GetInstance()->last_mouse_location().ToString());
+
+ // Synthesized event should not update the mouse location.
+ ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
+ ui::EF_IS_SYNTHESIZED, 0);
+ generator.Dispatch(&mouseev);
+ EXPECT_EQ("10,10",
+ Env::GetInstance()->last_mouse_location().ToString());
+
+ generator.MoveMouseTo(0, 0);
+ EXPECT_EQ("0,0",
+ Env::GetInstance()->last_mouse_location().ToString());
+
+ // Make sure the location gets updated when a syntheiszed enter
+ // event destroyed the window.
+ SelfDestructDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+ &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
+ delegate.set_window(window.Pass());
+ EXPECT_TRUE(delegate.has_window());
+
+ generator.MoveMouseTo(100, 100);
+ EXPECT_FALSE(delegate.has_window());
+ EXPECT_EQ("100,100",
+ Env::GetInstance()->last_mouse_location().ToString());
+}
+
+class StaticFocusClient : public client::FocusClient {
+ public:
+ explicit StaticFocusClient(Window* focused)
+ : focused_(focused) {}
+ virtual ~StaticFocusClient() {}
+
+ private:
+ // client::FocusClient:
+ virtual void AddObserver(client::FocusChangeObserver* observer) OVERRIDE {}
+ virtual void RemoveObserver(client::FocusChangeObserver* observer) OVERRIDE {}
+ virtual void FocusWindow(Window* window) OVERRIDE {}
+ virtual void ResetFocusWithinActiveWindow(Window* window) OVERRIDE {}
+ virtual Window* GetFocusedWindow() OVERRIDE { return focused_; }
+
+ Window* focused_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticFocusClient);
+};
+
+// Tests that host-cancel-mode event can be dispatched to a dispatcher safely
+// when the focused window does not live in the dispatcher's tree.
+TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) {
+ test::TestWindowDelegate delegate;
+ scoped_ptr<Window> focused(CreateTestWindowWithDelegate(&delegate, 123,
+ gfx::Rect(20, 30, 100, 50), NULL));
+ StaticFocusClient focus_client(focused.get());
+ client::SetFocusClient(root_window(), &focus_client);
+ EXPECT_FALSE(root_window()->Contains(focused.get()));
+ EXPECT_EQ(focused.get(),
+ client::GetFocusClient(root_window())->GetFocusedWindow());
+ host()->dispatcher()->DispatchCancelModeEvent();
+ EXPECT_EQ(focused.get(),
+ client::GetFocusClient(root_window())->GetFocusedWindow());
+}
+
+// Dispatches a mouse-move event to |target| when it receives a mouse-move
+// event.
+class DispatchEventHandler : public ui::EventHandler {
+ public:
+ explicit DispatchEventHandler(Window* target)
+ : target_(target),
+ dispatched_(false) {}
+ virtual ~DispatchEventHandler() {}
+
+ bool dispatched() const { return dispatched_; }
+ private:
+ // ui::EventHandler:
+ virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
+ if (mouse->type() == ui::ET_MOUSE_MOVED) {
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, target_->bounds().CenterPoint(),
+ target_->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE);
+ ui::EventDispatchDetails details =
+ target_->GetHost()->dispatcher()->OnEventFromSource(&move);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_EQ(target_, move.target());
+ dispatched_ = true;
+ }
+ ui::EventHandler::OnMouseEvent(mouse);
+ }
+
+ Window* target_;
+ bool dispatched_;
+
+ DISALLOW_COPY_AND_ASSIGN(DispatchEventHandler);
+};
+
+// Moves |window| to |root_window| when it receives a mouse-move event.
+class MoveWindowHandler : public ui::EventHandler {
+ public:
+ MoveWindowHandler(Window* window, Window* root_window)
+ : window_to_move_(window),
+ root_window_to_move_to_(root_window) {}
+ virtual ~MoveWindowHandler() {}
+
+ private:
+ // ui::EventHandler:
+ virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
+ if (mouse->type() == ui::ET_MOUSE_MOVED) {
+ root_window_to_move_to_->AddChild(window_to_move_);
+ }
+ ui::EventHandler::OnMouseEvent(mouse);
+ }
+
+ Window* window_to_move_;
+ Window* root_window_to_move_to_;
+
+ DISALLOW_COPY_AND_ASSIGN(MoveWindowHandler);
+};
+
+// Tests that nested event dispatch works correctly if the target of the older
+// event being dispatched is moved to a different dispatcher in response to an
+// event in the inner loop.
+TEST_F(WindowEventDispatcherTest, NestedEventDispatchTargetMoved) {
+ scoped_ptr<WindowTreeHost> second_host(
+ WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50)));
+ second_host->InitHost();
+ Window* second_root = second_host->window();
+
+ // Create two windows parented to |root_window()|.
+ test::TestWindowDelegate delegate;
+ scoped_ptr<Window> first(CreateTestWindowWithDelegate(&delegate, 123,
+ gfx::Rect(20, 10, 10, 20), root_window()));
+ scoped_ptr<Window> second(CreateTestWindowWithDelegate(&delegate, 234,
+ gfx::Rect(40, 10, 50, 20), root_window()));
+
+ // Setup a handler on |first| so that it dispatches an event to |second| when
+ // |first| receives an event.
+ DispatchEventHandler dispatch_event(second.get());
+ first->AddPreTargetHandler(&dispatch_event);
+
+ // Setup a handler on |second| so that it moves |first| into |second_root|
+ // when |second| receives an event.
+ MoveWindowHandler move_window(first.get(), second_root);
+ second->AddPreTargetHandler(&move_window);
+
+ // Some sanity checks: |first| is inside |root_window()|'s tree.
+ EXPECT_EQ(root_window(), first->GetRootWindow());
+ // The two root windows are different.
+ EXPECT_NE(root_window(), second_root);
+
+ // Dispatch an event to |first|.
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, first->bounds().CenterPoint(),
+ first->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE);
+ ui::EventDispatchDetails details =
+ host()->dispatcher()->OnEventFromSource(&move);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ EXPECT_TRUE(details.target_destroyed);
+ EXPECT_EQ(first.get(), move.target());
+ EXPECT_TRUE(dispatch_event.dispatched());
+ EXPECT_EQ(second_root, first->GetRootWindow());
+
+ first->RemovePreTargetHandler(&dispatch_event);
+ second->RemovePreTargetHandler(&move_window);
+}
+
+class AlwaysMouseDownInputStateLookup : public InputStateLookup {
+ public:
+ AlwaysMouseDownInputStateLookup() {}
+ virtual ~AlwaysMouseDownInputStateLookup() {}
+
+ private:
+ // InputStateLookup:
+ virtual bool IsMouseButtonDown() const OVERRIDE { return true; }
+
+ DISALLOW_COPY_AND_ASSIGN(AlwaysMouseDownInputStateLookup);
+};
+
+TEST_F(WindowEventDispatcherTest,
+ CursorVisibilityChangedWhileCaptureWindowInAnotherDispatcher) {
+ test::EventCountDelegate delegate;
+ scoped_ptr<Window> window(CreateTestWindowWithDelegate(&delegate, 123,
+ gfx::Rect(20, 10, 10, 20), root_window()));
+ window->Show();
+
+ scoped_ptr<WindowTreeHost> second_host(
+ WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50)));
+ second_host->InitHost();
+ WindowEventDispatcher* second_dispatcher = second_host->dispatcher();
+
+ // Install an InputStateLookup on the Env that always claims that a
+ // mouse-button is down.
+ test::EnvTestHelper(Env::GetInstance()).SetInputStateLookup(
+ scoped_ptr<InputStateLookup>(new AlwaysMouseDownInputStateLookup()));
+
+ window->SetCapture();
+
+ // Because the mouse button is down, setting the capture on |window| will set
+ // it as the mouse-move handler for |root_window()|.
+ EXPECT_EQ(window.get(), host()->dispatcher()->mouse_moved_handler());
+
+ // This does not set |window| as the mouse-move handler for the second
+ // dispatcher.
+ EXPECT_EQ(NULL, second_dispatcher->mouse_moved_handler());
+
+ // However, some capture-client updates the capture in each root-window on a
+ // capture. Emulate that here. Because of this, the second dispatcher also has
+ // |window| as the mouse-move handler.
+ client::CaptureDelegate* second_capture_delegate = second_dispatcher;
+ second_capture_delegate->UpdateCapture(NULL, window.get());
+ EXPECT_EQ(window.get(), second_dispatcher->mouse_moved_handler());
+
+ // Reset the mouse-event counts for |window|.
+ delegate.GetMouseMotionCountsAndReset();
+
+ // Notify both hosts that the cursor is now hidden. This should send a single
+ // mouse-exit event to |window|.
+ host()->OnCursorVisibilityChanged(false);
+ second_host->OnCursorVisibilityChanged(false);
+ EXPECT_EQ("0 0 1", delegate.GetMouseMotionCountsAndReset());
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_observer.cc b/chromium/ui/aura/window_observer.cc
new file mode 100644
index 00000000000..24d51d47df0
--- /dev/null
+++ b/chromium/ui/aura/window_observer.cc
@@ -0,0 +1,31 @@
+// 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/aura/window_observer.h"
+
+#include "base/logging.h"
+#include "ui/aura/window.h"
+
+namespace aura {
+
+WindowObserver::WindowObserver() : observing_(0) {
+}
+
+WindowObserver::~WindowObserver() {
+ // TODO(flackr): Remove this check and observing_ counter when the cause of
+ // http://crbug.com/365364 is discovered.
+ CHECK_EQ(0, observing_);
+}
+
+void WindowObserver::OnObservingWindow(aura::Window* window) {
+ if (!window->HasObserver(this))
+ observing_++;
+}
+
+void WindowObserver::OnUnobservingWindow(aura::Window* window) {
+ if (window->HasObserver(this))
+ observing_--;
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_observer.h b/chromium/ui/aura/window_observer.h
index 9408ee831dd..ef1259a234d 100644
--- a/chromium/ui/aura/window_observer.h
+++ b/chromium/ui/aura/window_observer.h
@@ -31,6 +31,8 @@ class AURA_EXPORT WindowObserver {
Window* receiver; // The window receiving the notification.
};
+ WindowObserver();
+
// Called when a window is added or removed. Notifications are sent to the
// following hierarchies in this order:
// 1. |target|.
@@ -75,6 +77,10 @@ class AURA_EXPORT WindowObserver {
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {}
+ // Invoked when SetTransform() is invoked on |window|.
+ virtual void OnWindowTransforming(Window* window) {}
+ virtual void OnWindowTransformed(Window* window) {}
+
// Invoked when |window|'s position among its siblings in the stacking order
// has changed.
virtual void OnWindowStackingChanged(Window* window) {}
@@ -100,17 +106,29 @@ class AURA_EXPORT WindowObserver {
// Called when a Window has been added to a RootWindow.
virtual void OnWindowAddedToRootWindow(Window* window) {}
- // Called when a Window is about to be removed from a RootWindow.
- virtual void OnWindowRemovingFromRootWindow(Window* window) {}
+ // Called when a Window is about to be removed from a root Window.
+ // |new_root| contains the new root Window if it is being added to one
+ // atomically.
+ virtual void OnWindowRemovingFromRootWindow(Window* window,
+ Window* new_root) {}
- // Called when a transient child is added to |window|.
- virtual void OnAddTransientChild(Window* window, Window* transient) {}
+ protected:
+ virtual ~WindowObserver();
- // Called when a transient child is removed from |window|.
- virtual void OnRemoveTransientChild(Window* window, Window* transient) {}
+ private:
+ friend class Window;
- protected:
- virtual ~WindowObserver() {}
+ // Called when this is added as an observer on |window|.
+ void OnObservingWindow(Window* window);
+
+ // Called when this is removed from the observers on |window|.
+ void OnUnobservingWindow(Window* window);
+
+ // Tracks the number of windows being observed to track down
+ // http://crbug.com/365364.
+ int observing_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowObserver);
};
} // namespace aura
diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc
index 586392bcdc8..601321525e8 100644
--- a/chromium/ui/aura/window_targeter.cc
+++ b/chromium/ui/aura/window_targeter.cc
@@ -7,9 +7,10 @@
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/event_client.h"
#include "ui/aura/client/focus_client.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/events/event_target.h"
namespace aura {
@@ -19,29 +20,28 @@ WindowTargeter::~WindowTargeter() {}
ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) {
- if (event->IsKeyEvent()) {
- Window* window = static_cast<Window*>(root);
- Window* root_window = window->GetRootWindow();
- const ui::KeyEvent& key = static_cast<const ui::KeyEvent&>(*event);
- if (key.key_code() == ui::VKEY_UNKNOWN)
- return NULL;
- client::EventClient* event_client = client::GetEventClient(root_window);
- client::FocusClient* focus_client = client::GetFocusClient(root_window);
- Window* focused_window = focus_client->GetFocusedWindow();
- if (event_client &&
- !event_client->CanProcessEventsWithinSubtree(focused_window)) {
- focus_client->FocusWindow(NULL);
- return NULL;
+ Window* window = static_cast<Window*>(root);
+ Window* target = event->IsKeyEvent() ?
+ FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event)) :
+ static_cast<Window*>(EventTargeter::FindTargetForEvent(root, event));
+ if (target && !window->parent()) {
+ // |window| is the root window.
+ if (!window->Contains(target)) {
+ // |target| is not a descendent of |window|. So do not allow dispatching
+ // from here. Instead, dispatch the event through the
+ // WindowEventDispatcher that owns |target|.
+ ui::EventDispatchDetails details ALLOW_UNUSED =
+ target->GetHost()->event_processor()->OnEventFromSource(event);
+ target = NULL;
}
- return focused_window ? focused_window : window;
}
- return EventTargeter::FindTargetForEvent(root, event);
+ return target;
}
-bool WindowTargeter::SubtreeShouldBeExploredForEvent(
- ui::EventTarget* root,
- const ui::LocatedEvent& event) {
- Window* window = static_cast<Window*>(root);
+bool WindowTargeter::SubtreeCanAcceptEvent(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ aura::Window* window = static_cast<aura::Window*>(target);
if (!window->IsVisible())
return false;
if (window->ignore_events())
@@ -55,7 +55,17 @@ bool WindowTargeter::SubtreeShouldBeExploredForEvent(
ShouldDescendIntoChildForEventHandling(window, event.location())) {
return false;
}
- return window->bounds().Contains(event.location());
+ return true;
+}
+
+bool WindowTargeter::EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ aura::Window* window = static_cast<aura::Window*>(target);
+ gfx::Point point = event.location();
+ if (window->parent())
+ aura::Window::ConvertPointToTarget(window->parent(), window, &point);
+ return gfx::Rect(window->bounds().size()).Contains(point);
}
ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent(
@@ -72,6 +82,27 @@ ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent(
return EventTargeter::FindTargetForLocatedEvent(root, event);
}
+Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
+ const ui::KeyEvent& key) {
+ Window* root_window = window->GetRootWindow();
+ if (key.key_code() == ui::VKEY_UNKNOWN &&
+ (key.flags() & ui::EF_IME_FABRICATED_KEY) == 0 &&
+ key.GetCharacter() == 0)
+ return NULL;
+ client::FocusClient* focus_client = client::GetFocusClient(root_window);
+ Window* focused_window = focus_client->GetFocusedWindow();
+ if (!focused_window)
+ return window;
+
+ client::EventClient* event_client = client::GetEventClient(root_window);
+ if (event_client &&
+ !event_client->CanProcessEventsWithinSubtree(focused_window)) {
+ focus_client->FocusWindow(NULL);
+ return NULL;
+ }
+ return focused_window ? focused_window : window;
+}
+
Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
const ui::LocatedEvent& event) {
DCHECK_EQ(root_window, root_window->GetRootWindow());
@@ -79,7 +110,7 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
// Mouse events should be dispatched to the window that processed the
// mouse-press events (if any).
if (event.IsScrollEvent() || event.IsMouseEvent()) {
- WindowEventDispatcher* dispatcher = root_window->GetDispatcher();
+ WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher();
if (dispatcher->mouse_pressed_handler())
return dispatcher->mouse_pressed_handler();
}
@@ -89,6 +120,24 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
if (capture_window)
return capture_window;
+ if (event.IsTouchEvent()) {
+ // Query the gesture-recognizer to find targets for touch events.
+ const ui::TouchEvent& touch = static_cast<const ui::TouchEvent&>(event);
+ ui::GestureConsumer* consumer =
+ ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch);
+ if (consumer)
+ return static_cast<Window*>(consumer);
+ consumer =
+ ui::GestureRecognizer::Get()->GetTargetForLocation(
+ event.location(), touch.source_device_id());
+ if (consumer)
+ return static_cast<Window*>(consumer);
+
+ // If the initial touch is outside the root window, target the root.
+ if (!root_window->bounds().Contains(event.location()))
+ return root_window;
+ }
+
return NULL;
}
diff --git a/chromium/ui/aura/window_targeter.h b/chromium/ui/aura/window_targeter.h
index 4457f77c371..e64ef75f807 100644
--- a/chromium/ui/aura/window_targeter.h
+++ b/chromium/ui/aura/window_targeter.h
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef UI_AURA_WINDOW_TARGETER_H_
+#define UI_AURA_WINDOW_TARGETER_H_
+
+#include "ui/aura/aura_export.h"
#include "ui/events/event_targeter.h"
namespace aura {
class Window;
-class WindowTargeter : public ui::EventTargeter {
+class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
public:
WindowTargeter();
virtual ~WindowTargeter();
@@ -20,11 +24,16 @@ class WindowTargeter : public ui::EventTargeter {
virtual ui::EventTarget* FindTargetForLocatedEvent(
ui::EventTarget* root,
ui::LocatedEvent* event) OVERRIDE;
- virtual bool SubtreeShouldBeExploredForEvent(
+ virtual bool SubtreeCanAcceptEvent(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+ virtual bool EventLocationInsideBounds(
ui::EventTarget* target,
- const ui::LocatedEvent& event) OVERRIDE;
+ const ui::LocatedEvent& event) const OVERRIDE;
private:
+ Window* FindTargetForKeyEvent(Window* root_window,
+ const ui::KeyEvent& event);
Window* FindTargetInRootWindow(Window* root_window,
const ui::LocatedEvent& event);
@@ -32,3 +41,5 @@ class WindowTargeter : public ui::EventTargeter {
};
} // namespace aura
+
+#endif // UI_AURA_WINDOW_TARGETER_H_
diff --git a/chromium/ui/aura/window_targeter_unittest.cc b/chromium/ui/aura/window_targeter_unittest.cc
index 396c805353f..f14d3379ea3 100644
--- a/chromium/ui/aura/window_targeter_unittest.cc
+++ b/chromium/ui/aura/window_targeter_unittest.cc
@@ -4,13 +4,34 @@
#include "ui/aura/window_targeter.h"
+#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_event_handler.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
+#include "ui/events/test/test_event_handler.h"
namespace aura {
+// Always returns the same window.
+class StaticWindowTargeter : public ui::EventTargeter {
+ public:
+ explicit StaticWindowTargeter(aura::Window* window)
+ : window_(window) {}
+ virtual ~StaticWindowTargeter() {}
+
+ private:
+ // ui::EventTargeter:
+ virtual ui::EventTarget* FindTargetForLocatedEvent(
+ ui::EventTarget* root,
+ ui::LocatedEvent* event) OVERRIDE {
+ return window_;
+ }
+
+ Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter);
+};
+
class WindowTargeterTest : public test::AuraTestBase {
public:
WindowTargeterTest() {}
@@ -19,6 +40,18 @@ class WindowTargeterTest : public test::AuraTestBase {
Window* root_window() { return AuraTestBase::root_window(); }
};
+gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) {
+ gfx::RectF bounds = gfx::Rect(window->bounds().size());
+ Window* root = window->GetRootWindow();
+ CHECK(window->layer());
+ CHECK(root->layer());
+ gfx::Transform transform;
+ if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform))
+ return gfx::RectF();
+ transform.TransformRect(&bounds);
+ return bounds;
+}
+
TEST_F(WindowTargeterTest, Basic) {
test::TestWindowDelegate delegate;
scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate));
@@ -31,24 +64,102 @@ TEST_F(WindowTargeterTest, Basic) {
root_window()->Show();
- test::TestEventHandler handler;
+ ui::test::TestEventHandler handler;
one->AddPreTargetHandler(&handler);
ui::MouseEvent press(ui::ET_MOUSE_PRESSED,
gfx::Point(20, 20),
gfx::Point(20, 20),
+ ui::EF_NONE,
ui::EF_NONE);
- root_window()->GetDispatcher()->AsRootWindowHostDelegate()->
- OnHostMouseEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_EQ(1, handler.num_mouse_events());
handler.Reset();
- ui::EventDispatchDetails details =
- root_window()->GetDispatcher()->OnEventFromSource(&press);
- EXPECT_FALSE(details.dispatcher_destroyed);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_EQ(1, handler.num_mouse_events());
one->RemovePreTargetHandler(&handler);
}
+TEST_F(WindowTargeterTest, ScopedWindowTargeter) {
+ test::TestWindowDelegate delegate;
+ scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate));
+ Window* child = CreateNormalWindow(2, window.get(), &delegate);
+
+ window->SetBounds(gfx::Rect(30, 30, 100, 100));
+ child->SetBounds(gfx::Rect(20, 20, 50, 50));
+ root_window()->Show();
+
+ ui::EventTarget* root = root_window();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+
+ gfx::Point event_location(60, 60);
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
+ }
+
+ // Install a targeter on |window| so that the events never reach the child.
+ scoped_ptr<ScopedWindowTargeter> scoped_targeter(
+ new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>(
+ new StaticWindowTargeter(window.get()))));
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse));
+ }
+ scoped_targeter.reset();
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
+ }
+}
+
+TEST_F(WindowTargeterTest, TargetTransformedWindow) {
+ root_window()->Show();
+
+ test::TestWindowDelegate delegate;
+ scoped_ptr<Window> window(CreateNormalWindow(2, root_window(), &delegate));
+
+ const gfx::Rect window_bounds(100, 20, 400, 80);
+ window->SetBounds(window_bounds);
+
+ ui::EventTarget* root_target = root_window();
+ ui::EventTargeter* targeter = root_target->GetEventTargeter();
+ gfx::Point event_location(490, 50);
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
+ }
+
+ // Scale |window| by 50%. This should move it away from underneath
+ // |event_location|, so an event in that location will not be targeted to it.
+ gfx::Transform transform;
+ transform.Scale(0.5, 0.5);
+ window->SetTransform(transform);
+ EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(),
+ GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse));
+ }
+
+ transform = gfx::Transform();
+ transform.Translate(200, 10);
+ transform.Scale(0.5, 0.5);
+ window->SetTransform(transform);
+ EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(),
+ GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
+ {
+ ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
+ }
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc
index 1bee9231a0a..9ac7cf7ab01 100644
--- a/chromium/ui/aura/window_tree_host.cc
+++ b/chromium/ui/aura/window_tree_host.cc
@@ -4,36 +4,270 @@
#include "ui/aura/window_tree_host.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_tree_host_delegate.h"
+#include "base/debug/trace_event.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_targeter.h"
+#include "ui/aura/window_tree_host_observer.h"
+#include "ui/base/view_prop.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/insets.h"
#include "ui/gfx/point.h"
+#include "ui/gfx/point3_f.h"
+#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/size_conversions.h"
namespace aura {
+const char kWindowTreeHostForAcceleratedWidget[] =
+ "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__";
+
+float GetDeviceScaleFactorFromDisplay(Window* window) {
+ gfx::Display display = gfx::Screen::GetScreenFor(window)->
+ GetDisplayNearestWindow(window);
+ DCHECK(display.is_valid());
+ return display.device_scale_factor();
+}
+
////////////////////////////////////////////////////////////////////////////////
-// RootWindowHost, public:
+// WindowTreeHost, public:
+
+WindowTreeHost::~WindowTreeHost() {
+ DCHECK(!compositor_) << "compositor must be destroyed before root window";
+}
+
+#if defined(OS_ANDROID)
+// static
+WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
+ // This is only hit for tests and ash, right now these aren't an issue so
+ // adding the CHECK.
+ // TODO(sky): decide if we want a factory.
+ CHECK(false);
+ return NULL;
+}
+#endif
+
+// static
+WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
+ gfx::AcceleratedWidget widget) {
+ return reinterpret_cast<WindowTreeHost*>(
+ ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget));
+}
+
+void WindowTreeHost::InitHost() {
+ InitCompositor();
+ UpdateRootWindowSize(GetBounds().size());
+ Env::GetInstance()->NotifyHostInitialized(this);
+ window()->Show();
+}
+
+void WindowTreeHost::InitCompositor() {
+ compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
+ GetBounds().size());
+ compositor_->SetRootLayer(window()->layer());
+}
+
+void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) {
+ observers_.AddObserver(observer);
+}
-RootWindowHost::~RootWindowHost() {
+void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) {
+ observers_.RemoveObserver(observer);
}
-void RootWindowHost::ConvertPointToNativeScreen(gfx::Point* point) const {
- delegate_->AsRootWindow()->ConvertPointToHost(point);
+ui::EventProcessor* WindowTreeHost::event_processor() {
+ return dispatcher();
+}
+
+gfx::Transform WindowTreeHost::GetRootTransform() const {
+ float scale = ui::GetDeviceScaleFactor(window()->layer());
+ gfx::Transform transform;
+ transform.Scale(scale, scale);
+ transform *= window()->layer()->transform();
+ return transform;
+}
+
+void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) {
+ window()->SetTransform(transform);
+ UpdateRootWindowSize(GetBounds().size());
+}
+
+gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
+ gfx::Transform invert;
+ gfx::Transform transform = GetRootTransform();
+ if (!transform.GetInverse(&invert))
+ return transform;
+ return invert;
+}
+
+void WindowTreeHost::UpdateRootWindowSize(const gfx::Size& host_size) {
+ gfx::Rect bounds(host_size);
+ gfx::RectF new_bounds(ui::ConvertRectToDIP(window()->layer(), bounds));
+ window()->layer()->transform().TransformRect(&new_bounds);
+ window()->SetBounds(gfx::Rect(gfx::ToFlooredSize(new_bounds.size())));
+}
+
+void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const {
+ ConvertPointToHost(point);
gfx::Point location = GetLocationOnNativeScreen();
point->Offset(location.x(), location.y());
}
-void RootWindowHost::ConvertPointFromNativeScreen(gfx::Point* point) const {
+void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const {
gfx::Point location = GetLocationOnNativeScreen();
point->Offset(-location.x(), -location.y());
- delegate_->AsRootWindow()->ConvertPointFromHost(point);
+ ConvertPointFromHost(point);
+}
+
+void WindowTreeHost::ConvertPointToHost(gfx::Point* point) const {
+ gfx::Point3F point_3f(*point);
+ GetRootTransform().TransformPoint(&point_3f);
+ *point = gfx::ToFlooredPoint(point_3f.AsPointF());
+}
+
+void WindowTreeHost::ConvertPointFromHost(gfx::Point* point) const {
+ gfx::Point3F point_3f(*point);
+ GetInverseRootTransform().TransformPoint(&point_3f);
+ *point = gfx::ToFlooredPoint(point_3f.AsPointF());
+}
+
+void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) {
+ last_cursor_ = cursor;
+ // A lot of code seems to depend on NULL cursors actually showing an arrow,
+ // so just pass everything along to the host.
+ SetCursorNative(cursor);
+}
+
+void WindowTreeHost::OnCursorVisibilityChanged(bool show) {
+ // Clear any existing mouse hover effects when the cursor becomes invisible.
+ // Note we do not need to dispatch a mouse enter when the cursor becomes
+ // visible because that can only happen in response to a mouse event, which
+ // will trigger its own mouse enter.
+ if (!show) {
+ dispatcher()->DispatchMouseExitAtPoint(
+ dispatcher()->GetLastMouseLocationInRoot());
+ }
+
+ OnCursorVisibilityChangedNative(show);
+}
+
+void WindowTreeHost::MoveCursorTo(const gfx::Point& location_in_dip) {
+ gfx::Point host_location(location_in_dip);
+ ConvertPointToHost(&host_location);
+ MoveCursorToInternal(location_in_dip, host_location);
+}
+
+void WindowTreeHost::MoveCursorToHostLocation(const gfx::Point& host_location) {
+ gfx::Point root_location(host_location);
+ ConvertPointFromHost(&root_location);
+ MoveCursorToInternal(root_location, host_location);
}
////////////////////////////////////////////////////////////////////////////////
-// RootWindowHost, protected:
+// WindowTreeHost, protected:
+
+WindowTreeHost::WindowTreeHost()
+ : window_(new Window(NULL)),
+ last_cursor_(ui::kCursorNull) {
+}
+
+void WindowTreeHost::DestroyCompositor() {
+ compositor_.reset();
+}
+
+void WindowTreeHost::DestroyDispatcher() {
+ delete window_;
+ window_ = NULL;
+ dispatcher_.reset();
+
+ // TODO(beng): this comment is no longer quite valid since this function
+ // isn't called from WED, and WED isn't a subclass of Window. So it seems
+ // like we could just rely on ~Window now.
+ // Destroy child windows while we're still valid. This is also done by
+ // ~Window, but by that time any calls to virtual methods overriden here (such
+ // as GetRootWindow()) result in Window's implementation. By destroying here
+ // we ensure GetRootWindow() still returns this.
+ //window()->RemoveOrDestroyChildren();
+}
-RootWindowHost::RootWindowHost()
- : delegate_(NULL) {
+void WindowTreeHost::CreateCompositor(
+ gfx::AcceleratedWidget accelerated_widget) {
+ DCHECK(Env::GetInstance());
+ ui::ContextFactory* context_factory = Env::GetInstance()->context_factory();
+ DCHECK(context_factory);
+ compositor_.reset(
+ new ui::Compositor(GetAcceleratedWidget(), context_factory));
+ // TODO(beng): I think this setup should probably all move to a "accelerated
+ // widget available" function.
+ if (!dispatcher()) {
+ window()->Init(WINDOW_LAYER_NOT_DRAWN);
+ window()->set_host(this);
+ window()->SetName("RootWindow");
+ window()->SetEventTargeter(
+ scoped_ptr<ui::EventTargeter>(new WindowTargeter()));
+ prop_.reset(new ui::ViewProp(GetAcceleratedWidget(),
+ kWindowTreeHostForAcceleratedWidget,
+ this));
+ dispatcher_.reset(new WindowEventDispatcher(this));
+ }
}
+void WindowTreeHost::OnHostMoved(const gfx::Point& new_location) {
+ TRACE_EVENT1("ui", "WindowTreeHost::OnHostMoved",
+ "origin", new_location.ToString());
+
+ FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
+ OnHostMoved(this, new_location));
+}
+
+void WindowTreeHost::OnHostResized(const gfx::Size& new_size) {
+ // 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(GetDeviceScaleFactorFromDisplay(window()),
+ new_size);
+
+ gfx::Size layer_size = GetBounds().size();
+ // The layer, and the observers should be notified of the
+ // transformed size of the root window.
+ UpdateRootWindowSize(layer_size);
+ FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, OnHostResized(this));
+}
+
+void WindowTreeHost::OnHostCloseRequested() {
+ FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
+ OnHostCloseRequested(this));
+}
+
+void WindowTreeHost::OnHostActivated() {
+ Env::GetInstance()->NotifyHostActivated(this);
+}
+
+void WindowTreeHost::OnHostLostWindowCapture() {
+ Window* capture_window = client::GetCaptureWindow(window());
+ if (capture_window && capture_window->GetRootWindow() == window())
+ capture_window->ReleaseCapture();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeHost, private:
+
+void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
+ const gfx::Point& host_location) {
+ last_cursor_request_position_in_host_ = host_location;
+ MoveCursorToNative(host_location);
+ client::CursorClient* cursor_client = client::GetCursorClient(window());
+ if (cursor_client) {
+ const gfx::Display& display =
+ gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
+ cursor_client->SetDisplay(display);
+ }
+ dispatcher()->OnCursorMovedToRootLocation(root_location);
+}
} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h
index 5aaa65c3116..9d54944777f 100644
--- a/chromium/ui/aura/window_tree_host.h
+++ b/chromium/ui/aura/window_tree_host.h
@@ -2,14 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_AURA_ROOT_WINDOW_HOST_H_
-#define UI_AURA_ROOT_WINDOW_HOST_H_
+#ifndef UI_AURA_WINDOW_TREE_HOST_H_
+#define UI_AURA_WINDOW_TREE_HOST_H_
#include <vector>
+#include "base/event_types.h"
#include "base/message_loop/message_loop.h"
#include "ui/aura/aura_export.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/events/event_source.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
@@ -17,53 +19,69 @@ class Insets;
class Point;
class Rect;
class Size;
+class Transform;
+}
+
+namespace ui {
+class Compositor;
+class EventProcessor;
+class ViewProp;
}
namespace aura {
+namespace test {
+class WindowTreeHostTestApi;
+}
-class RootWindow;
-class RootWindowHostDelegate;
+class WindowEventDispatcher;
+class WindowTreeHostObserver;
-// RootWindowHost bridges between a native window and the embedded RootWindow.
+// WindowTreeHost bridges between a native window and the embedded RootWindow.
// It provides the accelerated widget and maps events from the native os to
// aura.
-class AURA_EXPORT RootWindowHost {
+class AURA_EXPORT WindowTreeHost {
public:
- virtual ~RootWindowHost();
+ virtual ~WindowTreeHost();
- // Creates a new RootWindowHost. The caller owns the returned value.
- static RootWindowHost* Create(const gfx::Rect& bounds);
+ // Creates a new WindowTreeHost. The caller owns the returned value.
+ static WindowTreeHost* Create(const gfx::Rect& bounds);
- // Returns the actual size of the screen.
- // (gfx::Screen only reports on the virtual desktop exposed by Aura.)
- static gfx::Size GetNativeScreenSize();
+ // Returns the WindowTreeHost for the specified accelerated widget, or NULL
+ // if there is none associated.
+ static WindowTreeHost* GetForAcceleratedWidget(gfx::AcceleratedWidget widget);
- void set_delegate(RootWindowHostDelegate* delegate) {
- delegate_ = delegate;
- }
+ void InitHost();
- virtual RootWindow* GetRootWindow() = 0;
+ void InitCompositor();
- // Returns the accelerated widget.
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
+ void AddObserver(WindowTreeHostObserver* observer);
+ void RemoveObserver(WindowTreeHostObserver* observer);
- // Shows the RootWindowHost.
- virtual void Show() = 0;
+ Window* window() { return window_; }
+ const Window* window() const { return window_; }
- // Hides the RootWindowHost.
- virtual void Hide() = 0;
+ ui::EventProcessor* event_processor();
- // Toggles the host's full screen state.
- virtual void ToggleFullScreen() = 0;
+ WindowEventDispatcher* dispatcher() {
+ return const_cast<WindowEventDispatcher*>(
+ const_cast<const WindowTreeHost*>(this)->dispatcher());
+ }
+ const WindowEventDispatcher* dispatcher() const { return dispatcher_.get(); }
- // Gets/Sets the size of the RootWindowHost.
- virtual gfx::Rect GetBounds() const = 0;
- virtual void SetBounds(const gfx::Rect& bounds) = 0;
+ ui::Compositor* compositor() { return compositor_.get(); }
+
+ // Gets/Sets the root window's transform.
+ virtual gfx::Transform GetRootTransform() const;
+ virtual void SetRootTransform(const gfx::Transform& transform);
+ virtual gfx::Transform GetInverseRootTransform() const;
- // Sets/Gets the insets that specifies the effective root window area
- // in the host window.
- virtual gfx::Insets GetInsets() const = 0;
- virtual void SetInsets(const gfx::Insets& insets) = 0;
+ // Updates the root window's size using |host_size|, current
+ // transform and insets.
+ virtual void UpdateRootWindowSize(const gfx::Size& host_size);
+
+ // Returns the actual size of the screen.
+ // (gfx::Screen only reports on the virtual desktop exposed by Aura.)
+ static gfx::Size GetNativeScreenSize();
// Converts |point| from the root window's coordinate system to native
// screen's.
@@ -72,58 +90,117 @@ class AURA_EXPORT RootWindowHost {
// Converts |point| from native screen coordinate system to the root window's.
void ConvertPointFromNativeScreen(gfx::Point* point) const;
+ // Converts |point| from the root window's coordinate system to the
+ // host window's.
+ void ConvertPointToHost(gfx::Point* point) const;
+
+ // Converts |point| from the host window's coordinate system to the
+ // root window's.
+ void ConvertPointFromHost(gfx::Point* point) const;
+
+ // Cursor.
+ // Sets the currently-displayed cursor. If the cursor was previously hidden
+ // via ShowCursor(false), it will remain hidden until ShowCursor(true) is
+ // called, at which point the cursor that was last set via SetCursor() will be
+ // used.
+ void SetCursor(gfx::NativeCursor cursor);
+
+ // Invoked when the cursor's visibility has changed.
+ void OnCursorVisibilityChanged(bool visible);
+
+ // Moves the cursor to the specified location relative to the root window.
+ void MoveCursorTo(const gfx::Point& location);
+
+ // Moves the cursor to the |host_location| given in host coordinates.
+ void MoveCursorToHostLocation(const gfx::Point& host_location);
+
+ gfx::NativeCursor last_cursor() const { return last_cursor_; }
+
+ // Returns the EventSource responsible for dispatching events to the window
+ // tree.
+ virtual ui::EventSource* GetEventSource() = 0;
+
+ // Returns the accelerated widget.
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
+
+ // Shows the WindowTreeHost.
+ virtual void Show() = 0;
+
+ // Hides the WindowTreeHost.
+ virtual void Hide() = 0;
+
+ // Gets/Sets the size of the WindowTreeHost.
+ virtual gfx::Rect GetBounds() const = 0;
+ virtual void SetBounds(const gfx::Rect& bounds) = 0;
+
// Sets the OS capture to the root window.
virtual void SetCapture() = 0;
// Releases OS capture of the root window.
virtual void ReleaseCapture() = 0;
- // Sets the currently displayed cursor.
- virtual void SetCursor(gfx::NativeCursor cursor) = 0;
-
- // Queries the mouse's current position relative to the host window and sets
- // it in |location_return|. Returns true if the cursor is within the host
- // window. The position set to |location_return| is constrained within the
- // host window. If the cursor is disabled, returns false and (0, 0) is set to
- // |location_return|.
- // This method is expensive, instead use gfx::Screen::GetCursorScreenPoint().
- virtual bool QueryMouseLocation(gfx::Point* location_return) = 0;
-
- // Clips the cursor to the bounds of the root window until UnConfineCursor().
- // We would like to be able to confine the cursor to that window. However,
- // currently, we do not have such functionality in X. So we just confine
- // to the root window. This is ok because this option is currently only
- // being used in fullscreen mode, so root_window bounds = window bounds.
- virtual bool ConfineCursorToRootWindow() = 0;
- virtual void UnConfineCursor() = 0;
-
- // Called when the cursor visibility has changed.
- virtual void OnCursorVisibilityChanged(bool show) = 0;
-
- // Moves the cursor to the specified location relative to the root window.
- virtual void MoveCursorTo(const gfx::Point& location) = 0;
-
// Posts |native_event| to the platform's event queue.
virtual void PostNativeEvent(const base::NativeEvent& native_event) = 0;
// Called when the device scale factor of the root window has chagned.
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) = 0;
- // Stop listening events in preparation for shutdown.
- virtual void PrepareForShutdown() = 0;
-
protected:
- RootWindowHost();
+ friend class TestScreen; // TODO(beng): see if we can remove/consolidate.
+
+ WindowTreeHost();
+ void DestroyCompositor();
+ void DestroyDispatcher();
+
+ void CreateCompositor(gfx::AcceleratedWidget accelerated_widget);
// Returns the location of the RootWindow on native screen.
virtual gfx::Point GetLocationOnNativeScreen() const = 0;
- RootWindowHostDelegate* delegate_;
+ void OnHostMoved(const gfx::Point& new_location);
+ void OnHostResized(const gfx::Size& new_size);
+ void OnHostCloseRequested();
+ void OnHostActivated();
+ void OnHostLostWindowCapture();
+
+ // Sets the currently displayed cursor.
+ virtual void SetCursorNative(gfx::NativeCursor cursor) = 0;
+
+ // Moves the cursor to the specified location relative to the root window.
+ virtual void MoveCursorToNative(const gfx::Point& location) = 0;
+
+ // kCalled when the cursor visibility has changed.
+ virtual void OnCursorVisibilityChangedNative(bool show) = 0;
private:
- DISALLOW_COPY_AND_ASSIGN(RootWindowHost);
+ friend class test::WindowTreeHostTestApi;
+
+ // Moves the cursor to the specified location. This method is internally used
+ // by MoveCursorTo() and MoveCursorToHostLocation().
+ void MoveCursorToInternal(const gfx::Point& root_location,
+ const gfx::Point& host_location);
+
+ // We don't use a scoped_ptr for |window_| since we need this ptr to be valid
+ // during its deletion. (Window's dtor notifies observers that may attempt to
+ // reach back up to access this object which will be valid until the end of
+ // the dtor).
+ Window* window_; // Owning.
+
+ ObserverList<WindowTreeHostObserver> observers_;
+
+ scoped_ptr<WindowEventDispatcher> dispatcher_;
+
+ scoped_ptr<ui::Compositor> compositor_;
+
+ // Last cursor set. Used for testing.
+ gfx::NativeCursor last_cursor_;
+ gfx::Point last_cursor_request_position_in_host_;
+
+ scoped_ptr<ui::ViewProp> prop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHost);
};
} // namespace aura
-#endif // UI_AURA_ROOT_WINDOW_HOST_H_
+#endif // UI_AURA_WINDOW_TREE_HOST_H_
diff --git a/chromium/ui/aura/window_tree_host_delegate.h b/chromium/ui/aura/window_tree_host_delegate.h
deleted file mode 100644
index ad08039d627..00000000000
--- a/chromium/ui/aura/window_tree_host_delegate.h
+++ /dev/null
@@ -1,67 +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_AURA_ROOT_WINDOW_HOST_DELEGATE_H_
-#define UI_AURA_ROOT_WINDOW_HOST_DELEGATE_H_
-
-#include "ui/aura/aura_export.h"
-
-namespace gfx {
-class Point;
-class Rect;
-class Size;
-}
-
-namespace ui {
-class Event;
-class EventProcessor;
-class KeyEvent;
-class MouseEvent;
-class ScrollEvent;
-class TouchEvent;
-}
-
-namespace aura {
-
-class RootWindow;
-
-// A private interface used by RootWindowHost implementations to communicate
-// with their owning RootWindow.
-class AURA_EXPORT RootWindowHostDelegate {
- public:
- virtual bool OnHostKeyEvent(ui::KeyEvent* event) = 0;
- virtual bool OnHostMouseEvent(ui::MouseEvent* event) = 0;
- virtual bool OnHostScrollEvent(ui::ScrollEvent* event) = 0;
- virtual bool OnHostTouchEvent(ui::TouchEvent* event) = 0;
- virtual void OnHostCancelMode() = 0;
-
- // Called when the windowing system activates the window.
- virtual void OnHostActivated() = 0;
-
- // Called when system focus is changed to another window.
- virtual void OnHostLostWindowCapture() = 0;
-
- // Called when the windowing system has mouse grab because it's performing a
- // window move on our behalf, but we should still paint as if we're active.
- virtual void OnHostLostMouseGrab() = 0;
-
- virtual void OnHostPaint(const gfx::Rect& damage_rect) = 0;
-
- virtual void OnHostMoved(const gfx::Point& origin) = 0;
- virtual void OnHostResized(const gfx::Size& size) = 0;
-
- virtual float GetDeviceScaleFactor() = 0;
-
- virtual RootWindow* AsRootWindow() = 0;
- virtual const RootWindow* AsRootWindow() const = 0;
-
- virtual ui::EventProcessor* GetEventProcessor() = 0;
-
- protected:
- virtual ~RootWindowHostDelegate() {}
-};
-
-} // namespace aura
-
-#endif // UI_AURA_ROOT_WINDOW_HOST_DELEGATE_H_
diff --git a/chromium/ui/aura/window_tree_host_mac.h b/chromium/ui/aura/window_tree_host_mac.h
new file mode 100644
index 00000000000..8fbf4ec81bb
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_mac.h
@@ -0,0 +1,61 @@
+// 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_AURA_WINDOW_TREE_HOST_MAC_H_
+#define UI_AURA_WINDOW_TREE_HOST_MAC_H_
+
+#include <vector>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+
+namespace ui {
+class MouseEvent;
+}
+
+namespace aura {
+
+namespace internal {
+class TouchEventCalibrate;
+}
+
+class AURA_EXPORT WindowTreeHostMac : public WindowTreeHost {
+ public:
+ explicit WindowTreeHostMac(const gfx::Rect& bounds);
+ virtual ~WindowTreeHostMac();
+
+ private:
+ // WindowTreeHost Overrides.
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ToggleFullScreen() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Insets GetInsets() const OVERRIDE;
+ virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual bool ConfineCursorToRootWindow() OVERRIDE;
+ virtual void UnConfineCursor() OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+
+ private:
+ base::scoped_nsobject<NSWindow> window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHostMac);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_TREE_HOST_MAC_H_
diff --git a/chromium/ui/aura/window_tree_host_mac.mm b/chromium/ui/aura/window_tree_host_mac.mm
new file mode 100644
index 00000000000..7fb3f82a2ec
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_mac.mm
@@ -0,0 +1,114 @@
+// 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 <Cocoa/Cocoa.h>
+
+#include "ui/aura/window_tree_host_mac.h"
+#include "ui/aura/window_tree_host.h"
+
+namespace aura {
+
+WindowTreeHostMac::WindowTreeHostMac(const gfx::Rect& bounds) {
+ window_.reset(
+ [[NSWindow alloc]
+ initWithContentRect:NSRectFromCGRect(bounds.ToCGRect())
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+WindowTreeHostMac::~WindowTreeHostMac() {
+ DestroyDispatcher();
+}
+
+EventSource* WindowTreeHostMac::GetEventSource() {
+ NOTIMPLEMENTED();
+ return nil;
+}
+
+gfx::AcceleratedWidget WindowTreeHostMac::GetAcceleratedWidget() {
+ return [window_ contentView];
+}
+void WindowTreeHostMac::Show() {
+ [window_ makeKeyAndOrderFront:nil];
+}
+
+void WindowTreeHostMac::Hide() {
+ [window_ orderOut:nil];
+}
+
+void WindowTreeHostMac::ToggleFullScreen() {
+}
+
+gfx::Rect WindowTreeHostMac::GetBounds() const {
+ return gfx::Rect(NSRectToCGRect([window_ frame]));
+}
+
+void WindowTreeHostMac::SetBounds(const gfx::Rect& bounds) {
+ [window_ setFrame:NSRectFromCGRect(bounds.ToCGRect()) display:YES animate:NO];
+}
+
+gfx::Insets WindowTreeHostMac::GetInsets() const {
+ NOTIMPLEMENTED();
+ return gfx::Insets();
+}
+
+void WindowTreeHostMac::SetInsets(const gfx::Insets& insets) {
+ NOTIMPLEMENTED();
+}
+
+gfx::Point WindowTreeHostMac::GetLocationOnNativeScreen() const {
+ NOTIMPLEMENTED();
+ return gfx::Point(0, 0);
+}
+
+void WindowTreeHostMac::SetCapture() {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::ReleaseCapture() {
+ NOTIMPLEMENTED();
+}
+
+bool WindowTreeHostMac::ConfineCursorToRootWindow() {
+ return false;
+}
+
+void WindowTreeHostMac::UnConfineCursor() {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::SetCursorNative(gfx::NativeCursor cursor_type) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::MoveCursorToNative(const gfx::Point& location) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::OnCursorVisibilityChangedNative(bool show) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::PostNativeEvent(const base::NativeEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostMac::OnDeviceScaleFactorChanged(float device_scale_factor) {
+ NOTIMPLEMENTED();
+}
+
+// static
+WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
+ return new WindowTreeHostMac(bounds);
+}
+
+// static
+gfx::Size WindowTreeHost::GetNativeScreenSize() {
+ NOTIMPLEMENTED();
+ return gfx::Size(1024, 768);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_observer.h b/chromium/ui/aura/window_tree_host_observer.h
new file mode 100644
index 00000000000..d96e9d3b24d
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_observer.h
@@ -0,0 +1,36 @@
+// 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_AURA_WINDOW_TREE_HOST_OBSERVER_H_
+#define UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace aura {
+class Window;
+class WindowTreeHost;
+
+class AURA_EXPORT WindowTreeHostObserver {
+ public:
+ // Called when the host's client size has changed.
+ virtual void OnHostResized(const WindowTreeHost* host) {}
+
+ // Called when the host is moved on screen.
+ virtual void OnHostMoved(const WindowTreeHost* host,
+ const gfx::Point& new_origin) {}
+
+ // Called when the native window system sends the host request to close.
+ virtual void OnHostCloseRequested(const WindowTreeHost* host) {}
+
+ protected:
+ virtual ~WindowTreeHostObserver() {}
+};
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_
diff --git a/chromium/ui/aura/window_tree_host_ozone.cc b/chromium/ui/aura/window_tree_host_ozone.cc
new file mode 100644
index 00000000000..d247734940e
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_ozone.cc
@@ -0,0 +1,118 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/window_tree_host_ozone.h"
+
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace aura {
+
+WindowTreeHostOzone::WindowTreeHostOzone(const gfx::Rect& bounds)
+ : widget_(0),
+ bounds_(bounds) {
+ ui::SurfaceFactoryOzone* surface_factory =
+ ui::SurfaceFactoryOzone::GetInstance();
+ widget_ = surface_factory->GetAcceleratedWidget();
+
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+WindowTreeHostOzone::~WindowTreeHostOzone() {
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ DestroyCompositor();
+ DestroyDispatcher();
+}
+
+bool WindowTreeHostOzone::CanDispatchEvent(const ui::PlatformEvent& ne) {
+ CHECK(ne);
+ ui::Event* event = static_cast<ui::Event*>(ne);
+ if (event->IsMouseEvent() || event->IsScrollEvent())
+ return ui::CursorFactoryOzone::GetInstance()->GetCursorWindow() == widget_;
+
+ return true;
+}
+
+uint32_t WindowTreeHostOzone::DispatchEvent(const ui::PlatformEvent& ne) {
+ ui::Event* event = static_cast<ui::Event*>(ne);
+ ui::EventDispatchDetails details ALLOW_UNUSED = SendEventToProcessor(event);
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+}
+
+ui::EventSource* WindowTreeHostOzone::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget WindowTreeHostOzone::GetAcceleratedWidget() {
+ return widget_;
+}
+
+void WindowTreeHostOzone::Show() { NOTIMPLEMENTED(); }
+
+void WindowTreeHostOzone::Hide() { NOTIMPLEMENTED(); }
+
+gfx::Rect WindowTreeHostOzone::GetBounds() const { return bounds_; }
+
+void WindowTreeHostOzone::SetBounds(const gfx::Rect& bounds) {
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bool size_changed = bounds_.size() != bounds.size();
+ bounds_ = bounds;
+ if (size_changed)
+ OnHostResized(bounds_.size());
+ if (origin_changed)
+ OnHostMoved(bounds_.origin());
+}
+
+gfx::Point WindowTreeHostOzone::GetLocationOnNativeScreen() const {
+ return bounds_.origin();
+}
+
+void WindowTreeHostOzone::SetCapture() { NOTIMPLEMENTED(); }
+
+void WindowTreeHostOzone::ReleaseCapture() { NOTIMPLEMENTED(); }
+
+void WindowTreeHostOzone::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostOzone::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostOzone::SetCursorNative(gfx::NativeCursor cursor) {
+ ui::CursorFactoryOzone::GetInstance()->SetCursor(GetAcceleratedWidget(),
+ cursor.platform());
+}
+
+void WindowTreeHostOzone::MoveCursorToNative(const gfx::Point& location) {
+ ui::EventFactoryOzone::GetInstance()->WarpCursorTo(GetAcceleratedWidget(),
+ location);
+}
+
+void WindowTreeHostOzone::OnCursorVisibilityChangedNative(bool show) {
+ NOTIMPLEMENTED();
+}
+
+ui::EventProcessor* WindowTreeHostOzone::GetEventProcessor() {
+ return dispatcher();
+}
+
+// static
+WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
+ return new WindowTreeHostOzone(bounds);
+}
+
+// static
+gfx::Size WindowTreeHost::GetNativeScreenSize() {
+ NOTIMPLEMENTED();
+ return gfx::Size();
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_ozone.h b/chromium/ui/aura/window_tree_host_ozone.h
new file mode 100644
index 00000000000..f7ea6227996
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_ozone.h
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_WINDOW_TREE_HOST_OZONE_H_
+#define UI_AURA_WINDOW_TREE_HOST_OZONE_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_source.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+
+namespace aura {
+
+class AURA_EXPORT WindowTreeHostOzone : public WindowTreeHost,
+ public ui::EventSource,
+ public ui::PlatformEventDispatcher {
+ public:
+ explicit WindowTreeHostOzone(const gfx::Rect& bounds);
+ virtual ~WindowTreeHostOzone();
+
+ private:
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
+ // WindowTreeHost:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+
+ // ui::EventSource overrides.
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ gfx::AcceleratedWidget widget_;
+ gfx::Rect bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHostOzone);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_TREE_HOST_OZONE_H_
diff --git a/chromium/ui/aura/window_tree_host_win.cc b/chromium/ui/aura/window_tree_host_win.cc
new file mode 100644
index 00000000000..adf56e91ac7
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_win.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/window_tree_host_win.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/view_prop.h"
+#include "ui/compositor/compositor.h"
+#include "ui/events/event.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/screen.h"
+
+using std::max;
+using std::min;
+
+namespace aura {
+namespace {
+
+bool use_popup_as_root_window_for_test = false;
+
+} // namespace
+
+// static
+WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
+ return new WindowTreeHostWin(bounds);
+}
+
+// static
+gfx::Size WindowTreeHost::GetNativeScreenSize() {
+ return gfx::Size(GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN));
+}
+
+WindowTreeHostWin::WindowTreeHostWin(const gfx::Rect& bounds)
+ : has_capture_(false) {
+ if (use_popup_as_root_window_for_test)
+ set_window_style(WS_POPUP);
+ Init(NULL, bounds);
+ SetWindowText(hwnd(), L"aura::RootWindow!");
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+WindowTreeHostWin::~WindowTreeHostWin() {
+ DestroyCompositor();
+ DestroyDispatcher();
+ DestroyWindow(hwnd());
+}
+
+ui::EventSource* WindowTreeHostWin::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget WindowTreeHostWin::GetAcceleratedWidget() {
+ return hwnd();
+}
+
+void WindowTreeHostWin::Show() {
+ ShowWindow(hwnd(), SW_SHOWNORMAL);
+}
+
+void WindowTreeHostWin::Hide() {
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect WindowTreeHostWin::GetBounds() const {
+ RECT r;
+ GetClientRect(hwnd(), &r);
+ return gfx::Rect(r);
+}
+
+void WindowTreeHostWin::SetBounds(const gfx::Rect& bounds) {
+ RECT window_rect;
+ window_rect.left = bounds.x();
+ window_rect.top = bounds.y();
+ window_rect.right = bounds.right() ;
+ window_rect.bottom = bounds.bottom();
+ AdjustWindowRectEx(&window_rect,
+ GetWindowLong(hwnd(), GWL_STYLE),
+ FALSE,
+ GetWindowLong(hwnd(), GWL_EXSTYLE));
+ SetWindowPos(
+ hwnd(),
+ NULL,
+ window_rect.left,
+ window_rect.top,
+ window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top,
+ SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION);
+
+ // Explicity call OnHostResized when the scale has changed because
+ // the window size may not have changed.
+ float current_scale = compositor()->device_scale_factor();
+ float new_scale = gfx::Screen::GetScreenFor(window())->
+ GetDisplayNearestWindow(window()).device_scale_factor();
+ if (current_scale != new_scale)
+ OnHostResized(bounds.size());
+}
+
+gfx::Point WindowTreeHostWin::GetLocationOnNativeScreen() const {
+ RECT r;
+ GetClientRect(hwnd(), &r);
+ return gfx::Point(r.left, r.top);
+}
+
+
+void WindowTreeHostWin::SetCapture() {
+ if (!has_capture_) {
+ has_capture_ = true;
+ ::SetCapture(hwnd());
+ }
+}
+
+void WindowTreeHostWin::ReleaseCapture() {
+ if (has_capture_) {
+ has_capture_ = false;
+ ::ReleaseCapture();
+ }
+}
+
+void WindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) {
+ // Custom web cursors are handled directly.
+ if (native_cursor == ui::kCursorCustom)
+ return;
+
+ ui::CursorLoaderWin cursor_loader;
+ cursor_loader.SetPlatformCursor(&native_cursor);
+ ::SetCursor(native_cursor.platform());
+}
+
+void WindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) {
+ // Deliberately not implemented.
+}
+
+void WindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
+ NOTIMPLEMENTED();
+}
+
+void WindowTreeHostWin::PostNativeEvent(const base::NativeEvent& native_event) {
+ ::PostMessage(
+ hwnd(), native_event.message, native_event.wParam, native_event.lParam);
+}
+
+void WindowTreeHostWin::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+ NOTIMPLEMENTED();
+}
+
+ui::EventProcessor* WindowTreeHostWin::GetEventProcessor() {
+ return dispatcher();
+}
+
+void WindowTreeHostWin::OnClose() {
+ // TODO: this obviously shouldn't be here.
+ base::MessageLoopForUI::current()->Quit();
+}
+
+LRESULT WindowTreeHostWin::OnKeyEvent(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ MSG msg = { hwnd(), message, w_param, l_param };
+ ui::KeyEvent keyev(msg, message == WM_CHAR);
+ ui::EventDispatchDetails details = SendEventToProcessor(&keyev);
+ SetMsgHandled(keyev.handled() || details.dispatcher_destroyed);
+ return 0;
+}
+
+LRESULT WindowTreeHostWin::OnMouseRange(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ MSG msg = { hwnd(), message, w_param, l_param, 0,
+ { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } };
+ ui::MouseEvent event(msg);
+ bool handled = false;
+ if (!(event.flags() & ui::EF_IS_NON_CLIENT)) {
+ ui::EventDispatchDetails details = SendEventToProcessor(&event);
+ handled = event.handled() || details.dispatcher_destroyed;
+ }
+ SetMsgHandled(handled);
+ return 0;
+}
+
+LRESULT WindowTreeHostWin::OnCaptureChanged(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ if (has_capture_) {
+ has_capture_ = false;
+ OnHostLostWindowCapture();
+ }
+ return 0;
+}
+
+LRESULT WindowTreeHostWin::OnNCActivate(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ if (!!w_param)
+ OnHostActivated();
+ return DefWindowProc(hwnd(), message, w_param, l_param);
+}
+
+void WindowTreeHostWin::OnMove(const gfx::Point& point) {
+ OnHostMoved(point);
+}
+
+void WindowTreeHostWin::OnPaint(HDC dc) {
+ gfx::Rect damage_rect;
+ RECT update_rect = {0};
+ if (GetUpdateRect(hwnd(), &update_rect, FALSE))
+ damage_rect = gfx::Rect(update_rect);
+ compositor()->ScheduleRedrawRect(damage_rect);
+ ValidateRect(hwnd(), NULL);
+}
+
+void WindowTreeHostWin::OnSize(UINT param, const gfx::Size& size) {
+ // Minimizing resizes the window to 0x0 which causes our layout to go all
+ // screwy, so we just ignore it.
+ if (dispatcher() && param != SIZE_MINIMIZED)
+ OnHostResized(size);
+}
+
+namespace test {
+
+// static
+void SetUsePopupAsRootWindowForTest(bool use) {
+ use_popup_as_root_window_for_test = use;
+}
+
+} // namespace test
+
+} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_win.h b/chromium/ui/aura/window_tree_host_win.h
new file mode 100644
index 00000000000..64648510927
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_win.h
@@ -0,0 +1,93 @@
+// 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_AURA_WINDOW_TREE_HOST_WIN_H_
+#define UI_AURA_WINDOW_TREE_HOST_WIN_H_
+
+#include "base/compiler_specific.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_source.h"
+#include "ui/gfx/win/window_impl.h"
+
+namespace aura {
+
+class AURA_EXPORT WindowTreeHostWin : public WindowTreeHost,
+ public ui::EventSource,
+ public gfx::WindowImpl {
+ public:
+ explicit WindowTreeHostWin(const gfx::Rect& bounds);
+ virtual ~WindowTreeHostWin();
+ // WindowTreeHost:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+
+ // ui::EventSource:
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ private:
+ CR_BEGIN_MSG_MAP_EX(WindowTreeHostWin)
+ // Range handlers must go first!
+ CR_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+ CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE,
+ WM_NCXBUTTONDBLCLK,
+ OnMouseRange)
+
+ // Mouse capture events.
+ CR_MESSAGE_HANDLER_EX(WM_CAPTURECHANGED, OnCaptureChanged)
+
+ // Key events.
+ CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_CHAR, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_SYSCHAR, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_IME_CHAR, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate)
+
+ CR_MSG_WM_CLOSE(OnClose)
+ CR_MSG_WM_MOVE(OnMove)
+ CR_MSG_WM_PAINT(OnPaint)
+ CR_MSG_WM_SIZE(OnSize)
+ CR_END_MSG_MAP()
+
+ void OnClose();
+ LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param);
+ LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
+ LRESULT OnCaptureChanged(UINT message, WPARAM w_param, LPARAM l_param);
+ LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param);
+ void OnMove(const gfx::Point& point);
+ void OnPaint(HDC dc);
+ void OnSize(UINT param, const gfx::Size& size);
+
+ bool has_capture_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHostWin);
+};
+
+namespace test {
+
+// Set true to let WindowTreeHostWin use a popup window
+// with no frame/title so that the window size and test's
+// expectations matches.
+AURA_EXPORT void SetUsePopupAsRootWindowForTest(bool use);
+
+} // namespace
+
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_TREE_HOST_WIN_H_
diff --git a/chromium/ui/aura/window_tree_host_x11.cc b/chromium/ui/aura/window_tree_host_x11.cc
new file mode 100644
index 00000000000..c3dcb19f151
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_x11.cc
@@ -0,0 +1,744 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/window_tree_host_x11.h"
+
+#include <strings.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/Xatom.h>
+#include <X11/Xcursor/Xcursor.h>
+#include <X11/Xlib.h>
+
+#include <algorithm>
+#include <limits>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/events/event.h"
+#include "ui/events/event_switches.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform/platform_event_observer.h"
+#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/events/x/device_data_manager.h"
+#include "ui/events/x/device_list_cache_x.h"
+#include "ui/events/x/touch_factory_x11.h"
+#include "ui/gfx/screen.h"
+
+using std::max;
+using std::min;
+
+namespace aura {
+
+namespace {
+
+const char* kAtomsToCache[] = {
+ "WM_DELETE_WINDOW",
+ "_NET_WM_PING",
+ "_NET_WM_PID",
+ NULL
+};
+
+::Window FindEventTarget(const base::NativeEvent& xev) {
+ ::Window target = xev->xany.window;
+ if (xev->type == GenericEvent)
+ target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
+ return target;
+}
+
+void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) {
+ CHECK(ui::IsXInput2Available());
+ unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {};
+ memset(mask, 0, sizeof(mask));
+
+ XISetMask(mask, XI_HierarchyChanged);
+ XISetMask(mask, XI_KeyPress);
+ XISetMask(mask, XI_KeyRelease);
+
+ XIEventMask evmask;
+ evmask.deviceid = XIAllDevices;
+ evmask.mask_len = sizeof(mask);
+ evmask.mask = mask;
+ XISelectEvents(display, root_window, &evmask, 1);
+
+#if defined(OS_CHROMEOS)
+ if (base::SysInfo::IsRunningOnChromeOS()) {
+ // It is necessary to listen for touch events on the root window for proper
+ // touch event calibration on Chrome OS, but this is not currently necessary
+ // on the desktop. This seems to fail in some cases (e.g. when logging
+ // in incognito). So select for non-touch events first, and then select for
+ // touch-events (but keep the other events in the mask, i.e. do not memset
+ // |mask| back to 0).
+ // TODO(sad): Figure out why this happens. http://crbug.com/153976
+ XISetMask(mask, XI_TouchBegin);
+ XISetMask(mask, XI_TouchUpdate);
+ XISetMask(mask, XI_TouchEnd);
+ XISelectEvents(display, root_window, &evmask, 1);
+ }
+#endif
+}
+
+bool default_override_redirect = false;
+
+} // namespace
+
+namespace internal {
+
+// TODO(miletus) : Move this into DeviceDataManager.
+// Accomplishes 2 tasks concerning touch event calibration:
+// 1. Being a message-pump observer,
+// routes all the touch events to the X root window,
+// where they can be calibrated later.
+// 2. Has the Calibrate method that does the actual bezel calibration,
+// when invoked from X root window's event dispatcher.
+class TouchEventCalibrate : public ui::PlatformEventObserver {
+ public:
+ TouchEventCalibrate() : left_(0), right_(0), top_(0), bottom_(0) {
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+#if defined(USE_XI2_MT)
+ std::vector<std::string> parts;
+ if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTouchCalibration),
+ ",",
+ &parts) >= 4) {
+ if (!base::StringToInt(parts[0], &left_))
+ DLOG(ERROR) << "Incorrect left border calibration value passed.";
+ if (!base::StringToInt(parts[1], &right_))
+ DLOG(ERROR) << "Incorrect right border calibration value passed.";
+ if (!base::StringToInt(parts[2], &top_))
+ DLOG(ERROR) << "Incorrect top border calibration value passed.";
+ if (!base::StringToInt(parts[3], &bottom_))
+ DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
+ }
+#endif // defined(USE_XI2_MT)
+ }
+
+ virtual ~TouchEventCalibrate() {
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
+ }
+
+ // Modify the location of the |event|,
+ // expanding it from |bounds| to (|bounds| + bezels).
+ // Required when touchscreen is bigger than screen (i.e. has bezels),
+ // because we receive events in touchscreen coordinates,
+ // which need to be expanded when converting to screen coordinates,
+ // so that location on bezels will be outside of screen area.
+ void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
+#if defined(USE_XI2_MT)
+ int x = event->x();
+ int y = event->y();
+
+ if (!left_ && !right_ && !top_ && !bottom_)
+ return;
+
+ const int resolution_x = bounds.width();
+ const int resolution_y = bounds.height();
+ // The "grace area" (10% in this case) is to make it easier for the user to
+ // navigate to the corner.
+ const double kGraceAreaFraction = 0.1;
+ if (left_ || right_) {
+ // Offset the x position to the real
+ x -= left_;
+ // Check if we are in the grace area of the left side.
+ // Note: We might not want to do this when the gesture is locked?
+ if (x < 0 && x > -left_ * kGraceAreaFraction)
+ x = 0;
+ // Check if we are in the grace area of the right side.
+ // Note: We might not want to do this when the gesture is locked?
+ if (x > resolution_x - left_ &&
+ x < resolution_x - left_ + right_ * kGraceAreaFraction)
+ x = resolution_x - left_;
+ // Scale the screen area back to the full resolution of the screen.
+ x = (x * resolution_x) / (resolution_x - (right_ + left_));
+ }
+ if (top_ || bottom_) {
+ // When there is a top bezel we add our border,
+ y -= top_;
+
+ // Check if we are in the grace area of the top side.
+ // Note: We might not want to do this when the gesture is locked?
+ if (y < 0 && y > -top_ * kGraceAreaFraction)
+ y = 0;
+
+ // Check if we are in the grace area of the bottom side.
+ // Note: We might not want to do this when the gesture is locked?
+ if (y > resolution_y - top_ &&
+ y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
+ y = resolution_y - top_;
+ // Scale the screen area back to the full resolution of the screen.
+ y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
+ }
+
+ // Set the modified coordinate back to the event.
+ if (event->root_location() == event->location()) {
+ // Usually those will be equal,
+ // if not, I am not sure what the correct value should be.
+ event->set_root_location(gfx::Point(x, y));
+ }
+ event->set_location(gfx::Point(x, y));
+#endif // defined(USE_XI2_MT)
+ }
+
+ private:
+ // ui::PlatformEventObserver:
+ virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE {
+#if defined(USE_XI2_MT)
+ if (event->type == GenericEvent &&
+ (event->xgeneric.evtype == XI_TouchBegin ||
+ event->xgeneric.evtype == XI_TouchUpdate ||
+ event->xgeneric.evtype == XI_TouchEnd)) {
+ XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
+ xievent->event = xievent->root;
+ xievent->event_x = xievent->root_x;
+ xievent->event_y = xievent->root_y;
+ }
+#endif // defined(USE_XI2_MT)
+ }
+
+ virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {}
+
+ // The difference in screen's native resolution pixels between
+ // the border of the touchscreen and the border of the screen,
+ // aka bezel sizes.
+ int left_;
+ int right_;
+ int top_;
+ int bottom_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
+};
+
+} // namespace internal
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowTreeHostX11
+
+WindowTreeHostX11::WindowTreeHostX11(const gfx::Rect& bounds)
+ : xdisplay_(gfx::GetXDisplay()),
+ xwindow_(0),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ current_cursor_(ui::kCursorNull),
+ window_mapped_(false),
+ bounds_(bounds),
+ touch_calibrate_(new internal::TouchEventCalibrate),
+ atom_cache_(xdisplay_, kAtomsToCache) {
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.background_pixmap = None;
+ swa.override_redirect = default_override_redirect;
+ xwindow_ = XCreateWindow(
+ xdisplay_, x_root_window_,
+ bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWBackPixmap | CWOverrideRedirect,
+ &swa);
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+
+ long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
+ KeyPressMask | KeyReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask | PropertyChangeMask |
+ PointerMotionMask;
+ XSelectInput(xdisplay_, xwindow_, event_mask);
+ XFlush(xdisplay_);
+
+ if (ui::IsXInput2Available()) {
+ ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
+ SelectXInput2EventsForRootWindow(xdisplay_, x_root_window_);
+ }
+
+ // TODO(erg): We currently only request window deletion events. We also
+ // should listen for activation events and anything else that GTK+ listens
+ // for, and do something useful.
+ ::Atom protocols[2];
+ protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
+ protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
+ XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
+
+ // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
+ // the desktop environment.
+ XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+
+ // Likewise, the X server needs to know this window's pid so it knows which
+ // program to kill if the window hangs.
+ // XChangeProperty() expects "pid" to be long.
+ COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
+ long pid = getpid();
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_PID"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&pid), 1);
+
+ // Allow subclasses to create and cache additional atoms.
+ atom_cache_.allow_uncached_atoms();
+
+ XRRSelectInput(xdisplay_, x_root_window_,
+ RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+WindowTreeHostX11::~WindowTreeHostX11() {
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+
+ DestroyCompositor();
+ DestroyDispatcher();
+ XDestroyWindow(xdisplay_, xwindow_);
+}
+
+bool WindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) {
+ ::Window target = FindEventTarget(event);
+ return target == xwindow_ || target == x_root_window_;
+}
+
+uint32_t WindowTreeHostX11::DispatchEvent(const ui::PlatformEvent& event) {
+ XEvent* xev = event;
+ if (FindEventTarget(xev) == x_root_window_) {
+ if (xev->type == GenericEvent)
+ DispatchXI2Event(xev);
+ return ui::POST_DISPATCH_NONE;
+ }
+
+ switch (xev->type) {
+ case EnterNotify: {
+ // Ignore EventNotify events from children of |xwindow_|.
+ // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
+ // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
+ // necessary. crbug.com/385716
+ if (xev->xcrossing.detail == NotifyInferior)
+ break;
+
+ aura::Window* root_window = window();
+ client::CursorClient* cursor_client =
+ client::GetCursorClient(root_window);
+ if (cursor_client) {
+ const gfx::Display display = gfx::Screen::GetScreenFor(root_window)->
+ GetDisplayNearestWindow(root_window);
+ cursor_client->SetDisplay(display);
+ }
+ ui::MouseEvent mouse_event(xev);
+ // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not
+ // real mouse move event.
+ mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
+ TranslateAndDispatchLocatedEvent(&mouse_event);
+ break;
+ }
+ case LeaveNotify: {
+ // Ignore LeaveNotify events from children of |xwindow_|.
+ // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
+ // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
+ // necessary. crbug.com/385716
+ if (xev->xcrossing.detail == NotifyInferior)
+ break;
+
+ ui::MouseEvent mouse_event(xev);
+ TranslateAndDispatchLocatedEvent(&mouse_event);
+ break;
+ }
+ case Expose: {
+ gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
+ xev->xexpose.width, xev->xexpose.height);
+ compositor()->ScheduleRedrawRect(damage_rect);
+ break;
+ }
+ case KeyPress: {
+ ui::KeyEvent keydown_event(xev, false);
+ SendEventToProcessor(&keydown_event);
+ break;
+ }
+ case KeyRelease: {
+ ui::KeyEvent keyup_event(xev, false);
+ SendEventToProcessor(&keyup_event);
+ break;
+ }
+ case ButtonPress:
+ case ButtonRelease: {
+ switch (ui::EventTypeFromNative(xev)) {
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ TranslateAndDispatchLocatedEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED: {
+ ui::MouseEvent mouseev(xev);
+ TranslateAndDispatchLocatedEvent(&mouseev);
+ break;
+ }
+ case ui::ET_UNKNOWN:
+ // No event is created for X11-release events for mouse-wheel buttons.
+ break;
+ default:
+ NOTREACHED();
+ }
+ break;
+ }
+ case FocusOut:
+ if (xev->xfocus.mode != NotifyGrab)
+ OnHostLostWindowCapture();
+ break;
+ case ConfigureNotify: {
+ DCHECK_EQ(xwindow_, xev->xconfigure.event);
+ DCHECK_EQ(xwindow_, xev->xconfigure.window);
+ // It's possible that the X window may be resized by some other means
+ // than from within aura (e.g. the X window manager can change the
+ // size). Make sure the root window size is maintained properly.
+ gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
+ xev->xconfigure.width, xev->xconfigure.height);
+ bool size_changed = bounds_.size() != bounds.size();
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bounds_ = bounds;
+ OnConfigureNotify();
+ if (size_changed)
+ OnHostResized(bounds.size());
+ if (origin_changed)
+ OnHostMoved(bounds_.origin());
+ break;
+ }
+ case GenericEvent:
+ DispatchXI2Event(xev);
+ break;
+ case ClientMessage: {
+ Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
+ if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
+ // We have received a close message from the window manager.
+ OnHostCloseRequested();
+ } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
+ XEvent reply_event = *xev;
+ reply_event.xclient.window = x_root_window_;
+
+ XSendEvent(xdisplay_,
+ reply_event.xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &reply_event);
+ XFlush(xdisplay_);
+ }
+ break;
+ }
+ case MappingNotify: {
+ switch (xev->xmapping.request) {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping(&xev->xmapping);
+ break;
+ case MappingPointer:
+ ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
+ break;
+ default:
+ NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
+ break;
+ }
+ break;
+ }
+ case MotionNotify: {
+ // Discard all but the most recent motion event that targets the same
+ // window with unchanged state.
+ XEvent last_event;
+ while (XPending(xev->xany.display)) {
+ XEvent next_event;
+ XPeekEvent(xev->xany.display, &next_event);
+ if (next_event.type == MotionNotify &&
+ next_event.xmotion.window == xev->xmotion.window &&
+ next_event.xmotion.subwindow == xev->xmotion.subwindow &&
+ next_event.xmotion.state == xev->xmotion.state) {
+ XNextEvent(xev->xany.display, &last_event);
+ xev = &last_event;
+ } else {
+ break;
+ }
+ }
+
+ ui::MouseEvent mouseev(xev);
+ TranslateAndDispatchLocatedEvent(&mouseev);
+ break;
+ }
+ }
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+}
+
+ui::EventSource* WindowTreeHostX11::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget WindowTreeHostX11::GetAcceleratedWidget() {
+ return xwindow_;
+}
+
+void WindowTreeHostX11::Show() {
+ if (!window_mapped_) {
+ // Before we map the window, set size hints. Otherwise, some window managers
+ // will ignore toplevel XMoveWindow commands.
+ XSizeHints size_hints;
+ size_hints.flags = PPosition | PWinGravity;
+ size_hints.x = bounds_.x();
+ size_hints.y = bounds_.y();
+ // Set StaticGravity so that the window position is not affected by the
+ // frame width when running with window manager.
+ size_hints.win_gravity = StaticGravity;
+ XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
+
+ XMapWindow(xdisplay_, xwindow_);
+
+ // We now block until our window is mapped. Some X11 APIs will crash and
+ // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
+ // asynchronous.
+ if (ui::X11EventSource::GetInstance())
+ ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
+ window_mapped_ = true;
+ }
+}
+
+void WindowTreeHostX11::Hide() {
+ if (window_mapped_) {
+ XWithdrawWindow(xdisplay_, xwindow_, 0);
+ window_mapped_ = false;
+ }
+}
+
+gfx::Rect WindowTreeHostX11::GetBounds() const {
+ return bounds_;
+}
+
+void WindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
+ // Even if the host window's size doesn't change, aura's root window
+ // size, which is in DIP, changes when the scale changes.
+ float current_scale = compositor()->device_scale_factor();
+ float new_scale = gfx::Screen::GetScreenFor(window())->
+ GetDisplayNearestWindow(window()).device_scale_factor();
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bool size_changed = bounds_.size() != bounds.size();
+ XWindowChanges changes = {0};
+ unsigned value_mask = 0;
+
+ if (size_changed) {
+ changes.width = bounds.width();
+ changes.height = bounds.height();
+ value_mask = CWHeight | CWWidth;
+ }
+
+ if (origin_changed) {
+ changes.x = bounds.x();
+ changes.y = bounds.y();
+ value_mask |= CWX | CWY;
+ }
+ if (value_mask)
+ XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
+
+ // Assume that the resize will go through as requested, which should be the
+ // case if we're running without a window manager. If there's a window
+ // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
+ // (possibly synthetic) ConfigureNotify about the actual size and correct
+ // |bounds_| later.
+ bounds_ = bounds;
+ if (origin_changed)
+ OnHostMoved(bounds.origin());
+ if (size_changed || current_scale != new_scale) {
+ OnHostResized(bounds.size());
+ } else {
+ window()->SchedulePaintInRect(window()->bounds());
+ }
+}
+
+gfx::Point WindowTreeHostX11::GetLocationOnNativeScreen() const {
+ return bounds_.origin();
+}
+
+void WindowTreeHostX11::SetCapture() {
+ // TODO(oshima): Grab x input.
+}
+
+void WindowTreeHostX11::ReleaseCapture() {
+ // TODO(oshima): Release x input.
+}
+
+void WindowTreeHostX11::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+ DCHECK(xwindow_);
+ DCHECK(xdisplay_);
+ XEvent xevent = *native_event;
+ xevent.xany.display = xdisplay_;
+ xevent.xany.window = xwindow_;
+
+ switch (xevent.type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease: {
+ // The fields used below are in the same place for all of events
+ // above. Using xmotion from XEvent's unions to avoid repeating
+ // the code.
+ xevent.xmotion.root = x_root_window_;
+ xevent.xmotion.time = CurrentTime;
+
+ gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
+ ConvertPointToNativeScreen(&point);
+ xevent.xmotion.x_root = point.x();
+ xevent.xmotion.y_root = point.y();
+ }
+ default:
+ break;
+ }
+ XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
+ XFlush(xdisplay_);
+}
+
+void WindowTreeHostX11::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void WindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
+ if (cursor == current_cursor_)
+ return;
+ current_cursor_ = cursor;
+ SetCursorInternal(cursor);
+}
+
+void WindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
+ XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
+ bounds_.x() + location.x(),
+ bounds_.y() + location.y());
+}
+
+void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
+}
+
+ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() {
+ return dispatcher();
+}
+
+void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) {
+ ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
+ XEvent* xev = event;
+ XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ if (!factory->ShouldProcessXI2Event(xev))
+ return;
+
+ TRACE_EVENT1("input", "WindowTreeHostX11::DispatchXI2Event",
+ "event_latency_us",
+ (ui::EventTimeForNow() - ui::EventTimeFromNative(event)).
+ InMicroseconds());
+
+ ui::EventType type = ui::EventTypeFromNative(xev);
+ XEvent last_event;
+ int num_coalesced = 0;
+
+ switch (type) {
+ case ui::ET_TOUCH_MOVED:
+ case ui::ET_TOUCH_PRESSED:
+ case ui::ET_TOUCH_CANCELLED:
+ case ui::ET_TOUCH_RELEASED: {
+ ui::TouchEvent touchev(xev);
+ if (ui::DeviceDataManager::GetInstance()->TouchEventNeedsCalibrate(
+ xiev->deviceid)) {
+ touch_calibrate_->Calibrate(&touchev, bounds_);
+ }
+ TranslateAndDispatchLocatedEvent(&touchev);
+ break;
+ }
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_ENTERED:
+ case ui::ET_MOUSE_EXITED: {
+ if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
+ // If this is a motion event, we want to coalesce all pending motion
+ // events that are at the top of the queue.
+ num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
+ if (num_coalesced > 0)
+ xev = &last_event;
+ }
+ ui::MouseEvent mouseev(xev);
+ TranslateAndDispatchLocatedEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ TranslateAndDispatchLocatedEvent(&mouseev);
+ break;
+ }
+ case ui::ET_SCROLL_FLING_START:
+ case ui::ET_SCROLL_FLING_CANCEL:
+ case ui::ET_SCROLL: {
+ ui::ScrollEvent scrollev(xev);
+ SendEventToProcessor(&scrollev);
+ break;
+ }
+ case ui::ET_UMA_DATA:
+ break;
+ case ui::ET_UNKNOWN:
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // If we coalesced an event we need to free its cookie.
+ if (num_coalesced > 0)
+ XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
+}
+
+void WindowTreeHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
+ XDefineCursor(xdisplay_, xwindow_, cursor.platform());
+}
+
+void WindowTreeHostX11::OnConfigureNotify() {}
+
+void WindowTreeHostX11::TranslateAndDispatchLocatedEvent(
+ ui::LocatedEvent* event) {
+ SendEventToProcessor(event);
+}
+
+// static
+WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
+ return new WindowTreeHostX11(bounds);
+}
+
+// static
+gfx::Size WindowTreeHost::GetNativeScreenSize() {
+ ::XDisplay* xdisplay = gfx::GetXDisplay();
+ return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
+}
+
+namespace test {
+
+void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
+ default_override_redirect = override_redirect;
+}
+
+} // namespace test
+} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_x11.h b/chromium/ui/aura/window_tree_host_x11.h
new file mode 100644
index 00000000000..1db9f675684
--- /dev/null
+++ b/chromium/ui/aura/window_tree_host_x11.h
@@ -0,0 +1,118 @@
+// 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_AURA_WINDOW_TREE_HOST_X11_H_
+#define UI_AURA_WINDOW_TREE_HOST_X11_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_source.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+
+// X forward decls to avoid including Xlib.h in a header file.
+typedef struct _XDisplay XDisplay;
+typedef unsigned long XID;
+typedef XID Window;
+
+namespace ui {
+class MouseEvent;
+}
+
+namespace aura {
+
+namespace internal {
+class TouchEventCalibrate;
+}
+
+class AURA_EXPORT WindowTreeHostX11 : public WindowTreeHost,
+ public ui::EventSource,
+ public ui::PlatformEventDispatcher {
+
+ public:
+ explicit WindowTreeHostX11(const gfx::Rect& bounds);
+ virtual ~WindowTreeHostX11();
+
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
+ // WindowTreeHost:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+
+ // ui::EventSource overrides.
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ protected:
+ // Called when X Configure Notify event is recevied.
+ virtual void OnConfigureNotify();
+
+ // Translates the native mouse location into screen coordinates and
+ // dispatches the event via WindowEventDispatcher.
+ virtual void TranslateAndDispatchLocatedEvent(ui::LocatedEvent* event);
+
+ ::Window x_root_window() { return x_root_window_; }
+ XDisplay* xdisplay() { return xdisplay_; }
+ const gfx::Rect bounds() const { return bounds_; }
+ ui::X11AtomCache* atom_cache() { return &atom_cache_; }
+
+ private:
+ // Dispatches XI2 events. Note that some events targetted for the X root
+ // window are dispatched to the aura root window (e.g. touch events after
+ // calibration).
+ void DispatchXI2Event(const base::NativeEvent& event);
+
+ // Sets the cursor on |xwindow_| to |cursor|. Does not check or update
+ // |current_cursor_|.
+ void SetCursorInternal(gfx::NativeCursor cursor);
+
+ // The display and the native X window hosting the root window.
+ XDisplay* xdisplay_;
+ ::Window xwindow_;
+
+ // The native root window.
+ ::Window x_root_window_;
+
+ // Current Aura cursor.
+ gfx::NativeCursor current_cursor_;
+
+ // Is the window mapped to the screen?
+ bool window_mapped_;
+
+ // The bounds of |xwindow_|.
+ gfx::Rect bounds_;
+
+ scoped_ptr<internal::TouchEventCalibrate> touch_calibrate_;
+
+ ui::X11AtomCache atom_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHostX11);
+};
+
+namespace test {
+
+// Set the default value of the override redirect flag used to
+// create a X window for WindowTreeHostX11.
+AURA_EXPORT void SetUseOverrideRedirectWindowByDefault(bool override_redirect);
+
+} // namespace test
+} // namespace aura
+
+#endif // UI_AURA_WINDOW_TREE_HOST_X11_H_
diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc
index b79143113b7..37cf5edca78 100644
--- a/chromium/ui/aura/window_unittest.cc
+++ b/chromium/ui/aura/window_unittest.cc
@@ -18,20 +18,20 @@
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/client/visibility_client.h"
#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/layout_manager.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/root_window_observer.h"
#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/aura_test_utils.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/window_test_api.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_property.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/test_layers.h"
@@ -94,13 +94,13 @@ class DestroyTrackingDelegateImpl : public TestWindowDelegate {
bool in_destroying() const { return in_destroying_; }
- virtual void OnWindowDestroying() OVERRIDE {
+ virtual void OnWindowDestroying(Window* window) OVERRIDE {
EXPECT_FALSE(in_destroying_);
in_destroying_ = true;
destroying_count_++;
}
- virtual void OnWindowDestroyed() OVERRIDE {
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
EXPECT_TRUE(in_destroying_);
in_destroying_ = false;
destroyed_count_++;
@@ -123,9 +123,9 @@ class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl {
: parent_delegate_(parent_delegate) {
}
- virtual void OnWindowDestroying() OVERRIDE {
+ virtual void OnWindowDestroying(Window* window) OVERRIDE {
EXPECT_TRUE(parent_delegate_->in_destroying());
- DestroyTrackingDelegateImpl::OnWindowDestroying();
+ DestroyTrackingDelegateImpl::OnWindowDestroying(window);
}
private:
@@ -143,7 +143,7 @@ class DestroyOrphanDelegate : public TestWindowDelegate {
void set_window(Window* window) { window_ = window; }
- virtual void OnWindowDestroyed() OVERRIDE {
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
EXPECT_FALSE(window_->parent());
}
@@ -245,7 +245,7 @@ class DestroyWindowDelegate : public TestWindowDelegate {
virtual ~DestroyWindowDelegate() {}
// Overridden from WindowDelegate.
- virtual void OnWindowDestroyed() OVERRIDE {
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
delete this;
}
@@ -269,11 +269,11 @@ TEST_F(WindowTest, GetChildById) {
// and not containing NULL or parents.
TEST_F(WindowTest, Contains) {
Window parent(NULL);
- parent.Init(ui::LAYER_NOT_DRAWN);
+ parent.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child1(NULL);
- child1.Init(ui::LAYER_NOT_DRAWN);
+ child1.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child2(NULL);
- child2.Init(ui::LAYER_NOT_DRAWN);
+ child2.Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent.AddChild(&child1);
child1.AddChild(&child2);
@@ -372,13 +372,11 @@ TEST_F(WindowTest, MoveCursorToWithTransformRootWindow) {
transform.Translate(100.0, 100.0);
transform.Rotate(90.0);
transform.Scale(2.0, 5.0);
- dispatcher()->SetTransform(transform);
- dispatcher()->MoveCursorTo(gfx::Point(10, 10));
+ host()->SetRootTransform(transform);
+ host()->MoveCursorTo(gfx::Point(10, 10));
#if !defined(OS_WIN)
- gfx::Point mouse_location;
- EXPECT_TRUE(dispatcher()->host()->QueryMouseLocation(&mouse_location));
// TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.OD
- EXPECT_EQ("50,120", mouse_location.ToString());
+ EXPECT_EQ("50,120", QueryLatestMousePositionRequestInHost(host()).ToString());
#endif
EXPECT_EQ("10,10", gfx::Screen::GetScreenFor(
root_window())->GetCursorScreenPoint().ToString());
@@ -453,7 +451,7 @@ TEST_F(WindowTest, MoveCursorToWithComplexTransform) {
transform.Translate(10.0, 20.0);
transform.Rotate(10.0);
transform.Scale(0.3f, 0.5f);
- dispatcher()->SetTransform(root_transform);
+ host()->SetRootTransform(root_transform);
w1->SetTransform(transform);
w11->SetTransform(transform);
w111->SetTransform(transform);
@@ -463,67 +461,12 @@ TEST_F(WindowTest, MoveCursorToWithComplexTransform) {
#if !defined(OS_WIN)
// TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.
- gfx::Point mouse_location;
- EXPECT_TRUE(dispatcher()->host()->QueryMouseLocation(&mouse_location));
- EXPECT_EQ("169,80", mouse_location.ToString());
+ EXPECT_EQ("169,80", QueryLatestMousePositionRequestInHost(host()).ToString());
#endif
EXPECT_EQ("20,53",
gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString());
}
-TEST_F(WindowTest, HitTest) {
- Window w1(new ColorTestWindowDelegate(SK_ColorWHITE));
- w1.set_id(1);
- w1.Init(ui::LAYER_TEXTURED);
- w1.SetBounds(gfx::Rect(10, 20, 50, 60));
- w1.Show();
- ParentWindow(&w1);
-
- // Points are in the Window's coordinates.
- EXPECT_TRUE(w1.HitTest(gfx::Point(1, 1)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(-1, -1)));
-
- // We can expand the bounds slightly to track events outside our border.
- w1.SetHitTestBoundsOverrideOuter(gfx::Insets(-1, -1, -1, -1),
- gfx::Insets(-5, -5, -5, -5));
- EXPECT_TRUE(w1.HitTest(gfx::Point(-1, -1)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2)));
-
- ui::TouchEvent pressed(
- ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&pressed);
- EXPECT_TRUE(w1.HitTest(gfx::Point(-2, -2)));
- EXPECT_TRUE(w1.HitTest(gfx::Point(-5, -5)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(-5, -6)));
- ui::TouchEvent released(
- ui::ET_TOUCH_RELEASED, gfx::Point(50, 50), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&released);
- EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2)));
-
- // TODO(beng): clip Window to parent.
-}
-
-TEST_F(WindowTest, HitTestMask) {
- MaskedWindowDelegate d1(gfx::Rect(5, 6, 20, 30));
- Window w1(&d1);
- w1.Init(ui::LAYER_NOT_DRAWN);
- w1.SetBounds(gfx::Rect(10, 20, 50, 60));
- w1.Show();
- ParentWindow(&w1);
-
- // Points inside the mask.
- EXPECT_TRUE(w1.HitTest(gfx::Point(5, 6))); // top-left
- EXPECT_TRUE(w1.HitTest(gfx::Point(15, 21))); // center
- EXPECT_TRUE(w1.HitTest(gfx::Point(24, 35))); // bottom-right
-
- // Points outside the mask.
- EXPECT_FALSE(w1.HitTest(gfx::Point(0, 0)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(60, 80)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(4, 6)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(5, 5)));
- EXPECT_FALSE(w1.HitTest(gfx::Point(25, 36)));
-}
-
TEST_F(WindowTest, GetEventHandlerForPoint) {
scoped_ptr<Window> w1(
CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500),
@@ -660,7 +603,7 @@ TEST_F(WindowTest, WindowAddedToRootWindowShouldNotifyChildAndNotParent) {
AddedToRootWindowObserver child_observer;
scoped_ptr<Window> parent_window(CreateTestWindowWithId(1, root_window()));
scoped_ptr<Window> child_window(new Window(NULL));
- child_window->Init(ui::LAYER_TEXTURED);
+ child_window->Init(aura::WINDOW_LAYER_TEXTURED);
child_window->Show();
parent_window->AddObserver(&parent_observer);
@@ -709,11 +652,11 @@ TEST_F(WindowTest, OrphanedBeforeOnDestroyed) {
// Make sure StackChildAtTop moves both the window and layer to the front.
TEST_F(WindowTest, StackChildAtTop) {
Window parent(NULL);
- parent.Init(ui::LAYER_NOT_DRAWN);
+ parent.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child1(NULL);
- child1.Init(ui::LAYER_NOT_DRAWN);
+ child1.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child2(NULL);
- child2.Init(ui::LAYER_NOT_DRAWN);
+ child2.Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent.AddChild(&child1);
parent.AddChild(&child2);
@@ -736,15 +679,15 @@ TEST_F(WindowTest, StackChildAtTop) {
// Make sure StackChildBelow works.
TEST_F(WindowTest, StackChildBelow) {
Window parent(NULL);
- parent.Init(ui::LAYER_NOT_DRAWN);
+ parent.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child1(NULL);
- child1.Init(ui::LAYER_NOT_DRAWN);
+ child1.Init(aura::WINDOW_LAYER_NOT_DRAWN);
child1.set_id(1);
Window child2(NULL);
- child2.Init(ui::LAYER_NOT_DRAWN);
+ child2.Init(aura::WINDOW_LAYER_NOT_DRAWN);
child2.set_id(2);
Window child3(NULL);
- child3.Init(ui::LAYER_NOT_DRAWN);
+ child3.Init(aura::WINDOW_LAYER_NOT_DRAWN);
child3.set_id(3);
parent.AddChild(&child1);
@@ -768,13 +711,13 @@ TEST_F(WindowTest, StackChildBelow) {
// Various assertions for StackChildAbove.
TEST_F(WindowTest, StackChildAbove) {
Window parent(NULL);
- parent.Init(ui::LAYER_NOT_DRAWN);
+ parent.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child1(NULL);
- child1.Init(ui::LAYER_NOT_DRAWN);
+ child1.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child2(NULL);
- child2.Init(ui::LAYER_NOT_DRAWN);
+ child2.Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window child3(NULL);
- child3.Init(ui::LAYER_NOT_DRAWN);
+ child3.Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent.AddChild(&child1);
parent.AddChild(&child2);
@@ -848,7 +791,7 @@ TEST_F(WindowTest, CaptureTests) {
ui::TouchEvent touchev(
ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev);
+ DispatchEventUsingWindowDispatcher(&touchev);
EXPECT_EQ(1, delegate.touch_event_count());
delegate.ResetCounts();
@@ -864,7 +807,7 @@ TEST_F(WindowTest, CaptureTests) {
ui::TouchEvent touchev2(
ui::ET_TOUCH_PRESSED, gfx::Point(250, 250), 1, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev2);
+ DispatchEventUsingWindowDispatcher(&touchev2);
EXPECT_EQ(0, delegate.touch_event_count());
// Removing the capture window from parent should reset the capture window
@@ -887,7 +830,7 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) {
// Press on w1.
ui::TouchEvent press(
ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
// We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
EXPECT_EQ(2, delegate1.gesture_event_count());
delegate1.ResetCounts();
@@ -901,7 +844,7 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) {
// Events now go to w2.
ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_EQ(0, delegate1.gesture_event_count());
EXPECT_EQ(0, delegate1.touch_event_count());
EXPECT_EQ(0, delegate2.gesture_event_count());
@@ -909,14 +852,14 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) {
ui::TouchEvent release(
ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_EQ(0, delegate1.gesture_event_count());
EXPECT_EQ(0, delegate2.gesture_event_count());
// A new press is captured by w2.
ui::TouchEvent press2(
ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2);
+ DispatchEventUsingWindowDispatcher(&press2);
EXPECT_EQ(0, delegate1.gesture_event_count());
// We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
EXPECT_EQ(2, delegate2.gesture_event_count());
@@ -938,7 +881,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
ui::TouchEvent press(
ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
// We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
EXPECT_EQ(2, delegate.gesture_event_count());
@@ -953,7 +896,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
// On move We will get TOUCH_MOVED, GESTURE_TAP_CANCEL,
// GESTURE_SCROLL_START and GESTURE_SCROLL_UPDATE.
ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
+ DispatchEventUsingWindowDispatcher(&move);
EXPECT_EQ(1, delegate.touch_event_count());
EXPECT_EQ(3, delegate.gesture_event_count());
delegate.ResetCounts();
@@ -966,7 +909,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
// On move we still get TOUCH_MOVED and GESTURE_SCROLL_UPDATE.
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(10, 30), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2);
+ DispatchEventUsingWindowDispatcher(&move2);
EXPECT_EQ(1, delegate.touch_event_count());
EXPECT_EQ(1, delegate.gesture_event_count());
delegate.ResetCounts();
@@ -974,7 +917,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) {
// And on release we get TOUCH_RELEASED, GESTURE_SCROLL_END, GESTURE_END
ui::TouchEvent release(
ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ DispatchEventUsingWindowDispatcher(&release);
EXPECT_EQ(1, delegate.touch_event_count());
EXPECT_EQ(2, delegate.gesture_event_count());
}
@@ -987,7 +930,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) {
scoped_ptr<Window> w1(CreateTestWindowWithDelegate(
&d1, 0, gfx::Rect(0, 0, 20, 20), root_window()));
ui::TouchEvent p1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p1);
+ DispatchEventUsingWindowDispatcher(&p1);
// We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN.
EXPECT_EQ(1, d1.touch_event_count());
EXPECT_EQ(2, d1.gesture_event_count());
@@ -998,7 +941,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) {
scoped_ptr<Window> w2(CreateTestWindowWithDelegate(
&d2, 0, gfx::Rect(40, 0, 40, 20), root_window()));
ui::TouchEvent p2(ui::ET_TOUCH_PRESSED, gfx::Point(41, 10), 1, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p2);
+ DispatchEventUsingWindowDispatcher(&p2);
EXPECT_EQ(0, d1.touch_event_count());
EXPECT_EQ(0, d1.gesture_event_count());
// We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN for new target window.
@@ -1034,7 +977,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) {
// Move touch id originally associated with |w2|. Since capture was transfered
// from 2 to 3 only |w3| should get the event.
ui::TouchEvent m3(ui::ET_TOUCH_MOVED, gfx::Point(110, 105), 1, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&m3);
+ DispatchEventUsingWindowDispatcher(&m3);
EXPECT_EQ(0, d1.touch_event_count());
EXPECT_EQ(0, d1.gesture_event_count());
EXPECT_EQ(0, d2.touch_event_count());
@@ -1057,7 +1000,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) {
// And when we move the touch again, |w3| still gets the events.
ui::TouchEvent m4(ui::ET_TOUCH_MOVED, gfx::Point(120, 105), 1, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&m4);
+ DispatchEventUsingWindowDispatcher(&m4);
EXPECT_EQ(0, d1.touch_event_count());
EXPECT_EQ(0, d1.gesture_event_count());
EXPECT_EQ(0, d2.touch_event_count());
@@ -1123,7 +1066,7 @@ TEST_F(WindowTest, ReleaseCaptureOnDestroy) {
window.reset();
// Make sure the root window doesn't reference the window anymore.
- EXPECT_EQ(NULL, dispatcher()->mouse_pressed_handler());
+ EXPECT_EQ(NULL, host()->dispatcher()->mouse_pressed_handler());
EXPECT_EQ(NULL, aura::client::GetCaptureWindow(root_window()));
}
@@ -1208,7 +1151,7 @@ TEST_F(WindowTest, MouseEnterExit) {
}
// Verifies that the WindowDelegate receives MouseExit from ET_MOUSE_EXITED.
-TEST_F(WindowTest, RootWindowHostExit) {
+TEST_F(WindowTest, WindowTreeHostExit) {
MouseEnterExitWindowDelegate d1;
scoped_ptr<Window> w1(
CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50),
@@ -1221,8 +1164,8 @@ TEST_F(WindowTest, RootWindowHostExit) {
d1.ResetExpectations();
ui::MouseEvent exit_event(
- ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&exit_event);
+ ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), 0, 0);
+ DispatchEventUsingWindowDispatcher(&exit_event);
EXPECT_FALSE(d1.entered());
EXPECT_TRUE(d1.exited());
}
@@ -1298,21 +1241,23 @@ TEST_F(WindowTest, MouseEnterExitWithDelete) {
generator.MoveMouseToCenterOf(w1.get());
EXPECT_TRUE(d1.entered());
EXPECT_FALSE(d1.exited());
+ d1.ResetExpectations();
MouseEnterExitWindowDelegate d2;
{
scoped_ptr<Window> w2(
CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(10, 10, 50, 50),
root_window()));
- // Enters / exits can be send asynchronously.
+ // Enters / exits can be sent asynchronously.
RunAllPendingInMessageLoop();
- EXPECT_TRUE(d1.entered());
+ EXPECT_FALSE(d1.entered());
EXPECT_TRUE(d1.exited());
EXPECT_TRUE(d2.entered());
EXPECT_FALSE(d2.exited());
d1.ResetExpectations();
+ d2.ResetExpectations();
}
- // Enters / exits can be send asynchronously.
+ // Enters / exits can be sent asynchronously.
RunAllPendingInMessageLoop();
EXPECT_TRUE(d2.exited());
EXPECT_TRUE(d1.entered());
@@ -1538,7 +1483,7 @@ TEST_F(WindowTest, IgnoreEventsTest) {
// Tests transformation on the root window.
TEST_F(WindowTest, Transform) {
- gfx::Size size = dispatcher()->host()->GetBounds().size();
+ gfx::Size size = host()->GetBounds().size();
EXPECT_EQ(gfx::Rect(size),
gfx::Screen::GetScreenFor(root_window())->GetDisplayNearestPoint(
gfx::Point()).bounds());
@@ -1547,7 +1492,7 @@ TEST_F(WindowTest, Transform) {
gfx::Transform transform;
transform.Translate(size.height(), 0);
transform.Rotate(90.0);
- dispatcher()->SetTransform(transform);
+ host()->SetRootTransform(transform);
// The size should be the transformed size.
gfx::Size transformed_size(size.height(), size.width());
@@ -1559,12 +1504,11 @@ TEST_F(WindowTest, Transform) {
gfx::Point()).bounds().ToString());
// Host size shouldn't change.
- EXPECT_EQ(size.ToString(),
- dispatcher()->host()->GetBounds().size().ToString());
+ EXPECT_EQ(size.ToString(), host()->GetBounds().size().ToString());
}
TEST_F(WindowTest, TransformGesture) {
- gfx::Size size = dispatcher()->host()->GetBounds().size();
+ gfx::Size size = host()->GetBounds().size();
scoped_ptr<GestureTrackPositionDelegate> delegate(
new GestureTrackPositionDelegate);
@@ -1575,49 +1519,14 @@ TEST_F(WindowTest, TransformGesture) {
gfx::Transform transform;
transform.Translate(size.height(), 0.0);
transform.Rotate(90.0);
- dispatcher()->SetTransform(transform);
+ host()->SetRootTransform(transform);
ui::TouchEvent press(
ui::ET_TOUCH_PRESSED, gfx::Point(size.height() - 10, 10), 0, getTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ DispatchEventUsingWindowDispatcher(&press);
EXPECT_EQ(gfx::Point(10, 10).ToString(), delegate->position().ToString());
}
-// Various assertions for transient children.
-TEST_F(WindowTest, TransientChildren) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
- Window* w2 = CreateTestWindowWithId(2, parent.get());
- w1->AddTransientChild(w2); // w2 is now owned by w1.
- // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- ASSERT_EQ(3u, parent->children().size());
- EXPECT_EQ(w2, parent->children().back());
-
- // Destroy w1, which should also destroy w3 (since it's a transient child).
- w1.reset();
- w2 = NULL;
- ASSERT_EQ(1u, parent->children().size());
- EXPECT_EQ(w3.get(), parent->children()[0]);
-
- w1.reset(CreateTestWindowWithId(4, parent.get()));
- w2 = CreateTestWindowWithId(5, w3.get());
- w1->AddTransientChild(w2);
- parent->StackChildAtTop(w3.get());
- // Stack w1 at the top (end), this shouldn't affect w2 since it has a
- // different parent.
- parent->StackChildAtTop(w1.get());
- ASSERT_EQ(2u, parent->children().size());
- EXPECT_EQ(w3.get(), parent->children()[0]);
- EXPECT_EQ(w1.get(), parent->children()[1]);
-
- // Hiding parent should hide transient children.
- EXPECT_TRUE(w2->IsVisible());
- w1->Hide();
- EXPECT_FALSE(w2->IsVisible());
-}
-
namespace {
DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2);
DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
@@ -1717,7 +1626,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {
EXPECT_FALSE(!w1->layer());
w1->layer()->GetAnimator()->set_disable_timer_for_test(true);
- gfx::AnimationContainerElement* element = w1->layer()->GetAnimator();
+ ui::LayerAnimator* animator = w1->layer()->GetAnimator();
EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString());
@@ -1747,7 +1656,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) {
base::TimeTicks start_time =
w1->layer()->GetAnimator()->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_EQ("0,0 100x100", w1->bounds().ToString());
}
@@ -1971,6 +1880,12 @@ TEST_F(WindowTest, AcquireLayer) {
EXPECT_FALSE(window1_test_api.OwnsLayer());
EXPECT_TRUE(window1_layer.get() == window1->layer());
+ // The acquired layer's owner should be set NULL and re-acquring
+ // should return NULL.
+ EXPECT_FALSE(window1_layer->owner());
+ scoped_ptr<ui::Layer> window1_layer_reacquired(window1->AcquireLayer());
+ EXPECT_FALSE(window1_layer_reacquired.get());
+
// Upon destruction, window1's layer should still be valid, and in the layer
// hierarchy, but window2's should be gone, and no longer in the hierarchy.
window1.reset();
@@ -1987,11 +1902,10 @@ TEST_F(WindowTest, RecreateLayer) {
// Set properties to non default values.
Window w(new ColorTestWindowDelegate(SK_ColorWHITE));
w.set_id(1);
- w.Init(ui::LAYER_SOLID_COLOR);
+ w.Init(aura::WINDOW_LAYER_SOLID_COLOR);
w.SetBounds(gfx::Rect(0, 0, 100, 100));
ui::Layer* layer = w.layer();
- layer->set_scale_content(false);
layer->SetVisible(false);
layer->SetMasksToBounds(true);
@@ -2001,10 +1915,11 @@ TEST_F(WindowTest, RecreateLayer) {
scoped_ptr<ui::Layer> old_layer(w.RecreateLayer());
layer = w.layer();
EXPECT_EQ(ui::LAYER_SOLID_COLOR, layer->type());
- EXPECT_FALSE(layer->scale_content());
EXPECT_FALSE(layer->visible());
EXPECT_EQ(1u, layer->children().size());
EXPECT_TRUE(layer->GetMasksToBounds());
+ EXPECT_EQ("0,0 100x100", w.bounds().ToString());
+ EXPECT_EQ("0,0 100x100", layer->bounds().ToString());
}
// Verify that RecreateLayer() stacks the old layer above the newly creatd
@@ -2028,8 +1943,8 @@ TEST_F(WindowTest, AcquireThenRecreateLayer) {
scoped_ptr<Window> w(
CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(0, 0, 100, 100),
root_window()));
- scoped_ptr<ui::Layer>acquired_layer(w->AcquireLayer());
- scoped_ptr<ui::Layer>doubly_acquired_layer(w->RecreateLayer());
+ scoped_ptr<ui::Layer> acquired_layer(w->AcquireLayer());
+ scoped_ptr<ui::Layer> doubly_acquired_layer(w->RecreateLayer());
EXPECT_EQ(NULL, doubly_acquired_layer.get());
// Destroy window before layer gets destroyed.
@@ -2056,66 +1971,6 @@ TEST_F(WindowTest, StackWindowAtBottomBelowWindowWhoseLayerHasNoDelegate) {
ui::test::ChildLayerNamesAsString(*root_window()->layer()));
}
-TEST_F(WindowTest, StackWindowsWhoseLayersHaveNoDelegate) {
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- window1->layer()->set_name("1");
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- window2->layer()->set_name("2");
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
- window3->layer()->set_name("3");
-
- // This brings |window1| (and its layer) to the front.
- root_window()->StackChildAbove(window1.get(), window3.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // Since |window1| does not have a delegate, |window2| should not move in
- // front of it, nor should its layer.
- window1->layer()->set_delegate(NULL);
- root_window()->StackChildAbove(window2.get(), window1.get());
- EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("3 2 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // It should still be possible to stack |window3| immediately below |window1|.
- root_window()->StackChildBelow(window3.get(), window1.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // Since neither |window3| nor |window1| have a delegate, |window2| should
- // not move in front of either.
- window3->layer()->set_delegate(NULL);
- root_window()->StackChildBelow(window2.get(), window1.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-}
-
-TEST_F(WindowTest, StackTransientsWhoseLayersHaveNoDelegate) {
- // Create a window with several transients, then a couple windows on top.
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
- scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
- scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
-
- EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
-
- // Remove the delegates of a couple of transients, as if they are closing
- // and animating out.
- window11->layer()->set_delegate(NULL);
- window13->layer()->set_delegate(NULL);
-
- // Move window1 to the front. All transients should move with it, and their
- // order should be preserved.
- root_window()->StackChildAtTop(window1.get());
-
- EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
-}
-
class TestVisibilityClient : public client::VisibilityClient {
public:
explicit TestVisibilityClient(Window* root_window)
@@ -2161,7 +2016,7 @@ TEST_F(WindowTest, VisibilityClientIsVisible) {
// Tests mouse events on window change.
TEST_F(WindowTest, MouseEventsOnWindowChange) {
- gfx::Size size = dispatcher()->host()->GetBounds().size();
+ gfx::Size size = host()->GetBounds().size();
EventGenerator generator(root_window());
generator.MoveMouseTo(50, 50);
@@ -2253,240 +2108,6 @@ TEST_F(WindowTest, MouseEventsOnWindowChange) {
EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
}
-class StackingMadrigalLayoutManager : public LayoutManager {
- public:
- explicit StackingMadrigalLayoutManager(Window* root_window)
- : root_window_(root_window) {
- root_window_->SetLayoutManager(this);
- }
- virtual ~StackingMadrigalLayoutManager() {
- }
-
- private:
- // Overridden from LayoutManager:
- virtual void OnWindowResized() OVERRIDE {}
- virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {}
- virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {}
- virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {}
- virtual void OnChildWindowVisibilityChanged(Window* child,
- bool visible) OVERRIDE {
- Window::Windows::const_iterator it = root_window_->children().begin();
- Window* last_window = NULL;
- for (; it != root_window_->children().end(); ++it) {
- if (*it == child && last_window) {
- if (!visible)
- root_window_->StackChildAbove(last_window, *it);
- else
- root_window_->StackChildAbove(*it, last_window);
- break;
- }
- last_window = *it;
- }
- }
- virtual void SetChildBounds(Window* child,
- const gfx::Rect& requested_bounds) OVERRIDE {
- SetChildBoundsDirect(child, requested_bounds);
- }
-
- Window* root_window_;
-
- DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
-};
-
-class StackingMadrigalVisibilityClient : public client::VisibilityClient {
- public:
- explicit StackingMadrigalVisibilityClient(Window* root_window)
- : ignored_window_(NULL) {
- client::SetVisibilityClient(root_window, this);
- }
- virtual ~StackingMadrigalVisibilityClient() {
- }
-
- void set_ignored_window(Window* ignored_window) {
- ignored_window_ = ignored_window;
- }
-
- private:
- // Overridden from client::VisibilityClient:
- virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
- if (!visible) {
- if (window == ignored_window_)
- window->layer()->set_delegate(NULL);
- else
- window->layer()->SetVisible(visible);
- } else {
- window->layer()->SetVisible(visible);
- }
- }
-
- Window* ignored_window_;
-
- DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
-};
-
-// This test attempts to reconstruct a circumstance that can happen when the
-// aura client attempts to manipulate the visibility and delegate of a layer
-// independent of window visibility.
-// A use case is where the client attempts to keep a window visible onscreen
-// even after code has called Hide() on the window. The use case for this would
-// be that window hides are animated (e.g. the window fades out). To prevent
-// spurious updating the client code may also clear window's layer's delegate,
-// so that the window cannot attempt to paint or update it further. The window
-// uses the presence of a NULL layer delegate as a signal in stacking to note
-// that the window is being manipulated by such a use case and its stacking
-// should not be adjusted.
-// One issue that can arise when a window opens two transient children, and the
-// first is hidden. Subsequent attempts to activate the transient parent can
-// result in the transient parent being stacked above the second transient
-// child. A fix is made to Window::StackAbove to prevent this, and this test
-// verifies this fix.
-TEST_F(WindowTest, StackingMadrigal) {
- new StackingMadrigalLayoutManager(root_window());
- StackingMadrigalVisibilityClient visibility_client(root_window());
-
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
-
- visibility_client.set_ignored_window(window11.get());
-
- window11->Show();
- window11->Hide();
-
- // As a transient, window11 should still be stacked above window1, even when
- // hidden.
- EXPECT_TRUE(WindowIsAbove(window11.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window11.get(), window1.get()));
-
- // A new transient should still be above window1. It will appear behind
- // window11 because we don't stack windows on top of targets with NULL
- // delegates.
- scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
- window12->Show();
-
- EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
-
- // In earlier versions of the StackChildAbove() method, attempting to stack
- // window1 above window12 at this point would actually restack the layers
- // resulting in window12's layer being below window1's layer (though the
- // windows themselves would still be correctly stacked, so events would pass
- // through.)
- root_window()->StackChildAbove(window1.get(), window12.get());
-
- // Both window12 and its layer should be stacked above window1.
- EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
-}
-
-// Test for an issue where attempting to stack a primary window on top of a
-// transient with a NULL layer delegate causes that primary window to be moved,
-// but the layer order not changed to match. http://crbug.com/112562
-TEST_F(WindowTest, StackOverClosingTransient) {
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
-
- // Both windows and layers are stacked in creation order.
- Window* root = root_window();
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], transient1.get());
- EXPECT_EQ(root->children()[2], window2.get());
- EXPECT_EQ(root->children()[3], transient2.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], transient1->layer());
- EXPECT_EQ(root->layer()->children()[2], window2->layer());
- EXPECT_EQ(root->layer()->children()[3], transient2->layer());
- EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window()));
-
- // This brings window1 and its transient to the front.
- root->StackChildAtTop(window1.get());
- EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window()));
-
- EXPECT_EQ(root->children()[0], window2.get());
- EXPECT_EQ(root->children()[1], transient2.get());
- EXPECT_EQ(root->children()[2], window1.get());
- EXPECT_EQ(root->children()[3], transient1.get());
- EXPECT_EQ(root->layer()->children()[0], window2->layer());
- EXPECT_EQ(root->layer()->children()[1], transient2->layer());
- EXPECT_EQ(root->layer()->children()[2], window1->layer());
- EXPECT_EQ(root->layer()->children()[3], transient1->layer());
-
- // Pretend we're closing the top-most transient, then bring window2 to the
- // front. This mimics activating a browser window while the status bubble
- // is fading out. The transient should stay topmost.
- transient1->layer()->set_delegate(NULL);
- root->StackChildAtTop(window2.get());
-
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], transient1.get());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], transient1->layer());
-
- // Close the transient. Remaining windows are stable.
- transient1.reset();
-
- ASSERT_EQ(3u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- ASSERT_EQ(3u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
-
- // Open another window on top.
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-
- // Pretend we're closing the topmost non-transient window, then bring
- // window2 to the top. It should not move.
- window3->layer()->set_delegate(NULL);
- root->StackChildAtTop(window2.get());
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-
- // Bring window1 to the top. It should move ahead of window2, but not
- // ahead of window3 (with NULL delegate).
- root->StackChildAtTop(window1.get());
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window2.get());
- EXPECT_EQ(root->children()[1], transient2.get());
- EXPECT_EQ(root->children()[2], window1.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window2->layer());
- EXPECT_EQ(root->layer()->children()[1], transient2->layer());
- EXPECT_EQ(root->layer()->children()[2], window1->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-}
-
class RootWindowAttachmentObserver : public WindowObserver {
public:
RootWindowAttachmentObserver() : added_count_(0), removed_count_(0) {}
@@ -2504,7 +2125,8 @@ class RootWindowAttachmentObserver : public WindowObserver {
virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE {
++added_count_;
}
- virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE {
+ virtual void OnWindowRemovingFromRootWindow(Window* window,
+ Window* new_root) OVERRIDE {
++removed_count_;
}
@@ -2520,7 +2142,7 @@ TEST_F(WindowTest, RootWindowAttachment) {
// Test a direct add/remove from the RootWindow.
scoped_ptr<Window> w1(new Window(NULL));
- w1->Init(ui::LAYER_NOT_DRAWN);
+ w1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w1->AddObserver(&observer);
ParentWindow(w1.get());
@@ -2535,9 +2157,9 @@ TEST_F(WindowTest, RootWindowAttachment) {
// Test an indirect add/remove from the RootWindow.
w1.reset(new Window(NULL));
- w1->Init(ui::LAYER_NOT_DRAWN);
+ w1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
Window* w11 = new Window(NULL);
- w11->Init(ui::LAYER_NOT_DRAWN);
+ w11->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w11->AddObserver(&observer);
w1->AddChild(w11);
EXPECT_EQ(0, observer.added_count());
@@ -2556,13 +2178,13 @@ TEST_F(WindowTest, RootWindowAttachment) {
// Test an indirect add/remove with nested observers.
w1.reset(new Window(NULL));
- w1->Init(ui::LAYER_NOT_DRAWN);
+ w1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w11 = new Window(NULL);
- w11->Init(ui::LAYER_NOT_DRAWN);
+ w11->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w11->AddObserver(&observer);
w1->AddChild(w11);
Window* w111 = new Window(NULL);
- w111->Init(ui::LAYER_NOT_DRAWN);
+ w111->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w111->AddObserver(&observer);
w11->AddChild(w111);
@@ -2580,15 +2202,71 @@ TEST_F(WindowTest, RootWindowAttachment) {
EXPECT_EQ(2, observer.removed_count());
}
+class BoundsChangedWindowObserver : public WindowObserver {
+ public:
+ BoundsChangedWindowObserver() : root_set_(false) {}
+
+ virtual void OnWindowBoundsChanged(Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE {
+ root_set_ = window->GetRootWindow() != NULL;
+ }
+
+ bool root_set() const { return root_set_; }
+
+ private:
+ bool root_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundsChangedWindowObserver);
+};
+
+TEST_F(WindowTest, RootWindowSetWhenReparenting) {
+ Window parent1(NULL);
+ parent1.Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ Window parent2(NULL);
+ parent2.Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ ParentWindow(&parent1);
+ ParentWindow(&parent2);
+ parent1.SetBounds(gfx::Rect(10, 10, 300, 300));
+ parent2.SetBounds(gfx::Rect(20, 20, 300, 300));
+
+ BoundsChangedWindowObserver observer;
+ Window child(NULL);
+ child.Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ child.SetBounds(gfx::Rect(5, 5, 100, 100));
+ parent1.AddChild(&child);
+
+ // We need animations to start in order to observe the bounds changes.
+ ui::ScopedAnimationDurationScaleMode animation_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::ScopedLayerAnimationSettings settings1(child.layer()->GetAnimator());
+ settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100));
+ gfx::Rect new_bounds(gfx::Rect(35, 35, 50, 50));
+ child.SetBounds(new_bounds);
+
+ child.AddObserver(&observer);
+
+ // Reparenting the |child| will cause it to get moved. During this move
+ // the window should still have root window set.
+ parent2.AddChild(&child);
+ EXPECT_TRUE(observer.root_set());
+
+ // Animations should stop and the bounds should be as set before the |child|
+ // got reparented.
+ EXPECT_EQ(new_bounds.ToString(), child.GetTargetBounds().ToString());
+ EXPECT_EQ(new_bounds.ToString(), child.bounds().ToString());
+ EXPECT_EQ("55,55 50x50", child.GetBoundsInRootWindow().ToString());
+}
+
TEST_F(WindowTest, OwnedByParentFalse) {
// By default, a window is owned by its parent. If this is set to false, the
// window will not be destroyed when its parent is.
scoped_ptr<Window> w1(new Window(NULL));
- w1->Init(ui::LAYER_NOT_DRAWN);
+ w1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
scoped_ptr<Window> w2(new Window(NULL));
w2->set_owned_by_parent(false);
- w2->Init(ui::LAYER_NOT_DRAWN);
+ w2->Init(aura::WINDOW_LAYER_NOT_DRAWN);
w1->AddChild(w2.get());
w1.reset();
@@ -2609,7 +2287,7 @@ class OwningWindowDelegate : public TestWindowDelegate {
owned_window_.reset(window);
}
- virtual void OnWindowDestroyed() OVERRIDE {
+ virtual void OnWindowDestroyed(Window* window) OVERRIDE {
owned_window_.reset(NULL);
}
@@ -2628,13 +2306,13 @@ class OwningWindowDelegate : public TestWindowDelegate {
// bubble.
TEST_F(WindowTest, DeleteWindowFromOnWindowDestroyed) {
scoped_ptr<Window> parent(new Window(NULL));
- parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
OwningWindowDelegate delegate;
Window* c1 = new Window(&delegate);
- c1->Init(ui::LAYER_NOT_DRAWN);
+ c1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->AddChild(c1);
Window* c2 = new Window(NULL);
- c2->Init(ui::LAYER_NOT_DRAWN);
+ c2->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->AddChild(c2);
delegate.SetOwnedWindow(c2);
parent.reset();
@@ -2697,8 +2375,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChange) {
// Animate to the end, which should notify of the change.
base::TimeTicks start_time =
window->layer()->GetAnimator()->last_step_time();
- gfx::AnimationContainerElement* element = window->layer()->GetAnimator();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ ui::LayerAnimator* animator = window->layer()->GetAnimator();
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(delegate.bounds_changed());
EXPECT_NE("0,0 100x100", window->bounds().ToString());
}
@@ -2739,8 +2417,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) {
// Animate to the end: will *not* notify of the change since we are hidden.
base::TimeTicks start_time =
window->layer()->GetAnimator()->last_step_time();
- gfx::AnimationContainerElement* element = window->layer()->GetAnimator();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ ui::LayerAnimator* animator = window->layer()->GetAnimator();
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
// No bounds changed notification at the end of animation since layer
// delegate is NULL.
@@ -2766,7 +2444,8 @@ class AddChildNotificationsObserver : public WindowObserver {
virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE {
added_count_++;
}
- virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE {
+ virtual void OnWindowRemovingFromRootWindow(Window* window,
+ Window* new_root) OVERRIDE {
removed_count_++;
}
@@ -3007,59 +2686,15 @@ TEST_F(WindowTest, OnWindowHierarchyChange) {
}
-namespace {
-
-// Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
-// OnWindowDestroyed() is invoked so that destruction order can be verified.
-class DestroyedTrackingDelegate : public TestWindowDelegate {
- public:
- explicit DestroyedTrackingDelegate(const std::string& name,
- std::vector<std::string>* results)
- : name_(name),
- results_(results) {}
-
- virtual void OnWindowDestroyed() OVERRIDE {
- results_->push_back(name_);
- }
-
- private:
- const std::string name_;
- std::vector<std::string>* results_;
-
- DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
-};
-
-} // namespace
-
-// Verifies the delegate is notified of destruction after transients are
-// destroyed.
-TEST_F(WindowTest, NotifyDelegateAfterDeletingTransients) {
- std::vector<std::string> destruction_order;
-
- DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
- scoped_ptr<Window> parent(new Window(&parent_delegate));
- parent->Init(ui::LAYER_NOT_DRAWN);
-
- DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
- Window* transient = new Window(&transient_delegate); // Owned by |parent|.
- transient->Init(ui::LAYER_NOT_DRAWN);
- parent->AddTransientChild(transient);
- parent.reset();
-
- ASSERT_EQ(2u, destruction_order.size());
- EXPECT_EQ("transient", destruction_order[0]);
- EXPECT_EQ("parent", destruction_order[1]);
-}
-
// Verifies SchedulePaint() on a layerless window results in damaging the right
// thing.
TEST_F(WindowTest, LayerlessWindowSchedulePaint) {
Window root(NULL);
- root.Init(ui::LAYER_NOT_DRAWN);
+ root.Init(aura::WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* layerless_window = new Window(NULL); // Owned by |root|.
- layerless_window->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ layerless_window->Init(WINDOW_LAYER_NONE);
layerless_window->SetBounds(gfx::Rect(10, 11, 12, 13));
root.AddChild(layerless_window);
@@ -3071,7 +2706,7 @@ TEST_F(WindowTest, LayerlessWindowSchedulePaint) {
ToString());
Window* layerless_window2 = new Window(NULL); // Owned by |layerless_window|.
- layerless_window2->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ layerless_window2->Init(WINDOW_LAYER_NONE);
layerless_window2->SetBounds(gfx::Rect(1, 2, 3, 4));
layerless_window->AddChild(layerless_window2);
@@ -3097,30 +2732,30 @@ TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnAddRemove) {
//
// ll: layer less, eg no layer
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ root.Init(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(NULL);
- w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w1ll->Init(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 100, 100));
Window* w11ll = new Window(NULL);
- w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w11ll->Init(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 100, 100));
w1ll->AddChild(w11ll);
Window* w111 = new Window(NULL);
- w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w111->Init(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w11ll->AddChild(w111);
Window* w12 = new Window(NULL);
- w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w12->Init(WINDOW_LAYER_NOT_DRAWN);
w12->SetBounds(gfx::Rect(7, 8, 100, 100));
w1ll->AddChild(w12);
Window* w121 = new Window(NULL);
- w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w121->Init(WINDOW_LAYER_NOT_DRAWN);
w121->SetBounds(gfx::Rect(9, 10, 100, 100));
w12->AddChild(w121);
@@ -3177,30 +2812,30 @@ TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnSetBounds) {
//
// ll: layer less, eg no layer
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ root.Init(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(NULL);
- w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w1ll->Init(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 100, 100));
Window* w11ll = new Window(NULL);
- w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w11ll->Init(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 100, 100));
w1ll->AddChild(w11ll);
Window* w111 = new Window(NULL);
- w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w111->Init(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w11ll->AddChild(w111);
Window* w12 = new Window(NULL);
- w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w12->Init(WINDOW_LAYER_NOT_DRAWN);
w12->SetBounds(gfx::Rect(7, 8, 100, 100));
w1ll->AddChild(w12);
Window* w121 = new Window(NULL);
- w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w121->Init(WINDOW_LAYER_NOT_DRAWN);
w121->SetBounds(gfx::Rect(9, 10, 100, 100));
w12->AddChild(w121);
@@ -3291,23 +2926,23 @@ TEST_F(WindowTest, PaintLayerless) {
PaintWindowDelegate w111_delegate;
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ root.Init(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(&w1ll_delegate);
- w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w1ll->Init(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 40, 50));
w1ll->Show();
root.AddChild(w1ll);
Window* w11ll = new Window(&w11ll_delegate);
- w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w11ll->Init(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 11, 12));
w11ll->Show();
w1ll->AddChild(w11ll);
Window* w111 = new Window(&w111_delegate);
- w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w111->Init(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w111->Show();
w11ll->AddChild(w111);
@@ -3359,30 +2994,30 @@ TEST_F(WindowTest, ConvertPointToTargetLayerless) {
//
// ll: layer less, eg no layer
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ root.Init(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(NULL);
- w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w1ll->Init(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 100, 100));
Window* w11ll = new Window(NULL);
- w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ w11ll->Init(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 100, 100));
w1ll->AddChild(w11ll);
Window* w111 = new Window(NULL);
- w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w111->Init(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w11ll->AddChild(w111);
Window* w12 = new Window(NULL);
- w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w12->Init(WINDOW_LAYER_NOT_DRAWN);
w12->SetBounds(gfx::Rect(7, 8, 100, 100));
w1ll->AddChild(w12);
Window* w121 = new Window(NULL);
- w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ w121->Init(WINDOW_LAYER_NOT_DRAWN);
w121->SetBounds(gfx::Rect(9, 10, 100, 100));
w12->AddChild(w121);
@@ -3420,7 +3055,7 @@ TEST_F(WindowTest, ConvertPointToTargetLayerless) {
// Verifies PrintWindowHierarchy() doesn't crash with a layerless window.
TEST_F(WindowTest, PrintWindowHierarchyNotCrashLayerless) {
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NONE);
+ root.Init(WINDOW_LAYER_NONE);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
root.PrintWindowHierarchy(0);
}
@@ -3446,7 +3081,7 @@ aura::Window* CreateWindowFromDescription(const std::string& description,
<< description;
}
Window* window = new Window(delegate);
- window->InitWithWindowLayerType(window_type);
+ window->Init(window_type);
window->SetName(name);
// Window name is only propagated to layer in debug builds.
if (window->layer())
@@ -3676,7 +3311,7 @@ TEST_F(WindowTest, StackChildAtLayerless) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
test::TestWindowDelegate delegate;
Window root(NULL);
- root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
+ root.Init(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
AddWindowsFromString(
&root,
@@ -3713,5 +3348,95 @@ TEST_F(WindowTest, StackChildAtLayerless) {
}
}
+namespace {
+
+class TestLayerAnimationObserver : public ui::LayerAnimationObserver {
+ public:
+ TestLayerAnimationObserver()
+ : animation_completed_(false),
+ animation_aborted_(false) {}
+ virtual ~TestLayerAnimationObserver() {}
+
+ bool animation_completed() const { return animation_completed_; }
+ bool animation_aborted() const { return animation_aborted_; }
+
+ void Reset() {
+ animation_completed_ = false;
+ animation_aborted_ = false;
+ }
+
+ private:
+ // ui::LayerAnimationObserver:
+ virtual void OnLayerAnimationEnded(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {
+ animation_completed_ = true;
+ }
+
+ virtual void OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {
+ animation_aborted_ = true;
+ }
+
+ virtual void OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {
+ }
+
+ bool animation_completed_;
+ bool animation_aborted_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationObserver);
+};
+
+}
+
+TEST_F(WindowTest, WindowDestroyCompletesAnimations) {
+ ui::ScopedAnimationDurationScaleMode normal_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ scoped_refptr<ui::LayerAnimator> animator =
+ ui::LayerAnimator::CreateImplicitAnimator();
+ TestLayerAnimationObserver observer;
+ animator->AddObserver(&observer);
+ // Make sure destroying a Window completes the animation.
+ {
+ scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
+ window->layer()->SetAnimator(animator);
+
+ gfx::Transform transform;
+ transform.Scale(0.5f, 0.5f);
+ window->SetTransform(transform);
+
+ EXPECT_TRUE(animator->is_animating());
+ EXPECT_FALSE(observer.animation_completed());
+ }
+ EXPECT_TRUE(animator);
+ EXPECT_FALSE(animator->is_animating());
+ EXPECT_TRUE(observer.animation_completed());
+ EXPECT_FALSE(observer.animation_aborted());
+ animator->RemoveObserver(&observer);
+ observer.Reset();
+
+ animator = ui::LayerAnimator::CreateImplicitAnimator();
+ animator->AddObserver(&observer);
+ ui::Layer layer;
+ layer.SetAnimator(animator);
+ {
+ scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window()));
+ window->layer()->Add(&layer);
+
+ gfx::Transform transform;
+ transform.Scale(0.5f, 0.5f);
+ layer.SetTransform(transform);
+
+ EXPECT_TRUE(animator->is_animating());
+ EXPECT_FALSE(observer.animation_completed());
+ }
+
+ EXPECT_TRUE(animator);
+ EXPECT_FALSE(animator->is_animating());
+ EXPECT_TRUE(observer.animation_completed());
+ EXPECT_FALSE(observer.animation_aborted());
+ animator->RemoveObserver(&observer);
+}
+
} // namespace test
} // namespace aura
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
new file mode 100644
index 00000000000..fe42ae9ec26
--- /dev/null
+++ b/chromium/ui/base/BUILD.gn
@@ -0,0 +1,556 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+component("base") {
+ output_name = "ui_base"
+ sources = [
+ "accelerators/accelerator.cc",
+ "accelerators/accelerator.h",
+ "accelerators/accelerator_manager.cc",
+ "accelerators/accelerator_manager.h",
+ "accelerators/menu_label_accelerator_util_linux.cc",
+ "accelerators/menu_label_accelerator_util_linux.h",
+ "accelerators/platform_accelerator.h",
+ "accelerators/platform_accelerator_cocoa.h",
+ "accelerators/platform_accelerator_cocoa.mm",
+ "android/ui_base_jni_registrar.cc",
+ "android/ui_base_jni_registrar.h",
+ "android/view_android.cc",
+ "android/view_android.h",
+ "android/window_android.cc",
+ "android/window_android.h",
+ "android/window_android_compositor.h",
+ "android/window_android_observer.h",
+ "base_window.cc",
+ "base_window.h",
+ "clipboard/clipboard.cc",
+ "clipboard/clipboard.h",
+ "clipboard/clipboard_android.cc",
+ "clipboard/clipboard_android_initialization.h",
+ "clipboard/clipboard_constants.cc",
+ "clipboard/clipboard_mac.mm",
+ "clipboard/clipboard_types.h",
+ "clipboard/clipboard_util_win.cc",
+ "clipboard/clipboard_util_win.h",
+ "clipboard/clipboard_win.cc",
+ "clipboard/custom_data_helper.cc",
+ "clipboard/custom_data_helper.h",
+ "clipboard/custom_data_helper_linux.cc",
+ "clipboard/custom_data_helper_mac.mm",
+ "clipboard/scoped_clipboard_writer.cc",
+ "clipboard/scoped_clipboard_writer.h",
+ "cocoa/animation_utils.h",
+ "cocoa/appkit_utils.h",
+ "cocoa/appkit_utils.mm",
+ "cocoa/base_view.h",
+ "cocoa/base_view.mm",
+ "cocoa/cocoa_base_utils.h",
+ "cocoa/cocoa_base_utils.mm",
+ "cocoa/controls/blue_label_button.h",
+ "cocoa/controls/blue_label_button.mm",
+ "cocoa/controls/hover_image_menu_button.h",
+ "cocoa/controls/hover_image_menu_button.mm",
+ "cocoa/controls/hover_image_menu_button_cell.h",
+ "cocoa/controls/hover_image_menu_button_cell.mm",
+ "cocoa/controls/hyperlink_button_cell.h",
+ "cocoa/controls/hyperlink_button_cell.mm",
+ "cocoa/find_pasteboard.h",
+ "cocoa/find_pasteboard.mm",
+ "cocoa/flipped_view.h",
+ "cocoa/flipped_view.mm",
+ "cocoa/focus_tracker.h",
+ "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",
+ "cocoa/hover_image_button.mm",
+ "cocoa/menu_controller.h",
+ "cocoa/menu_controller.mm",
+ "cocoa/nib_loading.h",
+ "cocoa/nib_loading.mm",
+ "cocoa/nsgraphics_context_additions.h",
+ "cocoa/nsgraphics_context_additions.mm",
+ "cocoa/tracking_area.h",
+ "cocoa/tracking_area.mm",
+ "cocoa/underlay_opengl_hosting_window.h",
+ "cocoa/underlay_opengl_hosting_window.mm",
+ "cocoa/view_description.h",
+ "cocoa/view_description.mm",
+ "cocoa/window_size_constants.h",
+ "cocoa/window_size_constants.mm",
+ "cursor/cursor.cc",
+ "cursor/cursor.h",
+ "cursor/cursor_android.cc",
+ "cursor/cursor_loader.h",
+ "cursor/cursor_loader_win.cc",
+ "cursor/cursor_loader_win.h",
+ "cursor/cursor_util.cc",
+ "cursor/cursor_util.h",
+ "cursor/cursor_win.cc",
+ "cursor/cursors_aura.cc",
+ "cursor/cursors_aura.h",
+ "default_theme_provider.cc",
+ "default_theme_provider.h",
+ "default_theme_provider_mac.mm",
+ "device_form_factor_android.cc",
+ "device_form_factor_android.h",
+ "device_form_factor_desktop.cc",
+ "device_form_factor_ios.mm",
+ "device_form_factor.h",
+ "dragdrop/cocoa_dnd_util.h",
+ "dragdrop/cocoa_dnd_util.mm",
+ "dragdrop/drag_drop_types.h",
+ "dragdrop/drag_drop_types.h",
+ "dragdrop/drag_drop_types_win.cc",
+ "dragdrop/drag_source_win.cc",
+ "dragdrop/drag_source_win.h",
+ "dragdrop/drag_utils.cc",
+ "dragdrop/drag_utils.h",
+ "dragdrop/drag_utils_aura.cc",
+ "dragdrop/drag_utils_win.cc",
+ "dragdrop/drop_target_event.cc",
+ "dragdrop/drop_target_event.h",
+ "dragdrop/drop_target_win.cc",
+ "dragdrop/drop_target_win.h",
+ "dragdrop/file_info.cc",
+ "dragdrop/file_info.h",
+ "dragdrop/os_exchange_data.cc",
+ "dragdrop/os_exchange_data.h",
+ "dragdrop/os_exchange_data_provider_win.cc",
+ "dragdrop/os_exchange_data_provider_win.h",
+ "hit_test.h",
+ "l10n/formatter.cc",
+ "l10n/formatter.h",
+ "l10n/l10n_font_util.cc",
+ "l10n/l10n_font_util.h",
+ "l10n/l10n_util.cc",
+ "l10n/l10n_util.h",
+ "l10n/l10n_util_android.cc",
+ "l10n/l10n_util_android.h",
+ "l10n/l10n_util_collator.h",
+ "l10n/l10n_util_mac.h",
+ "l10n/l10n_util_mac.mm",
+ "l10n/l10n_util_plurals.cc",
+ "l10n/l10n_util_plurals.h",
+ "l10n/l10n_util_posix.cc",
+ "l10n/l10n_util_win.cc",
+ "l10n/l10n_util_win.h",
+ "l10n/time_format.cc",
+ "l10n/time_format.h",
+ "layout.cc",
+ "layout.h",
+ "layout_mac.mm",
+ "models/button_menu_item_model.cc",
+ "models/button_menu_item_model.h",
+ "models/combobox_model.cc",
+ "models/combobox_model.h",
+ "models/combobox_model_observer.h",
+ "models/dialog_model.cc",
+ "models/dialog_model.h",
+ "models/list_model.h",
+ "models/list_model_observer.h",
+ "models/list_selection_model.cc",
+ "models/list_selection_model.h",
+ "models/menu_model.cc",
+ "models/menu_model.h",
+ "models/menu_model_delegate.h",
+ "models/menu_separator_types.h",
+ "models/simple_menu_model.cc",
+ "models/simple_menu_model.h",
+ "models/table_model.cc",
+ "models/table_model.h",
+ "models/table_model_observer.h",
+ "models/tree_model.cc",
+ "models/tree_model.h",
+ "models/tree_node_iterator.h",
+ "models/tree_node_model.h",
+ "nine_image_painter_factory.cc",
+ "nine_image_painter_factory.h",
+ "resource/data_pack.cc",
+ "resource/data_pack.h",
+ "resource/resource_bundle.cc",
+ "resource/resource_bundle.h",
+ "resource/resource_bundle_android.cc",
+ "resource/resource_bundle_auralinux.cc",
+ "resource/resource_bundle_ios.mm",
+ "resource/resource_bundle_mac.mm",
+ "resource/resource_bundle_win.cc",
+ "resource/resource_bundle_win.h",
+ "resource/resource_data_dll_win.cc",
+ "resource/resource_data_dll_win.h",
+ "resource/resource_handle.h",
+ "text/bytes_formatting.cc",
+ "text/bytes_formatting.h",
+ "theme_provider.cc",
+ "theme_provider.h",
+ "touch/touch_device.h",
+ "touch/touch_editing_controller.cc",
+ "touch/touch_editing_controller.h",
+ "touch/touch_enabled.cc",
+ "touch/touch_enabled.h",
+ "ui_base_exports.cc",
+ "ui_base_paths.cc",
+ "ui_base_paths.h",
+ "ui_base_switches.cc",
+ "ui_base_switches.h",
+ "ui_base_switches_util.cc",
+ "ui_base_switches_util.h",
+ "ui_base_types.cc",
+ "ui_base_types.h",
+ "ui_base_export.h",
+ "view_prop.cc",
+ "view_prop.h",
+ "webui/jstemplate_builder.cc",
+ "webui/jstemplate_builder.h",
+ "webui/web_ui_util.cc",
+ "webui/web_ui_util.h",
+ "win/accessibility_ids_win.h",
+ "win/accessibility_misc_utils.cc",
+ "win/accessibility_misc_utils.h",
+ "win/atl_module.h",
+ "win/dpi_setup.cc",
+ "win/dpi_setup.h",
+ "win/foreground_helper.cc",
+ "win/foreground_helper.h",
+ "win/hidden_window.cc",
+ "win/hidden_window.h",
+ "win/hwnd_subclass.cc",
+ "win/hwnd_subclass.h",
+ "win/internal_constants.cc",
+ "win/internal_constants.h",
+ "win/lock_state.cc",
+ "win/lock_state.h",
+ "win/message_box_win.cc",
+ "win/message_box_win.h",
+ "win/mouse_wheel_util.cc",
+ "win/mouse_wheel_util.h",
+ "win/scoped_ole_initializer.cc",
+ "win/scoped_ole_initializer.h",
+ "win/shell.cc",
+ "win/shell.h",
+ "win/touch_input.cc",
+ "win/touch_input.h",
+ "win/window_event_target.cc",
+ "win/window_event_target.h",
+ "window_open_disposition.cc",
+ "window_open_disposition.h",
+ "work_area_watcher_observer.h",
+ "x/x11_menu_list.cc",
+ "x/x11_menu_list.h",
+ "x/x11_util.cc",
+ "x/x11_util.h",
+ "x/x11_util_internal.h",
+ ]
+
+ if (is_win) {
+ sources += [ "touch/touch_device_win.cc" ]
+ } else if (is_android) {
+ sources += [ "touch/touch_device_android.cc" ]
+ } else if (use_ozone) {
+ sources += [ "touch/touch_device_ozone.cc" ]
+ } else if (use_aura && use_x11) {
+ sources += [ "touch/touch_device_aurax11.cc" ]
+ } else {
+ # Empty implementation for all other cases.
+ sources += [ "touch/touch_device.cc" ]
+ }
+
+ defines = [ "UI_BASE_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//base:base_static",
+ "//base:i18n",
+ "//net",
+ "//skia",
+ "//third_party/icu",
+ "//ui/resources",
+ "//ui/resources:unscaled_resources",
+ "//ui/strings",
+ "//ui/webui/resources",
+ "//url",
+ ]
+
+ if (is_ios) {
+ sources += [
+ "l10n/l10n_util_mac.h",
+ "l10n/l10n_util_mac.mm",
+ ]
+ }
+
+ if (toolkit_views) {
+ deps += [
+ "//ui/events",
+ ]
+ }
+
+ if (use_x11 && use_aura) {
+ sources += [
+ "x/selection_owner.cc",
+ "x/selection_owner.h",
+ "x/selection_requestor.cc",
+ "x/selection_requestor.h",
+ "x/selection_utils.cc",
+ "x/selection_utils.h",
+ ]
+ }
+
+ if (use_aura) {
+ deps += [
+ "//ui/events",
+ ]
+ } else {
+ sources -= [
+ "cursor/cursor.cc",
+ "cursor/cursor.h",
+ "dragdrop/drag_utils_aura.cc",
+ ]
+ }
+ if (!use_x11) {
+ sources -= [
+ "x/x11_util.cc",
+ "x/x11_util.h",
+ "x/x11_util_internal.h",
+ ]
+ }
+
+ if (!use_aura || !is_linux) {
+ sources -= [
+ "resource/resource_bundle_auralinux.cc",
+ ]
+ }
+
+ if (use_aura && is_win) {
+ sources -= [
+ "dragdrop/drag_utils_aura.cc",
+ ]
+ }
+
+ if (is_linux) {
+ configs += [
+ "//build/config/linux:fontconfig",
+ "//build/config/linux:glib",
+ ]
+ }
+
+ if ((is_linux && !is_chromeos) || is_chromeos) {
+ if (!toolkit_views && !use_aura) {
+ sources -= [
+ "dragdrop/drag_utils.cc",
+ "dragdrop/drag_utils.h",
+ ]
+ }
+ }
+
+ if (use_pango) {
+ configs += [
+ "//build/config/linux:pangocairo",
+ ]
+ }
+
+ if (is_chromeos || (use_aura && is_linux && !use_x11)) {
+ sources += [
+ "dragdrop/os_exchange_data_provider_aura.cc",
+ "dragdrop/os_exchange_data_provider_aura.h",
+ ]
+ }
+
+ libs = []
+ if (is_win) {
+ deps += [
+ "//third_party/wtl",
+ ]
+ cflags = [
+ "/wd4267", # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int.
+ "/wd4324", # Structure was padded due to __declspec(align()), which is
+ # uninteresting.
+ ]
+ ldflags = [
+ "/DELAYLOAD:d2d1.dll",
+ "/DELAYLOAD:d3d10_1.dll",
+ "/DELAYLOAD:dwmapi.dll",
+ ]
+ libs += [
+ "d2d1.lib",
+ "d3d10_1.lib",
+ "dwmapi.lib",
+ "imm32.lib",
+ "d2d1.lib",
+ "dwmapi.lib",
+ "oleacc.lib",
+ ]
+ } else {
+ if (!use_aura) {
+ sources -= [
+ "view_prop.cc",
+ "view_prop.h",
+ ]
+ }
+ }
+
+ if (is_mac) {
+ deps += [
+ #TODO(tfarina): port this third_party component to GN.
+ #"//third_party/mozilla",
+ ]
+
+ sources -= [
+ "dragdrop/drag_utils.cc",
+ "dragdrop/drag_utils.h",
+ ]
+
+ libs += [
+ "Accelerate.framework",
+ "AudioUnit.framework",
+ "CoreView.framework",
+ ]
+ }
+
+ if (use_x11) {
+ #'all_dependent_settings': {
+ #'ldflags': [
+ #'-L<(PRODUCT_DIR)',
+ #],
+ #},
+ configs += [
+ "//build/config/linux:x11"
+ ]
+ }
+
+ if (use_aura) {
+ if (use_x11) {
+ sources += [
+ "cursor/cursor_loader_x11.cc",
+ "cursor/cursor_loader_x11.h",
+ "cursor/cursor_x11.cc",
+ ]
+ if (!is_chromeos) {
+ # These Aura X11 files aren't used on ChromeOS.
+ sources += [
+ "dragdrop/os_exchange_data_provider_aurax11.cc",
+ "dragdrop/os_exchange_data_provider_aurax11.h",
+ ]
+ }
+ }
+ }
+
+ if (!toolkit_views) {
+ sources -= [
+ "dragdrop/drag_drop_types.h",
+ "dragdrop/drop_target_event.cc",
+ "dragdrop/drop_target_event.h",
+ "dragdrop/os_exchange_data.cc",
+ "dragdrop/os_exchange_data.h",
+ "nine_image_painter_factory.cc",
+ "nine_image_painter_factory.h",
+ ]
+ }
+
+ if (is_android) {
+ sources -= [
+ "default_theme_provider.cc",
+ "dragdrop/drag_utils.cc",
+ "dragdrop/drag_utils.h",
+ "l10n/l10n_font_util.cc",
+ "models/button_menu_item_model.cc",
+ "models/dialog_model.cc",
+ "theme_provider.cc",
+ "touch/touch_editing_controller.cc",
+ "ui_base_types.cc",
+ ]
+
+ deps += [
+ ":ui_base_jni_headers",
+ ]
+
+ libs += [
+ "jnigraphics",
+ ]
+ }
+
+ if (is_android && is_android_webview_build) {
+ deps += [
+ #TODO(GYP): port this component to GN.
+ #"//ui/android:ui_java",
+ ]
+ }
+
+ if (is_android && !use_aura) {
+ sources -= [
+ "cursor/cursor_android.cc",
+ ]
+ }
+
+ # Aura clipboard.
+ if (use_aura) {
+ if (use_x11) {
+ sources += [ "clipboard/clipboard_aurax11.cc" ]
+ } else if (!is_win) {
+ # This file is used for all non-X11, non-Windows aura Builds.
+ sources += [ "clipboard/clipboard_aura.cc" ]
+ }
+ }
+
+ if (is_android || is_ios) {
+ sources -= [
+ "device_form_factor_desktop.cc",
+ ]
+ }
+}
+
+source_set("ui_base_test_support") {
+ sources = [
+ "test/ui_controls.h",
+ "test/ui_controls_aura.cc",
+ "test/ui_controls_internal_win.cc",
+ "test/ui_controls_internal_win.h",
+ "test/ui_controls_mac.mm",
+ "test/ui_controls_win.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//testing/gtest",
+ "//ui/events:events_base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ if (!is_ios) {
+ sources += [
+ "ime/dummy_input_method.cc",
+ "ime/dummy_input_method.h",
+ "ime/dummy_text_input_client.cc",
+ "ime/dummy_text_input_client.h",
+ ]
+ }
+}
+
+if (is_android) {
+ generate_jni("ui_base_jni_headers") {
+ sources = [
+ "../android/java/src/org/chromium/ui/base/Clipboard.java",
+ "../android/java/src/org/chromium/ui/base/DeviceFormFactor.java",
+ "../android/java/src/org/chromium/ui/base/LocalizationUtils.java",
+ "../android/java/src/org/chromium/ui/base/SelectFileDialog.java",
+ "../android/java/src/org/chromium/ui/base/TouchDevice.java",
+ "../android/java/src/org/chromium/ui/base/ViewAndroid.java",
+ "../android/java/src/org/chromium/ui/base/WindowAndroid.java",
+ ]
+ jni_package = "base"
+ }
+}
diff --git a/chromium/ui/base/DEPS b/chromium/ui/base/DEPS
index 99ec1517405..dd9bbe8d08d 100644
--- a/chromium/ui/base/DEPS
+++ b/chromium/ui/base/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+cc",
"+grit/app_locale_settings.h",
"+grit/ui_resources.h",
"+grit/ui_strings.h",
diff --git a/chromium/ui/base/accelerators/accelerator.cc b/chromium/ui/base/accelerators/accelerator.cc
index 4439af51dbe..3ed80fa1e07 100644
--- a/chromium/ui/base/accelerators/accelerator.cc
+++ b/chromium/ui/base/accelerators/accelerator.cc
@@ -6,8 +6,6 @@
#if defined(OS_WIN)
#include <windows.h>
-#elif defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
#endif
#include "base/i18n/rtl.h"
@@ -26,19 +24,22 @@ namespace ui {
Accelerator::Accelerator()
: key_code_(ui::VKEY_UNKNOWN),
type_(ui::ET_KEY_PRESSED),
- modifiers_(0) {
+ modifiers_(0),
+ is_repeat_(false) {
}
Accelerator::Accelerator(KeyboardCode keycode, int modifiers)
: key_code_(keycode),
type_(ui::ET_KEY_PRESSED),
- modifiers_(modifiers) {
+ modifiers_(modifiers),
+ is_repeat_(false) {
}
Accelerator::Accelerator(const Accelerator& accelerator) {
key_code_ = accelerator.key_code_;
type_ = accelerator.type_;
modifiers_ = accelerator.modifiers_;
+ is_repeat_ = accelerator.is_repeat_;
if (accelerator.platform_accelerator_.get())
platform_accelerator_ = accelerator.platform_accelerator_->CreateCopy();
}
@@ -51,6 +52,7 @@ Accelerator& Accelerator::operator=(const Accelerator& accelerator) {
key_code_ = accelerator.key_code_;
type_ = accelerator.type_;
modifiers_ = accelerator.modifiers_;
+ is_repeat_ = accelerator.is_repeat_;
if (accelerator.platform_accelerator_.get())
platform_accelerator_ = accelerator.platform_accelerator_->CreateCopy();
else
@@ -68,14 +70,15 @@ bool Accelerator::operator <(const Accelerator& rhs) const {
}
bool Accelerator::operator ==(const Accelerator& rhs) const {
- if (platform_accelerator_.get() != rhs.platform_accelerator_.get() &&
- ((!platform_accelerator_.get() || !rhs.platform_accelerator_.get()) ||
- !platform_accelerator_->Equals(*rhs.platform_accelerator_))) {
- return false;
- }
+ if ((key_code_ == rhs.key_code_) && (type_ == rhs.type_) &&
+ (modifiers_ == rhs.modifiers_))
+ return true;
+
+ bool platform_equal =
+ platform_accelerator_.get() && rhs.platform_accelerator_.get() &&
+ platform_accelerator_.get() == rhs.platform_accelerator_.get();
- return (key_code_ == rhs.key_code_) && (type_ == rhs.type_) &&
- (modifiers_ == rhs.modifiers_);
+ return platform_equal;
}
bool Accelerator::operator !=(const Accelerator& rhs) const {
@@ -98,6 +101,10 @@ bool Accelerator::IsCmdDown() const {
return (modifiers_ & EF_COMMAND_DOWN) != 0;
}
+bool Accelerator::IsRepeat() const {
+ return is_repeat_;
+}
+
base::string16 Accelerator::GetShortcutText() const {
int string_id = 0;
switch (key_code_) {
@@ -191,23 +198,6 @@ base::string16 Accelerator::GetShortcutText() const {
if (c != 0)
shortcut +=
static_cast<base::string16::value_type>(base::ToUpperASCII(c));
-#elif defined(TOOLKIT_GTK)
- const gchar* name = NULL;
- switch (key_code_) {
- case ui::VKEY_OEM_2:
- name = static_cast<const gchar*>("/");
- break;
- default:
- name = gdk_keyval_name(gdk_keyval_to_lower(key_code_));
- break;
- }
- if (name) {
- if (name[0] != 0 && name[1] == 0)
- shortcut +=
- static_cast<base::string16::value_type>(g_ascii_toupper(name[0]));
- else
- shortcut += UTF8ToUTF16(name);
- }
#endif
} else {
shortcut = l10n_util::GetStringUTF16(string_id);
@@ -262,7 +252,7 @@ base::string16 Accelerator::GetShortcutText() const {
if (adjust_shortcut_for_rtl) {
int key_length = static_cast<int>(shortcut_rtl.length());
DCHECK_GT(key_length, 0);
- shortcut_rtl.append(ASCIIToUTF16("+"));
+ 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);
diff --git a/chromium/ui/base/accelerators/accelerator.h b/chromium/ui/base/accelerators/accelerator.h
index 020c7bea40c..430a209f41c 100644
--- a/chromium/ui/base/accelerators/accelerator.h
+++ b/chromium/ui/base/accelerators/accelerator.h
@@ -14,7 +14,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "ui/base/accelerators/platform_accelerator.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -24,7 +24,7 @@ class PlatformAccelerator;
// This is a cross-platform class for accelerator keys used in menus.
// |platform_accelerator| should be used to store platform specific data.
-class UI_EXPORT Accelerator {
+class UI_BASE_EXPORT Accelerator {
public:
Accelerator();
Accelerator(ui::KeyboardCode keycode, int modifiers);
@@ -54,6 +54,7 @@ class UI_EXPORT Accelerator {
bool IsCtrlDown() const;
bool IsAltDown() const;
bool IsCmdDown() const;
+ bool IsRepeat() const;
// Returns a string with the localized shortcut if any.
base::string16 GetShortcutText() const;
@@ -67,6 +68,7 @@ class UI_EXPORT Accelerator {
return platform_accelerator_.get();
}
+ void set_is_repeat(bool is_repeat) { is_repeat_ = is_repeat; }
protected:
// The keycode (VK_...).
@@ -78,13 +80,16 @@ class UI_EXPORT Accelerator {
// The state of the Shift/Ctrl/Alt keys.
int modifiers_;
+ // True if the accelerator is created for an auto repeated key event.
+ bool is_repeat_;
+
// Stores platform specific data. May be NULL.
scoped_ptr<PlatformAccelerator> platform_accelerator_;
};
// An interface that classes that want to register for keyboard accelerators
// should implement.
-class UI_EXPORT AcceleratorTarget {
+class UI_BASE_EXPORT AcceleratorTarget {
public:
// Should return true if the accelerator was processed.
virtual bool AcceleratorPressed(const Accelerator& accelerator) = 0;
diff --git a/chromium/ui/base/accelerators/accelerator_manager.h b/chromium/ui/base/accelerators/accelerator_manager.h
index 818dc3ea05a..0e33ad659aa 100644
--- a/chromium/ui/base/accelerators/accelerator_manager.h
+++ b/chromium/ui/base/accelerators/accelerator_manager.h
@@ -11,13 +11,13 @@
#include "base/basictypes.h"
#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/events/event_constants.h"
namespace ui {
// The AcceleratorManger is used to handle keyboard accelerators.
-class UI_EXPORT AcceleratorManager {
+class UI_BASE_EXPORT AcceleratorManager {
public:
enum HandlerPriority {
kNormalPriority,
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
index 6cc9b5f17c6..bd8d3cf14aa 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
@@ -7,22 +7,24 @@
#include <string>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Change windows accelerator style to GTK style. (GTK uses _ for
// accelerators. Windows uses & with && as an escape for &.)
-UI_EXPORT std::string ConvertAcceleratorsFromWindowsStyle(
+UI_BASE_EXPORT std::string ConvertAcceleratorsFromWindowsStyle(
const std::string& label);
// Removes the "&" accelerators from a Windows label.
-UI_EXPORT std::string RemoveWindowsStyleAccelerators(const std::string& label);
+UI_BASE_EXPORT std::string RemoveWindowsStyleAccelerators(
+ const std::string& label);
// Escapes "&" characters by doubling them so that later calling
// ConvertAcceleratorsFromWindowsStyle() will return the original string (except
// with "_" characters doubled, to escape them for GTK).
-UI_EXPORT std::string EscapeWindowsStyleAccelerators(const std::string& label);
+UI_BASE_EXPORT std::string EscapeWindowsStyleAccelerators(
+ const std::string& label);
} // namespace ui
diff --git a/chromium/ui/base/accelerators/platform_accelerator.h b/chromium/ui/base/accelerators/platform_accelerator.h
index 1b46003ea91..cca8021f2e1 100644
--- a/chromium/ui/base/accelerators/platform_accelerator.h
+++ b/chromium/ui/base/accelerators/platform_accelerator.h
@@ -6,12 +6,12 @@
#define UI_BASE_ACCELERATORS_PLATFORM_ACCELERATOR_H_
#include "base/memory/scoped_ptr.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Abstract base class for platform specific accelerator keys.
-class UI_EXPORT PlatformAccelerator {
+class UI_BASE_EXPORT PlatformAccelerator {
public:
virtual ~PlatformAccelerator() {}
diff --git a/chromium/ui/base/accelerators/platform_accelerator_cocoa.h b/chromium/ui/base/accelerators/platform_accelerator_cocoa.h
index 30941c77bb2..3f72cacd84a 100644
--- a/chromium/ui/base/accelerators/platform_accelerator_cocoa.h
+++ b/chromium/ui/base/accelerators/platform_accelerator_cocoa.h
@@ -13,7 +13,7 @@
namespace ui {
// This is a Mac specific class for specifing accelerator keys.
-class UI_EXPORT PlatformAcceleratorCocoa : public PlatformAccelerator {
+class UI_BASE_EXPORT PlatformAcceleratorCocoa : public PlatformAccelerator {
public:
PlatformAcceleratorCocoa();
PlatformAcceleratorCocoa(NSString* key_code, NSUInteger modifier_mask);
@@ -23,7 +23,10 @@ class UI_EXPORT PlatformAcceleratorCocoa : public PlatformAccelerator {
virtual scoped_ptr<PlatformAccelerator> CreateCopy() const OVERRIDE;
virtual bool Equals(const PlatformAccelerator& rhs) const OVERRIDE;
+ // The keyEquivalent of the NSMenuItem associated with the accelerator.
NSString* characters() const { return characters_.get(); }
+ // The keyEquivalentModifierMask of the NSMenuItem associated with the
+ // accelerator.
NSUInteger modifier_mask() const { return modifier_mask_; }
private:
diff --git a/chromium/ui/base/accelerators/platform_accelerator_gtk.cc b/chromium/ui/base/accelerators/platform_accelerator_gtk.cc
deleted file mode 100644
index 5662452a530..00000000000
--- a/chromium/ui/base/accelerators/platform_accelerator_gtk.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/accelerators/platform_accelerator_gtk.h"
-
-#include "ui/events/keycodes/keyboard_code_conversion_gtk.h"
-
-namespace ui {
-
-namespace {
-
-int GdkModifierToEventFlag(GdkModifierType gdk_modifier) {
- int event_flags = 0;
- if (gdk_modifier & GDK_SHIFT_MASK)
- event_flags |= EF_SHIFT_DOWN;
- if (gdk_modifier & GDK_CONTROL_MASK)
- event_flags |= EF_CONTROL_DOWN;
- if (gdk_modifier & GDK_MOD1_MASK)
- event_flags |= EF_ALT_DOWN;
- return event_flags;
-}
-
-GdkModifierType EventFlagToGdkModifier(int event_flag) {
- int modifier = 0;
- if (event_flag & EF_SHIFT_DOWN)
- modifier |= GDK_SHIFT_MASK;
- if (event_flag & EF_CONTROL_DOWN)
- modifier |= GDK_CONTROL_MASK;
- if (event_flag & EF_ALT_DOWN)
- modifier |= GDK_MOD1_MASK;
- return static_cast<GdkModifierType>(modifier);
-}
-
-} // namespace
-
-PlatformAcceleratorGtk::PlatformAcceleratorGtk()
- : gdk_key_code_(0),
- gdk_modifier_(static_cast<GdkModifierType>(0)) {
-}
-
-PlatformAcceleratorGtk::PlatformAcceleratorGtk(guint gdk_key_code,
- GdkModifierType gdk_modifier)
- : gdk_key_code_(gdk_key_code),
- gdk_modifier_(gdk_modifier) {
-}
-
-PlatformAcceleratorGtk::~PlatformAcceleratorGtk() {
-}
-
-scoped_ptr<PlatformAccelerator> PlatformAcceleratorGtk::CreateCopy() const {
- scoped_ptr<PlatformAcceleratorGtk> copy(new PlatformAcceleratorGtk);
- copy->gdk_key_code_ = gdk_key_code_;
- copy->gdk_modifier_ = gdk_modifier_;
- return scoped_ptr<PlatformAccelerator>(copy.release());
-}
-
-bool PlatformAcceleratorGtk::Equals(const PlatformAccelerator& rhs) const {
- const PlatformAcceleratorGtk& rhs_gtk =
- static_cast<const PlatformAcceleratorGtk&>(rhs);
- return gdk_key_code_ == rhs_gtk.gdk_key_code_ &&
- gdk_modifier_ == rhs_gtk.gdk_modifier_;
-}
-
-Accelerator AcceleratorForGdkKeyCodeAndModifier(guint gdk_key_code,
- GdkModifierType gdk_modifier) {
- ui::Accelerator accelerator(ui::WindowsKeyCodeForGdkKeyCode(gdk_key_code),
- ui::GdkModifierToEventFlag(gdk_modifier));
- scoped_ptr<PlatformAccelerator> platform_accelerator(
- new PlatformAcceleratorGtk(gdk_key_code, gdk_modifier));
- accelerator.set_platform_accelerator(platform_accelerator.Pass());
- return accelerator;
-}
-
-guint GetGdkKeyCodeForAccelerator(const Accelerator& accelerator) {
- if (accelerator.platform_accelerator()) {
- return static_cast<const PlatformAcceleratorGtk*>(
- accelerator.platform_accelerator())->gdk_key_code();
- }
- // The second parameter is false because accelerator keys are expressed in
- // terms of the non-shift-modified key.
- return GdkKeyCodeForWindowsKeyCode(accelerator.key_code(), false);
-}
-
-GdkModifierType GetGdkModifierForAccelerator(const Accelerator& accelerator) {
- if (accelerator.platform_accelerator()) {
- return static_cast<const PlatformAcceleratorGtk*>(
- accelerator.platform_accelerator())->gdk_modifier();
- }
- return EventFlagToGdkModifier(accelerator.modifiers());
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/accelerators/platform_accelerator_gtk.h b/chromium/ui/base/accelerators/platform_accelerator_gtk.h
deleted file mode 100644
index 87900ddf858..00000000000
--- a/chromium/ui/base/accelerators/platform_accelerator_gtk.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_ACCELERATORS_PLATFORM_ACCELERATOR_GTK_H_
-#define UI_BASE_ACCELERATORS_PLATFORM_ACCELERATOR_GTK_H_
-
-#include <gdk/gdk.h>
-
-#include "base/compiler_specific.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/platform_accelerator.h"
-
-namespace ui {
-
-class Accelerator;
-
-// This is a GTK specific class for specifing accelerator keys.
-class UI_EXPORT PlatformAcceleratorGtk : public PlatformAccelerator {
- public:
- PlatformAcceleratorGtk();
- PlatformAcceleratorGtk(guint gdk_key_code, GdkModifierType gdk_modifier);
- virtual ~PlatformAcceleratorGtk();
-
- // PlatformAccelerator:
- virtual scoped_ptr<PlatformAccelerator> CreateCopy() const OVERRIDE;
- virtual bool Equals(const PlatformAccelerator& rhs) const OVERRIDE;
-
- guint gdk_key_code() const { return gdk_key_code_; }
- GdkModifierType gdk_modifier() const { return gdk_modifier_; }
-
- private:
- guint gdk_key_code_;
- GdkModifierType gdk_modifier_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformAcceleratorGtk);
-};
-
-UI_EXPORT Accelerator AcceleratorForGdkKeyCodeAndModifier(
- guint gdk_key_code,
- GdkModifierType gdk_modifier);
-UI_EXPORT guint GetGdkKeyCodeForAccelerator(const Accelerator& accelerator);
-UI_EXPORT GdkModifierType GetGdkModifierForAccelerator(
- const Accelerator& accelerator);
-
-} // namespace ui
-
-#endif // UI_BASE_ACCELERATORS_PLATFORM_ACCELERATOR_GTK_H_
diff --git a/chromium/ui/base/accessibility/OWNERS b/chromium/ui/base/accessibility/OWNERS
deleted file mode 100644
index c32e0598455..00000000000
--- a/chromium/ui/base/accessibility/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-dmazzoni@chromium.org
diff --git a/chromium/ui/base/accessibility/accessibility_types.h b/chromium/ui/base/accessibility/accessibility_types.h
deleted file mode 100644
index 91e497412be..00000000000
--- a/chromium/ui/base/accessibility/accessibility_types.h
+++ /dev/null
@@ -1,110 +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_ACCESSIBILITY_ACCESSIBILITY_TYPES_H_
-#define UI_BASE_ACCESSIBILITY_ACCESSIBILITY_TYPES_H_
-
-#include "base/basictypes.h"
-
-namespace ui {
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// AccessibilityTypes
-//
-// Provides enumerations used to preserve platform-independence in
-// accessibility functions.
-//
-////////////////////////////////////////////////////////////////////////////////
-class AccessibilityTypes {
- public:
-
- // This defines states of the supported accessibility roles in our
- // Views (e.g. used in View::GetAccessibleState). Any interface using states
- // must provide a conversion to its own states (see e.g.
- // NativeViewAccessibilityWin::get_accState).
- typedef uint32 State;
- enum StateFlag {
- STATE_CHECKED = 1 << 0,
- STATE_COLLAPSED = 1 << 1,
- STATE_DEFAULT = 1 << 2,
- STATE_EDITABLE = 1 << 3,
- STATE_EXPANDED = 1 << 4,
- STATE_FOCUSED = 1 << 5,
- STATE_HASPOPUP = 1 << 6,
- STATE_HOTTRACKED = 1 << 7,
- STATE_INVISIBLE = 1 << 8,
- STATE_LINKED = 1 << 9,
- STATE_OFFSCREEN = 1 << 10,
- STATE_PRESSED = 1 << 11,
- STATE_PROTECTED = 1 << 12,
- STATE_READONLY = 1 << 13,
- STATE_SELECTED = 1 << 14,
- STATE_UNAVAILABLE = 1 << 15
- };
-
- // This defines an enumeration of the supported accessibility roles in our
- // Views (e.g. used in View::GetAccessibleRole). Any interface using roles
- // must provide a conversion to its own roles (see e.g.
- // NativeViewAccessibilityWin::get_accRole).
- enum Role {
- ROLE_ALERT,
- ROLE_APPLICATION,
- ROLE_BUTTONDROPDOWN,
- ROLE_BUTTONMENU,
- ROLE_CHECKBUTTON,
- ROLE_CLIENT,
- ROLE_COMBOBOX,
- ROLE_DIALOG,
- ROLE_GRAPHIC,
- ROLE_GROUPING,
- ROLE_LINK,
- ROLE_LOCATION_BAR,
- ROLE_MENUBAR,
- ROLE_MENUITEM,
- ROLE_MENUPOPUP,
- ROLE_OUTLINE,
- ROLE_OUTLINEITEM,
- ROLE_PAGETAB,
- ROLE_PAGETABLIST,
- ROLE_PANE,
- ROLE_PROGRESSBAR,
- ROLE_PUSHBUTTON,
- ROLE_RADIOBUTTON,
- ROLE_SCROLLBAR,
- ROLE_SEPARATOR,
- ROLE_SLIDER,
- ROLE_STATICTEXT,
- ROLE_TEXT,
- ROLE_TITLEBAR,
- ROLE_TOOLBAR,
- ROLE_WINDOW
- };
-
- // This defines an enumeration of the supported accessibility events in our
- // Views (e.g. used in View::NotifyAccessibilityEvent). Any interface using
- // events must provide a conversion to its own events (see e.g.
- // ViewAccessibility::MSAAEvent).
- enum Event {
- EVENT_ALERT,
- EVENT_FOCUS,
- EVENT_MENUSTART,
- EVENT_MENUEND,
- EVENT_MENUPOPUPSTART,
- EVENT_MENUPOPUPEND,
- EVENT_NAME_CHANGED,
- EVENT_TEXT_CHANGED,
- EVENT_SELECTION_CHANGED,
- EVENT_VALUE_CHANGED
- };
-
- private:
- // Do not instantiate this class.
- AccessibilityTypes() {}
- ~AccessibilityTypes() {}
-};
-
-} // namespace ui
-
-#endif // UI_BASE_ACCESSIBILITY_ACCESSIBILITY_TYPES_H_
diff --git a/chromium/ui/base/accessibility/accessible_text_utils.cc b/chromium/ui/base/accessibility/accessible_text_utils.cc
deleted file mode 100644
index a878b23d476..00000000000
--- a/chromium/ui/base/accessibility/accessible_text_utils.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/accessibility/accessible_text_utils.h"
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-
-namespace ui {
-
-size_t FindAccessibleTextBoundary(const base::string16& text,
- const std::vector<int>& line_breaks,
- TextBoundaryType boundary,
- size_t start_offset,
- TextBoundaryDirection direction) {
- size_t text_size = text.size();
- DCHECK(start_offset <= text_size);
-
- if (boundary == CHAR_BOUNDARY) {
- if (direction == FORWARDS_DIRECTION && start_offset < text_size)
- return start_offset + 1;
- else
- return start_offset;
- } else if (boundary == LINE_BOUNDARY) {
- if (direction == FORWARDS_DIRECTION) {
- for (size_t j = 0; j < line_breaks.size(); ++j) {
- size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0;
- if (line_break > start_offset)
- return line_break;
- }
- return text_size;
- } else {
- // Note: j is unsigned, so for loop continues until j wraps around
- // and becomes greater than the starting value.
- for (size_t j = line_breaks.size() - 1;
- j < line_breaks.size();
- --j) {
- size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0;
- if (line_break <= start_offset)
- return line_break;
- }
- return 0;
- }
- }
-
- size_t result = start_offset;
- for (;;) {
- size_t pos;
- if (direction == FORWARDS_DIRECTION) {
- if (result >= text_size)
- return text_size;
- pos = result;
- } else {
- if (result == 0)
- return 0;
- pos = result - 1;
- }
-
- switch (boundary) {
- case CHAR_BOUNDARY:
- case LINE_BOUNDARY:
- NOTREACHED(); // These are handled above.
- break;
- case WORD_BOUNDARY:
- if (IsWhitespace(text[pos]))
- return result;
- break;
- case PARAGRAPH_BOUNDARY:
- if (text[pos] == '\n')
- return result;
- break;
- case SENTENCE_BOUNDARY:
- if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') &&
- (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) {
- return result;
- }
- break;
- case ALL_BOUNDARY:
- default:
- break;
- }
-
- if (direction == FORWARDS_DIRECTION) {
- result++;
- } else {
- result--;
- }
- }
-}
-
-} // Namespace ui
diff --git a/chromium/ui/base/accessibility/accessible_text_utils.h b/chromium/ui/base/accessibility/accessible_text_utils.h
deleted file mode 100644
index a64088c7f94..00000000000
--- a/chromium/ui/base/accessibility/accessible_text_utils.h
+++ /dev/null
@@ -1,53 +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_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_
-#define UI_BASE_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-// Boundaries that can be passed to FindAccessibleTextBoundary,
-// representing various visual boundaries in (potentially multi-line)
-// text. This is used by assistive technology in order to, for example,
-// retrieve the nearest word to the cursor, or retrieve all of the
-// text from the current cursor position to the end of the line.
-// These should be self-explanatory; "line" here refers to the visual
-// line as currently displayed (possibly affected by wrapping).
-enum TextBoundaryType {
- CHAR_BOUNDARY,
- WORD_BOUNDARY,
- LINE_BOUNDARY,
- SENTENCE_BOUNDARY,
- PARAGRAPH_BOUNDARY,
- ALL_BOUNDARY
-};
-
-// A direction when searching for the next boundary.
-enum TextBoundaryDirection {
- // Search forwards for the next boundary past the starting position.
- FORWARDS_DIRECTION,
- // Search backwards for the previous boundary before the starting position.
- BACKWARDS_DIRECTION
-};
-
-// Convenience method needed to implement platform-specific text
-// accessibility APIs like IAccessible2. Search forwards or backwards
-// (depending on |direction|) from the given |start_offset| until the
-// given boundary is found, and return the offset of that boundary,
-// using the vector of line break character offsets in |line_breaks|.
-size_t UI_EXPORT FindAccessibleTextBoundary(const base::string16& text,
- const std::vector<int>& line_breaks,
- TextBoundaryType boundary,
- size_t start_offset,
- TextBoundaryDirection direction);
-
-} // namespace ui
-
-#endif // UI_BASE_ACCESSIBILITY_ACCESSIBLE_TEXT_UTILS_H_
diff --git a/chromium/ui/base/accessibility/accessible_view_state.cc b/chromium/ui/base/accessibility/accessible_view_state.cc
deleted file mode 100644
index ff1d3e69259..00000000000
--- a/chromium/ui/base/accessibility/accessible_view_state.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/accessibility/accessible_view_state.h"
-
-namespace ui {
-
-AccessibleViewState::AccessibleViewState()
- : role(AccessibilityTypes::ROLE_CLIENT),
- state(0),
- selection_start(-1),
- selection_end(-1),
- index(-1),
- count(-1) { }
-
-AccessibleViewState::~AccessibleViewState() { }
-
-} // namespace ui
diff --git a/chromium/ui/base/accessibility/accessible_view_state.h b/chromium/ui/base/accessibility/accessible_view_state.h
deleted file mode 100644
index 2f4b4bffaac..00000000000
--- a/chromium/ui/base/accessibility/accessible_view_state.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_ACCESSIBILITY_ACCESSIBLE_VIEW_STATE_H_
-#define UI_BASE_ACCESSIBILITY_ACCESSIBLE_VIEW_STATE_H_
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/strings/string16.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// AccessibleViewState
-//
-// A cross-platform struct for storing the core accessibility information
-// that should be provided about any UI view to assistive technology (AT).
-//
-////////////////////////////////////////////////////////////////////////////////
-struct UI_EXPORT AccessibleViewState {
- public:
- AccessibleViewState();
- ~AccessibleViewState();
-
- // The view's role, like button or list box.
- AccessibilityTypes::Role role;
-
- // The view's state, a bitmask containing fields such as checked
- // (for a checkbox) and protected (for a password text box).
- AccessibilityTypes::State state;
-
- // The view's name / label.
- base::string16 name;
-
- // The view's value, for example the text content.
- base::string16 value;
-
- // The name of the default action if the user clicks on this view.
- base::string16 default_action;
-
- // The keyboard shortcut to activate this view, if any.
- base::string16 keyboard_shortcut;
-
- // The selection start and end. Only applies to views with text content,
- // such as a text box or combo box; start and end should be -1 otherwise.
- int selection_start;
- int selection_end;
-
- // The selected item's index and the count of the number of items.
- // Only applies to views with multiple choices like a listbox; both
- // index and count should be -1 otherwise.
- int index;
- int count;
-
- // An optional callback that can be used by accessibility clients to
- // set the string value of this view. This only applies to roles where
- // setting the value makes sense, like a text box. Not often used by
- // screen readers, but often used by automation software to script
- // things like logging into portals or filling forms.
- //
- // This callback is only valid for the lifetime of the view, and should
- // be a safe no-op if the view is deleted. Typically, accessible views
- // should use a WeakPtr when binding the callback.
- base::Callback<void(const base::string16&)> set_value_callback;
-};
-
-} // namespace ui
-
-#endif // UI_BASE_ACCESSIBILITY_ACCESSIBLE_VIEW_STATE_H_
diff --git a/chromium/ui/base/android/view_android.cc b/chromium/ui/base/android/view_android.cc
index ffb510f672d..30e43164409 100644
--- a/chromium/ui/base/android/view_android.cc
+++ b/chromium/ui/base/android/view_android.cc
@@ -5,7 +5,7 @@
#include "ui/base/android/view_android.h"
#include "base/android/jni_android.h"
-#include "base/android/jni_helper.h"
+#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "jni/ViewAndroid_jni.h"
#include "ui/base/android/window_android.h"
diff --git a/chromium/ui/base/android/view_android.h b/chromium/ui/base/android/view_android.h
index 7bd334d29aa..0205fdf1414 100644
--- a/chromium/ui/base/android/view_android.h
+++ b/chromium/ui/base/android/view_android.h
@@ -6,9 +6,9 @@
#define UI_BASE_ANDROID_VIEW_ANDROID_H_
#include <jni.h>
-#include "base/android/jni_helper.h"
+#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -16,7 +16,7 @@ class WindowAndroid;
// This class is the native counterpart for ViewAndroid. It is owned by the
// Java ViewAndroid object.
-class UI_EXPORT ViewAndroid {
+class UI_BASE_EXPORT ViewAndroid {
public:
ViewAndroid(JNIEnv* env, jobject obj, WindowAndroid* window);
diff --git a/chromium/ui/base/android/window_android.cc b/chromium/ui/base/android/window_android.cc
index bacf023dbfb..490c6f3b545 100644
--- a/chromium/ui/base/android/window_android.cc
+++ b/chromium/ui/base/android/window_android.cc
@@ -6,9 +6,10 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
-#include "base/android/jni_helper.h"
+#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "jni/WindowAndroid_jni.h"
+#include "ui/base/android/window_android_compositor.h"
#include "ui/base/android/window_android_observer.h"
namespace ui {
@@ -16,8 +17,10 @@ namespace ui {
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
-WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj)
- : weak_java_window_(env, obj) {
+WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period)
+ : weak_java_window_(env, obj),
+ compositor_(NULL),
+ vsync_period_(base::TimeDelta::FromInternalValue(vsync_period)) {
}
void WindowAndroid::Destroy(JNIEnv* env, jobject obj) {
@@ -33,22 +36,7 @@ bool WindowAndroid::RegisterWindowAndroid(JNIEnv* env) {
}
WindowAndroid::~WindowAndroid() {
-}
-
-bool WindowAndroid::GrabSnapshot(
- int content_x, int content_y, int width, int height,
- std::vector<unsigned char>* png_representation) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jbyteArray> result =
- Java_WindowAndroid_grabSnapshot(env, GetJavaObject().obj(),
- content_x + content_offset_.x(),
- content_y + content_offset_.y(),
- width, height);
- if (result.is_null())
- return false;
- base::android::JavaByteArrayToByteVector(
- env, result.obj(), png_representation);
- return true;
+ DCHECK(!compositor_);
}
void WindowAndroid::OnCompositingDidCommit() {
@@ -66,25 +54,55 @@ void WindowAndroid::RemoveObserver(WindowAndroidObserver* observer) {
observer_list_.RemoveObserver(observer);
}
-void WindowAndroid::AttachCompositor() {
+void WindowAndroid::AttachCompositor(WindowAndroidCompositor* compositor) {
+ if (compositor_ && compositor != compositor_)
+ DetachCompositor();
+
+ compositor_ = compositor;
FOR_EACH_OBSERVER(WindowAndroidObserver,
observer_list_,
OnAttachCompositor());
}
void WindowAndroid::DetachCompositor() {
+ compositor_ = NULL;
FOR_EACH_OBSERVER(WindowAndroidObserver,
observer_list_,
OnDetachCompositor());
observer_list_.Clear();
}
+void WindowAndroid::RequestVSyncUpdate() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_WindowAndroid_requestVSyncUpdate(env, GetJavaObject().obj());
+}
+
+void WindowAndroid::SetNeedsAnimate() {
+ if (compositor_)
+ compositor_->SetNeedsAnimate();
+}
+
+void WindowAndroid::Animate(base::TimeTicks begin_frame_time) {
+ FOR_EACH_OBSERVER(
+ WindowAndroidObserver, observer_list_, OnAnimate(begin_frame_time));
+}
+
+void WindowAndroid::OnVSync(JNIEnv* env, jobject obj, jlong time_micros) {
+ base::TimeTicks frame_time(base::TimeTicks::FromInternalValue(time_micros));
+ FOR_EACH_OBSERVER(
+ WindowAndroidObserver,
+ observer_list_,
+ OnVSync(frame_time, vsync_period_));
+ if (compositor_)
+ compositor_->OnVSync(frame_time, vsync_period_);
+}
+
// ----------------------------------------------------------------------------
// Native JNI methods
// ----------------------------------------------------------------------------
-jlong Init(JNIEnv* env, jobject obj) {
- WindowAndroid* window = new WindowAndroid(env, obj);
+jlong Init(JNIEnv* env, jobject obj, jlong vsync_period) {
+ WindowAndroid* window = new WindowAndroid(env, obj, vsync_period);
return reinterpret_cast<intptr_t>(window);
}
diff --git a/chromium/ui/base/android/window_android.h b/chromium/ui/base/android/window_android.h
index 1da70739344..cd8ae3408c8 100644
--- a/chromium/ui/base/android/window_android.h
+++ b/chromium/ui/base/android/window_android.h
@@ -7,20 +7,22 @@
#include <jni.h>
#include <vector>
-#include "base/android/jni_helper.h"
+#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/observer_list.h"
-#include "ui/base/ui_export.h"
+#include "base/time/time.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/vector2d_f.h"
namespace ui {
+class WindowAndroidCompositor;
class WindowAndroidObserver;
// Android implementation of the activity window.
-class UI_EXPORT WindowAndroid {
+class UI_BASE_EXPORT WindowAndroid {
public:
- WindowAndroid(JNIEnv* env, jobject obj);
+ WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period);
void Destroy(JNIEnv* env, jobject obj);
@@ -34,23 +36,33 @@ class UI_EXPORT WindowAndroid {
content_offset_ = content_offset;
}
- bool GrabSnapshot(int content_x, int content_y, int width, int height,
- std::vector<unsigned char>* png_representation);
+ gfx::Vector2dF content_offset() const {
+ return content_offset_;
+ }
// Compositor callback relay.
void OnCompositingDidCommit();
- void AttachCompositor();
+ void AttachCompositor(WindowAndroidCompositor* compositor);
void DetachCompositor();
void AddObserver(WindowAndroidObserver* observer);
void RemoveObserver(WindowAndroidObserver* observer);
+ WindowAndroidCompositor* GetCompositor() { return compositor_; }
+
+ void RequestVSyncUpdate();
+ void SetNeedsAnimate();
+ void OnVSync(JNIEnv* env, jobject obj, jlong time_micros);
+ void Animate(base::TimeTicks begin_frame_time);
+
private:
~WindowAndroid();
JavaObjectWeakGlobalRef weak_java_window_;
gfx::Vector2dF content_offset_;
+ WindowAndroidCompositor* compositor_;
+ base::TimeDelta vsync_period_;
ObserverList<WindowAndroidObserver> observer_list_;
diff --git a/chromium/ui/base/android/window_android_compositor.h b/chromium/ui/base/android/window_android_compositor.h
new file mode 100644
index 00000000000..eb55a7b13e6
--- /dev/null
+++ b/chromium/ui/base/android/window_android_compositor.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_
+#define UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_
+
+#include "cc/output/copy_output_request.h"
+#include "ui/base/ui_base_export.h"
+
+namespace cc {
+class Layer;
+}
+
+namespace ui {
+
+// Android interface for compositor-related tasks.
+class UI_BASE_EXPORT WindowAndroidCompositor {
+ public:
+ virtual ~WindowAndroidCompositor() {}
+
+ virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) = 0;
+ virtual void RequestCopyOfOutputOnRootLayer(
+ scoped_ptr<cc::CopyOutputRequest> request) = 0;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) = 0;
+ virtual void SetNeedsAnimate() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_
diff --git a/chromium/ui/base/android/window_android_observer.h b/chromium/ui/base/android/window_android_observer.h
index 790170ec943..b9f5fbad5cf 100644
--- a/chromium/ui/base/android/window_android_observer.h
+++ b/chromium/ui/base/android/window_android_observer.h
@@ -5,15 +5,18 @@
#ifndef UI_BASE_ANDROID_WINDOW_ANDROID_OBSERVER_H_
#define UI_BASE_ANDROID_WINDOW_ANDROID_OBSERVER_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
-class UI_EXPORT WindowAndroidObserver {
+class UI_BASE_EXPORT WindowAndroidObserver {
public:
virtual void OnCompositingDidCommit() = 0;
virtual void OnAttachCompositor() = 0;
virtual void OnDetachCompositor() = 0;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) = 0;
+ virtual void OnAnimate(base::TimeTicks frame_begin_time) {}
protected:
virtual ~WindowAndroidObserver() {}
diff --git a/chromium/ui/base/base_window.h b/chromium/ui/base/base_window.h
index 73c26890b64..664616994ae 100644
--- a/chromium/ui/base/base_window.h
+++ b/chromium/ui/base/base_window.h
@@ -19,7 +19,7 @@ namespace ui {
// Provides an interface to perform actions on windows, and query window
// state.
-class UI_EXPORT BaseWindow {
+class UI_BASE_EXPORT BaseWindow {
public:
// Returns true if the window is currently the active/focused window.
virtual bool IsActive() const = 0;
diff --git a/chromium/ui/base/clipboard/clipboard.cc b/chromium/ui/base/clipboard/clipboard.cc
index a77efd661e9..c71d5b910f1 100644
--- a/chromium/ui/base/clipboard/clipboard.cc
+++ b/chromium/ui/base/clipboard/clipboard.cc
@@ -163,7 +163,7 @@ void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) {
}
// Make sure the size is representable as a signed 32-bit int, so
// SkBitmap::getSize() won't be truncated.
- if (bitmap.getSize64().is64())
+ if (!sk_64_isS32(bitmap.computeSize64()))
return;
// It's OK to cast away constness here since we map the handle as
diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h
index f818bd6a6df..94748478614 100644
--- a/chromium/ui/base/clipboard/clipboard.h
+++ b/chromium/ui/base/clipboard/clipboard.h
@@ -18,11 +18,7 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_checker.h"
#include "ui/base/clipboard/clipboard_types.h"
-#include "ui/base/ui_export.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#endif
+#include "ui/base/ui_base_export.h"
#if defined(OS_WIN)
#include <objidl.h>
@@ -45,16 +41,17 @@ class MessageWindow;
} // namespace win
} // namespace base
+// TODO(dcheng): Temporary until the IPC layer doesn't use WriteObjects().
+namespace content {
+class ClipboardMessageFilter;
+}
+
namespace gfx {
class Size;
}
class SkBitmap;
-#if defined(TOOLKIT_GTK)
-typedef struct _GtkClipboard GtkClipboard;
-#endif
-
#ifdef __OBJC__
@class NSString;
#else
@@ -63,8 +60,9 @@ class NSString;
namespace ui {
class ClipboardTest;
+class ScopedClipboardWriter;
-class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
+class UI_BASE_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
public:
// MIME type constants.
static const char kMimeTypeText[];
@@ -75,7 +73,7 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
static const char kMimeTypePNG[];
// Platform neutral holder for native data representation of a clipboard type.
- struct UI_EXPORT FormatType {
+ struct UI_BASE_EXPORT FormatType {
FormatType();
~FormatType();
@@ -83,19 +81,19 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
std::string Serialize() const;
static FormatType Deserialize(const std::string& serialization);
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
// FormatType can be used in a set on some platforms.
bool operator<(const FormatType& other) const;
#endif
#if defined(OS_WIN)
const FORMATETC& ToFormatEtc() const { return data_; }
+#elif defined(USE_AURA)
+ const std::string& ToString() const { return data_; }
#elif defined(OS_MACOSX)
// Custom copy and assignment constructor to handle NSString.
FormatType(const FormatType& other);
FormatType& operator=(const FormatType& other);
-#elif defined(USE_AURA)
- const std::string& ToString() const { return data_; }
#endif
bool Equals(const FormatType& other) const;
@@ -116,18 +114,14 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
FormatType(UINT native_format, LONG index);
UINT ToUINT() const { return data_.cfFormat; }
FORMATETC data_;
+#elif defined(USE_AURA)
+ explicit FormatType(const std::string& native_format);
+ const std::string& data() const { return data_; }
+ std::string data_;
#elif defined(OS_MACOSX)
explicit FormatType(NSString* native_format);
NSString* ToNSString() const { return data_; }
NSString* data_;
-#elif defined(USE_AURA)
- explicit FormatType(const std::string& native_format);
- std::string data_;
-#elif defined(TOOLKIT_GTK)
- explicit FormatType(const std::string& native_format);
- explicit FormatType(const GdkAtom& native_format);
- const GdkAtom& ToGdkAtom() const { return data_; }
- GdkAtom data_;
#elif defined(OS_ANDROID)
explicit FormatType(const std::string& native_format);
const std::string& data() const { return data_; }
@@ -139,6 +133,8 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
// Copyable and assignable, since this is essentially an opaque value type.
};
+ // TODO(dcheng): Make this private once the IPC layer no longer needs to
+ // serialize this information.
// ObjectType designates the type of data to be stored in the clipboard. This
// designation is shared across all OSes. The system-specific designation
// is defined by FormatType. A single ObjectType might be represented by
@@ -183,7 +179,7 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
switch (type) {
case CLIPBOARD_TYPE_COPY_PASTE:
return true;
-#if defined(USE_X11) && !defined(OS_CHROMEOS)
+#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
case CLIPBOARD_TYPE_SELECTION:
return true;
#endif
@@ -212,12 +208,6 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
// clipboard, so it shouldn't be a problem.)
static void DestroyClipboardForCurrentThread();
- // Write a bunch of objects to the system clipboard. Copies are made of the
- // contents of |objects|.
- // Note: If you're thinking about calling this, you should probably be using
- // ScopedClipboardWriter instead.
- void WriteObjects(ClipboardType type, const ObjectMap& objects);
-
// Returns a sequence number which uniquely identifies clipboard state.
// This can be used to version the data on the clipboard and determine
// whether it has changed.
@@ -312,10 +302,18 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
FRIEND_TEST_ALL_PREFIXES(ClipboardTest, SharedBitmapTest);
FRIEND_TEST_ALL_PREFIXES(ClipboardTest, EmptyHTMLTest);
friend class ClipboardTest;
+ // For access to WriteObjects().
+ // TODO(dcheng): Remove the temporary exception for content.
+ friend class content::ClipboardMessageFilter;
+ friend class ScopedClipboardWriter;
Clipboard();
~Clipboard();
+ // Write a bunch of objects to the system clipboard. Copies are made of the
+ // contents of |objects|.
+ void WriteObjects(ClipboardType type, const ObjectMap& objects);
+
void DispatchObject(ObjectType type, const ObjectMapParams& params);
void WriteText(const char* text_data, size_t text_len);
@@ -360,30 +358,6 @@ class UI_EXPORT Clipboard : NON_EXPORTED_BASE(public base::ThreadChecker) {
// Mark this as mutable so const methods can still do lazy initialization.
mutable scoped_ptr<base::win::MessageWindow> clipboard_owner_;
-#elif defined(TOOLKIT_GTK)
- // The public API is via WriteObjects() which dispatches to multiple
- // Write*() calls, but on GTK we must write all the clipboard types
- // in a single GTK call. To support this we store the current set
- // of data we intend to put on the clipboard on clipboard_data_ as
- // WriteObjects is running, and then at the end call SetGtkClipboard
- // which replaces whatever is on the system clipboard with the
- // contents of clipboard_data_.
-
- public:
- typedef std::map<std::string, std::pair<char*, size_t> > TargetMap;
-
- private:
- // Write changes to gtk clipboard.
- void SetGtkClipboard(ClipboardType type);
- // Insert a mapping into clipboard_data_.
- void InsertMapping(const char* key, char* data, size_t data_len);
-
- // Find the gtk clipboard for the passed type enum.
- GtkClipboard* LookupBackingClipboard(ClipboardType type) const;
-
- TargetMap* clipboard_data_;
- GtkClipboard* clipboard_;
- GtkClipboard* primary_selection_;
#elif defined(USE_CLIPBOARD_AURAX11)
private:
// We keep our implementation details private because otherwise we bring in
diff --git a/chromium/ui/base/clipboard/clipboard_android.cc b/chromium/ui/base/clipboard/clipboard_android.cc
index f0971c448a0..e5e2a960d4d 100644
--- a/chromium/ui/base/clipboard/clipboard_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_android.cc
@@ -243,7 +243,7 @@ void Clipboard::Clear(ClipboardType type) {
}
void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<string16>* types,
+ std::vector<base::string16>* types,
bool* contains_filenames) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
@@ -259,12 +259,12 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
*contains_filenames = false;
}
-void Clipboard::ReadText(ClipboardType type, string16* result) const {
+void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
std::string utf8;
ReadAsciiText(type, &utf8);
- *result = UTF8ToUTF16(utf8);
+ *result = base::UTF8ToUTF16(utf8);
}
void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
@@ -275,7 +275,7 @@ void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
// Note: |src_url| isn't really used. It is only implemented in Windows
void Clipboard::ReadHTML(ClipboardType type,
- string16* markup,
+ base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -285,7 +285,7 @@ void Clipboard::ReadHTML(ClipboardType type,
src_url->clear();
std::string input = g_map.Get().Get(kHTMLFormat);
- *markup = UTF8ToUTF16(input);
+ *markup = base::UTF8ToUTF16(input);
*fragment_start = 0;
*fragment_end = static_cast<uint32>(markup->length());
@@ -317,13 +317,13 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const {
}
void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const string16& type,
- string16* result) const {
+ const base::string16& type,
+ base::string16* result) const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
-void Clipboard::ReadBookmark(string16* title, std::string* url) const {
+void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
diff --git a/chromium/ui/base/clipboard/clipboard_aura.cc b/chromium/ui/base/clipboard/clipboard_aura.cc
index 638604b5027..30b639a9076 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.cc
+++ b/chromium/ui/base/clipboard/clipboard_aura.cc
@@ -47,7 +47,7 @@ class ClipboardData {
virtual ~ClipboardData() {}
// Bitmask of AuraClipboardFormat types.
- const int format() const { return format_; }
+ int format() const { return format_; }
const std::string& text() const { return text_; }
void set_text(const std::string& text) {
@@ -87,7 +87,7 @@ class ClipboardData {
const SkBitmap& bitmap() const { return bitmap_; }
void SetBitmapData(const SkBitmap& bitmap) {
- bitmap.copyTo(&bitmap_, bitmap.getConfig());
+ bitmap.copyTo(&bitmap_);
format_ |= BITMAP;
}
@@ -150,20 +150,21 @@ class ClipboardData {
// on gtk or winapi clipboard on win.
class AuraClipboard {
public:
- AuraClipboard() {}
+ AuraClipboard() : sequence_number_(0) {
+ }
~AuraClipboard() {
Clear();
}
void Clear() {
+ sequence_number_++;
STLDeleteContainerPointers(data_list_.begin(), data_list_.end());
data_list_.clear();
}
- // Returns the number of entries currently in the clipboard stack.
- size_t GetNumClipboardEntries() {
- return data_list_.size();
+ uint64_t sequence_number() const {
+ return sequence_number_;
}
// Returns the data currently on the top of the clipboard stack, NULL if the
@@ -186,10 +187,10 @@ class AuraClipboard {
}
// Reads text from the data at the top of clipboard stack.
- void ReadText(string16* result) const {
+ void ReadText(base::string16* result) const {
std::string utf8_result;
ReadAsciiText(&utf8_result);
- *result = UTF8ToUTF16(utf8_result);
+ *result = base::UTF8ToUTF16(utf8_result);
}
// Reads ascii text from the data at the top of clipboard stack.
@@ -207,7 +208,7 @@ class AuraClipboard {
}
// Reads HTML from the data at the top of clipboard stack.
- void ReadHTML(string16* markup,
+ void ReadHTML(base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -221,7 +222,7 @@ class AuraClipboard {
return;
const ClipboardData* data = GetData();
- *markup = UTF8ToUTF16(data->markup_data());
+ *markup = base::UTF8ToUTF16(data->markup_data());
*src_url = data->url();
*fragment_start = 0;
@@ -247,12 +248,13 @@ class AuraClipboard {
// A shallow copy should be fine here, but just to be safe...
const SkBitmap& clipboard_bitmap = GetData()->bitmap();
- clipboard_bitmap.copyTo(&img, clipboard_bitmap.getConfig());
+ clipboard_bitmap.copyTo(&img);
return img;
}
// Reads data of type |type| from the data at the top of clipboard stack.
- void ReadCustomData(const string16& type, string16* result) const {
+ void ReadCustomData(const base::string16& type,
+ base::string16* result) const {
result->clear();
const ClipboardData* data = GetData();
if (!HasFormat(CUSTOM))
@@ -264,14 +266,14 @@ class AuraClipboard {
}
// Reads bookmark from the data at the top of clipboard stack.
- void ReadBookmark(string16* title, std::string* url) const {
+ void ReadBookmark(base::string16* title, std::string* url) const {
title->clear();
url->clear();
if (!HasFormat(BOOKMARK))
return;
const ClipboardData* data = GetData();
- *title = UTF8ToUTF16(data->bookmark_title());
+ *title = base::UTF8ToUTF16(data->bookmark_title());
*url = data->bookmark_url();
}
@@ -302,6 +304,7 @@ class AuraClipboard {
void AddToListEnsuringSize(ClipboardData* data) {
DCHECK(data);
+ sequence_number_++;
data_list_.push_front(data);
// If the size of list becomes more than the maximum allowed, we delete the
@@ -316,6 +319,9 @@ class AuraClipboard {
// Stack containing various versions of ClipboardData.
std::list<ClipboardData*> data_list_;
+ // Sequence number uniquely identifying clipboard state.
+ uint64_t sequence_number_;
+
DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
};
@@ -481,7 +487,7 @@ void Clipboard::Clear(ClipboardType type) {
}
void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<string16>* types,
+ std::vector<base::string16>* types,
bool* contains_filenames) const {
DCHECK(CalledOnValidThread());
if (!types || !contains_filenames) {
@@ -492,13 +498,13 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
types->clear();
*contains_filenames = false;
if (IsFormatAvailable(GetPlainTextFormatType(), type))
- types->push_back(UTF8ToUTF16(GetPlainTextFormatType().ToString()));
+ types->push_back(base::UTF8ToUTF16(GetPlainTextFormatType().ToString()));
if (IsFormatAvailable(GetHtmlFormatType(), type))
- types->push_back(UTF8ToUTF16(GetHtmlFormatType().ToString()));
+ types->push_back(base::UTF8ToUTF16(GetHtmlFormatType().ToString()));
if (IsFormatAvailable(GetRtfFormatType(), type))
- types->push_back(UTF8ToUTF16(GetRtfFormatType().ToString()));
+ types->push_back(base::UTF8ToUTF16(GetRtfFormatType().ToString()));
if (IsFormatAvailable(GetBitmapFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypePNG));
+ types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
AuraClipboard* clipboard = GetClipboard();
if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
@@ -507,7 +513,7 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
}
}
-void Clipboard::ReadText(ClipboardType type, string16* result) const {
+void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
DCHECK(CalledOnValidThread());
GetClipboard()->ReadText(result);
}
@@ -518,7 +524,7 @@ void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
}
void Clipboard::ReadHTML(ClipboardType type,
- string16* markup,
+ base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -537,13 +543,13 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const {
}
void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const string16& type,
- string16* result) const {
+ const base::string16& type,
+ base::string16* result) const {
DCHECK(CalledOnValidThread());
GetClipboard()->ReadCustomData(type, result);
}
-void Clipboard::ReadBookmark(string16* title, std::string* url) const {
+void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
DCHECK(CalledOnValidThread());
GetClipboard()->ReadBookmark(title, url);
}
@@ -555,7 +561,7 @@ void Clipboard::ReadData(const FormatType& format, std::string* result) const {
uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
DCHECK(CalledOnValidThread());
- return GetClipboard()->GetNumClipboardEntries();
+ return GetClipboard()->sequence_number();
}
void Clipboard::WriteText(const char* text_data, size_t text_len) {
diff --git a/chromium/ui/base/clipboard/clipboard_aurax11.cc b/chromium/ui/base/clipboard/clipboard_aurax11.cc
index 71a545c8b98..b075ddbddaf 100644
--- a/chromium/ui/base/clipboard/clipboard_aurax11.cc
+++ b/chromium/ui/base/clipboard/clipboard_aurax11.cc
@@ -15,8 +15,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
-#include "base/message_loop/message_pump_observer.h"
-#include "base/message_loop/message_pump_x11.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -25,6 +24,9 @@
#include "ui/base/x/selection_requestor.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_observer.h"
+#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/size.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -34,17 +36,21 @@ namespace ui {
namespace {
const char kClipboard[] = "CLIPBOARD";
+const char kClipboardManager[] = "CLIPBOARD_MANAGER";
const char kMimeTypeFilename[] = "chromium/filename";
const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
+const char kSaveTargets[] = "SAVE_TARGETS";
const char kTargets[] = "TARGETS";
const char* kAtomsToCache[] = {
kClipboard,
+ kClipboardManager,
Clipboard::kMimeTypePNG,
kMimeTypeFilename,
kMimeTypeMozillaURL,
kMimeTypeWebkitSmartPaste,
+ kSaveTargets,
kString,
kTargets,
kText,
@@ -55,7 +61,7 @@ const char* kAtomsToCache[] = {
///////////////////////////////////////////////////////////////////////////////
// Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
-class SelectionChangeObserver : public base::MessagePumpObserver {
+class SelectionChangeObserver : public ui::PlatformEventObserver {
public:
static SelectionChangeObserver* GetInstance();
@@ -70,11 +76,9 @@ class SelectionChangeObserver : public base::MessagePumpObserver {
SelectionChangeObserver();
virtual ~SelectionChangeObserver();
- // Overridden from base::MessagePumpObserver:
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE;
- virtual void DidProcessEvent(
- const base::NativeEvent& event) OVERRIDE {}
+ // ui::PlatformEventObserver:
+ virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {}
int event_base_;
Atom clipboard_atom_;
@@ -106,20 +110,19 @@ SelectionChangeObserver::SelectionChangeObserver()
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
- base::MessagePumpX11::Current()->AddObserver(this);
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
}
}
SelectionChangeObserver::~SelectionChangeObserver() {
- // We are a singleton; we will outlive our message pump.
+ // We are a singleton; we will outlive the event source.
}
SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
return Singleton<SelectionChangeObserver>::get();
}
-base::EventStatus SelectionChangeObserver::WillProcessEvent(
- const base::NativeEvent& event) {
+void SelectionChangeObserver::WillProcessEvent(const ui::PlatformEvent& event) {
if (event->type == event_base_ + XFixesSelectionNotify) {
XFixesSelectionNotifyEvent* ev =
reinterpret_cast<XFixesSelectionNotifyEvent*>(event);
@@ -131,7 +134,6 @@ base::EventStatus SelectionChangeObserver::WillProcessEvent(
DLOG(ERROR) << "Unexpected selection atom: " << ev->selection;
}
}
- return base::EVENT_CONTINUE;
}
///////////////////////////////////////////////////////////////////////////////
@@ -224,7 +226,7 @@ bool Clipboard::FormatType::Equals(const FormatType& other) const {
// Private implementation of our X11 integration. Keeps X11 headers out of the
// majority of chrome, which break badly.
-class Clipboard::AuraX11Details : public base::MessagePumpDispatcher {
+class Clipboard::AuraX11Details : public PlatformEventDispatcher {
public:
AuraX11Details();
virtual ~AuraX11Details();
@@ -235,6 +237,10 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher {
// given type.
::Atom LookupSelectionForClipboardType(ClipboardType type) const;
+ // Returns the X11 type that we pass to various XSelection functions for
+ // CLIPBOARD_TYPE_COPY_PASTE.
+ ::Atom GetCopyPasteSelection() const;
+
// Returns the object which is responsible for communication on |type|.
SelectionRequestor* GetSelectionRequestorForClipboardType(ClipboardType type);
@@ -278,12 +284,17 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher {
// Returns a vector with a |format| converted to an X11 atom.
std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format);
- // Clears a certain clipboard type.
+ // Clears a certain clipboard type, whether we own it or not.
void Clear(ClipboardType type);
+ // If we own the CLIPBOARD selection, requests the clipboard manager to take
+ // ownership of it.
+ void StoreCopyPasteDataAndWait();
+
private:
- // Overridden from base::MessagePumpDispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
// Our X11 state.
Display* x_display_;
@@ -297,6 +308,7 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher {
// Objects which request and receive selection data.
SelectionRequestor clipboard_requestor_;
SelectionRequestor primary_requestor_;
+ SelectionRequestor clipboard_manager_requestor_;
// Temporary target map that we write to during DispatchObects.
SelectionFormatMap clipboard_data_;
@@ -322,8 +334,11 @@ Clipboard::AuraX11Details::AuraX11Details()
NULL)),
atom_cache_(x_display_, kAtomsToCache),
clipboard_requestor_(x_display_, x_window_,
- atom_cache_.GetAtom(kClipboard)),
- primary_requestor_(x_display_, x_window_, XA_PRIMARY),
+ atom_cache_.GetAtom(kClipboard), this),
+ primary_requestor_(x_display_, x_window_, XA_PRIMARY, this),
+ clipboard_manager_requestor_(x_display_, x_window_,
+ atom_cache_.GetAtom(kClipboardManager),
+ this),
clipboard_owner_(x_display_, x_window_, atom_cache_.GetAtom(kClipboard)),
primary_owner_(x_display_, x_window_, XA_PRIMARY) {
// We don't know all possible MIME types at compile time.
@@ -332,11 +347,13 @@ Clipboard::AuraX11Details::AuraX11Details()
XStoreName(x_display_, x_window_, "Chromium clipboard");
XSelectInput(x_display_, x_window_, PropertyChangeMask);
- base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_);
+ if (PlatformEventSource::GetInstance())
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
}
Clipboard::AuraX11Details::~AuraX11Details() {
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_);
+ if (PlatformEventSource::GetInstance())
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
XDestroyWindow(x_display_, x_window_);
}
@@ -344,17 +361,21 @@ Clipboard::AuraX11Details::~AuraX11Details() {
::Atom Clipboard::AuraX11Details::LookupSelectionForClipboardType(
ClipboardType type) const {
if (type == CLIPBOARD_TYPE_COPY_PASTE)
- return atom_cache_.GetAtom(kClipboard);
+ return GetCopyPasteSelection();
return XA_PRIMARY;
}
+::Atom Clipboard::AuraX11Details::GetCopyPasteSelection() const {
+ return atom_cache_.GetAtom(kClipboard);
+}
+
const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom(
::Atom atom) {
if (atom == XA_PRIMARY)
return primary_owner_.selection_format_map();
- DCHECK_EQ(atom_cache_.GetAtom(kClipboard), atom);
+ DCHECK_EQ(GetCopyPasteSelection(), atom);
return clipboard_owner_.selection_format_map();
}
@@ -435,9 +456,13 @@ TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList(
NULL,
&out_data_items,
&out_type)) {
- const ::Atom* atom_array = reinterpret_cast<const ::Atom*>(data->front());
- for (size_t i = 0; i < out_data_items; ++i)
- out.push_back(atom_array[i]);
+ // Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
+ if (out_type == XA_ATOM || out_type == atom_cache_.GetAtom(kTargets)) {
+ const ::Atom* atom_array =
+ reinterpret_cast<const ::Atom*>(data->front());
+ for (size_t i = 0; i < out_data_items; ++i)
+ out.push_back(atom_array[i]);
+ }
} else {
// There was no target list. Most Java apps doesn't offer a TARGETS list,
// even though they AWT to. They will offer individual text types if you
@@ -477,41 +502,75 @@ std::vector< ::Atom> Clipboard::AuraX11Details::GetAtomsForFormat(
void Clipboard::AuraX11Details::Clear(ClipboardType type) {
if (type == CLIPBOARD_TYPE_COPY_PASTE)
- return clipboard_owner_.Clear();
+ clipboard_owner_.ClearSelectionOwner();
else
- return primary_owner_.Clear();
+ primary_owner_.ClearSelectionOwner();
+}
+
+void Clipboard::AuraX11Details::StoreCopyPasteDataAndWait() {
+ ::Atom selection = GetCopyPasteSelection();
+ if (XGetSelectionOwner(x_display_, selection) != x_window_)
+ return;
+
+ ::Atom clipboard_manager_atom = atom_cache_.GetAtom(kClipboardManager);
+ if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == None)
+ return;
+
+ const SelectionFormatMap& format_map = LookupStorageForAtom(selection);
+ if (format_map.size() == 0)
+ return;
+ std::vector<Atom> targets = format_map.GetTypes();
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ clipboard_manager_requestor_.PerformBlockingConvertSelectionWithParameter(
+ atom_cache_.GetAtom(kSaveTargets), targets);
+ UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
+ base::TimeTicks::Now() - start);
}
-bool Clipboard::AuraX11Details::Dispatch(const base::NativeEvent& event) {
- XEvent* xev = event;
+bool Clipboard::AuraX11Details::CanDispatchEvent(const PlatformEvent& event) {
+ return event->xany.window == x_window_;
+}
+uint32_t Clipboard::AuraX11Details::DispatchEvent(const PlatformEvent& xev) {
switch (xev->type) {
case SelectionRequest: {
- if (xev->xselectionrequest.selection == XA_PRIMARY)
+ if (xev->xselectionrequest.selection == XA_PRIMARY) {
primary_owner_.OnSelectionRequest(xev->xselectionrequest);
- else
+ } else {
+ // We should not get requests for the CLIPBOARD_MANAGER selection
+ // because we never take ownership of it.
+ DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection);
clipboard_owner_.OnSelectionRequest(xev->xselectionrequest);
+ }
break;
}
case SelectionNotify: {
- if (xev->xselection.selection == XA_PRIMARY)
+ ::Atom selection = xev->xselection.selection;
+ if (selection == XA_PRIMARY)
primary_requestor_.OnSelectionNotify(xev->xselection);
- else
+ else if (selection == GetCopyPasteSelection())
clipboard_requestor_.OnSelectionNotify(xev->xselection);
+ else if (selection == atom_cache_.GetAtom(kClipboardManager))
+ clipboard_manager_requestor_.OnSelectionNotify(xev->xselection);
break;
}
case SelectionClear: {
- if (xev->xselectionclear.selection == XA_PRIMARY)
+ if (xev->xselectionclear.selection == XA_PRIMARY) {
primary_owner_.OnSelectionClear(xev->xselectionclear);
- else
+ } else {
+ // We should not get requests for the CLIPBOARD_MANAGER selection
+ // because we never take ownership of it.
+ DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection);
clipboard_owner_.OnSelectionClear(xev->xselectionclear);
+ }
break;
}
default:
break;
}
- return true;
+ return POST_DISPATCH_NONE;
}
///////////////////////////////////////////////////////////////////////////////
@@ -525,9 +584,7 @@ Clipboard::Clipboard()
Clipboard::~Clipboard() {
DCHECK(CalledOnValidThread());
- // TODO(erg): We need to do whatever the equivalent of
- // gtk_clipboard_store(clipboard_) is here. When we shut down, we want the
- // current selection to live on.
+ aurax11_details_->StoreCopyPasteDataAndWait();
}
void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
@@ -545,8 +602,12 @@ void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
if (text_iter != objects.end()) {
aurax11_details_->CreateNewClipboardData();
- const ObjectMapParam& char_vector = text_iter->second[0];
- WriteText(&char_vector.front(), char_vector.size());
+ const ObjectMapParams& params_vector = text_iter->second;
+ if (params_vector.size()) {
+ const ObjectMapParam& char_vector = params_vector[0];
+ if (char_vector.size())
+ WriteText(&char_vector.front(), char_vector.size());
+ }
aurax11_details_->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION);
}
}
@@ -558,6 +619,10 @@ bool Clipboard::IsFormatAvailable(const FormatType& format,
DCHECK(IsSupportedClipboardType(type));
TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
+ if (format.Equals(GetPlainTextFormatType()) ||
+ format.Equals(GetUrlFormatType())) {
+ return target_list.ContainsText();
+ }
return target_list.ContainsFormat(format);
}
@@ -568,7 +633,7 @@ void Clipboard::Clear(ClipboardType type) {
}
void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<string16>* types,
+ std::vector<base::string16>* types,
bool* contains_filenames) const {
DCHECK(CalledOnValidThread());
if (!types || !contains_filenames) {
@@ -581,13 +646,13 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
types->clear();
if (target_list.ContainsText())
- types->push_back(UTF8ToUTF16(kMimeTypeText));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeText));
if (target_list.ContainsFormat(GetHtmlFormatType()))
- types->push_back(UTF8ToUTF16(kMimeTypeHTML));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
if (target_list.ContainsFormat(GetRtfFormatType()))
- types->push_back(UTF8ToUTF16(kMimeTypeRTF));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if (target_list.ContainsFormat(GetBitmapFormatType()))
- types->push_back(UTF8ToUTF16(kMimeTypePNG));
+ types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
*contains_filenames = false;
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
@@ -596,14 +661,14 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
}
-void Clipboard::ReadText(ClipboardType type, string16* result) const {
+void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
DCHECK(CalledOnValidThread());
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
type, aurax11_details_->GetTextAtoms()));
if (data.IsValid()) {
std::string text = data.GetText();
- *result = UTF8ToUTF16(text);
+ *result = base::UTF8ToUTF16(text);
}
}
@@ -619,7 +684,7 @@ void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
// TODO(estade): handle different charsets.
// TODO(port): set *src_url.
void Clipboard::ReadHTML(ClipboardType type,
- string16* markup,
+ base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -665,8 +730,8 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const {
}
void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const string16& type,
- string16* result) const {
+ const base::string16& type,
+ base::string16* result) const {
DCHECK(CalledOnValidThread());
SelectionData data(aurax11_details_->RequestAndWaitForTypes(
@@ -676,7 +741,7 @@ void Clipboard::ReadCustomData(ClipboardType clipboard_type,
ReadCustomDataForType(data.GetData(), data.GetSize(), type, result);
}
-void Clipboard::ReadBookmark(string16* title, std::string* url) const {
+void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
DCHECK(CalledOnValidThread());
// TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
NOTIMPLEMENTED();
@@ -736,8 +801,8 @@ void Clipboard::WriteBookmark(const char* title_data,
const char* url_data,
size_t url_len) {
// Write as a mozilla url (UTF16: URL, newline, title).
- string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n");
- string16 title = UTF8ToUTF16(std::string(title_data, title_len));
+ base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n");
+ base::string16 title = base::UTF8ToUTF16(std::string(title_data, title_len));
std::vector<unsigned char> data;
ui::AddString16ToVector(url, &data);
@@ -751,8 +816,11 @@ void Clipboard::WriteBookmark(const char* title_data,
// Write an extra flavor that signifies WebKit was the last to modify the
// pasteboard. This flavor has no data.
void Clipboard::WriteWebSmartPaste() {
- aurax11_details_->InsertMapping(kMimeTypeWebkitSmartPaste,
- scoped_refptr<base::RefCountedMemory>());
+ std::string empty;
+ aurax11_details_->InsertMapping(
+ kMimeTypeWebkitSmartPaste,
+ scoped_refptr<base::RefCountedMemory>(
+ base::RefCountedString::TakeString(&empty)));
}
void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
diff --git a/chromium/ui/base/clipboard/clipboard_gtk.cc b/chromium/ui/base/clipboard/clipboard_gtk.cc
deleted file mode 100644
index eebcc5e39c1..00000000000
--- a/chromium/ui/base/clipboard/clipboard_gtk.cc
+++ /dev/null
@@ -1,676 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/clipboard/clipboard.h"
-
-#include <gtk/gtk.h>
-#include <X11/extensions/Xfixes.h>
-#include <X11/Xatom.h>
-#include <map>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/clipboard/custom_data_helper.h"
-#include "ui/base/gtk/gtk_signal.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/scoped_gobject.h"
-#include "ui/gfx/size.h"
-
-namespace ui {
-
-namespace {
-
-class SelectionChangeObserver {
- public:
- static SelectionChangeObserver* GetInstance();
-
- uint64 clipboard_sequence_number() const {
- return clipboard_sequence_number_;
- }
- uint64 primary_sequence_number() const { return primary_sequence_number_; }
-
- private:
- friend struct DefaultSingletonTraits<SelectionChangeObserver>;
-
- SelectionChangeObserver();
- ~SelectionChangeObserver();
-
- CHROMEG_CALLBACK_1(SelectionChangeObserver, GdkFilterReturn, OnXEvent,
- GdkXEvent*, GdkEvent*);
-
- int event_base_;
- Atom clipboard_atom_;
- uint64 clipboard_sequence_number_;
- uint64 primary_sequence_number_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
-};
-
-SelectionChangeObserver::SelectionChangeObserver()
- : event_base_(-1),
- clipboard_atom_(None),
- clipboard_sequence_number_(0),
- primary_sequence_number_(0) {
- int ignored;
- if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) {
- clipboard_atom_ = XInternAtom(gfx::GetXDisplay(), "CLIPBOARD", false);
- XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
- clipboard_atom_,
- XFixesSetSelectionOwnerNotifyMask |
- XFixesSelectionWindowDestroyNotifyMask |
- XFixesSelectionClientCloseNotifyMask);
- // This seems to be semi-optional. For some reason, registering for any
- // selection notify events seems to subscribe us to events for both the
- // primary and the clipboard buffers. Register anyway just to be safe.
- XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
- XA_PRIMARY,
- XFixesSetSelectionOwnerNotifyMask |
- XFixesSelectionWindowDestroyNotifyMask |
- XFixesSelectionClientCloseNotifyMask);
- gdk_window_add_filter(NULL, &SelectionChangeObserver::OnXEventThunk, this);
- }
-}
-
-SelectionChangeObserver::~SelectionChangeObserver() {
-}
-
-SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
- return Singleton<SelectionChangeObserver>::get();
-}
-
-GdkFilterReturn SelectionChangeObserver::OnXEvent(GdkXEvent* xevent,
- GdkEvent* event) {
- XEvent* xev = static_cast<XEvent*>(xevent);
-
- if (xev->type == event_base_ + XFixesSelectionNotify) {
- XFixesSelectionNotifyEvent* ev =
- reinterpret_cast<XFixesSelectionNotifyEvent*>(xev);
- if (ev->selection == clipboard_atom_) {
- clipboard_sequence_number_++;
- } else if (ev->selection == XA_PRIMARY) {
- primary_sequence_number_++;
- } else {
- DLOG(ERROR) << "Unexpected selection atom: " << ev->selection;
- }
- }
- return GDK_FILTER_CONTINUE;
-}
-
-const char kMimeTypeBitmap[] = "image/bmp";
-const char kMimeTypeMozillaURL[] = "text/x-moz-url";
-const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
-const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
-
-std::string GdkAtomToString(const GdkAtom& atom) {
- gchar* name = gdk_atom_name(atom);
- std::string rv(name);
- g_free(name);
- return rv;
-}
-
-GdkAtom StringToGdkAtom(const std::string& str) {
- return gdk_atom_intern(str.c_str(), FALSE);
-}
-
-// GtkClipboardGetFunc callback.
-// GTK will call this when an application wants data we copied to the clipboard.
-void GetData(GtkClipboard* clipboard,
- GtkSelectionData* selection_data,
- guint info,
- gpointer user_data) {
- Clipboard::TargetMap* data_map =
- reinterpret_cast<Clipboard::TargetMap*>(user_data);
-
- std::string target_string = GdkAtomToString(
- gtk_selection_data_get_target(selection_data));
- Clipboard::TargetMap::iterator iter = data_map->find(target_string);
-
- if (iter == data_map->end())
- return;
-
- if (target_string == kMimeTypeBitmap) {
- gtk_selection_data_set_pixbuf(selection_data,
- reinterpret_cast<GdkPixbuf*>(iter->second.first));
- } else {
- gtk_selection_data_set(selection_data,
- gtk_selection_data_get_target(selection_data), 8,
- reinterpret_cast<guchar*>(iter->second.first),
- iter->second.second);
- }
-}
-
-// GtkClipboardClearFunc callback.
-// We are guaranteed this will be called exactly once for each call to
-// gtk_clipboard_set_with_data.
-void ClearData(GtkClipboard* /*clipboard*/,
- gpointer user_data) {
- Clipboard::TargetMap* map =
- reinterpret_cast<Clipboard::TargetMap*>(user_data);
- // The same data may be inserted under multiple keys, so use a set to
- // uniq them.
- std::set<char*> ptrs;
-
- for (Clipboard::TargetMap::iterator iter = map->begin();
- iter != map->end(); ++iter) {
- if (iter->first == kMimeTypeBitmap)
- g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first));
- else
- ptrs.insert(iter->second.first);
- }
-
- for (std::set<char*>::iterator iter = ptrs.begin();
- iter != ptrs.end(); ++iter) {
- delete[] *iter;
- }
-
- delete map;
-}
-
-} // namespace
-
-Clipboard::FormatType::FormatType() : data_(GDK_NONE) {
-}
-
-Clipboard::FormatType::FormatType(const std::string& format_string)
- : data_(StringToGdkAtom(format_string)) {
-}
-
-Clipboard::FormatType::FormatType(const GdkAtom& native_format)
- : data_(native_format) {
-}
-
-Clipboard::FormatType::~FormatType() {
-}
-
-std::string Clipboard::FormatType::Serialize() const {
- return GdkAtomToString(data_);
-}
-
-// static
-Clipboard::FormatType Clipboard::FormatType::Deserialize(
- const std::string& serialization) {
- return FormatType(serialization);
-}
-
-bool Clipboard::FormatType::Equals(const FormatType& other) const {
- return data_ == other.data_;
-}
-
-Clipboard::Clipboard() : clipboard_data_(NULL) {
- DCHECK(CalledOnValidThread());
- clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
- primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
-}
-
-Clipboard::~Clipboard() {
- DCHECK(CalledOnValidThread());
- gtk_clipboard_store(clipboard_);
-}
-
-void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
- DCHECK(CalledOnValidThread());
- clipboard_data_ = new TargetMap();
-
- for (ObjectMap::const_iterator iter = objects.begin();
- iter != objects.end(); ++iter) {
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
- }
- SetGtkClipboard(type);
-
- if (type == CLIPBOARD_TYPE_COPY_PASTE) {
- ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
- if (text_iter != objects.end()) {
- // Copy text and SourceTag to the selection clipboard.
- ObjectMap::const_iterator next_iter = text_iter;
- WriteObjects(CLIPBOARD_TYPE_SELECTION, ObjectMap(text_iter, ++next_iter));
- }
- }
-}
-
-// Take ownership of the GTK clipboard and inform it of the targets we support.
-void Clipboard::SetGtkClipboard(ClipboardType type) {
- scoped_ptr<GtkTargetEntry[]> targets(
- new GtkTargetEntry[clipboard_data_->size()]);
-
- int i = 0;
- for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin();
- iter != clipboard_data_->end(); ++iter, ++i) {
- targets[i].target = const_cast<char*>(iter->first.c_str());
- targets[i].flags = 0;
- targets[i].info = 0;
- }
-
- GtkClipboard *clipboard = LookupBackingClipboard(type);
-
- if (gtk_clipboard_set_with_data(clipboard, targets.get(),
- clipboard_data_->size(),
- GetData, ClearData,
- clipboard_data_)) {
- gtk_clipboard_set_can_store(clipboard,
- targets.get(),
- clipboard_data_->size());
- }
-
- // clipboard_data_ now owned by the GtkClipboard.
- clipboard_data_ = NULL;
-}
-
-void Clipboard::WriteText(const char* text_data, size_t text_len) {
- char* data = new char[text_len];
- memcpy(data, text_data, text_len);
-
- InsertMapping(kMimeTypeText, data, text_len);
- InsertMapping("TEXT", data, text_len);
- InsertMapping("STRING", data, text_len);
- InsertMapping("UTF8_STRING", data, text_len);
- InsertMapping("COMPOUND_TEXT", data, text_len);
-}
-
-void Clipboard::WriteHTML(const char* markup_data,
- size_t markup_len,
- const char* url_data,
- size_t url_len) {
- // TODO(estade): We need to expand relative links with |url_data|.
- static const char* html_prefix = "<meta http-equiv=\"content-type\" "
- "content=\"text/html; charset=utf-8\">";
- size_t html_prefix_len = strlen(html_prefix);
- size_t total_len = html_prefix_len + markup_len + 1;
-
- char* data = new char[total_len];
- snprintf(data, total_len, "%s", html_prefix);
- memcpy(data + html_prefix_len, markup_data, markup_len);
- // Some programs expect NULL-terminated data. See http://crbug.com/42624
- data[total_len - 1] = '\0';
-
- InsertMapping(kMimeTypeHTML, data, total_len);
-}
-
-void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
- WriteData(GetRtfFormatType(), rtf_data, data_len);
-}
-
-// Write an extra flavor that signifies WebKit was the last to modify the
-// pasteboard. This flavor has no data.
-void Clipboard::WriteWebSmartPaste() {
- InsertMapping(kMimeTypeWebkitSmartPaste, NULL, 0);
-}
-
-void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
- GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
-
- // We store the GdkPixbuf*, and the size_t half of the pair is meaningless.
- // Note that this contrasts with the vast majority of entries in our target
- // map, which directly store the data and its length.
- InsertMapping(kMimeTypeBitmap, reinterpret_cast<char*>(pixbuf), 0);
-}
-
-void Clipboard::WriteBookmark(const char* title_data, size_t title_len,
- const char* url_data, size_t url_len) {
- // Write as a mozilla url (UTF16: URL, newline, title).
- base::string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n");
- base::string16 title = UTF8ToUTF16(std::string(title_data, title_len));
- if (title.length() >= std::numeric_limits<size_t>::max() / 4 ||
- url.length() >= std::numeric_limits<size_t>::max() / 4)
- return;
- size_t data_len = 2 * (title.length() + url.length());
-
- char* data = new char[data_len];
- memcpy(data, url.data(), 2 * url.length());
- memcpy(data + 2 * url.length(), title.data(), 2 * title.length());
- InsertMapping(kMimeTypeMozillaURL, data, data_len);
-}
-
-void Clipboard::WriteData(const FormatType& format,
- const char* data_data,
- size_t data_len) {
- // We assume that certain mapping types are only written by trusted code.
- // Therefore we must upkeep their integrity.
- if (format.Equals(GetBitmapFormatType()))
- return;
- char* data = new char[data_len];
- memcpy(data, data_data, data_len);
- // TODO(dcheng): Maybe this map should use GdkAtoms...
- InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len);
-}
-
-// We do not use gtk_clipboard_wait_is_target_available because of
-// a bug with the gtk clipboard. It caches the available targets
-// and does not always refresh the cache when it is appropriate.
-bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format,
- ClipboardType type) const {
- DCHECK(CalledOnValidThread());
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (clipboard == NULL)
- return false;
-
- bool retval = false;
- GtkSelectionData* data = gtk_clipboard_wait_for_contents(
- clipboard, gdk_atom_intern_static_string("TARGETS"));
-
- bool format_is_plain_text = GetPlainTextFormatType().Equals(format);
- if (format_is_plain_text) {
- // This tries a number of common text targets.
- if (data) {
- retval = gtk_selection_data_targets_include_text(data);
- }
- // Some programs like Java decide to set an empty TARGETS list, so even if
- // data is not NULL, we still have to fall back.
- if (!retval) {
- // Some programs post data to the clipboard without any targets. If this
- // is the case we attempt to make sense of the contents as text. This is
- // pretty unfortunate since it means we have to actually copy the data to
- // see if it is available, but at least this path shouldn't be hit for
- // conforming programs.
- gchar* text = gtk_clipboard_wait_for_text(clipboard);
- if (text) {
- g_free(text);
- retval = true;
- }
- }
- } else if (data) {
- GdkAtom* targets = NULL;
- int num = 0;
- gtk_selection_data_get_targets(data, &targets, &num);
-
- for (int i = 0; i < num; i++) {
- if (targets[i] == format.ToGdkAtom()) {
- retval = true;
- break;
- }
- }
-
- g_free(targets);
- }
-
- if (data)
- gtk_selection_data_free(data);
-
- return retval;
-}
-
-void Clipboard::Clear(ClipboardType type) {
- DCHECK(CalledOnValidThread());
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (clipboard == NULL)
- return;
- gtk_clipboard_clear(clipboard);
-}
-
-void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<base::string16>* types,
- bool* contains_filenames) const {
- DCHECK(CalledOnValidThread());
- if (!types || !contains_filenames) {
- NOTREACHED();
- return;
- }
-
- types->clear();
- if (IsFormatAvailable(GetPlainTextFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeText));
- if (IsFormatAvailable(GetHtmlFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeHTML));
- if (IsFormatAvailable(GetRtfFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeRTF));
- if (IsFormatAvailable(GetBitmapFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypePNG));
- *contains_filenames = false;
-
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (!clipboard)
- return;
-
- GtkSelectionData* data = gtk_clipboard_wait_for_contents(
- clipboard, GetWebCustomDataFormatType().ToGdkAtom());
- if (!data)
- return;
- ReadCustomDataTypes(gtk_selection_data_get_data(data),
- gtk_selection_data_get_length(data),
- types);
- gtk_selection_data_free(data);
-}
-
-
-void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
- DCHECK(CalledOnValidThread());
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (clipboard == NULL)
- return;
-
- result->clear();
- gchar* text = gtk_clipboard_wait_for_text(clipboard);
-
- if (text == NULL)
- return;
-
- // TODO(estade): do we want to handle the possible error here?
- UTF8ToUTF16(text, strlen(text), result);
- g_free(text);
-}
-
-void Clipboard::ReadAsciiText(ClipboardType type,
- std::string* result) const {
- DCHECK(CalledOnValidThread());
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (clipboard == NULL)
- return;
-
- result->clear();
- gchar* text = gtk_clipboard_wait_for_text(clipboard);
-
- if (text == NULL)
- return;
-
- result->assign(text);
- g_free(text);
-}
-
-// TODO(estade): handle different charsets.
-// TODO(port): set *src_url.
-void Clipboard::ReadHTML(ClipboardType type,
- base::string16* markup,
- std::string* src_url,
- uint32* fragment_start,
- uint32* fragment_end) const {
- DCHECK(CalledOnValidThread());
- markup->clear();
- if (src_url)
- src_url->clear();
- *fragment_start = 0;
- *fragment_end = 0;
-
- GtkClipboard* clipboard = LookupBackingClipboard(type);
- if (clipboard == NULL)
- return;
- GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
- GetHtmlFormatType().ToGdkAtom());
-
- if (!data)
- return;
-
- // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
- // UTF-16, otherwise assume UTF-8.
- gint data_length = gtk_selection_data_get_length(data);
- const guchar* raw_data = gtk_selection_data_get_data(data);
-
- if (data_length >= 2 &&
- reinterpret_cast<const uint16_t*>(raw_data)[0] == 0xFEFF) {
- markup->assign(reinterpret_cast<const uint16_t*>(raw_data) + 1,
- (data_length / 2) - 1);
- } else {
- UTF8ToUTF16(reinterpret_cast<const char*>(raw_data), data_length, markup);
- }
-
- // If there is a terminating NULL, drop it.
- if (!markup->empty() && markup->at(markup->length() - 1) == '\0')
- markup->resize(markup->length() - 1);
-
- *fragment_start = 0;
- DCHECK(markup->length() <= kuint32max);
- *fragment_end = static_cast<uint32>(markup->length());
-
- gtk_selection_data_free(data);
-}
-
-void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
- DCHECK(CalledOnValidThread());
- ReadData(GetRtfFormatType(), result);
-}
-
-SkBitmap Clipboard::ReadImage(ClipboardType type) const {
- DCHECK(CalledOnValidThread());
- ScopedGObject<GdkPixbuf>::Type pixbuf(
- gtk_clipboard_wait_for_image(clipboard_));
- if (!pixbuf.get())
- return SkBitmap();
-
- gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf.get()),
- gdk_pixbuf_get_height(pixbuf.get())),
- 1.0f, false);
- {
- skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
- cairo_t* context = scoped_platform_paint.GetPlatformSurface();
- gdk_cairo_set_source_pixbuf(context, pixbuf.get(), 0.0, 0.0);
- cairo_paint(context);
- }
- return canvas.ExtractImageRep().sk_bitmap();
-}
-
-void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const base::string16& type,
- base::string16* result) const {
- DCHECK(CalledOnValidThread());
- GtkClipboard* clipboard = LookupBackingClipboard(clipboard_type);
- if (!clipboard)
- return;
-
- GtkSelectionData* data = gtk_clipboard_wait_for_contents(
- clipboard, GetWebCustomDataFormatType().ToGdkAtom());
- if (!data)
- return;
- ReadCustomDataForType(gtk_selection_data_get_data(data),
- gtk_selection_data_get_length(data),
- type, result);
- gtk_selection_data_free(data);
-}
-
-void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
- // TODO(estade): implement this.
- NOTIMPLEMENTED();
-}
-
-void Clipboard::ReadData(const FormatType& format, std::string* result) const {
- DCHECK(CalledOnValidThread());
- result->clear();
- GtkSelectionData* data =
- gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom());
- if (!data)
- return;
- result->assign(reinterpret_cast<const char*>(
- gtk_selection_data_get_data(data)),
- gtk_selection_data_get_length(data));
- gtk_selection_data_free(data);
-}
-
-uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
- DCHECK(CalledOnValidThread());
- if (type == CLIPBOARD_TYPE_COPY_PASTE)
- return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
- else
- return SelectionChangeObserver::GetInstance()->primary_sequence_number();
-}
-
-//static
-Clipboard::FormatType Clipboard::GetFormatType(
- const std::string& format_string) {
- return FormatType::Deserialize(format_string);
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
- CR_DEFINE_STATIC_LOCAL(
- FormatType, type, (GDK_TARGET_STRING));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
- return GetPlainTextFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
- return GetPlainTextFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
- return GetPlainTextWFormatType();
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
- return type;
-}
-
-// static
-const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
- CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
- return type;
-}
-
-void Clipboard::InsertMapping(const char* key,
- char* data,
- size_t data_len) {
- DCHECK(clipboard_data_->find(key) == clipboard_data_->end());
- (*clipboard_data_)[key] = std::make_pair(data, data_len);
-}
-
-GtkClipboard* Clipboard::LookupBackingClipboard(ClipboardType type) const {
- switch (type) {
- case CLIPBOARD_TYPE_COPY_PASTE:
- return clipboard_;
- case CLIPBOARD_TYPE_SELECTION:
- return primary_selection_;
- default:
- NOTREACHED();
- return NULL;
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_mac.mm b/chromium/ui/base/clipboard/clipboard_mac.mm
index c4b69e804ef..0b6d3a709ae 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_mac.mm
@@ -227,18 +227,18 @@ void Clipboard::Clear(ClipboardType type) {
}
void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<string16>* types,
+ std::vector<base::string16>* types,
bool* contains_filenames) const {
DCHECK(CalledOnValidThread());
types->clear();
if (IsFormatAvailable(Clipboard::GetPlainTextFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeText));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeText));
if (IsFormatAvailable(Clipboard::GetHtmlFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeHTML));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type))
- types->push_back(UTF8ToUTF16(kMimeTypeRTF));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if ([NSImage canInitWithPasteboard:GetPasteboard()])
- types->push_back(UTF8ToUTF16(kMimeTypePNG));
+ types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
*contains_filenames = false;
NSPasteboard* pb = GetPasteboard();
@@ -249,15 +249,13 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
}
}
-void Clipboard::ReadText(ClipboardType type, string16* result) const {
+void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
NSPasteboard* pb = GetPasteboard();
NSString* contents = [pb stringForType:NSStringPboardType];
- UTF8ToUTF16([contents UTF8String],
- [contents lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
- result);
+ *result = base::SysNSStringToUTF16(contents);
}
void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
@@ -273,7 +271,7 @@ void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
}
void Clipboard::ReadHTML(ClipboardType type,
- string16* markup,
+ base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -295,9 +293,7 @@ void Clipboard::ReadHTML(ClipboardType type,
NSString* contents = [pb stringForType:bestType];
if ([bestType isEqualToString:NSRTFPboardType])
contents = [pb htmlFromRtf];
- UTF8ToUTF16([contents UTF8String],
- [contents lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
- markup);
+ *markup = base::SysNSStringToUTF16(contents);
}
*fragment_start = 0;
@@ -331,8 +327,8 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const {
}
void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const string16& type,
- string16* result) const {
+ const base::string16& type,
+ base::string16* result) const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE);
@@ -344,15 +340,13 @@ void Clipboard::ReadCustomData(ClipboardType clipboard_type,
}
}
-void Clipboard::ReadBookmark(string16* title, std::string* url) const {
+void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
DCHECK(CalledOnValidThread());
NSPasteboard* pb = GetPasteboard();
if (title) {
NSString* contents = [pb stringForType:kUTTypeURLName];
- UTF8ToUTF16([contents UTF8String],
- [contents lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
- title);
+ *title = base::SysNSStringToUTF16(contents);
}
if (url) {
diff --git a/chromium/ui/base/clipboard/clipboard_types.h b/chromium/ui/base/clipboard/clipboard_types.h
index 68e44fea627..8929d921348 100644
--- a/chromium/ui/base/clipboard/clipboard_types.h
+++ b/chromium/ui/base/clipboard/clipboard_types.h
@@ -13,7 +13,8 @@ namespace ui {
enum ClipboardType {
CLIPBOARD_TYPE_COPY_PASTE,
CLIPBOARD_TYPE_SELECTION,
- CLIPBOARD_TYPE_DRAG
+ CLIPBOARD_TYPE_DRAG,
+ CLIPBOARD_TYPE_LAST = CLIPBOARD_TYPE_DRAG
};
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_unittest.cc b/chromium/ui/base/clipboard/clipboard_unittest.cc
index 324663aec15..72c07cf2c8a 100644
--- a/chromium/ui/base/clipboard/clipboard_unittest.cc
+++ b/chromium/ui/base/clipboard/clipboard_unittest.cc
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
+#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,22 +32,49 @@
#include "base/android/jni_string.h"
#endif
+#if defined(USE_AURA)
+#include "ui/events/platform/platform_event_source.h"
+#endif
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::UTF16ToUTF8;
+
namespace ui {
class ClipboardTest : public PlatformTest {
+ public:
+#if defined(USE_AURA)
+ ClipboardTest() : event_source_(ui::PlatformEventSource::CreateDefault()) {}
+#else
+ ClipboardTest() {}
+#endif
+
+ static void WriteObjectsToClipboard(ui::Clipboard* clipboard,
+ const Clipboard::ObjectMap& objects) {
+ clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
+ }
+
protected:
Clipboard& clipboard() { return clipboard_; }
+ void WriteObjectsToClipboard(const Clipboard::ObjectMap& objects) {
+ WriteObjectsToClipboard(&clipboard(), objects);
+ }
+
private:
base::MessageLoopForUI message_loop_;
+#if defined(USE_AURA)
+ scoped_ptr<PlatformEventSource> event_source_;
+#endif
Clipboard clipboard_;
};
namespace {
-bool MarkupMatches(const string16& expected_markup,
- const string16& actual_markup) {
- return actual_markup.find(expected_markup) != string16::npos;
+bool MarkupMatches(const base::string16& expected_markup,
+ const base::string16& actual_markup) {
+ return actual_markup.find(expected_markup) != base::string16::npos;
}
} // namespace
@@ -67,7 +95,7 @@ TEST_F(ClipboardTest, ClearTest) {
}
TEST_F(ClipboardTest, TextTest) {
- string16 text(ASCIIToUTF16("This is a string16!#$")), text_result;
+ base::string16 text(ASCIIToUTF16("This is a base::string16!#$")), text_result;
std::string ascii_text;
{
@@ -88,8 +116,8 @@ TEST_F(ClipboardTest, TextTest) {
}
TEST_F(ClipboardTest, HTMLTest) {
- string16 markup(ASCIIToUTF16("<string>Hi!</string>")), markup_result;
- string16 plain(ASCIIToUTF16("Hi!")), plain_result;
+ base::string16 markup(ASCIIToUTF16("<string>Hi!</string>")), markup_result;
+ base::string16 plain(ASCIIToUTF16("Hi!")), plain_result;
std::string url("http://www.example.com/"), url_result;
{
@@ -131,10 +159,12 @@ TEST_F(ClipboardTest, RTFTest) {
EXPECT_EQ(rtf, result);
}
-#if defined(TOOLKIT_GTK)
+// TODO(dnicoara) Enable test once Ozone implements clipboard support:
+// crbug.com/361707
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
TEST_F(ClipboardTest, MultipleBufferTest) {
- string16 text(ASCIIToUTF16("Standard")), text_result;
- string16 markup(ASCIIToUTF16("<string>Selection</string>")), markup_result;
+ base::string16 text(ASCIIToUTF16("Standard")), text_result;
+ base::string16 markup(ASCIIToUTF16("<string>Selection</string>"));
std::string url("http://www.example.com/"), url_result;
{
@@ -164,6 +194,7 @@ TEST_F(ClipboardTest, MultipleBufferTest) {
EXPECT_EQ(text, text_result);
uint32 ignored;
+ base::string16 markup_result;
clipboard().ReadHTML(CLIPBOARD_TYPE_SELECTION,
&markup_result,
&url_result,
@@ -174,10 +205,10 @@ TEST_F(ClipboardTest, MultipleBufferTest) {
#endif
TEST_F(ClipboardTest, TrickyHTMLTest) {
- string16 markup(ASCIIToUTF16("<em>Bye!<!--EndFragment --></em>")),
+ base::string16 markup(ASCIIToUTF16("<em>Bye!<!--EndFragment --></em>")),
markup_result;
std::string url, url_result;
- string16 plain(ASCIIToUTF16("Bye!")), plain_result;
+ base::string16 plain(ASCIIToUTF16("Bye!")), plain_result;
{
ScopedClipboardWriter clipboard_writer(&clipboard(),
@@ -201,7 +232,7 @@ TEST_F(ClipboardTest, TrickyHTMLTest) {
#if defined(OS_WIN)
TEST_F(ClipboardTest, UniodeHTMLTest) {
- string16 markup(UTF8ToUTF16("<div>A \xc3\xb8 \xe6\xb0\xb4</div>")),
+ base::string16 markup(UTF8ToUTF16("<div>A \xc3\xb8 \xe6\xb0\xb4</div>")),
markup_result;
std::string url, url_result;
@@ -225,31 +256,10 @@ TEST_F(ClipboardTest, UniodeHTMLTest) {
}
#endif // defined(OS_WIN)
-#if defined(TOOLKIT_GTK)
-// Regression test for crbug.com/56298 (pasting empty HTML crashes Linux).
-TEST_F(ClipboardTest, EmptyHTMLTest) {
- // ScopedClipboardWriter doesn't let us write empty data to the clipboard.
- clipboard().clipboard_data_ = new Clipboard::TargetMap();
- // The 1 is so the compiler doesn't warn about allocating an empty array.
- char* empty = new char[1];
- clipboard().InsertMapping("text/html", empty, 0U);
- clipboard().SetGtkClipboard(CLIPBOARD_TYPE_COPY_PASTE);
-
- EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
- CLIPBOARD_TYPE_COPY_PASTE));
- string16 markup_result;
- std::string url_result;
- uint32 ignored;
- clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, &url_result,
- &ignored, &ignored);
- EXPECT_PRED2(MarkupMatches, string16(), markup_result);
-}
-#endif
-
// TODO(estade): Port the following test (decide what target we use for urls)
#if !defined(OS_POSIX) || defined(OS_MACOSX)
TEST_F(ClipboardTest, BookmarkTest) {
- string16 title(ASCIIToUTF16("The Example Company")), title_result;
+ base::string16 title(ASCIIToUTF16("The Example Company")), title_result;
std::string url("http://www.example.com/"), url_result;
{
@@ -267,8 +277,8 @@ TEST_F(ClipboardTest, BookmarkTest) {
#endif // defined(OS_WIN)
TEST_F(ClipboardTest, MultiFormatTest) {
- string16 text(ASCIIToUTF16("Hi!")), text_result;
- string16 markup(ASCIIToUTF16("<strong>Hi!</string>")), markup_result;
+ base::string16 text(ASCIIToUTF16("Hi!")), text_result;
+ base::string16 markup(ASCIIToUTF16("<strong>Hi!</string>")), markup_result;
std::string url("http://www.example.com/"), url_result;
std::string ascii_text;
@@ -301,7 +311,7 @@ TEST_F(ClipboardTest, MultiFormatTest) {
}
TEST_F(ClipboardTest, URLTest) {
- string16 url(ASCIIToUTF16("http://www.google.com/"));
+ base::string16 url(ASCIIToUTF16("http://www.google.com/"));
{
ScopedClipboardWriter clipboard_writer(&clipboard(),
@@ -313,7 +323,7 @@ TEST_F(ClipboardTest, URLTest) {
Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetPlainTextFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
- string16 text_result;
+ base::string16 text_result;
clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
EXPECT_EQ(text_result, url);
@@ -329,6 +339,9 @@ TEST_F(ClipboardTest, URLTest) {
#endif
}
+// TODO(dcheng): The tests for copying to the clipboard also test IPC
+// interaction... consider moving them to a different layer so we can
+// consolidate the validation logic.
// Note that |bitmap_data| is not premultiplied!
static void TestBitmapWrite(Clipboard* clipboard,
const uint32* bitmap_data,
@@ -370,7 +383,7 @@ static void TestBitmapWrite(Clipboard* clipboard,
ASSERT_TRUE(Clipboard::ReplaceSharedMemHandle(
&objects, handle_to_share, current_process));
- clipboard->WriteObjects(CLIPBOARD_TYPE_COPY_PASTE, objects);
+ ClipboardTest::WriteObjectsToClipboard(clipboard, objects);
EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
@@ -382,19 +395,8 @@ static void TestBitmapWrite(Clipboard* clipboard,
for (int i = 0; i < image.width(); ++i) {
int offset = i + j * image.width();
uint32 pixel = SkPreMultiplyColor(bitmap_data[offset]);
-#if defined(TOOLKIT_GTK)
- // Non-Aura GTK doesn't support alpha transparency. Instead, the alpha
- // channel is always set to 0xFF - see http://crbug.com/154573.
- // However, since we premultiplied above, we must also premultiply here
- // before unpremultiplying and setting alpha to 0xFF; otherwise, the
- // results will not match GTK's.
- EXPECT_EQ(
- SkUnPreMultiply::PMColorToColor(pixel) | 0xFF000000, row_address[i])
- << "i = " << i << ", j = " << j;
-#else
EXPECT_EQ(pixel, row_address[i])
<< "i = " << i << ", j = " << j;
-#endif // defined(TOOLKIT_GTK)
}
}
}
@@ -455,7 +457,7 @@ TEST_F(ClipboardTest, SharedBitmapWithTwoNegativeSizes) {
Clipboard::ObjectMap objects;
objects[Clipboard::CBF_SMBITMAP] = params;
- clipboard().WriteObjects(CLIPBOARD_TYPE_COPY_PASTE, objects);
+ WriteObjectsToClipboard(objects);
EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
}
@@ -478,7 +480,7 @@ TEST_F(ClipboardTest, SharedBitmapWithOneNegativeSize) {
Clipboard::ObjectMap objects;
objects[Clipboard::CBF_SMBITMAP] = params;
- clipboard().WriteObjects(CLIPBOARD_TYPE_COPY_PASTE, objects);
+ WriteObjectsToClipboard(objects);
EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
}
@@ -503,7 +505,7 @@ TEST_F(ClipboardTest, BitmapWithSuperSize) {
Clipboard::ObjectMap objects;
objects[Clipboard::CBF_SMBITMAP] = params;
- clipboard().WriteObjects(CLIPBOARD_TYPE_COPY_PASTE, objects);
+ WriteObjectsToClipboard(objects);
EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
}
@@ -527,7 +529,7 @@ TEST_F(ClipboardTest, BitmapWithSuperSize2) {
Clipboard::ObjectMap objects;
objects[Clipboard::CBF_SMBITMAP] = params;
- clipboard().WriteObjects(CLIPBOARD_TYPE_COPY_PASTE, objects);
+ WriteObjectsToClipboard(objects);
EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
}
@@ -625,7 +627,7 @@ TEST_F(ClipboardTest, HyperlinkTest) {
"The &lt;Example&gt; Company&#39;s &quot;home page&quot;</a>");
std::string url_result;
- string16 html_result;
+ base::string16 html_result;
{
ScopedClipboardWriter clipboard_writer(&clipboard(),
CLIPBOARD_TYPE_COPY_PASTE);
@@ -712,6 +714,34 @@ TEST_F(ClipboardTest, WriteEverything) {
// Passes if we don't crash.
}
+// TODO(dcheng): Fix this test for Android. It's rather involved, since the
+// clipboard change listener is posted to the Java message loop, and spinning
+// that loop from C++ to trigger the callback in the test requires a non-trivial
+// amount of additional work.
+#if !defined(OS_ANDROID)
+// Simple test that the sequence number appears to change when the clipboard is
+// written to.
+// TODO(dcheng): Add a version to test CLIPBOARD_TYPE_SELECTION.
+TEST_F(ClipboardTest, GetSequenceNumber) {
+ const uint64 first_sequence_number =
+ clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE);
+
+ {
+ ScopedClipboardWriter writer(&clipboard(), CLIPBOARD_TYPE_COPY_PASTE);
+ writer.WriteText(UTF8ToUTF16("World"));
+ }
+
+ // On some platforms, the sequence number is updated by a UI callback so pump
+ // the message loop to make sure we get the notification.
+ base::RunLoop().RunUntilIdle();
+
+ const uint64 second_sequence_number =
+ clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE);
+
+ EXPECT_NE(first_sequence_number, second_sequence_number);
+}
+#endif
+
#if defined(OS_ANDROID)
// Test that if another application writes some text to the pasteboard the
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.cc b/chromium/ui/base/clipboard/clipboard_util_win.cc
index b1bf562756a..aa61e6a43d6 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_util_win.cc
@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/memory/scoped_handle.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -34,7 +33,9 @@ bool GetData(IDataObject* data_object,
return SUCCEEDED(data_object->GetData(&format_etc, medium));
}
-bool GetUrlFromHDrop(IDataObject* data_object, string16* url, string16* title) {
+bool GetUrlFromHDrop(IDataObject* data_object,
+ base::string16* url,
+ base::string16* title) {
DCHECK(data_object && url && title);
STGMEDIUM medium;
@@ -67,22 +68,22 @@ bool GetUrlFromHDrop(IDataObject* data_object, string16* url, string16* title) {
return success;
}
-void SplitUrlAndTitle(const string16& str,
- string16* url,
- string16* title) {
+void SplitUrlAndTitle(const base::string16& str,
+ base::string16* url,
+ base::string16* title) {
DCHECK(url && title);
size_t newline_pos = str.find('\n');
- if (newline_pos != string16::npos) {
+ if (newline_pos != base::string16::npos) {
url->assign(str, 0, newline_pos);
- title->assign(str, newline_pos + 1, string16::npos);
+ title->assign(str, newline_pos + 1, base::string16::npos);
} else {
url->assign(str);
title->assign(str);
}
}
-bool GetFileUrl(IDataObject* data_object, string16* url,
- string16* title) {
+bool GetFileUrl(IDataObject* data_object, base::string16* url,
+ base::string16* title) {
STGMEDIUM store;
if (GetData(data_object, Clipboard::GetFilenameWFormatType(), &store)) {
bool success = false;
@@ -117,7 +118,7 @@ bool GetFileUrl(IDataObject* data_object, string16* url,
DWORD file_url_len = arraysize(file_url);
if (SUCCEEDED(::UrlCreateFromPathA(data.get(), file_url, &file_url_len,
0))) {
- url->assign(UTF8ToWide(file_url));
+ url->assign(base::UTF8ToWide(file_url));
title->assign(*url);
success = true;
}
@@ -132,13 +133,14 @@ bool GetFileUrl(IDataObject* data_object, string16* url,
} // namespace
-bool ClipboardUtil::HasUrl(IDataObject* data_object) {
+bool ClipboardUtil::HasUrl(IDataObject* data_object, bool convert_filenames) {
DCHECK(data_object);
return HasData(data_object, Clipboard::GetMozUrlFormatType()) ||
HasData(data_object, Clipboard::GetUrlWFormatType()) ||
HasData(data_object, Clipboard::GetUrlFormatType()) ||
- HasData(data_object, Clipboard::GetFilenameWFormatType()) ||
- HasData(data_object, Clipboard::GetFilenameFormatType());
+ (convert_filenames && (
+ HasData(data_object, Clipboard::GetFilenameWFormatType()) ||
+ HasData(data_object, Clipboard::GetFilenameFormatType())));
}
bool ClipboardUtil::HasFilenames(IDataObject* data_object) {
@@ -164,9 +166,9 @@ bool ClipboardUtil::HasPlainText(IDataObject* data_object) {
}
bool ClipboardUtil::GetUrl(IDataObject* data_object,
- string16* url, string16* title, bool convert_filenames) {
+ base::string16* url, base::string16* title, bool convert_filenames) {
DCHECK(data_object && url && title);
- if (!HasUrl(data_object))
+ if (!HasUrl(data_object, convert_filenames))
return false;
// Try to extract a URL from |data_object| in a variety of formats.
@@ -189,7 +191,7 @@ bool ClipboardUtil::GetUrl(IDataObject* data_object,
{
// URL using ascii
base::win::ScopedHGlobal<char> data(store.hGlobal);
- SplitUrlAndTitle(UTF8ToWide(data.get()), url, title);
+ SplitUrlAndTitle(base::UTF8ToWide(data.get()), url, title);
}
ReleaseStgMedium(&store);
return true;
@@ -203,7 +205,7 @@ bool ClipboardUtil::GetUrl(IDataObject* data_object,
}
bool ClipboardUtil::GetFilenames(IDataObject* data_object,
- std::vector<string16>* filenames) {
+ std::vector<base::string16>* filenames) {
DCHECK(data_object && filenames);
if (!HasFilenames(data_object))
return false;
@@ -233,7 +235,7 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
}
bool ClipboardUtil::GetPlainText(IDataObject* data_object,
- string16* plain_text) {
+ base::string16* plain_text) {
DCHECK(data_object && plain_text);
if (!HasPlainText(data_object))
return false;
@@ -253,7 +255,7 @@ bool ClipboardUtil::GetPlainText(IDataObject* data_object,
{
// ascii text
base::win::ScopedHGlobal<char> data(store.hGlobal);
- plain_text->assign(UTF8ToWide(data.get()));
+ plain_text->assign(base::UTF8ToWide(data.get()));
}
ReleaseStgMedium(&store);
return true;
@@ -261,12 +263,12 @@ bool ClipboardUtil::GetPlainText(IDataObject* data_object,
// If a file is dropped on the window, it does not provide either of the
// plain text formats, so here we try to forcibly get a url.
- string16 title;
+ base::string16 title;
return GetUrl(data_object, plain_text, &title, false);
}
bool ClipboardUtil::GetHtml(IDataObject* data_object,
- string16* html, std::string* base_url) {
+ base::string16* html, std::string* base_url) {
DCHECK(data_object && html && base_url);
STGMEDIUM store;
@@ -278,7 +280,7 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
std::string html_utf8;
CFHtmlToHtml(std::string(data.get(), data.Size()), &html_utf8, base_url);
- html->assign(UTF8ToWide(html_utf8));
+ html->assign(base::UTF8ToWide(html_utf8));
}
ReleaseStgMedium(&store);
return true;
@@ -300,7 +302,7 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
}
bool ClipboardUtil::GetFileContents(IDataObject* data_object,
- string16* filename, std::string* file_contents) {
+ base::string16* filename, std::string* file_contents) {
DCHECK(data_object && filename && file_contents);
if (!HasData(data_object, Clipboard::GetFileContentZeroFormatType()) &&
!HasData(data_object, Clipboard::GetFileDescriptorFormatType()))
@@ -334,7 +336,8 @@ bool ClipboardUtil::GetFileContents(IDataObject* data_object,
}
bool ClipboardUtil::GetWebCustomData(
- IDataObject* data_object, std::map<string16, string16>* custom_data) {
+ IDataObject* data_object,
+ std::map<base::string16, base::string16>* custom_data) {
DCHECK(data_object && custom_data);
if (!HasData(data_object, Clipboard::GetWebCustomDataFormatType()))
@@ -452,7 +455,7 @@ void ClipboardUtil::CFHtmlToHtml(const std::string& cf_html,
fragment_start != std::string::npos &&
fragment_end != std::string::npos) {
*html = cf_html.substr(fragment_start, fragment_end - fragment_start);
- TrimWhitespace(*html, TRIM_ALL, html);
+ base::TrimWhitespace(*html, base::TRIM_ALL, html);
}
}
@@ -470,7 +473,7 @@ void ClipboardUtil::CFHtmlExtractMetadata(const std::string& cf_html,
size_t src_start = line_start + src_url_str.length();
if (src_end != std::string::npos && src_start != std::string::npos) {
*base_url = cf_html.substr(src_start, src_end - src_start);
- TrimWhitespace(*base_url, TRIM_ALL, base_url);
+ base::TrimWhitespace(*base_url, base::TRIM_ALL, base_url);
}
}
}
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.h b/chromium/ui/base/clipboard/clipboard_util_win.h
index f55853dd327..12e668f079e 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.h
+++ b/chromium/ui/base/clipboard/clipboard_util_win.h
@@ -13,16 +13,16 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
-class UI_EXPORT ClipboardUtil {
+class UI_BASE_EXPORT ClipboardUtil {
public:
/////////////////////////////////////////////////////////////////////////////
// These methods check to see if |data_object| has the requested type.
// Returns true if it does.
- static bool HasUrl(IDataObject* data_object);
+ static bool HasUrl(IDataObject* data_object, bool convert_filenames);
static bool HasFilenames(IDataObject* data_object);
static bool HasPlainText(IDataObject* data_object);
static bool HasFileContents(IDataObject* data_object);
@@ -32,24 +32,26 @@ class UI_EXPORT ClipboardUtil {
// Helper methods to extract information from an IDataObject. These methods
// return true if the requested data type is found in |data_object|.
static bool GetUrl(IDataObject* data_object,
- string16* url,
- string16* title,
+ base::string16* url,
+ base::string16* title,
bool convert_filenames);
static bool GetFilenames(IDataObject* data_object,
- std::vector<string16>* filenames);
- static bool GetPlainText(IDataObject* data_object, string16* plain_text);
+ std::vector<base::string16>* filenames);
+ static bool GetPlainText(IDataObject* data_object,
+ base::string16* plain_text);
static bool GetHtml(IDataObject* data_object,
- string16* text_html,
+ base::string16* text_html,
std::string* base_url);
static bool GetFileContents(IDataObject* data_object,
- string16* filename,
+ base::string16* filename,
std::string* file_contents);
// This represents custom MIME types a web page might set to transport its
// own types of data for drag and drop. It is sandboxed in its own CLIPFORMAT
// to avoid polluting the ::RegisterClipboardFormat() namespace with random
// strings from web content.
- static bool GetWebCustomData(IDataObject* data_object,
- std::map<string16, string16>* custom_data);
+ static bool GetWebCustomData(
+ IDataObject* data_object,
+ std::map<base::string16, base::string16>* custom_data);
// Helper method for converting between MS CF_HTML format and plain
// text/html.
diff --git a/chromium/ui/base/clipboard/clipboard_win.cc b/chromium/ui/base/clipboard/clipboard_win.cc
index 24875aae013..36d042d7abc 100644
--- a/chromium/ui/base/clipboard/clipboard_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_win.cc
@@ -7,8 +7,8 @@
#include "ui/base/clipboard/clipboard.h"
-#include <shlobj.h>
#include <shellapi.h>
+#include <shlobj.h>
#include "base/basictypes.h"
#include "base/bind.h"
@@ -16,7 +16,7 @@
#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
-#include "base/safe_numerics.h"
+#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -208,7 +208,7 @@ bool Clipboard::FormatType::Equals(const FormatType& other) const {
}
Clipboard::Clipboard() {
- if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI)
+ if (base::MessageLoopForUI::IsCurrent())
clipboard_owner_.reset(new base::win::MessageWindow());
}
@@ -231,8 +231,8 @@ void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
}
void Clipboard::WriteText(const char* text_data, size_t text_len) {
- string16 text;
- UTF8ToUTF16(text_data, text_len, &text);
+ base::string16 text;
+ base::UTF8ToUTF16(text_data, text_len, &text);
HGLOBAL glob = CreateGlobalData(text);
WriteToClipboard(CF_UNICODETEXT, glob);
@@ -266,7 +266,7 @@ void Clipboard::WriteBookmark(const char* title_data,
bookmark.append(1, L'\n');
bookmark.append(url_data, url_len);
- string16 wide_bookmark = UTF8ToWide(bookmark);
+ base::string16 wide_bookmark = base::UTF8ToWide(bookmark);
HGLOBAL glob = CreateGlobalData(wide_bookmark);
WriteToClipboard(GetUrlWFormatType().ToUINT(), glob);
@@ -399,7 +399,7 @@ void Clipboard::Clear(ClipboardType type) {
}
void Clipboard::ReadAvailableTypes(ClipboardType type,
- std::vector<string16>* types,
+ std::vector<base::string16>* types,
bool* contains_filenames) const {
if (!types || !contains_filenames) {
NOTREACHED();
@@ -408,13 +408,13 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
types->clear();
if (::IsClipboardFormatAvailable(GetPlainTextFormatType().ToUINT()))
- types->push_back(UTF8ToUTF16(kMimeTypeText));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeText));
if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToUINT()))
- types->push_back(UTF8ToUTF16(kMimeTypeHTML));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
if (::IsClipboardFormatAvailable(GetRtfFormatType().ToUINT()))
- types->push_back(UTF8ToUTF16(kMimeTypeRTF));
+ types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
if (::IsClipboardFormatAvailable(CF_DIB))
- types->push_back(UTF8ToUTF16(kMimeTypePNG));
+ types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
*contains_filenames = false;
// Acquire the clipboard.
@@ -430,7 +430,7 @@ void Clipboard::ReadAvailableTypes(ClipboardType type,
::GlobalUnlock(hdata);
}
-void Clipboard::ReadText(ClipboardType type, string16* result) const {
+void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
if (!result) {
NOTREACHED();
@@ -448,7 +448,7 @@ void Clipboard::ReadText(ClipboardType type, string16* result) const {
if (!data)
return;
- result->assign(static_cast<const char16*>(::GlobalLock(data)));
+ result->assign(static_cast<const base::char16*>(::GlobalLock(data)));
::GlobalUnlock(data);
}
@@ -475,7 +475,7 @@ void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
}
void Clipboard::ReadHTML(ClipboardType type,
- string16* markup,
+ base::string16* markup,
std::string* src_url,
uint32* fragment_start,
uint32* fragment_end) const {
@@ -522,8 +522,8 @@ void Clipboard::ReadHTML(ClipboardType type,
offsets.push_back(end_index - html_start);
markup->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html.data() + html_start,
&offsets));
- *fragment_start = base::checked_numeric_cast<uint32>(offsets[0]);
- *fragment_end = base::checked_numeric_cast<uint32>(offsets[1]);
+ *fragment_start = base::checked_cast<uint32>(offsets[0]);
+ *fragment_end = base::checked_cast<uint32>(offsets[1]);
}
void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
@@ -603,8 +603,8 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const {
}
void Clipboard::ReadCustomData(ClipboardType clipboard_type,
- const string16& type,
- string16* result) const {
+ const base::string16& type,
+ base::string16* result) const {
DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE);
// Acquire the clipboard.
@@ -620,7 +620,7 @@ void Clipboard::ReadCustomData(ClipboardType clipboard_type,
::GlobalUnlock(hdata);
}
-void Clipboard::ReadBookmark(string16* title, std::string* url) const {
+void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
if (title)
title->clear();
@@ -636,7 +636,7 @@ void Clipboard::ReadBookmark(string16* title, std::string* url) const {
if (!data)
return;
- string16 bookmark(static_cast<const char16*>(::GlobalLock(data)));
+ base::string16 bookmark(static_cast<const base::char16*>(::GlobalLock(data)));
::GlobalUnlock(data);
ParseBookmarkClipboardFormat(bookmark, title, url);
@@ -662,10 +662,10 @@ void Clipboard::ReadData(const FormatType& format, std::string* result) const {
}
// static
-void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark,
- string16* title,
+void Clipboard::ParseBookmarkClipboardFormat(const base::string16& bookmark,
+ base::string16* title,
std::string* url) {
- const string16 kDelim = ASCIIToUTF16("\r\n");
+ const base::string16 kDelim = base::ASCIIToUTF16("\r\n");
const size_t title_end = bookmark.find_first_of(kDelim);
if (title)
@@ -673,8 +673,10 @@ void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark,
if (url) {
const size_t url_start = bookmark.find_first_not_of(kDelim, title_end);
- if (url_start != string16::npos)
- *url = UTF16ToUTF8(bookmark.substr(url_start, string16::npos));
+ if (url_start != base::string16::npos) {
+ *url = base::UTF16ToUTF8(
+ bookmark.substr(url_start, base::string16::npos));
+ }
}
}
@@ -682,7 +684,7 @@ void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark,
Clipboard::FormatType Clipboard::GetFormatType(
const std::string& format_string) {
return FormatType(
- ::RegisterClipboardFormat(ASCIIToWide(format_string).c_str()));
+ ::RegisterClipboardFormat(base::ASCIIToWide(format_string).c_str()));
}
// static
diff --git a/chromium/ui/base/clipboard/custom_data_helper.cc b/chromium/ui/base/clipboard/custom_data_helper.cc
index f0b3aa30846..a6ac8d2b107 100644
--- a/chromium/ui/base/clipboard/custom_data_helper.cc
+++ b/chromium/ui/base/clipboard/custom_data_helper.cc
@@ -4,7 +4,7 @@
//
// TODO(dcheng): For efficiency reasons, consider passing custom data around
// as a vector instead. It allows us to append a
-// std::pair<string16, string16> and swap the deserialized values in.
+// std::pair<base::string16, base::string16> and swap the deserialized values.
#include "ui/base/clipboard/custom_data_helper.h"
diff --git a/chromium/ui/base/clipboard/custom_data_helper.h b/chromium/ui/base/clipboard/custom_data_helper.h
index 55e7dce3829..8c927aaecc5 100644
--- a/chromium/ui/base/clipboard/custom_data_helper.h
+++ b/chromium/ui/base/clipboard/custom_data_helper.h
@@ -14,7 +14,7 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class Pickle;
@@ -28,25 +28,25 @@ class NSString;
namespace ui {
-#if defined(OS_MACOSX)
-UI_EXPORT extern NSString* const kWebCustomDataPboardType;
-#elif (!defined(OS_WIN) && defined(USE_AURA)) || defined(TOOLKIT_GTK)
-UI_EXPORT extern const char kMimeTypeWebCustomData[];
+#if defined(OS_MACOSX) && !defined(USE_AURA)
+UI_BASE_EXPORT extern NSString* const kWebCustomDataPboardType;
+#elif !defined(OS_WIN) && defined(USE_AURA)
+UI_BASE_EXPORT extern const char kMimeTypeWebCustomData[];
#endif
-UI_EXPORT void ReadCustomDataTypes(const void* data,
- size_t data_length,
- std::vector<base::string16>* types);
-UI_EXPORT void ReadCustomDataForType(const void* data,
- size_t data_length,
- const base::string16& type,
- base::string16* result);
-UI_EXPORT void ReadCustomDataIntoMap(
+UI_BASE_EXPORT void ReadCustomDataTypes(const void* data,
+ size_t data_length,
+ std::vector<base::string16>* types);
+UI_BASE_EXPORT void ReadCustomDataForType(const void* data,
+ size_t data_length,
+ const base::string16& type,
+ base::string16* result);
+UI_BASE_EXPORT void ReadCustomDataIntoMap(
const void* data,
size_t data_length,
std::map<base::string16, base::string16>* result);
-UI_EXPORT void WriteCustomDataToPickle(
+UI_BASE_EXPORT void WriteCustomDataToPickle(
const std::map<base::string16, base::string16>& data,
Pickle* pickle);
diff --git a/chromium/ui/base/clipboard/custom_data_helper_linux.cc b/chromium/ui/base/clipboard/custom_data_helper_linux.cc
index 87ebd394b86..d8cc89edff5 100644
--- a/chromium/ui/base/clipboard/custom_data_helper_linux.cc
+++ b/chromium/ui/base/clipboard/custom_data_helper_linux.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "build/build_config.h"
#include "ui/base/clipboard/custom_data_helper.h"
namespace ui {
diff --git a/chromium/ui/base/clipboard/custom_data_helper_mac.mm b/chromium/ui/base/clipboard/custom_data_helper_mac.mm
index 5447ae30347..ae4362194f8 100644
--- a/chromium/ui/base/clipboard/custom_data_helper_mac.mm
+++ b/chromium/ui/base/clipboard/custom_data_helper_mac.mm
@@ -9,6 +9,10 @@
namespace ui {
// TODO(dcheng): This name is temporary. See crbug.com/106449.
+#if defined(USE_AURA)
+const char kMimeTypeWebCustomData[] = "chromium/x-web-custom-data";
+#else
NSString* const kWebCustomDataPboardType = @"org.chromium.web-custom-data";
+#endif
} // namespace ui
diff --git a/chromium/ui/base/clipboard/custom_data_helper_unittest.cc b/chromium/ui/base/clipboard/custom_data_helper_unittest.cc
index 3183b2bd25d..bc79d907513 100644
--- a/chromium/ui/base/clipboard/custom_data_helper_unittest.cc
+++ b/chromium/ui/base/clipboard/custom_data_helper_unittest.cc
@@ -10,18 +10,20 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::ASCIIToUTF16;
+
namespace ui {
namespace {
void PrepareEmptyTestData(Pickle* pickle) {
- std::map<string16, string16> data;
+ std::map<base::string16, base::string16> data;
WriteCustomDataToPickle(data, pickle);
}
void PrepareTestData(Pickle* pickle) {
- std::map<string16, string16> data;
- data.insert(std::make_pair(ASCIIToUTF16("abc"), string16()));
+ std::map<base::string16, base::string16> data;
+ data.insert(std::make_pair(ASCIIToUTF16("abc"), base::string16()));
data.insert(std::make_pair(ASCIIToUTF16("de"), ASCIIToUTF16("1")));
data.insert(std::make_pair(ASCIIToUTF16("f"), ASCIIToUTF16("23")));
WriteCustomDataToPickle(data, pickle);
@@ -31,7 +33,7 @@ TEST(CustomDataHelperTest, EmptyReadTypes) {
Pickle pickle;
PrepareEmptyTestData(&pickle);
- std::vector<string16> types;
+ std::vector<base::string16> types;
ReadCustomDataTypes(pickle.data(), pickle.size(), &types);
EXPECT_EQ(0u, types.size());
}
@@ -40,19 +42,19 @@ TEST(CustomDataHelperTest, EmptyReadSingleType) {
Pickle pickle;
PrepareEmptyTestData(&pickle);
- string16 result;
+ base::string16 result;
ReadCustomDataForType(pickle.data(),
pickle.size(),
ASCIIToUTF16("f"),
&result);
- EXPECT_EQ(string16(), result);
+ EXPECT_EQ(base::string16(), result);
}
TEST(CustomDataHelperTest, EmptyReadMap) {
Pickle pickle;
PrepareEmptyTestData(&pickle);
- std::map<string16, string16> result;
+ std::map<base::string16, base::string16> result;
ReadCustomDataIntoMap(pickle.data(), pickle.size(), &result);
EXPECT_EQ(0u, result.size());
}
@@ -61,10 +63,10 @@ TEST(CustomDataHelperTest, ReadTypes) {
Pickle pickle;
PrepareTestData(&pickle);
- std::vector<string16> types;
+ std::vector<base::string16> types;
ReadCustomDataTypes(pickle.data(), pickle.size(), &types);
- std::vector<string16> expected;
+ std::vector<base::string16> expected;
expected.push_back(ASCIIToUTF16("abc"));
expected.push_back(ASCIIToUTF16("de"));
expected.push_back(ASCIIToUTF16("f"));
@@ -75,12 +77,12 @@ TEST(CustomDataHelperTest, ReadSingleType) {
Pickle pickle;
PrepareTestData(&pickle);
- string16 result;
+ base::string16 result;
ReadCustomDataForType(pickle.data(),
pickle.size(),
ASCIIToUTF16("abc"),
&result);
- EXPECT_EQ(string16(), result);
+ EXPECT_EQ(base::string16(), result);
ReadCustomDataForType(pickle.data(),
pickle.size(),
@@ -99,11 +101,11 @@ TEST(CustomDataHelperTest, ReadMap) {
Pickle pickle;
PrepareTestData(&pickle);
- std::map<string16, string16> result;
+ std::map<base::string16, base::string16> result;
ReadCustomDataIntoMap(pickle.data(), pickle.size(), &result);
- std::map<string16, string16> expected;
- expected.insert(std::make_pair(ASCIIToUTF16("abc"), string16()));
+ std::map<base::string16, base::string16> expected;
+ expected.insert(std::make_pair(ASCIIToUTF16("abc"), base::string16()));
expected.insert(std::make_pair(ASCIIToUTF16("de"), ASCIIToUTF16("1")));
expected.insert(std::make_pair(ASCIIToUTF16("f"), ASCIIToUTF16("23")));
EXPECT_EQ(expected, result);
@@ -112,7 +114,7 @@ TEST(CustomDataHelperTest, ReadMap) {
TEST(CustomDataHelperTest, BadReadTypes) {
// ReadCustomDataTypes makes the additional guarantee that the contents of the
// result vector will not change if the input is malformed.
- std::vector<string16> expected;
+ std::vector<base::string16> expected;
expected.push_back(ASCIIToUTF16("abc"));
expected.push_back(ASCIIToUTF16("de"));
expected.push_back(ASCIIToUTF16("f"));
@@ -121,21 +123,21 @@ TEST(CustomDataHelperTest, BadReadTypes) {
malformed.WriteUInt64(1000);
malformed.WriteString16(ASCIIToUTF16("hello"));
malformed.WriteString16(ASCIIToUTF16("world"));
- std::vector<string16> actual(expected);
+ std::vector<base::string16> actual(expected);
ReadCustomDataTypes(malformed.data(), malformed.size(), &actual);
EXPECT_EQ(expected, actual);
Pickle malformed2;
malformed2.WriteUInt64(1);
malformed2.WriteString16(ASCIIToUTF16("hello"));
- std::vector<string16> actual2(expected);
+ std::vector<base::string16> actual2(expected);
ReadCustomDataTypes(malformed2.data(), malformed2.size(), &actual2);
EXPECT_EQ(expected, actual2);
}
TEST(CustomDataHelperTest, BadPickle) {
- string16 result_data;
- std::map<string16, string16> result_map;
+ base::string16 result_data;
+ std::map<base::string16, base::string16> result_map;
Pickle malformed;
malformed.WriteUInt64(1000);
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
index 120832f4a4f..380b8d2fb84 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -36,7 +36,7 @@ void ScopedClipboardWriter::WriteURL(const base::string16& text) {
void ScopedClipboardWriter::WriteHTML(const base::string16& markup,
const std::string& source_url) {
- std::string utf8_markup = UTF16ToUTF8(markup);
+ std::string utf8_markup = base::UTF16ToUTF8(markup);
Clipboard::ObjectMapParams parameters;
parameters.push_back(
@@ -62,7 +62,7 @@ void ScopedClipboardWriter::WriteBookmark(const base::string16& bookmark_title,
if (bookmark_title.empty() || url.empty())
return;
- std::string utf8_markup = UTF16ToUTF8(bookmark_title);
+ std::string utf8_markup = base::UTF16ToUTF8(bookmark_title);
Clipboard::ObjectMapParams parameters;
parameters.push_back(Clipboard::ObjectMapParam(utf8_markup.begin(),
@@ -80,9 +80,9 @@ void ScopedClipboardWriter::WriteHyperlink(const base::string16& anchor_text,
std::string html("<a href=\"");
html.append(net::EscapeForHTML(url));
html.append("\">");
- html.append(net::EscapeForHTML(UTF16ToUTF8(anchor_text)));
+ html.append(net::EscapeForHTML(base::UTF16ToUTF8(anchor_text)));
html.append("</a>");
- WriteHTML(UTF8ToUTF16(html), std::string());
+ WriteHTML(base::UTF8ToUTF16(html), std::string());
}
void ScopedClipboardWriter::WriteWebSmartPaste() {
@@ -113,7 +113,7 @@ void ScopedClipboardWriter::Reset() {
void ScopedClipboardWriter::WriteTextOrURL(const base::string16& text,
bool is_url) {
- std::string utf8_text = UTF16ToUTF8(text);
+ std::string utf8_text = base::UTF16ToUTF8(text);
Clipboard::ObjectMapParams parameters;
parameters.push_back(Clipboard::ObjectMapParam(utf8_text.begin(),
diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.h b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
index 8c7bb1a668b..504d2e3c13e 100644
--- a/chromium/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.h
@@ -15,7 +15,7 @@
#include "base/strings/string16.h"
#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class Pickle;
@@ -25,7 +25,7 @@ namespace ui {
// into a Clipboard::ObjectMap.
// NB: You should probably NOT be using this class if you include
// webkit_glue.h. Use ScopedClipboardWriterGlue instead.
-class UI_EXPORT ScopedClipboardWriter {
+class UI_BASE_EXPORT ScopedClipboardWriter {
public:
// Create an instance that is a simple wrapper around clipboard.
ScopedClipboardWriter(Clipboard* clipboard, ClipboardType type);
diff --git a/chromium/ui/base/cocoa/appkit_utils.h b/chromium/ui/base/cocoa/appkit_utils.h
index 159921bd136..18f1fdfa368 100644
--- a/chromium/ui/base/cocoa/appkit_utils.h
+++ b/chromium/ui/base/cocoa/appkit_utils.h
@@ -7,7 +7,7 @@
#import <Cocoa/Cocoa.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -23,12 +23,17 @@ struct NinePartImageIds {
int bottom_right;
};
+// A macro to define arrays of IDR constants used with DrawNinePartImage.
+#define IMAGE_GRID(x) { x ## _TOP_LEFT, x ## _TOP, x ## _TOP_RIGHT, \
+ x ## _LEFT, x ## _CENTER, x ## _RIGHT, \
+ x ## _BOTTOM_LEFT, x ## _BOTTOM, x ## _BOTTOM_RIGHT, }
+
// Utility method to draw a nine part image using image ids.
-UI_EXPORT void DrawNinePartImage(NSRect frame,
- const NinePartImageIds& image_ids,
- NSCompositingOperation operation,
- CGFloat alpha,
- BOOL flipped);
+UI_BASE_EXPORT void DrawNinePartImage(NSRect frame,
+ const NinePartImageIds& image_ids,
+ NSCompositingOperation operation,
+ CGFloat alpha,
+ BOOL flipped);
} // namespace ui
diff --git a/chromium/ui/base/cocoa/base_view.h b/chromium/ui/base/cocoa/base_view.h
index 60f0c39d30d..ac7bba42175 100644
--- a/chromium/ui/base/cocoa/base_view.h
+++ b/chromium/ui/base/cocoa/base_view.h
@@ -9,14 +9,14 @@
#include "base/mac/scoped_nsobject.h"
#import "ui/base/cocoa/tracking_area.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/rect.h"
// A view that provides common functionality that many views will need:
// - Automatic registration for mouse-moved events.
// - Funneling of mouse and key events to two methods
// - Coordinate conversion utilities
-UI_EXPORT
+UI_BASE_EXPORT
@interface BaseView : NSView {
@public
enum EventHandled {
@@ -47,7 +47,7 @@ UI_EXPORT
// The name is |kViewDidBecomeFirstResponder|, the object is the view, and the
// NSSelectionDirection is wrapped in an NSNumber under the key
// |kSelectionDirection|.
-UI_EXPORT extern NSString* kViewDidBecomeFirstResponder;
-UI_EXPORT extern NSString* kSelectionDirection;
+UI_BASE_EXPORT extern NSString* kViewDidBecomeFirstResponder;
+UI_BASE_EXPORT extern NSString* kSelectionDirection;
#endif // UI_BASE_COCOA_BASE_VIEW_H_
diff --git a/chromium/ui/base/cocoa/base_view_unittest.mm b/chromium/ui/base/cocoa/base_view_unittest.mm
index f9b06904e03..ceb1c656a90 100644
--- a/chromium/ui/base/cocoa/base_view_unittest.mm
+++ b/chromium/ui/base/cocoa/base_view_unittest.mm
@@ -8,7 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "ui/base/cocoa/base_view.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace {
diff --git a/chromium/ui/base/cocoa/cocoa_base_utils.h b/chromium/ui/base/cocoa/cocoa_base_utils.h
new file mode 100644
index 00000000000..c479f72f2a5
--- /dev/null
+++ b/chromium/ui/base/cocoa/cocoa_base_utils.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_COCOA_COCOA_BASE_UTILS_H_
+#define UI_BASE_COCOA_COCOA_BASE_UTILS_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "ui/base/ui_base_export.h"
+#include "ui/base/window_open_disposition.h"
+
+namespace ui {
+
+// Retrieves the WindowOpenDisposition used to open a link from a user gesture
+// represented by |event|. For example, a Cmd+Click would mean open the
+// associated link in a background tab.
+UI_BASE_EXPORT WindowOpenDisposition
+ WindowOpenDispositionFromNSEvent(NSEvent* event);
+
+// Retrieves the WindowOpenDisposition used to open a link from a user gesture
+// represented by |event|, but instead use the modifier flags given by |flags|,
+// which is the same format as |-NSEvent modifierFlags|. This allows
+// substitution of the modifiers without having to create a new event from
+// scratch.
+UI_BASE_EXPORT WindowOpenDisposition
+ WindowOpenDispositionFromNSEventWithFlags(NSEvent* event, NSUInteger flags);
+
+} // namespace ui
+
+#endif // UI_BASE_COCOA_COCOA_BASE_UTILS_H_
diff --git a/chromium/ui/base/cocoa/cocoa_base_utils.mm b/chromium/ui/base/cocoa/cocoa_base_utils.mm
new file mode 100644
index 00000000000..0830f3488a8
--- /dev/null
+++ b/chromium/ui/base/cocoa/cocoa_base_utils.mm
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cocoa/cocoa_base_utils.h"
+
+#include "ui/events/cocoa/cocoa_event_utils.h"
+
+namespace ui {
+
+WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event) {
+ NSUInteger modifiers = [event modifierFlags];
+ return WindowOpenDispositionFromNSEventWithFlags(event, modifiers);
+}
+
+WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
+ NSEvent* event, NSUInteger modifiers) {
+ int event_flags = EventFlagsFromNSEventWithModifiers(event, modifiers);
+ return DispositionFromEventFlags(event_flags);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/cocoa_base_utils_unittest.mm b/chromium/ui/base/cocoa/cocoa_base_utils_unittest.mm
new file mode 100644
index 00000000000..5749e2d176c
--- /dev/null
+++ b/chromium/ui/base/cocoa/cocoa_base_utils_unittest.mm
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cocoa/cocoa_base_utils.h"
+
+#import <objc/objc-class.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "ui/events/event_constants.h"
+#import "ui/events/test/cocoa_test_event_utils.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
+
+// We provide a donor class with a specially modified |modifierFlags|
+// implementation that we swap with NSEvent's. This is because we can't create a
+// NSEvent that represents a middle click with modifiers.
+@interface TestEvent : NSObject
+@end
+@implementation TestEvent
+- (NSUInteger)modifierFlags { return NSShiftKeyMask; }
+@end
+
+namespace ui {
+
+namespace {
+
+class CocoaBaseUtilsTest : public CocoaTest {
+};
+
+TEST_F(CocoaBaseUtilsTest, WindowOpenDispositionFromNSEvent) {
+ // Left Click = same tab.
+ NSEvent* me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
+ EXPECT_EQ(CURRENT_TAB, WindowOpenDispositionFromNSEvent(me));
+
+ // Middle Click = new background tab.
+ me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0);
+ EXPECT_EQ(NEW_BACKGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
+
+ // Shift+Middle Click = new foreground tab.
+ {
+ ScopedClassSwizzler swizzler([NSEvent class], [TestEvent class],
+ @selector(modifierFlags));
+ me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp,
+ NSShiftKeyMask);
+ EXPECT_EQ(NEW_FOREGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
+ }
+
+ // Cmd+Left Click = new background tab.
+ me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSCommandKeyMask);
+ EXPECT_EQ(NEW_BACKGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
+
+ // Cmd+Shift+Left Click = new foreground tab.
+ me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSCommandKeyMask |
+ NSShiftKeyMask);
+ EXPECT_EQ(NEW_FOREGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
+
+ // Shift+Left Click = new window
+ me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSShiftKeyMask);
+ EXPECT_EQ(NEW_WINDOW, WindowOpenDispositionFromNSEvent(me));
+}
+
+} // namespace
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/cocoa_event_utils.h b/chromium/ui/base/cocoa/cocoa_event_utils.h
deleted file mode 100644
index 1432f2dd6bd..00000000000
--- a/chromium/ui/base/cocoa/cocoa_event_utils.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_COCOA_COCOA_EVENT_UTILS_H_
-#define UI_BASE_COCOA_COCOA_EVENT_UTILS_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "ui/base/ui_export.h"
-#include "ui/base/window_open_disposition.h"
-
-namespace ui {
-
-// Retrieves a bitsum of ui::EventFlags represented by |event|,
-UI_EXPORT int EventFlagsFromNSEvent(NSEvent* event);
-
-// Retrieves a bitsum of ui::EventFlags represented by |event|,
-// but instead use the modifier flags given by |modifiers|,
-// which is the same format as |-NSEvent modifierFlags|. This allows
-// substitution of the modifiers without having to create a new event from
-// scratch.
-UI_EXPORT int EventFlagsFromNSEventWithModifiers(NSEvent* event,
- NSUInteger modifiers);
-
-// Retrieves the WindowOpenDisposition used to open a link from a user gesture
-// represented by |event|. For example, a Cmd+Click would mean open the
-// associated link in a background tab.
-UI_EXPORT WindowOpenDisposition WindowOpenDispositionFromNSEvent(
- NSEvent* event);
-
-// Retrieves the WindowOpenDisposition used to open a link from a user gesture
-// represented by |event|, but instead use the modifier flags given by |flags|,
-// which is the same format as |-NSEvent modifierFlags|. This allows
-// substitution of the modifiers without having to create a new event from
-// scratch.
-UI_EXPORT WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
- NSEvent* event, NSUInteger flags);
-
-} // namespace ui
-
-#endif // UI_BASE_COCOA_COCOA_EVENT_UTILS_H_
diff --git a/chromium/ui/base/cocoa/cocoa_event_utils.mm b/chromium/ui/base/cocoa/cocoa_event_utils.mm
deleted file mode 100644
index a8fd8c38a1c..00000000000
--- a/chromium/ui/base/cocoa/cocoa_event_utils.mm
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/base/cocoa/cocoa_event_utils.h"
-
-#include "ui/events/event_constants.h"
-#include "ui/base/window_open_disposition.h"
-
-namespace {
-
-bool isLeftButtonEvent(NSEvent* event) {
- NSEventType type = [event type];
- return type == NSLeftMouseDown ||
- type == NSLeftMouseDragged ||
- type == NSLeftMouseUp;
-}
-
-bool isRightButtonEvent(NSEvent* event) {
- NSEventType type = [event type];
- return type == NSRightMouseDown ||
- type == NSRightMouseDragged ||
- type == NSRightMouseUp;
-}
-
-bool isMiddleButtonEvent(NSEvent* event) {
- if ([event buttonNumber] != 2)
- return false;
-
- NSEventType type = [event type];
- return type == NSOtherMouseDown ||
- type == NSOtherMouseDragged ||
- type == NSOtherMouseUp;
-}
-
-} // namespace
-
-namespace ui {
-
-// Retrieves a bitsum of ui::EventFlags from NSEvent.
-int EventFlagsFromNSEvent(NSEvent* event) {
- NSUInteger modifiers = [event modifierFlags];
- return EventFlagsFromNSEventWithModifiers(event, modifiers);
-}
-
-int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
- int flags = 0;
- flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
- flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
- flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
- flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
- flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
- flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
- flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
- flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
- return flags;
-}
-
-WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event) {
- NSUInteger modifiers = [event modifierFlags];
- return WindowOpenDispositionFromNSEventWithFlags(event, modifiers);
-}
-
-WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
- NSEvent* event, NSUInteger modifiers) {
- int event_flags = EventFlagsFromNSEventWithModifiers(event, modifiers);
- return ui::DispositionFromEventFlags(event_flags);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cocoa/cocoa_event_utils_unittest.mm b/chromium/ui/base/cocoa/cocoa_event_utils_unittest.mm
deleted file mode 100644
index 5ec3936fdcb..00000000000
--- a/chromium/ui/base/cocoa/cocoa_event_utils_unittest.mm
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <objc/objc-class.h>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "ui/base/cocoa/cocoa_event_utils.h"
-#include "ui/events/event_constants.h"
-#import "ui/base/test/cocoa_test_event_utils.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-
-// We provide a donor class with a specially modified |modifierFlags|
-// implementation that we swap with NSEvent's. This is because we can't create a
-// NSEvent that represents a middle click with modifiers.
-@interface TestEvent : NSObject
-@end
-@implementation TestEvent
-- (NSUInteger)modifierFlags { return NSShiftKeyMask; }
-@end
-
-namespace ui {
-
-namespace {
-
-class EventUtilsTest : public CocoaTest {
-};
-
-TEST_F(EventUtilsTest, TestWindowOpenDispositionFromNSEvent) {
- // Left Click = same tab.
- NSEvent* me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
- EXPECT_EQ(CURRENT_TAB, WindowOpenDispositionFromNSEvent(me));
-
- // Middle Click = new background tab.
- me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0);
- EXPECT_EQ(NEW_BACKGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
-
- // Shift+Middle Click = new foreground tab.
- {
- ScopedClassSwizzler swizzler([NSEvent class], [TestEvent class],
- @selector(modifierFlags));
- me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp,
- NSShiftKeyMask);
- EXPECT_EQ(NEW_FOREGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
- }
-
- // Cmd+Left Click = new background tab.
- me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSCommandKeyMask);
- EXPECT_EQ(NEW_BACKGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
-
- // Cmd+Shift+Left Click = new foreground tab.
- me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSCommandKeyMask |
- NSShiftKeyMask);
- EXPECT_EQ(NEW_FOREGROUND_TAB, WindowOpenDispositionFromNSEvent(me));
-
- // Shift+Left Click = new window
- me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSShiftKeyMask);
- EXPECT_EQ(NEW_WINDOW, WindowOpenDispositionFromNSEvent(me));
-}
-
-
-TEST_F(EventUtilsTest, TestEventFlagsFromNSEvent) {
- // Left click.
- NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNSEvent(left));
-
- // Right click.
- NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp,
- 0);
- EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNSEvent(right));
-
- // Middle click.
- NSEvent* middle = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp,
- 0);
- EXPECT_EQ(EF_MIDDLE_MOUSE_BUTTON, EventFlagsFromNSEvent(middle));
-
- // Caps + Left
- NSEvent* caps =
- cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSAlphaShiftKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CAPS_LOCK_DOWN,
- EventFlagsFromNSEvent(caps));
-
- // Shift + Left
- NSEvent* shift = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSShiftKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN, EventFlagsFromNSEvent(shift));
-
- // Ctrl + Left
- NSEvent* ctrl = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSControlKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CONTROL_DOWN,
- EventFlagsFromNSEvent(ctrl));
-
- // Alt + Left
- NSEvent* alt = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSAlternateKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_ALT_DOWN, EventFlagsFromNSEvent(alt));
-
- // Cmd + Left
- NSEvent* cmd = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSCommandKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN, EventFlagsFromNSEvent(cmd));
-
- // Shift + Ctrl + Left
- NSEvent* shiftctrl =
- cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSShiftKeyMask |
- NSControlKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN,
- EventFlagsFromNSEvent(shiftctrl));
-
- // Cmd + Alt + Right
- NSEvent* cmdalt =
- cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
- NSCommandKeyMask |
- NSAlternateKeyMask);
- EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN,
- EventFlagsFromNSEvent(cmdalt));
-}
-
-} // namespace
-
-} // namespace ui
diff --git a/chromium/ui/base/cocoa/controls/blue_label_button.h b/chromium/ui/base/cocoa/controls/blue_label_button.h
index a8d66dbf989..d6d38ec1110 100644
--- a/chromium/ui/base/cocoa/controls/blue_label_button.h
+++ b/chromium/ui/base/cocoa/controls/blue_label_button.h
@@ -8,12 +8,12 @@
#import <Cocoa/Cocoa.h>
#import "ui/base/cocoa/hover_button.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A rectangular blue NSButton that reacts to hover, focus and lit states. It
// can contain an arbitrary single-line text label, and will be sized to fit the
// font height and label width.
-UI_EXPORT
+UI_BASE_EXPORT
@interface BlueLabelButton : HoverButton
@end
diff --git a/chromium/ui/base/cocoa/controls/blue_label_button.mm b/chromium/ui/base/cocoa/controls/blue_label_button.mm
index 495b60d6812..fad0a013bda 100644
--- a/chromium/ui/base/cocoa/controls/blue_label_button.mm
+++ b/chromium/ui/base/cocoa/controls/blue_label_button.mm
@@ -12,9 +12,8 @@
const CGFloat kCornerRadius = 2;
-const CGFloat kButtonFontSizeDelta = -1;
-const CGFloat kTopBottomTextPadding = 8;
-const CGFloat kLeftRightTextPadding = 16;
+const CGFloat kTopBottomTextPadding = 7;
+const CGFloat kLeftRightTextPadding = 15;
const SkColor kTextShadowColor = SkColorSetRGB(0x53, 0x8c, 0xea);
const SkColor kShadowColor = SkColorSetRGB(0xe9, 0xe9, 0xe9);
@@ -54,16 +53,22 @@ const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
+ (NSAttributedString*)generateAttributedString:(NSString*)buttonText {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- NSFont* buttonFont = rb.GetFont(ui::ResourceBundle::BaseFont).
- DeriveFont(kButtonFontSizeDelta).GetNativeFont();
+ NSFont* buttonFont = rb.GetFontList(ui::ResourceBundle::SmallFont).
+ GetPrimaryFont().GetNativeFont();
base::scoped_nsobject<NSMutableParagraphStyle> buttonTextParagraphStyle(
[[NSMutableParagraphStyle alloc] init]);
[buttonTextParagraphStyle setAlignment:NSCenterTextAlignment];
+ base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow setShadowOffset:NSMakeSize(0, -1)];
+ [shadow setShadowBlurRadius:0];
+ [shadow setShadowColor:gfx::SkColorToSRGBNSColor(kTextShadowColor)];
+
NSDictionary* buttonTextAttributes = @{
NSParagraphStyleAttributeName : buttonTextParagraphStyle,
NSFontAttributeName : buttonFont,
- NSForegroundColorAttributeName : [NSColor whiteColor]
+ NSForegroundColorAttributeName : [NSColor whiteColor],
+ NSShadowAttributeName : shadow.get()
};
base::scoped_nsobject<NSAttributedString> attributedButtonText(
[[NSAttributedString alloc] initWithString:buttonText
@@ -75,7 +80,9 @@ const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
NSAttributedString* attributedTitle =
[[self class] generateAttributedString:[self title]];
NSSize textSize = [attributedTitle size];
- textSize.height += 2 * kTopBottomTextPadding;
+
+ // Add 1 to maintain identical height w/ previous drawing code.
+ textSize.height += 2 * kTopBottomTextPadding + 1;
textSize.width += 2 * kLeftRightTextPadding;
return textSize;
}
@@ -83,15 +90,12 @@ const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
- (NSRect)drawTitle:(NSAttributedString*)title
withFrame:(NSRect)frame
inView:(NSView*)controlView {
+ // Fuzz factor to adjust for the drop shadow. Based on visual inspection.
+ frame.origin.y -= 1;
+
NSAttributedString* attributedTitle =
[[self class] generateAttributedString:[self title]];
- // Draw the text with a drop shadow.
- base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
gfx::ScopedNSGraphicsContextSaveGState context;
- [shadow setShadowOffset:NSMakeSize(0, -1)];
- [shadow setShadowBlurRadius:0];
- [shadow setShadowColor:gfx::SkColorToSRGBNSColor(kTextShadowColor)];
- [shadow set];
[attributedTitle drawInRect:frame];
return frame;
}
@@ -103,6 +107,8 @@ const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
NSColor* outerColor;
HoverState hoverState =
[base::mac::ObjCCastStrict<HoverButton>(controlView) hoverState];
+ // Leave a sliver of height 1 for the button drop shadow.
+ frame.size.height -= 1;
if (hoverState == kHoverStateMouseDown && [self isHighlighted]) {
centerColor = gfx::SkColorToSRGBNSColor(kPressedColor);
@@ -126,18 +132,17 @@ const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
[shadow set];
[outerColor set];
- // Inset by 1 initially for the button drop shadow.
- [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1, 1)
+ [[NSBezierPath bezierPathWithRoundedRect:frame
xRadius:kCornerRadius
yRadius:kCornerRadius] fill];
}
[innerColor set];
- [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2, 2)
+ [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1, 1)
xRadius:kCornerRadius
yRadius:kCornerRadius] fill];
[centerColor set];
- [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 3, 3)
+ [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2, 2)
xRadius:kCornerRadius
yRadius:kCornerRadius] fill];
}
diff --git a/chromium/ui/base/cocoa/controls/blue_label_button_unittest.mm b/chromium/ui/base/cocoa/controls/blue_label_button_unittest.mm
index 48342e87e98..1e2a8f8c135 100644
--- a/chromium/ui/base/cocoa/controls/blue_label_button_unittest.mm
+++ b/chromium/ui/base/cocoa/controls/blue_label_button_unittest.mm
@@ -6,7 +6,7 @@
#include "base/mac/scoped_nsobject.h"
#import "testing/gtest_mac.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace ui {
namespace test {
diff --git a/chromium/ui/base/cocoa/controls/hover_image_menu_button.h b/chromium/ui/base/cocoa/controls/hover_image_menu_button.h
index f6af7bf894c..86914192e02 100644
--- a/chromium/ui/base/cocoa/controls/hover_image_menu_button.h
+++ b/chromium/ui/base/cocoa/controls/hover_image_menu_button.h
@@ -8,7 +8,7 @@
#import <Cocoa/Cocoa.h>
#import "ui/base/cocoa/tracking_area.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
@class HoverImageMenuButtonCell;
@@ -16,7 +16,7 @@
// [[self cell] setHovered:flag] when the hover state changes. Uses
// HoverImageMenuButtonCell as the default cellClass. Note that the menu item at
// index 0 is ignored and client code should populate it with a dummy item.
-UI_EXPORT
+UI_BASE_EXPORT
@interface HoverImageMenuButton : NSPopUpButton {
@private
ui::ScopedCrTrackingArea trackingArea_;
diff --git a/chromium/ui/base/cocoa/controls/hover_image_menu_button_cell.h b/chromium/ui/base/cocoa/controls/hover_image_menu_button_cell.h
index fad48fe2e53..249a74d78e4 100644
--- a/chromium/ui/base/cocoa/controls/hover_image_menu_button_cell.h
+++ b/chromium/ui/base/cocoa/controls/hover_image_menu_button_cell.h
@@ -8,13 +8,13 @@
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A custom NSPopUpButtonCell that permits a hover image, and draws only an
// image in its frame; no border, bezel or drop-down arrow. Use setDefaultImage:
// to set the default image, setAlternateImage: to set the button shown while
// the menu is active, and setHoverImage: for the mouseover hover image.
-UI_EXPORT
+UI_BASE_EXPORT
@interface HoverImageMenuButtonCell : NSPopUpButtonCell {
@private
base::scoped_nsobject<NSImage> hoverImage_;
diff --git a/chromium/ui/base/cocoa/controls/hover_image_menu_button_unittest.mm b/chromium/ui/base/cocoa/controls/hover_image_menu_button_unittest.mm
index bf64f403636..ad5b2da7470 100644
--- a/chromium/ui/base/cocoa/controls/hover_image_menu_button_unittest.mm
+++ b/chromium/ui/base/cocoa/controls/hover_image_menu_button_unittest.mm
@@ -7,7 +7,7 @@
#include "base/mac/foundation_util.h"
#import "testing/gtest_mac.h"
#import "ui/base/cocoa/controls/hover_image_menu_button_cell.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace ui {
diff --git a/chromium/ui/base/cocoa/controls/hyperlink_button_cell.h b/chromium/ui/base/cocoa/controls/hyperlink_button_cell.h
index 944f0ed4407..6e3b74d437b 100644
--- a/chromium/ui/base/cocoa/controls/hyperlink_button_cell.h
+++ b/chromium/ui/base/cocoa/controls/hyperlink_button_cell.h
@@ -8,7 +8,7 @@
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A HyperlinkButtonCell is used to create an NSButton that looks and acts
// like a hyperlink. The default styling is to look like blue, underlined text
@@ -23,7 +23,7 @@
//
// Use this if all of your text is a link. If you need text that contains
// embedded links but also regular text, use HyperlinkTextView.
-UI_EXPORT
+UI_BASE_EXPORT
@interface HyperlinkButtonCell : NSButtonCell {
base::scoped_nsobject<NSColor> textColor_;
BOOL shouldUnderline_;
diff --git a/chromium/ui/base/cocoa/controls/hyperlink_button_cell_unittest.mm b/chromium/ui/base/cocoa/controls/hyperlink_button_cell_unittest.mm
index 3d24f01fa90..3e7c6110110 100644
--- a/chromium/ui/base/cocoa/controls/hyperlink_button_cell_unittest.mm
+++ b/chromium/ui/base/cocoa/controls/hyperlink_button_cell_unittest.mm
@@ -8,10 +8,10 @@
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
-#import "testing/gtest_mac.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
#include "testing/platform_test.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace ui {
diff --git a/chromium/ui/base/cocoa/events_mac_unittest.mm b/chromium/ui/base/cocoa/events_mac_unittest.mm
deleted file mode 100644
index 63f5319067e..00000000000
--- a/chromium/ui/base/cocoa/events_mac_unittest.mm
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Cocoa/Cocoa.h>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/event_utils.h"
-#include "ui/base/test/cocoa_test_event_utils.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
-#include "ui/gfx/point.h"
-
-using namespace cocoa_test_event_utils;
-
-namespace {
-
-class EventsMacTest : public ui::CocoaTest {
- public:
- EventsMacTest() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EventsMacTest);
-};
-
-TEST_F(EventsMacTest, EventTypeFromNative) {
- NSEvent* native_event = nil;
- ui::EventType type = ui::ET_UNKNOWN;
-
- native_event = MouseEventWithType(NSLeftMouseDown, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, type);
-
- native_event = MouseEventWithType(NSLeftMouseUp, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, type);
-
- native_event = MouseEventWithType(NSRightMouseDown, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, type);
-
- native_event = MouseEventWithType(NSRightMouseUp, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, type);
-
- native_event = MouseEventWithType(NSMouseMoved, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_MOVED, type);
-
- native_event = MouseEventWithType(NSLeftMouseDragged, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type);
-
- native_event = MouseEventWithType(NSRightMouseDragged, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type);
-
- native_event = EnterExitEventWithType(NSMouseEntered);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_ENTERED, type);
-
- native_event = EnterExitEventWithType(NSMouseExited);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_EXITED, type);
-
- native_event = KeyEventWithType(NSKeyDown, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_KEY_PRESSED, type);
-
- native_event = KeyEventWithType(NSKeyUp, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_KEY_RELEASED, type);
-
- native_event = KeyEventWithType(NSFlagsChanged, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_KEY_PRESSED, type);
-
- native_event = OtherEventWithType(NSAppKitDefined);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_UNKNOWN, type);
-
- native_event = OtherEventWithType(NSSystemDefined);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_UNKNOWN, type);
-
- native_event = OtherEventWithType(NSApplicationDefined);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_UNKNOWN, type);
-
- native_event = OtherEventWithType(NSPeriodic);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_UNKNOWN, type);
-
- native_event = EnterExitEventWithType(NSCursorUpdate);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_UNKNOWN, type);
-
- native_event = MouseEventWithType(NSOtherMouseDown, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, type);
-
- native_event = MouseEventWithType(NSOtherMouseUp, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, type);
-
- native_event = MouseEventWithType(NSOtherMouseDragged, 0);
- type = ui::EventTypeFromNative(native_event);
- EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type);
-}
-
-TEST_F(EventsMacTest, EventFlagsFromNative) {
- NSEvent* native_event = nil;
- int flags = 0;
-
- // No key flags.
- native_event = KeyEventWithType(NSKeyDown, 0);
- flags = ui::EventFlagsFromNative(native_event);
- EXPECT_EQ(0, flags);
-
- // All key flags.
- native_event = KeyEventWithType(NSKeyDown,
- NSAlphaShiftKeyMask |
- NSShiftKeyMask |
- NSControlKeyMask |
- NSAlternateKeyMask |
- NSCommandKeyMask);
- flags = ui::EventFlagsFromNative(native_event);
- EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN |
- ui::EF_SHIFT_DOWN |
- ui::EF_CONTROL_DOWN |
- ui::EF_ALT_DOWN |
- ui::EF_COMMAND_DOWN,
- flags);
-
- // Left mouse flags.
- native_event = MouseEventWithType(NSLeftMouseDown, 0);
- flags = ui::EventFlagsFromNative(native_event);
- EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, flags);
-
- // Right mouse flags.
- native_event = MouseEventWithType(NSRightMouseDown, 0);
- flags = ui::EventFlagsFromNative(native_event);
- EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, flags);
-
- // Center mouse flags.
- native_event = MouseEventWithType(NSOtherMouseDown, 0);
- flags = ui::EventFlagsFromNative(native_event);
- EXPECT_EQ(ui::EF_MIDDLE_MOUSE_BUTTON, flags);
-}
-
-TEST_F(EventsMacTest, EventLocationFromNative) {
- NSWindow* window = [[NSWindow alloc]
- initWithContentRect:NSMakeRect(10, 25, 200, 205)
- styleMask:NSTitledWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
- [window orderFront:nil];
-
- // Construct mouse event from window number having position at bottom-left.
- // Cocoa origin is at bottom-left. ui::Event origin is top-left.
- NSEvent* native_event =
- [NSEvent mouseEventWithType:NSLeftMouseDown
- location:NSMakePoint(10, 15)
- modifierFlags:0
- timestamp:[NSDate timeIntervalSinceReferenceDate]
- windowNumber:[window windowNumber]
- context:[window graphicsContext]
- eventNumber:0
- clickCount:1
- pressure:0.0f];
-
- // Expect resulting event to be positioned relative to top-left.
- gfx::Point location = ui::EventLocationFromNative(native_event);
- EXPECT_EQ(gfx::Point(10, 190), location);
-
- [window orderOut:nil];
- [window close];
-}
-
-TEST_F(EventsMacTest, KeyboardCodeFromNative) {
- NSEvent* native_event = nil;
- ui::KeyboardCode code = ui::VKEY_UNKNOWN;
-
- // Simple "x". No modifiers.
- native_event =
- [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:0
- timestamp:[NSDate timeIntervalSinceReferenceDate]
- windowNumber:0
- context:nil
- characters:@"x"
- charactersIgnoringModifiers:@"x"
- isARepeat:NO
- keyCode:0x58];
- code = ui::KeyboardCodeFromNative(native_event);
- EXPECT_EQ(ui::VKEY_X, code);
-
- // Option/Alt "x".
- native_event =
- [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:NSAlternateKeyMask
- timestamp:[NSDate timeIntervalSinceReferenceDate]
- windowNumber:0
- context:nil
- characters:@"\0x2248" // opt-x
- charactersIgnoringModifiers:@"x"
- isARepeat:NO
- keyCode:0x58];
- code = ui::KeyboardCodeFromNative(native_event);
- EXPECT_EQ(ui::VKEY_X, code);
-
- // Option/Alt (alone).
- native_event =
- [NSEvent keyEventWithType:NSFlagsChanged
- location:NSZeroPoint
- modifierFlags:NSAlternateKeyMask
- timestamp:[NSDate timeIntervalSinceReferenceDate]
- windowNumber:0
- context:nil
- characters:@""
- charactersIgnoringModifiers:@""
- isARepeat:NO
- keyCode:0x3a];
- code = ui::KeyboardCodeFromNative(native_event);
- EXPECT_EQ(ui::VKEY_MENU, code);
-}
-
-TEST_F(EventsMacTest, IsMouseEvent) {
- NSEvent* native_event = nil;
-
- native_event = MouseEventWithType(NSLeftMouseDown, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSLeftMouseUp, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSRightMouseDown, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSRightMouseUp, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSMouseMoved, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSLeftMouseDragged, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSRightMouseDragged, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = EnterExitEventWithType(NSMouseEntered);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = EnterExitEventWithType(NSMouseExited);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = KeyEventWithType(NSKeyDown, 0);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = KeyEventWithType(NSKeyUp, 0);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = KeyEventWithType(NSFlagsChanged, 0);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = OtherEventWithType(NSAppKitDefined);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = OtherEventWithType(NSSystemDefined);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = OtherEventWithType(NSApplicationDefined);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = OtherEventWithType(NSPeriodic);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = EnterExitEventWithType(NSCursorUpdate);
- EXPECT_FALSE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSOtherMouseDown, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSOtherMouseUp, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-
- native_event = MouseEventWithType(NSOtherMouseDragged, 0);
- EXPECT_TRUE(ui::IsMouseEvent(native_event));
-}
-
-TEST_F(EventsMacTest, CreateNoopEvent) {
- NSEvent* native_event = ui::CreateNoopEvent();
- EXPECT_TRUE(native_event != nil);
-}
-
-} // namespace
diff --git a/chromium/ui/base/cocoa/find_pasteboard.h b/chromium/ui/base/cocoa/find_pasteboard.h
index aada8a792bb..863b398a9ce 100644
--- a/chromium/ui/base/cocoa/find_pasteboard.h
+++ b/chromium/ui/base/cocoa/find_pasteboard.h
@@ -12,9 +12,9 @@
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
-UI_EXPORT extern NSString* kFindPasteboardChangedNotification;
+UI_BASE_EXPORT extern NSString* kFindPasteboardChangedNotification;
// Manages the find pasteboard. Use this to copy text to the find pasteboard,
// to get the text currently on the find pasteboard, and to receive
@@ -25,7 +25,7 @@ UI_EXPORT extern NSString* kFindPasteboardChangedNotification;
// This is not thread-safe and must be used on the main thread.
//
// This is supposed to be a singleton.
-UI_EXPORT
+UI_BASE_EXPORT
@interface FindPasteboard : NSObject {
@private
base::scoped_nsobject<NSString> findText_;
@@ -54,6 +54,6 @@ UI_EXPORT
#endif // __OBJC__
// Also provide a c++ interface
-UI_EXPORT string16 GetFindPboardText();
+UI_BASE_EXPORT base::string16 GetFindPboardText();
#endif // UI_BASE_COCOA_FIND_PASTEBOARD_H_
diff --git a/chromium/ui/base/cocoa/find_pasteboard.mm b/chromium/ui/base/cocoa/find_pasteboard.mm
index a74fa78a341..536d8ccd767 100644
--- a/chromium/ui/base/cocoa/find_pasteboard.mm
+++ b/chromium/ui/base/cocoa/find_pasteboard.mm
@@ -77,6 +77,6 @@ NSString* kFindPasteboardChangedNotification =
@end
-string16 GetFindPboardText() {
+base::string16 GetFindPboardText() {
return base::SysNSStringToUTF16([[FindPasteboard sharedInstance] findText]);
}
diff --git a/chromium/ui/base/cocoa/flipped_view.h b/chromium/ui/base/cocoa/flipped_view.h
index c05f38c6c0a..7bc117779d8 100644
--- a/chromium/ui/base/cocoa/flipped_view.h
+++ b/chromium/ui/base/cocoa/flipped_view.h
@@ -7,13 +7,13 @@
#import <Cocoa/Cocoa.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A view where the Y axis is flipped such that the origin is at the top left
// and Y value increases downwards. Drawing is flipped so that layout of the
// sections is easier. Apple recommends flipping the coordinate origin when
// doing a lot of text layout because it's more natural.
-UI_EXPORT
+UI_BASE_EXPORT
@interface FlippedView : NSView
@end
diff --git a/chromium/ui/base/cocoa/focus_tracker.h b/chromium/ui/base/cocoa/focus_tracker.h
index 6a0c3baf750..301a48f37fd 100644
--- a/chromium/ui/base/cocoa/focus_tracker.h
+++ b/chromium/ui/base/cocoa/focus_tracker.h
@@ -5,14 +5,14 @@
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A class that handles saving and restoring focus. An instance of
// this class snapshots the currently focused view when it is
// constructed, and callers can use restoreFocus to return focus to
// that view. FocusTracker will not restore focus to views that are
// no longer in the view hierarchy or are not in the correct window.
-UI_EXPORT
+UI_BASE_EXPORT
@interface FocusTracker : NSObject {
@private
base::scoped_nsobject<NSView> focusedView_;
diff --git a/chromium/ui/base/cocoa/focus_tracker_unittest.mm b/chromium/ui/base/cocoa/focus_tracker_unittest.mm
index 0fb70c143fe..4e15f260d27 100644
--- a/chromium/ui/base/cocoa/focus_tracker_unittest.mm
+++ b/chromium/ui/base/cocoa/focus_tracker_unittest.mm
@@ -8,7 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#import "ui/base/cocoa/focus_tracker.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace {
diff --git a/chromium/ui/base/cocoa/focus_window_set.h b/chromium/ui/base/cocoa/focus_window_set.h
index d43ff2acf97..e4b6d9f0471 100644
--- a/chromium/ui/base/cocoa/focus_window_set.h
+++ b/chromium/ui/base/cocoa/focus_window_set.h
@@ -7,7 +7,7 @@
#include <set>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
@@ -15,8 +15,17 @@ namespace ui {
// Brings a group of windows to the front without changing their order, and
// makes the frontmost one key and main. If none are visible, the frontmost
// miniaturized window is deminiaturized.
-UI_EXPORT void FocusWindowSet(const std::set<gfx::NativeWindow>& windows,
- bool allow_workspace_switch);
+UI_BASE_EXPORT void FocusWindowSet(const std::set<gfx::NativeWindow>& windows);
+
+// Brings a group of windows to the front without changing their
+// order, and makes the frontmost one key and main. If none are
+// visible, the frontmost miniaturized window is deminiaturized. This
+// variant is meant to clean up after the system-default Dock icon
+// behavior. Unlike FocusWindowSet, only windows on the current space
+// are considered. It also ignores the hidden state of windows; the
+// window system may be in the middle of unhiding the application.
+UI_BASE_EXPORT void FocusWindowSetOnCurrentSpace(
+ const std::set<gfx::NativeWindow>& windows);
} // namespace ui
diff --git a/chromium/ui/base/cocoa/focus_window_set.mm b/chromium/ui/base/cocoa/focus_window_set.mm
index fb6272730c9..abc5f92c40a 100644
--- a/chromium/ui/base/cocoa/focus_window_set.mm
+++ b/chromium/ui/base/cocoa/focus_window_set.mm
@@ -8,32 +8,14 @@
namespace ui {
+namespace {
+
// This attempts to match OS X's native behavior, namely that a window
// is only ever deminiaturized if ALL windows on ALL workspaces are
-// miniaturized. (This callback runs before AppKit picks its own
-// window to deminiaturize, so we get to pick one from the right set.)
-//
-// In addition, limit to the windows on the current
-// workspace. Otherwise we jump spaces haphazardly.
-//
-// NOTE: If this is called in the
-// applicationShouldHandleReopen:hasVisibleWindows: hook when clicking
-// the dock icon, and that caused OS X to begin switch spaces,
-// isOnActiveSpace gives the answer for the PREVIOUS space. This means
-// that we actually raise and focus the wrong space's windows, leaving
-// the new key window off-screen. To detect this, check if the key
-// window prior to calling is on an active space.
-//
-// Also, if we decide to deminiaturize a window during a space switch,
-// that can switch spaces and then switch back. Fortunately, this only
-// happens if, say, space 1 contains an app, space 2 contains a
-// miniaturized browser. We click the icon, OS X switches to space 1,
-// we deminiaturize the browser, and that triggers switching back.
-//
-// TODO(davidben): To limit those cases, consider preferentially
-// deminiaturizing a window on the current space.
-void FocusWindowSet(const std::set<NSWindow*>& windows,
- bool allow_workspace_switch) {
+// miniaturized.
+void FocusWindowSetHelper(const std::set<NSWindow*>& windows,
+ bool allow_workspace_switch,
+ bool visible_windows_only) {
NSArray* ordered_windows = [NSApp orderedWindows];
NSWindow* frontmost_window = nil;
NSWindow* frontmost_window_all_spaces = nil;
@@ -41,16 +23,16 @@ void FocusWindowSet(const std::set<NSWindow*>& windows,
bool all_miniaturized = true;
for (int i = [ordered_windows count] - 1; i >= 0; i--) {
NSWindow* win = [ordered_windows objectAtIndex:i];
- if (windows.find(win) != windows.end()) {
- if ([win isMiniaturized]) {
- frontmost_miniaturized_window = win;
- } else if ([win isVisible]) {
- all_miniaturized = false;
- frontmost_window_all_spaces = win;
- if ([win isOnActiveSpace]) {
- [win orderFront:nil];
- frontmost_window = win;
- }
+ if (windows.find(win) == windows.end())
+ continue;
+ if ([win isMiniaturized]) {
+ frontmost_miniaturized_window = win;
+ } else if (!visible_windows_only || [win isVisible]) {
+ all_miniaturized = false;
+ frontmost_window_all_spaces = win;
+ if ([win isOnActiveSpace]) {
+ [win orderFront:nil];
+ frontmost_window = win;
}
}
}
@@ -71,4 +53,39 @@ void FocusWindowSet(const std::set<NSWindow*>& windows,
}
}
+} // namespace
+
+void FocusWindowSet(const std::set<NSWindow*>& windows) {
+ FocusWindowSetHelper(windows, true, true);
+}
+
+void FocusWindowSetOnCurrentSpace(const std::set<NSWindow*>& windows) {
+ // This callback runs before AppKit picks its own window to
+ // deminiaturize, so we get to pick one from the right set. Limit to
+ // the windows on the current workspace. Otherwise we jump spaces
+ // haphazardly.
+ //
+ // Also consider both visible and hidden windows; this call races
+ // with the system unhiding the application. http://crbug.com/368238
+ //
+ // NOTE: If this is called in the
+ // applicationShouldHandleReopen:hasVisibleWindows: hook when
+ // clicking the dock icon, and that caused OS X to begin switch
+ // spaces, isOnActiveSpace gives the answer for the PREVIOUS
+ // space. This means that we actually raise and focus the wrong
+ // space's windows, leaving the new key window off-screen. To detect
+ // this, check if the key window is on the active space prior to
+ // calling.
+ //
+ // Also, if we decide to deminiaturize a window during a space switch,
+ // that can switch spaces and then switch back. Fortunately, this only
+ // happens if, say, space 1 contains an app, space 2 contains a
+ // miniaturized browser. We click the icon, OS X switches to space 1,
+ // we deminiaturize the browser, and that triggers switching back.
+ //
+ // TODO(davidben): To limit those cases, consider preferentially
+ // deminiaturizing a window on the current space.
+ FocusWindowSetHelper(windows, false, false);
+}
+
} // namespace ui
diff --git a/chromium/ui/base/cocoa/fullscreen_window_manager.h b/chromium/ui/base/cocoa/fullscreen_window_manager.h
index 1b18912cf6f..be59cad49c3 100644
--- a/chromium/ui/base/cocoa/fullscreen_window_manager.h
+++ b/chromium/ui/base/cocoa/fullscreen_window_manager.h
@@ -9,11 +9,11 @@
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.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_EXPORT
+UI_BASE_EXPORT
@interface FullscreenWindowManager : NSObject {
@private
base::scoped_nsobject<NSWindow> window_;
diff --git a/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm b/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm
index 5f9ff2f511b..c720a26f082 100644
--- a/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm
+++ b/chromium/ui/base/cocoa/fullscreen_window_manager_unittest.mm
@@ -6,7 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
typedef ui::CocoaTest FullscreenWindowManagerTest;
diff --git a/chromium/ui/base/cocoa/hover_button.h b/chromium/ui/base/cocoa/hover_button.h
index 4040c2c29fe..7a0e156660c 100644
--- a/chromium/ui/base/cocoa/hover_button.h
+++ b/chromium/ui/base/cocoa/hover_button.h
@@ -8,10 +8,10 @@
#import <Cocoa/Cocoa.h>
#import "ui/base/cocoa/tracking_area.h"
-#import "ui/base/ui_export.h"
+#import "ui/base/ui_base_export.h"
// A button that changes when you hover over it and click it.
-UI_EXPORT
+UI_BASE_EXPORT
@interface HoverButton : NSButton {
@protected
// Enumeration of the hover states that the close button can be in at any one
diff --git a/chromium/ui/base/cocoa/hover_image_button.h b/chromium/ui/base/cocoa/hover_image_button.h
index d43a7fa78ac..a00163fb53b 100644
--- a/chromium/ui/base/cocoa/hover_image_button.h
+++ b/chromium/ui/base/cocoa/hover_image_button.h
@@ -9,10 +9,10 @@
#import "base/mac/scoped_nsobject.h"
#import "ui/base/cocoa/hover_button.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// A button that changes images when you hover over it and click it.
-UI_EXPORT
+UI_BASE_EXPORT
@interface HoverImageButton : HoverButton {
@private
base::scoped_nsobject<NSImage> defaultImage_;
diff --git a/chromium/ui/base/cocoa/hover_image_button_unittest.mm b/chromium/ui/base/cocoa/hover_image_button_unittest.mm
index cc1cca0fab4..0dff3fc823c 100644
--- a/chromium/ui/base/cocoa/hover_image_button_unittest.mm
+++ b/chromium/ui/base/cocoa/hover_image_button_unittest.mm
@@ -5,7 +5,7 @@
#import "ui/base/cocoa/hover_image_button.h"
#import "base/mac/scoped_nsobject.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace {
diff --git a/chromium/ui/base/cocoa/menu_controller.h b/chromium/ui/base/cocoa/menu_controller.h
index a85640468a6..1da667491a6 100644
--- a/chromium/ui/base/cocoa/menu_controller.h
+++ b/chromium/ui/base/cocoa/menu_controller.h
@@ -9,7 +9,7 @@
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
class MenuModel;
@@ -21,7 +21,7 @@ class MenuModel;
// allow for hierarchical menus). The tag is the index into that model for
// that particular item. It is important that the model outlives this object
// as it only maintains weak references.
-UI_EXPORT
+UI_BASE_EXPORT
@interface MenuController : NSObject<NSMenuDelegate> {
@protected
ui::MenuModel* model_; // weak
@@ -35,8 +35,8 @@ UI_EXPORT
// |-initWithModel:useWithPopUpButtonCell:| or after the first call to |-menu|.
@property(nonatomic) BOOL useWithPopUpButtonCell;
-+ (string16)elideMenuTitle:(const string16&)title
- toWidth:(int)width;
++ (base::string16)elideMenuTitle:(const base::string16&)title
+ toWidth:(int)width;
// NIB-based initializer. This does not create a menu. Clients can set the
// properties of the object and the menu will be created upon the first call to
diff --git a/chromium/ui/base/cocoa/menu_controller.mm b/chromium/ui/base/cocoa/menu_controller.mm
index c7b8dff2fa3..9faa6071e44 100644
--- a/chromium/ui/base/cocoa/menu_controller.mm
+++ b/chromium/ui/base/cocoa/menu_controller.mm
@@ -8,10 +8,10 @@
#include "base/strings/sys_string_conversions.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
-#import "ui/base/cocoa/cocoa_event_utils.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/models/simple_menu_model.h"
-#include "ui/gfx/font.h"
+#import "ui/events/event_utils.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/text_elider.h"
@@ -25,12 +25,11 @@
@synthesize model = model_;
@synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_;
-+ (string16)elideMenuTitle:(const string16&)title
- toWidth:(int)width {
++ (base::string16)elideMenuTitle:(const base::string16&)title
+ toWidth:(int)width {
NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default"
- gfx::Font font(base::SysNSStringToUTF8([nsfont fontName]),
- static_cast<int>([nsfont pointSize]));
- return gfx::ElideText(title, font, width, gfx::ELIDE_AT_END);
+ return gfx::ElideText(title, gfx::FontList(gfx::Font(nsfont)), width,
+ gfx::ELIDE_TAIL);
}
- (id)init {
@@ -102,7 +101,7 @@
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model {
- string16 label16 = model->GetLabelAt(index);
+ base::string16 label16 = model->GetLabelAt(index);
int maxWidth = [self maxWidthForMenuModel:model modelIndex:index];
if (maxWidth != -1)
label16 = [MenuController elideMenuTitle:label16 toWidth:maxWidth];
@@ -180,10 +179,11 @@
model->GetIconAt(modelIndex, &icon);
[(id)item setImage:icon.IsEmpty() ? nil : icon.ToNSImage()];
}
- const gfx::Font* font = model->GetLabelFontAt(modelIndex);
- if (font) {
+ const gfx::FontList* font_list = model->GetLabelFontListAt(modelIndex);
+ if (font_list) {
NSDictionary *attributes =
- [NSDictionary dictionaryWithObject:font->GetNativeFont()
+ [NSDictionary dictionaryWithObject:font_list->GetPrimaryFont().
+ GetNativeFont()
forKey:NSFontAttributeName];
base::scoped_nsobject<NSAttributedString> title(
[[NSAttributedString alloc] initWithString:[(id)item title]
@@ -204,7 +204,7 @@
[[sender representedObject] pointerValue]);
DCHECK(model);
if (model) {
- int event_flags = ui::EventFlagsFromNSEvent([NSApp currentEvent]);
+ int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]);
model->ActivatedAt(modelIndex, event_flags);
}
}
diff --git a/chromium/ui/base/cocoa/menu_controller_unittest.mm b/chromium/ui/base/cocoa/menu_controller_unittest.mm
index 7cec6c6198a..43520ddda20 100644
--- a/chromium/ui/base/cocoa/menu_controller_unittest.mm
+++ b/chromium/ui/base/cocoa/menu_controller_unittest.mm
@@ -13,8 +13,10 @@
#import "ui/base/cocoa/menu_controller.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
#include "ui/gfx/image/image.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
+
+using base::ASCIIToUTF16;
namespace ui {
@@ -87,7 +89,7 @@ class DynamicDelegate : public Delegate {
virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE {
return true;
}
- virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE {
+ virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE {
return label_;
}
virtual bool GetIconForCommandId(
@@ -100,30 +102,31 @@ class DynamicDelegate : public Delegate {
return true;
}
}
- void SetDynamicLabel(string16 label) { label_ = label; }
+ void SetDynamicLabel(base::string16 label) { label_ = label; }
void SetDynamicIcon(const gfx::Image& icon) { icon_ = icon; }
private:
- string16 label_;
+ base::string16 label_;
gfx::Image icon_;
};
-// Menu model that returns a gfx::Font object for one of the items in the menu.
-class FontMenuModel : public SimpleMenuModel {
+// Menu model that returns a gfx::FontList object for one of the items in the
+// menu.
+class FontListMenuModel : public SimpleMenuModel {
public:
- FontMenuModel(SimpleMenuModel::Delegate* delegate,
- const gfx::Font* font, int index)
+ FontListMenuModel(SimpleMenuModel::Delegate* delegate,
+ const gfx::FontList* font_list, int index)
: SimpleMenuModel(delegate),
- font_(font),
+ font_list_(font_list),
index_(index) {
}
- virtual ~FontMenuModel() {}
- virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE {
- return (index == index_) ? font_ : NULL;
+ virtual ~FontListMenuModel() {}
+ virtual const gfx::FontList* GetLabelFontListAt(int index) const OVERRIDE {
+ return (index == index_) ? font_list_ : NULL;
}
private:
- const gfx::Font* font_;
+ const gfx::FontList* font_list_;
const int index_;
};
@@ -222,7 +225,7 @@ TEST_F(MenuControllerTest, PopUpButton) {
[[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:YES]);
EXPECT_EQ([[menu menu] numberOfItems], 4);
EXPECT_EQ(base::SysNSStringToUTF16([[[menu menu] itemAtIndex:0] title]),
- string16());
+ base::string16());
// Make sure the tags are still correct (the index no longer matches the tag).
NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
@@ -270,10 +273,11 @@ TEST_F(MenuControllerTest, Validate) {
}
// Tests that items which have a font set actually use that font.
-TEST_F(MenuControllerTest, LabelFont) {
+TEST_F(MenuControllerTest, LabelFontList) {
Delegate delegate;
- gfx::Font bold = (gfx::Font()).DeriveFont(0, gfx::Font::BOLD);
- FontMenuModel model(&delegate, &bold, 0);
+ const gfx::FontList& bold = ResourceBundle::GetSharedInstance().GetFontList(
+ ResourceBundle::BoldFont);
+ FontListMenuModel model(&delegate, &bold, 0);
model.AddItem(1, ASCIIToUTF16("one"));
model.AddItem(2, ASCIIToUTF16("two"));
@@ -313,7 +317,7 @@ TEST_F(MenuControllerTest, Dynamic) {
// Create a menu containing a single item whose label is "initial" and who has
// no icon.
- string16 initial = ASCIIToUTF16("initial");
+ base::string16 initial = ASCIIToUTF16("initial");
delegate.SetDynamicLabel(initial);
SimpleMenuModel model(&delegate);
model.AddItem(1, ASCIIToUTF16("foo"));
@@ -329,7 +333,7 @@ TEST_F(MenuControllerTest, Dynamic) {
EXPECT_EQ(nil, [item image]);
// Now update the item to have a label of "second" and an icon.
- string16 second = ASCIIToUTF16("second");
+ base::string16 second = ASCIIToUTF16("second");
delegate.SetDynamicLabel(second);
const gfx::Image& icon =
ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER);
@@ -349,7 +353,7 @@ TEST_F(MenuControllerTest, Dynamic) {
TEST_F(MenuControllerTest, OpenClose) {
// SimpleMenuModel posts a task that calls Delegate::MenuClosed. Create
// a MessageLoop for that purpose.
- base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+ base::MessageLoopForUI message_loop;
// Create the model.
Delegate delegate;
diff --git a/chromium/ui/base/cocoa/nib_loading.h b/chromium/ui/base/cocoa/nib_loading.h
index ab8e23f5343..263ac4883b9 100644
--- a/chromium/ui/base/cocoa/nib_loading.h
+++ b/chromium/ui/base/cocoa/nib_loading.h
@@ -7,13 +7,13 @@
#import <Cocoa/Cocoa.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Given the name of a nib file, gets an unowned reference to the NSView in the
// nib. Requires a nib with just a single root view.
-UI_EXPORT NSView* GetViewFromNib(NSString* name);
+UI_BASE_EXPORT NSView* GetViewFromNib(NSString* name);
} // namespace ui
diff --git a/chromium/ui/base/cocoa/nsgraphics_context_additions.mm b/chromium/ui/base/cocoa/nsgraphics_context_additions.mm
index 3f70145c47c..9e85fad24f2 100644
--- a/chromium/ui/base/cocoa/nsgraphics_context_additions.mm
+++ b/chromium/ui/base/cocoa/nsgraphics_context_additions.mm
@@ -8,11 +8,14 @@
- (void)cr_setPatternPhase:(NSPoint)phase
forView:(NSView*)view {
- if ([view layer]) {
+ NSView* ancestorWithLayer = view;
+ while (ancestorWithLayer && ![ancestorWithLayer layer])
+ ancestorWithLayer = [ancestorWithLayer superview];
+ if (ancestorWithLayer) {
NSPoint bottomLeft = NSZeroPoint;
- if ([view isFlipped])
- bottomLeft.y = NSMaxY([view bounds]);
- NSPoint offset = [view convertPoint:bottomLeft toView:nil];
+ if ([ancestorWithLayer isFlipped])
+ bottomLeft.y = NSMaxY([ancestorWithLayer bounds]);
+ NSPoint offset = [ancestorWithLayer convertPoint:bottomLeft toView:nil];
phase.x -= offset.x;
phase.y -= offset.y;
}
diff --git a/chromium/ui/base/cocoa/nsgraphics_context_additions_unittest.mm b/chromium/ui/base/cocoa/nsgraphics_context_additions_unittest.mm
index d4e958e9a99..bfa17611d3d 100644
--- a/chromium/ui/base/cocoa/nsgraphics_context_additions_unittest.mm
+++ b/chromium/ui/base/cocoa/nsgraphics_context_additions_unittest.mm
@@ -5,7 +5,7 @@
#import "ui/base/cocoa/nsgraphics_context_additions.h"
#include "base/mac/scoped_nsobject.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
typedef ui::CocoaTest NSGraphicsContextCrAdditionsTest;
diff --git a/chromium/ui/base/cocoa/tracking_area.h b/chromium/ui/base/cocoa/tracking_area.h
index 782cdaea270..df37686bd97 100644
--- a/chromium/ui/base/cocoa/tracking_area.h
+++ b/chromium/ui/base/cocoa/tracking_area.h
@@ -8,13 +8,13 @@
#import <AppKit/AppKit.h>
#include "base/mac/scoped_nsobject.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
@class CrTrackingAreaOwnerProxy;
// The CrTrackingArea can be used in place of an NSTrackingArea to shut off
// messaging to the |owner| at a specific point in time.
-UI_EXPORT
+UI_BASE_EXPORT
@interface CrTrackingArea : NSTrackingArea {
@private
base::scoped_nsobject<CrTrackingAreaOwnerProxy> ownerProxy_;
@@ -42,7 +42,7 @@ namespace ui {
// Use an instance of this class to call |-clearOwner| on the |tracking_area_|
// when this goes out of scope.
-class UI_EXPORT ScopedCrTrackingArea {
+class UI_BASE_EXPORT ScopedCrTrackingArea {
public:
// Takes ownership of |tracking_area| without retaining it.
explicit ScopedCrTrackingArea(CrTrackingArea* tracking_area = nil);
diff --git a/chromium/ui/base/cocoa/tracking_area_unittest.mm b/chromium/ui/base/cocoa/tracking_area_unittest.mm
index b12c9d49b7e..cb2c82925bc 100644
--- a/chromium/ui/base/cocoa/tracking_area_unittest.mm
+++ b/chromium/ui/base/cocoa/tracking_area_unittest.mm
@@ -4,7 +4,7 @@
#include "base/mac/scoped_nsobject.h"
#import "ui/base/cocoa/tracking_area.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
// A test object that counts the number of times a message is sent to it.
@interface TestTrackingAreaOwner : NSObject {
diff --git a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.h b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.h
index fb9eba4bef7..25c81fd940a 100644
--- a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.h
+++ b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.h
@@ -7,12 +7,12 @@
#import <Cocoa/Cocoa.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// Common base class for windows that host a OpenGL surface that renders under
// the window. Contains methods relating to hole punching so that the OpenGL
// surface is visible through the window.
-UI_EXPORT
+UI_BASE_EXPORT
@interface UnderlayOpenGLHostingWindow : NSWindow
@end
diff --git a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
index 1e562e200b7..39a30360441 100644
--- a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
+++ b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
@@ -6,10 +6,12 @@
#import <objc/runtime.h>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/mac/scoped_nsobject.h"
+#include "ui/base/ui_base_switches.h"
@interface NSWindow (UndocumentedAPI)
// Normally, punching a hole in a window by painting a subview with a
@@ -30,6 +32,12 @@
namespace {
+bool CoreAnimationIsEnabled() {
+ static bool is_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableCoreAnimation);
+ return is_enabled;
+}
+
NSComparisonResult OpaqueViewsOnTop(id view1, id view2, void* context) {
BOOL view_1_is_opaque_view = [view1 isKindOfClass:[OpaqueView class]];
BOOL view_2_is_opaque_view = [view2 isKindOfClass:[OpaqueView class]];
@@ -103,6 +111,14 @@ NSComparisonResult OpaqueViewsOnTop(id view1, id view2, void* context) {
styleMask:windowStyle
backing:bufferingType
defer:deferCreation])) {
+ if (CoreAnimationIsEnabled()) {
+ // If CoreAnimation is used, then the hole punching technique won't be
+ // used. Bail now and don't play any special games with the shadow.
+ // TODO(avi): Rip all this shadow code out once CoreAnimation can't be
+ // turned off. http://crbug.com/336554
+ return self;
+ }
+
// OpenGL-accelerated content works by punching holes in windows. Therefore
// all windows hosting OpenGL content must not be opaque.
[self setOpaque:NO];
diff --git a/chromium/ui/base/cocoa/window_size_constants.h b/chromium/ui/base/cocoa/window_size_constants.h
index 11cf318a515..bb94018fd53 100644
--- a/chromium/ui/base/cocoa/window_size_constants.h
+++ b/chromium/ui/base/cocoa/window_size_constants.h
@@ -5,14 +5,14 @@
#ifndef UI_BASE_COCOA_WINDOW_SIZE_CONSTANTS_H_
#define UI_BASE_COCOA_WINDOW_SIZE_CONSTANTS_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#import <Foundation/Foundation.h>
namespace ui {
// It is not valid to make a zero-sized window. Use this constant instead.
-UI_EXPORT extern const NSRect kWindowSizeDeterminedLater;
+UI_BASE_EXPORT extern const NSRect kWindowSizeDeterminedLater;
} // namespace ui
diff --git a/chromium/ui/base/cursor/DEPS b/chromium/ui/base/cursor/DEPS
new file mode 100644
index 00000000000..de08167e272
--- /dev/null
+++ b/chromium/ui/base/cursor/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/ozone/public",
+]
diff --git a/chromium/ui/base/cursor/cursor.h b/chromium/ui/base/cursor/cursor.h
index bb832fa9631..72999d4c3be 100644
--- a/chromium/ui/base/cursor/cursor.h
+++ b/chromium/ui/base/cursor/cursor.h
@@ -6,7 +6,7 @@
#define UI_BASE_CURSOR_CURSOR_H_
#include "build/build_config.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace gfx {
class Point;
@@ -88,7 +88,7 @@ enum CursorSetType {
};
// Ref-counted cursor that supports both default and custom cursors.
-class UI_EXPORT Cursor {
+class UI_BASE_EXPORT Cursor {
public:
Cursor();
diff --git a/chromium/ui/base/cursor/cursor_android.cc b/chromium/ui/base/cursor/cursor_android.cc
new file mode 100644
index 00000000000..e33d739c2a5
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_android.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/cursor.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+void Cursor::RefCustomCursor() {
+ NOTIMPLEMENTED();
+}
+
+void Cursor::UnrefCustomCursor() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader.h b/chromium/ui/base/cursor/cursor_loader.h
index d54d2989127..d4a0c3d2da0 100644
--- a/chromium/ui/base/cursor/cursor_loader.h
+++ b/chromium/ui/base/cursor/cursor_loader.h
@@ -7,26 +7,24 @@
#include "base/logging.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/display.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/point.h"
namespace ui {
-class UI_EXPORT CursorLoader {
+class UI_BASE_EXPORT CursorLoader {
public:
- CursorLoader() : scale_(1.f) {}
+ CursorLoader() : scale_(1.f), rotation_(gfx::Display::ROTATE_0) {}
virtual ~CursorLoader() {}
- // Returns the display the loader loads images for.
- const gfx::Display& display() const {
- return display_;
+ gfx::Display::Rotation rotation() const {
+ return rotation_;
}
- // Sets the display the loader loads images for.
- void set_display(const gfx::Display& display) {
- display_ = display;
+ void set_rotation(gfx::Display::Rotation rotation) {
+ rotation_ = rotation;
}
// Returns the current scale of the mouse cursor icon.
@@ -64,12 +62,12 @@ class UI_EXPORT CursorLoader {
static CursorLoader* Create();
private:
- // The display the loader loads images for.
- gfx::Display display_;
-
// The current scale of the mouse cursor icon.
float scale_;
+ // The current rotation of the mouse cursor icon.
+ gfx::Display::Rotation rotation_;
+
DISALLOW_COPY_AND_ASSIGN(CursorLoader);
};
diff --git a/chromium/ui/base/cursor/cursor_loader_null.cc b/chromium/ui/base/cursor/cursor_loader_null.cc
deleted file mode 100644
index 51ced4cde37..00000000000
--- a/chromium/ui/base/cursor/cursor_loader_null.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/cursor/cursor_loader_null.h"
-
-namespace ui {
-
-CursorLoader* CursorLoader::Create() {
- return new CursorLoaderNull;
-}
-
-CursorLoaderNull::CursorLoaderNull() {}
-CursorLoaderNull::~CursorLoaderNull() {}
-void CursorLoaderNull::LoadImageCursor(int id,
- int resource_id,
- const gfx::Point& hot) {}
-void CursorLoaderNull::LoadAnimatedCursor(int id,
- int resource_id,
- const gfx::Point& hot,
- int frame_delay_ms) {}
-void CursorLoaderNull::UnloadAll() {}
-void CursorLoaderNull::SetPlatformCursor(gfx::NativeCursor* cursor) {}
-
-} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader_null.h b/chromium/ui/base/cursor/cursor_loader_null.h
deleted file mode 100644
index 275030674b2..00000000000
--- a/chromium/ui/base/cursor/cursor_loader_null.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_CURSOR_CURSOR_LOADER_NULL_H_
-#define UI_BASE_CURSOR_CURSOR_LOADER_NULL_H_
-
-#include "base/compiler_specific.h"
-#include "ui/base/cursor/cursor_loader.h"
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-class UI_EXPORT CursorLoaderNull : public CursorLoader {
- public:
- CursorLoaderNull();
- virtual ~CursorLoaderNull();
-
- // Overridden from CursorLoader:
- virtual void LoadImageCursor(int id,
- int resource_id,
- const gfx::Point& hot) OVERRIDE;
- virtual void LoadAnimatedCursor(int id,
- int resource_id,
- const gfx::Point& hot,
- int frame_delay_ms) OVERRIDE;
- virtual void UnloadAll() OVERRIDE;
- virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CursorLoaderNull);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_CURSOR_CURSOR_LOADER_NULL_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.cc b/chromium/ui/base/cursor/cursor_loader_ozone.cc
new file mode 100644
index 00000000000..8309c2e4b2a
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_loader_ozone.cc
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/cursor_loader_ozone.h"
+
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+namespace ui {
+
+CursorLoaderOzone::CursorLoaderOzone() {}
+
+CursorLoaderOzone::~CursorLoaderOzone() {}
+
+void CursorLoaderOzone::LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) {
+ const gfx::ImageSkia* image =
+ ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
+ const gfx::ImageSkiaRep& image_rep =
+ image->GetRepresentation(scale());
+ SkBitmap bitmap = image_rep.sk_bitmap();
+ cursors_[id] =
+ CursorFactoryOzone::GetInstance()->CreateImageCursor(bitmap, hot);
+}
+
+void CursorLoaderOzone::LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) {
+ // TODO(dnicoara) Add support: crbug.com/343245
+ NOTIMPLEMENTED();
+}
+
+void CursorLoaderOzone::UnloadAll() {
+ for (ImageCursorMap::const_iterator it = cursors_.begin();
+ it != cursors_.end();
+ ++it)
+ CursorFactoryOzone::GetInstance()->UnrefImageCursor(it->second);
+ cursors_.clear();
+}
+
+void CursorLoaderOzone::SetPlatformCursor(gfx::NativeCursor* cursor) {
+ int native_type = cursor->native_type();
+ PlatformCursor platform;
+
+ if (cursors_.count(native_type)) {
+ // An image cursor is loaded for this type.
+ platform = cursors_[native_type];
+ } else if (native_type == kCursorCustom) {
+ // The platform cursor was already set via WebCursor::GetPlatformCursor.
+ platform = cursor->platform();
+ } else {
+ // Use default cursor of this type.
+ platform = CursorFactoryOzone::GetInstance()->GetDefaultCursor(native_type);
+ }
+
+ cursor->SetPlatformCursor(platform);
+}
+
+CursorLoader* CursorLoader::Create() {
+ return new CursorLoaderOzone();
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader_ozone.h b/chromium/ui/base/cursor/cursor_loader_ozone.h
new file mode 100644
index 00000000000..402cdc2bb6b
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_loader_ozone.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
+#define UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
+
+#include <map>
+
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_loader.h"
+
+namespace ui {
+
+class UI_BASE_EXPORT CursorLoaderOzone : public CursorLoader {
+ public:
+ CursorLoaderOzone();
+ virtual ~CursorLoaderOzone();
+
+ // CursorLoader overrides:
+ virtual void LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) OVERRIDE;
+ virtual void LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) OVERRIDE;
+ virtual void UnloadAll() OVERRIDE;
+ virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
+
+ private:
+ // Pointers are owned by ResourceBundle and must not be freed here.
+ typedef std::map<int, PlatformCursor> ImageCursorMap;
+ ImageCursorMap cursors_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorLoaderOzone);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_CURSOR_LOADER_OZONE_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_win.cc b/chromium/ui/base/cursor/cursor_loader_win.cc
index 6d35e554574..feb74e977f9 100644
--- a/chromium/ui/base/cursor/cursor_loader_win.cc
+++ b/chromium/ui/base/cursor/cursor_loader_win.cc
@@ -7,18 +7,13 @@
#include "base/lazy_instance.h"
#include "base/strings/string16.h"
#include "grit/ui_unscaled_resources.h"
-
-#if defined(USE_AURA)
#include "ui/base/cursor/cursor.h"
-#endif
namespace ui {
-#if defined(USE_AURA)
-
namespace {
-base::LazyInstance<string16> g_cursor_resource_module_name;
+base::LazyInstance<base::string16> g_cursor_resource_module_name;
const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
switch (native_cursor.native_type()) {
@@ -120,8 +115,6 @@ const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
} // namespace
-#endif
-
CursorLoader* CursorLoader::Create() {
return new CursorLoaderWin;
}
@@ -150,7 +143,6 @@ void CursorLoaderWin::UnloadAll() {
}
void CursorLoaderWin::SetPlatformCursor(gfx::NativeCursor* cursor) {
-#if defined(USE_AURA)
if (cursor->native_type() != kCursorCustom) {
if (cursor->platform()) {
cursor->SetPlatformCursor(cursor->platform());
@@ -165,14 +157,12 @@ void CursorLoaderWin::SetPlatformCursor(gfx::NativeCursor* cursor) {
cursor->SetPlatformCursor(platform_cursor);
}
}
-#endif
}
-#if defined(USE_AURA)
// static
-void CursorLoaderWin::SetCursorResourceModule(const string16& module_name) {
+void CursorLoaderWin::SetCursorResourceModule(
+ const base::string16& module_name) {
g_cursor_resource_module_name.Get() = module_name;
}
-#endif
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader_win.h b/chromium/ui/base/cursor/cursor_loader_win.h
index fcae566531a..adcc0aef7b1 100644
--- a/chromium/ui/base/cursor/cursor_loader_win.h
+++ b/chromium/ui/base/cursor/cursor_loader_win.h
@@ -10,7 +10,7 @@
namespace ui {
-class UI_EXPORT CursorLoaderWin : public CursorLoader {
+class UI_BASE_EXPORT CursorLoaderWin : public CursorLoader {
public:
CursorLoaderWin();
virtual ~CursorLoaderWin();
@@ -26,11 +26,9 @@ class UI_EXPORT CursorLoaderWin : public CursorLoader {
virtual void UnloadAll() OVERRIDE;
virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
-#if defined(USE_AURA)
// Used to pass the cursor resource module name to the cursor loader. This is
// typically used to load non system cursors.
- static void SetCursorResourceModule(const string16& module_name);
-#endif
+ static void SetCursorResourceModule(const base::string16& module_name);
private:
DISALLOW_COPY_AND_ASSIGN(CursorLoaderWin);
diff --git a/chromium/ui/base/cursor/cursor_loader_x11.cc b/chromium/ui/base/cursor/cursor_loader_x11.cc
index 8cfcce6e6f1..e0bb9eaeb70 100644
--- a/chromium/ui/base/cursor/cursor_loader_x11.cc
+++ b/chromium/ui/base/cursor/cursor_loader_x11.cc
@@ -12,6 +12,7 @@
#include "grit/ui_resources.h"
#include "skia/ext/image_operations.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/image/image.h"
@@ -158,12 +159,13 @@ void CursorLoaderX11::LoadImageCursor(int id,
const gfx::Point& hot) {
const gfx::ImageSkia* image =
ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
- const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
- display().device_scale_factor());
+ const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale());
SkBitmap bitmap = image_rep.sk_bitmap();
gfx::Point hotpoint = hot;
+ // TODO(oshima): The cursor should use resource scale factor when
+ // fractional scale factor is enabled. crbug.com/372212
ScaleAndRotateCursorBitmapAndHotpoint(
- scale(), display().rotation(), &bitmap, &hotpoint);
+ scale() / image_rep.scale(), rotation(), &bitmap, &hotpoint);
XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotpoint);
cursors_[id] = CreateReffedCustomXCursor(x_image);
@@ -174,10 +176,10 @@ void CursorLoaderX11::LoadAnimatedCursor(int id,
int resource_id,
const gfx::Point& hot,
int frame_delay_ms) {
+ // TODO(oshima|tdanderson): Support rotation and fractional scale factor.
const gfx::ImageSkia* image =
ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
- const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
- display().device_scale_factor());
+ const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale());
SkBitmap bitmap = image_rep.sk_bitmap();
int frame_width = bitmap.height();
int frame_height = frame_width;
@@ -232,8 +234,7 @@ void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
xcursor = invisible_cursor_.get();
else if (*cursor == kCursorCustom)
xcursor = cursor->platform();
- else if (display().device_scale_factor() == 1.0f &&
- display().rotation() == gfx::Display::ROTATE_0) {
+ else if (scale() == 1.0f && rotation() == gfx::Display::ROTATE_0) {
xcursor = GetXCursor(CursorShapeFromNative(*cursor));
} else {
xcursor = ImageCursorFromNative(kCursorPointer);
@@ -242,6 +243,10 @@ void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
cursor->SetPlatformCursor(xcursor);
}
+const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
+ return test::GetCachedXcursorImage(cursors_[id]);
+}
+
bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
int type = native_cursor.native_type();
return cursors_.count(type) || animated_cursors_.count(type);
@@ -259,48 +264,4 @@ bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
return GetXCursor(CursorShapeFromNative(native_cursor));
}
-void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
- gfx::Display::Rotation rotation,
- SkBitmap* bitmap,
- gfx::Point* hotpoint) {
- switch (rotation) {
- case gfx::Display::ROTATE_0:
- break;
- case gfx::Display::ROTATE_90:
- hotpoint->SetPoint(bitmap->height() - hotpoint->y(), hotpoint->x());
- *bitmap = SkBitmapOperations::Rotate(
- *bitmap, SkBitmapOperations::ROTATION_90_CW);
- break;
- case gfx::Display::ROTATE_180:
- hotpoint->SetPoint(
- bitmap->width() - hotpoint->x(), bitmap->height() - hotpoint->y());
- *bitmap = SkBitmapOperations::Rotate(
- *bitmap, SkBitmapOperations::ROTATION_180_CW);
- break;
- case gfx::Display::ROTATE_270:
- hotpoint->SetPoint(hotpoint->y(), bitmap->width() - hotpoint->x());
- *bitmap = SkBitmapOperations::Rotate(
- *bitmap, SkBitmapOperations::ROTATION_270_CW);
- break;
- }
-
- if (scale < FLT_EPSILON) {
- NOTREACHED() << "Scale must be larger than 0.";
- scale = 1.0f;
- }
-
- if (scale == 1.0f)
- return;
-
- gfx::Size scaled_size = gfx::ToFlooredSize(
- gfx::ScaleSize(gfx::Size(bitmap->width(), bitmap->height()), scale));
-
- *bitmap = skia::ImageOperations::Resize(
- *bitmap,
- skia::ImageOperations::RESIZE_BETTER,
- scaled_size.width(),
- scaled_size.height());
- *hotpoint = gfx::ToFlooredPoint(gfx::ScalePoint(*hotpoint, scale));
-}
-
} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_loader_x11.h b/chromium/ui/base/cursor/cursor_loader_x11.h
index a0265ffe3ae..331529b3b2c 100644
--- a/chromium/ui/base/cursor/cursor_loader_x11.h
+++ b/chromium/ui/base/cursor/cursor_loader_x11.h
@@ -11,13 +11,13 @@
#include "base/compiler_specific.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/cursor_loader.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/display.h"
namespace ui {
-class UI_EXPORT CursorLoaderX11 : public CursorLoader {
+class UI_BASE_EXPORT CursorLoaderX11 : public CursorLoader {
public:
CursorLoaderX11();
virtual ~CursorLoaderX11();
@@ -33,6 +33,8 @@ class UI_EXPORT CursorLoaderX11 : public CursorLoader {
virtual void UnloadAll() OVERRIDE;
virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
+ const XcursorImage* GetXcursorImageForTest(int id);
+
private:
// Returns true if we have an image resource loaded for the |native_cursor|.
bool IsImageCursor(gfx::NativeCursor native_cursor);
@@ -56,15 +58,6 @@ class UI_EXPORT CursorLoaderX11 : public CursorLoader {
DISALLOW_COPY_AND_ASSIGN(CursorLoaderX11);
};
-// Scale and rotate the cursor's bitmap and hotpoint.
-// |bitmap_in_out| and |hotpoint_in_out| are used as
-// both input and output.
-UI_EXPORT void ScaleAndRotateCursorBitmapAndHotpoint(
- float scale,
- gfx::Display::Rotation rotation,
- SkBitmap* bitmap_in_out,
- gfx::Point* hotpoint_in_out);
-
} // namespace ui
#endif // UI_BASE_CURSOR_CURSOR_LOADER_X11_H_
diff --git a/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc b/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc
index c2413b6acfa..9584cf12613 100644
--- a/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc
+++ b/chromium/ui/base/cursor/cursor_loader_x11_unittest.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/cursor/cursor_util.h"
namespace ui {
@@ -17,6 +18,7 @@ TEST(CursorLoaderX11Test, ScaleAndRotate) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 5);
bitmap.allocPixels();
+ bitmap.eraseColor(SK_ColorBLACK);
gfx::Point hotpoint(3,4);
diff --git a/chromium/ui/base/cursor/cursor_null.cc b/chromium/ui/base/cursor/cursor_null.cc
deleted file mode 100644
index ffb3def6c7b..00000000000
--- a/chromium/ui/base/cursor/cursor_null.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/cursor/cursor.h"
-
-namespace ui {
-
-void Cursor::RefCustomCursor() {
-}
-
-void Cursor::UnrefCustomCursor() {
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_ozone.cc b/chromium/ui/base/cursor/cursor_ozone.cc
new file mode 100644
index 00000000000..c4ef8c4d45e
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_ozone.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/base/cursor/cursor.h"
+
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+namespace ui {
+
+void Cursor::RefCustomCursor() {
+ if (platform_cursor_)
+ CursorFactoryOzone::GetInstance()->RefImageCursor(platform_cursor_);
+}
+
+void Cursor::UnrefCustomCursor() {
+ if (platform_cursor_)
+ CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor_);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_util.cc b/chromium/ui/base/cursor/cursor_util.cc
new file mode 100644
index 00000000000..a17d9447959
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_util.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/cursor_util.h"
+
+#include "base/logging.h"
+#include "skia/ext/image_operations.h"
+#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/skbitmap_operations.h"
+#include "ui/gfx/skia_util.h"
+
+namespace ui {
+
+void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
+ gfx::Display::Rotation rotation,
+ SkBitmap* bitmap,
+ gfx::Point* hotpoint) {
+ switch (rotation) {
+ case gfx::Display::ROTATE_0:
+ break;
+ case gfx::Display::ROTATE_90:
+ hotpoint->SetPoint(bitmap->height() - hotpoint->y(), hotpoint->x());
+ *bitmap = SkBitmapOperations::Rotate(
+ *bitmap, SkBitmapOperations::ROTATION_90_CW);
+ break;
+ case gfx::Display::ROTATE_180:
+ hotpoint->SetPoint(
+ bitmap->width() - hotpoint->x(), bitmap->height() - hotpoint->y());
+ *bitmap = SkBitmapOperations::Rotate(
+ *bitmap, SkBitmapOperations::ROTATION_180_CW);
+ break;
+ case gfx::Display::ROTATE_270:
+ hotpoint->SetPoint(hotpoint->y(), bitmap->width() - hotpoint->x());
+ *bitmap = SkBitmapOperations::Rotate(
+ *bitmap, SkBitmapOperations::ROTATION_270_CW);
+ break;
+ }
+
+ if (scale < FLT_EPSILON) {
+ NOTREACHED() << "Scale must be larger than 0.";
+ scale = 1.0f;
+ }
+
+ if (scale == 1.0f)
+ return;
+
+ gfx::Size scaled_size = gfx::ToFlooredSize(
+ gfx::ScaleSize(gfx::Size(bitmap->width(), bitmap->height()), scale));
+
+ *bitmap = skia::ImageOperations::Resize(
+ *bitmap,
+ skia::ImageOperations::RESIZE_BETTER,
+ scaled_size.width(),
+ scaled_size.height());
+ *hotpoint = gfx::ToFlooredPoint(gfx::ScalePoint(*hotpoint, scale));
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/cursor_util.h b/chromium/ui/base/cursor/cursor_util.h
new file mode 100644
index 00000000000..1625156e7a9
--- /dev/null
+++ b/chromium/ui/base/cursor/cursor_util.h
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CURSOR_CURSOR_UTIL_H_
+#define UI_BASE_CURSOR_CURSOR_UTIL_H_
+
+#include "base/compiler_specific.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace ui {
+
+// Scale and rotate the cursor's bitmap and hotpoint.
+// |bitmap_in_out| and |hotpoint_in_out| are used as
+// both input and output.
+UI_BASE_EXPORT void ScaleAndRotateCursorBitmapAndHotpoint(
+ float scale,
+ gfx::Display::Rotation rotation,
+ SkBitmap* bitmap_in_out,
+ gfx::Point* hotpoint_in_out);
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_CURSOR_UTIL_H_
diff --git a/chromium/ui/base/cursor/cursors_aura.h b/chromium/ui/base/cursor/cursors_aura.h
index 7d098a1eee4..e8eae0ab2de 100644
--- a/chromium/ui/base/cursor/cursors_aura.h
+++ b/chromium/ui/base/cursor/cursors_aura.h
@@ -6,7 +6,7 @@
#define UI_BASE_CURSOR_CURSORS_AURA_H_
#include "ui/base/cursor/cursor.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class SkBitmap;
@@ -22,24 +22,23 @@ const int kAnimatedCursorFrameDelayMs = 25;
// ui::kCursorHelp. The IDR will be placed in |resource_id| and the hotspots
// for the different DPIs will be placed in |hot_1x| and |hot_2x|. Returns
// false if |id| is invalid.
-bool UI_EXPORT GetCursorDataFor(CursorSetType cursor_set_id,
- int id,
- float scale_factor,
- int* resource_id,
- gfx::Point* point);
+bool UI_BASE_EXPORT GetCursorDataFor(CursorSetType cursor_set_id,
+ int id,
+ float scale_factor,
+ int* resource_id,
+ gfx::Point* point);
// Like above, but for animated cursors.
-bool UI_EXPORT GetAnimatedCursorDataFor(CursorSetType cursor_set_id,
- int id,
- float scale_factor,
- int* resource_id,
- gfx::Point* point);
+bool UI_BASE_EXPORT GetAnimatedCursorDataFor(CursorSetType cursor_set_id,
+ int id,
+ float scale_factor,
+ int* resource_id,
+ gfx::Point* point);
// Returns the cursor bitmap for |cursor|. Returns false if |cursor| is invalid.
// The cursor hot point location is set in |point|.
-bool UI_EXPORT GetCursorBitmap(const Cursor& cursor,
- SkBitmap* bitmap,
- gfx::Point* point);
+bool UI_BASE_EXPORT
+ GetCursorBitmap(const Cursor& cursor, SkBitmap* bitmap, gfx::Point* point);
} // namespace ui
diff --git a/chromium/ui/base/cursor/image_cursors.cc b/chromium/ui/base/cursor/image_cursors.cc
new file mode 100644
index 00000000000..b4c19fc837b
--- /dev/null
+++ b/chromium/ui/base/cursor/image_cursors.cc
@@ -0,0 +1,150 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/image_cursors.h"
+
+#include <float.h>
+
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/cursors_aura.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/point.h"
+
+namespace ui {
+
+namespace {
+
+const int kImageCursorIds[] = {
+ kCursorNull,
+ kCursorPointer,
+ kCursorNoDrop,
+ kCursorNotAllowed,
+ kCursorCopy,
+ kCursorHand,
+ kCursorMove,
+ kCursorNorthEastResize,
+ kCursorSouthWestResize,
+ kCursorSouthEastResize,
+ kCursorNorthWestResize,
+ kCursorNorthResize,
+ kCursorSouthResize,
+ kCursorEastResize,
+ kCursorWestResize,
+ kCursorIBeam,
+ kCursorAlias,
+ kCursorCell,
+ kCursorContextMenu,
+ kCursorCross,
+ kCursorHelp,
+ kCursorVerticalText,
+ kCursorZoomIn,
+ kCursorZoomOut,
+ kCursorRowResize,
+ kCursorColumnResize,
+ kCursorEastWestResize,
+ kCursorNorthSouthResize,
+ kCursorNorthEastSouthWestResize,
+ kCursorNorthWestSouthEastResize,
+ kCursorGrab,
+ kCursorGrabbing,
+};
+
+const int kAnimatedCursorIds[] = {
+ kCursorWait,
+ kCursorProgress
+};
+
+} // namespace
+
+ImageCursors::ImageCursors() : cursor_set_(CURSOR_SET_NORMAL) {
+}
+
+ImageCursors::~ImageCursors() {
+}
+
+float ImageCursors::GetScale() const {
+ if (!cursor_loader_) {
+ NOTREACHED();
+ // Returning default on release build as it's not serious enough to crash
+ // even if this ever happens.
+ return 1.0f;
+ }
+ return cursor_loader_->scale();
+}
+
+gfx::Display::Rotation ImageCursors::GetRotation() const {
+ if (!cursor_loader_) {
+ NOTREACHED();
+ // Returning default on release build as it's not serious enough to crash
+ // even if this ever happens.
+ return gfx::Display::ROTATE_0;
+ }
+ return cursor_loader_->rotation();
+}
+
+bool ImageCursors::SetDisplay(const gfx::Display& display,
+ float scale_factor) {
+ if (!cursor_loader_) {
+ cursor_loader_.reset(CursorLoader::Create());
+ } else if (cursor_loader_->rotation() == display.rotation() &&
+ cursor_loader_->scale() == scale_factor) {
+ return false;
+ }
+
+ cursor_loader_->set_rotation(display.rotation());
+ cursor_loader_->set_scale(scale_factor);
+ ReloadCursors();
+ return true;
+}
+
+void ImageCursors::ReloadCursors() {
+ float device_scale_factor = cursor_loader_->scale();
+
+ cursor_loader_->UnloadAll();
+
+ for (size_t i = 0; i < arraysize(kImageCursorIds); ++i) {
+ int resource_id = -1;
+ gfx::Point hot_point;
+ bool success = GetCursorDataFor(cursor_set_,
+ kImageCursorIds[i],
+ device_scale_factor,
+ &resource_id,
+ &hot_point);
+ DCHECK(success);
+ cursor_loader_->LoadImageCursor(kImageCursorIds[i], resource_id, hot_point);
+ }
+ for (size_t i = 0; i < arraysize(kAnimatedCursorIds); ++i) {
+ int resource_id = -1;
+ gfx::Point hot_point;
+ bool success = GetAnimatedCursorDataFor(cursor_set_,
+ kAnimatedCursorIds[i],
+ device_scale_factor,
+ &resource_id,
+ &hot_point);
+ DCHECK(success);
+ cursor_loader_->LoadAnimatedCursor(kAnimatedCursorIds[i],
+ resource_id,
+ hot_point,
+ kAnimatedCursorFrameDelayMs);
+ }
+}
+
+void ImageCursors::SetCursorSet(CursorSetType cursor_set) {
+ if (cursor_set_ == cursor_set)
+ return;
+
+ cursor_set_ = cursor_set;
+
+ if (cursor_loader_.get())
+ ReloadCursors();
+}
+
+void ImageCursors::SetPlatformCursor(gfx::NativeCursor* cursor) {
+ cursor_loader_->SetPlatformCursor(cursor);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/image_cursors.h b/chromium/ui/base/cursor/image_cursors.h
new file mode 100644
index 00000000000..25676ca462f
--- /dev/null
+++ b/chromium/ui/base/cursor/image_cursors.h
@@ -0,0 +1,52 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CURSOR_IMAGE_CURSORS_H_
+#define UI_BASE_CURSOR_IMAGE_CURSORS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+
+class CursorLoader;
+
+// A utility class that provides cursors for NativeCursors for which we have
+// image resources.
+class UI_BASE_EXPORT ImageCursors {
+ public:
+ ImageCursors();
+ ~ImageCursors();
+
+ // Returns the scale and rotation of the currently loaded cursor.
+ float GetScale() const;
+ gfx::Display::Rotation GetRotation() const;
+
+ // Sets the display the cursors are loaded for. |scale_factor| determines the
+ // size of the image to load. Returns true if the cursor image is reloaded.
+ bool SetDisplay(const gfx::Display& display, float scale_factor);
+
+ // Sets the type of the mouse cursor icon.
+ void SetCursorSet(CursorSetType cursor_set);
+
+ // Sets the platform cursor based on the native type of |cursor|.
+ void SetPlatformCursor(gfx::NativeCursor* cursor);
+
+ private:
+ // Reloads the all loaded cursors in the cursor loader.
+ void ReloadCursors();
+
+ scoped_ptr<CursorLoader> cursor_loader_;
+ CursorSetType cursor_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageCursors);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_IMAGE_CURSORS_H_
diff --git a/chromium/ui/base/cursor/ozone/OWNERS b/chromium/ui/base/cursor/ozone/OWNERS
new file mode 100644
index 00000000000..479c4d806cc
--- /dev/null
+++ b/chromium/ui/base/cursor/ozone/OWNERS
@@ -0,0 +1,2 @@
+rjkroege@chromium.org
+spang@chromium.org
diff --git a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc
new file mode 100644
index 00000000000..c24c80fd9c2
--- /dev/null
+++ b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/cursor/cursors_aura.h"
+
+namespace ui {
+
+namespace {
+
+BitmapCursorOzone* ToBitmapCursorOzone(PlatformCursor cursor) {
+ return static_cast<BitmapCursorOzone*>(cursor);
+}
+
+PlatformCursor ToPlatformCursor(BitmapCursorOzone* cursor) {
+ return static_cast<PlatformCursor>(cursor);
+}
+
+} // namespace
+
+BitmapCursorFactoryOzone::BitmapCursorFactoryOzone() {}
+
+BitmapCursorFactoryOzone::~BitmapCursorFactoryOzone() {}
+
+PlatformCursor BitmapCursorFactoryOzone::GetDefaultCursor(int type) {
+ if (type == kCursorNone)
+ return NULL; // NULL is used for hidden cursor.
+
+ if (!default_cursors_.count(type)) {
+ // Create new owned image cursor from default aura bitmap for this type.
+ SkBitmap bitmap;
+ gfx::Point hotspot;
+ CHECK(GetCursorBitmap(type, &bitmap, &hotspot));
+ default_cursors_[type] = new BitmapCursorOzone(bitmap, hotspot);
+ }
+
+ // Returned owned default cursor for this type.
+ return default_cursors_[type];
+}
+
+PlatformCursor BitmapCursorFactoryOzone::CreateImageCursor(
+ const SkBitmap& bitmap,
+ const gfx::Point& hotspot) {
+ BitmapCursorOzone* cursor = new BitmapCursorOzone(bitmap, hotspot);
+ cursor->AddRef(); // Balanced by UnrefImageCursor.
+ return ToPlatformCursor(cursor);
+}
+
+void BitmapCursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
+ ToBitmapCursorOzone(cursor)->AddRef();
+}
+
+void BitmapCursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
+ ToBitmapCursorOzone(cursor)->Release();
+}
+
+void BitmapCursorFactoryOzone::SetCursor(gfx::AcceleratedWidget widget,
+ PlatformCursor platform_cursor) {
+ BitmapCursorOzone* cursor = ToBitmapCursorOzone(platform_cursor);
+ SetBitmapCursor(widget, make_scoped_refptr(cursor));
+}
+
+void BitmapCursorFactoryOzone::SetBitmapCursor(
+ gfx::AcceleratedWidget widget,
+ scoped_refptr<BitmapCursorOzone>) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
new file mode 100644
index 00000000000..916e1293f0a
--- /dev/null
+++ b/chromium/ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CURSOR_OZONE_BITMAP_CURSOR_FACTORY_OZONE_H_
+#define UI_BASE_CURSOR_OZONE_BITMAP_CURSOR_FACTORY_OZONE_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+namespace ui {
+
+// A cursor that is an SkBitmap combined with a gfx::Point hotspot.
+class UI_BASE_EXPORT BitmapCursorOzone
+ : public base::RefCounted<BitmapCursorOzone> {
+ public:
+ BitmapCursorOzone(const SkBitmap& bitmap, const gfx::Point& hotspot)
+ : bitmap_(bitmap), hotspot_(hotspot) {}
+
+ const gfx::Point& hotspot() { return hotspot_; }
+ const SkBitmap& bitmap() { return bitmap_; }
+
+ private:
+ friend class base::RefCounted<BitmapCursorOzone>;
+ ~BitmapCursorOzone() {}
+
+ SkBitmap bitmap_;
+ gfx::Point hotspot_;
+
+ DISALLOW_COPY_AND_ASSIGN(BitmapCursorOzone);
+};
+
+// CursorFactoryOzone implementation for bitmapped cursors.
+//
+// This is a base class for platforms where PlatformCursor is an SkBitmap
+// combined with a gfx::Point for the hotspot.
+//
+// Subclasses need only implement SetBitmapCursor() as everything else is
+// implemented here.
+class UI_BASE_EXPORT BitmapCursorFactoryOzone : public CursorFactoryOzone {
+ public:
+ BitmapCursorFactoryOzone();
+ virtual ~BitmapCursorFactoryOzone();
+
+ // CursorFactoryOzone:
+ virtual PlatformCursor GetDefaultCursor(int type) OVERRIDE;
+ virtual PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
+ const gfx::Point& hotspot) OVERRIDE;
+ virtual void RefImageCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void UnrefImageCursor(PlatformCursor cursor) OVERRIDE;
+ virtual void SetCursor(gfx::AcceleratedWidget widget,
+ PlatformCursor cursor) OVERRIDE;
+
+ // Set a bitmap cursor for the given window. This must be overridden by
+ // subclasses. If the cursor is hidden (kCursorNone) then cursor is NULL.
+ virtual void SetBitmapCursor(gfx::AcceleratedWidget window,
+ scoped_refptr<BitmapCursorOzone> cursor);
+
+ private:
+ // Default cursors are cached & owned by the factory.
+ typedef std::map<int, scoped_refptr<BitmapCursorOzone> > DefaultCursorMap;
+ DefaultCursorMap default_cursors_;
+
+ DISALLOW_COPY_AND_ASSIGN(BitmapCursorFactoryOzone);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_OZONE_BITMAP_CURSOR_FACTORY_OZONE_H_
diff --git a/chromium/ui/base/default_theme_provider.cc b/chromium/ui/base/default_theme_provider.cc
index 9777b390729..210ff1899b9 100644
--- a/chromium/ui/base/default_theme_provider.cc
+++ b/chromium/ui/base/default_theme_provider.cc
@@ -7,16 +7,16 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(OS_WIN) && !defined(USE_AURA)
-#include "ui/base/win/shell.h"
-#endif
-
namespace ui {
DefaultThemeProvider::DefaultThemeProvider() {}
DefaultThemeProvider::~DefaultThemeProvider() {}
+bool DefaultThemeProvider::UsingSystemTheme() const {
+ return true;
+}
+
gfx::ImageSkia* DefaultThemeProvider::GetImageSkiaNamed(int id) const {
return ResourceBundle::GetSharedInstance().GetImageSkiaNamed(id);
}
@@ -31,11 +31,7 @@ int DefaultThemeProvider::GetDisplayProperty(int id) const {
}
bool DefaultThemeProvider::ShouldUseNativeFrame() const {
-#if defined(OS_WIN) && !defined(USE_AURA)
- return ui::win::IsAeroGlassEnabled();
-#else
return false;
-#endif
}
bool DefaultThemeProvider::HasCustomImage(int id) const {
@@ -48,10 +44,4 @@ base::RefCountedMemory* DefaultThemeProvider::GetRawData(
return NULL;
}
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)
-GdkPixbuf* DefaultThemeProvider::GetRTLEnabledPixbufNamed(int id) const {
- return NULL;
-}
-#endif
-
} // namespace ui
diff --git a/chromium/ui/base/default_theme_provider.h b/chromium/ui/base/default_theme_provider.h
index 15fa4a9f487..e2589c732e7 100644
--- a/chromium/ui/base/default_theme_provider.h
+++ b/chromium/ui/base/default_theme_provider.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "ui/base/theme_provider.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
class ResourceBundle;
@@ -18,12 +18,13 @@ class ResourceBundle;
namespace ui {
-class UI_EXPORT DefaultThemeProvider : public ThemeProvider {
+class UI_BASE_EXPORT DefaultThemeProvider : public ThemeProvider {
public:
DefaultThemeProvider();
virtual ~DefaultThemeProvider();
// Overridden from ui::ThemeProvider:
+ virtual bool UsingSystemTheme() const OVERRIDE;
virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE;
virtual SkColor GetColor(int id) const OVERRIDE;
virtual int GetDisplayProperty(int id) const OVERRIDE;
@@ -39,8 +40,6 @@ class UI_EXPORT DefaultThemeProvider : public ThemeProvider {
virtual NSColor* GetNSColor(int id) const OVERRIDE;
virtual NSColor* GetNSColorTint(int id) const OVERRIDE;
virtual NSGradient* GetNSGradient(int id) const OVERRIDE;
-#elif defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)
- virtual GdkPixbuf* GetRTLEnabledPixbufNamed(int id) const OVERRIDE;
#endif
private:
diff --git a/chromium/ui/base/device_form_factor.h b/chromium/ui/base/device_form_factor.h
index 4b5cd576cd1..f87ceca159f 100644
--- a/chromium/ui/base/device_form_factor.h
+++ b/chromium/ui/base/device_form_factor.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_DEVICE_FORM_FACTOR_H_
#define UI_BASE_DEVICE_FORM_FACTOR_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -17,7 +17,7 @@ enum DeviceFormFactor {
// Returns the form factor of current device. For platforms other than Android
// and iOS, DEVICE_FORM_FACTOR_DESKTOP is always returned.
-UI_EXPORT DeviceFormFactor GetDeviceFormFactor();
+UI_BASE_EXPORT DeviceFormFactor GetDeviceFormFactor();
} // namespace ui
diff --git a/chromium/ui/base/device_form_factor_android.cc b/chromium/ui/base/device_form_factor_android.cc
index 836a81f19f5..e7ed06b82f0 100644
--- a/chromium/ui/base/device_form_factor_android.cc
+++ b/chromium/ui/base/device_form_factor_android.cc
@@ -2,17 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/device_form_factor.h"
+#include "ui/base/device_form_factor_android.h"
-#include "base/command_line.h"
-#include "ui_base_switches.h"
+#include "base/android/jni_android.h"
+#include "jni/DeviceFormFactor_jni.h"
namespace ui {
DeviceFormFactor GetDeviceFormFactor() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTabletUI))
- return DEVICE_FORM_FACTOR_TABLET;
- return DEVICE_FORM_FACTOR_PHONE;
+ bool is_tablet = Java_DeviceFormFactor_isTablet(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext());
+ return is_tablet ? DEVICE_FORM_FACTOR_TABLET : DEVICE_FORM_FACTOR_PHONE;
+}
+
+bool RegisterDeviceFormFactorAndroid(JNIEnv* env) {
+ return RegisterNativesImpl(env);
}
} // namespace ui
diff --git a/chromium/ui/base/device_form_factor_android.h b/chromium/ui/base/device_form_factor_android.h
new file mode 100644
index 00000000000..7e2328d86c1
--- /dev/null
+++ b/chromium/ui/base/device_form_factor_android.h
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_DEVICE_FORM_FACTOR_ANDROID_H_
+#define UI_BASE_DEVICE_FORM_FACTOR_ANDROID_H_
+
+#include <jni.h>
+
+#include "ui/base/device_form_factor.h"
+
+namespace ui {
+
+bool RegisterDeviceFormFactorAndroid(JNIEnv* env);
+
+} // namespace ui
+
+#endif // UI_BASE_DEVICE_FORM_FACTOR_ANDROID_H_
diff --git a/chromium/ui/base/dragdrop/cocoa_dnd_util.h b/chromium/ui/base/dragdrop/cocoa_dnd_util.h
index 5b410145fe7..1945c177293 100644
--- a/chromium/ui/base/dragdrop/cocoa_dnd_util.h
+++ b/chromium/ui/base/dragdrop/cocoa_dnd_util.h
@@ -10,7 +10,7 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class GURL;
@@ -20,24 +20,24 @@ namespace ui {
// any data associated with this type; it's only used to ensure that Chrome
// supports any drag initiated inside of Chrome, whether or not data has been
// associated with it.
-UI_EXPORT extern NSString* const kChromeDragDummyPboardType;
+UI_BASE_EXPORT extern NSString* const kChromeDragDummyPboardType;
// Mail.app and TextEdit accept drags that have both HTML and image flavors on
// them, but don't process them correctly <http://crbug.com/55879>. Therefore,
// if there is an image flavor, don't put the HTML data on as HTML, but rather
// put it on as this Chrome-only flavor. External apps won't see HTML but
// Chrome will know enough to read it as HTML. <http://crbug.com/55879>
-UI_EXPORT extern NSString* const kChromeDragImageHTMLPboardType;
+UI_BASE_EXPORT extern NSString* const kChromeDragImageHTMLPboardType;
// Populates the |url| and |title| with URL data in |pboard|. There may be more
// than one, but we only handle dropping the first. |url| must not be |NULL|;
// |title| is an optional parameter. Returns |YES| if URL data was obtained from
// the pasteboard, |NO| otherwise. If |convert_filenames| is |YES|, the function
// will also attempt to convert filenames in |pboard| to file URLs.
-UI_EXPORT BOOL PopulateURLAndTitleFromPasteboard(GURL* url,
- base::string16* title,
- NSPasteboard* pboard,
- BOOL convert_filenames);
+UI_BASE_EXPORT BOOL PopulateURLAndTitleFromPasteboard(GURL* url,
+ base::string16* title,
+ NSPasteboard* pboard,
+ BOOL convert_filenames);
} // namespace ui
diff --git a/chromium/ui/base/dragdrop/download_file_interface.h b/chromium/ui/base/dragdrop/download_file_interface.h
index c157950ba46..327fe79ebe1 100644
--- a/chromium/ui/base/dragdrop/download_file_interface.h
+++ b/chromium/ui/base/dragdrop/download_file_interface.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#if defined(OS_WIN)
#include <objidl.h>
@@ -25,7 +25,7 @@ namespace ui {
// TODO(benjhayden, anybody): Do these need to be RefCountedThreadSafe?
// Defines the interface to observe the status of file download.
-class UI_EXPORT DownloadFileObserver
+class UI_BASE_EXPORT DownloadFileObserver
: public base::RefCountedThreadSafe<DownloadFileObserver> {
public:
virtual void OnDownloadCompleted(const base::FilePath& file_path) = 0;
@@ -37,7 +37,7 @@ class UI_EXPORT DownloadFileObserver
};
// Defines the interface to control how a file is downloaded.
-class UI_EXPORT DownloadFileProvider
+class UI_BASE_EXPORT DownloadFileProvider
: public base::RefCountedThreadSafe<DownloadFileProvider> {
public:
// Starts the download asynchronously and returns immediately.
diff --git a/chromium/ui/base/dragdrop/drag_drop_types.h b/chromium/ui/base/dragdrop/drag_drop_types.h
index ea57f95d374..c74d4e28a44 100644
--- a/chromium/ui/base/dragdrop/drag_drop_types.h
+++ b/chromium/ui/base/dragdrop/drag_drop_types.h
@@ -6,11 +6,11 @@
#define UI_BASE_DRAGDROP_DRAG_DROP_TYPES_H_
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
-class UI_EXPORT DragDropTypes {
+class UI_BASE_EXPORT DragDropTypes {
public:
enum DragOperation {
DRAG_NONE = 0,
@@ -22,14 +22,12 @@ class UI_EXPORT DragDropTypes {
enum DragEventSource {
DRAG_EVENT_SOURCE_MOUSE,
DRAG_EVENT_SOURCE_TOUCH,
+ DRAG_EVENT_SOURCE_LAST = DRAG_EVENT_SOURCE_TOUCH
};
#if defined(OS_WIN)
static uint32 DragOperationToDropEffect(int drag_operation);
static int DropEffectToDragOperation(uint32 effect);
-#elif defined(TOOLKIT_GTK)
- static int DragOperationToGdkDragAction(int drag_operation);
- static int GdkDragActionToDragOperation(int gdk_drag_action);
#endif
};
diff --git a/chromium/ui/base/dragdrop/drag_source_win.h b/chromium/ui/base/dragdrop/drag_source_win.h
index 7c03b6cb591..cec2aa14574 100644
--- a/chromium/ui/base/dragdrop/drag_source_win.h
+++ b/chromium/ui/base/dragdrop/drag_source_win.h
@@ -9,7 +9,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -17,7 +17,7 @@ namespace ui {
// drag-drop operation as the user mouses over other drop targets on their
// system. This object tells Windows whether or not the drag should continue,
// and supplies the appropriate cursors.
-class UI_EXPORT DragSourceWin
+class UI_BASE_EXPORT DragSourceWin
: public IDropSource,
public base::RefCountedThreadSafe<DragSourceWin> {
public:
diff --git a/chromium/ui/base/dragdrop/drag_utils.cc b/chromium/ui/base/dragdrop/drag_utils.cc
index 891a6496cea..b9faf3fd66b 100644
--- a/chromium/ui/base/dragdrop/drag_utils.cc
+++ b/chromium/ui/base/dragdrop/drag_utils.cc
@@ -8,12 +8,12 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/canvas_image_source.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/size.h"
#include "url/gurl.h"
namespace drag_utils {
@@ -41,37 +41,35 @@ class FileDragImageSource : public gfx::CanvasImageSource {
// Overridden from gfx::CanvasImageSource.
virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
- // Set up our text portion
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- gfx::Font font = rb.GetFont(ResourceBundle::BaseFont);
-
- // Paint the icon.
- canvas->DrawImageInt(icon_, (size().width() - icon_.width()) / 2, 0);
+ if (!icon_.isNull()) {
+ // Paint the icon.
+ canvas->DrawImageInt(icon_, (size().width() - icon_.width()) / 2, 0);
+ }
base::string16 name = file_name_.BaseName().LossyDisplayName();
const int flags = gfx::Canvas::TEXT_ALIGN_CENTER;
+ const gfx::FontList font_list;
#if defined(OS_WIN)
// Paint the file name. We inset it one pixel to allow room for the halo.
- canvas->DrawStringWithHalo(name, font, kFileDragImageTextColor,
- SK_ColorWHITE, 1,
- icon_.height() + kLinkDragImageVPadding + 1,
- size().width() - 2, font.GetHeight(), flags);
+ const gfx::Rect rect(1, icon_.height() + kLinkDragImageVPadding + 1,
+ size().width() - 2, font_list.GetHeight());
+ canvas->DrawStringRectWithHalo(name, font_list, kFileDragImageTextColor,
+ SK_ColorWHITE, rect, flags);
#else
// NO_SUBPIXEL_RENDERING is required when drawing to a non-opaque canvas.
- canvas->DrawStringInt(name, font, kFileDragImageTextColor,
- 0, icon_.height() + kLinkDragImageVPadding,
- size().width(), font.GetHeight(),
- flags | gfx::Canvas::NO_SUBPIXEL_RENDERING);
+ const gfx::Rect rect(0, icon_.height() + kLinkDragImageVPadding,
+ size().width(), font_list.GetHeight());
+ canvas->DrawStringRectWithFlags(name, font_list, kFileDragImageTextColor,
+ rect,
+ flags | gfx::Canvas::NO_SUBPIXEL_RENDERING);
#endif
}
private:
gfx::Size CalculateSize(const gfx::ImageSkia& icon) const {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- gfx::Font font = rb.GetFont(ResourceBundle::BaseFont);
const int width = kFileDragImageMaxWidth;
// Add +2 here to allow room for the halo.
- const int height = font.GetHeight() + icon.height() +
+ const int height = gfx::FontList().GetHeight() + icon.height() +
kLinkDragImageVPadding + 2;
return gfx::Size(width, height);
}
@@ -85,25 +83,23 @@ class FileDragImageSource : public gfx::CanvasImageSource {
} // namespace
void CreateDragImageForFile(const base::FilePath& file_name,
- const gfx::ImageSkia* icon,
+ const gfx::ImageSkia& icon,
ui::OSExchangeData* data_object) {
- DCHECK(icon);
DCHECK(data_object);
- gfx::CanvasImageSource* source = new FileDragImageSource(file_name, *icon);
+ gfx::CanvasImageSource* source = new FileDragImageSource(file_name, icon);
gfx::Size size = source->size();
// ImageSkia takes ownership of |source|.
gfx::ImageSkia image = gfx::ImageSkia(source, size);
gfx::Vector2d cursor_offset(size.width() / 2, kLinkDragImageVPadding);
- SetDragImageOnDataObject(image, size, cursor_offset, data_object);
+ SetDragImageOnDataObject(image, cursor_offset, data_object);
}
void SetDragImageOnDataObject(const gfx::Canvas& canvas,
- const gfx::Size& size,
const gfx::Vector2d& cursor_offset,
ui::OSExchangeData* data_object) {
gfx::ImageSkia image = gfx::ImageSkia(canvas.ExtractImageRep());
- SetDragImageOnDataObject(image, size, cursor_offset, data_object);
+ SetDragImageOnDataObject(image, cursor_offset, data_object);
}
} // namespace drag_utils
diff --git a/chromium/ui/base/dragdrop/drag_utils.h b/chromium/ui/base/dragdrop/drag_utils.h
index d31c628e53e..48ee94f128e 100644
--- a/chromium/ui/base/dragdrop/drag_utils.h
+++ b/chromium/ui/base/dragdrop/drag_utils.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/files/file_path.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class GURL;
@@ -28,27 +28,23 @@ namespace drag_utils {
// Creates a dragging image to be displayed when the user drags a file from
// Chrome (via the download manager, for example). The drag image is set into
-// the supplied data_object. 'file_name' can be a full path, but the directory
-// portion will be truncated in the drag image.
-UI_EXPORT void CreateDragImageForFile(const base::FilePath& file_name,
- const gfx::ImageSkia* icon,
- ui::OSExchangeData* data_object);
-
-// Sets the drag image on data_object from the supplied canvas. width/height
-// are the size of the image to use, and the offsets give the location of
-// the hotspot for the drag image.
-UI_EXPORT void SetDragImageOnDataObject(const gfx::Canvas& canvas,
- const gfx::Size& size,
- const gfx::Vector2d& cursor_offset,
- ui::OSExchangeData* data_object);
-
-// Sets the drag image on data_object from the supplied ImageSkia. width/height
-// are the size of the image to use, and the offsets give the location of
-// the hotspot for the drag image.
-UI_EXPORT void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia,
- const gfx::Size& size,
- const gfx::Vector2d& cursor_offset,
- ui::OSExchangeData* data_object);
+// the supplied data_object. |file_name| can be a full path, but the directory
+// portion will be truncated in the drag image. |icon| can be empty.
+UI_BASE_EXPORT void CreateDragImageForFile(const base::FilePath& file_name,
+ const gfx::ImageSkia& icon,
+ ui::OSExchangeData* data_object);
+
+// Sets the drag image on data_object from the supplied canvas.
+// |cursor_offset| gives the location of the hotspot for the drag image.
+UI_BASE_EXPORT void SetDragImageOnDataObject(const gfx::Canvas& canvas,
+ const gfx::Vector2d& cursor_offset,
+ ui::OSExchangeData* data_object);
+
+// Sets the drag image on data_object from the supplied ImageSkia.
+// |cursor_offset| gives the location of the hotspot for the drag image.
+UI_BASE_EXPORT void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia,
+ const gfx::Vector2d& cursor_offset,
+ ui::OSExchangeData* data_object);
} // namespace drag_utils
diff --git a/chromium/ui/base/dragdrop/drag_utils_aura.cc b/chromium/ui/base/dragdrop/drag_utils_aura.cc
index 23c84fc7452..e202e815e1e 100644
--- a/chromium/ui/base/dragdrop/drag_utils_aura.cc
+++ b/chromium/ui/base/dragdrop/drag_utils_aura.cc
@@ -14,7 +14,6 @@
namespace drag_utils {
void SetDragImageOnDataObject(const gfx::ImageSkia& image,
- const gfx::Size& size,
const gfx::Vector2d& cursor_offset,
ui::OSExchangeData* data_object) {
diff --git a/chromium/ui/base/dragdrop/drag_utils_mac.mm b/chromium/ui/base/dragdrop/drag_utils_mac.mm
new file mode 100644
index 00000000000..22171bde7fb
--- /dev/null
+++ b/chromium/ui/base/dragdrop/drag_utils_mac.mm
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/dragdrop/drag_utils.h"
+
+#include "base/logging.h"
+
+namespace drag_utils {
+
+void SetDragImageOnDataObject(const gfx::Canvas& canvas,
+ const gfx::Vector2d& cursor_offset,
+ ui::OSExchangeData* data_object) {
+ NOTIMPLEMENTED();
+}
+
+void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia,
+ const gfx::Vector2d& cursor_offset,
+ ui::OSExchangeData* data_object) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace drag_utils
diff --git a/chromium/ui/base/dragdrop/drag_utils_win.cc b/chromium/ui/base/dragdrop/drag_utils_win.cc
index 0bed7ea099c..9fedd4202a3 100644
--- a/chromium/ui/base/dragdrop/drag_utils_win.cc
+++ b/chromium/ui/base/dragdrop/drag_utils_win.cc
@@ -15,13 +15,14 @@
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/gdi_util.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/skbitmap_operations.h"
namespace drag_utils {
static void SetDragImageOnDataObject(HBITMAP hbitmap,
- const gfx::Size& size,
+ const gfx::Size& size_in_pixels,
const gfx::Vector2d& cursor_offset,
IDataObject* data_object) {
base::win::ScopedComPtr<IDragSourceHelper> helper;
@@ -29,7 +30,7 @@ static void SetDragImageOnDataObject(HBITMAP hbitmap,
IID_IDragSourceHelper, helper.ReceiveVoid());
if (SUCCEEDED(rv)) {
SHDRAGIMAGE sdi;
- sdi.sizeDragImage = size.ToSIZE();
+ sdi.sizeDragImage = size_in_pixels.ToSIZE();
sdi.crColorKey = 0xFFFFFFFF;
sdi.hbmpDragImage = hbitmap;
sdi.ptOffset = gfx::PointAtOffsetFromOrigin(cursor_offset).ToPOINT();
@@ -57,10 +58,9 @@ static HBITMAP CreateHBITMAPFromSkBitmap(const SkBitmap& sk_bitmap) {
}
void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia,
- const gfx::Size& size,
const gfx::Vector2d& cursor_offset,
ui::OSExchangeData* data_object) {
- DCHECK(data_object && !size.IsEmpty());
+ DCHECK(data_object && !image_skia.size().IsEmpty());
// InitializeFromBitmap() doesn't expect an alpha channel and is confused
// by premultiplied colors, so unpremultiply the bitmap.
// SetDragImageOnDataObject(HBITMAP) takes ownership of the bitmap.
@@ -68,17 +68,18 @@ void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia,
SkBitmapOperations::UnPreMultiply(*image_skia.bitmap()));
if (bitmap) {
// Attach 'bitmap' to the data_object.
- SetDragImageOnDataObject(bitmap, size, cursor_offset,
+ SetDragImageOnDataObject(
+ bitmap,
+ gfx::Size(image_skia.bitmap()->width(), image_skia.bitmap()->height()),
+ cursor_offset,
ui::OSExchangeDataProviderWin::GetIDataObject(*data_object));
}
-#if defined(USE_AURA)
// TODO: the above code is used in non-Ash, while below is used in Ash. If we
// could figure this context out then we wouldn't do unnecessary work. However
// as it stands getting this information in ui/base would be a layering
// violation.
data_object->provider().SetDragImage(image_skia, cursor_offset);
-#endif
}
} // namespace drag_utils
diff --git a/chromium/ui/base/dragdrop/drop_target_event.h b/chromium/ui/base/dragdrop/drop_target_event.h
index 88fcfc11986..18c0630f52f 100644
--- a/chromium/ui/base/dragdrop/drop_target_event.h
+++ b/chromium/ui/base/dragdrop/drop_target_event.h
@@ -10,7 +10,7 @@
namespace ui {
-class UI_EXPORT DropTargetEvent : public LocatedEvent {
+class UI_BASE_EXPORT DropTargetEvent : public LocatedEvent {
public:
DropTargetEvent(const OSExchangeData& data,
const gfx::Point& location,
diff --git a/chromium/ui/base/dragdrop/drop_target_win.h b/chromium/ui/base/dragdrop/drop_target_win.h
index 0f8c56d10af..4536f1d6aa6 100644
--- a/chromium/ui/base/dragdrop/drop_target_win.h
+++ b/chromium/ui/base/dragdrop/drop_target_win.h
@@ -8,7 +8,7 @@
#include <objidl.h>
#include "base/memory/ref_counted.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
// Windows interface.
struct IDropTargetHelper;
@@ -24,7 +24,7 @@ namespace ui {
// before the HWND is deleted too.
//
// This class is meant to be used in a STA and is not multithread-safe.
-class UI_EXPORT DropTargetWin : public IDropTarget {
+class UI_BASE_EXPORT DropTargetWin : public IDropTarget {
public:
// Create a new DropTarget associating it with the given HWND.
explicit DropTargetWin(HWND hwnd);
diff --git a/chromium/ui/base/dragdrop/file_info.cc b/chromium/ui/base/dragdrop/file_info.cc
new file mode 100644
index 00000000000..e5b894a020f
--- /dev/null
+++ b/chromium/ui/base/dragdrop/file_info.cc
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/dragdrop/file_info.h"
+
+namespace ui {
+
+FileInfo::FileInfo() {}
+
+FileInfo::FileInfo(const base::FilePath& path,
+ const base::FilePath& display_name)
+ : path(path), display_name(display_name) {}
+
+FileInfo::~FileInfo() {}
+
+} // namespace ui
diff --git a/chromium/ui/base/dragdrop/file_info.h b/chromium/ui/base/dragdrop/file_info.h
new file mode 100644
index 00000000000..6e4f456147a
--- /dev/null
+++ b/chromium/ui/base/dragdrop/file_info.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_DRAGDROP_FILE_INFO_H_
+#define UI_BASE_DRAGDROP_FILE_INFO_H_
+
+#include "base/files/file_path.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// struct that bundles a file's path with an optional display name.
+struct UI_BASE_EXPORT FileInfo {
+ FileInfo();
+ FileInfo(const base::FilePath& path, const base::FilePath& display_name);
+ ~FileInfo();
+
+ base::FilePath path;
+ base::FilePath display_name; // Optional.
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_FILE_INFO_H_
diff --git a/chromium/ui/base/dragdrop/gtk_dnd_util.cc b/chromium/ui/base/dragdrop/gtk_dnd_util.cc
deleted file mode 100644
index 899758b2a73..00000000000
--- a/chromium/ui/base/dragdrop/gtk_dnd_util.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/dragdrop/gtk_dnd_util.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/pickle.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/clipboard/custom_data_helper.h"
-#include "url/gurl.h"
-
-namespace ui {
-
-namespace {
-
-const int kBitsPerByte = 8;
-
-void AddTargetToList(GtkTargetList* targets, int target_code) {
- switch (target_code) {
- case ui::TEXT_PLAIN:
- gtk_target_list_add_text_targets(targets, ui::TEXT_PLAIN);
- break;
-
- case ui::TEXT_URI_LIST:
- gtk_target_list_add_uri_targets(targets, ui::TEXT_URI_LIST);
- break;
-
- case ui::TEXT_HTML:
- gtk_target_list_add(
- targets, ui::GetAtomForTarget(ui::TEXT_HTML), 0, ui::TEXT_HTML);
- break;
-
- case ui::NETSCAPE_URL:
- gtk_target_list_add(targets,
- ui::GetAtomForTarget(ui::NETSCAPE_URL), 0, ui::NETSCAPE_URL);
- break;
-
- case ui::CHROME_TAB:
- case ui::CHROME_BOOKMARK_ITEM:
- case ui::CHROME_NAMED_URL:
- gtk_target_list_add(targets, ui::GetAtomForTarget(target_code),
- GTK_TARGET_SAME_APP, target_code);
- break;
-
- case ui::DIRECT_SAVE_FILE:
- gtk_target_list_add(targets,
- ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE), 0, ui::DIRECT_SAVE_FILE);
- break;
-
- case ui::CUSTOM_DATA:
- gtk_target_list_add(targets,
- ui::GetAtomForTarget(ui::CUSTOM_DATA), 0, ui::CUSTOM_DATA);
- break;
-
- default:
- NOTREACHED() << " Unexpected target code: " << target_code;
- }
-}
-
-} // namespace
-
-GdkAtom GetAtomForTarget(int target) {
- switch (target) {
- case CHROME_TAB:
- static const GdkAtom kTabAtom = gdk_atom_intern(
- "application/x-chrome-tab", false);
- return kTabAtom;
-
- case TEXT_HTML:
- static const GdkAtom kHtmlAtom = gdk_atom_intern(
- "text/html", false);
- return kHtmlAtom;
-
- case CHROME_BOOKMARK_ITEM:
- static const GdkAtom kBookmarkAtom = gdk_atom_intern(
- "application/x-chrome-bookmark-item", false);
- return kBookmarkAtom;
-
- case TEXT_PLAIN:
- static const GdkAtom kTextAtom= gdk_atom_intern(
- "text/plain;charset=utf-8", false);
- return kTextAtom;
-
- case TEXT_URI_LIST:
- static const GdkAtom kUrisAtom = gdk_atom_intern(
- "text/uri-list", false);
- return kUrisAtom;
-
- case CHROME_NAMED_URL:
- static const GdkAtom kNamedUrl = gdk_atom_intern(
- "application/x-chrome-named-url", false);
- return kNamedUrl;
-
- case NETSCAPE_URL:
- static const GdkAtom kNetscapeUrl = gdk_atom_intern(
- "_NETSCAPE_URL", false);
- return kNetscapeUrl;
-
- case TEXT_PLAIN_NO_CHARSET:
- static const GdkAtom kTextNoCharsetAtom = gdk_atom_intern(
- "text/plain", false);
- return kTextNoCharsetAtom;
-
- case DIRECT_SAVE_FILE:
- static const GdkAtom kXdsAtom = gdk_atom_intern(
- "XdndDirectSave0", false);
- return kXdsAtom;
-
- case CUSTOM_DATA:
- static const GdkAtom kCustomData = gdk_atom_intern(
- kMimeTypeWebCustomData, false);
- return kCustomData;
-
- default:
- NOTREACHED();
- }
-
- return NULL;
-}
-
-GtkTargetList* GetTargetListFromCodeMask(int code_mask) {
- GtkTargetList* targets = gtk_target_list_new(NULL, 0);
-
- for (size_t i = 1; i < INVALID_TARGET; i = i << 1) {
- if (i == CHROME_WEBDROP_FILE_CONTENTS)
- continue;
-
- if (i & code_mask)
- AddTargetToList(targets, i);
- }
-
- return targets;
-}
-
-void SetSourceTargetListFromCodeMask(GtkWidget* source, int code_mask) {
- GtkTargetList* targets = GetTargetListFromCodeMask(code_mask);
- gtk_drag_source_set_target_list(source, targets);
- gtk_target_list_unref(targets);
-}
-
-void SetDestTargetList(GtkWidget* dest, const int* target_codes) {
- GtkTargetList* targets = gtk_target_list_new(NULL, 0);
-
- for (size_t i = 0; target_codes[i] != -1; ++i) {
- AddTargetToList(targets, target_codes[i]);
- }
-
- gtk_drag_dest_set_target_list(dest, targets);
- gtk_target_list_unref(targets);
-}
-
-void WriteURLWithName(GtkSelectionData* selection_data,
- const GURL& url,
- base::string16 title,
- int type) {
- if (title.empty()) {
- // We prefer to not have empty titles. Set it to the filename extracted
- // from the URL.
- title = UTF8ToUTF16(url.ExtractFileName());
- }
-
- switch (type) {
- case TEXT_PLAIN: {
- gtk_selection_data_set_text(selection_data, url.spec().c_str(),
- url.spec().length());
- break;
- }
- case TEXT_URI_LIST: {
- gchar* uri_array[2];
- uri_array[0] = strdup(url.spec().c_str());
- uri_array[1] = NULL;
- gtk_selection_data_set_uris(selection_data, uri_array);
- free(uri_array[0]);
- break;
- }
- case CHROME_NAMED_URL: {
- Pickle pickle;
- pickle.WriteString(UTF16ToUTF8(title));
- pickle.WriteString(url.spec());
- gtk_selection_data_set(
- selection_data,
- GetAtomForTarget(ui::CHROME_NAMED_URL),
- kBitsPerByte,
- reinterpret_cast<const guchar*>(pickle.data()),
- pickle.size());
- break;
- }
- case NETSCAPE_URL: {
- // _NETSCAPE_URL format is URL + \n + title.
- std::string utf8_text = url.spec() + "\n" + UTF16ToUTF8(title);
- gtk_selection_data_set(selection_data,
- gtk_selection_data_get_target(selection_data),
- kBitsPerByte,
- reinterpret_cast<const guchar*>(utf8_text.c_str()),
- utf8_text.length());
- break;
- }
-
- default: {
- NOTREACHED();
- break;
- }
- }
-}
-
-bool ExtractNamedURL(GtkSelectionData* selection_data,
- GURL* url,
- base::string16* title) {
- if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
- return false;
-
- Pickle data(
- reinterpret_cast<const char*>(
- gtk_selection_data_get_data(selection_data)),
- gtk_selection_data_get_length(selection_data));
- PickleIterator iter(data);
- std::string title_utf8, url_utf8;
- if (!data.ReadString(&iter, &title_utf8) ||
- !data.ReadString(&iter, &url_utf8)) {
- return false;
- }
-
- GURL gurl(url_utf8);
- if (!gurl.is_valid())
- return false;
-
- *url = gurl;
- *title = UTF8ToUTF16(title_utf8);
- return true;
-}
-
-bool ExtractURIList(GtkSelectionData* selection_data, std::vector<GURL>* urls) {
- gchar** uris = gtk_selection_data_get_uris(selection_data);
- if (!uris)
- return false;
-
- for (size_t i = 0; uris[i] != NULL; ++i) {
- GURL url(uris[i]);
- if (url.is_valid())
- urls->push_back(url);
- }
-
- g_strfreev(uris);
- return true;
-}
-
-bool ExtractNetscapeURL(GtkSelectionData* selection_data,
- GURL* url,
- base::string16* title) {
- if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
- return false;
-
- // Find the first '\n' in the data. It is the separator between the url and
- // the title.
- std::string data(
- reinterpret_cast<const char*>(
- gtk_selection_data_get_data(selection_data)),
- gtk_selection_data_get_length(selection_data));
- std::string::size_type newline = data.find('\n');
- if (newline == std::string::npos)
- return false;
-
- GURL gurl(data.substr(0, newline));
- if (!gurl.is_valid())
- return false;
-
- *url = gurl;
- *title = UTF8ToUTF16(data.substr(newline + 1));
- return true;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/dragdrop/gtk_dnd_util.h b/chromium/ui/base/dragdrop/gtk_dnd_util.h
deleted file mode 100644
index 88f00a309f1..00000000000
--- a/chromium/ui/base/dragdrop/gtk_dnd_util.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
-#define UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
-
-#include <gtk/gtk.h>
-
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
-
-class GURL;
-
-namespace ui {
-
-// Registry of all internal int codes for drag and drop.
-enum {
- // Intra-application types.
- CHROME_TAB = 1 << 0,
- CHROME_BOOKMARK_ITEM = 1 << 1,
- CHROME_WEBDROP_FILE_CONTENTS = 1 << 2,
- CHROME_NAMED_URL = 1 << 3,
-
- // Standard types.
- TEXT_PLAIN = 1 << 4,
- TEXT_URI_LIST = 1 << 5,
- TEXT_HTML = 1 << 6,
-
- // Other types. NETSCAPE_URL is provided for compatibility with other
- // apps.
- NETSCAPE_URL = 1 << 7,
-
- // Used for drag-out download.
- TEXT_PLAIN_NO_CHARSET = 1 << 8,
- DIRECT_SAVE_FILE = 1 << 9,
-
- // Custom data for web drag/drop.
- CUSTOM_DATA = 1 << 10,
-
- INVALID_TARGET = 1 << 11,
-};
-
-// Get the atom for a given target (of the above enum type). Will return NULL
-// for non-custom targets, such as CHROME_TEXT_PLAIN.
-UI_EXPORT GdkAtom GetAtomForTarget(int target);
-
-// Creates a target list from the given mask. The mask should be an OR of
-// CHROME_* values. The target list is returned with ref count 1; the caller
-// is responsible for calling gtk_target_list_unref() when it is no longer
-// needed.
-// Since the MIME type for WEBDROP_FILE_CONTENTS depends on the file's
-// contents, that flag is ignored by this function. It is the responsibility
-// of the client code to do the right thing.
-UI_EXPORT GtkTargetList* GetTargetListFromCodeMask(int code_mask);
-
-// Set the drag target list for |source| with the target list that
-// corresponds to |code_mask|.
-UI_EXPORT void SetSourceTargetListFromCodeMask(GtkWidget* source,
- int code_mask);
-
-// Set the accepted targets list for |dest|. The |target_codes| array should
-// be sorted in preference order and should be terminated with -1.
-UI_EXPORT void SetDestTargetList(GtkWidget* dest, const int* target_codes);
-
-// Write a URL to the selection in the given type.
-UI_EXPORT void WriteURLWithName(GtkSelectionData* selection_data,
- const GURL& url,
- base::string16 title,
- int type);
-
-// Extracts data of type CHROME_NAMED_URL from |selection_data| into
-// |url| and |title|. Returns true if the url/title were safely extracted
-// and the url is valid.
-UI_EXPORT bool ExtractNamedURL(GtkSelectionData* selection_data,
- GURL* url,
- base::string16* title);
-
-// Extracts data of type TEXT_URI_LIST from |selection_data| into |urls|.
-UI_EXPORT bool ExtractURIList(GtkSelectionData* selection_data,
- std::vector<GURL>* urls);
-
-// Extracts a Netscape URL (url\ntitle) from |selection_data|.
-UI_EXPORT bool ExtractNetscapeURL(GtkSelectionData* selection_data,
- GURL* url,
- base::string16* title);
-
-} // namespace ui
-
-#endif // UI_BASE_DRAGDROP_GTK_DND_UTIL_H_
diff --git a/chromium/ui/base/dragdrop/gtk_dnd_util_unittest.cc b/chromium/ui/base/dragdrop/gtk_dnd_util_unittest.cc
deleted file mode 100644
index 04f81aecdf5..00000000000
--- a/chromium/ui/base/dragdrop/gtk_dnd_util_unittest.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/pickle.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/dragdrop/gtk_dnd_util.h"
-#include "url/gurl.h"
-
-namespace ui {
-
-TEST(GtkDndUtilTest, ExtractNamedURLValid) {
- const std::string kTitle = "title";
- const std::string kUrl = "http://www.foobar.com/";
- Pickle pickle;
- pickle.WriteString(kTitle);
- pickle.WriteString(kUrl);
-
- GtkSelectionData data;
- scoped_ptr<guchar[]> test_data(new guchar[pickle.size()]);
- memcpy(test_data.get(), pickle.data(), pickle.size());
- data.data = test_data.get();
- data.length = pickle.size();
-
- GURL url;
- base::string16 title;
- ASSERT_EQ(true, ui::ExtractNamedURL(&data, &url, &title));
- EXPECT_EQ(UTF8ToUTF16(kTitle), title);
- EXPECT_EQ(GURL(kUrl), url);
-}
-
-TEST(GtkDndUtilTest, ExtractNamedURLInvalidURL) {
- const std::string kTitle = "title";
- const std::string kBadUrl = "foobar";
- Pickle pickle;
- pickle.WriteString(kTitle);
- pickle.WriteString(kBadUrl);
-
- GtkSelectionData data;
- scoped_ptr<guchar[]> test_data(new guchar[pickle.size()]);
- memcpy(test_data.get(), pickle.data(), pickle.size());
- data.data = test_data.get();
- data.length = pickle.size();
-
- GURL url;
- base::string16 title;
- EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
-}
-
-TEST(GtkDndUtilTest, ExtractNamedURLInvalidInput) {
- GURL url;
- base::string16 title;
- GtkSelectionData data;
- data.data = NULL;
- data.length = 0;
-
- EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
-
- guchar empty_data[] = "";
- data.data = empty_data;
- data.length = 0;
-
- EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
-
- const std::string kTitle = "title";
- Pickle pickle;
- pickle.WriteString(kTitle);
-
- scoped_ptr<guchar[]> test_data(new guchar[pickle.size()]);
- memcpy(test_data.get(), pickle.data(), pickle.size());
- data.data = test_data.get();
- data.length = pickle.size();
-
- EXPECT_FALSE(ui::ExtractNamedURL(&data, &url, &title));
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.cc b/chromium/ui/base/dragdrop/os_exchange_data.cc
index 1b13daf40b7..c236a467305 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data.cc
@@ -18,15 +18,6 @@ OSExchangeData::DownloadFileInfo::DownloadFileInfo(
OSExchangeData::DownloadFileInfo::~DownloadFileInfo() {}
-OSExchangeData::FileInfo::FileInfo(
- const base::FilePath& path,
- const base::FilePath& display_name)
- : path(path),
- display_name(display_name) {
-}
-
-OSExchangeData::FileInfo::~FileInfo() {}
-
OSExchangeData::OSExchangeData() : provider_(CreateProvider()) {
}
@@ -36,6 +27,14 @@ OSExchangeData::OSExchangeData(Provider* provider) : provider_(provider) {
OSExchangeData::~OSExchangeData() {
}
+void OSExchangeData::MarkOriginatedFromRenderer() {
+ provider_->MarkOriginatedFromRenderer();
+}
+
+bool OSExchangeData::DidOriginateFromRenderer() const {
+ return provider_->DidOriginateFromRenderer();
+}
+
void OSExchangeData::SetString(const base::string16& data) {
provider_->SetString(data);
}
@@ -86,8 +85,8 @@ bool OSExchangeData::HasString() const {
return provider_->HasString();
}
-bool OSExchangeData::HasURL() const {
- return provider_->HasURL();
+bool OSExchangeData::HasURL(FilenameToURLPolicy policy) const {
+ return provider_->HasURL(policy);
}
bool OSExchangeData::HasFile() const {
@@ -98,43 +97,18 @@ bool OSExchangeData::HasCustomFormat(const CustomFormat& format) const {
return provider_->HasCustomFormat(format);
}
-bool OSExchangeData::HasAllFormats(
- int formats,
- const std::set<CustomFormat>& custom_formats) const {
- if ((formats & STRING) != 0 && !HasString())
- return false;
- if ((formats & URL) != 0 && !HasURL())
- return false;
-#if defined(OS_WIN)
- if ((formats & FILE_CONTENTS) != 0 && !provider_->HasFileContents())
- return false;
-#endif
-#if defined(OS_WIN) || defined(USE_AURA)
- if ((formats & HTML) != 0 && !provider_->HasHtml())
- return false;
-#endif
- if ((formats & FILE_NAME) != 0 && !provider_->HasFile())
- return false;
- for (std::set<CustomFormat>::const_iterator i = custom_formats.begin();
- i != custom_formats.end(); ++i) {
- if (!HasCustomFormat(*i))
- return false;
- }
- return true;
-}
-
bool OSExchangeData::HasAnyFormat(
int formats,
const std::set<CustomFormat>& custom_formats) const {
if ((formats & STRING) != 0 && HasString())
return true;
- if ((formats & URL) != 0 && HasURL())
+ if ((formats & URL) != 0 && HasURL(CONVERT_FILENAMES))
return true;
#if defined(OS_WIN)
if ((formats & FILE_CONTENTS) != 0 && provider_->HasFileContents())
return true;
#endif
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
if ((formats & HTML) != 0 && provider_->HasHtml())
return true;
#endif
@@ -162,13 +136,9 @@ bool OSExchangeData::GetFileContents(base::FilePath* filename,
void OSExchangeData::SetDownloadFileInfo(const DownloadFileInfo& download) {
provider_->SetDownloadFileInfo(download);
}
-
-void OSExchangeData::SetInDragLoop(bool in_drag_loop) {
- provider_->SetInDragLoop(in_drag_loop);
-}
#endif
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
void OSExchangeData::SetHtml(const base::string16& html, const GURL& base_url) {
provider_->SetHtml(html, base_url);
}
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.h b/chromium/ui/base/dragdrop/os_exchange_data.h
index 67834e39c5f..539e8949f9d 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data.h
@@ -12,8 +12,6 @@
#if defined(OS_WIN)
#include <objidl.h>
-#elif defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
#endif
#include "base/basictypes.h"
@@ -21,7 +19,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/download_file_interface.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
class GURL;
class Pickle;
@@ -33,6 +31,8 @@ class Vector2d;
namespace ui {
+struct FileInfo;
+
///////////////////////////////////////////////////////////////////////////////
//
// OSExchangeData
@@ -47,7 +47,7 @@ namespace ui {
// TabContentsViewGtk uses a different class to handle drag support that does
// not use OSExchangeData. As such, file contents and html support is only
// compiled on windows.
-class UI_EXPORT OSExchangeData {
+class UI_BASE_EXPORT OSExchangeData {
public:
// CustomFormats are used for non-standard data types. For example, bookmark
// nodes are written using a CustomFormat.
@@ -63,7 +63,7 @@ class UI_EXPORT OSExchangeData {
#if defined(OS_WIN)
FILE_CONTENTS = 1 << 4,
#endif
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
HTML = 1 << 5,
#endif
};
@@ -73,7 +73,7 @@ class UI_EXPORT OSExchangeData {
enum FilenameToURLPolicy { CONVERT_FILENAMES, DO_NOT_CONVERT_FILENAMES, };
// Encapsulates the info about a file to be downloaded.
- struct UI_EXPORT DownloadFileInfo {
+ struct UI_BASE_EXPORT DownloadFileInfo {
DownloadFileInfo(const base::FilePath& filename,
DownloadFileProvider* downloader);
~DownloadFileInfo();
@@ -82,26 +82,18 @@ class UI_EXPORT OSExchangeData {
scoped_refptr<DownloadFileProvider> downloader;
};
- // Encapsulates the info about a file.
- struct UI_EXPORT FileInfo {
- FileInfo(const base::FilePath& path, const base::FilePath& display_name);
- ~FileInfo();
-
- // The path of the file.
- base::FilePath path;
- // The display name of the file. This field is optional.
- base::FilePath display_name;
- };
-
// Provider defines the platform specific part of OSExchangeData that
// interacts with the native system.
- class UI_EXPORT Provider {
+ class UI_BASE_EXPORT Provider {
public:
Provider() {}
virtual ~Provider() {}
virtual Provider* Clone() const = 0;
+ virtual void MarkOriginatedFromRenderer() = 0;
+ virtual bool DidOriginateFromRenderer() const = 0;
+
virtual void SetString(const base::string16& data) = 0;
virtual void SetURL(const GURL& url, const base::string16& title) = 0;
virtual void SetFilename(const base::FilePath& path) = 0;
@@ -121,21 +113,22 @@ class UI_EXPORT OSExchangeData {
Pickle* data) const = 0;
virtual bool HasString() const = 0;
- virtual bool HasURL() const = 0;
+ virtual bool HasURL(FilenameToURLPolicy policy) const = 0;
virtual bool HasFile() const = 0;
virtual bool HasCustomFormat(const CustomFormat& format) const = 0;
-#if defined(OS_WIN)
+#if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN)
virtual void SetFileContents(const base::FilePath& filename,
const std::string& file_contents) = 0;
+#endif
+#if defined(OS_WIN)
virtual bool GetFileContents(base::FilePath* filename,
std::string* file_contents) const = 0;
virtual bool HasFileContents() const = 0;
virtual void SetDownloadFileInfo(const DownloadFileInfo& download) = 0;
- virtual void SetInDragLoop(bool in_drag_loop) = 0;
#endif
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
virtual void SetHtml(const base::string16& html, const GURL& base_url) = 0;
virtual bool GetHtml(base::string16* html, GURL* base_url) const = 0;
virtual bool HasHtml() const = 0;
@@ -163,6 +156,12 @@ class UI_EXPORT OSExchangeData {
const Provider& provider() const { return *provider_; }
Provider& provider() { return *provider_; }
+ // Marks drag data as tainted if it originates from the renderer. This is used
+ // to avoid granting privileges to a renderer when dragging in tainted data,
+ // since it could allow potential escalation of privileges.
+ void MarkOriginatedFromRenderer();
+ bool DidOriginateFromRenderer() const;
+
// These functions add data to the OSExchangeData object of various Chrome
// types. The OSExchangeData object takes care of translating the data into
// a format suitable for exchange with the OS.
@@ -201,22 +200,18 @@ class UI_EXPORT OSExchangeData {
// Test whether or not data of certain types is present, without actually
// returning anything.
bool HasString() const;
- bool HasURL() const;
+ bool HasURL(FilenameToURLPolicy policy) const;
bool HasFile() const;
bool HasCustomFormat(const CustomFormat& format) const;
- // Returns true if this OSExchangeData has data for ALL the formats in
- // |formats| and ALL the custom formats in |custom_formats|.
- bool HasAllFormats(int formats,
- const std::set<CustomFormat>& custom_formats) const;
-
// Returns true if this OSExchangeData has data in any of the formats in
// |formats| or any custom format in |custom_formats|.
bool HasAnyFormat(int formats,
const std::set<CustomFormat>& custom_formats) const;
#if defined(OS_WIN)
- // Adds the bytes of a file (CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR).
+ // Adds the bytes of a file (CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR on
+ // Windows).
void SetFileContents(const base::FilePath& filename,
const std::string& file_contents);
bool GetFileContents(base::FilePath* filename,
@@ -224,11 +219,9 @@ class UI_EXPORT OSExchangeData {
// Adds a download file with full path (CF_HDROP).
void SetDownloadFileInfo(const DownloadFileInfo& download);
-
- void SetInDragLoop(bool in_drag_loop);
#endif
-#if defined(OS_WIN) || defined(USE_AURA)
+#if defined(USE_AURA)
// Adds a snippet of HTML. |html| is just raw html but this sets both
// text/html and CF_HTML.
void SetHtml(const base::string16& html, const GURL& base_url);
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
index 0d793495695..2a44793d070 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
@@ -9,6 +9,7 @@
#include "net/base/net_util.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/dragdrop/file_info.h"
namespace ui {
@@ -33,6 +34,15 @@ OSExchangeData::Provider* OSExchangeDataProviderAura::Clone() const {
return ret;
}
+void OSExchangeDataProviderAura::MarkOriginatedFromRenderer() {
+ // TODO(dcheng): Currently unneeded because ChromeOS Aura correctly separates
+ // URL and filename metadata, and does not implement the DownloadURL protocol.
+}
+
+bool OSExchangeDataProviderAura::DidOriginateFromRenderer() const {
+ return false;
+}
+
void OSExchangeDataProviderAura::SetString(const base::string16& data) {
string_ = data;
formats_ |= OSExchangeData::STRING;
@@ -44,17 +54,17 @@ void OSExchangeDataProviderAura::SetURL(const GURL& url,
title_ = title;
formats_ |= OSExchangeData::URL;
- SetString(UTF8ToUTF16(url.spec()));
+ SetString(base::UTF8ToUTF16(url.spec()));
}
void OSExchangeDataProviderAura::SetFilename(const base::FilePath& path) {
filenames_.clear();
- filenames_.push_back(OSExchangeData::FileInfo(path, base::FilePath()));
+ filenames_.push_back(FileInfo(path, base::FilePath()));
formats_ |= OSExchangeData::FILE_NAME;
}
void OSExchangeDataProviderAura::SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames) {
+ const std::vector<FileInfo>& filenames) {
filenames_ = filenames;
formats_ |= OSExchangeData::FILE_NAME;
}
@@ -100,7 +110,7 @@ bool OSExchangeDataProviderAura::GetFilename(base::FilePath* path) const {
}
bool OSExchangeDataProviderAura::GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const {
+ std::vector<FileInfo>* filenames) const {
if ((formats_ & OSExchangeData::FILE_NAME) == 0)
return false;
*filenames = filenames_;
@@ -122,7 +132,9 @@ bool OSExchangeDataProviderAura::HasString() const {
return (formats_ & OSExchangeData::STRING) != 0;
}
-bool OSExchangeDataProviderAura::HasURL() const {
+bool OSExchangeDataProviderAura::HasURL(
+ OSExchangeData::FilenameToURLPolicy policy) const {
+ // TODO(dcheng): implement filename conversion.
if ((formats_ & OSExchangeData::URL) != 0) {
return true;
}
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
index 06203434bf0..e54a2fdfe24 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.h
@@ -19,7 +19,7 @@ namespace ui {
class Clipboard;
// OSExchangeData::Provider implementation for aura on linux.
-class UI_EXPORT OSExchangeDataProviderAura
+class UI_BASE_EXPORT OSExchangeDataProviderAura
: public OSExchangeData::Provider {
public:
OSExchangeDataProviderAura();
@@ -27,11 +27,12 @@ class UI_EXPORT OSExchangeDataProviderAura
// Overridden from OSExchangeData::Provider:
virtual Provider* Clone() const OVERRIDE;
+ virtual void MarkOriginatedFromRenderer() OVERRIDE;
+ virtual bool DidOriginateFromRenderer() const OVERRIDE;
virtual void SetString(const base::string16& data) OVERRIDE;
virtual void SetURL(const GURL& url, const base::string16& title) OVERRIDE;
virtual void SetFilename(const base::FilePath& path) OVERRIDE;
- virtual void SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames) OVERRIDE;
+ virtual void SetFilenames(const std::vector<FileInfo>& filenames) OVERRIDE;
virtual void SetPickledData(const OSExchangeData::CustomFormat& format,
const Pickle& data) OVERRIDE;
virtual bool GetString(base::string16* data) const OVERRIDE;
@@ -39,12 +40,12 @@ class UI_EXPORT OSExchangeDataProviderAura
GURL* url,
base::string16* title) const OVERRIDE;
virtual bool GetFilename(base::FilePath* path) const OVERRIDE;
- virtual bool GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const OVERRIDE;
+ virtual bool GetFilenames(std::vector<FileInfo>* filenames) const OVERRIDE;
virtual bool GetPickledData(const OSExchangeData::CustomFormat& format,
Pickle* data) const OVERRIDE;
virtual bool HasString() const OVERRIDE;
- virtual bool HasURL() const OVERRIDE;
+ virtual bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const
+ OVERRIDE;
virtual bool HasFile() const OVERRIDE;
virtual bool HasCustomFormat(const OSExchangeData::CustomFormat& format) const
OVERRIDE;
@@ -77,7 +78,7 @@ class UI_EXPORT OSExchangeDataProviderAura
base::string16 title_;
// File name.
- std::vector<OSExchangeData::FileInfo> filenames_;
+ std::vector<FileInfo> filenames_;
// PICKLED_DATA contents.
PickleData pickle_data_;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
index aba74c01fcd..bf583984785 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
@@ -6,14 +6,15 @@
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_pump_x11.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/net_util.h"
+#include "net/base/filename_util.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/dragdrop/file_info.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/platform_event_source.h"
// Note: the GetBlah() methods are used immediately by the
// web_contents_view_aura.cc:PrepareDropData(), while the omnibox is a
@@ -25,6 +26,9 @@ namespace ui {
namespace {
const char kDndSelection[] = "XdndSelection";
+const char kRendererTaint[] = "chromium/x-renderer-taint";
+
+const char kNetscapeURL[] = "_NETSCAPE_URL";
const char* kAtomsToCache[] = {
kString,
@@ -33,7 +37,9 @@ const char* kAtomsToCache[] = {
kDndSelection,
Clipboard::kMimeTypeURIList,
kMimeTypeMozillaURL,
+ kNetscapeURL,
Clipboard::kMimeTypeText,
+ kRendererTaint,
NULL
};
@@ -77,12 +83,12 @@ OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11()
XStoreName(x_display_, x_window_, "Chromium Drag & Drop Window");
- base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_);
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
}
OSExchangeDataProviderAuraX11::~OSExchangeDataProviderAuraX11() {
if (own_window_) {
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_);
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
XDestroyWindow(x_display_, x_window_);
}
}
@@ -108,8 +114,20 @@ OSExchangeData::Provider* OSExchangeDataProviderAuraX11::Clone() const {
return ret;
}
+void OSExchangeDataProviderAuraX11::MarkOriginatedFromRenderer() {
+ std::string empty;
+ format_map_.Insert(atom_cache_.GetAtom(kRendererTaint),
+ scoped_refptr<base::RefCountedMemory>(
+ base::RefCountedString::TakeString(&empty)));
+}
+
+bool OSExchangeDataProviderAuraX11::DidOriginateFromRenderer() const {
+ return format_map_.find(atom_cache_.GetAtom(kRendererTaint)) !=
+ format_map_.end();
+}
+
void OSExchangeDataProviderAuraX11::SetString(const base::string16& text_data) {
- std::string utf8 = UTF16ToUTF8(text_data);
+ std::string utf8 = base::UTF16ToUTF8(text_data);
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedString::TakeString(&utf8));
@@ -121,30 +139,66 @@ void OSExchangeDataProviderAuraX11::SetString(const base::string16& text_data) {
void OSExchangeDataProviderAuraX11::SetURL(const GURL& url,
const base::string16& title) {
- // Mozilla's URL format: (UTF16: URL, newline, title)
+ // TODO(dcheng): The original GTK code tries very hard to avoid writing out an
+ // empty title. Is this necessary?
if (url.is_valid()) {
- string16 spec = UTF8ToUTF16(url.spec());
+ // Mozilla's URL format: (UTF16: URL, newline, title)
+ base::string16 spec = base::UTF8ToUTF16(url.spec());
std::vector<unsigned char> data;
ui::AddString16ToVector(spec, &data);
- ui::AddString16ToVector(ASCIIToUTF16("\n"), &data);
+ ui::AddString16ToVector(base::ASCIIToUTF16("\n"), &data);
ui::AddString16ToVector(title, &data);
scoped_refptr<base::RefCountedMemory> mem(
base::RefCountedBytes::TakeVector(&data));
format_map_.Insert(atom_cache_.GetAtom(kMimeTypeMozillaURL), mem);
+ // Set a string fallback as well.
SetString(spec);
+
+ // Return early if this drag already contains file contents (this implies
+ // that file contents must be populated before URLs). Nautilus (and possibly
+ // other file managers) prefer _NETSCAPE_URL over the X Direct Save
+ // protocol, but we want to prioritize XDS in this case.
+ if (!file_contents_name_.empty())
+ return;
+
+ // Set _NETSCAPE_URL for file managers like Nautilus that use it as a hint
+ // to create a link to the URL. Setting text/uri-list doesn't work because
+ // Nautilus will fetch and copy the contents of the URL to the drop target
+ // instead of linking...
+ // Format is UTF8: URL + "\n" + title.
+ std::string netscape_url = url.spec();
+ netscape_url += "\n";
+ netscape_url += base::UTF16ToUTF8(title);
+ format_map_.Insert(atom_cache_.GetAtom(kNetscapeURL),
+ scoped_refptr<base::RefCountedMemory>(
+ base::RefCountedString::TakeString(&netscape_url)));
}
}
void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) {
- NOTIMPLEMENTED();
+ std::vector<FileInfo> data;
+ data.push_back(FileInfo(path, base::FilePath()));
+ SetFilenames(data);
}
void OSExchangeDataProviderAuraX11::SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames) {
- NOTIMPLEMENTED();
+ const std::vector<FileInfo>& filenames) {
+ std::vector<std::string> paths;
+ for (std::vector<FileInfo>::const_iterator it = filenames.begin();
+ it != filenames.end();
+ ++it) {
+ std::string url_spec = net::FilePathToFileURL(it->path).spec();
+ if (!url_spec.empty())
+ paths.push_back(url_spec);
+ }
+
+ std::string joined_data = JoinString(paths, '\n');
+ scoped_refptr<base::RefCountedMemory> mem(
+ base::RefCountedString::TakeString(&joined_data));
+ format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeURIList), mem);
}
void OSExchangeDataProviderAuraX11::SetPickledData(
@@ -162,6 +216,13 @@ void OSExchangeDataProviderAuraX11::SetPickledData(
}
bool OSExchangeDataProviderAuraX11::GetString(base::string16* result) const {
+ if (HasFile()) {
+ // Various Linux file managers both pass a list of file:// URIs and set the
+ // string representation to the URI. We explicitly don't want to return use
+ // this representation.
+ return false;
+ }
+
std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
std::vector< ::Atom> requested_types;
ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
@@ -169,7 +230,7 @@ bool OSExchangeDataProviderAuraX11::GetString(base::string16* result) const {
ui::SelectionData data(format_map_.GetFirstOf(requested_types));
if (data.IsValid()) {
std::string text = data.GetText();
- *result = UTF8ToUTF16(text);
+ *result = base::UTF8ToUTF16(text);
return true;
}
@@ -196,33 +257,29 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
data.AssignTo(&unparsed);
std::vector<base::string16> tokens;
- size_t num_tokens = Tokenize(unparsed, ASCIIToUTF16("\n"), &tokens);
+ size_t num_tokens = Tokenize(unparsed, base::ASCIIToUTF16("\n"), &tokens);
if (num_tokens > 0) {
if (num_tokens > 1)
*title = tokens[1];
else
- *title = string16();
+ *title = base::string16();
*url = GURL(tokens[0]);
return true;
}
} else if (data.GetType() == atom_cache_.GetAtom(
Clipboard::kMimeTypeURIList)) {
- // uri-lists are newline separated file lists in URL encoding.
- std::string unparsed;
- data.AssignTo(&unparsed);
-
- std::vector<std::string> tokens;
- size_t num_tokens = Tokenize(unparsed, "\n", &tokens);
- if (!num_tokens) {
- NOTREACHED() << "Empty URI list";
- return false;
+ std::vector<std::string> tokens = ui::ParseURIList(data);
+ for (std::vector<std::string>::const_iterator it = tokens.begin();
+ it != tokens.end(); ++it) {
+ GURL test_url(*it);
+ if (!test_url.SchemeIsFile() ||
+ policy == OSExchangeData::CONVERT_FILENAMES) {
+ *url = test_url;
+ *title = base::string16();
+ return true;
+ }
}
-
- *url = GURL(tokens[0]);
- *title = base::string16();
-
- return true;
}
}
@@ -230,14 +287,36 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
}
bool OSExchangeDataProviderAuraX11::GetFilename(base::FilePath* path) const {
- // On X11, files are passed by URL and aren't separate.
+ std::vector<FileInfo> filenames;
+ if (GetFilenames(&filenames)) {
+ *path = filenames.front().path;
+ return true;
+ }
+
return false;
}
bool OSExchangeDataProviderAuraX11::GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const {
- // On X11, files are passed by URL and aren't separate.
- return false;
+ std::vector<FileInfo>* filenames) const {
+ std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
+ std::vector< ::Atom> requested_types;
+ ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
+
+ filenames->clear();
+ ui::SelectionData data(format_map_.GetFirstOf(requested_types));
+ if (data.IsValid()) {
+ std::vector<std::string> tokens = ui::ParseURIList(data);
+ for (std::vector<std::string>::const_iterator it = tokens.begin();
+ it != tokens.end(); ++it) {
+ GURL url(*it);
+ base::FilePath file_path;
+ if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) {
+ filenames->push_back(FileInfo(file_path, base::FilePath()));
+ }
+ }
+ }
+
+ return !filenames->empty();
}
bool OSExchangeDataProviderAuraX11::GetPickledData(
@@ -262,18 +341,65 @@ bool OSExchangeDataProviderAuraX11::HasString() const {
std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
std::vector< ::Atom> requested_types;
ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
- return !requested_types.empty();
+ return !requested_types.empty() && !HasFile();
}
-bool OSExchangeDataProviderAuraX11::HasURL() const {
+bool OSExchangeDataProviderAuraX11::HasURL(
+ OSExchangeData::FilenameToURLPolicy policy) const {
std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
std::vector< ::Atom> requested_types;
ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
- return !requested_types.empty();
+
+ if (requested_types.empty())
+ return false;
+
+ // The Linux desktop doesn't differentiate between files and URLs like
+ // Windows does and stuffs all the data into one mime type.
+ ui::SelectionData data(format_map_.GetFirstOf(requested_types));
+ if (data.IsValid()) {
+ if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) {
+ // File managers shouldn't be using this type, so this is a URL.
+ return true;
+ } else if (data.GetType() == atom_cache_.GetAtom(
+ ui::Clipboard::kMimeTypeURIList)) {
+ std::vector<std::string> tokens = ui::ParseURIList(data);
+ for (std::vector<std::string>::const_iterator it = tokens.begin();
+ it != tokens.end(); ++it) {
+ if (!GURL(*it).SchemeIsFile() ||
+ policy == OSExchangeData::CONVERT_FILENAMES)
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
}
bool OSExchangeDataProviderAuraX11::HasFile() const {
- // On X11, files are passed by URL and aren't separate.
+ std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
+ std::vector< ::Atom> requested_types;
+ ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
+
+ if (requested_types.empty())
+ return false;
+
+ // To actually answer whether we have a file, we need to look through the
+ // contents of the kMimeTypeURIList type, and see if any of them are file://
+ // URIs.
+ ui::SelectionData data(format_map_.GetFirstOf(requested_types));
+ if (data.IsValid()) {
+ std::vector<std::string> tokens = ui::ParseURIList(data);
+ for (std::vector<std::string>::const_iterator it = tokens.begin();
+ it != tokens.end(); ++it) {
+ GURL url(*it);
+ base::FilePath file_path;
+ if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
+ return true;
+ }
+ }
+
return false;
}
@@ -287,6 +413,42 @@ bool OSExchangeDataProviderAuraX11::HasCustomFormat(
return !requested_types.empty();
}
+void OSExchangeDataProviderAuraX11::SetFileContents(
+ const base::FilePath& filename,
+ const std::string& file_contents) {
+ DCHECK(!filename.empty());
+ DCHECK(format_map_.end() ==
+ format_map_.find(atom_cache_.GetAtom(kMimeTypeMozillaURL)));
+
+ file_contents_name_ = filename;
+
+ // Direct save handling is a complicated juggling affair between this class,
+ // SelectionFormat, and DesktopDragDropClientAuraX11. The general idea behind
+ // the protocol is this:
+ // - The source window sets its XdndDirectSave0 window property to the
+ // proposed filename.
+ // - When a target window receives the drop, it updates the XdndDirectSave0
+ // property on the source window to the filename it would like the contents
+ // to be saved to and then requests the XdndDirectSave0 type from the
+ // source.
+ // - The source is supposed to copy the file here and return success (S),
+ // failure (F), or error (E).
+ // - In this case, failure means the destination should try to populate the
+ // file itself by copying the data from application/octet-stream. To make
+ // things simpler for Chrome, we always 'fail' and let the destination do
+ // the work.
+ std::string failure("F");
+ format_map_.Insert(
+ atom_cache_.GetAtom("XdndDirectSave0"),
+ scoped_refptr<base::RefCountedMemory>(
+ base::RefCountedString::TakeString(&failure)));
+ std::string file_contents_copy = file_contents;
+ format_map_.Insert(
+ atom_cache_.GetAtom("application/octet-stream"),
+ scoped_refptr<base::RefCountedMemory>(
+ base::RefCountedString::TakeString(&file_contents_copy)));
+}
+
void OSExchangeDataProviderAuraX11::SetHtml(const base::string16& html,
const GURL& base_url) {
std::vector<unsigned char> bytes;
@@ -342,21 +504,26 @@ const gfx::Vector2d& OSExchangeDataProviderAuraX11::GetDragImageOffset() const {
return drag_image_offset_;
}
-bool OSExchangeDataProviderAuraX11::Dispatch(const base::NativeEvent& event) {
+bool OSExchangeDataProviderAuraX11::CanDispatchEvent(
+ const PlatformEvent& event) {
+ return event->xany.window == x_window_;
+}
+
+uint32_t OSExchangeDataProviderAuraX11::DispatchEvent(
+ const PlatformEvent& event) {
XEvent* xev = event;
switch (xev->type) {
case SelectionRequest:
selection_owner_.OnSelectionRequest(xev->xselectionrequest);
- break;
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
default:
NOTIMPLEMENTED();
}
-
- return true;
+ return ui::POST_DISPATCH_NONE;
}
bool OSExchangeDataProviderAuraX11::GetPlainTextURL(GURL* url) const {
- string16 text;
+ base::string16 text;
if (GetString(&text)) {
GURL test_url(text);
if (test_url.is_valid()) {
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 76cfad3a97c..702cc7e11e6 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.h
@@ -13,12 +13,12 @@
#include <map>
#include "base/files/file_path.h"
-#include "base/message_loop/message_pump_dispatcher.h"
#include "base/pickle.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/x/selection_owner.h"
#include "ui/base/x/selection_requestor.h"
#include "ui/base/x/selection_utils.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/vector2d.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -27,11 +27,12 @@
namespace ui {
class Clipboard;
+class OSExchangeDataProviderAuraX11Test;
// OSExchangeData::Provider implementation for aura on linux.
-class UI_EXPORT OSExchangeDataProviderAuraX11
+class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
: public OSExchangeData::Provider,
- public base::MessagePumpDispatcher {
+ public ui::PlatformEventDispatcher {
public:
// |x_window| is the window the cursor is over, and |selection| is the set of
// data being offered.
@@ -55,28 +56,38 @@ class UI_EXPORT OSExchangeDataProviderAuraX11
// Makes a copy of the format map currently being offered.
SelectionFormatMap GetFormatMap() const;
+ const base::FilePath& file_contents_name() const {
+ return file_contents_name_;
+ }
+
// Overridden from OSExchangeData::Provider:
virtual Provider* Clone() const OVERRIDE;
+ virtual void MarkOriginatedFromRenderer() OVERRIDE;
+ virtual bool DidOriginateFromRenderer() const OVERRIDE;
virtual void SetString(const base::string16& data) OVERRIDE;
virtual void SetURL(const GURL& url, const base::string16& title) OVERRIDE;
virtual void SetFilename(const base::FilePath& path) OVERRIDE;
- virtual void SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames) OVERRIDE;
+ virtual void SetFilenames(const std::vector<FileInfo>& filenames) OVERRIDE;
virtual void SetPickledData(const OSExchangeData::CustomFormat& format,
const Pickle& pickle) OVERRIDE;
virtual bool GetString(base::string16* data) const OVERRIDE;
- virtual bool GetURLAndTitle(GURL* url, base::string16* title) const OVERRIDE;
+ virtual bool GetURLAndTitle(OSExchangeData::FilenameToURLPolicy policy,
+ GURL* url,
+ base::string16* title) const OVERRIDE;
virtual bool GetFilename(base::FilePath* path) const OVERRIDE;
- virtual bool GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const OVERRIDE;
+ virtual bool GetFilenames(std::vector<FileInfo>* filenames) const OVERRIDE;
virtual bool GetPickledData(const OSExchangeData::CustomFormat& format,
Pickle* pickle) const OVERRIDE;
virtual bool HasString() const OVERRIDE;
- virtual bool HasURL() const OVERRIDE;
+ virtual bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const
+ OVERRIDE;
virtual bool HasFile() const OVERRIDE;
virtual bool HasCustomFormat(const OSExchangeData::CustomFormat& format) const
OVERRIDE;
+ virtual void SetFileContents(const base::FilePath& filename,
+ const std::string& file_contents) OVERRIDE;
+
virtual void SetHtml(const base::string16& html,
const GURL& base_url) OVERRIDE;
virtual bool GetHtml(base::string16* html, GURL* base_url) const OVERRIDE;
@@ -86,10 +97,12 @@ class UI_EXPORT OSExchangeDataProviderAuraX11
virtual const gfx::ImageSkia& GetDragImage() const OVERRIDE;
virtual const gfx::Vector2d& GetDragImageOffset() const OVERRIDE;
- // Overridden from base::MessagePumpDispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
private:
+ friend class OSExchangeDataProviderAuraX11Test;
typedef std::map<OSExchangeData::CustomFormat, Pickle> PickleData;
// Returns true if |formats_| contains a string format and the string can be
@@ -124,6 +137,9 @@ class UI_EXPORT OSExchangeDataProviderAuraX11
// to |selection_owner_| when we take the selection.
SelectionFormatMap format_map_;
+ // Auxilary data for the X Direct Save protocol.
+ base::FilePath file_contents_name_;
+
// Takes a snapshot of |format_map_| and offers it to other windows.
mutable SelectionOwner selection_owner_;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
index 0f5a914d75b..457ba6b41f7 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
@@ -12,34 +12,117 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/dragdrop/file_info.h"
+#include "ui/events/platform/x11/x11_event_source.h"
#include "url/gurl.h"
+const char kFileURL[] = "file:///home/user/file.txt";
+const char kFileName[] = "/home/user/file.txt";
const char kGoogleTitle[] = "Google";
const char kGoogleURL[] = "http://www.google.com/";
-TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) {
+namespace ui {
+
+class OSExchangeDataProviderAuraX11Test : public testing::Test {
+ public:
+ OSExchangeDataProviderAuraX11Test() : event_source(gfx::GetXDisplay()) {}
+
+ void AddURLList(const std::string& list_contents) {
+ std::string contents_copy = list_contents;
+ scoped_refptr<base::RefCountedMemory> mem(
+ base::RefCountedString::TakeString(&contents_copy));
+
+ provider.format_map_.Insert(
+ provider.atom_cache_.GetAtom(ui::Clipboard::kMimeTypeURIList),
+ mem);
+ }
+
+ protected:
base::MessageLoopForUI message_loop;
+ X11EventSource event_source;
ui::OSExchangeDataProviderAuraX11 provider;
+};
+TEST_F(OSExchangeDataProviderAuraX11Test, MozillaURL) {
// Check that we can get titled entries.
- provider.SetURL(GURL(kGoogleURL), ASCIIToUTF16(kGoogleTitle));
+ provider.SetURL(GURL(kGoogleURL), base::ASCIIToUTF16(kGoogleTitle));
{
GURL out_gurl;
base::string16 out_str;
EXPECT_TRUE(provider.GetURLAndTitle(
OSExchangeData::DO_NOT_CONVERT_FILENAMES, &out_gurl, &out_str));
- EXPECT_EQ(ASCIIToUTF16(kGoogleTitle), out_str);
+ EXPECT_EQ(base::ASCIIToUTF16(kGoogleTitle), out_str);
EXPECT_EQ(kGoogleURL, out_gurl.spec());
}
// Check that we can get non-titled entries.
- provider.SetURL(GURL(kGoogleURL), string16());
+ provider.SetURL(GURL(kGoogleURL), base::string16());
{
GURL out_gurl;
base::string16 out_str;
EXPECT_TRUE(provider.GetURLAndTitle(
OSExchangeData::DO_NOT_CONVERT_FILENAMES, &out_gurl, &out_str));
- EXPECT_EQ(string16(), out_str);
+ EXPECT_EQ(base::string16(), out_str);
EXPECT_EQ(kGoogleURL, out_gurl.spec());
}
}
+
+TEST_F(OSExchangeDataProviderAuraX11Test, FilesArentURLs) {
+ AddURLList(kFileURL);
+
+ EXPECT_TRUE(provider.HasFile());
+ EXPECT_TRUE(provider.HasURL(ui::OSExchangeData::CONVERT_FILENAMES));
+ EXPECT_FALSE(provider.HasURL(ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+}
+
+TEST_F(OSExchangeDataProviderAuraX11Test, HTTPURLsArentFiles) {
+ AddURLList(kGoogleURL);
+
+ EXPECT_FALSE(provider.HasFile());
+ EXPECT_TRUE(provider.HasURL(ui::OSExchangeData::CONVERT_FILENAMES));
+ EXPECT_TRUE(provider.HasURL(ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+}
+
+TEST_F(OSExchangeDataProviderAuraX11Test, URIListWithBoth) {
+ AddURLList("file:///home/user/file.txt\nhttp://www.google.com");
+
+ EXPECT_TRUE(provider.HasFile());
+ EXPECT_TRUE(provider.HasURL(ui::OSExchangeData::CONVERT_FILENAMES));
+ EXPECT_TRUE(provider.HasURL(ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+
+ // We should only receive the file from GetFilenames().
+ std::vector<FileInfo> filenames;
+ EXPECT_TRUE(provider.GetFilenames(&filenames));
+ ASSERT_EQ(1u, filenames.size());
+ EXPECT_EQ(kFileName, filenames[0].path.value());
+
+ // We should only receive the URL here.
+ GURL out_gurl;
+ base::string16 out_str;
+ EXPECT_TRUE(provider.GetURLAndTitle(
+ OSExchangeData::DO_NOT_CONVERT_FILENAMES, &out_gurl, &out_str));
+ EXPECT_EQ(base::string16(), out_str);
+ EXPECT_EQ(kGoogleURL, out_gurl.spec());
+}
+
+TEST_F(OSExchangeDataProviderAuraX11Test, OnlyStringURLIsUnfiltered) {
+ const base::string16 file_url = base::UTF8ToUTF16(kFileURL);
+ provider.SetString(file_url);
+
+ EXPECT_TRUE(provider.HasString());
+ EXPECT_FALSE(provider.HasURL(ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+}
+
+TEST_F(OSExchangeDataProviderAuraX11Test, StringAndURIListFilterString) {
+ const base::string16 file_url = base::UTF8ToUTF16(kFileURL);
+ provider.SetString(file_url);
+ AddURLList(kFileURL);
+
+ EXPECT_FALSE(provider.HasString());
+ base::string16 out_str;
+ EXPECT_FALSE(provider.GetString(&out_str));
+
+ EXPECT_TRUE(provider.HasFile());
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h
new file mode 100644
index 00000000000..513239f6656
--- /dev/null
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_DRAGDROP_OS_EXCHANGE_DATA_PROVIDER_MAC_H_
+#define UI_BASE_DRAGDROP_OS_EXCHANGE_DATA_PROVIDER_MAC_H_
+
+#include "ui/base/dragdrop/os_exchange_data.h"
+
+namespace ui {
+
+// OSExchangeData::Provider implementation for Mac.
+class UI_BASE_EXPORT OSExchangeDataProviderMac
+ : public OSExchangeData::Provider {
+ public:
+ OSExchangeDataProviderMac();
+ virtual ~OSExchangeDataProviderMac();
+
+ // Overridden from OSExchangeData::Provider:
+ virtual Provider* Clone() const OVERRIDE;
+ virtual void MarkOriginatedFromRenderer() OVERRIDE;
+ virtual bool DidOriginateFromRenderer() const OVERRIDE;
+ virtual void SetString(const base::string16& data) OVERRIDE;
+ virtual void SetURL(const GURL& url, const base::string16& title) OVERRIDE;
+ virtual void SetFilename(const base::FilePath& path) OVERRIDE;
+ virtual void SetFilenames(const std::vector<FileInfo>& filenames) OVERRIDE;
+ virtual void SetPickledData(const OSExchangeData::CustomFormat& format,
+ const Pickle& data) OVERRIDE;
+ virtual bool GetString(base::string16* data) const OVERRIDE;
+ virtual bool GetURLAndTitle(OSExchangeData::FilenameToURLPolicy policy,
+ GURL* url,
+ base::string16* title) const OVERRIDE;
+ virtual bool GetFilename(base::FilePath* path) const OVERRIDE;
+ virtual bool GetFilenames(std::vector<FileInfo>* filenames) const OVERRIDE;
+ virtual bool GetPickledData(const OSExchangeData::CustomFormat& format,
+ Pickle* data) const OVERRIDE;
+ virtual bool HasString() const OVERRIDE;
+ virtual bool HasURL(
+ OSExchangeData::FilenameToURLPolicy policy) const OVERRIDE;
+ virtual bool HasFile() const OVERRIDE;
+ virtual bool HasCustomFormat(
+ const OSExchangeData::CustomFormat& format) const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OSExchangeDataProviderMac);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_DRAGDROP_OS_EXCHANGE_DATA_PROVIDER_MAC_H_
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
new file mode 100644
index 00000000000..e8e60c3942c
--- /dev/null
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -0,0 +1,116 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/dragdrop/os_exchange_data_provider_mac.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+OSExchangeDataProviderMac::OSExchangeDataProviderMac() {
+}
+
+OSExchangeDataProviderMac::~OSExchangeDataProviderMac() {
+}
+
+OSExchangeData::Provider* OSExchangeDataProviderMac::Clone() const {
+ NOTIMPLEMENTED();
+ return new OSExchangeDataProviderMac();
+}
+
+void OSExchangeDataProviderMac::MarkOriginatedFromRenderer() {
+ NOTIMPLEMENTED();
+}
+
+bool OSExchangeDataProviderMac::DidOriginateFromRenderer() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void OSExchangeDataProviderMac::SetString(const base::string16& string) {
+ NOTIMPLEMENTED();
+}
+
+void OSExchangeDataProviderMac::SetURL(const GURL& url,
+ const base::string16& title) {
+ NOTIMPLEMENTED();
+}
+
+void OSExchangeDataProviderMac::SetFilename(const base::FilePath& path) {
+ NOTIMPLEMENTED();
+}
+
+void OSExchangeDataProviderMac::SetFilenames(
+ const std::vector<FileInfo>& filenames) {
+ NOTIMPLEMENTED();
+}
+
+void OSExchangeDataProviderMac::SetPickledData(
+ const OSExchangeData::CustomFormat& format,
+ const Pickle& data) {
+ NOTIMPLEMENTED();
+}
+
+bool OSExchangeDataProviderMac::GetString(base::string16* data) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::GetURLAndTitle(
+ OSExchangeData::FilenameToURLPolicy policy,
+ GURL* url,
+ base::string16* title) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::GetFilename(base::FilePath* path) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::GetFilenames(
+ std::vector<FileInfo>* filenames) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::GetPickledData(
+ const OSExchangeData::CustomFormat& format,
+ Pickle* data) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::HasString() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::HasURL(
+ OSExchangeData::FilenameToURLPolicy policy) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::HasFile() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool OSExchangeDataProviderMac::HasCustomFormat(
+ const OSExchangeData::CustomFormat& format) const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OSExchangeData, public:
+
+// static
+OSExchangeData::Provider* OSExchangeData::CreateProvider() {
+ return new OSExchangeDataProviderMac;
+}
+
+} // namespace ui
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 2bc3e19df81..4cbfa4a8512 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -10,19 +10,27 @@
#include "base/files/file_path.h"
#include "base/i18n/file_util_icu.h"
#include "base/logging.h"
-#include "base/memory/scoped_handle.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hglobal.h"
#include "grit/ui_strings.h"
-#include "net/base/net_util.h"
+#include "net/base/filename_util.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_util_win.h"
+#include "ui/base/dragdrop/file_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
namespace ui {
+static const OSExchangeData::CustomFormat& GetRendererTaintCustomType() {
+ CR_DEFINE_STATIC_LOCAL(
+ ui::OSExchangeData::CustomFormat,
+ format,
+ (ui::Clipboard::GetFormatType("chromium/x-renderer-taint")));
+ return format;
+}
+
// Creates a new STGMEDIUM object to hold the specified text. The caller
// owns the resulting object. The "Bytes" version does not NULL terminate, the
// string version does.
@@ -55,7 +63,7 @@ static STGMEDIUM* GetStorageForFileDescriptor(const base::FilePath& path);
// some sort of sequential data (why not just use an array?). See comments
// throughout.
//
-class FormatEtcEnumerator : public IEnumFORMATETC {
+class FormatEtcEnumerator FINAL : public IEnumFORMATETC {
public:
FormatEtcEnumerator(DataObjectImpl::StoredData::const_iterator begin,
DataObjectImpl::StoredData::const_iterator end);
@@ -269,13 +277,23 @@ OSExchangeData::Provider* OSExchangeDataProviderWin::Clone() const {
return new OSExchangeDataProviderWin(data_object());
}
+void OSExchangeDataProviderWin::MarkOriginatedFromRenderer() {
+ STGMEDIUM* storage = GetStorageForString(std::string());
+ data_->contents_.push_back(new DataObjectImpl::StoredDataInfo(
+ GetRendererTaintCustomType().ToFormatEtc(), storage));
+}
+
+bool OSExchangeDataProviderWin::DidOriginateFromRenderer() const {
+ return HasCustomFormat(GetRendererTaintCustomType());
+}
+
void OSExchangeDataProviderWin::SetString(const base::string16& data) {
STGMEDIUM* storage = GetStorageForString(data);
data_->contents_.push_back(new DataObjectImpl::StoredDataInfo(
Clipboard::GetPlainTextWFormatType().ToFormatEtc(), storage));
// Also add the UTF8-encoded version.
- storage = GetStorageForString(UTF16ToUTF8(data));
+ storage = GetStorageForString(base::UTF16ToUTF8(data));
data_->contents_.push_back(new DataObjectImpl::StoredDataInfo(
Clipboard::GetPlainTextFormatType().ToFormatEtc(), storage));
}
@@ -289,7 +307,7 @@ void OSExchangeDataProviderWin::SetURL(const GURL& url,
// will fail! It assumes an insertion order.
// Add text/x-moz-url for drags from Firefox
- base::string16 x_moz_url_str = UTF8ToUTF16(url.spec());
+ base::string16 x_moz_url_str = base::UTF8ToUTF16(url.spec());
x_moz_url_str += '\n';
x_moz_url_str += title;
STGMEDIUM* storage = GetStorageForString(x_moz_url_str);
@@ -304,7 +322,7 @@ void OSExchangeDataProviderWin::SetURL(const GURL& url,
SetFileContents(base::FilePath(valid_file_name), shortcut_url_file_contents);
// Add a UniformResourceLocator link for apps like IE and Word.
- storage = GetStorageForString(UTF8ToUTF16(url.spec()));
+ storage = GetStorageForString(base::UTF8ToUTF16(url.spec()));
data_->contents_.push_back(new DataObjectImpl::StoredDataInfo(
Clipboard::GetUrlWFormatType().ToFormatEtc(), storage));
storage = GetStorageForString(url.spec());
@@ -316,7 +334,7 @@ void OSExchangeDataProviderWin::SetURL(const GURL& url,
// Also add text representations (these should be last since they're the
// least preferable).
- SetString(UTF8ToUTF16(url.spec()));
+ SetString(base::UTF8ToUTF16(url.spec()));
}
void OSExchangeDataProviderWin::SetFilename(const base::FilePath& path) {
@@ -334,7 +352,7 @@ void OSExchangeDataProviderWin::SetFilename(const base::FilePath& path) {
}
void OSExchangeDataProviderWin::SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames) {
+ const std::vector<FileInfo>& filenames) {
for (size_t i = 0; i < filenames.size(); ++i) {
STGMEDIUM* storage = GetStorageForFileName(filenames[i].path);
DataObjectImpl::StoredDataInfo* info = new DataObjectImpl::StoredDataInfo(
@@ -368,7 +386,7 @@ void OSExchangeDataProviderWin::SetFileContents(
void OSExchangeDataProviderWin::SetHtml(const base::string16& html,
const GURL& base_url) {
// Add both MS CF_HTML and text/html format. CF_HTML should be in utf-8.
- std::string utf8_html = UTF16ToUTF8(html);
+ std::string utf8_html = base::UTF16ToUTF8(html);
std::string url = base_url.is_valid() ? base_url.spec() : std::string();
std::string cf_html = ClipboardUtil::HtmlToCFHtml(utf8_html, url);
@@ -421,14 +439,13 @@ bool OSExchangeDataProviderWin::GetFilename(base::FilePath* path) const {
}
bool OSExchangeDataProviderWin::GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const {
+ std::vector<FileInfo>* filenames) const {
std::vector<base::string16> filenames_local;
bool success = ClipboardUtil::GetFilenames(source_object_, &filenames_local);
if (success) {
for (size_t i = 0; i < filenames_local.size(); ++i)
filenames->push_back(
- OSExchangeData::FileInfo(base::FilePath(filenames_local[i]),
- base::FilePath()));
+ FileInfo(base::FilePath(filenames_local[i]), base::FilePath()));
}
return success;
}
@@ -477,8 +494,11 @@ bool OSExchangeDataProviderWin::HasString() const {
return ClipboardUtil::HasPlainText(source_object_);
}
-bool OSExchangeDataProviderWin::HasURL() const {
- return (ClipboardUtil::HasUrl(source_object_) ||
+bool OSExchangeDataProviderWin::HasURL(
+ OSExchangeData::FilenameToURLPolicy policy) const {
+ return (ClipboardUtil::HasUrl(
+ source_object_,
+ policy == OSExchangeData::CONVERT_FILENAMES ? true : false) ||
HasPlainTextURL(source_object_));
}
@@ -517,12 +537,6 @@ void OSExchangeDataProviderWin::SetDownloadFileInfo(
data_->contents_.push_back(info);
}
-void OSExchangeDataProviderWin::SetInDragLoop(bool in_drag_loop) {
- data_->set_in_drag_loop(in_drag_loop);
-}
-
-#if defined(USE_AURA)
-
void OSExchangeDataProviderWin::SetDragImage(
const gfx::ImageSkia& image,
const gfx::Vector2d& cursor_offset) {
@@ -538,8 +552,6 @@ const gfx::Vector2d& OSExchangeDataProviderWin::GetDragImageOffset() const {
return drag_image_offset_;
}
-#endif
-
///////////////////////////////////////////////////////////////////////////////
// DataObjectImpl, IDataObject implementation:
@@ -881,7 +893,7 @@ template <typename T>
static STGMEDIUM* GetStorageForString(const std::basic_string<T>& data) {
return GetStorageForBytes(
data.c_str(),
- (data.size() + 1) * sizeof(std::basic_string<T>::value_type));
+ (data.size() + 1) * sizeof(typename std::basic_string<T>::value_type));
}
static void GetInternetShortcutFileContents(const GURL& url,
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
index 74c6d2339e1..a89deb27a9d 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
@@ -21,7 +21,7 @@
#include "base/memory/scoped_vector.h"
#include "base/win/scoped_comptr.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/vector2d.h"
@@ -124,7 +124,8 @@ class DataObjectImpl : public DownloadFileObserver,
Observer* observer_;
};
-class UI_EXPORT OSExchangeDataProviderWin : public OSExchangeData::Provider {
+class UI_BASE_EXPORT OSExchangeDataProviderWin
+ : public OSExchangeData::Provider {
public:
// Returns true if source has plain text that is a valid url.
static bool HasPlainTextURL(IDataObject* source);
@@ -148,11 +149,12 @@ class UI_EXPORT OSExchangeDataProviderWin : public OSExchangeData::Provider {
// OSExchangeData::Provider methods.
virtual Provider* Clone() const;
+ virtual void MarkOriginatedFromRenderer();
+ virtual bool DidOriginateFromRenderer() const;
virtual void SetString(const base::string16& data);
virtual void SetURL(const GURL& url, const base::string16& title);
virtual void SetFilename(const base::FilePath& path);
- virtual void SetFilenames(
- const std::vector<OSExchangeData::FileInfo>& filenames);
+ virtual void SetFilenames(const std::vector<FileInfo>& filenames);
virtual void SetPickledData(const OSExchangeData::CustomFormat& format,
const Pickle& data);
virtual void SetFileContents(const base::FilePath& filename,
@@ -164,15 +166,14 @@ class UI_EXPORT OSExchangeDataProviderWin : public OSExchangeData::Provider {
GURL* url,
base::string16* title) const;
virtual bool GetFilename(base::FilePath* path) const;
- virtual bool GetFilenames(
- std::vector<OSExchangeData::FileInfo>* filenames) const;
+ virtual bool GetFilenames(std::vector<FileInfo>* filenames) const;
virtual bool GetPickledData(const OSExchangeData::CustomFormat& format,
Pickle* data) const;
virtual bool GetFileContents(base::FilePath* filename,
std::string* file_contents) const;
virtual bool GetHtml(base::string16* html, GURL* base_url) const;
virtual bool HasString() const;
- virtual bool HasURL() const;
+ virtual bool HasURL(OSExchangeData::FilenameToURLPolicy policy) const;
virtual bool HasFile() const;
virtual bool HasFileContents() const;
virtual bool HasHtml() const;
@@ -180,23 +181,18 @@ class UI_EXPORT OSExchangeDataProviderWin : public OSExchangeData::Provider {
const OSExchangeData::CustomFormat& format) const;
virtual void SetDownloadFileInfo(
const OSExchangeData::DownloadFileInfo& download_info);
- virtual void SetInDragLoop(bool in_drag_loop) OVERRIDE;
-#if defined(USE_AURA)
virtual void SetDragImage(const gfx::ImageSkia& image,
const gfx::Vector2d& cursor_offset) OVERRIDE;
virtual const gfx::ImageSkia& GetDragImage() const OVERRIDE;
virtual const gfx::Vector2d& GetDragImageOffset() const OVERRIDE;
-#endif
private:
scoped_refptr<DataObjectImpl> data_;
base::win::ScopedComPtr<IDataObject> source_object_;
-#if defined(USE_AURA)
// Drag image and offset data. Only used for Ash.
gfx::ImageSkia drag_image_;
gfx::Vector2d drag_image_offset_;
-#endif
DISALLOW_COPY_AND_ASSIGN(OSExchangeDataProviderWin);
};
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
index 32f89bb9b1e..41dd43a6923 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_unittest.cc
@@ -8,27 +8,33 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/events/platform/platform_event_source.h"
#include "url/gurl.h"
namespace ui {
class OSExchangeDataTest : public PlatformTest {
+ public:
+ OSExchangeDataTest()
+ : event_source_(ui::PlatformEventSource::CreateDefault()) {}
+
private:
base::MessageLoopForUI message_loop_;
+ scoped_ptr<PlatformEventSource> event_source_;
};
TEST_F(OSExchangeDataTest, StringDataGetAndSet) {
OSExchangeData data;
- string16 input = ASCIIToUTF16("I can has cheezburger?");
+ base::string16 input = base::ASCIIToUTF16("I can has cheezburger?");
data.SetString(input);
OSExchangeData data2(data.provider().Clone());
- string16 output;
+ base::string16 output;
EXPECT_TRUE(data2.GetString(&output));
EXPECT_EQ(input, output);
std::string url_spec = "http://www.goats.com/";
GURL url(url_spec);
- string16 title;
+ base::string16 title;
EXPECT_FALSE(
data2.GetURLAndTitle(OSExchangeData::CONVERT_FILENAMES, &url, &title));
// No URLs in |data|, so url should be untouched.
@@ -39,24 +45,24 @@ TEST_F(OSExchangeDataTest, TestURLExchangeFormats) {
OSExchangeData data;
std::string url_spec = "http://www.google.com/";
GURL url(url_spec);
- string16 url_title = ASCIIToUTF16("www.google.com");
+ base::string16 url_title = base::ASCIIToUTF16("www.google.com");
data.SetURL(url, url_title);
- string16 output;
+ base::string16 output;
OSExchangeData data2(data.provider().Clone());
// URL spec and title should match
GURL output_url;
- string16 output_title;
+ base::string16 output_title;
EXPECT_TRUE(data2.GetURLAndTitle(
OSExchangeData::CONVERT_FILENAMES, &output_url, &output_title));
EXPECT_EQ(url_spec, output_url.spec());
EXPECT_EQ(url_title, output_title);
- string16 output_string;
+ base::string16 output_string;
// URL should be the raw text response
EXPECT_TRUE(data2.GetString(&output_string));
- EXPECT_EQ(url_spec, UTF16ToUTF8(output_string));
+ EXPECT_EQ(url_spec, base::UTF16ToUTF8(output_string));
}
TEST_F(OSExchangeDataTest, TestPickledData) {
@@ -82,19 +88,21 @@ TEST_F(OSExchangeDataTest, TestPickledData) {
EXPECT_EQ(2, value);
}
+#if defined(USE_AURA)
TEST_F(OSExchangeDataTest, TestHTML) {
OSExchangeData data;
GURL url("http://www.google.com/");
- string16 html = ASCIIToUTF16(
+ base::string16 html = base::ASCIIToUTF16(
"<HTML>\n<BODY>\n"
"<b>bold.</b> <i><b>This is bold italic.</b></i>\n"
"</BODY>\n</HTML>");
data.SetHtml(html, url);
OSExchangeData copy(data.provider().Clone());
- string16 read_html;
+ base::string16 read_html;
EXPECT_TRUE(copy.GetHtml(&read_html, &url));
EXPECT_EQ(html, read_html);
}
+#endif
} // namespace ui
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
index 420254337bf..7c5876fe84a 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_handle.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hglobal.h"
@@ -62,10 +61,11 @@ TEST(OSExchangeDataWinTest, StringDataWritingViaCOM) {
// Construct a new object with the old object so that we can use our access
// APIs.
OSExchangeData data2(data.provider().Clone());
- EXPECT_TRUE(data2.HasURL());
+ EXPECT_TRUE(data2.HasURL(OSExchangeData::CONVERT_FILENAMES));
GURL url_from_data;
std::wstring title;
- EXPECT_TRUE(data2.GetURLAndTitle(&url_from_data, &title));
+ EXPECT_TRUE(data2.GetURLAndTitle(
+ OSExchangeData::CONVERT_FILENAMES, &url_from_data, &title));
GURL reference_url(input);
EXPECT_EQ(reference_url.spec(), url_from_data.spec());
}
@@ -113,10 +113,11 @@ TEST(OSExchangeDataWinTest, RemoveData) {
// Construct a new object with the old object so that we can use our access
// APIs.
OSExchangeData data2(data.provider().Clone());
- EXPECT_TRUE(data2.HasURL());
+ EXPECT_TRUE(data2.HasURL(OSExchangeData::CONVERT_FILENAMES));
GURL url_from_data;
std::wstring title;
- EXPECT_TRUE(data2.GetURLAndTitle(&url_from_data, &title));
+ EXPECT_TRUE(data2.GetURLAndTitle(
+ OSExchangeData::CONVERT_FILENAMES, &url_from_data, &title));
EXPECT_EQ(GURL(input2).spec(), url_from_data.spec());
}
@@ -136,7 +137,7 @@ TEST(OSExchangeDataWinTest, URLDataAccessViaCOM) {
EXPECT_EQ(S_OK, com_data->GetData(&format_etc, &medium));
std::wstring output =
base::win::ScopedHGlobal<wchar_t>(medium.hGlobal).get();
- EXPECT_EQ(url.spec(), WideToUTF8(output));
+ EXPECT_EQ(url.spec(), base::WideToUTF8(output));
ReleaseStgMedium(&medium);
}
@@ -163,7 +164,7 @@ TEST(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
EXPECT_EQ(S_OK, com_data->GetData(&url_format_etc, &medium));
std::wstring output_url =
base::win::ScopedHGlobal<wchar_t>(medium.hGlobal).get();
- EXPECT_EQ(url.spec(), WideToUTF8(output_url));
+ EXPECT_EQ(url.spec(), base::WideToUTF8(output_url));
ReleaseStgMedium(&medium);
// The text is supposed to be the raw text of the URL, _NOT_ the value of
@@ -171,7 +172,7 @@ TEST(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
EXPECT_EQ(S_OK, com_data->GetData(&text_format_etc, &medium));
std::wstring output_text =
base::win::ScopedHGlobal<wchar_t>(medium.hGlobal).get();
- EXPECT_EQ(url_spec, WideToUTF8(output_text));
+ EXPECT_EQ(url_spec, base::WideToUTF8(output_text));
ReleaseStgMedium(&medium);
}
@@ -321,7 +322,7 @@ TEST(OSExchangeDataWinTest, CFHtml) {
"StartFragment:0000000175\r\nEndFragment:0000000252\r\n"
"SourceURL:http://www.google.com/\r\n<html>\r\n<body>\r\n"
"<!--StartFragment-->");
- expected_cf_html += WideToUTF8(html);
+ expected_cf_html += base::WideToUTF8(html);
expected_cf_html.append("<!--EndFragment-->\r\n</body>\r\n</html>");
FORMATETC format = Clipboard::GetHtmlFormatType().ToFormatEtc();
@@ -345,10 +346,11 @@ TEST(OSExchangeDataWinTest, ProvideURLForPlainTextURL) {
data.SetString(L"http://google.com");
OSExchangeData data2(data.provider().Clone());
- ASSERT_TRUE(data2.HasURL());
+ ASSERT_TRUE(data2.HasURL(OSExchangeData::CONVERT_FILENAMES));
GURL read_url;
std::wstring title;
- EXPECT_TRUE(data2.GetURLAndTitle(&read_url, &title));
+ EXPECT_TRUE(data2.GetURLAndTitle(
+ OSExchangeData::CONVERT_FILENAMES, &read_url, &title));
EXPECT_EQ(GURL("http://google.com"), read_url);
}
diff --git a/chromium/ui/base/gtk/OWNERS b/chromium/ui/base/gtk/OWNERS
deleted file mode 100644
index 0573e6b64cb..00000000000
--- a/chromium/ui/base/gtk/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-erg@chromium.org
-estade@chromium.org
diff --git a/chromium/ui/base/gtk/event_synthesis_gtk.cc b/chromium/ui/base/gtk/event_synthesis_gtk.cc
deleted file mode 100644
index ea56162dd22..00000000000
--- a/chromium/ui/base/gtk/event_synthesis_gtk.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/event_synthesis_gtk.h"
-
-#include "ui/events/keycodes/keyboard_code_conversion_gtk.h"
-
-namespace ui {
-
-GdkEvent* SynthesizeKeyEvent(GdkWindow* window,
- bool press, guint gdk_key, guint state) {
- GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
-
- event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
- event->key.window = window;
- if (window)
- g_object_ref(window);
- event->key.send_event = false;
-
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- event->key.time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-
- event->key.state = state;
- event->key.keyval = gdk_key;
-
- GdkKeymapKey* keys;
- gint n_keys;
- if (event->key.keyval != 0 &&
- gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
- event->key.keyval, &keys, &n_keys)) {
- event->key.hardware_keycode = keys[0].keycode;
- event->key.group = keys[0].group;
- g_free(keys);
- }
-
- return event;
-}
-
-void SynthesizeKeyPressEvents(GdkWindow* window,
- KeyboardCode key,
- bool control, bool shift, bool alt,
- std::vector<GdkEvent*>* events) {
- if (control)
- events->push_back(
- SynthesizeKeyEvent(window, true, GDK_Control_L, 0));
-
- if (shift) {
- events->push_back(SynthesizeKeyEvent(window, true, GDK_Shift_L,
- control ? GDK_CONTROL_MASK : 0));
- }
-
- if (alt) {
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0);
- events->push_back(
- SynthesizeKeyEvent(window, true, GDK_Alt_L, state));
- }
-
- // TODO(estade): handle other state flags besides control, shift, alt?
- // For example caps lock.
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0) |
- (alt ? GDK_MOD1_MASK : 0);
-
- guint gdk_key = GdkKeyCodeForWindowsKeyCode(key, shift);
- events->push_back(SynthesizeKeyEvent(window, true, gdk_key, state));
- events->push_back(SynthesizeKeyEvent(window, false, gdk_key, state));
-
- if (alt) {
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0) | GDK_MOD1_MASK;
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Alt_L, state));
- }
-
- if (shift) {
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Shift_L,
- (control ? GDK_CONTROL_MASK : 0) | GDK_SHIFT_MASK));
- }
-
- if (control) {
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Control_L, GDK_CONTROL_MASK));
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/event_synthesis_gtk.h b/chromium/ui/base/gtk/event_synthesis_gtk.h
deleted file mode 100644
index 1839e29949a..00000000000
--- a/chromium/ui/base/gtk/event_synthesis_gtk.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This file declares routines for creating fake GDK events (at the moment,
-// only keyboard events). This is useful for a variety of testing purposes.
-// NOTE: This should not be used outside of testing.
-
-#ifndef UI_BASE_GTK_EVENT_SYNTHESIS_GTK_
-#define UI_BASE_GTK_EVENT_SYNTHESIS_GTK_
-
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <vector>
-
-#include "ui/base/ui_export.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-namespace ui {
-
-// Creates and returns a key event. Passes ownership to the caller.
-UI_EXPORT GdkEvent* SynthesizeKeyEvent(GdkWindow* event_window,
- bool press,
- guint gdk_key,
- guint state);
-
-// Creates the proper sequence of key events for a key press + release.
-// Ownership of the events in the vector is passed to the caller.
-UI_EXPORT void SynthesizeKeyPressEvents(
- GdkWindow* window,
- KeyboardCode key,
- bool control, bool shift, bool alt,
- std::vector<GdkEvent*>* events);
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_EVENT_SYNTHESIS_GTK_
diff --git a/chromium/ui/base/gtk/focus_store_gtk.cc b/chromium/ui/base/gtk/focus_store_gtk.cc
deleted file mode 100644
index 3af039d0175..00000000000
--- a/chromium/ui/base/gtk/focus_store_gtk.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/focus_store_gtk.h"
-
-#include <gtk/gtk.h>
-
-namespace ui {
-
-FocusStoreGtk::FocusStoreGtk()
- : widget_(NULL),
- destroy_handler_id_(0) {
-}
-
-FocusStoreGtk::~FocusStoreGtk() {
- DisconnectDestroyHandler();
-}
-
-void FocusStoreGtk::Store(GtkWidget* widget) {
- GtkWidget* focus_widget = NULL;
- if (widget) {
- // A detached widget won't have a toplevel window as an ancestor, so we
- // can't assume that the query for toplevel will return a window.
- GtkWidget* toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
- GtkWindow* window = GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : NULL;
- if (window)
- focus_widget = gtk_window_get_focus(window);
- }
-
- SetWidget(focus_widget);
-}
-
-void FocusStoreGtk::SetWidget(GtkWidget* widget) {
- DisconnectDestroyHandler();
-
- // We don't add a ref. The signal handler below effectively gives us a weak
- // reference.
- widget_ = widget;
- if (widget_) {
- // When invoked, |gtk_widget_destroyed| will set |widget_| to NULL.
- destroy_handler_id_ = g_signal_connect(widget_, "destroy",
- G_CALLBACK(gtk_widget_destroyed),
- &widget_);
- }
-}
-
-void FocusStoreGtk::DisconnectDestroyHandler() {
- if (widget_) {
- g_signal_handler_disconnect(widget_, destroy_handler_id_);
- widget_ = NULL;
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/focus_store_gtk.h b/chromium/ui/base/gtk/focus_store_gtk.h
deleted file mode 100644
index b0f420deea4..00000000000
--- a/chromium/ui/base/gtk/focus_store_gtk.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_FOCUS_STORE_GTK_H_
-#define UI_BASE_GTK_FOCUS_STORE_GTK_H_
-
-#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-namespace ui {
-
-class UI_EXPORT FocusStoreGtk {
- public:
- FocusStoreGtk();
- ~FocusStoreGtk();
-
- GtkWidget* widget() const { return widget_; }
-
- // Save the widget that is currently focused for |widget|'s toplevel (NOT
- // |widget|).
- void Store(GtkWidget* widget);
-
- // Save |widget| as the focus widget. Call with NULL to clear |widget_|.
- void SetWidget(GtkWidget* widget);
-
- private:
- // Disconnect the previous destroy handler (if any).
- void DisconnectDestroyHandler();
-
- // The widget which last had focus.
- GtkWidget* widget_;
-
- // The widget for which we've stored focus might be destroyed by the time we
- // want to restore focus. Thus we connect to the "destroy" signal on that
- // widget. This is the ID for the destroy handler.
- unsigned int destroy_handler_id_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusStoreGtk);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_FOCUS_STORE_GTK_H_
diff --git a/chromium/ui/base/gtk/g_object_destructor_filo.cc b/chromium/ui/base/gtk/g_object_destructor_filo.cc
deleted file mode 100644
index fe253c799b0..00000000000
--- a/chromium/ui/base/gtk/g_object_destructor_filo.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/g_object_destructor_filo.h"
-
-#include <glib-object.h>
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-
-namespace ui {
-
-GObjectDestructorFILO::GObjectDestructorFILO() {
-}
-
-GObjectDestructorFILO::~GObjectDestructorFILO() {
- // Probably CHECK(handler_map_.empty()) would look natural here. But
- // some tests (some views_unittests) violate this assertion.
-}
-
-// static
-GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() {
- return Singleton<GObjectDestructorFILO>::get();
-}
-
-void GObjectDestructorFILO::Connect(
- GObject* object, DestructorHook callback, void* context) {
- const Hook hook(object, callback, context);
- HandlerMap::iterator iter = handler_map_.find(object);
- if (iter == handler_map_.end()) {
- g_object_weak_ref(object, WeakNotifyThunk, this);
- handler_map_[object].push_front(hook);
- } else {
- iter->second.push_front(hook);
- }
-}
-
-void GObjectDestructorFILO::Disconnect(
- GObject* object, DestructorHook callback, void* context) {
- HandlerMap::iterator iter = handler_map_.find(object);
- if (iter == handler_map_.end()) {
- LOG(DFATAL) << "Unable to disconnect destructor hook for object " << object
- << ": hook not found (" << callback << ", " << context << ").";
- return;
- }
- HandlerList& dtors = iter->second;
- if (dtors.empty()) {
- LOG(DFATAL) << "Destructor list is empty for specified object " << object
- << " Maybe it is being executed?";
- return;
- }
- if (!dtors.front().equal(object, callback, context)) {
- // Reenable this warning once this bug is fixed:
- // http://code.google.com/p/chromium/issues/detail?id=85603
- DVLOG(1) << "Destructors should be unregistered the reverse order they "
- << "were registered. But for object " << object << " "
- << "deleted hook is "<< context << ", the last queued hook is "
- << dtors.front().context;
- }
- for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) {
- if (i->equal(object, callback, context)) {
- dtors.erase(i);
- break;
- }
- }
- if (dtors.empty()) {
- g_object_weak_unref(object, WeakNotifyThunk, this);
- handler_map_.erase(iter);
- }
-}
-
-void GObjectDestructorFILO::WeakNotify(GObject* where_the_object_was) {
- HandlerMap::iterator iter = handler_map_.find(where_the_object_was);
- DCHECK(iter != handler_map_.end());
- DCHECK(!iter->second.empty());
-
- // Save destructor list for given object into local copy to avoid reentrancy
- // problem: if callee wants to modify the caller list.
- HandlerList dtors;
- iter->second.swap(dtors);
- handler_map_.erase(iter);
-
- // Execute hooks in local list in FILO order.
- for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i)
- i->callback(i->context, where_the_object_was);
-}
-
-} // napespace ui
diff --git a/chromium/ui/base/gtk/g_object_destructor_filo.h b/chromium/ui/base/gtk/g_object_destructor_filo.h
deleted file mode 100644
index 76e41f7c046..00000000000
--- a/chromium/ui/base/gtk/g_object_destructor_filo.h
+++ /dev/null
@@ -1,91 +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_GTK_G_OBJECT_DESTRUCTOR_FILO_H_
-#define UI_BASE_GTK_G_OBJECT_DESTRUCTOR_FILO_H_
-
-#include <glib.h>
-#include <list>
-#include <map>
-
-#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-typedef struct _GObject GObject;
-
-namespace ui {
-
-// This class hooks calls to g_object_weak_ref()/unref() and executes them in
-// FILO order. This is important if there are several hooks to the single object
-// (set up at different levels of class hierarchy) and the lowest hook (set up
-// first) is deleting self - it must be called last (among hooks for the given
-// object). Unfortunately Glib does not provide this guarantee.
-//
-// Use it as follows:
-//
-// static void OnDestroyedThunk(gpointer data, GObject *where_the_object_was) {
-// reinterpret_cast<MyClass*>(data)->OnDestroyed(where_the_object_was);
-// }
-// void MyClass::OnDestroyed(GObject *where_the_object_was) {
-// destroyed_ = true;
-// delete this;
-// }
-// MyClass::Init() {
-// ...
-// ui::GObjectDestructorFILO::GetInstance()->Connect(
-// G_OBJECT(my_widget), &OnDestroyedThunk, this);
-// }
-// MyClass::~MyClass() {
-// if (!destroyed_) {
-// ui::GObjectDestructorFILO::GetInstance()->Disconnect(
-// G_OBJECT(my_widget), &OnDestroyedThunk, this);
-// }
-// }
-//
-// TODO(glotov): Probably worth adding ScopedGObjectDtor<T>.
-//
-// This class is a singleton. Not thread safe. Must be called within UI thread.
-class UI_EXPORT GObjectDestructorFILO {
- public:
- typedef void (*DestructorHook)(void* context, GObject* where_the_object_was);
-
- static GObjectDestructorFILO* GetInstance();
- void Connect(GObject* object, DestructorHook callback, void* context);
- void Disconnect(GObject* object, DestructorHook callback, void* context);
-
- private:
- struct Hook {
- Hook(GObject* o, DestructorHook cb, void* ctx)
- : object(o), callback(cb), context(ctx) {
- }
- bool equal(GObject* o, DestructorHook cb, void* ctx) const {
- return object == o && callback == cb && context == ctx;
- }
- GObject* object;
- DestructorHook callback;
- void* context;
- };
- typedef std::list<Hook> HandlerList;
- typedef std::map<GObject*, HandlerList> HandlerMap;
-
- GObjectDestructorFILO();
- ~GObjectDestructorFILO();
- friend struct DefaultSingletonTraits<GObjectDestructorFILO>;
-
- void WeakNotify(GObject* where_the_object_was);
- static void WeakNotifyThunk(gpointer data, GObject* where_the_object_was) {
- reinterpret_cast<GObjectDestructorFILO*>(data)->WeakNotify(
- where_the_object_was);
- }
-
- HandlerMap handler_map_;
-
- DISALLOW_COPY_AND_ASSIGN(GObjectDestructorFILO);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_G_OBJECT_DESTRUCTOR_FILO_H_
diff --git a/chromium/ui/base/gtk/gtk_expanded_container.cc b/chromium/ui/base/gtk/gtk_expanded_container.cc
deleted file mode 100644
index 6b39821d806..00000000000
--- a/chromium/ui/base/gtk/gtk_expanded_container.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_expanded_container.h"
-
-#include <gtk/gtk.h>
-
-#include <algorithm>
-
-#include "ui/gfx/gtk_compat.h"
-
-namespace {
-
-enum {
- CHILD_SIZE_REQUEST,
- LAST_SIGNAL
-};
-
-guint expanded_container_signals[LAST_SIGNAL] = { 0 };
-
-struct SizeAllocateData {
- GtkWidget* container;
- GtkAllocation* allocation;
- int border_width;
-};
-
-void GetChildPosition(GtkWidget* container, GtkWidget* child, int* x, int* y) {
- GValue v = { 0 };
- g_value_init(&v, G_TYPE_INT);
- gtk_container_child_get_property(GTK_CONTAINER(container), child, "x", &v);
- *x = g_value_get_int(&v);
- gtk_container_child_get_property(GTK_CONTAINER(container), child, "y", &v);
- *y = g_value_get_int(&v);
- g_value_unset(&v);
-}
-
-void ChildSizeAllocate(GtkWidget* child, gpointer userdata) {
- if (!gtk_widget_get_visible(child))
- return;
-
- SizeAllocateData* data = reinterpret_cast<SizeAllocateData*>(userdata);
-
- GtkRequisition child_requisition;
- child_requisition.width = data->allocation->width - data->border_width * 2;
- child_requisition.height = data->allocation->height - data->border_width * 2;
-
- // We need to give whoever is pulling our strings a chance to adjust the
- // size of our children.
- g_signal_emit(data->container,
- expanded_container_signals[CHILD_SIZE_REQUEST], 0,
- child, &child_requisition);
-
- GtkAllocation child_allocation;
- child_allocation.width = child_requisition.width;
- child_allocation.height = child_requisition.height;
- if (child_allocation.width < 0 || child_allocation.height < 0) {
- gtk_widget_get_child_requisition(child, &child_requisition);
- if (child_allocation.width < 0)
- child_allocation.width = child_requisition.width;
- if (child_allocation.height < 0)
- child_allocation.height = child_requisition.height;
- }
-
- int x, y;
- GetChildPosition(data->container, child, &x, &y);
-
- child_allocation.x = x + data->border_width;
- child_allocation.y = y + data->border_width;
-
- if (!gtk_widget_get_has_window(data->container)) {
- child_allocation.x += data->allocation->x;
- child_allocation.y += data->allocation->y;
- }
- gtk_widget_size_allocate(child, &child_allocation);
-}
-
-void Marshal_VOID__OBJECT_BOXED(GClosure* closure,
- GValue* return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue* param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data) {
- typedef void (*GMarshalFunc_VOID__OBJECT_BOXED) (gpointer data1,
- gpointer arg_1,
- gpointer arg_2,
- gpointer data2);
- register GMarshalFunc_VOID__OBJECT_BOXED callback;
- register GCClosure *cc = reinterpret_cast<GCClosure*>(closure);
- register gpointer data1, data2;
-
- g_return_if_fail(n_param_values == 3);
-
- if (G_CCLOSURE_SWAP_DATA(closure)) {
- data1 = closure->data;
- data2 = g_value_peek_pointer(param_values + 0);
- } else {
- data1 = g_value_peek_pointer(param_values + 0);
- data2 = closure->data;
- }
-
- callback = reinterpret_cast<GMarshalFunc_VOID__OBJECT_BOXED>(
- marshal_data ? marshal_data : cc->callback);
-
- callback(data1,
- g_value_get_object(param_values + 1),
- g_value_get_boxed(param_values + 2),
- data2);
-}
-
-} // namespace
-
-G_BEGIN_DECLS
-
-static void gtk_expanded_container_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation);
-
-G_DEFINE_TYPE(GtkExpandedContainer, gtk_expanded_container, GTK_TYPE_FIXED)
-
-static void gtk_expanded_container_class_init(
- GtkExpandedContainerClass *klass) {
- GtkObjectClass* object_class =
- reinterpret_cast<GtkObjectClass*>(klass);
-
- GtkWidgetClass* widget_class =
- reinterpret_cast<GtkWidgetClass*>(klass);
- widget_class->size_allocate = gtk_expanded_container_size_allocate;
-
- expanded_container_signals[CHILD_SIZE_REQUEST] =
- g_signal_new("child-size-request",
- G_OBJECT_CLASS_TYPE(object_class),
- static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST),
- 0,
- NULL, NULL,
- Marshal_VOID__OBJECT_BOXED,
- G_TYPE_NONE, 2,
- GTK_TYPE_WIDGET,
- GTK_TYPE_REQUISITION | G_SIGNAL_TYPE_STATIC_SCOPE);
-}
-
-static void gtk_expanded_container_init(GtkExpandedContainer* container) {
-}
-
-static void gtk_expanded_container_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- gtk_widget_set_allocation(widget, allocation);
-
- if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
- gdk_window_move_resize(gtk_widget_get_window(widget),
- allocation->x,
- allocation->y,
- allocation->width,
- allocation->height);
- }
-
- SizeAllocateData data;
- data.container = widget;
- data.allocation = allocation;
- data.border_width = gtk_container_get_border_width(GTK_CONTAINER(widget));
-
- gtk_container_foreach(GTK_CONTAINER(widget), ChildSizeAllocate, &data);
-}
-
-GtkWidget* gtk_expanded_container_new() {
- return GTK_WIDGET(g_object_new(GTK_TYPE_EXPANDED_CONTAINER, NULL));
-}
-
-void gtk_expanded_container_put(GtkExpandedContainer* container,
- GtkWidget* widget, gint x, gint y) {
- g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
- g_return_if_fail(GTK_IS_WIDGET(widget));
- gtk_fixed_put(GTK_FIXED(container), widget, x, y);
-}
-
-void gtk_expanded_container_move(GtkExpandedContainer* container,
- GtkWidget* widget, gint x, gint y) {
- g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
- g_return_if_fail(GTK_IS_WIDGET(widget));
- gtk_fixed_move(GTK_FIXED(container), widget, x, y);
-}
-
-void gtk_expanded_container_set_has_window(GtkExpandedContainer* container,
- gboolean has_window) {
- g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
- g_return_if_fail(!gtk_widget_get_realized(GTK_WIDGET(container)));
- gtk_widget_set_has_window(GTK_WIDGET(container), has_window);
-}
-
-gboolean gtk_expanded_container_get_has_window(
- GtkExpandedContainer* container) {
- g_return_val_if_fail(GTK_IS_EXPANDED_CONTAINER(container), FALSE);
- return gtk_widget_get_has_window(GTK_WIDGET(container));
-}
-
-G_END_DECLS
diff --git a/chromium/ui/base/gtk/gtk_expanded_container.h b/chromium/ui/base/gtk/gtk_expanded_container.h
deleted file mode 100644
index 63e3dbd1494..00000000000
--- a/chromium/ui/base/gtk/gtk_expanded_container.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
-#define UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/base/ui_export.h"
-
-// A specialized container derived from GtkFixed, which expands the size of its
-// children to fill the container, in one or both directions. The usage of this
-// container is similar to GtkFixed.
-//
-// The "child-size-request" signal is optional, if you want to expand child
-// widgets to customized size other than the container's size. It should have
-// the following signature:
-//
-// void (*child_size_request)(GtkExpandedContainer* container,
-// GtkWidget* child,
-// GtkRequisition* requisition);
-//
-// This signal is emitted for each child with the requisition set to the size of
-// the container. Your handler may adjust the value of the requisition. If the
-// width or height is set to -1, then that direction will not be expanded, and
-// the original size request of the child will be used.
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_EXPANDED_CONTAINER \
- (gtk_expanded_container_get_type())
-#define GTK_EXPANDED_CONTAINER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_EXPANDED_CONTAINER, \
- GtkExpandedContainer))
-#define GTK_EXPANDED_CONTAINER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_EXPANDED_CONTAINER, \
- GtkExpandedContainerClass))
-#define GTK_IS_EXPANDED_CONTAINER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_EXPANDED_CONTAINER))
-#define GTK_IS_EXPANDED_CONTAINER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_EXPANDED_CONTAINER))
-#define GTK_EXPANDED_CONTAINER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_EXPANDED_CONTAINER, \
- GtkExpandedContainerClass))
-
-typedef struct _GtkExpandedContainer GtkExpandedContainer;
-typedef struct _GtkExpandedContainerClass GtkExpandedContainerClass;
-
-struct _GtkExpandedContainer {
- // Parent class.
- GtkFixed fixed;
-};
-
-struct _GtkExpandedContainerClass {
- GtkFixedClass parent_class;
-};
-
-UI_EXPORT GType gtk_expanded_container_get_type() G_GNUC_CONST;
-UI_EXPORT GtkWidget* gtk_expanded_container_new();
-UI_EXPORT void gtk_expanded_container_put(GtkExpandedContainer* container,
- GtkWidget* widget, gint x, gint y);
-UI_EXPORT void gtk_expanded_container_move(GtkExpandedContainer* container,
- GtkWidget* widget, gint x, gint y);
-UI_EXPORT void gtk_expanded_container_set_has_window(
- GtkExpandedContainer* container,
- gboolean has_window);
-UI_EXPORT gboolean gtk_expanded_container_get_has_window(
- GtkExpandedContainer* container);
-
-G_END_DECLS
-
-#endif // UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
diff --git a/chromium/ui/base/gtk/gtk_expanded_container_unittest.cc b/chromium/ui/base/gtk/gtk_expanded_container_unittest.cc
deleted file mode 100644
index 532e58e5ca2..00000000000
--- a/chromium/ui/base/gtk/gtk_expanded_container_unittest.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_expanded_container.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define EXPECT_ALLOCATION_EQ(widget, x_, y_, width_, height_) \
-do { \
- GtkAllocation allocation; \
- gtk_widget_get_allocation(widget, &allocation); \
- EXPECT_EQ(x_, allocation.x); \
- EXPECT_EQ(y_, allocation.y); \
- EXPECT_EQ(width_, allocation.width); \
- EXPECT_EQ(height_, allocation.height); \
-} while(0);
-
-#define EXPECT_ALLOCATION_PARAM_EQ(widget, param, value) \
-do { \
- GtkAllocation allocation; \
- gtk_widget_get_allocation(widget, &allocation); \
- EXPECT_EQ(value,allocation.param); \
-} while(0);
-
-class GtkExpandedContainerTest : public testing::Test {
- protected:
- GtkExpandedContainerTest()
- : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
- expanded_(gtk_expanded_container_new()) {
- gtk_window_set_default_size(GTK_WINDOW(window_), 200, 200);
- gtk_container_add(GTK_CONTAINER(window_), expanded_);
- }
- virtual ~GtkExpandedContainerTest() {
- gtk_widget_destroy(window_);
- }
-
- bool FindChild(GtkWidget* widget) {
- GList* children = gtk_container_get_children(GTK_CONTAINER(expanded_));
- for (GList* child = children; child; child = child->next) {
- if (GTK_WIDGET(child->data) == widget) {
- g_list_free(children);
- return true;
- }
- }
- g_list_free(children);
- return false;
- }
-
- int GetChildX(GtkWidget* widget) {
- GValue x = { 0 };
- g_value_init(&x, G_TYPE_INT);
- gtk_container_child_get_property(GTK_CONTAINER(expanded_), widget, "x", &x);
- return g_value_get_int(&x);
- }
-
- int GetChildY(GtkWidget* widget) {
- GValue y = { 0 };
- g_value_init(&y, G_TYPE_INT);
- gtk_container_child_get_property(GTK_CONTAINER(expanded_), widget, "y", &y);
- return g_value_get_int(&y);
- }
-
- protected:
- GtkWidget* window_;
- GtkWidget* expanded_;
-};
-
-TEST_F(GtkExpandedContainerTest, AddRemove) {
- GtkWidget* child1 = gtk_fixed_new();
- GtkWidget* child2 = gtk_fixed_new();
- gtk_container_add(GTK_CONTAINER(expanded_), child1);
- ASSERT_TRUE(FindChild(child1));
-
- gtk_container_add(GTK_CONTAINER(expanded_), child2);
- ASSERT_TRUE(FindChild(child2));
- ASSERT_TRUE(FindChild(child1));
-
- gtk_container_remove(GTK_CONTAINER(expanded_), child1);
- ASSERT_FALSE(FindChild(child1));
- ASSERT_TRUE(FindChild(child2));
-
- gtk_container_remove(GTK_CONTAINER(expanded_), child2);
- ASSERT_FALSE(FindChild(child2));
-}
-
-TEST_F(GtkExpandedContainerTest, Expand) {
- GtkWidget* child1 = gtk_fixed_new();
- GtkWidget* child2 = gtk_fixed_new();
- gtk_container_add(GTK_CONTAINER(expanded_), child1);
- gtk_expanded_container_put(GTK_EXPANDED_CONTAINER(expanded_),
- child2, 10, 20);
- gtk_widget_show_all(window_);
-
- GtkAllocation allocation = { 0, 0, 50, 100 };
- gtk_widget_size_allocate(expanded_, &allocation);
-
- EXPECT_ALLOCATION_EQ(child1, 0, 0, 50, 100);
-
- EXPECT_ALLOCATION_EQ(child2, 10, 20, 50, 100);
-
- allocation.x = 10;
- allocation.y = 20;
- gtk_widget_size_allocate(expanded_, &allocation);
-
- EXPECT_ALLOCATION_PARAM_EQ(child1, x, 10);
- EXPECT_ALLOCATION_PARAM_EQ(child1, y, 20);
- EXPECT_ALLOCATION_PARAM_EQ(child2, x, 20);
- EXPECT_ALLOCATION_PARAM_EQ(child2, y, 40);
-}
-
-// Test if the size allocation for children still works when using own
-// GdkWindow. In this case, the children's origin starts from (0, 0) rather
-// than the container's origin.
-TEST_F(GtkExpandedContainerTest, HasWindow) {
- GtkWidget* child = gtk_fixed_new();
- gtk_container_add(GTK_CONTAINER(expanded_), child);
- gtk_expanded_container_set_has_window(GTK_EXPANDED_CONTAINER(expanded_),
- TRUE);
- gtk_widget_show_all(window_);
-
- GtkAllocation allocation = { 10, 10, 50, 100 };
- gtk_widget_size_allocate(expanded_, &allocation);
-
- EXPECT_ALLOCATION_EQ(child, 0, 0, 50, 100);
-}
-
-static void OnChildSizeRequest(GtkExpandedContainer* container,
- GtkWidget* child,
- GtkRequisition* requisition,
- gpointer userdata) {
- ASSERT_EQ(child, GTK_WIDGET(userdata));
- requisition->width = 250;
- requisition->height = -1;
-}
-
-TEST_F(GtkExpandedContainerTest, ChildSizeRequest) {
- GtkWidget* child = gtk_fixed_new();
- gtk_widget_set_size_request(child, 10, 25);
- g_signal_connect(expanded_, "child-size-request",
- G_CALLBACK(OnChildSizeRequest), child);
- gtk_container_add(GTK_CONTAINER(expanded_), child);
- gtk_widget_show_all(window_);
-
- GtkAllocation allocation = { 0, 0, 300, 100 };
- gtk_widget_size_allocate(expanded_, &allocation);
-
- EXPECT_ALLOCATION_EQ(child, 0, 0, 250, 25);
-}
-
-TEST_F(GtkExpandedContainerTest, ChildPosition) {
- GtkWidget* child = gtk_fixed_new();
- gtk_expanded_container_put(GTK_EXPANDED_CONTAINER(expanded_),
- child, 10, 20);
- gtk_widget_show_all(window_);
-
- EXPECT_EQ(10, GetChildX(child));
- EXPECT_EQ(20, GetChildY(child));
-
- gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(expanded_),
- child, 40, 50);
- EXPECT_EQ(40, GetChildX(child));
- EXPECT_EQ(50, GetChildY(child));
-}
diff --git a/chromium/ui/base/gtk/gtk_floating_container.cc b/chromium/ui/base/gtk/gtk_floating_container.cc
deleted file mode 100644
index dd1ac26b0a2..00000000000
--- a/chromium/ui/base/gtk/gtk_floating_container.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_floating_container.h"
-
-#include <gtk/gtk.h>
-
-#include <algorithm>
-
-#include "ui/gfx/gtk_compat.h"
-
-namespace {
-
-enum {
- SET_FLOATING_POSITION,
- LAST_SIGNAL
-};
-
-enum {
- CHILD_PROP_0,
- CHILD_PROP_X,
- CHILD_PROP_Y
-};
-
-// Returns the GtkFloatingContainerChild associated with |widget| (or NULL if
-// |widget| not found).
-GtkFloatingContainerChild* GetChild(GtkFloatingContainer* container,
- GtkWidget* widget) {
- for (GList* floating_children = container->floating_children;
- floating_children; floating_children = g_list_next(floating_children)) {
- GtkFloatingContainerChild* child =
- reinterpret_cast<GtkFloatingContainerChild*>(floating_children->data);
-
- if (child->widget == widget)
- return child;
- }
-
- return NULL;
-}
-
-const GParamFlags kStaticReadWriteProp = static_cast<GParamFlags>(
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-} // namespace
-
-G_BEGIN_DECLS
-
-static void gtk_floating_container_remove(GtkContainer* container,
- GtkWidget* widget);
-static void gtk_floating_container_forall(GtkContainer* container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data);
-static void gtk_floating_container_size_request(GtkWidget* widget,
- GtkRequisition* requisition);
-static void gtk_floating_container_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation);
-static void gtk_floating_container_set_child_property(GtkContainer* container,
- GtkWidget* child,
- guint property_id,
- const GValue* value,
- GParamSpec* pspec);
-static void gtk_floating_container_get_child_property(GtkContainer* container,
- GtkWidget* child,
- guint property_id,
- GValue* value,
- GParamSpec* pspec);
-
-static guint floating_container_signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE(GtkFloatingContainer, gtk_floating_container, GTK_TYPE_BIN)
-
-static void gtk_floating_container_class_init(
- GtkFloatingContainerClass *klass) {
- GtkObjectClass* object_class =
- reinterpret_cast<GtkObjectClass*>(klass);
-
- GtkWidgetClass* widget_class =
- reinterpret_cast<GtkWidgetClass*>(klass);
- widget_class->size_request = gtk_floating_container_size_request;
- widget_class->size_allocate = gtk_floating_container_size_allocate;
-
- GtkContainerClass* container_class =
- reinterpret_cast<GtkContainerClass*>(klass);
- container_class->remove = gtk_floating_container_remove;
- container_class->forall = gtk_floating_container_forall;
-
- container_class->set_child_property =
- gtk_floating_container_set_child_property;
- container_class->get_child_property =
- gtk_floating_container_get_child_property;
-
- gtk_container_class_install_child_property(
- container_class,
- CHILD_PROP_X,
- g_param_spec_int("x",
- "X position",
- "X position of child widget",
- G_MININT,
- G_MAXINT,
- 0,
- kStaticReadWriteProp));
-
- gtk_container_class_install_child_property(
- container_class,
- CHILD_PROP_Y,
- g_param_spec_int("y",
- "Y position",
- "Y position of child widget",
- G_MININT,
- G_MAXINT,
- 0,
- kStaticReadWriteProp));
-
- floating_container_signals[SET_FLOATING_POSITION] =
- g_signal_new("set-floating-position",
- G_OBJECT_CLASS_TYPE(object_class),
- static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST |
- G_SIGNAL_ACTION),
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1,
- GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
-}
-
-static void gtk_floating_container_init(GtkFloatingContainer* container) {
- gtk_widget_set_has_window(GTK_WIDGET(container), FALSE);
- container->floating_children = NULL;
-}
-
-static void gtk_floating_container_remove(GtkContainer* container,
- GtkWidget* widget) {
- g_return_if_fail(GTK_IS_WIDGET(widget));
-
- GtkBin* bin = GTK_BIN(container);
- if (gtk_bin_get_child(bin) == widget) {
- ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->remove)
- (container, widget);
- } else {
- // Handle the other case where it's in our |floating_children| list.
- GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container);
- GList* children = floating->floating_children;
- gboolean removed_child = false;
- while (children) {
- GtkFloatingContainerChild* child =
- reinterpret_cast<GtkFloatingContainerChild*>(children->data);
-
- if (child->widget == widget) {
- removed_child = true;
- gboolean was_visible = gtk_widget_get_visible(GTK_WIDGET(widget));
-
- gtk_widget_unparent(widget);
-
- floating->floating_children =
- g_list_remove_link(floating->floating_children, children);
- g_list_free(children);
- g_free(child);
-
- if (was_visible && gtk_widget_get_visible(GTK_WIDGET(container)))
- gtk_widget_queue_resize(GTK_WIDGET(container));
-
- break;
- }
- children = children->next;
- }
-
- g_return_if_fail(removed_child);
- }
-}
-
-static void gtk_floating_container_forall(GtkContainer* container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data) {
- g_return_if_fail(container != NULL);
- g_return_if_fail(callback != NULL);
-
- // Let GtkBin do its part of the forall.
- ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->forall)
- (container, include_internals, callback, callback_data);
-
- GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container);
- GList* children = floating->floating_children;
- while (children) {
- GtkFloatingContainerChild* child =
- reinterpret_cast<GtkFloatingContainerChild*>(children->data);
- children = children->next;
-
- (*callback)(child->widget, callback_data);
- }
-}
-
-static void gtk_floating_container_size_request(GtkWidget* widget,
- GtkRequisition* requisition) {
- GtkBin* bin = GTK_BIN(widget);
- if (bin && gtk_bin_get_child(bin)) {
- gtk_widget_size_request(gtk_bin_get_child(bin), requisition);
- } else {
- requisition->width = 0;
- requisition->height = 0;
- }
-}
-
-static void gtk_floating_container_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- gtk_widget_set_allocation(widget, allocation);
-
- if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
- gdk_window_move_resize(gtk_widget_get_window(widget),
- allocation->x,
- allocation->y,
- allocation->width,
- allocation->height);
- }
-
- // Give the same allocation to our GtkBin component.
- GtkBin* bin = GTK_BIN(widget);
- if (gtk_bin_get_child(bin)) {
- gtk_widget_size_allocate(gtk_bin_get_child(bin), allocation);
- }
-
- // We need to give whoever is pulling our strings a chance to set the "x" and
- // "y" properties on all of our children.
- g_signal_emit(widget, floating_container_signals[SET_FLOATING_POSITION], 0,
- allocation);
-
- // Our allocation has been set. We've asked our controller to place the other
- // widgets. Pass out allocations to all our children based on where they want
- // to be.
- GtkFloatingContainer* container = GTK_FLOATING_CONTAINER(widget);
- GList* children = container->floating_children;
- GtkAllocation child_allocation;
- GtkRequisition child_requisition;
- while (children) {
- GtkFloatingContainerChild* child =
- reinterpret_cast<GtkFloatingContainerChild*>(children->data);
- children = children->next;
-
- if (gtk_widget_get_visible(GTK_WIDGET(child->widget))) {
- gtk_widget_size_request(child->widget, &child_requisition);
- child_allocation.x = allocation->x + child->x;
- child_allocation.y = allocation->y + child->y;
- child_allocation.width = std::max(1, std::min(child_requisition.width,
- allocation->width));
- child_allocation.height = std::max(1, std::min(child_requisition.height,
- allocation->height));
- gtk_widget_size_allocate(child->widget, &child_allocation);
- }
- }
-}
-
-static void gtk_floating_container_set_child_property(GtkContainer* container,
- GtkWidget* child,
- guint property_id,
- const GValue* value,
- GParamSpec* pspec) {
- GtkFloatingContainerChild* floating_child =
- GetChild(GTK_FLOATING_CONTAINER(container), child);
- g_return_if_fail(floating_child);
-
- switch (property_id) {
- case CHILD_PROP_X:
- floating_child->x = g_value_get_int(value);
- gtk_widget_child_notify(child, "x");
- break;
- case CHILD_PROP_Y:
- floating_child->y = g_value_get_int(value);
- gtk_widget_child_notify(child, "y");
- break;
- default:
- GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(
- container, property_id, pspec);
- break;
- };
-}
-
-static void gtk_floating_container_get_child_property(GtkContainer* container,
- GtkWidget* child,
- guint property_id,
- GValue* value,
- GParamSpec* pspec) {
- GtkFloatingContainerChild* floating_child =
- GetChild(GTK_FLOATING_CONTAINER(container), child);
- g_return_if_fail(floating_child);
-
- switch (property_id) {
- case CHILD_PROP_X:
- g_value_set_int(value, floating_child->x);
- break;
- case CHILD_PROP_Y:
- g_value_set_int(value, floating_child->y);
- break;
- default:
- GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(
- container, property_id, pspec);
- break;
- };
-}
-
-GtkWidget* gtk_floating_container_new() {
- return GTK_WIDGET(g_object_new(GTK_TYPE_FLOATING_CONTAINER, NULL));
-}
-
-void gtk_floating_container_add_floating(GtkFloatingContainer* container,
- GtkWidget* widget) {
- g_return_if_fail(GTK_IS_FLOATING_CONTAINER(container));
- g_return_if_fail(GTK_IS_WIDGET(widget));
-
- GtkFloatingContainerChild* child_info = g_new(GtkFloatingContainerChild, 1);
- child_info->widget = widget;
- child_info->x = 0;
- child_info->y = 0;
-
- gtk_widget_set_parent(widget, GTK_WIDGET(container));
-
- container->floating_children =
- g_list_append(container->floating_children, child_info);
-}
-
-G_END_DECLS
diff --git a/chromium/ui/base/gtk/gtk_floating_container.h b/chromium/ui/base/gtk/gtk_floating_container.h
deleted file mode 100644
index 2d68edde5aa..00000000000
--- a/chromium/ui/base/gtk/gtk_floating_container.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_FLOATING_CONTAINER_H_
-#define UI_BASE_GTK_GTK_FLOATING_CONTAINER_H_
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/base/ui_export.h"
-
-// A specialized container, which is a cross between a GtkBin and a
-// GtkFixed. This container dervies from GtkBin and the implementation of
-// gtk_container_add() is the same: only one GtkWidget can be added through
-// that interface. The GtkBin portion contains normal content and is given the
-// same allocation that this container has.
-//
-// In addition, any number of widgets can be added through the
-// gtk_floating_container_add_floating() method, which provides functionality
-// similar to a GtkFixed. Unlike a GtkFixed, coordinates are not set when you
-// gtk_fixed_put(). The location of the floating widgets is determined while
-// running the "set-floating-position" signal, which is emitted during this
-// container's "size-allocate" handler.
-//
-// The "set-floating-position" signal is (semi-)mandatory if you want widgets
-// placed anywhere other than the origin and should have the following
-// signature:
-//
-// void (*set_floating_position)(GtkFloatingContainer* container,
-// GtkAllocation* allocation,
-// gpointer userdata);
-//
-// Your handler should, for each floating widget, set the "x" and "y" child
-// properties.
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_FLOATING_CONTAINER \
- (gtk_floating_container_get_type())
-#define GTK_FLOATING_CONTAINER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_FLOATING_CONTAINER, \
- GtkFloatingContainer))
-#define GTK_FLOATING_CONTAINER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_FLOATING_CONTAINER, \
- GtkFloatingContainerClass))
-#define GTK_IS_FLOATING_CONTAINER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_FLOATING_CONTAINER))
-#define GTK_IS_FLOATING_CONTAINER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_FLOATING_CONTAINER))
-#define GTK_FLOATING_CONTAINER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_FLOATING_CONTAINER, \
- GtkFloatingContainerClass))
-
-typedef struct _GtkFloatingContainer GtkFloatingContainer;
-typedef struct _GtkFloatingContainerClass GtkFloatingContainerClass;
-typedef struct _GtkFloatingContainerChild GtkFloatingContainerChild;
-
-struct _GtkFloatingContainer {
- // Parent class.
- GtkBin bin;
-
- // A GList of all our floating children, in GtkFloatingContainerChild
- // structs. Owned by the GtkFloatingContainer.
- GList* floating_children;
-};
-
-struct _GtkFloatingContainerClass {
- GtkBinClass parent_class;
-};
-
-// Internal structure used to associate a widget and its x/y child properties.
-struct _GtkFloatingContainerChild {
- GtkWidget* widget;
- gint x;
- gint y;
-};
-
-UI_EXPORT GType gtk_floating_container_get_type() G_GNUC_CONST;
-UI_EXPORT GtkWidget* gtk_floating_container_new();
-UI_EXPORT void gtk_floating_container_add_floating(
- GtkFloatingContainer* container,
- GtkWidget* widget);
-// Use gtk_container_remove to remove all widgets; both widgets added with
-// gtk_container_add() and gtk_floating_container_add_floating().
-
-G_END_DECLS
-
-#endif // UI_BASE_GTK_GTK_FLOATING_CONTAINER_H_
diff --git a/chromium/ui/base/gtk/gtk_hig_constants.h b/chromium/ui/base/gtk/gtk_hig_constants.h
deleted file mode 100644
index a03db506d17..00000000000
--- a/chromium/ui/base/gtk/gtk_hig_constants.h
+++ /dev/null
@@ -1,54 +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.
-//
-// A list of constants that are used in setting up GTK widgets.
-//
-// This contains named color constants, along with spacing constants from the
-// GNOME Human Interface Guide.
-
-#ifndef UI_BASE_GTK_GTK_HIG_CONSTANTS_H_
-#define UI_BASE_GTK_GTK_HIG_CONSTANTS_H_
-
-typedef struct _GdkColor GdkColor;
-
-// Define a macro for creating GdkColors from RGB values. This is a macro to
-// allow static construction of literals, etc. Use this like:
-// GdkColor white = GDK_COLOR_RGB(0xff, 0xff, 0xff);
-#define GDK_COLOR_RGB(r, g, b) {0, r * ::ui::kSkiaToGDKMultiplier, \
- g * ::ui::kSkiaToGDKMultiplier, b * ::ui::kSkiaToGDKMultiplier}
-
-namespace ui {
-
-// Multiply uint8 color components by this.
-const int kSkiaToGDKMultiplier = 257;
-
-// Common color constants.
-const GdkColor kGdkWhite = GDK_COLOR_RGB(0xFF, 0xFF, 0xFF);
-const GdkColor kGdkBlack = GDK_COLOR_RGB(0x00, 0x00, 0x00);
-const GdkColor kGdkGray = GDK_COLOR_RGB(0x7F, 0x7F, 0x7F);
-
-// Constants relating to the layout of dialog windows:
-// (See http://library.gnome.org/devel/hig-book/stable/design-window.html.en)
-
-// Spacing between controls of the same group.
-const int kControlSpacing = 6;
-
-// Horizontal spacing between a label and its control.
-const int kLabelSpacing = 12;
-
-// Indent of the controls within each group.
-const int kGroupIndent = 12;
-
-// Space around the outside of a dialog's contents.
-const int kContentAreaBorder = 12;
-
-// Spacing between groups of controls.
-const int kContentAreaSpacing = 18;
-
-// Horizontal Spacing between controls in a form.
-const int kFormControlSpacing = 10;
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_GTK_HIG_CONSTANTS_H_
diff --git a/chromium/ui/base/gtk/gtk_screen_util.cc b/chromium/ui/base/gtk/gtk_screen_util.cc
deleted file mode 100644
index 000f9509472..00000000000
--- a/chromium/ui/base/gtk/gtk_screen_util.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_screen_util.h"
-
-#include "base/logging.h"
-
-namespace ui {
-
-bool IsScreenComposited() {
- GdkScreen* screen = gdk_screen_get_default();
- return gdk_screen_is_composited(screen) == TRUE;
-}
-
-gfx::Point ScreenPoint(GtkWidget* widget) {
- int x, y;
- gdk_display_get_pointer(gtk_widget_get_display(widget), NULL, &x, &y,
- NULL);
- return gfx::Point(x, y);
-}
-
-gfx::Point ClientPoint(GtkWidget* widget) {
- int x, y;
- gtk_widget_get_pointer(widget, &x, &y);
- return gfx::Point(x, y);
-}
-
-gfx::Vector2d GetWidgetScreenOffset(GtkWidget* widget) {
- GdkWindow* window = gtk_widget_get_window(widget);
-
- if (!window) {
- NOTREACHED() << "Must only be called on realized widgets.";
- return gfx::Vector2d(0, 0);
- }
-
- gint x, y;
- gdk_window_get_origin(window, &x, &y);
-
- if (!gtk_widget_get_has_window(widget)) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(widget, &allocation);
- x += allocation.x;
- y += allocation.y;
- }
-
- return gfx::Vector2d(x, y);
-}
-
-gfx::Rect GetWidgetScreenBounds(GtkWidget* widget) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(widget, &allocation);
-
- return gfx::Rect(PointAtOffsetFromOrigin(GetWidgetScreenOffset(widget)),
- gfx::Size(allocation.width, allocation.height));
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/gtk_screen_util.h b/chromium/ui/base/gtk/gtk_screen_util.h
deleted file mode 100644
index b916cf238af..00000000000
--- a/chromium/ui/base/gtk/gtk_screen_util.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_SCREEN_UTILS_H_
-#define UI_BASE_GTK_GTK_SCREEN_UTILS_H_
-
-#include <gtk/gtk.h>
-
-#include "ui/base/ui_export.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/vector2d.h"
-
-namespace ui {
-
-// Returns true if the screen is composited, false otherwise.
-UI_EXPORT bool IsScreenComposited();
-
-// Get the current location of the mouse cursor relative to the screen.
-UI_EXPORT gfx::Point ScreenPoint(GtkWidget* widget);
-
-// Get the current location of the mouse cursor relative to the widget.
-UI_EXPORT gfx::Point ClientPoint(GtkWidget* widget);
-
-// Gets the offset of a gtk widget from the origin in screen coordinates.
-UI_EXPORT gfx::Vector2d GetWidgetScreenOffset(GtkWidget* widget);
-
-// Returns the bounds of the specified widget in screen coordinates.
-UI_EXPORT gfx::Rect GetWidgetScreenBounds(GtkWidget* widget);
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_GTK_SCREEN_UTILS_H_
diff --git a/chromium/ui/base/gtk/gtk_signal.h b/chromium/ui/base/gtk/gtk_signal.h
deleted file mode 100644
index ca6fa2308d0..00000000000
--- a/chromium/ui/base/gtk/gtk_signal.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_SIGNAL_H_
-#define UI_BASE_GTK_GTK_SIGNAL_H_
-
-#include "ui/base/glib/glib_signal.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-// These macros handle the common case where the sender object will be a
-// GtkWidget*.
-#define CHROMEGTK_CALLBACK_0(CLASS, RETURN, METHOD) \
- CHROMEG_CALLBACK_0(CLASS, RETURN, METHOD, GtkWidget*);
-
-#define CHROMEGTK_CALLBACK_1(CLASS, RETURN, METHOD, ARG1) \
- CHROMEG_CALLBACK_1(CLASS, RETURN, METHOD, GtkWidget*, ARG1);
-
-#define CHROMEGTK_CALLBACK_2(CLASS, RETURN, METHOD, ARG1, ARG2) \
- CHROMEG_CALLBACK_2(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2);
-
-#define CHROMEGTK_CALLBACK_3(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3) \
- CHROMEG_CALLBACK_3(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3);
-
-#define CHROMEGTK_CALLBACK_4(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4) \
- CHROMEG_CALLBACK_4(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
- ARG4);
-
-#define CHROMEGTK_CALLBACK_5(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4, \
- ARG5) \
- CHROMEG_CALLBACK_5(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
- ARG4, ARG5);
-
-#define CHROMEGTK_CALLBACK_6(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, ARG4, \
- ARG5, ARG6) \
- CHROMEG_CALLBACK_6(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, ARG3, \
- ARG4, ARG5, ARG6);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD) \
- CHROMEG_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD, GtkWidget*);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, ARG1) \
- CHROMEG_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, GtkWidget*, ARG1);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_2(CLASS, RETURN, METHOD, ARG1, ARG2) \
- CHROMEG_VIRTUAL_CALLBACK_2(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_3(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3) \
- CHROMEG_VIRTUAL_CALLBACK_3(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
- ARG3);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
- ARG4) \
- CHROMEG_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
- ARG3, ARG4);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
- ARG4, ARG5) \
- CHROMEG_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
- ARG3, ARG4, ARG5);
-
-#define CHROMEGTK_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, ARG1, ARG2, ARG3, \
- ARG4, ARG5, ARG6) \
- CHROMEG_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, GtkWidget*, ARG1, ARG2, \
- ARG3, ARG4, ARG5, ARG6);
-
-#endif // UI_BASE_GTK_GTK_SIGNAL_H_
diff --git a/chromium/ui/base/gtk/gtk_signal_registrar.cc b/chromium/ui/base/gtk/gtk_signal_registrar.cc
deleted file mode 100644
index 82527e8258b..00000000000
--- a/chromium/ui/base/gtk/gtk_signal_registrar.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_signal_registrar.h"
-
-#include <glib-object.h>
-
-#include "base/logging.h"
-#include "ui/base/gtk/g_object_destructor_filo.h"
-
-namespace ui {
-
-GtkSignalRegistrar::GtkSignalRegistrar() {
-}
-
-GtkSignalRegistrar::~GtkSignalRegistrar() {
- for (HandlerMap::iterator list_iter = handler_lists_.begin();
- list_iter != handler_lists_.end(); ++list_iter) {
- GObject* object = list_iter->first;
- GObjectDestructorFILO::GetInstance()->Disconnect(
- object, WeakNotifyThunk, this);
-
- HandlerList& handlers = list_iter->second;
- for (HandlerList::iterator ids_iter = handlers.begin();
- ids_iter != handlers.end(); ++ids_iter) {
- g_signal_handler_disconnect(object, *ids_iter);
- }
- }
-}
-
-glong GtkSignalRegistrar::Connect(gpointer instance,
- const gchar* detailed_signal,
- GCallback signal_handler,
- gpointer data) {
- return ConnectInternal(instance, detailed_signal, signal_handler, data,
- false);
-}
-
-glong GtkSignalRegistrar::ConnectAfter(gpointer instance,
- const gchar* detailed_signal,
- GCallback signal_handler,
- gpointer data) {
- return ConnectInternal(instance, detailed_signal, signal_handler, data, true);
-}
-
-glong GtkSignalRegistrar::ConnectInternal(gpointer instance,
- const gchar* detailed_signal,
- GCallback signal_handler,
- gpointer data,
- bool after) {
- GObject* object = G_OBJECT(instance);
-
- HandlerMap::iterator iter = handler_lists_.find(object);
- if (iter == handler_lists_.end()) {
- GObjectDestructorFILO::GetInstance()->Connect(
- object, WeakNotifyThunk, this);
- handler_lists_[object] = HandlerList();
- iter = handler_lists_.find(object);
- }
-
- glong handler_id = after ?
- g_signal_connect_after(instance, detailed_signal, signal_handler, data) :
- g_signal_connect(instance, detailed_signal, signal_handler, data);
- iter->second.push_back(handler_id);
-
- return handler_id;
-}
-
-void GtkSignalRegistrar::WeakNotify(GObject* where_the_object_was) {
- HandlerMap::iterator iter = handler_lists_.find(where_the_object_was);
- if (iter == handler_lists_.end()) {
- NOTREACHED();
- return;
- }
- // The signal handlers will be disconnected automatically. Just erase the
- // handler id list.
- handler_lists_.erase(iter);
-}
-
-void GtkSignalRegistrar::DisconnectAll(gpointer instance) {
- GObject* object = G_OBJECT(instance);
- HandlerMap::iterator iter = handler_lists_.find(object);
- if (iter == handler_lists_.end())
- return;
-
- GObjectDestructorFILO::GetInstance()->Disconnect(
- object, WeakNotifyThunk, this);
- HandlerList& handlers = iter->second;
- for (HandlerList::iterator ids_iter = handlers.begin();
- ids_iter != handlers.end(); ++ids_iter) {
- g_signal_handler_disconnect(object, *ids_iter);
- }
-
- handler_lists_.erase(iter);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/gtk_signal_registrar.h b/chromium/ui/base/gtk/gtk_signal_registrar.h
deleted file mode 100644
index 2fa839c5f91..00000000000
--- a/chromium/ui/base/gtk/gtk_signal_registrar.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_SIGNAL_REGISTRAR_H_
-#define UI_BASE_GTK_GTK_SIGNAL_REGISTRAR_H_
-
-#include <glib.h>
-#include <map>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
-
-typedef void (*GCallback) (void);
-typedef struct _GObject GObject;
-typedef struct _GtkWidget GtkWidget;
-
-namespace ui {
-
-// A class that ensures that callbacks don't run on stale owner objects. Similar
-// in spirit to NotificationRegistrar. Use as follows:
-//
-// class ChromeObject {
-// public:
-// ChromeObject() {
-// ...
-//
-// signals_.Connect(widget, "event", CallbackThunk, this);
-// }
-//
-// ...
-//
-// private:
-// GtkSignalRegistrar signals_;
-// };
-//
-// When |signals_| goes down, it will disconnect the handlers connected via
-// Connect.
-class UI_EXPORT GtkSignalRegistrar {
- public:
- GtkSignalRegistrar();
- ~GtkSignalRegistrar();
-
- // Connect before the default handler. Returns the handler id.
- glong Connect(gpointer instance, const gchar* detailed_signal,
- GCallback signal_handler, gpointer data);
- // Connect after the default handler. Returns the handler id.
- glong ConnectAfter(gpointer instance, const gchar* detailed_signal,
- GCallback signal_handler, gpointer data);
-
- // Disconnects all signal handlers connected to |instance|.
- void DisconnectAll(gpointer instance);
-
- private:
- typedef std::vector<glong> HandlerList;
- typedef std::map<GObject*, HandlerList> HandlerMap;
-
- static void WeakNotifyThunk(gpointer data, GObject* where_the_object_was) {
- reinterpret_cast<GtkSignalRegistrar*>(data)->WeakNotify(
- where_the_object_was);
- }
- void WeakNotify(GObject* where_the_object_was);
-
- glong ConnectInternal(gpointer instance, const gchar* detailed_signal,
- GCallback signal_handler, gpointer data, bool after);
-
- HandlerMap handler_lists_;
-
- DISALLOW_COPY_AND_ASSIGN(GtkSignalRegistrar);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_GTK_SIGNAL_REGISTRAR_H_
diff --git a/chromium/ui/base/gtk/gtk_windowing.cc b/chromium/ui/base/gtk/gtk_windowing.cc
deleted file mode 100644
index e378c8463ad..00000000000
--- a/chromium/ui/base/gtk/gtk_windowing.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/gtk_windowing.h"
-
-#include <gdk/gdkx.h>
-
-#include "base/logging.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/gtk_compat.h"
-
-namespace ui {
-
-void StackPopupWindow(GtkWidget* popup, GtkWidget* toplevel) {
- DCHECK(GTK_IS_WINDOW(popup) && gtk_widget_is_toplevel(popup) &&
- gtk_widget_get_realized(popup));
- DCHECK(GTK_IS_WINDOW(toplevel) && gtk_widget_is_toplevel(toplevel) &&
- gtk_widget_get_realized(toplevel));
-
- // Stack the |popup| window directly above the |toplevel| window.
- // The popup window is a direct child of the root window, so we need to
- // find a similar ancestor for the toplevel window (which might have been
- // reparented by a window manager). We grab the server while we're doing
- // this -- otherwise, we'll get an error if the window manager reparents the
- // toplevel window right after we call GetHighestAncestorWindow().
- gdk_x11_display_grab(gtk_widget_get_display(toplevel));
- XID toplevel_window_base = ui::GetHighestAncestorWindow(
- ui::GetX11WindowFromGtkWidget(toplevel),
- ui::GetX11RootWindow());
- if (toplevel_window_base) {
- XID window_xid = ui::GetX11WindowFromGtkWidget(popup);
- XID window_parent = ui::GetParentWindow(window_xid);
- if (window_parent == ui::GetX11RootWindow()) {
- ui::RestackWindow(window_xid, toplevel_window_base, true);
- } else {
- // The window manager shouldn't reparent override-redirect windows.
- DLOG(ERROR) << "override-redirect window " << window_xid
- << "'s parent is " << window_parent
- << ", rather than root window "
- << ui::GetX11RootWindow();
- }
- }
- gdk_x11_display_ungrab(gtk_widget_get_display(toplevel));
-}
-
-} // namespace ui
-
diff --git a/chromium/ui/base/gtk/gtk_windowing.h b/chromium/ui/base/gtk/gtk_windowing.h
deleted file mode 100644
index 93a9335753d..00000000000
--- a/chromium/ui/base/gtk/gtk_windowing.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_GTK_GTK_WINDOWING_H_
-#define UI_BASE_GTK_GTK_WINDOWING_H_
-
-#include <gtk/gtk.h>
-
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-// Stacks a |popup| window directly on top of a |toplevel| window.
-UI_EXPORT void StackPopupWindow(GtkWidget* popup, GtkWidget* toplevel);
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_GTK_WINDOWING_H_
diff --git a/chromium/ui/base/gtk/owned_widget_gtk.cc b/chromium/ui/base/gtk/owned_widget_gtk.cc
deleted file mode 100644
index 6a129a21807..00000000000
--- a/chromium/ui/base/gtk/owned_widget_gtk.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/owned_widget_gtk.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-
-namespace ui {
-
-OwnedWidgetGtk::~OwnedWidgetGtk() {
- Destroy();
-}
-
-void OwnedWidgetGtk::Own(GtkWidget* widget) {
- if (!widget)
- return;
-
- DCHECK(!widget_);
- // We want to make sure that Own() was called properly, right after the
- // widget was created. There should be a floating reference.
- DCHECK(g_object_is_floating(widget));
-
- // Sink the floating reference, we should now own this reference.
- g_object_ref_sink(widget);
- widget_ = widget;
-}
-
-void OwnedWidgetGtk::Destroy() {
- if (!widget_)
- return;
-
- GtkWidget* widget = widget_;
- widget_ = NULL;
- gtk_widget_destroy(widget);
-
- DCHECK(!g_object_is_floating(widget));
- // NOTE: Assumes some implementation details about glib internals.
- DCHECK_EQ(G_OBJECT(widget)->ref_count, 1U);
- g_object_unref(widget);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/owned_widget_gtk.h b/chromium/ui/base/gtk/owned_widget_gtk.h
deleted file mode 100644
index ba3068c9708..00000000000
--- a/chromium/ui/base/gtk/owned_widget_gtk.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This class assists you in dealing with a specific situation when managing
-// ownership between a C++ object and a GTK widget. It is common to have a
-// C++ object which encapsulates a GtkWidget, and that widget is exposed from
-// the object for use outside of the class. In this situation, you commonly
-// want the GtkWidget's lifetime to match its C++ object's lifetime. Using an
-// OwnedWigetGtk will take ownership over the initial reference of the
-// GtkWidget, so that it is "owned" by the C++ object. Example usage:
-//
-// class FooViewGtk() {
-// public:
-// FooViewGtk() { }
-// ~FooViewGtk() { }
-// void Init() { vbox_.Own(gtk_vbox_new()); }
-// GtkWidget* widget() { return vbox_.get() }; // Host my widget!
-// private:
-// OwnedWidgetGtk vbox_;
-// };
-//
-// This design will ensure that the widget stays alive from the call to Own()
-// until the call to Destroy().
-//
-// - Details of the problem and OwnedWidgetGtk's solution:
-// In order to make passing ownership more convenient for newly created
-// widgets, GTK has a concept of a "floating" reference. All GtkObjects (and
-// thus GtkWidgets) inherit from GInitiallyUnowned. When they are created, the
-// object starts with a reference count of 1, but has its floating flag set.
-// When it is put into a container for the first time, that container will
-// "sink" the floating reference, and the count will still be 1. Now the
-// container owns the widget, and if we remove the widget from the container,
-// the widget is destroyed. This style of ownership often causes problems when
-// you have an object encapsulating the widget. If we just use a raw
-// GtkObject* with no specific ownership management, we push the widget's
-// ownership onto the user of the class. Now the C++ object can't depend on
-// the widget being valid, since it doesn't manage its lifetime. If the widget
-// was removed from a container, removing its only reference, it would be
-// destroyed (from the C++ object's perspective) unexpectedly destroyed. The
-// solution is fairly simple, make sure that the C++ object owns the widget,
-// and thus it is also responsible for destroying it. This boils down to:
-// GtkWidget* widget = gtk_widget_new();
-// g_object_ref_sink(widget); // Claim the initial floating reference.
-// ...
-// gtk_destroy_widget(widget); // Ask all code to destroy their references.
-// g_object_unref(widget); // Destroy the initial reference we had claimed.
-
-#ifndef UI_BASE_GTK_OWNED_WIDGET_GTK_H_
-#define UI_BASE_GTK_OWNED_WIDGET_GTK_H_
-
-#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-namespace ui {
-
-class UI_EXPORT OwnedWidgetGtk {
- public:
- // Create an instance that isn't managing any ownership.
- OwnedWidgetGtk() : widget_(NULL) { }
- // Create an instance that owns |widget|.
- explicit OwnedWidgetGtk(GtkWidget* widget) : widget_(NULL) { Own(widget); }
-
- ~OwnedWidgetGtk();
-
- // Return the currently owned widget, or NULL if no widget is owned.
- GtkWidget* get() const { return widget_; }
- GtkWidget* operator->() const { return widget_; }
-
- // Takes ownership of a widget, by taking the initial floating reference of
- // the GtkWidget. It is expected that Own() is called right after the widget
- // has been created, and before any other references to the widget might have
- // been added. It is valid to never call Own(), in which case Destroy() will
- // do nothing. If Own() has been called, you must explicitly call Destroy().
- void Own(GtkWidget* widget);
-
- // You may call Destroy() after you have called Own(). Calling Destroy()
- // will call gtk_widget_destroy(), and drop our reference to the widget.
- // Destroy() is also called in this object's destructor.
- // After a call to Destroy(), you may call Own() again. NOTE: It is expected
- // that after gtk_widget_destroy we will be holding the only reference left
- // on the object. We assert this in debug mode to help catch any leaks.
- void Destroy();
-
- private:
- GtkWidget* widget_;
-
- DISALLOW_COPY_AND_ASSIGN(OwnedWidgetGtk);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_OWNED_WIDGET_GTK_H_
diff --git a/chromium/ui/base/gtk/scoped_region.cc b/chromium/ui/base/gtk/scoped_region.cc
deleted file mode 100644
index 729e3c3a6f7..00000000000
--- a/chromium/ui/base/gtk/scoped_region.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/gtk/scoped_region.h"
-
-#include <gdk/gdk.h>
-
-namespace ui {
-
-ScopedRegion::ScopedRegion() : region_(NULL) {}
-
-ScopedRegion::ScopedRegion(GdkRegion* region) : region_(region) {}
-
-ScopedRegion::~ScopedRegion() {
- Close();
-}
-
-void ScopedRegion::Set(GdkRegion* region) {
- Close();
- region_ = region;
-}
-
-GdkRegion* ScopedRegion::Get() {
- return region_;
-}
-
-GdkRegion* ScopedRegion::release() {
- GdkRegion* region = region_;
- region_ = NULL;
- return region;
-}
-
-void ScopedRegion::Close() {
- if (region_) {
- gdk_region_destroy(region_);
- region_ = NULL;
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/gtk/scoped_region.h b/chromium/ui/base/gtk/scoped_region.h
deleted file mode 100644
index faa7e817c3c..00000000000
--- a/chromium/ui/base/gtk/scoped_region.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_GTK_SCOPED_REGION_H_
-#define UI_BASE_GTK_SCOPED_REGION_H_
-
-#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
-
-typedef struct _GdkRegion GdkRegion;
-
-namespace ui {
-
-// Wraps a GdkRegion. This class provides the same methods as ScopedGDIObject in
-// base/win/scoped_gdi_object.h.
-class UI_EXPORT ScopedRegion {
- public:
- ScopedRegion();
- explicit ScopedRegion(GdkRegion* region);
-
- ~ScopedRegion();
-
- void Set(GdkRegion* region);
-
- GdkRegion* Get();
-
- GdkRegion* release();
-
- private:
- void Close();
-
- GdkRegion* region_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedRegion);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_GTK_SCOPED_REGION_H_
diff --git a/chromium/ui/base/ime/DEPS b/chromium/ui/base/ime/DEPS
index 56b2a81c976..d59514e924b 100644
--- a/chromium/ui/base/ime/DEPS
+++ b/chromium/ui/base/ime/DEPS
@@ -1,6 +1,4 @@
include_rules = [
- # TODO(nona): Remove chromoeos/dbus entry once crbug.com/171351 is fixed.
- "+chromeos/dbus",
"+chromeos/ime",
"+third_party/gtk+/gdk/gdkkeysyms.h",
"+third_party/gtk+/gtk/gtkimcontextsimpleseqs.h",
diff --git a/chromium/ui/base/ime/OWNERS b/chromium/ui/base/ime/OWNERS
index ec3410f4afc..bc96702ccda 100644
--- a/chromium/ui/base/ime/OWNERS
+++ b/chromium/ui/base/ime/OWNERS
@@ -1,11 +1,10 @@
-nona@chromium.org
-penghuang@chromium.org
+# primary reviewer.
+yukishiino@chromium.org
-# Chrome OS IME
+# backup reviewers.
komatsu@chromium.org
+mukai@chromium.org
+nona@chromium.org
-# Windows Aura IME
+# For Windows.
yukawa@chromium.org
-
-# Linux Aura IME
-yukishiino@chromium.org
diff --git a/chromium/ui/base/ime/candidate_window.cc b/chromium/ui/base/ime/candidate_window.cc
new file mode 100644
index 00000000000..6cb32e2d77f
--- /dev/null
+++ b/chromium/ui/base/ime/candidate_window.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/candidate_window.h"
+
+#include <string>
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace ui {
+
+namespace {
+// The default entry number of a page in CandidateWindow.
+const int kDefaultPageSize = 9;
+} // namespace
+
+CandidateWindow::CandidateWindow()
+ : property_(new CandidateWindowProperty) {
+}
+
+CandidateWindow::~CandidateWindow() {
+}
+
+bool CandidateWindow::IsEqual(const CandidateWindow& cw) const {
+ if (page_size() != cw.page_size() ||
+ cursor_position() != cw.cursor_position() ||
+ is_cursor_visible() != cw.is_cursor_visible() ||
+ orientation() != cw.orientation() ||
+ show_window_at_composition() != cw.show_window_at_composition() ||
+ is_auxiliary_text_visible() != cw.is_auxiliary_text_visible() ||
+ auxiliary_text() != cw.auxiliary_text() ||
+ candidates_.size() != cw.candidates_.size())
+ return false;
+
+ for (size_t i = 0; i < candidates_.size(); ++i) {
+ const Entry& left = candidates_[i];
+ const Entry& right = cw.candidates_[i];
+ if (left.value != right.value ||
+ left.label != right.label ||
+ left.annotation != right.annotation ||
+ left.description_title != right.description_title ||
+ left.description_body != right.description_body)
+ return false;
+ }
+ return true;
+}
+
+void CandidateWindow::CopyFrom(const CandidateWindow& cw) {
+ SetProperty(cw.GetProperty());
+ candidates_.clear();
+ candidates_ = cw.candidates_;
+}
+
+
+void CandidateWindow::GetInfolistEntries(
+ std::vector<ui::InfolistEntry>* infolist_entries,
+ bool* has_highlighted) const {
+ DCHECK(infolist_entries);
+ DCHECK(has_highlighted);
+ infolist_entries->clear();
+ *has_highlighted = false;
+
+ const size_t cursor_index_in_page = cursor_position() % page_size();
+
+ for (size_t i = 0; i < candidates().size(); ++i) {
+ const CandidateWindow::Entry& candidate_entry = candidates()[i];
+ if (candidate_entry.description_title.empty() &&
+ candidate_entry.description_body.empty())
+ continue;
+
+ InfolistEntry entry(candidate_entry.description_title,
+ candidate_entry.description_body);
+ if (i == cursor_index_in_page) {
+ entry.highlighted = true;
+ *has_highlighted = true;
+ }
+ infolist_entries->push_back(entry);
+ }
+}
+
+// When the default values are changed, please modify
+// InputMethodEngineInterface::CandidateWindowProperty too.
+CandidateWindow::CandidateWindowProperty::CandidateWindowProperty()
+ : page_size(kDefaultPageSize),
+ cursor_position(0),
+ is_cursor_visible(true),
+ is_vertical(false),
+ show_window_at_composition(false),
+ is_auxiliary_text_visible(false) {
+}
+
+CandidateWindow::CandidateWindowProperty::~CandidateWindowProperty() {
+}
+
+CandidateWindow::Entry::Entry() {
+}
+
+CandidateWindow::Entry::~Entry() {
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/candidate_window.h b/chromium/ui/base/ime/candidate_window.h
new file mode 100644
index 00000000000..6ae6dd8955a
--- /dev/null
+++ b/chromium/ui/base/ime/candidate_window.h
@@ -0,0 +1,131 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_CANDIDATE_WINDOW_H_
+#define UI_BASE_IME_CANDIDATE_WINDOW_H_
+
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ime/infolist_entry.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// CandidateWindow represents the structure of candidates generated from IME.
+class UI_BASE_EXPORT CandidateWindow {
+ public:
+ enum Orientation {
+ HORIZONTAL = 0,
+ VERTICAL = 1,
+ };
+
+ struct UI_BASE_EXPORT CandidateWindowProperty {
+ CandidateWindowProperty();
+ virtual ~CandidateWindowProperty();
+ int page_size;
+ int cursor_position;
+ bool is_cursor_visible;
+ bool is_vertical;
+ bool show_window_at_composition;
+
+ // Auxiliary text is typically displayed in the footer of the candidate
+ // window.
+ std::string auxiliary_text;
+ bool is_auxiliary_text_visible;
+ };
+
+ // Represents a candidate entry.
+ struct UI_BASE_EXPORT Entry {
+ Entry();
+ virtual ~Entry();
+ base::string16 value;
+ base::string16 label;
+ base::string16 annotation;
+ base::string16 description_title;
+ base::string16 description_body;
+ };
+
+ CandidateWindow();
+ virtual ~CandidateWindow();
+
+ // Returns true if the given |candidate_window| is equal to myself.
+ bool IsEqual(const CandidateWindow& candidate_window) const;
+
+ // Copies |candidate_window| to myself.
+ void CopyFrom(const CandidateWindow& candidate_window);
+
+ const CandidateWindowProperty& GetProperty() const {
+ return *property_;
+ }
+ void SetProperty(const CandidateWindowProperty& property) {
+ *property_ = property;
+ }
+
+ // Gets the infolist entry models. Sets |has_highlighted| to true if |entries|
+ // contains highlighted entry.
+ void GetInfolistEntries(std::vector<InfolistEntry>* entries,
+ bool* has_highlighted) const;
+
+ // Returns the number of candidates in one page.
+ uint32 page_size() const { return property_->page_size; }
+ void set_page_size(uint32 page_size) { property_->page_size = page_size; }
+
+ // Returns the cursor index of the currently selected candidate.
+ uint32 cursor_position() const { return property_->cursor_position; }
+ void set_cursor_position(uint32 cursor_position) {
+ property_->cursor_position = cursor_position;
+ }
+
+ // Returns true if the cursor is visible.
+ bool is_cursor_visible() const { return property_->is_cursor_visible; }
+ void set_is_cursor_visible(bool is_cursor_visible) {
+ property_->is_cursor_visible = is_cursor_visible;
+ }
+
+ // Returns the orientation of the candidate window.
+ Orientation orientation() const {
+ return property_->is_vertical ? VERTICAL : HORIZONTAL;
+ }
+ void set_orientation(Orientation orientation) {
+ property_->is_vertical = (orientation == VERTICAL);
+ }
+
+ // Returns true if the auxiliary text is visible.
+ bool is_auxiliary_text_visible() const {
+ return property_->is_auxiliary_text_visible;
+ }
+ void set_is_auxiliary_text_visible(bool is_auxiliary_text_visible) const {
+ property_->is_auxiliary_text_visible = is_auxiliary_text_visible;
+ }
+
+ // Accessors of auxiliary_text.
+ const std::string& auxiliary_text() const {
+ return property_->auxiliary_text;
+ }
+ void set_auxiliary_text(const std::string& auxiliary_text) const {
+ property_->auxiliary_text = auxiliary_text;
+ }
+
+ const std::vector<Entry>& candidates() const { return candidates_; }
+ std::vector<Entry>* mutable_candidates() { return &candidates_; }
+
+ bool show_window_at_composition() const {
+ return property_->show_window_at_composition;
+ }
+ void set_show_window_at_composition(bool show_window_at_composition) {
+ property_->show_window_at_composition = show_window_at_composition;
+ }
+
+ private:
+ scoped_ptr<CandidateWindowProperty> property_;
+ std::vector<Entry> candidates_;
+
+ DISALLOW_COPY_AND_ASSIGN(CandidateWindow);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_CANDIDATE_WINDOW_H_
diff --git a/chromium/ui/base/ime/candidate_window_unittest.cc b/chromium/ui/base/ime/candidate_window_unittest.cc
new file mode 100644
index 00000000000..4defe56b5e0
--- /dev/null
+++ b/chromium/ui/base/ime/candidate_window_unittest.cc
@@ -0,0 +1,262 @@
+// 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.
+// TODO(nona): Add more tests.
+
+#include "ui/base/ime/candidate_window.h"
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+namespace {
+
+const size_t kSampleCandidateSize = 3;
+const char* kSampleCandidate[] = {
+ "Sample Candidate 1",
+ "Sample Candidate 2",
+ "Sample Candidate 3",
+};
+const char* kSampleDescriptionTitle[] = {
+ "Sample Description Title 1",
+ "Sample Description Title 2",
+ "Sample Description Title 3",
+};
+const char* kSampleDescriptionBody[] = {
+ "Sample Description Body 1",
+ "Sample Description Body 2",
+ "Sample Description Body 3",
+};
+
+}
+
+TEST(CandidateWindow, IsEqualTest) {
+ CandidateWindow cw1;
+ CandidateWindow cw2;
+
+ const base::string16 kSampleString1 = base::UTF8ToUTF16("Sample 1");
+ const base::string16 kSampleString2 = base::UTF8ToUTF16("Sample 2");
+
+ EXPECT_TRUE(cw1.IsEqual(cw2));
+ EXPECT_TRUE(cw2.IsEqual(cw1));
+
+ cw1.set_page_size(1);
+ cw2.set_page_size(2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.set_page_size(1);
+
+ cw1.set_cursor_position(1);
+ cw2.set_cursor_position(2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.set_cursor_position(1);
+
+ cw1.set_is_cursor_visible(true);
+ cw2.set_is_cursor_visible(false);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.set_is_cursor_visible(true);
+
+ cw1.set_orientation(CandidateWindow::HORIZONTAL);
+ cw2.set_orientation(CandidateWindow::VERTICAL);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.set_orientation(CandidateWindow::HORIZONTAL);
+
+ cw1.set_show_window_at_composition(true);
+ cw2.set_show_window_at_composition(false);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.set_show_window_at_composition(true);
+
+ // Check equality for candidates member variable.
+ CandidateWindow::Entry entry1;
+ CandidateWindow::Entry entry2;
+
+ cw1.mutable_candidates()->push_back(entry1);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_TRUE(cw1.IsEqual(cw2));
+ EXPECT_TRUE(cw2.IsEqual(cw1));
+
+ entry1.value = kSampleString1;
+ entry2.value = kSampleString2;
+ cw1.mutable_candidates()->push_back(entry1);
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw1.mutable_candidates()->clear();
+ cw2.mutable_candidates()->clear();
+
+ entry1.label = kSampleString1;
+ entry2.label = kSampleString2;
+ cw1.mutable_candidates()->push_back(entry1);
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw1.mutable_candidates()->clear();
+ cw2.mutable_candidates()->clear();
+
+ entry1.annotation = kSampleString1;
+ entry2.annotation = kSampleString2;
+ cw1.mutable_candidates()->push_back(entry1);
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw1.mutable_candidates()->clear();
+ cw2.mutable_candidates()->clear();
+
+ entry1.description_title = kSampleString1;
+ entry2.description_title = kSampleString2;
+ cw1.mutable_candidates()->push_back(entry1);
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw1.mutable_candidates()->clear();
+ cw2.mutable_candidates()->clear();
+
+ entry1.description_body = kSampleString1;
+ entry2.description_body = kSampleString2;
+ cw1.mutable_candidates()->push_back(entry1);
+ cw2.mutable_candidates()->push_back(entry2);
+ EXPECT_FALSE(cw1.IsEqual(cw2));
+ EXPECT_FALSE(cw2.IsEqual(cw1));
+ cw1.mutable_candidates()->clear();
+ cw2.mutable_candidates()->clear();
+}
+
+TEST(CandidateWindow, CopyFromTest) {
+ CandidateWindow cw1;
+ CandidateWindow cw2;
+
+ const base::string16 kSampleString = base::UTF8ToUTF16("Sample");
+
+ cw1.set_page_size(1);
+ cw1.set_cursor_position(2);
+ cw1.set_is_cursor_visible(false);
+ cw1.set_orientation(CandidateWindow::HORIZONTAL);
+ cw1.set_show_window_at_composition(false);
+
+ CandidateWindow::Entry entry;
+ entry.value = kSampleString;
+ entry.label = kSampleString;
+ entry.annotation = kSampleString;
+ entry.description_title = kSampleString;
+ entry.description_body = kSampleString;
+ cw1.mutable_candidates()->push_back(entry);
+
+ cw2.CopyFrom(cw1);
+ EXPECT_TRUE(cw1.IsEqual(cw2));
+}
+
+TEST(CandidateWindow, GetInfolistEntries_DenseCase) {
+ CandidateWindow candidate_window;
+ candidate_window.set_page_size(10);
+ for (size_t i = 0; i < kSampleCandidateSize; ++i) {
+ CandidateWindow::Entry entry;
+ entry.value = base::UTF8ToUTF16(kSampleCandidate[i]);
+ entry.description_title = base::UTF8ToUTF16(kSampleDescriptionTitle[i]);
+ entry.description_body = base::UTF8ToUTF16(kSampleDescriptionBody[i]);
+ candidate_window.mutable_candidates()->push_back(entry);
+ }
+ candidate_window.set_cursor_position(1);
+
+ std::vector<InfolistEntry> infolist_entries;
+ bool has_highlighted = false;
+
+ candidate_window.GetInfolistEntries(&infolist_entries, &has_highlighted);
+
+ EXPECT_EQ(kSampleCandidateSize, infolist_entries.size());
+ EXPECT_TRUE(has_highlighted);
+ EXPECT_TRUE(infolist_entries[1].highlighted);
+}
+
+TEST(CandidateWindow, GetInfolistEntries_SparseCase) {
+ CandidateWindow candidate_window;
+ candidate_window.set_page_size(10);
+ for (size_t i = 0; i < kSampleCandidateSize; ++i) {
+ CandidateWindow::Entry entry;
+ entry.value = base::UTF8ToUTF16(kSampleCandidate[i]);
+ candidate_window.mutable_candidates()->push_back(entry);
+ }
+
+ std::vector<CandidateWindow::Entry>* candidates =
+ candidate_window.mutable_candidates();
+ (*candidates)[2].description_title =
+ base::UTF8ToUTF16(kSampleDescriptionTitle[2]);
+ (*candidates)[2].description_body =
+ base::UTF8ToUTF16(kSampleDescriptionBody[2]);
+
+ candidate_window.set_cursor_position(2);
+
+ std::vector<InfolistEntry> infolist_entries;
+ bool has_highlighted = false;
+
+ candidate_window.GetInfolistEntries(&infolist_entries, &has_highlighted);
+
+ // Infolist entries skips empty descriptions, so expected entry size is 1.
+ EXPECT_EQ(1UL, infolist_entries.size());
+ EXPECT_TRUE(has_highlighted);
+ EXPECT_TRUE(infolist_entries[0].highlighted);
+}
+
+TEST(CandidateWindow, GetInfolistEntries_SparseNoSelectionCase) {
+ CandidateWindow candidate_window;
+ candidate_window.set_page_size(10);
+
+ for (size_t i = 0; i < kSampleCandidateSize; ++i) {
+ CandidateWindow::Entry entry;
+ entry.value = base::UTF8ToUTF16(kSampleCandidate[i]);
+ candidate_window.mutable_candidates()->push_back(entry);
+ }
+
+ std::vector<CandidateWindow::Entry>* candidates =
+ candidate_window.mutable_candidates();
+ (*candidates)[2].description_title =
+ base::UTF8ToUTF16(kSampleDescriptionTitle[2]);
+ (*candidates)[2].description_body =
+ base::UTF8ToUTF16(kSampleDescriptionBody[2]);
+
+ candidate_window.set_cursor_position(0);
+
+ std::vector<InfolistEntry> infolist_entries;
+ bool has_highlighted;
+
+ candidate_window.GetInfolistEntries(&infolist_entries, &has_highlighted);
+
+ // Infolist entries skips empty descriptions, so expected entry size is 1 and
+ // no highlighted entries.
+ EXPECT_EQ(1UL, infolist_entries.size());
+ EXPECT_FALSE(has_highlighted);
+ EXPECT_FALSE(infolist_entries[0].highlighted);
+}
+
+TEST(CandidateWindow, GetInfolistEntries_NoInfolistCase) {
+ CandidateWindow candidate_window;
+ candidate_window.set_page_size(10);
+
+ for (size_t i = 0; i < kSampleCandidateSize; ++i) {
+ CandidateWindow::Entry entry;
+ entry.value = base::UTF8ToUTF16(kSampleCandidate[i]);
+ candidate_window.mutable_candidates()->push_back(entry);
+ }
+ candidate_window.set_cursor_position(1);
+
+ std::vector<InfolistEntry> infolist_entries;
+ bool has_highlighted = false;
+
+ candidate_window.GetInfolistEntries(&infolist_entries, &has_highlighted);
+
+ EXPECT_TRUE(infolist_entries.empty());
+ EXPECT_FALSE(has_highlighted);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/chromeos/character_composer.cc b/chromium/ui/base/ime/chromeos/character_composer.cc
index b9fb51f084f..b7a8808e7d1 100644
--- a/chromium/ui/base/ime/chromeos/character_composer.cc
+++ b/chromium/ui/base/ime/chromeos/character_composer.cc
@@ -4,9 +4,6 @@
#include "ui/base/ime/chromeos/character_composer.h"
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
#include <algorithm>
#include <iterator>
@@ -15,10 +12,10 @@
// Note for Gtk removal: gdkkeysyms.h only contains a set of
// '#define GDK_KeyName 0xNNNN' macros and does not #include any Gtk headers.
#include "third_party/gtk+/gdk/gdkkeysyms.h"
+
#include "ui/base/glib/glib_integers.h"
#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/x/x11_types.h"
+#include "ui/events/keycodes/keyboard_codes.h"
// Note for Gtk removal: gtkimcontextsimpleseqs.h does not #include any Gtk
// headers and only contains one big guint16 array |gtk_compose_seqs_compact|
@@ -358,7 +355,7 @@ bool CheckCharacterComposeTable(const ComposeBufferType& sequence,
// Converts |character| to UTF16 string.
// Returns false when |character| is not a valid character.
-bool UTF32CharacterToUTF16(uint32 character, string16* output) {
+bool UTF32CharacterToUTF16(uint32 character, base::string16* output) {
output->clear();
// Reject invalid character. (e.g. codepoint greater than 0x10ffff)
if (!CBU_IS_UNICODE_CHAR(character))
@@ -371,19 +368,6 @@ bool UTF32CharacterToUTF16(uint32 character, string16* output) {
return true;
}
-// Converts a X keycode to a X keysym with no modifiers.
-KeySym XKeyCodeToXKeySym(unsigned int keycode) {
- XDisplay* display = gfx::GetXDisplay();
- if (!display)
- return NoSymbol;
-
- XKeyEvent x_key_event = {0};
- x_key_event.type = KeyPress;
- x_key_event.display = display;
- x_key_event.keycode = keycode;
- return ::XLookupKeysym(&x_key_event, 0);
-}
-
// Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|.
// -1 is returned when |keyval| cannot be a hexadecimal digit.
int KeyvalToHexDigit(unsigned int keyval) {
@@ -396,6 +380,16 @@ int KeyvalToHexDigit(unsigned int keyval) {
return -1; // |keyval| cannot be a hexadecimal digit.
}
+// Returns an hexadecimal digit integer (0 to 15) corresponding to |keycode|.
+// -1 is returned when |keycode| cannot be a hexadecimal digit.
+int KeycodeToHexDigit(unsigned int keycode) {
+ if (ui::VKEY_0 <= keycode && keycode <= ui::VKEY_9)
+ return keycode - ui::VKEY_0;
+ if (ui::VKEY_A <= keycode && keycode <= ui::VKEY_F)
+ return keycode - ui::VKEY_A + 10;
+ return -1; // |keycode| cannot be a hexadecimal digit.
+}
+
} // namespace
namespace ui {
@@ -412,16 +406,12 @@ void CharacterComposer::Reset() {
}
bool CharacterComposer::FilterKeyPress(const ui::KeyEvent& event) {
- if (!event.HasNativeEvent() ||
+ uint32 keyval = event.platform_keycode();
+ if (!keyval ||
(event.type() != ET_KEY_PRESSED && event.type() != ET_KEY_RELEASED))
return false;
- XEvent* xevent = event.native_event();
- DCHECK(xevent);
- KeySym keysym = NoSymbol;
- ::XLookupString(&xevent->xkey, NULL, 0, &keysym, NULL);
-
- return FilterKeyPressInternal(keysym, xevent->xkey.keycode, event.flags());
+ return FilterKeyPressInternal(keyval, event.key_code(), event.flags());
}
@@ -507,7 +497,7 @@ bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval,
// have intended to type '3'. So, if a hexadecimal character was not found,
// suppose a user is holding shift key (and possibly control key, too) and
// try a character with modifier keys removed.
- hex_digit = KeyvalToHexDigit(XKeyCodeToXKeySym(keycode));
+ hex_digit = KeycodeToHexDigit(keycode);
}
if (keyval == GDK_KEY_Escape) {
@@ -561,7 +551,7 @@ void CharacterComposer::UpdatePreeditStringHexMode() {
DCHECK(0 <= digit && digit < 16);
preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10));
}
- preedit_string_ = ASCIIToUTF16(preedit_string_ascii);
+ preedit_string_ = base::ASCIIToUTF16(preedit_string_ascii);
}
} // namespace ui
diff --git a/chromium/ui/base/ime/chromeos/character_composer.h b/chromium/ui/base/ime/chromeos/character_composer.h
index 0624eb55c68..5d4267f384f 100644
--- a/chromium/ui/base/ime/chromeos/character_composer.h
+++ b/chromium/ui/base/ime/chromeos/character_composer.h
@@ -8,14 +8,14 @@
#include <vector>
#include "base/strings/string_util.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
class KeyEvent;
// A class to recognize compose and dead key sequence.
// Outputs composed character.
-class UI_EXPORT CharacterComposer {
+class UI_BASE_EXPORT CharacterComposer {
public:
CharacterComposer();
~CharacterComposer();
@@ -30,10 +30,12 @@ class UI_EXPORT CharacterComposer {
// Returns a string consisting of composed character.
// Empty string is returned when there is no composition result.
- const string16& composed_character() const { return composed_character_; }
+ const base::string16& composed_character() const {
+ return composed_character_;
+ }
// Returns the preedit string.
- const string16& preedit_string() const { return preedit_string_; }
+ const base::string16& preedit_string() const { return preedit_string_; }
private:
friend class CharacterComposerTest;
@@ -85,10 +87,10 @@ class UI_EXPORT CharacterComposer {
std::vector<unsigned int> compose_buffer_;
// A string representing the composed character.
- string16 composed_character_;
+ base::string16 composed_character_;
// Preedit string.
- string16 preedit_string_;
+ base::string16 preedit_string_;
// Composition mode which this instance is in.
CompositionMode composition_mode_;
diff --git a/chromium/ui/base/ime/chromeos/character_composer_unittest.cc b/chromium/ui/base/ime/chromeos/character_composer_unittest.cc
index 4e5d7f88382..208b51f7b34 100644
--- a/chromium/ui/base/ime/chromeos/character_composer_unittest.cc
+++ b/chromium/ui/base/ime/chromeos/character_composer_unittest.cc
@@ -9,6 +9,9 @@
#include "third_party/gtk+/gdk/gdkkeysyms.h"
#include "ui/base/glib/glib_integers.h"
#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+using base::ASCIIToUTF16;
namespace ui {
@@ -60,7 +63,7 @@ class CharacterComposerTest : public testing::Test {
uint key1,
uint key2,
int flags,
- const string16& expected_character) {
+ const base::string16& expected_character) {
ExpectKeyFiltered(character_composer, key1, flags);
EXPECT_TRUE(character_composer->FilterKeyPressInternal(key2, 0, flags));
EXPECT_EQ(expected_character, character_composer->composed_character());
@@ -72,7 +75,7 @@ class CharacterComposerTest : public testing::Test {
uint key2,
uint key3,
int flags,
- const string16& expected_character) {
+ const base::string16& expected_character) {
ExpectKeyFiltered(character_composer, key1, flags);
ExpectCharacterComposed(character_composer, key2, key3, flags,
expected_character);
@@ -86,7 +89,7 @@ class CharacterComposerTest : public testing::Test {
uint key3,
uint key4,
int flags,
- const string16& expected_character) {
+ const base::string16& expected_character) {
ExpectKeyFiltered(character_composer, key1, flags);
ExpectCharacterComposed(character_composer, key2, key3, key4, flags,
expected_character);
@@ -101,7 +104,7 @@ class CharacterComposerTest : public testing::Test {
uint key4,
uint key5,
int flags,
- const string16& expected_character) {
+ const base::string16& expected_character) {
ExpectKeyFiltered(character_composer, key1, flags);
ExpectCharacterComposed(character_composer, key2, key3, key4, key5, flags,
expected_character);
@@ -117,17 +120,18 @@ class CharacterComposerTest : public testing::Test {
uint key5,
uint key6,
int flags,
- const string16& expected_character) {
+ const base::string16& expected_character) {
ExpectKeyFiltered(character_composer, key1, flags);
ExpectCharacterComposed(character_composer, key2, key3, key4, key5, key6,
flags, expected_character);
}
// Expects |expected_character| is composed after sequence [{key1, keycode1}].
- void ExpectCharacterComposedWithKeyCode(CharacterComposer* character_composer,
- uint key1, uint keycode1,
- int flags,
- const string16& expected_character) {
+ void ExpectCharacterComposedWithKeyCode(
+ CharacterComposer* character_composer,
+ uint key1, uint keycode1,
+ int flags,
+ const base::string16& expected_character) {
EXPECT_TRUE(character_composer->FilterKeyPressInternal(key1, keycode1,
flags));
EXPECT_EQ(expected_character, character_composer->composed_character());
@@ -167,26 +171,27 @@ TEST_F(CharacterComposerTest, FullyMatchingSequences) {
CharacterComposer character_composer;
// LATIN SMALL LETTER A WITH ACUTE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_a, 0,
- string16(1, 0x00E1));
+ base::string16(1, 0x00E1));
// LATIN CAPITAL LETTER A WITH ACUTE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_A, 0,
- string16(1, 0x00C1));
+ base::string16(1, 0x00C1));
// GRAVE ACCENT
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_grave,
- GDK_KEY_dead_grave, 0, string16(1, 0x0060));
+ GDK_KEY_dead_grave, 0, base::string16(1, 0x0060));
// LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute,
GDK_KEY_dead_circumflex, GDK_KEY_a, 0,
- string16(1, 0x1EA5));
+ base::string16(1, 0x1EA5));
// LATIN CAPITAL LETTER U WITH HORN AND GRAVE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_grave,
- GDK_KEY_dead_horn, GDK_KEY_U, 0, string16(1, 0x1EEA));
+ GDK_KEY_dead_horn, GDK_KEY_U, 0,
+ base::string16(1, 0x1EEA));
// LATIN CAPITAL LETTER C WITH CEDILLA
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_C, 0,
- string16(1, 0x00C7));
+ base::string16(1, 0x00C7));
// LATIN SMALL LETTER C WITH CEDILLA
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_c, 0,
- string16(1, 0x00E7));
+ base::string16(1, 0x00E7));
}
TEST_F(CharacterComposerTest, FullyMatchingSequencesAfterMatchingFailure) {
@@ -198,13 +203,13 @@ TEST_F(CharacterComposerTest, FullyMatchingSequencesAfterMatchingFailure) {
// LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute,
GDK_KEY_dead_circumflex, GDK_KEY_a, 0,
- string16(1, 0x1EA5));
+ base::string16(1, 0x1EA5));
}
TEST_F(CharacterComposerTest, ComposedCharacterIsClearedAfterReset) {
CharacterComposer character_composer;
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_a, 0,
- string16(1, 0x00E1));
+ base::string16(1, 0x00E1));
character_composer.Reset();
EXPECT_TRUE(character_composer.composed_character().empty());
}
@@ -225,7 +230,7 @@ TEST_F(CharacterComposerTest, KeySequenceCompositionPreedit) {
ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute, 0);
EXPECT_TRUE(character_composer.preedit_string().empty());
EXPECT_TRUE(FilterKeyPress(&character_composer, GDK_KEY_a, 0, 0));
- EXPECT_EQ(string16(1, 0x00E1), character_composer.composed_character());
+ EXPECT_EQ(base::string16(1, 0x00E1), character_composer.composed_character());
EXPECT_TRUE(character_composer.preedit_string().empty());
}
@@ -281,14 +286,15 @@ TEST_F(CharacterComposerTest, HexadecimalComposition) {
ExpectKeyFiltered(&character_composer, GDK_KEY_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_3, GDK_KEY_0, GDK_KEY_4,
- GDK_KEY_2, GDK_KEY_space, 0, string16(1, 0x3042));
+ GDK_KEY_2, GDK_KEY_space, 0,
+ base::string16(1, 0x3042));
// MUSICAL KEYBOARD (U+1F3B9)
- const char16 kMusicalKeyboard[] = {0xd83c, 0xdfb9};
+ const base::char16 kMusicalKeyboard[] = {0xd83c, 0xdfb9};
ExpectKeyFiltered(&character_composer, GDK_KEY_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_1, GDK_KEY_f, GDK_KEY_3,
GDK_KEY_b, GDK_KEY_9, GDK_KEY_Return, 0,
- string16(kMusicalKeyboard,
+ base::string16(kMusicalKeyboard,
kMusicalKeyboard +
arraysize(kMusicalKeyboard)));
}
@@ -310,7 +316,7 @@ TEST_F(CharacterComposerTest, HexadecimalCompositionPreedit) {
ExpectKeyFiltered(&character_composer, GDK_KEY_BackSpace, 0);
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer.preedit_string());
ExpectCharacterComposed(&character_composer, GDK_KEY_2, GDK_KEY_Return, 0,
- string16(1, 0x3042));
+ base::string16(1, 0x3042));
EXPECT_EQ(ASCIIToUTF16(""), character_composer.preedit_string());
// Sequence with an ignored character ('x') and Escape.
@@ -346,7 +352,7 @@ TEST_F(CharacterComposerTest, HexadecimalCompositionWithNonHexKey) {
EF_SHIFT_DOWN | EF_CONTROL_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_3, GDK_KEY_0, GDK_KEY_x,
GDK_KEY_4, GDK_KEY_2, GDK_KEY_space, 0,
- string16(1, 0x3042));
+ base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, HexadecimalCompositionWithAdditionalModifiers) {
@@ -357,7 +363,8 @@ TEST_F(CharacterComposerTest, HexadecimalCompositionWithAdditionalModifiers) {
ExpectKeyFiltered(&character_composer, GDK_KEY_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN | EF_ALT_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_3, GDK_KEY_0, GDK_KEY_4,
- GDK_KEY_2, GDK_KEY_space, 0, string16(1, 0x3042));
+ GDK_KEY_2, GDK_KEY_space, 0,
+ base::string16(1, 0x3042));
// Ctrl+Shift+u (CapsLock enabled)
ExpectKeyNotFiltered(&character_composer, GDK_KEY_u,
@@ -378,7 +385,8 @@ TEST_F(CharacterComposerTest, CancelHexadecimalComposition) {
ExpectKeyFiltered(&character_composer, GDK_KEY_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_3, GDK_KEY_0, GDK_KEY_4,
- GDK_KEY_2, GDK_KEY_space, 0, string16(1, 0x3042));
+ GDK_KEY_2, GDK_KEY_space, 0,
+ base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, HexadecimalCompositionWithBackspace) {
@@ -391,7 +399,7 @@ TEST_F(CharacterComposerTest, HexadecimalCompositionWithBackspace) {
ExpectKeyFiltered(&character_composer, GDK_KEY_f, 0);
ExpectKeyFiltered(&character_composer, GDK_KEY_BackSpace, 0);
ExpectCharacterComposed(&character_composer, GDK_KEY_4, GDK_KEY_2,
- GDK_KEY_space, 0, string16(1, 0x3042));
+ GDK_KEY_space, 0, base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, CancelHexadecimalCompositionWithBackspace) {
@@ -419,53 +427,53 @@ TEST_F(CharacterComposerTest, HexadecimalCompositionPreeditWithModifierPressed)
const int control_shift = EF_CONTROL_DOWN | EF_SHIFT_DOWN;
// HIRAGANA LETTER A (U+3042)
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_U, 30, control_shift);
+ GDK_KEY_U, ui::VKEY_U, control_shift);
EXPECT_EQ(ASCIIToUTF16("u"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_numbersign, 12, control_shift);
+ GDK_KEY_numbersign, ui::VKEY_3, control_shift);
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_parenright, 19, control_shift);
+ GDK_KEY_parenright, ui::VKEY_0, control_shift);
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_dollar, 13, control_shift);
+ GDK_KEY_dollar, ui::VKEY_4, control_shift);
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_A, 38, control_shift);
+ GDK_KEY_A, ui::VKEY_A, control_shift);
EXPECT_EQ(ASCIIToUTF16("u304a"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_BackSpace, 22, control_shift);
+ GDK_KEY_BackSpace, ui::VKEY_BACK, control_shift);
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_at, 11, control_shift);
+ GDK_KEY_at, ui::VKEY_2, control_shift);
EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer.preedit_string());
ExpectCharacterComposedWithKeyCode(&character_composer,
- GDK_KEY_Return, 36,
+ GDK_KEY_Return, ui::VKEY_RETURN,
control_shift,
- string16(1, 0x3042));
+ base::string16(1, 0x3042));
EXPECT_EQ(ASCIIToUTF16(""), character_composer.preedit_string());
// Sequence with an ignored character (control + shift + 'x') and Escape.
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_U, 30, control_shift);
+ GDK_KEY_U, ui::VKEY_U, control_shift);
EXPECT_EQ(ASCIIToUTF16("u"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_numbersign, 12, control_shift);
+ GDK_KEY_numbersign, ui::VKEY_3, control_shift);
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_parenright, 19, control_shift);
+ GDK_KEY_parenright, ui::VKEY_0, control_shift);
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_X, 53, control_shift);
+ GDK_KEY_X, ui::VKEY_X, control_shift);
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_dollar, 13, control_shift);
+ GDK_KEY_dollar, ui::VKEY_4, control_shift);
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_at, 11, control_shift);
+ GDK_KEY_at, ui::VKEY_2, control_shift);
EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer.preedit_string());
ExpectKeyFilteredWithKeycode(&character_composer,
- GDK_KEY_Escape, 9, control_shift);
+ GDK_KEY_Escape, ui::VKEY_ESCAPE, control_shift);
EXPECT_EQ(ASCIIToUTF16(""), character_composer.preedit_string());
}
@@ -509,18 +517,18 @@ TEST_F(CharacterComposerTest, HexadecimalSequenceAndDeadKey) {
CharacterComposer character_composer;
// LATIN SMALL LETTER A WITH ACUTE
ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_a, 0,
- string16(1, 0x00E1));
+ base::string16(1, 0x00E1));
// HIRAGANA LETTER A (U+3042) with dead_acute ignored.
ExpectKeyFiltered(&character_composer, GDK_KEY_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN);
ExpectCharacterComposed(&character_composer, GDK_KEY_3, GDK_KEY_0,
GDK_KEY_dead_acute, GDK_KEY_4, GDK_KEY_2,
- GDK_KEY_space, 0, string16(1, 0x3042));
+ GDK_KEY_space, 0, base::string16(1, 0x3042));
// LATIN CAPITAL LETTER U WITH ACUTE while 'U' is pressed with Ctrl+Shift.
ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute, 0);
EXPECT_TRUE(FilterKeyPress(&character_composer, GDK_KEY_U, 0,
EF_SHIFT_DOWN | EF_CONTROL_DOWN));
- EXPECT_EQ(string16(1, 0x00DA), character_composer.composed_character());
+ EXPECT_EQ(base::string16(1, 0x00DA), character_composer.composed_character());
}
TEST_F(CharacterComposerTest, BlacklistedKeyeventsTest) {
diff --git a/chromium/ui/base/ime/chromeos/ibus_bridge.cc b/chromium/ui/base/ime/chromeos/ibus_bridge.cc
deleted file mode 100644
index bf10ebeaf92..00000000000
--- a/chromium/ui/base/ime/chromeos/ibus_bridge.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-
-#include <map>
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-
-namespace chromeos {
-
-static IBusBridge* g_ibus_bridge = NULL;
-
-// An implementation of IBusBridge.
-class IBusBridgeImpl : public IBusBridge {
- public:
- IBusBridgeImpl()
- : input_context_handler_(NULL),
- engine_handler_(NULL),
- candidate_window_handler_(NULL) {
- }
-
- virtual ~IBusBridgeImpl() {
- }
-
- // IBusBridge override.
- virtual IBusInputContextHandlerInterface*
- GetInputContextHandler() const OVERRIDE {
- return input_context_handler_;
- }
-
- // IBusBridge override.
- virtual void SetInputContextHandler(
- IBusInputContextHandlerInterface* handler) OVERRIDE {
- input_context_handler_ = handler;
- }
-
- // IBusBridge override.
- virtual void SetEngineHandler(
- const std::string& engine_id,
- IBusEngineHandlerInterface* handler) OVERRIDE {
- DCHECK(!engine_id.empty());
- DCHECK(handler);
- engine_handler_map_[engine_id] = handler;
- }
-
- // IBusBridge override.
- virtual IBusEngineHandlerInterface* GetEngineHandler(
- const std::string& engine_id) OVERRIDE {
- if (engine_id.empty() ||
- engine_handler_map_.find(engine_id) == engine_handler_map_.end()) {
- return NULL;
- }
- return engine_handler_map_[engine_id];
- }
-
- // IBusBridge override.
- virtual void SetCurrentEngineHandler(
- IBusEngineHandlerInterface* handler) OVERRIDE {
- engine_handler_ = handler;
- }
-
- // IBusBridge override.
- virtual IBusEngineHandlerInterface* SetCurrentEngineHandlerById(
- const std::string& engine_id) OVERRIDE {
- if (engine_id.empty()) {
- engine_handler_ = NULL;
- return NULL;
- }
-
- DCHECK(engine_handler_map_.find(engine_id) != engine_handler_map_.end());
- engine_handler_ = engine_handler_map_[engine_id];
- return engine_handler_;
- }
-
- // IBusBridge override.
- virtual IBusEngineHandlerInterface* GetCurrentEngineHandler() const OVERRIDE {
- return engine_handler_;
- }
-
- // IBusBridge override.
- virtual IBusPanelCandidateWindowHandlerInterface*
- GetCandidateWindowHandler() const OVERRIDE {
- return candidate_window_handler_;
- }
-
- // IBusBridge override.
- virtual void SetCandidateWindowHandler(
- IBusPanelCandidateWindowHandlerInterface* handler) OVERRIDE {
- candidate_window_handler_ = handler;
- }
-
- private:
- IBusInputContextHandlerInterface* input_context_handler_;
- IBusEngineHandlerInterface* engine_handler_;
- IBusPanelCandidateWindowHandlerInterface* candidate_window_handler_;
- std::map<std::string, IBusEngineHandlerInterface*> engine_handler_map_;
-
- DISALLOW_COPY_AND_ASSIGN(IBusBridgeImpl);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// IBusBridge
-IBusBridge::IBusBridge() {
-}
-
-IBusBridge::~IBusBridge() {
-}
-
-// static.
-void IBusBridge::Initialize() {
- if (!g_ibus_bridge)
- g_ibus_bridge = new IBusBridgeImpl();
-}
-
-// static.
-void IBusBridge::Shutdown() {
- delete g_ibus_bridge;
- g_ibus_bridge = NULL;
-}
-
-// static.
-IBusBridge* IBusBridge::Get() {
- return g_ibus_bridge;
-}
-
-} // namespace chromeos
diff --git a/chromium/ui/base/ime/chromeos/ibus_bridge.h b/chromium/ui/base/ime/chromeos/ibus_bridge.h
deleted file mode 100644
index 6cac4c01389..00000000000
--- a/chromium/ui/base/ime/chromeos/ibus_bridge.h
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// TODO(nona): Rename this file to ime_bridge.h
-
-#ifndef UI_BASE_IME_CHROMEOS_IBUS_BRIDGE_H_
-#define UI_BASE_IME_CHROMEOS_IBUS_BRIDGE_H_
-
-#include <string>
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "ui/base/ime/text_input_mode.h"
-#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_export.h"
-
-namespace gfx {
-class Rect;
-} // namespace gfx
-
-namespace ui {
-class KeyEvent;
-} // namespace ui
-
-namespace chromeos {
-namespace input_method {
-class CandidateWindow;
-} // namespace input_method
-
-class IBusText;
-
-class UI_EXPORT IBusInputContextHandlerInterface {
- public:
- // Called when the engine commit a text.
- virtual void CommitText(const std::string& text) = 0;
-
- // Called when the engine update preedit stroing.
- virtual void UpdatePreeditText(const IBusText& text,
- uint32 cursor_pos,
- bool visible) = 0;
-
- // Called when the engine request deleting surrounding string.
- virtual void DeleteSurroundingText(int32 offset, uint32 length) = 0;
-};
-
-
-// A interface to handle the engine handler method call.
-class UI_EXPORT IBusEngineHandlerInterface {
- public:
- typedef base::Callback<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
- // used to specify about a non html text field like Omnibox.
- struct InputContext {
- InputContext(ui::TextInputType type_, ui::TextInputMode mode_) :
- type(type_), mode(mode_) {}
-
- // An attribute of the field defined at
- // http://www.w3.org/TR/html401/interact/forms.html#input-control-types.
- ui::TextInputType type;
- // An attribute of the field defined at
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/
- // association-of-controls-and-forms.html#input-modalities
- // :-the-inputmode-attribute.
- ui::TextInputMode mode;
- };
-
- virtual ~IBusEngineHandlerInterface() {}
-
- // Called when the Chrome input field get the focus.
- virtual void FocusIn(const InputContext& input_context) = 0;
-
- // Called when the Chrome input field lose the focus.
- virtual void FocusOut() = 0;
-
- // Called when the IME is enabled.
- virtual void Enable() = 0;
-
- // Called when the IME is disabled.
- virtual void Disable() = 0;
-
- // Called when a property is activated or changed.
- virtual void PropertyActivate(const std::string& property_name) = 0;
-
- // Called when the IME is reset.
- virtual void Reset() = 0;
-
- // Called when the key event is received.
- // Actual implementation must call |callback| after key event handling.
- virtual void ProcessKeyEvent(const ui::KeyEvent& key_event,
- const KeyEventDoneCallback& callback) = 0;
-
- // Called when the candidate in lookup table is clicked. The |index| is 0
- // based candidate index in lookup table.
- virtual void CandidateClicked(uint32 index) = 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
- // selection range, |anchor_pos| represents opposite index from |cursor_pos|.
- // Otherwise |anchor_pos| is equal to |cursor_pos|.
- virtual void SetSurroundingText(const std::string& text, uint32 cursor_pos,
- uint32 anchor_pos) = 0;
-
- protected:
- IBusEngineHandlerInterface() {}
-};
-
-// A interface to handle the candidate window related method call.
-class UI_EXPORT IBusPanelCandidateWindowHandlerInterface {
- public:
- virtual ~IBusPanelCandidateWindowHandlerInterface() {}
-
- // Called when the IME updates the lookup table.
- virtual void UpdateLookupTable(
- const input_method::CandidateWindow& candidate_window,
- bool visible) = 0;
-
- // Called when the IME updates the auxiliary text. The |text| is given in
- // UTF-8 encoding.
- virtual void UpdateAuxiliaryText(const std::string& text, bool visible) = 0;
-
- // Called when the IME updates the preedit text. The |text| is given in
- // UTF-8 encoding.
- virtual void UpdatePreeditText(const std::string& text, uint32 cursor_pos,
- bool visible) = 0;
-
- // Called when the application changes its caret bounds.
- virtual void SetCursorBounds(const gfx::Rect& cursor_bounds,
- const gfx::Rect& composition_head) = 0;
-
- // Called when the text field's focus state is changed.
- // |is_focused| is true when the text field gains the focus.
- virtual void FocusStateChanged(bool is_focused) {}
-
- protected:
- IBusPanelCandidateWindowHandlerInterface() {}
-};
-
-
-// IBusBridge provides access of each IME related handler. This class is used
-// for IME implementation without ibus-daemon. The legacy ibus IME communicates
-// their engine with dbus protocol, but new implementation doesn't. Instead of
-// dbus communcation, new implementation calls target service(e.g. PanelService
-// or EngineService) directly by using this class.
-class UI_EXPORT IBusBridge {
- public:
- virtual ~IBusBridge();
-
- // Allocates the global instance. Must be called before any calls to Get().
- static void Initialize();
-
- // Releases the global instance.
- static void Shutdown();
-
- // Returns IBusBridge global instance. Initialize() must be called first.
- static IBusBridge* Get();
-
- // Returns current InputContextHandler. This function returns NULL if input
- // context is not ready to use.
- virtual IBusInputContextHandlerInterface* GetInputContextHandler() const = 0;
-
- // Updates current InputContextHandler. If there is no active input context,
- // pass NULL for |handler|. Caller must release |handler|.
- virtual void SetInputContextHandler(
- IBusInputContextHandlerInterface* handler) = 0;
-
- // Initializes the mapping from |engine_id| to |handler|.
- // |engine_id| must not be empty and |handler| must not be null.
- virtual void SetEngineHandler(
- const std::string& engine_id,
- IBusEngineHandlerInterface* handler) = 0;
-
- // Returns IBusEngineHandlerInterface* mapped by |engine_id|. NULL is
- // returned if |engine_id| is not mapped any engines.
- virtual IBusEngineHandlerInterface* GetEngineHandler(
- const std::string& engine_id) = 0;
-
- // Updates current EngineHandler. If there is no active engine service, pass
- // NULL for |handler|. Caller must release |handler|.
- virtual void SetCurrentEngineHandler(IBusEngineHandlerInterface* handler) = 0;
-
- // Updates current EngineHandler by Engine ID. If there is no active
- // engine service, pass an empty string for |engine_id|. The set
- // IBusEngineHandlerInterface is returned.
- virtual IBusEngineHandlerInterface* SetCurrentEngineHandlerById(
- const std::string& engine_id) = 0;
-
- // Returns current EngineHandler. This function returns NULL if current engine
- // is not ready to use.
- virtual IBusEngineHandlerInterface* GetCurrentEngineHandler() const = 0;
-
- // Returns current CandidateWindowHandler. This function returns NULL if
- // current candidate window is not ready to use.
- virtual IBusPanelCandidateWindowHandlerInterface*
- GetCandidateWindowHandler() const = 0;
-
- // Updates current CandidatWindowHandler. If there is no active candidate
- // window service, pass NULL for |handler|. Caller must release |handler|.
- virtual void SetCandidateWindowHandler(
- IBusPanelCandidateWindowHandlerInterface* handler) = 0;
-
- protected:
- IBusBridge();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IBusBridge);
-};
-
-} // namespace chromeos
-
-#endif // UI_BASE_IME_CHROMEOS_IBUS_BRIDGE_H_
diff --git a/chromium/ui/base/ime/chromeos/ime_bridge.cc b/chromium/ui/base/ime/chromeos/ime_bridge.cc
new file mode 100644
index 00000000000..49d0f73df3c
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/ime_bridge.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/chromeos/ime_bridge.h"
+
+#include <map>
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+
+namespace chromeos {
+
+static IMEBridge* g_ime_bridge = NULL;
+
+// An implementation of IMEBridge.
+class IMEBridgeImpl : public IMEBridge {
+ public:
+ IMEBridgeImpl()
+ : input_context_handler_(NULL),
+ engine_handler_(NULL),
+ candidate_window_handler_(NULL),
+ current_text_input_(ui::TEXT_INPUT_TYPE_NONE) {
+ }
+
+ virtual ~IMEBridgeImpl() {
+ }
+
+ // IMEBridge override.
+ virtual IMEInputContextHandlerInterface*
+ GetInputContextHandler() const OVERRIDE {
+ return input_context_handler_;
+ }
+
+ // IMEBridge override.
+ virtual void SetInputContextHandler(
+ IMEInputContextHandlerInterface* handler) OVERRIDE {
+ input_context_handler_ = handler;
+ }
+
+ // IMEBridge override.
+ virtual void SetCurrentEngineHandler(
+ IMEEngineHandlerInterface* handler) OVERRIDE {
+ engine_handler_ = handler;
+ }
+
+ // IMEBridge override.
+ virtual IMEEngineHandlerInterface* GetCurrentEngineHandler() const OVERRIDE {
+ return engine_handler_;
+ }
+
+ // IMEBridge override.
+ virtual IMECandidateWindowHandlerInterface* GetCandidateWindowHandler() const
+ OVERRIDE {
+ return candidate_window_handler_;
+ }
+
+ // IMEBridge override.
+ virtual void SetCandidateWindowHandler(
+ IMECandidateWindowHandlerInterface* handler) OVERRIDE {
+ candidate_window_handler_ = handler;
+ }
+
+ // IMEBridge override.
+ virtual void SetCurrentTextInputType(ui::TextInputType input_type) OVERRIDE {
+ current_text_input_ = input_type;
+ }
+
+ // IMEBridge override.
+ virtual ui::TextInputType GetCurrentTextInputType() const OVERRIDE {
+ return current_text_input_;
+ }
+
+ private:
+ IMEInputContextHandlerInterface* input_context_handler_;
+ IMEEngineHandlerInterface* engine_handler_;
+ IMECandidateWindowHandlerInterface* candidate_window_handler_;
+ ui::TextInputType current_text_input_;
+
+ DISALLOW_COPY_AND_ASSIGN(IMEBridgeImpl);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// IMEBridge
+IMEBridge::IMEBridge() {
+}
+
+IMEBridge::~IMEBridge() {
+}
+
+// static.
+void IMEBridge::Initialize() {
+ if (!g_ime_bridge)
+ g_ime_bridge = new IMEBridgeImpl();
+}
+
+// static.
+void IMEBridge::Shutdown() {
+ delete g_ime_bridge;
+ g_ime_bridge = NULL;
+}
+
+// static.
+IMEBridge* IMEBridge::Get() {
+ return g_ime_bridge;
+}
+
+} // namespace chromeos
diff --git a/chromium/ui/base/ime/chromeos/ime_bridge.h b/chromium/ui/base/ime/chromeos/ime_bridge.h
new file mode 100644
index 00000000000..2464f3ff89f
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/ime_bridge.h
@@ -0,0 +1,191 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_CHROMEOS_IME_BRIDGE_H_
+#define UI_BASE_IME_CHROMEOS_IME_BRIDGE_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "ui/base/ime/text_input_mode.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/base/ui_base_export.h"
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace ui {
+class CandidateWindow;
+class KeyEvent;
+} // namespace ui
+
+namespace chromeos {
+
+class CompositionText;
+
+class UI_BASE_EXPORT IMEInputContextHandlerInterface {
+ public:
+ // Called when the engine commit a text.
+ virtual void CommitText(const std::string& text) = 0;
+
+ // Called when the engine updates composition text.
+ virtual void UpdateCompositionText(const CompositionText& text,
+ uint32 cursor_pos,
+ bool visible) = 0;
+
+ // Called when the engine request deleting surrounding string.
+ virtual void DeleteSurroundingText(int32 offset, uint32 length) = 0;
+};
+
+
+// A interface to handle the engine handler method call.
+class UI_BASE_EXPORT IMEEngineHandlerInterface {
+ public:
+ typedef base::Callback<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
+ // used to specify about a non html text field like Omnibox.
+ struct InputContext {
+ InputContext(ui::TextInputType type_, ui::TextInputMode mode_) :
+ type(type_), mode(mode_) {}
+
+ // An attribute of the field defined at
+ // http://www.w3.org/TR/html401/interact/forms.html#input-control-types.
+ ui::TextInputType type;
+ // An attribute of the field defined at
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/
+ // association-of-controls-and-forms.html#input-modalities
+ // :-the-inputmode-attribute.
+ ui::TextInputMode mode;
+ };
+
+ virtual ~IMEEngineHandlerInterface() {}
+
+ // Called when the Chrome input field get the focus.
+ virtual void FocusIn(const InputContext& input_context) = 0;
+
+ // Called when the Chrome input field lose the focus.
+ virtual void FocusOut() = 0;
+
+ // Called when the IME is enabled.
+ virtual void Enable() = 0;
+
+ // Called when the IME is disabled.
+ virtual void Disable() = 0;
+
+ // Called when a property is activated or changed.
+ virtual void PropertyActivate(const std::string& property_name) = 0;
+
+ // Called when the IME is reset.
+ virtual void Reset() = 0;
+
+ // Called when the key event is received.
+ // Actual implementation must call |callback| after key event handling.
+ virtual void ProcessKeyEvent(const ui::KeyEvent& key_event,
+ const KeyEventDoneCallback& callback) = 0;
+
+ // Called when the candidate in lookup table is clicked. The |index| is 0
+ // based candidate index in lookup table.
+ virtual void CandidateClicked(uint32 index) = 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
+ // selection range, |anchor_pos| represents opposite index from |cursor_pos|.
+ // Otherwise |anchor_pos| is equal to |cursor_pos|.
+ virtual void SetSurroundingText(const std::string& text, uint32 cursor_pos,
+ uint32 anchor_pos) = 0;
+
+ protected:
+ IMEEngineHandlerInterface() {}
+};
+
+// A interface to handle the candidate window related method call.
+class UI_BASE_EXPORT IMECandidateWindowHandlerInterface {
+ public:
+ virtual ~IMECandidateWindowHandlerInterface() {}
+
+ // Called when the IME updates the lookup table.
+ virtual void UpdateLookupTable(const ui::CandidateWindow& candidate_window,
+ bool visible) = 0;
+
+ // Called when the IME updates the preedit text. The |text| is given in
+ // UTF-16 encoding.
+ virtual void UpdatePreeditText(const base::string16& text,
+ uint32 cursor_pos,
+ bool visible) = 0;
+
+ // Called when the application changes its caret bounds.
+ virtual void SetCursorBounds(const gfx::Rect& cursor_bounds,
+ const gfx::Rect& composition_head) = 0;
+
+ // Called when the text field's focus state is changed.
+ // |is_focused| is true when the text field gains the focus.
+ virtual void FocusStateChanged(bool is_focused) {}
+
+ protected:
+ IMECandidateWindowHandlerInterface() {}
+};
+
+
+// IMEBridge provides access of each IME related handler. This class
+// is used for IME implementation.
+class UI_BASE_EXPORT IMEBridge {
+ public:
+ virtual ~IMEBridge();
+
+ // Allocates the global instance. Must be called before any calls to Get().
+ static void Initialize();
+
+ // Releases the global instance.
+ static void Shutdown();
+
+ // Returns IMEBridge global instance. Initialize() must be called first.
+ static IMEBridge* Get();
+
+ // Returns current InputContextHandler. This function returns NULL if input
+ // context is not ready to use.
+ virtual IMEInputContextHandlerInterface* GetInputContextHandler() const = 0;
+
+ // Updates current InputContextHandler. If there is no active input context,
+ // pass NULL for |handler|. Caller must release |handler|.
+ virtual void SetInputContextHandler(
+ IMEInputContextHandlerInterface* handler) = 0;
+
+ // Updates current EngineHandler. If there is no active engine service, pass
+ // NULL for |handler|. Caller must release |handler|.
+ virtual void SetCurrentEngineHandler(IMEEngineHandlerInterface* handler) = 0;
+
+ // Returns current EngineHandler. This function returns NULL if current engine
+ // is not ready to use.
+ virtual IMEEngineHandlerInterface* GetCurrentEngineHandler() const = 0;
+
+ // Returns current CandidateWindowHandler. This function returns NULL if
+ // current candidate window is not ready to use.
+ virtual IMECandidateWindowHandlerInterface* GetCandidateWindowHandler()
+ const = 0;
+
+ // Updates current CandidatWindowHandler. If there is no active candidate
+ // window service, pass NULL for |handler|. Caller must release |handler|.
+ virtual void SetCandidateWindowHandler(
+ IMECandidateWindowHandlerInterface* handler) = 0;
+
+ // Updates current text input type.
+ virtual void SetCurrentTextInputType(ui::TextInputType input_type) = 0;
+
+ // Returns the current text input type.
+ virtual ui::TextInputType GetCurrentTextInputType() const = 0;
+
+ protected:
+ IMEBridge();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IMEBridge);
+};
+
+} // namespace chromeos
+
+#endif // UI_BASE_IME_CHROMEOS_IME_BRIDGE_H_
diff --git a/chromium/ui/base/ime/chromeos/ime_keymap.cc b/chromium/ui/base/ime/chromeos/ime_keymap.cc
new file mode 100644
index 00000000000..c6686094a44
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/ime_keymap.cc
@@ -0,0 +1,180 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/chromeos/ime_keymap.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+
+namespace ui {
+
+namespace {
+
+const struct KeyCodeTable {
+ KeyboardCode keyboard_code;
+ const char* dom_code;
+} kKeyCodeTable[] = {
+ {VKEY_BACK, "Backspace"},
+ {VKEY_TAB, "Tab"},
+ {VKEY_RETURN, "Enter"},
+ {VKEY_MENU, "ContextMenu"},
+ {VKEY_PAUSE, "Pause"},
+ {VKEY_CAPITAL, "CapsLock"},
+ {VKEY_KANA, "KanaMode"},
+ {VKEY_HANGUL, "HangulMode"},
+ {VKEY_HANJA, "Hanja"},
+ {VKEY_KANJI, "Kanji"},
+ {VKEY_ESCAPE, "Escape"},
+ {VKEY_CONVERT, "Convert"},
+ {VKEY_NONCONVERT, "NoConvert"},
+ {VKEY_SPACE, "Space"},
+ {VKEY_END, "End"},
+ {VKEY_HOME, "Home"},
+ {VKEY_LEFT, "ArrowLeft"},
+ {VKEY_UP, "ArrowUp"},
+ {VKEY_RIGHT, "ArrowRight"},
+ {VKEY_DOWN, "ArrowDown"},
+ {VKEY_PRINT, "PrintScreen"},
+ {VKEY_INSERT, "Insert"},
+ {VKEY_DELETE, "Delete"},
+ {VKEY_HELP, "Help"},
+ {VKEY_0, "Digit0"},
+ {VKEY_1, "Digit1"},
+ {VKEY_2, "Digit2"},
+ {VKEY_3, "Digit3"},
+ {VKEY_4, "Digit4"},
+ {VKEY_5, "Digit5"},
+ {VKEY_6, "Digit6"},
+ {VKEY_7, "Digit7"},
+ {VKEY_8, "Digit8"},
+ {VKEY_9, "Digit9"},
+ {VKEY_A, "KeyA"},
+ {VKEY_B, "KeyB"},
+ {VKEY_C, "KeyC"},
+ {VKEY_D, "KeyD"},
+ {VKEY_E, "KeyE"},
+ {VKEY_F, "KeyF"},
+ {VKEY_G, "KeyG"},
+ {VKEY_H, "KeyH"},
+ {VKEY_I, "KeyI"},
+ {VKEY_J, "KeyJ"},
+ {VKEY_K, "KeyK"},
+ {VKEY_L, "KeyL"},
+ {VKEY_M, "KeyM"},
+ {VKEY_N, "KeyN"},
+ {VKEY_O, "KeyO"},
+ {VKEY_P, "KeyP"},
+ {VKEY_Q, "KeyQ"},
+ {VKEY_R, "KeyR"},
+ {VKEY_S, "KeyS"},
+ {VKEY_T, "KeyT"},
+ {VKEY_U, "KeyU"},
+ {VKEY_V, "KeyV"},
+ {VKEY_W, "KeyW"},
+ {VKEY_X, "KeyX"},
+ {VKEY_Y, "KeyY"},
+ {VKEY_Z, "KeyZ"},
+ {VKEY_LWIN, "OSLeft"},
+ {VKEY_RWIN, "OSRight"},
+ {VKEY_NUMPAD0, "Numpad0"},
+ {VKEY_NUMPAD1, "Numpad1"},
+ {VKEY_NUMPAD2, "Numpad2"},
+ {VKEY_NUMPAD3, "Numpad3"},
+ {VKEY_NUMPAD4, "Numpad4"},
+ {VKEY_NUMPAD5, "Numpad5"},
+ {VKEY_NUMPAD6, "Numpad6"},
+ {VKEY_NUMPAD7, "Numpad7"},
+ {VKEY_NUMPAD8, "Numpad8"},
+ {VKEY_NUMPAD9, "Numpad9"},
+ {VKEY_MULTIPLY, "NumpadMultiply"},
+ {VKEY_ADD, "NumpadAdd"},
+ {VKEY_SUBTRACT, "NumpadSubtract"},
+ {VKEY_DECIMAL, "NumpadDecimal"},
+ {VKEY_DIVIDE, "NumpadDivide"},
+ {VKEY_F1, "F1"},
+ {VKEY_F2, "F2"},
+ {VKEY_F3, "F3"},
+ {VKEY_F4, "F4"},
+ {VKEY_F5, "F5"},
+ {VKEY_F6, "F6"},
+ {VKEY_F7, "F7"},
+ {VKEY_F8, "F8"},
+ {VKEY_F9, "F9"},
+ {VKEY_F10, "F10"},
+ {VKEY_F11, "F11"},
+ {VKEY_F12, "F12"},
+ {VKEY_F13, "F13"},
+ {VKEY_F14, "F14"},
+ {VKEY_F15, "F15"},
+ {VKEY_F16, "F16"},
+ {VKEY_F17, "F17"},
+ {VKEY_F18, "F18"},
+ {VKEY_F19, "F19"},
+ {VKEY_F20, "F20"},
+ {VKEY_F21, "F21"},
+ {VKEY_F22, "F22"},
+ {VKEY_F23, "F23"},
+ {VKEY_F24, "F24"},
+ {VKEY_NUMLOCK, "NumLock"},
+ {VKEY_SCROLL, "ScrollLock"},
+ {VKEY_LSHIFT, "ShiftLeft"},
+ {VKEY_RSHIFT, "ShiftRight"},
+ {VKEY_LCONTROL, "CtrlLeft"},
+ {VKEY_RCONTROL, "CtrlRight"},
+ {VKEY_LMENU, "AltLeft"},
+ {VKEY_RMENU, "AltRight"},
+ {VKEY_BROWSER_BACK, "BrowserBack"},
+ {VKEY_BROWSER_FORWARD, "BrowserForward"},
+ {VKEY_BROWSER_REFRESH, "BrowserRefresh"},
+ {VKEY_BROWSER_STOP, "BrowserStop"},
+ {VKEY_BROWSER_SEARCH, "BrowserSearch"},
+ {VKEY_BROWSER_HOME, "BrowserHome"},
+ {VKEY_VOLUME_MUTE, "VolumeMute"},
+ {VKEY_VOLUME_DOWN, "VolumeDown"},
+ {VKEY_VOLUME_UP, "VolumeUp"},
+ {VKEY_MEDIA_NEXT_TRACK, "MediaTrackNext"},
+ {VKEY_MEDIA_PREV_TRACK, "MediaTrackPrevious"},
+ {VKEY_MEDIA_STOP, "MediaStop"},
+ {VKEY_MEDIA_PLAY_PAUSE, "MediaPlayPause"},
+ {VKEY_MEDIA_LAUNCH_MAIL, "LaunchMail"},
+ {VKEY_OEM_1, "Semicolon"},
+ {VKEY_OEM_PLUS, "Equal"},
+ {VKEY_OEM_COMMA, "Comma"},
+ {VKEY_OEM_MINUS, "Minus"},
+ {VKEY_OEM_PERIOD, "Period"},
+ {VKEY_OEM_2, "Slash"},
+ {VKEY_OEM_3, "Backquote"},
+ {VKEY_OEM_4, "BracketLeft"},
+ {VKEY_OEM_5, "Backslash"},
+ {VKEY_OEM_6, "BracketRight"},
+ {VKEY_OEM_7, "Quote"}};
+
+class KeyCodeMap {
+ public:
+ KeyCodeMap() {
+ for (size_t i = 0; i < arraysize(kKeyCodeTable); ++i)
+ map_[kKeyCodeTable[i].dom_code] = kKeyCodeTable[i].keyboard_code;
+ }
+
+ KeyboardCode GetKeyboardCode(const std::string& dom_code) const {
+ std::map<std::string, KeyboardCode>::const_iterator it =
+ map_.find(dom_code);
+ return (it == map_.end()) ? VKEY_UNKNOWN : it->second;
+ }
+
+ private:
+ std::map<std::string, KeyboardCode> map_;
+};
+
+base::LazyInstance<KeyCodeMap>::Leaky g_keycode_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+KeyboardCode DomKeycodeToKeyboardCode(const std::string& code) {
+ return g_keycode_map.Get().GetKeyboardCode(code);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/chromeos/ime_keymap.h b/chromium/ui/base/ime/chromeos/ime_keymap.h
new file mode 100644
index 00000000000..7d41b3f323d
--- /dev/null
+++ b/chromium/ui/base/ime/chromeos/ime_keymap.h
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_CHROMEOS_IME_KEYMAP_H_
+#define UI_BASE_IME_CHROMEOS_IME_KEYMAP_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace ui {
+
+// Translates the DOM4 key code string to ui::KeyboardCode.
+UI_BASE_EXPORT KeyboardCode DomKeycodeToKeyboardCode(const std::string& code);
+
+} // namespace ui
+
+#endif // UI_BASE_IME_CHROMEOS_IME_KEYMAP_H_
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc b/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
index 7491643d312..6e6187657b4 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
+++ b/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
@@ -8,8 +8,7 @@ namespace chromeos {
MockIMECandidateWindowHandler::MockIMECandidateWindowHandler()
: set_cursor_bounds_call_count_(0),
- update_lookup_table_call_count_(0),
- update_auxiliary_text_call_count_(0) {
+ update_lookup_table_call_count_(0) {
}
MockIMECandidateWindowHandler::~MockIMECandidateWindowHandler() {
@@ -17,24 +16,17 @@ MockIMECandidateWindowHandler::~MockIMECandidateWindowHandler() {
}
void MockIMECandidateWindowHandler::UpdateLookupTable(
- const input_method::CandidateWindow& table,
+ const ui::CandidateWindow& table,
bool visible) {
++update_lookup_table_call_count_;
last_update_lookup_table_arg_.lookup_table.CopyFrom(table);
last_update_lookup_table_arg_.is_visible = visible;
}
-void MockIMECandidateWindowHandler::UpdateAuxiliaryText(const std::string& text,
- bool visible) {
- ++update_auxiliary_text_call_count_;
- last_update_auxiliary_text_arg_.text = text;
- last_update_auxiliary_text_arg_.is_visible = visible;
-}
-
-void MockIMECandidateWindowHandler::UpdatePreeditText(const std::string& text,
- uint32 cursor_pos,
- bool visible) {
-}
+void MockIMECandidateWindowHandler::UpdatePreeditText(
+ const base::string16& text,
+ uint32 cursor_pos,
+ bool visible) {}
void MockIMECandidateWindowHandler::SetCursorBounds(
const gfx::Rect& cursor_bounds,
@@ -45,7 +37,6 @@ void MockIMECandidateWindowHandler::SetCursorBounds(
void MockIMECandidateWindowHandler::Reset() {
set_cursor_bounds_call_count_ = 0;
update_lookup_table_call_count_ = 0;
- update_auxiliary_text_call_count_ = 0;
}
} // namespace chromeos
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h b/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
index 5d03b12e485..a7705e32571 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
+++ b/chromium/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
@@ -5,17 +5,17 @@
#ifndef UI_BASE_IME_CHROMEOS_MOCK_IME_CANDIDATE_WINDOW_HANDLER_H_
#define UI_BASE_IME_CHROMEOS_MOCK_IME_CANDIDATE_WINDOW_HANDLER_H_
-#include "chromeos/ime/candidate_window.h"
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ime/candidate_window.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ui_base_export.h"
namespace chromeos {
-class UI_EXPORT MockIMECandidateWindowHandler
- : public IBusPanelCandidateWindowHandlerInterface {
+class UI_BASE_EXPORT MockIMECandidateWindowHandler
+ : public IMECandidateWindowHandlerInterface {
public:
struct UpdateLookupTableArg {
- input_method::CandidateWindow lookup_table;
+ ui::CandidateWindow lookup_table;
bool is_visible;
};
@@ -27,14 +27,12 @@ class UI_EXPORT MockIMECandidateWindowHandler
MockIMECandidateWindowHandler();
virtual ~MockIMECandidateWindowHandler();
- // IBusPanelCandidateWindowHandlerInterface override.
+ // IMECandidateWindowHandlerInterface override.
virtual void UpdateLookupTable(
- const input_method::CandidateWindow& candidate_window,
+ const ui::CandidateWindow& candidate_window,
bool visible) OVERRIDE;
- virtual void UpdateAuxiliaryText(const std::string& text,
- bool visible) OVERRIDE;
- virtual void UpdatePreeditText(const std::string& text, uint32 cursor_pos,
- bool visible) OVERRIDE;
+ virtual void UpdatePreeditText(
+ const base::string16& text, uint32 cursor_pos, bool visible) OVERRIDE;
virtual void SetCursorBounds(const gfx::Rect& cursor_bounds,
const gfx::Rect& composition_head) OVERRIDE;
@@ -46,27 +44,16 @@ class UI_EXPORT MockIMECandidateWindowHandler
return update_lookup_table_call_count_;
}
- int update_auxiliary_text_call_count() const {
- return update_auxiliary_text_call_count_;
- }
-
const UpdateLookupTableArg& last_update_lookup_table_arg() {
return last_update_lookup_table_arg_;
}
-
- const UpdateAuxiliaryTextArg& last_update_auxiliary_text_arg() {
- return last_update_auxiliary_text_arg_;
- }
-
// Resets all call count.
void Reset();
private:
int set_cursor_bounds_call_count_;
int update_lookup_table_call_count_;
- int update_auxiliary_text_call_count_;
UpdateLookupTableArg last_update_lookup_table_arg_;
- UpdateAuxiliaryTextArg last_update_auxiliary_text_arg_;
};
} // namespace chromeos
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.cc b/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.cc
index f5e17238eed..000feef92b5 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.cc
+++ b/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.cc
@@ -22,12 +22,15 @@ MockIMEEngineHandler::~MockIMEEngineHandler() {
}
void MockIMEEngineHandler::FocusIn(const InputContext& input_context) {
- ++focus_in_call_count_;
last_text_input_context_ = input_context;
+ if (last_text_input_context_.type != ui::TEXT_INPUT_TYPE_NONE)
+ ++focus_in_call_count_;
}
void MockIMEEngineHandler::FocusOut() {
- ++focus_out_call_count_;
+ if (last_text_input_context_.type != ui::TEXT_INPUT_TYPE_NONE)
+ ++focus_out_call_count_;
+ last_text_input_context_.type = ui::TEXT_INPUT_TYPE_NONE;
}
void MockIMEEngineHandler::Enable() {
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.h b/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.h
index 3626ca5e913..bea6a8bd725 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.h
+++ b/chromium/ui/base/ime/chromeos/mock_ime_engine_handler.h
@@ -5,13 +5,13 @@
#ifndef UI_BASE_IME_CHROMEOS_MOCK_IME_ENGINE_HANDLER_H_
#define UI_BASE_IME_CHROMEOS_MOCK_IME_ENGINE_HANDLER_H_
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ui_base_export.h"
#include "ui/events/event.h"
namespace chromeos {
-class UI_EXPORT MockIMEEngineHandler : public IBusEngineHandlerInterface {
+class UI_BASE_EXPORT MockIMEEngineHandler : public IMEEngineHandlerInterface {
public:
MockIMEEngineHandler();
virtual ~MockIMEEngineHandler();
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.cc b/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
index 4d8d40c0391..14e5bc0b5fd 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
+++ b/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
@@ -4,7 +4,7 @@
#include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
-#include "chromeos/ime/ibus_text.h"
+#include "chromeos/ime/composition_text.h"
namespace chromeos {
@@ -22,13 +22,14 @@ void MockIMEInputContextHandler::CommitText(const std::string& text) {
last_commit_text_ = text;
}
-void MockIMEInputContextHandler::UpdatePreeditText(const IBusText& text,
- uint32 cursor_pos,
- bool visible) {
+void MockIMEInputContextHandler::UpdateCompositionText(
+ const CompositionText& text,
+ uint32 cursor_pos,
+ bool visible) {
++update_preedit_text_call_count_;
- last_update_preedit_arg_.ibus_text.CopyFrom(text);
- last_update_preedit_arg_.cursor_pos = cursor_pos;
- last_update_preedit_arg_.is_visible = visible;
+ last_update_composition_arg_.composition_text.CopyFrom(text);
+ last_update_composition_arg_.cursor_pos = cursor_pos;
+ last_update_composition_arg_.is_visible = visible;
}
void MockIMEInputContextHandler::DeleteSurroundingText(int32 offset,
diff --git a/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.h b/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.h
index a5b42b21497..71fe3956917 100644
--- a/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.h
+++ b/chromium/ui/base/ime/chromeos/mock_ime_input_context_handler.h
@@ -5,17 +5,17 @@
#ifndef UI_BASE_IME_CHROMEOS_MOCK_IME_INPUT_CONTEXT_HANDLER_H_
#define UI_BASE_IME_CHROMEOS_MOCK_IME_INPUT_CONTEXT_HANDLER_H_
-#include "chromeos/ime/ibus_text.h"
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#include "ui/base/ui_export.h"
+#include "chromeos/ime/composition_text.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ui_base_export.h"
namespace chromeos {
-class UI_EXPORT MockIMEInputContextHandler
- : public IBusInputContextHandlerInterface {
+class UI_BASE_EXPORT MockIMEInputContextHandler
+ : public IMEInputContextHandlerInterface {
public:
- struct UpdatePreeditTextArg {
- IBusText ibus_text;
+ struct UpdateCompositionTextArg {
+ CompositionText composition_text;
uint32 cursor_pos;
bool is_visible;
};
@@ -29,7 +29,7 @@ class UI_EXPORT MockIMEInputContextHandler
virtual ~MockIMEInputContextHandler();
virtual void CommitText(const std::string& text) OVERRIDE;
- virtual void UpdatePreeditText(const IBusText& text,
+ virtual void UpdateCompositionText(const CompositionText& text,
uint32 cursor_pos,
bool visible) OVERRIDE;
virtual void DeleteSurroundingText(int32 offset, uint32 length) OVERRIDE;
@@ -48,8 +48,8 @@ class UI_EXPORT MockIMEInputContextHandler
return last_commit_text_;
};
- const UpdatePreeditTextArg& last_update_preedit_arg() const {
- return last_update_preedit_arg_;
+ const UpdateCompositionTextArg& last_update_composition_arg() const {
+ return last_update_composition_arg_;
}
const DeleteSurroundingTextArg& last_delete_surrounding_text_arg() const {
@@ -64,7 +64,7 @@ class UI_EXPORT MockIMEInputContextHandler
int update_preedit_text_call_count_;
int delete_surrounding_text_call_count_;
std::string last_commit_text_;
- UpdatePreeditTextArg last_update_preedit_arg_;
+ UpdateCompositionTextArg last_update_composition_arg_;
DeleteSurroundingTextArg last_delete_surrounding_text_arg_;
};
diff --git a/chromium/ui/base/ime/composition_text.h b/chromium/ui/base/ime/composition_text.h
index 7d728635e3e..e4974bdd7b5 100644
--- a/chromium/ui/base/ime/composition_text.h
+++ b/chromium/ui/base/ime/composition_text.h
@@ -7,13 +7,13 @@
#include "base/strings/string16.h"
#include "ui/base/ime/composition_underline.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/range/range.h"
namespace ui {
// A struct represents the status of an ongoing composition text.
-struct UI_EXPORT CompositionText {
+struct UI_BASE_EXPORT CompositionText {
CompositionText();
~CompositionText();
diff --git a/chromium/ui/base/ime/composition_text_util_pango.cc b/chromium/ui/base/ime/composition_text_util_pango.cc
index 737380b10c6..325cdd61d92 100644
--- a/chromium/ui/base/ime/composition_text_util_pango.cc
+++ b/chromium/ui/base/ime/composition_text_util_pango.cc
@@ -19,7 +19,7 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
int cursor_position,
CompositionText* composition) {
composition->Clear();
- composition->text = UTF8ToUTF16(utf8_text);
+ composition->text = base::UTF8ToUTF16(utf8_text);
if (composition->text.empty())
return;
@@ -75,8 +75,11 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
if (background_attr || underline_attr) {
// Use a black thin underline by default.
- CompositionUnderline underline(
- char16_offsets[start], char16_offsets[end], SK_ColorBLACK, false);
+ CompositionUnderline underline(char16_offsets[start],
+ char16_offsets[end],
+ SK_ColorBLACK,
+ false,
+ SK_ColorTRANSPARENT);
// Always use thick underline for a range with background color, which
// is usually the selection range.
@@ -108,8 +111,8 @@ void ExtractCompositionTextFromGtkPreedit(const gchar* utf8_text,
// Use a black thin underline by default.
if (composition->underlines.empty()) {
- composition->underlines.push_back(
- CompositionUnderline(0, length, SK_ColorBLACK, false));
+ composition->underlines.push_back(CompositionUnderline(
+ 0, length, SK_ColorBLACK, false, SK_ColorTRANSPARENT));
}
}
diff --git a/chromium/ui/base/ime/composition_text_util_pango.h b/chromium/ui/base/ime/composition_text_util_pango.h
index 4f5123f3a80..1116fd9fbd9 100644
--- a/chromium/ui/base/ime/composition_text_util_pango.h
+++ b/chromium/ui/base/ime/composition_text_util_pango.h
@@ -6,7 +6,7 @@
#define UI_BASE_IME_COMPOSITION_TEXT_UTIL_PANGO_H_
#include "ui/base/glib/glib_integers.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
typedef struct _PangoAttrList PangoAttrList;
@@ -16,7 +16,7 @@ struct CompositionText;
// Extracts composition text information (text, underlines, selection range)
// from given Gtk preedit data (utf-8 text, pango attributes, cursor position).
-UI_EXPORT void ExtractCompositionTextFromGtkPreedit(
+UI_BASE_EXPORT void ExtractCompositionTextFromGtkPreedit(
const gchar* utf8_text,
PangoAttrList* attrs,
int cursor_position,
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 957adf1d4a7..a2056cfc0e9 100644
--- a/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
+++ b/chromium/ui/base/ime/composition_text_util_pango_unittest.cc
@@ -28,6 +28,7 @@ struct Underline {
unsigned end_offset;
uint32 color;
bool thick;
+ uint32 background_color;
};
struct TestData {
@@ -37,64 +38,59 @@ struct TestData {
};
const TestData kTestData[] = {
- // Normal case
- { "One Two Three",
- { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
- { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_DOUBLE, 4, 7 },
- { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
- { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
- { 0, 0, 0, 0 } },
- { { 0, 3, SK_ColorBLACK, false },
- { 4, 7, SK_ColorBLACK, true },
- { 8, 13, SK_ColorBLACK, false },
- { 0, 0, 0, false } }
- },
-
- // Offset overflow.
- { "One Two Three",
- { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
- { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
- { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 20 },
- { 0, 0, 0, 0 } },
- { { 0, 3, SK_ColorBLACK, false },
- { 4, 7, SK_ColorBLACK, true },
- { 8, 13, SK_ColorBLACK, false },
- { 0, 0, 0, false} }
- },
-
- // Error underline.
- { "One Two Three",
- { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
- { 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 },
- { 4, 7, SK_ColorRED, false },
- { 8, 13, SK_ColorBLACK, false },
- { 0, 0, 0, false} }
- },
-
- // Default underline.
- { "One Two Three",
- { { 0, 0, 0, 0 } },
- { { 0, 13, SK_ColorBLACK, false },
- { 0, 0, 0, false } }
- },
-
- // 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"
- "\xE4\xB8\x81 456",
- { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
- { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 3, 5 },
- { PANGO_ATTR_BACKGROUND, 0, 5, 7 },
- { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 7, 13 },
- { 0, 0, 0, 0 } },
- { { 0, 3, SK_ColorBLACK, false },
- { 3, 5, SK_ColorBLACK, false },
- { 5, 9, SK_ColorBLACK, true },
- { 9, 15, SK_ColorBLACK, false },
- { 0, 0, 0, false } }
- },
+ // Normal case
+ {"One Two Three",
+ {{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3},
+ {PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_DOUBLE, 4, 7},
+ {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}}},
+
+ // Offset overflow.
+ {"One Two Three",
+ {{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3},
+ {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}}},
+
+ // Error underline.
+ {"One Two Three",
+ {{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3},
+ {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}}},
+
+ // Default underline.
+ {"One Two Three",
+ {{0, 0, 0, 0}},
+ {{0, 13, SK_ColorBLACK, false, SK_ColorTRANSPARENT},
+ {0, 0, 0, false, 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"
+ "\xE4\xB8\x81 456",
+ {{PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3},
+ {PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 3, 5},
+ {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}}},
};
void CompareUnderline(const Underline& a,
@@ -103,6 +99,7 @@ void CompareUnderline(const Underline& a,
EXPECT_EQ(a.end_offset, b.end_offset);
EXPECT_EQ(a.color, b.color);
EXPECT_EQ(a.thick, b.thick);
+ EXPECT_EQ(a.background_color, b.background_color);
}
TEST(CompositionTextUtilPangoTest, ExtractCompositionText) {
diff --git a/chromium/ui/base/ime/composition_underline.h b/chromium/ui/base/ime/composition_underline.h
index c8d09d84163..a8c44b66854 100644
--- a/chromium/ui/base/ime/composition_underline.h
+++ b/chromium/ui/base/ime/composition_underline.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/basictypes.h"
#include "third_party/skia/include/core/SkColor.h"
namespace ui {
@@ -15,34 +16,43 @@ namespace ui {
// third_party/WebKit/public/web/WebCompositionUnderline.h
struct CompositionUnderline {
CompositionUnderline()
- : start_offset(0),
- end_offset(0),
- color(0),
- thick(false) {}
-
- CompositionUnderline(unsigned s, unsigned e, SkColor c, bool t)
- : start_offset(s),
- end_offset(e),
- color(c),
- thick(t) {}
+ : start_offset(0),
+ end_offset(0),
+ color(SK_ColorTRANSPARENT),
+ thick(false),
+ background_color(SK_ColorTRANSPARENT) {}
+
+ // TODO(huangs): remove this constructor.
+ CompositionUnderline(uint32 s, uint32 e, SkColor c, bool t)
+ : start_offset(s),
+ end_offset(e),
+ color(c),
+ thick(t),
+ background_color(SK_ColorTRANSPARENT) {}
+
+ CompositionUnderline(uint32 s, uint32 e, SkColor c, bool t, SkColor bc)
+ : start_offset(s),
+ end_offset(e),
+ color(c),
+ thick(t),
+ background_color(bc) {}
bool operator==(const CompositionUnderline& rhs) const {
return (this->start_offset == rhs.start_offset) &&
- (this->end_offset == rhs.end_offset) &&
- (this->color == rhs.color) &&
- (this->thick == rhs.thick);
+ (this->end_offset == rhs.end_offset) && (this->color == rhs.color) &&
+ (this->thick == rhs.thick) &&
+ (this->background_color == rhs.background_color);
}
bool operator!=(const CompositionUnderline& rhs) const {
return !(*this == rhs);
}
- // Though use of unsigned is discouraged, we use it here to make sure it's
- // identical to blink::WebCompositionUnderline.
- unsigned start_offset;
- unsigned end_offset;
+ uint32 start_offset;
+ uint32 end_offset;
SkColor color;
bool thick;
+ SkColor background_color;
};
typedef std::vector<CompositionUnderline> CompositionUnderlines;
diff --git a/chromium/ui/base/ime/dummy_input_method.cc b/chromium/ui/base/ime/dummy_input_method.cc
index b80f3f4e904..a12bbfc51bf 100644
--- a/chromium/ui/base/ime/dummy_input_method.cc
+++ b/chromium/ui/base/ime/dummy_input_method.cc
@@ -59,10 +59,6 @@ std::string DummyInputMethod::GetInputLocale() {
return std::string();
}
-base::i18n::TextDirection DummyInputMethod::GetInputTextDirection() {
- return base::i18n::UNKNOWN_DIRECTION;
-}
-
bool DummyInputMethod::IsActive() {
return true;
}
@@ -83,6 +79,9 @@ bool DummyInputMethod::IsCandidatePopupOpen() const {
return false;
}
+void DummyInputMethod::ShowImeIfNeeded() {
+}
+
void DummyInputMethod::AddObserver(InputMethodObserver* observer) {
}
diff --git a/chromium/ui/base/ime/dummy_input_method.h b/chromium/ui/base/ime/dummy_input_method.h
index 5ccb06cf55e..39b04195f9d 100644
--- a/chromium/ui/base/ime/dummy_input_method.h
+++ b/chromium/ui/base/ime/dummy_input_method.h
@@ -33,12 +33,13 @@ class DummyInputMethod : public InputMethod {
virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual TextInputType GetTextInputType() const OVERRIDE;
virtual TextInputMode GetTextInputMode() const OVERRIDE;
virtual bool CanComposeInline() const OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
+
virtual void AddObserver(InputMethodObserver* observer) OVERRIDE;
virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE;
diff --git a/chromium/ui/base/ime/dummy_input_method_delegate.cc b/chromium/ui/base/ime/dummy_input_method_delegate.cc
index e7bb7dae2bd..473884a65ae 100644
--- a/chromium/ui/base/ime/dummy_input_method_delegate.cc
+++ b/chromium/ui/base/ime/dummy_input_method_delegate.cc
@@ -11,14 +11,7 @@ DummyInputMethodDelegate::DummyInputMethodDelegate() {}
DummyInputMethodDelegate::~DummyInputMethodDelegate() {}
bool DummyInputMethodDelegate::DispatchKeyEventPostIME(
- const base::NativeEvent& native_key_event) {
- return true;
-}
-
-bool DummyInputMethodDelegate::DispatchFabricatedKeyEventPostIME(
- ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) {
+ const ui::KeyEvent& key_event) {
return true;
}
diff --git a/chromium/ui/base/ime/dummy_input_method_delegate.h b/chromium/ui/base/ime/dummy_input_method_delegate.h
index 360d0b42b38..ce64216c7c3 100644
--- a/chromium/ui/base/ime/dummy_input_method_delegate.h
+++ b/chromium/ui/base/ime/dummy_input_method_delegate.h
@@ -5,26 +5,20 @@
#ifndef UI_BASE_IME_DUMMY_INPUT_METHOD_DELEGATE_H_
#define UI_BASE_IME_DUMMY_INPUT_METHOD_DELEGATE_H_
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/base/ime/input_method_delegate.h"
-#include "ui/base/ui_export.h"
namespace ui {
namespace internal {
-class UI_EXPORT DummyInputMethodDelegate
- : NON_EXPORTED_BASE(public InputMethodDelegate) {
+class UI_BASE_EXPORT DummyInputMethodDelegate : public InputMethodDelegate {
public:
DummyInputMethodDelegate();
virtual ~DummyInputMethodDelegate();
- // InputMethodDelegate overrides:
- virtual bool DispatchKeyEventPostIME(
- const base::NativeEvent& native_key_event) OVERRIDE;
- virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) OVERRIDE;
+ // Overridden from InputMethodDelegate:
+ virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& key_event) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DummyInputMethodDelegate);
diff --git a/chromium/ui/base/ime/dummy_text_input_client.cc b/chromium/ui/base/ime/dummy_text_input_client.cc
index 652e2c52bf7..cea49c676c0 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.cc
+++ b/chromium/ui/base/ime/dummy_text_input_client.cc
@@ -7,14 +7,17 @@
namespace ui {
-DummyTextInputClient::DummyTextInputClient() {
-}
+DummyTextInputClient::DummyTextInputClient()
+ : text_input_type_(TEXT_INPUT_TYPE_NONE) {}
+
+DummyTextInputClient::DummyTextInputClient(TextInputType text_input_type)
+ : text_input_type_(text_input_type) {}
DummyTextInputClient::~DummyTextInputClient() {
}
void DummyTextInputClient::SetCompositionText(
- const ui::CompositionText& composition) {
+ const CompositionText& composition) {
}
void DummyTextInputClient::ConfirmCompositionText() {
@@ -23,21 +26,21 @@ void DummyTextInputClient::ConfirmCompositionText() {
void DummyTextInputClient::ClearCompositionText() {
}
-void DummyTextInputClient::InsertText(const string16& text) {
+void DummyTextInputClient::InsertText(const base::string16& text) {
}
-void DummyTextInputClient::InsertChar(char16 ch, int flags) {
+void DummyTextInputClient::InsertChar(base::char16 ch, int flags) {
}
gfx::NativeWindow DummyTextInputClient::GetAttachedWindow() const {
return NULL;
}
-ui::TextInputType DummyTextInputClient::GetTextInputType() const {
- return TEXT_INPUT_TYPE_NONE;
+TextInputType DummyTextInputClient::GetTextInputType() const {
+ return text_input_type_;
}
-ui::TextInputMode DummyTextInputClient::GetTextInputMode() const {
+TextInputMode DummyTextInputClient::GetTextInputMode() const {
return TEXT_INPUT_MODE_DEFAULT;
}
@@ -80,7 +83,7 @@ bool DummyTextInputClient::DeleteRange(const gfx::Range& range) {
}
bool DummyTextInputClient::GetTextFromRange(const gfx::Range& range,
- string16* text) const {
+ base::string16* text) const {
return false;
}
@@ -108,4 +111,11 @@ void DummyTextInputClient::OnCandidateWindowUpdated() {
void DummyTextInputClient::OnCandidateWindowHidden() {
}
+bool DummyTextInputClient::IsEditingCommandEnabled(int command_id) {
+ return false;
+}
+
+void DummyTextInputClient::ExecuteEditingCommand(int command_id) {
+}
+
} // namespace ui
diff --git a/chromium/ui/base/ime/dummy_text_input_client.h b/chromium/ui/base/ime/dummy_text_input_client.h
index 1242bb990d0..be2295c3bb9 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.h
+++ b/chromium/ui/base/ime/dummy_text_input_client.h
@@ -13,18 +13,18 @@ namespace ui {
class DummyTextInputClient : public TextInputClient {
public:
DummyTextInputClient();
+ explicit DummyTextInputClient(TextInputType text_input_type);
virtual ~DummyTextInputClient();
// Overriden from TextInputClient.
- virtual void SetCompositionText(
- const ui::CompositionText& composition) OVERRIDE;
+ virtual void SetCompositionText(const CompositionText& composition) OVERRIDE;
virtual void ConfirmCompositionText() OVERRIDE;
virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
- virtual ui::TextInputType GetTextInputType() const OVERRIDE;
- virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
+ virtual TextInputType GetTextInputType() const OVERRIDE;
+ virtual TextInputMode GetTextInputMode() const OVERRIDE;
virtual bool CanComposeInline() const OVERRIDE;
virtual gfx::Rect GetCaretBounds() const OVERRIDE;
virtual bool GetCompositionCharacterBounds(uint32 index,
@@ -36,7 +36,7 @@ class DummyTextInputClient : public TextInputClient {
virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
+ base::string16* text) const OVERRIDE;
virtual void OnInputMethodChanged() OVERRIDE;
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) OVERRIDE;
@@ -45,6 +45,12 @@ class DummyTextInputClient : public TextInputClient {
virtual void OnCandidateWindowShown() OVERRIDE;
virtual void OnCandidateWindowUpdated() OVERRIDE;
virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
+
+ TextInputType text_input_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(DummyTextInputClient);
};
} // namespace ui
diff --git a/chromium/ui/base/ime/ime.gypi b/chromium/ui/base/ime/ime.gypi
index 7d52d9d7839..322f0a962be 100644
--- a/chromium/ui/base/ime/ime.gypi
+++ b/chromium/ui/base/ime/ime.gypi
@@ -7,10 +7,14 @@
'<(DEPTH)/ui/events/events.gyp:events',
],
'sources': [
+ 'candidate_window.cc',
+ 'candidate_window.h',
'chromeos/character_composer.cc',
'chromeos/character_composer.h',
- 'chromeos/ibus_bridge.cc',
- 'chromeos/ibus_bridge.h',
+ 'chromeos/ime_bridge.cc',
+ 'chromeos/ime_bridge.h',
+ 'chromeos/ime_keymap.cc',
+ 'chromeos/ime_keymap.h',
'chromeos/mock_ime_candidate_window_handler.cc',
'chromeos/mock_ime_candidate_window_handler.h',
'chromeos/mock_ime_engine_handler.cc',
@@ -24,25 +28,25 @@
'composition_underline.h',
'dummy_input_method_delegate.cc',
'dummy_input_method_delegate.h',
+ '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',
+ 'input_method_chromeos.h',
'input_method_delegate.h',
'input_method_factory.cc',
'input_method_factory.h',
- 'input_method_ibus.cc',
- 'input_method_ibus.h',
- 'input_method_imm32.cc',
- 'input_method_imm32.h',
'input_method_initializer.cc',
'input_method_initializer.h',
- 'input_method_auralinux.cc',
- 'input_method_auralinux.h',
+ 'input_method_mac.h',
+ 'input_method_mac.mm',
'input_method_minimal.cc',
'input_method_minimal.h',
'input_method_observer.h',
- 'input_method_tsf.cc',
- 'input_method_tsf.h',
'input_method_win.cc',
'input_method_win.h',
'linux/fake_input_method_context.cc',
@@ -59,17 +63,13 @@
'remote_input_method_win.h',
'text_input_client.cc',
'text_input_client.h',
+ 'text_input_focus_manager.cc',
+ 'text_input_focus_manager.h',
'text_input_type.h',
'win/imm32_manager.cc',
'win/imm32_manager.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',
],
'conditions': [
['toolkit_views==0 and use_aura==0', {
@@ -82,8 +82,8 @@
}],
['chromeos==0 or use_x11==0', {
'sources!': [
- 'input_method_ibus.cc',
- 'input_method_ibus.h',
+ 'input_method_chromeos.cc',
+ 'input_method_chromeos.h',
],
}],
['chromeos==1', {
@@ -95,18 +95,12 @@
'sources!': [
'input_method_imm32.cc',
'input_method_imm32.h',
- 'input_method_tsf.cc',
- 'input_method_tsf.h',
],
}],
- ['use_aura==0 or desktop_linux==0', {
+ ['use_aura==0 or (desktop_linux==0 and use_ozone==0)', {
'sources!': [
'input_method_auralinux.cc',
'input_method_auralinux.h',
- ],
- }],
- ['use_aura==0 or desktop_linux==0', {
- 'sources!': [
'linux/fake_input_method_context.cc',
'linux/fake_input_method_context.h',
'linux/fake_input_method_context_factory.cc',
@@ -120,7 +114,14 @@
'sources!': [
'composition_text_util_pango.cc',
'composition_text_util_pango.h',
+ 'chromeos/character_composer.cc',
+ 'chromeos/character_composer.h',
],
}],
+ ['OS=="android"', {
+ 'dependencies!' : [
+ '<(DEPTH)/ui/events/events.gyp:events',
+ ],
+ }]
],
}
diff --git a/chromium/ui/base/ime/ime_test_support.gypi b/chromium/ui/base/ime/ime_test_support.gypi
index 02fa6eb1191..f82b3b02b2f 100644
--- a/chromium/ui/base/ime/ime_test_support.gypi
+++ b/chromium/ui/base/ime/ime_test_support.gypi
@@ -8,15 +8,5 @@
'dummy_input_method.h',
'dummy_text_input_client.cc',
'dummy_text_input_client.h',
- 'win/mock_tsf_bridge.cc',
- 'win/mock_tsf_bridge.h',
- ],
- 'conditions': [
- ['OS!="win"', {
- 'sources!': [
- 'win/mock_tsf_bridge.cc',
- 'win/mock_tsf_bridge.h',
- ],
- }],
],
}
diff --git a/chromium/ui/base/ime/ime_unittests.gypi b/chromium/ui/base/ime/ime_unittests.gypi
index 779764800d7..110b200b693 100644
--- a/chromium/ui/base/ime/ime_unittests.gypi
+++ b/chromium/ui/base/ime/ime_unittests.gypi
@@ -4,20 +4,20 @@
{
'sources': [
+ 'candidate_window_unittest.cc',
'chromeos/character_composer_unittest.cc',
'composition_text_util_pango_unittest.cc',
'input_method_base_unittest.cc',
- 'input_method_ibus_unittest.cc',
+ 'input_method_chromeos_unittest.cc',
'remote_input_method_win_unittest.cc',
'win/imm32_manager_unittest.cc',
'win/tsf_input_scope_unittest.cc',
- 'win/tsf_text_store_unittest.cc',
],
'conditions': [
['chromeos==0 or use_x11==0', {
'sources!': [
'chromeos/character_composer_unittest.cc',
- 'input_method_ibus_unittest.cc',
+ 'input_method_chromeos_unittest.cc',
],
}],
['use_x11==0', {
diff --git a/chromium/ui/base/ime/infolist_entry.cc b/chromium/ui/base/ime/infolist_entry.cc
new file mode 100644
index 00000000000..7423f73abb7
--- /dev/null
+++ b/chromium/ui/base/ime/infolist_entry.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/infolist_entry.h"
+
+namespace ui {
+
+InfolistEntry::InfolistEntry(const base::string16& title,
+ const base::string16& body)
+ : title(title), body(body), highlighted(false) {}
+
+bool InfolistEntry::operator==(const InfolistEntry& other) const {
+ return title == other.title && body == other.body &&
+ highlighted == other.highlighted;
+}
+
+bool InfolistEntry::operator!=(const InfolistEntry& other) const {
+ return !(*this == other);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/infolist_entry.h b/chromium/ui/base/ime/infolist_entry.h
new file mode 100644
index 00000000000..3cb76721cb3
--- /dev/null
+++ b/chromium/ui/base/ime/infolist_entry.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_INFOLIST_ENTRY_H_
+#define UI_BASE_IME_INFOLIST_ENTRY_H_
+
+#include "base/strings/string16.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// The data model of infolist window.
+struct UI_BASE_EXPORT InfolistEntry {
+ base::string16 title;
+ base::string16 body;
+ bool highlighted;
+
+ InfolistEntry(const base::string16& title, const base::string16& body);
+ bool operator==(const InfolistEntry& entry) const;
+ bool operator!=(const InfolistEntry& entry) const;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_INFOLIST_ENTRY_H_
diff --git a/chromium/ui/base/ime/input_method.h b/chromium/ui/base/ime/input_method.h
index 33c7beaed5d..462e0b0a64e 100644
--- a/chromium/ui/base/ime/input_method.h
+++ b/chromium/ui/base/ime/input_method.h
@@ -9,7 +9,6 @@
#include "base/basictypes.h"
#include "base/event_types.h"
-#include "base/i18n/rtl.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
@@ -43,11 +42,11 @@ class TextInputClient;
// - Keeps track of the focused TextInputClient to see which client can call
// APIs, OnTextInputTypeChanged, OnCaretBoundsChanged, and CancelComposition,
// that change the state of the input method.
-// In Aura environment, aura::RootWindowHost creates an instance of
+// In Aura environment, aura::WindowTreeHost creates an instance of
// ui::InputMethod and owns it.
class InputMethod {
public:
- // TODO(yukawa): Move these typedef into ime_constants.h or somewhere.
+
#if defined(OS_WIN)
typedef LRESULT NativeEventResult;
#else
@@ -126,10 +125,6 @@ class InputMethod {
// tag, or an empty string if the input method cannot provide it.
virtual std::string GetInputLocale() = 0;
- // Returns the text direction of current keyboard layout or input method, or
- // base::i18n::UNKNOWN_DIRECTION if the input method cannot provide it.
- virtual base::i18n::TextDirection GetInputTextDirection() = 0;
-
// Checks if the input method is active, i.e. if it's ready for processing
// keyboard event and generate composition or text result.
// If the input method is inactive, then it's not necessary to inform it the
@@ -159,6 +154,9 @@ class InputMethod {
// of IME popups is not supported.
virtual bool IsCandidatePopupOpen() const = 0;
+ // Displays an on screen keyboard if enabled.
+ virtual void ShowImeIfNeeded() = 0;
+
// Management of the observer list.
virtual void AddObserver(InputMethodObserver* observer) = 0;
virtual void RemoveObserver(InputMethodObserver* observer) = 0;
diff --git a/chromium/ui/base/ime/input_method_auralinux.cc b/chromium/ui/base/ime/input_method_auralinux.cc
index 4b996fb089f..a1c1b74bc1f 100644
--- a/chromium/ui/base/ime/input_method_auralinux.cc
+++ b/chromium/ui/base/ime/input_method_auralinux.cc
@@ -12,46 +12,20 @@
namespace ui {
InputMethodAuraLinux::InputMethodAuraLinux(
- internal::InputMethodDelegate* delegate) {
+ internal::InputMethodDelegate* delegate)
+ : allowed_to_fire_vkey_process_key_(false), vkey_processkey_flags_(0) {
SetDelegate(delegate);
}
InputMethodAuraLinux::~InputMethodAuraLinux() {}
-// static
-void InputMethodAuraLinux::Initialize() {
-#if (USE_X11)
- // Force a IBus IM context to run in synchronous mode.
- //
- // Background: IBus IM context runs by default in asynchronous mode. In
- // this mode, gtk_im_context_filter_keypress() consumes all the key events
- // and returns true while asynchronously sending the event to an underlying
- // IME implementation. When the event has not actually been consumed by
- // the underlying IME implementation, the context pushes the event back to
- // the GDK event queue marking the event as already handled by the IBus IM
- // context.
- //
- // The problem here is that those pushed-back GDK events are never handled
- // when base::MessagePumpX11 is used, which only handles X events. So, we
- // make a IBus IM context run in synchronous mode by setting an environment
- // variable. This is only the interface to change the mode.
- //
- // Another possible solution is to use GDK event loop instead of X event
- // loop.
- //
- // Since there is no reentrant version of setenv(3C), it's a caller's duty
- // to avoid race conditions. This function should be called in the main
- // thread on a very early stage, and supposed to be called from
- // ui::InitializeInputMethod().
- scoped_ptr<base::Environment> env(base::Environment::Create());
- env->SetVar("IBUS_ENABLE_SYNC_MODE", "1");
-#endif
-}
-
// Overriden from InputMethod.
void InputMethodAuraLinux::Init(bool focused) {
- CHECK(LinuxInputMethodContextFactory::instance());
+ CHECK(LinuxInputMethodContextFactory::instance())
+ << "This failure was likely caused because "
+ << "ui::InitializeInputMethod(ForTesting) was not called "
+ << "before instantiating this class.";
input_method_context_ =
LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
this);
@@ -81,17 +55,15 @@ bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
if (!GetTextInputClient())
return DispatchKeyEventPostIME(event);
- // Let an IME handle the key event first.
- if (input_method_context_->DispatchKeyEvent(event)) {
- if (event.type() == ET_KEY_PRESSED) {
- const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
- VKEY_PROCESSKEY,
- event.flags(),
- false); // is_char
- DispatchKeyEventPostIME(fabricated_event);
- }
+ // Let an IME handle the key event first, and allow to fire a VKEY_PROCESSKEY
+ // event for keydown events. Note that DOM Level 3 Events Sepc requires that
+ // only keydown events fire keyCode=229 events and not for keyup events.
+ if (event.type() == ET_KEY_PRESSED &&
+ (event.flags() & ui::EF_IME_FABRICATED_KEY) == 0)
+ AllowToFireProcessKey(event);
+ if (input_method_context_->DispatchKeyEvent(event))
return true;
- }
+ StopFiringProcessKey();
// Otherwise, insert the character.
const bool handled = DispatchKeyEventPostIME(event);
@@ -135,10 +107,6 @@ std::string InputMethodAuraLinux::GetInputLocale() {
return "";
}
-base::i18n::TextDirection InputMethodAuraLinux::GetInputTextDirection() {
- return input_method_context_->GetInputTextDirection();
-}
-
bool InputMethodAuraLinux::IsActive() {
// InputMethodAuraLinux is always ready and up.
return true;
@@ -152,25 +120,29 @@ bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
// Overriden from ui::LinuxInputMethodContextDelegate
void InputMethodAuraLinux::OnCommit(const base::string16& text) {
- TextInputClient* text_input_client = GetTextInputClient();
- if (text_input_client)
- text_input_client->InsertText(text);
+ MaybeFireProcessKey();
+ if (!IsTextInputTypeNone())
+ GetTextInputClient()->InsertText(text);
}
void InputMethodAuraLinux::OnPreeditChanged(
const CompositionText& composition_text) {
+ MaybeFireProcessKey();
TextInputClient* text_input_client = GetTextInputClient();
if (text_input_client)
text_input_client->SetCompositionText(composition_text);
}
void InputMethodAuraLinux::OnPreeditEnd() {
+ MaybeFireProcessKey();
TextInputClient* text_input_client = GetTextInputClient();
if (text_input_client && text_input_client->HasCompositionText())
text_input_client->ClearCompositionText();
}
-void InputMethodAuraLinux::OnPreeditStart() {}
+void InputMethodAuraLinux::OnPreeditStart() {
+ MaybeFireProcessKey();
+}
// Overridden from InputMethodBase.
@@ -184,4 +156,28 @@ void InputMethodAuraLinux::OnDidChangeFocusedClient(
InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
}
+// Helper functions to support VKEY_PROCESSKEY.
+
+void InputMethodAuraLinux::AllowToFireProcessKey(const ui::KeyEvent& event) {
+ allowed_to_fire_vkey_process_key_ = true;
+ vkey_processkey_flags_ = event.flags();
+}
+
+void InputMethodAuraLinux::MaybeFireProcessKey() {
+ if (!allowed_to_fire_vkey_process_key_)
+ return;
+
+ const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
+ VKEY_PROCESSKEY,
+ vkey_processkey_flags_,
+ false); // is_char
+ DispatchKeyEventPostIME(fabricated_event);
+ StopFiringProcessKey();
+}
+
+void InputMethodAuraLinux::StopFiringProcessKey() {
+ allowed_to_fire_vkey_process_key_ = false;
+ vkey_processkey_flags_ = 0;
+}
+
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_auralinux.h b/chromium/ui/base/ime/input_method_auralinux.h
index 87222a7bd05..de5c347be21 100644
--- a/chromium/ui/base/ime/input_method_auralinux.h
+++ b/chromium/ui/base/ime/input_method_auralinux.h
@@ -20,11 +20,6 @@ class InputMethodAuraLinux : public InputMethodBase,
explicit InputMethodAuraLinux(internal::InputMethodDelegate* delegate);
virtual ~InputMethodAuraLinux();
- // Initializes input methods. This function must be called once prior to
- // any use of this instance. This function is supposed to be called from
- // ui::InitializeInputMethod().
- static void Initialize();
-
// Overriden from InputMethod.
virtual void Init(bool focused) OVERRIDE;
virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
@@ -35,7 +30,6 @@ class InputMethodAuraLinux : public InputMethodBase,
virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
@@ -51,8 +45,36 @@ class InputMethodAuraLinux : public InputMethodBase,
virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
TextInputClient* focused) OVERRIDE;
+ private:
+ // Allows to fire a VKEY_PROCESSKEY key event.
+ void AllowToFireProcessKey(const ui::KeyEvent& event);
+ // Fires a VKEY_PROCESSKEY key event if allowed.
+ void MaybeFireProcessKey();
+ // Stops firing VKEY_PROCESSKEY key events.
+ void StopFiringProcessKey();
+
scoped_ptr<LinuxInputMethodContext> input_method_context_;
+ // IBus in async mode eagerly consumes all the key events first regardless of
+ // whether the underlying IME consumes the key event or not, and makes
+ // gtk_im_context_filter_keypress() always return true, and later pushes
+ // the key event back to the GDK event queue when it turns out that the
+ // underlying IME doesn't consume the key event.
+ //
+ // Thus we have to defer a decision whether or not to dispatch a
+ // VKEY_PROCESSKEY key event. Unlike other InputMethod's subclasses,
+ // DispatchKeyEvent() in this class does not directly dispatch a
+ // VKEY_PROCESSKEY event, OnCommit or OnPreedit{Start,Changed,End} dispatch
+ // a VKEY_PROCESSKEY event instead.
+ //
+ // Because of this hack, there could be chances that we accidentally dispatch
+ // VKEY_PROCESSKEY events and other key events in out of order.
+ //
+ // |allowed_to_fire_vkey_process_key_| is used not to dispatch a
+ // VKEY_PROCESSKEY event twice for a single key event.
+ bool allowed_to_fire_vkey_process_key_;
+ int vkey_processkey_flags_;
+
DISALLOW_COPY_AND_ASSIGN(InputMethodAuraLinux);
};
diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc
index d88fccfc6ff..ed347670ef3 100644
--- a/chromium/ui/base/ime/input_method_base.cc
+++ b/chromium/ui/base/ime/input_method_base.cc
@@ -10,6 +10,8 @@
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
namespace ui {
@@ -56,6 +58,9 @@ void InputMethodBase::DetachTextInputClient(TextInputClient* client) {
}
TextInputClient* InputMethodBase::GetTextInputClient() const {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return TextInputFocusManager::GetInstance()->GetFocusedTextInputClient();
+
return system_toplevel_window_focused_ ? text_input_client_ : NULL;
}
@@ -80,6 +85,10 @@ bool InputMethodBase::CanComposeInline() const {
return client ? client->CanComposeInline() : true;
}
+void InputMethodBase::ShowImeIfNeeded() {
+ FOR_EACH_OBSERVER(InputMethodObserver, observer_list_, OnShowImeIfNeeded());
+}
+
void InputMethodBase::AddObserver(InputMethodObserver* observer) {
observer_list_.AddObserver(observer);
}
@@ -107,11 +116,7 @@ bool InputMethodBase::DispatchKeyEventPostIME(
if (!delegate_)
return false;
- if (!event.HasNativeEvent())
- return delegate_->DispatchFabricatedKeyEventPostIME(
- event.type(), event.key_code(), event.flags());
-
- return delegate_->DispatchKeyEventPostIME(event.native_event());
+ return delegate_->DispatchKeyEventPostIME(event);
}
void InputMethodBase::NotifyTextInputStateChanged(
@@ -123,6 +128,9 @@ void InputMethodBase::NotifyTextInputStateChanged(
void InputMethodBase::SetFocusedTextInputClientInternal(
TextInputClient* client) {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return;
+
TextInputClient* old = text_input_client_;
if (old == client)
return;
@@ -152,18 +160,18 @@ void InputMethodBase::OnCandidateWindowHidden() {
}
void InputMethodBase::CandidateWindowShownCallback() {
- if (text_input_client_)
- text_input_client_->OnCandidateWindowShown();
+ if (TextInputClient* text_input_client = GetTextInputClient())
+ text_input_client->OnCandidateWindowShown();
}
void InputMethodBase::CandidateWindowUpdatedCallback() {
- if (text_input_client_)
- text_input_client_->OnCandidateWindowUpdated();
+ if (TextInputClient* text_input_client = GetTextInputClient())
+ text_input_client->OnCandidateWindowUpdated();
}
void InputMethodBase::CandidateWindowHiddenCallback() {
- if (text_input_client_)
- text_input_client_->OnCandidateWindowHidden();
+ if (TextInputClient* text_input_client = GetTextInputClient())
+ text_input_client->OnCandidateWindowHidden();
}
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_base.h b/chromium/ui/base/ime/input_method_base.h
index 10ac88dcef4..ce3801537d2 100644
--- a/chromium/ui/base/ime/input_method_base.h
+++ b/chromium/ui/base/ime/input_method_base.h
@@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "ui/base/ime/input_method.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace gfx {
class Rect;
@@ -24,7 +24,7 @@ class TextInputClient;
// A helper class providing functionalities shared among ui::InputMethod
// implementations.
-class UI_EXPORT InputMethodBase
+class UI_BASE_EXPORT InputMethodBase
: NON_EXPORTED_BASE(public InputMethod),
public base::SupportsWeakPtr<InputMethodBase> {
public:
@@ -50,6 +50,7 @@ class UI_EXPORT InputMethodBase
virtual TextInputType GetTextInputType() const OVERRIDE;
virtual TextInputMode GetTextInputMode() const OVERRIDE;
virtual bool CanComposeInline() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
virtual void AddObserver(InputMethodObserver* observer) OVERRIDE;
virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE;
diff --git a/chromium/ui/base/ime/input_method_base_unittest.cc b/chromium/ui/base/ime/input_method_base_unittest.cc
index ac80b1406f1..830bba0cc42 100644
--- a/chromium/ui/base/ime/input_method_base_unittest.cc
+++ b/chromium/ui/base/ime/input_method_base_unittest.cc
@@ -12,6 +12,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/dummy_text_input_client.h"
#include "ui/base/ime/input_method_observer.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
namespace ui {
@@ -52,9 +54,15 @@ class ClientChangeVerifier {
// Verifies the result satisfies the expectation or not.
void Verify() {
- EXPECT_EQ(call_expected_, on_will_change_focused_client_called_);
- EXPECT_EQ(call_expected_, on_did_change_focused_client_called_);
- EXPECT_EQ(call_expected_, on_text_input_state_changed_);
+ if (switches::IsTextInputFocusManagerEnabled()) {
+ EXPECT_FALSE(on_will_change_focused_client_called_);
+ EXPECT_FALSE(on_did_change_focused_client_called_);
+ EXPECT_FALSE(on_text_input_state_changed_);
+ } else {
+ EXPECT_EQ(call_expected_, on_will_change_focused_client_called_);
+ EXPECT_EQ(call_expected_, on_did_change_focused_client_called_);
+ EXPECT_EQ(call_expected_, on_text_input_state_changed_);
+ }
}
void OnWillChangeFocusedClient(TextInputClient* focused_before,
@@ -161,9 +169,6 @@ class MockInputMethodBase : public InputMethodBase {
virtual std::string GetInputLocale() OVERRIDE{
return "";
}
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
- return base::i18n::UNKNOWN_DIRECTION;
- }
virtual bool IsActive() OVERRIDE {
return false;
}
@@ -208,6 +213,8 @@ class MockInputMethodObserver : public InputMethodObserver {
virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE {
verifier_->OnTextInputStateChanged(client);
}
+ virtual void OnShowImeIfNeeded() OVERRIDE {
+ }
virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
}
@@ -246,6 +253,16 @@ class MockTextInputClient : public DummyTextInputClient {
typedef ScopedObserver<InputMethod, InputMethodObserver>
InputMethodScopedObserver;
+void SetFocusedTextInputClient(InputMethod* input_method,
+ TextInputClient* text_input_client) {
+ if (switches::IsTextInputFocusManagerEnabled()) {
+ TextInputFocusManager::GetInstance()->FocusTextInputClient(
+ text_input_client);
+ } else {
+ input_method->SetFocusedTextInputClient(text_input_client);
+ }
+}
+
TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
DummyTextInputClient text_input_client_1st;
DummyTextInputClient text_input_client_2nd;
@@ -264,7 +281,7 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
ASSERT_EQ(NULL, input_method.GetTextInputClient());
verifier.ExpectClientChange(NULL, &text_input_client_1st);
- input_method.SetFocusedTextInputClient(&text_input_client_1st);
+ SetFocusedTextInputClient(&input_method, &text_input_client_1st);
EXPECT_EQ(&text_input_client_1st, input_method.GetTextInputClient());
verifier.Verify();
}
@@ -272,7 +289,7 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
{
SCOPED_TRACE("Redundant focus events must be ignored");
verifier.ExpectClientDoesNotChange();
- input_method.SetFocusedTextInputClient(&text_input_client_1st);
+ SetFocusedTextInputClient(&input_method, &text_input_client_1st);
verifier.Verify();
}
@@ -282,7 +299,7 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
ASSERT_EQ(&text_input_client_1st, input_method.GetTextInputClient());
verifier.ExpectClientChange(&text_input_client_1st,
&text_input_client_2nd);
- input_method.SetFocusedTextInputClient(&text_input_client_2nd);
+ SetFocusedTextInputClient(&input_method, &text_input_client_2nd);
EXPECT_EQ(&text_input_client_2nd, input_method.GetTextInputClient());
verifier.Verify();
}
@@ -292,7 +309,7 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
ASSERT_EQ(&text_input_client_2nd, input_method.GetTextInputClient());
verifier.ExpectClientChange(&text_input_client_2nd, NULL);
- input_method.SetFocusedTextInputClient(NULL);
+ SetFocusedTextInputClient(&input_method, NULL);
EXPECT_EQ(NULL, input_method.GetTextInputClient());
verifier.Verify();
}
@@ -300,12 +317,16 @@ TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
{
SCOPED_TRACE("Redundant focus events must be ignored");
verifier.ExpectClientDoesNotChange();
- input_method.SetFocusedTextInputClient(NULL);
+ SetFocusedTextInputClient(&input_method, NULL);
verifier.Verify();
}
}
TEST_F(InputMethodBaseTest, DetachTextInputClient) {
+ // DetachTextInputClient is not supported when IsTextInputFocusManagerEnabled.
+ if (switches::IsTextInputFocusManagerEnabled())
+ return;
+
DummyTextInputClient text_input_client;
DummyTextInputClient text_input_client_the_other;
@@ -357,7 +378,7 @@ TEST_F(InputMethodBaseTest, CandidateWindowEvents) {
input_method_base.OnFocus();
verifier.ExpectClientChange(NULL, &text_input_client);
- input_method_base.SetFocusedTextInputClient(&text_input_client);
+ SetFocusedTextInputClient(&input_method_base, &text_input_client);
EXPECT_EQ(0, text_input_client.shown_event_count());
EXPECT_EQ(0, text_input_client.updated_event_count());
diff --git a/chromium/ui/base/ime/input_method_chromeos.cc b/chromium/ui/base/ime/input_method_chromeos.cc
new file mode 100644
index 00000000000..a37cb72e50b
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_chromeos.cc
@@ -0,0 +1,661 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/input_method_chromeos.h"
+
+#include <algorithm>
+#include <cstring>
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/i18n/char_iterator.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "chromeos/ime/composition_text.h"
+#include "chromeos/ime/ime_keyboard.h"
+#include "chromeos/ime/input_method_manager.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event.h"
+#include "ui/gfx/rect.h"
+
+namespace {
+chromeos::IMEEngineHandlerInterface* GetEngine() {
+ return chromeos::IMEBridge::Get()->GetCurrentEngineHandler();
+}
+} // namespace
+
+namespace ui {
+
+// InputMethodChromeOS implementation -----------------------------------------
+InputMethodChromeOS::InputMethodChromeOS(
+ internal::InputMethodDelegate* delegate)
+ : composing_text_(false),
+ composition_changed_(false),
+ current_keyevent_id_(0),
+ weak_ptr_factory_(this) {
+ SetDelegate(delegate);
+ chromeos::IMEBridge::Get()->SetInputContextHandler(this);
+
+ UpdateContextFocusState();
+}
+
+InputMethodChromeOS::~InputMethodChromeOS() {
+ AbandonAllPendingKeyEvents();
+ ConfirmCompositionText();
+ // We are dead, so we need to ask the client to stop relying on us.
+ OnInputMethodChanged();
+
+ chromeos::IMEBridge::Get()->SetInputContextHandler(NULL);
+}
+
+void InputMethodChromeOS::OnFocus() {
+ InputMethodBase::OnFocus();
+ OnTextInputTypeChanged(GetTextInputClient());
+}
+
+void InputMethodChromeOS::OnBlur() {
+ ConfirmCompositionText();
+ InputMethodBase::OnBlur();
+ OnTextInputTypeChanged(GetTextInputClient());
+}
+
+bool InputMethodChromeOS::OnUntranslatedIMEMessage(
+ const base::NativeEvent& event,
+ NativeEventResult* result) {
+ return false;
+}
+
+void InputMethodChromeOS::ProcessKeyEventDone(uint32 id,
+ ui::KeyEvent* event,
+ bool is_handled) {
+ if (pending_key_events_.find(id) == pending_key_events_.end())
+ return; // Abandoned key event.
+
+ DCHECK(event);
+ if (event->type() == ET_KEY_PRESSED) {
+ if (is_handled) {
+ // IME event has a priority to be handled, so that character composer
+ // should be reset.
+ character_composer_.Reset();
+ } else {
+ // If IME does not handle key event, passes keyevent to character composer
+ // to be able to compose complex characters.
+ is_handled = ExecuteCharacterComposer(*event);
+ }
+ }
+
+ if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED)
+ ProcessKeyEventPostIME(*event, is_handled);
+
+ // ProcessKeyEventPostIME may change the |pending_key_events_|.
+ pending_key_events_.erase(id);
+}
+
+bool InputMethodChromeOS::DispatchKeyEvent(const ui::KeyEvent& event) {
+ DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
+ DCHECK(system_toplevel_window_focused());
+
+ // For linux_chromeos, the ime keyboard cannot track the caps lock state by
+ // itself, so need to call SetCapsLockEnabled() method to reflect the caps
+ // lock state by the key event.
+ if (!base::SysInfo::IsRunningOnChromeOS()) {
+ chromeos::input_method::InputMethodManager* manager =
+ chromeos::input_method::InputMethodManager::Get();
+ if (manager) {
+ chromeos::input_method::ImeKeyboard* keyboard = manager->GetImeKeyboard();
+ if (keyboard && event.type() == ui::ET_KEY_PRESSED) {
+ bool caps = (event.key_code() == ui::VKEY_CAPITAL)
+ ? !keyboard->CapsLockIsEnabled()
+ : (event.flags() & EF_CAPS_LOCK_DOWN);
+ keyboard->SetCapsLockEnabled(caps);
+ }
+ }
+ }
+
+ // If |context_| is not usable, then we can only dispatch the key event as is.
+ // We only dispatch the key event to input method when the |context_| is an
+ // normal input field (not a password field).
+ // Note: We need to send the key event to ibus even if the |context_| is not
+ // enabled, so that ibus can have a chance to enable the |context_|.
+ if (!IsInputFieldFocused() || !GetEngine()) {
+ if (event.type() == ET_KEY_PRESSED) {
+ if (ExecuteCharacterComposer(event)) {
+ // Treating as PostIME event if character composer handles key event and
+ // generates some IME event,
+ ProcessKeyEventPostIME(event, true);
+ return true;
+ }
+ ProcessUnfilteredKeyPressEvent(event);
+ } else {
+ DispatchKeyEventPostIME(event);
+ }
+ return true;
+ }
+
+ pending_key_events_.insert(current_keyevent_id_);
+
+ ui::KeyEvent* copied_event = new ui::KeyEvent(event);
+ GetEngine()->ProcessKeyEvent(
+ event,
+ base::Bind(&InputMethodChromeOS::ProcessKeyEventDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ current_keyevent_id_,
+ // Pass the ownership of |copied_event|.
+ base::Owned(copied_event)));
+
+ ++current_keyevent_id_;
+ return true;
+}
+
+void InputMethodChromeOS::OnTextInputTypeChanged(
+ const TextInputClient* client) {
+ if (!IsTextInputClientFocused(client))
+ return;
+
+ UpdateContextFocusState();
+
+ chromeos::IMEEngineHandlerInterface* engine = GetEngine();
+ if (engine) {
+ // When focused input client is not changed, a text input type change should
+ // cause blur/focus events to engine.
+ // The focus in to or out from password field should also notify engine.
+ engine->FocusOut();
+ chromeos::IMEEngineHandlerInterface::InputContext context(
+ GetTextInputType(), GetTextInputMode());
+ engine->FocusIn(context);
+ }
+
+ InputMethodBase::OnTextInputTypeChanged(client);
+}
+
+void InputMethodChromeOS::OnCaretBoundsChanged(const TextInputClient* client) {
+ if (!IsInputFieldFocused() || !IsTextInputClientFocused(client))
+ return;
+
+ // The current text input type should not be NONE if |context_| is focused.
+ DCHECK(!IsTextInputTypeNone());
+ const gfx::Rect rect = GetTextInputClient()->GetCaretBounds();
+
+ gfx::Rect composition_head;
+ if (!GetTextInputClient()->GetCompositionCharacterBounds(0,
+ &composition_head)) {
+ composition_head = rect;
+ }
+
+ chromeos::IMECandidateWindowHandlerInterface* candidate_window =
+ chromeos::IMEBridge::Get()->GetCandidateWindowHandler();
+ if (!candidate_window)
+ return;
+ candidate_window->SetCursorBounds(rect, composition_head);
+
+ gfx::Range text_range;
+ gfx::Range selection_range;
+ base::string16 surrounding_text;
+ if (!GetTextInputClient()->GetTextRange(&text_range) ||
+ !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text) ||
+ !GetTextInputClient()->GetSelectionRange(&selection_range)) {
+ previous_surrounding_text_.clear();
+ previous_selection_range_ = gfx::Range::InvalidRange();
+ return;
+ }
+
+ if (previous_selection_range_ == selection_range &&
+ previous_surrounding_text_ == surrounding_text)
+ return;
+
+ previous_selection_range_ = selection_range;
+ previous_surrounding_text_ = surrounding_text;
+
+ if (!selection_range.IsValid()) {
+ // TODO(nona): Ideally selection_range should not be invalid.
+ // TODO(nona): If javascript changes the focus on page loading, even (0,0)
+ // can not be obtained. Need investigation.
+ return;
+ }
+
+ // Here SetSurroundingText accepts relative position of |surrounding_text|, so
+ // we have to convert |selection_range| from node coordinates to
+ // |surrounding_text| coordinates.
+ if (!GetEngine())
+ return;
+ GetEngine()->SetSurroundingText(base::UTF16ToUTF8(surrounding_text),
+ selection_range.start() - text_range.start(),
+ selection_range.end() - text_range.start());
+}
+
+void InputMethodChromeOS::CancelComposition(const TextInputClient* client) {
+ if (IsInputFieldFocused() && IsTextInputClientFocused(client))
+ ResetContext();
+}
+
+void InputMethodChromeOS::OnInputLocaleChanged() {
+ // Not supported.
+}
+
+std::string InputMethodChromeOS::GetInputLocale() {
+ // Not supported.
+ return "";
+}
+
+bool InputMethodChromeOS::IsActive() {
+ return true;
+}
+
+bool InputMethodChromeOS::IsCandidatePopupOpen() const {
+ // TODO(yukishiino): Implement this method.
+ return false;
+}
+
+void InputMethodChromeOS::OnWillChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* focused) {
+ ConfirmCompositionText();
+
+ if (GetEngine())
+ GetEngine()->FocusOut();
+}
+
+void InputMethodChromeOS::OnDidChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* 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.
+ UpdateContextFocusState();
+
+ if (GetEngine()) {
+ chromeos::IMEEngineHandlerInterface::InputContext context(
+ GetTextInputType(), GetTextInputMode());
+ GetEngine()->FocusIn(context);
+ }
+}
+
+void InputMethodChromeOS::ConfirmCompositionText() {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->HasCompositionText())
+ client->ConfirmCompositionText();
+
+ ResetContext();
+}
+
+void InputMethodChromeOS::ResetContext() {
+ if (!IsInputFieldFocused() || !GetTextInputClient())
+ return;
+
+ DCHECK(system_toplevel_window_focused());
+
+ composition_.Clear();
+ result_text_.clear();
+ composing_text_ = false;
+ composition_changed_ = false;
+
+ // We need to abandon all pending key events, but as above comment says, there
+ // is no reliable way to abandon all results generated by these abandoned key
+ // events.
+ AbandonAllPendingKeyEvents();
+
+ // This function runs asynchronously.
+ // Note: some input method engines may not support reset method, such as
+ // ibus-anthy. But as we control all input method engines by ourselves, we can
+ // make sure that all of the engines we are using support it correctly.
+ if (GetEngine())
+ GetEngine()->Reset();
+
+ character_composer_.Reset();
+}
+
+void InputMethodChromeOS::UpdateContextFocusState() {
+ ResetContext();
+ OnInputMethodChanged();
+
+ // Propagate the focus event to the candidate window handler which also
+ // manages the input method mode indicator.
+ chromeos::IMECandidateWindowHandlerInterface* candidate_window =
+ chromeos::IMEBridge::Get()->GetCandidateWindowHandler();
+ if (candidate_window)
+ candidate_window->FocusStateChanged(IsInputFieldFocused());
+
+ chromeos::IMEBridge::Get()->SetCurrentTextInputType(GetTextInputType());
+
+ if (!IsTextInputTypeNone())
+ OnCaretBoundsChanged(GetTextInputClient());
+}
+
+void InputMethodChromeOS::ProcessKeyEventPostIME(
+ const ui::KeyEvent& event,
+ bool handled) {
+ TextInputClient* client = GetTextInputClient();
+ if (!client) {
+ // As ibus works asynchronously, there is a chance that the focused client
+ // loses focus before this method gets called.
+ DispatchKeyEventPostIME(event);
+ return;
+ }
+
+ if (event.type() == ET_KEY_PRESSED && handled)
+ ProcessFilteredKeyPressEvent(event);
+
+ // In case the focus was changed by the key event. The |context_| should have
+ // been reset when the focused window changed.
+ if (client != GetTextInputClient())
+ return;
+
+ if (HasInputMethodResult())
+ ProcessInputMethodResult(event, handled);
+
+ // In case the focus was changed when sending input method results to the
+ // focused window.
+ if (client != GetTextInputClient())
+ return;
+
+ if (event.type() == ET_KEY_PRESSED && !handled)
+ ProcessUnfilteredKeyPressEvent(event);
+ else if (event.type() == ET_KEY_RELEASED)
+ DispatchKeyEventPostIME(event);
+}
+
+void InputMethodChromeOS::ProcessFilteredKeyPressEvent(
+ const ui::KeyEvent& event) {
+ if (NeedInsertChar()) {
+ DispatchKeyEventPostIME(event);
+ } else {
+ const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
+ VKEY_PROCESSKEY,
+ event.flags(),
+ false); // is_char
+ DispatchKeyEventPostIME(fabricated_event);
+ }
+}
+
+void InputMethodChromeOS::ProcessUnfilteredKeyPressEvent(
+ const ui::KeyEvent& event) {
+ const TextInputClient* prev_client = GetTextInputClient();
+ DispatchKeyEventPostIME(event);
+
+ // We shouldn't dispatch the character anymore if the key event dispatch
+ // caused focus change. For example, in the following scenario,
+ // 1. visit a web page which has a <textarea>.
+ // 2. click Omnibox.
+ // 3. enable Korean IME, press A, then press Tab to move the focus to the web
+ // page.
+ // We should return here not to send the Tab key event to RWHV.
+ TextInputClient* client = GetTextInputClient();
+ if (!client || client != prev_client)
+ return;
+
+ // If a key event was not filtered by |context_| and |character_composer_|,
+ // then it means the key event didn't generate any result text. So we need
+ // to send corresponding character to the focused text input client.
+ uint16 ch = event.GetCharacter();
+ if (ch)
+ client->InsertChar(ch, event.flags());
+}
+
+void InputMethodChromeOS::ProcessInputMethodResult(const ui::KeyEvent& event,
+ bool handled) {
+ TextInputClient* client = GetTextInputClient();
+ DCHECK(client);
+
+ if (result_text_.length()) {
+ if (handled && NeedInsertChar()) {
+ for (base::string16::const_iterator i = result_text_.begin();
+ i != result_text_.end(); ++i) {
+ client->InsertChar(*i, event.flags());
+ }
+ } else {
+ client->InsertText(result_text_);
+ composing_text_ = false;
+ }
+ }
+
+ if (composition_changed_ && !IsTextInputTypeNone()) {
+ if (composition_.text.length()) {
+ composing_text_ = true;
+ client->SetCompositionText(composition_);
+ } else if (result_text_.empty()) {
+ client->ClearCompositionText();
+ }
+ }
+
+ // We should not clear composition text here, as it may belong to the next
+ // composition session.
+ result_text_.clear();
+ composition_changed_ = false;
+}
+
+bool InputMethodChromeOS::NeedInsertChar() const {
+ return GetTextInputClient() &&
+ (IsTextInputTypeNone() ||
+ (!composing_text_ && result_text_.length() == 1));
+}
+
+bool InputMethodChromeOS::HasInputMethodResult() const {
+ return result_text_.length() || composition_changed_;
+}
+
+void InputMethodChromeOS::SendFakeProcessKeyEvent(bool pressed) const {
+ if (!GetTextInputClient())
+ return;
+ KeyEvent evt(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED,
+ pressed ? VKEY_PROCESSKEY : VKEY_UNKNOWN,
+ EF_IME_FABRICATED_KEY,
+ false); // is_char
+ DispatchKeyEventPostIME(evt);
+}
+
+void InputMethodChromeOS::AbandonAllPendingKeyEvents() {
+ pending_key_events_.clear();
+}
+
+void InputMethodChromeOS::CommitText(const std::string& text) {
+ if (text.empty())
+ return;
+
+ // We need to receive input method result even if the text input type is
+ // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct
+ // character for each key event to the focused text input client.
+ if (!GetTextInputClient())
+ return;
+
+ const base::string16 utf16_text = base::UTF8ToUTF16(text);
+ if (utf16_text.empty())
+ return;
+
+ // Append the text to the buffer, because commit signal might be fired
+ // multiple times when processing a key event.
+ result_text_.append(utf16_text);
+
+ // If we are not handling key event, do not bother sending text result if the
+ // focused text input client does not support text input.
+ if (pending_key_events_.empty() && !IsTextInputTypeNone()) {
+ SendFakeProcessKeyEvent(true);
+ GetTextInputClient()->InsertText(utf16_text);
+ SendFakeProcessKeyEvent(false);
+ result_text_.clear();
+ }
+}
+
+void InputMethodChromeOS::UpdateCompositionText(
+ const chromeos::CompositionText& text,
+ uint32 cursor_pos,
+ bool visible) {
+ if (IsTextInputTypeNone())
+ return;
+
+ if (!CanComposeInline()) {
+ chromeos::IMECandidateWindowHandlerInterface* candidate_window =
+ chromeos::IMEBridge::Get()->GetCandidateWindowHandler();
+ if (candidate_window)
+ candidate_window->UpdatePreeditText(text.text(), cursor_pos, visible);
+ }
+
+ // |visible| argument is very confusing. For example, what's the correct
+ // behavior when:
+ // 1. OnUpdatePreeditText() is called with a text and visible == false, then
+ // 2. OnShowPreeditText() is called afterwards.
+ //
+ // If it's only for clearing the current preedit text, then why not just use
+ // OnHidePreeditText()?
+ if (!visible) {
+ HidePreeditText();
+ return;
+ }
+
+ ExtractCompositionText(text, cursor_pos, &composition_);
+
+ composition_changed_ = true;
+
+ // In case OnShowPreeditText() is not called.
+ if (composition_.text.length())
+ composing_text_ = true;
+
+ // If we receive a composition text without pending key event, then we need to
+ // send it to the focused text input client directly.
+ if (pending_key_events_.empty()) {
+ SendFakeProcessKeyEvent(true);
+ GetTextInputClient()->SetCompositionText(composition_);
+ SendFakeProcessKeyEvent(false);
+ composition_changed_ = false;
+ composition_.Clear();
+ }
+}
+
+void InputMethodChromeOS::HidePreeditText() {
+ if (composition_.text.empty() || IsTextInputTypeNone())
+ return;
+
+ // Intentionally leaves |composing_text_| unchanged.
+ composition_changed_ = true;
+ composition_.Clear();
+
+ if (pending_key_events_.empty()) {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->HasCompositionText()) {
+ SendFakeProcessKeyEvent(true);
+ client->ClearCompositionText();
+ SendFakeProcessKeyEvent(false);
+ }
+ composition_changed_ = false;
+ }
+}
+
+void InputMethodChromeOS::DeleteSurroundingText(int32 offset, uint32 length) {
+ if (!composition_.text.empty())
+ return; // do nothing if there is ongoing composition.
+ if (offset < 0 && static_cast<uint32>(-1 * offset) != length)
+ return; // only preceding text can be deletable.
+ if (GetTextInputClient())
+ GetTextInputClient()->ExtendSelectionAndDelete(length, 0U);
+}
+
+bool InputMethodChromeOS::ExecuteCharacterComposer(const ui::KeyEvent& event) {
+ if (!character_composer_.FilterKeyPress(event))
+ return false;
+
+ // CharacterComposer consumed the key event. Update the composition text.
+ chromeos::CompositionText preedit;
+ preedit.set_text(character_composer_.preedit_string());
+ UpdateCompositionText(preedit, preedit.text().size(),
+ !preedit.text().empty());
+ std::string commit_text =
+ base::UTF16ToUTF8(character_composer_.composed_character());
+ if (!commit_text.empty()) {
+ CommitText(commit_text);
+ }
+ return true;
+}
+
+void InputMethodChromeOS::ExtractCompositionText(
+ const chromeos::CompositionText& text,
+ uint32 cursor_position,
+ CompositionText* out_composition) const {
+ out_composition->Clear();
+ out_composition->text = text.text();
+
+ if (out_composition->text.empty())
+ return;
+
+ // ibus uses character index for cursor position and attribute range, but we
+ // use char16 offset for them. So we need to do conversion here.
+ std::vector<size_t> char16_offsets;
+ size_t length = out_composition->text.length();
+ base::i18n::UTF16CharIterator char_iterator(&out_composition->text);
+ do {
+ char16_offsets.push_back(char_iterator.array_pos());
+ } while (char_iterator.Advance());
+
+ // The text length in Unicode characters.
+ uint32 char_length = static_cast<uint32>(char16_offsets.size());
+ // Make sure we can convert the value of |char_length| as well.
+ char16_offsets.push_back(length);
+
+ size_t cursor_offset =
+ char16_offsets[std::min(char_length, cursor_position)];
+
+ out_composition->selection = gfx::Range(cursor_offset);
+
+ const std::vector<chromeos::CompositionText::UnderlineAttribute>&
+ underline_attributes = text.underline_attributes();
+ if (!underline_attributes.empty()) {
+ for (size_t i = 0; i < underline_attributes.size(); ++i) {
+ const uint32 start = underline_attributes[i].start_index;
+ const uint32 end = underline_attributes[i].end_index;
+ if (start >= end)
+ continue;
+ CompositionUnderline underline(char16_offsets[start],
+ char16_offsets[end],
+ SK_ColorBLACK,
+ false /* thick */,
+ SK_ColorTRANSPARENT);
+ if (underline_attributes[i].type ==
+ chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE)
+ underline.thick = true;
+ else if (underline_attributes[i].type ==
+ chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_ERROR)
+ underline.color = SK_ColorRED;
+ out_composition->underlines.push_back(underline);
+ }
+ }
+
+ DCHECK(text.selection_start() <= text.selection_end());
+ if (text.selection_start() < text.selection_end()) {
+ const uint32 start = text.selection_start();
+ const uint32 end = text.selection_end();
+ CompositionUnderline underline(char16_offsets[start],
+ char16_offsets[end],
+ SK_ColorBLACK,
+ true /* thick */,
+ SK_ColorTRANSPARENT);
+ out_composition->underlines.push_back(underline);
+
+ // 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.
+ if (underline.start_offset == cursor_offset) {
+ out_composition->selection.set_start(underline.end_offset);
+ out_composition->selection.set_end(cursor_offset);
+ } else if (underline.end_offset == cursor_offset) {
+ out_composition->selection.set_start(underline.start_offset);
+ out_composition->selection.set_end(cursor_offset);
+ }
+ }
+
+ // Use a black thin underline by default.
+ if (out_composition->underlines.empty()) {
+ out_composition->underlines.push_back(CompositionUnderline(
+ 0, length, SK_ColorBLACK, false /* thick */, SK_ColorTRANSPARENT));
+ }
+}
+
+bool InputMethodChromeOS::IsInputFieldFocused() {
+ TextInputType type = GetTextInputType();
+ return (type != TEXT_INPUT_TYPE_NONE) && (type != TEXT_INPUT_TYPE_PASSWORD);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_chromeos.h b/chromium/ui/base/ime/input_method_chromeos.h
new file mode 100644
index 00000000000..98b42aed445
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_chromeos.h
@@ -0,0 +1,158 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_INPUT_METHOD_CHROMEOS_H_
+#define UI_BASE_IME_INPUT_METHOD_CHROMEOS_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/base/ime/chromeos/character_composer.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ime/composition_text.h"
+#include "ui/base/ime/input_method_base.h"
+
+namespace ui {
+
+// A ui::InputMethod implementation based on IBus.
+class UI_BASE_EXPORT InputMethodChromeOS
+ : public InputMethodBase,
+ public chromeos::IMEInputContextHandlerInterface {
+ public:
+ explicit InputMethodChromeOS(internal::InputMethodDelegate* delegate);
+ virtual ~InputMethodChromeOS();
+
+ // Overridden from InputMethod:
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ NativeEventResult* result) OVERRIDE;
+ virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
+ virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
+ virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
+ virtual void OnInputLocaleChanged() OVERRIDE;
+ virtual std::string GetInputLocale() OVERRIDE;
+ virtual bool IsActive() OVERRIDE;
+ virtual bool IsCandidatePopupOpen() const OVERRIDE;
+
+ protected:
+ // Converts |text| into CompositionText.
+ void ExtractCompositionText(const chromeos::CompositionText& text,
+ uint32 cursor_position,
+ CompositionText* out_composition) const;
+
+ // Process a key returned from the input method.
+ virtual void ProcessKeyEventPostIME(const ui::KeyEvent& event,
+ bool handled);
+
+ // Resets context and abandon all pending results and key events.
+ void ResetContext();
+
+ private:
+ class PendingKeyEvent;
+
+ // Overridden from InputMethodBase:
+ virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) OVERRIDE;
+ virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) OVERRIDE;
+
+ // Asks the client to confirm current composition text.
+ void ConfirmCompositionText();
+
+ // Checks the availability of focused text input client and update focus
+ // state.
+ void UpdateContextFocusState();
+
+ // Processes a key event that was already filtered by the input method.
+ // A VKEY_PROCESSKEY may be dispatched to the focused View.
+ void ProcessFilteredKeyPressEvent(const ui::KeyEvent& event);
+
+ // Processes a key event that was not filtered by the input method.
+ void ProcessUnfilteredKeyPressEvent(const ui::KeyEvent& event);
+
+ // Sends input method result caused by the given key event to the focused text
+ // input client.
+ void ProcessInputMethodResult(const ui::KeyEvent& event, bool filtered);
+
+ // Checks if the pending input method result needs inserting into the focused
+ // text input client as a single character.
+ bool NeedInsertChar() const;
+
+ // Checks if there is pending input method result.
+ bool HasInputMethodResult() const;
+
+ // Sends a fake key event for IME composing without physical key events.
+ void SendFakeProcessKeyEvent(bool pressed) const;
+
+ // Abandons all pending key events. It usually happends when we lose keyboard
+ // focus, the text input type is changed or we are destroyed.
+ void AbandonAllPendingKeyEvents();
+
+ // Passes keyevent and executes character composition if necessary. Returns
+ // true if character composer comsumes key event.
+ bool ExecuteCharacterComposer(const ui::KeyEvent& event);
+
+ // chromeos::IMEInputContextHandlerInterface overrides:
+ virtual void CommitText(const std::string& text) OVERRIDE;
+ virtual void UpdateCompositionText(const chromeos::CompositionText& text,
+ uint32 cursor_pos,
+ bool visible) OVERRIDE;
+ virtual void DeleteSurroundingText(int32 offset, uint32 length) OVERRIDE;
+
+ // Hides the composition text.
+ void HidePreeditText();
+
+ // Callback function for IMEEngineHandlerInterface::ProcessKeyEvent.
+ void ProcessKeyEventDone(uint32 id, ui::KeyEvent* event, bool is_handled);
+
+ // Returns whether an input field is focused. Note that password field is not
+ // considered as an input field.
+ bool IsInputFieldFocused();
+
+ // All pending key events. Note: we do not own these object, we just save
+ // pointers to these object so that we can abandon them when necessary.
+ // They will be deleted in ProcessKeyEventDone().
+ std::set<uint32> pending_key_events_;
+
+ // Pending composition text generated by the current pending key event.
+ // It'll be sent to the focused text input client as soon as we receive the
+ // processing result of the pending key event.
+ CompositionText composition_;
+
+ // Pending result text generated by the current pending key event.
+ // It'll be sent to the focused text input client as soon as we receive the
+ // processing result of the pending key event.
+ base::string16 result_text_;
+
+ base::string16 previous_surrounding_text_;
+ gfx::Range previous_selection_range_;
+
+ // Indicates if there is an ongoing composition text.
+ bool composing_text_;
+
+ // Indicates if the composition text is changed or deleted.
+ bool composition_changed_;
+
+ // The latest id of key event.
+ uint32 current_keyevent_id_;
+
+ // An object to compose a character from a sequence of key presses
+ // including dead key etc.
+ CharacterComposer character_composer_;
+
+ // Used for making callbacks.
+ base::WeakPtrFactory<InputMethodChromeOS> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOS);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_INPUT_METHOD_CHROMEOS_H_
diff --git a/chromium/ui/base/ime/input_method_chromeos_unittest.cc b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
new file mode 100644
index 00000000000..0470f0c36ad
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_chromeos_unittest.cc
@@ -0,0 +1,1071 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/input_method_chromeos.h"
+
+#include <X11/Xlib.h>
+#undef Bool
+#undef FocusIn
+#undef FocusOut
+#undef None
+
+#include <cstring>
+
+#include "base/i18n/char_iterator.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ime/composition_text.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
+#include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
+#include "ui/base/ime/input_method_delegate.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/events/event.h"
+#include "ui/events/test/events_test_utils_x11.h"
+#include "ui/gfx/geometry/rect.h"
+
+using base::UTF8ToUTF16;
+using base::UTF16ToUTF8;
+
+namespace ui {
+namespace {
+
+const base::string16 kSampleText = base::UTF8ToUTF16(
+ "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
+
+typedef chromeos::IMEEngineHandlerInterface::KeyEventDoneCallback
+ KeyEventCallback;
+
+uint32 GetOffsetInUTF16(
+ const base::string16& utf16_string, uint32 utf8_offset) {
+ DCHECK_LT(utf8_offset, utf16_string.size());
+ base::i18n::UTF16CharIterator char_iterator(&utf16_string);
+ for (size_t i = 0; i < utf8_offset; ++i)
+ char_iterator.Advance();
+ return char_iterator.array_pos();
+}
+
+bool IsEqualXKeyEvent(const XEvent& e1, const XEvent& e2) {
+ if ((e1.type == KeyPress && e2.type == KeyPress) ||
+ (e1.type == KeyRelease && e2.type == KeyRelease)) {
+ return !std::memcmp(&e1.xkey, &e2.xkey, sizeof(XKeyEvent));
+ }
+ return false;
+}
+
+enum KeyEventHandlerBehavior {
+ KEYEVENT_CONSUME,
+ KEYEVENT_NOT_CONSUME,
+};
+
+} // namespace
+
+
+class TestableInputMethodChromeOS : public InputMethodChromeOS {
+ public:
+ explicit TestableInputMethodChromeOS(internal::InputMethodDelegate* delegate)
+ : InputMethodChromeOS(delegate),
+ process_key_event_post_ime_call_count_(0) {
+ }
+
+ struct ProcessKeyEventPostIMEArgs {
+ ProcessKeyEventPostIMEArgs() : event(NULL), handled(false) {}
+ const ui::KeyEvent* event;
+ bool handled;
+ };
+
+ // Overridden from InputMethodChromeOS:
+ virtual void ProcessKeyEventPostIME(const ui::KeyEvent& key_event,
+ bool handled) OVERRIDE {
+ process_key_event_post_ime_args_.event = &key_event;
+ process_key_event_post_ime_args_.handled = handled;
+ ++process_key_event_post_ime_call_count_;
+ }
+
+ void ResetCallCount() {
+ process_key_event_post_ime_call_count_ = 0;
+ }
+
+ const ProcessKeyEventPostIMEArgs& process_key_event_post_ime_args() const {
+ return process_key_event_post_ime_args_;
+ }
+
+ int process_key_event_post_ime_call_count() const {
+ return process_key_event_post_ime_call_count_;
+ }
+
+ // Change access rights for testing.
+ using InputMethodChromeOS::ExtractCompositionText;
+ using InputMethodChromeOS::ResetContext;
+
+ private:
+ ProcessKeyEventPostIMEArgs process_key_event_post_ime_args_;
+ int process_key_event_post_ime_call_count_;
+};
+
+class SynchronousKeyEventHandler {
+ public:
+ SynchronousKeyEventHandler(uint32 expected_keyval,
+ uint32 expected_keycode,
+ uint32 expected_state,
+ KeyEventHandlerBehavior behavior)
+ : expected_keyval_(expected_keyval),
+ expected_keycode_(expected_keycode),
+ expected_state_(expected_state),
+ behavior_(behavior) {}
+
+ virtual ~SynchronousKeyEventHandler() {}
+
+ void Run(uint32 keyval,
+ uint32 keycode,
+ uint32 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 expected_keyval_;
+ const uint32 expected_keycode_;
+ const uint32 expected_state_;
+ const KeyEventHandlerBehavior behavior_;
+
+ DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler);
+};
+
+class AsynchronousKeyEventHandler {
+ public:
+ AsynchronousKeyEventHandler(uint32 expected_keyval,
+ uint32 expected_keycode,
+ uint32 expected_state)
+ : expected_keyval_(expected_keyval),
+ expected_keycode_(expected_keycode),
+ expected_state_(expected_state) {}
+
+ virtual ~AsynchronousKeyEventHandler() {}
+
+ void Run(uint32 keyval,
+ uint32 keycode,
+ uint32 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 expected_keyval_;
+ const uint32 expected_keycode_;
+ const uint32 expected_state_;
+ KeyEventCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler);
+};
+
+class SetSurroundingTextVerifier {
+ public:
+ SetSurroundingTextVerifier(const std::string& expected_surrounding_text,
+ uint32 expected_cursor_position,
+ uint32 expected_anchor_position)
+ : expected_surrounding_text_(expected_surrounding_text),
+ expected_cursor_position_(expected_cursor_position),
+ expected_anchor_position_(expected_anchor_position) {}
+
+ void Verify(const std::string& text,
+ uint32 cursor_pos,
+ uint32 anchor_pos) {
+ EXPECT_EQ(expected_surrounding_text_, text);
+ EXPECT_EQ(expected_cursor_position_, cursor_pos);
+ EXPECT_EQ(expected_anchor_position_, anchor_pos);
+ }
+
+ private:
+ const std::string expected_surrounding_text_;
+ const uint32 expected_cursor_position_;
+ const uint32 expected_anchor_position_;
+
+ DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier);
+};
+
+class InputMethodChromeOSTest : public internal::InputMethodDelegate,
+ public testing::Test,
+ public TextInputClient {
+ public:
+ InputMethodChromeOSTest()
+ : dispatched_key_event_(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, 0, false) {
+ ResetFlags();
+ }
+
+ virtual ~InputMethodChromeOSTest() {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ chromeos::IMEBridge::Initialize();
+
+ mock_ime_engine_handler_.reset(
+ new chromeos::MockIMEEngineHandler());
+ chromeos::IMEBridge::Get()->SetCurrentEngineHandler(
+ mock_ime_engine_handler_.get());
+
+ mock_ime_candidate_window_handler_.reset(
+ new chromeos::MockIMECandidateWindowHandler());
+ chromeos::IMEBridge::Get()->SetCandidateWindowHandler(
+ mock_ime_candidate_window_handler_.get());
+
+ ime_.reset(new TestableInputMethodChromeOS(this));
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->FocusTextInputClient(this);
+ else
+ ime_->SetFocusedTextInputClient(this);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ if (ime_.get()) {
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->BlurTextInputClient(this);
+ else
+ ime_->SetFocusedTextInputClient(NULL);
+ }
+ ime_.reset();
+ chromeos::IMEBridge::Get()->SetCurrentEngineHandler(NULL);
+ chromeos::IMEBridge::Get()->SetCandidateWindowHandler(NULL);
+ mock_ime_engine_handler_.reset();
+ mock_ime_candidate_window_handler_.reset();
+ chromeos::IMEBridge::Shutdown();
+ }
+
+ // Overridden from ui::internal::InputMethodDelegate:
+ virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) OVERRIDE {
+ dispatched_key_event_ = event;
+ return false;
+ }
+
+ // Overridden from ui::TextInputClient:
+ virtual void SetCompositionText(
+ const CompositionText& composition) OVERRIDE {
+ composition_text_ = composition;
+ }
+ virtual void ConfirmCompositionText() OVERRIDE {
+ confirmed_text_ = composition_text_;
+ composition_text_.Clear();
+ }
+ virtual void ClearCompositionText() OVERRIDE {
+ composition_text_.Clear();
+ }
+ virtual void InsertText(const base::string16& text) OVERRIDE {
+ inserted_text_ = text;
+ }
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {
+ inserted_char_ = ch;
+ inserted_char_flags_ = flags;
+ }
+ virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
+ return static_cast<gfx::NativeWindow>(NULL);
+ }
+ virtual TextInputType GetTextInputType() const OVERRIDE {
+ return input_type_;
+ }
+ virtual TextInputMode GetTextInputMode() const OVERRIDE {
+ return input_mode_;
+ }
+ virtual bool CanComposeInline() const OVERRIDE {
+ return can_compose_inline_;
+ }
+ virtual gfx::Rect GetCaretBounds() const OVERRIDE {
+ return caret_bounds_;
+ }
+ virtual bool GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const OVERRIDE {
+ return false;
+ }
+ virtual bool HasCompositionText() const OVERRIDE {
+ CompositionText empty;
+ return composition_text_ != empty;
+ }
+ virtual bool GetTextRange(gfx::Range* range) const OVERRIDE {
+ *range = text_range_;
+ return true;
+ }
+ virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE {
+ return false;
+ }
+ virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE {
+ *range = selection_range_;
+ return true;
+ }
+
+ virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE {
+ return false;
+ }
+ virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; }
+ virtual bool GetTextFromRange(const gfx::Range& range,
+ base::string16* text) const OVERRIDE {
+ *text = surrounding_text_.substr(range.GetMin(), range.length());
+ return true;
+ }
+ virtual void OnInputMethodChanged() OVERRIDE {
+ ++on_input_method_changed_call_count_;
+ }
+ virtual bool ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) OVERRIDE { return false; }
+ virtual void ExtendSelectionAndDelete(size_t before,
+ size_t after) OVERRIDE {}
+ virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {}
+ virtual void OnCandidateWindowShown() OVERRIDE {}
+ virtual void OnCandidateWindowUpdated() OVERRIDE {}
+ virtual void OnCandidateWindowHidden() OVERRIDE {}
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE {
+ return false;
+ }
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE {}
+
+ bool HasNativeEvent() const {
+ return dispatched_key_event_.HasNativeEvent();
+ }
+
+ void ResetFlags() {
+ dispatched_key_event_ = ui::KeyEvent(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, 0,
+ false);
+
+ composition_text_.Clear();
+ confirmed_text_.Clear();
+ inserted_text_.clear();
+ inserted_char_ = 0;
+ inserted_char_flags_ = 0;
+ on_input_method_changed_call_count_ = 0;
+
+ input_type_ = TEXT_INPUT_TYPE_NONE;
+ input_mode_ = TEXT_INPUT_MODE_DEFAULT;
+ can_compose_inline_ = true;
+ caret_bounds_ = gfx::Rect();
+ }
+
+ scoped_ptr<TestableInputMethodChromeOS> ime_;
+
+ // Copy of the dispatched key event.
+ ui::KeyEvent dispatched_key_event_;
+
+ // Variables for remembering the parameters that are passed to
+ // ui::TextInputClient functions.
+ CompositionText composition_text_;
+ CompositionText confirmed_text_;
+ base::string16 inserted_text_;
+ base::char16 inserted_char_;
+ unsigned int on_input_method_changed_call_count_;
+ int inserted_char_flags_;
+
+ // Variables that will be returned from the ui::TextInputClient functions.
+ TextInputType input_type_;
+ TextInputMode input_mode_;
+ bool can_compose_inline_;
+ gfx::Rect caret_bounds_;
+ gfx::Range text_range_;
+ gfx::Range selection_range_;
+ base::string16 surrounding_text_;
+
+ scoped_ptr<chromeos::MockIMEEngineHandler> mock_ime_engine_handler_;
+ scoped_ptr<chromeos::MockIMECandidateWindowHandler>
+ mock_ime_candidate_window_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSTest);
+};
+
+// Tests public APIs in ui::InputMethod first.
+
+TEST_F(InputMethodChromeOSTest, GetInputLocale) {
+ // ui::InputMethodChromeOS does not support the API.
+ ime_->Init(true);
+ EXPECT_EQ("", ime_->GetInputLocale());
+}
+
+TEST_F(InputMethodChromeOSTest, IsActive) {
+ ime_->Init(true);
+ // ui::InputMethodChromeOS always returns true.
+ EXPECT_TRUE(ime_->IsActive());
+}
+
+TEST_F(InputMethodChromeOSTest, GetInputTextType) {
+ ime_->Init(true);
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, ime_->GetTextInputType());
+}
+
+TEST_F(InputMethodChromeOSTest, CanComposeInline) {
+ ime_->Init(true);
+ EXPECT_TRUE(ime_->CanComposeInline());
+ can_compose_inline_ = false;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_FALSE(ime_->CanComposeInline());
+}
+
+TEST_F(InputMethodChromeOSTest, GetTextInputClient) {
+ ime_->Init(true);
+ EXPECT_EQ(this, ime_->GetTextInputClient());
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->BlurTextInputClient(this);
+ else
+ ime_->SetFocusedTextInputClient(NULL);
+ EXPECT_EQ(NULL, ime_->GetTextInputClient());
+}
+
+TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedClient) {
+ ime_->Init(true);
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->BlurTextInputClient(this);
+ else
+ ime_->SetFocusedTextInputClient(NULL);
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ // The OnTextInputTypeChanged() call above should be ignored since |this| is
+ // not the current focused client.
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->FocusTextInputClient(this);
+ else
+ ime_->SetFocusedTextInputClient(this);
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
+}
+
+TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow) {
+ ime_->Init(true);
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->BlurTextInputClient(this);
+ else
+ ime_->OnBlur();
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ // The OnTextInputTypeChanged() call above should be ignored since the top-
+ // level window which the ime_ is attached to is not currently focused.
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+
+ if (switches::IsTextInputFocusManagerEnabled())
+ TextInputFocusManager::GetInstance()->FocusTextInputClient(this);
+ else
+ ime_->OnFocus();
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
+}
+
+TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow2) {
+ // We no longer support the case that |ime_->Init(false)| because no one
+ // actually uses it.
+ if (switches::IsTextInputFocusManagerEnabled())
+ return;
+
+ ime_->Init(false); // the top-level is initially unfocused.
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
+
+ ime_->OnFocus();
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
+}
+
+// Confirm that IBusClient::FocusIn is called on "connected" if input_type_ is
+// TEXT.
+TEST_F(InputMethodChromeOSTest, FocusIn_Text) {
+ ime_->Init(true);
+ // A context shouldn't be created since the daemon is not running.
+ EXPECT_EQ(0U, on_input_method_changed_call_count_);
+ // Click a text input form.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+ // Since a form has focus, IBusClient::FocusIn() should be called.
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(
+ 1,
+ mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
+ // ui::TextInputClient::OnInputMethodChanged() should be called when
+ // ui::InputMethodChromeOS connects/disconnects to/from ibus-daemon and the
+ // current text input type is not NONE.
+ EXPECT_EQ(1U, on_input_method_changed_call_count_);
+}
+
+// Confirm that InputMethodEngine::FocusIn is called on "connected" even if
+// input_type_ is PASSWORD.
+TEST_F(InputMethodChromeOSTest, FocusIn_Password) {
+ ime_->Init(true);
+ EXPECT_EQ(0U, on_input_method_changed_call_count_);
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ // InputMethodEngine::FocusIn() should be called even for password field.
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(1U, on_input_method_changed_call_count_);
+}
+
+// Confirm that IBusClient::FocusOut is called as expected.
+TEST_F(InputMethodChromeOSTest, FocusOut_None) {
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->Init(true);
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+ input_type_ = TEXT_INPUT_TYPE_NONE;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
+}
+
+// Confirm that IBusClient::FocusOut is called as expected.
+TEST_F(InputMethodChromeOSTest, FocusOut_Password) {
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->Init(true);
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+ input_type_ = TEXT_INPUT_TYPE_PASSWORD;
+ ime_->OnTextInputTypeChanged(this);
+ EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
+}
+
+// FocusIn/FocusOut scenario test
+TEST_F(InputMethodChromeOSTest, Focus_Scenario) {
+ ime_->Init(true);
+ // Confirm that both FocusIn and FocusOut are NOT called.
+ EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+ EXPECT_EQ(TEXT_INPUT_TYPE_NONE,
+ mock_ime_engine_handler_->last_text_input_context().type);
+ EXPECT_EQ(TEXT_INPUT_MODE_DEFAULT,
+ mock_ime_engine_handler_->last_text_input_context().mode);
+
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ input_mode_ = TEXT_INPUT_MODE_LATIN;
+ ime_->OnTextInputTypeChanged(this);
+ // Confirm that only FocusIn is called, the TextInputType is TEXT and the
+ // TextInputMode is LATIN..
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
+ EXPECT_EQ(TEXT_INPUT_TYPE_TEXT,
+ mock_ime_engine_handler_->last_text_input_context().type);
+ EXPECT_EQ(TEXT_INPUT_MODE_LATIN,
+ mock_ime_engine_handler_->last_text_input_context().mode);
+
+ input_mode_ = TEXT_INPUT_MODE_KANA;
+ ime_->OnTextInputTypeChanged(this);
+ // Confirm that both FocusIn and FocusOut are called for mode change.
+ EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
+ EXPECT_EQ(TEXT_INPUT_TYPE_TEXT,
+ mock_ime_engine_handler_->last_text_input_context().type);
+ EXPECT_EQ(TEXT_INPUT_MODE_KANA,
+ mock_ime_engine_handler_->last_text_input_context().mode);
+
+ input_type_ = TEXT_INPUT_TYPE_URL;
+ ime_->OnTextInputTypeChanged(this);
+ // Confirm that both FocusIn and FocusOut are called and the TextInputType is
+ // changed to URL.
+ EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(2, mock_ime_engine_handler_->focus_out_call_count());
+ EXPECT_EQ(TEXT_INPUT_TYPE_URL,
+ mock_ime_engine_handler_->last_text_input_context().type);
+ EXPECT_EQ(TEXT_INPUT_MODE_KANA,
+ mock_ime_engine_handler_->last_text_input_context().mode);
+
+ // When IsTextInputFocusManagerEnabled, InputMethod::SetFocusedTextInputClient
+ // is not supported and it's no-op.
+ if (switches::IsTextInputFocusManagerEnabled())
+ return;
+ // Confirm that FocusOut is called when set focus to NULL client.
+ ime_->SetFocusedTextInputClient(NULL);
+ EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count());
+ // Confirm that FocusIn is called when set focus to this client.
+ ime_->SetFocusedTextInputClient(this);
+ EXPECT_EQ(4, mock_ime_engine_handler_->focus_in_call_count());
+ EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count());
+}
+
+// Test if the new |caret_bounds_| is correctly sent to ibus-daemon.
+TEST_F(InputMethodChromeOSTest, OnCaretBoundsChanged) {
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->Init(true);
+ EXPECT_EQ(
+ 1,
+ mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
+ caret_bounds_ = gfx::Rect(1, 2, 3, 4);
+ ime_->OnCaretBoundsChanged(this);
+ EXPECT_EQ(
+ 2,
+ mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
+ caret_bounds_ = gfx::Rect(0, 2, 3, 4);
+ ime_->OnCaretBoundsChanged(this);
+ EXPECT_EQ(
+ 3,
+ mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
+ caret_bounds_ = gfx::Rect(0, 2, 3, 4); // unchanged
+ ime_->OnCaretBoundsChanged(this);
+ // Current InputMethodChromeOS implementation performs the IPC
+ // regardless of the bounds are changed or not.
+ EXPECT_EQ(
+ 4,
+ mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
+}
+
+TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_NoAttribute) {
+ const base::string16 kSampleAsciiText = UTF8ToUTF16("Sample Text");
+ const uint32 kCursorPos = 2UL;
+
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleAsciiText);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleAsciiText, composition_text.text);
+ // If there is no selection, |selection| represents cursor position.
+ EXPECT_EQ(kCursorPos, composition_text.selection.start());
+ EXPECT_EQ(kCursorPos, composition_text.selection.end());
+ // If there is no underline, |underlines| contains one underline and it is
+ // whole text underline.
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(0UL, composition_text.underlines[0].start_offset);
+ EXPECT_EQ(kSampleAsciiText.size(), composition_text.underlines[0].end_offset);
+ EXPECT_FALSE(composition_text.underlines[0].thick);
+}
+
+TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) {
+ const uint32 kCursorPos = 2UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos::CompositionText::UnderlineAttribute underline;
+ underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE;
+ underline.start_index = 1UL;
+ underline.end_index = 4UL;
+ chromeos_composition_text.mutable_underline_attributes()->push_back(
+ underline);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ // If there is no selection, |selection| represents cursor position.
+ EXPECT_EQ(kCursorPos, composition_text.selection.start());
+ EXPECT_EQ(kCursorPos, composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
+ composition_text.underlines[0].end_offset);
+ // Single underline represents as black thin line.
+ EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
+ EXPECT_FALSE(composition_text.underlines[0].thick);
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ composition_text.underlines[0].background_color);
+}
+
+TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) {
+ const uint32 kCursorPos = 2UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos::CompositionText::UnderlineAttribute underline;
+ underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE;
+ underline.start_index = 1UL;
+ underline.end_index = 4UL;
+ chromeos_composition_text.mutable_underline_attributes()->push_back(
+ underline);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ // If there is no selection, |selection| represents cursor position.
+ EXPECT_EQ(kCursorPos, composition_text.selection.start());
+ EXPECT_EQ(kCursorPos, composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
+ composition_text.underlines[0].end_offset);
+ // Double underline represents as black thick line.
+ EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
+ EXPECT_TRUE(composition_text.underlines[0].thick);
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ composition_text.underlines[0].background_color);
+}
+
+TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) {
+ const uint32 kCursorPos = 2UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos::CompositionText::UnderlineAttribute underline;
+ underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_ERROR;
+ underline.start_index = 1UL;
+ underline.end_index = 4UL;
+ chromeos_composition_text.mutable_underline_attributes()->push_back(
+ underline);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ EXPECT_EQ(kCursorPos, composition_text.selection.start());
+ EXPECT_EQ(kCursorPos, composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
+ composition_text.underlines[0].end_offset);
+ // Error underline represents as red thin line.
+ EXPECT_EQ(SK_ColorRED, composition_text.underlines[0].color);
+ EXPECT_FALSE(composition_text.underlines[0].thick);
+}
+
+TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) {
+ const uint32 kCursorPos = 2UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos_composition_text.set_selection_start(1UL);
+ chromeos_composition_text.set_selection_end(4UL);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ EXPECT_EQ(kCursorPos, composition_text.selection.start());
+ EXPECT_EQ(kCursorPos, composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_start()),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_end()),
+ composition_text.underlines[0].end_offset);
+ EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
+ EXPECT_TRUE(composition_text.underlines[0].thick);
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ composition_text.underlines[0].background_color);
+}
+
+TEST_F(InputMethodChromeOSTest,
+ ExtractCompositionTextTest_SelectionStartWithCursor) {
+ const uint32 kCursorPos = 1UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos_composition_text.set_selection_start(kCursorPos);
+ chromeos_composition_text.set_selection_end(4UL);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ // If the cursor position is same as selection bounds, selection start
+ // position become opposit side of selection from cursor.
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_end()),
+ composition_text.selection.start());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos),
+ composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_start()),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_end()),
+ composition_text.underlines[0].end_offset);
+ EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
+ EXPECT_TRUE(composition_text.underlines[0].thick);
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ composition_text.underlines[0].background_color);
+}
+
+TEST_F(InputMethodChromeOSTest,
+ ExtractCompositionTextTest_SelectionEndWithCursor) {
+ const uint32 kCursorPos = 4UL;
+
+ // Set up chromeos composition text with one underline attribute.
+ chromeos::CompositionText chromeos_composition_text;
+ chromeos_composition_text.set_text(kSampleText);
+ chromeos_composition_text.set_selection_start(1UL);
+ chromeos_composition_text.set_selection_end(kCursorPos);
+
+ CompositionText composition_text;
+ ime_->ExtractCompositionText(
+ chromeos_composition_text, kCursorPos, &composition_text);
+ EXPECT_EQ(kSampleText, composition_text.text);
+ // If the cursor position is same as selection bounds, selection start
+ // position become opposit side of selection from cursor.
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_start()),
+ composition_text.selection.start());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos),
+ composition_text.selection.end());
+ ASSERT_EQ(1UL, composition_text.underlines.size());
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_start()),
+ composition_text.underlines[0].start_offset);
+ EXPECT_EQ(GetOffsetInUTF16(kSampleText,
+ chromeos_composition_text.selection_end()),
+ composition_text.underlines[0].end_offset);
+ EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
+ EXPECT_TRUE(composition_text.underlines[0].thick);
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ composition_text.underlines[0].background_color);
+}
+
+TEST_F(InputMethodChromeOSTest, SurroundingText_NoSelectionTest) {
+ ime_->Init(true);
+ // Click a text input form.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+
+ // Set the TextInputClient behaviors.
+ surrounding_text_ = UTF8ToUTF16("abcdef");
+ text_range_ = gfx::Range(0, 6);
+ selection_range_ = gfx::Range(3, 3);
+
+ // Set the verifier for SetSurroundingText mock call.
+ SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 3, 3);
+
+
+ ime_->OnCaretBoundsChanged(this);
+
+ // Check the call count.
+ EXPECT_EQ(1,
+ mock_ime_engine_handler_->set_surrounding_text_call_count());
+ EXPECT_EQ(UTF16ToUTF8(surrounding_text_),
+ mock_ime_engine_handler_->last_set_surrounding_text());
+ EXPECT_EQ(3U,
+ mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
+ EXPECT_EQ(3U,
+ mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
+}
+
+TEST_F(InputMethodChromeOSTest, SurroundingText_SelectionTest) {
+ ime_->Init(true);
+ // Click a text input form.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+
+ // Set the TextInputClient behaviors.
+ surrounding_text_ = UTF8ToUTF16("abcdef");
+ text_range_ = gfx::Range(0, 6);
+ selection_range_ = gfx::Range(2, 5);
+
+ // Set the verifier for SetSurroundingText mock call.
+ SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 2, 5);
+
+ ime_->OnCaretBoundsChanged(this);
+
+ // Check the call count.
+ EXPECT_EQ(1,
+ mock_ime_engine_handler_->set_surrounding_text_call_count());
+ EXPECT_EQ(UTF16ToUTF8(surrounding_text_),
+ mock_ime_engine_handler_->last_set_surrounding_text());
+ EXPECT_EQ(2U,
+ mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
+ EXPECT_EQ(5U,
+ mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
+}
+
+TEST_F(InputMethodChromeOSTest, SurroundingText_PartialText) {
+ ime_->Init(true);
+ // Click a text input form.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+
+ // Set the TextInputClient behaviors.
+ surrounding_text_ = UTF8ToUTF16("abcdefghij");
+ text_range_ = gfx::Range(5, 10);
+ selection_range_ = gfx::Range(7, 9);
+
+ ime_->OnCaretBoundsChanged(this);
+
+ // Check the call count.
+ EXPECT_EQ(1,
+ mock_ime_engine_handler_->set_surrounding_text_call_count());
+ // Set the verifier for SetSurroundingText mock call.
+ // Here (2, 4) is selection range in expected surrounding text coordinates.
+ EXPECT_EQ("fghij",
+ mock_ime_engine_handler_->last_set_surrounding_text());
+ EXPECT_EQ(2U,
+ mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
+ EXPECT_EQ(4U,
+ mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
+}
+
+TEST_F(InputMethodChromeOSTest, SurroundingText_BecomeEmptyText) {
+ ime_->Init(true);
+ // Click a text input form.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+
+ // Set the TextInputClient behaviors.
+ // If the surrounding text becomes empty, text_range become (0, 0) and
+ // selection range become invalid.
+ surrounding_text_ = UTF8ToUTF16("");
+ text_range_ = gfx::Range(0, 0);
+ selection_range_ = gfx::Range::InvalidRange();
+
+ ime_->OnCaretBoundsChanged(this);
+
+ // Check the call count.
+ EXPECT_EQ(0,
+ mock_ime_engine_handler_->set_surrounding_text_call_count());
+
+ // Should not be called twice with same condition.
+ ime_->OnCaretBoundsChanged(this);
+ EXPECT_EQ(0,
+ mock_ime_engine_handler_->set_surrounding_text_call_count());
+}
+
+class InputMethodChromeOSKeyEventTest : public InputMethodChromeOSTest {
+ public:
+ InputMethodChromeOSKeyEventTest() {}
+ virtual ~InputMethodChromeOSKeyEventTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ InputMethodChromeOSTest::SetUp();
+ ime_->Init(true);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSKeyEventTest);
+};
+
+TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseTest) {
+ const int kFlags = ui::EF_SHIFT_DOWN;
+ ScopedXI2Event xevent;
+ xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, kFlags);
+ const ui::KeyEvent event(xevent, true);
+
+ // Do key event.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+ ime_->DispatchKeyEvent(event);
+
+ // Check before state.
+ const ui::KeyEvent* key_event =
+ mock_ime_engine_handler_->last_processed_key_event();
+ EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count());
+ EXPECT_EQ(ui::VKEY_A, key_event->key_code());
+ EXPECT_EQ("KeyA", key_event->code());
+ EXPECT_EQ(kFlags, key_event->flags());
+ EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
+
+ // Do callback.
+ 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 =
+ ime_->process_key_event_post_ime_args().event;
+ EXPECT_TRUE(stored_event->HasNativeEvent());
+ EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event())));
+ EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
+}
+
+TEST_F(InputMethodChromeOSKeyEventTest, MultiKeyEventDelayResponseTest) {
+ // Preparation
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+
+ const int kFlags = ui::EF_SHIFT_DOWN;
+ ScopedXI2Event xevent;
+ xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, kFlags);
+ const ui::KeyEvent event(xevent, true);
+
+ // Do key event.
+ ime_->DispatchKeyEvent(event);
+ const ui::KeyEvent* key_event =
+ mock_ime_engine_handler_->last_processed_key_event();
+ EXPECT_EQ(ui::VKEY_B, key_event->key_code());
+ EXPECT_EQ("KeyB", key_event->code());
+ EXPECT_EQ(kFlags, key_event->flags());
+
+ KeyEventCallback first_callback =
+ mock_ime_engine_handler_->last_passed_callback();
+
+ // Do key event again.
+ ScopedXI2Event xevent2;
+ xevent2.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, kFlags);
+ const ui::KeyEvent event2(xevent2, true);
+
+ ime_->DispatchKeyEvent(event2);
+ const ui::KeyEvent* key_event2 =
+ mock_ime_engine_handler_->last_processed_key_event();
+ EXPECT_EQ(ui::VKEY_C, key_event2->key_code());
+ EXPECT_EQ("KeyC", key_event2->code());
+ EXPECT_EQ(kFlags, key_event2->flags());
+
+ // Check before state.
+ EXPECT_EQ(2,
+ mock_ime_engine_handler_->process_key_event_call_count());
+ EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
+
+ // Do callback for first key event.
+ first_callback.Run(true);
+
+ // 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_TRUE(stored_event->HasNativeEvent());
+ EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event())));
+ EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
+
+ // Do callback for second key event.
+ mock_ime_engine_handler_->last_passed_callback().Run(false);
+
+ // 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_TRUE(stored_event->HasNativeEvent());
+ EXPECT_TRUE(IsEqualXKeyEvent(*xevent2, *(stored_event->native_event())));
+ EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled);
+}
+
+TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseResetTest) {
+ ScopedXI2Event xevent;
+ xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_SHIFT_DOWN);
+ const ui::KeyEvent event(xevent, true);
+
+ // Do key event.
+ input_type_ = TEXT_INPUT_TYPE_TEXT;
+ ime_->OnTextInputTypeChanged(this);
+ ime_->DispatchKeyEvent(event);
+
+ // Check before state.
+ EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count());
+ EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
+
+ ime_->ResetContext();
+
+ // Do callback.
+ mock_ime_engine_handler_->last_passed_callback().Run(true);
+
+ EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
+}
+// TODO(nona): Introduce ProcessKeyEventPostIME tests(crbug.com/156593).
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_delegate.h b/chromium/ui/base/ime/input_method_delegate.h
index ac332025d70..080a8f6f334 100644
--- a/chromium/ui/base/ime/input_method_delegate.h
+++ b/chromium/ui/base/ime/input_method_delegate.h
@@ -5,29 +5,23 @@
#ifndef UI_BASE_IME_INPUT_METHOD_DELEGATE_H_
#define UI_BASE_IME_INPUT_METHOD_DELEGATE_H_
-#include "base/event_types.h"
-#include "ui/base/ui_export.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
+
+class KeyEvent;
+
namespace internal {
// An interface implemented by the object that handles events sent back from an
// ui::InputMethod implementation.
-class UI_EXPORT InputMethodDelegate {
+class UI_BASE_EXPORT InputMethodDelegate {
public:
virtual ~InputMethodDelegate() {}
// Dispatch a key event already processed by the input method.
// Returns true if the event was processed.
- virtual bool DispatchKeyEventPostIME(
- const base::NativeEvent& native_key_event) = 0;
-
- // TODO(komatsu): Unify this function to DispatchKeyEventPostIME.
- virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) = 0;
+ virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& key_event) = 0;
};
} // namespace internal
diff --git a/chromium/ui/base/ime/input_method_factory.cc b/chromium/ui/base/ime/input_method_factory.cc
index 616dd22bd24..876817c86a4 100644
--- a/chromium/ui/base/ime/input_method_factory.cc
+++ b/chromium/ui/base/ime/input_method_factory.cc
@@ -4,17 +4,17 @@
#include "ui/base/ime/input_method_factory.h"
-#include "base/memory/singleton.h"
#include "ui/base/ime/mock_input_method.h"
#if defined(OS_CHROMEOS) && defined(USE_X11)
-#include "ui/base/ime/input_method_ibus.h"
+#include "ui/base/ime/input_method_chromeos.h"
#elif defined(OS_WIN)
#include "base/win/metro.h"
-#include "ui/base/ime/input_method_imm32.h"
-#include "ui/base/ime/input_method_tsf.h"
+#include "ui/base/ime/input_method_win.h"
#include "ui/base/ime/remote_input_method_win.h"
-#elif defined(USE_AURA) && defined(USE_X11)
+#elif defined(OS_MACOSX)
+#include "ui/base/ime/input_method_mac.h"
+#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "ui/base/ime/input_method_auralinux.h"
#else
#include "ui/base/ime/input_method_minimal.h"
@@ -22,103 +22,48 @@
namespace {
-ui::InputMethodFactory* g_input_method_factory = NULL;
+bool g_input_method_set_for_testing = false;
-#if defined(OS_WIN)
-ui::InputMethod* g_shared_input_method = NULL;
-#endif
+bool g_create_input_method_called = false;
} // namespace
namespace ui {
-// static
-InputMethodFactory* InputMethodFactory::GetInstance() {
- if (!g_input_method_factory)
- SetInstance(DefaultInputMethodFactory::GetInstance());
-
- return g_input_method_factory;
-}
-
-// static
-void InputMethodFactory::SetInstance(InputMethodFactory* instance) {
- CHECK(!g_input_method_factory);
- CHECK(instance);
-
- g_input_method_factory = instance;
-}
-
-// static
-void InputMethodFactory::ClearInstance() {
- // It's a client's duty to delete the object.
- g_input_method_factory = NULL;
-}
-
-// DefaultInputMethodFactory
-
-// static
-DefaultInputMethodFactory* DefaultInputMethodFactory::GetInstance() {
- return Singleton<DefaultInputMethodFactory>::get();
-}
-
-scoped_ptr<InputMethod> DefaultInputMethodFactory::CreateInputMethod(
+scoped_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget) {
+ if (!g_create_input_method_called)
+ g_create_input_method_called = true;
+
+ if (g_input_method_set_for_testing)
+ return scoped_ptr<InputMethod>(new MockInputMethod(delegate));
+
#if defined(OS_CHROMEOS) && defined(USE_X11)
- return scoped_ptr<InputMethod>(new InputMethodIBus(delegate));
+ return scoped_ptr<InputMethod>(new InputMethodChromeOS(delegate));
#elif defined(OS_WIN)
- if (base::win::IsTSFAwareRequired())
- return scoped_ptr<InputMethod>(new InputMethodTSF(delegate, widget));
if (IsRemoteInputMethodWinRequired(widget))
return CreateRemoteInputMethodWin(delegate);
- return scoped_ptr<InputMethod>(new InputMethodIMM32(delegate, widget));
-#elif defined(USE_AURA) && defined(USE_X11)
+ return scoped_ptr<InputMethod>(new InputMethodWin(delegate, widget));
+#elif defined(OS_MACOSX)
+ return scoped_ptr<InputMethod>(new InputMethodMac(delegate));
+#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
return scoped_ptr<InputMethod>(new InputMethodAuraLinux(delegate));
#else
return scoped_ptr<InputMethod>(new InputMethodMinimal(delegate));
#endif
}
-// MockInputMethodFactory
-
-// static
-MockInputMethodFactory* MockInputMethodFactory::GetInstance() {
- return Singleton<MockInputMethodFactory>::get();
-}
-
-scoped_ptr<InputMethod> MockInputMethodFactory::CreateInputMethod(
- internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget /* widget */) {
- return scoped_ptr<InputMethod>(new MockInputMethod(delegate));
-}
-
-// Shorthands
-
-scoped_ptr<InputMethod> CreateInputMethod(
- internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget) {
- return InputMethodFactory::GetInstance()->CreateInputMethod(delegate, widget);
-}
-
void SetUpInputMethodFactoryForTesting() {
- InputMethodFactory::SetInstance(MockInputMethodFactory::GetInstance());
-}
+ if (g_input_method_set_for_testing)
+ return;
-#if defined(OS_WIN)
-InputMethod* GetSharedInputMethod() {
- if (!g_shared_input_method)
- g_shared_input_method = CreateInputMethod(NULL, NULL).release();
- return g_shared_input_method;
-}
-
-namespace internal {
+ CHECK(!g_create_input_method_called)
+ << "ui::SetUpInputMethodFactoryForTesting was called after use of "
+ << "ui::CreateInputMethod. You must call "
+ << "ui::SetUpInputMethodFactoryForTesting earlier.";
-void DestroySharedInputMethod() {
- delete g_shared_input_method;
- g_shared_input_method = NULL;
+ g_input_method_set_for_testing = true;
}
-} // namespace internal
-#endif
-
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_factory.h b/chromium/ui/base/ime/input_method_factory.h
index b7386205521..3debc82cd3e 100644
--- a/chromium/ui/base/ime/input_method_factory.h
+++ b/chromium/ui/base/ime/input_method_factory.h
@@ -9,11 +9,9 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/ime/input_method_initializer.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
-template <typename T> struct DefaultSingletonTraits;
-
namespace ui {
namespace internal {
class InputMethodDelegate;
@@ -21,94 +19,13 @@ class InputMethodDelegate;
class InputMethod;
-class UI_EXPORT InputMethodFactory {
- public:
- // Returns the current active factory.
- // If no factory was set, sets the DefaultInputMethodFactory by default. Once
- // a factory was set, you cannot change the factory, and always the same
- // factory is returned.
- static InputMethodFactory* GetInstance();
-
- // Sets an InputMethodFactory to be used.
- // This function must be called at most once. |instance| is not owned by this
- // class or marked automatically as a leaky object. It's a caller's duty to
- // destroy the object or mark it as leaky.
- static void SetInstance(InputMethodFactory* instance);
-
- virtual ~InputMethodFactory() {}
-
- // Creates and returns an input method implementation.
- virtual scoped_ptr<InputMethod> CreateInputMethod(
- internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget) = 0;
-
- private:
- static void ClearInstance();
-
- friend UI_EXPORT void ShutdownInputMethod();
- friend UI_EXPORT void ShutdownInputMethodForTesting();
-};
-
-class DefaultInputMethodFactory : public InputMethodFactory {
- public:
- // For Singleton
- static DefaultInputMethodFactory* GetInstance();
-
- // Overridden from InputMethodFactory.
- virtual scoped_ptr<InputMethod> CreateInputMethod(
- internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget) OVERRIDE;
-
- private:
- DefaultInputMethodFactory() {}
-
- friend struct DefaultSingletonTraits<DefaultInputMethodFactory>;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultInputMethodFactory);
-};
-
-class MockInputMethodFactory : public InputMethodFactory {
- public:
- // For Singleton
- static MockInputMethodFactory* GetInstance();
-
- // Overridden from InputMethodFactory.
- virtual scoped_ptr<InputMethod> CreateInputMethod(
- internal::InputMethodDelegate* delegate,
- gfx::AcceleratedWidget widget) OVERRIDE;
-
- private:
- MockInputMethodFactory() {}
-
- friend struct DefaultSingletonTraits<MockInputMethodFactory>;
-
- DISALLOW_COPY_AND_ASSIGN(MockInputMethodFactory);
-};
-
-// Shorthand for
-// InputMethodFactory::GetInstance()->CreateInputMethod(delegate, widget).
-UI_EXPORT scoped_ptr<InputMethod> CreateInputMethod(
+// Creates a new instance of InputMethod and returns it.
+UI_BASE_EXPORT scoped_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget);
-// Shorthand for InputMethodFactory::SetInstance(new MockInputMethodFactory()).
-// TODO(yukishiino): Retires this shorthand, and makes ui::InitializeInputMethod
-// and ui::InitializeInputMethodForTesting set the appropriate factory.
-UI_EXPORT void SetUpInputMethodFactoryForTesting();
-
-#if defined(OS_WIN)
-// Returns a shared input method object for the platform. Caller must not
-// delete the object. Currently supported only on Windows. This method is
-// for non-Aura environment, where only one input method object is created for
-// the browser process.
-UI_EXPORT InputMethod* GetSharedInputMethod();
-
-namespace internal {
-// Destroys the shared input method object returned by GetSharedInputMethod().
-// This function must be called only from input_method_initializer.cc.
-void DestroySharedInputMethod();
-} // namespace internal
-#endif
+// Makes CreateInputMethod return a MockInputMethod.
+UI_BASE_EXPORT void SetUpInputMethodFactoryForTesting();
} // namespace ui;
diff --git a/chromium/ui/base/ime/input_method_ibus.cc b/chromium/ui/base/ime/input_method_ibus.cc
deleted file mode 100644
index 6f1213b7c8f..00000000000
--- a/chromium/ui/base/ime/input_method_ibus.cc
+++ /dev/null
@@ -1,665 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/input_method_ibus.h"
-
-#include <algorithm>
-#include <cstring>
-#include <set>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/i18n/char_iterator.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/third_party/icu/icu_utf.h"
-#include "chromeos/ime/ibus_text.h"
-#include "chromeos/ime/input_method_descriptor.h"
-#include "chromeos/ime/input_method_manager.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_code_conversion.h"
-#include "ui/events/keycodes/keyboard_code_conversion_x.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/rect.h"
-
-namespace {
-chromeos::IBusEngineHandlerInterface* GetEngine() {
- return chromeos::IBusBridge::Get()->GetCurrentEngineHandler();
-}
-} // namespace
-
-namespace ui {
-
-// InputMethodIBus implementation -----------------------------------------
-InputMethodIBus::InputMethodIBus(
- internal::InputMethodDelegate* delegate)
- : context_focused_(false),
- composing_text_(false),
- composition_changed_(false),
- suppress_next_result_(false),
- current_keyevent_id_(0),
- previous_textinput_type_(TEXT_INPUT_TYPE_NONE),
- weak_ptr_factory_(this) {
- SetDelegate(delegate);
- chromeos::IBusBridge::Get()->SetInputContextHandler(this);
-
- UpdateContextFocusState();
- OnInputMethodChanged();
-}
-
-InputMethodIBus::~InputMethodIBus() {
- AbandonAllPendingKeyEvents();
- context_focused_ = false;
- ConfirmCompositionText();
- // We are dead, so we need to ask the client to stop relying on us.
- OnInputMethodChanged();
-
- chromeos::IBusBridge::Get()->SetInputContextHandler(NULL);
-}
-
-void InputMethodIBus::OnFocus() {
- InputMethodBase::OnFocus();
- UpdateContextFocusState();
-}
-
-void InputMethodIBus::OnBlur() {
- ConfirmCompositionText();
- InputMethodBase::OnBlur();
- UpdateContextFocusState();
-}
-
-bool InputMethodIBus::OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) {
- return false;
-}
-
-void InputMethodIBus::ProcessKeyEventDone(uint32 id,
- ui::KeyEvent* event,
- bool is_handled) {
- if (pending_key_events_.find(id) == pending_key_events_.end())
- return; // Abandoned key event.
-
- DCHECK(event);
- if (event->type() == ET_KEY_PRESSED) {
- if (is_handled) {
- // IME event has a priority to be handled, so that character composer
- // should be reset.
- character_composer_.Reset();
- } else {
- // If IME does not handle key event, passes keyevent to character composer
- // to be able to compose complex characters.
- is_handled = ExecuteCharacterComposer(*event);
- }
- }
-
- if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED)
- ProcessKeyEventPostIME(*event, is_handled);
-
- // ProcessKeyEventPostIME may change the |pending_key_events_|.
- pending_key_events_.erase(id);
-}
-
-bool InputMethodIBus::DispatchKeyEvent(const ui::KeyEvent& event) {
- DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
- DCHECK(system_toplevel_window_focused());
-
- // If |context_| is not usable, then we can only dispatch the key event as is.
- // We also dispatch the key event directly if the current text input type is
- // TEXT_INPUT_TYPE_PASSWORD, to bypass the input method.
- // Note: We need to send the key event to ibus even if the |context_| is not
- // enabled, so that ibus can have a chance to enable the |context_|.
- if (!context_focused_ || !GetEngine() ||
- GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD ) {
- if (event.type() == ET_KEY_PRESSED) {
- if (ExecuteCharacterComposer(event)) {
- // Treating as PostIME event if character composer handles key event and
- // generates some IME event,
- ProcessKeyEventPostIME(event, true);
- return true;
- }
- ProcessUnfilteredKeyPressEvent(event);
- } else {
- DispatchKeyEventPostIME(event);
- }
- return true;
- }
-
- pending_key_events_.insert(current_keyevent_id_);
-
- ui::KeyEvent* copied_event = new ui::KeyEvent(event);
- GetEngine()->ProcessKeyEvent(
- event,
- base::Bind(&InputMethodIBus::ProcessKeyEventDone,
- weak_ptr_factory_.GetWeakPtr(),
- current_keyevent_id_,
- // Pass the ownership of |copied_event|.
- base::Owned(copied_event)));
-
- ++current_keyevent_id_;
-
- // We don't want to suppress the result generated by this key event, but it
- // may cause problem. See comment in ResetContext() method.
- suppress_next_result_ = false;
- return true;
-}
-
-void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) {
- if (IsTextInputClientFocused(client)) {
- ResetContext();
- UpdateContextFocusState();
- if (previous_textinput_type_ != client->GetTextInputType())
- OnInputMethodChanged();
- previous_textinput_type_ = client->GetTextInputType();
- }
- InputMethodBase::OnTextInputTypeChanged(client);
-}
-
-void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) {
- if (!context_focused_ || !IsTextInputClientFocused(client))
- return;
-
- // The current text input type should not be NONE if |context_| is focused.
- DCHECK(!IsTextInputTypeNone());
- const gfx::Rect rect = GetTextInputClient()->GetCaretBounds();
-
- gfx::Rect composition_head;
- if (!GetTextInputClient()->GetCompositionCharacterBounds(0,
- &composition_head)) {
- composition_head = rect;
- }
-
- chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
- chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
- if (!candidate_window)
- return;
- candidate_window->SetCursorBounds(rect, composition_head);
-
- gfx::Range text_range;
- gfx::Range selection_range;
- string16 surrounding_text;
- if (!GetTextInputClient()->GetTextRange(&text_range) ||
- !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text) ||
- !GetTextInputClient()->GetSelectionRange(&selection_range)) {
- previous_surrounding_text_.clear();
- previous_selection_range_ = gfx::Range::InvalidRange();
- return;
- }
-
- if (previous_selection_range_ == selection_range &&
- previous_surrounding_text_ == surrounding_text)
- return;
-
- previous_selection_range_ = selection_range;
- previous_surrounding_text_ = surrounding_text;
-
- if (!selection_range.IsValid()) {
- // TODO(nona): Ideally selection_range should not be invalid.
- // TODO(nona): If javascript changes the focus on page loading, even (0,0)
- // can not be obtained. Need investigation.
- return;
- }
-
- // Here SetSurroundingText accepts relative position of |surrounding_text|, so
- // we have to convert |selection_range| from node coordinates to
- // |surrounding_text| coordinates.
- if (!GetEngine())
- return;
- GetEngine()->SetSurroundingText(UTF16ToUTF8(surrounding_text),
- selection_range.start() - text_range.start(),
- selection_range.end() - text_range.start());
-}
-
-void InputMethodIBus::CancelComposition(const TextInputClient* client) {
- if (context_focused_ && IsTextInputClientFocused(client))
- ResetContext();
-}
-
-void InputMethodIBus::OnInputLocaleChanged() {
- // Not supported.
-}
-
-std::string InputMethodIBus::GetInputLocale() {
- // Not supported.
- return "";
-}
-
-base::i18n::TextDirection InputMethodIBus::GetInputTextDirection() {
- // Not supported.
- return base::i18n::UNKNOWN_DIRECTION;
-}
-
-bool InputMethodIBus::IsActive() {
- return true;
-}
-
-bool InputMethodIBus::IsCandidatePopupOpen() const {
- // TODO(yukishiino): Implement this method.
- return false;
-}
-
-void InputMethodIBus::OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) {
- ConfirmCompositionText();
-}
-
-void InputMethodIBus::OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* 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);
-
- UpdateContextFocusState();
- // Force to update caret bounds, in case the client thinks that the caret
- // bounds has not changed.
- OnCaretBoundsChanged(focused);
-}
-
-void InputMethodIBus::ConfirmCompositionText() {
- TextInputClient* client = GetTextInputClient();
- if (client && client->HasCompositionText())
- client->ConfirmCompositionText();
-
- ResetContext();
-}
-
-void InputMethodIBus::ResetContext() {
- if (!context_focused_ || !GetTextInputClient())
- return;
-
- DCHECK(system_toplevel_window_focused());
-
- // Because ibus runs in asynchronous mode, the input method may still send us
- // results after sending out the reset request, so we use a flag to discard
- // all results generated by previous key events. But because ibus does not
- // have a mechanism to identify each key event and corresponding results, this
- // approach will not work for some corner cases. For example if the user types
- // very fast, then the next key event may come in before the |context_| is
- // really reset. Then we actually cannot know whether or not the next
- // result should be discard.
- suppress_next_result_ = true;
-
- composition_.Clear();
- result_text_.clear();
- composing_text_ = false;
- composition_changed_ = false;
-
- // We need to abandon all pending key events, but as above comment says, there
- // is no reliable way to abandon all results generated by these abandoned key
- // events.
- AbandonAllPendingKeyEvents();
-
- // This function runs asynchronously.
- // Note: some input method engines may not support reset method, such as
- // ibus-anthy. But as we control all input method engines by ourselves, we can
- // make sure that all of the engines we are using support it correctly.
- if (GetEngine())
- GetEngine()->Reset();
-
- character_composer_.Reset();
-}
-
-void InputMethodIBus::UpdateContextFocusState() {
- const bool old_context_focused = context_focused_;
- const TextInputType current_text_input_type = GetTextInputType();
- // Use switch here in case we are going to add more text input types.
- switch (current_text_input_type) {
- case TEXT_INPUT_TYPE_NONE:
- case TEXT_INPUT_TYPE_PASSWORD:
- context_focused_ = false;
- break;
- default:
- context_focused_ = true;
- break;
- }
-
- // Propagate the focus event to the candidate window handler which also
- // manages the input method mode indicator.
- chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
- chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
- if (candidate_window)
- candidate_window->FocusStateChanged(context_focused_);
-
- if (!GetEngine())
- return;
-
- // We only focus in |context_| when the focus is in a normal textfield.
- // Even if focus is not changed, a text input type change causes a focus
- // blink.
- // ibus_input_context_focus_{in|out}() run asynchronously.
- bool input_type_change =
- (current_text_input_type != previous_textinput_type_);
- if (old_context_focused && (!context_focused_ || input_type_change))
- GetEngine()->FocusOut();
- if (context_focused_ && (!old_context_focused || input_type_change)) {
- chromeos::IBusEngineHandlerInterface::InputContext context(
- current_text_input_type, GetTextInputMode());
- GetEngine()->FocusIn(context);
- OnCaretBoundsChanged(GetTextInputClient());
- }
-}
-
-void InputMethodIBus::ProcessKeyEventPostIME(
- const ui::KeyEvent& event,
- bool handled) {
- TextInputClient* client = GetTextInputClient();
- if (!client) {
- // As ibus works asynchronously, there is a chance that the focused client
- // loses focus before this method gets called.
- DispatchKeyEventPostIME(event);
- return;
- }
-
- if (event.type() == ET_KEY_PRESSED && handled)
- ProcessFilteredKeyPressEvent(event);
-
- // In case the focus was changed by the key event. The |context_| should have
- // been reset when the focused window changed.
- if (client != GetTextInputClient())
- return;
-
- if (HasInputMethodResult())
- ProcessInputMethodResult(event, handled);
-
- // In case the focus was changed when sending input method results to the
- // focused window.
- if (client != GetTextInputClient())
- return;
-
- if (event.type() == ET_KEY_PRESSED && !handled)
- ProcessUnfilteredKeyPressEvent(event);
- else if (event.type() == ET_KEY_RELEASED)
- DispatchKeyEventPostIME(event);
-}
-
-void InputMethodIBus::ProcessFilteredKeyPressEvent(const ui::KeyEvent& event) {
- if (NeedInsertChar()) {
- DispatchKeyEventPostIME(event);
- } else {
- const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
- VKEY_PROCESSKEY,
- event.flags(),
- false); // is_char
- DispatchKeyEventPostIME(fabricated_event);
- }
-}
-
-void InputMethodIBus::ProcessUnfilteredKeyPressEvent(
- const ui::KeyEvent& event) {
- const TextInputClient* prev_client = GetTextInputClient();
- DispatchKeyEventPostIME(event);
-
- // We shouldn't dispatch the character anymore if the key event dispatch
- // caused focus change. For example, in the following scenario,
- // 1. visit a web page which has a <textarea>.
- // 2. click Omnibox.
- // 3. enable Korean IME, press A, then press Tab to move the focus to the web
- // page.
- // We should return here not to send the Tab key event to RWHV.
- TextInputClient* client = GetTextInputClient();
- if (!client || client != prev_client)
- return;
-
- // If a key event was not filtered by |context_| and |character_composer_|,
- // then it means the key event didn't generate any result text. So we need
- // to send corresponding character to the focused text input client.
- const uint32 event_flags = event.flags();
- uint16 ch = 0;
- if (event.HasNativeEvent()) {
- const base::NativeEvent& native_event = event.native_event();
-
- if (!(event_flags & ui::EF_CONTROL_DOWN))
- ch = ui::GetCharacterFromXEvent(native_event);
- if (!ch) {
- ch = ui::GetCharacterFromKeyCode(
- ui::KeyboardCodeFromNative(native_event), event_flags);
- }
- } else {
- ch = ui::GetCharacterFromKeyCode(event.key_code(), event_flags);
- }
-
- if (ch)
- client->InsertChar(ch, event_flags);
-}
-
-void InputMethodIBus::ProcessInputMethodResult(const ui::KeyEvent& event,
- bool handled) {
- TextInputClient* client = GetTextInputClient();
- DCHECK(client);
-
- if (result_text_.length()) {
- if (handled && NeedInsertChar()) {
- for (string16::const_iterator i = result_text_.begin();
- i != result_text_.end(); ++i) {
- client->InsertChar(*i, event.flags());
- }
- } else {
- client->InsertText(result_text_);
- composing_text_ = false;
- }
- }
-
- if (composition_changed_ && !IsTextInputTypeNone()) {
- if (composition_.text.length()) {
- composing_text_ = true;
- client->SetCompositionText(composition_);
- } else if (result_text_.empty()) {
- client->ClearCompositionText();
- }
- }
-
- // We should not clear composition text here, as it may belong to the next
- // composition session.
- result_text_.clear();
- composition_changed_ = false;
-}
-
-bool InputMethodIBus::NeedInsertChar() const {
- return GetTextInputClient() &&
- (IsTextInputTypeNone() ||
- (!composing_text_ && result_text_.length() == 1));
-}
-
-bool InputMethodIBus::HasInputMethodResult() const {
- return result_text_.length() || composition_changed_;
-}
-
-void InputMethodIBus::AbandonAllPendingKeyEvents() {
- pending_key_events_.clear();
-}
-
-void InputMethodIBus::CommitText(const std::string& text) {
- if (suppress_next_result_ || text.empty())
- return;
-
- // We need to receive input method result even if the text input type is
- // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct
- // character for each key event to the focused text input client.
- if (!GetTextInputClient())
- return;
-
- const string16 utf16_text = UTF8ToUTF16(text);
- if (utf16_text.empty())
- return;
-
- // Append the text to the buffer, because commit signal might be fired
- // multiple times when processing a key event.
- result_text_.append(utf16_text);
-
- // If we are not handling key event, do not bother sending text result if the
- // focused text input client does not support text input.
- if (pending_key_events_.empty() && !IsTextInputTypeNone()) {
- GetTextInputClient()->InsertText(utf16_text);
- result_text_.clear();
- }
-}
-
-void InputMethodIBus::UpdatePreeditText(const chromeos::IBusText& text,
- uint32 cursor_pos,
- bool visible) {
- if (suppress_next_result_ || IsTextInputTypeNone())
- return;
-
- if (!CanComposeInline()) {
- chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
- chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
- if (candidate_window)
- candidate_window->UpdatePreeditText(text.text(), cursor_pos, visible);
- }
-
- // |visible| argument is very confusing. For example, what's the correct
- // behavior when:
- // 1. OnUpdatePreeditText() is called with a text and visible == false, then
- // 2. OnShowPreeditText() is called afterwards.
- //
- // If it's only for clearing the current preedit text, then why not just use
- // OnHidePreeditText()?
- if (!visible) {
- HidePreeditText();
- return;
- }
-
- ExtractCompositionText(text, cursor_pos, &composition_);
-
- composition_changed_ = true;
-
- // In case OnShowPreeditText() is not called.
- if (composition_.text.length())
- composing_text_ = true;
-
- // If we receive a composition text without pending key event, then we need to
- // send it to the focused text input client directly.
- if (pending_key_events_.empty()) {
- GetTextInputClient()->SetCompositionText(composition_);
- composition_changed_ = false;
- composition_.Clear();
- }
-}
-
-void InputMethodIBus::HidePreeditText() {
- if (composition_.text.empty() || IsTextInputTypeNone())
- return;
-
- // Intentionally leaves |composing_text_| unchanged.
- composition_changed_ = true;
- composition_.Clear();
-
- if (pending_key_events_.empty()) {
- TextInputClient* client = GetTextInputClient();
- if (client && client->HasCompositionText())
- client->ClearCompositionText();
- composition_changed_ = false;
- }
-}
-
-void InputMethodIBus::DeleteSurroundingText(int32 offset, uint32 length) {
- if (!composition_.text.empty())
- return; // do nothing if there is ongoing composition.
- if (offset < 0 && static_cast<uint32>(-1 * offset) != length)
- return; // only preceding text can be deletable.
- if (GetTextInputClient())
- GetTextInputClient()->ExtendSelectionAndDelete(length, 0U);
-}
-
-bool InputMethodIBus::ExecuteCharacterComposer(const ui::KeyEvent& event) {
- bool consumed = character_composer_.FilterKeyPress(event);
-
- suppress_next_result_ = false;
- chromeos::IBusText preedit;
- preedit.set_text(
- UTF16ToUTF8(character_composer_.preedit_string()));
- UpdatePreeditText(preedit, preedit.text().size(),
- !preedit.text().empty());
- std::string commit_text =
- UTF16ToUTF8(character_composer_.composed_character());
- if (!commit_text.empty()) {
- CommitText(commit_text);
- }
- return consumed;
-}
-
-void InputMethodIBus::ExtractCompositionText(
- const chromeos::IBusText& text,
- uint32 cursor_position,
- CompositionText* out_composition) const {
- out_composition->Clear();
- out_composition->text = UTF8ToUTF16(text.text());
-
- if (out_composition->text.empty())
- return;
-
- // ibus uses character index for cursor position and attribute range, but we
- // use char16 offset for them. So we need to do conversion here.
- std::vector<size_t> char16_offsets;
- size_t length = out_composition->text.length();
- base::i18n::UTF16CharIterator char_iterator(&out_composition->text);
- do {
- char16_offsets.push_back(char_iterator.array_pos());
- } while (char_iterator.Advance());
-
- // The text length in Unicode characters.
- uint32 char_length = static_cast<uint32>(char16_offsets.size());
- // Make sure we can convert the value of |char_length| as well.
- char16_offsets.push_back(length);
-
- size_t cursor_offset =
- char16_offsets[std::min(char_length, cursor_position)];
-
- out_composition->selection = gfx::Range(cursor_offset);
-
- const std::vector<chromeos::IBusText::UnderlineAttribute>&
- underline_attributes = text.underline_attributes();
- if (!underline_attributes.empty()) {
- for (size_t i = 0; i < underline_attributes.size(); ++i) {
- const uint32 start = underline_attributes[i].start_index;
- const uint32 end = underline_attributes[i].end_index;
- if (start >= end)
- continue;
- CompositionUnderline underline(
- char16_offsets[start], char16_offsets[end],
- SK_ColorBLACK, false /* thick */);
- if (underline_attributes[i].type ==
- chromeos::IBusText::IBUS_TEXT_UNDERLINE_DOUBLE)
- underline.thick = true;
- else if (underline_attributes[i].type ==
- chromeos::IBusText::IBUS_TEXT_UNDERLINE_ERROR)
- underline.color = SK_ColorRED;
- out_composition->underlines.push_back(underline);
- }
- }
-
- DCHECK(text.selection_start() <= text.selection_end());
- if (text.selection_start() < text.selection_end()) {
- const uint32 start = text.selection_start();
- const uint32 end = text.selection_end();
- CompositionUnderline underline(
- char16_offsets[start], char16_offsets[end],
- SK_ColorBLACK, true /* thick */);
- out_composition->underlines.push_back(underline);
-
- // 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.
- if (underline.start_offset == cursor_offset) {
- out_composition->selection.set_start(underline.end_offset);
- out_composition->selection.set_end(cursor_offset);
- } else if (underline.end_offset == cursor_offset) {
- out_composition->selection.set_start(underline.start_offset);
- out_composition->selection.set_end(cursor_offset);
- }
- }
-
- // Use a black thin underline by default.
- if (out_composition->underlines.empty()) {
- out_composition->underlines.push_back(CompositionUnderline(
- 0, length, SK_ColorBLACK, false /* thick */));
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_ibus.h b/chromium/ui/base/ime/input_method_ibus.h
deleted file mode 100644
index 01f958db16d..00000000000
--- a/chromium/ui/base/ime/input_method_ibus.h
+++ /dev/null
@@ -1,170 +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_IME_INPUT_METHOD_IBUS_H_
-#define UI_BASE_IME_INPUT_METHOD_IBUS_H_
-
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/base/ime/chromeos/character_composer.h"
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/input_method_base.h"
-
-namespace dbus {
-class ObjectPath;
-}
-namespace chromeos {
-namespace ibus {
-class IBusText;
-} // namespace ibus
-} // namespace chromeos
-
-namespace ui {
-
-// A ui::InputMethod implementation based on IBus.
-class UI_EXPORT InputMethodIBus
- : public InputMethodBase,
- public chromeos::IBusInputContextHandlerInterface {
- public:
- explicit InputMethodIBus(internal::InputMethodDelegate* delegate);
- virtual ~InputMethodIBus();
-
- // Overridden from InputMethod:
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) OVERRIDE;
- virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE;
- virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
- virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
- virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
- virtual void OnInputLocaleChanged() OVERRIDE;
- virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
- virtual bool IsActive() OVERRIDE;
- virtual bool IsCandidatePopupOpen() const OVERRIDE;
-
- protected:
- // Converts |text| into CompositionText.
- void ExtractCompositionText(const chromeos::IBusText& text,
- uint32 cursor_position,
- CompositionText* out_composition) const;
-
- // Process a key returned from the input method.
- virtual void ProcessKeyEventPostIME(const ui::KeyEvent& event,
- bool handled);
-
- // Resets context and abandon all pending results and key events.
- void ResetContext();
-
- private:
- class PendingKeyEvent;
-
- // Overridden from InputMethodBase:
- virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) OVERRIDE;
- virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) OVERRIDE;
-
- // Asks the client to confirm current composition text.
- void ConfirmCompositionText();
-
- // Checks the availability of focused text input client and update focus
- // state.
- void UpdateContextFocusState();
-
- // Processes a key event that was already filtered by the input method.
- // A VKEY_PROCESSKEY may be dispatched to the focused View.
- void ProcessFilteredKeyPressEvent(const ui::KeyEvent& event);
-
- // Processes a key event that was not filtered by the input method.
- void ProcessUnfilteredKeyPressEvent(const ui::KeyEvent& event);
-
- // Sends input method result caused by the given key event to the focused text
- // input client.
- void ProcessInputMethodResult(const ui::KeyEvent& event, bool filtered);
-
- // Checks if the pending input method result needs inserting into the focused
- // text input client as a single character.
- bool NeedInsertChar() const;
-
- // Checks if there is pending input method result.
- bool HasInputMethodResult() const;
-
- // Abandons all pending key events. It usually happends when we lose keyboard
- // focus, the text input type is changed or we are destroyed.
- void AbandonAllPendingKeyEvents();
-
- // Passes keyevent and executes character composition if necessary. Returns
- // true if character composer comsumes key event.
- bool ExecuteCharacterComposer(const ui::KeyEvent& event);
-
- // chromeos::IBusInputContextHandlerInterface overrides:
- virtual void CommitText(const std::string& text) OVERRIDE;
- virtual void UpdatePreeditText(const chromeos::IBusText& text,
- uint32 cursor_pos,
- bool visible) OVERRIDE;
- virtual void DeleteSurroundingText(int32 offset, uint32 length) OVERRIDE;
-
- // Hides the composition text.
- void HidePreeditText();
-
- // Callback function for IBusEngineHandlerInterface::ProcessKeyEvent.
- void ProcessKeyEventDone(uint32 id, ui::KeyEvent* event, bool is_handled);
-
- // All pending key events. Note: we do not own these object, we just save
- // pointers to these object so that we can abandon them when necessary.
- // They will be deleted in ProcessKeyEventDone().
- std::set<uint32> pending_key_events_;
-
- // Pending composition text generated by the current pending key event.
- // It'll be sent to the focused text input client as soon as we receive the
- // processing result of the pending key event.
- CompositionText composition_;
-
- // Pending result text generated by the current pending key event.
- // It'll be sent to the focused text input client as soon as we receive the
- // processing result of the pending key event.
- string16 result_text_;
-
- string16 previous_surrounding_text_;
- gfx::Range previous_selection_range_;
-
- // Indicates if input context is focused or not.
- bool context_focused_;
-
- // Indicates if there is an ongoing composition text.
- bool composing_text_;
-
- // Indicates if the composition text is changed or deleted.
- bool composition_changed_;
-
- // If it's true then all input method result received before the next key
- // event will be discarded.
- bool suppress_next_result_;
-
- // The latest id of key event.
- uint32 current_keyevent_id_;
-
- // An object to compose a character from a sequence of key presses
- // including dead key etc.
- CharacterComposer character_composer_;
-
- TextInputType previous_textinput_type_;
-
- // Used for making callbacks.
- base::WeakPtrFactory<InputMethodIBus> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodIBus);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_IME_INPUT_METHOD_IBUS_H_
diff --git a/chromium/ui/base/ime/input_method_ibus_unittest.cc b/chromium/ui/base/ime/input_method_ibus_unittest.cc
deleted file mode 100644
index e381aa4fb53..00000000000
--- a/chromium/ui/base/ime/input_method_ibus_unittest.cc
+++ /dev/null
@@ -1,1027 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <X11/Xlib.h>
-#undef Bool
-#undef FocusIn
-#undef FocusOut
-#undef None
-
-#include <cstring>
-
-#include "base/i18n/char_iterator.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/ime/ibus_keymap.h"
-#include "chromeos/ime/ibus_text.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
-#include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/base/ime/input_method_ibus.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/event.h"
-#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/gfx/rect.h"
-
-namespace ui {
-namespace {
-typedef chromeos::IBusEngineHandlerInterface::KeyEventDoneCallback
- KeyEventCallback;
-
-uint32 GetOffsetInUTF16(const std::string& utf8_string, uint32 utf8_offset) {
- string16 utf16_string = UTF8ToUTF16(utf8_string);
- DCHECK_LT(utf8_offset, utf16_string.size());
- base::i18n::UTF16CharIterator char_iterator(&utf16_string);
- for (size_t i = 0; i < utf8_offset; ++i)
- char_iterator.Advance();
- return char_iterator.array_pos();
-}
-
-bool IsEqualXKeyEvent(const XEvent& e1, const XEvent& e2) {
- if ((e1.type == KeyPress && e2.type == KeyPress) ||
- (e1.type == KeyRelease && e2.type == KeyRelease)) {
- return !std::memcmp(&e1.xkey, &e2.xkey, sizeof(XKeyEvent));
- }
- return false;
-}
-
-enum KeyEventHandlerBehavior {
- KEYEVENT_CONSUME,
- KEYEVENT_NOT_CONSUME,
-};
-
-} // namespace
-
-
-class TestableInputMethodIBus : public InputMethodIBus {
- public:
- explicit TestableInputMethodIBus(internal::InputMethodDelegate* delegate)
- : InputMethodIBus(delegate),
- process_key_event_post_ime_call_count_(0) {
- }
-
- struct ProcessKeyEventPostIMEArgs {
- ProcessKeyEventPostIMEArgs() : event(NULL), handled(false) {}
- const ui::KeyEvent* event;
- bool handled;
- };
-
- // InputMethodIBus override.
- virtual void ProcessKeyEventPostIME(const ui::KeyEvent& key_event,
- bool handled) OVERRIDE {
- process_key_event_post_ime_args_.event = &key_event;
- process_key_event_post_ime_args_.handled = handled;
- ++process_key_event_post_ime_call_count_;
- }
-
- void ResetCallCount() {
- process_key_event_post_ime_call_count_ = 0;
- }
-
- const ProcessKeyEventPostIMEArgs& process_key_event_post_ime_args() const {
- return process_key_event_post_ime_args_;
- }
-
- int process_key_event_post_ime_call_count() const {
- return process_key_event_post_ime_call_count_;
- }
-
- // Change access rights for testing.
- using InputMethodIBus::ExtractCompositionText;
- using InputMethodIBus::ResetContext;
-
- private:
- ProcessKeyEventPostIMEArgs process_key_event_post_ime_args_;
- int process_key_event_post_ime_call_count_;
-};
-
-class SynchronousKeyEventHandler {
- public:
- SynchronousKeyEventHandler(uint32 expected_keyval,
- uint32 expected_keycode,
- uint32 expected_state,
- KeyEventHandlerBehavior behavior)
- : expected_keyval_(expected_keyval),
- expected_keycode_(expected_keycode),
- expected_state_(expected_state),
- behavior_(behavior) {}
-
- virtual ~SynchronousKeyEventHandler() {}
-
- void Run(uint32 keyval,
- uint32 keycode,
- uint32 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 expected_keyval_;
- const uint32 expected_keycode_;
- const uint32 expected_state_;
- const KeyEventHandlerBehavior behavior_;
-
- DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler);
-};
-
-class AsynchronousKeyEventHandler {
- public:
- AsynchronousKeyEventHandler(uint32 expected_keyval,
- uint32 expected_keycode,
- uint32 expected_state)
- : expected_keyval_(expected_keyval),
- expected_keycode_(expected_keycode),
- expected_state_(expected_state) {}
-
- virtual ~AsynchronousKeyEventHandler() {}
-
- void Run(uint32 keyval,
- uint32 keycode,
- uint32 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 expected_keyval_;
- const uint32 expected_keycode_;
- const uint32 expected_state_;
- KeyEventCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler);
-};
-
-class SetSurroundingTextVerifier {
- public:
- SetSurroundingTextVerifier(const std::string& expected_surrounding_text,
- uint32 expected_cursor_position,
- uint32 expected_anchor_position)
- : expected_surrounding_text_(expected_surrounding_text),
- expected_cursor_position_(expected_cursor_position),
- expected_anchor_position_(expected_anchor_position) {}
-
- void Verify(const std::string& text,
- uint32 cursor_pos,
- uint32 anchor_pos) {
- EXPECT_EQ(expected_surrounding_text_, text);
- EXPECT_EQ(expected_cursor_position_, cursor_pos);
- EXPECT_EQ(expected_anchor_position_, anchor_pos);
- }
-
- private:
- const std::string expected_surrounding_text_;
- const uint32 expected_cursor_position_;
- const uint32 expected_anchor_position_;
-
- DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier);
-};
-
-class InputMethodIBusTest : public internal::InputMethodDelegate,
- public testing::Test,
- public TextInputClient {
- public:
- InputMethodIBusTest() {
- ResetFlags();
- }
-
- virtual ~InputMethodIBusTest() {
- }
-
- // testing::Test overrides:
- virtual void SetUp() OVERRIDE {
- chromeos::IBusBridge::Initialize();
-
- mock_ime_engine_handler_.reset(
- new chromeos::MockIMEEngineHandler());
- chromeos::IBusBridge::Get()->SetCurrentEngineHandler(
- mock_ime_engine_handler_.get());
-
- mock_ime_candidate_window_handler_.reset(
- new chromeos::MockIMECandidateWindowHandler());
- chromeos::IBusBridge::Get()->SetCandidateWindowHandler(
- mock_ime_candidate_window_handler_.get());
-
- ime_.reset(new TestableInputMethodIBus(this));
- ime_->SetFocusedTextInputClient(this);
- }
-
- virtual void TearDown() OVERRIDE {
- if (ime_.get())
- ime_->SetFocusedTextInputClient(NULL);
- ime_.reset();
- chromeos::IBusBridge::Get()->SetCurrentEngineHandler(NULL);
- chromeos::IBusBridge::Get()->SetCandidateWindowHandler(NULL);
- mock_ime_engine_handler_.reset();
- mock_ime_candidate_window_handler_.reset();
- chromeos::IBusBridge::Shutdown();
- }
-
- // ui::internal::InputMethodDelegate overrides:
- virtual bool DispatchKeyEventPostIME(
- const base::NativeEvent& native_key_event) OVERRIDE {
- dispatched_native_event_ = native_key_event;
- return false;
- }
- virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) OVERRIDE {
- dispatched_fabricated_event_type_ = type;
- dispatched_fabricated_event_key_code_ = key_code;
- dispatched_fabricated_event_flags_ = flags;
- return false;
- }
-
- // ui::TextInputClient overrides:
- virtual void SetCompositionText(
- const CompositionText& composition) OVERRIDE {
- composition_text_ = composition;
- }
- virtual void ConfirmCompositionText() OVERRIDE {
- confirmed_text_ = composition_text_;
- composition_text_.Clear();
- }
- virtual void ClearCompositionText() OVERRIDE {
- composition_text_.Clear();
- }
- virtual void InsertText(const string16& text) OVERRIDE {
- inserted_text_ = text;
- }
- virtual void InsertChar(char16 ch, int flags) OVERRIDE {
- inserted_char_ = ch;
- inserted_char_flags_ = flags;
- }
- virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
- return static_cast<gfx::NativeWindow>(NULL);
- }
- virtual TextInputType GetTextInputType() const OVERRIDE {
- return input_type_;
- }
- virtual TextInputMode GetTextInputMode() const OVERRIDE {
- return input_mode_;
- }
- virtual bool CanComposeInline() const OVERRIDE {
- return can_compose_inline_;
- }
- virtual gfx::Rect GetCaretBounds() const OVERRIDE {
- return caret_bounds_;
- }
- virtual bool GetCompositionCharacterBounds(uint32 index,
- gfx::Rect* rect) const OVERRIDE {
- return false;
- }
- virtual bool HasCompositionText() const OVERRIDE {
- CompositionText empty;
- return composition_text_ != empty;
- }
- virtual bool GetTextRange(gfx::Range* range) const OVERRIDE {
- *range = text_range_;
- return true;
- }
- virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE {
- return false;
- }
- virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE {
- *range = selection_range_;
- return true;
- }
-
- virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE { return false; }
- virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; }
- virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE {
- *text = surrounding_text_.substr(range.GetMin(), range.length());
- return true;
- }
- virtual void OnInputMethodChanged() OVERRIDE {
- ++on_input_method_changed_call_count_;
- }
- virtual bool ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) OVERRIDE { return false; }
- virtual void ExtendSelectionAndDelete(size_t before,
- size_t after) OVERRIDE { }
- virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE { }
- virtual void OnCandidateWindowShown() OVERRIDE { }
- virtual void OnCandidateWindowUpdated() OVERRIDE { }
- virtual void OnCandidateWindowHidden() OVERRIDE { }
-
- bool HasNativeEvent() const {
- base::NativeEvent empty;
- std::memset(&empty, 0, sizeof(empty));
- return !!std::memcmp(&dispatched_native_event_,
- &empty,
- sizeof(dispatched_native_event_));
- }
-
- void ResetFlags() {
- std::memset(&dispatched_native_event_, 0, sizeof(dispatched_native_event_));
- DCHECK(!HasNativeEvent());
- dispatched_fabricated_event_type_ = ET_UNKNOWN;
- dispatched_fabricated_event_key_code_ = VKEY_UNKNOWN;
- dispatched_fabricated_event_flags_ = 0;
-
- composition_text_.Clear();
- confirmed_text_.Clear();
- inserted_text_.clear();
- inserted_char_ = 0;
- inserted_char_flags_ = 0;
- on_input_method_changed_call_count_ = 0;
-
- input_type_ = TEXT_INPUT_TYPE_NONE;
- input_mode_ = TEXT_INPUT_MODE_DEFAULT;
- can_compose_inline_ = true;
- caret_bounds_ = gfx::Rect();
- }
-
- scoped_ptr<TestableInputMethodIBus> ime_;
-
- // Variables for remembering the parameters that are passed to
- // ui::internal::InputMethodDelegate functions.
- base::NativeEvent dispatched_native_event_;
- ui::EventType dispatched_fabricated_event_type_;
- ui::KeyboardCode dispatched_fabricated_event_key_code_;
- int dispatched_fabricated_event_flags_;
-
- // Variables for remembering the parameters that are passed to
- // ui::TextInputClient functions.
- CompositionText composition_text_;
- CompositionText confirmed_text_;
- string16 inserted_text_;
- char16 inserted_char_;
- unsigned int on_input_method_changed_call_count_;
- int inserted_char_flags_;
-
- // Variables that will be returned from the ui::TextInputClient functions.
- TextInputType input_type_;
- TextInputMode input_mode_;
- bool can_compose_inline_;
- gfx::Rect caret_bounds_;
- gfx::Range text_range_;
- gfx::Range selection_range_;
- string16 surrounding_text_;
-
- scoped_ptr<chromeos::MockIMEEngineHandler> mock_ime_engine_handler_;
- scoped_ptr<chromeos::MockIMECandidateWindowHandler>
- mock_ime_candidate_window_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodIBusTest);
-};
-
-// Tests public APIs in ui::InputMethod first.
-
-TEST_F(InputMethodIBusTest, GetInputLocale) {
- // ui::InputMethodIBus does not support the API.
- ime_->Init(true);
- EXPECT_EQ("", ime_->GetInputLocale());
-}
-
-TEST_F(InputMethodIBusTest, GetInputTextDirection) {
- // ui::InputMethodIBus does not support the API.
- ime_->Init(true);
- EXPECT_EQ(base::i18n::UNKNOWN_DIRECTION, ime_->GetInputTextDirection());
-}
-
-TEST_F(InputMethodIBusTest, IsActive) {
- ime_->Init(true);
- // ui::InputMethodIBus always returns true.
- EXPECT_TRUE(ime_->IsActive());
-}
-
-TEST_F(InputMethodIBusTest, GetInputTextType) {
- ime_->Init(true);
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, ime_->GetTextInputType());
-}
-
-TEST_F(InputMethodIBusTest, CanComposeInline) {
- ime_->Init(true);
- EXPECT_TRUE(ime_->CanComposeInline());
- can_compose_inline_ = false;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_FALSE(ime_->CanComposeInline());
-}
-
-TEST_F(InputMethodIBusTest, GetTextInputClient) {
- ime_->Init(true);
- EXPECT_EQ(this, ime_->GetTextInputClient());
- ime_->SetFocusedTextInputClient(NULL);
- EXPECT_EQ(NULL, ime_->GetTextInputClient());
-}
-
-TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedClient) {
- ime_->Init(true);
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
- ime_->SetFocusedTextInputClient(NULL);
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- // The OnTextInputTypeChanged() call above should be ignored since |this| is
- // not the current focused client.
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
-
- ime_->SetFocusedTextInputClient(this);
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
-}
-
-TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedWindow) {
- ime_->Init(true);
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
- ime_->OnBlur();
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- // The OnTextInputTypeChanged() call above should be ignored since the top-
- // level window which the ime_ is attached to is not currently focused.
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
-
- ime_->OnFocus();
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
-}
-
-TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedWindow2) {
- ime_->Init(false); // the top-level is initially unfocused.
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType());
-
- ime_->OnFocus();
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType());
-}
-
-// Confirm that IBusClient::FocusIn is called on "connected" if input_type_ is
-// TEXT.
-TEST_F(InputMethodIBusTest, FocusIn_Text) {
- ime_->Init(true);
- // A context shouldn't be created since the daemon is not running.
- EXPECT_EQ(0U, on_input_method_changed_call_count_);
- // Click a text input form.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
- // Since a form has focus, IBusClient::FocusIn() should be called.
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(
- 1,
- mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
- // ui::TextInputClient::OnInputMethodChanged() should be called when
- // ui::InputMethodIBus connects/disconnects to/from ibus-daemon and the
- // current text input type is not NONE.
- EXPECT_EQ(1U, on_input_method_changed_call_count_);
-}
-
-// Confirm that IBusClient::FocusIn is NOT called on "connected" if input_type_
-// is PASSWORD.
-TEST_F(InputMethodIBusTest, FocusIn_Password) {
- ime_->Init(true);
- EXPECT_EQ(0U, on_input_method_changed_call_count_);
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- // Since a form has focus, IBusClient::FocusIn() should NOT be called.
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(1U, on_input_method_changed_call_count_);
-}
-
-// Confirm that IBusClient::FocusOut is called as expected.
-TEST_F(InputMethodIBusTest, FocusOut_None) {
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->Init(true);
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
- input_type_ = TEXT_INPUT_TYPE_NONE;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
-}
-
-// Confirm that IBusClient::FocusOut is called as expected.
-TEST_F(InputMethodIBusTest, FocusOut_Password) {
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->Init(true);
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
- input_type_ = TEXT_INPUT_TYPE_PASSWORD;
- ime_->OnTextInputTypeChanged(this);
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
-}
-
-// FocusIn/FocusOut scenario test
-TEST_F(InputMethodIBusTest, Focus_Scenario) {
- ime_->Init(true);
- // Confirm that both FocusIn and FocusOut are NOT called.
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
- EXPECT_EQ(TEXT_INPUT_TYPE_NONE,
- mock_ime_engine_handler_->last_text_input_context().type);
- EXPECT_EQ(TEXT_INPUT_MODE_DEFAULT,
- mock_ime_engine_handler_->last_text_input_context().mode);
-
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- input_mode_ = TEXT_INPUT_MODE_LATIN;
- ime_->OnTextInputTypeChanged(this);
- // Confirm that only FocusIn is called, the TextInputType is TEXT and the
- // TextInputMode is LATIN..
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
- EXPECT_EQ(TEXT_INPUT_TYPE_TEXT,
- mock_ime_engine_handler_->last_text_input_context().type);
- EXPECT_EQ(TEXT_INPUT_MODE_LATIN,
- mock_ime_engine_handler_->last_text_input_context().mode);
-
- input_mode_ = TEXT_INPUT_MODE_KANA;
- ime_->OnTextInputTypeChanged(this);
- // Confirm that both FocusIn and FocusOut are NOT called.
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count());
- EXPECT_EQ(TEXT_INPUT_TYPE_TEXT,
- mock_ime_engine_handler_->last_text_input_context().type);
- EXPECT_EQ(TEXT_INPUT_MODE_LATIN,
- mock_ime_engine_handler_->last_text_input_context().mode);
-
- input_type_ = TEXT_INPUT_TYPE_URL;
- ime_->OnTextInputTypeChanged(this);
- // Confirm that both FocusIn and FocusOut are called and the TextInputType is
- // URL.
- EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count());
- EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count());
- EXPECT_EQ(TEXT_INPUT_TYPE_URL,
- mock_ime_engine_handler_->last_text_input_context().type);
- EXPECT_EQ(TEXT_INPUT_MODE_KANA,
- mock_ime_engine_handler_->last_text_input_context().mode);
-}
-
-// Test if the new |caret_bounds_| is correctly sent to ibus-daemon.
-TEST_F(InputMethodIBusTest, OnCaretBoundsChanged) {
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->Init(true);
- EXPECT_EQ(
- 1,
- mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
- caret_bounds_ = gfx::Rect(1, 2, 3, 4);
- ime_->OnCaretBoundsChanged(this);
- EXPECT_EQ(
- 2,
- mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
- caret_bounds_ = gfx::Rect(0, 2, 3, 4);
- ime_->OnCaretBoundsChanged(this);
- EXPECT_EQ(
- 3,
- mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
- caret_bounds_ = gfx::Rect(0, 2, 3, 4); // unchanged
- ime_->OnCaretBoundsChanged(this);
- // Current InputMethodIBus implementation performs the IPC regardless of the
- // bounds are changed or not.
- EXPECT_EQ(
- 4,
- mock_ime_candidate_window_handler_->set_cursor_bounds_call_count());
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_NoAttribute) {
- const char kSampleText[] = "Sample Text";
- const uint32 kCursorPos = 2UL;
-
- const string16 utf16_string = UTF8ToUTF16(kSampleText);
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- // If there is no selection, |selection| represents cursor position.
- EXPECT_EQ(kCursorPos, composition_text.selection.start());
- EXPECT_EQ(kCursorPos, composition_text.selection.end());
- // If there is no underline, |underlines| contains one underline and it is
- // whole text underline.
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(0UL, composition_text.underlines[0].start_offset);
- EXPECT_EQ(utf16_string.size(), composition_text.underlines[0].end_offset);
- EXPECT_FALSE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_SingleUnderline) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 2UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- chromeos::IBusText::UnderlineAttribute underline;
- underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_SINGLE;
- underline.start_index = 1UL;
- underline.end_index = 4UL;
- ibus_text.mutable_underline_attributes()->push_back(underline);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- // If there is no selection, |selection| represents cursor position.
- EXPECT_EQ(kCursorPos, composition_text.selection.start());
- EXPECT_EQ(kCursorPos, composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
- composition_text.underlines[0].end_offset);
- // Single underline represents as black thin line.
- EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
- EXPECT_FALSE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_DoubleUnderline) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 2UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- chromeos::IBusText::UnderlineAttribute underline;
- underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_DOUBLE;
- underline.start_index = 1UL;
- underline.end_index = 4UL;
- ibus_text.mutable_underline_attributes()->push_back(underline);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- // If there is no selection, |selection| represents cursor position.
- EXPECT_EQ(kCursorPos, composition_text.selection.start());
- EXPECT_EQ(kCursorPos, composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
- composition_text.underlines[0].end_offset);
- // Double underline represents as black thick line.
- EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
- EXPECT_TRUE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_ErrorUnderline) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 2UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- chromeos::IBusText::UnderlineAttribute underline;
- underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_ERROR;
- underline.start_index = 1UL;
- underline.end_index = 4UL;
- ibus_text.mutable_underline_attributes()->push_back(underline);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- EXPECT_EQ(kCursorPos, composition_text.selection.start());
- EXPECT_EQ(kCursorPos, composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index),
- composition_text.underlines[0].end_offset);
- // Error underline represents as red thin line.
- EXPECT_EQ(SK_ColorRED, composition_text.underlines[0].color);
- EXPECT_FALSE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_Selection) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 2UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- ibus_text.set_selection_start(1UL);
- ibus_text.set_selection_end(4UL);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- EXPECT_EQ(kCursorPos, composition_text.selection.start());
- EXPECT_EQ(kCursorPos, composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_start()),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_end()),
- composition_text.underlines[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
- EXPECT_TRUE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest,
- ExtractCompositionTextTest_SelectionStartWithCursor) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 1UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- ibus_text.set_selection_start(kCursorPos);
- ibus_text.set_selection_end(4UL);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- // If the cursor position is same as selection bounds, selection start
- // position become opposit side of selection from cursor.
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_end()),
- composition_text.selection.start());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos),
- composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_start()),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_end()),
- composition_text.underlines[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
- EXPECT_TRUE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_SelectionEndWithCursor) {
- const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"
- "\xE3\x81\x88\xE3\x81\x8A";
- const uint32 kCursorPos = 4UL;
-
- // Set up ibus text with one underline attribute.
- chromeos::IBusText ibus_text;
- ibus_text.set_text(kSampleText);
- ibus_text.set_selection_start(1UL);
- ibus_text.set_selection_end(kCursorPos);
-
- CompositionText composition_text;
- ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text);
- EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text);
- // If the cursor position is same as selection bounds, selection start
- // position become opposit side of selection from cursor.
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_start()),
- composition_text.selection.start());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos),
- composition_text.selection.end());
- ASSERT_EQ(1UL, composition_text.underlines.size());
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_start()),
- composition_text.underlines[0].start_offset);
- EXPECT_EQ(GetOffsetInUTF16(kSampleText, ibus_text.selection_end()),
- composition_text.underlines[0].end_offset);
- EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color);
- EXPECT_TRUE(composition_text.underlines[0].thick);
-}
-
-TEST_F(InputMethodIBusTest, SurroundingText_NoSelectionTest) {
- ime_->Init(true);
- // Click a text input form.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
-
- // Set the TextInputClient behaviors.
- surrounding_text_ = UTF8ToUTF16("abcdef");
- text_range_ = gfx::Range(0, 6);
- selection_range_ = gfx::Range(3, 3);
-
- // Set the verifier for SetSurroundingText mock call.
- SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 3, 3);
-
-
- ime_->OnCaretBoundsChanged(this);
-
- // Check the call count.
- EXPECT_EQ(1,
- mock_ime_engine_handler_->set_surrounding_text_call_count());
- EXPECT_EQ(UTF16ToUTF8(surrounding_text_),
- mock_ime_engine_handler_->last_set_surrounding_text());
- EXPECT_EQ(3U,
- mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
- EXPECT_EQ(3U,
- mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
-}
-
-TEST_F(InputMethodIBusTest, SurroundingText_SelectionTest) {
- ime_->Init(true);
- // Click a text input form.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
-
- // Set the TextInputClient behaviors.
- surrounding_text_ = UTF8ToUTF16("abcdef");
- text_range_ = gfx::Range(0, 6);
- selection_range_ = gfx::Range(2, 5);
-
- // Set the verifier for SetSurroundingText mock call.
- SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 2, 5);
-
- ime_->OnCaretBoundsChanged(this);
-
- // Check the call count.
- EXPECT_EQ(1,
- mock_ime_engine_handler_->set_surrounding_text_call_count());
- EXPECT_EQ(UTF16ToUTF8(surrounding_text_),
- mock_ime_engine_handler_->last_set_surrounding_text());
- EXPECT_EQ(2U,
- mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
- EXPECT_EQ(5U,
- mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
-}
-
-TEST_F(InputMethodIBusTest, SurroundingText_PartialText) {
- ime_->Init(true);
- // Click a text input form.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
-
- // Set the TextInputClient behaviors.
- surrounding_text_ = UTF8ToUTF16("abcdefghij");
- text_range_ = gfx::Range(5, 10);
- selection_range_ = gfx::Range(7, 9);
-
- ime_->OnCaretBoundsChanged(this);
-
- // Check the call count.
- EXPECT_EQ(1,
- mock_ime_engine_handler_->set_surrounding_text_call_count());
- // Set the verifier for SetSurroundingText mock call.
- // Here (2, 4) is selection range in expected surrounding text coordinates.
- EXPECT_EQ("fghij",
- mock_ime_engine_handler_->last_set_surrounding_text());
- EXPECT_EQ(2U,
- mock_ime_engine_handler_->last_set_surrounding_cursor_pos());
- EXPECT_EQ(4U,
- mock_ime_engine_handler_->last_set_surrounding_anchor_pos());
-}
-
-TEST_F(InputMethodIBusTest, SurroundingText_BecomeEmptyText) {
- ime_->Init(true);
- // Click a text input form.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
-
- // Set the TextInputClient behaviors.
- // If the surrounding text becomes empty, text_range become (0, 0) and
- // selection range become invalid.
- surrounding_text_ = UTF8ToUTF16("");
- text_range_ = gfx::Range(0, 0);
- selection_range_ = gfx::Range::InvalidRange();
-
- ime_->OnCaretBoundsChanged(this);
-
- // Check the call count.
- EXPECT_EQ(0,
- mock_ime_engine_handler_->set_surrounding_text_call_count());
-
- // Should not be called twice with same condition.
- ime_->OnCaretBoundsChanged(this);
- EXPECT_EQ(0,
- mock_ime_engine_handler_->set_surrounding_text_call_count());
-}
-
-class InputMethodIBusKeyEventTest : public InputMethodIBusTest {
- public:
- InputMethodIBusKeyEventTest() {}
- virtual ~InputMethodIBusKeyEventTest() {}
-
- virtual void SetUp() OVERRIDE {
- InputMethodIBusTest::SetUp();
- ime_->Init(true);
- }
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodIBusKeyEventTest);
-};
-
-TEST_F(InputMethodIBusKeyEventTest, KeyEventDelayResponseTest) {
- const int kFlags = ui::EF_SHIFT_DOWN;
- ScopedXI2Event xevent;
- xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, kFlags);
- const ui::KeyEvent event(xevent, true);
-
- // Do key event.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
- ime_->DispatchKeyEvent(event);
-
- // Check before state.
- const ui::KeyEvent* key_event =
- mock_ime_engine_handler_->last_processed_key_event();
- EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count());
- EXPECT_EQ(ui::VKEY_A, key_event->key_code());
- EXPECT_EQ("KeyA", key_event->code());
- EXPECT_EQ(kFlags, key_event->flags());
- EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
-
- // Do callback.
- 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 =
- ime_->process_key_event_post_ime_args().event;
- EXPECT_TRUE(stored_event->HasNativeEvent());
- EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event())));
- EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
-}
-
-TEST_F(InputMethodIBusKeyEventTest, MultiKeyEventDelayResponseTest) {
- // Preparation
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
-
- const int kFlags = ui::EF_SHIFT_DOWN;
- ScopedXI2Event xevent;
- xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, kFlags);
- const ui::KeyEvent event(xevent, true);
-
- // Do key event.
- ime_->DispatchKeyEvent(event);
- const ui::KeyEvent* key_event =
- mock_ime_engine_handler_->last_processed_key_event();
- EXPECT_EQ(ui::VKEY_B, key_event->key_code());
- EXPECT_EQ("KeyB", key_event->code());
- EXPECT_EQ(kFlags, key_event->flags());
-
- KeyEventCallback first_callback =
- mock_ime_engine_handler_->last_passed_callback();
-
- // Do key event again.
- ScopedXI2Event xevent2;
- xevent2.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, kFlags);
- const ui::KeyEvent event2(xevent2, true);
-
- ime_->DispatchKeyEvent(event2);
- const ui::KeyEvent* key_event2 =
- mock_ime_engine_handler_->last_processed_key_event();
- EXPECT_EQ(ui::VKEY_C, key_event2->key_code());
- EXPECT_EQ("KeyC", key_event2->code());
- EXPECT_EQ(kFlags, key_event2->flags());
-
- // Check before state.
- EXPECT_EQ(2,
- mock_ime_engine_handler_->process_key_event_call_count());
- EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
-
- // Do callback for first key event.
- first_callback.Run(true);
-
- // 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_TRUE(stored_event->HasNativeEvent());
- EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event())));
- EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled);
-
- // Do callback for second key event.
- mock_ime_engine_handler_->last_passed_callback().Run(false);
-
- // 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_TRUE(stored_event->HasNativeEvent());
- EXPECT_TRUE(IsEqualXKeyEvent(*xevent2, *(stored_event->native_event())));
- EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled);
-}
-
-TEST_F(InputMethodIBusKeyEventTest, KeyEventDelayResponseResetTest) {
- ScopedXI2Event xevent;
- xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_SHIFT_DOWN);
- const ui::KeyEvent event(xevent, true);
-
- // Do key event.
- input_type_ = TEXT_INPUT_TYPE_TEXT;
- ime_->OnTextInputTypeChanged(this);
- ime_->DispatchKeyEvent(event);
-
- // Check before state.
- EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count());
- EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
-
- ime_->ResetContext();
-
- // Do callback.
- mock_ime_engine_handler_->last_passed_callback().Run(true);
-
- EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
-}
-// TODO(nona): Introduce ProcessKeyEventPostIME tests(crbug.com/156593).
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_imm32.cc b/chromium/ui/base/ime/input_method_imm32.cc
deleted file mode 100644
index 16a33a1128c..00000000000
--- a/chromium/ui/base/ime/input_method_imm32.cc
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/input_method_imm32.h"
-
-#include "base/basictypes.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/ime/win/tsf_input_scope.h"
-
-
-namespace ui {
-
-InputMethodIMM32::InputMethodIMM32(internal::InputMethodDelegate* delegate,
- HWND toplevel_window_handle)
- : InputMethodWin(delegate, toplevel_window_handle),
- enabled_(false), is_candidate_popup_open_(false),
- composing_window_handle_(NULL) {
- // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
- // are not implemented yet. To work around this limitation, here we use
- // "always focused" model.
- // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
- // focus event will be passed.
- InputMethodWin::OnFocus();
-}
-
-void InputMethodIMM32::OnFocus() {
- // Ignore OnFocus event for "always focused" model. See the comment in the
- // constructor.
- // TODO(ime): Implement OnFocus once the callers are fixed.
-}
-
-void InputMethodIMM32::OnBlur() {
- // Ignore OnBlur event for "always focused" model. See the comment in the
- // constructor.
- // TODO(ime): Implement OnFocus once the callers are fixed.
-}
-
-bool InputMethodIMM32::OnUntranslatedIMEMessage(
- const base::NativeEvent& event, InputMethod::NativeEventResult* result) {
- LRESULT original_result = 0;
- BOOL handled = FALSE;
- switch (event.message) {
- case WM_IME_SETCONTEXT:
- original_result = OnImeSetContext(
- event.hwnd, event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_IME_STARTCOMPOSITION:
- original_result = OnImeStartComposition(
- event.hwnd, event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_IME_COMPOSITION:
- original_result = OnImeComposition(
- event.hwnd, event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_IME_ENDCOMPOSITION:
- original_result = OnImeEndComposition(
- event.hwnd, event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_IME_REQUEST:
- original_result = OnImeRequest(
- event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_CHAR:
- case WM_SYSCHAR:
- original_result = OnChar(
- event.hwnd, event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_DEADCHAR:
- case WM_SYSDEADCHAR:
- original_result = OnDeadChar(
- event.message, event.wParam, event.lParam, &handled);
- break;
- case WM_IME_NOTIFY:
- original_result = OnImeNotify(
- event.message, event.wParam, event.lParam, &handled);
- break;
- default:
- NOTREACHED() << "Unknown IME message:" << event.message;
- break;
- }
- if (result)
- *result = original_result;
- return !!handled;
-}
-
-void InputMethodIMM32::OnTextInputTypeChanged(const TextInputClient* client) {
- if (IsTextInputClientFocused(client) && IsWindowFocused(client)) {
- imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
- UpdateIMEState();
- }
- InputMethodWin::OnTextInputTypeChanged(client);
-}
-
-void InputMethodIMM32::OnCaretBoundsChanged(const TextInputClient* client) {
- if (!enabled_ || !IsTextInputClientFocused(client) ||
- !IsWindowFocused(client)) {
- return;
- }
- // The current text input type should not be NONE if |client| is focused.
- DCHECK(!IsTextInputTypeNone());
- gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds());
-
- HWND attached_window = GetAttachedWindowHandle(client);
- // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
- // conversion shouldn't be necessary.
- RECT r = {};
- GetClientRect(attached_window, &r);
- POINT window_point = { screen_bounds.x(), screen_bounds.y() };
- ScreenToClient(attached_window, &window_point);
- gfx::Rect caret_rect(gfx::Point(window_point.x, window_point.y),
- screen_bounds.size());
- imm32_manager_.UpdateCaretRect(attached_window, caret_rect);
-}
-
-void InputMethodIMM32::CancelComposition(const TextInputClient* client) {
- if (enabled_ && IsTextInputClientFocused(client))
- imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
-}
-
-bool InputMethodIMM32::IsCandidatePopupOpen() const {
- return is_candidate_popup_open_;
-}
-
-void InputMethodIMM32::OnWillChangeFocusedClient(
- TextInputClient* focused_before,
- TextInputClient* focused) {
- if (IsWindowFocused(focused_before)) {
- ConfirmCompositionText();
- }
-}
-
-void InputMethodIMM32::OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) {
- if (IsWindowFocused(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);
-
- UpdateIMEState();
-
- // Force to update caret bounds, in case the client thinks that the caret
- // bounds has not changed.
- OnCaretBoundsChanged(focused);
- }
- InputMethodWin::OnDidChangeFocusedClient(focused_before, focused);
-}
-
-LRESULT InputMethodIMM32::OnImeSetContext(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- if (!!wparam)
- imm32_manager_.CreateImeWindow(window_handle);
-
- OnInputMethodChanged();
- return imm32_manager_.SetImeWindowStyle(
- window_handle, message, wparam, lparam, handled);
-}
-
-LRESULT InputMethodIMM32::OnImeStartComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- // We have to prevent WTL from calling ::DefWindowProc() because the function
- // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
- // over-write the position of IME windows.
- *handled = TRUE;
-
- // Reset the composition status and create IME windows.
- composing_window_handle_ = window_handle;
- imm32_manager_.CreateImeWindow(window_handle);
- imm32_manager_.ResetComposition(window_handle);
- return 0;
-}
-
-LRESULT InputMethodIMM32::OnImeComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- // We have to prevent WTL from calling ::DefWindowProc() because we do not
- // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
- *handled = TRUE;
-
- // At first, update the position of the IME window.
- imm32_manager_.UpdateImeWindow(window_handle);
-
- // Retrieve the result string and its attributes of the ongoing composition
- // and send it to a renderer process.
- ui::CompositionText composition;
- if (imm32_manager_.GetResult(window_handle, lparam, &composition.text)) {
- if (!IsTextInputTypeNone())
- GetTextInputClient()->InsertText(composition.text);
- imm32_manager_.ResetComposition(window_handle);
- // Fall though and try reading the composition string.
- // Japanese IMEs send a message containing both GCS_RESULTSTR and
- // GCS_COMPSTR, which means an ongoing composition has been finished
- // by the start of another composition.
- }
- // Retrieve the composition string and its attributes of the ongoing
- // composition and send it to a renderer process.
- if (imm32_manager_.GetComposition(window_handle, lparam, &composition) &&
- !IsTextInputTypeNone())
- GetTextInputClient()->SetCompositionText(composition);
-
- return 0;
-}
-
-LRESULT InputMethodIMM32::OnImeEndComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- // Let WTL call ::DefWindowProc() and release its resources.
- *handled = FALSE;
-
- composing_window_handle_ = NULL;
-
- if (!IsTextInputTypeNone() && GetTextInputClient()->HasCompositionText())
- GetTextInputClient()->ClearCompositionText();
-
- imm32_manager_.ResetComposition(window_handle);
- imm32_manager_.DestroyImeWindow(window_handle);
- return 0;
-}
-
-LRESULT InputMethodIMM32::OnImeNotify(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- *handled = FALSE;
-
- bool previous_state = is_candidate_popup_open_;
-
- // Update |is_candidate_popup_open_|, whether a candidate window is open.
- switch (wparam) {
- case IMN_OPENCANDIDATE:
- is_candidate_popup_open_ = true;
- if (!previous_state)
- OnCandidateWindowShown();
- break;
- case IMN_CLOSECANDIDATE:
- is_candidate_popup_open_ = false;
- if (previous_state)
- OnCandidateWindowHidden();
- break;
- case IMN_CHANGECANDIDATE:
- // TODO(kochi): The IME API expects this event to notify window size change,
- // while this may fire more often without window resize. There is no generic
- // way to get bounds of candidate window.
- OnCandidateWindowUpdated();
- break;
- }
-
- return 0;
-}
-
-void InputMethodIMM32::ConfirmCompositionText() {
- if (composing_window_handle_)
- imm32_manager_.CleanupComposition(composing_window_handle_);
-
- if (!IsTextInputTypeNone()) {
- // Though above line should confirm the client's composition text by sending
- // a result text to us, in case the input method and the client are in
- // inconsistent states, we check the client's composition state again.
- if (GetTextInputClient()->HasCompositionText())
- GetTextInputClient()->ConfirmCompositionText();
- }
-}
-
-void InputMethodIMM32::UpdateIMEState() {
- // Use switch here in case we are going to add more text input types.
- // We disable input method in password field.
- const HWND window_handle = GetAttachedWindowHandle(GetTextInputClient());
- const TextInputType text_input_type = GetTextInputType();
- const TextInputMode text_input_mode = GetTextInputMode();
- switch (text_input_type) {
- case ui::TEXT_INPUT_TYPE_NONE:
- case ui::TEXT_INPUT_TYPE_PASSWORD:
- imm32_manager_.DisableIME(window_handle);
- enabled_ = false;
- break;
- default:
- imm32_manager_.EnableIME(window_handle);
- enabled_ = true;
- break;
- }
-
- imm32_manager_.SetTextInputMode(window_handle, text_input_mode);
- tsf_inputscope::SetInputScopeForTsfUnawareWindow(
- window_handle, text_input_type, text_input_mode);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_imm32.h b/chromium/ui/base/ime/input_method_imm32.h
deleted file mode 100644
index dc0a4dc8ea6..00000000000
--- a/chromium/ui/base/ime/input_method_imm32.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_INPUT_METHOD_IMM32_H_
-#define UI_BASE_IME_INPUT_METHOD_IMM32_H_
-
-#include <windows.h>
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/base/ime/input_method_win.h"
-
-namespace ui {
-
-// An InputMethod implementation based on Windows IMM32 API.
-class UI_EXPORT InputMethodIMM32 : public InputMethodWin {
- public:
- InputMethodIMM32(internal::InputMethodDelegate* delegate,
- HWND toplevel_window_handle);
-
- // Overridden from InputMethod:
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) OVERRIDE;
- virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
- virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
- virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
- virtual bool IsCandidatePopupOpen() const OVERRIDE;
-
- protected:
- // Overridden from InputMethodBase:
- virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) OVERRIDE;
- virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) OVERRIDE;
-
- private:
- LRESULT OnImeSetContext(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
- LRESULT OnImeStartComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
- LRESULT OnImeComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
- LRESULT OnImeEndComposition(HWND window_handle,
- UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
- LRESULT OnImeNotify(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled);
-
- // Asks the client to confirm current composition text.
- void ConfirmCompositionText();
-
- // Enables or disables the IME according to the current text input type.
- void UpdateIMEState();
-
- bool enabled_;
-
- // True if we know for sure that a candidate window is open.
- bool is_candidate_popup_open_;
-
- // Window handle where composition is on-going. NULL when there is no
- // composition.
- HWND composing_window_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodIMM32);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_IME_INPUT_METHOD_IMM32_H_
diff --git a/chromium/ui/base/ime/input_method_initializer.cc b/chromium/ui/base/ime/input_method_initializer.cc
index ad29e61f508..2fca46cff47 100644
--- a/chromium/ui/base/ime/input_method_initializer.cc
+++ b/chromium/ui/base/ime/input_method_initializer.cc
@@ -4,27 +4,16 @@
#include "ui/base/ime/input_method_initializer.h"
-#if defined(TOOLKIT_VIEWS) || defined(USE_AURA)
-#include "ui/base/ime/input_method_factory.h"
-#endif
-
#if defined(OS_CHROMEOS)
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#elif defined(USE_AURA) && defined(OS_LINUX)
#include "base/logging.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "ui/base/ime/chromeos/ibus_bridge.h"
-#elif defined(USE_AURA) && defined(USE_X11)
-#include "ui/base/ime/input_method_auralinux.h"
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
-#elif defined(OS_WIN)
-#include "base/win/metro.h"
-#include "ui/base/ime/win/tsf_bridge.h"
#endif
namespace {
-#if defined(OS_CHROMEOS)
-bool dbus_thread_manager_was_initialized = false;
-#elif defined(USE_AURA) && defined(USE_X11)
+#if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(OS_LINUX)
const ui::LinuxInputMethodContextFactory* g_linux_input_method_context_factory;
#endif
@@ -34,37 +23,20 @@ namespace ui {
void InitializeInputMethod() {
#if defined(OS_CHROMEOS)
- chromeos::IBusBridge::Initialize();
-#elif defined(USE_AURA) && defined(USE_X11)
- InputMethodAuraLinux::Initialize();
-#elif defined(OS_WIN)
- if (base::win::IsTSFAwareRequired())
- TSFBridge::Initialize();
+ chromeos::IMEBridge::Initialize();
#endif
}
void ShutdownInputMethod() {
-#if defined(TOOLKIT_VIEWS) || defined(USE_AURA)
- InputMethodFactory::ClearInstance();
-#endif
#if defined(OS_CHROMEOS)
- chromeos::IBusBridge::Shutdown();
-#elif defined(OS_WIN)
- internal::DestroySharedInputMethod();
- if (base::win::IsTSFAwareRequired())
- TSFBridge::Shutdown();
+ chromeos::IMEBridge::Shutdown();
#endif
}
void InitializeInputMethodForTesting() {
#if defined(OS_CHROMEOS)
- chromeos::IBusBridge::Initialize();
- // TODO(nona): Remove DBusThreadManager initialize.
- if (!chromeos::DBusThreadManager::IsInitialized()) {
- chromeos::DBusThreadManager::InitializeWithStub();
- dbus_thread_manager_was_initialized = true;
- }
-#elif defined(USE_AURA) && defined(USE_X11)
+ chromeos::IMEBridge::Initialize();
+#elif defined(USE_AURA) && defined(OS_LINUX)
if (!g_linux_input_method_context_factory)
g_linux_input_method_context_factory = new FakeInputMethodContextFactory();
const LinuxInputMethodContextFactory* factory =
@@ -74,27 +46,13 @@ void InitializeInputMethodForTesting() {
<< "else.";
LinuxInputMethodContextFactory::SetInstance(
g_linux_input_method_context_factory);
-#elif defined(OS_WIN)
- if (base::win::IsTSFAwareRequired()) {
- // Make sure COM is initialized because TSF depends on COM.
- CoInitialize(NULL);
- TSFBridge::Initialize();
- }
#endif
}
void ShutdownInputMethodForTesting() {
-#if defined(TOOLKIT_VIEWS) || defined(USE_AURA)
- InputMethodFactory::ClearInstance();
-#endif
#if defined(OS_CHROMEOS)
- chromeos::IBusBridge::Shutdown();
- // TODO(nona): Remove DBusThreadManager finalize.
- if (dbus_thread_manager_was_initialized) {
- chromeos::DBusThreadManager::Shutdown();
- dbus_thread_manager_was_initialized = false;
- }
-#elif defined(USE_AURA) && defined(USE_X11)
+ chromeos::IMEBridge::Shutdown();
+#elif defined(USE_AURA) && defined(OS_LINUX)
const LinuxInputMethodContextFactory* factory =
LinuxInputMethodContextFactory::instance();
CHECK(!factory || factory == g_linux_input_method_context_factory)
@@ -102,12 +60,6 @@ void ShutdownInputMethodForTesting() {
LinuxInputMethodContextFactory::SetInstance(NULL);
delete g_linux_input_method_context_factory;
g_linux_input_method_context_factory = NULL;
-#elif defined(OS_WIN)
- internal::DestroySharedInputMethod();
- if (base::win::IsTSFAwareRequired()) {
- TSFBridge::Shutdown();
- CoUninitialize();
- }
#endif
}
diff --git a/chromium/ui/base/ime/input_method_initializer.h b/chromium/ui/base/ime/input_method_initializer.h
index fbdf6733574..065e53ed8dd 100644
--- a/chromium/ui/base/ime/input_method_initializer.h
+++ b/chromium/ui/base/ime/input_method_initializer.h
@@ -6,25 +6,25 @@
#define UI_BASE_IME_INPUT_METHOD_INITIALIZER_H_
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Initializes thread-local resources for input method. This function should be
// called in the UI thread before input method is used.
-UI_EXPORT void InitializeInputMethod();
+UI_BASE_EXPORT void InitializeInputMethod();
// Shutdown thread-local resources for input method. This function should be
// called in the UI thread after input method is used.
-UI_EXPORT void ShutdownInputMethod();
+UI_BASE_EXPORT void ShutdownInputMethod();
// Initializes thread-local resources for input method. This function is
// intended to be called from Setup function of unit tests.
-UI_EXPORT void InitializeInputMethodForTesting();
+UI_BASE_EXPORT void InitializeInputMethodForTesting();
// Initializes thread-local resources for input method. This function is
// intended to be called from TearDown function of unit tests.
-UI_EXPORT void ShutdownInputMethodForTesting();
+UI_BASE_EXPORT void ShutdownInputMethodForTesting();
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_mac.h b/chromium/ui/base/ime/input_method_mac.h
new file mode 100644
index 00000000000..08f60801e24
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_mac.h
@@ -0,0 +1,38 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_INPUT_METHOD_MAC_H_
+#define UI_BASE_IME_INPUT_METHOD_MAC_H_
+
+#include "ui/base/ime/input_method_base.h"
+
+namespace ui {
+
+// A ui::InputMethod implementation for Mac.
+// On the Mac, key events don't pass through InputMethod.
+// Instead, NSTextInputClient calls are bridged to the currently focused
+// ui::TextInputClient object.
+class UI_BASE_EXPORT InputMethodMac : public InputMethodBase {
+ public:
+ explicit InputMethodMac(internal::InputMethodDelegate* delegate);
+ virtual ~InputMethodMac();
+
+ // Overriden from InputMethod.
+ virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ NativeEventResult* result) OVERRIDE;
+ virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
+ virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
+ virtual void OnInputLocaleChanged() OVERRIDE;
+ virtual std::string GetInputLocale() OVERRIDE;
+ virtual bool IsActive() OVERRIDE;
+ virtual bool IsCandidatePopupOpen() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InputMethodMac);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_INPUT_METHOD_MAC_H_
diff --git a/chromium/ui/base/ime/input_method_mac.mm b/chromium/ui/base/ime/input_method_mac.mm
new file mode 100644
index 00000000000..c4b55c984d9
--- /dev/null
+++ b/chromium/ui/base/ime/input_method_mac.mm
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/input_method_mac.h"
+
+namespace ui {
+
+InputMethodMac::InputMethodMac(internal::InputMethodDelegate* delegate) {
+ SetDelegate(delegate);
+}
+
+InputMethodMac::~InputMethodMac() {
+}
+
+bool InputMethodMac::OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ NativeEventResult* result) {
+ return false;
+}
+
+bool InputMethodMac::DispatchKeyEvent(const ui::KeyEvent& event) {
+ // IME processing on the Mac does not go through this path.
+ NOTREACHED();
+ return false;
+}
+
+void InputMethodMac::OnCaretBoundsChanged(const TextInputClient* client) {
+}
+
+void InputMethodMac::CancelComposition(const TextInputClient* client) {
+}
+
+void InputMethodMac::OnInputLocaleChanged() {
+}
+
+std::string InputMethodMac::GetInputLocale() {
+ return "";
+}
+
+bool InputMethodMac::IsActive() {
+ return true;
+}
+
+bool InputMethodMac::IsCandidatePopupOpen() const {
+ // There seems to be no way to tell if a candidate window is open.
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_minimal.cc b/chromium/ui/base/ime/input_method_minimal.cc
index 0b51b9e3ced..9466c4044db 100644
--- a/chromium/ui/base/ime/input_method_minimal.cc
+++ b/chromium/ui/base/ime/input_method_minimal.cc
@@ -52,10 +52,6 @@ std::string InputMethodMinimal::GetInputLocale() {
return std::string();
}
-base::i18n::TextDirection InputMethodMinimal::GetInputTextDirection() {
- return base::i18n::UNKNOWN_DIRECTION;
-}
-
bool InputMethodMinimal::IsActive() {
return true;
}
diff --git a/chromium/ui/base/ime/input_method_minimal.h b/chromium/ui/base/ime/input_method_minimal.h
index 2ba158f1815..84fd066be0c 100644
--- a/chromium/ui/base/ime/input_method_minimal.h
+++ b/chromium/ui/base/ime/input_method_minimal.h
@@ -11,7 +11,7 @@ namespace ui {
// A minimal implementation of ui::InputMethod, which supports only the direct
// input without any compositions or conversions.
-class UI_EXPORT InputMethodMinimal : public InputMethodBase {
+class UI_BASE_EXPORT InputMethodMinimal : public InputMethodBase {
public:
explicit InputMethodMinimal(internal::InputMethodDelegate* delegate);
virtual ~InputMethodMinimal();
@@ -24,7 +24,6 @@ class UI_EXPORT InputMethodMinimal : public InputMethodBase {
virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
diff --git a/chromium/ui/base/ime/input_method_observer.h b/chromium/ui/base/ime/input_method_observer.h
index 9ac177b4d64..d3432c9782d 100644
--- a/chromium/ui/base/ime/input_method_observer.h
+++ b/chromium/ui/base/ime/input_method_observer.h
@@ -5,14 +5,14 @@
#ifndef UI_BASE_IME_INPUT_METHOD_OBSERVER_H_
#define UI_BASE_IME_INPUT_METHOD_OBSERVER_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
class InputMethod;
class TextInputClient;
-class UI_EXPORT InputMethodObserver {
+class UI_BASE_EXPORT InputMethodObserver {
public:
virtual ~InputMethodObserver() {}
@@ -39,6 +39,10 @@ class UI_EXPORT InputMethodObserver {
// Called when the observed InputMethod is being destroyed.
virtual void OnInputMethodDestroyed(const InputMethod* input_method) = 0;
+
+ // Called when a user gesture should trigger showing the virtual keyboard
+ // or alternate input view (e.g. handwriting palette). Used in ChromeOS.
+ virtual void OnShowImeIfNeeded() = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_tsf.cc b/chromium/ui/base/ime/input_method_tsf.cc
deleted file mode 100644
index 5e6de052e55..00000000000
--- a/chromium/ui/base/ime/input_method_tsf.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/input_method_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 InputMethodTSF::TSFEventObserver : public TSFEventRouterObserver {
- public:
- TSFEventObserver() : is_candidate_popup_open_(false) {}
-
- // 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:
- virtual 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_;
-
- DISALLOW_COPY_AND_ASSIGN(TSFEventObserver);
-};
-
-InputMethodTSF::InputMethodTSF(internal::InputMethodDelegate* delegate,
- HWND toplevel_window_handle)
- : InputMethodWin(delegate, toplevel_window_handle),
- tsf_event_observer_(new TSFEventObserver()),
- tsf_event_router_(new TSFEventRouter(tsf_event_observer_.get())) {
- // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
- // are not implemented yet. To work around this limitation, here we use
- // "always focused" model.
- // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
- // focus event will be passed.
- InputMethodWin::OnFocus();
-}
-
-InputMethodTSF::~InputMethodTSF() {}
-
-void InputMethodTSF::OnFocus() {
- // Do not call baseclass' OnFocus() and discard the event being in
- // "always focused" model. See the comment in the constructor.
- // TODO(ime): Implement OnFocus once the callers are fixed.
-
- tsf_event_router_->SetManager(
- ui::TSFBridge::GetInstance()->GetThreadManager());
-}
-
-void InputMethodTSF::OnBlur() {
- // Do not call baseclass' OnBlur() and discard the event being in
- // "always focused" model. See the comment in the constructor.
- // TODO(ime): Implement OnFocus once the callers are fixed.
-
- tsf_event_router_->SetManager(NULL);
-}
-
-bool InputMethodTSF::OnUntranslatedIMEMessage(
- const base::NativeEvent& 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, &handled);
- break;
- case WM_DEADCHAR:
- case WM_SYSDEADCHAR:
- // See the comment in WM_CHAR/WM_SYSCHAR.
- original_result = OnDeadChar(
- event.message, event.wParam, event.lParam, &handled);
- break;
- }
- if (result)
- *result = original_result;
- return !!handled;
-}
-
-void InputMethodTSF::OnTextInputTypeChanged(const TextInputClient* client) {
- if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
- return;
- ui::TSFBridge::GetInstance()->CancelComposition();
- ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client);
-}
-
-void InputMethodTSF::OnCaretBoundsChanged(const TextInputClient* client) {
- if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
- return;
- ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
-}
-
-void InputMethodTSF::CancelComposition(const TextInputClient* client) {
- if (IsTextInputClientFocused(client) && IsWindowFocused(client))
- ui::TSFBridge::GetInstance()->CancelComposition();
-}
-
-void InputMethodTSF::DetachTextInputClient(TextInputClient* client) {
- InputMethodWin::DetachTextInputClient(client);
- ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
-}
-
-bool InputMethodTSF::IsCandidatePopupOpen() const {
- return tsf_event_observer_->IsCandidatePopupOpen();
-}
-
-void InputMethodTSF::OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) {
- if (IsWindowFocused(focused_before)) {
- ConfirmCompositionText();
- ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before);
- }
-}
-
-void InputMethodTSF::OnDidChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) {
- if (IsWindowFocused(focused) && IsTextInputClientFocused(focused)) {
- ui::TSFBridge::GetInstance()->SetFocusedClient(
- GetAttachedWindowHandle(focused), 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);
- }
- InputMethodWin::OnDidChangeFocusedClient(focused_before, focused);
-}
-
-void InputMethodTSF::ConfirmCompositionText() {
- if (!IsTextInputTypeNone())
- ui::TSFBridge::GetInstance()->ConfirmComposition();
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_tsf.h b/chromium/ui/base/ime/input_method_tsf.h
deleted file mode 100644
index 2b4a9bde10c..00000000000
--- a/chromium/ui/base/ime/input_method_tsf.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_INPUT_METHOD_TSF_H_
-#define UI_BASE_IME_INPUT_METHOD_TSF_H_
-
-#include <windows.h>
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/base/ime/input_method_win.h"
-
-namespace ui {
-
-class TSFEventRouter;
-
-// An InputMethod implementation based on Windows TSF API.
-class UI_EXPORT InputMethodTSF : public InputMethodWin {
- public:
- InputMethodTSF(internal::InputMethodDelegate* delegate,
- HWND toplevel_window_handle);
- virtual ~InputMethodTSF();
-
- // Overridden from InputMethod:
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
- NativeEventResult* result) OVERRIDE;
- virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
- virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
- virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
- virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE;
- virtual bool IsCandidatePopupOpen() const OVERRIDE;
-
- // Overridden from InputMethodBase:
- virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
- TextInputClient* focused) OVERRIDE;
- virtual 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.
- scoped_ptr<TSFEventObserver> tsf_event_observer_;
- scoped_ptr<TSFEventRouter> tsf_event_router_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodTSF);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_IME_INPUT_METHOD_TSF_H_
diff --git a/chromium/ui/base/ime/input_method_win.cc b/chromium/ui/base/ime/input_method_win.cc
index 5a30792e434..9b23c1a0359 100644
--- a/chromium/ui/base/ime/input_method_win.cc
+++ b/chromium/ui/base/ime/input_method_win.cc
@@ -6,10 +6,12 @@
#include "base/basictypes.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/win/tsf_input_scope.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/dpi.h"
#include "ui/gfx/win/hwnd_util.h"
namespace ui {
@@ -23,21 +25,85 @@ static const size_t kExtraNumberOfChars = 20;
InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
HWND toplevel_window_handle)
- : active_(false),
- toplevel_window_handle_(toplevel_window_handle),
- direction_(base::i18n::UNKNOWN_DIRECTION),
+ : toplevel_window_handle_(toplevel_window_handle),
pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION),
- accept_carriage_return_(false) {
+ accept_carriage_return_(false),
+ active_(false),
+ enabled_(false),
+ is_candidate_popup_open_(false),
+ composing_window_handle_(NULL) {
SetDelegate(delegate);
+ // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
+ // are not implemented yet. To work around this limitation, here we use
+ // "always focused" model.
+ // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
+ // focus event will be passed.
+ InputMethodBase::OnFocus();
}
void InputMethodWin::Init(bool focused) {
- // Gets the initial input locale and text direction information.
+ // Gets the initial input locale.
OnInputLocaleChanged();
InputMethodBase::Init(focused);
}
+void InputMethodWin::OnFocus() {
+ // Ignore OnFocus event for "always focused" model. See the comment in the
+ // constructor.
+ // TODO(ime): Implement OnFocus once the callers are fixed.
+}
+
+void InputMethodWin::OnBlur() {
+ // Ignore OnBlur event for "always focused" model. See the comment in the
+ // constructor.
+ // TODO(ime): Implement OnFocus once the callers are fixed.
+}
+
+bool InputMethodWin::OnUntranslatedIMEMessage(
+ const base::NativeEvent& event,
+ InputMethod::NativeEventResult* result) {
+ LRESULT original_result = 0;
+ BOOL handled = FALSE;
+ switch (event.message) {
+ case WM_IME_SETCONTEXT:
+ original_result = OnImeSetContext(
+ event.hwnd, event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_IME_STARTCOMPOSITION:
+ original_result = OnImeStartComposition(
+ event.hwnd, event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_IME_COMPOSITION:
+ original_result = OnImeComposition(
+ event.hwnd, event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_IME_ENDCOMPOSITION:
+ original_result = OnImeEndComposition(
+ event.hwnd, event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_IME_REQUEST:
+ original_result = OnImeRequest(
+ event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ original_result = OnChar(
+ event.hwnd, event.message, event.wParam, event.lParam, &handled);
+ break;
+ case WM_IME_NOTIFY:
+ original_result = OnImeNotify(
+ event.message, event.wParam, event.lParam, &handled);
+ break;
+ default:
+ NOTREACHED() << "Unknown IME message:" << event.message;
+ break;
+ }
+ if (result)
+ *result = original_result;
+ return !!handled;
+}
+
bool InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& event) {
if (!event.HasNativeEvent())
return DispatchFabricatedKeyEvent(event);
@@ -76,10 +142,45 @@ bool InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& event) {
return DispatchKeyEventPostIME(event);
}
+void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) {
+ if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
+ return;
+ imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
+ UpdateIMEState();
+}
+
+void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) {
+ if (!enabled_ || !IsTextInputClientFocused(client) ||
+ !IsWindowFocused(client)) {
+ return;
+ }
+ // The current text input type should not be NONE if |client| is focused.
+ DCHECK(!IsTextInputTypeNone());
+ // Tentatively assume that the returned value is DIP (Density Independent
+ // Pixel). See the comment in text_input_client.h and http://crbug.com/360334.
+ const gfx::Rect dip_screen_bounds(GetTextInputClient()->GetCaretBounds());
+ const gfx::Rect screen_bounds = gfx::win::DIPToScreenRect(dip_screen_bounds);
+
+ HWND attached_window = GetAttachedWindowHandle(client);
+ // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
+ // conversion shouldn't be necessary.
+ RECT r = {};
+ GetClientRect(attached_window, &r);
+ POINT window_point = { screen_bounds.x(), screen_bounds.y() };
+ ScreenToClient(attached_window, &window_point);
+ gfx::Rect caret_rect(gfx::Point(window_point.x, window_point.y),
+ screen_bounds.size());
+ imm32_manager_.UpdateCaretRect(attached_window, caret_rect);
+}
+
+void InputMethodWin::CancelComposition(const TextInputClient* client) {
+ if (enabled_ && IsTextInputClientFocused(client))
+ imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
+}
+
void InputMethodWin::OnInputLocaleChanged() {
active_ = imm32_manager_.SetInputLanguage();
locale_ = imm32_manager_.GetInputLanguageName();
- direction_ = imm32_manager_.GetTextDirection();
OnInputMethodChanged();
}
@@ -87,47 +188,37 @@ std::string InputMethodWin::GetInputLocale() {
return locale_;
}
-base::i18n::TextDirection InputMethodWin::GetInputTextDirection() {
- return direction_;
-}
-
bool InputMethodWin::IsActive() {
return active_;
}
+bool InputMethodWin::IsCandidatePopupOpen() const {
+ return is_candidate_popup_open_;
+}
+
+void InputMethodWin::OnWillChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) {
+ if (IsWindowFocused(focused_before))
+ ConfirmCompositionText();
+}
+
void InputMethodWin::OnDidChangeFocusedClient(
TextInputClient* focused_before,
TextInputClient* focused) {
- if (focused_before != focused)
- accept_carriage_return_ = false;
-}
-
-LRESULT InputMethodWin::OnImeRequest(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
- *handled = FALSE;
+ if (IsWindowFocused(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);
- // 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;
- }
+ UpdateIMEState();
- 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;
+ // Force to update caret bounds, in case the client thinks that the caret
+ // bounds has not changed.
+ OnCaretBoundsChanged(focused);
}
+ if (focused_before != focused)
+ accept_carriage_return_ = false;
}
LRESULT InputMethodWin::OnChar(HWND window_handle,
@@ -140,8 +231,8 @@ LRESULT InputMethodWin::OnChar(HWND window_handle,
// 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 char16 kCarriageReturn = L'\r';
- const char16 ch = static_cast<char16>(wparam);
+ 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.
@@ -163,14 +254,146 @@ LRESULT InputMethodWin::OnChar(HWND window_handle,
return 0;
}
-LRESULT InputMethodWin::OnDeadChar(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL* handled) {
+LRESULT InputMethodWin::OnImeSetContext(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ if (!!wparam)
+ imm32_manager_.CreateImeWindow(window_handle);
+
+ OnInputMethodChanged();
+ return imm32_manager_.SetImeWindowStyle(
+ window_handle, message, wparam, lparam, handled);
+}
+
+LRESULT InputMethodWin::OnImeStartComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ // We have to prevent WTL from calling ::DefWindowProc() because the function
+ // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
+ // over-write the position of IME windows.
*handled = TRUE;
+
+ // Reset the composition status and create IME windows.
+ composing_window_handle_ = window_handle;
+ imm32_manager_.CreateImeWindow(window_handle);
+ imm32_manager_.ResetComposition(window_handle);
return 0;
}
+LRESULT InputMethodWin::OnImeComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ // We have to prevent WTL from calling ::DefWindowProc() because we do not
+ // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
+ *handled = TRUE;
+
+ // At first, update the position of the IME window.
+ imm32_manager_.UpdateImeWindow(window_handle);
+
+ // Retrieve the result string and its attributes of the ongoing composition
+ // and send it to a renderer process.
+ ui::CompositionText composition;
+ if (imm32_manager_.GetResult(window_handle, lparam, &composition.text)) {
+ if (!IsTextInputTypeNone())
+ GetTextInputClient()->InsertText(composition.text);
+ imm32_manager_.ResetComposition(window_handle);
+ // Fall though and try reading the composition string.
+ // Japanese IMEs send a message containing both GCS_RESULTSTR and
+ // GCS_COMPSTR, which means an ongoing composition has been finished
+ // by the start of another composition.
+ }
+ // Retrieve the composition string and its attributes of the ongoing
+ // composition and send it to a renderer process.
+ if (imm32_manager_.GetComposition(window_handle, lparam, &composition) &&
+ !IsTextInputTypeNone())
+ GetTextInputClient()->SetCompositionText(composition);
+
+ return 0;
+}
+
+LRESULT InputMethodWin::OnImeEndComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ // Let WTL call ::DefWindowProc() and release its resources.
+ *handled = FALSE;
+
+ composing_window_handle_ = NULL;
+
+ if (!IsTextInputTypeNone() && GetTextInputClient()->HasCompositionText())
+ GetTextInputClient()->ClearCompositionText();
+
+ imm32_manager_.ResetComposition(window_handle);
+ imm32_manager_.DestroyImeWindow(window_handle);
+ return 0;
+}
+
+LRESULT InputMethodWin::OnImeNotify(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled) {
+ *handled = FALSE;
+
+ bool previous_state = is_candidate_popup_open_;
+
+ // Update |is_candidate_popup_open_|, whether a candidate window is open.
+ switch (wparam) {
+ case IMN_OPENCANDIDATE:
+ is_candidate_popup_open_ = true;
+ if (!previous_state)
+ OnCandidateWindowShown();
+ break;
+ case IMN_CLOSECANDIDATE:
+ is_candidate_popup_open_ = false;
+ if (previous_state)
+ OnCandidateWindowHidden();
+ break;
+ case IMN_CHANGECANDIDATE:
+ // TODO(kochi): The IME API expects this event to notify window size change,
+ // while this may fire more often without window resize. There is no generic
+ // way to get bounds of candidate window.
+ OnCandidateWindowUpdated();
+ break;
+ }
+
+ 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)
@@ -210,7 +433,7 @@ LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
if (reconv->dwSize < need_size)
return 0;
- string16 text;
+ base::string16 text;
if (!GetTextInputClient()->GetTextFromRange(text_range, &text))
return 0;
DCHECK_EQ(text_range.length(), text.length());
@@ -266,7 +489,7 @@ LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) {
// TODO(penghuang): Return some extra context to help improve IME's
// reconversion accuracy.
- string16 text;
+ base::string16 text;
if (!GetTextInputClient()->GetTextFromRange(selection_range, &text))
return 0;
DCHECK_EQ(selection_range.length(), text.length());
@@ -299,10 +522,13 @@ LRESULT InputMethodWin::OnQueryCharPosition(IMECHARPOSITION* char_positon) {
if (!client)
return 0;
- gfx::Rect rect;
+ // 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,
- &rect)) {
+ &dip_rect)) {
return 0;
}
} else {
@@ -310,8 +536,9 @@ LRESULT InputMethodWin::OnQueryCharPosition(IMECHARPOSITION* char_positon) {
// the caret bounds. This behavior is the same to that of RichEdit control.
if (char_positon->dwCharPos != 0)
return 0;
- rect = client->GetCaretBounds();
+ dip_rect = client->GetCaretBounds();
}
+ const gfx::Rect rect = gfx::win::DIPToScreenRect(dip_rect);
char_positon->pt.x = rect.x();
char_positon->pt.y = rect.y();
@@ -325,38 +552,22 @@ HWND InputMethodWin::GetAttachedWindowHandle(
// represents the valid top-level window handle because each top-level window
// is responsible for lifecycle management of corresponding InputMethod
// instance.
-#if defined(USE_AURA)
return toplevel_window_handle_;
-#else
- // On Non-Aura environment, TextInputClient::GetAttachedWindow() returns
- // window handle to which each input method is bound.
- if (!text_input_client)
- return NULL;
- return text_input_client->GetAttachedWindow();
-#endif
}
bool InputMethodWin::IsWindowFocused(const TextInputClient* client) const {
if (!client)
return false;
HWND attached_window_handle = GetAttachedWindowHandle(client);
-#if defined(USE_AURA)
// 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 attached_window_handle && GetActiveWindow() == attached_window_handle;
-#else
- return attached_window_handle && GetFocus() == attached_window_handle;
-#endif
}
bool InputMethodWin::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) {
- // TODO(ananta)
- // Support IMEs and RTL layout in Windows 8 metro Ash. The code below won't
- // work with IMEs.
- // Bug: https://code.google.com/p/chromium/issues/detail?id=164964
if (event.is_char()) {
if (GetTextInputClient()) {
GetTextInputClient()->InsertChar(event.key_code(),
@@ -367,4 +578,40 @@ bool InputMethodWin::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) {
return DispatchKeyEventPostIME(event);
}
+void InputMethodWin::ConfirmCompositionText() {
+ if (composing_window_handle_)
+ imm32_manager_.CleanupComposition(composing_window_handle_);
+
+ if (!IsTextInputTypeNone()) {
+ // Though above line should confirm the client's composition text by sending
+ // a result text to us, in case the input method and the client are in
+ // inconsistent states, we check the client's composition state again.
+ if (GetTextInputClient()->HasCompositionText())
+ GetTextInputClient()->ConfirmCompositionText();
+ }
+}
+
+void InputMethodWin::UpdateIMEState() {
+ // Use switch here in case we are going to add more text input types.
+ // We disable input method in password field.
+ const HWND window_handle = GetAttachedWindowHandle(GetTextInputClient());
+ const TextInputType text_input_type = GetTextInputType();
+ const TextInputMode text_input_mode = GetTextInputMode();
+ switch (text_input_type) {
+ case ui::TEXT_INPUT_TYPE_NONE:
+ case ui::TEXT_INPUT_TYPE_PASSWORD:
+ imm32_manager_.DisableIME(window_handle);
+ enabled_ = false;
+ break;
+ default:
+ imm32_manager_.EnableIME(window_handle);
+ enabled_ = true;
+ break;
+ }
+
+ imm32_manager_.SetTextInputMode(window_handle, text_input_mode);
+ tsf_inputscope::SetInputScopeForTsfUnawareWindow(
+ window_handle, text_input_type, text_input_mode);
+}
+
} // namespace ui
diff --git a/chromium/ui/base/ime/input_method_win.h b/chromium/ui/base/ime/input_method_win.h
index e034525b375..b02d670c17a 100644
--- a/chromium/ui/base/ime/input_method_win.h
+++ b/chromium/ui/base/ime/input_method_win.h
@@ -16,45 +16,76 @@
namespace ui {
-// A common InputMethod implementation shared between IMM32 and TSF.
-class UI_EXPORT InputMethodWin : public InputMethodBase {
+// A common InputMethod implementation based on IMM32.
+class UI_BASE_EXPORT InputMethodWin : public InputMethodBase {
public:
InputMethodWin(internal::InputMethodDelegate* delegate,
HWND toplevel_window_handle);
// Overridden from InputMethod:
virtual void Init(bool focused) OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ NativeEventResult* result) OVERRIDE;
virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
+ virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE;
+ virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
+ virtual bool IsCandidatePopupOpen() const OVERRIDE;
protected:
// Overridden from InputMethodBase:
// If a derived class overrides this method, it should call parent's
// implementation.
+ virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
+ TextInputClient* focused) OVERRIDE;
virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
TextInputClient* focused) OVERRIDE;
- // 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);
+ private:
// For both WM_CHAR and WM_SYSCHAR
LRESULT OnChar(HWND window_handle,
UINT message,
WPARAM wparam,
LPARAM lparam,
BOOL* handled);
- // For both WM_DEADCHAR and WM_SYSDEADCHAR
- // TODO(yukawa): Stop handling WM_DEADCHAR and WM_SYSDEADCHAR when non-Aura
- // build is deprecated.
- LRESULT OnDeadChar(UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
+ LRESULT OnImeSetContext(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled);
+ LRESULT OnImeStartComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled);
+ LRESULT OnImeComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled);
+ LRESULT OnImeEndComposition(HWND window_handle,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL* handled);
+ LRESULT OnImeNotify(UINT message,
+ WPARAM wparam,
+ 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);
@@ -67,16 +98,18 @@ class UI_EXPORT InputMethodWin : public InputMethodBase {
// to be ready for receiving keyboard input.
bool IsWindowFocused(const TextInputClient* client) const;
- // Indicates if the current input locale has an IME.
- bool active_;
+ bool DispatchFabricatedKeyEvent(const ui::KeyEvent& event);
+
+ // Asks the client to confirm current composition text.
+ void ConfirmCompositionText();
+
+ // Enables or disables the IME according to the current text input type.
+ void UpdateIMEState();
// Windows IMM32 wrapper.
// (See "ui/base/ime/win/ime_input.h" for its details.)
ui::IMM32Manager imm32_manager_;
- private:
- bool DispatchFabricatedKeyEvent(const ui::KeyEvent& event);
-
// The toplevel window handle.
// On non-Aura environment, this value is not used and always NULL.
const HWND toplevel_window_handle_;
@@ -84,9 +117,6 @@ class UI_EXPORT InputMethodWin : public InputMethodBase {
// Name of the current input locale.
std::string locale_;
- // The current input text direction.
- base::i18n::TextDirection direction_;
-
// 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.
@@ -98,6 +128,19 @@ class UI_EXPORT InputMethodWin : public InputMethodBase {
// TODO(yukawa, IME): Figure out long-term solution.
bool accept_carriage_return_;
+ // Indicates if the current input locale has an IME.
+ bool active_;
+
+ // True when an IME should be allowed to process key events.
+ bool enabled_;
+
+ // True if we know for sure that a candidate window is open.
+ bool is_candidate_popup_open_;
+
+ // Window handle where composition is on-going. NULL when there is no
+ // composition.
+ HWND composing_window_handle_;
+
DISALLOW_COPY_AND_ASSIGN(InputMethodWin);
};
diff --git a/chromium/ui/base/ime/linux/fake_input_method_context.cc b/chromium/ui/base/ime/linux/fake_input_method_context.cc
index 434dcf67041..fd0d8e2c06d 100644
--- a/chromium/ui/base/ime/linux/fake_input_method_context.cc
+++ b/chromium/ui/base/ime/linux/fake_input_method_context.cc
@@ -18,11 +18,6 @@ bool FakeInputMethodContext::DispatchKeyEvent(
void FakeInputMethodContext::Reset() {
}
-base::i18n::TextDirection FakeInputMethodContext::GetInputTextDirection()
- const {
- return base::i18n::UNKNOWN_DIRECTION;
-}
-
void FakeInputMethodContext::OnTextInputTypeChanged(
ui::TextInputType /* text_input_type */) {
}
diff --git a/chromium/ui/base/ime/linux/fake_input_method_context.h b/chromium/ui/base/ime/linux/fake_input_method_context.h
index 9d9681a1e7b..67210c13e3d 100644
--- a/chromium/ui/base/ime/linux/fake_input_method_context.h
+++ b/chromium/ui/base/ime/linux/fake_input_method_context.h
@@ -17,7 +17,6 @@ class FakeInputMethodContext : public LinuxInputMethodContext {
// Overriden from ui::LinuxInputMethodContext
virtual bool DispatchKeyEvent(const ui::KeyEvent& key_event) OVERRIDE;
virtual void Reset() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() const OVERRIDE;
virtual void OnTextInputTypeChanged(ui::TextInputType text_input_type)
OVERRIDE;
virtual void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) OVERRIDE;
diff --git a/chromium/ui/base/ime/linux/linux_input_method_context.h b/chromium/ui/base/ime/linux/linux_input_method_context.h
index 2466afd1c73..0bcfd0a41f1 100644
--- a/chromium/ui/base/ime/linux/linux_input_method_context.h
+++ b/chromium/ui/base/ime/linux/linux_input_method_context.h
@@ -5,10 +5,9 @@
#ifndef UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_H_
#define UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_H_
-#include "base/i18n/rtl.h"
#include "base/strings/string16.h"
#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace gfx {
class Rect;
@@ -21,7 +20,7 @@ class KeyEvent;
// An interface of input method context for input method frameworks on
// GNU/Linux and likes.
-class UI_EXPORT LinuxInputMethodContext {
+class UI_BASE_EXPORT LinuxInputMethodContext {
public:
virtual ~LinuxInputMethodContext() {}
@@ -34,9 +33,6 @@ class UI_EXPORT LinuxInputMethodContext {
// before calling DispatchKeyEvent().
virtual void Reset() = 0;
- // Returns the text direction of the current keyboard layout or input method.
- virtual base::i18n::TextDirection GetInputTextDirection() const = 0;
-
// Notifies the context that the text input type has changed.
virtual void OnTextInputTypeChanged(TextInputType text_input_type) = 0;
@@ -46,7 +42,7 @@ class UI_EXPORT LinuxInputMethodContext {
};
// An interface of callback functions called from LinuxInputMethodContext.
-class UI_EXPORT LinuxInputMethodContextDelegate {
+class UI_BASE_EXPORT LinuxInputMethodContextDelegate {
public:
virtual ~LinuxInputMethodContextDelegate() {}
diff --git a/chromium/ui/base/ime/linux/linux_input_method_context_factory.h b/chromium/ui/base/ime/linux/linux_input_method_context_factory.h
index 8ce1ec2a6be..af2a3a0c61e 100644
--- a/chromium/ui/base/ime/linux/linux_input_method_context_factory.h
+++ b/chromium/ui/base/ime/linux/linux_input_method_context_factory.h
@@ -6,7 +6,7 @@
#define UI_BASE_IME_LINUX_LINUX_INPUT_METHOD_CONTEXT_FACTORY_H_
#include "base/memory/scoped_ptr.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -16,7 +16,7 @@ class LinuxInputMethodContextDelegate;
// An interface that lets different Linux platforms override the
// CreateInputMethodContext function declared here to return native input method
// contexts.
-class UI_EXPORT LinuxInputMethodContextFactory {
+class UI_BASE_EXPORT LinuxInputMethodContextFactory {
public:
// Returns the current active factory or NULL.
static const LinuxInputMethodContextFactory* instance();
diff --git a/chromium/ui/base/ime/mock_input_method.cc b/chromium/ui/base/ime/mock_input_method.cc
index c0a5c2a1f21..5ffc76fc1dc 100644
--- a/chromium/ui/base/ime/mock_input_method.cc
+++ b/chromium/ui/base/ime/mock_input_method.cc
@@ -4,6 +4,9 @@
#include "ui/base/ime/mock_input_method.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
+
namespace ui {
MockInputMethod::MockInputMethod(internal::InputMethodDelegate* delegate)
@@ -17,6 +20,9 @@ void MockInputMethod::SetDelegate(internal::InputMethodDelegate* delegate) {
}
void MockInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return;
+
if (text_input_client_ == client)
return;
text_input_client_ = client;
@@ -31,6 +37,9 @@ void MockInputMethod::DetachTextInputClient(TextInputClient* client) {
}
TextInputClient* MockInputMethod::GetTextInputClient() const {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return TextInputFocusManager::GetInstance()->GetFocusedTextInputClient();
+
return text_input_client_;
}
@@ -81,10 +90,6 @@ std::string MockInputMethod::GetInputLocale() {
return "";
}
-base::i18n::TextDirection MockInputMethod::GetInputTextDirection() {
- return base::i18n::UNKNOWN_DIRECTION;
-}
-
bool MockInputMethod::IsActive() {
return true;
}
@@ -105,6 +110,10 @@ bool MockInputMethod::IsCandidatePopupOpen() const {
return false;
}
+void MockInputMethod::ShowImeIfNeeded() {
+ FOR_EACH_OBSERVER(InputMethodObserver, observer_list_, OnShowImeIfNeeded());
+}
+
void MockInputMethod::AddObserver(InputMethodObserver* observer) {
observer_list_.AddObserver(observer);
}
diff --git a/chromium/ui/base/ime/mock_input_method.h b/chromium/ui/base/ime/mock_input_method.h
index 997c4aac516..7716065ce98 100644
--- a/chromium/ui/base/ime/mock_input_method.h
+++ b/chromium/ui/base/ime/mock_input_method.h
@@ -12,7 +12,7 @@
#include "base/observer_list.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_observer.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -23,7 +23,7 @@ class TextInputClient;
// of this class as the global input method with calling
// SetUpInputMethodFactoryForTesting() which is declared in
// ui/base/ime/input_method_factory.h
-class UI_EXPORT MockInputMethod : NON_EXPORTED_BASE(public InputMethod) {
+class UI_BASE_EXPORT MockInputMethod : NON_EXPORTED_BASE(public InputMethod) {
public:
explicit MockInputMethod(internal::InputMethodDelegate* delegate);
virtual ~MockInputMethod();
@@ -44,12 +44,12 @@ class UI_EXPORT MockInputMethod : NON_EXPORTED_BASE(public InputMethod) {
virtual void CancelComposition(const TextInputClient* client) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual TextInputType GetTextInputType() const OVERRIDE;
virtual TextInputMode GetTextInputMode() const OVERRIDE;
virtual bool CanComposeInline() const OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
virtual void AddObserver(InputMethodObserver* observer) OVERRIDE;
virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE;
diff --git a/chromium/ui/base/ime/remote_input_method_delegate_win.h b/chromium/ui/base/ime/remote_input_method_delegate_win.h
index 961ccb7cb3f..993faf860bb 100644
--- a/chromium/ui/base/ime/remote_input_method_delegate_win.h
+++ b/chromium/ui/base/ime/remote_input_method_delegate_win.h
@@ -8,7 +8,7 @@
#include <vector>
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -16,7 +16,7 @@ namespace internal {
// An interface implemented by the object to forward events that should be
// handled by the IME which is running in the remote metro_driver process.
-class UI_EXPORT RemoteInputMethodDelegateWin {
+class UI_BASE_EXPORT RemoteInputMethodDelegateWin {
public:
virtual ~RemoteInputMethodDelegateWin() {}
diff --git a/chromium/ui/base/ime/remote_input_method_win.cc b/chromium/ui/base/ime/remote_input_method_win.cc
index cc5fc20156c..9fad0adbd95 100644
--- a/chromium/ui/base/ime/remote_input_method_win.cc
+++ b/chromium/ui/base/ime/remote_input_method_win.cc
@@ -61,7 +61,7 @@ std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
if (chars_written <= 1 || arraysize(buffer) < chars_written)
return std::string();
std::string result;
- WideToUTF8(buffer, chars_written - 1, &result);
+ base::WideToUTF8(buffer, chars_written - 1, &result);
return result;
}
@@ -85,19 +85,24 @@ std::vector<gfx::Rect> GetCompositionCharacterBounds(
if (!client)
return std::vector<gfx::Rect>();
- if (!client->HasCompositionText()) {
- std::vector<gfx::Rect> caret;
- caret.push_back(client->GetCaretBounds());
- return caret;
- }
-
std::vector<gfx::Rect> bounds;
- for (uint32 i = 0;; ++i) {
- gfx::Rect rect;
- if (!client->GetCompositionCharacterBounds(i, &rect))
- break;
- bounds.push_back(rect);
+ if (client->HasCompositionText()) {
+ gfx::Range range;
+ if (client->GetCompositionTextRange(&range)) {
+ for (uint32 i = 0; i < range.length(); ++i) {
+ gfx::Rect rect;
+ if (!client->GetCompositionCharacterBounds(i, &rect))
+ break;
+ bounds.push_back(rect);
+ }
+ }
}
+
+ // Use the caret bounds as a fallback if no composition character bounds is
+ // available. One typical use case is PPAPI Flash, which does not support
+ // GetCompositionCharacterBounds at all. crbug.com/133472
+ if (bounds.empty())
+ bounds.push_back(client->GetCaretBounds());
return bounds;
}
@@ -185,7 +190,7 @@ class RemoteInputMethodWin : public InputMethod,
if (!text_input_client_)
return false;
text_input_client_->InsertChar(
- static_cast<char16>(native_key_event.wParam),
+ static_cast<base::char16>(native_key_event.wParam),
ui::GetModifiersFromKeyState());
return true;
}
@@ -199,9 +204,7 @@ class RemoteInputMethodWin : public InputMethod,
}
if (!delegate_)
return false;
- return delegate_->DispatchFabricatedKeyEventPostIME(event.type(),
- event.key_code(),
- event.flags());
+ return delegate_->DispatchKeyEventPostIME(event);
}
virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
@@ -250,20 +253,6 @@ class RemoteInputMethodWin : public InputMethod,
return language.append(1, '-').append(region);
}
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
- switch (PRIMARYLANGID(langid_)) {
- case LANG_ARABIC:
- case LANG_HEBREW:
- case LANG_PERSIAN:
- case LANG_SYRIAC:
- case LANG_UIGHUR:
- case LANG_URDU:
- return base::i18n::RIGHT_TO_LEFT;
- default:
- return base::i18n::LEFT_TO_RIGHT;
- }
- }
-
virtual bool IsActive() OVERRIDE {
return true; // always turned on
}
@@ -286,6 +275,9 @@ class RemoteInputMethodWin : public InputMethod,
return is_candidate_popup_open_;
}
+ virtual void ShowImeIfNeeded() OVERRIDE {
+ }
+
virtual void AddObserver(InputMethodObserver* observer) OVERRIDE {
observer_list_.AddObserver(observer);
}
@@ -308,6 +300,14 @@ class RemoteInputMethodWin : public InputMethod,
virtual void OnCandidatePopupChanged(bool visible) OVERRIDE {
is_candidate_popup_open_ = visible;
+ if (!text_input_client_)
+ return;
+ // TODO(kochi): Support 'update' case, in addition to show/hide.
+ // http://crbug.com/238585
+ if (visible)
+ text_input_client_->OnCandidateWindowShown();
+ else
+ text_input_client_->OnCandidateWindowHidden();
}
virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) OVERRIDE {
diff --git a/chromium/ui/base/ime/remote_input_method_win.h b/chromium/ui/base/ime/remote_input_method_win.h
index f8d9fc01762..5258f3d4eac 100644
--- a/chromium/ui/base/ime/remote_input_method_win.h
+++ b/chromium/ui/base/ime/remote_input_method_win.h
@@ -13,7 +13,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
@@ -32,7 +32,7 @@ struct CompositionText;
// metro_driver process via RemoteInputMethodDelegateWin.
// - Data retrieval from RemoteInputMethodPrivateWin is implemented with
// data cache. Whenever the IME state in the metro_driver process is changed,
-// RemoteRootWindowHostWin, which receives IPCs from metro_driver process,
+// RemoteWindowTreeHostWin, which receives IPCs from metro_driver process,
// will call RemoteInputMethodPrivateWin::OnCandidatePopupChanged and/or
// RemoteInputMethodPrivateWin::OnInputSourceChanged accordingly so that
// the state cache should be updated.
@@ -46,11 +46,11 @@ bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget);
// Returns the public interface of RemoteInputMethodWin.
// Caveats: Currently only one instance of RemoteInputMethodWin is able to run
// at the same time.
-UI_EXPORT scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
+UI_BASE_EXPORT scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
internal::InputMethodDelegate* delegate);
// Private interface of RemoteInputMethodWin.
-class UI_EXPORT RemoteInputMethodPrivateWin {
+class UI_BASE_EXPORT RemoteInputMethodPrivateWin {
public:
RemoteInputMethodPrivateWin();
@@ -72,9 +72,8 @@ class UI_EXPORT RemoteInputMethodPrivateWin {
virtual void OnCandidatePopupChanged(bool visible) = 0;
// Updates internal cache so that subsequent calls of
- // RemoteInputMethodWin::GetInputLocale and
- // RemoteInputMethodWin::GetInputTextDirection can return the correct
- // values based on remote IME activities in the metro_driver process.
+ // RemoteInputMethodWin::GetInputLocale can return the correct values based on
+ // remote IME activities in the metro_driver process.
virtual void OnInputSourceChanged(LANGID langid, bool is_ime) = 0;
// Handles composition-update events occurred in the metro_driver process.
diff --git a/chromium/ui/base/ime/remote_input_method_win_unittest.cc b/chromium/ui/base/ime/remote_input_method_win_unittest.cc
index 781516872c5..3fa8be0cf32 100644
--- a/chromium/ui/base/ime/remote_input_method_win_unittest.cc
+++ b/chromium/ui/base/ime/remote_input_method_win_unittest.cc
@@ -30,7 +30,10 @@ class MockTextInputClient : public DummyTextInputClient {
text_input_mode_(TEXT_INPUT_MODE_DEFAULT),
call_count_set_composition_text_(0),
call_count_insert_char_(0),
- call_count_insert_text_(0) {
+ call_count_insert_text_(0),
+ emulate_pepper_flash_(false),
+ is_candidate_window_shown_called_(false),
+ is_candidate_window_hidden_called_(false) {
}
size_t call_count_set_composition_text() const {
@@ -45,6 +48,12 @@ class MockTextInputClient : public DummyTextInputClient {
size_t call_count_insert_text() const {
return call_count_insert_text_;
}
+ bool is_candidate_window_shown_called() const {
+ return is_candidate_window_shown_called_;
+ }
+ bool is_candidate_window_hidden_called() const {
+ return is_candidate_window_hidden_called_;
+ }
void Reset() {
text_input_type_ = TEXT_INPUT_TYPE_NONE;
text_input_mode_ = TEXT_INPUT_MODE_DEFAULT;
@@ -54,6 +63,9 @@ class MockTextInputClient : public DummyTextInputClient {
call_count_insert_text_ = 0;
caret_bounds_ = gfx::Rect();
composition_character_bounds_.clear();
+ emulate_pepper_flash_ = false;
+ is_candidate_window_shown_called_ = false;
+ is_candidate_window_hidden_called_ = false;
}
void set_text_input_type(ui::TextInputType type) {
text_input_type_ = type;
@@ -68,6 +80,9 @@ class MockTextInputClient : public DummyTextInputClient {
const std::vector<gfx::Rect>& composition_character_bounds) {
composition_character_bounds_ = composition_character_bounds;
}
+ void set_emulate_pepper_flash(bool enabled) {
+ emulate_pepper_flash_ = enabled;
+ }
private:
// Overriden from DummyTextInputClient.
@@ -75,11 +90,11 @@ class MockTextInputClient : public DummyTextInputClient {
const ui::CompositionText& composition) OVERRIDE {
++call_count_set_composition_text_;
}
- virtual void InsertChar(char16 ch, int flags) OVERRIDE{
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {
inserted_text_.append(1, ch);
++call_count_insert_char_;
}
- virtual void InsertText(const string16& text) OVERRIDE{
+ virtual void InsertText(const base::string16& text) OVERRIDE {
inserted_text_.append(text);
++call_count_insert_text_;
}
@@ -94,6 +109,9 @@ class MockTextInputClient : public DummyTextInputClient {
}
virtual bool GetCompositionCharacterBounds(uint32 index,
gfx::Rect* rect) const OVERRIDE {
+ // Emulate the situation of crbug.com/328237.
+ if (emulate_pepper_flash_)
+ return false;
if (!rect || composition_character_bounds_.size() <= index)
return false;
*rect = composition_character_bounds_[index];
@@ -102,6 +120,18 @@ class MockTextInputClient : public DummyTextInputClient {
virtual bool HasCompositionText() const OVERRIDE {
return !composition_character_bounds_.empty();
}
+ virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE {
+ if (composition_character_bounds_.empty())
+ return false;
+ *range = gfx::Range(0, composition_character_bounds_.size());
+ return true;
+ }
+ virtual void OnCandidateWindowShown() OVERRIDE {
+ is_candidate_window_shown_called_ = true;
+ }
+ virtual void OnCandidateWindowHidden() OVERRIDE {
+ is_candidate_window_hidden_called_ = true;
+ }
ui::TextInputType text_input_type_;
ui::TextInputMode text_input_mode_;
@@ -111,6 +141,9 @@ class MockTextInputClient : public DummyTextInputClient {
size_t call_count_set_composition_text_;
size_t call_count_insert_char_;
size_t call_count_insert_text_;
+ bool emulate_pepper_flash_;
+ bool is_candidate_window_shown_called_;
+ bool is_candidate_window_hidden_called_;
DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
};
@@ -126,15 +159,9 @@ class MockInputMethodDelegate : public internal::InputMethodDelegate {
}
private:
- virtual bool DispatchKeyEventPostIME(
- const base::NativeEvent& native_key_event) OVERRIDE {
- EXPECT_TRUE(false) << "Not reach here";
- return true;
- }
- virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) OVERRIDE {
- fabricated_key_events_.push_back(key_code);
+ virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) OVERRIDE {
+ EXPECT_FALSE(event.HasNativeEvent());
+ fabricated_key_events_.push_back(event.key_code());
return true;
}
@@ -224,6 +251,8 @@ class MockInputMethodObserver : public InputMethodObserver {
virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
++on_input_method_destroyed_changed_;
}
+ virtual void OnShowImeIfNeeded() {
+ }
size_t on_text_input_state_changed_;
size_t on_input_method_destroyed_changed_;
@@ -260,14 +289,10 @@ TEST(RemoteInputMethodWinTest, OnInputSourceChanged) {
private_ptr->OnInputSourceChanged(
MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true);
EXPECT_EQ("ja-JP", input_method->GetInputLocale());
- EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
- input_method->GetInputTextDirection());
private_ptr->OnInputSourceChanged(
MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true);
EXPECT_EQ("ar-QA", input_method->GetInputLocale());
- EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
- input_method->GetInputTextDirection());
}
TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) {
@@ -280,11 +305,28 @@ TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) {
// Initial value
EXPECT_FALSE(input_method->IsCandidatePopupOpen());
+ // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
+ // focused text input client is NULL.
+ ASSERT_TRUE(input_method->GetTextInputClient() == NULL);
+ private_ptr->OnCandidatePopupChanged(false);
+ private_ptr->OnCandidatePopupChanged(true);
+
+ MockTextInputClient mock_text_input_client;
+ input_method->SetFocusedTextInputClient(&mock_text_input_client);
+
+ ASSERT_FALSE(mock_text_input_client.is_candidate_window_shown_called());
+ ASSERT_FALSE(mock_text_input_client.is_candidate_window_hidden_called());
+ mock_text_input_client.Reset();
+
private_ptr->OnCandidatePopupChanged(true);
EXPECT_TRUE(input_method->IsCandidatePopupOpen());
+ EXPECT_TRUE(mock_text_input_client.is_candidate_window_shown_called());
+ EXPECT_FALSE(mock_text_input_client.is_candidate_window_hidden_called());
private_ptr->OnCandidatePopupChanged(false);
EXPECT_FALSE(input_method->IsCandidatePopupOpen());
+ EXPECT_TRUE(mock_text_input_client.is_candidate_window_shown_called());
+ EXPECT_TRUE(mock_text_input_client.is_candidate_window_hidden_called());
}
TEST(RemoteInputMethodWinTest, CancelComposition) {
@@ -424,6 +466,38 @@ TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) {
}
}
+// Test case against crbug.com/328237.
+TEST(RemoteInputMethodWinTest, OnCaretBoundsChangedForPepperFlash) {
+ MockInputMethodDelegate delegate_;
+ MockTextInputClient mock_text_input_client;
+ scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
+ input_method->SetFocusedTextInputClient(&mock_text_input_client);
+
+ RemoteInputMethodPrivateWin* private_ptr =
+ RemoteInputMethodPrivateWin::Get(input_method.get());
+ ASSERT_TRUE(private_ptr != NULL);
+ MockRemoteInputMethodDelegateWin mock_remote_delegate;
+ private_ptr->SetRemoteDelegate(&mock_remote_delegate);
+
+ mock_remote_delegate.Reset();
+ mock_text_input_client.Reset();
+ mock_text_input_client.set_emulate_pepper_flash(true);
+
+ std::vector<gfx::Rect> caret_bounds;
+ caret_bounds.push_back(gfx::Rect(5, 15, 25, 35));
+ mock_text_input_client.set_caret_bounds(caret_bounds[0]);
+
+ std::vector<gfx::Rect> composition_bounds;
+ composition_bounds.push_back(gfx::Rect(10, 20, 30, 40));
+ composition_bounds.push_back(gfx::Rect(40, 30, 20, 10));
+ mock_text_input_client.set_composition_character_bounds(composition_bounds);
+ input_method->OnCaretBoundsChanged(&mock_text_input_client);
+ EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
+ // The caret bounds must be used when
+ // TextInputClient::GetCompositionCharacterBounds failed.
+ EXPECT_EQ(caret_bounds, mock_remote_delegate.composition_character_bounds());
+}
+
TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) {
MockInputMethodDelegate delegate_;
MockTextInputClient mock_text_input_client;
diff --git a/chromium/ui/base/ime/text_input_client.h b/chromium/ui/base/ime/text_input_client.h
index 8623064f3c0..ff1242fae51 100644
--- a/chromium/ui/base/ime/text_input_client.h
+++ b/chromium/ui/base/ime/text_input_client.h
@@ -11,7 +11,7 @@
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/range/range.h"
@@ -22,7 +22,7 @@ class Rect;
namespace ui {
// An interface implemented by a View that needs text input support.
-class UI_EXPORT TextInputClient {
+class UI_BASE_EXPORT TextInputClient {
public:
virtual ~TextInputClient();
@@ -71,16 +71,24 @@ class UI_EXPORT TextInputClient {
// Returns if the client supports inline composition currently.
virtual bool CanComposeInline() const = 0;
- // Returns current caret (insertion point) bounds relative to the screen
+ // Returns current caret (insertion point) bounds in the universal screen
// coordinates. If there is selection, then the selection bounds will be
// returned.
+ // Note: On Windows, the returned value is supposed to be DIP (Density
+ // Independent Pixel).
+ // TODO(ime): Have a clear spec whether the returned value is DIP or not.
+ // http://crbug.com/360334
virtual gfx::Rect GetCaretBounds() const = 0;
- // Retrieves the composition character boundary rectangle relative to the
+ // Retrieves the composition character boundary rectangle in the universal
// screen coordinates. The |index| is zero-based index of character position
// in composition text.
// Returns false if there is no composition text or |index| is out of range.
// The |rect| is not touched in the case of failure.
+ // Note: On Windows, the returned value is supposed to be DIP
+ // (Density Independent Pixel).
+ // TODO(ime): Have a clear spec whether the returned value is DIP or not.
+ // http://crbug.com/360334
virtual bool GetCompositionCharacterBounds(uint32 index,
gfx::Rect* rect) const = 0;
@@ -146,6 +154,10 @@ class UI_EXPORT TextInputClient {
// Ensure the caret is within |rect|. |rect| is in screen coordinates and
// may extend beyond the bounds of this TextInputClient.
+ // Note: On Windows, the returned value is supposed to be DIP (Density
+ // Independent Pixel).
+ // TODO(ime): Have a clear spec whether the returned value is DIP or not.
+ // http://crbug.com/360334
virtual void EnsureCaretInRect(const gfx::Rect& rect) = 0;
// Called when IME shows a candidate window.
@@ -154,6 +166,11 @@ class UI_EXPORT TextInputClient {
virtual void OnCandidateWindowUpdated() = 0;
// Called when IME hides the candidate window.
virtual void OnCandidateWindowHidden() = 0;
+
+ // Returns true if |command_id| is currently allowed to be executed.
+ virtual bool IsEditingCommandEnabled(int command_id) = 0;
+ // Execute the command specified by |command_id|.
+ virtual void ExecuteEditingCommand(int command_id) = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/ime/text_input_focus_manager.cc b/chromium/ui/base/ime/text_input_focus_manager.cc
new file mode 100644
index 00000000000..4fd7dcffb3c
--- /dev/null
+++ b/chromium/ui/base/ime/text_input_focus_manager.cc
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/ime/text_input_focus_manager.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+
+namespace ui {
+
+TextInputFocusManager* TextInputFocusManager::GetInstance() {
+ TextInputFocusManager* instance = Singleton<TextInputFocusManager>::get();
+ DCHECK(instance->thread_checker_.CalledOnValidThread());
+ return instance;
+}
+
+TextInputClient* TextInputFocusManager::GetFocusedTextInputClient() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return focused_text_input_client_;
+}
+
+void TextInputFocusManager::FocusTextInputClient(
+ TextInputClient* text_input_client) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ focused_text_input_client_ = text_input_client;
+}
+
+void TextInputFocusManager::BlurTextInputClient(
+ TextInputClient* text_input_client) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (focused_text_input_client_ == text_input_client)
+ focused_text_input_client_ = NULL;
+}
+
+TextInputFocusManager::TextInputFocusManager()
+ : focused_text_input_client_(NULL) {}
+
+TextInputFocusManager::~TextInputFocusManager() {}
+
+} // namespace ui
diff --git a/chromium/ui/base/ime/text_input_focus_manager.h b/chromium/ui/base/ime/text_input_focus_manager.h
new file mode 100644
index 00000000000..22f47e3e419
--- /dev/null
+++ b/chromium/ui/base/ime/text_input_focus_manager.h
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_TEXT_INPUT_FOCUS_MANAGER_H_
+#define UI_BASE_IME_TEXT_INPUT_FOCUS_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "ui/base/ui_base_export.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace ui {
+
+class TextInputClient;
+
+// Manages the focused TextInputClient across windows and their contents.
+class UI_BASE_EXPORT TextInputFocusManager {
+ public:
+ static TextInputFocusManager* GetInstance();
+
+ // Returns the currently focused text input client or NULL.
+ TextInputClient* GetFocusedTextInputClient();
+
+ // Changes the text input focus to |text_input_client|.
+ void FocusTextInputClient(TextInputClient* text_input_client);
+
+ // Removes the text input focus from |text_input_client|. If
+ // |text_input_client| was not focused, does nothing.
+ void BlurTextInputClient(TextInputClient* text_input_client);
+
+ private:
+ friend struct DefaultSingletonTraits<TextInputFocusManager>;
+
+ TextInputFocusManager();
+ ~TextInputFocusManager();
+
+ TextInputClient* focused_text_input_client_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextInputFocusManager);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_TEXT_INPUT_FOCUS_MANAGER_H_
diff --git a/chromium/ui/base/ime/win/imm32_manager.cc b/chromium/ui/base/ime/win/imm32_manager.cc
index 093b0109366..7ad2d875e4c 100644
--- a/chromium/ui/base/ime/win/imm32_manager.cc
+++ b/chromium/ui/base/ime/win/imm32_manager.cc
@@ -4,8 +4,6 @@
#include "ui/base/ime/win/imm32_manager.h"
-#include <atlbase.h>
-#include <atlcom.h>
#include <msctf.h>
#include "base/basictypes.h"
@@ -24,7 +22,7 @@
// Following code requires wchar_t to be same as char16. It should always be
// true on Windows.
-COMPILE_ASSERT(sizeof(wchar_t) == sizeof(char16), wchar_t__char16_diff);
+COMPILE_ASSERT(sizeof(wchar_t) == sizeof(base::char16), wchar_t__char16_diff);
///////////////////////////////////////////////////////////////////////////////
// IMM32Manager
@@ -85,10 +83,11 @@ void GetCompositionUnderlines(HIMC imm_context,
underline.end_offset = clause_data[i+1];
underline.color = SK_ColorBLACK;
underline.thick = false;
+ underline.background_color = SK_ColorTRANSPARENT;
// Use thick underline for the target clause.
- if (underline.start_offset >= static_cast<unsigned>(target_start) &&
- underline.end_offset <= static_cast<unsigned>(target_end)) {
+ if (underline.start_offset >= static_cast<uint32>(target_start) &&
+ underline.end_offset <= static_cast<uint32>(target_end)) {
underline.thick = true;
}
underlines->push_back(underline);
@@ -344,21 +343,22 @@ void IMM32Manager::GetCompositionInfo(HIMC imm_context, LPARAM lparam,
if (!composition->underlines.size()) {
CompositionUnderline underline;
underline.color = SK_ColorBLACK;
+ underline.background_color = SK_ColorTRANSPARENT;
if (target_start > 0) {
- underline.start_offset = 0;
- underline.end_offset = target_start;
+ underline.start_offset = 0U;
+ underline.end_offset = static_cast<uint32>(target_start);
underline.thick = false;
composition->underlines.push_back(underline);
}
if (target_end > target_start) {
- underline.start_offset = target_start;
- underline.end_offset = target_end;
+ underline.start_offset = static_cast<uint32>(target_start);
+ underline.end_offset = static_cast<uint32>(target_end);
underline.thick = true;
composition->underlines.push_back(underline);
}
if (target_end < length) {
- underline.start_offset = target_end;
- underline.end_offset = length;
+ underline.start_offset = static_cast<uint32>(target_end);
+ underline.end_offset = static_cast<uint32>(length);
underline.thick = false;
composition->underlines.push_back(underline);
}
@@ -368,7 +368,7 @@ void IMM32Manager::GetCompositionInfo(HIMC imm_context, LPARAM lparam,
bool IMM32Manager::GetString(HIMC imm_context,
WPARAM lparam,
int type,
- string16* result) {
+ base::string16* result) {
if (!(lparam & type))
return false;
LONG string_size = ::ImmGetCompositionString(imm_context, type, NULL, 0);
@@ -381,7 +381,7 @@ bool IMM32Manager::GetString(HIMC imm_context,
}
bool IMM32Manager::GetResult(
- HWND window_handle, LPARAM lparam, string16* result) {
+ HWND window_handle, LPARAM lparam, base::string16* result) {
bool ret = false;
HIMC imm_context = ::ImmGetContext(window_handle);
if (imm_context) {
@@ -487,7 +487,7 @@ std::string IMM32Manager::GetInputLanguageName() const {
return std::string();
std::string language;
- WideToUTF8(buffer, length - 1, &language);
+ base::WideToUTF8(buffer, length - 1, &language);
if (SUBLANGID(input_language_id_) == SUBLANG_NEUTRAL)
return language;
@@ -498,15 +498,10 @@ std::string IMM32Manager::GetInputLanguageName() const {
return language;
std::string region;
- WideToUTF8(buffer, length - 1, &region);
+ base::WideToUTF8(buffer, length - 1, &region);
return language.append(1, '-').append(region);
}
-base::i18n::TextDirection IMM32Manager::GetTextDirection() const {
- return IsRTLPrimaryLangID(PRIMARYLANGID(input_language_id_)) ?
- base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
-}
-
void IMM32Manager::SetTextInputMode(HWND window_handle,
TextInputMode input_mode) {
if (input_mode == ui::TEXT_INPUT_MODE_DEFAULT)
diff --git a/chromium/ui/base/ime/win/imm32_manager.h b/chromium/ui/base/ime/win/imm32_manager.h
index 17892cb7640..3a969fd64a6 100644
--- a/chromium/ui/base/ime/win/imm32_manager.h
+++ b/chromium/ui/base/ime/win/imm32_manager.h
@@ -14,7 +14,7 @@
#include "base/i18n/rtl.h"
#include "base/strings/string16.h"
#include "ui/base/ime/text_input_mode.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -74,7 +74,7 @@ struct CompositionText;
// hand, we can NEVER disable either TSF or CUAS in Windows Vista, i.e.
// THIS CLASS IS NOT ONLY USED ON THE INPUT CONTEXTS OF EAST-ASIAN
// LANGUAGES BUT ALSO USED ON THE INPUT CONTEXTS OF ALL LANGUAGES.
-class UI_EXPORT IMM32Manager {
+class UI_BASE_EXPORT IMM32Manager {
public:
IMM32Manager();
virtual ~IMM32Manager();
@@ -154,7 +154,7 @@ class UI_EXPORT IMM32Manager {
// the same parameter of a WM_IME_COMPOSITION message handler.
// This parameter is used for checking if the ongoing composition has
// its result string,
- // * result [out] (string16)
+ // * result [out] (base::string16)
// Represents the object contains the composition result.
// Return values
// * true
@@ -164,7 +164,7 @@ class UI_EXPORT IMM32Manager {
// Remarks
// This function is designed for being called from WM_IME_COMPOSITION
// message handlers.
- bool GetResult(HWND window_handle, LPARAM lparam, string16* result);
+ bool GetResult(HWND window_handle, LPARAM lparam, base::string16* result);
// Retrieves the current composition status of the ongoing composition.
// Parameters
@@ -237,9 +237,6 @@ class UI_EXPORT IMM32Manager {
// Returns BCP-47 tag name of the current input language.
std::string GetInputLanguageName() const;
- // Returns the text direction of the current input language.
- base::i18n::TextDirection GetTextDirection() const;
-
// Sets conversion status corresponding to |input_mode|.
virtual void SetTextInputMode(HWND window_handle, TextInputMode input_mode);
@@ -274,7 +271,10 @@ class UI_EXPORT IMM32Manager {
void CompleteComposition(HWND window_handle, HIMC imm_context);
// Retrieves a string from the IMM.
- bool GetString(HIMC imm_context, WPARAM lparam, int type, string16* result);
+ bool GetString(HIMC imm_context,
+ WPARAM lparam,
+ int type,
+ base::string16* result);
private:
// Represents whether or not there is an ongoing composition in a browser
diff --git a/chromium/ui/base/ime/win/mock_tsf_bridge.cc b/chromium/ui/base/ime/win/mock_tsf_bridge.cc
deleted file mode 100644
index a26a81b1ebb..00000000000
--- a/chromium/ui/base/ime/win/mock_tsf_bridge.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/win/mock_tsf_bridge.h"
-
-#include "ui/base/ime/text_input_client.h"
-#include "base/logging.h"
-
-namespace ui {
-
-MockTSFBridge::MockTSFBridge()
- : enable_ime_call_count_(0),
- disalbe_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_(NULL),
- focused_window_(NULL),
- latest_text_input_type_(TEXT_INPUT_TYPE_NONE) {
-}
-
-MockTSFBridge::~MockTSFBridge() {
-}
-
-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_ = NULL;
- focused_window_ = NULL;
-}
-
-base::win::ScopedComPtr<ITfThreadMgr> MockTSFBridge::GetThreadManager() {
- return thread_manager_;
-}
-
-TextInputClient* MockTSFBridge::GetFocusedTextInputClient() const {
- return text_input_client_;
-}
-
-void MockTSFBridge::Reset() {
- enable_ime_call_count_ = 0;
- disalbe_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_ = NULL;
- focused_window_ = NULL;
- 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
deleted file mode 100644
index 1fdfc8ae049..00000000000
--- a/chromium/ui/base/ime/win/mock_tsf_bridge.h
+++ /dev/null
@@ -1,100 +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_IME_WIN_MOCK_TSF_BRIDGE_H_
-#define UI_BASE_IME_WIN_MOCK_TSF_BRIDGE_H_
-
-#include <msctf.h>
-
-#include "base/compiler_specific.h"
-#include "base/win/scoped_comptr.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();
- virtual ~MockTSFBridge();
-
- // TSFBridge:
- virtual bool CancelComposition() OVERRIDE;
- virtual bool ConfirmComposition() OVERRIDE;
- virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
- virtual void OnTextLayoutChanged() OVERRIDE;
- virtual void SetFocusedClient(HWND focused_window,
- TextInputClient* client) OVERRIDE;
- virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE;
- virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE;
- virtual TextInputClient* GetFocusedTextInputClient() const OVERRIDE;
-
- // Resets MockTSFBridge state including function call counter.
- void Reset();
-
- // Call count of EnableIME().
- int enable_ime_call_count() const { return enable_ime_call_count_; }
-
- // Call count of DisableIME().
- int disalbe_ime_call_count() const { return disalbe_ime_call_count_; }
-
- // Call count of CancelComposition().
- int cancel_composition_call_count() const {
- return cancel_composition_call_count_;
- }
-
- // Call count of ConfirmComposition().
- int confirm_composition_call_count() const {
- return confirm_composition_call_count_;
- }
-
- // Call count of OnTextLayoutChanged().
- int on_text_layout_changed() const {
- return on_text_layout_changed_;
- }
-
- // Call count of AssociateFocus().
- int associate_focus_call_count() const { return associate_focus_call_count_; }
-
- // Call count of SetFocusClient().
- int set_focused_client_call_count() const {
- return set_focused_client_call_count_;
- }
-
- // Call count of RemoveFocusedClient().
- int 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:
- int enable_ime_call_count_;
- int disalbe_ime_call_count_;
- int cancel_composition_call_count_;
- int confirm_composition_call_count_;
- int on_text_layout_changed_;
- int associate_focus_call_count_;
- int set_focused_client_call_count_;
- int remove_focused_client_call_count_;
- TextInputClient* text_input_client_;
- HWND focused_window_;
- TextInputType latest_text_input_type_;
- base::win::ScopedComPtr<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/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
deleted file mode 100644
index bf2820323ef..00000000000
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ /dev/null
@@ -1,558 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <msctf.h>
-
-#include <map>
-
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_local_storage.h"
-#include "base/win/scoped_comptr.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"
-
-namespace ui {
-
-namespace {
-
-// We use thread local storage for TSFBridge lifespan management.
-base::ThreadLocalStorage::StaticSlot tls_tsf_bridge = TLS_INITIALIZER;
-
-
-// TsfBridgeDelegate -----------------------------------------------------------
-
-// A TLS implementation of TSFBridge.
-class TSFBridgeDelegate : public TSFBridge {
- public:
- TSFBridgeDelegate();
- virtual ~TSFBridgeDelegate();
-
- bool Initialize();
-
- // TsfBridge:
- virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE;
- virtual void OnTextLayoutChanged() OVERRIDE;
- virtual bool CancelComposition() OVERRIDE;
- virtual bool ConfirmComposition() OVERRIDE;
- virtual void SetFocusedClient(HWND focused_window,
- TextInputClient* client) OVERRIDE;
- virtual void RemoveFocusedClient(TextInputClient* client) OVERRIDE;
- virtual base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() OVERRIDE;
- virtual 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 NULL 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) {}
- base::win::ScopedComPtr<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.
- base::win::ScopedComPtr<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_;
-
- // Current focused text input client. Do not free |client_|.
- TextInputClient* client_;
-
- // Represents the window that is currently owns text input focus.
- HWND attached_window_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(TSFBridgeDelegate);
-};
-
-TSFBridgeDelegate::TSFBridgeDelegate()
- : client_id_(TF_CLIENTID_NULL),
- client_(NULL),
- attached_window_handle_(NULL) {
-}
-
-TSFBridgeDelegate::~TSFBridgeDelegate() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- if (!IsInitialized())
- return;
- for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
- it != tsf_document_map_.end(); ++it) {
- base::win::ScopedComPtr<ITfContext> context;
- base::win::ScopedComPtr<ITfSource> source;
- if (it->second.cookie != TF_INVALID_COOKIE &&
- SUCCEEDED(it->second.document_manager->GetBase(context.Receive())) &&
- SUCCEEDED(source.QueryFrom(context))) {
- source->UnadviseSink(it->second.cookie);
- }
- }
- tsf_document_map_.clear();
-
- client_id_ = TF_CLIENTID_NULL;
-}
-
-bool TSFBridgeDelegate::Initialize() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- if (client_id_ != TF_CLIENTID_NULL) {
- DVLOG(1) << "Already initialized.";
- return false;
- }
-
- if (FAILED(thread_manager_.CreateInstance(CLSID_TF_ThreadMgr))) {
- 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.
- base::win::ScopedComPtr<ITfCompartmentMgr> thread_compartment_manager;
- if (FAILED(thread_compartment_manager.QueryFrom(thread_manager_))) {
- DVLOG(1) << "Failed to get ITfCompartmentMgr.";
- return false;
- }
-
- base::win::ScopedComPtr<ITfCompartment> sentence_compartment;
- if (FAILED(thread_compartment_manager->GetCompartment(
- GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE,
- sentence_compartment.Receive()))) {
- 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))) {
- DVLOG(1) << "Failed to change the sentence mode.";
- return false;
- }
-
- return true;
-}
-
-void TSFBridgeDelegate::OnTextInputTypeChanged(const TextInputClient* client) {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- 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 TSFBridgeDelegate::OnTextLayoutChanged() {
- TSFDocument* document = GetAssociatedDocument();
- if (!document)
- return;
- if (!document->text_store)
- return;
- document->text_store->SendOnLayoutChange();
-}
-
-bool TSFBridgeDelegate::CancelComposition() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- DCHECK(IsInitialized());
-
- TSFDocument* document = GetAssociatedDocument();
- if (!document)
- return false;
- if (!document->text_store)
- return false;
-
- return document->text_store->CancelComposition();
-}
-
-bool TSFBridgeDelegate::ConfirmComposition() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- DCHECK(IsInitialized());
-
- TSFDocument* document = GetAssociatedDocument();
- if (!document)
- return false;
- if (!document->text_store)
- return false;
-
- return document->text_store->ConfirmComposition();
-}
-
-void TSFBridgeDelegate::SetFocusedClient(HWND focused_window,
- TextInputClient* client) {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- 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() == NULL)
- continue;
- it->second.text_store->SetFocusedTextInputClient(focused_window,
- client);
- }
-
- // Synchronize text input type state.
- OnTextInputTypeChanged(client);
-}
-
-void TSFBridgeDelegate::RemoveFocusedClient(TextInputClient* client) {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- DCHECK(IsInitialized());
- if (client_ != client)
- return;
- ClearAssociateFocus();
- client_ = NULL;
- attached_window_handle_ = NULL;
- for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
- it != tsf_document_map_.end(); ++it) {
- if (it->second.text_store.get() == NULL)
- continue;
- it->second.text_store->SetFocusedTextInputClient(NULL, NULL);
- }
-}
-
-TextInputClient* TSFBridgeDelegate::GetFocusedTextInputClient() const {
- return client_;
-}
-
-base::win::ScopedComPtr<ITfThreadMgr> TSFBridgeDelegate::GetThreadManager() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
- DCHECK(IsInitialized());
- return thread_manager_;
-}
-
-bool TSFBridgeDelegate::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;
-
- base::win::ScopedComPtr<ITfSource> source;
- if (FAILED(source.QueryFrom(*context))) {
- 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 TSFBridgeDelegate::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];
- base::win::ScopedComPtr<ITfContext> context;
- base::win::ScopedComPtr<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 ? NULL : &cookie;
- scoped_refptr<TSFTextStore> text_store =
- use_null_text_store ? NULL : new TSFTextStore();
- if (!CreateDocumentManager(text_store,
- document_manager.Receive(),
- context.Receive(),
- 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))
- 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 TSFBridgeDelegate::InitializeDisabledContext(ITfContext* context) {
- base::win::ScopedComPtr<ITfCompartmentMgr> compartment_mgr;
- if (FAILED(compartment_mgr.QueryFrom(context))) {
- DVLOG(1) << "Failed to get CompartmentMgr.";
- return false;
- }
-
- base::win::ScopedComPtr<ITfCompartment> disabled_compartment;
- if (FAILED(compartment_mgr->GetCompartment(
- GUID_COMPARTMENT_KEYBOARD_DISABLED,
- disabled_compartment.Receive()))) {
- 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))) {
- DVLOG(1) << "Failed to disable the DocumentMgr.";
- return false;
- }
-
- base::win::ScopedComPtr<ITfCompartment> empty_context;
- if (FAILED(compartment_mgr->GetCompartment(GUID_COMPARTMENT_EMPTYCONTEXT,
- empty_context.Receive()))) {
- DVLOG(1) << "Failed to get empty context compartment.";
- return false;
- }
- base::win::ScopedVariant empty_context_variant;
- empty_context_variant.Set(static_cast<int32>(1));
- if (FAILED(empty_context->SetValue(client_id_, &empty_context_variant))) {
- DVLOG(1) << "Failed to set empty context.";
- return false;
- }
-
- return true;
-}
-
-bool TSFBridgeDelegate::IsFocused(ITfDocumentMgr* document_manager) {
- base::win::ScopedComPtr<ITfDocumentMgr> focused_document_manager;
- if (FAILED(thread_manager_->GetFocus(focused_document_manager.Receive())))
- return false;
- return focused_document_manager.IsSameObject(document_manager);
-}
-
-bool TSFBridgeDelegate::IsInitialized() {
- return client_id_ != TF_CLIENTID_NULL;
-}
-
-void TSFBridgeDelegate::UpdateAssociateFocus() {
- if (attached_window_handle_ == NULL)
- return;
- TSFDocument* document = GetAssociatedDocument();
- if (document == NULL) {
- 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.
- base::win::ScopedComPtr<ITfDocumentMgr> previous_focus;
- thread_manager_->AssociateFocus(
- attached_window_handle_, document->document_manager.get(),
- previous_focus.Receive());
-}
-
-void TSFBridgeDelegate::ClearAssociateFocus() {
- if (attached_window_handle_ == NULL)
- return;
- base::win::ScopedComPtr<ITfDocumentMgr> previous_focus;
- thread_manager_->AssociateFocus(
- attached_window_handle_, NULL, previous_focus.Receive());
-}
-
-TSFBridgeDelegate::TSFDocument* TSFBridgeDelegate::GetAssociatedDocument() {
- if (!client_)
- return NULL;
- 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 NULL;
- }
- return &it->second;
-}
-
-} // namespace
-
-
-// TsfBridge -----------------------------------------------------------------
-
-TSFBridge::TSFBridge() {
-}
-
-TSFBridge::~TSFBridge() {
-}
-
-// static
-bool TSFBridge::Initialize() {
- if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
- DVLOG(1) << "Do not use TSFBridge without UI thread.";
- return false;
- }
- if (!tls_tsf_bridge.initialized()) {
- tls_tsf_bridge.Initialize(TSFBridge::Finalize);
- }
- TSFBridgeDelegate* delegate =
- static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get());
- if (delegate)
- return true;
- delegate = new TSFBridgeDelegate();
- tls_tsf_bridge.Set(delegate);
- return delegate->Initialize();
-}
-
-// static
-TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) {
- if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
- DVLOG(1) << "Do not use TSFBridge without UI thread.";
- return NULL;
- }
- TSFBridge* old_bridge = TSFBridge::GetInstance();
- tls_tsf_bridge.Set(bridge);
- return old_bridge;
-}
-
-// static
-void TSFBridge::Shutdown() {
- if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
- DVLOG(1) << "Do not use TSFBridge without UI thread.";
- }
- if (tls_tsf_bridge.initialized()) {
- TSFBridgeDelegate* delegate =
- static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get());
- tls_tsf_bridge.Set(NULL);
- delete delegate;
- }
-}
-
-// static
-TSFBridge* TSFBridge::GetInstance() {
- if (base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
- DVLOG(1) << "Do not use TSFBridge without UI thread.";
- return NULL;
- }
- TSFBridgeDelegate* delegate =
- static_cast<TSFBridgeDelegate*>(tls_tsf_bridge.Get());
- DCHECK(delegate) << "Do no call GetInstance before TSFBridge::Initialize.";
- return delegate;
-}
-
-// static
-void TSFBridge::Finalize(void* data) {
- TSFBridgeDelegate* delegate = static_cast<TSFBridgeDelegate*>(data);
- delete delegate;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_bridge.h b/chromium/ui/base/ime/win/tsf_bridge.h
deleted file mode 100644
index 6256fac166a..00000000000
--- a/chromium/ui/base/ime/win/tsf_bridge.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_WIN_TSF_BRIDGE_H_
-#define UI_BASE_IME_WIN_TSF_BRIDGE_H_
-
-#include <Windows.h>
-#include <msctf.h>
-
-#include "base/basictypes.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/base/ui_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_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 bool 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 base::win::ScopedComPtr<ITfThreadMgr> GetThreadManager() = 0;
-
- // Returns the focused text input client.
- virtual TextInputClient* GetFocusedTextInputClient() const = 0;
-
- protected:
- // Uses GetInstance() instead.
- TSFBridge();
-
- private:
- // Releases TLS instance.
- static void Finalize(void* data);
-
- 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
deleted file mode 100644
index 4f34a048eec..00000000000
--- a/chromium/ui/base/ime/win/tsf_event_router.cc
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/win/tsf_event_router.h"
-
-#include <msctf.h>
-#include <set>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/metro.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 NULL.
- 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.
- base::win::ScopedComPtr<ITfContext> context_;
-
- // The ITfSource associated with |context_|.
- base::win::ScopedComPtr<ITfSource> context_source_;
-
- // The cookie for |context_source_|.
- DWORD context_source_cookie_;
-
- // A UIElementMgr associated with this class.
- base::win::ScopedComPtr<ITfUIElementMgr> ui_element_manager_;
-
- // The ITfSouce associated with |ui_element_manager_|.
- base::win::ScopedComPtr<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_;
-
- TSFEventRouter* router_;
- gfx::Range previous_composition_range_;
-
- DISALLOW_COPY_AND_ASSIGN(Delegate);
-};
-
-TSFEventRouter::Delegate::Delegate()
- : context_source_cookie_(TF_INVALID_COOKIE),
- ui_source_cookie_(TF_INVALID_COOKIE),
- router_(NULL),
- previous_composition_range_(gfx::Range::InvalidRange()) {
-}
-
-TSFEventRouter::Delegate::~Delegate() {}
-
-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.
- base::win::ScopedComPtr<IEnumTfRanges> ranges;
- if (FAILED(edit_record->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0,
- ranges.Receive())))
- return S_OK; // Don't care about failures.
-
- ULONG fetched_count = 0;
- base::win::ScopedComPtr<ITfRange> range;
- if (FAILED(ranges->Next(1, range.Receive(), &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_.Release();
-
- if (context_source_) {
- context_source_->UnadviseSink(context_source_cookie_);
- context_source_.Release();
- }
- context_source_cookie_ = TF_INVALID_COOKIE;
-
- ui_element_manager_.Release();
- if (ui_source_) {
- ui_source_->UnadviseSink(ui_source_cookie_);
- ui_source_.Release();
- }
- ui_source_cookie_ = TF_INVALID_COOKIE;
-
- if (!thread_manager)
- return;
-
- base::win::ScopedComPtr<ITfDocumentMgr> document_manager;
- if (FAILED(thread_manager->GetFocus(document_manager.Receive())) ||
- !document_manager.get() ||
- FAILED(document_manager->GetBase(context_.Receive())) ||
- FAILED(context_source_.QueryFrom(context_)))
- return;
- context_source_->AdviseSink(IID_ITfTextEditSink,
- static_cast<ITfTextEditSink*>(this),
- &context_source_cookie_);
-
- if (FAILED(ui_element_manager_.QueryFrom(thread_manager)) ||
- FAILED(ui_source_.QueryFrom(ui_element_manager_)))
- return;
- ui_source_->AdviseSink(IID_ITfUIElementSink,
- static_cast<ITfUIElementSink*>(this),
- &ui_source_cookie_);
-}
-
-bool TSFEventRouter::Delegate::IsImeComposing() {
- return context_ && GetCompositionRange(context_).IsValid();
-}
-
-// static
-gfx::Range TSFEventRouter::Delegate::GetCompositionRange(
- ITfContext* context) {
- DCHECK(context);
- base::win::ScopedComPtr<ITfContextComposition> context_composition;
- if (FAILED(context_composition.QueryFrom(context)))
- return gfx::Range::InvalidRange();
- base::win::ScopedComPtr<IEnumITfCompositionView> enum_composition_view;
- if (FAILED(context_composition->EnumCompositions(
- enum_composition_view.Receive())))
- return gfx::Range::InvalidRange();
- base::win::ScopedComPtr<ITfCompositionView> composition_view;
- if (enum_composition_view->Next(1, composition_view.Receive(),
- NULL) != S_OK)
- return gfx::Range::InvalidRange();
-
- base::win::ScopedComPtr<ITfRange> range;
- if (FAILED(composition_view->GetRange(range.Receive())))
- return gfx::Range::InvalidRange();
-
- base::win::ScopedComPtr<ITfRangeACP> range_acp;
- if (FAILED(range_acp.QueryFrom(range)))
- 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());
- base::win::ScopedComPtr<ITfUIElement> ui_element;
- if (FAILED(ui_element_manager_->GetUIElement(element_id,
- ui_element.Receive())))
- return false;
- base::win::ScopedComPtr<ITfCandidateListUIElement> candidate_list_ui_element;
- return SUCCEEDED(candidate_list_ui_element.QueryFrom(ui_element));
-}
-
-
-// TSFEventRouter ------------------------------------------------------------
-
-TSFEventRouter::TSFEventRouter(TSFEventRouterObserver* observer)
- : observer_(observer),
- delegate_(NULL) {
- DCHECK(base::win::IsTSFAwareRequired())
- << "Do not use TSFEventRouter without TSF environment.";
- 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(NULL);
- delegate_->SetRouter(NULL);
- }
-}
-
-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
deleted file mode 100644
index 04a2a1e9eb0..00000000000
--- a/chromium/ui/base/ime/win/tsf_event_router.h
+++ /dev/null
@@ -1,81 +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_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/basictypes.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_export.h"
-#include "ui/gfx/range/range.h"
-
-struct ITfDocumentMgr;
-
-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 monitores TSF related events and forwards them to given
-// |observer|.
-class UI_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_input_scope.cc b/chromium/ui/base/ime/win/tsf_input_scope.cc
index 06481e9d8f0..f40f928a5f7 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.cc
+++ b/chromium/ui/base/ime/win/tsf_input_scope.cc
@@ -29,7 +29,7 @@ void AppendNonTrivialInputScope(std::vector<InputScope>* input_scopes,
input_scopes->push_back(input_scope);
}
-class TSFInputScope : public ITfInputScope {
+class TSFInputScope FINAL : public ITfInputScope {
public:
explicit TSFInputScope(const std::vector<InputScope>& input_scopes)
: input_scopes_(input_scopes),
@@ -116,7 +116,7 @@ SetInputScopesFunc g_set_input_scopes = NULL;
bool g_get_proc_done = false;
SetInputScopesFunc GetSetInputScopes() {
- DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
+ DCHECK(base::MessageLoopForUI::IsCurrent());
// Thread safety is not required because this function is under UI thread.
if (!g_get_proc_done) {
g_get_proc_done = true;
diff --git a/chromium/ui/base/ime/win/tsf_input_scope.h b/chromium/ui/base/ime/win/tsf_input_scope.h
index 2e5856c60d8..536d395dce1 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.h
+++ b/chromium/ui/base/ime/win/tsf_input_scope.h
@@ -12,7 +12,7 @@
#include "base/basictypes.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
namespace tsf_inputscope {
@@ -20,8 +20,9 @@ namespace tsf_inputscope {
// Returns InputScope list corresoponding to ui::TextInputType and
// ui::TextInputMode.
// This function is only used from following functions but declared for test.
-UI_EXPORT std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
- TextInputMode text_input_mode);
+UI_BASE_EXPORT std::vector<InputScope> GetInputScopes(
+ TextInputType text_input_type,
+ TextInputMode text_input_mode);
// Returns an instance of ITfInputScope, which is the Windows-specific
// category representation corresponding to ui::TextInputType and
@@ -29,14 +30,14 @@ UI_EXPORT std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
// in the target field.
// The returned instance has 0 reference count. The caller must maintain its
// reference count.
-UI_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type,
- TextInputMode text_input_mode);
+UI_BASE_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type,
+ TextInputMode text_input_mode);
// A wrapper of the SetInputScopes API exported by msctf.dll.
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms629026.aspx
// Does nothing on Windows XP in case TSF is disabled.
// NOTE: For TSF-aware window, you should use ITfInputScope instead.
-UI_EXPORT void SetInputScopeForTsfUnawareWindow(
+UI_BASE_EXPORT void SetInputScopeForTsfUnawareWindow(
HWND window_handle,
TextInputType text_input_type,
TextInputMode text_input_mode);
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
deleted file mode 100644
index 0ef34b5be89..00000000000
--- a/chromium/ui/base/ime/win/tsf_text_store.cc
+++ /dev/null
@@ -1,923 +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.
-
-#define INITGUID // required for GUID_PROP_INPUTSCOPE
-#include "ui/base/ime/win/tsf_text_store.h"
-
-#include <InputScope.h>
-#include <OleCtl.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/rect.h"
-
-namespace ui {
-namespace {
-
-// We support only one view.
-const TsViewCookie kViewCookie = 1;
-
-} // namespace
-
-TSFTextStore::TSFTextStore()
- : ref_count_(0),
- text_store_acp_sink_mask_(0),
- window_handle_(NULL),
- text_input_client_(NULL),
- committed_size_(0),
- edit_flag_(false),
- current_lock_type_(0) {
- if (FAILED(category_manager_.CreateInstance(CLSID_TF_CategoryMgr))) {
- LOG(FATAL) << "Failed to initialize CategoryMgr.";
- return;
- }
- if (FAILED(display_attribute_manager_.CreateInstance(
- CLSID_TF_DisplayAttributeMgr))) {
- 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 = NULL;
- 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_.IsSameObject(unknown)) {
- text_store_acp_sink_mask_ = mask;
- return S_OK;
- } else {
- return CONNECT_E_ADVISELIMIT;
- }
- }
- if (FAILED(text_store_acp_sink_.QueryFrom(unknown)))
- 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 = NULL;
- 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.
- 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 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 start_pos = acp_start - committed_size_;
- const uint32 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) +
- 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 string16& new_committed_string =
- string_buffer_.substr(last_committed_size,
- new_committed_size - last_committed_size);
- const 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.underlines = composition_undelines_;
- // Adjusts the offset.
- for (size_t i = 0; i < composition_text.underlines.size(); ++i) {
- composition_text.underlines[i].start_offset -= new_committed_size;
- composition_text.underlines[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_.IsSameObject(unknown))
- return CONNECT_E_NOCONNECTION;
- text_store_acp_sink_.Release();
- 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;
- CompositionUnderlines undelines;
- if (!GetCompositionStatus(context, read_only_edit_cookie, &committed_size,
- &undelines)) {
- return S_OK;
- }
- composition_undelines_ = undelines;
- 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;
-
- base::win::ScopedComPtr<ITfDisplayAttributeInfo> display_attribute_info;
- if (FAILED(display_attribute_manager_->GetDisplayAttributeInfo(
- guid, display_attribute_info.Receive(), NULL))) {
- return false;
- }
- return SUCCEEDED(display_attribute_info->GetAttributeInfo(attribute));
-}
-
-bool TSFTextStore::GetCompositionStatus(
- ITfContext* context,
- const TfEditCookie read_only_edit_cookie,
- size_t* committed_size,
- CompositionUnderlines* undelines) {
- DCHECK(context);
- DCHECK(committed_size);
- DCHECK(undelines);
- const GUID* rgGuids[2] = {&GUID_PROP_COMPOSING, &GUID_PROP_ATTRIBUTE};
- base::win::ScopedComPtr<ITfReadOnlyProperty> track_property;
- if (FAILED(context->TrackProperties(rgGuids, 2, NULL, 0,
- track_property.Receive()))) {
- return false;
- }
-
- *committed_size = 0;
- undelines->clear();
- base::win::ScopedComPtr<ITfRange> start_to_end_range;
- base::win::ScopedComPtr<ITfRange> end_range;
- if (FAILED(context->GetStart(read_only_edit_cookie,
- start_to_end_range.Receive()))) {
- return false;
- }
- if (FAILED(context->GetEnd(read_only_edit_cookie, end_range.Receive())))
- return false;
- if (FAILED(start_to_end_range->ShiftEndToRange(read_only_edit_cookie,
- end_range, TF_ANCHOR_END))) {
- return false;
- }
-
- base::win::ScopedComPtr<IEnumTfRanges> ranges;
- if (FAILED(track_property->EnumRanges(read_only_edit_cookie, ranges.Receive(),
- start_to_end_range))) {
- return false;
- }
-
- while (true) {
- base::win::ScopedComPtr<ITfRange> range;
- if (ranges->Next(1, range.Receive(), NULL) != S_OK)
- break;
- base::win::ScopedVariant value;
- base::win::ScopedComPtr<IEnumTfPropertyValue> enum_prop_value;
- if (FAILED(track_property->GetValue(read_only_edit_cookie, range,
- value.Receive()))) {
- return false;
- }
- if (FAILED(enum_prop_value.QueryFrom(value.AsInput()->punkVal)))
- 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, NULL) == 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);
- }
-
- base::win::ScopedComPtr<ITfRangeACP> range_acp;
- range_acp.QueryFrom(range);
- 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 {
- CompositionUnderline underline;
- underline.start_offset = start_pos;
- underline.end_offset = start_pos + length;
- underline.color = SK_ColorBLACK;
- if (has_display_attribute)
- underline.thick = !!display_attribute.fBoldLine;
- undelines->push_back(underline);
- }
- }
- 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_ = NULL;
- text_input_client_ = NULL;
- }
-}
-
-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 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
deleted file mode 100644
index 87cd6b42991..00000000000
--- a/chromium/ui/base/ime/win/tsf_text_store.h
+++ /dev/null
@@ -1,297 +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_IME_WIN_TSF_TEXT_STORE_H_
-#define UI_BASE_IME_WIN_TSF_TEXT_STORE_H_
-
-#include <msctf.h>
-#include <deque>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/base/ime/composition_underline.h"
-#include "ui/base/ui_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_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,
- CompositionUnderlines* undelines);
-
- // The refrence count of this instance.
- volatile LONG ref_count_;
-
- // A pointer of ITextStoreACPSink, this instance is given in AdviseSink.
- base::win::ScopedComPtr<ITextStoreACPSink> text_store_acp_sink_;
-
- // The current mask of |text_store_acp_sink_|.
- DWORD text_store_acp_sink_mask_;
-
- // HWND of the current view window which is set in SetFocusedTextInputClient.
- HWND window_handle_;
-
- // Current TextInputClient which is set in SetFocusedTextInputClient.
- TextInputClient* text_input_client_;
-
- // |string_buffer_| contains committed string and composition string.
- // Example: "aoi" is committed, and "umi" is under composition.
- // |string_buffer_|: "aoiumi"
- // |committed_size_|: 3
- string16 string_buffer_;
- size_t committed_size_;
-
- // |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 |composition_undelines_| indicates
- // the offsets in |string_buffer_|.
- // Example: "aoi" is committed. There are two underlines in "umi" and "no".
- // |string_buffer_|: "aoiumino"
- // |committed_size_|: 3
- // composition_undelines_.underlines[0].start_offset: 3
- // composition_undelines_.underlines[0].end_offset: 6
- // composition_undelines_.underlines[1].start_offset: 6
- // composition_undelines_.underlines[1].end_offset: 8
- CompositionUnderlines composition_undelines_;
-
- // |edit_flag_| indicates that the status is edited during
- // ITextStoreACPSink::OnLockGranted().
- bool edit_flag_;
-
- // The type of current lock.
- // 0: No lock.
- // TS_LF_READ: read-only lock.
- // TS_LF_READWRITE: read/write lock.
- DWORD current_lock_type_;
-
- // 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.
- base::win::ScopedComPtr<ITfCategoryMgr> category_manager_;
- base::win::ScopedComPtr<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
deleted file mode 100644
index 33812a4e01e..00000000000
--- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
+++ /dev/null
@@ -1,1302 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/win/tsf_text_store.h"
-
-#include <initguid.h> // for GUID_NULL and GUID_PROP_INPUTSCOPE
-#include <InputScope.h>
-#include <OleCtl.h>
-
-#include "base/memory/ref_counted.h"
-#include "base/win/scoped_com_initializer.h"
-#include "base/win/scoped_variant.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/gfx/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 string16&));
- MOCK_METHOD2(InsertChar, void(char16, int));
- MOCK_CONST_METHOD0(GetAttachedWindow, gfx::NativeWindow());
- MOCK_CONST_METHOD0(GetTextInputType, ui::TextInputType());
- MOCK_CONST_METHOD0(GetTextInputMode, ui::TextInputMode());
- MOCK_CONST_METHOD0(CanComposeInline, bool());
- MOCK_CONST_METHOD0(GetCaretBounds, gfx::Rect());
- MOCK_CONST_METHOD2(GetCompositionCharacterBounds, bool(uint32, 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&, string16*));
- MOCK_METHOD0(OnInputMethodChanged, void());
- MOCK_METHOD1(ChangeTextDirectionAndLayoutAlignment,
- bool(base::i18n::TextDirection));
- MOCK_METHOD2(ExtendSelectionAndDelete, void(size_t, size_t));
- MOCK_METHOD1(EnsureCaretInRect, void(const gfx::Rect&));
- MOCK_METHOD0(OnCandidateWindowShown, void());
- MOCK_METHOD0(OnCandidateWindowUpdated, void());
- MOCK_METHOD0(OnCandidateWindowHidden, void());
-};
-
-class MockStoreACPSink : public ITextStoreACPSink {
- public:
- MockStoreACPSink() : ref_count_(0) {}
-
- // IUnknown
- virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE {
- return InterlockedIncrement(&ref_count_);
- }
- virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE {
- const LONG count = InterlockedDecrement(&ref_count_);
- if (!count) {
- delete this;
- return 0;
- }
- return static_cast<ULONG>(count);
- }
- virtual HRESULT STDMETHODCALLTYPE QueryInterface(
- REFIID iid, void** report) OVERRIDE {
- if (iid == IID_IUnknown || iid == IID_ITextStoreACPSink) {
- *report = static_cast<ITextStoreACPSink*>(this);
- } else {
- *report = NULL;
- 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:
- virtual void SetUp() OVERRIDE {
- text_store_ = new TSFTextStore();
- sink_ = new MockStoreACPSink();
- EXPECT_EQ(S_OK, text_store_->AdviseSink(IID_ITextStoreACPSink,
- sink_, TS_AS_ALL_SINKS));
- text_store_->SetFocusedTextInputClient(kWindowHandle,
- &text_input_client_);
- }
-
- virtual void TearDown() OVERRIDE {
- EXPECT_EQ(S_OK, text_store_->UnadviseSink(sink_));
- sink_ = NULL;
- text_store_ = NULL;
- }
-
- // Accessors to the internal state of TSFTextStore.
- 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_; }
- string16* string_buffer() { return &text_store_->string_buffer_; }
- size_t* committed_size() { return &text_store_->committed_size_; }
- gfx::Range* selection() { return &text_store_->selection_; }
- CompositionUnderlines* composition_undelines() {
- return &text_store_->composition_undelines_;
- }
-
- void SetInternalState(const 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(1, 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 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(), change.acpNewEnd);
- }
- }
-
- void GetTextTest(LONG acp_start, LONG acp_end,
- const 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, string16(buffer, buffer + text_buffer_copied));
- EXPECT_EQ(1, 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,
- NULL));
- 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(0, status.dwDynamicFlags);
- EXPECT_EQ(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, NULL, &result_end));
- EXPECT_EQ(E_INVALIDARG,
- text_store_->QueryInsert(0, 0, 0, &result_start, NULL));
- 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_);
- 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_);
- 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);
- composition_undelines()->clear();
-
- state_ = 2;
- return S_OK;
- }
-
- void InsertText(const 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(0, composition.selection.start());
- EXPECT_EQ(0, composition.selection.end());
- EXPECT_EQ(0, composition.underlines.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_);
- 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_);
- 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_);
- 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_);
- 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);
-
- composition_undelines()->clear();
- CompositionUnderline underline;
- underline.start_offset = 0;
- underline.end_offset = 5;
- underline.color = SK_ColorBLACK;
- underline.thick = false;
- composition_undelines()->push_back(underline);
- *edit_flag() = true;
- *committed_size() = 0;
- return S_OK;
- }
-
- void SetCompositionText1(const ui::CompositionText& composition) {
- EXPECT_EQ(L"axyzc", composition.text);
- EXPECT_EQ(1, composition.selection.start());
- EXPECT_EQ(4, composition.selection.end());
- ASSERT_EQ(1, composition.underlines.size());
- EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color);
- EXPECT_EQ(0, composition.underlines[0].start_offset);
- EXPECT_EQ(5, composition.underlines[0].end_offset);
- EXPECT_FALSE(composition.underlines[0].thick);
- }
-
- HRESULT LockGranted2(DWORD flags) {
- SetTextTest(3, 4, L"ZCP", S_OK);
- GetTextTest(0, -1, L"axyZCPc", 7);
-
- composition_undelines()->clear();
- CompositionUnderline underline;
- underline.start_offset = 3;
- underline.end_offset = 5;
- underline.color = SK_ColorBLACK;
- underline.thick = true;
- composition_undelines()->push_back(underline);
- underline.start_offset = 5;
- underline.end_offset = 7;
- underline.color = SK_ColorBLACK;
- underline.thick = false;
- composition_undelines()->push_back(underline);
-
- *edit_flag() = true;
- *committed_size() = 3;
-
- return S_OK;
- }
-
- void InsertText2(const string16& text) {
- EXPECT_EQ(L"axy", text);
- }
-
- void SetCompositionText2(const ui::CompositionText& composition) {
- EXPECT_EQ(L"ZCPc", composition.text);
- EXPECT_EQ(0, composition.selection.start());
- EXPECT_EQ(3, composition.selection.end());
- ASSERT_EQ(2, composition.underlines.size());
- EXPECT_EQ(SK_ColorBLACK, composition.underlines[0].color);
- EXPECT_EQ(0, composition.underlines[0].start_offset);
- EXPECT_EQ(2, composition.underlines[0].end_offset);
- EXPECT_TRUE(composition.underlines[0].thick);
- EXPECT_EQ(SK_ColorBLACK, composition.underlines[1].color);
- EXPECT_EQ(2, composition.underlines[1].start_offset);
- EXPECT_EQ(4, composition.underlines[1].end_offset);
- EXPECT_FALSE(composition.underlines[1].thick);
- }
-
- HRESULT LockGranted3(DWORD flags) {
- GetTextTest(0, -1, L"axyZCPc", 7);
-
- composition_undelines()->clear();
- *edit_flag() = true;
- *committed_size() = 7;
-
- return S_OK;
- }
-
- void InsertText3(const string16& text) {
- EXPECT_EQ(L"ZCPc", text);
- }
-
- void SetCompositionText3(const ui::CompositionText& composition) {
- EXPECT_EQ(L"", composition.text);
- EXPECT_EQ(0, composition.selection.start());
- EXPECT_EQ(0, composition.selection.end());
- EXPECT_EQ(0, composition.underlines.size());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ScenarioTestCallback);
-};
-
-TEST_F(TSFTextStoreTest, ScenarioTest) {
- ScenarioTestCallback callback(text_store_);
- 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 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 layout_prepared_character_num_;
-
- DISALLOW_COPY_AND_ASSIGN(GetTextExtTestCallback);
-};
-
-TEST_F(TSFTextStoreTest, GetTextExtTest) {
- GetTextExtTestCallback callback(text_store_);
- 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, NULL));
-
- 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(NULL, NULL);
- EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 0, NULL));
- 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, NULL, &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());
- base::win::ScopedComPtr<ITfInputScope> input_scope;
- EXPECT_HRESULT_SUCCEEDED(input_scope.QueryFrom((&variant)->punkVal));
- 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(NULL, NULL);
- 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/formatter.cc b/chromium/ui/base/l10n/formatter.cc
new file mode 100644
index 00000000000..14f49ae3c93
--- /dev/null
+++ b/chromium/ui/base/l10n/formatter.cc
@@ -0,0 +1,327 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/l10n/formatter.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "grit/ui_strings.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "ui/base/l10n/l10n_util_plurals.h"
+
+namespace ui {
+
+UI_BASE_EXPORT bool formatter_force_fallback = false;
+
+static const size_t kNumberPluralities = 6;
+struct Pluralities {
+ int ids[kNumberPluralities];
+ const char* fallback_one;
+ const char* fallback_other;
+};
+
+static const Pluralities IDS_ELAPSED_SHORT_SEC = {
+ { IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SECS_SINGULAR,
+ IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO,
+ IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY },
+ "one{# sec ago}",
+ " other{# secs ago}"
+};
+static const Pluralities IDS_ELAPSED_SHORT_MIN = {
+ { IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MINS_SINGULAR,
+ IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO,
+ IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY },
+ "one{# min ago}",
+ " other{# mins ago}"
+};
+static const Pluralities IDS_ELAPSED_HOUR = {
+ { IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOURS_SINGULAR,
+ IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO,
+ IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY },
+ "one{# hour ago}",
+ " other{# hours ago}"
+};
+static const Pluralities IDS_ELAPSED_DAY = {
+ { IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAYS_SINGULAR,
+ IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO,
+ IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY },
+ "one{# day ago}",
+ " other{# days ago}"
+};
+
+static const Pluralities IDS_REMAINING_SHORT_SEC = {
+ { IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SECS_SINGULAR,
+ IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO,
+ IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY },
+ "one{# sec left}",
+ " other{# secs left}"
+};
+static const Pluralities IDS_REMAINING_SHORT_MIN = {
+ { IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MINS_SINGULAR,
+ IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO,
+ IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY },
+ "one{# min left}",
+ " other{# mins left}"
+};
+
+static const Pluralities IDS_REMAINING_LONG_SEC = {
+ { IDS_TIME_REMAINING_LONG_SECS_DEFAULT, IDS_TIME_REMAINING_LONG_SECS_SINGULAR,
+ IDS_TIME_REMAINING_LONG_SECS_ZERO, IDS_TIME_REMAINING_LONG_SECS_TWO,
+ IDS_TIME_REMAINING_LONG_SECS_FEW, IDS_TIME_REMAINING_LONG_SECS_MANY },
+ "one{# second left}",
+ " other{# seconds left}"
+};
+static const Pluralities IDS_REMAINING_LONG_MIN = {
+ { IDS_TIME_REMAINING_LONG_MINS_DEFAULT, IDS_TIME_REMAINING_LONG_MINS_SINGULAR,
+ IDS_TIME_REMAINING_LONG_MINS_ZERO, IDS_TIME_REMAINING_LONG_MINS_TWO,
+ IDS_TIME_REMAINING_LONG_MINS_FEW, IDS_TIME_REMAINING_LONG_MINS_MANY },
+ "one{# minute left}",
+ " other{# minutes left}"
+};
+static const Pluralities IDS_REMAINING_HOUR = {
+ { IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOURS_SINGULAR,
+ IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO,
+ IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY },
+ "one{# hour left}",
+ " other{# hours left}"
+};
+static const Pluralities IDS_REMAINING_DAY = {
+ { IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAYS_SINGULAR,
+ IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO,
+ IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY },
+ "one{# day left}",
+ " other{# days left}"
+};
+
+static const Pluralities IDS_DURATION_SHORT_SEC = {
+ { IDS_TIME_SECS_DEFAULT, IDS_TIME_SECS_SINGULAR, IDS_TIME_SECS_ZERO,
+ IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY },
+ "one{# sec}",
+ " other{# secs}"
+};
+static const Pluralities IDS_DURATION_SHORT_MIN = {
+ { IDS_TIME_MINS_DEFAULT, IDS_TIME_MINS_SINGULAR, IDS_TIME_MINS_ZERO,
+ IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY },
+ "one{# min}",
+ " other{# mins}"
+};
+
+static const Pluralities IDS_LONG_SEC = {
+ { IDS_TIME_LONG_SECS_DEFAULT, IDS_TIME_LONG_SECS_SINGULAR,
+ IDS_TIME_LONG_SECS_ZERO, IDS_TIME_LONG_SECS_TWO,
+ IDS_TIME_LONG_SECS_FEW, IDS_TIME_LONG_SECS_MANY },
+ "one{# second}",
+ " other{# seconds}"
+};
+static const Pluralities IDS_LONG_MIN = {
+ { IDS_TIME_LONG_MINS_DEFAULT, IDS_TIME_LONG_MINS_SINGULAR,
+ IDS_TIME_LONG_MINS_ZERO, IDS_TIME_LONG_MINS_TWO,
+ IDS_TIME_LONG_MINS_FEW, IDS_TIME_LONG_MINS_MANY },
+ "one{# minute}",
+ " other{# minutes}"
+};
+static const Pluralities IDS_DURATION_HOUR = {
+ { IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOURS_SINGULAR, IDS_TIME_HOURS_ZERO,
+ IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY },
+ "one{# hour}",
+ " other{# hours}"
+};
+static const Pluralities IDS_DURATION_DAY = {
+ { IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAYS_SINGULAR, IDS_TIME_DAYS_ZERO,
+ IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY },
+ "one{# day}",
+ " other{# days}"
+};
+
+static const Pluralities IDS_LONG_MIN_1ST = {
+ { IDS_TIME_LONG_MINS_1ST_DEFAULT, IDS_TIME_LONG_MINS_1ST_SINGULAR,
+ IDS_TIME_LONG_MINS_1ST_ZERO, IDS_TIME_LONG_MINS_1ST_TWO,
+ IDS_TIME_LONG_MINS_1ST_FEW, IDS_TIME_LONG_MINS_1ST_MANY },
+ "one{# minute }",
+ " other{# minutes }"
+};
+static const Pluralities IDS_LONG_SEC_2ND = {
+ { IDS_TIME_LONG_SECS_2ND_DEFAULT, IDS_TIME_LONG_SECS_2ND_SINGULAR,
+ IDS_TIME_LONG_SECS_2ND_ZERO, IDS_TIME_LONG_SECS_2ND_TWO,
+ IDS_TIME_LONG_SECS_2ND_FEW, IDS_TIME_LONG_SECS_2ND_MANY },
+ "one{# second}",
+ " other{# seconds}"
+};
+static const Pluralities IDS_DURATION_HOUR_1ST = {
+ { IDS_TIME_HOURS_1ST_DEFAULT, IDS_TIME_HOURS_1ST_SINGULAR,
+ IDS_TIME_HOURS_1ST_ZERO, IDS_TIME_HOURS_1ST_TWO,
+ IDS_TIME_HOURS_1ST_FEW, IDS_TIME_HOURS_1ST_MANY },
+ "one{# hour }",
+ " other{# hours }"
+};
+static const Pluralities IDS_LONG_MIN_2ND = {
+ { IDS_TIME_LONG_MINS_2ND_DEFAULT, IDS_TIME_LONG_MINS_2ND_SINGULAR,
+ IDS_TIME_LONG_MINS_2ND_ZERO, IDS_TIME_LONG_MINS_2ND_TWO,
+ IDS_TIME_LONG_MINS_2ND_FEW, IDS_TIME_LONG_MINS_2ND_MANY },
+ "one{# minute}",
+ " other{# minutes}"
+};
+static const Pluralities IDS_DURATION_DAY_1ST = {
+ { IDS_TIME_DAYS_1ST_DEFAULT, IDS_TIME_DAYS_1ST_SINGULAR,
+ IDS_TIME_DAYS_1ST_ZERO, IDS_TIME_DAYS_1ST_TWO,
+ IDS_TIME_DAYS_1ST_FEW, IDS_TIME_DAYS_1ST_MANY },
+ "one{# day }",
+ " other{# days }"
+};
+static const Pluralities IDS_DURATION_HOUR_2ND = {
+ { IDS_TIME_HOURS_2ND_DEFAULT, IDS_TIME_HOURS_2ND_SINGULAR,
+ IDS_TIME_HOURS_2ND_ZERO, IDS_TIME_HOURS_2ND_TWO,
+ IDS_TIME_HOURS_2ND_FEW, IDS_TIME_HOURS_2ND_MANY },
+ "one{# hour}",
+ " other{# hours}"
+};
+
+Formatter::Formatter(const Pluralities& sec_pluralities,
+ const Pluralities& min_pluralities,
+ const Pluralities& hour_pluralities,
+ const Pluralities& day_pluralities) {
+ simple_format_[UNIT_SEC] = InitFormat(sec_pluralities);
+ simple_format_[UNIT_MIN] = InitFormat(min_pluralities);
+ simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities);
+ simple_format_[UNIT_DAY] = InitFormat(day_pluralities);
+}
+
+Formatter::Formatter(const Pluralities& sec_pluralities,
+ const Pluralities& min_pluralities,
+ const Pluralities& hour_pluralities,
+ const Pluralities& day_pluralities,
+ const Pluralities& min_sec_pluralities1,
+ const Pluralities& min_sec_pluralities2,
+ const Pluralities& hour_min_pluralities1,
+ const Pluralities& hour_min_pluralities2,
+ const Pluralities& day_hour_pluralities1,
+ const Pluralities& day_hour_pluralities2) {
+ simple_format_[UNIT_SEC] = InitFormat(sec_pluralities);
+ simple_format_[UNIT_MIN] = InitFormat(min_pluralities);
+ simple_format_[UNIT_HOUR] = InitFormat(hour_pluralities);
+ simple_format_[UNIT_DAY] = InitFormat(day_pluralities);
+ detailed_format_[TWO_UNITS_MIN_SEC][0] = InitFormat(min_sec_pluralities1);
+ detailed_format_[TWO_UNITS_MIN_SEC][1] = InitFormat(min_sec_pluralities2);
+ detailed_format_[TWO_UNITS_HOUR_MIN][0] = InitFormat(hour_min_pluralities1);
+ detailed_format_[TWO_UNITS_HOUR_MIN][1] = InitFormat(hour_min_pluralities2);
+ detailed_format_[TWO_UNITS_DAY_HOUR][0] = InitFormat(day_hour_pluralities1);
+ detailed_format_[TWO_UNITS_DAY_HOUR][1] = InitFormat(day_hour_pluralities2);
+}
+
+void Formatter::Format(Unit unit,
+ int value,
+ icu::UnicodeString& formatted_string) const {
+ DCHECK(simple_format_[unit]);
+ UErrorCode error = U_ZERO_ERROR;
+ formatted_string = simple_format_[unit]->format(value, error);
+ DCHECK(U_SUCCESS(error)) << "Error in icu::PluralFormat::format().";
+ return;
+}
+
+void Formatter::Format(TwoUnits units,
+ int value_1,
+ int value_2,
+ icu::UnicodeString& formatted_string) const {
+ DCHECK(detailed_format_[units][0])
+ << "Detailed() not implemented for your (format, length) combination!";
+ DCHECK(detailed_format_[units][1])
+ << "Detailed() not implemented for your (format, length) combination!";
+ UErrorCode error = U_ZERO_ERROR;
+ formatted_string = detailed_format_[units][0]->format(value_1, error);
+ DCHECK(U_SUCCESS(error));
+ formatted_string += detailed_format_[units][1]->format(value_2, error);
+ DCHECK(U_SUCCESS(error));
+ return;
+}
+
+scoped_ptr<icu::PluralFormat> Formatter::CreateFallbackFormat(
+ const icu::PluralRules& rules,
+ const Pluralities& pluralities) const {
+ icu::UnicodeString pattern;
+ if (rules.isKeyword(UNICODE_STRING_SIMPLE("one")))
+ pattern += icu::UnicodeString(pluralities.fallback_one);
+ pattern += icu::UnicodeString(pluralities.fallback_other);
+
+ UErrorCode error = U_ZERO_ERROR;
+ scoped_ptr<icu::PluralFormat> format(
+ new icu::PluralFormat(rules, pattern, error));
+ DCHECK(U_SUCCESS(error));
+ return format.Pass();
+}
+
+scoped_ptr<icu::PluralFormat> Formatter::InitFormat(
+ const Pluralities& pluralities) {
+ if (!formatter_force_fallback) {
+ icu::UnicodeString pattern;
+ std::vector<int> ids;
+ for (size_t j = 0; j < kNumberPluralities; ++j)
+ ids.push_back(pluralities.ids[j]);
+ scoped_ptr<icu::PluralFormat> format = l10n_util::BuildPluralFormat(ids);
+ if (format.get())
+ return format.Pass();
+ }
+
+ scoped_ptr<icu::PluralRules> rules(l10n_util::BuildPluralRules());
+ return CreateFallbackFormat(*rules, pluralities);
+}
+
+const Formatter* FormatterContainer::Get(TimeFormat::Format format,
+ TimeFormat::Length length) const {
+ DCHECK(formatter_[format][length])
+ << "Combination of FORMAT_ELAPSED and LENGTH_LONG is not implemented!";
+ return formatter_[format][length].get();
+}
+
+FormatterContainer::FormatterContainer() {
+ Initialize();
+}
+
+FormatterContainer::~FormatterContainer() {
+}
+
+void FormatterContainer::Initialize() {
+ formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_SHORT].reset(
+ new Formatter(IDS_ELAPSED_SHORT_SEC,
+ IDS_ELAPSED_SHORT_MIN,
+ IDS_ELAPSED_HOUR,
+ IDS_ELAPSED_DAY));
+ formatter_[TimeFormat::FORMAT_ELAPSED][TimeFormat::LENGTH_LONG].reset();
+ formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_SHORT].reset(
+ new Formatter(IDS_REMAINING_SHORT_SEC,
+ IDS_REMAINING_SHORT_MIN,
+ IDS_REMAINING_HOUR,
+ IDS_REMAINING_DAY));
+ formatter_[TimeFormat::FORMAT_REMAINING][TimeFormat::LENGTH_LONG].reset(
+ new Formatter(IDS_REMAINING_LONG_SEC,
+ IDS_REMAINING_LONG_MIN,
+ IDS_REMAINING_HOUR,
+ IDS_REMAINING_DAY));
+ formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_SHORT].reset(
+ new Formatter(IDS_DURATION_SHORT_SEC,
+ IDS_DURATION_SHORT_MIN,
+ IDS_DURATION_HOUR,
+ IDS_DURATION_DAY));
+ formatter_[TimeFormat::FORMAT_DURATION][TimeFormat::LENGTH_LONG].reset(
+ new Formatter(IDS_LONG_SEC,
+ IDS_LONG_MIN,
+ IDS_DURATION_HOUR,
+ IDS_DURATION_DAY,
+ IDS_LONG_MIN_1ST,
+ IDS_LONG_SEC_2ND,
+ IDS_DURATION_HOUR_1ST,
+ IDS_LONG_MIN_2ND,
+ IDS_DURATION_DAY_1ST,
+ IDS_DURATION_HOUR_2ND));
+}
+
+void FormatterContainer::Shutdown() {
+ for (int format = 0; format < TimeFormat::FORMAT_COUNT; ++format) {
+ for (int length = 0; length < TimeFormat::LENGTH_COUNT; ++length) {
+ formatter_[format][length].reset();
+ }
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/l10n/formatter.h b/chromium/ui/base/l10n/formatter.h
new file mode 100644
index 00000000000..de1aa4a79fe
--- /dev/null
+++ b/chromium/ui/base/l10n/formatter.h
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains implementation details, the public interface is declared
+// in time_format.h.
+
+#ifndef UI_BASE_L10N_FORMATTER_H_
+#define UI_BASE_L10N_FORMATTER_H_
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "third_party/icu/source/i18n/unicode/plurfmt.h"
+#include "third_party/icu/source/i18n/unicode/plurrule.h"
+#include "ui/base/l10n/time_format.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+struct Pluralities;
+
+// Formatter for a (format, length) combination. May either be instantiated
+// with four parameters for use in TimeFormat::Simple() or with ten parameters
+// for use in TimeFormat::Detailed().
+class Formatter {
+ public:
+ enum Unit {
+ UNIT_SEC,
+ UNIT_MIN,
+ UNIT_HOUR,
+ UNIT_DAY,
+ UNIT_COUNT // Enum size counter, not a unit. Must be last.
+ };
+ enum TwoUnits {
+ TWO_UNITS_MIN_SEC,
+ TWO_UNITS_HOUR_MIN,
+ TWO_UNITS_DAY_HOUR,
+ TWO_UNITS_COUNT // Enum size counter, not a unit pair. Must be last.
+ };
+
+ Formatter(const Pluralities& sec_pluralities,
+ const Pluralities& min_pluralities,
+ const Pluralities& hour_pluralities,
+ const Pluralities& day_pluralities);
+
+ Formatter(const Pluralities& sec_pluralities,
+ const Pluralities& min_pluralities,
+ const Pluralities& hour_pluralities,
+ const Pluralities& day_pluralities,
+ const Pluralities& min_sec_pluralities1,
+ const Pluralities& min_sec_pluralities2,
+ const Pluralities& hour_min_pluralities1,
+ const Pluralities& hour_min_pluralities2,
+ const Pluralities& day_hour_pluralities1,
+ const Pluralities& day_hour_pluralities2);
+
+ void Format(Unit unit, int value, icu::UnicodeString& formatted_string) const;
+
+ void Format(TwoUnits units,
+ int value_1,
+ int value_2,
+ icu::UnicodeString& formatted_string) const;
+
+ private:
+ // Create a hard-coded fallback plural format. This will never be called
+ // unless translators make a mistake.
+ scoped_ptr<icu::PluralFormat> CreateFallbackFormat(
+ const icu::PluralRules& rules,
+ const Pluralities& pluralities) const;
+
+ scoped_ptr<icu::PluralFormat> InitFormat(const Pluralities& pluralities);
+
+ scoped_ptr<icu::PluralFormat> simple_format_[UNIT_COUNT];
+ scoped_ptr<icu::PluralFormat> detailed_format_[TWO_UNITS_COUNT][2];
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Formatter);
+};
+
+// Class to hold all Formatters, intended to be used in a global LazyInstance.
+class UI_BASE_EXPORT FormatterContainer {
+ public:
+ FormatterContainer();
+ ~FormatterContainer();
+
+ const Formatter* Get(TimeFormat::Format format,
+ TimeFormat::Length length) const;
+
+ void ResetForTesting() {
+ Shutdown();
+ Initialize();
+ }
+
+ private:
+ void Initialize();
+ void Shutdown();
+
+ scoped_ptr<Formatter>
+ formatter_[TimeFormat::FORMAT_COUNT][TimeFormat::LENGTH_COUNT];
+
+ DISALLOW_COPY_AND_ASSIGN(FormatterContainer);
+};
+
+// Windows compilation requires full definition of FormatterContainer before
+// LazyInstance<FormatterContainter> may be declared.
+extern UI_BASE_EXPORT base::LazyInstance<FormatterContainer> g_container;
+
+// For use in unit tests only.
+extern UI_BASE_EXPORT bool formatter_force_fallback;
+
+} // namespace ui
+
+#endif
diff --git a/chromium/ui/base/l10n/l10n_font_util.h b/chromium/ui/base/l10n/l10n_font_util.h
index cfd0d81b263..b27b3f69dbd 100644
--- a/chromium/ui/base/l10n/l10n_font_util.h
+++ b/chromium/ui/base/l10n/l10n_font_util.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_L10N_FONT_UTIL_H_
#define UI_BASE_L10N_FONT_UTIL_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/size.h"
namespace gfx {
@@ -18,13 +18,13 @@ namespace ui {
// its localized size data and the given font. The width in cols is held in a
// localized string resource identified by |col_resource_id|, the height in the
// same fashion.
-UI_EXPORT int GetLocalizedContentsWidthForFont(int col_resource_id,
- const gfx::Font& font);
-UI_EXPORT int GetLocalizedContentsHeightForFont(int row_resource_id,
- const gfx::Font& font);
-UI_EXPORT gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
- int row_resource_id,
+UI_BASE_EXPORT int GetLocalizedContentsWidthForFont(int col_resource_id,
const gfx::Font& font);
+UI_BASE_EXPORT int GetLocalizedContentsHeightForFont(int row_resource_id,
+ const gfx::Font& font);
+UI_BASE_EXPORT gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
+ int row_resource_id,
+ const gfx::Font& font);
} // namespace ui
diff --git a/chromium/ui/base/l10n/l10n_util.cc b/chromium/ui/base/l10n/l10n_util.cc
index b610e9662d5..44d8df50547 100644
--- a/chromium/ui/base/l10n/l10n_util.cc
+++ b/chromium/ui/base/l10n/l10n_util.cc
@@ -225,7 +225,7 @@ bool IsLocalePartiallyPopulated(const std::string& locale_name) {
bool IsLocaleAvailable(const std::string& locale) {
// If locale has any illegal characters in it, we don't want to try to
// load it because it may be pointing outside the locale data file directory.
- if (!file_util::IsFilenameLegal(ASCIIToUTF16(locale)))
+ if (!file_util::IsFilenameLegal(base::ASCIIToUTF16(locale)))
return false;
// IsLocalePartiallyPopulated() can be called here for an early return w/o
@@ -263,12 +263,6 @@ void AdjustParagraphDirectionality(base::string16* paragraph) {
#endif
}
-#if defined(OS_WIN)
-std::string GetCanonicalLocale(const std::string& locale) {
- return base::i18n::GetCanonicalLocale(locale.c_str());
-}
-#endif
-
struct AvailableLocalesTraits
: base::DefaultLazyInstanceTraits<std::vector<std::string> > {
static std::vector<std::string>* New(void* instance) {
@@ -313,6 +307,10 @@ base::LazyInstance<std::vector<std::string>, AvailableLocalesTraits>
namespace l10n_util {
+std::string GetCanonicalLocale(const std::string& locale) {
+ return base::i18n::GetCanonicalLocale(locale.c_str());
+}
+
bool CheckAndResolveLocale(const std::string& locale,
std::string* resolved_locale) {
#if defined(OS_MACOSX)
@@ -507,7 +505,8 @@ bool IsLocaleNameTranslated(const char* locale,
// the translation is available or not. If ICU doesn't have a translated
// name for this locale, GetDisplayNameForLocale will just return the
// locale code.
- return !IsStringASCII(display_name) || UTF16ToASCII(display_name) != locale;
+ return !base::IsStringASCII(display_name) ||
+ base::UTF16ToASCII(display_name) != locale;
}
base::string16 GetDisplayNameForLocale(const std::string& locale,
@@ -661,7 +660,7 @@ bool IsValidLocaleSyntax(const std::string& locale) {
}
std::string GetStringUTF8(int message_id) {
- return UTF16ToUTF8(GetStringUTF16(message_id));
+ return base::UTF16ToUTF8(GetStringUTF16(message_id));
}
base::string16 GetStringUTF16(int message_id) {
@@ -688,7 +687,7 @@ base::string16 GetStringFUTF16(int message_id,
// check as the code may simply want to find the placeholders rather than
// actually replacing them.
if (!offsets) {
- std::string utf8_string = UTF16ToUTF8(format_string);
+ std::string utf8_string = base::UTF16ToUTF8(format_string);
// $9 is the highest allowed placeholder.
for (size_t i = 0; i < 9; ++i) {
@@ -719,20 +718,20 @@ base::string16 GetStringFUTF16(int message_id,
std::string GetStringFUTF8(int message_id,
const base::string16& a) {
- return UTF16ToUTF8(GetStringFUTF16(message_id, a));
+ return base::UTF16ToUTF8(GetStringFUTF16(message_id, a));
}
std::string GetStringFUTF8(int message_id,
const base::string16& a,
const base::string16& b) {
- return UTF16ToUTF8(GetStringFUTF16(message_id, a, b));
+ return base::UTF16ToUTF8(GetStringFUTF16(message_id, a, b));
}
std::string GetStringFUTF8(int message_id,
const base::string16& a,
const base::string16& b,
const base::string16& c) {
- return UTF16ToUTF8(GetStringFUTF16(message_id, a, b, c));
+ return base::UTF16ToUTF8(GetStringFUTF16(message_id, a, b, c));
}
std::string GetStringFUTF8(int message_id,
@@ -740,7 +739,7 @@ std::string GetStringFUTF8(int message_id,
const base::string16& b,
const base::string16& c,
const base::string16& d) {
- return UTF16ToUTF8(GetStringFUTF16(message_id, a, b, c, d));
+ return base::UTF16ToUTF8(GetStringFUTF16(message_id, a, b, c, d));
}
base::string16 GetStringFUTF16(int message_id,
@@ -819,11 +818,11 @@ base::string16 GetStringFUTF16(int message_id,
}
base::string16 GetStringFUTF16Int(int message_id, int a) {
- return GetStringFUTF16(message_id, UTF8ToUTF16(base::IntToString(a)));
+ return GetStringFUTF16(message_id, base::UTF8ToUTF16(base::IntToString(a)));
}
base::string16 GetStringFUTF16Int(int message_id, int64 a) {
- return GetStringFUTF16(message_id, UTF8ToUTF16(base::Int64ToString(a)));
+ return GetStringFUTF16(message_id, base::UTF8ToUTF16(base::Int64ToString(a)));
}
// Specialization of operator() method for base::string16 version.
diff --git a/chromium/ui/base/l10n/l10n_util.h b/chromium/ui/base/l10n/l10n_util.h
index 2d254fa7414..5440b0d18a4 100644
--- a/chromium/ui/base/l10n/l10n_util.h
+++ b/chromium/ui/base/l10n/l10n_util.h
@@ -13,17 +13,22 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#if defined(OS_MACOSX)
#include "ui/base/l10n/l10n_util_mac.h"
#endif // OS_MACOSX
namespace l10n_util {
+
+// The same as base::i18n::GetCanonicalLocale(const char*), but takes
+// std::string as an argument.
+UI_BASE_EXPORT std::string GetCanonicalLocale(const std::string& locale);
+
// This method translates a generic locale name to one of the locally defined
// ones. This method returns true if it succeeds.
-UI_EXPORT bool CheckAndResolveLocale(const std::string& locale,
- std::string* resolved_locale);
+UI_BASE_EXPORT bool CheckAndResolveLocale(const std::string& locale,
+ std::string* resolved_locale);
// This method is responsible for determining the locale as defined below. In
// nearly all cases you shouldn't call this, rather use GetApplicationLocale
@@ -34,12 +39,12 @@ UI_EXPORT bool CheckAndResolveLocale(const std::string& locale,
// as |pref_locale|), finally, we fall back on the system locale. We only return
// a value if there's a corresponding resource DLL for the locale. Otherwise,
// we fall back to en-us.
-UI_EXPORT std::string GetApplicationLocale(const std::string& pref_locale);
+UI_BASE_EXPORT std::string GetApplicationLocale(const std::string& pref_locale);
// Returns true if a display name for |locale| is available in the locale
// |display_locale|.
-UI_EXPORT bool IsLocaleNameTranslated(const char* locale,
- const std::string& display_locale);
+UI_BASE_EXPORT bool IsLocaleNameTranslated(const char* locale,
+ const std::string& display_locale);
// Given a locale code, return true if the OS is capable of supporting it.
// For instance, Oriya is not well supported on Windows XP and we return
@@ -55,24 +60,24 @@ bool IsLocaleSupportedByOS(const std::string& locale);
// in the UI thread.
// If |is_for_ui| is true, U+200F is appended so that it can be
// rendered properly in a RTL Chrome.
-UI_EXPORT base::string16 GetDisplayNameForLocale(
+UI_BASE_EXPORT base::string16 GetDisplayNameForLocale(
const std::string& locale,
const std::string& display_locale,
bool is_for_ui);
// Returns the display name of the |country_code| in |display_locale|.
-UI_EXPORT base::string16 GetDisplayNameForCountry(
+UI_BASE_EXPORT base::string16 GetDisplayNameForCountry(
const std::string& country_code,
const std::string& display_locale);
// Converts all - into _, to be consistent with ICU and file system names.
-UI_EXPORT std::string NormalizeLocale(const std::string& locale);
+UI_BASE_EXPORT std::string NormalizeLocale(const std::string& locale);
// Produce a vector of parent locales for given locale.
// It includes the current locale in the result.
// sr_Cyrl_RS generates sr_Cyrl_RS, sr_Cyrl and sr.
-UI_EXPORT void GetParentLocales(const std::string& current_locale,
- std::vector<std::string>* parent_locales);
+UI_BASE_EXPORT void GetParentLocales(const std::string& current_locale,
+ std::vector<std::string>* parent_locales);
// Checks if a string is plausibly a syntactically-valid locale string,
// for cases where we want the valid input to be a locale string such as
@@ -82,102 +87,104 @@ UI_EXPORT void GetParentLocales(const std::string& current_locale,
// accepted, but 'z', 'German', 'en-$1', or 'abcd-1234' should not.
// Case-insensitive. Based on BCP 47, see:
// http://unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers
-UI_EXPORT bool IsValidLocaleSyntax(const std::string& locale);
+UI_BASE_EXPORT bool IsValidLocaleSyntax(const std::string& locale);
//
// Mac Note: See l10n_util_mac.h for some NSString versions and other support.
//
// Pulls resource string from the string bundle and returns it.
-UI_EXPORT std::string GetStringUTF8(int message_id);
-UI_EXPORT base::string16 GetStringUTF16(int message_id);
+UI_BASE_EXPORT std::string GetStringUTF8(int message_id);
+UI_BASE_EXPORT base::string16 GetStringUTF16(int message_id);
// Get a resource string and replace $i with replacements[i] for all
// i < replacements.size(). Additionally, $$ is replaced by $.
// If non-NULL |offsets| will be replaced with the start points of the replaced
// strings.
-UI_EXPORT base::string16 GetStringFUTF16(
+UI_BASE_EXPORT base::string16 GetStringFUTF16(
int message_id,
const std::vector<base::string16>& replacements,
std::vector<size_t>* offsets);
// Convenience wrappers for the above.
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a);
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- const base::string16& b);
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- const base::string16& b,
- const base::string16& c);
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- const base::string16& b,
- const base::string16& c,
- const base::string16& d);
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- const base::string16& b,
- const base::string16& c,
- const base::string16& d,
- const base::string16& e);
-UI_EXPORT std::string GetStringFUTF8(int message_id,
- const base::string16& a);
-UI_EXPORT std::string GetStringFUTF8(int message_id,
- const base::string16& a,
- const base::string16& b);
-UI_EXPORT std::string GetStringFUTF8(int message_id,
- const base::string16& a,
- const base::string16& b,
- const base::string16& c);
-UI_EXPORT std::string GetStringFUTF8(int message_id,
- const base::string16& a,
- const base::string16& b,
- const base::string16& c,
- const base::string16& d);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ const base::string16& b);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d,
+ const base::string16& e);
+UI_BASE_EXPORT std::string GetStringFUTF8(int message_id,
+ const base::string16& a);
+UI_BASE_EXPORT std::string GetStringFUTF8(int message_id,
+ const base::string16& a,
+ const base::string16& b);
+UI_BASE_EXPORT std::string GetStringFUTF8(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c);
+UI_BASE_EXPORT std::string GetStringFUTF8(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d);
// Variants that return the offset(s) of the replaced parameters. The
// vector based version returns offsets ordered by parameter. For example if
// invoked with a and b offsets[0] gives the offset for a and offsets[1] the
// offset of b regardless of where the parameters end up in the string.
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- size_t* offset);
-UI_EXPORT base::string16 GetStringFUTF16(int message_id,
- const base::string16& a,
- const base::string16& b,
- std::vector<size_t>* offsets);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ size_t* offset);
+UI_BASE_EXPORT base::string16 GetStringFUTF16(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ std::vector<size_t>* offsets);
// Convenience functions to get a string with a single number as a parameter.
-UI_EXPORT base::string16 GetStringFUTF16Int(int message_id, int a);
+UI_BASE_EXPORT base::string16 GetStringFUTF16Int(int message_id, int a);
base::string16 GetStringFUTF16Int(int message_id, int64 a);
// Get a resource string using |number| to decide which of |message_ids| should
// be used. |message_ids| must be size 6 and in order: default, singular, zero,
// two, few, many.
-UI_EXPORT base::string16 GetPluralStringFUTF16(
+UI_BASE_EXPORT base::string16 GetPluralStringFUTF16(
+ const std::vector<int>& message_ids,
+ int number);
+UI_BASE_EXPORT std::string GetPluralStringFUTF8(
const std::vector<int>& message_ids,
int number);
-UI_EXPORT std::string GetPluralStringFUTF8(const std::vector<int>& message_ids,
- int number);
-// In place sorting of base::string16 strings using collation rules for |locale|.
-UI_EXPORT void SortStrings16(const std::string& locale,
- std::vector<base::string16>* strings);
+// In place sorting of base::string16 strings using collation rules for
+// |locale|.
+UI_BASE_EXPORT void SortStrings16(const std::string& locale,
+ std::vector<base::string16>* strings);
// Returns a vector of available locale codes. E.g., a vector containing
// en-US, es, fr, fi, pt-PT, pt-BR, etc.
-UI_EXPORT const std::vector<std::string>& GetAvailableLocales();
+UI_BASE_EXPORT const std::vector<std::string>& GetAvailableLocales();
// Returns a vector of locale codes usable for accept-languages.
-UI_EXPORT void GetAcceptLanguagesForLocale(
+UI_BASE_EXPORT void GetAcceptLanguagesForLocale(
const std::string& display_locale,
std::vector<std::string>* locale_codes);
// Returns the preferred size of the contents view of a window based on
// designer given constraints which might dependent on the language used.
-UI_EXPORT int GetLocalizedContentsWidthInPixels(int pixel_resource_id);
+UI_BASE_EXPORT int GetLocalizedContentsWidthInPixels(int pixel_resource_id);
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util_android.cc b/chromium/ui/base/l10n/l10n_util_android.cc
index 62d919bdc80..154b6759711 100644
--- a/chromium/ui/base/l10n/l10n_util_android.cc
+++ b/chromium/ui/base/l10n/l10n_util_android.cc
@@ -17,10 +17,6 @@
namespace l10n_util {
-jboolean IsRTL(JNIEnv* env, jclass clazz) {
- return base::i18n::IsRTL();
-}
-
jint GetFirstStrongCharacterDirection(JNIEnv* env, jclass clazz,
jstring string) {
return base::i18n::GetFirstStrongCharacterDirection(
@@ -34,6 +30,20 @@ std::string GetDefaultLocale() {
return ConvertJavaStringToUTF8(locale);
}
+bool IsLayoutRtl() {
+ static bool is_layout_rtl_cached = false;
+ static bool layout_rtl_cache;
+
+ if (!is_layout_rtl_cached) {
+ is_layout_rtl_cached = true;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ layout_rtl_cache =
+ static_cast<bool>(Java_LocalizationUtils_isLayoutRtl(env));
+ }
+
+ return layout_rtl_cache;
+}
+
namespace {
// Common prototype of ICU uloc_getXXX() functions.
@@ -73,8 +83,8 @@ ScopedJavaLocalRef<jobject> NewJavaLocale(
} // namespace
-string16 GetDisplayNameForLocale(const std::string& locale,
- const std::string& display_locale) {
+base::string16 GetDisplayNameForLocale(const std::string& locale,
+ const std::string& display_locale) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> java_locale =
NewJavaLocale(env, locale);
@@ -93,7 +103,8 @@ jstring GetDurationString(JNIEnv* env, jclass clazz, jlong timeInMillis) {
ScopedJavaLocalRef<jstring> jtime_remaining =
base::android::ConvertUTF16ToJavaString(
env,
- ui::TimeFormat::TimeRemaining(
+ ui::TimeFormat::Simple(
+ ui::TimeFormat::FORMAT_REMAINING, ui::TimeFormat::LENGTH_SHORT,
base::TimeDelta::FromMilliseconds(timeInMillis)));
return jtime_remaining.Release();
}
diff --git a/chromium/ui/base/l10n/l10n_util_android.h b/chromium/ui/base/l10n/l10n_util_android.h
index 467bf178b91..c8cf4bb2733 100644
--- a/chromium/ui/base/l10n/l10n_util_android.h
+++ b/chromium/ui/base/l10n/l10n_util_android.h
@@ -10,17 +10,20 @@
#include <string>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace l10n_util {
// Return the current default locale of the device.
-UI_EXPORT std::string GetDefaultLocale();
+UI_BASE_EXPORT std::string GetDefaultLocale();
-UI_EXPORT string16 GetDisplayNameForLocale(const std::string& locale,
- const std::string& display_locale);
+UI_BASE_EXPORT base::string16 GetDisplayNameForLocale(
+ const std::string& locale,
+ const std::string& display_locale);
-UI_EXPORT bool RegisterLocalizationUtil(JNIEnv* env);
+UI_BASE_EXPORT bool IsLayoutRtl();
+
+UI_BASE_EXPORT bool RegisterLocalizationUtil(JNIEnv* env);
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util_collator.h b/chromium/ui/base/l10n/l10n_util_collator.h
index a0bfb92ebbc..e1b91abd14a 100644
--- a/chromium/ui/base/l10n/l10n_util_collator.h
+++ b/chromium/ui/base/l10n/l10n_util_collator.h
@@ -13,7 +13,7 @@
#include "base/i18n/string_compare.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/icu/source/i18n/unicode/coll.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace l10n_util {
@@ -82,7 +82,7 @@ void SortStringsUsingMethod(const std::string& locale,
// Compares two elements' string keys and returns true if the first element's
// string key is less than the second element's string key. The Element must
// have a method like the follow format to return the string key.
-// const string16& GetStringKey() const;
+// const base::string16& GetStringKey() const;
// This uses the locale specified in the constructor.
template <class Element>
class StringComparator : public std::binary_function<const Element&,
@@ -105,8 +105,8 @@ class StringComparator : public std::binary_function<const Element&,
icu::Collator* collator_;
};
-// Specialization of operator() method for string16 version.
-template <> UI_EXPORT
+// Specialization of operator() method for base::string16 version.
+template <> UI_BASE_EXPORT
bool StringComparator<base::string16>::operator()(const base::string16& lhs,
const base::string16& rhs);
diff --git a/chromium/ui/base/l10n/l10n_util_mac.h b/chromium/ui/base/l10n/l10n_util_mac.h
index f617d8995df..74bc58b4935 100644
--- a/chromium/ui/base/l10n/l10n_util_mac.h
+++ b/chromium/ui/base/l10n/l10n_util_mac.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#ifdef __OBJC__
@class NSString;
@@ -23,59 +23,58 @@ namespace l10n_util {
// Remove the Windows-style accelerator marker (for labels, menuitems, etc.)
// and change "..." into an ellipsis.
// Returns the result in an autoreleased NSString.
-UI_EXPORT NSString* FixUpWindowsStyleLabel(const string16& label);
+UI_BASE_EXPORT NSString* FixUpWindowsStyleLabel(const base::string16& label);
// Pulls resource string from the string bundle and returns it.
-UI_EXPORT NSString* GetNSString(int message_id);
+UI_BASE_EXPORT NSString* GetNSString(int message_id);
// Get a resource string and replace $1-$2-$3 with |a| and |b|
// respectively. Additionally, $$ is replaced by $.
-UI_EXPORT NSString* GetNSStringF(int message_id,
- const string16& a);
-UI_EXPORT NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b);
-UI_EXPORT NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
- const string16& c);
-UI_EXPORT NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
- const string16& c,
- const string16& d);
+UI_BASE_EXPORT NSString* GetNSStringF(int message_id, const base::string16& a);
+UI_BASE_EXPORT NSString* GetNSStringF(int message_id,
+ const base::string16& a,
+ const base::string16& b);
+UI_BASE_EXPORT NSString* GetNSStringF(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c);
+UI_BASE_EXPORT NSString* GetNSStringF(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d);
// Variants that return the offset(s) of the replaced parameters. (See
// app/l10n_util.h for more details.)
-UI_EXPORT NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
- std::vector<size_t>* offsets);
+UI_BASE_EXPORT NSString* GetNSStringF(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ std::vector<size_t>* offsets);
// Same as GetNSString, but runs the result through FixUpWindowsStyleLabel
// before returning it.
-UI_EXPORT NSString* GetNSStringWithFixup(int message_id);
+UI_BASE_EXPORT NSString* GetNSStringWithFixup(int message_id);
// Same as GetNSStringF, but runs the result through FixUpWindowsStyleLabel
// before returning it.
-UI_EXPORT NSString* GetNSStringFWithFixup(int message_id,
- const string16& a);
-UI_EXPORT NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b);
-UI_EXPORT NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b,
- const string16& c);
-UI_EXPORT NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b,
- const string16& c,
- const string16& d);
+UI_BASE_EXPORT NSString* GetNSStringFWithFixup(int message_id,
+ const base::string16& a);
+UI_BASE_EXPORT NSString* GetNSStringFWithFixup(int message_id,
+ const base::string16& a,
+ const base::string16& b);
+UI_BASE_EXPORT NSString* GetNSStringFWithFixup(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c);
+UI_BASE_EXPORT NSString* GetNSStringFWithFixup(int message_id,
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d);
// Support the override of the locale with the value from Cocoa.
-UI_EXPORT void OverrideLocaleWithCocoaLocale();
-UI_EXPORT const std::string& GetLocaleOverride();
+UI_BASE_EXPORT void OverrideLocaleWithCocoaLocale();
+UI_BASE_EXPORT const std::string& GetLocaleOverride();
} // namespace l10n_util
diff --git a/chromium/ui/base/l10n/l10n_util_mac.mm b/chromium/ui/base/l10n/l10n_util_mac.mm
index e9d47c2dc1e..8d6ca703073 100644
--- a/chromium/ui/base/l10n/l10n_util_mac.mm
+++ b/chromium/ui/base/l10n/l10n_util_mac.mm
@@ -53,13 +53,13 @@ void OverrideLocaleWithCocoaLocale() {
// Remove the Windows-style accelerator marker and change "..." into an
// ellipsis. Returns the result in an autoreleased NSString.
-NSString* FixUpWindowsStyleLabel(const string16& label) {
- const char16 kEllipsisUTF16 = 0x2026;
- string16 ret;
+NSString* FixUpWindowsStyleLabel(const base::string16& label) {
+ const base::char16 kEllipsisUTF16 = 0x2026;
+ base::string16 ret;
size_t label_len = label.length();
ret.reserve(label_len);
for (size_t i = 0; i < label_len; ++i) {
- char16 c = label[i];
+ base::char16 c = label[i];
if (c == '(' && i + 3 < label_len && label[i + 1] == '&'
&& label[i + 3] == ')') {
// Strip '(&?)' patterns which means Windows-style accelerator in some
@@ -87,38 +87,38 @@ NSString* GetNSString(int message_id) {
}
NSString* GetNSStringF(int message_id,
- const string16& a) {
+ const base::string16& a) {
return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(message_id,
a));
}
NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b) {
+ const base::string16& a,
+ const base::string16& b) {
return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(message_id,
a, b));
}
NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
- const string16& c) {
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c) {
return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(message_id,
a, b, c));
}
NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
- const string16& c,
- const string16& d) {
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d) {
return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(message_id,
a, b, c, d));
}
NSString* GetNSStringF(int message_id,
- const string16& a,
- const string16& b,
+ const base::string16& a,
+ const base::string16& b,
std::vector<size_t>* offsets) {
return base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(message_id,
a, b, offsets));
@@ -129,31 +129,31 @@ NSString* GetNSStringWithFixup(int message_id) {
}
NSString* GetNSStringFWithFixup(int message_id,
- const string16& a) {
+ const base::string16& a) {
return FixUpWindowsStyleLabel(l10n_util::GetStringFUTF16(message_id,
a));
}
NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b) {
+ const base::string16& a,
+ const base::string16& b) {
return FixUpWindowsStyleLabel(l10n_util::GetStringFUTF16(message_id,
a, b));
}
NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b,
- const string16& c) {
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c) {
return FixUpWindowsStyleLabel(l10n_util::GetStringFUTF16(message_id,
a, b, c));
}
NSString* GetNSStringFWithFixup(int message_id,
- const string16& a,
- const string16& b,
- const string16& c,
- const string16& d) {
+ const base::string16& a,
+ const base::string16& b,
+ const base::string16& c,
+ const base::string16& d) {
return FixUpWindowsStyleLabel(l10n_util::GetStringFUTF16(message_id,
a, b, c, d));
}
diff --git a/chromium/ui/base/l10n/l10n_util_mac_unittest.mm b/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
index ec316728710..cd3e2034729 100644
--- a/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
+++ b/chromium/ui/base/l10n/l10n_util_mac_unittest.mm
@@ -37,7 +37,7 @@ TEST_F(L10nUtilMacTest, FixUpWindowsStyleLabel) {
{ @"(&b)foo", @"foo" },
};
for (size_t idx = 0; idx < ARRAYSIZE_UNSAFE(data); ++idx) {
- string16 input16(base::SysNSStringToUTF16(data[idx].input));
+ base::string16 input16(base::SysNSStringToUTF16(data[idx].input));
NSString* result = l10n_util::FixUpWindowsStyleLabel(input16);
EXPECT_TRUE(result != nil) << "Fixup Failed, idx = " << idx;
diff --git a/chromium/ui/base/l10n/l10n_util_unittest.cc b/chromium/ui/base/l10n/l10n_util_unittest.cc
index 6207ffa64e8..dbf38958d38 100644
--- a/chromium/ui/base/l10n/l10n_util_unittest.cc
+++ b/chromium/ui/base/l10n/l10n_util_unittest.cc
@@ -33,15 +33,18 @@
#include "ui/base/test/data/resource.h"
#endif
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+
namespace {
class StringWrapper {
public:
- explicit StringWrapper(const string16& string) : string_(string) {}
- const string16& string() const { return string_; }
+ explicit StringWrapper(const base::string16& string) : string_(string) {}
+ const base::string16& string() const { return string_; }
private:
- string16 string_;
+ base::string16 string_;
DISALLOW_COPY_AND_ASSIGN(StringWrapper);
};
@@ -62,7 +65,7 @@ TEST_F(L10nUtilTest, DISABLED_GetString) {
UTF8ToUTF16("10"));
EXPECT_EQ(std::string("Hello, chrome. Your number is 10."), s);
- string16 s16 = l10n_util::GetStringFUTF16Int(IDS_PLACEHOLDERS_2, 20);
+ base::string16 s16 = l10n_util::GetStringFUTF16Int(IDS_PLACEHOLDERS_2, 20);
EXPECT_EQ(UTF8ToUTF16("You owe me $20."), s16);
}
#endif // defined(OS_WIN)
@@ -125,7 +128,7 @@ TEST_F(L10nUtilTest, GetAppLocale) {
for (size_t i = 0; i < arraysize(filenames); ++i) {
base::FilePath filename = new_locale_dir.AppendASCII(
filenames[i] + ".pak");
- file_util::WriteFile(filename, "", 0);
+ base::WriteFile(filename, "", 0);
}
// Keep a copy of ICU's default locale before we overwrite it.
@@ -326,13 +329,13 @@ void CheckUiDisplayNameForLocale(const std::string& locale,
const std::string& display_locale,
bool is_rtl) {
EXPECT_EQ(true, base::i18n::IsRTL());
- string16 result = l10n_util::GetDisplayNameForLocale(locale,
+ base::string16 result = l10n_util::GetDisplayNameForLocale(locale,
display_locale,
/* is_for_ui */ true);
bool rtl_direction = true;
for (size_t i = 0; i < result.length() - 1; i++) {
- char16 ch = result.at(i);
+ base::char16 ch = result.at(i);
switch (ch) {
case base::i18n::kLeftToRightMark:
case base::i18n::kLeftToRightEmbeddingMark:
@@ -352,7 +355,8 @@ void CheckUiDisplayNameForLocale(const std::string& locale,
TEST_F(L10nUtilTest, GetDisplayNameForLocale) {
// TODO(jungshik): Make this test more extensive.
// Test zh-CN and zh-TW are treated as zh-Hans and zh-Hant.
- string16 result = l10n_util::GetDisplayNameForLocale("zh-CN", "en", false);
+ base::string16 result =
+ l10n_util::GetDisplayNameForLocale("zh-CN", "en", false);
EXPECT_EQ(ASCIIToUTF16("Chinese (Simplified Han)"), result);
result = l10n_util::GetDisplayNameForLocale("zh-TW", "en", false);
@@ -370,7 +374,6 @@ TEST_F(L10nUtilTest, GetDisplayNameForLocale) {
result = l10n_util::GetDisplayNameForLocale("xyz-xyz", "en", false);
EXPECT_EQ(ASCIIToUTF16("xyz (XYZ)"), result);
-#if !defined(TOOLKIT_GTK)
// Check for directional markers when using RTL languages to ensure that
// direction neutral characters such as parentheses are properly formatted.
@@ -383,26 +386,25 @@ TEST_F(L10nUtilTest, GetDisplayNameForLocale) {
// Clean up.
base::i18n::SetICUDefaultLocale(original_locale);
-#endif
// ToUpper and ToLower should work with embedded NULLs.
const size_t length_with_null = 4;
- char16 buf_with_null[length_with_null] = { 0, 'a', 0, 'b' };
- string16 string16_with_null(buf_with_null, length_with_null);
+ base::char16 buf_with_null[length_with_null] = { 0, 'a', 0, 'b' };
+ base::string16 string16_with_null(buf_with_null, length_with_null);
- string16 upper_with_null = base::i18n::ToUpper(string16_with_null);
+ base::string16 upper_with_null = base::i18n::ToUpper(string16_with_null);
ASSERT_EQ(length_with_null, upper_with_null.size());
EXPECT_TRUE(upper_with_null[0] == 0 && upper_with_null[1] == 'A' &&
upper_with_null[2] == 0 && upper_with_null[3] == 'B');
- string16 lower_with_null = base::i18n::ToLower(upper_with_null);
+ base::string16 lower_with_null = base::i18n::ToLower(upper_with_null);
ASSERT_EQ(length_with_null, upper_with_null.size());
EXPECT_TRUE(lower_with_null[0] == 0 && lower_with_null[1] == 'a' &&
lower_with_null[2] == 0 && lower_with_null[3] == 'b');
}
TEST_F(L10nUtilTest, GetDisplayNameForCountry) {
- string16 result = l10n_util::GetDisplayNameForCountry("BR", "en");
+ base::string16 result = l10n_util::GetDisplayNameForCountry("BR", "en");
EXPECT_EQ(ASCIIToUTF16("Brazil"), result);
result = l10n_util::GetDisplayNameForCountry("419", "en");
diff --git a/chromium/ui/base/l10n/l10n_util_win.cc b/chromium/ui/base/l10n/l10n_util_win.cc
index bc6a7e9792e..cd0a084a474 100644
--- a/chromium/ui/base/l10n/l10n_util_win.cc
+++ b/chromium/ui/base/l10n/l10n_util_win.cc
@@ -11,6 +11,7 @@
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/win/i18n.h"
#include "base/win/windows_version.h"
#include "grit/app_locale_settings.h"
@@ -20,7 +21,7 @@
namespace {
-void AdjustLogFont(const string16& font_family,
+void AdjustLogFont(const base::string16& font_family,
double font_size_scaler,
double dpi_scale,
LOGFONT* logfont) {
@@ -113,7 +114,7 @@ bool IsLocaleSupportedByOS(const std::string& locale) {
!LowerCaseEqualsASCII(locale, "am") || IsFontPresent(L"Abyssinica SIL"));
}
-bool NeedOverrideDefaultUIFont(string16* override_font_family,
+bool NeedOverrideDefaultUIFont(base::string16* override_font_family,
double* font_size_scaler) {
// This is rather simple-minded to deal with the UI font size
// issue for some Indian locales (ml, bn, hi) for which
@@ -130,7 +131,7 @@ bool NeedOverrideDefaultUIFont(string16* override_font_family,
ui_font_size_scaler_id = IDS_UI_FONT_SIZE_SCALER_XP;
}
- string16 ui_font_family = GetStringUTF16(ui_font_family_id);
+ base::string16 ui_font_family = GetStringUTF16(ui_font_family_id);
int scaler100;
if (!base::StringToInt(l10n_util::GetStringUTF16(ui_font_size_scaler_id),
&scaler100))
@@ -161,7 +162,7 @@ void AdjustUIFont(LOGFONT* logfont) {
}
void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont) {
- string16 ui_font_family = L"default";
+ base::string16 ui_font_family = L"default";
double ui_font_size_scaler = 1;
if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler) ||
dpi_scale != 1) {
@@ -170,7 +171,7 @@ void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont) {
}
void AdjustUIFontForWindow(HWND hwnd) {
- string16 ui_font_family;
+ base::string16 ui_font_family;
double ui_font_size_scaler;
if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler)) {
LOGFONT logfont;
@@ -185,12 +186,12 @@ void AdjustUIFontForWindow(HWND hwnd) {
}
void OverrideLocaleWithUILanguageList() {
- std::vector<std::wstring> ui_languages;
+ std::vector<base::string16> ui_languages;
if (base::win::i18n::GetThreadPreferredUILanguageList(&ui_languages)) {
std::vector<std::string> ascii_languages;
ascii_languages.reserve(ui_languages.size());
std::transform(ui_languages.begin(), ui_languages.end(),
- std::back_inserter(ascii_languages), &WideToASCII);
+ std::back_inserter(ascii_languages), &base::UTF16ToASCII);
override_locale_holder.Get().swap_value(&ascii_languages);
} else {
NOTREACHED() << "Failed to determine the UI language for locale override.";
diff --git a/chromium/ui/base/l10n/l10n_util_win.h b/chromium/ui/base/l10n/l10n_util_win.h
index 75588163341..75bfe5db03a 100644
--- a/chromium/ui/base/l10n/l10n_util_win.h
+++ b/chromium/ui/base/l10n/l10n_util_win.h
@@ -10,7 +10,7 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace l10n_util {
@@ -19,17 +19,17 @@ namespace l10n_util {
// (e.g. WS_EX_LAYOUTRTL, WS_EX_RTLREADING, etc.) when creating a window.
// Callers should OR this value into their extended style value when creating
// a window.
-UI_EXPORT int GetExtendedStyles();
+UI_BASE_EXPORT int GetExtendedStyles();
// TODO(xji):
// This is a temporary name, it will eventually replace GetExtendedStyles
-UI_EXPORT int GetExtendedTooltipStyles();
+UI_BASE_EXPORT int GetExtendedTooltipStyles();
// Give an HWND, this function sets the WS_EX_LAYOUTRTL extended style for the
// underlying window. When this style is set, the UI for the window is going to
// be mirrored. This is generally done for the UI of right-to-left languages
// such as Hebrew.
-UI_EXPORT void HWNDSetRTLLayout(HWND hwnd);
+UI_BASE_EXPORT void HWNDSetRTLLayout(HWND hwnd);
// See http://blogs.msdn.com/oldnewthing/archive/2005/09/15/467598.aspx
// and http://blogs.msdn.com/oldnewthing/archive/2006/06/26/647365.aspx
@@ -40,14 +40,15 @@ UI_EXPORT void HWNDSetRTLLayout(HWND hwnd);
// override_font_family and font_size_scaler are not null, they'll be
// filled with the font family name and the size scaler. The output
// parameters are not modified if the return value is false.
-UI_EXPORT bool NeedOverrideDefaultUIFont(string16* override_font_family,
- double* font_size_scaler);
+UI_BASE_EXPORT bool NeedOverrideDefaultUIFont(
+ base::string16* override_font_family,
+ double* font_size_scaler);
// If the default UI font stored in |logfont| is not suitable, its family
// and size are replaced with those stored in the per-locale resource. The
// font size is adjusted based on the font scale setting in the OS preferences.
// Windows 8 supports scale factors of 1, 1.4 and 1.8.
-UI_EXPORT void AdjustUIFont(LOGFONT* logfont);
+UI_BASE_EXPORT void AdjustUIFont(LOGFONT* logfont);
// If the default UI font stored in |logfont| is not suitable, its family
// and size are replaced with those stored in the per-locale resource. The
@@ -55,17 +56,17 @@ UI_EXPORT void AdjustUIFont(LOGFONT* logfont);
// baseline of 96 DPI. This ratio is also used for converting sizes from
// device independent pixels (DIP) to physical pixels. The font size is scaled
// for use with Views and Aura which work in DIP.
-UI_EXPORT void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont);
+UI_BASE_EXPORT void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont);
// If the font for a given window (pointed to by HWND) is not suitable for the
// UI in the current UI langauge, its family and size are replaced with those
// stored in the per-locale resource.
-UI_EXPORT void AdjustUIFontForWindow(HWND hwnd);
+UI_BASE_EXPORT void AdjustUIFontForWindow(HWND hwnd);
// Allow processes to override the configured locale with the user's Windows UI
// languages. This function should generally be called once early in
// Application startup.
-UI_EXPORT void OverrideLocaleWithUILanguageList();
+UI_BASE_EXPORT void OverrideLocaleWithUILanguageList();
// Retrieve the locale override, or an empty vector if the locale has not been
// or failed to be overridden.
diff --git a/chromium/ui/base/l10n/time_format.cc b/chromium/ui/base/l10n/time_format.cc
index f3b16a3f969..f7fa096485c 100644
--- a/chromium/ui/base/l10n/time_format.cc
+++ b/chromium/ui/base/l10n/time_format.cc
@@ -4,361 +4,117 @@
#include "ui/base/l10n/time_format.h"
-#include <vector>
+#include <limits>
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/stl_util.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "grit/ui_strings.h"
-#include "third_party/icu/source/common/unicode/locid.h"
-#include "third_party/icu/source/i18n/unicode/datefmt.h"
-#include "third_party/icu/source/i18n/unicode/plurfmt.h"
-#include "third_party/icu/source/i18n/unicode/plurrule.h"
-#include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+#include "ui/base/l10n/formatter.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_plurals.h"
+#include "ui/base/ui_base_export.h"
using base::Time;
using base::TimeDelta;
+using ui::TimeFormat;
-namespace {
-
-static const char kFallbackFormatSuffixShort[] = "}";
-static const char kFallbackFormatSuffixLeft[] = " left}";
-static const char kFallbackFormatSuffixAgo[] = " ago}";
-
-// Contains message IDs for various time units and pluralities.
-struct MessageIDs {
- // There are 4 different time units and 6 different pluralities.
- int ids[4][6];
-};
-
-// Message IDs for different time formats.
-static const MessageIDs kTimeShortMessageIDs = { {
- {
- IDS_TIME_SECS_DEFAULT, IDS_TIME_SEC_SINGULAR, IDS_TIME_SECS_ZERO,
- IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY
- },
- {
- IDS_TIME_MINS_DEFAULT, IDS_TIME_MIN_SINGULAR, IDS_TIME_MINS_ZERO,
- IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY
- },
- {
- IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR, IDS_TIME_HOURS_ZERO,
- IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY
- },
- {
- IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR, IDS_TIME_DAYS_ZERO,
- IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY
- }
-} };
-
-static const MessageIDs kTimeRemainingMessageIDs = { {
- {
- IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR,
- IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO,
- IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY
- },
- {
- IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MIN_SINGULAR,
- IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO,
- IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY
- },
- {
- IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR,
- IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO,
- IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY
- },
- {
- IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR,
- IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO,
- IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY
- }
-} };
-
-static const MessageIDs kTimeRemainingLongMessageIDs = { {
- {
- IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR,
- IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO,
- IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY
- },
- {
- IDS_TIME_REMAINING_LONG_MINS_DEFAULT, IDS_TIME_REMAINING_LONG_MIN_SINGULAR,
- IDS_TIME_REMAINING_LONG_MINS_ZERO, IDS_TIME_REMAINING_LONG_MINS_TWO,
- IDS_TIME_REMAINING_LONG_MINS_FEW, IDS_TIME_REMAINING_LONG_MINS_MANY
- },
- {
- IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR,
- IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO,
- IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY
- },
- {
- IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR,
- IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO,
- IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY
- }
-} };
-
-static const MessageIDs kTimeDurationLongMessageIDs = { {
- {
- IDS_TIME_DURATION_LONG_SECS_DEFAULT, IDS_TIME_DURATION_LONG_SEC_SINGULAR,
- IDS_TIME_DURATION_LONG_SECS_ZERO, IDS_TIME_DURATION_LONG_SECS_TWO,
- IDS_TIME_DURATION_LONG_SECS_FEW, IDS_TIME_DURATION_LONG_SECS_MANY
- },
- {
- IDS_TIME_DURATION_LONG_MINS_DEFAULT, IDS_TIME_DURATION_LONG_MIN_SINGULAR,
- IDS_TIME_DURATION_LONG_MINS_ZERO, IDS_TIME_DURATION_LONG_MINS_TWO,
- IDS_TIME_DURATION_LONG_MINS_FEW, IDS_TIME_DURATION_LONG_MINS_MANY
- },
- {
- IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR,
- IDS_TIME_HOURS_ZERO, IDS_TIME_HOURS_TWO,
- IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY
- },
- {
- IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR,
- IDS_TIME_DAYS_ZERO, IDS_TIME_DAYS_TWO,
- IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY
- }
-} };
-
-static const MessageIDs kTimeElapsedMessageIDs = { {
- {
- IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SEC_SINGULAR,
- IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO,
- IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY
- },
- {
- IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MIN_SINGULAR,
- IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO,
- IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY
- },
- {
- IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOUR_SINGULAR,
- IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO,
- IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY
- },
- {
- IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAY_SINGULAR,
- IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO,
- IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY
- }
-} };
-
-// Different format types.
-enum FormatType {
- FORMAT_SHORT,
- FORMAT_REMAINING,
- FORMAT_REMAINING_LONG,
- FORMAT_DURATION_LONG,
- FORMAT_ELAPSED,
-};
-
-class TimeFormatter {
- public:
- const std::vector<icu::PluralFormat*>& formatter(FormatType format_type) {
- switch (format_type) {
- case FORMAT_SHORT:
- return short_formatter_.get();
- case FORMAT_REMAINING:
- return time_left_formatter_.get();
- case FORMAT_REMAINING_LONG:
- return time_left_long_formatter_.get();
- case FORMAT_DURATION_LONG:
- return time_duration_long_formatter_.get();
- case FORMAT_ELAPSED:
- return time_elapsed_formatter_.get();
- default:
- NOTREACHED();
- return short_formatter_.get();
- }
- }
- private:
- static const MessageIDs& GetMessageIDs(FormatType format_type) {
- switch (format_type) {
- case FORMAT_SHORT:
- return kTimeShortMessageIDs;
- case FORMAT_REMAINING:
- return kTimeRemainingMessageIDs;
- case FORMAT_REMAINING_LONG:
- return kTimeRemainingLongMessageIDs;
- case FORMAT_DURATION_LONG:
- return kTimeDurationLongMessageIDs;
- case FORMAT_ELAPSED:
- return kTimeElapsedMessageIDs;
- default:
- NOTREACHED();
- return kTimeShortMessageIDs;
- }
- }
-
- static const char* GetFallbackFormatSuffix(FormatType format_type) {
- switch (format_type) {
- case FORMAT_SHORT:
- return kFallbackFormatSuffixShort;
- case FORMAT_REMAINING:
- case FORMAT_REMAINING_LONG:
- return kFallbackFormatSuffixLeft;
- case FORMAT_ELAPSED:
- return kFallbackFormatSuffixAgo;
- default:
- NOTREACHED();
- return kFallbackFormatSuffixShort;
- }
- }
-
- TimeFormatter() {
- BuildFormats(FORMAT_SHORT, &short_formatter_);
- BuildFormats(FORMAT_REMAINING, &time_left_formatter_);
- BuildFormats(FORMAT_REMAINING_LONG, &time_left_long_formatter_);
- BuildFormats(FORMAT_DURATION_LONG, &time_duration_long_formatter_);
- BuildFormats(FORMAT_ELAPSED, &time_elapsed_formatter_);
- }
- ~TimeFormatter() {
- }
- friend struct base::DefaultLazyInstanceTraits<TimeFormatter>;
-
- ScopedVector<icu::PluralFormat> short_formatter_;
- ScopedVector<icu::PluralFormat> time_left_formatter_;
- ScopedVector<icu::PluralFormat> time_left_long_formatter_;
- ScopedVector<icu::PluralFormat> time_duration_long_formatter_;
- ScopedVector<icu::PluralFormat> time_elapsed_formatter_;
- static void BuildFormats(FormatType format_type,
- ScopedVector<icu::PluralFormat>* time_formats);
- static icu::PluralFormat* createFallbackFormat(
- const icu::PluralRules& rules, int index, FormatType format_type);
-
- DISALLOW_COPY_AND_ASSIGN(TimeFormatter);
-};
+namespace ui {
-static base::LazyInstance<TimeFormatter> g_time_formatter =
+UI_BASE_EXPORT base::LazyInstance<FormatterContainer> g_container =
LAZY_INSTANCE_INITIALIZER;
-void TimeFormatter::BuildFormats(
- FormatType format_type, ScopedVector<icu::PluralFormat>* time_formats) {
- const MessageIDs& message_ids = GetMessageIDs(format_type);
-
- for (int i = 0; i < 4; ++i) {
- icu::UnicodeString pattern;
- std::vector<int> ids;
- for (size_t j = 0; j < arraysize(message_ids.ids[i]); ++j) {
- ids.push_back(message_ids.ids[i][j]);
- }
- scoped_ptr<icu::PluralFormat> format = l10n_util::BuildPluralFormat(ids);
- if (format) {
- time_formats->push_back(format.release());
- } else {
- scoped_ptr<icu::PluralRules> rules(l10n_util::BuildPluralRules());
- time_formats->push_back(createFallbackFormat(*rules, i, format_type));
- }
- }
-}
-
-// Create a hard-coded fallback plural format. This will never be called
-// unless translators make a mistake.
-icu::PluralFormat* TimeFormatter::createFallbackFormat(
- const icu::PluralRules& rules, int index, FormatType format_type) {
- const icu::UnicodeString kUnits[4][2] = {
- { UNICODE_STRING_SIMPLE("sec"), UNICODE_STRING_SIMPLE("secs") },
- { UNICODE_STRING_SIMPLE("min"), UNICODE_STRING_SIMPLE("mins") },
- { UNICODE_STRING_SIMPLE("hour"), UNICODE_STRING_SIMPLE("hours") },
- { UNICODE_STRING_SIMPLE("day"), UNICODE_STRING_SIMPLE("days") }
- };
- icu::UnicodeString suffix(GetFallbackFormatSuffix(format_type), -1, US_INV);
- icu::UnicodeString pattern;
- if (rules.isKeyword(UNICODE_STRING_SIMPLE("one"))) {
- pattern += UNICODE_STRING_SIMPLE("one{# ") + kUnits[index][0] + suffix;
- }
- pattern += UNICODE_STRING_SIMPLE(" other{# ") + kUnits[index][1] + suffix;
- UErrorCode err = U_ZERO_ERROR;
- icu::PluralFormat* format = new icu::PluralFormat(rules, pattern, err);
- DCHECK(U_SUCCESS(err));
- return format;
+// static
+base::string16 TimeFormat::Simple(TimeFormat::Format format,
+ TimeFormat::Length length,
+ const base::TimeDelta& delta) {
+ return Detailed(format, length, 0, delta);
}
-base::string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
- if (delta.ToInternalValue() < 0) {
+// static
+base::string16 TimeFormat::Detailed(TimeFormat::Format format,
+ TimeFormat::Length length,
+ int cutoff,
+ const base::TimeDelta& delta) {
+ if (delta < TimeDelta::FromSeconds(0)) {
NOTREACHED() << "Negative duration";
return base::string16();
}
- int number;
+ // Negative cutoff: always use two-value format.
+ if (cutoff < 0)
+ cutoff = std::numeric_limits<int>::max();
- const std::vector<icu::PluralFormat*>& formatters =
- g_time_formatter.Get().formatter(format_type);
+ const TimeDelta one_minute(TimeDelta::FromMinutes(1));
+ const TimeDelta one_hour(TimeDelta::FromHours(1));
+ const TimeDelta one_day(TimeDelta::FromDays(1));
+ const TimeDelta half_second(TimeDelta::FromMilliseconds(500));
+ const TimeDelta half_minute(TimeDelta::FromSeconds(30));
+ const TimeDelta half_hour(TimeDelta::FromMinutes(30));
+ const TimeDelta half_day(TimeDelta::FromHours(12));
- UErrorCode error = U_ZERO_ERROR;
+ // Rationale: Start by determining major (first) unit, then add minor (second)
+ // unit if mandated by |cutoff|.
icu::UnicodeString time_string;
- // Less than a minute gets "X seconds left"
- if (delta.ToInternalValue() < Time::kMicrosecondsPerMinute) {
- number = static_cast<int>(delta.ToInternalValue() /
- Time::kMicrosecondsPerSecond);
- time_string = formatters[0]->format(number, error);
-
- // Less than 1 hour gets "X minutes left".
- } else if (delta.ToInternalValue() < Time::kMicrosecondsPerHour) {
- number = static_cast<int>(delta.ToInternalValue() /
- Time::kMicrosecondsPerMinute);
- time_string = formatters[1]->format(number, error);
+ const Formatter* formatter = g_container.Get().Get(format, length);
+ if (delta < one_minute - half_second) {
+ // Anything up to 59.500 seconds is formatted as seconds.
+ const int seconds = static_cast<int>((delta + half_second).InSeconds());
+ formatter->Format(Formatter::UNIT_SEC, seconds, time_string);
+
+ } else if (delta < one_hour - (cutoff < 60 ? half_minute : half_second)) {
+ // Anything up to 59.5 minutes (respectively 59:59.500 when |cutoff| permits
+ // two-value output) is formatted as minutes (respectively minutes and
+ // seconds).
+ if (delta >= cutoff * one_minute - half_second) {
+ const int minutes = (delta + half_minute).InMinutes();
+ formatter->Format(Formatter::UNIT_MIN, minutes, time_string);
+ } else {
+ const int minutes = (delta + half_second).InMinutes();
+ const int seconds = static_cast<int>(
+ (delta + half_second).InSeconds() % 60);
+ formatter->Format(Formatter::TWO_UNITS_MIN_SEC,
+ minutes, seconds, time_string);
+ }
- // Less than 1 day remaining gets "X hours left"
- } else if (delta.ToInternalValue() < Time::kMicrosecondsPerDay) {
- number = static_cast<int>(delta.ToInternalValue() /
- Time::kMicrosecondsPerHour);
- time_string = formatters[2]->format(number, error);
+ } else if (delta < one_day - (cutoff < 24 ? half_hour : half_minute)) {
+ // Anything up to 23.5 hours (respectively 23:59:30.000 when |cutoff|
+ // permits two-value output) is formatted as hours (respectively hours and
+ // minutes).
+ if (delta >= cutoff * one_hour - half_minute) {
+ const int hours = (delta + half_hour).InHours();
+ formatter->Format(Formatter::UNIT_HOUR, hours, time_string);
+ } else {
+ const int hours = (delta + half_minute).InHours();
+ const int minutes = (delta + half_minute).InMinutes() % 60;
+ formatter->Format(Formatter::TWO_UNITS_HOUR_MIN,
+ hours, minutes, time_string);
+ }
- // Anything bigger gets "X days left"
} else {
- number = static_cast<int>(delta.ToInternalValue() /
- Time::kMicrosecondsPerDay);
- time_string = formatters[3]->format(number, error);
+ // Anything bigger is formatted as days (respectively days and hours).
+ if (delta >= cutoff * one_day - half_hour) {
+ const int days = (delta + half_day).InDays();
+ formatter->Format(Formatter::UNIT_DAY, days, time_string);
+ } else {
+ const int days = (delta + half_hour).InDays();
+ const int hours = (delta + half_hour).InHours() % 24;
+ formatter->Format(Formatter::TWO_UNITS_DAY_HOUR,
+ days, hours, time_string);
+ }
}
- // With the fallback added, this should never fail.
- DCHECK(U_SUCCESS(error));
- int capacity = time_string.length() + 1;
+ const int capacity = time_string.length() + 1;
DCHECK_GT(capacity, 1);
base::string16 result;
+ UErrorCode error = U_ZERO_ERROR;
time_string.extract(static_cast<UChar*>(WriteInto(&result, capacity)),
capacity, error);
DCHECK(U_SUCCESS(error));
return result;
}
-} // namespace
-
-namespace ui {
-
-// static
-base::string16 TimeFormat::TimeElapsed(const TimeDelta& delta) {
- return FormatTimeImpl(delta, FORMAT_ELAPSED);
-}
-
-// static
-base::string16 TimeFormat::TimeRemaining(const TimeDelta& delta) {
- return FormatTimeImpl(delta, FORMAT_REMAINING);
-}
-
-// static
-base::string16 TimeFormat::TimeRemainingLong(const TimeDelta& delta) {
- return FormatTimeImpl(delta, FORMAT_REMAINING_LONG);
-}
-
-// static
-base::string16 TimeFormat::TimeRemainingShort(const TimeDelta& delta) {
- return FormatTimeImpl(delta, FORMAT_SHORT);
-}
-
-// static
-base::string16 TimeFormat::TimeDurationLong(const TimeDelta& delta) {
- return FormatTimeImpl(delta, FORMAT_DURATION_LONG);
-}
-
// static
base::string16 TimeFormat::RelativeDate(
const Time& time,
diff --git a/chromium/ui/base/l10n/time_format.h b/chromium/ui/base/l10n/time_format.h
index 0b3a1be3531..38da936d617 100644
--- a/chromium/ui/base/l10n/time_format.h
+++ b/chromium/ui/base/l10n/time_format.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace base {
class Time;
@@ -17,29 +17,61 @@ class TimeDelta;
namespace ui {
// Methods to format time values as strings.
-class UI_EXPORT TimeFormat {
+class UI_BASE_EXPORT TimeFormat {
public:
- // TimeElapsed, TimeRemaining and TimeRemainingShort functions:
- // These functions return a localized string of approximate time duration. The
- // conditions are simpler than PastTime since these functions are used for
- // in-progress operations and users have different expectations of units.
+ enum Format {
+ FORMAT_DURATION, // Plain duration, e.g. in English: "2 minutes".
+ FORMAT_REMAINING, // Remaining time, e.g. in English: "2 minutes left".
+ FORMAT_ELAPSED, // Elapsed time, e.g. in English: "2 minutes ago".
+ FORMAT_COUNT // Enum size counter, not a format. Must be last.
+ };
- // Returns times in elapsed-format: "3 mins ago", "2 days ago".
- static base::string16 TimeElapsed(const base::TimeDelta& delta);
+ enum Length {
+ LENGTH_SHORT, // Short format, e.g. in English: sec/min/hour/day.
+ LENGTH_LONG, // Long format, e.g. in English: second/minute/hour/day.
+ LENGTH_COUNT // Enum size counter, not a length. Must be last.
+ };
- // Returns times in remaining-format: "3 mins left", "2 days left".
- static base::string16 TimeRemaining(const base::TimeDelta& delta);
+ // Return a localized string of approximate time duration, formatted as a
+ // single number, e.g. in English "2 hours ago". Currently, all combinations
+ // of format and length except (FORMAT_ELAPSED, LENGTH_LONG) are implemented
+ // but it's easy to add this, if required.
+ static base::string16 Simple(Format format,
+ Length length,
+ const base::TimeDelta& delta);
- // Returns times in remaining-long-format: "3 minutes left", "2 days left".
- // Currently, this only affects the minutes in long format, the rest
- // of the time units are formatted the same as TimeRemaining does.
- static base::string16 TimeRemainingLong(const base::TimeDelta& delta);
-
- // Returns times in short-format: "3 mins", "2 days".
- static base::string16 TimeRemainingShort(const base::TimeDelta& delta);
-
- // Return times in long-format: "2 hours", "25 minutes".
- static base::string16 TimeDurationLong(const base::TimeDelta& delta);
+ // Return a localized string of more precise time duration, either formatted
+ // as a single value or as two values: for a time delta of e.g. 2h19m either
+ // "2 hours" or "2 hours and 19 minutes" could be returned in English.
+ // Two-value output can be forced by setting |cutoff| to -1. Single-value
+ // output can be forced by using Simple() or setting |cutoff| to 0.
+ // Otherwise, choice of format happens automatically and the value of |cutoff|
+ // determines the largest numeric value that may appear in a single-value
+ // format -- for lower numeric values, a second unit is added to increase
+ // precision. (Applied to the examples above, a |cutoff| of 2 or smaller
+ // would yield the first string and a |cutoff| of 3 or larger would return the
+ // second string.)
+ //
+ // The aim of this logic is to reduce rounding errors (that in single-value
+ // representation can amount up to 33% of the true time duration) while at the
+ // same time avoiding over-precise time outputs such as e.g. "56 minutes 29
+ // seconds". The relative rounding error is guaranteed to be less than 0.5 /
+ // |cutoff| (e.g. 5% for a |cutoff| of 10) and a second unit is only used when
+ // necessary to achieve the precision guarantee.
+ //
+ // Currently, the only combination of format and length that is implemented is
+ // (FORMAT_DURATION, LENGTH_LONG), but it's easy to add others if required.
+ //
+ // Note: To allow pre-, post- and infixes which can be inflected depending on
+ // either the first or the second value, two separate translation strings
+ // (IDS_TIME_*_1ST and IDS_TIME_*_2ND) are used per [plurality] times [pair of
+ // units] and are concatenated after having been formatted individually. The
+ // separator between first unit and second unit (a blank in English) is
+ // included in IDS_TIME_*_1ST.
+ static base::string16 Detailed(Format format,
+ Length length,
+ int cutoff,
+ const base::TimeDelta& delta);
// For displaying a relative time in the past. This method returns either
// "Today", "Yesterday", or an empty string if it's older than that. Returns
diff --git a/chromium/ui/base/l10n/time_format_unittest.cc b/chromium/ui/base/l10n/time_format_unittest.cc
index eaee957136f..9a237b19e1f 100644
--- a/chromium/ui/base/l10n/time_format_unittest.cc
+++ b/chromium/ui/base/l10n/time_format_unittest.cc
@@ -4,68 +4,348 @@
#include "ui/base/l10n/time_format.h"
+#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/formatter.h"
#include "ui/base/resource/resource_bundle.h"
+using base::ASCIIToUTF16;
+
namespace ui {
namespace {
using base::TimeDelta;
-void TestTimeFormats(const TimeDelta& delta, const char* expected_ascii) {
- string16 expected = ASCIIToUTF16(expected_ascii);
- string16 expected_left = expected + ASCIIToUTF16(" left");
- string16 expected_ago = expected + ASCIIToUTF16(" ago");
- EXPECT_EQ(expected, TimeFormat::TimeRemainingShort(delta));
- EXPECT_EQ(expected_left, TimeFormat::TimeRemaining(delta));
- EXPECT_EQ(expected_ago, TimeFormat::TimeElapsed(delta));
+class TimeFormatTest : public ::testing::Test {
+ public:
+ TimeFormatTest() :
+ delta_0s_(TimeDelta::FromSeconds(0)),
+ delta_1ms_(TimeDelta::FromMilliseconds(1)),
+ delta_499ms_(TimeDelta::FromMilliseconds(499)),
+ delta_500ms_(TimeDelta::FromMilliseconds(500)),
+ delta_999ms_(TimeDelta::FromMilliseconds(999)),
+ delta_1s_(TimeDelta::FromSeconds(1)),
+ delta_1s499ms_(delta_1s_ + delta_499ms_),
+ delta_1s500ms_(delta_1s_ + delta_500ms_),
+ delta_2s_(TimeDelta::FromSeconds(2)),
+ delta_29s_(TimeDelta::FromSeconds(29)),
+ delta_30s_(TimeDelta::FromSeconds(30)),
+ delta_59s_(TimeDelta::FromSeconds(59)),
+ delta_59s499ms_(delta_59s_ + delta_499ms_),
+ delta_59s500ms_(delta_59s_ + delta_500ms_),
+ delta_1m_(TimeDelta::FromMinutes(1)),
+ delta_1m2s_(delta_1m_ + delta_2s_),
+ delta_1m29s999ms_(delta_1m_ + delta_29s_ + delta_999ms_),
+ delta_1m30s_(delta_1m_ + delta_30s_),
+ delta_2m_(TimeDelta::FromMinutes(2)),
+ delta_2m1s_(delta_2m_ + delta_1s_),
+ delta_29m_(TimeDelta::FromMinutes(29)),
+ delta_30m_(TimeDelta::FromMinutes(30)),
+ delta_59m_(TimeDelta::FromMinutes(59)),
+ delta_59m29s999ms_(delta_59m_ + delta_29s_ + delta_999ms_),
+ delta_59m30s_(delta_59m_ + delta_30s_),
+ delta_59m59s499ms_(delta_59m_ + delta_59s_ + delta_499ms_),
+ delta_59m59s500ms_(delta_59m_ + delta_59s_ + delta_500ms_),
+ delta_1h_(TimeDelta::FromHours(1)),
+ delta_1h2m_(delta_1h_ + delta_2m_),
+ delta_1h29m59s999ms_(delta_1h_ + delta_29m_ + delta_59s_ + delta_999ms_),
+ delta_1h30m_(delta_1h_ + delta_30m_),
+ delta_2h_(TimeDelta::FromHours(2)),
+ delta_2h1m_(delta_2h_ + delta_1m_),
+ delta_11h_(TimeDelta::FromHours(11)),
+ delta_12h_(TimeDelta::FromHours(12)),
+ delta_23h_(TimeDelta::FromHours(23)),
+ delta_23h29m59s999ms_(delta_23h_ + delta_29m_ + delta_59s_ +
+ delta_999ms_),
+ delta_23h30m_(delta_23h_ + delta_30m_),
+ delta_23h59m29s999ms_(delta_23h_ + delta_59m_ + delta_29s_ +
+ delta_999ms_),
+ delta_23h59m30s_(delta_23h_ + delta_59m_ + delta_30s_),
+ delta_1d_(TimeDelta::FromDays(1)),
+ delta_1d2h_(delta_1d_ + delta_2h_),
+ delta_1d11h59m59s999ms_(delta_1d_ + delta_11h_ + delta_59m_ + delta_29s_ +
+ delta_999ms_),
+ delta_1d12h_(delta_1d_ + delta_12h_),
+ delta_2d_(TimeDelta::FromDays(2)),
+ delta_2d1h_(delta_2d_ + delta_1h_)
+ {}
+
+ protected:
+ void TestStrings() {
+ // Test English strings (simple, singular).
+ EXPECT_EQ(ASCIIToUTF16("1 sec"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 min"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1h_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1d_));
+ EXPECT_EQ(ASCIIToUTF16("1 second"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 minute"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_1h_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_1d_));
+ EXPECT_EQ(ASCIIToUTF16("1 sec left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 min left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_1h_));
+ EXPECT_EQ(ASCIIToUTF16("1 day left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_1d_));
+ EXPECT_EQ(ASCIIToUTF16("1 second left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 minute left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_1h_));
+ EXPECT_EQ(ASCIIToUTF16("1 day left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_1d_));
+ EXPECT_EQ(ASCIIToUTF16("1 sec ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 min ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_1h_));
+ EXPECT_EQ(ASCIIToUTF16("1 day ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_1d_));
+
+ // Test English strings (simple, plural).
+ EXPECT_EQ(ASCIIToUTF16("2 secs"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 mins"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_2d_));
+ EXPECT_EQ(ASCIIToUTF16("2 seconds"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 minutes"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, delta_2d_));
+ EXPECT_EQ(ASCIIToUTF16("2 secs left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 mins left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_SHORT, delta_2d_));
+ EXPECT_EQ(ASCIIToUTF16("2 seconds left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 minutes left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days left"), TimeFormat::Simple(
+ TimeFormat::FORMAT_REMAINING, TimeFormat::LENGTH_LONG, delta_2d_));
+ EXPECT_EQ(ASCIIToUTF16("2 secs ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 mins ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days ago"), TimeFormat::Simple(
+ TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_SHORT, delta_2d_));
+
+ // Test English strings (detailed, singular and plural).
+ EXPECT_EQ(ASCIIToUTF16("1 minute 2 seconds"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_1m2s_));
+ EXPECT_EQ(ASCIIToUTF16("2 minutes 1 second"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_2m1s_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour 2 minutes"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_1h2m_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours 1 minute"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_2h1m_));
+ EXPECT_EQ(ASCIIToUTF16("1 day 2 hours"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_1d2h_));
+ EXPECT_EQ(ASCIIToUTF16("2 days 1 hour"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 3, delta_2d1h_));
+ }
+
+ TimeDelta delta_0s_;
+ TimeDelta delta_1ms_;
+ TimeDelta delta_499ms_;
+ TimeDelta delta_500ms_;
+ TimeDelta delta_999ms_;
+ TimeDelta delta_1s_;
+ TimeDelta delta_1s499ms_;
+ TimeDelta delta_1s500ms_;
+ TimeDelta delta_2s_;
+ TimeDelta delta_29s_;
+ TimeDelta delta_30s_;
+ TimeDelta delta_59s_;
+ TimeDelta delta_59s499ms_;
+ TimeDelta delta_59s500ms_;
+ TimeDelta delta_1m_;
+ TimeDelta delta_1m2s_;
+ TimeDelta delta_1m29s999ms_;
+ TimeDelta delta_1m30s_;
+ TimeDelta delta_2m_;
+ TimeDelta delta_2m1s_;
+ TimeDelta delta_29m_;
+ TimeDelta delta_30m_;
+ TimeDelta delta_59m_;
+ TimeDelta delta_59m29s999ms_;
+ TimeDelta delta_59m30s_;
+ TimeDelta delta_59m59s499ms_;
+ TimeDelta delta_59m59s500ms_;
+ TimeDelta delta_1h_;
+ TimeDelta delta_1h2m_;
+ TimeDelta delta_1h29m59s999ms_;
+ TimeDelta delta_1h30m_;
+ TimeDelta delta_2h_;
+ TimeDelta delta_2h1m_;
+ TimeDelta delta_11h_;
+ TimeDelta delta_12h_;
+ TimeDelta delta_23h_;
+ TimeDelta delta_23h29m59s999ms_;
+ TimeDelta delta_23h30m_;
+ TimeDelta delta_23h59m29s999ms_;
+ TimeDelta delta_23h59m30s_;
+ TimeDelta delta_1d_;
+ TimeDelta delta_1d2h_;
+ TimeDelta delta_1d11h59m59s999ms_;
+ TimeDelta delta_1d12h_;
+ TimeDelta delta_2d_;
+ TimeDelta delta_2d1h_;
+};
+
+TEST_F(TimeFormatTest, SimpleAndDetailedRounding) {
+ // Test rounding behavior (simple).
+ EXPECT_EQ(ASCIIToUTF16("0 secs"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_0s_));
+ EXPECT_EQ(ASCIIToUTF16("0 secs"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 sec"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_500ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 sec"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("2 secs"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("59 secs"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 min"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_59s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 min"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT,
+ delta_1m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("2 mins"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1m30s_));
+ EXPECT_EQ(ASCIIToUTF16("59 mins"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT,
+ delta_59m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_59m30s_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT,
+ delta_1h29m59s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("2 hours"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1h30m_));
+ EXPECT_EQ(ASCIIToUTF16("23 hours"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT,
+ delta_23h29m59s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_23h30m_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT,
+ delta_1d11h59m59s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("2 days"), TimeFormat::Simple(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_SHORT, delta_1d12h_));
+
+ // Test rounding behavior (detailed).
+ EXPECT_EQ(ASCIIToUTF16("59 seconds"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 100,
+ delta_59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 minute 0 seconds"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 2,
+ delta_59s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 minute"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 1,
+ delta_59s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("59 minutes 59 seconds"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 60,
+ delta_59m59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour 0 minutes"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 59,
+ delta_59m59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour 0 minutes"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 2,
+ delta_59m59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 1,
+ delta_59m59s499ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 1,
+ delta_59m59s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 hour 0 minutes"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 2,
+ delta_59m59s500ms_));
+ EXPECT_EQ(ASCIIToUTF16("23 hours 59 minutes"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 24,
+ delta_23h59m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 day 0 hours"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 23,
+ delta_23h59m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 day 0 hours"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 2,
+ delta_23h59m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 1,
+ delta_23h59m29s999ms_));
+ EXPECT_EQ(ASCIIToUTF16("1 day"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 1,
+ delta_23h59m30s_));
+ EXPECT_EQ(ASCIIToUTF16("1 day 0 hours"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, 2,
+ delta_23h59m30s_));
+ EXPECT_EQ(ASCIIToUTF16("1 day 0 hours"), TimeFormat::Detailed(
+ TimeFormat::FORMAT_DURATION, TimeFormat::LENGTH_LONG, -1,
+ delta_23h59m30s_));
+}
+
+// Test strings in default code path.
+TEST_F(TimeFormatTest, SimpleAndDetailedStrings) {
+ TestStrings();
}
-TEST(TimeFormat, FormatTime) {
- const TimeDelta one_day = TimeDelta::FromDays(1);
- const TimeDelta three_days = TimeDelta::FromDays(3);
- const TimeDelta one_hour = TimeDelta::FromHours(1);
- const TimeDelta four_hours = TimeDelta::FromHours(4);
- const TimeDelta one_min = TimeDelta::FromMinutes(1);
- const TimeDelta three_mins = TimeDelta::FromMinutes(3);
- const TimeDelta one_sec = TimeDelta::FromSeconds(1);
- const TimeDelta five_secs = TimeDelta::FromSeconds(5);
- const TimeDelta twohundred_millisecs = TimeDelta::FromMilliseconds(200);
-
- // TODO(jungshik) : These test only pass when the OS locale is 'en'.
- // We need to add SetUp() and TearDown() to set the locale to 'en'.
- TestTimeFormats(twohundred_millisecs, "0 secs");
- TestTimeFormats(one_sec - twohundred_millisecs, "0 secs");
- TestTimeFormats(one_sec + twohundred_millisecs, "1 sec");
- TestTimeFormats(five_secs + twohundred_millisecs, "5 secs");
- TestTimeFormats(one_min + five_secs, "1 min");
- TestTimeFormats(three_mins + twohundred_millisecs, "3 mins");
- TestTimeFormats(one_hour + five_secs, "1 hour");
- TestTimeFormats(four_hours + five_secs, "4 hours");
- TestTimeFormats(one_day + five_secs, "1 day");
- TestTimeFormats(three_days, "3 days");
- TestTimeFormats(three_days + four_hours, "3 days");
+// Test strings in fallback path in case of translator error.
+TEST_F(TimeFormatTest, SimpleAndDetailedStringFallback) {
+ formatter_force_fallback = true;
+ g_container.Get().ResetForTesting();
+ TestStrings();
+ formatter_force_fallback = false;
+ g_container.Get().ResetForTesting();
}
// crbug.com/159388: This test fails when daylight savings time ends.
-TEST(TimeFormat, RelativeDate) {
+TEST_F(TimeFormatTest, RelativeDate) {
base::Time now = base::Time::Now();
- string16 today_str = TimeFormat::RelativeDate(now, NULL);
+ base::string16 today_str = TimeFormat::RelativeDate(now, NULL);
EXPECT_EQ(ASCIIToUTF16("Today"), today_str);
base::Time yesterday = now - TimeDelta::FromDays(1);
- string16 yesterday_str = TimeFormat::RelativeDate(yesterday, NULL);
+ base::string16 yesterday_str = TimeFormat::RelativeDate(yesterday, NULL);
EXPECT_EQ(ASCIIToUTF16("Yesterday"), yesterday_str);
base::Time two_days_ago = now - TimeDelta::FromDays(2);
- string16 two_days_ago_str = TimeFormat::RelativeDate(two_days_ago, NULL);
+ base::string16 two_days_ago_str =
+ TimeFormat::RelativeDate(two_days_ago, NULL);
EXPECT_TRUE(two_days_ago_str.empty());
base::Time a_week_ago = now - TimeDelta::FromDays(7);
- string16 a_week_ago_str = TimeFormat::RelativeDate(a_week_ago, NULL);
+ base::string16 a_week_ago_str = TimeFormat::RelativeDate(a_week_ago, NULL);
EXPECT_TRUE(a_week_ago_str.empty());
}
diff --git a/chromium/ui/base/layout.cc b/chromium/ui/base/layout.cc
index 2c1fb51a395..aa3aecf55bd 100644
--- a/chromium/ui/base/layout.cc
+++ b/chromium/ui/base/layout.cc
@@ -20,6 +20,7 @@
#if defined(OS_WIN)
#include "base/win/metro.h"
+#include "ui/gfx/win/dpi.h"
#include <Windows.h>
#endif // defined(OS_WIN)
@@ -28,53 +29,18 @@ namespace ui {
namespace {
bool ScaleFactorComparator(const ScaleFactor& lhs, const ScaleFactor& rhs){
- return GetImageScale(lhs) < GetImageScale(rhs);
+ return GetScaleForScaleFactor(lhs) < GetScaleForScaleFactor(rhs);
}
std::vector<ScaleFactor>* g_supported_scale_factors = NULL;
-#if defined(OS_WIN)
-// Helper function that determines whether we want to optimize the UI for touch.
-bool UseTouchOptimizedUI() {
- // If --touch-optimized-ui is specified and not set to "auto", then override
- // the hardware-determined setting (eg. for testing purposes).
- static bool has_touch_optimized_ui = CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kTouchOptimizedUI);
- if (has_touch_optimized_ui) {
- const std::string switch_value = CommandLine::ForCurrentProcess()->
- GetSwitchValueASCII(switches::kTouchOptimizedUI);
-
- // Note that simply specifying the switch is the same as enabled.
- if (switch_value.empty() ||
- switch_value == switches::kTouchOptimizedUIEnabled) {
- return true;
- } else if (switch_value == switches::kTouchOptimizedUIDisabled) {
- return false;
- } else if (switch_value != switches::kTouchOptimizedUIAuto) {
- LOG(ERROR) << "Invalid --touch-optimized-ui option: " << switch_value;
- }
- }
-
- // We use the touch layout only when we are running in Metro mode.
- return base::win::IsMetroProcess() && ui::IsTouchDevicePresent();
-}
-#endif // defined(OS_WIN)
-
const float kScaleFactorScales[] = {1.0f, 1.0f, 1.25f, 1.33f, 1.4f, 1.5f, 1.8f,
- 2.0f, 3.0f};
+ 2.0f, 2.5f, 3.0f};
COMPILE_ASSERT(NUM_SCALE_FACTORS == arraysize(kScaleFactorScales),
kScaleFactorScales_incorrect_size);
} // namespace
-DisplayLayout GetDisplayLayout() {
-#if defined(OS_WIN)
- if (UseTouchOptimizedUI())
- return LAYOUT_TOUCH;
-#endif
- return LAYOUT_DESKTOP;
-}
-
void SetSupportedScaleFactors(
const std::vector<ui::ScaleFactor>& scale_factors) {
if (g_supported_scale_factors != NULL)
@@ -90,7 +56,7 @@ void SetSupportedScaleFactors(
for (std::vector<ScaleFactor>::const_iterator it =
g_supported_scale_factors->begin();
it != g_supported_scale_factors->end(); ++it) {
- scales.push_back(GetImageScale(*it));
+ scales.push_back(kScaleFactorScales[*it]);
}
gfx::ImageSkia::SetSupportedScales(scales);
}
@@ -117,31 +83,15 @@ ScaleFactor GetSupportedScaleFactor(float scale) {
}
float GetImageScale(ScaleFactor scale_factor) {
- return kScaleFactorScales[scale_factor];
-}
-
-bool IsScaleFactorSupported(ScaleFactor scale_factor) {
- DCHECK(g_supported_scale_factors != NULL);
- return std::find(g_supported_scale_factors->begin(),
- g_supported_scale_factors->end(),
- scale_factor) != g_supported_scale_factors->end();
+#if defined(OS_WIN)
+ if (gfx::IsHighDPIEnabled())
+ return gfx::win::GetDeviceScaleFactor();
+#endif
+ return GetScaleForScaleFactor(scale_factor);
}
-// Returns the scale factor closest to |scale| from the full list of factors.
-// Note that it does NOT rely on the list of supported scale factors.
-// Finding the closest match is inefficient and shouldn't be done frequently.
-ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
- float smallest_diff = std::numeric_limits<float>::max();
- ScaleFactor closest_match = SCALE_FACTOR_100P;
- for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
- const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
- float diff = std::abs(kScaleFactorScales[scale_factor] - scale);
- if (diff < smallest_diff) {
- closest_match = scale_factor;
- smallest_diff = diff;
- }
- }
- return closest_match;
+float GetScaleForScaleFactor(ScaleFactor scale_factor) {
+ return kScaleFactorScales[scale_factor];
}
namespace test {
@@ -170,13 +120,13 @@ ScopedSetSupportedScaleFactors::~ScopedSetSupportedScaleFactors() {
} // namespace test
#if !defined(OS_MACOSX)
-ScaleFactor GetScaleFactorForNativeView(gfx::NativeView view) {
+float GetScaleFactorForNativeView(gfx::NativeView view) {
gfx::Screen* screen = gfx::Screen::GetScreenFor(view);
if (screen->IsDIPEnabled()) {
gfx::Display display = screen->GetDisplayNearestWindow(view);
- return GetSupportedScaleFactor(display.device_scale_factor());
+ return display.device_scale_factor();
}
- return ui::SCALE_FACTOR_100P;
+ return 1.0f;
}
#endif // !defined(OS_MACOSX)
diff --git a/chromium/ui/base/layout.h b/chromium/ui/base/layout.h
index 6179a84f721..eaaa926a41e 100644
--- a/chromium/ui/base/layout.h
+++ b/chromium/ui/base/layout.h
@@ -8,26 +8,11 @@
#include <vector>
#include "build/build_config.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
-enum DisplayLayout {
- // The typical layout for e.g. Windows, Mac and Linux.
- LAYOUT_DESKTOP,
-
- // Layout optimized for touch. Used e.g. for Windows 8 Metro mode.
- LAYOUT_TOUCH,
-};
-
-// Returns the display layout that should be used. This could be used
-// e.g. to tweak hard-coded padding that's layout specific, or choose
-// the .pak file of theme resources to load.
-// WARNING: this is deprecated and will be nuked as soon as aura is the default
-// on windows.
-UI_EXPORT DisplayLayout GetDisplayLayout();
-
// Supported UI scale factors for the platform. This is used as an index
// into the array |kScaleFactorScales| which maps the enum value to a float.
// SCALE_FACTOR_NONE is used for density independent resources such as
@@ -42,6 +27,7 @@ enum ScaleFactor {
SCALE_FACTOR_150P,
SCALE_FACTOR_180P,
SCALE_FACTOR_200P,
+ SCALE_FACTOR_250P,
SCALE_FACTOR_300P,
NUM_SCALE_FACTORS // This always appears last.
@@ -50,37 +36,28 @@ enum ScaleFactor {
// Changes the value of GetSupportedScaleFactors() to |scale_factors|.
// Use ScopedSetSupportedScaleFactors for unit tests as not to affect the
// state of other tests.
-UI_EXPORT void SetSupportedScaleFactors(
+UI_BASE_EXPORT void SetSupportedScaleFactors(
const std::vector<ScaleFactor>& scale_factors);
// Returns a vector with the scale factors which are supported by this
// platform, in ascending order.
-UI_EXPORT const std::vector<ScaleFactor>& GetSupportedScaleFactors();
-
-// Returns the float scale value for |scale_factor|.
-UI_EXPORT float GetImageScale(ScaleFactor scale_factor);
+UI_BASE_EXPORT const std::vector<ScaleFactor>& GetSupportedScaleFactors();
// Returns the supported ScaleFactor which most closely matches |scale|.
// Converting from float to ScaleFactor is inefficient and should be done as
// little as possible.
-// TODO(oshima): Make ScaleFactor a class and remove this.
-UI_EXPORT ScaleFactor GetSupportedScaleFactor(float image_scale);
+UI_BASE_EXPORT ScaleFactor GetSupportedScaleFactor(float image_scale);
// Returns the ScaleFactor used by |view|.
-UI_EXPORT ScaleFactor GetScaleFactorForNativeView(gfx::NativeView view);
-
-// Returns true if |scale_factor| is supported by this platform.
-UI_EXPORT bool IsScaleFactorSupported(ScaleFactor scale_factor);
+UI_BASE_EXPORT float GetScaleFactorForNativeView(gfx::NativeView view);
-// Returns the scale factor closest to |scale| from the full list of factors.
-// Note that it does NOT rely on the list of supported scale factors.
-// Finding the closest match is inefficient and shouldn't be done frequently.
-UI_EXPORT ScaleFactor FindClosestScaleFactorUnsafe(float scale);
+// Returns the image scale for the scale factor passed in.
+UI_BASE_EXPORT float GetScaleForScaleFactor(ScaleFactor scale_factor);
namespace test {
// Class which changes the value of GetSupportedScaleFactors() to
// |new_scale_factors| for the duration of its lifetime.
-class UI_EXPORT ScopedSetSupportedScaleFactors {
+class UI_BASE_EXPORT ScopedSetSupportedScaleFactors {
public:
explicit ScopedSetSupportedScaleFactors(
const std::vector<ui::ScaleFactor>& new_scale_factors);
diff --git a/chromium/ui/base/layout_mac.mm b/chromium/ui/base/layout_mac.mm
index 6e50de14f8d..62331e99f0d 100644
--- a/chromium/ui/base/layout_mac.mm
+++ b/chromium/ui/base/layout_mac.mm
@@ -31,8 +31,8 @@ float GetScaleFactorScaleForNativeView(gfx::NativeView view) {
namespace ui {
-ScaleFactor GetScaleFactorForNativeView(gfx::NativeView view) {
- return GetSupportedScaleFactor(GetScaleFactorScaleForNativeView(view));
+float GetScaleFactorForNativeView(gfx::NativeView view) {
+ return GetScaleFactorScaleForNativeView(view);
}
} // namespace ui
diff --git a/chromium/ui/base/layout_unittest.cc b/chromium/ui/base/layout_unittest.cc
index b082beab72a..070247079ef 100644
--- a/chromium/ui/base/layout_unittest.cc
+++ b/chromium/ui/base/layout_unittest.cc
@@ -14,14 +14,15 @@
namespace ui {
TEST(LayoutTest, GetScaleFactorScale) {
- EXPECT_FLOAT_EQ(1.0f, GetImageScale(SCALE_FACTOR_100P));
- EXPECT_FLOAT_EQ(1.25f, GetImageScale(SCALE_FACTOR_125P));
- EXPECT_FLOAT_EQ(1.33f, GetImageScale(SCALE_FACTOR_133P));
- EXPECT_FLOAT_EQ(1.4f, GetImageScale(SCALE_FACTOR_140P));
- EXPECT_FLOAT_EQ(1.5f, GetImageScale(SCALE_FACTOR_150P));
- EXPECT_FLOAT_EQ(1.8f, GetImageScale(SCALE_FACTOR_180P));
- EXPECT_FLOAT_EQ(2.0f, GetImageScale(SCALE_FACTOR_200P));
- EXPECT_FLOAT_EQ(3.0f, GetImageScale(SCALE_FACTOR_300P));
+ EXPECT_FLOAT_EQ(1.0f, GetScaleForScaleFactor(SCALE_FACTOR_100P));
+ EXPECT_FLOAT_EQ(1.25f, GetScaleForScaleFactor(SCALE_FACTOR_125P));
+ EXPECT_FLOAT_EQ(1.33f, GetScaleForScaleFactor(SCALE_FACTOR_133P));
+ EXPECT_FLOAT_EQ(1.4f, GetScaleForScaleFactor(SCALE_FACTOR_140P));
+ EXPECT_FLOAT_EQ(1.5f, GetScaleForScaleFactor(SCALE_FACTOR_150P));
+ EXPECT_FLOAT_EQ(1.8f, GetScaleForScaleFactor(SCALE_FACTOR_180P));
+ EXPECT_FLOAT_EQ(2.0f, GetScaleForScaleFactor(SCALE_FACTOR_200P));
+ EXPECT_FLOAT_EQ(2.5f, GetScaleForScaleFactor(SCALE_FACTOR_250P));
+ EXPECT_FLOAT_EQ(3.0f, GetScaleForScaleFactor(SCALE_FACTOR_300P));
}
TEST(LayoutTest, GetScaleFactorFromScalePartlySupported) {
@@ -61,6 +62,10 @@ TEST(LayoutTest, GetScaleFactorFromScaleAllSupported) {
EXPECT_EQ(SCALE_FACTOR_200P, GetSupportedScaleFactor(1.91f));
EXPECT_EQ(SCALE_FACTOR_200P, GetSupportedScaleFactor(2.0f));
EXPECT_EQ(SCALE_FACTOR_200P, GetSupportedScaleFactor(2.1f));
+ EXPECT_EQ(SCALE_FACTOR_250P, GetSupportedScaleFactor(2.3f));
+ EXPECT_EQ(SCALE_FACTOR_250P, GetSupportedScaleFactor(2.5f));
+ EXPECT_EQ(SCALE_FACTOR_250P, GetSupportedScaleFactor(2.6f));
+ EXPECT_EQ(SCALE_FACTOR_300P, GetSupportedScaleFactor(2.9f));
EXPECT_EQ(SCALE_FACTOR_300P, GetSupportedScaleFactor(3.0f));
EXPECT_EQ(SCALE_FACTOR_300P, GetSupportedScaleFactor(3.1f));
EXPECT_EQ(SCALE_FACTOR_300P, GetSupportedScaleFactor(999.0f));
diff --git a/chromium/ui/base/models/button_menu_item_model.h b/chromium/ui/base/models/button_menu_item_model.h
index b9875b2f3e2..b0bc95bd03a 100644
--- a/chromium/ui/base/models/button_menu_item_model.h
+++ b/chromium/ui/base/models/button_menu_item_model.h
@@ -8,13 +8,13 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// A model representing the rows of buttons that should be inserted in a button
// containing menu item.
-class UI_EXPORT ButtonMenuItemModel {
+class UI_BASE_EXPORT ButtonMenuItemModel {
public:
// Types of buttons.
enum ButtonType {
@@ -23,7 +23,7 @@ class UI_EXPORT ButtonMenuItemModel {
TYPE_BUTTON_LABEL
};
- class UI_EXPORT Delegate {
+ class UI_BASE_EXPORT Delegate {
public:
// Some command ids have labels that change over time.
virtual bool IsItemForCommandIdDynamic(int command_id) const;
diff --git a/chromium/ui/base/models/combobox_model.h b/chromium/ui/base/models/combobox_model.h
index 1022685c8bc..361810989f8 100644
--- a/chromium/ui/base/models/combobox_model.h
+++ b/chromium/ui/base/models/combobox_model.h
@@ -6,14 +6,14 @@
#define UI_BASE_MODELS_COMBOBOX_MODEL_H_
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
class ComboboxModelObserver;
// A data model for a combo box.
-class UI_EXPORT ComboboxModel {
+class UI_BASE_EXPORT ComboboxModel {
public:
// Returns the number of items in the combo box.
virtual int GetItemCount() const = 0;
diff --git a/chromium/ui/base/models/combobox_model_observer.h b/chromium/ui/base/models/combobox_model_observer.h
index e79f7375134..f8e281e1842 100644
--- a/chromium/ui/base/models/combobox_model_observer.h
+++ b/chromium/ui/base/models/combobox_model_observer.h
@@ -5,16 +5,18 @@
#ifndef UI_BASE_MODELS_COMBOBOX_MODEL_OBSERVER_H_
#define UI_BASE_MODELS_COMBOBOX_MODEL_OBSERVER_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
+class ComboboxModel;
+
// Observer for the ComboboxModel.
-class UI_EXPORT ComboboxModelObserver {
+class UI_BASE_EXPORT ComboboxModelObserver {
public:
- // Invoked when the model has changed in some way. The observer should assume
+ // Invoked when |model| has changed in some way. The observer should assume
// everything changed.
- virtual void OnModelChanged() = 0;
+ virtual void OnComboboxModelChanged(ComboboxModel* model) = 0;
protected:
virtual ~ComboboxModelObserver() {}
diff --git a/chromium/ui/base/models/dialog_model.h b/chromium/ui/base/models/dialog_model.h
index f7254c55c69..853eb283441 100644
--- a/chromium/ui/base/models/dialog_model.h
+++ b/chromium/ui/base/models/dialog_model.h
@@ -6,15 +6,15 @@
#define UI_BASE_MODELS_DIALOG_MODEL_H_
#include "base/strings/string16.h"
+#include "ui/base/ui_base_export.h"
#include "ui/base/ui_base_types.h"
-#include "ui/base/ui_export.h"
namespace ui {
// A model representing a dialog window. The model provides the content to show
// to the user (i.e. label, title), and the ways the user can interact with it
// (i.e. the buttons).
-class UI_EXPORT DialogModel {
+class UI_BASE_EXPORT DialogModel {
public:
virtual ~DialogModel();
diff --git a/chromium/ui/base/models/list_model_observer.h b/chromium/ui/base/models/list_model_observer.h
index 3f59da97982..cc8be0f6e0a 100644
--- a/chromium/ui/base/models/list_model_observer.h
+++ b/chromium/ui/base/models/list_model_observer.h
@@ -7,11 +7,11 @@
#include <stddef.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
-class UI_EXPORT ListModelObserver {
+class UI_BASE_EXPORT ListModelObserver {
public:
// Invoked after items has been added to the model.
virtual void ListItemsAdded(size_t start, size_t count) = 0;
diff --git a/chromium/ui/base/models/list_selection_model.h b/chromium/ui/base/models/list_selection_model.h
index 8a175092ebb..234714dd2fa 100644
--- a/chromium/ui/base/models/list_selection_model.h
+++ b/chromium/ui/base/models/list_selection_model.h
@@ -8,7 +8,7 @@
#include <vector>
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -21,7 +21,7 @@ namespace ui {
//
// Typically there is only one selected item, in which case the anchor and
// active index correspond to the same thing.
-class UI_EXPORT ListSelectionModel {
+class UI_BASE_EXPORT ListSelectionModel {
public:
typedef std::vector<int> SelectedIndices;
diff --git a/chromium/ui/base/models/menu_model.cc b/chromium/ui/base/models/menu_model.cc
index e88742ebe12..1b5f6ab0bca 100644
--- a/chromium/ui/base/models/menu_model.cc
+++ b/chromium/ui/base/models/menu_model.cc
@@ -40,7 +40,7 @@ base::string16 MenuModel::GetMinorTextAt(int index) const {
return base::string16();
}
-const gfx::Font* MenuModel::GetLabelFontAt(int index) const {
+const gfx::FontList* MenuModel::GetLabelFontListAt(int index) const {
return NULL;
}
diff --git a/chromium/ui/base/models/menu_model.h b/chromium/ui/base/models/menu_model.h
index bd3730c07b7..d0d31005dcd 100644
--- a/chromium/ui/base/models/menu_model.h
+++ b/chromium/ui/base/models/menu_model.h
@@ -8,12 +8,12 @@
#include "base/strings/string16.h"
#include "ui/base/models/menu_model_delegate.h"
#include "ui/base/models/menu_separator_types.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
-class Font;
+class FontList;
class Image;
}
@@ -23,7 +23,7 @@ class Accelerator;
class ButtonMenuItemModel;
// An interface implemented by an object that provides the content of a menu.
-class UI_EXPORT MenuModel {
+class UI_BASE_EXPORT MenuModel {
public:
// The type of item.
enum ItemType {
@@ -71,9 +71,9 @@ class UI_EXPORT MenuModel {
// updated each time the menu is shown.
virtual bool IsItemDynamicAt(int index) const = 0;
- // Returns the font used for the label at the specified index.
- // If NULL, then the default font should be used.
- virtual const gfx::Font* GetLabelFontAt(int index) const;
+ // Returns the font list used for the label at the specified index.
+ // If NULL, then the default font list should be used.
+ virtual const gfx::FontList* GetLabelFontListAt(int index) const;
// Gets the acclerator information for the specified index, returning true if
// there is a shortcut accelerator for the item, false otherwise.
diff --git a/chromium/ui/base/models/simple_combobox_model.cc b/chromium/ui/base/models/simple_combobox_model.cc
new file mode 100644
index 00000000000..edf339de741
--- /dev/null
+++ b/chromium/ui/base/models/simple_combobox_model.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/models/simple_combobox_model.h"
+
+namespace ui {
+
+SimpleComboboxModel::SimpleComboboxModel(
+ const std::vector<base::string16>& items)
+ : items_(items) {
+}
+
+SimpleComboboxModel::~SimpleComboboxModel() {
+}
+
+int SimpleComboboxModel::GetItemCount() const {
+ return items_.size();
+}
+
+base::string16 SimpleComboboxModel::GetItemAt(int index) {
+ return items_[index];
+}
+
+bool SimpleComboboxModel::IsItemSeparatorAt(int index) {
+ return items_[index].empty();
+}
+
+int SimpleComboboxModel::GetDefaultIndex() const {
+ return 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/models/simple_combobox_model.h b/chromium/ui/base/models/simple_combobox_model.h
new file mode 100644
index 00000000000..c978ec932d8
--- /dev/null
+++ b/chromium/ui/base/models/simple_combobox_model.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_MODELS_SIMPLE_COMBOBOX_MODEL_H_
+#define UI_BASE_MODELS_SIMPLE_COMBOBOX_MODEL_H_
+
+#include "ui/base/models/combobox_model.h"
+
+#include <vector>
+
+namespace ui {
+
+// A simple data model for a combobox that takes a string16 vector as the items.
+// An empty string will be a separator.
+class UI_BASE_EXPORT SimpleComboboxModel : public ComboboxModel {
+ public:
+ explicit SimpleComboboxModel(const std::vector<base::string16>& items);
+ virtual ~SimpleComboboxModel();
+
+ // ui::ComboboxModel:
+ virtual int GetItemCount() const OVERRIDE;
+ virtual base::string16 GetItemAt(int index) OVERRIDE;
+ virtual bool IsItemSeparatorAt(int index) OVERRIDE;
+ virtual int GetDefaultIndex() const OVERRIDE;
+
+ private:
+ const std::vector<base::string16> items_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleComboboxModel);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_MODELS_SIMPLE_COMBOBOX_MODEL_H_
diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h
index 69a227b2444..78c8fd6ec3f 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -23,10 +23,12 @@ class ButtonMenuItemModel;
// items. This makes it easy to construct fixed menus. Menus populated by
// dynamic data sources may be better off implementing MenuModel directly.
// The breadth of MenuModel is not exposed through this API.
-class UI_EXPORT SimpleMenuModel : public MenuModel {
+class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
public:
- class UI_EXPORT Delegate {
+ class UI_BASE_EXPORT Delegate {
public:
+ virtual ~Delegate() {}
+
// Methods for determining the state of specific command ids.
virtual bool IsCommandIdChecked(int command_id) const = 0;
virtual bool IsCommandIdEnabled(int command_id) const = 0;
@@ -63,9 +65,6 @@ class UI_EXPORT SimpleMenuModel : public MenuModel {
// Notifies the delegate that the menu has closed.
virtual void MenuClosed(SimpleMenuModel* source);
-
- protected:
- virtual ~Delegate() {}
};
// The Delegate can be NULL, though if it is items can't be checked or
diff --git a/chromium/ui/base/models/table_model.h b/chromium/ui/base/models/table_model.h
index 5792bfee144..68cf20283bc 100644
--- a/chromium/ui/base/models/table_model.h
+++ b/chromium/ui/base/models/table_model.h
@@ -9,7 +9,7 @@
#include "base/strings/string16.h"
#include "third_party/icu/source/i18n/unicode/coll.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace gfx {
class ImageSkia;
@@ -20,7 +20,7 @@ namespace ui {
class TableModelObserver;
// The model driving the TableView.
-class UI_EXPORT TableModel {
+class UI_BASE_EXPORT TableModel {
public:
// See HasGroups, get GetGroupID for details as to how this is used.
struct Group {
@@ -91,7 +91,7 @@ class UI_EXPORT TableModel {
};
// TableColumn specifies the title, alignment and size of a particular column.
-struct UI_EXPORT TableColumn {
+struct UI_BASE_EXPORT TableColumn {
enum Alignment {
LEFT, RIGHT, CENTER
};
diff --git a/chromium/ui/base/models/table_model_observer.h b/chromium/ui/base/models/table_model_observer.h
index 21ee645d9d5..4c9d0eb0329 100644
--- a/chromium/ui/base/models/table_model_observer.h
+++ b/chromium/ui/base/models/table_model_observer.h
@@ -5,13 +5,13 @@
#ifndef UI_BASE_MODELS_TABLE_MODEL_OBSERVER_H_
#define UI_BASE_MODELS_TABLE_MODEL_OBSERVER_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Observer for a TableModel. Anytime the model changes, it must notify its
// observer.
-class UI_EXPORT TableModelObserver {
+class UI_BASE_EXPORT TableModelObserver {
public:
// Invoked when the model has been completely changed.
virtual void OnModelChanged() = 0;
diff --git a/chromium/ui/base/models/tree_model.h b/chromium/ui/base/models/tree_model.h
index 3ebe745e002..d553a4043a8 100644
--- a/chromium/ui/base/models/tree_model.h
+++ b/chromium/ui/base/models/tree_model.h
@@ -8,7 +8,7 @@
#include <vector>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace gfx {
class ImageSkia;
@@ -31,7 +31,7 @@ class TreeModelNode {
};
// Observer for the TreeModel. Notified of significant events to the model.
-class UI_EXPORT TreeModelObserver {
+class UI_BASE_EXPORT TreeModelObserver {
public:
// Notification that nodes were added to the specified parent.
virtual void TreeNodesAdded(TreeModel* model,
@@ -55,7 +55,7 @@ class UI_EXPORT TreeModelObserver {
// TreeModel ------------------------------------------------------------------
// The model for TreeView.
-class UI_EXPORT TreeModel {
+class UI_BASE_EXPORT TreeModel {
public:
// Returns the root of the tree. This may or may not be shown in the tree,
// see SetRootShown for details.
diff --git a/chromium/ui/base/models/tree_node_model.h b/chromium/ui/base/models/tree_node_model.h
index db5cb350a1e..003d20f5c91 100644
--- a/chromium/ui/base/models/tree_node_model.h
+++ b/chromium/ui/base/models/tree_node_model.h
@@ -106,7 +106,7 @@ class TreeNode : public TreeModelNode {
void SetChildren(const std::vector<NodeType*>& children) {
RemoveAll();
for (size_t i = 0; i < children.size(); ++i)
- Add(children[i], i);
+ Add(children[i], static_cast<int>(i));
}
// Returns the parent node, or NULL if this is the root node.
diff --git a/chromium/ui/base/models/tree_node_model_unittest.cc b/chromium/ui/base/models/tree_node_model_unittest.cc
index 48f71b96713..d9d387c3220 100644
--- a/chromium/ui/base/models/tree_node_model_unittest.cc
+++ b/chromium/ui/base/models/tree_node_model_unittest.cc
@@ -12,6 +12,8 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::ASCIIToUTF16;
+
namespace ui {
class TreeNodeModelTest : public testing::Test, public TreeModelObserver {
diff --git a/chromium/ui/base/nine_image_painter_factory.cc b/chromium/ui/base/nine_image_painter_factory.cc
new file mode 100644
index 00000000000..b22ba678c3c
--- /dev/null
+++ b/chromium/ui/base/nine_image_painter_factory.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/nine_image_painter_factory.h"
+
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/nine_image_painter.h"
+
+namespace ui {
+
+namespace {
+
+std::vector<gfx::ImageSkia> ImageIdsToImages(const int image_ids[]) {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ std::vector<gfx::ImageSkia> images(9);
+ for (size_t i = 0; i < 9; ++i) {
+ if (image_ids[i] != 0)
+ images[i] = *rb.GetImageSkiaNamed(image_ids[i]);
+ }
+ return images;
+}
+
+} // namespace
+
+scoped_ptr<gfx::NineImagePainter> CreateNineImagePainter(
+ const int image_ids[]) {
+ return scoped_ptr<gfx::NineImagePainter>(
+ new gfx::NineImagePainter(ImageIdsToImages(image_ids)));
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/nine_image_painter_factory.h b/chromium/ui/base/nine_image_painter_factory.h
new file mode 100644
index 00000000000..8a622839f4f
--- /dev/null
+++ b/chromium/ui/base/nine_image_painter_factory.h
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_NINE_IMAGE_PAINTER_FACTORY_H_
+#define UI_BASE_NINE_IMAGE_PAINTER_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ui_base_export.h"
+
+// A macro to define arrays of IDR constants used with CreateImageGridPainter.
+#define IMAGE_GRID(x) { x ## _TOP_LEFT, x ## _TOP, x ## _TOP_RIGHT, \
+ x ## _LEFT, x ## _CENTER, x ## _RIGHT, \
+ x ## _BOTTOM_LEFT, x ## _BOTTOM, x ## _BOTTOM_RIGHT, }
+
+// Defines a empty image for used in macro for creating image grid for a ring of
+// eight images.
+#define EMPTY_IMAGE 0
+
+// A macro to define arrays of IDR constants used with CreateImageGridPainter
+// where only a ring of eight images is provided and center image is empty.
+#define IMAGE_GRID_NO_CENTER(x) { x ## _TOP_LEFT, x ## _TOP, x ## _TOP_RIGHT, \
+ x ## _LEFT, EMPTY_IMAGE, x ## _RIGHT, \
+ x ## _BOTTOM_LEFT, x ## _BOTTOM, x ## _BOTTOM_RIGHT, }
+
+
+namespace gfx {
+class NineImagePainter;
+}
+
+namespace ui {
+
+// Creates a NineImagePainter from an array of image ids. It's expected the
+// array came from the IMAGE_GRID macro.
+UI_BASE_EXPORT scoped_ptr<gfx::NineImagePainter> CreateNineImagePainter(
+ const int image_ids[]);
+
+} // namespace ui
+
+#endif // UI_BASE_NINE_IMAGE_PAINTER_FACTORY_H_
diff --git a/chromium/ui/base/resource/data_pack.cc b/chromium/ui/base/resource/data_pack.cc
index 8f8f1822444..8e9ee30eef6 100644
--- a/chromium/ui/base/resource/data_pack.cc
+++ b/chromium/ui/base/resource/data_pack.cc
@@ -84,9 +84,9 @@ bool DataPack::LoadFromPath(const base::FilePath& path) {
return LoadImpl();
}
-bool DataPack::LoadFromFile(base::PlatformFile file) {
+bool DataPack::LoadFromFile(base::File file) {
mmap_.reset(new base::MemoryMappedFile);
- if (!mmap_->Initialize(file)) {
+ if (!mmap_->Initialize(file.Pass())) {
DLOG(ERROR) << "Failed to mmap datapack";
UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED_FROM_FILE,
LOAD_ERRORS_COUNT);
@@ -134,8 +134,9 @@ bool DataPack::LoadImpl() {
}
// Sanity check the file.
- // 1) Check we have enough entries.
- if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) >
+ // 1) Check we have enough entries. There's an extra entry after the last item
+ // which gives the length of the last item.
+ if (kHeaderLength + (resource_count_ + 1) * sizeof(DataPackEntry) >
mmap_->length()) {
LOG(ERROR) << "Data pack file corruption: too short for number of "
"entries specified.";
@@ -188,9 +189,21 @@ bool DataPack::GetStringPiece(uint16 resource_id,
}
const DataPackEntry* next_entry = target + 1;
- size_t length = next_entry->file_offset - target->file_offset;
+ // If the next entry points beyond the end of the file this data pack's entry
+ // table is corrupt. Log an error and return false. See
+ // http://crbug.com/371301.
+ if (next_entry->file_offset > mmap_->length()) {
+ size_t entry_index = target -
+ reinterpret_cast<const DataPackEntry*>(mmap_->data() + kHeaderLength);
+ LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end "
+ << "of file. This should have been caught when loading. Was the "
+ << "file modified?";
+ return false;
+ }
- data->set(mmap_->data() + target->file_offset, length);
+ size_t length = next_entry->file_offset - target->file_offset;
+ data->set(reinterpret_cast<const char*>(mmap_->data() + target->file_offset),
+ length);
return true;
}
@@ -200,8 +213,7 @@ base::RefCountedStaticMemory* DataPack::GetStaticMemory(
if (!GetStringPiece(resource_id, &piece))
return NULL;
- return new base::RefCountedStaticMemory(
- reinterpret_cast<const unsigned char*>(piece.data()), piece.length());
+ return new base::RefCountedStaticMemory(piece.data(), piece.length());
}
ResourceHandle::TextEncodingType DataPack::GetTextEncodingType() const {
diff --git a/chromium/ui/base/resource/data_pack.h b/chromium/ui/base/resource/data_pack.h
index 2ea938f9d1b..4d9d4bbdc2f 100644
--- a/chromium/ui/base/resource/data_pack.h
+++ b/chromium/ui/base/resource/data_pack.h
@@ -12,12 +12,12 @@
#include <map>
#include "base/basictypes.h"
+#include "base/files/file.h"
#include "base/memory/scoped_ptr.h"
-#include "base/platform_file.h"
#include "base/strings/string_piece.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_handle.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace base {
class FilePath;
@@ -27,7 +27,7 @@ class RefCountedStaticMemory;
namespace ui {
-class UI_EXPORT DataPack : public ResourceHandle {
+class UI_BASE_EXPORT DataPack : public ResourceHandle {
public:
DataPack(ui::ScaleFactor scale_factor);
virtual ~DataPack();
@@ -36,7 +36,7 @@ class UI_EXPORT DataPack : public ResourceHandle {
bool LoadFromPath(const base::FilePath& path);
// Loads a pack file from |file|, returning false on error.
- bool LoadFromFile(base::PlatformFile file);
+ bool LoadFromFile(base::File file);
// Writes a pack file containing |resources| to |path|. If there are any
// text resources to be written, their encoding must already agree to the
diff --git a/chromium/ui/base/resource/data_pack_literal.cc b/chromium/ui/base/resource/data_pack_literal.cc
index 05e610b8bed..0b3855f3a99 100644
--- a/chromium/ui/base/resource/data_pack_literal.cc
+++ b/chromium/ui/base/resource/data_pack_literal.cc
@@ -21,6 +21,22 @@ extern const char kSamplePakContents[] = {
extern const size_t kSamplePakSize = sizeof(kSamplePakContents);
+extern const char kSampleCorruptPakContents[] = {
+ 0x04, 0x00, 0x00, 0x00, // header(version
+ 0x04, 0x00, 0x00, 0x00, // no. entries
+ 0x01, // encoding)
+ 0x01, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 1
+ 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 4
+ 0x06, 0x00, 0x33, 0x00, 0x00, 0x00, // index entry 6
+ 0x0a, 0x00, 0x3f, 0x00, 0x00, 0x00, // index entry 10
+ 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // extra entry for the size of last,
+ // extends past END OF FILE.
+ 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
+ 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'
+};
+
+extern const size_t kSampleCorruptPakSize = sizeof(kSampleCorruptPakContents);
+
extern const char kSamplePakContents2x[] = {
0x04, 0x00, 0x00, 0x00, // header(version
0x01, 0x00, 0x00, 0x00, // no. entries
diff --git a/chromium/ui/base/resource/data_pack_unittest.cc b/chromium/ui/base/resource/data_pack_unittest.cc
index 0ac7819de72..9583df1b12e 100644
--- a/chromium/ui/base/resource/data_pack_unittest.cc
+++ b/chromium/ui/base/resource/data_pack_unittest.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "base/file_util.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/data_pack.h"
+#include "ui/base/ui_base_paths.h"
namespace ui {
@@ -19,7 +21,9 @@ class DataPackTest
};
extern const char kSamplePakContents[];
+extern const char kSampleCorruptPakContents[];
extern const size_t kSamplePakSize;
+extern const size_t kSampleCorruptPakSize;
TEST(DataPackTest, LoadFromPath) {
base::ScopedTempDir dir;
@@ -27,7 +31,7 @@ TEST(DataPackTest, LoadFromPath) {
base::FilePath data_path = dir.path().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak file.
- ASSERT_EQ(file_util::WriteFile(data_path, kSamplePakContents, kSamplePakSize),
+ ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize),
static_cast<int>(kSamplePakSize));
// Load the file through the data pack API.
@@ -59,18 +63,15 @@ TEST(DataPackTest, LoadFromFile) {
base::FilePath data_path = dir.path().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak file.
- ASSERT_EQ(file_util::WriteFile(data_path, kSamplePakContents, kSamplePakSize),
+ ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize),
static_cast<int>(kSamplePakSize));
- bool created = false;
- base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
- base::PlatformFile file = base::CreatePlatformFile(
- data_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
- &created, &error_code);
+ base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(file.IsValid());
// Load the file through the data pack API.
DataPack pack(SCALE_FACTOR_100P);
- ASSERT_TRUE(pack.LoadFromFile(file));
+ ASSERT_TRUE(pack.LoadFromFile(file.Pass()));
base::StringPiece data;
ASSERT_TRUE(pack.HasResource(4));
@@ -89,8 +90,6 @@ TEST(DataPackTest, LoadFromFile) {
// Try looking up an invalid key.
ASSERT_FALSE(pack.HasResource(140));
ASSERT_FALSE(pack.GetStringPiece(140, &data));
-
- base::ClosePlatformFile(file);
}
INSTANTIATE_TEST_CASE_P(WriteBINARY, DataPackTest, ::testing::Values(
@@ -102,9 +101,8 @@ INSTANTIATE_TEST_CASE_P(WriteUTF16, DataPackTest, ::testing::Values(
TEST(DataPackTest, LoadFileWithTruncatedHeader) {
base::FilePath data_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &data_path);
- data_path = data_path.Append(FILE_PATH_LITERAL(
- "ui/base/test/data/data_pack_unittest/truncated-header.pak"));
+ ASSERT_TRUE(PathService::Get(UI_DIR_TEST_DATA, &data_path));
+ data_path = data_path.AppendASCII("data_pack_unittest/truncated-header.pak");
DataPack pack(SCALE_FACTOR_100P);
ASSERT_FALSE(pack.LoadFromPath(data_path));
@@ -147,4 +145,35 @@ TEST_P(DataPackTest, Write) {
EXPECT_EQ(fifteen, data);
}
+#if defined(OS_POSIX)
+TEST(DataPackTest, ModifiedWhileUsed) {
+ base::ScopedTempDir dir;
+ ASSERT_TRUE(dir.CreateUniqueTempDir());
+ base::FilePath data_path = dir.path().Append(FILE_PATH_LITERAL("sample.pak"));
+
+ // Dump contents into the pak file.
+ ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize),
+ static_cast<int>(kSamplePakSize));
+
+ base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(file.IsValid());
+
+ // Load the file through the data pack API.
+ DataPack pack(SCALE_FACTOR_100P);
+ ASSERT_TRUE(pack.LoadFromFile(file.Pass()));
+
+ base::StringPiece data;
+ ASSERT_TRUE(pack.HasResource(10));
+ ASSERT_TRUE(pack.GetStringPiece(10, &data));
+
+ ASSERT_EQ(base::WriteFile(data_path, kSampleCorruptPakContents,
+ kSampleCorruptPakSize),
+ static_cast<int>(kSampleCorruptPakSize));
+
+ // Reading asset #10 should now fail as it extends past the end of the file.
+ ASSERT_TRUE(pack.HasResource(10));
+ ASSERT_FALSE(pack.GetStringPiece(10, &data));
+}
+#endif
+
} // namespace ui
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index b5f8f6138d1..f5a592d0221 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -4,10 +4,13 @@
#include "ui/base/resource/resource_bundle.h"
+#include <limits>
#include <vector>
+#include "base/big_endian.h"
#include "base/command_line.h"
#include "base/file_util.h"
+#include "base/files/file.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram.h"
@@ -18,7 +21,6 @@
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "grit/app_locale_settings.h"
-#include "net/base/big_endian.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
@@ -33,7 +35,6 @@
#include "ui/gfx/safe_integer_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/skbitmap_operations.h"
#if defined(OS_CHROMEOS)
#include "ui/base/l10n/l10n_util.h"
@@ -68,20 +69,40 @@ ResourceBundle* g_shared_instance_ = NULL;
void InitDefaultFontList() {
#if defined(OS_CHROMEOS)
- gfx::FontList::SetDefaultFontDescription(
- l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS));
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ std::string font_family = base::UTF16ToUTF8(
+ rb.GetLocalizedString(IDS_UI_FONT_FAMILY_CROS));
+ gfx::FontList::SetDefaultFontDescription(font_family);
// TODO(yukishiino): Remove SetDefaultFontDescription() once the migration to
// the font list is done. We will no longer need SetDefaultFontDescription()
// after every client gets started using a FontList instead of a Font.
- gfx::PlatformFontPango::SetDefaultFontDescription(
- l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS));
+ gfx::PlatformFontPango::SetDefaultFontDescription(font_family);
#else
// Use a single default font as the default font list.
gfx::FontList::SetDefaultFontDescription(std::string());
#endif
}
+#if defined(OS_ANDROID)
+// Returns the scale factor closest to |scale| from the full list of factors.
+// Note that it does NOT rely on the list of supported scale factors.
+// Finding the closest match is inefficient and shouldn't be done frequently.
+ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
+ float smallest_diff = std::numeric_limits<float>::max();
+ ScaleFactor closest_match = SCALE_FACTOR_100P;
+ for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
+ const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
+ float diff = std::abs(GetScaleForScaleFactor(scale_factor) - scale);
+ if (diff < smallest_diff) {
+ closest_match = scale_factor;
+ smallest_diff = diff;
+ }
+ }
+ return closest_match;
+}
+#endif // OS_ANDROID
+
} // namespace
// An ImageSkiaSource that loads bitmaps for the requested scale factor from
@@ -104,11 +125,15 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
ScaleFactor scale_factor = GetSupportedScaleFactor(scale);
bool found = rb_->LoadBitmap(resource_id_, &scale_factor,
&image, &fell_back_to_1x);
- // Force to a supported scale.
- scale = ui::GetImageScale(scale_factor);
if (!found)
return gfx::ImageSkiaRep();
+ // If the resource is in the package with SCALE_FACTOR_NONE, it
+ // can be used in any scale factor. The image is maked as "unscaled"
+ // so that the ImageSkia do not automatically scale.
+ if (scale_factor == ui::SCALE_FACTOR_NONE)
+ return gfx::ImageSkiaRep(image, 0.0f);
+
if (fell_back_to_1x) {
// GRIT fell back to the 100% image, so rescale it to the correct size.
image = skia::ImageOperations::Resize(
@@ -116,21 +141,9 @@ class ResourceBundle::ResourceBundleImageSource : public gfx::ImageSkiaSource {
skia::ImageOperations::RESIZE_LANCZOS3,
gfx::ToCeiledInt(image.width() * scale),
gfx::ToCeiledInt(image.height() * scale));
- // If --highlight-missing-scaled-resources is specified, log the resource
- // id and blend the created resource with red.
- if (ShouldHighlightMissingScaledResources()) {
- LOG(ERROR) << "Missing " << scale << "x scaled resource. id="
- << resource_id_;
-
- SkBitmap mask;
- mask.setConfig(SkBitmap::kARGB_8888_Config,
- image.width(), image.height());
- mask.allocPixels();
- mask.eraseColor(SK_ColorRED);
- image = SkBitmapOperations::CreateBlendedBitmap(image, mask, 0.2);
- }
+ } else {
+ scale = GetScaleForScaleFactor(scale_factor);
}
-
return gfx::ImageSkiaRep(image, scale);
}
@@ -162,14 +175,14 @@ std::string ResourceBundle::InitSharedInstanceLocaleOnly(
// static
void ResourceBundle::InitSharedInstanceWithPakFile(
- base::PlatformFile pak_file, bool should_load_common_resources) {
+ base::File pak_file, bool should_load_common_resources) {
InitSharedInstance(NULL);
if (should_load_common_resources)
g_shared_instance_->LoadCommonResources();
scoped_ptr<DataPack> data_pack(
new DataPack(SCALE_FACTOR_100P));
- if (!data_pack->LoadFromFile(pak_file)) {
+ if (!data_pack->LoadFromFile(pak_file.Pass())) {
NOTREACHED() << "failed to load pak file";
return;
}
@@ -219,11 +232,11 @@ void ResourceBundle::AddOptionalDataPackFromPath(const base::FilePath& path,
AddDataPackFromPathInternal(path, scale_factor, true);
}
-void ResourceBundle::AddDataPackFromFile(base::PlatformFile file,
+void ResourceBundle::AddDataPackFromFile(base::File file,
ScaleFactor scale_factor) {
scoped_ptr<DataPack> data_pack(
new DataPack(scale_factor));
- if (data_pack->LoadFromFile(file)) {
+ if (data_pack->LoadFromFile(file.Pass())) {
AddDataPack(data_pack.release());
} else {
LOG(ERROR) << "Failed to load data pack from file."
@@ -265,15 +278,8 @@ std::string ResourceBundle::LoadLocaleResources(
DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded";
std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
base::FilePath locale_file_path = GetOverriddenPakPath();
- if (locale_file_path.empty()) {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kLocalePak)) {
- locale_file_path =
- command_line->GetSwitchValuePath(switches::kLocalePak);
- } else {
- locale_file_path = GetLocaleFilePath(app_locale, true);
- }
- }
+ if (locale_file_path.empty())
+ locale_file_path = GetLocaleFilePath(app_locale, true);
if (locale_file_path.empty()) {
// It's possible that there is no locale.pak.
@@ -350,20 +356,19 @@ gfx::Image& ResourceBundle::GetImageNamed(int resource_id) {
DCHECK(!data_packs_.empty()) <<
"Missing call to SetResourcesDataDLL?";
-#if defined(OS_CHROMEOS)
- ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+ ui::ScaleFactor scale_factor_to_load = GetMaxScaleFactor();
#else
- ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
+ ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
#endif
- float scale = GetImageScale(scale_factor_to_load);
// TODO(oshima): Consider reading the image size from png IHDR chunk and
// skip decoding here and remove #ifdef below.
// ResourceBundle::GetSharedInstance() is destroyed after the
// BrowserMainLoop has finished running. |image_skia| is guaranteed to be
// destroyed before the resource bundle is destroyed.
gfx::ImageSkia image_skia(new ResourceBundleImageSource(this, resource_id),
- scale);
+ GetScaleForScaleFactor(scale_factor_to_load));
if (image_skia.isNull()) {
LOG(WARNING) << "Unable to load image with id " << resource_id;
NOTREACHED(); // Want to assert in debug mode.
@@ -405,8 +410,7 @@ base::RefCountedStaticMemory* ResourceBundle::LoadDataResourceBytesForScale(
base::StringPiece data =
GetRawDataResourceForScale(resource_id, scale_factor);
if (!data.empty()) {
- bytes = new base::RefCountedStaticMemory(
- reinterpret_cast<const unsigned char*>(data.data()), data.length());
+ bytes = new base::RefCountedStaticMemory(data.data(), data.length());
}
}
@@ -434,6 +438,7 @@ base::StringPiece ResourceBundle::GetRawDataResourceForScale(
}
for (size_t i = 0; i < data_packs_.size(); i++) {
if ((data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_100P ||
+ data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_200P ||
data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE) &&
data_packs_[i]->GetStringPiece(resource_id, &data))
return data;
@@ -481,7 +486,7 @@ base::string16 ResourceBundle::GetLocalizedString(int message_id) {
msg = base::string16(reinterpret_cast<const base::char16*>(data.data()),
data.length() / 2);
} else if (encoding == ResourceHandle::UTF8) {
- msg = UTF8ToUTF16(data);
+ msg = base::UTF8ToUTF16(data);
}
return msg;
}
@@ -522,13 +527,21 @@ void ResourceBundle::ReloadFonts() {
}
ScaleFactor ResourceBundle::GetMaxScaleFactor() const {
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
return max_scale_factor_;
#else
return GetSupportedScaleFactors().back();
#endif
}
+bool ResourceBundle::IsScaleFactorSupported(ScaleFactor scale_factor) {
+ const std::vector<ScaleFactor>& supported_scale_factors =
+ ui::GetSupportedScaleFactors();
+ return std::find(supported_scale_factors.begin(),
+ supported_scale_factors.end(),
+ scale_factor) != supported_scale_factors.end();
+}
+
ResourceBundle::ResourceBundle(Delegate* delegate)
: delegate_(delegate),
images_and_fonts_lock_(new base::Lock),
@@ -546,8 +559,9 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
g_shared_instance_ = new ResourceBundle(delegate);
static std::vector<ScaleFactor> supported_scale_factors;
-#if !defined(OS_IOS)
+#if !defined(OS_IOS) && !defined(OS_WIN)
// On platforms other than iOS, 100P is always a supported scale factor.
+ // For Windows we have a separate case in this function.
supported_scale_factors.push_back(SCALE_FACTOR_100P);
#endif
#if defined(OS_ANDROID)
@@ -571,12 +585,30 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
#elif defined(OS_CHROMEOS)
// TODO(oshima): Include 200P only if the device support 200P
supported_scale_factors.push_back(SCALE_FACTOR_200P);
+#elif defined(OS_LINUX) && defined(ENABLE_HIDPI)
+ supported_scale_factors.push_back(SCALE_FACTOR_200P);
+#elif defined(OS_WIN)
+ bool default_to_100P = true;
+ if (gfx::IsHighDPIEnabled()) {
+ // On Windows if the dpi scale is greater than 1.25 on high dpi machines
+ // downscaling from 200 percent looks better than scaling up from 100
+ // percent.
+ if (gfx::GetDPIScale() > 1.25) {
+ supported_scale_factors.push_back(SCALE_FACTOR_200P);
+ default_to_100P = false;
+ }
+ }
+ if (default_to_100P)
+ supported_scale_factors.push_back(SCALE_FACTOR_100P);
#endif
ui::SetSupportedScaleFactors(supported_scale_factors);
#if defined(OS_WIN)
// Must be called _after_ supported scale factors are set since it
// uses them.
- ui::win::InitDeviceScaleFactor();
+ // Don't initialize the device scale factor if it has already been
+ // initialized.
+ if (!gfx::win::IsDeviceScaleFactorSet())
+ ui::win::InitDeviceScaleFactor();
#endif
}
@@ -612,8 +644,8 @@ void ResourceBundle::AddDataPackFromPathInternal(const base::FilePath& path,
void ResourceBundle::AddDataPack(DataPack* data_pack) {
data_packs_.push_back(data_pack);
- if (GetImageScale(data_pack->GetScaleFactor()) >
- GetImageScale(max_scale_factor_))
+ if (GetScaleForScaleFactor(data_pack->GetScaleFactor()) >
+ GetScaleForScaleFactor(max_scale_factor_))
max_scale_factor_ = data_pack->GetScaleFactor();
}
@@ -636,43 +668,43 @@ void ResourceBundle::LoadFontsIfNecessary() {
if (!bold_font_list_.get()) {
bold_font_list_.reset(new gfx::FontList());
- *bold_font_list_ = base_font_list_->DeriveFontList(
+ *bold_font_list_ = base_font_list_->DeriveWithStyle(
base_font_list_->GetFontStyle() | gfx::Font::BOLD);
}
if (!small_font_list_.get()) {
small_font_list_.reset(new gfx::FontList());
- *small_font_list_ = base_font_list_->DeriveFontListWithSize(
- base_font_list_->GetFontSize() + kSmallFontSizeDelta);
+ *small_font_list_ =
+ base_font_list_->DeriveWithSizeDelta(kSmallFontSizeDelta);
}
if (!small_bold_font_list_.get()) {
small_bold_font_list_.reset(new gfx::FontList());
- *small_bold_font_list_ = small_font_list_->DeriveFontList(
+ *small_bold_font_list_ = small_font_list_->DeriveWithStyle(
small_font_list_->GetFontStyle() | gfx::Font::BOLD);
}
if (!medium_font_list_.get()) {
medium_font_list_.reset(new gfx::FontList());
- *medium_font_list_ = base_font_list_->DeriveFontListWithSize(
- base_font_list_->GetFontSize() + kMediumFontSizeDelta);
+ *medium_font_list_ =
+ base_font_list_->DeriveWithSizeDelta(kMediumFontSizeDelta);
}
if (!medium_bold_font_list_.get()) {
medium_bold_font_list_.reset(new gfx::FontList());
- *medium_bold_font_list_ = medium_font_list_->DeriveFontList(
+ *medium_bold_font_list_ = medium_font_list_->DeriveWithStyle(
medium_font_list_->GetFontStyle() | gfx::Font::BOLD);
}
if (!large_font_list_.get()) {
large_font_list_.reset(new gfx::FontList());
- *large_font_list_ = base_font_list_->DeriveFontListWithSize(
- base_font_list_->GetFontSize() + kLargeFontSizeDelta);
+ *large_font_list_ =
+ base_font_list_->DeriveWithSizeDelta(kLargeFontSizeDelta);
}
if (!large_bold_font_list_.get()) {
large_bold_font_list_.reset(new gfx::FontList());
- *large_bold_font_list_ = large_font_list_->DeriveFontList(
+ *large_bold_font_list_ = large_font_list_->DeriveWithStyle(
large_font_list_->GetFontStyle() | gfx::Font::BOLD);
}
}
@@ -722,13 +754,10 @@ bool ResourceBundle::LoadBitmap(int resource_id,
bool* fell_back_to_1x) const {
DCHECK(fell_back_to_1x);
for (size_t i = 0; i < data_packs_.size(); ++i) {
- // If the resource is in the package with SCALE_FACTOR_NONE, it
- // can be used in any scale factor, but set 100P in ImageSkia so
- // that it will be scaled property.
if (data_packs_[i]->GetScaleFactor() == ui::SCALE_FACTOR_NONE &&
LoadBitmap(*data_packs_[i], resource_id, bitmap, fell_back_to_1x)) {
- *scale_factor = ui::SCALE_FACTOR_100P;
DCHECK(!*fell_back_to_1x);
+ *scale_factor = ui::SCALE_FACTOR_NONE;
return true;
}
if (data_packs_[i]->GetScaleFactor() == *scale_factor &&
@@ -754,14 +783,8 @@ gfx::Image& ResourceBundle::GetEmptyImage() {
}
// static
-bool ResourceBundle::ShouldHighlightMissingScaledResources() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kHighlightMissingScaledResources);
-}
-
-// static
bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
- size_t size) {
+ size_t size) {
if (size < arraysize(kPngMagic) ||
memcmp(buf, kPngMagic, arraysize(kPngMagic)) != 0) {
// Data invalid or a JPEG.
@@ -775,7 +798,7 @@ bool ResourceBundle::PNGContainsFallbackMarker(const unsigned char* buf,
if (size - pos < kPngChunkMetadataSize)
break;
uint32 length = 0;
- net::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
+ base::ReadBigEndian(reinterpret_cast<const char*>(buf + pos), &length);
if (size - pos - kPngChunkMetadataSize < length)
break;
if (length == 0 && memcmp(buf + pos + sizeof(uint32), kPngScaleChunkType,
diff --git a/chromium/ui/base/resource/resource_bundle.h b/chromium/ui/base/resource/resource_bundle.h
index 272c5b3341b..060ea6c51f5 100644
--- a/chromium/ui/base/resource/resource_bundle.h
+++ b/chromium/ui/base/resource/resource_bundle.h
@@ -5,8 +5,6 @@
#ifndef UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_
#define UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_
-#include "build/build_config.h"
-
#include <map>
#include <string>
@@ -15,11 +13,11 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
-#include "base/platform_file.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#include "ui/base/layout.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/native_widget_types.h"
@@ -27,6 +25,7 @@
class SkBitmap;
namespace base {
+class File;
class Lock;
class RefCountedStaticMemory;
}
@@ -38,7 +37,7 @@ class ResourceHandle;
// ResourceBundle is a central facility to load images and other resources,
// such as theme graphics. Every resource is loaded only once.
-class UI_EXPORT ResourceBundle {
+class UI_BASE_EXPORT ResourceBundle {
public:
// An enumeration of the various font styles used throughout Chrome.
// The following holds true for the font sizes:
@@ -135,8 +134,8 @@ class UI_EXPORT ResourceBundle {
// controls whether or not ResourceBundle::LoadCommonResources is called.
// This allows the use of this function in a sandbox without local file
// access (as on Android).
- static void InitSharedInstanceWithPakFile(
- base::PlatformFile file, bool should_load_common_resources);
+ static void InitSharedInstanceWithPakFile(base::File file,
+ bool should_load_common_resources);
// Initialize the ResourceBundle using given data pack path for testing.
static void InitSharedInstanceWithPakPath(const base::FilePath& path);
@@ -164,7 +163,7 @@ class UI_EXPORT ResourceBundle {
ScaleFactor scale_factor);
// Same as above but using an already open file.
- void AddDataPackFromFile(base::PlatformFile file, ScaleFactor scale_factor);
+ void AddDataPackFromFile(base::File file, ScaleFactor scale_factor);
// Same as AddDataPackFromPath but does not log an error if the pack fails to
// load.
@@ -257,6 +256,10 @@ class UI_EXPORT ResourceBundle {
// Returns SCALE_FACTOR_100P if no resource is loaded.
ScaleFactor GetMaxScaleFactor() const;
+ protected:
+ // Returns true if |scale_factor| is supported by this platform.
+ static bool IsScaleFactorSupported(ScaleFactor scale_factor);
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceBundleTest, DelegateGetPathForLocalePack);
FRIEND_TEST_ALL_PREFIXES(ResourceBundleTest, DelegateGetImageNamed);
diff --git a/chromium/ui/base/resource/resource_bundle_auralinux.cc b/chromium/ui/base/resource/resource_bundle_auralinux.cc
index d5357175a7b..128fd6762d2 100644
--- a/chromium/ui/base/resource/resource_bundle_auralinux.cc
+++ b/chromium/ui/base/resource/resource_bundle_auralinux.cc
@@ -36,7 +36,7 @@ void ResourceBundle::LoadCommonResources() {
AddDataPackFromPath(GetResourcesPakFilePath(
"chrome_100_percent.pak"), SCALE_FACTOR_100P);
- if (ui::IsScaleFactorSupported(SCALE_FACTOR_200P)) {
+ if (IsScaleFactorSupported(SCALE_FACTOR_200P)) {
AddOptionalDataPackFromPath(GetResourcesPakFilePath(
"chrome_200_percent.pak"), SCALE_FACTOR_200P);
}
diff --git a/chromium/ui/base/resource/resource_bundle_gtk.cc b/chromium/ui/base/resource/resource_bundle_gtk.cc
deleted file mode 100644
index 2578dc29d37..00000000000
--- a/chromium/ui/base/resource/resource_bundle_gtk.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/resource/resource_bundle.h"
-
-#include "base/i18n/rtl.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/path_service.h"
-#include "base/synchronization/lock.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/layout.h"
-#include "ui/base/resource/resource_handle.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/scoped_gobject.h"
-
-#include <gtk/gtk.h>
-
-namespace ui {
-
-namespace {
-
-// Convert the raw image data into a GdkPixbuf. The GdkPixbuf that is returned
-// has a ref count of 1 so the caller must call g_object_unref to free the
-// memory.
-GdkPixbuf* LoadPixbuf(base::RefCountedStaticMemory* data, bool rtl_enabled) {
- ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
- bool ok = data && gdk_pixbuf_loader_write(loader.get(),
- reinterpret_cast<const guint8*>(data->front()), data->size(), NULL);
- if (!ok)
- return NULL;
- // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
- // loader. We must do this before calling gdk_pixbuf_loader_get_pixbuf.
- ok = gdk_pixbuf_loader_close(loader.get(), NULL);
- if (!ok)
- return NULL;
- GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
- if (!pixbuf)
- return NULL;
-
- if (base::i18n::IsRTL() && rtl_enabled) {
- // |pixbuf| will get unreffed and destroyed (see below). The returned value
- // has ref count 1.
- return gdk_pixbuf_flip(pixbuf, TRUE);
- } else {
- // The pixbuf is owned by the loader, so add a ref so when we delete the
- // loader (when the ScopedGObject goes out of scope), the pixbuf still
- // exists.
- g_object_ref(pixbuf);
- return pixbuf;
- }
-}
-
-base::FilePath GetResourcesPakFilePath(const std::string& pak_name) {
- base::FilePath path;
- if (PathService::Get(base::DIR_MODULE, &path))
- return path.AppendASCII(pak_name.c_str());
-
- // Return just the name of the pack file.
- return base::FilePath(pak_name.c_str());
-}
-
-} // namespace
-
-void ResourceBundle::LoadCommonResources() {
- AddDataPackFromPath(GetResourcesPakFilePath(
- "chrome_100_percent.pak"),
- SCALE_FACTOR_100P);
-}
-
-gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
- // Use the negative |resource_id| for the key for BIDI-aware images.
- int key = rtl == RTL_ENABLED ? -resource_id : resource_id;
-
- // Check to see if the image is already in the cache.
- {
- base::AutoLock lock_scope(*images_and_fonts_lock_);
- if (images_.count(key))
- return images_[key];
- }
-
- gfx::Image image;
- if (delegate_)
- image = delegate_->GetNativeImageNamed(resource_id, rtl);
-
- if (image.IsEmpty()) {
- scoped_refptr<base::RefCountedStaticMemory> data(
- LoadDataResourceBytesForScale(resource_id, SCALE_FACTOR_100P));
- GdkPixbuf* pixbuf = LoadPixbuf(data.get(), rtl == RTL_ENABLED);
-
- if (!pixbuf) {
- LOG(WARNING) << "Unable to load pixbuf with id " << resource_id;
- NOTREACHED(); // Want to assert in debug mode.
- return GetEmptyImage();
- }
-
- image = gfx::Image(pixbuf); // Takes ownership.
- }
-
- base::AutoLock lock_scope(*images_and_fonts_lock_);
-
- // Another thread raced the load and has already cached the image.
- if (images_.count(key))
- return images_[key];
-
- images_[key] = image;
- return images_[key];
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/resource/resource_bundle_ios.mm b/chromium/ui/base/resource/resource_bundle_ios.mm
index d947c2f55f1..4f5d9bc34fd 100644
--- a/chromium/ui/base/resource/resource_bundle_ios.mm
+++ b/chromium/ui/base/resource/resource_bundle_ios.mm
@@ -125,7 +125,7 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
bool is_fallback = PNGContainsFallbackMarker(data->front(), data->size());
// Create the image from the data.
- CGFloat target_scale = ui::GetImageScale(scale_factor);
+ CGFloat target_scale = ui::GetScaleForScaleFactor(scale_factor);
CGFloat source_scale = is_fallback ? 1.0 : target_scale;
base::scoped_nsobject<UIImage> ui_image(
[[UIImage alloc] initWithData:ns_data scale:source_scale]);
@@ -151,14 +151,6 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawImage(context, target_rect, [ui_image CGImage]);
- if (ShouldHighlightMissingScaledResources()) {
- CGContextSetFillColorSpace(context, color_space);
- CGFloat components[4] = { 1.0, 0.0, 0.0, 0.3 }; // Translucent red.
- CGContextSetFillColor(context, components);
- CGContextSetBlendMode(context, kCGBlendModeNormal);
- CGContextFillRect(context, target_rect);
- }
-
base::ScopedCFTypeRef<CGImageRef> cg_image(
CGBitmapContextCreateImage(context));
ui_image.reset([[UIImage alloc] initWithCGImage:cg_image
diff --git a/chromium/ui/base/resource/resource_bundle_unittest.cc b/chromium/ui/base/resource/resource_bundle_unittest.cc
index f6ab49dfbb9..4ba3deacba6 100644
--- a/chromium/ui/base/resource/resource_bundle_unittest.cc
+++ b/chromium/ui/base/resource/resource_bundle_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "base/base_paths.h"
+#include "base/big_endian.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
@@ -12,7 +13,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/big_endian.h"
+#include "grit/ui_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -20,8 +21,9 @@
#include "ui/base/resource/data_pack.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
-
-#include "grit/ui_resources.h"
+#if defined(OS_WIN)
+#include "ui/gfx/win/dpi.h"
+#endif
using ::testing::_;
using ::testing::Between;
@@ -78,8 +80,9 @@ class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate {
*value = GetRawDataResourceMock(resource_id, scale_factor);
return true;
}
- MOCK_METHOD1(GetLocalizedStringMock, string16(int message_id));
- virtual bool GetLocalizedString(int message_id, string16* value) OVERRIDE {
+ MOCK_METHOD1(GetLocalizedStringMock, base::string16(int message_id));
+ virtual bool GetLocalizedString(int message_id,
+ base::string16* value) OVERRIDE {
*value = GetLocalizedStringMock(message_id);
return true;
}
@@ -105,8 +108,8 @@ void AddCustomChunk(const base::StringPiece& custom_chunk,
for (size_t i = 0; i < sizeof(uint32); ++i)
ihdr_length_data[i] = *(ihdr_start + i);
uint32 ihdr_chunk_length = 0;
- net::ReadBigEndian(reinterpret_cast<char*>(ihdr_length_data),
- &ihdr_chunk_length);
+ base::ReadBigEndian(reinterpret_cast<char*>(ihdr_length_data),
+ &ihdr_chunk_length);
EXPECT_TRUE(std::equal(
ihdr_start + sizeof(uint32),
ihdr_start + sizeof(uint32) + sizeof(kPngIHDRChunkType),
@@ -297,14 +300,14 @@ TEST_F(ResourceBundleTest, DelegateGetLocalizedString) {
MockResourceBundleDelegate delegate;
ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
- string16 data = ASCIIToUTF16("My test data");
+ base::string16 data = base::ASCIIToUTF16("My test data");
int resource_id = 5;
EXPECT_CALL(delegate, GetLocalizedStringMock(resource_id))
.Times(1)
.WillOnce(Return(data));
- string16 result = resource_bundle->GetLocalizedString(resource_id);
+ base::string16 result = resource_bundle->GetLocalizedString(resource_id);
EXPECT_EQ(data, result);
}
@@ -359,7 +362,7 @@ class ResourceBundleImageTest : public ResourceBundleTest {
// Write an empty data pak for locale data.
const base::FilePath& locale_path = dir_path().Append(
FILE_PATH_LITERAL("locale.pak"));
- EXPECT_EQ(file_util::WriteFile(locale_path, kEmptyPakContents,
+ EXPECT_EQ(base::WriteFile(locale_path, kEmptyPakContents,
kEmptyPakSize),
static_cast<int>(kEmptyPakSize));
@@ -386,7 +389,7 @@ TEST_F(ResourceBundleImageTest, LoadDataResourceBytes) {
base::FilePath data_path = dir_path().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak files.
- ASSERT_EQ(file_util::WriteFile(data_path, kEmptyPakContents,
+ ASSERT_EQ(base::WriteFile(data_path, kEmptyPakContents,
kEmptyPakSize), static_cast<int>(kEmptyPakSize));
// Create a resource bundle from the file.
@@ -411,9 +414,9 @@ TEST_F(ResourceBundleImageTest, GetRawDataResource) {
dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak"));
// Dump contents into the pak files.
- ASSERT_EQ(file_util::WriteFile(data_path, kSamplePakContents,
+ ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents,
kSamplePakSize), static_cast<int>(kSamplePakSize));
- ASSERT_EQ(file_util::WriteFile(data_2x_path, kSamplePakContents2x,
+ ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x,
kSamplePakSize2x), static_cast<int>(kSamplePakSize2x));
// Load the regular and 2x pak files.
@@ -439,6 +442,9 @@ TEST_F(ResourceBundleImageTest, GetRawDataResource) {
// Test requesting image reps at various scale factors from the image returned
// via ResourceBundle::GetImageNamed().
TEST_F(ResourceBundleImageTest, GetImageNamed) {
+#if defined(OS_WIN)
+ gfx::ForceHighDPISupportForTesting(2.0);
+#endif
std::vector<ScaleFactor> supported_factors;
supported_factors.push_back(SCALE_FACTOR_100P);
supported_factors.push_back(SCALE_FACTOR_200P);
@@ -459,8 +465,8 @@ TEST_F(ResourceBundleImageTest, GetImageNamed) {
gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
-#if defined(OS_CHROMEOS)
- // ChromeOS loads highest scale factor first.
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+ // ChromeOS/Windows load highest scale factor first.
EXPECT_EQ(ui::SCALE_FACTOR_200P,
GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
#else
@@ -471,19 +477,25 @@ TEST_F(ResourceBundleImageTest, GetImageNamed) {
// Resource ID 3 exists in both 1x and 2x paks. Image reps should be
// available for both scale factors in |image_skia|.
gfx::ImageSkiaRep image_rep =
- image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_100P));
+ image_skia->GetRepresentation(
+ GetScaleForScaleFactor(ui::SCALE_FACTOR_100P));
EXPECT_EQ(ui::SCALE_FACTOR_100P, GetSupportedScaleFactor(image_rep.scale()));
image_rep =
- image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_200P));
+ image_skia->GetRepresentation(
+ GetScaleForScaleFactor(ui::SCALE_FACTOR_200P));
EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
// The 1.4x pack was not loaded. Requesting the 1.4x resource should return
// either the 1x or the 2x resource.
image_rep = image_skia->GetRepresentation(
- ui::GetImageScale(ui::SCALE_FACTOR_140P));
+ ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
ui::ScaleFactor scale_factor = GetSupportedScaleFactor(image_rep.scale());
EXPECT_TRUE(scale_factor == ui::SCALE_FACTOR_100P ||
scale_factor == ui::SCALE_FACTOR_200P);
+
+ // ImageSkia scales image if the one for the requested scale factor is not
+ // available.
+ EXPECT_EQ(1.4f, image_skia->GetRepresentation(1.4f).scale());
}
// Test that GetImageNamed() behaves properly for images which GRIT has
@@ -514,7 +526,8 @@ TEST_F(ResourceBundleImageTest, GetImageNamedFallback1x) {
// The image rep for 2x should be available. It should be resized to the
// proper 2x size.
gfx::ImageSkiaRep image_rep =
- image_skia->GetRepresentation(GetImageScale(ui::SCALE_FACTOR_200P));
+ image_skia->GetRepresentation(GetScaleForScaleFactor(
+ ui::SCALE_FACTOR_200P));
EXPECT_EQ(ui::SCALE_FACTOR_200P, GetSupportedScaleFactor(image_rep.scale()));
EXPECT_EQ(20, image_rep.pixel_width());
EXPECT_EQ(20, image_rep.pixel_height());
@@ -553,15 +566,21 @@ TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
gfx::ImageSkiaRep image_rep =
image_skia->GetRepresentation(
- GetImageScale(ui::SCALE_FACTOR_140P));
+ GetScaleForScaleFactor(ui::SCALE_FACTOR_140P));
EXPECT_EQ(12, image_rep.pixel_width());
image_rep = image_skia->GetRepresentation(
- GetImageScale(ui::SCALE_FACTOR_180P));
+ GetScaleForScaleFactor(ui::SCALE_FACTOR_180P));
EXPECT_EQ(15, image_rep.pixel_width());
}
#endif
-TEST_F(ResourceBundleImageTest, FallbackToNone) {
+#if defined(OS_IOS)
+// Fails on devices that have non-100P scaling. See crbug.com/298406
+#define MAYBE_FallbackToNone DISABLED_FallbackToNone
+#else
+#define MAYBE_FallbackToNone FallbackToNone
+#endif
+TEST_F(ResourceBundleImageTest, MAYBE_FallbackToNone) {
base::FilePath data_default_path = dir_path().AppendASCII("sample.pak");
// Create the pak files.
@@ -573,6 +592,7 @@ TEST_F(ResourceBundleImageTest, FallbackToNone) {
gfx::ImageSkia* image_skia = resource_bundle->GetImageSkiaNamed(3);
EXPECT_EQ(1u, image_skia->image_reps().size());
+ EXPECT_TRUE(image_skia->image_reps()[0].unscaled());
EXPECT_EQ(ui::SCALE_FACTOR_100P,
GetSupportedScaleFactor(image_skia->image_reps()[0].scale()));
}
diff --git a/chromium/ui/base/resource/resource_bundle_win.cc b/chromium/ui/base/resource/resource_bundle_win.cc
index cb99e209c3a..fa17eee5031 100644
--- a/chromium/ui/base/resource/resource_bundle_win.cc
+++ b/chromium/ui/base/resource/resource_bundle_win.cc
@@ -7,9 +7,13 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
+#include "skia/ext/image_operations.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/resource/resource_data_dll_win.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/win/dpi.h"
namespace ui {
@@ -30,7 +34,7 @@ base::FilePath GetResourcesPakFilePath(const std::string& pak_name) {
return path.AppendASCII(pak_name.c_str());
// Return just the name of the pack file.
- return base::FilePath(ASCIIToUTF16(pak_name));
+ return base::FilePath(base::ASCIIToUTF16(pak_name));
}
} // namespace
@@ -38,36 +42,18 @@ base::FilePath GetResourcesPakFilePath(const std::string& pak_name) {
void ResourceBundle::LoadCommonResources() {
// As a convenience, add the current resource module as a data packs.
data_packs_.push_back(new ResourceDataDLL(GetCurrentResourceDLL()));
- // Have high-DPI resources for 140% and 180% scaling on Windows based on
- // default scaling for Metro mode. If high-DPI mode is enabled, load resource
- // pak closest to the desired scale factor. The high-DPI resources are
- // scaled up from 100% touch.
- float scale = gfx::win::GetDeviceScaleFactor();
- bool force_touch_resources = false;
- switch(ui::GetSupportedScaleFactor(scale)) {
- case ui::SCALE_FACTOR_180P:
- AddDataPackFromPath(GetResourcesPakFilePath(
- "chrome_touch_180_percent.pak"),
- SCALE_FACTOR_180P);
- force_touch_resources = true;
- break;
- case ui::SCALE_FACTOR_140P:
- AddDataPackFromPath(GetResourcesPakFilePath(
- "chrome_touch_140_percent.pak"),
- SCALE_FACTOR_140P);
- force_touch_resources = true;
- }
- // TODO(kevers|girard): Remove loading of 1x resources when in high-DPI
- // mode once all resources are available at 140% and 180%.
- if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH || force_touch_resources) {
- AddDataPackFromPath(
- GetResourcesPakFilePath("chrome_touch_100_percent.pak"),
- SCALE_FACTOR_100P);
- } else {
+
+ if (IsScaleFactorSupported(SCALE_FACTOR_100P)) {
AddDataPackFromPath(
GetResourcesPakFilePath("chrome_100_percent.pak"),
SCALE_FACTOR_100P);
}
+ if (IsScaleFactorSupported(SCALE_FACTOR_200P)) {
+ DCHECK(gfx::IsHighDPIEnabled());
+ AddDataPackFromPath(
+ GetResourcesPakFilePath("chrome_200_percent.pak"),
+ SCALE_FACTOR_200P);
+ }
}
gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) {
diff --git a/chromium/ui/base/resource/resource_bundle_win.h b/chromium/ui/base/resource/resource_bundle_win.h
index 9a75bedf856..811464e1304 100644
--- a/chromium/ui/base/resource/resource_bundle_win.h
+++ b/chromium/ui/base/resource/resource_bundle_win.h
@@ -10,16 +10,16 @@
#include <windows.h>
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// NOTE: This needs to be called before initializing ResourceBundle if your
// resources are not stored in the executable.
-UI_EXPORT void SetResourcesDataDLL(HINSTANCE handle);
+UI_BASE_EXPORT void SetResourcesDataDLL(HINSTANCE handle);
// Loads and returns an icon from the app module.
-UI_EXPORT HICON LoadThemeIconFromResourcesDataDLL(int icon_id);
+UI_BASE_EXPORT HICON LoadThemeIconFromResourcesDataDLL(int icon_id);
} // namespace ui
diff --git a/chromium/ui/base/resource/resource_data_dll_win.cc b/chromium/ui/base/resource/resource_data_dll_win.cc
index c6c90c71d5b..e6a35aa3cd8 100644
--- a/chromium/ui/base/resource/resource_data_dll_win.cc
+++ b/chromium/ui/base/resource/resource_data_dll_win.cc
@@ -47,8 +47,7 @@ base::RefCountedStaticMemory* ResourceDataDLL::GetStaticMemory(
size_t data_size;
if (base::win::GetDataResourceFromModule(module_, resource_id, &data_ptr,
&data_size)) {
- return new base::RefCountedStaticMemory(
- reinterpret_cast<const unsigned char*>(data_ptr), data_size);
+ return new base::RefCountedStaticMemory(data_ptr, data_size);
}
return NULL;
}
diff --git a/chromium/ui/base/resource/resource_handle.h b/chromium/ui/base/resource/resource_handle.h
index 14be54efeb2..11eeac165ed 100644
--- a/chromium/ui/base/resource/resource_handle.h
+++ b/chromium/ui/base/resource/resource_handle.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "ui/base/layout.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace base {
class RefCountedStaticMemory;
@@ -16,7 +16,7 @@ class RefCountedStaticMemory;
namespace ui {
-class UI_EXPORT ResourceHandle {
+class UI_BASE_EXPORT ResourceHandle {
public:
// What type of encoding the text resources use.
enum TextEncodingType {
diff --git a/chromium/ui/base/strings/app_locale_settings.grd b/chromium/ui/base/strings/app_locale_settings.grd
deleted file mode 100644
index d285e9275b0..00000000000
--- a/chromium/ui/base/strings/app_locale_settings.grd
+++ /dev/null
@@ -1,263 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
- <outputs>
- <output filename="grit/app_locale_settings.h" type="rc_header">
- <emit emit_type='prepend'></emit>
- </output>
- <output filename="app_locale_settings_am.pak" type="data_package" lang="am" />
- <output filename="app_locale_settings_ar.pak" type="data_package" lang="ar" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_ast.pak" type="data_package" lang="ast" />
- </if>
- <output filename="app_locale_settings_bg.pak" type="data_package" lang="bg" />
- <output filename="app_locale_settings_bn.pak" type="data_package" lang="bn" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_bs.pak" type="data_package" lang="bs" />
- </if>
- <output filename="app_locale_settings_ca.pak" type="data_package" lang="ca" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
- </if>
- <output filename="app_locale_settings_cs.pak" type="data_package" lang="cs" />
- <output filename="app_locale_settings_da.pak" type="data_package" lang="da" />
- <output filename="app_locale_settings_de.pak" type="data_package" lang="de" />
- <output filename="app_locale_settings_el.pak" type="data_package" lang="el" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_en-AU.pak" type="data_package" lang="en-AU" />
- </if>
- <output filename="app_locale_settings_en-GB.pak" type="data_package" lang="en-GB" />
- <output filename="app_locale_settings_en-US.pak" type="data_package" lang="en" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_eo.pak" type="data_package" lang="eo" />
- </if>
- <output filename="app_locale_settings_es.pak" type="data_package" lang="es" />
- <if expr="is_ios">
- <!-- iOS uses es-MX for es-419 -->
- <output filename="app_locale_settings_es-MX.pak" type="data_package" lang="es-419" />
- </if>
- <if expr="not is_ios">
- <output filename="app_locale_settings_es-419.pak" type="data_package" lang="es-419" />
- </if>
- <output filename="app_locale_settings_et.pak" type="data_package" lang="et" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_eu.pak" type="data_package" lang="eu" />
- </if>
- <output filename="app_locale_settings_fa.pak" type="data_package" lang="fa" />
- <output filename="app_locale_settings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
- <output filename="app_locale_settings_fi.pak" type="data_package" lang="fi" />
- <output filename="app_locale_settings_fil.pak" type="data_package" lang="fil" />
- <output filename="app_locale_settings_fr.pak" type="data_package" lang="fr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_gl.pak" type="data_package" lang="gl" />
- </if>
- <output filename="app_locale_settings_gu.pak" type="data_package" lang="gu" />
- <output filename="app_locale_settings_he.pak" type="data_package" lang="he" />
- <output filename="app_locale_settings_hi.pak" type="data_package" lang="hi" />
- <output filename="app_locale_settings_hr.pak" type="data_package" lang="hr" />
- <output filename="app_locale_settings_hu.pak" type="data_package" lang="hu" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_hy.pak" type="data_package" lang="hy" />
- <output filename="app_locale_settings_ia.pak" type="data_package" lang="ia" />
- </if>
- <output filename="app_locale_settings_id.pak" type="data_package" lang="id" />
- <output filename="app_locale_settings_it.pak" type="data_package" lang="it" />
- <output filename="app_locale_settings_ja.pak" type="data_package" lang="ja" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_ka.pak" type="data_package" lang="ka" />
- </if>
- <output filename="app_locale_settings_kn.pak" type="data_package" lang="kn" />
- <output filename="app_locale_settings_ko.pak" type="data_package" lang="ko" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_ku.pak" type="data_package" lang="ku" />
- <output filename="app_locale_settings_kw.pak" type="data_package" lang="kw" />
- </if>
- <output filename="app_locale_settings_lt.pak" type="data_package" lang="lt" />
- <output filename="app_locale_settings_lv.pak" type="data_package" lang="lv" />
- <output filename="app_locale_settings_ml.pak" type="data_package" lang="ml" />
- <output filename="app_locale_settings_mr.pak" type="data_package" lang="mr" />
- <output filename="app_locale_settings_ms.pak" type="data_package" lang="ms" />
- <output filename="app_locale_settings_nl.pak" type="data_package" lang="nl" />
- <!-- The translation console uses 'no' for Norwegian Bokmål. It should
- be 'nb'. -->
- <output filename="app_locale_settings_nb.pak" type="data_package" lang="no" />
- <output filename="app_locale_settings_pl.pak" type="data_package" lang="pl" />
- <if expr="is_ios">
- <!-- iOS uses pt for pt-BR -->
- <output filename="app_locale_settings_pt.pak" type="data_package" lang="pt-BR" />
- </if>
- <if expr="not is_ios">
- <output filename="app_locale_settings_pt-BR.pak" type="data_package" lang="pt-BR" />
- </if>
- <output filename="app_locale_settings_pt-PT.pak" type="data_package" lang="pt-PT" />
- <output filename="app_locale_settings_ro.pak" type="data_package" lang="ro" />
- <output filename="app_locale_settings_ru.pak" type="data_package" lang="ru" />
- <output filename="app_locale_settings_sk.pak" type="data_package" lang="sk" />
- <output filename="app_locale_settings_sl.pak" type="data_package" lang="sl" />
- <output filename="app_locale_settings_sr.pak" type="data_package" lang="sr" />
- <output filename="app_locale_settings_sv.pak" type="data_package" lang="sv" />
- <output filename="app_locale_settings_sw.pak" type="data_package" lang="sw" />
- <output filename="app_locale_settings_ta.pak" type="data_package" lang="ta" />
- <output filename="app_locale_settings_te.pak" type="data_package" lang="te" />
- <output filename="app_locale_settings_th.pak" type="data_package" lang="th" />
- <output filename="app_locale_settings_tr.pak" type="data_package" lang="tr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="app_locale_settings_ug.pak" type="data_package" lang="ug" />
- </if>
- <output filename="app_locale_settings_uk.pak" type="data_package" lang="uk" />
- <output filename="app_locale_settings_vi.pak" type="data_package" lang="vi" />
- <output filename="app_locale_settings_zh-CN.pak" type="data_package" lang="zh-CN" />
- <output filename="app_locale_settings_zh-TW.pak" type="data_package" lang="zh-TW" />
- </outputs>
- <translations>
- <file path="app_locale_settings_am.xtb" lang="am" />
- <file path="app_locale_settings_ar.xtb" lang="ar" />
- <file path="app_locale_settings_bg.xtb" lang="bg" />
- <file path="app_locale_settings_bn.xtb" lang="bn" />
- <file path="app_locale_settings_ca.xtb" lang="ca" />
- <file path="app_locale_settings_cs.xtb" lang="cs" />
- <file path="app_locale_settings_da.xtb" lang="da" />
- <file path="app_locale_settings_de.xtb" lang="de" />
- <file path="app_locale_settings_el.xtb" lang="el" />
- <file path="app_locale_settings_en-GB.xtb" lang="en-GB" />
- <file path="app_locale_settings_es.xtb" lang="es" />
- <file path="app_locale_settings_es-419.xtb" lang="es-419" />
- <file path="app_locale_settings_et.xtb" lang="et" />
- <file path="app_locale_settings_fa.xtb" lang="fa" />
- <file path="app_locale_settings_fi.xtb" lang="fi" />
- <file path="app_locale_settings_fil.xtb" lang="fil" />
- <file path="app_locale_settings_fr.xtb" lang="fr" />
- <file path="app_locale_settings_gu.xtb" lang="gu" />
- <file path="app_locale_settings_he.xtb" lang="he" />
- <file path="app_locale_settings_hi.xtb" lang="hi" />
- <file path="app_locale_settings_hr.xtb" lang="hr" />
- <file path="app_locale_settings_hu.xtb" lang="hu" />
- <file path="app_locale_settings_id.xtb" lang="id" />
- <file path="app_locale_settings_it.xtb" lang="it" />
- <file path="app_locale_settings_ja.xtb" lang="ja" />
- <file path="app_locale_settings_kn.xtb" lang="kn" />
- <file path="app_locale_settings_ko.xtb" lang="ko" />
- <file path="app_locale_settings_lt.xtb" lang="lt" />
- <file path="app_locale_settings_lv.xtb" lang="lv" />
- <file path="app_locale_settings_ml.xtb" lang="ml" />
- <file path="app_locale_settings_mr.xtb" lang="mr" />
- <file path="app_locale_settings_ms.xtb" lang="ms" />
- <file path="app_locale_settings_nl.xtb" lang="nl" />
- <file path="app_locale_settings_nb.xtb" lang="no" />
- <file path="app_locale_settings_pl.xtb" lang="pl" />
- <file path="app_locale_settings_pt-BR.xtb" lang="pt-BR" />
- <file path="app_locale_settings_pt-PT.xtb" lang="pt-PT" />
- <file path="app_locale_settings_ro.xtb" lang="ro" />
- <file path="app_locale_settings_ru.xtb" lang="ru" />
- <file path="app_locale_settings_sk.xtb" lang="sk" />
- <file path="app_locale_settings_sl.xtb" lang="sl" />
- <file path="app_locale_settings_sr.xtb" lang="sr" />
- <file path="app_locale_settings_sv.xtb" lang="sv" />
- <file path="app_locale_settings_sw.xtb" lang="sw" />
- <file path="app_locale_settings_ta.xtb" lang="ta" />
- <file path="app_locale_settings_te.xtb" lang="te" />
- <file path="app_locale_settings_th.xtb" lang="th" />
- <file path="app_locale_settings_tr.xtb" lang="tr" />
- <file path="app_locale_settings_uk.xtb" lang="uk" />
- <file path="app_locale_settings_vi.xtb" lang="vi" />
- <file path="app_locale_settings_zh-CN.xtb" lang="zh-CN" />
- <file path="app_locale_settings_zh-TW.xtb" lang="zh-TW" />
- </translations>
- <release seq="1" allow_pseudo="false">
- <messages fallback_to_english="true">
- <!-- The UI font used in native UI components (e.g. menu). 'default'
- indicates that the font obtained from the system be used.
- Otherwise, the system default UI font will be overriden with
- the family specified. This should be default for locales
- other than Indian locales.
- TODO(jungshik): This and IDS_UI_FONT_SIZE_SCALER are only used
- on Windows now and are likely to be so in the future because Mac and
- Linux fonts do not have the issue Windows fonts for some locales
- (Indian) have. In that case, this need to be enclosed
- by platform-dependent if-clause. -->
- <if expr="is_win">
- <!-- Limit minimum UI font size to 5 by default. -->
- <message name="IDS_MINIMUM_UI_FONT_SIZE" use_name_for_id="true">
- 5
- </message>
-
- <message name="IDS_UI_FONT_FAMILY" use_name_for_id="true">
- default
- </message>
- <!-- For Windows XP -->
- <message name="IDS_UI_FONT_FAMILY_XP" use_name_for_id="true">
- default
- </message>
-
- <!-- To get the actual UI font size for native UI components
- (e.g. menu), the system UI font size is scaled with this value/100.
- This should be 100 for most locales. -->
- <message name="IDS_UI_FONT_SIZE_SCALER" use_name_for_id="true">
- 100
- </message>
- <!-- For Windows XP -->
- <message name="IDS_UI_FONT_SIZE_SCALER_XP" use_name_for_id="true">
- 100
- </message>
-
- <!-- The font used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
- 'Segoe UI', Tahoma, sans-serif
- </message>
- <!-- The font used in Web UI on Windows XP (e.g. History). -->
- <message name="IDS_WEB_FONT_FAMILY_XP" use_name_for_id="true">
- Tahoma, sans-serif
- </message>
-
- <!-- The relative font size in % used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
- 75%
- </message>
- <!-- The relative font size in % used in web-style native pages
- on Windows earlier than Vista (e.g. History). -->
- <message name="IDS_WEB_FONT_SIZE_XP" use_name_for_id="true">
- 75%
- </message>
- </if>
- <if expr="is_macosx or is_ios">
- <!-- The font used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
- 'Lucida Grande', sans-serif
- </message>
-
- <!-- The relative font size in % used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
- 75%
- </message>
- </if>
- <if expr="(is_linux or is_android) and not pp_ifdef('chromeos')">
- <!-- The font used in Web UI (e.g. History). Note that these are only
- backups. We try to use the system font if possible. -->
- <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
- Arial, sans-serif
- </message>
-
- <!-- The relative font size in % used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
- 75%
- </message>
- </if>
- <!-- For Chrome OS -->
- <if expr="pp_ifdef('chromeos')">
- <!-- The font name like: 'Font Name, 10' -->
- <message name="IDS_UI_FONT_FAMILY_CROS" use_name_for_id="true">
- Noto Sans UI,ui-sans, 12px
- </message>
-
- <!-- The font used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
- 'Noto Sans UI', sans-serif
- </message>
-
- <!-- The relative font size in % used in Web UI (e.g. History). -->
- <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
- 75%
- </message>
- </if>
- </messages>
- </release>
-</grit>
diff --git a/chromium/ui/base/strings/app_locale_settings_am.xtb b/chromium/ui/base/strings/app_locale_settings_am.xtb
deleted file mode 100644
index e16e4992f36..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_am.xtb
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="am">
-<translation id="IDS_UI_FONT_FAMILY_XP">abyssinica sil</translation>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Abyssinica SIL, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ar.xtb b/chromium/ui/base/strings/app_locale_settings_ar.xtb
deleted file mode 100644
index 2ec65feb761..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_ar.xtb
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ar">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Droid Arabic Kufi,ui-sans, 13px</translation>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Arabic Naskh, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_bn.xtb b/chromium/ui/base/strings/app_locale_settings_bn.xtb
deleted file mode 100644
index 1e9ee2c4a56..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_bn.xtb
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="bn">
-<if expr="is_win">
- <translation id="IDS_UI_FONT_FAMILY">Vrinda</translation>
- <translation id="IDS_UI_FONT_FAMILY_XP">Vrinda</translation>
- <translation id="IDS_UI_FONT_SIZE_SCALER_XP">160</translation>
- <translation id="IDS_UI_FONT_SIZE_SCALER">120</translation>
- <translation id="IDS_WEB_FONT_SIZE_XP">110%</translation>
- <translation id="IDS_WEB_FONT_FAMILY">Vrinda</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Vrinda</translation>
-</if>
-<if expr="is_linux and not pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Lohit Bengali</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Bengali UI, ui-sans, 13px</translation>
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Bengali UI, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_hi.xtb b/chromium/ui/base/strings/app_locale_settings_hi.xtb
deleted file mode 100644
index 73814971c8e..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_hi.xtb
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="hi">
-<translation id="IDS_UI_FONT_SIZE_SCALER_XP">140</translation>
-<translation id="IDS_UI_FONT_SIZE_SCALER">125</translation>
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Devanagari UI,ui-sans, 13px</translation>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Devanagari UI,sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ja.xtb b/chromium/ui/base/strings/app_locale_settings_ja.xtb
deleted file mode 100644
index 1e843b0ad73..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_ja.xtb
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ja">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">MotoyaG04Gothic,Noto Sans UI,IPAPGothic,ui-sans, 13px</translation>
-<if expr="is_win">
- <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,Meiryo,'MS PGothic',sans-serif</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,Meiryo,'MS PGothic',sans-serif</translation>
-</if>
-<if expr="is_macosx or is_ios">
- <translation id="IDS_WEB_FONT_FAMILY">Helvetica,Hiragino Kaku Gothic Pro,sans-serif</translation>
-</if>
-<if expr="is_linux and not pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">VL PGothic,Sazanami Gothic,Kochi Gothic,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">MotoyaG04Gothic, Noto Sans UI, sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and not pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, IPAPGothic, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_kn.xtb b/chromium/ui/base/strings/app_locale_settings_kn.xtb
deleted file mode 100644
index f385c52feb9..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_kn.xtb
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="kn">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<if expr="is_win">
- <translation id="IDS_UI_FONT_SIZE_SCALER_XP">142</translation>
- <translation id="IDS_UI_FONT_SIZE_SCALER">130</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Kannada UI,ui-sans, 13px</translation>
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Kannada UI, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ko.xtb b/chromium/ui/base/strings/app_locale_settings_ko.xtb
deleted file mode 100644
index e1db12edb41..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_ko.xtb
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ko">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,NanumGothic,ui-sans, 13px</translation>
-<if expr="is_win">
- <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Malgun Gothic',Gulim,sans-serif</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Malgun Gothic',Gulim,sans-serif</translation>
-</if>
-<if expr="is_macosx or is_ios">
- <translation id="IDS_WEB_FONT_FAMILY">Helvetica,AppleGothic,sans-serif</translation>
-</if>
-<if expr="is_linux and not pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">NanumGothic,UnDotum,Baekmuk Gulim,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, NanumGothic, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ml.xtb b/chromium/ui/base/strings/app_locale_settings_ml.xtb
deleted file mode 100644
index 27292f926b3..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_ml.xtb
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ml">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<if expr="is_win">
- <translation id="IDS_UI_FONT_FAMILY_XP">kartika</translation>
- <translation id="IDS_UI_FONT_SIZE_SCALER_XP">150</translation>
- <translation id="IDS_UI_FONT_SIZE_SCALER">120</translation>
- <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,AnjaliOldLipi,Rachana,Kartika</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,AnjaliOldLipi,Rachana,Kartika</translation>
-</if>
-<if expr="is_linux and not pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Arial,AnjaliOldLipi,Rachana,Kartika,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Malayalam UI,ui-sans, 13px</translation>
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Malayalam UI, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_mr.xtb b/chromium/ui/base/strings/app_locale_settings_mr.xtb
deleted file mode 100644
index d657ca38355..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_mr.xtb
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="mr">
-<translation id="IDS_UI_FONT_SIZE_SCALER_XP">140</translation>
-<translation id="IDS_UI_FONT_SIZE_SCALER">125</translation>
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Devanagari UI,ui-sans, 13px</translation>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Devanagari UI,sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ta.xtb b/chromium/ui/base/strings/app_locale_settings_ta.xtb
deleted file mode 100644
index ef5ff549358..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_ta.xtb
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ta">
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Tamil UI,ui-sans, 13px</translation>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Tamil UI,sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_te.xtb b/chromium/ui/base/strings/app_locale_settings_te.xtb
deleted file mode 100644
index a25522e8696..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_te.xtb
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="te">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<if expr="is_win">
-<translation id="IDS_UI_FONT_SIZE_SCALER_XP">145</translation>
-<translation id="IDS_UI_FONT_SIZE_SCALER">130</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Telugu UI,ui-sans, 13px</translation>
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Telugu UI, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_th.xtb b/chromium/ui/base/strings/app_locale_settings_th.xtb
deleted file mode 100644
index d1851985d0d..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_th.xtb
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="th">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Thai UI,ui-sans, 13px</translation>
-<if expr="is_win">
- <translation id="IDS_WEB_FONT_FAMILY">Tahoma,sans-serif</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Tahoma,sans-serif</translation>
-</if>
-<if expr="is_linux and not pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Norasi,Waree,Garuda,Loma,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Thai UI,sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_zh-CN.xtb b/chromium/ui/base/strings/app_locale_settings_zh-CN.xtb
deleted file mode 100644
index e67b6c12e12..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_zh-CN.xtb
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="zh-CN">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiGB18030,MYingHeiB5HK,ui-sans, 13px</translation>
-<if expr="is_win">
- <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
-</if>
-<if expr="is_macosx or is_ios">
- <translation id="IDS_WEB_FONT_FAMILY">Helvetica,STHeiti,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiGB18030, MYingHeiB5HK, sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and not pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_zh-TW.xtb b/chromium/ui/base/strings/app_locale_settings_zh-TW.xtb
deleted file mode 100644
index 2492fbc3138..00000000000
--- a/chromium/ui/base/strings/app_locale_settings_zh-TW.xtb
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="zh-TW">
-<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiB5HK,MYingHeiGB18030,ui-sans, 13px</translation>
-<if expr="is_win">
- <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
- <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
-</if>
-<if expr="is_macosx or is_ios">
- <translation id="IDS_WEB_FONT_FAMILY">Helvetica,LiHei Pro,sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiB5HK, MYingHeiGB18030, sans-serif</translation>
-</if>
-<if expr="pp_ifdef('chromeos') and not pp_ifdef('_google_chrome')">
- <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
-</if>
-</translationbundle>
diff --git a/chromium/ui/base/strings/ui_strings.grd b/chromium/ui/base/strings/ui_strings.grd
deleted file mode 100644
index 31413635cee..00000000000
--- a/chromium/ui/base/strings/ui_strings.grd
+++ /dev/null
@@ -1,1616 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- This file contains definitions of resources that will be translated for
-each locale. Specifically, these are UI strings that are used by app/ that
-need to be translated for each locale.-->
-
-<grit base_dir="." latest_public_release="0" current_release="1"
- source_lang_id="en" enc_check="möl">
- <outputs>
- <!-- TODO add each of your output files. Modify the three below, and add
- your own for your various languages. See the user's guide
- (http://wiki/Main/GritUsersGuide) for more details.
- Note that all output references are relative to the output directory
- which is specified at build time. -->
- <output filename="grit/ui_strings.h" type="rc_header">
- <emit emit_type='prepend'></emit>
- </output>
- <output filename="ui_strings_am.pak" type="data_package" lang="am" />
- <output filename="ui_strings_ar.pak" type="data_package" lang="ar" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_ast.pak" type="data_package" lang="ast" />
- </if>
- <output filename="ui_strings_bg.pak" type="data_package" lang="bg" />
- <output filename="ui_strings_bn.pak" type="data_package" lang="bn" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_bs.pak" type="data_package" lang="bs" />
- </if>
- <output filename="ui_strings_ca.pak" type="data_package" lang="ca" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
- </if>
- <output filename="ui_strings_cs.pak" type="data_package" lang="cs" />
- <output filename="ui_strings_da.pak" type="data_package" lang="da" />
- <output filename="ui_strings_de.pak" type="data_package" lang="de" />
- <output filename="ui_strings_el.pak" type="data_package" lang="el" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_en-AU.pak" type="data_package" lang="en-AU" />
- </if>
- <output filename="ui_strings_en-GB.pak" type="data_package" lang="en-GB" />
- <output filename="ui_strings_en-US.pak" type="data_package" lang="en" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_eo.pak" type="data_package" lang="eo" />
- </if>
- <output filename="ui_strings_es.pak" type="data_package" lang="es" />
- <if expr="is_ios">
- <!-- iOS uses es-MX for es-419 -->
- <output filename="ui_strings_es-MX.pak" type="data_package" lang="es-419" />
- </if>
- <if expr="not is_ios">
- <output filename="ui_strings_es-419.pak" type="data_package" lang="es-419" />
- </if>
- <output filename="ui_strings_et.pak" type="data_package" lang="et" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_eu.pak" type="data_package" lang="eu" />
- </if>
- <output filename="ui_strings_fa.pak" type="data_package" lang="fa" />
- <output filename="ui_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
- <output filename="ui_strings_fi.pak" type="data_package" lang="fi" />
- <output filename="ui_strings_fil.pak" type="data_package" lang="fil" />
- <output filename="ui_strings_fr.pak" type="data_package" lang="fr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_gl.pak" type="data_package" lang="gl" />
- </if>
- <output filename="ui_strings_gu.pak" type="data_package" lang="gu" />
- <output filename="ui_strings_he.pak" type="data_package" lang="he" />
- <output filename="ui_strings_hi.pak" type="data_package" lang="hi" />
- <output filename="ui_strings_hr.pak" type="data_package" lang="hr" />
- <output filename="ui_strings_hu.pak" type="data_package" lang="hu" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_hy.pak" type="data_package" lang="hy" />
- <output filename="ui_strings_ia.pak" type="data_package" lang="ia" />
- </if>
- <output filename="ui_strings_id.pak" type="data_package" lang="id" />
- <output filename="ui_strings_it.pak" type="data_package" lang="it" />
- <output filename="ui_strings_ja.pak" type="data_package" lang="ja" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_ka.pak" type="data_package" lang="ka" />
- </if>
- <output filename="ui_strings_kn.pak" type="data_package" lang="kn" />
- <output filename="ui_strings_ko.pak" type="data_package" lang="ko" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_ku.pak" type="data_package" lang="ku" />
- <output filename="ui_strings_kw.pak" type="data_package" lang="kw" />
- </if>
- <output filename="ui_strings_lt.pak" type="data_package" lang="lt" />
- <output filename="ui_strings_lv.pak" type="data_package" lang="lv" />
- <output filename="ui_strings_ml.pak" type="data_package" lang="ml" />
- <output filename="ui_strings_mr.pak" type="data_package" lang="mr" />
- <output filename="ui_strings_ms.pak" type="data_package" lang="ms" />
- <output filename="ui_strings_nl.pak" type="data_package" lang="nl" />
- <!-- The translation console uses 'no' for Norwegian Bokmål. It should
- be 'nb'. -->
- <output filename="ui_strings_nb.pak" type="data_package" lang="no" />
- <output filename="ui_strings_pl.pak" type="data_package" lang="pl" />
- <if expr="is_ios">
- <!-- iOS uses pt for pt-BR -->
- <output filename="ui_strings_pt.pak" type="data_package" lang="pt-BR" />
- </if>
- <if expr="not is_ios">
- <output filename="ui_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
- </if>
- <output filename="ui_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
- <output filename="ui_strings_ro.pak" type="data_package" lang="ro" />
- <output filename="ui_strings_ru.pak" type="data_package" lang="ru" />
- <output filename="ui_strings_sk.pak" type="data_package" lang="sk" />
- <output filename="ui_strings_sl.pak" type="data_package" lang="sl" />
- <output filename="ui_strings_sr.pak" type="data_package" lang="sr" />
- <output filename="ui_strings_sv.pak" type="data_package" lang="sv" />
- <output filename="ui_strings_sw.pak" type="data_package" lang="sw" />
- <output filename="ui_strings_ta.pak" type="data_package" lang="ta" />
- <output filename="ui_strings_te.pak" type="data_package" lang="te" />
- <output filename="ui_strings_th.pak" type="data_package" lang="th" />
- <output filename="ui_strings_tr.pak" type="data_package" lang="tr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <output filename="ui_strings_ug.pak" type="data_package" lang="ug" />
- </if>
- <output filename="ui_strings_uk.pak" type="data_package" lang="uk" />
- <output filename="ui_strings_vi.pak" type="data_package" lang="vi" />
- <output filename="ui_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
- <output filename="ui_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
- </outputs>
- <translations>
- <file path="ui_strings_am.xtb" lang="am" />
- <file path="ui_strings_ar.xtb" lang="ar" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_ast.xtb" lang="ast" />
- </if>
- <file path="ui_strings_bg.xtb" lang="bg" />
- <file path="ui_strings_bn.xtb" lang="bn" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_bs.xtb" lang="bs" />
- </if>
- <file path="ui_strings_ca.xtb" lang="ca" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_ca-valencia.xtb" lang="ca@valencia" />
- </if>
- <file path="ui_strings_cs.xtb" lang="cs" />
- <file path="ui_strings_da.xtb" lang="da" />
- <file path="ui_strings_de.xtb" lang="de" />
- <file path="ui_strings_el.xtb" lang="el" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_en-AU.xtb" lang="en-AU" />
- </if>
- <file path="ui_strings_en-GB.xtb" lang="en-GB" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_eo.xtb" lang="eo" />
- </if>
- <file path="ui_strings_es.xtb" lang="es" />
- <file path="ui_strings_es-419.xtb" lang="es-419" />
- <file path="ui_strings_et.xtb" lang="et" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_eu.xtb" lang="eu" />
- </if>
- <file path="ui_strings_fa.xtb" lang="fa" />
- <file path="ui_strings_fi.xtb" lang="fi" />
- <file path="ui_strings_fil.xtb" lang="fil" />
- <file path="ui_strings_fr.xtb" lang="fr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_gl.xtb" lang="gl" />
- </if>
- <file path="ui_strings_gu.xtb" lang="gu" />
- <file path="ui_strings_hi.xtb" lang="hi" />
- <file path="ui_strings_hr.xtb" lang="hr" />
- <file path="ui_strings_hu.xtb" lang="hu" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_hy.xtb" lang="hy" />
- <file path="../../../third_party/launchpad_translations/ui_strings_ia.xtb" lang="ia" />
- </if>
- <file path="ui_strings_id.xtb" lang="id" />
- <file path="ui_strings_it.xtb" lang="it" />
- <!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
- <file path="ui_strings_iw.xtb" lang="he" />
- <file path="ui_strings_ja.xtb" lang="ja" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_ka.xtb" lang="ka" />
- </if>
- <file path="ui_strings_kn.xtb" lang="kn" />
- <file path="ui_strings_ko.xtb" lang="ko" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_ku.xtb" lang="ku" />
- <file path="../../../third_party/launchpad_translations/ui_strings_kw.xtb" lang="kw" />
- </if>
- <file path="ui_strings_lt.xtb" lang="lt" />
- <file path="ui_strings_lv.xtb" lang="lv" />
- <file path="ui_strings_ml.xtb" lang="ml" />
- <file path="ui_strings_mr.xtb" lang="mr" />
- <file path="ui_strings_ms.xtb" lang="ms" />
- <file path="ui_strings_nl.xtb" lang="nl" />
- <file path="ui_strings_no.xtb" lang="no" />
- <file path="ui_strings_pl.xtb" lang="pl" />
- <file path="ui_strings_pt-BR.xtb" lang="pt-BR" />
- <file path="ui_strings_pt-PT.xtb" lang="pt-PT" />
- <file path="ui_strings_ro.xtb" lang="ro" />
- <file path="ui_strings_ru.xtb" lang="ru" />
- <file path="ui_strings_sk.xtb" lang="sk" />
- <file path="ui_strings_sl.xtb" lang="sl" />
- <file path="ui_strings_sr.xtb" lang="sr" />
- <file path="ui_strings_sv.xtb" lang="sv" />
- <file path="ui_strings_sw.xtb" lang="sw" />
- <file path="ui_strings_ta.xtb" lang="ta" />
- <file path="ui_strings_te.xtb" lang="te" />
- <file path="ui_strings_th.xtb" lang="th" />
- <file path="ui_strings_tr.xtb" lang="tr" />
- <if expr="pp_ifdef('use_third_party_translations')">
- <file path="../../../third_party/launchpad_translations/ui_strings_ug.xtb" lang="ug" />
- </if>
- <file path="ui_strings_uk.xtb" lang="uk" />
- <file path="ui_strings_vi.xtb" lang="vi" />
- <file path="ui_strings_zh-CN.xtb" lang="zh-CN" />
- <file path="ui_strings_zh-TW.xtb" lang="zh-TW" />
- </translations>
- <release seq="1" allow_pseudo="false">
- <messages fallback_to_english="true">
-
- <!-- time format -->
- <message name="IDS_TIME_SECS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_SEC_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_SEC_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_SECS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_SECS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_SECS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_SECS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_SECS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_SECS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_SECS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_SECS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_MINS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_MIN_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_MIN_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_MINS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_MINS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_MINS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_MINS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_MINS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_MINS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_MINS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_MINS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_HOURS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_HOUR_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_HOUR_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_HOURS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_HOURS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_HOURS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_HOURS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_HOURS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_HOURS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_HOURS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_HOURS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_DAYS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_DAY_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_DAY_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_DAYS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_DAYS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_DAYS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DAYS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_DAYS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DAYS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_DAYS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_DAYS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_REMAINING_SECS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs left
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_REMAINING_SEC_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec left
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_REMAINING_SEC_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_REMAINING_SECS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs left
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_REMAINING_SECS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_SECS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs left
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_SECS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_SECS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs left
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_SECS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_REMAINING_SECS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs left
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_REMAINING_SECS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_REMAINING_MINS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins left
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_REMAINING_MIN_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min left
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_REMAINING_MIN_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_REMAINING_MINS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins left
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_REMAINING_MINS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_MINS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins left
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_MINS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_MINS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins left
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_MINS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_REMAINING_MINS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins left
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_REMAINING_MINS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_REMAINING_LONG_MINS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes left
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute left
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes left
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_LONG_MINS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes left
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_LONG_MINS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes left
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_REMAINING_LONG_MINS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes left
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_REMAINING_HOURS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours left
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_REMAINING_HOUR_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour left
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_REMAINING_HOUR_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_REMAINING_HOURS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours left
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_REMAINING_HOURS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_HOURS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours left
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_HOURS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_HOURS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours left
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_HOURS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_REMAINING_HOURS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours left
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_REMAINING_HOURS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_REMAINING_DAYS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days left
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_REMAINING_DAY_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day left
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_REMAINING_DAY_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_REMAINING_DAYS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days left
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_REMAINING_DAYS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_DAYS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days left
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_DAYS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_REMAINING_DAYS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days left
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_REMAINING_DAYS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_REMAINING_DAYS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days left
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_REMAINING_DAYS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_DURATION_LONG_SECS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_DURATION_LONG_SECS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_DURATION_LONG_SECS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_DURATION_LONG_SECS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_DURATION_LONG_SECS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_DURATION_LONG_MINS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_DURATION_LONG_MINS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_DURATION_LONG_MINS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_DURATION_LONG_MINS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_DURATION_LONG_MINS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_TIME_ELAPSED_SECS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs ago
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_ELAPSED_SEC_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec ago
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_ELAPSED_SEC_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_ELAPSED_SECS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs ago
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_ELAPSED_SECS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_SECS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs ago
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_SECS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_SECS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs ago
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_SECS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_ELAPSED_SECS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs ago
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_ELAPSED_SECS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_ELAPSED_MINS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins ago
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_ELAPSED_MIN_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min ago
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_ELAPSED_MIN_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_ELAPSED_MINS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins ago
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_ELAPSED_MINS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_MINS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins ago
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_MINS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_MINS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins ago
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_MINS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_ELAPSED_MINS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins ago
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_ELAPSED_MINS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_ELAPSED_HOURS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours ago
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour ago
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_ELAPSED_HOURS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours ago
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_HOURS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours ago
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_HOURS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours ago
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_ELAPSED_HOURS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours ago
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_MANY"
- desc="">
- NA
- </message>
- </if>
-
-
- <message name="IDS_TIME_ELAPSED_DAYS_DEFAULT"
- desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
- <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days ago
- </message>
-
- <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message name="IDS_TIME_ELAPSED_DAY_SINGULAR"
- desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
- <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day ago
- </message>
- </if>
- <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
- <message translateable="false" name="IDS_TIME_ELAPSED_DAY_SINGULAR"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ar', 'ro', 'lv']">
- <message name="IDS_TIME_ELAPSED_DAYS_ZERO"
- desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
- <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days ago
- </message>
- </if>
- <if expr="lang not in ['ar', 'ro', 'lv']">
- <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_ZERO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ga', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_DAYS_TWO"
- desc="NUMBER_TWO is two or two-like/dual numbers : 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
- <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days ago
- </message>
- </if>
- <if expr="lang not in ['ga', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_TWO"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message name="IDS_TIME_ELAPSED_DAYS_FEW"
- desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
- <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days ago
- </message>
- </if>
- <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
- <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_FEW"
- desc="">
- NA
- </message>
- </if>
-
- <if expr="lang == 'ar'">
- <message name="IDS_TIME_ELAPSED_DAYS_MANY"
- desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
- <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days ago
- </message>
- </if>
- <if expr="lang != 'ar'">
- <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_MANY"
- desc="">
- NA
- </message>
- </if>
-
- <message name="IDS_PAST_TIME_TODAY" desc="Relative day today">
- Today
- </message>
- <message name="IDS_PAST_TIME_YESTERDAY" desc="Relative day yesterday">
- Yesterday
- </message>
-
- <!-- Menus -->
- <message name="IDS_APP_MENU_EMPTY_SUBMENU" desc="Used when a submenu has no entries">
- (empty)
- </message>
-
- <!-- General application strings -->
- <message name="IDS_APP_UNTITLED_SHORTCUT_FILE_NAME" desc="The name of the Internet Shortcut file created for URLs dragged that have no title">
- Untitled Webpage
- </message>
- <message name="IDS_APP_SAVEAS_ALL_FILES" desc="Save As dialog box default text">
- All Files
- </message>
- <message name="IDS_APP_SAVEAS_EXTENSION_FORMAT" desc="Save As dialog box extension format text">
- <ph name="SAVEAS_EXTENSION_TYPE">$1<ex>EXE</ex></ph> File (.<ph name="SAVEAS_EXTENSION_NAME">$2<ex>exe</ex></ph>)
- </message>
- <message name="IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE" desc="The default title for the Select Upload Folder dialog.">
- Select Folder to Upload
- </message>
-
- <if expr="is_macosx">
- <message name="IDS_SELECT_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog.">
- Select
- </message>
- <message name="IDS_SELECT_UPLOAD_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog for uploading.">
- Upload
- </message>
- </if>
-
- <!-- File chooser dialog default titles (only used on Linux) -->
- <message name="IDS_SELECT_FOLDER_DIALOG_TITLE" desc="The default title for the Select Folder file chooser dialog.">
- Select Folder
- </message>
- <message name="IDS_SAVE_AS_DIALOG_TITLE" desc="The default title for the Save As file chooser dialog.">
- Save File
- </message>
- <message name="IDS_OPEN_FILE_DIALOG_TITLE" desc="The default title for the Open File file chooser dialog (single file).">
- Open File
- </message>
- <message name="IDS_OPEN_FILES_DIALOG_TITLE" desc="The default title for the Open File file chooser dialog (multiple files).">
- Open Files
- </message>
- <message name="IDS_SAVEAS_ALL_FILES" desc="Save As dialog box default text">
- All Files
- </message>
- <message name="IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON" desc="Button label text for Upload Folder dialog">
- Upload
- </message>
-
- <!--Accessible name/action strings-->
- <message name="IDS_APP_ACCACTION_PRESS" desc="The accessible default action for a button.">
- Press
- </message>
- <message name="IDS_APP_ACCNAME_CLOSE" desc="The accessible name for the Close button.">
- Close
- </message>
- <message name="IDS_APP_ACCNAME_MINIMIZE" desc="The accessible name for the Minimize button.">
- Minimize
- </message>
- <message name="IDS_APP_ACCNAME_MAXIMIZE" desc="The accessible name for the Maximize button.">
- Maximize
- </message>
- <message name="IDS_APP_ACCNAME_RESTORE" desc="The accessible name for the Restore button.">
- Restore
- </message>
-
- <!-- Scroll Bar Context Menu Labels -->
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE" desc="The label for the 'Scroll Here' item">
- Scroll to Here
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE" desc="The label for the 'Left Edge' item">
- Left Edge
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE" desc="The label for the 'Right Edge' item">
- Right Edge
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME" desc="The label for the 'Top' item">
- Top
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLEND" desc="The label for the 'Bottom' item">
- Bottom
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP" desc="The label for the 'Page Up' item">
- Page Up
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN" desc="The label for the 'Page Down' item">
- Page Down
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT" desc="The label for the 'Scroll Left' item">
- Scroll Left
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT" desc="The label for the 'Scroll Left' item">
- Scroll Right
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLUP" desc="The label for the 'Scroll Up' item">
- Scroll Up
- </message>
- <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN" desc="The label for the 'Scroll Down' item">
- Scroll Down
- </message>
-
- <!-- Edit field context menu item labels. -->
- <message name="IDS_APP_UNDO" desc="The text label of the Undo menu item">
- &amp;Undo
- </message>
- <message name="IDS_APP_CUT" desc="The text label of the Cut menu item">
- Cu&amp;t
- </message>
- <message name="IDS_APP_COPY" desc="The text label of the Copy menu item">
- &amp;Copy
- </message>
- <message name="IDS_APP_PASTE" desc="The text label of the Paste menu item">
- &amp;Paste
- </message>
- <message name="IDS_APP_DELETE" desc="The text label of the Delete menu item">
- &amp;Delete
- </message>
- <message name="IDS_APP_SELECT_ALL" desc="The text label of the Select All menu item">
- Select &amp;all
- </message>
-
- <!-- Generic terms -->
- <message name="IDS_APP_OK" desc="Used for Ok on buttons">
- OK
- </message>
- <message name="IDS_APP_CANCEL" desc="Used for Cancel on buttons">
- Cancel
- </message>
- <message name="IDS_APP_CLOSE" desc="A generic term for Close on buttons and menus.">
- Close
- </message>
-
- <!-- Key names -->
- <message name="IDS_APP_ESC_KEY" desc="Escape key">
- Esc
- </message>
- <message name="IDS_APP_TAB_KEY" desc="Tab key">
- Tab
- </message>
- <message name="IDS_APP_INSERT_KEY" desc="Insert key">
- Ins
- </message>
- <message name="IDS_APP_HOME_KEY" desc="Home key">
- Home
- </message>
- <message name="IDS_APP_DELETE_KEY" desc="Delete key">
- Del
- </message>
- <message name="IDS_APP_END_KEY" desc="End key">
- End
- </message>
- <message name="IDS_APP_PAGEUP_KEY" desc="Page up key">
- PgUp
- </message>
- <message name="IDS_APP_PAGEDOWN_KEY" desc="Page down key">
- PgDwn
- </message>
- <message name="IDS_APP_LEFT_ARROW_KEY" desc="Left arrow key">
- Left Arrow
- </message>
- <message name="IDS_APP_RIGHT_ARROW_KEY" desc="Right arrow key">
- Right Arrow
- </message>
- <message name="IDS_APP_UP_ARROW_KEY" desc="Up arrow key">
- Up Arrow
- </message>
- <message name="IDS_APP_DOWN_ARROW_KEY" desc="Down arrow key">
- Down Arrow
- </message>
- <message name="IDS_APP_ENTER_KEY" desc="Enter key">
- Enter
- </message>
- <message name="IDS_APP_F1_KEY" desc="F1 key">
- F1
- </message>
- <message name="IDS_APP_F11_KEY" desc="F11 key">
- F11
- </message>
- <message name="IDS_APP_BACKSPACE_KEY" desc="Backspace key">
- Backspace
- </message>
- <message name="IDS_APP_COMMA_KEY" desc="Comma key">
- Comma
- </message>
- <message name="IDS_APP_PERIOD_KEY" desc="Period key">
- Period
- </message>
- <message name="IDS_APP_MEDIA_NEXT_TRACK_KEY" desc="Media next track key">
- Media Next Track
- </message>
- <message name="IDS_APP_MEDIA_PLAY_PAUSE_KEY" desc="Media play pause key">
- Media Play/Pause
- </message>
- <message name="IDS_APP_MEDIA_PREV_TRACK_KEY" desc="Media previous track key">
- Media Previous Track
- </message>
- <message name="IDS_APP_MEDIA_STOP_KEY" desc="Media stop key">
- Media Stop
- </message>
-
- <!-- Shortcut Modifiers -->
- <message name="IDS_APP_CONTROL_MODIFIER" desc="Control key shortcut modifier">
- Ctrl+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
- </message>
- <message name="IDS_APP_ALT_MODIFIER" desc="Alt key shortcut modifier">
- Alt+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
- </message>
- <message name="IDS_APP_SHIFT_MODIFIER" desc="Shift key shortcut modifier">
- Shift+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
- </message>
- <message name="IDS_APP_COMMAND_MODIFIER" desc="Command key shortcut modifier">
- Command+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
- </message>
-
- <!-- Byte size units -->
- <message name="IDS_APP_BYTES" desc="Units tag indicating a quantity of bytes">
- <ph name="QUANTITY">$1<ex>42</ex></ph> B
- </message>
- <message name="IDS_APP_KIBIBYTES" desc="Units tag indicating a quantity of kilobytes">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> KB
- </message>
- <message name="IDS_APP_MEBIBYTES" desc="Units tag indicating a quantity of megabytes">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> MB
- </message>
- <message name="IDS_APP_GIBIBYTES" desc="Units tag indicating a quantity of gigabytes">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> GB
- </message>
- <message name="IDS_APP_TEBIBYTES" desc="Units tag indicating a quantity of terabytes">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> TB
- </message>
- <message name="IDS_APP_PEBIBYTES" desc="Units tag indicating a quantity of petabytes">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> PB
- </message>
- <message name="IDS_APP_BYTES_PER_SECOND" desc="Units tag indicating a speed of bytes/second">
- <ph name="QUANTITY">$1<ex>42</ex></ph> B/s
- </message>
- <message name="IDS_APP_KIBIBYTES_PER_SECOND" desc="Units tag indicating a speed of kilobytes/second">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> KB/s
- </message>
- <message name="IDS_APP_MEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of megabytes/second">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> MB/s
- </message>
- <message name="IDS_APP_GIBIBYTES_PER_SECOND" desc="Units tag indicating a speed of gigabytes/second">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> GB/s
- </message>
- <message name="IDS_APP_TEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of terabytes/second">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> TB/s
- </message>
- <message name="IDS_APP_PEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of petabytes/second">
- <ph name="QUANTITY">$1<ex>42.0</ex></ph> PB/s
- </message>
-
- <!-- Message center -->
- <message name="IDS_MESSAGE_CENTER_ACCESSIBLE_NAME" desc="The accessible name for the Notification Center window.">
- Notification Center
- </message>
- <message name="IDS_MESSAGE_CENTER_NOTIFIER_DISABLE" desc="The menu entry for disabling a notifier from a notification.">
- Disable notifications from <ph name="notifier_name">$1<ex>Notification Galore!</ex></ph>
- </message>
- <message name="IDS_MESSAGE_CENTER_FOOTER_TITLE" desc="The label in the footer of the message center">
- Notifications
- </message>
- <message name="IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL" desc="The button label for visiting the appropriate settings page in the footer of the message center.">
- Settings
- </message>
- <message name="IDS_MESSAGE_CENTER_SETTINGS_GO_BACK_BUTTON_TOOLTIP" desc="The tooltip on back button that returns from settings to the notification list.">
- Go back to notifications
- </message>
- <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog.">
- Allow notifications from the following:
- </message>
- <message name="IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER" desc="The label to describe the settings dialog if there is more than one user.">
- Allow notifications from the following for each user:
- </message>
- <message name="IDS_MESSAGE_CENTER_SETTINGS" desc="The menu entry or button for visiting the appropriate settings page.">
- Settings...
- </message>
- <message name="IDS_MESSAGE_CENTER_CLEAR_ALL" desc="The button for clearing all notifications.">
- Clear All
- </message>
- <if expr="not pp_ifdef('use_titlecase')">
- <message name="IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP" desc="The tooltip text for the do not disturb button.">
- Do not disturb
- </message>
- </if>
- <if expr="pp_ifdef('use_titlecase')">
- <message name="IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP" desc="In Title Case: The tooltip text for the do not disturb button.">
- Do Not Disturb
- </message>
- </if>
- <message name="IDS_MESSAGE_CENTER_NO_MESSAGES" desc="The message displayed in the message center when there are no notifications.">
- Nothing to see here, move along.
- </message>
- <message name="IDS_MESSAGE_CENTER_QUIET_MODE" desc="The button label for do not disturb mode.">
- Do not disturb
- </message>
- <message name="IDS_MESSAGE_CENTER_QUIET_MODE_1HOUR" desc="The button label to enter do not disturb mode in one hour.">
- Do not disturb for one hour
- </message>
- <message name="IDS_MESSAGE_CENTER_QUIET_MODE_1DAY" desc="The button label to enter do not disturb mode in one day.">
- Do not disturb for one day
- </message>
- <message name="IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME" desc="The spoken feedback text for the close button in a notification. Usually 'button' is suffixed to this text automatically.">
- Notification close
- </message>
- <message name="IDS_MESSAGE_CENTER_EXPAND_NOTIFICATION_BUTTON_ACCESSIBLE_NAME" desc="The spoken feedback text for the expand button in a notification. Usually 'button' is suffixed to this text automatically.">
- Notification expand
- </message>
- <message name="IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME" desc="The name of screenshot notifier that is a system componet">
- Screenshot
- </message>
- <message name="IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_COPY_SCREENSHOT_TO_CLIPBOARD" desc="The button label for the screenshot notification which copies the screenshot image to clipboard on click.">
- Copy to clipboard
- </message>
- <message name="IDS_MESSAGE_CENTER_MORE_FROM" desc="Indicates how many more notifications came from the given source.">
- <ph name="number_of_notifications">$1<ex>20</ex></ph> more from <ph name="source_of_notifications">$2<ex>GMail</ex></ph>
- </message>
-
- <!-- App list -->
- <message name="IDS_APP_LIST_HELP" desc="The menu entry to show the app list help UI.">
- Help
- </message>
- <message name="IDS_APP_LIST_OPEN_SETTINGS" desc="The menu entry to show the settings UI.">
- Settings
- </message>
- <message name="IDS_APP_LIST_OPEN_FEEDBACK" desc="The menu entry to show the feedback UI.">
- Send feedback
- </message>
- <message name="IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER" desc="The placeholder text for app list folder name.">
- Unnamed Folder
- </message>
- <message name="IDS_APP_LIST_SPEECH_HINT_TEXT" desc="The text label in the speech recognition UI to ask the user to speak the search query">
- Speak now
- </message>
- </messages>
- </release>
-</grit>
diff --git a/chromium/ui/base/strings/ui_strings.gyp b/chromium/ui/base/strings/ui_strings.gyp
deleted file mode 100644
index f8750c209fc..00000000000
--- a/chromium/ui/base/strings/ui_strings.gyp
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- 'grit_base_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui',
- },
- 'targets': [
- {
- 'target_name': 'ui_strings',
- 'type': 'none',
- 'actions': [
- {
- 'action_name': 'ui_strings',
- 'variables': {
- 'grit_grd_file': 'ui_strings.grd',
- 'grit_out_dir': '<(grit_base_out_dir)/ui_strings',
- },
- 'includes': [ '../../../build/grit_action.gypi' ],
- },
- {
- 'action_name': 'app_locale_settings',
- 'variables': {
- 'grit_grd_file': 'app_locale_settings.grd',
- 'grit_out_dir': '<(grit_base_out_dir)/app_locale_settings',
- },
- 'includes': [ '../../../build/grit_action.gypi' ],
- },
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(grit_base_out_dir)/app_locale_settings',
- '<(grit_base_out_dir)/ui_strings',
- ],
- },
- },
- ],
- 'conditions': [
- ['os_posix == 1 and OS != "mac"', {
- 'targets': [{
- 'target_name': 'ui_unittest_strings',
- 'type': 'none',
- 'dependencies': [
- 'ui_strings',
- ],
- 'variables': {
- 'repack_path': '<(DEPTH)/tools/grit/grit/format/repack.py',
- 'conditions': [
- ['OS == "ios"', {
- 'pak_output': '<(PRODUCT_DIR)/ui_unittests_strings/en.lproj/locale.pak',
- }, {
- 'pak_output': '<(PRODUCT_DIR)/ui_unittests_strings/en-US.pak',
- }],
- ],
- },
- 'actions': [
- {
- 'action_name': 'repack_ui_unittest_strings',
- 'variables': {
- 'pak_inputs': [
- '<(grit_base_out_dir)/ui_strings/ui_strings_en-US.pak',
- '<(grit_base_out_dir)/app_locale_settings/app_locale_settings_en-US.pak',
- ],
- },
- 'inputs': [
- '<(repack_path)',
- '<@(pak_inputs)',
- ],
- 'outputs': [
- '<(pak_output)',
- ],
- 'action': ['python', '<(repack_path)', '<@(_outputs)',
- '<@(pak_inputs)'],
- },
- ],
- 'copies': [
- {
- 'destination': '<(PRODUCT_DIR)/ui_unittests_strings',
- 'files': [
- '<(grit_base_out_dir)/ui_resources/ui_resources_100_percent.pak',
- ],
- },
- ],
- }],
- }],
- ],
-}
diff --git a/chromium/ui/base/strings/ui_strings_am.xtb b/chromium/ui/base/strings/ui_strings_am.xtb
deleted file mode 100644
index d7ae9c214fc..00000000000
--- a/chromium/ui/base/strings/ui_strings_am.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="am">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">ጨርስ</translation>
-<translation id="5341849548509163798">ከ<ph name="NUMBER_MANY"/> ሰዓቶች በፊት</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> ሴኮንድ ይቀራል</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> ሴኮንድ ይቀራል</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> ደቂቃ ይቀራል</translation>
-<translation id="1801827354178857021">ነቁጥ</translation>
-<translation id="1190609913194133056">የማሳወቂያ ማዕከል</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> ደቂቃዎች ቀርተዋል</translation>
-<translation id="5613020302032141669">ግራ ቀስት</translation>
-<translation id="4971687151119236543">የሚዲያ ቀዳሚ ትራክ</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ፋይል(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918">ከ<ph name="NUMBER_ZERO"/> ደቂቃ በፊት</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> ሴኮንድ</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ሰዓቶች ይቀራሉ</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> ተጨማሪ ከ<ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">ሰርዝ</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> ባ</translation>
-<translation id="3660179305079774227">የላይ ቀስት</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> ሜባ/ሰ</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ሰዓት</translation>
-<translation id="3990502903496589789">የቀኝ ጠርዝ</translation>
-<translation id="9038489124413477075">ያልተሰየመ አቃፊ</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> ደቂቃ</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ቀናት ይቀራሉ</translation>
-<translation id="932327136139879170">መነሻ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> ደቂቃ ይቀራል</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ቀናት ይቀራሉ</translation>
-<translation id="6390842777729054533">ከ<ph name="NUMBER_ZERO"/> ሴኮንድ በፊት</translation>
-<translation id="3909791450649380159">&amp;ቁረጥ</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> ደቂቃዎች ቀርተዋል</translation>
-<translation id="688711909580084195">ርዕስ-አልባ ድረ-ገጽ</translation>
-<translation id="3353284378027041011">ከ<ph name="NUMBER_FEW"/> ቀናት በፊት</translation>
-<translation id="5076340679995252485">&amp;ለጥፍ</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> ቴባ</translation>
-<translation id="364720409959344976">የሚሰቀል ዓቃፊ ይምረጡ</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">ከ<ph name="NUMBER_TWO"/> ደቂቃ በፊት</translation>
-<translation id="3234408098842461169">ዝቅዝቅ ቀስት</translation>
-<translation id="3087734570205094154">ግርጌ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> ደቂቃ ይቀራል</translation>
-<translation id="1860796786778352021">ማሳወቂያ ዝጋ</translation>
-<translation id="6364916375976753737">ወደ ግራ ሸብልል</translation>
-<translation id="2629089419211541119">ከ<ph name="NUMBER_ONE"/> ሰዓት በፊት</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> ደቂቃዎች</translation>
-<translation id="6982279413068714821">ከ<ph name="NUMBER_DEFAULT"/> ደቂቃ በፊት</translation>
-<translation id="6945221475159498467">ይምረጡ</translation>
-<translation id="6620110761915583480">ፋይል አስቀምጥ</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ሰከንዶች</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ሰዓት</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> ደቂቃ ቀርቷል</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> ደቂቃ</translation>
-<translation id="8210608804940886430">ወደታች አንቀሳቅስ</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ቀናት</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ሰዓቶች ይቀራሉ</translation>
-<translation id="5329858601952122676">&amp;ሠርዝ</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ሴኮንድ</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> ኪባ</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> ደቂቃዎች</translation>
-<translation id="7275974018215686543">ከ<ph name="NUMBER_MANY"/> ሴኮንድ በፊት</translation>
-<translation id="7781829728241885113">ትናንት</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> ደቂቃዎች</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> ደቂቃ ይቀራል</translation>
-<translation id="6659594942844771486">ትር</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> ሜባ</translation>
-<translation id="4988273303304146523">ከ<ph name="NUMBER_DEFAULT"/> ቀን በፊት</translation>
-<translation id="8428213095426709021">ቅንብሮች</translation>
-<translation id="2497284189126895209">ሁሉም ፋይሎች</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> ደቂቃዎች ቀርተዋል</translation>
-<translation id="5110450810124758964">ከ<ph name="NUMBER_ONE"/> ቀን በፊት</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ሴኮንድ</translation>
-<translation id="7814458197256864873">&amp;ቅዳ</translation>
-<translation id="3889424535448813030">ቀኝ ቀስት</translation>
-<translation id="4229495110203539533">ከ<ph name="NUMBER_ONE"/> ሴኮንድ በፊት</translation>
-<translation id="2544782972264605588">ከ<ph name="NUMBER_DEFAULT"/> ሴኮንድ በፊት</translation>
-<translation id="6829324100069873704">ወደ ማሳወቂያዎች ተመለስ።</translation>
-<translation id="6528179044667508675">አትረብሽ</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ሰከንዶች</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> ደቂቃ</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> ሰዓት ይቀራል</translation>
-<translation id="7135556860107312402">ማሳወቂያዎች ከሚከተሉት እንዲመጡ ፍቀድ፦</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ሰዓቶች</translation>
-<translation id="1398853756734560583">አስፋ</translation>
-<translation id="4250229828105606438">ቅጽበታዊ ገጽ እይታ</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ሰዓቶች</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> ደቂቃ ይቀራል</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> ጊባ</translation>
-<translation id="1901303067676059328">&amp;ሁሉንም ምረጥ</translation>
-<translation id="2168039046890040389">ወደላይ አንቀሳቅስ</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> ደቂቃ</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ቀን</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> ደቂቃ</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> ደቂቃ</translation>
-<translation id="8448317557906454022">ከ<ph name="NUMBER_ZERO"/> ሴኮንድ በፊት</translation>
-<translation id="4927753642311223124">እዚህ ምንም የሚታይ ነገር የለም፣ ይቀጥሉ።</translation>
-<translation id="2482878487686419369">ማስታወቂያዎች</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> ቀን</translation>
-<translation id="3183922693828471536">ወደ እዚህ ሸብልል</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ሰዓቶች</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> ኪባ/ሰ</translation>
-<translation id="8394908167088220973">ሚዲያ አጫውት/ለአፍታ አቁም</translation>
-<translation id="2148716181193084225">ዛሬ</translation>
-<translation id="7960078400008666149">ለአንድ ሰዓት አትረብሽ</translation>
-<translation id="4373894838514502496">ከ<ph name="NUMBER_FEW"/> ደቂቃ በፊት</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ቀናት</translation>
-<translation id="2190355936436201913">(ባዶ)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ሰዓት ይቀራል</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ሴኮንድ ይቀራል</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">ወደ ቀኝ ሸብልል</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ሰዓት ይቀራል</translation>
-<translation id="1413622004203049571">ከ<ph name="NOTIFIER_NAME"/> የሚመጡ ማሳወቂያዎችን አሰናክል</translation>
-<translation id="2666092431469916601">ላይ</translation>
-<translation id="8331626408530291785">ወደ ላይ ሸብልል</translation>
-<translation id="7907591526440419938">ፋይል ክፈት</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> ቀን ይቀራል</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">ከ<ph name="NUMBER_DEFAULT"/> ሰዓት በፊት</translation>
-<translation id="815598010540052116">ወደ ታች ሸብልል</translation>
-<translation id="6808150112686056157">ሚዲያ አቁም</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> ደቂቃ ይቀራል</translation>
-<translation id="3157931365184549694">እነበረበት መልስ</translation>
-<translation id="1243314992276662751">ስቀል</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ቀን ይቀራል</translation>
-<translation id="8179976553408161302">አስገባ</translation>
-<translation id="945522503751344254">ግብረ መልስ ላክ</translation>
-<translation id="9170848237812810038">&amp;ቀልብስ</translation>
-<translation id="1285266685456062655">ከ<ph name="NUMBER_FEW"/> ሰዓቶች በፊት</translation>
-<translation id="6918245111648057970">ከሚከተሉት ውስጥ ለእያንዳንዱ ተጠቃሚ ማሳወቂያዎችን ይፍቀዱ፦</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ሴኮንድ</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> ደቂቃዎች ቀርተዋል</translation>
-<translation id="6358975074282722691">ከ<ph name="NUMBER_TWO"/> ሴኮንድ በፊት</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> ፔታ</translation>
-<translation id="2983818520079887040">ቅንብሮች ...</translation>
-<translation id="6845383723252244143">አቃፊ ምረጥ</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ሰከንዶች</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ሴኮንድ</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">ከ<ph name="NUMBER_MANY"/> ቀናት በፊት</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ቀናት</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ሰዓት</translation>
-<translation id="2679312662830811292">ከ<ph name="NUMBER_ONE"/> ደቂቃ በፊት</translation>
-<translation id="8788572795284305350">ከ<ph name="NUMBER_ZERO"/> ሰዓት በፊት</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> ጊባ/ሰ</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ቀን</translation>
-<translation id="9098468523912235228">ከ<ph name="NUMBER_DEFAULT"/> ሴኮንድ በፊት</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> ሴኮንድ ይቀራል</translation>
-<translation id="4570886800634958009">ማሳወቂያ ዘርጋ</translation>
-<translation id="436869212180315161">ተጫን</translation>
-<translation id="4860787810836767172">ከ<ph name="NUMBER_FEW"/> ሴኮንድ በፊት</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> ቴባ/ሰ</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> ደቂቃዎች</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> ደቂቃዎች ቀርተዋል</translation>
-<translation id="6040143037577758943">ዝጋ</translation>
-<translation id="1101671447232096497">ከ<ph name="NUMBER_MANY"/> ደቂቃ በፊት</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> ባ/ሰ</translation>
-<translation id="7649070708921625228">እገዛ</translation>
-<translation id="6699343763173986273">የሚዲያ ቀጣይ ትራክ</translation>
-<translation id="8226233771743600312">ለአንድ ቀን አትረብሽ</translation>
-<translation id="7457942297256758195">ሁሉንም አጽዳ</translation>
-<translation id="822618367988303761">ከ<ph name="NUMBER_TWO"/> ቀናት በፊት</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> ደቂቃ</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ቀን ይቀራል</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> ደቂቃዎች</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ሰዓቶች ይቀራሉ</translation>
-<translation id="8959208747503200525">ከ<ph name="NUMBER_TWO"/> ሰዓቶች በፊት</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ሴኮንድ</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ሴኮንድ</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ሰከንዶች</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ቀን ይቀራል</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> ፔባ/ሰ</translation>
-<translation id="2743387203779672305">ወደ ቅንጥብ ሰሌዳ ገልብጥ</translation>
-<translation id="8371695176452482769">አሁን ይናገሩ</translation>
-<translation id="6965382102122355670">ይሁን</translation>
-<translation id="7850320739366109486">አትረብሽ</translation>
-<translation id="6978839998405419496">ከ<ph name="NUMBER_ZERO"/> ቀን በፊት</translation>
-<translation id="5941711191222866238">አሳንስ</translation>
-<translation id="6394627529324717982">ኮማ</translation>
-<translation id="3036649622769666520">ፋይሎች ክፈት</translation>
-<translation id="8328145009876646418">የግራ ጠርዝ</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ሰከንዶች</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ar.xtb b/chromium/ui/base/strings/ui_strings_ar.xtb
deleted file mode 100644
index e57fa3b1672..00000000000
--- a/chromium/ui/base/strings/ui_strings_ar.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ar">
-<translation id="4820616160060340806">‏المفتاح Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">‏مفتاح Ins</translation>
-<translation id="6135826906199951471">‏مفتاح Del (حذف)</translation>
-<translation id="528468243742722775">‏مفتاح End</translation>
-<translation id="5341849548509163798">قبل <ph name="NUMBER_MANY"/> ساعة</translation>
-<translation id="6310545596129886942">عدد الثواني المتبقية <ph name="NUMBER_FEW"/></translation>
-<translation id="9213479837033539041">عدد الثواني المتبقية: <ph name="NUMBER_MANY"/></translation>
-<translation id="1209866192426315618">عدد الدقائق المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="1801827354178857021">نقطة</translation>
-<translation id="1190609913194133056">مركز الإشعارات</translation>
-<translation id="7470933019269157899">عدد الدقائق المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="5613020302032141669">مفتاح سهم إلى اليسار</translation>
-<translation id="4971687151119236543">المقطع الصوتي السابق للوسائط</translation>
-<translation id="8602707065186045623">ملف <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918">قبل <ph name="NUMBER_ZERO"/> دقيقة</translation>
-<translation id="7121570032414343252">عدد الثواني: <ph name="NUMBER_TWO"/></translation>
-<translation id="7511635910912978956">عدد الساعات المتبقية: <ph name="NUMBER_FEW"/></translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> أكثر من <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">إلغاء</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> بايت</translation>
-<translation id="3660179305079774227">مفتاح سهم إلى أعلى</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> ميغابايات/ثانية</translation>
-<translation id="5608669887400696928">عدد الساعات: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3990502903496589789">الحافة اليسرى</translation>
-<translation id="9038489124413477075">مجلد بدون اسم</translation>
-<translation id="8507996248087185956">عدد الدقائق: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3520476450377425184">عدد الأيام المتبقيّة <ph name="NUMBER_MANY"/></translation>
-<translation id="932327136139879170">الصفحة الرئيسية</translation>
-<translation id="5600907569873192868">عدد الدقائق المتبقية: <ph name="NUMBER_MANY"/></translation>
-<translation id="8666066831007952346">عدد الأيام المتبقية <ph name="NUMBER_TWO"/></translation>
-<translation id="6390842777729054533">عدد الثواني المتبقية: <ph name="NUMBER_ZERO"/></translation>
-<translation id="3909791450649380159">&amp;قص</translation>
-<translation id="2560788951337264832">عدد الدقائق المتبقية: <ph name="NUMBER_ZERO"/></translation>
-<translation id="688711909580084195">صفحة ويب بدون عنوان</translation>
-<translation id="3353284378027041011">قبل <ph name="NUMBER_FEW"/> يوم</translation>
-<translation id="5076340679995252485">ل&amp;صق</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> تيرابايت</translation>
-<translation id="364720409959344976">حدد مجلدًا للتحميل</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">قبل <ph name="NUMBER_TWO"/> دقيقة</translation>
-<translation id="3234408098842461169">مفتاح سهم إلى أسفل</translation>
-<translation id="3087734570205094154">أسفل</translation>
-<translation id="5935630983280450497">عدد الدقائق المتبقية: <ph name="NUMBER_ONE"/></translation>
-<translation id="1860796786778352021">إغلاق الإشعار</translation>
-<translation id="6364916375976753737">التمرير إلى اليمين</translation>
-<translation id="2629089419211541119">قبل <ph name="NUMBER_ONE"/> ساعة</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> دقيقة</translation>
-<translation id="6982279413068714821">قبل <ph name="NUMBER_DEFAULT"/> دقيقة</translation>
-<translation id="6945221475159498467">تحديد</translation>
-<translation id="6620110761915583480">حفظ الملف</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> بلا ثوانٍ</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ساعة</translation>
-<translation id="7836361698254323868">عدد الدقائق المتبقية: <ph name="NUMBER_ONE"/></translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> دقيقة</translation>
-<translation id="8210608804940886430">صفحة إلى أسفل</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> يومًا</translation>
-<translation id="7163503212501929773">عدد الساعات المتبقية: <ph name="NUMBER_MANY"/></translation>
-<translation id="5329858601952122676">&amp;حذف</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ثانية</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> كيلوبايت</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> دقيقة</translation>
-<translation id="7275974018215686543">قبل <ph name="NUMBER_MANY"/> ثانية</translation>
-<translation id="7781829728241885113">أمس</translation>
-<translation id="3424538384153559412">دقيقتان (<ph name="NUMBER_TWO"/>)</translation>
-<translation id="50960180632766478">عدد الدقائق المتبقية: <ph name="NUMBER_FEW"/></translation>
-<translation id="6659594942844771486">علامة تبويب</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> ميغابايت</translation>
-<translation id="4988273303304146523">قبل <ph name="NUMBER_DEFAULT"/> يوم</translation>
-<translation id="8428213095426709021">الإعدادات</translation>
-<translation id="2497284189126895209">الملفّات كلّها</translation>
-<translation id="7487278341251176613">عدد الدقائق المتبقية: <ph name="NUMBER_TWO"/></translation>
-<translation id="5110450810124758964">قبل <ph name="NUMBER_ONE"/> يوم</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ثانية</translation>
-<translation id="7814458197256864873">&amp;نسخ</translation>
-<translation id="3889424535448813030">مفتاح سهم إلى اليمين</translation>
-<translation id="4229495110203539533">قبل <ph name="NUMBER_ONE"/> ثانية</translation>
-<translation id="2544782972264605588">عدد الثواني المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6829324100069873704">الرجوع إلى الإشعارات</translation>
-<translation id="6528179044667508675">الرجاء عدم الإزعاج</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ثانية</translation>
-<translation id="290555789621781773">عدد الدقائق: <ph name="NUMBER_TWO"/></translation>
-<translation id="5149131957118398098">متبقٍ <ph name="NUMBER_ZERO"/> ساعة</translation>
-<translation id="7135556860107312402">السماح بالإشعارات من الجهات التالية:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ساعات</translation>
-<translation id="1398853756734560583">تكبير</translation>
-<translation id="4250229828105606438">لقطة شاشة</translation>
-<translation id="6690744523875189208">عدد الساعات: <ph name="NUMBER_TWO"/></translation>
-<translation id="5260878308685146029">عدد الدقائق المتبقية: <ph name="NUMBER_TWO"/></translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> غيغابايت</translation>
-<translation id="1901303067676059328">تح&amp;ديد الكلّ</translation>
-<translation id="2168039046890040389">صفحة إلى أعلى</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> دقيقة</translation>
-<translation id="9107059250669762581">عدد الأيام <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> دقيقة</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> دقيقة واحدة</translation>
-<translation id="8448317557906454022">قبل <ph name="NUMBER_ZERO"/> ثانية</translation>
-<translation id="4927753642311223124">ليس هناك شيء تراه هنا، انتقل إلى مكان آخر.</translation>
-<translation id="2482878487686419369">الاشعارات</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> يوم</translation>
-<translation id="3183922693828471536">التمرير إلى هنا</translation>
-<translation id="4552416320897244156">‏مفتاح PgDwn (صفحة إلى أسفل)</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ساعة</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> كيلوبايت/ثانية</translation>
-<translation id="8394908167088220973">تشغيل/إيقاف الوسائط</translation>
-<translation id="2148716181193084225">اليوم</translation>
-<translation id="7960078400008666149">الرجاء عدم الإزعاج لمدة ساعة واحدة</translation>
-<translation id="4373894838514502496">قبل <ph name="NUMBER_FEW"/> دقيقة</translation>
-<translation id="4115153316875436289">عدد الأيام: <ph name="NUMBER_TWO"/></translation>
-<translation id="2190355936436201913">(فارغ)</translation>
-<translation id="1164369517022005061">عدد الساعات المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="152482086482215392">عدد الثواني المتبقية: <ph name="NUMBER_ONE"/></translation>
-<translation id="8447116497070723931">‏مفتاح PgUp (صفحة إلى أعلى)</translation>
-<translation id="4588090240171750605">التمرير إلى اليسار</translation>
-<translation id="7414887922320653780">عدد الساعات المتبقية: <ph name="NUMBER_ONE"/></translation>
-<translation id="1413622004203049571">تعطيل الإشعارات من <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">أعلى</translation>
-<translation id="8331626408530291785">التمرير إلى أعلى</translation>
-<translation id="7907591526440419938">فتح ملف</translation>
-<translation id="2864069933652346933">متبقٍ <ph name="NUMBER_ZERO"/> يوم</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">قبل <ph name="NUMBER_DEFAULT"/> ساعة</translation>
-<translation id="815598010540052116">التمرير إلى أسفل</translation>
-<translation id="6808150112686056157">إيقاف الوسائط</translation>
-<translation id="1308727876662951186">متبقٍ <ph name="NUMBER_ZERO"/> دقيقة</translation>
-<translation id="3157931365184549694">استعادة</translation>
-<translation id="1243314992276662751">تحميل</translation>
-<translation id="50030952220075532">عدد الأيام المتبقية <ph name="NUMBER_ONE"/></translation>
-<translation id="8179976553408161302">تفضل</translation>
-<translation id="945522503751344254">إرسال تعليقات</translation>
-<translation id="9170848237812810038">&amp;إلغاء</translation>
-<translation id="1285266685456062655">قبل <ph name="NUMBER_FEW"/> ساعة</translation>
-<translation id="6918245111648057970">السماح بإشعارات مما يلي لكل مستخدم:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ثانية واحدة</translation>
-<translation id="3994835489895548312">عدد الدقائق المتبقية: <ph name="NUMBER_MANY"/></translation>
-<translation id="6358975074282722691">قبل <ph name="NUMBER_TWO"/> ثانية</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> بيتابايت</translation>
-<translation id="2983818520079887040">الإعدادات...</translation>
-<translation id="6845383723252244143">تحديد مجلد</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ثوانٍ</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ثوانٍ</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">قبل <ph name="NUMBER_MANY"/> يوم</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> أيام</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ساعة</translation>
-<translation id="2679312662830811292">قبل <ph name="NUMBER_ONE"/> دقيقة</translation>
-<translation id="8788572795284305350">قبل <ph name="NUMBER_ZERO"/> ساعة</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> غيغابايت/ثانية</translation>
-<translation id="6644971472240498405">عدد الأيام <ph name="NUMBER_ONE"/></translation>
-<translation id="9098468523912235228">قبل <ph name="NUMBER_DEFAULT"/> ثانية</translation>
-<translation id="494645311413743213">عدد الثواني المتبقية: <ph name="NUMBER_TWO"/></translation>
-<translation id="4570886800634958009">توسيع الإشعار</translation>
-<translation id="436869212180315161">اضغط</translation>
-<translation id="4860787810836767172">قبل <ph name="NUMBER_FEW"/> ثانية</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> تيرابايت/ثانية</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> بلا دقائق</translation>
-<translation id="1858722859751911017">عدد الدقائق المتبقية: <ph name="NUMBER_FEW"/></translation>
-<translation id="6040143037577758943">إغلاق</translation>
-<translation id="1101671447232096497">قبل <ph name="NUMBER_MANY"/> دقيقة</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> بايت/ثانية</translation>
-<translation id="7649070708921625228">مساعدة</translation>
-<translation id="6699343763173986273">المقطع الصوتي التالي للوسائط</translation>
-<translation id="8226233771743600312">الرجاء عدم الإزعاج لمدة يوم واحد</translation>
-<translation id="7457942297256758195">محو الكل</translation>
-<translation id="822618367988303761">قبل <ph name="NUMBER_TWO"/> يوم</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> دقيقة</translation>
-<translation id="1963692530539281474">عدد الأيام المتبقية <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> دقائق</translation>
-<translation id="5906719743126878045">عدد الساعات المتبقية: <ph name="NUMBER_TWO"/></translation>
-<translation id="8959208747503200525">قبل <ph name="NUMBER_TWO"/> ساعة</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> من الثواني</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ثانية</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ثانية</translation>
-<translation id="3759876923365568382">عدد الأيام المتبقية <ph name="NUMBER_FEW"/></translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> بيتابايت/ثانية</translation>
-<translation id="2743387203779672305">نسخ إلى الحافظة</translation>
-<translation id="8371695176452482769">تحدث الآن</translation>
-<translation id="6965382102122355670">موافق</translation>
-<translation id="7850320739366109486">الرجاء عدم الإزعاج</translation>
-<translation id="6978839998405419496">قبل <ph name="NUMBER_ZERO"/> يوم</translation>
-<translation id="5941711191222866238">تصغير</translation>
-<translation id="6394627529324717982">فاصلة</translation>
-<translation id="3036649622769666520">فتح الملفات</translation>
-<translation id="8328145009876646418">الحافة اليمنى</translation>
-<translation id="7372005818821648611">ثانيتان (<ph name="NUMBER_TWO"/>)</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_bg.xtb b/chromium/ui/base/strings/ui_strings_bg.xtb
deleted file mode 100644
index d1195c4d21c..00000000000
--- a/chromium/ui/base/strings/ui_strings_bg.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="bg">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798">преди <ph name="NUMBER_MANY"/> часа</translation>
-<translation id="6310545596129886942">Остават <ph name="NUMBER_FEW"/> сек</translation>
-<translation id="9213479837033539041">Остават <ph name="NUMBER_MANY"/> сек</translation>
-<translation id="1209866192426315618">Остават <ph name="NUMBER_DEFAULT"/> минути</translation>
-<translation id="1801827354178857021">Точка</translation>
-<translation id="1190609913194133056">Център за известия</translation>
-<translation id="7470933019269157899">Остават <ph name="NUMBER_DEFAULT"/> минути</translation>
-<translation id="5613020302032141669">Стрелка наляво</translation>
-<translation id="4971687151119236543">Мултимедия, предишният запис</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> файл (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек</translation>
-<translation id="7511635910912978956">Остават <ph name="NUMBER_FEW"/> часа</translation>
-<translation id="8717309436826820190">Още <ph name="NUMBER_OF_NOTIFICATIONS"/> от <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Отказ</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> Б</translation>
-<translation id="3660179305079774227">Стрелка нагоре</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> МБ/сек</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> часа</translation>
-<translation id="3990502903496589789">Десн край</translation>
-<translation id="9038489124413477075">Папка без име</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин</translation>
-<translation id="3520476450377425184">Остават <ph name="NUMBER_MANY"/> дни</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">Остават <ph name="NUMBER_MANY"/> мин</translation>
-<translation id="8666066831007952346">Остават <ph name="NUMBER_TWO"/> дни</translation>
-<translation id="6390842777729054533">Остават <ph name="NUMBER_ZERO"/> сек</translation>
-<translation id="3909791450649380159">Изрязва&amp;не</translation>
-<translation id="2560788951337264832">Остават <ph name="NUMBER_ZERO"/> минути</translation>
-<translation id="688711909580084195">Неозаглавена уеб страница</translation>
-<translation id="3353284378027041011">преди <ph name="NUMBER_FEW"/> дни</translation>
-<translation id="5076340679995252485">&amp;Поставяне</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> ТБ</translation>
-<translation id="364720409959344976">Избиране на папка за качване</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">преди <ph name="NUMBER_TWO"/> мин</translation>
-<translation id="3234408098842461169">Стрелка надолу</translation>
-<translation id="3087734570205094154">Най-долу</translation>
-<translation id="5935630983280450497">Остава <ph name="NUMBER_ONE"/> мин</translation>
-<translation id="1860796786778352021">Затваряне на известието</translation>
-<translation id="6364916375976753737">Превъртане наляво</translation>
-<translation id="2629089419211541119">преди <ph name="NUMBER_ONE"/> час/а</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> минути</translation>
-<translation id="6982279413068714821">преди <ph name="NUMBER_DEFAULT"/> мин</translation>
-<translation id="6945221475159498467">Изберете</translation>
-<translation id="6620110761915583480">Запазване на файл</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> секунди</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Остава <ph name="NUMBER_ONE"/> минута</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин</translation>
-<translation id="8210608804940886430">Страница надолу</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> дни</translation>
-<translation id="7163503212501929773">Остават <ph name="NUMBER_MANY"/> часа</translation>
-<translation id="5329858601952122676">&amp;Изтриване</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KБ</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> минути</translation>
-<translation id="7275974018215686543">преди <ph name="NUMBER_MANY"/> сек</translation>
-<translation id="7781829728241885113">Вчера</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> минути</translation>
-<translation id="50960180632766478">Остават <ph name="NUMBER_FEW"/> мин</translation>
-<translation id="6659594942844771486">Раздел</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> МБ</translation>
-<translation id="4988273303304146523">преди <ph name="NUMBER_DEFAULT"/> дни</translation>
-<translation id="8428213095426709021">Настройки</translation>
-<translation id="2497284189126895209">Всички файлове</translation>
-<translation id="7487278341251176613">Остават <ph name="NUMBER_TWO"/> минути</translation>
-<translation id="5110450810124758964">преди <ph name="NUMBER_ONE"/> ден/дни</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек</translation>
-<translation id="7814458197256864873">&amp;Копиране</translation>
-<translation id="3889424535448813030">Стрелка надясно</translation>
-<translation id="4229495110203539533">преди <ph name="NUMBER_ONE"/> сек</translation>
-<translation id="2544782972264605588">Остават <ph name="NUMBER_DEFAULT"/> сек</translation>
-<translation id="6829324100069873704">Назад към известията</translation>
-<translation id="6528179044667508675">Не безпокойте</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> секунди</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Разрешаване на известията от следните неща:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> часа</translation>
-<translation id="1398853756734560583">Увеличаване</translation>
-<translation id="4250229828105606438">Eкранна снимка</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> часа</translation>
-<translation id="5260878308685146029">Остават <ph name="NUMBER_TWO"/> мин</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> ГБ</translation>
-<translation id="1901303067676059328">&amp;Избиране на всички</translation>
-<translation id="2168039046890040389">Страница нагоре</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> дни</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> минута</translation>
-<translation id="8448317557906454022">преди <ph name="NUMBER_ZERO"/> сек</translation>
-<translation id="4927753642311223124">Тук няма нищо, продължете нататък.</translation>
-<translation id="2482878487686419369">Известия</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Превъртане до тук</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> часа</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> КБ/сек</translation>
-<translation id="8394908167088220973">Мултимедия, пускане/пауза</translation>
-<translation id="2148716181193084225">Днес</translation>
-<translation id="7960078400008666149">Не безпокойте за един час</translation>
-<translation id="4373894838514502496">преди <ph name="NUMBER_FEW"/> мин</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дни</translation>
-<translation id="2190355936436201913">(празно)</translation>
-<translation id="1164369517022005061">Остават <ph name="NUMBER_DEFAULT"/> часа</translation>
-<translation id="152482086482215392">Остава <ph name="NUMBER_ONE"/> сек</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Превъртане надясно</translation>
-<translation id="7414887922320653780">Остава <ph name="NUMBER_ONE"/> час</translation>
-<translation id="1413622004203049571">Деактивиране на известията от <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Най-горе</translation>
-<translation id="8331626408530291785">Превъртане нагоре</translation>
-<translation id="7907591526440419938">Отваряне на файл</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">преди <ph name="NUMBER_DEFAULT"/> часа</translation>
-<translation id="815598010540052116">Превъртане надолу</translation>
-<translation id="6808150112686056157">Мултимедия, стоп</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Възстановяване</translation>
-<translation id="1243314992276662751">Качване</translation>
-<translation id="50030952220075532">Остава <ph name="NUMBER_ONE"/> ден</translation>
-<translation id="8179976553408161302">Влизане</translation>
-<translation id="945522503751344254">Изпращане на отзиви</translation>
-<translation id="9170848237812810038">&amp;Отмяна</translation>
-<translation id="1285266685456062655">преди <ph name="NUMBER_FEW"/> часа</translation>
-<translation id="6918245111648057970">Разрешаване на известията от следните неща за всеки потребител:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
-<translation id="3994835489895548312">Остават <ph name="NUMBER_MANY"/> минути</translation>
-<translation id="6358975074282722691">преди <ph name="NUMBER_TWO"/> сек</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> ПБ</translation>
-<translation id="2983818520079887040">Настройки...</translation>
-<translation id="6845383723252244143">Избор на папка</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунди</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">преди <ph name="NUMBER_MANY"/> дни</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> дни</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> час</translation>
-<translation id="2679312662830811292">преди <ph name="NUMBER_ONE"/> мин</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> ГБ/сек</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ден</translation>
-<translation id="9098468523912235228">преди <ph name="NUMBER_DEFAULT"/> сек</translation>
-<translation id="494645311413743213">Остават <ph name="NUMBER_TWO"/> сек</translation>
-<translation id="4570886800634958009">Разгъване на известието</translation>
-<translation id="436869212180315161">Натиснете</translation>
-<translation id="4860787810836767172">преди <ph name="NUMBER_FEW"/> сек</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> ТБ/сек</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> минути</translation>
-<translation id="1858722859751911017">Остават <ph name="NUMBER_FEW"/> минути</translation>
-<translation id="6040143037577758943">Затваряне</translation>
-<translation id="1101671447232096497">преди <ph name="NUMBER_MANY"/> мин</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> Б/сек</translation>
-<translation id="7649070708921625228">Помощ</translation>
-<translation id="6699343763173986273">Мултимедия, следващият запис</translation>
-<translation id="8226233771743600312">Не безпокойте за един ден</translation>
-<translation id="7457942297256758195">Изчистване на всички</translation>
-<translation id="822618367988303761">преди <ph name="NUMBER_TWO"/> дни</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин</translation>
-<translation id="1963692530539281474">Остават <ph name="NUMBER_DEFAULT"/> дни</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> минути</translation>
-<translation id="5906719743126878045">Остават <ph name="NUMBER_TWO"/> часа</translation>
-<translation id="8959208747503200525">преди <ph name="NUMBER_TWO"/> часа</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> секунди</translation>
-<translation id="3759876923365568382">Остават <ph name="NUMBER_FEW"/> дни</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> ПБ/сек</translation>
-<translation id="2743387203779672305">Копиране в буферната памет</translation>
-<translation id="8371695176452482769">Говорете сега</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Не безпокойте</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Намаляване</translation>
-<translation id="6394627529324717982">Запетая</translation>
-<translation id="3036649622769666520">Отваряне на файлове</translation>
-<translation id="8328145009876646418">Ляв край</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> секунди</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_bn.xtb b/chromium/ui/base/strings/ui_strings_bn.xtb
deleted file mode 100644
index 4930bff97b6..00000000000
--- a/chromium/ui/base/strings/ui_strings_bn.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="bn">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> সেকেন্ড বাকি</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> সেকেন্ড বাকি</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> মিনিট বাকি</translation>
-<translation id="1801827354178857021">সময়কাল</translation>
-<translation id="1190609913194133056">বিজ্ঞপ্তি কেন্দ্র</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> মিনিট বাকি</translation>
-<translation id="5613020302032141669">Left Arrow</translation>
-<translation id="4971687151119236543">মিডিয়া পূর্ববর্তী ট্র্যাক</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ফাইল (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> সেকেন্ড</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ঘন্টা বাকি</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> থেকে আরো <ph name="NUMBER_OF_NOTIFICATIONS"/>টি</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">বাতিল</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Up Arrow</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ঘন্টা</translation>
-<translation id="3990502903496589789">ডান প্রান্ত</translation>
-<translation id="9038489124413477075">নামবিহীন ফোল্ডার</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> মিনিট</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> দিন বাকি</translation>
-<translation id="932327136139879170">হোম</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> মিনিট বাকি</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> দিন বাকি</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> সেকেন্ড বাকি</translation>
-<translation id="3909791450649380159">ছেদ&amp;ন</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> মিনিট বাকি</translation>
-<translation id="688711909580084195">শিরোনামহীন ওয়েবপৃষ্ঠা</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;প্রতিলেপন</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">আপলোড করার জন্য ফোল্ডার নির্বাচন করুন</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Down Arrow</translation>
-<translation id="3087734570205094154">নীচে</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> মিনিট বাকি</translation>
-<translation id="1860796786778352021">বিজ্ঞপ্তি বন্ধ করা হয়েছে</translation>
-<translation id="6364916375976753737">বাম দিকে স্ক্রোল করুন</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> মিনিট</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> মিনিট আগে</translation>
-<translation id="6945221475159498467">নির্বাচন</translation>
-<translation id="6620110761915583480">ফাইল সংরক্ষণ করুন</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> সেকেন্ড</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> মিনিট বাকি</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> মিনিট</translation>
-<translation id="8210608804940886430">পৃষ্ঠা উপরে</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> দিন</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ঘন্টা বাকি</translation>
-<translation id="5329858601952122676">&amp;মুছুন</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> সেকেন্ড</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> মিনিট</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">গতকাল</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> মিনিট</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> মিনিট বাকি</translation>
-<translation id="6659594942844771486">ট্যাব</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> দিন আগে</translation>
-<translation id="8428213095426709021">সেটিংস</translation>
-<translation id="2497284189126895209">সকল ফাইল</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> মিনিট বাকি</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> সেকেন্ড</translation>
-<translation id="7814458197256864873">&amp;copy</translation>
-<translation id="3889424535448813030">Right Arrow</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> সেকেন্ড বাকি</translation>
-<translation id="6829324100069873704">বিজ্ঞপ্তিগুলিতে ফিরে যান</translation>
-<translation id="6528179044667508675">বিরক্ত করবেন না</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> সেকেন্ড</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> মিনিট</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">নিম্নলিখিত থেকে বিজ্ঞপ্তিগুলি মঞ্জুরি করুন:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ঘন্টা</translation>
-<translation id="1398853756734560583">বড় করুন</translation>
-<translation id="4250229828105606438">স্ক্রীনশট</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ঘন্টা</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> মিনিট বাকি</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;সকল নির্বাচন করুন</translation>
-<translation id="2168039046890040389">পৃষ্ঠা নীচে</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> দিন</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> মিনিট</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> মিনিট</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">এখানে দেখার কিছু নেই , এগিয়ে যান৷</translation>
-<translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">এখান পর্যন্ত স্ক্রোল করুন</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ঘন্টা</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">মিডিয়া প্লে করুন/বিরতি</translation>
-<translation id="2148716181193084225">আজ</translation>
-<translation id="7960078400008666149">এক ঘন্টার জন্য বিরক্ত করবেন না</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> দিন</translation>
-<translation id="2190355936436201913">(খালি)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ঘন্টা বাকি</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> সেকেন্ড বাকি</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">ডান দিকে স্ক্রোল করুন</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ঘন্টা বাকি</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> এর থেকে বিজ্ঞপ্তিগুলি অক্ষম করুন</translation>
-<translation id="2666092431469916601">শীর্ষ</translation>
-<translation id="8331626408530291785">উপরে স্ক্রোল করুন</translation>
-<translation id="7907591526440419938">খোলা ফাইল</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ঘন্টা আগে</translation>
-<translation id="815598010540052116">নীচে স্ক্রোল করুন</translation>
-<translation id="6808150112686056157">মিডিয়া থামান</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">পুনরুদ্ধার করুন</translation>
-<translation id="1243314992276662751">আপলোড</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> দিন বাকি</translation>
-<translation id="8179976553408161302">প্রবেশ করুন</translation>
-<translation id="945522503751344254">প্রতিক্রিয়া প্রেরণ করুন</translation>
-<translation id="9170848237812810038">&amp;পূর্বাবস্থায় ফিরুন</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">প্রত্যেক ব্যবহারকারীর জন্য নিম্নলিখিত থেকে বিজ্ঞপ্তি মঞ্জুর করুন:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> সেকেন্ড</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> মিনিট বাকি</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">সেটিংস...</translation>
-<translation id="6845383723252244143">ফোল্ডার নির্বাচন করুন</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> সেকেন্ড</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> সেকেন্ড</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> দিন</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ঘন্টা</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> দিন</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> সেকেন্ড আগে</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> সেকেন্ড বাকি</translation>
-<translation id="4570886800634958009">বিজ্ঞপ্তি প্রসারিত করুন</translation>
-<translation id="436869212180315161">টিপুন</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> মিনিট</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> মিনিট বাকি</translation>
-<translation id="6040143037577758943">বন্ধ</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">সহায়তা</translation>
-<translation id="6699343763173986273">মিডিয়া পরবর্তী ট্র্যাক</translation>
-<translation id="8226233771743600312">এক দিনের জন্য বিরক্ত করবেন না</translation>
-<translation id="7457942297256758195">সমস্ত সাফ করুন</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> মিনিট</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> দিন বাকি</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> মিনিট</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ঘন্টা বাকি</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> সেকেন্ড</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> সেকেন্ড</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> সেকেন্ড</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> দিন বাকি</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">ক্লিপবোর্ডে অনুলিপি করুন</translation>
-<translation id="8371695176452482769">এখনই বলুন</translation>
-<translation id="6965382102122355670">ওকে</translation>
-<translation id="7850320739366109486">বিরক্ত করবেন না</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">ছোট করুন</translation>
-<translation id="6394627529324717982">কমা</translation>
-<translation id="3036649622769666520">খোলা ফাইল</translation>
-<translation id="8328145009876646418">বাম প্রান্ত</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> সেকেন্ড</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ca.xtb b/chromium/ui/base/strings/ui_strings_ca.xtb
deleted file mode 100644
index ca32ba15575..00000000000
--- a/chromium/ui/base/strings/ui_strings_ca.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ca">
-<translation id="4820616160060340806">Ordre+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Supr</translation>
-<translation id="528468243742722775">Fi</translation>
-<translation id="5341849548509163798">Fa <ph name="NUMBER_MANY"/> hores</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> segons restants</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> segons restants</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuts restants</translation>
-<translation id="1801827354178857021">Punt</translation>
-<translation id="1190609913194133056">Centre de notificacions</translation>
-<translation id="7470933019269157899">Queden <ph name="NUMBER_DEFAULT"/> minuts</translation>
-<translation id="5613020302032141669">Fletxa esquerra</translation>
-<translation id="4971687151119236543">Fitxer multimèdia: pista anterior</translation>
-<translation id="8602707065186045623">Fitxer <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> segons</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hores restants</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> més de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancel·la</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Fletxa amunt</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hores</translation>
-<translation id="3990502903496589789">Extrem dret</translation>
-<translation id="9038489124413477075">Carpeta sense nom</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuts</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dies restants</translation>
-<translation id="932327136139879170">Inici</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuts restants</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dies restants</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> segons restants</translation>
-<translation id="3909791450649380159">Re&amp;talla</translation>
-<translation id="2560788951337264832">Queden <ph name="NUMBER_ZERO"/> minuts</translation>
-<translation id="688711909580084195">Pàgina web sense títol</translation>
-<translation id="3353284378027041011">Fa <ph name="NUMBER_FEW"/> dies</translation>
-<translation id="5076340679995252485">Engan&amp;xa</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Selecció d'una carpeta per penjar</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Fa <ph name="NUMBER_TWO"/> minuts</translation>
-<translation id="3234408098842461169">Fletxa avall</translation>
-<translation id="3087734570205094154">Part inferior</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut restant</translation>
-<translation id="1860796786778352021">Tanca la notificació</translation>
-<translation id="6364916375976753737">Desplaçament a l'esquerra</translation>
-<translation id="2629089419211541119">Fa <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuts</translation>
-<translation id="6982279413068714821">Fa <ph name="NUMBER_DEFAULT"/> minuts</translation>
-<translation id="6945221475159498467">Selecciona</translation>
-<translation id="6620110761915583480">Desa el fitxer</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segons</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Queda <ph name="NUMBER_ONE"/> minut</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8210608804940886430">Av Pàg</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dies</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hores restants</translation>
-<translation id="5329858601952122676">&amp;Suprimeix</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> segons</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minuts</translation>
-<translation id="7275974018215686543">Fa <ph name="NUMBER_MANY"/> segons</translation>
-<translation id="7781829728241885113">Ahir</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuts</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuts restants</translation>
-<translation id="6659594942844771486">Pestanya</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Fa <ph name="NUMBER_DEFAULT"/> dies</translation>
-<translation id="8428213095426709021">Configuració</translation>
-<translation id="2497284189126895209">Tots els fitxers</translation>
-<translation id="7487278341251176613">Queden <ph name="NUMBER_TWO"/> minuts</translation>
-<translation id="5110450810124758964">Fa <ph name="NUMBER_ONE"/> dia</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segon</translation>
-<translation id="7814458197256864873">&amp;Copia</translation>
-<translation id="3889424535448813030">Fletxa dreta</translation>
-<translation id="4229495110203539533">Fa <ph name="NUMBER_ONE"/> segon</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> segons restants</translation>
-<translation id="6829324100069873704">Torna a les notificacions</translation>
-<translation id="6528179044667508675">No molesteu</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segons</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuts</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Permet notificacions de les fonts següents:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hores</translation>
-<translation id="1398853756734560583">Maximitza</translation>
-<translation id="4250229828105606438">Captura de pantalla</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hores</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuts restants</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Selecciona-ho &amp;tot</translation>
-<translation id="2168039046890040389">Re Pàg</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dies</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuts</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8448317557906454022">Fa <ph name="NUMBER_ZERO"/> segons</translation>
-<translation id="4927753642311223124">No hi ha cap notificació, podeu continuar.</translation>
-<translation id="2482878487686419369">Notificacions</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Desplaçament fins aquí</translation>
-<translation id="4552416320897244156">Av Pàg</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hores</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Fitxer multimèdia: reprodueix/posa en pausa</translation>
-<translation id="2148716181193084225">Avui</translation>
-<translation id="7960078400008666149">No molesteu durant una hora</translation>
-<translation id="4373894838514502496">Fa <ph name="NUMBER_FEW"/> minuts</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dies</translation>
-<translation id="2190355936436201913">(buit)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hores restants</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> segon restant</translation>
-<translation id="8447116497070723931">Re Pàg</translation>
-<translation id="4588090240171750605">Desplaçament a la dreta</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hores restants</translation>
-<translation id="1413622004203049571">Desactiva les notificacions de <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Superior</translation>
-<translation id="8331626408530291785">Desplaçament amunt</translation>
-<translation id="7907591526440419938">Obre un fitxer</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Fa <ph name="NUMBER_DEFAULT"/> hores</translation>
-<translation id="815598010540052116">Desplaçament avall</translation>
-<translation id="6808150112686056157">Fitxer multimèdia: atura</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaura</translation>
-<translation id="1243314992276662751">Penja</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restant</translation>
-<translation id="8179976553408161302">Intro</translation>
-<translation id="945522503751344254">Envia comentaris</translation>
-<translation id="9170848237812810038">&amp;Desfés</translation>
-<translation id="1285266685456062655">Fa <ph name="NUMBER_FEW"/> hores</translation>
-<translation id="6918245111648057970">Permet les notificacions de les opcions següents per a cada usuari:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segon</translation>
-<translation id="3994835489895548312">Queden <ph name="NUMBER_MANY"/> minuts</translation>
-<translation id="6358975074282722691">Fa <ph name="NUMBER_TWO"/> segons</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Configuració...</translation>
-<translation id="6845383723252244143">Selecció d'una carpeta</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segons</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> segons</translation>
-<translation id="5583640892426849032">Retrocés</translation>
-<translation id="5263972071113911534">Fa <ph name="NUMBER_MANY"/> dies</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dies</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2679312662830811292">Fa <ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
-<translation id="9098468523912235228">Fa <ph name="NUMBER_DEFAULT"/> segons</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> segons restants</translation>
-<translation id="4570886800634958009">Amplia la notificació</translation>
-<translation id="436869212180315161">Prem</translation>
-<translation id="4860787810836767172">Fa <ph name="NUMBER_FEW"/> segons</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuts</translation>
-<translation id="1858722859751911017">Queden <ph name="NUMBER_FEW"/> minuts</translation>
-<translation id="6040143037577758943">Tanca</translation>
-<translation id="1101671447232096497">Fa <ph name="NUMBER_MANY"/> minuts</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Ajuda</translation>
-<translation id="6699343763173986273">Fitxer multimèdia: pista següent</translation>
-<translation id="8226233771743600312">No molesteu durant un dia</translation>
-<translation id="7457942297256758195">Esborra-ho tot</translation>
-<translation id="822618367988303761">Fa <ph name="NUMBER_TWO"/> dies</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuts</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dies restants</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuts</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hores restants</translation>
-<translation id="8959208747503200525">Fa <ph name="NUMBER_TWO"/> hores</translation>
-<translation id="8400147561352026160">Maj+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> segons</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> segons</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segons</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dies restants</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copia al porta-retalls</translation>
-<translation id="8371695176452482769">Parleu ara</translation>
-<translation id="6965382102122355670">D'acord</translation>
-<translation id="7850320739366109486">No molesteu</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimitza</translation>
-<translation id="6394627529324717982">Coma</translation>
-<translation id="3036649622769666520">Obre fitxers</translation>
-<translation id="8328145009876646418">Extrem esquerre</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segons</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_cs.xtb b/chromium/ui/base/strings/ui_strings_cs.xtb
deleted file mode 100644
index 9ed94f89cb7..00000000000
--- a/chromium/ui/base/strings/ui_strings_cs.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="cs">
-<translation id="4820616160060340806">Příkaz + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Klávesa Ins</translation>
-<translation id="6135826906199951471">Klávesa Del</translation>
-<translation id="528468243742722775">Klávesa End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942">Zbývá: <ph name="NUMBER_FEW"/> s</translation>
-<translation id="9213479837033539041">Zbývá: <ph name="NUMBER_MANY"/> s</translation>
-<translation id="1209866192426315618">Zbývá: <ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="1801827354178857021">Tečka</translation>
-<translation id="1190609913194133056">Centrum oznámení</translation>
-<translation id="7470933019269157899">Zbývá <ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="5613020302032141669">Klávesa šipka vlevo</translation>
-<translation id="4971687151119236543">Média – předchozí skladba</translation>
-<translation id="8602707065186045623">Soubor <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
-<translation id="7511635910912978956">Zbývá: <ph name="NUMBER_FEW"/> hod</translation>
-<translation id="8717309436826820190">další oznámení služby <ph name="SOURCE_OF_NOTIFICATIONS"/> (<ph name="NUMBER_OF_NOTIFICATIONS"/>)</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Zrušit</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Klávesa šipka nahoru</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hod</translation>
-<translation id="3990502903496589789">Pravý okraj</translation>
-<translation id="9038489124413477075">Nepojmenovaná složka</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minut</translation>
-<translation id="3520476450377425184">Zbývá: <ph name="NUMBER_MANY"/> dnů</translation>
-<translation id="932327136139879170">Domů</translation>
-<translation id="5600907569873192868">Zbývá: <ph name="NUMBER_MANY"/> min</translation>
-<translation id="8666066831007952346">Zbývá: <ph name="NUMBER_TWO"/> dny</translation>
-<translation id="6390842777729054533">Zbývá: <ph name="NUMBER_ZERO"/> s</translation>
-<translation id="3909791450649380159">Vyjmou&amp;t</translation>
-<translation id="2560788951337264832">Zbývá <ph name="NUMBER_ZERO"/> minut</translation>
-<translation id="688711909580084195">Nepojmenovaná webová stránka</translation>
-<translation id="3353284378027041011">Před <ph name="NUMBER_FEW"/> dny</translation>
-<translation id="5076340679995252485">Vložit</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Vyberte složku pro nahrávání</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Klávesa šipka dolů</translation>
-<translation id="3087734570205094154">Až dolů</translation>
-<translation id="5935630983280450497">Zbývá: <ph name="NUMBER_ONE"/> min</translation>
-<translation id="1860796786778352021">Zavřít oznámení</translation>
-<translation id="6364916375976753737">Posuv doleva</translation>
-<translation id="2629089419211541119">Před <ph name="NUMBER_ONE"/> hodinou</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="6982279413068714821">před <ph name="NUMBER_DEFAULT"/> minutami</translation>
-<translation id="6945221475159498467">Vybrat</translation>
-<translation id="6620110761915583480">Uložit soubor</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> s</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Zbývá <ph name="NUMBER_ONE"/> minuta</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Klávesa PageDown</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dnů</translation>
-<translation id="7163503212501929773">Zbývá: <ph name="NUMBER_MANY"/> hod</translation>
-<translation id="5329858601952122676">&amp;Smazat</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> min</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Včera</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> min</translation>
-<translation id="50960180632766478">Zbývá: <ph name="NUMBER_FEW"/> min</translation>
-<translation id="6659594942844771486">Karta</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Před <ph name="NUMBER_DEFAULT"/> dny</translation>
-<translation id="8428213095426709021">Nastavení</translation>
-<translation id="2497284189126895209">Všechny soubory</translation>
-<translation id="7487278341251176613">Zbývají <ph name="NUMBER_TWO"/> minuty</translation>
-<translation id="5110450810124758964">Před <ph name="NUMBER_ONE"/> dnem</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
-<translation id="7814458197256864873">&amp;Kopírovat</translation>
-<translation id="3889424535448813030">Klávesa šipka vpravo</translation>
-<translation id="4229495110203539533">Před <ph name="NUMBER_ONE"/> sekundou</translation>
-<translation id="2544782972264605588">Zbývá: <ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="6829324100069873704">Přejít zpět k oznámením</translation>
-<translation id="6528179044667508675">Nerušit</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Povolit oznámení z následujících zdrojů:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hod</translation>
-<translation id="1398853756734560583">Maximalizovat</translation>
-<translation id="4250229828105606438">Snímek obrazovky</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hod</translation>
-<translation id="5260878308685146029">Zbývá: <ph name="NUMBER_TWO"/> min</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;Vybrat vše</translation>
-<translation id="2168039046890040389">Klávesa PageUp</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dnů</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Tady není nic k vidění, rozejděte se.</translation>
-<translation id="2482878487686419369">Oznámení</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Posunout sem</translation>
-<translation id="4552416320897244156">Klávesa PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hod</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Média – přehrát/pozastavit</translation>
-<translation id="2148716181193084225">Dnes</translation>
-<translation id="7960078400008666149">Nerušit jednu hodinu</translation>
-<translation id="4373894838514502496">před <ph name="NUMBER_FEW"/> minutami</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dnů</translation>
-<translation id="2190355936436201913">(prázdné)</translation>
-<translation id="1164369517022005061">Zbývá: <ph name="NUMBER_DEFAULT"/> hod</translation>
-<translation id="152482086482215392">Zbývá: <ph name="NUMBER_ONE"/> s</translation>
-<translation id="8447116497070723931">Klávesa PgUp</translation>
-<translation id="4588090240171750605">Posuv doprava</translation>
-<translation id="7414887922320653780">Zbývá: <ph name="NUMBER_ONE"/> hod</translation>
-<translation id="1413622004203049571">Deaktivovat oznámení ze služby <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Nahoru</translation>
-<translation id="8331626408530291785">Posuv nahoru</translation>
-<translation id="7907591526440419938">Otevřít soubor</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Klávesa Esc</translation>
-<translation id="2797524280730715045">Před <ph name="NUMBER_DEFAULT"/> hodinami</translation>
-<translation id="815598010540052116">Posuv dolů</translation>
-<translation id="6808150112686056157">Média – zastavit</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Obnovit</translation>
-<translation id="1243314992276662751">Nahrát</translation>
-<translation id="50030952220075532">Zbývá: <ph name="NUMBER_ONE"/> den</translation>
-<translation id="8179976553408161302">Začít</translation>
-<translation id="945522503751344254">Odeslat zpětnou vazbu</translation>
-<translation id="9170848237812810038">Z&amp;pět</translation>
-<translation id="1285266685456062655">Před <ph name="NUMBER_FEW"/> hodinami</translation>
-<translation id="6918245111648057970">Povolit oznámení z následujících zdrojů pro všechny uživatele:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> s</translation>
-<translation id="3994835489895548312">Zbývá <ph name="NUMBER_MANY"/> minut</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Nastavení...</translation>
-<translation id="6845383723252244143">Vybrat složku</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> s</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dnů</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hod</translation>
-<translation id="2679312662830811292">Před <ph name="NUMBER_ONE"/> minutou</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> den</translation>
-<translation id="9098468523912235228">Před <ph name="NUMBER_DEFAULT"/> sekundami</translation>
-<translation id="494645311413743213">Zbývá: <ph name="NUMBER_TWO"/> s</translation>
-<translation id="4570886800634958009">Rozbalit oznámení</translation>
-<translation id="436869212180315161">Tisk</translation>
-<translation id="4860787810836767172">Před <ph name="NUMBER_FEW"/> sekundami</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> min</translation>
-<translation id="1858722859751911017">Zbývají <ph name="NUMBER_FEW"/> minuty</translation>
-<translation id="6040143037577758943">Zavřít</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Nápověda</translation>
-<translation id="6699343763173986273">Média – další skladba</translation>
-<translation id="8226233771743600312">Nerušit jeden den</translation>
-<translation id="7457942297256758195">Vymazat vše</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
-<translation id="1963692530539281474">Zbývá: <ph name="NUMBER_DEFAULT"/> dnů</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> min</translation>
-<translation id="5906719743126878045">Zbývá: <ph name="NUMBER_TWO"/> hod</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> s</translation>
-<translation id="3759876923365568382">Zbývá: <ph name="NUMBER_FEW"/> dnů</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Zkopírovat do schránky</translation>
-<translation id="8371695176452482769">Mluvte</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Nerušit</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimalizovat</translation>
-<translation id="6394627529324717982">Čárka</translation>
-<translation id="3036649622769666520">Otevřít soubory</translation>
-<translation id="8328145009876646418">Levý okraj</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> s</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_da.xtb b/chromium/ui/base/strings/ui_strings_da.xtb
deleted file mode 100644
index 75d444e5715..00000000000
--- a/chromium/ui/base/strings/ui_strings_da.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="da">
-<translation id="4820616160060340806">Kommando+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> timer siden</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sek. tilbage</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sek. tilbage</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutter tilbage</translation>
-<translation id="1801827354178857021">Periode</translation>
-<translation id="1190609913194133056">Underretningcenter</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutter tilbage</translation>
-<translation id="5613020302032141669">Venstrepil</translation>
-<translation id="4971687151119236543">Medie: Forrige nummer</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek.</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timer tilbage</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> andre fra <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Annuller</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Pil opad</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sek.</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timer</translation>
-<translation id="3990502903496589789">Højre kant</translation>
-<translation id="9038489124413477075">Unavngiven mappe</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutter</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dage tilbage</translation>
-<translation id="932327136139879170">Start</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutter tilbage</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dage tilbage</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sek. tilbage</translation>
-<translation id="3909791450649380159">Kli&amp;p</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutter tilbage</translation>
-<translation id="688711909580084195">Ikke-navngivet webside</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dage siden</translation>
-<translation id="5076340679995252485">&amp;Indsæt</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Vælg den mappe, der skal uploades</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minutter siden</translation>
-<translation id="3234408098842461169">Pil nedad</translation>
-<translation id="3087734570205094154">Bund</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutter tilbage</translation>
-<translation id="1860796786778352021">Luk underretning</translation>
-<translation id="6364916375976753737">Scroll Left</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> time siden</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutter</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutter siden</translation>
-<translation id="6945221475159498467">Vælg</translation>
-<translation id="6620110761915583480">Gem fil</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut tilbage</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8210608804940886430">Side ned</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dage</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timer tilbage</translation>
-<translation id="5329858601952122676">&amp;Slet</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sek.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutter</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> sekunder siden</translation>
-<translation id="7781829728241885113">I går</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutter</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutter tilbage</translation>
-<translation id="6659594942844771486">Fane</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dage siden</translation>
-<translation id="8428213095426709021">Indstillinger</translation>
-<translation id="2497284189126895209">Alle filer</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutter tilbage</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dag siden</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek.</translation>
-<translation id="7814458197256864873">&amp;Kopier</translation>
-<translation id="3889424535448813030">Højrepil</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekund siden</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sek. tilbage</translation>
-<translation id="6829324100069873704">Gå tilbage til underretninger</translation>
-<translation id="6528179044667508675">Vil ikke forstyrres</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutter</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Tillad underretninger fra følgende:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timer</translation>
-<translation id="1398853756734560583">Maksimer</translation>
-<translation id="4250229828105606438">Skærmbillede</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timer</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutter tilbage</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Vælg &amp;alle</translation>
-<translation id="2168039046890040389">Side op</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dage</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutter</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> sekunder siden</translation>
-<translation id="4927753642311223124">Der er intet at se her, så du kan bare gå videre.</translation>
-<translation id="2482878487686419369">Meddelelser</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Scroll hertil</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timer</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/sek.</translation>
-<translation id="8394908167088220973">Medie: Afspil/Pause</translation>
-<translation id="2148716181193084225">I dag</translation>
-<translation id="7960078400008666149">Vil ikke forstyrres i en time</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minutter siden</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dage</translation>
-<translation id="2190355936436201913">(tom)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timer tilbage</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sek. tilbage</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Scroll til højre</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> timer tilbage</translation>
-<translation id="1413622004203049571">Deaktiver underretninger fra <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Top</translation>
-<translation id="8331626408530291785">Scroll Up</translation>
-<translation id="7907591526440419938">Åbn fil</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> timer siden</translation>
-<translation id="815598010540052116">Scroll Down</translation>
-<translation id="6808150112686056157">Medie: Stop</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Gendan</translation>
-<translation id="1243314992276662751">Upload</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dage tilbage</translation>
-<translation id="8179976553408161302">Start</translation>
-<translation id="945522503751344254">Send feedback</translation>
-<translation id="9170848237812810038">&amp;Fortryd</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> timer siden</translation>
-<translation id="6918245111648057970">Tillad underretninger fra følgende for hver bruger:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutter tilbage</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> sekunder siden</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Indstillinger...</translation>
-<translation id="6845383723252244143">Vælg mappe</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek.</translation>
-<translation id="5583640892426849032">Returtast</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> dage siden</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dage</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> time</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minut siden</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sek.</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>dag</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekunder siden</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sek. tilbage</translation>
-<translation id="4570886800634958009">Udvid underretning</translation>
-<translation id="436869212180315161">Tryk</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> sekunder siden</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sek.</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutter</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutter tilbage</translation>
-<translation id="6040143037577758943">Luk</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minutter siden</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sek.</translation>
-<translation id="7649070708921625228">Hjælp</translation>
-<translation id="6699343763173986273">Medie: Næste nummer</translation>
-<translation id="8226233771743600312">Vil ikke forstyrres i et døgn</translation>
-<translation id="7457942297256758195">Ryd alle</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dage siden</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutter</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dage tilbage</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutter</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timer tilbage</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> timer siden</translation>
-<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sek.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dage tilbage</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sek.</translation>
-<translation id="2743387203779672305">Kopiér til udklipsholderen</translation>
-<translation id="8371695176452482769">Indtal nu</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Vil ikke forstyrres</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimer</translation>
-<translation id="6394627529324717982">Komma</translation>
-<translation id="3036649622769666520">Åbn filer</translation>
-<translation id="8328145009876646418">Venstre kant</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_de.xtb b/chromium/ui/base/strings/ui_strings_de.xtb
deleted file mode 100644
index 87e45eafd50..00000000000
--- a/chromium/ui/base/strings/ui_strings_de.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="de">
-<translation id="4820616160060340806">Befehltaste+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Einfg</translation>
-<translation id="6135826906199951471">Entf</translation>
-<translation id="528468243742722775">Ende</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> Sekunden übrig</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> Sekunden übrig</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> Minuten übrig</translation>
-<translation id="1801827354178857021">Punkt</translation>
-<translation id="1190609913194133056">Benachrichtigungscenter</translation>
-<translation id="7470933019269157899">Noch <ph name="NUMBER_DEFAULT"/> Minuten</translation>
-<translation id="5613020302032141669">Linkspfeil</translation>
-<translation id="4971687151119236543">Medien – vorheriger Titel</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-Datei (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> Sekunden</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> Stunden übrig</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> weitere von <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Abbrechen</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Aufwärtspfeil</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> Stunden</translation>
-<translation id="3990502903496589789">Rechter Rand</translation>
-<translation id="9038489124413477075">Unbenannter Ordner</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> Minuten</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> Tage übrig</translation>
-<translation id="932327136139879170">Startseite</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> Minuten übrig</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> Tage übrig</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> Sekunden übrig</translation>
-<translation id="3909791450649380159">&amp;Ausschneiden</translation>
-<translation id="2560788951337264832">Noch <ph name="NUMBER_ZERO"/> Minuten</translation>
-<translation id="688711909580084195">Unbenannte Webseite</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Einfügen</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Ordner zum Hochladen auswählen</translation>
-<translation id="4999762576397546063">Strg+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Abwärtspfeil</translation>
-<translation id="3087734570205094154">Unten</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> Minute übrig</translation>
-<translation id="1860796786778352021">Benachrichtigung schließen</translation>
-<translation id="6364916375976753737">Nach links blättern</translation>
-<translation id="2629089419211541119">Vor <ph name="NUMBER_ONE"/> Stunde</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> Minuten</translation>
-<translation id="6982279413068714821">Vor <ph name="NUMBER_DEFAULT"/> Minuten</translation>
-<translation id="6945221475159498467">Auswählen</translation>
-<translation id="6620110761915583480">Datei speichern</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> Sekunden</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Noch <ph name="NUMBER_ONE"/> Minute</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> Minute</translation>
-<translation id="8210608804940886430">Nach unten</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> Tage</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> Stunden übrig</translation>
-<translation id="5329858601952122676">&amp;Löschen</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> Sekunden</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> Minuten</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Gestern</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> Minuten</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> Minuten übrig</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Vor <ph name="NUMBER_DEFAULT"/> Tagen</translation>
-<translation id="8428213095426709021">Einstellungen</translation>
-<translation id="2497284189126895209">Alle Dateien</translation>
-<translation id="7487278341251176613">Noch <ph name="NUMBER_TWO"/> Minuten</translation>
-<translation id="5110450810124758964">Vor <ph name="NUMBER_ONE"/> Tag</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> Sekunde</translation>
-<translation id="7814458197256864873">&amp;Kopieren</translation>
-<translation id="3889424535448813030">Rechtspfeil</translation>
-<translation id="4229495110203539533">Vor <ph name="NUMBER_ONE"/> Sekunde</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> Sekunden übrig</translation>
-<translation id="6829324100069873704">Zurück zu den Benachrichtigungen</translation>
-<translation id="6528179044667508675">Nicht stören</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> Sekunden</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> Minuten</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Alle Benachrichtigungen zulassen von:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> Stunden</translation>
-<translation id="1398853756734560583">Vergrößern</translation>
-<translation id="4250229828105606438">Screenshot</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> Stunden</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> Minuten übrig</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;Alles auswählen</translation>
-<translation id="2168039046890040389">Nach oben</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> Tage</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> Minuten</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> Minute</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Sie haben keine Benachrichtigungen.</translation>
-<translation id="2482878487686419369">Benachrichtigungen</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Hierher blättern</translation>
-<translation id="4552416320897244156">BildAb</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> Stunden</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Medien – Wiedergabe/Pause</translation>
-<translation id="2148716181193084225">Heute</translation>
-<translation id="7960078400008666149">1 Stunde nicht stören</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> Tage</translation>
-<translation id="2190355936436201913">(leer)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> Stunden übrig</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> Sekunde übrig</translation>
-<translation id="8447116497070723931">BildAuf</translation>
-<translation id="4588090240171750605">Nach rechts blättern</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> Stunde übrig</translation>
-<translation id="1413622004203049571">Benachrichtigungen von <ph name="NOTIFIER_NAME"/> deaktivieren</translation>
-<translation id="2666092431469916601">Oben</translation>
-<translation id="8331626408530291785">Nach oben blättern</translation>
-<translation id="7907591526440419938">Datei öffnen</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Vor <ph name="NUMBER_DEFAULT"/> Stunden</translation>
-<translation id="815598010540052116">Nach unten blättern</translation>
-<translation id="6808150112686056157">Medien – Stopp</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Wiederherstellen</translation>
-<translation id="1243314992276662751">Hochladen</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> Tag übrig</translation>
-<translation id="8179976553408161302">Enter</translation>
-<translation id="945522503751344254">Feedback geben</translation>
-<translation id="9170848237812810038">&amp;Rückgängig</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Benachrichtigungen von Folgendem für jeden Nutzer zulassen:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> Sekunde</translation>
-<translation id="3994835489895548312">Noch <ph name="NUMBER_MANY"/> Minuten</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Einstellungen...</translation>
-<translation id="6845383723252244143">Ordner auswählen</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> Sekunden</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> Sekunden</translation>
-<translation id="5583640892426849032">Rücktaste</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> Tage</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> Stunde</translation>
-<translation id="2679312662830811292">Vor <ph name="NUMBER_ONE"/> Minute</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> Tag</translation>
-<translation id="9098468523912235228">Vor <ph name="NUMBER_DEFAULT"/> Sekunden</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> Sekunden übrig</translation>
-<translation id="4570886800634958009">Benachrichtigung anzeigen</translation>
-<translation id="436869212180315161">Klicken</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> Minuten</translation>
-<translation id="1858722859751911017">Noch <ph name="NUMBER_FEW"/> Minuten</translation>
-<translation id="6040143037577758943">Schließen</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> Byte/s</translation>
-<translation id="7649070708921625228">Hilfe</translation>
-<translation id="6699343763173986273">Medien – nächster Titel</translation>
-<translation id="8226233771743600312">1 Tag nicht stören</translation>
-<translation id="7457942297256758195">Alle löschen</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> Minuten</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> Tage übrig</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> Minuten</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> Stunden übrig</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Umschalt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> Sekunden</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> Sekunden</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> Sekunden</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> Tage übrig</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">In Zwischenablage kopieren</translation>
-<translation id="8371695176452482769">Jetzt sprechen</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Nicht stören</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Verkleinern</translation>
-<translation id="6394627529324717982">Komma</translation>
-<translation id="3036649622769666520">Dateien öffnen</translation>
-<translation id="8328145009876646418">Linker Rand</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> Sekunden</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_el.xtb b/chromium/ui/base/strings/ui_strings_el.xtb
deleted file mode 100644
index 20f6f77031a..00000000000
--- a/chromium/ui/base/strings/ui_strings_el.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="el">
-<translation id="4820616160060340806">Εντολή+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798">Πριν από <ph name="NUMBER_MANY"/> ώρες</translation>
-<translation id="6310545596129886942">Υπολείπονται <ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
-<translation id="9213479837033539041">Υπολείπονται <ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
-<translation id="1209866192426315618">υπολείπονται <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
-<translation id="1801827354178857021">Τελεία</translation>
-<translation id="1190609913194133056">Κέντρο ειδοποιήσεων</translation>
-<translation id="7470933019269157899">Υπολείπονται <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
-<translation id="5613020302032141669">Αριστερό βέλος</translation>
-<translation id="4971687151119236543">Προηγούμενο κομμάτι πολυμέσων</translation>
-<translation id="8602707065186045623">Αρχείο <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
-<translation id="7511635910912978956">Υπολείπονται <ph name="NUMBER_FEW"/> ώρες</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> ακόμη από <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Ακύρωση</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> Β</translation>
-<translation id="3660179305079774227">Πάνω βέλος</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ώρες</translation>
-<translation id="3990502903496589789">Δεξιά άκρη</translation>
-<translation id="9038489124413477075">Φάκελος χωρίς όνομα</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> λεπτά</translation>
-<translation id="3520476450377425184">Υπολείπονται <ph name="NUMBER_MANY"/> ημέρες</translation>
-<translation id="932327136139879170">Αρχική σελίδα</translation>
-<translation id="5600907569873192868">Υπολείπονται <ph name="NUMBER_MANY"/> λεπτά</translation>
-<translation id="8666066831007952346">Υπολείπονται <ph name="NUMBER_TWO"/> ημέρες</translation>
-<translation id="6390842777729054533">Υπολείπονται <ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
-<translation id="3909791450649380159">Απο&amp;κοπή</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Ιστοσελίδα χωρίς τίτλο</translation>
-<translation id="3353284378027041011">Πριν από <ph name="NUMBER_FEW"/> ημέρες</translation>
-<translation id="5076340679995252485">&amp;Επικόλληση</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Επιλέξτε φάκελο για μεταφόρτωση</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Πριν από <ph name="NUMBER_TWO"/> λεπτά</translation>
-<translation id="3234408098842461169">Κάτω βέλος</translation>
-<translation id="3087734570205094154">Κάτω</translation>
-<translation id="5935630983280450497">Υπολείπεται <ph name="NUMBER_ONE"/> λεπτό</translation>
-<translation id="1860796786778352021">Κλείσιμο ειδοποίησης</translation>
-<translation id="6364916375976753737">Κύλιση αριστερά</translation>
-<translation id="2629089419211541119">Πριν από <ph name="NUMBER_ONE"/> ώρα</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> λεπτά</translation>
-<translation id="6982279413068714821">Πριν από <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
-<translation id="6945221475159498467">Επιλογή</translation>
-<translation id="6620110761915583480">Αποθήκευση Αρχείου</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Υπολείπεται <ph name="NUMBER_ONE"/> λεπτό</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> λεπτό</translation>
-<translation id="8210608804940886430">Επόμενη σελίδα</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ημέρες</translation>
-<translation id="7163503212501929773">Υπολείπονται <ph name="NUMBER_MANY"/> ώρες</translation>
-<translation id="5329858601952122676">&amp;Διαγραφή</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> λεπτά</translation>
-<translation id="7275974018215686543">Πριν από <ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
-<translation id="7781829728241885113">Χθες</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> λεπτά</translation>
-<translation id="50960180632766478">Υπολείπονται <ph name="NUMBER_FEW"/> λεπτά</translation>
-<translation id="6659594942844771486">Καρτέλα</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Πριν από <ph name="NUMBER_DEFAULT"/> ημέρες</translation>
-<translation id="8428213095426709021">Ρυθμίσεις</translation>
-<translation id="2497284189126895209">Όλα τα αρχεία</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964">Πριν από <ph name="NUMBER_ONE"/> ημέρα</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
-<translation id="7814458197256864873">&amp;Αντιγραφή</translation>
-<translation id="3889424535448813030">Δεξιό βέλος</translation>
-<translation id="4229495110203539533">Πριν από <ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
-<translation id="2544782972264605588">Υπολείπονται <ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
-<translation id="6829324100069873704">Επιστροφή στις ειδοποιήσεις</translation>
-<translation id="6528179044667508675">Μην ενοχλείτε</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> λεπτά</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Να επιτρέπονται ειδοποιήσεις από:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ώρες</translation>
-<translation id="1398853756734560583">Μεγιστοποίηση</translation>
-<translation id="4250229828105606438">Στιγμιότυπο οθόνης</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ώρες</translation>
-<translation id="5260878308685146029">Υπολείπονται <ph name="NUMBER_TWO"/> λεπτά</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Επιλογή όλ&amp;ων</translation>
-<translation id="2168039046890040389">Προηγούμενη σελίδα</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ημέρες</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> λεπτά</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> λεπτό</translation>
-<translation id="8448317557906454022">Πριν από <ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
-<translation id="4927753642311223124">Δεν υπάρχει τίποτα να δείτε εδώ, συνεχίστε με αυτό που κάνατε.</translation>
-<translation id="2482878487686419369">Ειδοποιήσεις</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Κύλιση εδώ</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">Πλήκτρο F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ώρες</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Αναπαραγωγή/παύση πολυμέσων</translation>
-<translation id="2148716181193084225">Σήμερα</translation>
-<translation id="7960078400008666149">Μην ενοχλείτε για μία ώρα</translation>
-<translation id="4373894838514502496">Πριν από <ph name="NUMBER_FEW"/> λεπτά</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ημέρες</translation>
-<translation id="2190355936436201913">(κενό)</translation>
-<translation id="1164369517022005061">Υπολείπονται <ph name="NUMBER_DEFAULT"/> ώρες</translation>
-<translation id="152482086482215392">Υπολείπεται <ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Κύλιση δεξιά</translation>
-<translation id="7414887922320653780">Υπολείπεται <ph name="NUMBER_ONE"/> ώρα</translation>
-<translation id="1413622004203049571">Απενεργοποίηση ειδοποιήσεων από <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Κορυφή</translation>
-<translation id="8331626408530291785">Κύλιση επάνω</translation>
-<translation id="7907591526440419938">Άνοιγμα Αρχείου</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Πριν από <ph name="NUMBER_DEFAULT"/> ώρες</translation>
-<translation id="815598010540052116">Κύλιση κάτω</translation>
-<translation id="6808150112686056157">Διακοπή πολυμέσων</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Επαναφορά</translation>
-<translation id="1243314992276662751">Μεταφόρτωση</translation>
-<translation id="50030952220075532">Υπολείπεται <ph name="NUMBER_ONE"/> ημέρα</translation>
-<translation id="8179976553408161302">Είσοδος</translation>
-<translation id="945522503751344254">Αποστολή σχολίων</translation>
-<translation id="9170848237812810038">Αναί&amp;ρεση</translation>
-<translation id="1285266685456062655">Πριν από <ph name="NUMBER_FEW"/> ώρες</translation>
-<translation id="6918245111648057970">Να επιτρέπονται οι ειδοποιήσεις από τις παρακάτω πηγές για κάθε χρήστη:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691">Πριν από <ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Ρυθμίσεις...</translation>
-<translation id="6845383723252244143">Επιλογή Φακέλου</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
-<translation id="5583640892426849032">Πλήκτρο Backspace</translation>
-<translation id="5263972071113911534">Πριν από <ph name="NUMBER_MANY"/> ημέρες</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ημέρες</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ώρα</translation>
-<translation id="2679312662830811292">Πριν από <ph name="NUMBER_ONE"/> λεπτό</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ημέρα</translation>
-<translation id="9098468523912235228">Πριν από <ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
-<translation id="494645311413743213">Υπολείπονται <ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
-<translation id="4570886800634958009">Επέκταση ειδοποίησης</translation>
-<translation id="436869212180315161">Πιέστε</translation>
-<translation id="4860787810836767172">Πριν από <ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> λεπτά</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Κλείσιμο</translation>
-<translation id="1101671447232096497">Πριν από <ph name="NUMBER_MANY"/> λεπτά</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Βοήθεια</translation>
-<translation id="6699343763173986273">Επόμενο κομμάτι πολυμέσων</translation>
-<translation id="8226233771743600312">Μην ενοχλείτε για μία ημέρα</translation>
-<translation id="7457942297256758195">Εκκαθάριση όλων</translation>
-<translation id="822618367988303761">Πριν από <ph name="NUMBER_TWO"/> ημέρες</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> λεπτά</translation>
-<translation id="1963692530539281474">Υπολείπονται <ph name="NUMBER_DEFAULT"/> ημέρες</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> λεπτά</translation>
-<translation id="5906719743126878045">Υπολείπονται <ph name="NUMBER_TWO"/> ώρες</translation>
-<translation id="8959208747503200525">Πριν από <ph name="NUMBER_TWO"/> ώρες</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
-<translation id="3759876923365568382">Υπολείπονται <ph name="NUMBER_FEW"/> ημέρες</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Αντιγραφή στο πρόχειρο</translation>
-<translation id="8371695176452482769">Μιλήστε τώρα</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Μην ενοχλείτε</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Ελαχιστοποίηση</translation>
-<translation id="6394627529324717982">Κόμμα</translation>
-<translation id="3036649622769666520">Άνοιγμα Αρχείων</translation>
-<translation id="8328145009876646418">Αριστερή άκρη</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_en-GB.xtb b/chromium/ui/base/strings/ui_strings_en-GB.xtb
deleted file mode 100644
index 51c81404419..00000000000
--- a/chromium/ui/base/strings/ui_strings_en-GB.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="en-GB">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> mins left</translation>
-<translation id="1801827354178857021">Full Stop</translation>
-<translation id="1190609913194133056">Notification Centre</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutes left</translation>
-<translation id="5613020302032141669">Left Arrow</translation>
-<translation id="4971687151119236543">Media Previous Track</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> more from <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancel</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Up Arrow</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hours</translation>
-<translation id="3990502903496589789">Right Edge</translation>
-<translation id="9038489124413477075">Unnamed Folder</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mins</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">Cu&amp;t</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Untitled Web Page</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Paste</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Select Folder to Upload</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Down Arrow</translation>
-<translation id="3087734570205094154">Bottom</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min left</translation>
-<translation id="1860796786778352021">Notification close</translation>
-<translation id="6364916375976753737">Scroll Left</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutes</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">Select</translation>
-<translation id="6620110761915583480">Save File</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute left</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
-<translation id="5329858601952122676">&amp;Delete</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Yesterday</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">Settings</translation>
-<translation id="2497284189126895209">All Files</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
-<translation id="7814458197256864873">&amp;Copy</translation>
-<translation id="3889424535448813030">Right Arrow</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> secs left</translation>
-<translation id="6829324100069873704">Go back to notifications</translation>
-<translation id="6528179044667508675">Do not disturb</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> seconds</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Allow notifications from the following:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
-<translation id="1398853756734560583">Maximise</translation>
-<translation id="4250229828105606438">Screenshot</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Select &amp;all</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> days</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Nothing to see here, move along.</translation>
-<translation id="2482878487686419369">Notifications</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Scroll to Here</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Media Play/Pause</translation>
-<translation id="2148716181193084225">Today</translation>
-<translation id="7960078400008666149">Do not disturb for one hour</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
-<translation id="2190355936436201913">(empty)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hours left</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec left</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Scroll Right</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hour left</translation>
-<translation id="1413622004203049571">Disable notifications from <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Top</translation>
-<translation id="8331626408530291785">Scroll Up</translation>
-<translation id="7907591526440419938">Open File</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">Scroll Down</translation>
-<translation id="6808150112686056157">Media Stop</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restore</translation>
-<translation id="1243314992276662751">Upload</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> day left</translation>
-<translation id="8179976553408161302">Enter</translation>
-<translation id="945522503751344254">Send feedback</translation>
-<translation id="9170848237812810038">&amp;Undo</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Allow notifications from the following for each user:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> second</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Settings...</translation>
-<translation id="6845383723252244143">Select Folder</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hour</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> day</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
-<translation id="4570886800634958009">Notification expand</translation>
-<translation id="436869212180315161">Press</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Close</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Help</translation>
-<translation id="6699343763173986273">Media Next Track</translation>
-<translation id="8226233771743600312">Do not disturb for one day</translation>
-<translation id="7457942297256758195">Clear All</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> days left</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secs</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copy to clipboard</translation>
-<translation id="8371695176452482769">Speak now</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Do Not Disturb</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimise</translation>
-<translation id="6394627529324717982">Comma</translation>
-<translation id="3036649622769666520">Open Files</translation>
-<translation id="8328145009876646418">Left Edge</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_es-419.xtb b/chromium/ui/base/strings/ui_strings_es-419.xtb
deleted file mode 100644
index 464c9670186..00000000000
--- a/chromium/ui/base/strings/ui_strings_es-419.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="es-419">
-<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Insert</translation>
-<translation id="6135826906199951471">Supr</translation>
-<translation id="528468243742722775">Fin</translation>
-<translation id="5341849548509163798">Hace <ph name="NUMBER_MANY"/> horas</translation>
-<translation id="6310545596129886942">Faltan <ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="9213479837033539041">Faltan <ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="1209866192426315618">Faltan <ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="1801827354178857021">Punto</translation>
-<translation id="1190609913194133056">Centro de notificaciones</translation>
-<translation id="7470933019269157899">Faltan <ph name="NUMBER_DEFAULT"/> minutos.</translation>
-<translation id="5613020302032141669">Flecha izquierda</translation>
-<translation id="4971687151119236543">Pista multimedia anterior</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Archivo (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
-<translation id="7511635910912978956">Faltan <ph name="NUMBER_FEW"/> horas</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> notificaciones más de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancelar</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Flecha arriba</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> de MB</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="3990502903496589789">Borde derecho</translation>
-<translation id="9038489124413477075">Carpeta sin nombre</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="3520476450377425184">Faltan <ph name="NUMBER_MANY"/> días</translation>
-<translation id="932327136139879170">Inicio</translation>
-<translation id="5600907569873192868">Faltan <ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="8666066831007952346">Faltan <ph name="NUMBER_TWO"/> días</translation>
-<translation id="6390842777729054533">Faltan <ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="3909791450649380159">Cor&amp;tar</translation>
-<translation id="2560788951337264832">Faltan <ph name="NUMBER_ZERO"/> minutos.</translation>
-<translation id="688711909580084195">Página web sin título</translation>
-<translation id="3353284378027041011">Hace <ph name="NUMBER_FEW"/> días</translation>
-<translation id="5076340679995252485">&amp;Pegar</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Seleccionar carpeta para cargar</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Hace <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="3234408098842461169">Flecha abajo</translation>
-<translation id="3087734570205094154">Inferior</translation>
-<translation id="5935630983280450497">Falta <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="1860796786778352021">Cerrar notificación</translation>
-<translation id="6364916375976753737">Desplazar hacia la izquierda</translation>
-<translation id="2629089419211541119">Hace <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6982279413068714821">Hace <ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6945221475159498467">Seleccionar</translation>
-<translation id="6620110761915583480">Guardar archivo</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Falta <ph name="NUMBER_ONE"/> minuto.</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Avanzar página</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> días</translation>
-<translation id="7163503212501929773">Faltan <ph name="NUMBER_MANY"/> horas</translation>
-<translation id="5329858601952122676">&amp;Suprimir</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543">Hace <ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="7781829728241885113">Ayer</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478">Faltan <ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="6659594942844771486">Pestaña</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Hace <ph name="NUMBER_DEFAULT"/> días</translation>
-<translation id="8428213095426709021">Configuración</translation>
-<translation id="2497284189126895209">Todos los archivos</translation>
-<translation id="7487278341251176613">Faltan <ph name="NUMBER_TWO"/> minutos.</translation>
-<translation id="5110450810124758964">Hace <ph name="NUMBER_ONE"/> día</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="7814458197256864873">&amp;Copiar</translation>
-<translation id="3889424535448813030">Flecha derecha</translation>
-<translation id="4229495110203539533">Hace <ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="2544782972264605588">Faltan <ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="6829324100069873704">Volver a las notificaciones</translation>
-<translation id="6528179044667508675">No molestar</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Permitir notificaciones de:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
-<translation id="1398853756734560583">Maximizar</translation>
-<translation id="4250229828105606438">Captura de pantalla</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
-<translation id="5260878308685146029">Faltan <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
-<translation id="2168039046890040389">Retroceder página</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> días</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022">Hace <ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="4927753642311223124">No hay ningún elemento que mostrar.</translation>
-<translation id="2482878487686419369">Notificaciones</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Desplazarse hasta aquí</translation>
-<translation id="4552416320897244156">AvPág</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Reproducir o pausar contenido multimedia</translation>
-<translation id="2148716181193084225">Hoy</translation>
-<translation id="7960078400008666149">No molestar durante una hora</translation>
-<translation id="4373894838514502496">Hace <ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> días</translation>
-<translation id="2190355936436201913">(vacío)</translation>
-<translation id="1164369517022005061">Faltan <ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="152482086482215392">Falta <ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="8447116497070723931">RePág</translation>
-<translation id="4588090240171750605">Desplazar a la derecha</translation>
-<translation id="7414887922320653780">Falta <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Superior</translation>
-<translation id="8331626408530291785">Desplazar hacia arriba</translation>
-<translation id="7907591526440419938">Abrir archivo</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Hace <ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="815598010540052116">Desplazar hacia abajo</translation>
-<translation id="6808150112686056157">Detener contenido multimedia</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaurar</translation>
-<translation id="1243314992276662751">Cargar</translation>
-<translation id="50030952220075532">Falta <ph name="NUMBER_ONE"/> día</translation>
-<translation id="8179976553408161302">Entrar</translation>
-<translation id="945522503751344254">Enviar comentarios</translation>
-<translation id="9170848237812810038">&amp;Deshacer</translation>
-<translation id="1285266685456062655">Hace <ph name="NUMBER_FEW"/> horas</translation>
-<translation id="6918245111648057970">Permitir notificaciones para cada usuario de lo siguiente:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="3994835489895548312">Faltan <ph name="NUMBER_MANY"/> minutos.</translation>
-<translation id="6358975074282722691">Hace <ph name="NUMBER_TWO"/> segundos</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Configuración...</translation>
-<translation id="6845383723252244143">Seleccionar carpeta</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
-<translation id="5583640892426849032">Tecla de retroceso</translation>
-<translation id="5263972071113911534">Hace <ph name="NUMBER_MANY"/> días</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> días</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2679312662830811292">Hace <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> día</translation>
-<translation id="9098468523912235228">Hace <ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="494645311413743213">Faltan <ph name="NUMBER_TWO"/> segundos</translation>
-<translation id="4570886800634958009">Ampliar notificación</translation>
-<translation id="436869212180315161">Hacer clic</translation>
-<translation id="4860787810836767172">Hace <ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">Faltan <ph name="NUMBER_FEW"/> minutos.</translation>
-<translation id="6040143037577758943">Cerrar</translation>
-<translation id="1101671447232096497">Hace <ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Ayuda</translation>
-<translation id="6699343763173986273">Pista multimedia siguiente</translation>
-<translation id="8226233771743600312">No molestar durante un día</translation>
-<translation id="7457942297256758195">Borrar todo</translation>
-<translation id="822618367988303761">Hace <ph name="NUMBER_TWO"/> días</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="1963692530539281474">Faltan <ph name="NUMBER_DEFAULT"/> días</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045">Faltan <ph name="NUMBER_TWO"/> horas</translation>
-<translation id="8959208747503200525">Hace <ph name="NUMBER_TWO"/> horas</translation>
-<translation id="8400147561352026160">Mayús+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382">Faltan <ph name="NUMBER_FEW"/> días</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copiar al portapapeles</translation>
-<translation id="8371695176452482769">Hablar ahora</translation>
-<translation id="6965382102122355670">Aceptar</translation>
-<translation id="7850320739366109486">No molestar</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimizar</translation>
-<translation id="6394627529324717982">Coma</translation>
-<translation id="3036649622769666520">Abrir archivos</translation>
-<translation id="8328145009876646418">Borde izquierdo</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_es.xtb b/chromium/ui/base/strings/ui_strings_es.xtb
deleted file mode 100644
index ce6ba133ade..00000000000
--- a/chromium/ui/base/strings/ui_strings_es.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="es">
-<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Insert</translation>
-<translation id="6135826906199951471">Supr</translation>
-<translation id="528468243742722775">Fin</translation>
-<translation id="5341849548509163798">hace <ph name="NUMBER_MANY"/> horas</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> segundos restantes</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> segundos restantes</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutos restantes</translation>
-<translation id="1801827354178857021">Punto</translation>
-<translation id="1190609913194133056">Centro de notificaciones</translation>
-<translation id="7470933019269157899">Quedan <ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="5613020302032141669">Flecha izquierda</translation>
-<translation id="4971687151119236543">Pista anterior multimedia</translation>
-<translation id="8602707065186045623">Archivo <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> horas restantes</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> notificaciones más de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancelar</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Flecha arriba</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="3990502903496589789">Borde derecho</translation>
-<translation id="9038489124413477075">Carpeta sin nombre</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> días restantes</translation>
-<translation id="932327136139879170">Inicio</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutos restantes</translation>
-<translation id="8666066831007952346">Faltan <ph name="NUMBER_TWO"/> días</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> segundos restantes</translation>
-<translation id="3909791450649380159">Cor&amp;tar</translation>
-<translation id="2560788951337264832">Quedan <ph name="NUMBER_ZERO"/> minutos</translation>
-<translation id="688711909580084195">Página web sin título</translation>
-<translation id="3353284378027041011">hace <ph name="NUMBER_FEW"/> días</translation>
-<translation id="5076340679995252485">&amp;Pegar</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Seleccionar una carpeta para subirla</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">hace <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="3234408098842461169">Flecha abajo</translation>
-<translation id="3087734570205094154">Inferior</translation>
-<translation id="5935630983280450497">Falta <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="1860796786778352021">Cerrar notificación</translation>
-<translation id="6364916375976753737">Desplazar hacia la izquierda</translation>
-<translation id="2629089419211541119">hace <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6982279413068714821">hace <ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6945221475159498467">Seleccionar</translation>
-<translation id="6620110761915583480">Guardar archivo</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Queda <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Avanzar página</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> días</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> horas restantes</translation>
-<translation id="5329858601952122676">&amp;Suprimir</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7275974018215686543">hace <ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="7781829728241885113">Ayer</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutos restantes</translation>
-<translation id="6659594942844771486">Pestaña</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">hace <ph name="NUMBER_DEFAULT"/> días</translation>
-<translation id="8428213095426709021">Configuración</translation>
-<translation id="2497284189126895209">Todos los archivos</translation>
-<translation id="7487278341251176613">Quedan <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="5110450810124758964">hace <ph name="NUMBER_ONE"/> día</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="7814458197256864873">&amp;Copiar</translation>
-<translation id="3889424535448813030">Flecha derecha</translation>
-<translation id="4229495110203539533">hace <ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> segundos restantes</translation>
-<translation id="6829324100069873704">Volver a las notificaciones</translation>
-<translation id="6528179044667508675">No molestar</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Permitir notificaciones de:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
-<translation id="1398853756734560583">Maximizar</translation>
-<translation id="4250229828105606438">Captura de pantalla</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
-<translation id="5260878308685146029">Faltan <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
-<translation id="2168039046890040389">Retroceder página</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> días</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022">hace <ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="4927753642311223124">Aquí no hay nada que ver, circulen...</translation>
-<translation id="2482878487686419369">Notificaciones</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Desplazarse hasta aquí</translation>
-<translation id="4552416320897244156">AvPág</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Pausar/Reproducir contenido multimedia</translation>
-<translation id="2148716181193084225">Hoy</translation>
-<translation id="7960078400008666149">No molestar durante una hora</translation>
-<translation id="4373894838514502496">hace <ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> días</translation>
-<translation id="2190355936436201913">(vacío)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> horas restantes</translation>
-<translation id="152482086482215392">Falta <ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="8447116497070723931">RePág</translation>
-<translation id="4588090240171750605">Desplazar a la derecha</translation>
-<translation id="7414887922320653780">Falta <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Superior</translation>
-<translation id="8331626408530291785">Desplazar hacia arriba</translation>
-<translation id="7907591526440419938">Abrir archivo</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">hace <ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="815598010540052116">Desplazar hacia abajo</translation>
-<translation id="6808150112686056157">Detener contenido multimedia</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaurar</translation>
-<translation id="1243314992276662751">Subir</translation>
-<translation id="50030952220075532">Falta <ph name="NUMBER_ONE"/> día</translation>
-<translation id="8179976553408161302">Entrar</translation>
-<translation id="945522503751344254">Danos tu opinión</translation>
-<translation id="9170848237812810038">&amp;Deshacer</translation>
-<translation id="1285266685456062655">hace <ph name="NUMBER_FEW"/> horas</translation>
-<translation id="6918245111648057970">Permitir que cada usuario reciba notificaciones de:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="3994835489895548312">Quedan <ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="6358975074282722691">hace <ph name="NUMBER_TWO"/> segundos</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Configuración...</translation>
-<translation id="6845383723252244143">Seleccionar carpeta</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
-<translation id="5583640892426849032">Tecla de retroceso</translation>
-<translation id="5263972071113911534">hace <ph name="NUMBER_MANY"/> días</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> días</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2679312662830811292">hace <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> día</translation>
-<translation id="9098468523912235228">hace <ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="494645311413743213">Faltan <ph name="NUMBER_TWO"/> segundos</translation>
-<translation id="4570886800634958009">Ampliar notificación</translation>
-<translation id="436869212180315161">Pulsar</translation>
-<translation id="4860787810836767172">hace <ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
-<translation id="1858722859751911017">Quedan <ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="6040143037577758943">Cerrar</translation>
-<translation id="1101671447232096497">hace <ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Ayuda</translation>
-<translation id="6699343763173986273">Siguiente pista multimedia</translation>
-<translation id="8226233771743600312">No molestar durante un día</translation>
-<translation id="7457942297256758195">Borrar todo</translation>
-<translation id="822618367988303761">hace <ph name="NUMBER_TWO"/> días</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> días restantes</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> horas restantes</translation>
-<translation id="8959208747503200525">hace <ph name="NUMBER_TWO"/> horas</translation>
-<translation id="8400147561352026160">Mayús+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> días restantes</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copiar al portapapeles</translation>
-<translation id="8371695176452482769">Habla ahora</translation>
-<translation id="6965382102122355670">Aceptar</translation>
-<translation id="7850320739366109486">No molestar</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimizar</translation>
-<translation id="6394627529324717982">Coma</translation>
-<translation id="3036649622769666520">Abrir archivos</translation>
-<translation id="8328145009876646418">Borde izquierdo</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_et.xtb b/chromium/ui/base/strings/ui_strings_et.xtb
deleted file mode 100644
index 844f22bdc29..00000000000
--- a/chromium/ui/base/strings/ui_strings_et.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="et">
-<translation id="4820616160060340806">Käsk + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> tundi tagasi</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekundit jäänud</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekundit jäänud</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutit jäänud</translation>
-<translation id="1801827354178857021">Periood</translation>
-<translation id="1190609913194133056">Märguannete keskus</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutit on jäänud</translation>
-<translation id="5613020302032141669">Vasaknool</translation>
-<translation id="4971687151119236543">Meediumi eelmine lugu</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fail (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekundit</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> tundi jäänud</translation>
-<translation id="8717309436826820190">Veel <ph name="NUMBER_OF_NOTIFICATIONS"/> allikast <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Tühista</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Ülesnool</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> tundi</translation>
-<translation id="3990502903496589789">Parem serv</translation>
-<translation id="9038489124413477075">Nimeta kaust</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutit</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/>päeva jäänud</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutit jäänud</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> päeva jäänud</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekundit jäänud</translation>
-<translation id="3909791450649380159">Lõ&amp;ika</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutit on jäänud</translation>
-<translation id="688711909580084195">Nimeta veebileht</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> päeva tagasi</translation>
-<translation id="5076340679995252485">&amp;Kleebi</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Kausta valimine üleslaadimiseks</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minutit tagasi</translation>
-<translation id="3234408098842461169">Allanool</translation>
-<translation id="3087734570205094154">Alaserv</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutit jäänud</translation>
-<translation id="1860796786778352021">Märguande sulgemine</translation>
-<translation id="6364916375976753737">Keri vasakule</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> tund tagasi</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutit</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutit tagasi</translation>
-<translation id="6945221475159498467">Vali</translation>
-<translation id="6620110761915583480">Faili salvestamine</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut on jäänud</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8210608804940886430">Lehekülje lõppu</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> päeva</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> tundi jäänud</translation>
-<translation id="5329858601952122676">&amp;Kustuta</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekundit</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> sekundit tagasi</translation>
-<translation id="7781829728241885113">Eile</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutit jäänud</translation>
-<translation id="6659594942844771486">Vaheleht</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> päeva tagasi</translation>
-<translation id="8428213095426709021">Seaded</translation>
-<translation id="2497284189126895209">Kõik failid</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutit on jäänud</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> päev tagasi</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekundit</translation>
-<translation id="7814458197256864873">&amp;Kopeeri</translation>
-<translation id="3889424535448813030">Paremnool</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekund tagasi</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekundit jäänud</translation>
-<translation id="6829324100069873704">Tagasi märguannete juurde</translation>
-<translation id="6528179044667508675">Mitte segada</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundit</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutit</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Luba märguanded järgmistest kohtadest:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> tundi</translation>
-<translation id="1398853756734560583">Maksimeeri</translation>
-<translation id="4250229828105606438">Ekraanipilt</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> tundi</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutit jäänud</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Vali &amp;kõik</translation>
-<translation id="2168039046890040389">Lehekülje üles</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> päeva</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutit</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> sekundit tagasi</translation>
-<translation id="4927753642311223124">Siin pole ühtegi märguannet, liikuge edasi.</translation>
-<translation id="2482878487686419369">Teatised</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Keri siia</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> tundi</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Meediumi esitamine/peatamine</translation>
-<translation id="2148716181193084225">Täna</translation>
-<translation id="7960078400008666149">Mitte segada üks tund</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minutit tagasi</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> päeva</translation>
-<translation id="2190355936436201913">(tühi)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> tundi jäänud</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekundit jäänud</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Keri paremale</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> tundi jäänud</translation>
-<translation id="1413622004203049571">Keela märguanded: <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Üles</translation>
-<translation id="8331626408530291785">Keri üles</translation>
-<translation id="7907591526440419938">Faili avamine</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> tundi tagasi</translation>
-<translation id="815598010540052116">Keri alla</translation>
-<translation id="6808150112686056157">Meediumi peatamine</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Taasta</translation>
-<translation id="1243314992276662751">Laadi üles</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> päev jäänud</translation>
-<translation id="8179976553408161302">Sisestusklahv</translation>
-<translation id="945522503751344254">Saada tagasisidet</translation>
-<translation id="9170848237812810038">&amp;Võta tagasi</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> tundi tagasi</translation>
-<translation id="6918245111648057970">Luba järgmised märguanded iga kasutaja puhul:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutit on jäänud</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> sekundit tagasi</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Seaded...</translation>
-<translation id="6845383723252244143">Kausta valimine</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekundit</translation>
-<translation id="5583640892426849032">Tagasilükkeklahv</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> päeva tagasi</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> päeva</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> tund</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minut tagasi</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> päev</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekundit tagasi</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekundit jäänud</translation>
-<translation id="4570886800634958009">Märguande laiendamine</translation>
-<translation id="436869212180315161">Vajuta</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> sekundit tagasi</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutit on jäänud</translation>
-<translation id="6040143037577758943">Sule</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minutit tagasi</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Abi</translation>
-<translation id="6699343763173986273">Meediumi järgmine lugu</translation>
-<translation id="8226233771743600312">Mitte segada üks päev</translation>
-<translation id="7457942297256758195">Kustuta kõik</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> päeva tagasi</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutit</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> päeva jäänud</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> tundi jäänud</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> tundi tagasi</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekundit</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekundit</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> päeva jäänud</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopeeri lõikelauale</translation>
-<translation id="8371695176452482769">Alustage rääkimist</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Mitte segada</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimeeri</translation>
-<translation id="6394627529324717982">Koma</translation>
-<translation id="3036649622769666520">Failide avamine</translation>
-<translation id="8328145009876646418">Vasak serv</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_fa.xtb b/chromium/ui/base/strings/ui_strings_fa.xtb
deleted file mode 100644
index a141a6263b9..00000000000
--- a/chromium/ui/base/strings/ui_strings_fa.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="fa">
-<translation id="4820616160060340806">فرمان+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">حذف</translation>
-<translation id="528468243742722775">پایان</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> دقیقه مانده</translation>
-<translation id="1801827354178857021">دوره</translation>
-<translation id="1190609913194133056">مرکز اعلان</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> دقیقه باقیمانده</translation>
-<translation id="5613020302032141669">پیکان چپ</translation>
-<translation id="4971687151119236543">آهنگ قبلی رسانه</translation>
-<translation id="8602707065186045623">فایل <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> مورد بیشتر از <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">لغو</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> بایت</translation>
-<translation id="3660179305079774227">پیکان بالا</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> مگابایت/ثانیه</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ساعت</translation>
-<translation id="3990502903496589789">حاشیه راست</translation>
-<translation id="9038489124413477075">پوشه بدون نام</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> دقیقه</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
-<translation id="932327136139879170">صفحهٔ اصلی</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">&amp;برش</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> دقیقه باقیمانده</translation>
-<translation id="688711909580084195">صفحهٔ وب بدون عنوان</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;جاگذاری</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> ترابایت</translation>
-<translation id="364720409959344976">انتخاب پوشه برای آپلود</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">پیکان پایین</translation>
-<translation id="3087734570205094154">پایین</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> دقیقه مانده</translation>
-<translation id="1860796786778352021">بستن اعلان</translation>
-<translation id="6364916375976753737">پیمایش به چپ</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ساعت قبل</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> دقیقه</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> دقیقه قبل</translation>
-<translation id="6945221475159498467">انتخاب</translation>
-<translation id="6620110761915583480">ذخیره کردن فایل</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ثانیه</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> دقیقه باقیمانده</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> دقیقه</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
-<translation id="5329858601952122676">&amp;حذف</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> کیلوبایت</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> دقیقه</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">دیروز</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> دقیقه</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> مگابایت</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> روز قبل</translation>
-<translation id="8428213095426709021">تنظیمات</translation>
-<translation id="2497284189126895209">همه فایل‌ها</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> دقیقه باقیمانده</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> روز قبل</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ثانیه</translation>
-<translation id="7814458197256864873">&amp;کپی</translation>
-<translation id="3889424535448813030">پیکان راست</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> ثانیه قبل</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> ثانیه مانده</translation>
-<translation id="6829324100069873704">بازگشت به اعلان‌ها</translation>
-<translation id="6528179044667508675">مزاحم نشوید</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ثانیه</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">اعلان موارد زیر مجاز باشد:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
-<translation id="1398853756734560583">بزرگ کردن</translation>
-<translation id="4250229828105606438">عکس از صفحه نمایش</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> گیگابایت</translation>
-<translation id="1901303067676059328">انتخاب &amp;همه</translation>
-<translation id="2168039046890040389">صفحه بالا</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> روز</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> دقیقه</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">اینجا خبری نیست، برگردید.</translation>
-<translation id="2482878487686419369">اعلام ها</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">پیمایش به اینجا</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> کیلوبایت/ثانیه</translation>
-<translation id="8394908167088220973">پخش/توقف موقت رسانه</translation>
-<translation id="2148716181193084225">امروز</translation>
-<translation id="7960078400008666149">یک ساعت مزاحم نشوید</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
-<translation id="2190355936436201913">(خالی)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ساعت مانده</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ثانیه مانده</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">پیمایش به راست</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ساعت مانده</translation>
-<translation id="1413622004203049571">غیرفعال کردن اعلان‌ها از <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">بالا</translation>
-<translation id="8331626408530291785">پیمایش به بالا</translation>
-<translation id="7907591526440419938">باز کردن فایل</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ساعت قبل</translation>
-<translation id="815598010540052116">پیمایش به پایین</translation>
-<translation id="6808150112686056157">توقف رسانه</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">بازیابی</translation>
-<translation id="1243314992276662751">آپلود</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> روز مانده</translation>
-<translation id="8179976553408161302">ورود</translation>
-<translation id="945522503751344254">ارسال بازخورد</translation>
-<translation id="9170848237812810038">&amp;واگرد</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">دریافت اعلان از موارد زیر برای هر کاربر مجاز است:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ثانیه</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> دقیقه باقیمانده</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> پتابایت</translation>
-<translation id="2983818520079887040">تنظیمات...</translation>
-<translation id="6845383723252244143">انتخاب پوشه</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ثانیه</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ساعت</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> گیگابایت/ثانیه</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> روز</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> ثانیه قبل</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
-<translation id="4570886800634958009">باز کردن اعلان</translation>
-<translation id="436869212180315161">فشار دادن</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> ترابایت/ثانیه</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> دقیقه</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> دقیقه باقیمانده</translation>
-<translation id="6040143037577758943">بستن</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> بایت/ثانیه</translation>
-<translation id="7649070708921625228">راهنما</translation>
-<translation id="6699343763173986273">آهنگ بعدی رسانه</translation>
-<translation id="8226233771743600312">یک روز مزاحم نشوید</translation>
-<translation id="7457942297256758195">پاک کردن همه</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> روز مانده</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> دقیقه</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ثانیه</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ثانیه</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> پتابایت/ثانیه</translation>
-<translation id="2743387203779672305">کپی در کلیپ‌بورد</translation>
-<translation id="8371695176452482769">اکنون صحبت کنید</translation>
-<translation id="6965382102122355670">تأیید</translation>
-<translation id="7850320739366109486">مزاحم نشوید</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">کوچک کردن</translation>
-<translation id="6394627529324717982">کاما</translation>
-<translation id="3036649622769666520">باز کردن فایل‌ها</translation>
-<translation id="8328145009876646418">حاشیه چپ</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ثانیه</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_fi.xtb b/chromium/ui/base/strings/ui_strings_fi.xtb
deleted file mode 100644
index febe7c38c5b..00000000000
--- a/chromium/ui/base/strings/ui_strings_fi.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="fi">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekuntia jäljellä</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekuntia jäljellä</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuuttia jäljellä</translation>
-<translation id="1801827354178857021">Piste</translation>
-<translation id="1190609913194133056">Ilmoituskeskus</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuuttia jäljellä</translation>
-<translation id="5613020302032141669">Nuoli vas.</translation>
-<translation id="4971687151119236543">Media: edellinen kappale</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-tiedosto (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekuntia</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> tuntia jäljellä</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> lisää lähteestä <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Peruuta</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> t</translation>
-<translation id="3660179305079774227">Nuoli yl.</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> Mt/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> tuntia</translation>
-<translation id="3990502903496589789">Oikea reuna</translation>
-<translation id="9038489124413477075">Nimetön kansio</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuuttia</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> päivää jäljellä</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuuttia jäljellä</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> päivää jäljellä</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekuntia jäljellä</translation>
-<translation id="3909791450649380159">L&amp;eikkaa</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Nimetön verkkosivu</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Liitä</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> Tt</translation>
-<translation id="364720409959344976">Valitse lähetettävä kansio</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Nuoli al.</translation>
-<translation id="3087734570205094154">Alaosa</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minuuttia jäljellä</translation>
-<translation id="1860796786778352021">Ilmoitus sulje</translation>
-<translation id="6364916375976753737">Vieritä vasemmalle</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> tunti sitten</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuuttia</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuuttia sitten</translation>
-<translation id="6945221475159498467">Valitse</translation>
-<translation id="6620110761915583480">Tallenna tiedosto</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekuntia</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuutti jäljellä</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuuttia</translation>
-<translation id="8210608804940886430">Sivu alas</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> päivää</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> tuntia jäljellä</translation>
-<translation id="5329858601952122676">&amp;Poista</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekuntia</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kt</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Eilen</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuuttia jäljellä</translation>
-<translation id="6659594942844771486">Välilehti</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> Mt</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> päivää sitten</translation>
-<translation id="8428213095426709021">Asetukset</translation>
-<translation id="2497284189126895209">Kaikki tiedostot</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> päivä sitten</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekuntia</translation>
-<translation id="7814458197256864873">K&amp;opioi</translation>
-<translation id="3889424535448813030">Nuoli oik.</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekunti sitten</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekuntia jäljellä</translation>
-<translation id="6829324100069873704">Palaa ilmoituksiin</translation>
-<translation id="6528179044667508675">Älä häiritse</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekuntia</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuuttia</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Salli ilmoitukset seuraavista:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> tuntia</translation>
-<translation id="1398853756734560583">Suurenna</translation>
-<translation id="4250229828105606438">Kuvakaappaus</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> tuntia</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuuttia jäljellä</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> Gt</translation>
-<translation id="1901303067676059328">Valitse &amp;kaikki</translation>
-<translation id="2168039046890040389">Sivu ylös</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> päivää</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuuttia</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuutti</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Täällä ei ole mitään nähtävää.</translation>
-<translation id="2482878487686419369">Ilmoitukset</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Vieritä tähän</translation>
-<translation id="4552416320897244156">Sivu alas</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> tuntia</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kt/s</translation>
-<translation id="8394908167088220973">Media: toista/keskeytä</translation>
-<translation id="2148716181193084225">Tänään</translation>
-<translation id="7960078400008666149">Älä häiritse tuntiin</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> päivää</translation>
-<translation id="2190355936436201913">(tyhjä)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> tuntia jäljellä</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekuntia jäljellä</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Vieritä oikealle</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> tuntia jäljellä</translation>
-<translation id="1413622004203049571">Poista ilmoitukset käytöstä sovellukselta <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Yleisin</translation>
-<translation id="8331626408530291785">Vieritä ylös</translation>
-<translation id="7907591526440419938">Avaa tiedosto</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> tuntia sitten</translation>
-<translation id="815598010540052116">Vieritä alas</translation>
-<translation id="6808150112686056157">Media: pysäytä</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Palauta</translation>
-<translation id="1243314992276662751">Lähetä</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> päivää jäljellä</translation>
-<translation id="8179976553408161302">Sisään</translation>
-<translation id="945522503751344254">Lähetä palautetta</translation>
-<translation id="9170848237812810038">K&amp;umoa</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Salli seuraavat ilmoitukset kaikilta käyttäjiltä:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunti</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> Pt</translation>
-<translation id="2983818520079887040">Asetukset...</translation>
-<translation id="6845383723252244143">Valitse kansio</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekuntia</translation>
-<translation id="5583640892426849032">Askelpalautin</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> päivää</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> tuntia</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuutti sitten</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> Gt/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> päivää</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekuntia sitten</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekuntia jäljellä</translation>
-<translation id="4570886800634958009">Ilmoitus laajenna</translation>
-<translation id="436869212180315161">Paina</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> Tt/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuuttia</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Sulje</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> t/s</translation>
-<translation id="7649070708921625228">Ohje</translation>
-<translation id="6699343763173986273">Media: seuraava kappale</translation>
-<translation id="8226233771743600312">Älä häiritse päivään</translation>
-<translation id="7457942297256758195">Tyhjennä kaikki</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuuttia</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> päivää jäljellä</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> tuntia jäljellä</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekuntia</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekuntia</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> päivää jäljellä</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> Pt/s</translation>
-<translation id="2743387203779672305">Kopioi leikepöydälle</translation>
-<translation id="8371695176452482769">Puhu nyt</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Älä häiritse</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Pienennä</translation>
-<translation id="6394627529324717982">Pilkku</translation>
-<translation id="3036649622769666520">Avaa tiedostot</translation>
-<translation id="8328145009876646418">Vasen reuna</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_fil.xtb b/chromium/ui/base/strings/ui_strings_fil.xtb
deleted file mode 100644
index c4a4d4b6cd5..00000000000
--- a/chromium/ui/base/strings/ui_strings_fil.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="fil">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">Wakas na</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> mga oras ang nakalipas</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/>nalalabing seg</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> mga natitirang segundo</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> nalalabing mga minuto</translation>
-<translation id="1801827354178857021">Tuldok</translation>
-<translation id="1190609913194133056">Notification Center</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> (na) minuto ang natitira</translation>
-<translation id="5613020302032141669">KAliwang Arrow</translation>
-<translation id="4971687151119236543">Nakaraang Track ng Media</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> segundo</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> natitirang oras</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> pa mula sa <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Kanselahin</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> (na) B</translation>
-<translation id="3660179305079774227">Up Arrow</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> (na) MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> mga oras</translation>
-<translation id="3990502903496589789">Tamang Lamang</translation>
-<translation id="9038489124413477075">Walang Pangalan na Folder</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mga minuto</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> mga nalalabing araw</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> natitirang minuto</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> natitirang mga araw</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> mga natitirang segundo</translation>
-<translation id="3909791450649380159">Al&amp;isin</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Walang Pamagat na Webpage</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> araw ang nakalipas</translation>
-<translation id="5076340679995252485">&amp;Ilagay</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> (na) TB</translation>
-<translation id="364720409959344976">Pumili ng Folder na I-a-upload</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuto ang nakalipas</translation>
-<translation id="3234408098842461169">Down Arrow</translation>
-<translation id="3087734570205094154">Sa ilalim</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> natitirang minuto</translation>
-<translation id="1860796786778352021">Isara ang notification</translation>
-<translation id="6364916375976753737">Mag-scroll Pakaliwa</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> oras ang nakalipas</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> (na) minuto</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuto ang nakalipas</translation>
-<translation id="6945221475159498467">Pumili</translation>
-<translation id="6620110761915583480">I-save ang File</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> na segundo</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto ang natitira</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> mga araw</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> mga oras na nalalabi</translation>
-<translation id="5329858601952122676">&amp;Tanggalin</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> (na) minuto</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> segundo ang nakalipas</translation>
-<translation id="7781829728241885113">Kahapon</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuto</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> natitirang minuto</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> (na) MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> araw ang nakalipas</translation>
-<translation id="8428213095426709021">Mga Setting</translation>
-<translation id="2497284189126895209">Lahat ng Mga File</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> araw ang nakalipas</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="7814458197256864873">&amp;Kopyahin</translation>
-<translation id="3889424535448813030">Right Arrow</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> segundo ang nakalipas</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> mga natitirang segundo</translation>
-<translation id="6829324100069873704">Bumalik sa mga notification</translation>
-<translation id="6528179044667508675">Huwag istorbohin</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> (na) segundo</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuto</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Payagan ang mga notification mula sa sumusunod:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/>mga oras</translation>
-<translation id="1398853756734560583">Maximize</translation>
-<translation id="4250229828105606438">Screenshot</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> mga oras</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> natitirang minuto</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> (na) GB</translation>
-<translation id="1901303067676059328">Piliin ang &amp;lahat</translation>
-<translation id="2168039046890040389">Pataas</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> mga araw</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mga minuto</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> segundo ang nakalipas</translation>
-<translation id="4927753642311223124">Walang makikita rito, magpatuloy.</translation>
-<translation id="2482878487686419369">Mga Abiso</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Mag-scroll dito</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> mga oras</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">I-Play/I-Pause ang Media</translation>
-<translation id="2148716181193084225">Ngayon</translation>
-<translation id="7960078400008666149">Huwag istorbohin sa loob ng isang oras</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuto ang nakalipas</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> mga araw</translation>
-<translation id="2190355936436201913">(walang laman)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> mga natitirang oras</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> natitirang segundo</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Mag-scroll Pakanan</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> natitirang oras</translation>
-<translation id="1413622004203049571">I-disable ang mga notification mula sa <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Tuktok</translation>
-<translation id="8331626408530291785">Mag-scroll Pataas</translation>
-<translation id="7907591526440419938">Buksan ang File</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> na oras ang nakalipas</translation>
-<translation id="815598010540052116">Mag-scroll Pababa</translation>
-<translation id="6808150112686056157">Media Ihinto</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Ipanumbalik</translation>
-<translation id="1243314992276662751">I-upload</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> natitirang araw</translation>
-<translation id="8179976553408161302">Pumasok</translation>
-<translation id="945522503751344254">Magpadala ng feedback...</translation>
-<translation id="9170848237812810038">&amp;I-undo</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> (na) oras ang nakalipas</translation>
-<translation id="6918245111648057970">Payagan ang mga notification mula sa sumusunod para sa bawat user:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> segundo ang nakalipas</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> (na) PB</translation>
-<translation id="2983818520079887040">Mga Setting...</translation>
-<translation id="6845383723252244143">Piliin ang Folder</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> (na) segundo</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> araw ang nakalipas</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> mga araw</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> oras</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto ang nakalipas</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> (na) GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> araw</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> segundo ang nakalipas</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> mga natitirang segundo</translation>
-<translation id="4570886800634958009">Palawakin ang notification</translation>
-<translation id="436869212180315161">Pindutin</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> segundo ang nakalipas</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> (na) TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> na minuto</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Isara</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuto ang nakalipas</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> (na) B/s</translation>
-<translation id="7649070708921625228">Tulong</translation>
-<translation id="6699343763173986273">Susunod na Track ng Media</translation>
-<translation id="8226233771743600312">Huwag istorbohin sa loob ng isang araw</translation>
-<translation id="7457942297256758195">I-clear Lahat</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> araw ang nakalipas</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mga minuto</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> mga natitirang araw</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> (na) minuto</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> mga oras na nalalabi</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> oras ang nakalipas</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> (na) segundo</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> mga natitirang araw</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> (na) PB/s</translation>
-<translation id="2743387203779672305">Kopyahin sa clipboard</translation>
-<translation id="8371695176452482769">Magsalita ngayon</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Huwag Istorbohin</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimize</translation>
-<translation id="6394627529324717982">Kuwit</translation>
-<translation id="3036649622769666520">Buksan ang Mga File</translation>
-<translation id="8328145009876646418">Kalwang Edge</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundo</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_fr.xtb b/chromium/ui/base/strings/ui_strings_fr.xtb
deleted file mode 100644
index 221f0268d9a..00000000000
--- a/chromium/ui/base/strings/ui_strings_fr.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="fr">
-<translation id="4820616160060340806">Commande + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Insér.</translation>
-<translation id="6135826906199951471">Suppr</translation>
-<translation id="528468243742722775">Fin</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secondes restantes</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secondes restantes</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutes restantes</translation>
-<translation id="1801827354178857021">Point</translation>
-<translation id="1190609913194133056">Centre de notification</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutes restantes</translation>
-<translation id="5613020302032141669">Gauche</translation>
-<translation id="4971687151119236543">Contenu multimédia : titre précédent</translation>
-<translation id="8602707065186045623">Fichier <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secondes</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> heures restantes</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> autres notifications de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Annuler</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> o</translation>
-<translation id="3660179305079774227">Haut</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> Mo/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> heures</translation>
-<translation id="3990502903496589789">Côté droit</translation>
-<translation id="9038489124413477075">Dossier sans nom</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutes</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> jours restants</translation>
-<translation id="932327136139879170">Début</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutes restantes</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> jours restants</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secondes restantes</translation>
-<translation id="3909791450649380159">Cou&amp;per</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Page Web sans titre</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">C&amp;oller</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> To</translation>
-<translation id="364720409959344976">Sélectionner le dossier d'importation</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">il y a <ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="3234408098842461169">Bas</translation>
-<translation id="3087734570205094154">Bas</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minute restante</translation>
-<translation id="1860796786778352021">Fermer la notification</translation>
-<translation id="6364916375976753737">Défilement vers la gauche</translation>
-<translation id="2629089419211541119">il y a <ph name="NUMBER_ONE"/> heure</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutes</translation>
-<translation id="6982279413068714821">il y a <ph name="NUMBER_DEFAULT"/> minutes</translation>
-<translation id="6945221475159498467">Sélectionner</translation>
-<translation id="6620110761915583480">Enregistrer le fichier</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute restante</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minute</translation>
-<translation id="8210608804940886430">Page suivante</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> jours</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> heures restantes</translation>
-<translation id="5329858601952122676">&amp;Supprimer</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secondes</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> Ko</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Hier</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutes restantes</translation>
-<translation id="6659594942844771486">Onglet</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> Mo</translation>
-<translation id="4988273303304146523">il y a <ph name="NUMBER_DEFAULT"/> jours</translation>
-<translation id="8428213095426709021">Paramètres</translation>
-<translation id="2497284189126895209">Tous les fichiers</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964">il y a <ph name="NUMBER_ONE"/> jour</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> seconde</translation>
-<translation id="7814458197256864873">&amp;Copier</translation>
-<translation id="3889424535448813030">Droite</translation>
-<translation id="4229495110203539533">il y a <ph name="NUMBER_ONE"/> seconde</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> secondes restantes</translation>
-<translation id="6829324100069873704">Revenir aux notifications</translation>
-<translation id="6528179044667508675">Ne pas déranger</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secondes</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Autoriser les notifications des éléments suivants :</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> heures</translation>
-<translation id="1398853756734560583">Agrandir</translation>
-<translation id="4250229828105606438">Capture d'écran</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> heures</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutes restantes</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> Go</translation>
-<translation id="1901303067676059328">&amp;Tout sélectionner</translation>
-<translation id="2168039046890040389">Page précédente</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> jours</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Aucune notification</translation>
-<translation id="2482878487686419369">Notifications</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Défilement jusqu'ici</translation>
-<translation id="4552416320897244156">PgSuiv</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> heures</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> Ko/s</translation>
-<translation id="8394908167088220973">Contenu multimédia : lecture/pause</translation>
-<translation id="2148716181193084225">Aujourd'hui</translation>
-<translation id="7960078400008666149">Ne pas déranger pendant une heure</translation>
-<translation id="4373894838514502496">il y a <ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> jours</translation>
-<translation id="2190355936436201913">(vide)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> heures restantes</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seconde restante</translation>
-<translation id="8447116497070723931">PgPréc</translation>
-<translation id="4588090240171750605">Défilement vers la droite</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> heure restante</translation>
-<translation id="1413622004203049571">Désactiver les notifications <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">En haut</translation>
-<translation id="8331626408530291785">Défilement vers le haut</translation>
-<translation id="7907591526440419938">Ouvrir le fichier</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Échap</translation>
-<translation id="2797524280730715045">il y a <ph name="NUMBER_DEFAULT"/> heures</translation>
-<translation id="815598010540052116">Défilement vers le bas</translation>
-<translation id="6808150112686056157">Contenu multimédia : arrêt</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaurer</translation>
-<translation id="1243314992276662751">Importer</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> jour restant</translation>
-<translation id="8179976553408161302">Entrer</translation>
-<translation id="945522503751344254">Envoyer le commentaire</translation>
-<translation id="9170848237812810038">Ann&amp;uler</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Autoriser les notifications issues des éléments suivants pour chaque utilisateur :</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> seconde</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> Po</translation>
-<translation id="2983818520079887040">Paramètres...</translation>
-<translation id="6845383723252244143">Sélectionner un dossier</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secondes</translation>
-<translation id="5583640892426849032">Retour</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> jours</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> heure</translation>
-<translation id="2679312662830811292">il y a <ph name="NUMBER_ONE"/> minute</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> Go/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> jour</translation>
-<translation id="9098468523912235228">il y a <ph name="NUMBER_DEFAULT"/> secondes</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secondes restantes</translation>
-<translation id="4570886800634958009">Développer la notification</translation>
-<translation id="436869212180315161">Cliquer</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> To/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Fermer</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> o/s</translation>
-<translation id="7649070708921625228">Aide</translation>
-<translation id="6699343763173986273">Contenu multimédia : titre suivant</translation>
-<translation id="8226233771743600312">Ne pas déranger pendant un jour</translation>
-<translation id="7457942297256758195">Tout effacer</translation>
-<translation id="822618367988303761">il y a <ph name="NUMBER_TWO"/> jours</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> jours restants</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> heures restantes</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Maj+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secondes</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secondes</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> jours restants</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> Po/s</translation>
-<translation id="2743387203779672305">Copier dans le Presse-papier</translation>
-<translation id="8371695176452482769">Parlez maintenant</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Ne pas déranger</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Réduire</translation>
-<translation id="6394627529324717982">Virgule</translation>
-<translation id="3036649622769666520">Ouvrir les fichiers</translation>
-<translation id="8328145009876646418">Côté gauche</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_gu.xtb b/chromium/ui/base/strings/ui_strings_gu.xtb
deleted file mode 100644
index 933abfeb3a5..00000000000
--- a/chromium/ui/base/strings/ui_strings_gu.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="gu">
-<translation id="4820616160060340806">કમાન્ડ+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">સમાપ્ત</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> સેકંડ બાકી</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> સેકન્ડ બાકી</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> મિનિટ બાકી</translation>
-<translation id="1801827354178857021">અવધિ</translation>
-<translation id="1190609913194133056">સૂચના કેન્દ્ર</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> મિનિટ બાકી</translation>
-<translation id="5613020302032141669">ડાબો એરો</translation>
-<translation id="4971687151119236543">મીડિયા પહેલાંનું ટ્રૅક</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ફાઇલ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> મિનિટ પહેલા</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> સેકંડ</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> કલાક બાકી</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> માંથી <ph name="NUMBER_OF_NOTIFICATIONS"/> વધુ</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">રદ કરો</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> અબજ</translation>
-<translation id="3660179305079774227">ઉપર એરો</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> કલાક</translation>
-<translation id="3990502903496589789">જમણી કિનારી</translation>
-<translation id="9038489124413477075">અનામાંકિત ફોલ્ડર</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> મિનિટ</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> દિવસ બાકી</translation>
-<translation id="932327136139879170">હોમ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> મિનિટ બાકી</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> દિવસ બાકી</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> સેકન્ડ બાકી</translation>
-<translation id="3909791450649380159">કા&amp;પો</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> મિનિટ બાકી</translation>
-<translation id="688711909580084195">શીર્ષક વિનાનું વેબપૃષ્ઠ </translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">પેસ્ટ કરો</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">અપલોડ કરવા માટે ફોલ્ડર પસંદ કરો</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">નીચલો એરો</translation>
-<translation id="3087734570205094154">તળિયું</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> મિનિટ બાકી</translation>
-<translation id="1860796786778352021">સૂચના બંધ છે</translation>
-<translation id="6364916375976753737">ડાબે સ્ક્રોલ કરો</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> મિનિટ</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">પસંદ કરો</translation>
-<translation id="6620110761915583480">ફાઇલ સાચવો</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> સેકંડ</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> કલાક</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> મિનિટ બાકી</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> મિનિટ</translation>
-<translation id="8210608804940886430">પૃષ્ઠ નીચે</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> દિવસ</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> કલાક બાકી</translation>
-<translation id="5329858601952122676">&amp;કાઢી નાખો</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> સેકંડ</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> મિનિટ</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">ગઈ કાલે</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> મિનિટ</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> મિનિટ બાકી</translation>
-<translation id="6659594942844771486">ટૅબ</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/>MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
-<translation id="2497284189126895209">બધી ફાઇલો</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> મિનિટ બાકી</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> સેકન્ડ</translation>
-<translation id="7814458197256864873">&amp;કૉપિ કરો</translation>
-<translation id="3889424535448813030">જમણો એરો</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> સેકંડ બાકી</translation>
-<translation id="6829324100069873704">સૂચનાઓ પર પાછા જાઓ</translation>
-<translation id="6528179044667508675">ખલેલ પાડશો નહીં</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> સેકંડ</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> મિનિટ</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> કલાક બાકી</translation>
-<translation id="7135556860107312402">નીચેના પરથી સૂચનાઓને મંજૂરી આપો:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> કલાક</translation>
-<translation id="1398853756734560583">મોટું કરો</translation>
-<translation id="4250229828105606438">સ્ક્રીનશૉટ</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> કલાક</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> મિનિટ બાકી</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;બધા પસંદ કરો</translation>
-<translation id="2168039046890040389">પૃષ્ઠ ઉપર</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> મિનિટ</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> દિવસ</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> મિનિટ્સ</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> મિનિટ</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">અહીં જોવા માટે કંઈ નથી, આગળ વધો.</translation>
-<translation id="2482878487686419369">સૂચનાઓ</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> દિવસ</translation>
-<translation id="3183922693828471536">અહીં સુધી સ્ક્રોલ કરો</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> કલાક</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">મીડિયા ચલાવો/થોભાવો</translation>
-<translation id="2148716181193084225">આજે</translation>
-<translation id="7960078400008666149">એક કલાક માટે ખલેલ પાડશો નહીં</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> દિવસ</translation>
-<translation id="2190355936436201913">(ખાલી)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> કલાક બાકી</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> સેકન્ડ બાકી</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">જમણે સ્ક્રોલ કરો</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> કલાક બાકી</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> તરફથી સૂચનાઓ અક્ષમ કરો</translation>
-<translation id="2666092431469916601">ઉપર</translation>
-<translation id="8331626408530291785">ઉપર સ્ક્રોલ કરો</translation>
-<translation id="7907591526440419938">ફાઇલ ખોલો</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> દિવસ બાકી</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">નીચે સ્ક્રોલ કરો</translation>
-<translation id="6808150112686056157">મીડિયા સ્ટોપ</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> મિનિટ બાકી</translation>
-<translation id="3157931365184549694">પુનઃસ્થાપિત કરો</translation>
-<translation id="1243314992276662751">અપલોડ કરો</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> દિવસ બાકી</translation>
-<translation id="8179976553408161302">દાખલ કરો</translation>
-<translation id="945522503751344254">પ્રતિસાદ મોકલો</translation>
-<translation id="9170848237812810038">&amp;પૂર્વવત્ કરો</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">દરેક વપરાશકર્તા માટે નીચેનામાંથી સૂચનાઓની પરવાનગી આપો:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> સેકંડ</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> મિનિટ બાકી</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">સેટિંગ્સ...</translation>
-<translation id="6845383723252244143">ફોલ્ડર પસંદ કરો</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> સેકંડ</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> સેકંડ</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> દિવસ</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> કલાક</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> કલાક પહેલા</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> દિવસ</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> સેકન્ડ બાકી</translation>
-<translation id="4570886800634958009">સૂચના વિસ્તૃત છે</translation>
-<translation id="436869212180315161">દબાવો</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> મિનિટ</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> મિનિટ બાકી</translation>
-<translation id="6040143037577758943">બંધ કરો</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">સહાય</translation>
-<translation id="6699343763173986273">મીડિયા આગલો ટ્રૅક</translation>
-<translation id="8226233771743600312">એક દિવસ માટે ખલેલ પાડશો નહીં</translation>
-<translation id="7457942297256758195">બધું સાફ કરો</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> મિનિટ</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> દિવસ બાકી</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> મિનિટ</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> કલાક બાકી</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> સેકંડ</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> સેકંડ</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> સેકંડ</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> દિવસ બાકી</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">ક્લિપબોર્ડ પર કૉપિ કરો</translation>
-<translation id="8371695176452482769">હવે બોલો</translation>
-<translation id="6965382102122355670">ઓકે</translation>
-<translation id="7850320739366109486">ખલેલ પાડશો નહીં</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> દિવસ પહેલા</translation>
-<translation id="5941711191222866238">નાનું કરો</translation>
-<translation id="6394627529324717982">અલ્પવિરામ</translation>
-<translation id="3036649622769666520">ફાઇલો ખોલો</translation>
-<translation id="8328145009876646418">ડાબી કિનારી</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> સેકંડ</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_hi.xtb b/chromium/ui/base/strings/ui_strings_hi.xtb
deleted file mode 100644
index b4da3a7514b..00000000000
--- a/chromium/ui/base/strings/ui_strings_hi.xtb
+++ /dev/null
@@ -1,194 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="hi">
-<translation id="4820616160060340806">आदेश+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">समाप्त</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> घंटे पहले</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> mins left</translation>
-<translation id="1801827354178857021">अवधि</translation>
-<translation id="1190609913194133056">सूचना केंद्र</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> मिनट शेष</translation>
-<translation id="5613020302032141669">बायां तीर</translation>
-<translation id="4971687151119236543">मीडिया पिछला ट्रैक</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> फ़ाइल (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> सेकंड</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> से <ph name="NUMBER_OF_NOTIFICATIONS"/> और हैं</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">रद्द करें</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> बाइट</translation>
-<translation id="3660179305079774227">ऊपर तीर</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> घंटे</translation>
-<translation id="3990502903496589789">दायां सिरा</translation>
-<translation id="9038489124413477075">अनाम फ़ोल्डर</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> मिनट</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
-<translation id="932327136139879170">मुख्यपृष्ठ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">&amp;काटें</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> मिनट शेष</translation>
-<translation id="688711909580084195">शीर्षक-रहित वेबपृष्ठ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> दिन पहले</translation>
-<translation id="5076340679995252485">&amp;चिपकाएं</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">अपलोड करने के लिए फ़ोल्‍डर चुनें</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">नीचे तीर</translation>
-<translation id="3087734570205094154">नीचे</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> मिनट शेष</translation>
-<translation id="1860796786778352021">सूचना बंद करें</translation>
-<translation id="6364916375976753737">बाएं स्क्रॉल करें</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> घंटे पहले</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> मिनट</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">चुनें</translation>
-<translation id="6620110761915583480">फ़ाइल सहेजें</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> सेकंड</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> घंटे</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> मिनट शेष</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> मिनट</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> दिन</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
-<translation id="5329858601952122676">&amp;हटाएं</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> सेकंड</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> मिनट</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> सेकंड पहले</translation>
-<translation id="7781829728241885113">बीता कल</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> मिनट</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
-<translation id="6659594942844771486">टैब</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> दिन पहले</translation>
-<translation id="8428213095426709021">सेटिंग</translation>
-<translation id="2497284189126895209">सभी फ़ाइलें</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> मिनट शेष</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> दिन पहले</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> सेकंड</translation>
-<translation id="7814458197256864873">&amp;प्रतिलिपि बनाएं</translation>
-<translation id="3889424535448813030">दायां तीर</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> सेकंड पहले
-</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> सेकंड शेष</translation>
-<translation id="6829324100069873704">सूचनाओं पर वापस जाएं</translation>
-<translation id="6528179044667508675">परेशान न करें</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> सेकंड</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> मिनट</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">निम्न से आने वाली सूचनाओं की अनुमति दें:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> घंटे</translation>
-<translation id="1398853756734560583">बड़ा करें</translation>
-<translation id="4250229828105606438">स्क्रीनशॉट</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> घंटे</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;सभी को चुनें</translation>
-<translation id="2168039046890040389">पृष्ठ ऊपर</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> मिनट</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> दिन</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> मिनट</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> मिनट</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">यहां देखने के लिए कुछ भी नहीं है, आगे चलें.</translation>
-<translation id="2482878487686419369">अधिसूचनाएं</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> दिन</translation>
-<translation id="3183922693828471536">यहां तक स्क्रॉल करें</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> घंटे</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">मीडिया चलाएं/रोकें</translation>
-<translation id="2148716181193084225">आज</translation>
-<translation id="7960078400008666149">एक घंटे तक परेशान न करें</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> दिन</translation>
-<translation id="2190355936436201913">(खाली)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hours left</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> सेकंड शेष</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">दाएं स्क्रॉल करें</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> घंटे शेष</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> से सूचनाएं अक्षम करें</translation>
-<translation id="2666092431469916601">शीर्ष</translation>
-<translation id="8331626408530291785">ऊपर स्क्रॉल करें</translation>
-<translation id="7907591526440419938">फ़ाइल खोलें</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> घंटे पहले</translation>
-<translation id="815598010540052116">नीचे स्क्रॉल करें</translation>
-<translation id="6808150112686056157">मीडिया रोकें</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">पुनर्स्थापित करें</translation>
-<translation id="1243314992276662751">अपलोड करें</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> दिन शेष</translation>
-<translation id="8179976553408161302">प्रविष्ट करें</translation>
-<translation id="945522503751344254">सुझाव भेजें</translation>
-<translation id="9170848237812810038">&amp;पूर्ववत् करें</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> घंटे पहले</translation>
-<translation id="6918245111648057970">प्रत्येक उपयोगकर्ता के लिए निम्न में से सूचनाओं की अनुमति दें:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> सेकंड</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> मिनट शेष</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">सेटिंग...</translation>
-<translation id="6845383723252244143">फ़ोल्डर को चुनें</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> सेकंड</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> सेकंड</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> दिन पहले</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> दिन</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/>घंटा</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> मिनट पहले
-</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> घंटे पहले</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> दिन</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> सेकंड पहले</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
-<translation id="4570886800634958009">सूचना विस्‍तार</translation>
-<translation id="436869212180315161">दबाएं</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> मिनट</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> मिनट शेष</translation>
-<translation id="6040143037577758943">बंद करें</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">सहायता</translation>
-<translation id="6699343763173986273">मीडिया अगला ट्रैक</translation>
-<translation id="8226233771743600312">एक दिन तक परेशान न करें</translation>
-<translation id="7457942297256758195">सभी साफ़ करें</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> दिन पहले</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> मिनट</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> days left</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> मिनट</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> घंटे पहले</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> सेकंड</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> सेकंड</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> सेकंड</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">क्लिपबोर्ड पर प्रतिलिपि बनाएं</translation>
-<translation id="8371695176452482769">अब बोलें</translation>
-<translation id="6965382102122355670">ठीक</translation>
-<translation id="7850320739366109486">परेशान न करें</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> दिन पहले</translation>
-<translation id="5941711191222866238">छोटा करें</translation>
-<translation id="6394627529324717982">अल्पविराम</translation>
-<translation id="3036649622769666520">फ़ाइलें खोलें</translation>
-<translation id="8328145009876646418">बायां सिरा</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> सेकंड</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_hr.xtb b/chromium/ui/base/strings/ui_strings_hr.xtb
deleted file mode 100644
index 9902a0c77a4..00000000000
--- a/chromium/ui/base/strings/ui_strings_hr.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="hr">
-<translation id="4820616160060340806">Naredba + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942">Preostalo sekundi: <ph name="NUMBER_FEW"/></translation>
-<translation id="9213479837033539041">Preostalo sekundi: <ph name="NUMBER_MANY"/></translation>
-<translation id="1209866192426315618">Preostalo minuta: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="1801827354178857021">Točka</translation>
-<translation id="1190609913194133056">Centar za obavijesti</translation>
-<translation id="7470933019269157899">Preostalo minuta: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="5613020302032141669">Strelica lijevo</translation>
-<translation id="4971687151119236543">Prethodni zapis Medija</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Datoteka (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252">Broj sekundi: <ph name="NUMBER_TWO"/></translation>
-<translation id="7511635910912978956">Preostali sati: <ph name="NUMBER_FEW"/></translation>
-<translation id="8717309436826820190">Još ovoliko obavijesti: <ph name="NUMBER_OF_NOTIFICATIONS"/> s usluge <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Odustani</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Strelica prema gore</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928">Broj sati: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3990502903496589789">Desni rub</translation>
-<translation id="9038489124413477075">Neimenovana mapa</translation>
-<translation id="8507996248087185956">Broj minuta: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3520476450377425184">Preostalo dana: <ph name="NUMBER_MANY"/></translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">Preostalo minuta: <ph name="NUMBER_MANY"/></translation>
-<translation id="8666066831007952346">Preostalo dana: <ph name="NUMBER_TWO"/></translation>
-<translation id="6390842777729054533">Preostalo sekundi: <ph name="NUMBER_ZERO"/></translation>
-<translation id="3909791450649380159">Iz&amp;reži</translation>
-<translation id="2560788951337264832">Preostalo minuta: <ph name="NUMBER_ZERO"/></translation>
-<translation id="688711909580084195">Web-stranica bez naslova</translation>
-<translation id="3353284378027041011">Prije <ph name="NUMBER_FEW"/> dana</translation>
-<translation id="5076340679995252485">&amp;Zalijepi</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Odabir mape za prijenos</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Prije <ph name="NUMBER_TWO"/> minute</translation>
-<translation id="3234408098842461169">Strelica dolje</translation>
-<translation id="3087734570205094154">Donji</translation>
-<translation id="5935630983280450497">Preostalo minuta: <ph name="NUMBER_ONE"/></translation>
-<translation id="1860796786778352021">Zatvaranje obavijesti</translation>
-<translation id="6364916375976753737">Pomakni se lijevo</translation>
-<translation id="2629089419211541119">Prije <ph name="NUMBER_ONE"/> sat</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuta</translation>
-<translation id="6982279413068714821">Prije <ph name="NUMBER_DEFAULT"/> minuta</translation>
-<translation id="6945221475159498467">Odaberi</translation>
-<translation id="6620110761915583480">Spremi datoteku</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Preostalo minuta: <ph name="NUMBER_ONE"/></translation>
-<translation id="2953767478223974804">Broj minuta: <ph name="NUMBER_ONE"/></translation>
-<translation id="8210608804940886430">Stranica prema dolje</translation>
-<translation id="1572103024875503863">Broj dana: <ph name="NUMBER_MANY"/></translation>
-<translation id="7163503212501929773">Preostalo sati: <ph name="NUMBER_MANY"/></translation>
-<translation id="5329858601952122676">&amp;Obriši</translation>
-<translation id="8088823334188264070">Sekundi: <ph name="NUMBER_MANY"/></translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Danas</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478">Preostalo minuta: <ph name="NUMBER_FEW"/></translation>
-<translation id="6659594942844771486">Kartica</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Prije <ph name="NUMBER_DEFAULT"/> dana</translation>
-<translation id="8428213095426709021">Postavke</translation>
-<translation id="2497284189126895209">Sve datoteke</translation>
-<translation id="7487278341251176613">Preostalo minuta: <ph name="NUMBER_TWO"/></translation>
-<translation id="5110450810124758964">Prije <ph name="NUMBER_ONE"/> dan</translation>
-<translation id="2820806154655529776">Broj sekundi: <ph name="NUMBER_ONE"/></translation>
-<translation id="7814458197256864873">&amp;Kopiraj</translation>
-<translation id="3889424535448813030">Strelica desno</translation>
-<translation id="4229495110203539533">Prije <ph name="NUMBER_ONE"/> sekundu</translation>
-<translation id="2544782972264605588">Preostalo sekundi: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6829324100069873704">Natrag na obavijesti</translation>
-<translation id="6528179044667508675">Ne ometaj</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundi</translation>
-<translation id="290555789621781773">Broj minuta: <ph name="NUMBER_TWO"/></translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Omogućite obavijesti iz sljedećih izvora:</translation>
-<translation id="8112886015144590373">Broj sati: <ph name="NUMBER_FEW"/></translation>
-<translation id="1398853756734560583">Maksimiziraj</translation>
-<translation id="4250229828105606438">Snimka zaslona</translation>
-<translation id="6690744523875189208">Broj sati: <ph name="NUMBER_TWO"/></translation>
-<translation id="5260878308685146029">Preostalo minuta: <ph name="NUMBER_TWO"/></translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Odaberi &amp;sve</translation>
-<translation id="2168039046890040389">Stranica prema gore</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581">Broj dana: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734">Broj minuta: <ph name="NUMBER_MANY"/></translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Nema nikakvih obavijesti.</translation>
-<translation id="2482878487686419369">Obavijesti</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Pomakni ovdje</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401">Sati: <ph name="NUMBER_MANY"/></translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Reproduciraj/pauziraj Medije</translation>
-<translation id="2148716181193084225">Danas</translation>
-<translation id="7960078400008666149">Ne ometaj jedan sat</translation>
-<translation id="4373894838514502496">Prije <ph name="NUMBER_FEW"/> min</translation>
-<translation id="4115153316875436289">Dana: <ph name="NUMBER_TWO"/></translation>
-<translation id="2190355936436201913">(prazno)</translation>
-<translation id="1164369517022005061">Preostalo sati: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="152482086482215392">Preostalo sekundi: <ph name="NUMBER_ONE"/></translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Pomakni se desno</translation>
-<translation id="7414887922320653780">Preostalo sati: <ph name="NUMBER_ONE"/></translation>
-<translation id="1413622004203049571">Onemogući obavijesti pošiljatelja <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Gornji</translation>
-<translation id="8331626408530291785">Pomakni se gore</translation>
-<translation id="7907591526440419938">Otvori datoteku</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Prije <ph name="NUMBER_DEFAULT"/> sati</translation>
-<translation id="815598010540052116">Pomakni se dolje</translation>
-<translation id="6808150112686056157">Zaustavi Medije</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Vrati</translation>
-<translation id="1243314992276662751">Prenesi</translation>
-<translation id="50030952220075532">Preostalo dana: <ph name="NUMBER_ONE"/></translation>
-<translation id="8179976553408161302">Pridružite se</translation>
-<translation id="945522503751344254">Slanje povratnih informacija</translation>
-<translation id="9170848237812810038">&amp;Poništi</translation>
-<translation id="1285266685456062655">Prije <ph name="NUMBER_FEW"/> sata</translation>
-<translation id="6918245111648057970">Za svakog korisnika dozvoli obavijesti sljedećih usluga:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="3994835489895548312">Preostalo minuta: <ph name="NUMBER_MANY"/></translation>
-<translation id="6358975074282722691">Prije <ph name="NUMBER_TWO"/> sekunde</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Postavke...</translation>
-<translation id="6845383723252244143">Odabir mape</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunde</translation>
-<translation id="1095623615273566396">Broj sekundi: <ph name="NUMBER_FEW"/></translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920">Broj dana: <ph name="NUMBER_FEW"/></translation>
-<translation id="5116333507878097773">Broj sati: <ph name="NUMBER_ONE"/></translation>
-<translation id="2679312662830811292">Prije <ph name="NUMBER_ONE"/> minutu</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>dan</translation>
-<translation id="9098468523912235228">Prije <ph name="NUMBER_DEFAULT"/> sekundi</translation>
-<translation id="494645311413743213">Preostalo sekundi <ph name="NUMBER_TWO"/></translation>
-<translation id="4570886800634958009">Proširivanje obavijesti</translation>
-<translation id="436869212180315161">Pritisnite</translation>
-<translation id="4860787810836767172">Prije <ph name="NUMBER_FEW"/> sek</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">Preostalo minuta: <ph name="NUMBER_FEW"/></translation>
-<translation id="6040143037577758943">Zatvori</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Pomoć</translation>
-<translation id="6699343763173986273">Sljedeći zapis Medija</translation>
-<translation id="8226233771743600312">Ne ometaj jedan dan</translation>
-<translation id="7457942297256758195">Očisti sve</translation>
-<translation id="822618367988303761">Prije <ph name="NUMBER_TWO"/> dana</translation>
-<translation id="4745438305783437565">Broj minuta: <ph name="NUMBER_FEW"/></translation>
-<translation id="1963692530539281474">Preostalo dana: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
-<translation id="5906719743126878045">Preostalo sati: <ph name="NUMBER_TWO"/></translation>
-<translation id="8959208747503200525">Prije <ph name="NUMBER_TWO"/> sata</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940">Sekundi: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="4197700912384709145">Sekundi: <ph name="NUMBER_ZERO"/></translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382">Preostalo dana: <ph name="NUMBER_FEW"/></translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopiraj u međuspremnik</translation>
-<translation id="8371695176452482769">Govorite sad</translation>
-<translation id="6965382102122355670">U redu</translation>
-<translation id="7850320739366109486">Ne ometaj</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimiziraj</translation>
-<translation id="6394627529324717982">Zarez</translation>
-<translation id="3036649622769666520">Otvori datoteke</translation>
-<translation id="8328145009876646418">Lijevi rub</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_hu.xtb b/chromium/ui/base/strings/ui_strings_hu.xtb
deleted file mode 100644
index 3728e235a54..00000000000
--- a/chromium/ui/base/strings/ui_strings_hu.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="hu">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">Befejezés</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> másodperc van hátra</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> másodperc van hátra</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> perc van hátra</translation>
-<translation id="1801827354178857021">Pont</translation>
-<translation id="1190609913194133056">Értesítési központ</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> perc van hátra</translation>
-<translation id="5613020302032141669">Bal nyíl</translation>
-<translation id="4971687151119236543">Előző szám</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> fájl (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> másodperc</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> óra van hátra</translation>
-<translation id="8717309436826820190">Még <ph name="NUMBER_OF_NOTIFICATIONS"/> a következőtől: <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Mégse</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> bájt</translation>
-<translation id="3660179305079774227">Felfelé nyíl</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> óra</translation>
-<translation id="3990502903496589789">Jobb sarok</translation>
-<translation id="9038489124413477075">Név nélküli mappa</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> perc</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> nap van hátra</translation>
-<translation id="932327136139879170">Főoldal</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> perc van hátra</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> nap van hátra</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> másodperc van hátra</translation>
-<translation id="3909791450649380159">Ki&amp;vágás</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> perc van hátra</translation>
-<translation id="688711909580084195">Névtelen weboldal</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Beillesztés</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Mappa kiválasztása a feltöltéshez</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Lefelé nyíl</translation>
-<translation id="3087734570205094154">Alja</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> perc van hátra</translation>
-<translation id="1860796786778352021">Értesítés bezárása</translation>
-<translation id="6364916375976753737">Görgetés balra</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> órája</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> perc</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> perce</translation>
-<translation id="6945221475159498467">Kiválasztás</translation>
-<translation id="6620110761915583480">Fájl mentése</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> másodperc</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> perc van hátra</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> perc</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> nap</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> óra van hátra</translation>
-<translation id="5329858601952122676">&amp;Törlés</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> másodperc</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> perc</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Tegnap</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> perc</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> perc van hátra</translation>
-<translation id="6659594942844771486">Lap</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> napja</translation>
-<translation id="8428213095426709021">Beállítások</translation>
-<translation id="2497284189126895209">Minden fájl</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> perc van hátra</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> napja</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> másodperc</translation>
-<translation id="7814458197256864873">&amp;Másolás</translation>
-<translation id="3889424535448813030">Jobb nyíl</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> másodperce</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> másodperc van hátra</translation>
-<translation id="6829324100069873704">Vissza az értesítésekhez</translation>
-<translation id="6528179044667508675">Ne zavarj</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> másodperc</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> perc</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Értesítések engedélyezése a következőtől:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> óra</translation>
-<translation id="1398853756734560583">Teljes méret</translation>
-<translation id="4250229828105606438">Képernyőkép</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> óra</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> perc van hátra</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Össz&amp;es kiválasztása</translation>
-<translation id="2168039046890040389">Oldal fel</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> nap</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> perc</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> perc</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Itt nincs semmi, továbbmehet.</translation>
-<translation id="2482878487686419369">Értesítések</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Görgessen ide</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> óra</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Lejátszás/szüneteltetés</translation>
-<translation id="2148716181193084225">Ma</translation>
-<translation id="7960078400008666149">Ne zavarj egy óráig</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> nap</translation>
-<translation id="2190355936436201913">(üres)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> óra van hátra</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> másodperc van hátra</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Görgetés jobbra</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> óra van hátra</translation>
-<translation id="1413622004203049571">A(z) <ph name="NOTIFIER_NAME"/> értesítéseinek kikapcsolása</translation>
-<translation id="2666092431469916601">Felülre</translation>
-<translation id="8331626408530291785">Görgetés felfelé</translation>
-<translation id="7907591526440419938">Fájl megnyitása</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> órája</translation>
-<translation id="815598010540052116">Görgetés lefelé</translation>
-<translation id="6808150112686056157">Leállítás</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Visszaállítás</translation>
-<translation id="1243314992276662751">Feltöltés</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> nap van hátra</translation>
-<translation id="8179976553408161302">Belépés</translation>
-<translation id="945522503751344254">Visszajelzés küldése</translation>
-<translation id="9170848237812810038">&amp;Visszavonás</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Értesítések engedélyezése mindegyik felhasználónak a következőtől:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> másodperc</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> perc van hátra</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Beállítások...</translation>
-<translation id="6845383723252244143">Mappa választása</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> másodperc</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> másodperc</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> nap</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> óra</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> perce</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> nap</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> másodperce</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> másodperc van hátra.</translation>
-<translation id="4570886800634958009">Értesítés kibontása</translation>
-<translation id="436869212180315161">Sajtó</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> perc</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> perc van hátra</translation>
-<translation id="6040143037577758943">Bezárás</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Súgó</translation>
-<translation id="6699343763173986273">Következő szám</translation>
-<translation id="8226233771743600312">Ne zavarj egy napig</translation>
-<translation id="7457942297256758195">Összes törlése</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> perc</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> nap van hátra</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> perc</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> óra van hátra</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> másodperc</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> másodperc</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> másodperc</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> nap van hátra</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Másolás a vágólapra</translation>
-<translation id="8371695176452482769">Most beszéljen</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Ne zavarj</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Kicsinyítés</translation>
-<translation id="6394627529324717982">Vessző</translation>
-<translation id="3036649622769666520">Fájlok megnyitása</translation>
-<translation id="8328145009876646418">Bal sarok</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> másodperc</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_id.xtb b/chromium/ui/base/strings/ui_strings_id.xtb
deleted file mode 100644
index 3b382e49c6e..00000000000
--- a/chromium/ui/base/strings/ui_strings_id.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="id">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">Berakhir</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> jam yang lalu</translation>
-<translation id="6310545596129886942">Tersisa <ph name="NUMBER_FEW"/> detik</translation>
-<translation id="9213479837033539041">Tersisa <ph name="NUMBER_MANY"/> detik</translation>
-<translation id="1209866192426315618">Tersisa <ph name="NUMBER_DEFAULT"/> menit</translation>
-<translation id="1801827354178857021">Titik</translation>
-<translation id="1190609913194133056">Pusat Pemberitahuan</translation>
-<translation id="7470933019269157899">Tersisa <ph name="NUMBER_DEFAULT"/> menit</translation>
-<translation id="5613020302032141669">Panah Kiri</translation>
-<translation id="4971687151119236543">Lacak Media Sebelumnya</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> detik</translation>
-<translation id="7511635910912978956">Tersisa <ph name="NUMBER_FEW"/> jam</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> lainnya dari <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Batal</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Panah Atas</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/dtk</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> jam</translation>
-<translation id="3990502903496589789">Tepi Kanan</translation>
-<translation id="9038489124413477075">Folder Tanpa Nama</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> menit</translation>
-<translation id="3520476450377425184">Tersisa <ph name="NUMBER_MANY"/> hari</translation>
-<translation id="932327136139879170">Beranda</translation>
-<translation id="5600907569873192868">Tersisa <ph name="NUMBER_MANY"/> menit</translation>
-<translation id="8666066831007952346">Tersisa <ph name="NUMBER_TWO"/> hari</translation>
-<translation id="6390842777729054533">Tersisa <ph name="NUMBER_ZERO"/> detik</translation>
-<translation id="3909791450649380159">Po&amp;tong</translation>
-<translation id="2560788951337264832">Tersisa <ph name="NUMBER_ZERO"/> menit</translation>
-<translation id="688711909580084195">Laman Web Tanpa Judul</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> hari yang lalu</translation>
-<translation id="5076340679995252485">Tem&amp;pel</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Pilih Folder untuk Diunggah</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mnt. yang lalu</translation>
-<translation id="3234408098842461169">Panah Bawah</translation>
-<translation id="3087734570205094154">Bawah</translation>
-<translation id="5935630983280450497">Tersisa <ph name="NUMBER_ONE"/> menit</translation>
-<translation id="1860796786778352021">Tutup pemberitahuan</translation>
-<translation id="6364916375976753737">Gulir ke Kiri</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> jam yang lalu</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> menit</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mnt. yang lalu</translation>
-<translation id="6945221475159498467">Pilih</translation>
-<translation id="6620110761915583480">Simpan File</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> detik</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Tersisa <ph name="NUMBER_ONE"/> menit</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> menit</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> hari</translation>
-<translation id="7163503212501929773">Tersisa <ph name="NUMBER_MANY"/> jam</translation>
-<translation id="5329858601952122676">&amp;Hapus</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> detik</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> menit</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> dtk. yang lalu</translation>
-<translation id="7781829728241885113">Kemarin</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> menit</translation>
-<translation id="50960180632766478">Tersisa <ph name="NUMBER_FEW"/> menit</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> hari yang lalu</translation>
-<translation id="8428213095426709021">Setelan</translation>
-<translation id="2497284189126895209">Semua Jenis File</translation>
-<translation id="7487278341251176613">Tersisa <ph name="NUMBER_TWO"/> menit</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> hari yang lalu</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> detik</translation>
-<translation id="7814458197256864873">&amp;Salin</translation>
-<translation id="3889424535448813030">Panah Kanan</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> dtk. yang lalu</translation>
-<translation id="2544782972264605588">Tersisa <ph name="NUMBER_DEFAULT"/> detik</translation>
-<translation id="6829324100069873704">Kembali ke pemberitahuan</translation>
-<translation id="6528179044667508675">Jangan ganggu</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> detik</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> menit</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Izinkan pemberitahuan dari yang berikut:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> jam</translation>
-<translation id="1398853756734560583">Perbesar</translation>
-<translation id="4250229828105606438">Tangkapan layar</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> jam</translation>
-<translation id="5260878308685146029">Tersisa <ph name="NUMBER_TWO"/> menit</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Pilih semu&amp;a</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> hari</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> menit</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> menit</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> dtk. yang lalu</translation>
-<translation id="4927753642311223124">Tidak ada apa-apa di sini, lihat yang lain saja.</translation>
-<translation id="2482878487686419369">Pemberitahuan</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Gulir ke Sini</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> jam</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/dtk</translation>
-<translation id="8394908167088220973">Putar/Jeda Media</translation>
-<translation id="2148716181193084225">Hari ini</translation>
-<translation id="7960078400008666149">Jangan ganggu selama satu jam</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mnt. yang lalu</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> hari</translation>
-<translation id="2190355936436201913">(kosong)</translation>
-<translation id="1164369517022005061">Tersisa <ph name="NUMBER_DEFAULT"/> jam</translation>
-<translation id="152482086482215392">Tersisa <ph name="NUMBER_ONE"/> detik</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Gulir ke Kanan</translation>
-<translation id="7414887922320653780">Tersisa <ph name="NUMBER_ONE"/> jam</translation>
-<translation id="1413622004203049571">Nonaktifkan pemberitahuan dari <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Atas</translation>
-<translation id="8331626408530291785">Gulir ke Atas</translation>
-<translation id="7907591526440419938">Buka File</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> jam yang lalu</translation>
-<translation id="815598010540052116">Gulir ke Bawah</translation>
-<translation id="6808150112686056157">Hentikan Media</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Pulihkan</translation>
-<translation id="1243314992276662751">Unggah</translation>
-<translation id="50030952220075532">Tersisa <ph name="NUMBER_ONE"/> hari</translation>
-<translation id="8179976553408161302">Masuk</translation>
-<translation id="945522503751344254">Kirim masukan</translation>
-<translation id="9170848237812810038">&amp;Urung</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> jam yang lalu</translation>
-<translation id="6918245111648057970">Mengizinkan pemberitahuan dari yang berikut untuk tiap pengguna:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> detik</translation>
-<translation id="3994835489895548312">Tersisa <ph name="NUMBER_MANY"/> menit</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> dtk. yang lalu</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Setelan...</translation>
-<translation id="6845383723252244143">Pilih Folder</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> detik</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> detik</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> hari yang lalu</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> hari</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> jam</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> mnt. yang lalu</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/dtk</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> hari</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> dtk. yang lalu</translation>
-<translation id="494645311413743213">Tersisa <ph name="NUMBER_TWO"/> detik</translation>
-<translation id="4570886800634958009">Luaskan pemberitahuan</translation>
-<translation id="436869212180315161">Tekan</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> dtk. yang lalu</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/dtk</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> menit</translation>
-<translation id="1858722859751911017">Tersisa <ph name="NUMBER_FEW"/> menit</translation>
-<translation id="6040143037577758943">Tutup</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mnt. yang lalu</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/dtk</translation>
-<translation id="7649070708921625228">Bantuan</translation>
-<translation id="6699343763173986273">Lacak Media Berikutnya</translation>
-<translation id="8226233771743600312">Jangan ganggu selama satu hari</translation>
-<translation id="7457942297256758195">Hapus Semua</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> hari yang lalu</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> menit</translation>
-<translation id="1963692530539281474">Tersisa <ph name="NUMBER_DEFAULT"/> hari</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> menit</translation>
-<translation id="5906719743126878045">Tersisa <ph name="NUMBER_TWO"/> jam</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> jam yang lalu</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> detik</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> detik</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> detik</translation>
-<translation id="3759876923365568382">Tersisa <ph name="NUMBER_FEW"/> hari</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/dtk</translation>
-<translation id="2743387203779672305">Salin ke papan klip</translation>
-<translation id="8371695176452482769">Bicaralah sekarang</translation>
-<translation id="6965382102122355670">Oke</translation>
-<translation id="7850320739366109486">Jangan Ganggu</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Perkecil</translation>
-<translation id="6394627529324717982">Koma</translation>
-<translation id="3036649622769666520">Buka File</translation>
-<translation id="8328145009876646418">Tepi Kiri</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> detik</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_it.xtb b/chromium/ui/base/strings/ui_strings_it.xtb
deleted file mode 100644
index 94ca0e0dd7e..00000000000
--- a/chromium/ui/base/strings/ui_strings_it.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="it">
-<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Canc</translation>
-<translation id="528468243742722775">Fine</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> ore fa</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sec. rimanenti</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sec. rimanenti</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min. rimanenti</translation>
-<translation id="1801827354178857021">Punto</translation>
-<translation id="1190609913194133056">Centro notifiche</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuti rimanenti</translation>
-<translation id="5613020302032141669">Freccia sinistra</translation>
-<translation id="4971687151119236543">Traccia precedente contenuti multimediali</translation>
-<translation id="8602707065186045623">File <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sec.</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ore rimanenti</translation>
-<translation id="8717309436826820190">Altre <ph name="NUMBER_OF_NOTIFICATIONS"/> da <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Annulla</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Freccia SU</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ore</translation>
-<translation id="3990502903496589789">Margine destro</translation>
-<translation id="9038489124413477075">Cartella senza nome</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> giorni rimanenti</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min. rimanenti</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> giorni rimanenti</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sec. rimanenti</translation>
-<translation id="3909791450649380159">T&amp;aglia</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Pagina web senza titolo</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> giorni fa</translation>
-<translation id="5076340679995252485">&amp;Incolla</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Seleziona la cartella da caricare</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuti fa</translation>
-<translation id="3234408098842461169">Freccia GIÙ</translation>
-<translation id="3087734570205094154">In basso</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min. rimanente</translation>
-<translation id="1860796786778352021">Chiusura notifica</translation>
-<translation id="6364916375976753737">Scorri a sinistra</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ora fa</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuti</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuti fa</translation>
-<translation id="6945221475159498467">Seleziona</translation>
-<translation id="6620110761915583480">Salva file</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> secondi</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto rimanente</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8210608804940886430">Pagina giù</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> giorni</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ore rimanenti</translation>
-<translation id="5329858601952122676">&amp;Elimina</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sec.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secondi fa</translation>
-<translation id="7781829728241885113">Ieri</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min. rimanenti</translation>
-<translation id="6659594942844771486">TAB</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> giorni fa</translation>
-<translation id="8428213095426709021">Impostazioni</translation>
-<translation id="2497284189126895209">Tutti i file</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> giorno fa</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec.</translation>
-<translation id="7814458197256864873">&amp;Copia</translation>
-<translation id="3889424535448813030">Freccia destra</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> secondo fa</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sec. rimanenti</translation>
-<translation id="6829324100069873704">Torna alle notifiche</translation>
-<translation id="6528179044667508675">Non disturbare</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secondi</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Consenti notifiche da:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ore</translation>
-<translation id="1398853756734560583">Ingrandisci</translation>
-<translation id="4250229828105606438">Screenshot</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ore</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min. rimanenti</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Seleziona &amp;tutto</translation>
-<translation id="2168039046890040389">Pagina su</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> giorni</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secondi fa</translation>
-<translation id="4927753642311223124">Nessuna notifica.</translation>
-<translation id="2482878487686419369">Notifiche</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Scorri fino a qui</translation>
-<translation id="4552416320897244156">PGGIÙ</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ore</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Play/Pausa contenuti multimediali</translation>
-<translation id="2148716181193084225">Oggi</translation>
-<translation id="7960078400008666149">Non disturbare per un'ora</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuti fa</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> giorni</translation>
-<translation id="2190355936436201913">(vuoto)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ore rimanenti</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec. rimanente</translation>
-<translation id="8447116497070723931">PGSU</translation>
-<translation id="4588090240171750605">Scorri a destra</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ora rimanente</translation>
-<translation id="1413622004203049571">Disabilita notifiche da <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">In alto</translation>
-<translation id="8331626408530291785">Scorri verso l'alto</translation>
-<translation id="7907591526440419938">Apri file</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ore fa</translation>
-<translation id="815598010540052116">Scorri verso il basso</translation>
-<translation id="6808150112686056157">Interrompi contenuti multimediali</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Ripristina</translation>
-<translation id="1243314992276662751">Carica</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> giorno rimanente</translation>
-<translation id="8179976553408161302">Invia</translation>
-<translation id="945522503751344254">Invia feedback</translation>
-<translation id="9170848237812810038">&amp;Annulla</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ore fa</translation>
-<translation id="6918245111648057970">Consenti a ogni utente di ricevere le notifiche di:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> secondo</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secondi fa</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Impostazioni...</translation>
-<translation id="6845383723252244143">Seleziona cartella</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sec.</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> giorni fa</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> giorni</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ora</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto fa</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> giorno</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secondi fa</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sec. rimanenti</translation>
-<translation id="4570886800634958009">Espansione notifica</translation>
-<translation id="436869212180315161">Premi</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secondi fa</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Chiudi</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuti fa</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Guida</translation>
-<translation id="6699343763173986273">Traccia successiva contenuti multimediali</translation>
-<translation id="8226233771743600312">Non disturbare per un giorno</translation>
-<translation id="7457942297256758195">Cancella tutto</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> giorni fa</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> giorni rimanenti</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ore rimanenti</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> ore fa</translation>
-<translation id="8400147561352026160">Maiusc+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sec.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sec.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> giorni rimanenti</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copia negli appunti</translation>
-<translation id="8371695176452482769">Parla adesso</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Non disturbare</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Riduci a icona</translation>
-<translation id="6394627529324717982">Virgola</translation>
-<translation id="3036649622769666520">Apri file</translation>
-<translation id="8328145009876646418">Margine sinistro</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_iw.xtb b/chromium/ui/base/strings/ui_strings_iw.xtb
deleted file mode 100644
index 6923c75f045..00000000000
--- a/chromium/ui/base/strings/ui_strings_iw.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="iw">
-<translation id="4820616160060340806">פקודה+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798">לפני <ph name="NUMBER_MANY"/> שעות</translation>
-<translation id="6310545596129886942">נותרו <ph name="NUMBER_FEW"/> שניות</translation>
-<translation id="9213479837033539041">נותרו <ph name="NUMBER_MANY"/> שניות</translation>
-<translation id="1209866192426315618">נותרו <ph name="NUMBER_DEFAULT"/> דקות</translation>
-<translation id="1801827354178857021">נקודה</translation>
-<translation id="1190609913194133056">מרכז התראות</translation>
-<translation id="7470933019269157899">נותרו <ph name="NUMBER_DEFAULT"/> דקות</translation>
-<translation id="5613020302032141669">חץ לשמאל</translation>
-<translation id="4971687151119236543">רצועה קודמת במדיה</translation>
-<translation id="8602707065186045623">קובץ <ph name="SAVEAS_EXTENSION_TYPE"/> (<ph name="SAVEAS_EXTENSION_NAME"/>.)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> שניות</translation>
-<translation id="7511635910912978956">נותרו <ph name="NUMBER_FEW"/> שעות</translation>
-<translation id="8717309436826820190">עוד <ph name="NUMBER_OF_NOTIFICATIONS"/> מ-<ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">ביטול</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">חץ למעלה</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> שעות</translation>
-<translation id="3990502903496589789">קצה ימני</translation>
-<translation id="9038489124413477075">תיקייה ללא שם</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> דקות</translation>
-<translation id="3520476450377425184">נותרו <ph name="NUMBER_MANY"/> ימים</translation>
-<translation id="932327136139879170">בית</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> דקות נותרו</translation>
-<translation id="8666066831007952346">נותרו <ph name="NUMBER_TWO"/> ימים</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> שניות נותרו</translation>
-<translation id="3909791450649380159">גז&amp;ור</translation>
-<translation id="2560788951337264832">נותרו <ph name="NUMBER_ZERO"/> דקות</translation>
-<translation id="688711909580084195">דף אינטרנט ללא כותרת</translation>
-<translation id="3353284378027041011">לפני <ph name="NUMBER_FEW"/> ימים</translation>
-<translation id="5076340679995252485">&amp;הדבק</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">בחירת תיקיה להעלאה</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">לפני <ph name="NUMBER_TWO"/> דקות</translation>
-<translation id="3234408098842461169">חץ למטה</translation>
-<translation id="3087734570205094154">תחתית</translation>
-<translation id="5935630983280450497">נותרה <ph name="NUMBER_ONE"/> דקה</translation>
-<translation id="1860796786778352021">סגירת הודעה</translation>
-<translation id="6364916375976753737">גלול שמאלה</translation>
-<translation id="2629089419211541119">לפני <ph name="NUMBER_ONE"/> שעה</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> דקות</translation>
-<translation id="6982279413068714821">לפני <ph name="NUMBER_DEFAULT"/> דקות</translation>
-<translation id="6945221475159498467">בחר</translation>
-<translation id="6620110761915583480">שמור קובץ</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> שניות</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">נותרה דקה <ph name="NUMBER_ONE"/></translation>
-<translation id="2953767478223974804">דקה <ph name="NUMBER_ONE"/></translation>
-<translation id="8210608804940886430">דף למטה</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ימים</translation>
-<translation id="7163503212501929773">נותרו <ph name="NUMBER_MANY"/> שעות</translation>
-<translation id="5329858601952122676">&amp;מחק</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> שניות</translation>
-<translation id="8901569739625249689">‏<ph name="QUANTITY"/> KB‏</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> דקות</translation>
-<translation id="7275974018215686543">לפני <ph name="NUMBER_MANY"/> שניות</translation>
-<translation id="7781829728241885113">אתמול</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> דקות</translation>
-<translation id="50960180632766478">נותרו <ph name="NUMBER_FEW"/> דקות</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">לפני <ph name="NUMBER_DEFAULT"/> ימים</translation>
-<translation id="8428213095426709021">הגדרות</translation>
-<translation id="2497284189126895209">כל הקבצים</translation>
-<translation id="7487278341251176613">נותרו <ph name="NUMBER_TWO"/> דקות</translation>
-<translation id="5110450810124758964">לפני <ph name="NUMBER_ONE"/> ימים</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> שניה</translation>
-<translation id="7814458197256864873">&amp;העתק</translation>
-<translation id="3889424535448813030">חץ לימין</translation>
-<translation id="4229495110203539533">לפני <ph name="NUMBER_ONE"/> שניות</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> שניות נותרו</translation>
-<translation id="6829324100069873704">חזור להודעות</translation>
-<translation id="6528179044667508675">נא לא להפריע</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> שניות</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> דקות</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">אפשר התראות ממקורות אלה:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> שעות</translation>
-<translation id="1398853756734560583">הגדל</translation>
-<translation id="4250229828105606438">צילום מסך</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> שעות</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> דקות נותרו</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">בחר &amp;הכל</translation>
-<translation id="2168039046890040389">דף למעלה</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ימים</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> דקות</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> דקה</translation>
-<translation id="8448317557906454022">לפני <ph name="NUMBER_ZERO"/> שניות</translation>
-<translation id="4927753642311223124">אין התראות להצגה, המשך הלאה.</translation>
-<translation id="2482878487686419369">התראות</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">גלול ל'כאן'</translation>
-<translation id="4552416320897244156">דף למטה</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> שעות</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s‎</translation>
-<translation id="8394908167088220973">הפעלה/השהיה של המדיה</translation>
-<translation id="2148716181193084225">היום</translation>
-<translation id="7960078400008666149">נא לא להפריע למשך שעה</translation>
-<translation id="4373894838514502496">לפני <ph name="NUMBER_FEW"/> דקות</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ימים</translation>
-<translation id="2190355936436201913">(ריק)</translation>
-<translation id="1164369517022005061">נותרו <ph name="NUMBER_DEFAULT"/> שעות</translation>
-<translation id="152482086482215392">נותרה שנייה <ph name="NUMBER_ONE"/></translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">גלול ימינה</translation>
-<translation id="7414887922320653780">נותרו <ph name="NUMBER_ONE"/> שעות</translation>
-<translation id="1413622004203049571">השבת הודעות מאת <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">למעלה</translation>
-<translation id="8331626408530291785">גלול למעלה</translation>
-<translation id="7907591526440419938">פתח קובץ</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">לפני <ph name="NUMBER_DEFAULT"/> שעות</translation>
-<translation id="815598010540052116">גלול למטה</translation>
-<translation id="6808150112686056157">עצור מדיה</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">שחזר</translation>
-<translation id="1243314992276662751">העלה</translation>
-<translation id="50030952220075532">נותר יום <ph name="NUMBER_ONE"/></translation>
-<translation id="8179976553408161302">היכנס</translation>
-<translation id="945522503751344254">שלח משוב</translation>
-<translation id="9170848237812810038">&amp;ביטול</translation>
-<translation id="1285266685456062655">לפני <ph name="NUMBER_FEW"/> שעות</translation>
-<translation id="6918245111648057970">אפשר קבלת הודעות מהגורמים הבאים עבור כל משתמש:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> שנייה</translation>
-<translation id="3994835489895548312">נותרו <ph name="NUMBER_MANY"/> דקות</translation>
-<translation id="6358975074282722691">לפני <ph name="NUMBER_TWO"/> שניות</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">הגדרות...</translation>
-<translation id="6845383723252244143">בחר תיקייה</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> שניות</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> שניות</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">לפני <ph name="NUMBER_MANY"/> ימים</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ימים</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> שעה</translation>
-<translation id="2679312662830811292">לפני <ph name="NUMBER_ONE"/> דקות</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405">יום <ph name="NUMBER_ONE"/></translation>
-<translation id="9098468523912235228">לפני <ph name="NUMBER_DEFAULT"/> שניות</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> שניות נותרו</translation>
-<translation id="4570886800634958009">הרחבת הודעה</translation>
-<translation id="436869212180315161">לחץ</translation>
-<translation id="4860787810836767172">לפני <ph name="NUMBER_FEW"/> שניות</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> דקות</translation>
-<translation id="1858722859751911017">נותרו <ph name="NUMBER_FEW"/> דקות</translation>
-<translation id="6040143037577758943">סגור</translation>
-<translation id="1101671447232096497">לפני <ph name="NUMBER_MANY"/> דקות</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">עזרה</translation>
-<translation id="6699343763173986273">הרצועה הבאה במדיה</translation>
-<translation id="8226233771743600312">נא לא להפריע ליום אחד</translation>
-<translation id="7457942297256758195">נקה הכל</translation>
-<translation id="822618367988303761">לפני <ph name="NUMBER_TWO"/> ימים</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> דקות</translation>
-<translation id="1963692530539281474">נותרו <ph name="NUMBER_DEFAULT"/> ימים</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> דקות</translation>
-<translation id="5906719743126878045">נותרו <ph name="NUMBER_TWO"/> שעות</translation>
-<translation id="8959208747503200525">לפני <ph name="NUMBER_TWO"/> שעות</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> שניות</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> שניות</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> שניות</translation>
-<translation id="3759876923365568382">נותרו <ph name="NUMBER_FEW"/> ימים</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">העתק ללוח</translation>
-<translation id="8371695176452482769">דבר עכשיו</translation>
-<translation id="6965382102122355670">אישור</translation>
-<translation id="7850320739366109486">נא לא להפריע</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">מזער</translation>
-<translation id="6394627529324717982">פסיק</translation>
-<translation id="3036649622769666520">פתח קבצים</translation>
-<translation id="8328145009876646418">קצה שמאלי</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> שניות</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ja.xtb b/chromium/ui/base/strings/ui_strings_ja.xtb
deleted file mode 100644
index db1f39e0ebb..00000000000
--- a/chromium/ui/base/strings/ui_strings_ja.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ja">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Insert</translation>
-<translation id="6135826906199951471">Delete</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 時間前</translation>
-<translation id="6310545596129886942">残り <ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="9213479837033539041">残り <ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="1209866192426315618">残り <ph name="NUMBER_DEFAULT"/> 分</translation>
-<translation id="1801827354178857021">ピリオド</translation>
-<translation id="1190609913194133056">通知センター</translation>
-<translation id="7470933019269157899">残り <ph name="NUMBER_DEFAULT"/> 分</translation>
-<translation id="5613020302032141669">左矢印キー</translation>
-<translation id="4971687151119236543">メディアの前のトラック</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ファイル (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> 秒</translation>
-<translation id="7511635910912978956">残り <ph name="NUMBER_FEW"/> 時間</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> から他 <ph name="NUMBER_OF_NOTIFICATIONS"/> 件</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">キャンセル</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">上矢印キー</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/秒</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 時間</translation>
-<translation id="3990502903496589789">右端</translation>
-<translation id="9038489124413477075">名前のないフォルダ</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分</translation>
-<translation id="3520476450377425184">残り <ph name="NUMBER_MANY"/> 日</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">残り <ph name="NUMBER_MANY"/> 分</translation>
-<translation id="8666066831007952346">残り <ph name="NUMBER_TWO"/> 日</translation>
-<translation id="6390842777729054533">残り <ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="3909791450649380159">切り取り(&amp;T)</translation>
-<translation id="2560788951337264832">残り <ph name="NUMBER_ZERO"/> 分</translation>
-<translation id="688711909580084195">無題のウェブページ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 日前</translation>
-<translation id="5076340679995252485">貼り付け(&amp;P)</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">アップロードするフォルダを選択</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分前</translation>
-<translation id="3234408098842461169">下矢印キー</translation>
-<translation id="3087734570205094154">下</translation>
-<translation id="5935630983280450497">残り <ph name="NUMBER_ONE"/> 分</translation>
-<translation id="1860796786778352021">通知を閉じる</translation>
-<translation id="6364916375976753737">左にスクロール</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 時間前</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分前</translation>
-<translation id="6945221475159498467">選択</translation>
-<translation id="6620110761915583480">ファイルを保存</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">残り <ph name="NUMBER_ONE"/> 分</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> 分</translation>
-<translation id="8210608804940886430">次のページへ</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> 日</translation>
-<translation id="7163503212501929773">残り <ph name="NUMBER_MANY"/> 時間</translation>
-<translation id="5329858601952122676">削除(&amp;D)</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
-<translation id="7781829728241885113">昨日</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分</translation>
-<translation id="50960180632766478">残り <ph name="NUMBER_FEW"/> 分</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 日前</translation>
-<translation id="8428213095426709021">設定</translation>
-<translation id="2497284189126895209">すべてのファイル</translation>
-<translation id="7487278341251176613">残り <ph name="NUMBER_TWO"/> 分</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 日前</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="7814458197256864873">コピー(&amp;C)</translation>
-<translation id="3889424535448813030">右矢印キー</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
-<translation id="2544782972264605588">残り <ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="6829324100069873704">通知に戻る</translation>
-<translation id="6528179044667508675">通知を一時的にミュート</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> 分</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">次の通知を許可:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> 時間</translation>
-<translation id="1398853756734560583">最大化</translation>
-<translation id="4250229828105606438">スクリーンショット</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> 時間</translation>
-<translation id="5260878308685146029">残り <ph name="NUMBER_TWO"/> 分</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">すべて選択(&amp;A)</translation>
-<translation id="2168039046890040389">前のページへ</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 日</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> 分</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
-<translation id="4927753642311223124">表示する通知はありません。続行してください。</translation>
-<translation id="2482878487686419369">通知</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">ここまでスクロール</translation>
-<translation id="4552416320897244156">PageDown</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> 時間</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/秒</translation>
-<translation id="8394908167088220973">メディアの再生/一時停止</translation>
-<translation id="2148716181193084225">今日</translation>
-<translation id="7960078400008666149">通知を 1 時間ミュート</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分前</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> 日</translation>
-<translation id="2190355936436201913">(なし)</translation>
-<translation id="1164369517022005061">残り <ph name="NUMBER_DEFAULT"/> 時間</translation>
-<translation id="152482086482215392">残り <ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="8447116497070723931">PageUp</translation>
-<translation id="4588090240171750605">右にスクロール</translation>
-<translation id="7414887922320653780">残り <ph name="NUMBER_ONE"/> 時間</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> からの通知を無効にする</translation>
-<translation id="2666092431469916601">一番上</translation>
-<translation id="8331626408530291785">上にスクロール</translation>
-<translation id="7907591526440419938">ファイルを開く</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 時間前</translation>
-<translation id="815598010540052116">下にスクロール</translation>
-<translation id="6808150112686056157">メディアの停止</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">復元</translation>
-<translation id="1243314992276662751">アップロード</translation>
-<translation id="50030952220075532">残り <ph name="NUMBER_ONE"/> 日</translation>
-<translation id="8179976553408161302">Enter</translation>
-<translation id="945522503751344254">フィードバックを送信</translation>
-<translation id="9170848237812810038">取消(&amp;U)</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 時間前</translation>
-<translation id="6918245111648057970">ユーザーごとに次の通知を許可:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="3994835489895548312">残り <ph name="NUMBER_MANY"/> 分</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">設定...</translation>
-<translation id="6845383723252244143">フォルダを選択</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 日前</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> 日</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> 時間</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分前</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/秒</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> 日</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
-<translation id="494645311413743213">残り <ph name="NUMBER_TWO"/> 秒</translation>
-<translation id="4570886800634958009">通知を展開</translation>
-<translation id="436869212180315161">押す</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/秒</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分</translation>
-<translation id="1858722859751911017">残り <ph name="NUMBER_FEW"/> 分</translation>
-<translation id="6040143037577758943">閉じる</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分前</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/秒</translation>
-<translation id="7649070708921625228">ヘルプ</translation>
-<translation id="6699343763173986273">メディアの次のトラック</translation>
-<translation id="8226233771743600312">通知を 1 日間ミュート</translation>
-<translation id="7457942297256758195">すべて消去</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 日前</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> 分</translation>
-<translation id="1963692530539281474">残り <ph name="NUMBER_DEFAULT"/> 日</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分</translation>
-<translation id="5906719743126878045">残り <ph name="NUMBER_TWO"/> 時間</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 時間前</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="3759876923365568382">残り <ph name="NUMBER_FEW"/> 日</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/秒</translation>
-<translation id="2743387203779672305">クリップボードにコピー</translation>
-<translation id="8371695176452482769">お話しください</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">通知を一時的にミュート</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">最小化</translation>
-<translation id="6394627529324717982">カンマ</translation>
-<translation id="3036649622769666520">ファイルを開く</translation>
-<translation id="8328145009876646418">左端</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_kn.xtb b/chromium/ui/base/strings/ui_strings_kn.xtb
deleted file mode 100644
index 5e0b1a92522..00000000000
--- a/chromium/ui/base/strings/ui_strings_kn.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="kn">
-<translation id="4820616160060340806">ಕಮಾಂಡ್+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">ಅಂತ್ಯ</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="1801827354178857021">ಅವಧಿ</translation>
-<translation id="1190609913194133056">ಅಧಿಸೂಚನೆಯ ಕೇಂದ್ರ</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="5613020302032141669">ಎಡ ಬಾಣದ ಗುರುತು</translation>
-<translation id="4971687151119236543">ಮೀಡಿಯಾದ ಹಿಂದಿನ ಟ್ರ್ಯಾಕ್</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ಫೈಲ್ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ಗಂಟೆಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> ನಿಂದ ಹೆಚ್ಚಿನ <ph name="NUMBER_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">ರದ್ದುಮಾಡು</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">ಮೇಲಿನ ಬಾಣದ ಗುರುತು</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ಗಂಟೆಗಳು</translation>
-<translation id="3990502903496589789">ಬಲ ತುದಿ</translation>
-<translation id="9038489124413477075">ಹೆಸರಿಸದ ಫೋಲ್ಡರ್</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="932327136139879170">ಮುಖಪುಟ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="3909791450649380159">ಕತ್ತರಿ&amp;ಸು</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="688711909580084195">ಶೀರ್ಷಿಕೆರಹಿತ ವೆಬ್‌ಪುಟ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;ಅಂಟಿಸಿ</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">ಅಪ್‌ಲೋಡ್ ಮಾಡಲು ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">ಕೆಳಗಿನ ಬಾಣದ ಗುರುತು</translation>
-<translation id="3087734570205094154">ಕೆಳಗೆ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="1860796786778352021">ಅಧಿಸೂಚನೆ ಮುಚ್ಚು</translation>
-<translation id="6364916375976753737">ಎಡಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">ಆಯ್ಕೆಮಾಡಿ</translation>
-<translation id="6620110761915583480">ಫೈಲ್ ಉಳಿಸು</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> ನಿಮಿಷ ಉಳಿದಿದೆ</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> ನಿಮಿಷ</translation>
-<translation id="8210608804940886430">ಪುಟ ಕೆಳಗೆ</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ದಿನಗಳು</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="5329858601952122676">&amp;ಅಳಿಸು</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">ನಿನ್ನೆ</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="6659594942844771486">ಟ್ಯಾಬ್</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">ಸೆಟ್ಟಿಂಗ್‌ಗಳು</translation>
-<translation id="2497284189126895209">ಎಲ್ಲ ಫೈಲ್‌ಗಳು</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡು</translation>
-<translation id="7814458197256864873">&amp;ನಕಲಿಸಿ</translation>
-<translation id="3889424535448813030">ಬಲ ಬಾಣದ ಗುರುತು</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="6829324100069873704">ಅಧಿಸೂಚನೆಗಳಿಗೆ ಹಿಂತಿರುಗಿ</translation>
-<translation id="6528179044667508675">ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">ಕೆಳಗಿನವುಗಳಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ಅನುಮತಿಸಿ:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ಗಂಟೆಗಳು</translation>
-<translation id="1398853756734560583">ಗರಿಷ್ಠಗೊಳಿಸು</translation>
-<translation id="4250229828105606438">ಸ್ಕ್ರೀನ್‌ಶಾಟ್</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ಗಂಟೆಗಳು</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;ಎಲ್ಲ ಆಯ್ಕೆ ಮಾಡಿ</translation>
-<translation id="2168039046890040389">ಪುಟ ಮೇಲೆ</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ದಿನಗಳು</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> ನಿಮಿಷ</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">ಇಲ್ಲಿ ನೋಡಲು ಏನೂ ಇಲ್ಲ, ಮುಂದೆ ಸಾಗಿ.</translation>
-<translation id="2482878487686419369">ಸೂಚನೆಗಳು</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">ಇಲ್ಲಿಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ಗಂಟೆಗಳು</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s </translation>
-<translation id="8394908167088220973">ಮೀಡಿಯಾ ಪ್ಲೇ/ವಿರಾಮ</translation>
-<translation id="2148716181193084225">ಇಂದು</translation>
-<translation id="7960078400008666149">ಒಂದು ಗಂಟೆಯ ಕಾಲ ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ದಿನಗಳು</translation>
-<translation id="2190355936436201913">(ಖಾಲಿ)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">ಬಲಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> ಅವರ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ</translation>
-<translation id="2666092431469916601">ಮೇಲೆ</translation>
-<translation id="8331626408530291785">ಮೇಲೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
-<translation id="7907591526440419938">ಫೈಲ್ ತೆರೆಯಿರಿ</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">ಕೆಳಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
-<translation id="6808150112686056157">ಮೀಡಿಯಾ ನಿಲುಗಡೆ</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">ಪುನಃಸ್ಥಾಪನೆ</translation>
-<translation id="1243314992276662751">ಅಪ್‌ಲೋಡ್</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="8179976553408161302">ನಮೂದಿಸಿ</translation>
-<translation id="945522503751344254">ಪ್ರತಿಕ್ರಿಯೆಯನ್ನು ಕಳುಹಿಸಿ</translation>
-<translation id="9170848237812810038">&amp;ರದ್ದುಮಾಡು</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">ಪ್ರತಿ ಬಳಕೆದಾರರಿಗಾಗಿ ಈ ಕೆಳಗಿನವುಗಳಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ಅನುಮತಿಸಿ:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡ್</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">ಸೆಟ್ಟಿಂಗ್‌ಗಳು...</translation>
-<translation id="6845383723252244143">ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ದಿನಗಳು</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ಗಂಟೆ</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ದಿನ</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="4570886800634958009">ಅಧಿಸೂಚನೆ ವಿಸ್ತರಿಸು</translation>
-<translation id="436869212180315161">ಒತ್ತಿರಿ</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> ನಿಮಿಷಗಳು</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="6040143037577758943">ಮುಚ್ಚು</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">ಸಹಾಯ</translation>
-<translation id="6699343763173986273">ಮೀಡಿಯಾದ ಮುಂದಿನ ಟ್ರ್ಯಾಕ್</translation>
-<translation id="8226233771743600312">ಒಂದು ದಿನದವರೆಗೆ ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
-<translation id="7457942297256758195">ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ</translation>
-<translation id="8371695176452482769">ಈಗ ಮಾತನಾಡಿ</translation>
-<translation id="6965382102122355670">ಸರಿ</translation>
-<translation id="7850320739366109486">ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">ಕುಗ್ಗಿಸು</translation>
-<translation id="6394627529324717982">ಅರ್ಧವಿರಾಮ</translation>
-<translation id="3036649622769666520">ಫೈಲ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ</translation>
-<translation id="8328145009876646418">ಎಡ ಬದಿ</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ko.xtb b/chromium/ui/base/strings/ui_strings_ko.xtb
deleted file mode 100644
index def4d0ce6be..00000000000
--- a/chromium/ui/base/strings/ui_strings_ko.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ko">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Insert</translation>
-<translation id="6135826906199951471">삭제</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/>시간 전</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/>초 남음</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/>초 남음</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/>분 남음</translation>
-<translation id="1801827354178857021">마침표</translation>
-<translation id="1190609913194133056">알림 센터</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/>분 남음</translation>
-<translation id="5613020302032141669">왼쪽 화살표</translation>
-<translation id="4971687151119236543">미디어 이전 트랙</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 파일(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/>초</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/>시간 남음</translation>
-<translation id="8717309436826820190">외 <ph name="SOURCE_OF_NOTIFICATIONS"/> 알림 <ph name="NUMBER_OF_NOTIFICATIONS"/>개</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">취소</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/>B</translation>
-<translation id="3660179305079774227">위쪽 화살표</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/>MB/초</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/>시간</translation>
-<translation id="3990502903496589789">오른쪽 모서리</translation>
-<translation id="9038489124413477075">이름이 없는 폴더</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/>분</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/>일 남음</translation>
-<translation id="932327136139879170">홈</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/>분</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/>일 남음</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/>초 남음</translation>
-<translation id="3909791450649380159">잘라내기(&amp;T)</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">제목 없는 웹페이지</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/>일 전</translation>
-<translation id="5076340679995252485">붙여넣기(&amp;P)</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/>TB</translation>
-<translation id="364720409959344976">업로드할 폴더 선택</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/>분 전</translation>
-<translation id="3234408098842461169">아래 화살표</translation>
-<translation id="3087734570205094154">맨 아래</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/>분 남음</translation>
-<translation id="1860796786778352021">알림 닫기</translation>
-<translation id="6364916375976753737">왼쪽으로 스크롤</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/>시간 전</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/>분</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/>분 전</translation>
-<translation id="6945221475159498467">선택</translation>
-<translation id="6620110761915583480">파일 저장</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/>초</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute left</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/>분</translation>
-<translation id="8210608804940886430">페이지 아래로</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/>일</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/>시간 남음</translation>
-<translation id="5329858601952122676">삭제(&amp;D)</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/>초</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/>KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/>분</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/>초 전</translation>
-<translation id="7781829728241885113">어제</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/>분</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/>분 남음</translation>
-<translation id="6659594942844771486">탭</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/>MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/>일 전</translation>
-<translation id="8428213095426709021">설정</translation>
-<translation id="2497284189126895209">모든 파일</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/>일 전</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/>초</translation>
-<translation id="7814458197256864873">복사(&amp;C)</translation>
-<translation id="3889424535448813030">오른쪽 화살표</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/>초 전</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/>초 남음</translation>
-<translation id="6829324100069873704">알림으로 돌아가기</translation>
-<translation id="6528179044667508675">알림 일시중지</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/>초</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/>분</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">다음 항목에 알림 허용:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/>시간</translation>
-<translation id="1398853756734560583">최대화</translation>
-<translation id="4250229828105606438">캡처화면</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/>시간</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/>분 남음</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/>GB</translation>
-<translation id="1901303067676059328">전체 선택(&amp;A)</translation>
-<translation id="2168039046890040389">페이지 위로</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/>일</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/>분</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/>분</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/>초 전</translation>
-<translation id="4927753642311223124">표시할 내용이 없습니다.</translation>
-<translation id="2482878487686419369">알림</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">여기로 스크롤</translation>
-<translation id="4552416320897244156">PageDown</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/>시간</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/>KB/초</translation>
-<translation id="8394908167088220973">미디어 재생/일시중지</translation>
-<translation id="2148716181193084225">오늘</translation>
-<translation id="7960078400008666149">1시간 동안 알림 일시중지</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/>분 전</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/>일</translation>
-<translation id="2190355936436201913">(비어있음)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/>시간 남음</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/>초 남음</translation>
-<translation id="8447116497070723931">PageUp</translation>
-<translation id="4588090240171750605">오른쪽 스크롤</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/>시간 남음</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/>의 알림 사용 중지</translation>
-<translation id="2666092431469916601">맨 위</translation>
-<translation id="8331626408530291785">위로 스크롤</translation>
-<translation id="7907591526440419938">파일 열기</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/>시간 전</translation>
-<translation id="815598010540052116">아래로 스크롤</translation>
-<translation id="6808150112686056157">미디어 중지</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">복구</translation>
-<translation id="1243314992276662751">업로드</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/>일 남음</translation>
-<translation id="8179976553408161302">Enter</translation>
-<translation id="945522503751344254">의견 보내기</translation>
-<translation id="9170848237812810038">실행 취소(&amp;U)</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/>시간 전</translation>
-<translation id="6918245111648057970">사용자별로 다음 알림 허용:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/>초</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/>초 전</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/>PB</translation>
-<translation id="2983818520079887040">설정...</translation>
-<translation id="6845383723252244143">폴더 선택</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/>초</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/>초</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/>일 전</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/>일</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/>시간</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/>분 전</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/>GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>일</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/>초 전</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/>초 남음</translation>
-<translation id="4570886800634958009">알림 펼치기</translation>
-<translation id="436869212180315161">누르기</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/>초 전</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/>TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/>분</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">닫기</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/>분 전</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/>B/s</translation>
-<translation id="7649070708921625228">도움말</translation>
-<translation id="6699343763173986273">미디어 다음 트랙</translation>
-<translation id="8226233771743600312">하루 동안 알림 일시중지</translation>
-<translation id="7457942297256758195">모두 지우기</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/>일 전</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/>분</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/>일 남음</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/>분</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/>시간 남음</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/>시간 전</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/>초</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/>초</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/>초</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/>일 남음</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/>PB/s</translation>
-<translation id="2743387203779672305">클립보드로 복사</translation>
-<translation id="8371695176452482769">지금 말하기</translation>
-<translation id="6965382102122355670">확인</translation>
-<translation id="7850320739366109486">알림 일시중지</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">최소화</translation>
-<translation id="6394627529324717982">콤마</translation>
-<translation id="3036649622769666520">파일 열기</translation>
-<translation id="8328145009876646418">왼쪽 모서리</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/>초</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_lt.xtb b/chromium/ui/base/strings/ui_strings_lt.xtb
deleted file mode 100644
index ccd630af6f7..00000000000
--- a/chromium/ui/base/strings/ui_strings_lt.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="lt">
-<translation id="4820616160060340806">„Command“ + „<ph name="KEY_COMBO_NAME"/>“</translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">Pabaiga</translation>
-<translation id="5341849548509163798">Prieš <ph name="NUMBER_MANY"/> val.</translation>
-<translation id="6310545596129886942">liko <ph name="NUMBER_FEW"/> sek.</translation>
-<translation id="9213479837033539041">liko <ph name="NUMBER_MANY"/> sek.</translation>
-<translation id="1209866192426315618">liko <ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="1801827354178857021">Taškas</translation>
-<translation id="1190609913194133056">Pranešimų centras</translation>
-<translation id="7470933019269157899">Liko <ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="5613020302032141669">Rodyklė į kairę</translation>
-<translation id="4971687151119236543">Ankstesnis medijos takelis</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> failas (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek.</translation>
-<translation id="7511635910912978956">liko <ph name="NUMBER_FEW"/> valandos (-ų)</translation>
-<translation id="8717309436826820190">Dar <ph name="NUMBER_OF_NOTIFICATIONS"/> iš „<ph name="SOURCE_OF_NOTIFICATIONS"/>“</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Atšaukti</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Rodyklė „Aukštyn“</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> val.</translation>
-<translation id="3990502903496589789">Dešinysis kraštas</translation>
-<translation id="9038489124413477075">Aplankas be pavadinimo</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="3520476450377425184">liko <ph name="NUMBER_MANY"/> dienos (-ų)</translation>
-<translation id="932327136139879170">Pradžia</translation>
-<translation id="5600907569873192868">liko <ph name="NUMBER_MANY"/> min.</translation>
-<translation id="8666066831007952346">liko <ph name="NUMBER_TWO"/> dienos (-ų)</translation>
-<translation id="6390842777729054533">liko <ph name="NUMBER_ZERO"/> sek.</translation>
-<translation id="3909791450649380159">Iškir&amp;pti</translation>
-<translation id="2560788951337264832">Liko <ph name="NUMBER_ZERO"/> min.</translation>
-<translation id="688711909580084195">Tinklalapis be pavadinimo</translation>
-<translation id="3353284378027041011">Prieš <ph name="NUMBER_FEW"/> dienas (-ų)</translation>
-<translation id="5076340679995252485">&amp;Įklijuoti</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Pasirinkite norimą įkelti aplanką</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Prieš <ph name="NUMBER_TWO"/> min.</translation>
-<translation id="3234408098842461169">Rodyklė „Žemyn“</translation>
-<translation id="3087734570205094154">Apačia</translation>
-<translation id="5935630983280450497">liko <ph name="NUMBER_ONE"/> min.</translation>
-<translation id="1860796786778352021">Uždaryti pranešimus</translation>
-<translation id="6364916375976753737">Slinkti į kairę</translation>
-<translation id="2629089419211541119">Prieš <ph name="NUMBER_ONE"/> val.</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="6982279413068714821">Prieš <ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="6945221475159498467">Pasirinkti</translation>
-<translation id="6620110761915583480">Išsaugoti failą</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sek.</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Liko <ph name="NUMBER_ONE"/> min.</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8210608804940886430">Puslapį žemyn</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dienos</translation>
-<translation id="7163503212501929773">liko <ph name="NUMBER_MANY"/> valandos (-ų)</translation>
-<translation id="5329858601952122676">&amp;Pašalinti</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sek.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> min.</translation>
-<translation id="7275974018215686543">Prieš <ph name="NUMBER_MANY"/> sek.</translation>
-<translation id="7781829728241885113">Vakar</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> min.</translation>
-<translation id="50960180632766478">liko <ph name="NUMBER_FEW"/> min.</translation>
-<translation id="6659594942844771486">Skirtukas</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Prieš <ph name="NUMBER_DEFAULT"/> dienas (-ų)</translation>
-<translation id="8428213095426709021">Nustatymai</translation>
-<translation id="2497284189126895209">Visi failai</translation>
-<translation id="7487278341251176613">Liko <ph name="NUMBER_TWO"/> min.</translation>
-<translation id="5110450810124758964">Prieš <ph name="NUMBER_ONE"/> dieną</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek.</translation>
-<translation id="7814458197256864873">&amp;Kopijuoti</translation>
-<translation id="3889424535448813030">Rodyklė į dešinę</translation>
-<translation id="4229495110203539533">Prieš <ph name="NUMBER_ONE"/> sek.</translation>
-<translation id="2544782972264605588">liko <ph name="NUMBER_DEFAULT"/> sek.</translation>
-<translation id="6829324100069873704">Atgal į pranešimus</translation>
-<translation id="6528179044667508675">Netrukdyti</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sek.</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Leisti pranešimus iš šių plėtinių:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> valandos (-ų)</translation>
-<translation id="1398853756734560583">Išskleisti</translation>
-<translation id="4250229828105606438">Ekrano kopija</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> valandos (-ų)</translation>
-<translation id="5260878308685146029">liko <ph name="NUMBER_TWO"/> min.</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Pasirinkti &amp;viską</translation>
-<translation id="2168039046890040389">Puslapį į viršų</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dienos</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8448317557906454022">Prieš <ph name="NUMBER_ZERO"/> sek.</translation>
-<translation id="4927753642311223124">Čia nieko nėra, slinkite toliau.</translation>
-<translation id="2482878487686419369">Pranešimai</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Slinkti iki čia</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> valandos (-ų)</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB per sek.</translation>
-<translation id="8394908167088220973">Leisti / pristabdyti mediją</translation>
-<translation id="2148716181193084225">Šiandien</translation>
-<translation id="7960078400008666149">Netrukdyti vieną valandą</translation>
-<translation id="4373894838514502496">Prieš <ph name="NUMBER_FEW"/> min.</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dienos</translation>
-<translation id="2190355936436201913">(tuščias)</translation>
-<translation id="1164369517022005061">liko <ph name="NUMBER_DEFAULT"/> valandos (-ų)</translation>
-<translation id="152482086482215392">liko <ph name="NUMBER_ONE"/> sek.</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Slinkti į dešinę</translation>
-<translation id="7414887922320653780">liko <ph name="NUMBER_ONE"/> val.</translation>
-<translation id="1413622004203049571">Išjungti pranešimus nuo <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Į viršų</translation>
-<translation id="8331626408530291785">Slinkti į viršų</translation>
-<translation id="7907591526440419938">Atidaryti failą</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Prieš <ph name="NUMBER_DEFAULT"/> val.</translation>
-<translation id="815598010540052116">Slinkti žemyn</translation>
-<translation id="6808150112686056157">Sustabdyti mediją</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Atkurti</translation>
-<translation id="1243314992276662751">Įkelti</translation>
-<translation id="50030952220075532">liko <ph name="NUMBER_ONE"/> diena</translation>
-<translation id="8179976553408161302">Įvesti</translation>
-<translation id="945522503751344254">Siųsti atsiliepimą</translation>
-<translation id="9170848237812810038">&amp;Atšaukti</translation>
-<translation id="1285266685456062655">Prieš <ph name="NUMBER_FEW"/> val.</translation>
-<translation id="6918245111648057970">Kiekvienam naudotojui leisti pranešimus iš nurodyto:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sek.</translation>
-<translation id="3994835489895548312">Liko <ph name="NUMBER_MANY"/> min.</translation>
-<translation id="6358975074282722691">Prieš <ph name="NUMBER_TWO"/> sek.</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Nustatymai...</translation>
-<translation id="6845383723252244143">Pasirinkti aplanką</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sek.</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek.</translation>
-<translation id="5583640892426849032">Grįžties klavišas</translation>
-<translation id="5263972071113911534">Prieš <ph name="NUMBER_MANY"/> dienas (-ų)</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dienos</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> val.</translation>
-<translation id="2679312662830811292">Prieš <ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> diena</translation>
-<translation id="9098468523912235228">Prieš <ph name="NUMBER_DEFAULT"/> sek.</translation>
-<translation id="494645311413743213">liko <ph name="NUMBER_TWO"/> sek.</translation>
-<translation id="4570886800634958009">Išplėsti pranešimą</translation>
-<translation id="436869212180315161">Spustelėti</translation>
-<translation id="4860787810836767172">Prieš <ph name="NUMBER_FEW"/> sek.</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> min.</translation>
-<translation id="1858722859751911017">Liko <ph name="NUMBER_FEW"/> min.</translation>
-<translation id="6040143037577758943">Uždaryti</translation>
-<translation id="1101671447232096497">Prieš <ph name="NUMBER_MANY"/> min.</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Žinynas</translation>
-<translation id="6699343763173986273">Kitas medijos takelis</translation>
-<translation id="8226233771743600312">Netrukdyti vieną dieną</translation>
-<translation id="7457942297256758195">Išvalyti viską</translation>
-<translation id="822618367988303761">Prieš <ph name="NUMBER_TWO"/> dienas</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
-<translation id="1963692530539281474">liko <ph name="NUMBER_DEFAULT"/> dienos (-ų)</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> min.</translation>
-<translation id="5906719743126878045">liko <ph name="NUMBER_TWO"/> valandos (-ų)</translation>
-<translation id="8959208747503200525">Prieš <ph name="NUMBER_TWO"/> val.</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sek.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sek.</translation>
-<translation id="3759876923365568382">liko <ph name="NUMBER_FEW"/> dienos (-ų)</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopijuoti į iškarpinę</translation>
-<translation id="8371695176452482769">Kalbėti dabar</translation>
-<translation id="6965382102122355670">Gerai</translation>
-<translation id="7850320739366109486">Netrukdyti</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Sumažinti</translation>
-<translation id="6394627529324717982">Kablelis</translation>
-<translation id="3036649622769666520">Atidaryti failus</translation>
-<translation id="8328145009876646418">Kairysis kraštas</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sek.</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_lv.xtb b/chromium/ui/base/strings/ui_strings_lv.xtb
deleted file mode 100644
index 276442fefc7..00000000000
--- a/chromium/ui/base/strings/ui_strings_lv.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="lv">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Iespraušana</translation>
-<translation id="6135826906199951471">Dzēst</translation>
-<translation id="528468243742722775">Beigas</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekundes atlikušas</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekundes atlikušas</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minūtes atlikušas</translation>
-<translation id="1801827354178857021">Punkts</translation>
-<translation id="1190609913194133056">Paziņojumu centrs</translation>
-<translation id="7470933019269157899">Atlikušas <ph name="NUMBER_DEFAULT"/> minūtes</translation>
-<translation id="5613020302032141669">Kreisā bulta</translation>
-<translation id="4971687151119236543">Multivide — iepriekšējā dziesma</translation>
-<translation id="8602707065186045623">Fails <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekundes</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> stundas atlikušas</translation>
-<translation id="8717309436826820190">Vēl <ph name="NUMBER_OF_NOTIFICATIONS"/> no pakalpojuma <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt +<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Atcelt</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Bulta augšup</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> stundas</translation>
-<translation id="3990502903496589789">Labā puse</translation>
-<translation id="9038489124413477075">Mape bez nosaukuma</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minūtes</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dienas atlikušas</translation>
-<translation id="932327136139879170">Sākumvieta</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minūtes atlikušas</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dienas atlikušas</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekundes atlikušas</translation>
-<translation id="3909791450649380159">Izgrie&amp;zt</translation>
-<translation id="2560788951337264832">Atlikusi <ph name="NUMBER_ZERO"/> minūšu</translation>
-<translation id="688711909580084195">Tīmekļa lapa bez nosaukuma</translation>
-<translation id="3353284378027041011">Pirms <ph name="NUMBER_FEW"/> dienām</translation>
-<translation id="5076340679995252485">&amp;Ielīmēt</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Augšupielādējamās mapes atlase</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Bulta Lejup</translation>
-<translation id="3087734570205094154">Apakša</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minūtes atlikušas</translation>
-<translation id="1860796786778352021">Paziņojuma aizvēršana</translation>
-<translation id="6364916375976753737">Ritināt pa kreisi</translation>
-<translation id="2629089419211541119">Pirms <ph name="NUMBER_ONE"/> stundas</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minūtes</translation>
-<translation id="6982279413068714821">Pirms <ph name="NUMBER_DEFAULT"/> minūtēm</translation>
-<translation id="6945221475159498467">Atlasīt</translation>
-<translation id="6620110761915583480">Saglabāt failu</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunžu</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Atlikusi <ph name="NUMBER_ONE"/> minūte</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minūtes</translation>
-<translation id="8210608804940886430">Lejup</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dienas</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/>stundas atlikušas</translation>
-<translation id="5329858601952122676">Dzēst</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekundes</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Vakar</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minūtes atlikušas</translation>
-<translation id="6659594942844771486">Cilne</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Pirms <ph name="NUMBER_DEFAULT"/> dienām</translation>
-<translation id="8428213095426709021">Iestatījumi</translation>
-<translation id="2497284189126895209">Visi faili</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964">Pirms <ph name="NUMBER_ONE"/> dienas</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekundes</translation>
-<translation id="7814458197256864873">Ko&amp;pēt</translation>
-<translation id="3889424535448813030">Labā bulta</translation>
-<translation id="4229495110203539533">Pirms <ph name="NUMBER_ONE"/> sekundes</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekundes atlikušas</translation>
-<translation id="6829324100069873704">Atgriezties paziņojumos</translation>
-<translation id="6528179044667508675">Netraucēt</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundes</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minūtes</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Atļaut paziņojumu saņemšanu no:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> stundas</translation>
-<translation id="1398853756734560583">Maksimizēt</translation>
-<translation id="4250229828105606438">Ekrānuzņēmums</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> stundas</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minūtes atlikušas</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Izvēlēties visus</translation>
-<translation id="2168039046890040389">Augšup</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/>dienas</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minūtes</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minūte</translation>
-<translation id="8448317557906454022">Pirms <ph name="NUMBER_ZERO"/> sekundēm</translation>
-<translation id="4927753642311223124">Te nekā nav, varat doties tālāk!</translation>
-<translation id="2482878487686419369">Paziņojumi</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Ritināt šeit</translation>
-<translation id="4552416320897244156">Lejup</translation>
-<translation id="7052633198403197513">taustiņš F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> stundas</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Multivide — atskaņot/apturēt</translation>
-<translation id="2148716181193084225">Šodien</translation>
-<translation id="7960078400008666149">Netraucēt stundu</translation>
-<translation id="4373894838514502496">Pirms <ph name="NUMBER_FEW"/> minūtēm</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dienas</translation>
-<translation id="2190355936436201913">(tukšs)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> stundas atlikušas</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekundes atlikušas</translation>
-<translation id="8447116497070723931">Augšup</translation>
-<translation id="4588090240171750605">Ritināt pa labi</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> stundas atlikušas</translation>
-<translation id="1413622004203049571">Atspējot paziņojumu saņemšanu no: <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Augša</translation>
-<translation id="8331626408530291785">Ritināt augšup</translation>
-<translation id="7907591526440419938">Atvērt failu</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Atsolis</translation>
-<translation id="2797524280730715045">Pirms <ph name="NUMBER_DEFAULT"/> stundām</translation>
-<translation id="815598010540052116">Ritināt lejup</translation>
-<translation id="6808150112686056157">Multivide — pārtraukt</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Atjaunot</translation>
-<translation id="1243314992276662751">Augšupielādēt</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dienas atlikušas</translation>
-<translation id="8179976553408161302">Ievadīt</translation>
-<translation id="945522503751344254">Sūtīt atsauksmes</translation>
-<translation id="9170848237812810038">&amp;Atsaukt</translation>
-<translation id="1285266685456062655">Pirms <ph name="NUMBER_FEW"/> stundām</translation>
-<translation id="6918245111648057970">Atļaut paziņojumus visiem lietotājiem no:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunde</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Iestatījumi...</translation>
-<translation id="6845383723252244143">Atlasīt mapi</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundes</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekundes</translation>
-<translation id="5583640892426849032">Atkāpšanās taustiņš</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dienas</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> stunda</translation>
-<translation id="2679312662830811292">Pirms <ph name="NUMBER_ONE"/> minūtes</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> diena</translation>
-<translation id="9098468523912235228">Pirms <ph name="NUMBER_DEFAULT"/> sekundēm</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekundes atlikušas</translation>
-<translation id="4570886800634958009">Paziņojuma izvēršana</translation>
-<translation id="436869212180315161">Nospiediet</translation>
-<translation id="4860787810836767172">Pirms <ph name="NUMBER_FEW"/> sekundēm</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minūšu</translation>
-<translation id="1858722859751911017">Atlikušas <ph name="NUMBER_FEW"/> minūtes</translation>
-<translation id="6040143037577758943">Aizvērt</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Palīdzība</translation>
-<translation id="6699343763173986273">Multivide — nākamā dziesma</translation>
-<translation id="8226233771743600312">Netraucēt dienu</translation>
-<translation id="7457942297256758195">Notīrīt visu</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minūtes</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dienas atlikušas</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minūtes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/>stundas atlikušas</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekundes</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekundes</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dienas atlikušas</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopēt starpliktuvē</translation>
-<translation id="8371695176452482769">Runājiet tūlīt</translation>
-<translation id="6965382102122355670">Labi</translation>
-<translation id="7850320739366109486">Netraucēt</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimizēt</translation>
-<translation id="6394627529324717982">Komats</translation>
-<translation id="3036649622769666520">Atvērt failus</translation>
-<translation id="8328145009876646418">Kreisā mala</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ml.xtb b/chromium/ui/base/strings/ui_strings_ml.xtb
deleted file mode 100644
index 3927fb51df8..00000000000
--- a/chromium/ui/base/strings/ui_strings_ml.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ml">
-<translation id="4820616160060340806">കമാൻഡ്+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">അവസാനം</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> സെക്കന്റ്‍ ശേഷിക്കുന്നു</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> സെക്കന്റ്‍ അവശേഷിക്കുന്നു</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="1801827354178857021">കാലയളവ്</translation>
-<translation id="1190609913194133056">അറിയിപ്പ് കേന്ദ്രം</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="5613020302032141669">ഇടത് ആരോ അടയാളം</translation>
-<translation id="4971687151119236543">മുമ്പത്തെ മീഡിയ ട്രാക്ക്</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ഫയല്‍ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> സെക്കന്റ്</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> മണിക്കൂര്‍‍ അവശേഷിക്കുന്നു</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/>-ൽ നിന്നുള്ള <ph name="NUMBER_OF_NOTIFICATIONS"/> അറിയിപ്പുകൾ</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">റദ്ദാക്കുക</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">മുകളിലേക്കുള്ള അമ്പടയാളം</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> മണിക്കൂര്‍</translation>
-<translation id="3990502903496589789">വലത് അഗ്രം</translation>
-<translation id="9038489124413477075">പേരിടാത്ത ഫോൾഡർ</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ്</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ദിവസം‍ ശേഷിക്കുന്നു</translation>
-<translation id="932327136139879170">ഹോം</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ദിവസം അവശേഷിക്കുന്നു</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="3909791450649380159">&amp;മുറിക്കുക</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="688711909580084195">ശീർഷകമില്ലാത്ത വെബ്‌പേജ്</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;ഒട്ടിക്കുക</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">അപ്‌ലോഡുചെയ്യുന്നതിന് ഫോൾഡർ തിരഞ്ഞെടുക്കുക</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">താഴേക്കുള്ള ആരോ അടയാളം</translation>
-<translation id="3087734570205094154">താഴെ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="1860796786778352021">അറിയിപ്പ് അടയ്‌ക്കൽ</translation>
-<translation id="6364916375976753737">ഇടത്തേക്ക് സ്ക്രോള്‍ ചെയ്യുക</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ്</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">തിരഞ്ഞെടുക്കുക</translation>
-<translation id="6620110761915583480">ഫയല്‍‌ സംരക്ഷിക്കുക</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> സെക്കൻഡ്</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> മിനിറ്റ്</translation>
-<translation id="8210608804940886430">താഴെയുള്ള പേജുകള്‍</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ദിവസം</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
-<translation id="5329858601952122676">&amp;ഇല്ലാതാക്കൂ</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> സെക്കന്റ്</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> മിനിറ്റ്</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">ഇന്നലെ</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> മിനിറ്റ്</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> മിനിറ്റ്‍ അവശേഷിക്കുന്നു</translation>
-<translation id="6659594942844771486">ടാബ്</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">ക്രമീകരണം</translation>
-<translation id="2497284189126895209">എല്ലാ ഫയലുകളും</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> സെക്കന്റ്</translation>
-<translation id="7814458197256864873">&amp;പകര്‍ത്തൂ</translation>
-<translation id="3889424535448813030">വലതുഭാഗത്തെ അമ്പടയാളം</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="6829324100069873704">അറിയിപ്പുകളിലേക്ക് തിരിച്ചുപോവുക</translation>
-<translation id="6528179044667508675">ശല്യപ്പെടുത്തരുത്</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> സെക്കൻഡ്</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> മിനിറ്റ്</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">ഇനിപ്പറയുന്നതിൽ നിന്നുള്ള അറിയിപ്പുകൾ അനുവദിക്കുക:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> മണിക്കൂര്‍</translation>
-<translation id="1398853756734560583">വലുതാക്കുക</translation>
-<translation id="4250229828105606438">സ്‌ക്രീൻഷോട്ട്</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> മണിക്കൂര്‍</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">എല്ലാം &amp;തിരഞ്ഞെടുക്കൂ</translation>
-<translation id="2168039046890040389">പേജ് മുകളിലേയ്ക്ക്</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ദിവസം</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> മിനിറ്റ്</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> മിനിറ്റ്</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">ഇവിടെ കാണുന്നതിനായി ഒന്നുമില്ല, തുടരുക.</translation>
-<translation id="2482878487686419369">വിജ്ഞാപനങ്ങള്‍‌</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">ഇവിടെ സ്ക്രോള്‍ ചെയ്യുക</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> മണിക്കൂര്‍</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">മീഡിയ പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക</translation>
-<translation id="2148716181193084225">ഇന്ന്</translation>
-<translation id="7960078400008666149">ഒരു മണിക്കൂർ നേരത്തേക്ക് ശല്യപ്പെടുത്തരുത്</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ദിവസം</translation>
-<translation id="2190355936436201913">(ശൂന്യം)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> മണിക്കൂര്‍ അവശേഷിക്കുന്നു</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">വലത്തോട്ട് സ്ക്രോള്‍ ചെയ്യുക</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> എന്നതിൽ നിന്നുള്ള അറിയിപ്പുകൾ പ്രവർത്തനരഹിതമാക്കുക</translation>
-<translation id="2666092431469916601">മുകളിലേക്ക്</translation>
-<translation id="8331626408530291785">മുകളിലേക്ക് സ്ക്രോള്‍ ചെയ്യൂ</translation>
-<translation id="7907591526440419938">ഫയല്‍ തുറക്കുക</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">താഴേക്ക് സ്ക്രോള്‍ചെയ്യൂ</translation>
-<translation id="6808150112686056157">മീഡിയ ‌നിർത്തുക</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
-<translation id="1243314992276662751">അപ്‌ലോഡുചെയ്യുക</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ദിവസം അവശേഷിക്കുന്നു</translation>
-<translation id="8179976553408161302">നൽകുക</translation>
-<translation id="945522503751344254">ഫീഡ്ബാക്ക് അയയ്ക്കുക</translation>
-<translation id="9170848237812810038">‍&amp;പൂര്‍വാവസ്ഥയിലാക്കുക</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">ഇനിപ്പറയുന്നതിൽ നിന്ന് ഓരോ ഉപയോക്താവിനും അറിയിപ്പുകൾ അനുവദിക്കുക:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> സെക്കൻഡ്</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">ക്രമീകരണങ്ങള്‍...</translation>
-<translation id="6845383723252244143">ഫോള്‍ഡര്‍ തിരഞ്ഞെടുക്കുക</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> സെക്കൻഡ്</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> സെക്കന്റ്</translation>
-<translation id="5583640892426849032">ബാക്ക്‌സ്പെയ്‌സ്</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ദിവസം</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> മണിക്കൂര്‍</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ദിവസം</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ് മുമ്പ്</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
-<translation id="4570886800634958009">അറിയിപ്പ് വിപുലീകരണം</translation>
-<translation id="436869212180315161">അമര്‍ത്തുക</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> മിനിറ്റ്</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
-<translation id="6040143037577758943">അടയ്ക്കുക</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">സഹായം</translation>
-<translation id="6699343763173986273">അടുത്ത മീഡിയ ട്രാക്ക്</translation>
-<translation id="8226233771743600312">ഒരു ദിവസത്തേക്ക് ശല്യപ്പെടുത്തരുത്</translation>
-<translation id="7457942297256758195">എല്ലാം മായ്‌ക്കുക</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> മിനിറ്റ്</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ദിവസം അവശേഷിക്കുന്നു</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> മിനിറ്റ്</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ്</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> സെക്കന്റ്</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> സെക്കൻഡ്</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ദിവസം‍ അവശേഷിക്കുന്നു</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക</translation>
-<translation id="8371695176452482769">ഇപ്പോള്‍ സംസാരിക്കുക</translation>
-<translation id="6965382102122355670">ശരി</translation>
-<translation id="7850320739366109486">ശല്യം ചെയ്യരുത്</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">ചെറുതാക്കുക‍</translation>
-<translation id="6394627529324717982">കോമ</translation>
-<translation id="3036649622769666520">ഫയലുകള്‍‌ തുറക്കുക</translation>
-<translation id="8328145009876646418">ഇടത് അഗ്രം</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> സെക്കൻഡ്</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_mr.xtb b/chromium/ui/base/strings/ui_strings_mr.xtb
deleted file mode 100644
index 733441dd0ef..00000000000
--- a/chromium/ui/base/strings/ui_strings_mr.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="mr">
-<translation id="4820616160060340806">आदेश+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">समाप्त</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> से बाकी</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> से बाकी</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> मिनिटे बाकी</translation>
-<translation id="1801827354178857021">अवधी</translation>
-<translation id="1190609913194133056">सूचना केंद्र</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> मिनिटे शिल्लक</translation>
-<translation id="5613020302032141669">Left Arrow</translation>
-<translation id="4971687151119236543">मीडिया मागील ट्रॅक</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> फाइल (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> से</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> तास बाकी</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> मधून <ph name="NUMBER_OF_NOTIFICATIONS"/> अधिक</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">रद्द करा</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Up Arrow</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> तास</translation>
-<translation id="3990502903496589789">उजवा काठ</translation>
-<translation id="9038489124413477075">अनामित फोल्डर</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> मि</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> दिवस बाकी</translation>
-<translation id="932327136139879170">मुख्यपृष्ठ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> मि बाकी</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> दिवस बाकी</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> से बाकी</translation>
-<translation id="3909791450649380159">क&amp;ट करा</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> मिनिटे शिल्लक</translation>
-<translation id="688711909580084195">अशीर्षकांकीत वेबपृष्‍ठ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;पेस्ट करा</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">अपलोड करण्यासाठी फोल्डर निवडा</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Down Arrow</translation>
-<translation id="3087734570205094154">तळाकडील</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> मि बाकी</translation>
-<translation id="1860796786778352021">सूचना बंद</translation>
-<translation id="6364916375976753737">डावीकडे स्क्रोल करा</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> मिनिटे</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">निवडा</translation>
-<translation id="6620110761915583480">फाइल जतन करा</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> सेकंद</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> मिनिट शिल्लक</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> मि</translation>
-<translation id="8210608804940886430">पृष्ठ खाली</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> दिवस</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> तास बाकी</translation>
-<translation id="5329858601952122676">&amp;हटवा</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> से</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> मिनिटे</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">काल</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> मिनिटे</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> मि बाकी</translation>
-<translation id="6659594942844771486">टॅब</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">सेटिंग्ज</translation>
-<translation id="2497284189126895209">सर्व फाइल</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> मिनिटे शिल्लक</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> से</translation>
-<translation id="7814458197256864873">&amp;कॉपी करा</translation>
-<translation id="3889424535448813030">Right Arrow</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> से बाकी</translation>
-<translation id="6829324100069873704">सूचनांवर परत जा</translation>
-<translation id="6528179044667508675">व्यत्यय आणू नका</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> सेकंद</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> मि</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">खालील लोकांकडील सूचनांना अनुमत करा:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> तास</translation>
-<translation id="1398853756734560583">वाढवा</translation>
-<translation id="4250229828105606438">स्क्रीनशॉट</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> तास</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> मि बाकी</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;सर्व निवडा</translation>
-<translation id="2168039046890040389">पृष्ठ वर</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> दिवस</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> मि</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> मिनिट</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">येथे पाहण्यासाठी काही नाही, पुढे चला.</translation>
-<translation id="2482878487686419369">सूचना</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">येथे स्क्रोल करा</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> तास</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">मीडिया प्ले करा/विराम द्या</translation>
-<translation id="2148716181193084225">आज</translation>
-<translation id="7960078400008666149">एक तास व्यत्यय आणू नका</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> दिवस</translation>
-<translation id="2190355936436201913">(रिक्त)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> तास बाकी</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> से बाकी</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">उजवे स्क्रोल करा</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> तास बाकी</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> वरील सूचना अक्षम करा</translation>
-<translation id="2666092431469916601">शीर्ष</translation>
-<translation id="8331626408530291785">वर स्क्रोल करा</translation>
-<translation id="7907591526440419938">फाइल उघडा</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">खाली स्क्रोल करा</translation>
-<translation id="6808150112686056157">मीडिया थांबवा</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">पुनर्संचयित करा</translation>
-<translation id="1243314992276662751">अपलोड करा</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> दिवस बाकी</translation>
-<translation id="8179976553408161302">प्रवेश करा</translation>
-<translation id="945522503751344254">अभिप्राय पाठवा</translation>
-<translation id="9170848237812810038">&amp;पूर्ववत करा</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">प्रत्येक वापरकर्त्यासाठी खालील मधून सूचनांना अनुमती द्या:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> सेकंद</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> मिनिटे शिल्लक</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">सेटिंग्ज...</translation>
-<translation id="6845383723252244143">फोल्डर निवडा</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> सेकंद</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> से</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> दिवस</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> तास</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> दिवस</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> से बाकी</translation>
-<translation id="4570886800634958009">सूचना विस्तार</translation>
-<translation id="436869212180315161">दाबा</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> मिनिटे</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> मिनिटे शिल्लक</translation>
-<translation id="6040143037577758943">बंद करा</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">मदत</translation>
-<translation id="6699343763173986273">मीडिया पुढील ट्रॅक</translation>
-<translation id="8226233771743600312">एक दिवस व्यत्यय आणू नका</translation>
-<translation id="7457942297256758195">सर्व साफ करा</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> मि</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> दिवस बाकी</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> मिनिटे</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> तास बाकी</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> से</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> से</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> सेकंद</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> दिवस बाकी</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">क्लिपबोर्डवर कॉपी करा</translation>
-<translation id="8371695176452482769">आता बोला</translation>
-<translation id="6965382102122355670">ठिक आहे</translation>
-<translation id="7850320739366109486">व्यत्यय आणू नका</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">लहान करा</translation>
-<translation id="6394627529324717982">स्वल्पविराम</translation>
-<translation id="3036649622769666520">फायली उघडा</translation>
-<translation id="8328145009876646418">डावे काठ</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> सेकंद</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ms.xtb b/chromium/ui/base/strings/ui_strings_ms.xtb
deleted file mode 100644
index 82263788e03..00000000000
--- a/chromium/ui/base/strings/ui_strings_ms.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ms">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> jam yang lalu</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> saat lagi</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> saat lagi</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minit lagi</translation>
-<translation id="1801827354178857021">Tempoh</translation>
-<translation id="1190609913194133056">Pusat Pemberitahuan</translation>
-<translation id="7470933019269157899">Tinggal <ph name="NUMBER_DEFAULT"/> minit</translation>
-<translation id="5613020302032141669">Anak Panah Kiri</translation>
-<translation id="4971687151119236543">Lagu Media Sebelumnya</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fail (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> minit yang lalu</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> saat</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> jam lagi</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> lagi dari <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Batal</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Anak Panah Atas</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> jam</translation>
-<translation id="3990502903496589789">Tepi Kanan</translation>
-<translation id="9038489124413477075">Folder Tanpa Nama</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mins</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> hari lagi</translation>
-<translation id="932327136139879170">Halaman Utama</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minit lagi</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> hari lagi</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> saat lagi</translation>
-<translation id="3909791450649380159">Po&amp;tong</translation>
-<translation id="2560788951337264832">Tinggal <ph name="NUMBER_ZERO"/> minit</translation>
-<translation id="688711909580084195">Laman Web Tidak Bertajuk</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> hari yang lalu</translation>
-<translation id="5076340679995252485">&amp;Tampal</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Pilih Folder untuk Dimuat Naik</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minit lalu</translation>
-<translation id="3234408098842461169">Anak Panah Bawah</translation>
-<translation id="3087734570205094154">Bawah</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minit lagi</translation>
-<translation id="1860796786778352021">Tutup Pemberitahuan</translation>
-<translation id="6364916375976753737">Tatal Ke Kiri</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> jam yang lalu</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minit</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minit yang lalu</translation>
-<translation id="6945221475159498467">Pilih</translation>
-<translation id="6620110761915583480">Simpan Fail</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> saat</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> jam</translation>
-<translation id="7836361698254323868">Tinggal <ph name="NUMBER_ONE"/> minit</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minit</translation>
-<translation id="8210608804940886430">Ke Bawah Halaman</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> hari</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> jam lagi</translation>
-<translation id="5329858601952122676">&amp;Padam</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> saat</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minit</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> saat yang lalu</translation>
-<translation id="7781829728241885113">Semalam</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minit</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minit lagi</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> hari yang lalu</translation>
-<translation id="8428213095426709021">Tetapan</translation>
-<translation id="2497284189126895209">Semua Fail</translation>
-<translation id="7487278341251176613">Tinggal <ph name="NUMBER_TWO"/> minit</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> hari yang lalu</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> saat</translation>
-<translation id="7814458197256864873">&amp;Salin</translation>
-<translation id="3889424535448813030">Anak Panah Kanan</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> saat yang lalu</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> saat lagi</translation>
-<translation id="6829324100069873704">Kembali ke pemberitahuan</translation>
-<translation id="6528179044667508675">Jangan ganggu</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> saat</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> jam lagi</translation>
-<translation id="7135556860107312402">Benarkan pemberitahuan daripada yang berikut:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> jam</translation>
-<translation id="1398853756734560583">Maksimumkan</translation>
-<translation id="4250229828105606438">Tangkapan skrin</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> jam</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minit lagi</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Pilih &amp;semua</translation>
-<translation id="2168039046890040389">Halaman Ke Atas</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> hari</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minit</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> saat yang lalu</translation>
-<translation id="4927753642311223124">Tiada apa-apa untuk dilihat di sini, teruskan.</translation>
-<translation id="2482878487686419369">Pemberitahuan</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> hari</translation>
-<translation id="3183922693828471536">Tatal ke Sini</translation>
-<translation id="4552416320897244156">BwhHlmn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> jam</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Main/Jeda Media</translation>
-<translation id="2148716181193084225">Hari ini</translation>
-<translation id="7960078400008666149">Jangan ganggu selama sejam</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minit yang lalu</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> hari</translation>
-<translation id="2190355936436201913">(kosong)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> jam lagi</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> saat lagi</translation>
-<translation id="8447116497070723931">AtsHlmn</translation>
-<translation id="4588090240171750605">Tatal ke Kanan</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> jam lagi</translation>
-<translation id="1413622004203049571">Lumpuhkan pemberitahuan daripada <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Atas</translation>
-<translation id="8331626408530291785">Tatal Ke Atas</translation>
-<translation id="7907591526440419938">Buka Fail</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> hari lagi</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> jam lalu</translation>
-<translation id="815598010540052116">Tatal Ke Bawah</translation>
-<translation id="6808150112686056157">Media Berhenti</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> minit lagi</translation>
-<translation id="3157931365184549694">Pulihkan</translation>
-<translation id="1243314992276662751">Muat naik</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> hari lagi</translation>
-<translation id="8179976553408161302">Masuk</translation>
-<translation id="945522503751344254">Hantar maklum balas</translation>
-<translation id="9170848237812810038">&amp;Buat asal</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> jam yang lalu</translation>
-<translation id="6918245111648057970">Benarkan pemberitahuan daripada yang berikut untuk setiap pengguna:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> saat</translation>
-<translation id="3994835489895548312">Tinggal <ph name="NUMBER_MANY"/> minit</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> saat yang lalu</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Tetapan...</translation>
-<translation id="6845383723252244143">Pilih Folder</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> saat</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> saat</translation>
-<translation id="5583640892426849032">Undur ruang</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> hari yang lalu</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> hari</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> jam</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minit yang lalu</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> jam yang lalu</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> hari</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> saat yang lalu</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> saat lagi</translation>
-<translation id="4570886800634958009">Kembangkan pemberitahuan</translation>
-<translation id="436869212180315161">Tekan</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> saat yang lalu</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minit</translation>
-<translation id="1858722859751911017">Tinggal <ph name="NUMBER_FEW"/> minit</translation>
-<translation id="6040143037577758943">Tutup</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minit yang lalu</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Bantuan</translation>
-<translation id="6699343763173986273">Lagu Media Seterusnya</translation>
-<translation id="8226233771743600312">Jangan ganggu selama sehari</translation>
-<translation id="7457942297256758195">Kosongkan Semua</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> hari yang lalu</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> hari lagi</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minit</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> jam lagi</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> jam yang lalu</translation>
-<translation id="8400147561352026160">Anjak+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> saat</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> saat</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> saat</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> hari lagi</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Salin ke papan keratan</translation>
-<translation id="8371695176452482769">Cakap sekarang</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Jangan Ganggu</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> hari yang lalu</translation>
-<translation id="5941711191222866238">Minimumkan</translation>
-<translation id="6394627529324717982">Koma</translation>
-<translation id="3036649622769666520">Buka Fail</translation>
-<translation id="8328145009876646418">Tepi Kiri</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> saat</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_nl.xtb b/chromium/ui/base/strings/ui_strings_nl.xtb
deleted file mode 100644
index 1e5591570cb..00000000000
--- a/chromium/ui/base/strings/ui_strings_nl.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="nl">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> uur geleden</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> seconden resterend</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> seconden resterend</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuten resterend</translation>
-<translation id="1801827354178857021">Punt</translation>
-<translation id="1190609913194133056">Meldingscentrum</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuten resterend</translation>
-<translation id="5613020302032141669">Pijl-links</translation>
-<translation id="4971687151119236543">Vorige track voor media</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-bestand (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seconden</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> uur resterend</translation>
-<translation id="8717309436826820190">Nog <ph name="NUMBER_OF_NOTIFICATIONS"/> andere van <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Annuleren</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Pijl-omhoog</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> uur</translation>
-<translation id="3990502903496589789">Rechterzijde</translation>
-<translation id="9038489124413477075">Naamloze map</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuten</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dagen resterend</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuten resterend</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dagen resterend</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> seconden resterend</translation>
-<translation id="3909791450649380159">&amp;Knippen</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minuten resterend</translation>
-<translation id="688711909580084195">Naamloze webpagina</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dagen geleden</translation>
-<translation id="5076340679995252485">&amp;Plakken</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Map voor uploaden selecteren</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuten geleden</translation>
-<translation id="3234408098842461169">Pijl-omlaag</translation>
-<translation id="3087734570205094154">Onderaan</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minuut resterend</translation>
-<translation id="1860796786778352021">Melding sluiten</translation>
-<translation id="6364916375976753737">Naar links bladeren</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> uur geleden</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuten</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuten geleden</translation>
-<translation id="6945221475159498467">Selecteren</translation>
-<translation id="6620110761915583480">Bestand opslaan</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconden</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuut resterend</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuut</translation>
-<translation id="8210608804940886430">Pagina omlaag</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dagen</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> uur resterend</translation>
-<translation id="5329858601952122676">Verwij&amp;deren</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seconden</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> seconden geleden</translation>
-<translation id="7781829728241885113">Gisteren</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuten</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuten resterend</translation>
-<translation id="6659594942844771486">Tabblad</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dagen geleden</translation>
-<translation id="8428213095426709021">Instellingen</translation>
-<translation id="2497284189126895209">Alle bestanden</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minuten resterend</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dag geleden</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
-<translation id="7814458197256864873">&amp;Kopiëren</translation>
-<translation id="3889424535448813030">Pijl-rechts</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> seconde geleden</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> seconden resterend</translation>
-<translation id="6829324100069873704">Terug naar meldingen</translation>
-<translation id="6528179044667508675">Niet storen</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> seconden</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuten</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Meldingen toestaan van het volgende:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> uur</translation>
-<translation id="1398853756734560583">Maximaliseren</translation>
-<translation id="4250229828105606438">Screenshot</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> uur</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuten resterend</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;Alles selecteren</translation>
-<translation id="2168039046890040389">Pagina omhoog</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dagen</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuten</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuut</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> seconden geleden</translation>
-<translation id="4927753642311223124">Er zijn geen meldingen.</translation>
-<translation id="2482878487686419369">Meldingen</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Hiernaartoe bladeren</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> uur</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Media afspelen/onderbreken</translation>
-<translation id="2148716181193084225">Vandaag</translation>
-<translation id="7960078400008666149">Een uur niet storen</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuten geleden</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dagen</translation>
-<translation id="2190355936436201913">(leeg)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> uur resterend</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seconde resterend</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Naar rechts bladeren</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> uur resterend</translation>
-<translation id="1413622004203049571">Meldingen van <ph name="NOTIFIER_NAME"/> uitschakelen</translation>
-<translation id="2666092431469916601">Boven</translation>
-<translation id="8331626408530291785">Omhoog bladeren</translation>
-<translation id="7907591526440419938">Bestand openen</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> uur geleden</translation>
-<translation id="815598010540052116">Omlaag bladeren</translation>
-<translation id="6808150112686056157">Media stoppen</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Herstellen</translation>
-<translation id="1243314992276662751">Uploaden</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag resterend</translation>
-<translation id="8179976553408161302">Beginnen</translation>
-<translation id="945522503751344254">Feedback verzenden</translation>
-<translation id="9170848237812810038">&amp;Ongedaan maken</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> uur geleden</translation>
-<translation id="6918245111648057970">Melden van het volgende toestaan voor elke gebruiker:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> seconde</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minuten resterend</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> seconden geleden</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Instellingen...</translation>
-<translation id="6845383723252244143">Map selecteren</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seconden</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> dagen geleden</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dagen</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> uur</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuut geleden</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> seconden geleden</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> seconden resterend</translation>
-<translation id="4570886800634958009">Melding uitbreiden</translation>
-<translation id="436869212180315161">Drukken</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> seconden geleden</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuten</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minuten resterend</translation>
-<translation id="6040143037577758943">Sluiten</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuten geleden</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Help</translation>
-<translation id="6699343763173986273">Volgende track voor media</translation>
-<translation id="8226233771743600312">Een dag niet storen</translation>
-<translation id="7457942297256758195">Alles wissen</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dagen geleden</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuten</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dagen resterend</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> uur resterend</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> uur geleden</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seconden</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seconden</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dagen resterend</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopiëren naar klembord</translation>
-<translation id="8371695176452482769">Begin nu te spreken</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Niet storen</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimaliseren</translation>
-<translation id="6394627529324717982">Komma</translation>
-<translation id="3036649622769666520">Bestanden openen</translation>
-<translation id="8328145009876646418">Linkerzijde</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconden</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_no.xtb b/chromium/ui/base/strings/ui_strings_no.xtb
deleted file mode 100644
index 44b9eacfe94..00000000000
--- a/chromium/ui/base/strings/ui_strings_no.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="no">
-<translation id="4820616160060340806">Kommando + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekunder igjen</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekunder igjen</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutter igjen</translation>
-<translation id="1801827354178857021">Punktum</translation>
-<translation id="1190609913194133056">Varselsenter</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutter igjen</translation>
-<translation id="5613020302032141669">Pil venstre</translation>
-<translation id="4971687151119236543">Media – forrige spor</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekunder</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timer igjen</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> til fra <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Avbryt</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Pil opp</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB per sek.</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timer</translation>
-<translation id="3990502903496589789">Høyre kant</translation>
-<translation id="9038489124413477075">Mappe uten navn</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutter</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dager igjen</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutter igjen</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dager igjen</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekunder igjen</translation>
-<translation id="3909791450649380159">Klipp u&amp;t</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutter igjen</translation>
-<translation id="688711909580084195">Nettside uten tittel</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Lim inn</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Velg mappen du vil laste opp</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Pil ned</translation>
-<translation id="3087734570205094154">Bunn</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutt igjen</translation>
-<translation id="1860796786778352021">Lukk varsel</translation>
-<translation id="6364916375976753737">Rull mot venstre</translation>
-<translation id="2629089419211541119">For <ph name="NUMBER_ONE"/> time siden</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutter</translation>
-<translation id="6982279413068714821">For <ph name="NUMBER_DEFAULT"/> minutter siden</translation>
-<translation id="6945221475159498467">Velg</translation>
-<translation id="6620110761915583480">Lagre fil</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minutt igjen</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minutt</translation>
-<translation id="8210608804940886430">Ned 1 s.</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dager</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timer igjen</translation>
-<translation id="5329858601952122676">&amp;Slett</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekunder</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutter</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">I går</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutter</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutter igjen</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">For <ph name="NUMBER_DEFAULT"/> dager siden</translation>
-<translation id="8428213095426709021">Innstillinger</translation>
-<translation id="2497284189126895209">Alle filer</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutter igjen</translation>
-<translation id="5110450810124758964">For <ph name="NUMBER_ONE"/> dag siden</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="7814458197256864873">&amp;Kopier</translation>
-<translation id="3889424535448813030">Pil høyre</translation>
-<translation id="4229495110203539533">For <ph name="NUMBER_ONE"/> sekund siden</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekunder igjen</translation>
-<translation id="6829324100069873704">Gå tilbake til varsler</translation>
-<translation id="6528179044667508675">Ikke forstyrr</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutter</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Tillat varsler fra følgende:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timer</translation>
-<translation id="1398853756734560583">Maksimer</translation>
-<translation id="4250229828105606438">Skjermdump</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timer</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutter igjen</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Marker &amp;alt</translation>
-<translation id="2168039046890040389">Opp 1 s.</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dager</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutter</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minutt</translation>
-<translation id="8448317557906454022">For <ph name="NUMBER_ZERO"/> sekunder siden</translation>
-<translation id="4927753642311223124">Det er ikke noe å se her. Gå videre.</translation>
-<translation id="2482878487686419369">Varslinger</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Rull hit</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timer</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB per sek</translation>
-<translation id="8394908167088220973">Media – spill av / pause</translation>
-<translation id="2148716181193084225">I dag</translation>
-<translation id="7960078400008666149">Ikke forstyrr i én time</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dager</translation>
-<translation id="2190355936436201913">(tom)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timer igjen</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekund igjen</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Rull mot høyre</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> time igjen</translation>
-<translation id="1413622004203049571">Deaktiver varsler fra <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Topp</translation>
-<translation id="8331626408530291785">Rull opp</translation>
-<translation id="7907591526440419938">Åpne filen</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">For <ph name="NUMBER_DEFAULT"/> timer siden</translation>
-<translation id="815598010540052116">Rull ned</translation>
-<translation id="6808150112686056157">Media – stopp</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Gjenopprett</translation>
-<translation id="1243314992276662751">Last opp</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag igjen</translation>
-<translation id="8179976553408161302">Start</translation>
-<translation id="945522503751344254">Gi tilbakemelding</translation>
-<translation id="9170848237812810038">&amp;Angre</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Tillat varsler fra følgende for hver bruker:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutter igjen</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Innstillinger</translation>
-<translation id="6845383723252244143">Velg mappe</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekunder</translation>
-<translation id="5583640892426849032">Tilbake-tasten</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dager</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> time</translation>
-<translation id="2679312662830811292">For <ph name="NUMBER_ONE"/> minutt siden</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB per sek</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
-<translation id="9098468523912235228">For <ph name="NUMBER_DEFAULT"/> sekunder siden</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekunder igjen</translation>
-<translation id="4570886800634958009">Utvid varsel</translation>
-<translation id="436869212180315161">Trykk</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB per sek</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutter</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutter igjen</translation>
-<translation id="6040143037577758943">Lukk</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B per sek</translation>
-<translation id="7649070708921625228">Hjelp</translation>
-<translation id="6699343763173986273">Media – neste spor</translation>
-<translation id="8226233771743600312">Ikke forstyrr i en dag</translation>
-<translation id="7457942297256758195">Fjern alle</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutter</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dager igjen</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutter</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timer igjen</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekunder</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dager igjen</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB per sek</translation>
-<translation id="2743387203779672305">Kopiér til utklippstavlen</translation>
-<translation id="8371695176452482769">Snakk nå</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Ikke forstyrr</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimer</translation>
-<translation id="6394627529324717982">Komma</translation>
-<translation id="3036649622769666520">Åpne filer</translation>
-<translation id="8328145009876646418">Venstre kant</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_pl.xtb b/chromium/ui/base/strings/ui_strings_pl.xtb
deleted file mode 100644
index e754dd2e0aa..00000000000
--- a/chromium/ui/base/strings/ui_strings_pl.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="pl">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sek</translation>
-<translation id="9213479837033539041">Pozostało: <ph name="NUMBER_MANY"/> sek</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="1801827354178857021">Okres</translation>
-<translation id="1190609913194133056">Centrum powiadomień</translation>
-<translation id="7470933019269157899">Pozostało <ph name="NUMBER_DEFAULT"/> minut</translation>
-<translation id="5613020302032141669">Strzałka w lewo</translation>
-<translation id="4971687151119236543">Poprzedni utwór multimedialny</translation>
-<translation id="8602707065186045623">Plik <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> godz</translation>
-<translation id="8717309436826820190">Jeszcze <ph name="NUMBER_OF_NOTIFICATIONS"/> z <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Anuluj</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Strzałka w górę</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> godz.</translation>
-<translation id="3990502903496589789">Krawędź po prawej</translation>
-<translation id="9038489124413477075">Folder bez nazwy</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dni</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dni</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sek</translation>
-<translation id="3909791450649380159">Wy&amp;tnij</translation>
-<translation id="2560788951337264832">Pozostało <ph name="NUMBER_ZERO"/> minut</translation>
-<translation id="688711909580084195">Strona internetowa bez tytułu</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dni temu</translation>
-<translation id="5076340679995252485">&amp;Wklej</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Wybierz folder do przesłania</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> min temu</translation>
-<translation id="3234408098842461169">Strzałka w dół</translation>
-<translation id="3087734570205094154">Na dół</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min do końca</translation>
-<translation id="1860796786778352021">Zamknięcie powiadomienia</translation>
-<translation id="6364916375976753737">Przewiń w lewo</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> godz. temu</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuty</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> min temu</translation>
-<translation id="6945221475159498467">Wybierz</translation>
-<translation id="6620110761915583480">Zapisz plik</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Pozostała <ph name="NUMBER_ONE"/> minuta</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Strona w dół</translation>
-<translation id="1572103024875503863">Liczba dni: <ph name="NUMBER_MANY"/></translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> godz</translation>
-<translation id="5329858601952122676">&amp;Usuń</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Wczoraj</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dni temu</translation>
-<translation id="8428213095426709021">Ustawienia</translation>
-<translation id="2497284189126895209">Wszystkie pliki</translation>
-<translation id="7487278341251176613">Pozostały <ph name="NUMBER_TWO"/> minuty</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dzień temu</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
-<translation id="7814458197256864873">&amp;Kopiuj</translation>
-<translation id="3889424535448813030">Strzałka w prawo</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> s temu</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sek</translation>
-<translation id="6829324100069873704">Wróć do powiadomień</translation>
-<translation id="6528179044667508675">Nie przeszkadzać</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundy</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Zezwalaj na powiadomienia z:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> godz.</translation>
-<translation id="1398853756734560583">Maksymalizuj</translation>
-<translation id="4250229828105606438">Zrzut ekranu</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> godz.</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Zaznacz &amp;wszystko</translation>
-<translation id="2168039046890040389">Strona do góry</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581">Liczba dni: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Nic tu nie ma.</translation>
-<translation id="2482878487686419369">Powiadomienia</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Przewiń tutaj</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> godz.</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Odtwórz/wstrzymaj multimedia</translation>
-<translation id="2148716181193084225">Dzisiaj</translation>
-<translation id="7960078400008666149">Nie przeszkadzać przez godzinę</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> min temu</translation>
-<translation id="4115153316875436289">Liczba dni: <ph name="NUMBER_TWO"/></translation>
-<translation id="2190355936436201913">(puste)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> godz</translation>
-<translation id="152482086482215392">Pozostała <ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Przewiń w prawo</translation>
-<translation id="7414887922320653780">Pozostała <ph name="NUMBER_ONE"/> godzina</translation>
-<translation id="1413622004203049571">Wyłącz powiadomienia z <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Do góry</translation>
-<translation id="8331626408530291785">Przewiń w górę</translation>
-<translation id="7907591526440419938">Otwórz plik</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> godz. temu</translation>
-<translation id="815598010540052116">Przewiń w dół</translation>
-<translation id="6808150112686056157">Zatrzymaj multimedia</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Przywróć</translation>
-<translation id="1243314992276662751">Prześlij</translation>
-<translation id="50030952220075532">Pozostał <ph name="NUMBER_ONE"/> dzień</translation>
-<translation id="8179976553408161302">Start</translation>
-<translation id="945522503751344254">Wyślij zgłoszenie</translation>
-<translation id="9170848237812810038">&amp;Cofnij</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> godz. temu</translation>
-<translation id="6918245111648057970">Zezwól na powiadomienia dla każdego użytkownika z:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="3994835489895548312">Pozostało <ph name="NUMBER_MANY"/> minut</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Ustawienia</translation>
-<translation id="6845383723252244143">Wybierz folder</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundy</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920">Liczba dni: <ph name="NUMBER_FEW"/></translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> godz.</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min temu</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dzień</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> s temu</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sek</translation>
-<translation id="4570886800634958009">Rozwinięcie powiadomienia</translation>
-<translation id="436869212180315161">Kliknij</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> s temu</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">Pozostały <ph name="NUMBER_FEW"/> minuty</translation>
-<translation id="6040143037577758943">Zamknij</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Pomoc</translation>
-<translation id="6699343763173986273">Następny utwór multimedialny</translation>
-<translation id="8226233771743600312">Nie przeszkadzać przez jeden dzień</translation>
-<translation id="7457942297256758195">Wyczyść wszystkie</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dni temu</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dni</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuty</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> godz</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dni</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Skopiuj do schowka</translation>
-<translation id="8371695176452482769">Mów teraz</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Nie przeszkadzać</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimalizuj</translation>
-<translation id="6394627529324717982">Przecinek</translation>
-<translation id="3036649622769666520">Otwórz pliki</translation>
-<translation id="8328145009876646418">Krawędź po lewej</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_pt-BR.xtb b/chromium/ui/base/strings/ui_strings_pt-BR.xtb
deleted file mode 100644
index 13fa1e89e5b..00000000000
--- a/chromium/ui/base/strings/ui_strings_pt-BR.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="pt-BR">
-<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> segundos restantes</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> segundos restantes</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutos restantes</translation>
-<translation id="1801827354178857021">Ponto final</translation>
-<translation id="1190609913194133056">Central de Notificações</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutos restantes</translation>
-<translation id="5613020302032141669">Seta para a esquerda</translation>
-<translation id="4971687151119236543">Faixa anterior da mídia</translation>
-<translation id="8602707065186045623">Arquivo <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> horas restantes</translation>
-<translation id="8717309436826820190">Mais <ph name="NUMBER_OF_NOTIFICATIONS"/> de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancelar</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> bytes</translation>
-<translation id="3660179305079774227">Seta para cima</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="3990502903496589789">Borda direita</translation>
-<translation id="9038489124413477075">Pasta sem nome</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dias restantes</translation>
-<translation id="932327136139879170">Página inicial</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutos restantes</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dias restantes</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> segundos restantes</translation>
-<translation id="3909791450649380159">&amp;Recortar</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Página da web sem título</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Colar</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Selecionar pasta para upload</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Seta para baixo</translation>
-<translation id="3087734570205094154">Parte inferior</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutos restantes</translation>
-<translation id="1860796786778352021">Fechar notificação</translation>
-<translation id="6364916375976753737">Percorrer à esquerda</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hora atrás</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutos atrás</translation>
-<translation id="6945221475159498467">Selecionar</translation>
-<translation id="6620110761915583480">Salvar arquivo</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto restante</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8210608804940886430">Página para baixo</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dias</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> horas restantes</translation>
-<translation id="5329858601952122676">&amp;Excluir</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Ontem</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutos restantes</translation>
-<translation id="6659594942844771486">Guia</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dias atrás</translation>
-<translation id="8428213095426709021">Configurações</translation>
-<translation id="2497284189126895209">Todos os arquivos</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dia atrás</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
-<translation id="7814458197256864873">Co&amp;piar</translation>
-<translation id="3889424535448813030">Seta para a direita</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> segundo atrás</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> segundos restantes</translation>
-<translation id="6829324100069873704">Voltar para notificações</translation>
-<translation id="6528179044667508675">Não perturbe</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Permitir as seguintes notificações:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
-<translation id="1398853756734560583">Maximizar</translation>
-<translation id="4250229828105606438">Captura de tela</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutos restantes</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Selecionar &amp;tudo</translation>
-<translation id="2168039046890040389">Página para cima</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dias</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Nada para ver aqui, siga em frente.</translation>
-<translation id="2482878487686419369">Notificações</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Percorrer até aqui</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Reproduzir/pausar mídia</translation>
-<translation id="2148716181193084225">Hoje</translation>
-<translation id="7960078400008666149">Não perturbe por uma hora</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dias</translation>
-<translation id="2190355936436201913">(vazio)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> horas restantes</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> segundo restante</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Percorrer à direita</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hora restante</translation>
-<translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Parte superior</translation>
-<translation id="8331626408530291785">Percorrer para cima</translation>
-<translation id="7907591526440419938">Abrir arquivo</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> horas atrás</translation>
-<translation id="815598010540052116">Percorrer para baixo</translation>
-<translation id="6808150112686056157">Parar mídia</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaurar</translation>
-<translation id="1243314992276662751">Fazer upload</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restante</translation>
-<translation id="8179976553408161302">Entrar</translation>
-<translation id="945522503751344254">Enviar comentários</translation>
-<translation id="9170848237812810038">&amp;Desfazer</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Permitir as seguintes notificações para cada usuário:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Configurações...</translation>
-<translation id="6845383723252244143">Selecionar pasta</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dias</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto atrás</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> segundos atrás</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> segundos restantes</translation>
-<translation id="4570886800634958009">Expandir notificação</translation>
-<translation id="436869212180315161">Apertar</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
-<translation id="6040143037577758943">Fechar</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Ajuda</translation>
-<translation id="6699343763173986273">Próxima faixa da mídia</translation>
-<translation id="8226233771743600312">Não perturbe por um dia</translation>
-<translation id="7457942297256758195">Limpar tudo</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dias restantes</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> horas restantes</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dias restantes</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copiar para a área de trabalho</translation>
-<translation id="8371695176452482769">Fale agora</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Não Perturbe</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimizar</translation>
-<translation id="6394627529324717982">Vírgula</translation>
-<translation id="3036649622769666520">Abrir arquivos</translation>
-<translation id="8328145009876646418">Borda esquerda</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_pt-PT.xtb b/chromium/ui/base/strings/ui_strings_pt-PT.xtb
deleted file mode 100644
index b649dfd1ce1..00000000000
--- a/chromium/ui/base/strings/ui_strings_pt-PT.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="pt-PT">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798">Há <ph name="NUMBER_MANY"/> horas</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> seg. restantes</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> seg. restantes</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min. restantes</translation>
-<translation id="1801827354178857021">Ponto final</translation>
-<translation id="1190609913194133056">Centro de Notificações</translation>
-<translation id="7470933019269157899">Faltam <ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="5613020302032141669">Seta para a esquerda</translation>
-<translation id="4971687151119236543">Faixa anterior de multimédia</translation>
-<translation id="8602707065186045623">Ficheiro <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> horas restantes</translation>
-<translation id="8717309436826820190">Mais <ph name="NUMBER_OF_NOTIFICATIONS"/> de <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Cancelar</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Seta para cima</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="3990502903496589789">Margem direita</translation>
-<translation id="9038489124413477075">Pasta sem nome</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dias restantes</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min. restantes</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dias restantes</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> seg. restantes</translation>
-<translation id="3909791450649380159">Cor&amp;tar</translation>
-<translation id="2560788951337264832">Faltam <ph name="NUMBER_ZERO"/> minutos</translation>
-<translation id="688711909580084195">Página Web Sem Nome</translation>
-<translation id="3353284378027041011">Há <ph name="NUMBER_FEW"/> dias</translation>
-<translation id="5076340679995252485">C&amp;olar</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Selecionar Pasta a Carregar</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Há <ph name="NUMBER_TWO"/> min.</translation>
-<translation id="3234408098842461169">Seta para baixo</translation>
-<translation id="3087734570205094154">Parte inferior</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min. restante</translation>
-<translation id="1860796786778352021">Fechar notificação</translation>
-<translation id="6364916375976753737">Deslocar-se para a esquerda</translation>
-<translation id="2629089419211541119">Há <ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
-<translation id="6982279413068714821">Há <ph name="NUMBER_DEFAULT"/> min.</translation>
-<translation id="6945221475159498467">Seleccionar</translation>
-<translation id="6620110761915583480">Guardar ficheiro</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Falta <ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8210608804940886430">Página para baixo</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dias</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> horas restantes</translation>
-<translation id="5329858601952122676">E&amp;liminar</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="7275974018215686543">Há <ph name="NUMBER_MANY"/> seg.</translation>
-<translation id="7781829728241885113">Ontem</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min. restantes</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Há <ph name="NUMBER_DEFAULT"/> dias</translation>
-<translation id="8428213095426709021">Definições</translation>
-<translation id="2497284189126895209">Todos os ficheiros</translation>
-<translation id="7487278341251176613">Faltam <ph name="NUMBER_TWO"/> minutos</translation>
-<translation id="5110450810124758964">Há <ph name="NUMBER_ONE"/> dia</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> seg.</translation>
-<translation id="7814458197256864873">&amp;Copiar</translation>
-<translation id="3889424535448813030">Seta para a direita</translation>
-<translation id="4229495110203539533">Há <ph name="NUMBER_ONE"/> seg.</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> seg. restantes</translation>
-<translation id="6829324100069873704">Voltar às notificações</translation>
-<translation id="6528179044667508675">Não incomodar</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Permitir notificações de:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
-<translation id="1398853756734560583">Maximizar</translation>
-<translation id="4250229828105606438">Captura de ecrã</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min. restantes</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Seleccion&amp;ar tudo</translation>
-<translation id="2168039046890040389">Página para cima</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dias</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
-<translation id="8448317557906454022">Há <ph name="NUMBER_ZERO"/> seg.</translation>
-<translation id="4927753642311223124">Nada de novo a apresentar por aqui.</translation>
-<translation id="2482878487686419369">Notificações</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Deslocar-se para aqui</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Reproduzir/interromper multimédia</translation>
-<translation id="2148716181193084225">Hoje</translation>
-<translation id="7960078400008666149">Não incomodar durante uma hora</translation>
-<translation id="4373894838514502496">Há <ph name="NUMBER_FEW"/> min.</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dias</translation>
-<translation id="2190355936436201913">(vazio)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> horas restantes</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seg. restante</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Deslocar-se para a direita</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hora restante</translation>
-<translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Parte superior</translation>
-<translation id="8331626408530291785">Deslocar-se para cima</translation>
-<translation id="7907591526440419938">Abrir ficheiro</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Há <ph name="NUMBER_DEFAULT"/> horas</translation>
-<translation id="815598010540052116">Deslocar-se para baixo</translation>
-<translation id="6808150112686056157">Parar multimédia</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Restaurar</translation>
-<translation id="1243314992276662751">Carregar</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restante</translation>
-<translation id="8179976553408161302">Entrar</translation>
-<translation id="945522503751344254">Enviar comentários</translation>
-<translation id="9170848237812810038">An&amp;ular</translation>
-<translation id="1285266685456062655">Há <ph name="NUMBER_FEW"/> horas</translation>
-<translation id="6918245111648057970">Permitir as seguintes notificações para cada utilizador:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
-<translation id="3994835489895548312">Faltam <ph name="NUMBER_MANY"/> minutos</translation>
-<translation id="6358975074282722691">Há <ph name="NUMBER_TWO"/> seg.</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Definições...</translation>
-<translation id="6845383723252244143">Seleccionar pasta</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
-<translation id="5583640892426849032">Retrocesso</translation>
-<translation id="5263972071113911534">Há <ph name="NUMBER_MANY"/> dias</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dias</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
-<translation id="2679312662830811292">Há <ph name="NUMBER_ONE"/> min.</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
-<translation id="9098468523912235228">Há <ph name="NUMBER_DEFAULT"/> seg.</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> seg. restantes</translation>
-<translation id="4570886800634958009">Expandir notificação</translation>
-<translation id="436869212180315161">Premir</translation>
-<translation id="4860787810836767172">Há <ph name="NUMBER_FEW"/> seg.</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
-<translation id="1858722859751911017">Faltam <ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="6040143037577758943">Fechar</translation>
-<translation id="1101671447232096497">Há <ph name="NUMBER_MANY"/> min.</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Ajuda</translation>
-<translation id="6699343763173986273">Faixa seguinte de multimédia</translation>
-<translation id="8226233771743600312">Não incomodar durante um dia</translation>
-<translation id="7457942297256758195">Limpar Tudo</translation>
-<translation id="822618367988303761">Há <ph name="NUMBER_TWO"/> dias</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dias restantes</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> horas restantes</translation>
-<translation id="8959208747503200525">Há <ph name="NUMBER_TWO"/> horas</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dias restantes</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Copiar para a área de transferência</translation>
-<translation id="8371695176452482769">Falar agora</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Não incomodar</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimizar</translation>
-<translation id="6394627529324717982">Vírgula</translation>
-<translation id="3036649622769666520">Abrir ficheiros</translation>
-<translation id="8328145009876646418">Margem esquerda</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ro.xtb b/chromium/ui/base/strings/ui_strings_ro.xtb
deleted file mode 100644
index 63a05783fb4..00000000000
--- a/chromium/ui/base/strings/ui_strings_ro.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ro">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins (Inserați)</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End (La sfârșit)</translation>
-<translation id="5341849548509163798">Cu <ph name="NUMBER_MANY"/> (de) ore în urmă</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secunde rămase</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secunde rămase</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minute rămase</translation>
-<translation id="1801827354178857021">Punct</translation>
-<translation id="1190609913194133056">Centrul pentru notificări</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minute rămase</translation>
-<translation id="5613020302032141669">Săgeata spre stânga</translation>
-<translation id="4971687151119236543">Melodia anterioară din conținutul media</translation>
-<translation id="8602707065186045623">Fișier <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918">Cu <ph name="NUMBER_ZERO"/> minute în urmă</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secunde</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ore rămase</translation>
-<translation id="8717309436826820190">Încă <ph name="NUMBER_OF_NOTIFICATIONS"/> de la <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Anulaţi</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> O</translation>
-<translation id="3660179305079774227">Săgeata în sus</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MO/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ore</translation>
-<translation id="3990502903496589789">Marginea dreaptă</translation>
-<translation id="9038489124413477075">Dosar fără nume</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minute</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> zile rămase</translation>
-<translation id="932327136139879170">Pagina de pornire</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minute rămase</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> zile rămase</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secunde rămase</translation>
-<translation id="3909791450649380159">&amp;Decupați</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minute rămase</translation>
-<translation id="688711909580084195">Pagină web fără titlu</translation>
-<translation id="3353284378027041011">Cu <ph name="NUMBER_FEW"/> zile în urmă</translation>
-<translation id="5076340679995252485">&amp;Inserați</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TO</translation>
-<translation id="364720409959344976">Selectați un dosar de încărcat</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Cu <ph name="NUMBER_TWO"/> minute în urmă</translation>
-<translation id="3234408098842461169">Săgeata în jos</translation>
-<translation id="3087734570205094154">Jos</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut rămas</translation>
-<translation id="1860796786778352021">Buton de închidere a notificării</translation>
-<translation id="6364916375976753737">Derulați spre stânga</translation>
-<translation id="2629089419211541119">Cu <ph name="NUMBER_ONE"/> oră în urmă</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minute</translation>
-<translation id="6982279413068714821">Cu <ph name="NUMBER_DEFAULT"/> (de) minute în urmă</translation>
-<translation id="6945221475159498467">Selectați</translation>
-<translation id="6620110761915583480">Salvați fișierul</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> secunde</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ore</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut rămas</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8210608804940886430">Page Down (o pagină mai jos)</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> zile</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ore rămase</translation>
-<translation id="5329858601952122676">Ș&amp;tergeți</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secunde</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KO</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543">Cu <ph name="NUMBER_MANY"/> (de) secunde în urmă</translation>
-<translation id="7781829728241885113">Ieri</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minute</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minute rămase</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MO</translation>
-<translation id="4988273303304146523">Cu <ph name="NUMBER_DEFAULT"/> zile în urmă</translation>
-<translation id="8428213095426709021">Setări</translation>
-<translation id="2497284189126895209">Toate fișierele</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minute rămase</translation>
-<translation id="5110450810124758964">Cu <ph name="NUMBER_ONE"/> zi în urmă</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> secundă</translation>
-<translation id="7814458197256864873">&amp;Copiați</translation>
-<translation id="3889424535448813030">Săgeata spre dreapta</translation>
-<translation id="4229495110203539533">Cu <ph name="NUMBER_ONE"/> secundă în urmă</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> secunde rămase</translation>
-<translation id="6829324100069873704">Reveniți la notificări</translation>
-<translation id="6528179044667508675">Nu deranja</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secunde</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minute</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> ore rămase</translation>
-<translation id="7135556860107312402">Permiteți notificările de la următoarele:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ore</translation>
-<translation id="1398853756734560583">Maximizați</translation>
-<translation id="4250229828105606438">Captură de ecran</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ore</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minute rămase</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GO</translation>
-<translation id="1901303067676059328">Select&amp;ați tot</translation>
-<translation id="2168039046890040389">O pagină mai sus</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> minute</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> zile</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minute</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8448317557906454022">Cu <ph name="NUMBER_ZERO"/> secunde în urmă</translation>
-<translation id="4927753642311223124">Nimic de văzut aici, treceți mai departe.</translation>
-<translation id="2482878487686419369">Notificări</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> zile</translation>
-<translation id="3183922693828471536">Derulați până aici</translation>
-<translation id="4552416320897244156">PgDwn (o pagină mai jos)</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ore</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KO/s</translation>
-<translation id="8394908167088220973">Redați/întrerupeți conținutul media</translation>
-<translation id="2148716181193084225">Astăzi</translation>
-<translation id="7960078400008666149">Nu deranja o oră</translation>
-<translation id="4373894838514502496">Cu <ph name="NUMBER_FEW"/> minute în urmă</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> zile</translation>
-<translation id="2190355936436201913">(gol)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ore rămase</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> secundă rămasă</translation>
-<translation id="8447116497070723931">PgUp (o pagină mai sus)</translation>
-<translation id="4588090240171750605">Derulați spre dreapta</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> oră rămasă</translation>
-<translation id="1413622004203049571">Dezactivați notificările de la <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Sus</translation>
-<translation id="8331626408530291785">Derulați în sus</translation>
-<translation id="7907591526440419938">Deschideți fișierul</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> zile rămase</translation>
-<translation id="1293699935367580298">Esc (Ieșiți)</translation>
-<translation id="2797524280730715045">Cu <ph name="NUMBER_DEFAULT"/> (de) ore în urmă</translation>
-<translation id="815598010540052116">Derulați în jos</translation>
-<translation id="6808150112686056157">Opriți conținutul media</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> minute rămase</translation>
-<translation id="3157931365184549694">Restabiliți</translation>
-<translation id="1243314992276662751">Încărcați</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> zi rămasă</translation>
-<translation id="8179976553408161302">Intrați</translation>
-<translation id="945522503751344254">Trimiteți feedback</translation>
-<translation id="9170848237812810038">&amp;Anulați</translation>
-<translation id="1285266685456062655">Cu <ph name="NUMBER_FEW"/> ore în urmă</translation>
-<translation id="6918245111648057970">Permiteți notificări de la următoarele servicii pentru fiecare utilizator:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> secundă</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> de minute rămase</translation>
-<translation id="6358975074282722691">Cu <ph name="NUMBER_TWO"/> secunde în urmă</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PO</translation>
-<translation id="2983818520079887040">Setări...</translation>
-<translation id="6845383723252244143">Selectați dosarul</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> secunde</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secunde</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">Cu <ph name="NUMBER_MANY"/> (de) zile în urmă</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> zile</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> oră</translation>
-<translation id="2679312662830811292">Cu <ph name="NUMBER_ONE"/> minut în urmă</translation>
-<translation id="8788572795284305350">Cu <ph name="NUMBER_ZERO"/> ore în urmă</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GO/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> zi</translation>
-<translation id="9098468523912235228">Cu <ph name="NUMBER_DEFAULT"/> (de) secunde în urmă</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secunde rămase</translation>
-<translation id="4570886800634958009">Buton de extindere a notificării</translation>
-<translation id="436869212180315161">Apăsați</translation>
-<translation id="4860787810836767172">Cu <ph name="NUMBER_FEW"/> secunde în urmă</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TO/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minute</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minute rămase</translation>
-<translation id="6040143037577758943">Închideți</translation>
-<translation id="1101671447232096497">Cu <ph name="NUMBER_MANY"/> (de) minute în urmă</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> O/s</translation>
-<translation id="7649070708921625228">Ajutor</translation>
-<translation id="6699343763173986273">Melodia următoare din conținutul media</translation>
-<translation id="8226233771743600312">Nu deranja o zi</translation>
-<translation id="7457942297256758195">Ștergeți-le pe toate</translation>
-<translation id="822618367988303761">Cu <ph name="NUMBER_TWO"/> zile în urmă</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minute</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> zile rămase</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ore rămase</translation>
-<translation id="8959208747503200525">Cu <ph name="NUMBER_TWO"/> ore în urmă</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secunde</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secunde</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> zile rămase</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PO/s</translation>
-<translation id="2743387203779672305">Copiați în clipboard</translation>
-<translation id="8371695176452482769">Vorbiți acum</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Nu deranja</translation>
-<translation id="6978839998405419496">Cu <ph name="NUMBER_ZERO"/> zile în urmă</translation>
-<translation id="5941711191222866238">Minimizați</translation>
-<translation id="6394627529324717982">Virgulă</translation>
-<translation id="3036649622769666520">Deschideți fișierele</translation>
-<translation id="8328145009876646418">Marginea stângă</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> secunde</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ru.xtb b/chromium/ui/base/strings/ui_strings_ru.xtb
deleted file mode 100644
index 43e936017ca..00000000000
--- a/chromium/ui/base/strings/ui_strings_ru.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ru">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">Завершить</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> сек.</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> мин.</translation>
-<translation id="1801827354178857021">Точка</translation>
-<translation id="1190609913194133056">Центр оповещений</translation>
-<translation id="7470933019269157899">Осталось <ph name="NUMBER_DEFAULT"/> минут</translation>
-<translation id="5613020302032141669">Стрелка влево</translation>
-<translation id="4971687151119236543">Предыдущий трек</translation>
-<translation id="8602707065186045623">Файл <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек.</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ч.</translation>
-<translation id="8717309436826820190">Ещё <ph name="NUMBER_OF_NOTIFICATIONS"/> (<ph name="SOURCE_OF_NOTIFICATIONS"/>)</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Отмена</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> Б</translation>
-<translation id="3660179305079774227">Стрелка вверх</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> МБ/с</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ч.</translation>
-<translation id="3990502903496589789">Правый край</translation>
-<translation id="9038489124413477075">Без названия</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин.</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> дн.</translation>
-<translation id="932327136139879170">На главную</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> мин.</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> дн.</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> сек.</translation>
-<translation id="3909791450649380159">Выре&amp;зать</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Страница без названия</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> дн. назад</translation>
-<translation id="5076340679995252485">&amp;Вставить</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> ТБ</translation>
-<translation id="364720409959344976">Выберите папку для загрузки</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Стрелка вниз</translation>
-<translation id="3087734570205094154">Низ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> мин.</translation>
-<translation id="1860796786778352021">Закрыть оповещение</translation>
-<translation id="6364916375976753737">Прокрутка влево</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ч. назад</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> мин.</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> мин. назад</translation>
-<translation id="6945221475159498467">Выбрать</translation>
-<translation id="6620110761915583480">Сохранить файл</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> сек.</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Осталась <ph name="NUMBER_ONE"/> минута</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин.</translation>
-<translation id="8210608804940886430">Прокрутка вниз</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> дн.</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ч.</translation>
-<translation id="5329858601952122676">&amp;Удалить</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> КБ</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> мин.</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Вчера</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> мин.</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="6659594942844771486">Вкладка</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> МБ</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> дн. назад</translation>
-<translation id="8428213095426709021">Настройки</translation>
-<translation id="2497284189126895209">Все файлы</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> дн. назад</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="7814458197256864873">&amp;Копировать</translation>
-<translation id="3889424535448813030">Стрелка вправо</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> с. назад</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="6829324100069873704">Назад к оповещениям</translation>
-<translation id="6528179044667508675">Не беспокоить</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин.</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Разрешить оповещения от:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ч.</translation>
-<translation id="1398853756734560583">Развернуть</translation>
-<translation id="4250229828105606438">Скриншот</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ч.</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> мин.</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> ГБ</translation>
-<translation id="1901303067676059328">Выделить &amp;все</translation>
-<translation id="2168039046890040389">Вверх</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> дн.</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин.</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> мин.</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Оповещений нет.</translation>
-<translation id="2482878487686419369">Оповещения</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Прокрутить до этого места</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ч.</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> КБ/с</translation>
-<translation id="8394908167088220973">Воспроизведение/пауза</translation>
-<translation id="2148716181193084225">Сегодня</translation>
-<translation id="7960078400008666149">Не беспокоить (1 час)</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> мин. назад</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дня</translation>
-<translation id="2190355936436201913">(пусто)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ч.</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Прокрутка вправо</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ч.</translation>
-<translation id="1413622004203049571">Отключить оповещения от <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Наверх</translation>
-<translation id="8331626408530291785">Прокрутка вверх</translation>
-<translation id="7907591526440419938">Открытие файла</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ч. назад</translation>
-<translation id="815598010540052116">Прокрутка вниз</translation>
-<translation id="6808150112686056157">Остановить</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Восстановить</translation>
-<translation id="1243314992276662751">Загрузить</translation>
-<translation id="50030952220075532">Остался <ph name="NUMBER_ONE"/> день</translation>
-<translation id="8179976553408161302">Войти</translation>
-<translation id="945522503751344254">Отправить отзыв</translation>
-<translation id="9170848237812810038">&amp;Отменить</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ч. назад</translation>
-<translation id="6918245111648057970">Разрешить оповещения для каждого пользователя:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> ПБ</translation>
-<translation id="2983818520079887040">Настройки...</translation>
-<translation id="6845383723252244143">Выбор папки</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="5583640892426849032">Клавиша возврата (Backspace)</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> дн.</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> час</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> мин. назад</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> ГБ/с</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> день</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> с. назад</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> сек.</translation>
-<translation id="4570886800634958009">Раскрыть оповещение</translation>
-<translation id="436869212180315161">Нажать</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> с. назад</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> ТБ/с</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> мин.</translation>
-<translation id="1858722859751911017">Осталось <ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="6040143037577758943">Закрыть</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> Б/с</translation>
-<translation id="7649070708921625228">Справка</translation>
-<translation id="6699343763173986273">Следующий трек</translation>
-<translation id="8226233771743600312">Не беспокоить (1 день)</translation>
-<translation id="7457942297256758195">Очистить все</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> дн.</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ч.</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> сек.</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> дн.</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> ПБ/с</translation>
-<translation id="2743387203779672305">Скопировать в буфер</translation>
-<translation id="8371695176452482769">Говорите</translation>
-<translation id="6965382102122355670">ОК</translation>
-<translation id="7850320739366109486">Не беспокоить</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Свернуть</translation>
-<translation id="6394627529324717982">Запятая</translation>
-<translation id="3036649622769666520">Открытие файлов</translation>
-<translation id="8328145009876646418">Левый край</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> сек.</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_sk.xtb b/chromium/ui/base/strings/ui_strings_sk.xtb
deleted file mode 100644
index db7d0f2dc16..00000000000
--- a/chromium/ui/base/strings/ui_strings_sk.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="sk">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942">Počet zvyšných sekúnd: <ph name="NUMBER_FEW"/></translation>
-<translation id="9213479837033539041">Počet zvyšných sekúnd: <ph name="NUMBER_MANY"/></translation>
-<translation id="1209866192426315618">Počet zvyšných minút: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="1801827354178857021">Bodka</translation>
-<translation id="1190609913194133056">Centrum upozornení</translation>
-<translation id="7470933019269157899">Zostáva <ph name="NUMBER_DEFAULT"/> minút</translation>
-<translation id="5613020302032141669">Šípka doľava</translation>
-<translation id="4971687151119236543">Média – predchádzajúca stopa</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Súbor (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252">Počet sekúnd: <ph name="NUMBER_TWO"/></translation>
-<translation id="7511635910912978956">Počet zvyšných hodín: <ph name="NUMBER_FEW"/></translation>
-<translation id="8717309436826820190">Počet ďalších upozornení zo služby <ph name="SOURCE_OF_NOTIFICATIONS"/>: <ph name="NUMBER_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Zrušiť</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Šípka nahor</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928">Počet hodín: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3990502903496589789">Pravý okraj</translation>
-<translation id="9038489124413477075">Priečinok bez názvu</translation>
-<translation id="8507996248087185956">Počet minút: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3520476450377425184">Počet zvyšných dní: <ph name="NUMBER_MANY"/></translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">Počet zvyšných minút: <ph name="NUMBER_MANY"/></translation>
-<translation id="8666066831007952346">Počet zvyšných dní: <ph name="NUMBER_TWO"/></translation>
-<translation id="6390842777729054533">Počet zvyšných sekúnd: <ph name="NUMBER_ZERO"/></translation>
-<translation id="3909791450649380159">&amp;Vystrihnúť</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Nepomenovaná webová stránka</translation>
-<translation id="3353284378027041011">Pred <ph name="NUMBER_FEW"/> dňami</translation>
-<translation id="5076340679995252485">&amp;Vložiť</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Výber priečinka na nahranie</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Šípka nadol</translation>
-<translation id="3087734570205094154">Spodok</translation>
-<translation id="5935630983280450497">Počet zvyšných minút: <ph name="NUMBER_ONE"/></translation>
-<translation id="1860796786778352021">Zavrieť upozornenie</translation>
-<translation id="6364916375976753737">Rolovať doľava</translation>
-<translation id="2629089419211541119">Pred <ph name="NUMBER_ONE"/> hod</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="6982279413068714821">Pred <ph name="NUMBER_DEFAULT"/> minútami</translation>
-<translation id="6945221475159498467">Vybrať</translation>
-<translation id="6620110761915583480">Uložiť súbor</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekúnd</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Zostáva <ph name="NUMBER_ONE"/> minúta</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minúta</translation>
-<translation id="8210608804940886430">Stránkovať nadol</translation>
-<translation id="1572103024875503863">Počet dní: <ph name="NUMBER_MANY"/></translation>
-<translation id="7163503212501929773">Počet zvyšných hodín: <ph name="NUMBER_MANY"/></translation>
-<translation id="5329858601952122676">&amp;Odstrániť</translation>
-<translation id="8088823334188264070">Počet sekúnd: <ph name="NUMBER_MANY"/></translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Včera</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minúty</translation>
-<translation id="50960180632766478">Počet zvyšných minút: <ph name="NUMBER_FEW"/></translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Pred <ph name="NUMBER_DEFAULT"/> dňami</translation>
-<translation id="8428213095426709021">Nastavenia</translation>
-<translation id="2497284189126895209">Všetky súbory</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964">Pred <ph name="NUMBER_ONE"/> dňom</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="7814458197256864873">&amp;Kopírovať</translation>
-<translation id="3889424535448813030">Šípka doprava</translation>
-<translation id="4229495110203539533">Pred <ph name="NUMBER_ONE"/> s</translation>
-<translation id="2544782972264605588">Počet zvyšných sekúnd: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6829324100069873704">Prejsť späť na upozornenia</translation>
-<translation id="6528179044667508675">Nerušiť</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="290555789621781773">Počet minút: <ph name="NUMBER_TWO"/></translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Povoliť prijímanie upozornení od:</translation>
-<translation id="8112886015144590373">Počet hodín: <ph name="NUMBER_FEW"/></translation>
-<translation id="1398853756734560583">Maximalizovať</translation>
-<translation id="4250229828105606438">Snímka obrazovky</translation>
-<translation id="6690744523875189208">Počet hodín: <ph name="NUMBER_TWO"/></translation>
-<translation id="5260878308685146029">Počet zvyšných minút: <ph name="NUMBER_TWO"/></translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Vybrať &amp;všetko</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581">Počet dní: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734">Počet minút: <ph name="NUMBER_MANY"/></translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minúta</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Tu sa nič nenachádza, pokračujte ďalej.</translation>
-<translation id="2482878487686419369">Upozornenia</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Rolovať na toto miesto</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401">Počet hodín: <ph name="NUMBER_MANY"/></translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
-<translation id="8394908167088220973">Média – prehrať / pozastaviť</translation>
-<translation id="2148716181193084225">Dnes</translation>
-<translation id="7960078400008666149">Nerušiť jednu hodinu</translation>
-<translation id="4373894838514502496">Pred <ph name="NUMBER_FEW"/> min</translation>
-<translation id="4115153316875436289">Počet dní: <ph name="NUMBER_TWO"/></translation>
-<translation id="2190355936436201913">(prázdne)</translation>
-<translation id="1164369517022005061">Počet zvyšných hodín: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="152482086482215392">Zostáva <ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Rolovať doprava</translation>
-<translation id="7414887922320653780">Zostáva <ph name="NUMBER_ONE"/> hodina</translation>
-<translation id="1413622004203049571">Zakázať upozornenia od <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Vrch</translation>
-<translation id="8331626408530291785">Rolovať nahor</translation>
-<translation id="7907591526440419938">Otvoriť súbor</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Pred <ph name="NUMBER_DEFAULT"/> hodinami</translation>
-<translation id="815598010540052116">Rolovať nadol</translation>
-<translation id="6808150112686056157">Médiá – zastaviť</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Obnoviť</translation>
-<translation id="1243314992276662751">Nahrať</translation>
-<translation id="50030952220075532">Zostáva <ph name="NUMBER_ONE"/> deň</translation>
-<translation id="8179976553408161302">Začať</translation>
-<translation id="945522503751344254">Poslať pripomienky</translation>
-<translation id="9170848237812810038">&amp;Naspäť</translation>
-<translation id="1285266685456062655">Pred <ph name="NUMBER_FEW"/> hodinami</translation>
-<translation id="6918245111648057970">Povoliť upozornenia na nasledujúce položky pre každého používateľa:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Nastavenia...</translation>
-<translation id="6845383723252244143">Vybrať priečinok</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundy</translation>
-<translation id="1095623615273566396">Počet sekúnd: <ph name="NUMBER_FEW"/></translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920">Počet dní: <ph name="NUMBER_FEW"/></translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hodina</translation>
-<translation id="2679312662830811292">Pred <ph name="NUMBER_ONE"/> min</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> deň</translation>
-<translation id="9098468523912235228">Pred <ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="494645311413743213">Počet zvyšných sekúnd: <ph name="NUMBER_TWO"/></translation>
-<translation id="4570886800634958009">Rozbaliť upozornenie</translation>
-<translation id="436869212180315161">Stlačiť</translation>
-<translation id="4860787810836767172">Pred <ph name="NUMBER_FEW"/> s</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minút</translation>
-<translation id="1858722859751911017">Zostávajú <ph name="NUMBER_FEW"/> minúty</translation>
-<translation id="6040143037577758943">Zatvoriť</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Pomocník</translation>
-<translation id="6699343763173986273">Média – ďalšia stopa</translation>
-<translation id="8226233771743600312">Nerušiť jeden deň</translation>
-<translation id="7457942297256758195">Vymazať všetky</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565">Počet minút: <ph name="NUMBER_FEW"/></translation>
-<translation id="1963692530539281474">Počet zvyšných dní: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minúty</translation>
-<translation id="5906719743126878045">Počet zvyšných hodín: <ph name="NUMBER_TWO"/></translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940">Počet sekúnd: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="4197700912384709145">Počet sekúnd: <ph name="NUMBER_ZERO"/></translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382">Počet zvyšných dní: <ph name="NUMBER_FEW"/></translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopírovať do schránky</translation>
-<translation id="8371695176452482769">Začnite hovoriť</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Nerušiť</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimalizovať</translation>
-<translation id="6394627529324717982">Čiarka</translation>
-<translation id="3036649622769666520">Otvoriť súbory</translation>
-<translation id="8328145009876646418">Ľavý okraj</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekundy</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_sl.xtb b/chromium/ui/base/strings/ui_strings_sl.xtb
deleted file mode 100644
index 8862aaed9c6..00000000000
--- a/chromium/ui/base/strings/ui_strings_sl.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="sl">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798">Pred <ph name="NUMBER_MANY"/> h</translation>
-<translation id="6310545596129886942">še <ph name="NUMBER_FEW"/> sek</translation>
-<translation id="9213479837033539041">še <ph name="NUMBER_MANY"/> sekund</translation>
-<translation id="1209866192426315618">še <ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="1801827354178857021">Pika</translation>
-<translation id="1190609913194133056">Središče za obvestila</translation>
-<translation id="7470933019269157899">še <ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="5613020302032141669">Puščica levo</translation>
-<translation id="4971687151119236543">Prejšnja skladba</translation>
-<translation id="8602707065186045623">Datoteka <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek</translation>
-<translation id="7511635910912978956">še <ph name="NUMBER_FEW"/> h</translation>
-<translation id="8717309436826820190">Še <ph name="NUMBER_OF_NOTIFICATIONS"/> iz vira <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Prekliči</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Puščica gor</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> h</translation>
-<translation id="3990502903496589789">Desni rob</translation>
-<translation id="9038489124413477075">Neimenovana mapa</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="3520476450377425184">še <ph name="NUMBER_MANY"/> dni</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">še <ph name="NUMBER_MANY"/> minut</translation>
-<translation id="8666066831007952346">še <ph name="NUMBER_TWO"/> dni</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">Izrež&amp;i</translation>
-<translation id="2560788951337264832">še <ph name="NUMBER_ZERO"/> min</translation>
-<translation id="688711909580084195">Spletna stran brez naslova</translation>
-<translation id="3353284378027041011">Pred <ph name="NUMBER_FEW"/> dnevi</translation>
-<translation id="5076340679995252485">&amp;Prilepi</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Izberite mapo, ki jo želite prenesti</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Pred <ph name="NUMBER_TWO"/> min</translation>
-<translation id="3234408098842461169">Puščica dol</translation>
-<translation id="3087734570205094154">Na dno</translation>
-<translation id="5935630983280450497">še <ph name="NUMBER_ONE"/> min</translation>
-<translation id="1860796786778352021">Zapri obvestilo</translation>
-<translation id="6364916375976753737">Pomik levo</translation>
-<translation id="2629089419211541119">Pred <ph name="NUMBER_ONE"/> h</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="6982279413068714821">Pred <ph name="NUMBER_DEFAULT"/> min</translation>
-<translation id="6945221475159498467">Izberi</translation>
-<translation id="6620110761915583480">Shrani datoteko</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">še <ph name="NUMBER_ONE"/> min</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">Stran dol</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
-<translation id="7163503212501929773">še <ph name="NUMBER_MANY"/> ur</translation>
-<translation id="5329858601952122676">&amp;Izbriši</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543">Pred <ph name="NUMBER_MANY"/> s</translation>
-<translation id="7781829728241885113">Včeraj</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuti</translation>
-<translation id="50960180632766478">še <ph name="NUMBER_FEW"/> min</translation>
-<translation id="6659594942844771486">Tabulator</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Pred <ph name="NUMBER_DEFAULT"/> dnevi</translation>
-<translation id="8428213095426709021">Nastavitve</translation>
-<translation id="2497284189126895209">Vse datoteke</translation>
-<translation id="7487278341251176613">še <ph name="NUMBER_TWO"/> min</translation>
-<translation id="5110450810124758964">Pred <ph name="NUMBER_ONE"/> dnevom</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek</translation>
-<translation id="7814458197256864873">&amp;Kopiraj</translation>
-<translation id="3889424535448813030">Puščica desno</translation>
-<translation id="4229495110203539533">Pred <ph name="NUMBER_ONE"/> s</translation>
-<translation id="2544782972264605588">še <ph name="NUMBER_DEFAULT"/> sek</translation>
-<translation id="6829324100069873704">Nazaj na obvestila</translation>
-<translation id="6528179044667508675">Ne moti</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Omogočanje obvestil teh aplikacij:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ur</translation>
-<translation id="1398853756734560583">Povečaj</translation>
-<translation id="4250229828105606438">Posnetek zaslona</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> uri</translation>
-<translation id="5260878308685146029">še <ph name="NUMBER_TWO"/> min</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Izberi &amp;vse</translation>
-<translation id="2168039046890040389">Stran gor</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dni</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
-<translation id="8448317557906454022">Pred <ph name="NUMBER_ZERO"/> s</translation>
-<translation id="4927753642311223124">Tu ni ničesar, pomaknite se naprej.</translation>
-<translation id="2482878487686419369">Obvestila</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Pomik do sem</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ur</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Ustavitev/začasna ustavitev</translation>
-<translation id="2148716181193084225">Danes</translation>
-<translation id="7960078400008666149">Ne moti eno uro</translation>
-<translation id="4373894838514502496">Pred <ph name="NUMBER_FEW"/> min</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dni</translation>
-<translation id="2190355936436201913">(prazno)</translation>
-<translation id="1164369517022005061">še <ph name="NUMBER_DEFAULT"/> h</translation>
-<translation id="152482086482215392">še <ph name="NUMBER_ONE"/> sek</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Pomik desno</translation>
-<translation id="7414887922320653780">še <ph name="NUMBER_ONE"/> ura</translation>
-<translation id="1413622004203049571">Izklop obvestil za <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Na vrh</translation>
-<translation id="8331626408530291785">Pomik gor</translation>
-<translation id="7907591526440419938">Odpri datoteko</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Pred <ph name="NUMBER_DEFAULT"/> h</translation>
-<translation id="815598010540052116">Pomik dol</translation>
-<translation id="6808150112686056157">Ustavitev</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Obnovi</translation>
-<translation id="1243314992276662751">Prenesi</translation>
-<translation id="50030952220075532">še <ph name="NUMBER_ONE"/> dan</translation>
-<translation id="8179976553408161302">Potrdi</translation>
-<translation id="945522503751344254">Pošlji povratne informacije</translation>
-<translation id="9170848237812810038">&amp;Razveljavi</translation>
-<translation id="1285266685456062655">Pred <ph name="NUMBER_FEW"/> h</translation>
-<translation id="6918245111648057970">Za vsakega uporabnika dovoli obvestila naslednjih storitev:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
-<translation id="3994835489895548312">še <ph name="NUMBER_MANY"/> min</translation>
-<translation id="6358975074282722691">Pred <ph name="NUMBER_TWO"/> s</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Nastavitve ...</translation>
-<translation id="6845383723252244143">Izberite mapo</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunde</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek</translation>
-<translation id="5583640892426849032">Vračalka</translation>
-<translation id="5263972071113911534">Pred <ph name="NUMBER_MANY"/> dnevi</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dni</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> h</translation>
-<translation id="2679312662830811292">Pred <ph name="NUMBER_ONE"/> min</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dan</translation>
-<translation id="9098468523912235228">Pred <ph name="NUMBER_DEFAULT"/> s</translation>
-<translation id="494645311413743213">še <ph name="NUMBER_TWO"/> sek</translation>
-<translation id="4570886800634958009">Razširi obvestilo</translation>
-<translation id="436869212180315161">Pritisnite</translation>
-<translation id="4860787810836767172">Pred <ph name="NUMBER_FEW"/> s</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">še <ph name="NUMBER_FEW"/> min</translation>
-<translation id="6040143037577758943">Zapri</translation>
-<translation id="1101671447232096497">Pred <ph name="NUMBER_MANY"/> min</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Pomoč</translation>
-<translation id="6699343763173986273">Naslednja skladba</translation>
-<translation id="8226233771743600312">Ne moti en dan</translation>
-<translation id="7457942297256758195">Izbriši vse</translation>
-<translation id="822618367988303761">Pred <ph name="NUMBER_TWO"/> dnevoma</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
-<translation id="1963692530539281474">še <ph name="NUMBER_DEFAULT"/> dni</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
-<translation id="5906719743126878045">še <ph name="NUMBER_TWO"/> uri</translation>
-<translation id="8959208747503200525">Pred <ph name="NUMBER_TWO"/> h</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekund</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382">še <ph name="NUMBER_FEW"/> dni</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Kopiraj v odložišče</translation>
-<translation id="8371695176452482769">Začnite govoriti</translation>
-<translation id="6965382102122355670">V redu</translation>
-<translation id="7850320739366109486">Ne moti</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Pomanjšaj</translation>
-<translation id="6394627529324717982">Vejica</translation>
-<translation id="3036649622769666520">Odpri datoteke</translation>
-<translation id="8328145009876646418">Levi rob</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekundi</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_sr.xtb b/chromium/ui/base/strings/ui_strings_sr.xtb
deleted file mode 100644
index 681c50632f8..00000000000
--- a/chromium/ui/base/strings/ui_strings_sr.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="sr">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942">Преостало <ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="9213479837033539041">Преостало <ph name="NUMBER_MANY"/> сек.</translation>
-<translation id="1209866192426315618">Преостало <ph name="NUMBER_DEFAULT"/> мин.</translation>
-<translation id="1801827354178857021">Тачка</translation>
-<translation id="1190609913194133056">Центар за обавештења</translation>
-<translation id="7470933019269157899">Преостало је <ph name="NUMBER_DEFAULT"/> минута</translation>
-<translation id="5613020302032141669">Стрелица налево</translation>
-<translation id="4971687151119236543">Претходна песма медија</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> датотека (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек.</translation>
-<translation id="7511635910912978956">Преостало сати: <ph name="NUMBER_FEW"/></translation>
-<translation id="8717309436826820190">Још <ph name="NUMBER_OF_NOTIFICATIONS"/> од <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Откажи</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Стрелица нагоре</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928">Сати: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3990502903496589789">Десна ивица</translation>
-<translation id="9038489124413477075">Неименовани директоријум</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин.</translation>
-<translation id="3520476450377425184">Преостало <ph name="NUMBER_MANY"/> дана</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">Преостало <ph name="NUMBER_MANY"/> мин.</translation>
-<translation id="8666066831007952346">Преостало <ph name="NUMBER_TWO"/> дана</translation>
-<translation id="6390842777729054533">Преостало <ph name="NUMBER_ZERO"/> сек.</translation>
-<translation id="3909791450649380159">Ис&amp;еци</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Веб-страница без наслова</translation>
-<translation id="3353284378027041011">Пре <ph name="NUMBER_FEW"/> дана</translation>
-<translation id="5076340679995252485">&amp;Налепи</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Избор директоријума за отпремање</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">Пре <ph name="NUMBER_TWO"/> минута</translation>
-<translation id="3234408098842461169">Стрелица надоле</translation>
-<translation id="3087734570205094154">Дно</translation>
-<translation id="5935630983280450497">Преостао <ph name="NUMBER_ONE"/> мин.</translation>
-<translation id="1860796786778352021">Затвори обавештење</translation>
-<translation id="6364916375976753737">Помери налево</translation>
-<translation id="2629089419211541119">Пре <ph name="NUMBER_ONE"/> сат</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> мин</translation>
-<translation id="6982279413068714821">Пре <ph name="NUMBER_DEFAULT"/> минута</translation>
-<translation id="6945221475159498467">Изабери</translation>
-<translation id="6620110761915583480">Чување датотеке</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> секунди</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Преостао је <ph name="NUMBER_ONE"/> минут</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин.</translation>
-<translation id="8210608804940886430">Страница надоле</translation>
-<translation id="1572103024875503863">Дана: <ph name="NUMBER_MANY"/></translation>
-<translation id="7163503212501929773">Преостало сати: <ph name="NUMBER_MANY"/></translation>
-<translation id="5329858601952122676">&amp;Избриши</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек.</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> минута</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Јуче</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> минута</translation>
-<translation id="50960180632766478">Преостало <ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">Пре <ph name="NUMBER_DEFAULT"/> дана</translation>
-<translation id="8428213095426709021">Подешавања</translation>
-<translation id="2497284189126895209">Све датотеке</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964">Пре <ph name="NUMBER_ONE"/> дан</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="7814458197256864873">&amp;Копирај</translation>
-<translation id="3889424535448813030">Стрелица надесно</translation>
-<translation id="4229495110203539533">Пре <ph name="NUMBER_ONE"/> секунду</translation>
-<translation id="2544782972264605588">Преостало <ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="6829324100069873704">Вратите се на обавештења</translation>
-<translation id="6528179044667508675">Не узнемиравај</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> сек</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин.</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Дозволи обавештења из следећих извора:</translation>
-<translation id="8112886015144590373">Сати: <ph name="NUMBER_FEW"/></translation>
-<translation id="1398853756734560583">Увећај</translation>
-<translation id="4250229828105606438">Снимак екрана</translation>
-<translation id="6690744523875189208">Сати: <ph name="NUMBER_TWO"/></translation>
-<translation id="5260878308685146029">Преостало <ph name="NUMBER_TWO"/> мин.</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Изабери &amp;све</translation>
-<translation id="2168039046890040389">Страница нагоре</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581">Дана: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин.</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> минут</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Нема шта да се види овде. Наставите даље.</translation>
-<translation id="2482878487686419369">Обавештења</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Помери се овде</translation>
-<translation id="4552416320897244156">Page Down</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401">Сати: <ph name="NUMBER_MANY"/></translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Пуштање/паузирање медија</translation>
-<translation id="2148716181193084225">Данас</translation>
-<translation id="7960078400008666149">Не узнемиравај у периоду од сат времена</translation>
-<translation id="4373894838514502496">Пре <ph name="NUMBER_FEW"/> минута</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дана</translation>
-<translation id="2190355936436201913">(празно)</translation>
-<translation id="1164369517022005061">Преостало сати: <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="152482086482215392">Преостала <ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="8447116497070723931">Page Up</translation>
-<translation id="4588090240171750605">Помери надесно</translation>
-<translation id="7414887922320653780">Преостао <ph name="NUMBER_ONE"/> сат</translation>
-<translation id="1413622004203049571">Онемогући обавештења од <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Врх</translation>
-<translation id="8331626408530291785">Помери нагоре</translation>
-<translation id="7907591526440419938">Отварање датотеке</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Пре <ph name="NUMBER_DEFAULT"/> сата</translation>
-<translation id="815598010540052116">Помери надоле</translation>
-<translation id="6808150112686056157">Заустављање медија</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Поново отвори</translation>
-<translation id="1243314992276662751">Отпреми</translation>
-<translation id="50030952220075532">Преостао <ph name="NUMBER_ONE"/> дан</translation>
-<translation id="8179976553408161302">Унеси</translation>
-<translation id="945522503751344254">Пошаљи повратне информације</translation>
-<translation id="9170848237812810038">&amp;Опозови</translation>
-<translation id="1285266685456062655">Пре <ph name="NUMBER_FEW"/> сата</translation>
-<translation id="6918245111648057970">Омогући обавештења следећих производа за сваког корисника:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691">Пре <ph name="NUMBER_TWO"/> секунде</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Подешавања...</translation>
-<translation id="6845383723252244143">Избор директоријума</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунде</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920">Дана: <ph name="NUMBER_FEW"/></translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> сат</translation>
-<translation id="2679312662830811292">Пре <ph name="NUMBER_ONE"/> минут</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> дан</translation>
-<translation id="9098468523912235228">Пре <ph name="NUMBER_DEFAULT"/> секунди</translation>
-<translation id="494645311413743213">Преостало <ph name="NUMBER_TWO"/> сек.</translation>
-<translation id="4570886800634958009">Прошири обавештење</translation>
-<translation id="436869212180315161">Притисните</translation>
-<translation id="4860787810836767172">Пре <ph name="NUMBER_FEW"/> секунде</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> минута</translation>
-<translation id="1858722859751911017">Преостала су <ph name="NUMBER_FEW"/> минута</translation>
-<translation id="6040143037577758943">Затвори</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Помоћ</translation>
-<translation id="6699343763173986273">Следећа песма медија</translation>
-<translation id="8226233771743600312">Не узнемиравај у периоду од једног дана</translation>
-<translation id="7457942297256758195">Обриши све</translation>
-<translation id="822618367988303761">Пре <ph name="NUMBER_TWO"/> дана</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин.</translation>
-<translation id="1963692530539281474">Преостало <ph name="NUMBER_DEFAULT"/> дана</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> минута</translation>
-<translation id="5906719743126878045">Преостало сати: <ph name="NUMBER_TWO"/></translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек.</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> секунди</translation>
-<translation id="3759876923365568382">Преостало <ph name="NUMBER_FEW"/> дана</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Копирај у меморију</translation>
-<translation id="8371695176452482769">Почните да говорите</translation>
-<translation id="6965382102122355670">Потврди</translation>
-<translation id="7850320739366109486">Не узнемиравај</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Смањи</translation>
-<translation id="6394627529324717982">Зарез</translation>
-<translation id="3036649622769666520">Отварање датотека</translation>
-<translation id="8328145009876646418">Лева ивица</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> секунде</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_sv.xtb b/chromium/ui/base/strings/ui_strings_sv.xtb
deleted file mode 100644
index f8885762c30..00000000000
--- a/chromium/ui/base/strings/ui_strings_sv.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="sv">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekunder kvar</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekunder kvar</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuter kvar</translation>
-<translation id="1801827354178857021">Punkt</translation>
-<translation id="1190609913194133056">Meddelandecenter</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuter kvar</translation>
-<translation id="5613020302032141669">Vänsterpil</translation>
-<translation id="4971687151119236543">Föregående spår</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekunder</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timmar kvar</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> till från <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Avbryt</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Uppil</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sek</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timmar</translation>
-<translation id="3990502903496589789">Högerkant</translation>
-<translation id="9038489124413477075">Namnlös mapp</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuter</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dagar kvar</translation>
-<translation id="932327136139879170">Startsida</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuter kvar</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dagar kvar</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekunder kvar</translation>
-<translation id="3909791450649380159">&amp;Klipp ut</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minuter kvar</translation>
-<translation id="688711909580084195">Namnlös webbsida</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">K&amp;listra in</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Välj en mapp för överföring</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Nedpil</translation>
-<translation id="3087734570205094154">Nederst</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut kvar</translation>
-<translation id="1860796786778352021">Meddelande om stängning</translation>
-<translation id="6364916375976753737">Rulla åt vänster</translation>
-<translation id="2629089419211541119">För <ph name="NUMBER_ONE"/> timme sedan</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuter</translation>
-<translation id="6982279413068714821">För <ph name="NUMBER_DEFAULT"/> minuter sedan</translation>
-<translation id="6945221475159498467">Välj</translation>
-<translation id="6620110761915583480">Spara fil</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut kvar</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dagar</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timmar kvar</translation>
-<translation id="5329858601952122676">&amp;Ta bort</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekunder</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minuter</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Igår</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuter</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuter kvar</translation>
-<translation id="6659594942844771486">Flik</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523">För <ph name="NUMBER_DEFAULT"/> dagar sedan</translation>
-<translation id="8428213095426709021">Inställningar</translation>
-<translation id="2497284189126895209">Alla filer</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minuter kvar</translation>
-<translation id="5110450810124758964">För <ph name="NUMBER_ONE"/> dag sedan</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="7814458197256864873">&amp;Kopiera</translation>
-<translation id="3889424535448813030">Högerpil</translation>
-<translation id="4229495110203539533">För <ph name="NUMBER_ONE"/> sekund sedan</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekunder kvar</translation>
-<translation id="6829324100069873704">Gå tillbaka till meddelanden</translation>
-<translation id="6528179044667508675">Stör inte</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuter</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Tillåt meddelanden från följande:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timmar</translation>
-<translation id="1398853756734560583">Maximera</translation>
-<translation id="4250229828105606438">Skärmdump</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timmar</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuter kvar</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Välj &amp;alla</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dagar</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuter</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Här finns inget att se, fortsätt.</translation>
-<translation id="2482878487686419369">Aviseringar</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Rulla hit</translation>
-<translation id="4552416320897244156">Page Down</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timmar</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/sek</translation>
-<translation id="8394908167088220973">Spela upp/Pausa</translation>
-<translation id="2148716181193084225">Idag</translation>
-<translation id="7960078400008666149">Stör inte i en timme</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dagar</translation>
-<translation id="2190355936436201913">(tom)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timmar kvar</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekund kvar</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Rulla åt höger</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> timmar kvar</translation>
-<translation id="1413622004203049571">Inaktivera aviseringar från <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Överst</translation>
-<translation id="8331626408530291785">Rulla uppåt</translation>
-<translation id="7907591526440419938">Öppna fil</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">För <ph name="NUMBER_DEFAULT"/> timmar sedan</translation>
-<translation id="815598010540052116">Rulla nedåt</translation>
-<translation id="6808150112686056157">Stoppa</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Återställ</translation>
-<translation id="1243314992276662751">Överför</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag kvar</translation>
-<translation id="8179976553408161302">Start</translation>
-<translation id="945522503751344254">Skicka synpunkter</translation>
-<translation id="9170848237812810038">&amp;Ångra</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Tillåt meddelanden från följande personer för alla användare:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minuter kvar</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Inställningar...</translation>
-<translation id="6845383723252244143">Välj mapp</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekunder</translation>
-<translation id="5583640892426849032">Backsteg</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dagar</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> timme</translation>
-<translation id="2679312662830811292">För <ph name="NUMBER_ONE"/> minut sedan</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sek</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
-<translation id="9098468523912235228">För <ph name="NUMBER_DEFAULT"/> sekunder sedan</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekunder kvar</translation>
-<translation id="4570886800634958009">Meddelande om utökning</translation>
-<translation id="436869212180315161">Pressen</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sek</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuter</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minuter kvar</translation>
-<translation id="6040143037577758943">Stäng</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sek</translation>
-<translation id="7649070708921625228">Hjälp</translation>
-<translation id="6699343763173986273">Nästa spår</translation>
-<translation id="8226233771743600312">Stör inte i en dag</translation>
-<translation id="7457942297256758195">Ta bort alla</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuter</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dagar kvar</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuter</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timmar kvar</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekunder</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dagar kvar</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sek</translation>
-<translation id="2743387203779672305">Kopiera till Urklipp</translation>
-<translation id="8371695176452482769">Prata nu</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Stör inte</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Minimera</translation>
-<translation id="6394627529324717982">Komma</translation>
-<translation id="3036649622769666520">Öppna filer</translation>
-<translation id="8328145009876646418">Vänsterkant</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_sw.xtb b/chromium/ui/base/strings/ui_strings_sw.xtb
deleted file mode 100644
index f0dc6efa8f1..00000000000
--- a/chromium/ui/base/strings/ui_strings_sw.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="sw">
-<translation id="4820616160060340806">Amri+ <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Futa</translation>
-<translation id="528468243742722775">Mwisho</translation>
-<translation id="5341849548509163798">Saa <ph name="NUMBER_MANY"/> zilizopita</translation>
-<translation id="6310545596129886942">zimesalia sekunde <ph name="NUMBER_FEW"/></translation>
-<translation id="9213479837033539041">zimesalia sekunde <ph name="NUMBER_MANY"/></translation>
-<translation id="1209866192426315618">zimesalia dakika <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="1801827354178857021">Kikomo</translation>
-<translation id="1190609913194133056">Kituo cha Arifa</translation>
-<translation id="7470933019269157899">Zimesalia dakika <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="5613020302032141669">Mshale Kushoto</translation>
-<translation id="4971687151119236543">Wimbo wa Awali wa Media</translation>
-<translation id="8602707065186045623">Faili ya <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918">dakika <ph name="NUMBER_ZERO"/> zilizopita</translation>
-<translation id="7121570032414343252">zimesalia sekunde <ph name="NUMBER_TWO"/></translation>
-<translation id="7511635910912978956">zimesalia saa <ph name="NUMBER_FEW"/></translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> zaidi kutoka <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Ghairi</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658">B <ph name="QUANTITY"/></translation>
-<translation id="3660179305079774227">Mshale Juu</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928">saa <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3990502903496589789">Ncha ya Kulia</translation>
-<translation id="9038489124413477075">Folda isiyo na jina</translation>
-<translation id="8507996248087185956">dakika <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="3520476450377425184">zimesalia siku <ph name="NUMBER_MANY"/></translation>
-<translation id="932327136139879170">Nyumbani</translation>
-<translation id="5600907569873192868">zimesalia dakika <ph name="NUMBER_MANY"/></translation>
-<translation id="8666066831007952346">zimesalia siku <ph name="NUMBER_TWO"/></translation>
-<translation id="6390842777729054533">zimesalia sekunde <ph name="NUMBER_ZERO"/></translation>
-<translation id="3909791450649380159">&amp;Kata</translation>
-<translation id="2560788951337264832">Zimesalia dakika <ph name="NUMBER_ZERO"/></translation>
-<translation id="688711909580084195">Ukurasa wa Wavuti usio na Kichwa</translation>
-<translation id="3353284378027041011">siku <ph name="NUMBER_FEW"/> zilizopita</translation>
-<translation id="5076340679995252485">&amp;Bandika</translation>
-<translation id="7460907917090416791">TB <ph name="QUANTITY"/></translation>
-<translation id="364720409959344976">Chagua Folda ya Kupakia</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016">dakika <ph name="NUMBER_TWO"/> zilizopita</translation>
-<translation id="3234408098842461169">Mshale Chini</translation>
-<translation id="3087734570205094154">Chini</translation>
-<translation id="5935630983280450497">imesalia dakika <ph name="NUMBER_ONE"/></translation>
-<translation id="1860796786778352021">Funga arifa</translation>
-<translation id="6364916375976753737">Sogeza Kushoto</translation>
-<translation id="2629089419211541119">saa <ph name="NUMBER_ONE"/> lililopita</translation>
-<translation id="2994641463185352298">Dakika <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6982279413068714821">dakika <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
-<translation id="6945221475159498467">Chagua</translation>
-<translation id="6620110761915583480">Hifadhi Faili</translation>
-<translation id="4349181486102621992">Sekunde <ph name="NUMBER_ZERO"/></translation>
-<translation id="6719684875142564568">saa <ph name="NUMBER_ZERO"/></translation>
-<translation id="7836361698254323868">Imesalia dakika <ph name="NUMBER_ONE"/></translation>
-<translation id="2953767478223974804">dakika <ph name="NUMBER_ONE"/></translation>
-<translation id="8210608804940886430">Ukurasa mmoja chini</translation>
-<translation id="1572103024875503863">siku <ph name="NUMBER_MANY"/></translation>
-<translation id="7163503212501929773">zimesalia saa <ph name="NUMBER_MANY"/></translation>
-<translation id="5329858601952122676">&amp;Futa</translation>
-<translation id="8088823334188264070">sekunde <ph name="NUMBER_MANY"/></translation>
-<translation id="8901569739625249689">KB <ph name="QUANTITY"/></translation>
-<translation id="7712011264267466734">Dakika <ph name="NUMBER_MANY"/></translation>
-<translation id="7275974018215686543">sekunde <ph name="NUMBER_MANY"/> zilizopita</translation>
-<translation id="7781829728241885113">Jana</translation>
-<translation id="3424538384153559412">Dakika <ph name="NUMBER_TWO"/></translation>
-<translation id="50960180632766478">zimesalia dakika <ph name="NUMBER_FEW"/></translation>
-<translation id="6659594942844771486">Kichupo</translation>
-<translation id="3049748772180311791">MB <ph name="QUANTITY"/></translation>
-<translation id="4988273303304146523">siku <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
-<translation id="8428213095426709021">Mipangilio</translation>
-<translation id="2497284189126895209">Faili zote</translation>
-<translation id="7487278341251176613">Zimesalia dakika <ph name="NUMBER_TWO"/></translation>
-<translation id="5110450810124758964">siku <ph name="NUMBER_ONE"/> iliyopita</translation>
-<translation id="2820806154655529776">sekunde <ph name="NUMBER_ONE"/></translation>
-<translation id="7814458197256864873">&amp;Nakili</translation>
-<translation id="3889424535448813030">Mshale Kulia</translation>
-<translation id="4229495110203539533">sekunde <ph name="NUMBER_ONE"/> iliyopita</translation>
-<translation id="2544782972264605588">zimesalia sekunde <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6829324100069873704">Rudi kwenye arifa</translation>
-<translation id="6528179044667508675">Usinisumbue</translation>
-<translation id="5066177358602611309">Sekunde <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="290555789621781773">dakika <ph name="NUMBER_TWO"/></translation>
-<translation id="5149131957118398098">Zimesalia saa <ph name="NUMBER_ZERO"/></translation>
-<translation id="7135556860107312402">Ruhusu arifa kutoka kwa:</translation>
-<translation id="8112886015144590373">saa <ph name="NUMBER_FEW"/></translation>
-<translation id="1398853756734560583">Tanua</translation>
-<translation id="4250229828105606438">Picha ya skrini</translation>
-<translation id="6690744523875189208">saa <ph name="NUMBER_TWO"/></translation>
-<translation id="5260878308685146029">zimesalia dakika <ph name="NUMBER_TWO"/></translation>
-<translation id="3757388668994797779">GB <ph name="QUANTITY"/></translation>
-<translation id="1901303067676059328">Chagua &amp;yote</translation>
-<translation id="2168039046890040389">Ukurasa mmoja juu</translation>
-<translation id="7363290921156020669">dakika <ph name="NUMBER_ZERO"/></translation>
-<translation id="9107059250669762581">siku <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="6463061331681402734">dakika <ph name="NUMBER_MANY"/></translation>
-<translation id="7634624804467787019">Dakika <ph name="NUMBER_ONE"/></translation>
-<translation id="8448317557906454022">sekunde <ph name="NUMBER_ZERO"/> zilizopita</translation>
-<translation id="4927753642311223124">Hakuna cha kuangalia hapa, endelea.</translation>
-<translation id="2482878487686419369">Arifa</translation>
-<translation id="6357135709975569075">siku <ph name="NUMBER_ZERO"/></translation>
-<translation id="3183922693828471536">Sogeza Hadi Hapa</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401">saa <ph name="NUMBER_MANY"/></translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Cheza Media/Sitisha</translation>
-<translation id="2148716181193084225">Leo</translation>
-<translation id="7960078400008666149">Usinisumbue kwa saa moja</translation>
-<translation id="4373894838514502496">dakika <ph name="NUMBER_FEW"/> zilizopita</translation>
-<translation id="4115153316875436289">siku <ph name="NUMBER_TWO"/></translation>
-<translation id="2190355936436201913">(tupu)</translation>
-<translation id="1164369517022005061">Zimesalia saa <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="152482086482215392">imesalia sekunde <ph name="NUMBER_ONE"/></translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Sogeza Kulia</translation>
-<translation id="7414887922320653780">limesalia saa <ph name="NUMBER_ONE"/></translation>
-<translation id="1413622004203049571">Zima arifa kutoka <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Ya Juu</translation>
-<translation id="8331626408530291785">Sogeza Juu</translation>
-<translation id="7907591526440419938">Fungua Faili</translation>
-<translation id="2864069933652346933">zimesalia siku <ph name="NUMBER_ZERO"/></translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045">Saa <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
-<translation id="815598010540052116">Sogeza Chini</translation>
-<translation id="6808150112686056157">Simamisha Media</translation>
-<translation id="1308727876662951186">zimesalia dakika <ph name="NUMBER_ZERO"/></translation>
-<translation id="3157931365184549694">Rejesha</translation>
-<translation id="1243314992276662751">Pakia</translation>
-<translation id="50030952220075532">imesalia siku <ph name="NUMBER_ONE"/></translation>
-<translation id="8179976553408161302">Enter</translation>
-<translation id="945522503751344254">Tuma maoni</translation>
-<translation id="9170848237812810038">&amp;Tendua</translation>
-<translation id="1285266685456062655">Saa <ph name="NUMBER_FEW"/> zilizopita</translation>
-<translation id="6918245111648057970">Ruhusu arifa kutoka kwa wafuatao kwa kila mtumiaji:</translation>
-<translation id="5489830104927132166">Sekunde <ph name="NUMBER_ONE"/></translation>
-<translation id="3994835489895548312">Zimesalia dakika <ph name="NUMBER_MANY"/></translation>
-<translation id="6358975074282722691">sekunde <ph name="NUMBER_TWO"/> zilizopita</translation>
-<translation id="520299402983819650">PB <ph name="QUANTITY"/></translation>
-<translation id="2983818520079887040">Mipangilio...</translation>
-<translation id="6845383723252244143">Chagua Folda</translation>
-<translation id="7600770490873519066">Sekunde <ph name="NUMBER_FEW"/></translation>
-<translation id="1095623615273566396">sekunde <ph name="NUMBER_FEW"/></translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534">siku <ph name="NUMBER_MANY"/> zilizopita</translation>
-<translation id="8355915647418390920">siku <ph name="NUMBER_FEW"/></translation>
-<translation id="5116333507878097773">saa <ph name="NUMBER_ONE"/></translation>
-<translation id="2679312662830811292">dakika <ph name="NUMBER_ONE"/> iliyopita</translation>
-<translation id="8788572795284305350">Saa <ph name="NUMBER_ZERO"/> zilizopita</translation>
-<translation id="3740362395218339114">GB/s <ph name="QUANTITY"/></translation>
-<translation id="6644971472240498405">siku <ph name="NUMBER_ONE"/></translation>
-<translation id="9098468523912235228">sekunde <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
-<translation id="494645311413743213">zimesalia sekunde <ph name="NUMBER_TWO"/></translation>
-<translation id="4570886800634958009">Panua arifa</translation>
-<translation id="436869212180315161">Bofya</translation>
-<translation id="4860787810836767172">sekunde <ph name="NUMBER_FEW"/> zilizopita</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074">Dakika <ph name="NUMBER_ZERO"/></translation>
-<translation id="1858722859751911017">Zimesalia dakika <ph name="NUMBER_FEW"/></translation>
-<translation id="6040143037577758943">Funga</translation>
-<translation id="1101671447232096497">dakika <ph name="NUMBER_MANY"/> zilizopita</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">Usaidizi</translation>
-<translation id="6699343763173986273">Wimbo Unaofuata kwenye Media</translation>
-<translation id="8226233771743600312">Usinisumbue kwa siku moja</translation>
-<translation id="7457942297256758195">Futa Zote</translation>
-<translation id="822618367988303761">siku <ph name="NUMBER_TWO"/> zilizopita</translation>
-<translation id="4745438305783437565">dakika <ph name="NUMBER_FEW"/></translation>
-<translation id="1963692530539281474">Zimesalia siku <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="7509440305564869263">Dakika <ph name="NUMBER_FEW"/></translation>
-<translation id="5906719743126878045">zimesalia saa <ph name="NUMBER_TWO"/></translation>
-<translation id="8959208747503200525">Saa <ph name="NUMBER_TWO"/> zilizopita</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940">sekunde <ph name="NUMBER_DEFAULT"/></translation>
-<translation id="4197700912384709145">sekunde <ph name="NUMBER_ZERO"/></translation>
-<translation id="27199337101878275">Sekunde <ph name="NUMBER_MANY"/></translation>
-<translation id="3759876923365568382">zimesalia siku <ph name="NUMBER_FEW"/></translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">Nakili kwenye ubao wa kunakili</translation>
-<translation id="8371695176452482769">Ongea sasa</translation>
-<translation id="6965382102122355670">Sawa</translation>
-<translation id="7850320739366109486">Usinisumbue</translation>
-<translation id="6978839998405419496">siku <ph name="NUMBER_ZERO"/> zilizopita</translation>
-<translation id="5941711191222866238">Punguza</translation>
-<translation id="6394627529324717982">Koma</translation>
-<translation id="3036649622769666520">Fungua Mafaili</translation>
-<translation id="8328145009876646418">Ncha ya Kushoto</translation>
-<translation id="7372005818821648611">Sekunde <ph name="NUMBER_TWO"/></translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_ta.xtb b/chromium/ui/base/strings/ui_strings_ta.xtb
deleted file mode 100644
index 2032880a820..00000000000
--- a/chromium/ui/base/strings/ui_strings_ta.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="ta">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942">இன்னும் <ph name="NUMBER_FEW"/> வினாடிகள் உள்ளன</translation>
-<translation id="9213479837033539041">இன்னும் <ph name="NUMBER_MANY"/> நொடிகள் உள்ளன</translation>
-<translation id="1209866192426315618">இன்னும் <ph name="NUMBER_DEFAULT"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="1801827354178857021">முற்றுப்புள்ளி</translation>
-<translation id="1190609913194133056">அறிவிப்பு மையம்</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="5613020302032141669">இடது அம்பு</translation>
-<translation id="4971687151119236543">ஊடகத்தின் முந்தைய டிராக்</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>கோப்பு(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> வினாடிகள்</translation>
-<translation id="7511635910912978956">இன்னும் <ph name="NUMBER_FEW"/> மணிநேரம் உள்ளது</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> இலிருந்து மேலும் <ph name="NUMBER_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">ரத்துசெய்</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> பை</translation>
-<translation id="3660179305079774227">மேல்நோக்கிய அம்பு</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> மெ.பை/வி</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> மணி நேரம்</translation>
-<translation id="3990502903496589789">வலது விளிம்பு</translation>
-<translation id="9038489124413477075">பெயரிடப்படாதக் கோப்புறை</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள்</translation>
-<translation id="3520476450377425184">இன்னும் <ph name="NUMBER_MANY"/> நாட்கள் உள்ளன</translation>
-<translation id="932327136139879170">முகப்பு</translation>
-<translation id="5600907569873192868">இன்னும் <ph name="NUMBER_MANY"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="8666066831007952346">இன்னும் <ph name="NUMBER_TWO"/> நாட்கள் உள்ளன</translation>
-<translation id="6390842777729054533">இன்னும் <ph name="NUMBER_ZERO"/> வினாடிகள் உள்ளன</translation>
-<translation id="3909791450649380159">வெட்&amp;டு</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="688711909580084195">தலைப்பிடாத வலைப்பக்கம்</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;ஒட்டு</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> டெ.பை</translation>
-<translation id="364720409959344976">பதிவேற்றுவதற்குக் கோப்புறையைத் தேர்ந்தெடு</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation>
-<translation id="3087734570205094154">கீழே</translation>
-<translation id="5935630983280450497">இன்னும் <ph name="NUMBER_ONE"/> நிமிடம் உள்ளது</translation>
-<translation id="1860796786778352021">அறிவிப்பை மூடு</translation>
-<translation id="6364916375976753737">இடப்புறம் உருட்டு</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள்</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">தேர்ந்தெடு</translation>
-<translation id="6620110761915583480">கோப்பைச் சேமி</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> வினாடிகள்</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> நிமிடம் உள்ளது</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> நிமிடம்</translation>
-<translation id="8210608804940886430">பக்கத்தின் கீழே</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> நாட்கள்</translation>
-<translation id="7163503212501929773">இன்னும் <ph name="NUMBER_MANY"/> மணிநேரம் உள்ளது</translation>
-<translation id="5329858601952122676">&amp;நீக்கு</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> நொடிகள்</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> கி.பை.</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> நிமிடங்கள்</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">நேற்று</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> நிமிடங்கள்</translation>
-<translation id="50960180632766478">இன்னும் <ph name="NUMBER_FEW"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> மெ.பை</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">அமைப்புகள்</translation>
-<translation id="2497284189126895209">அனைத்து கோப்புகளும்</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> நொடி</translation>
-<translation id="7814458197256864873">&amp;நகலெடு</translation>
-<translation id="3889424535448813030">வலது அம்பு</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588">இன்னும் <ph name="NUMBER_DEFAULT"/> வினாடிகள் உள்ளன</translation>
-<translation id="6829324100069873704">அறிவிப்புகளுக்குச் செல்</translation>
-<translation id="6528179044667508675">தொந்தரவு செய்ய வேண்டாம்</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> வினாடிகள்</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> நிமிடங்கள்</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">பின்வருபவற்றிலிருந்து வரும் அறிவிப்புகளை அனுமதி:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> மணி நேரம்</translation>
-<translation id="1398853756734560583">பெரிதாக்கு</translation>
-<translation id="4250229828105606438">ஸ்கிரீன் ஷாட்</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> மணி நேரம்</translation>
-<translation id="5260878308685146029">இன்னும் <ph name="NUMBER_TWO"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">அ&amp;னைத்தையும் தேர்ந்தெடு</translation>
-<translation id="2168039046890040389">பக்கத்தின் மேலே</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> நாட்கள்</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> நிமிடங்கள்</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> நிமிடம்</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">பார்க்க இங்கு எதுவுமில்லை, தொடரவும்.</translation>
-<translation id="2482878487686419369">அறிவிக்கைகள்</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">இங்கே உருட்டு</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> மணிநேரம்</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> கி.பை./வி</translation>
-<translation id="8394908167088220973">ஊடகத்தை இயக்கு/இடைநிறுத்து</translation>
-<translation id="2148716181193084225">இன்று</translation>
-<translation id="7960078400008666149">ஒரு மணிநேரத்திற்குத் தொந்தரவு செய்ய வேண்டாம்</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> நாட்கள்</translation>
-<translation id="2190355936436201913">(காலி)</translation>
-<translation id="1164369517022005061">இன்னும் <ph name="NUMBER_DEFAULT"/> மணிநேரம் உள்ளது</translation>
-<translation id="152482086482215392">இன்னும் <ph name="NUMBER_ONE"/> நொடிகள் உள்ளன</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">வலப்புறம் உருட்டு</translation>
-<translation id="7414887922320653780">இன்னும் <ph name="NUMBER_ONE"/> மணிநேரம் உள்ளது</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> இடமிருந்து வரும் அறிவிப்புகளை முடக்கு</translation>
-<translation id="2666092431469916601">மேலே</translation>
-<translation id="8331626408530291785">மேலே உருட்டு</translation>
-<translation id="7907591526440419938">கோப்பைத் திற</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">கீழே உருட்டு</translation>
-<translation id="6808150112686056157">ஊடகத்தை நிறுத்து</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">மீட்டமை</translation>
-<translation id="1243314992276662751">பதிவேற்று</translation>
-<translation id="50030952220075532">இன்னும் <ph name="NUMBER_ONE"/> நாட்கள் உள்ளன</translation>
-<translation id="8179976553408161302">உள்ளிடு</translation>
-<translation id="945522503751344254">பின்னூட்டம் அனுப்புக</translation>
-<translation id="9170848237812810038">&amp;செயல்தவிர்</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">ஒவ்வொரு பயனருக்கும் பின்வருபவையிலிருந்து அறிவிப்புகளை அனுமதி:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> வினாடி</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> பெ.பை</translation>
-<translation id="2983818520079887040">அமைப்புகள்...</translation>
-<translation id="6845383723252244143">கோப்புறையைத் தேர்ந்தெடு</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> வினாடிகள்</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> நொடிகள்</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> நாட்கள்</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> மணி நேரம்</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> ஜி.பை/வி</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> நாள்</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> வினாடிகள் உள்ளன</translation>
-<translation id="4570886800634958009">அறிவிப்பை விரிவாக்கு</translation>
-<translation id="436869212180315161">அழுத்து</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> டெ.பை/வி</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> நிமிடங்கள்</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> நிமிடங்கள் உள்ளன</translation>
-<translation id="6040143037577758943">மூடு</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> பை/வி</translation>
-<translation id="7649070708921625228">உதவி</translation>
-<translation id="6699343763173986273">ஊடகத்தின் அடுத்த டிராக்</translation>
-<translation id="8226233771743600312">ஒரு நாள் தொந்தரவு செய்ய வேண்டாம்</translation>
-<translation id="7457942297256758195">அனைத்தையும் அழி</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> நிமிடங்கள்</translation>
-<translation id="1963692530539281474">இன்னும் <ph name="NUMBER_DEFAULT"/> நாட்கள் உள்ளன</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> நிமிடங்கள்</translation>
-<translation id="5906719743126878045">இன்னும் <ph name="NUMBER_TWO"/> மணிநேரம் உள்ளது</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> நொடிகள்</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> நொடிகள்</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> வினாடிகள்</translation>
-<translation id="3759876923365568382">இன்னும் <ph name="NUMBER_FEW"/> நாட்கள் உள்ளன</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> பெ.பை/வி</translation>
-<translation id="2743387203779672305">கிளிப்போர்டுக்கு நகலெடு</translation>
-<translation id="8371695176452482769">இப்போது பேசுக</translation>
-<translation id="6965382102122355670">சரி</translation>
-<translation id="7850320739366109486">தொந்தரவு செய்ய வேண்டாம்</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">சிறிதாக்கு</translation>
-<translation id="6394627529324717982">கமா</translation>
-<translation id="3036649622769666520">கோப்புகளைத் திற</translation>
-<translation id="8328145009876646418">இடதுபுற முனை</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> வினாடிகள்</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_te.xtb b/chromium/ui/base/strings/ui_strings_te.xtb
deleted file mode 100644
index eede4c10b8d..00000000000
--- a/chromium/ui/base/strings/ui_strings_te.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="te">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">ముగింపు</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="1801827354178857021">సమయం</translation>
-<translation id="1190609913194133056">నోటిఫికేషన్ కేంద్రం</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="5613020302032141669">ఎడమ బాణం</translation>
-<translation id="4971687151119236543">మీడియా మునుపటి ట్రాక్</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ఫైల్ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> సెకన్లు</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> గంటలు మిగిలి ఉన్నాయి</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> నుండి మరో <ph name="NUMBER_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">రద్దు చెయ్యి</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">ఎగువ బాణం</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> గంటలు</translation>
-<translation id="3990502903496589789">కుడి సరిహద్దు</translation>
-<translation id="9038489124413477075">పేరులేని ఫోల్డర్</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> నిమిషాలు</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> రోజులు మిగిలి ఉన్నాయి</translation>
-<translation id="932327136139879170">హోమ్</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> నిమిషాలు మిగిలాయి</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> రోజులు మిగిలి ఉన్నాయి</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
-<translation id="3909791450649380159">క&amp;త్తిరించు</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="688711909580084195">శీర్షికలేని వెబ్‌పేజీ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;అతికించు</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">అప్‌లోడ్ చేయడానికి ఫోల్డర్‌ని ఎంచుకోండి</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">క్రింది బాణం</translation>
-<translation id="3087734570205094154">దిగువ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="1860796786778352021">నోటిఫికేషన్‌ను మూసివేయి</translation>
-<translation id="6364916375976753737">ఎడమకి స్క్రోల్ చేయి</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> నిమిషాలు</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
-<translation id="6945221475159498467">ఎంచుకోండి</translation>
-<translation id="6620110761915583480">ఫైల్‌ను సేవ్ చేయి</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> సెకన్లు</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> నిమిషం మిగిలి ఉంది</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> నిమిషం</translation>
-<translation id="8210608804940886430">పేజీ క్రిందికి</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> రోజులు</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> గంటలు మిగిలి ఉన్నాయి</translation>
-<translation id="5329858601952122676">&amp;తొలగించు</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> సెకన్లు</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> నిమిషాలు</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">నిన్న</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> నిమిషాలు</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> నిమిషాలు మిగిలిలాయి</translation>
-<translation id="6659594942844771486">టాబ్</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
-<translation id="8428213095426709021">సెట్టింగ్‌లు</translation>
-<translation id="2497284189126895209">మొత్తం ఫైళ్లు</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> సెకను</translation>
-<translation id="7814458197256864873">&amp;కాపీ</translation>
-<translation id="3889424535448813030">కుడి బాణం</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> సెకన్లు మిగిలాయి</translation>
-<translation id="6829324100069873704">నోటిఫికేషన్‌లకు తిరిగి వెళ్లు</translation>
-<translation id="6528179044667508675">అంతరాయం కలిగించవద్దు</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> సెకన్లు</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> నిమిషాలు</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">వీటి నుండి నోటిఫికేషన్‌లను అనుమతించు:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> గంటలు</translation>
-<translation id="1398853756734560583">గరిష్ఠీకరించు</translation>
-<translation id="4250229828105606438">స్క్రీన్‌షాట్</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> గంటలు</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> నిమిషాలు మిగిలాయి</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">&amp;అన్నీ ఎంచుకోండి</translation>
-<translation id="2168039046890040389">పేజీ పైకి</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> రోజులు</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> నిమిషాలు</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> నిమిషం</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">ఇక్కడ చూడటానికి ఏమీ లేదు, కొనసాగండి.</translation>
-<translation id="2482878487686419369">ప్రకటనలు</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">ఇక్కడ స్క్రోల్ చెయ్యండి</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> గంటలు</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/సె</translation>
-<translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation>
-<translation id="2148716181193084225">ఈ రోజు</translation>
-<translation id="7960078400008666149">ఒక గంటపాటు అంతరాయం కలిగించవద్దు</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> రోజులు</translation>
-<translation id="2190355936436201913">(ఖాళీ)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> గంటలు మిగిలాయి</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">కుడికి స్క్రోల్ చెయ్యి</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> గంటలు మిగిలా యి</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> నుండి వచ్చే నోటిఫికేషన్‌లను నిలిపివేయి</translation>
-<translation id="2666092431469916601">పైన</translation>
-<translation id="8331626408530291785">పైకి స్క్రోల్ చెయ్యి</translation>
-<translation id="7907591526440419938">ఫైల్‌ను తెరువు</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
-<translation id="815598010540052116">క్రిందికి స్క్రోల్ చేయి</translation>
-<translation id="6808150112686056157">మీడియా ఆపివేయి</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">పునరుద్ధరించు</translation>
-<translation id="1243314992276662751">అప్‌లోడ్ చేయి</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> రోజులు మిగిలి ఉన్నాయి</translation>
-<translation id="8179976553408161302">నమోదు చేయండి</translation>
-<translation id="945522503751344254">అభిప్రాయాన్ని పంపండి</translation>
-<translation id="9170848237812810038">&amp;అన్డు</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">ప్రతి వినియోగదారు కోసం కింది వారి నుండి నోటిఫికేషన్‌లను అనుమతించు:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> సెకను</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">సెట్టింగ్‌లు...</translation>
-<translation id="6845383723252244143">ఫోల్డర్‌ను ఎంచుకో</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> సెకన్లు</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> సెకన్లు</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> రోజులు</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> గంట</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> రోజు</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
-<translation id="4570886800634958009">నోటిఫికేషన్‌ను విస్తరించు</translation>
-<translation id="436869212180315161">నొక్కు</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> నిమిషాలు</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
-<translation id="6040143037577758943">మూసివేయి</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">సహాయం</translation>
-<translation id="6699343763173986273">మీడియా తదుపరి ట్రాక్</translation>
-<translation id="8226233771743600312">ఒక రోజుపాటు అంతరాయం కలిగించవద్దు</translation>
-<translation id="7457942297256758195">అన్నీ క్లియర్ చేయి</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> నిమిషాలు</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> రోజులు మిగిలాయి</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> నిమిషాలు</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> గంటలు మిగిలి ఉన్నాయి</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> సెకన్లు</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> సెకన్లు</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> సెకన్లు</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> రోజులు మిగిలాయి</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">క్లిప్‌బోర్డ్‌కు కాపీ చేయి</translation>
-<translation id="8371695176452482769">ఇప్పుడు మాట్లాడండి</translation>
-<translation id="6965382102122355670">సరే</translation>
-<translation id="7850320739366109486">అంతరాయం కలిగించవద్దు</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">కనిష్టీకరించు</translation>
-<translation id="6394627529324717982">కామా</translation>
-<translation id="3036649622769666520">ఫైళ్ళను తెరువు</translation>
-<translation id="8328145009876646418">ఎడమ హద్దు</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> సెకన్లు</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_th.xtb b/chromium/ui/base/strings/ui_strings_th.xtb
deleted file mode 100644
index 8f9debf1091..00000000000
--- a/chromium/ui/base/strings/ui_strings_th.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="th">
-<translation id="4820616160060340806">คำสั่ง+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> ชั่วโมงที่ผ่านมา</translation>
-<translation id="6310545596129886942">เหลือ <ph name="NUMBER_FEW"/> วินาที</translation>
-<translation id="9213479837033539041">เหลือ <ph name="NUMBER_MANY"/> วินาที</translation>
-<translation id="1209866192426315618">เหลือ <ph name="NUMBER_DEFAULT"/> นาที</translation>
-<translation id="1801827354178857021">มหัพภาค</translation>
-<translation id="1190609913194133056">ศูนย์การแจ้งเตือน</translation>
-<translation id="7470933019269157899">เหลือ <ph name="NUMBER_DEFAULT"/> นาที</translation>
-<translation id="5613020302032141669">ลูกศรซ้าย</translation>
-<translation id="4971687151119236543">แทร็กก่อนหน้าของสื่อ</translation>
-<translation id="8602707065186045623">ไฟล์ <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> วินาที</translation>
-<translation id="7511635910912978956">เหลือ <ph name="NUMBER_FEW"/> ชั่วโมง</translation>
-<translation id="8717309436826820190">อีก <ph name="NUMBER_OF_NOTIFICATIONS"/> รายการจาก <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">ยกเลิก</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">ลูกศรขึ้น</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/วินาที</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ชั่วโมง</translation>
-<translation id="3990502903496589789">ขอบขวา</translation>
-<translation id="9038489124413477075">โฟลเดอร์ที่ไม่มีชื่อ</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> นาที</translation>
-<translation id="3520476450377425184">เหลือ <ph name="NUMBER_MANY"/> วัน</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868">เหลือ <ph name="NUMBER_MANY"/> นาที</translation>
-<translation id="8666066831007952346">เหลือ <ph name="NUMBER_TWO"/> วัน</translation>
-<translation id="6390842777729054533">เหลือ <ph name="NUMBER_ZERO"/> วินาที</translation>
-<translation id="3909791450649380159">&amp;ตัด</translation>
-<translation id="2560788951337264832">เหลือ <ph name="NUMBER_ZERO"/> นาที</translation>
-<translation id="688711909580084195">หน้าเว็บที่ไม่มีชื่อ</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> วันที่ผ่านมา</translation>
-<translation id="5076340679995252485">&amp;วาง</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">เลือกโฟลเดอร์เพื่ออัปโหลด</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> นาทีที่ผ่านมา</translation>
-<translation id="3234408098842461169">ลูกศรลง</translation>
-<translation id="3087734570205094154">ด้านล่าง</translation>
-<translation id="5935630983280450497">เหลือ <ph name="NUMBER_ONE"/> นาที</translation>
-<translation id="1860796786778352021">ปิดการแจ้งเตือน</translation>
-<translation id="6364916375976753737">เลื่อนทางซ้าย</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ชั่วโมงที่ผ่านมา</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> นาที</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> นาทีที่ผ่านมา</translation>
-<translation id="6945221475159498467">เลือก</translation>
-<translation id="6620110761915583480">บันทึกไฟล์</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">เหลือ <ph name="NUMBER_ONE"/> นาที</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> นาที</translation>
-<translation id="8210608804940886430">เลื่อนหน้าลง</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> วัน</translation>
-<translation id="7163503212501929773">เหลือ <ph name="NUMBER_MANY"/> ชั่วโมง</translation>
-<translation id="5329858601952122676">&amp;ลบ</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> วินาที</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> วินาทีที่ผ่านมา</translation>
-<translation id="7781829728241885113">เมื่อวานนี้</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478">เหลือ <ph name="NUMBER_FEW"/> นาที</translation>
-<translation id="6659594942844771486">แท็บ</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> วันที่ผ่านมา</translation>
-<translation id="8428213095426709021">การตั้งค่า</translation>
-<translation id="2497284189126895209">ไฟล์ทั้งหมด</translation>
-<translation id="7487278341251176613">เหลือ <ph name="NUMBER_TWO"/> นาที</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> วันที่ผ่านมา</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> วินาที</translation>
-<translation id="7814458197256864873">&amp;คัดลอก</translation>
-<translation id="3889424535448813030">ลูกศรขวา</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> วินาทีที่ผ่านมา</translation>
-<translation id="2544782972264605588">เหลือ <ph name="NUMBER_DEFAULT"/> วินาที</translation>
-<translation id="6829324100069873704">กลับไปที่การแจ้งเตือน</translation>
-<translation id="6528179044667508675">ห้ามรบกวน</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> วินาที</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> นาที</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">อนุญาตให้มีการแจ้งเตือนจากรายการต่อไปนี้</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ชั่วโมง</translation>
-<translation id="1398853756734560583">ย่อ</translation>
-<translation id="4250229828105606438">ภาพหน้าจอ</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ชั่วโมง</translation>
-<translation id="5260878308685146029">เหลือ <ph name="NUMBER_TWO"/> นาที</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">เลือก&amp;ทั้งหมด</translation>
-<translation id="2168039046890040389">เลื่อนหน้าขึ้น</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> วัน</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> นาที</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> นาที</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> วินาทีที่ผ่านมา</translation>
-<translation id="4927753642311223124">ที่นี่ไม่มีอะไรต้องดู ไปต่อได้</translation>
-<translation id="2482878487686419369">การแจ้งเตือน</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">เลื่อนมาที่นี่</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ชั่วโมง</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/วินาที</translation>
-<translation id="8394908167088220973">เล่น/หยุดสื่อชั่วคราว</translation>
-<translation id="2148716181193084225">วันนี้</translation>
-<translation id="7960078400008666149">ห้ามรบกวนเป็นเวลาหนึ่งชั่วโมง</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> นาทีที่ผ่านมา</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> วัน</translation>
-<translation id="2190355936436201913">(ว่างเปล่า)</translation>
-<translation id="1164369517022005061">เหลือ <ph name="NUMBER_DEFAULT"/> ชั่วโมง</translation>
-<translation id="152482086482215392">เหลือ <ph name="NUMBER_ONE"/> วินาที</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">เลื่อนทางขวา</translation>
-<translation id="7414887922320653780">เหลือ <ph name="NUMBER_ONE"/> ชั่วโมง</translation>
-<translation id="1413622004203049571">ปิดการแจ้งเตือนจาก <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">ด้านบน</translation>
-<translation id="8331626408530291785">เลื่อนขึ้น</translation>
-<translation id="7907591526440419938">เปิดไฟล์</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ชั่วโมงที่ผ่านมา</translation>
-<translation id="815598010540052116">เลื่อนลง</translation>
-<translation id="6808150112686056157">หยุดสื่อ</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">คืนค่า</translation>
-<translation id="1243314992276662751">อัปโหลด</translation>
-<translation id="50030952220075532">เหลือ <ph name="NUMBER_ONE"/> วัน</translation>
-<translation id="8179976553408161302">เข้าใช้</translation>
-<translation id="945522503751344254">ส่งความคิดเห็น</translation>
-<translation id="9170848237812810038">เ&amp;ลิกทำ</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ชั่วโมงที่ผ่านมา</translation>
-<translation id="6918245111648057970">อนุญาตให้มีการแจ้งเตือนจากรายการต่อไปนี้สำหรับผู้ใช้แต่ละคน:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> วินาที</translation>
-<translation id="3994835489895548312">เหลือ <ph name="NUMBER_MANY"/> นาที</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> วินาทีที่ผ่านมา</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">การตั้งค่า...</translation>
-<translation id="6845383723252244143">เลือกโฟลเดอร์</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> วินาที</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> วันที่ผ่านมา</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> วัน</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ชั่วโมง</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> นาทีที่ผ่านมา</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/วินาที</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> วัน</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> วินาทีที่ผ่านมา</translation>
-<translation id="494645311413743213">เหลือ <ph name="NUMBER_TWO"/> วินาที</translation>
-<translation id="4570886800634958009">ขยายการแจ้งเตือน</translation>
-<translation id="436869212180315161">กด</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> วินาทีที่ผ่านมา</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/วินาที</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">เหลือ <ph name="NUMBER_FEW"/> นาที</translation>
-<translation id="6040143037577758943">ปิด</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> นาทีที่ผ่านมา</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/วินาที</translation>
-<translation id="7649070708921625228">ช่วยเหลือ</translation>
-<translation id="6699343763173986273">แทร็กถัดไปของสื่อ</translation>
-<translation id="8226233771743600312">ห้ามรบกวนเป็นเวลาหนึ่งวัน</translation>
-<translation id="7457942297256758195">ล้างทั้งหมด</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> วันที่ผ่านมา</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> นาที</translation>
-<translation id="1963692530539281474">เหลือ <ph name="NUMBER_DEFAULT"/> วัน</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045">เหลือ <ph name="NUMBER_TWO"/> ชั่วโมง</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> ชั่วโมงที่ผ่านมา</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> วินาที</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> วินาที</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382">เหลือ <ph name="NUMBER_FEW"/> วัน</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/วินาที</translation>
-<translation id="2743387203779672305">คัดลอกไว้ที่คลิปบอร์ด</translation>
-<translation id="8371695176452482769">พูดเดี๋ยวนี้</translation>
-<translation id="6965382102122355670">ตกลง</translation>
-<translation id="7850320739366109486">ห้ามรบกวน</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">ย่อ</translation>
-<translation id="6394627529324717982">จุลภาค</translation>
-<translation id="3036649622769666520">เปิดไฟล์</translation>
-<translation id="8328145009876646418">ขอบซ้าย</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_tr.xtb b/chromium/ui/base/strings/ui_strings_tr.xtb
deleted file mode 100644
index 4879d395d23..00000000000
--- a/chromium/ui/base/strings/ui_strings_tr.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="tr">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> saat önce</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> saniye kaldı</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> saniye kaldı</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> dakika kaldı</translation>
-<translation id="1801827354178857021">Nokta</translation>
-<translation id="1190609913194133056">Bildirim Merkezi</translation>
-<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> dakika kaldı</translation>
-<translation id="5613020302032141669">Sol Ok</translation>
-<translation id="4971687151119236543">Medya Önceki Parça</translation>
-<translation id="8602707065186045623">Dosyayı <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> saniye</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> saat kaldı</translation>
-<translation id="8717309436826820190"><ph name="SOURCE_OF_NOTIFICATIONS"/> kaynağından <ph name="NUMBER_OF_NOTIFICATIONS"/> bildirim daha</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">İptal</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Yukarı Ok</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sn</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> saat</translation>
-<translation id="3990502903496589789">Sağ Kenar</translation>
-<translation id="9038489124413477075">Adsız Klasör</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> dakika</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> gün kaldı</translation>
-<translation id="932327136139879170">Ana Sayfa</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> dakika kaldı</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> gün kaldı</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> saniye kaldı</translation>
-<translation id="3909791450649380159">&amp;Kes</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> dakika kaldı</translation>
-<translation id="688711909580084195">Başlıksız Web Sayfası</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> gün önce</translation>
-<translation id="5076340679995252485">&amp;Yapıştır</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Yüklenecek Klasörü Seçin</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> dakika önce</translation>
-<translation id="3234408098842461169">Aşağı Ok</translation>
-<translation id="3087734570205094154">Alt</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> dakika kaldı</translation>
-<translation id="1860796786778352021">Bildirimi kapat</translation>
-<translation id="6364916375976753737">Sola Kaydır</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> saat önce</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> dakika</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> dakika önce</translation>
-<translation id="6945221475159498467">Seç</translation>
-<translation id="6620110761915583480">Dosyayı Kaydet</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> dakika kaldı</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> dakika</translation>
-<translation id="8210608804940886430">Page Down</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> gün</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> saat kaldı</translation>
-<translation id="5329858601952122676">&amp;Sil</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> saniye</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> saniye önce</translation>
-<translation id="7781829728241885113">Dün</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> dakika kaldı</translation>
-<translation id="6659594942844771486">Sekme</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> gün önce</translation>
-<translation id="8428213095426709021">Ayarlar</translation>
-<translation id="2497284189126895209">Tüm Dosyalar</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> dakika kaldı</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> gün önce</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> saniye</translation>
-<translation id="7814458197256864873">K&amp;opyala</translation>
-<translation id="3889424535448813030">Sağ Ok</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> saniye önce</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> saniye kaldı</translation>
-<translation id="6829324100069873704">Bildirimlere geri dön</translation>
-<translation id="6528179044667508675">Rahatsız etmeyin</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> saniye</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> dakika</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Şunlardan gelen bildirimlere izin ver:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> saat</translation>
-<translation id="1398853756734560583">Büyüt</translation>
-<translation id="4250229828105606438">Ekran görüntüsü</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> saat</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> dakika kaldı</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Tümünü &amp;seç</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> gün</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> dakika</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> saniye önce</translation>
-<translation id="4927753642311223124">Burada görülecek bir şey yok, devam edin.</translation>
-<translation id="2482878487686419369">Bildirimler</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Buraya Kaydır</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> saat</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/sn</translation>
-<translation id="8394908167088220973">Medyayı Oynat/Duraklat</translation>
-<translation id="2148716181193084225">Bugün</translation>
-<translation id="7960078400008666149">Bir saat süreyle rahatsız etmeyin</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> dakika önce</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> gün</translation>
-<translation id="2190355936436201913">(boş)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> saat kaldı</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> saniye kaldı</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Sağa Kaydır</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> saat kaldı</translation>
-<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> bildirimlerini devre dışı bırak</translation>
-<translation id="2666092431469916601">Üst</translation>
-<translation id="8331626408530291785">Yukarı Kaydır</translation>
-<translation id="7907591526440419938">Dosya Aç</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> saat önce</translation>
-<translation id="815598010540052116">Aşağı Kaydır</translation>
-<translation id="6808150112686056157">Medyayı Durdur</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Geri yükle</translation>
-<translation id="1243314992276662751">Yükle</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> gün kaldı</translation>
-<translation id="8179976553408161302">Giriş</translation>
-<translation id="945522503751344254">Geri bildirim gönder</translation>
-<translation id="9170848237812810038">&amp;Geri al</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> saat önce</translation>
-<translation id="6918245111648057970">Her bir kullanıcı için şunlardan gelen bildirimlere izin ver:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> second</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> dakika kaldı</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> saniye önce</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Ayarlar...</translation>
-<translation id="6845383723252244143">Klasörü Seçin</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> saniye</translation>
-<translation id="5583640892426849032">Geri al tuşu</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> gün önce</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> gün</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> saat</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> dakika önce</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sn</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> gün</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> saniye önce</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> saniye kaldı</translation>
-<translation id="4570886800634958009">Bildirimi genişlet</translation>
-<translation id="436869212180315161">Basın</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> saniye önce</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sn</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> dakika kaldı</translation>
-<translation id="6040143037577758943">Kapat</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> dakika önce</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sn</translation>
-<translation id="7649070708921625228">Yardım</translation>
-<translation id="6699343763173986273">Medya Sonraki Parça</translation>
-<translation id="8226233771743600312">Bir gün süreyle rahatsız etmeyin</translation>
-<translation id="7457942297256758195">Tümünü Temizle</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> gün önce</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> dakika</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> gün kaldı</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> saat kaldı</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> saat önce</translation>
-<translation id="8400147561352026160">ÜstKrkt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> saniye</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> saniye</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> gün kaldı</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sn</translation>
-<translation id="2743387203779672305">Panoya kopyala</translation>
-<translation id="8371695176452482769">Şimdi konuşun</translation>
-<translation id="6965382102122355670">Tamam</translation>
-<translation id="7850320739366109486">Rahatsız Etmeyin</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Simge durumuna küçült</translation>
-<translation id="6394627529324717982">Virgül</translation>
-<translation id="3036649622769666520">Dosya Aç</translation>
-<translation id="8328145009876646418">Sol Kenar</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_uk.xtb b/chromium/ui/base/strings/ui_strings_uk.xtb
deleted file mode 100644
index 3510dafc804..00000000000
--- a/chromium/ui/base/strings/ui_strings_uk.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="uk">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> сек. залишилось</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
-<translation id="1209866192426315618">Залишилось <ph name="NUMBER_DEFAULT"/> хв.</translation>
-<translation id="1801827354178857021">Крапка</translation>
-<translation id="1190609913194133056">Центр сповіщень</translation>
-<translation id="7470933019269157899">Залишилося <ph name="NUMBER_DEFAULT"/> хвилини</translation>
-<translation id="5613020302032141669">Курсор ліворуч</translation>
-<translation id="4971687151119236543">Попередня композиція</translation>
-<translation id="8602707065186045623">файл <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> годин залишилось</translation>
-<translation id="8717309436826820190">Ще <ph name="NUMBER_OF_NOTIFICATIONS"/> з <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Скасувати</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> б</translation>
-<translation id="3660179305079774227">Курсор угору</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> Мб/сек.</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> годин</translation>
-<translation id="3990502903496589789">Правий край</translation>
-<translation id="9038489124413477075">Папка без назви</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> хв.</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
-<translation id="932327136139879170">Home</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">Вирізат&amp;и</translation>
-<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
-<translation id="688711909580084195">Веб-сторінка без назви</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> дн. тому</translation>
-<translation id="5076340679995252485">&amp;Вставити</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> Тб</translation>
-<translation id="364720409959344976">Виберіть папку для завантаження</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Курсор униз</translation>
-<translation id="3087734570205094154">Низ</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> хв. залишилась</translation>
-<translation id="1860796786778352021">Закрити сповіщення</translation>
-<translation id="6364916375976753737">Прокрутка вліво</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> год. тому</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> хв</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> хв. тому</translation>
-<translation id="6945221475159498467">Вибрати</translation>
-<translation id="6620110761915583480">Зберегти файл</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Залишилася <ph name="NUMBER_ONE"/> хвилина</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> хв.</translation>
-<translation id="8210608804940886430">Сторінка вниз</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
-<translation id="5329858601952122676">&amp;Видалити</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> Кб</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Учора</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> хв. залишилось</translation>
-<translation id="6659594942844771486">Вкладка</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> Мб</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> дн. тому</translation>
-<translation id="8428213095426709021">Налаштування</translation>
-<translation id="2497284189126895209">Усі файли</translation>
-<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> день тому</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
-<translation id="7814458197256864873">&amp;Копіювати</translation>
-<translation id="3889424535448813030">Курсор праворуч</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> сек. тому</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> сек. залишилось</translation>
-<translation id="6829324100069873704">Повернутися до сповіщень</translation>
-<translation id="6528179044667508675">Не турбувати</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> с</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Дозволити сповіщення з перелічених нижче джерел.</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> годин</translation>
-<translation id="1398853756734560583">Збільшити</translation>
-<translation id="4250229828105606438">Знімок екрана</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> Гб</translation>
-<translation id="1901303067676059328">Вибрати &amp;всі</translation>
-<translation id="2168039046890040389">Сторінка вгору</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> днів</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> хвилина</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Сповіщень немає.</translation>
-<translation id="2482878487686419369">Сповіщення</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Прокрутка до цього місця</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> годин</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> Кб/сек.</translation>
-<translation id="8394908167088220973">Відтворити чи призупинити</translation>
-<translation id="2148716181193084225">Сьогодні</translation>
-<translation id="7960078400008666149">Не турбувати впродовж однієї години</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> хв. тому</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
-<translation id="2190355936436201913">(пусто)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> годин залишилось</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> сек. залишилась</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Прокрутка вправо</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> година залишилась</translation>
-<translation id="1413622004203049571">Вимкнути сповіщення від <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Верх</translation>
-<translation id="8331626408530291785">Прокрутка вгору</translation>
-<translation id="7907591526440419938">Відкрити файл</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> год. тому</translation>
-<translation id="815598010540052116">Прокрутка вниз</translation>
-<translation id="6808150112686056157">Зупинити</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Відновити</translation>
-<translation id="1243314992276662751">Завантажити</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> день залишився</translation>
-<translation id="8179976553408161302">Увійти</translation>
-<translation id="945522503751344254">Надіслати відгук</translation>
-<translation id="9170848237812810038">&amp;Скасувати</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> год. тому</translation>
-<translation id="6918245111648057970">Дозволити сповіщення для кожного користувача:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
-<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> Пб</translation>
-<translation id="2983818520079887040">Налаштування...</translation>
-<translation id="6845383723252244143">Вибір папки</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунди</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> днів</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> година</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> хв. тому</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> Гб/сек.</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> день</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> сек. тому</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
-<translation id="4570886800634958009">Розгорнути сповіщення</translation>
-<translation id="436869212180315161">Натиснути</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> сек. тому</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> Тб/сек.</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
-<translation id="1858722859751911017">Залишилося <ph name="NUMBER_FEW"/> хвилини</translation>
-<translation id="6040143037577758943">Закрити</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> б/сек.</translation>
-<translation id="7649070708921625228">Довідка</translation>
-<translation id="6699343763173986273">Наступна композиція</translation>
-<translation id="8226233771743600312">Не турбувати впродовж одного дня</translation>
-<translation id="7457942297256758195">Очистити все</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> хв.</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> днів залишилось</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> хвилини</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> днів залишилось</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> Пб/сек.</translation>
-<translation id="2743387203779672305">Копіювати в буфер</translation>
-<translation id="8371695176452482769">Диктуйте</translation>
-<translation id="6965382102122355670">ОК</translation>
-<translation id="7850320739366109486">Не турбувати</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Зменшити</translation>
-<translation id="6394627529324717982">Кома</translation>
-<translation id="3036649622769666520">Відкрити файли</translation>
-<translation id="8328145009876646418">Лівий край</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_vi.xtb b/chromium/ui/base/strings/ui_strings_vi.xtb
deleted file mode 100644
index 53474a9d342..00000000000
--- a/chromium/ui/base/strings/ui_strings_vi.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="vi">
-<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> giây còn lại</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> giây còn lại</translation>
-<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> phút còn lại</translation>
-<translation id="1801827354178857021">Dấu chấm</translation>
-<translation id="1190609913194133056">Trung tâm thông báo</translation>
-<translation id="7470933019269157899">Còn lại <ph name="NUMBER_DEFAULT"/> phút</translation>
-<translation id="5613020302032141669">Mũi tên Trái</translation>
-<translation id="4971687151119236543">Bản nhạc trước của trình phát phương tiện</translation>
-<translation id="8602707065186045623">Tệp <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> giây</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> giờ còn lại</translation>
-<translation id="8717309436826820190"><ph name="NUMBER_OF_NOTIFICATIONS"/> thông báo khác từ <ph name="SOURCE_OF_NOTIFICATIONS"/></translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">Hủy</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">Phím mũi tên Lên</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/giây</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> giờ</translation>
-<translation id="3990502903496589789">Cạnh bên Phải</translation>
-<translation id="9038489124413477075">Thư mục không có tên</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> phút</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ngày còn lại</translation>
-<translation id="932327136139879170">Trang chủ</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> phút còn lại</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ngày còn lại</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> giây còn lại</translation>
-<translation id="3909791450649380159">Cắ&amp;t</translation>
-<translation id="2560788951337264832">Còn lại <ph name="NUMBER_ZERO"/> phút</translation>
-<translation id="688711909580084195">Trang web không có tiêu đề</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
-<translation id="5076340679995252485">&amp;Dán</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">Chọn thư mục để tải lên</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
-<translation id="3234408098842461169">Phím mũi tên Xuống</translation>
-<translation id="3087734570205094154">Bên dưới</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> phút còn lại</translation>
-<translation id="1860796786778352021">Đóng thông báo</translation>
-<translation id="6364916375976753737">Cuộn qua Trái</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> phút</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> phút trước</translation>
-<translation id="6945221475159498467">Chọn</translation>
-<translation id="6620110761915583480">Lưu Tệp</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> giây</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">Còn lại <ph name="NUMBER_ONE"/> phút</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> phút</translation>
-<translation id="8210608804940886430">Trang Dưới</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ngày</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> giờ còn lại</translation>
-<translation id="5329858601952122676">&amp;Xoá</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> giây</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> phút</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
-<translation id="7781829728241885113">Hôm qua</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> phút</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> phút còn lại</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> ngày trước</translation>
-<translation id="8428213095426709021">Cài đặt</translation>
-<translation id="2497284189126895209">Tất cả Tệp tin</translation>
-<translation id="7487278341251176613">Còn lại <ph name="NUMBER_TWO"/> phút</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> giây</translation>
-<translation id="7814458197256864873">Sao &amp;chép</translation>
-<translation id="3889424535448813030">Phím mũi tên Phải</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
-<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> giây còn lại</translation>
-<translation id="6829324100069873704">Quay lại thông báo</translation>
-<translation id="6528179044667508675">Không làm phiền</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> giây</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> phút</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">Cho phép thông báo từ:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> giờ</translation>
-<translation id="1398853756734560583">Phóng to</translation>
-<translation id="4250229828105606438">Ảnh chụp màn hình</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> giờ</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> phút còn lại</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">Chọn &amp;tất cả</translation>
-<translation id="2168039046890040389">Page Up</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ngày</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> phút</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> phút</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
-<translation id="4927753642311223124">Không có nội dung nào để xem ở đây, hãy tiếp tục.</translation>
-<translation id="2482878487686419369">Thông báo</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">Cuộn tới Đây</translation>
-<translation id="4552416320897244156">Trang Dưới</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> giờ</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">Phát/Tạm dừng trình phát phương tiện</translation>
-<translation id="2148716181193084225">Hôm nay</translation>
-<translation id="7960078400008666149">Không làm phiền trong một giờ</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ngày</translation>
-<translation id="2190355936436201913">(trống)</translation>
-<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> giờ còn lại</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> giây còn lại</translation>
-<translation id="8447116497070723931">Trang Trên</translation>
-<translation id="4588090240171750605">Cuộn qua Phải</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> giờ còn lại</translation>
-<translation id="1413622004203049571">Tắt thông báo từ <ph name="NOTIFIER_NAME"/></translation>
-<translation id="2666092431469916601">Hàng đầu</translation>
-<translation id="8331626408530291785">Cuộn Lên</translation>
-<translation id="7907591526440419938">Mở Tệp</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Thoát</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> giờ trước</translation>
-<translation id="815598010540052116">Cuộn Xuống</translation>
-<translation id="6808150112686056157">Dừng trình phát phương tiện</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">Khôi phục</translation>
-<translation id="1243314992276662751">Tải lên</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ngày còn lại</translation>
-<translation id="8179976553408161302">Vào</translation>
-<translation id="945522503751344254">Gửi phản hồi</translation>
-<translation id="9170848237812810038">H&amp;oàn tác</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
-<translation id="6918245111648057970">Cho phép thông báo từ mục sau đối với mỗi người dùng:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> giây</translation>
-<translation id="3994835489895548312">Còn lại <ph name="NUMBER_MANY"/> phút</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">Cài đặt...</translation>
-<translation id="6845383723252244143">Chọn Thư mục</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> giây</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> giây</translation>
-<translation id="5583640892426849032">Backspace</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ngày</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> giờ</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/giây</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ngày</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> giây trước</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> giây còn lại</translation>
-<translation id="4570886800634958009">Mở rộng thông báo</translation>
-<translation id="436869212180315161">Nhấp vào</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/giây</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> phút</translation>
-<translation id="1858722859751911017">Còn lại <ph name="NUMBER_FEW"/> phút</translation>
-<translation id="6040143037577758943">Đóng</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/giây</translation>
-<translation id="7649070708921625228">Trợ giúp</translation>
-<translation id="6699343763173986273">Bản nhạc tiếp theo của trình phát phương tiện</translation>
-<translation id="8226233771743600312">Không làm phiền trong một ngày</translation>
-<translation id="7457942297256758195">Xóa tất cả</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> phút</translation>
-<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ngày còn lại</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> phút</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> giờ còn lại</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> giây</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> giây</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> giây</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ngày còn lại</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/giây</translation>
-<translation id="2743387203779672305">Sao chép vào khay nhớ tạm</translation>
-<translation id="8371695176452482769">Nói ngay bây giờ</translation>
-<translation id="6965382102122355670">OK</translation>
-<translation id="7850320739366109486">Không làm phiền</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">Thu nhỏ</translation>
-<translation id="6394627529324717982">Dấu phẩy</translation>
-<translation id="3036649622769666520">Mở Tệp</translation>
-<translation id="8328145009876646418">Cạnh Bên trái</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> giây</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_zh-CN.xtb b/chromium/ui/base/strings/ui_strings_zh-CN.xtb
deleted file mode 100644
index 0046e94645b..00000000000
--- a/chromium/ui/base/strings/ui_strings_zh-CN.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="zh-CN">
-<translation id="4820616160060340806">命令键 + <ph name="KEY_COMBO_NAME"/></translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">End</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 小时前</translation>
-<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
-<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
-<translation id="1209866192426315618">还有 <ph name="NUMBER_DEFAULT"/> 分钟</translation>
-<translation id="1801827354178857021">句号</translation>
-<translation id="1190609913194133056">通知中心</translation>
-<translation id="7470933019269157899">还剩 <ph name="NUMBER_DEFAULT"/> 分钟</translation>
-<translation id="5613020302032141669">向左箭头</translation>
-<translation id="4971687151119236543">媒体上一曲</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 文件 (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
-<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
-<translation id="8717309436826820190">另外还有<ph name="NUMBER_OF_NOTIFICATIONS"/>条<ph name="SOURCE_OF_NOTIFICATIONS"/>通知</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">取消</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">向上箭头</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 小时</translation>
-<translation id="3990502903496589789">右边缘</translation>
-<translation id="9038489124413477075">未命名的文件夹</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分钟</translation>
-<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
-<translation id="932327136139879170">主页</translation>
-<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
-<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
-<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
-<translation id="3909791450649380159">剪切(&amp;T)</translation>
-<translation id="2560788951337264832">还剩 <ph name="NUMBER_ZERO"/> 分钟</translation>
-<translation id="688711909580084195">无标题网页</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 天前</translation>
-<translation id="5076340679995252485">粘贴(&amp;P)</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">选择要上传的文件夹</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分钟前</translation>
-<translation id="3234408098842461169">向下箭头</translation>
-<translation id="3087734570205094154">底部</translation>
-<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min left</translation>
-<translation id="1860796786778352021">关闭通知</translation>
-<translation id="6364916375976753737">向左滚动</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 小时前</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分钟</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分钟前</translation>
-<translation id="6945221475159498467">选择</translation>
-<translation id="6620110761915583480">保存文件</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">还剩 <ph name="NUMBER_ONE"/> 分钟</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
-<translation id="8210608804940886430">向下翻页</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
-<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
-<translation id="5329858601952122676">删除(&amp;D)</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分钟</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
-<translation id="7781829728241885113">昨天</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分钟</translation>
-<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 天前</translation>
-<translation id="8428213095426709021">设置</translation>
-<translation id="2497284189126895209">所有文件</translation>
-<translation id="7487278341251176613">还剩 <ph name="NUMBER_TWO"/> 分钟</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 天前</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
-<translation id="7814458197256864873">复制(&amp;C)</translation>
-<translation id="3889424535448813030">向右箭头</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
-<translation id="2544782972264605588">还有 <ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="6829324100069873704">返回通知</translation>
-<translation id="6528179044667508675">请勿打扰</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">允许以下来源的通知:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
-<translation id="1398853756734560583">最大化</translation>
-<translation id="4250229828105606438">屏幕截图</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
-<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">全选(&amp;A)</translation>
-<translation id="2168039046890040389">向上翻页</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 天</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分钟</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
-<translation id="4927753642311223124">这里没有任何通知,往前走吧。</translation>
-<translation id="2482878487686419369">通知</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">滚动到此处</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
-<translation id="8394908167088220973">媒体播放/暂停</translation>
-<translation id="2148716181193084225">今天</translation>
-<translation id="7960078400008666149">1 小时内请勿打扰</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分钟前</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
-<translation id="2190355936436201913">(空)</translation>
-<translation id="1164369517022005061">还有 <ph name="NUMBER_DEFAULT"/> 小时</translation>
-<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec left</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">向右滚动</translation>
-<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hour left</translation>
-<translation id="1413622004203049571">停用来自“<ph name="NOTIFIER_NAME"/>”的通知</translation>
-<translation id="2666092431469916601">顶部</translation>
-<translation id="8331626408530291785">向上滚动</translation>
-<translation id="7907591526440419938">打开文件</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 小时前</translation>
-<translation id="815598010540052116">向下滚动</translation>
-<translation id="6808150112686056157">媒体停止</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">恢复</translation>
-<translation id="1243314992276662751">上传</translation>
-<translation id="50030952220075532"><ph name="NUMBER_ONE"/> day left</translation>
-<translation id="8179976553408161302">进入</translation>
-<translation id="945522503751344254">发送反馈</translation>
-<translation id="9170848237812810038">撤消(&amp;U)</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 小时前</translation>
-<translation id="6918245111648057970">对于每位用户,允许接收下列源发出的通知:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="3994835489895548312">还剩 <ph name="NUMBER_MANY"/> 分钟</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">设置...</translation>
-<translation id="6845383723252244143">选择文件夹</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
-<translation id="5583640892426849032">退格</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 天前</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hour</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分钟前</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> day</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
-<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
-<translation id="4570886800634958009">展开通知</translation>
-<translation id="436869212180315161">按</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分钟</translation>
-<translation id="1858722859751911017">还剩 <ph name="NUMBER_FEW"/> 分钟</translation>
-<translation id="6040143037577758943">关闭</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分钟前</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
-<translation id="7649070708921625228">帮助</translation>
-<translation id="6699343763173986273">媒体下一曲</translation>
-<translation id="8226233771743600312">1 天内请勿打扰</translation>
-<translation id="7457942297256758195">全部清除</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 天前</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
-<translation id="1963692530539281474">还有 <ph name="NUMBER_DEFAULT"/> 天</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分钟</translation>
-<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 小时前</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secs</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
-<translation id="2743387203779672305">复制到剪贴板</translation>
-<translation id="8371695176452482769">请开始说话</translation>
-<translation id="6965382102122355670">确定</translation>
-<translation id="7850320739366109486">请勿打扰</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">最小化</translation>
-<translation id="6394627529324717982">逗号</translation>
-<translation id="3036649622769666520">打开文件</translation>
-<translation id="8328145009876646418">左边缘</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/strings/ui_strings_zh-TW.xtb b/chromium/ui/base/strings/ui_strings_zh-TW.xtb
deleted file mode 100644
index 8ff676ec383..00000000000
--- a/chromium/ui/base/strings/ui_strings_zh-TW.xtb
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE translationbundle>
-<translationbundle lang="zh-TW">
-<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/> 鍵</translation>
-<translation id="1871244248791675517">Ins</translation>
-<translation id="6135826906199951471">Del</translation>
-<translation id="528468243742722775">結束</translation>
-<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 小時前</translation>
-<translation id="6310545596129886942">剩下 <ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="9213479837033539041">剩下 <ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="1209866192426315618">剩下 <ph name="NUMBER_DEFAULT"/> 分鐘</translation>
-<translation id="1801827354178857021">句號</translation>
-<translation id="1190609913194133056">通知中心</translation>
-<translation id="7470933019269157899">剩下 <ph name="NUMBER_DEFAULT"/> 分鐘</translation>
-<translation id="5613020302032141669">向左鍵</translation>
-<translation id="4971687151119236543">上一首媒體曲目</translation>
-<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 檔案 (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
-<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
-<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> 秒</translation>
-<translation id="7511635910912978956">剩下 <ph name="NUMBER_FEW"/> 小時</translation>
-<translation id="8717309436826820190">還有 <ph name="NUMBER_OF_NOTIFICATIONS"/> 個來自 <ph name="SOURCE_OF_NOTIFICATIONS"/> 的通知</translation>
-<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7658239707568436148">取消</translation>
-<translation id="7222373446505536781">F11</translation>
-<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
-<translation id="3660179305079774227">向上鍵</translation>
-<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/秒</translation>
-<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 小時</translation>
-<translation id="3990502903496589789">右邊緣</translation>
-<translation id="9038489124413477075">未命名的資料夾</translation>
-<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分鐘</translation>
-<translation id="3520476450377425184">剩下 <ph name="NUMBER_MANY"/> 天</translation>
-<translation id="932327136139879170">首頁</translation>
-<translation id="5600907569873192868">剩下 <ph name="NUMBER_MANY"/> 分鐘</translation>
-<translation id="8666066831007952346">剩下 <ph name="NUMBER_TWO"/> 天</translation>
-<translation id="6390842777729054533">剩下 <ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="3909791450649380159">剪下(&amp;T)</translation>
-<translation id="2560788951337264832">剩下 <ph name="NUMBER_ZERO"/> 分鐘</translation>
-<translation id="688711909580084195">無標題網頁</translation>
-<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 天前</translation>
-<translation id="5076340679995252485">貼上(&amp;P)</translation>
-<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
-<translation id="364720409959344976">選取要上傳的資料夾</translation>
-<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分鐘前</translation>
-<translation id="3234408098842461169">向下鍵</translation>
-<translation id="3087734570205094154">置底</translation>
-<translation id="5935630983280450497">剩下 <ph name="NUMBER_ONE"/> 分鐘</translation>
-<translation id="1860796786778352021">通知關閉</translation>
-<translation id="6364916375976753737">向左捲動</translation>
-<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 小時前</translation>
-<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分鐘</translation>
-<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分鐘前</translation>
-<translation id="6945221475159498467">選取</translation>
-<translation id="6620110761915583480">儲存檔案</translation>
-<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
-<translation id="7836361698254323868">剩下 <ph name="NUMBER_ONE"/> 分鐘</translation>
-<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> 分鐘</translation>
-<translation id="8210608804940886430">向下翻頁</translation>
-<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> 天</translation>
-<translation id="7163503212501929773">剩下 <ph name="NUMBER_MANY"/> 小時</translation>
-<translation id="5329858601952122676">刪除(&amp;D)</translation>
-<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
-<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分鐘</translation>
-<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
-<translation id="7781829728241885113">昨天</translation>
-<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分鐘</translation>
-<translation id="50960180632766478">剩下 <ph name="NUMBER_FEW"/> 分鐘</translation>
-<translation id="6659594942844771486">Tab</translation>
-<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
-<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 天前</translation>
-<translation id="8428213095426709021">設定</translation>
-<translation id="2497284189126895209">所有檔案</translation>
-<translation id="7487278341251176613">剩下 <ph name="NUMBER_TWO"/> 分鐘</translation>
-<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 天前</translation>
-<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="7814458197256864873">複製(&amp;C)</translation>
-<translation id="3889424535448813030">向右鍵</translation>
-<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
-<translation id="2544782972264605588">剩下 <ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="6829324100069873704">返回通知</translation>
-<translation id="6528179044667508675">請勿打擾</translation>
-<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="290555789621781773"><ph name="NUMBER_TWO"/> 分鐘</translation>
-<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
-<translation id="7135556860107312402">允許接收下列來源發出的通知:</translation>
-<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> 小時</translation>
-<translation id="1398853756734560583">放到最大</translation>
-<translation id="4250229828105606438">螢幕擷取畫面</translation>
-<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> 小時</translation>
-<translation id="5260878308685146029">剩下 <ph name="NUMBER_TWO"/> 分鐘</translation>
-<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
-<translation id="1901303067676059328">選取全部(&amp;A)</translation>
-<translation id="2168039046890040389">向上翻頁</translation>
-<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
-<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 天</translation>
-<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> 分鐘</translation>
-<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分鐘</translation>
-<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
-<translation id="4927753642311223124">這裡沒有任何通知訊息,以後再來看看吧!</translation>
-<translation id="2482878487686419369">通知</translation>
-<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
-<translation id="3183922693828471536">捲動至此</translation>
-<translation id="4552416320897244156">PgDwn</translation>
-<translation id="7052633198403197513">F1 鍵</translation>
-<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> 小時</translation>
-<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/秒</translation>
-<translation id="8394908167088220973">媒體播放/暫停</translation>
-<translation id="2148716181193084225">今天</translation>
-<translation id="7960078400008666149">1 小時內請勿打擾</translation>
-<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分鐘前</translation>
-<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> 天</translation>
-<translation id="2190355936436201913">(空白)</translation>
-<translation id="1164369517022005061">剩下 <ph name="NUMBER_DEFAULT"/> 小時</translation>
-<translation id="152482086482215392">剩下 <ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">向右捲動</translation>
-<translation id="7414887922320653780">剩下 <ph name="NUMBER_ONE"/> 小時</translation>
-<translation id="1413622004203049571">停用「<ph name="NOTIFIER_NAME"/>」的通知</translation>
-<translation id="2666092431469916601">置頂</translation>
-<translation id="8331626408530291785">向上捲動</translation>
-<translation id="7907591526440419938">開啟檔案</translation>
-<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
-<translation id="1293699935367580298">Esc</translation>
-<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 小時前</translation>
-<translation id="815598010540052116">向下捲動</translation>
-<translation id="6808150112686056157">停止媒體播放</translation>
-<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
-<translation id="3157931365184549694">還原</translation>
-<translation id="1243314992276662751">上傳</translation>
-<translation id="50030952220075532">剩下 <ph name="NUMBER_ONE"/> 天</translation>
-<translation id="8179976553408161302">進入</translation>
-<translation id="945522503751344254">提供意見</translation>
-<translation id="9170848237812810038">取消(&amp;U)</translation>
-<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 小時前</translation>
-<translation id="6918245111648057970">允許接收下列使用者發出的通知:</translation>
-<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
-<translation id="3994835489895548312">剩下 <ph name="NUMBER_MANY"/> 分鐘</translation>
-<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
-<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
-<translation id="2983818520079887040">設定...</translation>
-<translation id="6845383723252244143">選取資料夾</translation>
-<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> 秒</translation>
-<translation id="5583640892426849032">Backspace 鍵</translation>
-<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 天前</translation>
-<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> 天</translation>
-<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> 小時</translation>
-<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分鐘前</translation>
-<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
-<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/秒</translation>
-<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> 天</translation>
-<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
-<translation id="494645311413743213">剩下 <ph name="NUMBER_TWO"/> 秒</translation>
-<translation id="4570886800634958009">通知展開</translation>
-<translation id="436869212180315161">按下</translation>
-<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
-<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/秒</translation>
-<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分鐘</translation>
-<translation id="1858722859751911017">剩下 <ph name="NUMBER_FEW"/> 分鐘</translation>
-<translation id="6040143037577758943">關閉</translation>
-<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分鐘前</translation>
-<translation id="6142413573757616983"><ph name="QUANTITY"/> B/秒</translation>
-<translation id="7649070708921625228">說明</translation>
-<translation id="6699343763173986273">下一首媒體曲目</translation>
-<translation id="8226233771743600312">1 天內請勿打擾</translation>
-<translation id="7457942297256758195">全部清除</translation>
-<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 天前</translation>
-<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> 分鐘</translation>
-<translation id="1963692530539281474">剩下 <ph name="NUMBER_DEFAULT"/> 天</translation>
-<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分鐘</translation>
-<translation id="5906719743126878045">剩下 <ph name="NUMBER_TWO"/> 小時</translation>
-<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 小時前</translation>
-<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
-<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> 秒</translation>
-<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> 秒</translation>
-<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
-<translation id="3759876923365568382">剩下 <ph name="NUMBER_FEW"/> 天</translation>
-<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/秒</translation>
-<translation id="2743387203779672305">複製到剪貼簿</translation>
-<translation id="8371695176452482769">請說話</translation>
-<translation id="6965382102122355670">確定</translation>
-<translation id="7850320739366109486">請勿打擾</translation>
-<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
-<translation id="5941711191222866238">縮到最小</translation>
-<translation id="6394627529324717982">逗號</translation>
-<translation id="3036649622769666520">開啟檔案</translation>
-<translation id="8328145009876646418">左邊緣</translation>
-<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
-</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/base/text/bytes_formatting.h b/chromium/ui/base/text/bytes_formatting.h
index 0e818183385..46de51c7549 100644
--- a/chromium/ui/base/text/bytes_formatting.h
+++ b/chromium/ui/base/text/bytes_formatting.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -16,12 +16,12 @@ namespace ui {
// Simple call to return a byte quantity as a string in human-readable format.
// Ex: FormatBytes(512) => "512 B"
// Ex: FormatBytes(101479) => "99.1 kB"
-UI_EXPORT base::string16 FormatBytes(int64 bytes);
+UI_BASE_EXPORT base::string16 FormatBytes(int64 bytes);
// Simple call to return a speed as a string in human-readable format.
// Ex: FormatSpeed(512) => "512 B/s"
// Ex: FormatSpeed(101479) => "99.1 kB/s"
-UI_EXPORT base::string16 FormatSpeed(int64 bytes);
+UI_BASE_EXPORT base::string16 FormatSpeed(int64 bytes);
// Less-Simple API -------------------------------------------------------------
@@ -37,15 +37,15 @@ enum DataUnits {
// Return the unit type that is appropriate for displaying the amount of bytes
// passed in. Most of the time, an explicit call to this isn't necessary; just
// use FormatBytes()/FormatSpeed() above.
-UI_EXPORT DataUnits GetByteDisplayUnits(int64 bytes);
+UI_BASE_EXPORT DataUnits GetByteDisplayUnits(int64 bytes);
// Return a byte quantity as a string in human-readable format with an optional
// unit suffix. Specify in the |units| argument the units to be used.
// Ex: FormatBytes(512, DATA_UNITS_KIBIBYTE, true) => "0.5 kB"
// Ex: FormatBytes(10*1024, DATA_UNITS_MEBIBYTE, false) => "0.1"
-UI_EXPORT base::string16 FormatBytesWithUnits(int64 bytes,
- DataUnits units,
- bool show_units);
+UI_BASE_EXPORT base::string16 FormatBytesWithUnits(int64 bytes,
+ DataUnits units,
+ bool show_units);
// As above, but with "/s" units for speed values.
// Ex: FormatSpeed(512, DATA_UNITS_KIBIBYTE, true) => "0.5 kB/s"
diff --git a/chromium/ui/base/text/bytes_formatting_unittest.cc b/chromium/ui/base/text/bytes_formatting_unittest.cc
index 357abc756a5..b2a03f97e9a 100644
--- a/chromium/ui/base/text/bytes_formatting_unittest.cc
+++ b/chromium/ui/base/text/bytes_formatting_unittest.cc
@@ -69,9 +69,9 @@ TEST(BytesFormattingTest, FormatBytes) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(ASCIIToUTF16(cases[i].expected),
+ EXPECT_EQ(base::ASCIIToUTF16(cases[i].expected),
FormatBytesWithUnits(cases[i].bytes, cases[i].units, false));
- EXPECT_EQ(ASCIIToUTF16(cases[i].expected_with_units),
+ EXPECT_EQ(base::ASCIIToUTF16(cases[i].expected_with_units),
FormatBytesWithUnits(cases[i].bytes, cases[i].units, true));
}
}
diff --git a/chromium/ui/base/theme_provider.h b/chromium/ui/base/theme_provider.h
index d12e2656235..defdf145370 100644
--- a/chromium/ui/base/theme_provider.h
+++ b/chromium/ui/base/theme_provider.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/layout.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#if defined(OS_MACOSX)
#ifdef __OBJC__
@@ -20,9 +20,6 @@ class NSColor;
class NSGradient;
class NSImage;
#endif // __OBJC__
-#elif !defined(OS_WIN)
-typedef struct _GdkColor GdkColor;
-typedef struct _GdkPixbuf GdkPixbuf;
#endif // OS_*
class SkBitmap;
@@ -46,10 +43,14 @@ namespace ui {
//
////////////////////////////////////////////////////////////////////////////////
-class UI_EXPORT ThemeProvider {
+class UI_BASE_EXPORT ThemeProvider {
public:
virtual ~ThemeProvider();
+ // Whether we're using the system theme (which may or may not be the
+ // same as the default theme).
+ virtual bool UsingSystemTheme() const = 0;
+
// Get the image specified by |id|. An implementation of ThemeProvider should
// have its own source of ids (e.g. an enum, or external resource bundle).
virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const = 0;
@@ -92,18 +93,6 @@ class UI_EXPORT ThemeProvider {
// Gets the NSGradient with the specified |id|.
virtual NSGradient* GetNSGradient(int id) const = 0;
-#elif defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)
- // Gets the GdkPixbuf with the specified |id|. Returns a pointer to a shared
- // instance of the GdkPixbuf. This shared GdkPixbuf is owned by the theme
- // provider and should not be freed.
- //
- // The bitmap is assumed to exist. This function will log in release, and
- // assert in debug mode if it does not. On failure, this will return a
- // pointer to a shared empty placeholder bitmap so it will be visible what
- // is missing.
-
- // As above, but flips it in RTL locales.
- virtual GdkPixbuf* GetRTLEnabledPixbufNamed(int id) const = 0;
#endif
};
diff --git a/chromium/ui/base/touch/touch_device.h b/chromium/ui/base/touch/touch_device.h
index b06c56462e6..fd75ebcc9c6 100644
--- a/chromium/ui/base/touch/touch_device.h
+++ b/chromium/ui/base/touch/touch_device.h
@@ -5,17 +5,17 @@
#ifndef UI_BASE_TOUCH_TOUCH_DEVICE_H_
#define UI_BASE_TOUCH_TOUCH_DEVICE_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
+
+#if defined(OS_ANDROID)
+#include <jni.h>
+#endif
-namespace ui {
-// TODO(sblom): This is non-standard, and should be removed before
-// RuntimeEnabledFlags::PointerEventsMaxTouchPoints is marked stable.
-// Tracked by: http://crbug.com/308649
-const int kMaxTouchPointsUnknown = -1;
+namespace ui {
// Returns true if a touch device is available.
-UI_EXPORT bool IsTouchDevicePresent();
+UI_BASE_EXPORT bool IsTouchDevicePresent();
// Returns the maximum number of simultaneous touch contacts supported
// by the device. In the case of devices with multiple digitizers (e.g.
@@ -24,7 +24,11 @@ UI_EXPORT bool IsTouchDevicePresent();
// For example, suppose a device has 3 touchscreens, which support 2, 5,
// and 10 simultaneous touch contacts, respectively. This returns 10.
// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints
-UI_EXPORT int MaxTouchPoints();
+UI_BASE_EXPORT int MaxTouchPoints();
+
+#if defined(OS_ANDROID)
+bool RegisterTouchDeviceAndroid(JNIEnv* env);
+#endif
} // namespace ui
diff --git a/chromium/ui/base/touch/touch_device_android.cc b/chromium/ui/base/touch/touch_device_android.cc
index 2b359c0e3dd..604306c8bb3 100644
--- a/chromium/ui/base/touch/touch_device_android.cc
+++ b/chromium/ui/base/touch/touch_device_android.cc
@@ -4,23 +4,23 @@
#include "ui/base/touch/touch_device.h"
+#include "jni/TouchDevice_jni.h"
+
namespace ui {
bool IsTouchDevicePresent() {
return true;
}
-// Looks like the best we can do here is detect 1, 2+, or 5+ by
-// feature detecting:
-// FEATURE_TOUCHSCREEN (1),
-// FEATURE_TOUCHSCREEN_MULTITOUCH (2),
-// FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT (2+), or
-// FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHANDS (5+)
-//
-// Probably start from the biggest and detect down the list until we
-// find one that's supported and return its value.
int MaxTouchPoints() {
- return kMaxTouchPointsUnknown;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ jobject context = base::android::GetApplicationContext();
+ jint max_touch_points = Java_TouchDevice_maxTouchPoints(env, context);
+ return static_cast<int>(max_touch_points);
+}
+
+bool RegisterTouchDeviceAndroid(JNIEnv* env) {
+ return RegisterNativesImpl(env);
}
} // namespace ui
diff --git a/chromium/ui/base/touch/touch_editing_controller.h b/chromium/ui/base/touch/touch_editing_controller.h
index 2c94f0a7534..9c0298efd10 100644
--- a/chromium/ui/base/touch/touch_editing_controller.h
+++ b/chromium/ui/base/touch/touch_editing_controller.h
@@ -13,8 +13,11 @@ namespace ui {
// An interface implemented by widget that has text that can be selected/edited
// using touch.
-class UI_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate {
+class UI_BASE_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate {
public:
+ // TODO(mohsen): Consider switching from local coordinates to screen
+ // coordinates in this interface and see if it will simplify things.
+
// Select everything between start and end (points are in view's local
// coordinate system). |start| is the logical start and |end| is the logical
// end of selection. Visually, |start| may lie after |end|.
@@ -24,7 +27,8 @@ class UI_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate {
virtual void MoveCaretTo(const gfx::Point& point) = 0;
// Gets the end points of the current selection. The end points p1 and p2 must
- // be the cursor rect for the start and end of selection:
+ // be the cursor rect for the start and end of selection (in local
+ // coordinates):
// ____________________________________
// | textfield with |selected text| |
// ------------------------------------
@@ -34,11 +38,11 @@ class UI_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate {
// visually, p1 could be to the right of p2 in the figure above.
virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) = 0;
- // Gets the bounds of the client view in parent's coordinates.
+ // Gets the bounds of the client view in its local coordinates.
virtual gfx::Rect GetBounds() = 0;
// Gets the NativeView hosting the client.
- virtual gfx::NativeView GetNativeView() = 0;
+ virtual gfx::NativeView GetNativeView() const = 0;
// Converts a point to/from screen coordinates from/to client view.
virtual void ConvertPointToScreen(gfx::Point* point) = 0;
@@ -51,13 +55,17 @@ class UI_EXPORT TouchEditable : public ui::SimpleMenuModel::Delegate {
// Tells the editable to open context menu.
virtual void OpenContextMenu(const gfx::Point& anchor) = 0;
+ // Tells the editable to end touch editing and destroy touch selection
+ // controller it owns.
+ virtual void DestroyTouchSelection() = 0;
+
protected:
virtual ~TouchEditable() {}
};
// This defines the callback interface for other code to be notified of changes
// in the state of a TouchEditable.
-class UI_EXPORT TouchSelectionController {
+class UI_BASE_EXPORT TouchSelectionController {
public:
virtual ~TouchSelectionController() {}
@@ -70,9 +78,13 @@ class UI_EXPORT TouchSelectionController {
// Returns true if the user is currently dragging one of the handles.
virtual bool IsHandleDragInProgress() = 0;
+
+ // Hides visible handles. According to the value of |quick|, handles might
+ // fade out quickly or slowly.
+ virtual void HideHandles(bool quick) = 0;
};
-class UI_EXPORT TouchSelectionControllerFactory {
+class UI_BASE_EXPORT TouchSelectionControllerFactory {
public:
static void SetInstance(TouchSelectionControllerFactory* instance);
diff --git a/chromium/ui/base/touch/touch_enabled.h b/chromium/ui/base/touch/touch_enabled.h
index 4155674ddb6..88837d7856c 100644
--- a/chromium/ui/base/touch/touch_enabled.h
+++ b/chromium/ui/base/touch/touch_enabled.h
@@ -5,13 +5,13 @@
#ifndef UI_BASE_TOUCH_TOUCH_ENABLED_H_
#define UI_BASE_TOUCH_TOUCH_ENABLED_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Returns true if the touch-enabled flag is enabled, or if it is set to auto
// and a touch device is present.
-UI_EXPORT bool AreTouchEventsEnabled();
+UI_BASE_EXPORT bool AreTouchEventsEnabled();
} // namespace ui
diff --git a/chromium/ui/base/ui_base.gyp b/chromium/ui/base/ui_base.gyp
new file mode 100644
index 00000000000..e5ddcd77aea
--- /dev/null
+++ b/chromium/ui/base/ui_base.gyp
@@ -0,0 +1,644 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ui_base',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:base_i18n',
+ '../../base/base.gyp:base_static',
+ '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../../net/net.gyp:net',
+ '../../skia/skia.gyp:skia',
+ '../../third_party/icu/icu.gyp:icui18n',
+ '../../third_party/icu/icu.gyp:icuuc',
+ '../../url/url.gyp:url_lib',
+ '../events/events.gyp:events_base',
+ '../events/platform/events_platform.gyp:events_platform',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../resources/ui_resources.gyp:ui_resources',
+ '../strings/ui_strings.gyp:ui_strings',
+ ],
+ 'defines': [
+ 'UI_BASE_IMPLEMENTATION',
+ ],
+ 'export_dependent_settings': [
+ '../../net/net.gyp:net',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'sources' : [
+ 'accelerators/accelerator.cc',
+ 'accelerators/accelerator.h',
+ 'accelerators/accelerator_manager.cc',
+ 'accelerators/accelerator_manager.h',
+ 'accelerators/menu_label_accelerator_util_linux.cc',
+ 'accelerators/menu_label_accelerator_util_linux.h',
+ 'accelerators/platform_accelerator.h',
+ 'accelerators/platform_accelerator_cocoa.h',
+ 'accelerators/platform_accelerator_cocoa.mm',
+ 'android/ui_base_jni_registrar.cc',
+ 'android/ui_base_jni_registrar.h',
+ 'android/view_android.cc',
+ 'android/view_android.h',
+ 'android/window_android.cc',
+ 'android/window_android.h',
+ 'android/window_android_compositor.h',
+ 'android/window_android_observer.h',
+ 'base_window.cc',
+ 'base_window.h',
+ 'clipboard/clipboard.cc',
+ 'clipboard/clipboard.h',
+ 'clipboard/clipboard_android.cc',
+ 'clipboard/clipboard_android_initialization.h',
+ 'clipboard/clipboard_aura.cc',
+ 'clipboard/clipboard_aurax11.cc',
+ 'clipboard/clipboard_constants.cc',
+ 'clipboard/clipboard_mac.mm',
+ 'clipboard/clipboard_types.h',
+ 'clipboard/clipboard_util_win.cc',
+ 'clipboard/clipboard_util_win.h',
+ 'clipboard/clipboard_win.cc',
+ 'clipboard/custom_data_helper.cc',
+ 'clipboard/custom_data_helper.h',
+ 'clipboard/custom_data_helper_linux.cc',
+ 'clipboard/custom_data_helper_mac.mm',
+ 'clipboard/scoped_clipboard_writer.cc',
+ 'clipboard/scoped_clipboard_writer.h',
+ 'cocoa/animation_utils.h',
+ 'cocoa/appkit_utils.h',
+ 'cocoa/appkit_utils.mm',
+ 'cocoa/base_view.h',
+ 'cocoa/base_view.mm',
+ 'cocoa/cocoa_base_utils.h',
+ 'cocoa/cocoa_base_utils.mm',
+ 'cocoa/controls/blue_label_button.h',
+ 'cocoa/controls/blue_label_button.mm',
+ 'cocoa/controls/hover_image_menu_button.h',
+ 'cocoa/controls/hover_image_menu_button.mm',
+ 'cocoa/controls/hover_image_menu_button_cell.h',
+ 'cocoa/controls/hover_image_menu_button_cell.mm',
+ 'cocoa/controls/hyperlink_button_cell.h',
+ 'cocoa/controls/hyperlink_button_cell.mm',
+ 'cocoa/find_pasteboard.h',
+ 'cocoa/find_pasteboard.mm',
+ 'cocoa/flipped_view.h',
+ 'cocoa/flipped_view.mm',
+ 'cocoa/focus_tracker.h',
+ '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',
+ 'cocoa/hover_image_button.mm',
+ 'cocoa/menu_controller.h',
+ 'cocoa/menu_controller.mm',
+ 'cocoa/nib_loading.h',
+ 'cocoa/nib_loading.mm',
+ 'cocoa/nsgraphics_context_additions.h',
+ 'cocoa/nsgraphics_context_additions.mm',
+ 'cocoa/tracking_area.h',
+ 'cocoa/tracking_area.mm',
+ 'cocoa/underlay_opengl_hosting_window.h',
+ 'cocoa/underlay_opengl_hosting_window.mm',
+ 'cocoa/view_description.h',
+ 'cocoa/view_description.mm',
+ 'cocoa/window_size_constants.h',
+ 'cocoa/window_size_constants.mm',
+ 'cursor/cursor.cc',
+ 'cursor/cursor.h',
+ 'cursor/cursor_android.cc',
+ 'cursor/cursor_loader.h',
+ 'cursor/cursor_loader_ozone.cc',
+ 'cursor/cursor_loader_ozone.h',
+ 'cursor/cursor_loader_win.cc',
+ 'cursor/cursor_loader_win.h',
+ 'cursor/cursor_loader_x11.cc',
+ 'cursor/cursor_loader_x11.h',
+ 'cursor/cursor_ozone.cc',
+ 'cursor/cursor_util.cc',
+ 'cursor/cursor_util.h',
+ 'cursor/cursor_win.cc',
+ 'cursor/cursor_x11.cc',
+ 'cursor/cursors_aura.cc',
+ 'cursor/cursors_aura.h',
+ 'cursor/image_cursors.cc',
+ 'cursor/image_cursors.h',
+ 'cursor/ozone/bitmap_cursor_factory_ozone.cc',
+ 'cursor/ozone/bitmap_cursor_factory_ozone.h',
+ 'default_theme_provider.cc',
+ 'default_theme_provider.h',
+ 'default_theme_provider_mac.mm',
+ 'device_form_factor_android.cc',
+ 'device_form_factor_android.h',
+ 'device_form_factor_desktop.cc',
+ 'device_form_factor_ios.mm',
+ 'device_form_factor.h',
+ 'dragdrop/cocoa_dnd_util.h',
+ 'dragdrop/cocoa_dnd_util.mm',
+ 'dragdrop/drag_drop_types.h',
+ 'dragdrop/drag_drop_types_win.cc',
+ 'dragdrop/drag_source_win.cc',
+ 'dragdrop/drag_source_win.h',
+ 'dragdrop/drag_utils.cc',
+ 'dragdrop/drag_utils.h',
+ 'dragdrop/drag_utils_aura.cc',
+ 'dragdrop/drag_utils_mac.mm',
+ 'dragdrop/drag_utils_win.cc',
+ 'dragdrop/drop_target_event.cc',
+ 'dragdrop/drop_target_event.h',
+ 'dragdrop/drop_target_win.cc',
+ 'dragdrop/drop_target_win.h',
+ 'dragdrop/file_info.cc',
+ 'dragdrop/file_info.h',
+ 'dragdrop/os_exchange_data.cc',
+ 'dragdrop/os_exchange_data.h',
+ 'dragdrop/os_exchange_data_provider_aura.cc',
+ 'dragdrop/os_exchange_data_provider_aura.h',
+ 'dragdrop/os_exchange_data_provider_aurax11.cc',
+ 'dragdrop/os_exchange_data_provider_aurax11.h',
+ 'dragdrop/os_exchange_data_provider_mac.h',
+ 'dragdrop/os_exchange_data_provider_mac.mm',
+ 'dragdrop/os_exchange_data_provider_win.cc',
+ 'dragdrop/os_exchange_data_provider_win.h',
+ 'hit_test.h',
+ 'l10n/formatter.cc',
+ 'l10n/formatter.h',
+ 'l10n/l10n_font_util.cc',
+ 'l10n/l10n_font_util.h',
+ 'l10n/l10n_util.cc',
+ 'l10n/l10n_util.h',
+ 'l10n/l10n_util_android.cc',
+ 'l10n/l10n_util_android.h',
+ 'l10n/l10n_util_collator.h',
+ 'l10n/l10n_util_mac.h',
+ 'l10n/l10n_util_mac.mm',
+ 'l10n/l10n_util_plurals.cc',
+ 'l10n/l10n_util_plurals.h',
+ 'l10n/l10n_util_posix.cc',
+ 'l10n/l10n_util_win.cc',
+ 'l10n/l10n_util_win.h',
+ 'l10n/time_format.cc',
+ 'l10n/time_format.h',
+ 'layout.cc',
+ 'layout.h',
+ 'layout_mac.mm',
+ 'models/button_menu_item_model.cc',
+ 'models/button_menu_item_model.h',
+ 'models/combobox_model.cc',
+ 'models/combobox_model.h',
+ 'models/combobox_model_observer.h',
+ 'models/dialog_model.cc',
+ 'models/dialog_model.h',
+ 'models/list_model.h',
+ 'models/list_model_observer.h',
+ 'models/list_selection_model.cc',
+ 'models/list_selection_model.h',
+ 'models/menu_model.cc',
+ 'models/menu_model.h',
+ 'models/menu_model_delegate.h',
+ 'models/menu_separator_types.h',
+ 'models/simple_combobox_model.cc',
+ 'models/simple_combobox_model.h',
+ 'models/simple_menu_model.cc',
+ 'models/simple_menu_model.h',
+ 'models/table_model.cc',
+ 'models/table_model.h',
+ 'models/table_model_observer.h',
+ 'models/tree_model.cc',
+ 'models/tree_model.h',
+ 'models/tree_node_iterator.h',
+ 'models/tree_node_model.h',
+ 'nine_image_painter_factory.cc',
+ 'nine_image_painter_factory.h',
+ 'resource/data_pack.cc',
+ 'resource/data_pack.h',
+ 'resource/resource_bundle.cc',
+ 'resource/resource_bundle.h',
+ 'resource/resource_bundle_android.cc',
+ 'resource/resource_bundle_auralinux.cc',
+ 'resource/resource_bundle_ios.mm',
+ 'resource/resource_bundle_mac.mm',
+ 'resource/resource_bundle_win.cc',
+ 'resource/resource_bundle_win.h',
+ 'resource/resource_data_dll_win.cc',
+ 'resource/resource_data_dll_win.h',
+ 'resource/resource_handle.h',
+ 'text/bytes_formatting.cc',
+ 'text/bytes_formatting.h',
+ 'theme_provider.cc',
+ 'theme_provider.h',
+ 'touch/touch_device.cc',
+ 'touch/touch_device.h',
+ 'touch/touch_device_android.cc',
+ 'touch/touch_device_aurax11.cc',
+ 'touch/touch_device_ozone.cc',
+ 'touch/touch_device_win.cc',
+ 'touch/touch_editing_controller.cc',
+ 'touch/touch_editing_controller.h',
+ 'touch/touch_enabled.cc',
+ 'touch/touch_enabled.h',
+ 'ui_base_export.h',
+ 'ui_base_exports.cc',
+ 'ui_base_paths.cc',
+ 'ui_base_paths.h',
+ 'ui_base_switches.cc',
+ 'ui_base_switches.h',
+ 'ui_base_switches_util.cc',
+ 'ui_base_switches_util.h',
+ 'ui_base_types.cc',
+ 'ui_base_types.h',
+ 'view_prop.cc',
+ 'view_prop.h',
+ 'webui/jstemplate_builder.cc',
+ 'webui/jstemplate_builder.h',
+ 'webui/web_ui_util.cc',
+ 'webui/web_ui_util.h',
+ 'win/accessibility_ids_win.h',
+ 'win/accessibility_misc_utils.cc',
+ 'win/accessibility_misc_utils.h',
+ 'win/atl_module.h',
+ 'win/dpi_setup.cc',
+ 'win/dpi_setup.h',
+ 'win/foreground_helper.cc',
+ 'win/foreground_helper.h',
+ 'win/hidden_window.cc',
+ 'win/hidden_window.h',
+ 'win/hwnd_subclass.cc',
+ 'win/hwnd_subclass.h',
+ 'win/internal_constants.cc',
+ 'win/internal_constants.h',
+ 'win/lock_state.cc',
+ 'win/lock_state.h',
+ 'win/message_box_win.cc',
+ 'win/message_box_win.h',
+ 'win/mouse_wheel_util.cc',
+ 'win/mouse_wheel_util.h',
+ 'win/scoped_ole_initializer.cc',
+ 'win/scoped_ole_initializer.h',
+ 'win/shell.cc',
+ 'win/shell.h',
+ 'win/touch_input.cc',
+ 'win/touch_input.h',
+ 'win/window_event_target.cc',
+ 'win/window_event_target.h',
+ 'window_open_disposition.cc',
+ 'window_open_disposition.h',
+ 'work_area_watcher_observer.h',
+ 'x/selection_owner.cc',
+ 'x/selection_owner.h',
+ 'x/selection_requestor.cc',
+ 'x/selection_requestor.h',
+ 'x/selection_utils.cc',
+ 'x/selection_utils.h',
+ 'x/x11_menu_list.cc',
+ 'x/x11_menu_list.h',
+ 'x/x11_util.cc',
+ 'x/x11_util.h',
+ 'x/x11_util_internal.h',
+ ],
+ 'target_conditions': [
+ ['OS == "ios"', {
+ 'sources/': [
+ ['include', '^l10n/l10n_util_mac\\.mm$'],
+ ],
+ }],
+ ],
+ 'conditions': [
+ ['OS!="ios"', {
+ 'includes': [
+ 'ime/ime.gypi',
+ ],
+ }, { # OS=="ios"
+ # iOS only uses a subset of UI.
+ 'sources/': [
+ ['exclude', '\\.(cc|mm)$'],
+ ['include', '_ios\\.(cc|mm)$'],
+ ['include', '(^|/)ios/'],
+ ['include', '^l10n/'],
+ ['include', '^layout'],
+ ['include', '^resource/'],
+ ['include', '^ui_base_'],
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+ ],
+ },
+ }],
+ ['toolkit_views==1', {
+ 'dependencies': [
+ '../events/events.gyp:events',
+ ],
+ }],
+ ['use_aura==1', {
+ 'sources/': [
+ ['exclude', 'clipboard/clipboard_mac.mm'],
+ ['exclude', 'layout_mac.mm'],
+ ['exclude', 'work_area_watcher_observer.h'],
+ ],
+ 'dependencies': [
+ '../events/events.gyp:events',
+ ],
+ }, { # use_aura!=1
+ 'sources!': [
+ 'cursor/cursor.cc',
+ 'cursor/cursor.h',
+ 'cursor/cursor_loader_x11.cc',
+ 'cursor/cursor_loader_x11.h',
+ 'cursor/cursor_win.cc',
+ 'cursor/cursor_x11.cc',
+ 'x/selection_owner.cc',
+ 'x/selection_owner.h',
+ 'x/selection_requestor.cc',
+ 'x/selection_requestor.h',
+ 'x/selection_utils.cc',
+ 'x/selection_utils.h',
+ ]
+ }],
+ ['use_aura==0 or OS!="linux"', {
+ 'sources!': [
+ 'resource/resource_bundle_auralinux.cc',
+ ],
+ }],
+ ['use_ozone==1', {
+ 'dependencies': [
+ '../ozone/ozone.gyp:ozone_base',
+ ],
+ }],
+ ['use_aura==1 and OS=="win"', {
+ 'sources/': [
+ ['exclude', 'dragdrop/drag_utils_aura.cc'],
+ ],
+ }],
+ ['use_glib == 1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:fontconfig',
+ '../../build/linux/system.gyp:glib',
+ ],
+ }],
+ ['desktop_linux == 1 or chromeos == 1', {
+ 'conditions': [
+ ['toolkit_views==0 and use_aura==0', {
+ # Note: because of gyp predence rules this has to be defined as
+ # 'sources/' rather than 'sources!'.
+ 'sources/': [
+ ['exclude', '^dragdrop/drag_utils.cc'],
+ ['exclude', '^dragdrop/drag_utils.h'],
+ ],
+ }, {
+ 'sources/': [
+ ['include', '^dragdrop/os_exchange_data.cc'],
+ ['include', '^dragdrop/os_exchange_data.h'],
+ ['include', '^nine_image_painter_factory.cc'],
+ ['include', '^nine_image_painter_factory.h'],
+ ],
+ }],
+ ],
+ }],
+ ['use_pango==1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:pangocairo',
+ ],
+ }],
+ ['OS=="win" or use_clipboard_aurax11==1', {
+ 'sources!': [
+ 'clipboard/clipboard_aura.cc',
+ ],
+ }, {
+ 'sources!': [
+ 'clipboard/clipboard_aurax11.cc',
+ ],
+ }],
+ ['chromeos==1 or (use_aura==1 and OS=="linux" and use_x11==0)', {
+ 'sources!': [
+ 'dragdrop/os_exchange_data_provider_aurax11.cc',
+ 'touch/touch_device.cc',
+ ],
+ }, {
+ 'sources!': [
+ 'dragdrop/os_exchange_data_provider_aura.cc',
+ 'dragdrop/os_exchange_data_provider_aura.h',
+ 'touch/touch_device_aurax11.cc',
+ ],
+ }],
+ ['OS=="win"', {
+ 'sources!': [
+ 'touch/touch_device.cc',
+ ],
+ 'include_dirs': [
+ '../..',
+ '../../third_party/wtl/include',
+ ],
+ # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int
+ # C4324 is structure was padded due to __declspec(align()), which is
+ # uninteresting.
+ 'msvs_disabled_warnings': [ 4267, 4324 ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'DelayLoadDLLs': [
+ 'd2d1.dll',
+ 'd3d10_1.dll',
+ 'dwmapi.dll',
+ ],
+ 'AdditionalDependencies': [
+ 'd2d1.lib',
+ 'd3d10_1.lib',
+ 'dwmapi.lib',
+ ],
+ },
+ },
+ 'link_settings': {
+ 'libraries': [
+ '-limm32.lib',
+ '-ld2d1.lib',
+ '-ldwmapi.lib',
+ '-loleacc.lib',
+ ],
+ },
+ },{ # OS!="win"
+ 'conditions': [
+ ['use_aura==0', {
+ 'sources!': [
+ 'view_prop.cc',
+ 'view_prop.h',
+ ],
+ }],
+ ],
+ }],
+ ['OS=="mac"', {
+ 'dependencies': [
+ '../../third_party/mozilla/mozilla.gyp:mozilla',
+ ],
+ 'sources!': [
+ 'cursor/image_cursors.cc',
+ 'cursor/image_cursors.h',
+ 'dragdrop/drag_utils.cc',
+ 'dragdrop/drag_utils.h',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Accelerate.framework',
+ '$(SDKROOT)/System/Library/Frameworks/AudioUnit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
+ ],
+ },
+ }],
+ ['use_x11==1', {
+ 'all_dependent_settings': {
+ 'ldflags': [
+ '-L<(PRODUCT_DIR)',
+ ],
+ },
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:xcursor',
+ '../../build/linux/system.gyp:xext',
+ '../../build/linux/system.gyp:xfixes',
+ '../../build/linux/system.gyp:xrender', # For XRender* function calls in x11_util.cc.
+ '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
+ ],
+ }],
+ ['toolkit_views==0', {
+ 'sources!': [
+ 'dragdrop/drag_drop_types.h',
+ 'dragdrop/drop_target_event.cc',
+ 'dragdrop/drop_target_event.h',
+ 'dragdrop/os_exchange_data.cc',
+ 'dragdrop/os_exchange_data.h',
+ 'nine_image_painter_factory.cc',
+ 'nine_image_painter_factory.h',
+ ],
+ }],
+ ['OS=="android"', {
+ 'sources!': [
+ 'cursor/image_cursors.cc',
+ 'cursor/image_cursors.h',
+ 'default_theme_provider.cc',
+ 'dragdrop/drag_utils.cc',
+ 'dragdrop/drag_utils.h',
+ 'l10n/l10n_font_util.cc',
+ 'models/button_menu_item_model.cc',
+ 'models/dialog_model.cc',
+ 'theme_provider.cc',
+ 'touch/touch_device.cc',
+ 'touch/touch_editing_controller.cc',
+ 'ui_base_types.cc',
+ ],
+ 'dependencies': [
+ 'ui_base_jni_headers',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-ljnigraphics',
+ ],
+ },
+ }],
+ ['OS=="android" and android_webview_build==0', {
+ 'dependencies': [
+ '../android/ui_android.gyp:ui_java',
+ ],
+ }],
+ ['OS=="android" and use_aura==0', {
+ 'sources!': [
+ 'cursor/cursor_android.cc'
+ ],
+ }],
+ ['OS=="android" and use_aura==1', {
+ 'sources!': [
+ 'clipboard/clipboard_aura.cc'
+ ],
+ }],
+ ['OS=="android" or OS=="ios"', {
+ 'sources!': [
+ 'device_form_factor_desktop.cc'
+ ],
+ }],
+ ['OS=="linux"', {
+ 'libraries': [
+ '-ldl',
+ ],
+ }],
+ ['use_system_icu==1', {
+ # When using the system icu, the icu targets generate shim headers
+ # which are included by public headers in the ui target, so we need
+ # ui to be a hard dependency for all its users.
+ 'hard_dependency': 1,
+ }],
+ ],
+ },
+ {
+ 'target_name': 'ui_base_test_support',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'sources': [
+ 'test/ui_controls.h',
+ 'test/ui_controls_aura.cc',
+ 'test/ui_controls_internal_win.cc',
+ 'test/ui_controls_internal_win.h',
+ 'test/ui_controls_mac.mm',
+ 'test/ui_controls_win.cc',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'conditions': [
+ ['OS!="ios"', {
+ 'type': 'static_library',
+ 'includes': [ 'ime/ime_test_support.gypi' ],
+ }, { # OS=="ios"
+ # None of the sources in this target are built on iOS, resulting in
+ # link errors when building targets that depend on this target
+ # because the static library isn't found. If this target is changed
+ # to have sources that are built on iOS, the target should be changed
+ # to be of type static_library on all platforms.
+ 'type': 'none',
+ }],
+ ['use_aura==1', {
+ 'sources!': [
+ 'test/ui_controls_mac.mm',
+ 'test/ui_controls_win.cc',
+ ],
+ }],
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="android"' , {
+ 'targets': [
+ {
+ 'target_name': 'ui_base_jni_headers',
+ 'type': 'none',
+ 'sources': [
+ '../android/java/src/org/chromium/ui/base/Clipboard.java',
+ '../android/java/src/org/chromium/ui/base/DeviceFormFactor.java',
+ '../android/java/src/org/chromium/ui/base/LocalizationUtils.java',
+ '../android/java/src/org/chromium/ui/base/SelectFileDialog.java',
+ '../android/java/src/org/chromium/ui/base/TouchDevice.java',
+ '../android/java/src/org/chromium/ui/base/ViewAndroid.java',
+ '../android/java/src/org/chromium/ui/base/WindowAndroid.java',
+ ],
+ 'variables': {
+ 'jni_gen_package': 'ui',
+ },
+ 'includes': [ '../../build/jni_generator.gypi' ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/ui/base/ui_base_export.h b/chromium/ui/base/ui_base_export.h
new file mode 100644
index 00000000000..dba9b898029
--- /dev/null
+++ b/chromium/ui/base/ui_base_export.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_UI_BASE_EXPORT_H_
+#define UI_BASE_UI_BASE_EXPORT_H_
+
+// Defines UI_BASE_EXPORT so that functionality implemented by the UI module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(UI_BASE_IMPLEMENTATION)
+#define UI_BASE_EXPORT __declspec(dllexport)
+#else
+#define UI_BASE_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(UI_BASE_IMPLEMENTATION)
+#define UI_BASE_EXPORT __attribute__((visibility("default")))
+#else
+#define UI_BASE_EXPORT
+#endif
+
+#endif
+
+#else // !defined(COMPONENT_BUILD)
+
+#define UI_BASE_EXPORT
+
+#endif
+
+#endif // UI_BASE_UI_BASE_EXPORT_H_
diff --git a/chromium/ui/base/ui_base_paths.cc b/chromium/ui/base/ui_base_paths.cc
index ee7566ef438..4cdf7c18e1d 100644
--- a/chromium/ui/base/ui_base_paths.cc
+++ b/chromium/ui/base/ui_base_paths.cc
@@ -23,7 +23,7 @@ bool PathProvider(int key, base::FilePath* result) {
base::FilePath cur;
switch (key) {
- case ui::DIR_LOCALES:
+ case DIR_LOCALES:
if (!PathService::Get(base::DIR_MODULE, &cur))
return false;
#if defined(OS_MACOSX)
@@ -32,7 +32,7 @@ bool PathProvider(int key, base::FilePath* result) {
cur = cur.DirName();
cur = cur.Append(FILE_PATH_LITERAL("Resources"));
#elif defined(OS_ANDROID)
- if (!PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &cur))
+ if (!PathService::Get(DIR_RESOURCE_PAKS_ANDROID, &cur))
return false;
#else
cur = cur.Append(FILE_PATH_LITERAL("locales"));
@@ -42,22 +42,28 @@ bool PathProvider(int key, base::FilePath* result) {
// The following are only valid in the development environment, and
// will fail if executed from an installed executable (because the
// generated path won't exist).
- case ui::DIR_TEST_DATA:
+ case UI_DIR_TEST_DATA:
if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
return false;
- cur = cur.Append(FILE_PATH_LITERAL("app"));
+ cur = cur.Append(FILE_PATH_LITERAL("ui"));
+ cur = cur.Append(FILE_PATH_LITERAL("base"));
cur = cur.Append(FILE_PATH_LITERAL("test"));
cur = cur.Append(FILE_PATH_LITERAL("data"));
if (!base::PathExists(cur)) // we don't want to create this
return false;
break;
#if defined(OS_ANDROID)
- case ui::DIR_RESOURCE_PAKS_ANDROID:
+ case DIR_RESOURCE_PAKS_ANDROID:
if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &cur))
return false;
cur = cur.Append(FILE_PATH_LITERAL("paks"));
break;
#endif
+ case UI_TEST_PAK:
+ if (!PathService::Get(base::DIR_MODULE, &cur))
+ return false;
+ cur = cur.AppendASCII("ui_test.pak");
+ break;
default:
return false;
}
diff --git a/chromium/ui/base/ui_base_paths.h b/chromium/ui/base/ui_base_paths.h
index 2b61723493a..cf5e0041e6f 100644
--- a/chromium/ui/base/ui_base_paths.h
+++ b/chromium/ui/base/ui_base_paths.h
@@ -6,10 +6,10 @@
#define UI_BASE_UI_BASE_PATHS_H_
#include "build/build_config.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
-// This file declares path keys for the app module. These can be used with
-// the PathService to access various special directories and files.
+// This file declares path keys for various special directories. These can be
+// used with the PathService to access these directories and files.
namespace ui {
@@ -19,17 +19,19 @@ enum {
DIR_LOCALES, // Directory where locale resources are stored.
// Valid only in development environment; TODO(darin): move this
- DIR_TEST_DATA, // Directory where unit test data resides.
+ UI_DIR_TEST_DATA, // Directory where unit test data resides.
#if defined(OS_ANDROID)
DIR_RESOURCE_PAKS_ANDROID,
#endif
+ UI_TEST_PAK,
+
PATH_END
};
// Call once to register the provider for the path keys defined above.
-UI_EXPORT void RegisterPathProvider();
+UI_BASE_EXPORT void RegisterPathProvider();
} // namespace ui
diff --git a/chromium/ui/base/ui_base_switches.cc b/chromium/ui/base/ui_base_switches.cc
index 8adac9966e2..9bacd0a71c2 100644
--- a/chromium/ui/base/ui_base_switches.cc
+++ b/chromium/ui/base/ui_base_switches.cc
@@ -6,9 +6,17 @@
namespace switches {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Disable use of CoreAnimation to draw on the Mac.
+const char kDisableCoreAnimation[] = "disable-core-animation";
+#endif
+
// Disables use of DWM composition for top level windows.
const char kDisableDwmComposition[] = "disable-dwm-composition";
+// Disables an experimental focus manager to track text input clients.
+const char kDisableTextInputFocusManager[] = "disable-text-input-focus-manager";
+
// Disables touch adjustment.
const char kDisableTouchAdjustment[] = "disable-touch-adjustment";
@@ -18,57 +26,21 @@ const char kDisableTouchDragDrop[] = "disable-touch-drag-drop";
// Disables controls that support touch base text editing.
const char kDisableTouchEditing[] = "disable-touch-editing";
+// Enables an experimental focus manager to track text input clients.
+const char kEnableTextInputFocusManager[] = "enable-text-input-focus-manager";
+
// Enables touch event based drag and drop.
const char kEnableTouchDragDrop[] = "enable-touch-drag-drop";
// Enables controls that support touch base text editing.
const char kEnableTouchEditing[] = "enable-touch-editing";
-// If a resource is requested at a scale factor at which it is not available
-// or the resource is the incorrect size (based on the size of the 1x resource),
-// generates the missing resource and applies a red mask to the generated
-// resource. Resources for which hidpi is not supported because of software
-// reasons will show up pixelated.
-const char kHighlightMissingScaledResources[] =
- "highlight-missing-scaled-resources";
-
// The language file that we want to try to open. Of the form
// language[-country] where language is the 2 letter code from ISO-639.
const char kLang[] = "lang";
-// Load the locale resources from the given path. When running on Mac/Unix the
-// path should point to a locale.pak file.
-const char kLocalePak[] = "locale_pak";
-
// Disable ui::MessageBox. This is useful when running as part of scripts that
// do not have a user interface.
const char kNoMessageBox[] = "no-message-box";
-// Enables UI changes that make it easier to use with a touchscreen.
-// WARNING: Do not check this flag directly when deciding what UI to draw,
-// instead you must call ui::GetDisplayLayout
-const char kTouchOptimizedUI[] = "touch-optimized-ui";
-
-// The values the kTouchOptimizedUI switch may have, as in
-// "--touch-optimized-ui=disabled".
-// auto: Enabled on monitors which have touchscreen support (default).
-const char kTouchOptimizedUIAuto[] = "auto";
-// enabled: always optimized for touch (even if no touch support).
-const char kTouchOptimizedUIEnabled[] = "enabled";
-// disabled: never optimized for touch.
-const char kTouchOptimizedUIDisabled[] = "disabled";
-
-// Enables touch events on the side bezels.
-const char kTouchSideBezels[] = "touch-side-bezels";
-
-#if defined(OS_ANDROID)
-// Uses the tablet specific UI components when available.
-const char kTabletUI[] = "tablet-ui";
-#endif
-
-#if defined(USE_XI2_MT)
-// The calibration factors given as "<left>,<right>,<top>,<bottom>".
-const char kTouchCalibration[] = "touch-calibration";
-#endif
-
} // namespace switches
diff --git a/chromium/ui/base/ui_base_switches.h b/chromium/ui/base/ui_base_switches.h
index 4e1b7e028f3..b638ae85a96 100644
--- a/chromium/ui/base/ui_base_switches.h
+++ b/chromium/ui/base/ui_base_switches.h
@@ -8,33 +8,24 @@
#define UI_BASE_UI_BASE_SWITCHES_H_
#include "base/compiler_specific.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace switches {
-UI_EXPORT extern const char kDisableDwmComposition[];
-UI_EXPORT extern const char kDisableTouchAdjustment[];
-UI_EXPORT extern const char kDisableTouchDragDrop[];
-UI_EXPORT extern const char kDisableTouchEditing[];
-UI_EXPORT extern const char kEnableTouchDragDrop[];
-UI_EXPORT extern const char kEnableTouchEditing[];
-UI_EXPORT extern const char kHighlightMissingScaledResources[];
-UI_EXPORT extern const char kLang[];
-UI_EXPORT extern const char kLocalePak[];
-UI_EXPORT extern const char kNoMessageBox[];
-UI_EXPORT extern const char kTouchOptimizedUI[];
-UI_EXPORT extern const char kTouchOptimizedUIAuto[];
-UI_EXPORT extern const char kTouchOptimizedUIDisabled[];
-UI_EXPORT extern const char kTouchOptimizedUIEnabled[];
-UI_EXPORT extern const char kTouchSideBezels[];
-
-#if defined(OS_ANDROID)
-UI_EXPORT extern const char kTabletUI[];
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+UI_BASE_EXPORT extern const char kDisableCoreAnimation[];
#endif
-#if defined(USE_XI2_MT)
-UI_EXPORT extern const char kTouchCalibration[];
-#endif
+UI_BASE_EXPORT extern const char kDisableDwmComposition[];
+UI_BASE_EXPORT extern const char kDisableTextInputFocusManager[];
+UI_BASE_EXPORT extern const char kDisableTouchAdjustment[];
+UI_BASE_EXPORT extern const char kDisableTouchDragDrop[];
+UI_BASE_EXPORT extern const char kDisableTouchEditing[];
+UI_BASE_EXPORT extern const char kEnableTextInputFocusManager[];
+UI_BASE_EXPORT extern const char kEnableTouchDragDrop[];
+UI_BASE_EXPORT extern const char kEnableTouchEditing[];
+UI_BASE_EXPORT extern const char kLang[];
+UI_BASE_EXPORT extern const char kNoMessageBox[];
} // namespace switches
diff --git a/chromium/ui/base/ui_base_switches_util.cc b/chromium/ui/base/ui_base_switches_util.cc
index 3089607af86..ba20e53f7fa 100644
--- a/chromium/ui/base/ui_base_switches_util.cc
+++ b/chromium/ui/base/ui_base_switches_util.cc
@@ -9,6 +9,11 @@
namespace switches {
+bool IsTextInputFocusManagerEnabled() {
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTextInputFocusManager);
+}
+
bool IsTouchDragDropEnabled() {
#if defined(OS_CHROMEOS)
return !CommandLine::ForCurrentProcess()->HasSwitch(
@@ -20,7 +25,7 @@ bool IsTouchDragDropEnabled() {
}
bool IsTouchEditingEnabled() {
-#if defined(OS_CHROMEOS)
+#if defined(USE_AURA)
return !CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTouchEditing);
#else
diff --git a/chromium/ui/base/ui_base_switches_util.h b/chromium/ui/base/ui_base_switches_util.h
index c64da8f6e3c..8dbc408f377 100644
--- a/chromium/ui/base/ui_base_switches_util.h
+++ b/chromium/ui/base/ui_base_switches_util.h
@@ -5,13 +5,13 @@
#ifndef UI_BASE_UI_BASE_SWITCHES_UTIL_H_
#define UI_BASE_UI_BASE_SWITCHES_UTIL_H_
-#include "base/compiler_specific.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace switches {
-UI_EXPORT bool IsTouchDragDropEnabled();
-UI_EXPORT bool IsTouchEditingEnabled();
+UI_BASE_EXPORT bool IsTextInputFocusManagerEnabled();
+UI_BASE_EXPORT bool IsTouchDragDropEnabled();
+UI_BASE_EXPORT bool IsTouchEditingEnabled();
} // namespace switches
diff --git a/chromium/ui/base/ui_base_types.h b/chromium/ui/base/ui_base_types.h
index 3b8ee9c7a52..fc4ed95bab1 100644
--- a/chromium/ui/base/ui_base_types.h
+++ b/chromium/ui/base/ui_base_types.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_UI_BASE_TYPES_H_
#define UI_BASE_UI_BASE_TYPES_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -48,9 +48,10 @@ enum MenuSourceType {
MENU_SOURCE_KEYBOARD = 2,
MENU_SOURCE_TOUCH = 3,
MENU_SOURCE_TOUCH_EDIT_MENU = 4,
+ MENU_SOURCE_TYPE_LAST = MENU_SOURCE_TOUCH_EDIT_MENU
};
-UI_EXPORT MenuSourceType GetMenuSourceTypeForEvent(const ui::Event& event);
+UI_BASE_EXPORT MenuSourceType GetMenuSourceTypeForEvent(const ui::Event& event);
} // namespace ui
diff --git a/chromium/ui/base/ui_export.h b/chromium/ui/base/ui_export.h
deleted file mode 100644
index ba05e33ec60..00000000000
--- a/chromium/ui/base/ui_export.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_UI_EXPORT_H_
-#define UI_UI_EXPORT_H_
-
-// Defines UI_EXPORT so that functionality implemented by the UI module can be
-// exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(UI_IMPLEMENTATION)
-#define UI_EXPORT __declspec(dllexport)
-#else
-#define UI_EXPORT __declspec(dllimport)
-#endif // defined(UI_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(UI_IMPLEMENTATION)
-#define UI_EXPORT __attribute__((visibility("default")))
-#else
-#define UI_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define UI_EXPORT
-#endif
-
-#endif // UI_UI_EXPORT_H_
diff --git a/chromium/ui/base/view_prop.h b/chromium/ui/base/view_prop.h
index eae6792b845..3ce14ba5d95 100644
--- a/chromium/ui/base/view_prop.h
+++ b/chromium/ui/base/view_prop.h
@@ -7,10 +7,10 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/native_widget_types.h"
-#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(USE_AURA))
+#if !defined(OS_WIN) && !defined(USE_AURA)
#error view_prop.h is only for windows and aura builds.
#endif
@@ -20,7 +20,7 @@ namespace ui {
// designed as a replacement for the Win32's SetProp, but does not make use of
// window manager memory. ViewProp shares similar semantics as SetProp, the
// value for a particular view/key pair comes from the last ViewProp created.
-class UI_EXPORT ViewProp {
+class UI_BASE_EXPORT ViewProp {
public:
// Associates data with a view/key pair. If a ViewProp has already been
// created for the specified pair |data| replaces the current value.
diff --git a/chromium/ui/base/webui/jstemplate_builder.h b/chromium/ui/base/webui/jstemplate_builder.h
index 66b265a0476..1ad15c36392 100644
--- a/chromium/ui/base/webui/jstemplate_builder.h
+++ b/chromium/ui/base/webui/jstemplate_builder.h
@@ -16,7 +16,7 @@
#include <string>
#include "base/strings/string_piece.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace base {
class DictionaryValue;
@@ -27,7 +27,7 @@ namespace webui {
// While an object of this class is in scope, the template builder will output
// version 2 html. Version 2 uses load_time_data.js and i18n_template2.js, and
// should soon become the default.
-class UI_EXPORT UseVersion2 {
+class UI_BASE_EXPORT UseVersion2 {
public:
UseVersion2();
~UseVersion2();
@@ -39,52 +39,55 @@ class UI_EXPORT UseVersion2 {
// A helper function that generates a string of HTML to be loaded. The
// string includes the HTML and the javascript code necessary to generate the
// full page with support for JsTemplates.
-UI_EXPORT std::string GetTemplateHtml(const base::StringPiece& html_template,
- const base::DictionaryValue* json,
- const base::StringPiece& template_id);
+UI_BASE_EXPORT std::string GetTemplateHtml(
+ const base::StringPiece& html_template,
+ const base::DictionaryValue* json,
+ const base::StringPiece& template_id);
// A helper function that generates a string of HTML to be loaded. The
// string includes the HTML and the javascript code necessary to generate the
// full page with support for i18n Templates.
-UI_EXPORT std::string GetI18nTemplateHtml(
+UI_BASE_EXPORT std::string GetI18nTemplateHtml(
const base::StringPiece& html_template,
const base::DictionaryValue* json);
// A helper function that generates a string of HTML to be loaded. The
// string includes the HTML and the javascript code necessary to generate the
// full page with support for both i18n Templates and JsTemplates.
-UI_EXPORT std::string GetTemplatesHtml(const base::StringPiece& html_template,
- const base::DictionaryValue* json,
- const base::StringPiece& template_id);
+UI_BASE_EXPORT std::string GetTemplatesHtml(
+ const base::StringPiece& html_template,
+ const base::DictionaryValue* json,
+ const base::StringPiece& template_id);
// The following functions build up the different parts that the above
// templates use.
// Appends a script tag with a variable name |templateData| that has the JSON
// assigned to it.
-UI_EXPORT void AppendJsonHtml(const base::DictionaryValue* json,
- std::string* output);
+UI_BASE_EXPORT void AppendJsonHtml(const base::DictionaryValue* json,
+ std::string* output);
// Same as AppendJsonHtml(), except does not include the <script></script>
// tag wrappers.
-UI_EXPORT void AppendJsonJS(const base::DictionaryValue* json,
- std::string* output);
+UI_BASE_EXPORT void AppendJsonJS(const base::DictionaryValue* json,
+ std::string* output);
// Appends the source for JsTemplates in a script tag.
-UI_EXPORT void AppendJsTemplateSourceHtml(std::string* output);
+UI_BASE_EXPORT void AppendJsTemplateSourceHtml(std::string* output);
// Appends the code that processes the JsTemplate with the JSON. You should
// call AppendJsTemplateSourceHtml and AppendJsonHtml before calling this.
-UI_EXPORT void AppendJsTemplateProcessHtml(const base::StringPiece& template_id,
- std::string* output);
+UI_BASE_EXPORT void AppendJsTemplateProcessHtml(
+ const base::StringPiece& template_id,
+ std::string* output);
// Appends the source for i18n Templates in a script tag.
-UI_EXPORT void AppendI18nTemplateSourceHtml(std::string* output);
+UI_BASE_EXPORT void AppendI18nTemplateSourceHtml(std::string* output);
// Appends the code that processes the i18n Template with the JSON. You
// should call AppendJsTemplateSourceHtml and AppendJsonHtml before calling
// this.
-UI_EXPORT void AppendI18nTemplateProcessHtml(std::string* output);
+UI_BASE_EXPORT void AppendI18nTemplateProcessHtml(std::string* output);
} // namespace webui
diff --git a/chromium/ui/base/webui/web_ui_util.cc b/chromium/ui/base/webui/web_ui_util.cc
index d901491300b..e2f1786069f 100644
--- a/chromium/ui/base/webui/web_ui_util.cc
+++ b/chromium/ui/base/webui/web_ui_util.cc
@@ -76,8 +76,8 @@ WindowOpenDisposition GetDispositionFromClick(const base::ListValue* args,
}
bool ParseScaleFactor(const base::StringPiece& identifier,
- ui::ScaleFactor* scale_factor) {
- *scale_factor = ui::SCALE_FACTOR_100P;
+ float* scale_factor) {
+ *scale_factor = 1.0f;
if (identifier.empty()) {
LOG(WARNING) << "Invalid scale factor format: " << identifier;
return false;
@@ -95,25 +95,24 @@ bool ParseScaleFactor(const base::StringPiece& identifier,
LOG(WARNING) << "Invalid scale factor format: " << identifier;
return false;
}
-
- *scale_factor = ui::GetSupportedScaleFactor(static_cast<float>(scale));
+ *scale_factor = scale;
return true;
}
void ParsePathAndScale(const GURL& url,
std::string* path,
- ui::ScaleFactor* scale_factor) {
+ float* scale_factor) {
*path = net::UnescapeURLComponent(url.path().substr(1),
(net::UnescapeRule::URL_SPECIAL_CHARS |
net::UnescapeRule::SPACES));
if (scale_factor)
- *scale_factor = ui::SCALE_FACTOR_100P;
+ *scale_factor = 1.0f;
// Detect and parse resource string ending in @<scale>x.
std::size_t pos = path->rfind('@');
if (pos != std::string::npos) {
base::StringPiece stripped_path(*path);
- ui::ScaleFactor factor;
+ float factor;
if (ParseScaleFactor(stripped_path.substr(
pos + 1, stripped_path.length() - pos - 1), &factor)) {
@@ -140,9 +139,9 @@ void SetFontAndTextDirection(base::DictionaryValue* localized_strings) {
std::string font_family = l10n_util::GetStringUTF8(web_font_family_id);
-#if defined(TOOLKIT_GTK)
- // Use the system font on Linux/GTK. Keep the hard-coded font families as
- // backup in case for some crazy reason this one isn't available.
+// TODO(dnicoara) Remove Ozone check when PlatformFont support is introduced
+// into Ozone: crbug.com/320050
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
font_family = ui::ResourceBundle::GetSharedInstance().GetFont(
ui::ResourceBundle::BaseFont).GetFontName() + ", " + font_family;
#endif
diff --git a/chromium/ui/base/webui/web_ui_util.h b/chromium/ui/base/webui/web_ui_util.h
index 72afec68543..85f5fd90043 100644
--- a/chromium/ui/base/webui/web_ui_util.h
+++ b/chromium/ui/base/webui/web_ui_util.h
@@ -9,8 +9,7 @@
#include "base/strings/string_piece.h"
#include "base/values.h"
-#include "ui/base/layout.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/base/window_open_disposition.h"
class GURL;
@@ -20,7 +19,7 @@ namespace webui {
// Convenience routine to convert SkBitmap object to data url
// so that it can be used in WebUI.
-UI_EXPORT std::string GetBitmapDataUrl(const SkBitmap& bitmap);
+UI_BASE_EXPORT std::string GetBitmapDataUrl(const SkBitmap& bitmap);
// Convenience routine to get data url that corresponds to given
// resource_id as a bitmap. This function does not check if the
@@ -28,31 +27,27 @@ UI_EXPORT std::string GetBitmapDataUrl(const SkBitmap& bitmap);
// caller's responsibility to make sure the resource is indeed a
// bitmap. Returns empty string if a resource does not exist for given
// |resource_id|.
-UI_EXPORT std::string GetBitmapDataUrlFromResource(int resource_id);
+UI_BASE_EXPORT std::string GetBitmapDataUrlFromResource(int resource_id);
// Extracts a disposition from click event arguments. |args| should contain
// an integer button and booleans alt key, ctrl key, meta key, and shift key
// (in that order), starting at |start_index|.
-UI_EXPORT WindowOpenDisposition GetDispositionFromClick(
- const base::ListValue* args,
- int start_index);
+UI_BASE_EXPORT WindowOpenDisposition
+ GetDispositionFromClick(const base::ListValue* args, int start_index);
-// Given a scale factor such as "1x", "2x" or "1.99x", sets |scale_factor| to
-// the closest ScaleFactor enum value for this scale factor. If string can not
-// be parsed, then |scale_factor| is set to SCALE_FACTOR_100P, and false is
-// returned.
-UI_EXPORT bool ParseScaleFactor(const base::StringPiece&identifier,
- ui::ScaleFactor* scale_factor);
+// Pares a formatted scale factor string into float and sets to |scale_factor|.
+UI_BASE_EXPORT bool ParseScaleFactor(const base::StringPiece& identifier,
+ float* scale_factor);
// Parses a URL containing some path @{scale}x. If it does not contain a scale
// factor then the default scale factor is returned.
-UI_EXPORT void ParsePathAndScale(const GURL& url,
- std::string* path,
- ui::ScaleFactor* scale_factor);
+UI_BASE_EXPORT void ParsePathAndScale(const GURL& url,
+ std::string* path,
+ float* scale_factor);
// Helper function to set the font family, size, and text direction into the
// given dictionary.
-UI_EXPORT void SetFontAndTextDirection(
+UI_BASE_EXPORT void SetFontAndTextDirection(
base::DictionaryValue* localized_strings);
} // namespace webui
diff --git a/chromium/ui/base/webui/web_ui_util_unittest.cc b/chromium/ui/base/webui/web_ui_util_unittest.cc
index 59ed4a5d21d..792895c9b24 100644
--- a/chromium/ui/base/webui/web_ui_util_unittest.cc
+++ b/chromium/ui/base/webui/web_ui_util_unittest.cc
@@ -8,48 +8,47 @@
#include "url/gurl.h"
TEST(WebUIUtilTest, ParsePathAndScale) {
- std::vector<ui::ScaleFactor> supported_scale_factors;
- supported_scale_factors.push_back(ui::SCALE_FACTOR_100P);
- supported_scale_factors.push_back(ui::SCALE_FACTOR_140P);
- supported_scale_factors.push_back(ui::SCALE_FACTOR_200P);
- ui::test::ScopedSetSupportedScaleFactors scoped_supported(
- supported_scale_factors);
-
std::string path;
- ui::ScaleFactor factor;
+ float factor = 0;
GURL url("http://some/random/username@email/and/more");
webui::ParsePathAndScale(url, &path, &factor);
EXPECT_EQ("random/username@email/and/more", path);
- EXPECT_EQ(ui::SCALE_FACTOR_100P, factor);
+ EXPECT_EQ(1.0f, factor);
+ factor = 0;
GURL url2("http://some/random/username/and/more");
webui::ParsePathAndScale(url2, &path, &factor);
EXPECT_EQ("random/username/and/more", path);
- EXPECT_EQ(ui::SCALE_FACTOR_100P, factor);
+ EXPECT_EQ(1.0f, factor);
+ factor = 0;
GURL url3("http://some/random/username/and/more@2ax");
webui::ParsePathAndScale(url3, &path, &factor);
EXPECT_EQ("random/username/and/more@2ax", path);
- EXPECT_EQ(ui::SCALE_FACTOR_100P, factor);
+ EXPECT_EQ(1.0f, factor);
+ factor = 0;
GURL url4("http://some/random/username/and/more@x");
webui::ParsePathAndScale(url4, &path, &factor);
EXPECT_EQ("random/username/and/more@x", path);
- EXPECT_EQ(ui::SCALE_FACTOR_100P, factor);
+ EXPECT_EQ(1.0f, factor);
+ factor = 0;
GURL url5("http://some/random/username@email/and/more@2x");
webui::ParsePathAndScale(url5, &path, &factor);
EXPECT_EQ("random/username@email/and/more", path);
- EXPECT_EQ(ui::SCALE_FACTOR_200P, factor);
+ EXPECT_EQ(2.0f, factor);
+ factor = 0;
GURL url6("http://some/random/username/and/more@1.4x");
webui::ParsePathAndScale(url6, &path, &factor);
EXPECT_EQ("random/username/and/more", path);
- EXPECT_EQ(ui::SCALE_FACTOR_140P, factor);
+ EXPECT_EQ(1.4f, factor);
+ factor = 0;
GURL url7("http://some/random/username/and/more@1.3x");
webui::ParsePathAndScale(url7, &path, &factor);
EXPECT_EQ("random/username/and/more", path);
- EXPECT_EQ(ui::SCALE_FACTOR_140P, factor);
+ EXPECT_EQ(1.3f, factor);
}
diff --git a/chromium/ui/base/win/accessibility_misc_utils.cc b/chromium/ui/base/win/accessibility_misc_utils.cc
index 5074ce372a7..621048ffcd8 100644
--- a/chromium/ui/base/win/accessibility_misc_utils.cc
+++ b/chromium/ui/base/win/accessibility_misc_utils.cc
@@ -14,7 +14,9 @@ UIATextProvider::UIATextProvider()
: editable_(false) {}
// static
-bool UIATextProvider::CreateTextProvider(bool editable, IUnknown** provider) {
+bool UIATextProvider::CreateTextProvider(const string16& value,
+ bool editable,
+ IUnknown** provider) {
// Make sure ATL is initialized in this module.
ui::win::CreateATLModuleIfNeeded();
@@ -23,6 +25,7 @@ bool UIATextProvider::CreateTextProvider(bool editable, IUnknown** provider) {
if (SUCCEEDED(hr)) {
DCHECK(text_provider);
text_provider->set_editable(editable);
+ text_provider->set_value(value);
text_provider->AddRef();
*provider = static_cast<ITextProvider*>(text_provider);
return true;
@@ -35,5 +38,10 @@ STDMETHODIMP UIATextProvider::get_IsReadOnly(BOOL* read_only) {
return S_OK;
}
+STDMETHODIMP UIATextProvider::get_Value(BSTR* value) {
+ *value = SysAllocString(value_.c_str());
+ return S_OK;
+}
+
} // namespace win
} // namespace base
diff --git a/chromium/ui/base/win/accessibility_misc_utils.h b/chromium/ui/base/win/accessibility_misc_utils.h
index 3789efb02b5..e17f1d3c6b0 100644
--- a/chromium/ui/base/win/accessibility_misc_utils.h
+++ b/chromium/ui/base/win/accessibility_misc_utils.h
@@ -9,13 +9,14 @@
#include <UIAutomationCore.h>
#include "base/compiler_specific.h"
-#include "ui/base/ui_export.h"
+#include "base/strings/string16.h"
+#include "ui/base/ui_base_export.h"
namespace base {
namespace win {
// UIA Text provider implementation for edit controls.
-class UI_EXPORT UIATextProvider
+class UI_BASE_EXPORT UIATextProvider
: public NON_EXPORTED_BASE(CComObjectRootEx<CComMultiThreadModel>),
public IValueProvider,
public ITextProvider {
@@ -30,12 +31,16 @@ class UI_EXPORT UIATextProvider
// Creates an instance of the UIATextProvider class.
// Returns true on success
- static bool CreateTextProvider(bool editable, IUnknown** provider);
+ static bool CreateTextProvider(const string16& value,
+ bool editable,
+ IUnknown** provider);
void set_editable(bool editable) {
editable_ = editable;
}
+ void set_value(const string16& value) { value_ = value; }
+
//
// IValueProvider methods.
//
@@ -48,9 +53,7 @@ class UI_EXPORT UIATextProvider
return E_NOTIMPL;
}
- STDMETHOD(get_Value)(BSTR* value) {
- return E_NOTIMPL;
- }
+ STDMETHOD(get_Value)(BSTR* value);
//
// ITextProvider methods.
@@ -83,6 +86,7 @@ class UI_EXPORT UIATextProvider
private:
bool editable_;
+ string16 value_;
};
} // win
diff --git a/chromium/ui/base/win/dpi_setup.cc b/chromium/ui/base/win/dpi_setup.cc
index ad4e6e8616e..423b788132a 100644
--- a/chromium/ui/base/win/dpi_setup.cc
+++ b/chromium/ui/base/win/dpi_setup.cc
@@ -4,6 +4,7 @@
#include "ui/base/win/dpi_setup.h"
+#include "base/command_line.h"
#include "ui/base/layout.h"
#include "ui/gfx/display.h"
#include "ui/gfx/win/dpi.h"
diff --git a/chromium/ui/base/win/dpi_setup.h b/chromium/ui/base/win/dpi_setup.h
index a88584996f0..5837153d9fd 100644
--- a/chromium/ui/base/win/dpi_setup.h
+++ b/chromium/ui/base/win/dpi_setup.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_WIN_DPI_SETUP_H_
#define UI_BASE_WIN_DPI_SETUP_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
namespace win {
@@ -14,7 +14,7 @@ namespace win {
// the best available scale based on the screen's pixel density. This can be
// affected (overridden) by --force-device-scale-factor=x
// This function can be called only once for the lifetime of a process.
-UI_EXPORT void InitDeviceScaleFactor();
+UI_BASE_EXPORT void InitDeviceScaleFactor();
} // namespace win
} // namespace ui
diff --git a/chromium/ui/base/win/foreground_helper.cc b/chromium/ui/base/win/foreground_helper.cc
index 219b26fc1fa..72830122ac0 100644
--- a/chromium/ui/base/win/foreground_helper.cc
+++ b/chromium/ui/base/win/foreground_helper.cc
@@ -43,7 +43,7 @@ HRESULT ForegroundHelper::ForegroundHotKey(HWND window) {
hotkey.type = INPUT_KEYBOARD;
hotkey.ki.wVk = VK_F22;
if (1 != SendInput(1, &hotkey, sizeof(hotkey))) {
- LOG(WARNING) << "Failed to send input";
+ LOG(WARNING) << "Failed to send input; GetLastError(): " << GetLastError();
return E_FAIL;
}
@@ -72,13 +72,9 @@ HRESULT ForegroundHelper::ForegroundHotKey(HWND window) {
return S_OK;
}
- // Handle the registered Hotkey being pressed.
-LRESULT ForegroundHelper::OnHotKey(UINT message,
- WPARAM wparam,
- LPARAM lparam,
- BOOL& handled) {
+// Handle the registered Hotkey being pressed.
+void ForegroundHelper::OnHotKey(int id, UINT vcode, UINT modifiers) {
SetForegroundWindow(window_);
- return 1;
}
} // namespace ui
diff --git a/chromium/ui/base/win/foreground_helper.h b/chromium/ui/base/win/foreground_helper.h
index a2d9ea2a541..8387c13b7ee 100644
--- a/chromium/ui/base/win/foreground_helper.h
+++ b/chromium/ui/base/win/foreground_helper.h
@@ -6,7 +6,7 @@
#define UI_BASE_WIN_FOREGROUND_HELPER_H_
#include "base/logging.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/win/window_impl.h"
namespace ui {
@@ -18,13 +18,13 @@ namespace ui {
// to be capable of moving to the foreground.
//
// This is probably leveraging a windows bug.
-class UI_EXPORT ForegroundHelper : public gfx::WindowImpl {
+class UI_BASE_EXPORT ForegroundHelper : public gfx::WindowImpl {
public:
ForegroundHelper() : window_(NULL) { }
- BEGIN_MSG_MAP_EX(ForegroundHelper)
- MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
- END_MSG_MAP()
+ CR_BEGIN_MSG_MAP_EX(ForegroundHelper)
+ CR_MSG_WM_HOTKEY(OnHotKey)
+ CR_END_MSG_MAP()
// Brings a window into the foreground.
// Can be called from any window, even if the caller is not the
@@ -35,7 +35,7 @@ class UI_EXPORT ForegroundHelper : public gfx::WindowImpl {
HRESULT ForegroundHotKey(HWND window);
// Handle the registered Hotkey being pressed.
- LRESULT OnHotKey(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ void OnHotKey(int id, UINT vcode, UINT modifiers);
HWND window_;
diff --git a/chromium/ui/base/win/hidden_window.cc b/chromium/ui/base/win/hidden_window.cc
index 3b21519597c..d04f2a3f7fa 100644
--- a/chromium/ui/base/win/hidden_window.cc
+++ b/chromium/ui/base/win/hidden_window.cc
@@ -42,9 +42,9 @@ class TempParent : public gfx::WindowImpl {
void OnClose() {
}
- BEGIN_MSG_MAP_EX(WebContentsViewWin)
- MSG_WM_CLOSE(OnClose)
- END_MSG_MAP()
+ CR_BEGIN_MSG_MAP_EX(WebContentsViewWin)
+ CR_MSG_WM_CLOSE(OnClose)
+ CR_END_MSG_MAP()
};
} // namespace
diff --git a/chromium/ui/base/win/hidden_window.h b/chromium/ui/base/win/hidden_window.h
index e3189a6a688..6cc2fd0dd6d 100644
--- a/chromium/ui/base/win/hidden_window.h
+++ b/chromium/ui/base/win/hidden_window.h
@@ -7,13 +7,13 @@
#include <windows.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Returns an HWND that can be used as a temporary parent. The returned HWND is
// never destroyed.
-UI_EXPORT HWND GetHiddenWindow();
+UI_BASE_EXPORT HWND GetHiddenWindow();
} // namespace ui
diff --git a/chromium/ui/base/win/hwnd_subclass.cc b/chromium/ui/base/win/hwnd_subclass.cc
index 34e2bf4fad6..8628a7c2e8b 100644
--- a/chromium/ui/base/win/hwnd_subclass.cc
+++ b/chromium/ui/base/win/hwnd_subclass.cc
@@ -142,11 +142,8 @@ LRESULT HWNDSubclass::OnWndProc(HWND hwnd,
if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1,
&point, sizeof(TOUCHINPUT))) {
- POINT touch_location = {
- TOUCH_COORD_TO_PIXEL(point.x) /
- gfx::win::GetUndocumentedDPITouchScale(),
- TOUCH_COORD_TO_PIXEL(point.y) /
- gfx::win::GetUndocumentedDPITouchScale()};
+ POINT touch_location = {TOUCH_COORD_TO_PIXEL(point.x),
+ TOUCH_COORD_TO_PIXEL(point.y)};
HWND actual_target = WindowFromPoint(touch_location);
if (actual_target != hwnd) {
return SendMessage(actual_target, message, w_param, l_param);
diff --git a/chromium/ui/base/win/hwnd_subclass.h b/chromium/ui/base/win/hwnd_subclass.h
index 834a45a376a..0a371cb2c8b 100644
--- a/chromium/ui/base/win/hwnd_subclass.h
+++ b/chromium/ui/base/win/hwnd_subclass.h
@@ -5,19 +5,19 @@
#ifndef UI_BASE_WIN_HWND_SUBCLASS_H_
#define UI_BASE_WIN_HWND_SUBCLASS_H_
-#include <vector>
#include <windows.h>
+#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/base/view_prop.h"
namespace ui {
// Classes implementing this interface get the opportunity to handle and consume
// messages before they are sent to their target HWND.
-class UI_EXPORT HWNDMessageFilter {
+class UI_BASE_EXPORT HWNDMessageFilter {
public:
virtual ~HWNDMessageFilter();
@@ -38,7 +38,7 @@ class UI_EXPORT HWNDMessageFilter {
// An object that instance-subclasses a window. If the window has already been
// instance-subclassed, that subclassing is lost.
-class UI_EXPORT HWNDSubclass {
+class UI_BASE_EXPORT HWNDSubclass {
public:
~HWNDSubclass();
diff --git a/chromium/ui/base/win/internal_constants.cc b/chromium/ui/base/win/internal_constants.cc
new file mode 100644
index 00000000000..325ab90468b
--- /dev/null
+++ b/chromium/ui/base/win/internal_constants.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/win/internal_constants.h"
+
+namespace ui {
+
+const wchar_t kIgnoreTouchMouseActivateForWindow[] =
+ L"Chrome.IgnoreMouseActivate";
+
+} // namespace ui
+
diff --git a/chromium/ui/base/win/internal_constants.h b/chromium/ui/base/win/internal_constants.h
new file mode 100644
index 00000000000..d81c34de4f1
--- /dev/null
+++ b/chromium/ui/base/win/internal_constants.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_INTERNAL_CONSTANTS_H_
+#define UI_BASE_WIN_INTERNAL_CONSTANTS_H_
+
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// This window property if set on the window does not activate the window for a
+// touch based WM_MOUSEACTIVATE message.
+UI_BASE_EXPORT extern const wchar_t kIgnoreTouchMouseActivateForWindow[];
+
+} // namespace ui
+
+#endif // UI_BASE_WIN_INTERNAL_CONSTANTS_H_
+
+
diff --git a/chromium/ui/base/win/lock_state.h b/chromium/ui/base/win/lock_state.h
index 637be034a50..be9c912678a 100644
--- a/chromium/ui/base/win/lock_state.h
+++ b/chromium/ui/base/win/lock_state.h
@@ -6,12 +6,12 @@
#define UI_BASE_WIN_LOCK_STATE_H_
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Returns true if the screen is currently locked.
-UI_EXPORT bool IsWorkstationLocked();
+UI_BASE_EXPORT bool IsWorkstationLocked();
} // namespace ui
diff --git a/chromium/ui/base/win/message_box_win.cc b/chromium/ui/base/win/message_box_win.cc
index c78e98baf66..6500f986163 100644
--- a/chromium/ui/base/win/message_box_win.cc
+++ b/chromium/ui/base/win/message_box_win.cc
@@ -14,8 +14,8 @@ namespace ui {
// RTL locale, we need to make sure that LTR strings are rendered correctly by
// adding the appropriate Unicode directionality marks.
int MessageBox(HWND hwnd,
- const string16& text,
- const string16& caption,
+ const base::string16& text,
+ const base::string16& caption,
UINT flags) {
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoMessageBox))
return IDOK;
@@ -24,11 +24,11 @@ int MessageBox(HWND hwnd,
if (base::i18n::IsRTL())
actual_flags |= MB_RIGHT | MB_RTLREADING;
- string16 localized_text = text;
+ base::string16 localized_text = text;
base::i18n::AdjustStringForLocaleDirection(&localized_text);
const wchar_t* text_ptr = localized_text.c_str();
- string16 localized_caption = caption;
+ base::string16 localized_caption = caption;
base::i18n::AdjustStringForLocaleDirection(&localized_caption);
const wchar_t* caption_ptr = localized_caption.c_str();
diff --git a/chromium/ui/base/win/message_box_win.h b/chromium/ui/base/win/message_box_win.h
index a91c00f7a37..f48bec3e4fa 100644
--- a/chromium/ui/base/win/message_box_win.h
+++ b/chromium/ui/base/win/message_box_win.h
@@ -8,7 +8,7 @@
#include <windows.h>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -16,10 +16,10 @@ namespace ui {
// MessageBox function allows us to control certain RTL locale flags so that
// callers don't have to worry about adding these flags when running in a
// right-to-left locale.
-UI_EXPORT int MessageBox(HWND hwnd,
- const string16& text,
- const string16& caption,
- UINT flags);
+UI_BASE_EXPORT int MessageBox(HWND hwnd,
+ const base::string16& text,
+ const base::string16& caption,
+ UINT flags);
} // namespace ui
diff --git a/chromium/ui/base/win/mouse_wheel_util.h b/chromium/ui/base/win/mouse_wheel_util.h
index d6266d7b3e6..b9f5872b0c4 100644
--- a/chromium/ui/base/win/mouse_wheel_util.h
+++ b/chromium/ui/base/win/mouse_wheel_util.h
@@ -7,7 +7,7 @@
#include <windows.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -17,7 +17,7 @@ class ViewProp;
// We reroute the mouse wheel messages to such HWND when they are under the
// mouse pointer (but are not the active window). Callers own the returned
// object.
-UI_EXPORT ViewProp* SetWindowSupportsRerouteMouseWheel(HWND hwnd);
+UI_BASE_EXPORT ViewProp* SetWindowSupportsRerouteMouseWheel(HWND hwnd);
// Forwards mouse wheel messages to the window under it.
// Windows sends mouse wheel messages to the currently active window.
@@ -26,8 +26,9 @@ UI_EXPORT ViewProp* SetWindowSupportsRerouteMouseWheel(HWND hwnd);
// mouse wheel in order to scroll that window. This is arguably a better user
// experience. The returns value says whether the mouse wheel message was
// successfully redirected.
-UI_EXPORT bool RerouteMouseWheel(HWND window, WPARAM w_param,
- LPARAM l_param);
+UI_BASE_EXPORT bool RerouteMouseWheel(HWND window,
+ WPARAM w_param,
+ LPARAM l_param);
} // namespace ui
diff --git a/chromium/ui/base/win/scoped_ole_initializer.h b/chromium/ui/base/win/scoped_ole_initializer.h
index 6b115f9a3ab..b2e81d22c41 100644
--- a/chromium/ui/base/win/scoped_ole_initializer.h
+++ b/chromium/ui/base/win/scoped_ole_initializer.h
@@ -8,11 +8,11 @@
#include <ole2.h>
#include "base/basictypes.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
-class UI_EXPORT ScopedOleInitializer {
+class UI_BASE_EXPORT ScopedOleInitializer {
public:
ScopedOleInitializer();
~ScopedOleInitializer();
diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc
index ff1a4ffec41..7866e713a88 100644
--- a/chromium/ui/base/win/shell.cc
+++ b/chromium/ui/base/win/shell.cc
@@ -24,7 +24,7 @@ namespace win {
// Show the Windows "Open With" dialog box to ask the user to pick an app to
// open the file with.
-bool OpenItemWithExternalApp(const string16& full_path) {
+bool OpenItemWithExternalApp(const base::string16& full_path) {
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.fMask = SEE_MASK_FLAG_DDEWAIT;
sei.nShow = SW_SHOWNORMAL;
@@ -33,9 +33,9 @@ bool OpenItemWithExternalApp(const string16& full_path) {
return (TRUE == ::ShellExecuteExW(&sei));
}
-bool OpenAnyViaShell(const string16& full_path,
- const string16& directory,
- const string16& args,
+bool OpenAnyViaShell(const base::string16& full_path,
+ const base::string16& directory,
+ const base::string16& args,
DWORD mask) {
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.fMask = mask;
@@ -54,11 +54,11 @@ bool OpenAnyViaShell(const string16& full_path,
bool OpenItemViaShell(const base::FilePath& full_path) {
return OpenAnyViaShell(full_path.value(), full_path.DirName().value(),
- string16(), 0);
+ base::string16(), 0);
}
bool OpenItemViaShellNoZoneCheck(const base::FilePath& full_path) {
- return OpenAnyViaShell(full_path.value(), string16(), string16(),
+ return OpenAnyViaShell(full_path.value(), base::string16(), base::string16(),
SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT);
}
@@ -80,10 +80,10 @@ bool PreventWindowFromPinning(HWND hwnd) {
// TODO(calamity): investigate moving this out of the UI thread as COM
// operations may spawn nested message loops which can cause issues.
-void SetAppDetailsForWindow(const string16& app_id,
- const string16& app_icon,
- const string16& relaunch_command,
- const string16& relaunch_display_name,
+void SetAppDetailsForWindow(const base::string16& app_id,
+ const base::string16& app_icon,
+ const base::string16& relaunch_command,
+ const base::string16& relaunch_display_name,
HWND hwnd) {
// This functionality is only available on Win7+. It also doesn't make sense
// to do this for Chrome Metro.
@@ -112,19 +112,27 @@ void SetAppDetailsForWindow(const string16& app_id,
}
}
-void SetAppIdForWindow(const string16& app_id, HWND hwnd) {
- SetAppDetailsForWindow(app_id, string16(), string16(), string16(), hwnd);
+void SetAppIdForWindow(const base::string16& app_id, HWND hwnd) {
+ SetAppDetailsForWindow(app_id,
+ base::string16(),
+ base::string16(),
+ base::string16(),
+ hwnd);
}
-void SetAppIconForWindow(const string16& app_icon, HWND hwnd) {
- SetAppDetailsForWindow(string16(), app_icon, string16(), string16(), hwnd);
+void SetAppIconForWindow(const base::string16& app_icon, HWND hwnd) {
+ SetAppDetailsForWindow(base::string16(),
+ app_icon,
+ base::string16(),
+ base::string16(),
+ hwnd);
}
-void SetRelaunchDetailsForWindow(const string16& relaunch_command,
- const string16& display_name,
+void SetRelaunchDetailsForWindow(const base::string16& relaunch_command,
+ const base::string16& display_name,
HWND hwnd) {
- SetAppDetailsForWindow(string16(),
- string16(),
+ SetAppDetailsForWindow(base::string16(),
+ base::string16(),
relaunch_command,
display_name,
hwnd);
diff --git a/chromium/ui/base/win/shell.h b/chromium/ui/base/win/shell.h
index e85d2b43fdc..e732abf8c54 100644
--- a/chromium/ui/base/win/shell.h
+++ b/chromium/ui/base/win/shell.h
@@ -8,7 +8,7 @@
#include <windows.h>
#include "base/strings/string16.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace base {
class FilePath;
@@ -21,58 +21,62 @@ namespace win {
// default application registered for the file specified by 'full_path',
// ask the user, via the Windows "Open With" dialog.
// Returns 'true' on successful open, 'false' otherwise.
-UI_EXPORT bool OpenItemViaShell(const base::FilePath& full_path);
+UI_BASE_EXPORT bool OpenItemViaShell(const base::FilePath& full_path);
// The download manager now writes the alternate data stream with the
// zone on all downloads. This function is equivalent to OpenItemViaShell
// without showing the zone warning dialog.
-UI_EXPORT bool OpenItemViaShellNoZoneCheck(const base::FilePath& full_path);
+UI_BASE_EXPORT bool OpenItemViaShellNoZoneCheck(
+ 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_FLAG_XXX as stated in msdn. If there is no default application
// registered for the item, it behaves the same as OpenItemViaShell.
-UI_EXPORT bool OpenAnyViaShell(const string16& full_path,
- const string16& directory,
- const string16& args,
- DWORD mask);
+UI_BASE_EXPORT bool OpenAnyViaShell(const base::string16& full_path,
+ const base::string16& directory,
+ const base::string16& args,
+ DWORD mask);
// Ask the user, via the Windows "Open With" dialog, for an application to use
// to open the file specified by 'full_path'.
// Returns 'true' on successful open, 'false' otherwise.
-bool OpenItemWithExternalApp(const string16& full_path);
+bool OpenItemWithExternalApp(const base::string16& full_path);
// 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.
-UI_EXPORT bool PreventWindowFromPinning(HWND hwnd);
+UI_BASE_EXPORT bool PreventWindowFromPinning(HWND hwnd);
// Sets the application id, app icon, relaunch command and relaunch display name
// for the given window.
-UI_EXPORT void SetAppDetailsForWindow(const string16& app_id,
- const string16& app_icon,
- const string16& relaunch_command,
- const string16& relaunch_display_name,
- HWND hwnd);
+UI_BASE_EXPORT void SetAppDetailsForWindow(
+ const base::string16& app_id,
+ const base::string16& app_icon,
+ const base::string16& relaunch_command,
+ const base::string16& relaunch_display_name,
+ HWND hwnd);
// Sets the application id given as the Application Model ID for the window
// specified. This method is used to insure that different web applications
// do not group together on the Win7 task bar.
-UI_EXPORT void SetAppIdForWindow(const string16& app_id, HWND hwnd);
+UI_BASE_EXPORT void SetAppIdForWindow(const base::string16& app_id, HWND hwnd);
// Sets the application icon for the window specified.
-UI_EXPORT void SetAppIconForWindow(const string16& app_icon, HWND hwnd);
+UI_BASE_EXPORT void SetAppIconForWindow(const base::string16& app_icon,
+ HWND hwnd);
// Sets the relaunch command and relaunch display name for the window specified.
// Windows will use this information for grouping on the taskbar, and to create
// a shortcut if the window is pinned to the taskbar.
-UI_EXPORT void SetRelaunchDetailsForWindow(const string16& relaunch_command,
- const string16& display_name,
- HWND hwnd);
+UI_BASE_EXPORT void SetRelaunchDetailsForWindow(
+ const base::string16& relaunch_command,
+ const base::string16& display_name,
+ HWND hwnd);
// Returns true if composition is available and turned on on the current
// platform.
-UI_EXPORT bool IsAeroGlassEnabled();
+UI_BASE_EXPORT bool IsAeroGlassEnabled();
} // namespace win
} // namespace ui
diff --git a/chromium/ui/base/win/touch_input.cc b/chromium/ui/base/win/touch_input.cc
index a369ab1f670..0114bdd3a7f 100644
--- a/chromium/ui/base/win/touch_input.cc
+++ b/chromium/ui/base/win/touch_input.cc
@@ -6,10 +6,10 @@
namespace ui {
-UI_EXPORT BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle,
- UINT count,
- PTOUCHINPUT pointer,
- int size) {
+BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle,
+ UINT count,
+ PTOUCHINPUT pointer,
+ int size) {
typedef BOOL(WINAPI *GetTouchInputInfoPtr)(HTOUCHINPUT, UINT,
PTOUCHINPUT, int);
static GetTouchInputInfoPtr get_touch_input_info_func =
diff --git a/chromium/ui/base/win/touch_input.h b/chromium/ui/base/win/touch_input.h
index dd0d82916b5..f113ec5b463 100644
--- a/chromium/ui/base/win/touch_input.h
+++ b/chromium/ui/base/win/touch_input.h
@@ -7,16 +7,16 @@
#include <windows.h>
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// Wrapper for GetTouchInputInfo, which is not defined before Win7. For
// earlier OS's, this function returns FALSE.
-UI_EXPORT BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle,
- UINT count,
- PTOUCHINPUT pointer,
- int size);
+UI_BASE_EXPORT BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle,
+ UINT count,
+ PTOUCHINPUT pointer,
+ int size);
} // namespace ui
diff --git a/chromium/ui/base/win/window_event_target.cc b/chromium/ui/base/win/window_event_target.cc
new file mode 100644
index 00000000000..555cd5af333
--- /dev/null
+++ b/chromium/ui/base/win/window_event_target.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/win/window_event_target.h"
+
+namespace ui {
+
+const char WindowEventTarget::kWin32InputEventTarget[]
+ = "Win32_InputEventTarget";
+
+WindowEventTarget::WindowEventTarget() {}
+
+WindowEventTarget::~WindowEventTarget() {}
+
+} // namespace ui
diff --git a/chromium/ui/base/win/window_event_target.h b/chromium/ui/base/win/window_event_target.h
new file mode 100644
index 00000000000..c7bb6700d8c
--- /dev/null
+++ b/chromium/ui/base/win/window_event_target.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_WINDOW_EVENT_TARGET_H_
+#define UI_BASE_WIN_WINDOW_EVENT_TARGET_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// This interface is implemented by classes who get input events forwarded to
+// them from others. E.g. would be a win32 parent child relationship where the
+// child forwards input events to the parent after doing minimal processing.
+class UI_BASE_EXPORT WindowEventTarget {
+ public:
+ static const char kWin32InputEventTarget[];
+
+ // Handles mouse events like WM_MOUSEMOVE, WM_LBUTTONDOWN, etc.
+ // The |message| parameter identifies the message.
+ // The |w_param| and |l_param| values are dependent on the type of the
+ // message.
+ // Returns the result of processing the message.
+ virtual LRESULT HandleMouseMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) = 0;
+
+ // Handles keyboard events like WM_KEYDOWN/WM_KEYUP, etc.
+ // The |message| parameter identifies the message.
+ // The |w_param| and |l_param| values are dependent on the type of the
+ // message.
+ // Returns the result of processing the message.
+ virtual LRESULT HandleKeyboardMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) = 0;
+
+ // Handles WM_TOUCH events.
+ // The |message| parameter identifies the message.
+ // The |w_param| and |l_param| values are as per MSDN docs.
+ // Returns the result of processing the message.
+ virtual LRESULT HandleTouchMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) = 0;
+
+ // Handles scroll messages like WM_VSCROLL and WM_HSCROLL.
+ // The |message| parameter identifies the scroll message.
+ // The |w_param| and |l_param| values are dependent on the type of scroll.
+ virtual LRESULT HandleScrollMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) = 0;
+
+ // Handles the WM_NCHITTEST message
+ // The |message| parameter identifies the message.
+ // The |w_param| and |l_param| values are as per MSDN docs.
+ // Returns the result of processing the message.
+ virtual LRESULT HandleNcHitTestMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) = 0;
+ protected:
+ WindowEventTarget();
+ virtual ~WindowEventTarget();
+};
+
+} // namespace ui
+
+#endif // UI_BASE_WIN_WINDOW_EVENT_TARGET_H_
+
+
diff --git a/chromium/ui/base/window_open_disposition.h b/chromium/ui/base/window_open_disposition.h
index 8d9662947f1..fe96aac5f07 100644
--- a/chromium/ui/base/window_open_disposition.h
+++ b/chromium/ui/base/window_open_disposition.h
@@ -5,7 +5,7 @@
#ifndef UI_BASE_WINDOW_OPEN_DISPOSITION_H_
#define UI_BASE_WINDOW_OPEN_DISPOSITION_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
enum WindowOpenDisposition {
@@ -20,16 +20,16 @@ namespace ui {
// Translates event flags from a click on a link into the user's desired
// window disposition. For example, a middle click would mean to open
// a background tab.
-UI_EXPORT WindowOpenDisposition DispositionFromClick(bool middle_button,
- bool alt_key,
- bool ctrl_key,
- bool meta_key,
- bool shift_key);
+UI_BASE_EXPORT WindowOpenDisposition DispositionFromClick(bool middle_button,
+ bool alt_key,
+ bool ctrl_key,
+ bool meta_key,
+ bool shift_key);
// Translates event flags into what kind of disposition they represents.
// For example, a middle click would mean to open a background tab.
// event_flags are the flags as understood by ui::MouseEvent.
-UI_EXPORT WindowOpenDisposition DispositionFromEventFlags(int event_flags);
+UI_BASE_EXPORT WindowOpenDisposition DispositionFromEventFlags(int event_flags);
} // namespace ui
diff --git a/chromium/ui/base/window_open_disposition_list.h b/chromium/ui/base/window_open_disposition_list.h
index f7676f118e3..1d3c97b37e4 100644
--- a/chromium/ui/base/window_open_disposition_list.h
+++ b/chromium/ui/base/window_open_disposition_list.h
@@ -17,3 +17,5 @@ WINDOW_OPEN_DISPOSITION(NEW_WINDOW, 7)
WINDOW_OPEN_DISPOSITION(SAVE_TO_DISK, 8)
WINDOW_OPEN_DISPOSITION(OFF_THE_RECORD, 9)
WINDOW_OPEN_DISPOSITION(IGNORE_ACTION, 10)
+// Update when adding a new disposition.
+WINDOW_OPEN_DISPOSITION(WINDOW_OPEN_DISPOSITION_LAST, 10)
diff --git a/chromium/ui/base/work_area_watcher_observer.h b/chromium/ui/base/work_area_watcher_observer.h
index 63fbf87d7e0..341eda0b9e6 100644
--- a/chromium/ui/base/work_area_watcher_observer.h
+++ b/chromium/ui/base/work_area_watcher_observer.h
@@ -5,14 +5,14 @@
#ifndef UI_BASE_WORK_AREA_WATCHER_OBSERVER_H_
#define UI_BASE_WORK_AREA_WATCHER_OBSERVER_H_
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
// This interface should be implemented by classes that want to be notified
// when the work area has changed due to something like screen resolution or
// taskbar changes.
-class UI_EXPORT WorkAreaWatcherObserver {
+class UI_BASE_EXPORT WorkAreaWatcherObserver {
public:
virtual void WorkAreaChanged() = 0;
diff --git a/chromium/ui/base/x/active_window_watcher_x.cc b/chromium/ui/base/x/active_window_watcher_x.cc
deleted file mode 100644
index 9d3e791fd53..00000000000
--- a/chromium/ui/base/x/active_window_watcher_x.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/x/active_window_watcher_x.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-
-#include "base/memory/singleton.h"
-#include "ui/base/x/active_window_watcher_x_observer.h"
-#include "ui/base/x/root_window_property_watcher_x.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/gdk_compat.h"
-#include "ui/gfx/gtk_compat.h"
-
-namespace ui {
-
-static const char* const kNetActiveWindow = "_NET_ACTIVE_WINDOW";
-
-// static
-ActiveWindowWatcherX* ActiveWindowWatcherX::GetInstance() {
- return Singleton<ActiveWindowWatcherX>::get();
-}
-
-// static
-void ActiveWindowWatcherX::AddObserver(ActiveWindowWatcherXObserver* observer) {
- // Ensure that RootWindowPropertyWatcherX exists.
- internal::RootWindowPropertyWatcherX::GetInstance();
- GetInstance()->observers_.AddObserver(observer);
-}
-
-// static
-void ActiveWindowWatcherX::RemoveObserver(
- ActiveWindowWatcherXObserver* observer) {
- GetInstance()->observers_.RemoveObserver(observer);
-}
-
-// static
-Atom ActiveWindowWatcherX::GetPropertyAtom() {
- return GetAtom(kNetActiveWindow);
-}
-
-// static
-void ActiveWindowWatcherX::Notify() {
- GetInstance()->NotifyActiveWindowChanged();
-}
-
-// static
-bool ActiveWindowWatcherX::WMSupportsActivation() {
- return gdk_x11_screen_supports_net_wm_hint(
- gdk_screen_get_default(),
- gdk_atom_intern_static_string(kNetActiveWindow));
-}
-
-ActiveWindowWatcherX::ActiveWindowWatcherX() {
-}
-
-ActiveWindowWatcherX::~ActiveWindowWatcherX() {
-}
-
-void ActiveWindowWatcherX::NotifyActiveWindowChanged() {
- // We don't use gdk_screen_get_active_window() because it caches
- // whether or not the window manager supports _NET_ACTIVE_WINDOW.
- // This causes problems at startup for chromiumos.
- Atom type = None;
- int format = 0; // size in bits of each item in 'property'
- long unsigned int num_items = 0, remaining_bytes = 0;
- unsigned char* property = NULL;
-
- XGetWindowProperty(gdk_x11_get_default_xdisplay(),
- GDK_WINDOW_XID(gdk_get_default_root_window()),
- GetAtom(kNetActiveWindow),
- 0, // offset into property data to read
- 1, // length to get in 32-bit quantities
- False, // deleted
- AnyPropertyType,
- &type,
- &format,
- &num_items,
- &remaining_bytes,
- &property);
-
- // Check that the property was set and contained a single 32-bit item (we
- // don't check that remaining_bytes is 0, though, as XFCE's window manager
- // seems to actually store two values in the property for some unknown
- // reason.)
- if (format == 32 && num_items == 1) {
- int xid = *reinterpret_cast<int*>(property);
- GdkDisplay* display = gdk_display_get_default();
- GdkWindow* active_window = gdk_x11_window_lookup_for_display(display, xid);
- FOR_EACH_OBSERVER(ActiveWindowWatcherXObserver, observers_,
- ActiveWindowChanged(active_window));
- }
- if (property)
- XFree(property);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/x/active_window_watcher_x.h b/chromium/ui/base/x/active_window_watcher_x.h
deleted file mode 100644
index 9e0ae134e15..00000000000
--- a/chromium/ui/base/x/active_window_watcher_x.h
+++ /dev/null
@@ -1,60 +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_X_ACTIVE_WINDOW_WATCHER_X_H_
-#define UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_H_
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "ui/base/ui_export.h"
-#include "ui/base/x/x11_util.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace ui {
-
-class ActiveWindowWatcherXObserver;
-
-namespace internal {
-class RootWindowPropertyWatcherX;
-}
-
-// This is a helper class that is used to keep track of which window the X
-// window manager thinks is active. Add an Observer to listen for changes to
-// the active window.
-class UI_EXPORT ActiveWindowWatcherX {
- public:
- static ActiveWindowWatcherX* GetInstance();
- static void AddObserver(ActiveWindowWatcherXObserver* observer);
- static void RemoveObserver(ActiveWindowWatcherXObserver* observer);
-
- // Checks if the WM supports the active window property. Note that the return
- // value can change, especially during system startup.
- static bool WMSupportsActivation();
-
- private:
- friend struct DefaultSingletonTraits<ActiveWindowWatcherX>;
- friend class ui::internal::RootWindowPropertyWatcherX;
-
- ActiveWindowWatcherX();
- ~ActiveWindowWatcherX();
-
- // Gets the atom for the default display for the property this class is
- // watching for.
- static Atom GetPropertyAtom();
-
- // Notify observers that the active window has changed.
- static void Notify();
-
- // Instance method that implements Notify().
- void NotifyActiveWindowChanged();
-
- ObserverList<ActiveWindowWatcherXObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(ActiveWindowWatcherX);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_H_
diff --git a/chromium/ui/base/x/active_window_watcher_x_observer.h b/chromium/ui/base/x/active_window_watcher_x_observer.h
deleted file mode 100644
index e4c71eae47d..00000000000
--- a/chromium/ui/base/x/active_window_watcher_x_observer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_
-#define UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_
-
-#include <gdk/gdk.h>
-
-#include "ui/base/ui_export.h"
-
-namespace ui {
-
-class UI_EXPORT ActiveWindowWatcherXObserver {
- public:
- // |active_window| will be NULL if the active window isn't one of Chrome's.
- virtual void ActiveWindowChanged(GdkWindow* active_window) = 0;
-
- protected:
- virtual ~ActiveWindowWatcherXObserver() {}
-};
-
-} // namespace ui
-
-#endif // UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_
diff --git a/chromium/ui/base/x/root_window_property_watcher_x.cc b/chromium/ui/base/x/root_window_property_watcher_x.cc
deleted file mode 100644
index dec47e2a1db..00000000000
--- a/chromium/ui/base/x/root_window_property_watcher_x.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/x/root_window_property_watcher_x.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-
-#include "base/memory/singleton.h"
-#include "ui/base/x/active_window_watcher_x.h"
-#include "ui/base/x/work_area_watcher_x.h"
-
-namespace ui {
-
-namespace internal {
-
-// static
-RootWindowPropertyWatcherX* RootWindowPropertyWatcherX::GetInstance() {
- return Singleton<RootWindowPropertyWatcherX>::get();
-}
-
-RootWindowPropertyWatcherX::RootWindowPropertyWatcherX() {
- GdkWindow* root = gdk_get_default_root_window();
-
- // Set up X Event filter to listen for PropertyChange X events.
- // Don't use XSelectInput directly here, as gdk internally seems to cache the
- // mask and reapply XSelectInput after this, resetting any mask we set here.
- gdk_window_set_events(root,
- static_cast<GdkEventMask>(gdk_window_get_events(root) |
- GDK_PROPERTY_CHANGE_MASK));
- gdk_window_add_filter(root,
- &RootWindowPropertyWatcherX::OnWindowXEventThunk,
- this);
-}
-
-RootWindowPropertyWatcherX::~RootWindowPropertyWatcherX() {
- gdk_window_remove_filter(NULL,
- &RootWindowPropertyWatcherX::OnWindowXEventThunk,
- this);
-}
-
-GdkFilterReturn RootWindowPropertyWatcherX::OnWindowXEvent(
- GdkXEvent* xevent, GdkEvent* event) {
- XEvent* xev = static_cast<XEvent*>(xevent);
-
- if (xev->xany.type == PropertyNotify) {
- if (xev->xproperty.atom == ActiveWindowWatcherX::GetPropertyAtom())
- ActiveWindowWatcherX::Notify();
- else if (xev->xproperty.atom == WorkAreaWatcherX::GetPropertyAtom())
- WorkAreaWatcherX::Notify();
- }
-
- return GDK_FILTER_CONTINUE;
-}
-
-} // namespace internal
-
-} // namespace ui
diff --git a/chromium/ui/base/x/root_window_property_watcher_x.h b/chromium/ui/base/x/root_window_property_watcher_x.h
deleted file mode 100644
index 76090162f7f..00000000000
--- a/chromium/ui/base/x/root_window_property_watcher_x.h
+++ /dev/null
@@ -1,41 +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_X_ROOT_WINDOW_PROPERTY_WATCHER_X_H_
-#define UI_BASE_X_ROOT_WINDOW_PROPERTY_WATCHER_X_H_
-
-#include <gdk/gdk.h>
-
-#include "base/basictypes.h"
-#include "ui/base/gtk/gtk_signal.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace ui {
-namespace internal {
-
-// This class keeps track of changes to properties on the root window. This is
-// not to be used directly. Implement a watcher for the specific property you're
-// interested in.
-class RootWindowPropertyWatcherX {
- public:
- static RootWindowPropertyWatcherX* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<RootWindowPropertyWatcherX>;
-
- RootWindowPropertyWatcherX();
- ~RootWindowPropertyWatcherX();
-
- // Callback for PropertyChange XEvents.
- CHROMEG_CALLBACK_1(RootWindowPropertyWatcherX, GdkFilterReturn,
- OnWindowXEvent, GdkXEvent*, GdkEvent*);
-
- DISALLOW_COPY_AND_ASSIGN(RootWindowPropertyWatcherX);
-};
-
-} // namespace internal
-} // namespace ui
-
-#endif // UI_BASE_X_ROOT_WINDOW_PROPERTY_WATCHER_X_H_
diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc
index 54f59a162d4..c30187e1991 100644
--- a/chromium/ui/base/x/selection_owner.cc
+++ b/chromium/ui/base/x/selection_owner.cc
@@ -9,20 +9,67 @@
#include "base/logging.h"
#include "ui/base/x/selection_utils.h"
+#include "ui/base/x/x11_util.h"
namespace ui {
namespace {
+const char kAtomPair[] = "ATOM_PAIR";
const char kMultiple[] = "MULTIPLE";
+const char kSaveTargets[] = "SAVE_TARGETS";
const char kTargets[] = "TARGETS";
const char* kAtomsToCache[] = {
+ kAtomPair,
kMultiple,
+ kSaveTargets,
kTargets,
NULL
};
+// Gets the value of an atom pair array property. On success, true is returned
+// and the value is stored in |value|.
+bool GetAtomPairArrayProperty(XID window,
+ Atom property,
+ std::vector<std::pair<Atom,Atom> >* value) {
+ Atom type = None;
+ int format = 0; // size in bits of each item in 'property'
+ unsigned long num_items = 0;
+ unsigned char* properties = NULL;
+ unsigned long remaining_bytes = 0;
+
+ int result = XGetWindowProperty(gfx::GetXDisplay(),
+ window,
+ property,
+ 0, // offset into property data to
+ // read
+ (~0L), // entire array
+ False, // deleted
+ AnyPropertyType,
+ &type,
+ &format,
+ &num_items,
+ &remaining_bytes,
+ &properties);
+
+ if (result != Success)
+ return false;
+
+ // GTK does not require |type| to be kAtomPair.
+ if (format != 32 || num_items % 2 != 0) {
+ XFree(properties);
+ return false;
+ }
+
+ Atom* atom_properties = reinterpret_cast<Atom*>(properties);
+ value->clear();
+ for (size_t i = 0; i < num_items; i+=2)
+ value->push_back(std::make_pair(atom_properties[i], atom_properties[i+1]));
+ XFree(properties);
+ return true;
+}
+
} // namespace
SelectionOwner::SelectionOwner(Display* x_display,
@@ -35,11 +82,14 @@ SelectionOwner::SelectionOwner(Display* x_display,
}
SelectionOwner::~SelectionOwner() {
- Clear();
+ // If we are the selection owner, we need to release the selection so we
+ // don't receive further events. However, we don't call ClearSelectionOwner()
+ // because we don't want to do this indiscriminately.
+ if (XGetSelectionOwner(x_display_, selection_name_) == x_window_)
+ XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
}
void SelectionOwner::RetrieveTargets(std::vector<Atom>* targets) {
- targets->clear();
for (SelectionFormatMap::const_iterator it = format_map_.begin();
it != format_map_.end(); ++it) {
targets->push_back(it->first);
@@ -56,10 +106,8 @@ void SelectionOwner::TakeOwnershipOfSelection(
}
}
-void SelectionOwner::Clear() {
- if (XGetSelectionOwner(x_display_, selection_name_) == x_window_)
- XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
-
+void SelectionOwner::ClearSelectionOwner() {
+ XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime);
format_map_ = SelectionFormatMap();
}
@@ -74,51 +122,93 @@ void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) {
reply.xselection.property = None; // Indicates failure
reply.xselection.time = event.time;
- // Get the proper selection.
+ if (event.target == atom_cache_.GetAtom(kMultiple)) {
+ // The contents of |event.property| should be a list of
+ // <target,property> pairs.
+ std::vector<std::pair<Atom,Atom> > conversions;
+ if (GetAtomPairArrayProperty(event.requestor,
+ event.property,
+ &conversions)) {
+ std::vector<Atom> conversion_results;
+ for (size_t i = 0; i < conversions.size(); ++i) {
+ bool conversion_successful = ProcessTarget(conversions[i].first,
+ event.requestor,
+ conversions[i].second);
+ conversion_results.push_back(conversions[i].first);
+ conversion_results.push_back(
+ conversion_successful ? conversions[i].second : None);
+ }
+
+ // Set the property to indicate which conversions succeeded. This matches
+ // what GTK does.
+ XChangeProperty(
+ x_display_,
+ event.requestor,
+ event.property,
+ atom_cache_.GetAtom(kAtomPair),
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&conversion_results.front()),
+ conversion_results.size());
+
+ reply.xselection.property = event.property;
+ }
+ } else {
+ if (ProcessTarget(event.target, event.requestor, event.property))
+ reply.xselection.property = event.property;
+ }
+
+ // Send off the reply.
+ XSendEvent(x_display_, event.requestor, False, 0, &reply);
+}
+
+void SelectionOwner::OnSelectionClear(const XSelectionClearEvent& event) {
+ DLOG(ERROR) << "SelectionClear";
+
+ // TODO(erg): If we receive a SelectionClear event while we're handling data,
+ // we need to delay clearing.
+}
+
+bool SelectionOwner::ProcessTarget(Atom target,
+ ::Window requestor,
+ ::Atom property) {
+ Atom multiple_atom = atom_cache_.GetAtom(kMultiple);
+ Atom save_targets_atom = atom_cache_.GetAtom(kSaveTargets);
Atom targets_atom = atom_cache_.GetAtom(kTargets);
- if (event.target == targets_atom) {
+
+ if (target == multiple_atom || target == save_targets_atom)
+ return false;
+
+ if (target == targets_atom) {
// We have been asked for TARGETS. Send an atom array back with the data
// types we support.
std::vector<Atom> targets;
targets.push_back(targets_atom);
+ targets.push_back(save_targets_atom);
+ targets.push_back(multiple_atom);
RetrieveTargets(&targets);
- XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM, 32,
+ XChangeProperty(x_display_, requestor, property, XA_ATOM, 32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&targets.front()),
targets.size());
- reply.xselection.property = event.property;
- } else if (event.target == atom_cache_.GetAtom(kMultiple)) {
- // TODO(erg): Theoretically, the spec claims I'm supposed to handle the
- // MULTIPLE case, but I haven't seen it in the wild yet.
- NOTIMPLEMENTED();
+ return true;
} else {
// Try to find the data type in map.
- SelectionFormatMap::const_iterator it =
- format_map_.find(event.target);
+ SelectionFormatMap::const_iterator it = format_map_.find(target);
if (it != format_map_.end()) {
- XChangeProperty(x_display_, event.requestor, event.property,
- event.target, 8,
+ XChangeProperty(x_display_, requestor, property, target, 8,
PropModeReplace,
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(
it->second->front())),
it->second->size());
- reply.xselection.property = event.property;
+ return true;
}
// I would put error logging here, but GTK ignores TARGETS and spams us
// looking for its own internal types.
}
-
- // Send off the reply.
- XSendEvent(x_display_, event.requestor, False, 0, &reply);
-}
-
-void SelectionOwner::OnSelectionClear(const XSelectionClearEvent& event) {
- DLOG(ERROR) << "SelectionClear";
-
- // TODO(erg): If we receive a SelectionClear event while we're handling data,
- // we need to delay clearing.
+ return false;
}
} // namespace ui
diff --git a/chromium/ui/base/x/selection_owner.h b/chromium/ui/base/x/selection_owner.h
index 8cecc621cc8..81d7e73a1f4 100644
--- a/chromium/ui/base/x/selection_owner.h
+++ b/chromium/ui/base/x/selection_owner.h
@@ -14,7 +14,7 @@
#include "base/basictypes.h"
#include "base/callback.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/base/x/selection_utils.h"
#include "ui/gfx/x/x11_atom_cache.h"
@@ -25,7 +25,7 @@ namespace ui {
// The selection owner object keeps track of which xwindow is the current
// owner, and when its |xwindow_|, offers different data types to other
// processes.
-class UI_EXPORT SelectionOwner {
+class UI_BASE_EXPORT SelectionOwner {
public:
SelectionOwner(Display* xdisplay,
::Window xwindow,
@@ -35,15 +35,16 @@ class UI_EXPORT SelectionOwner {
// Returns the current selection data. Useful for fast paths.
const SelectionFormatMap& selection_format_map() { return format_map_; }
- // Retrieves a list of types we're offering.
+ // Appends a list of types we're offering to |targets|.
void RetrieveTargets(std::vector<Atom>* targets);
// Attempts to take ownership of the selection. If we're successful, present
// |data| to other windows.
void TakeOwnershipOfSelection(const SelectionFormatMap& data);
- // Releases the selection (if we own it) and clears any data we own.
- void Clear();
+ // Clears our internal format map and clears the selection owner, whether we
+ // own the selection or not.
+ void ClearSelectionOwner();
// It is our owner's responsibility to plumb X11 events on |xwindow_| to us.
void OnSelectionRequest(const XSelectionRequestEvent& event);
@@ -52,6 +53,11 @@ class UI_EXPORT SelectionOwner {
// don't, but there were open todos in the previous implementation.
private:
+ // Attempts to convert the selection to |target|. If the conversion is
+ // successful, true is returned and the result is stored in the |property|
+ // of |requestor|.
+ bool ProcessTarget(::Atom target, ::Window requestor, ::Atom property);
+
// Our X11 state.
Display* x_display_;
::Window x_window_;
diff --git a/chromium/ui/base/x/selection_requestor.cc b/chromium/ui/base/x/selection_requestor.cc
index dd7a310e603..a946787d355 100644
--- a/chromium/ui/base/x/selection_requestor.cc
+++ b/chromium/ui/base/x/selection_requestor.cc
@@ -4,10 +4,12 @@
#include "ui/base/x/selection_requestor.h"
-#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11_types.h"
namespace ui {
@@ -24,10 +26,12 @@ const char* kAtomsToCache[] = {
SelectionRequestor::SelectionRequestor(Display* x_display,
Window x_window,
- Atom selection_name)
+ Atom selection_name,
+ PlatformEventDispatcher* dispatcher)
: x_display_(x_display),
x_window_(x_window),
selection_name_(selection_name),
+ dispatcher_(dispatcher),
atom_cache_(x_display_, kAtomsToCache) {
}
@@ -39,35 +43,41 @@ bool SelectionRequestor::PerformBlockingConvertSelection(
size_t* out_data_bytes,
size_t* out_data_items,
Atom* out_type) {
- // The name of the property we're asking to be set on |x_window_|.
- Atom property_to_set = atom_cache_.GetAtom(kChromeSelection);
+ // The name of the property that we are either:
+ // - Passing as a parameter with the XConvertSelection() request.
+ // OR
+ // - Asking the selection owner to set on |x_window_|.
+ Atom property = atom_cache_.GetAtom(kChromeSelection);
XConvertSelection(x_display_,
selection_name_,
target,
- property_to_set,
+ property,
x_window_,
CurrentTime);
// Now that we've thrown our message off to the X11 server, we block waiting
// for a response.
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
- base::RunLoop run_loop(base::MessagePumpX11::Current());
-
- PendingRequest pending_request(target, run_loop.QuitClosure());
- pending_requests_.push_back(&pending_request);
- run_loop.Run();
- DCHECK(!pending_requests_.empty());
- DCHECK_EQ(&pending_request, pending_requests_.back());
- pending_requests_.pop_back();
-
- if (pending_request.returned_property != property_to_set)
- return false;
+ PendingRequest pending_request(target);
+ BlockTillSelectionNotifyForRequest(&pending_request);
+
+ bool success = false;
+ if (pending_request.returned_property == property) {
+ success = ui::GetRawBytesOfProperty(x_window_,
+ pending_request.returned_property,
+ out_data, out_data_bytes,
+ out_data_items, out_type);
+ }
+ if (pending_request.returned_property != None)
+ XDeleteProperty(x_display_, x_window_, pending_request.returned_property);
+ return success;
+}
- return ui::GetRawBytesOfProperty(x_window_, pending_request.returned_property,
- out_data, out_data_bytes, out_data_items,
- out_type);
+void SelectionRequestor::PerformBlockingConvertSelectionWithParameter(
+ Atom target,
+ const std::vector< ::Atom>& parameter) {
+ SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter);
+ PerformBlockingConvertSelection(target, NULL, NULL, NULL, NULL);
}
SelectionData SelectionRequestor::RequestAndWaitForTypes(
@@ -111,18 +121,62 @@ void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) {
// This event doesn't correspond to any XConvertSelection calls that we
// issued in PerformBlockingConvertSelection. This shouldn't happen, but any
// client can send any message, so it can happen.
- if (!request_notified)
+ if (!request_notified) {
+ // ICCCM requires us to delete the property passed into SelectionNotify. If
+ // |request_notified| is true, the property will be deleted when the run
+ // loop has quit.
+ if (event.property != None)
+ XDeleteProperty(x_display_, x_window_, event.property);
return;
+ }
request_notified->returned_property = event.property;
request_notified->returned = true;
- request_notified->quit_closure.Run();
+
+ if (!request_notified->quit_closure.is_null())
+ request_notified->quit_closure.Run();
+}
+
+void SelectionRequestor::BlockTillSelectionNotifyForRequest(
+ PendingRequest* request) {
+ pending_requests_.push_back(request);
+
+ const int kMaxWaitTimeForClipboardResponse = 300;
+ if (PlatformEventSource::GetInstance()) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+ base::RunLoop run_loop;
+
+ request->quit_closure = run_loop.QuitClosure();
+ loop->PostDelayedTask(
+ FROM_HERE,
+ request->quit_closure,
+ base::TimeDelta::FromMilliseconds(kMaxWaitTimeForClipboardResponse));
+
+ run_loop.Run();
+ } else {
+ // This occurs if PerformBlockingConvertSelection() is called during
+ // shutdown and the PlatformEventSource has already been destroyed.
+ base::TimeTicks start = base::TimeTicks::Now();
+ while (!request->returned) {
+ if (XPending(x_display_)) {
+ XEvent event;
+ XNextEvent(x_display_, &event);
+ dispatcher_->DispatchEvent(&event);
+ }
+ base::TimeDelta wait_time = base::TimeTicks::Now() - start;
+ if (wait_time.InMilliseconds() > kMaxWaitTimeForClipboardResponse)
+ break;
+ }
+ }
+
+ DCHECK(!pending_requests_.empty());
+ DCHECK_EQ(request, pending_requests_.back());
+ pending_requests_.pop_back();
}
-SelectionRequestor::PendingRequest::PendingRequest(Atom target,
- base::Closure quit_closure)
+SelectionRequestor::PendingRequest::PendingRequest(Atom target)
: target(target),
- quit_closure(quit_closure),
returned_property(None),
returned(false) {
}
diff --git a/chromium/ui/base/x/selection_requestor.h b/chromium/ui/base/x/selection_requestor.h
index c045255e5c3..f142dd096cf 100644
--- a/chromium/ui/base/x/selection_requestor.h
+++ b/chromium/ui/base/x/selection_requestor.h
@@ -16,10 +16,11 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/ref_counted_memory.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace ui {
+class PlatformEventDispatcher;
class SelectionData;
// Requests and later receives data from the X11 server through the selection
@@ -29,11 +30,12 @@ class SelectionData;
// drop. This class interprets messages from the statefull selection request
// API. SelectionRequestor should only deal with the X11 details; it does not
// implement per-component fast-paths.
-class UI_EXPORT SelectionRequestor {
+class UI_BASE_EXPORT SelectionRequestor {
public:
SelectionRequestor(Display* xdisplay,
::Window xwindow,
- ::Atom selection_name);
+ ::Atom selection_name,
+ PlatformEventDispatcher* dispatcher);
~SelectionRequestor();
// Does the work of requesting |target| from the selection we handle,
@@ -48,6 +50,12 @@ class UI_EXPORT SelectionRequestor {
size_t* out_data_items,
::Atom* out_type);
+ // Requests |target| from the selection that we handle, passing |parameter|
+ // as a parameter to XConvertSelection().
+ void PerformBlockingConvertSelectionWithParameter(
+ ::Atom target,
+ const std::vector< ::Atom>& parameter);
+
// Returns the first of |types| offered by the current selection holder, or
// returns NULL if none of those types are available.
SelectionData RequestAndWaitForTypes(const std::vector< ::Atom>& types);
@@ -57,16 +65,9 @@ class UI_EXPORT SelectionRequestor {
void OnSelectionNotify(const XSelectionEvent& event);
private:
- // Our X11 state.
- Display* x_display_;
- ::Window x_window_;
-
- // The X11 selection that this instance communicates on.
- ::Atom selection_name_;
-
// A request that has been issued and we are waiting for a response to.
struct PendingRequest {
- PendingRequest(Atom target, base::Closure quit_closure);
+ explicit PendingRequest(Atom target);
~PendingRequest();
// Data to the current XConvertSelection request. Used for error detection;
@@ -86,6 +87,24 @@ class UI_EXPORT SelectionRequestor {
bool returned;
};
+ // Blocks till SelectionNotify is received for the target specified in
+ // |request|.
+ void BlockTillSelectionNotifyForRequest(PendingRequest* request);
+
+ // Our X11 state.
+ Display* x_display_;
+ ::Window x_window_;
+
+ // The X11 selection that this instance communicates on.
+ ::Atom selection_name_;
+
+ // Dispatcher which handles SelectionNotify and SelectionRequest for
+ // |selection_name_|. PerformBlockingConvertSelection() calls the
+ // dispatcher directly if PerformBlockingConvertSelection() is called after
+ // the PlatformEventSource is destroyed.
+ // Not owned.
+ PlatformEventDispatcher* dispatcher_;
+
// A list of requests for which we are waiting for responses.
std::list<PendingRequest*> pending_requests_;
diff --git a/chromium/ui/base/x/selection_utils.cc b/chromium/ui/base/x/selection_utils.cc
index a3f8494ec87..d5ce1c03cf2 100644
--- a/chromium/ui/base/x/selection_utils.cc
+++ b/chromium/ui/base/x/selection_utils.cc
@@ -8,6 +8,7 @@
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/x/x11_util.h"
@@ -18,12 +19,16 @@ namespace ui {
const char kMimeTypeMozillaURL[] = "text/x-moz-url";
const char kString[] = "STRING";
const char kText[] = "TEXT";
+const char kTextPlain[] = "text/plain";
+const char kTextPlainUtf8[] = "text/plain;charset=utf-8";
const char kUtf8String[] = "UTF8_STRING";
const char* kSelectionDataAtoms[] = {
Clipboard::kMimeTypeHTML,
kString,
kText,
+ kTextPlain,
+ kTextPlainUtf8,
kUtf8String,
NULL
};
@@ -33,6 +38,8 @@ std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) {
atoms.push_back(atom_cache->GetAtom(kUtf8String));
atoms.push_back(atom_cache->GetAtom(kString));
atoms.push_back(atom_cache->GetAtom(kText));
+ atoms.push_back(atom_cache->GetAtom(kTextPlain));
+ atoms.push_back(atom_cache->GetAtom(kTextPlainUtf8));
return atoms;
}
@@ -43,6 +50,12 @@ std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) {
return atoms;
}
+std::vector< ::Atom> GetURIListAtomsFrom(const X11AtomCache* atom_cache) {
+ std::vector< ::Atom> atoms;
+ atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
+ return atoms;
+}
+
void GetAtomIntersection(const std::vector< ::Atom>& desired,
const std::vector< ::Atom>& offered,
std::vector< ::Atom>* output) {
@@ -55,13 +68,23 @@ void GetAtomIntersection(const std::vector< ::Atom>& desired,
}
}
-void AddString16ToVector(const string16& str,
+void AddString16ToVector(const base::string16& str,
std::vector<unsigned char>* bytes) {
const unsigned char* front =
reinterpret_cast<const unsigned char*>(str.data());
bytes->insert(bytes->end(), front, front + (str.size() * 2));
}
+std::vector<std::string> ParseURIList(const SelectionData& data) {
+ // uri-lists are newline separated file lists in URL encoding.
+ std::string unparsed;
+ data.AssignTo(&unparsed);
+
+ std::vector<std::string> tokens;
+ Tokenize(unparsed, "\n", &tokens);
+ return tokens;
+}
+
std::string RefCountedMemoryToString(
const scoped_refptr<base::RefCountedMemory>& memory) {
if (!memory.get()) {
@@ -77,19 +100,19 @@ std::string RefCountedMemoryToString(
return std::string(reinterpret_cast<const char*>(front), size);
}
-string16 RefCountedMemoryToString16(
+base::string16 RefCountedMemoryToString16(
const scoped_refptr<base::RefCountedMemory>& memory) {
if (!memory.get()) {
NOTREACHED();
- return string16();
+ return base::string16();
}
size_t size = memory->size();
if (!size)
- return string16();
+ return base::string16();
const unsigned char* front = memory->front();
- return string16(reinterpret_cast<const base::char16*>(front), size / 2);
+ return base::string16(reinterpret_cast<const base::char16*>(front), size / 2);
}
///////////////////////////////////////////////////////////////////////////////
@@ -175,9 +198,11 @@ size_t SelectionData::GetSize() const {
std::string SelectionData::GetText() const {
if (type_ == atom_cache_.GetAtom(kUtf8String) ||
- type_ == atom_cache_.GetAtom(kText)) {
+ type_ == atom_cache_.GetAtom(kText) ||
+ type_ == atom_cache_.GetAtom(kTextPlainUtf8)) {
return RefCountedMemoryToString(memory_);
- } else if (type_ == atom_cache_.GetAtom(kString)) {
+ } else if (type_ == atom_cache_.GetAtom(kString) ||
+ type_ == atom_cache_.GetAtom(kTextPlain)) {
std::string result;
base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
base::kCodepageLatin1,
@@ -191,8 +216,8 @@ std::string SelectionData::GetText() const {
}
}
-string16 SelectionData::GetHtml() const {
- string16 markup;
+base::string16 SelectionData::GetHtml() const {
+ base::string16 markup;
if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) {
const unsigned char* data = GetData();
@@ -205,7 +230,7 @@ string16 SelectionData::GetHtml() const {
markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
(size / 2) - 1);
} else {
- UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
+ base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
}
// If there is a terminating NULL, drop it.
@@ -223,7 +248,7 @@ void SelectionData::AssignTo(std::string* result) const {
*result = RefCountedMemoryToString(memory_);
}
-void SelectionData::AssignTo(string16* result) const {
+void SelectionData::AssignTo(base::string16* result) const {
*result = RefCountedMemoryToString16(memory_);
}
diff --git a/chromium/ui/base/x/selection_utils.h b/chromium/ui/base/x/selection_utils.h
index 350f383e81c..9eca5beb4ab 100644
--- a/chromium/ui/base/x/selection_utils.h
+++ b/chromium/ui/base/x/selection_utils.h
@@ -15,7 +15,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted_memory.h"
#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace ui {
@@ -28,30 +28,38 @@ extern const char kText[];
extern const char kUtf8String[];
// Returns a list of all text atoms that we handle.
-UI_EXPORT std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache);
+UI_BASE_EXPORT std::vector< ::Atom> GetTextAtomsFrom(
+ const X11AtomCache* atom_cache);
-UI_EXPORT std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache);
+UI_BASE_EXPORT std::vector< ::Atom> GetURLAtomsFrom(
+ const X11AtomCache* atom_cache);
+
+UI_BASE_EXPORT std::vector< ::Atom> GetURIListAtomsFrom(
+ const X11AtomCache* atom_cache);
// Places the intersection of |desired| and |offered| into |output|.
-UI_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& desired,
- const std::vector< ::Atom>& offered,
- std::vector< ::Atom>* output);
+UI_BASE_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& desired,
+ const std::vector< ::Atom>& offered,
+ std::vector< ::Atom>* output);
+
+// Takes the raw bytes of the base::string16 and copies them into |bytes|.
+UI_BASE_EXPORT void AddString16ToVector(const base::string16& str,
+ std::vector<unsigned char>* bytes);
-// Takes the raw bytes of the string16 and copies them into |bytes|.
-UI_EXPORT void AddString16ToVector(const string16& str,
- std::vector<unsigned char>* bytes);
+// Tokenizes and parses the Selection Data as if it is a URI List.
+UI_BASE_EXPORT std::vector<std::string> ParseURIList(const SelectionData& data);
-UI_EXPORT std::string RefCountedMemoryToString(
+UI_BASE_EXPORT std::string RefCountedMemoryToString(
const scoped_refptr<base::RefCountedMemory>& memory);
-UI_EXPORT string16 RefCountedMemoryToString16(
+UI_BASE_EXPORT base::string16 RefCountedMemoryToString16(
const scoped_refptr<base::RefCountedMemory>& memory);
///////////////////////////////////////////////////////////////////////////////
// Represents the selection in different data formats. Binary data passed in is
// assumed to be allocated with new char[], and is owned by SelectionFormatMap.
-class UI_EXPORT SelectionFormatMap {
+class UI_BASE_EXPORT SelectionFormatMap {
public:
// Our internal data store, which we only expose through iterators.
typedef std::map< ::Atom, scoped_refptr<base::RefCountedMemory> > InternalMap;
@@ -85,7 +93,7 @@ class UI_EXPORT SelectionFormatMap {
///////////////////////////////////////////////////////////////////////////////
// A holder for data with optional X11 deletion semantics.
-class UI_EXPORT SelectionData {
+class UI_BASE_EXPORT SelectionData {
public:
// |atom_cache| is still owned by caller.
SelectionData();
@@ -105,11 +113,11 @@ class UI_EXPORT SelectionData {
// If |type_| is the HTML type, returns the data as a string16. This detects
// guesses the character encoding of the source.
- string16 GetHtml() const;
+ base::string16 GetHtml() const;
// Assigns the raw data to the string.
void AssignTo(std::string* result) const;
- void AssignTo(string16* result) const;
+ void AssignTo(base::string16* result) const;
private:
::Atom type_;
diff --git a/chromium/ui/base/x/work_area_watcher_x.cc b/chromium/ui/base/x/work_area_watcher_x.cc
deleted file mode 100644
index 053b4899011..00000000000
--- a/chromium/ui/base/x/work_area_watcher_x.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/x/work_area_watcher_x.h"
-
-#include "base/memory/singleton.h"
-#include "ui/base/work_area_watcher_observer.h"
-#include "ui/base/x/root_window_property_watcher_x.h"
-#include "ui/base/x/x11_util.h"
-
-namespace ui {
-
-static const char* const kNetWorkArea = "_NET_WORKAREA";
-
-// static
-WorkAreaWatcherX* WorkAreaWatcherX::GetInstance() {
- return Singleton<WorkAreaWatcherX>::get();
-}
-
-// static
-void WorkAreaWatcherX::AddObserver(WorkAreaWatcherObserver* observer) {
- // Ensure that RootWindowPropertyWatcherX exists.
- internal::RootWindowPropertyWatcherX::GetInstance();
- GetInstance()->observers_.AddObserver(observer);
-}
-
-// static
-void WorkAreaWatcherX::RemoveObserver(WorkAreaWatcherObserver* observer) {
- GetInstance()->observers_.RemoveObserver(observer);
-}
-
-// static
-void WorkAreaWatcherX::Notify() {
- GetInstance()->NotifyWorkAreaChanged();
-}
-
-// static
-Atom WorkAreaWatcherX::GetPropertyAtom() {
- return GetAtom(kNetWorkArea);
-}
-
-WorkAreaWatcherX::WorkAreaWatcherX() {
-}
-
-WorkAreaWatcherX::~WorkAreaWatcherX() {
-}
-
-void WorkAreaWatcherX::NotifyWorkAreaChanged() {
- FOR_EACH_OBSERVER(WorkAreaWatcherObserver, observers_, WorkAreaChanged());
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/x/work_area_watcher_x.h b/chromium/ui/base/x/work_area_watcher_x.h
deleted file mode 100644
index f888ea044a7..00000000000
--- a/chromium/ui/base/x/work_area_watcher_x.h
+++ /dev/null
@@ -1,55 +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_X_WORK_AREA_WATCHER_X_H_
-#define UI_BASE_X_WORK_AREA_WATCHER_X_H_
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "ui/base/ui_export.h"
-#include "ui/base/x/x11_util.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace ui {
-
-class WorkAreaWatcherObserver;
-
-namespace internal {
-class RootWindowPropertyWatcherX;
-}
-
-// This is a helper class that is used to keep track of changes to work area.
-// Add an observer to track changes.
-class UI_EXPORT WorkAreaWatcherX {
- public:
- static WorkAreaWatcherX* GetInstance();
- static void AddObserver(WorkAreaWatcherObserver* observer);
- static void RemoveObserver(WorkAreaWatcherObserver* observer);
-
- private:
- friend struct DefaultSingletonTraits<WorkAreaWatcherX>;
- friend class ui::internal::RootWindowPropertyWatcherX;
-
- WorkAreaWatcherX();
- ~WorkAreaWatcherX();
-
- // Gets the atom for the default display for the property this class is
- // watching for.
- static Atom GetPropertyAtom();
-
- // Notify observers that the work area has changed.
- static void Notify();
-
- // Instance method that implements Notify().
- void NotifyWorkAreaChanged();
-
- ObserverList<WorkAreaWatcherObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkAreaWatcherX);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_X_WORK_AREA_WATCHER_X_H_
diff --git a/chromium/ui/base/x/x11_menu_list.cc b/chromium/ui/base/x/x11_menu_list.cc
new file mode 100644
index 00000000000..3396e57840e
--- /dev/null
+++ b/chromium/ui/base/x/x11_menu_list.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/x/x11_menu_list.h"
+
+#include "base/memory/singleton.h"
+#include "ui/base/x/x11_util.h"
+
+namespace ui {
+
+// static
+XMenuList* XMenuList::GetInstance() {
+ return Singleton<XMenuList>::get();
+}
+
+XMenuList::XMenuList()
+ : menu_type_atom_(GetAtom("_NET_WM_WINDOW_TYPE_MENU")) {
+}
+
+XMenuList::~XMenuList() {
+ menus_.clear();
+}
+
+void XMenuList::MaybeRegisterMenu(XID menu) {
+ int value = 0;
+ if (!GetIntProperty(menu, "_NET_WM_WINDOW_TYPE", &value) ||
+ static_cast<Atom>(value) != menu_type_atom_) {
+ return;
+ }
+ menus_.push_back(menu);
+}
+
+void XMenuList::MaybeUnregisterMenu(XID menu) {
+ std::vector<XID>::iterator iter = std::find(menus_.begin(), menus_.end(),
+ menu);
+ if (iter == menus_.end())
+ return;
+ menus_.erase(iter);
+}
+
+void XMenuList::InsertMenuWindowXIDs(std::vector<XID>* stack) {
+ stack->insert(stack->begin(), menus_.begin(), menus_.end());
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/x/x11_menu_list.h b/chromium/ui/base/x/x11_menu_list.h
new file mode 100644
index 00000000000..4e8476aea08
--- /dev/null
+++ b/chromium/ui/base/x/x11_menu_list.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_X_X11_MENU_LIST_H_
+#define UI_BASE_X_X11_MENU_LIST_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/gfx/x/x11_types.h"
+
+typedef unsigned long Atom;
+
+// A process wide singleton cache for X menus.
+template <typename T> struct DefaultSingletonTraits;
+
+namespace ui {
+
+// Keeps track of created and destroyed top level menu windows.
+class UI_BASE_EXPORT XMenuList {
+ public:
+ static XMenuList* GetInstance();
+
+ // Checks if |menu| has _NET_WM_WINDOW_TYPE property set to
+ // "_NET_WM_WINDOW_TYPE_MENU" atom and if so caches it.
+ void MaybeRegisterMenu(XID menu);
+
+ // Finds |menu| in cache and if found removes it.
+ void MaybeUnregisterMenu(XID menu);
+
+ // Inserts cached menu XIDs at the beginning of |stack|.
+ void InsertMenuWindowXIDs(std::vector<XID>* stack);
+
+ private:
+ friend struct DefaultSingletonTraits<XMenuList>;
+ XMenuList();
+ ~XMenuList();
+
+ std::vector<XID> menus_;
+ ::Atom menu_type_atom_;
+ DISALLOW_COPY_AND_ASSIGN(XMenuList);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_X_X11_MENU_LIST_H_
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index dfecc6cd8a3..ddfb0aa66e1 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -19,9 +19,9 @@
#include <X11/extensions/shape.h>
#include <X11/extensions/XInput2.h>
+#include <X11/Xcursor/Xcursor.h>
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -33,9 +33,10 @@
#include "base/strings/stringprintf.h"
#include "base/sys_byteorder.h"
#include "base/threading/thread.h"
-#include "base/x11/x11_error_tracker.h"
+#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPostConfig.h"
+#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util_internal.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
@@ -48,53 +49,18 @@
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/x/x11_error_tracker.h"
#if defined(OS_FREEBSD)
#include <sys/sysctl.h>
#include <sys/types.h>
#endif
-#if defined(USE_AURA)
-#include <X11/Xcursor/Xcursor.h>
-#include "skia/ext/image_operations.h"
-#include "ui/gfx/skia_util.h"
-#endif
-
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#include "ui/gfx/gdk_compat.h"
-#include "ui/gfx/gtk_compat.h"
-#endif
-
namespace ui {
namespace {
-// Used to cache the XRenderPictFormat for a visual/display pair.
-struct CachedPictFormat {
- bool equals(XDisplay* display, Visual* visual) const {
- return display == this->display && visual == this->visual;
- }
-
- XDisplay* display;
- Visual* visual;
- XRenderPictFormat* format;
-};
-
-typedef std::list<CachedPictFormat> CachedPictFormats;
-
-// Returns the cache of pict formats.
-CachedPictFormats* get_cached_pict_formats() {
- static CachedPictFormats* formats = NULL;
- if (!formats)
- formats = new CachedPictFormats();
- return formats;
-}
-
-// Maximum number of CachedPictFormats we keep around.
-const size_t kMaxCacheSize = 5;
-
int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
if (base::MessageLoop::current()) {
base::MessageLoop::current()->PostTask(
@@ -150,14 +116,14 @@ class XCursorCache {
std::pair<std::map<int, ::Cursor>::iterator, bool> it = cache_.insert(
std::make_pair(cursor_shape, 0));
if (it.second) {
- XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
+ XDisplay* display = gfx::GetXDisplay();
it.first->second = XCreateFontCursor(display, cursor_shape);
}
return it.first->second;
}
void Clear() {
- XDisplay* display = base::MessagePumpForUI::GetDefaultXDisplay();
+ XDisplay* display = gfx::GetXDisplay();
for (std::map<int, ::Cursor>::iterator it =
cache_.begin(); it != cache_.end(); ++it) {
XFreeCursor(display, it->second);
@@ -174,7 +140,6 @@ class XCursorCache {
XCursorCache* cursor_cache = NULL;
-#if defined(USE_AURA)
// A process wide singleton cache for custom X cursors.
class XCustomCursorCache {
public:
@@ -202,6 +167,10 @@ class XCustomCursorCache {
cache_.clear();
}
+ const XcursorImage* GetXcursorImage(::Cursor cursor) const {
+ return cache_.find(cursor)->second->image();
+ }
+
private:
friend struct DefaultSingletonTraits<XCustomCursorCache>;
@@ -234,6 +203,10 @@ class XCustomCursorCache {
return false;
}
+ const XcursorImage* image() const {
+ return image_;
+ };
+
private:
XcursorImage* image_;
int ref_;
@@ -250,32 +223,9 @@ class XCustomCursorCache {
std::map< ::Cursor, XCustomCursor*> cache_;
DISALLOW_COPY_AND_ASSIGN(XCustomCursorCache);
};
-#endif // defined(USE_AURA)
-
-bool IsShapeAvailable() {
- int dummy;
- static bool is_shape_available =
- XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy);
- return is_shape_available;
-
-}
-
-// A list of bogus sizes in mm that X detects that should be ignored.
-// See crbug.com/136533. The first element maintains the minimum
-// size required to be valid size.
-const unsigned long kInvalidDisplaySizeList[][2] = {
- {40, 30},
- {50, 40},
- {160, 90},
- {160, 100},
-};
} // namespace
-bool XDisplayExists() {
- return (gfx::GetXDisplay() != NULL);
-}
-
bool IsXInput2Available() {
return DeviceDataManager::GetInstance()->IsXInput2Available();
}
@@ -317,7 +267,7 @@ static SharedMemorySupport DoQuerySharedMemorySupport(XDisplay* dpy) {
memset(&shminfo, 0, sizeof(shminfo));
shminfo.shmid = shmkey;
- base::X11ErrorTracker err_tracker;
+ gfx::X11ErrorTracker err_tracker;
bool result = XShmAttach(dpy, &shminfo);
if (result)
VLOG(1) << "X got shared memory segment " << shmkey;
@@ -350,38 +300,21 @@ SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy) {
return shared_memory_support;
}
-bool QueryRenderSupport(XDisplay* dpy) {
- static bool render_supported = false;
- static bool render_supported_cached = false;
-
- if (render_supported_cached)
- return render_supported;
-
+bool QueryRenderSupport(Display* dpy) {
+ int dummy;
// We don't care about the version of Xrender since all the features which
// we use are included in every version.
- int dummy;
- render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
- render_supported_cached = true;
+ static bool render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
return render_supported;
}
-int GetDefaultScreen(XDisplay* display) {
- return XDefaultScreen(display);
-}
-
::Cursor GetXCursor(int cursor_shape) {
if (!cursor_cache)
cursor_cache = new XCursorCache;
return cursor_cache->GetCursor(cursor_shape);
}
-void ResetXCursorCache() {
- delete cursor_cache;
- cursor_cache = NULL;
-}
-
-#if defined(USE_AURA)
::Cursor CreateReffedCustomXCursor(XcursorImage* image) {
return XCustomCursorCache::GetInstance()->InstallCustomCursor(image);
}
@@ -396,7 +329,7 @@ void UnrefCustomXCursor(::Cursor cursor) {
XcursorImage* SkBitmapToXcursorImage(const SkBitmap* cursor_image,
const gfx::Point& hotspot) {
- DCHECK(cursor_image->config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(cursor_image->colorType() == kPMColor_SkColorType);
gfx::Point hotspot_point = hotspot;
SkBitmap scaled;
@@ -507,7 +440,6 @@ int CoalescePendingMotionEvents(const XEvent* xev,
}
return num_coalesced;
}
-#endif
void HideHostCursor() {
CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
@@ -531,40 +463,51 @@ void HideHostCursor() {
return invisible_cursor;
}
-XID GetX11RootWindow() {
- return DefaultRootWindow(gfx::GetXDisplay());
-}
-
-bool GetCurrentDesktop(int* desktop) {
- return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
-}
-
-#if defined(TOOLKIT_GTK)
-XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
- return GDK_WINDOW_XID(gtk_widget_get_window(widget));
+void SetUseOSWindowFrame(XID window, bool use_os_window_frame) {
+ // This data structure represents additional hints that we send to the window
+ // manager and has a direct lineage back to Motif, which defined this de facto
+ // standard. This struct doesn't seem 64-bit safe though, but it's what GDK
+ // does.
+ typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long input_mode;
+ unsigned long status;
+ } MotifWmHints;
+
+ MotifWmHints motif_hints;
+ memset(&motif_hints, 0, sizeof(motif_hints));
+ // Signals that the reader of the _MOTIF_WM_HINTS property should pay
+ // attention to the value of |decorations|.
+ motif_hints.flags = (1L << 1);
+ motif_hints.decorations = use_os_window_frame ? 1 : 0;
+
+ ::Atom hint_atom = GetAtom("_MOTIF_WM_HINTS");
+ XChangeProperty(gfx::GetXDisplay(),
+ window,
+ hint_atom,
+ hint_atom,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&motif_hints),
+ sizeof(MotifWmHints)/sizeof(long));
}
-XID GetX11WindowFromGdkWindow(GdkWindow* window) {
- return GDK_WINDOW_XID(window);
+bool IsShapeExtensionAvailable() {
+ int dummy;
+ static bool is_shape_available =
+ XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy);
+ return is_shape_available;
}
-GtkWindow* GetGtkWindowFromX11Window(XID xid) {
- GdkWindow* gdk_window =
- gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);
- if (!gdk_window)
- return NULL;
- GtkWindow* gtk_window = NULL;
- gdk_window_get_user_data(gdk_window,
- reinterpret_cast<gpointer*>(&gtk_window));
- if (!gtk_window)
- return NULL;
- return gtk_window;
+XID GetX11RootWindow() {
+ return DefaultRootWindow(gfx::GetXDisplay());
}
-void* GetVisualFromGtkWidget(GtkWidget* widget) {
- return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
+bool GetCurrentDesktop(int* desktop) {
+ return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
}
-#endif // defined(TOOLKIT_GTK)
void SetHideTitlebarWhenMaximizedProperty(XID window,
HideTitlebarWhenMaximized property) {
@@ -608,6 +551,17 @@ bool IsWindowVisible(XID window) {
return false;
if (win_attributes.map_state != IsViewable)
return false;
+
+ // Minimized windows are not visible.
+ std::vector<Atom> wm_states;
+ if (GetAtomArrayProperty(window, "_NET_WM_STATE", &wm_states)) {
+ Atom hidden_atom = GetAtom("_NET_WM_STATE_HIDDEN");
+ if (std::find(wm_states.begin(), wm_states.end(), hidden_atom) !=
+ wm_states.end()) {
+ return false;
+ }
+ }
+
// Some compositing window managers (notably kwin) do not actually unmap
// windows on desktop switch, so we also must check the current desktop.
int window_desktop, current_desktop;
@@ -632,6 +586,15 @@ bool GetWindowRect(XID window, gfx::Rect* rect) {
return false;
*rect = gfx::Rect(x, y, width, height);
+
+ std::vector<int> insets;
+ if (GetIntArrayProperty(window, "_NET_FRAME_EXTENTS", &insets) &&
+ insets.size() == 4) {
+ rect->Inset(-insets[0], -insets[2], -insets[1], -insets[3]);
+ }
+ // Not all window managers support _NET_FRAME_EXTENTS so return true even if
+ // requesting the property fails.
+
return true;
}
@@ -646,7 +609,7 @@ bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
if (!window_rect.Contains(screen_loc))
return false;
- if (!IsShapeAvailable())
+ if (!IsShapeExtensionAvailable())
return true;
// According to http://www.x.org/releases/X11R7.6/doc/libXext/shapelib.html,
@@ -655,27 +618,47 @@ bool WindowContainsPoint(XID window, gfx::Point screen_loc) {
// rectangles. This means to determine if a point is inside a window for the
// purpose of input handling we have to check the rectangles in the ShapeInput
// list.
- int dummy;
- int input_rects_size = 0;
- XRectangle* input_rects = XShapeGetRectangles(
- gfx::GetXDisplay(), window, ShapeInput, &input_rects_size, &dummy);
- if (!input_rects)
- return true;
- bool is_in_input_rects = false;
- for (int i = 0; i < input_rects_size; ++i) {
- // The ShapeInput rects appear to be in window space, so we have to
- // translate by the window_rect's offset to map to screen space.
- gfx::Rect input_rect =
- gfx::Rect(input_rects[i].x + window_rect.x(),
- input_rects[i].y + window_rect.y(),
- input_rects[i].width, input_rects[i].height);
- if (input_rect.Contains(screen_loc)) {
- is_in_input_rects = true;
- break;
+ // According to http://www.x.org/releases/current/doc/xextproto/shape.html,
+ // we need to also respect the ShapeBounding rectangles.
+ // The effective input region of a window is defined to be the intersection
+ // of the client input region with both the default input region and the
+ // client bounding region. Any portion of the client input region that is not
+ // included in both the default input region and the client bounding region
+ // will not be included in the effective input region on the screen.
+ int rectangle_kind[] = {ShapeInput, ShapeBounding};
+ for (size_t kind_index = 0;
+ kind_index < arraysize(rectangle_kind);
+ kind_index++) {
+ int dummy;
+ int shape_rects_size = 0;
+ XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
+ window,
+ rectangle_kind[kind_index],
+ &shape_rects_size,
+ &dummy);
+ if (!shape_rects) {
+ // The shape is empty. This can occur when |window| is minimized.
+ DCHECK_EQ(0, shape_rects_size);
+ return false;
}
+ bool is_in_shape_rects = false;
+ for (int i = 0; i < shape_rects_size; ++i) {
+ // The ShapeInput and ShapeBounding rects are to be in window space, so we
+ // have to translate by the window_rect's offset to map to screen space.
+ gfx::Rect shape_rect =
+ gfx::Rect(shape_rects[i].x + window_rect.x(),
+ shape_rects[i].y + window_rect.y(),
+ shape_rects[i].width, shape_rects[i].height);
+ if (shape_rect.Contains(screen_loc)) {
+ is_in_shape_rects = true;
+ break;
+ }
+ }
+ XFree(shape_rects);
+ if (!is_in_shape_rects)
+ return false;
}
- XFree(input_rects);
- return is_in_input_rects;
+ return true;
}
@@ -891,7 +874,7 @@ bool SetIntArrayProperty(XID window,
for (size_t i = 0; i < value.size(); ++i)
data[i] = value[i];
- base::X11ErrorTracker err_tracker;
+ gfx::X11ErrorTracker err_tracker;
XChangeProperty(gfx::GetXDisplay(),
window,
name_atom,
@@ -903,6 +886,14 @@ bool SetIntArrayProperty(XID window,
return !err_tracker.FoundNewError();
}
+bool SetAtomProperty(XID window,
+ const std::string& name,
+ const std::string& type,
+ Atom value) {
+ std::vector<Atom> values(1, value);
+ return SetAtomArrayProperty(window, name, type, values);
+}
+
bool SetAtomArrayProperty(XID window,
const std::string& name,
const std::string& type,
@@ -916,7 +907,7 @@ bool SetAtomArrayProperty(XID window,
for (size_t i = 0; i < value.size(); ++i)
data[i] = value[i];
- base::X11ErrorTracker err_tracker;
+ gfx::X11ErrorTracker err_tracker;
XChangeProperty(gfx::GetXDisplay(),
window,
name_atom,
@@ -928,14 +919,25 @@ bool SetAtomArrayProperty(XID window,
return !err_tracker.FoundNewError();
}
+bool SetStringProperty(XID window,
+ Atom property,
+ Atom type,
+ const std::string& value) {
+ gfx::X11ErrorTracker err_tracker;
+ XChangeProperty(gfx::GetXDisplay(),
+ window,
+ property,
+ type,
+ 8,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(value.c_str()),
+ value.size());
+ return !err_tracker.FoundNewError();
+}
+
Atom GetAtom(const char* name) {
-#if defined(TOOLKIT_GTK)
- return gdk_x11_get_xatom_by_name_for_display(
- gdk_display_get_default(), name);
-#else
// TODO(derat): Cache atoms to avoid round-trips to the server.
return XInternAtom(gfx::GetXDisplay(), name, false);
-#endif
}
void SetWindowClassHint(XDisplay* display,
@@ -963,26 +965,24 @@ void SetWindowRole(XDisplay* display, XID window, const std::string& role) {
}
}
-XID GetParentWindow(XID window) {
- XID root = None;
- XID parent = None;
- XID* children = NULL;
- unsigned int num_children = 0;
- XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children, &num_children);
- if (children)
- XFree(children);
- return parent;
-}
-
-XID GetHighestAncestorWindow(XID window, XID root) {
- while (true) {
- XID parent = GetParentWindow(window);
- if (parent == None)
- return None;
- if (parent == root)
- return window;
- window = parent;
- }
+bool GetCustomFramePrefDefault() {
+ // Ideally, we'd use the custom frame by default and just fall back on using
+ // system decorations for the few (?) tiling window managers where the custom
+ // frame doesn't make sense (e.g. awesome, ion3, ratpoison, xmonad, etc.) or
+ // other WMs where it has issues (e.g. Fluxbox -- see issue 19130). The EWMH
+ // _NET_SUPPORTING_WM property makes it easy to look up a name for the current
+ // WM, but at least some of the WMs in the latter group don't set it.
+ // Instead, we default to using system decorations for all WMs and
+ // special-case the ones where the custom frame should be used.
+ ui::WindowManagerName wm_type = GuessWindowManager();
+ return (wm_type == WM_BLACKBOX ||
+ wm_type == WM_COMPIZ ||
+ wm_type == WM_ENLIGHTENMENT ||
+ wm_type == WM_METACITY ||
+ wm_type == WM_MUFFIN ||
+ wm_type == WM_MUTTER ||
+ wm_type == WM_OPENBOX ||
+ wm_type == WM_XFWM4);
}
bool GetWindowDesktop(XID window, int* desktop) {
@@ -1010,6 +1010,18 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
if (depth > max_depth)
return false;
+ std::vector<XID> windows;
+ std::vector<XID>::iterator iter;
+ if (depth == 0) {
+ XMenuList::GetInstance()->InsertMenuWindowXIDs(&windows);
+ // Enumerate the menus first.
+ for (iter = windows.begin(); iter != windows.end(); iter++) {
+ if (delegate->ShouldStopIterating(*iter))
+ return true;
+ }
+ windows.clear();
+ }
+
XID root, parent, *children;
unsigned int num_children;
int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children,
@@ -1017,7 +1029,6 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
if (status == 0)
return false;
- std::vector<XID> windows;
for (int i = static_cast<int>(num_children) - 1; i >= 0; i--)
windows.push_back(children[i]);
@@ -1025,7 +1036,6 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
// XQueryTree returns the children of |window| in bottom-to-top order, so
// reverse-iterate the list to check the windows from top-to-bottom.
- std::vector<XID>::iterator iter;
for (iter = windows.begin(); iter != windows.end(); iter++) {
if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
return true;
@@ -1061,6 +1071,7 @@ void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
return;
}
+ XMenuList::GetInstance()->InsertMenuWindowXIDs(&stack);
std::vector<XID>::iterator iter;
for (iter = stack.begin(); iter != stack.end(); iter++) {
@@ -1100,45 +1111,6 @@ bool GetXWindowStack(Window window, std::vector<XID>* windows) {
return result;
}
-void RestackWindow(XID window, XID sibling, bool above) {
- XWindowChanges changes;
- changes.sibling = sibling;
- changes.stack_mode = above ? Above : Below;
- XConfigureWindow(gfx::GetXDisplay(), window, CWSibling | CWStackMode, &changes);
-}
-
-XSharedMemoryId AttachSharedMemory(XDisplay* display, int shared_memory_key) {
- DCHECK(QuerySharedMemorySupport(display));
-
- XShmSegmentInfo shminfo;
- memset(&shminfo, 0, sizeof(shminfo));
- shminfo.shmid = shared_memory_key;
-
- // This function is only called if QuerySharedMemorySupport returned true. In
- // which case we've already succeeded in having the X server attach to one of
- // our shared memory segments.
- if (!XShmAttach(display, &shminfo)) {
- LOG(WARNING) << "X failed to attach to shared memory segment "
- << shminfo.shmid;
- NOTREACHED();
- } else {
- VLOG(1) << "X attached to shared memory segment " << shminfo.shmid;
- }
-
- return shminfo.shmseg;
-}
-
-void DetachSharedMemory(XDisplay* display, XSharedMemoryId shmseg) {
- DCHECK(QuerySharedMemorySupport(display));
-
- XShmSegmentInfo shminfo;
- memset(&shminfo, 0, sizeof(shminfo));
- shminfo.shmseg = shmseg;
-
- if (!XShmDetach(display, &shminfo))
- NOTREACHED();
-}
-
bool CopyAreaToCanvas(XID drawable,
gfx::Rect source_bounds,
gfx::Point dest_offset,
@@ -1172,10 +1144,9 @@ bool CopyAreaToCanvas(XID drawable,
image->data[i + 3] = 0xff;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- image->width, image->height,
- image->bytes_per_line);
- bitmap.setPixels(image->data);
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(image->width,
+ image->height),
+ image->data, image->bytes_per_line);
gfx::ImageSkia image_skia;
gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
image_skia.AddRepresentation(image_rep);
@@ -1188,21 +1159,6 @@ bool CopyAreaToCanvas(XID drawable,
return true;
}
-XID CreatePictureFromSkiaPixmap(XDisplay* display, XID pixmap) {
- XID picture = XRenderCreatePicture(
- display, pixmap, GetRenderARGB32Format(display), 0, NULL);
-
- return picture;
-}
-
-void FreePicture(XDisplay* display, XID picture) {
- XRenderFreePicture(display, picture);
-}
-
-void FreePixmap(XDisplay* display, XID pixmap) {
- XFreePixmap(display, pixmap);
-}
-
bool GetWindowManagerName(std::string* wm_name) {
DCHECK(wm_name);
int wm_window = 0;
@@ -1221,7 +1177,7 @@ bool GetWindowManagerName(std::string* wm_name) {
// _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
// property referencing an ID that's been recycled for another window), so we
// check that too.
- base::X11ErrorTracker err_tracker;
+ gfx::X11ErrorTracker err_tracker;
int wm_window_property = 0;
bool result = GetIntProperty(
wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
@@ -1267,29 +1223,6 @@ WindowManagerName GuessWindowManager() {
return WM_UNKNOWN;
}
-bool ChangeWindowDesktop(XID window, XID destination) {
- int desktop;
- if (!GetWindowDesktop(destination, &desktop))
- return false;
-
- // If |window| is sticky, use the current desktop.
- if (desktop == kAllDesktops &&
- !GetCurrentDesktop(&desktop))
- return false;
-
- XEvent event;
- event.xclient.type = ClientMessage;
- event.xclient.window = window;
- event.xclient.message_type = GetAtom("_NET_WM_DESKTOP");
- event.xclient.format = 32;
- event.xclient.data.l[0] = desktop;
- event.xclient.data.l[1] = 1; // source indication
-
- int result = XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), False,
- SubstructureNotifyMask, &event);
- return result == Success;
-}
-
void SetDefaultX11ErrorHandlers() {
SetX11ErrorHandlers(NULL, NULL);
}
@@ -1298,21 +1231,16 @@ bool IsX11WindowFullScreen(XID window) {
// If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or
// absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine
// whether we're fullscreen.
- std::vector<Atom> supported_atoms;
- if (GetAtomArrayProperty(GetX11RootWindow(),
- "_NET_SUPPORTED",
- &supported_atoms)) {
- Atom atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
-
- if (std::find(supported_atoms.begin(), supported_atoms.end(), atom)
- != supported_atoms.end()) {
- std::vector<Atom> atom_properties;
- if (GetAtomArrayProperty(window,
- "_NET_WM_STATE",
- &atom_properties)) {
- return std::find(atom_properties.begin(), atom_properties.end(), atom)
- != atom_properties.end();
- }
+ Atom fullscreen_atom = GetAtom("_NET_WM_STATE_FULLSCREEN");
+ if (WmSupportsHint(fullscreen_atom)) {
+ std::vector<Atom> atom_properties;
+ if (GetAtomArrayProperty(window,
+ "_NET_WM_STATE",
+ &atom_properties)) {
+ return std::find(atom_properties.begin(),
+ atom_properties.end(),
+ fullscreen_atom) !=
+ atom_properties.end();
}
}
@@ -1320,17 +1248,6 @@ bool IsX11WindowFullScreen(XID window) {
if (!ui::GetWindowRect(window, &window_rect))
return false;
-#if defined(TOOLKIT_GTK)
- // As the last resort, check if the window size is as large as the main
- // screen.
- GdkRectangle monitor_rect;
- gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect);
-
- return monitor_rect.x == window_rect.x() &&
- monitor_rect.y == window_rect.y() &&
- monitor_rect.width == window_rect.width() &&
- monitor_rect.height == window_rect.height();
-#else
// We can't use gfx::Screen here because we don't have an aura::Window. So
// instead just look at the size of the default display.
//
@@ -1341,26 +1258,18 @@ bool IsX11WindowFullScreen(XID window) {
int width = WidthOfScreen(screen);
int height = HeightOfScreen(screen);
return window_rect.size() == gfx::Size(width, height);
-#endif
}
-bool IsXDisplaySizeBlackListed(unsigned long mm_width,
- unsigned long mm_height) {
- // Ignore if the reported display is smaller than minimum size.
- if (mm_width <= kInvalidDisplaySizeList[0][0] ||
- mm_height <= kInvalidDisplaySizeList[0][1]) {
- LOG(WARNING) << "Smaller than minimum display size";
- return true;
- }
- for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
- const unsigned long* size = kInvalidDisplaySizeList[i];
- if (mm_width == size[0] && mm_height == size[1]) {
- LOG(WARNING) << "Black listed display size detected:"
- << size[0] << "x" << size[1];
- return true;
- }
+bool WmSupportsHint(Atom atom) {
+ std::vector<Atom> supported_atoms;
+ if (!GetAtomArrayProperty(GetX11RootWindow(),
+ "_NET_SUPPORTED",
+ &supported_atoms)) {
+ return false;
}
- return false;
+
+ return std::find(supported_atoms.begin(), supported_atoms.end(), atom) !=
+ supported_atoms.end();
}
const unsigned char* XRefcountedMemory::front() const {
@@ -1410,6 +1319,18 @@ void XScopedCursor::reset(::Cursor cursor) {
cursor_ = cursor;
}
+namespace test {
+
+void ResetXCursorCache() {
+ delete cursor_cache;
+ cursor_cache = NULL;
+}
+
+const XcursorImage* GetCachedXcursorImage(::Cursor cursor) {
+ return XCustomCursorCache::GetInstance()->GetXcursorImage(cursor);
+}
+}
+
// ----------------------------------------------------------------------------
// These functions are declared in x11_util_internal.h because they require
// XLib.h to be included, and it conflicts with many other headers.
@@ -1449,43 +1370,6 @@ XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) {
return pictformat;
}
-XRenderPictFormat* GetRenderVisualFormat(XDisplay* dpy, Visual* visual) {
- DCHECK(QueryRenderSupport(dpy));
-
- CachedPictFormats* formats = get_cached_pict_formats();
-
- for (CachedPictFormats::const_iterator i = formats->begin();
- i != formats->end(); ++i) {
- if (i->equals(dpy, visual))
- return i->format;
- }
-
- // Not cached, look up the value.
- XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
- CHECK(pictformat) << "XRENDER does not support default visual";
-
- // And store it in the cache.
- CachedPictFormat cached_value;
- cached_value.visual = visual;
- cached_value.display = dpy;
- cached_value.format = pictformat;
- formats->push_front(cached_value);
-
- if (formats->size() == kMaxCacheSize) {
- formats->pop_back();
- // We should really only have at most 2 display/visual combinations:
- // one for normal browser windows, and possibly another for an argb window
- // created to display a menu.
- //
- // If we get here it's not fatal, we just need to make sure we aren't
- // always blowing away the cache. If we are, then we should figure out why
- // and make it bigger.
- NOTREACHED();
- }
-
- return pictformat;
-}
-
void SetX11ErrorHandlers(XErrorHandler error_handler,
XIOErrorHandler io_error_handler) {
XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h
index 62aea96512c..093193f6d27 100644
--- a/chromium/ui/base/x/x11_util.h
+++ b/chromium/ui/base/x/x11_util.h
@@ -17,7 +17,7 @@
#include "base/basictypes.h"
#include "base/event_types.h"
#include "base/memory/ref_counted_memory.h"
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/point.h"
@@ -29,12 +29,6 @@ typedef unsigned long Cursor;
typedef struct _XcursorImage XcursorImage;
typedef union _XEvent XEvent;
-#if defined(TOOLKIT_GTK)
-typedef struct _GdkDrawable GdkWindow;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _GtkWindow GtkWindow;
-#endif
-
namespace gfx {
class Canvas;
class Point;
@@ -49,11 +43,8 @@ namespace ui {
// These functions cache their results ---------------------------------
-// Check if there's an open connection to an X server.
-UI_EXPORT bool XDisplayExists();
-
// Returns true if the system supports XINPUT2.
-UI_EXPORT bool IsXInput2Available();
+UI_BASE_EXPORT bool IsXInput2Available();
// X shared memory comes in three flavors:
// 1) No SHM support,
@@ -65,102 +56,85 @@ enum SharedMemorySupport {
SHARED_MEMORY_PIXMAP
};
// Return the shared memory type of our X connection.
-UI_EXPORT SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy);
+UI_BASE_EXPORT SharedMemorySupport QuerySharedMemorySupport(XDisplay* dpy);
// Return true iff the display supports Xrender
-UI_EXPORT bool QueryRenderSupport(XDisplay* dpy);
-
-// Return the default screen number for the display
-int GetDefaultScreen(XDisplay* display);
+UI_BASE_EXPORT bool QueryRenderSupport(XDisplay* dpy);
// Returns an X11 Cursor, sharable across the process.
// |cursor_shape| is an X font cursor shape, see XCreateFontCursor().
-UI_EXPORT ::Cursor GetXCursor(int cursor_shape);
-
-// Resets the cache used by GetXCursor(). Only useful for tests that may delete
-// the display.
-UI_EXPORT void ResetXCursorCache();
+UI_BASE_EXPORT ::Cursor GetXCursor(int cursor_shape);
-#if defined(USE_AURA)
// Creates a custom X cursor from the image. This takes ownership of image. The
// caller must not free/modify the image. The refcount of the newly created
// cursor is set to 1.
-UI_EXPORT ::Cursor CreateReffedCustomXCursor(XcursorImage* image);
+UI_BASE_EXPORT ::Cursor CreateReffedCustomXCursor(XcursorImage* image);
// Increases the refcount of the custom cursor.
-UI_EXPORT void RefCustomXCursor(::Cursor cursor);
+UI_BASE_EXPORT void RefCustomXCursor(::Cursor cursor);
// Decreases the refcount of the custom cursor, and destroys it if it reaches 0.
-UI_EXPORT void UnrefCustomXCursor(::Cursor cursor);
+UI_BASE_EXPORT void UnrefCustomXCursor(::Cursor cursor);
// Creates a XcursorImage and copies the SkBitmap |bitmap| on it. |bitmap|
// should be non-null. Caller owns the returned object.
-UI_EXPORT XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap,
- const gfx::Point& hotspot);
+UI_BASE_EXPORT XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap,
+ const gfx::Point& hotspot);
// Coalesce all pending motion events (touch or mouse) that are at the top of
// the queue, and return the number eliminated, storing the last one in
// |last_event|.
-UI_EXPORT int CoalescePendingMotionEvents(const XEvent* xev,
- XEvent* last_event);
-#endif
+UI_BASE_EXPORT int CoalescePendingMotionEvents(const XEvent* xev,
+ XEvent* last_event);
// Hides the host cursor.
-UI_EXPORT void HideHostCursor();
+UI_BASE_EXPORT void HideHostCursor();
// Returns an invisible cursor.
-UI_EXPORT ::Cursor CreateInvisibleCursor();
+UI_BASE_EXPORT ::Cursor CreateInvisibleCursor();
+
+// Sets whether |window| should use the OS window frame.
+UI_BASE_EXPORT void SetUseOSWindowFrame(XID window, bool use_os_window_frame);
// These functions do not cache their results --------------------------
+// Returns true if the shape extension is supported.
+UI_BASE_EXPORT bool IsShapeExtensionAvailable();
+
// Get the X window id for the default root window
-UI_EXPORT XID GetX11RootWindow();
+UI_BASE_EXPORT XID GetX11RootWindow();
// Returns the user's current desktop.
-bool GetCurrentDesktop(int* desktop);
-
-#if defined(TOOLKIT_GTK)
-// Get the X window id for the given GTK widget.
-UI_EXPORT XID GetX11WindowFromGtkWidget(GtkWidget* widget);
-XID GetX11WindowFromGdkWindow(GdkWindow* window);
-
-// Get the GtkWindow* wrapping a given XID, if any.
-// Returns NULL if there isn't already a GtkWindow* wrapping this XID;
-// see gdk_window_foreign_new() etc. to wrap arbitrary XIDs.
-UI_EXPORT GtkWindow* GetGtkWindowFromX11Window(XID xid);
-
-// Get a Visual from the given widget. Since we don't include the Xlib
-// headers, this is returned as a void*.
-UI_EXPORT void* GetVisualFromGtkWidget(GtkWidget* widget);
-#endif // defined(TOOLKIT_GTK)
+UI_BASE_EXPORT bool GetCurrentDesktop(int* desktop);
enum HideTitlebarWhenMaximized {
SHOW_TITLEBAR_WHEN_MAXIMIZED = 0,
HIDE_TITLEBAR_WHEN_MAXIMIZED = 1,
};
// Sets _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED on |window|.
-UI_EXPORT void SetHideTitlebarWhenMaximizedProperty(
+UI_BASE_EXPORT void SetHideTitlebarWhenMaximizedProperty(
XID window,
HideTitlebarWhenMaximized property);
// Clears all regions of X11's default root window by filling black pixels.
-UI_EXPORT void ClearX11DefaultRootWindow();
+UI_BASE_EXPORT void ClearX11DefaultRootWindow();
// Returns true if |window| is visible.
-UI_EXPORT bool IsWindowVisible(XID window);
+UI_BASE_EXPORT bool IsWindowVisible(XID window);
// Returns the bounds of |window|.
-UI_EXPORT bool GetWindowRect(XID window, gfx::Rect* rect);
+UI_BASE_EXPORT bool GetWindowRect(XID window, gfx::Rect* rect);
// Returns true if |window| contains the point |screen_loc|.
-UI_EXPORT bool WindowContainsPoint(XID window, gfx::Point screen_loc);
+UI_BASE_EXPORT bool WindowContainsPoint(XID window, gfx::Point screen_loc);
// Return true if |window| has any property with |property_name|.
-UI_EXPORT bool PropertyExists(XID window, const std::string& property_name);
+UI_BASE_EXPORT bool PropertyExists(XID window,
+ const std::string& property_name);
// Returns the raw bytes from a property with minimal
// interpretation. |out_data| should be freed by XFree() after use.
-UI_EXPORT bool GetRawBytesOfProperty(
+UI_BASE_EXPORT bool GetRawBytesOfProperty(
XID window,
Atom property,
scoped_refptr<base::RefCountedMemory>* out_data,
@@ -173,51 +147,61 @@ UI_EXPORT bool GetRawBytesOfProperty(
//
// TODO(erg): Once we remove the gtk port and are 100% aura, all of these
// should accept an Atom instead of a string.
-UI_EXPORT bool GetIntProperty(XID window, const std::string& property_name,
- int* value);
-UI_EXPORT bool GetXIDProperty(XID window, const std::string& property_name,
- XID* value);
-UI_EXPORT bool GetIntArrayProperty(XID window, const std::string& property_name,
- std::vector<int>* value);
-UI_EXPORT bool GetAtomArrayProperty(XID window,
- const std::string& property_name,
- std::vector<Atom>* value);
-UI_EXPORT bool GetStringProperty(
- XID window, const std::string& property_name, std::string* value);
+UI_BASE_EXPORT bool GetIntProperty(XID window,
+ const std::string& property_name,
+ int* value);
+UI_BASE_EXPORT bool GetXIDProperty(XID window,
+ const std::string& property_name,
+ XID* value);
+UI_BASE_EXPORT bool GetIntArrayProperty(XID window,
+ const std::string& property_name,
+ std::vector<int>* value);
+UI_BASE_EXPORT bool GetAtomArrayProperty(XID window,
+ const std::string& property_name,
+ std::vector<Atom>* value);
+UI_BASE_EXPORT bool GetStringProperty(XID window,
+ const std::string& property_name,
+ std::string* value);
// These setters all make round trips.
-UI_EXPORT bool SetIntProperty(XID window,
- const std::string& name,
- const std::string& type,
- int value);
-UI_EXPORT bool SetIntArrayProperty(XID window,
+UI_BASE_EXPORT bool SetIntProperty(XID window,
const std::string& name,
const std::string& type,
- const std::vector<int>& value);
-UI_EXPORT bool SetAtomArrayProperty(XID window,
+ int value);
+UI_BASE_EXPORT bool SetIntArrayProperty(XID window,
+ const std::string& name,
+ const std::string& type,
+ const std::vector<int>& value);
+UI_BASE_EXPORT bool SetAtomProperty(XID window,
const std::string& name,
const std::string& type,
- const std::vector<Atom>& value);
+ Atom value);
+UI_BASE_EXPORT bool SetAtomArrayProperty(XID window,
+ const std::string& name,
+ const std::string& type,
+ const std::vector<Atom>& value);
+UI_BASE_EXPORT bool SetStringProperty(XID window,
+ Atom property,
+ Atom type,
+ const std::string& value);
// Gets the X atom for default display corresponding to atom_name.
-Atom GetAtom(const char* atom_name);
+UI_BASE_EXPORT Atom GetAtom(const char* atom_name);
// Sets the WM_CLASS attribute for a given X11 window.
-UI_EXPORT void SetWindowClassHint(XDisplay* display,
- XID window,
- const std::string& res_name,
- const std::string& res_class);
+UI_BASE_EXPORT void SetWindowClassHint(XDisplay* display,
+ XID window,
+ const std::string& res_name,
+ const std::string& res_class);
// Sets the WM_WINDOW_ROLE attribute for a given X11 window.
-UI_EXPORT void SetWindowRole(XDisplay* display,
- XID window,
- const std::string& role);
-
-// Get |window|'s parent window, or None if |window| is the root window.
-UI_EXPORT XID GetParentWindow(XID window);
+UI_BASE_EXPORT void SetWindowRole(XDisplay* display,
+ XID window,
+ const std::string& role);
-// Walk up |window|'s hierarchy until we find a direct child of |root|.
-XID GetHighestAncestorWindow(XID window, XID root);
+// Determine whether we should default to native decorations or the custom
+// frame based on the currently-running window manager.
+UI_BASE_EXPORT bool GetCustomFramePrefDefault();
static const int kAllDesktops = -1;
// Queries the desktop |window| is on, kAllDesktops if sticky. Returns false if
@@ -225,7 +209,7 @@ static const int kAllDesktops = -1;
bool GetWindowDesktop(XID window, int* desktop);
// Translates an X11 error code into a printable string.
-UI_EXPORT std::string GetX11ErrorString(XDisplay* display, int err);
+UI_BASE_EXPORT std::string GetX11ErrorString(XDisplay* display, int err);
// Implementers of this interface receive a notification for every X window of
// the main display.
@@ -241,44 +225,26 @@ class EnumerateWindowsDelegate {
// Enumerates all windows in the current display. Will recurse into child
// windows up to a depth of |max_depth|.
-UI_EXPORT bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate,
- int max_depth);
+UI_BASE_EXPORT bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate,
+ int max_depth);
// Enumerates the top-level windows of the current display.
-UI_EXPORT void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate);
+UI_BASE_EXPORT void EnumerateTopLevelWindows(
+ ui::EnumerateWindowsDelegate* delegate);
// Returns all children windows of a given window in top-to-bottom stacking
// order.
-UI_EXPORT bool GetXWindowStack(XID window, std::vector<XID>* windows);
-
-// Restack a window in relation to one of its siblings. If |above| is true,
-// |window| will be stacked directly above |sibling|; otherwise it will stacked
-// directly below it. Both windows must be immediate children of the same
-// window.
-void RestackWindow(XID window, XID sibling, bool above);
-
-// Return a handle to a X ShmSeg. |shared_memory_key| is a SysV
-// IPC key. The shared memory region must contain 32-bit pixels.
-UI_EXPORT XSharedMemoryId AttachSharedMemory(XDisplay* display,
- int shared_memory_support);
-UI_EXPORT void DetachSharedMemory(XDisplay* display, XSharedMemoryId shmseg);
+UI_BASE_EXPORT bool GetXWindowStack(XID window, std::vector<XID>* windows);
// Copies |source_bounds| from |drawable| to |canvas| at offset |dest_offset|.
// |source_bounds| is in physical pixels, while |dest_offset| is relative to
// the canvas's scale. Note that this function is slow since it uses
// XGetImage() to copy the data from the X server to this process before
// copying it to |canvas|.
-UI_EXPORT bool CopyAreaToCanvas(XID drawable,
- gfx::Rect source_bounds,
- gfx::Point dest_offset,
- gfx::Canvas* canvas);
-
-// Return a handle to an XRender picture where |pixmap| is a handle to a
-// pixmap containing Skia ARGB data.
-UI_EXPORT XID CreatePictureFromSkiaPixmap(XDisplay* display, XID pixmap);
-
-void FreePicture(XDisplay* display, XID picture);
-void FreePixmap(XDisplay* display, XID pixmap);
+UI_BASE_EXPORT bool CopyAreaToCanvas(XID drawable,
+ gfx::Rect source_bounds,
+ gfx::Point dest_offset,
+ gfx::Canvas* canvas);
enum WindowManagerName {
WM_UNKNOWN,
@@ -296,33 +262,26 @@ enum WindowManagerName {
};
// Attempts to guess the window maager. Returns WM_UNKNOWN if we can't
// determine it for one reason or another.
-UI_EXPORT WindowManagerName GuessWindowManager();
-
-// Change desktop for |window| to the desktop of |destination| window.
-UI_EXPORT bool ChangeWindowDesktop(XID window, XID destination);
+UI_BASE_EXPORT WindowManagerName GuessWindowManager();
// Enable the default X error handlers. These will log the error and abort
// the process if called. Use SetX11ErrorHandlers() from x11_util_internal.h
// to set your own error handlers.
-UI_EXPORT void SetDefaultX11ErrorHandlers();
+UI_BASE_EXPORT void SetDefaultX11ErrorHandlers();
-// Return true if a given window is in full-screen mode.
-UI_EXPORT bool IsX11WindowFullScreen(XID window);
+// Returns true if a given window is in full-screen mode.
+UI_BASE_EXPORT bool IsX11WindowFullScreen(XID window);
-// Returns true if a given size is in list of bogus sizes in mm that X detects
-// that should be ignored.
-UI_EXPORT bool IsXDisplaySizeBlackListed(unsigned long mm_width,
- unsigned long mm_height);
+// Returns true if the window manager supports the given hint.
+UI_BASE_EXPORT bool WmSupportsHint(Atom atom);
// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
// object takes ownership over the passed in memory and will free it with the
// X11 allocator when done.
-class UI_EXPORT XRefcountedMemory : public base::RefCountedMemory {
+class UI_BASE_EXPORT XRefcountedMemory : public base::RefCountedMemory {
public:
XRefcountedMemory(unsigned char* x11_data, size_t length)
- : x11_data_(length ? x11_data : NULL),
- length_(length) {
- }
+ : x11_data_(length ? x11_data : NULL), length_(length) {}
// Overridden from RefCountedMemory:
virtual const unsigned char* front() const OVERRIDE;
@@ -339,7 +298,7 @@ class UI_EXPORT XRefcountedMemory : public base::RefCountedMemory {
// Keeps track of a string returned by an X function (e.g. XGetAtomName) and
// makes sure it's XFree'd.
-class UI_EXPORT XScopedString {
+class UI_BASE_EXPORT XScopedString {
public:
explicit XScopedString(char* str) : string_(str) {}
~XScopedString();
@@ -354,18 +313,14 @@ class UI_EXPORT XScopedString {
// Keeps track of an image returned by an X function (e.g. XGetImage) and
// makes sure it's XDestroyImage'd.
-class UI_EXPORT XScopedImage {
+class UI_BASE_EXPORT XScopedImage {
public:
explicit XScopedImage(XImage* image) : image_(image) {}
~XScopedImage();
- XImage* get() const {
- return image_;
- }
+ XImage* get() const { return image_; }
- XImage* operator->() const {
- return image_;
- }
+ XImage* operator->() const { return image_; }
void reset(XImage* image);
@@ -377,7 +332,7 @@ class UI_EXPORT XScopedImage {
// Keeps track of a cursor returned by an X function and makes sure it's
// XFreeCursor'd.
-class UI_EXPORT XScopedCursor {
+class UI_BASE_EXPORT XScopedCursor {
public:
// Keeps track of |cursor| created with |display|.
XScopedCursor(::Cursor cursor, XDisplay* display);
@@ -393,6 +348,16 @@ class UI_EXPORT XScopedCursor {
DISALLOW_COPY_AND_ASSIGN(XScopedCursor);
};
+namespace test {
+// Resets the cache used by GetXCursor(). Only useful for tests that may delete
+// the display.
+UI_BASE_EXPORT void ResetXCursorCache();
+
+// Returns the cached XcursorImage for |cursor|.
+UI_BASE_EXPORT const XcursorImage* GetCachedXcursorImage(::Cursor cursor);
+
+} // namespace test
+
} // namespace ui
#endif // UI_BASE_X_X11_UTIL_H_
diff --git a/chromium/ui/base/x/x11_util_internal.h b/chromium/ui/base/x/x11_util_internal.h
index b6816c70fff..f663fc5ac87 100644
--- a/chromium/ui/base/x/x11_util_internal.h
+++ b/chromium/ui/base/x/x11_util_internal.h
@@ -12,13 +12,13 @@
// when needed.
extern "C" {
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/XShm.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#include <X11/extensions/Xrender.h>
}
-#include "ui/base/ui_export.h"
+#include "ui/base/ui_base_export.h"
namespace ui {
@@ -28,26 +28,21 @@ namespace ui {
// Get the XRENDER format id for ARGB32 (Skia's format).
//
// NOTE:Currently this don't support multiple screens/displays.
-XRenderPictFormat* GetRenderARGB32Format(Display* dpy);
-
-// Get the XRENDER format id for the default visual on the first screen. This
-// is the format which our GTK window will have.
-UI_EXPORT XRenderPictFormat* GetRenderVisualFormat(Display* dpy,
- Visual* visual);
+UI_BASE_EXPORT XRenderPictFormat* GetRenderARGB32Format(Display* dpy);
// --------------------------------------------------------------------------
// X11 error handling.
// Sets the X Error Handlers. Passing NULL for either will enable the default
// error handler, which if called will log the error and abort the process.
-UI_EXPORT void SetX11ErrorHandlers(XErrorHandler error_handler,
- XIOErrorHandler io_error_handler);
+UI_BASE_EXPORT void SetX11ErrorHandlers(XErrorHandler error_handler,
+ XIOErrorHandler io_error_handler);
// NOTE: This function should not be called directly from the
// X11 Error handler because it queries the server to decode the
// error message, which may trigger other errors. A suitable workaround
// is to post a task in the error handler to call this function.
-UI_EXPORT void LogErrorEventDescription(Display* dpy,
- const XErrorEvent& error_event);
+UI_BASE_EXPORT void LogErrorEventDescription(Display* dpy,
+ const XErrorEvent& error_event);
} // namespace ui
diff --git a/chromium/ui/base/x/x11_util_unittest.cc b/chromium/ui/base/x/x11_util_unittest.cc
deleted file mode 100644
index 01947266e10..00000000000
--- a/chromium/ui/base/x/x11_util_unittest.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/x/x11_util.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-typedef testing::Test XUtilTest;
-
-namespace ui {
-
-TEST_F(XUtilTest, TestBlackListedDisplay) {
- EXPECT_TRUE(IsXDisplaySizeBlackListed(10, 10));
- EXPECT_TRUE(IsXDisplaySizeBlackListed(40, 30));
- EXPECT_TRUE(IsXDisplaySizeBlackListed(50, 40));
- EXPECT_TRUE(IsXDisplaySizeBlackListed(160, 90));
- EXPECT_TRUE(IsXDisplaySizeBlackListed(160, 100));
-
- EXPECT_FALSE(IsXDisplaySizeBlackListed(50, 60));
- EXPECT_FALSE(IsXDisplaySizeBlackListed(100, 70));
- EXPECT_FALSE(IsXDisplaySizeBlackListed(272, 181));
-}
-
-}
diff --git a/chromium/ui/chromeos/ui_chromeos.gyp b/chromium/ui/chromeos/ui_chromeos.gyp
new file mode 100644
index 00000000000..9a87672bfac
--- /dev/null
+++ b/chromium/ui/chromeos/ui_chromeos.gyp
@@ -0,0 +1,31 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ui_chromeos',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../aura/aura.gyp:aura',
+ '../events/events.gyp:events',
+ '../wm/wm.gyp:wm',
+ ],
+ 'defines': [
+ 'UI_CHROMEOS_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'touch_exploration_controller.cc',
+ 'touch_exploration_controller.h',
+ 'user_activity_power_manager_notifier.cc',
+ 'user_activity_power_manager_notifier.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/compositor/BUILD.gn b/chromium/ui/compositor/BUILD.gn
new file mode 100644
index 00000000000..950b9ab55c0
--- /dev/null
+++ b/chromium/ui/compositor/BUILD.gn
@@ -0,0 +1,153 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("compositor") {
+ sources = [
+ "compositor.cc",
+ "compositor.h",
+ "compositor_export.h",
+ "compositor_observer.h",
+ "compositor_vsync_manager.cc",
+ "compositor_vsync_manager.h",
+ "compositor_switches.cc",
+ "compositor_switches.h",
+ "debug_utils.cc",
+ "debug_utils.h",
+ "dip_util.cc",
+ "dip_util.h",
+ "float_animation_curve_adapter.cc",
+ "float_animation_curve_adapter.h",
+ "layer.cc",
+ "layer.h",
+ "layer_animation_delegate.h",
+ "layer_animation_element.cc",
+ "layer_animation_element.h",
+ "layer_animation_observer.cc",
+ "layer_animation_observer.h",
+ "layer_animation_sequence.cc",
+ "layer_animation_sequence.h",
+ "layer_animator.cc",
+ "layer_animator.h",
+ "layer_delegate.h",
+ "layer_owner.cc",
+ "layer_owner.h",
+ "layer_tree_owner.cc",
+ "layer_tree_owner.h",
+ "layer_type.h",
+ "reflector.h",
+ "scoped_animation_duration_scale_mode.cc",
+ "scoped_animation_duration_scale_mode.h",
+ "scoped_layer_animation_settings.cc",
+ "scoped_layer_animation_settings.h",
+ "transform_animation_curve_adapter.cc",
+ "transform_animation_curve_adapter.h",
+ ]
+
+ defines = [ "COMPOSITOR_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//cc",
+ "//gpu/command_buffer/common",
+ "//skia",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ ]
+
+ if (is_win && use_aura) {
+ # TODO(sky): before we make this real need to remove
+ # IDR_BITMAP_BRUSH_IMAGE.
+ deps += [
+ "//ui/resources",
+ "//third_party/angle:libEGL",
+ "//third_party/angle:libGLESv2",
+ ]
+ }
+}
+
+source_set("test_support") {
+ sources = [
+ "test/context_factories_for_test.cc",
+ "test/context_factories_for_test.h",
+ "test/draw_waiter_for_test.cc",
+ "test/draw_waiter_for_test.h",
+ "test/in_process_context_factory.cc",
+ "test/in_process_context_factory.h",
+ "test/layer_animator_test_controller.cc",
+ "test/layer_animator_test_controller.h",
+ "test/test_compositor_host.h",
+ "test/test_compositor_host_mac.mm",
+ "test/test_compositor_host_ozone.cc",
+ "test/test_compositor_host_win.cc",
+ "test/test_compositor_host_x11.cc",
+ "test/test_layer_animation_delegate.cc",
+ "test/test_layer_animation_delegate.h",
+ "test/test_layer_animation_observer.cc",
+ "test/test_layer_animation_observer.h",
+ "test/test_layers.cc",
+ "test/test_layers.h",
+ "test/test_suite.cc",
+ "test/test_suite.h",
+ "test/test_utils.cc",
+ "test/test_utils.h",
+ ]
+
+ deps = [
+ ":compositor",
+ "//base",
+ "//cc",
+ "//cc:test_support",
+ "//skia",
+ "//testing/gtest",
+ #"//third_party/WebKit/public:blink_minimal", TODO(GYP)
+ "//ui/base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ #'<(DEPTH)/webkit/common/gpu/webkit_gpu.gyp:webkit_gpu', TODO(GYP)
+ ]
+
+ if (use_x11) {
+ configs += [ "//build/config/linux:x11" ]
+ deps += [ "//ui/gfx:gfx_x11" ]
+ }
+}
+
+# TODO(GYP) enable this when all dependencies are complete and it links.
+#test("compositor_unittests") {
+# sources = [
+# "layer_animation_element_unittest.cc",
+# "layer_animation_sequence_unittest.cc",
+# "layer_animator_unittest.cc",
+# "layer_owner_unittest.cc",
+# "layer_unittest.cc",
+# "run_all_unittests.cc",
+# "transform_animation_curve_adapter_unittest.cc",
+# ]
+#
+# deps = [
+# ":compositor",
+# ":test_support",
+# "//base",
+# "//base/allocator",
+# "//base/test:test_support",
+# "//cc",
+# "//cc:test_support",
+# "//skia",
+# "//testing/gtest",
+# "//ui/base",
+# "//ui/gfx",
+# "//ui/gfx/geometry",
+# "//ui/gl",
+# "//ui/resources",
+# ]
+#
+# if (is_linux) {
+# #deps += [ "//third_party/mesa:osmesa" ] # TODO(GYP)
+# }
+#}
diff --git a/chromium/ui/compositor/DEPS b/chromium/ui/compositor/DEPS
index 80761f96e6f..176fdc82b12 100644
--- a/chromium/ui/compositor/DEPS
+++ b/chromium/ui/compositor/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+cc",
+ "-cc/surfaces",
"+gpu/command_buffer/client/gles2_interface.h",
"+third_party/skia",
"+ui/gfx",
diff --git a/chromium/ui/compositor/PRESUBMIT.py b/chromium/ui/compositor/PRESUBMIT.py
index 8f465d0e0ee..d99d85dcccf 100644
--- a/chromium/ui/compositor/PRESUBMIT.py
+++ b/chromium/ui/compositor/PRESUBMIT.py
@@ -8,5 +8,9 @@ See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details on the presubmit API built into gcl.
"""
-def GetPreferredTrySlaves():
- return ['linux_chromeos']
+def GetPreferredTryMasters(project, change):
+ return {
+ 'tryserver.chromium': {
+ 'linux_chromium_chromeos_rel': set(['defaulttests']),
+ }
+ }
diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc
index 76e09c45667..190a949b3fd 100644
--- a/chromium/ui/compositor/compositor.cc
+++ b/chromium/ui/compositor/compositor.cc
@@ -10,14 +10,10 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
-#include "base/memory/singleton.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
-#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
#include "cc/base/latency_info_swap_promise.h"
#include "cc/base/switches.h"
#include "cc/input/input_handler.h"
@@ -27,8 +23,10 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/compositor_switches.h"
+#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator_collection.h"
#include "ui/gfx/frame_time.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_switches.h"
@@ -38,64 +36,12 @@ namespace {
const double kDefaultRefreshRate = 60.0;
const double kTestRefreshRate = 200.0;
-enum SwapType {
- DRAW_SWAP,
- READPIXELS_SWAP,
-};
-
-bool g_compositor_initialized = false;
-base::Thread* g_compositor_thread = NULL;
-
-ui::ContextFactory* g_context_factory = NULL;
-
const int kCompositorLockTimeoutMs = 67;
-class PendingSwap {
- public:
- PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
- ~PendingSwap();
-
- SwapType type() const { return type_; }
- bool posted() const { return posted_; }
-
- private:
- friend class ui::PostedSwapQueue;
-
- SwapType type_;
- bool posted_;
- ui::PostedSwapQueue* posted_swaps_;
-
- DISALLOW_COPY_AND_ASSIGN(PendingSwap);
-};
-
} // namespace
namespace ui {
-// static
-ContextFactory* ContextFactory::GetInstance() {
- DCHECK(g_context_factory);
- return g_context_factory;
-}
-
-// static
-void ContextFactory::SetInstance(ContextFactory* instance) {
- g_context_factory = instance;
-}
-
-Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
- : size_(size),
- flipped_(flipped),
- device_scale_factor_(device_scale_factor) {
-}
-
-Texture::~Texture() {
-}
-
-std::string Texture::Produce() {
- return std::string();
-}
-
CompositorLock::CompositorLock(Compositor* compositor)
: compositor_(compositor) {
base::MessageLoop::current()->PostDelayedTask(
@@ -115,157 +61,52 @@ void CompositorLock::CancelLock() {
compositor_ = NULL;
}
-// static
-void DrawWaiterForTest::Wait(Compositor* compositor) {
- DrawWaiterForTest waiter;
- waiter.wait_for_commit_ = false;
- waiter.WaitImpl(compositor);
-}
-
-// static
-void DrawWaiterForTest::WaitForCommit(Compositor* compositor) {
- DrawWaiterForTest waiter;
- waiter.wait_for_commit_ = true;
- waiter.WaitImpl(compositor);
-}
-
-DrawWaiterForTest::DrawWaiterForTest() {
-}
-
-DrawWaiterForTest::~DrawWaiterForTest() {
-}
-
-void DrawWaiterForTest::WaitImpl(Compositor* compositor) {
- compositor->AddObserver(this);
- wait_run_loop_.reset(new base::RunLoop());
- wait_run_loop_->Run();
- compositor->RemoveObserver(this);
-}
-
-void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) {
- if (wait_for_commit_)
- wait_run_loop_->Quit();
-}
-
-void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor,
- base::TimeTicks start_time) {
-}
-
-void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) {
- if (!wait_for_commit_)
- wait_run_loop_->Quit();
-}
-
-void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {
-}
-
-void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {
-}
-
-void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) {
-}
-
-class PostedSwapQueue {
- public:
- PostedSwapQueue() : pending_swap_(NULL) {
- }
-
- ~PostedSwapQueue() {
- DCHECK(!pending_swap_);
- }
-
- SwapType NextPostedSwap() const {
- return queue_.front();
- }
-
- bool AreSwapsPosted() const {
- return !queue_.empty();
- }
-
- int NumSwapsPosted(SwapType type) const {
- int count = 0;
- for (std::deque<SwapType>::const_iterator it = queue_.begin();
- it != queue_.end(); ++it) {
- if (*it == type)
- count++;
- }
- return count;
- }
-
- void PostSwap() {
- DCHECK(pending_swap_);
- queue_.push_back(pending_swap_->type());
- pending_swap_->posted_ = true;
- }
-
- void EndSwap() {
- queue_.pop_front();
- }
-
- private:
- friend class ::PendingSwap;
-
- PendingSwap* pending_swap_;
- std::deque<SwapType> queue_;
-
- DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
-};
-
} // namespace ui
namespace {
-PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
- : type_(type), posted_(false), posted_swaps_(posted_swaps) {
- // Only one pending swap in flight.
- DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
- posted_swaps_->pending_swap_ = this;
-}
-
-PendingSwap::~PendingSwap() {
- DCHECK_EQ(this, posted_swaps_->pending_swap_);
- posted_swaps_->pending_swap_ = NULL;
-}
-
} // namespace
namespace ui {
-Compositor::Compositor(gfx::AcceleratedWidget widget)
- : root_layer_(NULL),
+Compositor::Compositor(gfx::AcceleratedWidget widget,
+ ui::ContextFactory* context_factory)
+ : context_factory_(context_factory),
+ root_layer_(NULL),
widget_(widget),
- posted_swaps_(new PostedSwapQueue()),
+ compositor_thread_loop_(context_factory->GetCompositorMessageLoop()),
+ vsync_manager_(new CompositorVSyncManager()),
device_scale_factor_(0.0f),
last_started_frame_(0),
last_ended_frame_(0),
- next_draw_is_resize_(false),
disable_schedule_composite_(false),
compositor_lock_(NULL),
defer_draw_scheduling_(false),
waiting_on_compositing_end_(false),
draw_on_compositing_end_(false),
+ swap_state_(SWAP_NONE),
+ layer_animator_collection_(this),
schedule_draw_factory_(this) {
- DCHECK(g_compositor_initialized)
- << "Compositor::Initialize must be called before creating a Compositor.";
-
root_web_layer_ = cc::Layer::Create();
- root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
CommandLine* command_line = CommandLine::ForCurrentProcess();
cc::LayerTreeSettings settings;
settings.refresh_rate =
- ContextFactory::GetInstance()->DoesCreateTestContexts()
+ context_factory_->DoesCreateTestContexts()
? kTestRefreshRate
: kDefaultRefreshRate;
- settings.deadline_scheduling_enabled =
- switches::IsUIDeadlineSchedulingEnabled();
+ settings.main_frame_before_draw_enabled = false;
+ settings.main_frame_before_activation_enabled = false;
+ settings.throttle_frame_production =
+ !command_line->HasSwitch(switches::kDisableGpuVsync);
+#if !defined(OS_MACOSX)
settings.partial_swap_enabled =
!command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
- settings.per_tile_painting_enabled =
- command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting);
+#endif
+#if defined(OS_CHROMEOS)
+ settings.per_tile_painting_enabled = true;
+#endif
// These flags should be mirrored by renderer versions in content/renderer/.
settings.initial_debug_state.show_debug_borders =
@@ -289,12 +130,22 @@ Compositor::Compositor(gfx::AcceleratedWidget widget)
settings.initial_debug_state.show_non_occluding_rects =
command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
+ settings.initial_debug_state.SetRecordRenderingStats(
+ command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
+
+ settings.impl_side_painting = IsUIImplSidePaintingEnabled();
+ settings.use_zero_copy = IsUIZeroCopyEnabled();
+
base::TimeTicks before_create = base::TimeTicks::Now();
- if (!!g_compositor_thread) {
+ if (compositor_thread_loop_) {
host_ = cc::LayerTreeHost::CreateThreaded(
- this, NULL, settings, g_compositor_thread->message_loop_proxy());
+ this,
+ context_factory_->GetSharedBitmapManager(),
+ settings,
+ compositor_thread_loop_);
} else {
- host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
+ host_ = cc::LayerTreeHost::CreateSingleThreaded(
+ this, this, context_factory_->GetSharedBitmapManager(), settings);
}
UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
base::TimeTicks::Now() - before_create);
@@ -305,8 +156,6 @@ Compositor::Compositor(gfx::AcceleratedWidget widget)
Compositor::~Compositor() {
TRACE_EVENT0("shutdown", "Compositor::destructor");
- DCHECK(g_compositor_initialized);
-
CancelCompositorLock();
DCHECK(!compositor_lock_);
@@ -317,59 +166,12 @@ Compositor::~Compositor() {
// down any contexts that the |host_| may rely upon.
host_.reset();
- ContextFactory::GetInstance()->RemoveCompositor(this);
-}
-
-// static
-void Compositor::Initialize() {
-#if defined(OS_CHROMEOS)
- bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUIDisableThreadedCompositing);
-#else
- bool use_thread =
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUIEnableThreadedCompositing) &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUIDisableThreadedCompositing);
-#endif
- if (use_thread) {
- g_compositor_thread = new base::Thread("Browser Compositor");
- g_compositor_thread->Start();
- }
-
- DCHECK(!g_compositor_initialized) << "Compositor initialized twice.";
- g_compositor_initialized = true;
-}
-
-// static
-bool Compositor::WasInitializedWithThread() {
- DCHECK(g_compositor_initialized);
- return !!g_compositor_thread;
-}
-
-// static
-scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
- scoped_refptr<base::MessageLoopProxy> proxy;
- if (g_compositor_thread)
- proxy = g_compositor_thread->message_loop_proxy();
- return proxy;
-}
-
-// static
-void Compositor::Terminate() {
- if (g_compositor_thread) {
- g_compositor_thread->Stop();
- delete g_compositor_thread;
- g_compositor_thread = NULL;
- }
-
- DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen.";
- g_compositor_initialized = false;
+ context_factory_->RemoveCompositor(this);
}
void Compositor::ScheduleDraw() {
- if (g_compositor_thread) {
- host_->Composite(gfx::FrameTime::Now());
+ if (compositor_thread_loop_) {
+ host_->SetNeedsCommit();
} else if (!defer_draw_scheduling_) {
defer_draw_scheduling_ = true;
base::MessageLoop::current()->PostTask(
@@ -397,7 +199,7 @@ void Compositor::SetHostHasTransparentBackground(
}
void Compositor::Draw() {
- DCHECK(!g_compositor_thread);
+ DCHECK(!compositor_thread_loop_);
defer_draw_scheduling_ = false;
if (waiting_on_compositing_end_) {
@@ -411,27 +213,19 @@ void Compositor::Draw() {
if (!root_layer_)
return;
+ DCHECK_NE(swap_state_, SWAP_POSTED);
+ swap_state_ = SWAP_NONE;
+
last_started_frame_++;
- PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
if (!IsLocked()) {
// TODO(nduca): Temporary while compositor calls
// compositeImmediately() directly.
+ base::TimeTicks now = gfx::FrameTime::Now();
+ Animate(now);
Layout();
- host_->Composite(gfx::FrameTime::Now());
-
-#if defined(OS_WIN)
- // While we resize, we are usually a few frames behind. By blocking
- // the UI thread here we minize the area that is mis-painted, specially
- // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
- // more details and bug 177115.
- if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
- next_draw_is_resize_ = false;
- host_->FinishAllRendering();
- }
-#endif
-
+ host_->Composite(now);
}
- if (!pending_swap.posted())
+ if (swap_state_ == SWAP_NONE)
NotifyEnd();
}
@@ -443,38 +237,26 @@ void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
host_->SetNeedsRedrawRect(damage_rect);
}
+void Compositor::FinishAllRendering() {
+ host_->FinishAllRendering();
+}
+
void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
scoped_ptr<cc::SwapPromise> swap_promise(
new cc::LatencyInfoSwapPromise(latency_info));
host_->QueueSwapPromise(swap_promise.Pass());
}
-bool Compositor::ReadPixels(SkBitmap* bitmap,
- const gfx::Rect& bounds_in_pixel) {
- if (bounds_in_pixel.right() > size().width() ||
- bounds_in_pixel.bottom() > size().height())
- return false;
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- bounds_in_pixel.width(), bounds_in_pixel.height());
- bitmap->allocPixels();
- SkAutoLockPixels lock_image(*bitmap);
- unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
- CancelCompositorLock();
- PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
- return host_->CompositeAndReadback(pixels, bounds_in_pixel);
-}
-
void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
DCHECK_GT(scale, 0);
if (!size_in_pixel.IsEmpty()) {
size_ = size_in_pixel;
host_->SetViewportSize(size_in_pixel);
root_web_layer_->SetBounds(size_in_pixel);
-
- next_draw_is_resize_ = true;
}
if (device_scale_factor_ != scale) {
device_scale_factor_ = scale;
+ host_->SetDeviceScaleFactor(scale);
if (root_layer_)
root_layer_->OnDeviceScaleFactorChanged(scale);
}
@@ -485,6 +267,10 @@ void Compositor::SetBackgroundColor(SkColor color) {
ScheduleDraw();
}
+scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
+ return vsync_manager_;
+}
+
void Compositor::AddObserver(CompositorObserver* observer) {
observer_list_.AddObserver(observer);
}
@@ -497,11 +283,10 @@ bool Compositor::HasObserver(CompositorObserver* observer) {
return observer_list_.HasObserver(observer);
}
-void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) {
- FOR_EACH_OBSERVER(CompositorObserver,
- observer_list_,
- OnUpdateVSyncParameters(this, timebase, interval));
+void Compositor::Animate(base::TimeTicks frame_begin_time) {
+ layer_animator_collection_.Progress(frame_begin_time);
+ if (layer_animator_collection_.HasActiveAnimators())
+ host_->SetNeedsAnimate();
}
void Compositor::Layout() {
@@ -514,7 +299,7 @@ void Compositor::Layout() {
}
scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
- return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback);
+ return context_factory_->CreateOutputSurface(this, fallback);
}
void Compositor::DidCommit() {
@@ -532,21 +317,15 @@ void Compositor::DidCommitAndDrawFrame() {
}
void Compositor::DidCompleteSwapBuffers() {
- if (g_compositor_thread) {
+ if (compositor_thread_loop_) {
NotifyEnd();
} else {
- DCHECK(posted_swaps_->AreSwapsPosted());
- DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
- if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
- NotifyEnd();
- posted_swaps_->EndSwap();
+ DCHECK_EQ(swap_state_, SWAP_POSTED);
+ NotifyEnd();
+ swap_state_ = SWAP_COMPLETED;
}
}
-scoped_refptr<cc::ContextProvider> Compositor::OffscreenContextProvider() {
- return ContextFactory::GetInstance()->OffscreenCompositorContextProvider();
-}
-
void Compositor::ScheduleComposite() {
if (!disable_schedule_composite_)
ScheduleDraw();
@@ -557,19 +336,16 @@ void Compositor::ScheduleAnimation() {
}
void Compositor::DidPostSwapBuffers() {
- DCHECK(!g_compositor_thread);
- posted_swaps_->PostSwap();
+ DCHECK(!compositor_thread_loop_);
+ DCHECK_EQ(swap_state_, SWAP_NONE);
+ swap_state_ = SWAP_POSTED;
}
void Compositor::DidAbortSwapBuffers() {
- if (!g_compositor_thread) {
- DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
-
- // We've just lost the context, so unwind all posted_swaps.
- while (posted_swaps_->AreSwapsPosted()) {
- if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
- NotifyEnd();
- posted_swaps_->EndSwap();
+ if (!compositor_thread_loop_) {
+ if (swap_state_ == SWAP_POSTED) {
+ NotifyEnd();
+ swap_state_ = SWAP_COMPLETED;
}
}
@@ -578,6 +354,10 @@ void Compositor::DidAbortSwapBuffers() {
OnCompositingAborted(this));
}
+void Compositor::ScheduleAnimationForLayerCollection() {
+ host_->SetNeedsAnimate();
+}
+
const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
return host_->debug_state();
}
@@ -590,7 +370,7 @@ void Compositor::SetLayerTreeDebugState(
scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
if (!compositor_lock_) {
compositor_lock_ = new CompositorLock(this);
- if (g_compositor_thread)
+ if (compositor_thread_loop_)
host_->SetDeferCommits(true);
FOR_EACH_OBSERVER(CompositorObserver,
observer_list_,
@@ -602,7 +382,7 @@ scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
void Compositor::UnlockCompositor() {
DCHECK(compositor_lock_);
compositor_lock_ = NULL;
- if (g_compositor_thread)
+ if (compositor_thread_loop_)
host_->SetDeferCommits(false);
FOR_EACH_OBSERVER(CompositorObserver,
observer_list_,
diff --git a/chromium/ui/compositor/compositor.gyp b/chromium/ui/compositor/compositor.gyp
index 405b46d7ce9..9b19e605f20 100644
--- a/chromium/ui/compositor/compositor.gyp
+++ b/chromium/ui/compositor/compositor.gyp
@@ -14,8 +14,10 @@
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'<(DEPTH)/cc/cc.gyp:cc',
+ '<(DEPTH)/gpu/gpu.gyp:command_buffer_common',
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
'<(DEPTH)/ui/gl/gl.gyp:gl',
],
'defines': [
@@ -26,6 +28,8 @@
'compositor.h',
'compositor_export.h',
'compositor_observer.h',
+ 'compositor_vsync_manager.cc',
+ 'compositor_vsync_manager.h',
'compositor_switches.cc',
'compositor_switches.h',
'debug_utils.cc',
@@ -45,9 +49,13 @@
'layer_animation_sequence.h',
'layer_animator.cc',
'layer_animator.h',
+ 'layer_animator_collection.cc',
+ 'layer_animator_collection.h',
'layer_delegate.h',
'layer_owner.cc',
'layer_owner.h',
+ 'layer_tree_owner.cc',
+ 'layer_tree_owner.h',
'layer_type.h',
'reflector.h',
'scoped_animation_duration_scale_mode.cc',
@@ -77,24 +85,48 @@
'<(DEPTH)/cc/cc.gyp:cc',
'<(DEPTH)/cc/cc_tests.gyp:cc_test_support',
'<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink_minimal',
+ '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
'<(DEPTH)/ui/gl/gl.gyp:gl',
- '<(DEPTH)/ui/ui.gyp:ui',
'<(DEPTH)/webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
'compositor',
],
'sources': [
- 'test/test_layers.cc',
- 'test/test_layers.h',
- 'test/test_context_factory.cc',
- 'test/test_context_factory.h',
- 'test/default_context_factory.cc',
- 'test/default_context_factory.h',
'test/context_factories_for_test.cc',
'test/context_factories_for_test.h',
+ 'test/draw_waiter_for_test.cc',
+ 'test/draw_waiter_for_test.h',
+ 'test/in_process_context_factory.cc',
+ 'test/in_process_context_factory.h',
+ 'test/layer_animator_test_controller.cc',
+ 'test/layer_animator_test_controller.h',
+ 'test/test_compositor_host.h',
+ 'test/test_compositor_host_mac.mm',
+ 'test/test_compositor_host_ozone.cc',
+ 'test/test_compositor_host_win.cc',
+ 'test/test_compositor_host_x11.cc',
+ 'test/test_layer_animation_delegate.cc',
+ 'test/test_layer_animation_delegate.h',
+ 'test/test_layer_animation_observer.cc',
+ 'test/test_layer_animation_observer.h',
+ 'test/test_layers.cc',
+ 'test/test_layers.h',
'test/test_suite.cc',
'test/test_suite.h',
+ 'test/test_utils.cc',
+ 'test/test_utils.h',
],
+ 'conditions': [
+ ['use_x11==1', {
+ 'dependencies': [
+ '<(DEPTH)/build/linux/system.gyp:x11',
+ '<(DEPTH)/ui/gfx/x/gfx_x11.gyp:gfx_x11',
+ ]
+ }]
+ ]
},
{
'target_name': 'compositor_unittests',
@@ -106,10 +138,11 @@
'<(DEPTH)/cc/cc_tests.gyp:cc_test_support',
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
'<(DEPTH)/ui/gl/gl.gyp:gl',
'<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources',
- '<(DEPTH)/ui/ui.gyp:ui',
'compositor',
'compositor_test_support',
],
@@ -117,21 +150,9 @@
'layer_animation_element_unittest.cc',
'layer_animation_sequence_unittest.cc',
'layer_animator_unittest.cc',
+ 'layer_owner_unittest.cc',
'layer_unittest.cc',
'run_all_unittests.cc',
- 'test/layer_animator_test_controller.cc',
- 'test/layer_animator_test_controller.h',
- 'test/test_compositor_host.h',
- 'test/test_compositor_host_mac.mm',
- 'test/test_compositor_host_ozone.cc',
- 'test/test_compositor_host_win.cc',
- 'test/test_compositor_host_x11.cc',
- 'test/test_layer_animation_delegate.cc',
- 'test/test_layer_animation_delegate.h',
- 'test/test_layer_animation_observer.cc',
- 'test/test_layer_animation_observer.h',
- 'test/test_utils.cc',
- 'test/test_utils.h',
'transform_animation_curve_adapter_unittest.cc',
],
'conditions': [
@@ -143,7 +164,7 @@
}],
['os_posix == 1 and OS != "mac"', {
'conditions': [
- ['linux_use_tcmalloc==1', {
+ ['use_allocator!="none"', {
'dependencies': [
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
],
diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h
index 4beb9fffcbd..79bf691c415 100644
--- a/chromium/ui/compositor/compositor.h
+++ b/chromium/ui/compositor/compositor.h
@@ -17,6 +17,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/compositor_export.h"
#include "ui/compositor/compositor_observer.h"
+#include "ui/compositor/layer_animator_collection.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gfx/vector2d.h"
@@ -28,15 +29,12 @@ class MessageLoopProxy;
class RunLoop;
}
-namespace blink {
-class WebGraphicsContext3D;
-}
-
namespace cc {
class ContextProvider;
class Layer;
class LayerTreeDebugState;
class LayerTreeHost;
+class SharedBitmapManager;
}
namespace gfx {
@@ -44,11 +42,15 @@ class Rect;
class Size;
}
+namespace gpu {
+struct Mailbox;
+}
+
namespace ui {
class Compositor;
+class CompositorVSyncManager;
class Layer;
-class PostedSwapQueue;
class Reflector;
class Texture;
struct LatencyInfo;
@@ -59,14 +61,6 @@ class COMPOSITOR_EXPORT ContextFactory {
public:
virtual ~ContextFactory() {}
- // Gets the global instance.
- static ContextFactory* GetInstance();
-
- // Sets the global instance. Caller keeps ownership.
- // If this function isn't called (for tests), a "default" factory will be
- // created on the first call of GetInstance.
- static void SetInstance(ContextFactory* instance);
-
// Creates an output surface for the given compositor. The factory may keep
// per-compositor data (e.g. a shared context), that needs to be cleaned up
// by calling RemoveCompositor when the compositor gets destroyed.
@@ -81,16 +75,8 @@ class COMPOSITOR_EXPORT ContextFactory {
// Removes the reflector, which stops the mirroring.
virtual void RemoveReflector(scoped_refptr<Reflector> reflector) = 0;
- // Returns a reference to the offscreen context provider used by the
- // compositor. This provider is bound and used on whichever thread the
- // compositor is rendering from.
- virtual scoped_refptr<cc::ContextProvider>
- OffscreenCompositorContextProvider() = 0;
-
// Return a reference to a shared offscreen context provider usable from the
- // main thread. This may be the same as OffscreenCompositorContextProvider()
- // depending on the compositor's threading configuration. This provider will
- // be bound to the main thread.
+ // main thread.
virtual scoped_refptr<cc::ContextProvider>
SharedMainThreadContextProvider() = 0;
@@ -100,39 +86,13 @@ class COMPOSITOR_EXPORT ContextFactory {
// When true, the factory uses test contexts that do not do real GL
// operations.
virtual bool DoesCreateTestContexts() = 0;
-};
-// Texture provide an abstraction over the external texture that can be passed
-// to a layer.
-class COMPOSITOR_EXPORT Texture : public base::RefCounted<Texture> {
- public:
- Texture(bool flipped, const gfx::Size& size, float device_scale_factor);
+ // Gets the shared bitmap manager for software mode.
+ virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0;
- bool flipped() const { return flipped_; }
- gfx::Size size() const { return size_; }
- float device_scale_factor() const { return device_scale_factor_; }
-
- virtual unsigned int PrepareTexture() = 0;
-
- // Replaces the texture with the texture from the specified mailbox.
- virtual void Consume(const std::string& mailbox_name,
- const gfx::Size& new_size) {}
-
- // Moves the texture into the mailbox and returns the mailbox name.
- // The texture must have been previously consumed from a mailbox.
- virtual std::string Produce();
-
- protected:
- virtual ~Texture();
- gfx::Size size_; // in pixel
-
- private:
- friend class base::RefCounted<Texture>;
-
- bool flipped_;
- float device_scale_factor_;
-
- DISALLOW_COPY_AND_ASSIGN(Texture);
+ // Gets the compositor message loop, or NULL if not using threaded
+ // compositing.
+ virtual base::MessageLoopProxy* GetCompositorMessageLoop() = 0;
};
// This class represents a lock on the compositor, that can be used to prevent
@@ -160,43 +120,6 @@ class COMPOSITOR_EXPORT CompositorLock
DISALLOW_COPY_AND_ASSIGN(CompositorLock);
};
-// This is only to be used for test. It allows execution of other tasks on
-// the current message loop before the current task finishs (there is a
-// potential for re-entrancy).
-class COMPOSITOR_EXPORT DrawWaiterForTest : public CompositorObserver {
- public:
- // Waits for a draw to be issued by the compositor. If the test times out
- // here, there may be a logic error in the compositor code causing it
- // not to draw.
- static void Wait(Compositor* compositor);
-
- // Waits for a commit instead of a draw.
- static void WaitForCommit(Compositor* compositor);
-
- private:
- DrawWaiterForTest();
- virtual ~DrawWaiterForTest();
-
- void WaitImpl(Compositor* compositor);
-
- // CompositorObserver implementation.
- virtual void OnCompositingDidCommit(Compositor* compositor) OVERRIDE;
- virtual void OnCompositingStarted(Compositor* compositor,
- base::TimeTicks start_time) OVERRIDE;
- virtual void OnCompositingEnded(Compositor* compositor) OVERRIDE;
- virtual void OnCompositingAborted(Compositor* compositor) OVERRIDE;
- virtual void OnCompositingLockStateChanged(Compositor* compositor) OVERRIDE;
- virtual void OnUpdateVSyncParameters(Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE;
-
- scoped_ptr<base::RunLoop> wait_run_loop_;
-
- bool wait_for_commit_;
-
- DISALLOW_COPY_AND_ASSIGN(DrawWaiterForTest);
-};
-
// Compositor object to take care of GPU painting.
// A Browser compositor object is responsible for generating the final
// displayable form of pixels comprising a single widget's contents. It draws an
@@ -205,15 +128,13 @@ class COMPOSITOR_EXPORT DrawWaiterForTest : public CompositorObserver {
class COMPOSITOR_EXPORT Compositor
: NON_EXPORTED_BASE(public cc::LayerTreeHostClient),
NON_EXPORTED_BASE(public cc::LayerTreeHostSingleThreadClient),
- public base::SupportsWeakPtr<Compositor> {
+ NON_EXPORTED_BASE(public LayerAnimatorCollectionDelegate) {
public:
- explicit Compositor(gfx::AcceleratedWidget widget);
+ Compositor(gfx::AcceleratedWidget widget,
+ ui::ContextFactory* context_factory);
virtual ~Compositor();
- static void Initialize();
- static bool WasInitializedWithThread();
- static scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop();
- static void Terminate();
+ ui::ContextFactory* context_factory() { return context_factory_; }
// Schedules a redraw of the layer tree associated with this compositor.
void ScheduleDraw();
@@ -248,12 +169,10 @@ class COMPOSITOR_EXPORT Compositor
// from changes to layer properties.
void ScheduleRedrawRect(const gfx::Rect& damage_rect);
- void SetLatencyInfo(const LatencyInfo& latency_info);
+ // Finishes all outstanding rendering on the GPU.
+ void FinishAllRendering();
- // Reads the region |bounds_in_pixel| of the contents of the last rendered
- // frame into the given bitmap.
- // Returns false if the pixels could not be read.
- bool ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds_in_pixel);
+ void SetLatencyInfo(const LatencyInfo& latency_info);
// Sets the compositor's device scale factor and size.
void SetScaleAndSize(float scale, const gfx::Size& size_in_pixel);
@@ -268,6 +187,9 @@ class COMPOSITOR_EXPORT Compositor
// Returns the widget for this compositor.
gfx::AcceleratedWidget widget() const { return widget_; }
+ // Returns the vsync manager for this compositor.
+ scoped_refptr<CompositorVSyncManager> vsync_manager() const;
+
// Compositor does not own observers. It is the responsibility of the
// observer to remove itself when it is done observing.
void AddObserver(CompositorObserver* observer);
@@ -290,25 +212,20 @@ class COMPOSITOR_EXPORT Compositor
// Signals swap has aborted (e.g. lost context).
void OnSwapBuffersAborted();
- void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval);
-
// LayerTreeHostClient implementation.
virtual void WillBeginMainFrame(int frame_id) OVERRIDE {}
virtual void DidBeginMainFrame() OVERRIDE {}
- virtual void Animate(double frame_begin_time) OVERRIDE {}
+ virtual void Animate(base::TimeTicks frame_begin_time) OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float page_scale) OVERRIDE {}
virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback)
OVERRIDE;
- virtual void DidInitializeOutputSurface(bool success) OVERRIDE {}
+ virtual void DidInitializeOutputSurface() OVERRIDE {}
virtual void WillCommit() OVERRIDE {}
virtual void DidCommit() OVERRIDE;
virtual void DidCommitAndDrawFrame() OVERRIDE;
virtual void DidCompleteSwapBuffers() OVERRIDE;
- virtual scoped_refptr<cc::ContextProvider>
- OffscreenContextProvider() OVERRIDE;
// cc::LayerTreeHostSingleThreadClient implementation.
virtual void ScheduleComposite() OVERRIDE;
@@ -316,6 +233,9 @@ class COMPOSITOR_EXPORT Compositor
virtual void DidPostSwapBuffers() OVERRIDE;
virtual void DidAbortSwapBuffers() OVERRIDE;
+ // LayerAnimatorCollectionDelegate implementation.
+ virtual void ScheduleAnimationForLayerCollection() OVERRIDE;
+
int last_started_frame() { return last_started_frame_; }
int last_ended_frame() { return last_ended_frame_; }
@@ -324,6 +244,10 @@ class COMPOSITOR_EXPORT Compositor
const cc::LayerTreeDebugState& GetLayerTreeDebugState() const;
void SetLayerTreeDebugState(const cc::LayerTreeDebugState& debug_state);
+ LayerAnimatorCollection* layer_animator_collection() {
+ return &layer_animator_collection_;
+ }
+
private:
friend class base::RefCounted<Compositor>;
friend class CompositorLock;
@@ -339,6 +263,8 @@ class COMPOSITOR_EXPORT Compositor
gfx::Size size_;
+ ui::ContextFactory* context_factory_;
+
// The root of the Layer tree drawn by this compositor.
Layer* root_layer_;
@@ -347,9 +273,10 @@ class COMPOSITOR_EXPORT Compositor
gfx::AcceleratedWidget widget_;
scoped_refptr<cc::Layer> root_web_layer_;
scoped_ptr<cc::LayerTreeHost> host_;
+ scoped_refptr<base::MessageLoopProxy> compositor_thread_loop_;
- // Used to verify that we have at most one draw swap in flight.
- scoped_ptr<PostedSwapQueue> posted_swaps_;
+ // The manager of vsync parameters for this compositor.
+ scoped_refptr<CompositorVSyncManager> vsync_manager_;
// The device scale factor of the monitor that this compositor is compositing
// layers on.
@@ -358,8 +285,6 @@ class COMPOSITOR_EXPORT Compositor
int last_started_frame_;
int last_ended_frame_;
- bool next_draw_is_resize_;
-
bool disable_schedule_composite_;
CompositorLock* compositor_lock_;
@@ -370,6 +295,10 @@ class COMPOSITOR_EXPORT Compositor
// Used to prevent Draw()s while a composite is in progress.
bool waiting_on_compositing_end_;
bool draw_on_compositing_end_;
+ enum SwapState { SWAP_NONE, SWAP_POSTED, SWAP_COMPLETED };
+ SwapState swap_state_;
+
+ LayerAnimatorCollection layer_animator_collection_;
base::WeakPtrFactory<Compositor> schedule_draw_factory_;
diff --git a/chromium/ui/compositor/compositor_observer.h b/chromium/ui/compositor/compositor_observer.h
index aced251b3f9..badc5b466c9 100644
--- a/chromium/ui/compositor/compositor_observer.h
+++ b/chromium/ui/compositor/compositor_observer.h
@@ -38,11 +38,6 @@ class COMPOSITOR_EXPORT CompositorObserver {
// Called when the compositor lock state changes.
virtual void OnCompositingLockStateChanged(Compositor* compositor) = 0;
- // Called when the compositor has received updated VSync parameters.
- virtual void OnUpdateVSyncParameters(Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) = 0;
-
protected:
virtual ~CompositorObserver() {}
};
diff --git a/chromium/ui/compositor/compositor_switches.cc b/chromium/ui/compositor/compositor_switches.cc
index 87a4f264573..a7ffc1465a0 100644
--- a/chromium/ui/compositor/compositor_switches.cc
+++ b/chromium/ui/compositor/compositor_switches.cc
@@ -8,36 +8,35 @@
namespace switches {
-const char kDisableTestCompositor[] = "disable-test-compositor";
+// Enable compositing individual elements via hardware overlays when
+// permitted by device.
+const char kEnableHardwareOverlays[] = "enable-hardware-overlays";
-const char kUIDisableDeadlineScheduling[] = "ui-disable-deadline-scheduling";
+// Forces tests to produce pixel output when they normally wouldn't.
+const char kEnablePixelOutputInTests[] = "enable-pixel-output-in-tests";
const char kUIDisableThreadedCompositing[] = "ui-disable-threaded-compositing";
-const char kUIEnableDeadlineScheduling[] = "ui-enable-deadline-scheduling";
+const char kUIEnableImplSidePainting[] = "ui-enable-impl-side-painting";
-const char kUIEnableSoftwareCompositing[] = "ui-enable-software-compositing";
+const char kUIEnableZeroCopy[] = "ui-enable-zero-copy";
-const char kUIEnableThreadedCompositing[] = "ui-enable-threaded-compositing";
+const char kUIShowPaintRects[] = "ui-show-paint-rects";
-const char kUIMaxFramesPending[] = "ui-max-frames-pending";
+} // namespace switches
-const char kUIShowPaintRects[] = "ui-show-paint-rects";
+namespace ui {
-bool IsUIDeadlineSchedulingEnabled() {
+bool IsUIImplSidePaintingEnabled() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- // Default to disabled.
- bool enabled = false;
-
- // Default to enabled for Aura.
- enabled = true;
+ return command_line.HasSwitch(switches::kUIEnableImplSidePainting);
+}
- // Flags override.
- enabled |= command_line.HasSwitch(switches::kUIEnableDeadlineScheduling);
- enabled &= !command_line.HasSwitch(switches::kUIDisableDeadlineScheduling);
+bool IsUIZeroCopyEnabled() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- return enabled;
+ return command_line.HasSwitch(switches::kUIEnableZeroCopy);
}
-} // namespace switches
+} // namespace ui
diff --git a/chromium/ui/compositor/compositor_switches.h b/chromium/ui/compositor/compositor_switches.h
index 2bf2b242260..d487bdd44a1 100644
--- a/chromium/ui/compositor/compositor_switches.h
+++ b/chromium/ui/compositor/compositor_switches.h
@@ -9,17 +9,20 @@
namespace switches {
-COMPOSITOR_EXPORT extern const char kDisableTestCompositor[];
-COMPOSITOR_EXPORT extern const char kUIDisableDeadlineScheduling[];
+COMPOSITOR_EXPORT extern const char kEnableHardwareOverlays[];
+COMPOSITOR_EXPORT extern const char kEnablePixelOutputInTests[];
COMPOSITOR_EXPORT extern const char kUIDisableThreadedCompositing[];
-COMPOSITOR_EXPORT extern const char kUIEnableDeadlineScheduling[];
-COMPOSITOR_EXPORT extern const char kUIEnableSoftwareCompositing[];
-COMPOSITOR_EXPORT extern const char kUIEnableThreadedCompositing[];
-COMPOSITOR_EXPORT extern const char kUIMaxFramesPending[];
+COMPOSITOR_EXPORT extern const char kUIEnableImplSidePainting[];
+COMPOSITOR_EXPORT extern const char kUIEnableZeroCopy[];
COMPOSITOR_EXPORT extern const char kUIShowPaintRects[];
-COMPOSITOR_EXPORT bool IsUIDeadlineSchedulingEnabled();
-
} // namespace switches
+namespace ui {
+
+COMPOSITOR_EXPORT bool IsUIImplSidePaintingEnabled();
+COMPOSITOR_EXPORT bool IsUIZeroCopyEnabled();
+
+} // namespace ui
+
#endif // UI_COMPOSITOR_COMPOSITOR_SWITCHES_H_
diff --git a/chromium/ui/compositor/compositor_vsync_manager.cc b/chromium/ui/compositor/compositor_vsync_manager.cc
new file mode 100644
index 00000000000..1a10d4ad309
--- /dev/null
+++ b/chromium/ui/compositor/compositor_vsync_manager.cc
@@ -0,0 +1,63 @@
+// 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/compositor/compositor_vsync_manager.h"
+
+namespace ui {
+
+CompositorVSyncManager::CompositorVSyncManager()
+ : observer_list_(new ObserverListThreadSafe<Observer>()),
+ authoritative_vsync_interval_(base::TimeDelta::FromSeconds(0)) {}
+
+CompositorVSyncManager::~CompositorVSyncManager() {}
+
+void CompositorVSyncManager::SetAuthoritativeVSyncInterval(
+ base::TimeDelta interval) {
+ base::TimeTicks timebase;
+ {
+ base::AutoLock lock(vsync_parameters_lock_);
+ timebase = last_timebase_;
+ authoritative_vsync_interval_ = interval;
+ last_interval_ = interval;
+ }
+ NotifyObservers(timebase, interval);
+}
+
+void CompositorVSyncManager::UpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ {
+ base::AutoLock lock(vsync_parameters_lock_);
+ if (authoritative_vsync_interval_ != base::TimeDelta::FromSeconds(0))
+ interval = authoritative_vsync_interval_;
+ last_timebase_ = timebase;
+ last_interval_ = interval;
+ }
+ NotifyObservers(timebase, interval);
+}
+
+void CompositorVSyncManager::AddObserver(Observer* observer) {
+ base::TimeTicks timebase;
+ base::TimeDelta interval;
+ {
+ base::AutoLock lock(vsync_parameters_lock_);
+ timebase = last_timebase_;
+ interval = last_interval_;
+ }
+ observer_list_->AddObserver(observer);
+ observer->OnUpdateVSyncParameters(timebase, interval);
+}
+
+void CompositorVSyncManager::RemoveObserver(Observer* observer) {
+ observer_list_->RemoveObserver(observer);
+}
+
+void CompositorVSyncManager::NotifyObservers(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ observer_list_->Notify(
+ &CompositorVSyncManager::Observer::OnUpdateVSyncParameters,
+ timebase,
+ interval);
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/compositor_vsync_manager.h b/chromium/ui/compositor/compositor_vsync_manager.h
new file mode 100644
index 00000000000..abfbad6b863
--- /dev/null
+++ b/chromium/ui/compositor/compositor_vsync_manager.h
@@ -0,0 +1,71 @@
+// 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_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_
+#define UI_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "ui/compositor/compositor_export.h"
+
+namespace ui {
+
+// This class manages vsync parameters for a compositor. It merges updates of
+// the parameters from different sources and sends the merged updates to
+// observers which register to it. This class is explicitly synchronized and is
+// safe to use and update from any thread. Observers of the manager will be
+// notified on the thread they have registered from, and should be removed from
+// the same thread.
+class COMPOSITOR_EXPORT CompositorVSyncManager
+ : public base::RefCountedThreadSafe<CompositorVSyncManager> {
+ public:
+ class Observer {
+ public:
+ virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) = 0;
+ };
+
+ CompositorVSyncManager();
+
+ // The "authoritative" vsync interval, if provided, will override |interval|
+ // as reported by UpdateVSyncParameters() whenever it is called. This is
+ // typically the value reported by a more reliable source, e.g. the platform
+ // display configuration. In the particular case of ChromeOS -- this is the
+ // value queried through XRandR, which is more reliable than the value
+ // queried through the 3D context.
+ void SetAuthoritativeVSyncInterval(base::TimeDelta interval);
+
+ // The vsync parameters consist of |timebase|, which is the platform timestamp
+ // of the last vsync, and |interval|, which is the interval between vsyncs.
+ // |interval| may be overriden by SetAuthoritativeVSyncInterval() above.
+ void UpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ private:
+ friend class base::RefCountedThreadSafe<CompositorVSyncManager>;
+
+ ~CompositorVSyncManager();
+
+ void NotifyObservers(base::TimeTicks timebase, base::TimeDelta interval);
+
+ // List of observers.
+ scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
+
+ // Protects the cached vsync parameters below.
+ base::Lock vsync_parameters_lock_;
+ base::TimeTicks last_timebase_;
+ base::TimeDelta last_interval_;
+ base::TimeDelta authoritative_vsync_interval_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositorVSyncManager);
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_
diff --git a/chromium/ui/compositor/debug_utils.cc b/chromium/ui/compositor/debug_utils.cc
index e1f62f9d42d..37b9af42f30 100644
--- a/chromium/ui/compositor/debug_utils.cc
+++ b/chromium/ui/compositor/debug_utils.cc
@@ -8,7 +8,7 @@
#include <cmath>
#include <iomanip>
-#include <iostream>
+#include <ostream>
#include <string>
#include "base/logging.h"
@@ -19,6 +19,8 @@
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/transform.h"
+using base::UTF8ToWide;
+
namespace ui {
namespace {
@@ -102,4 +104,4 @@ void PrintLayerHierarchy(const Layer* layer, gfx::Point mouse_location) {
LOG(ERROR) << out.str();
}
-} // namespace ui
+} // namespace ui
diff --git a/chromium/ui/compositor/debug_utils.h b/chromium/ui/compositor/debug_utils.h
index 18a2d657d9e..966b3ae5916 100644
--- a/chromium/ui/compositor/debug_utils.h
+++ b/chromium/ui/compositor/debug_utils.h
@@ -19,6 +19,6 @@ class Layer;
COMPOSITOR_EXPORT void PrintLayerHierarchy(const Layer* layer,
gfx::Point mouse_location);
-} // namespace ui
+} // namespace ui
#endif // UI_COMPOSITOR_DEBUG_UTILS_H_
diff --git a/chromium/ui/compositor/dip_util.cc b/chromium/ui/compositor/dip_util.cc
index 2d95af63830..fcecf249555 100644
--- a/chromium/ui/compositor/dip_util.cc
+++ b/chromium/ui/compositor/dip_util.cc
@@ -60,6 +60,14 @@ gfx::Size ConvertSizeToPixel(const Layer* layer,
gfx::Rect ConvertRectToPixel(const Layer* layer,
const gfx::Rect& rect_in_dip) {
float scale = GetDeviceScaleFactor(layer);
- return gfx::ToFlooredRectDeprecated(gfx::ScaleRect(rect_in_dip, scale));
+ // Use ToEnclosingRect() to ensure we paint all the possible pixels
+ // touched. ToEnclosingRect() floors the origin, and ceils the max
+ // coordinate. To do otherwise (such as flooring the size) potentially
+ // results in rounding down and not drawing all the pixels that are
+ // touched.
+ return gfx::ToEnclosingRect(
+ gfx::RectF(gfx::ScalePoint(rect_in_dip.origin(), scale),
+ gfx::ScaleSize(rect_in_dip.size(), scale)));
}
+
} // namespace ui
diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc
index 51322be303b..c1767422163 100644
--- a/chromium/ui/compositor/layer.cc
+++ b/chromium/ui/compositor/layer.cc
@@ -8,11 +8,13 @@
#include "base/command_line.h"
#include "base/debug/trace_event.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/scoped_ptr_algorithm.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/delegated_renderer_layer.h"
+#include "cc/layers/picture_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/output/copy_output_request.h"
@@ -39,6 +41,15 @@ const ui::Layer* GetRoot(const ui::Layer* layer) {
return layer;
}
+struct UIImplSidePaintingStatus {
+ UIImplSidePaintingStatus()
+ : enabled(ui::IsUIImplSidePaintingEnabled()) {
+ }
+ bool enabled;
+};
+base::LazyInstance<UIImplSidePaintingStatus> g_ui_impl_side_painting_status =
+ LAZY_INSTANCE_INITIALIZER;
+
} // namespace
namespace ui {
@@ -50,7 +61,7 @@ Layer::Layer()
visible_(true),
force_render_surface_(false),
fills_bounds_opaquely_(true),
- layer_updated_externally_(false),
+ fills_bounds_completely_(false),
background_blur_radius_(0),
layer_saturation_(0.0f),
layer_brightness_(0.0f),
@@ -61,8 +72,8 @@ Layer::Layer()
zoom_(1),
zoom_inset_(0),
delegate_(NULL),
+ owner_(NULL),
cc_layer_(NULL),
- scale_content_(true),
device_scale_factor_(1.0f) {
CreateWebLayer();
}
@@ -74,7 +85,7 @@ Layer::Layer(LayerType type)
visible_(true),
force_render_surface_(false),
fills_bounds_opaquely_(true),
- layer_updated_externally_(false),
+ fills_bounds_completely_(false),
background_blur_radius_(0),
layer_saturation_(0.0f),
layer_brightness_(0.0f),
@@ -85,8 +96,8 @@ Layer::Layer(LayerType type)
zoom_(1),
zoom_inset_(0),
delegate_(NULL),
+ owner_(NULL),
cc_layer_(NULL),
- scale_content_(true),
device_scale_factor_(1.0f) {
CreateWebLayer();
}
@@ -112,6 +123,11 @@ Layer::~Layer() {
cc_layer_->RemoveFromParent();
}
+// static
+bool Layer::UsingPictureLayer() {
+ return g_ui_impl_side_painting_status.Get().enabled;
+}
+
Compositor* Layer::GetCompositor() {
return GetRoot(this)->compositor_;
}
@@ -126,10 +142,15 @@ void Layer::SetCompositor(Compositor* compositor) {
DCHECK(!compositor || !compositor_);
DCHECK(!compositor || compositor->root_layer() == this);
DCHECK(!parent_);
+ if (compositor_) {
+ RemoveAnimatorsInTreeFromCollection(
+ compositor_->layer_animator_collection());
+ }
compositor_ = compositor;
if (compositor) {
OnDeviceScaleFactorChanged(compositor->device_scale_factor());
SendPendingThreadedAnimations();
+ AddAnimatorsInTreeToCollection(compositor_->layer_animator_collection());
}
}
@@ -143,9 +164,21 @@ void Layer::Add(Layer* child) {
child->OnDeviceScaleFactorChanged(device_scale_factor_);
if (GetCompositor())
child->SendPendingThreadedAnimations();
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection)
+ child->AddAnimatorsInTreeToCollection(collection);
}
void Layer::Remove(Layer* child) {
+ // Current bounds are used to calculate offsets when layers are reparented.
+ // Stop (and complete) an ongoing animation to update the bounds immediately.
+ LayerAnimator* child_animator = child->animator_;
+ if (child_animator)
+ child_animator->StopAnimatingProperty(ui::LayerAnimationElement::BOUNDS);
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection)
+ child->RemoveAnimatorsInTreeFromCollection(collection);
+
std::vector<Layer*>::iterator i =
std::find(children_.begin(), children_.end(), child);
DCHECK(i != children_.end());
@@ -210,6 +243,11 @@ void Layer::SetBounds(const gfx::Rect& bounds) {
GetAnimator()->SetBounds(bounds);
}
+void Layer::SetSubpixelPositionOffset(const gfx::Vector2dF offset) {
+ subpixel_position_offset_ = offset;
+ RecomputePosition();
+}
+
gfx::Rect Layer::GetTargetBounds() const {
if (animator_.get() && animator_->IsAnimatingProperty(
LayerAnimationElement::BOUNDS)) {
@@ -311,6 +349,12 @@ void Layer::SetBackgroundZoom(float zoom, int inset) {
SetLayerBackgroundFilters();
}
+void Layer::SetAlphaShape(scoped_ptr<SkRegion> region) {
+ alpha_shape_ = region.Pass();
+
+ SetLayerFilters();
+}
+
void Layer::SetLayerFilters() {
cc::FilterOperations filters;
if (layer_saturation_) {
@@ -330,6 +374,10 @@ void Layer::SetLayerFilters() {
filters.Append(cc::FilterOperation::CreateSaturatingBrightnessFilter(
layer_brightness_));
}
+ if (alpha_shape_) {
+ filters.Append(cc::FilterOperation::CreateAlphaThresholdFilter(
+ *alpha_shape_, 1.f, 0.f));
+ }
cc_layer_->SetFilters(filters);
}
@@ -408,17 +456,6 @@ bool Layer::GetTargetTransformRelativeTo(const Layer* ancestor,
return p == ancestor;
}
-// static
-gfx::Transform Layer::ConvertTransformToCCTransform(
- const gfx::Transform& transform,
- float device_scale_factor) {
- gfx::Transform cc_transform;
- cc_transform.Scale(device_scale_factor, device_scale_factor);
- cc_transform.PreconcatTransform(transform);
- cc_transform.Scale(1.0f / device_scale_factor, 1.0f / device_scale_factor);
- return cc_transform;
-}
-
void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
if (fills_bounds_opaquely_ == fills_bounds_opaquely)
return;
@@ -428,6 +465,10 @@ void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
cc_layer_->SetContentsOpaque(fills_bounds_opaquely);
}
+void Layer::SetFillsBoundsCompletely(bool fills_bounds_completely) {
+ fills_bounds_completely_ = fills_bounds_completely;
+}
+
void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
// Finish animations being handled by cc_layer_.
if (animator_.get()) {
@@ -436,13 +477,12 @@ void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
}
if (texture_layer_.get())
- texture_layer_->WillModifyTexture();
+ texture_layer_->ClearClient();
// TODO(piman): delegated_renderer_layer_ cleanup.
cc_layer_->RemoveAllChildren();
- if (parent_) {
- DCHECK(parent_->cc_layer_);
- parent_->cc_layer_->ReplaceChild(cc_layer_, new_layer);
+ if (cc_layer_->parent()) {
+ cc_layer_->parent()->ReplaceChild(cc_layer_, new_layer);
}
cc_layer_->SetLayerClient(NULL);
cc_layer_->RemoveLayerAnimationEventObserver(this);
@@ -462,7 +502,7 @@ void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
cc_layer_->AddChild(children_[i]->cc_layer_);
}
cc_layer_->SetLayerClient(this);
- cc_layer_->SetAnchorPoint(gfx::PointF());
+ cc_layer_->SetTransformOrigin(gfx::Point3F());
cc_layer_->SetContentsOpaque(fills_bounds_opaquely_);
cc_layer_->SetForceRenderSurface(force_render_surface_);
cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN);
@@ -470,56 +510,44 @@ void Layer::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) {
}
void Layer::SwitchCCLayerForTest() {
- scoped_refptr<cc::ContentLayer> new_layer = cc::ContentLayer::Create(this);
+ scoped_refptr<cc::Layer> new_layer;
+ if (Layer::UsingPictureLayer())
+ new_layer = cc::PictureLayer::Create(this);
+ else
+ new_layer = cc::ContentLayer::Create(this);
SwitchToLayer(new_layer);
content_layer_ = new_layer;
}
-void Layer::SetExternalTexture(Texture* texture) {
- DCHECK(texture);
-
- // Hold a ref to the old |Texture| until we have updated all
- // compositor references to the texture id that it holds.
- scoped_refptr<ui::Texture> old_texture = texture_;
-
- DCHECK_EQ(type_, LAYER_TEXTURED);
- DCHECK(!solid_color_layer_.get());
- layer_updated_externally_ = true;
- texture_ = texture;
- if (!texture_layer_.get()) {
- scoped_refptr<cc::TextureLayer> new_layer = cc::TextureLayer::Create(this);
- new_layer->SetFlipped(texture_->flipped());
- SwitchToLayer(new_layer);
- texture_layer_ = new_layer;
- }
- RecomputeDrawsContentAndUVRect();
-}
-
void Layer::SetTextureMailbox(
const cc::TextureMailbox& mailbox,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
- float scale_factor) {
+ gfx::Size texture_size_in_dip) {
DCHECK_EQ(type_, LAYER_TEXTURED);
DCHECK(!solid_color_layer_.get());
- layer_updated_externally_ = true;
- texture_ = NULL;
- if (!texture_layer_.get() || !texture_layer_->uses_mailbox()) {
+ DCHECK(mailbox.IsValid());
+ DCHECK(release_callback);
+ if (!texture_layer_) {
scoped_refptr<cc::TextureLayer> new_layer =
cc::TextureLayer::CreateForMailbox(this);
- new_layer->SetFlipped(false);
+ new_layer->SetFlipped(true);
SwitchToLayer(new_layer);
texture_layer_ = new_layer;
}
- texture_layer_->SetTextureMailbox(mailbox, release_callback.Pass());
+ if (mailbox_release_callback_)
+ mailbox_release_callback_->Run(0, false);
+ mailbox_release_callback_ = release_callback.Pass();
mailbox_ = mailbox;
- mailbox_scale_factor_ = scale_factor;
- RecomputeDrawsContentAndUVRect();
+ SetTextureSize(texture_size_in_dip);
}
-cc::TextureMailbox Layer::GetTextureMailbox(float* scale_factor) {
- if (scale_factor)
- *scale_factor = mailbox_scale_factor_;
- return mailbox_;
+void Layer::SetTextureSize(gfx::Size texture_size_in_dip) {
+ DCHECK(texture_layer_.get());
+ if (frame_size_in_dip_ == texture_size_in_dip)
+ return;
+ frame_size_in_dip_ = texture_size_in_dip;
+ RecomputeDrawsContentAndUVRect();
+ texture_layer_->SetNeedsDisplay();
}
void Layer::SetShowDelegatedContent(cc::DelegatedFrameProvider* frame_provider,
@@ -530,9 +558,8 @@ void Layer::SetShowDelegatedContent(cc::DelegatedFrameProvider* frame_provider,
cc::DelegatedRendererLayer::Create(frame_provider);
SwitchToLayer(new_layer);
delegated_renderer_layer_ = new_layer;
- layer_updated_externally_ = true;
- delegated_frame_size_in_dip_ = frame_size_in_dip;
+ frame_size_in_dip_ = frame_size_in_dip;
RecomputeDrawsContentAndUVRect();
}
@@ -540,21 +567,26 @@ void Layer::SetShowPaintedContent() {
if (content_layer_.get())
return;
- scoped_refptr<cc::ContentLayer> new_layer = cc::ContentLayer::Create(this);
+ scoped_refptr<cc::Layer> new_layer;
+ if (Layer::UsingPictureLayer())
+ new_layer = cc::PictureLayer::Create(this);
+ else
+ new_layer = cc::ContentLayer::Create(this);
SwitchToLayer(new_layer);
content_layer_ = new_layer;
- layer_updated_externally_ = false;
mailbox_ = cc::TextureMailbox();
- texture_ = NULL;
-
+ if (mailbox_release_callback_) {
+ mailbox_release_callback_->Run(0, false);
+ mailbox_release_callback_.reset();
+ }
RecomputeDrawsContentAndUVRect();
}
void Layer::SetColor(SkColor color) { GetAnimator()->SetColor(color); }
bool Layer::SchedulePaint(const gfx::Rect& invalid_rect) {
- if (type_ == LAYER_SOLID_COLOR || (!delegate_ && !texture_.get()))
+ if (type_ == LAYER_SOLID_COLOR || (!delegate_ && !mailbox_.IsValid()))
return false;
damaged_region_.op(invalid_rect.x(),
@@ -573,7 +605,7 @@ void Layer::ScheduleDraw() {
}
void Layer::SendDamagedRects() {
- if ((delegate_ || texture_.get()) && !damaged_region_.isEmpty()) {
+ if ((delegate_ || mailbox_.IsValid()) && !damaged_region_.isEmpty()) {
for (SkRegion::Iterator iter(damaged_region_); !iter.done(); iter.next()) {
const SkIRect& sk_damaged = iter.rect();
gfx::Rect damaged(
@@ -581,9 +613,7 @@ void Layer::SendDamagedRects() {
sk_damaged.y(),
sk_damaged.width(),
sk_damaged.height());
-
- gfx::Rect damaged_in_pixel = ConvertRectToPixel(this, damaged);
- cc_layer_->SetNeedsDisplayRect(damaged_in_pixel);
+ cc_layer_->SetNeedsDisplayRect(damaged);
}
damaged_region_.setEmpty();
}
@@ -591,6 +621,13 @@ void Layer::SendDamagedRects() {
children_[i]->SendDamagedRects();
}
+void Layer::CompleteAllAnimations() {
+ std::vector<scoped_refptr<LayerAnimator> > animators;
+ CollectAnimators(&animators);
+ std::for_each(animators.begin(), animators.end(),
+ std::mem_fun(&LayerAnimator::StopAnimating));
+}
+
void Layer::SuppressPaint() {
if (!delegate_)
return;
@@ -604,9 +641,7 @@ void Layer::OnDeviceScaleFactorChanged(float device_scale_factor) {
return;
if (animator_.get())
animator_->StopAnimatingProperty(LayerAnimationElement::TRANSFORM);
- gfx::Transform transform = this->transform();
device_scale_factor_ = device_scale_factor;
- RecomputeCCTransformFromTransform(transform);
RecomputeDrawsContentAndUVRect();
RecomputePosition();
SchedulePaint(gfx::Rect(bounds_.size()));
@@ -623,35 +658,27 @@ void Layer::RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) {
}
void Layer::PaintContents(SkCanvas* sk_canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) {
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) {
TRACE_EVENT0("ui", "Layer::PaintContents");
scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvasWithoutScaling(
sk_canvas, device_scale_factor_));
-
- bool scale_content = scale_content_;
- if (scale_content) {
- canvas->Save();
- canvas->sk_canvas()->scale(SkFloatToScalar(device_scale_factor_),
- SkFloatToScalar(device_scale_factor_));
- }
-
if (delegate_)
delegate_->OnPaintLayer(canvas.get());
- if (scale_content)
- canvas->Restore();
}
-unsigned Layer::PrepareTexture() {
- DCHECK(texture_layer_.get());
- return texture_->PrepareTexture();
-}
+bool Layer::FillsBoundsCompletely() const { return fills_bounds_completely_; }
bool Layer::PrepareTextureMailbox(
cc::TextureMailbox* mailbox,
scoped_ptr<cc::SingleReleaseCallback>* release_callback,
bool use_shared_memory) {
- return false;
+ if (!mailbox_release_callback_)
+ return false;
+ *mailbox = mailbox_;
+ *release_callback = mailbox_release_callback_.Pass();
+ return true;
}
void Layer::SetForceRenderSurface(bool force) {
@@ -662,13 +689,22 @@ void Layer::SetForceRenderSurface(bool force) {
cc_layer_->SetForceRenderSurface(force_render_surface_);
}
-std::string Layer::DebugName() {
- return name_;
-}
+class LayerDebugInfo : public base::debug::ConvertableToTraceFormat {
+ public:
+ explicit LayerDebugInfo(std::string name) : name_(name) { }
+ virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
+ base::DictionaryValue dictionary;
+ dictionary.SetString("layer_name", name_);
+ base::JSONWriter::Write(&dictionary, out);
+ }
+
+ private:
+ virtual ~LayerDebugInfo() { }
+ std::string name_;
+};
scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
- // TODO: return something useful here.
- return NULL;
+ return new LayerDebugInfo(name_);
}
void Layer::OnAnimationStarted(const cc::AnimationEvent& event) {
@@ -676,6 +712,15 @@ void Layer::OnAnimationStarted(const cc::AnimationEvent& event) {
animator_->OnThreadedAnimationStarted(event);
}
+void Layer::CollectAnimators(
+ std::vector<scoped_refptr<LayerAnimator> >* animators) {
+ if (IsAnimating())
+ animators->push_back(animator_);
+ std::for_each(children_.begin(), children_.end(),
+ std::bind2nd(std::mem_fun(&Layer::CollectAnimators),
+ animators));
+}
+
void Layer::StackRelativeTo(Layer* child, Layer* other, bool above) {
DCHECK_NE(child, other);
DCHECK_EQ(this, child->parent());
@@ -719,7 +764,7 @@ bool Layer::ConvertPointFromAncestor(const Layer* ancestor,
return result;
}
-void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
+void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds) {
if (bounds == bounds_)
return;
@@ -746,16 +791,16 @@ void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
}
}
-void Layer::SetTransformImmediately(const gfx::Transform& transform) {
- RecomputeCCTransformFromTransform(transform);
+void Layer::SetTransformFromAnimation(const gfx::Transform& transform) {
+ cc_layer_->SetTransform(transform);
}
-void Layer::SetOpacityImmediately(float opacity) {
+void Layer::SetOpacityFromAnimation(float opacity) {
cc_layer_->SetOpacity(opacity);
ScheduleDraw();
}
-void Layer::SetVisibilityImmediately(bool visible) {
+void Layer::SetVisibilityFromAnimation(bool visible) {
if (visible_ == visible)
return;
@@ -763,50 +808,22 @@ void Layer::SetVisibilityImmediately(bool visible) {
cc_layer_->SetHideLayerAndSubtree(!visible_);
}
-void Layer::SetBrightnessImmediately(float brightness) {
+void Layer::SetBrightnessFromAnimation(float brightness) {
layer_brightness_ = brightness;
SetLayerFilters();
}
-void Layer::SetGrayscaleImmediately(float grayscale) {
+void Layer::SetGrayscaleFromAnimation(float grayscale) {
layer_grayscale_ = grayscale;
SetLayerFilters();
}
-void Layer::SetColorImmediately(SkColor color) {
+void Layer::SetColorFromAnimation(SkColor color) {
DCHECK_EQ(type_, LAYER_SOLID_COLOR);
solid_color_layer_->SetBackgroundColor(color);
SetFillsBoundsOpaquely(SkColorGetA(color) == 0xFF);
}
-void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds) {
- SetBoundsImmediately(bounds);
-}
-
-void Layer::SetTransformFromAnimation(const gfx::Transform& transform) {
- SetTransformImmediately(transform);
-}
-
-void Layer::SetOpacityFromAnimation(float opacity) {
- SetOpacityImmediately(opacity);
-}
-
-void Layer::SetVisibilityFromAnimation(bool visibility) {
- SetVisibilityImmediately(visibility);
-}
-
-void Layer::SetBrightnessFromAnimation(float brightness) {
- SetBrightnessImmediately(brightness);
-}
-
-void Layer::SetGrayscaleFromAnimation(float grayscale) {
- SetGrayscaleImmediately(grayscale);
-}
-
-void Layer::SetColorFromAnimation(SkColor color) {
- SetColorImmediately(color);
-}
-
void Layer::ScheduleDrawForAnimation() {
ScheduleDraw();
}
@@ -888,6 +905,11 @@ void Layer::RemoveThreadedAnimation(int animation_id) {
pending_threaded_animations_.end());
}
+LayerAnimatorCollection* Layer::GetLayerAnimatorCollection() {
+ Compositor* compositor = GetCompositor();
+ return compositor ? compositor->layer_animator_collection() : NULL;
+}
+
void Layer::SendPendingThreadedAnimations() {
for (cc::ScopedPtrVector<cc::Animation>::iterator it =
pending_threaded_animations_.begin();
@@ -906,10 +928,13 @@ void Layer::CreateWebLayer() {
solid_color_layer_ = cc::SolidColorLayer::Create();
cc_layer_ = solid_color_layer_.get();
} else {
- content_layer_ = cc::ContentLayer::Create(this);
+ if (Layer::UsingPictureLayer())
+ content_layer_ = cc::PictureLayer::Create(this);
+ else
+ content_layer_ = cc::ContentLayer::Create(this);
cc_layer_ = content_layer_.get();
}
- cc_layer_->SetAnchorPoint(gfx::PointF());
+ cc_layer_->SetTransformOrigin(gfx::Point3F());
cc_layer_->SetContentsOpaque(true);
cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN);
cc_layer_->AddLayerAnimationEventObserver(this);
@@ -917,54 +942,56 @@ void Layer::CreateWebLayer() {
RecomputePosition();
}
-void Layer::RecomputeCCTransformFromTransform(const gfx::Transform& transform) {
- cc_layer_->SetTransform(ConvertTransformToCCTransform(transform,
- device_scale_factor_));
-}
-
gfx::Transform Layer::transform() const {
- gfx::Transform transform;
- transform.Scale(1.0f / device_scale_factor_, 1.0f / device_scale_factor_);
- transform.PreconcatTransform(cc_layer_->transform());
- transform.Scale(device_scale_factor_, device_scale_factor_);
- return transform;
+ return cc_layer_->transform();
}
void Layer::RecomputeDrawsContentAndUVRect() {
DCHECK(cc_layer_);
gfx::Size size(bounds_.size());
if (texture_layer_.get()) {
- gfx::Size texture_size;
- if (!texture_layer_->uses_mailbox()) {
- DCHECK(texture_.get());
- float texture_scale_factor = 1.0f / texture_->device_scale_factor();
- texture_size = gfx::ToFlooredSize(
- gfx::ScaleSize(texture_->size(), texture_scale_factor));
- } else {
- DCHECK(mailbox_.IsSharedMemory());
- float texture_scale_factor = 1.0f / mailbox_scale_factor_;
- texture_size = gfx::ToFlooredSize(
- gfx::ScaleSize(mailbox_.shared_memory_size(), texture_scale_factor));
- }
- size.SetToMin(texture_size);
-
+ size.SetToMin(frame_size_in_dip_);
gfx::PointF uv_top_left(0.f, 0.f);
gfx::PointF uv_bottom_right(
- static_cast<float>(size.width())/texture_size.width(),
- static_cast<float>(size.height())/texture_size.height());
+ static_cast<float>(size.width()) / frame_size_in_dip_.width(),
+ static_cast<float>(size.height()) / frame_size_in_dip_.height());
texture_layer_->SetUV(uv_top_left, uv_bottom_right);
} else if (delegated_renderer_layer_.get()) {
- delegated_renderer_layer_->SetDisplaySize(
- ConvertSizeToPixel(this, delegated_frame_size_in_dip_));
- size.SetToMin(delegated_frame_size_in_dip_);
+ size.SetToMin(frame_size_in_dip_);
}
- cc_layer_->SetBounds(ConvertSizeToPixel(this, size));
+ cc_layer_->SetBounds(size);
}
void Layer::RecomputePosition() {
- cc_layer_->SetPosition(gfx::ScalePoint(
- gfx::PointF(bounds_.x(), bounds_.y()),
- device_scale_factor_));
+ cc_layer_->SetPosition(bounds_.origin() + subpixel_position_offset_);
+}
+
+void Layer::AddAnimatorsInTreeToCollection(
+ LayerAnimatorCollection* collection) {
+ DCHECK(collection);
+ if (IsAnimating())
+ animator_->AddToCollection(collection);
+ std::for_each(
+ children_.begin(),
+ children_.end(),
+ std::bind2nd(std::mem_fun(&Layer::AddAnimatorsInTreeToCollection),
+ collection));
+}
+
+void Layer::RemoveAnimatorsInTreeFromCollection(
+ LayerAnimatorCollection* collection) {
+ DCHECK(collection);
+ if (IsAnimating())
+ animator_->RemoveFromCollection(collection);
+ std::for_each(
+ children_.begin(),
+ children_.end(),
+ std::bind2nd(std::mem_fun(&Layer::RemoveAnimatorsInTreeFromCollection),
+ collection));
+}
+
+bool Layer::IsAnimating() const {
+ return animator_ && animator_->is_animating();
}
} // namespace ui
diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h
index 0be0d93e65e..03041edb872 100644
--- a/chromium/ui/compositor/layer.h
+++ b/chromium/ui/compositor/layer.h
@@ -47,7 +47,7 @@ namespace ui {
class Compositor;
class LayerAnimator;
-class Texture;
+class LayerOwner;
// Layer manages a texture, transform and a set of child Layers. Any View that
// has enabled layers ends up creating a Layer to manage the texture.
@@ -56,8 +56,8 @@ class Texture;
// Coordinate system used in layers is DIP (Density Independent Pixel)
// coordinates unless explicitly mentioned as pixel coordinates.
//
-// NOTE: unlike Views, each Layer does *not* own its children views. If you
-// delete a Layer and it has children, the parent of each child layer is set to
+// NOTE: Unlike Views, each Layer does *not* own its child Layers. If you
+// delete a Layer and it has children, the parent of each child Layer is set to
// NULL, but the children are not deleted.
class COMPOSITOR_EXPORT Layer
: public LayerAnimationDelegate,
@@ -70,6 +70,8 @@ class COMPOSITOR_EXPORT Layer
explicit Layer(LayerType type);
virtual ~Layer();
+ static bool UsingPictureLayer();
+
// Retrieves the Layer's compositor. The Layer will walk up its parent chain
// to locate it. Returns NULL if the Layer is not attached to a compositor.
Compositor* GetCompositor();
@@ -81,6 +83,8 @@ class COMPOSITOR_EXPORT Layer
LayerDelegate* delegate() { return delegate_; }
void set_delegate(LayerDelegate* delegate) { delegate_ = delegate; }
+ LayerOwner* owner() { return owner_; }
+
// Adds a new Layer to this Layer.
void Add(Layer* child);
@@ -135,6 +139,10 @@ class COMPOSITOR_EXPORT Layer
void SetBounds(const gfx::Rect& bounds);
const gfx::Rect& bounds() const { return bounds_; }
+ // The offset from our parent (stored in bounds.origin()) is an integer but we
+ // may need to be at a fractional pixel offset to align properly on screen.
+ void SetSubpixelPositionOffset(const gfx::Vector2dF offset);
+
// Return the target bounds if animator is running, or the current bounds
// otherwise.
gfx::Rect GetTargetBounds() const;
@@ -188,6 +196,9 @@ class COMPOSITOR_EXPORT Layer
// edge across |inset| pixels.
void SetBackgroundZoom(float zoom, int inset);
+ // Set the shape of this layer.
+ void SetAlphaShape(scoped_ptr<SkRegion> region);
+
// Invert the layer.
bool layer_inverted() const { return layer_inverted_; }
void SetLayerInverted(bool inverted);
@@ -234,32 +245,23 @@ class COMPOSITOR_EXPORT Layer
bool GetTargetTransformRelativeTo(const Layer* ancestor,
gfx::Transform* transform) const;
- // Converts a ui::Layer's transform to the transform on the corresponding
- // cc::Layer.
- static gfx::Transform ConvertTransformToCCTransform(
- const gfx::Transform& transform,
- float device_scale_factor);
-
// See description in View for details
void SetFillsBoundsOpaquely(bool fills_bounds_opaquely);
bool fills_bounds_opaquely() const { return fills_bounds_opaquely_; }
+ // Set to true if this layer always paints completely within its bounds. If so
+ // we can omit an unnecessary clear, even if the layer is transparent.
+ void SetFillsBoundsCompletely(bool fills_bounds_completely);
+
const std::string& name() const { return name_; }
void set_name(const std::string& name) { name_ = name; }
- const ui::Texture* texture() const { return texture_.get(); }
-
- // Assigns a new external texture. |texture| can be NULL to disable external
- // updates.
- void SetExternalTexture(ui::Texture* texture);
- ui::Texture* external_texture() { return texture_.get(); }
-
// Set new TextureMailbox for this layer. Note that |mailbox| may hold a
// shared memory resource or an actual mailbox for a texture.
void SetTextureMailbox(const cc::TextureMailbox& mailbox,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
- float scale_factor);
- cc::TextureMailbox GetTextureMailbox(float* scale_factor);
+ gfx::Size texture_size_in_dip);
+ void SetTextureSize(gfx::Size texture_size_in_dip);
// Begins showing delegated frames from the |frame_provider|.
void SetShowDelegatedContent(cc::DelegatedFrameProvider* frame_provider,
@@ -283,46 +285,35 @@ class COMPOSITOR_EXPORT Layer
// SchedulePaint() for that.
void ScheduleDraw();
- // Sends damaged rectangles recorded in |damaged_region_| to
- // |compostior_| to repaint the content.
+ // Uses damaged rectangles recorded in |damaged_region_| to invalidate the
+ // |cc_layer_|.
void SendDamagedRects();
const SkRegion& damaged_region() const { return damaged_region_; }
- // Suppresses painting the content by disgarding damaged region and ignoring
- // new paint requests.
+ void CompleteAllAnimations();
+
+ // Suppresses painting the content by disconnecting |delegate_|.
void SuppressPaint();
// Notifies the layer that the device scale factor has changed.
void OnDeviceScaleFactorChanged(float device_scale_factor);
- // Sets whether the layer should scale its content. If true, the canvas will
- // be scaled in software rendering mode before it is passed to
- // |LayerDelegate::OnPaint|.
- // Set to false if the delegate handles scaling.
- // NOTE: if this is called during |LayerDelegate::OnPaint|, the new value will
- // not apply to the canvas passed to the pending draw.
- void set_scale_content(bool scale_content) { scale_content_ = scale_content; }
-
- // Returns true if the layer scales its content.
- bool scale_content() const { return scale_content_; }
-
- // Sometimes the Layer is being updated by something other than SetCanvas
- // (e.g. the GPU process on UI_COMPOSITOR_IMAGE_TRANSPORT).
- bool layer_updated_externally() const { return layer_updated_externally_; }
-
// Requets a copy of the layer's output as a texture or bitmap.
void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request);
// ContentLayerClient
virtual void PaintContents(
- SkCanvas* canvas, gfx::Rect clip, gfx::RectF* opaque) OVERRIDE;
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE;
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE;
cc::Layer* cc_layer() { return cc_layer_; }
// TextureLayerClient
- virtual unsigned PrepareTexture() OVERRIDE;
virtual bool PrepareTextureMailbox(
cc::TextureMailbox* mailbox,
scoped_ptr<cc::SingleReleaseCallback>* release_callback,
@@ -336,8 +327,6 @@ class COMPOSITOR_EXPORT Layer
bool force_render_surface() const { return force_render_surface_; }
// LayerClient
- virtual std::string DebugName() OVERRIDE;
-
virtual scoped_refptr<base::debug::ConvertableToTraceFormat>
TakeDebugInfo() OVERRIDE;
@@ -353,6 +342,10 @@ class COMPOSITOR_EXPORT Layer
void SwitchCCLayerForTest();
private:
+ friend class LayerOwner;
+
+ void CollectAnimators(std::vector<scoped_refptr<LayerAnimator> >* animators);
+
// Stacks |child| above or below |other|. Helper method for StackAbove() and
// StackBelow().
void StackRelativeTo(Layer* child, Layer* other, bool above);
@@ -360,16 +353,6 @@ class COMPOSITOR_EXPORT Layer
bool ConvertPointForAncestor(const Layer* ancestor, gfx::Point* point) const;
bool ConvertPointFromAncestor(const Layer* ancestor, gfx::Point* point) const;
- // Following are invoked from the animation or if no animation exists to
- // update the values immediately.
- void SetBoundsImmediately(const gfx::Rect& bounds);
- void SetTransformImmediately(const gfx::Transform& transform);
- void SetOpacityImmediately(float opacity);
- void SetVisibilityImmediately(bool visibility);
- void SetBrightnessImmediately(float brightness);
- void SetGrayscaleImmediately(float grayscale);
- void SetColorImmediately(SkColor color);
-
// Implementation of LayerAnimatorDelegate
virtual void SetBoundsFromAnimation(const gfx::Rect& bounds) OVERRIDE;
virtual void SetTransformFromAnimation(
@@ -391,9 +374,12 @@ class COMPOSITOR_EXPORT Layer
virtual void AddThreadedAnimation(
scoped_ptr<cc::Animation> animation) OVERRIDE;
virtual void RemoveThreadedAnimation(int animation_id) OVERRIDE;
+ virtual LayerAnimatorCollection* GetLayerAnimatorCollection() OVERRIDE;
+ // Creates a corresponding composited layer for |type_|.
void CreateWebLayer();
- void RecomputeCCTransformFromTransform(const gfx::Transform& transform);
+
+ // Recomputes and sets to |cc_layer_|.
void RecomputeDrawsContentAndUVRect();
void RecomputePosition();
@@ -403,8 +389,7 @@ class COMPOSITOR_EXPORT Layer
// Set all filters which got applied to the layer background.
void SetLayerBackgroundFilters();
- void UpdateIsDrawn();
-
+ // Cleanup |cc_layer_| and replaces it with |new_layer|.
void SwitchToLayer(scoped_refptr<cc::Layer> new_layer);
// We cannot send animations to our cc_layer_ until we have been added to a
@@ -413,18 +398,23 @@ class COMPOSITOR_EXPORT Layer
// be called once we have been added to a tree.
void SendPendingThreadedAnimations();
+ void AddAnimatorsInTreeToCollection(LayerAnimatorCollection* collection);
+ void RemoveAnimatorsInTreeFromCollection(LayerAnimatorCollection* collection);
+
+ // Returns whether the layer has an animating LayerAnimator.
+ bool IsAnimating() const;
+
const LayerType type_;
Compositor* compositor_;
- scoped_refptr<ui::Texture> texture_;
-
Layer* parent_;
// This layer's children, in bottom-to-top stacking order.
std::vector<Layer*> children_;
gfx::Rect bounds_;
+ gfx::Vector2dF subpixel_position_offset_;
// Visibility of this layer. See SetVisible/IsDrawn for more details.
bool visible_;
@@ -432,9 +422,7 @@ class COMPOSITOR_EXPORT Layer
bool force_render_surface_;
bool fills_bounds_opaquely_;
-
- // If true the layer is always up to date.
- bool layer_updated_externally_;
+ bool fills_bounds_completely_;
// Union of damaged rects, in pixel coordinates, to be used when
// compositor is ready to paint the content.
@@ -463,10 +451,15 @@ class COMPOSITOR_EXPORT Layer
// Width of the border in pixels, where the scaling is blended.
int zoom_inset_;
+ // Shape of the window.
+ scoped_ptr<SkRegion> alpha_shape_;
+
std::string name_;
LayerDelegate* delegate_;
+ LayerOwner* owner_;
+
scoped_refptr<LayerAnimator> animator_;
// Animations that are passed to AddThreadedAnimation before this layer is
@@ -475,28 +468,25 @@ class COMPOSITOR_EXPORT Layer
// Ownership of the layer is held through one of the strongly typed layer
// pointers, depending on which sort of layer this is.
- scoped_refptr<cc::ContentLayer> content_layer_;
+ scoped_refptr<cc::Layer> content_layer_;
scoped_refptr<cc::TextureLayer> texture_layer_;
scoped_refptr<cc::SolidColorLayer> solid_color_layer_;
scoped_refptr<cc::DelegatedRendererLayer> delegated_renderer_layer_;
cc::Layer* cc_layer_;
- // If true, the layer scales the canvas and the texture with the device scale
- // factor as apporpriate. When true, the texture size is in DIP.
- bool scale_content_;
-
// A cached copy of |Compositor::device_scale_factor()|.
float device_scale_factor_;
- // A cached copy of the TextureMailbox given texture_layer_.
+ // The mailbox used by texture_layer_.
cc::TextureMailbox mailbox_;
- // Device scale factor in which mailbox_ was rendered in.
- float mailbox_scale_factor_;
+ // The callback to release the mailbox. This is only set after
+ // SetTextureMailbox is called, before we give it to the TextureLayer.
+ scoped_ptr<cc::SingleReleaseCallback> mailbox_release_callback_;
- // The size of the delegated frame in DIP, set when SetShowDelegatedContent
- // was called.
- gfx::Size delegated_frame_size_in_dip_;
+ // The size of the frame or texture in DIP, set when SetShowDelegatedContent
+ // or SetTextureMailbox was called.
+ gfx::Size frame_size_in_dip_;
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/chromium/ui/compositor/layer_animation_delegate.h b/chromium/ui/compositor/layer_animation_delegate.h
index 1d57c714fc3..2f38d54819f 100644
--- a/chromium/ui/compositor/layer_animation_delegate.h
+++ b/chromium/ui/compositor/layer_animation_delegate.h
@@ -14,6 +14,8 @@
namespace ui {
+class LayerAnimatorCollection;
+
// Layer animations interact with the layers using this interface.
class COMPOSITOR_EXPORT LayerAnimationDelegate {
public:
@@ -35,6 +37,7 @@ class COMPOSITOR_EXPORT LayerAnimationDelegate {
virtual float GetDeviceScaleFactor() const = 0;
virtual void AddThreadedAnimation(scoped_ptr<cc::Animation> animation) = 0;
virtual void RemoveThreadedAnimation(int animation_id) = 0;
+ virtual LayerAnimatorCollection* GetLayerAnimatorCollection() = 0;
protected:
virtual ~LayerAnimationDelegate() {}
diff --git a/chromium/ui/compositor/layer_animation_element.cc b/chromium/ui/compositor/layer_animation_element.cc
index 76f8ab7a678..c25e4a1dc96 100644
--- a/chromium/ui/compositor/layer_animation_element.cc
+++ b/chromium/ui/compositor/layer_animation_element.cc
@@ -29,7 +29,7 @@ const int kFastDurationScaleFactor = 4;
// Pause -----------------------------------------------------------------------
class Pause : public LayerAnimationElement {
public:
- Pause(const AnimatableProperties& properties, base::TimeDelta duration)
+ Pause(AnimatableProperties properties, base::TimeDelta duration)
: LayerAnimationElement(properties, duration) {
}
virtual ~Pause() {}
@@ -51,7 +51,7 @@ class Pause : public LayerAnimationElement {
class TransformTransition : public LayerAnimationElement {
public:
TransformTransition(const gfx::Transform& target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(TRANSFORM, duration),
target_(target) {
}
virtual ~TransformTransition() {}
@@ -74,12 +74,6 @@ class TransformTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::TRANSFORM);
- return properties;
- }
-
gfx::Transform start_;
const gfx::Transform target_;
@@ -92,7 +86,7 @@ class InterpolatedTransformTransition : public LayerAnimationElement {
public:
InterpolatedTransformTransition(InterpolatedTransform* interpolated_transform,
base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(TRANSFORM, duration),
interpolated_transform_(interpolated_transform) {
}
virtual ~InterpolatedTransformTransition() {}
@@ -114,12 +108,6 @@ class InterpolatedTransformTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::TRANSFORM);
- return properties;
- }
-
scoped_ptr<InterpolatedTransform> interpolated_transform_;
DISALLOW_COPY_AND_ASSIGN(InterpolatedTransformTransition);
@@ -130,7 +118,7 @@ class InterpolatedTransformTransition : public LayerAnimationElement {
class BoundsTransition : public LayerAnimationElement {
public:
BoundsTransition(const gfx::Rect& target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(BOUNDS, duration),
target_(target) {
}
virtual ~BoundsTransition() {}
@@ -153,12 +141,6 @@ class BoundsTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::BOUNDS);
- return properties;
- }
-
gfx::Rect start_;
const gfx::Rect target_;
@@ -170,7 +152,7 @@ class BoundsTransition : public LayerAnimationElement {
class OpacityTransition : public LayerAnimationElement {
public:
OpacityTransition(float target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(OPACITY, duration),
start_(0.0f),
target_(target) {
}
@@ -194,12 +176,6 @@ class OpacityTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::OPACITY);
- return properties;
- }
-
float start_;
const float target_;
@@ -211,7 +187,7 @@ class OpacityTransition : public LayerAnimationElement {
class VisibilityTransition : public LayerAnimationElement {
public:
VisibilityTransition(bool target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(VISIBILITY, duration),
start_(false),
target_(target) {
}
@@ -234,12 +210,6 @@ class VisibilityTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::VISIBILITY);
- return properties;
- }
-
bool start_;
const bool target_;
@@ -251,7 +221,7 @@ class VisibilityTransition : public LayerAnimationElement {
class BrightnessTransition : public LayerAnimationElement {
public:
BrightnessTransition(float target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(BRIGHTNESS, duration),
start_(0.0f),
target_(target) {
}
@@ -275,12 +245,6 @@ class BrightnessTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::BRIGHTNESS);
- return properties;
- }
-
float start_;
const float target_;
@@ -292,7 +256,7 @@ class BrightnessTransition : public LayerAnimationElement {
class GrayscaleTransition : public LayerAnimationElement {
public:
GrayscaleTransition(float target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(GRAYSCALE, duration),
start_(0.0f),
target_(target) {
}
@@ -316,12 +280,6 @@ class GrayscaleTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::GRAYSCALE);
- return properties;
- }
-
float start_;
const float target_;
@@ -333,7 +291,7 @@ class GrayscaleTransition : public LayerAnimationElement {
class ColorTransition : public LayerAnimationElement {
public:
ColorTransition(SkColor target, base::TimeDelta duration)
- : LayerAnimationElement(GetProperties(), duration),
+ : LayerAnimationElement(COLOR, duration),
start_(SK_ColorBLACK),
target_(target) {
}
@@ -357,12 +315,6 @@ class ColorTransition : public LayerAnimationElement {
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::COLOR);
- return properties;
- }
-
SkColor start_;
const SkColor target_;
@@ -373,7 +325,7 @@ class ColorTransition : public LayerAnimationElement {
class ThreadedLayerAnimationElement : public LayerAnimationElement {
public:
- ThreadedLayerAnimationElement(const AnimatableProperties& properties,
+ ThreadedLayerAnimationElement(AnimatableProperties properties,
base::TimeDelta duration)
: LayerAnimationElement(properties, duration) {
}
@@ -433,7 +385,7 @@ class ThreadedLayerAnimationElement : public LayerAnimationElement {
class ThreadedOpacityTransition : public ThreadedLayerAnimationElement {
public:
ThreadedOpacityTransition(float target, base::TimeDelta duration)
- : ThreadedLayerAnimationElement(GetProperties(), duration),
+ : ThreadedLayerAnimationElement(OPACITY, duration),
start_(0.0f),
target_(target) {
}
@@ -477,12 +429,6 @@ class ThreadedOpacityTransition : public ThreadedLayerAnimationElement {
}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::OPACITY);
- return properties;
- }
-
float start_;
const float target_;
@@ -495,7 +441,7 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement {
public:
ThreadedTransformTransition(const gfx::Transform& target,
base::TimeDelta duration)
- : ThreadedLayerAnimationElement(GetProperties(), duration),
+ : ThreadedLayerAnimationElement(TRANSFORM, duration),
target_(target) {
}
virtual ~ThreadedTransformTransition() {}
@@ -503,11 +449,6 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement {
protected:
virtual void OnStart(LayerAnimationDelegate* delegate) OVERRIDE {
start_ = delegate->GetTransformForAnimation();
- float device_scale_factor = delegate->GetDeviceScaleFactor();
- cc_start_ = Layer::ConvertTransformToCCTransform(start_,
- device_scale_factor);
- cc_target_ = Layer::ConvertTransformToCCTransform(target_,
- device_scale_factor);
}
virtual void OnAbort(LayerAnimationDelegate* delegate) OVERRIDE {
@@ -527,8 +468,8 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement {
virtual scoped_ptr<cc::Animation> CreateCCAnimation() OVERRIDE {
scoped_ptr<cc::AnimationCurve> animation_curve(
new TransformAnimationCurveAdapter(tween_type(),
- cc_start_,
- cc_target_,
+ start_,
+ target_,
duration()));
scoped_ptr<cc::Animation> animation(
cc::Animation::Create(animation_curve.Pass(),
@@ -543,16 +484,8 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement {
}
private:
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::TRANSFORM);
- return properties;
- }
-
gfx::Transform start_;
- gfx::Transform cc_start_;
const gfx::Transform target_;
- gfx::Transform cc_target_;
DISALLOW_COPY_AND_ASSIGN(ThreadedTransformTransition);
};
@@ -589,22 +522,13 @@ class InverseTransformTransition : public ThreadedLayerAnimationElement {
set_tween_type(uninverted_transition_->tween_type());
- float device_scale_factor = delegate->GetDeviceScaleFactor();
- const gfx::Transform cc_base_start = Layer::ConvertTransformToCCTransform(
- base_transform_,
- device_scale_factor);
- const gfx::Transform cc_base_target = Layer::ConvertTransformToCCTransform(
- base_target_,
- device_scale_factor);
TransformAnimationCurveAdapter base_curve(tween_type(),
- cc_base_start,
- cc_base_target,
+ base_transform_,
+ base_target_,
duration());
- const gfx::Transform cc_start = Layer::ConvertTransformToCCTransform(
- start, device_scale_factor);
animation_curve_.reset(new InverseTransformCurveAdapter(
- base_curve, cc_start, duration()));
+ base_curve, start, duration()));
computed_target_transform_ = ComputeWithBaseTransform(effective_start_,
base_target_);
}
@@ -652,16 +576,10 @@ class InverseTransformTransition : public ThreadedLayerAnimationElement {
return to_return;
}
- static AnimatableProperties GetProperties() {
- AnimatableProperties properties;
- properties.insert(LayerAnimationElement::TRANSFORM);
- return properties;
- }
-
template <typename T>
static T CheckAndCast(const LayerAnimationElement* element) {
- const AnimatableProperties& properties = element->properties();
- DCHECK(properties.find(TRANSFORM) != properties.end());
+ AnimatableProperties properties = element->properties();
+ DCHECK(properties & TRANSFORM);
return static_cast<T>(element);
}
@@ -705,8 +623,7 @@ LayerAnimationElement::TargetValue::TargetValue(
// LayerAnimationElement -------------------------------------------------------
LayerAnimationElement::LayerAnimationElement(
- const AnimatableProperties& properties,
- base::TimeDelta duration)
+ AnimatableProperties properties, base::TimeDelta duration)
: first_frame_(true),
properties_(properties),
duration_(GetEffectiveDuration(duration)),
@@ -920,7 +837,7 @@ LayerAnimationElement* LayerAnimationElement::CreateGrayscaleElement(
// static
LayerAnimationElement* LayerAnimationElement::CreatePauseElement(
- const AnimatableProperties& properties,
+ AnimatableProperties properties,
base::TimeDelta duration) {
return new Pause(properties, duration);
}
diff --git a/chromium/ui/compositor/layer_animation_element.h b/chromium/ui/compositor/layer_animation_element.h
index 1127424087f..0b880a44acb 100644
--- a/chromium/ui/compositor/layer_animation_element.h
+++ b/chromium/ui/compositor/layer_animation_element.h
@@ -28,13 +28,18 @@ class LayerAnimationDelegate;
class COMPOSITOR_EXPORT LayerAnimationElement {
public:
enum AnimatableProperty {
- TRANSFORM = 0,
- BOUNDS,
- OPACITY,
- VISIBILITY,
- BRIGHTNESS,
- GRAYSCALE,
- COLOR,
+ UNKNOWN = 0,
+ TRANSFORM = (1 << 0),
+ BOUNDS = (1 << 1),
+ OPACITY = (1 << 2),
+ VISIBILITY = (1 << 3),
+ BRIGHTNESS = (1 << 4),
+ GRAYSCALE = (1 << 5),
+ COLOR = (1 << 6),
+
+ // Used when iterating over properties.
+ FIRST_PROPERTY = TRANSFORM,
+ SENTINEL = (1 << 7)
};
static AnimatableProperty ToAnimatableProperty(
@@ -54,9 +59,9 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
SkColor color;
};
- typedef std::set<AnimatableProperty> AnimatableProperties;
+ typedef uint32 AnimatableProperties;
- LayerAnimationElement(const AnimatableProperties& properties,
+ LayerAnimationElement(AnimatableProperties properties,
base::TimeDelta duration);
virtual ~LayerAnimationElement();
@@ -124,7 +129,7 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
// Creates an element that pauses the given properties. The caller owns the
// return value.
static LayerAnimationElement* CreatePauseElement(
- const AnimatableProperties& properties,
+ AnimatableProperties properties,
base::TimeDelta duration);
// Creates an element that transitions to the given color. The caller owns the
@@ -178,7 +183,7 @@ class COMPOSITOR_EXPORT LayerAnimationElement {
void GetTargetValue(TargetValue* target) const;
// The properties that the element modifies.
- const AnimatableProperties& properties() const { return properties_; }
+ AnimatableProperties properties() const { return properties_; }
// Whether this element animates on the compositor thread.
virtual bool IsThreaded() const;
diff --git a/chromium/ui/compositor/layer_animation_element_unittest.cc b/chromium/ui/compositor/layer_animation_element_unittest.cc
index 8871a2c9f5e..45de8d3fc55 100644
--- a/chromium/ui/compositor/layer_animation_element_unittest.cc
+++ b/chromium/ui/compositor/layer_animation_element_unittest.cc
@@ -314,12 +314,11 @@ TEST(LayerAnimationElementTest, GrayscaleElement) {
// Check that the pause element progresses the delegate as expected and
// that the element can be reused after it completes.
TEST(LayerAnimationElementTest, PauseElement) {
- LayerAnimationElement::AnimatableProperties properties;
- properties.insert(LayerAnimationElement::TRANSFORM);
- properties.insert(LayerAnimationElement::BOUNDS);
- properties.insert(LayerAnimationElement::OPACITY);
- properties.insert(LayerAnimationElement::BRIGHTNESS);
- properties.insert(LayerAnimationElement::GRAYSCALE);
+ LayerAnimationElement::AnimatableProperties properties =
+ LayerAnimationElement::TRANSFORM | LayerAnimationElement::BOUNDS |
+ LayerAnimationElement::OPACITY | LayerAnimationElement::BRIGHTNESS |
+ LayerAnimationElement::GRAYSCALE;
+
base::TimeTicks start_time;
base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
diff --git a/chromium/ui/compositor/layer_animation_observer.cc b/chromium/ui/compositor/layer_animation_observer.cc
index 88db4c65ec2..658a835ddfa 100644
--- a/chromium/ui/compositor/layer_animation_observer.cc
+++ b/chromium/ui/compositor/layer_animation_observer.cc
@@ -140,11 +140,16 @@ void ImplicitAnimationObserver::CheckCompleted() {
void ImplicitAnimationObserver::UpdatePropertyAnimationStatus(
LayerAnimationSequence* sequence,
AnimationStatus status) {
- const LayerAnimationElement::AnimatableProperties& properties =
+ LayerAnimationElement::AnimatableProperties properties =
sequence->properties();
- for (LayerAnimationElement::AnimatableProperties::const_iterator i =
- properties.begin(); i != properties.end(); ++i) {
- property_animation_status_[(*i)] = status;
+ for (unsigned i = LayerAnimationElement::FIRST_PROPERTY;
+ i != LayerAnimationElement::SENTINEL;
+ i = i << 1) {
+ if (i & properties) {
+ LayerAnimationElement::AnimatableProperty property =
+ static_cast<LayerAnimationElement::AnimatableProperty>(i);
+ property_animation_status_[property] = status;
+ }
}
}
diff --git a/chromium/ui/compositor/layer_animation_sequence.cc b/chromium/ui/compositor/layer_animation_sequence.cc
index 9ebf1e0552b..31d09c94775 100644
--- a/chromium/ui/compositor/layer_animation_sequence.cc
+++ b/chromium/ui/compositor/layer_animation_sequence.cc
@@ -16,7 +16,8 @@
namespace ui {
LayerAnimationSequence::LayerAnimationSequence()
- : is_cyclic_(false),
+ : properties_(LayerAnimationElement::UNKNOWN),
+ is_cyclic_(false),
last_element_(0),
waiting_for_group_start_(false),
animation_group_id_(0),
@@ -25,7 +26,8 @@ LayerAnimationSequence::LayerAnimationSequence()
}
LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element)
- : is_cyclic_(false),
+ : properties_(LayerAnimationElement::UNKNOWN),
+ is_cyclic_(false),
last_element_(0),
waiting_for_group_start_(false),
animation_group_id_(0),
@@ -178,20 +180,13 @@ void LayerAnimationSequence::Abort(LayerAnimationDelegate* delegate) {
}
void LayerAnimationSequence::AddElement(LayerAnimationElement* element) {
- properties_.insert(element->properties().begin(),
- element->properties().end());
+ properties_ |= element->properties();
elements_.push_back(make_linked_ptr(element));
}
bool LayerAnimationSequence::HasConflictingProperty(
- const LayerAnimationElement::AnimatableProperties& other) const {
- LayerAnimationElement::AnimatableProperties intersection;
- std::insert_iterator<LayerAnimationElement::AnimatableProperties> ii(
- intersection, intersection.begin());
- std::set_intersection(properties_.begin(), properties_.end(),
- other.begin(), other.end(),
- ii);
- return (intersection.size() > 0);
+ LayerAnimationElement::AnimatableProperties other) const {
+ return (properties_ & other) != LayerAnimationElement::UNKNOWN;
}
bool LayerAnimationSequence::IsFirstElementThreaded() const {
@@ -219,14 +214,12 @@ void LayerAnimationSequence::OnThreadedAnimationStarted(
return;
size_t current_index = last_element_ % elements_.size();
- const LayerAnimationElement::AnimatableProperties& element_properties =
+ LayerAnimationElement::AnimatableProperties element_properties =
elements_[current_index]->properties();
LayerAnimationElement::AnimatableProperty event_property =
LayerAnimationElement::ToAnimatableProperty(event.target_property);
- DCHECK(element_properties.find(event_property) != element_properties.end());
- elements_[current_index]->set_effective_start_time(
- base::TimeTicks::FromInternalValue(
- event.monotonic_time * base::Time::kMicrosecondsPerSecond));
+ DCHECK(element_properties & event_property);
+ elements_[current_index]->set_effective_start_time(event.monotonic_time);
}
void LayerAnimationSequence::OnScheduled() {
diff --git a/chromium/ui/compositor/layer_animation_sequence.h b/chromium/ui/compositor/layer_animation_sequence.h
index 53ce8d6dd40..19635adfc97 100644
--- a/chromium/ui/compositor/layer_animation_sequence.h
+++ b/chromium/ui/compositor/layer_animation_sequence.h
@@ -81,7 +81,7 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
void Abort(LayerAnimationDelegate* delegate);
// All properties modified by the sequence.
- const LayerAnimationElement::AnimatableProperties& properties() const {
+ LayerAnimationElement::AnimatableProperties properties() const {
return properties_;
}
@@ -96,7 +96,7 @@ class COMPOSITOR_EXPORT LayerAnimationSequence
// Returns true if this sequence has at least one element conflicting with a
// property in |other|.
bool HasConflictingProperty(
- const LayerAnimationElement::AnimatableProperties& other) const;
+ LayerAnimationElement::AnimatableProperties other) const;
// Returns true if the first element animates on the compositor thread.
bool IsFirstElementThreaded() const;
diff --git a/chromium/ui/compositor/layer_animation_sequence_unittest.cc b/chromium/ui/compositor/layer_animation_sequence_unittest.cc
index 3b4591762b0..65779741578 100644
--- a/chromium/ui/compositor/layer_animation_sequence_unittest.cc
+++ b/chromium/ui/compositor/layer_animation_sequence_unittest.cc
@@ -28,9 +28,10 @@ TEST(LayerAnimationSequenceTest, NoElement) {
start_time += base::TimeDelta::FromSeconds(1);
sequence.set_start_time(start_time);
EXPECT_TRUE(sequence.IsFinished(start_time));
- EXPECT_TRUE(sequence.properties().size() == 0);
- LayerAnimationElement::AnimatableProperties properties;
- EXPECT_FALSE(sequence.HasConflictingProperty(properties));
+ EXPECT_EQ(static_cast<LayerAnimationElement::AnimatableProperties>(
+ LayerAnimationElement::UNKNOWN),
+ sequence.properties());
+ EXPECT_FALSE(sequence.HasConflictingProperty(LayerAnimationElement::UNKNOWN));
}
// Check that the sequences progresses the delegate as expected when it contains
@@ -62,9 +63,9 @@ TEST(LayerAnimationSequenceTest, SingleElement) {
EXPECT_FLOAT_EQ(target, delegate.GetBrightnessForAnimation());
}
- EXPECT_TRUE(sequence.properties().size() == 1);
- EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::BRIGHTNESS) !=
- sequence.properties().end());
+ EXPECT_EQ(static_cast<LayerAnimationElement::AnimatableProperties>(
+ LayerAnimationElement::BRIGHTNESS),
+ sequence.properties());
}
// Check that the sequences progresses the delegate as expected when it contains
@@ -91,12 +92,12 @@ TEST(LayerAnimationSequenceTest, SingleThreadedElement) {
sequence.Progress(start_time, &delegate);
EXPECT_FLOAT_EQ(start, sequence.last_progressed_fraction());
effective_start = start_time + delta;
- sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
- cc::AnimationEvent::Started,
- 0,
- sequence.animation_group_id(),
- cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ sequence.OnThreadedAnimationStarted(
+ cc::AnimationEvent(cc::AnimationEvent::Started,
+ 0,
+ sequence.animation_group_id(),
+ cc::Animation::Opacity,
+ effective_start));
sequence.Progress(effective_start + delta/2, &delegate);
EXPECT_FLOAT_EQ(middle, sequence.last_progressed_fraction());
EXPECT_TRUE(sequence.IsFinished(effective_start + delta));
@@ -105,9 +106,9 @@ TEST(LayerAnimationSequenceTest, SingleThreadedElement) {
EXPECT_FLOAT_EQ(target, delegate.GetOpacityForAnimation());
}
- EXPECT_TRUE(sequence.properties().size() == 1);
- EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::OPACITY) !=
- sequence.properties().end());
+ EXPECT_EQ(static_cast<LayerAnimationElement::AnimatableProperties>(
+ LayerAnimationElement::OPACITY),
+ sequence.properties());
}
// Check that the sequences progresses the delegate as expected when it contains
@@ -125,11 +126,8 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
LayerAnimationElement::CreateOpacityElement(target_opacity, delta));
// Pause bounds for a second.
- LayerAnimationElement::AnimatableProperties properties;
- properties.insert(LayerAnimationElement::BOUNDS);
-
- sequence.AddElement(
- LayerAnimationElement::CreatePauseElement(properties, delta));
+ sequence.AddElement(LayerAnimationElement::CreatePauseElement(
+ LayerAnimationElement::BOUNDS, delta));
gfx::Transform start_transform, target_transform, middle_transform;
start_transform.Rotate(-30.0);
@@ -151,12 +149,12 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
opacity_effective_start = start_time + delta;
EXPECT_EQ(starting_group_id, sequence.animation_group_id());
- sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
- cc::AnimationEvent::Started,
- 0,
- sequence.animation_group_id(),
- cc::Animation::Opacity,
- (opacity_effective_start - base::TimeTicks()).InSecondsF()));
+ sequence.OnThreadedAnimationStarted(
+ cc::AnimationEvent(cc::AnimationEvent::Started,
+ 0,
+ sequence.animation_group_id(),
+ cc::Animation::Opacity,
+ opacity_effective_start));
sequence.Progress(opacity_effective_start + delta/2, &delegate);
EXPECT_FLOAT_EQ(0.5, sequence.last_progressed_fraction());
sequence.Progress(opacity_effective_start + delta, &delegate);
@@ -182,12 +180,12 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
transform_effective_start = opacity_effective_start + 3 * delta;
EXPECT_NE(starting_group_id, sequence.animation_group_id());
- sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
- cc::AnimationEvent::Started,
- 0,
- sequence.animation_group_id(),
- cc::Animation::Transform,
- (transform_effective_start - base::TimeTicks()).InSecondsF()));
+ sequence.OnThreadedAnimationStarted(
+ cc::AnimationEvent(cc::AnimationEvent::Started,
+ 0,
+ sequence.animation_group_id(),
+ cc::Animation::Transform,
+ transform_effective_start));
sequence.Progress(transform_effective_start + delta/2, &delegate);
EXPECT_FLOAT_EQ(0.5, sequence.last_progressed_fraction());
EXPECT_TRUE(sequence.IsFinished(transform_effective_start + delta));
@@ -196,13 +194,11 @@ TEST(LayerAnimationSequenceTest, MultipleElement) {
delegate.GetTransformForAnimation());
}
- EXPECT_TRUE(sequence.properties().size() == 3);
- EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::OPACITY) !=
- sequence.properties().end());
- EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::TRANSFORM) !=
- sequence.properties().end());
- EXPECT_TRUE(sequence.properties().find(LayerAnimationElement::BOUNDS) !=
- sequence.properties().end());
+ EXPECT_EQ(
+ static_cast<LayerAnimationElement::AnimatableProperties>(
+ LayerAnimationElement::OPACITY | LayerAnimationElement::TRANSFORM |
+ LayerAnimationElement::BOUNDS),
+ sequence.properties());
}
// Check that a sequence can still be aborted if it has cycled many times.
diff --git a/chromium/ui/compositor/layer_animator.cc b/chromium/ui/compositor/layer_animator.cc
index 0fad04a2cd2..39585a7c946 100644
--- a/chromium/ui/compositor/layer_animator.cc
+++ b/chromium/ui/compositor/layer_animator.cc
@@ -14,7 +14,7 @@
#include "ui/compositor/layer_animation_delegate.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/gfx/animation/animation_container.h"
+#include "ui/compositor/layer_animator_collection.h"
#include "ui/gfx/frame_time.h"
#define SAFE_INVOKE_VOID(function, running_anim, ...) \
@@ -31,22 +31,9 @@
namespace ui {
-class LayerAnimator;
-
namespace {
const int kDefaultTransitionDurationMs = 120;
-const int kTimerIntervalMs = 10;
-
-// Returns the AnimationContainer we're added to.
-gfx::AnimationContainer* GetAnimationContainer() {
- static gfx::AnimationContainer* container = NULL;
- if (!container) {
- container = new gfx::AnimationContainer();
- container->AddRef();
- }
- return container;
-}
} // namespace
@@ -124,7 +111,17 @@ base::TimeDelta LayerAnimator::GetTransitionDuration() const {
}
void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
+ if (delegate_ && is_started_) {
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection)
+ collection->StopAnimator(this);
+ }
delegate_ = delegate;
+ if (delegate_ && is_started_) {
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection)
+ collection->StartAnimator(this);
+ }
}
void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) {
@@ -181,19 +178,20 @@ void LayerAnimator::StartTogether(
adding_animations_ = true;
if (!is_animating()) {
- if (GetAnimationContainer()->is_running())
- last_step_time_ = GetAnimationContainer()->last_tick_time();
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection && collection->HasActiveAnimators())
+ last_step_time_ = collection->last_tick_time();
else
last_step_time_ = gfx::FrameTime::Now();
}
// Collect all the affected properties.
- LayerAnimationElement::AnimatableProperties animated_properties;
+ LayerAnimationElement::AnimatableProperties animated_properties =
+ LayerAnimationElement::UNKNOWN;
+
std::vector<LayerAnimationSequence*>::const_iterator iter;
- for (iter = animations.begin(); iter != animations.end(); ++iter) {
- animated_properties.insert((*iter)->properties().begin(),
- (*iter)->properties().end());
- }
+ for (iter = animations.begin(); iter != animations.end(); ++iter)
+ animated_properties |= (*iter)->properties();
// Starting a zero duration pause that affects all the animated properties
// will prevent any of the sequences from animating until there are no
@@ -227,12 +225,12 @@ void LayerAnimator::ScheduleTogether(
scoped_refptr<LayerAnimator> retain(this);
// Collect all the affected properties.
- LayerAnimationElement::AnimatableProperties animated_properties;
+ LayerAnimationElement::AnimatableProperties animated_properties =
+ LayerAnimationElement::UNKNOWN;
+
std::vector<LayerAnimationSequence*>::const_iterator iter;
- for (iter = animations.begin(); iter != animations.end(); ++iter) {
- animated_properties.insert((*iter)->properties().begin(),
- (*iter)->properties().end());
- }
+ for (iter = animations.begin(); iter != animations.end(); ++iter)
+ animated_properties |= (*iter)->properties();
// Scheduling a zero duration pause that affects all the animated properties
// will prevent any of the sequences from animating until there are no
@@ -260,16 +258,7 @@ void LayerAnimator::ScheduleTogether(
void LayerAnimator::SchedulePauseForProperties(
base::TimeDelta duration,
- LayerAnimationElement::AnimatableProperty property,
- ...) {
- ui::LayerAnimationElement::AnimatableProperties properties_to_pause;
- va_list marker;
- va_start(marker, property);
- for (int p = static_cast<int>(property); p != -1; p = va_arg(marker, int)) {
- properties_to_pause.insert(
- static_cast<LayerAnimationElement::AnimatableProperty>(p));
- }
- va_end(marker);
+ LayerAnimationElement::AnimatableProperties properties_to_pause) {
ScheduleAnimation(new ui::LayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
properties_to_pause, duration)));
@@ -279,10 +268,8 @@ bool LayerAnimator::IsAnimatingProperty(
LayerAnimationElement::AnimatableProperty property) const {
for (AnimationQueue::const_iterator queue_iter = animation_queue_.begin();
queue_iter != animation_queue_.end(); ++queue_iter) {
- if ((*queue_iter)->properties().find(property) !=
- (*queue_iter)->properties().end()) {
+ if ((*queue_iter)->properties() & property)
return true;
- }
}
return false;
}
@@ -333,8 +320,7 @@ void LayerAnimator::OnThreadedAnimationStarted(
if (!running->sequence()->waiting_for_group_start())
return;
- base::TimeTicks start_time = base::TimeTicks::FromInternalValue(
- event.monotonic_time * base::Time::kMicrosecondsPerSecond);
+ base::TimeTicks start_time = event.monotonic_time;
running->sequence()->set_waiting_for_group_start(false);
@@ -355,6 +341,20 @@ void LayerAnimator::OnThreadedAnimationStarted(
}
}
+void LayerAnimator::AddToCollection(LayerAnimatorCollection* collection) {
+ if (is_animating() && !is_started_) {
+ collection->StartAnimator(this);
+ is_started_ = true;
+ }
+}
+
+void LayerAnimator::RemoveFromCollection(LayerAnimatorCollection* collection) {
+ if (is_animating() && is_started_) {
+ collection->StopAnimator(this);
+ is_started_ = false;
+ }
+}
+
// LayerAnimator protected -----------------------------------------------------
void LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence,
@@ -407,14 +407,6 @@ void LayerAnimator::Step(base::TimeTicks now) {
}
}
-void LayerAnimator::SetStartTime(base::TimeTicks start_time) {
- // Do nothing.
-}
-
-base::TimeDelta LayerAnimator::GetTimerInterval() const {
- return base::TimeDelta::FromMilliseconds(kTimerIntervalMs);
-}
-
void LayerAnimator::StopAnimatingInternal(bool abort) {
scoped_refptr<LayerAnimator> retain(this);
while (is_animating()) {
@@ -443,12 +435,16 @@ void LayerAnimator::UpdateAnimationState() {
return;
const bool should_start = is_animating();
- if (should_start && !is_started_)
- GetAnimationContainer()->Start(this);
- else if (!should_start && is_started_)
- GetAnimationContainer()->Stop(this);
-
- is_started_ = should_start;
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
+ if (collection) {
+ if (should_start && !is_started_)
+ collection->StartAnimator(this);
+ else if (!should_start && is_started_)
+ collection->StopAnimator(this);
+ is_started_ = should_start;
+ } else {
+ is_started_ = false;
+ }
}
LayerAnimationSequence* LayerAnimator::RemoveAnimation(
@@ -556,8 +552,7 @@ LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation(
PurgeDeletedAnimations();
for (RunningAnimations::iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
- if ((*iter).sequence()->properties().find(property) !=
- (*iter).sequence()->properties().end())
+ if ((*iter).sequence()->properties() & property)
return &(*iter);
}
return NULL;
@@ -708,13 +703,14 @@ void LayerAnimator::ProcessQueue() {
do {
started_sequence = false;
// Build a list of all currently animated properties.
- LayerAnimationElement::AnimatableProperties animated;
+ LayerAnimationElement::AnimatableProperties animated =
+ LayerAnimationElement::UNKNOWN;
for (RunningAnimations::const_iterator iter = running_animations_.begin();
iter != running_animations_.end(); ++iter) {
if (!(*iter).is_sequence_alive())
continue;
- animated.insert((*iter).sequence()->properties().begin(),
- (*iter).sequence()->properties().end());
+
+ animated |= (*iter).sequence()->properties();
}
// Try to find an animation that doesn't conflict with an animated
@@ -744,8 +740,7 @@ void LayerAnimator::ProcessQueue() {
// the first element because it animates the transform, too. We cannot
// start the second element, either, because the first element animates
// bounds too, and needs to go first.
- animated.insert(sequences[i]->properties().begin(),
- sequences[i]->properties().end());
+ animated |= sequences[i]->properties();
}
// If we started a sequence, try again. We may be able to start several.
@@ -766,14 +761,15 @@ bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) {
// a resolution that can be as bad as 15ms. If this causes glitches in the
// animations, this can be switched to HighResNow() (animation uses Now()
// internally).
- // All LayerAnimators share the same AnimationContainer. Use the
+ // All LayerAnimators share the same LayerAnimatorCollection. Use the
// last_tick_time() from there to ensure animations started during the same
// event complete at the same time.
base::TimeTicks start_time;
+ LayerAnimatorCollection* collection = GetLayerAnimatorCollection();
if (is_animating() || adding_animations_)
start_time = last_step_time_;
- else if (GetAnimationContainer()->is_running())
- start_time = GetAnimationContainer()->last_tick_time();
+ else if (collection && collection->HasActiveAnimators())
+ start_time = collection->last_tick_time();
else
start_time = gfx::FrameTime::Now();
@@ -852,6 +848,10 @@ void LayerAnimator::PurgeDeletedAnimations() {
}
}
+LayerAnimatorCollection* LayerAnimator::GetLayerAnimatorCollection() {
+ return delegate_ ? delegate_->GetLayerAnimatorCollection() : NULL;
+}
+
LayerAnimator::RunningAnimation::RunningAnimation(
const base::WeakPtr<LayerAnimationSequence>& sequence)
: sequence_(sequence) {
diff --git a/chromium/ui/compositor/layer_animator.h b/chromium/ui/compositor/layer_animator.h
index ad3754de158..69744f8c462 100644
--- a/chromium/ui/compositor/layer_animator.h
+++ b/chromium/ui/compositor/layer_animator.h
@@ -9,13 +9,13 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "ui/compositor/compositor_export.h"
#include "ui/compositor/layer_animation_element.h"
-#include "ui/gfx/animation/animation_container_element.h"
#include "ui/gfx/animation/tween.h"
namespace gfx {
@@ -29,6 +29,7 @@ class Layer;
class LayerAnimationSequence;
class LayerAnimationDelegate;
class LayerAnimationObserver;
+class LayerAnimatorCollection;
class ScopedLayerAnimationSettings;
// When a property of layer needs to be changed it is set by way of
@@ -40,9 +41,7 @@ class ScopedLayerAnimationSettings;
// ensure that it is not disposed of until it finishes executing. It does this
// by holding a reference to itself for the duration of methods for which it
// must guarantee that |this| is valid.
-class COMPOSITOR_EXPORT LayerAnimator
- : public gfx::AnimationContainerElement,
- public base::RefCounted<LayerAnimator> {
+class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator> {
public:
enum PreemptionStrategy {
IMMEDIATELY_SET_NEW_TARGET,
@@ -138,8 +137,7 @@ class COMPOSITOR_EXPORT LayerAnimator
// End the list with -1.
void SchedulePauseForProperties(
base::TimeDelta duration,
- LayerAnimationElement::AnimatableProperty property,
- ...);
+ LayerAnimationElement::AnimatableProperties properties_to_pause);
// Returns true if there is an animation in the queue (animations remain in
// the queue until they complete, so this includes running animations).
@@ -189,6 +187,11 @@ class COMPOSITOR_EXPORT LayerAnimator
}
base::TimeTicks last_step_time() const { return last_step_time_; }
+ void Step(base::TimeTicks time_now);
+
+ void AddToCollection(LayerAnimatorCollection* collection);
+ void RemoveFromCollection(LayerAnimatorCollection* collection);
+
protected:
virtual ~LayerAnimator();
@@ -208,6 +211,9 @@ class COMPOSITOR_EXPORT LayerAnimator
friend class base::RefCounted<LayerAnimator>;
friend class ScopedLayerAnimationSettings;
friend class LayerAnimatorTestController;
+ FRIEND_TEST_ALL_PREFIXES(LayerAnimatorTest, AnimatorStartedCorrectly);
+ FRIEND_TEST_ALL_PREFIXES(LayerAnimatorTest,
+ AnimatorRemovedFromCollectionWhenLayerIsDestroyed);
class RunningAnimation {
public:
@@ -226,11 +232,6 @@ class COMPOSITOR_EXPORT LayerAnimator
typedef std::vector<RunningAnimation> RunningAnimations;
typedef std::deque<linked_ptr<LayerAnimationSequence> > AnimationQueue;
- // Implementation of AnimationContainerElement
- virtual void SetStartTime(base::TimeTicks start_time) OVERRIDE;
- virtual void Step(base::TimeTicks time_now) OVERRIDE;
- virtual base::TimeDelta GetTimerInterval() const OVERRIDE;
-
// Finishes all animations by either advancing them to their final state or by
// aborting them.
void StopAnimatingInternal(bool abort);
@@ -308,6 +309,8 @@ class COMPOSITOR_EXPORT LayerAnimator
// Cleans up any running animations that may have been deleted.
void PurgeDeletedAnimations();
+ LayerAnimatorCollection* GetLayerAnimatorCollection();
+
// This is the queue of animations to run.
AnimationQueue animation_queue_;
diff --git a/chromium/ui/compositor/layer_animator_collection.cc b/chromium/ui/compositor/layer_animator_collection.cc
new file mode 100644
index 00000000000..12142d88827
--- /dev/null
+++ b/chromium/ui/compositor/layer_animator_collection.cc
@@ -0,0 +1,56 @@
+// 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/compositor/layer_animator_collection.h"
+
+#include <set>
+
+#include "base/time/time.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/gfx/frame_time.h"
+
+namespace ui {
+
+LayerAnimatorCollection::LayerAnimatorCollection(
+ LayerAnimatorCollectionDelegate* delegate)
+ : delegate_(delegate),
+ last_tick_time_(gfx::FrameTime::Now()) {
+}
+
+LayerAnimatorCollection::~LayerAnimatorCollection() {
+}
+
+void LayerAnimatorCollection::StartAnimator(
+ scoped_refptr<LayerAnimator> animator) {
+ DCHECK_EQ(0U, animators_.count(animator));
+ if (!animators_.size())
+ last_tick_time_ = gfx::FrameTime::Now();
+ animators_.insert(animator);
+ if (delegate_)
+ delegate_->ScheduleAnimationForLayerCollection();
+}
+
+void LayerAnimatorCollection::StopAnimator(
+ scoped_refptr<LayerAnimator> animator) {
+ DCHECK_GT(animators_.count(animator), 0U);
+ animators_.erase(animator);
+}
+
+bool LayerAnimatorCollection::HasActiveAnimators() const {
+ return !animators_.empty();
+}
+
+void LayerAnimatorCollection::Progress(base::TimeTicks now) {
+ last_tick_time_ = now;
+ std::set<scoped_refptr<LayerAnimator> > list = animators_;
+ for (std::set<scoped_refptr<LayerAnimator> >::iterator iter = list.begin();
+ iter != list.end();
+ ++iter) {
+ // Make sure the animator is still valid.
+ if (animators_.count(*iter) > 0)
+ (*iter)->Step(now);
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/layer_animator_collection.h b/chromium/ui/compositor/layer_animator_collection.h
new file mode 100644
index 00000000000..2789eda3cb4
--- /dev/null
+++ b/chromium/ui/compositor/layer_animator_collection.h
@@ -0,0 +1,56 @@
+// 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_COMPOSITOR_LAYER_ANIMATOR_COLLECTION_H_
+#define UI_COMPOSITOR_LAYER_ANIMATOR_COLLECTION_H_
+
+#include <set>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "ui/compositor/compositor_export.h"
+
+namespace base {
+class TimeTicks;
+}
+
+namespace ui {
+
+class LayerAnimator;
+
+class COMPOSITOR_EXPORT LayerAnimatorCollectionDelegate {
+ public:
+ virtual ~LayerAnimatorCollectionDelegate() {}
+
+ virtual void ScheduleAnimationForLayerCollection() = 0;
+};
+
+// A collection of LayerAnimators that should be updated at each animation step
+// in the compositor.
+class COMPOSITOR_EXPORT LayerAnimatorCollection {
+ public:
+ explicit LayerAnimatorCollection(LayerAnimatorCollectionDelegate* delegate);
+ ~LayerAnimatorCollection();
+
+ void StartAnimator(scoped_refptr<LayerAnimator> animator);
+ void StopAnimator(scoped_refptr<LayerAnimator> animator);
+
+ bool HasActiveAnimators() const;
+
+ void Progress(base::TimeTicks now);
+
+ base::TimeTicks last_tick_time() const { return last_tick_time_; }
+
+ private:
+ LayerAnimatorCollectionDelegate* delegate_;
+ base::TimeTicks last_tick_time_;
+ std::set<scoped_refptr<LayerAnimator> > animators_;
+
+ DISALLOW_COPY_AND_ASSIGN(LayerAnimatorCollection);
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_LAYER_ANIMATOR_COLLECTION_H_
diff --git a/chromium/ui/compositor/layer_animator_unittest.cc b/chromium/ui/compositor/layer_animator_unittest.cc
index 7c5220057ea..3ae8c2b34eb 100644
--- a/chromium/ui/compositor/layer_animator_unittest.cc
+++ b/chromium/ui/compositor/layer_animator_unittest.cc
@@ -14,9 +14,12 @@
#include "ui/compositor/layer_animation_delegate.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/layer_animator_collection.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/context_factories_for_test.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/compositor/test/test_compositor_host.h"
#include "ui/compositor/test/test_layer_animation_delegate.h"
#include "ui/compositor/test/test_layer_animation_observer.h"
#include "ui/compositor/test/test_utils.h"
@@ -24,8 +27,6 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
-using gfx::AnimationContainerElement;
-
namespace ui {
namespace {
@@ -120,12 +121,41 @@ class DeletingLayerAnimationObserver : public LayerAnimationObserver {
DISALLOW_COPY_AND_ASSIGN(DeletingLayerAnimationObserver);
};
+class LayerAnimatorDestructionObserver {
+ public:
+ LayerAnimatorDestructionObserver() : animator_deleted_(false) {}
+ virtual ~LayerAnimatorDestructionObserver() {}
+
+ void NotifyAnimatorDeleted() {
+ animator_deleted_ = true;
+ }
+
+ bool IsAnimatorDeleted() {
+ return animator_deleted_;
+ }
+
+ private:
+ bool animator_deleted_;
+
+ DISALLOW_COPY_AND_ASSIGN(LayerAnimatorDestructionObserver);
+};
+
class TestLayerAnimator : public LayerAnimator {
public:
- TestLayerAnimator() : LayerAnimator(base::TimeDelta::FromSeconds(0)) {}
+ TestLayerAnimator() : LayerAnimator(base::TimeDelta::FromSeconds(0)),
+ destruction_observer_(NULL) {}
+
+ void SetDestructionObserver(
+ LayerAnimatorDestructionObserver* observer) {
+ destruction_observer_ = observer;
+ }
protected:
- virtual ~TestLayerAnimator() {}
+ virtual ~TestLayerAnimator() {
+ if (destruction_observer_) {
+ destruction_observer_->NotifyAnimatorDeleted();
+ }
+ }
virtual void ProgressAnimation(LayerAnimationSequence* sequence,
base::TimeTicks now) OVERRIDE {
@@ -134,6 +164,8 @@ class TestLayerAnimator : public LayerAnimator {
}
private:
+ LayerAnimatorDestructionObserver* destruction_observer_;
+
DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator);
};
@@ -165,14 +197,13 @@ class TestLayerAnimationSequence : public LayerAnimationSequence {
TEST(LayerAnimatorTest, ImplicitAnimation) {
scoped_refptr<LayerAnimator> animator(
LayerAnimator::CreateImplicitAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
base::TimeTicks now = gfx::FrameTime::Now();
animator->SetBrightness(0.5);
EXPECT_TRUE(animator->is_animating());
- element->Step(now + base::TimeDelta::FromSeconds(1));
+ animator->Step(now + base::TimeDelta::FromSeconds(1));
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), 0.5);
}
@@ -254,7 +285,6 @@ TEST(LayerAnimatorTest, AbortAllAnimations) {
// trivial case and should result in the animation being started immediately.
TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -277,12 +307,12 @@ TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
@@ -293,7 +323,7 @@ TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately) {
double epsilon = 0.00001;
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -318,12 +348,12 @@ TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta/2);
+ animator->Step(effective_start + delta / 2);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_NEAR(
@@ -332,7 +362,7 @@ TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately) {
last_progressed_fraction(),
epsilon);
- element->Step(effective_start + delta);
+ animator->Step(effective_start + delta);
EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
@@ -342,7 +372,6 @@ TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately) {
// should start immediately and should progress in lock step.
TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -376,13 +405,13 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
@@ -395,7 +424,7 @@ TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations) {
double epsilon = 0.00001;
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -434,12 +463,12 @@ TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta/2);
+ animator->Step(effective_start + delta / 2);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_NEAR(
@@ -449,7 +478,7 @@ TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations) {
epsilon);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);
- element->Step(effective_start + delta);
+ animator->Step(effective_start + delta);
EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
@@ -460,7 +489,6 @@ TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations) {
// animations should run one after another.
TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -488,22 +516,22 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
@@ -514,7 +542,6 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) {
// order.
TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -558,31 +585,31 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(4000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(4000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
@@ -594,7 +621,6 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) {
// the second grayscale animation starts.
TEST(LayerAnimatorTest, ScheduleTogether) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -631,13 +657,13 @@ TEST(LayerAnimatorTest, ScheduleTogether) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
@@ -648,7 +674,6 @@ TEST(LayerAnimatorTest, ScheduleTogether) {
// case (see the trival case for ScheduleAnimation).
TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -671,12 +696,12 @@ TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
@@ -687,7 +712,7 @@ TEST(LayerAnimatorTest, StartThreadedAnimationThatCanRunImmediately) {
double epsilon = 0.00001;
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -712,12 +737,12 @@ TEST(LayerAnimatorTest, StartThreadedAnimationThatCanRunImmediately) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta/2);
+ animator->Step(effective_start + delta / 2);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_NEAR(
@@ -726,7 +751,7 @@ TEST(LayerAnimatorTest, StartThreadedAnimationThatCanRunImmediately) {
last_progressed_fraction(),
epsilon);
- element->Step(effective_start + delta);
+ animator->Step(effective_start + delta);
EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
}
@@ -762,7 +787,6 @@ TEST(LayerAnimatorTest, PreemptBySettingNewTarget) {
// Preempt by animating to new target, with a non-threaded animation.
TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -785,7 +809,7 @@ TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartAnimation(
new LayerAnimationSequence(
@@ -802,13 +826,13 @@ TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) {
EXPECT_TRUE(animator->is_animating());
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
0.5 * (start_brightness + middle_brightness));
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
@@ -819,7 +843,7 @@ TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
double epsilon = 0.00001;
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -845,12 +869,12 @@ TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta/2);
+ animator->Step(effective_start + delta / 2);
test_controller.animator()->StartAnimation(
new LayerAnimationSequence(
@@ -870,12 +894,12 @@ TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (second_effective_start - base::TimeTicks()).InSecondsF()));
+ second_effective_start));
- element->Step(second_effective_start + delta/2);
+ animator->Step(second_effective_start + delta / 2);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_NEAR(
@@ -884,7 +908,7 @@ TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
last_progressed_fraction(),
epsilon);
- element->Step(second_effective_start + delta);
+ animator->Step(second_effective_start + delta);
EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
@@ -893,7 +917,6 @@ TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget) {
// Preempt by enqueuing the new animation.
TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -915,7 +938,7 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartAnimation(
new LayerAnimationSequence(
@@ -927,17 +950,17 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
EXPECT_TRUE(animator->is_animating());
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
@@ -948,7 +971,6 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) {
// animation started.
TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -970,7 +992,7 @@ TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartAnimation(
new LayerAnimationSequence(
@@ -987,17 +1009,17 @@ TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) {
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
@@ -1082,7 +1104,6 @@ TEST(LayerAnimatorTest, MultiPreemptBySettingNewTarget) {
// Preempt by animating to new target.
TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -1113,7 +1134,7 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartTogether(
CreateMultiSequence(
@@ -1133,7 +1154,7 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
EXPECT_TRUE(animator->is_animating());
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(),
@@ -1141,7 +1162,7 @@ TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
0.5 * (start_brightness + middle_brightness));
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
@@ -1153,7 +1174,7 @@ TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
double epsilon = 0.00001;
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -1187,12 +1208,12 @@ TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta/2);
+ animator->Step(effective_start + delta / 2);
test_controller.animator()->StartTogether(
CreateMultiSequence(
@@ -1217,12 +1238,12 @@ TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (second_effective_start - base::TimeTicks()).InSecondsF()));
+ second_effective_start));
- element->Step(second_effective_start + delta/2);
+ animator->Step(second_effective_start + delta / 2);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_NEAR(
@@ -1234,7 +1255,7 @@ TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
0.5 * (start_brightness + middle_brightness),
epsilon);
- element->Step(second_effective_start + delta);
+ animator->Step(second_effective_start + delta);
EXPECT_FALSE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
@@ -1244,7 +1265,6 @@ TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget) {
// Preempt by enqueuing the new animation.
TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -1273,7 +1293,7 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartTogether(
CreateMultiSequence(
@@ -1287,19 +1307,19 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
EXPECT_TRUE(animator->is_animating());
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
@@ -1311,7 +1331,6 @@ TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
// animation started.
TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -1340,7 +1359,7 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
animator->StartTogether(
CreateMultiSequence(
@@ -1361,19 +1380,19 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_FALSE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
@@ -1383,7 +1402,6 @@ TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
// Test that non-threaded cyclic sequences continue to animate.
TEST(LayerAnimatorTest, CyclicSequences) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -1409,29 +1427,29 @@ TEST(LayerAnimatorTest, CyclicSequences) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(3000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
// Skip ahead by a lot.
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000000000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000000000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
// Skip ahead by a lot.
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000001000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000001000));
EXPECT_TRUE(animator->is_animating());
EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
@@ -1445,7 +1463,7 @@ TEST(LayerAnimatorTest, CyclicSequences) {
TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
LayerAnimatorTestController test_controller(
LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = test_controller.animator();
+ LayerAnimator* animator = test_controller.animator();
test_controller.animator()->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
test_controller.animator()->SetDelegate(&delegate);
@@ -1474,12 +1492,12 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (effective_start - base::TimeTicks()).InSecondsF()));
+ effective_start));
- element->Step(effective_start + delta);
+ animator->Step(effective_start + delta);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
@@ -1487,12 +1505,12 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (second_effective_start - base::TimeTicks()).InSecondsF()));
+ second_effective_start));
- element->Step(second_effective_start + delta);
+ animator->Step(second_effective_start + delta);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
@@ -1501,12 +1519,12 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (third_effective_start - base::TimeTicks()).InSecondsF()));
+ third_effective_start));
- element->Step(third_effective_start + delta);
+ animator->Step(third_effective_start + delta);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
@@ -1514,13 +1532,13 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (fourth_effective_start - base::TimeTicks()).InSecondsF()));
+ fourth_effective_start));
// Skip ahead by a lot.
- element->Step(fourth_effective_start + 1000 * delta);
+ animator->Step(fourth_effective_start + 1000 * delta);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
@@ -1529,13 +1547,13 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
cc::AnimationEvent::Started,
0,
- test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->
- animation_group_id(),
+ test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
+ ->animation_group_id(),
cc::Animation::Opacity,
- (fifth_effective_start - base::TimeTicks()).InSecondsF()));
+ fifth_effective_start));
// Skip ahead by a lot.
- element->Step(fifth_effective_start + 999 * delta);
+ animator->Step(fifth_effective_start + 999 * delta);
EXPECT_TRUE(test_controller.animator()->is_animating());
EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
@@ -1548,7 +1566,6 @@ TEST(LayerAnimatorTest, ThreadedCyclicSequences) {
TEST(LayerAnimatorTest, AddObserverExplicit) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationObserver observer;
TestLayerAnimationDelegate delegate;
@@ -1571,7 +1588,7 @@ TEST(LayerAnimatorTest, AddObserverExplicit) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_EQ(observer.last_ended_sequence(), sequence);
@@ -1590,7 +1607,6 @@ TEST(LayerAnimatorTest, AddObserverExplicit) {
// when the object goes out of scope.
TEST(LayerAnimatorTest, ImplicitAnimationObservers) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestImplicitAnimationObserver observer(false);
TestLayerAnimationDelegate delegate;
@@ -1607,7 +1623,7 @@ TEST(LayerAnimatorTest, ImplicitAnimationObservers) {
EXPECT_FALSE(observer.animations_completed());
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_TRUE(observer.animations_completed());
EXPECT_TRUE(observer.WasAnimationCompletedForProperty(
LayerAnimationElement::BRIGHTNESS));
@@ -1642,6 +1658,29 @@ TEST(LayerAnimatorTest, InterruptedImplicitAnimationObservers) {
EXPECT_FLOAT_EQ(1.0f, delegate.GetBrightnessForAnimation());
}
+// Tests that LayerAnimator is not deleted after the animation completes as long
+// as there is a live ScopedLayerAnimationSettings object wrapped around it.
+TEST(LayerAnimatorTest, AnimatorKeptAliveBySettings) {
+ // Note we are using a raw pointer unlike in other tests.
+ TestLayerAnimator* animator = new TestLayerAnimator();
+ LayerAnimatorDestructionObserver destruction_observer;
+ animator->SetDestructionObserver(&destruction_observer);
+ animator->set_disable_timer_for_test(true);
+ TestLayerAnimationDelegate delegate;
+ animator->SetDelegate(&delegate);
+ {
+ // ScopedLayerAnimationSettings should keep the Animator alive as long as
+ // it is alive, even beyond the end of the animation.
+ ScopedLayerAnimationSettings settings(animator);
+ base::TimeTicks now = gfx::FrameTime::Now();
+ animator->SetBrightness(0.5);
+ animator->Step(now + base::TimeDelta::FromSeconds(1));
+ EXPECT_FALSE(destruction_observer.IsAnimatorDeleted());
+ }
+ // ScopedLayerAnimationSettings was destroyed, so Animator should be deleted.
+ EXPECT_TRUE(destruction_observer.IsAnimatorDeleted());
+}
+
// Tests that an observer added to a scoped settings object is not notified
// when the animator is destroyed unless explicitly requested.
TEST(LayerAnimatorTest, ImplicitObserversAtAnimatorDestruction) {
@@ -1715,7 +1754,6 @@ TEST(LayerAnimatorTest, AbortedAnimationStatusInImplicitObservers) {
TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationObserver observer;
TestLayerAnimationObserver removed_observer;
@@ -1742,7 +1780,7 @@ TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_EQ(observer.last_ended_sequence(), sequence);
EXPECT_TRUE(!removed_observer.last_ended_sequence());
@@ -1778,7 +1816,6 @@ TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds) {
TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestImplicitAnimationObserver observer(false);
@@ -1796,14 +1833,14 @@ TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) {
animator->StartAnimation(sequence);
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
setter.AddObserver(&observer);
// Start observing an in-flight animation.
sequence->AddObserver(&observer);
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
}
EXPECT_TRUE(observer.animations_completed());
@@ -1813,7 +1850,6 @@ TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) {
TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestImplicitAnimationObserver observer(false);
@@ -1831,7 +1867,7 @@ TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished) {
animator->StartAnimation(sequence);
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
}
EXPECT_FALSE(observer.animations_completed());
@@ -1857,7 +1893,6 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimationsOnEnd) {
ScopedAnimationDurationScaleMode normal_duration_mode(
ScopedAnimationDurationScaleMode::NORMAL_DURATION);
scoped_refptr<LayerAnimator> animator(new TestLayerAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -1891,7 +1926,7 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimationsOnEnd) {
ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + halfway_delta);
+ animator->Step(start_time + halfway_delta);
// Completing the brightness animation should have stopped the bounds
// animation.
@@ -1927,7 +1962,6 @@ TEST(LayerAnimatorTest, CallbackDeletesAnimationInProgress) {
ScopedAnimationDurationScaleMode normal_duration_mode(
ScopedAnimationDurationScaleMode::NORMAL_DURATION);
scoped_refptr<LayerAnimator> animator(new TestLayerAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDeletingDelegate delegate(animator.get(), 30);
animator->SetDelegate(&delegate);
@@ -1948,14 +1982,14 @@ TEST(LayerAnimatorTest, CallbackDeletesAnimationInProgress) {
ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
base::TimeTicks start_time = animator->last_step_time();
- ASSERT_NO_FATAL_FAILURE(element->Step(start_time + bounds_delta1));
+ ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + bounds_delta1));
ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
// The next step should change the animated bounds past the threshold and
// cause the animaton to stop.
- ASSERT_NO_FATAL_FAILURE(element->Step(start_time + bounds_delta2));
+ ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + bounds_delta2));
ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
- ASSERT_NO_FATAL_FAILURE(element->Step(start_time + final_delta));
+ ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + final_delta));
// Completing the animation should have stopped the bounds
// animation.
@@ -2145,7 +2179,6 @@ TEST(LayerAnimatorTest, GetTargetGrayscale) {
// Verifies color property is modified appropriately.
TEST(LayerAnimatorTest, Color) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
- AnimationContainerElement* element = animator.get();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -2168,13 +2201,13 @@ TEST(LayerAnimatorTest, Color) {
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(animator->is_animating());
EXPECT_EQ(ColorToString(middle_color),
ColorToString(delegate.GetColorForAnimation()));
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
EXPECT_FALSE(animator->is_animating());
EXPECT_EQ(ColorToString(target_color),
@@ -2185,9 +2218,9 @@ TEST(LayerAnimatorTest, Color) {
TEST(LayerAnimatorTest, SchedulePauseForProperties) {
scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
- animator->SchedulePauseForProperties(base::TimeDelta::FromMilliseconds(100),
- LayerAnimationElement::TRANSFORM,
- LayerAnimationElement::BOUNDS, -1);
+ animator->SchedulePauseForProperties(
+ base::TimeDelta::FromMilliseconds(100),
+ LayerAnimationElement::TRANSFORM | LayerAnimationElement::BOUNDS);
EXPECT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::TRANSFORM));
EXPECT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
EXPECT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::OPACITY));
@@ -2282,7 +2315,6 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation) {
observer->set_delete_on_animation_ended(true);
observer->set_delete_on_animation_aborted(true);
LayerAnimator* animator = observer->animator();
- AnimationContainerElement* element = observer->animator();
animator->set_disable_timer_for_test(true);
TestLayerAnimationDelegate delegate;
animator->SetDelegate(&delegate);
@@ -2305,7 +2337,7 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation) {
animator->StartAnimation(bounds_sequence);
base::TimeTicks start_time = animator->last_step_time();
- element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+ animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
EXPECT_TRUE(observer_was_deleted);
}
@@ -2470,4 +2502,122 @@ TEST(LayerAnimatorTest, TestScopedCounterAnimation) {
}
+class CollectionLayerAnimationDelegate : public TestLayerAnimationDelegate {
+ public:
+ CollectionLayerAnimationDelegate() : collection(NULL) {}
+ virtual ~CollectionLayerAnimationDelegate() {}
+
+ // LayerAnimationDelegate:
+ virtual LayerAnimatorCollection* GetLayerAnimatorCollection() OVERRIDE {
+ return &collection;
+ }
+
+ private:
+ LayerAnimatorCollection collection;
+};
+
+TEST(LayerAnimatorTest, LayerAnimatorCollectionTickTime) {
+ Layer layer;
+ LayerAnimator* animator = layer.GetAnimator();
+ CollectionLayerAnimationDelegate delegate;
+ animator->SetDelegate(&delegate);
+
+ LayerAnimatorCollection* collection = delegate.GetLayerAnimatorCollection();
+ base::TimeTicks null;
+ collection->Progress(null);
+ EXPECT_TRUE(collection->last_tick_time().is_null());
+
+ // Adding an animator to the collection should update the last tick time.
+ collection->StartAnimator(layer.GetAnimator());
+ EXPECT_TRUE(collection->HasActiveAnimators());
+ EXPECT_FALSE(collection->last_tick_time().is_null());
+
+ collection->StopAnimator(layer.GetAnimator());
+ EXPECT_FALSE(collection->HasActiveAnimators());
+}
+
+TEST(LayerAnimatorTest, AnimatorStartedCorrectly) {
+ Layer layer;
+ LayerAnimatorTestController test_controller(layer.GetAnimator());
+ LayerAnimator* animator = test_controller.animator();
+ ASSERT_FALSE(animator->is_started_);
+
+ TestLayerAnimationDelegate test_delegate;
+ animator->SetDelegate(&test_delegate);
+ double target_opacity = 1.0;
+ base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
+ animator->ScheduleAnimation(new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));
+ EXPECT_FALSE(animator->is_started_);
+
+ CollectionLayerAnimationDelegate collection_delegate;
+ animator->SetDelegate(&collection_delegate);
+ animator->UpdateAnimationState();
+ EXPECT_TRUE(animator->is_started_);
+ animator->SetDelegate(NULL);
+}
+
+TEST(LayerAnimatorTest, AnimatorRemovedFromCollectionWhenLayerIsDestroyed) {
+ scoped_ptr<Layer> layer(new Layer(LAYER_TEXTURED));
+ LayerAnimatorTestController test_controller(layer->GetAnimator());
+ scoped_refptr<LayerAnimator> animator = test_controller.animator();
+ CollectionLayerAnimationDelegate collection_delegate;
+ animator->SetDelegate(&collection_delegate);
+
+ double target_opacity = 1.0;
+ base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
+ animator->ScheduleAnimation(new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));
+
+ EXPECT_TRUE(
+ collection_delegate.GetLayerAnimatorCollection()->HasActiveAnimators());
+
+ layer.reset();
+ EXPECT_EQ(NULL, animator->delegate());
+ EXPECT_FALSE(
+ collection_delegate.GetLayerAnimatorCollection()->HasActiveAnimators());
+}
+
+TEST(LayerAnimatorTest, LayerMovedBetweenCompositorsDuringAnimation) {
+ bool enable_pixel_output = false;
+ ui::ContextFactory* context_factory =
+ InitializeContextFactoryForTests(enable_pixel_output);
+ const gfx::Rect bounds(10, 10, 100, 100);
+ scoped_ptr<TestCompositorHost> host_1(
+ TestCompositorHost::Create(bounds, context_factory));
+ scoped_ptr<TestCompositorHost> host_2(
+ TestCompositorHost::Create(bounds, context_factory));
+ host_1->Show();
+ host_2->Show();
+
+ Compositor* compositor_1 = host_1->GetCompositor();
+ Layer root_1;
+ compositor_1->SetRootLayer(&root_1);
+
+ Compositor* compositor_2 = host_2->GetCompositor();
+ Layer root_2;
+ compositor_2->SetRootLayer(&root_2);
+
+ // Verify that neither compositor has active animators.
+ EXPECT_FALSE(compositor_1->layer_animator_collection()->HasActiveAnimators());
+ EXPECT_FALSE(compositor_2->layer_animator_collection()->HasActiveAnimators());
+
+ Layer layer;
+ root_1.Add(&layer);
+ LayerAnimator* animator = layer.GetAnimator();
+ double target_opacity = 1.0;
+ base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
+ animator->ScheduleAnimation(new LayerAnimationSequence(
+ LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));
+ EXPECT_TRUE(compositor_1->layer_animator_collection()->HasActiveAnimators());
+ EXPECT_FALSE(compositor_2->layer_animator_collection()->HasActiveAnimators());
+
+ root_2.Add(&layer);
+ EXPECT_FALSE(compositor_1->layer_animator_collection()->HasActiveAnimators());
+ EXPECT_TRUE(compositor_2->layer_animator_collection()->HasActiveAnimators());
+ host_2.reset();
+ host_1.reset();
+ TerminateContextFactoryForTests();
+}
+
} // namespace ui
diff --git a/chromium/ui/compositor/layer_owner.cc b/chromium/ui/compositor/layer_owner.cc
index 1f4ffc86110..6a22e9a4a93 100644
--- a/chromium/ui/compositor/layer_owner.cc
+++ b/chromium/ui/compositor/layer_owner.cc
@@ -4,17 +4,81 @@
#include "ui/compositor/layer_owner.h"
+#include "ui/compositor/layer_owner_delegate.h"
+
namespace ui {
-LayerOwner::LayerOwner()
- : layer_(NULL) {
+LayerOwner::LayerOwner() : layer_(NULL), layer_owner_delegate_(NULL) {
}
LayerOwner::~LayerOwner() {
}
-Layer* LayerOwner::AcquireLayer() {
- return layer_owner_.release();
+void LayerOwner::SetLayer(Layer* layer) {
+ DCHECK(!OwnsLayer());
+ layer_owner_.reset(layer);
+ layer_ = layer;
+ layer_->owner_ = this;
+}
+
+scoped_ptr<Layer> LayerOwner::AcquireLayer() {
+ if (layer_owner_)
+ layer_owner_->owner_ = NULL;
+ return layer_owner_.Pass();
+}
+
+scoped_ptr<Layer> LayerOwner::RecreateLayer() {
+ scoped_ptr<ui::Layer> old_layer(AcquireLayer());
+ if (!old_layer)
+ return old_layer.Pass();
+
+ LayerDelegate* old_delegate = old_layer->delegate();
+ old_layer->set_delegate(NULL);
+
+ const gfx::Rect layer_bounds(old_layer->bounds());
+ Layer* new_layer = new ui::Layer(old_layer->type());
+ SetLayer(new_layer);
+ new_layer->SetVisible(old_layer->GetTargetVisibility());
+ new_layer->SetOpacity(old_layer->GetTargetOpacity());
+ new_layer->SetBounds(layer_bounds);
+ new_layer->SetMasksToBounds(old_layer->GetMasksToBounds());
+ new_layer->set_name(old_layer->name());
+ new_layer->SetFillsBoundsOpaquely(old_layer->fills_bounds_opaquely());
+ new_layer->SetFillsBoundsCompletely(old_layer->FillsBoundsCompletely());
+
+ // Install new layer as a sibling of the old layer, stacked below it.
+ if (old_layer->parent()) {
+ old_layer->parent()->Add(new_layer);
+ old_layer->parent()->StackBelow(new_layer, old_layer.get());
+ }
+
+ // Migrate all the child layers over to the new layer. Copy the list because
+ // the items are removed during iteration.
+ std::vector<ui::Layer*> children_copy = old_layer->children();
+ for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin();
+ it != children_copy.end();
+ ++it) {
+ ui::Layer* child = *it;
+ new_layer->Add(child);
+ }
+
+ // Install the delegate last so that the delegate isn't notified as we copy
+ // state to the new layer.
+ new_layer->set_delegate(old_delegate);
+
+ if (layer_owner_delegate_)
+ layer_owner_delegate_->OnLayerRecreated(old_layer.get(), new_layer);
+
+ return old_layer.Pass();
+}
+
+void LayerOwner::DestroyLayer() {
+ layer_ = NULL;
+ layer_owner_.reset();
+}
+
+bool LayerOwner::OwnsLayer() const {
+ return !!layer_owner_;
}
} // namespace ui
diff --git a/chromium/ui/compositor/layer_owner.h b/chromium/ui/compositor/layer_owner.h
index 8f115d5441c..27002e5db02 100644
--- a/chromium/ui/compositor/layer_owner.h
+++ b/chromium/ui/compositor/layer_owner.h
@@ -11,24 +11,43 @@
#include "ui/compositor/layer.h"
namespace ui {
+class LayerOwnerDelegate;
class COMPOSITOR_EXPORT LayerOwner {
public:
LayerOwner();
virtual ~LayerOwner();
+ void SetLayer(Layer* layer);
+
// Releases the owning reference to its layer, and returns it.
// This is used when you need to animate the presentation of the owner just
// prior to destroying it. The Owner can be destroyed soon after calling this
// function, and the caller is then responsible for disposing of the layer
// once any animation completes. Note that layer() will remain valid until the
// end of ~LayerOwner().
- Layer* AcquireLayer() WARN_UNUSED_RESULT;
+ scoped_ptr<Layer> AcquireLayer();
+
+ // Asks the owner to recreate the layer, returning the old Layer. NULL is
+ // returned if there is no existing layer, or recreate is not supported.
+ //
+ // This does not recurse. Existing children of the layer are moved to the new
+ // layer.
+ scoped_ptr<Layer> RecreateLayer();
ui::Layer* layer() { return layer_; }
const ui::Layer* layer() const { return layer_; }
+ void set_layer_owner_delegate(LayerOwnerDelegate* delegate) {
+ layer_owner_delegate_ = delegate;
+ }
+
protected:
+ void DestroyLayer();
+
+ bool OwnsLayer() const;
+
+ private:
// The LayerOwner owns its layer unless ownership is relinquished via a call
// to AcquireLayer(). After that moment |layer_| will still be valid but
// |layer_owner_| will be NULL. The reason for releasing ownership is that
@@ -37,7 +56,8 @@ class COMPOSITOR_EXPORT LayerOwner {
scoped_ptr<Layer> layer_owner_;
Layer* layer_;
- private:
+ LayerOwnerDelegate* layer_owner_delegate_;
+
DISALLOW_COPY_AND_ASSIGN(LayerOwner);
};
diff --git a/chromium/ui/compositor/layer_owner_delegate.h b/chromium/ui/compositor/layer_owner_delegate.h
new file mode 100644
index 00000000000..68ba92ee445
--- /dev/null
+++ b/chromium/ui/compositor/layer_owner_delegate.h
@@ -0,0 +1,27 @@
+// 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_COMPOSITOR_LAYER_OWNER_DELEGATE_H_
+#define UI_COMPOSITOR_LAYER_OWNER_DELEGATE_H_
+
+#include "ui/compositor/compositor_export.h"
+
+namespace ui {
+class Layer;
+
+// Called from RecreateLayer() after the new layer was created. old_layer is
+// the layer that will be returned to the caller of RecreateLayer, new_layer
+// will be the layer now used. Used when the layer has external content
+// (SetTextureMailbox / SetDelegatedFrame was called).
+class COMPOSITOR_EXPORT LayerOwnerDelegate {
+ public:
+ virtual void OnLayerRecreated(Layer* old_layer, Layer* new_layer) = 0;
+
+ protected:
+ virtual ~LayerOwnerDelegate() {}
+};
+
+} // namespace ui
+
+#endif // UI_COMPOSITOR_LAYER_OWNER_DELEGATE_H_
diff --git a/chromium/ui/compositor/layer_owner_unittest.cc b/chromium/ui/compositor/layer_owner_unittest.cc
new file mode 100644
index 00000000000..6390ecaf463
--- /dev/null
+++ b/chromium/ui/compositor/layer_owner_unittest.cc
@@ -0,0 +1,33 @@
+// 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/compositor/layer_owner.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+
+namespace ui {
+
+TEST(LayerOwnerTest, RecreateLayerHonorsTargetVisibilityAndOpacity) {
+ LayerOwner owner;
+ Layer* layer = new Layer;
+ layer->SetVisible(true);
+ layer->SetOpacity(1.0f);
+
+ owner.SetLayer(layer);
+
+ ScopedLayerAnimationSettings settings(layer->GetAnimator());
+ layer->SetVisible(false);
+ layer->SetOpacity(0.0f);
+ EXPECT_TRUE(layer->visible());
+ EXPECT_EQ(1.0f, layer->opacity());
+
+ scoped_ptr<Layer> old_layer(owner.RecreateLayer());
+ EXPECT_FALSE(owner.layer()->visible());
+ EXPECT_EQ(0.0f, owner.layer()->opacity());
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/layer_tree_owner.cc b/chromium/ui/compositor/layer_tree_owner.cc
new file mode 100644
index 00000000000..ebb0a7fc7f4
--- /dev/null
+++ b/chromium/ui/compositor/layer_tree_owner.cc
@@ -0,0 +1,34 @@
+// 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/compositor/layer_tree_owner.h"
+
+#include "ui/compositor/layer.h"
+
+namespace ui {
+
+namespace {
+
+// Deletes |layer| and all its descendants.
+void DeepDeleteLayers(Layer* layer) {
+ std::vector<Layer*> children = layer->children();
+ for (std::vector<Layer*>::const_iterator it = children.begin();
+ it != children.end();
+ ++it) {
+ Layer* child = *it;
+ DeepDeleteLayers(child);
+ }
+ delete layer;
+}
+
+} // namespace
+
+LayerTreeOwner::LayerTreeOwner(Layer* root) : root_(root) {}
+
+LayerTreeOwner::~LayerTreeOwner() {
+ if (root_)
+ DeepDeleteLayers(root_);
+}
+
+} // namespace ui
diff --git a/chromium/ui/compositor/layer_tree_owner.h b/chromium/ui/compositor/layer_tree_owner.h
new file mode 100644
index 00000000000..8b753555b47
--- /dev/null
+++ b/chromium/ui/compositor/layer_tree_owner.h
@@ -0,0 +1,38 @@
+// 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_COMPOSITOR_LAYER_TREE_OWNER_H_
+#define UI_COMPOSITOR_LAYER_TREE_OWNER_H_
+
+#include "base/basictypes.h"
+#include "ui/compositor/compositor_export.h"
+
+namespace ui {
+
+class Layer;
+
+// Scoping object that owns a Layer and all its descendants.
+class COMPOSITOR_EXPORT LayerTreeOwner {
+ public:
+ explicit LayerTreeOwner(Layer* root);
+ ~LayerTreeOwner();
+
+ Layer* release() WARN_UNUSED_RESULT {
+ Layer* root = root_;
+ root_ = NULL;
+ return root;
+ }
+
+ Layer* root() { return root_; }
+ const Layer* root() const { return root_; }
+
+ private:
+ Layer* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(LayerTreeOwner);
+};
+
+} // namespace
+
+#endif // UI_COMPOSITOR_LAYER_TREE_OWNER_H_
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index f4e1ab50a80..af85fcf2ca6 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -5,8 +5,10 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
@@ -15,6 +17,8 @@
#include "cc/layers/delegated_frame_provider.h"
#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/layers/layer.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/delegated_frame_data.h"
#include "cc/test/pixel_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +27,7 @@
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/compositor/test/test_compositor_host.h"
#include "ui/compositor/test/test_layers.h"
#include "ui/gfx/canvas.h"
@@ -84,24 +89,22 @@ class LayerWithRealCompositorTest : public testing::Test {
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
- bool allow_test_contexts = false;
- InitializeContextFactoryForTests(allow_test_contexts);
- Compositor::Initialize();
+ bool enable_pixel_output = true;
+ ui::ContextFactory* context_factory =
+ InitializeContextFactoryForTests(enable_pixel_output);
const gfx::Rect host_bounds(10, 10, 500, 500);
- window_.reset(TestCompositorHost::Create(host_bounds));
- window_->Show();
+ compositor_host_.reset(TestCompositorHost::Create(
+ host_bounds, context_factory));
+ compositor_host_->Show();
}
virtual void TearDown() OVERRIDE {
- window_.reset();
+ compositor_host_.reset();
TerminateContextFactoryForTests();
- Compositor::Terminate();
}
- Compositor* GetCompositor() {
- return window_->GetCompositor();
- }
+ Compositor* GetCompositor() { return compositor_host_->GetCompositor(); }
Layer* CreateLayer(LayerType type) {
return new Layer(type);
@@ -126,8 +129,34 @@ class LayerWithRealCompositorTest : public testing::Test {
}
bool ReadPixels(SkBitmap* bitmap) {
- return GetCompositor()->ReadPixels(bitmap,
- gfx::Rect(GetCompositor()->size()));
+ return ReadPixels(bitmap, gfx::Rect(GetCompositor()->size()));
+ }
+
+ bool ReadPixels(SkBitmap* bitmap, gfx::Rect source_rect) {
+ scoped_refptr<ReadbackHolder> holder(new ReadbackHolder);
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&ReadbackHolder::OutputRequestCallback, holder));
+ request->set_area(source_rect);
+
+ GetCompositor()->root_layer()->RequestCopyOfOutput(request.Pass());
+
+ // Wait for copy response. This needs to wait as the compositor could
+ // be in the middle of a draw right now, and the commit with the
+ // copy output request may not be done on the first draw.
+ for (int i = 0; i < 2; i++) {
+ GetCompositor()->ScheduleDraw();
+ WaitForDraw();
+ }
+
+ if (holder->completed()) {
+ *bitmap = holder->result();
+ return true;
+ }
+
+ // Callback never called.
+ NOTREACHED();
+ return false;
}
void WaitForDraw() {
@@ -149,7 +178,30 @@ class LayerWithRealCompositorTest : public testing::Test {
}
private:
- scoped_ptr<TestCompositorHost> window_;
+ class ReadbackHolder : public base::RefCountedThreadSafe<ReadbackHolder> {
+ public:
+ ReadbackHolder() : completed_(false) {}
+
+ void OutputRequestCallback(scoped_ptr<cc::CopyOutputResult> result) {
+ DCHECK(!completed_);
+ result_ = result->TakeBitmap();
+ completed_ = true;
+ }
+ bool completed() const {
+ return completed_;
+ };
+ const SkBitmap& result() const { return *result_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<ReadbackHolder>;
+
+ virtual ~ReadbackHolder() {}
+
+ scoped_ptr<SkBitmap> result_;
+ bool completed_;
+ };
+
+ scoped_ptr<TestCompositorHost> compositor_host_;
// The root directory for test files.
base::FilePath test_data_directory_;
@@ -180,8 +232,8 @@ class TestLayerDelegate : public LayerDelegate {
// Overridden from LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
- gfx::ImageSkiaRep contents = canvas->ExtractImageRep();
- paint_size_ = gfx::Size(contents.pixel_width(), contents.pixel_height());
+ SkISize size = canvas->sk_canvas()->getBaseLayerSize();
+ paint_size_ = gfx::Size(size.width(), size.height());
canvas->FillRect(gfx::Rect(paint_size_), colors_[color_index_]);
color_index_ = (color_index_ + 1) % static_cast<int>(colors_.size());
const SkMatrix& matrix = canvas->sk_canvas()->getTotalMatrix();
@@ -300,11 +352,6 @@ class TestCompositorObserver : public CompositorObserver {
virtual void OnCompositingLockStateChanged(Compositor* compositor) OVERRIDE {
}
- virtual void OnUpdateVSyncParameters(Compositor* compositor,
- base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE {
- }
-
bool committed_;
bool started_;
bool ended_;
@@ -351,20 +398,22 @@ class LayerWithDelegateTest : public testing::Test {
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
- bool allow_test_contexts = true;
- InitializeContextFactoryForTests(allow_test_contexts);
- Compositor::Initialize();
- compositor_.reset(new Compositor(gfx::kNullAcceleratedWidget));
- compositor_->SetScaleAndSize(1.0f, gfx::Size(1000, 1000));
+ bool enable_pixel_output = false;
+ ui::ContextFactory* context_factory =
+ InitializeContextFactoryForTests(enable_pixel_output);
+
+ const gfx::Rect host_bounds(1000, 1000);
+ compositor_host_.reset(TestCompositorHost::Create(host_bounds,
+ context_factory));
+ compositor_host_->Show();
}
virtual void TearDown() OVERRIDE {
- compositor_.reset();
+ compositor_host_.reset();
TerminateContextFactoryForTests();
- Compositor::Terminate();
}
- Compositor* compositor() { return compositor_.get(); }
+ Compositor* compositor() { return compositor_host_->GetCompositor(); }
virtual Layer* CreateLayer(LayerType type) {
return new Layer(type);
@@ -408,7 +457,7 @@ class LayerWithDelegateTest : public testing::Test {
}
private:
- scoped_ptr<Compositor> compositor_;
+ scoped_ptr<TestCompositorHost> compositor_host_;
DISALLOW_COPY_AND_ASSIGN(LayerWithDelegateTest);
};
@@ -593,16 +642,29 @@ class LayerWithNullDelegateTest : public LayerWithDelegateTest {
DISALLOW_COPY_AND_ASSIGN(LayerWithNullDelegateTest);
};
-class FakeTexture : public Texture {
- public:
- FakeTexture(bool flipped, const gfx::Size& size, float device_scale_factor)
- : Texture(flipped, size, device_scale_factor) {}
-
- virtual unsigned int PrepareTexture() OVERRIDE { return 0; }
+TEST_F(LayerWithNullDelegateTest, EscapedDebugNames) {
+ scoped_ptr<Layer> layer(CreateLayer(LAYER_NOT_DRAWN));
+ std::string name = "\"\'\\/\b\f\n\r\t\n";
+ layer->set_name(name);
+ scoped_refptr<base::debug::ConvertableToTraceFormat> debug_info =
+ layer->TakeDebugInfo();
+ EXPECT_TRUE(!!debug_info);
+ std::string json;
+ debug_info->AppendAsTraceFormat(&json);
+ base::JSONReader json_reader;
+ scoped_ptr<base::Value> debug_info_value(json_reader.ReadToValue(json));
+ EXPECT_TRUE(!!debug_info_value);
+ EXPECT_TRUE(debug_info_value->IsType(base::Value::TYPE_DICTIONARY));
+ base::DictionaryValue* dictionary = 0;
+ EXPECT_TRUE(debug_info_value->GetAsDictionary(&dictionary));
+ std::string roundtrip;
+ EXPECT_TRUE(dictionary->GetString("layer_name", &roundtrip));
+ EXPECT_EQ(name, roundtrip);
+}
- protected:
- virtual ~FakeTexture() {}
-};
+void ReturnMailbox(bool* run, uint32 sync_point, bool is_lost) {
+ *run = true;
+}
TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED,
@@ -611,8 +673,7 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
l1->SetForceRenderSurface(true);
l1->SetVisible(false);
- EXPECT_EQ(gfx::PointF().ToString(),
- l1->cc_layer()->anchor_point().ToString());
+ EXPECT_EQ(gfx::Point3F(), l1->cc_layer()->transform_origin());
EXPECT_TRUE(l1->cc_layer()->DrawsContent());
EXPECT_TRUE(l1->cc_layer()->contents_opaque());
EXPECT_TRUE(l1->cc_layer()->force_render_surface());
@@ -620,18 +681,38 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
cc::Layer* before_layer = l1->cc_layer();
- scoped_refptr<Texture> texture =
- new FakeTexture(false, gfx::Size(10, 10), 1.f);
- l1->SetExternalTexture(texture.get());
+ bool callback1_run = false;
+ cc::TextureMailbox mailbox(gpu::Mailbox::Generate(), 0, 0);
+ l1->SetTextureMailbox(mailbox,
+ cc::SingleReleaseCallback::Create(
+ base::Bind(ReturnMailbox, &callback1_run)),
+ gfx::Size(1, 1));
EXPECT_NE(before_layer, l1->cc_layer());
- EXPECT_EQ(gfx::PointF().ToString(),
- l1->cc_layer()->anchor_point().ToString());
+ EXPECT_EQ(gfx::Point3F(), l1->cc_layer()->transform_origin());
+ EXPECT_TRUE(l1->cc_layer()->DrawsContent());
+ EXPECT_TRUE(l1->cc_layer()->contents_opaque());
+ EXPECT_TRUE(l1->cc_layer()->force_render_surface());
+ EXPECT_TRUE(l1->cc_layer()->hide_layer_and_subtree());
+ EXPECT_FALSE(callback1_run);
+
+ bool callback2_run = false;
+ mailbox = cc::TextureMailbox(gpu::Mailbox::Generate(), 0, 0);
+ l1->SetTextureMailbox(mailbox,
+ cc::SingleReleaseCallback::Create(
+ base::Bind(ReturnMailbox, &callback2_run)),
+ gfx::Size(1, 1));
+ EXPECT_TRUE(callback1_run);
+ EXPECT_FALSE(callback2_run);
+
+ l1->SetShowPaintedContent();
+ EXPECT_EQ(gfx::Point3F(), l1->cc_layer()->transform_origin());
EXPECT_TRUE(l1->cc_layer()->DrawsContent());
EXPECT_TRUE(l1->cc_layer()->contents_opaque());
EXPECT_TRUE(l1->cc_layer()->force_render_surface());
EXPECT_TRUE(l1->cc_layer()->hide_layer_and_subtree());
+ EXPECT_TRUE(callback2_run);
}
// Various visibile/drawn assertions.
@@ -783,7 +864,7 @@ TEST_F(LayerWithRealCompositorTest, DrawPixels) {
DrawTree(layer.get());
SkBitmap bitmap;
- ASSERT_TRUE(GetCompositor()->ReadPixels(&bitmap, gfx::Rect(viewport_size)));
+ ASSERT_TRUE(ReadPixels(&bitmap, gfx::Rect(viewport_size)));
ASSERT_FALSE(bitmap.empty());
SkAutoLockPixels lock(bitmap);
@@ -1111,10 +1192,10 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
- gfx::Size size_in_pixel = root->cc_layer()->bounds();
- EXPECT_EQ("200x220", size_in_pixel.ToString());
- size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("140x180", size_in_pixel.ToString());
+ gfx::Size cc_bounds_size = root->cc_layer()->bounds();
+ EXPECT_EQ("200x220", cc_bounds_size.ToString());
+ cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
// No scale change, so no scale notification.
EXPECT_EQ(0.0f, root_delegate.device_scale_factor());
EXPECT_EQ(0.0f, l1_delegate.device_scale_factor());
@@ -1126,11 +1207,11 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500));
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
- // Pixel size must have been scaled up.
- size_in_pixel = root->cc_layer()->bounds();
- EXPECT_EQ("400x440", size_in_pixel.ToString());
- size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("280x360", size_in_pixel.ToString());
+ // CC layer should still match the UI layer bounds.
+ cc_bounds_size = root->cc_layer()->bounds();
+ EXPECT_EQ("200x220", cc_bounds_size.ToString());
+ cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
// New scale factor must have been notified.
EXPECT_EQ(2.0f, root_delegate.device_scale_factor());
EXPECT_EQ(2.0f, l1_delegate.device_scale_factor());
@@ -1146,11 +1227,11 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500));
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
- // Pixel size must have been scaled down.
- size_in_pixel = root->cc_layer()->bounds();
- EXPECT_EQ("200x220", size_in_pixel.ToString());
- size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("140x180", size_in_pixel.ToString());
+ // CC layer should still match the UI layer bounds.
+ cc_bounds_size = root->cc_layer()->bounds();
+ EXPECT_EQ("200x220", cc_bounds_size.ToString());
+ cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
// New scale factor must have been notified.
EXPECT_EQ(1.0f, root_delegate.device_scale_factor());
EXPECT_EQ(1.0f, l1_delegate.device_scale_factor());
@@ -1192,8 +1273,8 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
root->Add(l1.get());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
- gfx::Size size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("140x180", size_in_pixel.ToString());
+ gfx::Size cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
EXPECT_EQ(0.0f, l1_delegate.device_scale_factor());
WaitForDraw();
@@ -1207,42 +1288,19 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500));
// Sanity check on root and l1.
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
- size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("140x180", size_in_pixel.ToString());
-
+ cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
root->Add(l1.get());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
- size_in_pixel = l1->cc_layer()->bounds();
- EXPECT_EQ("280x360", size_in_pixel.ToString());
+ cc_bounds_size = l1->cc_layer()->bounds();
+ EXPECT_EQ("140x180", cc_bounds_size.ToString());
EXPECT_EQ(2.0f, l1_delegate.device_scale_factor());
WaitForDraw();
EXPECT_EQ("280x360", l1_delegate.paint_size().ToString());
EXPECT_EQ("2.0 2.0", l1_delegate.ToScaleString());
}
-// Tests layer::set_scale_content(false).
-TEST_F(LayerWithRealCompositorTest, NoScaleCanvas) {
- scoped_ptr<Layer> root(CreateColorLayer(SK_ColorWHITE,
- gfx::Rect(10, 20, 200, 220)));
- scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorWHITE,
- gfx::Rect(10, 20, 140, 180)));
- l1->set_scale_content(false);
- root->Add(l1.get());
- TestLayerDelegate l1_delegate;
- l1_delegate.AddColor(SK_ColorWHITE);
- l1->set_delegate(&l1_delegate);
-
- GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500));
- GetCompositor()->SetRootLayer(root.get());
- // Scale factor change is notified regardless of scale_content flag.
- EXPECT_EQ(2.0f, l1_delegate.device_scale_factor());
-
- WaitForDraw();
- EXPECT_EQ("280x360", l1_delegate.paint_size().ToString());
- EXPECT_EQ("1.0 1.0", l1_delegate.ToScaleString());
-}
-
// Verifies that when changing bounds on a layer that is invisible, and then
// made visible, the right thing happens:
// - if just a move, then no painting should happen.
@@ -1286,10 +1344,8 @@ TEST_F(LayerWithDelegateTest, SetBoundsWhenInvisible) {
static scoped_ptr<cc::DelegatedFrameData> MakeFrameData(gfx::Size size) {
scoped_ptr<cc::DelegatedFrameData> frame_data(new cc::DelegatedFrameData);
scoped_ptr<cc::RenderPass> render_pass(cc::RenderPass::Create());
- render_pass->SetNew(cc::RenderPass::Id(1, 1),
- gfx::Rect(size),
- gfx::RectF(),
- gfx::Transform());
+ render_pass->SetNew(
+ cc::RenderPass::Id(1, 1), gfx::Rect(size), gfx::Rect(), gfx::Transform());
frame_data->render_pass_list.push_back(render_pass.Pass());
return frame_data.Pass();
}
@@ -1337,14 +1393,14 @@ TEST_F(LayerWithDelegateTest, DelegatedLayer) {
// Hi-DPI content on hi-DPI layer.
compositor()->SetScaleAndSize(2.f, gfx::Size(1000, 1000));
EXPECT_EQ(child->cc_layer()->bounds().ToString(),
- gfx::Size(20, 20).ToString());
+ gfx::Size(10, 10).ToString());
// Low-DPI content on hi-DPI layer.
frame_provider = new cc::DelegatedFrameProvider(
resource_collection.get(), MakeFrameData(gfx::Size(10, 10)));
child->SetShowDelegatedContent(frame_provider, gfx::Size(10, 10));
EXPECT_EQ(child->cc_layer()->bounds().ToString(),
- gfx::Size(20, 20).ToString());
+ gfx::Size(10, 10).ToString());
}
TEST_F(LayerWithDelegateTest, ExternalContent) {
@@ -1448,4 +1504,54 @@ TEST_F(LayerWithRealCompositorTest, SwitchCCLayerAnimations) {
EXPECT_FLOAT_EQ(l1->opacity(), 0.5f);
}
+// Tests that the animators in the layer tree is added to the
+// animator-collection when the root-layer is set to the compositor.
+TEST_F(LayerWithDelegateTest, RootLayerAnimatorsInCompositor) {
+ scoped_ptr<Layer> root(CreateLayer(LAYER_SOLID_COLOR));
+ scoped_ptr<Layer> child(CreateColorLayer(SK_ColorRED, gfx::Rect(10, 10)));
+ child->SetAnimator(LayerAnimator::CreateImplicitAnimator());
+ child->SetOpacity(0.5f);
+ root->Add(child.get());
+
+ EXPECT_FALSE(compositor()->layer_animator_collection()->HasActiveAnimators());
+ compositor()->SetRootLayer(root.get());
+ EXPECT_TRUE(compositor()->layer_animator_collection()->HasActiveAnimators());
+}
+
+// Tests that adding/removing a layer adds/removes the animator from its entire
+// subtree from the compositor's animator-collection.
+TEST_F(LayerWithDelegateTest, AddRemoveLayerUpdatesAnimatorsFromSubtree) {
+ scoped_ptr<Layer> root(CreateLayer(LAYER_TEXTURED));
+ scoped_ptr<Layer> child(CreateLayer(LAYER_TEXTURED));
+ scoped_ptr<Layer> grandchild(CreateColorLayer(SK_ColorRED,
+ gfx::Rect(10, 10)));
+ root->Add(child.get());
+ child->Add(grandchild.get());
+ compositor()->SetRootLayer(root.get());
+
+ grandchild->SetAnimator(LayerAnimator::CreateImplicitAnimator());
+ grandchild->SetOpacity(0.5f);
+ EXPECT_TRUE(compositor()->layer_animator_collection()->HasActiveAnimators());
+
+ root->Remove(child.get());
+ EXPECT_FALSE(compositor()->layer_animator_collection()->HasActiveAnimators());
+
+ root->Add(child.get());
+ EXPECT_TRUE(compositor()->layer_animator_collection()->HasActiveAnimators());
+}
+
+TEST_F(LayerWithDelegateTest, DestroyingLayerRemovesTheAnimatorFromCollection) {
+ scoped_ptr<Layer> root(CreateLayer(LAYER_TEXTURED));
+ scoped_ptr<Layer> child(CreateLayer(LAYER_TEXTURED));
+ root->Add(child.get());
+ compositor()->SetRootLayer(root.get());
+
+ child->SetAnimator(LayerAnimator::CreateImplicitAnimator());
+ child->SetOpacity(0.5f);
+ EXPECT_TRUE(compositor()->layer_animator_collection()->HasActiveAnimators());
+
+ child.reset();
+ EXPECT_FALSE(compositor()->layer_animator_collection()->HasActiveAnimators());
+}
+
} // namespace ui
diff --git a/chromium/ui/compositor/scoped_layer_animation_settings.cc b/chromium/ui/compositor/scoped_layer_animation_settings.cc
index 84456ee5bc1..487f96afe69 100644
--- a/chromium/ui/compositor/scoped_layer_animation_settings.cc
+++ b/chromium/ui/compositor/scoped_layer_animation_settings.cc
@@ -61,10 +61,10 @@ class InvertingObserver : public ImplicitAnimationObserver {
"Inverse supported only for single element sequences.";
LayerAnimationElement* element = sequence->FirstElement();
- LayerAnimationElement::AnimatableProperties transform_property;
- transform_property.insert(LayerAnimationElement::TRANSFORM);
- DCHECK(transform_property == element->properties())
- << "Only transform animations are currently invertible.";
+ DCHECK_EQ(static_cast<LayerAnimationElement::AnimatableProperties>(
+ LayerAnimationElement::TRANSFORM),
+ element->properties())
+ << "Only transform animations are currently invertible.";
scoped_ptr<LayerAnimationElement> to_return(
LayerAnimationElement::CreateInverseTransformElement(base, element));
@@ -77,9 +77,9 @@ class InvertingObserver : public ImplicitAnimationObserver {
};
-// ScoperLayerAnimationSettings ------------------------------------------------
+// ScopedLayerAnimationSettings ------------------------------------------------
ScopedLayerAnimationSettings::ScopedLayerAnimationSettings(
- LayerAnimator* animator)
+ scoped_refptr<LayerAnimator> animator)
: animator_(animator),
old_is_transition_duration_locked_(
animator->is_transition_duration_locked_),
diff --git a/chromium/ui/compositor/scoped_layer_animation_settings.h b/chromium/ui/compositor/scoped_layer_animation_settings.h
index e8a1b468ba6..e201024c5d2 100644
--- a/chromium/ui/compositor/scoped_layer_animation_settings.h
+++ b/chromium/ui/compositor/scoped_layer_animation_settings.h
@@ -26,7 +26,7 @@ class InvertingObserver;
// (200ms).
class COMPOSITOR_EXPORT ScopedLayerAnimationSettings {
public:
- explicit ScopedLayerAnimationSettings(LayerAnimator* animator);
+ explicit ScopedLayerAnimationSettings(scoped_refptr<LayerAnimator> animator);
virtual ~ScopedLayerAnimationSettings();
void AddObserver(ImplicitAnimationObserver* observer);
@@ -55,7 +55,7 @@ class COMPOSITOR_EXPORT ScopedLayerAnimationSettings {
void AddInverselyAnimatedLayer(Layer* inverse_layer);
private:
- LayerAnimator* animator_;
+ scoped_refptr<LayerAnimator> animator_;
bool old_is_transition_duration_locked_;
base::TimeDelta old_transition_duration_;
gfx::Tween::Type old_tween_type_;
diff --git a/chromium/ui/compositor/test/test_compositor_host_ozone.cc b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
index 78431bee417..1c7a8da9aca 100644
--- a/chromium/ui/compositor/test/test_compositor_host_ozone.cc
+++ b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
@@ -18,7 +18,8 @@ namespace ui {
class TestCompositorHostOzone : public TestCompositorHost {
public:
- TestCompositorHostOzone(const gfx::Rect& bounds);
+ TestCompositorHostOzone(const gfx::Rect& bounds,
+ ui::ContextFactory* context_factory);
virtual ~TestCompositorHostOzone();
private:
@@ -30,13 +31,18 @@ class TestCompositorHostOzone : public TestCompositorHost {
gfx::Rect bounds_;
+ ui::ContextFactory* context_factory_;
+
scoped_ptr<ui::Compositor> compositor_;
DISALLOW_COPY_AND_ASSIGN(TestCompositorHostOzone);
};
-TestCompositorHostOzone::TestCompositorHostOzone(const gfx::Rect& bounds)
- : bounds_(bounds) {}
+TestCompositorHostOzone::TestCompositorHostOzone(
+ const gfx::Rect& bounds,
+ ui::ContextFactory* context_factory)
+ : bounds_(bounds),
+ context_factory_(context_factory) {}
TestCompositorHostOzone::~TestCompositorHostOzone() {}
@@ -48,7 +54,7 @@ void TestCompositorHostOzone::Show() {
// with a non-0 widget.
// TODO(rjkroege): Use a "real" ozone widget when it is
// available: http://crbug.com/255128
- compositor_.reset(new ui::Compositor(1));
+ compositor_.reset(new ui::Compositor(1, context_factory_));
compositor_->SetScaleAndSize(1.0f, bounds_.size());
}
@@ -62,8 +68,10 @@ void TestCompositorHostOzone::Draw() {
}
// static
-TestCompositorHost* TestCompositorHost::Create(const gfx::Rect& bounds) {
- return new TestCompositorHostOzone(bounds);
+TestCompositorHost* TestCompositorHost::Create(
+ const gfx::Rect& bounds,
+ ui::ContextFactory* context_factory) {
+ return new TestCompositorHostOzone(bounds, context_factory);
}
} // namespace ui
diff --git a/chromium/ui/compositor/transform_animation_curve_adapter.cc b/chromium/ui/compositor/transform_animation_curve_adapter.cc
index 49feb6af746..e875ca0f297 100644
--- a/chromium/ui/compositor/transform_animation_curve_adapter.cc
+++ b/chromium/ui/compositor/transform_animation_curve_adapter.cc
@@ -61,6 +61,20 @@ bool TransformAnimationCurveAdapter::AnimatedBoundsForBox(
return false;
}
+bool TransformAnimationCurveAdapter::AffectsScale() const {
+ return !initial_value_.IsIdentityOrTranslation() ||
+ !target_value_.IsIdentityOrTranslation();
+}
+
+bool TransformAnimationCurveAdapter::IsTranslation() const {
+ return initial_value_.IsIdentityOrTranslation() &&
+ target_value_.IsIdentityOrTranslation();
+}
+
+bool TransformAnimationCurveAdapter::MaximumScale(float* max_scale) const {
+ return false;
+}
+
InverseTransformCurveAdapter::InverseTransformCurveAdapter(
TransformAnimationCurveAdapter base_curve,
gfx::Transform initial_value,
@@ -110,4 +124,18 @@ bool InverseTransformCurveAdapter::AnimatedBoundsForBox(
return false;
}
+bool InverseTransformCurveAdapter::AffectsScale() const {
+ return !initial_value_.IsIdentityOrTranslation() ||
+ base_curve_.AffectsScale();
+}
+
+bool InverseTransformCurveAdapter::IsTranslation() const {
+ return initial_value_.IsIdentityOrTranslation() &&
+ base_curve_.IsTranslation();
+}
+
+bool InverseTransformCurveAdapter::MaximumScale(float* max_scale) const {
+ return false;
+}
+
} // namespace ui
diff --git a/chromium/ui/compositor/transform_animation_curve_adapter.h b/chromium/ui/compositor/transform_animation_curve_adapter.h
index 36861e46008..c410ac09e2b 100644
--- a/chromium/ui/compositor/transform_animation_curve_adapter.h
+++ b/chromium/ui/compositor/transform_animation_curve_adapter.h
@@ -30,6 +30,9 @@ class COMPOSITOR_EXPORT TransformAnimationCurveAdapter
virtual gfx::Transform GetValue(double t) const OVERRIDE;
virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const OVERRIDE;
+ virtual bool AffectsScale() const OVERRIDE;
+ virtual bool IsTranslation() const OVERRIDE;
+ virtual bool MaximumScale(float* max_scale) const OVERRIDE;
private:
gfx::Tween::Type tween_type_;
@@ -56,6 +59,9 @@ class COMPOSITOR_EXPORT InverseTransformCurveAdapter
virtual gfx::Transform GetValue(double t) const OVERRIDE;
virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const OVERRIDE;
+ virtual bool AffectsScale() const OVERRIDE;
+ virtual bool IsTranslation() const OVERRIDE;
+ virtual bool MaximumScale(float* max_scale) const OVERRIDE;
private:
TransformAnimationCurveAdapter base_curve_;
diff --git a/chromium/ui/display/DEPS b/chromium/ui/display/DEPS
new file mode 100644
index 00000000000..51399a619dc
--- /dev/null
+++ b/chromium/ui/display/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+third_party/cros_system_api",
+ "+ui/gfx/geometry",
+]
diff --git a/chromium/ui/display/OWNERS b/chromium/ui/display/OWNERS
new file mode 100644
index 00000000000..69f028b378a
--- /dev/null
+++ b/chromium/ui/display/OWNERS
@@ -0,0 +1,3 @@
+derat@chromium.org
+marcheu@chromium.org
+oshima@chromium.org
diff --git a/chromium/ui/display/display.gyp b/chromium/ui/display/display.gyp
new file mode 100644
index 00000000000..4b2ca521e6c
--- /dev/null
+++ b/chromium/ui/display/display.gyp
@@ -0,0 +1,162 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'display_types',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'DISPLAY_TYPES_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'types/chromeos/display_mode.cc',
+ 'types/chromeos/display_mode.h',
+ 'types/chromeos/display_snapshot.cc',
+ 'types/chromeos/display_snapshot.h',
+ 'types/chromeos/native_display_delegate.h',
+ 'types/chromeos/native_display_observer.h',
+ 'types/chromeos/touchscreen_device.cc',
+ 'types/chromeos/touchscreen_device.h',
+ 'types/chromeos/touchscreen_device_manager.h',
+ 'types/display_constants.h',
+ 'types/display_types_export.h',
+ ],
+ },
+ {
+ 'target_name': 'display',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../ui/gfx/gfx.gyp:gfx',
+ '../../ui/gfx/gfx.gyp:gfx_geometry',
+ 'display_util',
+ ],
+ 'defines': [
+ 'DISPLAY_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'chromeos/display_configurator.cc',
+ 'chromeos/display_configurator.h',
+ 'chromeos/touchscreen_delegate_impl.cc',
+ 'chromeos/touchscreen_delegate_impl.h',
+ 'chromeos/ozone/display_configurator_ozone.cc',
+ 'chromeos/x11/display_configurator_x11.cc',
+ 'chromeos/x11/display_mode_x11.cc',
+ 'chromeos/x11/display_mode_x11.h',
+ 'chromeos/x11/display_snapshot_x11.cc',
+ 'chromeos/x11/display_snapshot_x11.h',
+ 'chromeos/x11/display_util_x11.cc',
+ 'chromeos/x11/display_util_x11.h',
+ 'chromeos/x11/native_display_delegate_x11.cc',
+ 'chromeos/x11/native_display_delegate_x11.h',
+ 'chromeos/x11/native_display_event_dispatcher_x11.cc',
+ 'chromeos/x11/native_display_event_dispatcher_x11.h',
+ 'chromeos/x11/touchscreen_device_manager_x11.cc',
+ 'chromeos/x11/touchscreen_device_manager_x11.h',
+ 'display_export.h',
+ 'display_switches.cc',
+ 'display_switches.h',
+ ],
+ 'conditions': [
+ ['use_x11 == 1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:xext',
+ '../../build/linux/system.gyp:xi',
+ '../../build/linux/system.gyp:xrandr',
+ ],
+ }],
+ ['chromeos == 1', {
+ 'dependencies': [
+ 'display_types',
+ ],
+ }],
+ ['use_ozone == 1', {
+ 'dependencies': [
+ '../../ui/ozone/ozone.gyp:ozone',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'display_util',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'DISPLAY_UTIL_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'util/display_util.cc',
+ 'util/display_util.h',
+ 'util/display_util_export.h',
+ 'util/edid_parser.cc',
+ 'util/edid_parser.h',
+ 'util/x11/edid_parser_x11.cc',
+ 'util/x11/edid_parser_x11.h',
+ ],
+ 'conditions': [
+ ['use_x11 == 1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:xrandr',
+ '../../ui/gfx/x/gfx_x11.gyp:gfx_x11',
+ ],
+ }],
+ ['chromeos == 1', {
+ 'dependencies': [
+ 'display_types',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'display_test_util',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../ui/gfx/gfx.gyp:gfx',
+ '../../ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'DISPLAY_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'chromeos/test/test_display_snapshot.cc',
+ 'chromeos/test/test_display_snapshot.h',
+ ],
+ 'conditions': [
+ ['chromeos == 1', {
+ 'dependencies': [
+ 'display_types',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'display_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:run_all_unittests',
+ '../../testing/gtest.gyp:gtest',
+ 'display_util',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'util/edid_parser_unittest.cc',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/display/display_export.h b/chromium/ui/display/display_export.h
new file mode 100644
index 00000000000..5dc19e052a6
--- /dev/null
+++ b/chromium/ui/display/display_export.h
@@ -0,0 +1,37 @@
+// 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_DISPLAY_DISPLAY_EXPORT_H_
+#define UI_DISPLAY_DISPLAY_EXPORT_H_
+
+// Defines DISPLAY_EXPORT so that functionality implemented by the UI module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(DISPLAY_IMPLEMENTATION)
+#define DISPLAY_EXPORT __declspec(dllexport)
+#else
+#define DISPLAY_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(DISPLAY_IMPLEMENTATION)
+#define DISPLAY_EXPORT __attribute__((visibility("default")))
+#else
+#define DISPLAY_EXPORT
+#endif
+
+#endif
+
+#else // !defined(COMPONENT_BUILD)
+
+#define DISPLAY_EXPORT
+
+#endif
+
+#endif // UI_DISPLAY_DISPLAY_EXPORT_H_
diff --git a/chromium/ui/display/display_switches.cc b/chromium/ui/display/display_switches.cc
new file mode 100644
index 00000000000..7d32b5b6b99
--- /dev/null
+++ b/chromium/ui/display/display_switches.cc
@@ -0,0 +1,16 @@
+// 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/display/display_switches.h"
+
+namespace ui {
+namespace switches {
+
+#if defined(OS_CHROMEOS)
+const char kDisableDisplayColorCalibration[] =
+ "disable-display-color-calibration";
+#endif
+
+} // namespace switches
+} // namespace ui
diff --git a/chromium/ui/display/display_switches.h b/chromium/ui/display/display_switches.h
new file mode 100644
index 00000000000..362853b7d0d
--- /dev/null
+++ b/chromium/ui/display/display_switches.h
@@ -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.
+
+#ifndef UI_DISPLAY_DISPLAY_SWITCHES_H_
+#define UI_DISPLAY_DISPLAY_SWITCHES_H_
+
+#include "base/compiler_specific.h"
+#include "ui/display/display_export.h"
+
+namespace ui {
+namespace switches {
+
+#if defined(OS_CHROMEOS)
+DISPLAY_EXPORT extern const char kDisableDisplayColorCalibration[];
+#endif
+
+} // namespace switches
+} // namespace ui
+
+#endif // UI_BASE_UI_BASE_SWITCHES_H_
diff --git a/chromium/ui/display/display_unittests.gypi b/chromium/ui/display/display_unittests.gypi
new file mode 100644
index 00000000000..e32e7342367
--- /dev/null
+++ b/chromium/ui/display/display_unittests.gypi
@@ -0,0 +1,34 @@
+# 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.
+
+# TODO(dnicoara) Move this into its own executable. (Currently it is built as
+# part of ui_unittests.)
+{
+ 'dependencies': [
+ '../base/base.gyp:test_support_base',
+ '../testing/gtest.gyp:gtest',
+ '../ui/display/display.gyp:display_util',
+ '../ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'sources': [
+ 'chromeos/display_configurator_unittest.cc',
+ 'chromeos/touchscreen_delegate_impl_unittest.cc',
+ 'chromeos/x11/display_util_x11_unittest.cc',
+ 'chromeos/x11/native_display_event_dispatcher_x11_unittest.cc',
+ 'util/display_util_unittest.cc',
+ 'util/edid_parser_unittest.cc',
+ ],
+ 'conditions': [
+ # TODO(dnicoara) When we add non-chromeos display code this dependency can
+ # be added to the above list. For now, keep it here since Win & Android do
+ # not like empty libraries.
+ ['chromeos == 1', {
+ 'dependencies': [
+ '../ui/display/display.gyp:display',
+ '../ui/display/display.gyp:display_test_util',
+ '../ui/display/display.gyp:display_types',
+ ],
+ }],
+ ],
+}
diff --git a/chromium/ui/display/types/DEPS b/chromium/ui/display/types/DEPS
new file mode 100644
index 00000000000..f2fc77d6fcd
--- /dev/null
+++ b/chromium/ui/display/types/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "-ui",
+ "+ui/display/types",
+ "+ui/gfx/geometry",
+]
diff --git a/chromium/ui/display/types/chromeos/display_mode.cc b/chromium/ui/display/types/chromeos/display_mode.cc
new file mode 100644
index 00000000000..b0d5e5603f9
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/display_mode.cc
@@ -0,0 +1,28 @@
+// 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/display/types/chromeos/display_mode.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace ui {
+
+DisplayMode::DisplayMode(const gfx::Size& size,
+ bool interlaced,
+ float refresh_rate)
+ : size_(size),
+ is_interlaced_(interlaced),
+ refresh_rate_(refresh_rate) {}
+
+DisplayMode::~DisplayMode() {}
+
+std::string DisplayMode::ToString() const {
+ return base::StringPrintf("[%dx%d %srate=%f]",
+ size_.width(),
+ size_.height(),
+ is_interlaced_ ? "interlaced " : "",
+ refresh_rate_);
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/types/chromeos/display_mode.h b/chromium/ui/display/types/chromeos/display_mode.h
new file mode 100644
index 00000000000..092a43a0e1f
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/display_mode.h
@@ -0,0 +1,39 @@
+// 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_DISPLAY_TYPES_CHROMEOS_DISPLAY_MODE_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_DISPLAY_MODE_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "ui/display/types/display_types_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// This class represents the basic information for a native mode. Platforms will
+// extend this class to add platform specific information about the mode.
+class DISPLAY_TYPES_EXPORT DisplayMode {
+ public:
+ DisplayMode(const gfx::Size& size, bool interlaced, float refresh_rate);
+ virtual ~DisplayMode();
+
+ const gfx::Size& size() const { return size_; }
+ bool is_interlaced() const { return is_interlaced_; }
+ float refresh_rate() const { return refresh_rate_; }
+
+ virtual std::string ToString() const;
+
+ private:
+ gfx::Size size_;
+ bool is_interlaced_;
+ float refresh_rate_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayMode);
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_DISPLAY_MODE_H_
diff --git a/chromium/ui/display/types/chromeos/display_snapshot.cc b/chromium/ui/display/types/chromeos/display_snapshot.cc
new file mode 100644
index 00000000000..e90fdda137b
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/display_snapshot.cc
@@ -0,0 +1,34 @@
+// 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/display/types/chromeos/display_snapshot.h"
+
+namespace ui {
+
+DisplaySnapshot::DisplaySnapshot(int64_t display_id,
+ bool has_proper_display_id,
+ const gfx::Point& origin,
+ const gfx::Size& physical_size,
+ DisplayConnectionType type,
+ bool is_aspect_preserving_scaling,
+ bool has_overscan,
+ std::string display_name,
+ const std::vector<const DisplayMode*>& modes,
+ const DisplayMode* current_mode,
+ const DisplayMode* native_mode)
+ : display_id_(display_id),
+ has_proper_display_id_(has_proper_display_id),
+ origin_(origin),
+ physical_size_(physical_size),
+ type_(type),
+ is_aspect_preserving_scaling_(is_aspect_preserving_scaling),
+ has_overscan_(has_overscan),
+ display_name_(display_name),
+ modes_(modes),
+ current_mode_(current_mode),
+ native_mode_(native_mode) {}
+
+DisplaySnapshot::~DisplaySnapshot() {}
+
+} // namespace ui
diff --git a/chromium/ui/display/types/chromeos/display_snapshot.h b/chromium/ui/display/types/chromeos/display_snapshot.h
new file mode 100644
index 00000000000..1dc057384bf
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/display_snapshot.h
@@ -0,0 +1,90 @@
+// 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_DISPLAY_TYPES_CHROMEOS_DISPLAY_SNAPSHOT_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_DISPLAY_SNAPSHOT_H_
+
+#include <vector>
+
+#include "ui/display/types/chromeos/display_mode.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// This class represents the state of a display at one point in time. Platforms
+// will extend this class in order to add platform specific configuration and
+// identifiers required to configure this display.
+class DISPLAY_TYPES_EXPORT DisplaySnapshot {
+ public:
+ DisplaySnapshot(int64_t display_id,
+ bool has_proper_display_id,
+ const gfx::Point& origin,
+ const gfx::Size& physical_size,
+ DisplayConnectionType type,
+ bool is_aspect_preserving_scaling,
+ bool has_overscan,
+ std::string display_name,
+ const std::vector<const DisplayMode*>& modes,
+ const DisplayMode* current_mode,
+ const DisplayMode* native_mode);
+ virtual ~DisplaySnapshot();
+
+ const gfx::Point& origin() const { return origin_; }
+ const gfx::Size& physical_size() const { return physical_size_; }
+ ui::DisplayConnectionType type() const { return type_; }
+ bool is_aspect_preserving_scaling() const {
+ return is_aspect_preserving_scaling_;
+ }
+ bool has_overscan() const { return has_overscan_; }
+ std::string display_name() const { return display_name_; }
+
+ int64_t display_id() const { return display_id_; }
+ bool has_proper_display_id() const { return has_proper_display_id_; }
+
+ const DisplayMode* current_mode() const { return current_mode_; }
+ const DisplayMode* native_mode() const { return native_mode_; }
+
+ const std::vector<const DisplayMode*>& modes() const { return modes_; }
+
+ void set_current_mode(const DisplayMode* mode) { current_mode_ = mode; }
+ void set_origin(const gfx::Point& origin) { origin_ = origin; }
+ void add_mode(const DisplayMode* mode) { modes_.push_back(mode); }
+
+ // Returns a textual representation of this display state.
+ virtual std::string ToString() const = 0;
+
+ protected:
+ // Display id for this output.
+ int64_t display_id_;
+ bool has_proper_display_id_;
+
+ // Display's origin on the framebuffer.
+ gfx::Point origin_;
+
+ gfx::Size physical_size_;
+
+ DisplayConnectionType type_;
+
+ bool is_aspect_preserving_scaling_;
+
+ bool has_overscan_;
+
+ std::string display_name_;
+
+ std::vector<const DisplayMode*> modes_; // Not owned.
+
+ // Mode currently being used by the output.
+ const DisplayMode* current_mode_;
+
+ // "Best" mode supported by the output.
+ const DisplayMode* native_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplaySnapshot);
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_DISPLAY_SNAPSHOT_H_
diff --git a/chromium/ui/display/types/chromeos/native_display_delegate.h b/chromium/ui/display/types/chromeos/native_display_delegate.h
new file mode 100644
index 00000000000..8cbffdb1813
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/native_display_delegate.h
@@ -0,0 +1,95 @@
+// 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_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_DELEGATE_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_DELEGATE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "ui/display/types/display_constants.h"
+#include "ui/display/types/display_types_export.h"
+
+namespace gfx {
+class Point;
+class Size;
+}
+
+namespace ui {
+class DisplayMode;
+class DisplaySnapshot;
+
+class NativeDisplayObserver;
+
+// Interface for classes that perform display configuration actions on behalf
+// of DisplayConfigurator.
+class DISPLAY_TYPES_EXPORT NativeDisplayDelegate {
+ public:
+ virtual ~NativeDisplayDelegate() {}
+
+ virtual void Initialize() = 0;
+
+ // Grabs and refreshes any display server related resources. Must be balanced
+ // by a call to UngrabServer().
+ virtual void GrabServer() = 0;
+
+ // Released the display server and any resources allocated by GrabServer().
+ virtual void UngrabServer() = 0;
+
+ // Flushes all pending requests and waits for replies.
+ virtual void SyncWithServer() = 0;
+
+ // Sets the window's background color to |color_argb|.
+ virtual void SetBackgroundColor(uint32_t color_argb) = 0;
+
+ // Enables DPMS and forces it to the "on" state.
+ virtual void ForceDPMSOn() = 0;
+
+ // Returns information about the current outputs. This method may block for
+ // 60 milliseconds or more.
+ // NativeDisplayDelegate maintains ownership of the ui::DisplaySnapshot
+ // pointers.
+ virtual std::vector<ui::DisplaySnapshot*> GetDisplays() = 0;
+
+ // Adds |mode| to |output|. |mode| must be a valid display mode pointer.
+ virtual void AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) = 0;
+
+ // Configures the display represented by |output| to use |mode| and positions
+ // the display to |origin| in the framebuffer. |mode| can be NULL, which
+ // represents disabling the display. Returns true on success.
+ virtual bool Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin) = 0;
+
+ // Called to set the frame buffer (underlying XRR "screen") size.
+ virtual void CreateFrameBuffer(const gfx::Size& size) = 0;
+
+ // Gets HDCP state of output.
+ virtual bool GetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState* state) = 0;
+
+ // Sets HDCP state of output.
+ virtual bool SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state) = 0;
+
+ // Gets the available list of color calibrations.
+ virtual std::vector<ui::ColorCalibrationProfile>
+ GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) = 0;
+
+ // Sets the color calibration of |output| to |new_profile|.
+ virtual bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) = 0;
+
+ virtual void AddObserver(NativeDisplayObserver* observer) = 0;
+
+ virtual void RemoveObserver(NativeDisplayObserver* observer) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_DELEGATE_H_
diff --git a/chromium/ui/display/types/chromeos/native_display_observer.h b/chromium/ui/display/types/chromeos/native_display_observer.h
new file mode 100644
index 00000000000..1b3d0baaa1e
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/native_display_observer.h
@@ -0,0 +1,23 @@
+// 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_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_OBSERVER_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_OBSERVER_H_
+
+#include "ui/display/types/display_types_export.h"
+
+namespace ui {
+
+// Observer class used by NativeDisplayDelegate to announce when the display
+// configuration changes.
+class DISPLAY_TYPES_EXPORT NativeDisplayObserver {
+ public:
+ virtual ~NativeDisplayObserver() {}
+
+ virtual void OnConfigurationChanged() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_NATIVE_DISPLAY_OBSERVER_H_
diff --git a/chromium/ui/display/types/chromeos/touchscreen_device.cc b/chromium/ui/display/types/chromeos/touchscreen_device.cc
new file mode 100644
index 00000000000..714b8f9a35e
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/touchscreen_device.cc
@@ -0,0 +1,19 @@
+// 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/display/types/chromeos/touchscreen_device.h"
+
+namespace ui {
+
+// static
+const int TouchscreenDevice::kInvalidId = 0;
+
+TouchscreenDevice::TouchscreenDevice(int id,
+ const gfx::Size& size,
+ bool is_internal)
+ : id(id),
+ size(size),
+ is_internal(is_internal) {}
+
+} // namespace ui
diff --git a/chromium/ui/display/types/chromeos/touchscreen_device.h b/chromium/ui/display/types/chromeos/touchscreen_device.h
new file mode 100644
index 00000000000..3a471fa16d0
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/touchscreen_device.h
@@ -0,0 +1,31 @@
+// 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_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_H_
+
+#include "ui/display/types/display_types_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// Represents a Touchscreen device state.
+struct DISPLAY_TYPES_EXPORT TouchscreenDevice {
+ static const int kInvalidId;
+
+ TouchscreenDevice(int id, const gfx::Size& size, bool is_internal);
+
+ // ID of the touch screen. This ID must uniquely identify the touch screen.
+ int id;
+
+ // Size of the touch screen area.
+ gfx::Size size;
+
+ // True if this is an internal touchscreen.
+ bool is_internal;
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_H_
diff --git a/chromium/ui/display/types/chromeos/touchscreen_device_manager.h b/chromium/ui/display/types/chromeos/touchscreen_device_manager.h
new file mode 100644
index 00000000000..ef99c287940
--- /dev/null
+++ b/chromium/ui/display/types/chromeos/touchscreen_device_manager.h
@@ -0,0 +1,27 @@
+// 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_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_MANAGER_H_
+#define UI_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_MANAGER_H_
+
+#include <vector>
+
+#include "ui/display/types/chromeos/touchscreen_device.h"
+
+namespace ui {
+
+// Implementations are responsible for querying and returning a list of avalable
+// touchscreen devices.
+class DISPLAY_TYPES_EXPORT TouchscreenDeviceManager {
+ public:
+ virtual ~TouchscreenDeviceManager() {}
+
+ // Returns a list of available touchscreen devices. This call will query the
+ // underlying system for an updated list of devices.
+ virtual std::vector<TouchscreenDevice> GetDevices() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_CHROMEOS_TOUCHSCREEN_DEVICE_MANAGER_H_
diff --git a/chromium/ui/display/types/display_constants.h b/chromium/ui/display/types/display_constants.h
new file mode 100644
index 00000000000..cf4ee6030d1
--- /dev/null
+++ b/chromium/ui/display/types/display_constants.h
@@ -0,0 +1,52 @@
+// 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_DISPLAY_TYPES_DISPLAY_CONSTANTS_H_
+#define UI_DISPLAY_TYPES_DISPLAY_CONSTANTS_H_
+
+namespace ui {
+
+// Used to describe the state of a multi-display configuration.
+enum MultipleDisplayState {
+ MULTIPLE_DISPLAY_STATE_INVALID,
+ MULTIPLE_DISPLAY_STATE_HEADLESS,
+ MULTIPLE_DISPLAY_STATE_SINGLE,
+ MULTIPLE_DISPLAY_STATE_DUAL_MIRROR,
+ MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
+};
+
+// Video output types.
+enum DisplayConnectionType {
+ DISPLAY_CONNECTION_TYPE_NONE = 0,
+ DISPLAY_CONNECTION_TYPE_UNKNOWN = 1 << 0,
+ DISPLAY_CONNECTION_TYPE_INTERNAL = 1 << 1,
+ DISPLAY_CONNECTION_TYPE_VGA = 1 << 2,
+ DISPLAY_CONNECTION_TYPE_HDMI = 1 << 3,
+ DISPLAY_CONNECTION_TYPE_DVI = 1 << 4,
+ DISPLAY_CONNECTION_TYPE_DISPLAYPORT = 1 << 5,
+ DISPLAY_CONNECTION_TYPE_NETWORK = 1 << 6,
+};
+
+// Content protection methods applied on video output.
+enum ContentProtectionMethod {
+ CONTENT_PROTECTION_METHOD_NONE = 0,
+ CONTENT_PROTECTION_METHOD_HDCP = 1 << 0,
+};
+
+// HDCP protection state.
+enum HDCPState { HDCP_STATE_UNDESIRED, HDCP_STATE_DESIRED, HDCP_STATE_ENABLED };
+
+// Color calibration profiles. Don't change the order, and edit
+// tools/metrics/histograms/histograms.xml when a new item is added.
+enum ColorCalibrationProfile {
+ COLOR_PROFILE_STANDARD,
+ COLOR_PROFILE_DYNAMIC,
+ COLOR_PROFILE_MOVIE,
+ COLOR_PROFILE_READING,
+ NUM_COLOR_PROFILES,
+};
+
+} // namespace ui
+
+#endif // UI_DISPLAY_TYPES_DISPLAY_CONSTANTS_H_
diff --git a/chromium/ui/display/types/display_types_export.h b/chromium/ui/display/types/display_types_export.h
new file mode 100644
index 00000000000..b2ddbd1c627
--- /dev/null
+++ b/chromium/ui/display/types/display_types_export.h
@@ -0,0 +1,37 @@
+// 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_DISPLAY_DISPLAY_TYPES_EXPORT_H_
+#define UI_DISPLAY_DISPLAY_TYPES_EXPORT_H_
+
+// Defines DISPLAY_TYPES_EXPORT so that functionality implemented by the
+// DISPLAY_TYPES module can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(DISPLAY_TYPES_IMPLEMENTATION)
+#define DISPLAY_TYPES_EXPORT __declspec(dllexport)
+#else
+#define DISPLAY_TYPES_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(DISPLAY_TYPES_IMPLEMENTATION)
+#define DISPLAY_TYPES_EXPORT __attribute__((visibility("default")))
+#else
+#define DISPLAY_TYPES_EXPORT
+#endif
+
+#endif
+
+#else // !defined(COMPONENT_BUILD)
+
+#define DISPLAY_TYPES_EXPORT
+
+#endif
+
+#endif // UI_DISPLAY_DISPLAY_TYPES_EXPORT_H_
diff --git a/chromium/ui/display/util/display_util.cc b/chromium/ui/display/util/display_util.cc
new file mode 100644
index 00000000000..aa23ec69a7f
--- /dev/null
+++ b/chromium/ui/display/util/display_util.cc
@@ -0,0 +1,71 @@
+// 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/display/util/display_util.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+namespace {
+
+// A list of bogus sizes in mm that should be ignored.
+// See crbug.com/136533. The first element maintains the minimum
+// size required to be valid size.
+const int kInvalidDisplaySizeList[][2] = {
+ {40, 30},
+ {50, 40},
+ {160, 90},
+ {160, 100},
+};
+
+// The DPI threshold to detect high density screen.
+// Higher DPI than this will use device_scale_factor=2.
+const unsigned int kHighDensityDPIThresholdSmall = 170;
+
+// The HiDPI threshold for large (usually external) monitors. Lower threshold
+// makes sense for large monitors, because such monitors should be located
+// farther from the user's face usually. See http://crbug.com/348279
+const unsigned int kHighDensityDPIThresholdLarge = 150;
+
+// The width threshold in mm for "large" monitors.
+const int kLargeDisplayWidthThresholdMM = 500;
+
+// 1 inch in mm.
+const float kInchInMm = 25.4f;
+
+} // namespace
+
+bool IsDisplaySizeBlackListed(const gfx::Size& physical_size) {
+ // Ignore if the reported display is smaller than minimum size.
+ if (physical_size.width() <= kInvalidDisplaySizeList[0][0] ||
+ physical_size.height() <= kInvalidDisplaySizeList[0][1]) {
+ VLOG(1) << "Smaller than minimum display size";
+ return true;
+ }
+ for (size_t i = 1; i < arraysize(kInvalidDisplaySizeList); ++i) {
+ const gfx::Size size(kInvalidDisplaySizeList[i][0],
+ kInvalidDisplaySizeList[i][1]);
+ if (physical_size == size) {
+ VLOG(1) << "Black listed display size detected:" << size.ToString();
+ return true;
+ }
+ }
+ return false;
+}
+
+float GetScaleFactor(const gfx::Size& physical_size_in_mm,
+ const gfx::Size& screen_size_in_pixels) {
+ if (IsDisplaySizeBlackListed(physical_size_in_mm))
+ return 1.0f;
+
+ const unsigned int dpi = (kInchInMm * screen_size_in_pixels.width() /
+ physical_size_in_mm.width());
+ const unsigned int threshold =
+ (physical_size_in_mm.width() >= kLargeDisplayWidthThresholdMM) ?
+ kHighDensityDPIThresholdLarge : kHighDensityDPIThresholdSmall;
+ return (dpi > threshold) ? 2.0f : 1.0f;
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/util/display_util.h b/chromium/ui/display/util/display_util.h
new file mode 100644
index 00000000000..012269d1038
--- /dev/null
+++ b/chromium/ui/display/util/display_util.h
@@ -0,0 +1,26 @@
+// 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_DISPLAY_UTIL_DISPLAY_UTIL_H_
+#define UI_DISPLAY_UTIL_DISPLAY_UTIL_H_
+
+#include "ui/display/util/display_util_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// Returns true if a given size is in the list of bogus sizes in mm that should
+// be ignored.
+DISPLAY_UTIL_EXPORT bool IsDisplaySizeBlackListed(
+ const gfx::Size& physical_size);
+
+// Returns the desired device scale factor for the display with the given
+// physical_size and resoultion.
+DISPLAY_UTIL_EXPORT float GetScaleFactor(
+ const gfx::Size& physical_size_in_mm,
+ const gfx::Size& screen_size_in_pixels);
+
+} // namespace ui
+
+#endif // UI_DISPLAY_UTIL_DISPLAY_UTIL_H_
diff --git a/chromium/ui/display/util/display_util_export.h b/chromium/ui/display/util/display_util_export.h
new file mode 100644
index 00000000000..8eeb30d4e2b
--- /dev/null
+++ b/chromium/ui/display/util/display_util_export.h
@@ -0,0 +1,37 @@
+// 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_DISPLAY_UTIL_DISPLAY_UTIL_EXPORT_H_
+#define UI_DISPLAY_UTIL_DISPLAY_UTIL_EXPORT_H_
+
+// Defines DISPLAY_UTIL_EXPORT so that functionality implemented by the
+// display_util module can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(DISPLAY_UTIL_IMPLEMENTATION)
+#define DISPLAY_UTIL_EXPORT __declspec(dllexport)
+#else
+#define DISPLAY_UTIL_EXPORT __declspec(dllimport)
+#endif
+
+#else // !defined(WIN32)
+
+#if defined(DISPLAY_UTIL_IMPLEMENTATION)
+#define DISPLAY_UTIL_EXPORT __attribute__((visibility("default")))
+#else
+#define DISPLAY_UTIL_EXPORT
+#endif
+
+#endif
+
+#else // !defined(COMPONENT_BUILD)
+
+#define DISPLAY_UTIL_EXPORT
+
+#endif
+
+#endif // UI_DISPLAY_UTIL_DISPLAY_UTIL_EXPORT_H_
diff --git a/chromium/ui/display/util/display_util_unittest.cc b/chromium/ui/display/util/display_util_unittest.cc
new file mode 100644
index 00000000000..ddb4a1cd078
--- /dev/null
+++ b/chromium/ui/display/util/display_util_unittest.cc
@@ -0,0 +1,53 @@
+// 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/display/util/display_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+TEST(DisplayUtilTest, TestBlackListedDisplay) {
+ EXPECT_TRUE(IsDisplaySizeBlackListed(gfx::Size(10, 10)));
+ EXPECT_TRUE(IsDisplaySizeBlackListed(gfx::Size(40, 30)));
+ EXPECT_TRUE(IsDisplaySizeBlackListed(gfx::Size(50, 40)));
+ EXPECT_TRUE(IsDisplaySizeBlackListed(gfx::Size(160, 90)));
+ EXPECT_TRUE(IsDisplaySizeBlackListed(gfx::Size(160, 100)));
+
+ EXPECT_FALSE(IsDisplaySizeBlackListed(gfx::Size(50, 60)));
+ EXPECT_FALSE(IsDisplaySizeBlackListed(gfx::Size(100, 70)));
+ EXPECT_FALSE(IsDisplaySizeBlackListed(gfx::Size(272, 181)));
+}
+
+TEST(DisplayUtilTest, GetScaleFactor) {
+ // Normal chromebook spec. DPI ~= 130
+ EXPECT_EQ(1.0f, GetScaleFactor(
+ gfx::Size(256, 144), gfx::Size(1366, 768)));
+
+ // HiDPI like Pixel. DPI ~= 240
+ EXPECT_EQ(2.0f, GetScaleFactor(
+ gfx::Size(272, 181), gfx::Size(2560, 1700)));
+
+ // A large external display but normal pixel density. DPI ~= 100
+ EXPECT_EQ(1.0f, GetScaleFactor(
+ gfx::Size(641, 400), gfx::Size(2560, 1600)));
+
+ // A large external display with high pixel density. DPI ~= 157
+ EXPECT_EQ(2.0f, GetScaleFactor(
+ gfx::Size(621, 341), gfx::Size(3840, 2160)));
+
+ // 4K resolution but the display is physically even larger. DPI ~= 114
+ EXPECT_EQ(1.0f, GetScaleFactor(
+ gfx::Size(854, 481), gfx::Size(3840, 2160)));
+
+ // 21.5 inch, 1080p. DPI ~= 102
+ EXPECT_EQ(1.0f, GetScaleFactor(
+ gfx::Size(476, 267), gfx::Size(1920, 1080)));
+
+ // Corner case; slightly higher density but smaller screens. DPI ~= 165
+ EXPECT_EQ(1.0f, GetScaleFactor(
+ gfx::Size(293, 165), gfx::Size(1920, 1080)));
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/util/edid_parser.cc b/chromium/ui/display/util/edid_parser.cc
new file mode 100644
index 00000000000..b95eef4c626
--- /dev/null
+++ b/chromium/ui/display/util/edid_parser.cc
@@ -0,0 +1,197 @@
+// 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/display/util/edid_parser.h"
+
+#include <algorithm>
+
+#include "base/hash.h"
+#include "base/strings/string_util.h"
+#include "base/sys_byteorder.h"
+
+namespace ui {
+
+namespace {
+
+// Returns 64-bit persistent ID for the specified manufacturer's ID and
+// product_code_hash, and the index of the output it is connected to.
+// |output_index| is used to distinguish the displays of the same type. For
+// example, swapping two identical display between two outputs will not be
+// treated as swap. The 'serial number' field in EDID isn't used here because
+// it is not guaranteed to have unique number and it may have the same fixed
+// value (like 0).
+int64_t GetID(uint16_t manufacturer_id,
+ uint32_t product_code_hash,
+ uint8_t output_index) {
+ return ((static_cast<int64_t>(manufacturer_id) << 40) |
+ (static_cast<int64_t>(product_code_hash) << 8) | output_index);
+}
+
+} // namespace
+
+bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
+ uint8_t output_index,
+ int64_t* display_id_out) {
+ uint16_t manufacturer_id = 0;
+ std::string product_name;
+
+ // ParseOutputDeviceData fails if it doesn't have product_name.
+ ParseOutputDeviceData(edid, &manufacturer_id, &product_name);
+
+ // 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);
+ if (manufacturer_id != 0) {
+ // An ID based on display's index will be assigned later if this call
+ // fails.
+ *display_id_out = GetID(
+ manufacturer_id, product_code_hash, output_index);
+ return true;
+ }
+ return false;
+}
+
+bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
+ uint16_t* manufacturer_id,
+ std::string* human_readable_name) {
+ // 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 54-125: four descriptors (18-bytes each) which may contain
+ // the display name.
+ const unsigned int kManufacturerOffset = 8;
+ const unsigned int kManufacturerLength = 2;
+ const unsigned int kDescriptorOffset = 54;
+ const unsigned int kNumDescriptors = 4;
+ const unsigned int kDescriptorLength = 18;
+ // The specifier types.
+ const unsigned char kMonitorNameDescriptor = 0xfc;
+
+ if (manufacturer_id) {
+ if (edid.size() < kManufacturerOffset + kManufacturerLength) {
+ LOG(ERROR) << "too short EDID data: manifacturer id";
+ return false;
+ }
+
+ *manufacturer_id =
+ *reinterpret_cast<const uint16_t*>(&edid[kManufacturerOffset]);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+ *manufacturer_id = base::ByteSwap(*manufacturer_id);
+#endif
+ }
+
+ if (!human_readable_name)
+ return true;
+
+ human_readable_name->clear();
+ for (unsigned int i = 0; i < kNumDescriptors; ++i) {
+ if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength)
+ break;
+
+ size_t offset = kDescriptorOffset + i * kDescriptorLength;
+ // If the descriptor contains the display name, it has the following
+ // structure:
+ // bytes 0-2, 4: \0
+ // byte 3: descriptor type, defined above.
+ // bytes 5-17: text data, ending with \r, padding with spaces
+ // 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) {
+ std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]),
+ kDescriptorLength - 5);
+ base::TrimWhitespaceASCII(
+ found_name, base::TRIM_TRAILING, human_readable_name);
+ break;
+ }
+ }
+
+ // Verify if the |human_readable_name| consists of printable characters only.
+ 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;
+ }
+ }
+
+ 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.
+ // - byte 0: tag. should be 02h.
+ // - byte 1: revision. only cares revision 3 (03h).
+ // - byte 4-: data block.
+ const unsigned int kExtensionBase = 128;
+ const unsigned int kExtensionSize = 128;
+ const unsigned int kNumExtensionsOffset = 126;
+ const unsigned int kDataBlockOffset = 4;
+ const unsigned char kCEAExtensionTag = '\x02';
+ const unsigned char kExpectedExtensionRevision = '\x03';
+ const unsigned char kExtendedTag = 7;
+ const unsigned char kExtendedVideoCapabilityTag = 0;
+ const unsigned int kPTOverscan = 4;
+ const unsigned int kITOverscan = 2;
+ const unsigned int kCEOverscan = 0;
+
+ if (edid.size() <= kNumExtensionsOffset)
+ return false;
+
+ unsigned char num_extensions = edid[kNumExtensionsOffset];
+
+ for (size_t i = 0; i < num_extensions; ++i) {
+ // Skip parsing the whole extension if size is not enough.
+ if (edid.size() < kExtensionBase + (i + 1) * kExtensionSize)
+ break;
+
+ size_t extension_offset = kExtensionBase + i * kExtensionSize;
+ unsigned char tag = edid[extension_offset];
+ unsigned char revision = edid[extension_offset + 1];
+ if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision)
+ continue;
+
+ unsigned char timing_descriptors_start = std::min(
+ edid[extension_offset + 2], static_cast<unsigned char>(kExtensionSize));
+
+ for (size_t data_offset = extension_offset + kDataBlockOffset;
+ data_offset < extension_offset + timing_descriptors_start;) {
+ // A data block is encoded as:
+ // - byte 1 high 3 bits: tag. '07' for extended tags.
+ // - byte 1 remaining bits: the length of data block.
+ // - byte 2: the extended tag. '0' for video capability.
+ // - byte 3: the capability.
+ unsigned char tag = edid[data_offset] >> 5;
+ unsigned char payload_length = edid[data_offset] & 0x1f;
+ if (data_offset + payload_length > edid.size())
+ break;
+
+ if (tag != kExtendedTag || payload_length < 2 ||
+ edid[data_offset + 1] != kExtendedVideoCapabilityTag) {
+ data_offset += payload_length + 1;
+ continue;
+ }
+
+ // The difference between preferred, IT, and CE video formats
+ // doesn't matter. Sets |flag| to true if any of these flags are true.
+ if ((edid[data_offset + 2] & (1 << kPTOverscan)) ||
+ (edid[data_offset + 2] & (1 << kITOverscan)) ||
+ (edid[data_offset + 2] & (1 << kCEOverscan))) {
+ *flag = true;
+ } else {
+ *flag = false;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/util/edid_parser.h b/chromium/ui/display/util/edid_parser.h
new file mode 100644
index 00000000000..4f12d40aaa2
--- /dev/null
+++ b/chromium/ui/display/util/edid_parser.h
@@ -0,0 +1,42 @@
+// 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_DISPLAY_UTIL_EDID_PARSER_H_
+#define UI_DISPLAY_UTIL_EDID_PARSER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "ui/display/util/display_util_export.h"
+
+// EDID (Extended Display Identification Data) is a format for monitor
+// metadata. This provides a parser for the data.
+
+namespace ui {
+
+// Generates the display id for the pair of |edid| and |index|, and store in
+// |display_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);
+
+// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|
+// and |human_readable_name| and returns true. NULL 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,
+ std::string* human_readable_name);
+
+DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
+ const std::vector<uint8_t>& edid,
+ bool* flag);
+
+} // namespace ui
+
+#endif // UI_DISPLAY_UTIL_EDID_PARSER_H_
diff --git a/chromium/ui/display/util/edid_parser_unittest.cc b/chromium/ui/display/util/edid_parser_unittest.cc
new file mode 100644
index 00000000000..ef55bd682fc
--- /dev/null
+++ b/chromium/ui/display/util/edid_parser_unittest.cc
@@ -0,0 +1,229 @@
+// 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/display/util/edid_parser.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+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[] =
+ "\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"
+ "\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
+ "\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
+ "\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";
+
+const 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"
+ "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
+ "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
+ "\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";
+
+const 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"
+ "\xa9\xc0\xb3\x00\x01\x01\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+ "\x45\x00\xa0\x5a\x00\x00\x00\x1e\x66\x21\x56\xaa\x51\x00\x1e\x30"
+ "\x46\x8f\x33\x00\xa0\x5a\x00\x00\x00\x1e\x00\x00\x00\xfd\x00\x18"
+ "\x4b\x0f\x51\x17\x00\x0a\x20\x20\x20\x20\x20\x20\x00\x00\x00\xfc"
+ "\x00\x53\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x01\x1d"
+ "\x02\x03\x1f\xf1\x47\x90\x04\x05\x03\x20\x22\x07\x23\x09\x07\x07"
+ "\x83\x01\x00\x00\xe2\x00\x0f\x67\x03\x0c\x00\x20\x00\xb8\x2d\x01"
+ "\x1d\x80\x18\x71\x1c\x16\x20\x58\x2c\x25\x00\xa0\x5a\x00\x00\x00"
+ "\x9e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\xa0\x5a\x00"
+ "\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\xa0"
+ "\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";
+
+// The EDID info misdetecting overscan once. see crbug.com/226318
+const 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"
+ "\x01\x01\x01\x01\x01\x01\x28\x3c\x80\xa0\x70\xb0\x23\x40\x30\x20"
+ "\x36\x00\x81\x91\x21\x00\x00\x1a\x00\x00\x00\xff\x00\x50\x48\x35"
+ "\x4e\x59\x31\x33\x4e\x32\x30\x30\x4c\x0a\x00\x00\x00\xfc\x00\x44"
+ "\x45\x4c\x4c\x20\x55\x33\x30\x31\x31\x0a\x20\x20\x00\x00\x00\xfd"
+ "\x00\x31\x56\x1d\x5e\x12\x00\x0a\x20\x20\x20\x20\x20\x20\x01\x38"
+ "\x02\x03\x29\xf1\x50\x90\x05\x04\x03\x02\x07\x16\x01\x06\x11\x12"
+ "\x15\x13\x14\x1f\x20\x23\x0d\x7f\x07\x83\x0f\x00\x00\x67\x03\x0c"
+ "\x00\x10\x00\x38\x2d\xe3\x05\x03\x01\x02\x3a\x80\x18\x71\x38\x2d"
+ "\x40\x58\x2c\x45\x00\x81\x91\x21\x00\x00\x1e\x01\x1d\x80\x18\x71"
+ "\x1c\x16\x20\x58\x2c\x25\x00\x81\x91\x21\x00\x00\x9e\x01\x1d\x00"
+ "\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";
+
+const 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"
+ "\xA9\x40\xB3\x00\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20"
+ "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E"
+ "\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";
+
+const 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"
+ "\xB3\x00\xD1\xC0\xD1\x00\x28\x3C\x80\xA0\x70\xB0\x23\x40\x30\x20"
+ "\x36\x00\x07\x44\x21\x00\x00\x1A\x00\x00\x00\xFD\x00\x30\x55\x1E"
+ "\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";
+
+} // 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;
+ std::string human_readable_name;
+ std::vector<uint8_t> edid(
+ kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
+ EXPECT_TRUE(ParseOutputDeviceData(
+ edid, &manufacturer_id, &human_readable_name));
+ EXPECT_EQ(0x22f0u, manufacturer_id);
+ EXPECT_EQ("HP ZR30w", human_readable_name);
+
+ manufacturer_id = 0;
+ human_readable_name.clear();
+ edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
+ EXPECT_EQ(0x4ca3u, manufacturer_id);
+ EXPECT_EQ("", human_readable_name);
+
+ // Internal display doesn't have name.
+ EXPECT_TRUE(ParseOutputDeviceData(edid, NULL, &human_readable_name));
+ EXPECT_TRUE(human_readable_name.empty());
+
+ manufacturer_id = 0;
+ human_readable_name.clear();
+ edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
+ EXPECT_TRUE(ParseOutputDeviceData(
+ edid, &manufacturer_id, &human_readable_name));
+ EXPECT_EQ(0x4c2du, manufacturer_id);
+ EXPECT_EQ("SAMSUNG", human_readable_name);
+}
+
+TEST(EDIDParserTest, ParseBrokenEDID) {
+ uint16_t manufacturer_id = 0;
+ std::string human_readable_name;
+ std::vector<uint8_t> edid;
+
+ // length == 0
+ EXPECT_FALSE(ParseOutputDeviceData(
+ edid, &manufacturer_id, &human_readable_name));
+
+ // 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, &human_readable_name));
+
+ // If |human_readable_name| isn't specified, it skips parsing the name.
+ manufacturer_id = 0;
+ EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
+ EXPECT_EQ(0x22f0u, manufacturer_id);
+}
+
+TEST(EDIDParserTest, GetDisplayId) {
+ // EDID of kLP2565A and B are slightly different but actually the same device.
+ int64_t id1 = -1;
+ int64_t id2 = -1;
+ std::vector<uint8_t> edid(kLP2565A, kLP2565A + charsize(kLP2565A));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id1));
+ edid.assign(kLP2565B, kLP2565B + charsize(kLP2565B));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id2));
+ EXPECT_EQ(id1, id2);
+ EXPECT_NE(-1, id1);
+}
+
+TEST(EDIDParserTest, GetDisplayIdFromInternal) {
+ int64_t id = -1;
+ std::vector<uint8_t> edid(
+ kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
+ EXPECT_TRUE(GetDisplayIdFromEDID(edid, 0, &id));
+ EXPECT_NE(-1, id);
+}
+
+TEST(EDIDParserTest, GetDisplayIdFailure) {
+ int64_t id = -1;
+ std::vector<uint8_t> edid;
+ EXPECT_FALSE(GetDisplayIdFromEDID(edid, 0, &id));
+ EXPECT_EQ(-1, id);
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/util/x11/DEPS b/chromium/ui/display/util/x11/DEPS
new file mode 100644
index 00000000000..25c2d71b78a
--- /dev/null
+++ b/chromium/ui/display/util/x11/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/gfx/x",
+]
diff --git a/chromium/ui/display/util/x11/edid_parser_x11.cc b/chromium/ui/display/util/x11/edid_parser_x11.cc
new file mode 100644
index 00000000000..407639b6508
--- /dev/null
+++ b/chromium/ui/display/util/x11/edid_parser_x11.cc
@@ -0,0 +1,122 @@
+// 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/display/util/x11/edid_parser_x11.h"
+
+#include <X11/extensions/Xrandr.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+#include "base/strings/string_util.h"
+#include "ui/display/util/edid_parser.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace ui {
+
+namespace {
+
+bool IsRandRAvailable() {
+ int randr_version_major = 0;
+ int randr_version_minor = 0;
+ static bool is_randr_available = XRRQueryVersion(
+ gfx::GetXDisplay(), &randr_version_major, &randr_version_minor);
+ return is_randr_available;
+}
+
+// Get the EDID data from the |output| and stores to |edid|.
+// Returns true if EDID property is successfully obtained. Otherwise returns
+// false and does not touch |edid|.
+bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
+ if (!IsRandRAvailable())
+ return false;
+
+ Display* display = gfx::GetXDisplay();
+
+ static Atom edid_property = XInternAtom(
+ gfx::GetXDisplay(),
+ RR_PROPERTY_RANDR_EDID, false);
+
+ bool has_edid_property = false;
+ int num_properties = 0;
+ Atom* properties = XRRListOutputProperties(display, output, &num_properties);
+ for (int i = 0; i < num_properties; ++i) {
+ if (properties[i] == edid_property) {
+ has_edid_property = true;
+ break;
+ }
+ }
+ XFree(properties);
+ if (!has_edid_property)
+ return false;
+
+ Atom actual_type;
+ int actual_format;
+ unsigned long bytes_after;
+ unsigned long nitems = 0;
+ unsigned char* prop = NULL;
+ XRRGetOutputProperty(display,
+ output,
+ edid_property,
+ 0, // offset
+ 128, // length
+ false, // _delete
+ false, // pending
+ AnyPropertyType, // req_type
+ &actual_type,
+ &actual_format,
+ &nitems,
+ &bytes_after,
+ &prop);
+ DCHECK_EQ(XA_INTEGER, actual_type);
+ DCHECK_EQ(8, actual_format);
+ edid->assign(prop, prop + nitems);
+ XFree(prop);
+ return true;
+}
+
+// Gets some useful data from the specified output device, such like
+// manufacturer's ID, product code, and human readable name. Returns false if it
+// fails to get those data and doesn't touch manufacturer ID/product code/name.
+// NULL can be passed for unwanted output parameters.
+bool GetOutputDeviceData(XID output,
+ uint16_t* manufacturer_id,
+ std::string* human_readable_name) {
+ std::vector<uint8_t> edid;
+ if (!GetEDIDProperty(output, &edid))
+ return false;
+
+ bool result = ParseOutputDeviceData(
+ edid, manufacturer_id, human_readable_name);
+ return result;
+}
+
+} // namespace
+
+bool GetDisplayId(XID output_id,
+ uint8_t output_index,
+ int64_t* display_id_out) {
+ std::vector<uint8_t> edid;
+ if (!GetEDIDProperty(output_id, &edid))
+ return false;
+
+ bool result = GetDisplayIdFromEDID(edid, output_index, display_id_out);
+ return result;
+}
+
+std::string GetDisplayName(RROutput output) {
+ std::string display_name;
+ GetOutputDeviceData(output, NULL, &display_name);
+ return display_name;
+}
+
+bool GetOutputOverscanFlag(RROutput output, bool* flag) {
+ std::vector<uint8_t> edid;
+ if (!GetEDIDProperty(output, &edid))
+ return false;
+
+ bool found = ParseOutputOverscanFlag(edid, flag);
+ return found;
+}
+
+} // namespace ui
diff --git a/chromium/ui/display/util/x11/edid_parser_x11.h b/chromium/ui/display/util/x11/edid_parser_x11.h
new file mode 100644
index 00000000000..55048e699e4
--- /dev/null
+++ b/chromium/ui/display/util/x11/edid_parser_x11.h
@@ -0,0 +1,40 @@
+// 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_DISPLAY_UTIL_X11_EDID_PARSER_X11_H_
+#define UI_DISPLAY_UTIL_X11_EDID_PARSER_X11_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "ui/display/types/display_constants.h"
+#include "ui/display/util/display_util_export.h"
+
+typedef unsigned long XID;
+typedef XID RROutput;
+
+// Xrandr utility functions to help get EDID information.
+
+namespace ui {
+
+// Gets the EDID data from |output| and generates the display id through
+// |GetDisplayIdFromEDID|.
+DISPLAY_UTIL_EXPORT bool GetDisplayId(XID output,
+ uint8_t index,
+ int64_t* display_id_out);
+
+// Generate the human readable string from EDID obtained from |output|.
+DISPLAY_UTIL_EXPORT std::string GetDisplayName(RROutput output);
+
+// Gets the overscan flag from |output| and stores to |flag|. Returns true if
+// the flag is found. Otherwise returns false and doesn't touch |flag|. The
+// output will produce overscan if |flag| is set to true, but the output may
+// still produce overscan even though it returns true and |flag| is set to
+// false.
+DISPLAY_UTIL_EXPORT bool GetOutputOverscanFlag(RROutput output, bool* flag);
+
+} // namespace ui
+
+#endif // UI_DISPLAY_UTIL_X11_EDID_PARSER_X11_H_
diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn
new file mode 100644
index 00000000000..26c4b1ed633
--- /dev/null
+++ b/chromium/ui/events/BUILD.gn
@@ -0,0 +1,311 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+static_library("dom4_keycode_converter") {
+ sources = [
+ "keycodes/dom4/keycode_converter.cc",
+ "keycodes/dom4/keycode_converter.h",
+ "keycodes/dom4/keycode_converter_data.h",
+ ]
+
+ deps = [ "//base" ]
+}
+
+component("events_base") {
+ sources = [
+ "event_constants.h",
+ "event_switches.cc",
+ "event_switches.h",
+ "events_base_export.h",
+ "gesture_event_details.cc",
+ "gesture_event_details.h",
+ "gestures/gesture_configuration.cc",
+ "gestures/gesture_configuration.h",
+ "keycodes/keyboard_code_conversion.cc",
+ "keycodes/keyboard_code_conversion.h",
+ "keycodes/keyboard_code_conversion_android.cc",
+ "keycodes/keyboard_code_conversion_android.h",
+ "keycodes/keyboard_code_conversion_mac.h",
+ "keycodes/keyboard_code_conversion_mac.mm",
+ "keycodes/keyboard_code_conversion_win.cc",
+ "keycodes/keyboard_code_conversion_win.h",
+ "keycodes/keyboard_codes.h",
+ "latency_info.cc",
+ "latency_info.h",
+ ]
+
+ defines = [ "EVENTS_BASE_IMPLEMENTATION" ]
+
+ deps = [
+ ":dom4_keycode_converter",
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ if (use_x11) {
+ configs += [ "//build/config/linux:x11" ]
+
+ sources += [
+ "keycodes/keyboard_code_conversion_x.cc",
+ "keycodes/keyboard_code_conversion_x.h",
+ "x/device_data_manager.cc",
+ "x/device_data_manager.h",
+ "x/device_list_cache_x.cc",
+ "x/device_list_cache_x.h",
+ "x/touch_factory_x11.cc",
+ "x/touch_factory_x11.h",
+ ]
+ }
+}
+
+component("events") {
+ deps = [
+ ":dom4_keycode_converter",
+ ":events_base",
+ ":gesture_detection",
+ "//skia",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ defines = [ "EVENTS_IMPLEMENTATION" ]
+
+ sources = [
+ "cocoa/cocoa_event_utils.h",
+ "cocoa/cocoa_event_utils.mm",
+ "event.cc",
+ "event.h",
+ "event_dispatcher.cc",
+ "event_dispatcher.h",
+ "event_handler.cc",
+ "event_handler.h",
+ "event_processor.cc",
+ "event_processor.h",
+ "event_rewriter.h",
+ "event_source.cc",
+ "event_source.h",
+ "event_target.cc",
+ "event_target.h",
+ "event_target_iterator.h",
+ "event_targeter.cc",
+ "event_targeter.h",
+ "event_utils.cc",
+ "event_utils.h",
+ "events_export.h",
+ "events_stub.cc",
+ "gestures/gesture_point.cc",
+ "gestures/gesture_point.h",
+ "gestures/gesture_recognizer.h",
+ "gestures/gesture_recognizer_impl.cc",
+ "gestures/gesture_recognizer_impl.h",
+ "gestures/gesture_recognizer_impl_mac.cc",
+ "gestures/gesture_sequence.cc",
+ "gestures/gesture_sequence.h",
+ "gestures/gesture_types.h",
+ "gestures/unified_gesture_detector_enabled.cc",
+ "gestures/unified_gesture_detector_enabled.h",
+ "gestures/velocity_calculator.cc",
+ "gestures/velocity_calculator.h",
+ "platform/x11/x11_event_source.cc",
+ "platform/x11/x11_event_source.h",
+ "win/events_win.cc",
+ "x/events_x.cc",
+ ]
+
+ if (use_x11) {
+ configs += [
+ "//build/config/linux:glib",
+ "//build/config/linux:x11",
+ ]
+ } else {
+ sources -= [
+ "platform/x11/x11_event_source.cc",
+ "platform/x11/x11_event_source.h",
+ "x/events_x.cc",
+ ]
+ }
+
+ if (!is_chromeos && is_linux) {
+ sources += [
+ "linux/text_edit_command_auralinux.cc",
+ "linux/text_edit_command_auralinux.h",
+ "linux/text_edit_key_bindings_delegate_auralinux.cc",
+ "linux/text_edit_key_bindings_delegate_auralinux.h",
+ ]
+ }
+
+ if (use_ozone) {
+ sources += [
+ "ozone/device/udev/device_manager_udev.cc",
+ "ozone/device/udev/device_manager_udev.h",
+ "ozone/evdev/event_converter_evdev.cc",
+ "ozone/evdev/event_converter_evdev.h",
+ "ozone/evdev/event_device_info.cc",
+ "ozone/evdev/event_device_info.h",
+ "ozone/evdev/event_factory_evdev.cc",
+ "ozone/evdev/event_factory_evdev.h",
+ "ozone/evdev/event_modifiers_evdev.cc",
+ "ozone/evdev/event_modifiers_evdev.h",
+ "ozone/evdev/key_event_converter_evdev.cc",
+ "ozone/evdev/key_event_converter_evdev.h",
+ "ozone/evdev/touch_event_converter_evdev.cc",
+ "ozone/evdev/touch_event_converter_evdev.h",
+ "ozone/event_factory_ozone.cc",
+ "ozone/event_factory_ozone.h",
+ "ozone/events_ozone.cc",
+ ]
+ }
+
+ if (use_aura) {
+ sources += [
+ "gestures/gesture_provider_aura.cc",
+ "gestures/gesture_provider_aura.h",
+ "gestures/motion_event_aura.cc",
+ "gestures/motion_event_aura.h",
+ ]
+ }
+
+ if (is_win || use_x11 || use_ozone) {
+ sources -= [ "events_stub.cc" ]
+ }
+}
+
+component("gesture_detection") {
+ sources = [
+ "gesture_detection/bitset_32.h",
+ "gesture_detection/filtered_gesture_provider.cc",
+ "gesture_detection/filtered_gesture_provider.h",
+ "gesture_detection/gesture_detection_export.h",
+ "gesture_detection/gesture_detector.cc",
+ "gesture_detection/gesture_detector.h",
+ "gesture_detection/gesture_event_data.cc",
+ "gesture_detection/gesture_event_data.h",
+ "gesture_detection/gesture_event_data_packet.cc",
+ "gesture_detection/gesture_event_data_packet.h",
+ "gesture_detection/gesture_config_helper.h",
+ "gesture_detection/gesture_provider.cc",
+ "gesture_detection/gesture_provider.h",
+ "gesture_detection/motion_event.h",
+ "gesture_detection/scale_gesture_detector.cc",
+ "gesture_detection/scale_gesture_detector.h",
+ "gesture_detection/snap_scroll_controller.cc",
+ "gesture_detection/snap_scroll_controller.h",
+ "gesture_detection/touch_disposition_gesture_filter.cc",
+ "gesture_detection/touch_disposition_gesture_filter.h",
+ "gesture_detection/velocity_tracker_state.cc",
+ "gesture_detection/velocity_tracker_state.h",
+ "gesture_detection/velocity_tracker.cc",
+ "gesture_detection/velocity_tracker.h",
+ ]
+
+ deps = [
+ ":events_base",
+ "//base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ defines = [ "GESTURE_DETECTION_IMPLEMENTATION" ]
+
+ if (is_android) {
+ sources += [ "gesture_detection/gesture_config_helper_android.cc" ]
+ } else if (use_aura) {
+ sources += [ "gesture_detection/gesture_config_helper_aura.cc" ]
+ } else {
+ sources += [ "gesture_detection/gesture_config_helper.cc" ]
+ }
+}
+
+source_set("events_test_support") {
+ sources = [
+ "test/cocoa_test_event_utils.h",
+ "test/cocoa_test_event_utils.mm",
+ "test/events_test_utils.cc",
+ "test/events_test_utils.h",
+ "test/events_test_utils_x11.cc",
+ "test/events_test_utils_x11.h",
+ "test/platform_event_waiter.cc",
+ "test/platform_event_waiter.h",
+ "test/test_event_handler.cc",
+ "test/test_event_handler.h",
+ "test/test_event_processor.cc",
+ "test/test_event_processor.h",
+ "test/test_event_target.cc",
+ "test/test_event_target.h",
+ ]
+
+ deps = [
+ "//skia",
+ ":events_base",
+ ":events",
+ ]
+
+ if (is_ios) {
+ sources -= [
+ "test/cocoa_test_event_utils.h",
+ "test/cocoa_test_event_utils.mm",
+ ]
+ }
+
+ if (use_x11) {
+ configs += [ "//build/config/linux:x11" ]
+ } else {
+ sources -= [
+ "test/events_test_utils_x11.cc",
+ "test/events_test_utils_x11.h",
+ ]
+ }
+}
+
+test("events_unittests") {
+ sources = [
+ "cocoa/events_mac_unittest.mm",
+ "event_dispatcher_unittest.cc",
+ "event_processor_unittest.cc",
+ "event_rewriter_unittest.cc",
+ "event_unittest.cc",
+ "gestures/velocity_calculator_unittest.cc",
+ "gesture_detection/bitset_32_unittest.cc",
+ "gesture_detection/gesture_provider_unittest.cc",
+ "gesture_detection/mock_motion_event.h",
+ "gesture_detection/mock_motion_event.cc",
+ "gesture_detection/velocity_tracker_unittest.cc",
+ "gesture_detection/touch_disposition_gesture_filter_unittest.cc",
+ "keycodes/dom4/keycode_converter_unittest.cc",
+ "latency_info_unittest.cc",
+ "platform/platform_event_source_unittest.cc",
+ "x/events_x_unittest.cc",
+ ]
+
+ if (!use_x11) {
+ sources -= [
+ "x/events_x_unittest.cc",
+ ]
+ }
+
+ if (use_ozone) {
+ sources += [
+ "ozone/evdev/key_event_converter_evdev_unittest.cc",
+ "ozone/evdev/touch_event_converter_evdev_unittest.cc",
+ ]
+ }
+
+ deps = [
+ ":events",
+ ":events_base",
+ ":events_test_support",
+ ":gesture_detection",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//skia",
+ "//testing/gtest",
+ "//ui/gfx:gfx_test_support",
+ ]
+}
diff --git a/chromium/ui/events/PRESUBMIT.py b/chromium/ui/events/PRESUBMIT.py
new file mode 100644
index 00000000000..dcdf2d5fbfd
--- /dev/null
+++ b/chromium/ui/events/PRESUBMIT.py
@@ -0,0 +1,26 @@
+# 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.
+
+"""Chromium presubmit script for src/ui/events
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into gcl.
+"""
+
+def GetPreferredTryMasters(project, change):
+ tests = set(['ash_unittests',
+ 'aura_unittests',
+ 'events_unittests',
+ 'keyboard_unittests',
+ 'views_unittests'])
+
+ return {
+ 'tryserver.chromium': {
+ 'linux_chromium_rel': tests,
+ 'linux_chromium_chromeos_rel': tests,
+ 'linux_chromeos_asan': tests,
+ 'win_chromium_compile_dbg': tests,
+ 'win_chromium_rel': tests,
+ }
+ }
diff --git a/chromium/ui/events/cocoa/cocoa_event_utils.h b/chromium/ui/events/cocoa/cocoa_event_utils.h
new file mode 100644
index 00000000000..a5984357537
--- /dev/null
+++ b/chromium/ui/events/cocoa/cocoa_event_utils.h
@@ -0,0 +1,26 @@
+// 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_COCOA_COCOA_EVENT_UTILS_H_
+#define UI_EVENTS_COCOA_COCOA_EVENT_UTILS_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+// Converts the Cocoa |modifiers| bitsum into a ui::EventFlags bitsum.
+EVENTS_EXPORT int EventFlagsFromModifiers(NSUInteger modifiers);
+
+// Retrieves a bitsum of ui::EventFlags represented by |event|,
+// but instead use the modifier flags given by |modifiers|,
+// which is the same format as |-NSEvent modifierFlags|. This allows
+// substitution of the modifiers without having to create a new event from
+// scratch.
+EVENTS_EXPORT int EventFlagsFromNSEventWithModifiers(NSEvent* event,
+ NSUInteger modifiers);
+} // namespace ui
+
+#endif // UI_EVENTS_COCOA_COCOA_EVENT_UTILS_H_
diff --git a/chromium/ui/events/cocoa/cocoa_event_utils.mm b/chromium/ui/events/cocoa/cocoa_event_utils.mm
new file mode 100644
index 00000000000..ade083c0eb2
--- /dev/null
+++ b/chromium/ui/events/cocoa/cocoa_event_utils.mm
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/events/cocoa/cocoa_event_utils.h"
+
+#include "ui/events/event_constants.h"
+#include "ui/events/event_utils.h"
+
+namespace {
+
+bool IsLeftButtonEvent(NSEvent* event) {
+ NSEventType type = [event type];
+ return type == NSLeftMouseDown || type == NSLeftMouseDragged ||
+ type == NSLeftMouseUp;
+}
+
+bool IsRightButtonEvent(NSEvent* event) {
+ NSEventType type = [event type];
+ return type == NSRightMouseDown || type == NSRightMouseDragged ||
+ type == NSRightMouseUp;
+}
+
+bool IsMiddleButtonEvent(NSEvent* event) {
+ if ([event buttonNumber] != 2)
+ return false;
+
+ NSEventType type = [event type];
+ return type == NSOtherMouseDown || type == NSOtherMouseDragged ||
+ type == NSOtherMouseUp;
+}
+
+} // namespace
+
+namespace ui {
+
+int EventFlagsFromModifiers(NSUInteger modifiers) {
+ int flags = 0;
+ flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
+ flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
+ flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
+ flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
+ flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
+ return flags;
+}
+
+int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
+ int flags = EventFlagsFromModifiers(modifiers);
+ flags |= IsLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
+ flags |= IsRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
+ flags |= IsMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
+ return flags;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/cocoa/events_mac.mm b/chromium/ui/events/cocoa/events_mac.mm
index ffc34d7f2a7..7675eb6af05 100644
--- a/chromium/ui/events/cocoa/events_mac.mm
+++ b/chromium/ui/events/cocoa/events_mac.mm
@@ -1,59 +1,56 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 <Cocoa/Cocoa.h>
+#include "ui/events/event_utils.h"
-#include "ui/events/event_constants.h"
+#include <Cocoa/Cocoa.h>
-#include "base/event_types.h"
#include "base/logging.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/events/event_utils.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "ui/gfx/point.h"
+#include "ui/gfx/vector2d.h"
namespace ui {
+void UpdateDeviceList() {
+ NOTIMPLEMENTED();
+}
+
EventType EventTypeFromNative(const base::NativeEvent& native_event) {
- NSEventType native_type = [native_event type];
- switch (native_type) {
+ NSEventType type = [native_event type];
+ switch (type) {
+ case NSKeyDown:
+ return ET_KEY_PRESSED;
+ case NSKeyUp:
+ return ET_KEY_RELEASED;
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
return ET_MOUSE_PRESSED;
-
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:
return ET_MOUSE_RELEASED;
-
- case NSMouseMoved:
- return ET_MOUSE_MOVED;
-
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
return ET_MOUSE_DRAGGED;
-
+ case NSMouseMoved:
+ return ET_MOUSE_MOVED;
+ case NSScrollWheel:
+ return ET_MOUSEWHEEL;
case NSMouseEntered:
return ET_MOUSE_ENTERED;
-
case NSMouseExited:
return ET_MOUSE_EXITED;
-
- case NSKeyDown:
- return ET_KEY_PRESSED;
-
- case NSKeyUp:
- return ET_KEY_RELEASED;
-
+ case NSEventTypeSwipe:
+ return ET_SCROLL_FLING_START;
case NSFlagsChanged:
- return ET_KEY_PRESSED;
-
- case NSScrollWheel:
- return ET_MOUSEWHEEL;
-
case NSAppKitDefined:
case NSSystemDefined:
case NSApplicationDefined:
@@ -61,156 +58,176 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
case NSCursorUpdate:
case NSTabletPoint:
case NSTabletProximity:
+ case NSEventTypeGesture:
+ case NSEventTypeMagnify:
+ case NSEventTypeRotate:
+ case NSEventTypeBeginGesture:
+ case NSEventTypeEndGesture:
+ NOTIMPLEMENTED() << type;
+ break;
default:
- return ET_UNKNOWN;
+ NOTIMPLEMENTED() << type;
+ break;
}
+ return ET_UNKNOWN;
}
-int EventFlagsFromNative(const base::NativeEvent& native_event) {
- int event_flags = 0;
- NSUInteger modifiers = [native_event modifierFlags];
-
- if (modifiers & NSAlphaShiftKeyMask)
- event_flags = event_flags | EF_CAPS_LOCK_DOWN;
-
- if (modifiers & NSShiftKeyMask)
- event_flags = event_flags | EF_SHIFT_DOWN;
-
- if (modifiers & NSControlKeyMask)
- event_flags = event_flags | EF_CONTROL_DOWN;
-
- if (modifiers & NSAlternateKeyMask)
- event_flags = event_flags | EF_ALT_DOWN;
-
- if (modifiers & NSCommandKeyMask)
- event_flags = event_flags | EF_COMMAND_DOWN;
-
- NSEventType type = [native_event type];
-
- if (type == NSLeftMouseDown ||
- type == NSLeftMouseUp ||
- type == NSLeftMouseDragged) {
- event_flags = event_flags | EF_LEFT_MOUSE_BUTTON;
- }
-
- if (type == NSRightMouseDown ||
- type == NSRightMouseUp ||
- type == NSRightMouseDragged) {
- event_flags = event_flags | EF_RIGHT_MOUSE_BUTTON;
- }
-
- if (type == NSOtherMouseDown ||
- type == NSOtherMouseUp ||
- type == NSOtherMouseDragged) {
- event_flags = event_flags | EF_MIDDLE_MOUSE_BUTTON;
- }
-
- return event_flags;
+int EventFlagsFromNative(const base::NativeEvent& event) {
+ NSUInteger modifiers = [event modifierFlags];
+ return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
- return base::TimeDelta::FromMicroseconds(
- [native_event timestamp] * 1000000.0f);
+ NSTimeInterval since_system_startup = [native_event timestamp];
+ // Truncate to extract seconds before doing floating point arithmetic.
+ int64_t seconds = since_system_startup;
+ since_system_startup -= seconds;
+ int64_t microseconds = since_system_startup * 1000000;
+ return base::TimeDelta::FromSeconds(seconds) +
+ base::TimeDelta::FromMicroseconds(microseconds);
}
gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
NSWindow* window = [native_event window];
+ if (!window) {
+ NOTIMPLEMENTED(); // Point will be in screen coordinates.
+ return gfx::Point();
+ }
NSPoint location = [native_event locationInWindow];
-
- // Convert |location| to be relative to coordinate system of |contentView|.
- // Note: this assumes that ui::Event coordinates are rooted in the top-level
- // view (with flipped coordinates). A more general (but costly) approach
- // would be to hit-test the view of the event and use the found view's
- // coordinate system. Currently there is no need for this generality, and
- // speed is preferred. Flipped views are not suppported.
- DCHECK([[window contentView] isFlipped] == NO);
- location = [[window contentView] convertPoint:location fromView:nil];
- location.y = [[window contentView] bounds].size.height - location.y;
-
- return gfx::Point(NSPointToCGPoint(location));
+ NSRect content_rect = [window contentRectForFrameRect:[window frame]];
+ return gfx::Point(location.x, NSHeight(content_rect) - location.y);
}
gfx::Point EventSystemLocationFromNative(
const base::NativeEvent& native_event) {
- // TODO(port): Needs to always return screen position here. Returning normal
- // origin for now since that's obviously wrong.
- return gfx::Point(0, 0);
+ NOTIMPLEMENTED();
+ return gfx::Point();
}
-KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
- return ui::KeyboardCodeFromNSEvent(native_event);
+int EventButtonFromNative(const base::NativeEvent& native_event) {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+int GetChangedMouseButtonFlagsFromNative(
+ const base::NativeEvent& native_event) {
+ NSEventType type = [native_event type];
+ switch (type) {
+ case NSLeftMouseDown:
+ case NSLeftMouseUp:
+ case NSLeftMouseDragged:
+ return EF_LEFT_MOUSE_BUTTON;
+ case NSRightMouseDown:
+ case NSRightMouseUp:
+ case NSRightMouseDragged:
+ return EF_RIGHT_MOUSE_BUTTON;
+ case NSOtherMouseDown:
+ case NSOtherMouseUp:
+ case NSOtherMouseDragged:
+ return EF_MIDDLE_MOUSE_BUTTON;
+ }
+ return 0;
}
-std::string CodeFromNative(const base::NativeEvent& native_event) {
- return ui::CodeFromNSEvent(native_event);
+gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& event) {
+ // Empirically, a value of 0.1 is typical for one mousewheel click. Positive
+ // values when scrolling up or to the left. Scrolling quickly results in a
+ // higher delta per click, up to about 15.0. (Quartz documentation suggests
+ // +/-10).
+ // Multiply by 1000 to vaguely approximate WHEEL_DELTA on Windows (120).
+ const CGFloat kWheelDeltaMultiplier = 1000;
+ return gfx::Vector2d(kWheelDeltaMultiplier * [event deltaX],
+ kWheelDeltaMultiplier * [event deltaY]);
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
- EventType type = EventTypeFromNative(native_event);
- return type == ET_MOUSE_PRESSED ||
- type == ET_MOUSE_DRAGGED ||
- type == ET_MOUSE_RELEASED ||
- type == ET_MOUSE_MOVED ||
- type == ET_MOUSE_ENTERED ||
- type == ET_MOUSE_EXITED;
+base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+ return [event copy];
}
-gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
- // TODO(dhollowa): Come back to this once comparisons can be made with other
- // platforms.
- return gfx::Vector2d([native_event deltaX], [native_event deltaY]);
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+ [event release];
}
-void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
- // Touch is currently unsupported.
+void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
+ NOTIMPLEMENTED();
}
int GetTouchId(const base::NativeEvent& native_event) {
- // Touch is currently unsupported.
+ NOTIMPLEMENTED();
return 0;
}
float GetTouchRadiusX(const base::NativeEvent& native_event) {
- // Touch is currently unsupported.
- return 1.0;
+ NOTIMPLEMENTED();
+ return 0.f;
}
float GetTouchRadiusY(const base::NativeEvent& native_event) {
- // Touch is currently unsupported.
- return 1.0;
+ NOTIMPLEMENTED();
+ return 0.f;
}
float GetTouchAngle(const base::NativeEvent& native_event) {
- // Touch is currently unsupported.
- return 0.0;
+ NOTIMPLEMENTED();
+ return 0.f;
}
float GetTouchForce(const base::NativeEvent& native_event) {
- // Touch is currently unsupported.
- return 0.0;
+ NOTIMPLEMENTED();
+ return 0.f;
}
bool GetScrollOffsets(const base::NativeEvent& native_event,
float* x_offset,
float* y_offset,
+ float* x_offset_ordinal,
+ float* y_offset_ordinal,
int* finger_count) {
+ NOTIMPLEMENTED();
return false;
}
-bool IsNoopEvent(const base::NativeEvent& event) {
- return ([event type] == NSApplicationDefined && [event subtype] == 0);
+bool GetFlingData(const base::NativeEvent& native_event,
+ float* vx,
+ float* vy,
+ float* vx_ordinal,
+ float* vy_ordinal,
+ bool* is_cancel) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool GetGestureTimes(const base::NativeEvent& native_event,
+ double* start_time,
+ double* end_time) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void SetNaturalScroll(bool enabled) {
+ NOTIMPLEMENTED();
+}
+
+bool IsNaturalScrollEnabled() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool IsTouchpadEvent(const base::NativeEvent& native_event) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
+ return KeyboardCodeFromNSEvent(native_event);
+}
+
+const char* CodeFromNative(const base::NativeEvent& native_event) {
+ return CodeFromNSEvent(native_event);
}
-base::NativeEvent CreateNoopEvent() {
- return [NSEvent otherEventWithType:NSApplicationDefined
- location:NSZeroPoint
- modifierFlags:0
- timestamp:[NSDate timeIntervalSinceReferenceDate]
- windowNumber:0
- context:nil
- subtype:0
- data1:0
- data2:0];
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+ return native_event.keyCode;
}
} // namespace ui
diff --git a/chromium/ui/events/cocoa/events_mac_unittest.mm b/chromium/ui/events/cocoa/events_mac_unittest.mm
new file mode 100644
index 00000000000..77f85495f48
--- /dev/null
+++ b/chromium/ui/events/cocoa/events_mac_unittest.mm
@@ -0,0 +1,315 @@
+// 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/events/event_utils.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#import "ui/events/test/cocoa_test_event_utils.h"
+#include "ui/gfx/point.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
+
+namespace {
+
+NSWindow* g_test_window = nil;
+
+} // namespace
+
+// Mac APIs for creating test events are frustrating. Quartz APIs have, e.g.,
+// CGEventCreateMouseEvent() which can't set a window or modifier flags.
+// Cocoa APIs have +[NSEvent mouseEventWithType:..] which can't set
+// buttonNumber or scroll deltas. To work around this, these tests use some
+// Objective C magic to donate member functions to NSEvent temporarily.
+@interface MiddleMouseButtonNumberDonor : NSObject
+@end
+
+@interface TestWindowDonor : NSObject
+@end
+
+@implementation MiddleMouseButtonNumberDonor
+- (NSUInteger)buttonNumber { return 2; }
+@end
+
+@implementation TestWindowDonor
+- (NSWindow*)window { return g_test_window; }
+@end
+
+namespace ui {
+
+namespace {
+
+class EventsMacTest : public CocoaTest {
+ public:
+ EventsMacTest() {}
+
+ gfx::Point Flip(gfx::Point window_location) {
+ NSRect window_frame = [test_window() frame];
+ CGFloat content_height =
+ NSHeight([test_window() contentRectForFrameRect:window_frame]);
+ window_location.set_y(content_height - window_location.y());
+ return window_location;
+ }
+
+ void SwizzleMiddleMouseButton() {
+ DCHECK(!swizzler_);
+ swizzler_.reset(new ScopedClassSwizzler(
+ [NSEvent class],
+ [MiddleMouseButtonNumberDonor class],
+ @selector(buttonNumber)));
+ }
+
+ void SwizzleTestWindow() {
+ DCHECK(!g_test_window);
+ DCHECK(!swizzler_);
+ g_test_window = test_window();
+ swizzler_.reset(new ScopedClassSwizzler(
+ [NSEvent class],
+ [TestWindowDonor class],
+ @selector(window)));
+ }
+
+ void ClearSwizzle() {
+ swizzler_.reset();
+ g_test_window = nil;
+ }
+
+ NSEvent* TestMouseEvent(NSEventType type,
+ const gfx::Point &window_location,
+ NSInteger modifier_flags) {
+ NSPoint point = NSPointFromCGPoint(Flip(window_location).ToCGPoint());
+ return [NSEvent mouseEventWithType:type
+ location:point
+ modifierFlags:modifier_flags
+ timestamp:0
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:1.0];
+ }
+
+ NSEvent* TestScrollEvent(const gfx::Point& window_location,
+ int32_t delta_x,
+ int32_t delta_y) {
+ SwizzleTestWindow();
+ base::ScopedCFTypeRef<CGEventRef> scroll(
+ CGEventCreateScrollWheelEvent(NULL,
+ kCGScrollEventUnitLine,
+ 2,
+ delta_y,
+ delta_x));
+ // CGEvents are always in global display coordinates. These are like screen
+ // coordinates, but flipped. But first the point needs to be converted out
+ // of window coordinates (which also requires flipping).
+ NSPoint window_point =
+ NSPointFromCGPoint(Flip(window_location).ToCGPoint());
+ NSPoint screen_point = [test_window() convertBaseToScreen:window_point];
+ CGFloat primary_screen_height =
+ NSHeight([[[NSScreen screens] objectAtIndex:0] frame]);
+ screen_point.y = primary_screen_height - screen_point.y;
+ CGEventSetLocation(scroll, NSPointToCGPoint(screen_point));
+ return [NSEvent eventWithCGEvent:scroll];
+ }
+
+ private:
+ scoped_ptr<ScopedClassSwizzler> swizzler_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventsMacTest);
+};
+
+} // namespace
+
+TEST_F(EventsMacTest, EventFlagsFromNative) {
+ // Left click.
+ NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left));
+
+ // Right click.
+ NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp,
+ 0);
+ EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNative(right));
+
+ // Middle click.
+ NSEvent* middle = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp,
+ 0);
+ EXPECT_EQ(EF_MIDDLE_MOUSE_BUTTON, EventFlagsFromNative(middle));
+
+ // Caps + Left
+ NSEvent* caps = cocoa_test_event_utils::MouseEventWithType(
+ NSLeftMouseUp, NSAlphaShiftKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CAPS_LOCK_DOWN,
+ EventFlagsFromNative(caps));
+
+ // Shift + Left
+ NSEvent* shift = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSShiftKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN, EventFlagsFromNative(shift));
+
+ // Ctrl + Left
+ NSEvent* ctrl = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSControlKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CONTROL_DOWN, EventFlagsFromNative(ctrl));
+
+ // Alt + Left
+ NSEvent* alt = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSAlternateKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_ALT_DOWN, EventFlagsFromNative(alt));
+
+ // Cmd + Left
+ NSEvent* cmd = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
+ NSCommandKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN, EventFlagsFromNative(cmd));
+
+ // Shift + Ctrl + Left
+ NSEvent* shiftctrl = cocoa_test_event_utils::MouseEventWithType(
+ NSLeftMouseUp, NSShiftKeyMask | NSControlKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN,
+ EventFlagsFromNative(shiftctrl));
+
+ // Cmd + Alt + Right
+ NSEvent* cmdalt = cocoa_test_event_utils::MouseEventWithType(
+ NSLeftMouseUp, NSCommandKeyMask | NSAlternateKeyMask);
+ EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN,
+ EventFlagsFromNative(cmdalt));
+}
+
+// Tests mouse button presses and mouse wheel events.
+TEST_F(EventsMacTest, ButtonEvents) {
+ gfx::Point location(5, 10);
+ gfx::Vector2d offset;
+
+ NSEvent* event = TestMouseEvent(NSLeftMouseDown, location, 0);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event));
+ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+
+ SwizzleMiddleMouseButton();
+ event = TestMouseEvent(NSOtherMouseDown, location, NSShiftKeyMask);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event));
+ EXPECT_EQ(ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_SHIFT_DOWN,
+ ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+ ClearSwizzle();
+
+ event = TestMouseEvent(NSRightMouseUp, location, 0);
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(event));
+ EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+
+ // Scroll up.
+ event = TestScrollEvent(location, 0, 1);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location.ToString(), ui::EventLocationFromNative(event).ToString());
+ offset = ui::GetMouseWheelOffset(event);
+ EXPECT_GT(offset.y(), 0);
+ EXPECT_EQ(0, offset.x());
+ ClearSwizzle();
+
+ // Scroll down.
+ event = TestScrollEvent(location, 0, -1);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+ offset = ui::GetMouseWheelOffset(event);
+ EXPECT_LT(offset.y(), 0);
+ EXPECT_EQ(0, offset.x());
+ ClearSwizzle();
+
+ // Scroll left.
+ event = TestScrollEvent(location, 1, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+ offset = ui::GetMouseWheelOffset(event);
+ EXPECT_EQ(0, offset.y());
+ EXPECT_GT(offset.x(), 0);
+ ClearSwizzle();
+
+ // Scroll right.
+ event = TestScrollEvent(location, -1, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+ offset = ui::GetMouseWheelOffset(event);
+ EXPECT_EQ(0, offset.y());
+ EXPECT_LT(offset.x(), 0);
+ ClearSwizzle();
+}
+
+// Test correct location when the window has a native titlebar.
+TEST_F(EventsMacTest, NativeTitlebarEventLocation) {
+ gfx::Point location(5, 10);
+ NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask;
+
+ // First check that the window provided by ui::CocoaTest is how we think.
+ DCHECK_EQ(NSBorderlessWindowMask, [test_window() styleMask]);
+ [test_window() setStyleMask:style_mask];
+ DCHECK_EQ(style_mask, [test_window() styleMask]);
+
+ // EventLocationFromNative should behave the same as the ButtonEvents test.
+ NSEvent* event = TestMouseEvent(NSLeftMouseDown, location, 0);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event));
+ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(event));
+
+ // And be explicit, to ensure the test doesn't depend on some property of the
+ // test harness. The change to the frame rect could be OS-specfic, so set it
+ // to a known value.
+ const CGFloat kTestHeight = 400;
+ NSRect content_rect = NSMakeRect(0, 0, 600, kTestHeight);
+ NSRect frame_rect = [test_window() frameRectForContentRect:content_rect];
+ [test_window() setFrame:frame_rect display:YES];
+ event = [NSEvent mouseEventWithType:NSLeftMouseDown
+ location:NSMakePoint(0, 0) // Bottom-left corner.
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:1.0];
+ // Bottom-left corner should be flipped.
+ EXPECT_EQ(gfx::Point(0, kTestHeight), ui::EventLocationFromNative(event));
+
+ // Removing the border, and sending the same event should move it down in the
+ // toolkit-views coordinate system.
+ int height_change = NSHeight(frame_rect) - kTestHeight;
+ EXPECT_GT(height_change, 0);
+ [test_window() setStyleMask:NSBorderlessWindowMask];
+ [test_window() setFrame:frame_rect display:YES];
+ EXPECT_EQ(gfx::Point(0, kTestHeight + height_change),
+ ui::EventLocationFromNative(event));
+}
+
+// Testing for ui::EventTypeFromNative() not covered by ButtonEvents.
+TEST_F(EventsMacTest, EventTypeFromNative) {
+ NSEvent* event = cocoa_test_event_utils::KeyEventWithType(NSKeyDown, 0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, ui::EventTypeFromNative(event));
+
+ event = cocoa_test_event_utils::KeyEventWithType(NSKeyUp, 0);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, ui::EventTypeFromNative(event));
+
+ event = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseDragged, 0);
+ EXPECT_EQ(ui::ET_MOUSE_DRAGGED, ui::EventTypeFromNative(event));
+ event = cocoa_test_event_utils::MouseEventWithType(NSRightMouseDragged, 0);
+ EXPECT_EQ(ui::ET_MOUSE_DRAGGED, ui::EventTypeFromNative(event));
+ event = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseDragged, 0);
+ EXPECT_EQ(ui::ET_MOUSE_DRAGGED, ui::EventTypeFromNative(event));
+
+ event = cocoa_test_event_utils::MouseEventWithType(NSMouseMoved, 0);
+ EXPECT_EQ(ui::ET_MOUSE_MOVED, ui::EventTypeFromNative(event));
+
+ event = cocoa_test_event_utils::EnterExitEventWithType(NSMouseEntered);
+ EXPECT_EQ(ui::ET_MOUSE_ENTERED, ui::EventTypeFromNative(event));
+ event = cocoa_test_event_utils::EnterExitEventWithType(NSMouseExited);
+ EXPECT_EQ(ui::ET_MOUSE_EXITED, ui::EventTypeFromNative(event));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc
index 246e39721f2..ed7ff3adaea 100644
--- a/chromium/ui/events/event.cc
+++ b/chromium/ui/events/event.cc
@@ -5,6 +5,7 @@
#include "ui/events/event.h"
#if defined(USE_X11)
+#include <X11/extensions/XInput2.h>
#include <X11/Xlib.h>
#endif
@@ -28,24 +29,6 @@
namespace {
-base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
-#if defined(USE_X11)
- if (!event || event->type == GenericEvent)
- return NULL;
- XEvent* copy = new XEvent;
- *copy = *event;
- return copy;
-#elif defined(OS_WIN)
- return event;
-#elif defined(USE_OZONE)
- return NULL;
-#else
- NOTREACHED() <<
- "Don't know how to copy base::NativeEvent for this platform";
- return NULL;
-#endif
-}
-
std::string EventTypeName(ui::EventType type) {
#define RETURN_IF_TYPE(t) if (type == ui::t) return #t
#define CASE_TYPE(t) case ui::t: return #t
@@ -64,7 +47,6 @@ std::string EventTypeName(ui::EventType type) {
CASE_TYPE(ET_TOUCH_RELEASED);
CASE_TYPE(ET_TOUCH_PRESSED);
CASE_TYPE(ET_TOUCH_MOVED);
- CASE_TYPE(ET_TOUCH_STATIONARY);
CASE_TYPE(ET_TOUCH_CANCELLED);
CASE_TYPE(ET_DROP_TARGET_EVENT);
CASE_TYPE(ET_TRANSLATED_KEY_PRESS);
@@ -73,6 +55,7 @@ std::string EventTypeName(ui::EventType type) {
CASE_TYPE(ET_GESTURE_SCROLL_END);
CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
CASE_TYPE(ET_GESTURE_SHOW_PRESS);
+ CASE_TYPE(ET_GESTURE_WIN8_EDGE_SWIPE);
CASE_TYPE(ET_GESTURE_TAP);
CASE_TYPE(ET_GESTURE_TAP_DOWN);
CASE_TYPE(ET_GESTURE_TAP_CANCEL);
@@ -84,7 +67,9 @@ std::string EventTypeName(ui::EventType type) {
CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
CASE_TYPE(ET_GESTURE_LONG_PRESS);
CASE_TYPE(ET_GESTURE_LONG_TAP);
- CASE_TYPE(ET_GESTURE_MULTIFINGER_SWIPE);
+ CASE_TYPE(ET_GESTURE_SWIPE);
+ CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
+ CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
CASE_TYPE(ET_SCROLL);
CASE_TYPE(ET_SCROLL_FLING_START);
CASE_TYPE(ET_SCROLL_FLING_CANCEL);
@@ -101,10 +86,22 @@ std::string EventTypeName(ui::EventType type) {
bool IsX11SendEventTrue(const base::NativeEvent& event) {
#if defined(USE_X11)
- if (event && event->xany.send_event)
- return true;
+ return event && event->xany.send_event;
+#else
+ return false;
#endif
+}
+
+bool X11EventHasNonStandardState(const base::NativeEvent& event) {
+#if defined(USE_X11)
+ const unsigned int kAllStateMask =
+ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask |
+ Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask |
+ LockMask | ControlMask | AnyModifier;
+ return event && (event->xkey.state & ~kAllStateMask) != 0;
+#else
return false;
+#endif
}
} // namespace
@@ -115,10 +112,8 @@ namespace ui {
// Event
Event::~Event() {
-#if defined(USE_X11)
if (delete_native_event_)
- delete native_event_;
-#endif
+ ReleaseCopiedNativeEvent(native_event_);
}
bool Event::HasNativeEvent() const {
@@ -147,9 +142,7 @@ Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
: type_(type),
time_stamp_(time_stamp),
flags_(flags),
-#if defined(USE_X11)
- native_event_(NULL),
-#endif
+ native_event_(base::NativeEvent()),
delete_native_event_(false),
cancelable_(true),
target_(NULL),
@@ -157,7 +150,6 @@ Event::Event(EventType type, base::TimeDelta time_stamp, int flags)
result_(ER_UNHANDLED) {
if (type_ < ET_LAST)
name_ = EventTypeName(type_);
- Init();
}
Event::Event(const base::NativeEvent& native_event,
@@ -166,6 +158,7 @@ Event::Event(const base::NativeEvent& native_event,
: type_(type),
time_stamp_(EventTimeFromNative(native_event)),
flags_(flags),
+ native_event_(native_event),
delete_native_event_(false),
cancelable_(true),
target_(NULL),
@@ -175,18 +168,17 @@ Event::Event(const base::NativeEvent& native_event,
if (type_ < ET_LAST)
name_ = EventTypeName(type_);
UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser",
- delta.InMicroseconds(), 0, 1000000, 100);
+ delta.InMicroseconds(), 1, 1000000, 100);
std::string name_for_event =
base::StringPrintf("Event.Latency.Browser.%s", name_.c_str());
base::HistogramBase* counter_for_type =
base::Histogram::FactoryGet(
name_for_event,
- 0,
+ 1,
1000000,
100,
base::HistogramBase::kUmaTargetedHistogramFlag);
counter_for_type->Add(delta.InMicroseconds());
- InitWithNativeEvent(native_event);
}
Event::Event(const Event& copy)
@@ -194,18 +186,14 @@ Event::Event(const Event& copy)
time_stamp_(copy.time_stamp_),
latency_(copy.latency_),
flags_(copy.flags_),
- native_event_(::CopyNativeEvent(copy.native_event_)),
- delete_native_event_(false),
+ native_event_(CopyNativeEvent(copy.native_event_)),
+ delete_native_event_(true),
cancelable_(true),
target_(NULL),
phase_(EP_PREDISPATCH),
result_(ER_UNHANDLED) {
if (type_ < ET_LAST)
name_ = EventTypeName(type_);
-#if defined(USE_X11)
- if (native_event_)
- delete_native_event_ = true;
-#endif
}
void Event::SetType(EventType type) {
@@ -216,14 +204,6 @@ void Event::SetType(EventType type) {
name_ = EventTypeName(type_);
}
-void Event::Init() {
- std::memset(&native_event_, 0, sizeof(native_event_));
-}
-
-void Event::InitWithNativeEvent(const base::NativeEvent& native_event) {
- native_event_ = native_event;
-}
-
////////////////////////////////////////////////////////////////////////////////
// CancelModeEvent
@@ -250,8 +230,8 @@ LocatedEvent::LocatedEvent(const base::NativeEvent& native_event)
}
LocatedEvent::LocatedEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
+ const gfx::PointF& location,
+ const gfx::PointF& root_location,
base::TimeDelta time_stamp,
int flags)
: Event(type, time_stamp, flags),
@@ -264,7 +244,8 @@ void LocatedEvent::UpdateForRootTransform(
// Transform has to be done at root level.
gfx::Point3F p(location_);
reversed_root_transform.TransformPoint(&p);
- root_location_ = location_ = gfx::ToFlooredPoint(p.AsPointF());
+ location_ = p.AsPointF();
+ root_location_ = location_;
}
////////////////////////////////////////////////////////////////////////////////
@@ -279,11 +260,12 @@ MouseEvent::MouseEvent(const base::NativeEvent& native_event)
}
MouseEvent::MouseEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
- int flags)
+ const gfx::PointF& location,
+ const gfx::PointF& root_location,
+ int flags,
+ int changed_button_flags)
: LocatedEvent(type, location, root_location, EventTimeForNow(), flags),
- changed_button_flags_(0) {
+ changed_button_flags_(changed_button_flags) {
if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
SetType(ET_MOUSE_DRAGGED);
}
@@ -311,10 +293,10 @@ bool MouseEvent::IsRepeatedClickEvent(
if (time_difference.InMilliseconds() > kDoubleClickTimeMS)
return false;
- if (abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
+ if (std::abs(event2.x() - event1.x()) > kDoubleClickWidth / 2)
return false;
- if (abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
+ if (std::abs(event2.y() - event1.y()) > kDoubleClickHeight / 2)
return false;
return true;
@@ -324,23 +306,46 @@ bool MouseEvent::IsRepeatedClickEvent(
int MouseEvent::GetRepeatCount(const MouseEvent& event) {
int click_count = 1;
if (last_click_event_) {
- if (event.type() == ui::ET_MOUSE_RELEASED)
- return last_click_event_->GetClickCount();
- if (IsX11SendEventTrue(event.native_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
+ // return a click count of 1.
+ 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))
+ } else 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);
return click_count;
}
+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)
@@ -436,19 +441,25 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event)
radius_x_(GetTouchRadiusX(native_event)),
radius_y_(GetTouchRadiusY(native_event)),
rotation_angle_(GetTouchAngle(native_event)),
- force_(GetTouchForce(native_event)) {
+ force_(GetTouchForce(native_event)),
+ source_device_id_(-1) {
latency()->AddLatencyNumberWithTimestamp(
INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
0,
0,
base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
- 1,
- true);
+ 1);
+
+#if defined(USE_X11)
+ XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+ source_device_id_ = xiev->deviceid;
+#endif
+
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
}
TouchEvent::TouchEvent(EventType type,
- const gfx::Point& location,
+ const gfx::PointF& location,
int touch_id,
base::TimeDelta time_stamp)
: LocatedEvent(type, location, location, time_stamp, 0),
@@ -456,12 +467,13 @@ TouchEvent::TouchEvent(EventType type,
radius_x_(0.0f),
radius_y_(0.0f),
rotation_angle_(0.0f),
- force_(0.0f) {
+ force_(0.0f),
+ source_device_id_(-1) {
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
}
TouchEvent::TouchEvent(EventType type,
- const gfx::Point& location,
+ const gfx::PointF& location,
int flags,
int touch_id,
base::TimeDelta time_stamp,
@@ -474,7 +486,8 @@ TouchEvent::TouchEvent(EventType type,
radius_x_(radius_x),
radius_y_(radius_y),
rotation_angle_(angle),
- force_(force) {
+ force_(force),
+ source_device_id_(-1) {
latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
}
@@ -486,11 +499,6 @@ TouchEvent::~TouchEvent() {
ClearTouchIdIfReleased(native_event());
}
-void TouchEvent::Relocate(const gfx::Point& origin) {
- location_ -= origin.OffsetFromOrigin();
- root_location_ -= origin.OffsetFromOrigin();
-}
-
void TouchEvent::UpdateForRootTransform(
const gfx::Transform& inverted_root_transform) {
LocatedEvent::UpdateForRootTransform(inverted_root_transform);
@@ -506,6 +514,42 @@ void TouchEvent::UpdateForRootTransform(
////////////////////////////////////////////////////////////////////////////////
// KeyEvent
+// static
+KeyEvent* KeyEvent::last_key_event_ = NULL;
+
+// static
+bool KeyEvent::IsRepeated(const KeyEvent& event) {
+ // A safe guard in case if there were continous key pressed events that are
+ // not auto repeat.
+ const int kMaxAutoRepeatTimeMs = 2000;
+ // Ignore key events that have non standard state masks as it may be
+ // reposted by an IME. IBUS-GTK uses this field to detect the
+ // re-posted event for example. crbug.com/385873.
+ if (X11EventHasNonStandardState(event.native_event()))
+ return false;
+ if (event.is_char())
+ return false;
+ if (event.type() == ui::ET_KEY_RELEASED) {
+ delete last_key_event_;
+ last_key_event_ = NULL;
+ return false;
+ }
+ CHECK_EQ(ui::ET_KEY_PRESSED, event.type());
+ if (!last_key_event_) {
+ last_key_event_ = new KeyEvent(event);
+ return false;
+ }
+ if (event.key_code() == last_key_event_->key_code() &&
+ event.flags() == last_key_event_->flags() &&
+ (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() <
+ kMaxAutoRepeatTimeMs) {
+ return true;
+ }
+ delete last_key_event_;
+ last_key_event_ = new KeyEvent(event);
+ return false;
+}
+
KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char)
: Event(native_event,
EventTypeFromNative(native_event),
@@ -513,7 +557,11 @@ KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char)
key_code_(KeyboardCodeFromNative(native_event)),
code_(CodeFromNative(native_event)),
is_char_(is_char),
+ platform_keycode_(PlatformKeycodeFromNative(native_event)),
character_(0) {
+ if (IsRepeated(*this))
+ set_flags(flags() | ui::EF_IS_REPEAT);
+
#if defined(USE_X11)
NormalizeFlags();
#endif
@@ -526,6 +574,7 @@ KeyEvent::KeyEvent(EventType type,
: Event(type, EventTimeForNow(), flags),
key_code_(key_code),
is_char_(is_char),
+ platform_keycode_(0),
character_(GetCharacterFromKeyCode(key_code, flags)) {
}
@@ -538,6 +587,7 @@ KeyEvent::KeyEvent(EventType type,
key_code_(key_code),
code_(code),
is_char_(is_char),
+ platform_keycode_(0),
character_(GetCharacterFromKeyCode(key_code, flags)) {
}
@@ -555,10 +605,13 @@ uint16 KeyEvent::GetCharacter() const {
DCHECK(native_event()->type == KeyPress ||
native_event()->type == KeyRelease);
- uint16 ch = 0;
- if (!IsControlDown())
- ch = GetCharacterFromXEvent(native_event());
- return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
+ // When a control key is held, prefer ASCII characters to non ASCII
+ // characters in order to use it for shortcut keys. GetCharacterFromKeyCode
+ // returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
+ // GetCharacterFromXEvent returns 'à' in that case.
+ return IsControlDown() ?
+ GetCharacterFromKeyCode(key_code_, flags()) :
+ GetCharacterFromXEvent(native_event());
#else
if (native_event()) {
DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
@@ -570,6 +623,7 @@ uint16 KeyEvent::GetCharacter() const {
}
bool KeyEvent::IsUnicodeKeyCode() const {
+#if defined(OS_WIN)
if (!IsAltDown())
return false;
const int key = key_code();
@@ -583,6 +637,9 @@ bool KeyEvent::IsUnicodeKeyCode() const {
key == VKEY_NEXT || key == VKEY_LEFT || key == VKEY_CLEAR ||
key == VKEY_RIGHT || key == VKEY_HOME || key == VKEY_UP ||
key == VKEY_PRIOR));
+#else
+ return false;
+#endif
}
void KeyEvent::NormalizeFlags() {
@@ -609,28 +666,33 @@ void KeyEvent::NormalizeFlags() {
set_flags(flags() & ~mask);
}
-////////////////////////////////////////////////////////////////////////////////
-// TranslatedKeyEvent
-
-TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event,
- bool is_char)
- : KeyEvent(native_event, is_char) {
- SetType(type() == ET_KEY_PRESSED ?
- ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE);
-}
-
-TranslatedKeyEvent::TranslatedKeyEvent(bool is_press,
- KeyboardCode key_code,
- int flags)
- : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE),
- key_code,
- flags,
- false) {
+bool KeyEvent::IsTranslated() const {
+ switch (type()) {
+ case ET_KEY_PRESSED:
+ case ET_KEY_RELEASED:
+ return false;
+ case ET_TRANSLATED_KEY_PRESS:
+ case ET_TRANSLATED_KEY_RELEASE:
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
}
-void TranslatedKeyEvent::ConvertToKeyEvent() {
- SetType(type() == ET_TRANSLATED_KEY_PRESS ?
- ET_KEY_PRESSED : ET_KEY_RELEASED);
+void KeyEvent::SetTranslated(bool translated) {
+ switch (type()) {
+ case ET_KEY_PRESSED:
+ case ET_TRANSLATED_KEY_PRESS:
+ SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
+ break;
+ case ET_KEY_RELEASED:
+ case ET_TRANSLATED_KEY_RELEASE:
+ SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
+ break;
+ default:
+ NOTREACHED();
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -656,7 +718,7 @@ ScrollEvent::ScrollEvent(const base::NativeEvent& native_event)
}
ScrollEvent::ScrollEvent(EventType type,
- const gfx::Point& location,
+ const gfx::PointF& location,
base::TimeDelta time_stamp,
int flags,
float x_offset,
@@ -664,7 +726,7 @@ ScrollEvent::ScrollEvent(EventType type,
float x_offset_ordinal,
float y_offset_ordinal,
int finger_count)
- : MouseEvent(type, location, location, flags),
+ : MouseEvent(type, location, location, flags, 0),
x_offset_(x_offset),
y_offset_(y_offset),
x_offset_ordinal_(x_offset_ordinal),
@@ -685,15 +747,15 @@ void ScrollEvent::Scale(const float factor) {
// GestureEvent
GestureEvent::GestureEvent(EventType type,
- int x,
- int y,
+ float x,
+ float y,
int flags,
base::TimeDelta time_stamp,
const GestureEventDetails& details,
unsigned int touch_ids_bitfield)
: LocatedEvent(type,
- gfx::Point(x, y),
- gfx::Point(x, y),
+ gfx::PointF(x, y),
+ gfx::PointF(x, y),
time_stamp,
flags | EF_FROM_TOUCH),
details_(details),
diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h
index b8a341a2234..9c0c580707b 100644
--- a/chromium/ui/events/event.h
+++ b/chromium/ui/events/event.h
@@ -8,13 +8,16 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/event_types.h"
+#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "ui/events/event_constants.h"
+#include "ui/events/gesture_event_details.h"
#include "ui/events/gestures/gesture_types.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/latency_info.h"
#include "ui/gfx/point.h"
+#include "ui/gfx/point_conversions.h"
namespace gfx {
class Transform;
@@ -79,6 +82,7 @@ class EVENTS_EXPORT Event {
bool IsCapsLockDown() const { return (flags_ & EF_CAPS_LOCK_DOWN) != 0; }
bool IsAltDown() const { return (flags_ & EF_ALT_DOWN) != 0; }
bool IsAltGrDown() const { return (flags_ & EF_ALTGR_DOWN) != 0; }
+ bool IsRepeat() const { return (flags_ & EF_IS_REPEAT) != 0; }
bool IsKeyEvent() const {
return type_ == ET_KEY_PRESSED ||
@@ -102,7 +106,6 @@ class EVENTS_EXPORT Event {
return type_ == ET_TOUCH_RELEASED ||
type_ == ET_TOUCH_PRESSED ||
type_ == ET_TOUCH_MOVED ||
- type_ == ET_TOUCH_STATIONARY ||
type_ == ET_TOUCH_CANCELLED;
}
@@ -122,8 +125,9 @@ class EVENTS_EXPORT Event {
case ET_GESTURE_PINCH_UPDATE:
case ET_GESTURE_LONG_PRESS:
case ET_GESTURE_LONG_TAP:
- case ET_GESTURE_MULTIFINGER_SWIPE:
+ case ET_GESTURE_SWIPE:
case ET_GESTURE_SHOW_PRESS:
+ case ET_GESTURE_WIN8_EDGE_SWIPE:
// When adding a gesture event which is paired with an event which
// occurs earlier, add the event to |IsEndingEvent|.
return true;
@@ -216,10 +220,6 @@ class EVENTS_EXPORT Event {
private:
friend class EventTestApi;
- // Safely initializes the native event members of this class.
- void Init();
- void InitWithNativeEvent(const base::NativeEvent& native_event);
-
EventType type_;
std::string name_;
base::TimeDelta time_stamp_;
@@ -243,14 +243,22 @@ class EVENTS_EXPORT LocatedEvent : public Event {
public:
virtual ~LocatedEvent();
- int x() const { return location_.x(); }
- int y() const { return location_.y(); }
- void set_location(const gfx::Point& location) { location_ = location; }
- gfx::Point location() const { return location_; }
- void set_root_location(const gfx::Point& root_location) {
+ float x() const { return location_.x(); }
+ float y() const { return location_.y(); }
+ void set_location(const gfx::PointF& location) { location_ = location; }
+ // TODO(tdresser): Always return floating point location. See
+ // crbug.com/337824.
+ gfx::Point location() const { return gfx::ToFlooredPoint(location_); }
+ const gfx::PointF& location_f() const { return location_; }
+ void set_root_location(const gfx::PointF& root_location) {
root_location_ = root_location;
}
- gfx::Point root_location() const { return root_location_; }
+ gfx::Point root_location() const {
+ return gfx::ToFlooredPoint(root_location_);
+ }
+ const gfx::PointF& root_location_f() const {
+ return root_location_;
+ }
// Transform the locations using |inverted_root_transform|.
// This is applied to both |location_| and |root_location_|.
@@ -258,8 +266,14 @@ class EVENTS_EXPORT LocatedEvent : public Event {
const gfx::Transform& inverted_root_transform);
template <class T> void ConvertLocationToTarget(T* source, T* target) {
- if (target && target != source)
- T::ConvertPointToTarget(source, target, &location_);
+ if (!target || target == source)
+ return;
+ // TODO(tdresser): Rewrite ConvertPointToTarget to use PointF. See
+ // crbug.com/337824.
+ gfx::Point offset = gfx::ToFlooredPoint(location_);
+ T::ConvertPointToTarget(source, target, &offset);
+ gfx::Vector2d diff = gfx::ToFlooredPoint(location_) - offset;
+ location_= location_ - diff;
}
protected:
@@ -279,16 +293,16 @@ class EVENTS_EXPORT LocatedEvent : public Event {
// Used for synthetic events in testing.
LocatedEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
+ const gfx::PointF& location,
+ const gfx::PointF& root_location,
base::TimeDelta time_stamp,
int flags);
- gfx::Point location_;
+ gfx::PointF location_;
// |location_| multiplied by an optional transformation matrix for
// rotations, animations and skews.
- gfx::Point root_location_;
+ gfx::PointF root_location_;
};
class EVENTS_EXPORT MouseEvent : public LocatedEvent {
@@ -319,9 +333,10 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
// Used for synthetic events in testing and by the gesture recognizer.
MouseEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
- int flags);
+ const gfx::PointF& location,
+ const gfx::PointF& root_location,
+ int flags,
+ int changed_button_flags);
// Conveniences to quickly test what button is down
bool IsOnlyLeftMouseButton() const {
@@ -376,14 +391,25 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
int changed_button_flags() const { return changed_button_flags_; }
private:
+ FRIEND_TEST_ALL_PREFIXES(EventTest, DoubleClickRequiresRelease);
+ FRIEND_TEST_ALL_PREFIXES(EventTest, SingleClickRightLeft);
+
// Returns the repeat count based on the previous mouse click, if it is
// recent enough and within a small enough distance.
static int GetRepeatCount(const MouseEvent& click_event);
+ // Resets the last_click_event_ for unit tests.
+ static void ResetLastClickForTest();
+
// See description above getter for details.
int changed_button_flags_;
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_;
};
class ScrollEvent;
@@ -401,11 +427,9 @@ class EVENTS_EXPORT MouseWheelEvent : public MouseEvent {
template <class T>
MouseWheelEvent(const MouseWheelEvent& model,
T* source,
- T* target,
- EventType type,
- int flags)
- : MouseEvent(model, source, target, type, flags),
- offset_(model.x_offset(), model.y_offset()){
+ T* target)
+ : MouseEvent(model, source, target, model.type(), model.flags()),
+ offset_(model.x_offset(), model.y_offset()) {
}
// The amount to scroll. This is in multiples of kWheelDelta.
@@ -436,16 +460,17 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
radius_x_(model.radius_x_),
radius_y_(model.radius_y_),
rotation_angle_(model.rotation_angle_),
- force_(model.force_) {
+ force_(model.force_),
+ source_device_id_(model.source_device_id_) {
}
TouchEvent(EventType type,
- const gfx::Point& root_location,
+ const gfx::PointF& location,
int touch_id,
base::TimeDelta time_stamp);
TouchEvent(EventType type,
- const gfx::Point& location,
+ const gfx::PointF& location,
int flags,
int touch_id,
base::TimeDelta timestamp,
@@ -461,15 +486,14 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
float radius_y() const { return radius_y_; }
float rotation_angle() const { return rotation_angle_; }
float force() const { return force_; }
-
- // Relocate the touch-point to a new |origin|.
- // This is useful when touch event is in X Root Window coordinates,
- // and it needs to be mapped into Aura Root Window coordinates.
- void Relocate(const gfx::Point& origin);
+ int source_device_id() const { return source_device_id_; }
// Used for unit tests.
void set_radius_x(const float r) { radius_x_ = r; }
void set_radius_y(const float r) { radius_y_ = r; }
+ void set_source_device_id(int source_device_id) {
+ source_device_id_ = source_device_id;
+ }
// Overridden from LocatedEvent.
virtual void UpdateForRootTransform(
@@ -503,6 +527,9 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
// Force (pressure) of the touch. Normalized to be [0, 1]. Default to be 0.0.
float force_;
+
+ // The device id of the screen the event came from. Default to be -1.
+ int source_device_id_;
};
class EVENTS_EXPORT KeyEvent : public Event {
@@ -526,6 +553,8 @@ class EVENTS_EXPORT KeyEvent : public Event {
// BMP characters.
uint16 GetCharacter() const;
+ // Gets the platform key code. For XKB, this is the xksym value.
+ uint32 platform_keycode() const { return platform_keycode_; }
KeyboardCode key_code() const { return key_code_; }
bool is_char() const { return is_char_; }
@@ -545,6 +574,16 @@ class EVENTS_EXPORT KeyEvent : public Event {
// in http://crbug.com/127142#c8, the normalization is necessary.
void NormalizeFlags();
+ // Returns true if the key event has already been processed by an input method
+ // and there is no need to pass the key event to the input method again.
+ bool IsTranslated() const;
+ // Marks this key event as translated or not translated.
+ void SetTranslated(bool translated);
+
+ protected:
+ // This allows a subclass TranslatedKeyEvent to be a non character event.
+ void set_is_char(bool is_char) { is_char_ = is_char; }
+
private:
KeyboardCode key_code_;
@@ -559,28 +598,21 @@ class EVENTS_EXPORT KeyEvent : public Event {
// share the same type: ET_KEY_PRESSED.
bool is_char_;
- uint16 character_;
-};
-
-// A key event which is translated by an input method (IME).
-// For example, if an IME receives a KeyEvent(VKEY_SPACE), and it does not
-// consume the key, the IME usually generates and dispatches a
-// TranslatedKeyEvent(VKEY_SPACE) event. If the IME receives a KeyEvent and
-// it does consume the event, it might dispatch a
-// TranslatedKeyEvent(VKEY_PROCESSKEY) event as defined in the DOM spec.
-class EVENTS_EXPORT TranslatedKeyEvent : public KeyEvent {
- public:
- TranslatedKeyEvent(const base::NativeEvent& native_event, bool is_char);
+ // The platform related keycode value. For XKB, it's keysym value.
+ // For now, this is used for CharacterComposer in ChromeOS.
+ uint32 platform_keycode_;
- // Used for synthetic events such as a VKEY_PROCESSKEY key event.
- TranslatedKeyEvent(bool is_press, KeyboardCode key_code, int flags);
+ // String of 'key' defined in DOM KeyboardEvent (e.g. 'a', 'â')
+ // http://www.w3.org/TR/uievents/#keyboard-key-codes.
+ //
+ // This value represents the text that the key event will insert to input
+ // field. For key with modifier key, it may have specifial text.
+ // e.g. CTRL+A has '\x01'.
+ uint16 character_;
- // Changes the type() of the object from ET_TRANSLATED_KEY_* to ET_KEY_* so
- // that RenderWidgetHostViewAura and NativeWidgetAura could handle the event.
- void ConvertToKeyEvent();
+ static bool IsRepeated(const KeyEvent& event);
- private:
- DISALLOW_COPY_AND_ASSIGN(TranslatedKeyEvent);
+ static KeyEvent* last_key_event_;
};
class EVENTS_EXPORT ScrollEvent : public MouseEvent {
@@ -600,7 +632,7 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
// Used for tests.
ScrollEvent(EventType type,
- const gfx::Point& location,
+ const gfx::PointF& location,
base::TimeDelta time_stamp,
int flags,
float x_offset,
@@ -634,8 +666,8 @@ class EVENTS_EXPORT ScrollEvent : public MouseEvent {
class EVENTS_EXPORT GestureEvent : public LocatedEvent {
public:
GestureEvent(EventType type,
- int x,
- int y,
+ float x,
+ float y,
int flags,
base::TimeDelta time_stamp,
const GestureEventDetails& details,
diff --git a/chromium/ui/events/event_constants.h b/chromium/ui/events/event_constants.h
index 2a545b740ae..d2ff97c7aec 100644
--- a/chromium/ui/events/event_constants.h
+++ b/chromium/ui/events/event_constants.h
@@ -23,7 +23,6 @@ enum EventType {
ET_TOUCH_RELEASED,
ET_TOUCH_PRESSED,
ET_TOUCH_MOVED,
- ET_TOUCH_STATIONARY,
ET_TOUCH_CANCELLED,
ET_DROP_TARGET_EVENT,
ET_TRANSLATED_KEY_PRESS,
@@ -31,29 +30,37 @@ enum EventType {
// GestureEvent types
ET_GESTURE_SCROLL_BEGIN,
+ ET_GESTURE_TYPE_START = ET_GESTURE_SCROLL_BEGIN,
ET_GESTURE_SCROLL_END,
ET_GESTURE_SCROLL_UPDATE,
ET_GESTURE_TAP,
ET_GESTURE_TAP_DOWN,
ET_GESTURE_TAP_CANCEL,
- ET_GESTURE_BEGIN, // Sent before any other gesture types.
- ET_GESTURE_END, // Sent after any other gestures.
+ ET_GESTURE_TAP_UNCONFIRMED, // User tapped, but the tap delay hasn't expired.
+ ET_GESTURE_DOUBLE_TAP,
+ ET_GESTURE_BEGIN, // The first event sent when each finger is pressed.
+ ET_GESTURE_END, // Sent for each released finger.
ET_GESTURE_TWO_FINGER_TAP,
ET_GESTURE_PINCH_BEGIN,
ET_GESTURE_PINCH_END,
ET_GESTURE_PINCH_UPDATE,
ET_GESTURE_LONG_PRESS,
ET_GESTURE_LONG_TAP,
- // A SWIPE gesture can happen at the end of a TAP_UP gesture if the
- // finger(s) were moving quickly before they are released.
- ET_GESTURE_MULTIFINGER_SWIPE,
+ // A SWIPE gesture can happen at the end of a touch sequence involving one or
+ // more fingers if the finger velocity was high enough when the first finger
+ // was released.
+ ET_GESTURE_SWIPE,
ET_GESTURE_SHOW_PRESS,
+ // Sent by Win8+ metro when the user swipes from the bottom or top.
+ ET_GESTURE_WIN8_EDGE_SWIPE,
+
// Scroll support.
// TODO[davemoore] we need to unify these events w/ touch and gestures.
ET_SCROLL,
ET_SCROLL_FLING_START,
ET_SCROLL_FLING_CANCEL,
+ ET_GESTURE_TYPE_END = ET_SCROLL_FLING_CANCEL,
// Sent by the system to indicate any modal type operations, such as drag and
// drop or menus, should stop.
@@ -78,19 +85,34 @@ enum EventFlags {
EF_LEFT_MOUSE_BUTTON = 1 << 4,
EF_MIDDLE_MOUSE_BUTTON = 1 << 5,
EF_RIGHT_MOUSE_BUTTON = 1 << 6,
- EF_COMMAND_DOWN = 1 << 7, // Only useful on OSX
+ EF_COMMAND_DOWN = 1 << 7, // GUI Key (e.g. Command on OS X keyboards,
+ // Search on Chromebook keyboards,
+ // Windows on MS-oriented keyboards)
EF_EXTENDED = 1 << 8, // Windows extended key (see WM_KEYDOWN doc)
EF_IS_SYNTHESIZED = 1 << 9,
EF_ALTGR_DOWN = 1 << 10,
+ EF_MOD3_DOWN = 1 << 11,
+};
+
+// Flags specific to key events
+enum KeyEventFlags {
+ EF_NUMPAD_KEY = 1 << 16, // Key originates from number pad (Xkb only)
+ EF_IME_FABRICATED_KEY = 1 << 17, // Key event fabricated by the underlying
+ // IME without a user action.
+ // (Linux X11 only)
+ EF_IS_REPEAT = 1 << 18,
+ EF_FUNCTION_KEY = 1 << 19, // Key originates from function key row
};
// Flags specific to mouse events
enum MouseEventFlags {
- EF_IS_DOUBLE_CLICK = 1 << 16,
- EF_IS_TRIPLE_CLICK = 1 << 17,
- EF_IS_NON_CLIENT = 1 << 18,
- EF_FROM_TOUCH = 1 << 19, // Indicates this mouse event is generated
- // from an unconsumed touch/gesture event.
+ EF_IS_DOUBLE_CLICK = 1 << 16,
+ EF_IS_TRIPLE_CLICK = 1 << 17,
+ EF_IS_NON_CLIENT = 1 << 18,
+ EF_FROM_TOUCH = 1 << 19, // Indicates this mouse event is generated
+ // from an unconsumed touch/gesture event.
+ EF_TOUCH_ACCESSIBILITY = 1 << 20, // Indicates this event was generated from
+ // touch accessibility mode.
};
// Result of dispatching an event.
diff --git a/chromium/ui/events/event_dispatcher.cc b/chromium/ui/events/event_dispatcher.cc
index a1fbafa79c0..ca24cde3ff0 100644
--- a/chromium/ui/events/event_dispatcher.cc
+++ b/chromium/ui/events/event_dispatcher.cc
@@ -51,11 +51,18 @@ EventDispatchDetails EventDispatcherDelegate::DispatchEvent(EventTarget* target,
dispatch_helper.set_result(ER_UNHANDLED);
EventDispatchDetails details = PreDispatchEvent(target, event);
- if (!event->handled() && !details.dispatcher_destroyed)
+ if (!event->handled() &&
+ !details.dispatcher_destroyed &&
+ !details.target_destroyed) {
details = DispatchEventToTarget(target, event);
- if (!details.dispatcher_destroyed)
- details = PostDispatchEvent(target, *event);
+ }
+ bool target_destroyed_during_dispatch = details.target_destroyed;
+ if (!details.dispatcher_destroyed) {
+ details = PostDispatchEvent(target_destroyed_during_dispatch ?
+ NULL : target, *event);
+ }
+ details.target_destroyed |= target_destroyed_during_dispatch;
return details;
}
@@ -81,7 +88,11 @@ EventDispatchDetails EventDispatcherDelegate::DispatchEventToTarget(
else if (old_dispatcher)
old_dispatcher->OnDispatcherDelegateDestroyed();
- return dispatcher.details();
+ EventDispatchDetails details;
+ details.dispatcher_destroyed = dispatcher.delegate_destroyed();
+ details.target_destroyed =
+ (!details.dispatcher_destroyed && !CanDispatchToTarget(target));
+ return details;
}
////////////////////////////////////////////////////////////////////////////////
@@ -128,14 +139,9 @@ void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
return;
}
- if (!delegate_)
+ if (!delegate_ || !delegate_->CanDispatchToTarget(target))
return;
- if (!delegate_->CanDispatchToTarget(target)) {
- details_.target_destroyed = true;
- return;
- }
-
handler_list_.clear();
target->GetPostTargetHandlers(&handler_list_);
dispatch_helper.set_phase(EP_POSTTARGET);
@@ -143,7 +149,6 @@ void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
}
void EventDispatcher::OnDispatcherDelegateDestroyed() {
- details_.dispatcher_destroyed = true;
delegate_ = NULL;
}
@@ -175,7 +180,6 @@ void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
// If the target has been invalidated or deleted, don't dispatch the event.
if (!delegate_->CanDispatchToTarget(event->target())) {
- details_.target_destroyed = true;
if (event->cancelable())
event->StopPropagation();
return;
diff --git a/chromium/ui/events/event_dispatcher.h b/chromium/ui/events/event_dispatcher.h
index 9f3a450e76e..a8c985e6813 100644
--- a/chromium/ui/events/event_dispatcher.h
+++ b/chromium/ui/events/event_dispatcher.h
@@ -54,6 +54,7 @@ class EVENTS_EXPORT EventDispatcherDelegate {
Event* event) WARN_UNUSED_RESULT;
// This is called right after the event dispatch is completed.
+ // |target| is NULL if the target was deleted during dispatch.
virtual EventDispatchDetails PostDispatchEvent(
EventTarget* target,
const Event& event) WARN_UNUSED_RESULT;
@@ -80,7 +81,6 @@ class EVENTS_EXPORT EventDispatcher {
Event* current_event() { return current_event_; }
bool delegate_destroyed() const { return !delegate_; }
- const EventDispatchDetails& details() const { return details_; }
void OnHandlerDestroyed(EventHandler* handler);
void OnDispatcherDelegateDestroyed();
@@ -99,8 +99,6 @@ class EVENTS_EXPORT EventDispatcher {
EventHandlerList handler_list_;
- EventDispatchDetails details_;
-
DISALLOW_COPY_AND_ASSIGN(EventDispatcher);
};
diff --git a/chromium/ui/events/event_dispatcher_unittest.cc b/chromium/ui/events/event_dispatcher_unittest.cc
index 30bbd0dd997..248784a8870 100644
--- a/chromium/ui/events/event_dispatcher_unittest.cc
+++ b/chromium/ui/events/event_dispatcher_unittest.cc
@@ -209,10 +209,8 @@ class TestEventDispatcher : public EventDispatcherDelegate {
virtual ~TestEventDispatcher() {}
- void ProcessEvent(EventTarget* target, Event* event) {
- EventDispatchDetails details = DispatchEvent(target, event);
- if (details.dispatcher_destroyed)
- return;
+ EventDispatchDetails ProcessEvent(EventTarget* target, Event* event) {
+ return DispatchEvent(target, event);
}
private:
@@ -258,7 +256,7 @@ TEST(EventDispatcherTest, EventDispatchOrder) {
h8.set_expect_post_target(true);
MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4),
- gfx::Point(3, 4), 0);
+ gfx::Point(3, 4), 0, 0);
Event::DispatcherApi event_mod(&mouse);
dispatcher.ProcessEvent(&child, &mouse);
EXPECT_FALSE(mouse.stopped_propagation());
@@ -332,7 +330,7 @@ TEST(EventDispatcherTest, EventDispatchPhase) {
handler.set_expect_post_target(true);
MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4),
- gfx::Point(3, 4), 0);
+ gfx::Point(3, 4), 0, 0);
Event::DispatcherApi event_mod(&mouse);
dispatcher.ProcessEvent(&target, &mouse);
EXPECT_EQ(ER_UNHANDLED, mouse.result());
@@ -364,9 +362,9 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
h2.set_expect_pre_target(false);
MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4),
- gfx::Point(3, 4), 0);
- Event::DispatcherApi event_mod(&mouse);
- dispatcher->ProcessEvent(&target, &mouse);
+ gfx::Point(3, 4), 0, 0);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &mouse);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_EQ(ER_CONSUMED, mouse.result());
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
@@ -391,8 +389,8 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
h2.set_expect_pre_target(false);
NonCancelableEvent event;
- Event::DispatcherApi event_mod(&event);
- dispatcher->ProcessEvent(&target, &event);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &event);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
@@ -416,9 +414,9 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
h2.set_expect_post_target(false);
MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4),
- gfx::Point(3, 4), 0);
- Event::DispatcherApi event_mod(&mouse);
- dispatcher->ProcessEvent(&target, &mouse);
+ gfx::Point(3, 4), 0, 0);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &mouse);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_EQ(ER_CONSUMED, mouse.result());
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
@@ -443,8 +441,8 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
h2.set_expect_post_target(false);
NonCancelableEvent event;
- Event::DispatcherApi event_mod(&event);
- dispatcher->ProcessEvent(&target, &event);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &event);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
@@ -469,8 +467,11 @@ TEST(EventDispatcherTest, EventDispatcherInvalidateTarget) {
// |h3| should not receive events as the target will be invalidated.
h3.set_expect_pre_target(false);
- MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0);
- dispatcher.ProcessEvent(&target, &mouse);
+ MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0,
+ 0);
+ EventDispatchDetails details = dispatcher.ProcessEvent(&target, &mouse);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_TRUE(details.target_destroyed);
EXPECT_FALSE(target.valid());
EXPECT_TRUE(mouse.stopped_propagation());
EXPECT_EQ(2U, target.handler_list().size());
@@ -480,9 +481,10 @@ TEST(EventDispatcherTest, EventDispatcherInvalidateTarget) {
// Test for non-cancelable event.
target.Reset();
NonCancelableEvent event;
- dispatcher.ProcessEvent(&target, &event);
+ details = dispatcher.ProcessEvent(&target, &event);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_TRUE(details.target_destroyed);
EXPECT_FALSE(target.valid());
- EXPECT_TRUE(mouse.stopped_propagation());
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
@@ -508,8 +510,11 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
// destroyed it.
h3->set_expect_pre_target(false);
- MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0);
- dispatcher.ProcessEvent(&target, &mouse);
+ MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0,
+ 0);
+ EventDispatchDetails details = dispatcher.ProcessEvent(&target, &mouse);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
EXPECT_FALSE(mouse.stopped_propagation());
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
@@ -533,7 +538,9 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
h3->set_expect_pre_target(false);
NonCancelableEvent event;
- dispatcher.ProcessEvent(&target, &event);
+ EventDispatchDetails details = dispatcher.ProcessEvent(&target, &event);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
@@ -561,8 +568,10 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
// it.
h3->set_expect_pre_target(false);
- MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0);
- dispatcher->ProcessEvent(&target, &mouse);
+ MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(3, 4), gfx::Point(3, 4), 0,
+ 0);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &mouse);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_TRUE(mouse.stopped_propagation());
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
@@ -589,7 +598,8 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
h3->set_expect_pre_target(false);
NonCancelableEvent event;
- dispatcher->ProcessEvent(&target, &event);
+ EventDispatchDetails details = dispatcher->ProcessEvent(&target, &event);
+ EXPECT_TRUE(details.dispatcher_destroyed);
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
diff --git a/chromium/ui/events/event_processor.cc b/chromium/ui/events/event_processor.cc
index 1a50d2b7411..3077cc85b16 100644
--- a/chromium/ui/events/event_processor.cc
+++ b/chromium/ui/events/event_processor.cc
@@ -14,12 +14,22 @@ EventDispatchDetails EventProcessor::OnEventFromSource(Event* event) {
CHECK(root);
EventTargeter* targeter = root->GetEventTargeter();
CHECK(targeter);
+
PrepareEventForDispatch(event);
EventTarget* target = targeter->FindTargetForEvent(root, event);
- if (!target)
- return EventDispatchDetails();
- return DispatchEvent(target, event);
+ while (target) {
+ EventDispatchDetails details = DispatchEvent(target, event);
+ if (details.dispatcher_destroyed ||
+ details.target_destroyed ||
+ event->handled()) {
+ return details;
+ }
+
+ target = targeter->FindNextBestTarget(target, event);
+ }
+
+ return EventDispatchDetails();
}
void EventProcessor::PrepareEventForDispatch(Event* event) {
diff --git a/chromium/ui/events/event_processor.h b/chromium/ui/events/event_processor.h
index 34c973054d5..4ce1ef0522e 100644
--- a/chromium/ui/events/event_processor.h
+++ b/chromium/ui/events/event_processor.h
@@ -20,7 +20,9 @@ class EVENTS_EXPORT EventProcessor : public EventDispatcherDelegate {
virtual EventTarget* GetRootTarget() = 0;
// Dispatches an event received from the EventSource to the tree of
- // EventTargets (whose root is returned by GetRootTarget()).
+ // EventTargets (whose root is returned by GetRootTarget()). The co-ordinate
+ // space of the source must be the same as the root target, except that the
+ // target may have a high-dpi scale applied.
virtual EventDispatchDetails OnEventFromSource(Event* event)
WARN_UNUSED_RESULT;
diff --git a/chromium/ui/events/event_processor_unittest.cc b/chromium/ui/events/event_processor_unittest.cc
index 841cdb75038..048a4cdeae9 100644
--- a/chromium/ui/events/event_processor_unittest.cc
+++ b/chromium/ui/events/event_processor_unittest.cc
@@ -2,12 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <vector>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/event_targeter.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"
+typedef std::vector<std::string> HandlerSequenceRecorder;
+
namespace ui {
namespace test {
@@ -41,7 +47,7 @@ TEST_F(EventProcessorTest, Basic) {
root()->AddChild(child.Pass());
MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
- EF_NONE);
+ EF_NONE, EF_NONE);
DispatchEvent(&mouse);
EXPECT_TRUE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
@@ -130,7 +136,8 @@ TEST_F(EventProcessorTest, Bounds) {
// Dispatch a mouse event that falls on the parent, but not on the child. When
// the default event-targeter used, the event will still reach |grandchild|,
// because the default targeter does not look at the bounds.
- MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1), EF_NONE);
+ MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1), EF_NONE,
+ EF_NONE);
DispatchEvent(&mouse);
EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
EXPECT_FALSE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
@@ -141,9 +148,11 @@ TEST_F(EventProcessorTest, Bounds) {
// Now install a targeter on the parent that looks at the bounds and makes
// sure the event reaches the target only if the location of the event within
// the bounds of the target.
+ MouseEvent mouse2(ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1), EF_NONE,
+ EF_NONE);
parent_r->SetEventTargeter(scoped_ptr<EventTargeter>(
new BoundsEventTargeter<BoundsTestTarget>()));
- DispatchEvent(&mouse);
+ DispatchEvent(&mouse2);
EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
EXPECT_TRUE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
EXPECT_FALSE(child_r->DidReceiveEvent(ET_MOUSE_MOVED));
@@ -151,7 +160,7 @@ TEST_F(EventProcessorTest, Bounds) {
parent_r->ResetReceivedEvents();
MouseEvent second(ET_MOUSE_MOVED, gfx::Point(12, 12), gfx::Point(12, 12),
- EF_NONE);
+ EF_NONE, EF_NONE);
DispatchEvent(&second);
EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
EXPECT_FALSE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
@@ -159,5 +168,207 @@ TEST_F(EventProcessorTest, Bounds) {
EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_MOUSE_MOVED));
}
+class IgnoreEventTargeter : public EventTargeter {
+ public:
+ IgnoreEventTargeter() {}
+ virtual ~IgnoreEventTargeter() {}
+
+ private:
+ // EventTargeter:
+ virtual bool SubtreeShouldBeExploredForEvent(
+ EventTarget* target, const LocatedEvent& event) OVERRIDE {
+ return false;
+ }
+};
+
+// Verifies that the EventTargeter installed on an EventTarget can dictate
+// whether the target itself can process an event.
+TEST_F(EventProcessorTest, TargeterChecksOwningEventTarget) {
+ scoped_ptr<TestEventTarget> child(new TestEventTarget());
+ root()->AddChild(child.Pass());
+
+ MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
+ EF_NONE, EF_NONE);
+ DispatchEvent(&mouse);
+ EXPECT_TRUE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
+ EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
+ root()->child_at(0)->ResetReceivedEvents();
+
+ // Install an event handler on |child| which always prevents the target from
+ // receiving event.
+ root()->child_at(0)->SetEventTargeter(
+ scoped_ptr<EventTargeter>(new IgnoreEventTargeter()));
+ MouseEvent mouse2(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
+ EF_NONE, EF_NONE);
+ DispatchEvent(&mouse2);
+ EXPECT_FALSE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
+ EXPECT_TRUE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
+}
+
+// An EventTargeter which is used to allow a bubbling behaviour in event
+// dispatch: if an event is not handled after being dispatched to its
+// initial target, the event is dispatched to the next-best target as
+// specified by FindNextBestTarget().
+class BubblingEventTargeter : public EventTargeter {
+ public:
+ explicit BubblingEventTargeter(TestEventTarget* initial_target)
+ : initial_target_(initial_target) {}
+ virtual ~BubblingEventTargeter() {}
+
+ private:
+ // EventTargeter:
+ virtual EventTarget* FindTargetForEvent(EventTarget* root,
+ Event* event) OVERRIDE {
+ return initial_target_;
+ }
+
+ virtual EventTarget* FindNextBestTarget(EventTarget* previous_target,
+ Event* event) OVERRIDE {
+ return previous_target->GetParentTarget();
+ }
+
+ TestEventTarget* initial_target_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubblingEventTargeter);
+};
+
+// Tests that unhandled events are correctly dispatched to the next-best
+// target as decided by the BubblingEventTargeter.
+TEST_F(EventProcessorTest, DispatchToNextBestTarget) {
+ scoped_ptr<TestEventTarget> child(new TestEventTarget());
+ scoped_ptr<TestEventTarget> grandchild(new TestEventTarget());
+
+ root()->SetEventTargeter(
+ scoped_ptr<EventTargeter>(new BubblingEventTargeter(grandchild.get())));
+ child->AddChild(grandchild.Pass());
+ root()->AddChild(child.Pass());
+
+ ASSERT_EQ(1u, root()->child_count());
+ ASSERT_EQ(1u, root()->child_at(0)->child_count());
+ ASSERT_EQ(0u, root()->child_at(0)->child_at(0)->child_count());
+
+ TestEventTarget* child_r = root()->child_at(0);
+ TestEventTarget* grandchild_r = child_r->child_at(0);
+
+ // When the root has a BubblingEventTargeter installed, events targeted
+ // at the grandchild target should be dispatched to all three targets.
+ KeyEvent key_event(ET_KEY_PRESSED, VKEY_ESCAPE, 0, false);
+ DispatchEvent(&key_event);
+ EXPECT_TRUE(root()->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_TRUE(child_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_KEY_PRESSED));
+ root()->ResetReceivedEvents();
+ child_r->ResetReceivedEvents();
+ grandchild_r->ResetReceivedEvents();
+
+ // Add a pre-target handler on the child of the root that will mark the event
+ // as handled. No targets in the hierarchy should receive the event.
+ TestEventHandler handler;
+ child_r->AddPreTargetHandler(&handler);
+ key_event = KeyEvent(ET_KEY_PRESSED, VKEY_ESCAPE, 0, false);
+ DispatchEvent(&key_event);
+ EXPECT_FALSE(root()->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_FALSE(child_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_FALSE(grandchild_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_EQ(1, handler.num_key_events());
+ handler.Reset();
+
+ // Add a post-target handler on the child of the root that will mark the event
+ // as handled. Only the grandchild (the initial target) should receive the
+ // event.
+ child_r->RemovePreTargetHandler(&handler);
+ child_r->AddPostTargetHandler(&handler);
+ key_event = KeyEvent(ET_KEY_PRESSED, VKEY_ESCAPE, 0, false);
+ DispatchEvent(&key_event);
+ EXPECT_FALSE(root()->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_FALSE(child_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_EQ(1, handler.num_key_events());
+ handler.Reset();
+ grandchild_r->ResetReceivedEvents();
+ child_r->RemovePostTargetHandler(&handler);
+
+ // Mark the event as handled when it reaches the EP_TARGET phase of
+ // dispatch at the child of the root. The child and grandchild
+ // targets should both receive the event, but the root should not.
+ child_r->set_mark_events_as_handled(true);
+ key_event = KeyEvent(ET_KEY_PRESSED, VKEY_ESCAPE, 0, false);
+ DispatchEvent(&key_event);
+ EXPECT_FALSE(root()->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_TRUE(child_r->DidReceiveEvent(ET_KEY_PRESSED));
+ EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_KEY_PRESSED));
+ root()->ResetReceivedEvents();
+ child_r->ResetReceivedEvents();
+ grandchild_r->ResetReceivedEvents();
+ child_r->set_mark_events_as_handled(false);
+}
+
+// Tests that unhandled events are seen by the correct sequence of
+// targets, pre-target handlers, and post-target handlers when
+// a BubblingEventTargeter is installed on the root target.
+TEST_F(EventProcessorTest, HandlerSequence) {
+ scoped_ptr<TestEventTarget> child(new TestEventTarget());
+ scoped_ptr<TestEventTarget> grandchild(new TestEventTarget());
+
+ root()->SetEventTargeter(
+ scoped_ptr<EventTargeter>(new BubblingEventTargeter(grandchild.get())));
+ child->AddChild(grandchild.Pass());
+ root()->AddChild(child.Pass());
+
+ ASSERT_EQ(1u, root()->child_count());
+ ASSERT_EQ(1u, root()->child_at(0)->child_count());
+ ASSERT_EQ(0u, root()->child_at(0)->child_at(0)->child_count());
+
+ TestEventTarget* child_r = root()->child_at(0);
+ TestEventTarget* grandchild_r = child_r->child_at(0);
+
+ HandlerSequenceRecorder recorder;
+ root()->set_target_name("R");
+ root()->set_recorder(&recorder);
+ child_r->set_target_name("C");
+ child_r->set_recorder(&recorder);
+ grandchild_r->set_target_name("G");
+ grandchild_r->set_recorder(&recorder);
+
+ TestEventHandler pre_root;
+ pre_root.set_handler_name("PreR");
+ pre_root.set_recorder(&recorder);
+ root()->AddPreTargetHandler(&pre_root);
+
+ TestEventHandler pre_child;
+ pre_child.set_handler_name("PreC");
+ pre_child.set_recorder(&recorder);
+ child_r->AddPreTargetHandler(&pre_child);
+
+ TestEventHandler pre_grandchild;
+ pre_grandchild.set_handler_name("PreG");
+ pre_grandchild.set_recorder(&recorder);
+ grandchild_r->AddPreTargetHandler(&pre_grandchild);
+
+ TestEventHandler post_root;
+ post_root.set_handler_name("PostR");
+ post_root.set_recorder(&recorder);
+ root()->AddPostTargetHandler(&post_root);
+
+ TestEventHandler post_child;
+ post_child.set_handler_name("PostC");
+ post_child.set_recorder(&recorder);
+ child_r->AddPostTargetHandler(&post_child);
+
+ TestEventHandler post_grandchild;
+ post_grandchild.set_handler_name("PostG");
+ post_grandchild.set_recorder(&recorder);
+ grandchild_r->AddPostTargetHandler(&post_grandchild);
+
+ MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
+ EF_NONE, EF_NONE);
+ DispatchEvent(&mouse);
+
+ std::string expected[] = { "PreR", "PreC", "PreG", "G", "PostG", "PostC",
+ "PostR", "PreR", "PreC", "C", "PostC", "PostR", "PreR", "R", "PostR" };
+ EXPECT_EQ(std::vector<std::string>(
+ expected, expected + arraysize(expected)), recorder);
+}
+
} // namespace test
} // namespace ui
diff --git a/chromium/ui/events/event_rewriter.h b/chromium/ui/events/event_rewriter.h
new file mode 100644
index 00000000000..f948725709a
--- /dev/null
+++ b/chromium/ui/events/event_rewriter.h
@@ -0,0 +1,68 @@
+// 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_EVENT_REWRITER_H_
+#define UI_EVENTS_EVENT_REWRITER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+class Event;
+
+// Return status of EventRewriter operations; see that class below.
+enum EventRewriteStatus {
+ // Nothing was done; no rewritten event returned. Pass the original
+ // event to later rewriters, or send it to the EventProcessor if this
+ // was the final rewriter.
+ EVENT_REWRITE_CONTINUE,
+
+ // The event has been rewritten. Send the rewritten event to the
+ // EventProcessor instead of the original event (without sending
+ // either to any later rewriters).
+ EVENT_REWRITE_REWRITTEN,
+
+ // The event should be discarded, neither passing it to any later
+ // rewriters nor sending it to the EventProcessor.
+ EVENT_REWRITE_DISCARD,
+
+ // The event has been rewritten. As for EVENT_REWRITE_REWRITTEN,
+ // send the rewritten event to the EventProcessor instead of the
+ // original event (without sending either to any later rewriters).
+ // In addition the rewriter has one or more additional new events
+ // to be retrieved using |NextDispatchEvent()| and sent to the
+ // EventProcessor.
+ EVENT_REWRITE_DISPATCH_ANOTHER,
+};
+
+// EventRewriter provides a mechanism for Events to be rewritten
+// before being dispatched from EventSource to EventProcessor.
+class EVENTS_EXPORT EventRewriter {
+ public:
+ virtual ~EventRewriter() {}
+
+ // Potentially rewrites (replaces) an event, or requests it be discarded.
+ // or discards an event. If the rewriter wants to rewrite an event, and
+ // dispatch another event once the rewritten event is dispatched, it should
+ // return EVENT_REWRITE_DISPATCH_ANOTHER, and return the next event to
+ // dispatch from |NextDispatchEvent()|.
+ virtual EventRewriteStatus RewriteEvent(
+ const Event& event,
+ scoped_ptr<Event>* rewritten_event) = 0;
+
+ // Supplies an additional event to be dispatched. It is only valid to
+ // call this after the immediately previous call to |RewriteEvent()|
+ // or |NextDispatchEvent()| has returned EVENT_REWRITE_DISPATCH_ANOTHER.
+ // Should only return either EVENT_REWRITE_REWRITTEN or
+ // EVENT_REWRITE_DISPATCH_ANOTHER; otherwise the previous call should not
+ // have returned EVENT_REWRITE_DISPATCH_ANOTHER.
+ virtual EventRewriteStatus NextDispatchEvent(
+ const Event& last_event,
+ scoped_ptr<Event>* new_event) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_EVENT_REWRITER_H_
diff --git a/chromium/ui/events/event_rewriter_unittest.cc b/chromium/ui/events/event_rewriter_unittest.cc
new file mode 100644
index 00000000000..11a05c9c157
--- /dev/null
+++ b/chromium/ui/events/event_rewriter_unittest.cc
@@ -0,0 +1,231 @@
+// 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/events/event_rewriter.h"
+
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+
+#include "testing/gtest/include/gtest/gtest.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::TimeDelta(), 0), unique_id_(next_unique_id_++) {}
+ virtual ~TestEvent() {}
+ 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.
+class TestEventRewriteProcessor : public test::TestEventProcessor {
+ public:
+ TestEventRewriteProcessor() {}
+ virtual ~TestEventRewriteProcessor() { CheckAllReceived(); }
+
+ void AddExpectedEvent(EventType type) { expected_events_.push_back(type); }
+ // Test that all expected events have been received.
+ void CheckAllReceived() { EXPECT_TRUE(expected_events_.empty()); }
+
+ // EventProcessor:
+ virtual EventDispatchDetails OnEventFromSource(Event* event) OVERRIDE {
+ EXPECT_FALSE(expected_events_.empty());
+ EXPECT_EQ(expected_events_.front(), event->type());
+ expected_events_.pop_front();
+ return EventDispatchDetails();
+ }
+
+ private:
+ std::list<EventType> expected_events_;
+ DISALLOW_COPY_AND_ASSIGN(TestEventRewriteProcessor);
+};
+
+// Trivial EventSource that does nothing but send events.
+class TestEventRewriteSource : public EventSource {
+ public:
+ explicit TestEventRewriteSource(EventProcessor* processor)
+ : processor_(processor) {}
+ virtual EventProcessor* GetEventProcessor() OVERRIDE { return processor_; }
+ void Send(EventType type) {
+ scoped_ptr<Event> event(new TestEvent(type));
+ (void)SendEventToProcessor(event.get());
+ }
+
+ private:
+ EventProcessor* processor_;
+};
+
+// This EventRewriter always returns the same status, and if rewriting, the
+// same event type; it is used to test simple rewriting, and rewriter addition,
+// removal, and sequencing. Consequently EVENT_REWRITE_DISPATCH_ANOTHER is not
+// supported here (calls to NextDispatchEvent() would continue indefinitely).
+class TestConstantEventRewriter : public EventRewriter {
+ public:
+ TestConstantEventRewriter(EventRewriteStatus status, EventType type)
+ : status_(status), type_(type) {
+ CHECK_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
+ }
+
+ virtual EventRewriteStatus RewriteEvent(const Event& event,
+ scoped_ptr<Event>* rewritten_event)
+ OVERRIDE {
+ if (status_ == EVENT_REWRITE_REWRITTEN)
+ rewritten_event->reset(new TestEvent(type_));
+ return status_;
+ }
+ virtual EventRewriteStatus NextDispatchEvent(const Event& last_event,
+ scoped_ptr<Event>* new_event)
+ OVERRIDE {
+ NOTREACHED();
+ return status_;
+ }
+
+ private:
+ EventRewriteStatus status_;
+ EventType type_;
+};
+
+// This EventRewriter runs a simple state machine; it is used to test
+// EVENT_REWRITE_DISPATCH_ANOTHER.
+class TestStateMachineEventRewriter : public EventRewriter {
+ public:
+ TestStateMachineEventRewriter() : last_rewritten_event_(0), state_(0) {}
+ void AddRule(int from_state, EventType from_type,
+ int to_state, EventType to_type, EventRewriteStatus to_status) {
+ RewriteResult r = {to_state, to_type, to_status};
+ rules_.insert(std::pair<RewriteCase, RewriteResult>(
+ RewriteCase(from_state, from_type), r));
+ }
+ virtual EventRewriteStatus RewriteEvent(const Event& event,
+ scoped_ptr<Event>* rewritten_event)
+ OVERRIDE {
+ RewriteRules::iterator find =
+ rules_.find(RewriteCase(state_, event.type()));
+ if (find == rules_.end())
+ 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_);
+ } else {
+ last_rewritten_event_ = 0;
+ }
+ state_ = find->second.state;
+ return find->second.status;
+ }
+ virtual EventRewriteStatus NextDispatchEvent(const Event& last_event,
+ scoped_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());
+ return RewriteEvent(last_event, new_event);
+ }
+
+ private:
+ typedef std::pair<int, EventType> RewriteCase;
+ struct RewriteResult {
+ int state;
+ EventType type;
+ EventRewriteStatus status;
+ };
+ typedef std::map<RewriteCase, RewriteResult> RewriteRules;
+ RewriteRules rules_;
+ TestEvent* last_rewritten_event_;
+ int state_;
+};
+
+} // namespace
+
+TEST(EventRewriterTest, EventRewriting) {
+ // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
+ // it is placed at the beginning of the chain and later removed,
+ // to verify that rewriter removal works.
+ TestConstantEventRewriter r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
+
+ // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
+ // it is placed at the beginning of the chain to verify that a
+ // later rewriter sees the events.
+ TestConstantEventRewriter r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);
+
+ // TestEventRewriter r2 has a state machine, primarily to test
+ // |EVENT_REWRITE_DISPATCH_ANOTHER|.
+ TestStateMachineEventRewriter r2;
+
+ // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
+ // it is placed at the end of the chain to verify that previously
+ // rewritten events are not passed further down the chain.
+ TestConstantEventRewriter r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
+
+ TestEventRewriteProcessor p;
+ TestEventRewriteSource s(&p);
+ s.AddEventRewriter(&r0);
+ s.AddEventRewriter(&r1);
+ s.AddEventRewriter(&r2);
+
+ // These events should be rewritten by r0 to ET_CANCEL_MODE.
+ p.AddExpectedEvent(ET_CANCEL_MODE);
+ s.Send(ET_MOUSE_DRAGGED);
+ p.AddExpectedEvent(ET_CANCEL_MODE);
+ s.Send(ET_MOUSE_PRESSED);
+ p.CheckAllReceived();
+
+ // Remove r0, and verify that it's gone and that events make it through.
+ s.AddEventRewriter(&r3);
+ s.RemoveEventRewriter(&r0);
+ r2.AddRule(0, ET_SCROLL_FLING_START,
+ 0, ET_SCROLL_FLING_CANCEL, EVENT_REWRITE_REWRITTEN);
+ p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
+ s.Send(ET_SCROLL_FLING_START);
+ p.CheckAllReceived();
+ s.RemoveEventRewriter(&r3);
+
+ // Verify EVENT_REWRITE_DISPATCH_ANOTHER using a state machine
+ // (that happens to be analogous to sticky keys).
+ r2.AddRule(0, ET_KEY_PRESSED,
+ 1, ET_KEY_PRESSED, EVENT_REWRITE_CONTINUE);
+ r2.AddRule(1, ET_MOUSE_PRESSED,
+ 0, ET_MOUSE_PRESSED, EVENT_REWRITE_CONTINUE);
+ r2.AddRule(1, ET_KEY_RELEASED,
+ 2, ET_KEY_RELEASED, EVENT_REWRITE_DISCARD);
+ r2.AddRule(2, ET_MOUSE_RELEASED,
+ 3, ET_MOUSE_RELEASED, EVENT_REWRITE_DISPATCH_ANOTHER);
+ r2.AddRule(3, ET_MOUSE_RELEASED,
+ 0, ET_KEY_RELEASED, EVENT_REWRITE_REWRITTEN);
+ p.AddExpectedEvent(ET_KEY_PRESSED);
+ s.Send(ET_KEY_PRESSED);
+ s.Send(ET_KEY_RELEASED);
+ p.AddExpectedEvent(ET_MOUSE_PRESSED);
+ s.Send(ET_MOUSE_PRESSED);
+
+ // Removing rewriters r1 and r3 shouldn't affect r2.
+ s.RemoveEventRewriter(&r1);
+ s.RemoveEventRewriter(&r3);
+
+ // Continue with the state-based rewriting.
+ p.AddExpectedEvent(ET_MOUSE_RELEASED);
+ p.AddExpectedEvent(ET_KEY_RELEASED);
+ s.Send(ET_MOUSE_RELEASED);
+ p.CheckAllReceived();
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/event_source.cc b/chromium/ui/events/event_source.cc
index 4946ea0dfd1..0f3dfb80a0a 100644
--- a/chromium/ui/events/event_source.cc
+++ b/chromium/ui/events/event_source.cc
@@ -4,16 +4,73 @@
#include "ui/events/event_source.h"
+#include <algorithm>
+
#include "ui/events/event_processor.h"
+#include "ui/events/event_rewriter.h"
namespace ui {
-void EventSource::SendEventToProcessor(Event* event) {
+EventSource::EventSource() {}
+
+EventSource::~EventSource() {}
+
+void EventSource::AddEventRewriter(EventRewriter* rewriter) {
+ DCHECK(rewriter);
+ DCHECK(rewriter_list_.end() ==
+ std::find(rewriter_list_.begin(), rewriter_list_.end(), rewriter));
+ rewriter_list_.push_back(rewriter);
+}
+
+void EventSource::RemoveEventRewriter(EventRewriter* rewriter) {
+ EventRewriterList::iterator find =
+ std::find(rewriter_list_.begin(), rewriter_list_.end(), rewriter);
+ if (find != rewriter_list_.end())
+ rewriter_list_.erase(find);
+}
+
+EventDispatchDetails EventSource::SendEventToProcessor(Event* event) {
+ scoped_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);
+ if (status == EVENT_REWRITE_DISCARD) {
+ CHECK(!rewritten_event);
+ return EventDispatchDetails();
+ }
+ if (status == EVENT_REWRITE_CONTINUE) {
+ CHECK(!rewritten_event);
+ continue;
+ }
+ break;
+ }
+ CHECK((it == end && !rewritten_event) || rewritten_event);
+ EventDispatchDetails details =
+ DeliverEventToProcessor(rewritten_event ? rewritten_event.get() : event);
+ if (details.dispatcher_destroyed)
+ return details;
+
+ while (status == EVENT_REWRITE_DISPATCH_ANOTHER) {
+ scoped_ptr<Event> new_event;
+ status = (*it)->NextDispatchEvent(*rewritten_event, &new_event);
+ if (status == EVENT_REWRITE_DISCARD)
+ return EventDispatchDetails();
+ CHECK_NE(EVENT_REWRITE_CONTINUE, status);
+ CHECK(new_event);
+ details = DeliverEventToProcessor(new_event.get());
+ if (details.dispatcher_destroyed)
+ return details;
+ rewritten_event.reset(new_event.release());
+ }
+ return EventDispatchDetails();
+}
+
+EventDispatchDetails EventSource::DeliverEventToProcessor(Event* event) {
EventProcessor* processor = GetEventProcessor();
CHECK(processor);
- EventDispatchDetails details = processor->OnEventFromSource(event);
- if (details.dispatcher_destroyed)
- return;
+ return processor->OnEventFromSource(event);
}
} // namespace ui
diff --git a/chromium/ui/events/event_source.h b/chromium/ui/events/event_source.h
index f8da9e6635e..ca8b00f514b 100644
--- a/chromium/ui/events/event_source.h
+++ b/chromium/ui/events/event_source.h
@@ -5,23 +5,43 @@
#ifndef UI_EVENTS_EVENT_SOURCE_H_
#define UI_EVENTS_EVENT_SOURCE_H_
+#include <vector>
+
+#include "ui/events/event_dispatcher.h"
#include "ui/events/events_export.h"
namespace ui {
class Event;
class EventProcessor;
+class EventRewriter;
// EventSource receives events from the native platform (e.g. X11, win32 etc.)
// and sends the events to an EventProcessor.
class EVENTS_EXPORT EventSource {
public:
- virtual ~EventSource() {}
+ EventSource();
+ virtual ~EventSource();
virtual EventProcessor* GetEventProcessor() = 0;
+ // Adds a rewriter to modify events before they are sent to the
+ // EventProcessor. The rewriter must be explicitly removed from the
+ // EventSource before the rewriter is destroyed. The EventSource
+ // does not take ownership of the rewriter.
+ void AddEventRewriter(EventRewriter* rewriter);
+ void RemoveEventRewriter(EventRewriter* rewriter);
+
protected:
- void SendEventToProcessor(Event* event);
+ EventDispatchDetails SendEventToProcessor(Event* event);
+
+ private:
+ friend class EventSourceTestApi;
+
+ typedef std::vector<EventRewriter*> EventRewriterList;
+ EventDispatchDetails DeliverEventToProcessor(Event* event);
+ EventRewriterList rewriter_list_;
+ DISALLOW_COPY_AND_ASSIGN(EventSource);
};
} // namespace ui
diff --git a/chromium/ui/events/event_switches.cc b/chromium/ui/events/event_switches.cc
index 195e2bbdb4f..d5109700a9d 100644
--- a/chromium/ui/events/event_switches.cc
+++ b/chromium/ui/events/event_switches.cc
@@ -20,6 +20,18 @@ const char kTouchEventsEnabled[] = "enabled";
// disabled: touch events are disabled.
const char kTouchEventsDisabled[] = "disabled";
+// Enable the unified gesture detector, instead of the aura gesture detector.
+const char kUnifiedGestureDetector[] = "unified-gesture-detector";
+
+// The values the kUnifiedGestureDetector switch may have, as in
+// --unified-gesture-detector=disabled.
+// auto: Same as disabled.
+const char kUnifiedGestureDetectorAuto[] = "auto";
+// enabled: Use the unified gesture detector.
+const char kUnifiedGestureDetectorEnabled[] = "enabled";
+// disabled: Use the aura gesture detector.
+const char kUnifiedGestureDetectorDisabled[] = "disabled";
+
#if defined(OS_LINUX)
// Tells chrome to interpret events from these devices as touch events. Only
// available with XInput 2 (i.e. X server 1.8 or above). The id's of the
@@ -27,4 +39,9 @@ const char kTouchEventsDisabled[] = "disabled";
const char kTouchDevices[] = "touch-devices";
#endif
+#if defined(USE_XI2_MT) || defined(USE_OZONE)
+// The calibration factors given as "<left>,<right>,<top>,<bottom>".
+const char kTouchCalibration[] = "touch-calibration";
+#endif
+
} // namespace switches
diff --git a/chromium/ui/events/event_switches.h b/chromium/ui/events/event_switches.h
index d4343046e50..6697d3a7516 100644
--- a/chromium/ui/events/event_switches.h
+++ b/chromium/ui/events/event_switches.h
@@ -15,11 +15,19 @@ EVENTS_BASE_EXPORT extern const char kTouchEvents[];
EVENTS_BASE_EXPORT extern const char kTouchEventsAuto[];
EVENTS_BASE_EXPORT extern const char kTouchEventsEnabled[];
EVENTS_BASE_EXPORT extern const char kTouchEventsDisabled[];
+EVENTS_BASE_EXPORT extern const char kUnifiedGestureDetector[];
+EVENTS_BASE_EXPORT extern const char kUnifiedGestureDetectorAuto[];
+EVENTS_BASE_EXPORT extern const char kUnifiedGestureDetectorEnabled[];
+EVENTS_BASE_EXPORT extern const char kUnifiedGestureDetectorDisabled[];
#if defined(OS_LINUX)
EVENTS_BASE_EXPORT extern const char kTouchDevices[];
#endif
+#if defined(USE_XI2_MT) || defined(USE_OZONE)
+EVENTS_BASE_EXPORT extern const char kTouchCalibration[];
+#endif
+
} // namespace switches
#endif // UI_EVENTS_EVENTS_SWITCHES_H_
diff --git a/chromium/ui/events/event_target.h b/chromium/ui/events/event_target.h
index fd03667da95..3ffec550048 100644
--- a/chromium/ui/events/event_target.h
+++ b/chromium/ui/events/event_target.h
@@ -77,11 +77,13 @@ class EVENTS_EXPORT EventTarget : public EventHandler {
// Returns true if the event pre target list is empty.
bool IsPreTargetListEmpty() const;
- protected:
void set_target_handler(EventHandler* handler) {
target_handler_ = handler;
}
+ protected:
+ EventHandler* target_handler() { return target_handler_; }
+
// Overridden from EventHandler:
virtual void OnEvent(Event* event) OVERRIDE;
virtual void OnKeyEvent(KeyEvent* event) OVERRIDE;
diff --git a/chromium/ui/events/event_targeter.cc b/chromium/ui/events/event_targeter.cc
index 41d44426596..e76b5892197 100644
--- a/chromium/ui/events/event_targeter.cc
+++ b/chromium/ui/events/event_targeter.cc
@@ -32,16 +32,18 @@ EventTarget* EventTargeter::FindTargetForLocatedEvent(EventTarget* root,
EventTarget* target = root;
EventTarget* child = NULL;
while ((child = iter->GetNextTarget())) {
- if (!SubtreeShouldBeExploredForEvent(child, *event))
+ EventTargeter* targeter = child->GetEventTargeter();
+ if (!targeter)
+ targeter = this;
+ if (!targeter->SubtreeShouldBeExploredForEvent(child, *event))
continue;
target->ConvertEventToTarget(child, event);
- EventTargeter* targeter = child->GetEventTargeter();
+ target = child;
EventTarget* child_target = targeter ?
targeter->FindTargetForLocatedEvent(child, event) :
FindTargetForLocatedEvent(child, event);
if (child_target)
return child_target;
- target = child;
}
target->ConvertEventToTarget(root, event);
}
@@ -50,6 +52,22 @@ EventTarget* EventTargeter::FindTargetForLocatedEvent(EventTarget* root,
bool EventTargeter::SubtreeShouldBeExploredForEvent(EventTarget* target,
const LocatedEvent& event) {
+ return SubtreeCanAcceptEvent(target, event) &&
+ EventLocationInsideBounds(target, event);
+}
+
+EventTarget* EventTargeter::FindNextBestTarget(EventTarget* previous_target,
+ Event* event) {
+ return NULL;
+}
+
+bool EventTargeter::SubtreeCanAcceptEvent(EventTarget* target,
+ const LocatedEvent& event) const {
+ return true;
+}
+
+bool EventTargeter::EventLocationInsideBounds(EventTarget* target,
+ const LocatedEvent& event) const {
return true;
}
diff --git a/chromium/ui/events/event_targeter.h b/chromium/ui/events/event_targeter.h
index a28662b5e83..dead49f1367 100644
--- a/chromium/ui/events/event_targeter.h
+++ b/chromium/ui/events/event_targeter.h
@@ -26,18 +26,43 @@ class EVENTS_EXPORT EventTargeter {
// Same as FindTargetForEvent(), but used for positional events. The location
// etc. of |event| are in |root|'s coordinate system. When finding the target
- // for the event, the targeter can mutate the |event| (e.g. chnage the
- // coordinate to be in the returned target's coordinate sustem) so that it can
+ // for the event, the targeter can mutate the |event| (e.g. change the
+ // coordinate to be in the returned target's coordinate system) so that it can
// be dispatched to the target without any farther modification.
virtual EventTarget* FindTargetForLocatedEvent(EventTarget* root,
LocatedEvent* event);
- protected:
- // Returns true of |target| or one of its descendants can be a target of
- // |event|. Note that the location etc. of |event| is in |target|'s parent's
- // coordinate system.
+ // Returns true if |target| or one of its descendants can be a target of
+ // |event|. This requires that |target| and its descendants are not
+ // prohibited from accepting the event, and that the event is within an
+ // actionable region of the target's bounds. Note that the location etc. of
+ // |event| is in |target|'s parent's coordinate system.
+ // TODO(tdanderson|sadrul): This function should be made non-virtual and
+ // non-public.
virtual bool SubtreeShouldBeExploredForEvent(EventTarget* target,
const LocatedEvent& event);
+
+ // Returns the next best target for |event| as compared to |previous_target|.
+ // Also mutates |event| so that it can be dispatched to the returned target
+ // (e.g., by changing |event|'s location to be in the returned target's
+ // coordinate space).
+ virtual EventTarget* FindNextBestTarget(EventTarget* previous_target,
+ Event* event);
+
+ protected:
+ // Returns false if neither |target| nor any of its descendants are allowed
+ // to accept |event| for reasons unrelated to the event's location or the
+ // target's bounds. For example, overrides of this function may consider
+ // attributes such as the visibility or enabledness of |target|. Note that
+ // the location etc. of |event| is in |target|'s parent's coordinate system.
+ virtual bool SubtreeCanAcceptEvent(EventTarget* target,
+ const LocatedEvent& event) const;
+
+ // Returns whether the location of the event is in an actionable region of the
+ // target. Note that the location etc. of |event| is in the |target|'s
+ // parent's coordinate system.
+ virtual bool EventLocationInsideBounds(EventTarget* target,
+ const LocatedEvent& event) const;
};
} // namespace ui
diff --git a/chromium/ui/events/event_unittest.cc b/chromium/ui/events/event_unittest.cc
index 012fc608b66..186677969cb 100644
--- a/chromium/ui/events/event_unittest.cc
+++ b/chromium/ui/events/event_unittest.cc
@@ -58,17 +58,17 @@ TEST(EventTest, GetCharacter) {
TEST(EventTest, ClickCount) {
const gfx::Point origin(0, 0);
- MouseEvent mouseev(ET_MOUSE_PRESSED, origin, origin, 0);
+ MouseEvent mouseev(ET_MOUSE_PRESSED, origin, origin, 0, 0);
for (int i = 1; i <=3 ; ++i) {
mouseev.SetClickCount(i);
EXPECT_EQ(i, mouseev.GetClickCount());
}
}
-TEST(EventTest, Repeated) {
+TEST(EventTest, RepeatedClick) {
const gfx::Point origin(0, 0);
- MouseEvent mouse_ev1(ET_MOUSE_PRESSED, origin, origin, 0);
- MouseEvent mouse_ev2(ET_MOUSE_PRESSED, origin, origin, 0);
+ MouseEvent mouse_ev1(ET_MOUSE_PRESSED, origin, origin, 0, 0);
+ MouseEvent mouse_ev2(ET_MOUSE_PRESSED, origin, origin, 0, 0);
LocatedEventTestApi test_ev1(&mouse_ev1);
LocatedEventTestApi test_ev2(&mouse_ev2);
@@ -98,6 +98,68 @@ TEST(EventTest, Repeated) {
EXPECT_FALSE(MouseEvent::IsRepeatedClickEvent(mouse_ev1, mouse_ev2));
}
+// 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);
+ scoped_ptr<MouseEvent> ev;
+ base::TimeDelta start = base::TimeDelta::FromMilliseconds(0);
+
+ ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin1, origin1, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
+ ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin1, origin1, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
+
+ ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin2, origin2, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
+ ev.reset(new MouseEvent(ET_MOUSE_RELEASED, origin2, origin2, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(1, MouseEvent::GetRepeatCount(*ev));
+ ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin2, origin2, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
+ ev.reset(new MouseEvent(ET_MOUSE_RELEASED, origin2, origin2, 0, 0));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
+ MouseEvent::ResetLastClickForTest();
+}
+
+// Tests that clicking right and then left clicking does not generate a double
+// click.
+TEST(EventTest, SingleClickRightLeft) {
+ const gfx::Point origin(0, 0);
+ scoped_ptr<MouseEvent> ev;
+ base::TimeDelta start = base::TimeDelta::FromMilliseconds(0);
+
+ ev.reset(new MouseEvent(ET_MOUSE_PRESSED, origin, origin,
+ 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,
+ 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,
+ 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,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON));
+ ev->set_time_stamp(start);
+ EXPECT_EQ(2, MouseEvent::GetRepeatCount(*ev));
+ MouseEvent::ResetLastClickForTest();
+}
+
TEST(EventTest, KeyEvent) {
static const struct {
KeyboardCode key_code;
@@ -331,4 +393,66 @@ TEST(EventTest, KeyEventCode) {
#endif // OS_WIN
}
+#if defined(USE_X11) || defined(OS_WIN)
+TEST(EventTest, AutoRepeat) {
+ KeycodeConverter* conv = KeycodeConverter::GetInstance();
+
+ const uint16 kNativeCodeA = conv->CodeToNativeKeycode("KeyA");
+ const uint16 kNativeCodeB = conv->CodeToNativeKeycode("KeyB");
+#if defined(USE_X11)
+ ScopedXI2Event native_event_a_pressed;
+ native_event_a_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, kNativeCodeA);
+ ScopedXI2Event native_event_a_released;
+ native_event_a_released.InitKeyEvent(ET_KEY_RELEASED, VKEY_A, kNativeCodeA);
+ ScopedXI2Event native_event_b_pressed;
+ native_event_b_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_B, kNativeCodeB);
+ ScopedXI2Event native_event_a_pressed_nonstandard_state;
+ native_event_a_pressed_nonstandard_state.InitKeyEvent(
+ ET_KEY_PRESSED, VKEY_A, kNativeCodeA);
+ // IBUS-GTK uses the mask (1 << 25) to detect reposted event.
+ static_cast<XEvent*>(native_event_a_pressed_nonstandard_state)->xkey.state |=
+ 1 << 25;
+#elif defined(OS_WIN)
+ const LPARAM lParam_a = GetLParamFromScanCode(kNativeCodeA);
+ const LPARAM lParam_b = GetLParamFromScanCode(kNativeCodeB);
+ MSG native_event_a_pressed = { NULL, WM_KEYDOWN, VKEY_A, lParam_a };
+ MSG native_event_a_released = { NULL, WM_KEYUP, VKEY_A, lParam_a };
+ MSG native_event_b_pressed = { NULL, WM_KEYUP, VKEY_B, lParam_b };
+#endif
+ KeyEvent key_a1(native_event_a_pressed, false);
+ EXPECT_FALSE(key_a1.IsRepeat());
+ KeyEvent key_a1_released(native_event_a_released, false);
+ EXPECT_FALSE(key_a1_released.IsRepeat());
+
+ KeyEvent key_a2(native_event_a_pressed, false);
+ EXPECT_FALSE(key_a2.IsRepeat());
+ KeyEvent key_a2_repeated(native_event_a_pressed, false);
+ EXPECT_TRUE(key_a2_repeated.IsRepeat());
+ KeyEvent key_a2_released(native_event_a_released, false);
+ EXPECT_FALSE(key_a2_released.IsRepeat());
+
+ KeyEvent key_a3(native_event_a_pressed, false);
+ EXPECT_FALSE(key_a3.IsRepeat());
+ KeyEvent key_b(native_event_b_pressed, false);
+ EXPECT_FALSE(key_b.IsRepeat());
+ KeyEvent key_a3_again(native_event_a_pressed, false);
+ EXPECT_FALSE(key_a3_again.IsRepeat());
+ KeyEvent key_a3_repeated(native_event_a_pressed, false);
+ EXPECT_TRUE(key_a3_repeated.IsRepeat());
+ KeyEvent key_a3_repeated2(native_event_a_pressed, false);
+ EXPECT_TRUE(key_a3_repeated2.IsRepeat());
+ KeyEvent key_a3_released(native_event_a_released, false);
+ EXPECT_FALSE(key_a3_released.IsRepeat());
+
+#if defined(USE_X11)
+ KeyEvent key_a4_pressed(native_event_a_pressed, false);
+ EXPECT_FALSE(key_a4_pressed.IsRepeat());
+
+ KeyEvent key_a4_pressed_nonstandard_state(
+ native_event_a_pressed_nonstandard_state, false);
+ EXPECT_FALSE(key_a4_pressed_nonstandard_state.IsRepeat());
+#endif
+}
+#endif // USE_X11 || OS_WIN
+
} // namespace ui
diff --git a/chromium/ui/events/event_utils.cc b/chromium/ui/events/event_utils.cc
index a8c95da6f8f..e4b384a4744 100644
--- a/chromium/ui/events/event_utils.cc
+++ b/chromium/ui/events/event_utils.cc
@@ -16,8 +16,51 @@ namespace {
int g_custom_event_types = ET_LAST;
} // namespace
-bool EventCanceledDefaultHandling(const Event& event) {
- return event.phase() == EP_POSTTARGET && event.result() != ER_UNHANDLED;
+scoped_ptr<Event> EventFromNative(const base::NativeEvent& native_event) {
+ scoped_ptr<Event> event;
+ EventType type = EventTypeFromNative(native_event);
+ switch(type) {
+ case ET_KEY_PRESSED:
+ case ET_KEY_RELEASED:
+ event.reset(new KeyEvent(native_event, false));
+ break;
+
+ case ET_TRANSLATED_KEY_PRESS:
+ case ET_TRANSLATED_KEY_RELEASE:
+ // These should not be generated by native events.
+ NOTREACHED();
+ break;
+
+ case ET_MOUSE_PRESSED:
+ case ET_MOUSE_DRAGGED:
+ case ET_MOUSE_RELEASED:
+ case ET_MOUSE_MOVED:
+ case ET_MOUSE_ENTERED:
+ case ET_MOUSE_EXITED:
+ event.reset(new MouseEvent(native_event));
+ break;
+
+ case ET_MOUSEWHEEL:
+ event.reset(new MouseWheelEvent(native_event));
+ break;
+
+ case ET_SCROLL_FLING_START:
+ case ET_SCROLL_FLING_CANCEL:
+ case ET_SCROLL:
+ event.reset(new ScrollEvent(native_event));
+ break;
+
+ case ET_TOUCH_RELEASED:
+ case ET_TOUCH_PRESSED:
+ case ET_TOUCH_MOVED:
+ case ET_TOUCH_CANCELLED:
+ event.reset(new TouchEvent(native_event));
+ break;
+
+ default:
+ break;
+ }
+ return event.Pass();
}
int RegisterCustomEventType() {
@@ -30,18 +73,22 @@ base::TimeDelta EventTimeForNow() {
}
bool ShouldDefaultToNaturalScroll() {
+ return GetInternalDisplayTouchSupport() ==
+ gfx::Display::TOUCH_SUPPORT_AVAILABLE;
+}
+
+gfx::Display::TouchSupport GetInternalDisplayTouchSupport() {
gfx::Screen* screen = gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
+ // No screen in some unit tests.
if (!screen)
- return false;
+ return gfx::Display::TOUCH_SUPPORT_UNKNOWN;
const std::vector<gfx::Display>& displays = screen->GetAllDisplays();
for (std::vector<gfx::Display>::const_iterator it = displays.begin();
it != displays.end(); ++it) {
- const gfx::Display& display = *it;
- if (display.IsInternal() &&
- display.touch_support() == gfx::Display::TOUCH_SUPPORT_AVAILABLE)
- return true;
+ if (it->IsInternal())
+ return it->touch_support();
}
- return false;
+ return gfx::Display::TOUCH_SUPPORT_UNAVAILABLE;
}
} // namespace ui
diff --git a/chromium/ui/events/event_utils.h b/chromium/ui/events/event_utils.h
index e67a74111d6..87b720d5884 100644
--- a/chromium/ui/events/event_utils.h
+++ b/chromium/ui/events/event_utils.h
@@ -6,8 +6,10 @@
#define UI_EVENTS_EVENT_UTILS_H_
#include "base/event_types.h"
+#include "base/memory/scoped_ptr.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/events/events_export.h"
@@ -31,6 +33,11 @@ class Event;
// Updates the list of devices for cached properties.
EVENTS_EXPORT void UpdateDeviceList();
+// Returns a ui::Event wrapping a native event. Ownership of the returned value
+// is transferred to the caller.
+EVENTS_EXPORT scoped_ptr<Event> EventFromNative(
+ const base::NativeEvent& native_event);
+
// Get the EventType from a native event.
EVENTS_EXPORT EventType EventTypeFromNative(
const base::NativeEvent& native_event);
@@ -48,7 +55,8 @@ EVENTS_EXPORT base::TimeDelta EventTimeForNow();
// Get the location from a native event. The coordinate system of the resultant
// |Point| has the origin at top-left of the "root window". The nature of
// this "root window" and how it maps to platform-specific drawing surfaces is
-// defined in ui/aura/root_window.* and ui/aura/root_window_host*.
+// defined in ui/aura/root_window.* and ui/aura/window_tree_host*.
+// TODO(tdresser): Return gfx::PointF here. See crbug.com/337827.
EVENTS_EXPORT gfx::Point EventLocationFromNative(
const base::NativeEvent& native_event);
@@ -74,8 +82,9 @@ EVENTS_EXPORT KeyboardCode KeyboardCodeFromNative(
EVENTS_EXPORT const char* CodeFromNative(
const base::NativeEvent& native_event);
-// Returns true if the message is a mouse event.
-EVENTS_EXPORT bool IsMouseEvent(const base::NativeEvent& native_event);
+// Returns the platform related key code. For X11, it is xksym value.
+EVENTS_EXPORT uint32 PlatformKeycodeFromNative(
+ const base::NativeEvent& native_event);
// Returns the flags of the button that changed during a press/release.
EVENTS_EXPORT int GetChangedMouseButtonFlagsFromNative(
@@ -85,6 +94,15 @@ EVENTS_EXPORT int GetChangedMouseButtonFlagsFromNative(
EVENTS_EXPORT gfx::Vector2d GetMouseWheelOffset(
const base::NativeEvent& 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);
+
+// Delete a |native_event| previously created by CopyNativeEvent().
+void ReleaseCopiedNativeEvent(
+ const base::NativeEvent& native_event);
+
// Gets the touch id from a native event.
EVENTS_EXPORT int GetTouchId(const base::NativeEvent& native_event);
@@ -124,26 +142,17 @@ EVENTS_EXPORT bool GetGestureTimes(const base::NativeEvent& native_event,
double* start_time,
double* end_time);
-// Enable/disable natural scrolling for touchpads.
-EVENTS_EXPORT void SetNaturalScroll(bool enabled);
-
-// In natural scrolling enabled for touchpads?
-EVENTS_EXPORT bool IsNaturalScrollEnabled();
-
// Returns whether natural scrolling should be used for touchpad.
EVENTS_EXPORT bool ShouldDefaultToNaturalScroll();
+// Returns whether or not the internal display produces touch events.
+EVENTS_EXPORT gfx::Display::TouchSupport GetInternalDisplayTouchSupport();
+
// Was this event generated by a touchpad device?
// The caller is responsible for ensuring that this is a mouse/touchpad event
// before calling this function.
EVENTS_EXPORT bool IsTouchpadEvent(const base::NativeEvent& event);
-// Returns true if event is noop.
-EVENTS_EXPORT bool IsNoopEvent(const base::NativeEvent& event);
-
-// Creates and returns no-op event.
-EVENTS_EXPORT base::NativeEvent CreateNoopEvent();
-
#if defined(OS_WIN)
EVENTS_EXPORT int GetModifiersFromACCEL(const ACCEL& accel);
EVENTS_EXPORT int GetModifiersFromKeyState();
@@ -156,11 +165,8 @@ EVENTS_EXPORT bool IsMouseEventFromTouch(UINT message);
// representing an extended key contains 0xE000 bits.
EVENTS_EXPORT uint16 GetScanCodeFromLParam(LPARAM lParam);
EVENTS_EXPORT LPARAM GetLParamFromScanCode(uint16 scan_code);
-#endif
-// Returns true if default post-target handling was canceled for |event| after
-// its dispatch to its target.
-EVENTS_EXPORT bool EventCanceledDefaultHandling(const Event& event);
+#endif
// Registers a custom event type.
EVENTS_EXPORT int RegisterCustomEventType();
diff --git a/chromium/ui/events/events.gyp b/chromium/ui/events/events.gyp
index b7a43136822..890708dab2f 100644
--- a/chromium/ui/events/events.gyp
+++ b/chromium/ui/events/events.gyp
@@ -25,21 +25,27 @@
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '<(DEPTH)/skia/skia.gyp:skia',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'dom4_keycode_converter',
],
'defines': [
'EVENTS_BASE_IMPLEMENTATION',
],
'sources': [
- 'events_base_export.h',
+ 'event_constants.h',
'event_switches.cc',
'event_switches.h',
+ 'events_base_export.h',
+ 'gesture_event_details.cc',
+ 'gesture_event_details.h',
+ 'gestures/gesture_configuration.cc',
+ 'gestures/gesture_configuration.h',
'keycodes/keyboard_code_conversion.cc',
'keycodes/keyboard_code_conversion.h',
'keycodes/keyboard_code_conversion_android.cc',
'keycodes/keyboard_code_conversion_android.h',
- 'keycodes/keyboard_code_conversion_gtk.cc',
- 'keycodes/keyboard_code_conversion_gtk.h',
'keycodes/keyboard_code_conversion_mac.h',
'keycodes/keyboard_code_conversion_mac.mm',
'keycodes/keyboard_code_conversion_win.cc',
@@ -49,17 +55,18 @@
'keycodes/keyboard_codes.h',
'latency_info.cc',
'latency_info.h',
- 'x/device_list_cache_x.cc',
- 'x/device_list_cache_x.h',
'x/device_data_manager.cc',
'x/device_data_manager.h',
+ 'x/device_list_cache_x.cc',
+ 'x/device_list_cache_x.h',
'x/touch_factory_x11.cc',
'x/touch_factory_x11.h',
],
'conditions': [
['use_x11==1', {
'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:x11',
+ '../gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
],
@@ -72,21 +79,26 @@
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'<(DEPTH)/skia/skia.gyp:skia',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'events_base',
+ 'gesture_detection',
],
'defines': [
'EVENTS_IMPLEMENTATION',
],
'sources': [
+ 'cocoa/cocoa_event_utils.h',
+ 'cocoa/cocoa_event_utils.mm',
+ 'cocoa/events_mac.mm',
'event.cc',
'event.h',
- 'event_constants.h',
'event_dispatcher.cc',
'event_dispatcher.h',
'event_handler.cc',
'event_handler.h',
'event_processor.cc',
'event_processor.h',
+ 'event_rewriter.h',
'event_source.cc',
'event_source.h',
'event_target.cc',
@@ -98,54 +110,113 @@
'event_utils.h',
'events_export.h',
'events_stub.cc',
- 'gestures/gesture_configuration.cc',
- 'gestures/gesture_configuration.h',
'gestures/gesture_point.cc',
'gestures/gesture_point.h',
+ 'gestures/gesture_provider_aura.cc',
+ 'gestures/gesture_provider_aura.h',
'gestures/gesture_recognizer.h',
'gestures/gesture_recognizer_impl.cc',
'gestures/gesture_recognizer_impl.h',
+ 'gestures/gesture_recognizer_impl_mac.cc',
'gestures/gesture_sequence.cc',
'gestures/gesture_sequence.h',
- 'gestures/gesture_types.cc',
'gestures/gesture_types.h',
- 'gestures/gesture_util.cc',
- 'gestures/gesture_util.h',
+ 'gestures/motion_event_aura.cc',
+ 'gestures/motion_event_aura.h',
+ 'gestures/unified_gesture_detector_enabled.cc',
+ 'gestures/unified_gesture_detector_enabled.h',
'gestures/velocity_calculator.cc',
'gestures/velocity_calculator.h',
- 'ozone/evdev/event_device_info.cc',
- 'ozone/evdev/event_device_info.h',
- 'ozone/evdev/event_factory.cc',
- 'ozone/evdev/event_factory.h',
- 'ozone/evdev/event_modifiers.cc',
- 'ozone/evdev/event_modifiers.h',
- 'ozone/evdev/key_event_converter.cc',
- 'ozone/evdev/key_event_converter.h',
- 'ozone/evdev/touch_event_converter.cc',
- 'ozone/evdev/touch_event_converter.h',
- 'ozone/event_converter_ozone.cc',
- 'ozone/event_converter_ozone.h',
- 'ozone/event_factory_ozone.cc',
- 'ozone/event_factory_ozone.h',
'ozone/events_ozone.cc',
'win/events_win.cc',
'x/events_x.cc',
+ 'linux/text_edit_command_auralinux.cc',
+ 'linux/text_edit_command_auralinux.h',
+ 'linux/text_edit_key_bindings_delegate_auralinux.cc',
+ 'linux/text_edit_key_bindings_delegate_auralinux.h',
],
'conditions': [
+ ['use_aura==0', {
+ 'sources!': [
+ 'gestures/gesture_point.cc',
+ 'gestures/gesture_point.h',
+ 'gestures/gesture_provider_aura.cc',
+ 'gestures/gesture_provider_aura.h',
+ 'gestures/gesture_recognizer.h',
+ 'gestures/gesture_recognizer_impl.cc',
+ 'gestures/gesture_recognizer_impl.h',
+ 'gestures/gesture_sequence.cc',
+ 'gestures/gesture_sequence.h',
+ 'gestures/gesture_types.h',
+ 'gestures/motion_event_aura.cc',
+ 'gestures/motion_event_aura.h',
+ 'gestures/velocity_calculator.cc',
+ 'gestures/velocity_calculator.h',
+ ],
+ }],
# We explicitly enumerate the platforms we _do_ provide native cracking
# for here.
- ['OS=="win" or use_x11==1 or use_ozone==1', {
+ ['OS=="win" or OS=="mac" or use_x11==1 or use_ozone==1', {
'sources!': [
'events_stub.cc',
],
}],
- ['use_x11==1', {
- 'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:x11',
+ ['chromeos==1', {
+ 'sources!': [
+ 'linux/text_edit_command_auralinux.cc',
+ 'linux/text_edit_command_auralinux.h',
+ 'linux/text_edit_key_bindings_delegate_auralinux.cc',
+ 'linux/text_edit_key_bindings_delegate_auralinux.h',
],
}],
- ['use_ozone_evdev==1', {
- 'defines': ['USE_OZONE_EVDEV=1'],
+ ],
+ },
+ {
+ 'target_name': 'gesture_detection',
+ 'type': '<(component)',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ 'events_base',
+ ],
+ 'defines': [
+ 'GESTURE_DETECTION_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'gesture_detection/bitset_32.h',
+ 'gesture_detection/filtered_gesture_provider.cc',
+ 'gesture_detection/filtered_gesture_provider.h',
+ 'gesture_detection/gesture_config_helper.h',
+ 'gesture_detection/gesture_config_helper_android.cc',
+ 'gesture_detection/gesture_config_helper_aura.cc',
+ 'gesture_detection/gesture_detection_export.h',
+ 'gesture_detection/gesture_detector.cc',
+ 'gesture_detection/gesture_detector.h',
+ 'gesture_detection/gesture_event_data.cc',
+ 'gesture_detection/gesture_event_data.h',
+ 'gesture_detection/gesture_event_data_packet.cc',
+ 'gesture_detection/gesture_event_data_packet.h',
+ 'gesture_detection/gesture_provider.cc',
+ 'gesture_detection/gesture_provider.h',
+ 'gesture_detection/motion_event.h',
+ 'gesture_detection/scale_gesture_detector.cc',
+ 'gesture_detection/scale_gesture_detector.h',
+ 'gesture_detection/snap_scroll_controller.cc',
+ 'gesture_detection/snap_scroll_controller.h',
+ 'gesture_detection/touch_disposition_gesture_filter.cc',
+ 'gesture_detection/touch_disposition_gesture_filter.h',
+ 'gesture_detection/velocity_tracker_state.cc',
+ 'gesture_detection/velocity_tracker_state.h',
+ 'gesture_detection/velocity_tracker.cc',
+ 'gesture_detection/velocity_tracker.h',
+ ],
+ 'conditions': [
+ ['use_aura!=1 and OS!="android"', {
+ 'sources': [
+ 'gesture_detection/gesture_config_helper.cc',
+ ],
}],
],
},
@@ -153,14 +224,22 @@
'target_name': 'events_test_support',
'type': 'static_library',
'dependencies': [
+ '<(DEPTH)/skia/skia.gyp:skia',
'events',
'events_base',
+ 'platform/events_platform.gyp:events_platform',
],
'sources': [
+ 'test/cocoa_test_event_utils.h',
+ 'test/cocoa_test_event_utils.mm',
'test/events_test_utils.cc',
'test/events_test_utils.h',
'test/events_test_utils_x11.cc',
'test/events_test_utils_x11.h',
+ 'test/platform_event_waiter.cc',
+ 'test/platform_event_waiter.h',
+ 'test/test_event_handler.cc',
+ 'test/test_event_handler.h',
'test/test_event_processor.cc',
'test/test_event_processor.h',
'test/test_event_target.cc',
@@ -169,9 +248,14 @@
'conditions': [
['use_x11==1', {
'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:x11',
+ '../gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
+ ['OS=="ios"', {
+ # The cocoa files don't apply to iOS.
+ 'sources/': [['exclude', 'cocoa']],
+ }],
],
},
{
@@ -179,35 +263,90 @@
'type': '<(gtest_target_type)',
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/base/base.gyp:run_all_unittests',
'<(DEPTH)/base/base.gyp:test_support_base',
+ '<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/testing/gtest.gyp:gtest',
- '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../gfx/gfx.gyp:gfx_test_support',
'dom4_keycode_converter',
- 'events_base',
'events',
+ 'events_base',
'events_test_support',
+ 'gesture_detection',
+ 'platform/events_platform.gyp:events_platform',
],
'sources': [
+ 'cocoa/events_mac_unittest.mm',
'event_dispatcher_unittest.cc',
'event_processor_unittest.cc',
+ 'event_rewriter_unittest.cc',
'event_unittest.cc',
+ 'gestures/motion_event_aura_unittest.cc',
'gestures/velocity_calculator_unittest.cc',
+ 'gesture_detection/bitset_32_unittest.cc',
+ 'gesture_detection/gesture_provider_unittest.cc',
+ 'gesture_detection/mock_motion_event.h',
+ 'gesture_detection/mock_motion_event.cc',
+ 'gesture_detection/velocity_tracker_unittest.cc',
+ 'gesture_detection/touch_disposition_gesture_filter_unittest.cc',
'keycodes/dom4/keycode_converter_unittest.cc',
'latency_info_unittest.cc',
- 'test/run_all_unittests.cc',
- 'test/test_suite.cc',
- 'test/test_suite.h',
- 'ozone/evdev/key_event_converter_unittest.cc',
- 'ozone/evdev/touch_event_converter_unittest.cc',
+ 'platform/platform_event_source_unittest.cc',
'x/events_x_unittest.cc',
],
'conditions': [
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['use_ozone==1', {
+ 'sources': [
+ 'ozone/evdev/key_event_converter_evdev_unittest.cc',
+ 'ozone/evdev/touch_event_converter_evdev_unittest.cc',
+ ],
+ 'dependencies': [
+ 'ozone/events_ozone.gyp:events_ozone',
+ 'ozone/events_ozone.gyp:events_ozone_evdev',
+ ]
+ }],
+ ['use_aura==0', {
+ 'sources!': [
+ 'gestures/motion_event_aura_unittest.cc',
+ 'gestures/velocity_calculator_unittest.cc',
+ ],
+ }],
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
],
}],
+ # Exclude tests that rely on event_utils.h for platforms that do not
+ # provide native cracking, i.e., platforms that use events_stub.cc.
+ ['OS!="win" and use_x11!=1 and use_ozone!=1', {
+ 'sources!': [
+ 'event_unittest.cc',
+ ],
+ }],
+ ['OS == "android"', {
+ 'dependencies': [
+ '../../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
],
},
],
+ 'conditions': [
+ ['OS == "android"', {
+ 'targets': [
+ {
+ 'target_name': 'events_unittests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'events_unittests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'events_unittests',
+ },
+ 'includes': [ '../../build/apk_test.gypi' ],
+ },
+ ],
+ }],
+ ],
}
diff --git a/chromium/ui/events/events_stub.cc b/chromium/ui/events/events_stub.cc
index 3d63e4ddf63..2ce911361c1 100644
--- a/chromium/ui/events/events_stub.cc
+++ b/chromium/ui/events/events_stub.cc
@@ -4,6 +4,7 @@
#include "base/logging.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/point.h"
#include "ui/gfx/vector2d.h"
@@ -48,11 +49,6 @@ int EventButtonFromNative(const base::NativeEvent& native_event) {
return 0;
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
- NOTIMPLEMENTED();
- return false;
-}
-
int GetChangedMouseButtonFlagsFromNative(
const base::NativeEvent& native_event) {
NOTIMPLEMENTED();
@@ -64,6 +60,15 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
return gfx::Vector2d();
}
+base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+ NOTIMPLEMENTED() <<
+ "Don't know how to copy base::NativeEvent for this platform";
+ return NULL;
+}
+
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+}
+
void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
NOTIMPLEMENTED();
}
@@ -134,15 +139,6 @@ bool IsTouchpadEvent(const base::NativeEvent& native_event) {
return false;
}
-bool IsNoopEvent(const base::NativeEvent& native_event) {
- NOTIMPLEMENTED();
- return false;
-}
-
-base::NativeEvent CreateNoopEvent() {
- return base::NativeEvent();
-}
-
KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
NOTIMPLEMENTED();
return static_cast<KeyboardCode>(0);
@@ -153,4 +149,9 @@ const char* CodeFromNative(const base::NativeEvent& native_event) {
return "";
}
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/OWNERS b/chromium/ui/events/gesture_detection/OWNERS
new file mode 100644
index 00000000000..3e9a72974f2
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/OWNERS
@@ -0,0 +1,2 @@
+jdduke@chromium.org
+tdresser@chromium.org
diff --git a/chromium/ui/events/gesture_detection/bitset_32.h b/chromium/ui/events/gesture_detection/bitset_32.h
new file mode 100644
index 00000000000..9cb9d48aee6
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/bitset_32.h
@@ -0,0 +1,128 @@
+// 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_GESTURE_DETECTION_BITSET_32_H_
+#define UI_EVENTS_GESTURE_DETECTION_BITSET_32_H_
+
+#include "base/basictypes.h"
+
+namespace ui {
+
+// Port of BitSet32 from Android
+// * platform/system/core/include/utils/BitSet.h
+// * Change-Id: I9bbf41f9d2d4a2593b0e6d7d8be7e283f985bade
+// * Please update the Change-Id as upstream Android changes are pulled.
+struct BitSet32 {
+ uint32_t value;
+
+ inline BitSet32() : value(0) {}
+ explicit inline BitSet32(uint32_t value) : value(value) {}
+
+ // Gets the value associated with a particular bit index.
+ static inline uint32_t value_for_bit(uint32_t n) { return 0x80000000 >> n; }
+
+ // Clears the bit set.
+ inline void clear() { value = 0; }
+
+ // Returns the number of marked bits in the set.
+ inline uint32_t count() const { return popcnt(value); }
+
+ // Returns true if the bit set does not contain any marked bits.
+ inline bool is_empty() const { return !value; }
+
+ // Returns true if the bit set does not contain any unmarked bits.
+ inline bool is_full() const { return value == 0xffffffff; }
+
+ // Returns true if the specified bit is marked.
+ inline bool has_bit(uint32_t n) const {
+ return (value & value_for_bit(n)) != 0;
+ }
+
+ // Marks the specified bit.
+ inline void mark_bit(uint32_t n) { value |= value_for_bit(n); }
+
+ // Clears the specified bit.
+ inline void clear_bit(uint32_t n) { value &= ~value_for_bit(n); }
+
+ // Finds the first marked bit in the set.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t first_marked_bit() const { return clz(value); }
+
+ // Finds the first unmarked bit in the set.
+ // Result is undefined if all bits are marked.
+ inline uint32_t first_unmarked_bit() const { return clz(~value); }
+
+ // Finds the last marked bit in the set.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t last_marked_bit() const { return 31 - ctz(value); }
+
+ // Finds the first marked bit in the set and clears it. Returns the bit
+ // index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clear_first_marked_bit() {
+ uint32_t n = first_marked_bit();
+ clear_bit(n);
+ return n;
+ }
+
+ // Finds the first unmarked bit in the set and marks it. Returns the bit
+ // index.
+ // Result is undefined if all bits are marked.
+ inline uint32_t mark_first_unmarked_bit() {
+ uint32_t n = first_unmarked_bit();
+ mark_bit(n);
+ return n;
+ }
+
+ // Finds the last marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clear_last_marked_bit() {
+ uint32_t n = last_marked_bit();
+ clear_bit(n);
+ return n;
+ }
+
+ // Gets the inde of the specified bit in the set, which is the number of
+ // marked bits that appear before the specified bit.
+ inline uint32_t get_index_of_bit(uint32_t n) const {
+ return popcnt(value & ~(0xffffffffUL >> n));
+ }
+
+ inline bool operator==(const BitSet32& other) const {
+ return value == other.value;
+ }
+ inline bool operator!=(const BitSet32& other) const {
+ return value != other.value;
+ }
+
+ private:
+#if defined(COMPILER_GCC) || defined(__clang__)
+ static inline uint32_t popcnt(uint32_t v) { return __builtin_popcount(v); }
+ static inline uint32_t clz(uint32_t v) { return __builtin_clz(v); }
+ static inline uint32_t ctz(uint32_t v) { return __builtin_ctz(v); }
+#else
+ // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+ static inline uint32_t popcnt(uint32_t v) {
+ v = v - ((v >> 1) & 0x55555555);
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+ return (((v + (v >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+ }
+ // TODO(jdduke): Use intrinsics (BitScan{Forward,Reverse}) with MSVC.
+ static inline uint32_t clz(uint32_t v) {
+ v |= (v >> 1);
+ v |= (v >> 2);
+ v |= (v >> 4);
+ v |= (v >> 8);
+ v |= (v >> 16);
+ return 32 - popcnt(v);
+ }
+ static inline uint32_t ctz(uint32_t v) {
+ return popcnt((v & static_cast<uint32_t>(-static_cast<int>(v))) - 1);
+ }
+#endif
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_BITSET_32_H_
diff --git a/chromium/ui/events/gesture_detection/bitset_32_unittest.cc b/chromium/ui/events/gesture_detection/bitset_32_unittest.cc
new file mode 100644
index 00000000000..2e5d2711e02
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/bitset_32_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/gesture_detection/bitset_32.h"
+
+namespace ui {
+
+class BitSet32Test : public testing::Test {};
+
+TEST_F(BitSet32Test, Basic) {
+ BitSet32 bits;
+
+ // Test the empty set.
+ EXPECT_EQ(0U, bits.count());
+ EXPECT_TRUE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_FALSE(bits.has_bit(0));
+ EXPECT_FALSE(bits.has_bit(31));
+
+ // Mark the first bit.
+ bits.mark_bit(0);
+ EXPECT_EQ(1U, bits.count());
+ EXPECT_FALSE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_TRUE(bits.has_bit(0));
+ EXPECT_FALSE(bits.has_bit(31));
+ EXPECT_EQ(0U, bits.first_marked_bit());
+ EXPECT_EQ(0U, bits.last_marked_bit());
+ EXPECT_EQ(1U, bits.first_unmarked_bit());
+
+ // Mark the last bit.
+ bits.mark_bit(31);
+ EXPECT_EQ(2U, bits.count());
+ EXPECT_FALSE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_TRUE(bits.has_bit(0));
+ EXPECT_TRUE(bits.has_bit(31));
+ EXPECT_FALSE(bits.has_bit(15));
+ EXPECT_EQ(0U, bits.first_marked_bit());
+ EXPECT_EQ(31U, bits.last_marked_bit());
+ EXPECT_EQ(1U, bits.first_unmarked_bit());
+ EXPECT_EQ(0U, bits.get_index_of_bit(0));
+ EXPECT_EQ(1U, bits.get_index_of_bit(1));
+ EXPECT_EQ(1U, bits.get_index_of_bit(2));
+ EXPECT_EQ(1U, bits.get_index_of_bit(31));
+
+ // Clear the first bit.
+ bits.clear_first_marked_bit();
+ EXPECT_EQ(1U, bits.count());
+ EXPECT_FALSE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_FALSE(bits.has_bit(0));
+ EXPECT_TRUE(bits.has_bit(31));
+ EXPECT_EQ(31U, bits.first_marked_bit());
+ EXPECT_EQ(31U, bits.last_marked_bit());
+ EXPECT_EQ(0U, bits.first_unmarked_bit());
+ EXPECT_EQ(0U, bits.get_index_of_bit(0));
+ EXPECT_EQ(0U, bits.get_index_of_bit(1));
+ EXPECT_EQ(0U, bits.get_index_of_bit(31));
+
+ // Clear the last bit (the set should be empty).
+ bits.clear_last_marked_bit();
+ EXPECT_EQ(0U, bits.count());
+ EXPECT_TRUE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_FALSE(bits.has_bit(0));
+ EXPECT_FALSE(bits.has_bit(31));
+ EXPECT_EQ(0U, bits.get_index_of_bit(0));
+ EXPECT_EQ(0U, bits.get_index_of_bit(31));
+ EXPECT_EQ(BitSet32(), bits);
+
+ // Mark the first unmarked bit (bit 0).
+ bits.mark_first_unmarked_bit();
+ EXPECT_EQ(1U, bits.count());
+ EXPECT_FALSE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_TRUE(bits.has_bit(0));
+ EXPECT_EQ(0U, bits.first_marked_bit());
+ EXPECT_EQ(0U, bits.last_marked_bit());
+ EXPECT_EQ(1U, bits.first_unmarked_bit());
+
+ // Mark the next unmarked bit (bit 1).
+ bits.mark_first_unmarked_bit();
+ EXPECT_EQ(2U, bits.count());
+ EXPECT_FALSE(bits.is_empty());
+ EXPECT_FALSE(bits.is_full());
+ EXPECT_TRUE(bits.has_bit(0));
+ EXPECT_TRUE(bits.has_bit(1));
+ EXPECT_EQ(0U, bits.first_marked_bit());
+ EXPECT_EQ(1U, bits.last_marked_bit());
+ EXPECT_EQ(2U, bits.first_unmarked_bit());
+ EXPECT_EQ(0U, bits.get_index_of_bit(0));
+ EXPECT_EQ(1U, bits.get_index_of_bit(1));
+ EXPECT_EQ(2U, bits.get_index_of_bit(2));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc b/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc
new file mode 100644
index 00000000000..76ee5201d1a
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc
@@ -0,0 +1,77 @@
+// 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/events/gesture_detection/filtered_gesture_provider.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace ui {
+
+FilteredGestureProvider::FilteredGestureProvider(
+ const GestureProvider::Config& config,
+ GestureProviderClient* client)
+ : client_(client),
+ gesture_provider_(config, this),
+ gesture_filter_(this),
+ handling_event_(false) {}
+
+bool FilteredGestureProvider::OnTouchEvent(const MotionEvent& event) {
+ DCHECK(!handling_event_);
+ base::AutoReset<bool> handling_event(&handling_event_, true);
+
+ pending_gesture_packet_ = GestureEventDataPacket::FromTouch(event);
+
+ if (!gesture_provider_.OnTouchEvent(event))
+ return false;
+
+ TouchDispositionGestureFilter::PacketResult result =
+ gesture_filter_.OnGesturePacket(pending_gesture_packet_);
+ if (result != TouchDispositionGestureFilter::SUCCESS) {
+ NOTREACHED() << "Invalid touch gesture sequence detected.";
+ return false;
+ }
+
+ return true;
+}
+
+void FilteredGestureProvider::OnTouchEventAck(bool event_consumed) {
+ gesture_filter_.OnTouchEventAck(event_consumed);
+}
+
+void FilteredGestureProvider::SetMultiTouchZoomSupportEnabled(
+ bool enabled) {
+ gesture_provider_.SetMultiTouchZoomSupportEnabled(enabled);
+}
+
+void FilteredGestureProvider::SetDoubleTapSupportForPlatformEnabled(
+ bool enabled) {
+ gesture_provider_.SetDoubleTapSupportForPlatformEnabled(enabled);
+}
+
+void FilteredGestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
+ gesture_provider_.SetDoubleTapSupportForPageEnabled(enabled);
+}
+
+const ui::MotionEvent* FilteredGestureProvider::GetCurrentDownEvent() const {
+ return gesture_provider_.current_down_event();
+}
+
+void FilteredGestureProvider::OnGestureEvent(const GestureEventData& event) {
+ if (handling_event_) {
+ pending_gesture_packet_.Push(event);
+ return;
+ }
+
+ gesture_filter_.OnGesturePacket(
+ GestureEventDataPacket::FromTouchTimeout(event));
+}
+
+void FilteredGestureProvider::ForwardGestureEvent(
+ const GestureEventData& event) {
+ client_->OnGestureEvent(event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/filtered_gesture_provider.h b/chromium/ui/events/gesture_detection/filtered_gesture_provider.h
new file mode 100644
index 00000000000..4d63be64a83
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/filtered_gesture_provider.h
@@ -0,0 +1,61 @@
+// 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_GESTURE_DETECTION_FILTERED_GESTURE_PROVIDER_H_
+#define UI_EVENTS_GESTURE_DETECTION_FILTERED_GESTURE_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "ui/events/gesture_detection/gesture_event_data_packet.h"
+#include "ui/events/gesture_detection/gesture_provider.h"
+#include "ui/events/gesture_detection/touch_disposition_gesture_filter.h"
+
+namespace ui {
+
+// Provides filtered gesture detection and dispatch given a sequence of touch
+// events and touch event acks.
+class GESTURE_DETECTION_EXPORT FilteredGestureProvider
+ : public ui::TouchDispositionGestureFilterClient,
+ public ui::GestureProviderClient {
+ public:
+ // |client| will be offered all gestures detected by the |gesture_provider_|
+ // and allowed by the |gesture_filter_|.
+ FilteredGestureProvider(const GestureProvider::Config& config,
+ GestureProviderClient* client);
+
+ // Returns true if |event| was both valid and successfully handled by the
+ // gesture provider. Otherwise, returns false, in which case the caller
+ // should drop |event|, not forwarding it to the renderer.
+ bool OnTouchEvent(const MotionEvent& event);
+
+ // To be called upon ack of an event that was forwarded after a successful
+ // call to |OnTouchEvent()|.
+ void OnTouchEventAck(bool event_consumed);
+
+ // Methods delegated to |gesture_provider_|.
+ void SetMultiTouchZoomSupportEnabled(bool enabled);
+ void SetDoubleTapSupportForPlatformEnabled(bool enabled);
+ void SetDoubleTapSupportForPageEnabled(bool enabled);
+ const ui::MotionEvent* GetCurrentDownEvent() const;
+
+ private:
+ // GestureProviderClient implementation.
+ virtual void OnGestureEvent(const ui::GestureEventData& event) OVERRIDE;
+
+ // TouchDispositionGestureFilterClient implementation.
+ virtual void ForwardGestureEvent(const ui::GestureEventData& event) OVERRIDE;
+
+ GestureProviderClient* const client_;
+
+ ui::GestureProvider gesture_provider_;
+ ui::TouchDispositionGestureFilter gesture_filter_;
+
+ bool handling_event_;
+ ui::GestureEventDataPacket pending_gesture_packet_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilteredGestureProvider);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_FILTERED_GESTURE_PROVIDER_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_config_helper.cc b/chromium/ui/events/gesture_detection/gesture_config_helper.cc
new file mode 100644
index 00000000000..0039e2c1f93
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_config_helper.cc
@@ -0,0 +1,17 @@
+// 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/events/gesture_detection/gesture_config_helper.h"
+
+#include "ui/gfx/screen.h"
+
+namespace ui {
+
+GestureProvider::Config DefaultGestureProviderConfig() {
+ GestureProvider::Config config;
+ config.display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ return config;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_config_helper.h b/chromium/ui/events/gesture_detection/gesture_config_helper.h
new file mode 100644
index 00000000000..0b54c368786
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_config_helper.h
@@ -0,0 +1,20 @@
+// 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_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_
+
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/gesture_detector.h"
+#include "ui/events/gesture_detection/gesture_provider.h"
+#include "ui/events/gesture_detection/scale_gesture_detector.h"
+
+namespace ui {
+
+GESTURE_DETECTION_EXPORT GestureProvider::Config
+DefaultGestureProviderConfig();
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_config_helper_android.cc b/chromium/ui/events/gesture_detection/gesture_config_helper_android.cc
new file mode 100644
index 00000000000..546cb84e119
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_config_helper_android.cc
@@ -0,0 +1,73 @@
+// 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/events/gesture_detection/gesture_config_helper.h"
+
+#include "ui/gfx/android/view_configuration.h"
+#include "ui/gfx/screen.h"
+
+using gfx::ViewConfiguration;
+
+namespace ui {
+namespace {
+// TODO(jdduke): Adopt GestureConfiguration on Android, crbug/339203.
+
+// This was the minimum tap/press size used on Android before the new gesture
+// detection pipeline.
+const float kMinGestureBoundsLengthDips = 24.f;
+
+GestureDetector::Config DefaultGestureDetectorConfig(
+ const gfx::Display& display) {
+ GestureDetector::Config config;
+
+ config.longpress_timeout = base::TimeDelta::FromMilliseconds(
+ ViewConfiguration::GetLongPressTimeoutInMs());
+ config.showpress_timeout =
+ base::TimeDelta::FromMilliseconds(ViewConfiguration::GetTapTimeoutInMs());
+ config.double_tap_timeout = base::TimeDelta::FromMilliseconds(
+ ViewConfiguration::GetDoubleTapTimeoutInMs());
+
+ const float px_to_dp = 1.f / display.device_scale_factor();
+ config.touch_slop =
+ ViewConfiguration::GetTouchSlopInPixels() * px_to_dp;
+ config.double_tap_slop =
+ ViewConfiguration::GetDoubleTapSlopInPixels() * px_to_dp;
+ config.minimum_fling_velocity =
+ ViewConfiguration::GetMinimumFlingVelocityInPixelsPerSecond() * px_to_dp;
+ config.maximum_fling_velocity =
+ ViewConfiguration::GetMaximumFlingVelocityInPixelsPerSecond() * px_to_dp;
+
+ return config;
+}
+
+ScaleGestureDetector::Config DefaultScaleGestureDetectorConfig(
+ const gfx::Display& display) {
+ ScaleGestureDetector::Config config;
+
+ config.gesture_detector_config = DefaultGestureDetectorConfig(display);
+ config.quick_scale_enabled = true;
+
+ const float px_to_dp = 1.f / display.device_scale_factor();
+ config.min_scaling_touch_major =
+ ViewConfiguration::GetMinScalingTouchMajorInPixels() * px_to_dp;
+ config.min_scaling_span =
+ ViewConfiguration::GetMinScalingSpanInPixels() * px_to_dp;
+
+ return config;
+}
+
+} // namespace
+
+GestureProvider::Config DefaultGestureProviderConfig() {
+ GestureProvider::Config config;
+ config.display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ config.gesture_detector_config = DefaultGestureDetectorConfig(config.display);
+ config.scale_gesture_detector_config =
+ DefaultScaleGestureDetectorConfig(config.display);
+ config.gesture_begin_end_types_enabled = false;
+ config.min_gesture_bounds_length = kMinGestureBoundsLengthDips;
+ return config;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_config_helper_aura.cc b/chromium/ui/events/gesture_detection/gesture_config_helper_aura.cc
new file mode 100644
index 00000000000..36be122b772
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_config_helper_aura.cc
@@ -0,0 +1,73 @@
+// 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.
+
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
+#include "ui/events/gesture_detection/gesture_config_helper.h"
+
+#include <cmath>
+
+#include "ui/events/gestures/gesture_configuration.h"
+#include "ui/gfx/screen.h"
+
+namespace ui {
+namespace {
+
+GestureDetector::Config DefaultGestureDetectorConfig() {
+ GestureDetector::Config config;
+
+ config.longpress_timeout = base::TimeDelta::FromMilliseconds(
+ GestureConfiguration::long_press_time_in_seconds() * 1000.);
+ config.showpress_timeout = base::TimeDelta::FromMilliseconds(
+ GestureConfiguration::show_press_delay_in_ms());
+ config.double_tap_timeout = base::TimeDelta::FromMilliseconds(
+ GestureConfiguration::semi_long_press_time_in_seconds() * 1000.);
+ config.touch_slop =
+ GestureConfiguration::max_touch_move_in_pixels_for_click();
+ config.double_tap_slop =
+ GestureConfiguration::max_distance_between_taps_for_double_tap();
+ config.minimum_fling_velocity =
+ GestureConfiguration::min_scroll_velocity();
+ config.maximum_fling_velocity = GestureConfiguration::fling_velocity_cap();
+ config.swipe_enabled = true;
+ config.minimum_swipe_velocity = GestureConfiguration::min_swipe_speed();
+ config.maximum_swipe_deviation_angle =
+ atan2(1.f, GestureConfiguration::max_swipe_deviation_ratio()) * 180.0f /
+ static_cast<float>(M_PI);
+ config.two_finger_tap_enabled = true;
+ config.two_finger_tap_max_separation =
+ GestureConfiguration::max_distance_for_two_finger_tap_in_pixels();
+ config.two_finger_tap_timeout = base::TimeDelta::FromMilliseconds(
+ GestureConfiguration::max_touch_down_duration_in_seconds_for_click() *
+ 1000.);
+
+ return config;
+}
+
+ScaleGestureDetector::Config DefaultScaleGestureDetectorConfig() {
+ ScaleGestureDetector::Config config;
+
+ config.gesture_detector_config = DefaultGestureDetectorConfig();
+ config.min_scaling_touch_major = GestureConfiguration::default_radius() * 2;
+ config.min_scaling_span = GestureConfiguration::min_scaling_span_in_pixels();
+ config.min_pinch_update_span_delta =
+ GestureConfiguration::min_pinch_update_distance_in_pixels();
+ return config;
+}
+
+} // namespace
+
+GestureProvider::Config DefaultGestureProviderConfig() {
+ GestureProvider::Config config;
+ config.display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ config.gesture_detector_config = DefaultGestureDetectorConfig();
+ config.scale_gesture_detector_config = DefaultScaleGestureDetectorConfig();
+ config.gesture_begin_end_types_enabled = true;
+ // Half the size of the default touch length is a reasonable minimum.
+ config.min_gesture_bounds_length = GestureConfiguration::default_radius();
+ return config;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_detection_export.h b/chromium/ui/events/gesture_detection/gesture_detection_export.h
new file mode 100644
index 00000000000..edef5244be3
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_detection_export.h
@@ -0,0 +1,29 @@
+// 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_GESTURE_DETECTION_GESTURE_DETECTION_EXPORT_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTION_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(GESTURE_DETECTION_IMPLEMENTATION)
+#define GESTURE_DETECTION_EXPORT __declspec(dllexport)
+#else
+#define GESTURE_DETECTION_EXPORT __declspec(dllimport)
+#endif // defined(GESTURES_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GESTURE_DETECTION_IMPLEMENTATION)
+#define GESTURE_DETECTION_EXPORT __attribute__((visibility("default")))
+#else
+#define GESTURE_DETECTION_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GESTURE_DETECTION_EXPORT
+#endif
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTION_EXPORT_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_detector.cc b/chromium/ui/events/gesture_detection/gesture_detector.cc
new file mode 100644
index 00000000000..5dc61938b1a
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_detector.cc
@@ -0,0 +1,553 @@
+// 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.
+
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
+#include "ui/events/gesture_detection/gesture_detector.h"
+
+#include <cmath>
+
+#include "base/timer/timer.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace ui {
+namespace {
+
+// Using a small epsilon when comparing slop distances allows pixel perfect
+// slop determination when using fractional DIP coordinates (assuming the slop
+// region and DPI scale are reasonably proportioned).
+const float kSlopEpsilon = .05f;
+
+// Minimum distance a scroll must have traveled from the last scroll/focal point
+// to trigger an |OnScroll| callback.
+const float kScrollEpsilon = .1f;
+
+const float kDegreesToRadians = static_cast<float>(M_PI) / 180.0f;
+
+// Constants used by TimeoutGestureHandler.
+enum TimeoutEvent {
+ SHOW_PRESS = 0,
+ LONG_PRESS,
+ TAP,
+ TIMEOUT_EVENT_COUNT
+};
+
+} // namespace
+
+// Note: These constants were taken directly from the default (unscaled)
+// versions found in Android's ViewConfiguration.
+GestureDetector::Config::Config()
+ : longpress_timeout(base::TimeDelta::FromMilliseconds(500)),
+ showpress_timeout(base::TimeDelta::FromMilliseconds(180)),
+ double_tap_timeout(base::TimeDelta::FromMilliseconds(300)),
+ double_tap_min_time(base::TimeDelta::FromMilliseconds(40)),
+ touch_slop(8),
+ double_tap_slop(100),
+ minimum_fling_velocity(50),
+ maximum_fling_velocity(8000),
+ swipe_enabled(false),
+ minimum_swipe_velocity(20),
+ maximum_swipe_deviation_angle(20.f),
+ two_finger_tap_enabled(false),
+ two_finger_tap_max_separation(300),
+ two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)) {
+}
+
+GestureDetector::Config::~Config() {}
+
+bool GestureDetector::SimpleGestureListener::OnDown(const MotionEvent& e) {
+ return false;
+}
+
+void GestureDetector::SimpleGestureListener::OnShowPress(const MotionEvent& e) {
+}
+
+bool GestureDetector::SimpleGestureListener::OnSingleTapUp(
+ const MotionEvent& e) {
+ return false;
+}
+
+void GestureDetector::SimpleGestureListener::OnLongPress(const MotionEvent& e) {
+}
+
+bool GestureDetector::SimpleGestureListener::OnScroll(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float distance_x,
+ float distance_y) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnFling(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnSwipe(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnTwoFingerTap(
+ const MotionEvent& e1,
+ const MotionEvent& e2) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnSingleTapConfirmed(
+ const MotionEvent& e) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnDoubleTap(const MotionEvent& e) {
+ return false;
+}
+
+bool GestureDetector::SimpleGestureListener::OnDoubleTapEvent(
+ const MotionEvent& e) {
+ return false;
+}
+
+class GestureDetector::TimeoutGestureHandler {
+ public:
+ TimeoutGestureHandler(const Config& config, GestureDetector* gesture_detector)
+ : gesture_detector_(gesture_detector) {
+ DCHECK(config.showpress_timeout <= config.longpress_timeout);
+
+ timeout_callbacks_[SHOW_PRESS] = &GestureDetector::OnShowPressTimeout;
+ timeout_delays_[SHOW_PRESS] = config.showpress_timeout;
+
+ timeout_callbacks_[LONG_PRESS] = &GestureDetector::OnLongPressTimeout;
+ timeout_delays_[LONG_PRESS] =
+ config.longpress_timeout + config.showpress_timeout;
+
+ timeout_callbacks_[TAP] = &GestureDetector::OnTapTimeout;
+ timeout_delays_[TAP] = config.double_tap_timeout;
+ }
+
+ ~TimeoutGestureHandler() {
+ Stop();
+ }
+
+ void StartTimeout(TimeoutEvent event) {
+ timeout_timers_[event].Start(FROM_HERE,
+ timeout_delays_[event],
+ gesture_detector_,
+ timeout_callbacks_[event]);
+ }
+
+ void StopTimeout(TimeoutEvent event) { timeout_timers_[event].Stop(); }
+
+ void Stop() {
+ for (size_t i = SHOW_PRESS; i < TIMEOUT_EVENT_COUNT; ++i)
+ timeout_timers_[i].Stop();
+ }
+
+ bool HasTimeout(TimeoutEvent event) const {
+ return timeout_timers_[event].IsRunning();
+ }
+
+ private:
+ typedef void (GestureDetector::*ReceiverMethod)();
+
+ GestureDetector* const gesture_detector_;
+ base::OneShotTimer<GestureDetector> timeout_timers_[TIMEOUT_EVENT_COUNT];
+ ReceiverMethod timeout_callbacks_[TIMEOUT_EVENT_COUNT];
+ base::TimeDelta timeout_delays_[TIMEOUT_EVENT_COUNT];
+};
+
+GestureDetector::GestureDetector(
+ const Config& config,
+ GestureListener* listener,
+ DoubleTapListener* optional_double_tap_listener)
+ : timeout_handler_(new TimeoutGestureHandler(config, this)),
+ listener_(listener),
+ double_tap_listener_(optional_double_tap_listener),
+ touch_slop_square_(0),
+ double_tap_touch_slop_square_(0),
+ double_tap_slop_square_(0),
+ two_finger_tap_distance_square_(0),
+ min_fling_velocity_(1),
+ max_fling_velocity_(1),
+ min_swipe_velocity_(0),
+ min_swipe_direction_component_ratio_(0),
+ still_down_(false),
+ defer_confirm_single_tap_(false),
+ always_in_tap_region_(false),
+ always_in_bigger_tap_region_(false),
+ two_finger_tap_allowed_for_gesture_(false),
+ is_double_tapping_(false),
+ last_focus_x_(0),
+ last_focus_y_(0),
+ down_focus_x_(0),
+ down_focus_y_(0),
+ longpress_enabled_(true),
+ swipe_enabled_(false),
+ two_finger_tap_enabled_(false) {
+ DCHECK(listener_);
+ Init(config);
+}
+
+GestureDetector::~GestureDetector() {}
+
+bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
+ const MotionEvent::Action action = ev.GetAction();
+
+ velocity_tracker_.AddMovement(ev);
+
+ const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP;
+ const int skip_index = pointer_up ? ev.GetActionIndex() : -1;
+
+ // Determine focal point.
+ float sum_x = 0, sum_y = 0;
+ const int count = static_cast<int>(ev.GetPointerCount());
+ for (int i = 0; i < count; i++) {
+ if (skip_index == i)
+ continue;
+ sum_x += ev.GetX(i);
+ sum_y += ev.GetY(i);
+ }
+ const int div = pointer_up ? count - 1 : count;
+ const float focus_x = sum_x / div;
+ const float focus_y = sum_y / div;
+
+ bool handled = false;
+
+ switch (action) {
+ case MotionEvent::ACTION_POINTER_DOWN: {
+ down_focus_x_ = last_focus_x_ = focus_x;
+ down_focus_y_ = last_focus_y_ = focus_y;
+ // Cancel long press and taps.
+ CancelTaps();
+
+ if (!two_finger_tap_allowed_for_gesture_)
+ break;
+
+ const int action_index = ev.GetActionIndex();
+ const float dx = ev.GetX(action_index) - current_down_event_->GetX();
+ const float dy = ev.GetY(action_index) - current_down_event_->GetY();
+
+ if (ev.GetPointerCount() == 2 &&
+ dx * dx + dy * dy < two_finger_tap_distance_square_) {
+ secondary_pointer_down_event_ = ev.Clone();
+ } else {
+ two_finger_tap_allowed_for_gesture_ = false;
+ }
+ } break;
+
+ case MotionEvent::ACTION_POINTER_UP: {
+ down_focus_x_ = last_focus_x_ = focus_x;
+ down_focus_y_ = last_focus_y_ = focus_y;
+
+ // Check the dot product of current velocities.
+ // If the pointer that left was opposing another velocity vector, clear.
+ velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
+ const int up_index = ev.GetActionIndex();
+ const int id1 = ev.GetPointerId(up_index);
+ const float vx1 = velocity_tracker_.GetXVelocity(id1);
+ const float vy1 = velocity_tracker_.GetYVelocity(id1);
+ float vx_total = vx1;
+ float vy_total = vy1;
+ for (int i = 0; i < count; i++) {
+ if (i == up_index)
+ continue;
+
+ const int id2 = ev.GetPointerId(i);
+ const float vx2 = velocity_tracker_.GetXVelocity(id2);
+ const float vy2 = velocity_tracker_.GetYVelocity(id2);
+ const float dot = vx1 * vx2 + vy1 * vy2;
+ if (dot < 0) {
+ vx_total = 0;
+ vy_total = 0;
+ velocity_tracker_.Clear();
+ break;
+ }
+ vx_total += vx2;
+ vy_total += vy2;
+ }
+
+ handled = HandleSwipeIfNeeded(ev, vx_total / count, vy_total / count);
+
+ if (two_finger_tap_allowed_for_gesture_ && ev.GetPointerCount() == 2 &&
+ (ev.GetEventTime() - secondary_pointer_down_event_->GetEventTime() <=
+ two_finger_tap_timeout_)) {
+ handled = listener_->OnTwoFingerTap(*current_down_event_, ev);
+ }
+ two_finger_tap_allowed_for_gesture_ = false;
+ } break;
+
+ case MotionEvent::ACTION_DOWN:
+ if (double_tap_listener_) {
+ bool had_tap_message = timeout_handler_->HasTimeout(TAP);
+ if (had_tap_message)
+ timeout_handler_->StopTimeout(TAP);
+ if (current_down_event_ && previous_up_event_ && had_tap_message &&
+ IsConsideredDoubleTap(
+ *current_down_event_, *previous_up_event_, ev)) {
+ // This is a second tap.
+ is_double_tapping_ = true;
+ // Give a callback with the first tap of the double-tap.
+ handled |= double_tap_listener_->OnDoubleTap(*current_down_event_);
+ // Give a callback with down event of the double-tap.
+ handled |= double_tap_listener_->OnDoubleTapEvent(ev);
+ } else {
+ // This is a first tap.
+ DCHECK(double_tap_timeout_ > base::TimeDelta());
+ timeout_handler_->StartTimeout(TAP);
+ }
+ }
+
+ down_focus_x_ = last_focus_x_ = focus_x;
+ down_focus_y_ = last_focus_y_ = focus_y;
+ current_down_event_ = ev.Clone();
+
+ secondary_pointer_down_event_.reset();
+ always_in_tap_region_ = true;
+ always_in_bigger_tap_region_ = true;
+ still_down_ = true;
+ defer_confirm_single_tap_ = false;
+ two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_;
+
+ // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure
+ // proper timeout ordering.
+ timeout_handler_->StartTimeout(SHOW_PRESS);
+ if (longpress_enabled_)
+ timeout_handler_->StartTimeout(LONG_PRESS);
+ handled |= listener_->OnDown(ev);
+ break;
+
+ case MotionEvent::ACTION_MOVE:
+ {
+ const float scroll_x = last_focus_x_ - focus_x;
+ const float scroll_y = last_focus_y_ - focus_y;
+ if (is_double_tapping_) {
+ // Give the move events of the double-tap.
+ DCHECK(double_tap_listener_);
+ handled |= double_tap_listener_->OnDoubleTapEvent(ev);
+ } else if (always_in_tap_region_) {
+ const float delta_x = focus_x - down_focus_x_;
+ const float delta_y = focus_y - down_focus_y_;
+ const float distance_square = delta_x * delta_x + delta_y * delta_y;
+ if (distance_square > touch_slop_square_) {
+ handled = listener_->OnScroll(
+ *current_down_event_, ev, scroll_x, scroll_y);
+ last_focus_x_ = focus_x;
+ last_focus_y_ = focus_y;
+ always_in_tap_region_ = false;
+ timeout_handler_->Stop();
+ }
+ if (distance_square > double_tap_touch_slop_square_)
+ always_in_bigger_tap_region_ = false;
+ } else if (std::abs(scroll_x) > kScrollEpsilon ||
+ std::abs(scroll_y) > kScrollEpsilon) {
+ handled =
+ listener_->OnScroll(*current_down_event_, ev, scroll_x, scroll_y);
+ last_focus_x_ = focus_x;
+ last_focus_y_ = focus_y;
+ }
+
+ if (!two_finger_tap_allowed_for_gesture_)
+ break;
+
+ // Two-finger tap should be prevented if either pointer exceeds its
+ // (independent) slop region.
+ const int id0 = current_down_event_->GetPointerId(0);
+ const int ev_idx0 = ev.GetPointerId(0) == id0 ? 0 : 1;
+
+ // Check if the primary pointer exceeded the slop region.
+ float dx = current_down_event_->GetX() - ev.GetX(ev_idx0);
+ float dy = current_down_event_->GetY() - ev.GetY(ev_idx0);
+ if (dx * dx + dy * dy > touch_slop_square_) {
+ two_finger_tap_allowed_for_gesture_ = false;
+ break;
+ }
+ if (ev.GetPointerCount() == 2) {
+ // Check if the secondary pointer exceeded the slop region.
+ const int ev_idx1 = ev_idx0 == 0 ? 1 : 0;
+ const int idx1 = secondary_pointer_down_event_->GetActionIndex();
+ dx = secondary_pointer_down_event_->GetX(idx1) - ev.GetX(ev_idx1);
+ dy = secondary_pointer_down_event_->GetY(idx1) - ev.GetY(ev_idx1);
+ if (dx * dx + dy * dy > touch_slop_square_)
+ two_finger_tap_allowed_for_gesture_ = false;
+ }
+ }
+ break;
+
+ case MotionEvent::ACTION_UP:
+ still_down_ = false;
+ {
+ if (is_double_tapping_) {
+ // Finally, give the up event of the double-tap.
+ DCHECK(double_tap_listener_);
+ handled |= double_tap_listener_->OnDoubleTapEvent(ev);
+ } else if (always_in_tap_region_) {
+ handled = listener_->OnSingleTapUp(ev);
+ if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) {
+ double_tap_listener_->OnSingleTapConfirmed(ev);
+ }
+ } else {
+
+ // A fling must travel the minimum tap distance.
+ const int pointer_id = ev.GetPointerId(0);
+ velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
+ const float velocity_y = velocity_tracker_.GetYVelocity(pointer_id);
+ const float velocity_x = velocity_tracker_.GetXVelocity(pointer_id);
+
+ if ((std::abs(velocity_y) > min_fling_velocity_) ||
+ (std::abs(velocity_x) > min_fling_velocity_)) {
+ handled = listener_->OnFling(
+ *current_down_event_, ev, velocity_x, velocity_y);
+ }
+
+ handled |= HandleSwipeIfNeeded(ev, velocity_x, velocity_y);
+ }
+
+ previous_up_event_ = ev.Clone();
+
+ velocity_tracker_.Clear();
+ is_double_tapping_ = false;
+ defer_confirm_single_tap_ = false;
+ timeout_handler_->StopTimeout(SHOW_PRESS);
+ timeout_handler_->StopTimeout(LONG_PRESS);
+ }
+ break;
+
+ case MotionEvent::ACTION_CANCEL:
+ Cancel();
+ break;
+ }
+
+ return handled;
+}
+
+void GestureDetector::SetDoubleTapListener(
+ DoubleTapListener* double_tap_listener) {
+ if (double_tap_listener == double_tap_listener_)
+ return;
+
+ DCHECK(!is_double_tapping_);
+
+ // Null'ing the double-tap listener should flush an active tap timeout.
+ if (!double_tap_listener) {
+ if (timeout_handler_->HasTimeout(TAP)) {
+ timeout_handler_->StopTimeout(TAP);
+ OnTapTimeout();
+ }
+ }
+
+ double_tap_listener_ = double_tap_listener;
+}
+
+void GestureDetector::Init(const Config& config) {
+ DCHECK(listener_);
+
+ const float touch_slop = config.touch_slop + kSlopEpsilon;
+ const float double_tap_touch_slop = touch_slop;
+ const float double_tap_slop = config.double_tap_slop + kSlopEpsilon;
+ touch_slop_square_ = touch_slop * touch_slop;
+ double_tap_touch_slop_square_ = double_tap_touch_slop * double_tap_touch_slop;
+ double_tap_slop_square_ = double_tap_slop * double_tap_slop;
+ double_tap_timeout_ = config.double_tap_timeout;
+ double_tap_min_time_ = config.double_tap_min_time;
+ DCHECK(double_tap_min_time_ < double_tap_timeout_);
+ min_fling_velocity_ = config.minimum_fling_velocity;
+ max_fling_velocity_ = config.maximum_fling_velocity;
+
+ swipe_enabled_ = config.swipe_enabled;
+ min_swipe_velocity_ = config.minimum_swipe_velocity;
+ DCHECK_GT(config.maximum_swipe_deviation_angle, 0);
+ DCHECK_LE(config.maximum_swipe_deviation_angle, 45);
+ const float maximum_swipe_deviation_angle =
+ std::min(45.f, std::max(0.001f, config.maximum_swipe_deviation_angle));
+ min_swipe_direction_component_ratio_ =
+ 1.f / tan(maximum_swipe_deviation_angle * kDegreesToRadians);
+
+ two_finger_tap_enabled_ = config.two_finger_tap_enabled;
+ two_finger_tap_distance_square_ = config.two_finger_tap_max_separation *
+ config.two_finger_tap_max_separation;
+ two_finger_tap_timeout_ = config.two_finger_tap_timeout;
+}
+
+void GestureDetector::OnShowPressTimeout() {
+ listener_->OnShowPress(*current_down_event_);
+}
+
+void GestureDetector::OnLongPressTimeout() {
+ timeout_handler_->StopTimeout(TAP);
+ defer_confirm_single_tap_ = false;
+ listener_->OnLongPress(*current_down_event_);
+}
+
+void GestureDetector::OnTapTimeout() {
+ if (!double_tap_listener_)
+ return;
+ if (!still_down_)
+ double_tap_listener_->OnSingleTapConfirmed(*current_down_event_);
+ else
+ defer_confirm_single_tap_ = true;
+}
+
+void GestureDetector::Cancel() {
+ CancelTaps();
+ velocity_tracker_.Clear();
+ still_down_ = false;
+}
+
+void GestureDetector::CancelTaps() {
+ timeout_handler_->Stop();
+ is_double_tapping_ = false;
+ always_in_tap_region_ = false;
+ always_in_bigger_tap_region_ = false;
+ defer_confirm_single_tap_ = false;
+}
+
+bool GestureDetector::IsConsideredDoubleTap(
+ const MotionEvent& first_down,
+ const MotionEvent& first_up,
+ const MotionEvent& second_down) const {
+ if (!always_in_bigger_tap_region_)
+ return false;
+
+ const base::TimeDelta delta_time =
+ second_down.GetEventTime() - first_up.GetEventTime();
+ if (delta_time < double_tap_min_time_ || delta_time > double_tap_timeout_)
+ return false;
+
+ const float delta_x = first_down.GetX() - second_down.GetX();
+ const float delta_y = first_down.GetY() - second_down.GetY();
+ return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_);
+}
+
+bool GestureDetector::HandleSwipeIfNeeded(const MotionEvent& up,
+ float vx,
+ float vy) {
+ if (!swipe_enabled_ || (!vx && !vy))
+ return false;
+ float vx_abs = std::abs(vx);
+ float vy_abs = std::abs(vy);
+
+ if (vx_abs < min_swipe_velocity_)
+ vx_abs = vx = 0;
+ if (vy_abs < min_swipe_velocity_)
+ vy_abs = vy = 0;
+
+ // Note that the ratio will be 0 if both velocites are below the min.
+ float ratio = vx_abs > vy_abs ? vx_abs / std::max(vy_abs, 0.001f)
+ : vy_abs / std::max(vx_abs, 0.001f);
+
+ if (ratio < min_swipe_direction_component_ratio_)
+ return false;
+
+ if (vx_abs > vy_abs)
+ vy = 0;
+ else
+ vx = 0;
+ return listener_->OnSwipe(*current_down_event_, up, vx, vy);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_detector.h b/chromium/ui/events/gesture_detection/gesture_detector.h
new file mode 100644
index 00000000000..db665f8cbcd
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_detector.h
@@ -0,0 +1,214 @@
+// 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_GESTURE_DETECTION_GESTURE_DETECTOR_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/velocity_tracker_state.h"
+
+namespace ui {
+
+class MotionEvent;
+
+// Port of GestureDetector.java from Android
+// * platform/frameworks/base/core/java/android/view/GestureDetector.java
+// * Change-Id: Ib470735ec929b0b358fca4597e92dc81084e675f
+// * Please update the Change-Id as upstream Android changes are pulled.
+class GestureDetector {
+ public:
+ struct GESTURE_DETECTION_EXPORT Config {
+ Config();
+ ~Config();
+
+ base::TimeDelta longpress_timeout;
+ base::TimeDelta showpress_timeout;
+ base::TimeDelta double_tap_timeout;
+
+ // The minimum duration between the first tap's up event and the second
+ // tap's down event for an interaction to be considered a double-tap.
+ base::TimeDelta double_tap_min_time;
+
+ // Distance a touch can wander before a scroll will occur (in dips).
+ float touch_slop;
+
+ // Distance the first touch can wander before it is no longer considered a
+ // double tap (in dips).
+ float double_tap_slop;
+
+ // Minimum velocity to initiate a fling (in dips/second).
+ float minimum_fling_velocity;
+
+ // Maximum velocity of an initiated fling (in dips/second).
+ float maximum_fling_velocity;
+
+ // Whether |OnSwipe| should be called after a secondary touch is released
+ // while a logical swipe gesture is active. Defaults to false.
+ bool swipe_enabled;
+
+ // Minimum velocity to initiate a swipe (in dips/second).
+ float minimum_swipe_velocity;
+
+ // Maximum angle of the swipe from its dominant component axis, between
+ // (0, 45] degrees. The closer this is to 0, the closer the dominant
+ // direction of the swipe must be to up, down left or right.
+ float maximum_swipe_deviation_angle;
+
+ // Whether |OnTwoFingerTap| should be called for two finger tap
+ // gestures. Defaults to false.
+ bool two_finger_tap_enabled;
+
+ // Maximum distance between pointers for a two finger tap.
+ float two_finger_tap_max_separation;
+
+ // Maximum time the second pointer can be active for a two finger tap.
+ base::TimeDelta two_finger_tap_timeout;
+ };
+
+ class GestureListener {
+ public:
+ virtual ~GestureListener() {}
+ virtual bool OnDown(const MotionEvent& e) = 0;
+ virtual void OnShowPress(const MotionEvent& e) = 0;
+ virtual bool OnSingleTapUp(const MotionEvent& e) = 0;
+ virtual void OnLongPress(const MotionEvent& e) = 0;
+ virtual bool OnScroll(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float distance_x,
+ float distance_y) = 0;
+ virtual bool OnFling(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) = 0;
+ // Added for Chromium (Aura).
+ virtual bool OnSwipe(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) = 0;
+ virtual bool OnTwoFingerTap(const MotionEvent& e1,
+ const MotionEvent& e2) = 0;
+ };
+
+ class DoubleTapListener {
+ public:
+ virtual ~DoubleTapListener() {}
+ virtual bool OnSingleTapConfirmed(const MotionEvent& e) = 0;
+ virtual bool OnDoubleTap(const MotionEvent& e) = 0;
+ virtual bool OnDoubleTapEvent(const MotionEvent& e) = 0;
+ };
+
+ // A convenience class to extend when you only want to listen for a subset
+ // of all the gestures. This implements all methods in the
+ // |GestureListener| and |DoubleTapListener| but does
+ // nothing and returns false for all applicable methods.
+ class SimpleGestureListener : public GestureListener,
+ public DoubleTapListener {
+ public:
+ // GestureListener implementation.
+ virtual bool OnDown(const MotionEvent& e) OVERRIDE;
+ virtual void OnShowPress(const MotionEvent& e) OVERRIDE;
+ virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE;
+ virtual void OnLongPress(const MotionEvent& e) OVERRIDE;
+ virtual bool OnScroll(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float distance_x,
+ float distance_y) OVERRIDE;
+ virtual bool OnFling(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) OVERRIDE;
+ virtual bool OnSwipe(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) OVERRIDE;
+ virtual bool OnTwoFingerTap(const MotionEvent& e1,
+ const MotionEvent& e2) OVERRIDE;
+
+ // DoubleTapListener implementation.
+ virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE;
+ virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE;
+ virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE;
+ };
+
+ GestureDetector(const Config& config,
+ GestureListener* listener,
+ DoubleTapListener* optional_double_tap_listener);
+ ~GestureDetector();
+
+ bool OnTouchEvent(const MotionEvent& ev);
+
+ // Setting a valid |double_tap_listener| will enable double-tap detection,
+ // wherein calls to |OnSimpleTapConfirmed| are delayed by the tap timeout.
+ // Note: The listener must never be changed while |is_double_tapping| is true.
+ void SetDoubleTapListener(DoubleTapListener* double_tap_listener);
+
+ bool has_doubletap_listener() const { return double_tap_listener_ != NULL; }
+
+ bool is_double_tapping() const { return is_double_tapping_; }
+
+ void set_longpress_enabled(bool enabled) { longpress_enabled_ = enabled; }
+
+ private:
+ void Init(const Config& config);
+ void OnShowPressTimeout();
+ void OnLongPressTimeout();
+ void OnTapTimeout();
+ void Cancel();
+ void CancelTaps();
+ bool IsConsideredDoubleTap(const MotionEvent& first_down,
+ const MotionEvent& first_up,
+ const MotionEvent& second_down) const;
+ bool HandleSwipeIfNeeded(const MotionEvent& up, float vx, float vy);
+
+ class TimeoutGestureHandler;
+ scoped_ptr<TimeoutGestureHandler> timeout_handler_;
+ GestureListener* const listener_;
+ DoubleTapListener* double_tap_listener_;
+
+ float touch_slop_square_;
+ float double_tap_touch_slop_square_;
+ float double_tap_slop_square_;
+ float two_finger_tap_distance_square_;
+ float min_fling_velocity_;
+ float max_fling_velocity_;
+ float min_swipe_velocity_;
+ float min_swipe_direction_component_ratio_;
+ base::TimeDelta double_tap_timeout_;
+ base::TimeDelta two_finger_tap_timeout_;
+ base::TimeDelta double_tap_min_time_;
+
+ bool still_down_;
+ bool defer_confirm_single_tap_;
+ bool always_in_tap_region_;
+ bool always_in_bigger_tap_region_;
+ bool two_finger_tap_allowed_for_gesture_;
+
+ scoped_ptr<MotionEvent> current_down_event_;
+ scoped_ptr<MotionEvent> previous_up_event_;
+ scoped_ptr<MotionEvent> secondary_pointer_down_event_;
+
+ // True when the user is still touching for the second tap (down, move, and
+ // up events). Can only be true if there is a double tap listener attached.
+ bool is_double_tapping_;
+
+ float last_focus_x_;
+ float last_focus_y_;
+ float down_focus_x_;
+ float down_focus_y_;
+
+ bool longpress_enabled_;
+ bool swipe_enabled_;
+ bool two_finger_tap_enabled_;
+
+ // Determines speed during touch scrolling.
+ VelocityTrackerState velocity_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureDetector);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_event_data.cc b/chromium/ui/events/gesture_detection/gesture_event_data.cc
new file mode 100644
index 00000000000..42d1d009992
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_event_data.cc
@@ -0,0 +1,50 @@
+// 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/events/gesture_detection/gesture_event_data.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+GestureEventData::GestureEventData(const GestureEventDetails& details,
+ int motion_event_id,
+ base::TimeTicks time,
+ float x,
+ float y,
+ float raw_x,
+ float raw_y,
+ size_t touch_point_count,
+ const gfx::RectF& bounding_box)
+ : details(details),
+ motion_event_id(motion_event_id),
+ time(time),
+ x(x),
+ y(y),
+ raw_x(raw_x),
+ raw_y(raw_y) {
+ DCHECK_GE(motion_event_id, 0);
+ DCHECK_NE(0U, touch_point_count);
+ this->details.set_touch_points(static_cast<int>(touch_point_count));
+ this->details.set_bounding_box(bounding_box);
+}
+
+GestureEventData::GestureEventData(EventType type,
+ const GestureEventData& other)
+ : details(type, 0, 0),
+ motion_event_id(other.motion_event_id),
+ time(other.time),
+ x(other.x),
+ y(other.y),
+ raw_x(other.raw_x),
+ raw_y(other.raw_y) {
+ details.set_touch_points(other.details.touch_points());
+ details.set_bounding_box(other.details.bounding_box_f());
+}
+
+GestureEventData::GestureEventData()
+ : motion_event_id(0), x(0), y(0), raw_x(0), raw_y(0) {
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_event_data.h b/chromium/ui/events/gesture_detection/gesture_event_data.h
new file mode 100644
index 00000000000..35eb41e2c77
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_event_data.h
@@ -0,0 +1,48 @@
+// 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_GESTURE_DETECTION_GESTURE_EVENT_DATA_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DATA_H_
+
+#include "base/time/time.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_event_details.h"
+
+namespace ui {
+
+class GestureEventDataPacket;
+
+struct GESTURE_DETECTION_EXPORT GestureEventData {
+ GestureEventData(const GestureEventDetails&,
+ int motion_event_id,
+ base::TimeTicks time,
+ float x,
+ float y,
+ float raw_x,
+ float raw_y,
+ size_t touch_point_count,
+ const gfx::RectF& bounding_box);
+ GestureEventData(EventType type, const GestureEventData&);
+
+ EventType type() const { return details.type(); }
+
+ GestureEventDetails details;
+ int motion_event_id;
+ base::TimeTicks time;
+ float x;
+ float y;
+ float raw_x;
+ float raw_y;
+
+ private:
+ friend class GestureEventDataPacket;
+
+ // Initializes type to GESTURE_TYPE_INVALID.
+ GestureEventData();
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DATA_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc b/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc
new file mode 100644
index 00000000000..09adceca475
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc
@@ -0,0 +1,96 @@
+// 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/events/gesture_detection/gesture_event_data_packet.h"
+
+#include "base/logging.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace ui {
+namespace {
+
+GestureEventDataPacket::GestureSource ToGestureSource(
+ const ui::MotionEvent& event) {
+ switch (event.GetAction()) {
+ case ui::MotionEvent::ACTION_DOWN:
+ return GestureEventDataPacket::TOUCH_SEQUENCE_START;
+ case ui::MotionEvent::ACTION_UP:
+ return GestureEventDataPacket::TOUCH_SEQUENCE_END;
+ case ui::MotionEvent::ACTION_MOVE:
+ return GestureEventDataPacket::TOUCH_MOVE;
+ case ui::MotionEvent::ACTION_CANCEL:
+ return GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL;
+ case ui::MotionEvent::ACTION_POINTER_DOWN:
+ return GestureEventDataPacket::TOUCH_START;
+ case ui::MotionEvent::ACTION_POINTER_UP:
+ return GestureEventDataPacket::TOUCH_END;
+ };
+ NOTREACHED() << "Invalid ui::MotionEvent action: " << event.GetAction();
+ return GestureEventDataPacket::INVALID;
+}
+
+} // namespace
+
+GestureEventDataPacket::GestureEventDataPacket()
+ : gesture_source_(UNDEFINED) {
+}
+
+GestureEventDataPacket::GestureEventDataPacket(
+ base::TimeTicks timestamp,
+ GestureSource source,
+ const gfx::PointF& touch_location,
+ const gfx::PointF& raw_touch_location)
+ : timestamp_(timestamp),
+ touch_location_(touch_location),
+ raw_touch_location_(raw_touch_location),
+ gesture_source_(source) {
+ DCHECK_NE(gesture_source_, UNDEFINED);
+}
+
+GestureEventDataPacket::GestureEventDataPacket(
+ const GestureEventDataPacket& other)
+ : timestamp_(other.timestamp_),
+ gestures_(other.gestures_),
+ touch_location_(other.touch_location_),
+ raw_touch_location_(other.raw_touch_location_),
+ gesture_source_(other.gesture_source_) {
+}
+
+GestureEventDataPacket::~GestureEventDataPacket() {
+}
+
+GestureEventDataPacket& GestureEventDataPacket::operator=(
+ const GestureEventDataPacket& other) {
+ timestamp_ = other.timestamp_;
+ gesture_source_ = other.gesture_source_;
+ touch_location_ = other.touch_location_;
+ raw_touch_location_ = other.raw_touch_location_;
+ gestures_ = other.gestures_;
+ return *this;
+}
+
+void GestureEventDataPacket::Push(const GestureEventData& gesture) {
+ DCHECK_NE(ET_UNKNOWN, gesture.type());
+ gestures_.push_back(gesture);
+}
+
+GestureEventDataPacket GestureEventDataPacket::FromTouch(
+ const ui::MotionEvent& touch) {
+ return GestureEventDataPacket(touch.GetEventTime(),
+ ToGestureSource(touch),
+ gfx::PointF(touch.GetX(), touch.GetY()),
+ gfx::PointF(touch.GetRawX(), touch.GetRawY()));
+}
+
+GestureEventDataPacket GestureEventDataPacket::FromTouchTimeout(
+ const GestureEventData& gesture) {
+ GestureEventDataPacket packet(gesture.time,
+ TOUCH_TIMEOUT,
+ gfx::PointF(gesture.x, gesture.y),
+ gfx::PointF(gesture.raw_x, gesture.raw_y));
+ packet.Push(gesture);
+ return packet;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_event_data_packet.h b/chromium/ui/events/gesture_detection/gesture_event_data_packet.h
new file mode 100644
index 00000000000..0c40f576784
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_event_data_packet.h
@@ -0,0 +1,68 @@
+// 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_GESTURE_DETECTION_GESTURE_EVENT_DATA_PACKET_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DATA_PACKET_H_
+
+#include <vector>
+
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
+
+namespace ui {
+
+class MotionEvent;
+
+// Acts as a transport container for gestures created (directly or indirectly)
+// by a touch event.
+class GESTURE_DETECTION_EXPORT GestureEventDataPacket {
+ public:
+ enum GestureSource {
+ UNDEFINED = -1, // Used only for a default-constructed packet.
+ INVALID, // The source of the gesture was invalid.
+ TOUCH_SEQUENCE_START, // The start of a new gesture sequence.
+ TOUCH_SEQUENCE_END, // The end of a gesture sequence.
+ TOUCH_SEQUENCE_CANCEL, // The gesture sequence was cancelled.
+ TOUCH_START, // A touch down occured during a gesture sequence.
+ TOUCH_MOVE, // A touch move occured during a gesture sequence.
+ TOUCH_END, // A touch up occured during a gesture sequence.
+ TOUCH_TIMEOUT, // Timeout from an existing gesture sequence.
+ };
+
+ GestureEventDataPacket();
+ GestureEventDataPacket(const GestureEventDataPacket& other);
+ ~GestureEventDataPacket();
+ GestureEventDataPacket& operator=(const GestureEventDataPacket& other);
+
+ // Factory methods for creating a packet from a particular event.
+ static GestureEventDataPacket FromTouch(const ui::MotionEvent& touch);
+ static GestureEventDataPacket FromTouchTimeout(
+ const GestureEventData& gesture);
+
+ void Push(const GestureEventData& gesture);
+
+ const base::TimeTicks& timestamp() const { return timestamp_; }
+ const GestureEventData& gesture(size_t i) const { return gestures_[i]; }
+ size_t gesture_count() const { return gestures_.size(); }
+ GestureSource gesture_source() const { return gesture_source_; }
+ const gfx::PointF& touch_location() const { return touch_location_; }
+ const gfx::PointF& raw_touch_location() const { return raw_touch_location_; }
+
+ private:
+ GestureEventDataPacket(base::TimeTicks timestamp,
+ GestureSource source,
+ const gfx::PointF& touch_location,
+ const gfx::PointF& raw_touch_location);
+
+ base::TimeTicks timestamp_;
+ // TODO(jdduke): This vector is in general very short. Optimize?
+ std::vector<GestureEventData> gestures_;
+ gfx::PointF touch_location_;
+ gfx::PointF raw_touch_location_;
+ GestureSource gesture_source_;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DATA_PACKET_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_provider.cc b/chromium/ui/events/gesture_detection/gesture_provider.cc
new file mode 100644
index 00000000000..0255ac74bac
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_provider.cc
@@ -0,0 +1,810 @@
+// 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/events/gesture_detection/gesture_provider.h"
+
+#include <cmath>
+
+#include "base/auto_reset.h"
+#include "base/debug/trace_event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace ui {
+namespace {
+
+// Double-tap drag zoom sensitivity (speed).
+const float kDoubleTapDragZoomSpeed = 0.005f;
+
+const char* GetMotionEventActionName(MotionEvent::Action action) {
+ switch(action) {
+ case MotionEvent::ACTION_POINTER_DOWN: return "ACTION_POINTER_DOWN";
+ case MotionEvent::ACTION_POINTER_UP: return "ACTION_POINTER_UP";
+ case MotionEvent::ACTION_DOWN: return "ACTION_DOWN";
+ case MotionEvent::ACTION_UP: return "ACTION_UP";
+ case MotionEvent::ACTION_CANCEL: return "ACTION_CANCEL";
+ case MotionEvent::ACTION_MOVE: return "ACTION_MOVE";
+ }
+ return "";
+}
+
+gfx::RectF GetBoundingBox(const MotionEvent& event) {
+ gfx::RectF bounds;
+ for (size_t i = 0; i < event.GetPointerCount(); ++i) {
+ float diameter = event.GetTouchMajor(i);
+ bounds.Union(gfx::RectF(event.GetX(i) - diameter / 2,
+ event.GetY(i) - diameter / 2,
+ diameter,
+ diameter));
+ }
+ return bounds;
+}
+
+GestureEventData CreateGesture(const GestureEventDetails& details,
+ int motion_event_id,
+ base::TimeTicks time,
+ float x,
+ float y,
+ float raw_x,
+ float raw_y,
+ size_t touch_point_count,
+ const gfx::RectF& bounding_box) {
+ return GestureEventData(details,
+ motion_event_id,
+ time,
+ x,
+ y,
+ raw_x,
+ raw_y,
+ touch_point_count,
+ bounding_box);
+}
+
+GestureEventData CreateGesture(EventType type,
+ int motion_event_id,
+ base::TimeTicks time,
+ float x,
+ float y,
+ float raw_x,
+ float raw_y,
+ size_t touch_point_count,
+ const gfx::RectF& bounding_box) {
+ return GestureEventData(GestureEventDetails(type, 0, 0),
+ motion_event_id,
+ time,
+ x,
+ y,
+ raw_x,
+ raw_y,
+ touch_point_count,
+ bounding_box);
+}
+
+GestureEventData CreateGesture(const GestureEventDetails& details,
+ const MotionEvent& event) {
+ return GestureEventData(details,
+ event.GetId(),
+ event.GetEventTime(),
+ event.GetX(),
+ event.GetY(),
+ event.GetRawX(),
+ event.GetRawY(),
+ event.GetPointerCount(),
+ GetBoundingBox(event));
+}
+
+GestureEventData CreateGesture(EventType type, const MotionEvent& event) {
+ return CreateGesture(GestureEventDetails(type, 0, 0), event);
+}
+
+GestureEventDetails CreateTapGestureDetails(EventType type) {
+ // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be
+ // consistent with double tap behavior on a mobile viewport. See
+ // crbug.com/234986 for context.
+ GestureEventDetails tap_details(type, 1, 0);
+ return tap_details;
+}
+
+} // namespace
+
+// GestureProvider:::Config
+
+GestureProvider::Config::Config()
+ : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)),
+ disable_click_delay(false),
+ gesture_begin_end_types_enabled(false),
+ min_gesture_bounds_length(0) {}
+
+GestureProvider::Config::~Config() {}
+
+// GestureProvider::ScaleGestureListener
+
+class GestureProvider::ScaleGestureListenerImpl
+ : public ScaleGestureDetector::ScaleGestureListener {
+ public:
+ ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config,
+ GestureProvider* provider)
+ : scale_gesture_detector_(config, this),
+ provider_(provider),
+ ignore_multitouch_events_(false),
+ pinch_event_sent_(false),
+ min_pinch_update_span_delta_(config.min_pinch_update_span_delta) {}
+
+ bool OnTouchEvent(const MotionEvent& event) {
+ // TODO: Need to deal with multi-touch transition.
+ const bool in_scale_gesture = IsScaleGestureDetectionInProgress();
+ bool handled = scale_gesture_detector_.OnTouchEvent(event);
+ if (!in_scale_gesture &&
+ (event.GetAction() == MotionEvent::ACTION_UP ||
+ event.GetAction() == MotionEvent::ACTION_CANCEL)) {
+ return false;
+ }
+ return handled;
+ }
+
+ // ScaleGestureDetector::ScaleGestureListener implementation.
+ virtual bool OnScaleBegin(const ScaleGestureDetector& detector,
+ const MotionEvent& e) OVERRIDE {
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
+ return false;
+ pinch_event_sent_ = false;
+ return true;
+ }
+
+ virtual void OnScaleEnd(const ScaleGestureDetector& detector,
+ const MotionEvent& e) OVERRIDE {
+ if (!pinch_event_sent_)
+ return;
+ provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, e));
+ pinch_event_sent_ = false;
+ }
+
+ virtual bool OnScale(const ScaleGestureDetector& detector,
+ const MotionEvent& e) OVERRIDE {
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
+ return false;
+ if (!pinch_event_sent_) {
+ pinch_event_sent_ = true;
+ provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN,
+ e.GetId(),
+ detector.GetEventTime(),
+ detector.GetFocusX(),
+ detector.GetFocusY(),
+ detector.GetFocusX() + e.GetRawOffsetX(),
+ detector.GetFocusY() + e.GetRawOffsetY(),
+ e.GetPointerCount(),
+ GetBoundingBox(e)));
+ }
+
+ if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) <
+ min_pinch_update_span_delta_) {
+ return false;
+ }
+
+ float scale = detector.GetScaleFactor();
+ if (scale == 1)
+ return true;
+
+ if (detector.InDoubleTapMode()) {
+ // Relative changes in the double-tap scale factor computed by |detector|
+ // diminish as the touch moves away from the original double-tap focus.
+ // For historical reasons, Chrome has instead adopted a scale factor
+ // computation that is invariant to the focal distance, where
+ // the scale delta remains constant if the touch velocity is constant.
+ float dy =
+ (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f;
+ scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed
+ : 1.0f - kDoubleTapDragZoomSpeed,
+ std::abs(dy));
+ }
+ GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
+ provider_->Send(CreateGesture(pinch_details,
+ e.GetId(),
+ detector.GetEventTime(),
+ detector.GetFocusX(),
+ detector.GetFocusY(),
+ detector.GetFocusX() + e.GetRawOffsetX(),
+ detector.GetFocusY() + e.GetRawOffsetY(),
+ e.GetPointerCount(),
+ GetBoundingBox(e)));
+ return true;
+ }
+
+ void SetDoubleTapEnabled(bool enabled) {
+ DCHECK(!IsDoubleTapInProgress());
+ scale_gesture_detector_.SetQuickScaleEnabled(enabled);
+ }
+
+ void SetMultiTouchEnabled(bool enabled) {
+ // Note that returning false from OnScaleBegin / OnScale makes the
+ // gesture detector not to emit further scaling notifications
+ // related to this gesture. Thus, if detector events are enabled in
+ // the middle of the gesture, we don't need to do anything.
+ ignore_multitouch_events_ = !enabled;
+ }
+
+ bool IsDoubleTapInProgress() const {
+ return IsScaleGestureDetectionInProgress() && InDoubleTapMode();
+ }
+
+ bool IsScaleGestureDetectionInProgress() const {
+ return scale_gesture_detector_.IsInProgress();
+ }
+
+ private:
+ bool InDoubleTapMode() const {
+ return scale_gesture_detector_.InDoubleTapMode();
+ }
+
+ ScaleGestureDetector scale_gesture_detector_;
+
+ GestureProvider* const provider_;
+
+ // Completely silence multi-touch (pinch) scaling events. Used in WebView when
+ // zoom support is turned off.
+ bool ignore_multitouch_events_;
+
+ // Whether any pinch zoom event has been sent to native.
+ bool pinch_event_sent_;
+
+ // The minimum change in span required before this is considered a pinch. See
+ // crbug.com/373318.
+ float min_pinch_update_span_delta_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl);
+};
+
+// GestureProvider::GestureListener
+
+class GestureProvider::GestureListenerImpl
+ : public GestureDetector::GestureListener,
+ public GestureDetector::DoubleTapListener {
+ public:
+ GestureListenerImpl(
+ const gfx::Display& display,
+ const GestureDetector::Config& gesture_detector_config,
+ bool disable_click_delay,
+ GestureProvider* provider)
+ : gesture_detector_(gesture_detector_config, this, this),
+ snap_scroll_controller_(display),
+ provider_(provider),
+ disable_click_delay_(disable_click_delay),
+ touch_slop_(gesture_detector_config.touch_slop),
+ double_tap_timeout_(gesture_detector_config.double_tap_timeout),
+ ignore_single_tap_(false),
+ seen_first_scroll_event_(false) {}
+
+ virtual ~GestureListenerImpl() {}
+
+ bool OnTouchEvent(const MotionEvent& e,
+ bool is_scale_gesture_detection_in_progress) {
+ snap_scroll_controller_.SetSnapScrollingMode(
+ e, is_scale_gesture_detection_in_progress);
+
+ if (is_scale_gesture_detection_in_progress)
+ SetIgnoreSingleTap(true);
+
+ if (e.GetAction() == MotionEvent::ACTION_DOWN)
+ gesture_detector_.set_longpress_enabled(true);
+
+ return gesture_detector_.OnTouchEvent(e);
+ }
+
+ // GestureDetector::GestureListener implementation.
+ virtual bool OnDown(const MotionEvent& e) OVERRIDE {
+ current_down_time_ = e.GetEventTime();
+ ignore_single_tap_ = false;
+ seen_first_scroll_event_ = false;
+
+ GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0);
+ provider_->Send(CreateGesture(tap_details, e));
+
+ // Return true to indicate that we want to handle touch.
+ return true;
+ }
+
+ virtual bool OnScroll(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float raw_distance_x,
+ float raw_distance_y) OVERRIDE {
+ float distance_x = raw_distance_x;
+ float distance_y = raw_distance_y;
+ if (!seen_first_scroll_event_) {
+ // Remove the touch slop region from the first scroll event to avoid a
+ // jump.
+ seen_first_scroll_event_ = true;
+ double distance =
+ std::sqrt(distance_x * distance_x + distance_y * distance_y);
+ double epsilon = 1e-3;
+ if (distance > epsilon) {
+ double ratio = std::max(0., distance - touch_slop_) / distance;
+ distance_x *= ratio;
+ distance_y *= ratio;
+ }
+ }
+ snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y);
+ if (snap_scroll_controller_.IsSnappingScrolls()) {
+ if (snap_scroll_controller_.IsSnapHorizontal()) {
+ distance_y = 0;
+ } else {
+ distance_x = 0;
+ }
+ }
+
+ if (!provider_->IsScrollInProgress()) {
+ // Note that scroll start hints are in distance traveled, where
+ // scroll deltas are in the opposite direction.
+ GestureEventDetails scroll_details(
+ ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y);
+
+ // Use the co-ordinates from the touch down, as these co-ordinates are
+ // used to determine which layer the scroll should affect.
+ provider_->Send(CreateGesture(scroll_details,
+ e2.GetId(),
+ e2.GetEventTime(),
+ e1.GetX(),
+ e1.GetY(),
+ e1.GetRawX(),
+ e1.GetRawY(),
+ e2.GetPointerCount(),
+ GetBoundingBox(e2)));
+ }
+
+ if (distance_x || distance_y) {
+ const gfx::RectF bounding_box = GetBoundingBox(e2);
+ const gfx::PointF center = bounding_box.CenterPoint();
+ const gfx::PointF raw_center =
+ center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY());
+ GestureEventDetails scroll_details(
+ ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y);
+ provider_->Send(CreateGesture(scroll_details,
+ e2.GetId(),
+ e2.GetEventTime(),
+ center.x(),
+ center.y(),
+ raw_center.x(),
+ raw_center.y(),
+ e2.GetPointerCount(),
+ bounding_box));
+ }
+
+ return true;
+ }
+
+ virtual bool OnFling(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) OVERRIDE {
+ if (snap_scroll_controller_.IsSnappingScrolls()) {
+ if (snap_scroll_controller_.IsSnapHorizontal()) {
+ velocity_y = 0;
+ } else {
+ velocity_x = 0;
+ }
+ }
+
+ provider_->Fling(e2, velocity_x, velocity_y);
+ return true;
+ }
+
+ virtual bool OnSwipe(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float velocity_x,
+ float velocity_y) OVERRIDE {
+ GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y);
+ provider_->Send(CreateGesture(swipe_details, e2));
+ return true;
+ }
+
+ virtual bool OnTwoFingerTap(const MotionEvent& e1,
+ const MotionEvent& e2) OVERRIDE {
+ // The location of the two finger tap event should be the location of the
+ // primary pointer.
+ GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP,
+ e1.GetTouchMajor(),
+ e1.GetTouchMajor());
+ provider_->Send(CreateGesture(two_finger_tap_details,
+ e2.GetId(),
+ e2.GetEventTime(),
+ e1.GetX(),
+ e1.GetY(),
+ e1.GetRawX(),
+ e1.GetRawY(),
+ e2.GetPointerCount(),
+ GetBoundingBox(e2)));
+ return true;
+ }
+
+ virtual void OnShowPress(const MotionEvent& e) OVERRIDE {
+ GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0);
+ provider_->Send(CreateGesture(show_press_details, e));
+ }
+
+ virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE {
+ // This is a hack to address the issue where user hovers
+ // over a link for longer than double_tap_timeout_, then
+ // OnSingleTapConfirmed() is not triggered. But we still
+ // want to trigger the tap event at UP. So we override
+ // OnSingleTapUp() in this case. This assumes singleTapUp
+ // gets always called before singleTapConfirmed.
+ if (!ignore_single_tap_) {
+ if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) {
+ return OnSingleTapConfirmed(e);
+ } else if (!IsDoubleTapEnabled() || disable_click_delay_) {
+ // If double-tap has been disabled, there is no need to wait
+ // for the double-tap timeout.
+ return OnSingleTapConfirmed(e);
+ } else {
+ // Notify Blink about this tapUp event anyway, when none of the above
+ // conditions applied.
+ provider_->Send(CreateGesture(
+ CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e));
+ }
+ }
+
+ return provider_->SendLongTapIfNecessary(e);
+ }
+
+ // GestureDetector::DoubleTapListener implementation.
+ virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE {
+ // Long taps in the edges of the screen have their events delayed by
+ // ContentViewHolder for tab swipe operations. As a consequence of the delay
+ // this method might be called after receiving the up event.
+ // These corner cases should be ignored.
+ if (ignore_single_tap_)
+ return true;
+
+ ignore_single_tap_ = true;
+
+ provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e));
+ return true;
+ }
+
+ virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; }
+
+ virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
+ switch (e.GetAction()) {
+ case MotionEvent::ACTION_DOWN:
+ gesture_detector_.set_longpress_enabled(false);
+ break;
+
+ case MotionEvent::ACTION_UP:
+ if (!provider_->IsPinchInProgress() &&
+ !provider_->IsScrollInProgress()) {
+ provider_->Send(
+ CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e));
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ virtual void OnLongPress(const MotionEvent& e) OVERRIDE {
+ DCHECK(!IsDoubleTapInProgress());
+ SetIgnoreSingleTap(true);
+
+ GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0);
+ provider_->Send(CreateGesture(long_press_details, e));
+ }
+
+ void SetDoubleTapEnabled(bool enabled) {
+ DCHECK(!IsDoubleTapInProgress());
+ gesture_detector_.SetDoubleTapListener(enabled ? this : NULL);
+ }
+
+ bool IsDoubleTapInProgress() const {
+ return gesture_detector_.is_double_tapping();
+ }
+
+ private:
+ void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
+
+ bool IsDoubleTapEnabled() const {
+ return gesture_detector_.has_doubletap_listener();
+ }
+
+ GestureDetector gesture_detector_;
+ SnapScrollController snap_scroll_controller_;
+
+ GestureProvider* const provider_;
+
+ // Whether the click delay should always be disabled by sending clicks for
+ // double-tap gestures.
+ const bool disable_click_delay_;
+
+ const float touch_slop_;
+
+ const base::TimeDelta double_tap_timeout_;
+
+ base::TimeTicks current_down_time_;
+
+ // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch,
+ // always_in_tap_region_ is not reset. So when the last finger is up,
+ // OnSingleTapUp() will be mistakenly fired.
+ bool ignore_single_tap_;
+
+ // Used to remove the touch slop from the initial scroll event in a scroll
+ // gesture.
+ bool seen_first_scroll_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl);
+};
+
+// GestureProvider
+
+GestureProvider::GestureProvider(const Config& config,
+ GestureProviderClient* client)
+ : client_(client),
+ touch_scroll_in_progress_(false),
+ pinch_in_progress_(false),
+ double_tap_support_for_page_(true),
+ double_tap_support_for_platform_(true),
+ gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled),
+ min_gesture_bounds_length_(config.min_gesture_bounds_length) {
+ DCHECK(client);
+ InitGestureDetectors(config);
+}
+
+GestureProvider::~GestureProvider() {}
+
+bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
+ TRACE_EVENT1("input", "GestureProvider::OnTouchEvent",
+ "action", GetMotionEventActionName(event.GetAction()));
+
+ DCHECK_NE(0u, event.GetPointerCount());
+
+ if (!CanHandle(event))
+ return false;
+
+ const bool in_scale_gesture =
+ scale_gesture_listener_->IsScaleGestureDetectionInProgress();
+
+ OnTouchEventHandlingBegin(event);
+ gesture_listener_->OnTouchEvent(event, in_scale_gesture);
+ scale_gesture_listener_->OnTouchEvent(event);
+ OnTouchEventHandlingEnd(event);
+ return true;
+}
+
+void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) {
+ scale_gesture_listener_->SetMultiTouchEnabled(enabled);
+}
+
+void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
+ if (double_tap_support_for_platform_ == enabled)
+ return;
+ double_tap_support_for_platform_ = enabled;
+ UpdateDoubleTapDetectionSupport();
+}
+
+void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
+ if (double_tap_support_for_page_ == enabled)
+ return;
+ double_tap_support_for_page_ = enabled;
+ UpdateDoubleTapDetectionSupport();
+}
+
+bool GestureProvider::IsScrollInProgress() const {
+ // TODO(wangxianzhu): Also return true when fling is active once the UI knows
+ // exactly when the fling ends.
+ return touch_scroll_in_progress_;
+}
+
+bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; }
+
+bool GestureProvider::IsDoubleTapInProgress() const {
+ return gesture_listener_->IsDoubleTapInProgress() ||
+ scale_gesture_listener_->IsDoubleTapInProgress();
+}
+
+void GestureProvider::InitGestureDetectors(const Config& config) {
+ TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors");
+ gesture_listener_.reset(
+ new GestureListenerImpl(config.display,
+ config.gesture_detector_config,
+ config.disable_click_delay,
+ this));
+
+ scale_gesture_listener_.reset(
+ new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this));
+
+ UpdateDoubleTapDetectionSupport();
+}
+
+bool GestureProvider::CanHandle(const MotionEvent& event) const {
+ return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_;
+}
+
+void GestureProvider::Fling(const MotionEvent& event,
+ float velocity_x,
+ float velocity_y) {
+ if (!velocity_x && !velocity_y) {
+ EndTouchScrollIfNecessary(event, true);
+ return;
+ }
+
+ if (!touch_scroll_in_progress_) {
+ // The native side needs a ET_GESTURE_SCROLL_BEGIN before
+ // ET_SCROLL_FLING_START to send the fling to the correct target. Send if it
+ // has not sent. The distance traveled in one second is a reasonable scroll
+ // start hint.
+ GestureEventDetails scroll_details(
+ ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y);
+ Send(CreateGesture(scroll_details, event));
+ }
+ EndTouchScrollIfNecessary(event, false);
+
+ GestureEventDetails fling_details(
+ ET_SCROLL_FLING_START, velocity_x, velocity_y);
+ Send(CreateGesture(fling_details, event));
+}
+
+void GestureProvider::Send(GestureEventData gesture) {
+ DCHECK(!gesture.time.is_null());
+ // The only valid events that should be sent without an active touch sequence
+ // are SHOW_PRESS and TAP, potentially triggered by the double-tap
+ // delay timing out.
+ DCHECK(current_down_event_ || gesture.type() == ET_GESTURE_TAP ||
+ gesture.type() == ET_GESTURE_SHOW_PRESS);
+
+ // TODO(jdduke): Provide a way of skipping this clamping for stylus and/or
+ // mouse-based input, perhaps by exposing the source type on MotionEvent.
+ const gfx::RectF& gesture_bounds = gesture.details.bounding_box_f();
+ gesture.details.set_bounding_box(gfx::RectF(
+ gesture_bounds.x(),
+ gesture_bounds.y(),
+ std::max(min_gesture_bounds_length_, gesture_bounds.width()),
+ std::max(min_gesture_bounds_length_, gesture_bounds.height())));
+
+ switch (gesture.type()) {
+ case ET_GESTURE_LONG_PRESS:
+ DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress());
+ current_longpress_time_ = gesture.time;
+ break;
+ case ET_GESTURE_LONG_TAP:
+ current_longpress_time_ = base::TimeTicks();
+ break;
+ case ET_GESTURE_SCROLL_BEGIN:
+ DCHECK(!touch_scroll_in_progress_);
+ touch_scroll_in_progress_ = true;
+ break;
+ case ET_GESTURE_SCROLL_END:
+ DCHECK(touch_scroll_in_progress_);
+ if (pinch_in_progress_)
+ Send(GestureEventData(ET_GESTURE_PINCH_END, gesture));
+ touch_scroll_in_progress_ = false;
+ break;
+ case ET_GESTURE_PINCH_BEGIN:
+ DCHECK(!pinch_in_progress_);
+ if (!touch_scroll_in_progress_)
+ Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture));
+ pinch_in_progress_ = true;
+ break;
+ case ET_GESTURE_PINCH_END:
+ DCHECK(pinch_in_progress_);
+ pinch_in_progress_ = false;
+ break;
+ case ET_GESTURE_SHOW_PRESS:
+ // It's possible that a double-tap drag zoom (from ScaleGestureDetector)
+ // will start before the press gesture fires (from GestureDetector), in
+ // which case the press should simply be dropped.
+ if (pinch_in_progress_ || touch_scroll_in_progress_)
+ return;
+ default:
+ break;
+ };
+
+ client_->OnGestureEvent(gesture);
+}
+
+bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) {
+ if (event.GetAction() == MotionEvent::ACTION_UP &&
+ !current_longpress_time_.is_null() &&
+ !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) {
+ GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0);
+ Send(CreateGesture(long_tap_details, event));
+ return true;
+ }
+ return false;
+}
+
+void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event,
+ bool send_scroll_end_event) {
+ if (!touch_scroll_in_progress_)
+ return;
+ if (send_scroll_end_event)
+ Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
+ touch_scroll_in_progress_ = false;
+}
+
+void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) {
+ switch (event.GetAction()) {
+ case MotionEvent::ACTION_DOWN:
+ current_down_event_ = event.Clone();
+ touch_scroll_in_progress_ = false;
+ pinch_in_progress_ = false;
+ current_longpress_time_ = base::TimeTicks();
+ if (gesture_begin_end_types_enabled_)
+ Send(CreateGesture(ET_GESTURE_BEGIN, event));
+ break;
+ case MotionEvent::ACTION_POINTER_DOWN:
+ if (gesture_begin_end_types_enabled_) {
+ const int action_index = event.GetActionIndex();
+ Send(CreateGesture(ET_GESTURE_BEGIN,
+ event.GetId(),
+ event.GetEventTime(),
+ event.GetX(action_index),
+ event.GetY(action_index),
+ event.GetRawX(action_index),
+ event.GetRawY(action_index),
+ event.GetPointerCount(),
+ GetBoundingBox(event)));
+ }
+ break;
+ case MotionEvent::ACTION_POINTER_UP:
+ case MotionEvent::ACTION_UP:
+ case MotionEvent::ACTION_CANCEL:
+ case MotionEvent::ACTION_MOVE:
+ break;
+ }
+}
+
+void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) {
+ switch (event.GetAction()) {
+ case MotionEvent::ACTION_UP:
+ case MotionEvent::ACTION_CANCEL: {
+ // Note: This call will have no effect if a fling was just generated, as
+ // |Fling()| will have already signalled an end to touch-scrolling.
+ EndTouchScrollIfNecessary(event, true);
+
+ const gfx::RectF bounding_box = GetBoundingBox(event);
+
+ if (gesture_begin_end_types_enabled_) {
+ for (size_t i = 0; i < event.GetPointerCount(); ++i) {
+ Send(CreateGesture(ET_GESTURE_END,
+ event.GetId(),
+ event.GetEventTime(),
+ event.GetX(i),
+ event.GetY(i),
+ event.GetRawX(i),
+ event.GetRawY(i),
+ event.GetPointerCount() - i,
+ bounding_box));
+ }
+ }
+
+ current_down_event_.reset();
+
+ UpdateDoubleTapDetectionSupport();
+ break;
+ }
+ case MotionEvent::ACTION_POINTER_UP:
+ if (gesture_begin_end_types_enabled_)
+ Send(CreateGesture(ET_GESTURE_END, event));
+ break;
+ case MotionEvent::ACTION_DOWN:
+ case MotionEvent::ACTION_POINTER_DOWN:
+ case MotionEvent::ACTION_MOVE:
+ break;
+ }
+}
+
+void GestureProvider::UpdateDoubleTapDetectionSupport() {
+ // The GestureDetector requires that any provided DoubleTapListener remain
+ // attached to it for the duration of a touch sequence. Defer any potential
+ // null'ing of the listener until the sequence has ended.
+ if (current_down_event_)
+ return;
+
+ const bool double_tap_enabled = double_tap_support_for_page_ &&
+ double_tap_support_for_platform_;
+ gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
+ scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/gesture_provider.h b/chromium/ui/events/gesture_detection/gesture_provider.h
new file mode 100644
index 00000000000..e9407c7e699
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_provider.h
@@ -0,0 +1,136 @@
+// 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_GESTURE_DETECTION_GESTURE_PROVIDER_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/gesture_detector.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
+#include "ui/events/gesture_detection/scale_gesture_detector.h"
+#include "ui/events/gesture_detection/snap_scroll_controller.h"
+#include "ui/gfx/display.h"
+
+namespace ui {
+
+class GESTURE_DETECTION_EXPORT GestureProviderClient {
+ public:
+ virtual ~GestureProviderClient() {}
+ virtual void OnGestureEvent(const GestureEventData& gesture) = 0;
+};
+
+// Given a stream of |MotionEvent|'s, provides gesture detection and gesture
+// event dispatch.
+class GESTURE_DETECTION_EXPORT GestureProvider {
+ public:
+ struct GESTURE_DETECTION_EXPORT Config {
+ Config();
+ ~Config();
+ gfx::Display display;
+ GestureDetector::Config gesture_detector_config;
+ ScaleGestureDetector::Config scale_gesture_detector_config;
+
+ // If |disable_click_delay| is true and double-tap support is disabled,
+ // there will be no delay before tap events. When double-tap support is
+ // enabled, there will always be a delay before a tap event is fired, in
+ // order to allow the double tap gesture to occur without firing any tap
+ // events.
+ bool disable_click_delay;
+
+ // If |gesture_begin_end_types_enabled| is true, fire an ET_GESTURE_BEGIN
+ // event for every added touch point, and an ET_GESTURE_END event for every
+ // removed touch point. Defaults to false.
+ bool gesture_begin_end_types_enabled;
+
+ // The minimum size (both length and width, in dips) of the generated
+ // bounding box for all gesture types. This is useful for touch streams
+ // that may report zero or unreasonably small touch sizes.
+ // Defaults to 0.
+ float min_gesture_bounds_length;
+ };
+
+ GestureProvider(const Config& config, GestureProviderClient* client);
+ ~GestureProvider();
+
+ // Handle the incoming MotionEvent, returning false if the event could not
+ // be handled.
+ bool OnTouchEvent(const MotionEvent& event);
+
+ // Update whether multi-touch pinch zoom is supported by the platform.
+ void SetMultiTouchZoomSupportEnabled(bool enabled);
+
+ // Update whether double-tap gestures are supported by the platform.
+ void SetDoubleTapSupportForPlatformEnabled(bool enabled);
+
+ // Update whether double-tap gesture detection should be suppressed, e.g.,
+ // if the page scale is fixed or the page has a mobile viewport. This disables
+ // the tap delay, allowing rapid and responsive single-tap gestures.
+ void SetDoubleTapSupportForPageEnabled(bool enabled);
+
+ // Whether a scroll gesture is in-progress.
+ bool IsScrollInProgress() const;
+
+ // Whether a pinch gesture is in-progress (i.e. a pinch update has been
+ // forwarded and detection is still active).
+ bool IsPinchInProgress() const;
+
+ // Whether a double-tap gesture is in-progress (either double-tap or
+ // double-tap drag zoom).
+ bool IsDoubleTapInProgress() const;
+
+ // May be NULL if there is no currently active touch sequence.
+ const ui::MotionEvent* current_down_event() const {
+ return current_down_event_.get();
+ }
+
+ private:
+ void InitGestureDetectors(const Config& config);
+
+ bool CanHandle(const MotionEvent& event) const;
+
+ void Fling(const MotionEvent& e, float velocity_x, float velocity_y);
+ void Send(GestureEventData gesture);
+ bool SendLongTapIfNecessary(const MotionEvent& event);
+ void EndTouchScrollIfNecessary(const MotionEvent& event,
+ bool send_scroll_end_event);
+ void OnTouchEventHandlingBegin(const MotionEvent& event);
+ void OnTouchEventHandlingEnd(const MotionEvent& event);
+ void UpdateDoubleTapDetectionSupport();
+
+ GestureProviderClient* const client_;
+
+ class GestureListenerImpl;
+ friend class GestureListenerImpl;
+ scoped_ptr<GestureListenerImpl> gesture_listener_;
+
+ class ScaleGestureListenerImpl;
+ friend class ScaleGestureListenerImpl;
+ scoped_ptr<ScaleGestureListenerImpl> scale_gesture_listener_;
+
+ scoped_ptr<MotionEvent> current_down_event_;
+
+ // Whether the respective {SCROLL,PINCH}_BEGIN gestures have been terminated
+ // with a {SCROLL,PINCH}_END.
+ bool touch_scroll_in_progress_;
+ bool pinch_in_progress_;
+
+ // Whether double-tap gesture detection is currently supported.
+ bool double_tap_support_for_page_;
+ bool double_tap_support_for_platform_;
+
+ // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is
+ // opened after a GESTURE_LONG_PRESS, this is used to insert a
+ // GESTURE_TAP_CANCEL for removing any ::active styling.
+ base::TimeTicks current_longpress_time_;
+
+ const bool gesture_begin_end_types_enabled_;
+
+ const float min_gesture_bounds_length_;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_PROVIDER_H_
diff --git a/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc b/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc
new file mode 100644
index 00000000000..985aa377999
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc
@@ -0,0 +1,2298 @@
+// 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 "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
+#include "ui/events/gesture_detection/gesture_provider.h"
+#include "ui/events/gesture_detection/mock_motion_event.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/geometry/point_f.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace ui {
+namespace {
+
+const float kFakeCoordX = 42.f;
+const float kFakeCoordY = 24.f;
+const TimeDelta kOneSecond = TimeDelta::FromSeconds(1);
+const TimeDelta kOneMicrosecond = TimeDelta::FromMicroseconds(1);
+const TimeDelta kDeltaTimeForFlingSequences = TimeDelta::FromMilliseconds(5);
+const float kMockTouchRadius = MockMotionEvent::TOUCH_MAJOR / 2;
+const float kMaxTwoFingerTapSeparation = 300;
+
+GestureProvider::Config CreateDefaultConfig() {
+ GestureProvider::Config sConfig;
+ // The longpress timeout is non-zero only to indicate ordering with respect to
+ // the showpress timeout.
+ sConfig.gesture_detector_config.showpress_timeout = base::TimeDelta();
+ sConfig.gesture_detector_config.longpress_timeout = kOneMicrosecond;
+
+ // A valid doubletap timeout should always be non-zero. The value is used not
+ // only to trigger the timeout that confirms the tap event, but also to gate
+ // whether the second tap is in fact a double-tap (using a strict inequality
+ // between times for the first up and the second down events). We use 4
+ // microseconds simply to allow several intermediate events to occur before
+ // the second tap at microsecond intervals.
+ sConfig.gesture_detector_config.double_tap_timeout = kOneMicrosecond * 4;
+ sConfig.gesture_detector_config.double_tap_min_time = kOneMicrosecond * 2;
+
+ sConfig.scale_gesture_detector_config.gesture_detector_config =
+ sConfig.gesture_detector_config;
+ return sConfig;
+}
+
+gfx::RectF BoundsForSingleMockTouchAtLocation(float x, float y) {
+ float diameter = MockMotionEvent::TOUCH_MAJOR;
+ return gfx::RectF(x - diameter / 2, y - diameter / 2, diameter, diameter);
+}
+
+} // namespace
+
+class GestureProviderTest : public testing::Test, public GestureProviderClient {
+ public:
+ GestureProviderTest() {}
+ virtual ~GestureProviderTest() {}
+
+ static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time,
+ MotionEvent::Action action,
+ float x,
+ float y) {
+ return MockMotionEvent(action, event_time, x, y);
+ }
+
+ static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time,
+ MotionEvent::Action action,
+ float x0,
+ float y0,
+ float x1,
+ float y1) {
+ return MockMotionEvent(action, event_time, x0, y0, x1, y1);
+ }
+
+ static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time,
+ MotionEvent::Action action,
+ float x0,
+ float y0,
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return MockMotionEvent(action, event_time, x0, y0, x1, y1, x2, y2);
+ }
+
+ static MockMotionEvent ObtainMotionEvent(
+ base::TimeTicks event_time,
+ MotionEvent::Action action,
+ const std::vector<gfx::PointF>& positions) {
+ switch (positions.size()) {
+ case 1:
+ return MockMotionEvent(
+ action, event_time, positions[0].x(), positions[0].y());
+ case 2:
+ return MockMotionEvent(action,
+ event_time,
+ positions[0].x(),
+ positions[0].y(),
+ positions[1].x(),
+ positions[1].y());
+ case 3:
+ return MockMotionEvent(action,
+ event_time,
+ positions[0].x(),
+ positions[0].y(),
+ positions[1].x(),
+ positions[1].y(),
+ positions[2].x(),
+ positions[2].y());
+ default:
+ CHECK(false) << "MockMotionEvent only supports 1-3 pointers";
+ return MockMotionEvent();
+ }
+ }
+
+ static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time,
+ MotionEvent::Action action) {
+ return ObtainMotionEvent(event_time, action, kFakeCoordX, kFakeCoordY);
+ }
+
+ // Test
+ virtual void SetUp() OVERRIDE { SetUpWithConfig(GetDefaultConfig()); }
+
+ virtual void TearDown() OVERRIDE {
+ gestures_.clear();
+ gesture_provider_.reset();
+ }
+
+ // GestureProviderClient
+ virtual void OnGestureEvent(const GestureEventData& gesture) OVERRIDE {
+ if (gesture.type() == ET_GESTURE_SCROLL_BEGIN)
+ active_scroll_begin_event_.reset(new GestureEventData(gesture));
+ gestures_.push_back(gesture);
+ }
+
+ void SetUpWithConfig(const GestureProvider::Config& config) {
+ gesture_provider_.reset(new GestureProvider(config, this));
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(false);
+ }
+
+ void ResetGestureDetection() {
+ CancelActiveTouchSequence();
+ gestures_.clear();
+ }
+ bool CancelActiveTouchSequence() {
+ if (!gesture_provider_->current_down_event())
+ return false;
+ return gesture_provider_->OnTouchEvent(
+ *gesture_provider_->current_down_event()->Cancel());
+ }
+
+ bool HasReceivedGesture(EventType type) const {
+ for (size_t i = 0; i < gestures_.size(); ++i) {
+ if (gestures_[i].type() == type)
+ return true;
+ }
+ return false;
+ }
+
+ const GestureEventData& GetMostRecentGestureEvent() const {
+ EXPECT_FALSE(gestures_.empty());
+ return gestures_.back();
+ }
+
+ EventType GetMostRecentGestureEventType() const {
+ EXPECT_FALSE(gestures_.empty());
+ return gestures_.back().type();
+ }
+
+ size_t GetReceivedGestureCount() const { return gestures_.size(); }
+
+ const GestureEventData& GetReceivedGesture(size_t index) const {
+ EXPECT_LT(index, GetReceivedGestureCount());
+ return gestures_[index];
+ }
+
+ const GestureEventData* GetActiveScrollBeginEvent() const {
+ return active_scroll_begin_event_ ? active_scroll_begin_event_.get() : NULL;
+ }
+
+ const GestureProvider::Config& GetDefaultConfig() const {
+ static GestureProvider::Config sConfig = CreateDefaultConfig();
+ return sConfig;
+ }
+
+ float GetTouchSlop() const {
+ return GetDefaultConfig().gesture_detector_config.touch_slop;
+ }
+
+ float GetMinScalingSpan() const {
+ return GetDefaultConfig().scale_gesture_detector_config.min_scaling_span;
+ }
+
+ float GetMinSwipeVelocity() const {
+ return GetDefaultConfig().gesture_detector_config.minimum_swipe_velocity;
+ }
+
+ base::TimeDelta GetLongPressTimeout() const {
+ return GetDefaultConfig().gesture_detector_config.longpress_timeout;
+ }
+
+ base::TimeDelta GetShowPressTimeout() const {
+ return GetDefaultConfig().gesture_detector_config.showpress_timeout;
+ }
+
+ base::TimeDelta GetDoubleTapTimeout() const {
+ return GetDefaultConfig().gesture_detector_config.double_tap_timeout;
+ }
+
+ base::TimeDelta GetDoubleTapMinTime() const {
+ return GetDefaultConfig().gesture_detector_config.double_tap_min_time;
+ }
+
+ base::TimeDelta GetValidDoubleTapDelay() const {
+ return (GetDoubleTapTimeout() + GetDoubleTapMinTime()) / 2;
+ }
+
+ void EnableBeginEndTypes() {
+ GestureProvider::Config config = GetDefaultConfig();
+ config.gesture_begin_end_types_enabled = true;
+ SetUpWithConfig(config);
+ }
+
+ void EnableSwipe() {
+ GestureProvider::Config config = GetDefaultConfig();
+ config.gesture_detector_config.swipe_enabled = true;
+ SetUpWithConfig(config);
+ }
+
+ void EnableTwoFingerTap(float max_distance_for_two_finger_tap,
+ base::TimeDelta two_finger_tap_timeout) {
+ GestureProvider::Config config = GetDefaultConfig();
+ config.gesture_detector_config.two_finger_tap_enabled = true;
+ config.gesture_detector_config.two_finger_tap_max_separation =
+ max_distance_for_two_finger_tap;
+ config.gesture_detector_config.two_finger_tap_timeout =
+ two_finger_tap_timeout;
+ SetUpWithConfig(config);
+ }
+
+ void SetMinPinchUpdateSpanDelta(float min_pinch_update_span_delta) {
+ GestureProvider::Config config = GetDefaultConfig();
+ config.scale_gesture_detector_config.min_pinch_update_span_delta =
+ min_pinch_update_span_delta;
+ SetUpWithConfig(config);
+ }
+
+ void SetMinGestureBoundsLength(float min_gesture_bound_length) {
+ GestureProvider::Config config = GetDefaultConfig();
+ config.min_gesture_bounds_length = min_gesture_bound_length;
+ SetUpWithConfig(config);
+ }
+
+ bool HasDownEvent() const { return gesture_provider_->current_down_event(); }
+
+ protected:
+ void CheckScrollEventSequenceForEndActionType(
+ MotionEvent::Action end_action_type) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float scroll_to_x = kFakeCoordX + 100;
+ const float scroll_to_y = kFakeCoordY + 100;
+ int motion_event_id = 0;
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneSecond,
+ MotionEvent::ACTION_MOVE,
+ scroll_to_x,
+ scroll_to_y);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(gesture_provider_->IsScrollInProgress());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(scroll_to_x, scroll_to_y),
+ GetMostRecentGestureEvent().details.bounding_box());
+ ASSERT_EQ(3U, GetReceivedGestureCount()) << "Only TapDown, "
+ "ScrollBegin and ScrollBy "
+ "should have been sent";
+
+ EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type());
+ EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id);
+ EXPECT_EQ(event_time + kOneSecond, GetReceivedGesture(1).time)
+ << "ScrollBegin should have the time of the ACTION_MOVE";
+
+ event = ObtainMotionEvent(
+ event_time + kOneSecond, end_action_type, scroll_to_x, scroll_to_y);
+ event.SetId(++motion_event_id);
+
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_FALSE(gesture_provider_->IsScrollInProgress());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_END));
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(scroll_to_x, scroll_to_y),
+ GetMostRecentGestureEvent().details.bounding_box());
+ }
+
+ void OneFingerSwipe(float vx, float vy) {
+ std::vector<gfx::Vector2dF> velocities;
+ velocities.push_back(gfx::Vector2dF(vx, vy));
+ MultiFingerSwipe(velocities);
+ }
+
+ void TwoFingerSwipe(float vx0, float vy0, float vx1, float vy1) {
+ std::vector<gfx::Vector2dF> velocities;
+ velocities.push_back(gfx::Vector2dF(vx0, vy0));
+ velocities.push_back(gfx::Vector2dF(vx1, vy1));
+ MultiFingerSwipe(velocities);
+ }
+
+ void ThreeFingerSwipe(float vx0,
+ float vy0,
+ float vx1,
+ float vy1,
+ float vx2,
+ float vy2) {
+ std::vector<gfx::Vector2dF> velocities;
+ velocities.push_back(gfx::Vector2dF(vx0, vy0));
+ velocities.push_back(gfx::Vector2dF(vx1, vy1));
+ velocities.push_back(gfx::Vector2dF(vx2, vy2));
+ MultiFingerSwipe(velocities);
+ }
+
+ void MultiFingerSwipe(std::vector<gfx::Vector2dF> velocities) {
+ ASSERT_GT(velocities.size(), 0U);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ std::vector<gfx::PointF> positions(velocities.size());
+ for (size_t i = 0; i < positions.size(); ++i)
+ positions[i] = gfx::PointF(kFakeCoordX * (i + 1), kFakeCoordY * (i + 1));
+
+ float dt = kDeltaTimeForFlingSequences.InSecondsF();
+
+ // Each pointer down should be a separate event.
+ for (size_t i = 0; i < positions.size(); ++i) {
+ const size_t pointer_count = i + 1;
+ std::vector<gfx::PointF> event_positions(pointer_count);
+ event_positions.assign(positions.begin(),
+ positions.begin() + pointer_count);
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time,
+ pointer_count > 1 ? MotionEvent::ACTION_POINTER_DOWN
+ : MotionEvent::ACTION_DOWN,
+ event_positions);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ }
+
+ for (size_t i = 0; i < positions.size(); ++i)
+ positions[i] += gfx::ScaleVector2d(velocities[i], dt);
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time + kDeltaTimeForFlingSequences,
+ MotionEvent::ACTION_MOVE,
+ positions);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ for (size_t i = 0; i < positions.size(); ++i)
+ positions[i] += gfx::ScaleVector2d(velocities[i], dt);
+ event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences,
+ MotionEvent::ACTION_MOVE,
+ positions);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences,
+ MotionEvent::ACTION_POINTER_UP,
+ positions);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ }
+
+ static void RunTasksAndWait(base::TimeDelta delay) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(), delay);
+ base::MessageLoop::current()->Run();
+ }
+
+ std::vector<GestureEventData> gestures_;
+ scoped_ptr<GestureProvider> gesture_provider_;
+ scoped_ptr<GestureEventData> active_scroll_begin_event_;
+ base::MessageLoopForUI message_loop_;
+};
+
+// Verify that a DOWN followed shortly by an UP will trigger a single tap.
+TEST_F(GestureProviderTest, GestureTap) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ int motion_event_id = 0;
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+ // Ensure tap details have been set.
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+}
+
+// Verify that a DOWN followed shortly by an UP will trigger
+// a ET_GESTURE_TAP_UNCONFIRMED event if double-tap is enabled.
+TEST_F(GestureProviderTest, GestureTapWithDelay) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ int motion_event_id = 0;
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ // Ensure tap details have been set.
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_TAP));
+ RunTasksAndWait(GetDoubleTapTimeout());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_TAP));
+}
+
+// Verify that a DOWN followed by a MOVE will trigger fling (but not LONG).
+TEST_F(GestureProviderTest, GestureFlingAndCancelLongPress) {
+ base::TimeTicks event_time = TimeTicks::Now();
+ base::TimeDelta delta_time = kDeltaTimeForFlingSequences;
+ int motion_event_id = 0;
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(event_time + delta_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX * 10,
+ kFakeCoordY * 10);
+ event.SetId(++motion_event_id);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + delta_time * 2,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX * 10,
+ kFakeCoordY * 10);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_SCROLL_FLING_START, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS));
+ EXPECT_EQ(
+ BoundsForSingleMockTouchAtLocation(kFakeCoordX * 10, kFakeCoordY * 10),
+ GetMostRecentGestureEvent().details.bounding_box());
+}
+
+// Verify that for a normal scroll the following events are sent:
+// - ET_GESTURE_SCROLL_BEGIN
+// - ET_GESTURE_SCROLL_UPDATE
+// - ET_GESTURE_SCROLL_END
+TEST_F(GestureProviderTest, ScrollEventActionUpSequence) {
+ CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_UP);
+}
+
+// Verify that for a cancelled scroll the following events are sent:
+// - ET_GESTURE_SCROLL_BEGIN
+// - ET_GESTURE_SCROLL_UPDATE
+// - ET_GESTURE_SCROLL_END
+TEST_F(GestureProviderTest, ScrollEventActionCancelSequence) {
+ CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_CANCEL);
+}
+
+// Verify that for a normal fling (fling after scroll) the following events are
+// sent:
+// - ET_GESTURE_SCROLL_BEGIN
+// - ET_SCROLL_FLING_START
+TEST_F(GestureProviderTest, FlingEventSequence) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ base::TimeDelta delta_time = kDeltaTimeForFlingSequences;
+ int motion_event_id = 0;
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + delta_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX * 5,
+ kFakeCoordY * 5);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(gesture_provider_->IsScrollInProgress());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ ASSERT_EQ(3U, GetReceivedGestureCount());
+ ASSERT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type());
+ EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id);
+
+ // We don't want to take a dependency here on exactly how hints are calculated
+ // for a fling (eg. may depend on velocity), so just validate the direction.
+ int hint_x = GetReceivedGesture(1).details.scroll_x_hint();
+ int hint_y = GetReceivedGesture(1).details.scroll_y_hint();
+ EXPECT_TRUE(hint_x > 0 && hint_y > 0 && hint_x > hint_y)
+ << "ScrollBegin hint should be in positive X axis";
+
+ event = ObtainMotionEvent(event_time + delta_time * 2,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX * 10,
+ kFakeCoordY * 10);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(gesture_provider_->IsScrollInProgress());
+ EXPECT_EQ(ET_SCROLL_FLING_START, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_END));
+ EXPECT_EQ(event_time + delta_time * 2, GetMostRecentGestureEvent().time)
+ << "FlingStart should have the time of the ACTION_UP";
+}
+
+TEST_F(GestureProviderTest, GestureCancelledWhenWindowFocusLost) {
+ const base::TimeTicks event_time = TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+
+ RunTasksAndWait(GetLongPressTimeout() + GetShowPressTimeout() +
+ kOneMicrosecond);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SHOW_PRESS));
+ EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType());
+
+ // The long press triggers window focus loss by opening a context menu.
+ EXPECT_TRUE(CancelActiveTouchSequence());
+ EXPECT_FALSE(HasDownEvent());
+
+ // A final ACTION_UP should have no effect.
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_UP);
+ EXPECT_FALSE(gesture_provider_->OnTouchEvent(event));
+}
+
+TEST_F(GestureProviderTest, NoTapAfterScrollBegins) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + 50,
+ kFakeCoordY + 50);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+
+ event = ObtainMotionEvent(event_time + kOneSecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX + 50,
+ kFakeCoordY + 50);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP));
+}
+
+TEST_F(GestureProviderTest, DoubleTap) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event_time += GetValidDoubleTapDelay();
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // Moving a very small amount of distance should not trigger the double tap
+ // drag zoom mode.
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 1);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 1);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ const GestureEventData& double_tap = GetMostRecentGestureEvent();
+ EXPECT_EQ(ET_GESTURE_DOUBLE_TAP, double_tap.type());
+ // Ensure tap details have been set.
+ EXPECT_EQ(10, double_tap.details.bounding_box().width());
+ EXPECT_EQ(10, double_tap.details.bounding_box().height());
+ EXPECT_EQ(1, double_tap.details.tap_count());
+}
+
+TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) {
+ const base::TimeTicks down_time_1 = TimeTicks::Now();
+ const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(
+ down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ ASSERT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 100),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 200),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_GT(1.f, GetMostRecentGestureEvent().details.scale());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 100),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 4,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY - 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END));
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY - 200),
+ GetMostRecentGestureEvent().details.bounding_box());
+}
+
+// Generate a scroll gesture and verify that the resulting scroll motion event
+// has both absolute and relative position information.
+TEST_F(GestureProviderTest, ScrollUpdateValues) {
+ const float delta_x = 16;
+ const float delta_y = 84;
+ const float raw_offset_x = 17.3f;
+ const float raw_offset_y = 13.7f;
+
+ const base::TimeTicks event_time = TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ // Move twice so that we get two ET_GESTURE_SCROLL_UPDATE events and can
+ // compare the relative and absolute coordinates.
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX - delta_x / 2,
+ kFakeCoordY - delta_y / 2);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX - delta_x,
+ kFakeCoordY - delta_y);
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ // Make sure the reported gesture event has all the expected details.
+ ASSERT_LT(0U, GetReceivedGestureCount());
+ GestureEventData gesture = GetMostRecentGestureEvent();
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, gesture.type());
+ EXPECT_EQ(event_time + kOneMicrosecond * 2, gesture.time);
+ EXPECT_EQ(kFakeCoordX - delta_x, gesture.x);
+ EXPECT_EQ(kFakeCoordY - delta_y, gesture.y);
+ EXPECT_EQ(kFakeCoordX - delta_x + raw_offset_x, gesture.raw_x);
+ EXPECT_EQ(kFakeCoordY - delta_y + raw_offset_y, gesture.raw_y);
+ EXPECT_EQ(1, gesture.details.touch_points());
+
+ // No horizontal delta because of snapping.
+ EXPECT_EQ(0, gesture.details.scroll_x());
+ EXPECT_EQ(-delta_y / 2, gesture.details.scroll_y());
+}
+
+// Verify that fractional scroll deltas are rounded as expected and that
+// fractional scrolling doesn't break scroll snapping.
+TEST_F(GestureProviderTest, FractionalScroll) {
+ const float delta_x = 0.4f;
+ const float delta_y = 5.2f;
+
+ const base::TimeTicks event_time = TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ // Skip past the touch slop and move back.
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ // Now move up slowly, mostly vertically but with a (fractional) bit of
+ // horizontal motion.
+ for(int i = 1; i <= 10; i++) {
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * i,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + delta_x * i,
+ kFakeCoordY + delta_y * i);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ ASSERT_LT(0U, GetReceivedGestureCount());
+ GestureEventData gesture = GetMostRecentGestureEvent();
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, gesture.type());
+ EXPECT_EQ(event_time + kOneMicrosecond * i, gesture.time);
+ EXPECT_EQ(1, gesture.details.touch_points());
+
+ // Verify that the event co-ordinates are still the precise values we
+ // supplied.
+ EXPECT_EQ(kFakeCoordX + delta_x * i, gesture.x);
+ EXPECT_EQ(kFakeCoordY + delta_y * i, gesture.y);
+
+ // Verify that we're scrolling vertically by the expected amount
+ // (modulo rounding).
+ EXPECT_GE(gesture.details.scroll_y(), (int)delta_y);
+ EXPECT_LE(gesture.details.scroll_y(), ((int)delta_y) + 1);
+
+ // And that there has been no horizontal motion at all.
+ EXPECT_EQ(0, gesture.details.scroll_x());
+ }
+}
+
+// Generate a scroll gesture and verify that the resulting scroll begin event
+// has the expected hint values.
+TEST_F(GestureProviderTest, ScrollBeginValues) {
+ const float delta_x = 13;
+ const float delta_y = 89;
+
+ const base::TimeTicks event_time = TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ // Move twice such that the first event isn't sufficient to start
+ // scrolling on it's own.
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + 2,
+ kFakeCoordY + 1);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(gesture_provider_->IsScrollInProgress());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + delta_x,
+ kFakeCoordY + delta_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(gesture_provider_->IsScrollInProgress());
+
+ const GestureEventData* scroll_begin_gesture = GetActiveScrollBeginEvent();
+ ASSERT_TRUE(!!scroll_begin_gesture);
+ EXPECT_EQ(delta_x, scroll_begin_gesture->details.scroll_x_hint());
+ EXPECT_EQ(delta_y, scroll_begin_gesture->details.scroll_y_hint());
+}
+
+TEST_F(GestureProviderTest, LongPressAndTapCancelledWhenScrollBegins) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX * 5,
+ kFakeCoordY * 5);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX * 10,
+ kFakeCoordY * 10);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+
+ // No LONG_TAP as the LONG_PRESS timer is cancelled.
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP));
+}
+
+// Verify that LONG_TAP is triggered after LONG_PRESS followed by an UP.
+TEST_F(GestureProviderTest, GestureLongTap) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+
+ EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::ACTION_UP);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_LONG_TAP, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+}
+
+TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+
+ EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ event = ObtainMotionEvent(event_time + long_press_timeout,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + 100,
+ kFakeCoordY + 100);
+ gesture_provider_->OnTouchEvent(event);
+
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+
+ event = ObtainMotionEvent(event_time + long_press_timeout,
+ MotionEvent::ACTION_UP);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP));
+}
+
+TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ int motion_event_id = 0;
+
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event_time += GetValidDoubleTapDelay();
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_TRUE(gesture_provider_->IsDoubleTapInProgress());
+
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS));
+
+ event = ObtainMotionEvent(event_time + long_press_timeout,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + 20,
+ kFakeCoordY + 20);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_TRUE(gesture_provider_->IsDoubleTapInProgress());
+
+ event = ObtainMotionEvent(event_time + long_press_timeout + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 1);
+ event.SetId(++motion_event_id);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_FALSE(gesture_provider_->IsDoubleTapInProgress());
+}
+
+// Verify that the touch slop region is removed from the first scroll delta to
+// avoid a jump when starting to scroll.
+TEST_F(GestureProviderTest, TouchSlopRemovedFromScroll) {
+ const float touch_slop = GetTouchSlop();
+ const float scroll_delta = 5;
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + touch_slop + scroll_delta);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ GestureEventData gesture = GetMostRecentGestureEvent();
+ EXPECT_EQ(0, gesture.details.scroll_x());
+ EXPECT_EQ(scroll_delta, gesture.details.scroll_y());
+ EXPECT_EQ(1, gesture.details.touch_points());
+}
+
+// Verify that movement within the touch slop region does not generate a scroll,
+// and that the slop region is correct even when using fractional coordinates.
+TEST_F(GestureProviderTest, NoScrollWithinTouchSlop) {
+ const float touch_slop = GetTouchSlop();
+ const float scale_factor = 2.5f;
+ const int touch_slop_pixels = static_cast<int>(scale_factor * touch_slop);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + touch_slop_pixels / scale_factor,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + touch_slop_pixels / scale_factor);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX - touch_slop_pixels / scale_factor,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY - touch_slop_pixels / scale_factor);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+
+ event =
+ ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + (touch_slop_pixels + 1.f) / scale_factor);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+}
+
+TEST_F(GestureProviderTest, NoDoubleTapWhenTooRapid) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // If the second tap follows the first in too short a time span, no double-tap
+ // will occur.
+ event_time += (GetDoubleTapMinTime() / 2);
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+}
+
+TEST_F(GestureProviderTest, NoDoubleTapWhenExplicitlyDisabled) {
+ // Ensure that double-tap gestures can be disabled.
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+
+ event_time += GetValidDoubleTapDelay();
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+
+ // Ensure that double-tap gestures can be interrupted.
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ event_time = base::TimeTicks::Now();
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(5U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+
+ // Ensure that double-tap gestures can be resumed.
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ event_time += GetValidDoubleTapDelay();
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+
+ event_time += GetValidDoubleTapDelay();
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_DOWN,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_DOUBLE_TAP, GetMostRecentGestureEventType());
+}
+
+TEST_F(GestureProviderTest, NoDelayedTapWhenDoubleTapSupportToggled) {
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(2U, GetReceivedGestureCount());
+
+ // Disabling double-tap during the tap timeout should flush the delayed tap.
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+ EXPECT_EQ(3U, GetReceivedGestureCount());
+
+ // No further timeout gestures should arrive.
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+ EXPECT_EQ(3U, GetReceivedGestureCount());
+}
+
+TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPlatform) {
+ const base::TimeTicks down_time_1 = TimeTicks::Now();
+ const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay();
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+
+ event = ObtainMotionEvent(
+ down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+
+ // The move should become a scroll, as doubletap drag zoom is disabled.
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(down_time_2 + kOneMicrosecond * 2,
+ GetMostRecentGestureEvent().time);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END));
+}
+
+// Verify that double tap drag zoom feature is not invoked when the gesture
+// handler is told to disable double tap gesture detection.
+// The second tap sequence should be treated just as the first would be.
+TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPage) {
+ const base::TimeTicks down_time_1 = TimeTicks::Now();
+ const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay();
+
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+
+ event = ObtainMotionEvent(
+ down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+
+ // The move should become a scroll, as double tap drag zoom is disabled.
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END));
+}
+
+// Verify that updating double tap support during a double tap drag zoom
+// disables double tap detection after the gesture has ended.
+TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) {
+ base::TimeTicks down_time_1 = TimeTicks::Now();
+ base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay();
+
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(true);
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ // Start a double-tap drag gesture.
+ MockMotionEvent event =
+ ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ event = ObtainMotionEvent(
+ down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // Simulate setting a fixed page scale (or a mobile viewport);
+ // this should not disrupt the current double-tap gesture.
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
+
+ // Double tap zoom updates should continue.
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END));
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // The double-tap gesture has finished, but the page scale is fixed.
+ // The same event sequence should not generate any double tap getsures.
+ gestures_.clear();
+ down_time_1 += kOneMicrosecond * 40;
+ down_time_2 += kOneMicrosecond * 40;
+
+ // Start a double-tap drag gesture.
+ event = ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY);
+ gesture_provider_->OnTouchEvent(event);
+ event = ObtainMotionEvent(
+ down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 100);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
+
+ // Double tap zoom updates should not be sent.
+ // Instead, the second tap drag becomes a scroll gesture sequence.
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_UP,
+ kFakeCoordX,
+ kFakeCoordY + 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END));
+}
+
+// Verify that pinch zoom sends the proper event sequence.
+TEST_F(GestureProviderTest, PinchZoom) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float touch_slop = GetTouchSlop();
+ const float raw_offset_x = 3.2f;
+ const float raw_offset_y = 4.3f;
+ int motion_event_id = 0;
+
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(true);
+
+ int secondary_coord_x = kFakeCoordX + 20 * touch_slop;
+ int secondary_coord_y = kFakeCoordY + 20 * touch_slop;
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(kFakeCoordX, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(kFakeCoordY, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(kFakeCoordX + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(kFakeCoordY + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ // Toggling double-tap support should not take effect until the next sequence.
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(true);
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+ event.SetId(++motion_event_id);
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ secondary_coord_x += 5 * touch_slop;
+ secondary_coord_y += 5 * touch_slop;
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+ event.SetId(++motion_event_id);
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+
+ // Toggling double-tap support should not take effect until the next sequence.
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+
+ EXPECT_EQ((kFakeCoordX + secondary_coord_x) / 2, GetReceivedGesture(3).x);
+ EXPECT_EQ((kFakeCoordY + secondary_coord_y) / 2, GetReceivedGesture(3).y);
+ EXPECT_EQ((kFakeCoordX + secondary_coord_x) / 2 + raw_offset_x,
+ GetReceivedGesture(3).raw_x);
+ EXPECT_EQ((kFakeCoordY + secondary_coord_y) / 2 + raw_offset_y,
+ GetReceivedGesture(3).raw_y);
+
+ EXPECT_EQ(
+ gfx::RectF(kFakeCoordX - kMockTouchRadius,
+ kFakeCoordY - kMockTouchRadius,
+ secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2,
+ secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ secondary_coord_x += 2 * touch_slop;
+ secondary_coord_y += 2 * touch_slop;
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+ event.SetId(++motion_event_id);
+
+ // Toggling double-tap support should not take effect until the next sequence.
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(true);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+ EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
+ EXPECT_EQ(
+ gfx::RectF(kFakeCoordX - kMockTouchRadius,
+ kFakeCoordY - kMockTouchRadius,
+ secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2,
+ secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_UP,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+ event.SetId(++motion_event_id);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(ET_GESTURE_PINCH_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_END));
+ EXPECT_EQ(
+ gfx::RectF(kFakeCoordX - kMockTouchRadius,
+ kFakeCoordY - kMockTouchRadius,
+ secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2,
+ secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(gfx::RectF(kFakeCoordX - kMockTouchRadius,
+ kFakeCoordY - kMockTouchRadius,
+ kMockTouchRadius * 2,
+ kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+}
+
+// Verify that no accidental pinching occurs if the touch size is large relative
+// to the min scaling span.
+TEST_F(GestureProviderTest, NoPinchZoomWithFatFinger) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float kFatFingerSize = GetMinScalingSpan() * 3.f;
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(true);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneSecond,
+ MotionEvent::ACTION_MOVE);
+ event.SetTouchMajor(0.1f);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneSecond * 2,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX + 1.f,
+ kFakeCoordY);
+ event.SetTouchMajor(1.f);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneSecond * 3,
+ MotionEvent::ACTION_MOVE);
+ event.SetTouchMajor(kFatFingerSize * 3.5f);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(event_time + kOneSecond * 4,
+ MotionEvent::ACTION_MOVE);
+ event.SetTouchMajor(kFatFingerSize * 5.f);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+}
+
+// Verify that multi-finger swipe sends the proper event sequence.
+TEST_F(GestureProviderTest, MultiFingerSwipe) {
+ EnableSwipe();
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(false);
+ const float min_swipe_velocity = GetMinSwipeVelocity();
+
+ // One finger - swipe right
+ OneFingerSwipe(2 * min_swipe_velocity, 0);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // One finger - swipe left
+ OneFingerSwipe(-2 * min_swipe_velocity, 0);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_left());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // One finger - swipe down
+ OneFingerSwipe(0, 2 * min_swipe_velocity);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // One finger - swipe up
+ OneFingerSwipe(0, -2 * min_swipe_velocity);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_up());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // Two fingers
+ // Swipe right.
+ TwoFingerSwipe(min_swipe_velocity * 2, 0, min_swipe_velocity * 2, 0);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // Swipe left.
+ TwoFingerSwipe(-min_swipe_velocity * 2, 0, -min_swipe_velocity * 2, 0);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_left());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // No swipe with different touch directions.
+ TwoFingerSwipe(min_swipe_velocity * 2, 0, -min_swipe_velocity * 2, 0);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ ResetGestureDetection();
+
+ // No swipe without a dominant direction.
+ TwoFingerSwipe(min_swipe_velocity * 2,
+ min_swipe_velocity * 2,
+ min_swipe_velocity * 2,
+ min_swipe_velocity * 2);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ ResetGestureDetection();
+
+ // Swipe down with non-zero velocities on both axes and dominant direction.
+ TwoFingerSwipe(-min_swipe_velocity,
+ min_swipe_velocity * 4,
+ -min_swipe_velocity,
+ min_swipe_velocity * 4);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down());
+ EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_left());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // Swipe up with non-zero velocities on both axes.
+ TwoFingerSwipe(min_swipe_velocity,
+ -min_swipe_velocity * 4,
+ min_swipe_velocity,
+ -min_swipe_velocity * 4);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_up());
+ EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_right());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // No swipe without sufficient velocity.
+ TwoFingerSwipe(min_swipe_velocity / 2, 0, 0, 0);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ ResetGestureDetection();
+
+ // Swipe up with one small and one medium velocity in slightly different but
+ // not opposing directions.
+ TwoFingerSwipe(min_swipe_velocity / 2,
+ min_swipe_velocity / 2,
+ 0,
+ min_swipe_velocity * 2);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down());
+ EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_right());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // No swipe in orthogonal directions.
+ TwoFingerSwipe(min_swipe_velocity * 2, 0, 0, min_swipe_velocity * 7);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ ResetGestureDetection();
+
+ // Three finger swipe in same directions.
+ ThreeFingerSwipe(min_swipe_velocity * 2,
+ 0,
+ min_swipe_velocity * 3,
+ 0,
+ min_swipe_velocity * 4,
+ 0);
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE));
+ EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points());
+ ResetGestureDetection();
+
+ // No three finger swipe in different directions.
+ ThreeFingerSwipe(min_swipe_velocity * 2,
+ 0,
+ 0,
+ min_swipe_velocity * 3,
+ min_swipe_velocity * 4,
+ 0);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE));
+}
+
+// Verify that the timer of LONG_PRESS will be cancelled when scrolling begins
+// so LONG_PRESS and LONG_TAP won't be triggered.
+TEST_F(GestureProviderTest, GesturesCancelledAfterLongPressCausesLostFocus) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ const base::TimeDelta long_press_timeout =
+ GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond;
+ RunTasksAndWait(long_press_timeout);
+ EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ EXPECT_TRUE(CancelActiveTouchSequence());
+ EXPECT_FALSE(HasDownEvent());
+
+ event = ObtainMotionEvent(event_time + long_press_timeout,
+ MotionEvent::ACTION_UP);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP));
+}
+
+// Verify that inserting a touch cancel event will trigger proper touch and
+// gesture sequence cancellation.
+TEST_F(GestureProviderTest, CancelActiveTouchSequence) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ int motion_event_id = 0;
+
+ EXPECT_FALSE(CancelActiveTouchSequence());
+ EXPECT_EQ(0U, GetReceivedGestureCount());
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ event.SetId(++motion_event_id);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ ASSERT_TRUE(CancelActiveTouchSequence());
+ EXPECT_FALSE(HasDownEvent());
+
+ // Subsequent MotionEvent's are dropped until ACTION_DOWN.
+ event = ObtainMotionEvent(event_time + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE);
+ EXPECT_FALSE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 2,
+ MotionEvent::ACTION_UP);
+ EXPECT_FALSE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneMicrosecond * 3,
+ MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+}
+
+TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) {
+ const base::TimeTicks down_time_1 = TimeTicks::Now();
+ const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay();
+
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+
+ MockMotionEvent event =
+ ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event =
+ ObtainMotionEvent(down_time_1 + kOneMicrosecond, MotionEvent::ACTION_UP);
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(down_time_2, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY - 30);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY - 30,
+ kFakeCoordX + 50,
+ kFakeCoordY + 50);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_PINCH_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+
+ const size_t gesture_count = GetReceivedGestureCount();
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
+ MotionEvent::ACTION_POINTER_UP,
+ kFakeCoordX,
+ kFakeCoordY - 30,
+ kFakeCoordX + 50,
+ kFakeCoordY + 50);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(gesture_count, GetReceivedGestureCount());
+
+ event = ObtainMotionEvent(down_time_2 + kOneSecond,
+ MotionEvent::ACTION_UP);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(gesture_count + 1, GetReceivedGestureCount());
+ EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+}
+
+// Verify that gesture begin and gesture end events are dispatched correctly.
+TEST_F(GestureProviderTest, GestureBeginAndEnd) {
+ EnableBeginEndTypes();
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float raw_offset_x = 7.5f;
+ const float raw_offset_y = 5.7f;
+
+ EXPECT_EQ(0U, GetReceivedGestureCount());
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1);
+ event.pointer_count = 1;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type());
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(2U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(1 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(1 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+ EXPECT_EQ(gfx::RectF(1 - kMockTouchRadius,
+ 1 - kMockTouchRadius,
+ kMockTouchRadius * 2,
+ kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2);
+ event.pointer_count = 2;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(3U, GetReceivedGestureCount());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(2, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3);
+ event.pointer_count = 3;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(4U, GetReceivedGestureCount());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(3, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_UP, 1, 1, 2, 2, 3, 3);
+ event.pointer_count = 2;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(5U, GetReceivedGestureCount());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(1 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(1 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_DOWN, 2, 2, 3, 3, 4, 4);
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ event.pointer_count = 3;
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(6U, GetReceivedGestureCount());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(4, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(4, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(4 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(4 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_UP, 2, 2, 3, 3, 4, 4);
+ event.pointer_count = 2;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(7U, GetReceivedGestureCount());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(2, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+ event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_UP, 3, 3, 4, 4);
+ event.pointer_count = 1;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(8U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(3, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+
+
+ event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP, 4, 4);
+ event.pointer_count = 1;
+ event.SetRawOffset(raw_offset_x, raw_offset_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType());
+ EXPECT_EQ(9U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(4, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(4, GetMostRecentGestureEvent().y);
+ EXPECT_EQ(4 + raw_offset_x, GetMostRecentGestureEvent().raw_x);
+ EXPECT_EQ(4 + raw_offset_y, GetMostRecentGestureEvent().raw_y);
+}
+
+// Verify that gesture begin and gesture end events are dispatched correctly
+// when an ACTION_CANCEL is received.
+TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) {
+ EnableBeginEndTypes();
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ EXPECT_EQ(0U, GetReceivedGestureCount());
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1);
+ event.pointer_count = 1;
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type());
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(2U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(gfx::RectF(1 - kMockTouchRadius,
+ 1 - kMockTouchRadius,
+ kMockTouchRadius * 2,
+ kMockTouchRadius * 2),
+ GetMostRecentGestureEvent().details.bounding_box());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(1, GetMostRecentGestureEvent().y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2);
+ event.pointer_count = 2;
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(3U, GetReceivedGestureCount());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(2, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(2, GetMostRecentGestureEvent().y);
+
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3);
+ event.pointer_count = 3;
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType());
+ EXPECT_EQ(4U, GetReceivedGestureCount());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_EQ(3, GetMostRecentGestureEvent().x);
+ EXPECT_EQ(3, GetMostRecentGestureEvent().y);
+
+ event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_CANCEL, 1, 1, 2, 2, 3, 3);
+ event.pointer_count = 3;
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(7U, GetReceivedGestureCount());
+ EXPECT_EQ(3, GetReceivedGesture(4).details.touch_points());
+ EXPECT_EQ(ET_GESTURE_END, GetReceivedGesture(4).type());
+ EXPECT_EQ(2, GetReceivedGesture(5).details.touch_points());
+ EXPECT_EQ(ET_GESTURE_END, GetReceivedGesture(5).type());
+ EXPECT_EQ(1, GetReceivedGesture(6).details.touch_points());
+ EXPECT_EQ(ET_GESTURE_END, GetReceivedGesture(6).type());
+ EXPECT_EQ(1, GetReceivedGesture(4).x);
+ EXPECT_EQ(1, GetReceivedGesture(4).y);
+ EXPECT_EQ(2, GetReceivedGesture(5).x);
+ EXPECT_EQ(2, GetReceivedGesture(5).y);
+ EXPECT_EQ(3, GetReceivedGesture(6).x);
+ EXPECT_EQ(3, GetReceivedGesture(6).y);
+}
+
+// Test a simple two finger tap
+TEST_F(GestureProviderTest, TwoFingerTap) {
+ // The time between ACTION_POINTER_DOWN and ACTION_POINTER_UP must be <= the
+ // two finger tap delay.
+ EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta());
+ const float scaled_touch_slop = GetTouchSlop();
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ 0,
+ scaled_touch_slop / 2);
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ 0,
+ 0,
+ kMaxTwoFingerTapSeparation / 2,
+ 0);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event =
+ ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ 0,
+ -scaled_touch_slop / 2,
+ kMaxTwoFingerTapSeparation / 2 + scaled_touch_slop / 2,
+ 0);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_UP,
+ 0,
+ 0,
+ kMaxTwoFingerTapSeparation,
+ 0);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type());
+ EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type());
+ EXPECT_EQ(ET_GESTURE_TWO_FINGER_TAP, GetReceivedGesture(2).type());
+ EXPECT_EQ(3U, GetReceivedGestureCount());
+
+ EXPECT_EQ(kMockTouchRadius * 2,
+ GetReceivedGesture(2).details.first_finger_width());
+ EXPECT_EQ(kMockTouchRadius * 2,
+ GetReceivedGesture(2).details.first_finger_height());
+}
+
+// Test preventing a two finger tap via finger movement.
+TEST_F(GestureProviderTest, TwoFingerTapCancelledByFingerMovement) {
+ EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta());
+ const float scaled_touch_slop = GetTouchSlop();
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX + scaled_touch_slop + 0.1,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_UP,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type());
+ EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type());
+ EXPECT_EQ(2U, GetReceivedGestureCount());
+}
+
+// Test preventing a two finger tap by waiting too long before releasing the
+// secondary pointer.
+TEST_F(GestureProviderTest, TwoFingerTapCancelledByDelay) {
+ base::TimeDelta two_finger_tap_timeout = kOneSecond;
+ EnableTwoFingerTap(kMaxTwoFingerTapSeparation, two_finger_tap_timeout);
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY);
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX + kMaxTwoFingerTapSeparation / 2,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time + kOneSecond + kOneMicrosecond,
+ MotionEvent::ACTION_POINTER_UP,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX + kMaxTwoFingerTapSeparation / 2,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type());
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+}
+
+// Test preventing a two finger tap by pressing the secondary pointer too far
+// from the first
+TEST_F(GestureProviderTest, TwoFingerTapCancelledByDistanceBetweenPointers) {
+ EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta());
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ MockMotionEvent event = ObtainMotionEvent(
+ event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX + kMaxTwoFingerTapSeparation,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_UP,
+ kFakeCoordX,
+ kFakeCoordY,
+ kFakeCoordX + kMaxTwoFingerTapSeparation,
+ kFakeCoordY);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type());
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+}
+
+// Verify that pinch zoom only sends updates which exceed the
+// min_pinch_update_span_delta.
+TEST_F(GestureProviderTest, PinchZoomWithThreshold) {
+ const float kMinPinchUpdateDistance = 5;
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float touch_slop = GetTouchSlop();
+
+ SetMinPinchUpdateSpanDelta(kMinPinchUpdateDistance);
+ gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true);
+ gesture_provider_->SetMultiTouchZoomSupportEnabled(true);
+
+ int secondary_coord_x = kFakeCoordX + 20 * touch_slop;
+ int secondary_coord_y = kFakeCoordY + 20 * touch_slop;
+
+ // First finger down.
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // Second finger down.
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_POINTER_DOWN,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+
+ gesture_provider_->OnTouchEvent(event);
+ EXPECT_EQ(1U, GetReceivedGestureCount());
+ EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points());
+
+ // Move second finger.
+ secondary_coord_x += 5 * touch_slop;
+ secondary_coord_y += 5 * touch_slop;
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+
+ // Small move, shouldn't trigger pinch.
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x + kMinPinchUpdateDistance,
+ secondary_coord_y);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+
+ // Small move, but combined with the previous move, should trigger pinch. We
+ // need to overshoot kMinPinchUpdateDistance by a fair bit, as the span
+ // calculation factors in touch radius.
+ const float kOvershootMinPinchUpdateDistance = 3;
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x + kMinPinchUpdateDistance +
+ kOvershootMinPinchUpdateDistance,
+ secondary_coord_y);
+
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
+ EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points());
+}
+
+// Verify that the min gesture bound setting is honored.
+TEST_F(GestureProviderTest, MinGestureBoundsLength) {
+ const float kMinGestureBoundsLength = 10.f * kMockTouchRadius;
+ SetMinGestureBoundsLength(kMinGestureBoundsLength);
+ gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ MockMotionEvent event =
+ ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+
+ EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
+ EXPECT_EQ(kMinGestureBoundsLength,
+ GetMostRecentGestureEvent().details.bounding_box_f().width());
+ EXPECT_EQ(kMinGestureBoundsLength,
+ GetMostRecentGestureEvent().details.bounding_box_f().height());
+
+ event =
+ ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType());
+ EXPECT_EQ(kMinGestureBoundsLength,
+ GetMostRecentGestureEvent().details.bounding_box_f().width());
+ EXPECT_EQ(kMinGestureBoundsLength,
+ GetMostRecentGestureEvent().details.bounding_box_f().height());
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/mock_motion_event.cc b/chromium/ui/events/gesture_detection/mock_motion_event.cc
new file mode 100644
index 00000000000..d6e0a91b5a1
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/mock_motion_event.cc
@@ -0,0 +1,204 @@
+// 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/events/gesture_detection/mock_motion_event.h"
+
+#include "base/logging.h"
+
+using base::TimeTicks;
+
+namespace ui {
+
+MockMotionEvent::MockMotionEvent()
+ : action(ACTION_CANCEL), pointer_count(1), touch_major(TOUCH_MAJOR), id(0) {
+}
+
+MockMotionEvent::MockMotionEvent(Action action)
+ : action(action), pointer_count(1), touch_major(TOUCH_MAJOR), id(0) {
+}
+
+MockMotionEvent::MockMotionEvent(Action action,
+ TimeTicks time,
+ float x,
+ float y)
+ : action(action),
+ pointer_count(1),
+ time(time),
+ touch_major(TOUCH_MAJOR),
+ id(0) {
+ points[0].SetPoint(x, y);
+}
+
+MockMotionEvent::MockMotionEvent(Action action,
+ TimeTicks time,
+ float x0,
+ float y0,
+ float x1,
+ float y1)
+ : action(action),
+ pointer_count(2),
+ time(time),
+ touch_major(TOUCH_MAJOR),
+ id(0) {
+ points[0].SetPoint(x0, y0);
+ points[1].SetPoint(x1, y1);
+}
+
+MockMotionEvent::MockMotionEvent(Action action,
+ TimeTicks time,
+ float x0,
+ float y0,
+ float x1,
+ float y1,
+ float x2,
+ float y2)
+ : action(action),
+ pointer_count(3),
+ time(time),
+ touch_major(TOUCH_MAJOR),
+ id(0) {
+ points[0].SetPoint(x0, y0);
+ points[1].SetPoint(x1, y1);
+ points[2].SetPoint(x2, y2);
+}
+
+MockMotionEvent::MockMotionEvent(const MockMotionEvent& other)
+ : action(other.action),
+ pointer_count(other.pointer_count),
+ time(other.time),
+ touch_major(other.touch_major),
+ id(other.GetId()) {
+ for (size_t i = 0; i < pointer_count; ++i)
+ points[i] = other.points[i];
+}
+
+MockMotionEvent::~MockMotionEvent() {}
+
+MotionEvent::Action MockMotionEvent::GetAction() const { return action; }
+
+int MockMotionEvent::GetActionIndex() const {
+ return static_cast<int>(pointer_count) - 1;
+}
+
+size_t MockMotionEvent::GetPointerCount() const { return pointer_count; }
+
+int MockMotionEvent::GetId() const {
+ return id;
+}
+
+int MockMotionEvent::GetPointerId(size_t pointer_index) const {
+ DCHECK(pointer_index < pointer_count);
+ return static_cast<int>(pointer_index);
+}
+
+float MockMotionEvent::GetX(size_t pointer_index) const {
+ return points[pointer_index].x();
+}
+
+float MockMotionEvent::GetY(size_t pointer_index) const {
+ return points[pointer_index].y();
+}
+
+float MockMotionEvent::GetRawX(size_t pointer_index) const {
+ return GetX(pointer_index) + raw_offset.x();
+}
+
+float MockMotionEvent::GetRawY(size_t pointer_index) const {
+ return GetY(pointer_index) + raw_offset.y();
+}
+
+float MockMotionEvent::GetTouchMajor(size_t pointer_index) const {
+ return touch_major;
+}
+
+float MockMotionEvent::GetPressure(size_t pointer_index) const {
+ return 0;
+}
+
+TimeTicks MockMotionEvent::GetEventTime() const { return time; }
+
+size_t MockMotionEvent::GetHistorySize() const { return 0; }
+
+TimeTicks MockMotionEvent::GetHistoricalEventTime(
+ size_t historical_index) const {
+ return TimeTicks();
+}
+
+float MockMotionEvent::GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const {
+ return 0;
+}
+
+float MockMotionEvent::GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const {
+ return 0;
+}
+
+float MockMotionEvent::GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const {
+ return 0;
+}
+
+scoped_ptr<MotionEvent> MockMotionEvent::Clone() const {
+ return scoped_ptr<MotionEvent>(new MockMotionEvent(*this));
+}
+
+scoped_ptr<MotionEvent> MockMotionEvent::Cancel() const {
+ scoped_ptr<MockMotionEvent> cancel_event(new MockMotionEvent(*this));
+ cancel_event->action = MotionEvent::ACTION_CANCEL;
+ return cancel_event.PassAs<MotionEvent>();
+}
+
+void MockMotionEvent::SetId(int new_id) {
+ id = new_id;
+}
+
+void MockMotionEvent::SetTime(base::TimeTicks new_time) {
+ time = new_time;
+}
+
+void MockMotionEvent::PressPoint(float x, float y) {
+ // Reset the pointer count if the previously released and/or cancelled pointer
+ // was the last pointer in the event.
+ if (pointer_count == 1 && (action == ACTION_UP || action == ACTION_CANCEL))
+ pointer_count = 0;
+
+ DCHECK_LT(pointer_count, static_cast<size_t>(MAX_POINTERS));
+ points[pointer_count++] = gfx::PointF(x, y);
+ action = pointer_count > 1 ? ACTION_POINTER_DOWN : ACTION_DOWN;
+}
+
+void MockMotionEvent::MovePoint(size_t index, float x, float y) {
+ DCHECK_LT(index, pointer_count);
+ points[index] = gfx::PointF(x, y);
+ action = ACTION_MOVE;
+}
+
+void MockMotionEvent::ReleasePoint() {
+ DCHECK_GT(pointer_count, 0U);
+ if (pointer_count > 1) {
+ --pointer_count;
+ action = ACTION_POINTER_UP;
+ } else {
+ action = ACTION_UP;
+ }
+}
+
+void MockMotionEvent::CancelPoint() {
+ DCHECK_GT(pointer_count, 0U);
+ if (pointer_count > 1)
+ --pointer_count;
+ action = ACTION_CANCEL;
+}
+
+void MockMotionEvent::SetTouchMajor(float new_touch_major) {
+ touch_major = new_touch_major;
+}
+
+void MockMotionEvent::SetRawOffset(float raw_offset_x, float raw_offset_y) {
+ raw_offset.set_x(raw_offset_x);
+ raw_offset.set_y(raw_offset_y);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/mock_motion_event.h b/chromium/ui/events/gesture_detection/mock_motion_event.h
new file mode 100644
index 00000000000..433de7b3b08
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/mock_motion_event.h
@@ -0,0 +1,86 @@
+// 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 <vector>
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace ui {
+
+struct MockMotionEvent : public MotionEvent {
+ enum { MAX_POINTERS = 3 };
+ enum { TOUCH_MAJOR = 10 };
+
+ MockMotionEvent();
+ explicit MockMotionEvent(Action action);
+ MockMotionEvent(Action action, base::TimeTicks time, float x, float y);
+ MockMotionEvent(Action action,
+ base::TimeTicks time,
+ float x0,
+ float y0,
+ float x1,
+ float y1);
+ MockMotionEvent(Action action,
+ base::TimeTicks time,
+ float x0,
+ float y0,
+ float x1,
+ float y1,
+ float x2,
+ float y2);
+ MockMotionEvent(Action action,
+ base::TimeTicks time,
+ const std::vector<gfx::PointF>& positions);
+ MockMotionEvent(const MockMotionEvent& other);
+ virtual ~MockMotionEvent();
+
+ // MotionEvent methods.
+ virtual Action GetAction() const OVERRIDE;
+ virtual int GetActionIndex() const OVERRIDE;
+ virtual size_t GetPointerCount() const OVERRIDE;
+ virtual int GetId() const OVERRIDE;
+ virtual int GetPointerId(size_t pointer_index) const OVERRIDE;
+ virtual float GetX(size_t pointer_index) const OVERRIDE;
+ virtual float GetY(size_t pointer_index) const OVERRIDE;
+ virtual float GetRawX(size_t pointer_index) const OVERRIDE;
+ virtual float GetRawY(size_t pointer_index) const OVERRIDE;
+ virtual float GetTouchMajor(size_t pointer_index) const OVERRIDE;
+ virtual float GetPressure(size_t pointer_index) const OVERRIDE;
+ virtual base::TimeTicks GetEventTime() const OVERRIDE;
+ virtual size_t GetHistorySize() const OVERRIDE;
+ virtual base::TimeTicks GetHistoricalEventTime(size_t historical_index) const
+ OVERRIDE;
+ virtual float GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+ virtual float GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+ virtual float GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+
+ virtual scoped_ptr<MotionEvent> Clone() const OVERRIDE;
+ virtual scoped_ptr<MotionEvent> Cancel() const OVERRIDE;
+
+ // Utility methods.
+ void SetId(int new_id);
+ void SetTime(base::TimeTicks new_time);
+ void PressPoint(float x, float y);
+ void MovePoint(size_t index, float x, float y);
+ void ReleasePoint();
+ void CancelPoint();
+ void SetTouchMajor(float new_touch_major);
+ void SetRawOffset(float raw_offset_x, float raw_offset_y);
+
+ MotionEvent::Action action;
+ size_t pointer_count;
+ gfx::PointF points[MAX_POINTERS];
+ gfx::Vector2dF raw_offset;
+ base::TimeTicks time;
+ float touch_major;
+ int id;
+};
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/motion_event.h b/chromium/ui/events/gesture_detection/motion_event.h
new file mode 100644
index 00000000000..3cf4235b78a
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/motion_event.h
@@ -0,0 +1,73 @@
+// 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_GESTURE_DETECTION_MOTION_EVENT_H_
+#define UI_EVENTS_GESTURE_DETECTION_MOTION_EVENT_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+
+namespace ui {
+
+// Abstract class for a generic motion-related event, patterned after that
+// subset of Android's MotionEvent API used in gesture detection.
+class GESTURE_DETECTION_EXPORT MotionEvent {
+ public:
+ enum Action {
+ ACTION_DOWN,
+ ACTION_UP,
+ ACTION_MOVE,
+ ACTION_CANCEL,
+ ACTION_POINTER_DOWN,
+ ACTION_POINTER_UP,
+ };
+
+ // The implementer promises that |GetPointerId()| will never exceed this.
+ enum { MAX_POINTER_ID = 31 };
+
+ virtual ~MotionEvent() {}
+
+ virtual int GetId() const = 0;
+ virtual Action GetAction() const = 0;
+ // Only valid if |GetAction()| returns ACTION_POINTER_UP or
+ // ACTION_POINTER_DOWN.
+ virtual int GetActionIndex() const = 0;
+ virtual size_t GetPointerCount() const = 0;
+ virtual int GetPointerId(size_t pointer_index) const = 0;
+ virtual float GetX(size_t pointer_index) const = 0;
+ virtual float GetY(size_t pointer_index) const = 0;
+ virtual float GetRawX(size_t pointer_index) const = 0;
+ virtual float GetRawY(size_t pointer_index) const = 0;
+ virtual float GetTouchMajor(size_t pointer_index) const = 0;
+ virtual float GetPressure(size_t pointer_index) const = 0;
+ virtual base::TimeTicks GetEventTime() const = 0;
+
+ virtual size_t GetHistorySize() const = 0;
+ virtual base::TimeTicks GetHistoricalEventTime(
+ size_t historical_index) const = 0;
+ virtual float GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const = 0;
+ virtual float GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const = 0;
+ virtual float GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const = 0;
+
+ virtual scoped_ptr<MotionEvent> Clone() const = 0;
+ virtual scoped_ptr<MotionEvent> Cancel() const = 0;
+
+ // Utility accessor methods for convenience.
+ float GetX() const { return GetX(0); }
+ float GetY() const { return GetY(0); }
+ float GetRawX() const { return GetRawX(0); }
+ float GetRawY() const { return GetRawY(0); }
+ float GetRawOffsetX() const { return GetRawX() - GetX(); }
+ float GetRawOffsetY() const { return GetRawY() - GetY(); }
+ float GetTouchMajor() const { return GetTouchMajor(0); }
+ float GetPressure() const { return GetPressure(0); }
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_MOTION_EVENT_H_
diff --git a/chromium/ui/events/gesture_detection/scale_gesture_detector.cc b/chromium/ui/events/gesture_detection/scale_gesture_detector.cc
new file mode 100644
index 00000000000..18fd6d85b59
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/scale_gesture_detector.cc
@@ -0,0 +1,383 @@
+// 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/events/gesture_detection/scale_gesture_detector.h"
+
+#include <limits.h>
+#include <cmath>
+
+#include "base/float_util.h"
+#include "base/logging.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace ui {
+namespace {
+
+// Using a small epsilon when comparing slop distances allows pixel perfect
+// slop determination when using fractional DPI coordinates (assuming the slop
+// region and DPI scale are reasonably proportioned).
+const float kSlopEpsilon = .05f;
+
+const int kTouchStabilizeTimeMs = 128;
+
+const float kScaleFactor = .5f;
+
+} // namespace
+
+// Note: These constants were taken directly from the default (unscaled)
+// versions found in Android's ViewConfiguration.
+ScaleGestureDetector::Config::Config()
+ : min_scaling_touch_major(48),
+ min_scaling_span(200),
+ quick_scale_enabled(true),
+ min_pinch_update_span_delta(0) {
+}
+
+ScaleGestureDetector::Config::~Config() {}
+
+bool ScaleGestureDetector::SimpleScaleGestureListener::OnScale(
+ const ScaleGestureDetector&, const MotionEvent&) {
+ return false;
+}
+
+bool ScaleGestureDetector::SimpleScaleGestureListener::OnScaleBegin(
+ const ScaleGestureDetector&, const MotionEvent&) {
+ return true;
+}
+
+void ScaleGestureDetector::SimpleScaleGestureListener::OnScaleEnd(
+ const ScaleGestureDetector&, const MotionEvent&) {}
+
+ScaleGestureDetector::ScaleGestureDetector(const Config& config,
+ ScaleGestureListener* listener)
+ : listener_(listener),
+ config_(config),
+ focus_x_(0),
+ focus_y_(0),
+ quick_scale_enabled_(false),
+ curr_span_(0),
+ prev_span_(0),
+ initial_span_(0),
+ curr_span_x_(0),
+ curr_span_y_(0),
+ prev_span_x_(0),
+ prev_span_y_(0),
+ in_progress_(0),
+ span_slop_(0),
+ min_span_(0),
+ touch_upper_(0),
+ touch_lower_(0),
+ touch_history_last_accepted_(0),
+ touch_history_direction_(0),
+ touch_min_major_(0),
+ double_tap_focus_x_(0),
+ double_tap_focus_y_(0),
+ double_tap_mode_(DOUBLE_TAP_MODE_NONE),
+ event_before_or_above_starting_gesture_event_(false) {
+ DCHECK(listener_);
+ span_slop_ =
+ (config.gesture_detector_config.touch_slop + kSlopEpsilon) * 2;
+ touch_min_major_ = config.min_scaling_touch_major;
+ min_span_ = config.min_scaling_span + kSlopEpsilon;
+ ResetTouchHistory();
+ SetQuickScaleEnabled(config.quick_scale_enabled);
+}
+
+ScaleGestureDetector::~ScaleGestureDetector() {}
+
+bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) {
+ curr_time_ = event.GetEventTime();
+
+ const int action = event.GetAction();
+
+ // Forward the event to check for double tap gesture.
+ if (quick_scale_enabled_) {
+ DCHECK(gesture_detector_);
+ gesture_detector_->OnTouchEvent(event);
+ }
+
+ const bool stream_complete =
+ action == MotionEvent::ACTION_UP ||
+ action == MotionEvent::ACTION_CANCEL ||
+ (action == MotionEvent::ACTION_POINTER_DOWN && InDoubleTapMode());
+
+ if (action == MotionEvent::ACTION_DOWN || stream_complete) {
+ // Reset any scale in progress with the listener.
+ // If it's an ACTION_DOWN we're beginning a new event stream.
+ // This means the app probably didn't give us all the events. Shame on it.
+ if (in_progress_) {
+ listener_->OnScaleEnd(*this, event);
+ ResetScaleWithSpan(0);
+ } else if (InDoubleTapMode() && stream_complete) {
+ ResetScaleWithSpan(0);
+ }
+
+ if (stream_complete) {
+ ResetTouchHistory();
+ return true;
+ }
+ }
+
+ const bool config_changed = action == MotionEvent::ACTION_DOWN ||
+ action == MotionEvent::ACTION_POINTER_UP ||
+ action == MotionEvent::ACTION_POINTER_DOWN;
+
+ const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP;
+ const int skip_index = pointer_up ? event.GetActionIndex() : -1;
+
+ // Determine focal point.
+ float sum_x = 0, sum_y = 0;
+ const int count = static_cast<int>(event.GetPointerCount());
+ const int unreleased_point_count = pointer_up ? count - 1 : count;
+ const float inverse_unreleased_point_count = 1.0f / unreleased_point_count;
+
+ float focus_x;
+ float focus_y;
+ if (InDoubleTapMode()) {
+ // In double tap mode, the focal pt is always where the double tap
+ // gesture started.
+ focus_x = double_tap_focus_x_;
+ focus_y = double_tap_focus_y_;
+ if (event.GetY() < focus_y) {
+ event_before_or_above_starting_gesture_event_ = true;
+ } else {
+ event_before_or_above_starting_gesture_event_ = false;
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ if (skip_index == i)
+ continue;
+ sum_x += event.GetX(i);
+ sum_y += event.GetY(i);
+ }
+
+ focus_x = sum_x * inverse_unreleased_point_count;
+ focus_y = sum_y * inverse_unreleased_point_count;
+ }
+
+ AddTouchHistory(event);
+
+ // Determine average deviation from focal point.
+ float dev_sum_x = 0, dev_sum_y = 0;
+ for (int i = 0; i < count; i++) {
+ if (skip_index == i)
+ continue;
+
+ dev_sum_x += std::abs(event.GetX(i) - focus_x);
+ dev_sum_y += std::abs(event.GetY(i) - focus_y);
+ }
+ // Convert the resulting diameter into a radius, to include touch
+ // radius in overall deviation.
+ const float touch_size = touch_history_last_accepted_ / 2;
+
+ const float dev_x = (dev_sum_x * inverse_unreleased_point_count) + touch_size;
+ const float dev_y = (dev_sum_y * inverse_unreleased_point_count) + touch_size;
+
+ // Span is the average distance between touch points through the focal point;
+ // i.e. the diameter of the circle with a radius of the average deviation from
+ // the focal point.
+ const float span_x = dev_x * 2;
+ const float span_y = dev_y * 2;
+ float span;
+ if (InDoubleTapMode()) {
+ span = span_y;
+ } else {
+ span = std::sqrt(span_x * span_x + span_y * span_y);
+ }
+
+ // Dispatch begin/end events as needed.
+ // If the configuration changes, notify the app to reset its current state by
+ // beginning a fresh scale event stream.
+ const bool was_in_progress = in_progress_;
+ focus_x_ = focus_x;
+ focus_y_ = focus_y;
+ if (!InDoubleTapMode() && in_progress_ &&
+ (span < min_span_ || config_changed)) {
+ listener_->OnScaleEnd(*this, event);
+ ResetScaleWithSpan(span);
+ }
+ if (config_changed) {
+ prev_span_x_ = curr_span_x_ = span_x;
+ prev_span_y_ = curr_span_y_ = span_y;
+ initial_span_ = prev_span_ = curr_span_ = span;
+ }
+
+ const float min_span = InDoubleTapMode() ? span_slop_ : min_span_;
+ if (!in_progress_ && span >= min_span && (InDoubleTapMode() || count > 1) &&
+ (was_in_progress || std::abs(span - initial_span_) > span_slop_)) {
+ prev_span_x_ = curr_span_x_ = span_x;
+ prev_span_y_ = curr_span_y_ = span_y;
+ prev_span_ = curr_span_ = span;
+ prev_time_ = curr_time_;
+ in_progress_ = listener_->OnScaleBegin(*this, event);
+ }
+
+ // Handle motion; focal point and span/scale factor are changing.
+ if (action == MotionEvent::ACTION_MOVE) {
+ curr_span_x_ = span_x;
+ curr_span_y_ = span_y;
+ curr_span_ = span;
+
+ bool update_prev = true;
+
+ if (in_progress_) {
+ update_prev = listener_->OnScale(*this, event);
+ }
+
+ if (update_prev) {
+ prev_span_x_ = curr_span_x_;
+ prev_span_y_ = curr_span_y_;
+ prev_span_ = curr_span_;
+ prev_time_ = curr_time_;
+ }
+ }
+
+ return true;
+}
+
+void ScaleGestureDetector::SetQuickScaleEnabled(bool scales) {
+ quick_scale_enabled_ = scales;
+ if (quick_scale_enabled_ && !gesture_detector_) {
+ gesture_detector_.reset(
+ new GestureDetector(config_.gesture_detector_config, this, this));
+ }
+}
+
+bool ScaleGestureDetector::IsQuickScaleEnabled() const {
+ return quick_scale_enabled_;
+}
+
+bool ScaleGestureDetector::IsInProgress() const { return in_progress_; }
+
+bool ScaleGestureDetector::InDoubleTapMode() const {
+ return double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS;
+}
+
+float ScaleGestureDetector::GetFocusX() const { return focus_x_; }
+
+float ScaleGestureDetector::GetFocusY() const { return focus_y_; }
+
+float ScaleGestureDetector::GetCurrentSpan() const { return curr_span_; }
+
+float ScaleGestureDetector::GetCurrentSpanX() const { return curr_span_x_; }
+
+float ScaleGestureDetector::GetCurrentSpanY() const { return curr_span_y_; }
+
+float ScaleGestureDetector::GetPreviousSpan() const { return prev_span_; }
+
+float ScaleGestureDetector::GetPreviousSpanX() const { return prev_span_x_; }
+
+float ScaleGestureDetector::GetPreviousSpanY() const { return prev_span_y_; }
+
+float ScaleGestureDetector::GetScaleFactor() const {
+ if (InDoubleTapMode()) {
+ // Drag is moving up; the further away from the gesture start, the smaller
+ // the span should be, the closer, the larger the span, and therefore the
+ // larger the scale.
+ const bool scale_up = (event_before_or_above_starting_gesture_event_ &&
+ (curr_span_ < prev_span_)) ||
+ (!event_before_or_above_starting_gesture_event_ &&
+ (curr_span_ > prev_span_));
+ const float span_diff =
+ (std::abs(1.f - (curr_span_ / prev_span_)) * kScaleFactor);
+ return prev_span_ <= 0 ? 1.f
+ : (scale_up ? (1.f + span_diff) : (1.f - span_diff));
+ }
+ return prev_span_ > 0 ? curr_span_ / prev_span_ : 1;
+}
+
+base::TimeDelta ScaleGestureDetector::GetTimeDelta() const {
+ return curr_time_ - prev_time_;
+}
+
+base::TimeTicks ScaleGestureDetector::GetEventTime() const {
+ return curr_time_;
+}
+
+bool ScaleGestureDetector::OnDoubleTap(const MotionEvent& ev) {
+ // Double tap: start watching for a swipe.
+ double_tap_focus_x_ = ev.GetX();
+ double_tap_focus_y_ = ev.GetY();
+ double_tap_mode_ = DOUBLE_TAP_MODE_IN_PROGRESS;
+ return true;
+}
+
+void ScaleGestureDetector::AddTouchHistory(const MotionEvent& ev) {
+ const base::TimeTicks current_time = ev.GetEventTime();
+ DCHECK(!current_time.is_null());
+ const int count = static_cast<int>(ev.GetPointerCount());
+ bool accept = touch_history_last_accepted_time_.is_null() ||
+ (current_time - touch_history_last_accepted_time_) >=
+ base::TimeDelta::FromMilliseconds(kTouchStabilizeTimeMs);
+ float total = 0;
+ int sample_count = 0;
+ for (int i = 0; i < count; i++) {
+ const bool has_last_accepted = !base::IsNaN(touch_history_last_accepted_);
+ const int history_size = static_cast<int>(ev.GetHistorySize());
+ const int pointersample_count = history_size + 1;
+ for (int h = 0; h < pointersample_count; h++) {
+ float major;
+ if (h < history_size) {
+ major = ev.GetHistoricalTouchMajor(i, h);
+ } else {
+ major = ev.GetTouchMajor(i);
+ }
+ if (major < touch_min_major_)
+ major = touch_min_major_;
+ total += major;
+
+ if (base::IsNaN(touch_upper_) || major > touch_upper_) {
+ touch_upper_ = major;
+ }
+ if (base::IsNaN(touch_lower_) || major < touch_lower_) {
+ touch_lower_ = major;
+ }
+
+ if (has_last_accepted) {
+ const float major_delta = major - touch_history_last_accepted_;
+ const int direction_sig =
+ major_delta > 0 ? 1 : (major_delta < 0 ? -1 : 0);
+ if (direction_sig != touch_history_direction_ ||
+ (direction_sig == 0 && touch_history_direction_ == 0)) {
+ touch_history_direction_ = direction_sig;
+ touch_history_last_accepted_time_ = h < history_size
+ ? ev.GetHistoricalEventTime(h)
+ : ev.GetEventTime();
+ accept = false;
+ }
+ }
+ }
+ sample_count += pointersample_count;
+ }
+
+ const float avg = total / sample_count;
+
+ if (accept) {
+ float new_accepted = (touch_upper_ + touch_lower_ + avg) / 3;
+ touch_upper_ = (touch_upper_ + new_accepted) / 2;
+ touch_lower_ = (touch_lower_ + new_accepted) / 2;
+ touch_history_last_accepted_ = new_accepted;
+ touch_history_direction_ = 0;
+ touch_history_last_accepted_time_ = ev.GetEventTime();
+ }
+}
+
+void ScaleGestureDetector::ResetTouchHistory() {
+ touch_upper_ = std::numeric_limits<float>::quiet_NaN();
+ touch_lower_ = std::numeric_limits<float>::quiet_NaN();
+ touch_history_last_accepted_ = std::numeric_limits<float>::quiet_NaN();
+ touch_history_direction_ = 0;
+ touch_history_last_accepted_time_ = base::TimeTicks();
+}
+
+void ScaleGestureDetector::ResetScaleWithSpan(float span) {
+ in_progress_ = false;
+ initial_span_ = span;
+ double_tap_mode_ = DOUBLE_TAP_MODE_NONE;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/scale_gesture_detector.h b/chromium/ui/events/gesture_detection/scale_gesture_detector.h
new file mode 100644
index 00000000000..b07f78d5785
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/scale_gesture_detector.h
@@ -0,0 +1,158 @@
+// 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_GESTURE_DETECTION_SCALE_GESTURE_DETECTOR_H_
+#define UI_EVENTS_GESTURE_DETECTION_SCALE_GESTURE_DETECTOR_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/gesture_detector.h"
+
+namespace ui {
+
+class MotionEvent;
+
+// Port of ScaleGestureDetector.java from Android
+// * platform/frameworks/base/core/java/android/view/ScaleGestureDetector.java
+// * Change-Id: I3e7926a4f6f9ab4951f380bd004499c78b3bda69
+// * Please update the Change-Id as upstream Android changes are pulled.
+class ScaleGestureDetector : public GestureDetector::SimpleGestureListener {
+ public:
+ struct GESTURE_DETECTION_EXPORT Config {
+ Config();
+ ~Config();
+ GestureDetector::Config gesture_detector_config;
+
+ // Minimum accepted value for TouchMajor while scaling (in dips).
+ float min_scaling_touch_major;
+
+ // Minimum span needed to initiate a scaling gesture (in dips).
+ float min_scaling_span;
+
+ // Whether double-tap drag scaling is enabled.
+ bool quick_scale_enabled;
+
+ // Minimum pinch span change before pinch occurs (in dips). See
+ // crbug.com/373318.
+ float min_pinch_update_span_delta;
+ };
+
+ class ScaleGestureListener {
+ public:
+ virtual ~ScaleGestureListener() {}
+ virtual bool OnScale(const ScaleGestureDetector& detector,
+ const MotionEvent& e) = 0;
+ virtual bool OnScaleBegin(const ScaleGestureDetector& detector,
+ const MotionEvent& e) = 0;
+ virtual void OnScaleEnd(const ScaleGestureDetector& detector,
+ const MotionEvent& e) = 0;
+ };
+
+ // A convenience class to extend when you only want to listen for a subset of
+ // scaling-related events. This implements all methods in
+ // |ScaleGestureListener| but does nothing.
+ // |OnScale()| returns false so that a subclass can retrieve the accumulated
+ // scale factor in an overridden |OnScaleEnd()|.
+ // |OnScaleBegin() returns true.
+ class SimpleScaleGestureListener : public ScaleGestureListener {
+ public:
+ // ScaleGestureListener implementation.
+ virtual bool OnScale(const ScaleGestureDetector&,
+ const MotionEvent&) OVERRIDE;
+ virtual bool OnScaleBegin(const ScaleGestureDetector&,
+ const MotionEvent&) OVERRIDE;
+ virtual void OnScaleEnd(const ScaleGestureDetector&,
+ const MotionEvent&) OVERRIDE;
+ };
+
+ ScaleGestureDetector(const Config& config, ScaleGestureListener* listener);
+ virtual ~ScaleGestureDetector();
+
+ // Accepts MotionEvents and dispatches events to a |ScaleGestureListener|
+ // when appropriate.
+ //
+ // Note: Applications should pass a complete and consistent event stream to
+ // this method. A complete and consistent event stream involves all
+ // MotionEvents from the initial ACTION_DOWN to the final ACTION_UP or
+ // ACTION_CANCEL.
+ //
+ // Returns true if the event was processed and the detector wants to receive
+ // the rest of the MotionEvents in this event stream.
+ bool OnTouchEvent(const MotionEvent& event);
+
+ // Set whether the associated |ScaleGestureListener| should receive
+ // OnScale callbacks when the user performs a doubletap followed by a swipe.
+ void SetQuickScaleEnabled(bool scales);
+ bool IsQuickScaleEnabled() const;
+ bool IsInProgress() const;
+ bool InDoubleTapMode() const;
+ float GetFocusX() const;
+ float GetFocusY() const;
+ float GetCurrentSpan() const;
+ float GetCurrentSpanX() const;
+ float GetCurrentSpanY() const;
+ float GetPreviousSpan() const;
+ float GetPreviousSpanX() const;
+ float GetPreviousSpanY() const;
+ float GetScaleFactor() const;
+ base::TimeDelta GetTimeDelta() const;
+ base::TimeTicks GetEventTime() const;
+
+ private:
+ enum DoubleTapMode { DOUBLE_TAP_MODE_NONE, DOUBLE_TAP_MODE_IN_PROGRESS };
+
+ // DoubleTapListener implementation.
+ virtual bool OnDoubleTap(const MotionEvent& ev) OVERRIDE;
+
+ // The TouchMajor/TouchMinor elements of a MotionEvent can flutter/jitter on
+ // some hardware/driver combos. Smooth out to get kinder, gentler behavior.
+ void AddTouchHistory(const MotionEvent& ev);
+ void ResetTouchHistory();
+
+ void ResetScaleWithSpan(float span);
+
+ ScaleGestureListener* const listener_;
+
+ Config config_;
+
+ float focus_x_;
+ float focus_y_;
+
+ bool quick_scale_enabled_;
+
+ float curr_span_;
+ float prev_span_;
+ float initial_span_;
+ float curr_span_x_;
+ float curr_span_y_;
+ float prev_span_x_;
+ float prev_span_y_;
+ base::TimeTicks curr_time_;
+ base::TimeTicks prev_time_;
+ bool in_progress_;
+ float span_slop_;
+ float min_span_;
+
+ // Bounds for recently seen values.
+ float touch_upper_;
+ float touch_lower_;
+ float touch_history_last_accepted_;
+ int touch_history_direction_;
+ base::TimeTicks touch_history_last_accepted_time_;
+ float touch_min_major_;
+ float double_tap_focus_x_;
+ float double_tap_focus_y_;
+ DoubleTapMode double_tap_mode_;
+
+ bool event_before_or_above_starting_gesture_event_;
+
+ scoped_ptr<GestureDetector> gesture_detector_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScaleGestureDetector);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_SCALE_GESTURE_DETECTOR_H_
diff --git a/chromium/ui/events/gesture_detection/snap_scroll_controller.cc b/chromium/ui/events/gesture_detection/snap_scroll_controller.cc
new file mode 100644
index 00000000000..bde5a35602d
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/snap_scroll_controller.cc
@@ -0,0 +1,106 @@
+// 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/events/gesture_detection/snap_scroll_controller.h"
+
+#include <cmath>
+
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/display.h"
+
+namespace ui {
+namespace {
+const int kSnapBound = 16;
+const float kMinSnapChannelDistance = kSnapBound;
+const float kMaxSnapChannelDistance = kMinSnapChannelDistance * 3.f;
+const float kSnapChannelDipsPerScreenDip = kMinSnapChannelDistance / 480.f;
+
+float CalculateChannelDistance(const gfx::Display& display) {
+ if (display.bounds().IsEmpty())
+ return kMinSnapChannelDistance;
+
+ float screen_size =
+ std::abs(hypot(static_cast<float>(display.bounds().width()),
+ static_cast<float>(display.bounds().height())));
+
+ float snap_channel_distance = screen_size * kSnapChannelDipsPerScreenDip;
+ return std::max(kMinSnapChannelDistance,
+ std::min(kMaxSnapChannelDistance, snap_channel_distance));
+}
+
+} // namespace
+
+
+SnapScrollController::SnapScrollController(const gfx::Display& display)
+ : channel_distance_(CalculateChannelDistance(display)),
+ snap_scroll_mode_(SNAP_NONE),
+ first_touch_x_(-1),
+ first_touch_y_(-1),
+ distance_x_(0),
+ distance_y_(0) {}
+
+SnapScrollController::~SnapScrollController() {}
+
+void SnapScrollController::UpdateSnapScrollMode(float distance_x,
+ float distance_y) {
+ if (snap_scroll_mode_ == SNAP_HORIZ || snap_scroll_mode_ == SNAP_VERT) {
+ distance_x_ += std::abs(distance_x);
+ distance_y_ += std::abs(distance_y);
+ if (snap_scroll_mode_ == SNAP_HORIZ) {
+ if (distance_y_ > channel_distance_) {
+ snap_scroll_mode_ = SNAP_NONE;
+ } else if (distance_x_ > channel_distance_) {
+ distance_x_ = 0;
+ distance_y_ = 0;
+ }
+ } else {
+ if (distance_x_ > channel_distance_) {
+ snap_scroll_mode_ = SNAP_NONE;
+ } else if (distance_y_ > channel_distance_) {
+ distance_x_ = 0;
+ distance_y_ = 0;
+ }
+ }
+ }
+}
+
+void SnapScrollController::SetSnapScrollingMode(
+ const MotionEvent& event,
+ bool is_scale_gesture_detection_in_progress) {
+ switch (event.GetAction()) {
+ case MotionEvent::ACTION_DOWN:
+ snap_scroll_mode_ = SNAP_NONE;
+ first_touch_x_ = event.GetX();
+ first_touch_y_ = event.GetY();
+ break;
+ // Set scrolling mode to SNAP_X if scroll towards x-axis exceeds kSnapBound
+ // and movement towards y-axis is trivial.
+ // Set scrolling mode to SNAP_Y if scroll towards y-axis exceeds kSnapBound
+ // and movement towards x-axis is trivial.
+ // Scrolling mode will remain in SNAP_NONE for other conditions.
+ case MotionEvent::ACTION_MOVE:
+ if (!is_scale_gesture_detection_in_progress &&
+ snap_scroll_mode_ == SNAP_NONE) {
+ int x_diff = static_cast<int>(std::abs(event.GetX() - first_touch_x_));
+ int y_diff = static_cast<int>(std::abs(event.GetY() - first_touch_y_));
+ if (x_diff > kSnapBound && y_diff < kSnapBound) {
+ snap_scroll_mode_ = SNAP_HORIZ;
+ } else if (x_diff < kSnapBound && y_diff > kSnapBound) {
+ snap_scroll_mode_ = SNAP_VERT;
+ }
+ }
+ break;
+ case MotionEvent::ACTION_UP:
+ case MotionEvent::ACTION_CANCEL:
+ first_touch_x_ = -1;
+ first_touch_y_ = -1;
+ distance_x_ = 0;
+ distance_y_ = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/snap_scroll_controller.h b/chromium/ui/events/gesture_detection/snap_scroll_controller.h
new file mode 100644
index 00000000000..753c2bcb201
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/snap_scroll_controller.h
@@ -0,0 +1,60 @@
+// 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_GESTURE_DETECTION_SNAP_SCROLL_CONTROLLER_H_
+#define UI_EVENTS_GESTURE_DETECTION_SNAP_SCROLL_CONTROLLER_H_
+
+#include "base/basictypes.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+
+namespace gfx {
+class Display;
+}
+
+namespace ui {
+
+class MotionEvent;
+class ZoomManager;
+
+// Port of SnapScrollController.java from Chromium
+// Controls the scroll snapping behavior based on scroll updates.
+class SnapScrollController {
+ public:
+ explicit SnapScrollController(const gfx::Display& display);
+ ~SnapScrollController();
+
+ // Updates the snap scroll mode based on the given X and Y distance to be
+ // moved on scroll. If the scroll update is above a threshold, the snapping
+ // behavior is reset.
+ void UpdateSnapScrollMode(float distance_x, float distance_y);
+
+ // Sets the snap scroll mode based on the event type.
+ void SetSnapScrollingMode(const MotionEvent& event,
+ bool is_scale_gesture_detection_in_progress);
+
+ void ResetSnapScrollMode() { snap_scroll_mode_ = SNAP_NONE; }
+ bool IsSnapVertical() const { return snap_scroll_mode_ == SNAP_VERT; }
+ bool IsSnapHorizontal() const { return snap_scroll_mode_ == SNAP_HORIZ; }
+ bool IsSnappingScrolls() const { return snap_scroll_mode_ != SNAP_NONE; }
+
+ private:
+ enum SnapMode {
+ SNAP_NONE,
+ SNAP_HORIZ,
+ SNAP_VERT
+ };
+
+ float channel_distance_;
+ SnapMode snap_scroll_mode_;
+ float first_touch_x_;
+ float first_touch_y_;
+ float distance_x_;
+ float distance_y_;
+
+ DISALLOW_COPY_AND_ASSIGN(SnapScrollController);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_SNAP_SCROLL_CONTROLLER_H_
diff --git a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc
new file mode 100644
index 00000000000..0e775dd9c19
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc
@@ -0,0 +1,400 @@
+// 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/events/gesture_detection/touch_disposition_gesture_filter.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+#include "ui/events/gesture_event_details.h"
+
+namespace ui {
+namespace {
+
+// A BitSet32 is used for tracking dropped gesture types.
+COMPILE_ASSERT(ET_GESTURE_TYPE_END - ET_GESTURE_TYPE_START < 32,
+ gesture_type_count_too_large);
+
+GestureEventData CreateGesture(EventType type,
+ int motion_event_id,
+ const GestureEventDataPacket& packet) {
+ return GestureEventData(GestureEventDetails(type, 0, 0),
+ motion_event_id,
+ packet.timestamp(),
+ packet.touch_location().x(),
+ packet.touch_location().y(),
+ packet.raw_touch_location().x(),
+ packet.raw_touch_location().y(),
+ 1,
+ gfx::RectF(packet.touch_location(), gfx::SizeF()));
+}
+
+enum RequiredTouches {
+ RT_NONE = 0,
+ RT_START = 1 << 0,
+ RT_CURRENT = 1 << 1,
+};
+
+struct DispositionHandlingInfo {
+ // A bitwise-OR of |RequiredTouches|.
+ int required_touches;
+ EventType antecedent_event_type;
+
+ explicit DispositionHandlingInfo(int required_touches)
+ : required_touches(required_touches), antecedent_event_type(ET_UNKNOWN) {}
+
+ DispositionHandlingInfo(int required_touches,
+ EventType antecedent_event_type)
+ : required_touches(required_touches),
+ antecedent_event_type(antecedent_event_type) {}
+};
+
+DispositionHandlingInfo Info(int required_touches) {
+ return DispositionHandlingInfo(required_touches);
+}
+
+DispositionHandlingInfo Info(int required_touches,
+ EventType antecedent_event_type) {
+ return DispositionHandlingInfo(required_touches, antecedent_event_type);
+}
+
+// This approach to disposition handling is described at http://goo.gl/5G8PWJ.
+DispositionHandlingInfo GetDispositionHandlingInfo(EventType type) {
+ switch (type) {
+ case ET_GESTURE_TAP_DOWN:
+ return Info(RT_START);
+ case ET_GESTURE_TAP_CANCEL:
+ return Info(RT_START);
+ case ET_GESTURE_SHOW_PRESS:
+ return Info(RT_START);
+ case ET_GESTURE_LONG_PRESS:
+ return Info(RT_START);
+ case ET_GESTURE_LONG_TAP:
+ return Info(RT_START | RT_CURRENT);
+ case ET_GESTURE_TAP:
+ return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED);
+ case ET_GESTURE_TAP_UNCONFIRMED:
+ return Info(RT_START | RT_CURRENT);
+ case ET_GESTURE_DOUBLE_TAP:
+ return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED);
+ case ET_GESTURE_SCROLL_BEGIN:
+ return Info(RT_START | RT_CURRENT);
+ case ET_GESTURE_SCROLL_UPDATE:
+ return Info(RT_CURRENT, ET_GESTURE_SCROLL_BEGIN);
+ case ET_GESTURE_SCROLL_END:
+ return Info(RT_NONE, ET_GESTURE_SCROLL_BEGIN);
+ case ET_SCROLL_FLING_START:
+ // We rely on |EndScrollGestureIfNecessary| to end the scroll if the fling
+ // start is prevented.
+ return Info(RT_NONE, ET_GESTURE_SCROLL_UPDATE);
+ case ET_SCROLL_FLING_CANCEL:
+ return Info(RT_NONE, ET_SCROLL_FLING_START);
+ case ET_GESTURE_PINCH_BEGIN:
+ return Info(RT_START, ET_GESTURE_SCROLL_BEGIN);
+ case ET_GESTURE_PINCH_UPDATE:
+ return Info(RT_CURRENT, ET_GESTURE_PINCH_BEGIN);
+ case ET_GESTURE_PINCH_END:
+ return Info(RT_NONE, ET_GESTURE_PINCH_BEGIN);
+ case ET_GESTURE_BEGIN:
+ return Info(RT_START);
+ case ET_GESTURE_END:
+ return Info(RT_NONE, ET_GESTURE_BEGIN);
+ case ET_GESTURE_SWIPE:
+ return Info(RT_START, ET_GESTURE_SCROLL_BEGIN);
+ case ET_GESTURE_TWO_FINGER_TAP:
+ return Info(RT_START);
+ default:
+ break;
+ }
+ NOTREACHED();
+ return Info(RT_NONE);
+}
+
+int GetGestureTypeIndex(EventType type) {
+ DCHECK_GE(type, ET_GESTURE_TYPE_START);
+ DCHECK_LE(type, ET_GESTURE_TYPE_END);
+ return type - ET_GESTURE_TYPE_START;
+}
+
+bool IsTouchStartEvent(GestureEventDataPacket::GestureSource gesture_source) {
+ return gesture_source == GestureEventDataPacket::TOUCH_SEQUENCE_START ||
+ gesture_source == GestureEventDataPacket::TOUCH_START;
+}
+
+} // namespace
+
+// TouchDispositionGestureFilter
+
+TouchDispositionGestureFilter::TouchDispositionGestureFilter(
+ TouchDispositionGestureFilterClient* client)
+ : client_(client),
+ needs_tap_ending_event_(false),
+ needs_show_press_event_(false),
+ needs_fling_ending_event_(false),
+ needs_scroll_ending_event_(false) {
+ DCHECK(client_);
+}
+
+TouchDispositionGestureFilter::~TouchDispositionGestureFilter() {
+}
+
+TouchDispositionGestureFilter::PacketResult
+TouchDispositionGestureFilter::OnGesturePacket(
+ const GestureEventDataPacket& packet) {
+ if (packet.gesture_source() == GestureEventDataPacket::UNDEFINED ||
+ packet.gesture_source() == GestureEventDataPacket::INVALID)
+ return INVALID_PACKET_TYPE;
+
+ if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START)
+ sequences_.push(GestureSequence());
+
+ if (IsEmpty())
+ return INVALID_PACKET_ORDER;
+
+ if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT &&
+ Tail().empty()) {
+ // Handle the timeout packet immediately if the packet preceding the timeout
+ // has already been dispatched.
+ FilterAndSendPacket(packet);
+ return SUCCESS;
+ }
+
+ Tail().push(packet);
+ return SUCCESS;
+}
+
+void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) {
+ // Spurious touch acks from the renderer should not trigger a crash.
+ if (IsEmpty() || (Head().empty() && sequences_.size() == 1))
+ return;
+
+ if (Head().empty())
+ PopGestureSequence();
+
+ GestureSequence& sequence = Head();
+
+ // Dispatch the packet corresponding to the ack'ed touch, as well as any
+ // additional timeout-based packets queued before the ack was received.
+ bool touch_packet_for_current_ack_handled = false;
+ while (!sequence.empty()) {
+ DCHECK_NE(sequence.front().gesture_source(),
+ GestureEventDataPacket::UNDEFINED);
+ DCHECK_NE(sequence.front().gesture_source(),
+ GestureEventDataPacket::INVALID);
+
+ GestureEventDataPacket::GestureSource source =
+ sequence.front().gesture_source();
+ if (source != GestureEventDataPacket::TOUCH_TIMEOUT) {
+ // We should handle at most one non-timeout based packet.
+ if (touch_packet_for_current_ack_handled)
+ break;
+ state_.OnTouchEventAck(event_consumed, IsTouchStartEvent(source));
+ touch_packet_for_current_ack_handled = true;
+ }
+ // We need to pop the current sequence before sending the packet, because
+ // sending the packet could result in this method being re-entered (e.g. on
+ // Aura, we could trigger a touch-cancel). As popping the sequence destroys
+ // the packet, we copy the packet before popping it.
+ const GestureEventDataPacket packet = sequence.front();
+ sequence.pop();
+ FilterAndSendPacket(packet);
+ }
+ DCHECK(touch_packet_for_current_ack_handled);
+}
+
+bool TouchDispositionGestureFilter::IsEmpty() const {
+ return sequences_.empty();
+}
+
+void TouchDispositionGestureFilter::FilterAndSendPacket(
+ const GestureEventDataPacket& packet) {
+ if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START) {
+ CancelTapIfNecessary(packet);
+ EndScrollIfNecessary(packet);
+ CancelFlingIfNecessary(packet);
+ } else if (packet.gesture_source() == GestureEventDataPacket::TOUCH_START) {
+ CancelTapIfNecessary(packet);
+ }
+
+ for (size_t i = 0; i < packet.gesture_count(); ++i) {
+ const GestureEventData& gesture = packet.gesture(i);
+ DCHECK_GE(gesture.details.type(), ET_GESTURE_TYPE_START);
+ DCHECK_LE(gesture.details.type(), ET_GESTURE_TYPE_END);
+ if (state_.Filter(gesture.details.type())) {
+ CancelTapIfNecessary(packet);
+ continue;
+ }
+ if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT) {
+ // Sending a timed gesture could delete |this|, so we need to return
+ // directly after the |SendGesture| call.
+ SendGesture(gesture, packet);
+ return;
+ }
+
+ SendGesture(gesture, packet);
+ }
+
+ if (packet.gesture_source() ==
+ GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL) {
+ EndScrollIfNecessary(packet);
+ CancelTapIfNecessary(packet);
+ } else if (packet.gesture_source() ==
+ GestureEventDataPacket::TOUCH_SEQUENCE_END) {
+ EndScrollIfNecessary(packet);
+ }
+}
+
+void TouchDispositionGestureFilter::SendGesture(
+ const GestureEventData& event,
+ const GestureEventDataPacket& packet_being_sent) {
+ // TODO(jdduke): Factor out gesture stream reparation code into a standalone
+ // utility class.
+ switch (event.type()) {
+ case ET_GESTURE_LONG_TAP:
+ if (!needs_tap_ending_event_)
+ return;
+ CancelTapIfNecessary(packet_being_sent);
+ CancelFlingIfNecessary(packet_being_sent);
+ break;
+ case ET_GESTURE_TAP_DOWN:
+ DCHECK(!needs_tap_ending_event_);
+ ending_event_motion_event_id_ = event.motion_event_id;
+ needs_show_press_event_ = true;
+ needs_tap_ending_event_ = true;
+ break;
+ case ET_GESTURE_SHOW_PRESS:
+ if (!needs_show_press_event_)
+ return;
+ needs_show_press_event_ = false;
+ break;
+ case ET_GESTURE_DOUBLE_TAP:
+ CancelTapIfNecessary(packet_being_sent);
+ needs_show_press_event_ = false;
+ break;
+ case ET_GESTURE_TAP:
+ DCHECK(needs_tap_ending_event_);
+ if (needs_show_press_event_) {
+ SendGesture(GestureEventData(ET_GESTURE_SHOW_PRESS, event),
+ packet_being_sent);
+ DCHECK(!needs_show_press_event_);
+ }
+ needs_tap_ending_event_ = false;
+ break;
+ case ET_GESTURE_TAP_CANCEL:
+ needs_show_press_event_ = false;
+ needs_tap_ending_event_ = false;
+ break;
+ case ET_GESTURE_SCROLL_BEGIN:
+ CancelTapIfNecessary(packet_being_sent);
+ CancelFlingIfNecessary(packet_being_sent);
+ EndScrollIfNecessary(packet_being_sent);
+ ending_event_motion_event_id_ = event.motion_event_id;
+ needs_scroll_ending_event_ = true;
+ break;
+ case ET_GESTURE_SCROLL_END:
+ needs_scroll_ending_event_ = false;
+ break;
+ case ET_SCROLL_FLING_START:
+ CancelFlingIfNecessary(packet_being_sent);
+ ending_event_motion_event_id_ = event.motion_event_id;
+ needs_fling_ending_event_ = true;
+ needs_scroll_ending_event_ = false;
+ break;
+ case ET_SCROLL_FLING_CANCEL:
+ needs_fling_ending_event_ = false;
+ break;
+ default:
+ break;
+ }
+ client_->ForwardGestureEvent(event);
+}
+
+void TouchDispositionGestureFilter::CancelTapIfNecessary(
+ const GestureEventDataPacket& packet_being_sent) {
+ if (!needs_tap_ending_event_)
+ return;
+
+ SendGesture(CreateGesture(ET_GESTURE_TAP_CANCEL,
+ ending_event_motion_event_id_,
+ packet_being_sent),
+ packet_being_sent);
+ DCHECK(!needs_tap_ending_event_);
+}
+
+void TouchDispositionGestureFilter::CancelFlingIfNecessary(
+ const GestureEventDataPacket& packet_being_sent) {
+ if (!needs_fling_ending_event_)
+ return;
+
+ SendGesture(CreateGesture(ET_SCROLL_FLING_CANCEL,
+ ending_event_motion_event_id_,
+ packet_being_sent),
+ packet_being_sent);
+ DCHECK(!needs_fling_ending_event_);
+}
+
+void TouchDispositionGestureFilter::EndScrollIfNecessary(
+ const GestureEventDataPacket& packet_being_sent) {
+ if (!needs_scroll_ending_event_)
+ return;
+
+ SendGesture(CreateGesture(ET_GESTURE_SCROLL_END,
+ ending_event_motion_event_id_,
+ packet_being_sent),
+ packet_being_sent);
+ DCHECK(!needs_scroll_ending_event_);
+}
+
+void TouchDispositionGestureFilter::PopGestureSequence() {
+ DCHECK(Head().empty());
+ state_ = GestureHandlingState();
+ sequences_.pop();
+}
+
+TouchDispositionGestureFilter::GestureSequence&
+TouchDispositionGestureFilter::Head() {
+ DCHECK(!sequences_.empty());
+ return sequences_.front();
+}
+
+TouchDispositionGestureFilter::GestureSequence&
+TouchDispositionGestureFilter::Tail() {
+ DCHECK(!sequences_.empty());
+ return sequences_.back();
+}
+
+// TouchDispositionGestureFilter::GestureHandlingState
+
+TouchDispositionGestureFilter::GestureHandlingState::GestureHandlingState()
+ : start_touch_consumed_(false),
+ current_touch_consumed_(false) {}
+
+void TouchDispositionGestureFilter::GestureHandlingState::OnTouchEventAck(
+ bool event_consumed,
+ bool is_touch_start_event) {
+ current_touch_consumed_ = event_consumed;
+ if (event_consumed && is_touch_start_event)
+ start_touch_consumed_ = true;
+}
+
+bool TouchDispositionGestureFilter::GestureHandlingState::Filter(
+ EventType gesture_type) {
+ DispositionHandlingInfo disposition_handling_info =
+ GetDispositionHandlingInfo(gesture_type);
+
+ int required_touches = disposition_handling_info.required_touches;
+ EventType antecedent_event_type =
+ disposition_handling_info.antecedent_event_type;
+ if ((required_touches & RT_START && start_touch_consumed_) ||
+ (required_touches & RT_CURRENT && current_touch_consumed_) ||
+ (antecedent_event_type != ET_UNKNOWN &&
+ last_gesture_of_type_dropped_.has_bit(
+ GetGestureTypeIndex(antecedent_event_type)))) {
+ last_gesture_of_type_dropped_.mark_bit(GetGestureTypeIndex(gesture_type));
+ return true;
+ }
+ last_gesture_of_type_dropped_.clear_bit(GetGestureTypeIndex(gesture_type));
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.h b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.h
new file mode 100644
index 00000000000..6e57bdb5235
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.h
@@ -0,0 +1,108 @@
+// 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_GESTURE_DETECTION_TOUCH_DISPOSITION_GESTURE_FILTER_H_
+#define UI_EVENTS_GESTURE_DETECTION_TOUCH_DISPOSITION_GESTURE_FILTER_H_
+
+#include <queue>
+
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/bitset_32.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/gesture_event_data_packet.h"
+
+namespace ui {
+
+// Interface with which the |TouchDispositionGestureFilter| forwards gestures
+// for a given touch event.
+class GESTURE_DETECTION_EXPORT TouchDispositionGestureFilterClient {
+ public:
+ virtual void ForwardGestureEvent(const GestureEventData&) = 0;
+};
+
+// Given a stream of touch-derived gesture packets, produces a refined gesture
+// sequence based on the ack dispositions of the generating touch events.
+class GESTURE_DETECTION_EXPORT TouchDispositionGestureFilter {
+ public:
+ explicit TouchDispositionGestureFilter(
+ TouchDispositionGestureFilterClient* client);
+ ~TouchDispositionGestureFilter();
+
+ // To be called upon production of touch-derived gestures by the platform,
+ // *prior* to the generating touch being forward to the renderer. In
+ // particular, |packet| contains [0, n] gestures that correspond to a given
+ // touch event. It is imperative that a single packet is received for
+ // *each* touch event, even those that did not produce a gesture.
+ enum PacketResult {
+ SUCCESS, // Packet successfully queued.
+ INVALID_PACKET_ORDER, // Packets were received in the wrong order, i.e.,
+ // TOUCH_BEGIN should always precede other packets.
+ INVALID_PACKET_TYPE, // Packet had an invalid type.
+ };
+ PacketResult OnGesturePacket(const GestureEventDataPacket& packet);
+
+ // To be called upon receipt of *all* touch event acks.
+ void OnTouchEventAck(bool event_consumed);
+
+ // Whether there are any active gesture sequences still queued in the filter.
+ bool IsEmpty() const;
+
+ private:
+ // A single GestureSequence corresponds to all gestures created
+ // between the first finger down and the last finger up, including gestures
+ // generated by timeouts from a statinoary finger.
+ typedef std::queue<GestureEventDataPacket> GestureSequence;
+
+ // Utility class for maintaining the touch and gesture handling state for the
+ // current gesture sequence.
+ class GestureHandlingState {
+ public:
+ GestureHandlingState();
+
+ // To be called on each touch event ack.
+ void OnTouchEventAck(bool event_consumed, bool is_touch_start_event);
+
+ // Returns true iff the gesture should be dropped.
+ bool Filter(EventType type);
+
+ private:
+ // True iff the sequence has had any touch down event consumed.
+ bool start_touch_consumed_;
+ // True iff the most recently ack'ed touch event was consumed.
+ bool current_touch_consumed_;
+ // If the previous gesture of a given type was dropped instead of being
+ // dispatched, its type will occur in this set.
+ BitSet32 last_gesture_of_type_dropped_;
+ };
+
+ void FilterAndSendPacket(const GestureEventDataPacket& packet);
+ void SendGesture(const GestureEventData& gesture,
+ const GestureEventDataPacket& packet);
+ void CancelTapIfNecessary(const GestureEventDataPacket& packet);
+ void CancelFlingIfNecessary(const GestureEventDataPacket& packet);
+ void EndScrollIfNecessary(const GestureEventDataPacket& packet);
+ void PopGestureSequence();
+ GestureSequence& Head();
+ GestureSequence& Tail();
+
+ TouchDispositionGestureFilterClient* client_;
+ std::queue<GestureSequence> sequences_;
+
+ GestureHandlingState state_;
+
+ // Bookkeeping for inserting synthetic Gesture{Tap,Fling}Cancel events
+ // when necessary, e.g., GestureTapCancel when scrolling begins, or
+ // GestureFlingCancel when a user taps following a GestureFlingStart.
+ int ending_event_motion_event_id_;
+ bool needs_tap_ending_event_;
+ bool needs_show_press_event_;
+ bool needs_fling_ending_event_;
+ bool needs_scroll_ending_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchDispositionGestureFilter);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_TOUCH_DISPOSITION_GESTURE_FILTER_H_
diff --git a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc
new file mode 100644
index 00000000000..a5471f73cff
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc
@@ -0,0 +1,1059 @@
+// 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 "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/gesture_detection/mock_motion_event.h"
+#include "ui/events/gesture_detection/touch_disposition_gesture_filter.h"
+
+namespace ui {
+
+class TouchDispositionGestureFilterTest
+ : public testing::Test,
+ public TouchDispositionGestureFilterClient {
+ public:
+ TouchDispositionGestureFilterTest()
+ : cancel_after_next_gesture_(false), sent_gesture_count_(0) {}
+ virtual ~TouchDispositionGestureFilterTest() {}
+
+ // testing::Test
+ virtual void SetUp() OVERRIDE {
+ queue_.reset(new TouchDispositionGestureFilter(this));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ queue_.reset();
+ }
+
+ // TouchDispositionGestureFilterClient
+ virtual void ForwardGestureEvent(const GestureEventData& event) OVERRIDE {
+ ++sent_gesture_count_;
+ last_sent_gesture_time_ = event.time;
+ sent_gestures_.push_back(event.type());
+ last_sent_gesture_location_ = gfx::PointF(event.x, event.y);
+ last_sent_gesture_raw_location_ = gfx::PointF(event.raw_x, event.raw_y);
+ if (cancel_after_next_gesture_) {
+ CancelTouchPoint();
+ SendTouchNotConsumedAck();
+ cancel_after_next_gesture_ = false;
+ }
+ }
+
+ protected:
+ typedef std::vector<EventType> GestureList;
+
+ ::testing::AssertionResult GesturesMatch(const GestureList& expected,
+ const GestureList& actual) {
+ if (expected.size() != actual.size()) {
+ return ::testing::AssertionFailure()
+ << "actual.size(" << actual.size()
+ << ") != expected.size(" << expected.size() << ")";
+ }
+
+ for (size_t i = 0; i < expected.size(); ++i) {
+ if (expected[i] != actual[i]) {
+ return ::testing::AssertionFailure()
+ << "actual[" << i << "] ("
+ << actual[i]
+ << ") != expected[" << i << "] ("
+ << expected[i] << ")";
+ }
+ }
+
+ return ::testing::AssertionSuccess();
+ }
+
+ GestureList Gestures(EventType type) {
+ return GestureList(1, type);
+ }
+
+ GestureList Gestures(EventType type0, EventType type1) {
+ GestureList gestures(2);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ return gestures;
+ }
+
+ GestureList Gestures(EventType type0,
+ EventType type1,
+ EventType type2) {
+ GestureList gestures(3);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ gestures[2] = type2;
+ return gestures;
+ }
+
+ GestureList Gestures(EventType type0,
+ EventType type1,
+ EventType type2,
+ EventType type3) {
+ GestureList gestures(4);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ gestures[2] = type2;
+ gestures[3] = type3;
+ return gestures;
+ }
+
+ void SendTouchGestures() {
+ touch_event_.SetTime(base::TimeTicks::Now());
+ EXPECT_EQ(TouchDispositionGestureFilter::SUCCESS,
+ SendTouchGestures(touch_event_, pending_gesture_packet_));
+ GestureEventDataPacket gesture_packet;
+ std::swap(gesture_packet, pending_gesture_packet_);
+ }
+
+ TouchDispositionGestureFilter::PacketResult
+ SendTouchGestures(const MotionEvent& touch,
+ const GestureEventDataPacket& packet) {
+ GestureEventDataPacket touch_packet =
+ GestureEventDataPacket::FromTouch(touch);
+ for (size_t i = 0; i < packet.gesture_count(); ++i)
+ touch_packet.Push(packet.gesture(i));
+ return queue_->OnGesturePacket(touch_packet);
+ }
+
+ TouchDispositionGestureFilter::PacketResult
+ SendTimeoutGesture(EventType type) {
+ return queue_->OnGesturePacket(
+ GestureEventDataPacket::FromTouchTimeout(CreateGesture(type)));
+ }
+
+ TouchDispositionGestureFilter::PacketResult
+ SendGesturePacket(const GestureEventDataPacket& packet) {
+ return queue_->OnGesturePacket(packet);
+ }
+
+ void SendTouchEventAck(bool event_consumed) {
+ queue_->OnTouchEventAck(event_consumed);
+ }
+
+ void SendTouchConsumedAck() { SendTouchEventAck(true); }
+
+ void SendTouchNotConsumedAck() { SendTouchEventAck(false); }
+
+ void PushGesture(EventType type) {
+ pending_gesture_packet_.Push(CreateGesture(type));
+ }
+
+ void PressTouchPoint(int x, int y) {
+ touch_event_.PressPoint(x, y);
+ SendTouchGestures();
+ }
+
+ void MoveTouchPoint(size_t index, int x, int y) {
+ touch_event_.MovePoint(index, x, y);
+ SendTouchGestures();
+ }
+
+ void ReleaseTouchPoint() {
+ touch_event_.ReleasePoint();
+ SendTouchGestures();
+ }
+
+ void CancelTouchPoint() {
+ touch_event_.CancelPoint();
+ SendTouchGestures();
+ }
+
+ void SetRawTouchOffset(const gfx::Vector2dF& raw_offset) {
+ touch_event_.SetRawOffset(raw_offset.x(), raw_offset.y());
+ }
+
+ void ResetTouchPoints() { touch_event_ = MockMotionEvent(); }
+
+ bool GesturesSent() const { return !sent_gestures_.empty(); }
+
+ base::TimeTicks LastSentGestureTime() const {
+ return last_sent_gesture_time_;
+ }
+
+ base::TimeTicks CurrentTouchTime() const {
+ return touch_event_.GetEventTime();
+ }
+
+ bool IsEmpty() const { return queue_->IsEmpty(); }
+
+ GestureList GetAndResetSentGestures() {
+ GestureList sent_gestures;
+ sent_gestures.swap(sent_gestures_);
+ return sent_gestures;
+ }
+
+ const gfx::PointF& LastSentGestureLocation() const {
+ return last_sent_gesture_location_;
+ }
+
+ const gfx::PointF& LastSentGestureRawLocation() const {
+ return last_sent_gesture_raw_location_;
+ }
+
+ void SetCancelAfterNextGesture(bool cancel_after_next_gesture) {
+ cancel_after_next_gesture_ = cancel_after_next_gesture;
+ }
+
+ GestureEventData CreateGesture(EventType type) {
+ return GestureEventData(GestureEventDetails(type, 0, 0),
+ 0,
+ base::TimeTicks(),
+ touch_event_.GetX(0),
+ touch_event_.GetY(0),
+ touch_event_.GetRawX(0),
+ touch_event_.GetRawY(0),
+ 1,
+ gfx::RectF(0, 0, 0, 0));
+ }
+
+ private:
+ scoped_ptr<TouchDispositionGestureFilter> queue_;
+ bool cancel_after_next_gesture_;
+ MockMotionEvent touch_event_;
+ GestureEventDataPacket pending_gesture_packet_;
+ size_t sent_gesture_count_;
+ base::TimeTicks last_sent_gesture_time_;
+ GestureList sent_gestures_;
+ gfx::PointF last_sent_gesture_location_;
+ gfx::PointF last_sent_gesture_raw_location_;
+};
+
+TEST_F(TouchDispositionGestureFilterTest, BasicNoGestures) {
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+
+ MoveTouchPoint(0, 2, 2);
+ EXPECT_FALSE(GesturesSent());
+
+ // No gestures should be dispatched by the ack, as the queued packets
+ // contained no gestures.
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // Release the touch gesture.
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, BasicGestures) {
+ // An unconsumed touch's gesture should be sent.
+ PushGesture(ET_GESTURE_BEGIN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // Multiple gestures can be queued for a single event.
+ PushGesture(ET_SCROLL_FLING_START);
+ PushGesture(ET_SCROLL_FLING_CANCEL);
+ PushGesture(ET_GESTURE_END);
+ ReleaseTouchPoint();
+ EXPECT_FALSE(GesturesSent());
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START,
+ ET_SCROLL_FLING_CANCEL,
+ ET_GESTURE_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, BasicGesturesConsumed) {
+ // A consumed touch's gesture should not be sent.
+ PushGesture(ET_GESTURE_BEGIN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_SCROLL_FLING_START);
+ PushGesture(ET_SCROLL_FLING_CANCEL);
+ PushGesture(ET_GESTURE_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ConsumedThenNotConsumed) {
+ // A consumed touch's gesture should not be sent.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // Even if the subsequent touch is not consumed, continue dropping gestures.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // Even if the subsequent touch had no consumer, continue dropping gestures.
+ PushGesture(ET_SCROLL_FLING_START);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, NotConsumedThenConsumed) {
+ // A not consumed touch's gesture should be sent.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // A newly consumed gesture should not be sent.
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(10, 10);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // And subsequent non-consumed pinch updates should not be sent.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ PushGesture(ET_GESTURE_PINCH_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE),
+ GetAndResetSentGestures()));
+
+ // End events dispatched only when their start events were.
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ScrollAlternatelyConsumed) {
+ // A consumed touch's gesture should not be sent.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ for (size_t i = 0; i < 3; ++i) {
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 3, 3);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE),
+ GetAndResetSentGestures()));
+ }
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, NotConsumedThenNoConsumer) {
+ // An unconsumed touch's gesture should be sent.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch has no consumer (e.g., a secondary pointer is
+ // pressed but not on a touch handling rect), send the gesture.
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN),
+ GetAndResetSentGestures()));
+
+ // End events should be dispatched when their start events were, independent
+ // of the ack state.
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, EndingEventsSent) {
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN),
+ GetAndResetSentGestures()));
+
+ // Consuming the touchend event can't suppress the match end gesture.
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END),
+ GetAndResetSentGestures()));
+
+ // But other events in the same packet are still suppressed.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+
+ // ET_GESTURE_SCROLL_END and ET_SCROLL_FLING_START behave the same in this
+ // regard.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_SCROLL_FLING_START);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, EndingEventsNotSent) {
+ // Consuming a begin event ensures no end events are sent.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, UpdateEventsSuppressedPerEvent) {
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // Consuming a single scroll or pinch update should suppress only that event.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_PINCH_UPDATE);
+ MoveTouchPoint(1, 2, 3);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // Subsequent updates should not be affected.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 4, 4);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_PINCH_UPDATE);
+ MoveTouchPoint(0, 4, 5);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_UPDATE),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, UpdateEventsDependOnBeginEvents) {
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // Scroll and pinch gestures depend on the scroll begin gesture being
+ // dispatched.
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_UPDATE);
+ MoveTouchPoint(1, 2, 3);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, MultipleTouchSequences) {
+ // Queue two touch-to-gestures sequences.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ PushGesture(ET_GESTURE_TAP);
+ ReleaseTouchPoint();
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ PushGesture(ET_GESTURE_SCROLL_END);
+ ReleaseTouchPoint();
+
+ // The first gesture sequence should not be allowed.
+ SendTouchConsumedAck();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ // The subsequent sequence should "reset" allowance.
+ SendTouchNotConsumedAck();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN,
+ ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, FlingCancelledOnNewTouchSequence) {
+ const gfx::Vector2dF raw_offset(1.3f, 3.7f);
+ SetRawTouchOffset(raw_offset);
+ // Simulate a fling.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(
+ Gestures(
+ ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+ PushGesture(ET_SCROLL_FLING_START);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START),
+ GetAndResetSentGestures()));
+
+ // A new touch sequence should cancel the outstanding fling.
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+ EXPECT_EQ(LastSentGestureRawLocation(), gfx::PointF(1, 1) + raw_offset);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ScrollEndedOnTouchReleaseIfNoFling) {
+ // Simulate a scroll.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(
+ Gestures(
+ ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ScrollEndedOnNewTouchSequence) {
+ // Simulate a scroll.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(
+ Gestures(
+ ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // A new touch sequence should end the outstanding scroll.
+ ResetTouchPoints();
+ PressTouchPoint(2, 3);
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, FlingCancelledOnScrollBegin) {
+ // Simulate a fling sequence.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PushGesture(ET_SCROLL_FLING_START);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN,
+ ET_GESTURE_TAP_CANCEL,
+ ET_GESTURE_SCROLL_BEGIN,
+ ET_SCROLL_FLING_START),
+ GetAndResetSentGestures()));
+
+ // The new fling should cancel the preceding one.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PushGesture(ET_SCROLL_FLING_START);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_CANCEL,
+ ET_GESTURE_SCROLL_BEGIN,
+ ET_SCROLL_FLING_START),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, FlingNotCancelledIfGFCEventReceived) {
+ // Simulate a fling that is started then cancelled.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ PushGesture(ET_SCROLL_FLING_START);
+ MoveTouchPoint(0, 2, 3);
+ SendTouchNotConsumedAck();
+ PushGesture(ET_SCROLL_FLING_CANCEL);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN,
+ ET_SCROLL_FLING_START,
+ ET_SCROLL_FLING_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3));
+
+ // A new touch sequence will not inject a ET_SCROLL_FLING_CANCEL, as the fling
+ // has already been cancelled.
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TapCancelledWhenScrollBegins) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch turns into a scroll, the tap should be cancelled.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL,
+ ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TapCancelledWhenTouchConsumed) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch is consumed, the tap should be cancelled.
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 2));
+}
+
+TEST_F(TouchDispositionGestureFilterTest,
+ TapNotCancelledIfTapEndingEventReceived) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(
+ GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_TAP);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, ET_GESTURE_TAP),
+ GetAndResetSentGestures()));
+
+ // The tap should not be cancelled as it was terminated by a |ET_GESTURE_TAP|.
+ PressTouchPoint(2, 2);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) {
+ // If the sequence is allowed, and there are no preceding gestures, the
+ // timeout gestures should be forwarded immediately.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(ET_GESTURE_SHOW_PRESS);
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(ET_GESTURE_LONG_PRESS);
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_LONG_PRESS),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_LONG_TAP);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL,
+ ET_GESTURE_LONG_TAP),
+ GetAndResetSentGestures()));
+
+ // If the sequence is disallowed, and there are no preceding gestures, the
+ // timeout gestures should be dropped immediately.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ SendTimeoutGesture(ET_GESTURE_SHOW_PRESS);
+ EXPECT_FALSE(GesturesSent());
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+
+ // If the sequence has a pending ack, the timeout gestures should
+ // remain queued until the ack is received.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTimeoutGesture(ET_GESTURE_LONG_PRESS);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN,
+ ET_GESTURE_LONG_PRESS),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, SpuriousAcksIgnored) {
+ // Acks received when the queue is empty will be safely ignored.
+ ASSERT_TRUE(IsEmpty());
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 3,3);
+ SendTouchNotConsumedAck();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN,
+ ET_GESTURE_SCROLL_UPDATE),
+ GetAndResetSentGestures()));
+
+ // Even if all packets have been dispatched, the filter may not be empty as
+ // there could be follow-up timeout events. Spurious acks in such cases
+ // should also be safely ignored.
+ ASSERT_FALSE(IsEmpty());
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, PacketWithInvalidTypeIgnored) {
+ GestureEventDataPacket packet;
+ EXPECT_EQ(TouchDispositionGestureFilter::INVALID_PACKET_TYPE,
+ SendGesturePacket(packet));
+ EXPECT_TRUE(IsEmpty());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, PacketsWithInvalidOrderIgnored) {
+ EXPECT_EQ(TouchDispositionGestureFilter::INVALID_PACKET_ORDER,
+ SendTimeoutGesture(ET_GESTURE_SHOW_PRESS));
+ EXPECT_TRUE(IsEmpty());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ConsumedTouchCancel) {
+ // An unconsumed touch's gesture should be sent.
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_TAP_CANCEL);
+ PushGesture(ET_GESTURE_SCROLL_END);
+ CancelTouchPoint();
+ EXPECT_FALSE(GesturesSent());
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL,
+ ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TimeoutEventAfterRelease) {
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PushGesture(ET_GESTURE_TAP_UNCONFIRMED);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(
+ GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_UNCONFIRMED),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(ET_GESTURE_TAP);
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, ET_GESTURE_TAP),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ShowPressInsertedBeforeTap) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(ET_GESTURE_TAP_UNCONFIRMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_UNCONFIRMED),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_TAP);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS,
+ ET_GESTURE_TAP),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, ShowPressNotInsertedIfAlreadySent) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(ET_GESTURE_SHOW_PRESS);
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_TAP);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TapAndScrollCancelledOnTouchCancel) {
+ const gfx::Vector2dF raw_offset(1.3f, 3.7f);
+ SetRawTouchOffset(raw_offset);
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ // A cancellation motion event should cancel the tap.
+ CancelTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+ EXPECT_EQ(LastSentGestureRawLocation(), gfx::PointF(1, 1) + raw_offset);
+
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ // A cancellation motion event should end the scroll, even if the touch was
+ // consumed.
+ CancelTouchPoint();
+ SendTouchConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+ EXPECT_EQ(LastSentGestureRawLocation(), gfx::PointF(1, 1) + raw_offset);
+}
+
+TEST_F(TouchDispositionGestureFilterTest,
+ ConsumedScrollUpdateMakesFlingScrollEnd) {
+ // A consumed touch's gesture should not be sent.
+ PushGesture(ET_GESTURE_BEGIN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+
+ EXPECT_TRUE(
+ GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_SCROLL_UPDATE);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_SCROLL_FLING_START);
+ PushGesture(ET_SCROLL_FLING_CANCEL);
+ PushGesture(ET_GESTURE_END);
+ ReleaseTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_END, ET_GESTURE_SCROLL_END),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 2));
+
+ PushGesture(ET_GESTURE_BEGIN);
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TapCancelledOnTouchCancel) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ // A cancellation motion event should cancel the tap.
+ CancelTouchPoint();
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime());
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+}
+
+// Test that a GestureEvent whose dispatch causes a cancel event to be fired
+// won't cause a crash.
+TEST_F(TouchDispositionGestureFilterTest, TestCancelMidGesture) {
+ SetCancelAfterNextGesture(true);
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN,
+ ET_GESTURE_TAP_CANCEL),
+ GetAndResetSentGestures()));
+ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1));
+}
+
+// Test that a MultiFingerSwipe event is dispatched when appropriate.
+TEST_F(TouchDispositionGestureFilterTest, TestAllowedMultiFingerSwipe) {
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN),
+ GetAndResetSentGestures()));
+
+ PushGesture(ET_GESTURE_SWIPE);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SWIPE),
+ GetAndResetSentGestures()));
+}
+
+ // Test that a MultiFingerSwipe event is dispatched when appropriate.
+TEST_F(TouchDispositionGestureFilterTest, TestDisallowedMultiFingerSwipe) {
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+
+ PushGesture(ET_GESTURE_SCROLL_BEGIN);
+ MoveTouchPoint(0, 0, 0);
+ SendTouchConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_PINCH_BEGIN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(ET_GESTURE_SWIPE);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(TouchDispositionGestureFilterTest, TapCancelOnSecondFingerDown) {
+ PushGesture(ET_GESTURE_TAP_DOWN);
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN),
+ GetAndResetSentGestures()));
+
+ PressTouchPoint(1, 1);
+ SendTouchNotConsumedAck();
+ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL),
+ GetAndResetSentGestures()));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker.cc b/chromium/ui/events/gesture_detection/velocity_tracker.cc
new file mode 100644
index 00000000000..da9f8a7bf15
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/velocity_tracker.cc
@@ -0,0 +1,805 @@
+// 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/events/gesture_detection/velocity_tracker.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace ui {
+
+// Implements a particular velocity tracker algorithm.
+class VelocityTrackerStrategy {
+ public:
+ virtual ~VelocityTrackerStrategy() {}
+
+ virtual void Clear() = 0;
+ virtual void ClearPointers(BitSet32 id_bits) = 0;
+ virtual void AddMovement(const base::TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) = 0;
+ virtual bool GetEstimator(uint32_t id, Estimator* out_estimator) const = 0;
+
+ protected:
+ VelocityTrackerStrategy() {}
+};
+
+namespace {
+
+COMPILE_ASSERT(MotionEvent::MAX_POINTER_ID < 32, max_pointer_id_too_large);
+
+// Threshold for determining that a pointer has stopped moving.
+// Some input devices do not send ACTION_MOVE events in the case where a pointer
+// has stopped. We need to detect this case so that we can accurately predict
+// the velocity after the pointer starts moving again.
+const int kAssumePointerStoppedTimeMs = 40;
+
+struct Position {
+ float x, y;
+};
+
+struct Estimator {
+ enum { MAX_DEGREE = 4 };
+
+ // Estimator time base.
+ TimeTicks time;
+
+ // Polynomial coefficients describing motion in X and Y.
+ float xcoeff[MAX_DEGREE + 1], ycoeff[MAX_DEGREE + 1];
+
+ // Polynomial degree (number of coefficients), or zero if no information is
+ // available.
+ uint32_t degree;
+
+ // Confidence (coefficient of determination), between 0 (no fit)
+ // and 1 (perfect fit).
+ float confidence;
+
+ inline void Clear() {
+ time = TimeTicks();
+ degree = 0;
+ confidence = 0;
+ for (size_t i = 0; i <= MAX_DEGREE; i++) {
+ xcoeff[i] = 0;
+ ycoeff[i] = 0;
+ }
+ }
+};
+
+float VectorDot(const float* a, const float* b, uint32_t m) {
+ float r = 0;
+ while (m--) {
+ r += *(a++) * *(b++);
+ }
+ return r;
+}
+
+float VectorNorm(const float* a, uint32_t m) {
+ float r = 0;
+ while (m--) {
+ float t = *(a++);
+ r += t * t;
+ }
+ return sqrtf(r);
+}
+
+// Velocity tracker algorithm based on least-squares linear regression.
+class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
+ public:
+ enum Weighting {
+ // No weights applied. All data points are equally reliable.
+ WEIGHTING_NONE,
+
+ // Weight by time delta. Data points clustered together are weighted less.
+ WEIGHTING_DELTA,
+
+ // Weight such that points within a certain horizon are weighed more than
+ // those outside of that horizon.
+ WEIGHTING_CENTRAL,
+
+ // Weight such that points older than a certain amount are weighed less.
+ WEIGHTING_RECENT,
+ };
+
+ // Number of samples to keep.
+ enum { HISTORY_SIZE = 20 };
+
+ // Degree must be no greater than Estimator::MAX_DEGREE.
+ LeastSquaresVelocityTrackerStrategy(uint32_t degree,
+ Weighting weighting = WEIGHTING_NONE);
+ virtual ~LeastSquaresVelocityTrackerStrategy();
+
+ virtual void Clear() OVERRIDE;
+ virtual void ClearPointers(BitSet32 id_bits) OVERRIDE;
+ virtual void AddMovement(const TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) OVERRIDE;
+ virtual bool GetEstimator(uint32_t id,
+ Estimator* out_estimator) const OVERRIDE;
+
+ private:
+ // Sample horizon.
+ // We don't use too much history by default since we want to react to quick
+ // changes in direction.
+ enum { HORIZON_MS = 100 };
+
+ struct Movement {
+ TimeTicks event_time;
+ BitSet32 id_bits;
+ Position positions[VelocityTracker::MAX_POINTERS];
+
+ inline const Position& GetPosition(uint32_t id) const {
+ return positions[id_bits.get_index_of_bit(id)];
+ }
+ };
+
+ float ChooseWeight(uint32_t index) const;
+
+ const uint32_t degree_;
+ const Weighting weighting_;
+ uint32_t index_;
+ Movement movements_[HISTORY_SIZE];
+};
+
+// Velocity tracker algorithm that uses an IIR filter.
+class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
+ public:
+ // Degree must be 1 or 2.
+ explicit IntegratingVelocityTrackerStrategy(uint32_t degree);
+ virtual ~IntegratingVelocityTrackerStrategy();
+
+ virtual void Clear() OVERRIDE;
+ virtual void ClearPointers(BitSet32 id_bits) OVERRIDE;
+ virtual void AddMovement(const TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) OVERRIDE;
+ virtual bool GetEstimator(uint32_t id,
+ Estimator* out_estimator) const OVERRIDE;
+
+ private:
+ // Current state estimate for a particular pointer.
+ struct State {
+ TimeTicks update_time;
+ uint32_t degree;
+
+ float xpos, xvel, xaccel;
+ float ypos, yvel, yaccel;
+ };
+
+ const uint32_t degree_;
+ BitSet32 pointer_id_bits_;
+ State mPointerState[MotionEvent::MAX_POINTER_ID + 1];
+
+ void InitState(State& state,
+ const TimeTicks& event_time,
+ float xpos,
+ float ypos) const;
+ void UpdateState(State& state,
+ const TimeTicks& event_time,
+ float xpos,
+ float ypos) const;
+ void PopulateEstimator(const State& state, Estimator* out_estimator) const;
+};
+
+VelocityTrackerStrategy* CreateStrategy(VelocityTracker::Strategy strategy) {
+ switch (strategy) {
+ case VelocityTracker::LSQ1:
+ return new LeastSquaresVelocityTrackerStrategy(1);
+ case VelocityTracker::LSQ2:
+ return new LeastSquaresVelocityTrackerStrategy(2);
+ case VelocityTracker::LSQ3:
+ return new LeastSquaresVelocityTrackerStrategy(3);
+ case VelocityTracker::WLSQ2_DELTA:
+ return new LeastSquaresVelocityTrackerStrategy(
+ 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
+ case VelocityTracker::WLSQ2_CENTRAL:
+ return new LeastSquaresVelocityTrackerStrategy(
+ 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
+ case VelocityTracker::WLSQ2_RECENT:
+ return new LeastSquaresVelocityTrackerStrategy(
+ 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
+ case VelocityTracker::INT1:
+ return new IntegratingVelocityTrackerStrategy(1);
+ case VelocityTracker::INT2:
+ return new IntegratingVelocityTrackerStrategy(2);
+ }
+ NOTREACHED() << "Unrecognized velocity tracker strategy: " << strategy;
+ return CreateStrategy(VelocityTracker::STRATEGY_DEFAULT);
+}
+
+} // namespace
+
+// --- VelocityTracker ---
+
+VelocityTracker::VelocityTracker()
+ : current_pointer_id_bits_(0),
+ active_pointer_id_(-1),
+ strategy_(CreateStrategy(STRATEGY_DEFAULT)) {}
+
+VelocityTracker::VelocityTracker(Strategy strategy)
+ : current_pointer_id_bits_(0),
+ active_pointer_id_(-1),
+ strategy_(CreateStrategy(strategy)) {}
+
+VelocityTracker::~VelocityTracker() {}
+
+void VelocityTracker::Clear() {
+ current_pointer_id_bits_.clear();
+ active_pointer_id_ = -1;
+ strategy_->Clear();
+}
+
+void VelocityTracker::ClearPointers(BitSet32 id_bits) {
+ BitSet32 remaining_id_bits(current_pointer_id_bits_.value & ~id_bits.value);
+ current_pointer_id_bits_ = remaining_id_bits;
+
+ if (active_pointer_id_ >= 0 && id_bits.has_bit(active_pointer_id_)) {
+ active_pointer_id_ = !remaining_id_bits.is_empty()
+ ? remaining_id_bits.first_marked_bit()
+ : -1;
+ }
+
+ strategy_->ClearPointers(id_bits);
+}
+
+void VelocityTracker::AddMovement(const TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) {
+ while (id_bits.count() > MAX_POINTERS)
+ id_bits.clear_last_marked_bit();
+
+ if ((current_pointer_id_bits_.value & id_bits.value) &&
+ event_time >= (last_event_time_ + base::TimeDelta::FromMilliseconds(
+ kAssumePointerStoppedTimeMs))) {
+ // We have not received any movements for too long. Assume that all
+ // pointers
+ // have stopped.
+ strategy_->Clear();
+ }
+ last_event_time_ = event_time;
+
+ current_pointer_id_bits_ = id_bits;
+ if (active_pointer_id_ < 0 || !id_bits.has_bit(active_pointer_id_))
+ active_pointer_id_ = id_bits.is_empty() ? -1 : id_bits.first_marked_bit();
+
+ strategy_->AddMovement(event_time, id_bits, positions);
+}
+
+void VelocityTracker::AddMovement(const MotionEvent& event) {
+ int32_t actionMasked = event.GetAction();
+
+ switch (actionMasked) {
+ case MotionEvent::ACTION_DOWN:
+ // case MotionEvent::HOVER_ENTER:
+ // Clear all pointers on down before adding the new movement.
+ Clear();
+ break;
+ case MotionEvent::ACTION_POINTER_DOWN: {
+ // Start a new movement trace for a pointer that just went down.
+ // We do this on down instead of on up because the client may want to
+ // query the final velocity for a pointer that just went up.
+ BitSet32 downIdBits;
+ downIdBits.mark_bit(event.GetPointerId(event.GetActionIndex()));
+ ClearPointers(downIdBits);
+ break;
+ }
+ case MotionEvent::ACTION_MOVE:
+ // case MotionEvent::ACTION_HOVER_MOVE:
+ break;
+ default:
+ // Ignore all other actions because they do not convey any new information
+ // about pointer movement. We also want to preserve the last known
+ // velocity of the pointers.
+ // Note that ACTION_UP and ACTION_POINTER_UP always report the last known
+ // position of the pointers that went up. ACTION_POINTER_UP does include
+ // the new position of pointers that remained down but we will also
+ // receive an ACTION_MOVE with this information if any of them actually
+ // moved. Since we don't know how many pointers will be going up at once
+ // it makes sense to just wait for the following ACTION_MOVE before adding
+ // the movement.
+ return;
+ }
+
+ size_t pointer_count = event.GetPointerCount();
+ if (pointer_count > MAX_POINTERS) {
+ pointer_count = MAX_POINTERS;
+ }
+
+ BitSet32 id_bits;
+ for (size_t i = 0; i < pointer_count; i++) {
+ id_bits.mark_bit(event.GetPointerId(i));
+ }
+
+ uint32_t pointer_index[MAX_POINTERS];
+ for (size_t i = 0; i < pointer_count; i++) {
+ pointer_index[i] = id_bits.get_index_of_bit(event.GetPointerId(i));
+ }
+
+ Position positions[MAX_POINTERS];
+ size_t historySize = event.GetHistorySize();
+ for (size_t h = 0; h < historySize; h++) {
+ for (size_t i = 0; i < pointer_count; i++) {
+ uint32_t index = pointer_index[i];
+ positions[index].x = event.GetHistoricalX(i, h);
+ positions[index].y = event.GetHistoricalY(i, h);
+ }
+ AddMovement(event.GetHistoricalEventTime(h), id_bits, positions);
+ }
+
+ for (size_t i = 0; i < pointer_count; i++) {
+ uint32_t index = pointer_index[i];
+ positions[index].x = event.GetX(i);
+ positions[index].y = event.GetY(i);
+ }
+ AddMovement(event.GetEventTime(), id_bits, positions);
+}
+
+bool VelocityTracker::GetVelocity(uint32_t id,
+ float* out_vx,
+ float* out_vy) const {
+ Estimator estimator;
+ if (GetEstimator(id, &estimator) && estimator.degree >= 1) {
+ *out_vx = estimator.xcoeff[1];
+ *out_vy = estimator.ycoeff[1];
+ return true;
+ }
+ *out_vx = 0;
+ *out_vy = 0;
+ return false;
+}
+
+void LeastSquaresVelocityTrackerStrategy::AddMovement(
+ const TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) {
+ if (++index_ == HISTORY_SIZE) {
+ index_ = 0;
+ }
+
+ Movement& movement = movements_[index_];
+ movement.event_time = event_time;
+ movement.id_bits = id_bits;
+ uint32_t count = id_bits.count();
+ for (uint32_t i = 0; i < count; i++) {
+ movement.positions[i] = positions[i];
+ }
+}
+
+bool VelocityTracker::GetEstimator(uint32_t id,
+ Estimator* out_estimator) const {
+ return strategy_->GetEstimator(id, out_estimator);
+}
+
+// --- LeastSquaresVelocityTrackerStrategy ---
+
+LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
+ uint32_t degree,
+ Weighting weighting)
+ : degree_(degree), weighting_(weighting) {
+ DCHECK_LT(degree_, static_cast<uint32_t>(Estimator::MAX_DEGREE));
+ Clear();
+}
+
+LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {}
+
+void LeastSquaresVelocityTrackerStrategy::Clear() {
+ index_ = 0;
+ movements_[0].id_bits.clear();
+}
+
+/**
+ * Solves a linear least squares problem to obtain a N degree polynomial that
+ * fits the specified input data as nearly as possible.
+ *
+ * Returns true if a solution is found, false otherwise.
+ *
+ * The input consists of two vectors of data points X and Y with indices 0..m-1
+ * along with a weight vector W of the same size.
+ *
+ * The output is a vector B with indices 0..n that describes a polynomial
+ * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1]
+ * X[i] * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is
+ * minimized.
+ *
+ * Accordingly, the weight vector W should be initialized by the caller with the
+ * reciprocal square root of the variance of the error in each input data point.
+ * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 /
+ * stddev(Y[i]).
+ * The weights express the relative importance of each data point. If the
+ * weights are* all 1, then the data points are considered to be of equal
+ * importance when fitting the polynomial. It is a good idea to choose weights
+ * that diminish the importance of data points that may have higher than usual
+ * error margins.
+ *
+ * Errors among data points are assumed to be independent. W is represented
+ * here as a vector although in the literature it is typically taken to be a
+ * diagonal matrix.
+ *
+ * That is to say, the function that generated the input data can be
+ * approximated by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
+ *
+ * The coefficient of determination (R^2) is also returned to describe the
+ * goodness of fit of the model for the given data. It is a value between 0
+ * and 1, where 1 indicates perfect correspondence.
+ *
+ * This function first expands the X vector to a m by n matrix A such that
+ * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then
+ * multiplies it by w[i]./
+ *
+ * Then it calculates the QR decomposition of A yielding an m by m orthonormal
+ * matrix Q and an m by n upper triangular matrix R. Because R is upper
+ * triangular (lower part is all zeroes), we can simplify the decomposition into
+ * an m by n matrix Q1 and a n by n matrix R1 such that A = Q1 R1.
+ *
+ * Finally we solve the system of linear equations given by
+ * R1 B = (Qtranspose W Y) to find B.
+ *
+ * For efficiency, we lay out A and Q column-wise in memory because we
+ * frequently operate on the column vectors. Conversely, we lay out R row-wise.
+ *
+ * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
+ * http://en.wikipedia.org/wiki/Gram-Schmidt
+ */
+static bool SolveLeastSquares(const float* x,
+ const float* y,
+ const float* w,
+ uint32_t m,
+ uint32_t n,
+ float* out_b,
+ float* out_det) {
+ // MSVC does not support variable-length arrays (used by the original Android
+ // implementation of this function).
+#if defined(COMPILER_MSVC)
+ enum {
+ M_ARRAY_LENGTH = LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE,
+ N_ARRAY_LENGTH = Estimator::MAX_DEGREE
+ };
+ DCHECK_LE(m, static_cast<uint32_t>(M_ARRAY_LENGTH));
+ DCHECK_LE(n, static_cast<uint32_t>(N_ARRAY_LENGTH));
+#else
+ const uint32_t M_ARRAY_LENGTH = m;
+ const uint32_t N_ARRAY_LENGTH = n;
+#endif
+
+ // Expand the X vector to a matrix A, pre-multiplied by the weights.
+ float a[N_ARRAY_LENGTH][M_ARRAY_LENGTH]; // column-major order
+ for (uint32_t h = 0; h < m; h++) {
+ a[0][h] = w[h];
+ for (uint32_t i = 1; i < n; i++) {
+ a[i][h] = a[i - 1][h] * x[h];
+ }
+ }
+
+ // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
+
+ // Orthonormal basis, column-major order.
+ float q[N_ARRAY_LENGTH][M_ARRAY_LENGTH];
+ // Upper triangular matrix, row-major order.
+ float r[N_ARRAY_LENGTH][N_ARRAY_LENGTH];
+ for (uint32_t j = 0; j < n; j++) {
+ for (uint32_t h = 0; h < m; h++) {
+ q[j][h] = a[j][h];
+ }
+ for (uint32_t i = 0; i < j; i++) {
+ float dot = VectorDot(&q[j][0], &q[i][0], m);
+ for (uint32_t h = 0; h < m; h++) {
+ q[j][h] -= dot * q[i][h];
+ }
+ }
+
+ float norm = VectorNorm(&q[j][0], m);
+ if (norm < 0.000001f) {
+ // vectors are linearly dependent or zero so no solution
+ return false;
+ }
+
+ float invNorm = 1.0f / norm;
+ for (uint32_t h = 0; h < m; h++) {
+ q[j][h] *= invNorm;
+ }
+ for (uint32_t i = 0; i < n; i++) {
+ r[j][i] = i < j ? 0 : VectorDot(&q[j][0], &a[i][0], m);
+ }
+ }
+
+ // Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
+ // We just work from bottom-right to top-left calculating B's coefficients.
+ float wy[M_ARRAY_LENGTH];
+ for (uint32_t h = 0; h < m; h++) {
+ wy[h] = y[h] * w[h];
+ }
+ for (uint32_t i = n; i-- != 0;) {
+ out_b[i] = VectorDot(&q[i][0], wy, m);
+ for (uint32_t j = n - 1; j > i; j--) {
+ out_b[i] -= r[i][j] * out_b[j];
+ }
+ out_b[i] /= r[i][i];
+ }
+
+ // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
+ // SSerr is the residual sum of squares (variance of the error),
+ // and SStot is the total sum of squares (variance of the data) where each
+ // has been weighted.
+ float ymean = 0;
+ for (uint32_t h = 0; h < m; h++) {
+ ymean += y[h];
+ }
+ ymean /= m;
+
+ float sserr = 0;
+ float sstot = 0;
+ for (uint32_t h = 0; h < m; h++) {
+ float err = y[h] - out_b[0];
+ float term = 1;
+ for (uint32_t i = 1; i < n; i++) {
+ term *= x[h];
+ err -= term * out_b[i];
+ }
+ sserr += w[h] * w[h] * err * err;
+ float var = y[h] - ymean;
+ sstot += w[h] * w[h] * var * var;
+ }
+ *out_det = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
+ return true;
+}
+
+void LeastSquaresVelocityTrackerStrategy::ClearPointers(BitSet32 id_bits) {
+ BitSet32 remaining_id_bits(movements_[index_].id_bits.value & ~id_bits.value);
+ movements_[index_].id_bits = remaining_id_bits;
+}
+
+bool LeastSquaresVelocityTrackerStrategy::GetEstimator(
+ uint32_t id,
+ Estimator* out_estimator) const {
+ out_estimator->Clear();
+
+ // Iterate over movement samples in reverse time order and collect samples.
+ float x[HISTORY_SIZE];
+ float y[HISTORY_SIZE];
+ float w[HISTORY_SIZE];
+ float time[HISTORY_SIZE];
+ uint32_t m = 0;
+ uint32_t index = index_;
+ const base::TimeDelta horizon = base::TimeDelta::FromMilliseconds(HORIZON_MS);
+ const Movement& newest_movement = movements_[index_];
+ do {
+ const Movement& movement = movements_[index];
+ if (!movement.id_bits.has_bit(id))
+ break;
+
+ TimeDelta age = newest_movement.event_time - movement.event_time;
+ if (age > horizon)
+ break;
+
+ const Position& position = movement.GetPosition(id);
+ x[m] = position.x;
+ y[m] = position.y;
+ w[m] = ChooseWeight(index);
+ time[m] = -age.InSecondsF();
+ index = (index == 0 ? HISTORY_SIZE : index) - 1;
+ } while (++m < HISTORY_SIZE);
+
+ if (m == 0)
+ return false; // no data
+
+ // Calculate a least squares polynomial fit.
+ uint32_t degree = degree_;
+ if (degree > m - 1)
+ degree = m - 1;
+
+ if (degree >= 1) {
+ float xdet, ydet;
+ uint32_t n = degree + 1;
+ if (SolveLeastSquares(time, x, w, m, n, out_estimator->xcoeff, &xdet) &&
+ SolveLeastSquares(time, y, w, m, n, out_estimator->ycoeff, &ydet)) {
+ out_estimator->time = newest_movement.event_time;
+ out_estimator->degree = degree;
+ out_estimator->confidence = xdet * ydet;
+ return true;
+ }
+ }
+
+ // No velocity data available for this pointer, but we do have its current
+ // position.
+ out_estimator->xcoeff[0] = x[0];
+ out_estimator->ycoeff[0] = y[0];
+ out_estimator->time = newest_movement.event_time;
+ out_estimator->degree = 0;
+ out_estimator->confidence = 1;
+ return true;
+}
+
+float LeastSquaresVelocityTrackerStrategy::ChooseWeight(uint32_t index) const {
+ switch (weighting_) {
+ case WEIGHTING_DELTA: {
+ // Weight points based on how much time elapsed between them and the next
+ // point so that points that "cover" a shorter time span are weighed less.
+ // delta 0ms: 0.5
+ // delta 10ms: 1.0
+ if (index == index_) {
+ return 1.0f;
+ }
+ uint32_t next_index = (index + 1) % HISTORY_SIZE;
+ float delta_millis =
+ static_cast<float>((movements_[next_index].event_time -
+ movements_[index].event_time).InMillisecondsF());
+ if (delta_millis < 0)
+ return 0.5f;
+ if (delta_millis < 10)
+ return 0.5f + delta_millis * 0.05;
+
+ return 1.0f;
+ }
+
+ case WEIGHTING_CENTRAL: {
+ // Weight points based on their age, weighing very recent and very old
+ // points less.
+ // age 0ms: 0.5
+ // age 10ms: 1.0
+ // age 50ms: 1.0
+ // age 60ms: 0.5
+ float age_millis =
+ static_cast<float>((movements_[index_].event_time -
+ movements_[index].event_time).InMillisecondsF());
+ if (age_millis < 0)
+ return 0.5f;
+ if (age_millis < 10)
+ return 0.5f + age_millis * 0.05;
+ if (age_millis < 50)
+ return 1.0f;
+ if (age_millis < 60)
+ return 0.5f + (60 - age_millis) * 0.05;
+
+ return 0.5f;
+ }
+
+ case WEIGHTING_RECENT: {
+ // Weight points based on their age, weighing older points less.
+ // age 0ms: 1.0
+ // age 50ms: 1.0
+ // age 100ms: 0.5
+ float age_millis =
+ static_cast<float>((movements_[index_].event_time -
+ movements_[index].event_time).InMillisecondsF());
+ if (age_millis < 50) {
+ return 1.0f;
+ }
+ if (age_millis < 100) {
+ return 0.5f + (100 - age_millis) * 0.01f;
+ }
+ return 0.5f;
+ }
+
+ case WEIGHTING_NONE:
+ default:
+ return 1.0f;
+ }
+}
+
+// --- IntegratingVelocityTrackerStrategy ---
+
+IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(
+ uint32_t degree)
+ : degree_(degree) {
+ DCHECK_LT(degree_, static_cast<uint32_t>(Estimator::MAX_DEGREE));
+}
+
+IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {}
+
+void IntegratingVelocityTrackerStrategy::Clear() { pointer_id_bits_.clear(); }
+
+void IntegratingVelocityTrackerStrategy::ClearPointers(BitSet32 id_bits) {
+ pointer_id_bits_.value &= ~id_bits.value;
+}
+
+void IntegratingVelocityTrackerStrategy::AddMovement(
+ const TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions) {
+ uint32_t index = 0;
+ for (BitSet32 iter_id_bits(id_bits); !iter_id_bits.is_empty();) {
+ uint32_t id = iter_id_bits.clear_first_marked_bit();
+ State& state = mPointerState[id];
+ const Position& position = positions[index++];
+ if (pointer_id_bits_.has_bit(id))
+ UpdateState(state, event_time, position.x, position.y);
+ else
+ InitState(state, event_time, position.x, position.y);
+ }
+
+ pointer_id_bits_ = id_bits;
+}
+
+bool IntegratingVelocityTrackerStrategy::GetEstimator(
+ uint32_t id,
+ Estimator* out_estimator) const {
+ out_estimator->Clear();
+
+ if (pointer_id_bits_.has_bit(id)) {
+ const State& state = mPointerState[id];
+ PopulateEstimator(state, out_estimator);
+ return true;
+ }
+
+ return false;
+}
+
+void IntegratingVelocityTrackerStrategy::InitState(State& state,
+ const TimeTicks& event_time,
+ float xpos,
+ float ypos) const {
+ state.update_time = event_time;
+ state.degree = 0;
+ state.xpos = xpos;
+ state.xvel = 0;
+ state.xaccel = 0;
+ state.ypos = ypos;
+ state.yvel = 0;
+ state.yaccel = 0;
+}
+
+void IntegratingVelocityTrackerStrategy::UpdateState(
+ State& state,
+ const TimeTicks& event_time,
+ float xpos,
+ float ypos) const {
+ const base::TimeDelta MIN_TIME_DELTA = TimeDelta::FromMicroseconds(2);
+ const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
+
+ if (event_time <= state.update_time + MIN_TIME_DELTA)
+ return;
+
+ float dt = static_cast<float>((event_time - state.update_time).InSecondsF());
+ state.update_time = event_time;
+
+ float xvel = (xpos - state.xpos) / dt;
+ float yvel = (ypos - state.ypos) / dt;
+ if (state.degree == 0) {
+ state.xvel = xvel;
+ state.yvel = yvel;
+ state.degree = 1;
+ } else {
+ float alpha = dt / (FILTER_TIME_CONSTANT + dt);
+ if (degree_ == 1) {
+ state.xvel += (xvel - state.xvel) * alpha;
+ state.yvel += (yvel - state.yvel) * alpha;
+ } else {
+ float xaccel = (xvel - state.xvel) / dt;
+ float yaccel = (yvel - state.yvel) / dt;
+ if (state.degree == 1) {
+ state.xaccel = xaccel;
+ state.yaccel = yaccel;
+ state.degree = 2;
+ } else {
+ state.xaccel += (xaccel - state.xaccel) * alpha;
+ state.yaccel += (yaccel - state.yaccel) * alpha;
+ }
+ state.xvel += (state.xaccel * dt) * alpha;
+ state.yvel += (state.yaccel * dt) * alpha;
+ }
+ }
+ state.xpos = xpos;
+ state.ypos = ypos;
+}
+
+void IntegratingVelocityTrackerStrategy::PopulateEstimator(
+ const State& state,
+ Estimator* out_estimator) const {
+ out_estimator->time = state.update_time;
+ out_estimator->confidence = 1.0f;
+ out_estimator->degree = state.degree;
+ out_estimator->xcoeff[0] = state.xpos;
+ out_estimator->xcoeff[1] = state.xvel;
+ out_estimator->xcoeff[2] = state.xaccel / 2;
+ out_estimator->ycoeff[0] = state.ypos;
+ out_estimator->ycoeff[1] = state.yvel;
+ out_estimator->ycoeff[2] = state.yaccel / 2;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker.h b/chromium/ui/events/gesture_detection/velocity_tracker.h
new file mode 100644
index 00000000000..8147695dd25
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/velocity_tracker.h
@@ -0,0 +1,150 @@
+// 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_GESTURE_DETECTION_VELOCITY_TRACKER_H_
+#define UI_EVENTS_GESTURE_DETECTION_VELOCITY_TRACKER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "ui/events/gesture_detection/bitset_32.h"
+
+namespace ui {
+
+class MotionEvent;
+class VelocityTrackerStrategy;
+
+namespace {
+struct Estimator;
+struct Position;
+}
+
+// Port of VelocityTracker from Android
+// * platform/frameworks/native/include/input/VelocityTracker.h
+// * Change-Id: I4983db61b53e28479fc90d9211fafff68f7f49a6
+// * Please update the Change-Id as upstream Android changes are pulled.
+class VelocityTracker {
+ public:
+ enum {
+ // The maximum number of pointers to use when computing the velocity.
+ // Note that the supplied MotionEvent may expose more than 16 pointers, but
+ // at most |MAX_POINTERS| will be used.
+ MAX_POINTERS = 16,
+ };
+
+ enum Strategy {
+ // 1st order least squares. Quality: POOR.
+ // Frequently underfits the touch data especially when the finger
+ // accelerates or changes direction. Often underestimates velocity. The
+ // direction is overly influenced by historical touch points.
+ LSQ1,
+
+ // 2nd order least squares. Quality: VERY GOOD.
+ // Pretty much ideal, but can be confused by certain kinds of touch data,
+ // particularly if the panel has a tendency to generate delayed,
+ // duplicate or jittery touch coordinates when the finger is released.
+ LSQ2,
+
+ // 3rd order least squares. Quality: UNUSABLE.
+ // Frequently overfits the touch data yielding wildly divergent estimates
+ // of the velocity when the finger is released.
+ LSQ3,
+
+ // 2nd order weighted least squares, delta weighting.
+ // Quality: EXPERIMENTAL
+ WLSQ2_DELTA,
+
+ // 2nd order weighted least squares, central weighting.
+ // Quality: EXPERIMENTAL
+ WLSQ2_CENTRAL,
+
+ // 2nd order weighted least squares, recent weighting.
+ // Quality: EXPERIMENTAL
+ WLSQ2_RECENT,
+
+ // 1st order integrating filter. Quality: GOOD.
+ // Not as good as 'lsq2' because it cannot estimate acceleration but it is
+ // more tolerant of errors. Like 'lsq1', this strategy tends to
+ // underestimate
+ // the velocity of a fling but this strategy tends to respond to changes in
+ // direction more quickly and accurately.
+ INT1,
+
+ // 2nd order integrating filter. Quality: EXPERIMENTAL.
+ // For comparison purposes only. Unlike 'int1' this strategy can compensate
+ // for acceleration but it typically overestimates the effect.
+ INT2,
+ STRATEGY_MAX = INT2,
+
+ // The default velocity tracker strategy.
+ // Although other strategies are available for testing and comparison
+ // purposes, this is the strategy that applications will actually use. Be
+ // very careful when adjusting the default strategy because it can
+ // dramatically affect (often in a bad way) the user experience.
+ STRATEGY_DEFAULT = LSQ2,
+ };
+
+ // Creates a velocity tracker using the default strategy for the platform.
+ VelocityTracker();
+
+ // Creates a velocity tracker using the specified strategy.
+ // If strategy is NULL, uses the default strategy for the platform.
+ explicit VelocityTracker(Strategy strategy);
+
+ ~VelocityTracker();
+
+ // Resets the velocity tracker state.
+ void Clear();
+
+ // Adds movement information for all pointers in a MotionEvent, including
+ // historical samples.
+ void AddMovement(const MotionEvent& event);
+
+ // Gets the velocity of the specified pointer id in position units per second.
+ // Returns false and sets the velocity components to zero if there is
+ // insufficient movement information for the pointer.
+ bool GetVelocity(uint32_t id, float* outVx, float* outVy) const;
+
+ // Gets the active pointer id, or -1 if none.
+ inline int32_t GetActivePointerId() const { return active_pointer_id_; }
+
+ // Gets a bitset containing all pointer ids from the most recent movement.
+ inline BitSet32 GetCurrentPointerIdBits() const {
+ return current_pointer_id_bits_;
+ }
+
+ private:
+ // Resets the velocity tracker state for specific pointers.
+ // Call this method when some pointers have changed and may be reusing
+ // an id that was assigned to a different pointer earlier.
+ void ClearPointers(BitSet32 id_bits);
+
+ // Adds movement information for a set of pointers.
+ // The id_bits bitfield specifies the pointer ids of the pointers whose
+ // positions
+ // are included in the movement.
+ // The positions array contains position information for each pointer in order
+ // by
+ // increasing id. Its size should be equal to the number of one bits in
+ // id_bits.
+ void AddMovement(const base::TimeTicks& event_time,
+ BitSet32 id_bits,
+ const Position* positions);
+
+ // Gets an estimator for the recent movements of the specified pointer id.
+ // Returns false and clears the estimator if there is no information available
+ // about the pointer.
+ bool GetEstimator(uint32_t id, Estimator* out_estimator) const;
+
+ base::TimeTicks last_event_time_;
+ BitSet32 current_pointer_id_bits_;
+ int32_t active_pointer_id_;
+ scoped_ptr<VelocityTrackerStrategy> strategy_;
+
+ DISALLOW_COPY_AND_ASSIGN(VelocityTracker);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_VELOCITY_TRACKER_H_
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker_state.cc b/chromium/ui/events/gesture_detection/velocity_tracker_state.cc
new file mode 100644
index 00000000000..12168560dbd
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/velocity_tracker_state.cc
@@ -0,0 +1,105 @@
+// 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/events/gesture_detection/velocity_tracker_state.h"
+
+#include "base/logging.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+namespace ui {
+namespace {
+// Special constant to request the velocity of the active pointer.
+const int ACTIVE_POINTER_ID = -1;
+}
+
+VelocityTrackerState::VelocityTrackerState()
+ : velocity_tracker_(VelocityTracker::STRATEGY_DEFAULT),
+ active_pointer_id_(ACTIVE_POINTER_ID) {}
+
+VelocityTrackerState::VelocityTrackerState(VelocityTracker::Strategy strategy)
+ : velocity_tracker_(strategy), active_pointer_id_(ACTIVE_POINTER_ID) {}
+
+VelocityTrackerState::~VelocityTrackerState() {}
+
+void VelocityTrackerState::Clear() {
+ velocity_tracker_.Clear();
+ active_pointer_id_ = ACTIVE_POINTER_ID;
+ calculated_id_bits_.clear();
+}
+
+void VelocityTrackerState::AddMovement(const MotionEvent& event) {
+ velocity_tracker_.AddMovement(event);
+}
+
+void VelocityTrackerState::ComputeCurrentVelocity(int32_t units,
+ float max_velocity) {
+ DCHECK_GE(max_velocity, 0);
+
+ BitSet32 id_bits(velocity_tracker_.GetCurrentPointerIdBits());
+ calculated_id_bits_ = id_bits;
+
+ for (uint32_t index = 0; !id_bits.is_empty(); index++) {
+ uint32_t id = id_bits.clear_first_marked_bit();
+
+ float vx, vy;
+ velocity_tracker_.GetVelocity(id, &vx, &vy);
+
+ vx = vx * units / 1000.f;
+ vy = vy * units / 1000.f;
+
+ if (vx > max_velocity)
+ vx = max_velocity;
+ else if (vx < -max_velocity)
+ vx = -max_velocity;
+
+ if (vy > max_velocity)
+ vy = max_velocity;
+ else if (vy < -max_velocity)
+ vy = -max_velocity;
+
+ Velocity& velocity = calculated_velocity_[index];
+ velocity.vx = vx;
+ velocity.vy = vy;
+ }
+}
+
+float VelocityTrackerState::GetXVelocity(int32_t id) const {
+ float vx;
+ GetVelocity(id, &vx, NULL);
+ return vx;
+}
+
+float VelocityTrackerState::GetYVelocity(int32_t id) const {
+ float vy;
+ GetVelocity(id, NULL, &vy);
+ return vy;
+}
+
+void VelocityTrackerState::GetVelocity(int32_t id,
+ float* out_vx,
+ float* out_vy) const {
+ DCHECK(out_vx || out_vy);
+ if (id == ACTIVE_POINTER_ID)
+ id = velocity_tracker_.GetActivePointerId();
+
+ float vx, vy;
+ if (id >= 0 && id <= MotionEvent::MAX_POINTER_ID &&
+ calculated_id_bits_.has_bit(id)) {
+ uint32_t index = calculated_id_bits_.get_index_of_bit(id);
+ const Velocity& velocity = calculated_velocity_[index];
+ vx = velocity.vx;
+ vy = velocity.vy;
+ } else {
+ vx = 0;
+ vy = 0;
+ }
+
+ if (out_vx)
+ *out_vx = vx;
+
+ if (out_vy)
+ *out_vy = vy;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker_state.h b/chromium/ui/events/gesture_detection/velocity_tracker_state.h
new file mode 100644
index 00000000000..780871cb80b
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/velocity_tracker_state.h
@@ -0,0 +1,50 @@
+// 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_GESTURE_DETECTION_VELOCITY_TRACKER_STATE_H_
+#define UI_EVENTS_GESTURE_DETECTION_VELOCITY_TRACKER_STATE_H_
+
+#include "base/basictypes.h"
+#include "ui/events/gesture_detection/bitset_32.h"
+#include "ui/events/gesture_detection/gesture_detection_export.h"
+#include "ui/events/gesture_detection/velocity_tracker.h"
+
+namespace ui {
+
+class MotionEvent;
+
+// Port of VelocityTrackerState from Android
+// * platform/frameworks/base/core/jni/android_view_VelocityTracker.cpp
+// * Change-Id: I3517881b87b47dcc209d80dbd0ac6b5cf29a766f
+// * Please update the Change-Id as upstream Android changes are pulled.
+class GESTURE_DETECTION_EXPORT VelocityTrackerState {
+ public:
+ VelocityTrackerState();
+ explicit VelocityTrackerState(VelocityTracker::Strategy strategy);
+ ~VelocityTrackerState();
+
+ void Clear();
+ void AddMovement(const MotionEvent& event);
+ void ComputeCurrentVelocity(int32_t units, float max_velocity);
+ float GetXVelocity(int32_t id) const;
+ float GetYVelocity(int32_t id) const;
+
+ private:
+ struct Velocity {
+ float vx, vy;
+ };
+
+ void GetVelocity(int32_t id, float* out_vx, float* out_vy) const;
+
+ VelocityTracker velocity_tracker_;
+ int32_t active_pointer_id_;
+ BitSet32 calculated_id_bits_;
+ Velocity calculated_velocity_[VelocityTracker::MAX_POINTERS];
+
+ DISALLOW_COPY_AND_ASSIGN(VelocityTrackerState);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_VELOCITY_TRACKER_STATE_H_
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc
new file mode 100644
index 00000000000..eda1606d141
--- /dev/null
+++ b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc
@@ -0,0 +1,193 @@
+// 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 "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/gesture_detection/mock_motion_event.h"
+#include "ui/events/gesture_detection/velocity_tracker_state.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace ui {
+namespace {
+
+const TimeDelta kTenMillis = TimeDelta::FromMilliseconds(10);
+const TimeDelta kOneSecond = TimeDelta::FromSeconds(1);
+const float kEpsilson = .01f;
+
+const char* GetStrategyName(VelocityTracker::Strategy strategy) {
+ switch (strategy) {
+ case VelocityTracker::LSQ1: return "LSQ1";
+ case VelocityTracker::LSQ2: return "LSQ2";
+ case VelocityTracker::LSQ3: return "LSQ3";
+ case VelocityTracker::WLSQ2_DELTA: return "WLSQ2_DELTA";
+ case VelocityTracker::WLSQ2_CENTRAL: return "WLSQ2_CENTRAL";
+ case VelocityTracker::WLSQ2_RECENT: return "WLSQ2_RECENT";
+ case VelocityTracker::INT1: return "INT1";
+ case VelocityTracker::INT2: return "INT2";
+ };
+ NOTREACHED() << "Invalid strategy";
+ return "";
+}
+
+} // namespace
+
+class VelocityTrackerTest : public testing::Test {
+ public:
+ VelocityTrackerTest() {}
+ virtual ~VelocityTrackerTest() {}
+
+ protected:
+ static MockMotionEvent Sample(MotionEvent::Action action,
+ gfx::PointF p0,
+ TimeTicks t0,
+ gfx::Vector2dF v,
+ TimeDelta dt) {
+ const gfx::PointF p = p0 + ScaleVector2d(v, dt.InSecondsF());
+ return MockMotionEvent(action, t0 + dt, p.x(), p.y());
+ }
+
+ static void ApplyMovementSequence(VelocityTrackerState* state,
+ gfx::PointF p0,
+ gfx::Vector2dF v,
+ TimeTicks t0,
+ TimeDelta t,
+ size_t samples) {
+ EXPECT_TRUE(!!samples);
+ if (!samples)
+ return;
+ const base::TimeDelta dt = t / samples;
+ state->AddMovement(Sample(MotionEvent::ACTION_DOWN, p0, t0, v, dt * 0));
+ ApplyMovement(state, p0, v, t0, t, samples);
+ state->AddMovement(Sample(MotionEvent::ACTION_UP, p0, t0, v, t));
+ }
+
+ static void ApplyMovement(VelocityTrackerState* state,
+ gfx::PointF p0,
+ gfx::Vector2dF v,
+ TimeTicks t0,
+ TimeDelta t,
+ size_t samples) {
+ EXPECT_TRUE(!!samples);
+ if (!samples)
+ return;
+ const base::TimeDelta dt = t / samples;
+ for (size_t i = 0; i < samples; ++i)
+ state->AddMovement(Sample(MotionEvent::ACTION_MOVE, p0, t0, v, dt * i));
+ }
+};
+
+TEST_F(VelocityTrackerTest, Basic) {
+ const gfx::PointF p0(0, 0);
+ const gfx::Vector2dF v(0, 500);
+ const size_t samples = 60;
+
+ for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) {
+ VelocityTracker::Strategy strategy =
+ static_cast<VelocityTracker::Strategy>(i);
+
+ SCOPED_TRACE(GetStrategyName(strategy));
+ VelocityTrackerState state(strategy);
+
+ // Default state should report zero velocity.
+ EXPECT_EQ(0, state.GetXVelocity(0));
+ EXPECT_EQ(0, state.GetYVelocity(0));
+
+ // Sample a constant velocity sequence.
+ ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), kOneSecond, samples);
+
+ // The computed velocity should match that of the input.
+ state.ComputeCurrentVelocity(1000, 20000);
+ EXPECT_NEAR(v.x(), state.GetXVelocity(0), kEpsilson * v.x());
+ EXPECT_NEAR(v.y(), state.GetYVelocity(0), kEpsilson * v.y());
+
+ // A pointer ID of -1 should report the velocity of the active pointer.
+ EXPECT_NEAR(v.x(), state.GetXVelocity(-1), kEpsilson * v.x());
+ EXPECT_NEAR(v.y(), state.GetYVelocity(-1), kEpsilson * v.y());
+
+ // Invalid pointer ID's should report zero velocity.
+ EXPECT_EQ(0, state.GetXVelocity(1));
+ EXPECT_EQ(0, state.GetYVelocity(1));
+ EXPECT_EQ(0, state.GetXVelocity(7));
+ EXPECT_EQ(0, state.GetYVelocity(7));
+ }
+}
+
+TEST_F(VelocityTrackerTest, MaxVelocity) {
+ const gfx::PointF p0(0, 0);
+ const gfx::Vector2dF v(-50000, 50000);
+ const size_t samples = 3;
+ const base::TimeDelta dt = kTenMillis * 2;
+
+ VelocityTrackerState state;
+ ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), dt, samples);
+
+ // The computed velocity should be restricted to the provided maximum.
+ state.ComputeCurrentVelocity(1000, 100);
+ EXPECT_NEAR(-100, state.GetXVelocity(0), kEpsilson);
+ EXPECT_NEAR(100, state.GetYVelocity(0), kEpsilson);
+
+ state.ComputeCurrentVelocity(1000, 1000);
+ EXPECT_NEAR(-1000, state.GetXVelocity(0), kEpsilson);
+ EXPECT_NEAR(1000, state.GetYVelocity(0), kEpsilson);
+}
+
+TEST_F(VelocityTrackerTest, VaryingVelocity) {
+ const gfx::PointF p0(0, 0);
+ const gfx::Vector2dF vFast(0, 500);
+ const gfx::Vector2dF vSlow = ScaleVector2d(vFast, 0.5f);
+ const size_t samples = 12;
+
+ for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) {
+ VelocityTracker::Strategy strategy =
+ static_cast<VelocityTracker::Strategy>(i);
+
+ SCOPED_TRACE(GetStrategyName(strategy));
+ VelocityTrackerState state(strategy);
+
+ base::TimeTicks t0 = base::TimeTicks::Now();
+ base::TimeDelta dt = kTenMillis * 10;
+ state.AddMovement(
+ Sample(MotionEvent::ACTION_DOWN, p0, t0, vFast, base::TimeDelta()));
+
+ // Apply some fast movement and compute the velocity.
+ gfx::PointF pCurr = p0;
+ base::TimeTicks tCurr = t0;
+ ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples);
+ state.ComputeCurrentVelocity(1000, 20000);
+ float vOldY = state.GetYVelocity(0);
+
+ // Apply some slow movement.
+ pCurr += ScaleVector2d(vFast, dt.InSecondsF());
+ tCurr += dt;
+ ApplyMovement(&state, pCurr, vSlow, tCurr, dt, samples);
+
+ // The computed velocity should have decreased.
+ state.ComputeCurrentVelocity(1000, 20000);
+ float vCurrentY = state.GetYVelocity(0);
+ EXPECT_GT(vFast.y(), vCurrentY);
+ EXPECT_GT(vOldY, vCurrentY);
+ vOldY = vCurrentY;
+
+ // Apply some additional fast movement.
+ pCurr += ScaleVector2d(vSlow, dt.InSecondsF());
+ tCurr += dt;
+ ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples);
+
+ // The computed velocity should have increased.
+ state.ComputeCurrentVelocity(1000, 20000);
+ vCurrentY = state.GetYVelocity(0);
+ EXPECT_LT(vSlow.y(), vCurrentY);
+ EXPECT_LT(vOldY, vCurrentY);
+ }
+}
+
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_event_details.cc b/chromium/ui/events/gesture_event_details.cc
new file mode 100644
index 00000000000..4026d06ecdb
--- /dev/null
+++ b/chromium/ui/events/gesture_event_details.cc
@@ -0,0 +1,71 @@
+// 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/events/gesture_event_details.h"
+
+namespace ui {
+
+GestureEventDetails::GestureEventDetails() : type_(ET_UNKNOWN) {}
+
+GestureEventDetails::GestureEventDetails(ui::EventType type,
+ float delta_x,
+ float delta_y)
+ : type_(type),
+ touch_points_(1) {
+ DCHECK_GE(type, ET_GESTURE_TYPE_START);
+ DCHECK_LE(type, ET_GESTURE_TYPE_END);
+ switch (type_) {
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ data.scroll_begin.x_hint = delta_x;
+ data.scroll_begin.y_hint = delta_y;
+ break;
+
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ data.scroll_update.x = delta_x;
+ data.scroll_update.y = delta_y;
+ break;
+
+ case ui::ET_SCROLL_FLING_START:
+ data.fling_velocity.x = delta_x;
+ data.fling_velocity.y = delta_y;
+ break;
+
+ case ui::ET_GESTURE_TWO_FINGER_TAP:
+ data.first_finger_enclosing_rectangle.width = delta_x;
+ data.first_finger_enclosing_rectangle.height = delta_y;
+ break;
+
+ case ui::ET_GESTURE_PINCH_UPDATE:
+ data.scale = delta_x;
+ CHECK_EQ(0.f, delta_y) << "Unknown data in delta_y for pinch";
+ break;
+
+ case ui::ET_GESTURE_SWIPE:
+ data.swipe.left = delta_x < 0;
+ data.swipe.right = delta_x > 0;
+ data.swipe.up = delta_y < 0;
+ data.swipe.down = delta_y > 0;
+ break;
+
+ case ui::ET_GESTURE_TAP:
+ case ui::ET_GESTURE_DOUBLE_TAP:
+ case ui::ET_GESTURE_TAP_UNCONFIRMED:
+ data.tap_count = static_cast<int>(delta_x);
+ CHECK_EQ(0.f, delta_y) << "Unknown data in delta_y for tap.";
+ break;
+
+ default:
+ if (delta_x != 0.f || delta_y != 0.f) {
+ DLOG(WARNING) << "A gesture event (" << type << ") had unknown data: ("
+ << delta_x << "," << delta_y;
+ }
+ break;
+ }
+}
+
+GestureEventDetails::Details::Details() {
+ memset(this, 0, sizeof(Details));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gesture_event_details.h b/chromium/ui/events/gesture_event_details.h
new file mode 100644
index 00000000000..32db808bf72
--- /dev/null
+++ b/chromium/ui/events/gesture_event_details.h
@@ -0,0 +1,171 @@
+// 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_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_
+#define UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_
+
+#include "base/logging.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/events_base_export.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_conversions.h"
+
+namespace ui {
+
+struct EVENTS_BASE_EXPORT GestureEventDetails {
+ public:
+ GestureEventDetails();
+ GestureEventDetails(EventType type, float delta_x, float delta_y);
+
+ EventType type() const { return type_; }
+
+ int touch_points() const { return touch_points_; }
+ void set_touch_points(int touch_points) {
+ DCHECK_GT(touch_points, 0);
+ touch_points_ = touch_points;
+ }
+
+ // TODO(tdresser): Return RectF. See crbug.com/337824.
+ const gfx::Rect bounding_box() const {
+ return ToEnclosingRect(bounding_box_);
+ }
+
+ const gfx::RectF& bounding_box_f() const {
+ return bounding_box_;
+ }
+
+ void set_bounding_box(const gfx::RectF& box) { bounding_box_ = box; }
+
+ float scroll_x_hint() const {
+ DCHECK_EQ(ET_GESTURE_SCROLL_BEGIN, type_);
+ return data.scroll_begin.x_hint;
+ }
+
+ float scroll_y_hint() const {
+ DCHECK_EQ(ET_GESTURE_SCROLL_BEGIN, type_);
+ return data.scroll_begin.y_hint;
+ }
+
+ float scroll_x() const {
+ DCHECK_EQ(ET_GESTURE_SCROLL_UPDATE, type_);
+ return data.scroll_update.x;
+ }
+
+ float scroll_y() const {
+ DCHECK_EQ(ET_GESTURE_SCROLL_UPDATE, type_);
+ return data.scroll_update.y;
+ }
+
+ float velocity_x() const {
+ DCHECK_EQ(ET_SCROLL_FLING_START, type_);
+ return data.fling_velocity.x;
+ }
+
+ float velocity_y() const {
+ DCHECK_EQ(ET_SCROLL_FLING_START, type_);
+ return data.fling_velocity.y;
+ }
+
+ float first_finger_width() const {
+ DCHECK_EQ(ET_GESTURE_TWO_FINGER_TAP, type_);
+ return data.first_finger_enclosing_rectangle.width;
+ }
+
+ float first_finger_height() const {
+ DCHECK_EQ(ET_GESTURE_TWO_FINGER_TAP, type_);
+ return data.first_finger_enclosing_rectangle.height;
+ }
+
+ float scale() const {
+ DCHECK_EQ(ET_GESTURE_PINCH_UPDATE, type_);
+ return data.scale;
+ }
+
+ bool swipe_left() const {
+ DCHECK_EQ(ET_GESTURE_SWIPE, type_);
+ return data.swipe.left;
+ }
+
+ bool swipe_right() const {
+ DCHECK_EQ(ET_GESTURE_SWIPE, type_);
+ return data.swipe.right;
+ }
+
+ bool swipe_up() const {
+ DCHECK_EQ(ET_GESTURE_SWIPE, type_);
+ return data.swipe.up;
+ }
+
+ bool swipe_down() const {
+ DCHECK_EQ(ET_GESTURE_SWIPE, type_);
+ return data.swipe.down;
+ }
+
+ int tap_count() const {
+ DCHECK(type_ == ET_GESTURE_TAP ||
+ type_ == ET_GESTURE_TAP_UNCONFIRMED ||
+ type_ == ET_GESTURE_DOUBLE_TAP);
+ return data.tap_count;
+ }
+
+ void set_tap_count(int tap_count) {
+ DCHECK_GE(tap_count, 0);
+ DCHECK(type_ == ET_GESTURE_TAP ||
+ type_ == ET_GESTURE_TAP_UNCONFIRMED ||
+ type_ == ET_GESTURE_DOUBLE_TAP);
+ data.tap_count = tap_count;
+ }
+
+ private:
+ EventType type_;
+ union Details {
+ Details();
+ struct { // SCROLL start details.
+ // Distance that caused the scroll to start. Generally redundant with
+ // the x/y values from the first scroll_update.
+ float x_hint;
+ float y_hint;
+ } scroll_begin;
+
+ struct { // SCROLL delta.
+ float x;
+ float y;
+ } scroll_update;
+
+ float scale; // PINCH scale.
+
+ struct { // FLING velocity.
+ float x;
+ float y;
+ } fling_velocity;
+
+ // Dimensions of the first finger's enclosing rectangle for
+ // TWO_FINGER_TAP.
+ struct {
+ float width;
+ float height;
+ } first_finger_enclosing_rectangle;
+
+ struct { // SWIPE direction.
+ bool left;
+ bool right;
+ bool up;
+ bool down;
+ } swipe;
+
+ // Tap information must be set for ET_GESTURE_TAP,
+ // ET_GESTURE_TAP_UNCONFIRMED, and ET_GESTURE_DOUBLE_TAP events.
+ int tap_count; // TAP repeat count.
+ } data;
+
+ int touch_points_; // Number of active touch points in the gesture.
+
+ // Bounding box is an axis-aligned rectangle that contains all the
+ // enclosing rectangles of the touch-points in the gesture.
+ gfx::RectF bounding_box_;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_
diff --git a/chromium/ui/events/gestures/OWNERS b/chromium/ui/events/gestures/OWNERS
index 6a1dd965022..92704b0eb58 100644
--- a/chromium/ui/events/gestures/OWNERS
+++ b/chromium/ui/events/gestures/OWNERS
@@ -1,2 +1,3 @@
rjkroege@chromium.org
sadrul@chromium.org
+tdresser@chromium.org
diff --git a/chromium/ui/events/gestures/gesture_configuration.cc b/chromium/ui/events/gestures/gesture_configuration.cc
index e48ae6daed3..8623e9973ee 100644
--- a/chromium/ui/events/gestures/gesture_configuration.cc
+++ b/chromium/ui/events/gestures/gesture_configuration.cc
@@ -6,7 +6,7 @@
namespace ui {
-int GestureConfiguration::default_radius_ = 15;
+int GestureConfiguration::default_radius_ = 25;
int GestureConfiguration::fling_max_cancel_to_down_time_in_ms_ = 400;
int GestureConfiguration::fling_max_tap_gap_time_in_ms_ = 200;
float GestureConfiguration::fling_velocity_cap_ = 17000.0f;
@@ -21,20 +21,23 @@ double
double GestureConfiguration::max_swipe_deviation_ratio_ = 3;
double
GestureConfiguration::max_touch_down_duration_in_seconds_for_click_ = 0.8;
-double GestureConfiguration::max_touch_move_in_pixels_for_click_ = 25;
+double GestureConfiguration::max_touch_move_in_pixels_for_click_ = 15;
double GestureConfiguration::max_distance_between_taps_for_double_tap_ = 20;
double GestureConfiguration::min_distance_for_pinch_scroll_in_pixels_ = 20;
double GestureConfiguration::min_flick_speed_squared_ = 550.f * 550.f;
double GestureConfiguration::min_pinch_update_distance_in_pixels_ = 5;
double GestureConfiguration::min_rail_break_velocity_ = 200;
double GestureConfiguration::min_scroll_delta_squared_ = 4 * 4;
-int GestureConfiguration::min_scroll_successive_velocity_events_ = 4;
float GestureConfiguration::min_scroll_velocity_ = 30.0f;
double GestureConfiguration::min_swipe_speed_ = 20;
double GestureConfiguration::scroll_prediction_seconds_ = 0.03;
double
GestureConfiguration::min_touch_down_duration_in_seconds_for_click_ = 0.01;
+// If this is too small, we currently can get single finger pinch zoom. See
+// crbug.com/357237 for details.
+int GestureConfiguration::min_scaling_span_in_pixels_ = 125;
+
// The number of points used in the linear regression which determines
// touch velocity. Velocity is reported for 2 or more touch move events.
int GestureConfiguration::points_buffered_for_velocity_ = 8;
@@ -42,6 +45,14 @@ double GestureConfiguration::rail_break_proportion_ = 15;
double GestureConfiguration::rail_start_proportion_ = 2;
int GestureConfiguration::show_press_delay_in_ms_ = 150;
+// TODO(jdduke): Disable and remove entirely when issues with intermittent
+// scroll end detection on the Pixel are resolved, crbug.com/353702.
+#if defined(OS_CHROMEOS)
+int GestureConfiguration::scroll_debounce_interval_in_ms_ = 30;
+#else
+int GestureConfiguration::scroll_debounce_interval_in_ms_ = 0;
+#endif
+
// Coefficients for a function that computes fling acceleration.
// These are empirically determined defaults. Do not adjust without
// additional empirical validation.
diff --git a/chromium/ui/events/gestures/gesture_configuration.h b/chromium/ui/events/gestures/gesture_configuration.h
index a4bdcd3f4c2..08ce578eeeb 100644
--- a/chromium/ui/events/gestures/gesture_configuration.h
+++ b/chromium/ui/events/gestures/gesture_configuration.h
@@ -6,7 +6,7 @@
#define UI_EVENTS_GESTURES_GESTURE_CONFIGURATION_H_
#include "base/basictypes.h"
-#include "ui/events/events_export.h"
+#include "ui/events/events_base_export.h"
namespace ui {
@@ -14,7 +14,7 @@ namespace ui {
// approaches (windows, chrome, others). This would turn into an
// abstract base class.
-class EVENTS_EXPORT GestureConfiguration {
+class EVENTS_BASE_EXPORT GestureConfiguration {
public:
// Number of parameters in the array of parameters for the fling acceleration
// curve.
@@ -125,12 +125,6 @@ class EVENTS_EXPORT GestureConfiguration {
static void set_min_scroll_delta_squared(double val) {
min_scroll_delta_squared_ = val;
}
- static int min_scroll_successive_velocity_events() {
- return min_scroll_successive_velocity_events_;
- }
- static void set_min_scroll_successive_velocity_events(int val) {
- min_scroll_successive_velocity_events_ = val;
- }
static float min_scroll_velocity() {
return min_scroll_velocity_;
}
@@ -149,6 +143,15 @@ class EVENTS_EXPORT GestureConfiguration {
static void set_min_touch_down_duration_in_seconds_for_click(double val) {
min_touch_down_duration_in_seconds_for_click_ = val;
}
+
+ static int min_scaling_span_in_pixels() {
+ return min_scaling_span_in_pixels_;
+ };
+
+ static void set_min_scaling_span_in_pixels(int val) {
+ min_scaling_span_in_pixels_ = val;
+ }
+
static int points_buffered_for_velocity() {
return points_buffered_for_velocity_;
}
@@ -179,6 +182,12 @@ class EVENTS_EXPORT GestureConfiguration {
static int set_show_press_delay_in_ms(int val) {
return show_press_delay_in_ms_ = val;
}
+ static int scroll_debounce_interval_in_ms() {
+ return scroll_debounce_interval_in_ms_;
+ }
+ static int set_scroll_debounce_interval_in_ms(int val) {
+ return scroll_debounce_interval_in_ms_ = val;
+ }
static void set_fling_acceleration_curve_coefficients(int i, float val) {
fling_acceleration_curve_coefficients_[i] = val;
}
@@ -238,15 +247,17 @@ class EVENTS_EXPORT GestureConfiguration {
static double min_pinch_update_distance_in_pixels_;
static double min_rail_break_velocity_;
static double min_scroll_delta_squared_;
- static int min_scroll_successive_velocity_events_;
static float min_scroll_velocity_;
static double min_swipe_speed_;
static double min_touch_down_duration_in_seconds_for_click_;
+ static int min_scaling_span_in_pixels_;
static int points_buffered_for_velocity_;
static double rail_break_proportion_;
static double rail_start_proportion_;
static double scroll_prediction_seconds_;
static int show_press_delay_in_ms_;
+ static int scroll_debounce_interval_in_ms_;
+
static float fling_acceleration_curve_coefficients_[NumAccelParams];
static float fling_velocity_cap_;
// TODO(davemoore): Move into chrome/browser/ui.
diff --git a/chromium/ui/events/gestures/gesture_point.cc b/chromium/ui/events/gestures/gesture_point.cc
index 529471af8b4..33966235a10 100644
--- a/chromium/ui/events/gestures/gesture_point.cc
+++ b/chromium/ui/events/gestures/gesture_point.cc
@@ -11,7 +11,6 @@
#include "ui/events/event_constants.h"
#include "ui/events/gestures/gesture_configuration.h"
#include "ui/events/gestures/gesture_types.h"
-#include "ui/events/gestures/gesture_util.h"
namespace ui {
@@ -24,7 +23,14 @@ GesturePoint::GesturePoint()
velocity_calculator_(
GestureConfiguration::points_buffered_for_velocity()),
point_id_(-1),
- touch_id_(-1) {
+ touch_id_(-1),
+ source_device_id_(-1) {
+ max_touch_move_in_pixels_for_click_squared_ =
+ GestureConfiguration::max_touch_move_in_pixels_for_click() *
+ GestureConfiguration::max_touch_move_in_pixels_for_click();
+ max_distance_between_taps_for_double_tap_squared_ =
+ GestureConfiguration::max_distance_between_taps_for_double_tap() *
+ GestureConfiguration::max_distance_between_taps_for_double_tap();
}
GesturePoint::~GesturePoint() {}
@@ -34,14 +40,14 @@ void GesturePoint::Reset() {
ResetVelocity();
point_id_ = -1;
clear_enclosing_rectangle();
+ source_device_id_ = -1;
}
void GesturePoint::ResetVelocity() {
velocity_calculator_.ClearHistory();
- same_direction_count_ = gfx::Vector2d();
}
-gfx::Vector2d GesturePoint::ScrollDelta() {
+gfx::Vector2dF GesturePoint::ScrollDelta() const {
return last_touch_position_ - second_last_touch_position_;
}
@@ -54,11 +60,10 @@ void GesturePoint::UpdateValues(const TouchEvent& event) {
event_timestamp_microseconds);
gfx::Vector2d sd(ScrollVelocityDirection(velocity_calculator_.XVelocity()),
ScrollVelocityDirection(velocity_calculator_.YVelocity()));
- same_direction_count_ = same_direction_count_ + sd;
}
last_touch_time_ = event.time_stamp().InSecondsF();
- last_touch_position_ = event.location();
+ last_touch_position_ = event.location_f();
if (event.type() == ui::ET_TOUCH_PRESSED) {
ResetVelocity();
@@ -86,31 +91,30 @@ void GesturePoint::UpdateForTap() {
void GesturePoint::UpdateForScroll() {
second_last_touch_position_ = last_touch_position_;
second_last_touch_time_ = last_touch_time_;
- same_direction_count_ = gfx::Vector2d();
}
bool GesturePoint::IsInClickWindow(const TouchEvent& event) const {
- return IsInClickTimeWindow() && IsInsideManhattanSquare(event);
+ return IsInClickTimeWindow() && IsInsideTouchSlopRegion(event);
}
bool GesturePoint::IsInDoubleClickWindow(const TouchEvent& event) const {
return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
- IsPointInsideManhattanSquare(event.location(), last_tap_position_);
+ IsPointInsideDoubleTapTouchSlopRegion(
+ event.location(), last_tap_position_);
}
bool GesturePoint::IsInTripleClickWindow(const TouchEvent& event) const {
return IsInClickAggregateTimeWindow(last_tap_time_, last_touch_time_) &&
IsInClickAggregateTimeWindow(second_last_tap_time_, last_tap_time_) &&
- IsPointInsideManhattanSquare(event.location(), last_tap_position_) &&
- IsPointInsideManhattanSquare(last_tap_position_,
+ IsPointInsideDoubleTapTouchSlopRegion(
+ event.location(), last_tap_position_) &&
+ IsPointInsideDoubleTapTouchSlopRegion(last_tap_position_,
second_last_tap_position_);
}
bool GesturePoint::IsInScrollWindow(const TouchEvent& event) const {
- if (IsConsistentScrollingActionUnderway())
- return true;
return event.type() == ui::ET_TOUCH_MOVED &&
- !IsInsideManhattanSquare(event);
+ !IsInsideTouchSlopRegion(event);
}
bool GesturePoint::IsInFlickWindow(const TouchEvent& event) {
@@ -128,28 +132,20 @@ int GesturePoint::ScrollVelocityDirection(float v) {
}
bool GesturePoint::DidScroll(const TouchEvent& event, int dist) const {
- gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
- return abs(d.x()) > dist || abs(d.y()) > dist;
-}
-
-bool GesturePoint::IsConsistentScrollingActionUnderway() const {
- int me = GestureConfiguration::min_scroll_successive_velocity_events();
- if (abs(same_direction_count_.x()) >= me ||
- abs(same_direction_count_.y()) >= me)
- return true;
- return false;
+ gfx::Vector2dF d = last_touch_position_ - second_last_touch_position_;
+ return fabs(d.x()) > dist || fabs(d.y()) > dist;
}
bool GesturePoint::IsInHorizontalRailWindow() const {
- gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
- return abs(d.x()) >
- GestureConfiguration::rail_start_proportion() * abs(d.y());
+ gfx::Vector2dF d = last_touch_position_ - second_last_touch_position_;
+ return std::abs(d.x()) >
+ GestureConfiguration::rail_start_proportion() * std::abs(d.y());
}
bool GesturePoint::IsInVerticalRailWindow() const {
- gfx::Vector2d d = last_touch_position_ - second_last_touch_position_;
- return abs(d.y()) >
- GestureConfiguration::rail_start_proportion() * abs(d.x());
+ gfx::Vector2dF d = last_touch_position_ - second_last_touch_position_;
+ return std::abs(d.y()) >
+ GestureConfiguration::rail_start_proportion() * std::abs(d.x());
}
bool GesturePoint::BreaksHorizontalRail() {
@@ -180,16 +176,21 @@ bool GesturePoint::IsInClickAggregateTimeWindow(double before,
return duration < GestureConfiguration::max_seconds_between_double_click();
}
-bool GesturePoint::IsInsideManhattanSquare(const TouchEvent& event) const {
- return ui::gestures::IsInsideManhattanSquare(event.location(),
- first_touch_position_);
+bool GesturePoint::IsInsideTouchSlopRegion(const TouchEvent& event) const {
+ const gfx::PointF& p1 = event.location();
+ const gfx::PointF& p2 = first_touch_position_;
+ float dx = p1.x() - p2.x();
+ float dy = p1.y() - p2.y();
+ float distance = dx * dx + dy * dy;
+ return distance < max_touch_move_in_pixels_for_click_squared_;
}
-bool GesturePoint::IsPointInsideManhattanSquare(gfx::Point p1,
- gfx::Point p2) const {
- int manhattan_distance = abs(p1.x() - p2.x()) + abs(p1.y() - p2.y());
- return manhattan_distance <
- GestureConfiguration::max_distance_between_taps_for_double_tap();
+bool GesturePoint::IsPointInsideDoubleTapTouchSlopRegion(gfx::PointF p1,
+ gfx::PointF p2) const {
+ float dx = p1.x() - p2.x();
+ float dy = p1.y() - p2.y();
+ float distance = dx * dx + dy * dy;
+ return distance < max_distance_between_taps_for_double_tap_squared_;
}
bool GesturePoint::IsOverMinFlickSpeed() {
@@ -217,10 +218,10 @@ void GesturePoint::UpdateEnclosingRectangle(const TouchEvent& event) {
else
radius = GestureConfiguration::default_radius();
- gfx::Rect rect(event.location().x() - radius,
- event.location().y() - radius,
- radius * 2,
- radius * 2);
+ gfx::RectF rect(event.location_f().x() - radius,
+ event.location_f().y() - radius,
+ radius * 2,
+ radius * 2);
if (IsInClickWindow(event))
enclosing_rect_.Union(rect);
else
diff --git a/chromium/ui/events/gestures/gesture_point.h b/chromium/ui/events/gestures/gesture_point.h
index 02aa4608592..f20cf9dc7ec 100644
--- a/chromium/ui/events/gestures/gesture_point.h
+++ b/chromium/ui/events/gestures/gesture_point.h
@@ -43,20 +43,22 @@ class GesturePoint {
bool IsInFlickWindow(const TouchEvent& event);
bool IsInHorizontalRailWindow() const;
bool IsInVerticalRailWindow() const;
- bool IsInsideManhattanSquare(const TouchEvent& event) const;
+ bool IsInsideTouchSlopRegion(const TouchEvent& event) const;
bool IsInScrollWindow(const TouchEvent& event) const;
bool BreaksHorizontalRail();
bool BreaksVerticalRail();
bool DidScroll(const TouchEvent& event, int distance) const;
- const gfx::Point& first_touch_position() const {
+ const gfx::PointF& first_touch_position() const {
return first_touch_position_;
}
double last_touch_time() const { return last_touch_time_; }
- const gfx::Point& last_touch_position() const { return last_touch_position_; }
- int x() const { return last_touch_position_.x(); }
- int y() const { return last_touch_position_.y(); }
+ const gfx::PointF& last_touch_position() const {
+ return last_touch_position_;
+ }
+ float x() const { return last_touch_position_.x(); }
+ float y() const { return last_touch_position_.y(); }
// point_id_ is used to drive GestureSequence::ProcessTouchEventForGesture.
// point_ids are maintained such that the set of point_ids is always
@@ -72,22 +74,25 @@ class GesturePoint {
bool in_use() const { return point_id_ >= 0; }
- gfx::Vector2d ScrollDelta();
+ gfx::Vector2dF ScrollDelta() const;
float XVelocity() { return velocity_calculator_.XVelocity(); }
float YVelocity() { return velocity_calculator_.YVelocity(); }
- const gfx::Rect& enclosing_rectangle() const { return enclosing_rect_; }
+ const gfx::RectF& enclosing_rectangle() const { return enclosing_rect_; }
+
+ void set_source_device_id(int source_device_id) {
+ source_device_id_ = source_device_id;
+ }
+ int source_device_id() const { return source_device_id_; }
private:
// Various statistical functions to manipulate gestures.
- // Tests if the point has a consistent scroll vector across a window of touch
- // move events.
- bool IsConsistentScrollingActionUnderway() const;
bool IsInClickTimeWindow() const;
bool IsInClickAggregateTimeWindow(double before, double after) const;
- bool IsPointInsideManhattanSquare(gfx::Point p1, gfx::Point p2) const;
+ bool IsPointInsideDoubleTapTouchSlopRegion(
+ gfx::PointF p1, gfx::PointF p2) const;
bool IsOverMinFlickSpeed();
// Returns -1, 0, 1 for |v| below the negative velocity threshold,
@@ -101,23 +106,23 @@ class GesturePoint {
// cleared on a ET_TOUCH_PRESSED event (i.e., at the beginning of a possible
// GESTURE_TAP event) or when Reset is called.
void UpdateEnclosingRectangle(const TouchEvent& event);
- void clear_enclosing_rectangle() { enclosing_rect_ = gfx::Rect(); }
+ void clear_enclosing_rectangle() { enclosing_rect_ = gfx::RectF(); }
// The position of the first touchdown event.
- gfx::Point first_touch_position_;
+ gfx::PointF first_touch_position_;
double first_touch_time_;
- gfx::Point second_last_touch_position_;
+ gfx::PointF second_last_touch_position_;
double second_last_touch_time_;
- gfx::Point last_touch_position_;
+ gfx::PointF last_touch_position_;
double last_touch_time_;
double second_last_tap_time_;
- gfx::Point second_last_tap_position_;
+ gfx::PointF second_last_tap_position_;
double last_tap_time_;
- gfx::Point last_tap_position_;
+ gfx::PointF last_tap_position_;
VelocityCalculator velocity_calculator_;
@@ -126,10 +131,12 @@ class GesturePoint {
// Represents the rectangle that encloses the circles/ellipses
// generated by a sequence of touch events
- gfx::Rect enclosing_rect_;
+ gfx::RectF enclosing_rect_;
+
+ int source_device_id_;
- // Count of the number of events with same direction.
- gfx::Vector2d same_direction_count_;
+ float max_touch_move_in_pixels_for_click_squared_;
+ float max_distance_between_taps_for_double_tap_squared_;
DISALLOW_COPY_AND_ASSIGN(GesturePoint);
};
diff --git a/chromium/ui/events/gestures/gesture_provider_aura.cc b/chromium/ui/events/gestures/gesture_provider_aura.cc
new file mode 100644
index 00000000000..eb902f507f8
--- /dev/null
+++ b/chromium/ui/events/gestures/gesture_provider_aura.cc
@@ -0,0 +1,142 @@
+// 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/events/gestures/gesture_provider_aura.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+#include "ui/events/event.h"
+#include "ui/events/gesture_detection/gesture_config_helper.h"
+#include "ui/events/gesture_detection/gesture_event_data.h"
+#include "ui/events/gestures/gesture_configuration.h"
+
+namespace ui {
+
+GestureProviderAura::GestureProviderAura(GestureProviderAuraClient* client)
+ : client_(client),
+ filtered_gesture_provider_(ui::DefaultGestureProviderConfig(), this),
+ handling_event_(false) {
+ filtered_gesture_provider_.SetDoubleTapSupportForPlatformEnabled(false);
+}
+
+GestureProviderAura::~GestureProviderAura() {}
+
+bool GestureProviderAura::OnTouchEvent(const TouchEvent& event) {
+ bool pointer_id_is_active = false;
+ for (size_t i = 0; i < pointer_state_.GetPointerCount(); ++i) {
+ if (event.touch_id() != pointer_state_.GetPointerId(i))
+ continue;
+ pointer_id_is_active = true;
+ break;
+ }
+
+ if (event.type() == ET_TOUCH_PRESSED && pointer_id_is_active) {
+ // Ignore touch press events if we already believe the pointer is down.
+ return false;
+ } else if (event.type() != ET_TOUCH_PRESSED && !pointer_id_is_active) {
+ // We could have an active touch stream transfered to us, resulting in touch
+ // move or touch up events without associated touch down events. Ignore
+ // them.
+ return false;
+ }
+
+ last_touch_event_flags_ = event.flags();
+ last_touch_event_latency_info_ = *event.latency();
+ pointer_state_.OnTouch(event);
+
+ bool result = filtered_gesture_provider_.OnTouchEvent(pointer_state_);
+ pointer_state_.CleanupRemovedTouchPoints(event);
+ return result;
+}
+
+void GestureProviderAura::OnTouchEventAck(bool event_consumed) {
+ DCHECK(pending_gestures_.empty());
+ DCHECK(!handling_event_);
+ base::AutoReset<bool> handling_event(&handling_event_, true);
+ filtered_gesture_provider_.OnTouchEventAck(event_consumed);
+ last_touch_event_latency_info_.Clear();
+}
+
+void GestureProviderAura::OnGestureEvent(
+ const GestureEventData& gesture) {
+ GestureEventDetails details = gesture.details;
+
+ if (gesture.type() == ET_GESTURE_TAP) {
+ int tap_count = 1;
+ if (previous_tap_ && IsConsideredDoubleTap(*previous_tap_, gesture))
+ tap_count = 1 + (previous_tap_->details.tap_count() % 3);
+ details.set_tap_count(tap_count);
+ if (!previous_tap_)
+ previous_tap_.reset(new GestureEventData(gesture));
+ else
+ *previous_tap_ = gesture;
+ previous_tap_->details = details;
+ } else if (gesture.type() == ET_GESTURE_TAP_CANCEL) {
+ previous_tap_.reset();
+ }
+
+ scoped_ptr<ui::GestureEvent> event(
+ new ui::GestureEvent(gesture.type(),
+ gesture.x,
+ gesture.y,
+ last_touch_event_flags_,
+ gesture.time - base::TimeTicks(),
+ details,
+ // ui::GestureEvent stores a bitfield indicating the
+ // ids of active touch points. This is currently only
+ // used when one finger is down, and will eventually
+ // be cleaned up. See crbug.com/366707.
+ 1 << gesture.motion_event_id));
+
+
+ ui::LatencyInfo* gesture_latency = event->latency();
+
+ gesture_latency->CopyLatencyFrom(
+ last_touch_event_latency_info_,
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
+ gesture_latency->CopyLatencyFrom(
+ last_touch_event_latency_info_,
+ ui::INPUT_EVENT_LATENCY_UI_COMPONENT);
+ gesture_latency->CopyLatencyFrom(
+ last_touch_event_latency_info_,
+ ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT);
+
+ if (!handling_event_) {
+ // Dispatching event caused by timer.
+ client_->OnGestureEvent(event.get());
+ } else {
+ // Memory managed by ScopedVector pending_gestures_.
+ pending_gestures_.push_back(event.release());
+ }
+}
+
+ScopedVector<GestureEvent>* GestureProviderAura::GetAndResetPendingGestures() {
+ if (pending_gestures_.empty())
+ return NULL;
+ // Caller is responsible for deleting old_pending_gestures.
+ ScopedVector<GestureEvent>* old_pending_gestures =
+ new ScopedVector<GestureEvent>();
+ old_pending_gestures->swap(pending_gestures_);
+ return old_pending_gestures;
+}
+
+bool GestureProviderAura::IsConsideredDoubleTap(
+ const GestureEventData& previous_tap,
+ const GestureEventData& current_tap) const {
+ if (current_tap.time - previous_tap.time >
+ base::TimeDelta::FromMilliseconds(
+ ui::GestureConfiguration::max_seconds_between_double_click() *
+ 1000)) {
+ return false;
+ }
+
+ double double_tap_slop_square =
+ GestureConfiguration::max_distance_between_taps_for_double_tap();
+ double_tap_slop_square *= double_tap_slop_square;
+ const float delta_x = previous_tap.x - current_tap.x;
+ const float delta_y = previous_tap.y - current_tap.y;
+ return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square);
+}
+
+} // namespace content
diff --git a/chromium/ui/events/gestures/gesture_provider_aura.h b/chromium/ui/events/gestures/gesture_provider_aura.h
new file mode 100644
index 00000000000..ff7befce15e
--- /dev/null
+++ b/chromium/ui/events/gestures/gesture_provider_aura.h
@@ -0,0 +1,59 @@
+// 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_GESTURE_DETECTION_UI_GESTURE_PROVIDER_H_
+#define UI_EVENTS_GESTURE_DETECTION_UI_GESTURE_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "ui/events/event.h"
+#include "ui/events/events_export.h"
+#include "ui/events/gesture_detection/filtered_gesture_provider.h"
+#include "ui/events/gesture_detection/gesture_event_data_packet.h"
+#include "ui/events/gesture_detection/touch_disposition_gesture_filter.h"
+#include "ui/events/gestures/motion_event_aura.h"
+
+namespace ui {
+
+class EVENTS_EXPORT GestureProviderAuraClient {
+ public:
+ virtual ~GestureProviderAuraClient() {}
+ virtual void OnGestureEvent(GestureEvent* event) = 0;
+};
+
+// Provides gesture detection and dispatch given a sequence of touch events
+// and touch event acks.
+class EVENTS_EXPORT GestureProviderAura : public GestureProviderClient {
+ public:
+ GestureProviderAura(GestureProviderAuraClient* client);
+ virtual ~GestureProviderAura();
+
+ bool OnTouchEvent(const TouchEvent& event);
+ void OnTouchEventAck(bool event_consumed);
+ const MotionEventAura& pointer_state() { return pointer_state_; }
+ ScopedVector<GestureEvent>* GetAndResetPendingGestures();
+
+ // GestureProviderClient implementation
+ virtual void OnGestureEvent(const GestureEventData& gesture) OVERRIDE;
+
+ private:
+ bool IsConsideredDoubleTap(const GestureEventData& previous_tap,
+ const GestureEventData& current_tap) const;
+
+ scoped_ptr<GestureEventData> previous_tap_;
+
+ GestureProviderAuraClient* client_;
+ MotionEventAura pointer_state_;
+ FilteredGestureProvider filtered_gesture_provider_;
+
+ int last_touch_event_flags_;
+ ui::LatencyInfo last_touch_event_latency_info_;
+ bool handling_event_;
+ ScopedVector<GestureEvent> pending_gestures_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureProviderAura);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_UI_GESTURE_PROVIDER_H_
diff --git a/chromium/ui/events/gestures/gesture_recognizer.h b/chromium/ui/events/gestures/gesture_recognizer.h
index 92d225a7118..4b31e57bd71 100644
--- a/chromium/ui/events/gestures/gesture_recognizer.h
+++ b/chromium/ui/events/gestures/gesture_recognizer.h
@@ -11,6 +11,7 @@
#include "ui/events/event_constants.h"
#include "ui/events/events_export.h"
#include "ui/events/gestures/gesture_types.h"
+#include "ui/gfx/geometry/point_f.h"
namespace ui {
// A GestureRecognizer is an abstract base class for conversion of touch events
@@ -19,6 +20,7 @@ class EVENTS_EXPORT GestureRecognizer {
public:
static GestureRecognizer* Create();
static GestureRecognizer* Get();
+ static void Reset();
// List of GestureEvent*.
typedef ScopedVector<GestureEvent> Gestures;
@@ -34,8 +36,9 @@ class EVENTS_EXPORT GestureRecognizer {
GestureConsumer* consumer) = 0;
// This is called when the consumer is destroyed. So this should cleanup any
- // internal state maintained for |consumer|.
- virtual void CleanupStateForConsumer(GestureConsumer* consumer) = 0;
+ // internal state maintained for |consumer|. Returns true iff there was
+ // state relating to |consumer| to clean up.
+ virtual bool CleanupStateForConsumer(GestureConsumer* consumer) = 0;
// Return the window which should handle this TouchEvent, in the case where
// the touch is already associated with a target.
@@ -46,10 +49,12 @@ class EVENTS_EXPORT GestureRecognizer {
virtual GestureConsumer* GetTargetForGestureEvent(
const GestureEvent& event) = 0;
- // If there is an active touch within
- // GestureConfiguration::max_separation_for_gesture_touches_in_pixels,
- // of |location|, returns the target of the nearest active touch.
- virtual GestureConsumer* GetTargetForLocation(const gfx::Point& location) = 0;
+ // Returns the target of the nearest active touch with source device of
+ // |source_device_id|, within
+ // GestureConfiguration::max_separation_for_gesture_touches_in_pixels of
+ // |location|, or NULL if no such point exists.
+ virtual GestureConsumer* GetTargetForLocation(
+ const gfx::PointF& location, int source_device_id) = 0;
// Makes |new_consumer| the target for events previously targeting
// |current_consumer|. All other targets are canceled.
@@ -65,10 +70,11 @@ class EVENTS_EXPORT GestureRecognizer {
// point and true is returned. If no touch events have been processed for
// |consumer| false is returned and |point| is untouched.
virtual bool GetLastTouchPointForTarget(GestureConsumer* consumer,
- gfx::Point* point) = 0;
+ gfx::PointF* point) = 0;
- // Sends a touch cancel event for every active touch.
- virtual void CancelActiveTouches(GestureConsumer* consumer) = 0;
+ // Sends a touch cancel event for every active touch. Returns true iff any
+ // touch cancels were sent.
+ virtual bool CancelActiveTouches(GestureConsumer* consumer) = 0;
// Subscribes |helper| for dispatching async gestures such as long press.
// The Gesture Recognizer does NOT take ownership of |helper| and it is the
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl.cc b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
index 4a599345c84..e145334454b 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
@@ -4,15 +4,21 @@
#include "ui/events/gestures/gesture_recognizer_impl.h"
+#include <limits>
+
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
+#include "ui/events/event_switches.h"
#include "ui/events/event_utils.h"
#include "ui/events/gestures/gesture_configuration.h"
#include "ui/events/gestures/gesture_sequence.h"
#include "ui/events/gestures/gesture_types.h"
+#include "ui/events/gestures/unified_gesture_detector_enabled.h"
namespace ui {
@@ -28,15 +34,19 @@ void TransferConsumer(GestureConsumer* current_consumer,
}
}
-void RemoveConsumerFromMap(GestureConsumer* consumer,
+bool RemoveConsumerFromMap(GestureConsumer* consumer,
GestureRecognizerImpl::TouchIdToConsumerMap* map) {
+ bool consumer_removed = false;
for (GestureRecognizerImpl::TouchIdToConsumerMap::iterator i = map->begin();
i != map->end();) {
- if (i->second == consumer)
+ if (i->second == consumer) {
map->erase(i++);
- else
+ consumer_removed = true;
+ } else {
++i;
+ }
}
+ return consumer_removed;
}
void TransferTouchIdToConsumerMap(
@@ -50,16 +60,22 @@ void TransferTouchIdToConsumerMap(
}
}
+GestureProviderAura* CreateGestureProvider(GestureProviderAuraClient* client) {
+ return new GestureProviderAura(client);
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, public:
GestureRecognizerImpl::GestureRecognizerImpl() {
+ use_unified_gesture_detector_ = IsUnifiedGestureDetectorEnabled();
}
GestureRecognizerImpl::~GestureRecognizerImpl() {
STLDeleteValues(&consumer_sequence_);
+ STLDeleteValues(&consumer_gesture_provider_);
}
// Checks if this finger is already down, if so, returns the current target.
@@ -78,33 +94,66 @@ GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent(
}
GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
- const gfx::Point& location) {
- const GesturePoint* closest_point = NULL;
- int64 closest_distance_squared = 0;
- std::map<GestureConsumer*, GestureSequence*>::iterator i;
- for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
- const GesturePoint* points = i->second->points();
- for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
- if (!points[j].in_use())
- continue;
- gfx::Vector2d delta = points[j].last_touch_position() - location;
- // Relative distance is all we need here, so LengthSquared() is
- // appropriate, and cheaper than Length().
- int64 distance_squared = delta.LengthSquared();
- if (!closest_point || distance_squared < closest_distance_squared) {
- closest_point = &points[j];
- closest_distance_squared = distance_squared;
+ const gfx::PointF& location, int source_device_id) {
+ const int max_distance =
+ GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
+
+ if (!use_unified_gesture_detector_) {
+ const GesturePoint* closest_point = NULL;
+ int64 closest_distance_squared = 0;
+ std::map<GestureConsumer*, GestureSequence*>::iterator i;
+ for (i = consumer_sequence_.begin(); i != consumer_sequence_.end(); ++i) {
+ const GesturePoint* points = i->second->points();
+ for (int j = 0; j < GestureSequence::kMaxGesturePoints; ++j) {
+ if (!points[j].in_use() ||
+ source_device_id != points[j].source_device_id()) {
+ continue;
+ }
+ gfx::Vector2dF delta = points[j].last_touch_position() - location;
+ // Relative distance is all we need here, so LengthSquared() is
+ // appropriate, and cheaper than Length().
+ int64 distance_squared = delta.LengthSquared();
+ if (!closest_point || distance_squared < closest_distance_squared) {
+ closest_point = &points[j];
+ closest_distance_squared = distance_squared;
+ }
}
}
- }
- const int max_distance =
- GestureConfiguration::max_separation_for_gesture_touches_in_pixels();
+ if (closest_distance_squared < max_distance * max_distance && closest_point)
+ return touch_id_target_[closest_point->touch_id()];
+ else
+ return NULL;
+ } else {
+ gfx::PointF closest_point;
+ int closest_touch_id;
+ float closest_distance_squared = std::numeric_limits<float>::infinity();
+
+ std::map<GestureConsumer*, GestureProviderAura*>::iterator i;
+ for (i = consumer_gesture_provider_.begin();
+ i != consumer_gesture_provider_.end();
+ ++i) {
+ const MotionEventAura& pointer_state = i->second->pointer_state();
+ for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
+ if (source_device_id != pointer_state.GetSourceDeviceId(j))
+ continue;
+ gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
+ // Relative distance is all we need here, so LengthSquared() is
+ // appropriate, and cheaper than Length().
+ float distance_squared = (point - location).LengthSquared();
+ if (distance_squared < closest_distance_squared) {
+ closest_point = point;
+ closest_touch_id = pointer_state.GetPointerId(j);
+ closest_distance_squared = distance_squared;
+ }
+ }
+ }
- if (closest_distance_squared < max_distance * max_distance && closest_point)
- return touch_id_target_[closest_point->touch_id()];
- else
- return NULL;
+ if (closest_distance_squared < max_distance * max_distance)
+ return touch_id_target_[closest_touch_id];
+ else
+ return NULL;
+ }
}
void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
@@ -134,29 +183,42 @@ void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer,
&touch_id_target_);
TransferTouchIdToConsumerMap(current_consumer, new_consumer,
&touch_id_target_for_gestures_);
- TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
+ if (!use_unified_gesture_detector_)
+ TransferConsumer(current_consumer, new_consumer, &consumer_sequence_);
+ else
+ TransferConsumer(
+ current_consumer, new_consumer, &consumer_gesture_provider_);
}
}
bool GestureRecognizerImpl::GetLastTouchPointForTarget(
GestureConsumer* consumer,
- gfx::Point* point) {
- if (consumer_sequence_.count(consumer) == 0)
- return false;
-
- *point = consumer_sequence_[consumer]->last_touch_location();
- return true;
+ gfx::PointF* point) {
+ if (!use_unified_gesture_detector_) {
+ if (consumer_sequence_.count(consumer) == 0)
+ return false;
+ *point = consumer_sequence_[consumer]->last_touch_location();
+ return true;
+ } else {
+ if (consumer_gesture_provider_.count(consumer) == 0)
+ return false;
+ const MotionEvent& pointer_state =
+ consumer_gesture_provider_[consumer]->pointer_state();
+ *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
+ return true;
+ }
}
-void GestureRecognizerImpl::CancelActiveTouches(
- GestureConsumer* consumer) {
+bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
std::vector<std::pair<int, GestureConsumer*> > ids;
for (TouchIdToConsumerMap::const_iterator i = touch_id_target_.begin();
i != touch_id_target_.end(); ++i) {
if (i->second == consumer)
ids.push_back(std::make_pair(i->first, i->second));
}
+ bool cancelled_touch = !ids.empty();
CancelTouches(&ids);
+ return cancelled_touch;
}
////////////////////////////////////////////////////////////////////////////////
@@ -180,6 +242,16 @@ GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer(
return gesture_sequence;
}
+GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
+ GestureConsumer* consumer) {
+ GestureProviderAura* gesture_provider = consumer_gesture_provider_[consumer];
+ if (!gesture_provider) {
+ gesture_provider = CreateGestureProvider(this);
+ consumer_gesture_provider_[consumer] = gesture_provider;
+ }
+ return gesture_provider;
+}
+
void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
GestureConsumer* target) {
if (event.type() == ui::ET_TOUCH_RELEASED ||
@@ -197,7 +269,7 @@ void GestureRecognizerImpl::CancelTouches(
while (!touches->empty()) {
int touch_id = touches->begin()->first;
GestureConsumer* target = touches->begin()->second;
- TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0),
+ TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::PointF(0, 0),
ui::EF_IS_SYNTHESIZED, touch_id,
ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f);
GestureEventHelper* helper = FindDispatchHelperForConsumer(target);
@@ -207,23 +279,60 @@ void GestureRecognizerImpl::CancelTouches(
}
}
-GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture(
+void GestureRecognizerImpl::DispatchGestureEvent(GestureEvent* event) {
+ GestureConsumer* consumer = GetTargetForGestureEvent(*event);
+ if (consumer) {
+ GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
+ if (helper)
+ helper->DispatchGestureEvent(event);
+ }
+}
+
+ScopedVector<GestureEvent>* GestureRecognizerImpl::ProcessTouchEventForGesture(
const TouchEvent& event,
ui::EventResult result,
GestureConsumer* target) {
SetupTargets(event, target);
- GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
- return gesture_sequence->ProcessTouchEventForGesture(event, result);
+
+ if (!use_unified_gesture_detector_) {
+ GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target);
+ return gesture_sequence->ProcessTouchEventForGesture(event, result);
+ } else {
+ GestureProviderAura* gesture_provider =
+ GetGestureProviderForConsumer(target);
+ // TODO(tdresser) - detect gestures eagerly.
+ if (!(result & ER_CONSUMED)) {
+ if (gesture_provider->OnTouchEvent(event)) {
+ gesture_provider->OnTouchEventAck(result != ER_UNHANDLED);
+ return gesture_provider->GetAndResetPendingGestures();
+ }
+ }
+ return NULL;
+ }
}
-void GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
- if (consumer_sequence_.count(consumer)) {
- delete consumer_sequence_[consumer];
- consumer_sequence_.erase(consumer);
+bool GestureRecognizerImpl::CleanupStateForConsumer(
+ GestureConsumer* consumer) {
+ bool state_cleaned_up = false;
+
+ if (!use_unified_gesture_detector_) {
+ if (consumer_sequence_.count(consumer)) {
+ state_cleaned_up = true;
+ delete consumer_sequence_[consumer];
+ consumer_sequence_.erase(consumer);
+ }
+ } else {
+ if (consumer_gesture_provider_.count(consumer)) {
+ state_cleaned_up = true;
+ delete consumer_gesture_provider_[consumer];
+ consumer_gesture_provider_.erase(consumer);
+ }
}
- RemoveConsumerFromMap(consumer, &touch_id_target_);
- RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
+ state_cleaned_up |= RemoveConsumerFromMap(consumer, &touch_id_target_);
+ state_cleaned_up |=
+ RemoveConsumerFromMap(consumer, &touch_id_target_for_gestures_);
+ return state_cleaned_up;
}
void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
@@ -239,12 +348,11 @@ void GestureRecognizerImpl::RemoveGestureEventHelper(
}
void GestureRecognizerImpl::DispatchPostponedGestureEvent(GestureEvent* event) {
- GestureConsumer* consumer = GetTargetForGestureEvent(*event);
- if (consumer) {
- GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);
- if (helper)
- helper->DispatchPostponedGestureEvent(event);
- }
+ DispatchGestureEvent(event);
+}
+
+void GestureRecognizerImpl::OnGestureEvent(GestureEvent* event) {
+ DispatchGestureEvent(event);
}
GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
@@ -271,6 +379,12 @@ GestureRecognizer* GestureRecognizer::Get() {
return g_gesture_recognizer_instance;
}
+// GestureRecognizer, static
+void GestureRecognizer::Reset() {
+ delete g_gesture_recognizer_instance;
+ g_gesture_recognizer_instance = NULL;
+}
+
void SetGestureRecognizerForTesting(GestureRecognizer* gesture_recognizer) {
// Transfer helpers to the new GR.
std::vector<GestureEventHelper*>& helpers =
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl.h b/chromium/ui/events/gestures/gesture_recognizer_impl.h
index 59c92cfb4a4..80a3007030d 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl.h
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/events/event_constants.h"
#include "ui/events/events_export.h"
+#include "ui/events/gestures/gesture_provider_aura.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/gestures/gesture_sequence.h"
#include "ui/gfx/point.h"
@@ -23,8 +24,12 @@ class GestureEventHelper;
class GestureSequence;
class TouchEvent;
+// TODO(tdresser): Once the unified gesture recognition process sticks
+// (crbug.com/332418), GestureRecognizerImpl can be cleaned up
+// significantly.
class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
- public GestureSequenceDelegate {
+ public GestureSequenceDelegate,
+ public GestureProviderAuraClient {
public:
typedef std::map<int, GestureConsumer*> TouchIdToConsumerMap;
@@ -39,39 +44,49 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
virtual GestureConsumer* GetTargetForGestureEvent(
const GestureEvent& event) OVERRIDE;
virtual GestureConsumer* GetTargetForLocation(
- const gfx::Point& location) OVERRIDE;
+ const gfx::PointF& location, int source_device_id) OVERRIDE;
virtual void TransferEventsTo(GestureConsumer* current_consumer,
GestureConsumer* new_consumer) OVERRIDE;
virtual bool GetLastTouchPointForTarget(GestureConsumer* consumer,
- gfx::Point* point) OVERRIDE;
- virtual void CancelActiveTouches(GestureConsumer* consumer) OVERRIDE;
+ gfx::PointF* point) OVERRIDE;
+ virtual bool CancelActiveTouches(GestureConsumer* consumer) OVERRIDE;
protected:
- virtual GestureSequence* CreateSequence(GestureSequenceDelegate* delegate);
virtual GestureSequence* GetGestureSequenceForConsumer(GestureConsumer* c);
+ virtual GestureProviderAura* GetGestureProviderForConsumer(
+ GestureConsumer* c);
+ virtual GestureSequence* CreateSequence(
+ ui::GestureSequenceDelegate* delegate);
private:
// Sets up the target consumer for gestures based on the touch-event.
void SetupTargets(const TouchEvent& event, GestureConsumer* consumer);
void CancelTouches(std::vector<std::pair<int, GestureConsumer*> >* touches);
+ void DispatchGestureEvent(GestureEvent* event);
+
// Overridden from GestureRecognizer
virtual Gestures* ProcessTouchEventForGesture(
const TouchEvent& event,
ui::EventResult result,
GestureConsumer* target) OVERRIDE;
- virtual void CleanupStateForConsumer(GestureConsumer* consumer) OVERRIDE;
+ virtual bool CleanupStateForConsumer(GestureConsumer* consumer)
+ OVERRIDE;
virtual void AddGestureEventHelper(GestureEventHelper* helper) OVERRIDE;
virtual void RemoveGestureEventHelper(GestureEventHelper* helper) OVERRIDE;
// Overridden from ui::GestureSequenceDelegate.
virtual void DispatchPostponedGestureEvent(GestureEvent* event) OVERRIDE;
+ // Overridden from GestureProviderAuraClient
+ virtual void OnGestureEvent(GestureEvent* event) OVERRIDE;
+
// Convenience method to find the GestureEventHelper that can dispatch events
// to a specific |consumer|.
GestureEventHelper* FindDispatchHelperForConsumer(GestureConsumer* consumer);
std::map<GestureConsumer*, GestureSequence*> consumer_sequence_;
+ std::map<GestureConsumer*, GestureProviderAura*> consumer_gesture_provider_;
// Both |touch_id_target_| and |touch_id_target_for_gestures_| map a touch-id
// to its target window. touch-ids are removed from |touch_id_target_| on
@@ -82,6 +97,8 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
std::vector<GestureEventHelper*> helpers_;
+ bool use_unified_gesture_detector_;
+
DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImpl);
};
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc
new file mode 100644
index 00000000000..46dde02fad9
--- /dev/null
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc
@@ -0,0 +1,64 @@
+// 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 "base/macros.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+
+namespace ui {
+
+namespace {
+
+// Stub implementation of GestureRecognizer for Mac. Currently only serves to
+// provide a no-op implementation of TransferEventsTo().
+class GestureRecognizerImplMac : public GestureRecognizer {
+ public:
+ GestureRecognizerImplMac() {}
+ virtual ~GestureRecognizerImplMac() {}
+
+ private:
+ virtual Gestures* ProcessTouchEventForGesture(
+ const TouchEvent& event,
+ ui::EventResult result,
+ GestureConsumer* consumer) OVERRIDE {
+ return NULL;
+ }
+ virtual bool CleanupStateForConsumer(GestureConsumer* consumer) OVERRIDE {
+ return false;
+ }
+ virtual GestureConsumer* GetTouchLockedTarget(
+ const TouchEvent& event) OVERRIDE {
+ return NULL;
+ }
+ virtual GestureConsumer* GetTargetForGestureEvent(
+ const GestureEvent& event) OVERRIDE {
+ return NULL;
+ }
+ virtual GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
+ int source_device_id) OVERRIDE {
+ return NULL;
+ }
+ virtual void TransferEventsTo(GestureConsumer* current_consumer,
+ GestureConsumer* new_consumer) OVERRIDE {}
+ virtual bool GetLastTouchPointForTarget(GestureConsumer* consumer,
+ gfx::PointF* point) OVERRIDE {
+ return false;
+ }
+ virtual bool CancelActiveTouches(GestureConsumer* consumer) OVERRIDE {
+ return false;
+ }
+ virtual void AddGestureEventHelper(GestureEventHelper* helper) OVERRIDE {}
+ virtual void RemoveGestureEventHelper(GestureEventHelper* helper) OVERRIDE {}
+
+ DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImplMac);
+};
+
+} // namespace
+
+// static
+GestureRecognizer* GestureRecognizer::Get() {
+ CR_DEFINE_STATIC_LOCAL(GestureRecognizerImplMac, instance, ());
+ return &instance;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gestures/gesture_sequence.cc b/chromium/ui/events/gestures/gesture_sequence.cc
index 7c195199454..14824d0f676 100644
--- a/chromium/ui/events/gestures/gesture_sequence.cc
+++ b/chromium/ui/events/gestures/gesture_sequence.cc
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <cmath>
+#include <limits>
#include "base/command_line.h"
#include "base/logging.h"
@@ -16,7 +17,6 @@
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
#include "ui/events/gestures/gesture_configuration.h"
-#include "ui/events/gestures/gesture_util.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -29,7 +29,6 @@ enum TouchState {
TS_RELEASED,
TS_PRESSED,
TS_MOVED,
- TS_STATIONARY,
TS_CANCELLED,
TS_UNKNOWN,
};
@@ -60,8 +59,6 @@ TouchState TouchEventTypeToTouchState(ui::EventType type) {
return TS_PRESSED;
case ui::ET_TOUCH_MOVED:
return TS_MOVED;
- case ui::ET_TOUCH_STATIONARY:
- return TS_STATIONARY;
case ui::ET_TOUCH_CANCELLED:
return TS_CANCELLED;
default:
@@ -99,9 +96,6 @@ enum EdgeStateSignatureType {
GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED =
G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_MOVED, TSI_PROCESSED),
- GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY =
- G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_STATIONARY, TSI_NOT_PROCESSED),
-
GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED =
G(GS_PENDING_SYNTHETIC_CLICK, 0, TS_CANCELLED, TSI_ALWAYS),
@@ -120,21 +114,26 @@ enum EdgeStateSignatureType {
GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED =
G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_MOVED, TSI_ALWAYS),
- GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY =
- G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_STATIONARY, TSI_ALWAYS),
-
GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED =
G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 0, TS_CANCELLED, TSI_ALWAYS),
GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED =
G(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL, 1, TS_PRESSED, TSI_NOT_PROCESSED),
+ GST_SYNTHETIC_CLICK_ABORTED_FIRST_RELEASED =
+ G(GS_SYNTHETIC_CLICK_ABORTED, 0, TS_RELEASED, TSI_ALWAYS),
+
+ GST_SYNTHETIC_CLICK_ABORTED_SECOND_PRESSED =
+ G(GS_SYNTHETIC_CLICK_ABORTED, 1, TS_PRESSED, TSI_NOT_PROCESSED),
+
GST_SCROLL_FIRST_RELEASED =
G(GS_SCROLL, 0, TS_RELEASED, TSI_ALWAYS),
- // Once scroll has started, process all touch-move events.
GST_SCROLL_FIRST_MOVED =
- G(GS_SCROLL, 0, TS_MOVED, TSI_ALWAYS),
+ G(GS_SCROLL, 0, TS_MOVED, TSI_NOT_PROCESSED),
+
+ GST_SCROLL_FIRST_MOVED_HANDLED =
+ G(GS_SCROLL, 0, TS_MOVED, TSI_PROCESSED),
GST_SCROLL_FIRST_CANCELLED =
G(GS_SCROLL, 0, TS_CANCELLED, TSI_ALWAYS),
@@ -333,17 +332,18 @@ EdgeStateSignatureType Signature(GestureState gesture_state,
case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED_HANDLED:
case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED:
case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED:
- case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY:
case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED:
case GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED:
case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED:
case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED:
case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED:
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY:
case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED:
case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED:
+ case GST_SYNTHETIC_CLICK_ABORTED_FIRST_RELEASED:
+ case GST_SYNTHETIC_CLICK_ABORTED_SECOND_PRESSED:
case GST_SCROLL_FIRST_RELEASED:
case GST_SCROLL_FIRST_MOVED:
+ case GST_SCROLL_FIRST_MOVED_HANDLED:
case GST_SCROLL_FIRST_CANCELLED:
case GST_SCROLL_SECOND_PRESSED:
case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED:
@@ -412,7 +412,7 @@ EdgeStateSignatureType Signature(GestureState gesture_state,
}
#undef G
-float BoundingBoxDiagonal(const gfx::Rect& rect) {
+float BoundingBoxDiagonal(const gfx::RectF& rect) {
float width = rect.width() * rect.width();
float height = rect.height() * rect.height();
return sqrt(width + height);
@@ -449,28 +449,28 @@ float CalibrateFlingVelocity(float velocity) {
void UpdateGestureEventLatencyInfo(const TouchEvent& event,
GestureSequence::Gestures* gestures) {
- // If the touch event does not cause any rendering scheduled, we first
- // end the touch event's LatencyInfo. Then we copy the touch event's
- // LatencyInfo into the generated gesture's LatencyInfo. Since one touch
- // event can generate multiple gesture events, we have to clear the gesture
- // event's trace_id, remove its ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- // so when the gesture event passes through RWHI, a new trace_id will be
- // assigned and new ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT will be added.
- if (!event.latency()->FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, NULL)) {
- ui::LatencyInfo* touch_latency =
- const_cast<ui::LatencyInfo*>(event.latency());
- touch_latency->AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, 0);
- GestureSequence::Gestures::iterator it = gestures->begin();
- for (; it != gestures->end(); it++) {
- ui::LatencyInfo* gesture_latency = (*it)->latency();
- *gesture_latency = *touch_latency;
- gesture_latency->trace_id = -1;
- gesture_latency->terminated = false;
- gesture_latency->RemoveLatency(
- ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
- }
+ // Copy some of the touch event's LatencyInfo into the generated gesture's
+ // LatencyInfo so we can compute touch to scroll latency from gesture
+ // event's LatencyInfo.
+ GestureSequence::Gestures::iterator it = gestures->begin();
+ for (; it != gestures->end(); it++) {
+ ui::LatencyInfo* gesture_latency = (*it)->latency();
+ gesture_latency->CopyLatencyFrom(
+ *event.latency(), ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
+ gesture_latency->CopyLatencyFrom(
+ *event.latency(), ui::INPUT_EVENT_LATENCY_UI_COMPONENT);
+ gesture_latency->CopyLatencyFrom(
+ *event.latency(), ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT);
+ }
+}
+
+bool GestureStateSupportsActiveTimer(GestureState state) {
+ switch(state) {
+ case GS_PENDING_SYNTHETIC_CLICK:
+ case GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL:
+ return true;
+ default:
+ return false;
}
}
@@ -520,6 +520,7 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
}
new_point->set_point_id(point_count_++);
new_point->set_touch_id(event.touch_id());
+ new_point->set_source_device_id(event.source_device_id());
}
GestureState last_state = state_;
@@ -556,6 +557,7 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
set_state(GS_PENDING_SYNTHETIC_CLICK);
break;
case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED:
+ case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED:
if (Click(event, point, gestures.get()))
point.UpdateForTap();
else
@@ -563,39 +565,41 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
set_state(GS_NO_GESTURE);
break;
case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED:
- case GST_PENDING_SYNTHETIC_CLICK_FIRST_STATIONARY:
if (ScrollStart(event, point, gestures.get())) {
PrependTapCancelGestureEvent(point, gestures.get());
set_state(GS_SCROLL);
- if (ScrollUpdate(event, point, gestures.get()))
+ if (ScrollUpdate(event, point, gestures.get(), FS_FIRST_SCROLL))
point.UpdateForScroll();
}
break;
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED:
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_STATIONARY:
- // No scrolling allowed, so nothing happens.
- break;
case GST_PENDING_SYNTHETIC_CLICK_FIRST_MOVED_PROCESSED:
+ case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_MOVED:
if (point.IsInScrollWindow(event)) {
PrependTapCancelGestureEvent(point, gestures.get());
+ set_state(GS_SYNTHETIC_CLICK_ABORTED);
+ } else {
set_state(GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL);
}
break;
case GST_PENDING_SYNTHETIC_CLICK_FIRST_RELEASED_HANDLED:
case GST_PENDING_SYNTHETIC_CLICK_FIRST_CANCELLED:
+ case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED:
+ case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED:
PrependTapCancelGestureEvent(point, gestures.get());
set_state(GS_NO_GESTURE);
break;
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED:
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_RELEASED_HANDLED:
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_FIRST_CANCELLED:
+ case GST_SYNTHETIC_CLICK_ABORTED_FIRST_RELEASED:
set_state(GS_NO_GESTURE);
break;
case GST_SCROLL_FIRST_MOVED:
if (scroll_type_ == ST_VERTICAL ||
scroll_type_ == ST_HORIZONTAL)
BreakRailScroll(event, point, gestures.get());
- if (ScrollUpdate(event, point, gestures.get()))
+ if (ScrollUpdate(event, point, gestures.get(), FS_NOT_FIRST_SCROLL))
+ point.UpdateForScroll();
+ break;
+ case GST_SCROLL_FIRST_MOVED_HANDLED:
+ if (point.DidScroll(event, 0))
point.UpdateForScroll();
break;
case GST_SCROLL_FIRST_RELEASED:
@@ -604,10 +608,11 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
set_state(GS_NO_GESTURE);
break;
case GST_PENDING_SYNTHETIC_CLICK_SECOND_PRESSED:
+ case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED:
PrependTapCancelGestureEvent(point, gestures.get());
TwoFingerTapOrPinch(event, point, gestures.get());
break;
- case GST_PENDING_SYNTHETIC_CLICK_NO_SCROLL_SECOND_PRESSED:
+ case GST_SYNTHETIC_CLICK_ABORTED_SECOND_PRESSED:
TwoFingerTapOrPinch(event, point, gestures.get());
break;
case GST_SCROLL_SECOND_PRESSED:
@@ -617,7 +622,7 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
case GST_PENDING_TWO_FINGER_TAP_FIRST_RELEASED:
case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED:
TwoFingerTouchReleased(event, point, gestures.get());
- set_state(GS_SCROLL);
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PENDING_TWO_FINGER_TAP_FIRST_MOVED:
case GST_PENDING_TWO_FINGER_TAP_SECOND_MOVED:
@@ -632,8 +637,7 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
case GST_PENDING_TWO_FINGER_TAP_SECOND_RELEASED_HANDLED:
case GST_PENDING_TWO_FINGER_TAP_FIRST_CANCELLED:
case GST_PENDING_TWO_FINGER_TAP_SECOND_CANCELLED:
- scroll_type_ = ST_FREE;
- set_state(GS_SCROLL);
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PENDING_TWO_FINGER_TAP_THIRD_PRESSED:
set_state(GS_PENDING_PINCH);
@@ -645,18 +649,17 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED:
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED:
TwoFingerTouchReleased(event, point, gestures.get());
- // We transit into GS_SCROLL even though the touch move can be
- // consumed and no scroll should happen. crbug.com/240399.
- set_state(GS_SCROLL);
+ // We transition into GS_SCROLL even though the touch move can be consumed
+ // and no scroll should happen. crbug.com/240399.
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_RELEASED_HANDLED:
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_RELEASED_HANDLED:
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_FIRST_CANCELLED:
case GST_PENDING_TWO_FINGER_TAP_NO_PINCH_SECOND_CANCELLED:
- // We transit into GS_SCROLL even though the touch move can be
- // consumed and no scroll should happen. crbug.com/240399.
- scroll_type_ = ST_FREE;
- set_state(GS_SCROLL);
+ // We transition into GS_SCROLL even though the touch move can be consumed
+ // and no scroll should happen. crbug.com/240399.
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PENDING_PINCH_FIRST_MOVED:
case GST_PENDING_PINCH_SECOND_MOVED:
@@ -671,10 +674,9 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
case GST_PENDING_PINCH_SECOND_RELEASED:
case GST_PENDING_PINCH_FIRST_CANCELLED:
case GST_PENDING_PINCH_SECOND_CANCELLED:
- // We transit into GS_SCROLL even though the touch move can be
- // consumed and no scroll should happen. crbug.com/240399.
- scroll_type_ = ST_FREE;
- set_state(GS_SCROLL);
+ // We transition into GS_SCROLL even though the touch move can be consumed
+ // and no scroll should happen. crbug.com/240399.
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PENDING_PINCH_NO_PINCH_FIRST_MOVED:
case GST_PENDING_PINCH_NO_PINCH_SECOND_MOVED:
@@ -684,16 +686,19 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
case GST_PENDING_PINCH_NO_PINCH_SECOND_RELEASED:
case GST_PENDING_PINCH_NO_PINCH_FIRST_CANCELLED:
case GST_PENDING_PINCH_NO_PINCH_SECOND_CANCELLED:
- // We transit into GS_SCROLL even though the touch move can be
- // consumed and no scroll should happen. crbug.com/240399.
- scroll_type_ = ST_FREE;
- set_state(GS_SCROLL);
+ // We transition into GS_SCROLL even though the touch move can be consumed
+ // and no scroll should happen. crbug.com/240399.
+ StartRailFreeScroll(point, gestures.get());
break;
case GST_PINCH_FIRST_MOVED_HANDLED:
case GST_PINCH_SECOND_MOVED_HANDLED:
case GST_PINCH_THIRD_MOVED_HANDLED:
case GST_PINCH_FOURTH_MOVED_HANDLED:
case GST_PINCH_FIFTH_MOVED_HANDLED:
+ // If touches are consumed for a while, and then left unconsumed, we don't
+ // want a PinchUpdate or ScrollUpdate with a massive delta.
+ latest_multi_scroll_update_location_ = bounding_box_.CenterPoint();
+ pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_);
break;
case GST_PINCH_FIRST_MOVED:
case GST_PINCH_SECOND_MOVED:
@@ -750,7 +755,10 @@ GestureSequence::Gestures* GestureSequence::ProcessTouchEventForGesture(
<< " State: " << state_
<< " touch id: " << event.touch_id();
- if (last_state == GS_PENDING_SYNTHETIC_CLICK && state_ != last_state) {
+ // If the state has changed from one in which a long/show press is possible to
+ // one in which they are not possible, cancel the timers.
+ if (GestureStateSupportsActiveTimer(last_state) &&
+ !GestureStateSupportsActiveTimer(state_)) {
GetLongPressTimer()->Stop();
GetShowPressTimer()->Stop();
}
@@ -789,8 +797,10 @@ void GestureSequence::RecreateBoundingBox() {
} else if (point_count_ == 1) {
bounding_box_ = GetPointByPointId(0)->enclosing_rectangle();
} else {
- int left = INT_MAX / 20, top = INT_MAX / 20;
- int right = INT_MIN / 20, bottom = INT_MIN / 20;
+ float left = std::numeric_limits<float>::max();
+ float top = std::numeric_limits<float>::max();
+ float right = -std::numeric_limits<float>::max();
+ float bottom = -std::numeric_limits<float>::max();
for (int i = 0; i < kMaxGesturePoints; ++i) {
if (!points_[i].in_use())
continue;
@@ -798,7 +808,7 @@ void GestureSequence::RecreateBoundingBox() {
// However, this becomes brittle especially when a finger is in motion
// because the change in radius can overshadow the actual change in
// position. So the actual position of the point is used instead.
- const gfx::Point& point = points_[i].last_touch_position();
+ const gfx::PointF& point = points_[i].last_touch_position();
left = std::min(left, point.x());
right = std::max(right, point.x());
top = std::min(top, point.y());
@@ -854,8 +864,8 @@ GesturePoint* GestureSequence::GetPointByPointId(int point_id) {
}
bool GestureSequence::IsSecondTouchDownCloseEnoughForTwoFingerTap() {
- gfx::Point p1 = GetPointByPointId(0)->last_touch_position();
- gfx::Point p2 = GetPointByPointId(1)->last_touch_position();
+ gfx::PointF p1 = GetPointByPointId(0)->last_touch_position();
+ gfx::PointF p2 = GetPointByPointId(1)->last_touch_position();
double max_distance =
GestureConfiguration::max_distance_for_two_finger_tap_in_pixels();
double distance = (p1.x() - p2.x()) * (p1.x() - p2.x()) +
@@ -867,7 +877,7 @@ bool GestureSequence::IsSecondTouchDownCloseEnoughForTwoFingerTap() {
GestureEvent* GestureSequence::CreateGestureEvent(
const GestureEventDetails& details,
- const gfx::Point& location,
+ const gfx::PointF& location,
int flags,
base::Time timestamp,
unsigned int touch_id_bitmask) {
@@ -915,7 +925,7 @@ void GestureSequence::AppendEndGestureEvent(const GesturePoint& point,
Gestures* gestures) {
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_END, 0, 0),
- point.first_touch_position(),
+ point.last_touch_position(),
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
1 << point.touch_id()));
@@ -924,8 +934,8 @@ void GestureSequence::AppendEndGestureEvent(const GesturePoint& point,
void GestureSequence::AppendClickGestureEvent(const GesturePoint& point,
int tap_count,
Gestures* gestures) {
- gfx::Rect er = point.enclosing_rectangle();
- gfx::Point center = er.CenterPoint();
+ gfx::RectF er = point.enclosing_rectangle();
+ gfx::PointF center = er.CenterPoint();
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_TAP, tap_count, 0),
center,
@@ -935,10 +945,11 @@ void GestureSequence::AppendClickGestureEvent(const GesturePoint& point,
}
void GestureSequence::AppendScrollGestureBegin(const GesturePoint& point,
- const gfx::Point& location,
+ const gfx::PointF& location,
Gestures* gestures) {
+ gfx::Vector2dF d = point.ScrollDelta();
gestures->push_back(CreateGestureEvent(
- GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
+ GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, d.x(), d.y()),
location,
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
@@ -946,7 +957,7 @@ void GestureSequence::AppendScrollGestureBegin(const GesturePoint& point,
}
void GestureSequence::AppendScrollGestureEnd(const GesturePoint& point,
- const gfx::Point& location,
+ const gfx::PointF& location,
Gestures* gestures,
float x_velocity,
float y_velocity) {
@@ -965,9 +976,7 @@ void GestureSequence::AppendScrollGestureEnd(const GesturePoint& point,
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_SCROLL_FLING_START,
CalibrateFlingVelocity(railed_x_velocity),
- CalibrateFlingVelocity(railed_y_velocity),
- CalibrateFlingVelocity(x_velocity),
- CalibrateFlingVelocity(y_velocity)),
+ CalibrateFlingVelocity(railed_y_velocity)),
location,
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
@@ -983,11 +992,12 @@ void GestureSequence::AppendScrollGestureEnd(const GesturePoint& point,
}
void GestureSequence::AppendScrollGestureUpdate(GesturePoint& point,
- Gestures* gestures) {
+ Gestures* gestures,
+ IsFirstScroll is_first_scroll) {
static bool use_scroll_prediction = CommandLine::ForCurrentProcess()->
HasSwitch(switches::kEnableScrollPrediction);
gfx::Vector2dF d;
- gfx::Point location;
+ gfx::PointF location;
if (point_count_ == 1) {
d = point.ScrollDelta();
location = point.last_touch_position();
@@ -1006,11 +1016,18 @@ void GestureSequence::AppendScrollGestureUpdate(GesturePoint& point,
last_scroll_prediction_offset_.set_y(
GestureConfiguration::scroll_prediction_seconds() * point.YVelocity());
d += last_scroll_prediction_offset_;
- location += gfx::Vector2d(last_scroll_prediction_offset_.x(),
- last_scroll_prediction_offset_.y());
+ location += gfx::Vector2dF(last_scroll_prediction_offset_.x(),
+ last_scroll_prediction_offset_.y());
}
- gfx::Vector2dF o = d;
+ if (is_first_scroll == FS_FIRST_SCROLL) {
+ float slop = GestureConfiguration::max_touch_move_in_pixels_for_click();
+ float length = d.Length();
+ float ratio = std::max((length - slop) / length, 0.0f);
+
+ d.set_x(d.x() * ratio);
+ d.set_y(d.y() * ratio);
+ }
if (scroll_type_ == ST_HORIZONTAL)
d.set_y(0);
@@ -1019,13 +1036,7 @@ void GestureSequence::AppendScrollGestureUpdate(GesturePoint& point,
if (d.IsZero())
return;
- GestureEventDetails details(ui::ET_GESTURE_SCROLL_UPDATE,
- d.x(), d.y(), o.x(), o.y());
- details.SetScrollVelocity(
- scroll_type_ == ST_VERTICAL ? 0 : point.XVelocity(),
- scroll_type_ == ST_HORIZONTAL ? 0 : point.YVelocity(),
- point.XVelocity(),
- point.YVelocity());
+ GestureEventDetails details(ui::ET_GESTURE_SCROLL_UPDATE, d.x(), d.y());
gestures->push_back(CreateGestureEvent(
details,
location,
@@ -1037,7 +1048,7 @@ void GestureSequence::AppendScrollGestureUpdate(GesturePoint& point,
void GestureSequence::AppendPinchGestureBegin(const GesturePoint& p1,
const GesturePoint& p2,
Gestures* gestures) {
- gfx::Point center = bounding_box_.CenterPoint();
+ gfx::PointF center = bounding_box_.CenterPoint();
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_PINCH_BEGIN, 0, 0),
center,
@@ -1050,7 +1061,7 @@ void GestureSequence::AppendPinchGestureEnd(const GesturePoint& p1,
const GesturePoint& p2,
float scale,
Gestures* gestures) {
- gfx::Point center = bounding_box_.CenterPoint();
+ gfx::PointF center = bounding_box_.CenterPoint();
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_PINCH_END, 0, 0),
center,
@@ -1077,7 +1088,7 @@ void GestureSequence::AppendSwipeGesture(const GesturePoint& point,
int swipe_y,
Gestures* gestures) {
gestures->push_back(CreateGestureEvent(
- GestureEventDetails(ui::ET_GESTURE_MULTIFINGER_SWIPE, swipe_x, swipe_y),
+ GestureEventDetails(ui::ET_GESTURE_SWIPE, swipe_x, swipe_y),
bounding_box_.CenterPoint(),
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
@@ -1086,7 +1097,7 @@ void GestureSequence::AppendSwipeGesture(const GesturePoint& point,
void GestureSequence::AppendTwoFingerTapGestureEvent(Gestures* gestures) {
const GesturePoint* point = GetPointByPointId(0);
- const gfx::Rect rect = point->enclosing_rectangle();
+ const gfx::RectF& rect = point->enclosing_rectangle();
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_TWO_FINGER_TAP,
rect.width(),
@@ -1100,7 +1111,8 @@ void GestureSequence::AppendTwoFingerTapGestureEvent(Gestures* gestures) {
bool GestureSequence::Click(const TouchEvent& event,
const GesturePoint& point,
Gestures* gestures) {
- DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK);
+ DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK ||
+ state_ == GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL);
if (point.IsInClickWindow(event)) {
int tap_count = 1;
if (point.IsInTripleClickWindow(event))
@@ -1113,7 +1125,7 @@ bool GestureSequence::Click(const TouchEvent& event,
}
AppendClickGestureEvent(point, tap_count, gestures);
return true;
- } else if (point.IsInsideManhattanSquare(event) &&
+ } else if (point.IsInsideTouchSlopRegion(event) &&
!GetLongPressTimer()->IsRunning()) {
AppendLongTapGestureEvent(point, gestures);
}
@@ -1150,11 +1162,12 @@ void GestureSequence::BreakRailScroll(const TouchEvent& event,
bool GestureSequence::ScrollUpdate(const TouchEvent& event,
GesturePoint& point,
- Gestures* gestures) {
+ Gestures* gestures,
+ IsFirstScroll is_first_scroll) {
DCHECK(state_ == GS_SCROLL);
if (!point.DidScroll(event, 0))
return false;
- AppendScrollGestureUpdate(point, gestures);
+ AppendScrollGestureUpdate(point, gestures, is_first_scroll);
return true;
}
@@ -1185,11 +1198,13 @@ bool GestureSequence::TwoFingerTouchDown(const TouchEvent& event,
Gestures* gestures) {
DCHECK(state_ == GS_PENDING_SYNTHETIC_CLICK ||
state_ == GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL ||
+ state_ == GS_SYNTHETIC_CLICK_ABORTED ||
state_ == GS_SCROLL);
if (state_ == GS_SCROLL) {
- AppendScrollGestureEnd(point, point.last_touch_position(), gestures,
- 0.f, 0.f);
+ AppendScrollGestureEnd(point,
+ point.last_touch_position(),
+ gestures, 0.f, 0.f);
}
second_touch_time_ = event.time_stamp();
return true;
@@ -1204,7 +1219,7 @@ bool GestureSequence::TwoFingerTouchMove(const TouchEvent& event,
base::TimeDelta time_delta = event.time_stamp() - second_touch_time_;
base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click());
- if (time_delta > max_delta || !point.IsInsideManhattanSquare(event)) {
+ if (time_delta > max_delta || !point.IsInsideTouchSlopRegion(event)) {
PinchStart(event, point, gestures);
return true;
}
@@ -1219,7 +1234,7 @@ bool GestureSequence::TwoFingerTouchReleased(const TouchEvent& event,
base::TimeDelta time_delta = event.time_stamp() - second_touch_time_;
base::TimeDelta max_delta = base::TimeDelta::FromMilliseconds(1000 *
ui::GestureConfiguration::max_touch_down_duration_in_seconds_for_click());
- if (time_delta < max_delta && point.IsInsideManhattanSquare(event))
+ if (time_delta < max_delta && point.IsInsideTouchSlopRegion(event))
AppendTwoFingerTapGestureEvent(gestures);
return true;
}
@@ -1248,11 +1263,9 @@ void GestureSequence::AppendShowPressGestureEvent() {
void GestureSequence::AppendLongTapGestureEvent(const GesturePoint& point,
Gestures* gestures) {
- gfx::Rect er = point.enclosing_rectangle();
- gfx::Point center = er.CenterPoint();
gestures->push_back(CreateGestureEvent(
GestureEventDetails(ui::ET_GESTURE_LONG_TAP, 0, 0),
- center,
+ point.enclosing_rectangle().CenterPoint(),
flags_,
base::Time::FromDoubleT(point.last_touch_time()),
1 << point.touch_id()));
@@ -1263,11 +1276,14 @@ bool GestureSequence::ScrollEnd(const TouchEvent& event,
Gestures* gestures) {
DCHECK(state_ == GS_SCROLL);
if (point.IsInFlickWindow(event)) {
- AppendScrollGestureEnd(point, point.last_touch_position(), gestures,
- point.XVelocity(), point.YVelocity());
+ AppendScrollGestureEnd(point,
+ point.last_touch_position(),
+ gestures,
+ point.XVelocity(), point.YVelocity());
} else {
- AppendScrollGestureEnd(point, point.last_touch_position(), gestures,
- 0.f, 0.f);
+ AppendScrollGestureEnd(point,
+ point.last_touch_position(),
+ gestures, 0.f, 0.f);
}
return true;
}
@@ -1285,17 +1301,16 @@ bool GestureSequence::PinchStart(const TouchEvent& event,
const GesturePoint* point1 = GetPointByPointId(0);
const GesturePoint* point2 = GetPointByPointId(1);
+ if (state_ == GS_PENDING_TWO_FINGER_TAP ||
+ state_ == GS_PENDING_PINCH) {
+ AppendScrollGestureBegin(point, bounding_box_.CenterPoint(), gestures);
+ }
+
pinch_distance_current_ = BoundingBoxDiagonal(bounding_box_);
pinch_distance_start_ = pinch_distance_current_;
latest_multi_scroll_update_location_ = bounding_box_.CenterPoint();
AppendPinchGestureBegin(*point1, *point2, gestures);
- if (state_ == GS_PENDING_TWO_FINGER_TAP ||
- state_ == GS_PENDING_PINCH) {
- gfx::Point center = bounding_box_.CenterPoint();
- AppendScrollGestureBegin(point, center, gestures);
- }
-
return true;
}
@@ -1322,13 +1337,13 @@ bool GestureSequence::PinchUpdate(const TouchEvent& event,
float distance = BoundingBoxDiagonal(bounding_box_);
- if (abs(distance - pinch_distance_current_) >=
+ if (std::abs(distance - pinch_distance_current_) >=
GestureConfiguration::min_pinch_update_distance_in_pixels()) {
AppendPinchGestureUpdate(point,
distance / pinch_distance_current_, gestures);
pinch_distance_current_ = distance;
}
- AppendScrollGestureUpdate(point, gestures);
+ AppendScrollGestureUpdate(point, gestures, FS_NOT_FIRST_SCROLL);
return true;
}
@@ -1385,7 +1400,6 @@ bool GestureSequence::MaybeSwipe(const TouchEvent& event,
}
float min_velocity = GestureConfiguration::min_swipe_speed();
- min_velocity *= min_velocity;
velocity_x = fabs(velocity_x / point_count_);
velocity_y = fabs(velocity_y / point_count_);
@@ -1437,11 +1451,17 @@ void GestureSequence::StopTimersIfRequired(const TouchEvent& event) {
// Since a timer is running, there should be a non-NULL point.
const GesturePoint* point = GetPointByPointId(0);
- if (!ui::gestures::IsInsideManhattanSquare(point->first_touch_position(),
- event.location())) {
+ if (!point->IsInsideTouchSlopRegion(event)) {
GetLongPressTimer()->Stop();
GetShowPressTimer()->Stop();
}
}
+void GestureSequence::StartRailFreeScroll(const GesturePoint& point,
+ Gestures* gestures) {
+ AppendScrollGestureBegin(point, point.first_touch_position(), gestures);
+ scroll_type_ = ST_FREE;
+ set_state(GS_SCROLL);
+}
+
} // namespace ui
diff --git a/chromium/ui/events/gestures/gesture_sequence.h b/chromium/ui/events/gestures/gesture_sequence.h
index b3255df573c..62676e940ae 100644
--- a/chromium/ui/events/gestures/gesture_sequence.h
+++ b/chromium/ui/events/gestures/gesture_sequence.h
@@ -7,6 +7,7 @@
#include "base/timer/timer.h"
#include "ui/events/event_constants.h"
+#include "ui/events/gesture_event_details.h"
#include "ui/events/gestures/gesture_point.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/rect.h"
@@ -19,7 +20,12 @@ class GestureEvent;
enum GestureState {
GS_NO_GESTURE,
GS_PENDING_SYNTHETIC_CLICK,
+ // One finger is down: tap could occur, but scroll cannot until the number of
+ // active touch points changes.
GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL,
+ // One finger is down: no gestures can occur until the number of active touch
+ // points changes.
+ GS_SYNTHETIC_CLICK_ABORTED,
GS_SCROLL,
GS_PINCH,
GS_PENDING_TWO_FINGER_TAP,
@@ -34,6 +40,11 @@ enum ScrollType {
ST_VERTICAL,
};
+enum IsFirstScroll {
+ FS_FIRST_SCROLL,
+ FS_NOT_FIRST_SCROLL,
+};
+
// Delegates dispatch of gesture events for which the GestureSequence does not
// have enough context to dispatch itself.
class EVENTS_EXPORT GestureSequenceDelegate {
@@ -64,7 +75,9 @@ class EVENTS_EXPORT GestureSequence {
const GesturePoint* points() const { return points_; }
int point_count() const { return point_count_; }
- const gfx::Point& last_touch_location() const { return last_touch_location_; }
+ const gfx::PointF& last_touch_location() const {
+ return last_touch_location_;
+ }
protected:
virtual base::OneShotTimer<GestureSequence>* CreateTimer();
@@ -90,7 +103,7 @@ class EVENTS_EXPORT GestureSequence {
// includes some common information (e.g. number of touch-points in the
// gesture etc.) in the gesture event as well.
GestureEvent* CreateGestureEvent(const GestureEventDetails& details,
- const gfx::Point& location,
+ const gfx::PointF& location,
int flags,
base::Time timestamp,
unsigned int touch_id_bitmask);
@@ -115,15 +128,16 @@ class EVENTS_EXPORT GestureSequence {
// Scroll gestures.
void AppendScrollGestureBegin(const GesturePoint& point,
- const gfx::Point& location,
+ const gfx::PointF& location,
Gestures* gestures);
void AppendScrollGestureEnd(const GesturePoint& point,
- const gfx::Point& location,
+ const gfx::PointF& location,
Gestures* gestures,
float x_velocity,
float y_velocity);
void AppendScrollGestureUpdate(GesturePoint& point,
- Gestures* gestures);
+ Gestures* gestures,
+ IsFirstScroll is_first_scroll);
// Pinch gestures.
void AppendPinchGestureBegin(const GesturePoint& p1,
@@ -158,7 +172,8 @@ class EVENTS_EXPORT GestureSequence {
Gestures* gestures);
bool ScrollUpdate(const TouchEvent& event,
GesturePoint& point,
- Gestures* gestures);
+ Gestures* gestures,
+ IsFirstScroll is_first_scroll);
bool TouchDown(const TouchEvent& event,
const GesturePoint& point,
Gestures* gestures);
@@ -193,6 +208,8 @@ class EVENTS_EXPORT GestureSequence {
void StopTimersIfRequired(const TouchEvent& event);
+ void StartRailFreeScroll(const GesturePoint& point, Gestures* gestures);
+
// Current state of gesture recognizer.
GestureState state_;
@@ -201,11 +218,11 @@ class EVENTS_EXPORT GestureSequence {
// We maintain the smallest axis-aligned rectangle that contains all the
// current touch-points. This box is updated after every touch-event.
- gfx::Rect bounding_box_;
+ gfx::RectF bounding_box_;
// The center of the bounding box used in the latest multi-finger scroll
// update gesture.
- gfx::Point latest_multi_scroll_update_location_;
+ gfx::PointF latest_multi_scroll_update_location_;
// The last scroll update prediction offset. This is removed from the scroll
// distance on the next update since the page has already been scrolled this
@@ -233,7 +250,7 @@ class EVENTS_EXPORT GestureSequence {
int point_count_;
// Location of the last touch event.
- gfx::Point last_touch_location_;
+ gfx::PointF last_touch_location_;
GestureSequenceDelegate* delegate_;
diff --git a/chromium/ui/events/gestures/gesture_types.cc b/chromium/ui/events/gestures/gesture_types.cc
deleted file mode 100644
index da91bd07db0..00000000000
--- a/chromium/ui/events/gestures/gesture_types.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/gestures/gesture_types.h"
-
-namespace ui {
-
-GestureEventDetails::GestureEventDetails(ui::EventType type,
- float delta_x,
- float delta_y)
- : type_(type),
- touch_points_(1) {
- switch (type_) {
- case ui::ET_GESTURE_SCROLL_UPDATE:
- data.scroll_update.x = delta_x;
- data.scroll_update.y = delta_y;
- data.scroll_update.x_ordinal = delta_x;
- data.scroll_update.y_ordinal = delta_y;
- break;
-
- case ui::ET_SCROLL_FLING_START:
- data.fling_velocity.x = delta_x;
- data.fling_velocity.y = delta_y;
- data.fling_velocity.x_ordinal = delta_x;
- data.fling_velocity.y_ordinal = delta_y;
- break;
-
- case ui::ET_GESTURE_LONG_PRESS:
- data.touch_id = static_cast<int>(delta_x);
- CHECK_EQ(0.f, delta_y) << "Unknown data in delta_y for long press.";
- break;
-
- case ui::ET_GESTURE_TWO_FINGER_TAP:
- data.first_finger_enclosing_rectangle.width = delta_x;
- data.first_finger_enclosing_rectangle.height = delta_y;
- break;
-
- case ui::ET_GESTURE_PINCH_UPDATE:
- data.scale = delta_x;
- CHECK_EQ(0.f, delta_y) << "Unknown data in delta_y for pinch";
- break;
-
- case ui::ET_GESTURE_MULTIFINGER_SWIPE:
- data.swipe.left = delta_x < 0;
- data.swipe.right = delta_x > 0;
- data.swipe.up = delta_y < 0;
- data.swipe.down = delta_y > 0;
- break;
-
- case ui::ET_GESTURE_TAP:
- data.tap_count = static_cast<int>(delta_x);
- CHECK_EQ(0.f, delta_y) << "Unknown data in delta_y for tap.";
- break;
-
- default:
- if (delta_x != 0.f || delta_y != 0.f) {
- DLOG(WARNING) << "A gesture event (" << type << ") had unknown data: ("
- << delta_x << "," << delta_y;
- }
- break;
- }
-}
-
-GestureEventDetails::GestureEventDetails(ui::EventType type,
- float delta_x,
- float delta_y,
- float delta_x_ordinal,
- float delta_y_ordinal)
- : type_(type),
- touch_points_(1) {
- CHECK(type == ui::ET_GESTURE_SCROLL_UPDATE ||
- type == ui::ET_SCROLL_FLING_START);
- switch (type_) {
- case ui::ET_GESTURE_SCROLL_UPDATE:
- data.scroll_update.x = delta_x;
- data.scroll_update.y = delta_y;
- data.scroll_update.x_ordinal = delta_x_ordinal;
- data.scroll_update.y_ordinal = delta_y_ordinal;
- break;
-
- case ui::ET_SCROLL_FLING_START:
- data.fling_velocity.x = delta_x;
- data.fling_velocity.y = delta_y;
- data.fling_velocity.x_ordinal = delta_x_ordinal;
- data.fling_velocity.y_ordinal = delta_y_ordinal;
- break;
-
- default:
- break;
- }
-}
-
-void GestureEventDetails::SetScrollVelocity(float velocity_x,
- float velocity_y,
- float velocity_x_ordinal,
- float velocity_y_ordinal) {
- CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, type_);
- data.scroll_update.velocity_x = velocity_x;
- data.scroll_update.velocity_y = velocity_y;
- data.scroll_update.velocity_x_ordinal = velocity_x_ordinal;
- data.scroll_update.velocity_y_ordinal = velocity_y_ordinal;
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/gestures/gesture_types.h b/chromium/ui/events/gestures/gesture_types.h
index b0670fe8f6d..c15a2fdca47 100644
--- a/chromium/ui/events/gestures/gesture_types.h
+++ b/chromium/ui/events/gestures/gesture_types.h
@@ -5,178 +5,13 @@
#ifndef UI_EVENTS_GESTURES_GESTURE_TYPES_H_
#define UI_EVENTS_GESTURES_GESTURE_TYPES_H_
-#include "base/logging.h"
-#include "ui/events/event_constants.h"
#include "ui/events/events_export.h"
-#include "ui/gfx/rect.h"
namespace ui {
class GestureEvent;
class TouchEvent;
-struct EVENTS_EXPORT GestureEventDetails {
- public:
- GestureEventDetails(EventType type, float delta_x, float delta_y);
- GestureEventDetails(EventType type,
- float delta_x, float delta_y,
- float delta_x_ordinal, float delta_y_ordinal);
-
- EventType type() const { return type_; }
-
- int touch_points() const { return touch_points_; }
- void set_touch_points(int touch_points) { touch_points_ = touch_points; }
-
- const gfx::Rect& bounding_box() const { return bounding_box_; }
- void set_bounding_box(const gfx::Rect& box) { bounding_box_ = box; }
-
- void SetScrollVelocity(float velocity_x, float velocity_y,
- float velocity_x_ordinal, float velocity_y_ordinal);
-
- float scroll_x() const {
- CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, type_);
- return data.scroll_update.x;
- }
-
- float scroll_y() const {
- CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, type_);
- return data.scroll_update.y;
- }
-
- float velocity_x() const {
- CHECK(type_ == ui::ET_GESTURE_SCROLL_UPDATE ||
- type_ == ui::ET_SCROLL_FLING_START);
- return type_ == ui::ET_SCROLL_FLING_START ? data.fling_velocity.x :
- data.scroll_update.velocity_x;
- }
-
- float velocity_y() const {
- CHECK(type_ == ui::ET_GESTURE_SCROLL_UPDATE ||
- type_ == ui::ET_SCROLL_FLING_START);
- return type_ == ui::ET_SCROLL_FLING_START ? data.fling_velocity.y :
- data.scroll_update.velocity_y;
- }
-
- // *_ordinal values are unmodified by rail based clamping.
- float scroll_x_ordinal() const {
- CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, type_);
- return data.scroll_update.x_ordinal;
- }
-
- float scroll_y_ordinal() const {
- CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, type_);
- return data.scroll_update.y_ordinal;
- }
-
- float velocity_x_ordinal() const {
- CHECK(type_ == ui::ET_GESTURE_SCROLL_UPDATE ||
- type_ == ui::ET_SCROLL_FLING_START);
- return type_ == ui::ET_SCROLL_FLING_START ?
- data.fling_velocity.x_ordinal :
- data.scroll_update.velocity_x_ordinal;
- }
-
- float velocity_y_ordinal() const {
- CHECK(type_ == ui::ET_GESTURE_SCROLL_UPDATE ||
- type_ == ui::ET_SCROLL_FLING_START);
- return type_ == ui::ET_SCROLL_FLING_START ?
- data.fling_velocity.y_ordinal :
- data.scroll_update.velocity_y_ordinal;
- }
-
- int touch_id() const {
- CHECK_EQ(ui::ET_GESTURE_LONG_PRESS, type_);
- return data.touch_id;
- }
-
- float first_finger_width() const {
- CHECK_EQ(ui::ET_GESTURE_TWO_FINGER_TAP, type_);
- return data.first_finger_enclosing_rectangle.width;
- }
-
- float first_finger_height() const {
- CHECK_EQ(ui::ET_GESTURE_TWO_FINGER_TAP, type_);
- return data.first_finger_enclosing_rectangle.height;
- }
-
- float scale() const {
- CHECK_EQ(ui::ET_GESTURE_PINCH_UPDATE, type_);
- return data.scale;
- }
-
- bool swipe_left() const {
- CHECK_EQ(ui::ET_GESTURE_MULTIFINGER_SWIPE, type_);
- return data.swipe.left;
- }
-
- bool swipe_right() const {
- CHECK_EQ(ui::ET_GESTURE_MULTIFINGER_SWIPE, type_);
- return data.swipe.right;
- }
-
- bool swipe_up() const {
- CHECK_EQ(ui::ET_GESTURE_MULTIFINGER_SWIPE, type_);
- return data.swipe.up;
- }
-
- bool swipe_down() const {
- CHECK_EQ(ui::ET_GESTURE_MULTIFINGER_SWIPE, type_);
- return data.swipe.down;
- }
-
- int tap_count() const {
- CHECK_EQ(ui::ET_GESTURE_TAP, type_);
- return data.tap_count;
- }
-
- private:
- ui::EventType type_;
- union {
- struct { // SCROLL delta.
- float x;
- float y;
- float velocity_x;
- float velocity_y;
- float x_ordinal;
- float y_ordinal;
- float velocity_x_ordinal;
- float velocity_y_ordinal;
- } scroll_update;
-
- float scale; // PINCH scale.
-
- struct { // FLING velocity.
- float x;
- float y;
- float x_ordinal;
- float y_ordinal;
- } fling_velocity;
-
- int touch_id; // LONG_PRESS touch-id.
-
- // Dimensions of the first finger's enclosing rectangle for TWO_FINGER_TAP.
- struct {
- float width;
- float height;
- } first_finger_enclosing_rectangle;
-
- struct { // SWIPE direction.
- bool left;
- bool right;
- bool up;
- bool down;
- } swipe;
-
- int tap_count; // TAP repeat count.
- } data;
-
- int touch_points_; // Number of active touch points in the gesture.
-
- // Bounding box is an axis-aligned rectangle that contains all the
- // enclosing rectangles of the touch-points in the gesture.
- gfx::Rect bounding_box_;
-};
-
// An abstract type for consumers of gesture-events created by the
// gesture-recognizer.
class EVENTS_EXPORT GestureConsumer {
@@ -193,7 +28,7 @@ class EVENTS_EXPORT GestureEventHelper {
// Returns true if this helper can dispatch events to |consumer|.
virtual bool CanDispatchToConsumer(GestureConsumer* consumer) = 0;
- virtual void DispatchPostponedGestureEvent(GestureEvent* event) = 0;
+ virtual void DispatchGestureEvent(GestureEvent* event) = 0;
virtual void DispatchCancelTouchEvent(TouchEvent* event) = 0;
};
diff --git a/chromium/ui/events/gestures/gesture_util.cc b/chromium/ui/events/gestures/gesture_util.cc
deleted file mode 100644
index 5a99039453c..00000000000
--- a/chromium/ui/events/gestures/gesture_util.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/gestures/gesture_util.h"
-
-#include <stdlib.h>
-
-#include "ui/events/gestures/gesture_configuration.h"
-#include "ui/gfx/point.h"
-
-namespace ui {
-namespace gestures {
-
-bool IsInsideManhattanSquare(const gfx::Point& p1,
- const gfx::Point& p2) {
- int manhattan_distance = abs(p1.x() - p2.x()) + abs(p1.y() - p2.y());
- return manhattan_distance <
- GestureConfiguration::max_touch_move_in_pixels_for_click();
-}
-
-} // namespace gestures
-} // namespace ui
diff --git a/chromium/ui/events/gestures/gesture_util.h b/chromium/ui/events/gestures/gesture_util.h
deleted file mode 100644
index 36c1584e7b4..00000000000
--- a/chromium/ui/events/gestures/gesture_util.h
+++ /dev/null
@@ -1,26 +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_EVENTS_GESTURES_GESTURE_UTIL_H_
-#define UI_EVENTS_GESTURES_GESTURE_UTIL_H_
-
-#include "ui/events/events_export.h"
-
-namespace gfx {
-class Point;
-} // namespace gfx
-
-namespace ui {
-namespace gestures {
-
-// Returns true if the distance between points |p1| and |p2| is less than a
-// threshold. This is generally used to determine if a touch point has moved
-// enough to be no longer considered a tap.
-EVENTS_EXPORT bool IsInsideManhattanSquare(const gfx::Point& p1,
- const gfx::Point& p2);
-
-} // namespace gestures
-} // namespace ui
-
-#endif // UI_EVENTS_GESTURES_GESTURE_UTIL_H_
diff --git a/chromium/ui/events/gestures/gestures.dot b/chromium/ui/events/gestures/gestures.dot
index 07883f8d274..168d02f6fff 100644
--- a/chromium/ui/events/gestures/gestures.dot
+++ b/chromium/ui/events/gestures/gestures.dot
@@ -25,11 +25,16 @@ GS_PENDING_SYNTHETIC_CLICK -> GS_NO_GESTURE [label= "C0\n R0"];
GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0"];
GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
GS_PENDING_SYNTHETIC_CLICK -> GS_PENDING_PINCH [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK -> GS_SYNTHETIC_CLICK_ABORTED [label= "M0"];
GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL [label= "M0\n S0"];
GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_NO_GESTURE [label= "C0\n R0"];
GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_TWO_FINGER_TAP [label= "D1"];
GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_PENDING_PINCH [label= "D1"];
+GS_PENDING_SYNTHETIC_CLICK_NO_SCROLL -> GS_SYNTHETIC_CLICK_ABORTED [label= "M0"];
+
+GS_SYNTHETIC_CLICK_ABORTED -> GS_NO_GESTURE [label= "C0\n R0"];
+GS_SYNTHETIC_CLICK_ABORTED -> GS_PENDING_PINCH [label= "D1"];
GS_SCROLL -> GS_SCROLL [label= "M0"];
GS_SCROLL -> GS_NO_GESTURE [label= "C0\n R0\n"];
diff --git a/chromium/ui/events/gestures/motion_event_aura.cc b/chromium/ui/events/gestures/motion_event_aura.cc
new file mode 100644
index 00000000000..2bf4e9b3ce7
--- /dev/null
+++ b/chromium/ui/events/gestures/motion_event_aura.cc
@@ -0,0 +1,255 @@
+// 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/events/gestures/motion_event_aura.h"
+
+#include "base/logging.h"
+#include "ui/events/gestures/gesture_configuration.h"
+
+namespace ui {
+
+MotionEventAura::MotionEventAura()
+ : pointer_count_(0), cached_action_index_(-1) {
+}
+
+MotionEventAura::MotionEventAura(
+ size_t pointer_count,
+ const base::TimeTicks& last_touch_time,
+ Action cached_action,
+ int cached_action_index,
+ const PointData (&active_touches)[GestureSequence::kMaxGesturePoints])
+ : pointer_count_(pointer_count),
+ last_touch_time_(last_touch_time),
+ cached_action_(cached_action),
+ cached_action_index_(cached_action_index) {
+ DCHECK(pointer_count_);
+ for (size_t i = 0; i < pointer_count; ++i)
+ active_touches_[i] = active_touches[i];
+}
+
+MotionEventAura::~MotionEventAura() {}
+
+MotionEventAura::PointData MotionEventAura::GetPointDataFromTouchEvent(
+ const TouchEvent& touch) {
+ PointData point_data;
+ point_data.x = touch.x();
+ point_data.y = touch.y();
+ point_data.raw_x = touch.root_location_f().x();
+ point_data.raw_y = touch.root_location_f().y();
+ point_data.touch_id = touch.touch_id();
+ point_data.pressure = touch.force();
+ point_data.source_device_id = touch.source_device_id();
+
+ // TODO(tdresser): at some point we should start using both radii if they are
+ // available, but for now we use the max.
+ point_data.major_radius = std::max(touch.radius_x(), touch.radius_y());
+ if (!point_data.major_radius)
+ point_data.major_radius = GestureConfiguration::default_radius();
+ return point_data;
+}
+
+void MotionEventAura::OnTouch(const TouchEvent& touch) {
+ switch (touch.type()) {
+ case ET_TOUCH_PRESSED:
+ AddTouch(touch);
+ break;
+ case ET_TOUCH_RELEASED:
+ case ET_TOUCH_CANCELLED:
+ // Removing these touch points needs to be postponed until after the
+ // MotionEvent has been dispatched. This cleanup occurs in
+ // CleanupRemovedTouchPoints.
+ UpdateTouch(touch);
+ break;
+ case ET_TOUCH_MOVED:
+ UpdateTouch(touch);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ UpdateCachedAction(touch);
+ last_touch_time_ = touch.time_stamp() + base::TimeTicks();
+}
+
+int MotionEventAura::GetId() const {
+ return GetPointerId(0);
+}
+
+MotionEvent::Action MotionEventAura::GetAction() const {
+ return cached_action_;
+}
+
+int MotionEventAura::GetActionIndex() const {
+ DCHECK(cached_action_ == ACTION_POINTER_DOWN ||
+ cached_action_ == ACTION_POINTER_UP);
+ DCHECK_GE(cached_action_index_, 0);
+ DCHECK_LE(cached_action_index_, static_cast<int>(pointer_count_));
+ return cached_action_index_;
+}
+
+size_t MotionEventAura::GetPointerCount() const { return pointer_count_; }
+
+int MotionEventAura::GetPointerId(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].touch_id;
+}
+
+float MotionEventAura::GetX(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].x;
+}
+
+float MotionEventAura::GetY(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].y;
+}
+
+float MotionEventAura::GetRawX(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].raw_x;
+}
+
+float MotionEventAura::GetRawY(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].raw_y;
+}
+
+float MotionEventAura::GetTouchMajor(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].major_radius * 2;
+}
+
+float MotionEventAura::GetPressure(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].pressure;
+}
+
+base::TimeTicks MotionEventAura::GetEventTime() const {
+ return last_touch_time_;
+}
+
+size_t MotionEventAura::GetHistorySize() const { return 0; }
+
+base::TimeTicks MotionEventAura::GetHistoricalEventTime(
+ size_t historical_index) const {
+ NOTIMPLEMENTED();
+ return base::TimeTicks();
+}
+
+float MotionEventAura::GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+float MotionEventAura::GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+float MotionEventAura::GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+scoped_ptr<MotionEvent> MotionEventAura::Clone() const {
+ return scoped_ptr<MotionEvent>(new MotionEventAura(pointer_count_,
+ last_touch_time_,
+ cached_action_,
+ cached_action_index_,
+ active_touches_));
+}
+scoped_ptr<MotionEvent> MotionEventAura::Cancel() const {
+ return scoped_ptr<MotionEvent>(new MotionEventAura(
+ pointer_count_, last_touch_time_, ACTION_CANCEL, -1, active_touches_));
+}
+
+void MotionEventAura::CleanupRemovedTouchPoints(const TouchEvent& event) {
+ if (event.type() != ET_TOUCH_RELEASED &&
+ event.type() != ET_TOUCH_CANCELLED) {
+ return;
+ }
+
+ int index_to_delete = static_cast<int>(GetIndexFromId(event.touch_id()));
+ pointer_count_--;
+ active_touches_[index_to_delete] = active_touches_[pointer_count_];
+}
+
+MotionEventAura::PointData::PointData()
+ : x(0),
+ y(0),
+ raw_x(0),
+ raw_y(0),
+ touch_id(0),
+ pressure(0),
+ source_device_id(0),
+ major_radius(0) {
+}
+
+int MotionEventAura::GetSourceDeviceId(size_t pointer_index) const {
+ DCHECK_LE(pointer_index, pointer_count_);
+ return active_touches_[pointer_index].source_device_id;
+}
+
+void MotionEventAura::AddTouch(const TouchEvent& touch) {
+ if (pointer_count_ == static_cast<size_t>(GestureSequence::kMaxGesturePoints))
+ return;
+
+ active_touches_[pointer_count_] = GetPointDataFromTouchEvent(touch);
+ pointer_count_++;
+}
+
+
+void MotionEventAura::UpdateTouch(const TouchEvent& touch) {
+ active_touches_[GetIndexFromId(touch.touch_id())] =
+ GetPointDataFromTouchEvent(touch);
+}
+
+void MotionEventAura::UpdateCachedAction(const TouchEvent& touch) {
+ DCHECK(pointer_count_);
+ switch (touch.type()) {
+ case ET_TOUCH_PRESSED:
+ if (pointer_count_ == 1) {
+ cached_action_ = ACTION_DOWN;
+ } else {
+ cached_action_ = ACTION_POINTER_DOWN;
+ cached_action_index_ =
+ static_cast<int>(GetIndexFromId(touch.touch_id()));
+ }
+ break;
+ case ET_TOUCH_RELEASED:
+ if (pointer_count_ == 1) {
+ cached_action_ = ACTION_UP;
+ } else {
+ cached_action_ = ACTION_POINTER_UP;
+ cached_action_index_ =
+ static_cast<int>(GetIndexFromId(touch.touch_id()));
+ DCHECK_LE(cached_action_index_, static_cast<int>(pointer_count_));
+ }
+ break;
+ case ET_TOUCH_CANCELLED:
+ cached_action_ = ACTION_CANCEL;
+ break;
+ case ET_TOUCH_MOVED:
+ cached_action_ = ACTION_MOVE;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+size_t MotionEventAura::GetIndexFromId(int id) const {
+ for (size_t i = 0; i < pointer_count_; ++i) {
+ if (active_touches_[i].touch_id == id)
+ return i;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gestures/motion_event_aura.h b/chromium/ui/events/gestures/motion_event_aura.h
new file mode 100644
index 00000000000..7ebf264103f
--- /dev/null
+++ b/chromium/ui/events/gestures/motion_event_aura.h
@@ -0,0 +1,106 @@
+// 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_GESTURE_DETECTION_UI_MOTION_EVENT_H_
+#define UI_EVENTS_GESTURE_DETECTION_UI_MOTION_EVENT_H_
+
+#include "ui/events/gesture_detection/motion_event.h"
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "ui/events/event.h"
+#include "ui/events/events_export.h"
+#include "ui/events/gestures/gesture_sequence.h"
+
+namespace ui {
+
+// Implementation of MotionEvent which takes a stream of ui::TouchEvents.
+class EVENTS_EXPORT MotionEventAura : public MotionEvent {
+ public:
+ MotionEventAura();
+ virtual ~MotionEventAura();
+
+ void OnTouch(const TouchEvent& touch);
+
+ // MotionEvent implementation.
+ virtual int GetId() const OVERRIDE;
+ virtual Action GetAction() const OVERRIDE;
+ virtual int GetActionIndex() const OVERRIDE;
+ virtual size_t GetPointerCount() const OVERRIDE;
+ virtual int GetPointerId(size_t pointer_index) const OVERRIDE;
+ virtual float GetX(size_t pointer_index) const OVERRIDE;
+ virtual float GetY(size_t pointer_index) const OVERRIDE;
+ virtual float GetRawX(size_t pointer_index) const OVERRIDE;
+ virtual float GetRawY(size_t pointer_index) const OVERRIDE;
+ virtual float GetTouchMajor(size_t pointer_index) const OVERRIDE;
+ virtual float GetPressure(size_t pointer_index) const OVERRIDE;
+ virtual base::TimeTicks GetEventTime() const OVERRIDE;
+
+ virtual size_t GetHistorySize() const OVERRIDE;
+ virtual base::TimeTicks GetHistoricalEventTime(size_t historical_index) const
+ OVERRIDE;
+ virtual float GetHistoricalTouchMajor(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+ virtual float GetHistoricalX(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+ virtual float GetHistoricalY(size_t pointer_index,
+ size_t historical_index) const OVERRIDE;
+
+ virtual scoped_ptr<MotionEvent> Clone() const OVERRIDE;
+ virtual scoped_ptr<MotionEvent> Cancel() const OVERRIDE;
+
+ int GetSourceDeviceId(size_t pointer_index) const;
+
+ // We can't cleanup removed touch points immediately upon receipt of a
+ // TouchCancel or TouchRelease, as the MotionEvent needs to be able to report
+ // information about those touch events. Once the MotionEvent has been
+ // processed, we call CleanupRemovedTouchPoints to do the required
+ // book-keeping.
+ void CleanupRemovedTouchPoints(const TouchEvent& event);
+
+ private:
+ struct PointData {
+ PointData();
+ float x;
+ float y;
+ float raw_x;
+ float raw_y;
+ int touch_id;
+ float pressure;
+ int source_device_id;
+ float major_radius;
+ };
+
+ MotionEventAura(
+ size_t pointer_count,
+ const base::TimeTicks& last_touch_time,
+ Action cached_action,
+ int cached_action_index,
+ const PointData (&active_touches)[GestureSequence::kMaxGesturePoints]);
+
+ static PointData GetPointDataFromTouchEvent(const TouchEvent& touch);
+ void AddTouch(const TouchEvent& touch);
+ void UpdateTouch(const TouchEvent& touch);
+ void UpdateCachedAction(const TouchEvent& touch);
+ size_t GetIndexFromId(int id) const;
+
+ size_t pointer_count_;
+ base::TimeTicks last_touch_time_;
+ Action cached_action_;
+ // The index of the touch responsible for last ACTION_POINTER_DOWN or
+ // ACTION_POINTER_UP. -1 if no such action has occurred.
+ int cached_action_index_;
+
+ // We want constant time indexing by pointer_index, and fast indexing by id.
+ // TODO(tdresser): figure out which constant to use here.
+ PointData active_touches_[GestureSequence::kMaxGesturePoints];
+
+ DISALLOW_COPY_AND_ASSIGN(MotionEventAura);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURE_DETECTION_UI_MOTION_EVENT_H_
diff --git a/chromium/ui/events/gestures/motion_event_aura_unittest.cc b/chromium/ui/events/gestures/motion_event_aura_unittest.cc
new file mode 100644
index 00000000000..c45348efeee
--- /dev/null
+++ b/chromium/ui/events/gestures/motion_event_aura_unittest.cc
@@ -0,0 +1,323 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/gestures/motion_event_aura.h"
+
+namespace {
+
+ui::TouchEvent TouchWithType(ui::EventType type, int id) {
+ return ui::TouchEvent(
+ type, gfx::PointF(0, 0), id, base::TimeDelta::FromMilliseconds(0));
+}
+
+ui::TouchEvent TouchWithPosition(ui::EventType type,
+ int id,
+ float x,
+ float y,
+ float raw_x,
+ float raw_y,
+ float radius,
+ float pressure) {
+ ui::TouchEvent event(type,
+ gfx::PointF(x, y),
+ 0,
+ id,
+ base::TimeDelta::FromMilliseconds(0),
+ radius,
+ radius,
+ 0,
+ pressure);
+ event.set_root_location(gfx::PointF(raw_x, raw_y));
+ return event;
+}
+
+ui::TouchEvent TouchWithTime(ui::EventType type, int id, int ms) {
+ return ui::TouchEvent(
+ type, gfx::PointF(0, 0), id, base::TimeDelta::FromMilliseconds(ms));
+}
+
+base::TimeTicks MsToTicks(int ms) {
+ return base::TimeTicks() + base::TimeDelta::FromMilliseconds(ms);
+}
+
+} // namespace
+
+namespace ui {
+
+TEST(MotionEventAuraTest, PointerCountAndIds) {
+ // Test that |PointerCount()| returns the correct number of pointers, and ids
+ // are assigned correctly.
+ int ids[] = {4, 6, 1};
+
+ MotionEventAura event;
+ EXPECT_EQ(0U, event.GetPointerCount());
+
+ TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]);
+ event.OnTouch(press0);
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ EXPECT_EQ(ids[0], event.GetPointerId(0));
+
+ TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]);
+ event.OnTouch(press1);
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ EXPECT_EQ(ids[0], event.GetPointerId(0));
+ EXPECT_EQ(ids[1], event.GetPointerId(1));
+
+ TouchEvent press2 = TouchWithType(ET_TOUCH_PRESSED, ids[2]);
+ event.OnTouch(press2);
+ EXPECT_EQ(3U, event.GetPointerCount());
+
+ EXPECT_EQ(ids[0], event.GetPointerId(0));
+ EXPECT_EQ(ids[1], event.GetPointerId(1));
+ EXPECT_EQ(ids[2], event.GetPointerId(2));
+
+ TouchEvent release1 = TouchWithType(ET_TOUCH_RELEASED, ids[1]);
+ event.OnTouch(release1);
+ event.CleanupRemovedTouchPoints(release1);
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ EXPECT_EQ(ids[0], event.GetPointerId(0));
+ EXPECT_EQ(ids[2], event.GetPointerId(1));
+
+ // Test cloning of pointer count and id information.
+ scoped_ptr<MotionEvent> clone = event.Clone();
+ EXPECT_EQ(2U, clone->GetPointerCount());
+ EXPECT_EQ(ids[0], clone->GetPointerId(0));
+ EXPECT_EQ(ids[2], clone->GetPointerId(1));
+
+ TouchEvent release0 = TouchWithType(ET_TOUCH_RELEASED, ids[0]);
+ event.OnTouch(release0);
+ event.CleanupRemovedTouchPoints(release0);
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ EXPECT_EQ(ids[2], event.GetPointerId(0));
+
+ TouchEvent release2 = TouchWithType(ET_TOUCH_RELEASED, ids[2]);
+ event.OnTouch(release2);
+ event.CleanupRemovedTouchPoints(release2);
+ EXPECT_EQ(0U, event.GetPointerCount());
+}
+
+TEST(MotionEventAuraTest, GetActionIndexAfterRemoval) {
+ // Test that |GetActionIndex()| returns the correct index when points have
+ // been removed.
+ int ids[] = {4, 6, 9};
+
+ MotionEventAura event;
+ EXPECT_EQ(0U, event.GetPointerCount());
+
+ TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]);
+ event.OnTouch(press0);
+ TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]);
+ event.OnTouch(press1);
+ TouchEvent press2 = TouchWithType(ET_TOUCH_PRESSED, ids[2]);
+ event.OnTouch(press2);
+ EXPECT_EQ(3U, event.GetPointerCount());
+
+ TouchEvent release1 = TouchWithType(ET_TOUCH_RELEASED, ids[1]);
+ event.OnTouch(release1);
+ event.CleanupRemovedTouchPoints(release1);
+ EXPECT_EQ(1, event.GetActionIndex());
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ TouchEvent release2 = TouchWithType(ET_TOUCH_RELEASED, ids[0]);
+ event.OnTouch(release2);
+ event.CleanupRemovedTouchPoints(release2);
+ EXPECT_EQ(0, event.GetActionIndex());
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ TouchEvent release0 = TouchWithType(ET_TOUCH_RELEASED, ids[2]);
+ event.OnTouch(release0);
+ event.CleanupRemovedTouchPoints(release0);
+ EXPECT_EQ(0U, event.GetPointerCount());
+}
+
+TEST(MotionEventAuraTest, PointerLocations) {
+ // Test that location information is stored correctly.
+ MotionEventAura event;
+
+ const float kRawOffsetX = 11.1f;
+ const float kRawOffsetY = 13.3f;
+
+ int ids[] = {15, 13};
+ float x;
+ float y;
+ float raw_x;
+ float raw_y;
+ float r;
+ float p;
+
+ x = 14.4f;
+ y = 17.3f;
+ raw_x = x + kRawOffsetX;
+ raw_y = y + kRawOffsetY;
+ r = 25.7f;
+ p = 48.2f;
+ TouchEvent press0 =
+ TouchWithPosition(ET_TOUCH_PRESSED, ids[0], x, y, raw_x, raw_y, r, p);
+ event.OnTouch(press0);
+
+ EXPECT_EQ(1U, event.GetPointerCount());
+ EXPECT_FLOAT_EQ(x, event.GetX(0));
+ EXPECT_FLOAT_EQ(y, event.GetY(0));
+ EXPECT_FLOAT_EQ(raw_x, event.GetRawX(0));
+ EXPECT_FLOAT_EQ(raw_y, event.GetRawY(0));
+ EXPECT_FLOAT_EQ(r, event.GetTouchMajor(0) / 2);
+ EXPECT_FLOAT_EQ(p, event.GetPressure(0));
+
+ x = 17.8f;
+ y = 12.1f;
+ raw_x = x + kRawOffsetX;
+ raw_y = y + kRawOffsetY;
+ r = 21.2f;
+ p = 18.4f;
+ TouchEvent press1 =
+ TouchWithPosition(ET_TOUCH_PRESSED, ids[1], x, y, raw_x, raw_y, r, p);
+ event.OnTouch(press1);
+
+ EXPECT_EQ(2U, event.GetPointerCount());
+ EXPECT_FLOAT_EQ(x, event.GetX(1));
+ EXPECT_FLOAT_EQ(y, event.GetY(1));
+ EXPECT_FLOAT_EQ(raw_x, event.GetRawX(1));
+ EXPECT_FLOAT_EQ(raw_y, event.GetRawY(1));
+ EXPECT_FLOAT_EQ(r, event.GetTouchMajor(1) / 2);
+ EXPECT_FLOAT_EQ(p, event.GetPressure(1));
+
+ // Test cloning of pointer location information.
+ scoped_ptr<MotionEvent> clone = event.Clone();
+ EXPECT_EQ(2U, clone->GetPointerCount());
+ EXPECT_FLOAT_EQ(x, clone->GetX(1));
+ EXPECT_FLOAT_EQ(y, clone->GetY(1));
+ EXPECT_FLOAT_EQ(raw_x, event.GetRawX(1));
+ EXPECT_FLOAT_EQ(raw_y, event.GetRawY(1));
+ EXPECT_FLOAT_EQ(r, clone->GetTouchMajor(1) / 2);
+ EXPECT_FLOAT_EQ(p, clone->GetPressure(1));
+
+ x = 27.9f;
+ y = 22.3f;
+ raw_x = x + kRawOffsetX;
+ raw_y = y + kRawOffsetY;
+ r = 7.6f;
+ p = 82.1f;
+ TouchEvent move1 =
+ TouchWithPosition(ET_TOUCH_MOVED, ids[1], x, y, raw_x, raw_y, r, p);
+ event.OnTouch(move1);
+
+ EXPECT_FLOAT_EQ(x, event.GetX(1));
+ EXPECT_FLOAT_EQ(y, event.GetY(1));
+ EXPECT_FLOAT_EQ(raw_x, event.GetRawX(1));
+ EXPECT_FLOAT_EQ(raw_y, event.GetRawY(1));
+ EXPECT_FLOAT_EQ(r, event.GetTouchMajor(1) / 2);
+ EXPECT_FLOAT_EQ(p, event.GetPressure(1));
+
+ x = 34.6f;
+ y = 23.8f;
+ raw_x = x + kRawOffsetX;
+ raw_y = y + kRawOffsetY;
+ r = 12.9f;
+ p = 14.2f;
+ TouchEvent move0 =
+ TouchWithPosition(ET_TOUCH_MOVED, ids[0], x, y, raw_x, raw_y, r, p);
+ event.OnTouch(move0);
+
+ EXPECT_FLOAT_EQ(x, event.GetX(0));
+ EXPECT_FLOAT_EQ(y, event.GetY(0));
+ EXPECT_FLOAT_EQ(raw_x, event.GetRawX(0));
+ EXPECT_FLOAT_EQ(raw_y, event.GetRawY(0));
+ EXPECT_FLOAT_EQ(r, event.GetTouchMajor(0) / 2);
+ EXPECT_FLOAT_EQ(p, event.GetPressure(0));
+}
+
+TEST(MotionEventAuraTest, Timestamps) {
+ // Test that timestamp information is stored and converted correctly.
+ MotionEventAura event;
+ int ids[] = {7, 13};
+ int times_in_ms[] = {59436, 60263, 82175};
+
+ TouchEvent press0 = TouchWithTime(
+ ui::ET_TOUCH_PRESSED, ids[0], times_in_ms[0]);
+ event.OnTouch(press0);
+ EXPECT_EQ(MsToTicks(times_in_ms[0]), event.GetEventTime());
+
+ TouchEvent press1 = TouchWithTime(
+ ui::ET_TOUCH_PRESSED, ids[1], times_in_ms[1]);
+ event.OnTouch(press1);
+ EXPECT_EQ(MsToTicks(times_in_ms[1]), event.GetEventTime());
+
+ TouchEvent move0 = TouchWithTime(
+ ui::ET_TOUCH_MOVED, ids[0], times_in_ms[2]);
+ event.OnTouch(move0);
+ EXPECT_EQ(MsToTicks(times_in_ms[2]), event.GetEventTime());
+
+ // Test cloning of timestamp information.
+ scoped_ptr<MotionEvent> clone = event.Clone();
+ EXPECT_EQ(MsToTicks(times_in_ms[2]), clone->GetEventTime());
+}
+
+TEST(MotionEventAuraTest, CachedAction) {
+ // Test that the cached action and cached action index are correct.
+ int ids[] = {4, 6};
+ MotionEventAura event;
+
+ TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]);
+ event.OnTouch(press0);
+ EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction());
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]);
+ event.OnTouch(press1);
+ EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction());
+ EXPECT_EQ(1, event.GetActionIndex());
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ // Test cloning of CachedAction information.
+ scoped_ptr<MotionEvent> clone = event.Clone();
+ EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, clone->GetAction());
+ EXPECT_EQ(1, clone->GetActionIndex());
+
+ TouchEvent move0 = TouchWithType(ET_TOUCH_MOVED, ids[0]);
+ event.OnTouch(move0);
+ EXPECT_EQ(MotionEvent::ACTION_MOVE, event.GetAction());
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ TouchEvent release0 = TouchWithType(ET_TOUCH_RELEASED, ids[0]);
+ event.OnTouch(release0);
+ EXPECT_EQ(MotionEvent::ACTION_POINTER_UP, event.GetAction());
+ EXPECT_EQ(2U, event.GetPointerCount());
+ event.CleanupRemovedTouchPoints(release0);
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ TouchEvent release1 = TouchWithType(ET_TOUCH_RELEASED, ids[1]);
+ event.OnTouch(release1);
+ EXPECT_EQ(MotionEvent::ACTION_UP, event.GetAction());
+ EXPECT_EQ(1U, event.GetPointerCount());
+ event.CleanupRemovedTouchPoints(release1);
+ EXPECT_EQ(0U, event.GetPointerCount());
+}
+
+TEST(MotionEventAuraTest, Cancel) {
+ int ids[] = {4, 6};
+ MotionEventAura event;
+
+ TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]);
+ event.OnTouch(press0);
+ EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction());
+ EXPECT_EQ(1U, event.GetPointerCount());
+
+ TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]);
+ event.OnTouch(press1);
+ EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction());
+ EXPECT_EQ(1, event.GetActionIndex());
+ EXPECT_EQ(2U, event.GetPointerCount());
+
+ scoped_ptr<MotionEvent> cancel = event.Cancel();
+ EXPECT_EQ(MotionEvent::ACTION_CANCEL, cancel->GetAction());
+ EXPECT_EQ(2U, static_cast<MotionEventAura*>(cancel.get())->GetPointerCount());
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gestures/unified_gesture_detector_enabled.cc b/chromium/ui/events/gestures/unified_gesture_detector_enabled.cc
new file mode 100644
index 00000000000..cf221ff9d03
--- /dev/null
+++ b/chromium/ui/events/gestures/unified_gesture_detector_enabled.cc
@@ -0,0 +1,37 @@
+// 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 "base/command_line.h"
+#include "base/logging.h"
+#include "ui/events/event_switches.h"
+#include "ui/events/gestures/unified_gesture_detector_enabled.h"
+
+namespace ui {
+
+bool IsUnifiedGestureDetectorEnabled() {
+ const bool kUseUnifiedGestureDetectorByDefault = true;
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const std::string unified_gd_enabled_switch =
+ command_line.HasSwitch(switches::kUnifiedGestureDetector) ?
+ command_line.GetSwitchValueASCII(switches::kUnifiedGestureDetector) :
+ switches::kUnifiedGestureDetectorAuto;
+
+ if (unified_gd_enabled_switch.empty() ||
+ unified_gd_enabled_switch == switches::kUnifiedGestureDetectorEnabled) {
+ return true;
+ }
+
+ if (unified_gd_enabled_switch == switches::kUnifiedGestureDetectorDisabled)
+ return false;
+
+ if (unified_gd_enabled_switch == switches::kUnifiedGestureDetectorAuto)
+ return kUseUnifiedGestureDetectorByDefault;
+
+ LOG(ERROR) << "Invalid --unified-gesture-detector option: "
+ << unified_gd_enabled_switch;
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/gestures/unified_gesture_detector_enabled.h b/chromium/ui/events/gestures/unified_gesture_detector_enabled.h
new file mode 100644
index 00000000000..18fdc26d8ac
--- /dev/null
+++ b/chromium/ui/events/gestures/unified_gesture_detector_enabled.h
@@ -0,0 +1,17 @@
+// 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_GESTURES_UNIFIED_GESTURE_DETECTOR_ENABLED_H_
+#define UI_EVENTS_GESTURES_UNIFIED_GESTURE_DETECTOR_ENABLED_H_
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+// Returns true iff the unified gesture detector is enabled for Aura.
+EVENTS_EXPORT bool IsUnifiedGestureDetectorEnabled();
+
+} // namespace ui
+
+#endif // UI_EVENTS_GESTURES_UNIFIED_GESTURE_DETECTOR_ENABLED_H_
diff --git a/chromium/ui/events/gestures/velocity_calculator.cc b/chromium/ui/events/gestures/velocity_calculator.cc
index 5380d5126fa..37ec671b17f 100644
--- a/chromium/ui/events/gestures/velocity_calculator.cc
+++ b/chromium/ui/events/gestures/velocity_calculator.cc
@@ -30,7 +30,7 @@ float VelocityCalculator::YVelocity() {
return y_velocity_;
}
-void VelocityCalculator::PointSeen(int x, int y, int64 time) {
+void VelocityCalculator::PointSeen(float x, float y, int64 time) {
buffer_[index_].x = x;
buffer_[index_].y = y;
buffer_[index_].time = time;
diff --git a/chromium/ui/events/gestures/velocity_calculator.h b/chromium/ui/events/gestures/velocity_calculator.h
index 1690438ae32..3678514f271 100644
--- a/chromium/ui/events/gestures/velocity_calculator.h
+++ b/chromium/ui/events/gestures/velocity_calculator.h
@@ -17,7 +17,7 @@ class EVENTS_EXPORT VelocityCalculator {
public:
explicit VelocityCalculator(int bufferSize);
~VelocityCalculator();
- void PointSeen(int x, int y, int64 time);
+ void PointSeen(float x, float y, int64 time);
float XVelocity();
float YVelocity();
float VelocitySquared();
@@ -25,8 +25,8 @@ class EVENTS_EXPORT VelocityCalculator {
private:
struct Point {
- int x;
- int y;
+ float x;
+ float y;
int64 time;
};
diff --git a/chromium/ui/events/gestures/velocity_calculator_unittest.cc b/chromium/ui/events/gestures/velocity_calculator_unittest.cc
index 3352acd6722..4e892170d04 100644
--- a/chromium/ui/events/gestures/velocity_calculator_unittest.cc
+++ b/chromium/ui/events/gestures/velocity_calculator_unittest.cc
@@ -74,7 +74,7 @@ TEST(VelocityCalculatorTest, IsAccurateWithLargeTimes) {
EXPECT_GT(velocity_calculator.YVelocity(), -1270000);
EXPECT_LT(velocity_calculator.YVelocity(), -1240000);
- start_time = GG_LONGLONG(1223372036800000000);
+ start_time = 1223372036800000000LL;
velocity_calculator.PointSeen(9, -11, start_time);
velocity_calculator.PointSeen(21, -19, start_time + 8);
velocity_calculator.PointSeen(30, -32, start_time + 16);
diff --git a/chromium/ui/events/ipc/BUILD.gn b/chromium/ui/events/ipc/BUILD.gn
new file mode 100644
index 00000000000..82ac834cf3d
--- /dev/null
+++ b/chromium/ui/events/ipc/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("events_ipc") {
+ sources = [
+ "latency_info_param_traits.cc",
+ "latency_info_param_traits.h",
+ ]
+
+ defines = [ "EVENTS_IMPLEMENTATION" ]
+
+ deps = [ "//ipc" ]
+}
+
diff --git a/chromium/ui/events/ipc/OWNERS b/chromium/ui/events/ipc/OWNERS
new file mode 100644
index 00000000000..2d12f8e4d21
--- /dev/null
+++ b/chromium/ui/events/ipc/OWNERS
@@ -0,0 +1,13 @@
+set noparent
+cevans@chromium.org
+dcheng@chromium.org
+inferno@chromium.org
+jln@chromium.org
+jschuh@chromium.org
+kenrb@chromium.org
+nasko@chromium.org
+palmer@chromium.org
+tsepez@chromium.org
+
+per-file *.gyp*=*
+per-file BUILD.gn=*
diff --git a/chromium/ui/events/ipc/events_ipc.gyp b/chromium/ui/events/ipc/events_ipc.gyp
new file mode 100644
index 00000000000..dd6433d33a6
--- /dev/null
+++ b/chromium/ui/events/ipc/events_ipc.gyp
@@ -0,0 +1,29 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'events_ipc',
+ 'type': '<(component)',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/ipc/ipc.gyp:ipc',
+ ],
+ 'defines': [
+ 'EVENTS_IMPLEMENTATION',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'latency_info_param_traits.cc',
+ 'latency_info_param_traits.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/events/ipc/latency_info_param_traits.cc b/chromium/ui/events/ipc/latency_info_param_traits.cc
new file mode 100644
index 00000000000..0b36c3121aa
--- /dev/null
+++ b/chromium/ui/events/ipc/latency_info_param_traits.cc
@@ -0,0 +1,26 @@
+// 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/events/ipc/latency_info_param_traits.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#include "ui/events/ipc/latency_info_param_traits.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#include "ui/events/ipc/latency_info_param_traits.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#include "ui/events/ipc/latency_info_param_traits.h"
+} // namespace IPC
diff --git a/chromium/ui/events/ipc/latency_info_param_traits.h b/chromium/ui/events/ipc/latency_info_param_traits.h
new file mode 100644
index 00000000000..0206d7d52e6
--- /dev/null
+++ b/chromium/ui/events/ipc/latency_info_param_traits.h
@@ -0,0 +1,30 @@
+// 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_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+
+#include "ipc/ipc_message_macros.h"
+#include "ui/events/events_export.h"
+#include "ui/events/latency_info.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT EVENTS_EXPORT
+
+IPC_ENUM_TRAITS_MAX_VALUE(ui::LatencyComponentType,
+ ui::LATENCY_COMPONENT_TYPE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo::LatencyComponent)
+ IPC_STRUCT_TRAITS_MEMBER(sequence_number)
+ IPC_STRUCT_TRAITS_MEMBER(event_time)
+ IPC_STRUCT_TRAITS_MEMBER(event_count)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo)
+ IPC_STRUCT_TRAITS_MEMBER(latency_components)
+ IPC_STRUCT_TRAITS_MEMBER(trace_id)
+ IPC_STRUCT_TRAITS_MEMBER(terminated)
+IPC_STRUCT_TRAITS_END()
+
+#endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
diff --git a/chromium/ui/events/keycodes/DEPS b/chromium/ui/events/keycodes/DEPS
new file mode 100644
index 00000000000..a2ede37fc05
--- /dev/null
+++ b/chromium/ui/events/keycodes/DEPS
@@ -0,0 +1,11 @@
+include_rules = [
+ # Remove DEPS allowed by ui/base
+ "-grit",
+ "-jni",
+ "-net",
+ "-skia",
+ "-third_party",
+ "-ui",
+
+ "+ui/events",
+]
diff --git a/chromium/ui/events/keycodes/dom4/DEPS b/chromium/ui/events/keycodes/dom4/DEPS
new file mode 100644
index 00000000000..b5489564447
--- /dev/null
+++ b/chromium/ui/events/keycodes/dom4/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/events/keycodes/dom4",
+]
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.cc
deleted file mode 100644
index 9a396534e20..00000000000
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// WindowsKeyCodeForGdkKeyCode is copied from platform/gtk/KeyEventGtk.cpp
-
-#include "ui/events/keycodes/keyboard_code_conversion_gtk.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <X11/keysym.h>
-
-#include "base/basictypes.h"
-#include "build/build_config.h"
-#include "ui/events/keycodes/keyboard_code_conversion_x.h"
-#include "ui/events/keycodes/keyboard_codes_posix.h"
-
-namespace ui {
-
-KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode) {
- // Gdk key codes (e.g. GDK_BackSpace) and X keysyms (e.g. XK_BackSpace) share
- // the same values.
- return KeyboardCodeFromXKeysym(keycode);
-}
-
-int GdkKeyCodeForWindowsKeyCode(KeyboardCode keycode, bool shift) {
- // Gdk key codes and X keysyms share the same values.
- return XKeysymForWindowsKeyCode(keycode, shift);
-}
-
-// Just in case, test whether Gdk key codes match X ones.
-COMPILE_ASSERT(GDK_KP_0 == XK_KP_0, keycode_check);
-COMPILE_ASSERT(GDK_A == XK_A, keycode_check);
-COMPILE_ASSERT(GDK_Escape == XK_Escape, keycode_check);
-COMPILE_ASSERT(GDK_F1 == XK_F1, keycode_check);
-COMPILE_ASSERT(GDK_Kanji == XK_Kanji, keycode_check);
-COMPILE_ASSERT(GDK_Page_Up == XK_Page_Up, keycode_check);
-COMPILE_ASSERT(GDK_Tab == XK_Tab, keycode_check);
-COMPILE_ASSERT(GDK_a == XK_a, keycode_check);
-COMPILE_ASSERT(GDK_space == XK_space, keycode_check);
-
-int GdkNativeKeyCodeForWindowsKeyCode(KeyboardCode keycode, bool shift) {
- int keyval = GdkKeyCodeForWindowsKeyCode(keycode, shift);
- GdkKeymapKey* keys;
- gint n_keys;
-
- int native_keycode = 0;
- if (keyval && gdk_keymap_get_entries_for_keyval(0, keyval, &keys, &n_keys)) {
- native_keycode = keys[0].keycode;
- g_free(keys);
- }
-
- return native_keycode;
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.h b/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.h
deleted file mode 100644
index 6258f4116c1..00000000000
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_gtk.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// WindowsKeyCodeForGdkKeyCode is copied from platform/gtk/KeyEventGtk.cpp
-
-#ifndef UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_GTK_H_
-#define UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_GTK_H_
-
-#include "ui/events/events_base_export.h"
-#include "ui/events/keycodes/keyboard_codes_posix.h"
-
-typedef struct _GdkEventKey GdkEventKey;
-
-namespace ui {
-
-EVENTS_BASE_EXPORT KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode);
-
-EVENTS_BASE_EXPORT int GdkKeyCodeForWindowsKeyCode(KeyboardCode keycode,
- bool shift);
-
-// For WebKit DRT testing: simulate the native keycode for the given
-// input |keycode|. Return the native keycode.
-EVENTS_BASE_EXPORT int GdkNativeKeyCodeForWindowsKeyCode(KeyboardCode keycode,
- bool shift);
-
-} // namespace ui
-
-#endif // UI_EVENTS_KEYCODES_KEYBOARD_CODE_CONVERSION_GTK_H_
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.h b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.h
index 719c922d139..fee39815d42 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.h
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.h
@@ -16,8 +16,8 @@ namespace ui {
// We use windows virtual keycodes throughout our keyboard event related code,
// including unit tests. But Mac uses a different set of virtual keycodes.
// This function converts a windows virtual keycode into Mac's virtual key code
-// and corresponding unicode character. |flags| is the modifiers mask such
-// as NSControlKeyMask, NSShiftKeyMask, etc.
+// and corresponding unicode character. |flags| is the Cocoa modifiers mask
+// such as NSControlKeyMask, NSShiftKeyMask, etc.
// When success, the corresponding Mac's virtual key code will be returned.
// The corresponding unicode character will be stored in |character|, and the
// corresponding unicode character ignoring the modifiers will be stored in
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
index fdda790be1f..e354e58883c 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_mac.mm
@@ -521,18 +521,6 @@ int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
}
}
- // Control characters.
- if (flags & NSControlKeyMask) {
- if (keycode >= VKEY_A && keycode <= VKEY_Z)
- *character = 1 + keycode - VKEY_A;
- else if (macKeycode == kVK_ANSI_LeftBracket)
- *character = 27;
- else if (macKeycode == kVK_ANSI_Backslash)
- *character = 28;
- else if (macKeycode == kVK_ANSI_RightBracket)
- *character = 29;
- }
-
// TODO(suzhe): Support characters for Option key bindings.
return macKeycode;
}
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
index 821f8c47013..4f277ecff27 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_x.cc
@@ -4,6 +4,8 @@
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include <algorithm>
+
#define XK_3270 // for XK_3270_BackTab
#include <X11/keysym.h>
#include <X11/Xlib.h>
@@ -13,23 +15,529 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/events/keycodes/dom4/keycode_converter.h"
+#define VKEY_UNSUPPORTED VKEY_UNKNOWN
+
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].
+//
+// ch0: the keysym without modifier states.
+// ch1: the keysym with shift state.
+// ch2: the keysym with altgr state.
+// sc: the hardware keycode (in Windows, it's called scan code).
+// vk: the VKEY code.
+//
+// MAP0: maps from ch0 to vk.
+// MAP1: maps from ch0+sc to vk.
+// MAP2: maps from ch0+ch1+sc to vk.
+// MAP3: maps from ch0+ch1+ch2+sc to vk.
+// MAP0 - MAP3 are all sorted, so that finding VK can be binary search.
+//
+// Reason for creating these maps is because a hard-coded mapping in
+// KeyboardCodeFromXKeysym() doesn't support non-US keyboard layouts.
+// e.g. in UK keyboard, the key between Quote and Enter keys has the VKEY code
+// VKEY_OEM_5 instead of VKEY_3.
+//
+// The key symbols which are not [a-zA-Z0-9] and functional/extend keys (e.g.
+// TAB, ENTER, BS, Arrow keys, modifier keys, F1-F12, media/app keys, etc.)
+// should go through these maps for correct VKEY codes.
+//
+// Please refer to crbug.com/386066.
+//
+const struct MAP0 {
+ KeySym ch0;
+ uint8 vk;
+ bool operator()(const MAP0& m1, const MAP0& m2) const {
+ return m1.ch0 < m2.ch0;
+ }
+} map0[] = {
+ {0x0025, 0x35}, // XK_percent: VKEY_5
+ {0x0026, 0x31}, // XK_ampersand: VKEY_1
+ {0x003C, 0xDC}, // XK_less: VKEY_OEM_5
+ {0x007B, 0xDE}, // XK_braceleft: VKEY_OEM_7
+ {0x007C, 0xDC}, // XK_bar: VKEY_OEM_5
+ {0x007D, 0xBF}, // XK_braceright: VKEY_OEM_2
+ {0x007E, 0xDC}, // XK_asciitilde: VKEY_OEM_5
+ {0x00A1, 0xDD}, // XK_exclamdown: VKEY_OEM_6
+ {0x00AD, 0xC0}, // XK_hyphen: VKEY_OEM_3
+ {0x00B2, 0xDE}, // XK_twosuperior: VKEY_OEM_7
+ {0x00B5, 0xDC}, // XK_mu: VKEY_OEM_5
+ {0x00BB, 0x39}, // XK_guillemotright: VKEY_9
+ {0x00BD, 0xDC}, // XK_onehalf: VKEY_OEM_5
+ {0x00BF, 0xDD}, // XK_questiondown: VKEY_OEM_6
+ {0x00DF, 0xDB}, // XK_ssharp: VKEY_OEM_4
+ {0x00E5, 0xDD}, // XK_aring: VKEY_OEM_6
+ {0x00EA, 0x33}, // XK_ecircumflex: VKEY_3
+ {0x00EB, 0xBA}, // XK_ediaeresis: VKEY_OEM_1
+ {0x00EC, 0xDD}, // XK_igrave: VKEY_OEM_6
+ {0x00EE, 0xDD}, // XK_icircumflex: VKEY_OEM_6
+ {0x00F1, 0xC0}, // XK_ntilde: VKEY_OEM_3
+ {0x00F2, 0xC0}, // XK_ograve: VKEY_OEM_3
+ {0x00F5, 0xDB}, // XK_otilde: VKEY_OEM_4
+ {0x00F7, 0xDD}, // XK_division: VKEY_OEM_6
+ {0x00FD, 0x37}, // XK_yacute: VKEY_7
+ {0x00FE, 0xBD}, // XK_thorn: VKEY_OEM_MINUS
+ {0x01A1, 0xDD}, // XK_ohorn: VKEY_OEM_6
+ {0x01B0, 0xDB}, // XK_uhorn: VKEY_OEM_4
+ {0x01B5, 0x32}, // XK_lcaron: VKEY_2
+ {0x01B6, 0xDD}, // XK_zstroke: VKEY_OEM_6
+ {0x01BB, 0x35}, // XK_tcaron: VKEY_5
+ {0x01E6, 0xDE}, // XK_cacute: VKEY_OEM_7
+ {0x01EC, 0x32}, // XK_ecaron: VKEY_2
+ {0x01F2, 0xDC}, // XK_ncaron: VKEY_OEM_5
+ {0x01F5, 0xDB}, // XK_odoubleacute: VKEY_OEM_4
+ {0x01F8, 0x35}, // XK_rcaron: VKEY_5
+ {0x01F9, 0xBA}, // XK_uring: VKEY_OEM_1
+ {0x01FB, 0xDC}, // XK_udoubleacute: VKEY_OEM_5
+ {0x01FE, 0xDE}, // XK_tcedilla: VKEY_OEM_7
+ {0x0259, 0xC0}, // XK_schwa: VKEY_OEM_3
+ {0x02B1, 0xDD}, // XK_hstroke: VKEY_OEM_6
+ {0x02B9, 0xBA}, // XK_idotless: VKEY_OEM_1
+ {0x02BB, 0xDD}, // XK_gbreve: VKEY_OEM_6
+ {0x02E5, 0xC0}, // XK_cabovedot: VKEY_OEM_3
+ {0x02F5, 0xDB}, // XK_gabovedot: VKEY_OEM_4
+ {0x03B6, 0xBF}, // XK_lcedilla: VKEY_OEM_2
+ {0x03BA, 0x57}, // XK_emacron: VKEY_W
+ {0x03E0, 0xDF}, // XK_amacron: VKEY_OEM_8
+ {0x03EF, 0xDD}, // XK_imacron: VKEY_OEM_6
+ {0x03F1, 0xDB}, // XK_ncedilla: VKEY_OEM_4
+ {0x03F3, 0xDC}, // XK_kcedilla: VKEY_OEM_5
+};
+
+const struct MAP1 {
+ KeySym ch0;
+ unsigned sc;
+ uint8 vk;
+ bool operator()(const MAP1& m1, const MAP1& m2) const {
+ if (m1.ch0 == m2.ch0)
+ return m1.sc < m2.sc;
+ 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
+};
+
+const struct MAP2 {
+ KeySym ch0;
+ unsigned sc;
+ KeySym ch1;
+ uint8 vk;
+ bool operator()(const MAP2& m1, const MAP2& m2) const {
+ if (m1.ch0 == m2.ch0 && m1.sc == m2.sc)
+ return m1.ch1 < m2.ch1;
+ if (m1.ch0 == m2.ch0)
+ return m1.sc < m2.sc;
+ return m1.ch0 < m2.ch0;
+ }
+} map2[] = {
+ {0x0023, 0x33, 0x0027,
+ 0xBF}, // XK_numbersign+BKSL+XK_quoteright: VKEY_OEM_2
+ {0x0027, 0x30, 0x0022,
+ 0xDE}, // XK_quoteright+AC11+XK_quotedbl: VKEY_OEM_7
+ {0x0027, 0x31, 0x0022,
+ 0xC0}, // XK_quoteright+TLDE+XK_quotedbl: VKEY_OEM_3
+ {0x0027, 0x31, 0x00B7,
+ 0xDC}, // XK_quoteright+TLDE+XK_periodcentered: VKEY_OEM_5
+ {0x0027, 0x33, 0x0000, 0xDC}, // XK_quoteright+BKSL+NoSymbol: VKEY_OEM_5
+ {0x002D, 0x3D, 0x003D, 0xBD}, // XK_minus+AB10+XK_equal: VKEY_OEM_MINUS
+ {0x002F, 0x0C, 0x0033, 0x33}, // XK_slash+AE03+XK_3: VKEY_3
+ {0x002F, 0x0C, 0x003F, 0xBF}, // XK_slash+AE03+XK_question: VKEY_OEM_2
+ {0x002F, 0x13, 0x0030, 0x30}, // XK_slash+AE10+XK_0: VKEY_0
+ {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
+ {0x00A7, 0x31, 0x00B0, 0xBF}, // XK_section+TLDE+XK_degree: VKEY_OEM_2
+ {0x00A7, 0x31, 0x00BD, 0xDC}, // XK_section+TLDE+XK_onehalf: VKEY_OEM_5
+ {0x00E0, 0x30, 0x00B0, 0xDE}, // XK_agrave+AC11+XK_degree: VKEY_OEM_7
+ {0x00E0, 0x30, 0x00E4, 0xDC}, // XK_agrave+AC11+XK_adiaeresis: VKEY_OEM_5
+ {0x00E4, 0x30, 0x00E0, 0xDC}, // XK_adiaeresis+AC11+XK_agrave: VKEY_OEM_5
+ {0x00E9, 0x2F, 0x00C9, 0xBA}, // XK_eacute+AC10+XK_Eacute: VKEY_OEM_1
+ {0x00E9, 0x2F, 0x00F6, 0xDE}, // XK_eacute+AC10+XK_odiaeresis: VKEY_OEM_7
+ {0x00F6, 0x2F, 0x00E9, 0xDE}, // XK_odiaeresis+AC10+XK_eacute: VKEY_OEM_7
+ {0x00FC, 0x22, 0x00E8, 0xBA}, // XK_udiaeresis+AD11+XK_egrave: VKEY_OEM_1
+};
+
+const struct MAP3 {
+ KeySym ch0;
+ unsigned sc;
+ KeySym ch1;
+ KeySym ch2;
+ uint8 vk;
+ bool operator()(const MAP3& m1, const MAP3& m2) const {
+ if (m1.ch0 == m2.ch0 && m1.sc == m2.sc && m1.ch1 == m2.ch1)
+ return m1.ch2 < m2.ch2;
+ if (m1.ch0 == m2.ch0 && m1.sc == m2.sc)
+ return m1.ch1 < m2.ch1;
+ if (m1.ch0 == m2.ch0)
+ return m1.sc < m2.sc;
+ 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
+};
+
+template <class T_MAP>
+KeyboardCode FindVK(const T_MAP& key, const T_MAP* map, size_t size) {
+ T_MAP comp = {0};
+ const T_MAP* p = std::lower_bound(map, map + size, key, comp);
+ if (p != map + size && !comp(*p, key) && !comp(key, *p))
+ return static_cast<KeyboardCode>(p->vk);
+ return VKEY_UNKNOWN;
+}
+
+} // namespace
+
// Get an ui::KeyboardCode from an X keyevent
KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
+ // Gets correct VKEY code from XEvent is performed as the following steps:
+ // 1. Gets the keysym without modifier states.
+ // 2. For [a-z] & [0-9] cases, returns the VKEY code accordingly.
+ // 3. Find keysym in map0.
+ // 4. If not found, fallback to find keysym + hardware_code in map1.
+ // 5. If not found, fallback to find keysym + keysym_shift + hardware_code
+ // in map2.
+ // 6. If not found, fallback to find keysym + keysym_shift + keysym_altgr +
+ // hardware_code in map3.
+ // 7. If not found, fallback to find in KeyboardCodeFromXKeysym(), which
+ // mainly for non-letter keys.
+ // 8. If not found, fallback to find with the hardware code in US layout.
+
+ KeySym keysym = NoSymbol;
+ XKeyEvent xkey = xev->xkey;
+ xkey.state &= (~0xFF | Mod2Mask); // Clears the xkey's state except numlock.
// XLookupKeysym does not take into consideration the state of the lock/shift
// etc. keys. So it is necessary to use XLookupString instead.
- KeySym keysym;
- XLookupString(&xev->xkey, NULL, 0, &keysym, NULL);
- KeyboardCode keycode = KeyboardCodeFromXKeysym(keysym);
- if (keycode == VKEY_UNKNOWN) {
- keysym = DefaultXKeysymFromHardwareKeycode(xev->xkey.keycode);
- keycode = KeyboardCodeFromXKeysym(keysym);
+ XLookupString(&xkey, NULL, 0, &keysym, NULL);
+
+ // [a-z] cases.
+ if (keysym >= XK_a && keysym <= XK_z)
+ return static_cast<KeyboardCode>(VKEY_A + keysym - XK_a);
+
+ // [0-9] cases.
+ if (keysym >= XK_0 && keysym <= XK_9)
+ return static_cast<KeyboardCode>(VKEY_0 + keysym - XK_0);
+
+ KeyboardCode keycode = VKEY_UNKNOWN;
+
+ if (!IsKeypadKey(keysym) && !IsPrivateKeypadKey(keysym) &&
+ !IsCursorKey(keysym) && !IsPFKey(keysym) && !IsFunctionKey(keysym) &&
+ !IsModifierKey(keysym)) {
+ MAP0 key0 = {keysym & 0xFFFF, 0};
+ keycode = FindVK(key0, map0, arraysize(map0));
+ if (keycode != VKEY_UNKNOWN)
+ return keycode;
+
+ MAP1 key1 = {keysym & 0xFFFF, xkey.keycode, 0};
+ keycode = FindVK(key1, map1, arraysize(map1));
+ if (keycode != VKEY_UNKNOWN)
+ return keycode;
+
+ KeySym keysym_shift = NoSymbol;
+ xkey.state |= ShiftMask;
+ XLookupString(&xkey, NULL, 0, &keysym_shift, NULL);
+ MAP2 key2 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0};
+ keycode = FindVK(key2, map2, arraysize(map2));
+ if (keycode != VKEY_UNKNOWN)
+ return keycode;
+
+ KeySym keysym_altgr = NoSymbol;
+ xkey.state &= ~ShiftMask;
+ xkey.state |= Mod1Mask;
+ XLookupString(&xkey, NULL, 0, &keysym_altgr, NULL);
+ MAP3 key3 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF,
+ keysym_altgr & 0xFFFF, 0};
+ keycode = FindVK(key3, map3, arraysize(map3));
+ if (keycode != VKEY_UNKNOWN)
+ return keycode;
+
+ // On Linux some keys has AltGr char but not on Windows.
+ // So if cannot find VKEY with (ch0+sc+ch1+ch2) in map3, tries to fallback
+ // to just find VKEY with (ch0+sc+ch1). This is the best we could do.
+ MAP3 key4 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0xFFFF,
+ 0};
+ const MAP3* p =
+ std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3());
+ if (p != map3 + arraysize(map3) && p->ch0 == key4.ch0 && p->sc == key4.sc &&
+ p->ch1 == key4.ch1)
+ return static_cast<KeyboardCode>(p->vk);
}
+ keycode = KeyboardCodeFromXKeysym(keysym);
+ if (keycode == VKEY_UNKNOWN)
+ keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey.keycode);
+
return keycode;
}
@@ -99,117 +607,6 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
return VKEY_NONCONVERT;
case XK_Zenkaku_Hankaku:
return VKEY_DBE_DBCSCHAR;
- case XK_A:
- case XK_a:
- return VKEY_A;
- case XK_B:
- case XK_b:
- return VKEY_B;
- case XK_C:
- case XK_c:
- return VKEY_C;
- case XK_D:
- case XK_d:
- return VKEY_D;
- case XK_E:
- case XK_e:
- return VKEY_E;
- case XK_F:
- case XK_f:
- return VKEY_F;
- case XK_G:
- case XK_g:
- return VKEY_G;
- case XK_H:
- case XK_h:
- return VKEY_H;
- case XK_I:
- case XK_i:
- return VKEY_I;
- case XK_J:
- case XK_j:
- return VKEY_J;
- case XK_K:
- case XK_k:
- return VKEY_K;
- case XK_L:
- case XK_l:
- return VKEY_L;
- case XK_M:
- case XK_m:
- return VKEY_M;
- case XK_N:
- case XK_n:
- return VKEY_N;
- case XK_O:
- case XK_o:
- return VKEY_O;
- case XK_P:
- case XK_p:
- return VKEY_P;
- case XK_Q:
- case XK_q:
- return VKEY_Q;
- case XK_R:
- case XK_r:
- return VKEY_R;
- case XK_S:
- case XK_s:
- return VKEY_S;
- case XK_T:
- case XK_t:
- return VKEY_T;
- case XK_U:
- case XK_u:
- return VKEY_U;
- case XK_V:
- case XK_v:
- return VKEY_V;
- case XK_W:
- case XK_w:
- return VKEY_W;
- case XK_X:
- case XK_x:
- return VKEY_X;
- case XK_Y:
- case XK_y:
- return VKEY_Y;
- case XK_Z:
- case XK_z:
- return VKEY_Z;
-
- case XK_0:
- case XK_1:
- case XK_2:
- case XK_3:
- case XK_4:
- case XK_5:
- case XK_6:
- case XK_7:
- case XK_8:
- case XK_9:
- return static_cast<KeyboardCode>(VKEY_0 + (keysym - XK_0));
-
- case XK_parenright:
- return VKEY_0;
- case XK_exclam:
- return VKEY_1;
- case XK_at:
- return VKEY_2;
- case XK_numbersign:
- return VKEY_3;
- case XK_dollar:
- return VKEY_4;
- case XK_percent:
- return VKEY_5;
- case XK_asciicircum:
- return VKEY_6;
- case XK_ampersand:
- return VKEY_7;
- case XK_asterisk:
- return VKEY_8;
- case XK_parenleft:
- return VKEY_9;
case XK_KP_0:
case XK_KP_1:
@@ -371,20 +768,6 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
case XF86XK_Launch9:
return VKEY_F18;
-#if defined(TOOLKIT_GTK)
- case XF86XK_Refresh:
- case XF86XK_History:
- case XF86XK_OpenURL:
- case XF86XK_AddFavorite:
- case XF86XK_Go:
- case XF86XK_ZoomIn:
- case XF86XK_ZoomOut:
- // ui::AcceleratorGtk tries to convert the XF86XK_ keysyms on Chrome
- // startup. It's safe to return VKEY_UNKNOWN here since ui::AcceleratorGtk
- // also checks a Gdk keysym. http://crbug.com/109843
- return VKEY_UNKNOWN;
-#endif
-
// For supporting multimedia buttons on a USB keyboard.
case XF86XK_Back:
return VKEY_BROWSER_BACK;
@@ -450,96 +833,178 @@ uint16 GetCharacterFromXEvent(XEvent* xev) {
int bytes_written = XLookupString(&xev->xkey, buf, 6, NULL, NULL);
DCHECK_LE(bytes_written, 6);
- base::string16 result;
- return (bytes_written > 0 && UTF8ToUTF16(buf, bytes_written, &result) &&
- result.length() == 1) ? result[0] : 0;
+ if (bytes_written <= 0)
+ return 0;
+ const base::string16& result = base::WideToUTF16(
+ base::SysNativeMBToWide(base::StringPiece(buf, bytes_written)));
+ return result.length() == 1 ? result[0] : 0;
}
-unsigned int DefaultXKeysymFromHardwareKeycode(unsigned int hardware_code) {
- static const unsigned int kHardwareKeycodeMap[] = {
- 0, // 0x00:
- 0, // 0x01:
- 0, // 0x02:
- 0, // 0x03:
- 0, // 0x04:
- 0, // 0x05:
- 0, // 0x06:
- 0, // 0x07:
- 0, // 0x08:
- XK_Escape, // 0x09: XK_Escape
- XK_1, // 0x0A: XK_1
- XK_2, // 0x0B: XK_2
- XK_3, // 0x0C: XK_3
- XK_4, // 0x0D: XK_4
- XK_5, // 0x0E: XK_5
- XK_6, // 0x0F: XK_6
- XK_7, // 0x10: XK_7
- XK_8, // 0x11: XK_8
- XK_9, // 0x12: XK_9
- XK_0, // 0x13: XK_0
- XK_minus, // 0x14: XK_minus
- XK_equal, // 0x15: XK_equal
- XK_BackSpace, // 0x16: XK_BackSpace
- XK_Tab, // 0x17: XK_Tab
- XK_q, // 0x18: XK_q
- XK_w, // 0x19: XK_w
- XK_e, // 0x1A: XK_e
- XK_r, // 0x1B: XK_r
- XK_t, // 0x1C: XK_t
- XK_y, // 0x1D: XK_y
- XK_u, // 0x1E: XK_u
- XK_i, // 0x1F: XK_i
- XK_o, // 0x20: XK_o
- XK_p, // 0x21: XK_p
- XK_bracketleft, // 0x22: XK_bracketleft
- XK_bracketright, // 0x23: XK_bracketright
- XK_Return, // 0x24: XK_Return
- XK_Control_L, // 0x25: XK_Control_L
- XK_a, // 0x26: XK_a
- XK_s, // 0x27: XK_s
- XK_d, // 0x28: XK_d
- XK_f, // 0x29: XK_f
- XK_g, // 0x2A: XK_g
- XK_h, // 0x2B: XK_h
- XK_j, // 0x2C: XK_j
- XK_k, // 0x2D: XK_k
- XK_l, // 0x2E: XK_l
- XK_semicolon, // 0x2F: XK_semicolon
- XK_apostrophe, // 0x30: XK_apostrophe
- XK_grave, // 0x31: XK_grave
- XK_Shift_L, // 0x32: XK_Shift_L
- XK_backslash, // 0x33: XK_backslash
- XK_z, // 0x34: XK_z
- XK_x, // 0x35: XK_x
- XK_c, // 0x36: XK_c
- XK_v, // 0x37: XK_v
- XK_b, // 0x38: XK_b
- XK_n, // 0x39: XK_n
- XK_m, // 0x3A: XK_m
- XK_comma, // 0x3B: XK_comma
- XK_period, // 0x3C: XK_period
- XK_slash, // 0x3D: XK_slash
- XK_Shift_R, // 0x3E: XK_Shift_R
- 0, // 0x3F: XK_KP_Multiply
- XK_Alt_L, // 0x40: XK_Alt_L
- XK_space, // 0x41: XK_space
- XK_Caps_Lock, // 0x42: XK_Caps_Lock
- XK_F1, // 0x43: XK_F1
- XK_F2, // 0x44: XK_F2
- XK_F3, // 0x45: XK_F3
- XK_F4, // 0x46: XK_F4
- XK_F5, // 0x47: XK_F5
- XK_F6, // 0x48: XK_F6
- XK_F7, // 0x49: XK_F7
- XK_F8, // 0x4A: XK_F8
- XK_F9, // 0x4B: XK_F9
- XK_F10, // 0x4C: XK_F10
- XK_Num_Lock, // 0x4D: XK_Num_Lock
- XK_Scroll_Lock, // 0x4E: XK_Scroll_Lock
+KeyboardCode DefaultKeyboardCodeFromHardwareKeycode(
+ unsigned int hardware_code) {
+ // This function assumes that X11 is using evdev-based keycodes.
+ static const KeyboardCode kHardwareKeycodeMap[] = {
+ // Please refer to below links for the table content:
+ // http://www.w3.org/TR/DOM-Level-3-Events-code/#keyboard-101
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode
+ // http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
+ VKEY_UNKNOWN, // 0x00:
+ VKEY_UNKNOWN, // 0x01:
+ VKEY_UNKNOWN, // 0x02:
+ VKEY_UNKNOWN, // 0x03:
+ VKEY_UNKNOWN, // 0x04:
+ VKEY_UNKNOWN, // 0x05:
+ VKEY_UNKNOWN, // 0x06:
+ VKEY_UNKNOWN, // XKB evdev (XKB - 8) X KeySym
+ VKEY_UNKNOWN, // === =============== ======
+ VKEY_ESCAPE, // 0x09: KEY_ESC Escape
+ VKEY_1, // 0x0A: KEY_1 1
+ VKEY_2, // 0x0B: KEY_2 2
+ VKEY_3, // 0x0C: KEY_3 3
+ VKEY_4, // 0x0D: KEY_4 4
+ VKEY_5, // 0x0E: KEY_5 5
+ VKEY_6, // 0x0F: KEY_6 6
+ VKEY_7, // 0x10: KEY_7 7
+ VKEY_8, // 0x11: KEY_8 8
+ VKEY_9, // 0x12: KEY_9 9
+ VKEY_0, // 0x13: KEY_0 0
+ VKEY_OEM_MINUS, // 0x14: KEY_MINUS minus
+ VKEY_OEM_PLUS, // 0x15: KEY_EQUAL equal
+ VKEY_BACK, // 0x16: KEY_BACKSPACE BackSpace
+ VKEY_TAB, // 0x17: KEY_TAB Tab
+ VKEY_Q, // 0x18: KEY_Q q
+ VKEY_W, // 0x19: KEY_W w
+ VKEY_E, // 0x1A: KEY_E e
+ VKEY_R, // 0x1B: KEY_R r
+ VKEY_T, // 0x1C: KEY_T t
+ VKEY_Y, // 0x1D: KEY_Y y
+ VKEY_U, // 0x1E: KEY_U u
+ VKEY_I, // 0x1F: KEY_I i
+ VKEY_O, // 0x20: KEY_O o
+ VKEY_P, // 0x21: KEY_P p
+ VKEY_OEM_4, // 0x22: KEY_LEFTBRACE bracketleft
+ VKEY_OEM_6, // 0x23: KEY_RIGHTBRACE bracketright
+ VKEY_RETURN, // 0x24: KEY_ENTER Return
+ VKEY_LCONTROL, // 0x25: KEY_LEFTCTRL Control_L
+ VKEY_A, // 0x26: KEY_A a
+ VKEY_S, // 0x27: KEY_S s
+ VKEY_D, // 0x28: KEY_D d
+ VKEY_F, // 0x29: KEY_F f
+ VKEY_G, // 0x2A: KEY_G g
+ VKEY_H, // 0x2B: KEY_H h
+ VKEY_J, // 0x2C: KEY_J j
+ VKEY_K, // 0x2D: KEY_K k
+ VKEY_L, // 0x2E: KEY_L l
+ VKEY_OEM_1, // 0x2F: KEY_SEMICOLON semicolon
+ VKEY_OEM_7, // 0x30: KEY_APOSTROPHE apostrophe
+ VKEY_OEM_3, // 0x31: KEY_GRAVE grave
+ VKEY_LSHIFT, // 0x32: KEY_LEFTSHIFT Shift_L
+ VKEY_OEM_5, // 0x33: KEY_BACKSLASH backslash
+ VKEY_Z, // 0x34: KEY_Z z
+ VKEY_X, // 0x35: KEY_X x
+ VKEY_C, // 0x36: KEY_C c
+ VKEY_V, // 0x37: KEY_V v
+ VKEY_B, // 0x38: KEY_B b
+ VKEY_N, // 0x39: KEY_N n
+ VKEY_M, // 0x3A: KEY_M m
+ VKEY_OEM_COMMA, // 0x3B: KEY_COMMA comma
+ VKEY_OEM_PERIOD, // 0x3C: KEY_DOT period
+ VKEY_OEM_2, // 0x3D: KEY_SLASH slash
+ VKEY_RSHIFT, // 0x3E: KEY_RIGHTSHIFT Shift_R
+ VKEY_MULTIPLY, // 0x3F: KEY_KPASTERISK KP_Multiply
+ VKEY_LMENU, // 0x40: KEY_LEFTALT Alt_L
+ VKEY_SPACE, // 0x41: KEY_SPACE space
+ VKEY_CAPITAL, // 0x42: KEY_CAPSLOCK Caps_Lock
+ VKEY_F1, // 0x43: KEY_F1 F1
+ VKEY_F2, // 0x44: KEY_F2 F2
+ VKEY_F3, // 0x45: KEY_F3 F3
+ VKEY_F4, // 0x46: KEY_F4 F4
+ VKEY_F5, // 0x47: KEY_F5 F5
+ VKEY_F6, // 0x48: KEY_F6 F6
+ VKEY_F7, // 0x49: KEY_F7 F7
+ VKEY_F8, // 0x4A: KEY_F8 F8
+ VKEY_F9, // 0x4B: KEY_F9 F9
+ VKEY_F10, // 0x4C: KEY_F10 F10
+ VKEY_NUMLOCK, // 0x4D: KEY_NUMLOCK Num_Lock
+ VKEY_SCROLL, // 0x4E: KEY_SCROLLLOCK Scroll_Lock
+ VKEY_NUMPAD7, // 0x4F: KEY_KP7 KP_7
+ VKEY_NUMPAD8, // 0x50: KEY_KP8 KP_8
+ VKEY_NUMPAD9, // 0x51: KEY_KP9 KP_9
+ VKEY_SUBTRACT, // 0x52: KEY_KPMINUS KP_Subtract
+ VKEY_NUMPAD4, // 0x53: KEY_KP4 KP_4
+ VKEY_NUMPAD5, // 0x54: KEY_KP5 KP_5
+ VKEY_NUMPAD6, // 0x55: KEY_KP6 KP_6
+ VKEY_ADD, // 0x56: KEY_KPPLUS KP_Add
+ VKEY_NUMPAD1, // 0x57: KEY_KP1 KP_1
+ VKEY_NUMPAD2, // 0x58: KEY_KP2 KP_2
+ VKEY_NUMPAD3, // 0x59: KEY_KP3 KP_3
+ VKEY_NUMPAD0, // 0x5A: KEY_KP0 KP_0
+ VKEY_DECIMAL, // 0x5B: KEY_KPDOT KP_Decimal
+ VKEY_UNKNOWN, // 0x5C:
+ VKEY_DBE_DBCSCHAR, // 0x5D: KEY_ZENKAKUHANKAKU Zenkaku_Hankaku
+ VKEY_OEM_5, // 0x5E: KEY_102ND backslash
+ VKEY_F11, // 0x5F: KEY_F11 F11
+ VKEY_F12, // 0x60: KEY_F12 F12
+ VKEY_OEM_102, // 0x61: KEY_RO Romaji
+ VKEY_UNSUPPORTED, // 0x62: KEY_KATAKANA Katakana
+ VKEY_UNSUPPORTED, // 0x63: KEY_HIRAGANA Hiragana
+ VKEY_CONVERT, // 0x64: KEY_HENKAN Henkan
+ VKEY_UNSUPPORTED, // 0x65: KEY_KATAKANAHIRAGANA Hiragana_Katakana
+ VKEY_NONCONVERT, // 0x66: KEY_MUHENKAN Muhenkan
+ VKEY_SEPARATOR, // 0x67: KEY_KPJPCOMMA KP_Separator
+ VKEY_RETURN, // 0x68: KEY_KPENTER KP_Enter
+ VKEY_RCONTROL, // 0x69: KEY_RIGHTCTRL Control_R
+ VKEY_DIVIDE, // 0x6A: KEY_KPSLASH KP_Divide
+ VKEY_PRINT, // 0x6B: KEY_SYSRQ Print
+ VKEY_RMENU, // 0x6C: KEY_RIGHTALT Alt_R
+ VKEY_RETURN, // 0x6D: KEY_LINEFEED Linefeed
+ VKEY_HOME, // 0x6E: KEY_HOME Home
+ VKEY_UP, // 0x6F: KEY_UP Up
+ VKEY_PRIOR, // 0x70: KEY_PAGEUP Page_Up
+ VKEY_LEFT, // 0x71: KEY_LEFT Left
+ VKEY_RIGHT, // 0x72: KEY_RIGHT Right
+ VKEY_END, // 0x73: KEY_END End
+ VKEY_DOWN, // 0x74: KEY_DOWN Down
+ VKEY_NEXT, // 0x75: KEY_PAGEDOWN Page_Down
+ VKEY_INSERT, // 0x76: KEY_INSERT Insert
+ VKEY_DELETE, // 0x77: KEY_DELETE Delete
+ VKEY_UNSUPPORTED, // 0x78: KEY_MACRO
+ VKEY_VOLUME_MUTE, // 0x79: KEY_MUTE XF86AudioMute
+ VKEY_VOLUME_DOWN, // 0x7A: KEY_VOLUMEDOWN XF86AudioLowerVolume
+ VKEY_VOLUME_UP, // 0x7B: KEY_VOLUMEUP XF86AudioRaiseVolume
+ VKEY_POWER, // 0x7C: KEY_POWER XF86PowerOff
+ VKEY_OEM_PLUS, // 0x7D: KEY_KPEQUAL KP_Equal
+ VKEY_UNSUPPORTED, // 0x7E: KEY_KPPLUSMINUS plusminus
+ VKEY_PAUSE, // 0x7F: KEY_PAUSE Pause
+ VKEY_MEDIA_LAUNCH_APP1, // 0x80: KEY_SCALE XF86LaunchA
+ VKEY_DECIMAL, // 0x81: KEY_KPCOMMA KP_Decimal
+ VKEY_HANGUL, // 0x82: KEY_HANGUEL Hangul
+ VKEY_HANJA, // 0x83: KEY_HANJA Hangul_Hanja
+ VKEY_OEM_5, // 0x84: KEY_YEN yen
+ VKEY_LWIN, // 0x85: KEY_LEFTMETA Super_L
+ VKEY_RWIN, // 0x86: KEY_RIGHTMETA Super_R
+ VKEY_COMPOSE, // 0x87: KEY_COMPOSE Menu
};
- return hardware_code < arraysize(kHardwareKeycodeMap) ?
- kHardwareKeycodeMap[hardware_code] : 0;
+ if (hardware_code >= arraysize(kHardwareKeycodeMap)) {
+ // Additional keycodes used by the Chrome OS top row special function keys.
+ switch (hardware_code) {
+ case 0xA6: // KEY_BACK
+ return VKEY_BACK;
+ case 0xA7: // KEY_FORWARD
+ return VKEY_BROWSER_FORWARD;
+ case 0xB5: // KEY_REFRESH
+ return VKEY_BROWSER_REFRESH;
+ case 0xD4: // KEY_DASHBOARD
+ return VKEY_MEDIA_LAUNCH_APP2;
+ case 0xE8: // KEY_BRIGHTNESSDOWN
+ return VKEY_BRIGHTNESS_DOWN;
+ case 0xE9: // KEY_BRIGHTNESSUP
+ return VKEY_BRIGHTNESS_UP;
+ }
+ return VKEY_UNKNOWN;
+ }
+ return kHardwareKeycodeMap[hardware_code];
}
// TODO(jcampan): this method might be incomplete.
diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_x.h b/chromium/ui/events/keycodes/keyboard_code_conversion_x.h
index b5d8fe87c37..f9186ca0c88 100644
--- a/chromium/ui/events/keycodes/keyboard_code_conversion_x.h
+++ b/chromium/ui/events/keycodes/keyboard_code_conversion_x.h
@@ -26,8 +26,9 @@ EVENTS_BASE_EXPORT uint16 GetCharacterFromXEvent(XEvent* xev);
EVENTS_BASE_EXPORT int XKeysymForWindowsKeyCode(KeyboardCode keycode,
bool shift);
-// Converts an X keycode into an X KeySym.
-unsigned int DefaultXKeysymFromHardwareKeycode(unsigned int keycode);
+// Converts an X keycode into ui::KeyboardCode.
+EVENTS_BASE_EXPORT KeyboardCode
+ DefaultKeyboardCodeFromHardwareKeycode(unsigned int hardware_code);
} // namespace ui
diff --git a/chromium/ui/events/latency_info.cc b/chromium/ui/events/latency_info.cc
index a3a11828db0..3fedd67e736 100644
--- a/chromium/ui/events/latency_info.cc
+++ b/chromium/ui/events/latency_info.cc
@@ -11,10 +11,14 @@
#include <algorithm>
namespace {
+
+const size_t kMaxLatencyInfoNumber = 100;
+
const char* GetComponentName(ui::LatencyComponentType type) {
#define CASE_TYPE(t) case ui::t: return #t
switch (type) {
CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_PLUGIN_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
@@ -29,6 +33,7 @@ const char* GetComponentName(ui::LatencyComponentType type) {
CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT);
CASE_TYPE(LATENCY_INFO_LIST_TERMINATED_OVERFLOW_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_PLUGIN_COMPONENT);
default:
DLOG(WARNING) << "Unhandled LatencyComponentType.\n";
break;
@@ -46,6 +51,7 @@ bool IsTerminalComponent(ui::LatencyComponentType type) {
case ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT:
case ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT:
case ui::LATENCY_INFO_LIST_TERMINATED_OVERFLOW_COMPONENT:
+ case ui::INPUT_EVENT_LATENCY_TERMINATED_PLUGIN_COMPONENT:
return true;
default:
return false;
@@ -53,7 +59,8 @@ bool IsTerminalComponent(ui::LatencyComponentType type) {
}
bool IsBeginComponent(ui::LatencyComponentType type) {
- return (type == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
+ return (type == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT ||
+ type == ui::INPUT_EVENT_LATENCY_BEGIN_PLUGIN_COMPONENT);
}
// This class is for converting latency info to trace buffer friendly format.
@@ -119,16 +126,28 @@ LatencyInfo::LatencyInfo() : trace_id(-1), terminated(false) {
LatencyInfo::~LatencyInfo() {
}
-void LatencyInfo::MergeWith(const LatencyInfo& other) {
+bool LatencyInfo::Verify(const std::vector<LatencyInfo>& latency_info,
+ const char* referring_msg) {
+ if (latency_info.size() > kMaxLatencyInfoNumber) {
+ LOG(ERROR) << referring_msg << ", LatencyInfo vector size "
+ << latency_info.size() << " is too big.";
+ return false;
+ }
+ return true;
+}
+
+void LatencyInfo::CopyLatencyFrom(const LatencyInfo& other,
+ LatencyComponentType type) {
for (LatencyMap::const_iterator it = other.latency_components.begin();
it != other.latency_components.end();
++it) {
- AddLatencyNumberWithTimestamp(it->first.first,
- it->first.second,
- it->second.sequence_number,
- it->second.event_time,
- it->second.event_count,
- false);
+ if (it->first.first == type) {
+ AddLatencyNumberWithTimestamp(it->first.first,
+ it->first.second,
+ it->second.sequence_number,
+ it->second.event_time,
+ it->second.event_count);
+ }
}
}
@@ -141,8 +160,7 @@ void LatencyInfo::AddNewLatencyFrom(const LatencyInfo& other) {
it->first.second,
it->second.sequence_number,
it->second.event_time,
- it->second.event_count,
- false);
+ it->second.event_count);
}
}
}
@@ -151,22 +169,23 @@ void LatencyInfo::AddLatencyNumber(LatencyComponentType component,
int64 id,
int64 component_sequence_number) {
AddLatencyNumberWithTimestamp(component, id, component_sequence_number,
- base::TimeTicks::HighResNow(), 1, true);
+ base::TimeTicks::HighResNow(), 1);
}
void LatencyInfo::AddLatencyNumberWithTimestamp(LatencyComponentType component,
int64 id,
int64 component_sequence_number,
base::TimeTicks time,
- uint32 event_count,
- bool dump_to_trace) {
- if (dump_to_trace && IsBeginComponent(component)) {
+ uint32 event_count) {
+ if (IsBeginComponent(component)) {
// Should only ever add begin component once.
CHECK_EQ(-1, trace_id);
trace_id = component_sequence_number;
TRACE_EVENT_ASYNC_BEGIN0("benchmark",
"InputLatency",
TRACE_ID_DONT_MANGLE(trace_id));
+ TRACE_EVENT_FLOW_BEGIN0(
+ "input", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
}
LatencyMap::key_type key = std::make_pair(component, id);
@@ -188,7 +207,7 @@ void LatencyInfo::AddLatencyNumberWithTimestamp(LatencyComponentType component,
}
}
- if (dump_to_trace && IsTerminalComponent(component) && trace_id != -1) {
+ if (IsTerminalComponent(component) && trace_id != -1) {
// Should only ever add terminal component once.
CHECK(!terminated);
terminated = true;
@@ -196,6 +215,8 @@ void LatencyInfo::AddLatencyNumberWithTimestamp(LatencyComponentType component,
"InputLatency",
TRACE_ID_DONT_MANGLE(trace_id),
"data", AsTraceableData(*this));
+ TRACE_EVENT_FLOW_END0(
+ "input", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
}
}
diff --git a/chromium/ui/events/latency_info.h b/chromium/ui/events/latency_info.h
index 3e50cc4f80c..619b0462f71 100644
--- a/chromium/ui/events/latency_info.h
+++ b/chromium/ui/events/latency_info.h
@@ -5,10 +5,11 @@
#ifndef UI_EVENTS_LATENCY_INFO_H_
#define UI_EVENTS_LATENCY_INFO_H_
-#include <map>
#include <utility>
+#include <vector>
#include "base/basictypes.h"
+#include "base/containers/small_map.h"
#include "base/time/time.h"
#include "ui/events/events_base_export.h"
@@ -19,6 +20,8 @@ enum LatencyComponentType {
// BEGIN COMPONENT is when we show the latency begin in chrome://tracing.
// Timestamp when the input event is sent from RenderWidgetHost to renderer.
INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ // Timestamp when the input event is received in plugin.
+ INPUT_EVENT_LATENCY_BEGIN_PLUGIN_COMPONENT,
// ---------------------------NORMAL COMPONENT-------------------------------
// Timestamp when the scroll update gesture event is sent from RWH to
// renderer. In Aura, touch event's LatencyInfo is carried over to the gesture
@@ -64,6 +67,10 @@ enum LatencyComponentType {
// This component indicates that the cached LatencyInfo number exceeds the
// maximal allowed size.
LATENCY_INFO_LIST_TERMINATED_OVERFLOW_COMPONENT,
+ // Timestamp when the input event is considered not cause any rendering
+ // damage in plugin and thus terminated.
+ INPUT_EVENT_LATENCY_TERMINATED_PLUGIN_COMPONENT,
+ LATENCY_COMPONENT_TYPE_LAST = INPUT_EVENT_LATENCY_TERMINATED_PLUGIN_COMPONENT
};
struct EVENTS_BASE_EXPORT LatencyInfo {
@@ -78,17 +85,31 @@ struct EVENTS_BASE_EXPORT LatencyInfo {
uint32 event_count;
};
+ // Empirically determined constant based on a typical scroll sequence.
+ enum { kTypicalMaxComponentsPerLatencyInfo = 6 };
+
// Map a Latency Component (with a component-specific int64 id) to a
// component info.
- typedef std::map<std::pair<LatencyComponentType, int64>, LatencyComponent>
- LatencyMap;
+ typedef base::SmallMap<
+ std::map<std::pair<LatencyComponentType, int64>, LatencyComponent>,
+ kTypicalMaxComponentsPerLatencyInfo> LatencyMap;
LatencyInfo();
~LatencyInfo();
- // Merges the contents of another LatencyInfo into this one.
- void MergeWith(const LatencyInfo& other);
+ // Returns true if the vector |latency_info| is valid. Returns false
+ // if it is not valid and log the |referring_msg|.
+ // This function is mainly used to check the latency_info vector that
+ // is passed between processes using IPC message has reasonable size
+ // so that we are confident the IPC message is not corrupted/compromised.
+ // This check will go away once the IPC system has better built-in scheme
+ // for corruption/compromise detection.
+ static bool Verify(const std::vector<LatencyInfo>& latency_info,
+ const char* referring_msg);
+
+ // Copy LatencyComponents with type |type| from |other| into |this|.
+ void CopyLatencyFrom(const LatencyInfo& other, LatencyComponentType type);
// Add LatencyComponents that are in |other| but not in |this|.
void AddNewLatencyFrom(const LatencyInfo& other);
@@ -101,13 +122,11 @@ struct EVENTS_BASE_EXPORT LatencyInfo {
// Modifies the current sequence number and adds a certain number of events
// for a specific component.
- // TODO(miletus): Remove the |dump_to_trace| once we remove MergeWith().
void AddLatencyNumberWithTimestamp(LatencyComponentType component,
int64 id,
int64 component_sequence_number,
base::TimeTicks time,
- uint32 event_count,
- bool dump_to_trace);
+ uint32 event_count);
// Returns true if the a component with |type| and |id| is found in
// the latency_components and the component is stored to |output| if
diff --git a/chromium/ui/events/latency_info_nacl.gyp b/chromium/ui/events/latency_info_nacl.gyp
new file mode 100644
index 00000000000..e42dbf87ee4
--- /dev/null
+++ b/chromium/ui/events/latency_info_nacl.gyp
@@ -0,0 +1,78 @@
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../../build/common_untrusted.gypi',
+ ],
+ 'conditions': [
+ ['disable_nacl==0 and disable_nacl_untrusted==0', {
+ 'targets': [
+ {
+ 'target_name': 'latency_info_nacl',
+ 'type': 'none',
+ 'defines': [
+ 'EVENTS_BASE_IMPLEMENTATION',
+ 'EVENTS_IMPLEMENTATION',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/base/base_nacl.gyp:base_nacl',
+ '<(DEPTH)/ipc/ipc_nacl.gyp:ipc_nacl',
+ '<(DEPTH)/native_client/tools.gyp:prep_toolchain'
+ ],
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'liblatency_info_nacl.a',
+ 'build_glibc': 0,
+ 'build_newlib': 0,
+ 'build_irt': 1,
+ },
+ 'sources': [
+ 'latency_info.cc',
+ 'latency_info.h',
+ 'ipc/latency_info_param_traits.cc',
+ 'ipc/latency_info_param_traits.h',
+ ],
+ },
+ ],
+ }],
+ ['disable_nacl!=1 and OS=="win" and target_arch=="ia32"', {
+ 'targets': [
+ {
+ 'target_name': 'latency_info_nacl_win64',
+ 'type' : '<(component)',
+ 'variables': {
+ 'nacl_win64_target': 1,
+ },
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base_win64',
+ '<(DEPTH)/ipc/ipc.gyp:ipc_win64',
+ ],
+ 'defines': [
+ 'EVENTS_BASE_IMPLEMENTATION',
+ 'EVENTS_IMPLEMENTATION',
+ '<@(nacl_win64_defines)',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'latency_info.cc',
+ 'latency_info.h',
+ 'ipc/latency_info_param_traits.cc',
+ 'ipc/latency_info_param_traits.h',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ ],
+ }],
+ ],
+}
+
diff --git a/chromium/ui/events/latency_info_unittest.cc b/chromium/ui/events/latency_info_unittest.cc
index ec39a0dbcba..2f9ad0562be 100644
--- a/chromium/ui/events/latency_info_unittest.cc
+++ b/chromium/ui/events/latency_info_unittest.cc
@@ -14,14 +14,12 @@ TEST(LatencyInfoTest, AddTwoSeparateEvent) {
0,
1,
base::TimeTicks::FromInternalValue(100),
- 1,
- true);
+ 1);
info.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
1,
5,
base::TimeTicks::FromInternalValue(1000),
- 2,
- true);
+ 2);
EXPECT_EQ(info.latency_components.size(), 2u);
LatencyInfo::LatencyComponent component;
@@ -47,14 +45,12 @@ TEST(LatencyInfoTest, AddTwoSameEvent) {
0,
30,
base::TimeTicks::FromInternalValue(100),
- 2,
- true);
+ 2);
info.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
0,
13,
base::TimeTicks::FromInternalValue(200),
- 3,
- true);
+ 3);
EXPECT_EQ(info.latency_components.size(), 1u);
LatencyInfo::LatencyComponent component;
@@ -69,79 +65,13 @@ TEST(LatencyInfoTest, AddTwoSameEvent) {
EXPECT_EQ(component.event_time.ToInternalValue(), (100 * 2 + 200 * 3) / 5);
}
-TEST(LatencyInfoTest, MergeTwoSeparateEvent) {
- LatencyInfo info1;
- LatencyInfo info2;
- info1.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- 0,
- 1,
- base::TimeTicks::FromInternalValue(100),
- 1,
- true);
- info2.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 1,
- 5,
- base::TimeTicks::FromInternalValue(1000),
- 2,
- true);
- info1.MergeWith(info2);
-
- EXPECT_EQ(info1.latency_components.size(), 2u);
- LatencyInfo::LatencyComponent component;
- EXPECT_FALSE(
- info1.FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component));
- EXPECT_FALSE(info1.FindLatency(
- INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1, &component));
- EXPECT_TRUE(info1.FindLatency(
- INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, &component));
- EXPECT_EQ(component.sequence_number, 1);
- EXPECT_EQ(component.event_count, 1u);
- EXPECT_EQ(component.event_time.ToInternalValue(), 100);
- EXPECT_TRUE(
- info1.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1, &component));
- EXPECT_EQ(component.sequence_number, 5);
- EXPECT_EQ(component.event_count, 2u);
- EXPECT_EQ(component.event_time.ToInternalValue(), 1000);
-}
-
-TEST(LatencyInfoTest, MergeTwoSameEvent) {
- LatencyInfo info1;
- LatencyInfo info2;
- info1.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0,
- 30,
- base::TimeTicks::FromInternalValue(100),
- 2,
- true);
- info2.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0,
- 13,
- base::TimeTicks::FromInternalValue(200),
- 3,
- true);
- info1.MergeWith(info2);
-
- EXPECT_EQ(info1.latency_components.size(), 1u);
- LatencyInfo::LatencyComponent component;
- EXPECT_FALSE(
- info1.FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component));
- EXPECT_FALSE(
- info1.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1, &component));
- EXPECT_TRUE(
- info1.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &component));
- EXPECT_EQ(component.sequence_number, 30);
- EXPECT_EQ(component.event_count, 5u);
- EXPECT_EQ(component.event_time.ToInternalValue(), (100 * 2 + 200 * 3) / 5);
-}
-
TEST(LatencyInfoTest, ClearEvents) {
LatencyInfo info;
info.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
0,
30,
base::TimeTicks::FromInternalValue(100),
- 2,
- true);
+ 2);
EXPECT_EQ(info.latency_components.size(), 1u);
info.Clear();
diff --git a/chromium/ui/events/linux/text_edit_command_auralinux.cc b/chromium/ui/events/linux/text_edit_command_auralinux.cc
new file mode 100644
index 00000000000..4429225f48c
--- /dev/null
+++ b/chromium/ui/events/linux/text_edit_command_auralinux.cc
@@ -0,0 +1,124 @@
+// 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/events/linux/text_edit_command_auralinux.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+std::string TextEditCommandAuraLinux::GetCommandString() const {
+ std::string base_name;
+ switch (command_id_) {
+ case COPY:
+ base_name = "Copy";
+ break;
+ case CUT:
+ base_name = "Cut";
+ break;
+ case DELETE_BACKWARD:
+ base_name = "DeleteBackward";
+ break;
+ case DELETE_FORWARD:
+ base_name = "DeleteForward";
+ break;
+ case DELETE_TO_BEGINING_OF_LINE:
+ base_name = "DeleteToBeginningOfLine";
+ break;
+ case DELETE_TO_BEGINING_OF_PARAGRAPH:
+ base_name = "DeleteToBeginningOfParagraph";
+ break;
+ case DELETE_TO_END_OF_LINE:
+ base_name = "DeleteToEndOfLine";
+ break;
+ case DELETE_TO_END_OF_PARAGRAPH:
+ base_name = "DeleteToEndOfParagraph";
+ break;
+ case DELETE_WORD_BACKWARD:
+ base_name = "DeleteWordBackward";
+ break;
+ case DELETE_WORD_FORWARD:
+ base_name = "DeleteWordForward";
+ break;
+ case INSERT_TEXT:
+ base_name = "InsertText";
+ break;
+ case MOVE_BACKWARD:
+ base_name = "MoveBackward";
+ break;
+ case MOVE_DOWN:
+ base_name = "MoveDown";
+ break;
+ case MOVE_FORWARD:
+ base_name = "MoveForward";
+ break;
+ case MOVE_LEFT:
+ base_name = "MoveLeft";
+ break;
+ case MOVE_PAGE_DOWN:
+ base_name = "MovePageDown";
+ break;
+ case MOVE_PAGE_UP:
+ base_name = "MovePageUp";
+ break;
+ case MOVE_RIGHT:
+ base_name = "MoveRight";
+ break;
+ case MOVE_TO_BEGINING_OF_DOCUMENT:
+ base_name = "MoveToBeginningOfDocument";
+ break;
+ case MOVE_TO_BEGINING_OF_LINE:
+ base_name = "MoveToBeginningOfLine";
+ break;
+ case MOVE_TO_BEGINING_OF_PARAGRAPH:
+ base_name = "MoveToBeginningOfParagraph";
+ break;
+ case MOVE_TO_END_OF_DOCUMENT:
+ base_name = "MoveToEndOfDocument";
+ break;
+ case MOVE_TO_END_OF_LINE:
+ base_name = "MoveToEndOfLine";
+ break;
+ case MOVE_TO_END_OF_PARAGRAPH:
+ base_name = "MoveToEndOfParagraph";
+ break;
+ case MOVE_UP:
+ base_name = "MoveUp";
+ break;
+ case MOVE_WORD_BACKWARD:
+ base_name = "MoveWordBackward";
+ break;
+ case MOVE_WORD_FORWARD:
+ base_name = "MoveWordForward";
+ break;
+ case MOVE_WORD_LEFT:
+ base_name = "MoveWordLeft";
+ break;
+ case MOVE_WORD_RIGHT:
+ base_name = "MoveWordRight";
+ break;
+ case PASTE:
+ base_name = "Paste";
+ break;
+ case SELECT_ALL:
+ base_name = "SelectAll";
+ break;
+ case SET_MARK:
+ base_name = "SetMark";
+ break;
+ case UNSELECT:
+ base_name = "Unselect";
+ break;
+ case INVALID_COMMAND:
+ NOTREACHED();
+ return std::string();
+ }
+
+ if (extend_selection())
+ base_name += "AndModifySelection";
+
+ return base_name;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/linux/text_edit_command_auralinux.h b/chromium/ui/events/linux/text_edit_command_auralinux.h
new file mode 100644
index 00000000000..82d3af24306
--- /dev/null
+++ b/chromium/ui/events/linux/text_edit_command_auralinux.h
@@ -0,0 +1,82 @@
+// 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_X_TEXT_EDIT_COMMAND_X11_H_
+#define UI_EVENTS_X_TEXT_EDIT_COMMAND_X11_H_
+
+#include <string>
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+// Represents a command that performs a specific operation on text.
+// Copy and assignment are explicitly allowed; these objects live in vectors.
+class EVENTS_EXPORT TextEditCommandAuraLinux {
+ public:
+ enum CommandId {
+ COPY,
+ CUT,
+ DELETE_BACKWARD,
+ DELETE_FORWARD,
+ DELETE_TO_BEGINING_OF_LINE,
+ DELETE_TO_BEGINING_OF_PARAGRAPH,
+ DELETE_TO_END_OF_LINE,
+ DELETE_TO_END_OF_PARAGRAPH,
+ DELETE_WORD_BACKWARD,
+ DELETE_WORD_FORWARD,
+ INSERT_TEXT,
+ MOVE_BACKWARD,
+ MOVE_DOWN,
+ MOVE_FORWARD,
+ MOVE_LEFT,
+ MOVE_PAGE_DOWN,
+ MOVE_PAGE_UP,
+ MOVE_RIGHT,
+ MOVE_TO_BEGINING_OF_DOCUMENT,
+ MOVE_TO_BEGINING_OF_LINE,
+ MOVE_TO_BEGINING_OF_PARAGRAPH,
+ MOVE_TO_END_OF_DOCUMENT,
+ MOVE_TO_END_OF_LINE,
+ MOVE_TO_END_OF_PARAGRAPH,
+ MOVE_UP,
+ MOVE_WORD_BACKWARD,
+ MOVE_WORD_FORWARD,
+ MOVE_WORD_LEFT,
+ MOVE_WORD_RIGHT,
+ PASTE,
+ SELECT_ALL,
+ SET_MARK,
+ UNSELECT,
+ INVALID_COMMAND
+ };
+
+ TextEditCommandAuraLinux(CommandId command_id,
+ const std::string& argument,
+ bool extend_selection)
+ : command_id_(command_id),
+ argument_(argument),
+ extend_selection_(extend_selection) {}
+
+ CommandId command_id() const { return command_id_; }
+ const std::string& argument() const { return argument_; }
+ bool extend_selection() const { return extend_selection_; }
+
+ // We communicate these commands back to blink with a string representation.
+ // This will combine the base command name with "AndModifySelection" if we
+ // have |extend_selection_| set.
+ std::string GetCommandString() const;
+
+ private:
+ CommandId command_id_;
+
+ std::string argument_;
+
+ // In addition to executing the command, modify the selection.
+ bool extend_selection_;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_X_TEXT_EDIT_COMMAND_X11_H_
diff --git a/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.cc b/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.cc
new file mode 100644
index 00000000000..e6a941bcda4
--- /dev/null
+++ b/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.cc
@@ -0,0 +1,23 @@
+// 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/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+
+namespace ui {
+
+namespace {
+// Optional delegate. Unowned pointer.
+TextEditKeyBindingsDelegateAuraLinux* text_edit_keybinding_delegate_ = 0;
+}
+
+void SetTextEditKeyBindingsDelegate(
+ TextEditKeyBindingsDelegateAuraLinux* delegate) {
+ text_edit_keybinding_delegate_ = delegate;
+}
+
+TextEditKeyBindingsDelegateAuraLinux* GetTextEditKeyBindingsDelegate() {
+ return text_edit_keybinding_delegate_;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.h b/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.h
new file mode 100644
index 00000000000..d2916260380
--- /dev/null
+++ b/chromium/ui/events/linux/text_edit_key_bindings_delegate_auralinux.h
@@ -0,0 +1,43 @@
+// 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_X_TEXT_EDIT_KEY_BINDINGS_DELEGATE_X11_H_
+#define UI_EVENTS_X_TEXT_EDIT_KEY_BINDINGS_DELEGATE_X11_H_
+
+#include <vector>
+
+#include "ui/events/events_export.h"
+
+namespace ui {
+class Event;
+class TextEditCommandAuraLinux;
+
+// An interface which can interpret various text editing commands out of key
+// events.
+//
+// On desktop Linux, we've traditionally supported the user's custom
+// keybindings. We need to support this in both content/ and in views/.
+class EVENTS_EXPORT TextEditKeyBindingsDelegateAuraLinux {
+ public:
+ // Matches a key event against the users' platform specific key bindings,
+ // false will be returned if the key event doesn't correspond to a predefined
+ // key binding. Edit commands matched with |event| will be stored in
+ // |edit_commands|, if |edit_commands| is non-NULL.
+ virtual bool MatchEvent(const ui::Event& event,
+ std::vector<TextEditCommandAuraLinux>* commands) = 0;
+
+ protected:
+ virtual ~TextEditKeyBindingsDelegateAuraLinux() {}
+};
+
+// Sets/Gets the global TextEditKeyBindingsDelegateAuraLinux. No ownership
+// changes. Can be NULL.
+EVENTS_EXPORT void SetTextEditKeyBindingsDelegate(
+ TextEditKeyBindingsDelegateAuraLinux* delegate);
+EVENTS_EXPORT TextEditKeyBindingsDelegateAuraLinux*
+ GetTextEditKeyBindingsDelegate();
+
+} // namespace ui
+
+#endif // UI_EVENTS_X_TEXT_EDIT_KEY_BINDINGS_DELEGATE_X11_H_
diff --git a/chromium/ui/events/ozone/BUILD.gn b/chromium/ui/events/ozone/BUILD.gn
new file mode 100644
index 00000000000..a5054b7eb7b
--- /dev/null
+++ b/chromium/ui/events/ozone/BUILD.gn
@@ -0,0 +1,101 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/ui.gni")
+
+component("events_ozone") {
+ sources = [
+ "device/device_event.cc",
+ "device/device_event.h",
+ "device/device_event_observer.h",
+ "device/device_manager.cc",
+ "device/device_manager.h",
+ "device/device_manager_manual.cc",
+ "device/device_manager_manual.h",
+ "device/udev/device_manager_udev.cc",
+ "device/udev/device_manager_udev.h",
+ "event_factory_ozone.cc",
+ "event_factory_ozone.h",
+ "events_ozone_export.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+
+ defines = [
+ "EVENTS_OZONE_IMPLEMENTATION",
+ ]
+
+ if (!use_udev) {
+ sources -= [
+ "device/udev/device_manager_udev.cc",
+ "device/udev/device_manager_udev.h",
+ ]
+ }
+
+ if (use_ozone_evdev && use_udev) {
+ deps += [
+ "//device/udev_linux",
+ ]
+ }
+}
+
+component("events_ozone_evdev") {
+ sources = [
+ "evdev/event_converter_evdev.cc",
+ "evdev/event_converter_evdev.h",
+ "evdev/event_device_info.cc",
+ "evdev/event_device_info.h",
+ "evdev/event_factory_evdev.cc",
+ "evdev/event_factory_evdev.h",
+ "evdev/event_modifiers_evdev.cc",
+ "evdev/event_modifiers_evdev.h",
+ "evdev/events_ozone_evdev_export.h",
+ "evdev/key_event_converter_evdev.cc",
+ "evdev/key_event_converter_evdev.h",
+ "evdev/touch_event_converter_evdev.cc",
+ "evdev/touch_event_converter_evdev.h",
+ ]
+
+ defines = [
+ "EVENTS_OZONE_EVDEV_IMPLEMENTATION",
+ ]
+
+ deps = [
+ ":events_ozone",
+ "//base",
+ "//ui/events/platform",
+ "//ui/gfx",
+ ]
+
+ if (use_ozone_evdev) {
+ defines += [
+ "USE_OZONE_EVDEV=1"
+ ]
+ }
+
+ if (use_ozone_evdev && use_evdev_gestures) {
+ sources += [
+ "evdev/libgestures_glue/event_reader_libevdev_cros.cc",
+ "evdev/libgestures_glue/event_reader_libevdev_cros.h",
+ "evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc",
+ "evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h",
+ "evdev/libgestures_glue/gesture_logging.cc",
+ "evdev/libgestures_glue/gesture_logging.h",
+ "evdev/libgestures_glue/gesture_timer_provider.cc",
+ "evdev/libgestures_glue/gesture_timer_provider.h",
+ ]
+
+ defines += [
+ "USE_EVDEV_GESTURES",
+ ]
+
+ configs += [
+ "//build/config/linux:libevdev-cros",
+ "//build/config/linux:libgestures",
+ ]
+ }
+}
diff --git a/chromium/ui/events/ozone/DEPS b/chromium/ui/events/ozone/DEPS
new file mode 100644
index 00000000000..3f271147d36
--- /dev/null
+++ b/chromium/ui/events/ozone/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+device/udev_linux",
+ "+ui/ozone/public",
+]
diff --git a/chromium/ui/events/ozone/OWNERS b/chromium/ui/events/ozone/OWNERS
index 77f21b5cae7..479c4d806cc 100644
--- a/chromium/ui/events/ozone/OWNERS
+++ b/chromium/ui/events/ozone/OWNERS
@@ -1 +1,2 @@
rjkroege@chromium.org
+spang@chromium.org
diff --git a/chromium/ui/events/ozone/device/device_event.cc b/chromium/ui/events/ozone/device/device_event.cc
new file mode 100644
index 00000000000..e20079a79cf
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_event.cc
@@ -0,0 +1,16 @@
+// 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/events/ozone/device/device_event.h"
+
+namespace ui {
+
+DeviceEvent::DeviceEvent(DeviceType type,
+ ActionType action,
+ const base::FilePath& path)
+ : device_type_(type),
+ action_type_(action),
+ path_(path) {}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/device/device_event.h b/chromium/ui/events/ozone/device/device_event.h
new file mode 100644
index 00000000000..a24394c75af
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_event.h
@@ -0,0 +1,43 @@
+// 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_OZONE_DEVICE_EVENT_H_
+#define UI_EVENTS_OZONE_DEVICE_EVENT_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "ui/events/ozone/events_ozone_export.h"
+
+namespace ui {
+
+class EVENTS_OZONE_EXPORT DeviceEvent {
+ public:
+ enum DeviceType {
+ INPUT,
+ DISPLAY,
+ };
+
+ enum ActionType {
+ ADD,
+ REMOVE,
+ CHANGE,
+ };
+
+ DeviceEvent(DeviceType type, ActionType action, const base::FilePath& path);
+
+ DeviceType device_type() const { return device_type_; }
+ ActionType action_type() const { return action_type_; }
+ base::FilePath path() const { return path_; }
+
+ private:
+ DeviceType device_type_;
+ ActionType action_type_;
+ base::FilePath path_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceEvent);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_DEVICE_EVENT_H_
diff --git a/chromium/ui/events/ozone/device/device_event_observer.h b/chromium/ui/events/ozone/device/device_event_observer.h
new file mode 100644
index 00000000000..7ad2f4966c1
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_event_observer.h
@@ -0,0 +1,24 @@
+// 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_OZONE_DEVICE_EVENT_OBSERVER_H_
+#define UI_EVENTS_OZONE_DEVICE_EVENT_OBSERVER_H_
+
+#include "ui/events/ozone/events_ozone_export.h"
+
+namespace ui {
+
+class DeviceEvent;
+
+class EVENTS_OZONE_EXPORT DeviceEventObserver {
+ public:
+ virtual ~DeviceEventObserver() {}
+
+ virtual void OnDeviceEvent(const DeviceEvent& event) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_DEVICE_EVENT_OBSERVER_H_
+
diff --git a/chromium/ui/events/ozone/device/device_manager.cc b/chromium/ui/events/ozone/device/device_manager.cc
new file mode 100644
index 00000000000..bbd5d800fa5
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_manager.cc
@@ -0,0 +1,23 @@
+// 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/events/ozone/device/device_manager.h"
+
+#if defined(USE_UDEV)
+#include "ui/events/ozone/device/udev/device_manager_udev.h"
+#else
+#include "ui/events/ozone/device/device_manager_manual.h"
+#endif
+
+namespace ui {
+
+scoped_ptr<DeviceManager> CreateDeviceManager() {
+#if defined(USE_UDEV)
+ return scoped_ptr<DeviceManager>(new DeviceManagerUdev());
+#else
+ return scoped_ptr<DeviceManager>(new DeviceManagerManual());
+#endif
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/device/device_manager.h b/chromium/ui/events/ozone/device/device_manager.h
new file mode 100644
index 00000000000..0551e7ecf8b
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_manager.h
@@ -0,0 +1,36 @@
+// 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_OZONE_DEVICE_DEVICE_MANAGER_H_
+#define UI_EVENTS_OZONE_DEVICE_DEVICE_MANAGER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/ozone/events_ozone_export.h"
+
+namespace ui {
+
+class DeviceEventObserver;
+
+class EVENTS_OZONE_EXPORT DeviceManager {
+ public:
+ virtual ~DeviceManager() {}
+
+ // Scans the currently available devices and notifies |observer| for each
+ // device found. If also registering for notifications through AddObserver(),
+ // the scan should happen after the registration otherwise the observer may
+ // miss events.
+ virtual void ScanDevices(DeviceEventObserver* observer) = 0;
+
+ // Registers |observer| for device event notifications.
+ virtual void AddObserver(DeviceEventObserver* observer) = 0;
+
+ // Removes |observer| from the list of observers notified.
+ virtual void RemoveObserver(DeviceEventObserver* observer) = 0;
+};
+
+EVENTS_OZONE_EXPORT scoped_ptr<DeviceManager> CreateDeviceManager();
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_DEVICE_DEVICE_MANAGER_H_
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.cc b/chromium/ui/events/ozone/device/device_manager_manual.cc
new file mode 100644
index 00000000000..c86ffccf62b
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_manager_manual.cc
@@ -0,0 +1,33 @@
+// 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/events/ozone/device/device_manager_manual.h"
+
+#include "base/files/file_enumerator.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+
+namespace ui {
+
+DeviceManagerManual::DeviceManagerManual() {}
+
+DeviceManagerManual::~DeviceManagerManual() {}
+
+void DeviceManagerManual::ScanDevices(DeviceEventObserver* observer) {
+ base::FileEnumerator file_enum(base::FilePath("/dev/input"),
+ false,
+ base::FileEnumerator::FILES,
+ "event*[0-9]");
+ for (base::FilePath path = file_enum.Next(); !path.empty();
+ path = file_enum.Next()) {
+ DeviceEvent event(DeviceEvent::INPUT, DeviceEvent::ADD, path);
+ observer->OnDeviceEvent(event);
+ }
+}
+
+void DeviceManagerManual::AddObserver(DeviceEventObserver* observer) {}
+
+void DeviceManagerManual::RemoveObserver(DeviceEventObserver* observer) {}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.h b/chromium/ui/events/ozone/device/device_manager_manual.h
new file mode 100644
index 00000000000..9d1cf61d9d7
--- /dev/null
+++ b/chromium/ui/events/ozone/device/device_manager_manual.h
@@ -0,0 +1,29 @@
+// 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_OZONE_DEVICE_DEVICE_MANAGER_MANUAL_H_
+#define UI_EVENTS_OZONE_DEVICE_DEVICE_MANAGER_MANUAL_H_
+
+#include "base/macros.h"
+#include "ui/events/ozone/device/device_manager.h"
+
+namespace ui {
+
+class DeviceManagerManual : public DeviceManager {
+ public:
+ DeviceManagerManual();
+ virtual ~DeviceManagerManual();
+
+ private:
+ // DeviceManager overrides:
+ virtual void ScanDevices(DeviceEventObserver* observer) OVERRIDE;
+ virtual void AddObserver(DeviceEventObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(DeviceEventObserver* observer) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceManagerManual);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_DEVICE_DEVICE_MANAGER_MANUAL_H_
diff --git a/chromium/ui/events/ozone/device/udev/device_manager_udev.cc b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
new file mode 100644
index 00000000000..7f86bee4f84
--- /dev/null
+++ b/chromium/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -0,0 +1,186 @@
+// 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/events/ozone/device/udev/device_manager_udev.h"
+
+#include <libudev.h>
+
+#include "base/debug/trace_event.h"
+#include "base/strings/stringprintf.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+
+namespace ui {
+
+namespace {
+
+const char* kSubsystems[] = {
+ "input",
+ "drm",
+};
+
+// Severity levels from syslog.h. We can't include it directly as it
+// conflicts with base/logging.h
+enum {
+ SYS_LOG_EMERG = 0,
+ SYS_LOG_ALERT = 1,
+ SYS_LOG_CRIT = 2,
+ SYS_LOG_ERR = 3,
+ SYS_LOG_WARNING = 4,
+ SYS_LOG_NOTICE = 5,
+ SYS_LOG_INFO = 6,
+ SYS_LOG_DEBUG = 7,
+};
+
+// Log handler for messages generated from libudev.
+void UdevLog(struct udev* udev,
+ int priority,
+ const char* file,
+ int line,
+ const char* fn,
+ const char* format,
+ va_list args) {
+ if (priority <= SYS_LOG_ERR)
+ LOG(ERROR) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
+ else if (priority <= SYS_LOG_INFO)
+ VLOG(1) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
+ else // SYS_LOG_DEBUG
+ VLOG(2) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
+}
+
+// Create libudev context.
+device::ScopedUdevPtr UdevCreate() {
+ struct udev* udev = udev_new();
+ if (udev) {
+ udev_set_log_fn(udev, UdevLog);
+ udev_set_log_priority(udev, SYS_LOG_DEBUG);
+ }
+ return device::ScopedUdevPtr(udev);
+}
+
+// Start monitoring input device changes.
+device::ScopedUdevMonitorPtr UdevCreateMonitor(struct udev* udev) {
+ struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (monitor) {
+ for (size_t i = 0; i < arraysize(kSubsystems); ++i)
+ udev_monitor_filter_add_match_subsystem_devtype(
+ monitor, kSubsystems[i], NULL);
+
+ if (udev_monitor_enable_receiving(monitor))
+ LOG(ERROR) << "Failed to start receiving events from udev";
+ } else {
+ LOG(ERROR) << "Failed to create udev monitor";
+ }
+
+ return device::ScopedUdevMonitorPtr(monitor);
+}
+
+} // namespace
+
+DeviceManagerUdev::DeviceManagerUdev() : udev_(UdevCreate()) {
+}
+
+DeviceManagerUdev::~DeviceManagerUdev() {
+}
+
+void DeviceManagerUdev::CreateMonitor() {
+ if (monitor_)
+ return;
+ monitor_ = UdevCreateMonitor(udev_.get());
+ if (monitor_) {
+ int fd = udev_monitor_get_fd(monitor_.get());
+ CHECK_GT(fd, 0);
+ base::MessageLoopForUI::current()->WatchFileDescriptor(
+ fd, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
+ }
+}
+
+void DeviceManagerUdev::ScanDevices(DeviceEventObserver* observer) {
+ CreateMonitor();
+
+ device::ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get()));
+ if (!enumerate)
+ return;
+
+ for (size_t i = 0; i < arraysize(kSubsystems); ++i)
+ udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystems[i]);
+ udev_enumerate_scan_devices(enumerate.get());
+
+ struct udev_list_entry* devices =
+ udev_enumerate_get_list_entry(enumerate.get());
+ struct udev_list_entry* entry;
+
+ udev_list_entry_foreach(entry, devices) {
+ device::ScopedUdevDevicePtr device(udev_device_new_from_syspath(
+ udev_.get(), udev_list_entry_get_name(entry)));
+ if (!device)
+ continue;
+
+ scoped_ptr<DeviceEvent> event = ProcessMessage(device.get());
+ if (event)
+ observer->OnDeviceEvent(*event.get());
+ }
+}
+
+void DeviceManagerUdev::AddObserver(DeviceEventObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DeviceManagerUdev::RemoveObserver(DeviceEventObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void DeviceManagerUdev::OnFileCanReadWithoutBlocking(int fd) {
+ // The netlink socket should never become disconnected. There's no need
+ // to handle broken connections here.
+ TRACE_EVENT1("ozone", "UdevDeviceChange", "socket", fd);
+
+ device::ScopedUdevDevicePtr device(
+ udev_monitor_receive_device(monitor_.get()));
+ if (!device)
+ return;
+
+ scoped_ptr<DeviceEvent> event = ProcessMessage(device.get());
+ if (event)
+ FOR_EACH_OBSERVER(
+ DeviceEventObserver, observers_, OnDeviceEvent(*event.get()));
+}
+
+void DeviceManagerUdev::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTREACHED();
+}
+
+scoped_ptr<DeviceEvent> DeviceManagerUdev::ProcessMessage(udev_device* device) {
+ const char* path = udev_device_get_devnode(device);
+ const char* action = udev_device_get_action(device);
+ const char* hotplug = udev_device_get_property_value(device, "HOTPLUG");
+ const char* subsystem = udev_device_get_property_value(device, "SUBSYSTEM");
+
+ if (!path || !subsystem)
+ return scoped_ptr<DeviceEvent>();
+
+ DeviceEvent::DeviceType device_type;
+ if (!strcmp(subsystem, "input") &&
+ StartsWithASCII(path, "/dev/input/event", true))
+ device_type = DeviceEvent::INPUT;
+ else if (!strcmp(subsystem, "drm") && hotplug && !strcmp(hotplug, "1"))
+ device_type = DeviceEvent::DISPLAY;
+ else
+ return scoped_ptr<DeviceEvent>();
+
+ DeviceEvent::ActionType action_type;
+ if (!action || !strcmp(action, "add"))
+ action_type = DeviceEvent::ADD;
+ else if (!strcmp(action, "remove"))
+ action_type = DeviceEvent::REMOVE;
+ else if (!strcmp(action, "change"))
+ action_type = DeviceEvent::CHANGE;
+ else
+ return scoped_ptr<DeviceEvent>();
+
+ return scoped_ptr<DeviceEvent>(
+ new DeviceEvent(device_type, action_type, base::FilePath(path)));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/device/udev/device_manager_udev.h b/chromium/ui/events/ozone/device/udev/device_manager_udev.h
new file mode 100644
index 00000000000..8a7537abebe
--- /dev/null
+++ b/chromium/ui/events/ozone/device/udev/device_manager_udev.h
@@ -0,0 +1,51 @@
+// 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_OZONE_DEVICE_UDEV_DEVICE_MANAGER_UDEV_H_
+#define UI_EVENTS_OZONE_DEVICE_UDEV_DEVICE_MANAGER_UDEV_H_
+
+#include "base/message_loop/message_pump_libevent.h"
+#include "base/observer_list.h"
+#include "device/udev_linux/udev.h"
+#include "ui/events/ozone/device/device_manager.h"
+
+namespace ui {
+
+class DeviceEvent;
+class DeviceEventObserver;
+
+class DeviceManagerUdev
+ : public DeviceManager, base::MessagePumpLibevent::Watcher {
+ public:
+ DeviceManagerUdev();
+ virtual ~DeviceManagerUdev();
+
+ private:
+ scoped_ptr<DeviceEvent> ProcessMessage(udev_device* device);
+
+ // Creates a device-monitor to look for device add/remove/change events.
+ void CreateMonitor();
+
+ // DeviceManager overrides:
+ virtual void ScanDevices(DeviceEventObserver* observer) OVERRIDE;
+ virtual void AddObserver(DeviceEventObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(DeviceEventObserver* observer) OVERRIDE;
+
+ // base::MessagePumpLibevent::Watcher overrides:
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ device::ScopedUdevPtr udev_;
+ device::ScopedUdevMonitorPtr monitor_;
+
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ ObserverList<DeviceEventObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceManagerUdev);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_DEVICE_UDEV_DEVICE_MANAGER_UDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/cursor_delegate_evdev.h b/chromium/ui/events/ozone/evdev/cursor_delegate_evdev.h
new file mode 100644
index 00000000000..7ff01befd9e
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/cursor_delegate_evdev.h
@@ -0,0 +1,31 @@
+// 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_OZONE_EVDEV_CURSOR_DELEGATE_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_CURSOR_DELEGATE_EVDEV_H_
+
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Vector2dF;
+}
+
+namespace ui {
+
+class EVENTS_OZONE_EVDEV_EXPORT CursorDelegateEvdev {
+ public:
+ // Move the cursor.
+ virtual void MoveCursor(const gfx::Vector2dF& delta) = 0;
+ virtual void MoveCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) = 0;
+
+ // Location in window.
+ virtual gfx::PointF location() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_CURSOR_DELEGATE_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/event_converter_evdev.cc
new file mode 100644
index 00000000000..5b1e9a58981
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -0,0 +1,23 @@
+// 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/events/ozone/evdev/event_converter_evdev.h"
+
+#include "ui/events/event.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+
+namespace ui {
+
+EventConverterEvdev::EventConverterEvdev() {}
+
+EventConverterEvdev::EventConverterEvdev(const EventDispatchCallback& callback)
+ : dispatch_callback_(callback) {}
+
+EventConverterEvdev::~EventConverterEvdev() {}
+
+void EventConverterEvdev::DispatchEventToCallback(ui::Event* event) {
+ dispatch_callback_.Run(event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_converter_evdev.h b/chromium/ui/events/ozone/evdev/event_converter_evdev.h
new file mode 100644
index 00000000000..ebc36fcc5a2
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_converter_evdev.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_H_
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+
+namespace ui {
+
+class Event;
+class EventModifiersEvdev;
+
+typedef base::Callback<void(Event*)> EventDispatchCallback;
+
+// Base class for device-specific evdev event conversion.
+class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdev {
+ public:
+ EventConverterEvdev();
+ explicit EventConverterEvdev(const EventDispatchCallback& callback);
+ virtual ~EventConverterEvdev();
+
+ // Start converting events.
+ virtual void Start() = 0;
+
+ // Stop converting events.
+ virtual void Stop() = 0;
+
+ protected:
+ // Dispatches an event using the dispatch-callback set using
+ // |SetDispatchCalback()|.
+ virtual void DispatchEventToCallback(ui::Event* event);
+
+ private:
+ EventDispatchCallback dispatch_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventConverterEvdev);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.cc b/chromium/ui/events/ozone/evdev/event_device_info.cc
index 9621646d26b..2734b9d2f49 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info.cc
@@ -14,8 +14,6 @@ namespace ui {
namespace {
bool GetEventBits(int fd, unsigned int type, void* buf, unsigned int size) {
- base::ThreadRestrictions::AssertIOAllowed();
-
if (ioctl(fd, EVIOCGBIT(type, size), buf) < 0) {
DLOG(ERROR) << "failed EVIOCGBIT(" << type << ", " << size << ") on fd "
<< fd;
@@ -26,8 +24,6 @@ bool GetEventBits(int fd, unsigned int type, void* buf, unsigned int size) {
}
bool GetPropBits(int fd, void* buf, unsigned int size) {
- base::ThreadRestrictions::AssertIOAllowed();
-
if (ioctl(fd, EVIOCGPROP(size), buf) < 0) {
DLOG(ERROR) << "failed EVIOCGPROP(" << size << ") on fd " << fd;
return false;
@@ -40,6 +36,14 @@ bool BitIsSet(const unsigned long* bits, unsigned int bit) {
return (bits[bit / EVDEV_LONG_BITS] & (1UL << (bit % EVDEV_LONG_BITS)));
}
+bool GetAbsInfo(int fd, int code, struct input_absinfo* absinfo) {
+ if (ioctl(fd, EVIOCGABS(code), absinfo)) {
+ DLOG(ERROR) << "failed EVIOCGABS(" << code << ") on fd " << fd;
+ return false;
+ }
+ return true;
+}
+
} // namespace
EventDeviceInfo::EventDeviceInfo() {
@@ -51,6 +55,7 @@ EventDeviceInfo::EventDeviceInfo() {
memset(sw_bits_, 0, sizeof(sw_bits_));
memset(led_bits_, 0, sizeof(led_bits_));
memset(prop_bits_, 0, sizeof(prop_bits_));
+ memset(abs_info_, 0, sizeof(abs_info_));
}
EventDeviceInfo::~EventDeviceInfo() {}
@@ -80,6 +85,11 @@ bool EventDeviceInfo::Initialize(int fd) {
if (!GetPropBits(fd, prop_bits_, sizeof(prop_bits_)))
return false;
+ for (unsigned int i = 0; i < ABS_CNT; ++i)
+ if (HasAbsEvent(i))
+ if (!GetAbsInfo(fd, i, &abs_info_[i]))
+ return false;
+
return true;
}
@@ -131,4 +141,49 @@ bool EventDeviceInfo::HasProp(unsigned int code) const {
return BitIsSet(prop_bits_, code);
}
+int32 EventDeviceInfo::GetAbsMinimum(unsigned int code) const {
+ return abs_info_[code].minimum;
+}
+
+int32 EventDeviceInfo::GetAbsMaximum(unsigned int code) const {
+ return abs_info_[code].maximum;
+}
+
+bool EventDeviceInfo::HasAbsXY() const {
+ if (HasAbsEvent(ABS_X) && HasAbsEvent(ABS_Y))
+ return true;
+
+ if (HasAbsEvent(ABS_MT_POSITION_X) && HasAbsEvent(ABS_MT_POSITION_Y))
+ return true;
+
+ return false;
+}
+
+bool EventDeviceInfo::HasRelXY() const {
+ return HasRelEvent(REL_X) && HasRelEvent(REL_Y);
+}
+
+bool EventDeviceInfo::IsMappedToScreen() const {
+ // Device position is mapped directly to the screen.
+ if (HasProp(INPUT_PROP_DIRECT))
+ return true;
+
+ // Device position moves the cursor.
+ if (HasProp(INPUT_PROP_POINTER))
+ return false;
+
+ // Tablets are mapped to the screen.
+ if (HasKeyEvent(BTN_TOOL_PEN) || HasKeyEvent(BTN_STYLUS) ||
+ HasKeyEvent(BTN_STYLUS2))
+ return true;
+
+ // Touchpads are not mapped to the screen.
+ if (HasKeyEvent(BTN_LEFT) || HasKeyEvent(BTN_MIDDLE) ||
+ HasKeyEvent(BTN_RIGHT) || HasKeyEvent(BTN_TOOL_FINGER))
+ return false;
+
+ // Touchscreens are mapped to the screen.
+ return true;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.h b/chromium/ui/events/ozone/evdev/event_device_info.h
index b4b1c05c233..492539bd83a 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.h
+++ b/chromium/ui/events/ozone/evdev/event_device_info.h
@@ -9,6 +9,7 @@
#include <linux/input.h>
#include "base/basictypes.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
#define EVDEV_LONG_BITS (CHAR_BIT * sizeof(long))
#define EVDEV_BITS_TO_LONGS(x) (((x) + EVDEV_LONG_BITS - 1) / EVDEV_LONG_BITS)
@@ -19,7 +20,7 @@ namespace ui {
//
// This stores and queries information about input devices; in
// particular it knows which events the device can generate.
-class EventDeviceInfo {
+class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
public:
EventDeviceInfo();
~EventDeviceInfo();
@@ -36,9 +37,23 @@ class EventDeviceInfo {
bool HasSwEvent(unsigned int code) const;
bool HasLedEvent(unsigned int code) const;
+ // Properties of absolute axes.
+ int32 GetAbsMinimum(unsigned int code) const;
+ int32 GetAbsMaximum(unsigned int code) const;
+
// Check input device properties.
bool HasProp(unsigned int code) const;
+ // Has absolute X & Y axes.
+ bool HasAbsXY() const;
+
+ // Has relativeX & Y axes.
+ bool HasRelXY() const;
+
+ // Determine whether absolute device X/Y coordinates are mapped onto the
+ // screen. This is the case for touchscreens and tablets but not touchpads.
+ bool IsMappedToScreen() const;
+
private:
unsigned long ev_bits_[EVDEV_BITS_TO_LONGS(EV_CNT)];
unsigned long key_bits_[EVDEV_BITS_TO_LONGS(KEY_CNT)];
@@ -49,6 +64,8 @@ class EventDeviceInfo {
unsigned long led_bits_[EVDEV_BITS_TO_LONGS(LED_CNT)];
unsigned long prop_bits_[EVDEV_BITS_TO_LONGS(INPUT_PROP_CNT)];
+ struct input_absinfo abs_info_[ABS_CNT];
+
DISALLOW_COPY_AND_ASSIGN(EventDeviceInfo);
};
diff --git a/chromium/ui/events/ozone/evdev/event_factory.cc b/chromium/ui/events/ozone/evdev/event_factory.cc
deleted file mode 100644
index 9c3f9713730..00000000000
--- a/chromium/ui/events/ozone/evdev/event_factory.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/event_factory.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "base/strings/stringprintf.h"
-#include "ui/events/ozone/evdev/event_device_info.h"
-#include "ui/events/ozone/evdev/key_event_converter.h"
-#include "ui/events/ozone/evdev/touch_event_converter.h"
-#include "ui/events/ozone/event_factory_ozone.h"
-
-namespace ui {
-
-namespace {
-
-bool IsTouchPad(const EventDeviceInfo& devinfo) {
- if (!devinfo.HasEventType(EV_ABS))
- return false;
-
- return devinfo.HasKeyEvent(BTN_LEFT) || devinfo.HasKeyEvent(BTN_MIDDLE) ||
- devinfo.HasKeyEvent(BTN_RIGHT) || devinfo.HasKeyEvent(BTN_TOOL_FINGER);
-}
-
-bool IsTouchScreen(const EventDeviceInfo& devinfo) {
- return devinfo.HasEventType(EV_ABS) && !IsTouchPad(devinfo);
-}
-
-} // namespace
-
-EventFactoryEvdev::EventFactoryEvdev() {}
-
-EventFactoryEvdev::~EventFactoryEvdev() {}
-
-void EventFactoryEvdev::StartProcessingEvents() {
- // The number of devices in the directory is unknown without reading
- // the contents of the directory. Further, with hot-plugging, the entries
- // might decrease during the execution of this loop. So exciting from the
- // loop on the first failure of open below is both cheaper and more
- // reliable.
- for (int id = 0; true; id++) {
- std::string path = base::StringPrintf("/dev/input/event%d", id);
- int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno);
- break;
- }
-
- EventDeviceInfo devinfo;
- if (!devinfo.Initialize(fd)) {
- DLOG(ERROR) << "failed to get device information for " << path;
- close(fd);
- continue;
- }
-
- if (IsTouchPad(devinfo)) {
- LOG(WARNING) << "touchpad device not supported: " << path;
- close(fd);
- continue;
- }
-
- scoped_ptr<EventConverterOzone> converter;
- // TODO(rjkroege) Add more device types. Support hot-plugging.
- if (IsTouchScreen(devinfo))
- converter.reset(new TouchEventConverterEvdev(fd, id));
- else if (devinfo.HasEventType(EV_KEY))
- converter.reset(new KeyEventConverterEvdev(fd, id, &modifiers_));
-
- if (converter) {
- AddEventConverter(fd, converter.Pass());
- } else {
- close(fd);
- }
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_factory.h b/chromium/ui/events/ozone/evdev/event_factory.h
deleted file mode 100644
index b0e7a0a633f..00000000000
--- a/chromium/ui/events/ozone/evdev/event_factory.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
-#define UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
-
-#include "base/compiler_specific.h"
-#include "ui/events/events_export.h"
-#include "ui/events/ozone/evdev/event_modifiers.h"
-#include "ui/events/ozone/event_factory_ozone.h"
-
-namespace ui {
-
-// Ozone events implementation for the Linux input subsystem ("evdev").
-class EVENTS_EXPORT EventFactoryEvdev : public EventFactoryOzone {
- public:
- EventFactoryEvdev();
- virtual ~EventFactoryEvdev();
-
- virtual void StartProcessingEvents() OVERRIDE;
-
- private:
- EventModifiersEvdev modifiers_;
-
- DISALLOW_COPY_AND_ASSIGN(EventFactoryEvdev);
-};
-
-} // namespace ui
-
-#endif // UI_EVENTS_OZONE_EVENT_FACTORY_DELEGATE_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/event_factory_evdev.cc b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
new file mode 100644
index 00000000000..216488ee5b0
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -0,0 +1,242 @@
+// 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/events/ozone/evdev/event_factory_evdev.h"
+
+#include <fcntl.h>
+#include <linux/input.h>
+
+#include "base/debug/trace_event.h"
+#include "base/stl_util.h"
+#include "base/task_runner.h"
+#include "base/threading/worker_pool.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/key_event_converter_evdev.h"
+#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
+
+#if defined(USE_EVDEV_GESTURES)
+#include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h"
+#endif
+
+#ifndef EVIOCSCLOCKID
+#define EVIOCSCLOCKID _IOW('E', 0xa0, int)
+#endif
+
+namespace ui {
+
+namespace {
+
+#if defined(USE_EVDEV_GESTURES)
+bool UseGesturesLibraryForDevice(const EventDeviceInfo& devinfo) {
+ if (devinfo.HasAbsXY() && !devinfo.IsMappedToScreen())
+ return true; // touchpad
+
+ if (devinfo.HasRelXY())
+ return true; // mouse
+
+ return false;
+}
+#endif
+
+scoped_ptr<EventConverterEvdev> CreateConverter(
+ int fd,
+ const base::FilePath& path,
+ const EventDeviceInfo& devinfo,
+ const EventDispatchCallback& dispatch,
+ EventModifiersEvdev* modifiers,
+ CursorDelegateEvdev* cursor) {
+#if defined(USE_EVDEV_GESTURES)
+ // Touchpad or mouse: use gestures library.
+ // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent
+ if (UseGesturesLibraryForDevice(devinfo)) {
+ scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = make_scoped_ptr(
+ new GestureInterpreterLibevdevCros(modifiers, cursor, dispatch));
+ scoped_ptr<EventReaderLibevdevCros> libevdev_reader =
+ make_scoped_ptr(new EventReaderLibevdevCros(
+ fd,
+ path,
+ gesture_interp.PassAs<EventReaderLibevdevCros::Delegate>()));
+ return libevdev_reader.PassAs<EventConverterEvdev>();
+ }
+#endif
+
+ // Touchscreen: use TouchEventConverterEvdev.
+ scoped_ptr<EventConverterEvdev> converter;
+ if (devinfo.HasAbsXY())
+ return make_scoped_ptr<EventConverterEvdev>(
+ new TouchEventConverterEvdev(fd, path, devinfo, dispatch));
+
+ // Everything else: use KeyEventConverterEvdev.
+ return make_scoped_ptr<EventConverterEvdev>(
+ new KeyEventConverterEvdev(fd, path, modifiers, dispatch));
+}
+
+// Open an input device. Opening may put the calling thread to sleep, and
+// therefore should be run on a thread where latency is not critical. We
+// run it on a thread from the worker pool.
+//
+// This takes a TaskRunner and runs the reply on that thread, so that we
+// can hop threads if necessary (back to the UI thread).
+void OpenInputDevice(
+ const base::FilePath& path,
+ EventModifiersEvdev* modifiers,
+ CursorDelegateEvdev* cursor,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const EventDispatchCallback& dispatch,
+ base::Callback<void(scoped_ptr<EventConverterEvdev>)> reply_callback) {
+ TRACE_EVENT1("ozone", "OpenInputDevice", "path", path.value());
+
+ int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ PLOG(ERROR) << "Cannot open '" << path.value();
+ return;
+ }
+
+ // Use monotonic timestamps for events. The touch code in particular
+ // expects event timestamps to correlate to the monotonic clock
+ // (base::TimeTicks).
+ unsigned int clk = CLOCK_MONOTONIC;
+ if (ioctl(fd, EVIOCSCLOCKID, &clk))
+ PLOG(ERROR) << "failed to set CLOCK_MONOTONIC";
+
+ EventDeviceInfo devinfo;
+ if (!devinfo.Initialize(fd)) {
+ LOG(ERROR) << "failed to get device information for " << path.value();
+ close(fd);
+ return;
+ }
+
+ scoped_ptr<EventConverterEvdev> converter =
+ CreateConverter(fd, path, devinfo, dispatch, modifiers, cursor);
+
+ // Reply with the constructed converter.
+ reply_runner->PostTask(FROM_HERE,
+ base::Bind(reply_callback, base::Passed(&converter)));
+}
+
+// Close an input device. Closing may put the calling thread to sleep, and
+// therefore should be run on a thread where latency is not critical. We
+// run it on the FILE thread.
+void CloseInputDevice(const base::FilePath& path,
+ scoped_ptr<EventConverterEvdev> converter) {
+ TRACE_EVENT1("ozone", "CloseInputDevice", "path", path.value());
+ converter.reset();
+}
+
+} // namespace
+
+EventFactoryEvdev::EventFactoryEvdev(
+ CursorDelegateEvdev* cursor,
+ DeviceManager* device_manager)
+ : device_manager_(device_manager),
+ cursor_(cursor),
+ dispatch_callback_(
+ base::Bind(base::IgnoreResult(&EventFactoryEvdev::DispatchUiEvent),
+ base::Unretained(this))),
+ weak_ptr_factory_(this) {
+ CHECK(device_manager_);
+}
+
+EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); }
+
+void EventFactoryEvdev::DispatchUiEvent(Event* event) {
+ DispatchEvent(event);
+}
+
+void EventFactoryEvdev::AttachInputDevice(
+ const base::FilePath& path,
+ scoped_ptr<EventConverterEvdev> converter) {
+ TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
+ CHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+
+ // If we have an existing device, detach it. We don't want two
+ // devices with the same name open at the same time.
+ if (converters_[path])
+ DetachInputDevice(path);
+
+ // Add initialized device to map.
+ converters_[path] = converter.release();
+ converters_[path]->Start();
+}
+
+void EventFactoryEvdev::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::INPUT)
+ return;
+
+ switch (event.action_type()) {
+ case DeviceEvent::ADD:
+ case DeviceEvent::CHANGE: {
+ TRACE_EVENT1("ozone", "OnDeviceAdded", "path", event.path().value());
+
+ // Dispatch task to open from the worker pool, since open may block.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&OpenInputDevice,
+ event.path(),
+ &modifiers_,
+ cursor_,
+ ui_task_runner_,
+ dispatch_callback_,
+ base::Bind(&EventFactoryEvdev::AttachInputDevice,
+ weak_ptr_factory_.GetWeakPtr(),
+ event.path())),
+ true);
+ }
+ break;
+ case DeviceEvent::REMOVE: {
+ TRACE_EVENT1("ozone", "OnDeviceRemoved", "path", event.path().value());
+ DetachInputDevice(event.path());
+ }
+ break;
+ }
+}
+
+void EventFactoryEvdev::OnDispatcherListChanged() {
+ if (!ui_task_runner_) {
+ ui_task_runner_ = base::MessageLoopProxy::current();
+ // Scan & monitor devices.
+ device_manager_->AddObserver(this);
+ device_manager_->ScanDevices(this);
+ }
+}
+
+void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
+ TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
+ CHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+
+ // Remove device from map.
+ scoped_ptr<EventConverterEvdev> converter(converters_[path]);
+ converters_.erase(path);
+
+ if (converter) {
+ // Cancel libevent notifications from this converter. This part must be
+ // on UI since the polling happens on UI.
+ converter->Stop();
+
+ // Dispatch task to close from the worker pool, since close may block.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&CloseInputDevice, path, base::Passed(&converter)),
+ true);
+ }
+}
+
+void EventFactoryEvdev::WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) {
+ if (cursor_) {
+ cursor_->MoveCursorTo(widget, location);
+ MouseEvent mouse_event(ET_MOUSE_MOVED,
+ cursor_->location(),
+ cursor_->location(),
+ modifiers_.GetModifierFlags(),
+ /* changed_button_flags */ 0);
+ DispatchEvent(&mouse_event);
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_factory_evdev.h b/chromium/ui/events/ozone/evdev/event_factory_evdev.h
new file mode 100644
index 00000000000..3eb11d23822
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_factory_evdev.h
@@ -0,0 +1,82 @@
+// 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_OZONE_EVDEV_EVENT_FACTORY_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_EVENT_FACTORY_EVDEV_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/events/ozone/evdev/event_converter_evdev.h"
+#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+
+namespace ui {
+
+class CursorDelegateEvdev;
+class DeviceManager;
+
+// Ozone events implementation for the Linux input subsystem ("evdev").
+class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public EventFactoryOzone,
+ public DeviceEventObserver,
+ public PlatformEventSource {
+ public:
+ EventFactoryEvdev(CursorDelegateEvdev* cursor,
+ DeviceManager* device_manager);
+ virtual ~EventFactoryEvdev();
+
+ void DispatchUiEvent(Event* event);
+
+ // EventFactoryOzone:
+ virtual void WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) OVERRIDE;
+
+ private:
+ // Open device at path & starting processing events (on UI thread).
+ void AttachInputDevice(const base::FilePath& file_path,
+ scoped_ptr<EventConverterEvdev> converter);
+
+ // Close device at path (on UI thread).
+ void DetachInputDevice(const base::FilePath& file_path);
+
+ // DeviceEventObserver overrides:
+ //
+ // Callback for device add (on UI thread).
+ virtual void OnDeviceEvent(const DeviceEvent& event) OVERRIDE;
+
+ // PlatformEventSource:
+ virtual void OnDispatcherListChanged() OVERRIDE;
+
+ // Owned per-device event converters (by path).
+ std::map<base::FilePath, EventConverterEvdev*> converters_;
+
+ // Interface for scanning & monitoring input devices.
+ DeviceManager* device_manager_; // Not owned.
+
+ // Task runner for event dispatch.
+ scoped_refptr<base::TaskRunner> ui_task_runner_;
+
+ // Modifier key state (shift, ctrl, etc).
+ EventModifiersEvdev modifiers_;
+
+ // Cursor movement.
+ CursorDelegateEvdev* cursor_;
+
+ // Dispatch callback for events.
+ EventDispatchCallback dispatch_callback_;
+
+ // Support weak pointers for attach & detach callbacks.
+ base::WeakPtrFactory<EventFactoryEvdev> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventFactoryEvdev);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_EVENT_FACTORY_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/event_modifiers.cc b/chromium/ui/events/ozone/evdev/event_modifiers.cc
deleted file mode 100644
index 220ec083c3b..00000000000
--- a/chromium/ui/events/ozone/evdev/event_modifiers.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/event_modifiers.h"
-
-#include <linux/input.h>
-
-#include "ui/events/event.h"
-
-namespace ui {
-
-namespace {
-
-static const int kEventFlagFromModifiers[] = {
- EF_NONE, // EVDEV_MODIFIER_NONE,
- EF_CAPS_LOCK_DOWN, // EVDEV_MODIFIER_CAPS_LOCK
- EF_SHIFT_DOWN, // EVDEV_MODIFIER_SHIFT
- EF_CONTROL_DOWN, // EVDEV_MODIFIER_CONTROL
- EF_ALT_DOWN, // EVDEV_MODIFIER_ALT
- EF_LEFT_MOUSE_BUTTON, // EVDEV_MODIFIER_LEFT_MOUSE_BUTTON
- EF_MIDDLE_MOUSE_BUTTON, // EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON
- EF_RIGHT_MOUSE_BUTTON, // EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON
- EF_COMMAND_DOWN, // EVDEV_MODIFIER_COMMAND
- EF_ALTGR_DOWN, // EVDEV_MODIFIER_ALTGR
-};
-
-} // namespace
-
-EventModifiersEvdev::EventModifiersEvdev()
- : modifier_flags_locked_(0), modifier_flags_(0) {
- memset(modifiers_down_, 0, sizeof(modifiers_down_));
-}
-EventModifiersEvdev::~EventModifiersEvdev() {}
-
-void EventModifiersEvdev::UpdateModifier(unsigned int modifier, bool down) {
- CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
-
- if (down) {
- modifiers_down_[modifier]++;
- } else {
- // Ignore spurious modifier "up" events. This might happen if the
- // button is down during startup.
- if (modifiers_down_[modifier])
- modifiers_down_[modifier]--;
- }
-
- UpdateFlags(modifier);
-}
-
-void EventModifiersEvdev::UpdateModifierLock(unsigned int modifier, bool down) {
- CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
-
- if (down)
- modifier_flags_locked_ ^= kEventFlagFromModifiers[modifier];
-
- // TODO(spang): Synchronize with the CapsLock LED.
-
- UpdateFlags(modifier);
-}
-
-void EventModifiersEvdev::UpdateFlags(unsigned int modifier) {
- int mask = kEventFlagFromModifiers[modifier];
- bool down = modifiers_down_[modifier];
- bool locked = (modifier_flags_locked_ & mask);
- if (down != locked)
- modifier_flags_ |= mask;
- else
- modifier_flags_ &= ~mask;
-}
-
-int EventModifiersEvdev::GetModifierFlags() { return modifier_flags_; }
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_modifiers.h b/chromium/ui/events/ozone/evdev/event_modifiers.h
deleted file mode 100644
index 225af026fbc..00000000000
--- a/chromium/ui/events/ozone/evdev/event_modifiers.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
-#define UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
-
-#include "ui/events/events_export.h"
-#include "ui/events/ozone/event_converter_ozone.h"
-
-namespace ui {
-
-enum {
- EVDEV_MODIFIER_NONE,
- EVDEV_MODIFIER_CAPS_LOCK,
- EVDEV_MODIFIER_SHIFT,
- EVDEV_MODIFIER_CONTROL,
- EVDEV_MODIFIER_ALT,
- EVDEV_MODIFIER_LEFT_MOUSE_BUTTON,
- EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON,
- EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON,
- EVDEV_MODIFIER_COMMAND,
- EVDEV_MODIFIER_ALTGR,
- EVDEV_NUM_MODIFIERS
-};
-
-// Modifier key state for Evdev.
-//
-// Chrome relies on the underlying OS to interpret modifier keys such as Shift,
-// Ctrl, and Alt. The Linux input subsystem does not assign any special meaning
-// to these keys, so this work must happen at a higher layer (normally X11 or
-// the console driver). When using evdev directly, we must do it ourselves.
-//
-// The modifier state is shared between all input devices connected to the
-// system. This is to support actions such as Shift-Clicking that use multiple
-// devices.
-//
-// Normally a modifier is set if any of the keys or buttons assigned to it are
-// currently pressed. However some keys toggle a persistent "lock" for the
-// modifier instead, such as CapsLock. If a modifier is "locked" then its state
-// is inverted until it is unlocked.
-class EVENTS_EXPORT EventModifiersEvdev {
- public:
- EventModifiersEvdev();
- ~EventModifiersEvdev();
-
- // Record key press or release for regular modifier key (shift, alt, etc).
- void UpdateModifier(unsigned int modifier, bool down);
-
- // Record key press or release for locking modifier key (caps lock).
- void UpdateModifierLock(unsigned int modifier, bool down);
-
- // Return current flags to use for incoming events.
- int GetModifierFlags();
-
- private:
- // Count of keys pressed for each modifier.
- int modifiers_down_[EVDEV_NUM_MODIFIERS];
-
- // Mask of modifier flags currently "locked".
- int modifier_flags_locked_;
-
- // Mask of modifier flags currently active (nonzero keys pressed xor locked).
- int modifier_flags_;
-
- // Update modifier_flags_ from modifiers_down_ and modifier_flags_locked_.
- void UpdateFlags(unsigned int modifier);
-
- DISALLOW_COPY_AND_ASSIGN(EventModifiersEvdev);
-};
-
-} // namspace ui
-
-#endif // UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_H_
diff --git a/chromium/ui/events/ozone/evdev/event_modifiers_evdev.cc b/chromium/ui/events/ozone/evdev/event_modifiers_evdev.cc
new file mode 100644
index 00000000000..d867b5eef7d
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_modifiers_evdev.cc
@@ -0,0 +1,79 @@
+// 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/events/ozone/evdev/event_modifiers_evdev.h"
+
+#include <linux/input.h>
+
+#include "ui/events/event.h"
+
+namespace ui {
+
+namespace {
+
+static const int kEventFlagFromModifiers[] = {
+ EF_NONE, // EVDEV_MODIFIER_NONE,
+ EF_CAPS_LOCK_DOWN, // EVDEV_MODIFIER_CAPS_LOCK
+ EF_SHIFT_DOWN, // EVDEV_MODIFIER_SHIFT
+ EF_CONTROL_DOWN, // EVDEV_MODIFIER_CONTROL
+ EF_ALT_DOWN, // EVDEV_MODIFIER_ALT
+ EF_LEFT_MOUSE_BUTTON, // EVDEV_MODIFIER_LEFT_MOUSE_BUTTON
+ EF_MIDDLE_MOUSE_BUTTON, // EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON
+ EF_RIGHT_MOUSE_BUTTON, // EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON
+ EF_COMMAND_DOWN, // EVDEV_MODIFIER_COMMAND
+ EF_ALTGR_DOWN, // EVDEV_MODIFIER_ALTGR
+};
+
+} // namespace
+
+EventModifiersEvdev::EventModifiersEvdev()
+ : modifier_flags_locked_(0), modifier_flags_(0) {
+ memset(modifiers_down_, 0, sizeof(modifiers_down_));
+}
+EventModifiersEvdev::~EventModifiersEvdev() {}
+
+void EventModifiersEvdev::UpdateModifier(unsigned int modifier, bool down) {
+ CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
+
+ if (down) {
+ modifiers_down_[modifier]++;
+ } else {
+ // Ignore spurious modifier "up" events. This might happen if the
+ // button is down during startup.
+ if (modifiers_down_[modifier])
+ modifiers_down_[modifier]--;
+ }
+
+ UpdateFlags(modifier);
+}
+
+void EventModifiersEvdev::UpdateModifierLock(unsigned int modifier, bool down) {
+ CHECK_LT(modifier, EVDEV_NUM_MODIFIERS);
+
+ if (down)
+ modifier_flags_locked_ ^= kEventFlagFromModifiers[modifier];
+
+ // TODO(spang): Synchronize with the CapsLock LED.
+
+ UpdateFlags(modifier);
+}
+
+void EventModifiersEvdev::UpdateFlags(unsigned int modifier) {
+ int mask = kEventFlagFromModifiers[modifier];
+ bool down = modifiers_down_[modifier];
+ bool locked = (modifier_flags_locked_ & mask);
+ if (down != locked)
+ modifier_flags_ |= mask;
+ else
+ modifier_flags_ &= ~mask;
+}
+
+int EventModifiersEvdev::GetModifierFlags() { return modifier_flags_; }
+
+// static
+int EventModifiersEvdev::GetEventFlagFromModifier(unsigned int modifier) {
+ return kEventFlagFromModifiers[modifier];
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_modifiers_evdev.h b/chromium/ui/events/ozone/evdev/event_modifiers_evdev.h
new file mode 100644
index 00000000000..d10bb8cc4db
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/event_modifiers_evdev.h
@@ -0,0 +1,77 @@
+// 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_OZONE_EVDEV_EVENT_MODIFIERS_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_EVDEV_H_
+
+#include "base/basictypes.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+
+namespace ui {
+
+enum {
+ EVDEV_MODIFIER_NONE,
+ EVDEV_MODIFIER_CAPS_LOCK,
+ EVDEV_MODIFIER_SHIFT,
+ EVDEV_MODIFIER_CONTROL,
+ EVDEV_MODIFIER_ALT,
+ EVDEV_MODIFIER_LEFT_MOUSE_BUTTON,
+ EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON,
+ EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON,
+ EVDEV_MODIFIER_COMMAND,
+ EVDEV_MODIFIER_ALTGR,
+ EVDEV_NUM_MODIFIERS
+};
+
+// Modifier key state for Evdev.
+//
+// Chrome relies on the underlying OS to interpret modifier keys such as Shift,
+// Ctrl, and Alt. The Linux input subsystem does not assign any special meaning
+// to these keys, so this work must happen at a higher layer (normally X11 or
+// the console driver). When using evdev directly, we must do it ourselves.
+//
+// The modifier state is shared between all input devices connected to the
+// system. This is to support actions such as Shift-Clicking that use multiple
+// devices.
+//
+// Normally a modifier is set if any of the keys or buttons assigned to it are
+// currently pressed. However some keys toggle a persistent "lock" for the
+// modifier instead, such as CapsLock. If a modifier is "locked" then its state
+// is inverted until it is unlocked.
+class EVENTS_OZONE_EVDEV_EXPORT EventModifiersEvdev {
+ public:
+ EventModifiersEvdev();
+ ~EventModifiersEvdev();
+
+ // Record key press or release for regular modifier key (shift, alt, etc).
+ void UpdateModifier(unsigned int modifier, bool down);
+
+ // Record key press or release for locking modifier key (caps lock).
+ void UpdateModifierLock(unsigned int modifier, bool down);
+
+ // Return current flags to use for incoming events.
+ int GetModifierFlags();
+
+ // Return the mask for the specified modifier.
+ static int GetEventFlagFromModifier(unsigned int modifier);
+
+ private:
+ // Count of keys pressed for each modifier.
+ int modifiers_down_[EVDEV_NUM_MODIFIERS];
+
+ // Mask of modifier flags currently "locked".
+ int modifier_flags_locked_;
+
+ // Mask of modifier flags currently active (nonzero keys pressed xor locked).
+ int modifier_flags_;
+
+ // Update modifier_flags_ from modifiers_down_ and modifier_flags_locked_.
+ void UpdateFlags(unsigned int modifier);
+
+ DISALLOW_COPY_AND_ASSIGN(EventModifiersEvdev);
+};
+
+} // namspace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_EVENT_MODIFIERS_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/events_ozone_evdev_export.h b/chromium/ui/events/ozone/evdev/events_ozone_evdev_export.h
new file mode 100644
index 00000000000..4a4cbacee64
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/events_ozone_evdev_export.h
@@ -0,0 +1,29 @@
+// 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_OZONE_EVDEV_EVENTS_OZONE_EVDEV_EXPORT_H_
+#define UI_EVENTS_OZONE_EVDEV_EVENTS_OZONE_EVDEV_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(EVENTS_OZONE_EVDEV_IMPLEMENTATION)
+#define EVENTS_OZONE_EVDEV_EXPORT __declspec(dllexport)
+#else
+#define EVENTS_OZONE_EVDEV_EXPORT __declspec(dllimport)
+#endif // defined(EVENTS_OZONE_EVDEV_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(EVENTS_OZONE_EVDEV_IMPLEMENTATION)
+#define EVENTS_OZONE_EVDEV_EXPORT __attribute__((visibility("default")))
+#else
+#define EVENTS_OZONE_EVDEV_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define EVENTS_OZONE_EVDEV_EXPORT
+#endif
+
+#endif // UI_EVENTS_OZONE_EVDEV_EVENTS_OZONE_EVDEV_EXPORT_H_
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter.cc b/chromium/ui/events/ozone/evdev/key_event_converter.cc
deleted file mode 100644
index b739b34a53c..00000000000
--- a/chromium/ui/events/ozone/evdev/key_event_converter.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/key_event_converter.h"
-
-#include <linux/input.h>
-
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/events/ozone/evdev/event_modifiers.h"
-
-namespace ui {
-
-namespace {
-
-ui::KeyboardCode KeyboardCodeFromButton(unsigned int code) {
- static const ui::KeyboardCode kLinuxBaseKeyMap[] = {
- ui::VKEY_UNKNOWN, // KEY_RESERVED
- ui::VKEY_ESCAPE, // KEY_ESC
- ui::VKEY_1, // KEY_1
- ui::VKEY_2, // KEY_2
- ui::VKEY_3, // KEY_3
- ui::VKEY_4, // KEY_4
- ui::VKEY_5, // KEY_5
- ui::VKEY_6, // KEY_6
- ui::VKEY_7, // KEY_7
- ui::VKEY_8, // KEY_8
- ui::VKEY_9, // KEY_9
- ui::VKEY_0, // KEY_0
- ui::VKEY_OEM_MINUS, // KEY_MINUS
- ui::VKEY_OEM_PLUS, // KEY_EQUAL
- ui::VKEY_BACK, // KEY_BACKSPACE
- ui::VKEY_TAB, // KEY_TAB
- ui::VKEY_Q, // KEY_Q
- ui::VKEY_W, // KEY_W
- ui::VKEY_E, // KEY_E
- ui::VKEY_R, // KEY_R
- ui::VKEY_T, // KEY_T
- ui::VKEY_Y, // KEY_Y
- ui::VKEY_U, // KEY_U
- ui::VKEY_I, // KEY_I
- ui::VKEY_O, // KEY_O
- ui::VKEY_P, // KEY_P
- ui::VKEY_OEM_4, // KEY_LEFTBRACE
- ui::VKEY_OEM_6, // KEY_RIGHTBRACE
- ui::VKEY_RETURN, // KEY_ENTER
- ui::VKEY_CONTROL, // KEY_LEFTCTRL
- ui::VKEY_A, // KEY_A
- ui::VKEY_S, // KEY_S
- ui::VKEY_D, // KEY_D
- ui::VKEY_F, // KEY_F
- ui::VKEY_G, // KEY_G
- ui::VKEY_H, // KEY_H
- ui::VKEY_J, // KEY_J
- ui::VKEY_K, // KEY_K
- ui::VKEY_L, // KEY_L
- ui::VKEY_OEM_1, // KEY_SEMICOLON
- ui::VKEY_OEM_7, // KEY_APOSTROPHE
- ui::VKEY_OEM_3, // KEY_GRAVE
- ui::VKEY_SHIFT, // KEY_LEFTSHIFT
- ui::VKEY_OEM_5, // KEY_BACKSLASH
- ui::VKEY_Z, // KEY_Z
- ui::VKEY_X, // KEY_X
- ui::VKEY_C, // KEY_C
- ui::VKEY_V, // KEY_V
- ui::VKEY_B, // KEY_B
- ui::VKEY_N, // KEY_N
- ui::VKEY_M, // KEY_M
- ui::VKEY_OEM_COMMA, // KEY_COMMA
- ui::VKEY_OEM_PERIOD, // KEY_DOT
- ui::VKEY_OEM_2, // KEY_SLASH
- ui::VKEY_SHIFT, // KEY_RIGHTSHIFT
- ui::VKEY_MULTIPLY, // KEY_KPASTERISK
- ui::VKEY_MENU, // KEY_LEFTALT
- ui::VKEY_SPACE, // KEY_SPACE
- ui::VKEY_CAPITAL, // KEY_CAPSLOCK
- ui::VKEY_F1, // KEY_F1
- ui::VKEY_F2, // KEY_F2
- ui::VKEY_F3, // KEY_F3
- ui::VKEY_F4, // KEY_F4
- ui::VKEY_F5, // KEY_F5
- ui::VKEY_F6, // KEY_F6
- ui::VKEY_F7, // KEY_F7
- ui::VKEY_F8, // KEY_F8
- ui::VKEY_F9, // KEY_F9
- ui::VKEY_F10, // KEY_F10
- ui::VKEY_NUMLOCK, // KEY_NUMLOCK
- ui::VKEY_SCROLL, // KEY_SCROLLLOCK
- ui::VKEY_NUMPAD7, // KEY_KP7
- ui::VKEY_NUMPAD8, // KEY_KP8
- ui::VKEY_NUMPAD9, // KEY_KP9
- ui::VKEY_SUBTRACT, // KEY_KPMINUS
- ui::VKEY_NUMPAD4, // KEY_KP4
- ui::VKEY_NUMPAD5, // KEY_KP5
- ui::VKEY_NUMPAD6, // KEY_KP6
- ui::VKEY_ADD, // KEY_KPPLUS
- ui::VKEY_NUMPAD1, // KEY_KP1
- ui::VKEY_NUMPAD2, // KEY_KP2
- ui::VKEY_NUMPAD3, // KEY_KP3
- ui::VKEY_NUMPAD0, // KEY_KP0
- ui::VKEY_DECIMAL, // KEY_KPDOT
- ui::VKEY_UNKNOWN, // (unassigned)
- ui::VKEY_DBE_DBCSCHAR, // KEY_ZENKAKUHANKAKU
- ui::VKEY_OEM_102, // KEY_102ND
- ui::VKEY_F11, // KEY_F11
- ui::VKEY_F12, // KEY_F12
- ui::VKEY_UNKNOWN, // KEY_RO
- ui::VKEY_UNKNOWN, // KEY_KATAKANA
- ui::VKEY_UNKNOWN, // KEY_HIRAGANA
- ui::VKEY_CONVERT, // KEY_HENKAN
- ui::VKEY_UNKNOWN, // KEY_KATAKANAHIRAGANA
- ui::VKEY_NONCONVERT, // KEY_MUHENKAN
- ui::VKEY_UNKNOWN, // KEY_KPJPCOMMA
- ui::VKEY_RETURN, // KEY_KPENTER
- ui::VKEY_CONTROL, // KEY_RIGHTCTRL
- ui::VKEY_DIVIDE, // KEY_KPSLASH
- ui::VKEY_PRINT, // KEY_SYSRQ
- ui::VKEY_MENU, // KEY_RIGHTALT
- ui::VKEY_RETURN, // KEY_LINEFEED
- ui::VKEY_HOME, // KEY_HOME
- ui::VKEY_UP, // KEY_UP
- ui::VKEY_PRIOR, // KEY_PAGEUP
- ui::VKEY_LEFT, // KEY_LEFT
- ui::VKEY_RIGHT, // KEY_RIGHT
- ui::VKEY_END, // KEY_END
- ui::VKEY_DOWN, // KEY_DOWN
- ui::VKEY_NEXT, // KEY_PAGEDOWN
- ui::VKEY_INSERT, // KEY_INSERT
- ui::VKEY_DELETE, // KEY_DELETE
- ui::VKEY_UNKNOWN, // KEY_MACRO
- ui::VKEY_VOLUME_MUTE, // KEY_MUTE
- ui::VKEY_VOLUME_DOWN, // KEY_VOLUMEDOWN
- ui::VKEY_VOLUME_UP, // KEY_VOLUMEUP
- ui::VKEY_POWER, // KEY_POWER
- ui::VKEY_OEM_PLUS, // KEY_KPEQUAL
- ui::VKEY_UNKNOWN, // KEY_KPPLUSMINUS
- ui::VKEY_PAUSE, // KEY_PAUSE
- ui::VKEY_MEDIA_LAUNCH_APP1, // KEY_SCALE
- ui::VKEY_DECIMAL, // KEY_KPCOMMA
- ui::VKEY_HANGUL, // KEY_HANGEUL
- ui::VKEY_HANJA, // KEY_HANJA
- ui::VKEY_UNKNOWN, // KEY_YEN
- ui::VKEY_LWIN, // KEY_LEFTMETA
- ui::VKEY_RWIN, // KEY_RIGHTMETA
- ui::VKEY_APPS, // KEY_COMPOSE
- };
-
- if (code < arraysize(kLinuxBaseKeyMap))
- return kLinuxBaseKeyMap[code];
-
- LOG(ERROR) << "Unknown key code: " << code;
- return ui::VKEY_UNKNOWN;
-}
-
-int ModifierFromButton(unsigned int code) {
- switch (code) {
- case KEY_CAPSLOCK:
- return EVDEV_MODIFIER_CAPS_LOCK;
- case KEY_LEFTSHIFT:
- case KEY_RIGHTSHIFT:
- return EVDEV_MODIFIER_SHIFT;
- case KEY_LEFTCTRL:
- case KEY_RIGHTCTRL:
- return EVDEV_MODIFIER_CONTROL;
- case KEY_LEFTALT:
- case KEY_RIGHTALT:
- return EVDEV_MODIFIER_ALT;
- case BTN_LEFT:
- return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
- case BTN_MIDDLE:
- return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
- case BTN_RIGHT:
- return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
- case KEY_LEFTMETA:
- case KEY_RIGHTMETA:
- return EVDEV_MODIFIER_COMMAND;
- default:
- return EVDEV_MODIFIER_NONE;
- }
-}
-
-bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
-
-} // namespace
-
-KeyEventConverterEvdev::KeyEventConverterEvdev(int fd,
- int id,
- EventModifiersEvdev* modifiers)
- : fd_(fd), id_(id), modifiers_(modifiers) {
- // TODO(spang): Initialize modifiers using EVIOCGKEY.
-}
-
-KeyEventConverterEvdev::~KeyEventConverterEvdev() {
- if (fd_ >= 0 && close(fd_) < 0)
- DLOG(WARNING) << "failed close on /dev/input/event" << id_;
-}
-
-void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
- input_event inputs[4];
- ssize_t read_size = read(fd, inputs, sizeof(inputs));
- if (read_size <= 0)
- return;
-
- CHECK_EQ(read_size % sizeof(*inputs), 0u);
- ProcessEvents(inputs, read_size / sizeof(*inputs));
-}
-
-void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
- NOTREACHED();
-}
-
-void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs,
- int count) {
- for (int i = 0; i < count; ++i) {
- const input_event& input = inputs[i];
- if (input.type == EV_KEY) {
- ConvertKeyEvent(input.code, input.value);
- } else if (input.type == EV_SYN) {
- // TODO(sadrul): Handle this case appropriately.
- }
- }
-}
-
-void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) {
- int down = (value != 0);
- int repeat = (value == 2);
- int modifier = ModifierFromButton(key);
- ui::KeyboardCode code = KeyboardCodeFromButton(key);
-
- if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) {
- if (IsLockButton(key)) {
- // Locking modifier keys: CapsLock.
- modifiers_->UpdateModifierLock(modifier, down);
- } else {
- // Regular modifier keys: Shift, Ctrl, Alt, etc.
- modifiers_->UpdateModifier(modifier, down);
- }
- }
-
- int flags = modifiers_->GetModifierFlags();
-
- scoped_ptr<KeyEvent> key_event(
- new KeyEvent(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, code, flags, true));
- DispatchEvent(key_event.PassAs<ui::Event>());
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter.h b/chromium/ui/events/ozone/evdev/key_event_converter.h
deleted file mode 100644
index a544b02104c..00000000000
--- a/chromium/ui/events/ozone/evdev/key_event_converter.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
-#define UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
-
-#include "ui/events/event.h"
-#include "ui/events/events_export.h"
-#include "ui/events/ozone/evdev/event_modifiers.h"
-#include "ui/events/ozone/event_converter_ozone.h"
-
-struct input_event;
-
-namespace ui {
-
-class EVENTS_EXPORT KeyEventConverterEvdev : public EventConverterOzone {
- public:
- KeyEventConverterEvdev(int fd, int id, EventModifiersEvdev* modifiers);
- virtual ~KeyEventConverterEvdev();
-
- // Overidden from base::MessagePumpLibevent::Watcher.
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
-
- void ProcessEvents(const struct input_event* inputs, int count);
-
- private:
- // File descriptor for the /dev/input/event* instance.
- int fd_;
-
- // Number corresponding to * in the source evdev device: /dev/input/event*
- int id_;
-
- // Shared modifier state.
- EventModifiersEvdev* modifiers_;
-
- void ConvertKeyEvent(int key, int value);
-
- DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdev);
-};
-
-} // namspace ui
-
-#endif // UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
-
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/key_event_converter_evdev.cc
new file mode 100644
index 00000000000..2e6f31e052a
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/key_event_converter_evdev.cc
@@ -0,0 +1,271 @@
+// 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/events/ozone/evdev/key_event_converter_evdev.h"
+
+#include <errno.h>
+#include <linux/input.h>
+
+#include "base/message_loop/message_loop.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+
+namespace ui {
+
+namespace {
+
+ui::KeyboardCode KeyboardCodeFromButton(unsigned int code) {
+ static const ui::KeyboardCode kLinuxBaseKeyMap[] = {
+ ui::VKEY_UNKNOWN, // KEY_RESERVED
+ ui::VKEY_ESCAPE, // KEY_ESC
+ ui::VKEY_1, // KEY_1
+ ui::VKEY_2, // KEY_2
+ ui::VKEY_3, // KEY_3
+ ui::VKEY_4, // KEY_4
+ ui::VKEY_5, // KEY_5
+ ui::VKEY_6, // KEY_6
+ ui::VKEY_7, // KEY_7
+ ui::VKEY_8, // KEY_8
+ ui::VKEY_9, // KEY_9
+ ui::VKEY_0, // KEY_0
+ ui::VKEY_OEM_MINUS, // KEY_MINUS
+ ui::VKEY_OEM_PLUS, // KEY_EQUAL
+ ui::VKEY_BACK, // KEY_BACKSPACE
+ ui::VKEY_TAB, // KEY_TAB
+ ui::VKEY_Q, // KEY_Q
+ ui::VKEY_W, // KEY_W
+ ui::VKEY_E, // KEY_E
+ ui::VKEY_R, // KEY_R
+ ui::VKEY_T, // KEY_T
+ ui::VKEY_Y, // KEY_Y
+ ui::VKEY_U, // KEY_U
+ ui::VKEY_I, // KEY_I
+ ui::VKEY_O, // KEY_O
+ ui::VKEY_P, // KEY_P
+ ui::VKEY_OEM_4, // KEY_LEFTBRACE
+ ui::VKEY_OEM_6, // KEY_RIGHTBRACE
+ ui::VKEY_RETURN, // KEY_ENTER
+ ui::VKEY_CONTROL, // KEY_LEFTCTRL
+ ui::VKEY_A, // KEY_A
+ ui::VKEY_S, // KEY_S
+ ui::VKEY_D, // KEY_D
+ ui::VKEY_F, // KEY_F
+ ui::VKEY_G, // KEY_G
+ ui::VKEY_H, // KEY_H
+ ui::VKEY_J, // KEY_J
+ ui::VKEY_K, // KEY_K
+ ui::VKEY_L, // KEY_L
+ ui::VKEY_OEM_1, // KEY_SEMICOLON
+ ui::VKEY_OEM_7, // KEY_APOSTROPHE
+ ui::VKEY_OEM_3, // KEY_GRAVE
+ ui::VKEY_SHIFT, // KEY_LEFTSHIFT
+ ui::VKEY_OEM_5, // KEY_BACKSLASH
+ ui::VKEY_Z, // KEY_Z
+ ui::VKEY_X, // KEY_X
+ ui::VKEY_C, // KEY_C
+ ui::VKEY_V, // KEY_V
+ ui::VKEY_B, // KEY_B
+ ui::VKEY_N, // KEY_N
+ ui::VKEY_M, // KEY_M
+ ui::VKEY_OEM_COMMA, // KEY_COMMA
+ ui::VKEY_OEM_PERIOD, // KEY_DOT
+ ui::VKEY_OEM_2, // KEY_SLASH
+ ui::VKEY_SHIFT, // KEY_RIGHTSHIFT
+ ui::VKEY_MULTIPLY, // KEY_KPASTERISK
+ ui::VKEY_MENU, // KEY_LEFTALT
+ ui::VKEY_SPACE, // KEY_SPACE
+ ui::VKEY_CAPITAL, // KEY_CAPSLOCK
+ ui::VKEY_F1, // KEY_F1
+ ui::VKEY_F2, // KEY_F2
+ ui::VKEY_F3, // KEY_F3
+ ui::VKEY_F4, // KEY_F4
+ ui::VKEY_F5, // KEY_F5
+ ui::VKEY_F6, // KEY_F6
+ ui::VKEY_F7, // KEY_F7
+ ui::VKEY_F8, // KEY_F8
+ ui::VKEY_F9, // KEY_F9
+ ui::VKEY_F10, // KEY_F10
+ ui::VKEY_NUMLOCK, // KEY_NUMLOCK
+ ui::VKEY_SCROLL, // KEY_SCROLLLOCK
+ ui::VKEY_NUMPAD7, // KEY_KP7
+ ui::VKEY_NUMPAD8, // KEY_KP8
+ ui::VKEY_NUMPAD9, // KEY_KP9
+ ui::VKEY_SUBTRACT, // KEY_KPMINUS
+ ui::VKEY_NUMPAD4, // KEY_KP4
+ ui::VKEY_NUMPAD5, // KEY_KP5
+ ui::VKEY_NUMPAD6, // KEY_KP6
+ ui::VKEY_ADD, // KEY_KPPLUS
+ ui::VKEY_NUMPAD1, // KEY_KP1
+ ui::VKEY_NUMPAD2, // KEY_KP2
+ ui::VKEY_NUMPAD3, // KEY_KP3
+ ui::VKEY_NUMPAD0, // KEY_KP0
+ ui::VKEY_DECIMAL, // KEY_KPDOT
+ ui::VKEY_UNKNOWN, // (unassigned)
+ ui::VKEY_DBE_DBCSCHAR, // KEY_ZENKAKUHANKAKU
+ ui::VKEY_OEM_102, // KEY_102ND
+ ui::VKEY_F11, // KEY_F11
+ ui::VKEY_F12, // KEY_F12
+ ui::VKEY_UNKNOWN, // KEY_RO
+ ui::VKEY_UNKNOWN, // KEY_KATAKANA
+ ui::VKEY_UNKNOWN, // KEY_HIRAGANA
+ ui::VKEY_CONVERT, // KEY_HENKAN
+ ui::VKEY_UNKNOWN, // KEY_KATAKANAHIRAGANA
+ ui::VKEY_NONCONVERT, // KEY_MUHENKAN
+ ui::VKEY_UNKNOWN, // KEY_KPJPCOMMA
+ ui::VKEY_RETURN, // KEY_KPENTER
+ ui::VKEY_CONTROL, // KEY_RIGHTCTRL
+ ui::VKEY_DIVIDE, // KEY_KPSLASH
+ ui::VKEY_PRINT, // KEY_SYSRQ
+ ui::VKEY_MENU, // KEY_RIGHTALT
+ ui::VKEY_RETURN, // KEY_LINEFEED
+ ui::VKEY_HOME, // KEY_HOME
+ ui::VKEY_UP, // KEY_UP
+ ui::VKEY_PRIOR, // KEY_PAGEUP
+ ui::VKEY_LEFT, // KEY_LEFT
+ ui::VKEY_RIGHT, // KEY_RIGHT
+ ui::VKEY_END, // KEY_END
+ ui::VKEY_DOWN, // KEY_DOWN
+ ui::VKEY_NEXT, // KEY_PAGEDOWN
+ ui::VKEY_INSERT, // KEY_INSERT
+ ui::VKEY_DELETE, // KEY_DELETE
+ ui::VKEY_UNKNOWN, // KEY_MACRO
+ ui::VKEY_VOLUME_MUTE, // KEY_MUTE
+ ui::VKEY_VOLUME_DOWN, // KEY_VOLUMEDOWN
+ ui::VKEY_VOLUME_UP, // KEY_VOLUMEUP
+ ui::VKEY_POWER, // KEY_POWER
+ ui::VKEY_OEM_PLUS, // KEY_KPEQUAL
+ ui::VKEY_UNKNOWN, // KEY_KPPLUSMINUS
+ ui::VKEY_PAUSE, // KEY_PAUSE
+ ui::VKEY_MEDIA_LAUNCH_APP1, // KEY_SCALE
+ ui::VKEY_DECIMAL, // KEY_KPCOMMA
+ ui::VKEY_HANGUL, // KEY_HANGEUL
+ ui::VKEY_HANJA, // KEY_HANJA
+ ui::VKEY_UNKNOWN, // KEY_YEN
+ ui::VKEY_LWIN, // KEY_LEFTMETA
+ ui::VKEY_RWIN, // KEY_RIGHTMETA
+ ui::VKEY_APPS, // KEY_COMPOSE
+ };
+
+ if (code < arraysize(kLinuxBaseKeyMap))
+ return kLinuxBaseKeyMap[code];
+
+ LOG(ERROR) << "Unknown key code: " << code;
+ return ui::VKEY_UNKNOWN;
+}
+
+int ModifierFromButton(unsigned int code) {
+ switch (code) {
+ case KEY_CAPSLOCK:
+ return EVDEV_MODIFIER_CAPS_LOCK;
+ case KEY_LEFTSHIFT:
+ case KEY_RIGHTSHIFT:
+ return EVDEV_MODIFIER_SHIFT;
+ case KEY_LEFTCTRL:
+ case KEY_RIGHTCTRL:
+ return EVDEV_MODIFIER_CONTROL;
+ case KEY_LEFTALT:
+ case KEY_RIGHTALT:
+ return EVDEV_MODIFIER_ALT;
+ case BTN_LEFT:
+ return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
+ case BTN_MIDDLE:
+ return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON;
+ case BTN_RIGHT:
+ return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON;
+ case KEY_LEFTMETA:
+ case KEY_RIGHTMETA:
+ return EVDEV_MODIFIER_COMMAND;
+ default:
+ return EVDEV_MODIFIER_NONE;
+ }
+}
+
+bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
+
+} // namespace
+
+KeyEventConverterEvdev::KeyEventConverterEvdev(
+ int fd,
+ base::FilePath path,
+ EventModifiersEvdev* modifiers,
+ const EventDispatchCallback& callback)
+ : EventConverterEvdev(callback),
+ fd_(fd),
+ path_(path),
+ modifiers_(modifiers) {
+ // TODO(spang): Initialize modifiers using EVIOCGKEY.
+}
+
+KeyEventConverterEvdev::~KeyEventConverterEvdev() {
+ Stop();
+ close(fd_);
+}
+
+void KeyEventConverterEvdev::Start() {
+ base::MessageLoopForUI::current()->WatchFileDescriptor(
+ fd_, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
+}
+
+void KeyEventConverterEvdev::Stop() {
+ controller_.StopWatchingFileDescriptor();
+}
+
+void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
+ input_event inputs[4];
+ ssize_t read_size = read(fd, inputs, sizeof(inputs));
+ if (read_size < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ return;
+ if (errno != ENODEV)
+ PLOG(ERROR) << "error reading device " << path_.value();
+ Stop();
+ return;
+ }
+
+ CHECK_EQ(read_size % sizeof(*inputs), 0u);
+ ProcessEvents(inputs, read_size / sizeof(*inputs));
+}
+
+void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTREACHED();
+}
+
+void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs,
+ int count) {
+ for (int i = 0; i < count; ++i) {
+ const input_event& input = inputs[i];
+ if (input.type == EV_KEY) {
+ ConvertKeyEvent(input.code, input.value);
+ } else if (input.type == EV_SYN) {
+ // TODO(sadrul): Handle this case appropriately.
+ }
+ }
+}
+
+void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) {
+ int down = (value != 0);
+ int repeat = (value == 2);
+ int modifier = ModifierFromButton(key);
+ ui::KeyboardCode code = KeyboardCodeFromButton(key);
+
+ if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) {
+ if (IsLockButton(key)) {
+ // Locking modifier keys: CapsLock.
+ modifiers_->UpdateModifierLock(modifier, down);
+ } else {
+ // Regular modifier keys: Shift, Ctrl, Alt, etc.
+ modifiers_->UpdateModifier(modifier, down);
+ }
+ }
+
+ int flags = modifiers_->GetModifierFlags();
+
+ KeyEvent key_event(
+ down ? ET_KEY_PRESSED : ET_KEY_RELEASED, code, flags, false);
+ DispatchEventToCallback(&key_event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter_evdev.h b/chromium/ui/events/ozone/evdev/key_event_converter_evdev.h
new file mode 100644
index 00000000000..26615d94942
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/key_event_converter_evdev.h
@@ -0,0 +1,60 @@
+// 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_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
+
+#include "base/files/file_path.h"
+#include "base/message_loop/message_pump_libevent.h"
+#include "ui/events/event.h"
+#include "ui/events/ozone/evdev/event_converter_evdev.h"
+#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+
+struct input_event;
+
+namespace ui {
+
+class EVENTS_OZONE_EVDEV_EXPORT KeyEventConverterEvdev
+ : public EventConverterEvdev,
+ public base::MessagePumpLibevent::Watcher {
+ public:
+ KeyEventConverterEvdev(int fd,
+ base::FilePath path,
+ EventModifiersEvdev* modifiers,
+ const EventDispatchCallback& dispatch);
+ virtual ~KeyEventConverterEvdev();
+
+ // Start & stop watching for events.
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ // Overidden from base::MessagePumpLibevent::Watcher.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ void ProcessEvents(const struct input_event* inputs, int count);
+
+ private:
+ // File descriptor for the /dev/input/event* instance.
+ int fd_;
+
+ // Path to input device.
+ base::FilePath path_;
+
+ // Shared modifier state.
+ EventModifiersEvdev* modifiers_;
+
+ // Controller for watching the input fd.
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ void ConvertKeyEvent(int key, int value);
+
+ DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdev);
+};
+
+} // namspace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_KEY_EVENT_CONVERTER_EVDEV_H_
+
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/key_event_converter_evdev_unittest.cc
new file mode 100644
index 00000000000..88ee64609ed
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/key_event_converter_evdev_unittest.cc
@@ -0,0 +1,347 @@
+// 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 <linux/input.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/evdev/key_event_converter_evdev.h"
+
+namespace ui {
+
+const char kTestDevicePath[] = "/dev/input/test-device";
+
+class MockKeyEventConverterEvdev : public KeyEventConverterEvdev {
+ public:
+ MockKeyEventConverterEvdev(int fd, EventModifiersEvdev* modifiers)
+ : KeyEventConverterEvdev(fd,
+ base::FilePath(kTestDevicePath),
+ modifiers,
+ EventDispatchCallback()) {
+ Start();
+ }
+ virtual ~MockKeyEventConverterEvdev() {};
+
+ unsigned size() { return dispatched_events_.size(); }
+ KeyEvent* event(unsigned index) {
+ CHECK_GT(dispatched_events_.size(), index);
+ return dispatched_events_[index];
+ }
+
+ virtual void DispatchEventToCallback(Event* event) OVERRIDE;
+
+ private:
+ ScopedVector<KeyEvent> dispatched_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockKeyEventConverterEvdev);
+};
+
+void MockKeyEventConverterEvdev::DispatchEventToCallback(Event* event) {
+ dispatched_events_.push_back(new KeyEvent(*static_cast<KeyEvent*>(event)));
+}
+
+} // namespace ui
+
+// Test fixture.
+class KeyEventConverterEvdevTest : public testing::Test {
+ public:
+ KeyEventConverterEvdevTest() {}
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+
+ // Set up pipe to satisfy message pump (unused).
+ int evdev_io[2];
+ if (pipe(evdev_io))
+ PLOG(FATAL) << "failed pipe";
+ events_in_ = evdev_io[0];
+ events_out_ = evdev_io[1];
+
+ modifiers_ = new ui::EventModifiersEvdev();
+ device_ = new ui::MockKeyEventConverterEvdev(events_in_, modifiers_);
+ }
+ virtual void TearDown() OVERRIDE {
+ delete device_;
+ delete modifiers_;
+ close(events_in_);
+ close(events_out_);
+ }
+
+ ui::MockKeyEventConverterEvdev* device() { return device_; }
+ ui::EventModifiersEvdev* modifiers() { return modifiers_; }
+
+ private:
+ base::MessageLoopForUI ui_loop_;
+
+ ui::EventModifiersEvdev* modifiers_;
+ ui::MockKeyEventConverterEvdev* device_;
+
+ int events_out_;
+ int events_in_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdevTest);
+};
+
+TEST_F(KeyEventConverterEvdevTest, KeyPress) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+
+ dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ EXPECT_EQ(2u, dev->size());
+
+ ui::KeyEvent* event;
+
+ event = dev->event(0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+
+ event = dev->event(1);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyRepeat) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
+ {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+
+ dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ EXPECT_EQ(4u, dev->size());
+
+ ui::KeyEvent* event;
+
+ event = dev->event(0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+
+ event = dev->event(1);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+
+ event = dev->event(2);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+
+ event = dev->event(3);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_BACK, event->key_code());
+ EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, NoEvents) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+ dev->ProcessEvents(NULL, 0);
+ EXPECT_EQ(0u, dev->size());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithModifier) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+ {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
+ {{0, 0}, EV_KEY, KEY_A, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
+ {{0, 0}, EV_KEY, KEY_A, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+ {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+
+ dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ EXPECT_EQ(4u, dev->size());
+
+ ui::KeyEvent* event;
+
+ event = dev->event(0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
+ EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+ event = dev->event(1);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_A, event->key_code());
+ EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+ event = dev->event(2);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_A, event->key_code());
+ EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
+
+ event = dev->event(3);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
+ EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithDuplicateModifier) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+ {{0, 0}, EV_KEY, KEY_LEFTCTRL, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
+ {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
+ {{0, 0}, EV_KEY, KEY_Z, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
+ {{0, 0}, EV_KEY, KEY_Z, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
+ {{0, 0}, EV_KEY, KEY_LEFTCTRL, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
+ {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+
+ dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ EXPECT_EQ(6u, dev->size());
+
+ ui::KeyEvent* event;
+
+ event = dev->event(0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+ EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+ event = dev->event(1);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+ EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+ event = dev->event(2);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_Z, event->key_code());
+ EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+ event = dev->event(3);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_Z, event->key_code());
+ EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+ event = dev->event(4);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+ EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
+
+ event = dev->event(5);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
+ EXPECT_EQ(0, event->flags());
+}
+
+TEST_F(KeyEventConverterEvdevTest, KeyWithLock) {
+ ui::MockKeyEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+ {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+ {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
+ {{0, 0}, EV_KEY, KEY_Q, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
+ {{0, 0}, EV_KEY, KEY_Q, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+ {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+
+ {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
+ {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+
+ dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
+ EXPECT_EQ(6u, dev->size());
+
+ ui::KeyEvent* event;
+
+ event = dev->event(0);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+ EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+ event = dev->event(1);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+ EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+ event = dev->event(2);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_Q, event->key_code());
+ EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+ event = dev->event(3);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_Q, event->key_code());
+ EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
+
+ event = dev->event(4);
+ EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
+ EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+ EXPECT_EQ(0, event->flags());
+
+ event = dev->event(5);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
+ EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
+ EXPECT_EQ(0, event->flags());
+}
diff --git a/chromium/ui/events/ozone/evdev/key_event_converter_unittest.cc b/chromium/ui/events/ozone/evdev/key_event_converter_unittest.cc
deleted file mode 100644
index 472139078bd..00000000000
--- a/chromium/ui/events/ozone/evdev/key_event_converter_unittest.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <linux/input.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/events/ozone/evdev/key_event_converter.h"
-
-namespace ui {
-
-const int kInvalidFileDescriptor = -1;
-const int kTestDeviceId = 0;
-
-class MockKeyEventConverterEvdev : public KeyEventConverterEvdev {
- public:
- MockKeyEventConverterEvdev(EventModifiersEvdev* modifiers)
- : KeyEventConverterEvdev(kInvalidFileDescriptor,
- kTestDeviceId,
- modifiers) {}
- virtual ~MockKeyEventConverterEvdev() {};
-
- unsigned size() { return dispatched_events_.size(); }
- KeyEvent* event(unsigned index) { return dispatched_events_[index]; }
-
- virtual void DispatchEvent(scoped_ptr<Event> event) OVERRIDE;
-
- private:
- ScopedVector<KeyEvent> dispatched_events_;
-
- DISALLOW_COPY_AND_ASSIGN(MockKeyEventConverterEvdev);
-};
-
-void MockKeyEventConverterEvdev::DispatchEvent(scoped_ptr<Event> event) {
- dispatched_events_.push_back(static_cast<KeyEvent*>(event.release()));
-}
-
-} // namespace ui
-
-// Test fixture.
-class KeyEventConverterEvdevTest : public testing::Test {
- public:
- KeyEventConverterEvdevTest() {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- modifiers_ = new ui::EventModifiersEvdev();
- device_ = new ui::MockKeyEventConverterEvdev(modifiers_);
- }
- virtual void TearDown() OVERRIDE {
- delete device_;
- delete modifiers_;
- }
-
- ui::MockKeyEventConverterEvdev* device() { return device_; }
- ui::EventModifiersEvdev* modifiers() { return modifiers_; }
-
- private:
- ui::EventModifiersEvdev* modifiers_;
- ui::MockKeyEventConverterEvdev* device_;
- DISALLOW_COPY_AND_ASSIGN(KeyEventConverterEvdevTest);
-};
-
-TEST_F(KeyEventConverterEvdevTest, KeyPress) {
- ui::MockKeyEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
-
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
- EXPECT_EQ(2u, dev->size());
-
- ui::KeyEvent* event;
-
- event = dev->event(0);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-
- event = dev->event(1);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-}
-
-TEST_F(KeyEventConverterEvdevTest, KeyRepeat) {
- ui::MockKeyEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
- {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
-
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
- EXPECT_EQ(4u, dev->size());
-
- ui::KeyEvent* event;
-
- event = dev->event(0);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-
- event = dev->event(1);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-
- event = dev->event(2);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-
- event = dev->event(3);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_BACK, event->key_code());
- EXPECT_EQ(0, event->flags());
-}
-
-TEST_F(KeyEventConverterEvdevTest, NoEvents) {
- ui::MockKeyEventConverterEvdev* dev = device();
- dev->ProcessEvents(NULL, 0);
- EXPECT_EQ(0u, dev->size());
-}
-
-TEST_F(KeyEventConverterEvdevTest, KeyWithModifier) {
- ui::MockKeyEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
- {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
- {{0, 0}, EV_KEY, KEY_A, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
- {{0, 0}, EV_KEY, KEY_A, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
- {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
-
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
- EXPECT_EQ(4u, dev->size());
-
- ui::KeyEvent* event;
-
- event = dev->event(0);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
- EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
-
- event = dev->event(1);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_A, event->key_code());
- EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
-
- event = dev->event(2);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_A, event->key_code());
- EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());
-
- event = dev->event(3);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
- EXPECT_EQ(0, event->flags());
-}
-
-TEST_F(KeyEventConverterEvdevTest, KeyWithDuplicateModifier) {
- ui::MockKeyEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
- {{0, 0}, EV_KEY, KEY_LEFTCTRL, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
- {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
- {{0, 0}, EV_KEY, KEY_Z, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
- {{0, 0}, EV_KEY, KEY_Z, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
- {{0, 0}, EV_KEY, KEY_LEFTCTRL, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
- {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
-
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
- EXPECT_EQ(6u, dev->size());
-
- ui::KeyEvent* event;
-
- event = dev->event(0);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
-
- event = dev->event(1);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
-
- event = dev->event(2);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_Z, event->key_code());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
-
- event = dev->event(3);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_Z, event->key_code());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
-
- event = dev->event(4);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());
-
- event = dev->event(5);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
- EXPECT_EQ(0, event->flags());
-}
-
-TEST_F(KeyEventConverterEvdevTest, KeyWithLock) {
- ui::MockKeyEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
- {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
- {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
- {{0, 0}, EV_KEY, KEY_Q, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70014},
- {{0, 0}, EV_KEY, KEY_Q, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
- {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
-
- {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
- {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
- {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
-
- dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
- EXPECT_EQ(6u, dev->size());
-
- ui::KeyEvent* event;
-
- event = dev->event(0);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
- EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
-
- event = dev->event(1);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
- EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
-
- event = dev->event(2);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_Q, event->key_code());
- EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
-
- event = dev->event(3);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_Q, event->key_code());
- EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN, event->flags());
-
- event = dev->event(4);
- EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
- EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
- EXPECT_EQ(0, event->flags());
-
- event = dev->event(5);
- EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
- EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
- EXPECT_EQ(0, event->flags());
-}
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
new file mode 100644
index 00000000000..86f8834d389
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -0,0 +1,107 @@
+// 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/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
+
+#include <errno.h>
+#include <libevdev/libevdev.h>
+#include <linux/input.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace ui {
+
+namespace {
+
+std::string FormatLog(const char* fmt, va_list args) {
+ std::string msg = base::StringPrintV(fmt, args);
+ if (!msg.empty() && msg[msg.size() - 1] == '\n')
+ msg.erase(msg.end() - 1, msg.end());
+ return msg;
+}
+
+} // namespace
+
+EventReaderLibevdevCros::EventReaderLibevdevCros(int fd,
+ const base::FilePath& path,
+ scoped_ptr<Delegate> delegate)
+ : path_(path), delegate_(delegate.Pass()) {
+ memset(&evdev_, 0, sizeof(evdev_));
+ evdev_.log = OnLogMessage;
+ evdev_.log_udata = this;
+ evdev_.syn_report = OnSynReport;
+ evdev_.syn_report_udata = this;
+ evdev_.fd = fd;
+
+ memset(&evstate_, 0, sizeof(evstate_));
+ evdev_.evstate = &evstate_;
+ Event_Init(&evdev_);
+
+ Event_Open(&evdev_);
+
+ delegate_->OnLibEvdevCrosOpen(&evdev_, &evstate_);
+}
+
+EventReaderLibevdevCros::~EventReaderLibevdevCros() {
+ Stop();
+ EvdevClose(&evdev_);
+}
+
+EventReaderLibevdevCros::Delegate::~Delegate() {}
+
+void EventReaderLibevdevCros::Start() {
+ base::MessageLoopForUI::current()->WatchFileDescriptor(
+ evdev_.fd,
+ true,
+ base::MessagePumpLibevent::WATCH_READ,
+ &controller_,
+ this);
+}
+
+void EventReaderLibevdevCros::Stop() {
+ controller_.StopWatchingFileDescriptor();
+}
+
+void EventReaderLibevdevCros::OnFileCanReadWithoutBlocking(int fd) {
+ if (EvdevRead(&evdev_)) {
+ if (errno == EINTR || errno == EAGAIN)
+ return;
+ if (errno != ENODEV)
+ PLOG(ERROR) << "error reading device " << path_.value();
+ Stop();
+ return;
+ }
+}
+
+void EventReaderLibevdevCros::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTREACHED();
+}
+
+// static
+void EventReaderLibevdevCros::OnSynReport(void* data,
+ EventStateRec* evstate,
+ struct timeval* tv) {
+ EventReaderLibevdevCros* reader = static_cast<EventReaderLibevdevCros*>(data);
+ reader->delegate_->OnLibEvdevCrosEvent(&reader->evdev_, evstate, *tv);
+}
+
+// static
+void EventReaderLibevdevCros::OnLogMessage(void* data,
+ int level,
+ const char* fmt,
+ ...) {
+ va_list args;
+ va_start(args, fmt);
+ if (level >= LOGLEVEL_ERROR)
+ LOG(ERROR) << "libevdev: " << FormatLog(fmt, args);
+ else if (level >= LOGLEVEL_WARNING)
+ LOG(WARNING) << "libevdev: " << FormatLog(fmt, args);
+ else
+ VLOG(3) << "libevdev: " << FormatLog(fmt, args);
+ va_end(args);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h b/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
new file mode 100644
index 00000000000..1631c5b685b
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.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_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_EVENT_READER_LIBEVDEV_CROS_H_
+#define UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_EVENT_READER_LIBEVDEV_CROS_H_
+
+#include <libevdev/libevdev.h>
+
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/events/ozone/evdev/event_converter_evdev.h"
+
+namespace ui {
+
+// Basic wrapper for libevdev-cros.
+//
+// This drives libevdev-cros from a file descriptor and calls delegate
+// with the updated event state from libevdev-cros.
+//
+// The library doesn't support all devices currently. In particular there
+// is no support for keyboard events.
+class EventReaderLibevdevCros : public base::MessagePumpLibevent::Watcher,
+ public EventConverterEvdev {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate();
+
+ // Notifier for open. This is called with the initial event state.
+ virtual void OnLibEvdevCrosOpen(Evdev* evdev, EventStateRec* evstate) = 0;
+
+ // Notifier for event. This is called with the updated event state.
+ virtual void OnLibEvdevCrosEvent(Evdev* evdev,
+ EventStateRec* state,
+ const timeval& time) = 0;
+ };
+
+ EventReaderLibevdevCros(int fd,
+ const base::FilePath& path,
+ scoped_ptr<Delegate> delegate);
+ ~EventReaderLibevdevCros();
+
+ // Overridden from ui::EventDeviceEvdev.
+ void Start() OVERRIDE;
+ void Stop() OVERRIDE;
+
+ // Overidden from MessagePumpLibevent::Watcher.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ private:
+ static void OnSynReport(void* data,
+ EventStateRec* evstate,
+ struct timeval* tv);
+ static void OnLogMessage(void*, int level, const char*, ...);
+
+ // Libevdev state.
+ Evdev evdev_;
+
+ // Event state.
+ EventStateRec evstate_;
+
+ // Path to input device.
+ base::FilePath path_;
+
+ // Delegate for event processing.
+ scoped_ptr<Delegate> delegate_;
+
+ // Controller for watching the input fd.
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventReaderLibevdevCros);
+};
+
+} // namspace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_EVENT_READER_LIBEVDEV_CROS_H_
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
new file mode 100644
index 00000000000..c41a04d2f08
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -0,0 +1,274 @@
+// 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/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h"
+
+#include <gestures/gestures.h>
+#include <libevdev/libevdev.h>
+
+#include "base/strings/stringprintf.h"
+#include "base/timer/timer.h"
+#include "ui/events/event.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/events/ozone/evdev/event_modifiers_evdev.h"
+#include "ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace ui {
+
+namespace {
+
+// Convert libevdev device class to libgestures device class.
+GestureInterpreterDeviceClass GestureDeviceClass(Evdev* evdev) {
+ switch (evdev->info.evdev_class) {
+ case EvdevClassMouse:
+ return GESTURES_DEVCLASS_MOUSE;
+ case EvdevClassMultitouchMouse:
+ return GESTURES_DEVCLASS_MULTITOUCH_MOUSE;
+ case EvdevClassTouchpad:
+ return GESTURES_DEVCLASS_TOUCHPAD;
+ case EvdevClassTouchscreen:
+ return GESTURES_DEVCLASS_TOUCHSCREEN;
+ default:
+ return GESTURES_DEVCLASS_UNKNOWN;
+ }
+}
+
+// Convert libevdev state to libgestures hardware properties.
+HardwareProperties GestureHardwareProperties(Evdev* evdev) {
+ HardwareProperties hwprops;
+ hwprops.left = Event_Get_Left(evdev);
+ hwprops.top = Event_Get_Top(evdev);
+ hwprops.right = Event_Get_Right(evdev);
+ hwprops.bottom = Event_Get_Bottom(evdev);
+ hwprops.res_x = Event_Get_Res_X(evdev);
+ hwprops.res_y = Event_Get_Res_Y(evdev);
+ hwprops.screen_x_dpi = 133;
+ hwprops.screen_y_dpi = 133;
+ hwprops.orientation_minimum = Event_Get_Orientation_Minimum(evdev);
+ hwprops.orientation_maximum = Event_Get_Orientation_Maximum(evdev);
+ hwprops.max_finger_cnt = Event_Get_Slot_Count(evdev);
+ hwprops.max_touch_cnt = Event_Get_Touch_Count_Max(evdev);
+ hwprops.supports_t5r2 = Event_Get_T5R2(evdev);
+ hwprops.support_semi_mt = Event_Get_Semi_MT(evdev);
+ /* buttonpad means a physical button under the touch surface */
+ hwprops.is_button_pad = Event_Get_Button_Pad(evdev);
+ return hwprops;
+}
+
+// Callback from libgestures when a gesture is ready.
+void OnGestureReadyHelper(void* client_data, const Gesture* gesture) {
+ GestureInterpreterLibevdevCros* interpreter =
+ static_cast<GestureInterpreterLibevdevCros*>(client_data);
+ interpreter->OnGestureReady(gesture);
+}
+
+// Convert gestures timestamp (stime_t) to ui::Event timestamp.
+base::TimeDelta StimeToTimedelta(stime_t timestamp) {
+ return base::TimeDelta::FromMicroseconds(timestamp *
+ base::Time::kMicrosecondsPerSecond);
+}
+
+// Number of fingers for scroll gestures.
+const int kGestureScrollFingerCount = 2;
+
+} // namespace
+
+GestureInterpreterLibevdevCros::GestureInterpreterLibevdevCros(
+ EventModifiersEvdev* modifiers,
+ CursorDelegateEvdev* cursor,
+ const EventDispatchCallback& callback)
+ : modifiers_(modifiers),
+ cursor_(cursor),
+ dispatch_callback_(callback),
+ interpreter_(NULL) {}
+
+GestureInterpreterLibevdevCros::~GestureInterpreterLibevdevCros() {
+ if (interpreter_) {
+ DeleteGestureInterpreter(interpreter_);
+ interpreter_ = NULL;
+ }
+}
+
+void GestureInterpreterLibevdevCros::OnLibEvdevCrosOpen(
+ Evdev* evdev,
+ EventStateRec* evstate) {
+ CHECK(evdev->info.is_monotonic) << "libevdev must use monotonic timestamps";
+ VLOG(9) << "HACK DO NOT REMOVE OR LINK WILL FAIL" << (void*)gestures_log;
+
+ HardwareProperties hwprops = GestureHardwareProperties(evdev);
+ GestureInterpreterDeviceClass devclass = GestureDeviceClass(evdev);
+
+ // Create & initialize GestureInterpreter.
+ CHECK(!interpreter_);
+ interpreter_ = NewGestureInterpreter();
+ GestureInterpreterInitialize(interpreter_, devclass);
+ GestureInterpreterSetHardwareProperties(interpreter_, &hwprops);
+ GestureInterpreterSetTimerProvider(
+ interpreter_,
+ const_cast<GesturesTimerProvider*>(&kGestureTimerProvider),
+ this);
+ GestureInterpreterSetCallback(interpreter_, OnGestureReadyHelper, this);
+}
+
+void GestureInterpreterLibevdevCros::OnLibEvdevCrosEvent(Evdev* evdev,
+ EventStateRec* evstate,
+ const timeval& time) {
+ HardwareState hwstate;
+ memset(&hwstate, 0, sizeof(hwstate));
+ hwstate.timestamp = StimeFromTimeval(&time);
+
+ // Mouse.
+ hwstate.rel_x = evstate->rel_x;
+ hwstate.rel_y = evstate->rel_y;
+ hwstate.rel_wheel = evstate->rel_wheel;
+ hwstate.rel_hwheel = evstate->rel_hwheel;
+
+ // Touch.
+ FingerState fingers[Event_Get_Slot_Count(evdev)];
+ memset(&fingers, 0, sizeof(fingers));
+ int current_finger = 0;
+ for (int i = 0; i < evstate->slot_count; i++) {
+ MtSlotPtr slot = &evstate->slots[i];
+ if (slot->tracking_id == -1)
+ continue;
+ fingers[current_finger].touch_major = slot->touch_major;
+ fingers[current_finger].touch_minor = slot->touch_minor;
+ fingers[current_finger].width_major = slot->width_major;
+ fingers[current_finger].width_minor = slot->width_minor;
+ fingers[current_finger].pressure = slot->pressure;
+ fingers[current_finger].orientation = slot->orientation;
+ fingers[current_finger].position_x = slot->position_x;
+ fingers[current_finger].position_y = slot->position_y;
+ fingers[current_finger].tracking_id = slot->tracking_id;
+ current_finger++;
+ }
+ hwstate.touch_cnt = Event_Get_Touch_Count(evdev);
+ hwstate.finger_cnt = current_finger;
+ hwstate.fingers = fingers;
+
+ // Buttons.
+ if (Event_Get_Button_Left(evdev))
+ hwstate.buttons_down |= GESTURES_BUTTON_LEFT;
+ if (Event_Get_Button_Middle(evdev))
+ hwstate.buttons_down |= GESTURES_BUTTON_MIDDLE;
+ if (Event_Get_Button_Right(evdev))
+ hwstate.buttons_down |= GESTURES_BUTTON_RIGHT;
+
+ GestureInterpreterPushHardwareState(interpreter_, &hwstate);
+}
+
+void GestureInterpreterLibevdevCros::OnGestureReady(const Gesture* gesture) {
+ switch (gesture->type) {
+ case kGestureTypeMove:
+ OnGestureMove(gesture, &gesture->details.move);
+ break;
+ case kGestureTypeScroll:
+ OnGestureScroll(gesture, &gesture->details.scroll);
+ break;
+ case kGestureTypeButtonsChange:
+ OnGestureButtonsChange(gesture, &gesture->details.buttons);
+ break;
+ case kGestureTypeContactInitiated:
+ case kGestureTypeFling:
+ case kGestureTypeSwipe:
+ case kGestureTypeSwipeLift:
+ case kGestureTypePinch:
+ case kGestureTypeMetrics:
+ // TODO(spang): Support remaining gestures.
+ NOTIMPLEMENTED();
+ break;
+ default:
+ LOG(WARNING) << base::StringPrintf("Unrecognized gesture type (%u)",
+ gesture->type);
+ break;
+ }
+}
+
+void GestureInterpreterLibevdevCros::OnGestureMove(const Gesture* gesture,
+ const GestureMove* move) {
+ DVLOG(3) << base::StringPrintf("Gesture Move: (%f, %f) [%f, %f]",
+ move->dx,
+ move->dy,
+ move->ordinal_dx,
+ move->ordinal_dy);
+ if (!cursor_)
+ return; // No cursor!
+ cursor_->MoveCursor(gfx::Vector2dF(move->dx, move->dy));
+ // TODO(spang): Use move->ordinal_dx, move->ordinal_dy
+ // TODO(spang): Use move->start_time, move->end_time
+ MouseEvent event(ET_MOUSE_MOVED,
+ cursor_->location(),
+ cursor_->location(),
+ modifiers_->GetModifierFlags(),
+ /* changed_button_flags */ 0);
+ Dispatch(&event);
+}
+
+void GestureInterpreterLibevdevCros::OnGestureScroll(
+ const Gesture* gesture,
+ const GestureScroll* scroll) {
+ if (!cursor_)
+ return; // No cursor!
+ DVLOG(3) << base::StringPrintf("Gesture Scroll: (%f, %f) [%f, %f]",
+ scroll->dx,
+ scroll->dy,
+ scroll->ordinal_dx,
+ scroll->ordinal_dy);
+ // TODO(spang): Support SetNaturalScroll
+ // TODO(spang): Use scroll->start_time
+ ScrollEvent event(ET_SCROLL,
+ cursor_->location(),
+ StimeToTimedelta(gesture->end_time),
+ modifiers_->GetModifierFlags(),
+ scroll->dx,
+ scroll->dy,
+ scroll->ordinal_dx,
+ scroll->ordinal_dy,
+ kGestureScrollFingerCount);
+ Dispatch(&event);
+}
+
+void GestureInterpreterLibevdevCros::OnGestureButtonsChange(
+ const Gesture* gesture,
+ const GestureButtonsChange* buttons) {
+ DVLOG(3) << base::StringPrintf("Gesture Button Change: down=0x%02x up=0x%02x",
+ buttons->down,
+ buttons->up);
+ // TODO(spang): Use buttons->start_time, buttons->end_time
+ if (buttons->down & GESTURES_BUTTON_LEFT)
+ DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, true);
+ if (buttons->down & GESTURES_BUTTON_MIDDLE)
+ DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, true);
+ if (buttons->down & GESTURES_BUTTON_RIGHT)
+ DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, true);
+ if (buttons->up & GESTURES_BUTTON_LEFT)
+ DispatchMouseButton(EVDEV_MODIFIER_LEFT_MOUSE_BUTTON, false);
+ if (buttons->up & GESTURES_BUTTON_MIDDLE)
+ DispatchMouseButton(EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON, false);
+ if (buttons->up & GESTURES_BUTTON_RIGHT)
+ DispatchMouseButton(EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON, false);
+}
+
+void GestureInterpreterLibevdevCros::Dispatch(Event* event) {
+ dispatch_callback_.Run(event);
+}
+
+void GestureInterpreterLibevdevCros::DispatchMouseButton(unsigned int modifier,
+ bool down) {
+ if (!cursor_)
+ return; // No cursor!
+ const gfx::PointF& loc = cursor_->location();
+ int flag = modifiers_->GetEventFlagFromModifier(modifier);
+ EventType type = (down ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED);
+ modifiers_->UpdateModifier(modifier, down);
+ MouseEvent event(type, loc, loc, modifiers_->GetModifierFlags() | flag, flag);
+
+ // This hack is necessary to trigger setting the repeat count.
+ // TODO(spang): Fix it.
+ MouseEvent event2(&event);
+ Dispatch(&event2);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h
new file mode 100644
index 00000000000..30d8f62ab90
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h
@@ -0,0 +1,82 @@
+// 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_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_INTERPRETER_LIBEVDEV_CROS_H_
+#define UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_INTERPRETER_LIBEVDEV_CROS_H_
+
+#include <gestures/gestures.h>
+#include <libevdev/libevdev.h>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+#include "ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h"
+
+namespace ui {
+
+class Event;
+class EventDeviceInfo;
+class EventModifiersEvdev;
+class CursorDelegateEvdev;
+
+typedef base::Callback<void(Event*)> EventDispatchCallback;
+
+// Convert libevdev-cros events to ui::Events using libgestures.
+//
+// This builds a GestureInterpreter for an input device (touchpad or
+// mouse).
+//
+// Raw input events must be preprocessed into a form suitable for
+// libgestures. The kernel protocol only emits changes to the device state,
+// so changes must be accumulated until a sync event. The full device state
+// at sync is then processed by libgestures.
+//
+// Once we have the state at sync, we convert it to a HardwareState object
+// and forward it to libgestures. If any gestures are produced, they are
+// converted to ui::Events and dispatched.
+class EVENTS_OZONE_EVDEV_EXPORT GestureInterpreterLibevdevCros
+ : public EventReaderLibevdevCros::Delegate {
+ public:
+ GestureInterpreterLibevdevCros(EventModifiersEvdev* modifiers,
+ CursorDelegateEvdev* cursor,
+ const EventDispatchCallback& callback);
+ virtual ~GestureInterpreterLibevdevCros();
+
+ // Overriden from ui::EventReaderLibevdevCros::Delegate
+ virtual void OnLibEvdevCrosOpen(Evdev* evdev,
+ EventStateRec* evstate) OVERRIDE;
+ virtual void OnLibEvdevCrosEvent(Evdev* evdev,
+ EventStateRec* evstate,
+ const timeval& time) OVERRIDE;
+
+ // Handler for gesture events generated from libgestures.
+ void OnGestureReady(const Gesture* gesture);
+
+ private:
+ void OnGestureMove(const Gesture* gesture, const GestureMove* move);
+ void OnGestureScroll(const Gesture* gesture, const GestureScroll* move);
+ void OnGestureButtonsChange(const Gesture* gesture,
+ const GestureButtonsChange* move);
+ void Dispatch(Event* event);
+ void DispatchMouseButton(unsigned int modifier, bool down);
+
+ // Shared modifier state.
+ EventModifiersEvdev* modifiers_;
+
+ // Shared cursor state.
+ CursorDelegateEvdev* cursor_;
+
+ // Callback for dispatching events.
+ EventDispatchCallback dispatch_callback_;
+
+ // Gestures interpretation state.
+ gestures::GestureInterpreter* interpreter_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureInterpreterLibevdevCros);
+};
+
+} // namspace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_INTERPRETER_LIBEVDEV_CROS_H_
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.cc
new file mode 100644
index 00000000000..009fc939020
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.cc
@@ -0,0 +1,32 @@
+// 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/events/ozone/evdev/libgestures_glue/gesture_logging.h"
+
+#include <gestures/gestures.h>
+#include <stdarg.h>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+namespace {
+
+std::string FormatLog(const char* fmt, va_list args) {
+ std::string msg = base::StringPrintV(fmt, args);
+ if (!msg.empty() && msg[msg.size() - 1] == '\n')
+ msg.erase(msg.end() - 1, msg.end());
+ return msg;
+}
+
+} // namespace
+
+void gestures_log(int verb, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ if (verb <= GESTURES_LOG_ERROR)
+ LOG(ERROR) << "gestures: " << FormatLog(fmt, args);
+ else if (verb <= GESTURES_LOG_INFO)
+ VLOG(3) << "gestures: " << FormatLog(fmt, args);
+ va_end(args);
+}
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.h b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.h
new file mode 100644
index 00000000000..a5f543556ab
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_logging.h
@@ -0,0 +1,15 @@
+// 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_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_LOGGING_H_
+#define UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_LOGGING_H_
+
+// libgestures.so binds to this function for logging.
+// TODO(spang): Fix libgestures to not require this.
+extern "C"
+ __attribute__((visibility("default"))) void gestures_log(int verb,
+ const char* fmt,
+ ...);
+
+#endif // UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_LOGGING_H_
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.cc b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.cc
new file mode 100644
index 00000000000..92f15b77825
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.cc
@@ -0,0 +1,72 @@
+// 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/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h"
+
+#include <gestures/gestures.h>
+
+#include "base/timer/timer.h"
+
+// libgestures requires that this be in the top level namespace.
+class GesturesTimer {
+ public:
+ GesturesTimer() : callback_(NULL), callback_data_(NULL) {}
+ ~GesturesTimer() {}
+
+ void Set(stime_t delay, GesturesTimerCallback callback, void* callback_data) {
+ callback_ = callback;
+ callback_data_ = callback_data;
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMicroseconds(
+ delay * base::Time::kMicrosecondsPerSecond),
+ this,
+ &GesturesTimer::OnTimerExpired);
+ }
+
+ void Cancel() { timer_.Stop(); }
+
+ private:
+ void OnTimerExpired() {
+ struct timespec ts;
+ CHECK(!clock_gettime(CLOCK_MONOTONIC, &ts));
+ stime_t next_delay = callback_(StimeFromTimespec(&ts), callback_data_);
+ if (next_delay >= 0) {
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMicroseconds(
+ next_delay * base::Time::kMicrosecondsPerSecond),
+ this,
+ &GesturesTimer::OnTimerExpired);
+ }
+ }
+
+ GesturesTimerCallback callback_;
+ void* callback_data_;
+ base::OneShotTimer<GesturesTimer> timer_;
+};
+
+namespace ui {
+
+namespace {
+
+GesturesTimer* GesturesTimerCreate(void* data) { return new GesturesTimer; }
+
+void GesturesTimerSet(void* data,
+ GesturesTimer* timer,
+ stime_t delay,
+ GesturesTimerCallback callback,
+ void* callback_data) {
+ timer->Set(delay, callback, callback_data);
+}
+
+void GesturesTimerCancel(void* data, GesturesTimer* timer) { timer->Cancel(); }
+
+void GesturesTimerFree(void* data, GesturesTimer* timer) { delete timer; }
+
+} // namespace
+
+const GesturesTimerProvider kGestureTimerProvider = {
+ GesturesTimerCreate, GesturesTimerSet, GesturesTimerCancel,
+ GesturesTimerFree};
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h
new file mode 100644
index 00000000000..edc20ba9c07
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h
@@ -0,0 +1,16 @@
+// 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_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_TIMER_PROVIDER_H_
+#define UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_TIMER_PROVIDER_H_
+
+#include <gestures/gestures.h>
+
+namespace ui {
+
+extern const GesturesTimerProvider kGestureTimerProvider;
+
+} // namspace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_TIMER_PROVIDER_H_
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter.cc b/chromium/ui/events/ozone/evdev/touch_event_converter.cc
deleted file mode 100644
index dc3c30a43f6..00000000000
--- a/chromium/ui/events/ozone/evdev/touch_event_converter.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/touch_event_converter.h"
-
-#include <fcntl.h>
-#include <linux/input.h>
-#include <poll.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <cmath>
-#include <limits>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_ozone.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-namespace {
-
-// Number is determined empirically.
-// TODO(rjkroege): Configure this per device.
-const float kFingerWidth = 25.f;
-
-} // namespace
-
-namespace ui {
-
-TouchEventConverterEvdev::TouchEventConverterEvdev(int fd, int id)
- : pressure_min_(0),
- pressure_max_(0),
- x_scale_(1.),
- y_scale_(1.),
- x_max_(std::numeric_limits<int>::max()),
- y_max_(std::numeric_limits<int>::max()),
- current_slot_(0),
- fd_(fd),
- id_(id) {
- Init();
-}
-
-TouchEventConverterEvdev::~TouchEventConverterEvdev() {
- if (fd_ >= 0 && close(fd_) < 0)
- DLOG(WARNING) << "failed close on /dev/input/event" << id_;
-}
-
-void TouchEventConverterEvdev::Init() {
- input_absinfo abs = {};
- if (ioctl(fd_, EVIOCGABS(ABS_MT_SLOT), &abs) != -1) {
- CHECK_GE(abs.maximum, abs.minimum);
- CHECK_GE(abs.minimum, 0);
- } else {
- DLOG(WARNING) << "failed ioctl EVIOCGABS ABS_MT_SLOT event" << id_;
- }
- if (ioctl(fd_, EVIOCGABS(ABS_MT_PRESSURE), &abs) != -1) {
- pressure_min_ = abs.minimum;
- pressure_max_ = abs.maximum;
- } else {
- DLOG(WARNING) << "failed ioctl EVIOCGABS ABS_MT_PRESSURE event" << id_;
- }
- int x_min = 0, x_max = 0;
- if (ioctl(fd_, EVIOCGABS(ABS_MT_POSITION_X), &abs) != -1) {
- x_min = abs.minimum;
- x_max = abs.maximum;
- } else {
- LOG(WARNING) << "failed ioctl EVIOCGABS ABS_X event" << id_;
- }
- int y_min = 0, y_max = 0;
- if (ioctl(fd_, EVIOCGABS(ABS_MT_POSITION_Y), &abs) != -1) {
- y_min = abs.minimum;
- y_max = abs.maximum;
- } else {
- LOG(WARNING) << "failed ioctl EVIOCGABS ABS_Y event" << id_;
- }
- if (x_max && y_max && gfx::SurfaceFactoryOzone::GetInstance()) {
- const char* display =
- gfx::SurfaceFactoryOzone::GetInstance()->DefaultDisplaySpec();
- int screen_width, screen_height;
- int sc = sscanf(display, "%dx%d", &screen_width, &screen_height);
- if (sc == 2) {
- x_scale_ = (double)screen_width / (x_max - x_min);
- y_scale_ = (double)screen_height / (y_max - y_min);
- x_max_ = screen_width - 1;
- y_max_ = screen_height - 1;
- LOG(INFO) << "touch input x_scale=" << x_scale_
- << " y_scale=" << y_scale_;
- } else {
- LOG(WARNING) << "malformed display spec from "
- << "SurfaceFactoryOzone::DefaultDisplaySpec";
- }
- }
-}
-
-void TouchEventConverterEvdev::OnFileCanWriteWithoutBlocking(int /* fd */) {
- // Read-only file-descriptors.
- NOTREACHED();
-}
-
-void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
- input_event inputs[MAX_FINGERS * 6 + 1];
- ssize_t read_size = read(fd, inputs, sizeof(inputs));
- if (read_size <= 0)
- return;
-
- for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
- const input_event& input = inputs[i];
- if (input.type == EV_ABS) {
- switch (input.code) {
- case ABS_MT_TOUCH_MAJOR:
- altered_slots_.set(current_slot_);
- events_[current_slot_].major_ = input.value;
- break;
- case ABS_X:
- case ABS_MT_POSITION_X:
- altered_slots_.set(current_slot_);
- events_[current_slot_].x_ = roundf(input.value * x_scale_);
- break;
- case ABS_Y:
- case ABS_MT_POSITION_Y:
- altered_slots_.set(current_slot_);
- events_[current_slot_].y_ = roundf(input.value * y_scale_);
- break;
- case ABS_MT_TRACKING_ID:
- altered_slots_.set(current_slot_);
- if (input.value < 0) {
- events_[current_slot_].type_ = ET_TOUCH_RELEASED;
- } else {
- events_[current_slot_].finger_ = input.value;
- events_[current_slot_].type_ = ET_TOUCH_PRESSED;
- }
- break;
- case ABS_MT_PRESSURE:
- case ABS_PRESSURE:
- altered_slots_.set(current_slot_);
- events_[current_slot_].pressure_ = input.value - pressure_min_;
- events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
- break;
- case ABS_MT_SLOT:
- current_slot_ = input.value;
- altered_slots_.set(current_slot_);
- break;
- default:
- NOTREACHED() << "invalid code for EV_ABS: " << input.code;
- }
- } else if (input.type == EV_SYN) {
- switch (input.code) {
- case SYN_REPORT:
- for (int j = 0; j < MAX_FINGERS; j++) {
- if (altered_slots_[j]) {
- // TODO(rjkroege): Support elliptical finger regions.
- scoped_ptr<TouchEvent> tev(new TouchEvent(
- events_[j].type_,
- gfx::Point(std::min(x_max_, events_[j].x_),
- std::min(y_max_, events_[j].y_)),
- /* flags */ 0,
- /* touch_id */ j,
- base::TimeDelta::FromMicroseconds(
- input.time.tv_sec * 1000000 + input.time.tv_usec),
- events_[j].pressure_ * kFingerWidth,
- events_[j].pressure_ * kFingerWidth,
- /* angle */ 0.,
- events_[j].pressure_));
- DispatchEvent(tev.PassAs<ui::Event>());
-
- // Subsequent events for this finger will be touch-move until it
- // is released.
- events_[j].type_ = ET_TOUCH_MOVED;
- }
- }
- altered_slots_.reset();
- break;
- case SYN_MT_REPORT:
- case SYN_CONFIG:
- case SYN_DROPPED:
- NOTREACHED() << "invalid code for EV_SYN: " << input.code;
- break;
- }
- } else if (input.type == EV_KEY) {
- switch (input.code) {
- case BTN_TOUCH:
- break;
- default:
- NOTREACHED() << "invalid code for EV_KEY: " << input.code;
- }
- } else {
- NOTREACHED() << "invalid type: " << input.type;
- }
- }
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter.h b/chromium/ui/events/ozone/evdev/touch_event_converter.h
deleted file mode 100644
index 7ebac408d8f..00000000000
--- a/chromium/ui/events/ozone/evdev/touch_event_converter.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
-#define UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
-
-#include <bitset>
-
-#include "base/compiler_specific.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/events_export.h"
-#include "ui/events/ozone/event_converter_ozone.h"
-
-namespace ui {
-
-class TouchEvent;
-
-class EVENTS_EXPORT TouchEventConverterEvdev : public EventConverterOzone {
- public:
- enum {
- MAX_FINGERS = 11
- };
- TouchEventConverterEvdev(int fd, int id);
- virtual ~TouchEventConverterEvdev();
-
- private:
- friend class MockTouchEventConverterEvdev;
-
- // Unsafe part of initialization.
- void Init();
-
- // Overidden from base::MessagePumpLibevent::Watcher.
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
-
- // Pressure values.
- int pressure_min_;
- int pressure_max_; // Used to normalize pressure values.
-
- // Touch scaling.
- float x_scale_;
- float y_scale_;
-
- // Maximum coordinate-values allowed for the events.
- int x_max_;
- int y_max_;
-
- // Touch point currently being updated from the /dev/input/event* stream.
- int current_slot_;
-
- // File descriptor for the /dev/input/event* instance.
- int fd_;
-
- // Number corresponding to * in the source evdev device: /dev/input/event*
- int id_;
-
- // Bit field tracking which in-progress touch points have been modified
- // without a syn event.
- std::bitset<MAX_FINGERS> altered_slots_;
-
- struct InProgressEvents {
- int x_;
- int y_;
- int id_; // Device reported "unique" touch point id; -1 means not active
- int finger_; // "Finger" id starting from 0; -1 means not active
-
- EventType type_;
- int major_;
- float pressure_;
- };
-
- // In-progress touch points.
- InProgressEvents events_[MAX_FINGERS];
-
- DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdev);
-};
-
-} // namespace ui
-
-#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
-
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc
new file mode 100644
index 00000000000..9cfab5bf11c
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -0,0 +1,307 @@
+// 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/events/ozone/evdev/touch_event_converter_evdev.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <cmath>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_switches.h"
+#include "ui/gfx/screen.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+
+namespace {
+
+// Number is determined empirically.
+// TODO(rjkroege): Configure this per device.
+const float kFingerWidth = 25.f;
+
+struct TouchCalibration {
+ int bezel_left;
+ int bezel_right;
+ int bezel_top;
+ int bezel_bottom;
+};
+
+void GetTouchCalibration(TouchCalibration* cal) {
+ std::vector<std::string> parts;
+ if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTouchCalibration),
+ ",",
+ &parts) >= 4) {
+ if (!base::StringToInt(parts[0], &cal->bezel_left))
+ DLOG(ERROR) << "Incorrect left border calibration value passed.";
+ if (!base::StringToInt(parts[1], &cal->bezel_right))
+ DLOG(ERROR) << "Incorrect right border calibration value passed.";
+ if (!base::StringToInt(parts[2], &cal->bezel_top))
+ DLOG(ERROR) << "Incorrect top border calibration value passed.";
+ if (!base::StringToInt(parts[3], &cal->bezel_bottom))
+ DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
+ }
+}
+
+float TuxelsToPixels(float val,
+ float min_tuxels,
+ float num_tuxels,
+ float min_pixels,
+ float num_pixels) {
+ // Map [min_tuxels, min_tuxels + num_tuxels) to
+ // [min_pixels, min_pixels + num_pixels).
+ return min_pixels + (val - min_tuxels) * num_pixels / num_tuxels;
+}
+
+} // namespace
+
+namespace ui {
+
+TouchEventConverterEvdev::TouchEventConverterEvdev(
+ int fd,
+ base::FilePath path,
+ const EventDeviceInfo& info,
+ const EventDispatchCallback& callback)
+ : EventConverterEvdev(callback),
+ syn_dropped_(false),
+ is_type_a_(false),
+ current_slot_(0),
+ fd_(fd),
+ path_(path) {
+ Init(info);
+}
+
+TouchEventConverterEvdev::~TouchEventConverterEvdev() {
+ Stop();
+ close(fd_);
+}
+
+void TouchEventConverterEvdev::Init(const EventDeviceInfo& info) {
+ gfx::Screen *screen = gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
+ if (!screen)
+ return; // No scaling.
+ gfx::Display display = screen->GetPrimaryDisplay();
+ gfx::Size size = display.GetSizeInPixel();
+
+ pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE),
+ pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE),
+ x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X),
+ x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1,
+ y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y),
+ y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1,
+ x_min_pixels_ = x_min_tuxels_,
+ x_num_pixels_ = x_num_tuxels_,
+ y_min_pixels_ = y_min_tuxels_,
+ y_num_pixels_ = y_num_tuxels_,
+
+ // Map coordinates onto screen.
+ x_min_pixels_ = 0;
+ y_min_pixels_ = 0;
+ x_num_pixels_ = size.width();
+ y_num_pixels_ = size.height();
+
+ VLOG(1) << "mapping touch coordinates to screen coordinates: "
+ << base::StringPrintf("%dx%d", size.width(), size.height());
+
+ // Apply --touch-calibration.
+ TouchCalibration cal = {};
+ GetTouchCalibration(&cal);
+ x_min_tuxels_ += cal.bezel_left;
+ x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
+ y_min_tuxels_ += cal.bezel_top;
+ y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;
+
+ VLOG(1) << "applying touch calibration: "
+ << base::StringPrintf("[%d, %d, %d, %d]",
+ cal.bezel_left,
+ cal.bezel_right,
+ cal.bezel_top,
+ cal.bezel_bottom);
+}
+
+void TouchEventConverterEvdev::Start() {
+ base::MessageLoopForUI::current()->WatchFileDescriptor(
+ fd_, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
+}
+
+void TouchEventConverterEvdev::Stop() {
+ controller_.StopWatchingFileDescriptor();
+}
+
+bool TouchEventConverterEvdev::Reinitialize() {
+ EventDeviceInfo info;
+ if (info.Initialize(fd_)) {
+ Init(info);
+ return true;
+ }
+ return false;
+}
+
+void TouchEventConverterEvdev::OnFileCanWriteWithoutBlocking(int /* fd */) {
+ // Read-only file-descriptors.
+ NOTREACHED();
+}
+
+void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
+ input_event inputs[MAX_FINGERS * 6 + 1];
+ ssize_t read_size = read(fd, inputs, sizeof(inputs));
+ if (read_size < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ return;
+ if (errno != ENODEV)
+ PLOG(ERROR) << "error reading device " << path_.value();
+ Stop();
+ return;
+ }
+
+ for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
+ ProcessInputEvent(inputs[i]);
+ }
+}
+
+void TouchEventConverterEvdev::ProcessInputEvent(const input_event& input) {
+ if (input.type == EV_SYN) {
+ ProcessSyn(input);
+ } else if(syn_dropped_) {
+ // Do nothing. This branch indicates we have lost sync with the driver.
+ } else if (input.type == EV_ABS) {
+ if (current_slot_ >= MAX_FINGERS) {
+ LOG(ERROR) << "too many touch events: " << current_slot_;
+ return;
+ }
+ ProcessAbs(input);
+ } else if (input.type == EV_KEY) {
+ switch (input.code) {
+ case BTN_TOUCH:
+ break;
+ default:
+ NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
+ }
+ } else {
+ NOTIMPLEMENTED() << "invalid type: " << input.type;
+ }
+}
+
+void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
+ switch (input.code) {
+ case ABS_MT_TOUCH_MAJOR:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].major_ = input.value;
+ break;
+ case ABS_X:
+ case ABS_MT_POSITION_X:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].x_ = TuxelsToPixels(input.value,
+ x_min_tuxels_,
+ x_num_tuxels_,
+ x_min_pixels_,
+ x_num_pixels_);
+ break;
+ case ABS_Y:
+ case ABS_MT_POSITION_Y:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].y_ = TuxelsToPixels(input.value,
+ y_min_tuxels_,
+ y_num_tuxels_,
+ y_min_pixels_,
+ y_num_pixels_);
+ break;
+ case ABS_MT_TRACKING_ID:
+ altered_slots_.set(current_slot_);
+ if (input.value < 0) {
+ events_[current_slot_].type_ = ET_TOUCH_RELEASED;
+ } else {
+ events_[current_slot_].finger_ = input.value;
+ events_[current_slot_].type_ = ET_TOUCH_PRESSED;
+ }
+ break;
+ case ABS_MT_PRESSURE:
+ case ABS_PRESSURE:
+ altered_slots_.set(current_slot_);
+ events_[current_slot_].pressure_ = input.value - pressure_min_;
+ events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
+ break;
+ case ABS_MT_SLOT:
+ current_slot_ = input.value;
+ altered_slots_.set(current_slot_);
+ break;
+ default:
+ NOTIMPLEMENTED() << "invalid code for EV_ABS: " << input.code;
+ }
+}
+
+void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
+ switch (input.code) {
+ case SYN_REPORT:
+ if (syn_dropped_) {
+ // Have to re-initialize.
+ if (Reinitialize()) {
+ syn_dropped_ = false;
+ altered_slots_.reset();
+ } else {
+ LOG(ERROR) << "failed to re-initialize device info";
+ }
+ } else {
+ ReportEvents(base::TimeDelta::FromMicroseconds(
+ input.time.tv_sec * 1000000 + input.time.tv_usec));
+ }
+ if (is_type_a_)
+ current_slot_ = 0;
+ break;
+ case SYN_MT_REPORT:
+ // For type A devices, we just get a stream of all current contacts,
+ // in some arbitrary order.
+ events_[current_slot_++].type_ = ET_TOUCH_PRESSED;
+ is_type_a_ = true;
+ break;
+ case SYN_DROPPED:
+ // Some buffer has overrun. We ignore all events up to and
+ // including the next SYN_REPORT.
+ syn_dropped_ = true;
+ break;
+ default:
+ NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
+ }
+}
+
+void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
+ for (int i = 0; i < MAX_FINGERS; i++) {
+ if (altered_slots_[i]) {
+ // TODO(rikroege): Support elliptical finger regions.
+ TouchEvent evt(
+ events_[i].type_,
+ gfx::PointF(events_[i].x_, events_[i].y_),
+ /* flags */ 0,
+ /* touch_id */ i,
+ delta,
+ events_[i].pressure_ * kFingerWidth,
+ events_[i].pressure_ * kFingerWidth,
+ /* angle */ 0.,
+ events_[i].pressure_);
+ DispatchEventToCallback(&evt);
+
+ // Subsequent events for this finger will be touch-move until it
+ // is released.
+ events_[i].type_ = ET_TOUCH_MOVED;
+ }
+ }
+ altered_slots_.reset();
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h
new file mode 100644
index 00000000000..668901d5f9d
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -0,0 +1,118 @@
+// 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_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
+
+#include <bitset>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_pump_libevent.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/ozone/evdev/event_converter_evdev.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+
+namespace ui {
+
+class TouchEvent;
+
+class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
+ : public EventConverterEvdev,
+ public base::MessagePumpLibevent::Watcher {
+ public:
+ enum {
+ MAX_FINGERS = 11
+ };
+ TouchEventConverterEvdev(int fd,
+ base::FilePath path,
+ const EventDeviceInfo& info,
+ const EventDispatchCallback& dispatch);
+ virtual ~TouchEventConverterEvdev();
+
+ // Start & stop watching for events.
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ private:
+ friend class MockTouchEventConverterEvdev;
+
+ // Unsafe part of initialization.
+ void Init(const EventDeviceInfo& info);
+
+ // Overidden from base::MessagePumpLibevent::Watcher.
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+ virtual bool Reinitialize();
+
+ void ProcessInputEvent(const input_event& input);
+ void ProcessAbs(const input_event& input);
+ void ProcessSyn(const input_event& input);
+
+ void ReportEvents(base::TimeDelta delta);
+
+ // Set if we have seen a SYN_DROPPED and not yet re-synced with the device.
+ bool syn_dropped_;
+
+ // Set if this is a type A device (uses SYN_MT_REPORT).
+ bool is_type_a_;
+
+ // Pressure values.
+ int pressure_min_;
+ int pressure_max_; // Used to normalize pressure values.
+
+ // Input range for x-axis.
+ float x_min_tuxels_;
+ float x_num_tuxels_;
+
+ // Input range for y-axis.
+ float y_min_tuxels_;
+ float y_num_tuxels_;
+
+ // Output range for x-axis.
+ float x_min_pixels_;
+ float x_num_pixels_;
+
+ // Output range for y-axis.
+ float y_min_pixels_;
+ float y_num_pixels_;
+
+ // Touch point currently being updated from the /dev/input/event* stream.
+ int current_slot_;
+
+ // File descriptor for the /dev/input/event* instance.
+ int fd_;
+
+ // Path to input device.
+ base::FilePath path_;
+
+ // Bit field tracking which in-progress touch points have been modified
+ // without a syn event.
+ std::bitset<MAX_FINGERS> altered_slots_;
+
+ struct InProgressEvents {
+ float x_;
+ float y_;
+ int id_; // Device reported "unique" touch point id; -1 means not active
+ int finger_; // "Finger" id starting from 0; -1 means not active
+
+ EventType type_;
+ int major_;
+ float pressure_;
+ };
+
+ // In-progress touch points.
+ InProgressEvents events_[MAX_FINGERS];
+
+ // Controller for watching the input fd.
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdev);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_OZONE_EVDEV_TOUCH_EVENT_CONVERTER_EVDEV_H_
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
new file mode 100644
index 00000000000..ce2957a1ece
--- /dev/null
+++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -0,0 +1,481 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+
+namespace {
+
+static int SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+const char kTestDevicePath[] = "/dev/input/test-device";
+
+} // namespace
+
+namespace ui {
+
+class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
+ public:
+ MockTouchEventConverterEvdev(int fd, base::FilePath path);
+ virtual ~MockTouchEventConverterEvdev() {};
+
+ void ConfigureReadMock(struct input_event* queue,
+ long read_this_many,
+ long queue_index);
+
+ unsigned size() { return dispatched_events_.size(); }
+ TouchEvent* event(unsigned index) { return dispatched_events_[index]; }
+
+ // Actually dispatch the event reader code.
+ void ReadNow() {
+ OnFileCanReadWithoutBlocking(read_pipe_);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void DispatchCallback(Event* event) {
+ dispatched_events_.push_back(
+ new TouchEvent(*static_cast<TouchEvent*>(event)));
+ }
+
+ virtual bool Reinitialize() OVERRIDE { return true; }
+
+ private:
+ int read_pipe_;
+ int write_pipe_;
+
+ ScopedVector<TouchEvent> dispatched_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockTouchEventConverterEvdev);
+};
+
+MockTouchEventConverterEvdev::MockTouchEventConverterEvdev(int fd,
+ base::FilePath path)
+ : TouchEventConverterEvdev(
+ fd,
+ path,
+ EventDeviceInfo(),
+ base::Bind(&MockTouchEventConverterEvdev::DispatchCallback,
+ base::Unretained(this))) {
+ pressure_min_ = 30;
+ pressure_max_ = 60;
+
+ // TODO(rjkroege): Check test axes.
+ x_min_pixels_ = x_min_tuxels_ = 0;
+ x_num_pixels_ = x_num_tuxels_ = std::numeric_limits<int>::max();
+ y_min_pixels_ = y_min_tuxels_ = 0;
+ y_num_pixels_ = y_num_tuxels_ = std::numeric_limits<int>::max();
+
+ int fds[2];
+
+ if (pipe(fds))
+ PLOG(FATAL) << "failed pipe";
+
+ DCHECK(SetNonBlocking(fds[0]) == 0)
+ << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ DCHECK(SetNonBlocking(fds[1]) == 0)
+ << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ read_pipe_ = fds[0];
+ write_pipe_ = fds[1];
+}
+
+void MockTouchEventConverterEvdev::ConfigureReadMock(struct input_event* queue,
+ long read_this_many,
+ long queue_index) {
+ int nwrite = HANDLE_EINTR(write(write_pipe_,
+ queue + queue_index,
+ sizeof(struct input_event) * read_this_many));
+ DCHECK(nwrite ==
+ static_cast<int>(sizeof(struct input_event) * read_this_many))
+ << "write() failed, errno: " << errno;
+}
+
+} // namespace ui
+
+// Test fixture.
+class TouchEventConverterEvdevTest : public testing::Test {
+ public:
+ TouchEventConverterEvdevTest() {}
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ // Set up pipe to satisfy message pump (unused).
+ int evdev_io[2];
+ if (pipe(evdev_io))
+ PLOG(FATAL) << "failed pipe";
+ events_in_ = evdev_io[0];
+ events_out_ = evdev_io[1];
+
+ loop_ = new base::MessageLoopForUI;
+ device_ = new ui::MockTouchEventConverterEvdev(
+ events_in_, base::FilePath(kTestDevicePath));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ delete device_;
+ delete loop_;
+ }
+
+ ui::MockTouchEventConverterEvdev* device() { return device_; }
+
+ private:
+ base::MessageLoop* loop_;
+ ui::MockTouchEventConverterEvdev* device_;
+
+ int events_out_;
+ int events_in_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdevTest);
+};
+
+// TODO(rjkroege): Test for valid handling of time stamps.
+TEST_F(TouchEventConverterEvdevTest, TouchDown) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ dev->ConfigureReadMock(mock_kernel_queue, 1, 0);
+ dev->ReadNow();
+ EXPECT_EQ(0u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue, 2, 1);
+ dev->ReadNow();
+ EXPECT_EQ(0u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue, 3, 3);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ ui::TouchEvent* event = dev->event(0);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(51, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(.5f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterEvdevTest, NoEvents) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+ dev->ConfigureReadMock(NULL, 0, 0);
+ EXPECT_EQ(0u, dev->size());
+}
+
+TEST_F(TouchEventConverterEvdevTest, TouchMove) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue_press[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 50},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 43}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_move2[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 42}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ dev->ConfigureReadMock(mock_kernel_queue_move1, 4, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+ ui::TouchEvent* event = dev->event(1);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(43, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+
+ dev->ConfigureReadMock(mock_kernel_queue_move2, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(3u, dev->size());
+ event = dev->event(2);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(42, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterEvdevTest, TouchRelease) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue_press[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ struct input_event mock_kernel_queue_release[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+ ui::TouchEvent* event = dev->event(0);
+ EXPECT_FALSE(event == NULL);
+
+ dev->ConfigureReadMock(mock_kernel_queue_release, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+ event = dev->event(1);
+ EXPECT_FALSE(event == NULL);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
+ EXPECT_EQ(42, event->x());
+ EXPECT_EQ(51, event->y());
+ EXPECT_EQ(0, event->touch_id());
+ EXPECT_FLOAT_EQ(.5f, event->force());
+ EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
+}
+
+TEST_F(TouchEventConverterEvdevTest, TwoFingerGesture) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ ui::TouchEvent* ev0;
+ ui::TouchEvent* ev1;
+
+ struct input_event mock_kernel_queue_press0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Setup and discard a press.
+ dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ struct input_event mock_kernel_queue_move0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Setup and discard a move.
+ dev->ConfigureReadMock(mock_kernel_queue_move0, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+
+ struct input_event mock_kernel_queue_move0press1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ {{0, 0}, EV_ABS, ABS_MT_SLOT, 1}, {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 686},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 101},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 102}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ // Move on 0, press on 1.
+ dev->ConfigureReadMock(mock_kernel_queue_move0press1, 9, 0);
+ dev->ReadNow();
+ EXPECT_EQ(4u, dev->size());
+ ev0 = dev->event(2);
+ ev1 = dev->event(3);
+
+ // Move
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(40, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ // Press
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(101, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Stationary 0, Moves 1.
+ struct input_event mock_kernel_queue_stationary0_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_stationary0_move1, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(5u, dev->size());
+ ev1 = dev->event(4);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(40, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Move 0, stationary 1.
+ struct input_event mock_kernel_queue_move0_stationary1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_SLOT, 0}, {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 39},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_move0_stationary1, 3, 0);
+ dev->ReadNow();
+ EXPECT_EQ(6u, dev->size());
+ ev0 = dev->event(5);
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(39, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ // Release 0, move 1.
+ struct input_event mock_kernel_queue_release0_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_ABS, ABS_MT_SLOT, 1},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 38}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_release0_move1, 4, 0);
+ dev->ReadNow();
+ EXPECT_EQ(8u, dev->size());
+ ev0 = dev->event(6);
+ ev1 = dev->event(7);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev0->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
+ EXPECT_EQ(39, ev0->x());
+ EXPECT_EQ(51, ev0->y());
+ EXPECT_EQ(0, ev0->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev0->force());
+ EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
+
+ EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(38, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+
+ // Release 1.
+ struct input_event mock_kernel_queue_release1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
+ };
+ dev->ConfigureReadMock(mock_kernel_queue_release1, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(9u, dev->size());
+ ev1 = dev->event(8);
+
+ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev1->type());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
+ EXPECT_EQ(38, ev1->x());
+ EXPECT_EQ(102, ev1->y());
+ EXPECT_EQ(1, ev1->touch_id());
+ EXPECT_FLOAT_EQ(.5f, ev1->force());
+ EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
+}
+
+TEST_F(TouchEventConverterEvdevTest, TypeA) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue_press0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51},
+ {{0, 0}, EV_SYN, SYN_MT_REPORT, 0},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 61},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 71},
+ {{0, 0}, EV_SYN, SYN_MT_REPORT, 0},
+ {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Check that two events are generated.
+ dev->ConfigureReadMock(mock_kernel_queue_press0, 10, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+}
+
+TEST_F(TouchEventConverterEvdevTest, Unsync) {
+ ui::MockTouchEventConverterEvdev* dev = device();
+
+ struct input_event mock_kernel_queue_press0[] = {
+ {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
+ {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
+ {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ // Prepare a move with a drop.
+ struct input_event mock_kernel_queue_move0[] = {
+ {{0, 0}, EV_SYN, SYN_DROPPED, 0},
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Verify that we didn't receive it/
+ dev->ConfigureReadMock(mock_kernel_queue_move0, 3, 0);
+ dev->ReadNow();
+ EXPECT_EQ(1u, dev->size());
+
+ struct input_event mock_kernel_queue_move1[] = {
+ {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
+ };
+
+ // Verify that it re-syncs after a SYN_REPORT.
+ dev->ConfigureReadMock(mock_kernel_queue_move1, 2, 0);
+ dev->ReadNow();
+ EXPECT_EQ(2u, dev->size());
+}
diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_unittest.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_unittest.cc
deleted file mode 100644
index d99ab720115..00000000000
--- a/chromium/ui/events/ozone/evdev/touch_event_converter_unittest.cc
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <unistd.h>
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/run_loop.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/events/ozone/evdev/touch_event_converter.h"
-
-namespace {
-
-static int SetNonBlocking(int fd) {
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
- flags = 0;
- return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-}
-
-} // namespace
-
-namespace ui {
-
-class MockTouchEventConverterEvdev : public TouchEventConverterEvdev,
- public base::MessageLoop::Dispatcher {
- public:
- MockTouchEventConverterEvdev(int a, int b);
- virtual ~MockTouchEventConverterEvdev() {};
-
- void ConfigureReadMock(struct input_event* queue,
- long read_this_many,
- long queue_index);
-
- unsigned size() { return dispatched_events_.size(); }
- TouchEvent* event(unsigned index) { return dispatched_events_[index]; }
-
- // Actually dispatch the event reader code.
- void ReadNow() {
- OnFileCanReadWithoutBlocking(read_pipe_);
- base::RunLoop().RunUntilIdle();
- }
-
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- private:
- int read_pipe_;
- int write_pipe_;
-
- ScopedVector<TouchEvent> dispatched_events_;
-
- DISALLOW_COPY_AND_ASSIGN(MockTouchEventConverterEvdev);
-};
-
-MockTouchEventConverterEvdev::MockTouchEventConverterEvdev(int a, int b)
- : TouchEventConverterEvdev(a, b) {
- pressure_min_ = 30;
- pressure_max_ = 60;
-
- int fds[2];
-
- if (pipe(fds))
- NOTREACHED() << "failed pipe(): " << strerror(errno);
-
- DCHECK(SetNonBlocking(fds[0]) == 0)
- << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
- DCHECK(SetNonBlocking(fds[1]) == 0)
- << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
- read_pipe_ = fds[0];
- write_pipe_ = fds[1];
-}
-
-bool MockTouchEventConverterEvdev::Dispatch(const base::NativeEvent& event) {
- ui::TouchEvent* ev = new ui::TouchEvent(event);
- dispatched_events_.push_back(ev);
- return true;
-}
-
-void MockTouchEventConverterEvdev::ConfigureReadMock(struct input_event* queue,
- long read_this_many,
- long queue_index) {
- int nwrite = HANDLE_EINTR(write(write_pipe_,
- queue + queue_index,
- sizeof(struct input_event) * read_this_many));
- DCHECK(nwrite ==
- static_cast<int>(sizeof(struct input_event) * read_this_many))
- << "write() failed, errno: " << errno;
-}
-
-} // namespace ui
-
-// Test fixture.
-class TouchEventConverterEvdevTest : public testing::Test {
- public:
- TouchEventConverterEvdevTest() {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- loop_ = new base::MessageLoop(base::MessageLoop::TYPE_UI);
- device_ = new ui::MockTouchEventConverterEvdev(-1, 2);
- base::MessagePumpOzone::Current()->AddDispatcherForRootWindow(device_);
- }
- virtual void TearDown() OVERRIDE {
- delete device_;
- delete loop_;
- }
-
- ui::MockTouchEventConverterEvdev* device() { return device_; }
-
- private:
- base::MessageLoop* loop_;
- ui::MockTouchEventConverterEvdev* device_;
- DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdevTest);
-};
-
-// TODO(rjkroege): Test for valid handling of time stamps.
-TEST_F(TouchEventConverterEvdevTest, TouchDown) {
- ui::MockTouchEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
- {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- dev->ConfigureReadMock(mock_kernel_queue, 1, 0);
- dev->ReadNow();
- EXPECT_EQ(0u, dev->size());
-
- dev->ConfigureReadMock(mock_kernel_queue, 2, 1);
- dev->ReadNow();
- EXPECT_EQ(0u, dev->size());
-
- dev->ConfigureReadMock(mock_kernel_queue, 3, 3);
- dev->ReadNow();
- EXPECT_EQ(1u, dev->size());
-
- ui::TouchEvent* event = dev->event(0);
- EXPECT_FALSE(event == NULL);
-
- EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
- EXPECT_EQ(42, event->x());
- EXPECT_EQ(51, event->y());
- EXPECT_EQ(0, event->touch_id());
- EXPECT_FLOAT_EQ(.5f, event->force());
- EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
-}
-
-TEST_F(TouchEventConverterEvdevTest, NoEvents) {
- ui::MockTouchEventConverterEvdev* dev = device();
- dev->ConfigureReadMock(NULL, 0, 0);
- EXPECT_EQ(0u, dev->size());
-}
-
-TEST_F(TouchEventConverterEvdevTest, TouchMove) {
- ui::MockTouchEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue_press[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
- {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- struct input_event mock_kernel_queue_move1[] = {
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 50},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 43}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- struct input_event mock_kernel_queue_move2[] = {
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 42}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- // Setup and discard a press.
- dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
- dev->ReadNow();
- EXPECT_EQ(1u, dev->size());
-
- dev->ConfigureReadMock(mock_kernel_queue_move1, 4, 0);
- dev->ReadNow();
- EXPECT_EQ(2u, dev->size());
- ui::TouchEvent* event = dev->event(1);
- EXPECT_FALSE(event == NULL);
-
- EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
- EXPECT_EQ(42, event->x());
- EXPECT_EQ(43, event->y());
- EXPECT_EQ(0, event->touch_id());
- EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
- EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
-
- dev->ConfigureReadMock(mock_kernel_queue_move2, 2, 0);
- dev->ReadNow();
- EXPECT_EQ(3u, dev->size());
- event = dev->event(2);
- EXPECT_FALSE(event == NULL);
-
- EXPECT_EQ(ui::ET_TOUCH_MOVED, event->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
- EXPECT_EQ(42, event->x());
- EXPECT_EQ(42, event->y());
- EXPECT_EQ(0, event->touch_id());
- EXPECT_FLOAT_EQ(2.f / 3.f, event->force());
- EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
-}
-
-TEST_F(TouchEventConverterEvdevTest, TouchRelease) {
- ui::MockTouchEventConverterEvdev* dev = device();
-
- struct input_event mock_kernel_queue_press[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
- {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- struct input_event mock_kernel_queue_release[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
-
- // Setup and discard a press.
- dev->ConfigureReadMock(mock_kernel_queue_press, 6, 0);
- dev->ReadNow();
- EXPECT_EQ(1u, dev->size());
- ui::TouchEvent* event = dev->event(0);
- EXPECT_FALSE(event == NULL);
-
- dev->ConfigureReadMock(mock_kernel_queue_release, 2, 0);
- dev->ReadNow();
- EXPECT_EQ(2u, dev->size());
- event = dev->event(1);
- EXPECT_FALSE(event == NULL);
-
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), event->time_stamp());
- EXPECT_EQ(42, event->x());
- EXPECT_EQ(51, event->y());
- EXPECT_EQ(0, event->touch_id());
- EXPECT_FLOAT_EQ(.5f, event->force());
- EXPECT_FLOAT_EQ(0.f, event->rotation_angle());
-}
-
-TEST_F(TouchEventConverterEvdevTest, TwoFingerGesture) {
- ui::MockTouchEventConverterEvdev* dev = device();
-
- ui::TouchEvent* ev0;
- ui::TouchEvent* ev1;
-
- struct input_event mock_kernel_queue_press0[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 684},
- {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 42},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 51}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- // Setup and discard a press.
- dev->ConfigureReadMock(mock_kernel_queue_press0, 6, 0);
- dev->ReadNow();
- EXPECT_EQ(1u, dev->size());
-
- struct input_event mock_kernel_queue_move0[] = {
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- // Setup and discard a move.
- dev->ConfigureReadMock(mock_kernel_queue_move0, 2, 0);
- dev->ReadNow();
- EXPECT_EQ(2u, dev->size());
-
- struct input_event mock_kernel_queue_move0press1[] = {
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
- {{0, 0}, EV_ABS, ABS_MT_SLOT, 1}, {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, 686},
- {{0, 0}, EV_ABS, ABS_MT_TOUCH_MAJOR, 3},
- {{0, 0}, EV_ABS, ABS_MT_PRESSURE, 45},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 101},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_Y, 102}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- // Move on 0, press on 1.
- dev->ConfigureReadMock(mock_kernel_queue_move0press1, 9, 0);
- dev->ReadNow();
- EXPECT_EQ(4u, dev->size());
- ev0 = dev->event(2);
- ev1 = dev->event(3);
-
- // Move
- EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
- EXPECT_EQ(40, ev0->x());
- EXPECT_EQ(51, ev0->y());
- EXPECT_EQ(0, ev0->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev0->force());
- EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
-
- // Press
- EXPECT_EQ(ui::ET_TOUCH_PRESSED, ev1->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
- EXPECT_EQ(101, ev1->x());
- EXPECT_EQ(102, ev1->y());
- EXPECT_EQ(1, ev1->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev1->force());
- EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
-
- // Stationary 0, Moves 1.
- struct input_event mock_kernel_queue_stationary0_move1[] = {
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 40}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- dev->ConfigureReadMock(mock_kernel_queue_stationary0_move1, 2, 0);
- dev->ReadNow();
- EXPECT_EQ(5u, dev->size());
- ev1 = dev->event(4);
-
- EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
- EXPECT_EQ(40, ev1->x());
- EXPECT_EQ(102, ev1->y());
- EXPECT_EQ(1, ev1->touch_id());
-
- EXPECT_FLOAT_EQ(.5f, ev1->force());
- EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
-
- // Move 0, stationary 1.
- struct input_event mock_kernel_queue_move0_stationary1[] = {
- {{0, 0}, EV_ABS, ABS_MT_SLOT, 0}, {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 39},
- {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- dev->ConfigureReadMock(mock_kernel_queue_move0_stationary1, 3, 0);
- dev->ReadNow();
- EXPECT_EQ(6u, dev->size());
- ev0 = dev->event(5);
-
- EXPECT_EQ(ui::ET_TOUCH_MOVED, ev0->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
- EXPECT_EQ(39, ev0->x());
- EXPECT_EQ(51, ev0->y());
- EXPECT_EQ(0, ev0->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev0->force());
- EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
-
- // Release 0, move 1.
- struct input_event mock_kernel_queue_release0_move1[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_ABS, ABS_MT_SLOT, 1},
- {{0, 0}, EV_ABS, ABS_MT_POSITION_X, 38}, {{0, 0}, EV_SYN, SYN_REPORT, 0}
- };
- dev->ConfigureReadMock(mock_kernel_queue_release0_move1, 4, 0);
- dev->ReadNow();
- EXPECT_EQ(8u, dev->size());
- ev0 = dev->event(6);
- ev1 = dev->event(7);
-
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev0->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev0->time_stamp());
- EXPECT_EQ(39, ev0->x());
- EXPECT_EQ(51, ev0->y());
- EXPECT_EQ(0, ev0->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev0->force());
- EXPECT_FLOAT_EQ(0.f, ev0->rotation_angle());
-
- EXPECT_EQ(ui::ET_TOUCH_MOVED, ev1->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
- EXPECT_EQ(38, ev1->x());
- EXPECT_EQ(102, ev1->y());
- EXPECT_EQ(1, ev1->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev1->force());
- EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
-
- // Release 1.
- struct input_event mock_kernel_queue_release1[] = {
- {{0, 0}, EV_ABS, ABS_MT_TRACKING_ID, -1}, {{0, 0}, EV_SYN, SYN_REPORT, 0},
- };
- dev->ConfigureReadMock(mock_kernel_queue_release1, 2, 0);
- dev->ReadNow();
- EXPECT_EQ(9u, dev->size());
- ev1 = dev->event(8);
-
- EXPECT_EQ(ui::ET_TOUCH_RELEASED, ev1->type());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(0), ev1->time_stamp());
- EXPECT_EQ(38, ev1->x());
- EXPECT_EQ(102, ev1->y());
- EXPECT_EQ(1, ev1->touch_id());
- EXPECT_FLOAT_EQ(.5f, ev1->force());
- EXPECT_FLOAT_EQ(0.f, ev1->rotation_angle());
-}
diff --git a/chromium/ui/events/ozone/event_converter_ozone.cc b/chromium/ui/events/ozone/event_converter_ozone.cc
deleted file mode 100644
index 2bb6164e80b..00000000000
--- a/chromium/ui/events/ozone/event_converter_ozone.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/event_converter_ozone.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_ozone.h"
-#include "ui/events/event.h"
-
-namespace {
-
-void DispatchEventHelper(scoped_ptr<ui::Event> key) {
- base::MessagePumpOzone::Current()->Dispatch(key.get());
-}
-
-} // namespace
-
-namespace ui {
-
-EventConverterOzone::EventConverterOzone() {
-}
-
-EventConverterOzone::~EventConverterOzone() {
-}
-
-void EventConverterOzone::DispatchEvent(scoped_ptr<ui::Event> event) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&DispatchEventHelper, base::Passed(&event)));
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/event_converter_ozone.h b/chromium/ui/events/ozone/event_converter_ozone.h
deleted file mode 100644
index 90826c26580..00000000000
--- a/chromium/ui/events/ozone/event_converter_ozone.h
+++ /dev/null
@@ -1,40 +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_EVENTS_OZONE_EVENT_CONVERTER_OZONE_H_
-#define UI_EVENTS_OZONE_EVENT_CONVERTER_OZONE_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_pump_libevent.h"
-#include "ui/events/events_export.h"
-
-namespace ui {
-class Event;
-
-// In ozone, Chrome reads events from file descriptors created from Linux device
-// drivers. The |MessagePumpLibevent::Watcher| parent class provides the
-// functionality to watch a file descriptor for the arrival of new data and
-// notify its subclasses. Device-specific event converters turn bytes read from
-// the file descriptor into |ui::Event| instances. This class provides the
-// functionality needed in common across all converters: dispatching the
-// |ui::Event| to aura.
-class EVENTS_EXPORT EventConverterOzone
- : public base::MessagePumpLibevent::Watcher {
- public:
- EventConverterOzone();
- virtual ~EventConverterOzone();
-
- protected:
- // Subclasses should use this method to post a task that will dispatch
- // |event| from the UI message loop. This method takes ownership of
- // |event|. |event| will be deleted at the end of the posted task.
- virtual void DispatchEvent(scoped_ptr<ui::Event> event);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EventConverterOzone);
-};
-
-} // namespace ui
-
-#endif // UI_EVENTS_OZONE_EVENT_CONVERTER_OZONE_H_
diff --git a/chromium/ui/events/ozone/event_factory_ozone.cc b/chromium/ui/events/ozone/event_factory_ozone.cc
deleted file mode 100644
index b051e21daee..00000000000
--- a/chromium/ui/events/ozone/event_factory_ozone.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/event_factory_ozone.h"
-
-#include "base/command_line.h"
-#include "base/message_loop/message_pump_ozone.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "ui/events/event_switches.h"
-
-namespace ui {
-
-// static
-EventFactoryOzone* EventFactoryOzone::impl_ = NULL;
-
-EventFactoryOzone::EventFactoryOzone() {}
-
-EventFactoryOzone::~EventFactoryOzone() {
- // Always delete watchers before converters to prevent a possible race.
- STLDeleteValues<std::map<int, FDWatcher> >(&watchers_);
- STLDeleteValues<std::map<int, Converter> >(&converters_);
-}
-
-EventFactoryOzone* EventFactoryOzone::GetInstance() {
- CHECK(impl_) << "No EventFactoryOzone implementation set.";
- return impl_;
-}
-
-void EventFactoryOzone::SetInstance(EventFactoryOzone* impl) { impl_ = impl; }
-
-void EventFactoryOzone::StartProcessingEvents() {}
-
-void EventFactoryOzone::AddEventConverter(
- int fd,
- scoped_ptr<EventConverterOzone> converter) {
- CHECK(watchers_.count(fd) == 0 && converters_.count(fd) == 0);
-
- FDWatcher watcher = new base::MessagePumpLibevent::FileDescriptorWatcher();
-
- base::MessagePumpOzone::Current()->WatchFileDescriptor(
- fd,
- true,
- base::MessagePumpLibevent::WATCH_READ,
- watcher,
- converter.get());
-
- converters_[fd] = converter.release();
- watchers_[fd] = watcher;
-}
-
-void EventFactoryOzone::RemoveEventConverter(int fd) {
- // Always delete watchers before converters to prevent a possible race.
- delete watchers_[fd];
- delete converters_[fd];
- watchers_.erase(fd);
- converters_.erase(fd);
-}
-
-} // namespace ui
diff --git a/chromium/ui/events/ozone/event_factory_ozone.h b/chromium/ui/events/ozone/event_factory_ozone.h
deleted file mode 100644
index 389946ae339..00000000000
--- a/chromium/ui/events/ozone/event_factory_ozone.h
+++ /dev/null
@@ -1,62 +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_EVENTS_OZONE_EVENT_FACTORY_OZONE_H_
-#define UI_EVENTS_OZONE_EVENT_FACTORY_OZONE_H_
-
-#include <map>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_pump_libevent.h"
-#include "ui/events/events_export.h"
-#include "ui/events/ozone/event_converter_ozone.h"
-
-namespace ui {
-
-// Creates and dispatches |ui.Event|'s. Ozone assumes that events arrive on file
-// descriptors with one |EventConverterOzone| instance for each descriptor.
-// Ozone presumes that the set of file desctiprtors can vary at runtime so this
-// class supports dynamically adding and removing |EventConverterOzone|
-// instances as necessary.
-class EVENTS_EXPORT EventFactoryOzone {
- public:
- EventFactoryOzone();
- virtual ~EventFactoryOzone();
-
- // Called from RootWindowHostOzone to initialize and start processing events.
- // This should create the initial set of converters, and potentially arrange
- // for more converters to be created as new event sources become available.
- // No events processing should happen until this is called. All processes have
- // an EventFactoryOzone but not all of them should process events. In chrome,
- // events are dispatched in the browser process on the UI thread.
- virtual void StartProcessingEvents();
-
- // Returns the static instance last set using SetInstance().
- static EventFactoryOzone* GetInstance();
-
- // Sets the implementation delegate. Ownership is retained by the caller.
- static void SetInstance(EventFactoryOzone*);
-
- // Add an |EventConverterOzone| instances for the given file descriptor.
- // Transfers ownership of the |EventConverterOzone| to this class.
- void AddEventConverter(int fd, scoped_ptr<EventConverterOzone> converter);
-
- // Remote the |EventConverterOzone|
- void RemoveEventConverter(int fd);
-
- private:
- // |EventConverterOzone| for each file descriptor.
- typedef EventConverterOzone* Converter;
- typedef base::MessagePumpLibevent::FileDescriptorWatcher* FDWatcher;
- std::map<int, Converter> converters_;
- std::map<int, FDWatcher> watchers_;
-
- static EventFactoryOzone* impl_; // not owned
-
- DISALLOW_COPY_AND_ASSIGN(EventFactoryOzone);
-};
-
-} // namespace ui
-
-#endif // UI_EVENTS_OZONE_EVENT_FACTORY_OZONE_H_
diff --git a/chromium/ui/events/ozone/events_ozone.cc b/chromium/ui/events/ozone/events_ozone.cc
index 4655d411923..7d3f627d078 100644
--- a/chromium/ui/events/ozone/events_ozone.cc
+++ b/chromium/ui/events/ozone/events_ozone.cc
@@ -58,9 +58,10 @@ const char* CodeFromNative(const base::NativeEvent& native_event) {
return event->code().c_str();
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
- const ui::Event* e = static_cast<const ui::Event*>(native_event);
- return e->IsMouseEvent();
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+ const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
+ DCHECK(event->IsKeyEvent());
+ return event->platform_keycode();
}
gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
@@ -70,6 +71,13 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
return event->offset();
}
+base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+ return NULL;
+}
+
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+}
+
void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
}
@@ -145,16 +153,6 @@ bool IsTouchpadEvent(const base::NativeEvent& event) {
return false;
}
-bool IsNoopEvent(const base::NativeEvent& event) {
- NOTIMPLEMENTED();
- return false;
-}
-
-base::NativeEvent CreateNoopEvent() {
- NOTIMPLEMENTED();
- return NULL;
-}
-
int GetModifiersFromKeyState() {
NOTIMPLEMENTED();
return 0;
diff --git a/chromium/ui/events/ozone/events_ozone.gyp b/chromium/ui/events/ozone/events_ozone.gyp
new file mode 100644
index 00000000000..e20e75af203
--- /dev/null
+++ b/chromium/ui/events/ozone/events_ozone.gyp
@@ -0,0 +1,97 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [{
+ 'target_name': 'events_ozone',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ ],
+ 'defines': [
+ 'EVENTS_OZONE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'device/device_event.cc',
+ 'device/device_event.h',
+ 'device/device_event_observer.h',
+ 'device/device_manager.cc',
+ 'device/device_manager.h',
+ 'device/device_manager_manual.cc',
+ 'device/device_manager_manual.h',
+ 'device/udev/device_manager_udev.cc',
+ 'device/udev/device_manager_udev.h',
+ 'events_ozone_export.h',
+ ],
+ 'conditions': [
+ ['use_udev==0', {
+ 'sources/': [
+ ['exclude', '_udev\\.(h|cc)$'],
+ ],
+ }],
+ ['use_ozone_evdev==1 and use_udev==1', {
+ 'dependencies': [
+ '<(DEPTH)/device/udev_linux/udev.gyp:udev_linux',
+ ],
+ }],
+ ],
+ }, {
+ 'target_name': 'events_ozone_evdev',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../gfx/gfx.gyp:gfx',
+ '../../ozone/ozone.gyp:ozone_base',
+ '../platform/events_platform.gyp:events_platform',
+ 'events_ozone',
+ ],
+ 'defines': [
+ 'EVENTS_OZONE_EVDEV_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'evdev/libgestures_glue/event_reader_libevdev_cros.cc',
+ 'evdev/libgestures_glue/event_reader_libevdev_cros.h',
+ 'evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc',
+ 'evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h',
+ 'evdev/libgestures_glue/gesture_logging.cc',
+ 'evdev/libgestures_glue/gesture_logging.h',
+ 'evdev/libgestures_glue/gesture_timer_provider.cc',
+ 'evdev/libgestures_glue/gesture_timer_provider.h',
+ 'evdev/event_converter_evdev.cc',
+ 'evdev/event_converter_evdev.h',
+ 'evdev/event_device_info.cc',
+ 'evdev/event_device_info.h',
+ 'evdev/event_factory_evdev.cc',
+ 'evdev/event_factory_evdev.h',
+ 'evdev/event_modifiers_evdev.cc',
+ 'evdev/event_modifiers_evdev.h',
+ 'evdev/events_ozone_evdev_export.h',
+ 'evdev/key_event_converter_evdev.cc',
+ 'evdev/key_event_converter_evdev.h',
+ 'evdev/touch_event_converter_evdev.cc',
+ 'evdev/touch_event_converter_evdev.h',
+ ],
+ 'conditions': [
+ ['use_ozone_evdev==1 and use_evdev_gestures==1', {
+ 'dependencies': [
+ '<(DEPTH)/build/linux/system.gyp:libgestures',
+ '<(DEPTH)/build/linux/system.gyp:libevdev-cros',
+ ],
+ 'defines': [
+ 'USE_EVDEV_GESTURES',
+ ],
+ }, {
+ 'sources/': [
+ ['exclude', '^evdev/libgestures_glue/'],
+ ],
+ }],
+ ['use_ozone_evdev==1', {
+ 'defines': ['USE_OZONE_EVDEV=1'],
+ }],
+ ],
+ }]
+}
diff --git a/chromium/ui/events/ozone/events_ozone_export.h b/chromium/ui/events/ozone/events_ozone_export.h
new file mode 100644
index 00000000000..bda8814eda9
--- /dev/null
+++ b/chromium/ui/events/ozone/events_ozone_export.h
@@ -0,0 +1,29 @@
+// 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_OZONE_EVENTS_OZONE_EXPORT_H_
+#define UI_EVENTS_OZONE_EVENTS_OZONE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(EVENTS_OZONE_IMPLEMENTATION)
+#define EVENTS_OZONE_EXPORT __declspec(dllexport)
+#else
+#define EVENTS_OZONE_EXPORT __declspec(dllimport)
+#endif // defined(EVENTS_OZONE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(EVENTS_OZONE_IMPLEMENTATION)
+#define EVENTS_OZONE_EXPORT __attribute__((visibility("default")))
+#else
+#define EVENTS_OZONE_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define EVENTS_OZONE_EXPORT
+#endif
+
+#endif // UI_EVENTS_OZONE_EVENTS_OZONE_EXPORT_H_
diff --git a/chromium/ui/events/platform/BUILD.gn b/chromium/ui/events/platform/BUILD.gn
new file mode 100644
index 00000000000..3a20219a33c
--- /dev/null
+++ b/chromium/ui/events/platform/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("platform") {
+ sources = [
+ "platform_event_dispatcher.h",
+ "platform_event_observer.h",
+ "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",
+ ]
+
+ defines = [
+ "EVENTS_IMPLEMENTATION",
+ ]
+
+ deps = [
+ "//base"
+ ]
+
+ if (use_x11) {
+ sources -= [
+ "platform_event_source_stub.cc",
+ ]
+ }
+}
diff --git a/chromium/ui/events/platform/events_platform.gyp b/chromium/ui/events/platform/events_platform.gyp
new file mode 100644
index 00000000000..d1b3f6bfe3e
--- /dev/null
+++ b/chromium/ui/events/platform/events_platform.gyp
@@ -0,0 +1,36 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [{
+ 'target_name': 'events_platform',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ ],
+ 'defines': [
+ 'EVENTS_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'platform_event_dispatcher.h',
+ 'platform_event_observer.h',
+ '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',
+ ],
+ 'conditions': [
+ ['use_x11==1', {
+ 'sources!': [
+ 'platform_event_source_stub.cc',
+ ],
+ }],
+ ],
+ }],
+}
diff --git a/chromium/ui/events/platform/platform_event_dispatcher.h b/chromium/ui/events/platform/platform_event_dispatcher.h
new file mode 100644
index 00000000000..bda035d8f0f
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_dispatcher.h
@@ -0,0 +1,43 @@
+// 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_DISPATCHER_H_
+#define UI_EVENTS_PLATFORM_PLATFORM_EVENT_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "ui/events/events_export.h"
+#include "ui/events/platform/platform_event_types.h"
+
+namespace ui {
+
+// See documentation for |PlatformEventDispatcher::DispatchEvent()| for
+// explanation of the meaning of the flags.
+enum PostDispatchAction {
+ POST_DISPATCH_NONE = 0x0,
+ POST_DISPATCH_PERFORM_DEFAULT = 0x1,
+ POST_DISPATCH_STOP_PROPAGATION = 0x2,
+};
+
+// PlatformEventDispatcher receives events from a PlatformEventSource and
+// dispatches them.
+class EVENTS_EXPORT PlatformEventDispatcher {
+ public:
+ // Returns whether this dispatcher wants to dispatch |event|.
+ virtual bool CanDispatchEvent(const PlatformEvent& event) = 0;
+
+ // Dispatches |event|. If this is not the default dispatcher, then the
+ // dispatcher can request that the default dispatcher gets a chance to
+ // dispatch the event by setting POST_DISPATCH_PERFORM_DEFAULT to the return
+ // value. If the dispatcher has processed the event, and no other dispatcher
+ // should be allowed to dispatch the event, then the dispatcher should set
+ // POST_DISPATCH_STOP_PROPAGATION flag on the return value.
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) = 0;
+
+ protected:
+ virtual ~PlatformEventDispatcher() {}
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_PLATFORM_EVENT_DISPATCHER_H_
diff --git a/chromium/ui/events/platform/platform_event_observer.h b/chromium/ui/events/platform/platform_event_observer.h
new file mode 100644
index 00000000000..37aec638ea5
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_observer.h
@@ -0,0 +1,29 @@
+// 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_OBSERVER_H_
+#define UI_EVENTS_PLATFORM_PLATFORM_EVENT_OBSERVER_H_
+
+#include "ui/events/events_export.h"
+#include "ui/events/platform/platform_event_types.h"
+
+namespace ui {
+
+// PlatformEventObserver can be installed on a PlatformEventSource, and it
+// receives all events that are dispatched to the dispatchers.
+class EVENTS_EXPORT PlatformEventObserver {
+ public:
+ // This is called before the dispatcher receives the event.
+ virtual void WillProcessEvent(const PlatformEvent& event) = 0;
+
+ // This is called after the event has been dispatched to the dispatcher(s).
+ virtual void DidProcessEvent(const PlatformEvent& event) = 0;
+
+ protected:
+ virtual ~PlatformEventObserver() {}
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_PLATFORM_EVENT_OBSERVER_H_
diff --git a/chromium/ui/events/platform/platform_event_source.cc b/chromium/ui/events/platform/platform_event_source.cc
new file mode 100644
index 00000000000..9607ab78232
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_source.cc
@@ -0,0 +1,111 @@
+// 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/events/platform/platform_event_source.h"
+
+#include <algorithm>
+
+#include "base/message_loop/message_loop.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_observer.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+
+namespace ui {
+
+// static
+PlatformEventSource* PlatformEventSource::instance_ = NULL;
+
+PlatformEventSource::PlatformEventSource()
+ : overridden_dispatcher_(NULL),
+ overridden_dispatcher_restored_(false) {
+ CHECK(!instance_) << "Only one platform event source can be created.";
+ instance_ = this;
+}
+
+PlatformEventSource::~PlatformEventSource() {
+ CHECK_EQ(this, instance_);
+ instance_ = NULL;
+}
+
+PlatformEventSource* PlatformEventSource::GetInstance() { return instance_; }
+
+void PlatformEventSource::AddPlatformEventDispatcher(
+ PlatformEventDispatcher* dispatcher) {
+ CHECK(dispatcher);
+ dispatchers_.AddObserver(dispatcher);
+ OnDispatcherListChanged();
+}
+
+void PlatformEventSource::RemovePlatformEventDispatcher(
+ PlatformEventDispatcher* dispatcher) {
+ dispatchers_.RemoveObserver(dispatcher);
+ OnDispatcherListChanged();
+}
+
+scoped_ptr<ScopedEventDispatcher> PlatformEventSource::OverrideDispatcher(
+ PlatformEventDispatcher* dispatcher) {
+ CHECK(dispatcher);
+ overridden_dispatcher_restored_ = false;
+ return make_scoped_ptr(
+ new ScopedEventDispatcher(&overridden_dispatcher_, dispatcher));
+}
+
+void PlatformEventSource::AddPlatformEventObserver(
+ PlatformEventObserver* observer) {
+ CHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void PlatformEventSource::RemovePlatformEventObserver(
+ PlatformEventObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+uint32_t PlatformEventSource::DispatchEvent(PlatformEvent platform_event) {
+ uint32_t action = POST_DISPATCH_PERFORM_DEFAULT;
+
+ FOR_EACH_OBSERVER(PlatformEventObserver, observers_,
+ WillProcessEvent(platform_event));
+ // Give the overridden dispatcher a chance to dispatch the event first.
+ if (overridden_dispatcher_)
+ action = overridden_dispatcher_->DispatchEvent(platform_event);
+
+ if ((action & POST_DISPATCH_PERFORM_DEFAULT) &&
+ dispatchers_.might_have_observers()) {
+ ObserverList<PlatformEventDispatcher>::Iterator iter(dispatchers_);
+ while (PlatformEventDispatcher* dispatcher = iter.GetNext()) {
+ if (dispatcher->CanDispatchEvent(platform_event))
+ action = dispatcher->DispatchEvent(platform_event);
+ if (action & POST_DISPATCH_STOP_PROPAGATION)
+ break;
+ }
+ }
+ FOR_EACH_OBSERVER(PlatformEventObserver, observers_,
+ DidProcessEvent(platform_event));
+
+ // If an overridden dispatcher has been destroyed, then the platform
+ // event-source should halt dispatching the current stream of events, and wait
+ // until the next message-loop iteration for dispatching events. This lets any
+ // nested message-loop to unwind correctly and any new dispatchers to receive
+ // the correct sequence of events.
+ if (overridden_dispatcher_restored_)
+ StopCurrentEventStream();
+
+ overridden_dispatcher_restored_ = false;
+
+ return action;
+}
+
+void PlatformEventSource::StopCurrentEventStream() {
+}
+
+void PlatformEventSource::OnDispatcherListChanged() {
+}
+
+void PlatformEventSource::OnOverriddenDispatcherRestored() {
+ CHECK(overridden_dispatcher_);
+ overridden_dispatcher_restored_ = true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/platform_event_source.h b/chromium/ui/events/platform/platform_event_source.h
new file mode 100644
index 00000000000..87b553197a3
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_source.h
@@ -0,0 +1,102 @@
+// 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_SOURCE_H_
+#define UI_EVENTS_PLATFORM_PLATFORM_EVENT_SOURCE_H_
+
+#include <map>
+#include <vector>
+
+#include "base/auto_reset.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "ui/events/events_export.h"
+#include "ui/events/platform/platform_event_types.h"
+
+namespace ui {
+
+class Event;
+class PlatformEventDispatcher;
+class PlatformEventObserver;
+class ScopedEventDispatcher;
+
+// PlatformEventSource receives events from a source and dispatches the events
+// to the appropriate dispatchers.
+class EVENTS_EXPORT PlatformEventSource {
+ public:
+ virtual ~PlatformEventSource();
+
+ static PlatformEventSource* GetInstance();
+
+ // Adds a dispatcher to the dispatcher list. If a dispatcher is added during
+ // dispatching an event, then the newly added dispatcher also receives that
+ // event.
+ void AddPlatformEventDispatcher(PlatformEventDispatcher* dispatcher);
+
+ // Removes a dispatcher from the dispatcher list. Dispatchers can safely be
+ // removed from the dispatcher list during an event is being dispatched,
+ // without affecting the dispatch of the event to other existing dispatchers.
+ void RemovePlatformEventDispatcher(PlatformEventDispatcher* dispatcher);
+
+ // Installs a PlatformEventDispatcher that receives all the events. The
+ // dispatcher can process the event, or request that the default dispatchers
+ // be invoked by setting |POST_DISPATCH_PERFORM_DEFAULT| flag from the
+ // |DispatchEvent()| override.
+ // The returned |ScopedEventDispatcher| object is a handler for the overridden
+ // dispatcher. When this handler is destroyed, it removes the overridden
+ // dispatcher, and restores the previous override-dispatcher (or NULL if there
+ // wasn't any).
+ scoped_ptr<ScopedEventDispatcher> OverrideDispatcher(
+ PlatformEventDispatcher* dispatcher);
+
+ void AddPlatformEventObserver(PlatformEventObserver* observer);
+ void RemovePlatformEventObserver(PlatformEventObserver* observer);
+
+ static scoped_ptr<PlatformEventSource> CreateDefault();
+
+ protected:
+ PlatformEventSource();
+
+ // Dispatches |platform_event| to the dispatchers. If there is an override
+ // dispatcher installed using |OverrideDispatcher()|, then that dispatcher
+ // receives the event first. |POST_DISPATCH_QUIT_LOOP| flag is set in the
+ // returned value if the event-source should stop dispatching events at the
+ // current message-loop iteration.
+ virtual uint32_t DispatchEvent(PlatformEvent platform_event);
+
+ private:
+ friend class ScopedEventDispatcher;
+ static PlatformEventSource* instance_;
+
+ // Called to indicate that the source should stop dispatching the current
+ // stream of events and wait until the next iteration of the message-loop to
+ // dispatch the rest of the events.
+ virtual void StopCurrentEventStream();
+
+ // This is invoked when the list of dispatchers changes (i.e. a new dispatcher
+ // is added, or a dispatcher is removed).
+ virtual void OnDispatcherListChanged();
+
+ void OnOverriddenDispatcherRestored();
+
+ // Use an ObserverList<> instead of an std::vector<> to store the list of
+ // dispatchers, so that adding/removing dispatchers during an event dispatch
+ // is well-defined.
+ typedef ObserverList<PlatformEventDispatcher> PlatformEventDispatcherList;
+ PlatformEventDispatcherList dispatchers_;
+ PlatformEventDispatcher* overridden_dispatcher_;
+
+ // Used to keep track of whether the current override-dispatcher has been
+ // reset and a previous override-dispatcher has been restored.
+ bool overridden_dispatcher_restored_;
+
+ ObserverList<PlatformEventObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformEventSource);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_PLATFORM_EVENT_SOURCE_H_
diff --git a/chromium/ui/events/platform/platform_event_source_stub.cc b/chromium/ui/events/platform/platform_event_source_stub.cc
new file mode 100644
index 00000000000..57e2a61c3dc
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_source_stub.cc
@@ -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.
+
+#include "ui/events/platform/platform_event_source.h"
+
+namespace ui {
+
+scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
+ return scoped_ptr<PlatformEventSource>();
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/platform_event_source_unittest.cc b/chromium/ui/events/platform/platform_event_source_unittest.cc
new file mode 100644
index 00000000000..cdbd0c4b35c
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_source_unittest.cc
@@ -0,0 +1,787 @@
+// 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/events/platform/platform_event_source.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_observer.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+
+namespace ui {
+
+namespace {
+
+scoped_ptr<PlatformEvent> CreatePlatformEvent() {
+ scoped_ptr<PlatformEvent> event(new PlatformEvent());
+ memset(event.get(), 0, sizeof(PlatformEvent));
+ return event.Pass();
+}
+
+template <typename T>
+void DestroyScopedPtr(scoped_ptr<T> object) {}
+
+void RemoveDispatcher(PlatformEventDispatcher* dispatcher) {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(dispatcher);
+}
+
+void RemoveDispatchers(PlatformEventDispatcher* first,
+ PlatformEventDispatcher* second) {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(first);
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(second);
+}
+
+void AddDispatcher(PlatformEventDispatcher* dispatcher) {
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(dispatcher);
+}
+
+} // namespace
+
+class TestPlatformEventSource : public PlatformEventSource {
+ public:
+ TestPlatformEventSource()
+ : stop_stream_(false) {
+ }
+ virtual ~TestPlatformEventSource() {}
+
+ uint32_t Dispatch(const PlatformEvent& event) { return DispatchEvent(event); }
+
+ // Dispatches the stream of events, and returns the number of events that are
+ // dispatched before it is requested to stop.
+ size_t DispatchEventStream(const ScopedVector<PlatformEvent>& events) {
+ stop_stream_ = false;
+ for (size_t count = 0; count < events.size(); ++count) {
+ DispatchEvent(*events[count]);
+ if (stop_stream_)
+ return count + 1;
+ }
+ return events.size();
+ }
+
+ // PlatformEventSource:
+ virtual void StopCurrentEventStream() OVERRIDE {
+ stop_stream_ = true;
+ }
+
+ private:
+ bool stop_stream_;
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
+};
+
+class TestPlatformEventDispatcher : public PlatformEventDispatcher {
+ public:
+ TestPlatformEventDispatcher(int id, std::vector<int>* list)
+ : id_(id),
+ list_(list),
+ post_dispatch_action_(POST_DISPATCH_NONE),
+ stop_stream_(false) {
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ }
+ virtual ~TestPlatformEventDispatcher() {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ }
+
+ void set_post_dispatch_action(uint32_t action) {
+ post_dispatch_action_ = action;
+ }
+
+ protected:
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE {
+ return true;
+ }
+
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE {
+ list_->push_back(id_);
+ return post_dispatch_action_;
+ }
+
+ private:
+ int id_;
+ std::vector<int>* list_;
+ uint32_t post_dispatch_action_;
+ bool stop_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventDispatcher);
+};
+
+class TestPlatformEventObserver : public PlatformEventObserver {
+ public:
+ TestPlatformEventObserver(int id, std::vector<int>* list)
+ : id_(id), list_(list) {
+ PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+ }
+ virtual ~TestPlatformEventObserver() {
+ PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
+ }
+
+ protected:
+ // PlatformEventObserver:
+ virtual void WillProcessEvent(const PlatformEvent& event) OVERRIDE {
+ list_->push_back(id_);
+ }
+
+ virtual void DidProcessEvent(const PlatformEvent& event) OVERRIDE {}
+
+ private:
+ int id_;
+ std::vector<int>* list_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventObserver);
+};
+
+class PlatformEventTest : public testing::Test {
+ public:
+ PlatformEventTest() {}
+ virtual ~PlatformEventTest() {}
+
+ TestPlatformEventSource* source() { return source_.get(); }
+
+ protected:
+ // testing::Test:
+ virtual void SetUp() OVERRIDE {
+ source_.reset(new TestPlatformEventSource());
+ }
+
+ private:
+ scoped_ptr<TestPlatformEventSource> source_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformEventTest);
+};
+
+// Tests that a dispatcher receives an event.
+TEST_F(PlatformEventTest, DispatcherBasic) {
+ std::vector<int> list_dispatcher;
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ EXPECT_EQ(0u, list_dispatcher.size());
+ {
+ TestPlatformEventDispatcher dispatcher(1, &list_dispatcher);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(1u, list_dispatcher.size());
+ EXPECT_EQ(1, list_dispatcher[0]);
+ }
+
+ list_dispatcher.clear();
+ event = CreatePlatformEvent();
+ source()->Dispatch(*event);
+ EXPECT_EQ(0u, list_dispatcher.size());
+}
+
+// Tests that dispatchers receive events in the correct order.
+TEST_F(PlatformEventTest, DispatcherOrder) {
+ std::vector<int> list_dispatcher;
+ int sequence[] = {21, 3, 6, 45};
+ ScopedVector<TestPlatformEventDispatcher> dispatchers;
+ for (size_t i = 0; i < arraysize(sequence); ++i) {
+ dispatchers.push_back(
+ new TestPlatformEventDispatcher(sequence[i], &list_dispatcher));
+ }
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(arraysize(sequence), list_dispatcher.size());
+ EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)),
+ list_dispatcher);
+}
+
+// Tests that if a dispatcher consumes the event, the subsequent dispatchers do
+// not receive the event.
+TEST_F(PlatformEventTest, DispatcherConsumesEventToStopDispatch) {
+ std::vector<int> list_dispatcher;
+ TestPlatformEventDispatcher first(12, &list_dispatcher);
+ TestPlatformEventDispatcher second(23, &list_dispatcher);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list_dispatcher.size());
+ EXPECT_EQ(12, list_dispatcher[0]);
+ EXPECT_EQ(23, list_dispatcher[1]);
+ list_dispatcher.clear();
+
+ first.set_post_dispatch_action(POST_DISPATCH_STOP_PROPAGATION);
+ event = CreatePlatformEvent();
+ source()->Dispatch(*event);
+ ASSERT_EQ(1u, list_dispatcher.size());
+ EXPECT_EQ(12, list_dispatcher[0]);
+}
+
+// Tests that observers receive events.
+TEST_F(PlatformEventTest, ObserverBasic) {
+ std::vector<int> list_observer;
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ EXPECT_EQ(0u, list_observer.size());
+ {
+ TestPlatformEventObserver observer(31, &list_observer);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(1u, list_observer.size());
+ EXPECT_EQ(31, list_observer[0]);
+ }
+
+ list_observer.clear();
+ event = CreatePlatformEvent();
+ source()->Dispatch(*event);
+ EXPECT_EQ(0u, list_observer.size());
+}
+
+// Tests that observers receive events in the correct order.
+TEST_F(PlatformEventTest, ObserverOrder) {
+ std::vector<int> list_observer;
+ const int sequence[] = {21, 3, 6, 45};
+ ScopedVector<TestPlatformEventObserver> observers;
+ for (size_t i = 0; i < arraysize(sequence); ++i) {
+ observers.push_back(
+ new TestPlatformEventObserver(sequence[i], &list_observer));
+ }
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(arraysize(sequence), list_observer.size());
+ EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)),
+ list_observer);
+}
+
+// Tests that observers and dispatchers receive events in the correct order.
+TEST_F(PlatformEventTest, DispatcherAndObserverOrder) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first_d(12, &list);
+ TestPlatformEventObserver first_o(10, &list);
+ TestPlatformEventDispatcher second_d(23, &list);
+ TestPlatformEventObserver second_o(20, &list);
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ const int expected[] = {10, 20, 12, 23};
+ EXPECT_EQ(std::vector<int>(expected, expected + arraysize(expected)), list);
+}
+
+// Tests that an overridden dispatcher receives events before the default
+// dispatchers.
+TEST_F(PlatformEventTest, OverriddenDispatcherBasic) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher dispatcher(10, &list);
+ TestPlatformEventObserver observer(15, &list);
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(10, list[1]);
+ list.clear();
+
+ TestPlatformEventDispatcher overriding_dispatcher(20, &list);
+ source()->RemovePlatformEventDispatcher(&overriding_dispatcher);
+ scoped_ptr<ScopedEventDispatcher> handle =
+ source()->OverrideDispatcher(&overriding_dispatcher);
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(20, list[1]);
+}
+
+// Tests that an overridden dispatcher can request that the default dispatchers
+// can dispatch the events.
+TEST_F(PlatformEventTest, OverriddenDispatcherInvokeDefaultDispatcher) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher dispatcher(10, &list);
+ TestPlatformEventObserver observer(15, &list);
+ TestPlatformEventDispatcher overriding_dispatcher(20, &list);
+ source()->RemovePlatformEventDispatcher(&overriding_dispatcher);
+ scoped_ptr<ScopedEventDispatcher> handle =
+ source()->OverrideDispatcher(&overriding_dispatcher);
+ overriding_dispatcher.set_post_dispatch_action(POST_DISPATCH_PERFORM_DEFAULT);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // First the observer, then the overriding dispatcher, then the default
+ // dispatcher.
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(20, list[1]);
+ EXPECT_EQ(10, list[2]);
+ list.clear();
+
+ // Install a second overriding dispatcher.
+ TestPlatformEventDispatcher second_overriding(50, &list);
+ source()->RemovePlatformEventDispatcher(&second_overriding);
+ scoped_ptr<ScopedEventDispatcher> second_override_handle =
+ source()->OverrideDispatcher(&second_overriding);
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(50, list[1]);
+ list.clear();
+
+ second_overriding.set_post_dispatch_action(POST_DISPATCH_PERFORM_DEFAULT);
+ source()->Dispatch(*event);
+ // First the observer, then the second overriding dispatcher, then the default
+ // dispatcher.
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(50, list[1]);
+ EXPECT_EQ(10, list[2]);
+}
+
+// Runs a callback during an event dispatch.
+class RunCallbackDuringDispatch : public TestPlatformEventDispatcher {
+ public:
+ RunCallbackDuringDispatch(int id, std::vector<int>* list)
+ : TestPlatformEventDispatcher(id, list) {}
+ virtual ~RunCallbackDuringDispatch() {}
+
+ void set_callback(const base::Closure& callback) {
+ callback_ = callback;
+ }
+
+ protected:
+ // PlatformEventDispatcher:
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE {
+ if (!callback_.is_null())
+ callback_.Run();
+ return TestPlatformEventDispatcher::DispatchEvent(event);
+ }
+
+ private:
+ base::Closure callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(RunCallbackDuringDispatch);
+};
+
+// Test that if a dispatcher removes another dispatcher that is later in the
+// dispatcher list during dispatching an event, then event dispatching still
+// continues correctly.
+TEST_F(PlatformEventTest, DispatcherRemovesNextDispatcherDuringDispatch) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ RunCallbackDuringDispatch second(15, &list);
+ TestPlatformEventDispatcher third(20, &list);
+ TestPlatformEventDispatcher fourth(30, &list);
+
+ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&third)));
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // |second| removes |third| from the dispatcher list during dispatch. So the
+ // event should only reach |first|, |second|, and |fourth|.
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+ EXPECT_EQ(30, list[2]);
+}
+
+// Tests that if a dispatcher removes itself from the dispatcher list during
+// dispatching an event, then event dispatching continues correctly.
+TEST_F(PlatformEventTest, DispatcherRemovesSelfDuringDispatch) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ RunCallbackDuringDispatch second(15, &list);
+ TestPlatformEventDispatcher third(20, &list);
+
+ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second)));
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // |second| removes itself from the dispatcher list during dispatch. So the
+ // event should reach all three dispatchers in the list.
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+ EXPECT_EQ(20, list[2]);
+}
+
+// Tests that if a dispatcher removes itself from the dispatcher list during
+// dispatching an event, and this dispatcher is last in the dispatcher-list,
+// then event dispatching ends correctly.
+TEST_F(PlatformEventTest, DispatcherRemovesSelfDuringDispatchLast) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ RunCallbackDuringDispatch second(15, &list);
+
+ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second)));
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // |second| removes itself during dispatch. So both dispatchers will have
+ // received the event.
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+}
+
+// Tests that if a dispatcher removes a single dispatcher that comes before it
+// in the dispatcher list, then dispatch continues correctly.
+TEST_F(PlatformEventTest, DispatcherRemovesPrevDispatcherDuringDispatch) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ RunCallbackDuringDispatch second(15, &list);
+ TestPlatformEventDispatcher third(20, &list);
+
+ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&first)));
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // |second| removes |first| from the dispatcher list during dispatch. The
+ // event should reach all three dispatchers.
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+ EXPECT_EQ(20, list[2]);
+}
+
+// Tests that if a dispatcher removes multiple dispatchers that comes before it
+// in the dispatcher list, then dispatch continues correctly.
+TEST_F(PlatformEventTest, DispatcherRemovesPrevDispatchersDuringDispatch) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ TestPlatformEventDispatcher second(12, &list);
+ RunCallbackDuringDispatch third(15, &list);
+ TestPlatformEventDispatcher fourth(20, &list);
+
+ third.set_callback(base::Bind(&RemoveDispatchers,
+ base::Unretained(&first),
+ base::Unretained(&second)));
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ // |third| removes |first| and |second| from the dispatcher list during
+ // dispatch. The event should reach all three dispatchers.
+ ASSERT_EQ(4u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(12, list[1]);
+ EXPECT_EQ(15, list[2]);
+ EXPECT_EQ(20, list[3]);
+}
+
+// Tests that adding a dispatcher during dispatching an event receives that
+// event.
+TEST_F(PlatformEventTest, DispatcherAddedDuringDispatchReceivesEvent) {
+ std::vector<int> list;
+ TestPlatformEventDispatcher first(10, &list);
+ RunCallbackDuringDispatch second(15, &list);
+ TestPlatformEventDispatcher third(20, &list);
+ TestPlatformEventDispatcher fourth(30, &list);
+ RemoveDispatchers(&third, &fourth);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+
+ second.set_callback(base::Bind(&AddDispatcher, base::Unretained(&third)));
+ list.clear();
+ source()->Dispatch(*event);
+ ASSERT_EQ(3u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+ EXPECT_EQ(20, list[2]);
+
+ second.set_callback(base::Bind(&AddDispatcher, base::Unretained(&fourth)));
+ list.clear();
+ source()->Dispatch(*event);
+ ASSERT_EQ(4u, list.size());
+ EXPECT_EQ(10, list[0]);
+ EXPECT_EQ(15, list[1]);
+ EXPECT_EQ(20, list[2]);
+ EXPECT_EQ(30, list[3]);
+}
+
+// Provides mechanism for running tests from inside an active message-loop.
+class PlatformEventTestWithMessageLoop : public PlatformEventTest {
+ public:
+ PlatformEventTestWithMessageLoop() {}
+ virtual ~PlatformEventTestWithMessageLoop() {}
+
+ void Run() {
+ message_loop_.PostTask(
+ FROM_HERE,
+ base::Bind(&PlatformEventTestWithMessageLoop::RunTest,
+ base::Unretained(this)));
+ message_loop_.Run();
+ }
+
+ protected:
+ void RunTest() {
+ RunTestImpl();
+ message_loop_.Quit();
+ }
+
+ virtual void RunTestImpl() = 0;
+
+ private:
+ base::MessageLoopForUI message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformEventTestWithMessageLoop);
+};
+
+#define RUN_TEST_IN_MESSAGE_LOOP(name) \
+ TEST_F(name, Run) { Run(); }
+
+// Tests that a ScopedEventDispatcher restores the previous dispatcher when
+// destroyed.
+class ScopedDispatcherRestoresAfterDestroy
+ : public PlatformEventTestWithMessageLoop {
+ public:
+ // PlatformEventTestWithMessageLoop:
+ virtual void RunTestImpl() OVERRIDE {
+ std::vector<int> list;
+ TestPlatformEventDispatcher dispatcher(10, &list);
+ TestPlatformEventObserver observer(15, &list);
+
+ TestPlatformEventDispatcher first_overriding(20, &list);
+ source()->RemovePlatformEventDispatcher(&first_overriding);
+ scoped_ptr<ScopedEventDispatcher> first_override_handle =
+ source()->OverrideDispatcher(&first_overriding);
+
+ // Install a second overriding dispatcher.
+ TestPlatformEventDispatcher second_overriding(50, &list);
+ source()->RemovePlatformEventDispatcher(&second_overriding);
+ scoped_ptr<ScopedEventDispatcher> second_override_handle =
+ source()->OverrideDispatcher(&second_overriding);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(50, list[1]);
+ list.clear();
+
+ second_override_handle.reset();
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(20, list[1]);
+ }
+};
+
+RUN_TEST_IN_MESSAGE_LOOP(ScopedDispatcherRestoresAfterDestroy)
+
+// This dispatcher destroys the handle to the ScopedEventDispatcher when
+// dispatching an event.
+class DestroyScopedHandleDispatcher : public TestPlatformEventDispatcher {
+ public:
+ DestroyScopedHandleDispatcher(int id, std::vector<int>* list)
+ : TestPlatformEventDispatcher(id, list) {}
+ virtual ~DestroyScopedHandleDispatcher() {}
+
+ void SetScopedHandle(scoped_ptr<ScopedEventDispatcher> handler) {
+ handler_ = handler.Pass();
+ }
+
+ void set_callback(const base::Closure& callback) {
+ callback_ = callback;
+ }
+
+ private:
+ // PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE {
+ return true;
+ }
+
+ virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE {
+ handler_.reset();
+ uint32_t action = TestPlatformEventDispatcher::DispatchEvent(event);
+ if (!callback_.is_null()) {
+ callback_.Run();
+ callback_ = base::Closure();
+ }
+ return action;
+ }
+
+ scoped_ptr<ScopedEventDispatcher> handler_;
+ base::Closure callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DestroyScopedHandleDispatcher);
+};
+
+// Tests that resetting an overridden dispatcher causes the nested message-loop
+// iteration to stop and the rest of the events are dispatched in the next
+// iteration.
+class DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration
+ : public PlatformEventTestWithMessageLoop {
+ public:
+ void NestedTask(std::vector<int>* list,
+ TestPlatformEventDispatcher* dispatcher) {
+ ScopedVector<PlatformEvent> events;
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ events.push_back(event.release());
+ event = CreatePlatformEvent();
+ events.push_back(event.release());
+
+ // Attempt to dispatch a couple of events. Dispatching the first event will
+ // have terminated the ScopedEventDispatcher object, which will terminate
+ // the current iteration of the message-loop.
+ size_t count = source()->DispatchEventStream(events);
+ EXPECT_EQ(1u, count);
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(20, (*list)[1]);
+ list->clear();
+
+ ASSERT_LT(count, events.size());
+ events.erase(events.begin(), events.begin() + count);
+
+ count = source()->DispatchEventStream(events);
+ EXPECT_EQ(1u, count);
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(10, (*list)[1]);
+ list->clear();
+
+ // Terminate the message-loop.
+ base::MessageLoopForUI::current()->QuitNow();
+ }
+
+ // PlatformEventTestWithMessageLoop:
+ virtual void RunTestImpl() OVERRIDE {
+ std::vector<int> list;
+ TestPlatformEventDispatcher dispatcher(10, &list);
+ TestPlatformEventObserver observer(15, &list);
+
+ DestroyScopedHandleDispatcher overriding(20, &list);
+ source()->RemovePlatformEventDispatcher(&overriding);
+ scoped_ptr<ScopedEventDispatcher> override_handle =
+ source()->OverrideDispatcher(&overriding);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(20, list[1]);
+ list.clear();
+
+ overriding.SetScopedHandle(override_handle.Pass());
+ base::RunLoop run_loop;
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
+ loop->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration::
+ NestedTask,
+ base::Unretained(this),
+ base::Unretained(&list),
+ base::Unretained(&overriding)));
+ run_loop.Run();
+
+ // Dispatching the event should now reach the default dispatcher.
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(10, list[1]);
+ }
+};
+
+RUN_TEST_IN_MESSAGE_LOOP(
+ DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration)
+
+// Tests that resetting an overridden dispatcher, and installing another
+// overridden dispatcher before the nested message-loop completely unwinds
+// function correctly.
+class ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration
+ : public PlatformEventTestWithMessageLoop {
+ public:
+ void NestedTask(scoped_ptr<ScopedEventDispatcher> dispatch_handle,
+ std::vector<int>* list) {
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(20, (*list)[1]);
+ list->clear();
+
+ // Reset the override dispatcher. This should restore the default
+ // dispatcher.
+ dispatch_handle.reset();
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(10, (*list)[1]);
+ list->clear();
+
+ // Install another override-dispatcher.
+ DestroyScopedHandleDispatcher second_overriding(70, list);
+ source()->RemovePlatformEventDispatcher(&second_overriding);
+ scoped_ptr<ScopedEventDispatcher> second_override_handle =
+ source()->OverrideDispatcher(&second_overriding);
+
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(70, (*list)[1]);
+ list->clear();
+
+ second_overriding.SetScopedHandle(second_override_handle.Pass());
+ second_overriding.set_post_dispatch_action(POST_DISPATCH_NONE);
+ base::RunLoop run_loop;
+ second_overriding.set_callback(run_loop.QuitClosure());
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
+ loop->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&TestPlatformEventSource::Dispatch),
+ base::Unretained(source()),
+ *event));
+ run_loop.Run();
+ ASSERT_EQ(2u, list->size());
+ EXPECT_EQ(15, (*list)[0]);
+ EXPECT_EQ(70, (*list)[1]);
+ list->clear();
+
+ // Terminate the message-loop.
+ base::MessageLoopForUI::current()->QuitNow();
+ }
+
+ // PlatformEventTestWithMessageLoop:
+ virtual void RunTestImpl() OVERRIDE {
+ std::vector<int> list;
+ TestPlatformEventDispatcher dispatcher(10, &list);
+ TestPlatformEventObserver observer(15, &list);
+
+ TestPlatformEventDispatcher overriding(20, &list);
+ source()->RemovePlatformEventDispatcher(&overriding);
+ scoped_ptr<ScopedEventDispatcher> override_handle =
+ source()->OverrideDispatcher(&overriding);
+
+ scoped_ptr<PlatformEvent> event(CreatePlatformEvent());
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(20, list[1]);
+ list.clear();
+
+ // 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::RunLoop run_loop;
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
+ loop->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration::
+ NestedTask,
+ base::Unretained(this),
+ base::Passed(&override_handle),
+ base::Unretained(&list)));
+ run_loop.Run();
+
+ // Dispatching the event should now reach the default dispatcher.
+ source()->Dispatch(*event);
+ ASSERT_EQ(2u, list.size());
+ EXPECT_EQ(15, list[0]);
+ EXPECT_EQ(10, list[1]);
+ }
+};
+
+RUN_TEST_IN_MESSAGE_LOOP(
+ ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration)
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/platform_event_types.h b/chromium/ui/events/platform/platform_event_types.h
new file mode 100644
index 00000000000..dedb38ff063
--- /dev/null
+++ b/chromium/ui/events/platform/platform_event_types.h
@@ -0,0 +1,14 @@
+// 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/scoped_event_dispatcher.cc b/chromium/ui/events/platform/scoped_event_dispatcher.cc
new file mode 100644
index 00000000000..b0941ab8513
--- /dev/null
+++ b/chromium/ui/events/platform/scoped_event_dispatcher.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/events/platform/scoped_event_dispatcher.h"
+
+#include "ui/events/platform/platform_event_source.h"
+
+namespace ui {
+
+ScopedEventDispatcher::ScopedEventDispatcher(
+ PlatformEventDispatcher** scoped_dispatcher,
+ PlatformEventDispatcher* new_dispatcher)
+ : original_(*scoped_dispatcher),
+ restore_(scoped_dispatcher, new_dispatcher) {}
+
+ScopedEventDispatcher::~ScopedEventDispatcher() {
+ PlatformEventSource::GetInstance()->OnOverriddenDispatcherRestored();
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/scoped_event_dispatcher.h b/chromium/ui/events/platform/scoped_event_dispatcher.h
new file mode 100644
index 00000000000..a2f52945d91
--- /dev/null
+++ b/chromium/ui/events/platform/scoped_event_dispatcher.h
@@ -0,0 +1,40 @@
+// 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_SCOPED_EVENT_DISPATCHER_H_
+#define UI_EVENTS_PLATFORM_SCOPED_EVENT_DISPATCHER_H_
+
+#include "base/auto_reset.h"
+#include "base/basictypes.h"
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+class PlatformEventDispatcher;
+
+// A temporary PlatformEventDispatcher can be installed on a
+// PlatformEventSource that overrides all installed event dispatchers, and
+// always gets a chance to dispatch the event first. The PlatformEventSource
+// returns a ScopedEventDispatcher object in such cases. This
+// ScopedEventDispatcher object can be used to dispatch the event to any
+// previous overridden dispatcher. When this object is destroyed, it removes the
+// override-dispatcher, and restores the previous override-dispatcher.
+class EVENTS_EXPORT ScopedEventDispatcher {
+ public:
+ ScopedEventDispatcher(PlatformEventDispatcher** scoped_dispatcher,
+ PlatformEventDispatcher* new_dispatcher);
+ ~ScopedEventDispatcher();
+
+ operator PlatformEventDispatcher*() const { return original_; }
+
+ private:
+ PlatformEventDispatcher* original_;
+ base::AutoReset<PlatformEventDispatcher*> restore_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedEventDispatcher);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_SCOPED_EVENT_DISPATCHER_H_
diff --git a/chromium/ui/events/platform/x11/BUILD.gn b/chromium/ui/events/platform/x11/BUILD.gn
new file mode 100644
index 00000000000..6c8bbe4b1f2
--- /dev/null
+++ b/chromium/ui/events/platform/x11/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+component("x11") {
+ output_name = "x11_events_platform"
+
+ sources = [
+ "x11_event_source.cc",
+ "x11_event_source.h",
+ "x11_event_source_glib.cc",
+ "x11_event_source_libevent.cc",
+ ]
+
+ defines = [
+ "EVENTS_IMPLEMENTATION",
+ ]
+
+ configs += [
+ "//build/config/linux:x11",
+ ]
+
+ deps = [
+ "//ui/events",
+ "//ui/events/platform",
+ "//ui/gfx/x",
+ ]
+
+ if (is_linux) {
+ sources -= [
+ "x11_event_source_libevent.cc",
+ ]
+
+ configs += [
+ "//build/config/linux:glib",
+ ]
+ } else {
+ 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
new file mode 100644
index 00000000000..25e74098fac
--- /dev/null
+++ b/chromium/ui/events/platform/x11/x11_event_source.cc
@@ -0,0 +1,149 @@
+// 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/events/platform/x11/x11_event_source.h"
+
+#include <X11/extensions/XInput2.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#include "base/logging.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace ui {
+
+namespace {
+
+int g_xinput_opcode = -1;
+
+bool InitializeXInput2(XDisplay* display) {
+ if (!display)
+ return false;
+
+ int event, err;
+
+ int xiopcode;
+ if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
+ DVLOG(1) << "X Input extension not available.";
+ return false;
+ }
+ g_xinput_opcode = xiopcode;
+
+#if defined(USE_XI2_MT)
+ // USE_XI2_MT also defines the required XI2 minor minimum version.
+ int major = 2, minor = USE_XI2_MT;
+#else
+ int major = 2, minor = 0;
+#endif
+ if (XIQueryVersion(display, &major, &minor) == BadRequest) {
+ DVLOG(1) << "XInput2 not supported in the server.";
+ return false;
+ }
+#if defined(USE_XI2_MT)
+ if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
+ DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
+ << "But 2." << USE_XI2_MT << " is required.";
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+bool InitializeXkb(XDisplay* display) {
+ if (!display)
+ return false;
+
+ int opcode, event, error;
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
+ if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
+ DVLOG(1) << "Xkb extension not available.";
+ return false;
+ }
+
+ // Ask the server not to send KeyRelease event when the user holds down a key.
+ // crbug.com/138092
+ Bool supported_return;
+ if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
+ DVLOG(1) << "XKB not supported in the server.";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+X11EventSource::X11EventSource(XDisplay* display)
+ : display_(display),
+ continue_stream_(true) {
+ CHECK(display_);
+ InitializeXInput2(display_);
+ InitializeXkb(display_);
+}
+
+X11EventSource::~X11EventSource() {
+}
+
+// static
+X11EventSource* X11EventSource::GetInstance() {
+ return static_cast<X11EventSource*>(PlatformEventSource::GetInstance());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// X11EventSource, public
+
+void X11EventSource::DispatchXEvents() {
+ DCHECK(display_);
+ // Handle all pending events.
+ // It may be useful to eventually align this event dispatch with vsync, but
+ // not yet.
+ continue_stream_ = true;
+ while (XPending(display_) && continue_stream_) {
+ XEvent xevent;
+ XNextEvent(display_, &xevent);
+ DispatchEvent(&xevent);
+ }
+}
+
+void X11EventSource::BlockUntilWindowMapped(XID window) {
+ XEvent event;
+ do {
+ // Block until there's a message of |event_mask| type on |w|. Then remove
+ // it from the queue and stuff it in |event|.
+ XWindowEvent(display_, window, StructureNotifyMask, &event);
+ DispatchEvent(&event);
+ } while (event.type != MapNotify);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// X11EventSource, private
+
+uint32_t X11EventSource::DispatchEvent(XEvent* xevent) {
+ bool have_cookie = false;
+ if (xevent->type == GenericEvent &&
+ XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) {
+ have_cookie = true;
+ }
+
+ uint32_t action = PlatformEventSource::DispatchEvent(xevent);
+ if (xevent->type == GenericEvent &&
+ xevent->xgeneric.evtype == XI_HierarchyChanged) {
+ ui::UpdateDeviceList();
+ }
+
+ if (have_cookie)
+ XFreeEventData(xevent->xgeneric.display, &xevent->xcookie);
+ return action;
+}
+
+void X11EventSource::StopCurrentEventStream() {
+ continue_stream_ = false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/x11/x11_event_source.h b/chromium/ui/events/platform/x11/x11_event_source.h
new file mode 100644
index 00000000000..602eda67dd3
--- /dev/null
+++ b/chromium/ui/events/platform/x11/x11_event_source.h
@@ -0,0 +1,64 @@
+// 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_X11_X11_EVENT_SOURCE_H_
+#define UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/events_export.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11_types.h"
+
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+typedef union _XEvent XEvent;
+typedef unsigned long XID;
+
+namespace ui {
+
+// A PlatformEventSource implementation for reading events from X11 server and
+// dispatching the events to the appropriate dispatcher.
+class EVENTS_EXPORT X11EventSource : public PlatformEventSource {
+ public:
+ explicit X11EventSource(XDisplay* display);
+ virtual ~X11EventSource();
+
+ static X11EventSource* GetInstance();
+
+ // Called by the glib source dispatch function. Processes all (if any)
+ // available X events.
+ void DispatchXEvents();
+
+ // Blocks on the X11 event queue until we receive notification from the
+ // xserver that |w| has been mapped; StructureNotifyMask events on |w| are
+ // pulled out from the queue and dispatched out of order.
+ //
+ // For those that know X11, this is really a wrapper around XWindowEvent
+ // which still makes sure the preempted event is dispatched instead of
+ // dropped on the floor. This method exists because mapping a window is
+ // asynchronous (and we receive an XEvent when mapped), while there are also
+ // functions which require a mapped window.
+ void BlockUntilWindowMapped(XID window);
+
+ protected:
+ XDisplay* display() { return display_; }
+
+ private:
+ // PlatformEventSource:
+ virtual uint32_t DispatchEvent(XEvent* xevent) OVERRIDE;
+ virtual void StopCurrentEventStream() OVERRIDE;
+
+ // The connection to the X11 server used to receive the events.
+ XDisplay* display_;
+
+ // Keeps track of whether this source should continue to dispatch all the
+ // available events.
+ bool continue_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11EventSource);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_PLATFORM_X11_X11_EVENT_SOURCE_H_
diff --git a/chromium/ui/events/platform/x11/x11_event_source_glib.cc b/chromium/ui/events/platform/x11/x11_event_source_glib.cc
new file mode 100644
index 00000000000..95044226b50
--- /dev/null
+++ b/chromium/ui/events/platform/x11/x11_event_source_glib.cc
@@ -0,0 +1,101 @@
+// 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/events/platform/x11/x11_event_source.h"
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+namespace ui {
+
+namespace {
+
+struct GLibX11Source : public GSource {
+ // Note: The GLibX11Source is created and destroyed by GLib. So its
+ // constructor/destructor may or may not get called.
+ XDisplay* display;
+ GPollFD* poll_fd;
+};
+
+gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
+ GLibX11Source* gxsource = static_cast<GLibX11Source*>(source);
+ if (XPending(gxsource->display))
+ *timeout_ms = 0;
+ else
+ *timeout_ms = -1;
+ return FALSE;
+}
+
+gboolean XSourceCheck(GSource* source) {
+ GLibX11Source* gxsource = static_cast<GLibX11Source*>(source);
+ return XPending(gxsource->display);
+}
+
+gboolean XSourceDispatch(GSource* source,
+ GSourceFunc unused_func,
+ gpointer data) {
+ X11EventSource* x11_source = static_cast<X11EventSource*>(data);
+ x11_source->DispatchXEvents();
+ return TRUE;
+}
+
+GSourceFuncs XSourceFuncs = {
+ XSourcePrepare,
+ XSourceCheck,
+ XSourceDispatch,
+ NULL
+};
+
+class X11EventSourceGlib : public X11EventSource {
+ public:
+ explicit X11EventSourceGlib(XDisplay* display)
+ : X11EventSource(display),
+ x_source_(NULL) {
+ InitXSource(ConnectionNumber(display));
+ }
+
+ virtual ~X11EventSourceGlib() {
+ g_source_destroy(x_source_);
+ g_source_unref(x_source_);
+ }
+
+ private:
+ void InitXSource(int fd) {
+ CHECK(!x_source_);
+ CHECK(display()) << "Unable to get connection to X server";
+
+ x_poll_.reset(new GPollFD());
+ x_poll_->fd = fd;
+ x_poll_->events = G_IO_IN;
+ x_poll_->revents = 0;
+
+ GLibX11Source* glib_x_source = static_cast<GLibX11Source*>
+ (g_source_new(&XSourceFuncs, sizeof(GLibX11Source)));
+ glib_x_source->display = display();
+ glib_x_source->poll_fd = x_poll_.get();
+
+ x_source_ = glib_x_source;
+ g_source_add_poll(x_source_, x_poll_.get());
+ g_source_set_can_recurse(x_source_, TRUE);
+ g_source_set_callback(x_source_, NULL, this, NULL);
+ g_source_attach(x_source_, g_main_context_default());
+ }
+
+ // The GLib event source for X events.
+ GSource* x_source_;
+
+ // The poll attached to |x_source_|.
+ scoped_ptr<GPollFD> x_poll_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11EventSourceGlib);
+};
+
+} // namespace
+
+scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
+ return scoped_ptr<PlatformEventSource>(
+ new X11EventSourceGlib(gfx::GetXDisplay()));
+}
+
+} // 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
new file mode 100644
index 00000000000..d92e12a5d82
--- /dev/null
+++ b/chromium/ui/events/platform/x11/x11_event_source_libevent.cc
@@ -0,0 +1,68 @@
+// 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/events/platform/x11/x11_event_source.h"
+
+#include <X11/Xlib.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_libevent.h"
+
+namespace ui {
+
+namespace {
+
+class X11EventSourceLibevent : public X11EventSource,
+ public base::MessagePumpLibevent::Watcher {
+ public:
+ explicit X11EventSourceLibevent(XDisplay* display)
+ : X11EventSource(display),
+ initialized_(false) {
+ AddEventWatcher();
+ }
+
+ virtual ~X11EventSourceLibevent() {
+ }
+
+ private:
+ void AddEventWatcher() {
+ if (initialized_)
+ return;
+ if (!base::MessageLoop::current())
+ return;
+
+ int fd = ConnectionNumber(display());
+ base::MessageLoopForUI::current()->WatchFileDescriptor(fd, true,
+ base::MessagePumpLibevent::WATCH_READ, &watcher_controller_, this);
+ initialized_ = true;
+ }
+
+ // PlatformEventSource:
+ virtual void OnDispatcherListChanged() OVERRIDE {
+ AddEventWatcher();
+ }
+
+ // base::MessagePumpLibevent::Watcher:
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
+ DispatchXEvents();
+ }
+
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
+ NOTREACHED();
+ }
+
+ base::MessagePumpLibevent::FileDescriptorWatcher watcher_controller_;
+ bool initialized_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11EventSourceLibevent);
+};
+
+} // namespace
+
+scoped_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
+ return scoped_ptr<PlatformEventSource>(
+ new X11EventSourceLibevent(gfx::GetXDisplay()));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/platform/x11/x11_events_platform.gyp b/chromium/ui/events/platform/x11/x11_events_platform.gyp
new file mode 100644
index 00000000000..9070de7cb29
--- /dev/null
+++ b/chromium/ui/events/platform/x11/x11_events_platform.gyp
@@ -0,0 +1,43 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [{
+ 'target_name': 'x11_events_platform',
+ 'type': '<(component)',
+ 'defines': [
+ 'EVENTS_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../../../build/linux/system.gyp:x11',
+ '../../../gfx/x/gfx_x11.gyp:gfx_x11',
+ '../../events.gyp:events',
+ '../events_platform.gyp:events_platform',
+ ],
+ 'sources': [
+ 'x11_event_source.cc',
+ 'x11_event_source.h',
+ 'x11_event_source_glib.cc',
+ 'x11_event_source_libevent.cc',
+ ],
+ 'conditions': [
+ ['use_glib==1', {
+ 'dependencies': [
+ '../../../../build/linux/system.gyp:glib',
+ ],
+ 'sources!': [
+ 'x11_event_source_libevent.cc',
+ ],
+ }, {
+ # use_glib == 0
+ 'sources!': [
+ 'x11_event_source_glib.cc',
+ ],
+ }],
+ ],
+ }],
+}
diff --git a/chromium/ui/events/win/events_win.cc b/chromium/ui/events/win/events_win.cc
index e255fc988eb..9e74d3a4556 100644
--- a/chromium/ui/events/win/events_win.cc
+++ b/chromium/ui/events/win/events_win.cc
@@ -77,6 +77,11 @@ bool IsNonClientMouseEvent(const base::NativeEvent& native_event) {
native_event.message <= WM_NCXBUTTONDBLCLK);
}
+bool IsMouseEvent(const base::NativeEvent& native_event) {
+ return IsClientMouseEvent(native_event) ||
+ IsNonClientMouseEvent(native_event);
+}
+
bool IsMouseWheelEvent(const base::NativeEvent& native_event) {
return native_event.message == WM_MOUSEWHEEL ||
native_event.message == WM_MOUSEHWHEEL;
@@ -231,7 +236,7 @@ gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
native_point.y = GET_Y_LPARAM(native_event.lParam);
}
ScreenToClient(native_event.hwnd, &native_point);
- return gfx::win::ScreenToDIPPoint(gfx::Point(native_point));
+ return gfx::Point(native_point);
}
gfx::Point EventSystemLocationFromNative(
@@ -250,9 +255,8 @@ const char* CodeFromNative(const base::NativeEvent& native_event) {
return CodeForWindowsScanCode(scan_code);
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
- return IsClientMouseEvent(native_event) ||
- IsNonClientMouseEvent(native_event);
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+ return static_cast<uint32>(native_event.wParam);
}
int GetChangedMouseButtonFlagsFromNative(
@@ -279,6 +283,13 @@ 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) {
+ return event;
+}
+
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+}
+
void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
NOTIMPLEMENTED();
}
@@ -355,16 +366,6 @@ bool IsTouchpadEvent(const base::NativeEvent& event) {
return false;
}
-bool IsNoopEvent(const base::NativeEvent& event) {
- return event.message == WM_USER + 310;
-}
-
-base::NativeEvent CreateNoopEvent() {
- MSG event = { NULL };
- event.message = WM_USER + 310;
- return event;
-}
-
int GetModifiersFromACCEL(const ACCEL& accel) {
int modifiers = EF_NONE;
if (accel.fVirt & FSHIFT)
diff --git a/chromium/ui/events/x/device_data_manager.cc b/chromium/ui/events/x/device_data_manager.cc
index a2e02928c4b..4cc0957b4a8 100644
--- a/chromium/ui/events/x/device_data_manager.cc
+++ b/chromium/ui/events/x/device_data_manager.cc
@@ -10,9 +10,13 @@
#include "base/logging.h"
#include "base/memory/singleton.h"
+#include "base/sys_info.h"
#include "ui/events/event_constants.h"
+#include "ui/events/event_switches.h"
#include "ui/events/x/device_list_cache_x.h"
#include "ui/events/x/touch_factory_x11.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/point3_f.h"
#include "ui/gfx/x/x11_types.h"
// XIScrollClass was introduced in XI 2.1 so we need to define it here
@@ -110,8 +114,7 @@ DeviceDataManager* DeviceDataManager::GetInstance() {
}
DeviceDataManager::DeviceDataManager()
- : natural_scroll_enabled_(false),
- xi_opcode_(-1),
+ : xi_opcode_(-1),
atom_cache_(gfx::GetXDisplay(), kCachedAtoms),
button_map_count_(0) {
CHECK(gfx::GetXDisplay());
@@ -121,6 +124,8 @@ DeviceDataManager::DeviceDataManager()
CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1);
UpdateDeviceList(gfx::GetXDisplay());
UpdateButtonMap();
+ for (int i = 0; i < kMaxDeviceNum; i++)
+ touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID;
}
DeviceDataManager::~DeviceDataManager() {
@@ -177,14 +182,6 @@ bool DeviceDataManager::IsXInput2Available() const {
return xi_opcode_ != -1;
}
-float DeviceDataManager::GetNaturalScrollFactor(int sourceid) const {
- // Natural scroll is touchpad-only.
- if (sourceid >= kMaxDeviceNum || !touchpads_[sourceid])
- return -1.0f;
-
- return natural_scroll_enabled_ ? 1.0f : -1.0f;
-}
-
void DeviceDataManager::UpdateDeviceList(Display* display) {
cmt_devices_.reset();
touchpads_.reset();
@@ -460,20 +457,17 @@ void DeviceDataManager::GetScrollOffsets(const base::NativeEvent& native_event,
*y_offset_ordinal = 0;
*finger_count = 2;
- XIDeviceEvent* xiev =
- static_cast<XIDeviceEvent*>(native_event->xcookie.data);
- const float natural_scroll_factor = GetNaturalScrollFactor(xiev->sourceid);
EventData data;
GetEventRawData(*native_event, &data);
if (data.find(DT_CMT_SCROLL_X) != data.end())
- *x_offset = data[DT_CMT_SCROLL_X] * natural_scroll_factor;
+ *x_offset = data[DT_CMT_SCROLL_X];
if (data.find(DT_CMT_SCROLL_Y) != data.end())
- *y_offset = data[DT_CMT_SCROLL_Y] * natural_scroll_factor;
+ *y_offset = data[DT_CMT_SCROLL_Y];
if (data.find(DT_CMT_ORDINAL_X) != data.end())
- *x_offset_ordinal = data[DT_CMT_ORDINAL_X] * natural_scroll_factor;
+ *x_offset_ordinal = data[DT_CMT_ORDINAL_X];
if (data.find(DT_CMT_ORDINAL_Y) != data.end())
- *y_offset_ordinal = data[DT_CMT_ORDINAL_Y] * natural_scroll_factor;
+ *y_offset_ordinal = data[DT_CMT_ORDINAL_Y];
if (data.find(DT_CMT_FINGER_COUNT) != data.end())
*finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]);
}
@@ -488,22 +482,19 @@ void DeviceDataManager::GetFlingData(const base::NativeEvent& native_event,
*vy_ordinal = 0;
*is_cancel = false;
- XIDeviceEvent* xiev =
- static_cast<XIDeviceEvent*>(native_event->xcookie.data);
- const float natural_scroll_factor = GetNaturalScrollFactor(xiev->sourceid);
EventData data;
GetEventRawData(*native_event, &data);
if (data.find(DT_CMT_FLING_X) != data.end())
- *vx = data[DT_CMT_FLING_X] * natural_scroll_factor;
+ *vx = data[DT_CMT_FLING_X];
if (data.find(DT_CMT_FLING_Y) != data.end())
- *vy = data[DT_CMT_FLING_Y] * natural_scroll_factor;
+ *vy = data[DT_CMT_FLING_Y];
if (data.find(DT_CMT_FLING_STATE) != data.end())
*is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]);
if (data.find(DT_CMT_ORDINAL_X) != data.end())
- *vx_ordinal = data[DT_CMT_ORDINAL_X] * natural_scroll_factor;
+ *vx_ordinal = data[DT_CMT_ORDINAL_X];
if (data.find(DT_CMT_ORDINAL_Y) != data.end())
- *vy_ordinal = data[DT_CMT_ORDINAL_Y] * natural_scroll_factor;
+ *vy_ordinal = data[DT_CMT_ORDINAL_Y];
}
void DeviceDataManager::GetMetricsData(const base::NativeEvent& native_event,
@@ -649,4 +640,54 @@ void DeviceDataManager::InitializeValuatorsForTest(int deviceid,
}
}
+bool DeviceDataManager::TouchEventNeedsCalibrate(int touch_device_id) const {
+#if defined(OS_CHROMEOS) && defined(USE_XI2_MT)
+ int64 touch_display_id = GetDisplayForTouchDevice(touch_device_id);
+ if (base::SysInfo::IsRunningOnChromeOS() &&
+ touch_display_id == gfx::Display::InternalDisplayId()) {
+ return true;
+ }
+#endif // defined(OS_CHROMEOS) && defined(USE_XI2_MT)
+ return false;
+}
+
+void DeviceDataManager::ClearTouchTransformerRecord() {
+ for (int i = 0; i < kMaxDeviceNum; i++) {
+ touch_device_transformer_map_[i] = gfx::Transform();
+ touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID;
+ }
+}
+
+bool DeviceDataManager::IsTouchDeviceIdValid(int touch_device_id) const {
+ return (touch_device_id > 0 && touch_device_id < kMaxDeviceNum);
+}
+
+void DeviceDataManager::UpdateTouchInfoForDisplay(
+ int64 display_id,
+ int touch_device_id,
+ const gfx::Transform& touch_transformer) {
+ if (IsTouchDeviceIdValid(touch_device_id)) {
+ touch_device_to_display_map_[touch_device_id] = display_id;
+ touch_device_transformer_map_[touch_device_id] = touch_transformer;
+ }
+}
+
+void DeviceDataManager::ApplyTouchTransformer(int touch_device_id,
+ float* x, float* y) {
+ if (IsTouchDeviceIdValid(touch_device_id)) {
+ gfx::Point3F point(*x, *y, 0.0);
+ const gfx::Transform& trans =
+ touch_device_transformer_map_[touch_device_id];
+ trans.TransformPoint(&point);
+ *x = point.x();
+ *y = point.y();
+ }
+}
+
+int64 DeviceDataManager::GetDisplayForTouchDevice(int touch_device_id) const {
+ if (IsTouchDeviceIdValid(touch_device_id))
+ return touch_device_to_display_map_[touch_device_id];
+ return gfx::Display::kInvalidDisplayID;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/x/device_data_manager.h b/chromium/ui/events/x/device_data_manager.h
index aff06493571..1135ec222b8 100644
--- a/chromium/ui/events/x/device_data_manager.h
+++ b/chromium/ui/events/x/device_data_manager.h
@@ -20,8 +20,12 @@
#include "base/basictypes.h"
#include "base/event_types.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/events_base_export.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/transform.h"
#include "ui/gfx/x/x11_atom_cache.h"
template <typename T> struct DefaultSingletonTraits;
@@ -104,18 +108,9 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
// Returns the DeviceDataManager singleton.
static DeviceDataManager* GetInstance();
- // Natural scroll setter/getter.
- bool natural_scroll_enabled() const { return natural_scroll_enabled_; }
- void set_natural_scroll_enabled(bool enabled) {
- natural_scroll_enabled_ = enabled;
- }
-
// Returns if XInput2 is available on the system.
bool IsXInput2Available() const;
- // Get the natural scroll direction multiplier (1.0f or -1.0f).
- float GetNaturalScrollFactor(int sourceid) const;
-
// Updates the list of devices.
void UpdateDeviceList(Display* display);
@@ -226,6 +221,14 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
DataType type,
double value);
+ void ClearTouchTransformerRecord();
+ void UpdateTouchInfoForDisplay(int64 display_id,
+ int touch_device_id,
+ const gfx::Transform& touch_transformer);
+ void ApplyTouchTransformer(int touch_device_id, float* x, float* y);
+ int64 GetDisplayForTouchDevice(int touch_device_id) const;
+ bool TouchEventNeedsCalibrate(int touch_device_id) const;
+
private:
// Requirement for Singleton.
friend struct DefaultSingletonTraits<DeviceDataManager>;
@@ -245,10 +248,11 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
double min_value,
double max_value);
+ bool IsTouchDeviceIdValid(int touch_device_id) const;
+
static const int kMaxDeviceNum = 128;
static const int kMaxXIEventType = XI_LASTEVENT + 1;
static const int kMaxSlotNum = 10;
- bool natural_scroll_enabled_;
// Major opcode for the XInput extension. Used to identify XInput events.
int xi_opcode_;
@@ -292,6 +296,11 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
unsigned char button_map_[256];
int button_map_count_;
+ // Table to keep track of which display id is mapped to which touch device.
+ int64 touch_device_to_display_map_[kMaxDeviceNum];
+ // Index table to find the TouchTransformer for a touch device.
+ gfx::Transform touch_device_transformer_map_[kMaxDeviceNum];
+
DISALLOW_COPY_AND_ASSIGN(DeviceDataManager);
};
diff --git a/chromium/ui/events/x/events_x.cc b/chromium/ui/events/x/events_x.cc
index 5e3b9dd5462..bd12bd835db 100644
--- a/chromium/ui/events/x/events_x.cc
+++ b/chromium/ui/events/x/events_x.cc
@@ -9,10 +9,10 @@
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xlib.h>
+#include <X11/Xutil.h>
#include "base/logging.h"
#include "base/memory/singleton.h"
-#include "base/message_loop/message_pump_x11.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/events/x/device_data_manager.h"
@@ -137,6 +137,10 @@ int GetEventFlagsFromXState(unsigned int state) {
flags |= ui::EF_ALT_DOWN;
if (state & LockMask)
flags |= ui::EF_CAPS_LOCK_DOWN;
+ if (state & Mod3Mask)
+ flags |= ui::EF_MOD3_DOWN;
+ if (state & Mod4Mask)
+ flags |= ui::EF_COMMAND_DOWN;
if (state & Mod5Mask)
flags |= ui::EF_ALTGR_DOWN;
if (state & Button1Mask)
@@ -148,6 +152,36 @@ int GetEventFlagsFromXState(unsigned int state) {
return flags;
}
+int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
+ DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
+
+#if defined(OS_CHROMEOS)
+ const int ime_fabricated_flag = 0;
+#else
+ // XIM fabricates key events for the character compositions by XK_Multi_key.
+ // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
+ // order to input "é", then XIM generates a key event with keycode=0 and
+ // state=0 for the composition, and the sequence of X11 key events will be
+ // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
+ // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
+ //
+ // We have to send these fabricated key events to XIM so it can correctly
+ // handle the character compositions.
+ const unsigned int shift_lock_mask = ShiftMask | LockMask;
+ const bool fabricated_by_xim =
+ xevent->xkey.keycode == 0 &&
+ (xevent->xkey.state & ~shift_lock_mask) == 0;
+ const int ime_fabricated_flag =
+ fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
+#endif
+
+ return GetEventFlagsFromXState(xevent->xkey.state) |
+ (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
+ (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
+ ui::EF_FUNCTION_KEY : 0) |
+ ime_fabricated_flag;
+}
+
// Get the event flag for the button in XButtonEvent. During a ButtonPress
// event, |state| in XButtonEvent does not include the button that has just been
// pressed. Instead |state| contains flags for the buttons (if any) that had
@@ -225,10 +259,6 @@ double GetTouchParamFromXEvent(XEvent* xev,
return default_value;
}
-Atom GetNoopEventAtom() {
- return XInternAtom(gfx::GetXDisplay(), "noop", False);
-}
-
} // namespace
namespace ui {
@@ -277,10 +307,19 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
XIDeviceEvent* xievent =
static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+ // This check works only for master and floating slave devices. That is
+ // why it is necessary to check for the XI_Touch* events in the following
+ // switch statement to account for attached-slave touchscreens.
if (factory->IsTouchDevice(xievent->sourceid))
return GetTouchEventType(native_event);
switch (xievent->evtype) {
+ case XI_TouchBegin:
+ return ui::ET_TOUCH_PRESSED;
+ case XI_TouchUpdate:
+ return ui::ET_TOUCH_MOVED;
+ case XI_TouchEnd:
+ return ui::ET_TOUCH_RELEASED;
case XI_ButtonPress: {
int button = EventButtonFromNative(native_event);
if (button >= kMinWheelButton && button <= kMaxWheelButton)
@@ -323,7 +362,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
case KeyPress:
case KeyRelease: {
XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event);
- return GetEventFlagsFromXState(native_event->xkey.state);
+ return GetEventFlagsFromXKeyEvent(native_event);
}
case ButtonPress:
case ButtonRelease: {
@@ -333,6 +372,9 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
flags |= GetEventFlagsForButton(native_event->xbutton.button);
return flags;
}
+ case EnterNotify:
+ case LeaveNotify:
+ return GetEventFlagsFromXState(native_event->xcrossing.state);
case MotionNotify:
return GetEventFlagsFromXState(native_event->xmotion.state);
case GenericEvent: {
@@ -426,8 +468,21 @@ gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
case GenericEvent: {
XIDeviceEvent* xievent =
static_cast<XIDeviceEvent*>(native_event->xcookie.data);
- return gfx::Point(static_cast<int>(xievent->event_x),
- static_cast<int>(xievent->event_y));
+ float x = xievent->event_x;
+ float y = xievent->event_y;
+#if defined(OS_CHROMEOS)
+ switch (xievent->evtype) {
+ case XI_TouchBegin:
+ case XI_TouchUpdate:
+ case XI_TouchEnd:
+ ui::DeviceDataManager::GetInstance()->ApplyTouchTransformer(
+ xievent->deviceid, &x, &y);
+ break;
+ default:
+ break;
+ }
+#endif // defined(OS_CHROMEOS)
+ return gfx::Point(static_cast<int>(x), static_cast<int>(y));
}
}
return gfx::Point();
@@ -478,21 +533,10 @@ const char* CodeFromNative(const base::NativeEvent& native_event) {
return CodeFromXEvent(native_event);
}
-bool IsMouseEvent(const base::NativeEvent& native_event) {
- if (native_event->type == EnterNotify ||
- native_event->type == LeaveNotify ||
- native_event->type == ButtonPress ||
- native_event->type == ButtonRelease ||
- native_event->type == MotionNotify)
- return true;
- if (native_event->type == GenericEvent) {
- XIDeviceEvent* xievent =
- static_cast<XIDeviceEvent*>(native_event->xcookie.data);
- return xievent->evtype == XI_ButtonPress ||
- xievent->evtype == XI_ButtonRelease ||
- xievent->evtype == XI_Motion;
- }
- return false;
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+ KeySym keysym;
+ XLookupString(&native_event->xkey, NULL, 0, &keysym, NULL);
+ return keysym;
}
int GetChangedMouseButtonFlagsFromNative(
@@ -534,12 +578,27 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
return gfx::Vector2d(0, kWheelScrollAmount);
case 5:
return gfx::Vector2d(0, -kWheelScrollAmount);
+ case 6:
+ return gfx::Vector2d(kWheelScrollAmount, 0);
+ case 7:
+ return gfx::Vector2d(-kWheelScrollAmount, 0);
default:
- // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)?
return gfx::Vector2d();
}
}
+base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+ if (!event || event->type == GenericEvent)
+ return NULL;
+ XEvent* copy = new XEvent;
+ *copy = *event;
+ return copy;
+}
+
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+ delete event;
+}
+
void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
ui::EventType type = ui::EventTypeFromNative(xev);
if (type == ui::ET_TOUCH_CANCELLED ||
@@ -673,37 +732,8 @@ bool GetGestureTimes(const base::NativeEvent& native_event,
return true;
}
-void SetNaturalScroll(bool enabled) {
- DeviceDataManager::GetInstance()->set_natural_scroll_enabled(enabled);
-}
-
-bool IsNaturalScrollEnabled() {
- return DeviceDataManager::GetInstance()->natural_scroll_enabled();
-}
-
bool IsTouchpadEvent(const base::NativeEvent& event) {
return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event);
}
-bool IsNoopEvent(const base::NativeEvent& event) {
- return (event->type == ClientMessage &&
- event->xclient.message_type == GetNoopEventAtom());
-}
-
-base::NativeEvent CreateNoopEvent() {
- static XEvent* noop = NULL;
- if (!noop) {
- noop = new XEvent();
- memset(noop, 0, sizeof(XEvent));
- noop->xclient.type = ClientMessage;
- noop->xclient.window = None;
- noop->xclient.format = 8;
- DCHECK(!noop->xclient.display);
- }
- // Make sure we use atom from current xdisplay, which may
- // change during the test.
- noop->xclient.message_type = GetNoopEventAtom();
- return noop;
-}
-
} // namespace ui
diff --git a/chromium/ui/events/x/events_x_unittest.cc b/chromium/ui/events/x/events_x_unittest.cc
index b6c7f38c0ce..5047c59b19c 100644
--- a/chromium/ui/events/x/events_x_unittest.cc
+++ b/chromium/ui/events/x/events_x_unittest.cc
@@ -6,6 +6,8 @@
#include <X11/extensions/XInput2.h>
#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
// Generically-named #defines from Xlib that conflict with symbols in GTest.
#undef Bool
@@ -40,6 +42,37 @@ void InitButtonEvent(XEvent* event,
button_event->state = state;
}
+// Initializes the passed-in Xlib event.
+void InitKeyEvent(Display* display,
+ XEvent* event,
+ bool is_press,
+ int keycode,
+ int state) {
+ memset(event, 0, sizeof(*event));
+
+ // We don't bother setting fields that the event code doesn't use, such as
+ // x_root/y_root and window/root/subwindow.
+ XKeyEvent* key_event = &(event->xkey);
+ key_event->display = display;
+ key_event->type = is_press ? KeyPress : KeyRelease;
+ key_event->keycode = keycode;
+ key_event->state = state;
+}
+
+// Returns true if the keysym maps to a KeyEvent with the EF_FUNCTION_KEY
+// flag set, or the keysym maps to a zero key code.
+bool HasFunctionKeyFlagSetIfSupported(Display* display, int x_keysym) {
+ XEvent event;
+ int x_keycode = XKeysymToKeycode(display, x_keysym);
+ // Exclude keysyms for which the server has no corresponding keycode.
+ if (x_keycode) {
+ InitKeyEvent(display, &event, true, x_keycode, 0);
+ ui::KeyEvent ui_key_event(&event, false);
+ return (ui_key_event.flags() & ui::EF_FUNCTION_KEY);
+ }
+ return true;
+}
+
} // namespace
TEST(EventsXTest, ButtonEvents) {
@@ -51,7 +84,6 @@ TEST(EventsXTest, ButtonEvents) {
EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
InitButtonEvent(&event, true, location, 2, Button1Mask | ShiftMask);
EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
@@ -59,20 +91,17 @@ TEST(EventsXTest, ButtonEvents) {
ui::EF_SHIFT_DOWN,
ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
InitButtonEvent(&event, false, location, 3, 0);
EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(&event));
EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
// Scroll up.
InitButtonEvent(&event, true, location, 4, 0);
EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
offset = ui::GetMouseWheelOffset(&event);
EXPECT_GT(offset.y(), 0);
EXPECT_EQ(0, offset.x());
@@ -82,30 +111,27 @@ TEST(EventsXTest, ButtonEvents) {
EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
offset = ui::GetMouseWheelOffset(&event);
EXPECT_LT(offset.y(), 0);
EXPECT_EQ(0, offset.x());
- // Scroll left, typically.
+ // Scroll left.
InitButtonEvent(&event, true, location, 6, 0);
EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
offset = ui::GetMouseWheelOffset(&event);
EXPECT_EQ(0, offset.y());
- EXPECT_EQ(0, offset.x());
+ EXPECT_GT(offset.x(), 0);
- // Scroll right, typically.
+ // Scroll right.
InitButtonEvent(&event, true, location, 7, 0);
EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
EXPECT_EQ(location, ui::EventLocationFromNative(&event));
- EXPECT_TRUE(ui::IsMouseEvent(&event));
offset = ui::GetMouseWheelOffset(&event);
EXPECT_EQ(0, offset.y());
- EXPECT_EQ(0, offset.x());
+ EXPECT_LT(offset.x(), 0);
// TODO(derat): Test XInput code.
}
@@ -245,4 +271,193 @@ TEST(EventsXTest, TouchEventBasic) {
EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.5f);
}
#endif
+
+TEST(EventsXTest, NumpadKeyEvents) {
+ XEvent event;
+ Display* display = gfx::GetXDisplay();
+
+ struct {
+ bool is_numpad_key;
+ int x_keysym;
+ } keys[] = {
+ // XK_KP_Space and XK_KP_Equal are the extrema in the conventional
+ // keysymdef.h numbering.
+ { true, XK_KP_Space },
+ { true, XK_KP_Equal },
+ // Other numpad keysyms. (This is actually exhaustive in the current list.)
+ { true, XK_KP_Tab },
+ { true, XK_KP_Enter },
+ { true, XK_KP_F1 },
+ { true, XK_KP_F2 },
+ { true, XK_KP_F3 },
+ { true, XK_KP_F4 },
+ { true, XK_KP_Home },
+ { true, XK_KP_Left },
+ { true, XK_KP_Up },
+ { true, XK_KP_Right },
+ { true, XK_KP_Down },
+ { true, XK_KP_Prior },
+ { true, XK_KP_Page_Up },
+ { true, XK_KP_Next },
+ { true, XK_KP_Page_Down },
+ { true, XK_KP_End },
+ { true, XK_KP_Begin },
+ { true, XK_KP_Insert },
+ { true, XK_KP_Delete },
+ { true, XK_KP_Multiply },
+ { true, XK_KP_Add },
+ { true, XK_KP_Separator },
+ { true, XK_KP_Subtract },
+ { true, XK_KP_Decimal },
+ { true, XK_KP_Divide },
+ { true, XK_KP_0 },
+ { true, XK_KP_1 },
+ { true, XK_KP_2 },
+ { true, XK_KP_3 },
+ { true, XK_KP_4 },
+ { true, XK_KP_5 },
+ { true, XK_KP_6 },
+ { true, XK_KP_7 },
+ { true, XK_KP_8 },
+ { true, XK_KP_9 },
+ // Largest keysym preceding XK_KP_Space.
+ { false, XK_Num_Lock },
+ // Smallest keysym following XK_KP_Equal.
+ { false, XK_F1 },
+ // Non-numpad analogues of numpad keysyms.
+ { false, XK_Tab },
+ { false, XK_Return },
+ { false, XK_F1 },
+ { false, XK_F2 },
+ { false, XK_F3 },
+ { false, XK_F4 },
+ { false, XK_Home },
+ { false, XK_Left },
+ { false, XK_Up },
+ { false, XK_Right },
+ { false, XK_Down },
+ { false, XK_Prior },
+ { false, XK_Page_Up },
+ { false, XK_Next },
+ { false, XK_Page_Down },
+ { false, XK_End },
+ { false, XK_Insert },
+ { false, XK_Delete },
+ { false, XK_multiply },
+ { false, XK_plus },
+ { false, XK_minus },
+ { false, XK_period },
+ { false, XK_slash },
+ { false, XK_0 },
+ { false, XK_1 },
+ { false, XK_2 },
+ { false, XK_3 },
+ { false, XK_4 },
+ { false, XK_5 },
+ { false, XK_6 },
+ { false, XK_7 },
+ { false, XK_8 },
+ { false, XK_9 },
+ // Miscellaneous other keysyms.
+ { false, XK_BackSpace },
+ { false, XK_Scroll_Lock },
+ { false, XK_Multi_key },
+ { false, XK_Select },
+ { false, XK_Num_Lock },
+ { false, XK_Shift_L },
+ { false, XK_space },
+ { false, XK_A },
+ };
+
+ for (size_t k = 0; k < ARRAYSIZE_UNSAFE(keys); ++k) {
+ int x_keycode = XKeysymToKeycode(display, keys[k].x_keysym);
+ // Exclude keysyms for which the server has no corresponding keycode.
+ if (x_keycode) {
+ InitKeyEvent(display, &event, true, x_keycode, 0);
+ // int keysym = XLookupKeysym(&event.xkey, 0);
+ // if (keysym) {
+ ui::KeyEvent ui_key_event(&event, false);
+ EXPECT_EQ(keys[k].is_numpad_key ? ui::EF_NUMPAD_KEY : 0,
+ ui_key_event.flags() & ui::EF_NUMPAD_KEY);
+ }
+ }
+}
+
+TEST(EventsXTest, FunctionKeyEvents) {
+ Display* display = gfx::GetXDisplay();
+
+ // Min function key code minus 1.
+ EXPECT_FALSE(HasFunctionKeyFlagSetIfSupported(display, XK_F1 - 1));
+ // All function keys.
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F1));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F2));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F3));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F4));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F5));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F6));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F7));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F8));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F9));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F10));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F11));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F12));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F13));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F14));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F15));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F16));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F17));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F18));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F19));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F20));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F21));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F22));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F23));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F24));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F25));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F26));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F27));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F28));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F29));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F30));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F31));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F32));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F33));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F34));
+ EXPECT_TRUE(HasFunctionKeyFlagSetIfSupported(display, XK_F35));
+ // Max function key code plus 1.
+ EXPECT_FALSE(HasFunctionKeyFlagSetIfSupported(display, XK_F35 + 1));
+}
+
+#if !defined(OS_CHROMEOS)
+TEST(EventsXTest, ImeFabricatedKeyEvents) {
+ Display* display = gfx::GetXDisplay();
+
+ unsigned int state_to_be_fabricated[] = {
+ 0, ShiftMask, LockMask, ShiftMask | LockMask,
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(state_to_be_fabricated); ++i) {
+ unsigned int state = state_to_be_fabricated[i];
+ for (int is_char = 0; is_char < 2; ++is_char) {
+ XEvent x_event;
+ InitKeyEvent(display, &x_event, true, 0, state);
+ ui::KeyEvent key_event(&x_event, is_char);
+ EXPECT_TRUE(key_event.flags() & ui::EF_IME_FABRICATED_KEY);
+ }
+ }
+
+ unsigned int state_to_be_not_fabricated[] = {
+ ControlMask, Mod1Mask, Mod2Mask, ShiftMask | ControlMask,
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(state_to_be_not_fabricated); ++i) {
+ unsigned int state = state_to_be_not_fabricated[i];
+ for (int is_char = 0; is_char < 2; ++is_char) {
+ XEvent x_event;
+ InitKeyEvent(display, &x_event, true, 0, state);
+ ui::KeyEvent key_event(&x_event, is_char);
+ EXPECT_FALSE(key_event.flags() & ui::EF_IME_FABRICATED_KEY);
+ }
+ }
+}
+#endif
+
} // namespace ui
diff --git a/chromium/ui/events/x/touch_factory_x11.cc b/chromium/ui/events/x/touch_factory_x11.cc
index 62f6c89dab7..8176ce221a6 100644
--- a/chromium/ui/events/x/touch_factory_x11.cc
+++ b/chromium/ui/events/x/touch_factory_x11.cc
@@ -4,6 +4,7 @@
#include "ui/events/x/touch_factory_x11.h"
+#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
@@ -81,6 +82,7 @@ void TouchFactory::UpdateDeviceList(Display* display) {
touch_device_available_ = false;
touch_device_lookup_.reset();
touch_device_list_.clear();
+ touchscreen_ids_.clear();
max_touch_points_ = -1;
#if !defined(USE_XI2_MT)
@@ -128,7 +130,7 @@ void TouchFactory::UpdateDeviceList(Display* display) {
XIAnyClassInfo* xiclassinfo = devinfo->classes[k];
if (xiclassinfo->type == XITouchClass) {
XITouchClassInfo* tci =
- reinterpret_cast<XITouchClassInfo *>(xiclassinfo);
+ reinterpret_cast<XITouchClassInfo*>(xiclassinfo);
// Only care direct touch device (such as touch screen) right now
if (tci->mode == XIDirectTouch) {
touch_device_lookup_[devinfo->deviceid] = true;
@@ -142,6 +144,21 @@ void TouchFactory::UpdateDeviceList(Display* display) {
#endif
pointer_device_lookup_[devinfo->deviceid] = true;
}
+
+#if defined(USE_XI2_MT)
+ if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) {
+ for (int k = 0; k < devinfo->num_classes; ++k) {
+ XIAnyClassInfo* xiclassinfo = devinfo->classes[k];
+ if (xiclassinfo->type == XITouchClass) {
+ XITouchClassInfo* tci =
+ reinterpret_cast<XITouchClassInfo*>(xiclassinfo);
+ // Only care direct touch device (such as touch screen) right now
+ if (tci->mode == XIDirectTouch)
+ CacheTouchscreenIds(display, devinfo->deviceid);
+ }
+ }
+ }
+#endif
}
}
@@ -268,4 +285,43 @@ void TouchFactory::SetPointerDeviceForTest(
}
}
+void TouchFactory::CacheTouchscreenIds(Display* display, int device_id) {
+ XDevice* device = XOpenDevice(display, device_id);
+ if (!device)
+ return;
+
+ Atom actual_type_return;
+ int actual_format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_return;
+
+ const char kDeviceProductIdString[] = "Device Product ID";
+ Atom device_product_id_atom =
+ XInternAtom(display, kDeviceProductIdString, false);
+
+ if (device_product_id_atom != None &&
+ XGetDeviceProperty(display, device, device_product_id_atom, 0, 2,
+ False, XA_INTEGER, &actual_type_return,
+ &actual_format_return, &nitems_return,
+ &bytes_after_return, &prop_return) == Success) {
+ if (actual_type_return == XA_INTEGER &&
+ actual_format_return == 32 &&
+ nitems_return == 2) {
+ // An actual_format_return of 32 implies that the returned data is an
+ // array of longs. See the description of |prop_return| in `man
+ // XGetDeviceProperty` for details.
+ long* ptr = reinterpret_cast<long*>(prop_return);
+
+ // Internal displays will have a vid and pid of 0. Ignore them.
+ // ptr[0] is the vid, and ptr[1] is the pid.
+ if (ptr[0] || ptr[1])
+ touchscreen_ids_.insert(std::make_pair(ptr[0], ptr[1]));
+ }
+ XFree(prop_return);
+ }
+
+ XCloseDevice(display, device);
+}
+
} // namespace ui
diff --git a/chromium/ui/events/x/touch_factory_x11.h b/chromium/ui/events/x/touch_factory_x11.h
index ed62c6d247f..4d8a989fd8f 100644
--- a/chromium/ui/events/x/touch_factory_x11.h
+++ b/chromium/ui/events/x/touch_factory_x11.h
@@ -7,6 +7,8 @@
#include <bitset>
#include <map>
+#include <set>
+#include <utility>
#include <vector>
#include "base/timer/timer.h"
@@ -72,6 +74,11 @@ class EVENTS_BASE_EXPORT TouchFactory {
// Whether any touch device is currently present and enabled.
bool IsTouchDevicePresent();
+ // Pairs of <vendor id, product id> of external touch screens.
+ const std::set<std::pair<int, int> >& GetTouchscreenIds() const {
+ return touchscreen_ids_;
+ }
+
// Return maximum simultaneous touch points supported by device.
int GetMaxTouchPoints() const;
@@ -89,6 +96,8 @@ class EVENTS_BASE_EXPORT TouchFactory {
// Requirement for Singleton
friend struct DefaultSingletonTraits<TouchFactory>;
+ void CacheTouchscreenIds(Display* display, int id);
+
// NOTE: To keep track of touch devices, we currently maintain a lookup table
// to quickly decide if a device is a touch device or not. We also maintain a
// list of the touch devices. Ideally, there will be only one touch device,
@@ -118,6 +127,9 @@ class EVENTS_BASE_EXPORT TouchFactory {
// capable.
std::map<int, bool> touch_device_list_;
+ // Touch screen <vid, pid>s.
+ std::set<std::pair<int, int> > touchscreen_ids_;
+
// Maximum simultaneous touch points supported by device. In the case of
// devices with multiple digitizers (e.g. multiple touchscreens), the value
// is the maximum of the set of maximum supported contacts by each individual
diff --git a/chromium/ui/file_manager/file_manager.gyp b/chromium/ui/file_manager/file_manager.gyp
new file mode 100644
index 00000000000..ec12f68839f
--- /dev/null
+++ b/chromium/ui/file_manager/file_manager.gyp
@@ -0,0 +1,52 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/file_manager',
+ },
+ 'targets': [
+ {
+ 'target_name': 'file_manager_resources',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'file_manager_resources',
+ 'variables': {
+ 'grit_grd_file': 'file_manager_resources.grd',
+ },
+ 'includes': [ '../../build/grit_action.gypi' ],
+ },
+ ],
+ 'includes': [ '../../build/grit_target.gypi' ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ '<(SHARED_INTERMEDIATE_DIR)/ui/file_manager/file_manager_resources.pak',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'file_manager',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ 'file_manager_resources',
+ ],
+ 'defines': [
+ 'FILE_MANAGER_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'file_manager_export.h',
+ 'file_manager_resource_util.cc',
+ 'file_manager_resource_util.h',
+ '<(grit_out_dir)/grit/file_manager_resources_map.cc',
+ '<(grit_out_dir)/grit/file_manager_resources_map.h',
+ ]
+ },
+ ],
+}
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
new file mode 100644
index 00000000000..e2796a1b7ac
--- /dev/null
+++ b/chromium/ui/gfx/BUILD.gn
@@ -0,0 +1,445 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+if (use_ozone) {
+ import("//ui/ozone/ozone.gni")
+}
+
+# Several targets want to include this header file, and some of them are
+# child dependencies of "gfx". Therefore, we separate it out here so multiple
+# targets can all have a dependency for header checking purposes without
+# creating circular dependencies.
+source_set("gfx_export") {
+ sources = [
+ "gfx_export.h",
+ ]
+}
+
+component("gfx") {
+ sources = [
+ "android/device_display_info.cc",
+ "android/device_display_info.h",
+ "android/gfx_jni_registrar.cc",
+ "android/gfx_jni_registrar.h",
+ "android/java_bitmap.cc",
+ "android/java_bitmap.h",
+ "android/scroller.cc",
+ "android/scroller.h",
+ "android/shared_device_display_info.cc",
+ "android/shared_device_display_info.h",
+ "android/view_configuration.cc",
+ "android/view_configuration.h",
+ "animation/animation.cc",
+ "animation/animation.h",
+ "animation/animation_container.cc",
+ "animation/animation_container.h",
+ "animation/animation_container_element.h",
+ "animation/animation_container_observer.h",
+ "animation/animation_delegate.h",
+ "animation/linear_animation.cc",
+ "animation/linear_animation.h",
+ "animation/multi_animation.cc",
+ "animation/multi_animation.h",
+ "animation/slide_animation.cc",
+ "animation/slide_animation.h",
+ "animation/throb_animation.cc",
+ "animation/throb_animation.h",
+ "animation/tween.cc",
+ "animation/tween.h",
+ "blit.cc",
+ "blit.h",
+ "break_list.h",
+ "canvas.cc",
+ "canvas.h",
+ "canvas_android.cc",
+ "canvas_paint_mac.h",
+ "canvas_paint_mac.mm",
+ "canvas_paint_win.cc",
+ "canvas_paint_win.h",
+ "canvas_skia.cc",
+ "canvas_skia_paint.h",
+ "codec/jpeg_codec.cc",
+ "codec/jpeg_codec.h",
+ "codec/png_codec.cc",
+ "codec/png_codec.h",
+ "color_analysis.cc",
+ "color_analysis.h",
+ "color_profile.cc",
+ "color_profile.h",
+ "color_profile_mac.mm",
+ "color_profile_win.cc",
+ "color_utils.cc",
+ "color_utils.h",
+ "display.cc",
+ "display.h",
+ "display_observer.cc",
+ "display_observer.h",
+ "favicon_size.cc",
+ "favicon_size.h",
+ "font.cc",
+ "font.h",
+ "font_fallback_win.cc",
+ "font_fallback_win.h",
+ "font_list.cc",
+ "font_list.h",
+ "font_list_impl.cc",
+ "font_list_impl.h",
+ "font_render_params_android.cc",
+ "font_render_params_linux.cc",
+ "font_render_params_linux.h",
+ "font_smoothing_win.cc",
+ "font_smoothing_win.h",
+ "frame_time.h",
+ "gdi_util.cc",
+ "gdi_util.h",
+ "gfx_paths.cc",
+ "gfx_paths.h",
+ "gpu_memory_buffer.cc",
+ "gpu_memory_buffer.h",
+ "icon_util.cc",
+ "icon_util.h",
+ "image/canvas_image_source.cc",
+ "image/canvas_image_source.h",
+ "image/image.cc",
+ "image/image.h",
+ "image/image_family.cc",
+ "image/image_family.h",
+ "image/image_ios.mm",
+ "image/image_mac.mm",
+ "image/image_png_rep.cc",
+ "image/image_png_rep.h",
+ "image/image_skia.cc",
+ "image/image_skia.h",
+ "image/image_skia_operations.cc",
+ "image/image_skia_operations.h",
+ "image/image_skia_rep.cc",
+ "image/image_skia_rep.h",
+ "image/image_skia_source.h",
+ "image/image_skia_util_ios.h",
+ "image/image_skia_util_ios.mm",
+ "image/image_skia_util_mac.h",
+ "image/image_skia_util_mac.mm",
+ "image/image_util.cc",
+ "image/image_util.h",
+ "image/image_util_ios.mm",
+ "interpolated_transform.cc",
+ "interpolated_transform.h",
+ "linux_font_delegate.cc",
+ "linux_font_delegate.h",
+ "mac/scoped_ns_disable_screen_updates.h",
+ "native_widget_types.h",
+ "nine_image_painter.cc",
+ "nine_image_painter.h",
+ "path.cc",
+ "path.h",
+ "path_aura.cc",
+ "path_win.cc",
+ "path_win.h",
+ "path_x11.cc",
+ "path_x11.h",
+ "platform_font.h",
+ "platform_font_android.cc",
+ "platform_font_ios.h",
+ "platform_font_ios.mm",
+ "platform_font_mac.h",
+ "platform_font_mac.mm",
+ "platform_font_win.cc",
+ "platform_font_win.h",
+ "range/range.cc",
+ "range/range.h",
+ "range/range_mac.mm",
+ "range/range_win.cc",
+ "scoped_canvas.h",
+ "scoped_cg_context_save_gstate_mac.h",
+ "scoped_ns_graphics_context_save_gstate_mac.h",
+ "scoped_ns_graphics_context_save_gstate_mac.mm",
+ "scoped_ui_graphics_push_context_ios.h",
+ "scoped_ui_graphics_push_context_ios.mm",
+ "screen.cc",
+ "screen.h",
+ "screen_android.cc",
+ "screen_aura.cc",
+ "screen_ios.mm",
+ "screen_mac.mm",
+ "screen_win.cc",
+ "screen_win.h",
+ "scrollbar_size.cc",
+ "scrollbar_size.h",
+ "selection_model.cc",
+ "selection_model.h",
+ "sequential_id_generator.cc",
+ "sequential_id_generator.h",
+ "shadow_value.cc",
+ "shadow_value.h",
+ "skbitmap_operations.cc",
+ "skbitmap_operations.h",
+ "skia_util.cc",
+ "skia_util.h",
+ "switches.cc",
+ "switches.h",
+ "sys_color_change_listener.cc",
+ "sys_color_change_listener.h",
+ "text_constants.h",
+ "text_elider.cc",
+ "text_elider.h",
+ "text_utils.cc",
+ "text_utils.h",
+ "text_utils_android.cc",
+ "text_utils_ios.mm",
+ "transform.cc",
+ "transform.h",
+ "transform_util.cc",
+ "transform_util.h",
+ "ui_gfx_exports.cc",
+ "utf16_indexing.cc",
+ "utf16_indexing.h",
+ "vsync_provider.h",
+ "win/dpi.cc",
+ "win/dpi.h",
+ "win/hwnd_util.cc",
+ "win/hwnd_util.h",
+ "win/scoped_set_map_mode.h",
+ "win/singleton_hwnd.cc",
+ "win/singleton_hwnd.h",
+ "win/window_impl.cc",
+ "win/window_impl.h",
+ ]
+
+ defines = [ "GFX_IMPLEMENTATION" ]
+
+ deps = [
+ ":gfx_export",
+ "//base",
+ "//base:i18n",
+ "//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//third_party/harfbuzz-ng",
+ "//third_party/icu:icui18n",
+ "//third_party/icu:icuuc",
+ "//third_party/libpng",
+ "//third_party/zlib",
+ "//ui/gfx/geometry",
+ ]
+
+ # Text rendering conditions (complicated so separated out).
+ if (is_android || is_ios) {
+ # We don't support RenderText on these platforms.
+ } else {
+ # These text rendering files are supported everywhere text rendering is.
+ sources += [
+ "render_text.cc",
+ "render_text.h",
+ "render_text_harfbuzz.cc",
+ "render_text_harfbuzz.h",
+ "text_utils_skia.cc",
+ ]
+ # These are the "native" rendering routines, only one should apply.
+ if (is_win) {
+ sources += [ "render_text_win.cc" ]
+ } else if (is_mac) {
+ sources += [ "render_text_mac.cc" ]
+ } else if (use_pango) {
+ sources += [ "render_text_pango.cc" ]
+ } else if (use_ozone) {
+ sources += [ "render_text_ozone.cc" ]
+ }
+ }
+
+ # iOS.
+ if (is_ios) {
+ sources -= [
+ "codec/jpeg_codec.cc",
+ "codec/jpeg_codec.h",
+ ]
+ } else {
+ deps += [ "//third_party:jpeg" ]
+ }
+
+ # Android.
+ if (is_android) {
+ sources -= [
+ "animation/throb_animation.cc",
+ "canvas_skia.cc",
+ "display_observer.cc",
+ "selection_model.cc",
+ ]
+
+ if (use_aura) {
+ sources -= [ "screen_android.cc" ]
+ } else {
+ sources -= [ "path.cc" ]
+ }
+
+ # TODO(GYP) re-enable when base_java exists.
+ #if (!is_android_webview_build) {
+ # deps += [ "//base:base_java" ]
+ #}
+
+ deps += [ ":gfx_jni_headers" ]
+ libs = [
+ "android",
+ "jnigraphics",
+ ]
+ }
+
+ # Windows.
+ if (is_win) {
+ cflags = [
+ "/wd4267", # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int.
+ "/wd4324", # Structure was padded due to __declspec(align()), which is
+ # uninteresting.
+ ]
+ } else {
+ sources -= [
+ "gdi_util.cc",
+ "gdi_util.h",
+ "icon_util.cc",
+ "icon_util.h",
+ ]
+ }
+
+ # Linux.
+ if (is_linux) {
+ configs += [ "//build/config/linux:fontconfig" ]
+ }
+
+ # Ozone stuff.
+ if (use_ozone) {
+ sources += [
+ "platform_font_ozone.cc",
+ "ozone/impl/file_surface_factory.cc",
+ "ozone/impl/file_surface_factory.h",
+ "ozone/surface_factory_ozone.cc",
+ "ozone/surface_factory_ozone.h",
+ "ozone/surface_ozone.h",
+ "ozone/overlay_candidates_ozone.cc",
+ "ozone/overlay_candidates_ozone.h",
+ ]
+ }
+
+ if (!use_aura) {
+ sources -= [
+ "nine_image_painter.cc",
+ "nine_image_painter.h",
+ "path_aura.cc",
+ "screen_aura.cc",
+ ]
+ }
+
+ if (use_x11) {
+ deps += [
+ ":gfx_x11",
+ ]
+ } else {
+ sources -= [
+ "path_x11.cc",
+ ]
+ }
+
+ if (use_pango) {
+ sources += [
+ "pango_util.cc",
+ "pango_util.h",
+ "platform_font_pango.cc",
+ "platform_font_pango.h",
+ ]
+ configs += [ "//build/config/linux:pangocairo" ]
+ }
+}
+
+# Looking for gfx_geometry? It's //ui/gfx/geometry:geometry
+
+source_set("gfx_test_support") {
+ sources = [
+ "test/gfx_util.cc",
+ "test/gfx_util.h",
+ "test/ui_cocoa_test_helper.h",
+ "test/ui_cocoa_test_helper.mm",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//skia",
+ "//testing/gtest",
+ ]
+
+ if (is_ios) {
+ # The cocoa files don't apply to iOS.
+ sources -= [
+ "test/ui_cocoa_test_helper.h",
+ "test/ui_cocoa_test_helper.mm",
+ ]
+ }
+}
+
+test("gfx_unittests") {
+ sources = [
+ "geometry/box_unittest.cc",
+ "geometry/cubic_bezier_unittest.cc",
+ "geometry/insets_unittest.cc",
+ "geometry/matrix3_unittest.cc",
+ "geometry/point_unittest.cc",
+ "geometry/point3_unittest.cc",
+ "geometry/quad_unittest.cc",
+ "geometry/rect_unittest.cc",
+ "geometry/safe_integer_conversions_unittest.cc",
+ "geometry/size_unittest.cc",
+ "geometry/vector2d_unittest.cc",
+ "geometry/vector3d_unittest.cc",
+ "range/range_unittest.cc",
+ ]
+
+ deps = [
+ ":gfx",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ "//ui/gfx/geometry",
+ ]
+}
+
+if (is_android) {
+ generate_jni("gfx_jni_headers") {
+ sources = [
+ "../android/java/src/org/chromium/ui/gfx/BitmapHelper.java",
+ "../android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java",
+ "../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java",
+ ]
+ jni_package = "gfx"
+ }
+}
+
+if (use_x11) {
+ component("gfx_x11") {
+ sources = [
+ "x/x11_atom_cache.cc",
+ "x/x11_atom_cache.h",
+ "x/x11_connection.cc",
+ "x/x11_connection.h",
+ "x/x11_error_tracker.cc",
+ "x/x11_error_tracker.h",
+ "x/x11_switches.cc",
+ "x/x11_switches.h",
+ "x/x11_types.cc",
+ "x/x11_types.h",
+ ]
+
+ defines = [ "GFX_IMPLEMENTATION" ]
+ configs += [ "//build/config/linux:x11" ]
+
+ deps = [
+ ":gfx_export",
+ "//base"
+ ]
+ }
+}
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS
index 07a2ea9406f..758e42abb66 100644
--- a/chromium/ui/gfx/DEPS
+++ b/chromium/ui/gfx/DEPS
@@ -1,8 +1,6 @@
include_rules = [
"+base",
- "+net",
"+skia/ext",
- "+third_party/angle",
+ "+third_party/harfbuzz-ng",
"+third_party/skia",
- "+ui/test/ui_unittests_resource.h", # TODO(beng): remove
]
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index 563c600ea4d..dad6c9a8452 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -7,9 +7,6 @@ danakj@chromium.org
# RenderText and related classes.
msw@chromium.org
-# RenderText and related classes.
-xji@chromium.org
-
# Display and related classes.
per-file display*=oshima@chromium.org
per-file screen*=oshima@chromium.org
@@ -19,5 +16,11 @@ per-file transform*=shawnsingh@chromium.org
per-file transform*=vollick@chromium.org
per-file interpolated_transform*=vollick@chromium.org
+# GPU memory buffer interface.
+per-file gpu_memory_buffer*=reveman@chromium.org
+
+# R-Tree implementation.
+per-file r_tree*=luken@chromium.org
+
# If you're doing structural changes get a review from one of the OWNERS.
per-file *.gyp*=*
diff --git a/chromium/ui/gfx/android/OWNERS b/chromium/ui/gfx/android/OWNERS
index c87688f018a..316565b6ed3 100644
--- a/chromium/ui/gfx/android/OWNERS
+++ b/chromium/ui/gfx/android/OWNERS
@@ -1 +1,3 @@
-yfriedman@chromium.org
+aelias@chromium.org
+jdduke@chromium.org
+skyostil@chromium.org
diff --git a/chromium/ui/gfx/android/bitmap_config_list.h b/chromium/ui/gfx/android/bitmap_config_list.h
new file mode 100644
index 00000000000..9561168f3b3
--- /dev/null
+++ b/chromium/ui/gfx/android/bitmap_config_list.h
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate enum values.
+
+#ifndef DEFINE_BITMAP_CONFIG
+#error "DEFINE_BITMAP_CONFIG should be defined before including this file"
+#endif
+DEFINE_BITMAP_CONFIG(FORMAT_NO_CONFIG, 0)
+DEFINE_BITMAP_CONFIG(FORMAT_ALPHA_8, 1)
+DEFINE_BITMAP_CONFIG(FORMAT_ARGB_4444, 2)
+DEFINE_BITMAP_CONFIG(FORMAT_ARGB_8888, 3)
+DEFINE_BITMAP_CONFIG(FORMAT_RGB_565, 4)
diff --git a/chromium/ui/gfx/android/device_display_info.cc b/chromium/ui/gfx/android/device_display_info.cc
index 2de8440e1d3..4d2c80c09d6 100644
--- a/chromium/ui/gfx/android/device_display_info.cc
+++ b/chromium/ui/gfx/android/device_display_info.cc
@@ -23,6 +23,14 @@ int DeviceDisplayInfo::GetDisplayWidth() {
return SharedDeviceDisplayInfo::GetInstance()->GetDisplayWidth();
}
+int DeviceDisplayInfo::GetPhysicalDisplayHeight() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetPhysicalDisplayHeight();
+}
+
+int DeviceDisplayInfo::GetPhysicalDisplayWidth() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetPhysicalDisplayWidth();
+}
+
int DeviceDisplayInfo::GetBitsPerPixel() {
return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerPixel();
}
@@ -39,4 +47,8 @@ int DeviceDisplayInfo::GetSmallestDIPWidth() {
return SharedDeviceDisplayInfo::GetInstance()->GetSmallestDIPWidth();
}
+int DeviceDisplayInfo::GetRotationDegrees() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetRotationDegrees();
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/android/device_display_info.h b/chromium/ui/gfx/android/device_display_info.h
index 83968e9b51e..74e0ada4875 100644
--- a/chromium/ui/gfx/android/device_display_info.h
+++ b/chromium/ui/gfx/android/device_display_info.h
@@ -26,6 +26,18 @@ class GFX_EXPORT DeviceDisplayInfo {
// Returns display width in physical pixels.
int GetDisplayWidth();
+ // Returns real display height in physical pixels.
+ // This version does not subtract window decorations etc.
+ // WARNING: This is only supported on JB-MR1 (sdk >= 17). Either
+ // check the SDK-level, or check for '0' being returned.
+ int GetPhysicalDisplayHeight();
+
+ // Returns real display width in physical pixels.
+ // This version does not subtract window decorations etc.
+ // WARNING: This is only supported on JB-MR1 (sdk >= 17). Either
+ // check the SDK-level, or check for '0' being returned.
+ int GetPhysicalDisplayWidth();
+
// Returns number of bits per pixel.
int GetBitsPerPixel();
@@ -39,6 +51,11 @@ class GFX_EXPORT DeviceDisplayInfo {
// Smallest possible screen size in density-independent pixels.
int GetSmallestDIPWidth();
+ // Returns the display rotation angle from its natural orientation. Expected
+ // values are one of { 0, 90, 180, 270 }.
+ // See DeviceDispayInfo.java for more information.
+ int GetRotationDegrees();
+
private:
DISALLOW_COPY_AND_ASSIGN(DeviceDisplayInfo);
};
diff --git a/chromium/ui/gfx/android/java_bitmap.cc b/chromium/ui/gfx/android/java_bitmap.cc
index 2a1be65d215..a5b891a4af7 100644
--- a/chromium/ui/gfx/android/java_bitmap.cc
+++ b/chromium/ui/gfx/android/java_bitmap.cc
@@ -9,11 +9,10 @@
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "jni/BitmapHelper_jni.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/size.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
namespace gfx {
@@ -42,17 +41,52 @@ bool JavaBitmap::RegisterJavaBitmap(JNIEnv* env) {
return RegisterNativesImpl(env);
}
-static ScopedJavaLocalRef<jobject> CreateJavaBitmap(const gfx::Size& size) {
- return Java_BitmapHelper_createBitmap(AttachCurrentThread(),
- size.width(), size.height());
+static int SkBitmapConfigToBitmapFormat(SkBitmap::Config bitmap_config) {
+ switch (bitmap_config) {
+ case SkBitmap::kA8_Config:
+ return BITMAP_FORMAT_ALPHA_8;
+ case SkBitmap::kARGB_4444_Config:
+ return BITMAP_FORMAT_ARGB_4444;
+ case SkBitmap::kARGB_8888_Config:
+ return BITMAP_FORMAT_ARGB_8888;
+ case SkBitmap::kRGB_565_Config:
+ return BITMAP_FORMAT_RGB_565;
+ case SkBitmap::kNo_Config:
+ default:
+ NOTREACHED();
+ return BITMAP_FORMAT_NO_CONFIG;
+ }
+}
+
+ScopedJavaLocalRef<jobject> CreateJavaBitmap(int width,
+ int height,
+ SkBitmap::Config bitmap_config) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ int java_bitmap_config = SkBitmapConfigToBitmapFormat(bitmap_config);
+ return Java_BitmapHelper_createBitmap(
+ AttachCurrentThread(), width, height, java_bitmap_config);
+}
+
+ScopedJavaLocalRef<jobject> CreateJavaBitmapFromAndroidResource(
+ const char* name,
+ gfx::Size size) {
+ DCHECK(name);
+ DCHECK(!size.IsEmpty());
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> jname(ConvertUTF8ToJavaString(env, name));
+ return Java_BitmapHelper_decodeDrawableResource(
+ env, jname.obj(), size.width(), size.height());
}
ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) {
DCHECK(skbitmap);
- DCHECK_EQ(skbitmap->bytesPerPixel(), 4);
-
- ScopedJavaLocalRef<jobject> jbitmap =
- CreateJavaBitmap(gfx::Size(skbitmap->width(), skbitmap->height()));
+ DCHECK(!skbitmap->isNull());
+ SkBitmap::Config bitmap_config = skbitmap->config();
+ DCHECK((bitmap_config == SkBitmap::kRGB_565_Config) ||
+ (bitmap_config == SkBitmap::kARGB_8888_Config));
+ ScopedJavaLocalRef<jobject> jbitmap = CreateJavaBitmap(
+ skbitmap->width(), skbitmap->height(), bitmap_config);
SkAutoLockPixels src_lock(*skbitmap);
JavaBitmap dst_lock(jbitmap.obj());
void* src_pixels = skbitmap->getPixels();
@@ -62,8 +96,13 @@ ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) {
return jbitmap;
}
-SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap) {
- DCHECK_EQ(jbitmap.format(), ANDROID_BITMAP_FORMAT_RGBA_8888);
+SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap) {
+ // TODO(jdduke): Convert to DCHECK's when sufficient data has been capture for
+ // crbug.com/341406.
+ CHECK_EQ(jbitmap.format(), ANDROID_BITMAP_FORMAT_RGBA_8888);
+ CHECK(!jbitmap.size().IsEmpty());
+ CHECK_GT(jbitmap.stride(), 0U);
+ CHECK(jbitmap.pixels());
gfx::Size src_size = jbitmap.size();
@@ -72,30 +111,34 @@ SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap) {
src_size.width(),
src_size.height(),
jbitmap.stride());
- skbitmap.allocPixels();
+ if (!skbitmap.allocPixels()) {
+ LOG(FATAL) << " Failed to allocate bitmap of size " << src_size.width()
+ << "x" << src_size.height() << " stride=" << jbitmap.stride();
+ }
SkAutoLockPixels dst_lock(skbitmap);
-
- void* src_pixels = jbitmap.pixels();
+ const void* src_pixels = jbitmap.pixels();
void* dst_pixels = skbitmap.getPixels();
-
memcpy(dst_pixels, src_pixels, skbitmap.getSize());
return skbitmap;
}
-SkBitmap CreateSkBitmapFromResource(const char* name, gfx::Size size) {
- DCHECK(!size.IsEmpty());
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> jname(env, env->NewStringUTF(name));
- ScopedJavaLocalRef<jobject> jobj(Java_BitmapHelper_decodeDrawableResource(
- env, jname.obj(), size.width(), size.height()));
- if (jobj.is_null())
- return SkBitmap();
-
- JavaBitmap jbitmap(jobj.obj());
- SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(jbitmap);
- return skia::ImageOperations::Resize(
- bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height());
+SkBitmap::Config ConvertToSkiaConfig(jobject bitmap_config) {
+ int jbitmap_config = Java_BitmapHelper_getBitmapFormatForConfig(
+ AttachCurrentThread(), bitmap_config);
+ switch (jbitmap_config) {
+ case BITMAP_FORMAT_ALPHA_8:
+ return SkBitmap::kA8_Config;
+ case BITMAP_FORMAT_ARGB_4444:
+ return SkBitmap::kARGB_4444_Config;
+ case BITMAP_FORMAT_ARGB_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case BITMAP_FORMAT_RGB_565:
+ return SkBitmap::kRGB_565_Config;
+ case BITMAP_FORMAT_NO_CONFIG:
+ default:
+ return SkBitmap::kNo_Config;
+ }
}
} // namespace gfx
diff --git a/chromium/ui/gfx/android/java_bitmap.h b/chromium/ui/gfx/android/java_bitmap.h
index 9d1e4432cb7..44a17cade74 100644
--- a/chromium/ui/gfx/android/java_bitmap.h
+++ b/chromium/ui/gfx/android/java_bitmap.h
@@ -8,12 +8,20 @@
#include <jni.h>
#include "base/android/scoped_java_ref.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/size.h"
-class SkBitmap;
-
namespace gfx {
+// Define Bitmap Config values like BITMAP_CONFIG_ARGB_8888 in a
+// way that ensures they're always the same than their Java counterpart.
+
+enum BitmapConfig {
+#define DEFINE_BITMAP_CONFIG(x, y) BITMAP_##x = y,
+#include "bitmap_config_list.h"
+#undef DEFINE_BITMAP_CONFIG
+};
+
// This class wraps a JNI AndroidBitmap object to make it easier to use. It
// handles locking and unlocking of the underlying pixels, along with wrapping
// various JNI methods.
@@ -23,6 +31,7 @@ class GFX_EXPORT JavaBitmap {
~JavaBitmap();
inline void* pixels() { return pixels_; }
+ inline const void* pixels() const { return pixels_; }
inline const gfx::Size& size() const { return size_; }
// Formats are in android/bitmap.h; e.g. ANDROID_BITMAP_FORMAT_RGBA_8888
inline int format() const { return format_; }
@@ -41,15 +50,32 @@ class GFX_EXPORT JavaBitmap {
DISALLOW_COPY_AND_ASSIGN(JavaBitmap);
};
+// Allocates a Java-backed bitmap (android.graphics.Bitmap) with the given
+// (non-empty!) size and configuration.
+GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> CreateJavaBitmap(
+ int width,
+ int height,
+ SkBitmap::Config bitmap_config);
+
+// Loads a Java-backed bitmap (android.graphics.Bitmap) from the provided
+// drawable resource identifier (e.g., android:drawable/overscroll_glow). If the
+// resource loads successfully, it will be integrally scaled down, preserving
+// aspect ratio, to a size no smaller than |size|. Otherwise, null is returned.
+GFX_EXPORT base::android::ScopedJavaLocalRef<jobject>
+ CreateJavaBitmapFromAndroidResource(const char* name, gfx::Size size);
+
+// Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap).
+// Note: |skbitmap| is assumed to be non-null, non-empty and one of RGBA_8888 or
+// RGB_565 formats.
GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(
const SkBitmap* skbitmap);
-GFX_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap);
+// Converts |bitmap| to an SkBitmap of the same size and format.
+// Note: |jbitmap| is assumed to be non-null, non-empty and of format RGBA_8888.
+GFX_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap);
-// If the resource loads successfully, it will be resized to |size|.
-// Note: If the source resource is smaller than |size|, quality may suffer.
-GFX_EXPORT SkBitmap CreateSkBitmapFromResource(const char* name,
- gfx::Size size);
+// Returns a Skia config value for the requested input java Bitmap.Config.
+GFX_EXPORT SkBitmap::Config ConvertToSkiaConfig(jobject bitmap_config);
} // namespace gfx
diff --git a/chromium/ui/gfx/android/scroller.cc b/chromium/ui/gfx/android/scroller.cc
new file mode 100644
index 00000000000..4a44741f52e
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller.cc
@@ -0,0 +1,439 @@
+// 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/gfx/android/scroller.h"
+
+#include <cmath>
+
+#include "base/lazy_instance.h"
+
+namespace gfx {
+namespace {
+
+// Default scroll duration from android.widget.Scroller.
+const int kDefaultDurationMs = 250;
+
+// Default friction constant in android.view.ViewConfiguration.
+const float kDefaultFriction = 0.015f;
+
+// == std::log(0.78f) / std::log(0.9f)
+const float kDecelerationRate = 2.3582018f;
+
+// Tension lines cross at (kInflexion, 1).
+const float kInflexion = 0.35f;
+
+const float kEpsilon = 1e-5f;
+
+bool ApproxEquals(float a, float b) {
+ return std::abs(a - b) < kEpsilon;
+}
+
+struct ViscosityConstants {
+ ViscosityConstants()
+ : viscous_fluid_scale_(8.f), viscous_fluid_normalize_(1.f) {
+ viscous_fluid_normalize_ = 1.0f / ApplyViscosity(1.0f);
+ }
+
+ float ApplyViscosity(float x) {
+ x *= viscous_fluid_scale_;
+ if (x < 1.0f) {
+ x -= (1.0f - std::exp(-x));
+ } else {
+ float start = 0.36787944117f; // 1/e == exp(-1)
+ x = 1.0f - std::exp(1.0f - x);
+ x = start + x * (1.0f - start);
+ }
+ x *= viscous_fluid_normalize_;
+ return x;
+ }
+
+ private:
+ // This controls the intensity of the viscous fluid effect.
+ float viscous_fluid_scale_;
+ float viscous_fluid_normalize_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViscosityConstants);
+};
+
+struct SplineConstants {
+ SplineConstants() {
+ const float kStartTension = 0.5f;
+ const float kEndTension = 1.0f;
+ const float kP1 = kStartTension * kInflexion;
+ const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion);
+
+ float x_min = 0.0f;
+ float y_min = 0.0f;
+ for (int i = 0; i < NUM_SAMPLES; i++) {
+ const float alpha = static_cast<float>(i) / NUM_SAMPLES;
+
+ float x_max = 1.0f;
+ float x, tx, coef;
+ while (true) {
+ x = x_min + (x_max - x_min) / 2.0f;
+ coef = 3.0f * x * (1.0f - x);
+ tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x;
+ if (ApproxEquals(tx, alpha))
+ break;
+ if (tx > alpha)
+ x_max = x;
+ else
+ x_min = x;
+ }
+ spline_position_[i] = coef * ((1.0f - x) * kStartTension + x) + x * x * x;
+
+ float y_max = 1.0f;
+ float y, dy;
+ while (true) {
+ y = y_min + (y_max - y_min) / 2.0f;
+ coef = 3.0f * y * (1.0f - y);
+ dy = coef * ((1.0f - y) * kStartTension + y) + y * y * y;
+ if (ApproxEquals(dy, alpha))
+ break;
+ if (dy > alpha)
+ y_max = y;
+ else
+ y_min = y;
+ }
+ spline_time_[i] = coef * ((1.0f - y) * kP1 + y * kP2) + y * y * y;
+ }
+ spline_position_[NUM_SAMPLES] = spline_time_[NUM_SAMPLES] = 1.0f;
+ }
+
+ void CalculateCoefficients(float t,
+ float* distance_coef,
+ float* velocity_coef) {
+ *distance_coef = 1.f;
+ *velocity_coef = 0.f;
+ const int index = static_cast<int>(NUM_SAMPLES * t);
+ if (index < NUM_SAMPLES) {
+ const float t_inf = static_cast<float>(index) / NUM_SAMPLES;
+ const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES;
+ const float d_inf = spline_position_[index];
+ const float d_sup = spline_position_[index + 1];
+ *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf);
+ *distance_coef = d_inf + (t - t_inf) * *velocity_coef;
+ }
+ }
+
+ private:
+ enum {
+ NUM_SAMPLES = 100
+ };
+
+ float spline_position_[NUM_SAMPLES + 1];
+ float spline_time_[NUM_SAMPLES + 1];
+
+ DISALLOW_COPY_AND_ASSIGN(SplineConstants);
+};
+
+float ComputeDeceleration(float friction) {
+ const float kGravityEarth = 9.80665f;
+ return kGravityEarth // g (m/s^2)
+ * 39.37f // inch/meter
+ * 160.f // pixels/inch
+ * friction;
+}
+
+template <typename T>
+int Signum(T t) {
+ return (T(0) < t) - (t < T(0));
+}
+
+template <typename T>
+T Clamped(T t, T a, T b) {
+ return t < a ? a : (t > b ? b : t);
+}
+
+// Leaky to allow access from the impl thread.
+base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants =
+ LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<SplineConstants>::Leaky g_spline_constants =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+Scroller::Config::Config()
+ : fling_friction(kDefaultFriction),
+ flywheel_enabled(false) {}
+
+Scroller::Scroller(const Config& config)
+ : mode_(UNDEFINED),
+ start_x_(0),
+ start_y_(0),
+ final_x_(0),
+ final_y_(0),
+ min_x_(0),
+ max_x_(0),
+ min_y_(0),
+ max_y_(0),
+ curr_x_(0),
+ curr_y_(0),
+ duration_seconds_reciprocal_(1),
+ delta_x_(0),
+ delta_x_norm_(1),
+ delta_y_(0),
+ delta_y_norm_(1),
+ finished_(true),
+ flywheel_enabled_(config.flywheel_enabled),
+ velocity_(0),
+ curr_velocity_(0),
+ distance_(0),
+ fling_friction_(config.fling_friction),
+ deceleration_(ComputeDeceleration(fling_friction_)),
+ tuning_coeff_(ComputeDeceleration(0.84f)) {}
+
+Scroller::~Scroller() {}
+
+void Scroller::StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time) {
+ StartScroll(start_x,
+ start_y,
+ dx,
+ dy,
+ start_time,
+ base::TimeDelta::FromMilliseconds(kDefaultDurationMs));
+}
+
+void Scroller::StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time,
+ base::TimeDelta duration) {
+ mode_ = SCROLL_MODE;
+ finished_ = false;
+ duration_ = duration;
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ start_time_ = start_time;
+ curr_x_ = start_x_ = start_x;
+ curr_y_ = start_y_ = start_y;
+ final_x_ = start_x + dx;
+ final_y_ = start_y + dy;
+ RecomputeDeltas();
+ curr_time_ = start_time_;
+}
+
+void Scroller::Fling(float start_x,
+ float start_y,
+ float velocity_x,
+ float velocity_y,
+ float min_x,
+ float max_x,
+ float min_y,
+ float max_y,
+ base::TimeTicks start_time) {
+ // Continue a scroll or fling in progress.
+ if (flywheel_enabled_ && !finished_) {
+ float old_velocity_x = GetCurrVelocityX();
+ float old_velocity_y = GetCurrVelocityY();
+ if (Signum(velocity_x) == Signum(old_velocity_x) &&
+ Signum(velocity_y) == Signum(old_velocity_y)) {
+ velocity_x += old_velocity_x;
+ velocity_y += old_velocity_y;
+ }
+ }
+
+ mode_ = FLING_MODE;
+ finished_ = false;
+
+ float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y);
+
+ velocity_ = velocity;
+ duration_ = GetSplineFlingDuration(velocity);
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ start_time_ = start_time;
+ curr_time_ = start_time_;
+ curr_x_ = start_x_ = start_x;
+ curr_y_ = start_y_ = start_y;
+
+ float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity;
+ float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity;
+
+ double total_distance = GetSplineFlingDistance(velocity);
+ distance_ = total_distance * Signum(velocity);
+
+ min_x_ = min_x;
+ max_x_ = max_x;
+ min_y_ = min_y;
+ max_y_ = max_y;
+
+ final_x_ = start_x + total_distance * coeff_x;
+ final_x_ = Clamped(final_x_, min_x_, max_x_);
+
+ final_y_ = start_y + total_distance * coeff_y;
+ final_y_ = Clamped(final_y_, min_y_, max_y_);
+
+ RecomputeDeltas();
+}
+
+bool Scroller::ComputeScrollOffset(base::TimeTicks time) {
+ if (finished_)
+ return false;
+
+ if (time == curr_time_)
+ return true;
+
+ base::TimeDelta time_passed = time - start_time_;
+
+ if (time_passed < base::TimeDelta()) {
+ time_passed = base::TimeDelta();
+ }
+
+ if (time_passed >= duration_) {
+ curr_x_ = final_x_;
+ curr_y_ = final_y_;
+ curr_time_ = start_time_ + duration_;
+ finished_ = true;
+ return true;
+ }
+
+ curr_time_ = time;
+
+ const float t = time_passed.InSecondsF() * duration_seconds_reciprocal_;
+
+ switch (mode_) {
+ case UNDEFINED:
+ NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
+ "scroll offset computation.";
+ return false;
+
+ case SCROLL_MODE: {
+ float x = g_viscosity_constants.Get().ApplyViscosity(t);
+
+ curr_x_ = start_x_ + x * delta_x_;
+ curr_y_ = start_y_ + x * delta_y_;
+ } break;
+
+ case FLING_MODE: {
+ float distance_coef = 1.f;
+ float velocity_coef = 0.f;
+ g_spline_constants.Get().CalculateCoefficients(
+ t, &distance_coef, &velocity_coef);
+
+ curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
+
+ curr_x_ = start_x_ + distance_coef * delta_x_;
+ curr_x_ = Clamped(curr_x_, min_x_, max_x_);
+
+ curr_y_ = start_y_ + distance_coef * delta_y_;
+ curr_y_ = Clamped(curr_y_, min_y_, max_y_);
+
+ if (ApproxEquals(curr_x_, final_x_) && ApproxEquals(curr_y_, final_y_)) {
+ finished_ = true;
+ }
+ } break;
+ }
+
+ return true;
+}
+
+void Scroller::ExtendDuration(base::TimeDelta extend) {
+ base::TimeDelta passed = GetTimePassed();
+ duration_ = passed + extend;
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ finished_ = false;
+}
+
+void Scroller::SetFinalX(float new_x) {
+ final_x_ = new_x;
+ finished_ = false;
+ RecomputeDeltas();
+}
+
+void Scroller::SetFinalY(float new_y) {
+ final_y_ = new_y;
+ finished_ = false;
+ RecomputeDeltas();
+}
+
+void Scroller::AbortAnimation() {
+ curr_x_ = final_x_;
+ curr_y_ = final_y_;
+ curr_velocity_ = 0;
+ curr_time_ = start_time_ + duration_;
+ finished_ = true;
+}
+
+void Scroller::ForceFinished(bool finished) { finished_ = finished; }
+
+bool Scroller::IsFinished() const { return finished_; }
+
+base::TimeDelta Scroller::GetTimePassed() const {
+ return curr_time_ - start_time_;
+}
+
+base::TimeDelta Scroller::GetDuration() const { return duration_; }
+
+float Scroller::GetCurrX() const { return curr_x_; }
+
+float Scroller::GetCurrY() const { return curr_y_; }
+
+float Scroller::GetCurrVelocity() const {
+ if (finished_)
+ return 0;
+ if (mode_ == FLING_MODE)
+ return curr_velocity_;
+ return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f;
+}
+
+float Scroller::GetCurrVelocityX() const {
+ return delta_x_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetCurrVelocityY() const {
+ return delta_y_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetStartX() const { return start_x_; }
+
+float Scroller::GetStartY() const { return start_y_; }
+
+float Scroller::GetFinalX() const { return final_x_; }
+
+float Scroller::GetFinalY() const { return final_y_; }
+
+bool Scroller::IsScrollingInDirection(float xvel, float yvel) const {
+ return !finished_ && Signum(xvel) == Signum(delta_x_) &&
+ Signum(yvel) == Signum(delta_y_);
+}
+
+void Scroller::RecomputeDeltas() {
+ delta_x_ = final_x_ - start_x_;
+ delta_y_ = final_y_ - start_y_;
+
+ const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_);
+ if (hyp > kEpsilon) {
+ delta_x_norm_ = delta_x_ / hyp;
+ delta_y_norm_ = delta_y_ / hyp;
+ } else {
+ delta_x_norm_ = delta_y_norm_ = 1;
+ }
+}
+
+double Scroller::GetSplineDeceleration(float velocity) const {
+ return std::log(kInflexion * std::abs(velocity) /
+ (fling_friction_ * tuning_coeff_));
+}
+
+base::TimeDelta Scroller::GetSplineFlingDuration(float velocity) const {
+ const double l = GetSplineDeceleration(velocity);
+ const double decel_minus_one = kDecelerationRate - 1.0;
+ const double time_seconds = std::exp(l / decel_minus_one);
+ return base::TimeDelta::FromMicroseconds(time_seconds *
+ base::Time::kMicrosecondsPerSecond);
+}
+
+double Scroller::GetSplineFlingDistance(float velocity) const {
+ const double l = GetSplineDeceleration(velocity);
+ const double decel_minus_one = kDecelerationRate - 1.0;
+ return fling_friction_ * tuning_coeff_ *
+ std::exp(kDecelerationRate / decel_minus_one * l);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/android/scroller.h b/chromium/ui/gfx/android/scroller.h
new file mode 100644
index 00000000000..39d7255dc87
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller.h
@@ -0,0 +1,148 @@
+// 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_GFX_ANDROID_SCROLLER_H_
+#define UI_GFX_ANDROID_SCROLLER_H_
+
+#include "base/time/time.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Native port of android.widget.Scroller.
+// * Change-Id: I4365946f890a76fcfa78ca9d69f2a8e0848095a9
+// * Please update the Change-Id as upstream Android changes are pulled.
+class GFX_EXPORT Scroller {
+ public:
+ struct Config {
+ Config();
+
+ // Controls fling deceleration. Defaults to 0.015f.
+ float fling_friction;
+
+ // Controls fling accumulation. Defaults to disabled.
+ bool flywheel_enabled;
+ };
+
+ explicit Scroller(const Config& config);
+ ~Scroller();
+
+ // Start scrolling by providing a starting point and the distance to travel.
+ // The default value of 250 milliseconds will be used for the duration.
+ void StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time);
+
+ // Start scrolling by providing a starting point, the distance to travel,
+ // and the duration of the scroll.
+ void StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time,
+ base::TimeDelta duration);
+
+ // Start scrolling based on a fling gesture. The distance travelled will
+ // depend on the initial velocity of the fling.
+ void Fling(float start_x,
+ float start_y,
+ float velocity_x,
+ float velocity_y,
+ float min_x,
+ float max_x,
+ float min_y,
+ float max_y,
+ base::TimeTicks start_time);
+
+ // Call this when you want to know the new location. If it returns true,
+ // the animation is not yet finished.
+ bool ComputeScrollOffset(base::TimeTicks time);
+
+ // Extend the scroll animation by |extend|. This allows a running animation
+ // to scroll further and longer when used with |SetFinalX()| or |SetFinalY()|.
+ void ExtendDuration(base::TimeDelta extend);
+ void SetFinalX(float new_x);
+ void SetFinalY(float new_y);
+
+ // Stops the animation. Contrary to |ForceFinished()|, aborting the animation
+ // causes the scroller to move to the final x and y position.
+ void AbortAnimation();
+
+ // Terminate the scroll without affecting the current x and y positions.
+ void ForceFinished(bool finished);
+
+ // Returns whether the scroller has finished scrolling.
+ bool IsFinished() const;
+
+ // Returns the time elapsed since the beginning of the scrolling.
+ base::TimeDelta GetTimePassed() const;
+
+ // Returns how long the scroll event will take.
+ base::TimeDelta GetDuration() const;
+
+ float GetStartX() const;
+ float GetStartY() const;
+ float GetCurrX() const;
+ float GetCurrY() const;
+ float GetCurrVelocity() const;
+ float GetCurrVelocityX() const;
+ float GetCurrVelocityY() const;
+ float GetFinalX() const;
+ float GetFinalY() const;
+
+ bool IsScrollingInDirection(float xvel, float yvel) const;
+
+ private:
+ enum Mode {
+ UNDEFINED,
+ SCROLL_MODE,
+ FLING_MODE,
+ };
+
+ void OnDurationChanged();
+ void RecomputeDeltas();
+
+ double GetSplineDeceleration(float velocity) const;
+ base::TimeDelta GetSplineFlingDuration(float velocity) const;
+ double GetSplineFlingDistance(float velocity) const;
+
+ Mode mode_;
+
+ float start_x_;
+ float start_y_;
+ float final_x_;
+ float final_y_;
+
+ float min_x_;
+ float max_x_;
+ float min_y_;
+ float max_y_;
+
+ float curr_x_;
+ float curr_y_;
+ base::TimeTicks start_time_;
+ base::TimeTicks curr_time_;
+ base::TimeDelta duration_;
+ double duration_seconds_reciprocal_;
+ float delta_x_;
+ float delta_x_norm_;
+ float delta_y_;
+ float delta_y_norm_;
+ bool finished_;
+ bool flywheel_enabled_;
+
+ float velocity_;
+ float curr_velocity_;
+ float distance_;
+
+ float fling_friction_;
+ float deceleration_;
+ float tuning_coeff_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANDROID_SCROLLER_H_
diff --git a/chromium/ui/gfx/android/scroller_unittest.cc b/chromium/ui/gfx/android/scroller_unittest.cc
new file mode 100644
index 00000000000..9b1018d6ab9
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/android/scroller.h"
+
+namespace gfx {
+
+namespace {
+
+const float kDefaultStartX = 7.f;
+const float kDefaultStartY = 25.f;
+const float kDefaultDeltaX = -20.f;
+const float kDefaultDeltaY = 73.f;
+const float kDefaultVelocityX = -35.f;
+const float kDefaultVelocityY = 22.f;
+const float kEpsilon = 1e-3f;
+
+Scroller::Config DefaultConfig() {
+ return Scroller::Config();
+}
+
+} // namespace
+
+class ScrollerTest : public testing::Test {};
+
+TEST_F(ScrollerTest, Scroll) {
+ Scroller scroller(DefaultConfig());
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ // Start a scroll and verify initialized values.
+ scroller.StartScroll(kDefaultStartX,
+ kDefaultStartY,
+ kDefaultDeltaX,
+ kDefaultDeltaY,
+ start_time);
+
+ EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+ EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_EQ(kDefaultStartX + kDefaultDeltaX, scroller.GetFinalX());
+ EXPECT_EQ(kDefaultStartY + kDefaultDeltaY, scroller.GetFinalY());
+ EXPECT_FALSE(scroller.IsFinished());
+ EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+ // Advance halfway through the scroll.
+ const base::TimeDelta scroll_duration = scroller.GetDuration();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+
+ // Ensure we've moved in the direction of the delta, but have yet to reach
+ // the target.
+ EXPECT_GT(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_LT(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_LT(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_GT(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_FALSE(scroller.IsFinished());
+
+ // Ensure our velocity is non-zero and in the same direction as the delta.
+ EXPECT_GT(0.f, scroller.GetCurrVelocityX() * kDefaultDeltaX);
+ EXPECT_GT(0.f, scroller.GetCurrVelocityY() * kDefaultDeltaY);
+ EXPECT_TRUE(scroller.IsScrollingInDirection(kDefaultDeltaX, kDefaultDeltaY));
+
+ // Repeated offset computations at the same timestamp should yield identical
+ // results.
+ float curr_x = scroller.GetCurrX();
+ float curr_y = scroller.GetCurrY();
+ float curr_velocity_x = scroller.GetCurrVelocityX();
+ float curr_velocity_y = scroller.GetCurrVelocityY();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+ EXPECT_EQ(curr_x, scroller.GetCurrX());
+ EXPECT_EQ(curr_y, scroller.GetCurrY());
+ EXPECT_EQ(curr_velocity_x, scroller.GetCurrVelocityX());
+ EXPECT_EQ(curr_velocity_y, scroller.GetCurrVelocityY());
+
+ // Advance to the end.
+ scroller.ComputeScrollOffset(start_time + scroll_duration);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityX(), kEpsilon);
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityY(), kEpsilon);
+
+ // Try to advance further; nothing should change.
+ scroller.ComputeScrollOffset(start_time + scroll_duration * 2);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+TEST_F(ScrollerTest, Fling) {
+ Scroller scroller(DefaultConfig());
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ // Start a fling and verify initialized values.
+ scroller.Fling(kDefaultStartX,
+ kDefaultStartY,
+ kDefaultVelocityX,
+ kDefaultVelocityY,
+ INT_MIN,
+ INT_MAX,
+ INT_MIN,
+ INT_MAX,
+ start_time);
+
+ EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+ EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_GT(kDefaultStartX, scroller.GetFinalX());
+ EXPECT_LT(kDefaultStartY, scroller.GetFinalY());
+ EXPECT_FALSE(scroller.IsFinished());
+ EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+ // Advance halfway through the fling.
+ const base::TimeDelta scroll_duration = scroller.GetDuration();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+
+ // Ensure we've moved in the direction of the velocity, but have yet to reach
+ // the target.
+ EXPECT_GT(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_LT(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_LT(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_GT(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_FALSE(scroller.IsFinished());
+
+ // Ensure our velocity is non-zero and in the same direction as the original
+ // velocity.
+ EXPECT_LT(0.f, scroller.GetCurrVelocityX() * kDefaultVelocityX);
+ EXPECT_LT(0.f, scroller.GetCurrVelocityY() * kDefaultVelocityY);
+ EXPECT_TRUE(
+ scroller.IsScrollingInDirection(kDefaultVelocityX, kDefaultVelocityY));
+
+ // Repeated offset computations at the same timestamp should yield identical
+ // results.
+ float curr_x = scroller.GetCurrX();
+ float curr_y = scroller.GetCurrY();
+ float curr_velocity_x = scroller.GetCurrVelocityX();
+ float curr_velocity_y = scroller.GetCurrVelocityY();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+ EXPECT_EQ(curr_x, scroller.GetCurrX());
+ EXPECT_EQ(curr_y, scroller.GetCurrY());
+ EXPECT_EQ(curr_velocity_x, scroller.GetCurrVelocityX());
+ EXPECT_EQ(curr_velocity_y, scroller.GetCurrVelocityY());
+
+ // Advance to the end.
+ scroller.ComputeScrollOffset(start_time + scroll_duration);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityX(), kEpsilon);
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityY(), kEpsilon);
+
+ // Try to advance further; nothing should change.
+ scroller.ComputeScrollOffset(start_time + scroll_duration * 2);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/android/shared_device_display_info.cc b/chromium/ui/gfx/android/shared_device_display_info.cc
index 9ac18d0218d..c58813dfcef 100644
--- a/chromium/ui/gfx/android/shared_device_display_info.cc
+++ b/chromium/ui/gfx/android/shared_device_display_info.cc
@@ -16,13 +16,18 @@ static void UpdateSharedDeviceDisplayInfo(JNIEnv* env,
jobject obj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
SharedDeviceDisplayInfo::GetInstance()->InvokeUpdate(env, obj,
- display_height, display_width, bits_per_pixel, bits_per_component,
- dip_scale, smallest_dip_width);
+ display_height, display_width,
+ physical_display_height, physical_display_width,
+ bits_per_pixel, bits_per_component,
+ dip_scale, smallest_dip_width, rotation_degrees);
}
// static
@@ -42,6 +47,16 @@ int SharedDeviceDisplayInfo::GetDisplayWidth() {
return display_width_;
}
+int SharedDeviceDisplayInfo::GetPhysicalDisplayHeight() {
+ base::AutoLock autolock(lock_);
+ return physical_display_height_;
+}
+
+int SharedDeviceDisplayInfo::GetPhysicalDisplayWidth() {
+ base::AutoLock autolock(lock_);
+ return physical_display_width_;
+}
+
int SharedDeviceDisplayInfo::GetBitsPerPixel() {
base::AutoLock autolock(lock_);
DCHECK_NE(0, bits_per_pixel_);
@@ -66,6 +81,11 @@ int SharedDeviceDisplayInfo::GetSmallestDIPWidth() {
return smallest_dip_width_;
}
+int SharedDeviceDisplayInfo::GetRotationDegrees() {
+ base::AutoLock autolock(lock_);
+ return rotation_degrees_;
+}
+
// static
bool SharedDeviceDisplayInfo::RegisterSharedDeviceDisplayInfo(JNIEnv* env) {
return RegisterNativesImpl(env);
@@ -75,15 +95,20 @@ void SharedDeviceDisplayInfo::InvokeUpdate(JNIEnv* env,
jobject obj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
base::AutoLock autolock(lock_);
- UpdateDisplayInfo(env, obj, display_height,
- display_width, bits_per_pixel, bits_per_component, dip_scale,
- smallest_dip_width);
+ UpdateDisplayInfo(env, obj,
+ display_height, display_width,
+ physical_display_height, physical_display_width,
+ bits_per_pixel, bits_per_component, dip_scale,
+ smallest_dip_width, rotation_degrees);
}
SharedDeviceDisplayInfo::SharedDeviceDisplayInfo()
@@ -95,15 +120,19 @@ SharedDeviceDisplayInfo::SharedDeviceDisplayInfo()
smallest_dip_width_(0) {
JNIEnv* env = base::android::AttachCurrentThread();
j_device_info_.Reset(
- Java_DeviceDisplayInfo_createWithListener(env,
- base::android::GetApplicationContext()));
+ Java_DeviceDisplayInfo_create(
+ env, base::android::GetApplicationContext()));
UpdateDisplayInfo(env, j_device_info_.obj(),
Java_DeviceDisplayInfo_getDisplayHeight(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getDisplayWidth(env, j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getPhysicalDisplayHeight(env,
+ j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getPhysicalDisplayWidth(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getBitsPerPixel(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getBitsPerComponent(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getDIPScale(env, j_device_info_.obj()),
- Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj()));
+ Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getRotationDegrees(env, j_device_info_.obj()));
}
SharedDeviceDisplayInfo::~SharedDeviceDisplayInfo() {
@@ -113,16 +142,22 @@ void SharedDeviceDisplayInfo::UpdateDisplayInfo(JNIEnv* env,
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
display_height_ = static_cast<int>(display_height);
display_width_ = static_cast<int>(display_width);
+ physical_display_height_ = static_cast<int>(physical_display_height);
+ physical_display_width_ = static_cast<int>(physical_display_width);
bits_per_pixel_ = static_cast<int>(bits_per_pixel);
bits_per_component_ = static_cast<int>(bits_per_component);
dip_scale_ = static_cast<double>(dip_scale);
smallest_dip_width_ = static_cast<int>(smallest_dip_width);
+ rotation_degrees_ = static_cast<int>(rotation_degrees);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/android/shared_device_display_info.h b/chromium/ui/gfx/android/shared_device_display_info.h
index 1e1fc0c6662..e6983e58aa3 100644
--- a/chromium/ui/gfx/android/shared_device_display_info.h
+++ b/chromium/ui/gfx/android/shared_device_display_info.h
@@ -18,12 +18,16 @@ class SharedDeviceDisplayInfo {
public:
static SharedDeviceDisplayInfo* GetInstance();
+ // See documentation in DeviceDisplayInfo.java
int GetDisplayHeight();
int GetDisplayWidth();
+ int GetPhysicalDisplayHeight();
+ int GetPhysicalDisplayWidth();
int GetBitsPerPixel();
int GetBitsPerComponent();
double GetDIPScale();
int GetSmallestDIPWidth();
+ int GetRotationDegrees();
// Registers methods with JNI and returns true if succeeded.
static bool RegisterSharedDeviceDisplayInfo(JNIEnv* env);
@@ -32,10 +36,13 @@ class SharedDeviceDisplayInfo {
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width);
+ jint smallest_dip_width,
+ jint rotation_degrees);
private:
friend struct DefaultSingletonTraits<SharedDeviceDisplayInfo>;
@@ -45,20 +52,26 @@ class SharedDeviceDisplayInfo {
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width);
+ jint smallest_dip_width,
+ jint rotation_degrees);
base::Lock lock_;
base::android::ScopedJavaGlobalRef<jobject> j_device_info_;
int display_height_;
int display_width_;
+ int physical_display_height_;
+ int physical_display_width_;
int bits_per_pixel_;
int bits_per_component_;
double dip_scale_;
int smallest_dip_width_;
+ int rotation_degrees_;
DISALLOW_COPY_AND_ASSIGN(SharedDeviceDisplayInfo);
};
diff --git a/chromium/ui/gfx/android/view_configuration.cc b/chromium/ui/gfx/android/view_configuration.cc
index 63657178b15..16c8617ed6b 100644
--- a/chromium/ui/gfx/android/view_configuration.cc
+++ b/chromium/ui/gfx/android/view_configuration.cc
@@ -1,52 +1,206 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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/gfx/android/view_configuration.h"
#include "base/android/jni_android.h"
-#include "jni/ViewConfiguration_jni.h"
+#include "base/lazy_instance.h"
+#include "base/threading/non_thread_safe.h"
+#include "jni/ViewConfigurationHelper_jni.h"
-using namespace JNI_ViewConfiguration;
using base::android::AttachCurrentThread;
using base::android::GetApplicationContext;
namespace gfx {
+namespace {
+
+struct ViewConfigurationData {
+ ViewConfigurationData()
+ : double_tap_timeout_in_ms_(0),
+ long_press_timeout_in_ms_(0),
+ tap_timeout_in_ms_(0),
+ scroll_friction_(1.f),
+ max_fling_velocity_in_pixels_s_(0),
+ min_fling_velocity_in_pixels_s_(0),
+ touch_slop_in_pixels_(0),
+ double_tap_slop_in_pixels_(0),
+ min_scaling_span_in_pixels_(0),
+ min_scaling_touch_major_in_pixels_(0) {
+ JNIEnv* env = AttachCurrentThread();
+ j_view_configuration_helper_.Reset(
+ Java_ViewConfigurationHelper_createWithListener(
+ env, base::android::GetApplicationContext()));
+
+ double_tap_timeout_in_ms_ =
+ Java_ViewConfigurationHelper_getDoubleTapTimeout(env);
+ long_press_timeout_in_ms_ =
+ Java_ViewConfigurationHelper_getLongPressTimeout(env);
+ tap_timeout_in_ms_ = Java_ViewConfigurationHelper_getTapTimeout(env);
+ scroll_friction_ = Java_ViewConfigurationHelper_getScrollFriction(env);
+
+ jobject obj = j_view_configuration_helper_.obj();
+ Update(
+ Java_ViewConfigurationHelper_getScaledMaximumFlingVelocity(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinimumFlingVelocity(env, obj),
+ Java_ViewConfigurationHelper_getScaledTouchSlop(env, obj),
+ Java_ViewConfigurationHelper_getScaledDoubleTapSlop(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinScalingSpan(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinScalingTouchMajor(env, obj));
+ }
+
+ ~ViewConfigurationData() {}
+
+ void SynchronizedUpdate(int scaled_maximum_fling_velocity,
+ int scaled_minimum_fling_velocity,
+ int scaled_touch_slop,
+ int scaled_double_tap_slop,
+ int scaled_min_scaling_span,
+ int scaled_min_scaling_touch_major) {
+ base::AutoLock autolock(lock_);
+ Update(scaled_maximum_fling_velocity,
+ scaled_minimum_fling_velocity,
+ scaled_touch_slop,
+ scaled_double_tap_slop,
+ scaled_min_scaling_span,
+ scaled_min_scaling_touch_major);
+ }
+
+ int double_tap_timeout_in_ms() const { return double_tap_timeout_in_ms_; }
+ int long_press_timeout_in_ms() const { return long_press_timeout_in_ms_; }
+ int tap_timeout_in_ms() const { return tap_timeout_in_ms_; }
+ float scroll_friction() const { return scroll_friction_; }
+
+ int max_fling_velocity_in_pixels_s() {
+ base::AutoLock autolock(lock_);
+ return max_fling_velocity_in_pixels_s_;
+ }
+
+ int min_fling_velocity_in_pixels_s() {
+ base::AutoLock autolock(lock_);
+ return min_fling_velocity_in_pixels_s_;
+ }
+
+ int touch_slop_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return touch_slop_in_pixels_;
+ }
+
+ int double_tap_slop_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return double_tap_slop_in_pixels_;
+ }
+
+ int min_scaling_span_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return min_scaling_span_in_pixels_;
+ }
+
+ int min_scaling_touch_major_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return min_scaling_touch_major_in_pixels_;
+ }
+
+ private:
+ void Update(int scaled_maximum_fling_velocity,
+ int scaled_minimum_fling_velocity,
+ int scaled_touch_slop,
+ int scaled_double_tap_slop,
+ int scaled_min_scaling_span,
+ int scaled_min_scaling_touch_major) {
+ DCHECK_LE(scaled_minimum_fling_velocity, scaled_maximum_fling_velocity);
+ max_fling_velocity_in_pixels_s_ = scaled_maximum_fling_velocity;
+ min_fling_velocity_in_pixels_s_ = scaled_minimum_fling_velocity;
+ touch_slop_in_pixels_ = scaled_touch_slop;
+ double_tap_slop_in_pixels_ = scaled_double_tap_slop;
+ min_scaling_span_in_pixels_ = scaled_min_scaling_span;
+ min_scaling_touch_major_in_pixels_ = scaled_min_scaling_touch_major;
+ }
+
+ base::Lock lock_;
+ base::android::ScopedJavaGlobalRef<jobject> j_view_configuration_helper_;
+
+ // These values will remain constant throughout the lifetime of the app, so
+ // read-access needn't be synchronized.
+ int double_tap_timeout_in_ms_;
+ int long_press_timeout_in_ms_;
+ int tap_timeout_in_ms_;
+ float scroll_friction_;
+
+ // These values may vary as view-specific parameters (DPI scale) are changed,
+ // so read/write access must be synchronized.
+ int max_fling_velocity_in_pixels_s_;
+ int min_fling_velocity_in_pixels_s_;
+ int touch_slop_in_pixels_;
+ int double_tap_slop_in_pixels_;
+ int min_scaling_span_in_pixels_;
+ int min_scaling_touch_major_in_pixels_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ViewConfigurationData);
+};
+
+// Leaky to allow access from any thread.
+base::LazyInstance<ViewConfigurationData>::Leaky g_view_configuration =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+static void UpdateSharedViewConfiguration(JNIEnv* env,
+ jobject obj,
+ jint scaled_maximum_fling_velocity,
+ jint scaled_minimum_fling_velocity,
+ jint scaled_touch_slop,
+ jint scaled_double_tap_slop,
+ jint scaled_min_scaling_span,
+ jint scaled_min_scaling_touch_major) {
+ g_view_configuration.Get().SynchronizedUpdate(scaled_maximum_fling_velocity,
+ scaled_minimum_fling_velocity,
+ scaled_touch_slop,
+ scaled_double_tap_slop,
+ scaled_min_scaling_span,
+ scaled_min_scaling_touch_major);
+}
+
int ViewConfiguration::GetDoubleTapTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getDoubleTapTimeout(env);
+ return g_view_configuration.Get().double_tap_timeout_in_ms();
}
int ViewConfiguration::GetLongPressTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getLongPressTimeout(env);
+ return g_view_configuration.Get().long_press_timeout_in_ms();
}
int ViewConfiguration::GetTapTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getTapTimeout(env);
+ return g_view_configuration.Get().tap_timeout_in_ms();
+}
+
+float ViewConfiguration::GetScrollFriction() {
+ return g_view_configuration.Get().scroll_friction();
}
int ViewConfiguration::GetMaximumFlingVelocityInPixelsPerSecond() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledMaximumFlingVelocity(env, view.obj());
+ return g_view_configuration.Get().max_fling_velocity_in_pixels_s();
}
int ViewConfiguration::GetMinimumFlingVelocityInPixelsPerSecond() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledMinimumFlingVelocity(env, view.obj());
+ return g_view_configuration.Get().min_fling_velocity_in_pixels_s();
}
int ViewConfiguration::GetTouchSlopInPixels() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledTouchSlop(env, view.obj());
+ return g_view_configuration.Get().touch_slop_in_pixels();
+}
+
+int ViewConfiguration::GetDoubleTapSlopInPixels() {
+ return g_view_configuration.Get().double_tap_slop_in_pixels();
+}
+
+int ViewConfiguration::GetMinScalingSpanInPixels() {
+ return g_view_configuration.Get().min_scaling_span_in_pixels();
+}
+
+int ViewConfiguration::GetMinScalingTouchMajorInPixels() {
+ return g_view_configuration.Get().min_scaling_touch_major_in_pixels();
}
bool ViewConfiguration::RegisterViewConfiguration(JNIEnv* env) {
diff --git a/chromium/ui/gfx/android/view_configuration.h b/chromium/ui/gfx/android/view_configuration.h
index f0995cb3e29..4595071c4f1 100644
--- a/chromium/ui/gfx/android/view_configuration.h
+++ b/chromium/ui/gfx/android/view_configuration.h
@@ -12,16 +12,24 @@
namespace gfx {
// Provides access to Android's ViewConfiguration for gesture-related constants.
+// Note: All methods may be safely called from any thread.
class GFX_EXPORT ViewConfiguration {
public:
static int GetDoubleTapTimeoutInMs();
static int GetLongPressTimeoutInMs();
static int GetTapTimeoutInMs();
+ // Dimensionless coefficient of friction.
+ static float GetScrollFriction();
+
static int GetMaximumFlingVelocityInPixelsPerSecond();
static int GetMinimumFlingVelocityInPixelsPerSecond();
static int GetTouchSlopInPixels();
+ static int GetDoubleTapSlopInPixels();
+
+ static int GetMinScalingSpanInPixels();
+ static int GetMinScalingTouchMajorInPixels();
// Registers methods with JNI and returns true if succeeded.
static bool RegisterViewConfiguration(JNIEnv* env);
diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc
index 3b525f22f00..fce72e8fce5 100644
--- a/chromium/ui/gfx/animation/animation.cc
+++ b/chromium/ui/gfx/animation/animation.cc
@@ -106,8 +106,9 @@ bool Animation::ShouldRenderRichAnimation() {
}
}
return !::GetSystemMetrics(SM_REMOTESESSION);
-#endif
+#else
return true;
+#endif
}
bool Animation::ShouldSendCanceledFromStop() {
diff --git a/chromium/ui/gfx/animation/animation_delegate.h b/chromium/ui/gfx/animation/animation_delegate.h
index 94303ddd93a..b1e88d2fdac 100644
--- a/chromium/ui/gfx/animation/animation_delegate.h
+++ b/chromium/ui/gfx/animation/animation_delegate.h
@@ -17,6 +17,8 @@ class Animation;
// state of an animation.
class GFX_EXPORT AnimationDelegate {
public:
+ virtual ~AnimationDelegate() {}
+
// Called when an animation has completed.
virtual void AnimationEnded(const Animation* animation) {}
@@ -25,9 +27,6 @@ class GFX_EXPORT AnimationDelegate {
// Called when an animation has been canceled.
virtual void AnimationCanceled(const Animation* animation) {}
-
- protected:
- virtual ~AnimationDelegate() {}
};
} // namespace gfx
diff --git a/chromium/ui/gfx/animation/tween.cc b/chromium/ui/gfx/animation/tween.cc
index 174305078c2..483d772b5b4 100644
--- a/chromium/ui/gfx/animation/tween.cc
+++ b/chromium/ui/gfx/animation/tween.cc
@@ -14,6 +14,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "ui/gfx/geometry/cubic_bezier.h"
#include "ui/gfx/safe_integer_conversions.h"
namespace gfx {
@@ -51,6 +52,15 @@ double Tween::CalculateValue(Tween::Type type, double state) {
case SMOOTH_IN_OUT:
return sin(state);
+ case FAST_OUT_SLOW_IN:
+ return gfx::CubicBezier(0.4, 0, 0.2, 1).Solve(state);
+
+ case LINEAR_OUT_SLOW_IN:
+ return gfx::CubicBezier(0, 0, .2, 1).Solve(state);
+
+ case FAST_OUT_LINEAR_IN:
+ return gfx::CubicBezier(0.4, 0, 1, 1).Solve(state);
+
case ZERO:
return 0;
}
diff --git a/chromium/ui/gfx/animation/tween.h b/chromium/ui/gfx/animation/tween.h
index 04f353db1ae..8b079ac73cb 100644
--- a/chromium/ui/gfx/animation/tween.h
+++ b/chromium/ui/gfx/animation/tween.h
@@ -16,15 +16,22 @@ namespace gfx {
class GFX_EXPORT Tween {
public:
enum Type {
- LINEAR, // Linear.
- EASE_OUT, // Fast in, slow out (default).
- EASE_IN, // Slow in, fast out.
- EASE_IN_2, // Variant of EASE_IN that starts out slower.
- EASE_IN_OUT, // Slow in and out, fast in the middle.
- FAST_IN_OUT, // Fast in and out, slow in the middle.
- EASE_OUT_SNAP, // Fast in, slow out, snap to final value.
- SMOOTH_IN_OUT, // Smooth, consistent speeds in and out (sine wave).
- ZERO, // Returns a value of 0 always.
+ LINEAR, // Linear.
+ EASE_OUT, // Fast in, slow out (default).
+ EASE_IN, // Slow in, fast out.
+ EASE_IN_2, // Variant of EASE_IN that starts out slower than
+ // EASE_IN.
+ EASE_IN_OUT, // Slow in and out, fast in the middle.
+ FAST_IN_OUT, // Fast in and out, slow in the middle.
+ EASE_OUT_SNAP, // Fast in, slow out, snap to final value.
+ SMOOTH_IN_OUT, // Smooth, consistent speeds in and out (sine wave).
+ FAST_OUT_SLOW_IN, // Variant of EASE_IN_OUT which should be used in most
+ // cases.
+ LINEAR_OUT_SLOW_IN, // Variant of EASE_OUT which should be used for
+ // fading in from 0% or motion when entering a scene.
+ FAST_OUT_LINEAR_IN, // Variant of EASE_IN which should should be used for
+ // fading out to 0% or motion when exiting a scene.
+ ZERO, // Returns a value of 0 always.
};
// Returns the value based on the tween type. |state| is from 0-1.
diff --git a/chromium/ui/gfx/animation/tween_unittest.cc b/chromium/ui/gfx/animation/tween_unittest.cc
index d92fe1bacc4..f71a77dccbd 100644
--- a/chromium/ui/gfx/animation/tween_unittest.cc
+++ b/chromium/ui/gfx/animation/tween_unittest.cc
@@ -11,16 +11,19 @@
#endif
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/test/color_util.h"
+#include "ui/gfx/test/gfx_util.h"
namespace gfx {
namespace {
double next_double(double d) {
#if defined(OS_WIN)
- return _nextafter(d, d+1);
+ return _nextafter(d, d + 1);
#else
- return nextafter(d, d+1);
+ // Step two units of least precision towards positive infinity. On some 32
+ // bit x86 compilers a single step was not enough due to loss of precision in
+ // optimized code.
+ return nextafter(nextafter(d, d + 1), d + 1);
#endif
}
diff --git a/chromium/ui/gfx/blit.cc b/chromium/ui/gfx/blit.cc
index 4b87bc9aac5..653c56bda7f 100644
--- a/chromium/ui/gfx/blit.cc
+++ b/chromium/ui/gfx/blit.cc
@@ -29,21 +29,28 @@ namespace {
// Returns true if the given canvas has any part of itself clipped out or
// any non-identity tranform.
-bool HasClipOrTransform(const SkCanvas& canvas) {
+bool HasClipOrTransform(SkCanvas& canvas) {
if (!canvas.getTotalMatrix().isIdentity())
return true;
- const SkRegion& clip_region = canvas.getTotalClip();
- if (clip_region.isEmpty() || clip_region.isComplex())
+ if (!canvas.isClipRect())
return true;
// Now we know the clip is a regular rectangle, make sure it covers the
// entire canvas.
- const SkBitmap& bitmap = skia::GetTopDevice(canvas)->accessBitmap(false);
- const SkIRect& clip_bounds = clip_region.getBounds();
+ SkIRect clip_bounds;
+ canvas.getClipDeviceBounds(&clip_bounds);
+
+ SkImageInfo info;
+ size_t row_bytes;
+ void* pixels = canvas.accessTopLayerPixels(&info, &row_bytes);
+ DCHECK(pixels);
+ if (!pixels)
+ return true;
+
if (clip_bounds.fLeft != 0 || clip_bounds.fTop != 0 ||
- clip_bounds.fRight != bitmap.width() ||
- clip_bounds.fBottom != bitmap.height())
+ clip_bounds.fRight != info.width() ||
+ clip_bounds.fBottom != info.height())
return true;
return false;
diff --git a/chromium/ui/gfx/box_f.cc b/chromium/ui/gfx/box_f.cc
deleted file mode 100644
index 62e755bdc3e..00000000000
--- a/chromium/ui/gfx/box_f.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/box_f.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-std::string BoxF::ToString() const {
- return base::StringPrintf("%s %fx%fx%f",
- origin().ToString().c_str(),
- width_,
- height_,
- depth_);
-}
-
-bool BoxF::IsEmpty() const {
- return (width_ == 0 && height_ == 0) ||
- (width_ == 0 && depth_ == 0) ||
- (height_ == 0 && depth_ == 0);
-}
-
-void BoxF::ExpandTo(const Point3F& min, const Point3F& max) {
- DCHECK_LE(min.x(), max.x());
- DCHECK_LE(min.y(), max.y());
- DCHECK_LE(min.z(), max.z());
-
- float min_x = std::min(x(), min.x());
- float min_y = std::min(y(), min.y());
- float min_z = std::min(z(), min.z());
- float max_x = std::max(right(), max.x());
- float max_y = std::max(bottom(), max.y());
- float max_z = std::max(front(), max.z());
-
- origin_.SetPoint(min_x, min_y, min_z);
- width_ = max_x - min_x;
- height_ = max_y - min_y;
- depth_ = max_z - min_z;
-}
-
-void BoxF::Union(const BoxF& box) {
- if (IsEmpty()) {
- *this = box;
- return;
- }
- if (box.IsEmpty())
- return;
- ExpandTo(box);
-}
-
-void BoxF::ExpandTo(const Point3F& point) {
- ExpandTo(point, point);
-}
-
-void BoxF::ExpandTo(const BoxF& box) {
- ExpandTo(box.origin(), gfx::Point3F(box.right(), box.bottom(), box.front()));
-}
-
-BoxF UnionBoxes(const BoxF& a, const BoxF& b) {
- BoxF result = a;
- result.Union(b);
- return result;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/box_f.h b/chromium/ui/gfx/box_f.h
index 73e0972f662..47d822eb33f 100644
--- a/chromium/ui/gfx/box_f.h
+++ b/chromium/ui/gfx/box_f.h
@@ -2,159 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_BOX_F_H_
-#define UI_GFX_BOX_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/point3_f.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-// A 3d version of gfx::RectF, with the positive z-axis pointed towards
-// the camera.
-class GFX_EXPORT BoxF {
- public:
- BoxF()
- : width_(0.f),
- height_(0.f),
- depth_(0.f) {}
-
- BoxF(float width, float height, float depth)
- : width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- BoxF(float x, float y, float z, float width, float height, float depth)
- : origin_(x, y, z),
- width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- BoxF(const Point3F& origin, float width, float height, float depth)
- : origin_(origin),
- width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- ~BoxF() {}
-
- // Scales all three axes by the given scale.
- void Scale(float scale) {
- Scale(scale, scale, scale);
- }
-
- // Scales each axis by the corresponding given scale.
- void Scale(float x_scale, float y_scale, float z_scale) {
- origin_.Scale(x_scale, y_scale, z_scale);
- set_size(width_ * x_scale, height_ * y_scale, depth_ * z_scale);
- }
-
- // Moves the box by the specified distance in each dimension.
- void operator+=(const Vector3dF& offset) {
- origin_ += offset;
- }
-
- // Returns true if the box has no interior points.
- bool IsEmpty() const;
-
- // Computes the union of this box with the given box. The union is the
- // smallest box that contains both boxes.
- void Union(const BoxF& box);
-
- std::string ToString() const;
-
- float x() const { return origin_.x(); }
- void set_x(float x) { origin_.set_x(x); }
-
- float y() const { return origin_.y(); }
- void set_y(float y) { origin_.set_y(y); }
-
- float z() const { return origin_.z(); }
- void set_z(float z) { origin_.set_z(z); }
-
- float width() const { return width_; }
- void set_width(float width) { width_ = width < 0 ? 0 : width; }
-
- float height() const { return height_; }
- void set_height(float height) { height_ = height < 0 ? 0 : height; }
-
- float depth() const { return depth_; }
- void set_depth(float depth) { depth_ = depth < 0 ? 0 : depth; }
-
- float right() const { return x() + width(); }
- float bottom() const { return y() + height(); }
- float front() const { return z() + depth(); }
-
- void set_size(float width, float height, float depth) {
- width_ = width < 0 ? 0 : width;
- height_ = height < 0 ? 0 : height;
- depth_ = depth < 0 ? 0 : depth;
- }
-
- const Point3F& origin() const { return origin_; }
- void set_origin(const Point3F& origin) { origin_ = origin; }
-
- // Expands |this| to contain the given point, if necessary. Please note, even
- // if |this| is empty, after the function |this| will continue to contain its
- // |origin_|.
- void ExpandTo(const Point3F& point);
-
- // Expands |this| to contain the given box, if necessary. Please note, even
- // if |this| is empty, after the function |this| will continue to contain its
- // |origin_|.
- void ExpandTo(const BoxF& box);
-
- private:
- // Expands the box to contain the two given points. It is required that each
- // component of |min| is less than or equal to the corresponding component in
- // |max|. Precisely, what this function does is ensure that after the function
- // completes, |this| contains origin_, min, max, and origin_ + (width_,
- // height_, depth_), even if the box is empty. Emptiness checks are handled in
- // the public function Union.
- void ExpandTo(const Point3F& min, const Point3F& max);
-
- Point3F origin_;
- float width_;
- float height_;
- float depth_;
-};
-
-GFX_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b);
-
-inline BoxF ScaleBox(const BoxF& b,
- float x_scale,
- float y_scale,
- float z_scale) {
- return BoxF(b.x() * x_scale,
- b.y() * y_scale,
- b.z() * z_scale,
- b.width() * x_scale,
- b.height() * y_scale,
- b.depth() * z_scale);
-}
-
-inline BoxF ScaleBox(const BoxF& b, float scale) {
- return ScaleBox(b, scale, scale, scale);
-}
-
-inline bool operator==(const BoxF& a, const BoxF& b) {
- return a.origin() == b.origin() && a.width() == b.width() &&
- a.height() == b.height() && a.depth() == b.depth();
-}
-
-inline bool operator!=(const BoxF& a, const BoxF& b) {
- return !(a == b);
-}
-
-inline BoxF operator+(const BoxF& b, const Vector3dF& v) {
- return BoxF(b.x() + v.x(),
- b.y() + v.y(),
- b.z() + v.z(),
- b.width(),
- b.height(),
- b.depth());
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_BOX_F_H_
diff --git a/chromium/ui/gfx/box_unittest.cc b/chromium/ui/gfx/box_unittest.cc
deleted file mode 100644
index db894cae1cd..00000000000
--- a/chromium/ui/gfx/box_unittest.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/box_f.h"
-
-namespace gfx {
-
-TEST(BoxTest, Constructors) {
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).ToString(),
- BoxF().ToString());
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, -3.f, -5.f, -7.f).ToString(),
- BoxF().ToString());
-
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 3.f, 5.f, 7.f).ToString(),
- BoxF(3.f, 5.f, 7.f).ToString());
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).ToString(),
- BoxF(-3.f, -5.f, -7.f).ToString());
-
- EXPECT_EQ(BoxF(2.f, 4.f, 6.f, 3.f, 5.f, 7.f).ToString(),
- BoxF(Point3F(2.f, 4.f, 6.f), 3.f, 5.f, 7.f).ToString());
- EXPECT_EQ(BoxF(2.f, 4.f, 6.f, 0.f, 0.f, 0.f).ToString(),
- BoxF(Point3F(2.f, 4.f, 6.f), -3.f, -5.f, -7.f).ToString());
-}
-
-TEST(BoxTest, IsEmpty) {
- EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).IsEmpty());
- EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 0.f, 0.f).IsEmpty());
-
- EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 2.f, 0.f, 0.f).IsEmpty());
- EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 2.f, 0.f, 0.f).IsEmpty());
- EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 2.f, 0.f).IsEmpty());
- EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 2.f, 0.f).IsEmpty());
- EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 2.f).IsEmpty());
- EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 0.f, 2.f).IsEmpty());
-
- EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 0.f, 2.f, 2.f).IsEmpty());
- EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 0.f, 2.f, 2.f).IsEmpty());
- EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 0.f, 2.f).IsEmpty());
- EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 0.f, 2.f).IsEmpty());
- EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 2.f, 0.f).IsEmpty());
- EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 2.f, 0.f).IsEmpty());
-
- EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 2.f, 2.f).IsEmpty());
- EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 2.f, 2.f).IsEmpty());
-}
-
-TEST(BoxTest, Union) {
- BoxF empty_box;
- BoxF box1(0.f, 0.f, 0.f, 1.f, 1.f, 1.f);
- BoxF box2(0.f, 0.f, 0.f, 4.f, 6.f, 8.f);
- BoxF box3(3.f, 4.f, 5.f, 6.f, 4.f, 0.f);
-
- EXPECT_EQ(empty_box.ToString(), UnionBoxes(empty_box, empty_box).ToString());
- EXPECT_EQ(box1.ToString(), UnionBoxes(empty_box, box1).ToString());
- EXPECT_EQ(box1.ToString(), UnionBoxes(box1, empty_box).ToString());
- EXPECT_EQ(box2.ToString(), UnionBoxes(empty_box, box2).ToString());
- EXPECT_EQ(box2.ToString(), UnionBoxes(box2, empty_box).ToString());
- EXPECT_EQ(box3.ToString(), UnionBoxes(empty_box, box3).ToString());
- EXPECT_EQ(box3.ToString(), UnionBoxes(box3, empty_box).ToString());
-
- // box_1 is contained in box_2
- EXPECT_EQ(box2.ToString(), UnionBoxes(box1, box2).ToString());
- EXPECT_EQ(box2.ToString(), UnionBoxes(box2, box1).ToString());
-
- // box_1 and box_3 are disjoint
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 5.f).ToString(),
- UnionBoxes(box1, box3).ToString());
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 5.f).ToString(),
- UnionBoxes(box3, box1).ToString());
-
- // box_2 and box_3 intersect, but neither contains the other
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 8.f).ToString(),
- UnionBoxes(box2, box3).ToString());
- EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 8.f).ToString(),
- UnionBoxes(box3, box2).ToString());
-}
-
-TEST(BoxTest, ExpandTo) {
- BoxF box1;
- BoxF box2(0.f, 0.f, 0.f, 1.f, 1.f, 1.f);
- BoxF box3(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
-
- Point3F point1(0.5f, 0.5f, 0.5f);
- Point3F point2(-0.5f, -0.5f, -0.5f);
-
- BoxF expected1_1(0.f, 0.f, 0.f, 0.5f, 0.5f, 0.5f);
- BoxF expected1_2(-0.5f, -0.5f, -0.5f, 1.f, 1.f, 1.f);
-
- BoxF expected2_1 = box2;
- BoxF expected2_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f);
-
- BoxF expected3_1(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
- BoxF expected3_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f);
-
- box1.ExpandTo(point1);
- EXPECT_EQ(expected1_1.ToString(), box1.ToString());
- box1.ExpandTo(point2);
- EXPECT_EQ(expected1_2.ToString(), box1.ToString());
-
- box2.ExpandTo(point1);
- EXPECT_EQ(expected2_1.ToString(), box2.ToString());
- box2.ExpandTo(point2);
- EXPECT_EQ(expected2_2.ToString(), box2.ToString());
-
- box3.ExpandTo(point1);
- EXPECT_EQ(expected3_1.ToString(), box3.ToString());
- box3.ExpandTo(point2);
- EXPECT_EQ(expected3_2.ToString(), box3.ToString());
-}
-
-TEST(BoxTest, Scale) {
- BoxF box1(2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
-
- EXPECT_EQ(BoxF().ToString(), ScaleBox(box1, 0.f).ToString());
- EXPECT_EQ(box1.ToString(), ScaleBox(box1, 1.f).ToString());
- EXPECT_EQ(BoxF(4.f, 12.f, 24.f, 10.f, 24.f, 42.f).ToString(),
- ScaleBox(box1, 2.f, 4.f, 6.f).ToString());
-
- BoxF box2 = box1;
- box2.Scale(0.f);
- EXPECT_EQ(BoxF().ToString(), box2.ToString());
-
- box2 = box1;
- box2.Scale(1.f);
- EXPECT_EQ(box1.ToString(), box2.ToString());
-
- box2.Scale(2.f, 4.f, 6.f);
- EXPECT_EQ(BoxF(4.f, 12.f, 24.f, 10.f, 24.f, 42.f).ToString(),
- box2.ToString());
-}
-
-TEST(BoxTest, Equals) {
- EXPECT_TRUE(BoxF() == BoxF());
- EXPECT_TRUE(BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f) ==
- BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f));
- EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 1.f));
- EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 0.f, 1.f, 0.f));
- EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 1.f, 0.f, 0.f));
- EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 1.f, 0.f, 0.f, 0.f));
- EXPECT_FALSE(BoxF() == BoxF(0.f, 1.f, 0.f, 0.f, 0.f, 0.f));
- EXPECT_FALSE(BoxF() == BoxF(1.f, 0.f, 0.f, 0.f, 0.f, 0.f));
-}
-
-TEST(BoxTest, NotEquals) {
- EXPECT_FALSE(BoxF() != BoxF());
- EXPECT_FALSE(BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f) !=
- BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f));
- EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 1.f));
- EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 0.f, 1.f, 0.f));
- EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 1.f, 0.f, 0.f));
- EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 1.f, 0.f, 0.f, 0.f));
- EXPECT_TRUE(BoxF() != BoxF(0.f, 1.f, 0.f, 0.f, 0.f, 0.f));
- EXPECT_TRUE(BoxF() != BoxF(1.f, 0.f, 0.f, 0.f, 0.f, 0.f));
-}
-
-
-TEST(BoxTest, Offset) {
- BoxF box1(2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
-
- EXPECT_EQ(box1.ToString(), (box1 + Vector3dF(0.f, 0.f, 0.f)).ToString());
- EXPECT_EQ(BoxF(3.f, 1.f, 0.f, 5.f, 6.f, 7.f).ToString(),
- (box1 + Vector3dF(1.f, -2.f, -4.f)).ToString());
-
- BoxF box2 = box1;
- box2 += Vector3dF(0.f, 0.f, 0.f);
- EXPECT_EQ(box1.ToString(), box2.ToString());
-
- box2 += Vector3dF(1.f, -2.f, -4.f);
- EXPECT_EQ(BoxF(3.f, 1.f, 0.f, 5.f, 6.f, 7.f).ToString(),
- box2.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/canvas.cc b/chromium/ui/gfx/canvas.cc
index b89efa9e2b7..db8b28fc0a9 100644
--- a/chromium/ui/gfx/canvas.cc
+++ b/chromium/ui/gfx/canvas.cc
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size_conversions.h"
@@ -99,16 +98,6 @@ void Canvas::SizeStringInt(const base::string16& text,
}
// static
-void Canvas::SizeStringInt(const base::string16& text,
- const Font& font,
- int* width,
- int* height,
- int line_height,
- int flags) {
- SizeStringInt(text, FontList(font), width, height, line_height, flags);
-}
-
-// static
int Canvas::GetStringWidth(const base::string16& text,
const FontList& font_list) {
int width = 0, height = 0;
@@ -125,39 +114,19 @@ float Canvas::GetStringWidthF(const base::string16& text,
}
// static
-int Canvas::GetStringWidth(const base::string16& text, const Font& font) {
- int width = 0, height = 0;
- SizeStringInt(text, FontList(font), &width, &height, 0, NO_ELLIPSIS);
- return width;
-}
-
-// static
int Canvas::DefaultCanvasTextAlignment() {
return base::i18n::IsRTL() ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
}
-void Canvas::DrawStringWithHalo(const base::string16& text,
- const Font& font,
- SkColor text_color,
- SkColor halo_color_in,
- int x,
- int y,
- int w,
- int h,
- int flags) {
- DrawStringRectWithHalo(text, FontList(font), text_color, halo_color_in,
- Rect(x, y, w, h), flags);
-}
-
ImageSkiaRep Canvas::ExtractImageRep() const {
- const SkBitmap& device_bitmap = canvas_->getDevice()->accessBitmap(false);
-
// Make a bitmap to return, and a canvas to draw into it. We don't just want
// to call extractSubset or the copy constructor, since we want an actual copy
// of the bitmap.
+ const SkISize size = canvas_->getDeviceSize();
SkBitmap result;
- device_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config);
+ result.allocN32Pixels(size.width(), size.height());
+ canvas_->readPixels(&result, 0, 0);
return ImageSkiaRep(result, image_scale_);
}
@@ -175,8 +144,7 @@ void Canvas::DrawDashedRect(const Rect& rect, SkColor color) {
delete dots;
last_color = color;
dots = new SkBitmap;
- dots->setConfig(SkBitmap::kARGB_8888_Config, col_pixels, row_pixels);
- dots->allocPixels();
+ dots->allocN32Pixels(col_pixels, row_pixels);
dots->eraseARGB(0, 0, 0, 0);
uint32_t* dot = dots->getAddr32(0, 0);
@@ -216,7 +184,6 @@ void Canvas::SaveLayerAlpha(uint8 alpha) {
canvas_->saveLayerAlpha(NULL, alpha);
}
-
void Canvas::SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds) {
SkRect bounds(RectToSkRect(layer_bounds));
canvas_->saveLayerAlpha(&bounds, alpha);
@@ -226,12 +193,16 @@ void Canvas::Restore() {
canvas_->restore();
}
-bool Canvas::ClipRect(const Rect& rect) {
- return canvas_->clipRect(RectToSkRect(rect));
+void Canvas::ClipRect(const Rect& rect) {
+ canvas_->clipRect(RectToSkRect(rect));
+}
+
+void Canvas::ClipPath(const SkPath& path, bool do_anti_alias) {
+ canvas_->clipPath(path, SkRegion::kIntersect_Op, do_anti_alias);
}
-bool Canvas::ClipPath(const SkPath& path) {
- return canvas_->clipPath(path);
+bool Canvas::IsClipEmpty() const {
+ return canvas_->isClipEmpty();
}
bool Canvas::GetClipBounds(Rect* bounds) {
@@ -363,7 +334,7 @@ void Canvas::DrawImageInt(const ImageSkia& image,
int x,
int y,
const SkPaint& paint) {
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
const SkBitmap& bitmap = image_rep.sk_bitmap();
@@ -405,63 +376,65 @@ void Canvas::DrawImageInt(const ImageSkia& image,
int dest_h,
bool filter,
const SkPaint& paint) {
- DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
- src_y + src_h < std::numeric_limits<int16_t>::max());
- if (src_w <= 0 || src_h <= 0) {
- NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
- return;
- }
-
- if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
- return;
-
- float user_scale_x = static_cast<float>(dest_w) / src_w;
- float user_scale_y = static_cast<float>(dest_h) / src_h;
-
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
- user_scale_x, user_scale_y);
- if (image_rep.is_null())
- return;
-
- SkRect dest_rect = { SkIntToScalar(dest_x),
- SkIntToScalar(dest_y),
- SkIntToScalar(dest_x + dest_w),
- SkIntToScalar(dest_y + dest_h) };
-
- if (src_w == dest_w && src_h == dest_h &&
- user_scale_x == 1.0f && user_scale_y == 1.0f &&
- image_rep.scale() == 1.0f) {
- // Workaround for apparent bug in Skia that causes image to occasionally
- // shift.
- SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
- const SkBitmap& bitmap = image_rep.sk_bitmap();
- canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
- return;
- }
-
- // Make a bitmap shader that contains the bitmap we want to draw. This is
- // basically what SkCanvas.drawBitmap does internally, but it gives us
- // more control over quality and will use the mipmap in the source image if
- // it has one, whereas drawBitmap won't.
- SkMatrix shader_scale;
- shader_scale.setScale(SkFloatToScalar(user_scale_x),
- SkFloatToScalar(user_scale_y));
- shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
- shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
-
- skia::RefPtr<SkShader> shader = CreateImageRepShader(
- image_rep,
- SkShader::kRepeat_TileMode,
- shader_scale);
-
- // Set up our paint to use the shader & release our reference (now just owned
- // by the paint).
- SkPaint p(paint);
- p.setFilterBitmap(filter);
- p.setShader(shader.get());
-
- // The rect will be filled by the bitmap.
- canvas_->drawRect(dest_rect, p);
+ DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
+ dest_h, filter, paint, image_scale_, false);
+}
+
+void Canvas::DrawImageIntInPixel(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint) {
+ // All values passed into this function are in pixels, i.e. no scaling needs
+ // be done.
+ // Logic as below:-
+ // 1. Get the matrix transform from the canvas.
+ // 2. Set the scale in the matrix to 1.0 while honoring the direction of the
+ // the scale (x/y). Example RTL layouts.
+ // 3. Round off the X and Y translation components in the matrix. This is to
+ // reduce floating point errors during rect transformation. This is needed
+ // for fractional scale factors like 1.25/1.5, etc.
+ // 4. Save the current state of the canvas.
+ // 5. Set the modified matrix in the canvas. This ensures that no scaling
+ // will be done for draw operations on the canvas.
+ // 6. Draw the image.
+ // 7. Restore the state of the canvas and the SkCanvas matrix stack.
+ SkMatrix matrix = canvas_->getTotalMatrix();
+
+ // Ensure that the direction of the x and y scales is preserved. This is
+ // important for RTL layouts.
+ matrix.getScaleX() > 0 ? matrix.setScaleX(1.0f) : matrix.setScaleX(-1.0f);
+ matrix.getScaleY() > 0 ? matrix.setScaleY(1.0f) : matrix.setScaleY(-1.0f);
+
+ matrix.setTranslateX(SkScalarRoundToInt(matrix.getTranslateX()));
+ matrix.setTranslateY(SkScalarRoundToInt(matrix.getTranslateY()));
+
+ Save();
+
+ canvas_->setMatrix(matrix);
+
+ DrawImageIntHelper(image,
+ src_x,
+ src_y,
+ src_w,
+ src_h,
+ dest_x,
+ dest_y,
+ dest_w,
+ dest_h,
+ filter,
+ paint,
+ image_scale_,
+ true);
+
+ // Restore the state of the canvas.
+ Restore();
}
void Canvas::DrawImageInPath(const ImageSkia& image,
@@ -469,7 +442,7 @@ void Canvas::DrawImageInPath(const ImageSkia& image,
int y,
const SkPath& path,
const SkPaint& paint) {
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
@@ -502,47 +475,6 @@ void Canvas::DrawStringRectWithFlags(const base::string16& text,
ShadowValues());
}
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h) {
- DrawStringInt(text, font, color, x, y, w, h, DefaultCanvasTextAlignment());
-}
-
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& display_rect) {
- DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
- display_rect.width(), display_rect.height());
-}
-
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h,
- int flags) {
- DrawStringWithShadows(text, font, color, Rect(x, y, w, h), 0, flags,
- ShadowValues());
-}
-
-void Canvas::DrawStringWithShadows(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& text_bounds,
- int line_height,
- int flags,
- const ShadowValues& shadows) {
- DrawStringRectWithShadows(text, FontList(font), color, text_bounds,
- line_height, flags, shadows);
-}
-
void Canvas::TileImageInt(const ImageSkia& image,
int x,
int y,
@@ -573,8 +505,7 @@ void Canvas::TileImageInt(const ImageSkia& image,
if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
return;
- const ImageSkiaRep& image_rep = GetImageRepToPaint(
- image, tile_scale_x, tile_scale_y);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
@@ -631,29 +562,77 @@ bool Canvas::IntersectsClipRect(const Rect& rect) {
rect.width(), rect.height());
}
-const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
- return GetImageRepToPaint(image, 1.0f, 1.0f);
-}
+void Canvas::DrawImageIntHelper(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint,
+ float image_scale,
+ bool pixel) {
+ DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
+ src_y + src_h < std::numeric_limits<int16_t>::max());
+ if (src_w <= 0 || src_h <= 0) {
+ NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
+ return;
+ }
-const ImageSkiaRep& Canvas::GetImageRepToPaint(
- const ImageSkia& image,
- float user_additional_scale_x,
- float user_additional_scale_y) const {
- const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
+ if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
+ return;
+
+ float user_scale_x = static_cast<float>(dest_w) / src_w;
+ float user_scale_y = static_cast<float>(dest_h) / src_h;
+
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
+ if (image_rep.is_null())
+ return;
- if (!image_rep.is_null()) {
- SkMatrix m = canvas_->getTotalMatrix();
- float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) *
- user_additional_scale_x;
- float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) *
- user_additional_scale_y;
+ SkRect dest_rect = { SkIntToScalar(dest_x),
+ SkIntToScalar(dest_y),
+ SkIntToScalar(dest_x + dest_w),
+ SkIntToScalar(dest_y + dest_h) };
- float bitmap_scale = image_rep.scale();
- if (scale_x < bitmap_scale || scale_y < bitmap_scale)
- const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap();
+ if (src_w == dest_w && src_h == dest_h &&
+ user_scale_x == 1.0f && user_scale_y == 1.0f &&
+ image_rep.scale() == 1.0f && !pixel) {
+ // Workaround for apparent bug in Skia that causes image to occasionally
+ // shift.
+ SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
+ const SkBitmap& bitmap = image_rep.sk_bitmap();
+ canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
+ return;
}
- return image_rep;
+ // Make a bitmap shader that contains the bitmap we want to draw. This is
+ // basically what SkCanvas.drawBitmap does internally, but it gives us
+ // more control over quality and will use the mipmap in the source image if
+ // it has one, whereas drawBitmap won't.
+ SkMatrix shader_scale;
+ shader_scale.setScale(SkFloatToScalar(user_scale_x),
+ SkFloatToScalar(user_scale_y));
+ shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
+ shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
+
+ skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
+ image_rep,
+ SkShader::kRepeat_TileMode,
+ shader_scale,
+ pixel ? 1.0f : image_rep.scale());
+
+ // Set up our paint to use the shader & release our reference (now just owned
+ // by the paint).
+ SkPaint p(paint);
+ p.setFilterLevel(filter ? SkPaint::kLow_FilterLevel
+ : SkPaint::kNone_FilterLevel);
+ p.setShader(shader.get());
+
+ // The rect will be filled by the bitmap.
+ canvas_->drawRect(dest_rect, p);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/canvas.h b/chromium/ui/gfx/canvas.h
index f8193f1134c..f3d9486f9a6 100644
--- a/chromium/ui/gfx/canvas.h
+++ b/chromium/ui/gfx/canvas.h
@@ -15,11 +15,11 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/shadow_value.h"
+#include "ui/gfx/text_constants.h"
namespace gfx {
class Rect;
-class Font;
class FontList;
class Point;
class Size;
@@ -40,12 +40,7 @@ class Transform;
// of kSrcOver_Mode.
class GFX_EXPORT Canvas {
public:
- enum TruncateFadeMode {
- TruncateFadeTail,
- TruncateFadeHead,
- };
-
- // Specifies the alignment for text rendered with the DrawStringInt method.
+ // Specifies the alignment for text rendered with the DrawStringRect method.
enum {
TEXT_ALIGN_LEFT = 1 << 0,
TEXT_ALIGN_CENTER = 1 << 1,
@@ -54,7 +49,7 @@ class GFX_EXPORT Canvas {
// Specifies the text consists of multiple lines.
MULTI_LINE = 1 << 3,
- // By default DrawStringInt does not process the prefix ('&') character
+ // By default DrawStringRect does not process the prefix ('&') character
// specially. That is, the string "&foo" is rendered as "&foo". When
// rendering text from a resource that uses the prefix character for
// mnemonics, the prefix should be processed and can be rendered as an
@@ -69,7 +64,7 @@ class GFX_EXPORT Canvas {
// This only works with MULTI_LINE.
CHARACTER_BREAK = 1 << 7,
- // Instructs DrawStringInt() to render the text using RTL directionality.
+ // Instructs DrawStringRect() to render the text using RTL directionality.
// In most cases, passing this flag is not necessary because information
// about the text directionality is going to be embedded within the string
// in the form of special Unicode characters. However, we don't insert
@@ -83,7 +78,7 @@ class GFX_EXPORT Canvas {
// See FORCE_RTL_DIRECTIONALITY for details.
FORCE_LTR_DIRECTIONALITY = 1 << 9,
- // Instructs DrawStringInt() to not use subpixel rendering. This is useful
+ // Instructs DrawStringRect() to not use subpixel rendering. This is useful
// when rendering text onto a fully- or partially-transparent background
// that will later be blended with another image.
NO_SUBPIXEL_RENDERING = 1 << 10,
@@ -130,13 +125,6 @@ class GFX_EXPORT Canvas {
int* height,
int line_height,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- static void SizeStringInt(const base::string16& text,
- const Font& font,
- int* width,
- int* height,
- int line_height,
- int flags);
// This is same as SizeStringInt except that fractional size is returned.
// See comment in GetStringWidthF for its usage.
@@ -151,8 +139,6 @@ class GFX_EXPORT Canvas {
// |text| with |font_list|.
static int GetStringWidth(const base::string16& text,
const FontList& font_list);
- // Obsolete version. Use the above version which takes FontList.
- static int GetStringWidth(const base::string16& text, const Font& font);
// This is same as GetStringWidth except that fractional width is returned.
// Use this method for the scenario that multiple string widths need to be
@@ -164,7 +150,7 @@ class GFX_EXPORT Canvas {
// Returns the default text alignment to be used when drawing text on a
// Canvas based on the directionality of the system locale language.
- // This function is used by Canvas::DrawStringInt when the text alignment
+ // This function is used by Canvas::DrawStringRect when the text alignment
// is not specified.
//
// This function returns either Canvas::TEXT_ALIGN_LEFT or
@@ -186,16 +172,6 @@ class GFX_EXPORT Canvas {
SkColor halo_color,
const Rect& display_rect,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringWithHalo(const base::string16& text,
- const Font& font,
- SkColor text_color,
- SkColor halo_color,
- int x,
- int y,
- int w,
- int h,
- int flags);
// Extracts an ImageSkiaRep from the contents of this canvas.
ImageSkiaRep ExtractImageRep() const;
@@ -218,13 +194,15 @@ class GFX_EXPORT Canvas {
// call Restore() more times than Save*().
void Restore();
- // Adds |rect| to the current clip. Returns true if the resulting clip is
- // non-empty.
- bool ClipRect(const Rect& rect);
+ // Adds |rect| to the current clip.
+ void ClipRect(const Rect& rect);
+
+ // Adds |path| to the current clip. |do_anti_alias| is true if the clip
+ // should be antialiased.
+ void ClipPath(const SkPath& path, bool do_anti_alias);
- // Adds |path| to the current clip. Returns true if the resulting clip is
- // non-empty.
- bool ClipPath(const SkPath& path);
+ // Returns true if the current clip is empty.
+ bool IsClipEmpty() const;
// Returns the bounds of the current clip (in local coordinates) in the
// |bounds| parameter, and returns true if it is non empty.
@@ -339,6 +317,22 @@ class GFX_EXPORT Canvas {
bool filter,
const SkPaint& paint);
+ // Same as the DrawImageInt functions above. Difference being this does not
+ // do any scaling, i.e. it assumes that the source/destination/image, etc are
+ // in pixels. It does translate the destination rectangle to ensure that the
+ // image is displayed at the correct pixel coordinates.
+ void DrawImageIntInPixel(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint);
+
// Draws an |image| with the top left corner at |x| and |y|, clipped to
// |path|.
// Parameters are specified relative to current canvas scale not in pixels.
@@ -356,18 +350,6 @@ class GFX_EXPORT Canvas {
const FontList& font_list,
SkColor color,
const Rect& display_rect);
- // Obsolete versions. Use the above versions which take FontList.
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h);
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& display_rect);
// Draws text with the specified color, fonts and location. The last argument
// specifies flags for how the text should be rendered. It can be one of
@@ -377,17 +359,8 @@ class GFX_EXPORT Canvas {
SkColor color,
const Rect& display_rect,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h,
- int flags);
-
- // Similar to above DrawStringInt method but with text shadows support.
+
+ // Similar to above DrawStringRect method but with text shadows support.
// Currently it's only implemented for canvas skia. Specifying a 0 line_height
// will cause the default height to be used.
void DrawStringRectWithShadows(const base::string16& text,
@@ -397,14 +370,6 @@ class GFX_EXPORT Canvas {
int line_height,
int flags,
const ShadowValues& shadows);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringWithShadows(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& text_bounds,
- int line_height,
- int flags,
- const ShadowValues& shadows);
// Draws a dotted gray rectangle used for focus purposes.
void DrawFocusRect(const Rect& rect);
@@ -449,20 +414,12 @@ class GFX_EXPORT Canvas {
// Apply transformation on the canvas.
void Transform(const Transform& transform);
- // Draws the given string with the beginning or the end using a fade gradient.
- void DrawFadeTruncatingStringRect(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect);
- void DrawFadeTruncatingStringRectWithFlags(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect,
- int flags);
+ // Draws the given string with a fade gradient at the end.
+ void DrawFadedString(const base::string16& text,
+ const FontList& font_list,
+ SkColor color,
+ const Rect& display_rect,
+ int flags);
skia::PlatformCanvas* platform_canvas() const { return owned_canvas_.get(); }
SkCanvas* sk_canvas() const { return canvas_; }
@@ -475,16 +432,22 @@ class GFX_EXPORT Canvas {
bool IntersectsClipRectInt(int x, int y, int w, int h);
bool IntersectsClipRect(const Rect& rect);
- // Returns the image rep which best matches the canvas |image_scale_|.
- // Returns a null image rep if |image| contains no image reps.
- // Builds mip map for returned image rep if necessary.
- //
- // An optional additional user defined scale can be provided.
- const ImageSkiaRep& GetImageRepToPaint(const ImageSkia& image) const;
- const ImageSkiaRep& GetImageRepToPaint(
- const ImageSkia& image,
- float user_defined_scale_factor_x,
- float user_defined_scale_factor_y) const;
+ // Helper for the DrawImageInt functions declared above. The |pixel|
+ // parameter if true indicates that the bounds and the image are to
+ // be assumed to be in pixels, i.e. no scaling needs to be performed.
+ void DrawImageIntHelper(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint,
+ float image_scale,
+ bool pixel);
// The device scale factor at which drawing on this canvas occurs.
// An additional scale can be applied via Canvas::Scale(). However,
diff --git a/chromium/ui/gfx/canvas_paint_gtk.cc b/chromium/ui/gfx/canvas_paint_gtk.cc
deleted file mode 100644
index aef6fc982e3..00000000000
--- a/chromium/ui/gfx/canvas_paint_gtk.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/rect.h"
-
-namespace gfx {
-
-// CanvasSkiaPaint
-
-CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event)
- : context_(NULL),
- window_(event->window),
- region_(gdk_region_copy(event->region)),
- composite_alpha_(false) {
- Init(true);
-}
-
-CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event, bool opaque)
- : context_(NULL),
- window_(event->window),
- region_(gdk_region_copy(event->region)),
- composite_alpha_(false) {
- Init(opaque);
-}
-
-CanvasSkiaPaint::~CanvasSkiaPaint() {
- if (!is_empty()) {
- platform_canvas()->restoreToCount(1);
-
- // Blit the dirty rect to the window.
- CHECK(window_);
- cairo_t* cr = gdk_cairo_create(window_);
- CHECK(cr);
- if (composite_alpha_)
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_surface_t* source_surface = cairo_get_target(context_);
- CHECK(source_surface);
- // Flush cairo's cache of the surface.
- cairo_surface_mark_dirty(source_surface);
- GdkRectangle bounds = rectangle();
- cairo_set_source_surface(cr, source_surface, bounds.x, bounds.y);
- gdk_cairo_region(cr, region_);
- cairo_fill(cr);
- cairo_destroy(cr);
- }
-
- gdk_region_destroy(region_);
-}
-
-void CanvasSkiaPaint::Init(bool opaque) {
- GdkRectangle bounds = rectangle();
- RecreateBackingCanvas(Size(bounds.width, bounds.height), 1.0f, opaque);
-
- skia::PlatformCanvas* canvas = platform_canvas();
-
- // Need to translate so that the dirty region appears at the origin of the
- // surface.
- canvas->translate(-SkIntToScalar(bounds.x), -SkIntToScalar(bounds.y));
-
- context_ = skia::BeginPlatformPaint(canvas);
-}
-
-// CanvasSkiaPaintCairo
-
-CanvasSkiaPaintCairo::CanvasSkiaPaintCairo(cairo_t* cairo,
- Size size,
- bool opaque)
- : context_(NULL),
- dest_(cairo),
- size_(size),
- composite_alpha_(false) {
- CHECK(dest_);
- Init(opaque);
-}
-
-CanvasSkiaPaintCairo::~CanvasSkiaPaintCairo() {
- if (!is_empty()) {
- platform_canvas()->restoreToCount(1);
-
- // Blit the dirty rect to the window.
- if (composite_alpha_)
- cairo_set_operator(dest_, CAIRO_OPERATOR_SOURCE);
- cairo_surface_t* source_surface = cairo_get_target(context_);
- CHECK(source_surface);
- // Flush cairo's cache of the surface.
- cairo_surface_mark_dirty(source_surface);
- cairo_set_source_surface(dest_, source_surface, 0, 0);
- GdkRectangle bounds = {0, 0, size_.width(), size_.height()};
- gdk_cairo_rectangle(dest_, &bounds);
- cairo_fill(dest_);
- }
-}
-
-void CanvasSkiaPaintCairo::Init(bool opaque) {
- RecreateBackingCanvas(size_, 1.0f, opaque);
-
- context_ = skia::BeginPlatformPaint(platform_canvas());
-}
-
-} // namespace gfx
-
-
diff --git a/chromium/ui/gfx/canvas_paint_gtk.h b/chromium/ui/gfx/canvas_paint_gtk.h
deleted file mode 100644
index 487db79f47a..00000000000
--- a/chromium/ui/gfx/canvas_paint_gtk.h
+++ /dev/null
@@ -1,102 +0,0 @@
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_CANVAS_PAINT_LINUX_H_
-#define UI_GFX_CANVAS_PAINT_LINUX_H_
-
-#include "base/logging.h"
-#include "skia/ext/platform_canvas.h"
-#include "ui/gfx/canvas.h"
-#include <gdk/gdk.h>
-
-namespace gfx {
-
-// A class designed to translate skia painting into a region in a GdkWindow.
-// On construction, it will set up a context for painting into, and on
-// destruction, it will commit it to the GdkWindow.
-// Note: The created context is always inialized to (0, 0, 0, 0).
-class GFX_EXPORT CanvasSkiaPaint : public Canvas {
- public:
- // This constructor assumes the result is opaque.
- explicit CanvasSkiaPaint(GdkEventExpose* event);
- CanvasSkiaPaint(GdkEventExpose* event, bool opaque);
- virtual ~CanvasSkiaPaint();
-
- // Sets whether the bitmap is composited in such a way that the alpha channel
- // is honored. This is only useful if you've enabled an RGBA colormap on the
- // widget. The default is false.
- void set_composite_alpha(bool composite_alpha) {
- composite_alpha_ = composite_alpha;
- }
-
- // Returns true if the invalid region is empty. The caller should call this
- // function to determine if anything needs painting.
- bool is_empty() const {
- return gdk_region_empty(region_);
- }
-
- GdkRectangle rectangle() const {
- GdkRectangle bounds;
- gdk_region_get_clipbox(region_, &bounds);
- return bounds;
- }
-
- private:
- void Init(bool opaque);
-
- cairo_t* context_;
- GdkWindow* window_;
- GdkRegion* region_;
- // See description above setter.
- bool composite_alpha_;
-
- // Disallow copy and assign.
- CanvasSkiaPaint(const CanvasSkiaPaint&);
- CanvasSkiaPaint& operator=(const CanvasSkiaPaint&);
-};
-
-// A class designed to translate skia painting into a region in a Cairo context.
-// On construction, it will set up a context for painting into, and on
-// destruction, it will commit it to the Cairo context. If there are any
-// transformations applied to the Cairo context, they will affect the drawing.
-class GFX_EXPORT CanvasSkiaPaintCairo : public Canvas {
- public:
- CanvasSkiaPaintCairo(cairo_t* cairo, Size size, bool opaque);
- virtual ~CanvasSkiaPaintCairo();
-
- // Sets whether the bitmap is composited in such a way that the alpha channel
- // is honored. This is only useful if you've enabled an RGBA colormap on the
- // widget. The default is false.
- void set_composite_alpha(bool composite_alpha) {
- composite_alpha_ = composite_alpha;
- }
-
- // Returns true if size of the drawing region is empty. The caller should call
- // this function to determine if anything needs painting.
- bool is_empty() const {
- return size_.IsEmpty();
- }
-
- Size size() const {
- return size_;
- }
-
- private:
- void Init(bool opaque);
-
- cairo_t* context_;
- cairo_t* dest_;
- Size size_;
- // See description above setter.
- bool composite_alpha_;
-
- // Disallow copy and assign.
- CanvasSkiaPaintCairo(const CanvasSkiaPaintCairo&);
- CanvasSkiaPaintCairo& operator=(const CanvasSkiaPaintCairo&);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_CANVAS_PAINT_LINUX_H_
diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc
index 1ad60ba2b04..8d1311faf39 100644
--- a/chromium/ui/gfx/canvas_skia.cc
+++ b/chromium/ui/gfx/canvas_skia.cc
@@ -84,7 +84,7 @@ bool PixelShouldGetHalo(const SkBitmap& bitmap,
}
// Strips accelerator character prefixes in |text| if needed, based on |flags|.
-// Returns a range in |text| to underline or gfx::Range::InvalidRange() if
+// Returns a range in |text| to underline or Range::InvalidRange() if
// underlining is not needed.
Range StripAcceleratorChars(int flags, base::string16* text) {
if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) {
@@ -105,7 +105,7 @@ void ElideTextAndAdjustRange(const FontList& font_list,
Range* range) {
const base::char16 start_char =
(range->IsValid() ? text->at(range->start()) : 0);
- *text = gfx::ElideText(*text, font_list, width, gfx::ELIDE_AT_END);
+ *text = ElideText(*text, font_list, width, ELIDE_TAIL);
if (!range->IsValid())
return;
if (range->start() >= text->length() ||
@@ -171,17 +171,16 @@ void Canvas::SizeStringFloat(const base::string16& text,
#endif
if ((flags & MULTI_LINE) && *width != 0) {
- gfx::WordWrapBehavior wrap_behavior = gfx::TRUNCATE_LONG_WORDS;
+ WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS;
if (flags & CHARACTER_BREAK)
- wrap_behavior = gfx::WRAP_LONG_WORDS;
+ wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
- wrap_behavior = gfx::ELIDE_LONG_WORDS;
+ wrap_behavior = ELIDE_LONG_WORDS;
Rect rect(*width, INT_MAX);
std::vector<base::string16> strings;
- gfx::ElideRectangleText(adjusted_text, font_list,
- rect.width(), rect.height(),
- wrap_behavior, &strings);
+ ElideRectangleText(adjusted_text, font_list, rect.width(), rect.height(),
+ wrap_behavior, &strings);
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
UpdateRenderText(rect, base::string16(), font_list, flags, 0,
render_text.get());
@@ -230,7 +229,7 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
Rect clip_rect(text_bounds);
clip_rect.Inset(ShadowValue::GetMargin(shadows));
- canvas_->save(SkCanvas::kClip_SaveFlag);
+ canvas_->save();
ClipRect(clip_rect);
Rect rect(text_bounds);
@@ -241,21 +240,18 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
#endif
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetTextShadows(shadows);
+ render_text->set_shadows(shadows);
if (flags & MULTI_LINE) {
- gfx::WordWrapBehavior wrap_behavior = gfx::IGNORE_LONG_WORDS;
+ WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS;
if (flags & CHARACTER_BREAK)
- wrap_behavior = gfx::WRAP_LONG_WORDS;
+ wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
- wrap_behavior = gfx::ELIDE_LONG_WORDS;
+ wrap_behavior = ELIDE_LONG_WORDS;
std::vector<base::string16> strings;
- gfx::ElideRectangleText(adjusted_text,
- font_list,
- text_bounds.width(), text_bounds.height(),
- wrap_behavior,
- &strings);
+ ElideRectangleText(adjusted_text, font_list, text_bounds.width(),
+ text_bounds.height(), wrap_behavior, &strings);
for (size_t i = 0; i < strings.size(); i++) {
Range range = StripAcceleratorChars(flags, &strings[i]);
@@ -294,16 +290,14 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
if (elide_text) {
render_text->SetText(adjusted_text);
if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) {
- render_text->set_fade_tail(true);
+ render_text->SetElideBehavior(FADE_TAIL);
elide_text = false;
}
}
#endif
if (elide_text) {
- ElideTextAndAdjustRange(font_list,
- text_bounds.width(),
- &adjusted_text,
+ ElideTextAndAdjustRange(font_list, text_bounds.width(), &adjusted_text,
&range);
}
@@ -311,7 +305,6 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
render_text.get());
const int text_height = render_text->GetStringSize().height();
- // Center the text vertically.
rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
rect.set_height(text_height);
render_text->SetDisplayRect(rect);
@@ -371,60 +364,44 @@ void Canvas::DrawStringRectWithHalo(const base::string16& text,
DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1);
}
-void Canvas::DrawFadeTruncatingStringRect(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect) {
- DrawFadeTruncatingStringRectWithFlags(
- text, truncate_mode, font_list, color, display_rect, NO_ELLIPSIS);
-}
-
-void Canvas::DrawFadeTruncatingStringRectWithFlags(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect,
- int flags) {
+void Canvas::DrawFadedString(const base::string16& text,
+ const FontList& font_list,
+ SkColor color,
+ const Rect& display_rect,
+ int flags) {
// If the whole string fits in the destination then just draw it directly.
if (GetStringWidth(text, font_list) <= display_rect.width()) {
DrawStringRectWithFlags(text, font_list, color, display_rect, flags);
return;
}
- scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
- base::i18n::RIGHT_TO_LEFT;
-
- switch (truncate_mode) {
- case TruncateFadeTail:
- render_text->set_fade_tail(true);
- if (is_rtl)
- flags |= TEXT_ALIGN_RIGHT;
- break;
- case TruncateFadeHead:
- render_text->set_fade_head(true);
- if (!is_rtl)
- flags |= TEXT_ALIGN_RIGHT;
- break;
- }
-
- // Default to left alignment unless right alignment was chosen above.
- if (!(flags & TEXT_ALIGN_RIGHT))
+ // Align with forced content directionality, overriding alignment flags.
+ if (flags & FORCE_RTL_DIRECTIONALITY) {
+ flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_LEFT);
+ flags |= TEXT_ALIGN_RIGHT;
+ } else if (flags & FORCE_LTR_DIRECTIONALITY) {
+ flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_RIGHT);
flags |= TEXT_ALIGN_LEFT;
+ } else if (!(flags & TEXT_ALIGN_LEFT) && !(flags & TEXT_ALIGN_RIGHT)) {
+ // Also align with content directionality instead of fading both ends.
+ flags &= ~TEXT_ALIGN_CENTER;
+ const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
+ base::i18n::RIGHT_TO_LEFT;
+ flags |= is_rtl ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
+ }
+ flags |= NO_ELLIPSIS;
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
Rect rect = display_rect;
UpdateRenderText(rect, text, font_list, flags, color, render_text.get());
+ render_text->SetElideBehavior(FADE_TAIL);
const int line_height = render_text->GetStringSize().height();
- // Center the text vertically.
rect += Vector2d(0, (display_rect.height() - line_height) / 2);
rect.set_height(line_height);
render_text->SetDisplayRect(rect);
- canvas_->save(SkCanvas::kClip_SaveFlag);
+ canvas_->save();
ClipRect(display_rect);
render_text->Draw(this);
canvas_->restore();
diff --git a/chromium/ui/gfx/canvas_skia_paint.h b/chromium/ui/gfx/canvas_skia_paint.h
index 3f21f5cc410..e9e22fff44e 100644
--- a/chromium/ui/gfx/canvas_skia_paint.h
+++ b/chromium/ui/gfx/canvas_skia_paint.h
@@ -12,12 +12,8 @@
#include "ui/gfx/canvas_paint_win.h"
#elif defined(__APPLE__)
#include "ui/gfx/canvas_paint_mac.h"
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun)
-#if defined(TOOLKIT_GTK)
-#include "ui/gfx/canvas_paint_gtk.h"
#else
#error "No canvas paint for this platform"
#endif
-#endif
#endif // UI_GFX_CANVAS_SKIA_PAINT_H_
diff --git a/chromium/ui/gfx/canvas_unittest.cc b/chromium/ui/gfx/canvas_unittest.cc
index 21b9f51e57e..806e8f0e7a5 100644
--- a/chromium/ui/gfx/canvas_unittest.cc
+++ b/chromium/ui/gfx/canvas_unittest.cc
@@ -2,32 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/canvas.h"
+
#include <limits>
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
namespace gfx {
class CanvasTest : public testing::Test {
protected:
int GetStringWidth(const char *text) {
- return Canvas::GetStringWidth(UTF8ToUTF16(text), font_);
+ return Canvas::GetStringWidth(base::UTF8ToUTF16(text), font_list_);
}
gfx::Size SizeStringInt(const char *text, int width, int line_height) {
- base::string16 text16 = UTF8ToUTF16(text);
+ base::string16 text16 = base::UTF8ToUTF16(text);
int height = 0;
int flags =
- (text16.find('\n') != base::string16::npos) ? Canvas::MULTI_LINE : 0;
- Canvas::SizeStringInt(text16, font_, &width, &height, line_height, flags);
+ (text16.find('\n') != base::string16::npos) ? Canvas::MULTI_LINE : 0;
+ Canvas::SizeStringInt(text16, font_list_, &width, &height, line_height,
+ flags);
return gfx::Size(width, height);
}
private:
- gfx::Font font_;
+ FontList font_list_;
};
TEST_F(CanvasTest, StringWidth) {
diff --git a/chromium/ui/gfx/codec/png_codec.cc b/chromium/ui/gfx/codec/png_codec.cc
index b3f4345343f..d098eb4ee18 100644
--- a/chromium/ui/gfx/codec/png_codec.cc
+++ b/chromium/ui/gfx/codec/png_codec.cc
@@ -678,15 +678,29 @@ bool EncodeWithCompressionLevel(const unsigned char* input,
break;
case PNGCodec::FORMAT_SkBitmap:
- input_color_components = 4;
- if (discard_transparency) {
- output_color_components = 3;
- png_output_color_type = PNG_COLOR_TYPE_RGB;
- converter = ConvertSkiatoRGB;
+ // Compare row_byte_width and size.width() to detect the format of
+ // SkBitmap. kA8_Config (1bpp) and kARGB_8888_Config (4bpp) are the two
+ // supported formats.
+ if (row_byte_width < 4 * size.width()) {
+ // Not 4bpp, so must be 1bpp.
+ // Ignore discard_transparency - it doesn't make sense in this context,
+ // since alpha is the only thing we have and it needs to be used for
+ // color intensity.
+ input_color_components = 1;
+ output_color_components = 1;
+ png_output_color_type = PNG_COLOR_TYPE_GRAY;
+ // |converter| is left as null
} else {
- output_color_components = 4;
- png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- converter = ConvertSkiatoRGBA;
+ input_color_components = 4;
+ if (discard_transparency) {
+ output_color_components = 3;
+ png_output_color_type = PNG_COLOR_TYPE_RGB;
+ converter = ConvertSkiatoRGB;
+ } else {
+ output_color_components = 4;
+ png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ converter = ConvertSkiatoRGBA;
+ }
}
break;
@@ -719,12 +733,38 @@ bool EncodeWithCompressionLevel(const unsigned char* input,
return success;
}
+bool InternalEncodeSkBitmap(const SkBitmap& input,
+ bool discard_transparency,
+ int compression_level,
+ std::vector<unsigned char>* output) {
+ if (input.empty() || input.isNull())
+ return false;
+ int bpp = input.bytesPerPixel();
+ DCHECK(bpp == 1 || bpp == 4); // We support kA8_Config and kARGB_8888_Config.
+
+ SkAutoLockPixels lock_input(input);
+ unsigned char* inputAddr = bpp == 1 ?
+ reinterpret_cast<unsigned char*>(input.getAddr8(0, 0)) :
+ reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)); // bpp = 4
+ return EncodeWithCompressionLevel(
+ inputAddr,
+ PNGCodec::FORMAT_SkBitmap,
+ Size(input.width(), input.height()),
+ static_cast<int>(input.rowBytes()),
+ discard_transparency,
+ std::vector<PNGCodec::Comment>(),
+ compression_level,
+ output);
+}
+
} // namespace
// static
-bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
- const Size& size, int row_byte_width,
+bool PNGCodec::Encode(const unsigned char* input,
+ ColorFormat format,
+ const Size& size,
+ int row_byte_width,
bool discard_transparency,
const std::vector<Comment>& comments,
std::vector<unsigned char>* output) {
@@ -742,37 +782,29 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- static const int bbp = 4;
-
- if (input.empty())
- return false;
- DCHECK_EQ(input.bytesPerPixel(), bbp);
- DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
+ return InternalEncodeSkBitmap(input,
+ discard_transparency,
+ Z_DEFAULT_COMPRESSION,
+ output);
+}
- SkAutoLockPixels lock_input(input);
- return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
- FORMAT_SkBitmap, Size(input.width(), input.height()),
- static_cast<int>(input.rowBytes()), discard_transparency,
- std::vector<Comment>(), output);
+// static
+bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input,
+ std::vector<unsigned char>* output) {
+ return InternalEncodeSkBitmap(input,
+ false,
+ Z_DEFAULT_COMPRESSION,
+ output);
}
// static
bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- static const int bbp = 4;
-
- if (input.empty())
- return false;
- DCHECK_EQ(input.bytesPerPixel(), bbp);
- DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
-
- SkAutoLockPixels lock_input(input);
- return EncodeWithCompressionLevel(
- reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
- FORMAT_SkBitmap, Size(input.width(), input.height()),
- static_cast<int>(input.rowBytes()), discard_transparency,
- std::vector<Comment>(), Z_BEST_SPEED, output);
+ return InternalEncodeSkBitmap(input,
+ discard_transparency,
+ Z_BEST_SPEED,
+ output);
}
PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
diff --git a/chromium/ui/gfx/codec/png_codec.h b/chromium/ui/gfx/codec/png_codec.h
index abb3eaab32c..5f849c462fc 100644
--- a/chromium/ui/gfx/codec/png_codec.h
+++ b/chromium/ui/gfx/codec/png_codec.h
@@ -37,8 +37,10 @@ class GFX_EXPORT PNGCodec {
// This is the default Windows DIB order.
FORMAT_BGRA,
- // 4 bytes per pixel, in pre-multiplied kARGB_8888_Config format. For use
- // with directly writing to a skia bitmap.
+ // SkBitmap format. For Encode() kARGB_8888_Config (4 bytes per pixel) and
+ // kA8_Config (1 byte per pixel) formats are supported. kA8_Config gets
+ // encoded into a grayscale PNG treating alpha as the color intensity.
+ // For Decode() kARGB_8888_Config is always used.
FORMAT_SkBitmap
};
@@ -77,9 +79,10 @@ class GFX_EXPORT PNGCodec {
std::vector<unsigned char>* output);
// Call PNGCodec::Encode on the supplied SkBitmap |input|, which is assumed
- // to be BGRA, 32 bits per pixel. The params |discard_transparency| and
- // |output| are passed directly to Encode; refer to Encode for more
- // information. During the call, an SkAutoLockPixels lock is held on |input|.
+ // to be kARGB_8888_Config, 32 bits per pixel. The params
+ // |discard_transparency| and |output| are passed directly to Encode; refer to
+ // Encode for more information. During the call, an SkAutoLockPixels lock
+ // is held on |input|.
static bool EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output);
@@ -91,6 +94,14 @@ class GFX_EXPORT PNGCodec {
bool discard_transparency,
std::vector<unsigned char>* output);
+ // Call PNGCodec::Encode on the supplied SkBitmap |input|, which is assumed
+ // to be kA8_Config, 8 bits per pixel. The bitmap is encoded as a grayscale
+ // PNG with alpha used for color intensity. The |output| param is passed
+ // directly to Encode; refer to Encode for more information. During the call,
+ // an SkAutoLockPixels lock is held on |input|.
+ static bool EncodeA8SkBitmap(const SkBitmap& input,
+ std::vector<unsigned char>* output);
+
// Decodes the PNG data contained in input of length input_size. The
// decoded data will be placed in *output with the dimensions in *w and *h
// on success (returns true). This data will be written in the 'format'
diff --git a/chromium/ui/gfx/codec/png_codec_unittest.cc b/chromium/ui/gfx/codec/png_codec_unittest.cc
index f1654d9d363..37816807ba9 100644
--- a/chromium/ui/gfx/codec/png_codec_unittest.cc
+++ b/chromium/ui/gfx/codec/png_codec_unittest.cc
@@ -249,14 +249,29 @@ bool NonAlphaColorsClose(uint32_t a, uint32_t b) {
abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2;
}
-void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) {
+// Returns true if the BGRA 32-bit SkColor specified by |a| is equivalent to the
+// 8-bit Gray color specified by |b|.
+bool BGRAGrayEqualsA8Gray(uint32_t a, uint8_t b) {
+ return SkColorGetB(a) == b && SkColorGetG(a) == b &&
+ SkColorGetR(a) == b && SkColorGetA(a) == 255;
+}
+
+void MakeTestBGRASkBitmap(int w, int h, SkBitmap* bmp) {
bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
bmp->allocPixels();
uint32_t* src_data = bmp->getAddr32(0, 0);
- for (int i = 0; i < w * h; i++) {
+ for (int i = 0; i < w * h; i++)
src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
- }
+}
+
+void MakeTestA8SkBitmap(int w, int h, SkBitmap* bmp) {
+ bmp->setConfig(SkBitmap::kA8_Config, w, h);
+ bmp->allocPixels();
+
+ uint8_t* src_data = bmp->getAddr8(0, 0);
+ for (int i = 0; i < w * h; i++)
+ src_data[i] = i % 255;
}
TEST(PNGCodec, EncodeDecodeRGB) {
@@ -1017,7 +1032,7 @@ TEST(PNGCodec, EncodeBGRASkBitmap) {
const int w = 20, h = 20;
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// Encode the bitmap.
std::vector<unsigned char> encoded;
@@ -1040,11 +1055,35 @@ TEST(PNGCodec, EncodeBGRASkBitmap) {
}
}
+TEST(PNGCodec, EncodeA8SkBitmap) {
+ const int w = 20, h = 20;
+
+ SkBitmap original_bitmap;
+ MakeTestA8SkBitmap(w, h, &original_bitmap);
+
+ // Encode the bitmap.
+ std::vector<unsigned char> encoded;
+ EXPECT_TRUE(PNGCodec::EncodeA8SkBitmap(original_bitmap, &encoded));
+
+ // Decode the encoded string.
+ SkBitmap decoded_bitmap;
+ EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
+ &decoded_bitmap));
+
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ uint8_t original_pixel = *original_bitmap.getAddr8(x, y);
+ uint32_t decoded_pixel = *decoded_bitmap.getAddr32(x, y);
+ EXPECT_TRUE(BGRAGrayEqualsA8Gray(decoded_pixel, original_pixel));
+ }
+ }
+}
+
TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) {
const int w = 20, h = 20;
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// Encode the bitmap.
std::vector<unsigned char> encoded;
@@ -1121,7 +1160,7 @@ TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) {
// create an image with known values, a must be opaque because it will be
// lost during encoding
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// encode
std::vector<unsigned char> encoded_normal;
diff --git a/chromium/ui/gfx/color_analysis.cc b/chromium/ui/gfx/color_analysis.cc
index f8987cfb546..5cae9b6d4cc 100644
--- a/chromium/ui/gfx/color_analysis.cc
+++ b/chromium/ui/gfx/color_analysis.cc
@@ -13,14 +13,17 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/color_utils.h"
+namespace color_utils {
namespace {
// RGBA KMean Constants
const uint32_t kNumberOfClusters = 4;
const int kNumberOfIterations = 50;
-const uint32_t kMaxBrightness = 665;
-const uint32_t kMinDarkness = 100;
+
+const HSL kDefaultLowerHSLBound = {-1, -1, 0.15};
+const HSL kDefaultUpperHSLBound = {-1, -1, 0.85};
// Background Color Modification Constants
const SkColor kDefaultBgColor = SK_ColorWHITE;
@@ -139,8 +142,6 @@ void UnPreMultiply(const SkBitmap& bitmap, uint32_t* buffer, int buffer_size) {
} // namespace
-namespace color_utils {
-
KMeanImageSampler::KMeanImageSampler() {
}
@@ -214,8 +215,8 @@ SkColor FindClosestColor(const uint8_t* image,
SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
int img_width,
int img_height,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
KMeanImageSampler* sampler) {
SkColor color = kDefaultBgColor;
if (img_width > 0 && img_height > 0) {
@@ -331,21 +332,19 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
cluster != clusters.end(); ++cluster) {
uint8_t r, g, b;
cluster->GetCentroid(&r, &g, &b);
- // Sum the RGB components to determine if the color is too bright or too
- // dark.
- // TODO (dtrainor): Look into using HSV here instead. This approximation
- // might be fine though.
- uint32_t summed_color = r + g + b;
- if (summed_color < brightness_limit && summed_color > darkness_limit) {
+ SkColor current_color = SkColorSetARGB(SK_AlphaOPAQUE, r, g, b);
+ HSL hsl;
+ SkColorToHSL(current_color, &hsl);
+ if (IsWithinHSLRange(hsl, lower_bound, upper_bound)) {
// If we found a valid color just set it and break. We don't want to
// check the other ones.
- color = SkColorSetARGB(0xFF, r, g, b);
+ color = current_color;
break;
} else if (cluster == clusters.begin()) {
// We haven't found a valid color, but we are at the first color so
// set the color anyway to make sure we at least have a value here.
- color = SkColorSetARGB(0xFF, r, g, b);
+ color = current_color;
}
}
}
@@ -356,16 +355,15 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
}
SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
KMeanImageSampler* sampler) {
int img_width = 0;
int img_height = 0;
std::vector<uint8_t> decoded_data;
SkColor color = kDefaultBgColor;
- if (png.get() &&
- png->size() &&
+ if (png.get() && png->size() &&
gfx::PNGCodec::Decode(png->front(),
png->size(),
gfx::PNGCodec::FORMAT_BGRA,
@@ -375,14 +373,23 @@ SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
return CalculateKMeanColorOfBuffer(&decoded_data[0],
img_width,
img_height,
- darkness_limit,
- brightness_limit,
+ lower_bound,
+ upper_bound,
sampler);
}
return color;
}
-SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
+SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png) {
+ GridSampler sampler;
+ return CalculateKMeanColorOfPNG(
+ png, kDefaultLowerHSLBound, kDefaultUpperHSLBound, &sampler);
+}
+
+SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler) {
// SkBitmap uses pre-multiplied alpha but the KMean clustering function
// above uses non-pre-multiplied alpha. Transform the bitmap before we
// analyze it because the function reads each pixel multiple times.
@@ -390,15 +397,18 @@ SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
scoped_ptr<uint32_t[]> image(new uint32_t[pixel_count]);
UnPreMultiply(bitmap, image.get(), pixel_count);
+ return CalculateKMeanColorOfBuffer(reinterpret_cast<uint8_t*>(image.get()),
+ bitmap.width(),
+ bitmap.height(),
+ lower_bound,
+ upper_bound,
+ sampler);
+}
+
+SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
GridSampler sampler;
- SkColor color = CalculateKMeanColorOfBuffer(
- reinterpret_cast<uint8_t*>(image.get()),
- bitmap.width(),
- bitmap.height(),
- kMinDarkness,
- kMaxBrightness,
- &sampler);
- return color;
+ return CalculateKMeanColorOfBitmap(
+ bitmap, kDefaultLowerHSLBound, kDefaultUpperHSLBound, &sampler);
}
gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
@@ -409,7 +419,7 @@ gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
return covariance;
// Assume ARGB_8888 format.
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
int64_t r_sum = 0;
int64_t g_sum = 0;
@@ -478,8 +488,8 @@ bool ApplyColorReduction(const SkBitmap& source_bitmap,
DCHECK(source_bitmap.getPixels());
DCHECK(target_bitmap->getPixels());
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, source_bitmap.config());
- DCHECK_EQ(SkBitmap::kA8_Config, target_bitmap->config());
+ DCHECK_EQ(kPMColor_SkColorType, source_bitmap.colorType());
+ DCHECK_EQ(kAlpha_8_SkColorType, target_bitmap->colorType());
DCHECK_EQ(source_bitmap.height(), target_bitmap->height());
DCHECK_EQ(source_bitmap.width(), target_bitmap->width());
DCHECK(!source_bitmap.empty());
diff --git a/chromium/ui/gfx/color_analysis.h b/chromium/ui/gfx/color_analysis.h
index dcbfabc9d77..dd273bc11e4 100644
--- a/chromium/ui/gfx/color_analysis.h
+++ b/chromium/ui/gfx/color_analysis.h
@@ -17,6 +17,8 @@ class SkBitmap;
namespace color_utils {
+struct HSL;
+
// This class exposes the sampling method to the caller, which allows
// stubbing out for things like unit tests. Might be useful to pass more
// arguments into the GetSample method in the future (such as which
@@ -52,14 +54,13 @@ class GFX_EXPORT GridSampler : public KMeanImageSampler {
GFX_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height,
SkColor color);
-// Returns an SkColor that represents the calculated dominant color in the png.
-// This uses a KMean clustering algorithm to find clusters of pixel colors in
-// RGB space.
-// |png| represents the data of a png encoded image.
-// |darkness_limit| represents the minimum sum of the RGB components that is
-// acceptable as a color choice. This can be from 0 to 765.
-// |brightness_limit| represents the maximum sum of the RGB components that is
-// acceptable as a color choice. This can be from 0 to 765.
+// Returns an SkColor that represents the calculated dominant color in the
+// image. This uses a KMean clustering algorithm to find clusters of pixel
+// colors in RGB space.
+// |png|/|bitmap| represents the data of a png/bitmap encoded image.
+// |lower_bound| represents the minimum bound of HSL values to allow.
+// |upper_bound| represents the maximum bound of HSL values to allow.
+// See color_utils::IsWithinHSLRange() for description of these bounds.
//
// RGB KMean Algorithm (N clusters, M iterations):
// 1.Pick N starting colors by randomly sampling the pixels. If you see a
@@ -82,21 +83,28 @@ GFX_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height,
// the clusters by weight (where weight is the number of pixels that make up
// this cluster).
// 6.Going through the sorted list of clusters, pick the first cluster with the
-// largest weight that's centroid fulfills the equation
-// |darkness_limit| < SUM(R, G, B) < |brightness_limit|. Return that color.
+// largest weight that's centroid falls between |lower_bound| and
+// |upper_bound|. Return that color.
// If no color fulfills that requirement return the color with the largest
// weight regardless of whether or not it fulfills the equation above.
-//
-// Note: Switching to HSV space did not improve the results of this algorithm
-// for typical favicon images.
+GFX_EXPORT SkColor
+ CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler);
+// Computes a dominant color using the above algorithm and reasonable defaults
+// for |lower_bound|, |upper_bound| and |sampler|.
GFX_EXPORT SkColor CalculateKMeanColorOfPNG(
- scoped_refptr<base::RefCountedMemory> png,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
- KMeanImageSampler* sampler);
-
-// Computes a dominant color for an SkBitmap using the above algorithm and
-// reasonable defaults for |darkness_limit|, |brightness_limit| and |sampler|.
+ scoped_refptr<base::RefCountedMemory> png);
+
+// Returns an SkColor that represents the calculated dominant color in the
+// image. See CalculateKMeanColorOfPNG() for details.
+GFX_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler);
+// Computes a dominant color using the above algorithm and reasonable defaults
+// for |lower_bound|, |upper_bound| and |sampler|.
GFX_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap);
// Compute color covariance matrix for the input bitmap.
diff --git a/chromium/ui/gfx/color_analysis_unittest.cc b/chromium/ui/gfx/color_analysis_unittest.cc
index 7757eb959ba..8e6ec831c1e 100644
--- a/chromium/ui/gfx/color_analysis_unittest.cc
+++ b/chromium/ui/gfx/color_analysis_unittest.cc
@@ -10,11 +10,11 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
-using color_utils::FindClosestColor;
-
-namespace {
+namespace color_utils {
const unsigned char k1x1White[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
@@ -87,7 +87,24 @@ const unsigned char k1x3BlueRed[] = {
0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
-class MockKMeanImageSampler : public color_utils::KMeanImageSampler {
+const HSL kDefaultLowerBound = {-1, -1, 0.15};
+const HSL kDefaultUpperBound = {-1, -1, 0.85};
+
+// Creates a 1-dimensional png of the pixel colors found in |colors|.
+scoped_refptr<base::RefCountedMemory> CreateTestPNG(
+ const std::vector<SkColor>& colors) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, colors.size(), 1);
+ bitmap.allocPixels();
+
+ SkAutoLockPixels lock(bitmap);
+ for (size_t i = 0; i < colors.size(); ++i) {
+ bitmap.eraseArea(SkIRect::MakeXYWH(i, 0, 1, 1), colors[i]);
+ }
+ return gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes();
+}
+
+class MockKMeanImageSampler : public KMeanImageSampler {
public:
MockKMeanImageSampler() : current_result_index_(0) {
}
@@ -104,15 +121,6 @@ class MockKMeanImageSampler : public color_utils::KMeanImageSampler {
prebaked_sample_results_.push_back(sample);
}
- void Reset() {
- prebaked_sample_results_.clear();
- ResetCounter();
- }
-
- void ResetCounter() {
- current_result_index_ = 0;
- }
-
virtual int GetSample(int width, int height) OVERRIDE {
if (current_result_index_ >= prebaked_sample_results_.size()) {
current_result_index_ = 0;
@@ -156,8 +164,6 @@ void Calculate8bitBitmapMinMax(const SkBitmap& bitmap,
}
}
-} // namespace
-
class ColorAnalysisTest : public testing::Test {
};
@@ -171,13 +177,13 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanAllWhite) {
k1x1White,
k1x1White + sizeof(k1x1White) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
EXPECT_EQ(color, SK_ColorWHITE);
}
-TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhite) {
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhiteLightness) {
MockKMeanImageSampler test_sampler;
test_sampler.AddSample(0);
test_sampler.AddSample(1);
@@ -189,10 +195,10 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhite) {
k1x3BlueWhite,
k1x3BlueWhite + sizeof(k1x3BlueWhite) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
- EXPECT_EQ(color, SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF));
+ EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF), color);
}
TEST_F(ColorAnalysisTest, CalculatePNGKMeanPickMostCommon) {
@@ -207,14 +213,51 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanPickMostCommon) {
k1x3BlueRed,
k1x3BlueRed + sizeof(k1x3BlueRed) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
- EXPECT_EQ(color, SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00));
+ EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), color);
+}
+
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreRedHue) {
+ MockKMeanImageSampler test_sampler;
+ test_sampler.AddSample(0);
+ test_sampler.AddSample(1);
+ test_sampler.AddSample(2);
+
+ std::vector<SkColor> colors(4, SK_ColorRED);
+ colors[1] = SK_ColorBLUE;
+
+ scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
+
+ HSL lower = {0.2, -1, 0.15};
+ HSL upper = {0.8, -1, 0.85};
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, lower, upper, &test_sampler);
+
+ EXPECT_EQ(SK_ColorBLUE, color);
+}
+
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreGreySaturation) {
+ MockKMeanImageSampler test_sampler;
+ test_sampler.AddSample(0);
+ test_sampler.AddSample(1);
+ test_sampler.AddSample(2);
+
+ std::vector<SkColor> colors(4, SK_ColorGRAY);
+ colors[1] = SK_ColorBLUE;
+
+ scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
+ HSL lower = {-1, 0.3, -1};
+ HSL upper = {-1, 1, -1};
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, lower, upper, &test_sampler);
+
+ EXPECT_EQ(SK_ColorBLUE, color);
}
TEST_F(ColorAnalysisTest, GridSampler) {
- color_utils::GridSampler sampler;
+ GridSampler sampler;
const int kWidth = 16;
const int kHeight = 16;
// Sample starts at 1,1.
@@ -263,7 +306,7 @@ TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
bitmap.allocPixels();
bitmap.eraseARGB(255, 100, 150, 200);
- SkColor color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
+ SkColor color = CalculateKMeanColorOfBitmap(bitmap);
EXPECT_EQ(255u, SkColorGetA(color));
// Color values are not exactly equal due to reversal of premultiplied alpha.
EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
@@ -272,7 +315,7 @@ TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
// Test a bitmap with an alpha channel.
bitmap.eraseARGB(128, 100, 150, 200);
- color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
+ color = CalculateKMeanColorOfBitmap(bitmap);
// Alpha channel should be ignored for dominant color calculation.
EXPECT_EQ(255u, SkColorGetA(color));
@@ -285,11 +328,10 @@ TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 200);
- EXPECT_EQ(gfx::Matrix3F::Zeros(),
- color_utils::ComputeColorCovariance(bitmap));
+ EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap));
bitmap.allocPixels();
- bitmap.eraseRGB(50, 150, 200);
- gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+ bitmap.eraseARGB(255, 50, 150, 200);
+ gfx::Matrix3F covariance = ComputeColorCovariance(bitmap);
// The answer should be all zeros.
EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros());
}
@@ -306,7 +348,7 @@ TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) {
SkBitmap bitmap =
skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
- gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+ gfx::Matrix3F covariance = ComputeColorCovariance(bitmap);
gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros();
expected_covariance.set(2400, 400, -1600,
@@ -324,12 +366,11 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) {
source.allocPixels();
result.allocPixels();
- source.eraseRGB(50, 150, 200);
+ source.eraseARGB(255, 50, 150, 200);
gfx::Vector3dF transform(1.0f, .5f, 0.1f);
// This transform, if not scaled, should result in GL=145.
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
@@ -338,24 +379,21 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) {
EXPECT_EQ(145, max_gl);
// Now scan requesting rescale. Expect all 0.
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0, min_gl);
EXPECT_EQ(0, max_gl);
// Test cliping to upper limit.
transform.set_z(1.1f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0xFF, min_gl);
EXPECT_EQ(0xFF, max_gl);
// Test cliping to upper limit.
transform.Scale(-1.0f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0x0, min_gl);
EXPECT_EQ(0x0, max_gl);
@@ -376,8 +414,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) {
result.allocPixels();
gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -389,8 +426,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) {
// Reverse test.
transform.Scale(-1.0f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
min_gl = 0;
max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -417,8 +453,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) {
result.allocPixels();
gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -428,8 +463,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) {
EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0)));
EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0)));
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0, min_gl);
EXPECT_EQ(255, max_gl);
@@ -445,10 +479,10 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) {
source.allocPixels();
result.allocPixels();
- source.eraseRGB(50, 150, 200);
+ source.eraseARGB(255, 50, 150, 200);
// This computation should fail since all colors always vary together.
- EXPECT_FALSE(color_utils::ComputePrincipalComponentImage(source, &result));
+ EXPECT_FALSE(ComputePrincipalComponentImage(source, &result));
}
TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
@@ -465,7 +499,7 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
result.allocPixels();
// This computation should fail since all colors always vary together.
- EXPECT_TRUE(color_utils::ComputePrincipalComponentImage(source, &result));
+ EXPECT_TRUE(ComputePrincipalComponentImage(source, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
@@ -477,3 +511,5 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199)));
EXPECT_EQ(93U, SkColorGetA(result.getColor(150, 0)));
}
+
+} // namespace color_utils
diff --git a/chromium/ui/gfx/color_profile.cc b/chromium/ui/gfx/color_profile.cc
index fcd9a52ea0c..bb7c3d546c2 100644
--- a/chromium/ui/gfx/color_profile.cc
+++ b/chromium/ui/gfx/color_profile.cc
@@ -8,8 +8,15 @@ namespace gfx {
#if defined(OS_WIN) || defined(OS_MACOSX)
void ReadColorProfile(std::vector<char>* profile);
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile);
#else
void ReadColorProfile(std::vector<char>* profile) { }
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ // TODO(port): consider screen color profile support.
+ return false;
+}
#endif
ColorProfile::ColorProfile() {
diff --git a/chromium/ui/gfx/color_profile.h b/chromium/ui/gfx/color_profile.h
index 20a02bf169f..790bfe57fff 100644
--- a/chromium/ui/gfx/color_profile.h
+++ b/chromium/ui/gfx/color_profile.h
@@ -7,8 +7,7 @@
#include <vector>
-#include "base/basictypes.h"
-
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -31,10 +30,16 @@ class GFX_EXPORT ColorProfile {
DISALLOW_COPY_AND_ASSIGN(ColorProfile);
};
-// Loads the monitor color space if available.
-GFX_EXPORT void GetColorProfile(std::vector<char>* profile);
+inline bool InvalidColorProfileLength(size_t length) {
+ return (length < kMinProfileLength) || (length > kMaxProfileLength);
+}
+// Return the color profile of the display nearest the screen bounds. On Win32,
+// this may read a file from disk, so it shouldn't be run on the UI/IO threads.
+// If the given bounds are empty, or are off-screen, return false meaning there
+// is no color profile associated with the bounds.
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile);
} // namespace gfx
#endif // UI_GFX_COLOR_PROFILE_H_
-
diff --git a/chromium/ui/gfx/color_profile_mac.cc b/chromium/ui/gfx/color_profile_mac.cc
deleted file mode 100644
index 2c7f686a5f4..00000000000
--- a/chromium/ui/gfx/color_profile_mac.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/color_profile.h"
-
-#include "base/mac/mac_util.h"
-
-namespace gfx {
-
-void ReadColorProfile(std::vector<char>* profile) {
- CGColorSpaceRef monitor_color_space(base::mac::GetSystemColorSpace());
- base::ScopedCFTypeRef<CFDataRef> icc_profile(
- CGColorSpaceCopyICCProfile(monitor_color_space));
- if (icc_profile) {
- size_t length = CFDataGetLength(icc_profile);
- if (length > gfx::kMaxProfileLength)
- return;
- if (length < gfx::kMinProfileLength)
- return;
- const unsigned char* sys_profile = CFDataGetBytePtr(icc_profile);
- profile->assign(sys_profile, sys_profile + length);
- }
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/color_profile_mac.mm b/chromium/ui/gfx/color_profile_mac.mm
new file mode 100644
index 00000000000..c36072d9330
--- /dev/null
+++ b/chromium/ui/gfx/color_profile_mac.mm
@@ -0,0 +1,32 @@
+// 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/gfx/color_profile.h"
+
+#include "base/mac/mac_util.h"
+
+namespace gfx {
+
+bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ if (bounds.IsEmpty())
+ return false;
+ // TODO(noel): implement.
+ return false;
+}
+
+void ReadColorProfile(std::vector<char>* profile) {
+ CGColorSpaceRef monitor_color_space(base::mac::GetSystemColorSpace());
+ base::ScopedCFTypeRef<CFDataRef> icc_profile(
+ CGColorSpaceCopyICCProfile(monitor_color_space));
+ if (!icc_profile)
+ return;
+ size_t length = CFDataGetLength(icc_profile);
+ if (gfx::InvalidColorProfileLength(length))
+ return;
+ const unsigned char* data = CFDataGetBytePtr(icc_profile);
+ profile->assign(data, data + length);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/color_profile_win.cc b/chromium/ui/gfx/color_profile_win.cc
index 2e08a36d4b6..a22c3d96a18 100644
--- a/chromium/ui/gfx/color_profile_win.cc
+++ b/chromium/ui/gfx/color_profile_win.cc
@@ -4,32 +4,118 @@
#include "ui/gfx/color_profile.h"
+#include <map>
#include <windows.h>
#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
namespace gfx {
+class ColorProfileCache {
+ public:
+ // A thread-safe cache of color profiles keyed by windows device name.
+ ColorProfileCache() {}
+
+ bool Find(const std::wstring& device, std::vector<char>* profile) {
+ base::AutoLock lock(lock_);
+ DeviceColorProfile::const_iterator it = cache_.find(device);
+ if (it == cache_.end())
+ return false;
+ *profile = it->second;
+ return true;
+ }
+
+ void Insert(const std::wstring& device, const std::vector<char>& profile) {
+ base::AutoLock lock(lock_);
+ cache_[device] = profile;
+ }
+
+ bool Erase(const std::wstring& device) {
+ base::AutoLock lock(lock_);
+ DeviceColorProfile::iterator it = cache_.find(device);
+ if (it == cache_.end())
+ return false;
+ cache_.erase(device);
+ return true;
+ }
+
+ void Clear() {
+ base::AutoLock lock(lock_);
+ cache_.clear();
+ }
+
+ private:
+ typedef std::map<std::wstring, std::vector<char> > DeviceColorProfile;
+
+ DeviceColorProfile cache_;
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ColorProfileCache);
+};
+
+base::LazyInstance<ColorProfileCache>::Leaky g_color_profile_cache =
+ LAZY_INSTANCE_INITIALIZER;
+
+inline ColorProfileCache& GetColorProfileCache() {
+ return g_color_profile_cache.Get();
+}
+
+bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ DCHECK(profile->empty());
+
+ RECT rect = bounds.ToRECT();
+ HMONITOR handle = ::MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
+ if (bounds.IsEmpty() || !handle)
+ return false;
+
+ MONITORINFOEX monitor;
+ monitor.cbSize = sizeof(MONITORINFOEX);
+ CHECK(::GetMonitorInfo(handle, &monitor));
+ if (GetColorProfileCache().Find(monitor.szDevice, profile))
+ return true;
+
+ HDC hdc = ::CreateDC(monitor.szDevice, NULL, NULL, NULL);
+ DWORD path_length = MAX_PATH;
+ WCHAR path[MAX_PATH + 1];
+ BOOL result = ::GetICMProfile(hdc, &path_length, path);
+ ::DeleteDC(hdc);
+ if (!result)
+ return false;
+
+ base::FilePath file_name = base::FilePath(path).BaseName();
+ if (file_name != base::FilePath(L"sRGB Color Space Profile.icm")) {
+ std::string data;
+ if (base::ReadFileToString(base::FilePath(path), &data))
+ profile->assign(data.data(), data.data() + data.size());
+ size_t length = profile->size();
+ if (gfx::InvalidColorProfileLength(length))
+ profile->clear();
+ }
+
+ GetColorProfileCache().Insert(monitor.szDevice, *profile);
+ return true;
+}
+
void ReadColorProfile(std::vector<char>* profile) {
// TODO: support multiple monitors.
HDC screen_dc = GetDC(NULL);
DWORD path_len = MAX_PATH;
WCHAR path[MAX_PATH + 1];
- BOOL res = GetICMProfile(screen_dc, &path_len, path);
+ BOOL result = GetICMProfile(screen_dc, &path_len, path);
ReleaseDC(NULL, screen_dc);
- if (!res)
+ if (!result)
return;
std::string profileData;
if (!base::ReadFileToString(base::FilePath(path), &profileData))
return;
size_t length = profileData.size();
- if (length > gfx::kMaxProfileLength)
- return;
- if (length < gfx::kMinProfileLength)
+ if (gfx::InvalidColorProfileLength(length))
return;
profile->assign(profileData.data(), profileData.data() + length);
}
} // namespace gfx
-
diff --git a/chromium/ui/gfx/color_profile_win_unittest.cc b/chromium/ui/gfx/color_profile_win_unittest.cc
new file mode 100644
index 00000000000..604ee36201b
--- /dev/null
+++ b/chromium/ui/gfx/color_profile_win_unittest.cc
@@ -0,0 +1,32 @@
+// 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/gfx/color_profile.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+bool TestColorProfileUsingScreenBounds(const gfx::Rect& bounds) {
+ std::vector<char> color_profile;
+ return gfx::GetDisplayColorProfile(bounds, &color_profile);
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfile) {
+ const gfx::Rect in_screen_bounds(10, 10, 100, 100);
+ EXPECT_TRUE(TestColorProfileUsingScreenBounds(in_screen_bounds));
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfileForOffScreenBounds) {
+ const gfx::Rect off_screen_bounds(-100, -100, 10, 10);
+ EXPECT_FALSE(TestColorProfileUsingScreenBounds(off_screen_bounds));
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfileForEmptyBounds) {
+ const gfx::Rect empty_screen_bounds(10, 10, 0, 0);
+ EXPECT_TRUE(empty_screen_bounds.IsEmpty());
+ EXPECT_FALSE(TestColorProfileUsingScreenBounds(empty_screen_bounds));
+}
+
+} // namespace
diff --git a/chromium/ui/gfx/color_utils.cc b/chromium/ui/gfx/color_utils.cc
index 9ced80f3952..3e00326f522 100644
--- a/chromium/ui/gfx/color_utils.cc
+++ b/chromium/ui/gfx/color_utils.cc
@@ -151,6 +151,36 @@ SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) {
calcHue(temp1, temp2, hue - 1.0 / 3.0));
}
+bool IsWithinHSLRange(const HSL& hsl,
+ const HSL& lower_bound,
+ const HSL& upper_bound) {
+ DCHECK(hsl.h >= 0 && hsl.h <= 1) << hsl.h;
+ DCHECK(hsl.s >= 0 && hsl.s <= 1) << hsl.s;
+ DCHECK(hsl.l >= 0 && hsl.l <= 1) << hsl.l;
+ DCHECK(lower_bound.h < 0 || upper_bound.h < 0 ||
+ (lower_bound.h <= 1 && upper_bound.h <= lower_bound.h + 1))
+ << "lower_bound.h: " << lower_bound.h
+ << ", upper_bound.h: " << upper_bound.h;
+ DCHECK(lower_bound.s < 0 || upper_bound.s < 0 ||
+ (lower_bound.s <= upper_bound.s && upper_bound.s <= 1))
+ << "lower_bound.s: " << lower_bound.s
+ << ", upper_bound.s: " << upper_bound.s;
+ DCHECK(lower_bound.l < 0 || upper_bound.l < 0 ||
+ (lower_bound.l <= upper_bound.l && upper_bound.l <= 1))
+ << "lower_bound.l: " << lower_bound.l
+ << ", upper_bound.l: " << upper_bound.l;
+
+ // If the upper hue is >1, the given hue bounds wrap around at 1.
+ bool matches_hue = upper_bound.h > 1
+ ? hsl.h >= lower_bound.h || hsl.h <= upper_bound.h - 1
+ : hsl.h >= lower_bound.h && hsl.h <= upper_bound.h;
+ return (upper_bound.h < 0 || lower_bound.h < 0 || matches_hue) &&
+ (upper_bound.s < 0 || lower_bound.s < 0 ||
+ (hsl.s >= lower_bound.s && hsl.s <= upper_bound.s)) &&
+ (upper_bound.l < 0 || lower_bound.l < 0 ||
+ (hsl.l >= lower_bound.l && hsl.l <= upper_bound.l));
+}
+
SkColor HSLShift(SkColor color, const HSL& shift) {
HSL hsl;
int alpha = SkColorGetA(color);
@@ -194,7 +224,7 @@ SkColor HSLShift(SkColor color, const HSL& shift) {
}
void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) {
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, bitmap.config());
+ DCHECK_EQ(kPMColor_SkColorType, bitmap.colorType());
SkAutoLockPixels bitmap_lock(bitmap);
diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h
index 6dd6300aa3b..9446654cdbe 100644
--- a/chromium/ui/gfx/color_utils.h
+++ b/chromium/ui/gfx/color_utils.h
@@ -29,6 +29,20 @@ GFX_EXPORT double RelativeLuminance(SkColor color);
GFX_EXPORT void SkColorToHSL(SkColor c, HSL* hsl);
GFX_EXPORT SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha);
+// Determines whether the given |hsl| falls within the given range for each
+// component. All components of |hsl| are expected to be in the range [0, 1].
+//
+// If a component is negative in either |lower_bound| or |upper_bound|, that
+// component will be ignored.
+//
+// For hue, the lower bound should be in the range [0, 1] and the upper bound
+// should be in the range [(lower bound), (lower bound + 1)].
+// For saturation and value, bounds should be specified in the range [0, 1],
+// with the lower bound less than the upper bound.
+GFX_EXPORT bool IsWithinHSLRange(const HSL& hsl,
+ const HSL& lower_bound,
+ const HSL& upper_bound);
+
// HSL-Shift an SkColor. The shift values are in the range of 0-1, with the
// option to specify -1 for 'no change'. The shift values are defined as:
// hsl_shift[0] (hue): The absolute hue value - 0 and 1 map
diff --git a/chromium/ui/gfx/color_utils_unittest.cc b/chromium/ui/gfx/color_utils_unittest.cc
index 59eaeba1e3e..b90ae8e2c42 100644
--- a/chromium/ui/gfx/color_utils_unittest.cc
+++ b/chromium/ui/gfx/color_utils_unittest.cc
@@ -9,17 +9,19 @@
#include "third_party/skia/include/core/SkColorPriv.h"
#include "ui/gfx/color_utils.h"
+namespace color_utils {
+
TEST(ColorUtils, SkColorToHSLRed) {
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(SK_ColorRED, &hsl);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(SK_ColorRED, &hsl);
EXPECT_DOUBLE_EQ(hsl.h, 0);
EXPECT_DOUBLE_EQ(hsl.s, 1);
EXPECT_DOUBLE_EQ(hsl.l, 0.5);
}
TEST(ColorUtils, SkColorToHSLGrey) {
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(SkColorSetARGB(255, 128, 128, 128), &hsl);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(SkColorSetARGB(255, 128, 128, 128), &hsl);
EXPECT_DOUBLE_EQ(hsl.h, 0);
EXPECT_DOUBLE_EQ(hsl.s, 0);
EXPECT_EQ(static_cast<int>(hsl.l * 100),
@@ -28,24 +30,23 @@ TEST(ColorUtils, SkColorToHSLGrey) {
TEST(ColorUtils, HSLToSkColorWithAlpha) {
SkColor red = SkColorSetARGB(128, 255, 0, 0);
- color_utils::HSL hsl = { 0, 1, 0.5 };
- SkColor result = color_utils::HSLToSkColor(hsl, 128);
+ HSL hsl = {0, 1, 0.5};
+ SkColor result = HSLToSkColor(hsl, 128);
EXPECT_EQ(SkColorGetA(red), SkColorGetA(result));
EXPECT_EQ(SkColorGetR(red), SkColorGetR(result));
EXPECT_EQ(SkColorGetG(red), SkColorGetG(result));
EXPECT_EQ(SkColorGetB(red), SkColorGetB(result));
}
-
TEST(ColorUtils, RGBtoHSLRoundTrip) {
// Just spot check values near the edges.
for (int r = 0; r < 10; ++r) {
for (int g = 0; g < 10; ++g) {
for (int b = 0; b < 10; ++b) {
SkColor rgb = SkColorSetARGB(255, r, g, b);
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(rgb, &hsl);
- SkColor out = color_utils::HSLToSkColor(hsl, 255);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(rgb, &hsl);
+ SkColor out = HSLToSkColor(hsl, 255);
EXPECT_EQ(SkColorGetR(out), SkColorGetR(rgb));
EXPECT_EQ(SkColorGetG(out), SkColorGetG(rgb));
EXPECT_EQ(SkColorGetB(out), SkColorGetB(rgb));
@@ -56,9 +57,9 @@ TEST(ColorUtils, RGBtoHSLRoundTrip) {
for (int g = 240; g < 256; ++g) {
for (int b = 240; b < 256; ++b) {
SkColor rgb = SkColorSetARGB(255, r, g, b);
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(rgb, &hsl);
- SkColor out = color_utils::HSLToSkColor(hsl, 255);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(rgb, &hsl);
+ SkColor out = HSLToSkColor(hsl, 255);
EXPECT_EQ(SkColorGetR(out), SkColorGetR(rgb));
EXPECT_EQ(SkColorGetG(out), SkColorGetG(rgb));
EXPECT_EQ(SkColorGetB(out), SkColorGetB(rgb));
@@ -67,12 +68,44 @@ TEST(ColorUtils, RGBtoHSLRoundTrip) {
}
}
+TEST(ColorUtils, IsWithinHSLRange) {
+ HSL hsl = {0.3, 0.4, 0.5};
+ HSL lower = {0.2, 0.3, 0.4};
+ HSL upper = {0.4, 0.5, 0.6};
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ // Bounds are inclusive.
+ hsl.h = 0.2;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.4;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.s = 0.3;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.s = 0.5;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.l = 0.4;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.l = 0.6;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+}
+
+TEST(ColorUtils, IsWithinHSLRangeHueWrapAround) {
+ HSL hsl = {0.3, 0.4, 0.5};
+ HSL lower = {0.8, -1, -1};
+ HSL upper = {1.2, -1, -1};
+ hsl.h = 0.1;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.9;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.3;
+ EXPECT_FALSE(IsWithinHSLRange(hsl, lower, upper));
+}
+
TEST(ColorUtils, ColorToHSLRegisterSpill) {
// In a opt build on Linux, this was causing a register spill on my laptop
// (Pentium M) when converting from SkColor to HSL.
SkColor input = SkColorSetARGB(255, 206, 154, 89);
- color_utils::HSL hsl = { -1, -1, -1 };
- SkColor result = color_utils::HSLShift(input, hsl);
+ HSL hsl = {-1, -1, -1};
+ SkColor result = HSLShift(input, hsl);
// |result| should be the same as |input| since we passed in a value meaning
// no color shift.
EXPECT_EQ(SkColorGetA(input), SkColorGetA(result));
@@ -85,16 +118,16 @@ TEST(ColorUtils, AlphaBlend) {
SkColor fore = SkColorSetARGB(255, 200, 200, 200);
SkColor back = SkColorSetARGB(255, 100, 100, 100);
- EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 255) ==
- fore);
- EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 0) ==
- back);
+ EXPECT_TRUE(AlphaBlend(fore, back, 255) == fore);
+ EXPECT_TRUE(AlphaBlend(fore, back, 0) == back);
// One is fully transparent, result is partially transparent.
back = SkColorSetA(back, 0);
- EXPECT_EQ(136U, SkColorGetA(color_utils::AlphaBlend(fore, back, 136)));
+ EXPECT_EQ(136U, SkColorGetA(AlphaBlend(fore, back, 136)));
// Both are fully transparent, result is fully transparent.
fore = SkColorSetA(fore, 0);
- EXPECT_EQ(0U, SkColorGetA(color_utils::AlphaBlend(fore, back, 255)));
+ EXPECT_EQ(0U, SkColorGetA(AlphaBlend(fore, back, 255)));
}
+
+} // namespace color_utils
diff --git a/chromium/ui/gfx/display.cc b/chromium/ui/gfx/display.cc
index 024b1f9aaa6..029359c0938 100644
--- a/chromium/ui/gfx/display.cc
+++ b/chromium/ui/gfx/display.cc
@@ -35,12 +35,11 @@ float GetForcedDeviceScaleFactorImpl() {
return static_cast<float>(scale_in_double);
}
-const int64 kInvalidDisplayIDForCompileTimeInit = -1;
-int64 internal_display_id_ = kInvalidDisplayIDForCompileTimeInit;
+int64 internal_display_id_ = -1;
} // namespace
-const int64 Display::kInvalidDisplayID = kInvalidDisplayIDForCompileTimeInit;
+const int64 Display::kInvalidDisplayID = -1;
// static
float Display::GetForcedDeviceScaleFactor() {
@@ -51,7 +50,9 @@ float Display::GetForcedDeviceScaleFactor() {
//static
bool Display::HasForceDeviceScaleFactor() {
- return HasForceDeviceScaleFactorImpl();
+ static const bool kHasForceDeviceScaleFactor =
+ HasForceDeviceScaleFactorImpl();
+ return kHasForceDeviceScaleFactor;
}
Display::Display()
@@ -83,6 +84,42 @@ Display::Display(int64 id, const gfx::Rect& bounds)
Display::~Display() {
}
+int Display::RotationAsDegree() const {
+ switch (rotation_) {
+ case ROTATE_0:
+ return 0;
+ case ROTATE_90:
+ return 90;
+ case ROTATE_180:
+ return 180;
+ case ROTATE_270:
+ return 270;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+void Display::SetRotationAsDegree(int rotation) {
+ switch (rotation) {
+ case 0:
+ rotation_ = ROTATE_0;
+ break;
+ case 90:
+ rotation_ = ROTATE_90;
+ break;
+ case 180:
+ rotation_ = ROTATE_180;
+ break;
+ case 270:
+ rotation_ = ROTATE_270;
+ break;
+ default:
+ // We should not reach that but we will just ignore the call if we do.
+ NOTREACHED();
+ }
+}
+
Insets Display::GetWorkAreaInsets() const {
return gfx::Insets(work_area_.y() - bounds_.y(),
work_area_.x() - bounds_.x(),
diff --git a/chromium/ui/gfx/display.h b/chromium/ui/gfx/display.h
index eb35a5f5c6f..90fc42f5c31 100644
--- a/chromium/ui/gfx/display.h
+++ b/chromium/ui/gfx/display.h
@@ -73,6 +73,8 @@ class GFX_EXPORT Display {
Rotation rotation() const { return rotation_; }
void set_rotation(Rotation rotation) { rotation_ = rotation; }
+ int RotationAsDegree() const;
+ void SetRotationAsDegree(int rotation);
TouchSupport touch_support() const { return touch_support_; }
void set_touch_support(TouchSupport support) { touch_support_ = support; }
diff --git a/chromium/ui/gfx/display_observer.h b/chromium/ui/gfx/display_observer.h
index ca97247f9ed..0730f266206 100644
--- a/chromium/ui/gfx/display_observer.h
+++ b/chromium/ui/gfx/display_observer.h
@@ -5,6 +5,8 @@
#ifndef UI_GFX_DISPLAY_OBSERVER_H_
#define UI_GFX_DISPLAY_OBSERVER_H_
+#include <stdint.h>
+
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -15,8 +17,13 @@ class Display;
// |DisplaySettingsProvier|. crbug.com/122863.
class GFX_EXPORT DisplayObserver {
public:
- // Called when the |display|'s bound has changed.
- virtual void OnDisplayBoundsChanged(const Display& display) = 0;
+ enum DisplayMetric {
+ DISPLAY_METRIC_NONE = 0,
+ DISPLAY_METRIC_BOUNDS = 1 << 0,
+ DISPLAY_METRIC_WORK_AREA = 1 << 1,
+ DISPLAY_METRIC_DEVICE_SCALE_FACTOR = 1 << 2,
+ DISPLAY_METRIC_ROTATION = 1 << 3,
+ };
// Called when |new_display| has been added.
virtual void OnDisplayAdded(const Display& new_display) = 0;
@@ -24,6 +31,11 @@ class GFX_EXPORT DisplayObserver {
// Called when |old_display| has been removed.
virtual void OnDisplayRemoved(const Display& old_display) = 0;
+ // Called when a |display| has one or more metrics changed. |changed_metrics|
+ // will contain the information about the change, see |DisplayMetric|.
+ virtual void OnDisplayMetricsChanged(const Display& display,
+ uint32_t changed_metrics) = 0;
+
protected:
virtual ~DisplayObserver();
};
diff --git a/chromium/ui/gfx/font.cc b/chromium/ui/gfx/font.cc
index 9eea73b608a..31f27b4f294 100644
--- a/chromium/ui/gfx/font.cc
+++ b/chromium/ui/gfx/font.cc
@@ -18,7 +18,7 @@ Font::Font() : platform_font_(PlatformFont::CreateDefault()) {
Font::Font(const Font& other) : platform_font_(other.platform_font_) {
}
-gfx::Font& Font::operator=(const Font& other) {
+Font& Font::operator=(const Font& other) {
platform_font_ = other.platform_font_;
return *this;
}
@@ -38,11 +38,7 @@ Font::Font(const std::string& font_name, int font_size)
Font::~Font() {
}
-Font Font::DeriveFont(int size_delta) const {
- return DeriveFont(size_delta, GetStyle());
-}
-
-Font Font::DeriveFont(int size_delta, int style) const {
+Font Font::Derive(int size_delta, int style) const {
return platform_font_->DeriveFont(size_delta, style);
}
@@ -58,14 +54,6 @@ int Font::GetCapHeight() const {
return platform_font_->GetCapHeight();
}
-int Font::GetAverageCharacterWidth() const {
- return platform_font_->GetAverageCharacterWidth();
-}
-
-int Font::GetStringWidth(const base::string16& text) const {
- return platform_font_->GetStringWidth(text);
-}
-
int Font::GetExpectedTextWidth(int length) const {
return platform_font_->GetExpectedTextWidth(length);
}
diff --git a/chromium/ui/gfx/font.h b/chromium/ui/gfx/font.h
index 963dde70ffe..5ab0f170bda 100644
--- a/chromium/ui/gfx/font.h
+++ b/chromium/ui/gfx/font.h
@@ -42,7 +42,7 @@ class GFX_EXPORT Font {
// Creates a font that is a clone of another font object.
Font(const Font& other);
- gfx::Font& operator=(const Font& other);
+ Font& operator=(const Font& other);
// Creates a font from the specified native font.
explicit Font(NativeFont native_font);
@@ -57,16 +57,11 @@ class GFX_EXPORT Font {
~Font();
// Returns a new Font derived from the existing font.
- // |size_deta| is the size in pixels to add to the current font. For example,
+ // |size_delta| is the size in pixels to add to the current font. For example,
// a value of 5 results in a font 5 pixels bigger than this font.
- Font DeriveFont(int size_delta) const;
-
- // Returns a new Font derived from the existing font.
- // |size_delta| is the size in pixels to add to the current font. See the
- // single argument version of this method for an example.
// The style parameter specifies the new style for the font, and is a
// bitmask of the values: BOLD, ITALIC and UNDERLINE.
- Font DeriveFont(int size_delta, int style) const;
+ Font Derive(int size_delta, int style) const;
// Returns the number of vertical pixels needed to display characters from
// the specified font. This may include some leading, i.e. height may be
@@ -81,15 +76,8 @@ class GFX_EXPORT Font {
// Returns the cap height of the font.
int GetCapHeight() const;
- // Returns the average character width for the font.
- int GetAverageCharacterWidth() const;
-
- // Returns the number of horizontal pixels needed to display the specified
- // string.
- int GetStringWidth(const base::string16& text) const;
-
// Returns the expected number of horizontal pixels needed to display the
- // specified length of characters. Call GetStringWidth() to retrieve the
+ // specified length of characters. Call gfx::GetStringWidth() to retrieve the
// actual number.
int GetExpectedTextWidth(int length) const;
diff --git a/chromium/ui/gfx/font_fallback_win.cc b/chromium/ui/gfx/font_fallback_win.cc
index 40666ee239a..4426718959b 100644
--- a/chromium/ui/gfx/font_fallback_win.cc
+++ b/chromium/ui/gfx/font_fallback_win.cc
@@ -24,8 +24,9 @@ void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
base::win::RegistryValueIterator it(HKEY_LOCAL_MACHINE, kFonts);
for (; it.Valid(); ++it) {
- const std::string filename = StringToLowerASCII(WideToUTF8(it.Value()));
- (*map)[filename] = WideToUTF8(it.Name());
+ const std::string filename =
+ StringToLowerASCII(base::WideToUTF8(it.Value()));
+ (*map)[filename] = base::WideToUTF8(it.Name());
}
}
@@ -69,7 +70,7 @@ void QueryLinkedFontsFromRegistry(const Font& font,
if (FAILED(key.Open(HKEY_LOCAL_MACHINE, kSystemLink, KEY_READ)))
return;
- const std::wstring original_font_name = UTF8ToWide(font.GetFontName());
+ const std::wstring original_font_name = base::UTF8ToWide(font.GetFontName());
std::vector<std::wstring> values;
if (FAILED(key.ReadValues(original_font_name.c_str(), &values))) {
key.Close();
@@ -79,7 +80,8 @@ void QueryLinkedFontsFromRegistry(const Font& font,
std::string filename;
std::string font_name;
for (size_t i = 0; i < values.size(); ++i) {
- internal::ParseFontLinkEntry(WideToUTF8(values[i]), &filename, &font_name);
+ internal::ParseFontLinkEntry(
+ base::WideToUTF8(values[i]), &filename, &font_name);
// If the font name is present, add that directly, otherwise add the
// font names corresponding to the filename.
if (!font_name.empty()) {
@@ -178,7 +180,8 @@ void ParseFontFamilyString(const std::string& family,
const size_t index = font_names->back().find('(');
if (index != std::string::npos) {
font_names->back().resize(index);
- TrimWhitespace(font_names->back(), TRIM_TRAILING, &font_names->back());
+ base::TrimWhitespace(font_names->back(), base::TRIM_TRAILING,
+ &font_names->back());
}
}
}
diff --git a/chromium/ui/gfx/font_list.cc b/chromium/ui/gfx/font_list.cc
index 3b1ab9bcd1f..920204bf7a7 100644
--- a/chromium/ui/gfx/font_list.cc
+++ b/chromium/ui/gfx/font_list.cc
@@ -4,13 +4,9 @@
#include "ui/gfx/font_list.h"
-#include <algorithm>
-
#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "ui/gfx/font_list_impl.h"
namespace {
@@ -18,128 +14,37 @@ namespace {
base::LazyInstance<std::string>::Leaky g_default_font_description =
LAZY_INSTANCE_INITIALIZER;
-// Parses font description into |font_names|, |font_style| and |font_size|.
-void ParseFontDescriptionString(const std::string& font_description_string,
- std::vector<std::string>* font_names,
- int* font_style,
- int* font_size) {
- base::SplitString(font_description_string, ',', font_names);
- DCHECK_GT(font_names->size(), 1U);
-
- // The last item is [STYLE_OPTIONS] SIZE.
- std::vector<std::string> styles_size;
- base::SplitString(font_names->back(), ' ', &styles_size);
- DCHECK(!styles_size.empty());
- base::StringToInt(styles_size.back(), font_size);
- DCHECK_GT(*font_size, 0);
- font_names->pop_back();
-
- // Font supports BOLD and ITALIC; underline is supported via RenderText.
- *font_style = 0;
- for (size_t i = 0; i < styles_size.size() - 1; ++i) {
- // Styles are separated by white spaces. base::SplitString splits styles
- // by space, and it inserts empty string for continuous spaces.
- if (styles_size[i].empty())
- continue;
- if (!styles_size[i].compare("Bold"))
- *font_style |= gfx::Font::BOLD;
- else if (!styles_size[i].compare("Italic"))
- *font_style |= gfx::Font::ITALIC;
- else
- NOTREACHED();
- }
-}
-
-// Returns the font style and size as a string.
-std::string FontStyleAndSizeToString(int font_style, int font_size) {
- std::string result;
- if (font_style & gfx::Font::BOLD)
- result += "Bold ";
- if (font_style & gfx::Font::ITALIC)
- result += "Italic ";
- result += base::IntToString(font_size);
- result += "px";
- return result;
-}
-
-// Returns font description from |font_names|, |font_style|, and |font_size|.
-std::string BuildFontDescription(const std::vector<std::string>& font_names,
- int font_style,
- int font_size) {
- std::string description = JoinString(font_names, ',');
- description += "," + FontStyleAndSizeToString(font_style, font_size);
- return description;
-}
+// The default instance of gfx::FontListImpl.
+base::LazyInstance<scoped_refptr<gfx::FontListImpl> >::Leaky g_default_impl =
+ LAZY_INSTANCE_INITIALIZER;
+bool g_default_impl_initialized = false;
} // namespace
namespace gfx {
-FontList::FontList()
- : common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- // SetDefaultFontDescription() must be called and the default font description
- // must be set earlier than any call of the default constructor.
- DCHECK(!(g_default_font_description == NULL)) // != is not overloaded.
- << "SetDefaultFontDescription has not been called.";
+FontList::FontList() : impl_(GetDefaultImpl()) {}
- font_description_string_ = g_default_font_description.Get();
- if (font_description_string_.empty())
- fonts_.push_back(Font());
-}
+FontList::FontList(const FontList& other) : impl_(other.impl_) {}
FontList::FontList(const std::string& font_description_string)
- : font_description_string_(font_description_string),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- DCHECK(!font_description_string.empty());
- // DCHECK description string ends with "px" for size in pixel.
- DCHECK(EndsWith(font_description_string, "px", true));
-}
+ : impl_(new FontListImpl(font_description_string)) {}
FontList::FontList(const std::vector<std::string>& font_names,
int font_style,
int font_size)
- : font_description_string_(BuildFontDescription(font_names, font_style,
- font_size)),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(font_style),
- font_size_(font_size) {
- DCHECK(!font_names.empty());
- DCHECK(!font_names[0].empty());
-}
+ : impl_(new FontListImpl(font_names, font_style, font_size)) {}
FontList::FontList(const std::vector<Font>& fonts)
- : fonts_(fonts),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- DCHECK(!fonts.empty());
- font_style_ = fonts[0].GetStyle();
- font_size_ = fonts[0].GetFontSize();
- if (DCHECK_IS_ON()) {
- for (size_t i = 1; i < fonts.size(); ++i) {
- DCHECK_EQ(fonts[i].GetStyle(), font_style_);
- DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
- }
- }
-}
+ : impl_(new FontListImpl(fonts)) {}
-FontList::FontList(const Font& font)
- : common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- fonts_.push_back(font);
-}
+FontList::FontList(const Font& font) : impl_(new FontListImpl(font)) {}
-FontList::~FontList() {
+FontList::~FontList() {}
+
+FontList& FontList::operator=(const FontList& other) {
+ impl_ = other.impl_;
+ return *this;
}
// static
@@ -150,151 +55,75 @@ void FontList::SetDefaultFontDescription(const std::string& font_description) {
EndsWith(font_description, "px", true));
g_default_font_description.Get() = font_description;
+ g_default_impl_initialized = false;
}
-FontList FontList::DeriveFontList(int font_style) const {
- return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
-}
-
-FontList FontList::DeriveFontListWithSize(int size) const {
- DCHECK_GT(size, 0);
- return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
- GetFontStyle());
+FontList FontList::Derive(int size_delta, int font_style) const {
+ return FontList(impl_->Derive(size_delta, font_style));
}
-FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
- return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
+FontList FontList::DeriveWithSizeDelta(int size_delta) const {
+ return Derive(size_delta, GetFontStyle());
}
-FontList FontList::DeriveFontListWithSizeDeltaAndStyle(int size_delta,
- int style) const {
- // If there is a font vector, derive from that.
- if (!fonts_.empty()) {
- std::vector<Font> fonts = fonts_;
- for (size_t i = 0; i < fonts.size(); ++i)
- fonts[i] = fonts[i].DeriveFont(size_delta, style);
- return FontList(fonts);
- }
-
- // Otherwise, parse the font description string to derive from it.
- std::vector<std::string> font_names;
- int old_size;
- int old_style;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &old_style, &old_size);
- int size = old_size + size_delta;
- DCHECK_GT(size, 0);
- return FontList(font_names, style, size);
+FontList FontList::DeriveWithStyle(int font_style) const {
+ return Derive(0, font_style);
}
int FontList::GetHeight() const {
- if (common_height_ == -1)
- CacheCommonFontHeightAndBaseline();
- return common_height_;
+ return impl_->GetHeight();
}
int FontList::GetBaseline() const {
- if (common_baseline_ == -1)
- CacheCommonFontHeightAndBaseline();
- return common_baseline_;
+ return impl_->GetBaseline();
}
int FontList::GetCapHeight() const {
- // Assume the primary font is used to render Latin characters.
- return GetPrimaryFont().GetCapHeight();
-}
-
-int FontList::GetStringWidth(const base::string16& text) const {
- // Rely on the primary font metrics for the time being.
- // TODO(yukishiino): Not only the first font, all the fonts in the list should
- // be taken into account to compute the pixels needed to display |text|.
- // Also this method, including one in Font class, should be deprecated and
- // client code should call Canvas::GetStringWidth(text, font_list) directly.
- // Our plan is as follows:
- // 1. Introduce the FontList version of Canvas::GetStringWidth().
- // 2. Make client code call Canvas::GetStringWidth().
- // 3. Retire {Font,FontList}::GetStringWidth().
- return GetPrimaryFont().GetStringWidth(text);
+ return impl_->GetCapHeight();
}
int FontList::GetExpectedTextWidth(int length) const {
- // Rely on the primary font metrics for the time being.
- return GetPrimaryFont().GetExpectedTextWidth(length);
+ return impl_->GetExpectedTextWidth(length);
}
int FontList::GetFontStyle() const {
- if (font_style_ == -1)
- CacheFontStyleAndSize();
- return font_style_;
+ return impl_->GetFontStyle();
}
const std::string& FontList::GetFontDescriptionString() const {
- if (font_description_string_.empty()) {
- DCHECK(!fonts_.empty());
- for (size_t i = 0; i < fonts_.size(); ++i) {
- std::string name = fonts_[i].GetFontName();
- font_description_string_ += name;
- font_description_string_ += ',';
- }
- // All fonts have the same style and size.
- font_description_string_ +=
- FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
- }
- return font_description_string_;
+ return impl_->GetFontDescriptionString();
}
int FontList::GetFontSize() const {
- if (font_size_ == -1)
- CacheFontStyleAndSize();
- return font_size_;
+ return impl_->GetFontSize();
}
const std::vector<Font>& FontList::GetFonts() const {
- if (fonts_.empty()) {
- DCHECK(!font_description_string_.empty());
-
- std::vector<std::string> font_names;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &font_style_, &font_size_);
- for (size_t i = 0; i < font_names.size(); ++i) {
- DCHECK(!font_names[i].empty());
-
- Font font(font_names[i], font_size_);
- if (font_style_ == Font::NORMAL)
- fonts_.push_back(font);
- else
- fonts_.push_back(font.DeriveFont(0, font_style_));
- }
- }
- return fonts_;
+ return impl_->GetFonts();
}
const Font& FontList::GetPrimaryFont() const {
- return GetFonts()[0];
+ return impl_->GetPrimaryFont();
}
-void FontList::CacheCommonFontHeightAndBaseline() const {
- int ascent = 0;
- int descent = 0;
- const std::vector<Font>& fonts = GetFonts();
- for (std::vector<Font>::const_iterator i = fonts.begin();
- i != fonts.end(); ++i) {
- ascent = std::max(ascent, i->GetBaseline());
- descent = std::max(descent, i->GetHeight() - i->GetBaseline());
- }
- common_height_ = ascent + descent;
- common_baseline_ = ascent;
-}
+FontList::FontList(FontListImpl* impl) : impl_(impl) {}
+
+// static
+const scoped_refptr<FontListImpl>& FontList::GetDefaultImpl() {
+ // SetDefaultFontDescription() must be called and the default font description
+ // must be set earlier than any call of this function.
+ DCHECK(!(g_default_font_description == NULL)) // != is not overloaded.
+ << "SetDefaultFontDescription has not been called.";
-void FontList::CacheFontStyleAndSize() const {
- if (!fonts_.empty()) {
- font_style_ = fonts_[0].GetStyle();
- font_size_ = fonts_[0].GetFontSize();
- } else {
- std::vector<std::string> font_names;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &font_style_, &font_size_);
+ if (!g_default_impl_initialized) {
+ g_default_impl.Get() =
+ g_default_font_description.Get().empty() ?
+ new FontListImpl(Font()) :
+ new FontListImpl(g_default_font_description.Get());
+ g_default_impl_initialized = true;
}
+
+ return g_default_impl.Get();
}
} // namespace gfx
diff --git a/chromium/ui/gfx/font_list.h b/chromium/ui/gfx/font_list.h
index e37fd625a23..1ba8ad1aff9 100644
--- a/chromium/ui/gfx/font_list.h
+++ b/chromium/ui/gfx/font_list.h
@@ -8,35 +8,35 @@
#include <string>
#include <vector>
+#include "base/memory/ref_counted.h"
#include "ui/gfx/font.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
-// FontList represents a list of fonts either in the form of Font vector or in
-// the form of a string representing font names, styles, and size.
-//
-// The string representation is in the form "FAMILY_LIST [STYLE_OPTIONS] SIZE",
-// where FAMILY_LIST is a comma separated list of families terminated by a
-// comma, STYLE_OPTIONS is a whitespace separated list of words where each word
-// describes one of style, variant, weight, stretch, or gravity, and SIZE is
-// a decimal number followed by "px" for absolute size. STYLE_OPTIONS may be
-// absent.
+class FontListImpl;
+
+// FontList represents a list of fonts and provides metrics which are common
+// in the fonts. FontList is copyable and it's quite cheap to copy.
//
-// The string format complies with that of Pango detailed at
+// The format of font description string complies with that of Pango detailed at
// http://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string
-//
-// FontList could be initialized either way without conversion to the other
-// form. The conversion to the other form is done only when asked to get the
-// other form.
-//
-// FontList allows operator= since FontList is a data member type in RenderText,
-// and operator= is used in RenderText::SetFontList().
+// The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>" where
+// FONT_FAMILY_LIST is a comma-separated list of font family names,
+// STYLES is a space-separated list of style names ("Bold" and "Italic"),
+// SIZE is a font size in pixel with the suffix "px".
+// Here are examples of font description string:
+// "Arial, Helvetica, Bold Italic 14px"
+// "Arial, 14px"
class GFX_EXPORT FontList {
public:
- // Creates a font list with a Font with default name and style.
+ // Creates a font list with default font names, size and style, which are
+ // specified by SetDefaultFontDescription().
FontList();
+ // Creates a font list that is a clone of another font list.
+ FontList(const FontList& other);
+
// Creates a font list from a string representing font names, styles, and
// size.
explicit FontList(const std::string& font_description_string);
@@ -55,6 +55,9 @@ class GFX_EXPORT FontList {
~FontList();
+ // Copies the given font list into this object.
+ FontList& operator=(const FontList& other);
+
// Sets the description string for default FontList construction. If it's
// empty, FontList will initialize using the default Font constructor.
//
@@ -65,23 +68,20 @@ class GFX_EXPORT FontList {
// is changed.
static void SetDefaultFontDescription(const std::string& font_description);
- // Returns a new FontList with the given |font_style| flags.
- FontList DeriveFontList(int font_style) const;
-
- // Returns a new FontList with the same font names and style but with the
- // given font |size| in pixels.
- FontList DeriveFontListWithSize(int size) const;
-
- // Returns a new FontList with the same font names and style but resized.
- // |size_delta| is the size in pixels to add to the current font size.
- FontList DeriveFontListWithSizeDelta(int size_delta) const;
-
// Returns a new FontList with the same font names but resized and the given
// style. |size_delta| is the size in pixels to add to the current font size.
// |font_style| specifies the new style, which is a bitmask of the values:
// Font::BOLD, Font::ITALIC and Font::UNDERLINE.
- FontList DeriveFontListWithSizeDeltaAndStyle(int size_delta,
- int font_style) const;
+ FontList Derive(int size_delta, int font_style) const;
+
+ // Returns a new FontList with the same font names and style but resized.
+ // |size_delta| is the size in pixels to add to the current font size.
+ FontList DeriveWithSizeDelta(int size_delta) const;
+
+ // Returns a new FontList with the same font names and size but the given
+ // style. |font_style| specifies the new style, which is a bitmask of the
+ // values: Font::BOLD, Font::ITALIC and Font::UNDERLINE.
+ FontList DeriveWithStyle(int font_style) const;
// Returns the height of this font list, which is max(ascent) + max(descent)
// for all the fonts in the font list.
@@ -95,9 +95,6 @@ class GFX_EXPORT FontList {
// Currently returns the cap height of the primary font.
int GetCapHeight() const;
- // Returns the number of horizontal pixels needed to display |text|.
- int GetStringWidth(const base::string16& text) const;
-
// Returns the expected number of horizontal pixels needed to display the
// specified length of characters. Call GetStringWidth() to retrieve the
// actual number.
@@ -121,33 +118,11 @@ class GFX_EXPORT FontList {
const Font& GetPrimaryFont() const;
private:
- // Extracts common font height and baseline into |common_height_| and
- // |common_baseline_|.
- void CacheCommonFontHeightAndBaseline() const;
-
- // Extracts font style and size into |font_style_| and |font_size_|.
- void CacheFontStyleAndSize() const;
-
- // A vector of Font. If FontList is constructed with font description string,
- // |fonts_| is not initialized during construction. Instead, it is computed
- // lazily when user asked to get the font vector.
- mutable std::vector<Font> fonts_;
-
- // A string representing font names, styles, and sizes.
- // Please refer to the comments before class declaration for details on string
- // format.
- // If FontList is constructed with a vector of font,
- // |font_description_string_| is not initialized during construction. Instead,
- // it is computed lazily when user asked to get the font description string.
- mutable std::string font_description_string_;
-
- // The cached common height and baseline of the fonts in the font list.
- mutable int common_height_;
- mutable int common_baseline_;
-
- // Cached font style and size.
- mutable int font_style_;
- mutable int font_size_;
+ explicit FontList(FontListImpl* impl);
+
+ static const scoped_refptr<FontListImpl>& GetDefaultImpl();
+
+ scoped_refptr<FontListImpl> impl_;
};
} // namespace gfx
diff --git a/chromium/ui/gfx/font_list_impl.cc b/chromium/ui/gfx/font_list_impl.cc
new file mode 100644
index 00000000000..8c00fcc8278
--- /dev/null
+++ b/chromium/ui/gfx/font_list_impl.cc
@@ -0,0 +1,248 @@
+// 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/gfx/font_list_impl.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "ui/gfx/font.h"
+
+namespace {
+
+// Parses font description into |font_names|, |font_style| and |font_size|.
+void ParseFontDescriptionString(const std::string& font_description_string,
+ std::vector<std::string>* font_names,
+ int* font_style,
+ int* font_size) {
+ base::SplitString(font_description_string, ',', font_names);
+ DCHECK_GT(font_names->size(), 1U);
+
+ // The last item is [STYLE_OPTIONS] SIZE.
+ std::vector<std::string> styles_size;
+ base::SplitString(font_names->back(), ' ', &styles_size);
+ DCHECK(!styles_size.empty());
+ base::StringToInt(styles_size.back(), font_size);
+ DCHECK_GT(*font_size, 0);
+ font_names->pop_back();
+
+ // Font supports BOLD and ITALIC; underline is supported via RenderText.
+ *font_style = 0;
+ for (size_t i = 0; i < styles_size.size() - 1; ++i) {
+ // Styles are separated by white spaces. base::SplitString splits styles
+ // by space, and it inserts empty string for continuous spaces.
+ if (styles_size[i].empty())
+ continue;
+ if (!styles_size[i].compare("Bold"))
+ *font_style |= gfx::Font::BOLD;
+ else if (!styles_size[i].compare("Italic"))
+ *font_style |= gfx::Font::ITALIC;
+ else
+ NOTREACHED();
+ }
+}
+
+// Returns the font style and size as a string.
+std::string FontStyleAndSizeToString(int font_style, int font_size) {
+ std::string result;
+ if (font_style & gfx::Font::BOLD)
+ result += "Bold ";
+ if (font_style & gfx::Font::ITALIC)
+ result += "Italic ";
+ result += base::IntToString(font_size);
+ result += "px";
+ return result;
+}
+
+// Returns font description from |font_names|, |font_style|, and |font_size|.
+std::string BuildFontDescription(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size) {
+ std::string description = JoinString(font_names, ',');
+ description += "," + FontStyleAndSizeToString(font_style, font_size);
+ return description;
+}
+
+} // namespace
+
+namespace gfx {
+
+FontListImpl::FontListImpl(const std::string& font_description_string)
+ : font_description_string_(font_description_string),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ DCHECK(!font_description_string.empty());
+ // DCHECK description string ends with "px" for size in pixel.
+ DCHECK(EndsWith(font_description_string, "px", true));
+}
+
+FontListImpl::FontListImpl(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size)
+ : font_description_string_(BuildFontDescription(font_names, font_style,
+ font_size)),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(font_style),
+ font_size_(font_size) {
+ DCHECK(!font_names.empty());
+ DCHECK(!font_names[0].empty());
+}
+
+FontListImpl::FontListImpl(const std::vector<Font>& fonts)
+ : fonts_(fonts),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ DCHECK(!fonts.empty());
+ font_style_ = fonts[0].GetStyle();
+ font_size_ = fonts[0].GetFontSize();
+#if DCHECK_IS_ON
+ for (size_t i = 1; i < fonts.size(); ++i) {
+ DCHECK_EQ(fonts[i].GetStyle(), font_style_);
+ DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
+ }
+#endif
+}
+
+FontListImpl::FontListImpl(const Font& font)
+ : common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ fonts_.push_back(font);
+}
+
+FontListImpl* FontListImpl::Derive(int size_delta, int font_style) const {
+ // If there is a font vector, derive from that.
+ if (!fonts_.empty()) {
+ std::vector<Font> fonts = fonts_;
+ for (size_t i = 0; i < fonts.size(); ++i)
+ fonts[i] = fonts[i].Derive(size_delta, font_style);
+ return new FontListImpl(fonts);
+ }
+
+ // Otherwise, parse the font description string to derive from it.
+ std::vector<std::string> font_names;
+ int old_size;
+ int old_style;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &old_style, &old_size);
+ const int size = std::max(1, old_size + size_delta);
+ return new FontListImpl(font_names, font_style, size);
+}
+
+int FontListImpl::GetHeight() const {
+ if (common_height_ == -1)
+ CacheCommonFontHeightAndBaseline();
+ return common_height_;
+}
+
+int FontListImpl::GetBaseline() const {
+ if (common_baseline_ == -1)
+ CacheCommonFontHeightAndBaseline();
+ return common_baseline_;
+}
+
+int FontListImpl::GetCapHeight() const {
+ // Assume the primary font is used to render Latin characters.
+ return GetPrimaryFont().GetCapHeight();
+}
+
+int FontListImpl::GetExpectedTextWidth(int length) const {
+ // Rely on the primary font metrics for the time being.
+ return GetPrimaryFont().GetExpectedTextWidth(length);
+}
+
+int FontListImpl::GetFontStyle() const {
+ if (font_style_ == -1)
+ CacheFontStyleAndSize();
+ return font_style_;
+}
+
+const std::string& FontListImpl::GetFontDescriptionString() const {
+ if (font_description_string_.empty()) {
+ DCHECK(!fonts_.empty());
+ for (size_t i = 0; i < fonts_.size(); ++i) {
+ std::string name = fonts_[i].GetFontName();
+ font_description_string_ += name;
+ font_description_string_ += ',';
+ }
+ // All fonts have the same style and size.
+ font_description_string_ +=
+ FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
+ }
+ return font_description_string_;
+}
+
+int FontListImpl::GetFontSize() const {
+ if (font_size_ == -1)
+ CacheFontStyleAndSize();
+ return font_size_;
+}
+
+const std::vector<Font>& FontListImpl::GetFonts() const {
+ if (fonts_.empty()) {
+ DCHECK(!font_description_string_.empty());
+
+ std::vector<std::string> font_names;
+ // It's possible that gfx::Font::UNDERLINE is specified and it's already
+ // stored in |font_style_| but |font_description_string_| doesn't have the
+ // underline info. So we should respect |font_style_| as long as it's
+ // valid.
+ int style = 0;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &style, &font_size_);
+ if (font_style_ == -1)
+ font_style_ = style;
+ for (size_t i = 0; i < font_names.size(); ++i) {
+ DCHECK(!font_names[i].empty());
+
+ Font font(font_names[i], font_size_);
+ if (font_style_ == Font::NORMAL)
+ fonts_.push_back(font);
+ else
+ fonts_.push_back(font.Derive(0, font_style_));
+ }
+ }
+ return fonts_;
+}
+
+const Font& FontListImpl::GetPrimaryFont() const {
+ return GetFonts()[0];
+}
+
+FontListImpl::~FontListImpl() {}
+
+void FontListImpl::CacheCommonFontHeightAndBaseline() const {
+ int ascent = 0;
+ int descent = 0;
+ const std::vector<Font>& fonts = GetFonts();
+ for (std::vector<Font>::const_iterator i = fonts.begin();
+ i != fonts.end(); ++i) {
+ ascent = std::max(ascent, i->GetBaseline());
+ descent = std::max(descent, i->GetHeight() - i->GetBaseline());
+ }
+ common_height_ = ascent + descent;
+ common_baseline_ = ascent;
+}
+
+void FontListImpl::CacheFontStyleAndSize() const {
+ if (!fonts_.empty()) {
+ font_style_ = fonts_[0].GetStyle();
+ font_size_ = fonts_[0].GetFontSize();
+ } else {
+ std::vector<std::string> font_names;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &font_style_, &font_size_);
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/font_list_impl.h b/chromium/ui/gfx/font_list_impl.h
new file mode 100644
index 00000000000..94bb33036ab
--- /dev/null
+++ b/chromium/ui/gfx/font_list_impl.h
@@ -0,0 +1,123 @@
+// 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_GFX_FONT_LIST_IMPL_H_
+#define UI_GFX_FONT_LIST_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+
+namespace gfx {
+
+class Font;
+
+// FontListImpl is designed to provide the implementation of FontList and
+// intended to be used only from FontList. You must not use this class
+// directly.
+//
+// FontListImpl represents a list of fonts either in the form of Font vector or
+// in the form of a string representing font names, styles, and size.
+//
+// FontListImpl could be initialized either way without conversion to the other
+// form. The conversion to the other form is done only when asked to get the
+// other form.
+//
+// For the format of font description string, see font_list.h for details.
+class FontListImpl : public base::RefCounted<FontListImpl> {
+ public:
+ // Creates a font list from a string representing font names, styles, and
+ // size.
+ explicit FontListImpl(const std::string& font_description_string);
+
+ // Creates a font list from font names, styles and size.
+ FontListImpl(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size);
+
+ // Creates a font list from a Font vector.
+ // All fonts in this vector should have the same style and size.
+ explicit FontListImpl(const std::vector<Font>& fonts);
+
+ // Creates a font list from a Font.
+ explicit FontListImpl(const Font& font);
+
+ // Returns a new FontListImpl with the same font names but resized and the
+ // given style. |size_delta| is the size in pixels to add to the current font
+ // size. |font_style| specifies the new style, which is a bitmask of the
+ // values: Font::BOLD, Font::ITALIC and Font::UNDERLINE.
+ FontListImpl* Derive(int size_delta, int font_style) const;
+
+ // Returns the height of this font list, which is max(ascent) + max(descent)
+ // for all the fonts in the font list.
+ int GetHeight() const;
+
+ // Returns the baseline of this font list, which is max(baseline) for all the
+ // fonts in the font list.
+ int GetBaseline() const;
+
+ // Returns the cap height of this font list.
+ // Currently returns the cap height of the primary font.
+ int GetCapHeight() const;
+
+ // Returns the expected number of horizontal pixels needed to display the
+ // specified length of characters. Call GetStringWidth() to retrieve the
+ // actual number.
+ int GetExpectedTextWidth(int length) const;
+
+ // Returns the |gfx::Font::FontStyle| style flags for this font list.
+ int GetFontStyle() const;
+
+ // Returns a string representing font names, styles, and size. If the
+ // FontListImpl is initialized by a vector of Font, use the first font's style
+ // and size for the description.
+ const std::string& GetFontDescriptionString() const;
+
+ // Returns the font size in pixels.
+ int GetFontSize() const;
+
+ // Returns the Font vector.
+ const std::vector<Font>& GetFonts() const;
+
+ // Returns the first font in the list.
+ const Font& GetPrimaryFont() const;
+
+ private:
+ friend class base::RefCounted<FontListImpl>;
+
+ ~FontListImpl();
+
+ // Extracts common font height and baseline into |common_height_| and
+ // |common_baseline_|.
+ void CacheCommonFontHeightAndBaseline() const;
+
+ // Extracts font style and size into |font_style_| and |font_size_|.
+ void CacheFontStyleAndSize() const;
+
+ // A vector of Font. If FontListImpl is constructed with font description
+ // string, |fonts_| is not initialized during construction. Instead, it is
+ // computed lazily when user asked to get the font vector.
+ mutable std::vector<Font> fonts_;
+
+ // A string representing font names, styles, and sizes.
+ // Please refer to the comments before class declaration for details on string
+ // format.
+ // If FontListImpl is constructed with a vector of font,
+ // |font_description_string_| is not initialized during construction. Instead,
+ // it is computed lazily when user asked to get the font description string.
+ mutable std::string font_description_string_;
+
+ // The cached common height and baseline of the fonts in the font list.
+ mutable int common_height_;
+ mutable int common_baseline_;
+
+ // Cached font style and size.
+ mutable int font_style_;
+ mutable int font_size_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_FONT_LIST_IMPL_H_
diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc
index 6cbb41fbecd..b96de46318b 100644
--- a/chromium/ui/gfx/font_list_unittest.cc
+++ b/chromium/ui/gfx/font_list_unittest.cc
@@ -24,6 +24,8 @@ std::string FontToString(const gfx::Font& font) {
font_string += "|bold";
if (style & gfx::Font::ITALIC)
font_string += "|italic";
+ if (style & gfx::Font::UNDERLINE)
+ font_string += "|underline";
return font_string;
}
@@ -43,9 +45,10 @@ TEST(FontListTest, FontDescString_FromFontNamesStyleAndSize) {
std::vector<std::string> font_names;
font_names.push_back("Arial");
font_names.push_back("Droid Sans serif");
- int font_style = Font::BOLD | Font::ITALIC;
+ int font_style = Font::BOLD | Font::ITALIC | Font::UNDERLINE;
int font_size = 11;
FontList font_list = FontList(font_names, font_style, font_size);
+ // "Underline" doesn't appear in the font description string.
EXPECT_EQ("Arial,Droid Sans serif,Bold Italic 11px",
font_list.GetFontDescriptionString());
}
@@ -60,11 +63,15 @@ TEST(FontListTest, FontDescString_FromFont) {
TEST(FontListTest, FontDescString_FromFontWithNonNormalStyle) {
// Test init from Font with non-normal style.
Font font("Arial", 8);
- FontList font_list = FontList(font.DeriveFont(2, Font::BOLD));
+ FontList font_list = FontList(font.Derive(2, Font::BOLD));
EXPECT_EQ("Arial,Bold 10px", font_list.GetFontDescriptionString());
- font_list = FontList(font.DeriveFont(-2, Font::ITALIC));
+ font_list = FontList(font.Derive(-2, Font::ITALIC));
EXPECT_EQ("Arial,Italic 6px", font_list.GetFontDescriptionString());
+
+ // "Underline" doesn't appear in the font description string.
+ font_list = FontList(font.Derive(-4, Font::UNDERLINE));
+ EXPECT_EQ("Arial,4px", font_list.GetFontDescriptionString());
}
TEST(FontListTest, FontDescString_FromFontVector) {
@@ -72,8 +79,8 @@ TEST(FontListTest, FontDescString_FromFontVector) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> fonts;
- fonts.push_back(font.DeriveFont(0, Font::BOLD));
- fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ fonts.push_back(font.Derive(0, Font::BOLD));
+ fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(fonts);
EXPECT_EQ("Arial,Sans serif,Bold 8px", font_list.GetFontDescriptionString());
}
@@ -118,12 +125,12 @@ TEST(FontListTest, Fonts_FromFont) {
TEST(FontListTest, Fonts_FromFontWithNonNormalStyle) {
// Test init from Font with non-normal style.
Font font("Arial", 8);
- FontList font_list = FontList(font.DeriveFont(2, Font::BOLD));
+ FontList font_list = FontList(font.Derive(2, Font::BOLD));
std::vector<Font> fonts = font_list.GetFonts();
EXPECT_EQ(1U, fonts.size());
EXPECT_EQ("Arial|10|bold", FontToString(fonts[0]));
- font_list = FontList(font.DeriveFont(-2, Font::ITALIC));
+ font_list = FontList(font.Derive(-2, Font::ITALIC));
fonts = font_list.GetFonts();
EXPECT_EQ(1U, fonts.size());
EXPECT_EQ("Arial|6|italic", FontToString(fonts[0]));
@@ -134,8 +141,8 @@ TEST(FontListTest, Fonts_FromFontVector) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> input_fonts;
- input_fonts.push_back(font.DeriveFont(0, Font::BOLD));
- input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ input_fonts.push_back(font.Derive(0, Font::BOLD));
+ input_fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(input_fonts);
const std::vector<Font>& fonts = font_list.GetFonts();
EXPECT_EQ(2U, fonts.size());
@@ -161,8 +168,8 @@ TEST(FontListTest, Fonts_FontVector_RoundTrip) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> input_fonts;
- input_fonts.push_back(font.DeriveFont(0, Font::BOLD));
- input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ input_fonts.push_back(font.Derive(0, Font::BOLD));
+ input_fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(input_fonts);
const std::string& desc_string = font_list.GetFontDescriptionString();
@@ -194,71 +201,54 @@ TEST(FontListTest, Fonts_GetStyle) {
fonts.push_back(gfx::Font("Sans serif", 8));
FontList font_list = FontList(fonts);
EXPECT_EQ(Font::NORMAL, font_list.GetFontStyle());
- fonts[0] = fonts[0].DeriveFont(0, Font::ITALIC | Font::BOLD);
- fonts[1] = fonts[1].DeriveFont(0, Font::ITALIC | Font::BOLD);
+ fonts[0] = fonts[0].Derive(0, Font::ITALIC | Font::BOLD);
+ fonts[1] = fonts[1].Derive(0, Font::ITALIC | Font::BOLD);
font_list = FontList(fonts);
EXPECT_EQ(Font::ITALIC | Font::BOLD, font_list.GetFontStyle());
}
-TEST(FontListTest, FontDescString_DeriveFontList) {
- FontList font_list = FontList("Arial,Sans serif, 8px");
-
- FontList derived = font_list.DeriveFontList(Font::BOLD | Font::ITALIC);
- EXPECT_EQ("Arial,Sans serif,Bold Italic 8px",
- derived.GetFontDescriptionString());
-}
-
-TEST(FontListTest, Fonts_DeriveFontList) {
- std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 8));
- fonts.push_back(gfx::Font("Sans serif", 8));
- FontList font_list = FontList(fonts);
-
- FontList derived = font_list.DeriveFontList(Font::BOLD | Font::ITALIC);
- const std::vector<Font>& derived_fonts = derived.GetFonts();
-
- EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|8|bold|italic", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|8|bold|italic", FontToString(derived_fonts[1]));
-}
+TEST(FontListTest, FontDescString_Derive) {
+ FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
-TEST(FontListTest, FontDescString_DeriveFontListWithSize) {
- FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
+ FontList derived = font_list.Derive(10, Font::ITALIC | Font::UNDERLINE);
+ EXPECT_EQ("Arial,Sans serif,Italic 18px", derived.GetFontDescriptionString());
+ EXPECT_EQ(Font::ITALIC | Font::UNDERLINE, derived.GetFontStyle());
- FontList derived = font_list.DeriveFontListWithSize(10);
- EXPECT_EQ("Arial,Sans serif,Bold Italic 10px",
- derived.GetFontDescriptionString());
+ // FontList has a special case for Font::UNDERLINE. See if the handling of
+ // Font::UNDERLINE in GetFonts() is okay or not.
+ derived.GetFonts();
+ EXPECT_EQ(Font::ITALIC | Font::UNDERLINE, derived.GetFontStyle());
}
-TEST(FontListTest, Fonts_DeriveFontListWithSize) {
+TEST(FontListTest, Fonts_Derive) {
std::vector<Font> fonts;
fonts.push_back(gfx::Font("Arial", 8));
fonts.push_back(gfx::Font("Sans serif", 8));
FontList font_list = FontList(fonts);
- FontList derived = font_list.DeriveFontListWithSize(5);
+ FontList derived = font_list.Derive(5, Font::BOLD | Font::UNDERLINE);
const std::vector<Font>& derived_fonts = derived.GetFonts();
EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|5", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|5", FontToString(derived_fonts[1]));
+ EXPECT_EQ("Arial|13|bold|underline", FontToString(derived_fonts[0]));
+ EXPECT_EQ("Sans serif|13|bold|underline", FontToString(derived_fonts[1]));
}
-TEST(FontListTest, FontDescString_DeriveFontListWithSizeDelta) {
+TEST(FontListTest, FontDescString_DeriveWithSizeDelta) {
FontList font_list = FontList("Arial,Sans serif,Bold 18px");
- FontList derived = font_list.DeriveFontListWithSizeDelta(-8);
+ FontList derived = font_list.DeriveWithSizeDelta(-8);
EXPECT_EQ("Arial,Sans serif,Bold 10px",
derived.GetFontDescriptionString());
}
-TEST(FontListTest, Fonts_DeriveFontListWithSizeDelta) {
+TEST(FontListTest, Fonts_DeriveWithSizeDelta) {
std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 18).DeriveFont(0, Font::ITALIC));
- fonts.push_back(gfx::Font("Sans serif", 18).DeriveFont(0, Font::ITALIC));
+ fonts.push_back(gfx::Font("Arial", 18).Derive(0, Font::ITALIC));
+ fonts.push_back(gfx::Font("Sans serif", 18).Derive(0, Font::ITALIC));
FontList font_list = FontList(fonts);
- FontList derived = font_list.DeriveFontListWithSizeDelta(-5);
+ FontList derived = font_list.DeriveWithSizeDelta(-5);
const std::vector<Font>& derived_fonts = derived.GetFonts();
EXPECT_EQ(2U, derived_fonts.size());
@@ -266,30 +256,6 @@ TEST(FontListTest, Fonts_DeriveFontListWithSizeDelta) {
EXPECT_EQ("Sans serif|13|italic", FontToString(derived_fonts[1]));
}
-TEST(FontListTest, FontDescString_DeriveFontListWithSizeDeltaAndStyle) {
- FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
-
- FontList derived =
- font_list.DeriveFontListWithSizeDeltaAndStyle(10, Font::ITALIC);
- EXPECT_EQ("Arial,Sans serif,Italic 18px",
- derived.GetFontDescriptionString());
-}
-
-TEST(FontListTest, Fonts_DeriveFontListWithSizeDeltaAndStyle) {
- std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 8));
- fonts.push_back(gfx::Font("Sans serif", 8));
- FontList font_list = FontList(fonts);
-
- FontList derived =
- font_list.DeriveFontListWithSizeDeltaAndStyle(5, Font::BOLD);
- const std::vector<Font>& derived_fonts = derived.GetFonts();
-
- EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|13|bold", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|13|bold", FontToString(derived_fonts[1]));
-}
-
TEST(FontListTest, Fonts_GetHeight_GetBaseline) {
// If a font list has only one font, the height and baseline must be the same.
Font font1("Arial", 16);
diff --git a/chromium/ui/gfx/font_render_params_linux.cc b/chromium/ui/gfx/font_render_params_linux.cc
index 2fb369a5d4c..fdef6a9926f 100644
--- a/chromium/ui/gfx/font_render_params_linux.cc
+++ b/chromium/ui/gfx/font_render_params_linux.cc
@@ -6,12 +6,13 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/switches.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#else
#include <fontconfig/fontconfig.h>
+
+#if defined(OS_LINUX) && defined(USE_AURA) && !defined(OS_CHROMEOS)
+#include "ui/gfx/linux_font_delegate.h"
#endif
namespace gfx {
@@ -19,67 +20,21 @@ namespace gfx {
namespace {
bool SubpixelPositioningRequested(bool renderer) {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- renderer ?
- switches::kEnableWebkitTextSubpixelPositioning :
- switches::kEnableBrowserTextSubpixelPositioning);
+ const CommandLine* cl = CommandLine::ForCurrentProcess();
+ if (renderer) {
+ // Text rendered by Blink in high-DPI mode is poorly-hinted unless subpixel
+ // positioning is used (as opposed to each glyph being individually snapped
+ // to the pixel grid).
+ return cl->HasSwitch(switches::kEnableWebkitTextSubpixelPositioning) ||
+ (Display::HasForceDeviceScaleFactor() &&
+ Display::GetForcedDeviceScaleFactor() != 1.0);
+ }
+ return cl->HasSwitch(switches::kEnableBrowserTextSubpixelPositioning);
}
// Initializes |params| with the system's default settings. |renderer| is true
// when setting WebKit renderer defaults.
void LoadDefaults(FontRenderParams* params, bool renderer) {
-#if defined(TOOLKIT_GTK)
- params->antialiasing = true;
- // TODO(wangxianzhu): autohinter is now true to keep original behavior
- // of WebKit, but it might not be the best value.
- params->autohinter = true;
- params->use_bitmaps = true;
- params->hinting = FontRenderParams::HINTING_SLIGHT;
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
-
- GtkSettings* gtk_settings = gtk_settings_get_default();
- CHECK(gtk_settings);
- gint gtk_antialias = 0;
- gint gtk_hinting = 0;
- gchar* gtk_hint_style = NULL;
- gchar* gtk_rgba = NULL;
- g_object_get(gtk_settings,
- "gtk-xft-antialias", &gtk_antialias,
- "gtk-xft-hinting", &gtk_hinting,
- "gtk-xft-hintstyle", &gtk_hint_style,
- "gtk-xft-rgba", &gtk_rgba,
- NULL);
-
- // g_object_get() doesn't tell us whether the properties were present or not,
- // but if they aren't (because gnome-settings-daemon isn't running), we'll get
- // NULL values for the strings.
- if (gtk_hint_style && gtk_rgba) {
- params->antialiasing = gtk_antialias;
-
- if (gtk_hinting == 0 || strcmp(gtk_hint_style, "hintnone") == 0)
- params->hinting = FontRenderParams::HINTING_NONE;
- else if (strcmp(gtk_hint_style, "hintslight") == 0)
- params->hinting = FontRenderParams::HINTING_SLIGHT;
- else if (strcmp(gtk_hint_style, "hintmedium") == 0)
- params->hinting = FontRenderParams::HINTING_MEDIUM;
- else if (strcmp(gtk_hint_style, "hintfull") == 0)
- params->hinting = FontRenderParams::HINTING_FULL;
-
- if (strcmp(gtk_rgba, "none") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
- else if (strcmp(gtk_rgba, "rgb") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
- else if (strcmp(gtk_rgba, "bgr") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_BGR;
- else if (strcmp(gtk_rgba, "vrgb") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_VRGB;
- else if (strcmp(gtk_rgba, "vbgr") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_VBGR;
- }
-
- g_free(gtk_hint_style);
- g_free(gtk_rgba);
-#else
// For non-GTK builds (read: Aura), just use reasonable hardcoded values.
params->antialiasing = true;
params->autohinter = true;
@@ -114,6 +69,14 @@ void LoadDefaults(FontRenderParams* params, bool renderer) {
default:
params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
}
+
+#if defined(OS_LINUX) && defined(USE_AURA) && !defined(OS_CHROMEOS)
+ const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
+ if (delegate) {
+ params->antialiasing = delegate->UseAntialiasing();
+ params->hinting = delegate->GetHintingStyle();
+ params->subpixel_rendering = delegate->GetSubpixelRenderingStyle();
+ }
#endif
params->subpixel_positioning = SubpixelPositioningRequested(renderer);
diff --git a/chromium/ui/gfx/font_smoothing_win.cc b/chromium/ui/gfx/font_smoothing_win.cc
index b181fb564e8..78309ff3d96 100644
--- a/chromium/ui/gfx/font_smoothing_win.cc
+++ b/chromium/ui/gfx/font_smoothing_win.cc
@@ -36,7 +36,7 @@ class CachedFontSmoothingSettings : public gfx::SingletonHwnd::Observer {
// Queries the font settings from the system.
void QueryFontSettings();
- // Indicates whether the MessagePumpObserver has been registered.
+ // Indicates whether the SingletonHwnd::Observer has been registered.
bool observer_added_;
// Indicates whether |smoothing_enabled_| and |cleartype_enabled_| are valid
diff --git a/chromium/ui/gfx/font_unittest.cc b/chromium/ui/gfx/font_unittest.cc
index 2fdaab872f4..da4bdfcc4bd 100644
--- a/chromium/ui/gfx/font_unittest.cc
+++ b/chromium/ui/gfx/font_unittest.cc
@@ -70,7 +70,7 @@ TEST_F(FontTest, LoadArial) {
TEST_F(FontTest, LoadArialBold) {
Font cf("Arial", 16);
- Font bold(cf.DeriveFont(0, Font::BOLD));
+ Font bold(cf.Derive(0, Font::BOLD));
NativeFont native = bold.GetNativeFont();
EXPECT_TRUE(native);
EXPECT_EQ(bold.GetStyle(), Font::BOLD);
@@ -95,11 +95,7 @@ TEST_F(FontTest, CapHeight) {
Font cf("Arial", 16);
EXPECT_GT(cf.GetCapHeight(), 0);
EXPECT_GT(cf.GetCapHeight(), cf.GetHeight() / 2);
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
- EXPECT_EQ(cf.GetCapHeight(), cf.GetBaseline());
-#else
EXPECT_LT(cf.GetCapHeight(), cf.GetBaseline());
-#endif
}
TEST_F(FontTest, AvgWidths) {
@@ -110,30 +106,26 @@ TEST_F(FontTest, AvgWidths) {
EXPECT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2));
}
-TEST_F(FontTest, AvgCharWidth) {
- Font cf("Arial", 16);
- EXPECT_GT(cf.GetAverageCharacterWidth(), 0);
-}
-
-TEST_F(FontTest, Widths) {
- Font cf("Arial", 16);
- EXPECT_EQ(cf.GetStringWidth(base::string16()), 0);
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("a")),
- cf.GetStringWidth(base::string16()));
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("ab")),
- cf.GetStringWidth(ASCIIToUTF16("a")));
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("abc")),
- cf.GetStringWidth(ASCIIToUTF16("ab")));
-}
-
#if !defined(OS_WIN)
// On Windows, Font::GetActualFontNameForTesting() doesn't work well for now.
// http://crbug.com/327287
+//
+// Check that fonts used for testing are installed and enabled. On Mac
+// fonts may be installed but still need enabling in Font Book.app.
+// http://crbug.com/347429
TEST_F(FontTest, GetActualFontNameForTesting) {
Font arial("Arial", 16);
- EXPECT_EQ("arial", StringToLowerASCII(arial.GetActualFontNameForTesting()));
+ EXPECT_EQ("arial", StringToLowerASCII(arial.GetActualFontNameForTesting()))
+ << "********\n"
+ << "Your test environment seems to be missing Arial font, which is "
+ << "needed for unittests. Check if Arial font is installed.\n"
+ << "********";
Font symbol("Symbol", 16);
- EXPECT_EQ("symbol", StringToLowerASCII(symbol.GetActualFontNameForTesting()));
+ EXPECT_EQ("symbol", StringToLowerASCII(symbol.GetActualFontNameForTesting()))
+ << "********\n"
+ << "Your test environment seems to be missing Symbol font, which is "
+ << "needed for unittests. Check if Symbol font is installed.\n"
+ << "********";
const char* const invalid_font_name = "no_such_font_name";
Font fallback_font(invalid_font_name, 16);
@@ -143,21 +135,21 @@ TEST_F(FontTest, GetActualFontNameForTesting) {
#endif
#if defined(OS_WIN)
-TEST_F(FontTest, DeriveFontResizesIfSizeTooSmall) {
+TEST_F(FontTest, DeriveResizesIfSizeTooSmall) {
Font cf("Arial", 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
- Font derived_font = cf.DeriveFont(-4);
+ Font derived_font = cf.Derive(-4, cf.GetStyle());
EXPECT_EQ(5, derived_font.GetFontSize());
}
-TEST_F(FontTest, DeriveFontKeepsOriginalSizeIfHeightOk) {
+TEST_F(FontTest, DeriveKeepsOriginalSizeIfHeightOk) {
Font cf("Arial", 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
- Font derived_font = cf.DeriveFont(-2);
+ Font derived_font = cf.Derive(-2, cf.GetStyle());
EXPECT_EQ(6, derived_font.GetFontSize());
}
#endif // defined(OS_WIN)
diff --git a/chromium/ui/gfx/gdi_util.cc b/chromium/ui/gfx/gdi_util.cc
index 88c09355a28..dc7d83f37cf 100644
--- a/chromium/ui/gfx/gdi_util.cc
+++ b/chromium/ui/gfx/gdi_util.cc
@@ -85,8 +85,8 @@ HRGN ConvertPathToHRGN(const gfx::Path& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<POINT[]> windows_points(new POINT[point_count]);
for (int i = 0; i < point_count; ++i) {
- windows_points[i].x = SkScalarRound(points[i].fX);
- windows_points[i].y = SkScalarRound(points[i].fY);
+ windows_points[i].x = SkScalarRoundToInt(points[i].fX);
+ windows_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return ::CreatePolygonRgn(windows_points.get(), point_count, ALTERNATE);
diff --git a/chromium/ui/gfx/gdk_compat.h b/chromium/ui/gfx/gdk_compat.h
deleted file mode 100644
index b11d7795831..00000000000
--- a/chromium/ui/gfx/gdk_compat.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GDK_COMPAT_H_
-#define UI_GFX_GDK_COMPAT_H_
-
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-
-// Google Chrome must depend on GTK 2.18, at least until the next LTS drops
-// (and we might have to extend which version of GTK we want to target due to
-// RHEL). To make our porting job for GTK3 easier, we define all the methods
-// that replace deprecated APIs in this file and then include it everywhere.
-//
-// This file is organized first by version, and then with each version,
-// alphabetically by method.
-
-#if !GTK_CHECK_VERSION(2, 24, 0)
-inline GdkWindow* gdk_x11_window_lookup_for_display(GdkDisplay* display,
- Window window) {
- return static_cast<GdkWindow*>(gdk_xid_table_lookup_for_display(display,
- window));
-}
-#endif
-
-#endif // UI_GFX_GDK_COMPAT_H_
diff --git a/chromium/ui/gfx/geometry/BUILD.gn b/chromium/ui/gfx/geometry/BUILD.gn
new file mode 100644
index 00000000000..b7c877ac108
--- /dev/null
+++ b/chromium/ui/gfx/geometry/BUILD.gn
@@ -0,0 +1,62 @@
+# 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.
+
+component("geometry") {
+ sources = [
+ "../gfx_export.h",
+ "box_f.cc",
+ "box_f.h",
+ "cubic_bezier.h",
+ "cubic_bezier.cc",
+ "insets.cc",
+ "insets.h",
+ "insets_base.h",
+ "insets_f.cc",
+ "insets_f.h",
+ "matrix3_f.cc",
+ "matrix3_f.h",
+ "point.cc",
+ "point.h",
+ "point3_f.cc",
+ "point3_f.h",
+ "point_base.h",
+ "point_conversions.cc",
+ "point_conversions.h",
+ "point_f.cc",
+ "point_f.h",
+ "quad_f.cc",
+ "quad_f.h",
+ "rect.cc",
+ "rect.h",
+ "rect_base.h",
+ "rect_base_impl.h",
+ "rect_conversions.cc",
+ "rect_conversions.h",
+ "rect_f.cc",
+ "rect_f.h",
+ "safe_integer_conversions.h",
+ "size.cc",
+ "size.h",
+ "size_base.h",
+ "size_conversions.cc",
+ "size_conversions.h",
+ "size_f.cc",
+ "size_f.h",
+ "vector2d.cc",
+ "vector2d.h",
+ "vector2d_conversions.cc",
+ "vector2d_conversions.h",
+ "vector2d_f.cc",
+ "vector2d_f.h",
+ "vector3d_f.cc",
+ "vector3d_f.h",
+ ]
+
+ defines = [ "GFX_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//ui/gfx:gfx_export",
+ ]
+}
diff --git a/chromium/ui/gfx/geometry/box_f.cc b/chromium/ui/gfx/geometry/box_f.cc
new file mode 100644
index 00000000000..674bb509c88
--- /dev/null
+++ b/chromium/ui/gfx/geometry/box_f.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/box_f.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+std::string BoxF::ToString() const {
+ return base::StringPrintf("%s %fx%fx%f",
+ origin().ToString().c_str(),
+ width_,
+ height_,
+ depth_);
+}
+
+bool BoxF::IsEmpty() const {
+ return (width_ == 0 && height_ == 0) ||
+ (width_ == 0 && depth_ == 0) ||
+ (height_ == 0 && depth_ == 0);
+}
+
+void BoxF::ExpandTo(const Point3F& min, const Point3F& max) {
+ DCHECK_LE(min.x(), max.x());
+ DCHECK_LE(min.y(), max.y());
+ DCHECK_LE(min.z(), max.z());
+
+ float min_x = std::min(x(), min.x());
+ float min_y = std::min(y(), min.y());
+ float min_z = std::min(z(), min.z());
+ float max_x = std::max(right(), max.x());
+ float max_y = std::max(bottom(), max.y());
+ float max_z = std::max(front(), max.z());
+
+ origin_.SetPoint(min_x, min_y, min_z);
+ width_ = max_x - min_x;
+ height_ = max_y - min_y;
+ depth_ = max_z - min_z;
+}
+
+void BoxF::Union(const BoxF& box) {
+ if (IsEmpty()) {
+ *this = box;
+ return;
+ }
+ if (box.IsEmpty())
+ return;
+ ExpandTo(box);
+}
+
+void BoxF::ExpandTo(const Point3F& point) {
+ ExpandTo(point, point);
+}
+
+void BoxF::ExpandTo(const BoxF& box) {
+ ExpandTo(box.origin(), gfx::Point3F(box.right(), box.bottom(), box.front()));
+}
+
+BoxF UnionBoxes(const BoxF& a, const BoxF& b) {
+ BoxF result = a;
+ result.Union(b);
+ return result;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/box_f.h b/chromium/ui/gfx/geometry/box_f.h
new file mode 100644
index 00000000000..13fb9d0d47b
--- /dev/null
+++ b/chromium/ui/gfx/geometry/box_f.h
@@ -0,0 +1,160 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_BOX_F_H_
+#define UI_GFX_GEOMETRY_BOX_F_H_
+
+#include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+
+// A 3d version of gfx::RectF, with the positive z-axis pointed towards
+// the camera.
+class GFX_EXPORT BoxF {
+ public:
+ BoxF()
+ : width_(0.f),
+ height_(0.f),
+ depth_(0.f) {}
+
+ BoxF(float width, float height, float depth)
+ : width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ BoxF(float x, float y, float z, float width, float height, float depth)
+ : origin_(x, y, z),
+ width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ BoxF(const Point3F& origin, float width, float height, float depth)
+ : origin_(origin),
+ width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ ~BoxF() {}
+
+ // Scales all three axes by the given scale.
+ void Scale(float scale) {
+ Scale(scale, scale, scale);
+ }
+
+ // Scales each axis by the corresponding given scale.
+ void Scale(float x_scale, float y_scale, float z_scale) {
+ origin_.Scale(x_scale, y_scale, z_scale);
+ set_size(width_ * x_scale, height_ * y_scale, depth_ * z_scale);
+ }
+
+ // Moves the box by the specified distance in each dimension.
+ void operator+=(const Vector3dF& offset) {
+ origin_ += offset;
+ }
+
+ // Returns true if the box has no interior points.
+ bool IsEmpty() const;
+
+ // Computes the union of this box with the given box. The union is the
+ // smallest box that contains both boxes.
+ void Union(const BoxF& box);
+
+ std::string ToString() const;
+
+ float x() const { return origin_.x(); }
+ void set_x(float x) { origin_.set_x(x); }
+
+ float y() const { return origin_.y(); }
+ void set_y(float y) { origin_.set_y(y); }
+
+ float z() const { return origin_.z(); }
+ void set_z(float z) { origin_.set_z(z); }
+
+ float width() const { return width_; }
+ void set_width(float width) { width_ = width < 0 ? 0 : width; }
+
+ float height() const { return height_; }
+ void set_height(float height) { height_ = height < 0 ? 0 : height; }
+
+ float depth() const { return depth_; }
+ void set_depth(float depth) { depth_ = depth < 0 ? 0 : depth; }
+
+ float right() const { return x() + width(); }
+ float bottom() const { return y() + height(); }
+ float front() const { return z() + depth(); }
+
+ void set_size(float width, float height, float depth) {
+ width_ = width < 0 ? 0 : width;
+ height_ = height < 0 ? 0 : height;
+ depth_ = depth < 0 ? 0 : depth;
+ }
+
+ const Point3F& origin() const { return origin_; }
+ void set_origin(const Point3F& origin) { origin_ = origin; }
+
+ // Expands |this| to contain the given point, if necessary. Please note, even
+ // if |this| is empty, after the function |this| will continue to contain its
+ // |origin_|.
+ void ExpandTo(const Point3F& point);
+
+ // Expands |this| to contain the given box, if necessary. Please note, even
+ // if |this| is empty, after the function |this| will continue to contain its
+ // |origin_|.
+ void ExpandTo(const BoxF& box);
+
+ private:
+ // Expands the box to contain the two given points. It is required that each
+ // component of |min| is less than or equal to the corresponding component in
+ // |max|. Precisely, what this function does is ensure that after the function
+ // completes, |this| contains origin_, min, max, and origin_ + (width_,
+ // height_, depth_), even if the box is empty. Emptiness checks are handled in
+ // the public function Union.
+ void ExpandTo(const Point3F& min, const Point3F& max);
+
+ Point3F origin_;
+ float width_;
+ float height_;
+ float depth_;
+};
+
+GFX_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b);
+
+inline BoxF ScaleBox(const BoxF& b,
+ float x_scale,
+ float y_scale,
+ float z_scale) {
+ return BoxF(b.x() * x_scale,
+ b.y() * y_scale,
+ b.z() * z_scale,
+ b.width() * x_scale,
+ b.height() * y_scale,
+ b.depth() * z_scale);
+}
+
+inline BoxF ScaleBox(const BoxF& b, float scale) {
+ return ScaleBox(b, scale, scale, scale);
+}
+
+inline bool operator==(const BoxF& a, const BoxF& b) {
+ return a.origin() == b.origin() && a.width() == b.width() &&
+ a.height() == b.height() && a.depth() == b.depth();
+}
+
+inline bool operator!=(const BoxF& a, const BoxF& b) {
+ return !(a == b);
+}
+
+inline BoxF operator+(const BoxF& b, const Vector3dF& v) {
+ return BoxF(b.x() + v.x(),
+ b.y() + v.y(),
+ b.z() + v.z(),
+ b.width(),
+ b.height(),
+ b.depth());
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_BOX_F_H_
diff --git a/chromium/ui/gfx/geometry/box_unittest.cc b/chromium/ui/gfx/geometry/box_unittest.cc
new file mode 100644
index 00000000000..449c50f9a48
--- /dev/null
+++ b/chromium/ui/gfx/geometry/box_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/box_f.h"
+
+namespace gfx {
+
+TEST(BoxTest, Constructors) {
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).ToString(),
+ BoxF().ToString());
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, -3.f, -5.f, -7.f).ToString(),
+ BoxF().ToString());
+
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 3.f, 5.f, 7.f).ToString(),
+ BoxF(3.f, 5.f, 7.f).ToString());
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).ToString(),
+ BoxF(-3.f, -5.f, -7.f).ToString());
+
+ EXPECT_EQ(BoxF(2.f, 4.f, 6.f, 3.f, 5.f, 7.f).ToString(),
+ BoxF(Point3F(2.f, 4.f, 6.f), 3.f, 5.f, 7.f).ToString());
+ EXPECT_EQ(BoxF(2.f, 4.f, 6.f, 0.f, 0.f, 0.f).ToString(),
+ BoxF(Point3F(2.f, 4.f, 6.f), -3.f, -5.f, -7.f).ToString());
+}
+
+TEST(BoxTest, IsEmpty) {
+ EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 0.f).IsEmpty());
+ EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 0.f, 0.f).IsEmpty());
+
+ EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 2.f, 0.f, 0.f).IsEmpty());
+ EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 2.f, 0.f, 0.f).IsEmpty());
+ EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 2.f, 0.f).IsEmpty());
+ EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 2.f, 0.f).IsEmpty());
+ EXPECT_TRUE(BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 2.f).IsEmpty());
+ EXPECT_TRUE(BoxF(1.f, 2.f, 3.f, 0.f, 0.f, 2.f).IsEmpty());
+
+ EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 0.f, 2.f, 2.f).IsEmpty());
+ EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 0.f, 2.f, 2.f).IsEmpty());
+ EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 0.f, 2.f).IsEmpty());
+ EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 0.f, 2.f).IsEmpty());
+ EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 2.f, 0.f).IsEmpty());
+ EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 2.f, 0.f).IsEmpty());
+
+ EXPECT_FALSE(BoxF(0.f, 0.f, 0.f, 2.f, 2.f, 2.f).IsEmpty());
+ EXPECT_FALSE(BoxF(1.f, 2.f, 3.f, 2.f, 2.f, 2.f).IsEmpty());
+}
+
+TEST(BoxTest, Union) {
+ BoxF empty_box;
+ BoxF box1(0.f, 0.f, 0.f, 1.f, 1.f, 1.f);
+ BoxF box2(0.f, 0.f, 0.f, 4.f, 6.f, 8.f);
+ BoxF box3(3.f, 4.f, 5.f, 6.f, 4.f, 0.f);
+
+ EXPECT_EQ(empty_box.ToString(), UnionBoxes(empty_box, empty_box).ToString());
+ EXPECT_EQ(box1.ToString(), UnionBoxes(empty_box, box1).ToString());
+ EXPECT_EQ(box1.ToString(), UnionBoxes(box1, empty_box).ToString());
+ EXPECT_EQ(box2.ToString(), UnionBoxes(empty_box, box2).ToString());
+ EXPECT_EQ(box2.ToString(), UnionBoxes(box2, empty_box).ToString());
+ EXPECT_EQ(box3.ToString(), UnionBoxes(empty_box, box3).ToString());
+ EXPECT_EQ(box3.ToString(), UnionBoxes(box3, empty_box).ToString());
+
+ // box_1 is contained in box_2
+ EXPECT_EQ(box2.ToString(), UnionBoxes(box1, box2).ToString());
+ EXPECT_EQ(box2.ToString(), UnionBoxes(box2, box1).ToString());
+
+ // box_1 and box_3 are disjoint
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 5.f).ToString(),
+ UnionBoxes(box1, box3).ToString());
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 5.f).ToString(),
+ UnionBoxes(box3, box1).ToString());
+
+ // box_2 and box_3 intersect, but neither contains the other
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 8.f).ToString(),
+ UnionBoxes(box2, box3).ToString());
+ EXPECT_EQ(BoxF(0.f, 0.f, 0.f, 9.f, 8.f, 8.f).ToString(),
+ UnionBoxes(box3, box2).ToString());
+}
+
+TEST(BoxTest, ExpandTo) {
+ BoxF box1;
+ BoxF box2(0.f, 0.f, 0.f, 1.f, 1.f, 1.f);
+ BoxF box3(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
+
+ Point3F point1(0.5f, 0.5f, 0.5f);
+ Point3F point2(-0.5f, -0.5f, -0.5f);
+
+ BoxF expected1_1(0.f, 0.f, 0.f, 0.5f, 0.5f, 0.5f);
+ BoxF expected1_2(-0.5f, -0.5f, -0.5f, 1.f, 1.f, 1.f);
+
+ BoxF expected2_1 = box2;
+ BoxF expected2_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f);
+
+ BoxF expected3_1(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
+ BoxF expected3_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f);
+
+ box1.ExpandTo(point1);
+ EXPECT_EQ(expected1_1.ToString(), box1.ToString());
+ box1.ExpandTo(point2);
+ EXPECT_EQ(expected1_2.ToString(), box1.ToString());
+
+ box2.ExpandTo(point1);
+ EXPECT_EQ(expected2_1.ToString(), box2.ToString());
+ box2.ExpandTo(point2);
+ EXPECT_EQ(expected2_2.ToString(), box2.ToString());
+
+ box3.ExpandTo(point1);
+ EXPECT_EQ(expected3_1.ToString(), box3.ToString());
+ box3.ExpandTo(point2);
+ EXPECT_EQ(expected3_2.ToString(), box3.ToString());
+}
+
+TEST(BoxTest, Scale) {
+ BoxF box1(2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
+
+ EXPECT_EQ(BoxF().ToString(), ScaleBox(box1, 0.f).ToString());
+ EXPECT_EQ(box1.ToString(), ScaleBox(box1, 1.f).ToString());
+ EXPECT_EQ(BoxF(4.f, 12.f, 24.f, 10.f, 24.f, 42.f).ToString(),
+ ScaleBox(box1, 2.f, 4.f, 6.f).ToString());
+
+ BoxF box2 = box1;
+ box2.Scale(0.f);
+ EXPECT_EQ(BoxF().ToString(), box2.ToString());
+
+ box2 = box1;
+ box2.Scale(1.f);
+ EXPECT_EQ(box1.ToString(), box2.ToString());
+
+ box2.Scale(2.f, 4.f, 6.f);
+ EXPECT_EQ(BoxF(4.f, 12.f, 24.f, 10.f, 24.f, 42.f).ToString(),
+ box2.ToString());
+}
+
+TEST(BoxTest, Equals) {
+ EXPECT_TRUE(BoxF() == BoxF());
+ EXPECT_TRUE(BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f) ==
+ BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f));
+ EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 1.f));
+ EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 0.f, 1.f, 0.f));
+ EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 0.f, 1.f, 0.f, 0.f));
+ EXPECT_FALSE(BoxF() == BoxF(0.f, 0.f, 1.f, 0.f, 0.f, 0.f));
+ EXPECT_FALSE(BoxF() == BoxF(0.f, 1.f, 0.f, 0.f, 0.f, 0.f));
+ EXPECT_FALSE(BoxF() == BoxF(1.f, 0.f, 0.f, 0.f, 0.f, 0.f));
+}
+
+TEST(BoxTest, NotEquals) {
+ EXPECT_FALSE(BoxF() != BoxF());
+ EXPECT_FALSE(BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f) !=
+ BoxF(2.f, 3.f, 4.f, 6.f, 8.f, 10.f));
+ EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 0.f, 0.f, 1.f));
+ EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 0.f, 1.f, 0.f));
+ EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 0.f, 1.f, 0.f, 0.f));
+ EXPECT_TRUE(BoxF() != BoxF(0.f, 0.f, 1.f, 0.f, 0.f, 0.f));
+ EXPECT_TRUE(BoxF() != BoxF(0.f, 1.f, 0.f, 0.f, 0.f, 0.f));
+ EXPECT_TRUE(BoxF() != BoxF(1.f, 0.f, 0.f, 0.f, 0.f, 0.f));
+}
+
+
+TEST(BoxTest, Offset) {
+ BoxF box1(2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
+
+ EXPECT_EQ(box1.ToString(), (box1 + Vector3dF(0.f, 0.f, 0.f)).ToString());
+ EXPECT_EQ(BoxF(3.f, 1.f, 0.f, 5.f, 6.f, 7.f).ToString(),
+ (box1 + Vector3dF(1.f, -2.f, -4.f)).ToString());
+
+ BoxF box2 = box1;
+ box2 += Vector3dF(0.f, 0.f, 0.f);
+ EXPECT_EQ(box1.ToString(), box2.ToString());
+
+ box2 += Vector3dF(1.f, -2.f, -4.f);
+ EXPECT_EQ(BoxF(3.f, 1.f, 0.f, 5.f, 6.f, 7.f).ToString(),
+ box2.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/cubic_bezier.cc b/chromium/ui/gfx/geometry/cubic_bezier.cc
new file mode 100644
index 00000000000..3d7e8fe9303
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier.cc
@@ -0,0 +1,128 @@
+// 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/gfx/geometry/cubic_bezier.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace gfx {
+
+namespace {
+
+static const double kBezierEpsilon = 1e-7;
+static const int MAX_STEPS = 30;
+
+static double eval_bezier(double x1, double x2, double t) {
+ const double x1_times_3 = 3.0 * x1;
+ const double x2_times_3 = 3.0 * x2;
+ const double h3 = x1_times_3;
+ const double h1 = x1_times_3 - x2_times_3 + 1.0;
+ const double h2 = x2_times_3 - 6.0 * x1;
+ return t * (t * (t * h1 + h2) + h3);
+}
+
+static double bezier_interp(double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x) {
+ DCHECK_GE(1.0, x1);
+ DCHECK_LE(0.0, x1);
+ DCHECK_GE(1.0, x2);
+ DCHECK_LE(0.0, x2);
+
+ x1 = std::min(std::max(x1, 0.0), 1.0);
+ x2 = std::min(std::max(x2, 0.0), 1.0);
+ x = std::min(std::max(x, 0.0), 1.0);
+
+ // Step 1. Find the t corresponding to the given x. I.e., we want t such that
+ // eval_bezier(x1, x2, t) = x. There is a unique solution if x1 and x2 lie
+ // within (0, 1).
+ //
+ // We're just going to do bisection for now (for simplicity), but we could
+ // easily do some newton steps if this turns out to be a bottleneck.
+ double t = 0.0;
+ double step = 1.0;
+ for (int i = 0; i < MAX_STEPS; ++i, step *= 0.5) {
+ const double error = eval_bezier(x1, x2, t) - x;
+ if (std::abs(error) < kBezierEpsilon)
+ break;
+ t += error > 0.0 ? -step : step;
+ }
+
+ // We should have terminated the above loop because we got close to x, not
+ // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
+ DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
+
+ // Step 2. Return the interpolated y values at the t we computed above.
+ return eval_bezier(y1, y2, t);
+}
+
+} // namespace
+
+CubicBezier::CubicBezier(double x1, double y1, double x2, double y2)
+ : x1_(x1),
+ y1_(y1),
+ x2_(x2),
+ y2_(y2) {
+}
+
+CubicBezier::~CubicBezier() {
+}
+
+double CubicBezier::Solve(double x) const {
+ return bezier_interp(x1_, y1_, x2_, y2_, x);
+}
+
+void CubicBezier::Range(double* min, double* max) const {
+ *min = 0;
+ *max = 1;
+ if (0 <= y1_ && y1_ < 1 && 0 <= y2_ && y2_ <= 1)
+ return;
+
+ // Represent the function's derivative in the form at^2 + bt + c.
+ double a = 3 * (y1_ - y2_) + 1;
+ double b = 2 * (y2_ - 2 * y1_);
+ double c = y1_;
+
+ // Check if the derivative is constant.
+ if (std::abs(a) < kBezierEpsilon &&
+ std::abs(b) < kBezierEpsilon)
+ return;
+
+ // Zeros of the function's derivative.
+ double t_1 = 0;
+ double t_2 = 0;
+
+ if (std::abs(a) < kBezierEpsilon) {
+ // The function's derivative is linear.
+ t_1 = -c / b;
+ } else {
+ // The function's derivative is a quadratic. We find the zeros of this
+ // quadratic using the quadratic formula.
+ double discriminant = b * b - 4 * a * c;
+ if (discriminant < 0)
+ return;
+ double discriminant_sqrt = sqrt(discriminant);
+ t_1 = (-b + discriminant_sqrt) / (2 * a);
+ t_2 = (-b - discriminant_sqrt) / (2 * a);
+ }
+
+ double sol_1 = 0;
+ double sol_2 = 0;
+
+ if (0 < t_1 && t_1 < 1)
+ sol_1 = eval_bezier(y1_, y2_, t_1);
+
+ if (0 < t_2 && t_2 < 1)
+ sol_2 = eval_bezier(y1_, y2_, t_2);
+
+ *min = std::min(std::min(*min, sol_1), sol_2);
+ *max = std::max(std::max(*max, sol_1), sol_2);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/cubic_bezier.h b/chromium/ui/gfx/geometry/cubic_bezier.h
new file mode 100644
index 00000000000..645dfb7106d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier.h
@@ -0,0 +1,36 @@
+// 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_GFX_GEOMETRY_CUBIC_BEZIER_H_
+#define UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
+
+#include "base/macros.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT CubicBezier {
+ public:
+ CubicBezier(double x1, double y1, double x2, double y2);
+ ~CubicBezier();
+
+ // Returns an approximation of y at the given x.
+ double Solve(double x) const;
+
+ // Sets |min| and |max| to the bezier's minimum and maximium y values in the
+ // interval [0, 1].
+ void Range(double* min, double* max) const;
+
+ private:
+ double x1_;
+ double y1_;
+ double x2_;
+ double y2_;
+
+ DISALLOW_ASSIGN(CubicBezier);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
diff --git a/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc b/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc
new file mode 100644
index 00000000000..4fd60e87825
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc
@@ -0,0 +1,140 @@
+// 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/gfx/geometry/cubic_bezier.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gfx {
+namespace {
+
+TEST(CubicBezierTest, Basic) {
+ CubicBezier function(0.25, 0.0, 0.75, 1.0);
+
+ double epsilon = 0.00015;
+
+ EXPECT_NEAR(function.Solve(0), 0, epsilon);
+ EXPECT_NEAR(function.Solve(0.05), 0.01136, epsilon);
+ EXPECT_NEAR(function.Solve(0.1), 0.03978, epsilon);
+ EXPECT_NEAR(function.Solve(0.15), 0.079780, epsilon);
+ EXPECT_NEAR(function.Solve(0.2), 0.12803, epsilon);
+ EXPECT_NEAR(function.Solve(0.25), 0.18235, epsilon);
+ EXPECT_NEAR(function.Solve(0.3), 0.24115, epsilon);
+ EXPECT_NEAR(function.Solve(0.35), 0.30323, epsilon);
+ EXPECT_NEAR(function.Solve(0.4), 0.36761, epsilon);
+ EXPECT_NEAR(function.Solve(0.45), 0.43345, epsilon);
+ EXPECT_NEAR(function.Solve(0.5), 0.5, epsilon);
+ EXPECT_NEAR(function.Solve(0.6), 0.63238, epsilon);
+ EXPECT_NEAR(function.Solve(0.65), 0.69676, epsilon);
+ EXPECT_NEAR(function.Solve(0.7), 0.75884, epsilon);
+ EXPECT_NEAR(function.Solve(0.75), 0.81764, epsilon);
+ EXPECT_NEAR(function.Solve(0.8), 0.87196, epsilon);
+ EXPECT_NEAR(function.Solve(0.85), 0.92021, epsilon);
+ EXPECT_NEAR(function.Solve(0.9), 0.96021, epsilon);
+ EXPECT_NEAR(function.Solve(0.95), 0.98863, epsilon);
+ EXPECT_NEAR(function.Solve(1), 1, epsilon);
+}
+
+// Tests that solving the bezier works with knots with y not in (0, 1).
+TEST(CubicBezierTest, UnclampedYValues) {
+ CubicBezier function(0.5, -1.0, 0.5, 2.0);
+
+ double epsilon = 0.00015;
+
+ EXPECT_NEAR(function.Solve(0.0), 0.0, epsilon);
+ EXPECT_NEAR(function.Solve(0.05), -0.08954, epsilon);
+ EXPECT_NEAR(function.Solve(0.1), -0.15613, epsilon);
+ EXPECT_NEAR(function.Solve(0.15), -0.19641, epsilon);
+ EXPECT_NEAR(function.Solve(0.2), -0.20651, epsilon);
+ EXPECT_NEAR(function.Solve(0.25), -0.18232, epsilon);
+ EXPECT_NEAR(function.Solve(0.3), -0.11992, epsilon);
+ EXPECT_NEAR(function.Solve(0.35), -0.01672, epsilon);
+ EXPECT_NEAR(function.Solve(0.4), 0.12660, epsilon);
+ EXPECT_NEAR(function.Solve(0.45), 0.30349, epsilon);
+ EXPECT_NEAR(function.Solve(0.5), 0.50000, epsilon);
+ EXPECT_NEAR(function.Solve(0.55), 0.69651, epsilon);
+ EXPECT_NEAR(function.Solve(0.6), 0.87340, epsilon);
+ EXPECT_NEAR(function.Solve(0.65), 1.01672, epsilon);
+ EXPECT_NEAR(function.Solve(0.7), 1.11992, epsilon);
+ EXPECT_NEAR(function.Solve(0.75), 1.18232, epsilon);
+ EXPECT_NEAR(function.Solve(0.8), 1.20651, epsilon);
+ EXPECT_NEAR(function.Solve(0.85), 1.19641, epsilon);
+ EXPECT_NEAR(function.Solve(0.9), 1.15613, epsilon);
+ EXPECT_NEAR(function.Solve(0.95), 1.08954, epsilon);
+ EXPECT_NEAR(function.Solve(1.0), 1.0, epsilon);
+}
+
+TEST(CubicBezierTest, Range) {
+ double epsilon = 0.00015;
+ double min, max;
+
+ // Derivative is a constant.
+ scoped_ptr<CubicBezier> function(
+ new CubicBezier(0.25, (1.0 / 3.0), 0.75, (2.0 / 3.0)));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative is linear.
+ function.reset(new CubicBezier(0.25, -0.5, 0.75, (-1.0 / 6.0)));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.225, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has no real roots.
+ function.reset(new CubicBezier(0.25, 0.25, 0.75, 0.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has exactly one real root.
+ function.reset(new CubicBezier(0.0, 1.0, 1.0, 0.0));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has one root < 0 and one root > 1.
+ function.reset(new CubicBezier(0.25, 0.1, 0.75, 0.9));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots in [0,1].
+ function.reset(new CubicBezier(0.25, 2.5, 0.75, 0.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_NEAR(max, 1.28818, epsilon);
+ function.reset(new CubicBezier(0.25, 0.5, 0.75, -1.5));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.28818, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has one root < 0 and one root in [0,1].
+ function.reset(new CubicBezier(0.25, 0.1, 0.75, 1.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_NEAR(max, 1.10755, epsilon);
+
+ // Derivative has one root in [0,1] and one root > 1.
+ function.reset(new CubicBezier(0.25, -0.5, 0.75, 0.9));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.10755, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots < 0.
+ function.reset(new CubicBezier(0.25, 0.3, 0.75, 0.633));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots > 1.
+ function.reset(new CubicBezier(0.25, 0.367, 0.75, 0.7));
+ function->Range(&min, &max);
+ EXPECT_EQ(0.f, min);
+ EXPECT_EQ(1.f, max);
+}
+
+} // namespace
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/insets.cc b/chromium/ui/gfx/geometry/insets.cc
new file mode 100644
index 00000000000..c29368e1bd9
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/insets.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class InsetsBase<Insets, int>;
+
+Insets::Insets() : InsetsBase<Insets, int>(0, 0, 0, 0) {}
+
+Insets::Insets(int top, int left, int bottom, int right)
+ : InsetsBase<Insets, int>(top, left, bottom, right) {}
+
+Insets::~Insets() {}
+
+std::string Insets::ToString() const {
+ // Print members in the same order of the constructor parameters.
+ return base::StringPrintf("%d,%d,%d,%d", top(), left(), bottom(), right());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/insets.h b/chromium/ui/gfx/geometry/insets.h
new file mode 100644
index 00000000000..00b612540dd
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_INSETS_H_
+#define UI_GFX_GEOMETRY_INSETS_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets_base.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// An integer version of gfx::Insets.
+class GFX_EXPORT Insets : public InsetsBase<Insets, int> {
+ public:
+ Insets();
+ Insets(int top, int left, int bottom, int right);
+
+ ~Insets();
+
+ Insets Scale(float scale) const {
+ return Scale(scale, scale);
+ }
+
+ Insets Scale(float x_scale, float y_scale) const {
+ return Insets(static_cast<int>(top() * y_scale),
+ static_cast<int>(left() * x_scale),
+ static_cast<int>(bottom() * y_scale),
+ static_cast<int>(right() * x_scale));
+ }
+
+ operator InsetsF() const {
+ return InsetsF(top(), left(), bottom(), right());
+ }
+
+ // Returns a string representation of the insets.
+ std::string ToString() const;
+};
+
+#if !defined(COMPILER_MSVC)
+extern template class InsetsBase<Insets, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_H_
diff --git a/chromium/ui/gfx/geometry/insets_base.h b/chromium/ui/gfx/geometry/insets_base.h
new file mode 100644
index 00000000000..751d5c11d9b
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets_base.h
@@ -0,0 +1,80 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_INSETS_BASE_H_
+#define UI_GFX_GEOMETRY_INSETS_BASE_H_
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// An insets represents the borders of a container (the space the container must
+// leave at each of its edges).
+template<typename Class, typename Type>
+class GFX_EXPORT InsetsBase {
+ public:
+ Type top() const { return top_; }
+ Type left() const { return left_; }
+ Type bottom() const { return bottom_; }
+ Type right() const { return right_; }
+
+ // Returns the total width taken up by the insets, which is the sum of the
+ // left and right insets.
+ Type width() const { return left_ + right_; }
+
+ // Returns the total height taken up by the insets, which is the sum of the
+ // top and bottom insets.
+ Type height() const { return top_ + bottom_; }
+
+ // Returns true if the insets are empty.
+ bool empty() const { return width() == 0 && height() == 0; }
+
+ void Set(Type top, Type left, Type bottom, Type right) {
+ top_ = top;
+ left_ = left;
+ bottom_ = bottom;
+ right_ = right;
+ }
+
+ bool operator==(const Class& insets) const {
+ return top_ == insets.top_ && left_ == insets.left_ &&
+ bottom_ == insets.bottom_ && right_ == insets.right_;
+ }
+
+ bool operator!=(const Class& insets) const {
+ return !(*this == insets);
+ }
+
+ void operator+=(const Class& insets) {
+ top_ += insets.top_;
+ left_ += insets.left_;
+ bottom_ += insets.bottom_;
+ right_ += insets.right_;
+ }
+
+ Class operator-() const {
+ return Class(-top_, -left_, -bottom_, -right_);
+ }
+
+ protected:
+ InsetsBase(Type top, Type left, Type bottom, Type right)
+ : top_(top),
+ left_(left),
+ bottom_(bottom),
+ right_(right) {}
+
+ // Destructor is intentionally made non virtual and protected.
+ // Do not make this public.
+ ~InsetsBase() {}
+
+ private:
+ Type top_;
+ Type left_;
+ Type bottom_;
+ Type right_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_BASE_H_
diff --git a/chromium/ui/gfx/geometry/insets_f.cc b/chromium/ui/gfx/geometry/insets_f.cc
new file mode 100644
index 00000000000..774b4ab8ca8
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets_f.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/insets_f.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class InsetsBase<InsetsF, float>;
+
+InsetsF::InsetsF() : InsetsBase<InsetsF, float>(0, 0, 0, 0) {}
+
+InsetsF::InsetsF(float top, float left, float bottom, float right)
+ : InsetsBase<InsetsF, float>(top, left, bottom, right) {}
+
+InsetsF::~InsetsF() {}
+
+std::string InsetsF::ToString() const {
+ // Print members in the same order of the constructor parameters.
+ return base::StringPrintf("%f,%f,%f,%f", top(), left(), bottom(), right());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/insets_f.h b/chromium/ui/gfx/geometry/insets_f.h
new file mode 100644
index 00000000000..ac3585a5a59
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets_f.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_INSETS_F_H_
+#define UI_GFX_GEOMETRY_INSETS_F_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets_base.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating versin of gfx::Insets.
+class GFX_EXPORT InsetsF : public InsetsBase<InsetsF, float> {
+ public:
+ InsetsF();
+ InsetsF(float top, float left, float bottom, float right);
+ ~InsetsF();
+
+ // Returns a string representation of the insets.
+ std::string ToString() const;
+};
+
+#if !defined(COMPILER_MSVC)
+extern template class InsetsBase<InsetsF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_F_H_
diff --git a/chromium/ui/gfx/geometry/insets_unittest.cc b/chromium/ui/gfx/geometry/insets_unittest.cc
new file mode 100644
index 00000000000..b20a9d36f48
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/insets.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(InsetsTest, InsetsDefault) {
+ gfx::Insets insets;
+ EXPECT_EQ(0, insets.top());
+ EXPECT_EQ(0, insets.left());
+ EXPECT_EQ(0, insets.bottom());
+ EXPECT_EQ(0, insets.right());
+ EXPECT_EQ(0, insets.width());
+ EXPECT_EQ(0, insets.height());
+ EXPECT_TRUE(insets.empty());
+}
+
+TEST(InsetsTest, Insets) {
+ gfx::Insets insets(1, 2, 3, 4);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(2, insets.left());
+ EXPECT_EQ(3, insets.bottom());
+ EXPECT_EQ(4, insets.right());
+ EXPECT_EQ(6, insets.width()); // Left + right.
+ EXPECT_EQ(4, insets.height()); // Top + bottom.
+ EXPECT_FALSE(insets.empty());
+}
+
+TEST(InsetsTest, Set) {
+ gfx::Insets insets;
+ insets.Set(1, 2, 3, 4);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(2, insets.left());
+ EXPECT_EQ(3, insets.bottom());
+ EXPECT_EQ(4, insets.right());
+}
+
+TEST(InsetsTest, Add) {
+ gfx::Insets insets;
+ insets.Set(1, 2, 3, 4);
+ insets += gfx::Insets(5, 6, 7, 8);
+ EXPECT_EQ(6, insets.top());
+ EXPECT_EQ(8, insets.left());
+ EXPECT_EQ(10, insets.bottom());
+ EXPECT_EQ(12, insets.right());
+}
+
+TEST(InsetsTest, Equality) {
+ gfx::Insets insets1;
+ insets1.Set(1, 2, 3, 4);
+ gfx::Insets insets2;
+ // Test operator== and operator!=.
+ EXPECT_FALSE(insets1 == insets2);
+ EXPECT_TRUE(insets1 != insets2);
+
+ insets2.Set(1, 2, 3, 4);
+ EXPECT_TRUE(insets1 == insets2);
+ EXPECT_FALSE(insets1 != insets2);
+}
+
+TEST(InsetsTest, ToString) {
+ gfx::Insets insets(1, 2, 3, 4);
+ EXPECT_EQ("1,2,3,4", insets.ToString());
+}
diff --git a/chromium/ui/gfx/geometry/matrix3_f.cc b/chromium/ui/gfx/geometry/matrix3_f.cc
new file mode 100644
index 00000000000..5836ae677b9
--- /dev/null
+++ b/chromium/ui/gfx/geometry/matrix3_f.cc
@@ -0,0 +1,237 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/matrix3_f.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace {
+
+// This is only to make accessing indices self-explanatory.
+enum MatrixCoordinates {
+ M00,
+ M01,
+ M02,
+ M10,
+ M11,
+ M12,
+ M20,
+ M21,
+ M22,
+ M_END
+};
+
+template<typename T>
+double Determinant3x3(T data[M_END]) {
+ // This routine is separated from the Matrix3F::Determinant because in
+ // computing inverse we do want higher precision afforded by the explicit
+ // use of 'double'.
+ return
+ static_cast<double>(data[M00]) * (
+ static_cast<double>(data[M11]) * data[M22] -
+ static_cast<double>(data[M12]) * data[M21]) +
+ static_cast<double>(data[M01]) * (
+ static_cast<double>(data[M12]) * data[M20] -
+ static_cast<double>(data[M10]) * data[M22]) +
+ static_cast<double>(data[M02]) * (
+ static_cast<double>(data[M10]) * data[M21] -
+ static_cast<double>(data[M11]) * data[M20]);
+}
+
+} // namespace
+
+namespace gfx {
+
+Matrix3F::Matrix3F() {
+}
+
+Matrix3F::~Matrix3F() {
+}
+
+// static
+Matrix3F Matrix3F::Zeros() {
+ Matrix3F matrix;
+ matrix.set(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ return matrix;
+}
+
+// static
+Matrix3F Matrix3F::Ones() {
+ Matrix3F matrix;
+ matrix.set(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
+ return matrix;
+}
+
+// static
+Matrix3F Matrix3F::Identity() {
+ Matrix3F matrix;
+ matrix.set(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+ return matrix;
+}
+
+// static
+Matrix3F Matrix3F::FromOuterProduct(const Vector3dF& a, const Vector3dF& bt) {
+ Matrix3F matrix;
+ matrix.set(a.x() * bt.x(), a.x() * bt.y(), a.x() * bt.z(),
+ a.y() * bt.x(), a.y() * bt.y(), a.y() * bt.z(),
+ a.z() * bt.x(), a.z() * bt.y(), a.z() * bt.z());
+ return matrix;
+}
+
+bool Matrix3F::IsEqual(const Matrix3F& rhs) const {
+ return 0 == memcmp(data_, rhs.data_, sizeof(data_));
+}
+
+bool Matrix3F::IsNear(const Matrix3F& rhs, float precision) const {
+ DCHECK(precision >= 0);
+ for (int i = 0; i < M_END; ++i) {
+ if (std::abs(data_[i] - rhs.data_[i]) > precision)
+ return false;
+ }
+ return true;
+}
+
+Matrix3F Matrix3F::Inverse() const {
+ Matrix3F inverse = Matrix3F::Zeros();
+ double determinant = Determinant3x3(data_);
+ if (std::numeric_limits<float>::epsilon() > std::abs(determinant))
+ return inverse; // Singular matrix. Return Zeros().
+
+ inverse.set(
+ (data_[M11] * data_[M22] - data_[M12] * data_[M21]) / determinant,
+ (data_[M02] * data_[M21] - data_[M01] * data_[M22]) / determinant,
+ (data_[M01] * data_[M12] - data_[M02] * data_[M11]) / determinant,
+ (data_[M12] * data_[M20] - data_[M10] * data_[M22]) / determinant,
+ (data_[M00] * data_[M22] - data_[M02] * data_[M20]) / determinant,
+ (data_[M02] * data_[M10] - data_[M00] * data_[M12]) / determinant,
+ (data_[M10] * data_[M21] - data_[M11] * data_[M20]) / determinant,
+ (data_[M01] * data_[M20] - data_[M00] * data_[M21]) / determinant,
+ (data_[M00] * data_[M11] - data_[M01] * data_[M10]) / determinant);
+ return inverse;
+}
+
+float Matrix3F::Determinant() const {
+ return static_cast<float>(Determinant3x3(data_));
+}
+
+Vector3dF Matrix3F::SolveEigenproblem(Matrix3F* eigenvectors) const {
+ // The matrix must be symmetric.
+ const float epsilon = std::numeric_limits<float>::epsilon();
+ if (std::abs(data_[M01] - data_[M10]) > epsilon ||
+ std::abs(data_[M02] - data_[M20]) > epsilon ||
+ std::abs(data_[M12] - data_[M21]) > epsilon) {
+ NOTREACHED();
+ return Vector3dF();
+ }
+
+ float eigenvalues[3];
+ float p =
+ data_[M01] * data_[M01] +
+ data_[M02] * data_[M02] +
+ data_[M12] * data_[M12];
+
+ bool diagonal = std::abs(p) < epsilon;
+ if (diagonal) {
+ eigenvalues[0] = data_[M00];
+ eigenvalues[1] = data_[M11];
+ eigenvalues[2] = data_[M22];
+ } else {
+ float q = Trace() / 3.0f;
+ p = (data_[M00] - q) * (data_[M00] - q) +
+ (data_[M11] - q) * (data_[M11] - q) +
+ (data_[M22] - q) * (data_[M22] - q) +
+ 2 * p;
+ p = std::sqrt(p / 6);
+
+ // The computation below puts B as (A - qI) / p, where A is *this.
+ Matrix3F matrix_b(*this);
+ matrix_b.data_[M00] -= q;
+ matrix_b.data_[M11] -= q;
+ matrix_b.data_[M22] -= q;
+ for (int i = 0; i < M_END; ++i)
+ matrix_b.data_[i] /= p;
+
+ double half_det_b = Determinant3x3(matrix_b.data_) / 2.0;
+ // half_det_b should be in <-1, 1>, but beware of rounding error.
+ double phi = 0.0f;
+ if (half_det_b <= -1.0)
+ phi = M_PI / 3;
+ else if (half_det_b < 1.0)
+ phi = acos(half_det_b) / 3;
+
+ eigenvalues[0] = q + 2 * p * static_cast<float>(cos(phi));
+ eigenvalues[2] = q + 2 * p *
+ static_cast<float>(cos(phi + 2.0 * M_PI / 3.0));
+ eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2];
+ }
+
+ // Put eigenvalues in the descending order.
+ int indices[3] = {0, 1, 2};
+ if (eigenvalues[2] > eigenvalues[1]) {
+ std::swap(eigenvalues[2], eigenvalues[1]);
+ std::swap(indices[2], indices[1]);
+ }
+
+ if (eigenvalues[1] > eigenvalues[0]) {
+ std::swap(eigenvalues[1], eigenvalues[0]);
+ std::swap(indices[1], indices[0]);
+ }
+
+ if (eigenvalues[2] > eigenvalues[1]) {
+ std::swap(eigenvalues[2], eigenvalues[1]);
+ std::swap(indices[2], indices[1]);
+ }
+
+ if (eigenvectors != NULL && diagonal) {
+ // Eigenvectors are e-vectors, just need to be sorted accordingly.
+ *eigenvectors = Zeros();
+ for (int i = 0; i < 3; ++i)
+ eigenvectors->set(indices[i], i, 1.0f);
+ } else if (eigenvectors != NULL) {
+ // Consult the following for a detailed discussion:
+ // Joachim Kopp
+ // Numerical diagonalization of hermitian 3x3 matrices
+ // arXiv.org preprint: physics/0610206
+ // Int. J. Mod. Phys. C19 (2008) 523-548
+
+ // TODO(motek): expand to handle correctly negative and multiple
+ // eigenvalues.
+ for (int i = 0; i < 3; ++i) {
+ float l = eigenvalues[i];
+ // B = A - l * I
+ Matrix3F matrix_b(*this);
+ matrix_b.data_[M00] -= l;
+ matrix_b.data_[M11] -= l;
+ matrix_b.data_[M22] -= l;
+ Vector3dF e1 = CrossProduct(matrix_b.get_column(0),
+ matrix_b.get_column(1));
+ Vector3dF e2 = CrossProduct(matrix_b.get_column(1),
+ matrix_b.get_column(2));
+ Vector3dF e3 = CrossProduct(matrix_b.get_column(2),
+ matrix_b.get_column(0));
+
+ // e1, e2 and e3 should point in the same direction.
+ if (DotProduct(e1, e2) < 0)
+ e2 = -e2;
+
+ if (DotProduct(e1, e3) < 0)
+ e3 = -e3;
+
+ Vector3dF eigvec = e1 + e2 + e3;
+ // Normalize.
+ eigvec.Scale(1.0f / eigvec.Length());
+ eigenvectors->set_column(i, eigvec);
+ }
+ }
+
+ return Vector3dF(eigenvalues[0], eigenvalues[1], eigenvalues[2]);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/matrix3_f.h b/chromium/ui/gfx/geometry/matrix3_f.h
new file mode 100644
index 00000000000..7e43496fd71
--- /dev/null
+++ b/chromium/ui/gfx/geometry/matrix3_f.h
@@ -0,0 +1,108 @@
+// 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_GFX_GEOMETRY_MATRIX3_F_H_
+#define UI_GFX_GEOMETRY_MATRIX3_F_H_
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+
+class GFX_EXPORT Matrix3F {
+ public:
+ ~Matrix3F();
+
+ static Matrix3F Zeros();
+ static Matrix3F Ones();
+ static Matrix3F Identity();
+ static Matrix3F FromOuterProduct(const Vector3dF& a, const Vector3dF& bt);
+
+ bool IsEqual(const Matrix3F& rhs) const;
+
+ // Element-wise comparison with given precision.
+ bool IsNear(const Matrix3F& rhs, float precision) const;
+
+ float get(int i, int j) const {
+ return data_[MatrixToArrayCoords(i, j)];
+ }
+
+ void set(int i, int j, float v) {
+ data_[MatrixToArrayCoords(i, j)] = v;
+ }
+
+ void set(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22) {
+ data_[0] = m00;
+ data_[1] = m01;
+ data_[2] = m02;
+ data_[3] = m10;
+ data_[4] = m11;
+ data_[5] = m12;
+ data_[6] = m20;
+ data_[7] = m21;
+ data_[8] = m22;
+ }
+
+ Vector3dF get_column(int i) const {
+ return Vector3dF(
+ data_[MatrixToArrayCoords(0, i)],
+ data_[MatrixToArrayCoords(1, i)],
+ data_[MatrixToArrayCoords(2, i)]);
+ }
+
+ void set_column(int i, const Vector3dF& c) {
+ data_[MatrixToArrayCoords(0, i)] = c.x();
+ data_[MatrixToArrayCoords(1, i)] = c.y();
+ data_[MatrixToArrayCoords(2, i)] = c.z();
+ }
+
+ // Returns an inverse of this if the matrix is non-singular, zero (== Zero())
+ // otherwise.
+ Matrix3F Inverse() const;
+
+ // Value of the determinant of the matrix.
+ float Determinant() const;
+
+ // Trace (sum of diagonal elements) of the matrix.
+ float Trace() const {
+ return data_[MatrixToArrayCoords(0, 0)] +
+ data_[MatrixToArrayCoords(1, 1)] +
+ data_[MatrixToArrayCoords(2, 2)];
+ }
+
+ // Compute eigenvalues and (optionally) normalized eigenvectors of
+ // a positive defnite matrix *this. Eigenvectors are computed only if
+ // non-null |eigenvectors| matrix is passed. If it is NULL, the routine
+ // will not attempt to compute eigenvectors but will still return eigenvalues
+ // if they can be computed.
+ // If eigenvalues cannot be computed (the matrix does not meet constraints)
+ // the 0-vector is returned. Note that to retrieve eigenvalues, the matrix
+ // only needs to be symmetric while eigenvectors require it to be
+ // positive-definite. Passing a non-positive definite matrix will result in
+ // NaNs in vectors which cannot be computed.
+ // Eigenvectors are placed as column in |eigenvectors| in order corresponding
+ // to eigenvalues.
+ Vector3dF SolveEigenproblem(Matrix3F* eigenvectors) const;
+
+ private:
+ Matrix3F(); // Uninitialized default.
+
+ static int MatrixToArrayCoords(int i, int j) {
+ DCHECK(i >= 0 && i < 3);
+ DCHECK(j >= 0 && j < 3);
+ return i * 3 + j;
+ }
+
+ float data_[9];
+};
+
+inline bool operator==(const Matrix3F& lhs, const Matrix3F& rhs) {
+ return lhs.IsEqual(rhs);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_MATRIX3_F_H_
diff --git a/chromium/ui/gfx/geometry/matrix3_unittest.cc b/chromium/ui/gfx/geometry/matrix3_unittest.cc
new file mode 100644
index 00000000000..0f57e8e7a95
--- /dev/null
+++ b/chromium/ui/gfx/geometry/matrix3_unittest.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/matrix3_f.h"
+
+namespace gfx {
+namespace {
+
+TEST(Matrix3fTest, Constructors) {
+ Matrix3F zeros = Matrix3F::Zeros();
+ Matrix3F ones = Matrix3F::Ones();
+ Matrix3F identity = Matrix3F::Identity();
+
+ Matrix3F product_ones = Matrix3F::FromOuterProduct(
+ Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(1.0f, 1.0f, 1.0f));
+ Matrix3F product_zeros = Matrix3F::FromOuterProduct(
+ Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(0.0f, 0.0f, 0.0f));
+ EXPECT_EQ(ones, product_ones);
+ EXPECT_EQ(zeros, product_zeros);
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j)
+ EXPECT_EQ(i == j ? 1.0f : 0.0f, identity.get(i, j));
+ }
+}
+
+TEST(Matrix3fTest, DataAccess) {
+ Matrix3F matrix = Matrix3F::Ones();
+ Matrix3F identity = Matrix3F::Identity();
+
+ EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), identity.get_column(1));
+ matrix.set(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
+ EXPECT_EQ(Vector3dF(2.0f, 5.0f, 8.0f), matrix.get_column(2));
+ matrix.set_column(0, Vector3dF(0.1f, 0.2f, 0.3f));
+ EXPECT_EQ(Vector3dF(0.1f, 0.2f, 0.3f), matrix.get_column(0));
+
+ EXPECT_EQ(0.1f, matrix.get(0, 0));
+ EXPECT_EQ(5.0f, matrix.get(1, 2));
+}
+
+TEST(Matrix3fTest, Determinant) {
+ EXPECT_EQ(1.0f, Matrix3F::Identity().Determinant());
+ EXPECT_EQ(0.0f, Matrix3F::Zeros().Determinant());
+ EXPECT_EQ(0.0f, Matrix3F::Ones().Determinant());
+
+ // Now for something non-trivial...
+ Matrix3F matrix = Matrix3F::Zeros();
+ matrix.set(0, 5, 6, 8, 7, 0, 1, 9, 0);
+ EXPECT_EQ(390.0f, matrix.Determinant());
+ matrix.set(2, 0, 3 * matrix.get(0, 0));
+ matrix.set(2, 1, 3 * matrix.get(0, 1));
+ matrix.set(2, 2, 3 * matrix.get(0, 2));
+ EXPECT_EQ(0, matrix.Determinant());
+
+ matrix.set(0.57f, 0.205f, 0.942f,
+ 0.314f, 0.845f, 0.826f,
+ 0.131f, 0.025f, 0.962f);
+ EXPECT_NEAR(0.3149f, matrix.Determinant(), 0.0001f);
+}
+
+TEST(Matrix3fTest, Inverse) {
+ Matrix3F identity = Matrix3F::Identity();
+ Matrix3F inv_identity = identity.Inverse();
+ EXPECT_EQ(identity, inv_identity);
+
+ Matrix3F singular = Matrix3F::Zeros();
+ singular.set(1.0f, 3.0f, 4.0f,
+ 2.0f, 11.0f, 5.0f,
+ 0.5f, 1.5f, 2.0f);
+ EXPECT_EQ(0, singular.Determinant());
+ EXPECT_EQ(Matrix3F::Zeros(), singular.Inverse());
+
+ Matrix3F regular = Matrix3F::Zeros();
+ regular.set(0.57f, 0.205f, 0.942f,
+ 0.314f, 0.845f, 0.826f,
+ 0.131f, 0.025f, 0.962f);
+ Matrix3F inv_regular = regular.Inverse();
+ regular.set(2.51540616f, -0.55138018f, -1.98968043f,
+ -0.61552266f, 1.34920184f, -0.55573636f,
+ -0.32653861f, 0.04002158f, 1.32488726f);
+ EXPECT_TRUE(regular.IsNear(inv_regular, 0.00001f));
+}
+
+TEST(Matrix3fTest, EigenvectorsIdentity) {
+ // This block tests the trivial case of eigenvalues of the identity matrix.
+ Matrix3F identity = Matrix3F::Identity();
+ Vector3dF eigenvals = identity.SolveEigenproblem(NULL);
+ EXPECT_EQ(Vector3dF(1.0f, 1.0f, 1.0f), eigenvals);
+}
+
+TEST(Matrix3fTest, EigenvectorsDiagonal) {
+ // This block tests the another trivial case of eigenvalues of a diagonal
+ // matrix. Here we expect values to be sorted.
+ Matrix3F matrix = Matrix3F::Zeros();
+ matrix.set(0, 0, 1.0f);
+ matrix.set(1, 1, -2.5f);
+ matrix.set(2, 2, 3.14f);
+ Matrix3F eigenvectors = Matrix3F::Zeros();
+ Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
+ EXPECT_EQ(Vector3dF(3.14f, 1.0f, -2.5f), eigenvals);
+
+ EXPECT_EQ(Vector3dF(0.0f, 0.0f, 1.0f), eigenvectors.get_column(0));
+ EXPECT_EQ(Vector3dF(1.0f, 0.0f, 0.0f), eigenvectors.get_column(1));
+ EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), eigenvectors.get_column(2));
+}
+
+TEST(Matrix3fTest, EigenvectorsNiceNotPositive) {
+ // This block tests computation of eigenvectors of a matrix where nice
+ // round values are expected.
+ Matrix3F matrix = Matrix3F::Zeros();
+ // This is not a positive-definite matrix but eigenvalues and the first
+ // eigenvector should nonetheless be computed correctly.
+ matrix.set(3, 2, 4, 2, 0, 2, 4, 2, 3);
+ Matrix3F eigenvectors = Matrix3F::Zeros();
+ Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
+ EXPECT_EQ(Vector3dF(8.0f, -1.0f, -1.0f), eigenvals);
+
+ Vector3dF expected_principal(0.66666667f, 0.33333333f, 0.66666667f);
+ EXPECT_NEAR(0.0f,
+ (expected_principal - eigenvectors.get_column(0)).Length(),
+ 0.000001f);
+}
+
+TEST(Matrix3fTest, EigenvectorsPositiveDefinite) {
+ // This block tests computation of eigenvectors of a matrix where output
+ // is not as nice as above, but it actually meets the definition.
+ Matrix3F matrix = Matrix3F::Zeros();
+ Matrix3F eigenvectors = Matrix3F::Zeros();
+ Matrix3F expected_eigenvectors = Matrix3F::Zeros();
+ matrix.set(1, -1, 2, -1, 4, 5, 2, 5, 0);
+ Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
+ Vector3dF expected_eigv(7.3996266f, 1.91197255f, -4.31159915f);
+ expected_eigv -= eigenvals;
+ EXPECT_NEAR(0, expected_eigv.LengthSquared(), 0.00001f);
+ expected_eigenvectors.set(0.04926317f, -0.92135662f, -0.38558414f,
+ 0.82134249f, 0.25703273f, -0.50924521f,
+ 0.56830419f, -0.2916096f, 0.76941158f);
+ EXPECT_TRUE(expected_eigenvectors.IsNear(eigenvectors, 0.00001f));
+}
+
+}
+}
diff --git a/chromium/ui/gfx/geometry/point.cc b/chromium/ui/gfx/geometry/point.cc
new file mode 100644
index 00000000000..5a68ba67bdd
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/point.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class PointBase<Point, int, Vector2d>;
+
+#if defined(OS_WIN)
+Point::Point(DWORD point) : PointBase<Point, int, Vector2d>(0, 0){
+ POINTS points = MAKEPOINTS(point);
+ set_x(points.x);
+ set_y(points.y);
+}
+
+Point::Point(const POINT& point)
+ : PointBase<Point, int, Vector2d>(point.x, point.y) {
+}
+
+Point& Point::operator=(const POINT& point) {
+ set_x(point.x);
+ set_y(point.y);
+ return *this;
+}
+
+POINT Point::ToPOINT() const {
+ POINT p;
+ p.x = x();
+ p.y = y();
+ return p;
+}
+#elif defined(OS_MACOSX)
+Point::Point(const CGPoint& point)
+ : PointBase<Point, int, Vector2d>(point.x, point.y) {
+}
+
+CGPoint Point::ToCGPoint() const {
+ return CGPointMake(x(), y());
+}
+#endif
+
+std::string Point::ToString() const {
+ return base::StringPrintf("%d,%d", x(), y());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/point.h b/chromium/ui/gfx/geometry/point.h
new file mode 100644
index 00000000000..ff99d71d361
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_POINT_H_
+#define UI_GFX_GEOMETRY_POINT_H_
+
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/gfx_export.h"
+
+#if defined(OS_WIN)
+typedef unsigned long DWORD;
+typedef struct tagPOINT POINT;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+// A point has an x and y coordinate.
+class GFX_EXPORT Point : public PointBase<Point, int, Vector2d> {
+ public:
+ Point() : PointBase<Point, int, Vector2d>(0, 0) {}
+ Point(int x, int y) : PointBase<Point, int, Vector2d>(x, y) {}
+#if defined(OS_WIN)
+ // |point| is a DWORD value that contains a coordinate. The x-coordinate is
+ // the low-order short and the y-coordinate is the high-order short. This
+ // value is commonly acquired from GetMessagePos/GetCursorPos.
+ explicit Point(DWORD point);
+ explicit Point(const POINT& point);
+ Point& operator=(const POINT& point);
+#elif defined(OS_MACOSX)
+ explicit Point(const CGPoint& point);
+#endif
+
+ ~Point() {}
+
+#if defined(OS_WIN)
+ POINT ToPOINT() const;
+#elif defined(OS_MACOSX)
+ CGPoint ToCGPoint() const;
+#endif
+
+ operator PointF() const {
+ return PointF(x(), y());
+ }
+
+ // Returns a string representation of point.
+ std::string ToString() const;
+};
+
+inline bool operator==(const Point& lhs, const Point& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+}
+
+inline bool operator!=(const Point& lhs, const Point& rhs) {
+ return !(lhs == rhs);
+}
+
+inline Point operator+(const Point& lhs, const Vector2d& rhs) {
+ Point result(lhs);
+ result += rhs;
+ return result;
+}
+
+inline Point operator-(const Point& lhs, const Vector2d& rhs) {
+ Point result(lhs);
+ result -= rhs;
+ return result;
+}
+
+inline Vector2d operator-(const Point& lhs, const Point& rhs) {
+ return Vector2d(lhs.x() - rhs.x(), lhs.y() - rhs.y());
+}
+
+inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
+ return Point(offset_from_origin.x(), offset_from_origin.y());
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class PointBase<Point, int, Vector2d>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_H_
diff --git a/chromium/ui/gfx/geometry/point3_f.cc b/chromium/ui/gfx/geometry/point3_f.cc
new file mode 100644
index 00000000000..465376e55e8
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point3_f.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/point3_f.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+std::string Point3F::ToString() const {
+ return base::StringPrintf("%f,%f,%f", x_, y_, z_);
+}
+
+Point3F operator+(const Point3F& lhs, const Vector3dF& rhs) {
+ float x = lhs.x() + rhs.x();
+ float y = lhs.y() + rhs.y();
+ float z = lhs.z() + rhs.z();
+ return Point3F(x, y, z);
+}
+
+// Subtract a vector from a point, producing a new point offset by the vector's
+// inverse.
+Point3F operator-(const Point3F& lhs, const Vector3dF& rhs) {
+ float x = lhs.x() - rhs.x();
+ float y = lhs.y() - rhs.y();
+ float z = lhs.z() - rhs.z();
+ return Point3F(x, y, z);
+}
+
+// Subtract one point from another, producing a vector that represents the
+// distances between the two points along each axis.
+Vector3dF operator-(const Point3F& lhs, const Point3F& rhs) {
+ float x = lhs.x() - rhs.x();
+ float y = lhs.y() - rhs.y();
+ float z = lhs.z() - rhs.z();
+ return Vector3dF(x, y, z);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/point3_f.h b/chromium/ui/gfx/geometry/point3_f.h
new file mode 100644
index 00000000000..45bae6e8d32
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point3_f.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_POINT3_F_H_
+#define UI_GFX_GEOMETRY_POINT3_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A point has an x, y and z coordinate.
+class GFX_EXPORT Point3F {
+ public:
+ Point3F() : x_(0), y_(0), z_(0) {}
+
+ Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
+
+ explicit Point3F(const PointF& point) : x_(point.x()), y_(point.y()), z_(0) {}
+
+ ~Point3F() {}
+
+ void Scale(float scale) {
+ Scale(scale, scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale, float z_scale) {
+ SetPoint(x() * x_scale, y() * y_scale, z() * z_scale);
+ }
+
+ float x() const { return x_; }
+ float y() const { return y_; }
+ float z() const { return z_; }
+
+ void set_x(float x) { x_ = x; }
+ void set_y(float y) { y_ = y; }
+ void set_z(float z) { z_ = z; }
+
+ void SetPoint(float x, float y, float z) {
+ x_ = x;
+ y_ = y;
+ z_ = z;
+ }
+
+ // Offset the point by the given vector.
+ void operator+=(const Vector3dF& v) {
+ x_ += v.x();
+ y_ += v.y();
+ z_ += v.z();
+ }
+
+ // Offset the point by the given vector's inverse.
+ void operator-=(const Vector3dF& v) {
+ x_ -= v.x();
+ y_ -= v.y();
+ z_ -= v.z();
+ }
+
+ // Returns the squared euclidean distance between two points.
+ float SquaredDistanceTo(const Point3F& other) const {
+ float dx = x_ - other.x_;
+ float dy = y_ - other.y_;
+ float dz = z_ - other.z_;
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ PointF AsPointF() const { return PointF(x_, y_); }
+
+ // Returns a string representation of 3d point.
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+ float z_;
+
+ // copy/assign are allowed.
+};
+
+inline bool operator==(const Point3F& lhs, const Point3F& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
+}
+
+inline bool operator!=(const Point3F& lhs, const Point3F& rhs) {
+ return !(lhs == rhs);
+}
+
+// Add a vector to a point, producing a new point offset by the vector.
+GFX_EXPORT Point3F operator+(const Point3F& lhs, const Vector3dF& rhs);
+
+// Subtract a vector from a point, producing a new point offset by the vector's
+// inverse.
+GFX_EXPORT Point3F operator-(const Point3F& lhs, const Vector3dF& rhs);
+
+// Subtract one point from another, producing a vector that represents the
+// distances between the two points along each axis.
+GFX_EXPORT Vector3dF operator-(const Point3F& lhs, const Point3F& rhs);
+
+inline Point3F PointAtOffsetFromOrigin(const Vector3dF& offset) {
+ return Point3F(offset.x(), offset.y(), offset.z());
+}
+
+inline Point3F ScalePoint(const Point3F& p,
+ float x_scale,
+ float y_scale,
+ float z_scale) {
+ return Point3F(p.x() * x_scale, p.y() * y_scale, p.z() * z_scale);
+}
+
+inline Point3F ScalePoint(const Point3F& p, float scale) {
+ return ScalePoint(p, scale, scale, scale);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT3_F_H_
diff --git a/chromium/ui/gfx/geometry/point3_unittest.cc b/chromium/ui/gfx/geometry/point3_unittest.cc
new file mode 100644
index 00000000000..77f20d79963
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point3_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point3_f.h"
+
+namespace gfx {
+
+TEST(Point3Test, VectorArithmetic) {
+ gfx::Point3F a(1.6f, 5.1f, 3.2f);
+ gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
+ gfx::Vector3dF v2(-8.1f, 1.2f, 3.3f);
+
+ static const struct {
+ gfx::Point3F expected;
+ gfx::Point3F actual;
+ } tests[] = {
+ { gfx::Point3F(4.7f, 1.9f, 12.5f), a + v1 },
+ { gfx::Point3F(-1.5f, 8.3f, -6.1f), a - v1 },
+ { a, a - v1 + v1 },
+ { a, a + v1 - v1 },
+ { a, a + gfx::Vector3dF() },
+ { gfx::Point3F(12.8f, 0.7f, 9.2f), a + v1 - v2 },
+ { gfx::Point3F(-9.6f, 9.5f, -2.8f), a - v1 + v2 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i)
+ EXPECT_EQ(tests[i].expected.ToString(),
+ tests[i].actual.ToString());
+
+ a += v1;
+ EXPECT_EQ(Point3F(4.7f, 1.9f, 12.5f).ToString(), a.ToString());
+
+ a -= v2;
+ EXPECT_EQ(Point3F(12.8f, 0.7f, 9.2f).ToString(), a.ToString());
+}
+
+TEST(Point3Test, VectorFromPoints) {
+ gfx::Point3F a(1.6f, 5.2f, 3.2f);
+ gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
+
+ gfx::Point3F b(a + v1);
+ EXPECT_EQ((b - a).ToString(), v1.ToString());
+}
+
+TEST(Point3Test, Scale) {
+ EXPECT_EQ(Point3F().ToString(), ScalePoint(Point3F(), 2.f).ToString());
+ EXPECT_EQ(Point3F().ToString(),
+ ScalePoint(Point3F(), 2.f, 2.f, 2.f).ToString());
+
+ EXPECT_EQ(Point3F(2.f, -2.f, 4.f).ToString(),
+ ScalePoint(Point3F(1.f, -1.f, 2.f), 2.f).ToString());
+ EXPECT_EQ(Point3F(2.f, -3.f, 8.f).ToString(),
+ ScalePoint(Point3F(1.f, -1.f, 2.f), 2.f, 3.f, 4.f).ToString());
+
+ Point3F zero;
+ zero.Scale(2.f);
+ zero.Scale(6.f, 3.f, 1.5f);
+ EXPECT_EQ(Point3F().ToString(), zero.ToString());
+
+ Point3F point(1.f, -1.f, 2.f);
+ point.Scale(2.f);
+ point.Scale(6.f, 3.f, 1.5f);
+ EXPECT_EQ(Point3F(12.f, -6.f, 6.f).ToString(), point.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/point_base.h b/chromium/ui/gfx/geometry/point_base.h
new file mode 100644
index 00000000000..6db1c0cf916
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_base.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_POINT_BASE_H_
+#define UI_GFX_GEOMETRY_POINT_BASE_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A point has an x and y coordinate.
+template<typename Class, typename Type, typename VectorClass>
+class GFX_EXPORT PointBase {
+ public:
+ Type x() const { return x_; }
+ Type y() const { return y_; }
+
+ void SetPoint(Type x, Type y) {
+ x_ = x;
+ y_ = y;
+ }
+
+ void set_x(Type x) { x_ = x; }
+ void set_y(Type y) { y_ = y; }
+
+ void Offset(Type delta_x, Type delta_y) {
+ x_ += delta_x;
+ y_ += delta_y;
+ }
+
+ void operator+=(const VectorClass& vector) {
+ x_ += vector.x();
+ y_ += vector.y();
+ }
+
+ void operator-=(const VectorClass& vector) {
+ x_ -= vector.x();
+ y_ -= vector.y();
+ }
+
+ void SetToMin(const Class& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ }
+
+ void SetToMax(const Class& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ }
+
+ bool IsOrigin() const {
+ return x_ == 0 && y_ == 0;
+ }
+
+ VectorClass OffsetFromOrigin() const {
+ return VectorClass(x_, y_);
+ }
+
+ // A point is less than another point if its y-value is closer
+ // to the origin. If the y-values are the same, then point with
+ // the x-value closer to the origin is considered less than the
+ // other.
+ // This comparison is required to use Point in sets, or sorted
+ // vectors.
+ bool operator<(const Class& rhs) const {
+ return (y_ == rhs.y_) ? (x_ < rhs.x_) : (y_ < rhs.y_);
+ }
+
+ protected:
+ PointBase(Type x, Type y) : x_(x), y_(y) {}
+ // Destructor is intentionally made non virtual and protected.
+ // Do not make this public.
+ ~PointBase() {}
+
+ private:
+ Type x_;
+ Type y_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_BASE_H_
diff --git a/chromium/ui/gfx/geometry/point_conversions.cc b/chromium/ui/gfx/geometry/point_conversions.cc
new file mode 100644
index 00000000000..0613e7a9db1
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_conversions.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/point_conversions.h"
+
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace gfx {
+
+Point ToFlooredPoint(const PointF& point) {
+ int x = ToFlooredInt(point.x());
+ int y = ToFlooredInt(point.y());
+ return Point(x, y);
+}
+
+Point ToCeiledPoint(const PointF& point) {
+ int x = ToCeiledInt(point.x());
+ int y = ToCeiledInt(point.y());
+ return Point(x, y);
+}
+
+Point ToRoundedPoint(const PointF& point) {
+ int x = ToRoundedInt(point.x());
+ int y = ToRoundedInt(point.y());
+ return Point(x, y);
+}
+
+} // namespace gfx
+
diff --git a/chromium/ui/gfx/geometry/point_conversions.h b/chromium/ui/gfx/geometry/point_conversions.h
new file mode 100644
index 00000000000..bfab9e4e463
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_conversions.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace gfx {
+
+// Returns a Point with each component from the input PointF floored.
+GFX_EXPORT Point ToFlooredPoint(const PointF& point);
+
+// Returns a Point with each component from the input PointF ceiled.
+GFX_EXPORT Point ToCeiledPoint(const PointF& point);
+
+// Returns a Point with each component from the input PointF rounded.
+GFX_EXPORT Point ToRoundedPoint(const PointF& point);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/geometry/point_f.cc b/chromium/ui/gfx/geometry/point_f.cc
new file mode 100644
index 00000000000..9c2ece23a59
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_f.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/point_f.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class PointBase<PointF, float, Vector2dF>;
+
+std::string PointF::ToString() const {
+ return base::StringPrintf("%f,%f", x(), y());
+}
+
+PointF ScalePoint(const PointF& p, float x_scale, float y_scale) {
+ PointF scaled_p(p);
+ scaled_p.Scale(x_scale, y_scale);
+ return scaled_p;
+}
+
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/point_f.h b/chromium/ui/gfx/geometry/point_f.h
new file mode 100644
index 00000000000..00266d311d0
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_f.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_POINT_F_H_
+#define UI_GFX_GEOMETRY_POINT_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating version of gfx::Point.
+class GFX_EXPORT PointF : public PointBase<PointF, float, Vector2dF> {
+ public:
+ PointF() : PointBase<PointF, float, Vector2dF>(0, 0) {}
+ PointF(float x, float y) : PointBase<PointF, float, Vector2dF>(x, y) {}
+ ~PointF() {}
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ SetPoint(x() * x_scale, y() * y_scale);
+ }
+
+ // Returns a string representation of point.
+ std::string ToString() const;
+};
+
+inline bool operator==(const PointF& lhs, const PointF& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+}
+
+inline bool operator!=(const PointF& lhs, const PointF& rhs) {
+ return !(lhs == rhs);
+}
+
+inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
+ PointF result(lhs);
+ result += rhs;
+ return result;
+}
+
+inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
+ PointF result(lhs);
+ result -= rhs;
+ return result;
+}
+
+inline Vector2dF operator-(const PointF& lhs, const PointF& rhs) {
+ return Vector2dF(lhs.x() - rhs.x(), lhs.y() - rhs.y());
+}
+
+inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) {
+ return PointF(offset_from_origin.x(), offset_from_origin.y());
+}
+
+GFX_EXPORT PointF ScalePoint(const PointF& p, float x_scale, float y_scale);
+
+inline PointF ScalePoint(const PointF& p, float scale) {
+ return ScalePoint(p, scale, scale);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class PointBase<PointF, float, Vector2dF>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_F_H_
diff --git a/chromium/ui/gfx/geometry/point_unittest.cc b/chromium/ui/gfx/geometry/point_unittest.cc
new file mode 100644
index 00000000000..8c5f552f89c
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace gfx {
+
+namespace {
+
+int TestPointF(const PointF& p) {
+ return p.x();
+}
+
+} // namespace
+
+TEST(PointTest, ToPointF) {
+ // Check that implicit conversion from integer to float compiles.
+ Point a(10, 20);
+ float x = TestPointF(a);
+ EXPECT_EQ(x, a.x());
+
+ PointF b(10, 20);
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(b, a);
+}
+
+TEST(PointTest, IsOrigin) {
+ EXPECT_FALSE(Point(1, 0).IsOrigin());
+ EXPECT_FALSE(Point(0, 1).IsOrigin());
+ EXPECT_FALSE(Point(1, 2).IsOrigin());
+ EXPECT_FALSE(Point(-1, 0).IsOrigin());
+ EXPECT_FALSE(Point(0, -1).IsOrigin());
+ EXPECT_FALSE(Point(-1, -2).IsOrigin());
+ EXPECT_TRUE(Point(0, 0).IsOrigin());
+
+ EXPECT_FALSE(PointF(0.1f, 0).IsOrigin());
+ EXPECT_FALSE(PointF(0, 0.1f).IsOrigin());
+ EXPECT_FALSE(PointF(0.1f, 2).IsOrigin());
+ EXPECT_FALSE(PointF(-0.1f, 0).IsOrigin());
+ EXPECT_FALSE(PointF(0, -0.1f).IsOrigin());
+ EXPECT_FALSE(PointF(-0.1f, -2).IsOrigin());
+ EXPECT_TRUE(PointF(0, 0).IsOrigin());
+}
+
+TEST(PointTest, VectorArithmetic) {
+ Point a(1, 5);
+ Vector2d v1(3, -3);
+ Vector2d v2(-8, 1);
+
+ static const struct {
+ Point expected;
+ Point actual;
+ } tests[] = {
+ { Point(4, 2), a + v1 },
+ { Point(-2, 8), a - v1 },
+ { a, a - v1 + v1 },
+ { a, a + v1 - v1 },
+ { a, a + Vector2d() },
+ { Point(12, 1), a + v1 - v2 },
+ { Point(-10, 9), a - v1 + v2 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i)
+ EXPECT_EQ(tests[i].expected.ToString(), tests[i].actual.ToString());
+}
+
+TEST(PointTest, OffsetFromPoint) {
+ Point a(1, 5);
+ Point b(-20, 8);
+ EXPECT_EQ(Vector2d(-20 - 1, 8 - 5).ToString(), (b - a).ToString());
+}
+
+TEST(PointTest, ToRoundedPoint) {
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0, 0)));
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.5f, 0.5f)));
+ EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10, 10)));
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.5f, 10.5f)));
+ EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.9999f, 10.9999f)));
+
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10, -10)));
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.0001f, -10.0001f)));
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.4999f, -10.4999f)));
+ EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.5f, -10.5f)));
+ EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.9999f, -10.9999f)));
+}
+
+TEST(PointTest, Scale) {
+ EXPECT_EQ(PointF().ToString(), ScalePoint(Point(), 2).ToString());
+ EXPECT_EQ(PointF().ToString(), ScalePoint(Point(), 2, 2).ToString());
+
+ EXPECT_EQ(PointF(2, -2).ToString(),
+ ScalePoint(Point(1, -1), 2).ToString());
+ EXPECT_EQ(PointF(2, -2).ToString(),
+ ScalePoint(Point(1, -1), 2, 2).ToString());
+
+ PointF zero;
+ PointF one(1, -1);
+
+ zero.Scale(2);
+ zero.Scale(3, 1.5);
+
+ one.Scale(2);
+ one.Scale(3, 1.5);
+
+ EXPECT_EQ(PointF().ToString(), zero.ToString());
+ EXPECT_EQ(PointF(6, -3).ToString(), one.ToString());
+}
+
+TEST(PointTest, ClampPoint) {
+ Point a;
+
+ a = Point(3, 5);
+ EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ a.SetToMax(Point(2, 4));
+ EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ a.SetToMax(Point(3, 5));
+ EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ a.SetToMax(Point(4, 2));
+ EXPECT_EQ(Point(4, 5).ToString(), a.ToString());
+ a.SetToMax(Point(8, 10));
+ EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+
+ a.SetToMin(Point(9, 11));
+ EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+ a.SetToMin(Point(8, 10));
+ EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+ a.SetToMin(Point(11, 9));
+ EXPECT_EQ(Point(8, 9).ToString(), a.ToString());
+ a.SetToMin(Point(7, 11));
+ EXPECT_EQ(Point(7, 9).ToString(), a.ToString());
+ a.SetToMin(Point(3, 5));
+ EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+}
+
+TEST(PointTest, ClampPointF) {
+ PointF a;
+
+ a = PointF(3.5f, 5.5f);
+ EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(PointF(2.5f, 4.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(PointF(3.5f, 5.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(PointF(4.5f, 2.5f));
+ EXPECT_EQ(PointF(4.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(PointF(8.5f, 10.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
+
+ a.SetToMin(PointF(9.5f, 11.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(PointF(8.5f, 10.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(PointF(11.5f, 9.5f));
+ EXPECT_EQ(PointF(8.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(PointF(7.5f, 11.5f));
+ EXPECT_EQ(PointF(7.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(PointF(3.5f, 5.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/quad_f.cc b/chromium/ui/gfx/geometry/quad_f.cc
new file mode 100644
index 00000000000..dbc50458b3f
--- /dev/null
+++ b/chromium/ui/gfx/geometry/quad_f.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/quad_f.h"
+
+#include <limits>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+void QuadF::operator=(const RectF& rect) {
+ p1_ = PointF(rect.x(), rect.y());
+ p2_ = PointF(rect.right(), rect.y());
+ p3_ = PointF(rect.right(), rect.bottom());
+ p4_ = PointF(rect.x(), rect.bottom());
+}
+
+std::string QuadF::ToString() const {
+ return base::StringPrintf("%s;%s;%s;%s",
+ p1_.ToString().c_str(),
+ p2_.ToString().c_str(),
+ p3_.ToString().c_str(),
+ p4_.ToString().c_str());
+}
+
+static inline bool WithinEpsilon(float a, float b) {
+ return std::abs(a - b) < std::numeric_limits<float>::epsilon();
+}
+
+bool QuadF::IsRectilinear() const {
+ return
+ (WithinEpsilon(p1_.x(), p2_.x()) && WithinEpsilon(p2_.y(), p3_.y()) &&
+ WithinEpsilon(p3_.x(), p4_.x()) && WithinEpsilon(p4_.y(), p1_.y())) ||
+ (WithinEpsilon(p1_.y(), p2_.y()) && WithinEpsilon(p2_.x(), p3_.x()) &&
+ WithinEpsilon(p3_.y(), p4_.y()) && WithinEpsilon(p4_.x(), p1_.x()));
+}
+
+bool QuadF::IsCounterClockwise() const {
+ // This math computes the signed area of the quad. Positive area
+ // indicates the quad is clockwise; negative area indicates the quad is
+ // counter-clockwise. Note carefully: this is backwards from conventional
+ // math because our geometric space uses screen coordiantes with y-axis
+ // pointing downards.
+ // Reference: http://mathworld.wolfram.com/PolygonArea.html
+
+ // Up-cast to double so this cannot overflow.
+ double determinant1 = static_cast<double>(p1_.x()) * p2_.y()
+ - static_cast<double>(p2_.x()) * p1_.y();
+ double determinant2 = static_cast<double>(p2_.x()) * p3_.y()
+ - static_cast<double>(p3_.x()) * p2_.y();
+ double determinant3 = static_cast<double>(p3_.x()) * p4_.y()
+ - static_cast<double>(p4_.x()) * p3_.y();
+ double determinant4 = static_cast<double>(p4_.x()) * p1_.y()
+ - static_cast<double>(p1_.x()) * p4_.y();
+
+ return determinant1 + determinant2 + determinant3 + determinant4 < 0;
+}
+
+static inline bool PointIsInTriangle(const PointF& point,
+ const PointF& r1,
+ const PointF& r2,
+ const PointF& r3) {
+ // Compute the barycentric coordinates (u, v, w) of |point| relative to the
+ // triangle (r1, r2, r3) by the solving the system of equations:
+ // 1) point = u * r1 + v * r2 + w * r3
+ // 2) u + v + w = 1
+ // This algorithm comes from Christer Ericson's Real-Time Collision Detection.
+
+ Vector2dF r31 = r1 - r3;
+ Vector2dF r32 = r2 - r3;
+ Vector2dF r3p = point - r3;
+
+ float denom = r32.y() * r31.x() - r32.x() * r31.y();
+ float u = (r32.y() * r3p.x() - r32.x() * r3p.y()) / denom;
+ float v = (r31.x() * r3p.y() - r31.y() * r3p.x()) / denom;
+ float w = 1.f - u - v;
+
+ // Use the barycentric coordinates to test if |point| is inside the
+ // triangle (r1, r2, r2).
+ return (u >= 0) && (v >= 0) && (w >= 0);
+}
+
+bool QuadF::Contains(const PointF& point) const {
+ return PointIsInTriangle(point, p1_, p2_, p3_)
+ || PointIsInTriangle(point, p1_, p3_, p4_);
+}
+
+void QuadF::Scale(float x_scale, float y_scale) {
+ p1_.Scale(x_scale, y_scale);
+ p2_.Scale(x_scale, y_scale);
+ p3_.Scale(x_scale, y_scale);
+ p4_.Scale(x_scale, y_scale);
+}
+
+void QuadF::operator+=(const Vector2dF& rhs) {
+ p1_ += rhs;
+ p2_ += rhs;
+ p3_ += rhs;
+ p4_ += rhs;
+}
+
+void QuadF::operator-=(const Vector2dF& rhs) {
+ p1_ -= rhs;
+ p2_ -= rhs;
+ p3_ -= rhs;
+ p4_ -= rhs;
+}
+
+QuadF operator+(const QuadF& lhs, const Vector2dF& rhs) {
+ QuadF result = lhs;
+ result += rhs;
+ return result;
+}
+
+QuadF operator-(const QuadF& lhs, const Vector2dF& rhs) {
+ QuadF result = lhs;
+ result -= rhs;
+ return result;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/quad_f.h b/chromium/ui/gfx/geometry/quad_f.h
new file mode 100644
index 00000000000..25f8b2b34b3
--- /dev/null
+++ b/chromium/ui/gfx/geometry/quad_f.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_QUAD_F_H_
+#define UI_GFX_GEOMETRY_QUAD_F_H_
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A Quad is defined by four corners, allowing it to have edges that are not
+// axis-aligned, unlike a Rect.
+class GFX_EXPORT QuadF {
+ public:
+ QuadF() {}
+ QuadF(const PointF& p1, const PointF& p2, const PointF& p3, const PointF& p4)
+ : p1_(p1),
+ p2_(p2),
+ p3_(p3),
+ p4_(p4) {}
+
+ explicit QuadF(const RectF& rect)
+ : p1_(rect.x(), rect.y()),
+ p2_(rect.right(), rect.y()),
+ p3_(rect.right(), rect.bottom()),
+ p4_(rect.x(), rect.bottom()) {}
+
+ void operator=(const RectF& rect);
+
+ void set_p1(const PointF& p) { p1_ = p; }
+ void set_p2(const PointF& p) { p2_ = p; }
+ void set_p3(const PointF& p) { p3_ = p; }
+ void set_p4(const PointF& p) { p4_ = p; }
+
+ const PointF& p1() const { return p1_; }
+ const PointF& p2() const { return p2_; }
+ const PointF& p3() const { return p3_; }
+ const PointF& p4() const { return p4_; }
+
+ // Returns true if the quad is an axis-aligned rectangle.
+ bool IsRectilinear() const;
+
+ // Returns true if the points of the quad are in counter-clockwise order. This
+ // assumes that the quad is convex, and that no three points are collinear.
+ bool IsCounterClockwise() const;
+
+ // Returns true if the |point| is contained within the quad, or lies on on
+ // edge of the quad. This assumes that the quad is convex.
+ bool Contains(const gfx::PointF& point) const;
+
+ // Returns a rectangle that bounds the four points of the quad. The points of
+ // the quad may lie on the right/bottom edge of the resulting rectangle,
+ // rather than being strictly inside it.
+ RectF BoundingBox() const {
+ float rl = std::min(std::min(p1_.x(), p2_.x()), std::min(p3_.x(), p4_.x()));
+ float rr = std::max(std::max(p1_.x(), p2_.x()), std::max(p3_.x(), p4_.x()));
+ float rt = std::min(std::min(p1_.y(), p2_.y()), std::min(p3_.y(), p4_.y()));
+ float rb = std::max(std::max(p1_.y(), p2_.y()), std::max(p3_.y(), p4_.y()));
+ return RectF(rl, rt, rr - rl, rb - rt);
+ }
+
+ // Add a vector to the quad, offseting each point in the quad by the vector.
+ void operator+=(const Vector2dF& rhs);
+ // Subtract a vector from the quad, offseting each point in the quad by the
+ // inverse of the vector.
+ void operator-=(const Vector2dF& rhs);
+
+ // Scale each point in the quad by the |scale| factor.
+ void Scale(float scale) { Scale(scale, scale); }
+
+ // Scale each point in the quad by the scale factors along each axis.
+ void Scale(float x_scale, float y_scale);
+
+ // Returns a string representation of quad.
+ std::string ToString() const;
+
+ private:
+ PointF p1_;
+ PointF p2_;
+ PointF p3_;
+ PointF p4_;
+};
+
+inline bool operator==(const QuadF& lhs, const QuadF& rhs) {
+ return
+ lhs.p1() == rhs.p1() && lhs.p2() == rhs.p2() &&
+ lhs.p3() == rhs.p3() && lhs.p4() == rhs.p4();
+}
+
+inline bool operator!=(const QuadF& lhs, const QuadF& rhs) {
+ return !(lhs == rhs);
+}
+
+// Add a vector to a quad, offseting each point in the quad by the vector.
+GFX_EXPORT QuadF operator+(const QuadF& lhs, const Vector2dF& rhs);
+// Subtract a vector from a quad, offseting each point in the quad by the
+// inverse of the vector.
+GFX_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_QUAD_F_H_
diff --git a/chromium/ui/gfx/geometry/quad_unittest.cc b/chromium/ui/gfx/geometry/quad_unittest.cc
new file mode 100644
index 00000000000..6ba2b51813e
--- /dev/null
+++ b/chromium/ui/gfx/geometry/quad_unittest.cc
@@ -0,0 +1,359 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace gfx {
+
+TEST(QuadTest, Construction) {
+ // Verify constructors.
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ PointF e;
+ QuadF q1;
+ QuadF q2(e, e, e, e);
+ QuadF q3(a, b, c, d);
+ QuadF q4(BoundingRect(a, c));
+ EXPECT_EQ(q1.ToString(), q2.ToString());
+ EXPECT_EQ(q3.ToString(), q4.ToString());
+
+ // Verify getters.
+ EXPECT_EQ(q3.p1().ToString(), a.ToString());
+ EXPECT_EQ(q3.p2().ToString(), b.ToString());
+ EXPECT_EQ(q3.p3().ToString(), c.ToString());
+ EXPECT_EQ(q3.p4().ToString(), d.ToString());
+
+ // Verify setters.
+ q3.set_p1(b);
+ q3.set_p2(c);
+ q3.set_p3(d);
+ q3.set_p4(a);
+ EXPECT_EQ(q3.p1().ToString(), b.ToString());
+ EXPECT_EQ(q3.p2().ToString(), c.ToString());
+ EXPECT_EQ(q3.p3().ToString(), d.ToString());
+ EXPECT_EQ(q3.p4().ToString(), a.ToString());
+
+ // Verify operator=(Rect)
+ EXPECT_NE(q1.ToString(), q4.ToString());
+ q1 = BoundingRect(a, c);
+ EXPECT_EQ(q1.ToString(), q4.ToString());
+
+ // Verify operator=(Quad)
+ EXPECT_NE(q1.ToString(), q3.ToString());
+ q1 = q3;
+ EXPECT_EQ(q1.ToString(), q3.ToString());
+}
+
+TEST(QuadTest, AddingVectors) {
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ Vector2dF v(3.5f, -2.5f);
+
+ QuadF q1(a, b, c, d);
+ QuadF added = q1 + v;
+ q1 += v;
+ QuadF expected1(PointF(4.5f, -1.5f),
+ PointF(5.5f, -1.5f),
+ PointF(5.5f, -0.5f),
+ PointF(4.5f, -0.5f));
+ EXPECT_EQ(expected1.ToString(), added.ToString());
+ EXPECT_EQ(expected1.ToString(), q1.ToString());
+
+ QuadF q2(a, b, c, d);
+ QuadF subtracted = q2 - v;
+ q2 -= v;
+ QuadF expected2(PointF(-2.5f, 3.5f),
+ PointF(-1.5f, 3.5f),
+ PointF(-1.5f, 4.5f),
+ PointF(-2.5f, 4.5f));
+ EXPECT_EQ(expected2.ToString(), subtracted.ToString());
+ EXPECT_EQ(expected2.ToString(), q2.ToString());
+
+ QuadF q3(a, b, c, d);
+ q3 += v;
+ q3 -= v;
+ EXPECT_EQ(QuadF(a, b, c, d).ToString(), q3.ToString());
+ EXPECT_EQ(q3.ToString(), (q3 + v - v).ToString());
+}
+
+TEST(QuadTest, IsRectilinear) {
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ Vector2dF v(3.5f, -2.5f);
+
+ EXPECT_TRUE(QuadF().IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
+
+ float epsilon = std::numeric_limits<float>::epsilon();
+ PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
+ PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
+ PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
+ PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
+ EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
+
+ struct {
+ PointF a_off, b_off, c_off, d_off;
+ } tests[] = {
+ {
+ PointF(1, 1.00001f),
+ PointF(2, 1.00001f),
+ PointF(2, 2.00001f),
+ PointF(1, 2.00001f)
+ },
+ {
+ PointF(1.00001f, 1),
+ PointF(2.00001f, 1),
+ PointF(2.00001f, 2),
+ PointF(1.00001f, 2)
+ },
+ {
+ PointF(1.00001f, 1.00001f),
+ PointF(2.00001f, 1.00001f),
+ PointF(2.00001f, 2.00001f),
+ PointF(1.00001f, 2.00001f)
+ },
+ {
+ PointF(1, 0.99999f),
+ PointF(2, 0.99999f),
+ PointF(2, 1.99999f),
+ PointF(1, 1.99999f)
+ },
+ {
+ PointF(0.99999f, 1),
+ PointF(1.99999f, 1),
+ PointF(1.99999f, 2),
+ PointF(0.99999f, 2)
+ },
+ {
+ PointF(0.99999f, 0.99999f),
+ PointF(1.99999f, 0.99999f),
+ PointF(1.99999f, 1.99999f),
+ PointF(0.99999f, 1.99999f)
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ PointF a_off = tests[i].a_off;
+ PointF b_off = tests[i].b_off;
+ PointF c_off = tests[i].c_off;
+ PointF d_off = tests[i].d_off;
+
+ EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
+ EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
+ }
+}
+
+TEST(QuadTest, IsCounterClockwise) {
+ PointF a1(1, 1);
+ PointF b1(2, 1);
+ PointF c1(2, 2);
+ PointF d1(1, 2);
+ EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
+
+ // Slightly more complicated quads should work just as easily.
+ PointF a2(1.3f, 1.4f);
+ PointF b2(-0.7f, 4.9f);
+ PointF c2(1.8f, 6.2f);
+ PointF d2(2.1f, 1.6f);
+ EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
+
+ // Quads with 3 collinear points should work correctly, too.
+ PointF a3(0, 0);
+ PointF b3(1, 0);
+ PointF c3(2, 0);
+ PointF d3(1, 1);
+ EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
+ // The next expectation in particular would fail for an implementation
+ // that incorrectly uses only a cross product of the first 3 vertices.
+ EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
+
+ // Non-convex quads should work correctly, too.
+ PointF a4(0, 0);
+ PointF b4(1, 1);
+ PointF c4(2, 0);
+ PointF d4(1, 3);
+ EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
+
+ // A quad with huge coordinates should not fail this check due to
+ // single-precision overflow.
+ PointF a5(1e30f, 1e30f);
+ PointF b5(1e35f, 1e30f);
+ PointF c5(1e35f, 1e35f);
+ PointF d5(1e30f, 1e35f);
+ EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
+}
+
+TEST(QuadTest, BoundingBox) {
+ RectF r(3.2f, 5.4f, 7.007f, 12.01f);
+ EXPECT_EQ(r.ToString(), QuadF(r).BoundingBox().ToString());
+
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.7f, 4.9f);
+ PointF c(1.8f, 6.2f);
+ PointF d(2.1f, 1.6f);
+ float left = -0.7f;
+ float top = 1.4f;
+ float right = 2.1f;
+ float bottom = 6.2f;
+ EXPECT_EQ(RectF(left, top, right - left, bottom - top).ToString(),
+ QuadF(a, b, c, d).BoundingBox().ToString());
+}
+
+TEST(QuadTest, ContainsPoint) {
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.8f, 4.4f);
+ PointF c(1.8f, 6.1f);
+ PointF d(2.1f, 1.6f);
+
+ Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
+ Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
+
+ Vector2dF ac_center = c - a;
+ ac_center.Scale(0.5f);
+ Vector2dF bd_center = d - b;
+ bd_center.Scale(0.5f);
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
+
+ // Test a simple square.
+ PointF s1(-1, -1);
+ PointF s2(1, -1);
+ PointF s3(1, 1);
+ PointF s4(-1, 1);
+ // Top edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
+ // Bottom edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
+ // Left edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
+ // Right edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
+ // Centered inside.
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
+ // Centered outside.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
+}
+
+TEST(QuadTest, Scale) {
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.8f, 4.4f);
+ PointF c(1.8f, 6.1f);
+ PointF d(2.1f, 1.6f);
+ QuadF q1(a, b, c, d);
+ q1.Scale(1.5f);
+
+ PointF a_scaled = ScalePoint(a, 1.5f);
+ PointF b_scaled = ScalePoint(b, 1.5f);
+ PointF c_scaled = ScalePoint(c, 1.5f);
+ PointF d_scaled = ScalePoint(d, 1.5f);
+ EXPECT_EQ(q1.ToString(),
+ QuadF(a_scaled, b_scaled, c_scaled, d_scaled).ToString());
+
+ QuadF q2;
+ q2.Scale(1.5f);
+ EXPECT_EQ(q2.ToString(), q2.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/r_tree.h b/chromium/ui/gfx/geometry/r_tree.h
new file mode 100644
index 00000000000..53fd5c9f900
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree.h
@@ -0,0 +1,182 @@
+// 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.
+
+// Defines a hierarchical bounding rectangle data structure for Rect objects,
+// associated with a generic unique key K for efficient spatial queries. The
+// R*-tree algorithm is used to build the trees. Based on the papers:
+//
+// A Guttman 'R-trees: a dynamic index structure for spatial searching', Proc
+// ACM SIGMOD Int Conf on Management of Data, 47-57, 1984
+//
+// N Beckmann, H-P Kriegel, R Schneider, B Seeger 'The R*-tree: an efficient and
+// robust access method for points and rectangles', Proc ACM SIGMOD Int Conf on
+// Management of Data, 322-331, 1990
+
+#ifndef UI_GFX_GEOMETRY_R_TREE_H_
+#define UI_GFX_GEOMETRY_R_TREE_H_
+
+#include "r_tree_base.h"
+
+namespace gfx {
+
+template <typename Key>
+class RTree : public RTreeBase {
+ public:
+ typedef base::hash_set<Key> Matches;
+
+ // RTrees organize pairs of keys and rectangles in a hierarchical bounding
+ // box structure. This allows for queries of the tree within logarithmic time.
+ // |min_children| and |max_children| allows for adjustment of the average size
+ // of the nodes within RTree, which adjusts the base of the logarithm in the
+ // algorithm runtime. Some parts of insertion and deletion are polynomial
+ // in the size of the individual node, so the trade-off with larger nodes is
+ // potentially faster queries but slower insertions and deletions. Generally
+ // it is worth considering how much overlap between rectangles of different
+ // keys will occur in the tree, and trying to set |max_children| as a
+ // reasonable upper bound to the number of overlapping rectangles expected.
+ // Then |min_children| can bet set to a quantity slightly less than half of
+ // that.
+ RTree(size_t min_children, size_t max_children);
+ ~RTree();
+
+ // Insert a new rect into the tree, associated with provided key. Note that if
+ // |rect| is empty, the |key| will not actually be inserted. Duplicate keys
+ // overwrite old entries.
+ void Insert(const Rect& rect, Key key);
+
+ // If present, remove the supplied |key| from the tree.
+ void Remove(Key key);
+
+ // Fills |matches_out| with all keys having bounding rects intersecting
+ // |query_rect|.
+ void AppendIntersectingRecords(const Rect& query_rect,
+ Matches* matches_out) const;
+
+ void Clear();
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ class Record : public RecordBase {
+ public:
+ Record(const Rect& rect, const Key& key);
+ virtual ~Record();
+ const Key& key() const { return key_; }
+
+ private:
+ Key key_;
+
+ DISALLOW_COPY_AND_ASSIGN(Record);
+ };
+
+ // A map of supplied keys to their Node representation within the RTree, for
+ // efficient retrieval of keys without requiring a bounding rect.
+ typedef base::hash_map<Key, Record*> RecordMap;
+ RecordMap record_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTree);
+};
+
+template <typename Key>
+RTree<Key>::RTree(size_t min_children, size_t max_children)
+ : RTreeBase(min_children, max_children) {
+}
+
+template <typename Key>
+RTree<Key>::~RTree() {
+}
+
+template <typename Key>
+void RTree<Key>::Insert(const Rect& rect, Key key) {
+ scoped_ptr<NodeBase> record;
+ // Check if this key is already present in the tree.
+ typename RecordMap::iterator it(record_map_.find(key));
+
+ if (it != record_map_.end()) {
+ // We will re-use this node structure, regardless of re-insert or return.
+ Record* existing_record = it->second;
+ // If the new rect and the current rect are identical we can skip the rest
+ // of Insert() as nothing has changed.
+ if (existing_record->rect() == rect)
+ return;
+
+ // Remove the node from the tree in its current position.
+ record = RemoveNode(existing_record);
+
+ PruneRootIfNecessary();
+
+ // If we are replacing this key with an empty rectangle we just remove the
+ // old node from the list and return, thus preventing insertion of empty
+ // rectangles into our spatial database.
+ if (rect.IsEmpty()) {
+ record_map_.erase(it);
+ return;
+ }
+
+ // Reset the rectangle to the new value.
+ record->set_rect(rect);
+ } else {
+ if (rect.IsEmpty())
+ return;
+
+ record.reset(new Record(rect, key));
+ record_map_.insert(std::make_pair(key, static_cast<Record*>(record.get())));
+ }
+
+ int highest_reinsert_level = -1;
+ InsertNode(record.Pass(), &highest_reinsert_level);
+}
+
+template <typename Key>
+void RTree<Key>::Clear() {
+ record_map_.clear();
+ ResetRoot();
+}
+
+template <typename Key>
+void RTree<Key>::Remove(Key key) {
+ // Search the map for the leaf parent that has the provided record.
+ typename RecordMap::iterator it = record_map_.find(key);
+ if (it == record_map_.end())
+ return;
+
+ Record* record = it->second;
+ record_map_.erase(it);
+ RemoveNode(record);
+
+ // Lastly check the root. If it has only one non-leaf child, delete it and
+ // replace it with its child.
+ PruneRootIfNecessary();
+}
+
+template <typename Key>
+void RTree<Key>::AppendIntersectingRecords(
+ const Rect& query_rect, Matches* matches_out) const {
+ RTreeBase::Records matching_records;
+ root()->AppendIntersectingRecords(query_rect, &matching_records);
+ for (RTreeBase::Records::const_iterator it = matching_records.begin();
+ it != matching_records.end();
+ ++it) {
+ const Record* record = static_cast<const Record*>(*it);
+ matches_out->insert(record->key());
+ }
+}
+
+
+// RTree::Record --------------------------------------------------------------
+
+template <typename Key>
+RTree<Key>::Record::Record(const Rect& rect, const Key& key)
+ : RecordBase(rect),
+ key_(key) {
+}
+
+template <typename Key>
+RTree<Key>::Record::~Record() {
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_R_TREE_H_
diff --git a/chromium/ui/gfx/geometry/r_tree_base.cc b/chromium/ui/gfx/geometry/r_tree_base.cc
new file mode 100644
index 00000000000..e93e1d5b6b1
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_base.cc
@@ -0,0 +1,658 @@
+// 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/gfx/geometry/r_tree_base.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+
+// Helpers --------------------------------------------------------------------
+
+namespace {
+
+// Returns a Vector2d to allow us to do arithmetic on the result such as
+// computing distances between centers.
+gfx::Vector2d CenterOfRect(const gfx::Rect& rect) {
+ return rect.OffsetFromOrigin() +
+ gfx::Vector2d(rect.width() / 2, rect.height() / 2);
+}
+
+}
+
+namespace gfx {
+
+
+// RTreeBase::NodeBase --------------------------------------------------------
+
+RTreeBase::NodeBase::~NodeBase() {
+}
+
+void RTreeBase::NodeBase::RecomputeBoundsUpToRoot() {
+ RecomputeLocalBounds();
+ if (parent_)
+ parent_->RecomputeBoundsUpToRoot();
+}
+
+RTreeBase::NodeBase::NodeBase(const Rect& rect, NodeBase* parent)
+ : rect_(rect),
+ parent_(parent) {
+}
+
+void RTreeBase::NodeBase::RecomputeLocalBounds() {
+}
+
+// RTreeBase::RecordBase ------------------------------------------------------
+
+RTreeBase::RecordBase::RecordBase(const Rect& rect) : NodeBase(rect, NULL) {
+}
+
+RTreeBase::RecordBase::~RecordBase() {
+}
+
+void RTreeBase::RecordBase::AppendIntersectingRecords(
+ const Rect& query_rect, Records* matches_out) const {
+ if (rect().Intersects(query_rect))
+ matches_out->push_back(this);
+}
+
+void RTreeBase::RecordBase::AppendAllRecords(Records* matches_out) const {
+ matches_out->push_back(this);
+}
+
+scoped_ptr<RTreeBase::NodeBase>
+RTreeBase::RecordBase::RemoveAndReturnLastChild() {
+ return scoped_ptr<NodeBase>();
+}
+
+int RTreeBase::RecordBase::Level() const {
+ return -1;
+}
+
+
+// RTreeBase::Node ------------------------------------------------------------
+
+RTreeBase::Node::Node() : NodeBase(Rect(), NULL), level_(0) {
+}
+
+RTreeBase::Node::~Node() {
+}
+
+scoped_ptr<RTreeBase::Node> RTreeBase::Node::ConstructParent() {
+ DCHECK(!parent());
+ scoped_ptr<Node> new_parent(new Node(level_ + 1));
+ new_parent->AddChild(scoped_ptr<NodeBase>(this));
+ return new_parent.Pass();
+}
+
+void RTreeBase::Node::AppendIntersectingRecords(
+ const Rect& query_rect, Records* matches_out) const {
+ // Check own bounding box for intersection, can cull all children if no
+ // intersection.
+ if (!rect().Intersects(query_rect))
+ return;
+
+ // Conversely if we are completely contained within the query rect we can
+ // confidently skip all bounds checks for ourselves and all our children.
+ if (query_rect.Contains(rect())) {
+ AppendAllRecords(matches_out);
+ return;
+ }
+
+ // We intersect the query rect but we are not are not contained within it.
+ // We must query each of our children in turn.
+ for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i)
+ (*i)->AppendIntersectingRecords(query_rect, matches_out);
+}
+
+void RTreeBase::Node::AppendAllRecords(Records* matches_out) const {
+ for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i)
+ (*i)->AppendAllRecords(matches_out);
+}
+
+void RTreeBase::Node::RemoveNodesForReinsert(size_t number_to_remove,
+ Nodes* nodes) {
+ DCHECK_LE(number_to_remove, children_.size());
+
+ std::partial_sort(children_.begin(),
+ children_.begin() + number_to_remove,
+ children_.end(),
+ &RTreeBase::Node::CompareCenterDistanceFromParent);
+
+ // Move the lowest-distance nodes to the returned vector.
+ nodes->insert(
+ nodes->end(), children_.begin(), children_.begin() + number_to_remove);
+ children_.weak_erase(children_.begin(), children_.begin() + number_to_remove);
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::RemoveChild(
+ NodeBase* child_node, Nodes* orphans) {
+ DCHECK_EQ(this, child_node->parent());
+
+ scoped_ptr<NodeBase> orphan(child_node->RemoveAndReturnLastChild());
+ while (orphan) {
+ orphans->push_back(orphan.release());
+ orphan = child_node->RemoveAndReturnLastChild();
+ }
+
+ Nodes::iterator i = std::find(children_.begin(), children_.end(), child_node);
+ DCHECK(i != children_.end());
+ children_.weak_erase(i);
+
+ return scoped_ptr<NodeBase>(child_node);
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::RemoveAndReturnLastChild() {
+ if (children_.empty())
+ return scoped_ptr<NodeBase>();
+
+ scoped_ptr<NodeBase> last_child(children_.back());
+ children_.weak_erase(children_.end() - 1);
+ last_child->set_parent(NULL);
+ return last_child.Pass();
+}
+
+RTreeBase::Node* RTreeBase::Node::ChooseSubtree(NodeBase* node) {
+ DCHECK(node);
+ // Should never be called on a node at equal or lower level in the tree than
+ // the node to insert.
+ DCHECK_GT(level_, node->Level());
+
+ // If we are a parent of nodes on the provided node level, we are done.
+ if (level_ == node->Level() + 1)
+ return this;
+
+ // Precompute a vector of expanded rects, used by both LeastOverlapIncrease
+ // and LeastAreaEnlargement.
+ Rects expanded_rects;
+ expanded_rects.reserve(children_.size());
+ for (Nodes::iterator i = children_.begin(); i != children_.end(); ++i)
+ expanded_rects.push_back(UnionRects(node->rect(), (*i)->rect()));
+
+ Node* best_candidate = NULL;
+ // For parents of leaf nodes, we pick the node that will cause the least
+ // increase in overlap by the addition of this new node. This may detect a
+ // tie, in which case it will return NULL.
+ if (level_ == 1)
+ best_candidate = LeastOverlapIncrease(node->rect(), expanded_rects);
+
+ // For non-parents of leaf nodes, or for parents of leaf nodes with ties in
+ // overlap increase, we choose the subtree with least area enlargement caused
+ // by the addition of the new node.
+ if (!best_candidate)
+ best_candidate = LeastAreaEnlargement(node->rect(), expanded_rects);
+
+ DCHECK(best_candidate);
+ return best_candidate->ChooseSubtree(node);
+}
+
+size_t RTreeBase::Node::AddChild(scoped_ptr<NodeBase> node) {
+ DCHECK(node);
+ // Sanity-check that the level of the child being added is one less than ours.
+ DCHECK_EQ(level_ - 1, node->Level());
+ node->set_parent(this);
+ set_rect(UnionRects(rect(), node->rect()));
+ children_.push_back(node.release());
+ return children_.size();
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::Split(size_t min_children,
+ size_t max_children) {
+ // We should have too many children to begin with.
+ DCHECK_EQ(max_children + 1, children_.size());
+
+ // Determine if we should split along the horizontal or vertical axis.
+ std::vector<NodeBase*> vertical_sort(children_.get());
+ std::vector<NodeBase*> horizontal_sort(children_.get());
+ std::sort(vertical_sort.begin(),
+ vertical_sort.end(),
+ &RTreeBase::Node::CompareVertical);
+ std::sort(horizontal_sort.begin(),
+ horizontal_sort.end(),
+ &RTreeBase::Node::CompareHorizontal);
+
+ Rects low_vertical_bounds;
+ Rects low_horizontal_bounds;
+ BuildLowBounds(vertical_sort,
+ horizontal_sort,
+ &low_vertical_bounds,
+ &low_horizontal_bounds);
+
+ Rects high_vertical_bounds;
+ Rects high_horizontal_bounds;
+ BuildHighBounds(vertical_sort,
+ horizontal_sort,
+ &high_vertical_bounds,
+ &high_horizontal_bounds);
+
+ // Choose |end_index| such that both Nodes after the split will have
+ // min_children <= children_.size() <= max_children.
+ size_t end_index = std::min(max_children, children_.size() - min_children);
+ bool is_vertical_split =
+ SmallestMarginSum(min_children,
+ end_index,
+ low_horizontal_bounds,
+ high_horizontal_bounds) <
+ SmallestMarginSum(min_children,
+ end_index,
+ low_vertical_bounds,
+ high_vertical_bounds);
+
+ // Choose split index along chosen axis and perform the split.
+ const Rects& low_bounds(
+ is_vertical_split ? low_vertical_bounds : low_horizontal_bounds);
+ const Rects& high_bounds(
+ is_vertical_split ? high_vertical_bounds : high_horizontal_bounds);
+ size_t split_index =
+ ChooseSplitIndex(min_children, end_index, low_bounds, high_bounds);
+
+ const std::vector<NodeBase*>& sort(
+ is_vertical_split ? vertical_sort : horizontal_sort);
+ return DivideChildren(low_bounds, high_bounds, sort, split_index);
+}
+
+int RTreeBase::Node::Level() const {
+ return level_;
+}
+
+RTreeBase::Node::Node(int level) : NodeBase(Rect(), NULL), level_(level) {
+}
+
+// static
+bool RTreeBase::Node::CompareVertical(const NodeBase* a, const NodeBase* b) {
+ const Rect& a_rect = a->rect();
+ const Rect& b_rect = b->rect();
+ return (a_rect.y() < b_rect.y()) ||
+ ((a_rect.y() == b_rect.y()) && (a_rect.height() < b_rect.height()));
+}
+
+// static
+bool RTreeBase::Node::CompareHorizontal(const NodeBase* a, const NodeBase* b) {
+ const Rect& a_rect = a->rect();
+ const Rect& b_rect = b->rect();
+ return (a_rect.x() < b_rect.x()) ||
+ ((a_rect.x() == b_rect.x()) && (a_rect.width() < b_rect.width()));
+}
+
+// static
+bool RTreeBase::Node::CompareCenterDistanceFromParent(const NodeBase* a,
+ const NodeBase* b) {
+ const NodeBase* p = a->parent();
+
+ DCHECK(p);
+ DCHECK_EQ(p, b->parent());
+
+ Vector2d p_center = CenterOfRect(p->rect());
+ Vector2d a_center = CenterOfRect(a->rect());
+ Vector2d b_center = CenterOfRect(b->rect());
+
+ // We don't bother with square roots because we are only comparing the two
+ // values for sorting purposes.
+ return (a_center - p_center).LengthSquared() <
+ (b_center - p_center).LengthSquared();
+}
+
+// static
+void RTreeBase::Node::BuildLowBounds(
+ const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds) {
+ Rect vertical_bounds_rect;
+ vertical_bounds->reserve(vertical_sort.size());
+ for (std::vector<NodeBase*>::const_iterator i = vertical_sort.begin();
+ i != vertical_sort.end();
+ ++i) {
+ vertical_bounds_rect.Union((*i)->rect());
+ vertical_bounds->push_back(vertical_bounds_rect);
+ }
+
+ Rect horizontal_bounds_rect;
+ horizontal_bounds->reserve(horizontal_sort.size());
+ for (std::vector<NodeBase*>::const_iterator i = horizontal_sort.begin();
+ i != horizontal_sort.end();
+ ++i) {
+ horizontal_bounds_rect.Union((*i)->rect());
+ horizontal_bounds->push_back(horizontal_bounds_rect);
+ }
+}
+
+// static
+void RTreeBase::Node::BuildHighBounds(
+ const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds) {
+ Rect vertical_bounds_rect;
+ vertical_bounds->reserve(vertical_sort.size());
+ for (std::vector<NodeBase*>::const_reverse_iterator i =
+ vertical_sort.rbegin();
+ i != vertical_sort.rend();
+ ++i) {
+ vertical_bounds_rect.Union((*i)->rect());
+ vertical_bounds->push_back(vertical_bounds_rect);
+ }
+ std::reverse(vertical_bounds->begin(), vertical_bounds->end());
+
+ Rect horizontal_bounds_rect;
+ horizontal_bounds->reserve(horizontal_sort.size());
+ for (std::vector<NodeBase*>::const_reverse_iterator i =
+ horizontal_sort.rbegin();
+ i != horizontal_sort.rend();
+ ++i) {
+ horizontal_bounds_rect.Union((*i)->rect());
+ horizontal_bounds->push_back(horizontal_bounds_rect);
+ }
+ std::reverse(horizontal_bounds->begin(), horizontal_bounds->end());
+}
+
+size_t RTreeBase::Node::ChooseSplitIndex(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+
+ int smallest_overlap_area = UnionRects(
+ low_bounds[start_index], high_bounds[start_index]).size().GetArea();
+ int smallest_combined_area = low_bounds[start_index].size().GetArea() +
+ high_bounds[start_index].size().GetArea();
+ size_t optimal_split_index = start_index;
+ for (size_t p = start_index + 1; p < end_index; ++p) {
+ const int overlap_area =
+ UnionRects(low_bounds[p], high_bounds[p]).size().GetArea();
+ const int combined_area =
+ low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea();
+ if ((overlap_area < smallest_overlap_area) ||
+ ((overlap_area == smallest_overlap_area) &&
+ (combined_area < smallest_combined_area))) {
+ smallest_overlap_area = overlap_area;
+ smallest_combined_area = combined_area;
+ optimal_split_index = p;
+ }
+ }
+
+ // optimal_split_index currently points at the last element in the first set,
+ // so advance it by 1 to point at the first element in the second set.
+ return optimal_split_index + 1;
+}
+
+// static
+int RTreeBase::Node::SmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+ DCHECK_LT(start_index, low_bounds.size());
+ DCHECK_LE(start_index, end_index);
+ DCHECK_LE(end_index, low_bounds.size());
+ Rects::const_iterator i(low_bounds.begin() + start_index);
+ Rects::const_iterator j(high_bounds.begin() + start_index);
+ int smallest_sum = i->width() + i->height() + j->width() + j->height();
+ for (; i != (low_bounds.begin() + end_index); ++i, ++j) {
+ smallest_sum = std::min(
+ smallest_sum, i->width() + i->height() + j->width() + j->height());
+ }
+
+ return smallest_sum;
+}
+
+void RTreeBase::Node::RecomputeLocalBounds() {
+ Rect bounds;
+ for (size_t i = 0; i < children_.size(); ++i)
+ bounds.Union(children_[i]->rect());
+
+ set_rect(bounds);
+}
+
+int RTreeBase::Node::OverlapIncreaseToAdd(const Rect& rect,
+ const NodeBase* candidate_node,
+ const Rect& expanded_rect) const {
+ DCHECK(candidate_node);
+
+ // Early-out when |rect| is contained completely within |candidate|.
+ if (candidate_node->rect().Contains(rect))
+ return 0;
+
+ int total_original_overlap = 0;
+ int total_expanded_overlap = 0;
+
+ // Now calculate overlap with all other rects in this node.
+ for (Nodes::const_iterator it = children_.begin();
+ it != children_.end(); ++it) {
+ // Skip calculating overlap with the candidate rect.
+ if ((*it) == candidate_node)
+ continue;
+ NodeBase* overlap_node = (*it);
+ total_original_overlap += IntersectRects(
+ candidate_node->rect(), overlap_node->rect()).size().GetArea();
+ Rect expanded_overlap_rect = expanded_rect;
+ expanded_overlap_rect.Intersect(overlap_node->rect());
+ total_expanded_overlap += expanded_overlap_rect.size().GetArea();
+ }
+
+ return total_expanded_overlap - total_original_overlap;
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::DivideChildren(
+ const Rects& low_bounds,
+ const Rects& high_bounds,
+ const std::vector<NodeBase*>& sorted_children,
+ size_t split_index) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+ DCHECK_EQ(low_bounds.size(), sorted_children.size());
+ DCHECK_LT(split_index, low_bounds.size());
+ DCHECK_GT(split_index, 0U);
+
+ scoped_ptr<Node> sibling(new Node(level_));
+ sibling->set_parent(parent());
+ set_rect(low_bounds[split_index - 1]);
+ sibling->set_rect(high_bounds[split_index]);
+
+ // Our own children_ vector is unsorted, so we wipe it out and divide the
+ // sorted bounds rects between ourselves and our sibling.
+ children_.weak_clear();
+ children_.insert(children_.end(),
+ sorted_children.begin(),
+ sorted_children.begin() + split_index);
+ sibling->children_.insert(sibling->children_.end(),
+ sorted_children.begin() + split_index,
+ sorted_children.end());
+
+ for (size_t i = 0; i < sibling->children_.size(); ++i)
+ sibling->children_[i]->set_parent(sibling.get());
+
+ return sibling.PassAs<NodeBase>();
+}
+
+RTreeBase::Node* RTreeBase::Node::LeastOverlapIncrease(
+ const Rect& node_rect,
+ const Rects& expanded_rects) {
+ NodeBase* best_node = children_.front();
+ int least_overlap_increase =
+ OverlapIncreaseToAdd(node_rect, children_[0], expanded_rects[0]);
+ for (size_t i = 1; i < children_.size(); ++i) {
+ int overlap_increase =
+ OverlapIncreaseToAdd(node_rect, children_[i], expanded_rects[i]);
+ if (overlap_increase < least_overlap_increase) {
+ least_overlap_increase = overlap_increase;
+ best_node = children_[i];
+ } else if (overlap_increase == least_overlap_increase) {
+ // If we are tied at zero there is no possible better overlap increase,
+ // so we can report a tie early.
+ if (overlap_increase == 0)
+ return NULL;
+
+ best_node = NULL;
+ }
+ }
+
+ // Ensure that our children are always Nodes and not Records.
+ DCHECK_GE(level_, 1);
+ return static_cast<Node*>(best_node);
+}
+
+RTreeBase::Node* RTreeBase::Node::LeastAreaEnlargement(
+ const Rect& node_rect,
+ const Rects& expanded_rects) {
+ DCHECK(!children_.empty());
+ DCHECK_EQ(children_.size(), expanded_rects.size());
+
+ NodeBase* best_node = children_.front();
+ int least_area_enlargement =
+ expanded_rects[0].size().GetArea() - best_node->rect().size().GetArea();
+ for (size_t i = 1; i < children_.size(); ++i) {
+ NodeBase* candidate_node = children_[i];
+ int area_change = expanded_rects[i].size().GetArea() -
+ candidate_node->rect().size().GetArea();
+ DCHECK_GE(area_change, 0);
+ if (area_change < least_area_enlargement) {
+ best_node = candidate_node;
+ least_area_enlargement = area_change;
+ } else if (area_change == least_area_enlargement &&
+ candidate_node->rect().size().GetArea() <
+ best_node->rect().size().GetArea()) {
+ // Ties are broken by choosing the entry with the least area.
+ best_node = candidate_node;
+ }
+ }
+
+ // Ensure that our children are always Nodes and not Records.
+ DCHECK_GE(level_, 1);
+ return static_cast<Node*>(best_node);
+}
+
+
+// RTreeBase ------------------------------------------------------------------
+
+RTreeBase::RTreeBase(size_t min_children, size_t max_children)
+ : root_(new Node()),
+ min_children_(min_children),
+ max_children_(max_children) {
+ DCHECK_GE(min_children_, 2U);
+ DCHECK_LE(min_children_, max_children_ / 2U);
+}
+
+RTreeBase::~RTreeBase() {
+}
+
+void RTreeBase::InsertNode(
+ scoped_ptr<NodeBase> node, int* highest_reinsert_level) {
+ // Find the most appropriate parent to insert node into.
+ Node* parent = root_->ChooseSubtree(node.get());
+ DCHECK(parent);
+ // Verify ChooseSubtree returned a Node at the correct level.
+ DCHECK_EQ(parent->Level(), node->Level() + 1);
+ Node* insert_parent = static_cast<Node*>(parent);
+ NodeBase* needs_bounds_recomputed = insert_parent->parent();
+ Nodes reinserts;
+ // Attempt to insert the Node, if this overflows the Node we must handle it.
+ while (insert_parent &&
+ insert_parent->AddChild(node.Pass()) > max_children_) {
+ // If we have yet to re-insert nodes at this level during this data insert,
+ // and we're not at the root, R*-Tree calls for re-insertion of some of the
+ // nodes, resulting in a better balance on the tree.
+ if (insert_parent->parent() &&
+ insert_parent->Level() > *highest_reinsert_level) {
+ insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts);
+ // Adjust highest_reinsert_level to this level.
+ *highest_reinsert_level = insert_parent->Level();
+ // RemoveNodesForReinsert() does not recompute bounds, so mark it.
+ needs_bounds_recomputed = insert_parent;
+ break;
+ }
+
+ // Split() will create a sibling to insert_parent both of which will have
+ // valid bounds, but this invalidates their parent's bounds.
+ node = insert_parent->Split(min_children_, max_children_);
+ insert_parent = static_cast<Node*>(insert_parent->parent());
+ needs_bounds_recomputed = insert_parent;
+ }
+
+ // If we have a Node to insert, and we hit the root of the current tree,
+ // we create a new root which is the parent of the current root and the
+ // insert_node. Note that we must release() the |root_| since
+ // ConstructParent() will take ownership of it.
+ if (!insert_parent && node) {
+ root_ = root_.release()->ConstructParent();
+ root_->AddChild(node.Pass());
+ }
+
+ // Recompute bounds along insertion path.
+ if (needs_bounds_recomputed)
+ needs_bounds_recomputed->RecomputeBoundsUpToRoot();
+
+ // Complete re-inserts, if any. The algorithm only allows for one invocation
+ // of RemoveNodesForReinsert() per level of the tree in an overall call to
+ // Insert().
+ while (!reinserts.empty()) {
+ Nodes::iterator last_element = reinserts.end() - 1;
+ NodeBase* temp_ptr(*last_element);
+ reinserts.weak_erase(last_element);
+ InsertNode(make_scoped_ptr(temp_ptr), highest_reinsert_level);
+ }
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::RemoveNode(NodeBase* node) {
+ // We need to remove this node from its parent.
+ Node* parent = static_cast<Node*>(node->parent());
+ // Record nodes are never allowed as the root, so we should always have a
+ // parent.
+ DCHECK(parent);
+ // Should always be a leaf that had the record.
+ DCHECK_EQ(0, parent->Level());
+
+ Nodes orphans;
+ scoped_ptr<NodeBase> removed_node(parent->RemoveChild(node, &orphans));
+
+ // It's possible that by removing |node| from |parent| we have made |parent|
+ // have less than the minimum number of children, in which case we will need
+ // to remove and delete |parent| while reinserting any other children that it
+ // had. We traverse up the tree doing this until we remove a child from a
+ // parent that still has greater than or equal to the minimum number of Nodes.
+ while (parent->count() < min_children_) {
+ NodeBase* child = parent;
+ parent = static_cast<Node*>(parent->parent());
+
+ // If we've hit the root, stop.
+ if (!parent)
+ break;
+
+ parent->RemoveChild(child, &orphans);
+ }
+
+ // If we stopped deleting nodes up the tree before encountering the root,
+ // we'll need to fix up the bounds from the first parent we didn't delete
+ // up to the root.
+ if (parent)
+ parent->RecomputeBoundsUpToRoot();
+ else
+ root_->RecomputeBoundsUpToRoot();
+
+ while (!orphans.empty()) {
+ Nodes::iterator last_element = orphans.end() - 1;
+ NodeBase* temp_ptr(*last_element);
+ orphans.weak_erase(last_element);
+ int starting_level = -1;
+ InsertNode(make_scoped_ptr(temp_ptr), &starting_level);
+ }
+
+ return removed_node.Pass();
+}
+
+void RTreeBase::PruneRootIfNecessary() {
+ if (root()->count() == 1 && root()->Level() > 0) {
+ // Awkward reset(cast(release)) pattern here because there's no better way
+ // to downcast the scoped_ptr from RemoveAndReturnLastChild() from NodeBase
+ // to Node.
+ root_.reset(
+ static_cast<Node*>(root_->RemoveAndReturnLastChild().release()));
+ }
+}
+
+void RTreeBase::ResetRoot() {
+ root_.reset(new Node());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/r_tree_base.h b/chromium/ui/gfx/geometry/r_tree_base.h
new file mode 100644
index 00000000000..21dc86b2d4d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_base.h
@@ -0,0 +1,309 @@
+// 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.
+
+// Provides an implementation the parts of the RTree data structure that don't
+// require knowledge of the generic key type. Don't use these objects directly,
+// rather specialize the RTree<> object in r_tree.h. This file defines the
+// internal objects of an RTree, namely Nodes (internal nodes of the tree) and
+// Records, which hold (key, rectangle) pairs.
+
+#ifndef UI_GFX_GEOMETRY_R_TREE_BASE_H_
+#define UI_GFX_GEOMETRY_R_TREE_BASE_H_
+
+#include <list>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT RTreeBase {
+ protected:
+ class NodeBase;
+ class RecordBase;
+
+ typedef std::vector<const RecordBase*> Records;
+ typedef ScopedVector<NodeBase> Nodes;
+
+ RTreeBase(size_t min_children, size_t max_children);
+ ~RTreeBase();
+
+ // Protected data structure class for storing internal Nodes or leaves with
+ // Records.
+ class GFX_EXPORT NodeBase {
+ public:
+ virtual ~NodeBase();
+
+ // Appends to |records_out| the set of Records in this subtree with rects
+ // that intersect |query_rect|. Avoids clearing |records_out| so that it
+ // can be called recursively.
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const = 0;
+
+ // Returns all records stored in the subtree rooted at this node. Appends to
+ // |matches_out| without clearing.
+ virtual void AppendAllRecords(Records* records_out) const = 0;
+
+ // Returns NULL if no children. Does not recompute bounds.
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() = 0;
+
+ // Returns -1 for Records, or the height of this subtree for Nodes. The
+ // height of a leaf Node (a Node containing only Records) is 0, a leaf's
+ // parent is 1, etc. Note that in an R*-Tree, all branches from the root
+ // Node will be the same height.
+ virtual int Level() const = 0;
+
+ // Recomputes our bounds by taking the union of all child rects, then calls
+ // recursively on our parent so that ultimately all nodes up to the root
+ // recompute their bounds.
+ void RecomputeBoundsUpToRoot();
+
+ NodeBase* parent() { return parent_; }
+ const NodeBase* parent() const { return parent_; }
+ void set_parent(NodeBase* parent) { parent_ = parent; }
+ const Rect& rect() const { return rect_; }
+ void set_rect(const Rect& rect) { rect_ = rect; }
+
+ protected:
+ NodeBase(const Rect& rect, NodeBase* parent);
+
+ // Bounds recomputation without calling parents to do the same.
+ virtual void RecomputeLocalBounds();
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ // This Node's bounding rectangle.
+ Rect rect_;
+
+ // A weak pointer to our parent Node in the RTree. The root node will have a
+ // NULL value for |parent_|.
+ NodeBase* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(NodeBase);
+ };
+
+ class GFX_EXPORT RecordBase : public NodeBase {
+ public:
+ explicit RecordBase(const Rect& rect);
+ virtual ~RecordBase();
+
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const OVERRIDE;
+ virtual void AppendAllRecords(Records* records_out) const OVERRIDE;
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() OVERRIDE;
+ virtual int Level() const OVERRIDE;
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordBase);
+ };
+
+ class GFX_EXPORT Node : public NodeBase {
+ public:
+ // Constructs an empty Node with |level_| of 0.
+ Node();
+ virtual ~Node();
+
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const OVERRIDE;
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() OVERRIDE;
+ virtual int Level() const OVERRIDE;
+ virtual void AppendAllRecords(Records* matches_out) const OVERRIDE;
+
+ // Constructs a new Node that is the parent of this Node and already has
+ // this Node as its sole child. Valid to call only on root Nodes, meaning
+ // Nodes with |parent_| NULL. Note that ownership of this Node is
+ // transferred to the parent returned by this function.
+ scoped_ptr<Node> ConstructParent();
+
+ // Removes |number_to_remove| children from this Node, and appends them to
+ // the supplied list. Does not repair bounds upon completion. Nodes are
+ // selected in the manner suggested in the Beckmann et al. paper, which
+ // suggests that the children should be sorted by the distance from the
+ // center of their bounding rectangle to their parent's bounding rectangle,
+ // and then the n closest children should be removed for re-insertion. This
+ // removal occurs at most once on each level of the tree when overflowing
+ // nodes that have exceeded the maximum number of children during an Insert.
+ void RemoveNodesForReinsert(size_t number_to_remove, Nodes* nodes);
+
+ // Given a pointer to a child node within this Node, removes it from our
+ // list. If that child had any children, appends them to the supplied orphan
+ // list. Returns the removed child. Does not recompute bounds, as the caller
+ // might subsequently remove this node as well, meaning the recomputation
+ // would be wasted work.
+ scoped_ptr<NodeBase> RemoveChild(NodeBase* child_node, Nodes* orphans);
+
+ // Returns the best parent for insertion of the provided |node| as a child.
+ Node* ChooseSubtree(NodeBase* node);
+
+ // Adds |node| as a child of this Node, and recomputes the bounds of this
+ // node after the addition of the child. Returns the new count of children
+ // stored in this Node. This node becomes the owner of |node|.
+ size_t AddChild(scoped_ptr<NodeBase> node);
+
+ // Returns a sibling to this Node with at least min_children and no greater
+ // than max_children of this Node's children assigned to it, and having the
+ // same parent. Bounds will be valid on both Nodes after this call.
+ scoped_ptr<NodeBase> Split(size_t min_children, size_t max_children);
+
+ size_t count() const { return children_.size(); }
+ const NodeBase* child(size_t i) const { return children_[i]; }
+ NodeBase* child(size_t i) { return children_[i]; }
+
+ private:
+ typedef std::vector<Rect> Rects;
+
+ explicit Node(int level);
+
+ // Given two arrays of bounds rectangles as computed by BuildLowBounds()
+ // and BuildHighBounds(), returns the index of the element in those arrays
+ // along which a split of the arrays would result in a minimum amount of
+ // overlap (area of intersection) in the two groups.
+ static size_t ChooseSplitIndex(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds);
+
+ // R*-Tree attempts to keep groups of rectangles that are roughly square
+ // in shape. It does this by comparing the "margins" of different bounding
+ // boxes, where margin is defined as the sum of the length of all four sides
+ // of a rectangle. For two rectangles of equal area, the one with the
+ // smallest margin will be the rectangle whose width and height differ the
+ // least. When splitting we decide to split along an axis chosen from the
+ // rectangles either sorted vertically or horizontally by finding the axis
+ // that would result in the smallest sum of margins between the two bounding
+ // boxes of the resulting split. Returns the smallest sum computed given the
+ // sorted bounding boxes and a range to look within.
+ static int SmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds);
+
+ // Sorts nodes primarily by increasing y coordinates, and secondarily by
+ // increasing height.
+ static bool CompareVertical(const NodeBase* a, const NodeBase* b);
+
+ // Sorts nodes primarily by increasing x coordinates, and secondarily by
+ // increasing width.
+ static bool CompareHorizontal(const NodeBase* a, const NodeBase* b);
+
+ // Sorts nodes by the distance of the center of their rectangles to the
+ // center of their parent's rectangles.
+ static bool CompareCenterDistanceFromParent(
+ const NodeBase* a, const NodeBase* b);
+
+ // Given two vectors of Nodes sorted by vertical or horizontal bounds,
+ // populates two vectors of Rectangles in which the ith element is the union
+ // of all bounding rectangles [0,i] in the associated sorted array of Nodes.
+ static void BuildLowBounds(const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds);
+
+ // Given two vectors of Nodes sorted by vertical or horizontal bounds,
+ // populates two vectors of Rectangles in which the ith element is the
+ // union of all bounding rectangles [i, count()) in the associated sorted
+ // array of Nodes.
+ static void BuildHighBounds(const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds);
+
+ virtual void RecomputeLocalBounds() OVERRIDE;
+
+ // Returns the increase in overlap value, as defined in Beckmann et al. as
+ // the sum of the areas of the intersection of all child rectangles
+ // (excepting the candidate child) with the argument rectangle. Here the
+ // |candidate_node| is one of our |children_|, and |expanded_rect| is the
+ // already-computed union of the candidate's rect and |rect|.
+ int OverlapIncreaseToAdd(const Rect& rect,
+ const NodeBase* candidate_node,
+ const Rect& expanded_rect) const;
+
+ // Returns a new node containing children [split_index, count()) within
+ // |sorted_children|. Children before |split_index| remain with |this|.
+ scoped_ptr<NodeBase> DivideChildren(
+ const Rects& low_bounds,
+ const Rects& high_bounds,
+ const std::vector<NodeBase*>& sorted_children,
+ size_t split_index);
+
+ // Returns a pointer to the child node that will result in the least overlap
+ // increase with the addition of node_rect, or NULL if there's a tie found.
+ // Requires a precomputed vector of expanded rectangles where the ith
+ // rectangle in the vector is the union of |children_|[i] and node_rect.
+ // Overlap is defined in Beckmann et al. as the sum of the areas of
+ // intersection of all child rectangles with the |node_rect| argument
+ // rectangle. This heuristic attempts to choose the node for which adding
+ // the new rectangle to their bounding box will result in the least overlap
+ // with the other rectangles, thus trying to preserve the usefulness of the
+ // bounding rectangle by keeping it from covering too much redundant area.
+ Node* LeastOverlapIncrease(const Rect& node_rect,
+ const Rects& expanded_rects);
+
+ // Returns a pointer to the child node that will result in the least area
+ // enlargement if the argument node rectangle were to be added to that
+ // node's bounding box. Requires a precomputed vector of expanded rectangles
+ // where the ith rectangle in the vector is the union of children_[i] and
+ // |node_rect|.
+ Node* LeastAreaEnlargement(const Rect& node_rect,
+ const Rects& expanded_rects);
+
+ const int level_;
+
+ Nodes children_;
+
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ DISALLOW_COPY_AND_ASSIGN(Node);
+ };
+
+ // Inserts |node| into the tree. The |highest_reinsert_level| supports
+ // re-insertion as described by Beckmann et al. As Node overflows progagate
+ // up the tree the algorithm performs a reinsertion of the overflow Nodes
+ // (instead of a split) at most once per level of the tree. A starting value
+ // of -1 for |highest_reinsert_level| means that reinserts are permitted for
+ // every level of the tree. This should always be set to -1 except by
+ // recursive calls from within InsertNode().
+ void InsertNode(scoped_ptr<NodeBase> node, int* highest_reinsert_level);
+
+ // Removes |node| from the tree without deleting it.
+ scoped_ptr<NodeBase> RemoveNode(NodeBase* node);
+
+ // If |root_| has only one child, deletes the |root_| Node and replaces it
+ // with its only descendant child. Otherwise does nothing.
+ void PruneRootIfNecessary();
+
+ // Deletes the entire current tree and replaces it with an empty Node.
+ void ResetRoot();
+
+ const Node* root() const { return root_.get(); }
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ // A pointer to the root node in the RTree.
+ scoped_ptr<Node> root_;
+
+ // The parameters used to define the shape of the RTree.
+ const size_t min_children_;
+ const size_t max_children_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTreeBase);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_R_TREE_BASE_H_
diff --git a/chromium/ui/gfx/geometry/r_tree_unittest.cc b/chromium/ui/gfx/geometry/r_tree_unittest.cc
new file mode 100644
index 00000000000..ba45405ee2a
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_unittest.cc
@@ -0,0 +1,1025 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/r_tree.h"
+#include "ui/gfx/geometry/r_tree_base.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace gfx {
+
+class RTreeTest : public ::testing::Test {
+ protected:
+ typedef RTree<int> RT;
+
+ // Given a pointer to an RTree, traverse it and verify that its internal
+ // structure is consistent with RTree semantics.
+ void ValidateRTree(RTreeBase* rt) {
+ // If RTree is empty it should have an empty rectangle.
+ if (!rt->root()->count()) {
+ EXPECT_TRUE(rt->root()->rect().IsEmpty());
+ EXPECT_EQ(0, rt->root()->Level());
+ return;
+ }
+ // Root is allowed to have fewer than min_children_ but never more than
+ // max_children_.
+ EXPECT_LE(rt->root()->count(), rt->max_children_);
+ // The root should never be a record node.
+ EXPECT_GT(rt->root()->Level(), -1);
+ // The root should never have a parent pointer.
+ EXPECT_TRUE(rt->root()->parent() == NULL);
+ // Bounds must be consistent on the root.
+ CheckBoundsConsistent(rt->root());
+ for (size_t i = 0; i < rt->root()->count(); ++i) {
+ ValidateNode(
+ rt->root()->child(i), rt->min_children_, rt->max_children_);
+ }
+ }
+
+ // Recursive descent method used by ValidateRTree to check each node within
+ // the RTree for consistency with RTree semantics.
+ void ValidateNode(const RTreeBase::NodeBase* node_base,
+ size_t min_children,
+ size_t max_children) {
+ if (node_base->Level() >= 0) {
+ const RTreeBase::Node* node =
+ static_cast<const RTreeBase::Node*>(node_base);
+ EXPECT_GE(node->count(), min_children);
+ EXPECT_LE(node->count(), max_children);
+ CheckBoundsConsistent(node);
+ for (size_t i = 0; i < node->count(); ++i)
+ ValidateNode(node->child(i), min_children, max_children);
+ }
+ }
+
+ // Check bounds are consistent with children bounds, and other checks
+ // convenient to do while enumerating the children of node.
+ void CheckBoundsConsistent(const RTreeBase::Node* node) {
+ EXPECT_FALSE(node->rect().IsEmpty());
+ Rect check_bounds;
+ for (size_t i = 0; i < node->count(); ++i) {
+ const RTreeBase::NodeBase* child_node = node->child(i);
+ check_bounds.Union(child_node->rect());
+ EXPECT_EQ(node->Level() - 1, child_node->Level());
+ EXPECT_EQ(node, child_node->parent());
+ }
+ EXPECT_EQ(check_bounds, node->rect());
+ }
+
+ // Adds count squares stacked around the point (0,0) with key equal to width.
+ void AddStackedSquares(RT* rt, int count) {
+ for (int i = 1; i <= count; ++i) {
+ rt->Insert(Rect(0, 0, i, i), i);
+ ValidateRTree(static_cast<RTreeBase*>(rt));
+ }
+ }
+
+ // Given an unordered list of matching keys, verifies that it contains all
+ // values [1..length] for the length of that list.
+ void VerifyAllKeys(const RT::Matches& keys) {
+ for (size_t i = 1; i <= keys.size(); ++i)
+ EXPECT_EQ(1U, keys.count(i));
+ }
+
+ // Given a node and a rectangle, builds an expanded rectangle list where the
+ // ith element of the vector is the union of the rectangle of the ith child of
+ // the node and the argument rectangle.
+ void BuildExpandedRects(RTreeBase::Node* node,
+ const Rect& rect,
+ std::vector<Rect>* expanded_rects) {
+ expanded_rects->clear();
+ expanded_rects->reserve(node->count());
+ for (size_t i = 0; i < node->count(); ++i) {
+ Rect expanded_rect(rect);
+ expanded_rect.Union(node->child(i)->rect());
+ expanded_rects->push_back(expanded_rect);
+ }
+ }
+};
+
+class RTreeNodeTest : public RTreeTest {
+ protected:
+ typedef RTreeBase::NodeBase RTreeNodeBase;
+ typedef RT::Record RTreeRecord;
+ typedef RTreeBase::Node RTreeNode;
+ typedef RTreeBase::Node::Rects RTreeRects;
+ typedef RTreeBase::Nodes RTreeNodes;
+
+ // Accessors to private members of RTree::Node.
+ const RTreeRecord* record(RTreeNode* node, size_t i) {
+ return static_cast<const RTreeRecord*>(node->child(i));
+ }
+
+ // Provides access for tests to private methods of RTree::Node.
+ scoped_ptr<RTreeNode> NewNodeAtLevel(size_t level) {
+ return make_scoped_ptr(new RTreeBase::Node(level));
+ }
+
+ void NodeRecomputeLocalBounds(RTreeNodeBase* node) {
+ node->RecomputeLocalBounds();
+ }
+
+ bool NodeCompareVertical(RTreeNodeBase* a, RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareVertical(a, b);
+ }
+
+ bool NodeCompareHorizontal(RTreeNodeBase* a, RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareHorizontal(a, b);
+ }
+
+ bool NodeCompareCenterDistanceFromParent(
+ const RTreeNodeBase* a, const RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareCenterDistanceFromParent(a, b);
+ }
+
+ int NodeOverlapIncreaseToAdd(RTreeNode* node,
+ const Rect& rect,
+ const RTreeNodeBase* candidate_node,
+ const Rect& expanded_rect) {
+ return node->OverlapIncreaseToAdd(rect, candidate_node, expanded_rect);
+ }
+
+ void NodeBuildLowBounds(const std::vector<RTreeNodeBase*>& vertical_sort,
+ const std::vector<RTreeNodeBase*>& horizontal_sort,
+ RTreeRects* vertical_bounds,
+ RTreeRects* horizontal_bounds) {
+ RTreeBase::Node::BuildLowBounds(
+ vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds);
+ }
+
+ void NodeBuildHighBounds(const std::vector<RTreeNodeBase*>& vertical_sort,
+ const std::vector<RTreeNodeBase*>& horizontal_sort,
+ RTreeRects* vertical_bounds,
+ RTreeRects* horizontal_bounds) {
+ RTreeBase::Node::BuildHighBounds(
+ vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds);
+ }
+
+ int NodeSmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds) {
+ return RTreeBase::Node::SmallestMarginSum(
+ start_index, end_index, low_bounds, high_bounds);
+ }
+
+ size_t NodeChooseSplitIndex(size_t min_children,
+ size_t max_children,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds) {
+ return RTreeBase::Node::ChooseSplitIndex(
+ min_children, max_children, low_bounds, high_bounds);
+ }
+
+ scoped_ptr<RTreeNodeBase> NodeDivideChildren(
+ RTreeNode* node,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds,
+ const std::vector<RTreeNodeBase*>& sorted_children,
+ size_t split_index) {
+ return node->DivideChildren(
+ low_bounds, high_bounds, sorted_children, split_index);
+ }
+
+ RTreeNode* NodeLeastOverlapIncrease(RTreeNode* node,
+ const Rect& node_rect,
+ const RTreeRects& expanded_rects) {
+ return node->LeastOverlapIncrease(node_rect, expanded_rects);
+ }
+
+ RTreeNode* NodeLeastAreaEnlargement(RTreeNode* node,
+ const Rect& node_rect,
+ const RTreeRects& expanded_rects) {
+ return node->LeastAreaEnlargement(node_rect, expanded_rects);
+ }
+};
+
+// RTreeNodeTest --------------------------------------------------------------
+
+TEST_F(RTreeNodeTest, RemoveNodesForReinsert) {
+ // Make a leaf node for testing removal from.
+ scoped_ptr<RTreeNode> test_node(new RTreeNode);
+ // Build 20 record nodes with rectangle centers going from (1,1) to (20,20)
+ for (int i = 1; i <= 20; ++i)
+ test_node->AddChild(scoped_ptr<RTreeNodeBase>(
+ new RTreeRecord(Rect(i - 1, i - 1, 2, 2), i)));
+
+ // Quick verification of the node before removing children.
+ ValidateNode(test_node.get(), 1U, 20U);
+ // Use a scoped vector to delete all children that get removed from the Node.
+ RTreeNodes removals;
+ test_node->RemoveNodesForReinsert(1, &removals);
+ // Should have gotten back 1 node pointer.
+ EXPECT_EQ(1U, removals.size());
+ // There should be 19 left in the test_node.
+ EXPECT_EQ(19U, test_node->count());
+ // If we fix up the bounds on the test_node, it should verify.
+ NodeRecomputeLocalBounds(test_node.get());
+ ValidateNode(test_node.get(), 2U, 20U);
+ // The node we removed should be node 10, as it was exactly in the center.
+ EXPECT_EQ(10, static_cast<RTreeRecord*>(removals[0])->key());
+
+ // Now remove the next 2.
+ removals.clear();
+ test_node->RemoveNodesForReinsert(2, &removals);
+ EXPECT_EQ(2U, removals.size());
+ EXPECT_EQ(17U, test_node->count());
+ NodeRecomputeLocalBounds(test_node.get());
+ ValidateNode(test_node.get(), 2U, 20U);
+ // Lastly the 2 nodes we should have gotten back are keys 9 and 11, as their
+ // centers were the closest to the center of the node bounding box.
+ base::hash_set<intptr_t> results_hash;
+ results_hash.insert(static_cast<RTreeRecord*>(removals[0])->key());
+ results_hash.insert(static_cast<RTreeRecord*>(removals[1])->key());
+ EXPECT_EQ(1U, results_hash.count(9));
+ EXPECT_EQ(1U, results_hash.count(11));
+}
+
+TEST_F(RTreeNodeTest, CompareVertical) {
+ // One rect with lower y than another should always sort lower.
+ RTreeRecord low(Rect(0, 1, 10, 10), 1);
+ RTreeRecord middle(Rect(0, 5, 10, 10), 5);
+ EXPECT_TRUE(NodeCompareVertical(&low, &middle));
+ EXPECT_FALSE(NodeCompareVertical(&middle, &low));
+
+ // Try a non-overlapping higher-y rectangle.
+ RTreeRecord high(Rect(-10, 20, 10, 1), 10);
+ EXPECT_TRUE(NodeCompareVertical(&low, &high));
+ EXPECT_FALSE(NodeCompareVertical(&high, &low));
+
+ // Ties are broken by lowest bottom y value.
+ RTreeRecord shorter_tie(Rect(10, 1, 100, 2), 2);
+ EXPECT_TRUE(NodeCompareVertical(&shorter_tie, &low));
+ EXPECT_FALSE(NodeCompareVertical(&low, &shorter_tie));
+}
+
+TEST_F(RTreeNodeTest, CompareHorizontal) {
+ // One rect with lower x than another should always sort lower than higher x.
+ RTreeRecord low(Rect(1, 0, 10, 10), 1);
+ RTreeRecord middle(Rect(5, 0, 10, 10), 5);
+ EXPECT_TRUE(NodeCompareHorizontal(&low, &middle));
+ EXPECT_FALSE(NodeCompareHorizontal(&middle, &low));
+
+ // Try a non-overlapping higher-x rectangle.
+ RTreeRecord high(Rect(20, -10, 1, 10), 10);
+ EXPECT_TRUE(NodeCompareHorizontal(&low, &high));
+ EXPECT_FALSE(NodeCompareHorizontal(&high, &low));
+
+ // Ties are broken by lowest bottom x value.
+ RTreeRecord shorter_tie(Rect(1, 10, 2, 100), 2);
+ EXPECT_TRUE(NodeCompareHorizontal(&shorter_tie, &low));
+ EXPECT_FALSE(NodeCompareHorizontal(&low, &shorter_tie));
+}
+
+TEST_F(RTreeNodeTest, CompareCenterDistanceFromParent) {
+ // Create a test node we can add children to, for distance comparisons.
+ scoped_ptr<RTreeNode> parent(new RTreeNode);
+
+ // Add three children, one each with centers at (0, 0), (10, 10), (-9, -9),
+ // around which a bounding box will be centered at (0, 0)
+ scoped_ptr<RTreeRecord> center_zero(new RTreeRecord(Rect(-1, -1, 2, 2), 1));
+ parent->AddChild(center_zero.PassAs<RTreeNodeBase>());
+
+ scoped_ptr<RTreeRecord> center_positive(new RTreeRecord(Rect(9, 9, 2, 2), 2));
+ parent->AddChild(center_positive.PassAs<RTreeNodeBase>());
+
+ scoped_ptr<RTreeRecord> center_negative(
+ new RTreeRecord(Rect(-10, -10, 2, 2), 3));
+ parent->AddChild(center_negative.PassAs<RTreeNodeBase>());
+
+ ValidateNode(parent.get(), 1U, 5U);
+ EXPECT_EQ(Rect(-10, -10, 21, 21), parent->rect());
+
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(1)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(0)));
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(2)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(0)));
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(1)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(2)));
+}
+
+TEST_F(RTreeNodeTest, OverlapIncreaseToAdd) {
+ // Create a test node with three children, for overlap comparisons.
+ scoped_ptr<RTreeNode> parent(new RTreeNode);
+
+ // Add three children, each 4 wide and tall, at (0, 0), (3, 3), (6, 6) with
+ // overlapping corners.
+ Rect top(0, 0, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(top, 1)));
+ Rect middle(3, 3, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(middle, 2)));
+ Rect bottom(6, 6, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(bottom, 3)));
+ ValidateNode(parent.get(), 1U, 5U);
+
+ // Test a rect in corner.
+ Rect corner(0, 0, 1, 1);
+ Rect expanded = top;
+ expanded.Union(corner);
+ // It should not add any overlap to add this to the first child at (0, 0).
+ EXPECT_EQ(0, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(0), expanded));
+
+ expanded = middle;
+ expanded.Union(corner);
+ // Overlap for middle rectangle should increase from 2 pixels at (3, 3) and
+ // (6, 6) to 17 pixels, as it will now cover 4x4 rectangle top,
+ // so a change of +15.
+ EXPECT_EQ(15, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(1), expanded));
+
+ expanded = bottom;
+ expanded.Union(corner);
+ // Overlap for bottom rectangle should increase from 1 pixel at (6, 6) to
+ // 32 pixels, as it will now cover both 4x4 rectangles top and middle,
+ // so a change of 31.
+ EXPECT_EQ(31, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(2), expanded));
+
+ // Test a rect that doesn't overlap with anything, in the far right corner.
+ Rect far_corner(9, 0, 1, 1);
+ expanded = top;
+ expanded.Union(far_corner);
+ // Overlap of top should go from 1 to 4, as it will now cover the entire first
+ // row of pixels in middle.
+ EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(0), expanded));
+
+ expanded = middle;
+ expanded.Union(far_corner);
+ // Overlap of middle should go from 2 to 8, as it will cover the rightmost 4
+ // pixels of top and the top 4 pixels of bottom as it expands.
+ EXPECT_EQ(6, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(1), expanded));
+
+ expanded = bottom;
+ expanded.Union(far_corner);
+ // Overlap of bottom should go from 1 to 4, as it will now cover the rightmost
+ // 4 pixels of middle.
+ EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(2), expanded));
+}
+
+TEST_F(RTreeNodeTest, BuildLowBounds) {
+ RTreeNodes records;
+ records.reserve(10);
+ for (int i = 1; i <= 10; ++i)
+ records.push_back(new RTreeRecord(Rect(0, 0, i, i), i));
+
+ RTreeRects vertical_bounds;
+ RTreeRects horizontal_bounds;
+ NodeBuildLowBounds(
+ records.get(), records.get(), &vertical_bounds, &horizontal_bounds);
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(records[i]->rect(), vertical_bounds[i]);
+ EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]);
+ }
+}
+
+TEST_F(RTreeNodeTest, BuildHighBounds) {
+ RTreeNodes records;
+ records.reserve(25);
+ for (int i = 0; i < 25; ++i)
+ records.push_back(new RTreeRecord(Rect(i, i, 25 - i, 25 - i), i));
+
+ RTreeRects vertical_bounds;
+ RTreeRects horizontal_bounds;
+ NodeBuildHighBounds(
+ records.get(), records.get(), &vertical_bounds, &horizontal_bounds);
+ for (int i = 0; i < 25; ++i) {
+ EXPECT_EQ(records[i]->rect(), vertical_bounds[i]);
+ EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]);
+ }
+}
+
+TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexVertical) {
+ RTreeRects low_vertical_bounds;
+ RTreeRects high_vertical_bounds;
+ RTreeRects low_horizontal_bounds;
+ RTreeRects high_horizontal_bounds;
+ // In this test scenario we describe a mirrored, stacked configuration of
+ // horizontal, 1 pixel high rectangles labeled a-f like this:
+ //
+ // shape: | v sort: | h sort: |
+ // -------+---------+---------+
+ // aaaaa | 0 | 0 |
+ // bbb | 1 | 2 |
+ // c | 2 | 4 |
+ // d | 3 | 5 |
+ // eee | 4 | 3 |
+ // fffff | 5 | 1 |
+ //
+ // These are already sorted vertically from top to bottom. Bounding rectangles
+ // of these vertically sorted will be 5 wide, i tall bounding boxes.
+ for (int i = 0; i < 6; ++i) {
+ low_vertical_bounds.push_back(Rect(0, 0, 5, i + 1));
+ high_vertical_bounds.push_back(Rect(0, i, 5, 6 - i));
+ }
+
+ // Low bounds of horizontal sort start with bounds of box a and then jump to
+ // cover everything, as box f is second in horizontal sort.
+ low_horizontal_bounds.push_back(Rect(0, 0, 5, 1));
+ for (int i = 0; i < 5; ++i)
+ low_horizontal_bounds.push_back(Rect(0, 0, 5, 6));
+
+ // High horizontal bounds are hand-calculated.
+ high_horizontal_bounds.push_back(Rect(0, 0, 5, 6));
+ high_horizontal_bounds.push_back(Rect(0, 1, 5, 5));
+ high_horizontal_bounds.push_back(Rect(1, 1, 3, 4));
+ high_horizontal_bounds.push_back(Rect(1, 2, 3, 3));
+ high_horizontal_bounds.push_back(Rect(2, 2, 1, 2));
+ high_horizontal_bounds.push_back(Rect(2, 3, 1, 1));
+
+ int smallest_vertical_margin =
+ NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds);
+ int smallest_horizontal_margin = NodeSmallestMarginSum(
+ 2, 3, low_horizontal_bounds, high_horizontal_bounds);
+ EXPECT_LT(smallest_vertical_margin, smallest_horizontal_margin);
+
+ EXPECT_EQ(
+ 3U,
+ NodeChooseSplitIndex(2, 5, low_vertical_bounds, high_vertical_bounds));
+}
+
+TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexHorizontal) {
+ RTreeRects low_vertical_bounds;
+ RTreeRects high_vertical_bounds;
+ RTreeRects low_horizontal_bounds;
+ RTreeRects high_horizontal_bounds;
+ // We rotate the shape from ChooseSplitAxisAndIndexVertical to test
+ // horizontal split axis detection:
+ //
+ // +--------+
+ // | a f |
+ // | ab ef |
+ // sort: | abcdef |
+ // | ab ef |
+ // | a f |
+ // |--------+
+ // v sort: | 024531 |
+ // h sort: | 012345 |
+ // +--------+
+ //
+ // Low bounds of vertical sort start with bounds of box a and then jump to
+ // cover everything, as box f is second in vertical sort.
+ low_vertical_bounds.push_back(Rect(0, 0, 1, 5));
+ for (int i = 0; i < 5; ++i)
+ low_vertical_bounds.push_back(Rect(0, 0, 6, 5));
+
+ // High vertical bounds are hand-calculated.
+ high_vertical_bounds.push_back(Rect(0, 0, 6, 5));
+ high_vertical_bounds.push_back(Rect(1, 0, 5, 5));
+ high_vertical_bounds.push_back(Rect(1, 1, 4, 3));
+ high_vertical_bounds.push_back(Rect(2, 1, 3, 3));
+ high_vertical_bounds.push_back(Rect(2, 2, 2, 1));
+ high_vertical_bounds.push_back(Rect(3, 2, 1, 1));
+
+ // These are already sorted horizontally from left to right. Bounding
+ // rectangles of these horizontally sorted will be i wide, 5 tall bounding
+ // boxes.
+ for (int i = 0; i < 6; ++i) {
+ low_horizontal_bounds.push_back(Rect(0, 0, i + 1, 5));
+ high_horizontal_bounds.push_back(Rect(i, 0, 6 - i, 5));
+ }
+
+ int smallest_vertical_margin =
+ NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds);
+ int smallest_horizontal_margin = NodeSmallestMarginSum(
+ 2, 3, low_horizontal_bounds, high_horizontal_bounds);
+
+ EXPECT_GT(smallest_vertical_margin, smallest_horizontal_margin);
+
+ EXPECT_EQ(3U,
+ NodeChooseSplitIndex(
+ 2, 5, low_horizontal_bounds, high_horizontal_bounds));
+}
+
+TEST_F(RTreeNodeTest, DivideChildren) {
+ // Create a test node to split.
+ scoped_ptr<RTreeNode> test_node(new RTreeNode);
+ std::vector<RTreeNodeBase*> sorted_children;
+ RTreeRects low_bounds;
+ RTreeRects high_bounds;
+ // Insert 10 record nodes, also inserting them into our children array.
+ for (int i = 1; i <= 10; ++i) {
+ scoped_ptr<RTreeRecord> record(new RTreeRecord(Rect(0, 0, i, i), i));
+ sorted_children.push_back(record.get());
+ test_node->AddChild(record.PassAs<RTreeNodeBase>());
+ low_bounds.push_back(Rect(0, 0, i, i));
+ high_bounds.push_back(Rect(0, 0, 10, 10));
+ }
+ // Split the children in half.
+ scoped_ptr<RTreeNodeBase> split_node_base(NodeDivideChildren(
+ test_node.get(), low_bounds, high_bounds, sorted_children, 5));
+ RTreeNode* split_node = static_cast<RTreeNode*>(split_node_base.get());
+ // Both nodes should be valid.
+ ValidateNode(test_node.get(), 1U, 10U);
+ ValidateNode(split_node, 1U, 10U);
+ // Both nodes should have five children.
+ EXPECT_EQ(5U, test_node->count());
+ EXPECT_EQ(5U, split_node->count());
+ // Test node should have children 1-5, split node should have children 6-10.
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_EQ(i + 1, record(test_node.get(), i)->key());
+ EXPECT_EQ(i + 6, record(split_node, i)->key());
+ }
+}
+
+TEST_F(RTreeNodeTest, RemoveChildNoOrphans) {
+ scoped_ptr<RTreeNode> test_parent(new RTreeNode);
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ RTreeNodes orphans;
+
+ // Remove the middle node.
+ scoped_ptr<RTreeNodeBase> middle_child(
+ test_parent->RemoveChild(test_parent->child(1), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(2U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Remove the end node.
+ scoped_ptr<RTreeNodeBase> end_child(
+ test_parent->RemoveChild(test_parent->child(1), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(1U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Remove the first node.
+ scoped_ptr<RTreeNodeBase> first_child(
+ test_parent->RemoveChild(test_parent->child(0), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(0U, test_parent->count());
+}
+
+TEST_F(RTreeNodeTest, RemoveChildOrphans) {
+ // Build binary tree of Nodes of height 4, keeping weak pointers to the
+ // Levels 0 and 1 Nodes and the Records so we can test removal of them below.
+ std::vector<RTreeNode*> level_1_children;
+ std::vector<RTreeNode*> level_0_children;
+ std::vector<RTreeRecord*> records;
+ int id = 1;
+ scoped_ptr<RTreeNode> root(NewNodeAtLevel(2));
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RTreeNode> level_1_child(NewNodeAtLevel(1));
+ for (int j = 0; j < 2; ++j) {
+ scoped_ptr<RTreeNode> level_0_child(new RTreeNode);
+ for (int k = 0; k < 2; ++k) {
+ scoped_ptr<RTreeRecord> record(
+ new RTreeRecord(Rect(0, 0, id, id), id));
+ ++id;
+ records.push_back(record.get());
+ level_0_child->AddChild(record.PassAs<RTreeNodeBase>());
+ }
+ level_0_children.push_back(level_0_child.get());
+ level_1_child->AddChild(level_0_child.PassAs<RTreeNodeBase>());
+ }
+ level_1_children.push_back(level_1_child.get());
+ root->AddChild(level_1_child.PassAs<RTreeNodeBase>());
+ }
+
+ // This should now be a valid tree structure.
+ ValidateNode(root.get(), 2U, 2U);
+ EXPECT_EQ(2U, level_1_children.size());
+ EXPECT_EQ(4U, level_0_children.size());
+ EXPECT_EQ(8U, records.size());
+
+ // Now remove all of the level 0 nodes so we get the record nodes as orphans.
+ RTreeNodes orphans;
+ for (size_t i = 0; i < level_0_children.size(); ++i)
+ level_1_children[i / 2]->RemoveChild(level_0_children[i], &orphans);
+
+ // Orphans should be all 8 records but no order guarantee.
+ EXPECT_EQ(8U, orphans.size());
+ for (std::vector<RTreeRecord*>::iterator it = records.begin();
+ it != records.end(); ++it) {
+ RTreeNodes::iterator orphan =
+ std::find(orphans.begin(), orphans.end(), *it);
+ EXPECT_NE(orphan, orphans.end());
+ orphans.erase(orphan);
+ }
+ EXPECT_EQ(0U, orphans.size());
+}
+
+TEST_F(RTreeNodeTest, RemoveAndReturnLastChild) {
+ scoped_ptr<RTreeNode> test_parent(new RTreeNode);
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ RTreeNodeBase* child = test_parent->child(2);
+ scoped_ptr<RTreeNodeBase> last_child(test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, last_child.get());
+ EXPECT_EQ(2U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ child = test_parent->child(1);
+ scoped_ptr<RTreeNodeBase> middle_child(
+ test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, middle_child.get());
+ EXPECT_EQ(1U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ child = test_parent->child(0);
+ scoped_ptr<RTreeNodeBase> first_child(
+ test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, first_child.get());
+ EXPECT_EQ(0U, test_parent->count());
+}
+
+TEST_F(RTreeNodeTest, LeastOverlapIncrease) {
+ scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1));
+ // Construct 4 nodes with 1x2 rects spaced horizontally 1 pixel apart, or:
+ //
+ // a b c d
+ // a b c d
+ //
+ for (int i = 0; i < 4; ++i) {
+ scoped_ptr<RTreeNode> node(new RTreeNode);
+ scoped_ptr<RTreeRecord> record(
+ new RTreeRecord(Rect(i * 2, 0, 1, 2), i + 1));
+ node->AddChild(record.PassAs<RTreeNodeBase>());
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ }
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (7, 0) should require minimum overlap on the part of the
+ // fourth rectangle to add:
+ //
+ // a b c dT
+ // a b c d
+ //
+ Rect test_rect_far(7, 0, 1, 1);
+ RTreeRects expanded_rects;
+ BuildExpandedRects(test_parent.get(), test_rect_far, &expanded_rects);
+ RTreeNode* result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_far, expanded_rects);
+ EXPECT_EQ(4, record(result, 0)->key());
+
+ // Test rect covering the bottom half of all children should be a 4-way tie,
+ // so LeastOverlapIncrease should return NULL:
+ //
+ // a b c d
+ // TTTTTTT
+ //
+ Rect test_rect_tie(0, 1, 7, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_tie, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_tie, expanded_rects);
+ EXPECT_TRUE(result == NULL);
+
+ // Test rect completely inside c should return the third rectangle:
+ //
+ // a b T d
+ // a b c d
+ //
+ Rect test_rect_inside(4, 0, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_EQ(3, record(result, 0)->key());
+
+ // Add a rectangle that overlaps completely with rectangle c, to test
+ // when there is a tie between two completely contained rectangles:
+ //
+ // a b Ted
+ // a b eed
+ //
+ scoped_ptr<RTreeNode> record_parent(new RTreeNode);
+ record_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(4, 0, 2, 2), 9)));
+ test_parent->AddChild(record_parent.PassAs<RTreeNodeBase>());
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_TRUE(result == NULL);
+}
+
+TEST_F(RTreeNodeTest, LeastAreaEnlargement) {
+ scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1));
+ // Construct 4 nodes in a cross-hairs style configuration:
+ //
+ // a
+ // b c
+ // d
+ //
+ scoped_ptr<RTreeNode> node(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 0, 1, 1), 1)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 1, 1), 2)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(2, 1, 1, 1), 3)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 2, 1, 1), 4)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (1, 3) should require minimum area to add to Node d:
+ //
+ // a
+ // b c
+ // d
+ // T
+ //
+ Rect test_rect_below(1, 3, 1, 1);
+ RTreeRects expanded_rects;
+ BuildExpandedRects(test_parent.get(), test_rect_below, &expanded_rects);
+ RTreeNode* result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_below, expanded_rects);
+ EXPECT_EQ(4, record(result, 0)->key());
+
+ // Test rect completely inside b should require minimum area to add to Node b:
+ //
+ // a
+ // T c
+ // d
+ //
+ Rect test_rect_inside(0, 1, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_EQ(2, record(result, 0)->key());
+
+ // Add e at (0, 1) to overlap b and c, to test tie-breaking:
+ //
+ // a
+ // eee
+ // d
+ //
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 3, 1), 7)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (3, 1) should tie between c and e, but c has smaller area so
+ // the algorithm should select c:
+ //
+ //
+ // a
+ // eeeT
+ // d
+ //
+ Rect test_rect_tie_breaker(3, 1, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_tie_breaker, &expanded_rects);
+ result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_tie_breaker, expanded_rects);
+ EXPECT_EQ(3, record(result, 0)->key());
+}
+
+// RTreeTest ------------------------------------------------------------------
+
+// An empty RTree should never return AppendIntersectingRecords results, and
+// RTrees should be empty upon construction.
+TEST_F(RTreeTest, AppendIntersectingRecordsOnEmptyTree) {
+ RT rt(2, 10);
+ ValidateRTree(&rt);
+ RT::Matches results;
+ Rect test_rect(25, 25);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Clear should empty the tree, meaning that all queries should not return
+// results after.
+TEST_F(RTreeTest, ClearEmptiesTreeOfSingleNode) {
+ RT rt(2, 5);
+ rt.Insert(Rect(0, 0, 100, 100), 1);
+ rt.Clear();
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Even with a complex internal structure, clear should empty the tree, meaning
+// that all queries should not return results after.
+TEST_F(RTreeTest, ClearEmptiesTreeOfManyNodes) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ rt.Clear();
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Duplicate inserts should overwrite previous inserts.
+TEST_F(RTreeTest, DuplicateInsertsOverwrite) {
+ RT rt(2, 5);
+ // Add 100 stacked squares, but always with duplicate key of 0.
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, i, i), 0);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(1U, results.size());
+ EXPECT_EQ(1U, results.count(0));
+}
+
+// Call Remove() once on something that's been inserted repeatedly.
+TEST_F(RTreeTest, DuplicateInsertRemove) {
+ RT rt(3, 9);
+ AddStackedSquares(&rt, 25);
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, i, i), 26);
+ ValidateRTree(&rt);
+ }
+ rt.Remove(26);
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(25U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Call Remove() repeatedly on something that's been inserted once.
+TEST_F(RTreeTest, InsertDuplicateRemove) {
+ RT rt(7, 15);
+ AddStackedSquares(&rt, 101);
+ for (int i = 0; i < 100; ++i) {
+ rt.Remove(101);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should meet all matching queries regardless of nesting.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresNestedHit) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should meet all matching queries when contained completely by
+// the query rectangle.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresContainedHit) {
+ RT rt(2, 10);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(0, 0, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should miss a missing query when the query has no intersection
+// with the rects.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresCompleteMiss) {
+ RT rt(2, 7);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(150, 150, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+}
+
+// Removing half the nodes after insertion should still result in a valid tree.
+TEST_F(RTreeTest, RemoveHalfStackedRects) {
+ RT rt(2, 11);
+ AddStackedSquares(&rt, 200);
+ for (int i = 101; i <= 200; ++i) {
+ rt.Remove(i);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+
+ // Add the nodes back in.
+ for (int i = 101; i <= 200; ++i) {
+ rt.Insert(Rect(0, 0, i, i), i);
+ ValidateRTree(&rt);
+ }
+ results.clear();
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(200U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertDupToRoot) {
+ RT rt(2, 5);
+ rt.Insert(Rect(0, 0, 1, 2), 1);
+ ValidateRTree(&rt);
+ rt.Insert(Rect(0, 0, 2, 1), 1);
+ ValidateRTree(&rt);
+}
+
+TEST_F(RTreeTest, InsertNegativeCoordsRect) {
+ RT rt(5, 11);
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(-i, -i, i, i), (i * 2) - 1);
+ ValidateRTree(&rt);
+ rt.Insert(Rect(0, 0, i, i), i * 2);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(-1, -1, 2, 2);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(200U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, RemoveNegativeCoordsRect) {
+ RT rt(7, 21);
+
+ // Add 100 positive stacked squares.
+ AddStackedSquares(&rt, 100);
+
+ // Now add 100 negative stacked squares.
+ for (int i = 101; i <= 200; ++i) {
+ rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), 301 - i);
+ ValidateRTree(&rt);
+ }
+
+ // Now remove half of the negative squares.
+ for (int i = 101; i <= 150; ++i) {
+ rt.Remove(301 - i);
+ ValidateRTree(&rt);
+ }
+
+ // Queries should return 100 positive and 50 negative stacked squares.
+ RT::Matches results;
+ Rect test_rect(-1, -1, 2, 2);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(150U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertEmptyRectReplacementRemovesKey) {
+ RT rt(10, 31);
+ AddStackedSquares(&rt, 50);
+ ValidateRTree(&rt);
+
+ // Replace last square with empty rect.
+ rt.Insert(Rect(), 50);
+ ValidateRTree(&rt);
+
+ // Now query large area to get all rects in tree.
+ RT::Matches results;
+ Rect test_rect(0, 0, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+
+ // Should only be 49 rects in tree.
+ EXPECT_EQ(49U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertReplacementMaintainsTree) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ ValidateRTree(&rt);
+
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, 0, 0), i);
+ ValidateRTree(&rt);
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/rect.cc b/chromium/ui/gfx/geometry/rect.cc
new file mode 100644
index 00000000000..f418e175b89
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/rect.h"
+
+#include <algorithm>
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect_base_impl.h"
+
+namespace gfx {
+
+template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
+
+typedef class RectBase<Rect, Point, Size, Insets, Vector2d, int> RectBaseT;
+
+#if defined(OS_WIN)
+Rect::Rect(const RECT& r)
+ : RectBaseT(gfx::Point(r.left, r.top)) {
+ set_width(std::abs(r.right - r.left));
+ set_height(std::abs(r.bottom - r.top));
+}
+#elif defined(OS_MACOSX)
+Rect::Rect(const CGRect& r)
+ : RectBaseT(gfx::Point(r.origin.x, r.origin.y)) {
+ set_width(r.size.width);
+ set_height(r.size.height);
+}
+#endif
+
+#if defined(OS_WIN)
+RECT Rect::ToRECT() const {
+ RECT r;
+ r.left = x();
+ r.right = right();
+ r.top = y();
+ r.bottom = bottom();
+ return r;
+}
+#elif defined(OS_MACOSX)
+CGRect Rect::ToCGRect() const {
+ return CGRectMake(x(), y(), width(), height());
+}
+#endif
+
+std::string Rect::ToString() const {
+ return base::StringPrintf("%s %s",
+ origin().ToString().c_str(),
+ size().ToString().c_str());
+}
+
+Rect operator+(const Rect& lhs, const Vector2d& rhs) {
+ Rect result(lhs);
+ result += rhs;
+ return result;
+}
+
+Rect operator-(const Rect& lhs, const Vector2d& rhs) {
+ Rect result(lhs);
+ result -= rhs;
+ return result;
+}
+
+Rect IntersectRects(const Rect& a, const Rect& b) {
+ Rect result = a;
+ result.Intersect(b);
+ return result;
+}
+
+Rect UnionRects(const Rect& a, const Rect& b) {
+ Rect result = a;
+ result.Union(b);
+ return result;
+}
+
+Rect SubtractRects(const Rect& a, const Rect& b) {
+ Rect result = a;
+ result.Subtract(b);
+ return result;
+}
+
+Rect BoundingRect(const Point& p1, const Point& p2) {
+ int rx = std::min(p1.x(), p2.x());
+ int ry = std::min(p1.y(), p2.y());
+ int rr = std::max(p1.x(), p2.x());
+ int rb = std::max(p1.y(), p2.y());
+ return Rect(rx, ry, rr - rx, rb - ry);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/rect.h b/chromium/ui/gfx/geometry/rect.h
new file mode 100644
index 00000000000..28d37bc31b3
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect.h
@@ -0,0 +1,139 @@
+// 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.
+
+// Defines a simple integer rectangle class. The containment semantics
+// are array-like; that is, the coordinate (x, y) is considered to be
+// contained by the rectangle, but the coordinate (x + width, y) is not.
+// The class will happily let you create malformed rectangles (that is,
+// rectangles with negative width and/or height), but there will be assertions
+// in the operations (such as Contains()) to complain in this case.
+
+#ifndef UI_GFX_GEOMETRY_RECT_H_
+#define UI_GFX_GEOMETRY_RECT_H_
+
+#include <cmath>
+#include <string>
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect_base.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+#if defined(OS_WIN)
+typedef struct tagRECT RECT;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+class Insets;
+
+class GFX_EXPORT Rect
+ : public RectBase<Rect, Point, Size, Insets, Vector2d, int> {
+ public:
+ Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {}
+
+ Rect(int width, int height)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>
+ (Size(width, height)) {}
+
+ Rect(int x, int y, int width, int height)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>
+ (Point(x, y), Size(width, height)) {}
+
+#if defined(OS_WIN)
+ explicit Rect(const RECT& r);
+#elif defined(OS_MACOSX)
+ explicit Rect(const CGRect& r);
+#endif
+
+ explicit Rect(const gfx::Size& size)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>(size) {}
+
+ Rect(const gfx::Point& origin, const gfx::Size& size)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>(origin, size) {}
+
+ ~Rect() {}
+
+#if defined(OS_WIN)
+ // Construct an equivalent Win32 RECT object.
+ RECT ToRECT() const;
+#elif defined(OS_MACOSX)
+ // Construct an equivalent CoreGraphics object.
+ CGRect ToCGRect() const;
+#endif
+
+ operator RectF() const {
+ return RectF(origin().x(), origin().y(), size().width(), size().height());
+ }
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const Rect& lhs, const Rect& rhs) {
+ return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
+}
+
+inline bool operator!=(const Rect& lhs, const Rect& rhs) {
+ return !(lhs == rhs);
+}
+
+GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
+GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
+
+inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
+ return rhs + lhs;
+}
+
+GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
+GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
+GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
+
+// Constructs a rectangle with |p1| and |p2| as opposite corners.
+//
+// This could also be thought of as "the smallest rect that contains both
+// points", except that we consider points on the right/bottom edges of the
+// rect to be outside the rect. So technically one or both points will not be
+// contained within the rect, because they will appear on one of these edges.
+GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
+
+inline Rect ScaleToEnclosingRect(const Rect& rect,
+ float x_scale,
+ float y_scale) {
+ int x = std::floor(rect.x() * x_scale);
+ int y = std::floor(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : std::ceil(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : std::ceil(rect.bottom() * y_scale);
+ return Rect(x, y, r - x, b - y);
+}
+
+inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
+ return ScaleToEnclosingRect(rect, scale, scale);
+}
+
+inline Rect ScaleToEnclosedRect(const Rect& rect,
+ float x_scale,
+ float y_scale) {
+ int x = std::ceil(rect.x() * x_scale);
+ int y = std::ceil(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : std::floor(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : std::floor(rect.bottom() * y_scale);
+ return Rect(x, y, r - x, b - y);
+}
+
+inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
+ return ScaleToEnclosedRect(rect, scale, scale);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_H_
diff --git a/chromium/ui/gfx/geometry/rect_base.h b/chromium/ui/gfx/geometry/rect_base.h
new file mode 100644
index 00000000000..b0a9b06a6b5
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_base.h
@@ -0,0 +1,174 @@
+// 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.
+
+// A template for a simple rectangle class. The containment semantics
+// are array-like; that is, the coordinate (x, y) is considered to be
+// contained by the rectangle, but the coordinate (x + width, y) is not.
+// The class will happily let you create malformed rectangles (that is,
+// rectangles with negative width and/or height), but there will be assertions
+// in the operations (such as Contains()) to complain in this case.
+
+#ifndef UI_GFX_GEOMETRY_RECT_BASE_H_
+#define UI_GFX_GEOMETRY_RECT_BASE_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+
+namespace gfx {
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+class GFX_EXPORT RectBase {
+ public:
+ Type x() const { return origin_.x(); }
+ void set_x(Type x) { origin_.set_x(x); }
+
+ Type y() const { return origin_.y(); }
+ void set_y(Type y) { origin_.set_y(y); }
+
+ Type width() const { return size_.width(); }
+ void set_width(Type width) { size_.set_width(width); }
+
+ Type height() const { return size_.height(); }
+ void set_height(Type height) { size_.set_height(height); }
+
+ const PointClass& origin() const { return origin_; }
+ void set_origin(const PointClass& origin) { origin_ = origin; }
+
+ const SizeClass& size() const { return size_; }
+ void set_size(const SizeClass& size) { size_ = size; }
+
+ Type right() const { return x() + width(); }
+ Type bottom() const { return y() + height(); }
+
+ PointClass top_right() const { return PointClass(right(), y()); }
+ PointClass bottom_left() const { return PointClass(x(), bottom()); }
+ PointClass bottom_right() const { return PointClass(right(), bottom()); }
+
+ VectorClass OffsetFromOrigin() const {
+ return VectorClass(x(), y());
+ }
+
+ void SetRect(Type x, Type y, Type width, Type height);
+
+ // Shrink the rectangle by a horizontal and vertical distance on all sides.
+ void Inset(Type horizontal, Type vertical) {
+ Inset(horizontal, vertical, horizontal, vertical);
+ }
+
+ // Shrink the rectangle by the given insets.
+ void Inset(const InsetsClass& insets);
+
+ // Shrink the rectangle by the specified amount on each side.
+ void Inset(Type left, Type top, Type right, Type bottom);
+
+ // Move the rectangle by a horizontal and vertical distance.
+ void Offset(Type horizontal, Type vertical);
+ void Offset(const VectorClass& distance) {
+ Offset(distance.x(), distance.y());
+ }
+ void operator+=(const VectorClass& offset);
+ void operator-=(const VectorClass& offset);
+
+ InsetsClass InsetsFrom(const Class& inner) const {
+ return InsetsClass(inner.y() - y(),
+ inner.x() - x(),
+ bottom() - inner.bottom(),
+ right() - inner.right());
+ }
+
+ // Returns true if the area of the rectangle is zero.
+ bool IsEmpty() const { return size_.IsEmpty(); }
+
+ // A rect is less than another rect if its origin is less than
+ // the other rect's origin. If the origins are equal, then the
+ // shortest rect is less than the other. If the origin and the
+ // height are equal, then the narrowest rect is less than.
+ // This comparison is required to use Rects in sets, or sorted
+ // vectors.
+ bool operator<(const Class& other) const;
+
+ // Returns true if the point identified by point_x and point_y falls inside
+ // this rectangle. The point (x, y) is inside the rectangle, but the
+ // point (x + width, y + height) is not.
+ bool Contains(Type point_x, Type point_y) const;
+
+ // Returns true if the specified point is contained by this rectangle.
+ bool Contains(const PointClass& point) const {
+ return Contains(point.x(), point.y());
+ }
+
+ // Returns true if this rectangle contains the specified rectangle.
+ bool Contains(const Class& rect) const;
+
+ // Returns true if this rectangle intersects the specified rectangle.
+ // An empty rectangle doesn't intersect any rectangle.
+ bool Intersects(const Class& rect) const;
+
+ // Computes the intersection of this rectangle with the given rectangle.
+ void Intersect(const Class& rect);
+
+ // Computes the union of this rectangle with the given rectangle. The union
+ // is the smallest rectangle containing both rectangles.
+ void Union(const Class& rect);
+
+ // Computes the rectangle resulting from subtracting |rect| from |*this|,
+ // i.e. the bounding rect of |Region(*this) - Region(rect)|.
+ void Subtract(const Class& rect);
+
+ // Fits as much of the receiving rectangle into the supplied rectangle as
+ // possible, becoming the result. For example, if the receiver had
+ // a x-location of 2 and a width of 4, and the supplied rectangle had
+ // an x-location of 0 with a width of 5, the returned rectangle would have
+ // an x-location of 1 with a width of 4.
+ void AdjustToFit(const Class& rect);
+
+ // Returns the center of this rectangle.
+ PointClass CenterPoint() const;
+
+ // Becomes a rectangle that has the same center point but with a size capped
+ // at given |size|.
+ void ClampToCenteredSize(const SizeClass& size);
+
+ // Splits |this| in two halves, |left_half| and |right_half|.
+ void SplitVertically(Class* left_half, Class* right_half) const;
+
+ // Returns true if this rectangle shares an entire edge (i.e., same width or
+ // same height) with the given rectangle, and the rectangles do not overlap.
+ bool SharesEdgeWith(const Class& rect) const;
+
+ // Returns the manhattan distance from the rect to the point. If the point is
+ // inside the rect, returns 0.
+ Type ManhattanDistanceToPoint(const PointClass& point) const;
+
+ // Returns the manhattan distance between the contents of this rect and the
+ // contents of the given rect. That is, if the intersection of the two rects
+ // is non-empty then the function returns 0. If the rects share a side, it
+ // returns the smallest non-zero value appropriate for Type.
+ Type ManhattanInternalDistance(const Class& rect) const;
+
+ protected:
+ RectBase(const PointClass& origin, const SizeClass& size)
+ : origin_(origin), size_(size) {}
+ explicit RectBase(const SizeClass& size)
+ : size_(size) {}
+ explicit RectBase(const PointClass& origin)
+ : origin_(origin) {}
+ // Destructor is intentionally made non virtual and protected.
+ // Do not make this public.
+ ~RectBase() {}
+
+ private:
+ PointClass origin_;
+ SizeClass size_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_BASE_H_
diff --git a/chromium/ui/gfx/geometry/rect_base_impl.h b/chromium/ui/gfx/geometry/rect_base_impl.h
new file mode 100644
index 00000000000..7720608e9b5
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_base_impl.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/rect_base.h"
+
+// This file provides the implementation for RectBaese template and
+// used to instantiate the base class for Rect and RectF classes.
+#if !defined(GFX_IMPLEMENTATION)
+#error "This file is intended for UI implementation only"
+#endif
+
+namespace {
+
+template<typename Type>
+void AdjustAlongAxis(Type dst_origin, Type dst_size, Type* origin, Type* size) {
+ *size = std::min(dst_size, *size);
+ if (*origin < dst_origin)
+ *origin = dst_origin;
+ else
+ *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
+}
+
+} // namespace
+
+namespace gfx {
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ SetRect(Type x, Type y, Type width, Type height) {
+ origin_.SetPoint(x, y);
+ set_width(width);
+ set_height(height);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Inset(const InsetsClass& insets) {
+ Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Inset(Type left, Type top, Type right, Type bottom) {
+ origin_ += VectorClass(left, top);
+ set_width(std::max(width() - left - right, static_cast<Type>(0)));
+ set_height(std::max(height() - top - bottom, static_cast<Type>(0)));
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Offset(Type horizontal, Type vertical) {
+ origin_ += VectorClass(horizontal, vertical);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ operator+=(const VectorClass& offset) {
+ origin_ += offset;
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ operator-=(const VectorClass& offset) {
+ origin_ -= offset;
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ operator<(const Class& other) const {
+ if (origin_ == other.origin_) {
+ if (width() == other.width()) {
+ return height() < other.height();
+ } else {
+ return width() < other.width();
+ }
+ } else {
+ return origin_ < other.origin_;
+ }
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Contains(Type point_x, Type point_y) const {
+ return (point_x >= x()) && (point_x < right()) &&
+ (point_y >= y()) && (point_y < bottom());
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Contains(const Class& rect) const {
+ return (rect.x() >= x() && rect.right() <= right() &&
+ rect.y() >= y() && rect.bottom() <= bottom());
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Intersects(const Class& rect) const {
+ return !(IsEmpty() || rect.IsEmpty() ||
+ rect.x() >= right() || rect.right() <= x() ||
+ rect.y() >= bottom() || rect.bottom() <= y());
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Intersect(const Class& rect) {
+ if (IsEmpty() || rect.IsEmpty()) {
+ SetRect(0, 0, 0, 0);
+ return;
+ }
+
+ Type rx = std::max(x(), rect.x());
+ Type ry = std::max(y(), rect.y());
+ Type rr = std::min(right(), rect.right());
+ Type rb = std::min(bottom(), rect.bottom());
+
+ if (rx >= rr || ry >= rb)
+ rx = ry = rr = rb = 0; // non-intersecting
+
+ SetRect(rx, ry, rr - rx, rb - ry);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Union(const Class& rect) {
+ if (IsEmpty()) {
+ *this = rect;
+ return;
+ }
+ if (rect.IsEmpty())
+ return;
+
+ Type rx = std::min(x(), rect.x());
+ Type ry = std::min(y(), rect.y());
+ Type rr = std::max(right(), rect.right());
+ Type rb = std::max(bottom(), rect.bottom());
+
+ SetRect(rx, ry, rr - rx, rb - ry);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ Subtract(const Class& rect) {
+ if (!Intersects(rect))
+ return;
+ if (rect.Contains(*static_cast<const Class*>(this))) {
+ SetRect(0, 0, 0, 0);
+ return;
+ }
+
+ Type rx = x();
+ Type ry = y();
+ Type rr = right();
+ Type rb = bottom();
+
+ if (rect.y() <= y() && rect.bottom() >= bottom()) {
+ // complete intersection in the y-direction
+ if (rect.x() <= x()) {
+ rx = rect.right();
+ } else if (rect.right() >= right()) {
+ rr = rect.x();
+ }
+ } else if (rect.x() <= x() && rect.right() >= right()) {
+ // complete intersection in the x-direction
+ if (rect.y() <= y()) {
+ ry = rect.bottom();
+ } else if (rect.bottom() >= bottom()) {
+ rb = rect.y();
+ }
+ }
+ SetRect(rx, ry, rr - rx, rb - ry);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ AdjustToFit(const Class& rect) {
+ Type new_x = x();
+ Type new_y = y();
+ Type new_width = width();
+ Type new_height = height();
+ AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
+ AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
+ SetRect(new_x, new_y, new_width, new_height);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+PointClass RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
+ Type>::CenterPoint() const {
+ return PointClass(x() + width() / 2, y() + height() / 2);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ ClampToCenteredSize(const SizeClass& size) {
+ Type new_width = std::min(width(), size.width());
+ Type new_height = std::min(height(), size.height());
+ Type new_x = x() + (width() - new_width) / 2;
+ Type new_y = y() + (height() - new_height) / 2;
+ SetRect(new_x, new_y, new_width, new_height);
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ SplitVertically(Class* left_half, Class* right_half) const {
+ DCHECK(left_half);
+ DCHECK(right_half);
+
+ left_half->SetRect(x(), y(), width() / 2, height());
+ right_half->SetRect(left_half->right(),
+ y(),
+ width() - left_half->width(),
+ height());
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ SharesEdgeWith(const Class& rect) const {
+ return (y() == rect.y() && height() == rect.height() &&
+ (x() == rect.right() || right() == rect.x())) ||
+ (x() == rect.x() && width() == rect.width() &&
+ (y() == rect.bottom() || bottom() == rect.y()));
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ ManhattanDistanceToPoint(const PointClass& point) const {
+ Type x_distance = std::max<Type>(0, std::max(
+ x() - point.x(), point.x() - right()));
+ Type y_distance = std::max<Type>(0, std::max(
+ y() - point.y(), point.y() - bottom()));
+
+ return x_distance + y_distance;
+}
+
+template<typename Class,
+ typename PointClass,
+ typename SizeClass,
+ typename InsetsClass,
+ typename VectorClass,
+ typename Type>
+Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
+ ManhattanInternalDistance(const Class& rect) const {
+ Class c(x(), y(), width(), height());
+ c.Union(rect);
+
+ static const Type kEpsilon = std::numeric_limits<Type>::is_integer
+ ? 1
+ : std::numeric_limits<Type>::epsilon();
+
+ Type x = std::max<Type>(0, c.width() - width() - rect.width() + kEpsilon);
+ Type y = std::max<Type>(0, c.height() - height() - rect.height() + kEpsilon);
+ return x + y;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/rect_conversions.cc b/chromium/ui/gfx/geometry/rect_conversions.cc
new file mode 100644
index 00000000000..cceeb83a0ae
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_conversions.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/rect_conversions.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace gfx {
+
+Rect ToEnclosingRect(const RectF& rect) {
+ int min_x = ToFlooredInt(rect.x());
+ int min_y = ToFlooredInt(rect.y());
+ float max_x = rect.right();
+ float max_y = rect.bottom();
+ int width = rect.width() == 0 ? 0 : std::max(ToCeiledInt(max_x) - min_x, 0);
+ int height = rect.height() == 0 ? 0 : std::max(ToCeiledInt(max_y) - min_y, 0);
+ return Rect(min_x, min_y, width, height);
+}
+
+Rect ToEnclosedRect(const RectF& rect) {
+ int min_x = ToCeiledInt(rect.x());
+ int min_y = ToCeiledInt(rect.y());
+ float max_x = rect.right();
+ float max_y = rect.bottom();
+ int width = std::max(ToFlooredInt(max_x) - min_x, 0);
+ int height = std::max(ToFlooredInt(max_y) - min_y, 0);
+ return Rect(min_x, min_y, width, height);
+}
+
+Rect ToNearestRect(const RectF& rect) {
+ float float_min_x = rect.x();
+ float float_min_y = rect.y();
+ float float_max_x = rect.right();
+ float float_max_y = rect.bottom();
+
+ int min_x = ToRoundedInt(float_min_x);
+ int min_y = ToRoundedInt(float_min_y);
+ int max_x = ToRoundedInt(float_max_x);
+ int max_y = ToRoundedInt(float_max_y);
+
+ // If these DCHECKs fail, you're using the wrong method, consider using
+ // ToEnclosingRect or ToEnclosedRect instead.
+ DCHECK(std::abs(min_x - float_min_x) < 0.01f);
+ DCHECK(std::abs(min_y - float_min_y) < 0.01f);
+ DCHECK(std::abs(max_x - float_max_x) < 0.01f);
+ DCHECK(std::abs(max_y - float_max_y) < 0.01f);
+
+ return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
+}
+
+bool IsNearestRectWithinDistance(const gfx::RectF& rect, float distance) {
+ float float_min_x = rect.x();
+ float float_min_y = rect.y();
+ float float_max_x = rect.right();
+ float float_max_y = rect.bottom();
+
+ int min_x = ToRoundedInt(float_min_x);
+ int min_y = ToRoundedInt(float_min_y);
+ int max_x = ToRoundedInt(float_max_x);
+ int max_y = ToRoundedInt(float_max_y);
+
+ return
+ (std::abs(min_x - float_min_x) < distance) &&
+ (std::abs(min_y - float_min_y) < distance) &&
+ (std::abs(max_x - float_max_x) < distance) &&
+ (std::abs(max_y - float_max_y) < distance);
+}
+
+Rect ToFlooredRectDeprecated(const RectF& rect) {
+ return Rect(ToFlooredInt(rect.x()),
+ ToFlooredInt(rect.y()),
+ ToFlooredInt(rect.width()),
+ ToFlooredInt(rect.height()));
+}
+
+} // namespace gfx
+
diff --git a/chromium/ui/gfx/geometry/rect_conversions.h b/chromium/ui/gfx/geometry/rect_conversions.h
new file mode 100644
index 00000000000..617074abeee
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_conversions.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_RECT_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_RECT_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace gfx {
+
+// Returns the smallest Rect that encloses the given RectF.
+GFX_EXPORT Rect ToEnclosingRect(const RectF& rect);
+
+// Returns the largest Rect that is enclosed by the given RectF.
+GFX_EXPORT Rect ToEnclosedRect(const RectF& rect);
+
+// Returns the Rect after snapping the corners of the RectF to an integer grid.
+// This should only be used when the RectF you provide is expected to be an
+// integer rect with floating point error. If it is an arbitrary RectF, then
+// you should use a different method.
+GFX_EXPORT Rect ToNearestRect(const RectF& rect);
+
+// Returns true if the Rect produced after snapping the corners of the RectF
+// to an integer grid is withing |distance|.
+GFX_EXPORT bool IsNearestRectWithinDistance(
+ const gfx::RectF& rect, float distance);
+
+// Returns a Rect obtained by flooring the values of the given RectF.
+// Please prefer the previous two functions in new code.
+GFX_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/geometry/rect_f.cc b/chromium/ui/gfx/geometry/rect_f.cc
new file mode 100644
index 00000000000..44c08aafaff
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_f.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/rect_f.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/rect_base_impl.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace gfx {
+
+template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
+
+typedef class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF,
+ float> RectBaseT;
+
+bool RectF::IsExpressibleAsRect() const {
+ return IsExpressibleAsInt(x()) && IsExpressibleAsInt(y()) &&
+ IsExpressibleAsInt(width()) && IsExpressibleAsInt(height()) &&
+ IsExpressibleAsInt(right()) && IsExpressibleAsInt(bottom());
+}
+
+std::string RectF::ToString() const {
+ return base::StringPrintf("%s %s",
+ origin().ToString().c_str(),
+ size().ToString().c_str());
+}
+
+RectF IntersectRects(const RectF& a, const RectF& b) {
+ RectF result = a;
+ result.Intersect(b);
+ return result;
+}
+
+RectF UnionRects(const RectF& a, const RectF& b) {
+ RectF result = a;
+ result.Union(b);
+ return result;
+}
+
+RectF SubtractRects(const RectF& a, const RectF& b) {
+ RectF result = a;
+ result.Subtract(b);
+ return result;
+}
+
+RectF BoundingRect(const PointF& p1, const PointF& p2) {
+ float rx = std::min(p1.x(), p2.x());
+ float ry = std::min(p1.y(), p2.y());
+ float rr = std::max(p1.x(), p2.x());
+ float rb = std::max(p1.y(), p2.y());
+ return RectF(rx, ry, rr - rx, rb - ry);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/rect_f.h b/chromium/ui/gfx/geometry/rect_f.h
new file mode 100644
index 00000000000..50ea76bff9f
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_f.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_RECT_F_H_
+#define UI_GFX_GEOMETRY_RECT_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_base.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+class InsetsF;
+
+// A floating version of gfx::Rect.
+class GFX_EXPORT RectF
+ : public RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float> {
+ public:
+ RectF()
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (SizeF()) {}
+
+ RectF(float width, float height)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (SizeF(width, height)) {}
+
+ RectF(float x, float y, float width, float height)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (PointF(x, y), SizeF(width, height)) {}
+
+ explicit RectF(const SizeF& size)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (size) {}
+
+ RectF(const PointF& origin, const SizeF& size)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (origin, size) {}
+
+ ~RectF() {}
+
+ // Scales the rectangle by |scale|.
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ set_origin(ScalePoint(origin(), x_scale, y_scale));
+ set_size(ScaleSize(size(), x_scale, y_scale));
+ }
+
+ // This method reports if the RectF can be safely converted to an integer
+ // Rect. When it is false, some dimension of the RectF is outside the bounds
+ // of what an integer can represent, and converting it to a Rect will require
+ // clamping.
+ bool IsExpressibleAsRect() const;
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const RectF& lhs, const RectF& rhs) {
+ return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
+}
+
+inline bool operator!=(const RectF& lhs, const RectF& rhs) {
+ return !(lhs == rhs);
+}
+
+inline RectF operator+(const RectF& lhs, const Vector2dF& rhs) {
+ return RectF(lhs.x() + rhs.x(), lhs.y() + rhs.y(),
+ lhs.width(), lhs.height());
+}
+
+inline RectF operator-(const RectF& lhs, const Vector2dF& rhs) {
+ return RectF(lhs.x() - rhs.x(), lhs.y() - rhs.y(),
+ lhs.width(), lhs.height());
+}
+
+inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) {
+ return rhs + lhs;
+}
+
+GFX_EXPORT RectF IntersectRects(const RectF& a, const RectF& b);
+GFX_EXPORT RectF UnionRects(const RectF& a, const RectF& b);
+GFX_EXPORT RectF SubtractRects(const RectF& a, const RectF& b);
+
+inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) {
+ return RectF(r.x() * x_scale, r.y() * y_scale,
+ r.width() * x_scale, r.height() * y_scale);
+}
+
+inline RectF ScaleRect(const RectF& r, float scale) {
+ return ScaleRect(r, scale, scale);
+}
+
+// Constructs a rectangle with |p1| and |p2| as opposite corners.
+//
+// This could also be thought of as "the smallest rect that contains both
+// points", except that we consider points on the right/bottom edges of the
+// rect to be outside the rect. So technically one or both points will not be
+// contained within the rect, because they will appear on one of these edges.
+GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2);
+
+#if !defined(COMPILER_MSVC)
+extern template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_F_H_
diff --git a/chromium/ui/gfx/geometry/rect_unittest.cc b/chromium/ui/gfx/geometry/rect_unittest.cc
new file mode 100644
index 00000000000..5fcd76b706b
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_unittest.cc
@@ -0,0 +1,925 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace gfx {
+
+TEST(RectTest, Contains) {
+ static const struct ContainsCase {
+ int rect_x;
+ int rect_y;
+ int rect_width;
+ int rect_height;
+ int point_x;
+ int point_y;
+ bool contained;
+ } contains_cases[] = {
+ {0, 0, 10, 10, 0, 0, true},
+ {0, 0, 10, 10, 5, 5, true},
+ {0, 0, 10, 10, 9, 9, true},
+ {0, 0, 10, 10, 5, 10, false},
+ {0, 0, 10, 10, 10, 5, false},
+ {0, 0, 10, 10, -1, -1, false},
+ {0, 0, 10, 10, 50, 50, false},
+ #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+ {0, 0, -10, -10, 0, 0, false},
+ #endif
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(contains_cases); ++i) {
+ const ContainsCase& value = contains_cases[i];
+ Rect rect(value.rect_x, value.rect_y, value.rect_width, value.rect_height);
+ EXPECT_EQ(value.contained, rect.Contains(value.point_x, value.point_y));
+ }
+}
+
+TEST(RectTest, Intersects) {
+ static const struct {
+ int x1; // rect 1
+ int y1;
+ int w1;
+ int h1;
+ int x2; // rect 2
+ int y2;
+ int w2;
+ int h2;
+ bool intersects;
+ } tests[] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0, false },
+ { 0, 0, 0, 0, -10, -10, 20, 20, false },
+ { -10, 0, 0, 20, 0, -10, 20, 0, false },
+ { 0, 0, 10, 10, 0, 0, 10, 10, true },
+ { 0, 0, 10, 10, 10, 10, 10, 10, false },
+ { 10, 10, 10, 10, 0, 0, 10, 10, false },
+ { 10, 10, 10, 10, 5, 5, 10, 10, true },
+ { 10, 10, 10, 10, 15, 15, 10, 10, true },
+ { 10, 10, 10, 10, 20, 15, 10, 10, false },
+ { 10, 10, 10, 10, 21, 15, 10, 10, false }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+ EXPECT_EQ(tests[i].intersects, r1.Intersects(r2));
+ EXPECT_EQ(tests[i].intersects, r2.Intersects(r1));
+ }
+}
+
+TEST(RectTest, Intersect) {
+ static const struct {
+ int x1; // rect 1
+ int y1;
+ int w1;
+ int h1;
+ int x2; // rect 2
+ int y2;
+ int w2;
+ int h2;
+ int x3; // rect 3: the union of rects 1 and 2
+ int y3;
+ int w3;
+ int h3;
+ } tests[] = {
+ { 0, 0, 0, 0, // zeros
+ 0, 0, 0, 0,
+ 0, 0, 0, 0 },
+ { 0, 0, 4, 4, // equal
+ 0, 0, 4, 4,
+ 0, 0, 4, 4 },
+ { 0, 0, 4, 4, // neighboring
+ 4, 4, 4, 4,
+ 0, 0, 0, 0 },
+ { 0, 0, 4, 4, // overlapping corners
+ 2, 2, 4, 4,
+ 2, 2, 2, 2 },
+ { 0, 0, 4, 4, // T junction
+ 3, 1, 4, 2,
+ 3, 1, 1, 2 },
+ { 3, 0, 2, 2, // gap
+ 0, 0, 2, 2,
+ 0, 0, 0, 0 }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+ Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
+ Rect ir = IntersectRects(r1, r2);
+ EXPECT_EQ(r3.x(), ir.x());
+ EXPECT_EQ(r3.y(), ir.y());
+ EXPECT_EQ(r3.width(), ir.width());
+ EXPECT_EQ(r3.height(), ir.height());
+ }
+}
+
+TEST(RectTest, Union) {
+ static const struct Test {
+ int x1; // rect 1
+ int y1;
+ int w1;
+ int h1;
+ int x2; // rect 2
+ int y2;
+ int w2;
+ int h2;
+ int x3; // rect 3: the union of rects 1 and 2
+ int y3;
+ int w3;
+ int h3;
+ } tests[] = {
+ { 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0 },
+ { 0, 0, 4, 4,
+ 0, 0, 4, 4,
+ 0, 0, 4, 4 },
+ { 0, 0, 4, 4,
+ 4, 4, 4, 4,
+ 0, 0, 8, 8 },
+ { 0, 0, 4, 4,
+ 0, 5, 4, 4,
+ 0, 0, 4, 9 },
+ { 0, 0, 2, 2,
+ 3, 3, 2, 2,
+ 0, 0, 5, 5 },
+ { 3, 3, 2, 2, // reverse r1 and r2 from previous test
+ 0, 0, 2, 2,
+ 0, 0, 5, 5 },
+ { 0, 0, 0, 0, // union with empty rect
+ 2, 2, 2, 2,
+ 2, 2, 2, 2 }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+ Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
+ Rect u = UnionRects(r1, r2);
+ EXPECT_EQ(r3.x(), u.x());
+ EXPECT_EQ(r3.y(), u.y());
+ EXPECT_EQ(r3.width(), u.width());
+ EXPECT_EQ(r3.height(), u.height());
+ }
+}
+
+TEST(RectTest, Equals) {
+ ASSERT_TRUE(Rect(0, 0, 0, 0) == Rect(0, 0, 0, 0));
+ ASSERT_TRUE(Rect(1, 2, 3, 4) == Rect(1, 2, 3, 4));
+ ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 0, 0, 1));
+ ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 0, 1, 0));
+ ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 1, 0, 0));
+ ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(1, 0, 0, 0));
+}
+
+TEST(RectTest, AdjustToFit) {
+ static const struct Test {
+ int x1; // source
+ int y1;
+ int w1;
+ int h1;
+ int x2; // target
+ int y2;
+ int w2;
+ int h2;
+ int x3; // rect 3: results of invoking AdjustToFit
+ int y3;
+ int w3;
+ int h3;
+ } tests[] = {
+ { 0, 0, 2, 2,
+ 0, 0, 2, 2,
+ 0, 0, 2, 2 },
+ { 2, 2, 3, 3,
+ 0, 0, 4, 4,
+ 1, 1, 3, 3 },
+ { -1, -1, 5, 5,
+ 0, 0, 4, 4,
+ 0, 0, 4, 4 },
+ { 2, 2, 4, 4,
+ 0, 0, 3, 3,
+ 0, 0, 3, 3 },
+ { 2, 2, 1, 1,
+ 0, 0, 3, 3,
+ 2, 2, 1, 1 }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+ Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
+ Rect u = r1;
+ u.AdjustToFit(r2);
+ EXPECT_EQ(r3.x(), u.x());
+ EXPECT_EQ(r3.y(), u.y());
+ EXPECT_EQ(r3.width(), u.width());
+ EXPECT_EQ(r3.height(), u.height());
+ }
+}
+
+TEST(RectTest, Subtract) {
+ Rect result;
+
+ // Matching
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(10, 10, 20, 20));
+ EXPECT_EQ(Rect(0, 0, 0, 0).ToString(), result.ToString());
+
+ // Contains
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(5, 5, 30, 30));
+ EXPECT_EQ(Rect(0, 0, 0, 0).ToString(), result.ToString());
+
+ // No intersection
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(30, 30, 30, 30));
+ EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
+
+ // Not a complete intersection in either direction
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(15, 15, 20, 20));
+ EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
+
+ // Complete intersection in the x-direction, top edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(10, 15, 20, 20));
+ EXPECT_EQ(Rect(10, 10, 20, 5).ToString(), result.ToString());
+
+ // Complete intersection in the x-direction, top edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(5, 15, 30, 20));
+ EXPECT_EQ(Rect(10, 10, 20, 5).ToString(), result.ToString());
+
+ // Complete intersection in the x-direction, bottom edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(5, 5, 30, 20));
+ EXPECT_EQ(Rect(10, 25, 20, 5).ToString(), result.ToString());
+
+ // Complete intersection in the x-direction, none of the edges is fully
+ // covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(5, 15, 30, 1));
+ EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
+
+ // Complete intersection in the y-direction, left edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(10, 10, 10, 30));
+ EXPECT_EQ(Rect(20, 10, 10, 20).ToString(), result.ToString());
+
+ // Complete intersection in the y-direction, left edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(5, 5, 20, 30));
+ EXPECT_EQ(Rect(25, 10, 5, 20).ToString(), result.ToString());
+
+ // Complete intersection in the y-direction, right edge is fully covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(20, 5, 20, 30));
+ EXPECT_EQ(Rect(10, 10, 10, 20).ToString(), result.ToString());
+
+ // Complete intersection in the y-direction, none of the edges is fully
+ // covered.
+ result = Rect(10, 10, 20, 20);
+ result.Subtract(Rect(15, 5, 1, 30));
+ EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
+}
+
+TEST(RectTest, IsEmpty) {
+ EXPECT_TRUE(Rect(0, 0, 0, 0).IsEmpty());
+ EXPECT_TRUE(Rect(0, 0, 0, 0).size().IsEmpty());
+ EXPECT_TRUE(Rect(0, 0, 10, 0).IsEmpty());
+ EXPECT_TRUE(Rect(0, 0, 10, 0).size().IsEmpty());
+ EXPECT_TRUE(Rect(0, 0, 0, 10).IsEmpty());
+ EXPECT_TRUE(Rect(0, 0, 0, 10).size().IsEmpty());
+ EXPECT_FALSE(Rect(0, 0, 10, 10).IsEmpty());
+ EXPECT_FALSE(Rect(0, 0, 10, 10).size().IsEmpty());
+}
+
+TEST(RectTest, SplitVertically) {
+ Rect left_half, right_half;
+
+ // Splitting when origin is (0, 0).
+ Rect(0, 0, 20, 20).SplitVertically(&left_half, &right_half);
+ EXPECT_TRUE(left_half == Rect(0, 0, 10, 20));
+ EXPECT_TRUE(right_half == Rect(10, 0, 10, 20));
+
+ // Splitting when origin is arbitrary.
+ Rect(10, 10, 20, 10).SplitVertically(&left_half, &right_half);
+ EXPECT_TRUE(left_half == Rect(10, 10, 10, 10));
+ EXPECT_TRUE(right_half == Rect(20, 10, 10, 10));
+
+ // Splitting a rectangle of zero width.
+ Rect(10, 10, 0, 10).SplitVertically(&left_half, &right_half);
+ EXPECT_TRUE(left_half == Rect(10, 10, 0, 10));
+ EXPECT_TRUE(right_half == Rect(10, 10, 0, 10));
+
+ // Splitting a rectangle of odd width.
+ Rect(10, 10, 5, 10).SplitVertically(&left_half, &right_half);
+ EXPECT_TRUE(left_half == Rect(10, 10, 2, 10));
+ EXPECT_TRUE(right_half == Rect(12, 10, 3, 10));
+}
+
+TEST(RectTest, CenterPoint) {
+ Point center;
+
+ // When origin is (0, 0).
+ center = Rect(0, 0, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == Point(10, 10));
+
+ // When origin is even.
+ center = Rect(10, 10, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == Point(20, 20));
+
+ // When origin is odd.
+ center = Rect(11, 11, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == Point(21, 21));
+
+ // When 0 width or height.
+ center = Rect(10, 10, 0, 20).CenterPoint();
+ EXPECT_TRUE(center == Point(10, 20));
+ center = Rect(10, 10, 20, 0).CenterPoint();
+ EXPECT_TRUE(center == Point(20, 10));
+
+ // When an odd size.
+ center = Rect(10, 10, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == Point(20, 20));
+
+ // When an odd size and position.
+ center = Rect(11, 11, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == Point(21, 21));
+}
+
+TEST(RectTest, CenterPointF) {
+ PointF center;
+
+ // When origin is (0, 0).
+ center = RectF(0, 0, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(10, 10));
+
+ // When origin is even.
+ center = RectF(10, 10, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(20, 20));
+
+ // When origin is odd.
+ center = RectF(11, 11, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(21, 21));
+
+ // When 0 width or height.
+ center = RectF(10, 10, 0, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(10, 20));
+ center = RectF(10, 10, 20, 0).CenterPoint();
+ EXPECT_TRUE(center == PointF(20, 10));
+
+ // When an odd size.
+ center = RectF(10, 10, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == PointF(20.5f, 20.5f));
+
+ // When an odd size and position.
+ center = RectF(11, 11, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == PointF(21.5f, 21.5f));
+}
+
+TEST(RectTest, SharesEdgeWith) {
+ Rect r(2, 3, 4, 5);
+
+ // Must be non-overlapping
+ EXPECT_FALSE(r.SharesEdgeWith(r));
+
+ Rect just_above(2, 1, 4, 2);
+ Rect just_below(2, 8, 4, 2);
+ Rect just_left(0, 3, 2, 5);
+ Rect just_right(6, 3, 2, 5);
+
+ EXPECT_TRUE(r.SharesEdgeWith(just_above));
+ EXPECT_TRUE(r.SharesEdgeWith(just_below));
+ EXPECT_TRUE(r.SharesEdgeWith(just_left));
+ EXPECT_TRUE(r.SharesEdgeWith(just_right));
+
+ // Wrong placement
+ Rect same_height_no_edge(0, 0, 1, 5);
+ Rect same_width_no_edge(0, 0, 4, 1);
+
+ EXPECT_FALSE(r.SharesEdgeWith(same_height_no_edge));
+ EXPECT_FALSE(r.SharesEdgeWith(same_width_no_edge));
+
+ Rect just_above_no_edge(2, 1, 5, 2); // too wide
+ Rect just_below_no_edge(2, 8, 3, 2); // too narrow
+ Rect just_left_no_edge(0, 3, 2, 6); // too tall
+ Rect just_right_no_edge(6, 3, 2, 4); // too short
+
+ EXPECT_FALSE(r.SharesEdgeWith(just_above_no_edge));
+ EXPECT_FALSE(r.SharesEdgeWith(just_below_no_edge));
+ EXPECT_FALSE(r.SharesEdgeWith(just_left_no_edge));
+ EXPECT_FALSE(r.SharesEdgeWith(just_right_no_edge));
+}
+
+// Similar to EXPECT_FLOAT_EQ, but lets NaN equal NaN
+#define EXPECT_FLOAT_AND_NAN_EQ(a, b) \
+ { if (a == a || b == b) { EXPECT_FLOAT_EQ(a, b); } }
+
+TEST(RectTest, ScaleRect) {
+ static const struct Test {
+ int x1; // source
+ int y1;
+ int w1;
+ int h1;
+ float scale;
+ float x2; // target
+ float y2;
+ float w2;
+ float h2;
+ } tests[] = {
+ { 3, 3, 3, 3,
+ 1.5f,
+ 4.5f, 4.5f, 4.5f, 4.5f },
+ { 3, 3, 3, 3,
+ 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f },
+ { 3, 3, 3, 3,
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN() },
+ { 3, 3, 3, 3,
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max() }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ RectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+
+ RectF scaled = ScaleRect(r1, tests[i].scale);
+ EXPECT_FLOAT_AND_NAN_EQ(r2.x(), scaled.x());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.y(), scaled.y());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.width(), scaled.width());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.height(), scaled.height());
+ }
+}
+
+TEST(RectTest, ToEnclosedRect) {
+ static const struct Test {
+ float x1; // source
+ float y1;
+ float w1;
+ float h1;
+ int x2; // target
+ int y2;
+ int w2;
+ int h2;
+ } tests [] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f,
+ 0, 0, 0, 0 },
+ { -1.5f, -1.5f, 3.0f, 3.0f,
+ -1, -1, 2, 2 },
+ { -1.5f, -1.5f, 3.5f, 3.5f,
+ -1, -1, 3, 3 },
+ { std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ 2.0f, 2.0f,
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max(),
+ 0, 0 },
+ { 0.0f, 0.0f,
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ 0, 0,
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max() },
+ { 20000.5f, 20000.5f, 0.5f, 0.5f,
+ 20001, 20001, 0, 0 },
+ { std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ 0, 0, 0, 0 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+
+ Rect enclosed = ToEnclosedRect(r1);
+ EXPECT_FLOAT_AND_NAN_EQ(r2.x(), enclosed.x());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.y(), enclosed.y());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.width(), enclosed.width());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.height(), enclosed.height());
+ }
+}
+
+TEST(RectTest, ToEnclosingRect) {
+ static const struct Test {
+ float x1; // source
+ float y1;
+ float w1;
+ float h1;
+ int x2; // target
+ int y2;
+ int w2;
+ int h2;
+ } tests [] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f,
+ 0, 0, 0, 0 },
+ { 5.5f, 5.5f, 0.0f, 0.0f,
+ 5, 5, 0, 0 },
+ { -1.5f, -1.5f, 3.0f, 3.0f,
+ -2, -2, 4, 4 },
+ { -1.5f, -1.5f, 3.5f, 3.5f,
+ -2, -2, 4, 4 },
+ { std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ 2.0f, 2.0f,
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max(),
+ 0, 0 },
+ { 0.0f, 0.0f,
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ 0, 0,
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max() },
+ { 20000.5f, 20000.5f, 0.5f, 0.5f,
+ 20000, 20000, 1, 1 },
+ { std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ std::numeric_limits<float>::quiet_NaN(),
+ 0, 0, 0, 0 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+
+ Rect enclosed = ToEnclosingRect(r1);
+ EXPECT_FLOAT_AND_NAN_EQ(r2.x(), enclosed.x());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.y(), enclosed.y());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.width(), enclosed.width());
+ EXPECT_FLOAT_AND_NAN_EQ(r2.height(), enclosed.height());
+ }
+}
+
+TEST(RectTest, ToNearestRect) {
+ Rect rect;
+ EXPECT_EQ(rect.ToString(), ToNearestRect(RectF(rect)).ToString());
+
+ rect = Rect(-1, -1, 3, 3);
+ EXPECT_EQ(rect.ToString(), ToNearestRect(RectF(rect)).ToString());
+
+ RectF rectf(-1.00001f, -0.999999f, 3.0000001f, 2.999999f);
+ EXPECT_EQ(rect.ToString(), ToNearestRect(rectf).ToString());
+}
+
+TEST(RectTest, ToFlooredRect) {
+ static const struct Test {
+ float x1; // source
+ float y1;
+ float w1;
+ float h1;
+ int x2; // target
+ int y2;
+ int w2;
+ int h2;
+ } tests [] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f,
+ 0, 0, 0, 0 },
+ { -1.5f, -1.5f, 3.0f, 3.0f,
+ -2, -2, 3, 3 },
+ { -1.5f, -1.5f, 3.5f, 3.5f,
+ -2, -2, 3, 3 },
+ { 20000.5f, 20000.5f, 0.5f, 0.5f,
+ 20000, 20000, 0, 0 },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
+ Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+
+ Rect floored = ToFlooredRectDeprecated(r1);
+ EXPECT_FLOAT_EQ(r2.x(), floored.x());
+ EXPECT_FLOAT_EQ(r2.y(), floored.y());
+ EXPECT_FLOAT_EQ(r2.width(), floored.width());
+ EXPECT_FLOAT_EQ(r2.height(), floored.height());
+ }
+}
+
+TEST(RectTest, ScaleToEnclosedRect) {
+ static const struct Test {
+ Rect input_rect;
+ float input_scale;
+ Rect expected_rect;
+ } tests[] = {
+ {
+ Rect(),
+ 5.f,
+ Rect(),
+ }, {
+ Rect(1, 1, 1, 1),
+ 5.f,
+ Rect(5, 5, 5, 5),
+ }, {
+ Rect(-1, -1, 0, 0),
+ 5.f,
+ Rect(-5, -5, 0, 0),
+ }, {
+ Rect(1, -1, 0, 1),
+ 5.f,
+ Rect(5, -5, 0, 5),
+ }, {
+ Rect(-1, 1, 1, 0),
+ 5.f,
+ Rect(-5, 5, 5, 0),
+ }, {
+ Rect(1, 2, 3, 4),
+ 1.5f,
+ Rect(2, 3, 4, 6),
+ }, {
+ Rect(-1, -2, 0, 0),
+ 1.5f,
+ Rect(-1, -3, 0, 0),
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect result = ScaleToEnclosedRect(tests[i].input_rect,
+ tests[i].input_scale);
+ EXPECT_EQ(tests[i].expected_rect.ToString(), result.ToString());
+ }
+}
+
+TEST(RectTest, ScaleToEnclosingRect) {
+ static const struct Test {
+ Rect input_rect;
+ float input_scale;
+ Rect expected_rect;
+ } tests[] = {
+ {
+ Rect(),
+ 5.f,
+ Rect(),
+ }, {
+ Rect(1, 1, 1, 1),
+ 5.f,
+ Rect(5, 5, 5, 5),
+ }, {
+ Rect(-1, -1, 0, 0),
+ 5.f,
+ Rect(-5, -5, 0, 0),
+ }, {
+ Rect(1, -1, 0, 1),
+ 5.f,
+ Rect(5, -5, 0, 5),
+ }, {
+ Rect(-1, 1, 1, 0),
+ 5.f,
+ Rect(-5, 5, 5, 0),
+ }, {
+ Rect(1, 2, 3, 4),
+ 1.5f,
+ Rect(1, 3, 5, 6),
+ }, {
+ Rect(-1, -2, 0, 0),
+ 1.5f,
+ Rect(-2, -3, 0, 0),
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Rect result = ScaleToEnclosingRect(tests[i].input_rect,
+ tests[i].input_scale);
+ EXPECT_EQ(tests[i].expected_rect.ToString(), result.ToString());
+ }
+}
+
+#if defined(OS_WIN)
+TEST(RectTest, ConstructAndAssign) {
+ const RECT rect_1 = { 0, 0, 10, 10 };
+ const RECT rect_2 = { 0, 0, -10, -10 };
+ Rect test1(rect_1);
+ Rect test2(rect_2);
+}
+#endif
+
+TEST(RectTest, ToRectF) {
+ // Check that implicit conversion from integer to float compiles.
+ Rect a(10, 20, 30, 40);
+ RectF b(10, 20, 30, 40);
+
+ RectF intersect = IntersectRects(a, b);
+ EXPECT_EQ(b.ToString(), intersect.ToString());
+
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(b, a);
+}
+
+TEST(RectTest, BoundingRect) {
+ struct {
+ Point a;
+ Point b;
+ Rect expected;
+ } int_tests[] = {
+ // If point B dominates A, then A should be the origin.
+ { Point(4, 6), Point(4, 6), Rect(4, 6, 0, 0) },
+ { Point(4, 6), Point(8, 6), Rect(4, 6, 4, 0) },
+ { Point(4, 6), Point(4, 9), Rect(4, 6, 0, 3) },
+ { Point(4, 6), Point(8, 9), Rect(4, 6, 4, 3) },
+ // If point A dominates B, then B should be the origin.
+ { Point(4, 6), Point(4, 6), Rect(4, 6, 0, 0) },
+ { Point(8, 6), Point(4, 6), Rect(4, 6, 4, 0) },
+ { Point(4, 9), Point(4, 6), Rect(4, 6, 0, 3) },
+ { Point(8, 9), Point(4, 6), Rect(4, 6, 4, 3) },
+ // If neither point dominates, then the origin is a combination of the two.
+ { Point(4, 6), Point(6, 4), Rect(4, 4, 2, 2) },
+ { Point(-4, -6), Point(-6, -4), Rect(-6, -6, 2, 2) },
+ { Point(-4, 6), Point(6, -4), Rect(-4, -4, 10, 10) },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i) {
+ Rect actual = BoundingRect(int_tests[i].a, int_tests[i].b);
+ EXPECT_EQ(int_tests[i].expected.ToString(), actual.ToString());
+ }
+
+ struct {
+ PointF a;
+ PointF b;
+ RectF expected;
+ } float_tests[] = {
+ // If point B dominates A, then A should be the origin.
+ { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
+ RectF(4.2f, 6.8f, 0, 0) },
+ { PointF(4.2f, 6.8f), PointF(8.5f, 6.8f),
+ RectF(4.2f, 6.8f, 4.3f, 0) },
+ { PointF(4.2f, 6.8f), PointF(4.2f, 9.3f),
+ RectF(4.2f, 6.8f, 0, 2.5f) },
+ { PointF(4.2f, 6.8f), PointF(8.5f, 9.3f),
+ RectF(4.2f, 6.8f, 4.3f, 2.5f) },
+ // If point A dominates B, then B should be the origin.
+ { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
+ RectF(4.2f, 6.8f, 0, 0) },
+ { PointF(8.5f, 6.8f), PointF(4.2f, 6.8f),
+ RectF(4.2f, 6.8f, 4.3f, 0) },
+ { PointF(4.2f, 9.3f), PointF(4.2f, 6.8f),
+ RectF(4.2f, 6.8f, 0, 2.5f) },
+ { PointF(8.5f, 9.3f), PointF(4.2f, 6.8f),
+ RectF(4.2f, 6.8f, 4.3f, 2.5f) },
+ // If neither point dominates, then the origin is a combination of the two.
+ { PointF(4.2f, 6.8f), PointF(6.8f, 4.2f),
+ RectF(4.2f, 4.2f, 2.6f, 2.6f) },
+ { PointF(-4.2f, -6.8f), PointF(-6.8f, -4.2f),
+ RectF(-6.8f, -6.8f, 2.6f, 2.6f) },
+ { PointF(-4.2f, 6.8f), PointF(6.8f, -4.2f),
+ RectF(-4.2f, -4.2f, 11.0f, 11.0f) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i) {
+ RectF actual = BoundingRect(float_tests[i].a, float_tests[i].b);
+ EXPECT_EQ(float_tests[i].expected.ToString(), actual.ToString());
+ }
+}
+
+TEST(RectTest, IsExpressibleAsRect) {
+ EXPECT_TRUE(RectF().IsExpressibleAsRect());
+
+ float min = std::numeric_limits<int>::min();
+ float max = std::numeric_limits<int>::max();
+ float infinity = std::numeric_limits<float>::infinity();
+
+ EXPECT_TRUE(RectF(
+ min + 200, min + 200, max - 200, max - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(
+ min - 200, min + 200, max + 200, max + 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(
+ min + 200 , min - 200, max + 200, max + 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(
+ min + 200, min + 200, max + 200, max - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(
+ min + 200, min + 200, max - 200, max + 200).IsExpressibleAsRect());
+
+ EXPECT_TRUE(RectF(0, 0, max - 200, max - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(200, 0, max + 200, max - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 200, max - 200, max + 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, max + 200, max - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, max - 200, max + 200).IsExpressibleAsRect());
+
+ EXPECT_FALSE(RectF(infinity, 0, 1, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, infinity, 1, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, infinity, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, 1, infinity).IsExpressibleAsRect());
+}
+
+TEST(RectTest, Offset) {
+ Rect i(1, 2, 3, 4);
+
+ EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), (i + Vector2d(1, -1)).ToString());
+ EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), (Vector2d(1, -1) + i).ToString());
+ i += Vector2d(1, -1);
+ EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), i.ToString());
+ EXPECT_EQ(Rect(1, 2, 3, 4).ToString(), (i - Vector2d(1, -1)).ToString());
+ i -= Vector2d(1, -1);
+ EXPECT_EQ(Rect(1, 2, 3, 4).ToString(), i.ToString());
+
+ RectF f(1.1f, 2.2f, 3.3f, 4.4f);
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(),
+ (f + Vector2dF(1.1f, -1.1f)).ToString());
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(),
+ (Vector2dF(1.1f, -1.1f) + f).ToString());
+ f += Vector2dF(1.1f, -1.1f);
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(), f.ToString());
+ EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f).ToString(),
+ (f - Vector2dF(1.1f, -1.1f)).ToString());
+ f -= Vector2dF(1.1f, -1.1f);
+ EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f).ToString(), f.ToString());
+}
+
+TEST(RectTest, Corners) {
+ Rect i(1, 2, 3, 4);
+ RectF f(1.1f, 2.1f, 3.1f, 4.1f);
+
+ EXPECT_EQ(Point(1, 2).ToString(), i.origin().ToString());
+ EXPECT_EQ(Point(4, 2).ToString(), i.top_right().ToString());
+ EXPECT_EQ(Point(1, 6).ToString(), i.bottom_left().ToString());
+ EXPECT_EQ(Point(4, 6).ToString(), i.bottom_right().ToString());
+
+ EXPECT_EQ(PointF(1.1f, 2.1f).ToString(), f.origin().ToString());
+ EXPECT_EQ(PointF(4.2f, 2.1f).ToString(), f.top_right().ToString());
+ EXPECT_EQ(PointF(1.1f, 6.2f).ToString(), f.bottom_left().ToString());
+ EXPECT_EQ(PointF(4.2f, 6.2f).ToString(), f.bottom_right().ToString());
+}
+
+TEST(RectTest, ManhattanDistanceToPoint) {
+ Rect i(1, 2, 3, 4);
+ EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(1, 2)));
+ EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(4, 6)));
+ EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(2, 4)));
+ EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(0, 0)));
+ EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(2, 0)));
+ EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 0)));
+ EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(5, 4)));
+ EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 8)));
+ EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(3, 8)));
+ EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(0, 7)));
+ EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(0, 3)));
+
+ RectF f(1.1f, 2.1f, 3.1f, 4.1f);
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(1.1f, 2.1f)));
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(4.2f, 6.f)));
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(2.f, 4.f)));
+ EXPECT_FLOAT_EQ(3.2f, f.ManhattanDistanceToPoint(PointF(0.f, 0.f)));
+ EXPECT_FLOAT_EQ(2.1f, f.ManhattanDistanceToPoint(PointF(2.f, 0.f)));
+ EXPECT_FLOAT_EQ(2.9f, f.ManhattanDistanceToPoint(PointF(5.f, 0.f)));
+ EXPECT_FLOAT_EQ(.8f, f.ManhattanDistanceToPoint(PointF(5.f, 4.f)));
+ EXPECT_FLOAT_EQ(2.6f, f.ManhattanDistanceToPoint(PointF(5.f, 8.f)));
+ EXPECT_FLOAT_EQ(1.8f, f.ManhattanDistanceToPoint(PointF(3.f, 8.f)));
+ EXPECT_FLOAT_EQ(1.9f, f.ManhattanDistanceToPoint(PointF(0.f, 7.f)));
+ EXPECT_FLOAT_EQ(1.1f, f.ManhattanDistanceToPoint(PointF(0.f, 3.f)));
+}
+
+TEST(RectTest, ManhattanInternalDistance) {
+ Rect i(0, 0, 400, 400);
+ EXPECT_EQ(0, i.ManhattanInternalDistance(gfx::Rect(-1, 0, 2, 1)));
+ EXPECT_EQ(1, i.ManhattanInternalDistance(gfx::Rect(400, 0, 1, 400)));
+ EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-100, -100, 100, 100)));
+ EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-101, 100, 100, 100)));
+ EXPECT_EQ(4, i.ManhattanInternalDistance(gfx::Rect(-101, -101, 100, 100)));
+ EXPECT_EQ(435, i.ManhattanInternalDistance(gfx::Rect(630, 603, 100, 100)));
+
+ RectF f(0.0f, 0.0f, 400.0f, 400.0f);
+ static const float kEpsilon = std::numeric_limits<float>::epsilon();
+
+ EXPECT_FLOAT_EQ(
+ 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 2.0f, 1.0f)));
+ EXPECT_FLOAT_EQ(
+ kEpsilon,
+ f.ManhattanInternalDistance(gfx::RectF(400.0f, 0.0f, 1.0f, 400.0f)));
+ EXPECT_FLOAT_EQ(2.0f * kEpsilon,
+ f.ManhattanInternalDistance(
+ gfx::RectF(-100.0f, -100.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(
+ 1.0f + kEpsilon,
+ f.ManhattanInternalDistance(gfx::RectF(-101.0f, 100.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(2.0f + 2.0f * kEpsilon,
+ f.ManhattanInternalDistance(
+ gfx::RectF(-101.0f, -101.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(
+ 433.0f + 2.0f * kEpsilon,
+ f.ManhattanInternalDistance(gfx::RectF(630.0f, 603.0f, 100.0f, 100.0f)));
+
+ EXPECT_FLOAT_EQ(
+ 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 1.1f, 1.0f)));
+ EXPECT_FLOAT_EQ(
+ 0.1f + kEpsilon,
+ f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.4f, 1.0f)));
+ EXPECT_FLOAT_EQ(
+ kEpsilon,
+ f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.5f, 1.0f)));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/safe_integer_conversions.h b/chromium/ui/gfx/geometry/safe_integer_conversions.h
new file mode 100644
index 00000000000..4d289ecabaf
--- /dev/null
+++ b/chromium/ui/gfx/geometry/safe_integer_conversions.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_
+
+#include <cmath>
+#include <limits>
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+inline int ClampToInt(float value) {
+ if (value != value)
+ return 0; // no int NaN.
+ if (value >= std::numeric_limits<int>::max())
+ return std::numeric_limits<int>::max();
+ if (value <= std::numeric_limits<int>::min())
+ return std::numeric_limits<int>::min();
+ return static_cast<int>(value);
+}
+
+inline int ToFlooredInt(float value) {
+ return ClampToInt(std::floor(value));
+}
+
+inline int ToCeiledInt(float value) {
+ return ClampToInt(std::ceil(value));
+}
+
+inline int ToRoundedInt(float value) {
+ float rounded;
+ if (value >= 0.0f)
+ rounded = std::floor(value + 0.5f);
+ else
+ rounded = std::ceil(value - 0.5f);
+ return ClampToInt(rounded);
+}
+
+inline bool IsExpressibleAsInt(float value) {
+ if (value != value)
+ return false; // no int NaN.
+ if (value > std::numeric_limits<int>::max())
+ return false;
+ if (value < std::numeric_limits<int>::min())
+ return false;
+ return true;
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc b/chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc
new file mode 100644
index 00000000000..e00671b264a
--- /dev/null
+++ b/chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gfx {
+
+TEST(SafeIntegerConversions, ClampToInt) {
+ EXPECT_EQ(0, ClampToInt(std::numeric_limits<float>::quiet_NaN()));
+
+ float max = std::numeric_limits<int>::max();
+ float min = std::numeric_limits<int>::min();
+ float infinity = std::numeric_limits<float>::infinity();
+
+ int int_max = std::numeric_limits<int>::max();
+ int int_min = std::numeric_limits<int>::min();
+
+ EXPECT_EQ(int_max, ClampToInt(infinity));
+ EXPECT_EQ(int_max, ClampToInt(max));
+ EXPECT_EQ(int_max, ClampToInt(max + 100));
+
+ EXPECT_EQ(-100, ClampToInt(-100.5f));
+ EXPECT_EQ(0, ClampToInt(0));
+ EXPECT_EQ(100, ClampToInt(100.5f));
+
+ EXPECT_EQ(int_min, ClampToInt(-infinity));
+ EXPECT_EQ(int_min, ClampToInt(min));
+ EXPECT_EQ(int_min, ClampToInt(min - 100));
+}
+
+TEST(SafeIntegerConversions, ToFlooredInt) {
+ EXPECT_EQ(0, ToFlooredInt(std::numeric_limits<float>::quiet_NaN()));
+
+ float max = std::numeric_limits<int>::max();
+ float min = std::numeric_limits<int>::min();
+ float infinity = std::numeric_limits<float>::infinity();
+
+ int int_max = std::numeric_limits<int>::max();
+ int int_min = std::numeric_limits<int>::min();
+
+ EXPECT_EQ(int_max, ToFlooredInt(infinity));
+ EXPECT_EQ(int_max, ToFlooredInt(max));
+ EXPECT_EQ(int_max, ToFlooredInt(max + 100));
+
+ EXPECT_EQ(-101, ToFlooredInt(-100.5f));
+ EXPECT_EQ(0, ToFlooredInt(0));
+ EXPECT_EQ(100, ToFlooredInt(100.5f));
+
+ EXPECT_EQ(int_min, ToFlooredInt(-infinity));
+ EXPECT_EQ(int_min, ToFlooredInt(min));
+ EXPECT_EQ(int_min, ToFlooredInt(min - 100));
+}
+
+TEST(SafeIntegerConversions, ToCeiledInt) {
+ EXPECT_EQ(0, ToCeiledInt(std::numeric_limits<float>::quiet_NaN()));
+
+ float max = std::numeric_limits<int>::max();
+ float min = std::numeric_limits<int>::min();
+ float infinity = std::numeric_limits<float>::infinity();
+
+ int int_max = std::numeric_limits<int>::max();
+ int int_min = std::numeric_limits<int>::min();
+
+ EXPECT_EQ(int_max, ToCeiledInt(infinity));
+ EXPECT_EQ(int_max, ToCeiledInt(max));
+ EXPECT_EQ(int_max, ToCeiledInt(max + 100));
+
+ EXPECT_EQ(-100, ToCeiledInt(-100.5f));
+ EXPECT_EQ(0, ToCeiledInt(0));
+ EXPECT_EQ(101, ToCeiledInt(100.5f));
+
+ EXPECT_EQ(int_min, ToCeiledInt(-infinity));
+ EXPECT_EQ(int_min, ToCeiledInt(min));
+ EXPECT_EQ(int_min, ToCeiledInt(min - 100));
+}
+
+TEST(SafeIntegerConversions, ToRoundedInt) {
+ EXPECT_EQ(0, ToRoundedInt(std::numeric_limits<float>::quiet_NaN()));
+
+ float max = std::numeric_limits<int>::max();
+ float min = std::numeric_limits<int>::min();
+ float infinity = std::numeric_limits<float>::infinity();
+
+ int int_max = std::numeric_limits<int>::max();
+ int int_min = std::numeric_limits<int>::min();
+
+ EXPECT_EQ(int_max, ToRoundedInt(infinity));
+ EXPECT_EQ(int_max, ToRoundedInt(max));
+ EXPECT_EQ(int_max, ToRoundedInt(max + 100));
+
+ EXPECT_EQ(-100, ToRoundedInt(-100.1f));
+ EXPECT_EQ(-101, ToRoundedInt(-100.5f));
+ EXPECT_EQ(-101, ToRoundedInt(-100.9f));
+ EXPECT_EQ(0, ToRoundedInt(0));
+ EXPECT_EQ(100, ToRoundedInt(100.1f));
+ EXPECT_EQ(101, ToRoundedInt(100.5f));
+ EXPECT_EQ(101, ToRoundedInt(100.9f));
+
+ EXPECT_EQ(int_min, ToRoundedInt(-infinity));
+ EXPECT_EQ(int_min, ToRoundedInt(min));
+ EXPECT_EQ(int_min, ToRoundedInt(min - 100));
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/size.cc b/chromium/ui/gfx/geometry/size.cc
new file mode 100644
index 00000000000..38ec4b3a516
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/size.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class SizeBase<Size, int>;
+
+#if defined(OS_MACOSX)
+Size::Size(const CGSize& s)
+ : SizeBase<Size, int>(s.width, s.height) {
+}
+
+Size& Size::operator=(const CGSize& s) {
+ set_width(s.width);
+ set_height(s.height);
+ return *this;
+}
+#endif
+
+#if defined(OS_WIN)
+SIZE Size::ToSIZE() const {
+ SIZE s;
+ s.cx = width();
+ s.cy = height();
+ return s;
+}
+#elif defined(OS_MACOSX)
+CGSize Size::ToCGSize() const {
+ return CGSizeMake(width(), height());
+}
+#endif
+
+std::string Size::ToString() const {
+ return base::StringPrintf("%dx%d", width(), height());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/size.h b/chromium/ui/gfx/geometry/size.h
new file mode 100644
index 00000000000..78984b073f4
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_SIZE_H_
+#define UI_GFX_GEOMETRY_SIZE_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/gfx_export.h"
+
+#if defined(OS_WIN)
+typedef struct tagSIZE SIZE;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+// A size has width and height values.
+class GFX_EXPORT Size : public SizeBase<Size, int> {
+ public:
+ Size() : SizeBase<Size, int>(0, 0) {}
+ Size(int width, int height) : SizeBase<Size, int>(width, height) {}
+#if defined(OS_MACOSX)
+ explicit Size(const CGSize& s);
+#endif
+
+ ~Size() {}
+
+#if defined(OS_MACOSX)
+ Size& operator=(const CGSize& s);
+#endif
+
+#if defined(OS_WIN)
+ SIZE ToSIZE() const;
+#elif defined(OS_MACOSX)
+ CGSize ToCGSize() const;
+#endif
+
+ operator SizeF() const {
+ return SizeF(width(), height());
+ }
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+ return lhs.width() == rhs.width() && lhs.height() == rhs.height();
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+ return !(lhs == rhs);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class SizeBase<Size, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_H_
diff --git a/chromium/ui/gfx/geometry/size_base.h b/chromium/ui/gfx/geometry/size_base.h
new file mode 100644
index 00000000000..88a98ef4584
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_base.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_SIZE_BASE_H_
+#define UI_GFX_GEOMETRY_SIZE_BASE_H_
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A size has width and height values.
+template<typename Class, typename Type>
+class GFX_EXPORT SizeBase {
+ public:
+ Type width() const { return width_; }
+ Type height() const { return height_; }
+
+ Type GetArea() const { return width_ * height_; }
+
+ void SetSize(Type width, Type height) {
+ set_width(width);
+ set_height(height);
+ }
+
+ void Enlarge(Type width, Type height) {
+ set_width(width_ + width);
+ set_height(height_ + height);
+ }
+
+ void set_width(Type width) {
+ width_ = width < 0 ? 0 : width;
+ }
+ void set_height(Type height) {
+ height_ = height < 0 ? 0 : height;
+ }
+
+ void SetToMin(const Class& other) {
+ width_ = width_ <= other.width_ ? width_ : other.width_;
+ height_ = height_ <= other.height_ ? height_ : other.height_;
+ }
+
+ void SetToMax(const Class& other) {
+ width_ = width_ >= other.width_ ? width_ : other.width_;
+ height_ = height_ >= other.height_ ? height_ : other.height_;
+ }
+
+ bool IsEmpty() const {
+ return (width_ == 0) || (height_ == 0);
+ }
+
+ protected:
+ SizeBase(Type width, Type height)
+ : width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height) {
+ }
+
+ // Destructor is intentionally made non virtual and protected.
+ // Do not make this public.
+ ~SizeBase() {}
+
+ private:
+ Type width_;
+ Type height_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_BASE_H_
diff --git a/chromium/ui/gfx/geometry/size_conversions.cc b/chromium/ui/gfx/geometry/size_conversions.cc
new file mode 100644
index 00000000000..c924e86c9ae
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_conversions.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/size_conversions.h"
+
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace gfx {
+
+Size ToFlooredSize(const SizeF& size) {
+ int w = ToFlooredInt(size.width());
+ int h = ToFlooredInt(size.height());
+ return Size(w, h);
+}
+
+Size ToCeiledSize(const SizeF& size) {
+ int w = ToCeiledInt(size.width());
+ int h = ToCeiledInt(size.height());
+ return Size(w, h);
+}
+
+Size ToRoundedSize(const SizeF& size) {
+ int w = ToRoundedInt(size.width());
+ int h = ToRoundedInt(size.height());
+ return Size(w, h);
+}
+
+} // namespace gfx
+
diff --git a/chromium/ui/gfx/geometry/size_conversions.h b/chromium/ui/gfx/geometry/size_conversions.h
new file mode 100644
index 00000000000..96fb79f93c2
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_conversions.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace gfx {
+
+// Returns a Size with each component from the input SizeF floored.
+GFX_EXPORT Size ToFlooredSize(const SizeF& size);
+
+// Returns a Size with each component from the input SizeF ceiled.
+GFX_EXPORT Size ToCeiledSize(const SizeF& size);
+
+// Returns a Size with each component from the input SizeF rounded.
+GFX_EXPORT Size ToRoundedSize(const SizeF& size);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/geometry/size_f.cc b/chromium/ui/gfx/geometry/size_f.cc
new file mode 100644
index 00000000000..10c144575e7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_f.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/size_f.h"
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+template class SizeBase<SizeF, float>;
+
+std::string SizeF::ToString() const {
+ return base::StringPrintf("%fx%f", width(), height());
+}
+
+SizeF ScaleSize(const SizeF& s, float x_scale, float y_scale) {
+ SizeF scaled_s(s);
+ scaled_s.Scale(x_scale, y_scale);
+ return scaled_s;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/size_f.h b/chromium/ui/gfx/geometry/size_f.h
new file mode 100644
index 00000000000..8ec5628e62d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_f.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_SIZE_F_H_
+#define UI_GFX_GEOMETRY_SIZE_F_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating version of gfx::Size.
+class GFX_EXPORT SizeF : public SizeBase<SizeF, float> {
+ public:
+ SizeF() : SizeBase<SizeF, float>(0, 0) {}
+ SizeF(float width, float height) : SizeBase<SizeF, float>(width, height) {}
+ ~SizeF() {}
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ SetSize(width() * x_scale, height() * y_scale);
+ }
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const SizeF& lhs, const SizeF& rhs) {
+ return lhs.width() == rhs.width() && lhs.height() == rhs.height();
+}
+
+inline bool operator!=(const SizeF& lhs, const SizeF& rhs) {
+ return !(lhs == rhs);
+}
+
+GFX_EXPORT SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale);
+
+inline SizeF ScaleSize(const SizeF& p, float scale) {
+ return ScaleSize(p, scale, scale);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class SizeBase<SizeF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_F_H_
diff --git a/chromium/ui/gfx/geometry/size_unittest.cc b/chromium/ui/gfx/geometry/size_unittest.cc
new file mode 100644
index 00000000000..15892833307
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace gfx {
+
+namespace {
+
+int TestSizeF(const SizeF& s) {
+ return s.width();
+}
+
+} // namespace
+
+TEST(SizeTest, ToSizeF) {
+ // Check that implicit conversion from integer to float compiles.
+ Size a(10, 20);
+ float width = TestSizeF(a);
+ EXPECT_EQ(width, a.width());
+
+ SizeF b(10, 20);
+
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(b, a);
+}
+
+TEST(SizeTest, ToFlooredSize) {
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeTest, ToCeiledSize) {
+ EXPECT_EQ(Size(0, 0), ToCeiledSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToCeiledSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeTest, ToRoundedSize) {
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeTest, ClampSize) {
+ Size a;
+
+ a = Size(3, 5);
+ EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
+ a.SetToMax(Size(2, 4));
+ EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
+ a.SetToMax(Size(3, 5));
+ EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
+ a.SetToMax(Size(4, 2));
+ EXPECT_EQ(Size(4, 5).ToString(), a.ToString());
+ a.SetToMax(Size(8, 10));
+ EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
+
+ a.SetToMin(Size(9, 11));
+ EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
+ a.SetToMin(Size(8, 10));
+ EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
+ a.SetToMin(Size(11, 9));
+ EXPECT_EQ(Size(8, 9).ToString(), a.ToString());
+ a.SetToMin(Size(7, 11));
+ EXPECT_EQ(Size(7, 9).ToString(), a.ToString());
+ a.SetToMin(Size(3, 5));
+ EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
+}
+
+TEST(SizeTest, ClampSizeF) {
+ SizeF a;
+
+ a = SizeF(3.5f, 5.5f);
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(2.5f, 4.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(3.5f, 5.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(4.5f, 2.5f));
+ EXPECT_EQ(SizeF(4.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(8.5f, 10.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+
+ a.SetToMin(SizeF(9.5f, 11.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(8.5f, 10.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(11.5f, 9.5f));
+ EXPECT_EQ(SizeF(8.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(7.5f, 11.5f));
+ EXPECT_EQ(SizeF(7.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(3.5f, 5.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/vector2d.cc b/chromium/ui/gfx/geometry/vector2d.cc
new file mode 100644
index 00000000000..d9f57fd3b10
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/vector2d.h"
+
+#include <cmath>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+bool Vector2d::IsZero() const {
+ return x_ == 0 && y_ == 0;
+}
+
+void Vector2d::Add(const Vector2d& other) {
+ x_ += other.x_;
+ y_ += other.y_;
+}
+
+void Vector2d::Subtract(const Vector2d& other) {
+ x_ -= other.x_;
+ y_ -= other.y_;
+}
+
+int64 Vector2d::LengthSquared() const {
+ return static_cast<int64>(x_) * x_ + static_cast<int64>(y_) * y_;
+}
+
+float Vector2d::Length() const {
+ return static_cast<float>(std::sqrt(static_cast<double>(LengthSquared())));
+}
+
+std::string Vector2d::ToString() const {
+ return base::StringPrintf("[%d %d]", x_, y_);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/vector2d.h b/chromium/ui/gfx/geometry/vector2d.h
new file mode 100644
index 00000000000..12f29a956d7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d.h
@@ -0,0 +1,91 @@
+// 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.
+
+// Defines a simple integer vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR2D_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector2d {
+ public:
+ Vector2d() : x_(0), y_(0) {}
+ Vector2d(int x, int y) : x_(x), y_(y) {}
+
+ int x() const { return x_; }
+ void set_x(int x) { x_ = x; }
+
+ int y() const { return y_; }
+ void set_y(int y) { y_ = y; }
+
+ // True if both components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector2d& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector2d& other);
+
+ void operator+=(const Vector2d& other) { Add(other); }
+ void operator-=(const Vector2d& other) { Subtract(other); }
+
+ void SetToMin(const Vector2d& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ }
+
+ void SetToMax(const Vector2d& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ }
+
+ // Gives the square of the diagonal length of the vector. Since this is
+ // cheaper to compute than Length(), it is useful when you want to compare
+ // relative lengths of different vectors without needing the actual lengths.
+ int64 LengthSquared() const;
+ // Gives the diagonal length of the vector.
+ float Length() const;
+
+ std::string ToString() const;
+
+ operator Vector2dF() const { return Vector2dF(x_, y_); }
+
+ private:
+ int x_;
+ int y_;
+};
+
+inline bool operator==(const Vector2d& lhs, const Vector2d& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+}
+
+inline Vector2d operator-(const Vector2d& v) {
+ return Vector2d(-v.x(), -v.y());
+}
+
+inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) {
+ Vector2d result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) {
+ Vector2d result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_H_
diff --git a/chromium/ui/gfx/geometry/vector2d_conversions.cc b/chromium/ui/gfx/geometry/vector2d_conversions.cc
new file mode 100644
index 00000000000..dceb69e2ffe
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_conversions.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/vector2d_conversions.h"
+
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace gfx {
+
+Vector2d ToFlooredVector2d(const Vector2dF& vector2d) {
+ int x = ToFlooredInt(vector2d.x());
+ int y = ToFlooredInt(vector2d.y());
+ return Vector2d(x, y);
+}
+
+Vector2d ToCeiledVector2d(const Vector2dF& vector2d) {
+ int x = ToCeiledInt(vector2d.x());
+ int y = ToCeiledInt(vector2d.y());
+ return Vector2d(x, y);
+}
+
+Vector2d ToRoundedVector2d(const Vector2dF& vector2d) {
+ int x = ToRoundedInt(vector2d.x());
+ int y = ToRoundedInt(vector2d.y());
+ return Vector2d(x, y);
+}
+
+} // namespace gfx
+
diff --git a/chromium/ui/gfx/geometry/vector2d_conversions.h b/chromium/ui/gfx/geometry/vector2d_conversions.h
new file mode 100644
index 00000000000..f4e16ae4be7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_conversions.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR2D_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+// Returns a Vector2d with each component from the input Vector2dF floored.
+GFX_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d);
+
+// Returns a Vector2d with each component from the input Vector2dF ceiled.
+GFX_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d);
+
+// Returns a Vector2d with each component from the input Vector2dF rounded.
+GFX_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/geometry/vector2d_f.cc b/chromium/ui/gfx/geometry/vector2d_f.cc
new file mode 100644
index 00000000000..ccb15ae0c4c
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_f.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/vector2d_f.h"
+
+#include <cmath>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+std::string Vector2dF::ToString() const {
+ return base::StringPrintf("[%f %f]", x_, y_);
+}
+
+bool Vector2dF::IsZero() const {
+ return x_ == 0 && y_ == 0;
+}
+
+void Vector2dF::Add(const Vector2dF& other) {
+ x_ += other.x_;
+ y_ += other.y_;
+}
+
+void Vector2dF::Subtract(const Vector2dF& other) {
+ x_ -= other.x_;
+ y_ -= other.y_;
+}
+
+double Vector2dF::LengthSquared() const {
+ return static_cast<double>(x_) * x_ + static_cast<double>(y_) * y_;
+}
+
+float Vector2dF::Length() const {
+ return static_cast<float>(std::sqrt(LengthSquared()));
+}
+
+void Vector2dF::Scale(float x_scale, float y_scale) {
+ x_ *= x_scale;
+ y_ *= y_scale;
+}
+
+double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs) {
+ return static_cast<double>(lhs.x()) * rhs.y() -
+ static_cast<double>(lhs.y()) * rhs.x();
+}
+
+double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs) {
+ return static_cast<double>(lhs.x()) * rhs.x() +
+ static_cast<double>(lhs.y()) * rhs.y();
+}
+
+Vector2dF ScaleVector2d(const Vector2dF& v, float x_scale, float y_scale) {
+ Vector2dF scaled_v(v);
+ scaled_v.Scale(x_scale, y_scale);
+ return scaled_v;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/vector2d_f.h b/chromium/ui/gfx/geometry/vector2d_f.h
new file mode 100644
index 00000000000..4bab99e5825
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_f.h
@@ -0,0 +1,112 @@
+// 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.
+
+// Defines a simple float vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR2D_F_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_F_H_
+
+#include <string>
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector2dF {
+ public:
+ Vector2dF() : x_(0), y_(0) {}
+ Vector2dF(float x, float y) : x_(x), y_(y) {}
+
+ float x() const { return x_; }
+ void set_x(float x) { x_ = x; }
+
+ float y() const { return y_; }
+ void set_y(float y) { y_ = y; }
+
+ // True if both components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector2dF& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector2dF& other);
+
+ void operator+=(const Vector2dF& other) { Add(other); }
+ void operator-=(const Vector2dF& other) { Subtract(other); }
+
+ void SetToMin(const Vector2dF& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ }
+
+ void SetToMax(const Vector2dF& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ }
+
+ // Gives the square of the diagonal length of the vector.
+ double LengthSquared() const;
+ // Gives the diagonal length of the vector.
+ float Length() const;
+
+ // Scale the x and y components of the vector by |scale|.
+ void Scale(float scale) { Scale(scale, scale); }
+ // Scale the x and y components of the vector by |x_scale| and |y_scale|
+ // respectively.
+ void Scale(float x_scale, float y_scale);
+
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+};
+
+inline bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+}
+
+inline bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) {
+ return !(lhs == rhs);
+}
+
+inline Vector2dF operator-(const Vector2dF& v) {
+ return Vector2dF(-v.x(), -v.y());
+}
+
+inline Vector2dF operator+(const Vector2dF& lhs, const Vector2dF& rhs) {
+ Vector2dF result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) {
+ Vector2dF result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+// Return the cross product of two vectors.
+GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+
+// Return the dot product of two vectors.
+GFX_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+
+// Return a vector that is |v| scaled by the given scale factors along each
+// axis.
+GFX_EXPORT Vector2dF ScaleVector2d(const Vector2dF& v,
+ float x_scale,
+ float y_scale);
+
+// Return a vector that is |v| scaled by the given scale factor.
+inline Vector2dF ScaleVector2d(const Vector2dF& v, float scale) {
+ return ScaleVector2d(v, scale, scale);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_F_H_
diff --git a/chromium/ui/gfx/geometry/vector2d_unittest.cc b/chromium/ui/gfx/geometry/vector2d_unittest.cc
new file mode 100644
index 00000000000..38af69405f5
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+TEST(Vector2dTest, ConversionToFloat) {
+ Vector2d i(3, 4);
+ Vector2dF f = i;
+ EXPECT_EQ(i, f);
+}
+
+TEST(Vector2dTest, IsZero) {
+ Vector2d int_zero(0, 0);
+ Vector2d int_nonzero(2, -2);
+ Vector2dF float_zero(0, 0);
+ Vector2dF float_nonzero(0.1f, -0.1f);
+
+ EXPECT_TRUE(int_zero.IsZero());
+ EXPECT_FALSE(int_nonzero.IsZero());
+ EXPECT_TRUE(float_zero.IsZero());
+ EXPECT_FALSE(float_nonzero.IsZero());
+}
+
+TEST(Vector2dTest, Add) {
+ Vector2d i1(3, 5);
+ Vector2d i2(4, -1);
+
+ const struct {
+ Vector2d expected;
+ Vector2d actual;
+ } int_tests[] = {
+ { Vector2d(3, 5), i1 + Vector2d() },
+ { Vector2d(3 + 4, 5 - 1), i1 + i2 },
+ { Vector2d(3 - 4, 5 + 1), i1 - i2 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i)
+ EXPECT_EQ(int_tests[i].expected.ToString(),
+ int_tests[i].actual.ToString());
+
+ Vector2dF f1(3.1f, 5.1f);
+ Vector2dF f2(4.3f, -1.3f);
+
+ const struct {
+ Vector2dF expected;
+ Vector2dF actual;
+ } float_tests[] = {
+ { Vector2dF(3.1F, 5.1F), f1 + Vector2d() },
+ { Vector2dF(3.1F, 5.1F), f1 + Vector2dF() },
+ { Vector2dF(3.1f + 4.3f, 5.1f - 1.3f), f1 + f2 },
+ { Vector2dF(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
+ EXPECT_EQ(float_tests[i].expected.ToString(),
+ float_tests[i].actual.ToString());
+}
+
+TEST(Vector2dTest, Negative) {
+ const struct {
+ Vector2d expected;
+ Vector2d actual;
+ } int_tests[] = {
+ { Vector2d(0, 0), -Vector2d(0, 0) },
+ { Vector2d(-3, -3), -Vector2d(3, 3) },
+ { Vector2d(3, 3), -Vector2d(-3, -3) },
+ { Vector2d(-3, 3), -Vector2d(3, -3) },
+ { Vector2d(3, -3), -Vector2d(-3, 3) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i)
+ EXPECT_EQ(int_tests[i].expected.ToString(),
+ int_tests[i].actual.ToString());
+
+ const struct {
+ Vector2dF expected;
+ Vector2dF actual;
+ } float_tests[] = {
+ { Vector2dF(0, 0), -Vector2d(0, 0) },
+ { Vector2dF(-0.3f, -0.3f), -Vector2dF(0.3f, 0.3f) },
+ { Vector2dF(0.3f, 0.3f), -Vector2dF(-0.3f, -0.3f) },
+ { Vector2dF(-0.3f, 0.3f), -Vector2dF(0.3f, -0.3f) },
+ { Vector2dF(0.3f, -0.3f), -Vector2dF(-0.3f, 0.3f) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
+ EXPECT_EQ(float_tests[i].expected.ToString(),
+ float_tests[i].actual.ToString());
+}
+
+TEST(Vector2dTest, Scale) {
+ float double_values[][4] = {
+ { 4.5f, 1.2f, 3.3f, 5.6f },
+ { 4.5f, -1.2f, 3.3f, 5.6f },
+ { 4.5f, 1.2f, 3.3f, -5.6f },
+ { 4.5f, 1.2f, -3.3f, -5.6f },
+ { -4.5f, 1.2f, 3.3f, 5.6f },
+ { -4.5f, 1.2f, 0, 5.6f },
+ { -4.5f, 1.2f, 3.3f, 0 },
+ { 4.5f, 0, 3.3f, 5.6f },
+ { 0, 1.2f, 3.3f, 5.6f }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(double_values); ++i) {
+ Vector2dF v(double_values[i][0], double_values[i][1]);
+ v.Scale(double_values[i][2], double_values[i][3]);
+ EXPECT_EQ(v.x(), double_values[i][0] * double_values[i][2]);
+ EXPECT_EQ(v.y(), double_values[i][1] * double_values[i][3]);
+
+ Vector2dF v2 = ScaleVector2d(
+ gfx::Vector2dF(double_values[i][0], double_values[i][1]),
+ double_values[i][2], double_values[i][3]);
+ EXPECT_EQ(double_values[i][0] * double_values[i][2], v2.x());
+ EXPECT_EQ(double_values[i][1] * double_values[i][3], v2.y());
+ }
+
+ float single_values[][3] = {
+ { 4.5f, 1.2f, 3.3f },
+ { 4.5f, -1.2f, 3.3f },
+ { 4.5f, 1.2f, 3.3f },
+ { 4.5f, 1.2f, -3.3f },
+ { -4.5f, 1.2f, 3.3f },
+ { -4.5f, 1.2f, 0 },
+ { -4.5f, 1.2f, 3.3f },
+ { 4.5f, 0, 3.3f },
+ { 0, 1.2f, 3.3f }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(single_values); ++i) {
+ Vector2dF v(single_values[i][0], single_values[i][1]);
+ v.Scale(single_values[i][2]);
+ EXPECT_EQ(v.x(), single_values[i][0] * single_values[i][2]);
+ EXPECT_EQ(v.y(), single_values[i][1] * single_values[i][2]);
+
+ Vector2dF v2 = ScaleVector2d(
+ gfx::Vector2dF(double_values[i][0], double_values[i][1]),
+ double_values[i][2]);
+ EXPECT_EQ(single_values[i][0] * single_values[i][2], v2.x());
+ EXPECT_EQ(single_values[i][1] * single_values[i][2], v2.y());
+ }
+}
+
+TEST(Vector2dTest, Length) {
+ int int_values[][2] = {
+ { 0, 0 },
+ { 10, 20 },
+ { 20, 10 },
+ { -10, -20 },
+ { -20, 10 },
+ { 10, -20 },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_values); ++i) {
+ int v0 = int_values[i][0];
+ int v1 = int_values[i][1];
+ double length_squared =
+ static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
+ double length = std::sqrt(length_squared);
+ Vector2d vector(v0, v1);
+ EXPECT_EQ(static_cast<float>(length_squared), vector.LengthSquared());
+ EXPECT_EQ(static_cast<float>(length), vector.Length());
+ }
+
+ float float_values[][2] = {
+ { 0, 0 },
+ { 10.5f, 20.5f },
+ { 20.5f, 10.5f },
+ { -10.5f, -20.5f },
+ { -20.5f, 10.5f },
+ { 10.5f, -20.5f },
+ // A large vector that fails if the Length function doesn't use
+ // double precision internally.
+ { 1236278317862780234892374893213178027.12122348904204230f,
+ 335890352589839028212313231225425134332.38123f },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_values); ++i) {
+ double v0 = float_values[i][0];
+ double v1 = float_values[i][1];
+ double length_squared =
+ static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
+ double length = std::sqrt(length_squared);
+ Vector2dF vector(v0, v1);
+ EXPECT_DOUBLE_EQ(length_squared, vector.LengthSquared());
+ EXPECT_FLOAT_EQ(static_cast<float>(length), vector.Length());
+ }
+}
+
+TEST(Vector2dTest, ClampVector2d) {
+ Vector2d a;
+
+ a = Vector2d(3, 5);
+ EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ a.SetToMax(Vector2d(2, 4));
+ EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ a.SetToMax(Vector2d(3, 5));
+ EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ a.SetToMax(Vector2d(4, 2));
+ EXPECT_EQ(Vector2d(4, 5).ToString(), a.ToString());
+ a.SetToMax(Vector2d(8, 10));
+ EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+
+ a.SetToMin(Vector2d(9, 11));
+ EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+ a.SetToMin(Vector2d(8, 10));
+ EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+ a.SetToMin(Vector2d(11, 9));
+ EXPECT_EQ(Vector2d(8, 9).ToString(), a.ToString());
+ a.SetToMin(Vector2d(7, 11));
+ EXPECT_EQ(Vector2d(7, 9).ToString(), a.ToString());
+ a.SetToMin(Vector2d(3, 5));
+ EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+}
+
+TEST(Vector2dTest, ClampVector2dF) {
+ Vector2dF a;
+
+ a = Vector2dF(3.5f, 5.5f);
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(Vector2dF(2.5f, 4.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(Vector2dF(3.5f, 5.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(Vector2dF(4.5f, 2.5f));
+ EXPECT_EQ(Vector2dF(4.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(Vector2dF(8.5f, 10.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
+
+ a.SetToMin(Vector2dF(9.5f, 11.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(Vector2dF(8.5f, 10.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(Vector2dF(11.5f, 9.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(Vector2dF(7.5f, 11.5f));
+ EXPECT_EQ(Vector2dF(7.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(Vector2dF(3.5f, 5.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/vector3d_f.cc b/chromium/ui/gfx/geometry/vector3d_f.cc
new file mode 100644
index 00000000000..a30f9db5cbe
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector3d_f.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/vector3d_f.h"
+
+#include <cmath>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+Vector3dF::Vector3dF()
+ : x_(0),
+ y_(0),
+ z_(0) {
+}
+
+Vector3dF::Vector3dF(float x, float y, float z)
+ : x_(x),
+ y_(y),
+ z_(z) {
+}
+
+Vector3dF::Vector3dF(const Vector2dF& other)
+ : x_(other.x()),
+ y_(other.y()),
+ z_(0) {
+}
+
+std::string Vector3dF::ToString() const {
+ return base::StringPrintf("[%f %f %f]", x_, y_, z_);
+}
+
+bool Vector3dF::IsZero() const {
+ return x_ == 0 && y_ == 0 && z_ == 0;
+}
+
+void Vector3dF::Add(const Vector3dF& other) {
+ x_ += other.x_;
+ y_ += other.y_;
+ z_ += other.z_;
+}
+
+void Vector3dF::Subtract(const Vector3dF& other) {
+ x_ -= other.x_;
+ y_ -= other.y_;
+ z_ -= other.z_;
+}
+
+double Vector3dF::LengthSquared() const {
+ return static_cast<double>(x_) * x_ + static_cast<double>(y_) * y_ +
+ static_cast<double>(z_) * z_;
+}
+
+float Vector3dF::Length() const {
+ return static_cast<float>(std::sqrt(LengthSquared()));
+}
+
+void Vector3dF::Scale(float x_scale, float y_scale, float z_scale) {
+ x_ *= x_scale;
+ y_ *= y_scale;
+ z_ *= z_scale;
+}
+
+void Vector3dF::Cross(const Vector3dF& other) {
+ float x = y_ * other.z() - z_ * other.y();
+ float y = z_ * other.x() - x_ * other.z();
+ float z = x_ * other.y() - y_ * other.x();
+ x_ = x;
+ y_ = y;
+ z_ = z;
+}
+
+float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
+ return lhs.x() * rhs.x() + lhs.y() * rhs.y() + lhs.z() * rhs.z();
+}
+
+Vector3dF ScaleVector3d(const Vector3dF& v,
+ float x_scale,
+ float y_scale,
+ float z_scale) {
+ Vector3dF scaled_v(v);
+ scaled_v.Scale(x_scale, y_scale, z_scale);
+ return scaled_v;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/vector3d_f.h b/chromium/ui/gfx/geometry/vector3d_f.h
new file mode 100644
index 00000000000..8f8b75d91e7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector3d_f.h
@@ -0,0 +1,124 @@
+// 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.
+
+// Defines a simple float vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR3D_F_H_
+#define UI_GFX_GEOMETRY_VECTOR3D_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector3dF {
+ public:
+ Vector3dF();
+ Vector3dF(float x, float y, float z);
+
+ explicit Vector3dF(const Vector2dF& other);
+
+ float x() const { return x_; }
+ void set_x(float x) { x_ = x; }
+
+ float y() const { return y_; }
+ void set_y(float y) { y_ = y; }
+
+ float z() const { return z_; }
+ void set_z(float z) { z_ = z; }
+
+ // True if all components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector3dF& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector3dF& other);
+
+ void operator+=(const Vector3dF& other) { Add(other); }
+ void operator-=(const Vector3dF& other) { Subtract(other); }
+
+ void SetToMin(const Vector3dF& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ z_ = z_ <= other.z_ ? z_ : other.z_;
+ }
+
+ void SetToMax(const Vector3dF& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ z_ = z_ >= other.z_ ? z_ : other.z_;
+ }
+
+ // Gives the square of the diagonal length of the vector.
+ double LengthSquared() const;
+ // Gives the diagonal length of the vector.
+ float Length() const;
+
+ // Scale all components of the vector by |scale|.
+ void Scale(float scale) { Scale(scale, scale, scale); }
+ // Scale the each component of the vector by the given scale factors.
+ void Scale(float x_scale, float y_scale, float z_scale);
+
+ // Take the cross product of this vector with |other| and become the result.
+ void Cross(const Vector3dF& other);
+
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+ float z_;
+};
+
+inline bool operator==(const Vector3dF& lhs, const Vector3dF& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
+}
+
+inline Vector3dF operator-(const Vector3dF& v) {
+ return Vector3dF(-v.x(), -v.y(), -v.z());
+}
+
+inline Vector3dF operator+(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector3dF operator-(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+// Return the cross product of two vectors.
+inline Vector3dF CrossProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Cross(rhs);
+ return result;
+}
+
+// Return the dot product of two vectors.
+GFX_EXPORT float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs);
+
+// Return a vector that is |v| scaled by the given scale factors along each
+// axis.
+GFX_EXPORT Vector3dF ScaleVector3d(const Vector3dF& v,
+ float x_scale,
+ float y_scale,
+ float z_scale);
+
+// Return a vector that is |v| scaled by the given scale factor.
+inline Vector3dF ScaleVector3d(const Vector3dF& v, float scale) {
+ return ScaleVector3d(v, scale, scale, scale);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR3D_F_H_
diff --git a/chromium/ui/gfx/geometry/vector3d_unittest.cc b/chromium/ui/gfx/geometry/vector3d_unittest.cc
new file mode 100644
index 00000000000..d5ec8d6700c
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector3d_unittest.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+
+TEST(Vector3dTest, IsZero) {
+ gfx::Vector3dF float_zero(0, 0, 0);
+ gfx::Vector3dF float_nonzero(0.1f, -0.1f, 0.1f);
+
+ EXPECT_TRUE(float_zero.IsZero());
+ EXPECT_FALSE(float_nonzero.IsZero());
+}
+
+TEST(Vector3dTest, Add) {
+ gfx::Vector3dF f1(3.1f, 5.1f, 2.7f);
+ gfx::Vector3dF f2(4.3f, -1.3f, 8.1f);
+
+ const struct {
+ gfx::Vector3dF expected;
+ gfx::Vector3dF actual;
+ } float_tests[] = {
+ { gfx::Vector3dF(3.1F, 5.1F, 2.7f), f1 + gfx::Vector3dF() },
+ { gfx::Vector3dF(3.1f + 4.3f, 5.1f - 1.3f, 2.7f + 8.1f), f1 + f2 },
+ { gfx::Vector3dF(3.1f - 4.3f, 5.1f + 1.3f, 2.7f - 8.1f), f1 - f2 }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
+ EXPECT_EQ(float_tests[i].expected.ToString(),
+ float_tests[i].actual.ToString());
+}
+
+TEST(Vector3dTest, Negative) {
+ const struct {
+ gfx::Vector3dF expected;
+ gfx::Vector3dF actual;
+ } float_tests[] = {
+ { gfx::Vector3dF(-0.0f, -0.0f, -0.0f), -gfx::Vector3dF(0, 0, 0) },
+ { gfx::Vector3dF(-0.3f, -0.3f, -0.3f), -gfx::Vector3dF(0.3f, 0.3f, 0.3f) },
+ { gfx::Vector3dF(0.3f, 0.3f, 0.3f), -gfx::Vector3dF(-0.3f, -0.3f, -0.3f) },
+ { gfx::Vector3dF(-0.3f, 0.3f, -0.3f), -gfx::Vector3dF(0.3f, -0.3f, 0.3f) },
+ { gfx::Vector3dF(0.3f, -0.3f, -0.3f), -gfx::Vector3dF(-0.3f, 0.3f, 0.3f) },
+ { gfx::Vector3dF(-0.3f, -0.3f, 0.3f), -gfx::Vector3dF(0.3f, 0.3f, -0.3f) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
+ EXPECT_EQ(float_tests[i].expected.ToString(),
+ float_tests[i].actual.ToString());
+}
+
+TEST(Vector3dTest, Scale) {
+ float triple_values[][6] = {
+ { 4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f },
+ { 4.5f, -1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
+ { 4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
+ { 4.5f, -1.2f -1.8f, 3.3f, 5.6f, 4.2f },
+
+ { 4.5f, 1.2f, 1.8f, 3.3f, -5.6f, -4.2f },
+ { 4.5f, 1.2f, 1.8f, -3.3f, -5.6f, -4.2f },
+ { 4.5f, 1.2f, -1.8f, 3.3f, -5.6f, -4.2f },
+ { 4.5f, 1.2f, -1.8f, -3.3f, -5.6f, -4.2f },
+
+ { -4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f },
+ { -4.5f, 1.2f, 1.8f, 0, 5.6f, 4.2f },
+ { -4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
+ { -4.5f, 1.2f, -1.8f, 0, 5.6f, 4.2f },
+
+ { -4.5f, 1.2f, 1.8f, 3.3f, 0, 4.2f },
+ { 4.5f, 0, 1.8f, 3.3f, 5.6f, 4.2f },
+ { -4.5f, 1.2f, -1.8f, 3.3f, 0, 4.2f },
+ { 4.5f, 0, -1.8f, 3.3f, 5.6f, 4.2f },
+ { -4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 0 },
+ { -4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 0 },
+
+ { 0, 1.2f, 0, 3.3f, 5.6f, 4.2f },
+ { 0, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(triple_values); ++i) {
+ gfx::Vector3dF v(triple_values[i][0],
+ triple_values[i][1],
+ triple_values[i][2]);
+ v.Scale(triple_values[i][3], triple_values[i][4], triple_values[i][5]);
+ EXPECT_EQ(triple_values[i][0] * triple_values[i][3], v.x());
+ EXPECT_EQ(triple_values[i][1] * triple_values[i][4], v.y());
+ EXPECT_EQ(triple_values[i][2] * triple_values[i][5], v.z());
+
+ Vector3dF v2 = ScaleVector3d(
+ gfx::Vector3dF(triple_values[i][0],
+ triple_values[i][1],
+ triple_values[i][2]),
+ triple_values[i][3], triple_values[i][4], triple_values[i][5]);
+ EXPECT_EQ(triple_values[i][0] * triple_values[i][3], v2.x());
+ EXPECT_EQ(triple_values[i][1] * triple_values[i][4], v2.y());
+ EXPECT_EQ(triple_values[i][2] * triple_values[i][5], v2.z());
+ }
+
+ float single_values[][4] = {
+ { 4.5f, 1.2f, 1.8f, 3.3f },
+ { 4.5f, -1.2f, 1.8f, 3.3f },
+ { 4.5f, 1.2f, -1.8f, 3.3f },
+ { 4.5f, -1.2f, -1.8f, 3.3f },
+ { -4.5f, 1.2f, 3.3f },
+ { -4.5f, 1.2f, 0 },
+ { -4.5f, 1.2f, 1.8f, 3.3f },
+ { -4.5f, 1.2f, 1.8f, 0 },
+ { 4.5f, 0, 1.8f, 3.3f },
+ { 0, 1.2f, 1.8f, 3.3f },
+ { 4.5f, 0, 1.8f, 3.3f },
+ { 0, 1.2f, 1.8f, 3.3f },
+ { 4.5f, 1.2f, 0, 3.3f },
+ { 4.5f, 1.2f, 0, 3.3f }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(single_values); ++i) {
+ gfx::Vector3dF v(single_values[i][0],
+ single_values[i][1],
+ single_values[i][2]);
+ v.Scale(single_values[i][3]);
+ EXPECT_EQ(single_values[i][0] * single_values[i][3], v.x());
+ EXPECT_EQ(single_values[i][1] * single_values[i][3], v.y());
+ EXPECT_EQ(single_values[i][2] * single_values[i][3], v.z());
+
+ Vector3dF v2 = ScaleVector3d(
+ gfx::Vector3dF(single_values[i][0],
+ single_values[i][1],
+ single_values[i][2]),
+ single_values[i][3]);
+ EXPECT_EQ(single_values[i][0] * single_values[i][3], v2.x());
+ EXPECT_EQ(single_values[i][1] * single_values[i][3], v2.y());
+ EXPECT_EQ(single_values[i][2] * single_values[i][3], v2.z());
+ }
+}
+
+TEST(Vector3dTest, Length) {
+ float float_values[][3] = {
+ { 0, 0, 0 },
+ { 10.5f, 20.5f, 8.5f },
+ { 20.5f, 10.5f, 8.5f },
+ { 8.5f, 20.5f, 10.5f },
+ { 10.5f, 8.5f, 20.5f },
+ { -10.5f, -20.5f, -8.5f },
+ { -20.5f, 10.5f, -8.5f },
+ { -8.5f, -20.5f, -10.5f },
+ { -10.5f, -8.5f, -20.5f },
+ { 10.5f, -20.5f, 8.5f },
+ { -10.5f, 20.5f, 8.5f },
+ { 10.5f, -20.5f, -8.5f },
+ { -10.5f, 20.5f, -8.5f },
+ // A large vector that fails if the Length function doesn't use
+ // double precision internally.
+ { 1236278317862780234892374893213178027.12122348904204230f,
+ 335890352589839028212313231225425134332.38123f,
+ 27861786423846742743236423478236784678.236713617231f }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_values); ++i) {
+ double v0 = float_values[i][0];
+ double v1 = float_values[i][1];
+ double v2 = float_values[i][2];
+ double length_squared =
+ static_cast<double>(v0) * v0 +
+ static_cast<double>(v1) * v1 +
+ static_cast<double>(v2) * v2;
+ double length = std::sqrt(length_squared);
+ gfx::Vector3dF vector(v0, v1, v2);
+ EXPECT_DOUBLE_EQ(length_squared, vector.LengthSquared());
+ EXPECT_FLOAT_EQ(static_cast<float>(length), vector.Length());
+ }
+}
+
+TEST(Vector3dTest, DotProduct) {
+ const struct {
+ float expected;
+ gfx::Vector3dF input1;
+ gfx::Vector3dF input2;
+ } tests[] = {
+ { 0, gfx::Vector3dF(1, 0, 0), gfx::Vector3dF(0, 1, 1) },
+ { 0, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(1, 0, 1) },
+ { 0, gfx::Vector3dF(0, 0, 1), gfx::Vector3dF(1, 1, 0) },
+
+ { 3, gfx::Vector3dF(1, 1, 1), gfx::Vector3dF(1, 1, 1) },
+
+ { 1.2f, gfx::Vector3dF(1.2f, -1.2f, 1.2f), gfx::Vector3dF(1, 1, 1) },
+ { 1.2f, gfx::Vector3dF(1, 1, 1), gfx::Vector3dF(1.2f, -1.2f, 1.2f) },
+
+ { 38.72f,
+ gfx::Vector3dF(1.1f, 2.2f, 3.3f), gfx::Vector3dF(4.4f, 5.5f, 6.6f) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ float actual = gfx::DotProduct(tests[i].input1, tests[i].input2);
+ EXPECT_EQ(tests[i].expected, actual);
+ }
+}
+
+TEST(Vector3dTest, CrossProduct) {
+ const struct {
+ gfx::Vector3dF expected;
+ gfx::Vector3dF input1;
+ gfx::Vector3dF input2;
+ } tests[] = {
+ { Vector3dF(), Vector3dF(), Vector3dF(1, 1, 1) },
+ { Vector3dF(), Vector3dF(1, 1, 1), Vector3dF() },
+ { Vector3dF(), Vector3dF(1, 1, 1), Vector3dF(1, 1, 1) },
+ { Vector3dF(),
+ Vector3dF(1.6f, 10.6f, -10.6f),
+ Vector3dF(1.6f, 10.6f, -10.6f) },
+
+ { Vector3dF(1, -1, 0), Vector3dF(1, 1, 1), Vector3dF(0, 0, 1) },
+ { Vector3dF(-1, 0, 1), Vector3dF(1, 1, 1), Vector3dF(0, 1, 0) },
+ { Vector3dF(0, 1, -1), Vector3dF(1, 1, 1), Vector3dF(1, 0, 0) },
+
+ { Vector3dF(-1, 1, 0), Vector3dF(0, 0, 1), Vector3dF(1, 1, 1) },
+ { Vector3dF(1, 0, -1), Vector3dF(0, 1, 0), Vector3dF(1, 1, 1) },
+ { Vector3dF(0, -1, 1), Vector3dF(1, 0, 0), Vector3dF(1, 1, 1) }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ Vector3dF actual = gfx::CrossProduct(tests[i].input1, tests[i].input2);
+ EXPECT_EQ(tests[i].expected.ToString(), actual.ToString());
+ }
+}
+
+TEST(Vector3dFTest, ClampVector3dF) {
+ Vector3dF a;
+
+ a = Vector3dF(3.5f, 5.5f, 7.5f);
+ EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(2, 4.5f, 6.5f));
+ EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(3.5f, 5.5f, 7.5f));
+ EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(4.5f, 2, 6.5f));
+ EXPECT_EQ(Vector3dF(4.5f, 5.5f, 7.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(3.5f, 6.5f, 6.5f));
+ EXPECT_EQ(Vector3dF(4.5f, 6.5f, 7.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(3.5f, 5.5f, 8.5f));
+ EXPECT_EQ(Vector3dF(4.5f, 6.5f, 8.5f).ToString(), a.ToString());
+ a.SetToMax(Vector3dF(8.5f, 10.5f, 12.5f));
+ EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
+
+ a.SetToMin(Vector3dF(9.5f, 11.5f, 13.5f));
+ EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
+ a.SetToMin(Vector3dF(8.5f, 10.5f, 12.5f));
+ EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
+ a.SetToMin(Vector3dF(7.5f, 11.5f, 13.5f));
+ EXPECT_EQ(Vector3dF(7.5f, 10.5f, 12.5f).ToString(), a.ToString());
+ a.SetToMin(Vector3dF(9.5f, 9.5f, 13.5f));
+ EXPECT_EQ(Vector3dF(7.5f, 9.5f, 12.5f).ToString(), a.ToString());
+ a.SetToMin(Vector3dF(9.5f, 11.5f, 11.5f));
+ EXPECT_EQ(Vector3dF(7.5f, 9.5f, 11.5f).ToString(), a.ToString());
+ a.SetToMin(Vector3dF(3.5f, 5.5f, 7.5f));
+ EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/gfx.gyp b/chromium/ui/gfx/gfx.gyp
index 5fb17d52ee6..3077ac90c18 100644
--- a/chromium/ui/gfx/gfx.gyp
+++ b/chromium/ui/gfx/gfx.gyp
@@ -8,6 +8,67 @@
},
'targets': [
{
+ 'target_name': 'gfx_geometry',
+ 'type': '<(component)',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ ],
+ 'defines': [
+ 'GFX_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'geometry/box_f.cc',
+ 'geometry/box_f.h',
+ 'geometry/cubic_bezier.h',
+ 'geometry/cubic_bezier.cc',
+ 'geometry/insets.cc',
+ 'geometry/insets.h',
+ 'geometry/insets_base.h',
+ 'geometry/insets_f.cc',
+ 'geometry/insets_f.h',
+ 'geometry/matrix3_f.cc',
+ 'geometry/matrix3_f.h',
+ 'geometry/point.cc',
+ 'geometry/point.h',
+ 'geometry/point3_f.cc',
+ 'geometry/point3_f.h',
+ 'geometry/point_base.h',
+ 'geometry/point_conversions.cc',
+ 'geometry/point_conversions.h',
+ 'geometry/point_f.cc',
+ 'geometry/point_f.h',
+ 'geometry/quad_f.cc',
+ 'geometry/quad_f.h',
+ 'geometry/rect.cc',
+ 'geometry/rect.h',
+ 'geometry/rect_base.h',
+ 'geometry/rect_base_impl.h',
+ 'geometry/rect_conversions.cc',
+ 'geometry/rect_conversions.h',
+ 'geometry/rect_f.cc',
+ 'geometry/rect_f.h',
+ 'geometry/r_tree.h',
+ 'geometry/r_tree_base.cc',
+ 'geometry/r_tree_base.h',
+ 'geometry/safe_integer_conversions.h',
+ 'geometry/size.cc',
+ 'geometry/size.h',
+ 'geometry/size_base.h',
+ 'geometry/size_conversions.cc',
+ 'geometry/size_conversions.h',
+ 'geometry/size_f.cc',
+ 'geometry/size_f.h',
+ 'geometry/vector2d.cc',
+ 'geometry/vector2d.h',
+ 'geometry/vector2d_conversions.cc',
+ 'geometry/vector2d_conversions.h',
+ 'geometry/vector2d_f.cc',
+ 'geometry/vector2d_f.h',
+ 'geometry/vector3d_f.cc',
+ 'geometry/vector3d_f.h',
+ ],
+ },
+ {
'target_name': 'gfx',
'type': '<(component)',
'dependencies': [
@@ -15,13 +76,13 @@
'<(DEPTH)/base/base.gyp:base_i18n',
'<(DEPTH)/base/base.gyp:base_static',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/third_party/harfbuzz-ng/harfbuzz.gyp:harfbuzz-ng',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
'<(DEPTH)/third_party/libpng/libpng.gyp:libpng',
'<(DEPTH)/third_party/zlib/zlib.gyp:zlib',
- '<(DEPTH)/url/url.gyp:url_lib',
+ 'gfx_geometry',
],
# text_elider.h includes ICU headers.
'export_dependent_settings': [
@@ -32,6 +93,9 @@
'defines': [
'GFX_IMPLEMENTATION',
],
+ 'include_dirs': [
+ '<(DEPTH)/third_party/icu/source/common'
+ ],
'sources': [
'android/device_display_info.cc',
'android/device_display_info.h',
@@ -39,6 +103,8 @@
'android/gfx_jni_registrar.h',
'android/java_bitmap.cc',
'android/java_bitmap.h',
+ 'android/scroller.cc',
+ 'android/scroller.h',
'android/shared_device_display_info.cc',
'android/shared_device_display_info.h',
'android/view_configuration.cc',
@@ -62,14 +128,10 @@
'animation/tween.h',
'blit.cc',
'blit.h',
- 'box_f.cc',
- 'box_f.h',
'break_list.h',
'canvas.cc',
'canvas.h',
'canvas_android.cc',
- 'canvas_paint_gtk.cc',
- 'canvas_paint_gtk.h',
'canvas_paint_mac.h',
'canvas_paint_mac.mm',
'canvas_paint_win.cc',
@@ -84,7 +146,7 @@
'color_analysis.h',
'color_profile.cc',
'color_profile.h',
- 'color_profile_mac.cc',
+ 'color_profile_mac.mm',
'color_profile_win.cc',
'color_utils.cc',
'color_utils.h',
@@ -94,18 +156,20 @@
'display_observer.h',
'favicon_size.cc',
'favicon_size.h',
- 'frame_time.h',
'font.cc',
'font.h',
'font_fallback_win.cc',
'font_fallback_win.h',
'font_list.cc',
'font_list.h',
+ 'font_list_impl.cc',
+ 'font_list_impl.h',
'font_render_params_android.cc',
'font_render_params_linux.cc',
'font_render_params_linux.h',
'font_smoothing_win.cc',
'font_smoothing_win.h',
+ 'frame_time.h',
'gfx_export.h',
'gfx_paths.cc',
'gfx_paths.h',
@@ -135,39 +199,20 @@
'image/image_util.cc',
'image/image_util.h',
'image/image_util_ios.mm',
- 'insets.cc',
- 'insets.h',
- 'insets_base.h',
- 'insets_f.cc',
- 'insets_f.h',
'interpolated_transform.cc',
'interpolated_transform.h',
+ 'linux_font_delegate.cc',
+ 'linux_font_delegate.h',
'mac/scoped_ns_disable_screen_updates.h',
- 'matrix3_f.cc',
- 'matrix3_f.h',
'native_widget_types.h',
- 'ozone/dri/dri_skbitmap.cc',
- 'ozone/dri/dri_skbitmap.h',
- 'ozone/dri/dri_surface.cc',
- 'ozone/dri/dri_surface.h',
- 'ozone/dri/dri_surface_factory.cc',
- 'ozone/dri/dri_surface_factory.h',
- 'ozone/dri/dri_vsync_provider.cc',
- 'ozone/dri/dri_vsync_provider.h',
- 'ozone/dri/dri_wrapper.cc',
- 'ozone/dri/dri_wrapper.h',
- 'ozone/dri/hardware_display_controller.cc',
- 'ozone/dri/hardware_display_controller.h',
- 'ozone/impl/file_surface_factory.cc',
- 'ozone/impl/file_surface_factory.h',
- 'ozone/surface_factory_ozone.cc',
- 'ozone/surface_factory_ozone.h',
+ 'nine_image_painter.cc',
+ 'nine_image_painter.h',
+ 'overlay_transform.h',
'pango_util.cc',
'pango_util.h',
'path.cc',
'path.h',
'path_aura.cc',
- 'path_gtk.cc',
'path_win.cc',
'path_win.h',
'path_x11.cc',
@@ -183,31 +228,14 @@
'platform_font_pango.h',
'platform_font_win.cc',
'platform_font_win.h',
- 'point.cc',
- 'point.h',
- 'point3_f.cc',
- 'point3_f.h',
- 'point_base.h',
- 'point_conversions.cc',
- 'point_conversions.h',
- 'point_f.cc',
- 'point_f.h',
- 'quad_f.cc',
- 'quad_f.h',
'range/range.cc',
'range/range.h',
'range/range_mac.mm',
'range/range_win.cc',
- 'rect.cc',
- 'rect.h',
- 'rect_base.h',
- 'rect_base_impl.h',
- 'rect_conversions.cc',
- 'rect_conversions.h',
- 'rect_f.cc',
- 'rect_f.h',
'render_text.cc',
'render_text.h',
+ 'render_text_harfbuzz.cc',
+ 'render_text_harfbuzz.h',
'render_text_mac.cc',
'render_text_mac.h',
'render_text_ozone.cc',
@@ -215,7 +243,6 @@
'render_text_pango.h',
'render_text_win.cc',
'render_text_win.h',
- 'safe_integer_conversions.h',
'scoped_canvas.h',
'scoped_cg_context_save_gstate_mac.h',
'scoped_ns_graphics_context_save_gstate_mac.h',
@@ -226,7 +253,6 @@
'screen.h',
'screen_android.cc',
'screen_aura.cc',
- 'screen_gtk.cc',
'screen_ios.mm',
'screen_mac.mm',
'screen_win.cc',
@@ -239,19 +265,10 @@
'sequential_id_generator.h',
'shadow_value.cc',
'shadow_value.h',
- 'size.cc',
- 'size.h',
- 'size_base.h',
- 'size_conversions.cc',
- 'size_conversions.h',
- 'size_f.cc',
- 'size_f.h',
'skbitmap_operations.cc',
'skbitmap_operations.h',
'skia_util.cc',
'skia_util.h',
- 'skia_utils_gtk.cc',
- 'skia_utils_gtk.h',
'switches.cc',
'switches.h',
'sys_color_change_listener.cc',
@@ -271,14 +288,6 @@
'ui_gfx_exports.cc',
'utf16_indexing.cc',
'utf16_indexing.h',
- 'vector2d.cc',
- 'vector2d.h',
- 'vector2d_conversions.cc',
- 'vector2d_conversions.h',
- 'vector2d_f.cc',
- 'vector2d_f.h',
- 'vector3d_f.cc',
- 'vector3d_f.h',
'vsync_provider.h',
'win/dpi.cc',
'win/dpi.h',
@@ -289,10 +298,6 @@
'win/singleton_hwnd.h',
'win/window_impl.cc',
'win/window_impl.h',
- 'x/x11_atom_cache.cc',
- 'x/x11_atom_cache.h',
- 'x/x11_types.cc',
- 'x/x11_types.h',
],
'conditions': [
['OS=="ios"', {
@@ -316,24 +321,6 @@
'canvas_skia.cc',
],
}],
- ['toolkit_uses_gtk == 1', {
- 'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:gtk',
- ],
- 'sources': [
- 'gtk_native_view_id_manager.cc',
- 'gtk_native_view_id_manager.h',
- 'gtk_preserve_window.cc',
- 'gtk_preserve_window.h',
- 'gdk_compat.h',
- 'gtk_compat.h',
- 'gtk_util.cc',
- 'gtk_util.h',
- 'image/cairo_cached_surface.cc',
- 'image/cairo_cached_surface.h',
- 'scoped_gobject.h',
- ],
- }],
['OS=="win"', {
'sources': [
'gdi_util.cc',
@@ -350,7 +337,6 @@
'sources!': [
'animation/throb_animation.cc',
'display_observer.cc',
- 'path.cc',
'selection_model.cc',
],
'dependencies': [
@@ -363,6 +349,22 @@
],
},
}],
+ ['use_aura==0 and toolkit_views==0', {
+ 'sources!': [
+ 'nine_image_painter.cc',
+ 'nine_image_painter.h',
+ ],
+ }],
+ ['OS=="android" and use_aura==0', {
+ 'sources!': [
+ 'path.cc',
+ ],
+ }],
+ ['OS=="android" and use_aura==1', {
+ 'sources!': [
+ 'screen_android.cc',
+ ],
+ }],
['OS=="android" and android_webview_build==0', {
'dependencies': [
'<(DEPTH)/base/base.gyp:base_java',
@@ -372,9 +374,17 @@
'sources!': [
'render_text.cc',
'render_text.h',
+ 'render_text_harfbuzz.cc',
+ 'render_text_harfbuzz.h',
'text_utils_skia.cc',
],
}],
+ ['use_x11==1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ 'x/gfx_x11.gyp:gfx_x11',
+ ],
+ }],
['use_pango==1', {
'dependencies': [
'<(DEPTH)/build/linux/system.gyp:pangocairo',
@@ -384,9 +394,10 @@
'render_text_ozone.cc',
],
}],
- ['ozone_platform_dri==1', {
+ ['desktop_linux==1 or chromeos==1', {
'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:dridrm',
+ # font_render_params_linux.cc uses fontconfig
+ '<(DEPTH)/build/linux/system.gyp:fontconfig',
],
}],
],
@@ -399,38 +410,58 @@
],
}],
],
- }
+ },
+ {
+ 'target_name': 'gfx_test_support',
+ 'sources': [
+ 'test/gfx_util.cc',
+ 'test/gfx_util.h',
+ 'test/ui_cocoa_test_helper.h',
+ 'test/ui_cocoa_test_helper.mm',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ ],
+ 'conditions': [
+ ['OS == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+ ],
+ },
+ }],
+ ['OS!="ios"', {
+ 'type': 'static_library',
+ }, { # OS=="ios"
+ # None of the sources in this target are built on iOS, resulting in
+ # link errors when building targets that depend on this target
+ # because the static library isn't found. If this target is changed
+ # to have sources that are built on iOS, the target should be changed
+ # to be of type static_library on all platforms.
+ 'type': 'none',
+ # The cocoa files don't apply to iOS.
+ 'sources/': [
+ ['exclude', 'cocoa']
+ ],
+ }],
+ ],
+ },
],
'conditions': [
['OS=="android"' , {
'targets': [
{
- 'target_name': 'gfx_view_jni_headers',
- 'type': 'none',
- 'variables': {
- 'jni_gen_package': 'ui/gfx',
- 'input_java_class': 'android/view/ViewConfiguration.class',
- },
- 'includes': [ '../../build/jar_file_jni_generator.gypi' ],
- },
- {
'target_name': 'gfx_jni_headers',
'type': 'none',
- 'dependencies': [
- 'gfx_view_jni_headers'
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/ui/gfx',
- ],
- },
'sources': [
'../android/java/src/org/chromium/ui/gfx/BitmapHelper.java',
'../android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java',
+ '../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java',
],
'variables': {
'jni_gen_package': 'ui/gfx',
- 'jni_generator_ptr_type': 'long'
},
'includes': [ '../../build/jni_generator.gypi' ],
},
diff --git a/chromium/ui/gfx/gfx_tests.gyp b/chromium/ui/gfx/gfx_tests.gyp
new file mode 100644
index 00000000000..dda6d142ef3
--- /dev/null
+++ b/chromium/ui/gfx/gfx_tests.gyp
@@ -0,0 +1,146 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'gfx_unittests',
+ 'type': '<(gtest_target_type)',
+ # iOS uses a small subset of ui. common_sources are the only files that
+ # are built on iOS.
+ 'common_sources' : [
+ 'font_unittest.cc',
+ 'image/image_family_unittest.cc',
+ 'image/image_skia_unittest.cc',
+ 'image/image_unittest.cc',
+ 'image/image_unittest_util.cc',
+ 'image/image_unittest_util.h',
+ 'image/image_unittest_util_ios.mm',
+ 'image/image_unittest_util_mac.mm',
+ 'test/run_all_unittests.cc',
+ 'text_elider_unittest.cc',
+ 'text_utils_unittest.cc',
+ ],
+ 'all_sources': [
+ '<@(_common_sources)',
+ 'animation/animation_container_unittest.cc',
+ 'animation/animation_unittest.cc',
+ 'animation/multi_animation_unittest.cc',
+ 'animation/slide_animation_unittest.cc',
+ 'animation/tween_unittest.cc',
+ 'blit_unittest.cc',
+ 'break_list_unittest.cc',
+ 'canvas_unittest.cc',
+ 'codec/jpeg_codec_unittest.cc',
+ 'codec/png_codec_unittest.cc',
+ 'color_analysis_unittest.cc',
+ 'color_utils_unittest.cc',
+ 'display_unittest.cc',
+ 'font_list_unittest.cc',
+ 'geometry/box_unittest.cc',
+ 'geometry/cubic_bezier_unittest.cc',
+ 'geometry/insets_unittest.cc',
+ 'geometry/matrix3_unittest.cc',
+ 'geometry/point_unittest.cc',
+ 'geometry/point3_unittest.cc',
+ 'geometry/quad_unittest.cc',
+ 'geometry/r_tree_unittest.cc',
+ 'geometry/rect_unittest.cc',
+ 'geometry/safe_integer_conversions_unittest.cc',
+ 'geometry/size_unittest.cc',
+ 'geometry/vector2d_unittest.cc',
+ 'geometry/vector3d_unittest.cc',
+ 'image/image_mac_unittest.mm',
+ 'image/image_util_unittest.cc',
+ 'range/range_mac_unittest.mm',
+ 'range/range_unittest.cc',
+ 'range/range_win_unittest.cc',
+ 'sequential_id_generator_unittest.cc',
+ 'shadow_value_unittest.cc',
+ 'skbitmap_operations_unittest.cc',
+ 'skrect_conversion_unittest.cc',
+ 'transform_util_unittest.cc',
+ 'utf16_indexing_unittest.cc',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ '../../third_party/libpng/libpng.gyp:libpng',
+ '../base/ui_base.gyp:ui_base',
+ 'gfx.gyp:gfx',
+ 'gfx.gyp:gfx_geometry',
+ 'gfx.gyp:gfx_test_support',
+ ],
+ 'conditions': [
+ ['OS == "ios"', {
+ 'sources': ['<@(_common_sources)'],
+ }, { # OS != "ios"
+ 'sources': ['<@(_all_sources)'],
+ }],
+ ['OS == "win"', {
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ }],
+ ['OS != "mac" and OS != "ios"', {
+ 'sources': [
+ 'transform_unittest.cc',
+ 'interpolated_transform_unittest.cc',
+ ],
+ }],
+ ['use_pango == 1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:fontconfig',
+ '../../build/linux/system.gyp:pangocairo',
+ ],
+ 'sources': [
+ 'platform_font_pango_unittest.cc',
+ ],
+ 'conditions': [
+ ['use_allocator!="none"', {
+ 'dependencies': [
+ '../../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ }],
+ ['use_ozone==1 and use_pango==0', {
+ 'sources!': [
+ 'canvas_unittest.cc',
+ 'font_list_unittest.cc',
+ 'font_unittest.cc',
+ 'text_elider_unittest.cc',
+ ],
+ }],
+ ['OS == "android"', {
+ 'dependencies': [
+ '../../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ }
+ ],
+ 'conditions': [
+ ['OS == "android"', {
+ 'targets': [
+ {
+ 'target_name': 'gfx_unittests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ '../android/ui_android.gyp:ui_java',
+ 'gfx_unittests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'gfx_unittests',
+ },
+ 'includes': [ '../../build/apk_test.gypi' ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/ui/gfx/gpu_memory_buffer.cc b/chromium/ui/gfx/gpu_memory_buffer.cc
index c1de26c374b..057e8c7575a 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.cc
+++ b/chromium/ui/gfx/gpu_memory_buffer.cc
@@ -6,6 +6,20 @@
namespace gfx {
+GpuMemoryBufferHandle::GpuMemoryBufferHandle()
+ : type(EMPTY_BUFFER),
+ handle(base::SharedMemory::NULLHandle())
+#if defined(OS_MACOSX)
+ ,
+ io_surface_id(0u)
+#endif
+#if defined(OS_ANDROID)
+ ,
+ native_buffer(NULL)
+#endif
+{
+}
+
GpuMemoryBuffer::GpuMemoryBuffer() {}
GpuMemoryBuffer::~GpuMemoryBuffer() {}
diff --git a/chromium/ui/gfx/gpu_memory_buffer.h b/chromium/ui/gfx/gpu_memory_buffer.h
index 4a7b142d175..1a622016c7c 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.h
+++ b/chromium/ui/gfx/gpu_memory_buffer.h
@@ -18,61 +18,63 @@ namespace gfx {
enum GpuMemoryBufferType {
EMPTY_BUFFER,
SHARED_MEMORY_BUFFER,
- EGL_CLIENT_BUFFER,
- IO_SURFACE_BUFFER
+ IO_SURFACE_BUFFER,
+ ANDROID_NATIVE_BUFFER,
+ SURFACE_TEXTURE_BUFFER,
+ GPU_MEMORY_BUFFER_TYPE_LAST = SURFACE_TEXTURE_BUFFER
};
-struct GpuMemoryBufferHandle {
- GpuMemoryBufferHandle()
- : type(EMPTY_BUFFER),
- handle(base::SharedMemory::NULLHandle())
+// TODO(alexst): Merge this with GpuMemoryBufferId as part of switchover to
+// the new API for GpuMemoryBuffer allocation when it's done.
#if defined(OS_ANDROID)
- , native_buffer(NULL)
-#endif
-#if defined(OS_MACOSX)
- , io_surface_id(0)
+struct SurfaceTextureId {
+ SurfaceTextureId() : primary_id(0), secondary_id(0) {}
+ SurfaceTextureId(int32 primary_id, int32 secondary_id)
+ : primary_id(primary_id), secondary_id(secondary_id) {}
+ int32 primary_id;
+ int32 secondary_id;
+};
#endif
- {
- }
+
+struct GpuMemoryBufferId {
+ GpuMemoryBufferId() : primary_id(0), secondary_id(0) {}
+ GpuMemoryBufferId(int32 primary_id, int32 secondary_id)
+ : primary_id(primary_id), secondary_id(secondary_id) {}
+ int32 primary_id;
+ int32 secondary_id;
+};
+
+struct GFX_EXPORT GpuMemoryBufferHandle {
+ GpuMemoryBufferHandle();
bool is_null() const { return type == EMPTY_BUFFER; }
GpuMemoryBufferType type;
base::SharedMemoryHandle handle;
-#if defined(OS_ANDROID)
- EGLClientBuffer native_buffer;
-#endif
+ GpuMemoryBufferId global_id;
#if defined(OS_MACOSX)
uint32 io_surface_id;
#endif
-
+#if defined(OS_ANDROID)
+ EGLClientBuffer native_buffer;
+ SurfaceTextureId surface_texture_id;
+#endif
};
-// Interface for creating and accessing a zero-copy GPU memory buffer.
-// This design evolved from the generalization of GraphicBuffer API
-// of Android framework.
-//
-// THREADING CONSIDERATIONS:
-//
-// This interface is thread-safe. However, multiple threads mapping
-// a buffer for Write or ReadOrWrite simultaneously may result in undefined
-// behavior and is not allowed.
+// This interface typically correspond to a type of shared memory that is also
+// shared with the GPU. A GPU memory buffer can be written to directly by
+// regular CPU code, but can also be read by the GPU.
class GFX_EXPORT GpuMemoryBuffer {
public:
- enum AccessMode {
- READ_ONLY,
- WRITE_ONLY,
- READ_WRITE,
- };
-
GpuMemoryBuffer();
virtual ~GpuMemoryBuffer();
- // Maps the buffer so the client can write the bitmap data in |*vaddr|
- // subsequently. This call may block, for instance if the hardware needs
- // to finish rendering or if CPU caches need to be synchronized.
- virtual void Map(AccessMode mode, void** vaddr) = 0;
+ // Maps the buffer into the client's address space so it can be written to by
+ // the CPU. This call may block, for instance if the GPU needs to finish
+ // accessing the buffer or if CPU caches need to be synchronized. Returns NULL
+ // on failure.
+ virtual void* Map() = 0;
- // Unmaps the buffer. Called after all changes to the buffer are
- // completed.
+ // Unmaps the buffer. It's illegal to use the pointer returned by Map() after
+ // this has been called.
virtual void Unmap() = 0;
// Returns true iff the buffer is mapped.
diff --git a/chromium/ui/gfx/gtk_compat.h b/chromium/ui/gfx/gtk_compat.h
deleted file mode 100644
index ca14a27627a..00000000000
--- a/chromium/ui/gfx/gtk_compat.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GTK_COMPAT_H_
-#define UI_GFX_GTK_COMPAT_H_
-
-#include <gtk/gtk.h>
-
-// Google Chrome must depend on GTK 2.18, at least until the next LTS drops
-// (and we might have to extend which version of GTK we want to target due to
-// RHEL). To make our porting job for GTK3 easier, we define all the methods
-// that replace deprecated APIs in this file and then include it everywhere.
-//
-// This file is organized first by version, and then with each version,
-// alphabetically by method.
-//
-// For Google Chrome builds, we want to support RHEL 6, which uses GTK 2.18,
-// but the official builder is Ubuntu Lucid with GTK 2.20. Thus for Google
-// Chrome builds, we define the GTK 2.20.0 compatibility functions even though
-// the system GTK provides the functions.
-
-#if !GTK_CHECK_VERSION(2, 20, 0) || defined(GOOGLE_CHROME_BUILD)
-inline gboolean gtk_widget_get_mapped(GtkWidget* widget) {
- return GTK_WIDGET_MAPPED(widget);
-}
-
-inline gboolean gtk_widget_get_realized(GtkWidget* widget) {
- return GTK_WIDGET_REALIZED(widget);
-}
-
-inline gboolean gtk_widget_is_toplevel(GtkWidget* widget) {
- return GTK_WIDGET_TOPLEVEL(widget);
-}
-
-inline void gtk_widget_set_mapped(GtkWidget* widget,
- gboolean mapped) {
- if (mapped)
- GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED);
- else
- GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED);
-}
-
-inline void gtk_widget_set_realized(GtkWidget* widget,
- gboolean realized) {
- if (realized)
- GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
- else
- GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
-}
-
-inline void gtk_widget_style_attach(GtkWidget* widget) {
- widget->style = gtk_style_attach(widget->style, widget->window);
-}
-#endif // !GTK_CHECK_VERSION(2, 20, 0) || defined(GOOGLE_CHROME_BUILD)
-
-#if !GTK_CHECK_VERSION(2, 22, 0)
-inline GdkWindow* gdk_drag_context_get_source_window(GdkDragContext *context) {
- return context->source_window;
-}
-
-inline gint gdk_visual_get_depth(GdkVisual* visual) {
- return visual->depth;
-}
-
-inline GdkWindow* gtk_button_get_event_window(GtkButton* button) {
- return button->event_window;
-}
-#endif // !GTK_CHECK_VERSION(2, 22, 0)
-
-#if !GTK_CHECK_VERSION(2, 24, 0)
-inline void gdk_pixmap_get_size(GdkPixmap* pixmap, gint* width, gint* height) {
- gdk_drawable_get_size(GDK_DRAWABLE(pixmap), width, height);
-}
-
-inline GdkDisplay* gdk_window_get_display(GdkWindow* window) {
- return gdk_drawable_get_display(GDK_DRAWABLE(window));
-}
-
-inline int gdk_window_get_height(GdkWindow* window) {
- int height;
- gdk_drawable_get_size(GDK_DRAWABLE(window), NULL, &height);
- return height;
-}
-
-inline GdkScreen* gdk_window_get_screen(GdkWindow* window) {
- return gdk_drawable_get_screen(GDK_DRAWABLE(window));
-}
-
-inline int gdk_window_get_width(GdkWindow* window) {
- int width;
- gdk_drawable_get_size(GDK_DRAWABLE(window), &width, NULL);
- return width;
-}
-#endif // !GTK_CHECK_VERSION(2, 24, 0)
-
-#endif // UI_GFX_GTK_COMPAT_H_
diff --git a/chromium/ui/gfx/gtk_native_view_id_manager.cc b/chromium/ui/gfx/gtk_native_view_id_manager.cc
deleted file mode 100644
index 0844b190dd9..00000000000
--- a/chromium/ui/gfx/gtk_native_view_id_manager.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/gtk_native_view_id_manager.h"
-
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/rand_util.h"
-#include "ui/gfx/gdk_compat.h"
-#include "ui/gfx/gtk_compat.h"
-#include "ui/gfx/gtk_preserve_window.h"
-
-// -----------------------------------------------------------------------------
-// Bounce functions for GTK to callback into a C++ object...
-
-void OnRealize(gfx::NativeView widget, void* arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnRealize(widget);
-}
-
-void OnUnrealize(gfx::NativeView widget, void *arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnUnrealize(widget);
-}
-
-static void OnDestroy(GtkObject* obj, void* arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj));
-}
-
-// -----------------------------------------------------------------------------
-
-
-// -----------------------------------------------------------------------------
-// Public functions...
-
-GtkNativeViewManager::GtkNativeViewManager() {
-}
-
-GtkNativeViewManager::~GtkNativeViewManager() {
-}
-
-// static
-GtkNativeViewManager* GtkNativeViewManager::GetInstance() {
- return Singleton<GtkNativeViewManager>::get();
-}
-
-gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) {
- // This is just for unit tests:
- if (!widget)
- return 0;
-
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
- native_view_to_id_.find(widget);
-
- if (i != native_view_to_id_.end())
- return i->second;
-
- gfx::NativeViewId new_id =
- static_cast<gfx::NativeViewId>(base::RandUint64());
- while (id_to_info_.find(new_id) != id_to_info_.end())
- new_id = static_cast<gfx::NativeViewId>(base::RandUint64());
-
- NativeViewInfo info;
- info.widget = widget;
- if (gtk_widget_get_realized(widget)) {
- GdkWindow *gdk_window = gtk_widget_get_window(widget);
- DCHECK(gdk_window);
- info.x_window_id = GDK_WINDOW_XID(gdk_window);
- }
-
- native_view_to_id_[widget] = new_id;
- id_to_info_[new_id] = info;
-
- g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this);
- g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this);
- g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this);
-
- return new_id;
-}
-
-bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- *output = i->second.x_window_id;
- return true;
-}
-
-bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView* output,
- gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- *output = i->second.widget;
- return true;
-}
-
-bool GtkNativeViewManager::GetPermanentXIDForId(XID* output,
- gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- // We only return permanent XIDs for widgets that allow us to guarantee that
- // the XID will not change.
- DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget));
- GtkPreserveWindow* widget =
- reinterpret_cast<GtkPreserveWindow*>(i->second.widget);
- gtk_preserve_window_set_preserve(widget, TRUE);
-
- *output = GDK_WINDOW_XID(gtk_widget_get_window(i->second.widget));
-
- // Update the reference count on the permanent XID.
- PermanentXIDInfo info;
- info.widget = widget;
- info.ref_count = 1;
- std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret =
- perm_xid_to_info_.insert(std::make_pair(*output, info));
-
- if (!ret.second) {
- DCHECK(ret.first->second.widget == widget);
- ret.first->second.ref_count++;
- }
-
- return true;
-}
-
-bool GtkNativeViewManager::AddRefPermanentXID(XID xid) {
- base::AutoLock locked(lock_);
-
- std::map<XID, PermanentXIDInfo>::iterator i =
- perm_xid_to_info_.find(xid);
-
- if (i == perm_xid_to_info_.end())
- return false;
-
- i->second.ref_count++;
-
- return true;
-}
-
-void GtkNativeViewManager::ReleasePermanentXID(XID xid) {
- base::AutoLock locked(lock_);
-
- std::map<XID, PermanentXIDInfo>::iterator i =
- perm_xid_to_info_.find(xid);
-
- if (i == perm_xid_to_info_.end())
- return;
-
- if (i->second.ref_count > 1) {
- i->second.ref_count--;
- } else {
- if (i->second.widget) {
- gtk_preserve_window_set_preserve(i->second.widget, FALSE);
- } else {
- GdkWindow* window = reinterpret_cast<GdkWindow*>(
- gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid));
- DCHECK(window);
- gdk_window_destroy(window);
- }
- perm_xid_to_info_.erase(i);
- }
-}
-
-// -----------------------------------------------------------------------------
-
-
-// -----------------------------------------------------------------------------
-// Private functions...
-
-gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) {
- lock_.AssertAcquired();
-
- std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
- native_view_to_id_.find(widget);
-
- CHECK(i != native_view_to_id_.end());
- return i->second;
-}
-
-void GtkNativeViewManager::OnRealize(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- const gfx::NativeViewId id = GetWidgetId(widget);
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- CHECK(i != id_to_info_.end());
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- CHECK(gdk_window);
- i->second.x_window_id = GDK_WINDOW_XID(gdk_window);
-}
-
-void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- const gfx::NativeViewId id = GetWidgetId(widget);
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- CHECK(i != id_to_info_.end());
-}
-
-void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeView, gfx::NativeViewId>::iterator i =
- native_view_to_id_.find(widget);
- CHECK(i != native_view_to_id_.end());
-
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator j =
- id_to_info_.find(i->second);
- CHECK(j != id_to_info_.end());
-
- // If the XID is supposed to outlive the widget, mark it
- // in the lookup table.
- if (GTK_IS_PRESERVE_WINDOW(widget) &&
- gtk_preserve_window_get_preserve(
- reinterpret_cast<GtkPreserveWindow*>(widget))) {
- std::map<XID, PermanentXIDInfo>::iterator k =
- perm_xid_to_info_.find(GDK_WINDOW_XID(gtk_widget_get_window(widget)));
-
- if (k != perm_xid_to_info_.end())
- k->second.widget = NULL;
- }
-
- native_view_to_id_.erase(i);
- id_to_info_.erase(j);
-}
-
-// -----------------------------------------------------------------------------
diff --git a/chromium/ui/gfx/gtk_native_view_id_manager.h b/chromium/ui/gfx/gtk_native_view_id_manager.h
deleted file mode 100644
index 44219209273..00000000000
--- a/chromium/ui/gfx/gtk_native_view_id_manager.h
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
-#define UI_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
-
-#include <map>
-
-#include "base/synchronization/lock.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-typedef unsigned long XID;
-struct _GtkPreserveWindow;
-
-// NativeViewIds are the opaque values which the renderer holds as a reference
-// to a window.
-//
-// We could make NativeViewIds be the X id of the window. However, at the
-// time when we need to tell the renderer about its NativeViewId, an XID isn't
-// availible and it goes very much against the grain of the code to make it so.
-// Also, we worry that GTK might choose to change the underlying X window id
-// when, say, the widget is hidden or repacked. Finally, if we used XIDs then a
-// compromised renderer could start asking questions about any X windows on the
-// system.
-//
-// Thus, we have this object. It produces random NativeViewIds from GtkWidget
-// pointers and observes the various signals from the widget for when an X
-// window is created, destroyed etc. Thus it provides a thread safe mapping
-// from NativeViewIds to the current XID for that widget.
-class GFX_EXPORT GtkNativeViewManager {
- public:
- // Returns the singleton instance.
- static GtkNativeViewManager* GetInstance();
-
- // Must be called from the UI thread:
- //
- // Return a NativeViewId for the given widget and attach to the various
- // signals emitted by that widget. The NativeViewId is pseudo-randomly
- // allocated so that a compromised renderer trying to guess values will fail
- // with high probability. The NativeViewId will not be reused for the
- // lifetime of the GtkWidget.
- gfx::NativeViewId GetIdForWidget(gfx::NativeView widget);
-
- // May be called from any thread:
- //
- // xid: (output) the resulting X window ID, or 0
- // id: a value previously returned from GetIdForWidget
- // returns: true if |id| is a valid id, false otherwise.
- //
- // If the widget referenced by |id| does not current have an X window id,
- // |*xid| is set to 0.
- bool GetXIDForId(XID* xid, gfx::NativeViewId id);
-
- // May be called from the UI thread:
- //
- // Same as GetXIDForId except it returns the NativeView (GtkWidget*).
- bool GetNativeViewForId(gfx::NativeView* xid, gfx::NativeViewId id);
-
- // Must be called from the UI thread because we may need the associated
- // widget to create a window.
- //
- // Keeping the XID permanent requires a bit of overhead, so it must
- // be explicitly requested.
- //
- // xid: (output) the resulting X window
- // id: a value previously returned from GetIdForWidget
- // returns: true if |id| is a valid id, false otherwise.
- bool GetPermanentXIDForId(XID* xid, gfx::NativeViewId id);
-
- // Can be called from any thread.
- // Will return false if the given XID isn't permanent or has already been
- // released.
- bool AddRefPermanentXID(XID xid);
-
- // Must be called from the UI thread because we may need to access a
- // GtkWidget or destroy a GdkWindow.
- //
- // If the widget associated with the XID is still alive, allow the widget
- // to destroy the associated XID when it wants. Otherwise, destroy the
- // GdkWindow associated with the XID.
- void ReleasePermanentXID(XID xid);
-
- // These are actually private functions, but need to be called from statics.
- void OnRealize(gfx::NativeView widget);
- void OnUnrealize(gfx::NativeView widget);
- void OnDestroy(gfx::NativeView widget);
-
- private:
- // This object is a singleton:
- GtkNativeViewManager();
- ~GtkNativeViewManager();
- friend struct DefaultSingletonTraits<GtkNativeViewManager>;
-
- struct NativeViewInfo {
- NativeViewInfo() : widget(NULL), x_window_id(0) {
- }
- gfx::NativeView widget;
- XID x_window_id;
- };
-
- gfx::NativeViewId GetWidgetId(gfx::NativeView id);
-
- // protects native_view_to_id_ and id_to_info_
- base::Lock lock_;
-
- // If asked for an id for the same widget twice, we want to return the same
- // id. So this records the current mapping.
- std::map<gfx::NativeView, gfx::NativeViewId> native_view_to_id_;
- std::map<gfx::NativeViewId, NativeViewInfo> id_to_info_;
-
- struct PermanentXIDInfo {
- PermanentXIDInfo() : widget(NULL), ref_count(0) {
- }
- _GtkPreserveWindow* widget;
- int ref_count;
- };
-
- // Used to maintain the reference count for permanent XIDs
- // (referenced by GetPermanentXIDForId and dereferenced by
- // ReleasePermanentXID). Only those XIDs with a positive reference count
- // will be in the table.
- //
- // In general, several GTK widgets may share the same X window. We assume
- // that is not true of the widgets stored in this registry.
- //
- // An XID will map to NULL, if there is an outstanding reference but the
- // widget was destroyed. In this case, the destruction of the X window
- // is deferred to the dropping of all references.
- std::map<XID, PermanentXIDInfo> perm_xid_to_info_;
-
- DISALLOW_COPY_AND_ASSIGN(GtkNativeViewManager);
-};
-
-#endif // UI_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
diff --git a/chromium/ui/gfx/gtk_preserve_window.cc b/chromium/ui/gfx/gtk_preserve_window.cc
deleted file mode 100644
index 78a49c28510..00000000000
--- a/chromium/ui/gfx/gtk_preserve_window.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/gtk_preserve_window.h"
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/gfx/gtk_compat.h"
-
-G_BEGIN_DECLS
-
-#define GTK_PRESERVE_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
- GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowPrivate))
-
-typedef struct _GtkPreserveWindowPrivate GtkPreserveWindowPrivate;
-
-struct _GtkPreserveWindowPrivate {
- // If true, don't create/destroy windows on realize/unrealize.
- gboolean preserve_window;
-
- // Whether or not we delegate the resize of the GdkWindow
- // to someone else.
- gboolean delegate_resize;
-
- // Accessible factory and userdata.
- AtkObject* (*accessible_factory)(void* userdata);
- void* accessible_factory_userdata;
-};
-
-G_DEFINE_TYPE(GtkPreserveWindow, gtk_preserve_window, GTK_TYPE_FIXED)
-
-static void gtk_preserve_window_destroy(GtkObject* object);
-static void gtk_preserve_window_realize(GtkWidget* widget);
-static void gtk_preserve_window_unrealize(GtkWidget* widget);
-static void gtk_preserve_window_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation);
-static AtkObject* gtk_preserve_window_get_accessible(GtkWidget* widget);
-
-static void gtk_preserve_window_class_init(GtkPreserveWindowClass *klass) {
- GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(klass);
- widget_class->realize = gtk_preserve_window_realize;
- widget_class->unrealize = gtk_preserve_window_unrealize;
- widget_class->size_allocate = gtk_preserve_window_size_allocate;
- widget_class->get_accessible = gtk_preserve_window_get_accessible;
-
- GtkObjectClass* object_class = reinterpret_cast<GtkObjectClass*>(klass);
- object_class->destroy = gtk_preserve_window_destroy;
-
- GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
- g_type_class_add_private(gobject_class, sizeof(GtkPreserveWindowPrivate));
-}
-
-static void gtk_preserve_window_init(GtkPreserveWindow* widget) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->preserve_window = FALSE;
- priv->accessible_factory = NULL;
- priv->accessible_factory_userdata = NULL;
-
- // These widgets always have their own window.
- gtk_widget_set_has_window(GTK_WIDGET(widget), TRUE);
-}
-
-GtkWidget* gtk_preserve_window_new() {
- return GTK_WIDGET(g_object_new(GTK_TYPE_PRESERVE_WINDOW, NULL));
-}
-
-static void gtk_preserve_window_destroy(GtkObject* object) {
- GtkWidget* widget = reinterpret_cast<GtkWidget*>(object);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (gdk_window) {
- gdk_window_set_user_data(gdk_window, NULL);
- // If the window is preserved, someone else must destroy it.
- if (!priv->preserve_window)
- gdk_window_destroy(gdk_window);
- gtk_widget_set_window(widget, NULL);
- }
-
- GTK_OBJECT_CLASS(gtk_preserve_window_parent_class)->destroy(object);
-}
-
-static void gtk_preserve_window_realize(GtkWidget* widget) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (gdk_window) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(widget, &allocation);
-
- gdk_window_reparent(gdk_window,
- gtk_widget_get_parent_window(widget),
- allocation.x,
- allocation.y);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (!priv->delegate_resize) {
- gdk_window_resize(gdk_window,
- allocation.width,
- allocation.height);
- }
- gint event_mask = gtk_widget_get_events(widget);
- event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
- gdk_window_set_events(gdk_window, (GdkEventMask) event_mask);
- gdk_window_set_user_data(gdk_window, widget);
-
- gtk_widget_set_realized(widget, TRUE);
-
- gtk_widget_style_attach(widget);
- gtk_style_set_background(gtk_widget_get_style(widget),
- gdk_window, GTK_STATE_NORMAL);
- } else {
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->realize(widget);
- }
-}
-
-static void gtk_preserve_window_unrealize(GtkWidget* widget) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (priv->preserve_window) {
- GtkWidgetClass* widget_class =
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class);
- GtkContainerClass* container_class =
- GTK_CONTAINER_CLASS(gtk_preserve_window_parent_class);
-
- if (gtk_widget_get_mapped(widget)) {
- widget_class->unmap(widget);
-
- gtk_widget_set_mapped(widget, FALSE);
- }
-
- // This is the behavior from GtkWidget, inherited by GtkFixed.
- // It is unclear why we should not call the potentially overridden
- // unrealize method (via the callback), but doing so causes errors.
- container_class->forall(
- GTK_CONTAINER(widget), FALSE,
- reinterpret_cast<GtkCallback>(gtk_widget_unrealize), NULL);
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
-
- // TODO(erg): Almost all style handling will need to be overhauled in GTK3.
- gtk_style_detach(gtk_widget_get_style(widget));
- gdk_window_reparent(gdk_window, gdk_get_default_root_window(), 0, 0);
- gtk_selection_remove_all(widget);
- gdk_window_set_user_data(gdk_window, NULL);
-
- gtk_widget_set_realized(widget, FALSE);
- } else {
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->unrealize(widget);
- }
-}
-
-gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* window) {
- g_return_val_if_fail(GTK_IS_PRESERVE_WINDOW(window), FALSE);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
-
- return priv->preserve_window;
-}
-
-void gtk_preserve_window_set_preserve(GtkPreserveWindow* window,
- gboolean value) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(window));
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
- priv->preserve_window = value;
-
- GtkWidget* widget = GTK_WIDGET(window);
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (value && !gdk_window) {
- GdkWindowAttr attributes;
- gint attributes_mask;
-
- // We may not know the width and height, so we rely on the fact
- // that a size-allocation will resize it later.
- attributes.width = 1;
- attributes.height = 1;
-
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.override_redirect = TRUE;
-
- attributes.visual = gtk_widget_get_visual(widget);
- attributes.colormap = gtk_widget_get_colormap(widget);
-
- attributes.event_mask = gtk_widget_get_events(widget);
- attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
-
- attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_NOREDIR;
- gdk_window = gdk_window_new(
- gdk_get_default_root_window(), &attributes, attributes_mask);
- gtk_widget_set_window(widget, gdk_window);
- } else if (!value && gdk_window && !gtk_widget_get_realized(widget)) {
- gdk_window_destroy(gdk_window);
- gtk_widget_set_window(widget, NULL);
- }
-}
-
-void gtk_preserve_window_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- gtk_widget_set_allocation(widget, allocation);
-
- if (gtk_widget_get_realized(widget)) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (priv->delegate_resize) {
- gdk_window_move(gdk_window, allocation->x, allocation->y);
- } else {
- gdk_window_move_resize(
- gdk_window, allocation->x, allocation->y,
- allocation->width, allocation->height);
- }
- }
-
- // Propagate resize to children
- guint16 border_width = gtk_container_get_border_width(GTK_CONTAINER(widget));
- GList *children = GTK_FIXED(widget)->children;
- while (children) {
- GtkFixedChild *child = reinterpret_cast<GtkFixedChild*>(children->data);
- if (gtk_widget_get_visible(child->widget)) {
- GtkRequisition child_requisition;
- gtk_widget_get_child_requisition(child->widget, &child_requisition);
-
- GtkAllocation child_allocation;
- child_allocation.x = child->x + border_width;
- child_allocation.y = child->y + border_width;
- child_allocation.width = child_requisition.width;
- child_allocation.height = child_requisition.height;
-
- gtk_widget_size_allocate(child->widget, &child_allocation);
- }
- children = children->next;
- }
-}
-
-void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
- gboolean delegate) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->delegate_resize = delegate;
-}
-
-void gtk_preserve_window_set_accessible_factory(
- GtkPreserveWindow* widget,
- AtkObject* (*factory)(void* userdata),
- gpointer userdata) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->accessible_factory = factory;
- priv->accessible_factory_userdata = userdata;
-}
-
-AtkObject* gtk_preserve_window_get_accessible(GtkWidget* widget) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (priv->accessible_factory) {
- return priv->accessible_factory(priv->accessible_factory_userdata);
- } else {
- return GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)
- ->get_accessible(widget);
- }
-}
-
-G_END_DECLS
diff --git a/chromium/ui/gfx/gtk_preserve_window.h b/chromium/ui/gfx/gtk_preserve_window.h
deleted file mode 100644
index 5b5198bf56f..00000000000
--- a/chromium/ui/gfx/gtk_preserve_window.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GTK_PRESERVE_WINDOW_H_
-#define UI_GFX_GTK_PRESERVE_WINDOW_H_
-
-#include <atk/atk.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/gfx/gfx_export.h"
-
-// GtkFixed creates an X window when realized and destroys an X window
-// when unrealized. GtkPreserveWindow allows overrides this
-// behaviour. When preserve is set (via gtk_preserve_window_set_preserve),
-// the X window is only destroyed when the widget is destroyed.
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_PRESERVE_WINDOW \
- (gtk_preserve_window_get_type())
-#define GTK_PRESERVE_WINDOW(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindow))
-#define GTK_PRESERVE_WINDOW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowClass))
-#define GTK_IS_PRESERVE_WINDOW(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_PRESERVE_WINDOW))
-#define GTK_IS_PRESERVE_WINDOW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_PRESERVE_WINDOW))
-#define GTK_PRESERVE_WINDOW_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowClass))
-
-typedef struct _GtkPreserveWindow GtkPreserveWindow;
-typedef struct _GtkPreserveWindowClass GtkPreserveWindowClass;
-
-struct _GtkPreserveWindow {
- // Parent class.
- GtkFixed fixed;
-};
-
-struct _GtkPreserveWindowClass {
- GtkFixedClass parent_class;
-};
-
-GFX_EXPORT GType gtk_preserve_window_get_type() G_GNUC_CONST;
-GFX_EXPORT GtkWidget* gtk_preserve_window_new();
-
-// Whether or not we should preserve associated windows as the widget
-// is realized or unrealized.
-GFX_EXPORT gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* widget);
-GFX_EXPORT void gtk_preserve_window_set_preserve(GtkPreserveWindow* widget,
- gboolean value);
-
-// Whether or not someone else will gdk_window_resize the GdkWindow associated
-// with this widget (needed by the GPU process to synchronize resizing
-// with swapped between front and back buffer).
-GFX_EXPORT void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
- gboolean delegate);
-
-// Provide a function to return an AtkObject* when calls to get_accessible
-// are made on this widget. The parameter |userdata| will be passed to the
-// factory function.
-GFX_EXPORT void gtk_preserve_window_set_accessible_factory(
- GtkPreserveWindow* widget,
- AtkObject* (*factory)(void* userdata),
- gpointer userdata);
-
-G_END_DECLS
-
-#endif // UI_GFX_GTK_PRESERVE_WINDOW_H_
diff --git a/chromium/ui/gfx/gtk_util.cc b/chromium/ui/gfx/gtk_util.cc
deleted file mode 100644
index 0c111687572..00000000000
--- a/chromium/ui/gfx/gtk_util.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/gtk_util.h"
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/memory/scoped_ptr.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkUnPreMultiply.h"
-#include "ui/gfx/rect.h"
-
-namespace {
-
-// A process wide singleton that manages our usage of gdk cursors.
-// gdk_cursor_new() hits the disk in several places and GdkCursor instances can
-// be reused throughout the process.
-class GdkCursorCache {
- public:
- GdkCursorCache() {}
- ~GdkCursorCache() {
- for (GdkCursorMap::iterator i(cursors_.begin()); i != cursors_.end(); ++i) {
- gdk_cursor_unref(i->second);
- }
- cursors_.clear();
- }
-
- GdkCursor* GetCursorImpl(GdkCursorType type) {
- GdkCursorMap::iterator it = cursors_.find(type);
- GdkCursor* cursor = NULL;
- if (it == cursors_.end()) {
- cursor = gdk_cursor_new(type);
- cursors_.insert(std::make_pair(type, cursor));
- } else {
- cursor = it->second;
- }
-
- // It is not necessary to add a reference here. The callers can ref the
- // cursor if they need it for something.
- return cursor;
- }
-
- private:
- typedef std::map<GdkCursorType, GdkCursor*> GdkCursorMap;
- GdkCursorMap cursors_;
-
- DISALLOW_COPY_AND_ASSIGN(GdkCursorCache);
-};
-
-} // namespace
-
-namespace gfx {
-
-static void CommonInitFromCommandLine(const CommandLine& command_line,
- void (*init_func)(gint*, gchar***)) {
- const std::vector<std::string>& args = command_line.argv();
- int argc = args.size();
- scoped_ptr<char *[]> argv(new char *[argc + 1]);
- for (size_t i = 0; i < args.size(); ++i) {
- // TODO(piman@google.com): can gtk_init modify argv? Just being safe
- // here.
- argv[i] = strdup(args[i].c_str());
- }
- argv[argc] = NULL;
- char **argv_pointer = argv.get();
-
- init_func(&argc, &argv_pointer);
- for (size_t i = 0; i < args.size(); ++i) {
- free(argv[i]);
- }
-}
-
-void GtkInitFromCommandLine(const CommandLine& command_line) {
- CommonInitFromCommandLine(command_line, gtk_init);
-}
-
-void GdkInitFromCommandLine(const CommandLine& command_line) {
- CommonInitFromCommandLine(command_line, gdk_init);
-}
-
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
- if (bitmap.isNull())
- return NULL;
-
- SkAutoLockPixels lock_pixels(bitmap);
-
- int width = bitmap.width();
- int height = bitmap.height();
-
- GdkPixbuf* pixbuf = gdk_pixbuf_new(
- GDK_COLORSPACE_RGB, // The only colorspace gtk supports.
- TRUE, // There is an alpha channel.
- 8,
- width, height);
-
- // SkBitmaps are premultiplied, we need to unpremultiply them.
- const int kBytesPerPixel = 4;
- uint8* divided = gdk_pixbuf_get_pixels(pixbuf);
-
- for (int y = 0, i = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- uint32 pixel = bitmap.getAddr32(0, y)[x];
-
- int alpha = SkColorGetA(pixel);
- if (alpha != 0 && alpha != 255) {
- SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
- divided[i + 0] = SkColorGetR(unmultiplied);
- divided[i + 1] = SkColorGetG(unmultiplied);
- divided[i + 2] = SkColorGetB(unmultiplied);
- divided[i + 3] = alpha;
- } else {
- divided[i + 0] = SkColorGetR(pixel);
- divided[i + 1] = SkColorGetG(pixel);
- divided[i + 2] = SkColorGetB(pixel);
- divided[i + 3] = alpha;
- }
- i += kBytesPerPixel;
- }
- }
-
- return pixbuf;
-}
-
-void SubtractRectanglesFromRegion(GdkRegion* region,
- const std::vector<Rect>& cutouts) {
- for (size_t i = 0; i < cutouts.size(); ++i) {
- GdkRectangle rect = cutouts[i].ToGdkRectangle();
- GdkRegion* rect_region = gdk_region_rectangle(&rect);
- gdk_region_subtract(region, rect_region);
- // TODO(deanm): It would be nice to be able to reuse the GdkRegion here.
- gdk_region_destroy(rect_region);
- }
-}
-
-GdkCursor* GetCursor(int type) {
- CR_DEFINE_STATIC_LOCAL(GdkCursorCache, impl, ());
- return impl.GetCursorImpl(static_cast<GdkCursorType>(type));
-}
-
-void InitRCStyles() {
- static const char kRCText[] =
- // Make our dialogs styled like the GNOME HIG.
- //
- // TODO(evanm): content-area-spacing was introduced in a later
- // version of GTK, so we need to set that manually on all dialogs.
- // Perhaps it would make sense to have a shared FixupDialog() function.
- "style \"gnome-dialog\" {\n"
- " xthickness = 12\n"
- " GtkDialog::action-area-border = 0\n"
- " GtkDialog::button-spacing = 6\n"
- " GtkDialog::content-area-spacing = 18\n"
- " GtkDialog::content-area-border = 12\n"
- "}\n"
- // Note we set it at the "application" priority, so users can override.
- "widget \"GtkDialog\" style : application \"gnome-dialog\"\n"
-
- // Make our about dialog special, so the image is flush with the edge.
- "style \"about-dialog\" {\n"
- " GtkDialog::action-area-border = 12\n"
- " GtkDialog::button-spacing = 6\n"
- " GtkDialog::content-area-spacing = 18\n"
- " GtkDialog::content-area-border = 0\n"
- "}\n"
- "widget \"about-dialog\" style : application \"about-dialog\"\n";
-
- gtk_rc_parse_string(kRCText);
-}
-
-base::TimeDelta GetCursorBlinkCycle() {
- // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is
- // the default value for gtk-cursor-blink-time.
- static const gint kGtkDefaultCursorBlinkTime = 1200;
-
- gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
- gboolean cursor_blink = TRUE;
- g_object_get(gtk_settings_get_default(),
- "gtk-cursor-blink-time", &cursor_blink_time,
- "gtk-cursor-blink", &cursor_blink,
- NULL);
- return cursor_blink ?
- base::TimeDelta::FromMilliseconds(cursor_blink_time) :
- base::TimeDelta();
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/gtk_util.h b/chromium/ui/gfx/gtk_util.h
deleted file mode 100644
index 91f864bbe4c..00000000000
--- a/chromium/ui/gfx/gtk_util.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GTK_UTIL_H_
-#define UI_GFX_GTK_UTIL_H_
-
-#include <vector>
-
-#include "base/time/time.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GdkRegion GdkRegion;
-typedef struct _GdkCursor GdkCursor;
-
-class CommandLine;
-class SkBitmap;
-
-namespace gfx {
-
-class Rect;
-
-// Call gtk_init() / gdk_init() using the argc and argv from command_line.
-// These init functions want an argc and argv that they can mutate; we provide
-// those, but leave the original CommandLine unaltered.
-GFX_EXPORT void GtkInitFromCommandLine(const CommandLine& command_line);
-GFX_EXPORT void GdkInitFromCommandLine(const CommandLine& command_line);
-
-// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
-// it is an expensive operation. The returned GdkPixbuf will have a refcount of
-// 1, and the caller is responsible for unrefing it when done.
-GFX_EXPORT GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap);
-
-// Modify the given region by subtracting the given rectangles.
-GFX_EXPORT void SubtractRectanglesFromRegion(GdkRegion* region,
- const std::vector<Rect>& cutouts);
-
-// Returns a static instance of a GdkCursor* object, sharable across the
-// process. Caller must gdk_cursor_ref() it if they want to assume ownership.
-GFX_EXPORT GdkCursor* GetCursor(int type);
-
-// Initialize some GTK settings so that our dialogs are consistent.
-GFX_EXPORT void InitRCStyles();
-
-// Queries GtkSettings for the cursor blink cycle time. Returns a 0 duration if
-// blinking is disabled.
-GFX_EXPORT base::TimeDelta GetCursorBlinkCycle();
-
-} // namespace gfx
-
-#endif // UI_GFX_GTK_UTIL_H_
diff --git a/chromium/ui/gfx/icon_util.cc b/chromium/ui/gfx/icon_util.cc
index 223618601e3..dd2b9bd6b50 100644
--- a/chromium/ui/gfx/icon_util.cc
+++ b/chromium/ui/gfx/icon_util.cc
@@ -77,7 +77,7 @@ bool BuildResizedImageFamily(const gfx::ImageFamily& image_family,
SkBitmap best_bitmap = best->AsBitmap();
// Only kARGB_8888 images are supported.
// This will also filter out images with no pixels.
- if (best_bitmap.config() != SkBitmap::kARGB_8888_Config)
+ if (best_bitmap.colorType() != kPMColor_SkColorType)
return false;
SkBitmap resized_bitmap = skia::ImageOperations::Resize(
best_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
@@ -119,7 +119,7 @@ bool ConvertImageFamilyToBitmaps(
// Only 32 bit ARGB bitmaps are supported. We also make sure the bitmap has
// been properly initialized.
SkAutoLockPixels bitmap_lock(bitmap);
- if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
+ if ((bitmap.colorType() != kPMColor_SkColorType) ||
(bitmap.getPixels() == NULL)) {
return false;
}
@@ -166,7 +166,7 @@ HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) {
// Only 32 bit ARGB bitmaps are supported. We also try to perform as many
// validations as we can on the bitmap.
SkAutoLockPixels bitmap_lock(bitmap);
- if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
+ if ((bitmap.colorType() != kPMColor_SkColorType) ||
(bitmap.width() <= 0) || (bitmap.height() <= 0) ||
(bitmap.getPixels() == NULL))
return NULL;
@@ -177,13 +177,18 @@ HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) {
// alpha mask for the DIB.
BITMAPV5HEADER bitmap_header;
InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height());
- void* bits;
- HDC hdc = ::GetDC(NULL);
+
+ void* bits = NULL;
HBITMAP dib;
- dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS, &bits, NULL, 0);
- DCHECK(dib);
- ::ReleaseDC(NULL, hdc);
+
+ {
+ base::win::ScopedGetDC hdc(NULL);
+ dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &bits, NULL, 0);
+ }
+ if (!dib || !bits)
+ return NULL;
+
memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4);
// Icons are generally created using an AND and XOR masks where the AND
@@ -290,9 +295,8 @@ scoped_ptr<SkBitmap> IconUtil::CreateSkBitmapFromIconResource(HMODULE module,
DCHECK(png_data);
DCHECK_EQ(png_size, large_icon_entry->dwBytesInRes);
- const unsigned char* png_bytes =
- reinterpret_cast<const unsigned char*>(png_data);
- gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(png_bytes, png_size);
+ gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
+ new base::RefCountedStaticMemory(png_data, png_size));
return scoped_ptr<SkBitmap>(new SkBitmap(image.AsBitmap()));
}
@@ -372,8 +376,7 @@ SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
// Allocating memory for the SkBitmap object. We are going to create an ARGB
// bitmap so we should set the configuration appropriately.
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, s.width(), s.height());
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(s.width(), s.height());
bitmap.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels bitmap_lock(bitmap);
diff --git a/chromium/ui/gfx/icon_util_unittest.cc b/chromium/ui/gfx/icon_util_unittest.cc
index 641422a24ef..1e2e96297c2 100644
--- a/chromium/ui/gfx/icon_util_unittest.cc
+++ b/chromium/ui/gfx/icon_util_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/gfx/icon_util.h"
+
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
@@ -9,11 +11,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/gfx_paths.h"
-#include "ui/gfx/icon_util.h"
+#include "ui/gfx/icon_util_unittests_resource.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_family.h"
#include "ui/gfx/size.h"
-#include "ui/test/ui_unittests_resource.h"
namespace {
@@ -50,9 +51,8 @@ class IconUtilTest : public testing::Test {
SkBitmap CreateBlackSkBitmap(int width, int height) {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bitmap.allocPixels();
- // Setting the pixels to black.
+ bitmap.allocN32Pixels(width, height);
+ // Setting the pixels to transparent-black.
memset(bitmap.getPixels(), 0, width * height * 4);
return bitmap;
}
@@ -172,23 +172,22 @@ TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
// Wrong bitmap format.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_EQ(icon, static_cast<HICON>(NULL));
// Invalid bitmap size.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(0, 0));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_EQ(icon, static_cast<HICON>(NULL));
// Valid bitmap configuration but no pixels allocated.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth,
+ kSmallIconHeight));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_TRUE(icon == NULL);
}
@@ -206,10 +205,9 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
// Wrong bitmap format.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
// Must allocate pixels or else ImageSkia will ignore the bitmap and just
// return an empty image.
- bitmap->allocPixels();
+ bitmap->allocPixels(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight));
memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height());
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
@@ -220,8 +218,7 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
- bitmap->allocPixels();
+ bitmap->allocPixels(SkImageInfo::MakeN32Premul(0, 0));
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
valid_icon_filename));
@@ -231,9 +228,8 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth,
+ kSmallIconHeight));
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
valid_icon_filename));
@@ -284,7 +280,7 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
EXPECT_EQ(bitmap->width(), small_icon_size.width());
EXPECT_EQ(bitmap->height(), small_icon_size.height());
- EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
+ EXPECT_EQ(bitmap->colorType(), kPMColor_SkColorType);
::DestroyIcon(small_icon);
base::FilePath large_icon_filename = test_data_directory_.AppendASCII(
@@ -298,7 +294,7 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
EXPECT_EQ(bitmap->width(), large_icon_size.width());
EXPECT_EQ(bitmap->height(), large_icon_size.height());
- EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
+ EXPECT_EQ(bitmap->colorType(), kPMColor_SkColorType);
::DestroyIcon(large_icon);
}
diff --git a/chromium/ui/gfx/icon_util_unittests.ico b/chromium/ui/gfx/icon_util_unittests.ico
new file mode 100644
index 00000000000..8cd57a12299
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests.ico
Binary files differ
diff --git a/chromium/ui/gfx/icon_util_unittests.rc b/chromium/ui/gfx/icon_util_unittests.rc
new file mode 100644
index 00000000000..a44a001bc0b
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests.rc
@@ -0,0 +1,36 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "icon_util_unittests_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON "icon_util_unittests.ico"
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/gfx/icon_util_unittests_resource.h b/chromium/ui/gfx/icon_util_unittests_resource.h
new file mode 100644
index 00000000000..0a50edfdd01
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests_resource.h
@@ -0,0 +1,5 @@
+// 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.
+
+#define IDR_MAINFRAME 101
diff --git a/chromium/ui/gfx/image/OWNERS b/chromium/ui/gfx/image/OWNERS
index d3273727c23..23dbb5a958f 100644
--- a/chromium/ui/gfx/image/OWNERS
+++ b/chromium/ui/gfx/image/OWNERS
@@ -1,4 +1,4 @@
rsesek@chromium.org
# ImageSkia related classes except for _mac/_ios stuff
-per-file image_skia.*=oshima@chromium.org
+per-file image_skia*=oshima@chromium.org
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.cc b/chromium/ui/gfx/image/cairo_cached_surface.cc
deleted file mode 100644
index 2de4a3210b3..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/image/cairo_cached_surface.h"
-
-#include <gtk/gtk.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-
-namespace gfx {
-
-CairoCachedSurface::CairoCachedSurface() : pixbuf_(NULL) {
-}
-
-CairoCachedSurface::~CairoCachedSurface() {
- Reset();
-}
-
-void CairoCachedSurface::Reset() {
- for (SurfaceVector::iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- cairo_surface_destroy(it->second);
- }
- surface_map_.clear();
-
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
-}
-
-int CairoCachedSurface::Width() const {
- return pixbuf_ ? gdk_pixbuf_get_width(pixbuf_) : -1;
-}
-
-int CairoCachedSurface::Height() const {
- return pixbuf_ ? gdk_pixbuf_get_height(pixbuf_) : -1;
-}
-
-void CairoCachedSurface::UsePixbuf(GdkPixbuf* pixbuf) {
- if (pixbuf)
- g_object_ref(pixbuf);
-
- Reset();
-
- pixbuf_ = pixbuf;
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- SetSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_set_source_surface(cr, surface, x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- MaskSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_mask_surface(cr, surface, x, y);
-}
-
-cairo_surface_t* CairoCachedSurface::GetSurfaceFor(cairo_t* cr,
- GdkDisplay* display) const {
- for (SurfaceVector::const_iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- if (display == it->first) {
- return it->second;
- }
- }
-
- // First time here since last UsePixbuf call. Generate the surface.
- cairo_surface_t* target = cairo_get_target(cr);
- cairo_surface_t* out = cairo_surface_create_similar(
- target,
- CAIRO_CONTENT_COLOR_ALPHA,
- gdk_pixbuf_get_width(pixbuf_),
- gdk_pixbuf_get_height(pixbuf_));
-
- DCHECK(out);
-
- cairo_t* copy_cr = cairo_create(out);
- gdk_cairo_set_source_pixbuf(copy_cr, pixbuf_, 0, 0);
- cairo_paint(copy_cr);
- cairo_destroy(copy_cr);
-
- surface_map_.push_back(std::make_pair(display, out));
- return out;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.h b/chromium/ui/gfx/image/cairo_cached_surface.h
deleted file mode 100644
index ceece4ba2d2..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
-#define UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
-
-#include <vector>
-
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkDisplay GdkDisplay;
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _cairo cairo_t;
-typedef struct _cairo_surface cairo_surface_t;
-
-namespace gfx {
-
-// A helper class that takes a GdkPixbuf* and renders it to the screen. Unlike
-// gdk_cairo_set_source_pixbuf(), CairoCachedSurface assumes that the pixbuf is
-// immutable after UsePixbuf() is called and can be sent to the display server
-// once. From then on, that cached version is used so we don't upload the same
-// image each and every time we expose.
-//
-// Most cached surfaces are owned by the GtkThemeService, which associates
-// them with a certain XDisplay. Some users of surfaces (CustomDrawButtonBase,
-// for example) own their surfaces instead since they interact with the
-// ResourceBundle instead of the GtkThemeService.
-class GFX_EXPORT CairoCachedSurface {
- public:
- CairoCachedSurface();
- ~CairoCachedSurface();
-
- // Whether this CairoCachedSurface owns a GdkPixbuf.
- bool valid() const {
- return pixbuf_;
- }
-
- // Delete all our data.
- void Reset();
-
- // The dimensions of the underlying pixbuf/surface. (or -1 if invalid.)
- int Width() const;
- int Height() const;
-
- // Sets the pixbuf that we pass to cairo. Calling UsePixbuf() only derefs the
- // current pixbuf and surface (if they exist). Actually transfering data to
- // the X server occurs at SetSource() time. Calling UsePixbuf() should only
- // be done once as it clears cached data from the X server.
- void UsePixbuf(GdkPixbuf* pixbuf);
-
- // Sets our pixbuf as the active surface starting at (x, y), uploading it in
- // case we don't have an X backed surface cached.
- void SetSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void SetSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Performs a mask operation, using this surface as the alpha channel.
- void MaskSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void MaskSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Raw access to the pixbuf. May be NULL. Used for a few gdk operations
- // regarding window shaping.
- GdkPixbuf* pixbuf() { return pixbuf_; }
-
- private:
- typedef std::vector<std::pair<GdkDisplay*, cairo_surface_t*> > SurfaceVector;
-
- // Returns a surface . Caches results so only one copy of the image data
- // lives on the display server.
- cairo_surface_t* GetSurfaceFor(cairo_t* cr, GdkDisplay* display) const;
-
- // The source pixbuf.
- GdkPixbuf* pixbuf_;
-
- // Our list of cached surfaces. 99% of the time, this will only contain a
- // single entry. At most two. We need to get this right for multiple displays
- // to work correct, since each GdkDisplay is a different display server.
- mutable SurfaceVector surface_map_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc
index 91b9e69b289..459880742f8 100644
--- a/chromium/ui/gfx/image/image.cc
+++ b/chromium/ui/gfx/image/image.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/image/image.h"
#include <algorithm>
+#include <set>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -12,21 +13,14 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
#if !defined(OS_IOS)
#include "ui/gfx/codec/png_codec.h"
#endif
-#if defined(TOOLKIT_GTK)
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdk.h>
-#include <glib-object.h>
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/image/cairo_cached_surface.h"
-#include "ui/gfx/scoped_gobject.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "ui/gfx/image/image_skia_util_ios.h"
#elif defined(OS_MACOSX)
@@ -38,100 +32,25 @@ namespace gfx {
namespace internal {
-#if defined(TOOLKIT_GTK)
-const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) {
- CHECK(pixbuf);
- gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf),
- gdk_pixbuf_get_height(pixbuf)),
- 1.0f,
- false);
- skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
- cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
- gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
- cairo_paint(cr);
- return ImageSkia(canvas.ExtractImageRep());
-}
-
-// Returns a 16x16 red pixbuf to visually show error in decoding PNG.
-// Also logs error to console.
-GdkPixbuf* GetErrorPixbuf() {
- LOG(ERROR) << "Unable to decode PNG.";
- GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
- gdk_pixbuf_fill(pixbuf, 0xff0000ff);
- return pixbuf;
-}
-
-GdkPixbuf* GdkPixbufFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
- scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
- if (image_png_reps[i].scale == 1.0f)
- png_bytes = image_png_reps[i].raw_data;
- }
-
- if (!png_bytes.get())
- return GetErrorPixbuf();
-
- GdkPixbuf* pixbuf = NULL;
- ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
-
- bool ok = gdk_pixbuf_loader_write(loader.get(),
- reinterpret_cast<const guint8*>(png_bytes->front()), png_bytes->size(),
- NULL);
-
- // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
- // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
- if (ok)
- ok = gdk_pixbuf_loader_close(loader.get(), NULL);
- if (ok)
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
-
- if (pixbuf) {
- // The pixbuf is owned by the scoped loader which will delete its ref when
- // it goes out of scope. Add a ref so that the pixbuf still exists.
- g_object_ref(pixbuf);
- } else {
- return GetErrorPixbuf();
- }
-
- return pixbuf;
-}
-
-scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromPixbuf(
- GdkPixbuf* pixbuf) {
- gchar* image = NULL;
- gsize image_size;
- GError* error = NULL;
- CHECK(gdk_pixbuf_save_to_buffer(
- pixbuf, &image, &image_size, "png", &error, NULL));
- scoped_refptr<base::RefCountedBytes> png_bytes(
- new base::RefCountedBytes());
- png_bytes->data().assign(image, image + image_size);
- g_free(image);
- return png_bytes;
-}
-
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage);
// Caller takes ownership of the returned UIImage.
UIImage* CreateUIImageFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
gfx::Size UIImageSize(UIImage* image);
#elif defined(OS_MACOSX)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage);
// Caller takes ownership of the returned NSImage.
-NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
+NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
CGColorSpaceRef color_space);
gfx::Size NSImageSize(NSImage* image);
#endif // defined(OS_MACOSX)
#if defined(OS_IOS)
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
const ImageSkia* skia);
#else
@@ -141,32 +60,92 @@ ImageSkia* GetErrorImageSkia() {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
bitmap.allocPixels();
- bitmap.eraseRGB(0xff, 0, 0);
- return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f));
+ bitmap.eraseARGB(0xff, 0xff, 0, 0);
+ return new ImageSkia(ImageSkiaRep(bitmap, 1.0f));
}
+class PNGImageSource : public ImageSkiaSource {
+ public:
+ PNGImageSource() {}
+ virtual ~PNGImageSource() {}
+
+ virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ if (image_skia_reps_.empty())
+ return ImageSkiaRep();
+
+ const ImageSkiaRep* rep = NULL;
+ // gfx::ImageSkia passes one of the resource scale factors. The source
+ // should return:
+ // 1) The ImageSkiaRep with the highest scale if all available
+ // scales are smaller than |scale|.
+ // 2) The ImageSkiaRep with the smallest one that is larger than |scale|.
+ for (ImageSkiaRepSet::const_iterator iter = image_skia_reps_.begin();
+ iter != image_skia_reps_.end(); ++iter) {
+ if ((*iter).scale() == scale)
+ return (*iter);
+ if (!rep || rep->scale() < (*iter).scale())
+ rep = &(*iter);
+ if (rep->scale() >= scale)
+ break;
+ }
+ return rep ? *rep : ImageSkiaRep();
+ }
+
+ const gfx::Size size() const {
+ return size_;
+ }
+
+ bool AddPNGData(const ImagePNGRep& png_rep) {
+ const gfx::ImageSkiaRep rep = ToImageSkiaRep(png_rep);
+ if (rep.is_null())
+ return false;
+ if (size_.IsEmpty())
+ size_ = gfx::Size(rep.GetWidth(), rep.GetHeight());
+ image_skia_reps_.insert(rep);
+ return true;
+ }
+
+ static ImageSkiaRep ToImageSkiaRep(const ImagePNGRep& png_rep) {
+ scoped_refptr<base::RefCountedMemory> raw_data = png_rep.raw_data;
+ CHECK(raw_data.get());
+ SkBitmap bitmap;
+ if (!PNGCodec::Decode(raw_data->front(), raw_data->size(),
+ &bitmap)) {
+ LOG(ERROR) << "Unable to decode PNG for " << png_rep.scale << ".";
+ return ImageSkiaRep();
+ }
+ return ImageSkiaRep(bitmap, png_rep.scale);
+ }
+
+ private:
+ struct Compare {
+ bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
+ return rep1.scale() < rep2.scale();
+ }
+ };
+
+ typedef std::set<ImageSkiaRep, Compare> ImageSkiaRepSet;
+ ImageSkiaRepSet image_skia_reps_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(PNGImageSource);
+};
+
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
+ const std::vector<ImagePNGRep>& image_png_reps) {
if (image_png_reps.empty())
return GetErrorImageSkia();
+ scoped_ptr<PNGImageSource> image_source(new PNGImageSource);
- scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia());
for (size_t i = 0; i < image_png_reps.size(); ++i) {
- scoped_refptr<base::RefCountedMemory> raw_data =
- image_png_reps[i].raw_data;
- CHECK(raw_data.get());
- SkBitmap bitmap;
- if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
- &bitmap)) {
- LOG(ERROR) << "Unable to decode PNG for "
- << image_png_reps[i].scale
- << ".";
+ if (!image_source->AddPNGData(image_png_reps[i]))
return GetErrorImageSkia();
- }
- image_skia->AddRepresentation(gfx::ImageSkiaRep(
- bitmap, image_png_reps[i].scale));
}
- return image_skia.release();
+ const gfx::Size& size = image_source->size();
+ DCHECK(!size.IsEmpty());
+ if (size.IsEmpty())
+ return GetErrorImageSkia();
+ return new ImageSkia(image_source.release(), size);
}
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
@@ -175,7 +154,7 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
if (image_skia_rep.scale() != 1.0f ||
- !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
+ !PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
&png_bytes->data())) {
return NULL;
}
@@ -185,8 +164,6 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
class ImageRepPNG;
class ImageRepSkia;
-class ImageRepGdk;
-class ImageRepCairo;
class ImageRepCocoa;
class ImageRepCocoaTouch;
@@ -213,18 +190,6 @@ class ImageRep {
return reinterpret_cast<ImageRepSkia*>(this);
}
-#if defined(TOOLKIT_GTK)
- ImageRepGdk* AsImageRepGdk() {
- CHECK_EQ(type_, Image::kImageRepGdk);
- return reinterpret_cast<ImageRepGdk*>(this);
- }
-
- ImageRepCairo* AsImageRepCairo() {
- CHECK_EQ(type_, Image::kImageRepCairo);
- return reinterpret_cast<ImageRepCairo*>(this);
- }
-#endif
-
#if defined(OS_IOS)
ImageRepCocoaTouch* AsImageRepCocoaTouch() {
CHECK_EQ(type_, Image::kImageRepCocoaTouch);
@@ -326,77 +291,6 @@ class ImageRepSkia : public ImageRep {
DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
};
-#if defined(TOOLKIT_GTK)
-class ImageRepGdk : public ImageRep {
- public:
- explicit ImageRepGdk(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepGdk),
- pixbuf_(pixbuf) {
- CHECK(pixbuf);
- }
-
- virtual ~ImageRepGdk() {
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
- }
-
- virtual int Width() const OVERRIDE {
- return gdk_pixbuf_get_width(pixbuf_);
- }
-
- virtual int Height() const OVERRIDE {
- return gdk_pixbuf_get_height(pixbuf_);
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- GdkPixbuf* pixbuf() const { return pixbuf_; }
-
- private:
- GdkPixbuf* pixbuf_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepGdk);
-};
-
-// Represents data that lives on the display server instead of in the client.
-class ImageRepCairo : public ImageRep {
- public:
- explicit ImageRepCairo(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepCairo),
- cairo_cache_(new CairoCachedSurface) {
- CHECK(pixbuf);
- cairo_cache_->UsePixbuf(pixbuf);
- }
-
- virtual ~ImageRepCairo() {
- delete cairo_cache_;
- }
-
- virtual int Width() const OVERRIDE {
- return cairo_cache_->Width();
- }
-
- virtual int Height() const OVERRIDE {
- return cairo_cache_->Height();
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- CairoCachedSurface* surface() const { return cairo_cache_; }
-
- private:
- CairoCachedSurface* cairo_cache_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepCairo);
-};
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
class ImageRepCocoaTouch : public ImageRep {
public:
@@ -470,7 +364,7 @@ class ImageRepCocoa : public ImageRep {
// ImageReps. This way, the Image can be cheaply copied.
class ImageStorage : public base::RefCounted<ImageStorage> {
public:
- ImageStorage(gfx::Image::RepresentationType default_type)
+ ImageStorage(Image::RepresentationType default_type)
: default_representation_type_(default_type),
#if defined(OS_MACOSX) && !defined(OS_IOS)
default_representation_color_space_(
@@ -479,10 +373,10 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
representations_deleter_(&representations_) {
}
- gfx::Image::RepresentationType default_representation_type() {
+ Image::RepresentationType default_representation_type() {
return default_representation_type_;
}
- gfx::Image::RepresentationMap& representations() { return representations_; }
+ Image::RepresentationMap& representations() { return representations_; }
#if defined(OS_MACOSX) && !defined(OS_IOS)
void set_default_representation_color_space(CGColorSpaceRef color_space) {
@@ -500,7 +394,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// The type of image that was passed to the constructor. This key will always
// exist in the |representations_| map.
- gfx::Image::RepresentationType default_representation_type_;
+ Image::RepresentationType default_representation_type_;
#if defined(OS_MACOSX) && !defined(OS_IOS)
// The default representation's colorspace. This is used for converting to
@@ -512,7 +406,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// All the representations of an Image. Size will always be at least one, with
// more for any converted representations.
- gfx::Image::RepresentationMap representations_;
+ Image::RepresentationMap representations_;
STLValueDeleter<Image::RepresentationMap> representations_deleter_;
@@ -550,16 +444,6 @@ Image::Image(const ImageSkia& image) {
}
}
-#if defined(TOOLKIT_GTK)
-Image::Image(GdkPixbuf* pixbuf) {
- if (pixbuf) {
- storage_ = new internal::ImageStorage(Image::kImageRepGdk);
- internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf);
- AddRepresentation(rep);
- }
-}
-#endif
-
#if defined(OS_IOS)
Image::Image(UIImage* image)
: storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
@@ -591,20 +475,29 @@ Image::~Image() {
// static
Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
+ return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
}
// static
Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size) {
if (input_size == 0u)
- return gfx::Image();
+ return Image();
scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
raw_data->data().assign(input, input + input_size);
- std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(ImagePNGRep(raw_data, 1.0f));
- return gfx::Image(image_reps);
+
+ return CreateFrom1xPNGBytes(raw_data);
+}
+
+Image Image::CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input) {
+ if (!input.get() || input->size() == 0u)
+ return Image();
+
+ std::vector<ImagePNGRep> image_reps;
+ image_reps.push_back(ImagePNGRep(input, 1.0f));
+ return Image(image_reps);
}
const SkBitmap* Image::ToSkBitmap() const {
@@ -623,15 +516,7 @@ const ImageSkia* Image::ToImageSkia() const {
internal::ImageSkiaFromPNG(png_rep->image_reps()));
break;
}
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* native_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- rep = new internal::ImageRepSkia(new ImageSkia(
- internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* native_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -658,47 +543,6 @@ const ImageSkia* Image::ToImageSkia() const {
return rep->AsImageRepSkia()->image();
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::ToGdkPixbuf() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
- if (!rep) {
- switch (DefaultRepresentationType()) {
- case kImageRepPNG: {
- internal::ImageRepPNG* png_rep =
- GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
- rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
- png_rep->image_reps()));
- break;
- }
- case kImageRepSkia: {
- internal::ImageRepSkia* skia_rep =
- GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
- rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
- *skia_rep->image()->bitmap()));
- break;
- }
- default:
- NOTREACHED();
- }
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepGdk()->pixbuf();
-}
-
-CairoCachedSurface* const Image::ToCairo() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
- if (!rep) {
- // Handle any-to-Cairo conversion. This may create and cache an intermediate
- // pixbuf before sending the data to the display server.
- rep = new internal::ImageRepCairo(ToGdkPixbuf());
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepCairo()->surface();
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::ToUIImage() const {
internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
@@ -768,7 +612,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
if (rep) {
- const std::vector<gfx::ImagePNGRep>& image_png_reps =
+ const std::vector<ImagePNGRep>& image_png_reps =
rep->AsImageRepPNG()->image_reps();
for (size_t i = 0; i < image_png_reps.size(); ++i) {
if (image_png_reps[i].scale == 1.0f)
@@ -779,14 +623,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
switch (DefaultRepresentationType()) {
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* gdk_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf());
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* cocoa_touch_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -826,7 +663,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
// final type eg (converting from ImageRepSkia to ImageRepPNG to get an
// ImageRepCocoa).
std::vector<ImagePNGRep> image_png_reps;
- image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f));
+ image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
rep = new internal::ImageRepPNG(image_png_reps);
AddRepresentation(rep);
return png_bytes;
@@ -861,14 +698,6 @@ SkBitmap* Image::CopySkBitmap() const {
return new SkBitmap(*ToSkBitmap());
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::CopyGdkPixbuf() const {
- GdkPixbuf* pixbuf = ToGdkPixbuf();
- g_object_ref(pixbuf);
- return pixbuf;
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::CopyUIImage() const {
UIImage* image = ToUIImage();
@@ -916,7 +745,7 @@ gfx::Size Image::Size() const {
return GetRepresentation(DefaultRepresentationType(), true)->Size();
}
-void Image::SwapRepresentations(gfx::Image* other) {
+void Image::SwapRepresentations(Image* other) {
storage_.swap(other->storage_);
}
@@ -929,11 +758,7 @@ void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
Image::RepresentationType Image::DefaultRepresentationType() const {
CHECK(storage_.get());
- RepresentationType default_type = storage_->default_representation_type();
- // The conversions above assume that the default representation type is never
- // kImageRepCairo.
- DCHECK_NE(default_type, kImageRepCairo);
- return default_type;
+ return storage_->default_representation_type();
}
internal::ImageRep* Image::GetRepresentation(
diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h
index d4093b74063..19ca93dada9 100644
--- a/chromium/ui/gfx/image/image.h
+++ b/chromium/ui/gfx/image/image.h
@@ -44,10 +44,6 @@ struct ImagePNGRep;
class ImageSkia;
class Size;
-#if defined(TOOLKIT_GTK)
-class CairoCachedSurface;
-#endif
-
namespace internal {
class ImageRep;
class ImageStorage;
@@ -56,10 +52,8 @@ class ImageStorage;
class GFX_EXPORT Image {
public:
enum RepresentationType {
- kImageRepGdk,
kImageRepCocoa,
kImageRepCocoaTouch,
- kImageRepCairo,
kImageRepSkia,
kImageRepPNG,
};
@@ -77,10 +71,7 @@ class GFX_EXPORT Image {
// representation.
explicit Image(const ImageSkia& image);
-#if defined(TOOLKIT_GTK)
- // Does not increase |pixbuf|'s reference count; expects to take ownership.
- explicit Image(GdkPixbuf* pixbuf);
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
// Does not retain |image|; expects to take ownership.
explicit Image(UIImage* image);
#elif defined(OS_MACOSX)
@@ -113,15 +104,16 @@ class GFX_EXPORT Image {
static Image CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size);
+ // Creates an image from the PNG encoded input.
+ static Image CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input);
+
// Converts the Image to the desired representation and stores it internally.
// The returned result is a weak pointer owned by and scoped to the life of
// the Image. Must only be called if IsEmpty() is false.
const SkBitmap* ToSkBitmap() const;
const ImageSkia* ToImageSkia() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* ToGdkPixbuf() const;
- CairoCachedSurface* const ToCairo() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* ToUIImage() const;
#elif defined(OS_MACOSX)
NSImage* ToNSImage() const;
@@ -154,9 +146,7 @@ class GFX_EXPORT Image {
scoped_refptr<base::RefCountedMemory> Copy1xPNGBytes() const;
ImageSkia* CopyImageSkia() const;
SkBitmap* CopySkBitmap() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* CopyGdkPixbuf() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* CopyUIImage() const;
#elif defined(OS_MACOSX)
NSImage* CopyNSImage() const;
diff --git a/chromium/ui/gfx/image/image_skia.cc b/chromium/ui/gfx/image/image_skia.cc
index a283117db24..21d08de3003 100644
--- a/chromium/ui/gfx/image/image_skia.cc
+++ b/chromium/ui/gfx/image/image_skia.cc
@@ -8,14 +8,17 @@
#include <cmath>
#include <limits>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
namespace gfx {
namespace {
@@ -27,6 +30,13 @@ gfx::ImageSkiaRep& NullImageRep() {
}
std::vector<float>* g_supported_scales = NULL;
+
+// The difference to fall back to the smaller scale factor rather than the
+// larger one. For example, assume 1.25 is requested but only 1.0 and 2.0 are
+// supported. In that case, not fall back to 2.0 but 1.0, and then expand
+// the image to 1.25.
+const float kFallbackToSmallerScaleDiff = 0.25f;
+
} // namespace
namespace internal {
@@ -102,12 +112,36 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
return (read_only_ && !source_.get()) || CalledOnValidThread();
}
+ // Add a new representation. This checks if the scale of the added image
+ // is not 1.0f, and mark the existing rep as scaled to make
+ // the image high DPI aware.
+ void AddRepresentation(const ImageSkiaRep& image) {
+ if (image.scale() != 1.0f) {
+ for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin();
+ it < image_reps_.end();
+ ++it) {
+ if (it->unscaled()) {
+ DCHECK_EQ(1.0f, it->scale());
+ it->SetScaled();
+ break;
+ }
+ }
+ }
+ image_reps_.push_back(image);
+ }
+
// Returns the iterator of the image rep whose density best matches
// |scale|. If the image for the |scale| doesn't exist in the storage and
// |storage| is set, it fetches new image by calling
- // |ImageSkiaSource::GetImageForScale|. If the source returns the image with
- // different scale (if the image doesn't exist in resource, for example), it
- // will fallback to closest image rep.
+ // |ImageSkiaSource::GetImageForScale|. There are two modes to deal with
+ // arbitrary scale factors.
+ // 1: Invoke GetImageForScale with requested scale and if the source
+ // returns the image with different scale (if the image doesn't exist in
+ // resource, for example), it will fallback to closest image rep.
+ // 2: Invoke GetImageForScale with the closest known scale to the requested
+ // one and rescale the image.
+ // Right now only Windows uses 2 and other platforms use 1 by default.
+ // TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms.
std::vector<ImageSkiaRep>::iterator FindRepresentation(
float scale, bool fetch_new_image) const {
ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);
@@ -139,7 +173,47 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
DCHECK(CalledOnValidThread()) <<
"An ImageSkia with the source must be accessed by the same thread.";
- ImageSkiaRep image = source_->GetImageForScale(scale);
+ ImageSkiaRep image;
+ float resource_scale = scale;
+ if (ImageSkia::IsDSFScalingInImageSkiaEnabled() && g_supported_scales) {
+ if (g_supported_scales->back() <= scale) {
+ resource_scale = g_supported_scales->back();
+ } else {
+ for (size_t i = 0; i < g_supported_scales->size(); ++i) {
+ if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >=
+ scale) {
+ resource_scale = (*g_supported_scales)[i];
+ break;
+ }
+ }
+ }
+ }
+ if (ImageSkia::IsDSFScalingInImageSkiaEnabled() &&
+ scale != resource_scale) {
+ std::vector<ImageSkiaRep>::iterator iter = FindRepresentation(
+ resource_scale, fetch_new_image);
+
+ DCHECK(iter != image_reps_.end());
+
+ if (!iter->unscaled()) {
+ SkBitmap scaled_image;
+ gfx::Size unscaled_size(iter->pixel_width(), iter->pixel_height());
+ gfx::Size scaled_size = ToCeiledSize(
+ gfx::ScaleSize(unscaled_size, scale / iter->scale()));
+
+ image = ImageSkiaRep(skia::ImageOperations::Resize(
+ iter->sk_bitmap(),
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ scaled_size.width(),
+ scaled_size.height()), scale);
+ DCHECK_EQ(image.pixel_width(), scaled_size.width());
+ DCHECK_EQ(image.pixel_height(), scaled_size.height());
+ } else {
+ image = *iter;
+ }
+ } else {
+ image = source_->GetImageForScale(scale);
+ }
// If the source returned the new image, store it.
if (!image.is_null() &&
@@ -240,7 +314,13 @@ float ImageSkia::GetMaxSupportedScale() {
// static
ImageSkia ImageSkia::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return ImageSkia(ImageSkiaRep(bitmap, 1.0f));
+ return ImageSkia(ImageSkiaRep(bitmap, 0.0f));
+}
+
+bool ImageSkia::IsDSFScalingInImageSkiaEnabled() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ return !command_line->HasSwitch(
+ switches::kDisableArbitraryScaleFactorInImageSkia);
}
scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const {
@@ -278,7 +358,9 @@ void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
Init(image_rep);
} else {
CHECK(CanModify());
- storage_->image_reps().push_back(image_rep);
+ // If someone is adding ImageSkia explicitly, check if we should
+ // make the image high DPI aware.
+ storage_->AddRepresentation(image_rep);
}
}
diff --git a/chromium/ui/gfx/image/image_skia.h b/chromium/ui/gfx/image/image_skia.h
index fa5d070ad9b..8765457b432 100644
--- a/chromium/ui/gfx/image/image_skia.h
+++ b/chromium/ui/gfx/image/image_skia.h
@@ -78,6 +78,10 @@ class GFX_EXPORT ImageSkia {
// density display.
static ImageSkia CreateFrom1xBitmap(const SkBitmap& bitmap);
+ // Returns true when ImageSkia looks up the resource pack with the closest
+ // scale factor and rescale the fetched image.
+ static bool IsDSFScalingInImageSkiaEnabled();
+
// Returns a deep copy of this ImageSkia which has its own storage with
// the ImageSkiaRep instances that this ImageSkia currently has.
// This can be safely passed to and manipulated by another thread.
diff --git a/chromium/ui/gfx/image/image_skia_rep.cc b/chromium/ui/gfx/image/image_skia_rep.cc
index f8f3acb1946..f31db600465 100644
--- a/chromium/ui/gfx/image/image_skia_rep.cc
+++ b/chromium/ui/gfx/image/image_skia_rep.cc
@@ -4,9 +4,11 @@
#include "ui/gfx/image/image_skia_rep.h"
+#include "base/logging.h"
+
namespace gfx {
-ImageSkiaRep::ImageSkiaRep() : scale_(1.0f) {
+ImageSkiaRep::ImageSkiaRep() : scale_(0.0f) {
}
ImageSkiaRep::~ImageSkiaRep() {
@@ -14,9 +16,10 @@ ImageSkiaRep::~ImageSkiaRep() {
ImageSkiaRep::ImageSkiaRep(const gfx::Size& size, float scale) : scale_(scale) {
bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
- static_cast<int>(size.width() * scale),
- static_cast<int>(size.height() * scale));
+ static_cast<int>(size.width() * this->scale()),
+ static_cast<int>(size.height() * this->scale()));
bitmap_.allocPixels();
+ bitmap_.eraseColor(SK_ColorRED);
}
ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
@@ -25,11 +28,17 @@ ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
}
int ImageSkiaRep::GetWidth() const {
- return static_cast<int>(bitmap_.width() / scale_);
+ return static_cast<int>(bitmap_.width() / scale());
}
int ImageSkiaRep::GetHeight() const {
- return static_cast<int>(bitmap_.height() / scale_);
+ return static_cast<int>(bitmap_.height() / scale());
+}
+
+void ImageSkiaRep::SetScaled() {
+ DCHECK_EQ(0.0f, scale_);
+ if (scale_ == 0.0f)
+ scale_ = 1.0f;
}
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_rep.h b/chromium/ui/gfx/image/image_skia_rep.h
index 7a1e83709ab..47f6713acf5 100644
--- a/chromium/ui/gfx/image/image_skia_rep.h
+++ b/chromium/ui/gfx/image/image_skia_rep.h
@@ -12,14 +12,20 @@
namespace gfx {
// An ImageSkiaRep represents a bitmap and the scale factor it is intended for.
+// 0.0f scale is used to indicate that this ImageSkiaRep is used for unscaled
+// image (the image that only returns 1.0f scale image).
class GFX_EXPORT ImageSkiaRep {
public:
// Create null bitmap.
ImageSkiaRep();
~ImageSkiaRep();
+ // Note: This is for testing purpose only.
// Creates a bitmap with kARGB_8888_Config config with given |size| in DIP.
- // This allocates pixels in the bitmap.
+ // This allocates pixels in the bitmap. It is guaranteed that the data in the
+ // bitmap are initialized but the actual values are undefined.
+ // Specifying 0 scale means the image is for unscaled image. (unscaled()
+ // returns truen, and scale() returns 1.0f;)
ImageSkiaRep(const gfx::Size& size, float scale);
// Creates a bitmap with given scale.
@@ -41,7 +47,12 @@ class GFX_EXPORT ImageSkiaRep {
}
// Retrieves the scale that the bitmap will be painted at.
- float scale() const { return scale_; }
+ float scale() const { return unscaled() ? 1.0f : scale_; }
+
+ bool unscaled() const { return scale_ == 0.0f; }
+
+ // Mark the image to be used as scaled image.
+ void SetScaled();
// Returns backing bitmap.
const SkBitmap& sk_bitmap() const { return bitmap_; }
@@ -51,6 +62,7 @@ class GFX_EXPORT ImageSkiaRep {
SkBitmap& mutable_sk_bitmap() { return bitmap_; }
SkBitmap bitmap_;
+
float scale_;
};
diff --git a/chromium/ui/gfx/image/image_skia_unittest.cc b/chromium/ui/gfx/image/image_skia_unittest.cc
index 0047822122b..e3e93c73b78 100644
--- a/chromium/ui/gfx/image/image_skia_unittest.cc
+++ b/chromium/ui/gfx/image/image_skia_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/gfx/image/image_skia.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,6 +12,7 @@
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
+#include "ui/gfx/switches.h"
// Duplicated from base/threading/non_thread_safe.h so that we can be
// good citizens there and undef the macro.
@@ -43,17 +45,27 @@ class FixedSource : public ImageSkiaSource {
class DynamicSource : public ImageSkiaSource {
public:
- DynamicSource(const gfx::Size& size) : size_(size) {}
+ DynamicSource(const gfx::Size& size)
+ : size_(size),
+ last_requested_scale_(0.0f) {}
virtual ~DynamicSource() {
}
virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ last_requested_scale_ = scale;
return gfx::ImageSkiaRep(size_, scale);
}
+ float GetLastRequestedScaleAndReset() {
+ float result = last_requested_scale_;
+ last_requested_scale_ = 0.0f;
+ return result;
+ }
+
private:
gfx::Size size_;
+ float last_requested_scale_;
DISALLOW_COPY_AND_ASSIGN(DynamicSource);
};
@@ -113,7 +125,28 @@ class TestOnThread : public base::SimpleThread {
} // namespace test
-TEST(ImageSkiaTest, FixedSource) {
+class ImageSkiaTest : public testing::Test {
+ public:
+ ImageSkiaTest() {
+ // In the test, we assume that we support 1.0f and 2.0f DSFs.
+ old_scales_ = ImageSkia::GetSupportedScales();
+
+ // Sets the list of scale factors supported by resource bundle.
+ std::vector<float> supported_scales;
+ supported_scales.push_back(1.0f);
+ supported_scales.push_back(2.0f);
+ ImageSkia::SetSupportedScales(supported_scales);
+ }
+ virtual ~ImageSkiaTest() {
+ ImageSkia::SetSupportedScales(old_scales_);
+ }
+
+ private:
+ std::vector<float> old_scales_;
+ DISALLOW_COPY_AND_ASSIGN(ImageSkiaTest);
+};
+
+TEST_F(ImageSkiaTest, FixedSource) {
ImageSkiaRep image(Size(100, 200), 1.0f);
ImageSkia image_skia(new FixedSource(image), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
@@ -140,7 +173,7 @@ TEST(ImageSkiaTest, FixedSource) {
EXPECT_EQ(1U, image_skia.image_reps().size());
}
-TEST(ImageSkiaTest, DynamicSource) {
+TEST_F(ImageSkiaTest, DynamicSource) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f);
@@ -169,7 +202,7 @@ TEST(ImageSkiaTest, DynamicSource) {
// Tests that image_reps returns all of the representations in the
// image when there are multiple representations for a scale factor.
// This currently is the case with ImageLoader::LoadImages.
-TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
+TEST_F(ImageSkiaTest, ManyRepsPerScaleFactor) {
const int kSmallIcon1x = 16;
const int kSmallIcon2x = 32;
const int kLargeIcon1x = 32;
@@ -204,14 +237,14 @@ TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
EXPECT_EQ(1, num_2x);
}
-TEST(ImageSkiaTest, GetBitmap) {
+TEST_F(ImageSkiaTest, GetBitmap) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
const SkBitmap* bitmap = image_skia.bitmap();
EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap);
EXPECT_FALSE(bitmap->isNull());
}
-TEST(ImageSkiaTest, GetBitmapFromEmpty) {
+TEST_F(ImageSkiaTest, GetBitmapFromEmpty) {
// Create an image with 1 representation and remove it so the ImageSkiaStorage
// is left with no representations.
ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f));
@@ -226,7 +259,7 @@ TEST(ImageSkiaTest, GetBitmapFromEmpty) {
EXPECT_TRUE(bitmap->empty());
}
-TEST(ImageSkiaTest, BackedBySameObjectAs) {
+TEST_F(ImageSkiaTest, BackedBySameObjectAs) {
// Null images should all be backed by the same object (NULL).
ImageSkia image;
ImageSkia unrelated;
@@ -245,7 +278,7 @@ TEST(ImageSkiaTest, BackedBySameObjectAs) {
}
#if ENABLE_NON_THREAD_SAFE
-TEST(ImageSkiaTest, EmptyOnThreadTest) {
+TEST_F(ImageSkiaTest, EmptyOnThreadTest) {
ImageSkia empty;
test::TestOnThread empty_on_thread(&empty);
empty_on_thread.Start();
@@ -254,7 +287,7 @@ TEST(ImageSkiaTest, EmptyOnThreadTest) {
EXPECT_TRUE(empty_on_thread.can_modify());
}
-TEST(ImageSkiaTest, StaticOnThreadTest) {
+TEST_F(ImageSkiaTest, StaticOnThreadTest) {
ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f));
EXPECT_FALSE(image.IsThreadSafe());
@@ -323,7 +356,7 @@ TEST(ImageSkiaTest, StaticOnThreadTest) {
EXPECT_FALSE(image.CanModify());
}
-TEST(ImageSkiaTest, SourceOnThreadTest) {
+TEST_F(ImageSkiaTest, SourceOnThreadTest) {
ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_FALSE(image.IsThreadSafe());
@@ -375,4 +408,136 @@ TEST(ImageSkiaTest, SourceOnThreadTest) {
// Just in case we ever get lumped together with other compilation units.
#undef ENABLE_NON_THREAD_SAFE
+TEST_F(ImageSkiaTest, Unscaled) {
+ SkBitmap bitmap;
+
+ // An ImageSkia created with 1x bitmap is unscaled.
+ ImageSkia image_skia = ImageSkia::CreateFrom1xBitmap(bitmap);
+ EXPECT_TRUE(image_skia.GetRepresentation(1.0f).unscaled());
+ ImageSkiaRep rep_2x(Size(100, 100), 2.0f);
+
+ // When reps for other scales are added, the unscaled image
+ // becomes scaled.
+ image_skia.AddRepresentation(rep_2x);
+ EXPECT_FALSE(image_skia.GetRepresentation(1.0f).unscaled());
+ EXPECT_FALSE(image_skia.GetRepresentation(2.0f).unscaled());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // source is owned by |image|
+ DynamicSource* source = new DynamicSource(Size(100, 200));
+ ImageSkia image(source, gfx::Size(100, 200));
+
+ image.GetRepresentation(1.5f);
+ EXPECT_EQ(2.0f, source->GetLastRequestedScaleAndReset());
+ std::vector<ImageSkiaRep> image_reps = image.image_reps();
+ EXPECT_EQ(2u, image_reps.size());
+
+ std::vector<float> scale_factors;
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(2.0f, scale_factors[1]);
+
+ // Requesting 1.75 scale factor also falls back to 2.0f and rescale.
+ // However, the image already has the 2.0f data, so it won't fetch again.
+ image.GetRepresentation(1.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(3u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(1.75f, scale_factors[1]);
+ EXPECT_EQ(2.0f, scale_factors[2]);
+
+ // 1.25 is falled back to 1.0.
+ image.GetRepresentation(1.25f);
+ EXPECT_EQ(1.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(5u, image_reps.size());
+
+ // Scale factor less than 1.0f will be falled back to 1.0f
+ image.GetRepresentation(0.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(6u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(0.75f, scale_factors[0]);
+ EXPECT_EQ(1.0f, scale_factors[1]);
+ EXPECT_EQ(1.25f, scale_factors[2]);
+ EXPECT_EQ(1.5f, scale_factors[3]);
+ EXPECT_EQ(1.75f, scale_factors[4]);
+ EXPECT_EQ(2.0f, scale_factors[5]);
+
+ // Scale factor greater than 2.0f is falled back to 2.0f because it's not
+ // supported.
+ image.GetRepresentation(3.0f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(7u, image_reps.size());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactorWithMissingResource) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 1.0f)), Size(100, 200));
+
+ // Requesting 1.5f -- falls back to 2.0f, but couldn't find. It should
+ // look up 1.0f and then rescale it.
+ const ImageSkiaRep& rep = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.5f, rep.scale());
+ EXPECT_EQ(2U, image.image_reps().size());
+ EXPECT_EQ(1.0f, image.image_reps()[0].scale());
+ EXPECT_EQ(1.5f, image.image_reps()[1].scale());
+}
+
+TEST_F(ImageSkiaTest, UnscaledImageForArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // 0.0f means unscaled.
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 0.0f)), Size(100, 200));
+
+ // Requesting 2.0f, which should return 1.0f unscaled image.
+ const ImageSkiaRep& rep = image.GetRepresentation(2.0f);
+ EXPECT_EQ(1.0f, rep.scale());
+ EXPECT_EQ("100x200", rep.pixel_size().ToString());
+ EXPECT_TRUE(rep.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ // Same for any other scale factors.
+ const ImageSkiaRep& rep15 = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.0f, rep15.scale());
+ EXPECT_EQ("100x200", rep15.pixel_size().ToString());
+ EXPECT_TRUE(rep15.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ const ImageSkiaRep& rep12 = image.GetRepresentation(1.2f);
+ EXPECT_EQ(1.0f, rep12.scale());
+ EXPECT_EQ("100x200", rep12.pixel_size().ToString());
+ EXPECT_TRUE(rep12.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.h b/chromium/ui/gfx/image/image_skia_util_mac.h
index 553c3f8741d..fc6a65fb027 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.h
+++ b/chromium/ui/gfx/image/image_skia_util_mac.h
@@ -31,10 +31,6 @@ GFX_EXPORT gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image);
GFX_EXPORT gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
NSSize size);
-// Resizes |[NSImage imageNamed:@NSApplicationIcon]| to have edge width of
-// |size| DIP and returns result as ImageSkia.
-GFX_EXPORT gfx::ImageSkia ApplicationIconAtSize(int size);
-
// Converts to NSImage from ImageSkia.
GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.mm b/chromium/ui/gfx/image/image_skia_util_mac.mm
index 281badc7423..26c067331a7 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.mm
+++ b/chromium/ui/gfx/image/image_skia_util_mac.mm
@@ -78,12 +78,6 @@ gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
return image_skia;
}
-gfx::ImageSkia ApplicationIconAtSize(int desired_size) {
- NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
- return ImageSkiaFromResizedNSImage(image,
- NSMakeSize(desired_size, desired_size));
-}
-
NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) {
if (image_skia.isNull())
return nil;
diff --git a/chromium/ui/gfx/image/image_unittest.cc b/chromium/ui/gfx/image/image_unittest.cc
index 039cb13f606..ca9efa0003c 100644
--- a/chromium/ui/gfx/image/image_unittest.cc
+++ b/chromium/ui/gfx/image/image_unittest.cc
@@ -10,10 +10,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "skia/ext/skia_utils_ios.h"
#elif defined(OS_MACOSX)
@@ -75,7 +72,7 @@ TEST_F(ImageTest, EmptyImage) {
// Test constructing a gfx::Image from an empty PlatformImage.
TEST_F(ImageTest, EmptyImageFromEmptyPlatformImage) {
-#if defined(OS_IOS) || defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_IOS) || defined(OS_MACOSX)
gfx::Image image1(NULL);
EXPECT_TRUE(image1.IsEmpty());
EXPECT_EQ(0, image1.Width());
@@ -246,12 +243,24 @@ TEST_F(ImageTest, MultiResolutionPNGToImageSkia) {
scales.push_back(1.0f);
scales.push_back(2.0f);
gfx::ImageSkia image_skia = image.AsImageSkia();
- EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
- scales));
EXPECT_TRUE(gt::IsEqual(bytes1x,
image_skia.GetRepresentation(1.0f).sk_bitmap()));
EXPECT_TRUE(gt::IsEqual(bytes2x,
image_skia.GetRepresentation(2.0f).sk_bitmap()));
+ EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
+ scales));
+#if !defined(OS_IOS)
+ // IOS does not support arbitrary scale factors.
+ gfx::ImageSkiaRep rep_1_6x = image_skia.GetRepresentation(1.6f);
+ ASSERT_FALSE(rep_1_6x.is_null());
+ ASSERT_EQ(1.6f, rep_1_6x.scale());
+ EXPECT_EQ("40x40", rep_1_6x.pixel_size().ToString());
+
+ gfx::ImageSkiaRep rep_0_8x = image_skia.GetRepresentation(0.8f);
+ ASSERT_FALSE(rep_0_8x.is_null());
+ ASSERT_EQ(0.8f, rep_0_8x.scale());
+ EXPECT_EQ("20x20", rep_0_8x.pixel_size().ToString());
+#endif
}
TEST_F(ImageTest, MultiResolutionPNGToPlatform) {
@@ -436,27 +445,6 @@ TEST_F(ImageTest, PlatformToSkiaToCopy) {
delete bitmap;
}
-#if defined(TOOLKIT_GTK)
-TEST_F(ImageTest, SkiaToGdkCopy) {
- GdkPixbuf* pixbuf;
-
- {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- pixbuf = image.CopyGdkPixbuf();
- }
-
- EXPECT_TRUE(pixbuf);
- g_object_unref(pixbuf);
-}
-
-TEST_F(ImageTest, SkiaToCairoCreatesGdk) {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- EXPECT_FALSE(image.HasRepresentation(gfx::Image::kImageRepGdk));
- EXPECT_TRUE(image.ToCairo());
- EXPECT_TRUE(image.HasRepresentation(gfx::Image::kImageRepGdk));
-}
-#endif
-
#if defined(OS_IOS)
TEST_F(ImageTest, SkiaToCocoaTouchCopy) {
UIImage* ui_image;
@@ -495,9 +483,8 @@ TEST_F(ImageTest, SkBitmapConversionPreservesOrientation) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.allocN32Pixels(width, height);
+ bitmap.eraseARGB(255, 0, 255, 0);
// Paint the upper half of the image in red (lower half is in green).
SkCanvas canvas(bitmap);
@@ -538,9 +525,7 @@ TEST_F(ImageTest, SkBitmapConversionPreservesTransparency) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
- kPremul_SkAlphaType);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(width, height);
bitmap.eraseARGB(0, 0, 255, 0);
// Paint the upper half of the image in red (lower half is transparent).
diff --git a/chromium/ui/gfx/image/image_unittest_util.cc b/chromium/ui/gfx/image/image_unittest_util.cc
index 4baf30a4cc6..e9a003216d9 100644
--- a/chromium/ui/gfx/image/image_unittest_util.cc
+++ b/chromium/ui/gfx/image/image_unittest_util.cc
@@ -15,10 +15,7 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_ios.h"
@@ -59,7 +56,7 @@ const SkBitmap CreateBitmap(int width, int height) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.eraseARGB(255, 0, 255, 0);
return bitmap;
}
@@ -83,6 +80,8 @@ gfx::Image CreateImage(int width, int height) {
}
bool IsEqual(const gfx::Image& img1, const gfx::Image& img2) {
+ img1.AsImageSkia().EnsureRepsForSupportedScales();
+ img2.AsImageSkia().EnsureRepsForSupportedScales();
std::vector<gfx::ImageSkiaRep> img1_reps = img1.AsImageSkia().image_reps();
gfx::ImageSkia image_skia2 = img2.AsImageSkia();
if (image_skia2.image_reps().size() != img1_reps.size())
@@ -192,8 +191,6 @@ PlatformImage CreatePlatformImage() {
NSImage* image = gfx::SkBitmapToNSImage(bitmap);
base::mac::NSObjectRetain(image);
return image;
-#elif defined(TOOLKIT_GTK)
- return gfx::GdkPixbufFromSkBitmap(bitmap);
#else
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
#endif
@@ -204,8 +201,6 @@ gfx::Image::RepresentationType GetPlatformRepresentationType() {
return gfx::Image::kImageRepCocoaTouch;
#elif defined(OS_MACOSX)
return gfx::Image::kImageRepCocoa;
-#elif defined(TOOLKIT_GTK)
- return gfx::Image::kImageRepGdk;
#else
return gfx::Image::kImageRepSkia;
#endif
@@ -216,8 +211,6 @@ PlatformImage ToPlatformType(const gfx::Image& image) {
return image.ToUIImage();
#elif defined(OS_MACOSX)
return image.ToNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.ToGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -228,8 +221,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
return image.CopyUIImage();
#elif defined(OS_MACOSX)
return image.CopyNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.CopyGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -237,16 +228,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
#if defined(OS_MACOSX)
// Defined in image_unittest_util_mac.mm.
-#elif defined(TOOLKIT_GTK)
-SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
- int n_channels = gdk_pixbuf_get_n_channels(image);
- int rowstride = gdk_pixbuf_get_rowstride(image);
- guchar* gdk_pixels = gdk_pixbuf_get_pixels(image);
-
- guchar* pixel = gdk_pixels + (y * rowstride) + (x * n_channels);
- guchar alpha = gdk_pixbuf_get_has_alpha(image) ? pixel[3] : 255;
- return SkColorSetARGB(alpha, pixel[0], pixel[1], pixel[2]);
-}
#else
SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
SkBitmap bitmap = *image.bitmap();
@@ -264,7 +245,7 @@ void CheckIsTransparent(SkColor color) {
}
bool IsPlatformImageValid(PlatformImage image) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image != NULL;
#else
return !image.isNull();
@@ -272,7 +253,7 @@ bool IsPlatformImageValid(PlatformImage image) {
}
bool PlatformImagesEqual(PlatformImage image1, PlatformImage image2) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image1 == image2;
#else
return image1.BackedBySameObjectAs(image2);
diff --git a/chromium/ui/gfx/image/image_unittest_util.h b/chromium/ui/gfx/image/image_unittest_util.h
index 4788e4e1009..cac8015eb16 100644
--- a/chromium/ui/gfx/image/image_unittest_util.h
+++ b/chromium/ui/gfx/image/image_unittest_util.h
@@ -18,8 +18,6 @@ namespace test {
typedef UIImage* PlatformImage;
#elif defined(OS_MACOSX)
typedef NSImage* PlatformImage;
-#elif defined(TOOLKIT_GTK)
-typedef GdkPixbuf* PlatformImage;
#else
typedef gfx::ImageSkia PlatformImage;
#endif
diff --git a/chromium/ui/gfx/image/image_util.cc b/chromium/ui/gfx/image/image_util.cc
index 59d631d171d..89a3f8c03b8 100644
--- a/chromium/ui/gfx/image/image_util.cc
+++ b/chromium/ui/gfx/image/image_util.cc
@@ -12,6 +12,8 @@
namespace gfx {
+const uint32_t kMinimumVisibleOpacity = 12;
+
// The iOS implementations of the JPEG functions are in image_util_ios.mm.
#if !defined(OS_IOS)
Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
@@ -24,7 +26,7 @@ Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
}
bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
- std::vector<unsigned char>* dst) {
+ std::vector<unsigned char>* dst) {
const gfx::ImageSkiaRep& image_skia_rep =
image.AsImageSkia().GetRepresentation(1.0f);
if (image_skia_rep.scale() != 1.0f)
@@ -45,4 +47,57 @@ bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
}
#endif // !defined(OS_IOS)
+bool VisibleMargins(const ImageSkia& image, int* leading, int* trailing) {
+ *leading = 0;
+ *trailing = std::max(1, image.width()) - 1;
+ if (!image.HasRepresentation(1.0))
+ return false;
+
+ const ImageSkiaRep& rep = image.GetRepresentation(1.0);
+ if (rep.is_null())
+ return false;
+
+ const SkBitmap& bitmap = rep.sk_bitmap();
+ if (bitmap.isNull() || bitmap.width() == 0)
+ return false;
+
+ if (bitmap.isOpaque())
+ return true;
+
+ SkAutoLockPixels l(bitmap);
+ int inner_min = bitmap.width();
+ for (int x = 0; x < bitmap.width(); ++x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_min = x;
+ break;
+ }
+ }
+ if (inner_min < bitmap.width())
+ break;
+ }
+
+ int inner_max = -1;
+ for (int x = bitmap.width() - 1; x > inner_min; --x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_max = x;
+ break;
+ }
+ }
+ if (inner_max > -1)
+ break;
+ }
+
+ if (inner_min == bitmap.width()) {
+ *leading = bitmap.width()/2;
+ *trailing = bitmap.width()/2 + 1;
+ return true;
+ }
+
+ *leading = inner_min;
+ *trailing = inner_max;
+ return true;
}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_util.h b/chromium/ui/gfx/image/image_util.h
index f33835ca232..2711850dc96 100644
--- a/chromium/ui/gfx/image/image_util.h
+++ b/chromium/ui/gfx/image/image_util.h
@@ -12,6 +12,7 @@
namespace gfx {
class Image;
+class ImageSkia;
}
namespace gfx {
@@ -31,6 +32,22 @@ GFX_EXPORT bool JPEG1xEncodedDataFromImage(const Image& image,
int quality,
std::vector<unsigned char>* dst);
+// Returns the visible (non-transparent) width of the 1x rep of the given
+// image. If the image has no transparency, the leading value will be 0 and
+// the trailing will be the image width. Return values are in the 1x width
+// pixel units. Margins are given in 0-based column format. So if the image
+// has only transparent pixels in columns 0, 1, 2, 3, then the leading value
+// will be 4. Similarly, if there are all transparent pixels in column
+// width-2, width-1, then the trailing margin value will be width-3.
+// Returns true if the value is computed from opacity, false if it is a
+// default value because of null image, missing Rep, etc.
+// This method is only suitable for fairly small images (i.e. 16x16).
+// The margins for a completely transparent image will be w/2-1, w/2, but this
+// will be an expensive operation: it isn't expected that it will be frequently
+// calculated.
+GFX_EXPORT bool VisibleMargins(const ImageSkia& image,
+ int* leading, int* trailing);
+
} // namespace gfx
#endif // UI_GFX_IMAGE_IMAGE_UTIL_H_
diff --git a/chromium/ui/gfx/image/image_util_unittest.cc b/chromium/ui/gfx/image/image_util_unittest.cc
index cd9d74898f6..74c39e68fa4 100644
--- a/chromium/ui/gfx/image/image_util_unittest.cc
+++ b/chromium/ui/gfx/image/image_util_unittest.cc
@@ -9,6 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
TEST(ImageUtilTest, JPEGEncodeAndDecode) {
@@ -23,3 +25,79 @@ TEST(ImageUtilTest, JPEGEncodeAndDecode) {
// JPEG is lossy, so simply check that the image decoded successfully.
EXPECT_FALSE(decoded.IsEmpty());
}
+
+TEST(ImageUtilTest, TestVisibleMargins) {
+ // Image with non-transparent piece should return margins at those
+ // columns.
+ SkBitmap bitmap1;
+ bitmap1.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap1.allocPixels();
+ bitmap1.eraseColor(SK_ColorTRANSPARENT);
+ bitmap1.eraseArea(SkIRect::MakeLTRB(3, 3, 14, 14), SK_ColorYELLOW);
+ gfx::ImageSkia img = gfx::ImageSkia::CreateFrom1xBitmap(bitmap1);
+ int x = 0;
+ int y = 0;
+ gfx::VisibleMargins(img, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(13, y);
+ EXPECT_EQ(16, img.width());
+
+ // Full-width-transparent image should return margins in the center
+ // of the image.
+ SkBitmap bitmap2;
+ bitmap2.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap2.allocPixels();
+ bitmap2.eraseColor(SK_ColorTRANSPARENT);
+ gfx::ImageSkia img_transparent = gfx::ImageSkia::CreateFrom1xBitmap(bitmap2);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img_transparent, &x, &y);
+ EXPECT_EQ(8, x);
+ EXPECT_EQ(9, y);
+ EXPECT_EQ(16, img_transparent.width());
+
+ // Image with non-transparent piece that is skewed to one side should
+ // return margins at those columns.
+ SkBitmap bitmap3;
+ bitmap3.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap3.allocPixels();
+ bitmap3.eraseColor(SK_ColorTRANSPARENT);
+ bitmap3.eraseArea(SkIRect::MakeLTRB(3, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img3 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap3);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img3, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img3.width());
+
+ // Image with non-transparent piece that is at one edge should
+ // return margins at those columns.
+ SkBitmap bitmap4;
+ bitmap4.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap4.allocPixels();
+ bitmap4.eraseColor(SK_ColorTRANSPARENT);
+ bitmap4.eraseArea(SkIRect::MakeLTRB(0, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img4 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap4);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img4, &x, &y);
+ EXPECT_EQ(0, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img4.width());
+
+ // Image with non-transparent piece that is at trailing edge should
+ // return margins at those columns.
+ SkBitmap bitmap5;
+ bitmap5.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap5.allocPixels();
+ bitmap5.eraseColor(SK_ColorTRANSPARENT);
+ bitmap5.eraseArea(SkIRect::MakeLTRB(4, 3, 16, 16), SK_ColorYELLOW);
+ gfx::ImageSkia img5 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap5);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img5, &x, &y);
+ EXPECT_EQ(4, x);
+ EXPECT_EQ(15, y);
+ EXPECT_EQ(16, img5.width());
+}
diff --git a/chromium/ui/gfx/insets.cc b/chromium/ui/gfx/insets.cc
deleted file mode 100644
index 44a29916acf..00000000000
--- a/chromium/ui/gfx/insets.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/insets.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#endif
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class InsetsBase<Insets, int>;
-
-Insets::Insets() : InsetsBase<Insets, int>(0, 0, 0, 0) {}
-
-Insets::Insets(int top, int left, int bottom, int right)
- : InsetsBase<Insets, int>(top, left, bottom, right) {}
-
-#if defined(TOOLKIT_GTK)
-Insets::Insets(const GtkBorder& border)
- : InsetsBase<Insets, int>(border.top,
- border.left,
- border.bottom,
- border.right) {
-}
-#endif
-
-Insets::~Insets() {}
-
-std::string Insets::ToString() const {
- // Print members in the same order of the constructor parameters.
- return base::StringPrintf("%d,%d,%d,%d", top(), left(), bottom(), right());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/insets.h b/chromium/ui/gfx/insets.h
index a419059a55d..aa4b9eb5270 100644
--- a/chromium/ui/gfx/insets.h
+++ b/chromium/ui/gfx/insets.h
@@ -1,52 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_INSETS_H_
-#define UI_GFX_INSETS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/insets.h"
-#include <string>
-
-#include "build/build_config.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/insets_base.h"
-
-#if defined(TOOLKIT_GTK)
-typedef struct _GtkBorder GtkBorder;
-#endif
-
-namespace gfx {
-
-// An integer version of gfx::Insets.
-class GFX_EXPORT Insets : public InsetsBase<Insets, int> {
- public:
- Insets();
- Insets(int top, int left, int bottom, int right);
-#if defined(TOOLKIT_GTK)
- explicit Insets(const GtkBorder& border);
-#endif
-
- ~Insets();
-
- Insets Scale(float scale) const {
- return Scale(scale, scale);
- }
-
- Insets Scale(float x_scale, float y_scale) const {
- return Insets(static_cast<int>(top() * y_scale),
- static_cast<int>(left() * x_scale),
- static_cast<int>(bottom() * y_scale),
- static_cast<int>(right() * x_scale));
- }
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-};
-
-#if !defined(COMPILER_MSVC)
-extern template class InsetsBase<Insets, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_INSETS_H_
diff --git a/chromium/ui/gfx/insets_base.h b/chromium/ui/gfx/insets_base.h
deleted file mode 100644
index da7aca103e5..00000000000
--- a/chromium/ui/gfx/insets_base.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_INSETS_BASE_H_
-#define UI_GFX_INSETS_BASE_H_
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// An insets represents the borders of a container (the space the container must
-// leave at each of its edges).
-template<typename Class, typename Type>
-class GFX_EXPORT InsetsBase {
- public:
- Type top() const { return top_; }
- Type left() const { return left_; }
- Type bottom() const { return bottom_; }
- Type right() const { return right_; }
-
- // Returns the total width taken up by the insets, which is the sum of the
- // left and right insets.
- Type width() const { return left_ + right_; }
-
- // Returns the total height taken up by the insets, which is the sum of the
- // top and bottom insets.
- Type height() const { return top_ + bottom_; }
-
- // Returns true if the insets are empty.
- bool empty() const { return width() == 0 && height() == 0; }
-
- void Set(Type top, Type left, Type bottom, Type right) {
- top_ = top;
- left_ = left;
- bottom_ = bottom;
- right_ = right;
- }
-
- bool operator==(const Class& insets) const {
- return top_ == insets.top_ && left_ == insets.left_ &&
- bottom_ == insets.bottom_ && right_ == insets.right_;
- }
-
- bool operator!=(const Class& insets) const {
- return !(*this == insets);
- }
-
- void operator+=(const Class& insets) {
- top_ += insets.top_;
- left_ += insets.left_;
- bottom_ += insets.bottom_;
- right_ += insets.right_;
- }
-
- Class operator-() const {
- return Class(-top_, -left_, -bottom_, -right_);
- }
-
- protected:
- InsetsBase(Type top, Type left, Type bottom, Type right)
- : top_(top),
- left_(left),
- bottom_(bottom),
- right_(right) {}
-
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~InsetsBase() {}
-
- private:
- Type top_;
- Type left_;
- Type bottom_;
- Type right_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_INSETS_BASE_H_
diff --git a/chromium/ui/gfx/insets_f.cc b/chromium/ui/gfx/insets_f.cc
deleted file mode 100644
index f790b3c4187..00000000000
--- a/chromium/ui/gfx/insets_f.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/insets_f.h"
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class InsetsBase<InsetsF, float>;
-
-InsetsF::InsetsF() : InsetsBase<InsetsF, float>(0, 0, 0, 0) {}
-
-InsetsF::InsetsF(float top, float left, float bottom, float right)
- : InsetsBase<InsetsF, float>(top, left, bottom, right) {}
-
-InsetsF::~InsetsF() {}
-
-std::string InsetsF::ToString() const {
- // Print members in the same order of the constructor parameters.
- return base::StringPrintf("%f,%f,%f,%f", top(), left(), bottom(), right());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/insets_f.h b/chromium/ui/gfx/insets_f.h
index 43b801dcb22..d6cfd0392af 100644
--- a/chromium/ui/gfx/insets_f.h
+++ b/chromium/ui/gfx/insets_f.h
@@ -1,33 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_INSETS_F_H_
-#define UI_GFX_INSETS_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/insets_f.h"
-#include <string>
-
-#include "build/build_config.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/insets_base.h"
-
-namespace gfx {
-
-// A floating versin of gfx::Insets.
-class GFX_EXPORT InsetsF : public InsetsBase<InsetsF, float> {
- public:
- InsetsF();
- InsetsF(float top, float left, float bottom, float right);
- ~InsetsF();
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-};
-
-#if !defined(COMPILER_MSVC)
-extern template class InsetsBase<InsetsF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_INSETS_F_H_
diff --git a/chromium/ui/gfx/insets_unittest.cc b/chromium/ui/gfx/insets_unittest.cc
deleted file mode 100644
index 563f20fca23..00000000000
--- a/chromium/ui/gfx/insets_unittest.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/insets.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(InsetsTest, InsetsDefault) {
- gfx::Insets insets;
- EXPECT_EQ(0, insets.top());
- EXPECT_EQ(0, insets.left());
- EXPECT_EQ(0, insets.bottom());
- EXPECT_EQ(0, insets.right());
- EXPECT_EQ(0, insets.width());
- EXPECT_EQ(0, insets.height());
- EXPECT_TRUE(insets.empty());
-}
-
-TEST(InsetsTest, Insets) {
- gfx::Insets insets(1, 2, 3, 4);
- EXPECT_EQ(1, insets.top());
- EXPECT_EQ(2, insets.left());
- EXPECT_EQ(3, insets.bottom());
- EXPECT_EQ(4, insets.right());
- EXPECT_EQ(6, insets.width()); // Left + right.
- EXPECT_EQ(4, insets.height()); // Top + bottom.
- EXPECT_FALSE(insets.empty());
-}
-
-TEST(InsetsTest, Set) {
- gfx::Insets insets;
- insets.Set(1, 2, 3, 4);
- EXPECT_EQ(1, insets.top());
- EXPECT_EQ(2, insets.left());
- EXPECT_EQ(3, insets.bottom());
- EXPECT_EQ(4, insets.right());
-}
-
-TEST(InsetsTest, Add) {
- gfx::Insets insets;
- insets.Set(1, 2, 3, 4);
- insets += gfx::Insets(5, 6, 7, 8);
- EXPECT_EQ(6, insets.top());
- EXPECT_EQ(8, insets.left());
- EXPECT_EQ(10, insets.bottom());
- EXPECT_EQ(12, insets.right());
-}
-
-TEST(InsetsTest, Equality) {
- gfx::Insets insets1;
- insets1.Set(1, 2, 3, 4);
- gfx::Insets insets2;
- // Test operator== and operator!=.
- EXPECT_FALSE(insets1 == insets2);
- EXPECT_TRUE(insets1 != insets2);
-
- insets2.Set(1, 2, 3, 4);
- EXPECT_TRUE(insets1 == insets2);
- EXPECT_FALSE(insets1 != insets2);
-}
-
-TEST(InsetsTest, ToString) {
- gfx::Insets insets(1, 2, 3, 4);
- EXPECT_EQ("1,2,3,4", insets.ToString());
-}
diff --git a/chromium/ui/gfx/linux_font_delegate.cc b/chromium/ui/gfx/linux_font_delegate.cc
new file mode 100644
index 00000000000..3dfdf942ece
--- /dev/null
+++ b/chromium/ui/gfx/linux_font_delegate.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/linux_font_delegate.h"
+
+namespace {
+
+gfx::LinuxFontDelegate* g_linux_font_delegate = 0;
+
+} // namespace
+
+namespace gfx {
+
+void LinuxFontDelegate::SetInstance(LinuxFontDelegate* instance) {
+ g_linux_font_delegate = instance;
+}
+
+const LinuxFontDelegate* LinuxFontDelegate::instance() {
+ return g_linux_font_delegate;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/linux_font_delegate.h b/chromium/ui/gfx/linux_font_delegate.h
new file mode 100644
index 00000000000..8a3070bfd7b
--- /dev/null
+++ b/chromium/ui/gfx/linux_font_delegate.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_LINUX_FONT_DELEGATE_H_
+#define UI_GFX_LINUX_FONT_DELEGATE_H_
+
+#include <string>
+
+#include "ui/gfx/font_render_params_linux.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Allows a Linux platform specific overriding of font preferences.
+class GFX_EXPORT LinuxFontDelegate {
+ public:
+ virtual ~LinuxFontDelegate() {}
+
+ // Sets the dynamically loaded singleton that provides font preferences.
+ // This pointer is not owned, and if this method is called a second time,
+ // the first instance is not deleted.
+ static void SetInstance(LinuxFontDelegate* instance);
+
+ // Returns a LinuxFontDelegate instance for the toolkit used in
+ // the user's desktop environment.
+ //
+ // Can return NULL, in case no toolkit has been set. (For example, if we're
+ // running with the "--ash" flag.)
+ static const LinuxFontDelegate* instance();
+
+ // Whether we should antialias our text.
+ virtual bool UseAntialiasing() const = 0;
+
+ // What sort of text hinting should we apply?
+ virtual FontRenderParams::Hinting GetHintingStyle() const = 0;
+
+ // What sort of subpixel rendering should we perform.
+ virtual FontRenderParams::SubpixelRendering
+ GetSubpixelRenderingStyle() const = 0;
+
+ // Returns the default font name for pango style rendering. The format is a
+ // string of the form "[font name] [font size]".
+ virtual std::string GetDefaultFontName() const = 0;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_LINUX_FONT_DELEGATE_H_
diff --git a/chromium/ui/gfx/matrix3_f.cc b/chromium/ui/gfx/matrix3_f.cc
deleted file mode 100644
index 562fdb3a964..00000000000
--- a/chromium/ui/gfx/matrix3_f.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/matrix3_f.h"
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-namespace {
-
-// This is only to make accessing indices self-explanatory.
-enum MatrixCoordinates {
- M00,
- M01,
- M02,
- M10,
- M11,
- M12,
- M20,
- M21,
- M22,
- M_END
-};
-
-template<typename T>
-double Determinant3x3(T data[M_END]) {
- // This routine is separated from the Matrix3F::Determinant because in
- // computing inverse we do want higher precision afforded by the explicit
- // use of 'double'.
- return
- static_cast<double>(data[M00]) * (
- static_cast<double>(data[M11]) * data[M22] -
- static_cast<double>(data[M12]) * data[M21]) +
- static_cast<double>(data[M01]) * (
- static_cast<double>(data[M12]) * data[M20] -
- static_cast<double>(data[M10]) * data[M22]) +
- static_cast<double>(data[M02]) * (
- static_cast<double>(data[M10]) * data[M21] -
- static_cast<double>(data[M11]) * data[M20]);
-}
-
-} // namespace
-
-namespace gfx {
-
-Matrix3F::Matrix3F() {
-}
-
-Matrix3F::~Matrix3F() {
-}
-
-// static
-Matrix3F Matrix3F::Zeros() {
- Matrix3F matrix;
- matrix.set(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
- return matrix;
-}
-
-// static
-Matrix3F Matrix3F::Ones() {
- Matrix3F matrix;
- matrix.set(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
- return matrix;
-}
-
-// static
-Matrix3F Matrix3F::Identity() {
- Matrix3F matrix;
- matrix.set(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
- return matrix;
-}
-
-// static
-Matrix3F Matrix3F::FromOuterProduct(const Vector3dF& a, const Vector3dF& bt) {
- Matrix3F matrix;
- matrix.set(a.x() * bt.x(), a.x() * bt.y(), a.x() * bt.z(),
- a.y() * bt.x(), a.y() * bt.y(), a.y() * bt.z(),
- a.z() * bt.x(), a.z() * bt.y(), a.z() * bt.z());
- return matrix;
-}
-
-bool Matrix3F::IsEqual(const Matrix3F& rhs) const {
- return 0 == memcmp(data_, rhs.data_, sizeof(data_));
-}
-
-bool Matrix3F::IsNear(const Matrix3F& rhs, float precision) const {
- DCHECK(precision >= 0);
- for (int i = 0; i < M_END; ++i) {
- if (std::abs(data_[i] - rhs.data_[i]) > precision)
- return false;
- }
- return true;
-}
-
-Matrix3F Matrix3F::Inverse() const {
- Matrix3F inverse = Matrix3F::Zeros();
- double determinant = Determinant3x3(data_);
- if (std::numeric_limits<float>::epsilon() > std::abs(determinant))
- return inverse; // Singular matrix. Return Zeros().
-
- inverse.set(
- (data_[M11] * data_[M22] - data_[M12] * data_[M21]) / determinant,
- (data_[M02] * data_[M21] - data_[M01] * data_[M22]) / determinant,
- (data_[M01] * data_[M12] - data_[M02] * data_[M11]) / determinant,
- (data_[M12] * data_[M20] - data_[M10] * data_[M22]) / determinant,
- (data_[M00] * data_[M22] - data_[M02] * data_[M20]) / determinant,
- (data_[M02] * data_[M10] - data_[M00] * data_[M12]) / determinant,
- (data_[M10] * data_[M21] - data_[M11] * data_[M20]) / determinant,
- (data_[M01] * data_[M20] - data_[M00] * data_[M21]) / determinant,
- (data_[M00] * data_[M11] - data_[M01] * data_[M10]) / determinant);
- return inverse;
-}
-
-float Matrix3F::Determinant() const {
- return static_cast<float>(Determinant3x3(data_));
-}
-
-Vector3dF Matrix3F::SolveEigenproblem(Matrix3F* eigenvectors) const {
- // The matrix must be symmetric.
- const float epsilon = std::numeric_limits<float>::epsilon();
- if (std::abs(data_[M01] - data_[M10]) > epsilon ||
- std::abs(data_[M02] - data_[M20]) > epsilon ||
- std::abs(data_[M12] - data_[M21]) > epsilon) {
- NOTREACHED();
- return Vector3dF();
- }
-
- float eigenvalues[3];
- float p =
- data_[M01] * data_[M01] +
- data_[M02] * data_[M02] +
- data_[M12] * data_[M12];
-
- bool diagonal = std::abs(p) < epsilon;
- if (diagonal) {
- eigenvalues[0] = data_[M00];
- eigenvalues[1] = data_[M11];
- eigenvalues[2] = data_[M22];
- } else {
- float q = Trace() / 3.0f;
- p = (data_[M00] - q) * (data_[M00] - q) +
- (data_[M11] - q) * (data_[M11] - q) +
- (data_[M22] - q) * (data_[M22] - q) +
- 2 * p;
- p = std::sqrt(p / 6);
-
- // The computation below puts B as (A - qI) / p, where A is *this.
- Matrix3F matrix_b(*this);
- matrix_b.data_[M00] -= q;
- matrix_b.data_[M11] -= q;
- matrix_b.data_[M22] -= q;
- for (int i = 0; i < M_END; ++i)
- matrix_b.data_[i] /= p;
-
- double half_det_b = Determinant3x3(matrix_b.data_) / 2.0;
- // half_det_b should be in <-1, 1>, but beware of rounding error.
- double phi = 0.0f;
- if (half_det_b <= -1.0)
- phi = M_PI / 3;
- else if (half_det_b < 1.0)
- phi = acos(half_det_b) / 3;
-
- eigenvalues[0] = q + 2 * p * static_cast<float>(cos(phi));
- eigenvalues[2] = q + 2 * p *
- static_cast<float>(cos(phi + 2.0 * M_PI / 3.0));
- eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2];
- }
-
- // Put eigenvalues in the descending order.
- int indices[3] = {0, 1, 2};
- if (eigenvalues[2] > eigenvalues[1]) {
- std::swap(eigenvalues[2], eigenvalues[1]);
- std::swap(indices[2], indices[1]);
- }
-
- if (eigenvalues[1] > eigenvalues[0]) {
- std::swap(eigenvalues[1], eigenvalues[0]);
- std::swap(indices[1], indices[0]);
- }
-
- if (eigenvalues[2] > eigenvalues[1]) {
- std::swap(eigenvalues[2], eigenvalues[1]);
- std::swap(indices[2], indices[1]);
- }
-
- if (eigenvectors != NULL && diagonal) {
- // Eigenvectors are e-vectors, just need to be sorted accordingly.
- *eigenvectors = Zeros();
- for (int i = 0; i < 3; ++i)
- eigenvectors->set(indices[i], i, 1.0f);
- } else if (eigenvectors != NULL) {
- // Consult the following for a detailed discussion:
- // Joachim Kopp
- // Numerical diagonalization of hermitian 3x3 matrices
- // arXiv.org preprint: physics/0610206
- // Int. J. Mod. Phys. C19 (2008) 523-548
-
- // TODO(motek): expand to handle correctly negative and multiple
- // eigenvalues.
- for (int i = 0; i < 3; ++i) {
- float l = eigenvalues[i];
- // B = A - l * I
- Matrix3F matrix_b(*this);
- matrix_b.data_[M00] -= l;
- matrix_b.data_[M11] -= l;
- matrix_b.data_[M22] -= l;
- Vector3dF e1 = CrossProduct(matrix_b.get_column(0),
- matrix_b.get_column(1));
- Vector3dF e2 = CrossProduct(matrix_b.get_column(1),
- matrix_b.get_column(2));
- Vector3dF e3 = CrossProduct(matrix_b.get_column(2),
- matrix_b.get_column(0));
-
- // e1, e2 and e3 should point in the same direction.
- if (DotProduct(e1, e2) < 0)
- e2 = -e2;
-
- if (DotProduct(e1, e3) < 0)
- e3 = -e3;
-
- Vector3dF eigvec = e1 + e2 + e3;
- // Normalize.
- eigvec.Scale(1.0f / eigvec.Length());
- eigenvectors->set_column(i, eigvec);
- }
- }
-
- return Vector3dF(eigenvalues[0], eigenvalues[1], eigenvalues[2]);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/matrix3_f.h b/chromium/ui/gfx/matrix3_f.h
index a8ae5b578a8..936c312475b 100644
--- a/chromium/ui/gfx/matrix3_f.h
+++ b/chromium/ui/gfx/matrix3_f.h
@@ -1,108 +1,7 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_MATRIX3_F_H_
-#define UI_GFX_MATRIX3_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/matrix3_f.h"
-#include "base/logging.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Matrix3F {
- public:
- ~Matrix3F();
-
- static Matrix3F Zeros();
- static Matrix3F Ones();
- static Matrix3F Identity();
- static Matrix3F FromOuterProduct(const Vector3dF& a, const Vector3dF& bt);
-
- bool IsEqual(const Matrix3F& rhs) const;
-
- // Element-wise comparison with given precision.
- bool IsNear(const Matrix3F& rhs, float precision) const;
-
- float get(int i, int j) const {
- return data_[MatrixToArrayCoords(i, j)];
- }
-
- void set(int i, int j, float v) {
- data_[MatrixToArrayCoords(i, j)] = v;
- }
-
- void set(float m00, float m01, float m02,
- float m10, float m11, float m12,
- float m20, float m21, float m22) {
- data_[0] = m00;
- data_[1] = m01;
- data_[2] = m02;
- data_[3] = m10;
- data_[4] = m11;
- data_[5] = m12;
- data_[6] = m20;
- data_[7] = m21;
- data_[8] = m22;
- }
-
- Vector3dF get_column(int i) const {
- return Vector3dF(
- data_[MatrixToArrayCoords(0, i)],
- data_[MatrixToArrayCoords(1, i)],
- data_[MatrixToArrayCoords(2, i)]);
- }
-
- void set_column(int i, const Vector3dF& c) {
- data_[MatrixToArrayCoords(0, i)] = c.x();
- data_[MatrixToArrayCoords(1, i)] = c.y();
- data_[MatrixToArrayCoords(2, i)] = c.z();
- }
-
- // Returns an inverse of this if the matrix is non-singular, zero (== Zero())
- // otherwise.
- Matrix3F Inverse() const;
-
- // Value of the determinant of the matrix.
- float Determinant() const;
-
- // Trace (sum of diagonal elements) of the matrix.
- float Trace() const {
- return data_[MatrixToArrayCoords(0, 0)] +
- data_[MatrixToArrayCoords(1, 1)] +
- data_[MatrixToArrayCoords(2, 2)];
- }
-
- // Compute eigenvalues and (optionally) normalized eigenvectors of
- // a positive defnite matrix *this. Eigenvectors are computed only if
- // non-null |eigenvectors| matrix is passed. If it is NULL, the routine
- // will not attempt to compute eigenvectors but will still return eigenvalues
- // if they can be computed.
- // If eigenvalues cannot be computed (the matrix does not meet constraints)
- // the 0-vector is returned. Note that to retrieve eigenvalues, the matrix
- // only needs to be symmetric while eigenvectors require it to be
- // positive-definite. Passing a non-positive definite matrix will result in
- // NaNs in vectors which cannot be computed.
- // Eigenvectors are placed as column in |eigenvectors| in order corresponding
- // to eigenvalues.
- Vector3dF SolveEigenproblem(Matrix3F* eigenvectors) const;
-
- private:
- Matrix3F(); // Uninitialized default.
-
- static int MatrixToArrayCoords(int i, int j) {
- DCHECK(i >= 0 && i < 3);
- DCHECK(j >= 0 && j < 3);
- return i * 3 + j;
- }
-
- float data_[9];
-};
-
-inline bool operator==(const Matrix3F& lhs, const Matrix3F& rhs) {
- return lhs.IsEqual(rhs);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_MATRIX3_F_H_
diff --git a/chromium/ui/gfx/matrix3_unittest.cc b/chromium/ui/gfx/matrix3_unittest.cc
deleted file mode 100644
index 04c656f6d26..00000000000
--- a/chromium/ui/gfx/matrix3_unittest.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cmath>
-#include <limits>
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/matrix3_f.h"
-
-namespace gfx {
-namespace {
-
-TEST(Matrix3fTest, Constructors) {
- Matrix3F zeros = Matrix3F::Zeros();
- Matrix3F ones = Matrix3F::Ones();
- Matrix3F identity = Matrix3F::Identity();
-
- Matrix3F product_ones = Matrix3F::FromOuterProduct(
- Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(1.0f, 1.0f, 1.0f));
- Matrix3F product_zeros = Matrix3F::FromOuterProduct(
- Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(0.0f, 0.0f, 0.0f));
- EXPECT_EQ(ones, product_ones);
- EXPECT_EQ(zeros, product_zeros);
-
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j)
- EXPECT_EQ(i == j ? 1.0f : 0.0f, identity.get(i, j));
- }
-}
-
-TEST(Matrix3fTest, DataAccess) {
- Matrix3F matrix = Matrix3F::Ones();
- Matrix3F identity = Matrix3F::Identity();
-
- EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), identity.get_column(1));
- matrix.set(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
- EXPECT_EQ(Vector3dF(2.0f, 5.0f, 8.0f), matrix.get_column(2));
- matrix.set_column(0, Vector3dF(0.1f, 0.2f, 0.3f));
- EXPECT_EQ(Vector3dF(0.1f, 0.2f, 0.3f), matrix.get_column(0));
-
- EXPECT_EQ(0.1f, matrix.get(0, 0));
- EXPECT_EQ(5.0f, matrix.get(1, 2));
-}
-
-TEST(Matrix3fTest, Determinant) {
- EXPECT_EQ(1.0f, Matrix3F::Identity().Determinant());
- EXPECT_EQ(0.0f, Matrix3F::Zeros().Determinant());
- EXPECT_EQ(0.0f, Matrix3F::Ones().Determinant());
-
- // Now for something non-trivial...
- Matrix3F matrix = Matrix3F::Zeros();
- matrix.set(0, 5, 6, 8, 7, 0, 1, 9, 0);
- EXPECT_EQ(390.0f, matrix.Determinant());
- matrix.set(2, 0, 3 * matrix.get(0, 0));
- matrix.set(2, 1, 3 * matrix.get(0, 1));
- matrix.set(2, 2, 3 * matrix.get(0, 2));
- EXPECT_EQ(0, matrix.Determinant());
-
- matrix.set(0.57f, 0.205f, 0.942f,
- 0.314f, 0.845f, 0.826f,
- 0.131f, 0.025f, 0.962f);
- EXPECT_NEAR(0.3149f, matrix.Determinant(), 0.0001f);
-}
-
-TEST(Matrix3fTest, Inverse) {
- Matrix3F identity = Matrix3F::Identity();
- Matrix3F inv_identity = identity.Inverse();
- EXPECT_EQ(identity, inv_identity);
-
- Matrix3F singular = Matrix3F::Zeros();
- singular.set(1.0f, 3.0f, 4.0f,
- 2.0f, 11.0f, 5.0f,
- 0.5f, 1.5f, 2.0f);
- EXPECT_EQ(0, singular.Determinant());
- EXPECT_EQ(Matrix3F::Zeros(), singular.Inverse());
-
- Matrix3F regular = Matrix3F::Zeros();
- regular.set(0.57f, 0.205f, 0.942f,
- 0.314f, 0.845f, 0.826f,
- 0.131f, 0.025f, 0.962f);
- Matrix3F inv_regular = regular.Inverse();
- regular.set(2.51540616f, -0.55138018f, -1.98968043f,
- -0.61552266f, 1.34920184f, -0.55573636f,
- -0.32653861f, 0.04002158f, 1.32488726f);
- EXPECT_TRUE(regular.IsNear(inv_regular, 0.00001f));
-}
-
-TEST(Matrix3fTest, EigenvectorsIdentity) {
- // This block tests the trivial case of eigenvalues of the identity matrix.
- Matrix3F identity = Matrix3F::Identity();
- Vector3dF eigenvals = identity.SolveEigenproblem(NULL);
- EXPECT_EQ(Vector3dF(1.0f, 1.0f, 1.0f), eigenvals);
-}
-
-TEST(Matrix3fTest, EigenvectorsDiagonal) {
- // This block tests the another trivial case of eigenvalues of a diagonal
- // matrix. Here we expect values to be sorted.
- Matrix3F matrix = Matrix3F::Zeros();
- matrix.set(0, 0, 1.0f);
- matrix.set(1, 1, -2.5f);
- matrix.set(2, 2, 3.14f);
- Matrix3F eigenvectors = Matrix3F::Zeros();
- Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
- EXPECT_EQ(Vector3dF(3.14f, 1.0f, -2.5f), eigenvals);
-
- EXPECT_EQ(Vector3dF(0.0f, 0.0f, 1.0f), eigenvectors.get_column(0));
- EXPECT_EQ(Vector3dF(1.0f, 0.0f, 0.0f), eigenvectors.get_column(1));
- EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), eigenvectors.get_column(2));
-}
-
-TEST(Matrix3fTest, EigenvectorsNiceNotPositive) {
- // This block tests computation of eigenvectors of a matrix where nice
- // round values are expected.
- Matrix3F matrix = Matrix3F::Zeros();
- // This is not a positive-definite matrix but eigenvalues and the first
- // eigenvector should nonetheless be computed correctly.
- matrix.set(3, 2, 4, 2, 0, 2, 4, 2, 3);
- Matrix3F eigenvectors = Matrix3F::Zeros();
- Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
- EXPECT_EQ(Vector3dF(8.0f, -1.0f, -1.0f), eigenvals);
-
- Vector3dF expected_principal(0.66666667f, 0.33333333f, 0.66666667f);
- EXPECT_NEAR(0.0f,
- (expected_principal - eigenvectors.get_column(0)).Length(),
- 0.000001f);
-}
-
-TEST(Matrix3fTest, EigenvectorsPositiveDefinite) {
- // This block tests computation of eigenvectors of a matrix where output
- // is not as nice as above, but it actually meets the definition.
- Matrix3F matrix = Matrix3F::Zeros();
- Matrix3F eigenvectors = Matrix3F::Zeros();
- Matrix3F expected_eigenvectors = Matrix3F::Zeros();
- matrix.set(1, -1, 2, -1, 4, 5, 2, 5, 0);
- Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
- Vector3dF expected_eigv(7.3996266f, 1.91197255f, -4.31159915f);
- expected_eigv -= eigenvals;
- EXPECT_NEAR(0, expected_eigv.LengthSquared(), 0.00001f);
- expected_eigenvectors.set(0.04926317f, -0.92135662f, -0.38558414f,
- 0.82134249f, 0.25703273f, -0.50924521f,
- 0.56830419f, -0.2916096f, 0.76941158f);
- EXPECT_TRUE(expected_eigenvectors.IsNear(eigenvectors, 0.00001f));
-}
-
-}
-}
diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h
index bd14ed50f77..f7f2808cba9 100644
--- a/chromium/ui/gfx/native_widget_types.h
+++ b/chromium/ui/gfx/native_widget_types.h
@@ -98,14 +98,7 @@ typedef struct _PangoFontDescription PangoFontDescription;
typedef struct _cairo cairo_t;
#endif
-#if defined(TOOLKIT_GTK)
-typedef struct _GdkCursor GdkCursor;
-typedef union _GdkEvent GdkEvent;
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GdkRegion GdkRegion;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _GtkWindow GtkWindow;
-#elif defined(OS_ANDROID)
+#if defined(OS_ANDROID)
struct ANativeWindow;
namespace ui {
class WindowAndroid;
@@ -122,12 +115,6 @@ typedef aura::Window* NativeView;
typedef aura::Window* NativeWindow;
typedef SkRegion* NativeRegion;
typedef ui::Event* NativeEvent;
-#elif defined(OS_WIN)
-typedef HCURSOR NativeCursor;
-typedef HWND NativeView;
-typedef HWND NativeWindow;
-typedef HRGN NativeRegion;
-typedef MSG NativeEvent;
#elif defined(OS_IOS)
typedef void* NativeCursor;
typedef UIView* NativeView;
@@ -137,13 +124,8 @@ typedef UIEvent* NativeEvent;
typedef NSCursor* NativeCursor;
typedef NSView* NativeView;
typedef NSWindow* NativeWindow;
+typedef void* NativeRegion;
typedef NSEvent* NativeEvent;
-#elif defined(TOOLKIT_GTK)
-typedef GdkCursor* NativeCursor;
-typedef GtkWidget* NativeView;
-typedef GtkWindow* NativeWindow;
-typedef GdkRegion* NativeRegion;
-typedef GdkEvent* NativeEvent;
#elif defined(OS_ANDROID)
typedef void* NativeCursor;
typedef ui::ViewAndroid* NativeView;
@@ -166,11 +148,6 @@ typedef NSFont* NativeFont;
typedef NSTextField* NativeEditView;
typedef CGContext* NativeDrawingContext;
typedef void* NativeViewAccessible;
-#elif defined(TOOLKIT_GTK)
-typedef PangoFontDescription* NativeFont;
-typedef GtkWidget* NativeEditView;
-typedef cairo_t* NativeDrawingContext;
-typedef void* NativeViewAccessible;
#elif defined(USE_CAIRO)
typedef PangoFontDescription* NativeFont;
typedef void* NativeEditView;
@@ -194,8 +171,6 @@ const gfx::NativeCursor kNullCursor = static_cast<gfx::NativeCursor>(NULL);
typedef UIImage NativeImageType;
#elif defined(OS_MACOSX)
typedef NSImage NativeImageType;
-#elif defined(TOOLKIT_GTK)
-typedef GdkPixbuf NativeImageType;
#else
typedef SkBitmap NativeImageType;
#endif
@@ -208,32 +183,8 @@ typedef NativeImageType* NativeImage;
// See comment at the top of the file for usage.
typedef intptr_t NativeViewId;
-#if defined(OS_WIN) && !defined(USE_AURA)
-// Convert a NativeViewId to a NativeView.
-//
-// On Windows, we pass an HWND into the renderer. As stated above, the renderer
-// should not be performing operations on the view.
-static inline NativeView NativeViewFromId(NativeViewId id) {
- return reinterpret_cast<NativeView>(id);
-}
-#define NativeViewFromIdInBrowser(x) NativeViewFromId(x)
-#elif defined(OS_POSIX) || defined(USE_AURA)
-// On Mac, Linux and USE_AURA, a NativeView is a pointer to an object, and is
-// useless outside the process in which it was created. NativeViewFromId should
-// only be used inside the appropriate platform ifdef outside of the browser.
-// (NativeViewFromIdInBrowser can be used everywhere in the browser.) If your
-// cross-platform design involves a call to NativeViewFromId from outside the
-// browser it will never work on Mac or Linux and is fundamentally broken.
-
-// Please do not call this from outside the browser. It won't work; the name
-// should give you a subtle hint.
-static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
- return reinterpret_cast<NativeView>(id);
-}
-#endif // defined(OS_POSIX)
-
// PluginWindowHandle is an abstraction wrapping "the types of windows
-// used by NPAPI plugins". On Windows it's an HWND, on X it's an X
+// used by NPAPI plugins". On Windows it's an HWND, on X it's an X
// window id.
#if defined(OS_WIN)
typedef HWND PluginWindowHandle;
@@ -241,11 +192,6 @@ static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
#elif defined(USE_X11)
typedef unsigned long PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
-#elif defined(USE_AURA) && defined(OS_MACOSX)
- // Mac-Aura uses NSView-backed GLSurface. Regular Mac does not.
- // TODO(dhollowa): Rationalize these two definitions. http://crbug.com/104551.
- typedef NSView* PluginWindowHandle;
- const PluginWindowHandle kNullPluginWindow = 0;
#elif defined(OS_ANDROID)
typedef uint64 PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
@@ -253,17 +199,9 @@ static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
typedef intptr_t PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
#else
- // On OS X we don't have windowed plugins.
- // We use a NULL/0 PluginWindowHandle in shared code to indicate there
- // is no window present, so mirror that behavior here.
- //
- // The GPU plugin is currently an exception to this rule. As of this
- // writing it uses some NPAPI infrastructure, and minimally we need
- // to identify the plugin instance via this window handle. When the
- // GPU plugin becomes a full-on GPU process, this typedef can be
- // returned to a bool. For now we use a type large enough to hold a
- // pointer on 64-bit architectures in case we need this capability.
- typedef uint64 PluginWindowHandle;
+ // On Mac we don't have windowed plugins. We use a NULL/0 PluginWindowHandle
+ // in shared code to indicate there is no window present.
+ typedef bool PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
#endif
@@ -271,20 +209,19 @@ enum SurfaceType {
EMPTY,
NATIVE_DIRECT,
NATIVE_TRANSPORT,
- TEXTURE_TRANSPORT
+ TEXTURE_TRANSPORT,
+ SURFACE_TYPE_LAST = TEXTURE_TRANSPORT
};
struct GLSurfaceHandle {
GLSurfaceHandle()
: handle(kNullPluginWindow),
transport_type(EMPTY),
- parent_gpu_process_id(0),
parent_client_id(0) {
}
GLSurfaceHandle(PluginWindowHandle handle_, SurfaceType transport_)
: handle(handle_),
transport_type(transport_),
- parent_gpu_process_id(0),
parent_client_id(0) {
DCHECK(!is_null() || handle == kNullPluginWindow);
DCHECK(transport_type != TEXTURE_TRANSPORT ||
@@ -297,7 +234,6 @@ struct GLSurfaceHandle {
}
PluginWindowHandle handle;
SurfaceType transport_type;
- int parent_gpu_process_id;
uint32 parent_client_id;
};
diff --git a/chromium/ui/gfx/nine_image_painter.cc b/chromium/ui/gfx/nine_image_painter.cc
new file mode 100644
index 00000000000..24a3e3b3627
--- /dev/null
+++ b/chromium/ui/gfx/nine_image_painter.cc
@@ -0,0 +1,157 @@
+// 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/gfx/nine_image_painter.h"
+
+#include <limits>
+
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/skia_util.h"
+
+namespace gfx {
+
+namespace {
+
+// The following functions width and height of the image in pixels for the
+// scale factor in the Canvas.
+int ImageWidthInPixels(const ImageSkia& i, Canvas* c) {
+ return i.GetRepresentation(c->image_scale()).pixel_width();
+}
+
+int ImageHeightInPixels(const ImageSkia& i, Canvas* c) {
+ return i.GetRepresentation(c->image_scale()).pixel_height();
+}
+
+// Stretches the given image over the specified canvas area.
+void Fill(Canvas* c,
+ const ImageSkia& i,
+ int x,
+ int y,
+ int w,
+ int h,
+ const SkPaint& paint) {
+ c->DrawImageIntInPixel(i, 0, 0, ImageWidthInPixels(i, c),
+ ImageHeightInPixels(i, c), x, y, w, h, false, paint);
+}
+
+} // namespace
+
+NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) {
+ DCHECK_EQ(arraysize(images_), images.size());
+ for (size_t i = 0; i < arraysize(images_); ++i)
+ images_[i] = images[i];
+}
+
+NineImagePainter::NineImagePainter(const ImageSkia& image,
+ const Insets& insets) {
+ DCHECK_GE(image.width(), insets.width());
+ DCHECK_GE(image.height(), insets.height());
+
+ // Extract subsets of the original image to match the |images_| format.
+ const int x[] =
+ { 0, insets.left(), image.width() - insets.right(), image.width() };
+ const int y[] =
+ { 0, insets.top(), image.height() - insets.bottom(), image.height() };
+
+ for (size_t j = 0; j < 3; ++j) {
+ for (size_t i = 0; i < 3; ++i) {
+ images_[i + j * 3] = ImageSkiaOperations::ExtractSubset(image,
+ Rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j]));
+ }
+ }
+}
+
+NineImagePainter::~NineImagePainter() {
+}
+
+bool NineImagePainter::IsEmpty() const {
+ return images_[0].isNull();
+}
+
+Size NineImagePainter::GetMinimumSize() const {
+ return IsEmpty() ? Size() : Size(
+ images_[0].width() + images_[1].width() + images_[2].width(),
+ images_[0].height() + images_[3].height() + images_[6].height());
+}
+
+void NineImagePainter::Paint(Canvas* canvas, const Rect& bounds) {
+ // When no alpha value is specified, use default value of 100% opacity.
+ Paint(canvas, bounds, std::numeric_limits<uint8>::max());
+}
+
+void NineImagePainter::Paint(Canvas* canvas,
+ const Rect& bounds,
+ const uint8 alpha) {
+ if (IsEmpty())
+ return;
+
+ ScopedCanvas scoped_canvas(canvas);
+ canvas->Translate(bounds.OffsetFromOrigin());
+
+ SkPaint paint;
+ paint.setAlpha(alpha);
+
+ // Get the current transform from the canvas and apply it to the logical
+ // bounds passed in. This will give us the pixel bounds which can be used
+ // to draw the images at the correct locations.
+ // We should not scale the bounds by the canvas->image_scale() as that can be
+ // different from the real scale in the canvas transform.
+ SkMatrix matrix = canvas->sk_canvas()->getTotalMatrix();
+ SkRect scaled_rect;
+ matrix.mapRect(&scaled_rect, RectToSkRect(bounds));
+
+ int scaled_width = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.width()));
+ int scaled_height = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.height()));
+
+ // In case the corners and edges don't all have the same width/height, we draw
+ // the center first, and extend it out in all directions to the edges of the
+ // images with the smallest widths/heights. This way there will be no
+ // unpainted areas, though some corners or edges might overlap the center.
+ int i0w = ImageWidthInPixels(images_[0], canvas);
+ int i2w = ImageWidthInPixels(images_[2], canvas);
+ int i3w = ImageWidthInPixels(images_[3], canvas);
+ int i5w = ImageWidthInPixels(images_[5], canvas);
+ int i6w = ImageWidthInPixels(images_[6], canvas);
+ int i8w = ImageWidthInPixels(images_[8], canvas);
+
+ int i4x = std::min(std::min(i0w, i3w), i6w);
+ int i4w = scaled_width - i4x - std::min(std::min(i2w, i5w), i8w);
+
+ int i0h = ImageHeightInPixels(images_[0], canvas);
+ int i1h = ImageHeightInPixels(images_[1], canvas);
+ int i2h = ImageHeightInPixels(images_[2], canvas);
+ int i6h = ImageHeightInPixels(images_[6], canvas);
+ int i7h = ImageHeightInPixels(images_[7], canvas);
+ int i8h = ImageHeightInPixels(images_[8], canvas);
+
+ int i4y = std::min(std::min(i0h, i1h), i2h);
+ int i4h = scaled_height - i4y - std::min(std::min(i6h, i7h), i8h);
+ if (!images_[4].isNull())
+ Fill(canvas, images_[4], i4x, i4y, i4w, i4h, paint);
+ canvas->DrawImageIntInPixel(images_[0], 0, 0, i0w, i0h,
+ 0, 0, i0w, i0h, false, paint);
+ Fill(canvas, images_[1], i0w, 0, scaled_width - i0w - i2w, i1h, paint);
+ canvas->DrawImageIntInPixel(images_[2], 0, 0, i2w, i2h, scaled_width - i2w,
+ 0, i2w, i2h, false, paint);
+ Fill(canvas, images_[3], 0, i0h, i3w, scaled_height - i0h - i6h, paint);
+ Fill(canvas, images_[5], scaled_width - i5w, i2h, i5w,
+ scaled_height - i2h - i8h, paint);
+ canvas->DrawImageIntInPixel(images_[6], 0, 0, i6w, i6h, 0,
+ scaled_height - i6h, i6w, i6h, false, paint);
+ Fill(canvas, images_[7], i6w, scaled_height - i7h, scaled_width - i6w - i8w,
+ i7h, paint);
+ canvas->DrawImageIntInPixel(images_[8], 0, 0, i8w, i8h, scaled_width - i8w,
+ scaled_height - i8h, i8w, i8h, false, paint);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/nine_image_painter.h b/chromium/ui/gfx/nine_image_painter.h
new file mode 100644
index 00000000000..46458d5cb28
--- /dev/null
+++ b/chromium/ui/gfx/nine_image_painter.h
@@ -0,0 +1,42 @@
+// 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_GFX_NINE_IMAGE_PAINTER_H_
+#define UI_GFX_NINE_IMAGE_PAINTER_H_
+
+#include "base/logging.h"
+#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace gfx {
+
+class Canvas;
+class Insets;
+class Rect;
+
+class GFX_EXPORT NineImagePainter {
+ public:
+ explicit NineImagePainter(const std::vector<ImageSkia>& images);
+ NineImagePainter(const ImageSkia& image, const Insets& insets);
+ ~NineImagePainter();
+
+ bool IsEmpty() const;
+ Size GetMinimumSize() const;
+ void Paint(Canvas* canvas, const Rect& bounds);
+ void Paint(Canvas* canvas, const Rect& bounds, uint8 alpha);
+
+ private:
+ // Images are numbered as depicted below.
+ // ____________________
+ // |__i0__|__i1__|__i2__|
+ // |__i3__|__i4__|__i5__|
+ // |__i6__|__i7__|__i8__|
+ ImageSkia images_[9];
+
+ DISALLOW_COPY_AND_ASSIGN(NineImagePainter);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_NINE_IMAGE_PAINTER_H_
diff --git a/chromium/ui/gfx/overlay_transform.h b/chromium/ui/gfx/overlay_transform.h
new file mode 100644
index 00000000000..1e27010933e
--- /dev/null
+++ b/chromium/ui/gfx/overlay_transform.h
@@ -0,0 +1,24 @@
+// 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_GFX_OVERLAY_TRANSFORM_H_
+#define UI_GFX_OVERLAY_TRANSFORM_H_
+
+namespace gfx {
+
+// Describes transformation to be applied to the buffer before presenting
+// to screen.
+enum OverlayTransform {
+ OVERLAY_TRANSFORM_INVALID,
+ OVERLAY_TRANSFORM_NONE,
+ OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
+ OVERLAY_TRANSFORM_FLIP_VERTICAL,
+ OVERLAY_TRANSFORM_ROTATE_90,
+ OVERLAY_TRANSFORM_ROTATE_180,
+ OVERLAY_TRANSFORM_ROTATE_270,
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_OVERLAY_TRANSFORM_H_
diff --git a/chromium/ui/gfx/ozone/OWNERS b/chromium/ui/gfx/ozone/OWNERS
deleted file mode 100644
index 77f21b5cae7..00000000000
--- a/chromium/ui/gfx/ozone/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rjkroege@chromium.org
diff --git a/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc b/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc
deleted file mode 100644
index 4fbe0f54d89..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <xf86drm.h>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-
-namespace gfx {
-
-namespace {
-
-void DestroyDumbBuffer(int fd, uint32_t handle) {
- struct drm_mode_destroy_dumb destroy_request;
- destroy_request.handle = handle;
- drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
-}
-
-// Special DRM implementation of a SkPixelRef. The DRM allocator will create a
-// SkPixelRef for the backing pixels. It will then associate the SkPixelRef with
-// the SkBitmap. SkBitmap will access the allocated memory by locking the pixels
-// in the SkPixelRef.
-// At the end of its life the SkPixelRef is responsible for deallocating the
-// pixel memory.
-class DriSkPixelRef : public SkPixelRef {
- public:
- DriSkPixelRef(void* pixels,
- SkColorTable* color_table_,
- size_t size,
- int fd,
- uint32_t handle);
- virtual ~DriSkPixelRef();
-
- virtual void* onLockPixels(SkColorTable** ct) OVERRIDE;
- virtual void onUnlockPixels() OVERRIDE;
-
- SK_DECLARE_UNFLATTENABLE_OBJECT()
- private:
- // Raw pointer to the pixel memory.
- void* pixels_;
-
- // Optional color table associated with the pixel memory.
- SkColorTable* color_table_;
-
- // Size of the allocated memory.
- size_t size_;
-
- // File descriptor to the graphics card used to allocate/deallocate the
- // memory.
- int fd_;
-
- // Handle for the allocated memory.
- uint32_t handle_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSkPixelRef);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSkPixelRef implementation
-
-DriSkPixelRef::DriSkPixelRef(
- void* pixels,
- SkColorTable* color_table,
- size_t size,
- int fd,
- uint32_t handle)
- : pixels_(pixels),
- color_table_(color_table),
- size_(size),
- fd_(fd),
- handle_(handle) {
-}
-
-DriSkPixelRef::~DriSkPixelRef() {
- munmap(pixels_, size_);
- DestroyDumbBuffer(fd_, handle_);
-}
-
-void* DriSkPixelRef::onLockPixels(SkColorTable** ct) {
- *ct = color_table_;
- return pixels_;
-}
-
-void DriSkPixelRef::onUnlockPixels() {
-}
-
-} // namespace
-
-// Allocates pixel memory for a SkBitmap using DRM dumb buffers.
-class DriAllocator : public SkBitmap::Allocator {
- public:
- DriAllocator();
-
- virtual bool allocPixelRef(SkBitmap* bitmap,
- SkColorTable* color_table) OVERRIDE;
-
- private:
- bool AllocatePixels(DriSkBitmap* bitmap, SkColorTable* color_table);
-
- DISALLOW_COPY_AND_ASSIGN(DriAllocator);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DriAllocator implementation
-
-DriAllocator::DriAllocator() {
-}
-
-bool DriAllocator::allocPixelRef(SkBitmap* bitmap,
- SkColorTable* color_table) {
- return AllocatePixels(static_cast<DriSkBitmap*>(bitmap), color_table);
-}
-
-bool DriAllocator::AllocatePixels(DriSkBitmap* bitmap,
- SkColorTable* color_table) {
- struct drm_mode_create_dumb request;
- request.width = bitmap->width();
- request.height = bitmap->height();
- request.bpp = bitmap->bytesPerPixel() << 3;
- request.flags = 0;
-
- if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
- DLOG(ERROR) << "Cannot create dumb buffer (" << errno << ") "
- << strerror(errno);
- return false;
- }
-
- CHECK(request.size == bitmap->getSize());
-
- bitmap->set_handle(request.handle);
-
- struct drm_mode_map_dumb map_request;
- map_request.handle = bitmap->get_handle();
- if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
- DLOG(ERROR) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
- << strerror(errno);
- DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
- return false;
- }
-
- void* pixels = mmap(0,
- bitmap->getSize(),
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- bitmap->get_fd(),
- map_request.offset);
- if (pixels == MAP_FAILED) {
- DLOG(ERROR) << "Cannot mmap dumb buffer (" << errno << ") "
- << strerror(errno);
- DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
- return false;
- }
-
- bitmap->setPixelRef(new DriSkPixelRef(
- pixels,
- color_table,
- bitmap->getSize(),
- bitmap->get_fd(),
- bitmap->get_handle()))->unref();
- bitmap->lockPixels();
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSkBitmap implementation
-
-DriSkBitmap::DriSkBitmap(int fd)
- : fd_(fd),
- handle_(0),
- framebuffer_(0) {
-}
-
-DriSkBitmap::~DriSkBitmap() {
-}
-
-bool DriSkBitmap::Initialize() {
- DriAllocator drm_allocator;
- return allocPixels(&drm_allocator, NULL);
-}
-
-uint8_t DriSkBitmap::GetColorDepth() const {
- switch (config()) {
- case SkBitmap::kNo_Config:
- case SkBitmap::kA8_Config:
- return 0;
- case SkBitmap::kIndex8_Config:
- return 8;
- case SkBitmap::kRGB_565_Config:
- return 16;
- case SkBitmap::kARGB_4444_Config:
- return 12;
- case SkBitmap::kARGB_8888_Config:
- return 24;
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_skbitmap.h b/chromium/ui/gfx/ozone/dri/dri_skbitmap.h
deleted file mode 100644
index f5b8f9455fa..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_skbitmap.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_DRI_DRI_SKBITMAP_H_
-#define UI_GFX_OZONE_DRI_DRI_SKBITMAP_H_
-
-#include "base/basictypes.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// Extend the SkBitmap interface to keep track of additional parameters used by
-// the DRM stack when allocating buffers.
-class GFX_EXPORT DriSkBitmap : public SkBitmap {
- public:
- DriSkBitmap(int fd);
- virtual ~DriSkBitmap();
-
- // Allocates the backing pixels using DRI.
- // Return true on success, false otherwise.
- virtual bool Initialize();
-
- uint32_t get_handle() const { return handle_; };
-
- uint32_t get_framebuffer() const { return framebuffer_; };
-
- int get_fd() const { return fd_; };
-
- // Return the color depth of a pixel in this buffer.
- uint8_t GetColorDepth() const;
-
- private:
- friend class DriAllocator;
- friend class HardwareDisplayController;
-
- void set_handle(uint32_t handle) { handle_ = handle; };
- void set_framebuffer(uint32_t framebuffer) { framebuffer_ = framebuffer; };
-
- // File descriptor used by the DRI allocator to request buffers from the DRI
- // stack.
- int fd_;
-
- // Buffer handle used by the DRI allocator.
- uint32_t handle_;
-
- // Buffer ID used by the DRI modesettings API. This is set when the buffer is
- // registered with the CRTC.
- uint32_t framebuffer_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSkBitmap);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SKBITMAP_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface.cc b/chromium/ui/gfx/ozone/dri/dri_surface.cc
deleted file mode 100644
index c9b6af4b562..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/dri_surface.h"
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <xf86drm.h>
-
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-#include "ui/gfx/skia_util.h"
-
-namespace gfx {
-
-namespace {
-
-// Extends the SkBitmapDevice to allow setting the SkPixelRef. We use the setter
-// to change the SkPixelRef such that the device always points to the
-// backbuffer.
-class CustomSkBitmapDevice : public SkBitmapDevice {
- public:
- CustomSkBitmapDevice(const SkBitmap& bitmap) : SkBitmapDevice(bitmap) {}
- virtual ~CustomSkBitmapDevice() {}
-
- void SetPixelRef(SkPixelRef* pixel_ref) { setPixelRef(pixel_ref, 0); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CustomSkBitmapDevice);
-};
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSurface implementation
-
-DriSurface::DriSurface(
- HardwareDisplayController* controller)
- : controller_(controller),
- bitmaps_(),
- front_buffer_(0) {
-}
-
-DriSurface::~DriSurface() {
-}
-
-bool DriSurface::Initialize() {
- for (int i = 0; i < 2; ++i) {
- bitmaps_[i].reset(CreateBuffer());
- // TODO(dnicoara) Should select the configuration based on what the
- // underlying system supports.
- bitmaps_[i]->setConfig(SkBitmap::kARGB_8888_Config,
- controller_->get_mode().hdisplay,
- controller_->get_mode().vdisplay);
-
- if (!bitmaps_[i]->Initialize()) {
- return false;
- }
- }
-
- skia_device_ = skia::AdoptRef(
- new CustomSkBitmapDevice(*bitmaps_[front_buffer_ ^ 1].get()));
- skia_canvas_ = skia::AdoptRef(new SkCanvas(skia_device_.get()));
-
- return true;
-}
-
-uint32_t DriSurface::GetFramebufferId() const {
- CHECK(bitmaps_[0].get() && bitmaps_[1].get());
- return bitmaps_[front_buffer_ ^ 1]->get_framebuffer();
-}
-
-// This call is made after the hardware just started displaying our back buffer.
-// We need to update our pointer reference and synchronize the two buffers.
-void DriSurface::SwapBuffers() {
- CHECK(bitmaps_[0].get() && bitmaps_[1].get());
-
- // Update our front buffer pointer.
- front_buffer_ ^= 1;
-
- // Unlocking will unset the pixel pointer, so it won't be pointing to the old
- // PixelRef.
- skia_device_->accessBitmap(false).unlockPixels();
- // Update the backing pixels for the bitmap device.
- static_cast<CustomSkBitmapDevice*>(skia_device_.get())->SetPixelRef(
- bitmaps_[front_buffer_ ^ 1]->pixelRef());
- // Locking the pixels will set the pixel pointer based on the PixelRef value.
- skia_device_->accessBitmap(false).lockPixels();
-
- SkIRect device_damage;
- skia_canvas_->getClipDeviceBounds(&device_damage);
- SkRect damage = SkRect::Make(device_damage);
-
- skia_canvas_->drawBitmapRectToRect(*bitmaps_[front_buffer_].get(),
- &damage,
- damage);
-}
-
-SkCanvas* DriSurface::GetDrawableForWidget() {
- return skia_canvas_.get();
-}
-
-DriSkBitmap* DriSurface::CreateBuffer() {
- return new DriSkBitmap(controller_->get_fd());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface.h b/chromium/ui/gfx/ozone/dri/dri_surface.h
deleted file mode 100644
index 53258cf8086..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface.h
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_DRI_DRI_SURFACE_H_
-#define UI_GFX_OZONE_DRI_DRI_SURFACE_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/skia_util.h"
-
-class SkBitmapDevice;
-class SkCanvas;
-
-namespace gfx {
-
-class DriSkBitmap;
-class HardwareDisplayController;
-
-// DriSurface is used to represent a surface that can be scanned out
-// to a monitor. It will store the internal state associated with the drawing
-// surface associated with it. DriSurface also performs all the needed
-// operations to initialize and update the drawing surface.
-//
-// The implementation uses dumb buffers, which is used for software rendering.
-// The intent is to have one DriSurface implementation for a
-// HardwareDisplayController.
-//
-// DoubleBufferedSurface is intended to be the software analog to
-// EGLNativeSurface while DriSurface is intended to provide the glue
-// necessary to initialize and display the surface to the screen.
-//
-// The typical usage pattern is:
-// -----------------------------------------------------------------------------
-// HardwareDisplayController controller;
-// // Initialize controller
-//
-// DriSurface* surface = new DriSurface(controller);
-// surface.Initialize();
-// controller.BindSurfaceToController(surface);
-//
-// while (true) {
-// SkCanvas* canvas = surface->GetDrawableForWidget();
-// DrawStuff(canvas);
-// controller.SchedulePageFlip();
-//
-// Wait for page flip event. The DRM page flip handler will call
-// surface.SwapBuffers();
-// }
-//
-// delete surface;
-// -----------------------------------------------------------------------------
-// In the above example the wait consists of reading a DRM pageflip event from
-// the graphics card file descriptor. This is done by calling |drmHandleEvent|,
-// which will read and process the event. |drmHandleEvent| will call a callback
-// registered by |SchedulePageFlip| which will update the internal state.
-//
-// |SchedulePageFlip| can also be used to limit drawing to the screen's vsync
-// since page flips only happen on vsync. In a threaded environment a message
-// loop would listen on the graphics card file descriptor for an event and
-// |drmHandleEvent| would be called from the message loop. The event handler
-// would also be responsible for updating the renderer's state and signal that
-// it is OK to start drawing the next frame.
-//
-// The following example will illustrate the system state transitions in one
-// iteration of the above loop.
-//
-// 1. Both buffers contain the same image with b[0] being the front buffer
-// (star will represent the frontbuffer).
-// ------- -------
-// | | | |
-// | | | |
-// | | | |
-// | | | |
-// ------- -------
-// b[0]* b[1]
-//
-// 2. Call |GetBackbuffer| to get a SkCanvas wrapper for the backbuffer and draw
-// to it.
-// ------- -------
-// | | | |
-// | | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0]* b[1]
-//
-// 3. Call |SchedulePageFlip| to display the backbuffer. At this point we can't
-// modify b[0] because it is the frontbuffer and we can't modify b[1] since it
-// has been scheduled for pageflip. If we do draw in b[1] it is possible that
-// the pageflip and draw happen at the same time and we could get tearing.
-//
-// 4. The pageflip callback is called which will call |SwapSurfaces|. Before
-// |SwapSurfaces| is called the state is as following from the hardware's
-// perspective:
-// ------- -------
-// | | | |
-// | | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0] b[1]*
-//
-// 5. |SwapSurfaces| will update out internal reference to the front buffer and
-// synchronize the damaged area such that both buffers are identical. The
-// damaged area is used from the SkCanvas clip.
-// ------- -------
-// | | | |
-// | d | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0] b[1]*
-//
-// The synchronization consists of copying the damaged area from the frontbuffer
-// to the backbuffer.
-//
-// At this point we're back to step 1 and can start a new draw iteration.
-class GFX_EXPORT DriSurface {
- public:
- DriSurface(HardwareDisplayController* controller);
-
- virtual ~DriSurface();
-
- // Used to allocate all necessary buffers for this surface. If the
- // initialization succeeds, the device is ready to be used for drawing
- // operations.
- // Returns true if the initialization is successful, false otherwise.
- bool Initialize();
-
- // Returns the ID of the current backbuffer.
- uint32_t GetFramebufferId() const;
-
- // Synchronizes and swaps the back buffer with the front buffer.
- void SwapBuffers();
-
- // Get a Skia canvas for a backbuffer.
- SkCanvas* GetDrawableForWidget();
-
- private:
- friend class HardwareDisplayController;
-
- // Used to create the backing buffers.
- virtual DriSkBitmap* CreateBuffer();
-
- // Stores DRM information for this output device (connector, encoder, last
- // CRTC state).
- HardwareDisplayController* controller_;
-
- // The actual buffers used for painting.
- scoped_ptr<DriSkBitmap> bitmaps_[2];
-
- // BitmapDevice for the current backbuffer.
- skia::RefPtr<SkBitmapDevice> skia_device_;
-
- // Canvas for the current backbuffer.
- skia::RefPtr<SkCanvas> skia_canvas_;
-
- // Keeps track of which bitmap is |buffers_| is the frontbuffer.
- int front_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSurface);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SURFACE_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc b/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc
deleted file mode 100644
index 4c201373942..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/dri_surface_factory.h"
-
-#include <drm.h>
-#include <errno.h>
-#include <xf86drm.h>
-
-#include "base/message_loop/message_loop.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_vsync_provider.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace gfx {
-
-namespace {
-
-const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
-const char kDPMSProperty[] = "DPMS";
-
-const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
-
-// DRM callback on page flip events. This callback is triggered after the
-// page flip has happened and the backbuffer is now the new frontbuffer
-// The old frontbuffer is no longer used by the hardware and can be used for
-// future draw operations.
-//
-// |device| will contain a reference to the |DriSurface| object which
-// the event belongs to.
-//
-// TODO(dnicoara) When we have a FD handler for the DRM calls in the message
-// loop, we can move this function in the handler.
-void HandlePageFlipEvent(int fd,
- unsigned int frame,
- unsigned int seconds,
- unsigned int useconds,
- void* controller) {
- static_cast<HardwareDisplayController*>(controller)
- ->OnPageFlipEvent(frame, seconds, useconds);
-}
-
-uint32_t GetDriProperty(int fd, drmModeConnector* connector, const char* name) {
- for (int i = 0; i < connector->count_props; ++i) {
- drmModePropertyPtr property = drmModeGetProperty(fd, connector->props[i]);
- if (!property)
- continue;
-
- if (strcmp(property->name, name) == 0) {
- uint32_t id = property->prop_id;
- drmModeFreeProperty(property);
- return id;
- }
-
- drmModeFreeProperty(property);
- }
- return 0;
-}
-
-uint32_t GetCrtc(int fd, drmModeRes* resources, drmModeConnector* connector) {
- // If the connector already has an encoder try to re-use.
- if (connector->encoder_id) {
- drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoder_id);
- if (encoder) {
- if (encoder->crtc_id) {
- uint32_t crtc = encoder->crtc_id;
- drmModeFreeEncoder(encoder);
- return crtc;
- }
- drmModeFreeEncoder(encoder);
- }
- }
-
- // Try to find an encoder for the connector.
- for (int i = 0; i < connector->count_encoders; ++i) {
- drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoders[i]);
- if (!encoder)
- continue;
-
- for (int j = 0; j < resources->count_crtcs; ++j) {
- // Check if the encoder is compatible with this CRTC
- if (!(encoder->possible_crtcs & (1 << j)))
- continue;
-
- drmModeFreeEncoder(encoder);
- return resources->crtcs[j];
- }
- }
-
- return 0;
-}
-
-} // namespace
-
-DriSurfaceFactory::DriSurfaceFactory()
- : drm_(),
- state_(UNINITIALIZED),
- controller_() {
-}
-
-DriSurfaceFactory::~DriSurfaceFactory() {
- if (state_ == INITIALIZED)
- ShutdownHardware();
-}
-
-SurfaceFactoryOzone::HardwareState
-DriSurfaceFactory::InitializeHardware() {
- CHECK(state_ == UNINITIALIZED);
-
- // TODO(dnicoara): Short-cut right now. What we want is to look at all the
- // graphics devices available and select the primary one.
- drm_.reset(CreateWrapper());
- if (drm_->get_fd() < 0) {
- LOG(ERROR) << "Cannot open graphics card '"
- << kDefaultGraphicsCardPath << "': " << strerror(errno);
- state_ = FAILED;
- return state_;
- }
-
- state_ = INITIALIZED;
- return state_;
-}
-
-void DriSurfaceFactory::ShutdownHardware() {
- CHECK(state_ == INITIALIZED);
-
- controller_.reset();
- drm_.reset();
-
- state_ = UNINITIALIZED;
-}
-
-gfx::AcceleratedWidget DriSurfaceFactory::GetAcceleratedWidget() {
- CHECK(state_ != FAILED);
-
- // TODO(dnicoara) When there's more information on which display we want,
- // then we can return the widget associated with the display.
- // For now just assume we have 1 display device and return it.
- if (!controller_.get())
- controller_.reset(new HardwareDisplayController());
-
- // TODO(dnicoara) We only have 1 display for now, so only 1 AcceleratedWidget.
- // When we'll support multiple displays this needs to be changed to return a
- // different handle for every display.
- return kDefaultWidgetHandle;
-}
-
-gfx::AcceleratedWidget DriSurfaceFactory::RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- // TODO(dnicoara) Once we can handle multiple displays this needs to be
- // changed.
- CHECK(w == kDefaultWidgetHandle);
-
- CHECK(controller_->get_state() ==
- HardwareDisplayController::UNASSOCIATED);
-
- // Until now the controller is just a stub. Initializing it will link it to a
- // hardware display.
- if (!InitializeControllerForPrimaryDisplay(drm_.get(), controller_.get())) {
- LOG(ERROR) << "Failed to initialize controller";
- return gfx::kNullAcceleratedWidget;
- }
-
- // Create a surface suitable for the current controller.
- scoped_ptr<DriSurface> surface(CreateSurface(controller_.get()));
-
- if (!surface->Initialize()) {
- LOG(ERROR) << "Failed to initialize surface";
- return gfx::kNullAcceleratedWidget;
- }
-
- // Bind the surface to the controller. This will register the backing buffers
- // with the hardware CRTC such that we can show the buffers. The controller
- // takes ownership of the surface.
- if (!controller_->BindSurfaceToController(surface.Pass())) {
- LOG(ERROR) << "Failed to bind surface to controller";
- return gfx::kNullAcceleratedWidget;
- }
-
- return reinterpret_cast<gfx::AcceleratedWidget>(controller_->get_surface());
-}
-
-bool DriSurfaceFactory::LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
- return false;
-}
-
-bool DriSurfaceFactory::AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) {
- return false;
-}
-
-bool DriSurfaceFactory::SchedulePageFlip(gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- // TODO(dnicoara) Change this CHECK once we're running with the threaded
- // compositor.
- CHECK(base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI);
-
- // TODO(dnicoara) Once we can handle multiple displays this needs to be
- // changed.
- CHECK(w == kDefaultWidgetHandle);
-
- if (!controller_->SchedulePageFlip())
- return false;
-
- // Only wait for the page flip event to finish if it was properly scheduled.
- //
- // TODO(dnicoara) The following call will wait for the page flip event to
- // complete. This means that it will block until the next VSync. Ideally the
- // wait should happen in the message loop. The message loop would then
- // schedule the next draw event. Alternatively, the VSyncProvider could be
- // used to schedule the next draw. Unfortunately, at this point,
- // DriOutputDevice does not provide any means to use any of the above
- // solutions. Note that if the DRM callback does not schedule the next draw,
- // then some sort of synchronization needs to take place since starting a new
- // draw before the page flip happened is considered an error. However we can
- // not use any lock constructs unless we're using the threaded compositor.
- // Note that the following call does not use any locks, so it is safe to be
- // made on the UI thread (thought not ideal).
- WaitForPageFlipEvent(drm_->get_fd());
-
- return true;
-}
-
-SkCanvas* DriSurfaceFactory::GetCanvasForWidget(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- return reinterpret_cast<DriSurface*>(w)->GetDrawableForWidget();
-}
-
-gfx::VSyncProvider* DriSurfaceFactory::GetVSyncProvider(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- return new DriVSyncProvider(controller_.get());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSurfaceFactory private
-
-DriSurface* DriSurfaceFactory::CreateSurface(
- HardwareDisplayController* controller) {
- return new DriSurface(controller);
-}
-
-DriWrapper* DriSurfaceFactory::CreateWrapper() {
- return new DriWrapper(kDefaultGraphicsCardPath);
-}
-
-bool DriSurfaceFactory::InitializeControllerForPrimaryDisplay(
- DriWrapper* drm,
- HardwareDisplayController* controller) {
- CHECK(state_ == SurfaceFactoryOzone::INITIALIZED);
-
- drmModeRes* resources = drmModeGetResources(drm->get_fd());
-
- // Search for an active connector.
- for (int i = 0; i < resources->count_connectors; ++i) {
- drmModeConnector* connector = drmModeGetConnector(
- drm->get_fd(),
- resources->connectors[i]);
-
- if (!connector)
- continue;
-
- if (connector->connection != DRM_MODE_CONNECTED ||
- connector->count_modes == 0) {
- drmModeFreeConnector(connector);
- continue;
- }
-
- uint32_t crtc = GetCrtc(drm->get_fd(), resources, connector);
-
- if (!crtc)
- continue;
-
- uint32_t dpms_property_id = GetDriProperty(drm->get_fd(),
- connector,
- kDPMSProperty);
-
- // TODO(dnicoara) Select one mode for now. In the future we may need to
- // save all the modes and allow the user to choose a specific mode. Or
- // even some fullscreen applications may need to change the mode.
- controller->SetControllerInfo(
- drm,
- connector->connector_id,
- crtc,
- dpms_property_id,
- connector->modes[0]);
-
- drmModeFreeConnector(connector);
-
- return true;
- }
-
- return false;
-}
-
-void DriSurfaceFactory::WaitForPageFlipEvent(int fd) {
- drmEventContext drm_event;
- drm_event.version = DRM_EVENT_CONTEXT_VERSION;
- drm_event.page_flip_handler = HandlePageFlipEvent;
- drm_event.vblank_handler = NULL;
-
- // Wait for the page-flip to complete.
- drmHandleEvent(fd, &drm_event);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory.h b/chromium/ui/gfx/ozone/dri/dri_surface_factory.h
deleted file mode 100644
index 616e989e910..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_DRI_DRI_SURFACE_FACTORY_H_
-#define UI_GFX_OZONE_DRI_DRI_SURFACE_FACTORY_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-namespace gfx {
-
-class DriSurface;
-class DriWrapper;
-class HardwareDisplayController;
-
-// SurfaceFactoryOzone implementation on top of DRM/KMS using dumb buffers.
-// This implementation is used in conjunction with the software rendering
-// path.
-class GFX_EXPORT DriSurfaceFactory : public SurfaceFactoryOzone {
- public:
- DriSurfaceFactory();
- virtual ~DriSurfaceFactory();
-
- virtual HardwareState InitializeHardware() OVERRIDE;
- virtual void ShutdownHardware() OVERRIDE;
-
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
-
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) OVERRIDE;
-
- virtual bool SchedulePageFlip(gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual gfx::VSyncProvider* GetVSyncProvider(
- gfx::AcceleratedWidget w) OVERRIDE;
-
- private:
- virtual DriSurface* CreateSurface(
- HardwareDisplayController* controller);
-
- virtual DriWrapper* CreateWrapper();
-
- virtual bool InitializeControllerForPrimaryDisplay(
- DriWrapper* drm,
- HardwareDisplayController* controller);
-
- // Blocks until a DRM event is read.
- // TODO(dnicoara) Remove once we can safely move DRM event processing in the
- // message loop while correctly signaling when we're done displaying the
- // pending frame.
- virtual void WaitForPageFlipEvent(int fd);
-
- scoped_ptr<DriWrapper> drm_;
-
- HardwareState state_;
-
- // Active output.
- scoped_ptr<HardwareDisplayController> controller_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactory);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SURFACE_FACTORY_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc b/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc
deleted file mode 100644
index 2e70f642f2a..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_surface_factory.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-namespace {
-
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-const uint32_t kDPMSPropertyId = 1;
-
-const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
-
-// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper(int fd) : DriWrapper(""),
- add_framebuffer_expectation_(true),
- page_flip_expectation_(true) {
- fd_ = fd;
- }
-
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
- return new drmModeCrtc;
- }
-
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
- delete crtc;
- }
-
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE {
- return true;
- }
-
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- return true;
- }
-
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- return add_framebuffer_expectation_;
- }
-
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE { return true; }
-
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- static_cast<gfx::HardwareDisplayController*>(data)->get_surface()
- ->SwapBuffers();
- return page_flip_expectation_;
- }
-
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- void set_add_framebuffer_expectation(bool state) {
- add_framebuffer_expectation_ = state;
- }
-
- void set_page_flip_expectation(bool state) {
- page_flip_expectation_ = state;
- }
-
- private:
- bool add_framebuffer_expectation_;
- bool page_flip_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap() : DriSkBitmap(kFd) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- allocPixels();
- eraseColor(SK_ColorBLACK);
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller) {}
- virtual ~MockDriSurface() {}
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap();
- }
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-// SSFO would normally allocate DRM resources. We can't rely on having a DRM
-// backend to allocate and display our buffers. Thus, we replace these
-// resources with stubs. For DRM calls, we simply use stubs that do nothing and
-// for buffers we use the default SkBitmap allocator.
-class MockDriSurfaceFactory
- : public gfx::DriSurfaceFactory {
- public:
- MockDriSurfaceFactory()
- : DriSurfaceFactory(),
- mock_drm_(NULL),
- drm_wrapper_expectation_(true),
- initialize_controller_expectation_(true) {}
- virtual ~MockDriSurfaceFactory() {};
-
- void set_drm_wrapper_expectation(bool state) {
- drm_wrapper_expectation_ = state;
- }
-
- void set_initialize_controller_expectation(bool state) {
- initialize_controller_expectation_ = state;
- }
-
- MockDriWrapper* get_drm() const {
- return mock_drm_;
- }
-
- private:
- virtual gfx::DriSurface* CreateSurface(
- gfx::HardwareDisplayController* controller) OVERRIDE {
- return new MockDriSurface(controller);
- }
-
- virtual gfx::DriWrapper* CreateWrapper() OVERRIDE {
- if (drm_wrapper_expectation_)
- mock_drm_ = new MockDriWrapper(kFd);
- else
- mock_drm_ = new MockDriWrapper(-1);
-
- return mock_drm_;
- }
-
- // Normally we'd use DRM to figure out the controller configuration. But we
- // can't use DRM in unit tests, so we just create a fake configuration.
- virtual bool InitializeControllerForPrimaryDisplay(
- gfx::DriWrapper* drm,
- gfx::HardwareDisplayController* controller) OVERRIDE {
- if (initialize_controller_expectation_) {
- controller->SetControllerInfo(drm,
- kConnectorId,
- kCrtcId,
- kDPMSPropertyId,
- kDefaultMode);
- return true;
- } else {
- return false;
- }
- }
-
- virtual void WaitForPageFlipEvent(int fd) OVERRIDE {}
-
- MockDriWrapper* mock_drm_;
- bool drm_wrapper_expectation_;
- bool initialize_controller_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurfaceFactory);
-};
-
-} // namespace
-
-class DriSurfaceFactoryTest : public testing::Test {
- public:
- DriSurfaceFactoryTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
- protected:
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<MockDriSurfaceFactory> factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactoryTest);
-};
-
-void DriSurfaceFactoryTest::SetUp() {
- message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
- factory_.reset(new MockDriSurfaceFactory());
-}
-
-void DriSurfaceFactoryTest::TearDown() {
- factory_.reset();
- message_loop_.reset();
-}
-
-TEST_F(DriSurfaceFactoryTest, FailInitialization) {
- factory_->set_drm_wrapper_expectation(false);
-
- EXPECT_EQ(gfx::SurfaceFactoryOzone::FAILED, factory_->InitializeHardware());
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulInitialization) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-}
-
-TEST_F(DriSurfaceFactoryTest, FailSurfaceInitialization) {
- factory_->set_initialize_controller_expectation(false);
-
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_EQ(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, FailBindingSurfaceToController) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- factory_->get_drm()->set_add_framebuffer_expectation(false);
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_EQ(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulWidgetRealization) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, FailSchedulePageFlip) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- factory_->get_drm()->set_page_flip_expectation(false);
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-
- EXPECT_FALSE(factory_->SchedulePageFlip(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulSchedulePageFlip) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-
- EXPECT_TRUE(factory_->SchedulePageFlip(w));
-}
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc b/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc
deleted file mode 100644
index 754659163a2..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace {
-
-// Create a basic mode for a 6x4 screen.
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-// Mock DPMS property ID.
-const uint32_t kDPMSPropertyId = 1;
-
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper() : DriWrapper(""), id_(1) { fd_ = kFd; }
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE { return NULL; }
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {}
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE { return true; }
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- return true;
- }
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- *framebuffer = id_++;
- return true;
- }
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE { return true; }
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- return true;
- }
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- private:
- int id_;
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap(int fd,
- bool initialize_expectation)
- : DriSkBitmap(fd),
- initialize_expectation_(initialize_expectation) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- if (!initialize_expectation_)
- return false;
-
- allocPixels();
- // Clear the bitmap to black.
- eraseColor(SK_ColorBLACK);
-
- return true;
- }
- private:
- bool initialize_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller),
- initialize_expectation_(true) {}
- virtual ~MockDriSurface() {}
-
- void set_initialize_expectation(bool state) {
- initialize_expectation_ = state;
- }
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap(kFd, initialize_expectation_);
- }
-
- bool initialize_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-} // namespace
-
-class DriSurfaceTest : public testing::Test {
- public:
- DriSurfaceTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
-
- protected:
- scoped_ptr<MockDriWrapper> drm_;
- scoped_ptr<gfx::HardwareDisplayController> controller_;
- scoped_ptr<MockDriSurface> surface_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceTest);
-};
-
-void DriSurfaceTest::SetUp() {
- drm_.reset(new MockDriWrapper());
- controller_.reset(new gfx::HardwareDisplayController());
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
-
- surface_.reset(new MockDriSurface(controller_.get()));
-}
-
-void DriSurfaceTest::TearDown() {
- surface_.reset();
- controller_.reset();
- drm_.reset();
-}
-
-TEST_F(DriSurfaceTest, FailInitialization) {
- surface_->set_initialize_expectation(false);
- EXPECT_FALSE(surface_->Initialize());
-}
-
-TEST_F(DriSurfaceTest, SuccessfulInitialization) {
- EXPECT_TRUE(surface_->Initialize());
-}
-
-TEST_F(DriSurfaceTest, CheckFBIDOnSwap) {
- EXPECT_TRUE(surface_->Initialize());
- controller_->BindSurfaceToController(
- surface_.PassAs<gfx::DriSurface>());
-
- // Check that the framebuffer ID is correct.
- EXPECT_EQ(2u, controller_->get_surface()->GetFramebufferId());
-
- controller_->get_surface()->SwapBuffers();
-
- EXPECT_EQ(1u, controller_->get_surface()->GetFramebufferId());
-}
-
-TEST_F(DriSurfaceTest, CheckPixelPointerOnSwap) {
- EXPECT_TRUE(surface_->Initialize());
-
- void* bitmap_pixels1 = surface_->GetDrawableForWidget()->getDevice()
- ->accessBitmap(false).getPixels();
-
- surface_->SwapBuffers();
-
- void* bitmap_pixels2 = surface_->GetDrawableForWidget()->getDevice()
- ->accessBitmap(false).getPixels();
-
- // Check that once the buffers have been swapped the drawable's underlying
- // pixels have been changed.
- EXPECT_NE(bitmap_pixels1, bitmap_pixels2);
-}
-
-TEST_F(DriSurfaceTest, CheckCorrectBufferSync) {
- EXPECT_TRUE(surface_->Initialize());
-
- SkCanvas* canvas = surface_->GetDrawableForWidget();
- SkRect clip;
- // Modify part of the canvas.
- clip.set(0, 0,
- canvas->getDeviceSize().width() / 2,
- canvas->getDeviceSize().height() / 2);
- canvas->clipRect(clip, SkRegion::kReplace_Op);
-
- canvas->drawColor(SK_ColorWHITE);
-
- surface_->SwapBuffers();
-
- // Verify that the modified contents have been copied over on swap (make sure
- // the 2 buffers have the same content).
- for (int i = 0; i < canvas->getDeviceSize().height(); ++i) {
- for (int j = 0; j < canvas->getDeviceSize().width(); ++j) {
- if (i < clip.height() && j < clip.width())
- EXPECT_EQ(SK_ColorWHITE,
- canvas->getDevice()->accessBitmap(false).getColor(j, i));
- else
- EXPECT_EQ(SK_ColorBLACK,
- canvas->getDevice()->accessBitmap(false).getColor(j, i));
- }
- }
-}
diff --git a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc
deleted file mode 100644
index b5717e686f1..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/dri_vsync_provider.h"
-
-#include "base/time/time.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace gfx {
-
-DriVSyncProvider::DriVSyncProvider(HardwareDisplayController* controller)
- : controller_(controller) {}
-
-DriVSyncProvider::~DriVSyncProvider() {}
-
-void DriVSyncProvider::GetVSyncParameters(const UpdateVSyncCallback& callback) {
- // The value is invalid, so we can't update the parameters.
- if (controller_->get_time_of_last_flip() == 0)
- return;
-
- // Stores the time of the last refresh.
- base::TimeTicks timebase =
- base::TimeTicks::FromInternalValue(controller_->get_time_of_last_flip());
- // Stores the refresh rate.
- base::TimeDelta interval =
- base::TimeDelta::FromSeconds(1) / controller_->get_mode().vrefresh;
-
- callback.Run(timebase, interval);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h
deleted file mode 100644
index b6cb6047eb8..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
-#define UI_GFX_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
-
-#include "ui/gfx/vsync_provider.h"
-
-namespace gfx {
-
-class HardwareDisplayController;
-
-class DriVSyncProvider : public VSyncProvider {
- public:
- DriVSyncProvider(HardwareDisplayController* controller);
- virtual ~DriVSyncProvider();
-
- virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) OVERRIDE;
-
- private:
- HardwareDisplayController* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(DriVSyncProvider);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_wrapper.cc b/chromium/ui/gfx/ozone/dri/dri_wrapper.cc
deleted file mode 100644
index 2b1104b444d..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_wrapper.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <xf86drmMode.h>
-
-#include "base/logging.h"
-
-namespace gfx {
-
-DriWrapper::DriWrapper(const char* device_path) {
- fd_ = open(device_path, O_RDWR | O_CLOEXEC);
-}
-
-DriWrapper::~DriWrapper() {
- if (fd_ >= 0)
- close(fd_);
-}
-
-drmModeCrtc* DriWrapper::GetCrtc(uint32_t crtc_id) {
- CHECK(fd_ >= 0);
- return drmModeGetCrtc(fd_, crtc_id);
-}
-
-void DriWrapper::FreeCrtc(drmModeCrtc* crtc) {
- drmModeFreeCrtc(crtc);
-}
-
-bool DriWrapper::SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) {
- CHECK(fd_ >= 0);
- return !drmModeSetCrtc(fd_, crtc_id, framebuffer, 0, 0, connectors, 1, mode);
-}
-
-bool DriWrapper::SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) {
- CHECK(fd_ >= 0);
- return !drmModeSetCrtc(fd_,
- crtc->crtc_id,
- crtc->buffer_id,
- crtc->x,
- crtc->y,
- connectors,
- 1,
- &crtc->mode);
-}
-
-bool DriWrapper::AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) {
- CHECK(fd_ >= 0);
- return !drmModeAddFB(fd_,
- mode.hdisplay,
- mode.vdisplay,
- depth,
- bpp,
- stride,
- handle,
- framebuffer);
-}
-
-bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
- CHECK(fd_ >= 0);
- return !drmModeRmFB(fd_, framebuffer);
-}
-
-bool DriWrapper::PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) {
- CHECK(fd_ >= 0);
- return !drmModePageFlip(fd_,
- crtc_id,
- framebuffer,
- DRM_MODE_PAGE_FLIP_EVENT,
- data);
-}
-
-bool DriWrapper::ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) {
- CHECK(fd_ >= 0);
- return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_wrapper.h b/chromium/ui/gfx/ozone/dri/dri_wrapper.h
deleted file mode 100644
index 0848132c9ad..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_wrapper.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_DRI_DRI_WRAPPER_H_
-#define UI_GFX_OZONE_DRI_DRI_WRAPPER_H_
-
-#include <stdint.h>
-
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _drmModeCrtc drmModeCrtc;
-typedef struct _drmModeModeInfo drmModeModeInfo;
-
-namespace gfx {
-
-// Wraps DRM calls into a nice interface. Used to provide different
-// implementations of the DRM calls. For the actual implementation the DRM API
-// would be called. In unit tests this interface would be stubbed.
-class GFX_EXPORT DriWrapper {
- public:
- DriWrapper(const char* device_path);
- virtual ~DriWrapper();
-
- // Get the CRTC state. This is generally used to save state before using the
- // CRTC. When the user finishes using the CRTC, the user should restore the
- // CRTC to it's initial state. Use |SetCrtc| to restore the state.
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id);
-
- // Frees the CRTC mode object.
- virtual void FreeCrtc(drmModeCrtc* crtc);
-
- // Used to configure CRTC with ID |crtc_id| to use the connector in
- // |connectors|. The CRTC will be configured with mode |mode| and will display
- // the framebuffer with ID |framebuffer|. Before being able to display the
- // framebuffer, it should be registered with the CRTC using |AddFramebuffer|.
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode);
-
- // Used to set a specific configuration to the CRTC. Normally this function
- // would be called with a CRTC saved state (from |GetCrtc|) to restore it to
- // its original configuration.
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors);
-
- // Register a buffer with the CRTC. On successful registration, the CRTC will
- // assign a framebuffer ID to |framebuffer|.
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer);
-
- // Deregister the given |framebuffer|.
- virtual bool RemoveFramebuffer(uint32_t framebuffer);
-
- // Schedules a pageflip for CRTC |crtc_id|. This function will return
- // immediately. Upon completion of the pageflip event, the CRTC will be
- // displaying the buffer with ID |framebuffer| and will have a DRM event
- // queued on |fd_|. |data| is a generic pointer to some information the user
- // will receive when processing the pageflip event.
- virtual bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, void* data);
-
- // Sets the value of property with ID |property_id| to |value|. The property
- // is applied to the connector with ID |connector_id|.
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value);
-
- int get_fd() const { return fd_; }
-
- protected:
- // The file descriptor associated with this wrapper. All DRM operations will
- // be performed using this FD.
- int fd_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriWrapper);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_WRAPPER_H_
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc b/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc
deleted file mode 100644
index 6accfc00d53..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-#include <errno.h>
-#include <string.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-
-namespace gfx {
-
-HardwareDisplayController::HardwareDisplayController()
- : drm_(NULL),
- connector_id_(0),
- crtc_id_(0),
- mode_(),
- saved_crtc_(NULL),
- state_(UNASSOCIATED),
- surface_(),
- time_of_last_flip_(0) {}
-
-void HardwareDisplayController::SetControllerInfo(
- DriWrapper* drm,
- uint32_t connector_id,
- uint32_t crtc_id,
- uint32_t dpms_property_id,
- drmModeModeInfo mode) {
- drm_ = drm;
- connector_id_ = connector_id;
- crtc_id_ = crtc_id;
- dpms_property_id_ = dpms_property_id;
- mode_ = mode;
- saved_crtc_ = drm_->GetCrtc(crtc_id_);
- state_ = UNINITIALIZED;
-}
-
-HardwareDisplayController::~HardwareDisplayController() {
- if (saved_crtc_) {
- if (!drm_->SetCrtc(saved_crtc_, &connector_id_))
- DLOG(ERROR) << "Failed to restore CRTC state: " << strerror(errno);
- drm_->FreeCrtc(saved_crtc_);
- }
-
- if (surface_.get()) {
- // Unregister the buffers.
- for (int i = 0; i < 2; ++i) {
- if (!drm_->RemoveFramebuffer(surface_->bitmaps_[i]->get_framebuffer()))
- DLOG(ERROR) << "Failed to remove FB: " << strerror(errno);
- }
- }
-}
-
-bool
-HardwareDisplayController::BindSurfaceToController(
- scoped_ptr<DriSurface> surface) {
- CHECK(state_ == UNINITIALIZED);
-
- // Register the buffers.
- for (int i = 0; i < 2; ++i) {
- uint32_t fb_id;
- if (!drm_->AddFramebuffer(mode_,
- surface->bitmaps_[i]->GetColorDepth(),
- surface->bitmaps_[i]->bytesPerPixel() << 3,
- surface->bitmaps_[i]->rowBytes(),
- surface->bitmaps_[i]->get_handle(),
- &fb_id)) {
- DLOG(ERROR) << "Failed to register framebuffer: " << strerror(errno);
- state_ = FAILED;
- return false;
- }
- surface->bitmaps_[i]->set_framebuffer(fb_id);
- }
-
- surface_.reset(surface.release());
- state_ = SURFACE_INITIALIZED;
- return true;
-}
-
-bool HardwareDisplayController::SchedulePageFlip() {
- CHECK(state_ == SURFACE_INITIALIZED || state_ == INITIALIZED);
-
- if (state_ == SURFACE_INITIALIZED) {
- // Perform the initial modeset.
- if (!drm_->SetCrtc(crtc_id_,
- surface_->GetFramebufferId(),
- &connector_id_,
- &mode_)) {
- DLOG(ERROR) << "Cannot set CRTC: " << strerror(errno);
- state_ = FAILED;
- return false;
- } else {
- state_ = INITIALIZED;
- }
-
- if (dpms_property_id_)
- drm_->ConnectorSetProperty(connector_id_,
- dpms_property_id_,
- DRM_MODE_DPMS_ON);
- }
-
- if (!drm_->PageFlip(crtc_id_,
- surface_->GetFramebufferId(),
- this)) {
- state_ = FAILED;
- LOG(ERROR) << "Cannot page flip: " << strerror(errno);
- return false;
- }
-
- return true;
-}
-
-void HardwareDisplayController::OnPageFlipEvent(unsigned int frame,
- unsigned int seconds,
- unsigned int useconds) {
- time_of_last_flip_ =
- static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
- useconds;
-
- surface_->SwapBuffers();
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller.h b/chromium/ui/gfx/ozone/dri/hardware_display_controller.h
deleted file mode 100644
index cae8a6ba821..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
-#define UI_GFX_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <xf86drmMode.h>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-
-namespace gfx {
-
-class DriSurface;
-
-// The HDCOz will handle modesettings and scannout operations for hardware
-// devices.
-//
-// In the DRM world there are 3 components that need to be paired up to be able
-// to display an image to the monitor: CRTC (cathode ray tube controller),
-// encoder and connector. The CRTC determines which framebuffer to read, when
-// to scanout and where to scanout. Encoders converts the stream from the CRTC
-// to the appropriate format for the connector. The connector is the physical
-// connection that monitors connect to.
-//
-// There is no 1:1:1 pairing for these components. It is possible for an encoder
-// to be compatible to multiple CRTCs and each connector can be used with
-// multiple encoders. In addition, it is possible to use one CRTC with multiple
-// connectors such that we can display the same image on multiple monitors.
-//
-// For example, the following configuration shows 2 different screens being
-// initialized separately.
-// ------------- -------------
-// | Connector | | Connector |
-// | HDMI | | VGA |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | Encoder1 | | Encoder2 |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | CRTC1 | | CRTC2 |
-// ------------- -------------
-//
-// In the following configuration 2 different screens are associated with the
-// same CRTC, so on scanout the same framebuffer will be displayed on both
-// monitors.
-// ------------- -------------
-// | Connector | | Connector |
-// | HDMI | | VGA |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | Encoder1 | | Encoder2 |
-// ------------- -------------
-// ^ ^
-// | |
-// ----------------------
-// | CRTC1 |
-// ----------------------
-//
-// Note that it is possible to have more connectors than CRTCs which means that
-// only a subset of connectors can be active independently, showing different
-// framebuffers. Though, in this case, it would be possible to have all
-// connectors active if some use the same CRTC to mirror the display.
-//
-// TODO(dnicoara) Need to have a way to detect events (such as monitor
-// connected or disconnected).
-class GFX_EXPORT HardwareDisplayController {
- public:
- // Controller states. The state transitions will happen from top to bottom.
- enum State {
- // When we allocate a HDCO as a stub. At this point there is no connector
- // and CRTC associated with this device.
- UNASSOCIATED,
-
- // When |SetControllerInfo| is called and the HDCO has the information of
- // the hardware it will control. At this point it knows everything it needs
- // to control the hardware but doesn't have a surface.
- UNINITIALIZED,
-
- // A surface is associated with the HDCO. This means that the controller can
- // potentially display the backing surface to the display. Though the
- // surface framebuffer still needs to be registered with the CRTC.
- SURFACE_INITIALIZED,
-
- // The CRTC now knows about the surface attributes.
- INITIALIZED,
-
- // Error state if any of the initialization steps fail.
- FAILED,
- };
-
- HardwareDisplayController();
-
- ~HardwareDisplayController();
-
- // Set the hardware configuration for this HDCO. Once this is set, the HDCO is
- // responsible for keeping track of the connector and CRTC and cleaning up
- // when it is destroyed.
- void SetControllerInfo(DriWrapper* drm,
- uint32_t connector_id,
- uint32_t crtc_id,
- uint32_t dpms_property_id,
- drmModeModeInfo mode);
-
- // Associate the HDCO with a surface implementation and initialize it.
- bool BindSurfaceToController(scoped_ptr<DriSurface> surface);
-
- // Schedules the |surface_|'s framebuffer to be displayed on the next vsync
- // event. The event will be posted on the graphics card file descriptor |fd_|
- // and it can be read and processed by |drmHandleEvent|. That function can
- // define the callback for the page flip event. A generic data argument will
- // be presented to the callback. We use that argument to pass in the HDCO
- // object the event belongs to.
- //
- // Between this call and the callback, the framebuffer used in this call
- // should not be modified in any way as it would cause screen tearing if the
- // hardware performed the flip. Note that the frontbuffer should also not
- // be modified as it could still be displayed.
- //
- // Note that this function does not block. Also, this function should not be
- // called again before the page flip occurrs.
- //
- // Returns true if the page flip was successfully registered, false otherwise.
- bool SchedulePageFlip();
-
- // Called when the page flip event occurred. The event is provided by the
- // kernel when a VBlank event finished. This allows the controller to
- // update internal state and propagate the update to the surface.
- // The tuple (seconds, useconds) represents the event timestamp. |seconds|
- // represents the number of seconds while |useconds| represents the
- // microseconds (< 1 second) in the timestamp.
- void OnPageFlipEvent(unsigned int frame,
- unsigned int seconds,
- unsigned int useconds);
-
- State get_state() const { return state_; };
-
- int get_fd() const { return drm_->get_fd(); };
-
- const drmModeModeInfo& get_mode() const { return mode_; };
-
- DriSurface* get_surface() const { return surface_.get(); };
-
- uint64_t get_time_of_last_flip() const {
- return time_of_last_flip_;
- };
-
- private:
- // Object containing the connection to the graphics device and wraps the API
- // calls to control it.
- DriWrapper* drm_;
-
- // TODO(dnicoara) Need to allow a CRTC to have multiple connectors.
- uint32_t connector_id_;
-
- uint32_t crtc_id_;
-
- uint32_t dpms_property_id_;
-
- // TODO(dnicoara) Need to store all the modes.
- drmModeModeInfo mode_;
-
- // Saved CRTC state from before we used it. Need it to restore state once we
- // are finished using this device.
- drmModeCrtc* saved_crtc_;
-
- State state_;
-
- scoped_ptr<DriSurface> surface_;
-
- uint64_t time_of_last_flip_;
-
- DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc b/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc
deleted file mode 100644
index 3806b5a157b..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace {
-
-// Create a basic mode for a 6x4 screen.
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-const uint32_t kDPMSPropertyId = 1;
-
-// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper(int fd) : DriWrapper(""),
- get_crtc_call_count_(0),
- free_crtc_call_count_(0),
- restore_crtc_call_count_(0),
- add_framebuffer_call_count_(0),
- remove_framebuffer_call_count_(0),
- set_crtc_expectation_(true),
- add_framebuffer_expectation_(true),
- page_flip_expectation_(true) {
- fd_ = fd;
- }
-
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
- get_crtc_call_count_++;
- return new drmModeCrtc;
- }
-
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
- free_crtc_call_count_++;
- delete crtc;
- }
-
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE {
- return set_crtc_expectation_;
- }
-
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- restore_crtc_call_count_++;
- return true;
- }
-
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- add_framebuffer_call_count_++;
- return add_framebuffer_expectation_;
- }
-
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE {
- remove_framebuffer_call_count_++;
- return true;
- }
-
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- return page_flip_expectation_;
- }
-
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- int get_get_crtc_call_count() const {
- return get_crtc_call_count_;
- }
-
- int get_free_crtc_call_count() const {
- return free_crtc_call_count_;
- }
-
- int get_restore_crtc_call_count() const {
- return restore_crtc_call_count_;
- }
-
- int get_add_framebuffer_call_count() const {
- return add_framebuffer_call_count_;
- }
-
- int get_remove_framebuffer_call_count() const {
- return remove_framebuffer_call_count_;
- }
-
- void set_set_crtc_expectation(bool state) {
- set_crtc_expectation_ = state;
- }
-
- void set_add_framebuffer_expectation(bool state) {
- add_framebuffer_expectation_ = state;
- }
-
- void set_page_flip_expectation(bool state) {
- page_flip_expectation_ = state;
- }
-
- private:
- int get_crtc_call_count_;
- int free_crtc_call_count_;
- int restore_crtc_call_count_;
- int add_framebuffer_call_count_;
- int remove_framebuffer_call_count_;
-
- bool set_crtc_expectation_;
- bool add_framebuffer_expectation_;
- bool page_flip_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap(int fd) : DriSkBitmap(fd) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- return allocPixels();
- }
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller) {}
- virtual ~MockDriSurface() {}
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap(kFd);
- }
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-} // namespace
-
-class HardwareDisplayControllerTest : public testing::Test {
- public:
- HardwareDisplayControllerTest() {}
- virtual ~HardwareDisplayControllerTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
- protected:
- scoped_ptr<gfx::HardwareDisplayController> controller_;
- scoped_ptr<MockDriWrapper> drm_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerTest);
-};
-
-void HardwareDisplayControllerTest::SetUp() {
- controller_.reset(new gfx::HardwareDisplayController());
- drm_.reset(new MockDriWrapper(kFd));
-}
-
-void HardwareDisplayControllerTest::TearDown() {
- controller_.reset();
- drm_.reset();
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckInitialState) {
- EXPECT_EQ(gfx::HardwareDisplayController::UNASSOCIATED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest,
- CheckStateAfterControllerIsInitialized) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
-
- EXPECT_EQ(1, drm_->get_get_crtc_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::UNINITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateAfterSurfaceIsBound) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(2, drm_->get_add_framebuffer_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::SURFACE_INITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfBindingFails) {
- drm_->set_add_framebuffer_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_FALSE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(1, drm_->get_add_framebuffer_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::INITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
- drm_->set_set_crtc_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
- drm_->set_page_flip_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckProperDestruction) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(gfx::HardwareDisplayController::SURFACE_INITIALIZED,
- controller_->get_state());
-
- controller_.reset();
-
- EXPECT_EQ(2, drm_->get_remove_framebuffer_call_count());
- EXPECT_EQ(1, drm_->get_restore_crtc_call_count());
- EXPECT_EQ(1, drm_->get_free_crtc_call_count());
-}
diff --git a/chromium/ui/gfx/ozone/impl/file_surface_factory.cc b/chromium/ui/gfx/ozone/impl/file_surface_factory.cc
deleted file mode 100644
index 9d34f7f95a3..00000000000
--- a/chromium/ui/gfx/ozone/impl/file_surface_factory.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/impl/file_surface_factory.h"
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/location.h"
-#include "base/stl_util.h"
-#include "base/threading/worker_pool.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/codec/png_codec.h"
-
-namespace {
-
-void WriteDataToFile(const base::FilePath& location,
- const SkBitmap& bitmap) {
- std::vector<unsigned char> png_data;
- gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, true, &png_data);
- file_util::WriteFile(location,
- (char*)vector_as_array(&png_data),
- png_data.size());
-}
-
-}
-
-namespace gfx {
-
-FileSurfaceFactory::FileSurfaceFactory(
- const base::FilePath& dump_location)
- : location_(dump_location) {
- CHECK(!base::DirectoryExists(location_))
- << "Location cannot be a directory (" << location_.value() << ")";
- CHECK(!base::PathExists(location_) || base::PathIsWritable(location_));
-}
-
-FileSurfaceFactory::~FileSurfaceFactory() {}
-
-SurfaceFactoryOzone::HardwareState
-FileSurfaceFactory::InitializeHardware() {
- return INITIALIZED;
-}
-
-void FileSurfaceFactory::ShutdownHardware() {
-}
-
-AcceleratedWidget FileSurfaceFactory::GetAcceleratedWidget() {
- return 1;
-}
-
-AcceleratedWidget FileSurfaceFactory::RealizeAcceleratedWidget(
- AcceleratedWidget widget) {
- return 1;
-}
-
-bool FileSurfaceFactory::LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
- return false;
-}
-
-bool FileSurfaceFactory::AttemptToResizeAcceleratedWidget(
- AcceleratedWidget widget,
- const Rect& bounds) {
- device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
- bounds.width(),
- bounds.height()));
- canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
- return true;
-}
-
-bool FileSurfaceFactory::SchedulePageFlip(AcceleratedWidget widget) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- device_->width(),
- device_->height());
-
- if (canvas_->readPixels(&bitmap, 0, 0)) {
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(&WriteDataToFile, location_, bitmap),
- true);
- }
- return true;
-}
-
-SkCanvas* FileSurfaceFactory::GetCanvasForWidget(AcceleratedWidget w) {
- return canvas_.get();
-}
-
-VSyncProvider* FileSurfaceFactory::GetVSyncProvider(AcceleratedWidget w) {
- return NULL;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/impl/file_surface_factory.h b/chromium/ui/gfx/ozone/impl/file_surface_factory.h
deleted file mode 100644
index 19f1c946a33..00000000000
--- a/chromium/ui/gfx/ozone/impl/file_surface_factory.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
-#define UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-#include "ui/gfx/skia_util.h"
-
-class SkBitmapDevice;
-class SkCanvas;
-
-namespace gfx {
-
-class GFX_EXPORT FileSurfaceFactory : public SurfaceFactoryOzone {
- public:
- explicit FileSurfaceFactory(const base::FilePath& dump_location);
- virtual ~FileSurfaceFactory();
-
- private:
- // SurfaceFactoryOzone:
- virtual HardwareState InitializeHardware() OVERRIDE;
- virtual void ShutdownHardware() OVERRIDE;
- virtual AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual AcceleratedWidget RealizeAcceleratedWidget(
- AcceleratedWidget widget) OVERRIDE;
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
- virtual bool AttemptToResizeAcceleratedWidget(AcceleratedWidget widget,
- const Rect& bounds) OVERRIDE;
- virtual bool SchedulePageFlip(AcceleratedWidget widget) OVERRIDE;
- virtual SkCanvas* GetCanvasForWidget(AcceleratedWidget widget) OVERRIDE;
- virtual VSyncProvider* GetVSyncProvider(AcceleratedWidget widget) OVERRIDE;
-
- base::FilePath location_;
- skia::RefPtr<SkBitmapDevice> device_;
- skia::RefPtr<SkCanvas> canvas_;
-
- DISALLOW_COPY_AND_ASSIGN(FileSurfaceFactory);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
diff --git a/chromium/ui/gfx/ozone/surface_factory_ozone.cc b/chromium/ui/gfx/ozone/surface_factory_ozone.cc
deleted file mode 100644
index ea8e2f1a0b2..00000000000
--- a/chromium/ui/gfx/ozone/surface_factory_ozone.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-#include <stdlib.h>
-
-#include "base/command_line.h"
-
-namespace gfx {
-
-// static
-SurfaceFactoryOzone* SurfaceFactoryOzone::impl_ = NULL;
-
-class SurfaceFactoryOzoneStub : public SurfaceFactoryOzone {
- public:
- SurfaceFactoryOzoneStub() {}
- virtual ~SurfaceFactoryOzoneStub() {}
-
- virtual HardwareState InitializeHardware() OVERRIDE { return INITIALIZED; }
- virtual void ShutdownHardware() OVERRIDE {}
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 0; }
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) OVERRIDE {
- return 0;
- }
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE {
- return true;
- }
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) OVERRIDE {
- return false;
- }
- virtual gfx::VSyncProvider* GetVSyncProvider(
- gfx::AcceleratedWidget w) OVERRIDE {
- return NULL;
- }
-};
-
-SurfaceFactoryOzone::SurfaceFactoryOzone() {
-}
-
-SurfaceFactoryOzone::~SurfaceFactoryOzone() {
-}
-
-SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() {
- CHECK(impl_) << "No SurfaceFactoryOzone implementation set.";
- return impl_;
-}
-
-void SurfaceFactoryOzone::SetInstance(SurfaceFactoryOzone* impl) {
- impl_ = impl;
-}
-
-const char* SurfaceFactoryOzone::DefaultDisplaySpec() {
- char* envvar = getenv("ASH_DISPLAY_SPEC");
- if (envvar)
- return envvar;
- return "720x1280*2";
-}
-
-gfx::Screen* SurfaceFactoryOzone::CreateDesktopScreen() {
- return NULL;
-}
-
-intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
- return 0;
-}
-
-bool SurfaceFactoryOzone::SchedulePageFlip(gfx::AcceleratedWidget w) {
- return true;
-}
-
-SkCanvas* SurfaceFactoryOzone::GetCanvasForWidget(gfx::AcceleratedWidget w) {
- return NULL;
-}
-
-const int32* SurfaceFactoryOzone::GetEGLSurfaceProperties(
- const int32* desired_attributes) {
- return desired_attributes;
-}
-
-// static
-SurfaceFactoryOzone* SurfaceFactoryOzone::CreateTestHelper() {
- return new SurfaceFactoryOzoneStub;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/surface_factory_ozone.h b/chromium/ui/gfx/ozone/surface_factory_ozone.h
deleted file mode 100644
index c09a65ff8c7..00000000000
--- a/chromium/ui/gfx/ozone/surface_factory_ozone.h
+++ /dev/null
@@ -1,147 +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_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
-#define UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
-
-#include "base/callback.h"
-#include "base/native_library.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-
-class SkCanvas;
-
-namespace gfx {
-class Screen;
-class VSyncProvider;
-
-// The Ozone interface allows external implementations to hook into Chromium to
-// provide a system specific implementation. The Ozone interface supports two
-// drawing modes: 1) accelerated drawing through EGL and 2) software drawing
-// through Skia.
-//
-// The following functionality is specific to the drawing mode and may not have
-// any meaningful implementation in the other mode. An implementation must
-// provide functionality for at least one mode.
-//
-// 1) Accelerated Drawing (EGL path):
-//
-// The following functions are specific to EGL:
-// - GetNativeDisplay
-// - LoadEGLGLES2Bindings
-// - GetEGLSurfaceProperties (optional if the properties match the default
-// Chromium ones).
-//
-// 2) Software Drawing (Skia):
-//
-// The following function is specific to the software path:
-// - GetCanvasForWidget
-//
-// The accelerated path can optionally provide support for the software drawing
-// path.
-//
-// The remaining functions are not covered since they are needed in both drawing
-// modes (See comments bellow for descriptions).
-class GFX_EXPORT SurfaceFactoryOzone {
- public:
- // Describes the state of the hardware after initialization.
- enum HardwareState {
- UNINITIALIZED,
- INITIALIZED,
- FAILED,
- };
-
- typedef void*(*GLGetProcAddressProc)(const char* name);
- typedef base::Callback<void(base::NativeLibrary)> AddGLLibraryCallback;
- typedef base::Callback<void(GLGetProcAddressProc)>
- SetGLGetProcAddressProcCallback;
-
- SurfaceFactoryOzone();
- virtual ~SurfaceFactoryOzone();
-
- // Returns the instance
- static SurfaceFactoryOzone* GetInstance();
-
- // Returns a display spec as in |CreateDisplayFromSpec| for the default
- // native surface.
- virtual const char* DefaultDisplaySpec();
-
- // Sets the implementation delegate. Ownership is retained by the caller.
- static void SetInstance(SurfaceFactoryOzone* impl);
-
- // TODO(rjkroege): decide how to separate screen/display stuff from SFOz
- // This method implements gfx::Screen, particularly useful in Desktop Aura.
- virtual gfx::Screen* CreateDesktopScreen();
-
- // Configures the display hardware. Must be called from within the GPU
- // process before the sandbox has been activated.
- virtual HardwareState InitializeHardware() = 0;
-
- // Cleans up display hardware state. Call this from within the GPU process.
- // This method must be safe to run inside of the sandbox.
- virtual void ShutdownHardware() = 0;
-
- // Returns native platform display handle. This is used to obtain the EGL
- // display connection for the native display.
- virtual intptr_t GetNativeDisplay();
-
- // Obtains an AcceleratedWidget backed by a native Linux framebuffer.
- // The returned AcceleratedWidget is an opaque token that must realized
- // before it can be used to create a GL surface.
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
-
- // Realizes an AcceleratedWidget so that the returned AcceleratedWidget
- // can be used to to create a GLSurface. This method may only be called in
- // a process that has a valid GL context.
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) = 0;
-
- // Sets up GL bindings for the native surface. Takes two callback parameters
- // that allow Ozone to register the GL bindings.
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) = 0;
-
- // If possible attempts to resize the given AcceleratedWidget instance and if
- // a resize action was performed returns true, otherwise false (native
- // hardware may only support a single fixed size).
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) = 0;
-
- // Called after the appropriate GL swap buffers command. Used if extra work
- // is needed to perform the actual buffer swap.
- virtual bool SchedulePageFlip(gfx::AcceleratedWidget w);
-
- // Returns a SkCanvas for the backing buffers. Drawing to the canvas will draw
- // to the native surface. The canvas is intended for use when no EGL
- // acceleration is possible. Its implementation is optional when an EGL
- // backend is provided for rendering.
- virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w);
-
- // Returns a gfx::VsyncProvider for the provided AcceleratedWidget. Note
- // that this may be called after we have entered the sandbox so if there are
- // operations (e.g. opening a file descriptor providing vsync events) that
- // must be done outside of the sandbox, they must have been completed
- // in InitializeHardware. Returns NULL on error.
- virtual gfx::VSyncProvider* GetVSyncProvider(gfx::AcceleratedWidget w) = 0;
-
- // Returns an array of EGL properties, which can be used in any EGL function
- // used to select a display configuration. Note that all properties should be
- // immediately followed by the corresponding desired value and array should be
- // terminated with EGL_NONE. Ownership of the array is not transferred to
- // caller. desired_list contains list of desired EGL properties and values.
- virtual const int32* GetEGLSurfaceProperties(const int32* desired_list);
-
- // Create a default SufaceFactoryOzone implementation useful for tests.
- static SurfaceFactoryOzone* CreateTestHelper();
-
- private:
- static SurfaceFactoryOzone* impl_; // not owned
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
diff --git a/chromium/ui/gfx/pango_util.cc b/chromium/ui/gfx/pango_util.cc
index 1f8ac261b59..56503c6a01f 100644
--- a/chromium/ui/gfx/pango_util.cc
+++ b/chromium/ui/gfx/pango_util.cc
@@ -23,10 +23,6 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/text_utils.h"
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#endif
-
namespace gfx {
namespace {
@@ -116,12 +112,8 @@ float GetPixelsInPoint() {
} // namespace
PangoContext* GetPangoContext() {
-#if defined(TOOLKIT_GTK)
- return gdk_pango_context_get();
-#else
PangoFontMap* font_map = pango_cairo_font_map_get_default();
return pango_font_map_create_context(font_map);
-#endif
}
double GetPangoResolution() {
@@ -211,7 +203,7 @@ static void SetupPangoLayoutWithoutFont(
// Set text and accelerator character if needed.
if (flags & Canvas::SHOW_PREFIX) {
// Escape the text string to be used as markup.
- std::string utf8 = UTF16ToUTF8(text);
+ std::string utf8 = base::UTF16ToUTF8(text);
gchar* escaped_text = g_markup_escape_text(utf8.c_str(), utf8.size());
pango_layout_set_markup_with_accel(layout,
escaped_text,
@@ -229,9 +221,9 @@ static void SetupPangoLayoutWithoutFont(
RemoveAcceleratorChar(text,
static_cast<base::char16>(kAcceleratorChar),
NULL, NULL);
- utf8 = UTF16ToUTF8(accelerator_removed);
+ utf8 = base::UTF16ToUTF8(accelerator_removed);
} else {
- utf8 = UTF16ToUTF8(text);
+ utf8 = base::UTF16ToUTF8(text);
}
pango_layout_set_text(layout, utf8.data(), utf8.size());
diff --git a/chromium/ui/gfx/path.h b/chromium/ui/gfx/path.h
index 257a65c0102..b0f07279c7f 100644
--- a/chromium/ui/gfx/path.h
+++ b/chromium/ui/gfx/path.h
@@ -32,7 +32,7 @@ class GFX_EXPORT Path : public SkPath {
~Path();
-#if defined(USE_AURA) || defined(OS_WIN) || defined(USE_X11)
+#if defined(USE_AURA) || defined(USE_X11)
// Creates a NativeRegion from the path. The caller is responsible for freeing
// resources used by this region. This only supports polygon paths.
NativeRegion CreateNativeRegion() const;
diff --git a/chromium/ui/gfx/path_gtk.cc b/chromium/ui/gfx/path_gtk.cc
deleted file mode 100644
index 99dad2be43b..00000000000
--- a/chromium/ui/gfx/path_gtk.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/path.h"
-
-#include <gdk/gdk.h>
-
-#include "base/command_line.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace gfx {
-
-GdkRegion* Path::CreateNativeRegion() const {
- int point_count = getPoints(NULL, 0);
- if (point_count <= 1) {
- // NOTE: ideally this would return gdk_empty_region, but that returns a
- // region with nothing in it.
- return NULL;
- }
-
- scoped_ptr<SkPoint[]> points(new SkPoint[point_count]);
- getPoints(points.get(), point_count);
-
- scoped_ptr<GdkPoint[]> gdk_points(new GdkPoint[point_count]);
- for (int i = 0; i < point_count; ++i) {
- gdk_points[i].x = SkScalarRound(points[i].fX);
- gdk_points[i].y = SkScalarRound(points[i].fY);
- }
-
- return gdk_region_polygon(gdk_points.get(), point_count, GDK_EVEN_ODD_RULE);
-}
-
-// static
-NativeRegion Path::IntersectRegions(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_intersect(copy, r2);
- return copy;
-}
-
-// static
-NativeRegion Path::CombineRegions(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_union(copy, r2);
- return copy;
-}
-
-// static
-NativeRegion Path::SubtractRegion(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_subtract(copy, r2);
- return copy;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/path_win.cc b/chromium/ui/gfx/path_win.cc
index bce62ac849b..b28ea7a2c7b 100644
--- a/chromium/ui/gfx/path_win.cc
+++ b/chromium/ui/gfx/path_win.cc
@@ -30,8 +30,8 @@ HRGN CreateHRGNFromSkPath(const SkPath& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<POINT[]> windows_points(new POINT[point_count]);
for (int i = 0; i < point_count; ++i) {
- windows_points[i].x = SkScalarRound(points[i].fX);
- windows_points[i].y = SkScalarRound(points[i].fY);
+ windows_points[i].x = SkScalarRoundToInt(points[i].fX);
+ windows_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return ::CreatePolygonRgn(windows_points.get(), point_count, ALTERNATE);
diff --git a/chromium/ui/gfx/path_x11.cc b/chromium/ui/gfx/path_x11.cc
index 2fe764fbd4c..caea2ec12e6 100644
--- a/chromium/ui/gfx/path_x11.cc
+++ b/chromium/ui/gfx/path_x11.cc
@@ -4,6 +4,8 @@
#include "ui/gfx/path_x11.h"
+#include <X11/Xlib.h>
+#include <X11/Xregion.h>
#include <X11/Xutil.h>
#include "base/memory/scoped_ptr.h"
@@ -33,8 +35,8 @@ Region CreateRegionFromSkPath(const SkPath& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<XPoint[]> x11_points(new XPoint[point_count]);
for (int i = 0; i < point_count; ++i) {
- x11_points[i].x = SkScalarRound(points[i].fX);
- x11_points[i].y = SkScalarRound(points[i].fY);
+ x11_points[i].x = SkScalarRoundToInt(points[i].fX);
+ x11_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return XPolygonRegion(x11_points.get(), point_count, EvenOddRule);
diff --git a/chromium/ui/gfx/path_x11.h b/chromium/ui/gfx/path_x11.h
index c6e750742ec..6e3a1568293 100644
--- a/chromium/ui/gfx/path_x11.h
+++ b/chromium/ui/gfx/path_x11.h
@@ -5,14 +5,13 @@
#ifndef UI_GFX_PATH_X11_H_
#define UI_GFX_PATH_X11_H_
-#include <X11/Xlib.h>
-#include <X11/Xregion.h>
-
#include "ui/gfx/gfx_export.h"
class SkPath;
class SkRegion;
+typedef struct _XRegion REGION;
+
namespace gfx {
// Creates a new REGION given |region|. The caller is responsible for destroying
diff --git a/chromium/ui/gfx/platform_font.h b/chromium/ui/gfx/platform_font.h
index bf470983e12..27f39b751a9 100644
--- a/chromium/ui/gfx/platform_font.h
+++ b/chromium/ui/gfx/platform_font.h
@@ -45,13 +45,6 @@ class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> {
// Returns the cap height of the font.
virtual int GetCapHeight() const = 0;
- // Returns the average character width for the font.
- virtual int GetAverageCharacterWidth() const = 0;
-
- // Returns the number of horizontal pixels needed to display the specified
- // string.
- virtual int GetStringWidth(const base::string16& text) const = 0;
-
// Returns the expected number of horizontal pixels needed to display the
// specified length of characters. Call GetStringWidth() to retrieve the
// actual number.
diff --git a/chromium/ui/gfx/platform_font_ios.h b/chromium/ui/gfx/platform_font_ios.h
index ed93a6b6e66..3323f820c45 100644
--- a/chromium/ui/gfx/platform_font_ios.h
+++ b/chromium/ui/gfx/platform_font_ios.h
@@ -21,8 +21,6 @@ class PlatformFontIOS : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_ios.mm b/chromium/ui/gfx/platform_font_ios.mm
index 32dcca4e395..aba239b732d 100644
--- a/chromium/ui/gfx/platform_font_ios.mm
+++ b/chromium/ui/gfx/platform_font_ios.mm
@@ -55,15 +55,6 @@ int PlatformFontIOS::GetCapHeight() const {
return cap_height_;
}
-int PlatformFontIOS::GetAverageCharacterWidth() const {
- return average_width_;
-}
-
-int PlatformFontIOS::GetStringWidth(const base::string16& text) const {
- NSString* ns_text = base::SysUTF16ToNSString(text);
- return [ns_text sizeWithFont:GetNativeFont()].width;
-}
-
int PlatformFontIOS::GetExpectedTextWidth(int length) const {
return length * average_width_;
}
diff --git a/chromium/ui/gfx/platform_font_mac.h b/chromium/ui/gfx/platform_font_mac.h
index 2f5f8deb3fe..8c469882ff1 100644
--- a/chromium/ui/gfx/platform_font_mac.h
+++ b/chromium/ui/gfx/platform_font_mac.h
@@ -23,8 +23,6 @@ class PlatformFontMac : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_mac.mm b/chromium/ui/gfx/platform_font_mac.mm
index 877507eb47b..53e3013170c 100644
--- a/chromium/ui/gfx/platform_font_mac.mm
+++ b/chromium/ui/gfx/platform_font_mac.mm
@@ -105,15 +105,6 @@ int PlatformFontMac::GetCapHeight() const {
return cap_height_;
}
-int PlatformFontMac::GetAverageCharacterWidth() const {
- return average_width_;
-}
-
-int PlatformFontMac::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontMac*>(this)));
-}
-
int PlatformFontMac::GetExpectedTextWidth(int length) const {
return length * average_width_;
}
diff --git a/chromium/ui/gfx/platform_font_mac_unittest.mm b/chromium/ui/gfx/platform_font_mac_unittest.mm
index 088d4a9bd2d..2584cb50d31 100644
--- a/chromium/ui/gfx/platform_font_mac_unittest.mm
+++ b/chromium/ui/gfx/platform_font_mac_unittest.mm
@@ -12,20 +12,20 @@ TEST(PlatformFontMacTest, DeriveFont) {
gfx::Font base_font("Helvetica", 13);
// Bold
- gfx::Font bold_font(base_font.DeriveFont(0, gfx::Font::BOLD));
+ gfx::Font bold_font(base_font.Derive(0, gfx::Font::BOLD));
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_font.GetNativeFont()];
EXPECT_EQ(NSBoldFontMask, traits);
// Italic
- gfx::Font italic_font(base_font.DeriveFont(0, gfx::Font::ITALIC));
+ gfx::Font italic_font(base_font.Derive(0, gfx::Font::ITALIC));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:italic_font.GetNativeFont()];
EXPECT_EQ(NSItalicFontMask, traits);
// Bold italic
- gfx::Font bold_italic_font(base_font.DeriveFont(0, gfx::Font::BOLD |
- gfx::Font::ITALIC));
+ gfx::Font bold_italic_font(base_font.Derive(
+ 0, gfx::Font::BOLD | gfx::Font::ITALIC));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_italic_font.GetNativeFont()];
EXPECT_EQ(static_cast<NSFontTraitMask>(NSBoldFontMask | NSItalicFontMask),
diff --git a/chromium/ui/gfx/platform_font_pango.cc b/chromium/ui/gfx/platform_font_pango.cc
index db1d7dce351..efc940bd186 100644
--- a/chromium/ui/gfx/platform_font_pango.cc
+++ b/chromium/ui/gfx/platform_font_pango.cc
@@ -19,12 +19,10 @@
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/linux_font_delegate.h"
#include "ui/gfx/pango_util.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#endif
+#include "ui/gfx/text_utils.h"
namespace {
@@ -184,23 +182,7 @@ int PlatformFontPango::GetBaseline() const {
}
int PlatformFontPango::GetCapHeight() const {
- // Return the ascent as an approximation because Pango doesn't support cap
- // height.
- // TODO(yukishiino): Come up with a better approximation of cap height, or
- // support cap height metrics. Another option is to have a hard-coded table
- // of cap height for major fonts used in Chromium/Chrome.
- // See http://crbug.com/249507
- return ascent_pixels_;
-}
-
-int PlatformFontPango::GetAverageCharacterWidth() const {
- const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
- return SkScalarRound(average_width_pixels_);
-}
-
-int PlatformFontPango::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontPango*>(this)));
+ return cap_height_pixels_;
}
int PlatformFontPango::GetExpectedTextWidth(int length) const {
@@ -269,31 +251,19 @@ PlatformFontPango::~PlatformFontPango() {}
// static
std::string PlatformFontPango::GetDefaultFont() {
-#if !defined(TOOLKIT_GTK)
#if defined(OS_CHROMEOS)
// Font name must have been provided by way of SetDefaultFontDescription().
CHECK(default_font_description_);
return *default_font_description_;
#else
+ const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance();
+ if (delegate)
+ return delegate->GetDefaultFontName();
+
return "sans 10";
#endif // defined(OS_CHROMEOS)
-#else
- GtkSettings* settings = gtk_settings_get_default();
-
- gchar* font_name = NULL;
- g_object_get(settings, "gtk-font-name", &font_name, NULL);
-
- // Temporary CHECK for helping track down
- // http://code.google.com/p/chromium/issues/detail?id=12530
- CHECK(font_name) << " Unable to get gtk-font-name for default font.";
-
- std::string default_font = std::string(font_name);
- g_free(font_name);
- return default_font;
-#endif // !defined(TOOLKIT_GTK)
}
-
void PlatformFontPango::InitWithNameAndSize(const std::string& font_name,
int font_size) {
DCHECK_GT(font_size, 0);
@@ -338,8 +308,9 @@ void PlatformFontPango::InitWithTypefaceNameSizeAndStyle(
PaintSetup(&paint);
paint.getFontMetrics(&metrics);
- ascent_pixels_ = SkScalarCeil(-metrics.fAscent);
- height_pixels_ = ascent_pixels_ + SkScalarCeil(metrics.fDescent);
+ ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
+ height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
+ cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
}
void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
@@ -349,6 +320,7 @@ void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
style_ = other->style_;
height_pixels_ = other->height_pixels_;
ascent_pixels_ = other->ascent_pixels_;
+ cap_height_pixels_ = other->cap_height_pixels_;
pango_metrics_inited_ = other->pango_metrics_inited_;
average_width_pixels_ = other->average_width_pixels_;
underline_position_pixels_ = other->underline_position_pixels_;
@@ -392,7 +364,9 @@ void PlatformFontPango::InitPangoMetrics() {
// Yes, this is how Microsoft recommends calculating the dialog unit
// conversions.
const int text_width_pixels = GetStringWidth(
- ASCIIToUTF16("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+ base::ASCIIToUTF16(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
+ FontList(Font(this)));
const double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
}
diff --git a/chromium/ui/gfx/platform_font_pango.h b/chromium/ui/gfx/platform_font_pango.h
index 739a633aa47..548b3ac56e7 100644
--- a/chromium/ui/gfx/platform_font_pango.h
+++ b/chromium/ui/gfx/platform_font_pango.h
@@ -50,8 +50,6 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
@@ -104,6 +102,7 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
// Cached metrics, generated at construction.
int height_pixels_;
int ascent_pixels_;
+ int cap_height_pixels_;
// The pango metrics are much more expensive so we wait until we need them
// to compute them.
diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc
index 0209be6673e..4acaf64b34a 100644
--- a/chromium/ui/gfx/platform_font_win.cc
+++ b/chromium/ui/gfx/platform_font_win.cc
@@ -101,7 +101,7 @@ Font PlatformFontWin::DeriveFontWithHeight(int height, int style) {
int font_height = font.GetHeight();
int font_size = font.GetFontSize();
while (font_height > height && font_size != min_font_size) {
- font = font.DeriveFont(-1, style);
+ font = font.Derive(-1, style);
if (font_height == font.GetHeight() && font_size == font.GetFontSize())
break;
font_height = font.GetHeight();
@@ -145,18 +145,9 @@ int PlatformFontWin::GetCapHeight() const {
return font_ref_->cap_height();
}
-int PlatformFontWin::GetAverageCharacterWidth() const {
- return font_ref_->ave_char_width();
-}
-
-int PlatformFontWin::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontWin*>(this)));
-}
-
int PlatformFontWin::GetExpectedTextWidth(int length) const {
return length * std::min(font_ref_->GetDluBaseX(),
- GetAverageCharacterWidth());
+ font_ref_->ave_char_width());
}
int PlatformFontWin::GetStyle() const {
@@ -211,7 +202,7 @@ void PlatformFontWin::InitWithCopyOfHFONT(HFONT hfont) {
void PlatformFontWin::InitWithFontNameAndSize(const std::string& font_name,
int font_size) {
HFONT hf = ::CreateFont(-font_size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- UTF8ToUTF16(font_name).c_str());
+ base::UTF8ToUTF16(font_name).c_str());
font_ref_ = CreateHFontRef(hf);
}
@@ -289,7 +280,7 @@ PlatformFontWin::HFontRef::HFontRef(HFONT hfont,
LOGFONT font_info;
GetObject(hfont_, sizeof(LOGFONT), &font_info);
- font_name_ = UTF16ToUTF8(base::string16(font_info.lfFaceName));
+ font_name_ = base::UTF16ToUTF8(base::string16(font_info.lfFaceName));
if (font_info.lfHeight < 0)
requested_font_size_ = -font_info.lfHeight;
}
diff --git a/chromium/ui/gfx/platform_font_win.h b/chromium/ui/gfx/platform_font_win.h
index 4826f777ffc..2c6f51e0508 100644
--- a/chromium/ui/gfx/platform_font_win.h
+++ b/chromium/ui/gfx/platform_font_win.h
@@ -58,8 +58,6 @@ class GFX_EXPORT PlatformFontWin : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_win_unittest.cc b/chromium/ui/gfx/platform_font_win_unittest.cc
index bfbe92203d1..1ecdde1d352 100644
--- a/chromium/ui/gfx/platform_font_win_unittest.cc
+++ b/chromium/ui/gfx/platform_font_win_unittest.cc
@@ -20,15 +20,15 @@ gfx::Font AdjustFontSizeForHeight(const gfx::Font& base_font,
Font expected_font = base_font;
if (base_font.GetHeight() < target_height) {
// Increase size while height is <= |target_height|.
- Font larger_font = base_font.DeriveFont(1, 0);
+ Font larger_font = base_font.Derive(1, 0);
while (larger_font.GetHeight() <= target_height) {
expected_font = larger_font;
- larger_font = larger_font.DeriveFont(1, 0);
+ larger_font = larger_font.Derive(1, 0);
}
} else if (expected_font.GetHeight() > target_height) {
// Decrease size until height is <= |target_height|.
do {
- expected_font = expected_font.DeriveFont(-1, 0);
+ expected_font = expected_font.Derive(-1, 0);
} while (expected_font.GetHeight() > target_height);
}
return expected_font;
@@ -60,7 +60,7 @@ TEST(PlatformFontWinTest, DeriveFontWithHeight) {
EXPECT_EQ(Font::BOLD, derived_font.GetStyle());
// Test that deriving from the new font has the expected result.
- Font rederived_font = derived_font.DeriveFont(1, 0);
+ Font rederived_font = derived_font.Derive(1, 0);
expected_font = Font(derived_font.GetFontName(),
derived_font.GetFontSize() + 1);
EXPECT_EQ(expected_font.GetFontName(), rederived_font.GetFontName());
diff --git a/chromium/ui/gfx/point.cc b/chromium/ui/gfx/point.cc
deleted file mode 100644
index 7fdf3560fe3..00000000000
--- a/chromium/ui/gfx/point.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/point.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class PointBase<Point, int, Vector2d>;
-
-#if defined(OS_WIN)
-Point::Point(DWORD point) : PointBase<Point, int, Vector2d>(0, 0){
- POINTS points = MAKEPOINTS(point);
- set_x(points.x);
- set_y(points.y);
-}
-
-Point::Point(const POINT& point)
- : PointBase<Point, int, Vector2d>(point.x, point.y) {
-}
-
-Point& Point::operator=(const POINT& point) {
- set_x(point.x);
- set_y(point.y);
- return *this;
-}
-
-POINT Point::ToPOINT() const {
- POINT p;
- p.x = x();
- p.y = y();
- return p;
-}
-#elif defined(OS_MACOSX)
-Point::Point(const CGPoint& point)
- : PointBase<Point, int, Vector2d>(point.x, point.y) {
-}
-
-CGPoint Point::ToCGPoint() const {
- return CGPointMake(x(), y());
-}
-#endif
-
-std::string Point::ToString() const {
- return base::StringPrintf("%d,%d", x(), y());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/point.h b/chromium/ui/gfx/point.h
index 020c4e1251a..bbca081095d 100644
--- a/chromium/ui/gfx/point.h
+++ b/chromium/ui/gfx/point.h
@@ -1,90 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_POINT_H_
-#define UI_GFX_POINT_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_base.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/vector2d.h"
-
-#if defined(OS_WIN)
-typedef unsigned long DWORD;
-typedef struct tagPOINT POINT;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-// A point has an x and y coordinate.
-class GFX_EXPORT Point : public PointBase<Point, int, Vector2d> {
- public:
- Point() : PointBase<Point, int, Vector2d>(0, 0) {}
- Point(int x, int y) : PointBase<Point, int, Vector2d>(x, y) {}
-#if defined(OS_WIN)
- // |point| is a DWORD value that contains a coordinate. The x-coordinate is
- // the low-order short and the y-coordinate is the high-order short. This
- // value is commonly acquired from GetMessagePos/GetCursorPos.
- explicit Point(DWORD point);
- explicit Point(const POINT& point);
- Point& operator=(const POINT& point);
-#elif defined(OS_MACOSX)
- explicit Point(const CGPoint& point);
-#endif
-
- ~Point() {}
-
-#if defined(OS_WIN)
- POINT ToPOINT() const;
-#elif defined(OS_MACOSX)
- CGPoint ToCGPoint() const;
-#endif
-
- operator PointF() const {
- return PointF(x(), y());
- }
-
- // Returns a string representation of point.
- std::string ToString() const;
-};
-
-inline bool operator==(const Point& lhs, const Point& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline bool operator!=(const Point& lhs, const Point& rhs) {
- return !(lhs == rhs);
-}
-
-inline Point operator+(const Point& lhs, const Vector2d& rhs) {
- Point result(lhs);
- result += rhs;
- return result;
-}
-
-inline Point operator-(const Point& lhs, const Vector2d& rhs) {
- Point result(lhs);
- result -= rhs;
- return result;
-}
-
-inline Vector2d operator-(const Point& lhs, const Point& rhs) {
- return Vector2d(lhs.x() - rhs.x(), lhs.y() - rhs.y());
-}
-
-inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
- return Point(offset_from_origin.x(), offset_from_origin.y());
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class PointBase<Point, int, Vector2d>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_H_
diff --git a/chromium/ui/gfx/point3_f.cc b/chromium/ui/gfx/point3_f.cc
deleted file mode 100644
index 70089a46c21..00000000000
--- a/chromium/ui/gfx/point3_f.cc
+++ /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.
-
-#include "ui/gfx/point3_f.h"
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-std::string Point3F::ToString() const {
- return base::StringPrintf("%f,%f,%f", x_, y_, z_);
-}
-
-Point3F operator+(const Point3F& lhs, const Vector3dF& rhs) {
- float x = lhs.x() + rhs.x();
- float y = lhs.y() + rhs.y();
- float z = lhs.z() + rhs.z();
- return Point3F(x, y, z);
-}
-
-// Subtract a vector from a point, producing a new point offset by the vector's
-// inverse.
-Point3F operator-(const Point3F& lhs, const Vector3dF& rhs) {
- float x = lhs.x() - rhs.x();
- float y = lhs.y() - rhs.y();
- float z = lhs.z() - rhs.z();
- return Point3F(x, y, z);
-}
-
-// Subtract one point from another, producing a vector that represents the
-// distances between the two points along each axis.
-Vector3dF operator-(const Point3F& lhs, const Point3F& rhs) {
- float x = lhs.x() - rhs.x();
- float y = lhs.y() - rhs.y();
- float z = lhs.z() - rhs.z();
- return Vector3dF(x, y, z);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/point3_f.h b/chromium/ui/gfx/point3_f.h
index 485f6558136..8c57c578f48 100644
--- a/chromium/ui/gfx/point3_f.h
+++ b/chromium/ui/gfx/point3_f.h
@@ -1,120 +1,7 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_POINT3_F_H_
-#define UI_GFX_POINT3_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point3_f.h"
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-// A point has an x, y and z coordinate.
-class GFX_EXPORT Point3F {
- public:
- Point3F() : x_(0), y_(0), z_(0) {}
-
- Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
-
- explicit Point3F(const PointF& point) : x_(point.x()), y_(point.y()), z_(0) {}
-
- ~Point3F() {}
-
- void Scale(float scale) {
- Scale(scale, scale, scale);
- }
-
- void Scale(float x_scale, float y_scale, float z_scale) {
- SetPoint(x() * x_scale, y() * y_scale, z() * z_scale);
- }
-
- float x() const { return x_; }
- float y() const { return y_; }
- float z() const { return z_; }
-
- void set_x(float x) { x_ = x; }
- void set_y(float y) { y_ = y; }
- void set_z(float z) { z_ = z; }
-
- void SetPoint(float x, float y, float z) {
- x_ = x;
- y_ = y;
- z_ = z;
- }
-
- // Offset the point by the given vector.
- void operator+=(const Vector3dF& v) {
- x_ += v.x();
- y_ += v.y();
- z_ += v.z();
- }
-
- // Offset the point by the given vector's inverse.
- void operator-=(const Vector3dF& v) {
- x_ -= v.x();
- y_ -= v.y();
- z_ -= v.z();
- }
-
- // Returns the squared euclidean distance between two points.
- float SquaredDistanceTo(const Point3F& other) const {
- float dx = x_ - other.x_;
- float dy = y_ - other.y_;
- float dz = z_ - other.z_;
- return dx * dx + dy * dy + dz * dz;
- }
-
- PointF AsPointF() const { return PointF(x_, y_); }
-
- // Returns a string representation of 3d point.
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
- float z_;
-
- // copy/assign are allowed.
-};
-
-inline bool operator==(const Point3F& lhs, const Point3F& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
-}
-
-inline bool operator!=(const Point3F& lhs, const Point3F& rhs) {
- return !(lhs == rhs);
-}
-
-// Add a vector to a point, producing a new point offset by the vector.
-GFX_EXPORT Point3F operator+(const Point3F& lhs, const Vector3dF& rhs);
-
-// Subtract a vector from a point, producing a new point offset by the vector's
-// inverse.
-GFX_EXPORT Point3F operator-(const Point3F& lhs, const Vector3dF& rhs);
-
-// Subtract one point from another, producing a vector that represents the
-// distances between the two points along each axis.
-GFX_EXPORT Vector3dF operator-(const Point3F& lhs, const Point3F& rhs);
-
-inline Point3F PointAtOffsetFromOrigin(const Vector3dF& offset) {
- return Point3F(offset.x(), offset.y(), offset.z());
-}
-
-inline Point3F ScalePoint(const Point3F& p,
- float x_scale,
- float y_scale,
- float z_scale) {
- return Point3F(p.x() * x_scale, p.y() * y_scale, p.z() * z_scale);
-}
-
-inline Point3F ScalePoint(const Point3F& p, float scale) {
- return ScalePoint(p, scale, scale, scale);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT3_F_H_
diff --git a/chromium/ui/gfx/point3_unittest.cc b/chromium/ui/gfx/point3_unittest.cc
deleted file mode 100644
index 735ffd55425..00000000000
--- a/chromium/ui/gfx/point3_unittest.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/point3_f.h"
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace gfx {
-
-TEST(Point3Test, VectorArithmetic) {
- gfx::Point3F a(1.6f, 5.1f, 3.2f);
- gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
- gfx::Vector3dF v2(-8.1f, 1.2f, 3.3f);
-
- static const struct {
- gfx::Point3F expected;
- gfx::Point3F actual;
- } tests[] = {
- { gfx::Point3F(4.7f, 1.9f, 12.5f), a + v1 },
- { gfx::Point3F(-1.5f, 8.3f, -6.1f), a - v1 },
- { a, a - v1 + v1 },
- { a, a + v1 - v1 },
- { a, a + gfx::Vector3dF() },
- { gfx::Point3F(12.8f, 0.7f, 9.2f), a + v1 - v2 },
- { gfx::Point3F(-9.6f, 9.5f, -2.8f), a - v1 + v2 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i)
- EXPECT_EQ(tests[i].expected.ToString(),
- tests[i].actual.ToString());
-
- a += v1;
- EXPECT_EQ(Point3F(4.7f, 1.9f, 12.5f).ToString(), a.ToString());
-
- a -= v2;
- EXPECT_EQ(Point3F(12.8f, 0.7f, 9.2f).ToString(), a.ToString());
-}
-
-TEST(Point3Test, VectorFromPoints) {
- gfx::Point3F a(1.6f, 5.2f, 3.2f);
- gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
-
- gfx::Point3F b(a + v1);
- EXPECT_EQ((b - a).ToString(), v1.ToString());
-}
-
-TEST(Point3Test, Scale) {
- EXPECT_EQ(Point3F().ToString(), ScalePoint(Point3F(), 2.f).ToString());
- EXPECT_EQ(Point3F().ToString(),
- ScalePoint(Point3F(), 2.f, 2.f, 2.f).ToString());
-
- EXPECT_EQ(Point3F(2.f, -2.f, 4.f).ToString(),
- ScalePoint(Point3F(1.f, -1.f, 2.f), 2.f).ToString());
- EXPECT_EQ(Point3F(2.f, -3.f, 8.f).ToString(),
- ScalePoint(Point3F(1.f, -1.f, 2.f), 2.f, 3.f, 4.f).ToString());
-
- Point3F zero;
- zero.Scale(2.f);
- zero.Scale(6.f, 3.f, 1.5f);
- EXPECT_EQ(Point3F().ToString(), zero.ToString());
-
- Point3F point(1.f, -1.f, 2.f);
- point.Scale(2.f);
- point.Scale(6.f, 3.f, 1.5f);
- EXPECT_EQ(Point3F(12.f, -6.f, 6.f).ToString(), point.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/point_base.h b/chromium/ui/gfx/point_base.h
deleted file mode 100644
index d7a3951913e..00000000000
--- a/chromium/ui/gfx/point_base.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_POINT_BASE_H_
-#define UI_GFX_POINT_BASE_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// A point has an x and y coordinate.
-template<typename Class, typename Type, typename VectorClass>
-class GFX_EXPORT PointBase {
- public:
- Type x() const { return x_; }
- Type y() const { return y_; }
-
- void SetPoint(Type x, Type y) {
- x_ = x;
- y_ = y;
- }
-
- void set_x(Type x) { x_ = x; }
- void set_y(Type y) { y_ = y; }
-
- void Offset(Type delta_x, Type delta_y) {
- x_ += delta_x;
- y_ += delta_y;
- }
-
- void operator+=(const VectorClass& vector) {
- x_ += vector.x();
- y_ += vector.y();
- }
-
- void operator-=(const VectorClass& vector) {
- x_ -= vector.x();
- y_ -= vector.y();
- }
-
- void SetToMin(const Class& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- }
-
- void SetToMax(const Class& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- }
-
- bool IsOrigin() const {
- return x_ == 0 && y_ == 0;
- }
-
- VectorClass OffsetFromOrigin() const {
- return VectorClass(x_, y_);
- }
-
- // A point is less than another point if its y-value is closer
- // to the origin. If the y-values are the same, then point with
- // the x-value closer to the origin is considered less than the
- // other.
- // This comparison is required to use Point in sets, or sorted
- // vectors.
- bool operator<(const Class& rhs) const {
- return (y_ == rhs.y_) ? (x_ < rhs.x_) : (y_ < rhs.y_);
- }
-
- protected:
- PointBase(Type x, Type y) : x_(x), y_(y) {}
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~PointBase() {}
-
- private:
- Type x_;
- Type y_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_BASE_H_
diff --git a/chromium/ui/gfx/point_conversions.cc b/chromium/ui/gfx/point_conversions.cc
deleted file mode 100644
index f7845a03f41..00000000000
--- a/chromium/ui/gfx/point_conversions.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/point_conversions.h"
-
-#include "ui/gfx/safe_integer_conversions.h"
-
-namespace gfx {
-
-Point ToFlooredPoint(const PointF& point) {
- int x = ToFlooredInt(point.x());
- int y = ToFlooredInt(point.y());
- return Point(x, y);
-}
-
-Point ToCeiledPoint(const PointF& point) {
- int x = ToCeiledInt(point.x());
- int y = ToCeiledInt(point.y());
- return Point(x, y);
-}
-
-Point ToRoundedPoint(const PointF& point) {
- int x = ToRoundedInt(point.x());
- int y = ToRoundedInt(point.y());
- return Point(x, y);
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/point_conversions.h b/chromium/ui/gfx/point_conversions.h
index 942edd711cc..b7c961fe923 100644
--- a/chromium/ui/gfx/point_conversions.h
+++ b/chromium/ui/gfx/point_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_POINT_CONVERSIONS_H_
-#define UI_GFX_POINT_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_f.h"
-
-namespace gfx {
-
-// Returns a Point with each component from the input PointF floored.
-GFX_EXPORT Point ToFlooredPoint(const PointF& point);
-
-// Returns a Point with each component from the input PointF ceiled.
-GFX_EXPORT Point ToCeiledPoint(const PointF& point);
-
-// Returns a Point with each component from the input PointF rounded.
-GFX_EXPORT Point ToRoundedPoint(const PointF& point);
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/point_f.cc b/chromium/ui/gfx/point_f.cc
deleted file mode 100644
index 21028565d99..00000000000
--- a/chromium/ui/gfx/point_f.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/point_f.h"
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class PointBase<PointF, float, Vector2dF>;
-
-std::string PointF::ToString() const {
- return base::StringPrintf("%f,%f", x(), y());
-}
-
-PointF ScalePoint(const PointF& p, float x_scale, float y_scale) {
- PointF scaled_p(p);
- scaled_p.Scale(x_scale, y_scale);
- return scaled_p;
-}
-
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/point_f.h b/chromium/ui/gfx/point_f.h
index 664c18d8aa0..f4be8ff0578 100644
--- a/chromium/ui/gfx/point_f.h
+++ b/chromium/ui/gfx/point_f.h
@@ -1,75 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_POINT_F_H_
-#define UI_GFX_POINT_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point_f.h"
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_base.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-// A floating version of gfx::Point.
-class GFX_EXPORT PointF : public PointBase<PointF, float, Vector2dF> {
- public:
- PointF() : PointBase<PointF, float, Vector2dF>(0, 0) {}
- PointF(float x, float y) : PointBase<PointF, float, Vector2dF>(x, y) {}
- ~PointF() {}
-
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- SetPoint(x() * x_scale, y() * y_scale);
- }
-
- // Returns a string representation of point.
- std::string ToString() const;
-};
-
-inline bool operator==(const PointF& lhs, const PointF& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline bool operator!=(const PointF& lhs, const PointF& rhs) {
- return !(lhs == rhs);
-}
-
-inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
- PointF result(lhs);
- result += rhs;
- return result;
-}
-
-inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
- PointF result(lhs);
- result -= rhs;
- return result;
-}
-
-inline Vector2dF operator-(const PointF& lhs, const PointF& rhs) {
- return Vector2dF(lhs.x() - rhs.x(), lhs.y() - rhs.y());
-}
-
-inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) {
- return PointF(offset_from_origin.x(), offset_from_origin.y());
-}
-
-GFX_EXPORT PointF ScalePoint(const PointF& p, float x_scale, float y_scale);
-
-inline PointF ScalePoint(const PointF& p, float scale) {
- return ScalePoint(p, scale, scale);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class PointBase<PointF, float, Vector2dF>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_F_H_
diff --git a/chromium/ui/gfx/point_unittest.cc b/chromium/ui/gfx/point_unittest.cc
deleted file mode 100644
index 6cf73dd2adb..00000000000
--- a/chromium/ui/gfx/point_unittest.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/point_base.h"
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/point_f.h"
-
-namespace gfx {
-
-namespace {
-
-int TestPointF(const PointF& p) {
- return p.x();
-}
-
-} // namespace
-
-TEST(PointTest, ToPointF) {
- // Check that implicit conversion from integer to float compiles.
- Point a(10, 20);
- float x = TestPointF(a);
- EXPECT_EQ(x, a.x());
-
- PointF b(10, 20);
- EXPECT_EQ(a, b);
- EXPECT_EQ(b, a);
-}
-
-TEST(PointTest, IsOrigin) {
- EXPECT_FALSE(Point(1, 0).IsOrigin());
- EXPECT_FALSE(Point(0, 1).IsOrigin());
- EXPECT_FALSE(Point(1, 2).IsOrigin());
- EXPECT_FALSE(Point(-1, 0).IsOrigin());
- EXPECT_FALSE(Point(0, -1).IsOrigin());
- EXPECT_FALSE(Point(-1, -2).IsOrigin());
- EXPECT_TRUE(Point(0, 0).IsOrigin());
-
- EXPECT_FALSE(PointF(0.1f, 0).IsOrigin());
- EXPECT_FALSE(PointF(0, 0.1f).IsOrigin());
- EXPECT_FALSE(PointF(0.1f, 2).IsOrigin());
- EXPECT_FALSE(PointF(-0.1f, 0).IsOrigin());
- EXPECT_FALSE(PointF(0, -0.1f).IsOrigin());
- EXPECT_FALSE(PointF(-0.1f, -2).IsOrigin());
- EXPECT_TRUE(PointF(0, 0).IsOrigin());
-}
-
-TEST(PointTest, VectorArithmetic) {
- Point a(1, 5);
- Vector2d v1(3, -3);
- Vector2d v2(-8, 1);
-
- static const struct {
- Point expected;
- Point actual;
- } tests[] = {
- { Point(4, 2), a + v1 },
- { Point(-2, 8), a - v1 },
- { a, a - v1 + v1 },
- { a, a + v1 - v1 },
- { a, a + Vector2d() },
- { Point(12, 1), a + v1 - v2 },
- { Point(-10, 9), a - v1 + v2 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i)
- EXPECT_EQ(tests[i].expected.ToString(), tests[i].actual.ToString());
-}
-
-TEST(PointTest, OffsetFromPoint) {
- Point a(1, 5);
- Point b(-20, 8);
- EXPECT_EQ(Vector2d(-20 - 1, 8 - 5).ToString(), (b - a).ToString());
-}
-
-TEST(PointTest, ToRoundedPoint) {
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0, 0)));
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.0001f, 0.0001f)));
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.4999f, 0.4999f)));
- EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.5f, 0.5f)));
- EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10, 10)));
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.0001f, 10.0001f)));
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.4999f, 10.4999f)));
- EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.5f, 10.5f)));
- EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.9999f, 10.9999f)));
-
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10, -10)));
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.0001f, -10.0001f)));
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.4999f, -10.4999f)));
- EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.5f, -10.5f)));
- EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.9999f, -10.9999f)));
-}
-
-TEST(PointTest, Scale) {
- EXPECT_EQ(PointF().ToString(), ScalePoint(Point(), 2).ToString());
- EXPECT_EQ(PointF().ToString(), ScalePoint(Point(), 2, 2).ToString());
-
- EXPECT_EQ(PointF(2, -2).ToString(),
- ScalePoint(Point(1, -1), 2).ToString());
- EXPECT_EQ(PointF(2, -2).ToString(),
- ScalePoint(Point(1, -1), 2, 2).ToString());
-
- PointF zero;
- PointF one(1, -1);
-
- zero.Scale(2);
- zero.Scale(3, 1.5);
-
- one.Scale(2);
- one.Scale(3, 1.5);
-
- EXPECT_EQ(PointF().ToString(), zero.ToString());
- EXPECT_EQ(PointF(6, -3).ToString(), one.ToString());
-}
-
-TEST(PointTest, ClampPoint) {
- Point a;
-
- a = Point(3, 5);
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
- a.SetToMax(Point(2, 4));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
- a.SetToMax(Point(3, 5));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
- a.SetToMax(Point(4, 2));
- EXPECT_EQ(Point(4, 5).ToString(), a.ToString());
- a.SetToMax(Point(8, 10));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
-
- a.SetToMin(Point(9, 11));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
- a.SetToMin(Point(8, 10));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
- a.SetToMin(Point(11, 9));
- EXPECT_EQ(Point(8, 9).ToString(), a.ToString());
- a.SetToMin(Point(7, 11));
- EXPECT_EQ(Point(7, 9).ToString(), a.ToString());
- a.SetToMin(Point(3, 5));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
-}
-
-TEST(PointTest, ClampPointF) {
- PointF a;
-
- a = PointF(3.5f, 5.5f);
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(2.5f, 4.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(3.5f, 5.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(4.5f, 2.5f));
- EXPECT_EQ(PointF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(8.5f, 10.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(PointF(9.5f, 11.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(PointF(8.5f, 10.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(PointF(11.5f, 9.5f));
- EXPECT_EQ(PointF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(PointF(7.5f, 11.5f));
- EXPECT_EQ(PointF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(PointF(3.5f, 5.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/quad_f.cc b/chromium/ui/gfx/quad_f.cc
deleted file mode 100644
index 2796bf192b2..00000000000
--- a/chromium/ui/gfx/quad_f.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/quad_f.h"
-
-#include <limits>
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-void QuadF::operator=(const RectF& rect) {
- p1_ = PointF(rect.x(), rect.y());
- p2_ = PointF(rect.right(), rect.y());
- p3_ = PointF(rect.right(), rect.bottom());
- p4_ = PointF(rect.x(), rect.bottom());
-}
-
-std::string QuadF::ToString() const {
- return base::StringPrintf("%s;%s;%s;%s",
- p1_.ToString().c_str(),
- p2_.ToString().c_str(),
- p3_.ToString().c_str(),
- p4_.ToString().c_str());
-}
-
-static inline bool WithinEpsilon(float a, float b) {
- return std::abs(a - b) < std::numeric_limits<float>::epsilon();
-}
-
-bool QuadF::IsRectilinear() const {
- return
- (WithinEpsilon(p1_.x(), p2_.x()) && WithinEpsilon(p2_.y(), p3_.y()) &&
- WithinEpsilon(p3_.x(), p4_.x()) && WithinEpsilon(p4_.y(), p1_.y())) ||
- (WithinEpsilon(p1_.y(), p2_.y()) && WithinEpsilon(p2_.x(), p3_.x()) &&
- WithinEpsilon(p3_.y(), p4_.y()) && WithinEpsilon(p4_.x(), p1_.x()));
-}
-
-bool QuadF::IsCounterClockwise() const {
- // This math computes the signed area of the quad. Positive area
- // indicates the quad is clockwise; negative area indicates the quad is
- // counter-clockwise. Note carefully: this is backwards from conventional
- // math because our geometric space uses screen coordiantes with y-axis
- // pointing downards.
- // Reference: http://mathworld.wolfram.com/PolygonArea.html
-
- // Up-cast to double so this cannot overflow.
- double determinant1 = static_cast<double>(p1_.x()) * p2_.y()
- - static_cast<double>(p2_.x()) * p1_.y();
- double determinant2 = static_cast<double>(p2_.x()) * p3_.y()
- - static_cast<double>(p3_.x()) * p2_.y();
- double determinant3 = static_cast<double>(p3_.x()) * p4_.y()
- - static_cast<double>(p4_.x()) * p3_.y();
- double determinant4 = static_cast<double>(p4_.x()) * p1_.y()
- - static_cast<double>(p1_.x()) * p4_.y();
-
- return determinant1 + determinant2 + determinant3 + determinant4 < 0;
-}
-
-static inline bool PointIsInTriangle(const PointF& point,
- const PointF& r1,
- const PointF& r2,
- const PointF& r3) {
- // Compute the barycentric coordinates of |point| relative to the triangle
- // (r1, r2, r3). This algorithm comes from Christer Ericson's Real-Time
- // Collision Detection.
- Vector2dF v0 = r2 - r1;
- Vector2dF v1 = r3 - r1;
- Vector2dF v2 = point - r1;
-
- double dot00 = DotProduct(v0, v0);
- double dot01 = DotProduct(v0, v1);
- double dot11 = DotProduct(v1, v1);
- double dot20 = DotProduct(v2, v0);
- double dot21 = DotProduct(v2, v1);
-
- double denom = dot00 * dot11 - dot01 * dot01;
-
- double v = (dot11 * dot20 - dot01 * dot21) / denom;
- double w = (dot00 * dot21 - dot01 * dot20) / denom;
- double u = 1 - v - w;
-
- // Use the barycentric coordinates to test if |point| is inside the
- // triangle (r1, r2, r2).
- return (v >= 0) && (w >= 0) && (u >= 0);
-}
-
-bool QuadF::Contains(const PointF& point) const {
- return PointIsInTriangle(point, p1_, p2_, p3_)
- || PointIsInTriangle(point, p1_, p3_, p4_);
-}
-
-void QuadF::Scale(float x_scale, float y_scale) {
- p1_.Scale(x_scale, y_scale);
- p2_.Scale(x_scale, y_scale);
- p3_.Scale(x_scale, y_scale);
- p4_.Scale(x_scale, y_scale);
-}
-
-void QuadF::operator+=(const Vector2dF& rhs) {
- p1_ += rhs;
- p2_ += rhs;
- p3_ += rhs;
- p4_ += rhs;
-}
-
-void QuadF::operator-=(const Vector2dF& rhs) {
- p1_ -= rhs;
- p2_ -= rhs;
- p3_ -= rhs;
- p4_ -= rhs;
-}
-
-QuadF operator+(const QuadF& lhs, const Vector2dF& rhs) {
- QuadF result = lhs;
- result += rhs;
- return result;
-}
-
-QuadF operator-(const QuadF& lhs, const Vector2dF& rhs) {
- QuadF result = lhs;
- result -= rhs;
- return result;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/quad_f.h b/chromium/ui/gfx/quad_f.h
index b8a42e9883e..05bf9d82dfc 100644
--- a/chromium/ui/gfx/quad_f.h
+++ b/chromium/ui/gfx/quad_f.h
@@ -1,109 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_QUAD_F_H_
-#define UI_GFX_QUAD_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/quad_f.h"
-#include <algorithm>
-#include <cmath>
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/rect_f.h"
-
-namespace gfx {
-
-// A Quad is defined by four corners, allowing it to have edges that are not
-// axis-aligned, unlike a Rect.
-class GFX_EXPORT QuadF {
- public:
- QuadF() {}
- QuadF(const PointF& p1, const PointF& p2, const PointF& p3, const PointF& p4)
- : p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4) {}
-
- explicit QuadF(const RectF& rect)
- : p1_(rect.x(), rect.y()),
- p2_(rect.right(), rect.y()),
- p3_(rect.right(), rect.bottom()),
- p4_(rect.x(), rect.bottom()) {}
-
- void operator=(const RectF& rect);
-
- void set_p1(const PointF& p) { p1_ = p; }
- void set_p2(const PointF& p) { p2_ = p; }
- void set_p3(const PointF& p) { p3_ = p; }
- void set_p4(const PointF& p) { p4_ = p; }
-
- const PointF& p1() const { return p1_; }
- const PointF& p2() const { return p2_; }
- const PointF& p3() const { return p3_; }
- const PointF& p4() const { return p4_; }
-
- // Returns true if the quad is an axis-aligned rectangle.
- bool IsRectilinear() const;
-
- // Returns true if the points of the quad are in counter-clockwise order. This
- // assumes that the quad is convex, and that no three points are collinear.
- bool IsCounterClockwise() const;
-
- // Returns true if the |point| is contained within the quad, or lies on on
- // edge of the quad.
- bool Contains(const gfx::PointF& point) const;
-
- // Returns a rectangle that bounds the four points of the quad. The points of
- // the quad may lie on the right/bottom edge of the resulting rectangle,
- // rather than being strictly inside it.
- RectF BoundingBox() const {
- float rl = std::min(std::min(p1_.x(), p2_.x()), std::min(p3_.x(), p4_.x()));
- float rr = std::max(std::max(p1_.x(), p2_.x()), std::max(p3_.x(), p4_.x()));
- float rt = std::min(std::min(p1_.y(), p2_.y()), std::min(p3_.y(), p4_.y()));
- float rb = std::max(std::max(p1_.y(), p2_.y()), std::max(p3_.y(), p4_.y()));
- return RectF(rl, rt, rr - rl, rb - rt);
- }
-
- // Add a vector to the quad, offseting each point in the quad by the vector.
- void operator+=(const Vector2dF& rhs);
- // Subtract a vector from the quad, offseting each point in the quad by the
- // inverse of the vector.
- void operator-=(const Vector2dF& rhs);
-
- // Scale each point in the quad by the |scale| factor.
- void Scale(float scale) { Scale(scale, scale); }
-
- // Scale each point in the quad by the scale factors along each axis.
- void Scale(float x_scale, float y_scale);
-
- // Returns a string representation of quad.
- std::string ToString() const;
-
- private:
- PointF p1_;
- PointF p2_;
- PointF p3_;
- PointF p4_;
-};
-
-inline bool operator==(const QuadF& lhs, const QuadF& rhs) {
- return
- lhs.p1() == rhs.p1() && lhs.p2() == rhs.p2() &&
- lhs.p3() == rhs.p3() && lhs.p4() == rhs.p4();
-}
-
-inline bool operator!=(const QuadF& lhs, const QuadF& rhs) {
- return !(lhs == rhs);
-}
-
-// Add a vector to a quad, offseting each point in the quad by the vector.
-GFX_EXPORT QuadF operator+(const QuadF& lhs, const Vector2dF& rhs);
-// Subtract a vector from a quad, offseting each point in the quad by the
-// inverse of the vector.
-GFX_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs);
-
-} // namespace gfx
-
-#endif // UI_GFX_QUAD_F_H_
diff --git a/chromium/ui/gfx/quad_unittest.cc b/chromium/ui/gfx/quad_unittest.cc
deleted file mode 100644
index 8859a0e6972..00000000000
--- a/chromium/ui/gfx/quad_unittest.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/quad_f.h"
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect_f.h"
-
-namespace gfx {
-
-TEST(QuadTest, Construction) {
- // Verify constructors.
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- PointF e;
- QuadF q1;
- QuadF q2(e, e, e, e);
- QuadF q3(a, b, c, d);
- QuadF q4(BoundingRect(a, c));
- EXPECT_EQ(q1.ToString(), q2.ToString());
- EXPECT_EQ(q3.ToString(), q4.ToString());
-
- // Verify getters.
- EXPECT_EQ(q3.p1().ToString(), a.ToString());
- EXPECT_EQ(q3.p2().ToString(), b.ToString());
- EXPECT_EQ(q3.p3().ToString(), c.ToString());
- EXPECT_EQ(q3.p4().ToString(), d.ToString());
-
- // Verify setters.
- q3.set_p1(b);
- q3.set_p2(c);
- q3.set_p3(d);
- q3.set_p4(a);
- EXPECT_EQ(q3.p1().ToString(), b.ToString());
- EXPECT_EQ(q3.p2().ToString(), c.ToString());
- EXPECT_EQ(q3.p3().ToString(), d.ToString());
- EXPECT_EQ(q3.p4().ToString(), a.ToString());
-
- // Verify operator=(Rect)
- EXPECT_NE(q1.ToString(), q4.ToString());
- q1 = BoundingRect(a, c);
- EXPECT_EQ(q1.ToString(), q4.ToString());
-
- // Verify operator=(Quad)
- EXPECT_NE(q1.ToString(), q3.ToString());
- q1 = q3;
- EXPECT_EQ(q1.ToString(), q3.ToString());
-}
-
-TEST(QuadTest, AddingVectors) {
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- Vector2dF v(3.5f, -2.5f);
-
- QuadF q1(a, b, c, d);
- QuadF added = q1 + v;
- q1 += v;
- QuadF expected1(PointF(4.5f, -1.5f),
- PointF(5.5f, -1.5f),
- PointF(5.5f, -0.5f),
- PointF(4.5f, -0.5f));
- EXPECT_EQ(expected1.ToString(), added.ToString());
- EXPECT_EQ(expected1.ToString(), q1.ToString());
-
- QuadF q2(a, b, c, d);
- QuadF subtracted = q2 - v;
- q2 -= v;
- QuadF expected2(PointF(-2.5f, 3.5f),
- PointF(-1.5f, 3.5f),
- PointF(-1.5f, 4.5f),
- PointF(-2.5f, 4.5f));
- EXPECT_EQ(expected2.ToString(), subtracted.ToString());
- EXPECT_EQ(expected2.ToString(), q2.ToString());
-
- QuadF q3(a, b, c, d);
- q3 += v;
- q3 -= v;
- EXPECT_EQ(QuadF(a, b, c, d).ToString(), q3.ToString());
- EXPECT_EQ(q3.ToString(), (q3 + v - v).ToString());
-}
-
-TEST(QuadTest, IsRectilinear) {
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- Vector2dF v(3.5f, -2.5f);
-
- EXPECT_TRUE(QuadF().IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
-
- float epsilon = std::numeric_limits<float>::epsilon();
- PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
- PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
- PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
- PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
- EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
-
- struct {
- PointF a_off, b_off, c_off, d_off;
- } tests[] = {
- {
- PointF(1, 1.00001f),
- PointF(2, 1.00001f),
- PointF(2, 2.00001f),
- PointF(1, 2.00001f)
- },
- {
- PointF(1.00001f, 1),
- PointF(2.00001f, 1),
- PointF(2.00001f, 2),
- PointF(1.00001f, 2)
- },
- {
- PointF(1.00001f, 1.00001f),
- PointF(2.00001f, 1.00001f),
- PointF(2.00001f, 2.00001f),
- PointF(1.00001f, 2.00001f)
- },
- {
- PointF(1, 0.99999f),
- PointF(2, 0.99999f),
- PointF(2, 1.99999f),
- PointF(1, 1.99999f)
- },
- {
- PointF(0.99999f, 1),
- PointF(1.99999f, 1),
- PointF(1.99999f, 2),
- PointF(0.99999f, 2)
- },
- {
- PointF(0.99999f, 0.99999f),
- PointF(1.99999f, 0.99999f),
- PointF(1.99999f, 1.99999f),
- PointF(0.99999f, 1.99999f)
- }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- PointF a_off = tests[i].a_off;
- PointF b_off = tests[i].b_off;
- PointF c_off = tests[i].c_off;
- PointF d_off = tests[i].d_off;
-
- EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
- EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
- }
-}
-
-TEST(QuadTest, IsCounterClockwise) {
- PointF a1(1, 1);
- PointF b1(2, 1);
- PointF c1(2, 2);
- PointF d1(1, 2);
- EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
-
- // Slightly more complicated quads should work just as easily.
- PointF a2(1.3f, 1.4f);
- PointF b2(-0.7f, 4.9f);
- PointF c2(1.8f, 6.2f);
- PointF d2(2.1f, 1.6f);
- EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
- EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
- EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
- EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
-
- // Quads with 3 collinear points should work correctly, too.
- PointF a3(0, 0);
- PointF b3(1, 0);
- PointF c3(2, 0);
- PointF d3(1, 1);
- EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
- // The next expectation in particular would fail for an implementation
- // that incorrectly uses only a cross product of the first 3 vertices.
- EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
-
- // Non-convex quads should work correctly, too.
- PointF a4(0, 0);
- PointF b4(1, 1);
- PointF c4(2, 0);
- PointF d4(1, 3);
- EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
-
- // A quad with huge coordinates should not fail this check due to
- // single-precision overflow.
- PointF a5(1e30f, 1e30f);
- PointF b5(1e35f, 1e30f);
- PointF c5(1e35f, 1e35f);
- PointF d5(1e30f, 1e35f);
- EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
-}
-
-TEST(QuadTest, BoundingBox) {
- RectF r(3.2f, 5.4f, 7.007f, 12.01f);
- EXPECT_EQ(r.ToString(), QuadF(r).BoundingBox().ToString());
-
- PointF a(1.3f, 1.4f);
- PointF b(-0.7f, 4.9f);
- PointF c(1.8f, 6.2f);
- PointF d(2.1f, 1.6f);
- float left = -0.7f;
- float top = 1.4f;
- float right = 2.1f;
- float bottom = 6.2f;
- EXPECT_EQ(RectF(left, top, right - left, bottom - top).ToString(),
- QuadF(a, b, c, d).BoundingBox().ToString());
-}
-
-TEST(QuadTest, ContainsPoint) {
- PointF a(1.3f, 1.4f);
- PointF b(-0.8f, 4.4f);
- PointF c(1.8f, 6.1f);
- PointF d(2.1f, 1.6f);
-
- Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
- Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
-
- Vector2dF ac_center = c - a;
- ac_center.Scale(0.5f);
- Vector2dF bd_center = d - b;
- bd_center.Scale(0.5f);
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
-
- // Test a simple square.
- PointF s1(-1, -1);
- PointF s2(1, -1);
- PointF s3(1, 1);
- PointF s4(-1, 1);
- // Top edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
- // Bottom edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
- // Left edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
- // Right edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
- // Centered inside.
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
- // Centered outside.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
-}
-
-TEST(QuadTest, Scale) {
- PointF a(1.3f, 1.4f);
- PointF b(-0.8f, 4.4f);
- PointF c(1.8f, 6.1f);
- PointF d(2.1f, 1.6f);
- QuadF q1(a, b, c, d);
- q1.Scale(1.5f);
-
- PointF a_scaled = ScalePoint(a, 1.5f);
- PointF b_scaled = ScalePoint(b, 1.5f);
- PointF c_scaled = ScalePoint(c, 1.5f);
- PointF d_scaled = ScalePoint(d, 1.5f);
- EXPECT_EQ(q1.ToString(),
- QuadF(a_scaled, b_scaled, c_scaled, d_scaled).ToString());
-
- QuadF q2;
- q2.Scale(1.5f);
- EXPECT_EQ(q2.ToString(), q2.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/rect.cc b/chromium/ui/gfx/rect.cc
deleted file mode 100644
index 8372cc4e7c5..00000000000
--- a/chromium/ui/gfx/rect.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/rect.h"
-
-#include <algorithm>
-
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#endif
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect_base_impl.h"
-
-namespace gfx {
-
-template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
-
-typedef class RectBase<Rect, Point, Size, Insets, Vector2d, int> RectBaseT;
-
-#if defined(OS_WIN)
-Rect::Rect(const RECT& r)
- : RectBaseT(gfx::Point(r.left, r.top)) {
- set_width(std::abs(r.right - r.left));
- set_height(std::abs(r.bottom - r.top));
-}
-#elif defined(OS_MACOSX)
-Rect::Rect(const CGRect& r)
- : RectBaseT(gfx::Point(r.origin.x, r.origin.y)) {
- set_width(r.size.width);
- set_height(r.size.height);
-}
-#elif defined(TOOLKIT_GTK)
-Rect::Rect(const GdkRectangle& r)
- : RectBaseT(gfx::Point(r.x, r.y)) {
- set_width(r.width);
- set_height(r.height);
-}
-#endif
-
-#if defined(OS_WIN)
-RECT Rect::ToRECT() const {
- RECT r;
- r.left = x();
- r.right = right();
- r.top = y();
- r.bottom = bottom();
- return r;
-}
-#elif defined(OS_MACOSX)
-CGRect Rect::ToCGRect() const {
- return CGRectMake(x(), y(), width(), height());
-}
-#elif defined(TOOLKIT_GTK)
-GdkRectangle Rect::ToGdkRectangle() const {
- GdkRectangle r = {x(), y(), width(), height()};
- return r;
-}
-#endif
-
-std::string Rect::ToString() const {
- return base::StringPrintf("%s %s",
- origin().ToString().c_str(),
- size().ToString().c_str());
-}
-
-Rect operator+(const Rect& lhs, const Vector2d& rhs) {
- Rect result(lhs);
- result += rhs;
- return result;
-}
-
-Rect operator-(const Rect& lhs, const Vector2d& rhs) {
- Rect result(lhs);
- result -= rhs;
- return result;
-}
-
-Rect IntersectRects(const Rect& a, const Rect& b) {
- Rect result = a;
- result.Intersect(b);
- return result;
-}
-
-Rect UnionRects(const Rect& a, const Rect& b) {
- Rect result = a;
- result.Union(b);
- return result;
-}
-
-Rect SubtractRects(const Rect& a, const Rect& b) {
- Rect result = a;
- result.Subtract(b);
- return result;
-}
-
-Rect BoundingRect(const Point& p1, const Point& p2) {
- int rx = std::min(p1.x(), p2.x());
- int ry = std::min(p1.y(), p2.y());
- int rr = std::max(p1.x(), p2.x());
- int rb = std::max(p1.y(), p2.y());
- return Rect(rx, ry, rr - rx, rb - ry);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/rect.h b/chromium/ui/gfx/rect.h
index df7f9aac366..a83d6b42cef 100644
--- a/chromium/ui/gfx/rect.h
+++ b/chromium/ui/gfx/rect.h
@@ -1,145 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Defines a simple integer rectangle class. The containment semantics
-// are array-like; that is, the coordinate (x, y) is considered to be
-// contained by the rectangle, but the coordinate (x + width, y) is not.
-// The class will happily let you create malformed rectangles (that is,
-// rectangles with negative width and/or height), but there will be assertions
-// in the operations (such as Contains()) to complain in this case.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect.h"
-#ifndef UI_GFX_RECT_H_
-#define UI_GFX_RECT_H_
-
-#include <cmath>
-#include <string>
-
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect_base.h"
-#include "ui/gfx/rect_f.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/vector2d.h"
-
-#if defined(OS_WIN)
-typedef struct tagRECT RECT;
-#elif defined(TOOLKIT_GTK)
-typedef struct _GdkRectangle GdkRectangle;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-class Insets;
-
-class GFX_EXPORT Rect
- : public RectBase<Rect, Point, Size, Insets, Vector2d, int> {
- public:
- Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {}
-
- Rect(int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>
- (Size(width, height)) {}
-
- Rect(int x, int y, int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>
- (Point(x, y), Size(width, height)) {}
-
-#if defined(OS_WIN)
- explicit Rect(const RECT& r);
-#elif defined(OS_MACOSX)
- explicit Rect(const CGRect& r);
-#elif defined(TOOLKIT_GTK)
- explicit Rect(const GdkRectangle& r);
-#endif
-
- explicit Rect(const gfx::Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(size) {}
-
- Rect(const gfx::Point& origin, const gfx::Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(origin, size) {}
-
- ~Rect() {}
-
-#if defined(OS_WIN)
- // Construct an equivalent Win32 RECT object.
- RECT ToRECT() const;
-#elif defined(TOOLKIT_GTK)
- GdkRectangle ToGdkRectangle() const;
-#elif defined(OS_MACOSX)
- // Construct an equivalent CoreGraphics object.
- CGRect ToCGRect() const;
-#endif
-
- operator RectF() const {
- return RectF(origin().x(), origin().y(), size().width(), size().height());
- }
-
- std::string ToString() const;
-};
-
-inline bool operator==(const Rect& lhs, const Rect& rhs) {
- return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
-}
-
-inline bool operator!=(const Rect& lhs, const Rect& rhs) {
- return !(lhs == rhs);
-}
-
-GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
-GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
-
-inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
- return rhs + lhs;
-}
-
-GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
-GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
-GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
-
-// Constructs a rectangle with |p1| and |p2| as opposite corners.
-//
-// This could also be thought of as "the smallest rect that contains both
-// points", except that we consider points on the right/bottom edges of the
-// rect to be outside the rect. So technically one or both points will not be
-// contained within the rect, because they will appear on one of these edges.
-GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
-
-inline Rect ScaleToEnclosingRect(const Rect& rect,
- float x_scale,
- float y_scale) {
- int x = std::floor(rect.x() * x_scale);
- int y = std::floor(rect.y() * y_scale);
- int r = rect.width() == 0 ? x : std::ceil(rect.right() * x_scale);
- int b = rect.height() == 0 ? y : std::ceil(rect.bottom() * y_scale);
- return Rect(x, y, r - x, b - y);
-}
-
-inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
- return ScaleToEnclosingRect(rect, scale, scale);
-}
-
-inline Rect ScaleToEnclosedRect(const Rect& rect,
- float x_scale,
- float y_scale) {
- int x = std::ceil(rect.x() * x_scale);
- int y = std::ceil(rect.y() * y_scale);
- int r = rect.width() == 0 ? x : std::floor(rect.right() * x_scale);
- int b = rect.height() == 0 ? y : std::floor(rect.bottom() * y_scale);
- return Rect(x, y, r - x, b - y);
-}
-
-inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
- return ScaleToEnclosedRect(rect, scale, scale);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_H_
diff --git a/chromium/ui/gfx/rect_base.h b/chromium/ui/gfx/rect_base.h
deleted file mode 100644
index 412836ced19..00000000000
--- a/chromium/ui/gfx/rect_base.h
+++ /dev/null
@@ -1,174 +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.
-
-// A template for a simple rectangle class. The containment semantics
-// are array-like; that is, the coordinate (x, y) is considered to be
-// contained by the rectangle, but the coordinate (x + width, y) is not.
-// The class will happily let you create malformed rectangles (that is,
-// rectangles with negative width and/or height), but there will be assertions
-// in the operations (such as Contains()) to complain in this case.
-
-#ifndef UI_GFX_RECT_BASE_H_
-#define UI_GFX_RECT_BASE_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-
-namespace gfx {
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-class GFX_EXPORT RectBase {
- public:
- Type x() const { return origin_.x(); }
- void set_x(Type x) { origin_.set_x(x); }
-
- Type y() const { return origin_.y(); }
- void set_y(Type y) { origin_.set_y(y); }
-
- Type width() const { return size_.width(); }
- void set_width(Type width) { size_.set_width(width); }
-
- Type height() const { return size_.height(); }
- void set_height(Type height) { size_.set_height(height); }
-
- const PointClass& origin() const { return origin_; }
- void set_origin(const PointClass& origin) { origin_ = origin; }
-
- const SizeClass& size() const { return size_; }
- void set_size(const SizeClass& size) { size_ = size; }
-
- Type right() const { return x() + width(); }
- Type bottom() const { return y() + height(); }
-
- PointClass top_right() const { return PointClass(right(), y()); }
- PointClass bottom_left() const { return PointClass(x(), bottom()); }
- PointClass bottom_right() const { return PointClass(right(), bottom()); }
-
- VectorClass OffsetFromOrigin() const {
- return VectorClass(x(), y());
- }
-
- void SetRect(Type x, Type y, Type width, Type height);
-
- // Shrink the rectangle by a horizontal and vertical distance on all sides.
- void Inset(Type horizontal, Type vertical) {
- Inset(horizontal, vertical, horizontal, vertical);
- }
-
- // Shrink the rectangle by the given insets.
- void Inset(const InsetsClass& insets);
-
- // Shrink the rectangle by the specified amount on each side.
- void Inset(Type left, Type top, Type right, Type bottom);
-
- // Move the rectangle by a horizontal and vertical distance.
- void Offset(Type horizontal, Type vertical);
- void Offset(const VectorClass& distance) {
- Offset(distance.x(), distance.y());
- }
- void operator+=(const VectorClass& offset);
- void operator-=(const VectorClass& offset);
-
- InsetsClass InsetsFrom(const Class& inner) const {
- return InsetsClass(inner.y() - y(),
- inner.x() - x(),
- bottom() - inner.bottom(),
- right() - inner.right());
- }
-
- // Returns true if the area of the rectangle is zero.
- bool IsEmpty() const { return size_.IsEmpty(); }
-
- // A rect is less than another rect if its origin is less than
- // the other rect's origin. If the origins are equal, then the
- // shortest rect is less than the other. If the origin and the
- // height are equal, then the narrowest rect is less than.
- // This comparison is required to use Rects in sets, or sorted
- // vectors.
- bool operator<(const Class& other) const;
-
- // Returns true if the point identified by point_x and point_y falls inside
- // this rectangle. The point (x, y) is inside the rectangle, but the
- // point (x + width, y + height) is not.
- bool Contains(Type point_x, Type point_y) const;
-
- // Returns true if the specified point is contained by this rectangle.
- bool Contains(const PointClass& point) const {
- return Contains(point.x(), point.y());
- }
-
- // Returns true if this rectangle contains the specified rectangle.
- bool Contains(const Class& rect) const;
-
- // Returns true if this rectangle intersects the specified rectangle.
- // An empty rectangle doesn't intersect any rectangle.
- bool Intersects(const Class& rect) const;
-
- // Computes the intersection of this rectangle with the given rectangle.
- void Intersect(const Class& rect);
-
- // Computes the union of this rectangle with the given rectangle. The union
- // is the smallest rectangle containing both rectangles.
- void Union(const Class& rect);
-
- // Computes the rectangle resulting from subtracting |rect| from |*this|,
- // i.e. the bounding rect of |Region(*this) - Region(rect)|.
- void Subtract(const Class& rect);
-
- // Fits as much of the receiving rectangle into the supplied rectangle as
- // possible, becoming the result. For example, if the receiver had
- // a x-location of 2 and a width of 4, and the supplied rectangle had
- // an x-location of 0 with a width of 5, the returned rectangle would have
- // an x-location of 1 with a width of 4.
- void AdjustToFit(const Class& rect);
-
- // Returns the center of this rectangle.
- PointClass CenterPoint() const;
-
- // Becomes a rectangle that has the same center point but with a size capped
- // at given |size|.
- void ClampToCenteredSize(const SizeClass& size);
-
- // Splits |this| in two halves, |left_half| and |right_half|.
- void SplitVertically(Class* left_half, Class* right_half) const;
-
- // Returns true if this rectangle shares an entire edge (i.e., same width or
- // same height) with the given rectangle, and the rectangles do not overlap.
- bool SharesEdgeWith(const Class& rect) const;
-
- // Returns the manhattan distance from the rect to the point. If the point is
- // inside the rect, returns 0.
- Type ManhattanDistanceToPoint(const PointClass& point) const;
-
- // Returns the manhattan distance between the contents of this rect and the
- // contents of the given rect. That is, if the intersection of the two rects
- // is non-empty then the function returns 0. If the rects share a side, it
- // returns the smallest non-zero value appropriate for Type.
- Type ManhattanInternalDistance(const Class& rect) const;
-
- protected:
- RectBase(const PointClass& origin, const SizeClass& size)
- : origin_(origin), size_(size) {}
- explicit RectBase(const SizeClass& size)
- : size_(size) {}
- explicit RectBase(const PointClass& origin)
- : origin_(origin) {}
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~RectBase() {}
-
- private:
- PointClass origin_;
- SizeClass size_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_BASE_H_
diff --git a/chromium/ui/gfx/rect_base_impl.h b/chromium/ui/gfx/rect_base_impl.h
deleted file mode 100644
index 52201691a1b..00000000000
--- a/chromium/ui/gfx/rect_base_impl.h
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits>
-
-#include "ui/gfx/rect_base.h"
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-
-// This file provides the implementation for RectBaese template and
-// used to instantiate the base class for Rect and RectF classes.
-#if !defined(GFX_IMPLEMENTATION)
-#error "This file is intended for UI implementation only"
-#endif
-
-namespace {
-
-template<typename Type>
-void AdjustAlongAxis(Type dst_origin, Type dst_size, Type* origin, Type* size) {
- *size = std::min(dst_size, *size);
- if (*origin < dst_origin)
- *origin = dst_origin;
- else
- *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
-}
-
-} // namespace
-
-namespace gfx {
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- SetRect(Type x, Type y, Type width, Type height) {
- origin_.SetPoint(x, y);
- set_width(width);
- set_height(height);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Inset(const InsetsClass& insets) {
- Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Inset(Type left, Type top, Type right, Type bottom) {
- origin_ += VectorClass(left, top);
- set_width(std::max(width() - left - right, static_cast<Type>(0)));
- set_height(std::max(height() - top - bottom, static_cast<Type>(0)));
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Offset(Type horizontal, Type vertical) {
- origin_ += VectorClass(horizontal, vertical);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- operator+=(const VectorClass& offset) {
- origin_ += offset;
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- operator-=(const VectorClass& offset) {
- origin_ -= offset;
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- operator<(const Class& other) const {
- if (origin_ == other.origin_) {
- if (width() == other.width()) {
- return height() < other.height();
- } else {
- return width() < other.width();
- }
- } else {
- return origin_ < other.origin_;
- }
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Contains(Type point_x, Type point_y) const {
- return (point_x >= x()) && (point_x < right()) &&
- (point_y >= y()) && (point_y < bottom());
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Contains(const Class& rect) const {
- return (rect.x() >= x() && rect.right() <= right() &&
- rect.y() >= y() && rect.bottom() <= bottom());
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Intersects(const Class& rect) const {
- return !(IsEmpty() || rect.IsEmpty() ||
- rect.x() >= right() || rect.right() <= x() ||
- rect.y() >= bottom() || rect.bottom() <= y());
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Intersect(const Class& rect) {
- if (IsEmpty() || rect.IsEmpty()) {
- SetRect(0, 0, 0, 0);
- return;
- }
-
- Type rx = std::max(x(), rect.x());
- Type ry = std::max(y(), rect.y());
- Type rr = std::min(right(), rect.right());
- Type rb = std::min(bottom(), rect.bottom());
-
- if (rx >= rr || ry >= rb)
- rx = ry = rr = rb = 0; // non-intersecting
-
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Union(const Class& rect) {
- if (IsEmpty()) {
- *this = rect;
- return;
- }
- if (rect.IsEmpty())
- return;
-
- Type rx = std::min(x(), rect.x());
- Type ry = std::min(y(), rect.y());
- Type rr = std::max(right(), rect.right());
- Type rb = std::max(bottom(), rect.bottom());
-
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- Subtract(const Class& rect) {
- if (!Intersects(rect))
- return;
- if (rect.Contains(*static_cast<const Class*>(this))) {
- SetRect(0, 0, 0, 0);
- return;
- }
-
- Type rx = x();
- Type ry = y();
- Type rr = right();
- Type rb = bottom();
-
- if (rect.y() <= y() && rect.bottom() >= bottom()) {
- // complete intersection in the y-direction
- if (rect.x() <= x()) {
- rx = rect.right();
- } else if (rect.right() >= right()) {
- rr = rect.x();
- }
- } else if (rect.x() <= x() && rect.right() >= right()) {
- // complete intersection in the x-direction
- if (rect.y() <= y()) {
- ry = rect.bottom();
- } else if (rect.bottom() >= bottom()) {
- rb = rect.y();
- }
- }
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- AdjustToFit(const Class& rect) {
- Type new_x = x();
- Type new_y = y();
- Type new_width = width();
- Type new_height = height();
- AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
- AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
- SetRect(new_x, new_y, new_width, new_height);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-PointClass RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::CenterPoint() const {
- return PointClass(x() + width() / 2, y() + height() / 2);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- ClampToCenteredSize(const SizeClass& size) {
- Type new_width = std::min(width(), size.width());
- Type new_height = std::min(height(), size.height());
- Type new_x = x() + (width() - new_width) / 2;
- Type new_y = y() + (height() - new_height) / 2;
- SetRect(new_x, new_y, new_width, new_height);
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- SplitVertically(Class* left_half, Class* right_half) const {
- DCHECK(left_half);
- DCHECK(right_half);
-
- left_half->SetRect(x(), y(), width() / 2, height());
- right_half->SetRect(left_half->right(),
- y(),
- width() - left_half->width(),
- height());
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- SharesEdgeWith(const Class& rect) const {
- return (y() == rect.y() && height() == rect.height() &&
- (x() == rect.right() || right() == rect.x())) ||
- (x() == rect.x() && width() == rect.width() &&
- (y() == rect.bottom() || bottom() == rect.y()));
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- ManhattanDistanceToPoint(const PointClass& point) const {
- Type x_distance = std::max<Type>(0, std::max(
- x() - point.x(), point.x() - right()));
- Type y_distance = std::max<Type>(0, std::max(
- y() - point.y(), point.y() - bottom()));
-
- return x_distance + y_distance;
-}
-
-template<typename Class,
- typename PointClass,
- typename SizeClass,
- typename InsetsClass,
- typename VectorClass,
- typename Type>
-Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
- ManhattanInternalDistance(const Class& rect) const {
- Class c(x(), y(), width(), height());
- c.Union(rect);
-
- static const Type kEpsilon = std::numeric_limits<Type>::is_integer
- ? 1
- : std::numeric_limits<Type>::epsilon();
-
- Type x = std::max<Type>(0, c.width() - width() - rect.width() + kEpsilon);
- Type y = std::max<Type>(0, c.height() - height() - rect.height() + kEpsilon);
- return x + y;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/rect_conversions.cc b/chromium/ui/gfx/rect_conversions.cc
deleted file mode 100644
index a54a49a23d6..00000000000
--- a/chromium/ui/gfx/rect_conversions.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/rect_conversions.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "ui/gfx/safe_integer_conversions.h"
-
-namespace gfx {
-
-Rect ToEnclosingRect(const RectF& rect) {
- int min_x = ToFlooredInt(rect.x());
- int min_y = ToFlooredInt(rect.y());
- float max_x = rect.right();
- float max_y = rect.bottom();
- int width = rect.width() == 0 ? 0 : std::max(ToCeiledInt(max_x) - min_x, 0);
- int height = rect.height() == 0 ? 0 : std::max(ToCeiledInt(max_y) - min_y, 0);
- return Rect(min_x, min_y, width, height);
-}
-
-Rect ToEnclosedRect(const RectF& rect) {
- int min_x = ToCeiledInt(rect.x());
- int min_y = ToCeiledInt(rect.y());
- float max_x = rect.right();
- float max_y = rect.bottom();
- int width = std::max(ToFlooredInt(max_x) - min_x, 0);
- int height = std::max(ToFlooredInt(max_y) - min_y, 0);
- return Rect(min_x, min_y, width, height);
-}
-
-Rect ToNearestRect(const RectF& rect) {
- float float_min_x = rect.x();
- float float_min_y = rect.y();
- float float_max_x = rect.right();
- float float_max_y = rect.bottom();
-
- int min_x = ToRoundedInt(float_min_x);
- int min_y = ToRoundedInt(float_min_y);
- int max_x = ToRoundedInt(float_max_x);
- int max_y = ToRoundedInt(float_max_y);
-
- // If these DCHECKs fail, you're using the wrong method, consider using
- // ToEnclosingRect or ToEnclosedRect instead.
- DCHECK(std::abs(min_x - float_min_x) < 0.01f);
- DCHECK(std::abs(min_y - float_min_y) < 0.01f);
- DCHECK(std::abs(max_x - float_max_x) < 0.01f);
- DCHECK(std::abs(max_y - float_max_y) < 0.01f);
-
- return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
-}
-
-bool IsNearestRectWithinDistance(const gfx::RectF& rect, float distance) {
- float float_min_x = rect.x();
- float float_min_y = rect.y();
- float float_max_x = rect.right();
- float float_max_y = rect.bottom();
-
- int min_x = ToRoundedInt(float_min_x);
- int min_y = ToRoundedInt(float_min_y);
- int max_x = ToRoundedInt(float_max_x);
- int max_y = ToRoundedInt(float_max_y);
-
- return
- (std::abs(min_x - float_min_x) < distance) &&
- (std::abs(min_y - float_min_y) < distance) &&
- (std::abs(max_x - float_max_x) < distance) &&
- (std::abs(max_y - float_max_y) < distance);
-}
-
-Rect ToFlooredRectDeprecated(const RectF& rect) {
- return Rect(ToFlooredInt(rect.x()),
- ToFlooredInt(rect.y()),
- ToFlooredInt(rect.width()),
- ToFlooredInt(rect.height()));
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/rect_conversions.h b/chromium/ui/gfx/rect_conversions.h
index 988f6c76418..537435120c0 100644
--- a/chromium/ui/gfx/rect_conversions.h
+++ b/chromium/ui/gfx/rect_conversions.h
@@ -1,36 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_RECT_CONVERSIONS_H_
-#define UI_GFX_RECT_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
-
-namespace gfx {
-
-// Returns the smallest Rect that encloses the given RectF.
-GFX_EXPORT Rect ToEnclosingRect(const RectF& rect);
-
-// Returns the largest Rect that is enclosed by the given RectF.
-GFX_EXPORT Rect ToEnclosedRect(const RectF& rect);
-
-// Returns the Rect after snapping the corners of the RectF to an integer grid.
-// This should only be used when the RectF you provide is expected to be an
-// integer rect with floating point error. If it is an arbitrary RectF, then
-// you should use a different method.
-GFX_EXPORT Rect ToNearestRect(const RectF& rect);
-
-// Returns true if the Rect produced after snapping the corners of the RectF
-// to an integer grid is withing |distance|.
-GFX_EXPORT bool IsNearestRectWithinDistance(
- const gfx::RectF& rect, float distance);
-
-// Returns a Rect obtained by flooring the values of the given RectF.
-// Please prefer the previous two functions in new code.
-GFX_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect);
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/rect_f.cc b/chromium/ui/gfx/rect_f.cc
deleted file mode 100644
index c55752aa843..00000000000
--- a/chromium/ui/gfx/rect_f.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/rect_f.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "ui/gfx/insets_f.h"
-#include "ui/gfx/rect_base_impl.h"
-#include "ui/gfx/safe_integer_conversions.h"
-
-namespace gfx {
-
-template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
-
-typedef class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF,
- float> RectBaseT;
-
-bool RectF::IsExpressibleAsRect() const {
- return IsExpressibleAsInt(x()) && IsExpressibleAsInt(y()) &&
- IsExpressibleAsInt(width()) && IsExpressibleAsInt(height()) &&
- IsExpressibleAsInt(right()) && IsExpressibleAsInt(bottom());
-}
-
-std::string RectF::ToString() const {
- return base::StringPrintf("%s %s",
- origin().ToString().c_str(),
- size().ToString().c_str());
-}
-
-RectF IntersectRects(const RectF& a, const RectF& b) {
- RectF result = a;
- result.Intersect(b);
- return result;
-}
-
-RectF UnionRects(const RectF& a, const RectF& b) {
- RectF result = a;
- result.Union(b);
- return result;
-}
-
-RectF SubtractRects(const RectF& a, const RectF& b) {
- RectF result = a;
- result.Subtract(b);
- return result;
-}
-
-RectF BoundingRect(const PointF& p1, const PointF& p2) {
- float rx = std::min(p1.x(), p2.x());
- float ry = std::min(p1.y(), p2.y());
- float rr = std::max(p1.x(), p2.x());
- float rb = std::max(p1.y(), p2.y());
- return RectF(rx, ry, rr - rx, rb - ry);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/rect_f.h b/chromium/ui/gfx/rect_f.h
index 09de529a627..71564bb65c8 100644
--- a/chromium/ui/gfx/rect_f.h
+++ b/chromium/ui/gfx/rect_f.h
@@ -1,113 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_RECT_F_H_
-#define UI_GFX_RECT_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect_f.h"
-#include <string>
-
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/rect_base.h"
-#include "ui/gfx/size_f.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class InsetsF;
-
-// A floating version of gfx::Rect.
-class GFX_EXPORT RectF
- : public RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float> {
- public:
- RectF()
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (SizeF()) {}
-
- RectF(float width, float height)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (SizeF(width, height)) {}
-
- RectF(float x, float y, float width, float height)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (PointF(x, y), SizeF(width, height)) {}
-
- explicit RectF(const SizeF& size)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (size) {}
-
- RectF(const PointF& origin, const SizeF& size)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (origin, size) {}
-
- ~RectF() {}
-
- // Scales the rectangle by |scale|.
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- set_origin(ScalePoint(origin(), x_scale, y_scale));
- set_size(ScaleSize(size(), x_scale, y_scale));
- }
-
- // This method reports if the RectF can be safely converted to an integer
- // Rect. When it is false, some dimension of the RectF is outside the bounds
- // of what an integer can represent, and converting it to a Rect will require
- // clamping.
- bool IsExpressibleAsRect() const;
-
- std::string ToString() const;
-};
-
-inline bool operator==(const RectF& lhs, const RectF& rhs) {
- return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
-}
-
-inline bool operator!=(const RectF& lhs, const RectF& rhs) {
- return !(lhs == rhs);
-}
-
-inline RectF operator+(const RectF& lhs, const Vector2dF& rhs) {
- return RectF(lhs.x() + rhs.x(), lhs.y() + rhs.y(),
- lhs.width(), lhs.height());
-}
-
-inline RectF operator-(const RectF& lhs, const Vector2dF& rhs) {
- return RectF(lhs.x() - rhs.x(), lhs.y() - rhs.y(),
- lhs.width(), lhs.height());
-}
-
-inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) {
- return rhs + lhs;
-}
-
-GFX_EXPORT RectF IntersectRects(const RectF& a, const RectF& b);
-GFX_EXPORT RectF UnionRects(const RectF& a, const RectF& b);
-GFX_EXPORT RectF SubtractRects(const RectF& a, const RectF& b);
-
-inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) {
- return RectF(r.x() * x_scale, r.y() * y_scale,
- r.width() * x_scale, r.height() * y_scale);
-}
-
-inline RectF ScaleRect(const RectF& r, float scale) {
- return ScaleRect(r, scale, scale);
-}
-
-// Constructs a rectangle with |p1| and |p2| as opposite corners.
-//
-// This could also be thought of as "the smallest rect that contains both
-// points", except that we consider points on the right/bottom edges of the
-// rect to be outside the rect. So technically one or both points will not be
-// contained within the rect, because they will appear on one of these edges.
-GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2);
-
-#if !defined(COMPILER_MSVC)
-extern template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_F_H_
diff --git a/chromium/ui/gfx/rect_unittest.cc b/chromium/ui/gfx/rect_unittest.cc
deleted file mode 100644
index 31a156b7910..00000000000
--- a/chromium/ui/gfx/rect_unittest.cc
+++ /dev/null
@@ -1,936 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/skia_util.h"
-
-#include <limits>
-
-namespace gfx {
-
-TEST(RectTest, Contains) {
- static const struct ContainsCase {
- int rect_x;
- int rect_y;
- int rect_width;
- int rect_height;
- int point_x;
- int point_y;
- bool contained;
- } contains_cases[] = {
- {0, 0, 10, 10, 0, 0, true},
- {0, 0, 10, 10, 5, 5, true},
- {0, 0, 10, 10, 9, 9, true},
- {0, 0, 10, 10, 5, 10, false},
- {0, 0, 10, 10, 10, 5, false},
- {0, 0, 10, 10, -1, -1, false},
- {0, 0, 10, 10, 50, 50, false},
- #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
- {0, 0, -10, -10, 0, 0, false},
- #endif
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(contains_cases); ++i) {
- const ContainsCase& value = contains_cases[i];
- Rect rect(value.rect_x, value.rect_y, value.rect_width, value.rect_height);
- EXPECT_EQ(value.contained, rect.Contains(value.point_x, value.point_y));
- }
-}
-
-TEST(RectTest, Intersects) {
- static const struct {
- int x1; // rect 1
- int y1;
- int w1;
- int h1;
- int x2; // rect 2
- int y2;
- int w2;
- int h2;
- bool intersects;
- } tests[] = {
- { 0, 0, 0, 0, 0, 0, 0, 0, false },
- { 0, 0, 0, 0, -10, -10, 20, 20, false },
- { -10, 0, 0, 20, 0, -10, 20, 0, false },
- { 0, 0, 10, 10, 0, 0, 10, 10, true },
- { 0, 0, 10, 10, 10, 10, 10, 10, false },
- { 10, 10, 10, 10, 0, 0, 10, 10, false },
- { 10, 10, 10, 10, 5, 5, 10, 10, true },
- { 10, 10, 10, 10, 15, 15, 10, 10, true },
- { 10, 10, 10, 10, 20, 15, 10, 10, false },
- { 10, 10, 10, 10, 21, 15, 10, 10, false }
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
- EXPECT_EQ(tests[i].intersects, r1.Intersects(r2));
- EXPECT_EQ(tests[i].intersects, r2.Intersects(r1));
- }
-}
-
-TEST(RectTest, Intersect) {
- static const struct {
- int x1; // rect 1
- int y1;
- int w1;
- int h1;
- int x2; // rect 2
- int y2;
- int w2;
- int h2;
- int x3; // rect 3: the union of rects 1 and 2
- int y3;
- int w3;
- int h3;
- } tests[] = {
- { 0, 0, 0, 0, // zeros
- 0, 0, 0, 0,
- 0, 0, 0, 0 },
- { 0, 0, 4, 4, // equal
- 0, 0, 4, 4,
- 0, 0, 4, 4 },
- { 0, 0, 4, 4, // neighboring
- 4, 4, 4, 4,
- 0, 0, 0, 0 },
- { 0, 0, 4, 4, // overlapping corners
- 2, 2, 4, 4,
- 2, 2, 2, 2 },
- { 0, 0, 4, 4, // T junction
- 3, 1, 4, 2,
- 3, 1, 1, 2 },
- { 3, 0, 2, 2, // gap
- 0, 0, 2, 2,
- 0, 0, 0, 0 }
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
- Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
- Rect ir = IntersectRects(r1, r2);
- EXPECT_EQ(r3.x(), ir.x());
- EXPECT_EQ(r3.y(), ir.y());
- EXPECT_EQ(r3.width(), ir.width());
- EXPECT_EQ(r3.height(), ir.height());
- }
-}
-
-TEST(RectTest, Union) {
- static const struct Test {
- int x1; // rect 1
- int y1;
- int w1;
- int h1;
- int x2; // rect 2
- int y2;
- int w2;
- int h2;
- int x3; // rect 3: the union of rects 1 and 2
- int y3;
- int w3;
- int h3;
- } tests[] = {
- { 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0 },
- { 0, 0, 4, 4,
- 0, 0, 4, 4,
- 0, 0, 4, 4 },
- { 0, 0, 4, 4,
- 4, 4, 4, 4,
- 0, 0, 8, 8 },
- { 0, 0, 4, 4,
- 0, 5, 4, 4,
- 0, 0, 4, 9 },
- { 0, 0, 2, 2,
- 3, 3, 2, 2,
- 0, 0, 5, 5 },
- { 3, 3, 2, 2, // reverse r1 and r2 from previous test
- 0, 0, 2, 2,
- 0, 0, 5, 5 },
- { 0, 0, 0, 0, // union with empty rect
- 2, 2, 2, 2,
- 2, 2, 2, 2 }
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
- Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
- Rect u = UnionRects(r1, r2);
- EXPECT_EQ(r3.x(), u.x());
- EXPECT_EQ(r3.y(), u.y());
- EXPECT_EQ(r3.width(), u.width());
- EXPECT_EQ(r3.height(), u.height());
- }
-}
-
-TEST(RectTest, Equals) {
- ASSERT_TRUE(Rect(0, 0, 0, 0) == Rect(0, 0, 0, 0));
- ASSERT_TRUE(Rect(1, 2, 3, 4) == Rect(1, 2, 3, 4));
- ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 0, 0, 1));
- ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 0, 1, 0));
- ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(0, 1, 0, 0));
- ASSERT_FALSE(Rect(0, 0, 0, 0) == Rect(1, 0, 0, 0));
-}
-
-TEST(RectTest, AdjustToFit) {
- static const struct Test {
- int x1; // source
- int y1;
- int w1;
- int h1;
- int x2; // target
- int y2;
- int w2;
- int h2;
- int x3; // rect 3: results of invoking AdjustToFit
- int y3;
- int w3;
- int h3;
- } tests[] = {
- { 0, 0, 2, 2,
- 0, 0, 2, 2,
- 0, 0, 2, 2 },
- { 2, 2, 3, 3,
- 0, 0, 4, 4,
- 1, 1, 3, 3 },
- { -1, -1, 5, 5,
- 0, 0, 4, 4,
- 0, 0, 4, 4 },
- { 2, 2, 4, 4,
- 0, 0, 3, 3,
- 0, 0, 3, 3 },
- { 2, 2, 1, 1,
- 0, 0, 3, 3,
- 2, 2, 1, 1 }
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
- Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
- Rect u = r1;
- u.AdjustToFit(r2);
- EXPECT_EQ(r3.x(), u.x());
- EXPECT_EQ(r3.y(), u.y());
- EXPECT_EQ(r3.width(), u.width());
- EXPECT_EQ(r3.height(), u.height());
- }
-}
-
-TEST(RectTest, Subtract) {
- Rect result;
-
- // Matching
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(10, 10, 20, 20));
- EXPECT_EQ(Rect(0, 0, 0, 0).ToString(), result.ToString());
-
- // Contains
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(5, 5, 30, 30));
- EXPECT_EQ(Rect(0, 0, 0, 0).ToString(), result.ToString());
-
- // No intersection
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(30, 30, 30, 30));
- EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
-
- // Not a complete intersection in either direction
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(15, 15, 20, 20));
- EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
-
- // Complete intersection in the x-direction, top edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(10, 15, 20, 20));
- EXPECT_EQ(Rect(10, 10, 20, 5).ToString(), result.ToString());
-
- // Complete intersection in the x-direction, top edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(5, 15, 30, 20));
- EXPECT_EQ(Rect(10, 10, 20, 5).ToString(), result.ToString());
-
- // Complete intersection in the x-direction, bottom edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(5, 5, 30, 20));
- EXPECT_EQ(Rect(10, 25, 20, 5).ToString(), result.ToString());
-
- // Complete intersection in the x-direction, none of the edges is fully
- // covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(5, 15, 30, 1));
- EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
-
- // Complete intersection in the y-direction, left edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(10, 10, 10, 30));
- EXPECT_EQ(Rect(20, 10, 10, 20).ToString(), result.ToString());
-
- // Complete intersection in the y-direction, left edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(5, 5, 20, 30));
- EXPECT_EQ(Rect(25, 10, 5, 20).ToString(), result.ToString());
-
- // Complete intersection in the y-direction, right edge is fully covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(20, 5, 20, 30));
- EXPECT_EQ(Rect(10, 10, 10, 20).ToString(), result.ToString());
-
- // Complete intersection in the y-direction, none of the edges is fully
- // covered.
- result = Rect(10, 10, 20, 20);
- result.Subtract(Rect(15, 5, 1, 30));
- EXPECT_EQ(Rect(10, 10, 20, 20).ToString(), result.ToString());
-}
-
-TEST(RectTest, IsEmpty) {
- EXPECT_TRUE(Rect(0, 0, 0, 0).IsEmpty());
- EXPECT_TRUE(Rect(0, 0, 0, 0).size().IsEmpty());
- EXPECT_TRUE(Rect(0, 0, 10, 0).IsEmpty());
- EXPECT_TRUE(Rect(0, 0, 10, 0).size().IsEmpty());
- EXPECT_TRUE(Rect(0, 0, 0, 10).IsEmpty());
- EXPECT_TRUE(Rect(0, 0, 0, 10).size().IsEmpty());
- EXPECT_FALSE(Rect(0, 0, 10, 10).IsEmpty());
- EXPECT_FALSE(Rect(0, 0, 10, 10).size().IsEmpty());
-}
-
-TEST(RectTest, SplitVertically) {
- Rect left_half, right_half;
-
- // Splitting when origin is (0, 0).
- Rect(0, 0, 20, 20).SplitVertically(&left_half, &right_half);
- EXPECT_TRUE(left_half == Rect(0, 0, 10, 20));
- EXPECT_TRUE(right_half == Rect(10, 0, 10, 20));
-
- // Splitting when origin is arbitrary.
- Rect(10, 10, 20, 10).SplitVertically(&left_half, &right_half);
- EXPECT_TRUE(left_half == Rect(10, 10, 10, 10));
- EXPECT_TRUE(right_half == Rect(20, 10, 10, 10));
-
- // Splitting a rectangle of zero width.
- Rect(10, 10, 0, 10).SplitVertically(&left_half, &right_half);
- EXPECT_TRUE(left_half == Rect(10, 10, 0, 10));
- EXPECT_TRUE(right_half == Rect(10, 10, 0, 10));
-
- // Splitting a rectangle of odd width.
- Rect(10, 10, 5, 10).SplitVertically(&left_half, &right_half);
- EXPECT_TRUE(left_half == Rect(10, 10, 2, 10));
- EXPECT_TRUE(right_half == Rect(12, 10, 3, 10));
-}
-
-TEST(RectTest, CenterPoint) {
- Point center;
-
- // When origin is (0, 0).
- center = Rect(0, 0, 20, 20).CenterPoint();
- EXPECT_TRUE(center == Point(10, 10));
-
- // When origin is even.
- center = Rect(10, 10, 20, 20).CenterPoint();
- EXPECT_TRUE(center == Point(20, 20));
-
- // When origin is odd.
- center = Rect(11, 11, 20, 20).CenterPoint();
- EXPECT_TRUE(center == Point(21, 21));
-
- // When 0 width or height.
- center = Rect(10, 10, 0, 20).CenterPoint();
- EXPECT_TRUE(center == Point(10, 20));
- center = Rect(10, 10, 20, 0).CenterPoint();
- EXPECT_TRUE(center == Point(20, 10));
-
- // When an odd size.
- center = Rect(10, 10, 21, 21).CenterPoint();
- EXPECT_TRUE(center == Point(20, 20));
-
- // When an odd size and position.
- center = Rect(11, 11, 21, 21).CenterPoint();
- EXPECT_TRUE(center == Point(21, 21));
-}
-
-TEST(RectTest, CenterPointF) {
- PointF center;
-
- // When origin is (0, 0).
- center = RectF(0, 0, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(10, 10));
-
- // When origin is even.
- center = RectF(10, 10, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(20, 20));
-
- // When origin is odd.
- center = RectF(11, 11, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(21, 21));
-
- // When 0 width or height.
- center = RectF(10, 10, 0, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(10, 20));
- center = RectF(10, 10, 20, 0).CenterPoint();
- EXPECT_TRUE(center == PointF(20, 10));
-
- // When an odd size.
- center = RectF(10, 10, 21, 21).CenterPoint();
- EXPECT_TRUE(center == PointF(20.5f, 20.5f));
-
- // When an odd size and position.
- center = RectF(11, 11, 21, 21).CenterPoint();
- EXPECT_TRUE(center == PointF(21.5f, 21.5f));
-}
-
-TEST(RectTest, SharesEdgeWith) {
- Rect r(2, 3, 4, 5);
-
- // Must be non-overlapping
- EXPECT_FALSE(r.SharesEdgeWith(r));
-
- Rect just_above(2, 1, 4, 2);
- Rect just_below(2, 8, 4, 2);
- Rect just_left(0, 3, 2, 5);
- Rect just_right(6, 3, 2, 5);
-
- EXPECT_TRUE(r.SharesEdgeWith(just_above));
- EXPECT_TRUE(r.SharesEdgeWith(just_below));
- EXPECT_TRUE(r.SharesEdgeWith(just_left));
- EXPECT_TRUE(r.SharesEdgeWith(just_right));
-
- // Wrong placement
- Rect same_height_no_edge(0, 0, 1, 5);
- Rect same_width_no_edge(0, 0, 4, 1);
-
- EXPECT_FALSE(r.SharesEdgeWith(same_height_no_edge));
- EXPECT_FALSE(r.SharesEdgeWith(same_width_no_edge));
-
- Rect just_above_no_edge(2, 1, 5, 2); // too wide
- Rect just_below_no_edge(2, 8, 3, 2); // too narrow
- Rect just_left_no_edge(0, 3, 2, 6); // too tall
- Rect just_right_no_edge(6, 3, 2, 4); // too short
-
- EXPECT_FALSE(r.SharesEdgeWith(just_above_no_edge));
- EXPECT_FALSE(r.SharesEdgeWith(just_below_no_edge));
- EXPECT_FALSE(r.SharesEdgeWith(just_left_no_edge));
- EXPECT_FALSE(r.SharesEdgeWith(just_right_no_edge));
-}
-
-TEST(RectTest, SkiaRectConversions) {
- Rect isrc(10, 20, 30, 40);
- RectF fsrc(10.5f, 20.5f, 30.5f, 40.5f);
-
- SkIRect skirect = RectToSkIRect(isrc);
- EXPECT_EQ(isrc.ToString(), SkIRectToRect(skirect).ToString());
-
- SkRect skrect = RectToSkRect(isrc);
- EXPECT_EQ(gfx::RectF(isrc).ToString(), SkRectToRectF(skrect).ToString());
-
- skrect = RectFToSkRect(fsrc);
- EXPECT_EQ(fsrc.ToString(), SkRectToRectF(skrect).ToString());
-}
-
-// Similar to EXPECT_FLOAT_EQ, but lets NaN equal NaN
-#define EXPECT_FLOAT_AND_NAN_EQ(a, b) \
- { if (a == a || b == b) { EXPECT_FLOAT_EQ(a, b); } }
-
-TEST(RectTest, ScaleRect) {
- static const struct Test {
- int x1; // source
- int y1;
- int w1;
- int h1;
- float scale;
- float x2; // target
- float y2;
- float w2;
- float h2;
- } tests[] = {
- { 3, 3, 3, 3,
- 1.5f,
- 4.5f, 4.5f, 4.5f, 4.5f },
- { 3, 3, 3, 3,
- 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f },
- { 3, 3, 3, 3,
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN() },
- { 3, 3, 3, 3,
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max() }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- RectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
-
- RectF scaled = ScaleRect(r1, tests[i].scale);
- EXPECT_FLOAT_AND_NAN_EQ(r2.x(), scaled.x());
- EXPECT_FLOAT_AND_NAN_EQ(r2.y(), scaled.y());
- EXPECT_FLOAT_AND_NAN_EQ(r2.width(), scaled.width());
- EXPECT_FLOAT_AND_NAN_EQ(r2.height(), scaled.height());
- }
-}
-
-TEST(RectTest, ToEnclosedRect) {
- static const struct Test {
- float x1; // source
- float y1;
- float w1;
- float h1;
- int x2; // target
- int y2;
- int w2;
- int h2;
- } tests [] = {
- { 0.0f, 0.0f, 0.0f, 0.0f,
- 0, 0, 0, 0 },
- { -1.5f, -1.5f, 3.0f, 3.0f,
- -1, -1, 2, 2 },
- { -1.5f, -1.5f, 3.5f, 3.5f,
- -1, -1, 3, 3 },
- { std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- 2.0f, 2.0f,
- std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max(),
- 0, 0 },
- { 0.0f, 0.0f,
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- 0, 0,
- std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max() },
- { 20000.5f, 20000.5f, 0.5f, 0.5f,
- 20001, 20001, 0, 0 },
- { std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- 0, 0, 0, 0 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
-
- Rect enclosed = ToEnclosedRect(r1);
- EXPECT_FLOAT_AND_NAN_EQ(r2.x(), enclosed.x());
- EXPECT_FLOAT_AND_NAN_EQ(r2.y(), enclosed.y());
- EXPECT_FLOAT_AND_NAN_EQ(r2.width(), enclosed.width());
- EXPECT_FLOAT_AND_NAN_EQ(r2.height(), enclosed.height());
- }
-}
-
-TEST(RectTest, ToEnclosingRect) {
- static const struct Test {
- float x1; // source
- float y1;
- float w1;
- float h1;
- int x2; // target
- int y2;
- int w2;
- int h2;
- } tests [] = {
- { 0.0f, 0.0f, 0.0f, 0.0f,
- 0, 0, 0, 0 },
- { 5.5f, 5.5f, 0.0f, 0.0f,
- 5, 5, 0, 0 },
- { -1.5f, -1.5f, 3.0f, 3.0f,
- -2, -2, 4, 4 },
- { -1.5f, -1.5f, 3.5f, 3.5f,
- -2, -2, 4, 4 },
- { std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- 2.0f, 2.0f,
- std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max(),
- 0, 0 },
- { 0.0f, 0.0f,
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- 0, 0,
- std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max() },
- { 20000.5f, 20000.5f, 0.5f, 0.5f,
- 20000, 20000, 1, 1 },
- { std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- 0, 0, 0, 0 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
-
- Rect enclosed = ToEnclosingRect(r1);
- EXPECT_FLOAT_AND_NAN_EQ(r2.x(), enclosed.x());
- EXPECT_FLOAT_AND_NAN_EQ(r2.y(), enclosed.y());
- EXPECT_FLOAT_AND_NAN_EQ(r2.width(), enclosed.width());
- EXPECT_FLOAT_AND_NAN_EQ(r2.height(), enclosed.height());
- }
-}
-
-TEST(RectTest, ToNearestRect) {
- Rect rect;
- EXPECT_EQ(rect.ToString(), ToNearestRect(RectF(rect)).ToString());
-
- rect = Rect(-1, -1, 3, 3);
- EXPECT_EQ(rect.ToString(), ToNearestRect(RectF(rect)).ToString());
-
- RectF rectf(-1.00001f, -0.999999f, 3.0000001f, 2.999999f);
- EXPECT_EQ(rect.ToString(), ToNearestRect(rectf).ToString());
-}
-
-TEST(RectTest, ToFlooredRect) {
- static const struct Test {
- float x1; // source
- float y1;
- float w1;
- float h1;
- int x2; // target
- int y2;
- int w2;
- int h2;
- } tests [] = {
- { 0.0f, 0.0f, 0.0f, 0.0f,
- 0, 0, 0, 0 },
- { -1.5f, -1.5f, 3.0f, 3.0f,
- -2, -2, 3, 3 },
- { -1.5f, -1.5f, 3.5f, 3.5f,
- -2, -2, 3, 3 },
- { 20000.5f, 20000.5f, 0.5f, 0.5f,
- 20000, 20000, 0, 0 },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
-
- Rect floored = ToFlooredRectDeprecated(r1);
- EXPECT_FLOAT_EQ(r2.x(), floored.x());
- EXPECT_FLOAT_EQ(r2.y(), floored.y());
- EXPECT_FLOAT_EQ(r2.width(), floored.width());
- EXPECT_FLOAT_EQ(r2.height(), floored.height());
- }
-}
-
-TEST(RectTest, ScaleToEnclosedRect) {
- static const struct Test {
- Rect input_rect;
- float input_scale;
- Rect expected_rect;
- } tests[] = {
- {
- Rect(),
- 5.f,
- Rect(),
- }, {
- Rect(1, 1, 1, 1),
- 5.f,
- Rect(5, 5, 5, 5),
- }, {
- Rect(-1, -1, 0, 0),
- 5.f,
- Rect(-5, -5, 0, 0),
- }, {
- Rect(1, -1, 0, 1),
- 5.f,
- Rect(5, -5, 0, 5),
- }, {
- Rect(-1, 1, 1, 0),
- 5.f,
- Rect(-5, 5, 5, 0),
- }, {
- Rect(1, 2, 3, 4),
- 1.5f,
- Rect(2, 3, 4, 6),
- }, {
- Rect(-1, -2, 0, 0),
- 1.5f,
- Rect(-1, -3, 0, 0),
- }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect result = ScaleToEnclosedRect(tests[i].input_rect,
- tests[i].input_scale);
- EXPECT_EQ(tests[i].expected_rect.ToString(), result.ToString());
- }
-}
-
-TEST(RectTest, ScaleToEnclosingRect) {
- static const struct Test {
- Rect input_rect;
- float input_scale;
- Rect expected_rect;
- } tests[] = {
- {
- Rect(),
- 5.f,
- Rect(),
- }, {
- Rect(1, 1, 1, 1),
- 5.f,
- Rect(5, 5, 5, 5),
- }, {
- Rect(-1, -1, 0, 0),
- 5.f,
- Rect(-5, -5, 0, 0),
- }, {
- Rect(1, -1, 0, 1),
- 5.f,
- Rect(5, -5, 0, 5),
- }, {
- Rect(-1, 1, 1, 0),
- 5.f,
- Rect(-5, 5, 5, 0),
- }, {
- Rect(1, 2, 3, 4),
- 1.5f,
- Rect(1, 3, 5, 6),
- }, {
- Rect(-1, -2, 0, 0),
- 1.5f,
- Rect(-2, -3, 0, 0),
- }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Rect result = ScaleToEnclosingRect(tests[i].input_rect,
- tests[i].input_scale);
- EXPECT_EQ(tests[i].expected_rect.ToString(), result.ToString());
- }
-}
-
-#if defined(OS_WIN)
-TEST(RectTest, ConstructAndAssign) {
- const RECT rect_1 = { 0, 0, 10, 10 };
- const RECT rect_2 = { 0, 0, -10, -10 };
- Rect test1(rect_1);
- Rect test2(rect_2);
-}
-#endif
-
-TEST(RectTest, ToRectF) {
- // Check that implicit conversion from integer to float compiles.
- Rect a(10, 20, 30, 40);
- RectF b(10, 20, 30, 40);
-
- RectF intersect = IntersectRects(a, b);
- EXPECT_EQ(b.ToString(), intersect.ToString());
-
- EXPECT_EQ(a, b);
- EXPECT_EQ(b, a);
-}
-
-TEST(RectTest, BoundingRect) {
- struct {
- Point a;
- Point b;
- Rect expected;
- } int_tests[] = {
- // If point B dominates A, then A should be the origin.
- { Point(4, 6), Point(4, 6), Rect(4, 6, 0, 0) },
- { Point(4, 6), Point(8, 6), Rect(4, 6, 4, 0) },
- { Point(4, 6), Point(4, 9), Rect(4, 6, 0, 3) },
- { Point(4, 6), Point(8, 9), Rect(4, 6, 4, 3) },
- // If point A dominates B, then B should be the origin.
- { Point(4, 6), Point(4, 6), Rect(4, 6, 0, 0) },
- { Point(8, 6), Point(4, 6), Rect(4, 6, 4, 0) },
- { Point(4, 9), Point(4, 6), Rect(4, 6, 0, 3) },
- { Point(8, 9), Point(4, 6), Rect(4, 6, 4, 3) },
- // If neither point dominates, then the origin is a combination of the two.
- { Point(4, 6), Point(6, 4), Rect(4, 4, 2, 2) },
- { Point(-4, -6), Point(-6, -4), Rect(-6, -6, 2, 2) },
- { Point(-4, 6), Point(6, -4), Rect(-4, -4, 10, 10) },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i) {
- Rect actual = BoundingRect(int_tests[i].a, int_tests[i].b);
- EXPECT_EQ(int_tests[i].expected.ToString(), actual.ToString());
- }
-
- struct {
- PointF a;
- PointF b;
- RectF expected;
- } float_tests[] = {
- // If point B dominates A, then A should be the origin.
- { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 0) },
- { PointF(4.2f, 6.8f), PointF(8.5f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 0) },
- { PointF(4.2f, 6.8f), PointF(4.2f, 9.3f),
- RectF(4.2f, 6.8f, 0, 2.5f) },
- { PointF(4.2f, 6.8f), PointF(8.5f, 9.3f),
- RectF(4.2f, 6.8f, 4.3f, 2.5f) },
- // If point A dominates B, then B should be the origin.
- { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 0) },
- { PointF(8.5f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 0) },
- { PointF(4.2f, 9.3f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 2.5f) },
- { PointF(8.5f, 9.3f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 2.5f) },
- // If neither point dominates, then the origin is a combination of the two.
- { PointF(4.2f, 6.8f), PointF(6.8f, 4.2f),
- RectF(4.2f, 4.2f, 2.6f, 2.6f) },
- { PointF(-4.2f, -6.8f), PointF(-6.8f, -4.2f),
- RectF(-6.8f, -6.8f, 2.6f, 2.6f) },
- { PointF(-4.2f, 6.8f), PointF(6.8f, -4.2f),
- RectF(-4.2f, -4.2f, 11.0f, 11.0f) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i) {
- RectF actual = BoundingRect(float_tests[i].a, float_tests[i].b);
- EXPECT_EQ(float_tests[i].expected.ToString(), actual.ToString());
- }
-}
-
-TEST(RectTest, IsExpressibleAsRect) {
- EXPECT_TRUE(RectF().IsExpressibleAsRect());
-
- float min = std::numeric_limits<int>::min();
- float max = std::numeric_limits<int>::max();
- float infinity = std::numeric_limits<float>::infinity();
-
- EXPECT_TRUE(RectF(
- min + 200, min + 200, max - 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min - 200, min + 200, max + 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200 , min - 200, max + 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200, min + 200, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200, min + 200, max - 200, max + 200).IsExpressibleAsRect());
-
- EXPECT_TRUE(RectF(0, 0, max - 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(200, 0, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 200, max - 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, max - 200, max + 200).IsExpressibleAsRect());
-
- EXPECT_FALSE(RectF(infinity, 0, 1, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, infinity, 1, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, infinity, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, 1, infinity).IsExpressibleAsRect());
-}
-
-TEST(RectTest, Offset) {
- Rect i(1, 2, 3, 4);
-
- EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), (i + Vector2d(1, -1)).ToString());
- EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), (Vector2d(1, -1) + i).ToString());
- i += Vector2d(1, -1);
- EXPECT_EQ(Rect(2, 1, 3, 4).ToString(), i.ToString());
- EXPECT_EQ(Rect(1, 2, 3, 4).ToString(), (i - Vector2d(1, -1)).ToString());
- i -= Vector2d(1, -1);
- EXPECT_EQ(Rect(1, 2, 3, 4).ToString(), i.ToString());
-
- RectF f(1.1f, 2.2f, 3.3f, 4.4f);
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(),
- (f + Vector2dF(1.1f, -1.1f)).ToString());
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(),
- (Vector2dF(1.1f, -1.1f) + f).ToString());
- f += Vector2dF(1.1f, -1.1f);
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f).ToString(), f.ToString());
- EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f).ToString(),
- (f - Vector2dF(1.1f, -1.1f)).ToString());
- f -= Vector2dF(1.1f, -1.1f);
- EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f).ToString(), f.ToString());
-}
-
-TEST(RectTest, Corners) {
- Rect i(1, 2, 3, 4);
- RectF f(1.1f, 2.1f, 3.1f, 4.1f);
-
- EXPECT_EQ(Point(1, 2).ToString(), i.origin().ToString());
- EXPECT_EQ(Point(4, 2).ToString(), i.top_right().ToString());
- EXPECT_EQ(Point(1, 6).ToString(), i.bottom_left().ToString());
- EXPECT_EQ(Point(4, 6).ToString(), i.bottom_right().ToString());
-
- EXPECT_EQ(PointF(1.1f, 2.1f).ToString(), f.origin().ToString());
- EXPECT_EQ(PointF(4.2f, 2.1f).ToString(), f.top_right().ToString());
- EXPECT_EQ(PointF(1.1f, 6.2f).ToString(), f.bottom_left().ToString());
- EXPECT_EQ(PointF(4.2f, 6.2f).ToString(), f.bottom_right().ToString());
-}
-
-TEST(RectTest, ManhattanDistanceToPoint) {
- Rect i(1, 2, 3, 4);
- EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(1, 2)));
- EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(4, 6)));
- EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(2, 4)));
- EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(0, 0)));
- EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(2, 0)));
- EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 0)));
- EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(5, 4)));
- EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 8)));
- EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(3, 8)));
- EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(0, 7)));
- EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(0, 3)));
-
- RectF f(1.1f, 2.1f, 3.1f, 4.1f);
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(1.1f, 2.1f)));
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(4.2f, 6.f)));
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(2.f, 4.f)));
- EXPECT_FLOAT_EQ(3.2f, f.ManhattanDistanceToPoint(PointF(0.f, 0.f)));
- EXPECT_FLOAT_EQ(2.1f, f.ManhattanDistanceToPoint(PointF(2.f, 0.f)));
- EXPECT_FLOAT_EQ(2.9f, f.ManhattanDistanceToPoint(PointF(5.f, 0.f)));
- EXPECT_FLOAT_EQ(.8f, f.ManhattanDistanceToPoint(PointF(5.f, 4.f)));
- EXPECT_FLOAT_EQ(2.6f, f.ManhattanDistanceToPoint(PointF(5.f, 8.f)));
- EXPECT_FLOAT_EQ(1.8f, f.ManhattanDistanceToPoint(PointF(3.f, 8.f)));
- EXPECT_FLOAT_EQ(1.9f, f.ManhattanDistanceToPoint(PointF(0.f, 7.f)));
- EXPECT_FLOAT_EQ(1.1f, f.ManhattanDistanceToPoint(PointF(0.f, 3.f)));
-}
-
-TEST(RectTest, ManhattanInternalDistance) {
- Rect i(0, 0, 400, 400);
- EXPECT_EQ(0, i.ManhattanInternalDistance(gfx::Rect(-1, 0, 2, 1)));
- EXPECT_EQ(1, i.ManhattanInternalDistance(gfx::Rect(400, 0, 1, 400)));
- EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-100, -100, 100, 100)));
- EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-101, 100, 100, 100)));
- EXPECT_EQ(4, i.ManhattanInternalDistance(gfx::Rect(-101, -101, 100, 100)));
- EXPECT_EQ(435, i.ManhattanInternalDistance(gfx::Rect(630, 603, 100, 100)));
-
- RectF f(0.0f, 0.0f, 400.0f, 400.0f);
- static const float kEpsilon = std::numeric_limits<float>::epsilon();
-
- EXPECT_FLOAT_EQ(
- 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 2.0f, 1.0f)));
- EXPECT_FLOAT_EQ(
- kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(400.0f, 0.0f, 1.0f, 400.0f)));
- EXPECT_FLOAT_EQ(2.0f * kEpsilon,
- f.ManhattanInternalDistance(
- gfx::RectF(-100.0f, -100.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(
- 1.0f + kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-101.0f, 100.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(2.0f + 2.0f * kEpsilon,
- f.ManhattanInternalDistance(
- gfx::RectF(-101.0f, -101.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(
- 433.0f + 2.0f * kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(630.0f, 603.0f, 100.0f, 100.0f)));
-
- EXPECT_FLOAT_EQ(
- 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 1.1f, 1.0f)));
- EXPECT_FLOAT_EQ(
- 0.1f + kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.4f, 1.0f)));
- EXPECT_FLOAT_EQ(
- kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.5f, 1.0f)));
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index e8e3436f11c..c7871ee7a05 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -7,18 +7,24 @@
#include <algorithm>
#include <climits>
+#include "base/command_line.h"
#include "base/i18n/break_iterator.h"
#include "base/logging.h"
#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/utf16.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
+#include "ui/gfx/render_text_harfbuzz.h"
+#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
#include "ui/gfx/text_constants.h"
#include "ui/gfx/text_elider.h"
+#include "ui/gfx/text_utils.h"
#include "ui/gfx/utf16_indexing.h"
namespace gfx {
@@ -72,20 +78,20 @@ int DetermineBaselineCenteringText(const Rect& display_rect,
return baseline + std::max(min_shift, std::min(max_shift, baseline_shift));
}
-// Converts |gfx::Font::FontStyle| flags to |SkTypeface::Style| flags.
+// Converts |Font::FontStyle| flags to |SkTypeface::Style| flags.
SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) {
int skia_style = SkTypeface::kNormal;
- skia_style |= (font_style & gfx::Font::BOLD) ? SkTypeface::kBold : 0;
- skia_style |= (font_style & gfx::Font::ITALIC) ? SkTypeface::kItalic : 0;
+ skia_style |= (font_style & Font::BOLD) ? SkTypeface::kBold : 0;
+ skia_style |= (font_style & Font::ITALIC) ? SkTypeface::kItalic : 0;
return static_cast<SkTypeface::Style>(skia_style);
}
// Given |font| and |display_width|, returns the width of the fade gradient.
-int CalculateFadeGradientWidth(const Font& font, int display_width) {
+int CalculateFadeGradientWidth(const FontList& font_list, int display_width) {
// Fade in/out about 2.5 characters of the beginning/end of the string.
// The .5 here is helpful if one of the characters is a space.
// Use a quarter of the display width if the display width is very short.
- const int average_character_width = font.GetAverageCharacterWidth();
+ const int average_character_width = font_list.GetExpectedTextWidth(1);
const double gradient_width = std::min(average_character_width * 2.5,
display_width / 4.0);
DCHECK_GE(gradient_width, 0.0);
@@ -158,7 +164,8 @@ namespace internal {
const SkScalar kUnderlineMetricsNotSet = -1.0f;
SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
- : canvas_skia_(canvas->sk_canvas()),
+ : canvas_(canvas),
+ canvas_skia_(canvas->sk_canvas()),
started_drawing_(false),
underline_thickness_(kUnderlineMetricsNotSet),
underline_position_(0.0f) {
@@ -168,6 +175,7 @@ SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
paint_.setAntiAlias(true);
paint_.setSubpixelText(true);
paint_.setLCDRenderText(true);
+ paint_.setHinting(SkPaint::kNormal_Hinting);
bounds_.setEmpty();
}
@@ -190,11 +198,16 @@ void SkiaTextRenderer::SetDrawLooper(SkDrawLooper* draw_looper) {
paint_.setLooper(draw_looper);
}
-void SkiaTextRenderer::SetFontSmoothingSettings(bool enable_smoothing,
- bool enable_lcd_text) {
- paint_.setAntiAlias(enable_smoothing);
- paint_.setSubpixelText(enable_smoothing);
- paint_.setLCDRenderText(enable_lcd_text);
+void SkiaTextRenderer::SetFontSmoothingSettings(bool antialiasing,
+ bool subpixel_rendering,
+ bool subpixel_positioning) {
+ paint_.setAntiAlias(antialiasing);
+ paint_.setLCDRenderText(subpixel_rendering);
+ paint_.setSubpixelText(subpixel_positioning);
+}
+
+void SkiaTextRenderer::SetFontHinting(SkPaint::Hinting hinting) {
+ paint_.setHinting(hinting);
}
void SkiaTextRenderer::SetTypeface(SkTypeface* typeface) {
@@ -209,17 +222,14 @@ void SkiaTextRenderer::SetFontFamilyWithStyle(const std::string& family,
int style) {
DCHECK(!family.empty());
- SkTypeface::Style skia_style = ConvertFontStyleToSkiaTypefaceStyle(style);
- skia::RefPtr<SkTypeface> typeface =
- skia::AdoptRef(SkTypeface::CreateFromName(family.c_str(), skia_style));
+ skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(family.c_str(), style);
if (typeface) {
// |paint_| adds its own ref. So don't |release()| it from the ref ptr here.
SetTypeface(typeface.get());
// Enable fake bold text if bold style is needed but new typeface does not
// have it.
- paint_.setFakeBoldText((skia_style & SkTypeface::kBold) &&
- !typeface->isBold());
+ paint_.setFakeBoldText((style & Font::BOLD) && !typeface->isBold());
}
}
@@ -271,8 +281,20 @@ void SkiaTextRenderer::DrawDecorations(int x, int y, int width, bool underline,
DrawUnderline(x, y, width);
if (strike)
DrawStrike(x, y, width);
- if (diagonal_strike)
- DrawDiagonalStrike(x, y, width);
+ if (diagonal_strike) {
+ if (!diagonal_)
+ diagonal_.reset(new DiagonalStrike(canvas_, Point(x, y), paint_));
+ diagonal_->AddPiece(width, paint_.getColor());
+ } else if (diagonal_) {
+ EndDiagonalStrike();
+ }
+}
+
+void SkiaTextRenderer::EndDiagonalStrike() {
+ if (diagonal_) {
+ diagonal_->Draw();
+ diagonal_.reset();
+ }
}
void SkiaTextRenderer::DrawUnderline(int x, int y, int width) {
@@ -294,15 +316,56 @@ void SkiaTextRenderer::DrawStrike(int x, int y, int width) const {
canvas_skia_->drawRect(r, paint_);
}
-void SkiaTextRenderer::DrawDiagonalStrike(int x, int y, int width) const {
+SkiaTextRenderer::DiagonalStrike::DiagonalStrike(Canvas* canvas,
+ Point start,
+ const SkPaint& paint)
+ : canvas_(canvas),
+ matrix_(canvas->sk_canvas()->getTotalMatrix()),
+ start_(start),
+ paint_(paint),
+ total_length_(0) {
+}
+
+SkiaTextRenderer::DiagonalStrike::~DiagonalStrike() {
+}
+
+void SkiaTextRenderer::DiagonalStrike::AddPiece(int length, SkColor color) {
+ pieces_.push_back(Piece(length, color));
+ total_length_ += length;
+}
+
+void SkiaTextRenderer::DiagonalStrike::Draw() {
const SkScalar text_size = paint_.getTextSize();
const SkScalar offset = SkScalarMul(text_size, kDiagonalStrikeMarginOffset);
+ const int thickness =
+ SkScalarCeilToInt(SkScalarMul(text_size, kLineThickness) * 2);
+ const int height = SkScalarCeilToInt(text_size - offset);
+ const Point end = start_ + Vector2d(total_length_, -height);
+ const int clip_height = height + 2 * thickness;
+
+ paint_.setAntiAlias(true);
+ paint_.setStrokeWidth(thickness);
+
+ ScopedCanvas scoped_canvas(canvas_);
+
+ SkCanvas* sk_canvas = canvas_->sk_canvas();
+ sk_canvas->setMatrix(matrix_);
+
+ const bool clipped = pieces_.size() > 1;
+ int x = start_.x();
+ for (size_t i = 0; i < pieces_.size(); ++i) {
+ paint_.setColor(pieces_[i].second);
+
+ if (clipped) {
+ sk_canvas->clipRect(RectToSkRect(
+ Rect(x, end.y() - thickness, pieces_[i].first, clip_height)),
+ SkRegion::kReplace_Op);
+ }
+
+ canvas_->DrawLine(start_, end, paint_);
- SkPaint paint(paint_);
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setStrokeWidth(SkScalarMul(text_size, kLineThickness) * 2);
- canvas_skia_->drawLine(x, y, x + width, y - text_size + offset, paint);
+ x += pieces_[i].first;
+ }
}
StyleIterator::StyleIterator(const BreakList<SkColor>& colors,
@@ -337,11 +400,30 @@ Line::Line() : preceding_heights(0), baseline(0) {}
Line::~Line() {}
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
+ int style) {
+ SkTypeface::Style skia_style = ConvertFontStyleToSkiaTypefaceStyle(style);
+ return skia::AdoptRef(SkTypeface::CreateFromName(family.c_str(), skia_style));
+}
+
} // namespace internal
RenderText::~RenderText() {
}
+RenderText* RenderText::CreateInstance() {
+#if defined(OS_MACOSX) && defined(TOOLKIT_VIEWS)
+ // Use the more complete HarfBuzz implementation for Views controls on Mac.
+ return new RenderTextHarfBuzz;
+#else
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHarfBuzzRenderText)) {
+ return new RenderTextHarfBuzz;
+ }
+ return CreateNativeInstance();
+#endif
+}
+
void RenderText::SetText(const base::string16& text) {
DCHECK(!composition_range_.IsValid());
if (text_ == text)
@@ -365,7 +447,6 @@ void RenderText::SetText(const base::string16& text) {
obscured_reveal_index_ = -1;
UpdateLayoutText();
- ResetLayout();
}
void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) {
@@ -383,18 +464,6 @@ void RenderText::SetFontList(const FontList& font_list) {
ResetLayout();
}
-void RenderText::SetFont(const Font& font) {
- SetFontList(FontList(font));
-}
-
-void RenderText::SetFontSize(int size) {
- SetFontList(font_list_.DeriveFontListWithSize(size));
-}
-
-const Font& RenderText::GetPrimaryFont() const {
- return font_list_.GetPrimaryFont();
-}
-
void RenderText::SetCursorEnabled(bool cursor_enabled) {
cursor_enabled_ = cursor_enabled;
cached_bounds_and_offset_valid_ = false;
@@ -411,7 +480,6 @@ void RenderText::SetObscured(bool obscured) {
obscured_reveal_index_ = -1;
cached_bounds_and_offset_valid_ = false;
UpdateLayoutText();
- ResetLayout();
}
}
@@ -422,7 +490,6 @@ void RenderText::SetObscuredRevealIndex(int index) {
obscured_reveal_index_ = index;
cached_bounds_and_offset_valid_ = false;
UpdateLayoutText();
- ResetLayout();
}
void RenderText::SetMultiline(bool multiline) {
@@ -433,11 +500,23 @@ void RenderText::SetMultiline(bool multiline) {
}
}
+void RenderText::SetElideBehavior(ElideBehavior elide_behavior) {
+ // TODO(skanuj) : Add a test for triggering layout change.
+ if (elide_behavior_ != elide_behavior) {
+ elide_behavior_ = elide_behavior;
+ UpdateLayoutText();
+ }
+}
+
void RenderText::SetDisplayRect(const Rect& r) {
- display_rect_ = r;
- baseline_ = kInvalidBaseline;
- cached_bounds_and_offset_valid_ = false;
- lines_.clear();
+ if (r != display_rect_) {
+ display_rect_ = r;
+ baseline_ = kInvalidBaseline;
+ cached_bounds_and_offset_valid_ = false;
+ lines_.clear();
+ if (elide_behavior_ != TRUNCATE)
+ UpdateLayoutText();
+ }
}
void RenderText::SetCursorPosition(size_t position) {
@@ -447,26 +526,28 @@ void RenderText::SetCursorPosition(size_t position) {
void RenderText::MoveCursor(BreakType break_type,
VisualCursorDirection direction,
bool select) {
- SelectionModel position(cursor_position(), selection_model_.caret_affinity());
+ SelectionModel cursor(cursor_position(), selection_model_.caret_affinity());
// Cancelling a selection moves to the edge of the selection.
if (break_type != LINE_BREAK && !selection().is_empty() && !select) {
SelectionModel selection_start = GetSelectionModelForSelectionStart();
int start_x = GetCursorBounds(selection_start, true).x();
- int cursor_x = GetCursorBounds(position, true).x();
+ int cursor_x = GetCursorBounds(cursor, true).x();
// Use the selection start if it is left (when |direction| is CURSOR_LEFT)
// or right (when |direction| is CURSOR_RIGHT) of the selection end.
if (direction == CURSOR_RIGHT ? start_x > cursor_x : start_x < cursor_x)
- position = selection_start;
- // For word breaks, use the nearest word boundary in the appropriate
- // |direction|.
+ cursor = selection_start;
+ // Use the nearest word boundary in the proper |direction| for word breaks.
if (break_type == WORD_BREAK)
- position = GetAdjacentSelectionModel(position, break_type, direction);
+ cursor = GetAdjacentSelectionModel(cursor, break_type, direction);
+ // Use an adjacent selection model if the cursor is not at a valid position.
+ if (!IsValidCursorIndex(cursor.caret_pos()))
+ cursor = GetAdjacentSelectionModel(cursor, CHARACTER_BREAK, direction);
} else {
- position = GetAdjacentSelectionModel(position, break_type, direction);
+ cursor = GetAdjacentSelectionModel(cursor, break_type, direction);
}
if (select)
- position.set_selection_start(selection().start());
- MoveCursorTo(position);
+ cursor.set_selection_start(selection().start());
+ MoveCursorTo(cursor);
}
bool RenderText::MoveCursorTo(const SelectionModel& model) {
@@ -474,9 +555,8 @@ bool RenderText::MoveCursorTo(const SelectionModel& model) {
size_t text_length = text().length();
Range range(std::min(model.selection().start(), text_length),
std::min(model.caret_pos(), text_length));
- // The current model only supports caret positions at valid character indices.
- if (!IsCursorablePosition(range.start()) ||
- !IsCursorablePosition(range.end()))
+ // The current model only supports caret positions at valid cursor indices.
+ if (!IsValidCursorIndex(range.start()) || !IsValidCursorIndex(range.end()))
return false;
SelectionModel sel(range, model.caret_affinity());
bool changed = sel != selection_model_;
@@ -484,17 +564,11 @@ bool RenderText::MoveCursorTo(const SelectionModel& model) {
return changed;
}
-bool RenderText::MoveCursorTo(const Point& point, bool select) {
- SelectionModel position = FindCursorPosition(point);
- if (select)
- position.set_selection_start(selection().start());
- return MoveCursorTo(position);
-}
-
bool RenderText::SelectRange(const Range& range) {
Range sel(std::min(range.start(), text().length()),
std::min(range.end(), text().length()));
- if (!IsCursorablePosition(sel.start()) || !IsCursorablePosition(sel.end()))
+ // Allow selection bounds at valid indicies amid multi-character graphemes.
+ if (!IsValidLogicalIndex(sel.start()) || !IsValidLogicalIndex(sel.end()))
return false;
LogicalCursorDirection affinity =
(sel.is_reversed() || sel.is_empty()) ? CURSOR_FORWARD : CURSOR_BACKWARD;
@@ -688,7 +762,7 @@ void RenderText::Draw(Canvas* canvas) {
if (clip_to_display_rect()) {
Rect clip_rect(display_rect());
- clip_rect.Inset(ShadowValue::GetMargin(text_shadows_));
+ clip_rect.Inset(ShadowValue::GetMargin(shadows_));
canvas->Save();
canvas->ClipRect(clip_rect);
@@ -713,27 +787,19 @@ void RenderText::DrawCursor(Canvas* canvas, const SelectionModel& position) {
canvas->FillRect(GetCursorBounds(position, true), cursor_color_);
}
-void RenderText::DrawSelectedTextForDrag(Canvas* canvas) {
- EnsureLayout();
- const std::vector<Rect> sel = GetSubstringBounds(selection());
-
- // Override the selection color with black, and force the background to be
- // transparent so that it's rendered without subpixel antialiasing.
- const bool saved_background_is_transparent = background_is_transparent();
- const SkColor saved_selection_color = selection_color();
- set_background_is_transparent(true);
- set_selection_color(SK_ColorBLACK);
-
- for (size_t i = 0; i < sel.size(); ++i) {
- canvas->Save();
- canvas->ClipRect(sel[i]);
- DrawVisualText(canvas);
- canvas->Restore();
- }
-
- // Restore saved transparency and selection color.
- set_selection_color(saved_selection_color);
- set_background_is_transparent(saved_background_is_transparent);
+bool RenderText::IsValidLogicalIndex(size_t index) {
+ // Check that the index is at a valid code point (not mid-surrgate-pair) and
+ // that it's not truncated from the layout text (its glyph may be shown).
+ //
+ // Indices within truncated text are disallowed so users can easily interact
+ // with the underlying truncated text using the ellipsis as a proxy. This lets
+ // users select all text, select the truncated text, and transition from the
+ // last rendered glyph to the end of the text without getting invisible cursor
+ // positions nor needing unbounded arrow key presses to traverse the ellipsis.
+ return index == 0 || index == text().length() ||
+ (index < text().length() &&
+ (truncate_length_ == 0 || index < truncate_length_) &&
+ IsValidCodePointIndex(text(), index));
}
Rect RenderText::GetCursorBounds(const SelectionModel& caret,
@@ -743,9 +809,8 @@ Rect RenderText::GetCursorBounds(const SelectionModel& caret,
// the multiline size, eliminate its use here.
EnsureLayout();
-
size_t caret_pos = caret.caret_pos();
- DCHECK(IsCursorablePosition(caret_pos));
+ DCHECK(IsValidLogicalIndex(caret_pos));
// In overtype mode, ignore the affinity and always indicate that we will
// overtype the next character.
LogicalCursorDirection caret_affinity =
@@ -786,7 +851,7 @@ size_t RenderText::IndexOfAdjacentGrapheme(size_t index,
if (direction == CURSOR_FORWARD) {
while (index < text().length()) {
index++;
- if (IsCursorablePosition(index))
+ if (IsValidCursorIndex(index))
return index;
}
return text().length();
@@ -794,7 +859,7 @@ size_t RenderText::IndexOfAdjacentGrapheme(size_t index,
while (index > 0) {
index--;
- if (IsCursorablePosition(index))
+ if (IsValidCursorIndex(index))
return index;
}
return 0;
@@ -808,10 +873,6 @@ SelectionModel RenderText::GetSelectionModelForSelectionStart() {
sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD);
}
-void RenderText::SetTextShadows(const ShadowValues& shadows) {
- text_shadows_ = shadows;
-}
-
RenderText::RenderText()
: horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT),
directionality_mode_(DIRECTIONALITY_FROM_TEXT),
@@ -830,9 +891,8 @@ RenderText::RenderText()
obscured_(false),
obscured_reveal_index_(-1),
truncate_length_(0),
+ elide_behavior_(TRUNCATE),
multiline_(false),
- fade_head_(false),
- fade_tail_(false),
background_is_transparent_(false),
clip_to_display_rect_(true),
baseline_(kInvalidBaseline),
@@ -872,7 +932,7 @@ void RenderText::SetSelectionModel(const SelectionModel& model) {
}
const base::string16& RenderText::GetLayoutText() const {
- return layout_text_.empty() ? text_ : layout_text_;
+ return layout_text_;
}
const BreakList<size_t>& RenderText::GetLineBreaks() {
@@ -1013,38 +1073,23 @@ Vector2d RenderText::GetAlignmentOffset(size_t line_number) {
}
void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
- if (multiline() || (!fade_head() && !fade_tail()))
+ const int width = display_rect().width();
+ if (multiline() || elide_behavior_ != FADE_TAIL || GetContentWidth() <= width)
return;
- const int display_width = display_rect().width();
-
- // If the text fits as-is, no need to fade.
- if (GetStringSize().width() <= display_width)
- return;
-
- int gradient_width = CalculateFadeGradientWidth(GetPrimaryFont(),
- display_width);
+ const int gradient_width = CalculateFadeGradientWidth(font_list(), width);
if (gradient_width == 0)
return;
- bool fade_left = fade_head();
- bool fade_right = fade_tail();
- // Under RTL, |fade_right| == |fade_head|.
- // TODO(asvitkine): This is currently not based on GetTextDirection() because
- // RenderTextWin does not return a direction that's based on
- // the text content.
- if (horizontal_alignment_ == ALIGN_RIGHT)
- std::swap(fade_left, fade_right);
-
Rect solid_part = display_rect();
Rect left_part;
Rect right_part;
- if (fade_left) {
+ if (horizontal_alignment_ != ALIGN_LEFT) {
left_part = solid_part;
left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
solid_part.Inset(gradient_width, 0, 0, 0);
}
- if (fade_right) {
+ if (horizontal_alignment_ != ALIGN_RIGHT) {
right_part = solid_part;
right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
solid_part.Inset(0, 0, gradient_width, 0);
@@ -1061,7 +1106,7 @@ void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
}
void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) {
- skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_);
+ skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(shadows_);
renderer->SetDrawLooper(looper.get());
}
@@ -1077,7 +1122,7 @@ bool RenderText::RangeContainsCaret(const Range& range,
void RenderText::MoveCursorTo(size_t position, bool select) {
size_t cursor = std::min(position, text().length());
- if (IsCursorablePosition(cursor))
+ if (IsValidCursorIndex(cursor))
SetSelectionModel(SelectionModel(
Range(select ? selection().start() : cursor, cursor),
(cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD));
@@ -1089,7 +1134,7 @@ void RenderText::UpdateLayoutText() {
if (obscured_) {
size_t obscured_text_length =
- static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length()));
+ static_cast<size_t>(UTF16IndexToOffset(text_, 0, text_.length()));
layout_text_.assign(obscured_text_length, kPasswordReplacementChar);
if (obscured_reveal_index_ >= 0 &&
@@ -1103,19 +1148,122 @@ void RenderText::UpdateLayoutText() {
// Gets the index in |layout_text_| to be replaced.
const size_t cp_start =
- static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, start));
+ static_cast<size_t>(UTF16IndexToOffset(text_, 0, start));
if (layout_text_.length() > cp_start)
layout_text_.replace(cp_start, 1, text_.substr(start, end - start));
}
+ } else {
+ layout_text_ = text_;
}
- const base::string16& text = obscured_ ? layout_text_ : text_;
+ const base::string16& text = layout_text_;
if (truncate_length_ > 0 && truncate_length_ < text.length()) {
// Truncate the text at a valid character break and append an ellipsis.
icu::StringCharacterIterator iter(text.c_str());
iter.setIndex32(truncate_length_ - 1);
- layout_text_.assign(text.substr(0, iter.getIndex()) + gfx::kEllipsisUTF16);
+ layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16);
+ }
+
+ if (elide_behavior_ != TRUNCATE && elide_behavior_ != FADE_TAIL &&
+ display_rect_.width() > 0 && !layout_text_.empty() &&
+ GetContentWidth() > display_rect_.width()) {
+ // This doesn't trim styles so ellipsis may get rendered as a different
+ // style than the preceding text. See crbug.com/327850.
+ layout_text_.assign(ElideText(layout_text_));
+ }
+
+ ResetLayout();
+}
+
+// TODO(skanuj): Fix code duplication with ElideText in ui/gfx/text_elider.cc
+// See crbug.com/327846
+base::string16 RenderText::ElideText(const base::string16& text) {
+ const bool insert_ellipsis = (elide_behavior_ != TRUNCATE);
+ // Create a RenderText copy with attributes that affect the rendering width.
+ scoped_ptr<RenderText> render_text(CreateInstance());
+ render_text->SetFontList(font_list_);
+ render_text->SetDirectionalityMode(directionality_mode_);
+ render_text->SetCursorEnabled(cursor_enabled_);
+
+ render_text->styles_ = styles_;
+ render_text->colors_ = colors_;
+ render_text->SetText(text);
+ const int current_text_pixel_width = render_text->GetContentWidth();
+
+ const base::string16 ellipsis = base::string16(kEllipsisUTF16);
+ const bool elide_in_middle = false;
+ const bool elide_at_beginning = false;
+ StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
+
+ // Pango will return 0 width for absurdly long strings. Cut the string in
+ // half and try again.
+ // This is caused by an int overflow in Pango (specifically, in
+ // pango_glyph_string_extents_range). It's actually more subtle than just
+ // returning 0, since on super absurdly long strings, the int can wrap and
+ // return positive numbers again. Detecting that is probably not worth it
+ // (eliding way too much from a ridiculous string is probably still
+ // ridiculous), but we should check other widths for bogus values as well.
+ if (current_text_pixel_width <= 0 && !text.empty())
+ return ElideText(slicer.CutString(text.length() / 2, insert_ellipsis));
+
+ if (current_text_pixel_width <= display_rect_.width())
+ return text;
+
+ render_text->SetText(base::string16());
+ render_text->SetText(ellipsis);
+ const int ellipsis_width = render_text->GetContentWidth();
+
+ if (insert_ellipsis && (ellipsis_width >= display_rect_.width()))
+ return base::string16();
+
+ // Use binary search to compute the elided text.
+ size_t lo = 0;
+ size_t hi = text.length() - 1;
+ const base::i18n::TextDirection text_direction = GetTextDirection();
+ for (size_t guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) {
+ // Restore styles and colors. They will be truncated to size by SetText.
+ render_text->styles_ = styles_;
+ render_text->colors_ = colors_;
+ base::string16 new_text = slicer.CutString(guess, false);
+ render_text->SetText(new_text);
+
+ // This has to be an additional step so that the ellipsis is rendered with
+ // same style as trailing part of the text.
+ if (insert_ellipsis) {
+ // When ellipsis follows text whose directionality is not the same as that
+ // of the whole text, it will be rendered with the directionality of the
+ // whole text. Since we want ellipsis to indicate continuation of the
+ // preceding text, we force the directionality of ellipsis to be same as
+ // the preceding text using LTR or RTL markers.
+ base::i18n::TextDirection trailing_text_direction =
+ base::i18n::GetLastStrongCharacterDirection(new_text);
+ new_text.append(ellipsis);
+ if (trailing_text_direction != text_direction) {
+ if (trailing_text_direction == base::i18n::LEFT_TO_RIGHT)
+ new_text += base::i18n::kLeftToRightMark;
+ else
+ new_text += base::i18n::kRightToLeftMark;
+ }
+ render_text->SetText(new_text);
+ }
+
+ // We check the width of the whole desired string at once to ensure we
+ // handle kerning/ligatures/etc. correctly.
+ const int guess_width = render_text->GetContentWidth();
+ if (guess_width == display_rect_.width())
+ break;
+ if (guess_width > display_rect_.width()) {
+ hi = guess - 1;
+ // Move back if we are on loop terminating condition, and guess is wider
+ // than available.
+ if (hi < lo)
+ lo = hi;
+ } else {
+ lo = guess + 1;
+ }
}
+
+ return render_text->text();
}
void RenderText::UpdateCachedBoundsAndOffset() {
@@ -1128,7 +1276,8 @@ void RenderText::UpdateCachedBoundsAndOffset() {
// the stale |display_offset_|. Applying |delta_offset| at the end of this
// function will set |cursor_bounds_| and |display_offset_| to correct values.
cached_bounds_and_offset_valid_ = true;
- cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
+ if (cursor_enabled())
+ cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
// Update |display_offset_| to ensure the current cursor is visible.
const int display_width = display_rect_.width();
diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h
index 8696d690560..885df0a9b41 100644
--- a/chromium/ui/gfx/render_text.h
+++ b/chromium/ui/gfx/render_text.h
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -27,6 +28,7 @@
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/size_f.h"
#include "ui/gfx/text_constants.h"
+#include "ui/gfx/text_elider.h"
#include "ui/gfx/vector2d.h"
class SkCanvas;
@@ -50,7 +52,10 @@ class SkiaTextRenderer {
~SkiaTextRenderer();
void SetDrawLooper(SkDrawLooper* draw_looper);
- void SetFontSmoothingSettings(bool enable_smoothing, bool enable_lcd_text);
+ void SetFontSmoothingSettings(bool antialiasing,
+ bool subpixel_rendering,
+ bool subpixel_positioning);
+ void SetFontHinting(SkPaint::Hinting hinting);
void SetTypeface(SkTypeface* typeface);
void SetTextSize(SkScalar size);
void SetFontFamilyWithStyle(const std::string& family, int font_style);
@@ -69,11 +74,36 @@ class SkiaTextRenderer {
// third_party/skia/src/core/SkTextFormatParams.h
void DrawDecorations(int x, int y, int width, bool underline, bool strike,
bool diagonal_strike);
+ // Finishes any ongoing diagonal strike run.
+ void EndDiagonalStrike();
void DrawUnderline(int x, int y, int width);
void DrawStrike(int x, int y, int width) const;
- void DrawDiagonalStrike(int x, int y, int width) const;
private:
+ // Helper class to draw a diagonal line with multiple pieces of different
+ // lengths and colors; to support text selection appearances.
+ class DiagonalStrike {
+ public:
+ DiagonalStrike(Canvas* canvas, Point start, const SkPaint& paint);
+ ~DiagonalStrike();
+
+ void AddPiece(int length, SkColor color);
+ void Draw();
+
+ private:
+ typedef std::pair<int, SkColor> Piece;
+
+ Canvas* canvas_;
+ SkMatrix matrix_;
+ const Point start_;
+ SkPaint paint_;
+ int total_length_;
+ std::vector<Piece> pieces_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiagonalStrike);
+ };
+
+ Canvas* canvas_;
SkCanvas* canvas_skia_;
bool started_drawing_;
SkPaint paint_;
@@ -81,6 +111,7 @@ class SkiaTextRenderer {
skia::RefPtr<SkShader> deferred_fade_shader_;
SkScalar underline_thickness_;
SkScalar underline_position_;
+ scoped_ptr<DiagonalStrike> diagonal_;
DISALLOW_COPY_AND_ASSIGN(SkiaTextRenderer);
};
@@ -146,6 +177,10 @@ struct Line {
int baseline;
};
+// Creates an SkTypeface from a font |family| name and a |gfx::Font::FontStyle|.
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
+ int style);
+
} // namespace internal
// RenderText represents an abstract model of styled text and its corresponding
@@ -156,7 +191,7 @@ class GFX_EXPORT RenderText {
public:
virtual ~RenderText();
- // Creates a platform-specific RenderText instance.
+ // Creates a platform-specific or cross-platform RenderText instance.
static RenderText* CreateInstance();
const base::string16& text() const { return text_; }
@@ -169,13 +204,6 @@ class GFX_EXPORT RenderText {
const FontList& font_list() const { return font_list_; }
void SetFontList(const FontList& font_list);
- void SetFont(const Font& font);
-
- // Set the font size to |size| in pixels.
- void SetFontSize(int size);
-
- // Get the first font in |font_list_|.
- const Font& GetPrimaryFont() const;
bool cursor_enabled() const { return cursor_enabled_; }
void SetCursorEnabled(bool cursor_enabled);
@@ -227,14 +255,14 @@ class GFX_EXPORT RenderText {
// WARNING: Only use this for system limits, it lacks complex text support.
void set_truncate_length(size_t length) { truncate_length_ = length; }
+ // Elides the text to fit in |display_rect| according to the specified
+ // |elide_behavior|. |ELIDE_MIDDLE| is not supported. If a truncate length and
+ // an elide mode are specified, the shorter of the two will be applicable.
+ void SetElideBehavior(ElideBehavior elide_behavior);
+
const Rect& display_rect() const { return display_rect_; }
void SetDisplayRect(const Rect& r);
- void set_fade_head(bool fade_head) { fade_head_ = fade_head; }
- bool fade_head() const { return fade_head_; }
- void set_fade_tail(bool fade_tail) { fade_tail_ = fade_tail; }
- bool fade_tail() const { return fade_tail_; }
-
bool background_is_transparent() const { return background_is_transparent_; }
void set_background_is_transparent(bool transparent) {
background_is_transparent_ = transparent;
@@ -261,11 +289,6 @@ class GFX_EXPORT RenderText {
// grapheme boundary), it is a no-op and returns false.
bool MoveCursorTo(const SelectionModel& selection_model);
- // Move the cursor to the position associated with the clicked point.
- // If |select| is false, the selection start is moved to the same position.
- // Returns true if the cursor position or selection range changed.
- bool MoveCursorTo(const Point& point, bool select);
-
// Set the selection_model_ based on |range|.
// If the |range| start or end is greater than text length, it is modified
// to be the text length.
@@ -320,9 +343,8 @@ class GFX_EXPORT RenderText {
VisualCursorDirection GetVisualDirectionOfLogicalEnd();
// Returns the size required to display the current string (which is the
- // wrapped size in multiline mode). Note that this returns the raw size of the
- // string, which does not include the cursor or the margin area of text
- // shadows.
+ // wrapped size in multiline mode). The returned size does not include space
+ // reserved for the cursor or the offset text shadows.
virtual Size GetStringSize() = 0;
// This is same as GetStringSize except that fractional size is returned.
@@ -347,16 +369,16 @@ class GFX_EXPORT RenderText {
// Draws a cursor at |position|.
void DrawCursor(Canvas* canvas, const SelectionModel& position);
- // Draw the selected text without a cursor or selection highlight. Subpixel
- // antialiasing is disabled and foreground color is forced to black.
- void DrawSelectedTextForDrag(Canvas* canvas);
-
// Gets the SelectionModel from a visual point in local coordinates.
virtual SelectionModel FindCursorPosition(const Point& point) = 0;
- // Return true if cursor can appear in front of the character at |position|,
- // which means it is a grapheme boundary or the first character in the text.
- virtual bool IsCursorablePosition(size_t position) = 0;
+ // Returns true if the position is a valid logical index into text(), and is
+ // also a valid grapheme boundary, which may be used as a cursor position.
+ virtual bool IsValidCursorIndex(size_t index) = 0;
+
+ // Returns true if the position is a valid logical index into text(). Indices
+ // amid multi-character graphemes are allowed here, unlike IsValidCursorIndex.
+ virtual bool IsValidLogicalIndex(size_t index);
// Get the visual bounds of a cursor at |caret|. These bounds typically
// represent a vertical line if |insert_mode| is true. Pass false for
@@ -364,8 +386,7 @@ class GFX_EXPORT RenderText {
// are in local coordinates, but may be outside the visible region if the text
// is longer than the textfield. Subsequent text, cursor, or bounds changes
// may invalidate returned values. Note that |caret| must be placed at
- // grapheme boundary, that is, |IsCursorablePosition(caret.caret_pos())| must
- // return true.
+ // grapheme boundary, i.e. caret.caret_pos() must be a cursorable position.
Rect GetCursorBounds(const SelectionModel& caret, bool insert_mode);
// Compute the current cursor bounds, panning the text to show the cursor in
@@ -374,10 +395,9 @@ class GFX_EXPORT RenderText {
const Rect& GetUpdatedCursorBounds();
// Given an |index| in text(), return the next or previous grapheme boundary
- // in logical order (that is, the nearest index for which
- // |IsCursorablePosition(index)| returns true). The return value is in the
- // range 0 to text().length() inclusive (the input is clamped if it is out of
- // that range). Always moves by at least one character index unless the
+ // in logical order (i.e. the nearest cursorable index). The return value is
+ // in the range 0 to text().length() inclusive (the input is clamped if it is
+ // out of that range). Always moves by at least one character index unless the
// supplied index is already at the boundary of the string.
size_t IndexOfAdjacentGrapheme(size_t index,
LogicalCursorDirection direction);
@@ -387,7 +407,7 @@ class GFX_EXPORT RenderText {
SelectionModel GetSelectionModelForSelectionStart();
// Sets shadows to drawn with text.
- void SetTextShadows(const ShadowValues& shadows);
+ void set_shadows(const ShadowValues& shadows) { shadows_ = shadows; }
typedef std::pair<Font, Range> FontSpan;
// For testing purposes, returns which fonts were chosen for which parts of
@@ -396,6 +416,12 @@ class GFX_EXPORT RenderText {
// chosen.
virtual std::vector<FontSpan> GetFontSpansForTesting() = 0;
+ // Gets the horizontal bounds (relative to the left of the text, not the view)
+ // of the glyph starting at |index|. If the glyph is RTL then the returned
+ // Range will have is_reversed() true. (This does not return a Rect because a
+ // Rect can't have a negative width.)
+ virtual Range GetGlyphBounds(size_t index) = 0;
+
protected:
RenderText();
@@ -460,12 +486,6 @@ class GFX_EXPORT RenderText {
// Sets the selection model, the argument is assumed to be valid.
virtual void SetSelectionModel(const SelectionModel& model);
- // Get the horizontal bounds (relative to the left of the text, not the view)
- // of the glyph starting at |index|. If the glyph is RTL then the returned
- // Range will have is_reversed() true. (This does not return a Rect because a
- // Rect can't have a negative width.)
- virtual Range GetGlyphBounds(size_t index) = 0;
-
// Get the visual bounds containing the logical substring within the |range|.
// If |range| is empty, the result is empty. These bounds could be visually
// discontinuous if the substring is split by a LTR/RTL level change.
@@ -508,12 +528,10 @@ class GFX_EXPORT RenderText {
Point ToTextPoint(const Point& point);
Point ToViewPoint(const Point& point);
- // Convert a text space x-coordinate range to corresponding rects in view
- // space.
+ // Convert a text space x-coordinate range to rects in view space.
std::vector<Rect> TextBoundsToViewBounds(const Range& x);
- // Returns the line offset from the origin, accounting for text alignment
- // only.
+ // Returns the line offset from the origin, accounts for text alignment only.
Vector2d GetAlignmentOffset(size_t line_number);
// Applies fade effects to |renderer|.
@@ -535,6 +553,8 @@ class GFX_EXPORT RenderText {
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ApplyColorAndStyle);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, RevealObscuredText);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ElidedText);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ElidedObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, TruncatedText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, TruncatedObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, GraphemePositions);
@@ -545,6 +565,11 @@ class GFX_EXPORT RenderText {
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_NormalWidth);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_SufficientWidth);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_Newline);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, GlyphBounds);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_GlyphBounds);
+
+ // Creates a platform-specific RenderText instance.
+ static RenderText* CreateNativeInstance();
// Set the cursor to |position|, with the caret trailing the previous
// grapheme, or if there is no previous grapheme, leading the cursor position.
@@ -556,6 +581,10 @@ class GFX_EXPORT RenderText {
// Updates |layout_text_| if the text is obscured or truncated.
void UpdateLayoutText();
+ // Elides |text| to fit in the |display_rect_| with given |elide_behavior_|.
+ // See ElideText in ui/gfx/text_elider.cc for reference.
+ base::string16 ElideText(const base::string16& text);
+
// Update the cached bounds and display offset to ensure that the current
// cursor is within the visible display area.
void UpdateCachedBoundsAndOffset();
@@ -628,6 +657,9 @@ class GFX_EXPORT RenderText {
// The maximum length of text to display, 0 forgoes a hard limit.
size_t truncate_length_;
+ // The behavior for eliding, fading, or truncating.
+ ElideBehavior elide_behavior_;
+
// The obscured and/or truncated text that will be displayed.
base::string16 layout_text_;
@@ -635,10 +667,6 @@ class GFX_EXPORT RenderText {
// |display_rect_| as the width cap.
bool multiline_;
- // Fade text head and/or tail, if text doesn't fit into |display_rect_|.
- bool fade_head_;
- bool fade_tail_;
-
// Is the background transparent (either partially or fully)?
bool background_is_transparent_;
@@ -665,7 +693,7 @@ class GFX_EXPORT RenderText {
bool cached_bounds_and_offset_valid_;
// Text shadows to be drawn.
- ShadowValues text_shadows_;
+ ShadowValues shadows_;
// A list of valid layout text line break positions.
BreakList<size_t> line_breaks_;
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
new file mode 100644
index 00000000000..3d9bf58141e
--- /dev/null
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -0,0 +1,1010 @@
+// 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/gfx/render_text_harfbuzz.h"
+
+#include <map>
+
+#include "base/debug/leak_annotations.h"
+#include "base/i18n/bidi_line_iterator.h"
+#include "base/i18n/break_iterator.h"
+#include "base/i18n/char_iterator.h"
+#include "base/lazy_instance.h"
+#include "third_party/harfbuzz-ng/src/hb.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/utf16_indexing.h"
+
+#if defined(OS_WIN)
+#include "ui/gfx/font_smoothing_win.h"
+#endif
+
+namespace gfx {
+
+namespace {
+
+// The maximum number of scripts a Unicode character can belong to. This value
+// is arbitrarily chosen to be a good limit because it is unlikely for a single
+// character to belong to more scripts.
+const size_t kMaxScripts = 5;
+
+// Maps from code points to glyph indices in a font.
+typedef std::map<uint32_t, uint16_t> GlyphCache;
+
+// Font data provider for HarfBuzz using Skia. Copied from Blink.
+// TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375
+struct FontData {
+ FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
+
+ SkPaint paint_;
+ GlyphCache* glyph_cache_;
+};
+
+hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) {
+ return SkScalarToFixed(value);
+}
+
+// Deletes the object at the given pointer after casting it to the given type.
+template<typename Type>
+void DeleteByType(void* data) {
+ Type* typed_data = reinterpret_cast<Type*>(data);
+ delete typed_data;
+}
+
+template<typename Type>
+void DeleteArrayByType(void* data) {
+ Type* typed_data = reinterpret_cast<Type*>(data);
+ delete[] typed_data;
+}
+
+// Outputs the |width| and |extents| of the glyph with index |codepoint| in
+// |paint|'s font.
+void GetGlyphWidthAndExtents(SkPaint* paint,
+ hb_codepoint_t codepoint,
+ hb_position_t* width,
+ hb_glyph_extents_t* extents) {
+ DCHECK_LE(codepoint, 0xFFFFU);
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ SkScalar sk_width;
+ SkRect sk_bounds;
+ uint16_t glyph = codepoint;
+
+ paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds);
+ if (width)
+ *width = SkiaScalarToHarfBuzzPosition(sk_width);
+ if (extents) {
+ // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be
+ // y-grows-up.
+ extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft);
+ extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop);
+ extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width());
+ extents->height = SkiaScalarToHarfBuzzPosition(-sk_bounds.height());
+ }
+}
+
+// Writes the |glyph| index for the given |unicode| code point. Returns whether
+// the glyph exists, i.e. it is not a missing glyph.
+hb_bool_t GetGlyph(hb_font_t* font,
+ void* data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t* glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ GlyphCache* cache = font_data->glyph_cache_;
+
+ bool exists = cache->count(unicode) != 0;
+ if (!exists) {
+ SkPaint* paint = &font_data->paint_;
+ paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
+ paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]);
+ }
+ *glyph = (*cache)[unicode];
+ return !!*glyph;
+}
+
+// Returns the horizontal advance value of the |glyph|.
+hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ hb_position_t advance = 0;
+
+ GetGlyphWidthAndExtents(&font_data->paint_, glyph, &advance, 0);
+ return advance;
+}
+
+hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ hb_position_t* x,
+ hb_position_t* y,
+ void* user_data) {
+ // Just return true, like the HarfBuzz-FreeType implementation.
+ return true;
+}
+
+hb_position_t GetGlyphKerning(FontData* font_data,
+ hb_codepoint_t first_glyph,
+ hb_codepoint_t second_glyph) {
+ SkTypeface* typeface = font_data->paint_.getTypeface();
+ const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph),
+ static_cast<uint16_t>(second_glyph) };
+ int32_t kerning_adjustments[1] = { 0 };
+
+ if (!typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments))
+ return 0;
+
+ SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
+ SkScalar size = font_data->paint_.getTextSize();
+ return SkiaScalarToHarfBuzzPosition(
+ SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm));
+}
+
+hb_position_t GetGlyphHorizontalKerning(hb_font_t* font,
+ void* data,
+ hb_codepoint_t left_glyph,
+ hb_codepoint_t right_glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ if (font_data->paint_.isVerticalText()) {
+ // We don't support cross-stream kerning.
+ return 0;
+ }
+
+ return GetGlyphKerning(font_data, left_glyph, right_glyph);
+}
+
+hb_position_t GetGlyphVerticalKerning(hb_font_t* font,
+ void* data,
+ hb_codepoint_t top_glyph,
+ hb_codepoint_t bottom_glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ if (!font_data->paint_.isVerticalText()) {
+ // We don't support cross-stream kerning.
+ return 0;
+ }
+
+ return GetGlyphKerning(font_data, top_glyph, bottom_glyph);
+}
+
+// Writes the |extents| of |glyph|.
+hb_bool_t GetGlyphExtents(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t* extents,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+
+ GetGlyphWidthAndExtents(&font_data->paint_, glyph, 0, extents);
+ return true;
+}
+
+class FontFuncs {
+ public:
+ FontFuncs() : font_funcs_(hb_font_funcs_create()) {
+ hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0);
+ hb_font_funcs_set_glyph_h_advance_func(
+ font_funcs_, GetGlyphHorizontalAdvance, 0, 0);
+ hb_font_funcs_set_glyph_h_kerning_func(
+ font_funcs_, GetGlyphHorizontalKerning, 0, 0);
+ hb_font_funcs_set_glyph_h_origin_func(
+ font_funcs_, GetGlyphHorizontalOrigin, 0, 0);
+ hb_font_funcs_set_glyph_v_kerning_func(
+ font_funcs_, GetGlyphVerticalKerning, 0, 0);
+ hb_font_funcs_set_glyph_extents_func(
+ font_funcs_, GetGlyphExtents, 0, 0);
+ hb_font_funcs_make_immutable(font_funcs_);
+ }
+
+ ~FontFuncs() {
+ hb_font_funcs_destroy(font_funcs_);
+ }
+
+ hb_font_funcs_t* get() { return font_funcs_; }
+
+ private:
+ hb_font_funcs_t* font_funcs_;
+
+ DISALLOW_COPY_AND_ASSIGN(FontFuncs);
+};
+
+base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER;
+
+// Returns the raw data of the font table |tag|.
+hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) {
+ SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data);
+
+ const size_t table_size = typeface->getTableSize(tag);
+ if (!table_size)
+ return 0;
+
+ scoped_ptr<char[]> buffer(new char[table_size]);
+ if (!buffer)
+ return 0;
+ size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer.get());
+ if (table_size != actual_size)
+ return 0;
+
+ char* buffer_raw = buffer.release();
+ return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE,
+ buffer_raw, DeleteArrayByType<char>);
+}
+
+void UnrefSkTypeface(void* data) {
+ SkTypeface* skia_face = reinterpret_cast<SkTypeface*>(data);
+ SkSafeUnref(skia_face);
+}
+
+// Creates a HarfBuzz face from the given Skia face.
+hb_face_t* CreateHarfBuzzFace(SkTypeface* skia_face) {
+ SkSafeRef(skia_face);
+ hb_face_t* face = hb_face_create_for_tables(GetFontTable, skia_face,
+ UnrefSkTypeface);
+ DCHECK(face);
+ return face;
+}
+
+// Creates a HarfBuzz font from the given Skia face and text size.
+hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, int text_size) {
+ typedef std::pair<hb_face_t*, GlyphCache> FaceCache;
+
+ // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache?
+ static std::map<SkFontID, FaceCache> face_caches;
+
+ FaceCache* face_cache = &face_caches[skia_face->uniqueID()];
+ if (face_cache->first == 0) {
+ // These HarfBuzz faces live indefinitely and are intentionally leaked.
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ hb_face_t* harfbuzz_face = CreateHarfBuzzFace(skia_face);
+ *face_cache = FaceCache(harfbuzz_face, GlyphCache());
+ }
+
+ hb_font_t* harfbuzz_font = hb_font_create(face_cache->first);
+ // TODO(ckocagil): Investigate whether disabling hinting here has any effect
+ // on text quality.
+ int upem = hb_face_get_upem(face_cache->first);
+ hb_font_set_scale(harfbuzz_font, upem, upem);
+ FontData* hb_font_data = new FontData(&face_cache->second);
+ hb_font_data->paint_.setTypeface(skia_face);
+ hb_font_data->paint_.setTextSize(text_size);
+ hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data,
+ DeleteByType<FontData>);
+ hb_font_make_immutable(harfbuzz_font);
+ return harfbuzz_font;
+}
+
+// Returns true if characters of |block_code| may trigger font fallback.
+bool IsUnusualBlockCode(UBlockCode block_code) {
+ return block_code == UBLOCK_GEOMETRIC_SHAPES ||
+ block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
+}
+
+// Returns the index of the first unusual character after a usual character or
+// vice versa. Unusual characters are defined by |IsUnusualBlockCode|.
+size_t FindUnusualCharacter(const base::string16& text,
+ size_t run_start,
+ size_t run_break) {
+ const int32 run_length = static_cast<int32>(run_break - run_start);
+ base::i18n::UTF16CharIterator iter(text.c_str() + run_start,
+ run_length);
+ const UBlockCode first_block_code = ublock_getCode(iter.get());
+ const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
+ while (iter.Advance() && iter.array_pos() < run_length) {
+ const UBlockCode current_block_code = ublock_getCode(iter.get());
+ if (current_block_code != first_block_code &&
+ (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
+ return run_start + iter.array_pos();
+ }
+ }
+ return run_break;
+}
+
+// If the given scripts match, returns the one that isn't USCRIPT_COMMON or
+// USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns
+// USCRIPT_INVALID_CODE.
+UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) {
+ if (first == second ||
+ (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) {
+ return first;
+ }
+ if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED)
+ return second;
+ return USCRIPT_INVALID_CODE;
+}
+
+// Writes the script and the script extensions of the character with the
+// Unicode |codepoint|. Returns the number of written scripts.
+int GetScriptExtensions(UChar32 codepoint, UScriptCode* scripts) {
+ UErrorCode icu_error = U_ZERO_ERROR;
+ // ICU documentation incorrectly states that the result of
+ // |uscript_getScriptExtensions| will contain the regular script property.
+ // Write the character's script property to the first element.
+ scripts[0] = uscript_getScript(codepoint, &icu_error);
+ if (U_FAILURE(icu_error))
+ return 0;
+ // Fill the rest of |scripts| with the extensions.
+ int count = uscript_getScriptExtensions(codepoint, scripts + 1,
+ kMaxScripts - 1, &icu_error);
+ if (U_FAILURE(icu_error))
+ count = 0;
+ return count + 1;
+}
+
+// Intersects the script extensions set of |codepoint| with |result| and writes
+// to |result|, reading and updating |result_size|.
+void ScriptSetIntersect(UChar32 codepoint,
+ UScriptCode* result,
+ size_t* result_size) {
+ UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
+ int count = GetScriptExtensions(codepoint, scripts);
+
+ size_t out_size = 0;
+
+ for (size_t i = 0; i < *result_size; ++i) {
+ for (int j = 0; j < count; ++j) {
+ UScriptCode intersection = ScriptIntersect(result[i], scripts[j]);
+ if (intersection != USCRIPT_INVALID_CODE) {
+ result[out_size++] = intersection;
+ break;
+ }
+ }
+ }
+
+ *result_size = out_size;
+}
+
+// Find the longest sequence of characters from 0 and up to |length| that
+// have at least one common UScriptCode value. Writes the common script value to
+// |script| and returns the length of the sequence. Takes the characters' script
+// extensions into account. http://www.unicode.org/reports/tr24/#ScriptX
+//
+// Consider 3 characters with the script values {Kana}, {Hira, Kana}, {Kana}.
+// Without script extensions only the first script in each set would be taken
+// into account, resulting in 3 runs where 1 would be enough.
+// TODO(ckocagil): Write a unit test for the case above.
+int ScriptInterval(const base::string16& text,
+ size_t start,
+ size_t length,
+ UScriptCode* script) {
+ DCHECK_GT(length, 0U);
+
+ UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
+
+ base::i18n::UTF16CharIterator char_iterator(text.c_str() + start, length);
+ size_t scripts_size = GetScriptExtensions(char_iterator.get(), scripts);
+ *script = scripts[0];
+
+ while (char_iterator.Advance()) {
+ ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
+ if (scripts_size == 0U)
+ return char_iterator.array_pos();
+ *script = scripts[0];
+ }
+
+ return length;
+}
+
+// A port of hb_icu_script_to_script because harfbuzz on CrOS is built without
+// hb-icu. See http://crbug.com/356929
+inline hb_script_t ICUScriptToHBScript(UScriptCode script) {
+ if (script == USCRIPT_INVALID_CODE)
+ return HB_SCRIPT_INVALID;
+ return hb_script_from_string(uscript_getShortName(script), -1);
+}
+
+} // namespace
+
+namespace internal {
+
+TextRunHarfBuzz::TextRunHarfBuzz()
+ : width(0),
+ preceding_run_widths(0),
+ is_rtl(false),
+ level(0),
+ script(USCRIPT_INVALID_CODE),
+ glyph_count(-1),
+ font_size(0),
+ font_style(0),
+ strike(false),
+ diagonal_strike(false),
+ underline(false) {}
+
+TextRunHarfBuzz::~TextRunHarfBuzz() {}
+
+size_t TextRunHarfBuzz::CharToGlyph(size_t pos) const {
+ DCHECK(range.start() <= pos && pos < range.end());
+
+ if (!is_rtl) {
+ size_t cluster_start = 0;
+ for (size_t i = 1; i < glyph_count && pos >= glyph_to_char[i]; ++i)
+ if (glyph_to_char[i] != glyph_to_char[i - 1])
+ cluster_start = i;
+ return cluster_start;
+ }
+
+ for (size_t i = 0; i < glyph_count; ++i) {
+ if (pos >= glyph_to_char[i])
+ return i;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const {
+ DCHECK(range.Contains(char_range));
+ DCHECK(!char_range.is_reversed());
+ DCHECK(!char_range.is_empty());
+
+ size_t first = 0;
+ size_t last = 0;
+
+ if (is_rtl) {
+ // For RTL runs, we subtract 1 from |char_range| to get the leading edges.
+ last = CharToGlyph(char_range.end() - 1);
+ // Loop until we find a non-empty glyph range. For multi-character clusters,
+ // the loop is needed to find the cluster end. Do the same for LTR below.
+ for (size_t i = char_range.start(); i > range.start(); --i) {
+ first = CharToGlyph(i - 1);
+ if (first != last)
+ return Range(last, first);
+ }
+ return Range(last, glyph_count);
+ }
+
+ first = CharToGlyph(char_range.start());
+ for (size_t i = char_range.end(); i < range.end(); ++i) {
+ last = CharToGlyph(i);
+ if (first != last)
+ return Range(first, last);
+ }
+ return Range(first, glyph_count);
+}
+
+// Returns whether the given shaped run contains any missing glyphs.
+bool TextRunHarfBuzz::HasMissingGlyphs() const {
+ static const int kMissingGlyphId = 0;
+ for (size_t i = 0; i < glyph_count; ++i) {
+ if (glyphs[i] == kMissingGlyphId)
+ return true;
+ }
+ return false;
+}
+
+int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const {
+ if (text_index == range.end()) {
+ trailing = true;
+ --text_index;
+ }
+ Range glyph_range = CharRangeToGlyphRange(Range(text_index, text_index + 1));
+ const size_t glyph_pos = (is_rtl == trailing) ?
+ glyph_range.start() : glyph_range.end();
+ const int x = glyph_pos < glyph_count ?
+ SkScalarRoundToInt(positions[glyph_pos].x()) : width;
+ return preceding_run_widths + x;
+}
+
+} // namespace internal
+
+RenderTextHarfBuzz::RenderTextHarfBuzz()
+ : RenderText(),
+ needs_layout_(false) {}
+
+RenderTextHarfBuzz::~RenderTextHarfBuzz() {}
+
+Size RenderTextHarfBuzz::GetStringSize() {
+ EnsureLayout();
+ return lines()[0].size;
+}
+
+SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) {
+ EnsureLayout();
+
+ int x = ToTextPoint(point).x();
+ int offset = 0;
+ size_t run_index = GetRunContainingXCoord(x, &offset);
+ if (run_index >= runs_.size())
+ return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
+ const internal::TextRunHarfBuzz& run = *runs_[run_index];
+
+ for (size_t i = 0; i < run.glyph_count; ++i) {
+ const SkScalar end =
+ i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x();
+ const SkScalar middle = (end + run.positions[i].x()) / 2;
+
+ if (offset < middle) {
+ return SelectionModel(LayoutIndexToTextIndex(
+ run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)),
+ (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD));
+ }
+ if (offset < end) {
+ return SelectionModel(LayoutIndexToTextIndex(
+ run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)),
+ (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD));
+ }
+ }
+ return EdgeSelectionModel(CURSOR_RIGHT);
+}
+
+std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() {
+ NOTIMPLEMENTED();
+ return std::vector<RenderText::FontSpan>();
+}
+
+int RenderTextHarfBuzz::GetLayoutTextBaseline() {
+ EnsureLayout();
+ return lines()[0].baseline;
+}
+
+SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) {
+ DCHECK(!needs_layout_);
+ internal::TextRunHarfBuzz* run;
+ size_t run_index = GetRunContainingCaret(selection);
+ if (run_index >= runs_.size()) {
+ // The cursor is not in any run: we're at the visual and logical edge.
+ SelectionModel edge = EdgeSelectionModel(direction);
+ if (edge.caret_pos() == selection.caret_pos())
+ return edge;
+ int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1;
+ run = runs_[visual_to_logical_[visual_index]];
+ } else {
+ // If the cursor is moving within the current run, just move it by one
+ // grapheme in the appropriate direction.
+ run = runs_[run_index];
+ size_t caret = selection.caret_pos();
+ bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+ if (forward_motion) {
+ if (caret < LayoutIndexToTextIndex(run->range.end())) {
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
+ return SelectionModel(caret, CURSOR_BACKWARD);
+ }
+ } else {
+ if (caret > LayoutIndexToTextIndex(run->range.start())) {
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
+ return SelectionModel(caret, CURSOR_FORWARD);
+ }
+ }
+ // The cursor is at the edge of a run; move to the visually adjacent run.
+ int visual_index = logical_to_visual_[run_index];
+ visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
+ if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size()))
+ return EdgeSelectionModel(direction);
+ run = runs_[visual_to_logical_[visual_index]];
+ }
+ bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+ return forward_motion ? FirstSelectionModelInsideRun(run) :
+ LastSelectionModelInsideRun(run);
+}
+
+SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) {
+ // TODO(ckocagil): This implementation currently matches RenderTextWin, but it
+ // should match the native behavior on other platforms.
+ if (obscured())
+ return EdgeSelectionModel(direction);
+
+ base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return selection;
+
+ size_t pos;
+ if (direction == CURSOR_RIGHT) {
+ pos = std::min(selection.caret_pos() + 1, text().length());
+ while (iter.Advance()) {
+ pos = iter.pos();
+ if (iter.IsWord() && pos > selection.caret_pos())
+ break;
+ }
+ } else { // direction == CURSOR_LEFT
+ // Notes: We always iterate words from the beginning.
+ // This is probably fast enough for our usage, but we may
+ // want to modify WordIterator so that it can start from the
+ // middle of string and advance backwards.
+ pos = std::max<int>(selection.caret_pos() - 1, 0);
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ size_t begin = iter.pos() - iter.GetString().length();
+ if (begin == selection.caret_pos()) {
+ // The cursor is at the beginning of a word.
+ // Move to previous word.
+ break;
+ } else if (iter.pos() >= selection.caret_pos()) {
+ // The cursor is in the middle or at the end of a word.
+ // Move to the top of current word.
+ pos = begin;
+ break;
+ }
+ pos = iter.pos() - iter.GetString().length();
+ }
+ }
+ }
+ return SelectionModel(pos, CURSOR_FORWARD);
+}
+
+Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) {
+ const size_t run_index =
+ GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
+ // Return edge bounds if the index is invalid or beyond the layout text size.
+ if (run_index >= runs_.size())
+ return Range(GetStringSize().width());
+ const size_t layout_index = TextIndexToLayoutIndex(index);
+ return Range(runs_[run_index]->GetGlyphXBoundary(layout_index, false),
+ runs_[run_index]->GetGlyphXBoundary(layout_index, true));
+}
+
+std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
+ DCHECK(!needs_layout_);
+ DCHECK(Range(0, text().length()).Contains(range));
+ Range layout_range(TextIndexToLayoutIndex(range.start()),
+ TextIndexToLayoutIndex(range.end()));
+ DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range));
+
+ std::vector<Rect> rects;
+ if (layout_range.is_empty())
+ return rects;
+ std::vector<Range> bounds;
+
+ // Add a Range for each run/selection intersection.
+ // TODO(msw): The bounds should probably not always be leading the range ends.
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ Range intersection = run->range.Intersect(layout_range);
+ if (intersection.IsValid()) {
+ DCHECK(!intersection.is_reversed());
+ Range range_x(run->GetGlyphXBoundary(intersection.start(), false),
+ run->GetGlyphXBoundary(intersection.end(), false));
+ if (range_x.is_empty())
+ continue;
+ range_x = Range(range_x.GetMin(), range_x.GetMax());
+ // Union this with the last range if they're adjacent.
+ DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin());
+ if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
+ range_x = Range(bounds.back().GetMin(), range_x.GetMax());
+ bounds.pop_back();
+ }
+ bounds.push_back(range_x);
+ }
+ }
+ for (size_t i = 0; i < bounds.size(); ++i) {
+ std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]);
+ rects.insert(rects.end(), current_rects.begin(), current_rects.end());
+ }
+ return rects;
+}
+
+size_t RenderTextHarfBuzz::TextIndexToLayoutIndex(size_t index) const {
+ DCHECK_LE(index, text().length());
+ ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
+ CHECK_GE(i, 0);
+ // Clamp layout indices to the length of the text actually used for layout.
+ return std::min<size_t>(GetLayoutText().length(), i);
+}
+
+size_t RenderTextHarfBuzz::LayoutIndexToTextIndex(size_t index) const {
+ if (!obscured())
+ return index;
+
+ DCHECK_LE(index, GetLayoutText().length());
+ const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
+ DCHECK_LE(text_index, text().length());
+ return text_index;
+}
+
+bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
+ return true;
+ if (!IsValidLogicalIndex(index))
+ return false;
+ EnsureLayout();
+ // Disallow indices amid multi-character graphemes by checking glyph bounds.
+ // These characters are not surrogate-pairs, but may yield a single glyph:
+ // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
+ // \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair.
+ return GetGlyphBounds(index) != GetGlyphBounds(index - 1);
+}
+
+void RenderTextHarfBuzz::ResetLayout() {
+ needs_layout_ = true;
+}
+
+void RenderTextHarfBuzz::EnsureLayout() {
+ if (needs_layout_) {
+ runs_.clear();
+
+ if (!GetLayoutText().empty()) {
+ ItemizeText();
+
+ for (size_t i = 0; i < runs_.size(); ++i)
+ ShapeRun(runs_[i]);
+
+ // Precalculate run width information.
+ size_t preceding_run_widths = 0;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ run->preceding_run_widths = preceding_run_widths;
+ preceding_run_widths += run->width;
+ }
+ }
+
+ needs_layout_ = false;
+ std::vector<internal::Line> empty_lines;
+ set_lines(&empty_lines);
+ }
+
+ if (lines().empty()) {
+ std::vector<internal::Line> lines;
+ lines.push_back(internal::Line());
+ lines[0].baseline = font_list().GetBaseline();
+ lines[0].size.set_height(font_list().GetHeight());
+
+ int current_x = 0;
+ SkPaint paint;
+
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]];
+ internal::LineSegment segment;
+ segment.x_range = Range(current_x, current_x + run.width);
+ segment.char_range = run.range;
+ segment.run = i;
+ lines[0].segments.push_back(segment);
+
+ paint.setTypeface(run.skia_face.get());
+ paint.setTextSize(run.font_size);
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+
+ lines[0].size.set_width(lines[0].size.width() + run.width);
+ lines[0].size.set_height(std::max(lines[0].size.height(),
+ SkScalarRoundToInt(metrics.fDescent - metrics.fAscent)));
+ lines[0].baseline = std::max(lines[0].baseline,
+ SkScalarRoundToInt(-metrics.fAscent));
+ }
+
+ set_lines(&lines);
+ }
+}
+
+void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
+ DCHECK(!needs_layout_);
+
+ int current_x = 0;
+
+ internal::SkiaTextRenderer renderer(canvas);
+ ApplyFadeEffects(&renderer);
+ ApplyTextShadows(&renderer);
+
+#if defined(OS_WIN)
+ bool smoothing_enabled;
+ bool cleartype_enabled;
+ GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
+ // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
+ renderer.SetFontSmoothingSettings(
+ smoothing_enabled, cleartype_enabled && !background_is_transparent(),
+ smoothing_enabled /* subpixel_positioning */);
+#endif
+
+ ApplyCompositionAndSelectionStyles();
+
+ const Vector2d line_offset = GetLineOffset(0);
+
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]];
+ renderer.SetTypeface(run.skia_face.get());
+ renderer.SetTextSize(run.font_size);
+
+ canvas->Save();
+ Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline);
+ canvas->Translate(origin);
+
+ for (BreakList<SkColor>::const_iterator it =
+ colors().GetBreak(run.range.start());
+ it != colors().breaks().end() && it->first < run.range.end();
+ ++it) {
+ const Range intersection = colors().GetRange(it).Intersect(run.range);
+ const Range colored_glyphs = run.CharRangeToGlyphRange(intersection);
+ // The range may be empty if a portion of a multi-character grapheme is
+ // selected, yielding two colors for a single glyph. For now, this just
+ // paints the glyph with a single style, but it should paint it twice,
+ // clipped according to selection bounds. See http://crbug.com/366786
+ if (colored_glyphs.is_empty())
+ continue;
+
+ renderer.SetForegroundColor(it->second);
+ renderer.DrawPosText(&run.positions[colored_glyphs.start()],
+ &run.glyphs[colored_glyphs.start()],
+ colored_glyphs.length());
+ int width = (colored_glyphs.end() == run.glyph_count ? run.width :
+ run.positions[colored_glyphs.end()].x()) -
+ run.positions[colored_glyphs.start()].x();
+ renderer.DrawDecorations(0, 0, width, run.underline, run.strike,
+ run.diagonal_strike);
+ }
+
+ canvas->Restore();
+ current_x += run.width;
+ }
+
+ renderer.EndDiagonalStrike();
+
+ UndoCompositionAndSelectionStyles();
+}
+
+size_t RenderTextHarfBuzz::GetRunContainingCaret(
+ const SelectionModel& caret) const {
+ DCHECK(!needs_layout_);
+ size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
+ LogicalCursorDirection affinity = caret.caret_affinity();
+ for (size_t run = 0; run < runs_.size(); ++run) {
+ if (RangeContainsCaret(runs_[run]->range, layout_position, affinity))
+ return run;
+ }
+ return runs_.size();
+}
+
+size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const {
+ DCHECK(!needs_layout_);
+ if (x < 0)
+ return runs_.size();
+ // Find the text run containing the argument point (assumed already offset).
+ int current_x = 0;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ size_t run = visual_to_logical_[i];
+ current_x += runs_[run]->width;
+ if (x < current_x) {
+ *offset = x - (current_x - runs_[run]->width);
+ return run;
+ }
+ }
+ return runs_.size();
+}
+
+SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run) {
+ size_t position = LayoutIndexToTextIndex(run->range.start());
+ position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD);
+ return SelectionModel(position, CURSOR_BACKWARD);
+}
+
+SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run) {
+ size_t position = LayoutIndexToTextIndex(run->range.end());
+ position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
+ return SelectionModel(position, CURSOR_FORWARD);
+}
+
+void RenderTextHarfBuzz::ItemizeText() {
+ const base::string16& text = GetLayoutText();
+ const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ DCHECK_NE(0U, text.length());
+
+ // If ICU fails to itemize the text, we create a run that spans the entire
+ // text. This is needed because leaving the runs set empty causes some clients
+ // to misbehave since they expect non-zero text metrics from a non-empty text.
+ base::i18n::BiDiLineIterator bidi_iterator;
+ if (!bidi_iterator.Open(text, is_text_rtl, false)) {
+ internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
+ run->range = Range(0, text.length());
+ runs_.push_back(run);
+ visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0);
+ return;
+ }
+
+ // Temporarily apply composition underlines and selection colors.
+ ApplyCompositionAndSelectionStyles();
+
+ // Build the list of runs from the script items and ranged styles. Use an
+ // empty color BreakList to avoid breaking runs at color boundaries.
+ BreakList<SkColor> empty_colors;
+ empty_colors.SetMax(text.length());
+ internal::StyleIterator style(empty_colors, styles());
+
+ for (size_t run_break = 0; run_break < text.length();) {
+ internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
+ run->range.set_start(run_break);
+ run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
+ (style.style(ITALIC) ? Font::ITALIC : 0);
+ run->strike = style.style(STRIKE);
+ run->diagonal_strike = style.style(DIAGONAL_STRIKE);
+ run->underline = style.style(UNDERLINE);
+
+ int32 script_item_break = 0;
+ bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level);
+ // Odd BiDi embedding levels correspond to RTL runs.
+ run->is_rtl = (run->level % 2) == 1;
+ // Find the length and script of this script run.
+ script_item_break = ScriptInterval(text, run_break,
+ script_item_break - run_break, &run->script) + run_break;
+
+ // Find the next break and advance the iterators as needed.
+ run_break = std::min(static_cast<size_t>(script_item_break),
+ TextIndexToLayoutIndex(style.GetRange().end()));
+
+ // Break runs adjacent to character substrings in certain code blocks.
+ // This avoids using their fallback fonts for more characters than needed,
+ // in cases like "\x25B6 Media Title", etc. http://crbug.com/278913
+ if (run_break > run->range.start())
+ run_break = FindUnusualCharacter(text, run->range.start(), run_break);
+
+ DCHECK(IsValidCodePointIndex(text, run_break));
+ style.UpdatePosition(LayoutIndexToTextIndex(run_break));
+ run->range.set_end(run_break);
+
+ runs_.push_back(run);
+ }
+
+ // Undo the temporarily applied composition underlines and selection colors.
+ UndoCompositionAndSelectionStyles();
+
+ const size_t num_runs = runs_.size();
+ std::vector<UBiDiLevel> levels(num_runs);
+ for (size_t i = 0; i < num_runs; ++i)
+ levels[i] = runs_[i]->level;
+ visual_to_logical_.resize(num_runs);
+ ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]);
+ logical_to_visual_.resize(num_runs);
+ ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]);
+}
+
+void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
+ const base::string16& text = GetLayoutText();
+ // TODO(ckocagil|yukishiino): Implement font fallback.
+ const Font& primary_font = font_list().GetPrimaryFont();
+ run->skia_face = internal::CreateSkiaTypeface(primary_font.GetFontName(),
+ run->font_style);
+ run->font_size = primary_font.GetFontSize();
+
+ hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(),
+ run->font_size);
+
+ // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz
+ // buffer holds our text, run information to be used by the shaping engine,
+ // and the resulting glyph data.
+ hb_buffer_t* buffer = hb_buffer_create();
+ hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()),
+ text.length(), run->range.start(), run->range.length());
+ hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script));
+ hb_buffer_set_direction(buffer,
+ run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+ // TODO(ckocagil): Should we determine the actual language?
+ hb_buffer_set_language(buffer, hb_language_get_default());
+
+ // Shape the text.
+ hb_shape(harfbuzz_font, buffer, NULL, 0);
+
+ // Populate the run fields with the resulting glyph data in the buffer.
+ unsigned int glyph_count = 0;
+ hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count);
+ hb_glyph_position_t* hb_positions = hb_buffer_get_glyph_positions(buffer,
+ NULL);
+ run->glyph_count = glyph_count;
+ run->glyphs.reset(new uint16[run->glyph_count]);
+ run->glyph_to_char.reset(new uint32[run->glyph_count]);
+ run->positions.reset(new SkPoint[run->glyph_count]);
+ for (size_t i = 0; i < run->glyph_count; ++i) {
+ run->glyphs[i] = infos[i].codepoint;
+ run->glyph_to_char[i] = infos[i].cluster;
+ const int x_offset =
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset));
+ const int y_offset =
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset));
+ run->positions[i].set(run->width + x_offset, y_offset);
+ run->width +=
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance));
+ }
+
+ hb_buffer_destroy(buffer);
+ hb_font_destroy(harfbuzz_font);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/render_text_harfbuzz.h b/chromium/ui/gfx/render_text_harfbuzz.h
new file mode 100644
index 00000000000..59ce92f21c3
--- /dev/null
+++ b/chromium/ui/gfx/render_text_harfbuzz.h
@@ -0,0 +1,130 @@
+// 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_GFX_RENDER_TEXT_HARFBUZZ_H_
+#define UI_GFX_RENDER_TEXT_HARFBUZZ_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "third_party/harfbuzz-ng/src/hb.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "ui/gfx/render_text.h"
+
+namespace gfx {
+
+namespace internal {
+
+struct GFX_EXPORT TextRunHarfBuzz {
+ TextRunHarfBuzz();
+ ~TextRunHarfBuzz();
+
+ // Returns the index of the first glyph that corresponds to the character at
+ // |pos|.
+ size_t CharToGlyph(size_t pos) const;
+
+ // Returns the corresponding glyph range of the given character range.
+ // |range| is in text-space (0 corresponds to |GetLayoutText()[0]|). Returned
+ // value is in run-space (0 corresponds to the first glyph in the run).
+ Range CharRangeToGlyphRange(const Range& range) const;
+
+ // Returns whether the given shaped run contains any missing glyphs.
+ bool HasMissingGlyphs() const;
+
+ // Returns the X coordinate of the leading or |trailing| edge of the glyph
+ // starting at |text_index|, relative to the left of the text (not the view).
+ int GetGlyphXBoundary(size_t text_index, bool trailing) const;
+
+ int width;
+ int preceding_run_widths;
+ Range range;
+ bool is_rtl;
+ UBiDiLevel level;
+ UScriptCode script;
+
+ scoped_ptr<uint16[]> glyphs;
+ scoped_ptr<SkPoint[]> positions;
+ scoped_ptr<uint32[]> glyph_to_char;
+ size_t glyph_count;
+
+ skia::RefPtr<SkTypeface> skia_face;
+ int font_size;
+ int font_style;
+ bool strike;
+ bool diagonal_strike;
+ bool underline;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz);
+};
+
+} // namespace internal
+
+class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
+ public:
+ RenderTextHarfBuzz();
+ virtual ~RenderTextHarfBuzz();
+
+ // Overridden from RenderText.
+ virtual Size GetStringSize() OVERRIDE;
+ virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE;
+ virtual std::vector<FontSpan> GetFontSpansForTesting() OVERRIDE;
+
+ protected:
+ // Overridden from RenderText.
+ virtual int GetLayoutTextBaseline() OVERRIDE;
+ virtual SelectionModel AdjacentCharSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) OVERRIDE;
+ virtual SelectionModel AdjacentWordSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) OVERRIDE;
+ virtual Range GetGlyphBounds(size_t index) OVERRIDE;
+ virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
+ virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
+ virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
+ virtual void ResetLayout() OVERRIDE;
+ virtual void EnsureLayout() OVERRIDE;
+ virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
+
+ private:
+ friend class RenderTextTest;
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_RunDirection);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks);
+
+ // Return the run index that contains the argument; or the length of the
+ // |runs_| vector if argument exceeds the text length or width.
+ size_t GetRunContainingCaret(const SelectionModel& caret) const;
+ size_t GetRunContainingXCoord(int x, int* offset) const;
+
+ // Given a |run|, returns the SelectionModel that contains the logical first
+ // or last caret position inside (not at a boundary of) the run.
+ // The returned value represents a cursor/caret position without a selection.
+ SelectionModel FirstSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run);
+ SelectionModel LastSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run);
+
+ // Break the text into logical runs and populate the visual <-> logical maps.
+ void ItemizeText();
+
+ // Shape the glyphs needed for the text |run|.
+ void ShapeRun(internal::TextRunHarfBuzz* run);
+
+ // Text runs in logical order.
+ ScopedVector<internal::TextRunHarfBuzz> runs_;
+
+ // Maps visual run indices to logical run indices and vice versa.
+ std::vector<int32_t> visual_to_logical_;
+ std::vector<int32_t> logical_to_visual_;
+
+ bool needs_layout_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzz);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_RENDER_TEXT_HARFBUZZ_H_
diff --git a/chromium/ui/gfx/render_text_mac.cc b/chromium/ui/gfx/render_text_mac.cc
index 4feb9302c18..68780f84b94 100644
--- a/chromium/ui/gfx/render_text_mac.cc
+++ b/chromium/ui/gfx/render_text_mac.cc
@@ -45,7 +45,7 @@ std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() {
std::vector<RenderText::FontSpan> spans;
for (size_t i = 0; i < runs_.size(); ++i) {
- gfx::Font font(runs_[i].font_name, runs_[i].text_size);
+ Font font(runs_[i].font_name, runs_[i].text_size);
const CFRange cf_range = CTRunGetStringRange(runs_[i].ct_run);
const Range range(cf_range.location, cf_range.location + cf_range.length);
spans.push_back(RenderText::FontSpan(font, range));
@@ -93,9 +93,9 @@ size_t RenderTextMac::LayoutIndexToTextIndex(size_t index) const {
return index;
}
-bool RenderTextMac::IsCursorablePosition(size_t position) {
+bool RenderTextMac::IsValidCursorIndex(size_t index) {
// TODO(asvitkine): Implement this. http://crbug.com/131618
- return true;
+ return IsValidLogicalIndex(index);
}
void RenderTextMac::ResetLayout() {
@@ -111,8 +111,8 @@ void RenderTextMac::EnsureLayout() {
runs_.clear();
runs_valid_ = false;
- const Font& font = GetPrimaryFont();
- CTFontRef ct_font = base::mac::NSToCFCast(font.GetNativeFont());
+ CTFontRef ct_font = base::mac::NSToCFCast(
+ font_list().GetPrimaryFont().GetNativeFont());
const void* keys[] = { kCTFontAttributeName };
const void* values[] = { ct_font };
@@ -174,6 +174,8 @@ void RenderTextMac::DrawVisualText(Canvas* canvas) {
renderer.DrawDecorations(run.origin.x(), run.origin.y(), run.width,
run.underline, run.strike, run.diagonal_strike);
}
+
+ renderer.EndDiagonalStrike();
}
RenderTextMac::TextRun::TextRun()
@@ -209,7 +211,7 @@ void RenderTextMac::ApplyStyles(CFMutableAttributedStringRef attr_string,
end = TextIndexToLayoutIndex(style.GetRange().end());
const CFRange range = CFRangeMake(i, end - i);
base::ScopedCFTypeRef<CGColorRef> foreground(
- gfx::CGColorCreateFromSkColor(style.color()));
+ CGColorCreateFromSkColor(style.color()));
CFAttributedStringSetAttribute(attr_string, range,
kCTForegroundColorAttributeName, foreground);
CFArrayAppendValue(attributes_, foreground);
@@ -252,9 +254,9 @@ void RenderTextMac::ComputeRuns() {
// TODO(asvitkine): Don't use GetLineOffset() until draw time, since it may be
// updated based on alignment changes without resetting the layout.
- gfx::Vector2d text_offset = GetLineOffset(0);
+ Vector2d text_offset = GetLineOffset(0);
// Skia will draw glyphs with respect to the baseline.
- text_offset += gfx::Vector2d(0, common_baseline_);
+ text_offset += Vector2d(0, common_baseline_);
const SkScalar x = SkIntToScalar(text_offset.x());
const SkScalar y = SkIntToScalar(text_offset.y());
@@ -323,7 +325,7 @@ void RenderTextMac::ComputeRuns() {
base::mac::GetValueFromDictionary<CGColorRef>(
attributes, kCTForegroundColorAttributeName);
if (foreground)
- run->foreground = gfx::CGColorRefToSkColor(foreground);
+ run->foreground = CGColorRefToSkColor(foreground);
const CFNumberRef underline =
base::mac::GetValueFromDictionary<CFNumberRef>(
@@ -337,7 +339,7 @@ void RenderTextMac::ComputeRuns() {
runs_valid_ = true;
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextMac;
}
diff --git a/chromium/ui/gfx/render_text_mac.h b/chromium/ui/gfx/render_text_mac.h
index 3a18a0fad45..ad03b845935 100644
--- a/chromium/ui/gfx/render_text_mac.h
+++ b/chromium/ui/gfx/render_text_mac.h
@@ -44,7 +44,7 @@ class RenderTextMac : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/render_text_ozone.cc b/chromium/ui/gfx/render_text_ozone.cc
index 058b5a6389d..fb5ef993d8b 100644
--- a/chromium/ui/gfx/render_text_ozone.cc
+++ b/chromium/ui/gfx/render_text_ozone.cc
@@ -6,7 +6,7 @@
namespace gfx {
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return NULL;
}
diff --git a/chromium/ui/gfx/render_text_pango.cc b/chromium/ui/gfx/render_text_pango.cc
index f120a5c10bb..a1269264617 100644
--- a/chromium/ui/gfx/render_text_pango.cc
+++ b/chromium/ui/gfx/render_text_pango.cc
@@ -40,8 +40,7 @@ bool IsForwardMotion(VisualCursorDirection direction, const PangoItem* item) {
}
// Checks whether |range| contains |index|. This is not the same as calling
-// |range.Contains(gfx::Range(index))| - as that would return true when
-// |index| == |range.end()|.
+// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
bool IndexInRange(const Range& range, size_t index) {
return index >= range.start() && index < range.end();
}
@@ -211,6 +210,7 @@ SelectionModel RenderTextPango::AdjacentWordSelectionModel(
}
Range RenderTextPango::GetGlyphBounds(size_t index) {
+ EnsureLayout();
PangoRectangle pos;
pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos);
// TODO(derat): Support fractional ranges for subpixel positioning?
@@ -248,7 +248,7 @@ std::vector<Rect> RenderTextPango::GetSubstringBounds(const Range& range) {
size_t RenderTextPango::TextIndexToLayoutIndex(size_t index) const {
DCHECK(layout_);
- ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index);
+ ptrdiff_t offset = UTF16IndexToOffset(text(), 0, index);
// Clamp layout indices to the length of the text actually used for layout.
offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1));
const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset);
@@ -259,24 +259,19 @@ size_t RenderTextPango::LayoutIndexToTextIndex(size_t index) const {
DCHECK(layout_);
const char* layout_pointer = layout_text_ + index;
const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer);
- return gfx::UTF16OffsetToIndex(text(), 0, offset);
+ return UTF16OffsetToIndex(text(), 0, offset);
}
-bool RenderTextPango::IsCursorablePosition(size_t position) {
- if (position == 0 && text().empty())
+bool RenderTextPango::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
return true;
- if (position >= text().length())
- return position == text().length();
- if (!gfx::IsValidCodePointIndex(text(), position))
+ if (!IsValidLogicalIndex(index))
return false;
EnsureLayout();
- ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position);
- // Check that the index corresponds with a valid text code point, that it is
- // marked as a legitimate cursor position by Pango, and that it is not
- // truncated from layout text (its glyph is shown on screen).
- return (offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position &&
- offset < g_utf8_strlen(layout_text_, -1));
+ ptrdiff_t offset = UTF16IndexToOffset(text(), 0, index);
+ // Check that the index is marked as a legitimate cursor position by Pango.
+ return offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position;
}
void RenderTextPango::ResetLayout() {
@@ -353,7 +348,7 @@ void RenderTextPango::SetupPangoAttributes(PangoLayout* layout) {
const size_t italic_end = styles()[ITALIC].GetRange(italic).end();
const size_t style_end = std::min(bold_end, italic_end);
if (style != font_list().GetFontStyle()) {
- FontList derived_font_list = font_list().DeriveFontList(style);
+ FontList derived_font_list = font_list().DeriveWithStyle(style);
ScopedPangoFontDescription desc(pango_font_description_from_string(
derived_font_list.GetFontDescriptionString().c_str()));
@@ -390,14 +385,31 @@ void RenderTextPango::DrawVisualText(Canvas* canvas) {
ApplyTextShadows(&renderer);
// TODO(derat): Use font-specific params: http://crbug.com/125235
- const gfx::FontRenderParams& render_params =
- gfx::GetDefaultFontRenderParams();
+ const FontRenderParams& render_params = GetDefaultFontRenderParams();
const bool use_subpixel_rendering =
render_params.subpixel_rendering !=
- gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE;
+ FontRenderParams::SUBPIXEL_RENDERING_NONE;
renderer.SetFontSmoothingSettings(
render_params.antialiasing,
- use_subpixel_rendering && !background_is_transparent());
+ use_subpixel_rendering && !background_is_transparent(),
+ render_params.subpixel_positioning);
+
+ SkPaint::Hinting skia_hinting = SkPaint::kNormal_Hinting;
+ switch (render_params.hinting) {
+ case FontRenderParams::HINTING_NONE:
+ skia_hinting = SkPaint::kNo_Hinting;
+ break;
+ case FontRenderParams::HINTING_SLIGHT:
+ skia_hinting = SkPaint::kSlight_Hinting;
+ break;
+ case FontRenderParams::HINTING_MEDIUM:
+ skia_hinting = SkPaint::kNormal_Hinting;
+ break;
+ case FontRenderParams::HINTING_FULL:
+ skia_hinting = SkPaint::kFull_Hinting;
+ break;
+ }
+ renderer.SetFontHinting(skia_hinting);
// Temporarily apply composition underlines and selection colors.
ApplyCompositionAndSelectionStyles();
@@ -468,6 +480,8 @@ void RenderTextPango::DrawVisualText(Canvas* canvas) {
} while (glyph_index < glyph_count);
}
+ renderer.EndDiagonalStrike();
+
// Undo the temporarily applied composition underlines and selection colors.
UndoCompositionAndSelectionStyles();
}
@@ -507,7 +521,7 @@ size_t RenderTextPango::GetGlyphTextIndex(PangoLayoutRun* run,
run->glyphs->log_clusters[glyph_index]);
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextPango;
}
diff --git a/chromium/ui/gfx/render_text_pango.h b/chromium/ui/gfx/render_text_pango.h
index ba7361c4d30..4c62e0aab89 100644
--- a/chromium/ui/gfx/render_text_pango.h
+++ b/chromium/ui/gfx/render_text_pango.h
@@ -36,7 +36,7 @@ class RenderTextPango : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index c8c50d42814..4686066f088 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -14,6 +14,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/render_text_harfbuzz.h"
#if defined(OS_WIN)
#include "base/win/windows_version.h"
@@ -24,9 +25,9 @@
#include "ui/gfx/render_text_pango.h"
#endif
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#endif
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
namespace gfx {
@@ -44,8 +45,7 @@ const wchar_t kRtlLtrRtl[] = L"\x5d0" L"a" L"\x5d1";
#endif
// Checks whether |range| contains |index|. This is not the same as calling
-// |range.Contains(gfx::Range(index))| - as that would return true when
-// |index| == |range.end()|.
+// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
bool IndexInRange(const Range& range, size_t index) {
return index >= range.start() && index < range.end();
}
@@ -59,10 +59,6 @@ base::string16 GetSelectedText(RenderText* render_text) {
void SetRTL(bool rtl) {
// Override the current locale/direction.
base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
-#if defined(TOOLKIT_GTK)
- // Do the same for GTK, which does not rely on the ICU default locale.
- gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
-#endif
EXPECT_EQ(rtl, base::i18n::IsRTL());
}
@@ -283,10 +279,10 @@ TEST_F(RenderTextTest, ObscuredText) {
render_text->SetObscured(true);
// Surrogate pairs are counted as one code point.
- const char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
+ const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
render_text->SetText(invalid_surrogates);
EXPECT_EQ(ASCIIToUTF16("**"), render_text->GetLayoutText());
- const char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
+ const base::char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
render_text->SetText(valid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*"), render_text->GetLayoutText());
EXPECT_EQ(0U, render_text->cursor_position());
@@ -299,9 +295,9 @@ TEST_F(RenderTextTest, ObscuredText) {
EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(2U));
EXPECT_EQ(0U, render_text->LayoutIndexToTextIndex(0U));
EXPECT_EQ(2U, render_text->LayoutIndexToTextIndex(1U));
- EXPECT_TRUE(render_text->IsCursorablePosition(0U));
- EXPECT_FALSE(render_text->IsCursorablePosition(1U));
- EXPECT_TRUE(render_text->IsCursorablePosition(2U));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(0U));
+ EXPECT_FALSE(render_text->IsValidCursorIndex(1U));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(2U));
// FindCursorPosition() should not return positions between a surrogate pair.
render_text->SetDisplayRect(Rect(0, 0, 20, 20));
@@ -370,37 +366,127 @@ TEST_F(RenderTextTest, RevealObscuredText) {
EXPECT_EQ(ASCIIToUTF16("**********"), render_text->GetLayoutText());
// Text with invalid surrogates.
- const char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
+ const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
render_text->SetText(invalid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(0);
- const char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
+ const base::char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
EXPECT_EQ(invalid_expect_0, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(1);
- const char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
+ const base::char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
EXPECT_EQ(invalid_expect_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(2);
EXPECT_EQ(ASCIIToUTF16("**h**"), render_text->GetLayoutText());
// Text with valid surrogates before and after the reveal index.
- const char16 valid_surrogates[] =
+ const base::char16 valid_surrogates[] =
{0xD800, 0xDC00, 'h', 'o', 'p', 0xD800, 0xDC00, 0};
render_text->SetText(valid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(0);
- const char16 valid_expect_0_and_1[] = {0xD800, 0xDC00, '*', '*', '*', '*', 0};
+ const base::char16 valid_expect_0_and_1[] =
+ {0xD800, 0xDC00, '*', '*', '*', '*', 0};
EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(1);
EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(2);
EXPECT_EQ(ASCIIToUTF16("*h***"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(5);
- const char16 valid_expect_5_and_6[] = {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
+ const base::char16 valid_expect_5_and_6[] =
+ {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(6);
EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
}
+TEST_F(RenderTextTest, ElidedText) {
+ // TODO(skanuj) : Add more test cases for following
+ // - RenderText styles.
+ // - Cross interaction of truncate, elide and obscure.
+ // - ElideText tests from text_elider.cc.
+ struct {
+ const wchar_t* text;
+ const wchar_t* layout_text;
+ const bool elision_expected;
+ } cases[] = {
+ // Strings shorter than the elision width should be laid out in full.
+ { L"", L"" , false },
+ { L"M", L"" , false },
+ { L" . ", L" . " , false },
+ { kWeak, kWeak , false },
+ { kLtr, kLtr , false },
+ { kLtrRtl, kLtrRtl , false },
+ { kLtrRtlLtr, kLtrRtlLtr, false },
+ { kRtl, kRtl , false },
+ { kRtlLtr, kRtlLtr , false },
+ { kRtlLtrRtl, kRtlLtrRtl, false },
+ // Strings as long as the elision width should be laid out in full.
+ { L"012ab", L"012ab" , false },
+ // Long strings should be elided with an ellipsis appended at the end.
+ { L"012abc", L"012a\x2026", true },
+ { L"012ab" L"\x5d0\x5d1", L"012a\x2026", true },
+ { L"012a" L"\x5d1" L"b", L"012a\x2026", true },
+ // No RLM marker added as digits (012) have weak directionality.
+ { L"01" L"\x5d0\x5d1\x5d2", L"01\x5d0\x5d1\x2026", true },
+ // RLM marker added as "ab" have strong LTR directionality.
+ { L"ab" L"\x5d0\x5d1\x5d2", L"ab\x5d0\x5d1\x2026\x200f", true },
+ // Complex script is not handled. In this example, the "\x0915\x093f" is a
+ // compound glyph, but only half of it is elided.
+ { L"0123\x0915\x093f", L"0123\x0915\x2026", true },
+ // Surrogate pairs should be elided reasonably enough.
+ { L"0\x05e9\x05bc\x05c1\x05b8", L"0\x05e9\x05bc\x05c1\x05b8", false },
+ { L"0\x05e9\x05bc\x05c1\x05b8", L"0\x05e9\x05bc\x2026" , true },
+ { L"01\x05e9\x05bc\x05c1\x05b8", L"01\x05e9\x2026" , true },
+ { L"012\x05e9\x05bc\x05c1\x05b8", L"012\x2026\x200E" , true },
+ { L"012\xF0\x9D\x84\x9E", L"012\xF0\x2026" , true },
+ };
+
+ scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
+ expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ // Compute expected width
+ expected_render_text->SetText(WideToUTF16(cases[i].layout_text));
+ int expected_width = expected_render_text->GetContentWidth();
+
+ base::string16 input = WideToUTF16(cases[i].text);
+ // Extend the input text to ensure that it is wider than the layout_text,
+ // and so it will get elided.
+ if (cases[i].elision_expected)
+ input.append(WideToUTF16(L" MMMMMMMMMMM"));
+
+ render_text->SetText(input);
+ render_text->SetDisplayRect(Rect(0, 0, expected_width, 100));
+ EXPECT_EQ(input, render_text->text())
+ << "->For case " << i << ": " << cases[i].text << "\n";
+ EXPECT_EQ(WideToUTF16(cases[i].layout_text), render_text->GetLayoutText())
+ << "->For case " << i << ": " << cases[i].text << "\n";
+ expected_render_text->SetText(base::string16());
+ }
+}
+
+TEST_F(RenderTextTest, ElidedObscuredText) {
+ scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
+ expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
+ expected_render_text->SetText(WideToUTF16(L"**\x2026"));
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+ render_text->SetDisplayRect(
+ Rect(0, 0, expected_render_text->GetContentWidth(), 100));
+ render_text->SetObscured(true);
+ render_text->SetText(WideToUTF16(L"abcdef"));
+ EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
+ EXPECT_EQ(WideToUTF16(L"**\x2026"), render_text->GetLayoutText());
+}
+
TEST_F(RenderTextTest, TruncatedText) {
struct {
const wchar_t* text;
@@ -742,7 +828,7 @@ TEST_F(RenderTextTest, MoveCursorLeftRight_MeiryoUILigatures) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
// Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
// (code point) has unique bounds, so mid-glyph cursoring should be possible.
- render_text->SetFont(Font("Meiryo UI", 12));
+ render_text->SetFontList(FontList("Meiryo UI, 12px"));
render_text->SetText(WideToUTF16(L"ff ffi"));
EXPECT_EQ(0U, render_text->cursor_position());
for (size_t i = 0; i < render_text->text().length(); ++i) {
@@ -806,26 +892,74 @@ TEST_F(RenderTextTest, GraphemePositions) {
{ kText3, 50, 6, 6 },
};
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
if (base::win::GetVersion() < base::win::VERSION_VISTA)
return;
#endif
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i].text);
size_t next = render_text->IndexOfAdjacentGrapheme(cases[i].index,
CURSOR_FORWARD);
EXPECT_EQ(cases[i].expected_next, next);
- EXPECT_TRUE(render_text->IsCursorablePosition(next));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(next));
size_t previous = render_text->IndexOfAdjacentGrapheme(cases[i].index,
CURSOR_BACKWARD);
EXPECT_EQ(cases[i].expected_previous, previous);
- EXPECT_TRUE(render_text->IsCursorablePosition(previous));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(previous));
+ }
+}
+
+TEST_F(RenderTextTest, MidGraphemeSelectionBounds) {
+#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return;
+#endif
+
+ // Test that selection bounds may be set amid multi-character graphemes.
+ const base::string16 kHindi = WideToUTF16(L"\x0915\x093f");
+ const base::string16 kThai = WideToUTF16(L"\x0e08\x0e33");
+ const base::string16 cases[] = { kHindi, kThai };
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ for (size_t i = 0; i < arraysize(cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
+ render_text->SetText(cases[i]);
+ EXPECT_TRUE(render_text->IsValidLogicalIndex(1));
+#if !defined(OS_MACOSX)
+ EXPECT_FALSE(render_text->IsValidCursorIndex(1));
+#endif
+ EXPECT_TRUE(render_text->SelectRange(Range(2, 1)));
+ EXPECT_EQ(Range(2, 1), render_text->selection());
+ EXPECT_EQ(1U, render_text->cursor_position());
+ // Although selection bounds may be set within a multi-character grapheme,
+ // cursor movement (e.g. via arrow key) should avoid those indices.
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
+ EXPECT_EQ(0U, render_text->cursor_position());
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
+ EXPECT_EQ(2U, render_text->cursor_position());
+ }
+}
+
+TEST_F(RenderTextTest, FindCursorPosition) {
+ const wchar_t* kTestStrings[] = { kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl };
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetDisplayRect(Rect(0, 0, 100, 20));
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ for(size_t j = 0; j < render_text->text().length(); ++j) {
+ const Range range(render_text->GetGlyphBounds(j));
+ // Test a point just inside the leading edge of the glyph bounds.
+ int x = range.is_reversed() ? range.GetMax() - 1 : range.GetMin() + 1;
+ EXPECT_EQ(j, render_text->FindCursorPosition(Point(x, 0)).caret_pos());
+ }
}
}
@@ -855,9 +989,8 @@ TEST_F(RenderTextTest, EdgeSelectionModels) {
{ kHebrewLatin, base::i18n::RIGHT_TO_LEFT },
};
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
if (base::win::GetVersion() < base::win::VERSION_VISTA)
return;
#endif
@@ -1210,13 +1343,6 @@ TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) {
EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline());
}
-TEST_F(RenderTextTest, SetFont) {
- scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetFont(Font("Arial", 12));
- EXPECT_EQ("Arial", render_text->GetPrimaryFont().GetFontName());
- EXPECT_EQ(12, render_text->GetPrimaryFont().GetFontSize());
-}
-
TEST_F(RenderTextTest, SetFontList) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
render_text->SetFontList(FontList("Arial,Symbol, 13px"));
@@ -1224,7 +1350,7 @@ TEST_F(RenderTextTest, SetFontList) {
ASSERT_EQ(2U, fonts.size());
EXPECT_EQ("Arial", fonts[0].GetFontName());
EXPECT_EQ("Symbol", fonts[1].GetFontName());
- EXPECT_EQ(13, render_text->GetPrimaryFont().GetFontSize());
+ EXPECT_EQ(13, render_text->font_list().GetFontSize());
}
TEST_F(RenderTextTest, StringSizeBoldWidth) {
@@ -1254,20 +1380,20 @@ TEST_F(RenderTextTest, StringSizeHeight) {
WideToUTF16(L"\x05e0\x05b8"), // Hebrew
};
- Font default_font;
- Font larger_font = default_font.DeriveFont(24, default_font.GetStyle());
- EXPECT_GT(larger_font.GetHeight(), default_font.GetHeight());
+ const FontList default_font_list;
+ const FontList& larger_font_list = default_font_list.DeriveWithSizeDelta(24);
+ EXPECT_GT(larger_font_list.GetHeight(), default_font_list.GetHeight());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetFont(default_font);
+ render_text->SetFontList(default_font_list);
render_text->SetText(cases[i]);
const int height1 = render_text->GetStringSize().height();
EXPECT_GT(height1, 0);
// Check that setting the larger font increases the height.
- render_text->SetFont(larger_font);
+ render_text->SetFontList(larger_font_list);
const int height2 = render_text->GetStringSize().height();
EXPECT_GT(height2, height1);
}
@@ -1364,8 +1490,8 @@ TEST_F(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
TEST_F(RenderTextTest, SameFontForParentheses) {
struct {
- const char16 left_char;
- const char16 right_char;
+ const base::char16 left_char;
+ const base::char16 right_char;
} punctuation_pairs[] = {
{ '(', ')' },
{ '{', '}' },
@@ -1642,11 +1768,7 @@ TEST_F(RenderTextTest, DisplayRectShowsCursorRTL) {
// Changing colors between or inside ligated glyphs should not break shaping.
TEST_F(RenderTextTest, SelectionKeepsLigatures) {
- const wchar_t* kTestStrings[] = {
- L"\x644\x623",
- L"\x633\x627"
- };
-
+ const wchar_t* kTestStrings[] = { L"\x644\x623", L"\x633\x627" };
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
render_text->set_selection_color(SK_ColorRED);
Canvas canvas;
@@ -1656,8 +1778,7 @@ TEST_F(RenderTextTest, SelectionKeepsLigatures) {
const int expected_width = render_text->GetStringSize().width();
render_text->MoveCursorTo(SelectionModel(Range(0, 1), CURSOR_FORWARD));
EXPECT_EQ(expected_width, render_text->GetStringSize().width());
- // Draw the text. It shouldn't hit any DCHECKs or crash.
- // See http://crbug.com/214150
+ // Drawing the text should not DCHECK or crash; see http://crbug.com/262119
render_text->Draw(&canvas);
render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
}
@@ -1782,7 +1903,6 @@ TEST_F(RenderTextTest, Multiline_Newline) {
}
}
-
TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) {
scoped_ptr<RenderTextWin> render_text(
static_cast<RenderTextWin*>(RenderText::CreateInstance()));
@@ -1804,4 +1924,120 @@ TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) {
}
#endif // defined(OS_WIN)
+TEST_F(RenderTextTest, HarfBuzz_CharToGlyph) {
+ struct {
+ uint32 glyph_to_char[4];
+ size_t char_to_glyph_expected[4];
+ Range char_range_to_glyph_range_expected[4];
+ bool is_rtl;
+ } cases[] = {
+ { // From string "A B C D" to glyphs "a b c d".
+ { 0, 1, 2, 3 },
+ { 0, 1, 2, 3 },
+ { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) },
+ false
+ },
+ { // From string "A B C D" to glyphs "d b c a".
+ { 3, 2, 1, 0 },
+ { 3, 2, 1, 0 },
+ { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) },
+ true
+ },
+ { // From string "A B C D" to glyphs "ab c c d".
+ { 0, 2, 2, 3 },
+ { 0, 0, 1, 3 },
+ { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) },
+ false
+ },
+ { // From string "A B C D" to glyphs "d c c ba".
+ { 3, 2, 2, 0 },
+ { 3, 3, 1, 0 },
+ { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) },
+ true
+ },
+ };
+
+ internal::TextRunHarfBuzz run;
+ run.range = Range(0, 4);
+ run.glyph_count = 4;
+ run.glyph_to_char.reset(new uint32[4]);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
+ run.glyph_to_char.get());
+ run.is_rtl = cases[i].is_rtl;
+ for (size_t j = 0; j < 4; ++j) {
+ SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
+ EXPECT_EQ(cases[i].char_to_glyph_expected[j], run.CharToGlyph(j));
+ EXPECT_EQ(cases[i].char_range_to_glyph_range_expected[j],
+ run.CharRangeToGlyphRange(Range(j, j + 1)));
+ }
+ }
+}
+
+TEST_F(RenderTextTest, HarfBuzz_RunDirection) {
+ RenderTextHarfBuzz render_text;
+ const base::string16 mixed =
+ WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3");
+ render_text.SetText(mixed);
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_TRUE(render_text.runs_[0]->is_rtl);
+ EXPECT_FALSE(render_text.runs_[1]->is_rtl);
+ EXPECT_TRUE(render_text.runs_[2]->is_rtl);
+}
+
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
+ RenderTextHarfBuzz render_text;
+
+ // The '\x25B6' "play character" should break runs. http://crbug.com/278913
+ render_text.SetText(WideToUTF16(L"x\x25B6y"));
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_EQ(Range(0, 1), render_text.runs_[0]->range);
+ EXPECT_EQ(Range(1, 2), render_text.runs_[1]->range);
+ EXPECT_EQ(Range(2, 3), render_text.runs_[2]->range);
+
+ render_text.SetText(WideToUTF16(L"x \x25B6 y"));
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_EQ(Range(0, 2), render_text.runs_[0]->range);
+ EXPECT_EQ(Range(2, 3), render_text.runs_[1]->range);
+ EXPECT_EQ(Range(3, 5), render_text.runs_[2]->range);
+}
+
+// Disabled on Mac because RenderTextMac doesn't implement GetGlyphBounds.
+#if !defined(OS_MACOSX)
+TEST_F(RenderTextTest, GlyphBounds) {
+ const wchar_t* kTestStrings[] = {
+ L"asdf 1234 qwer", L"\x0647\x0654", L"\x0645\x0631\x062D\x0628\x0627"
+ };
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ render_text->EnsureLayout();
+
+ for (size_t j = 0; j < render_text->text().length(); ++j)
+ EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty());
+ }
+}
+#endif
+
+// Remove this after making RTHB default in favor of RenderTextTest.GlyphBounds.
+TEST_F(RenderTextTest, HarfBuzz_GlyphBounds) {
+ const wchar_t* kTestStrings[] = {
+ L"asdf 1234 qwer", L"\x0647\x0654", L"\x0645\x0631\x062D\x0628\x0627"
+ };
+ scoped_ptr<RenderText> render_text(new RenderTextHarfBuzz);
+
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ render_text->EnsureLayout();
+
+ for (size_t j = 0; j < render_text->text().length(); ++j)
+ EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty());
+ }
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/render_text_win.cc b/chromium/ui/gfx/render_text_win.cc
index 4afbc7fa71e..f79577fde0a 100644
--- a/chromium/ui/gfx/render_text_win.cc
+++ b/chromium/ui/gfx/render_text_win.cc
@@ -86,7 +86,8 @@ bool ChooseFallbackFont(HDC hdc,
log_font.lfFaceName[0] = 0;
EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
if (log_font.lfFaceName[0]) {
- *result = Font(UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
+ *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
+ font.GetFontSize());
found_fallback = true;
}
}
@@ -117,11 +118,11 @@ void DeriveFontIfNecessary(int font_size,
const int current_style = (font->GetStyle() & kStyleMask);
const int current_size = font->GetFontSize();
if (current_style != target_style || current_size != font_size)
- *font = font->DeriveFont(font_size - current_size, target_style);
+ *font = font->Derive(font_size - current_size, target_style);
}
// Returns true if |c| is a Unicode BiDi control character.
-bool IsUnicodeBidiControlCharacter(char16 c) {
+bool IsUnicodeBidiControlCharacter(base::char16 c) {
return c == base::i18n::kRightToLeftMark ||
c == base::i18n::kLeftToRightMark ||
c == base::i18n::kLeftToRightEmbeddingMark ||
@@ -263,6 +264,26 @@ bool IsUnusualBlockCode(const UBlockCode block_code) {
block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
}
+// Returns the index of the first unusual character after a usual character or
+// vice versa. Unusual characters are defined by |IsUnusualBlockCode|.
+size_t FindUnusualCharacter(const base::string16& text,
+ size_t run_start,
+ size_t run_break) {
+ const int32 run_length = static_cast<int32>(run_break - run_start);
+ base::i18n::UTF16CharIterator iter(text.c_str() + run_start,
+ run_length);
+ const UBlockCode first_block_code = ublock_getCode(iter.get());
+ const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
+ while (iter.Advance() && iter.array_pos() < run_length) {
+ const UBlockCode current_block_code = ublock_getCode(iter.get());
+ if (current_block_code != first_block_code &&
+ (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
+ return run_start + iter.array_pos();
+ }
+ }
+ return run_break;
+}
+
} // namespace
namespace internal {
@@ -503,19 +524,14 @@ HDC RenderTextWin::cached_hdc_ = NULL;
// static
std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
-RenderTextWin::RenderTextWin()
- : RenderText(),
- needs_layout_(false) {
+RenderTextWin::RenderTextWin() : RenderText(), needs_layout_(false) {
set_truncate_length(kMaxUniscribeTextLength);
-
memset(&script_control_, 0, sizeof(script_control_));
memset(&script_state_, 0, sizeof(script_state_));
-
MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
}
-RenderTextWin::~RenderTextWin() {
-}
+RenderTextWin::~RenderTextWin() {}
Size RenderTextWin::GetStringSize() {
EnsureLayout();
@@ -662,6 +678,7 @@ SelectionModel RenderTextWin::AdjacentWordSelectionModel(
}
Range RenderTextWin::GetGlyphBounds(size_t index) {
+ EnsureLayout();
const size_t run_index =
GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
// Return edge bounds if the index is invalid or beyond the layout text size.
@@ -715,7 +732,7 @@ std::vector<Rect> RenderTextWin::GetSubstringBounds(const Range& range) {
size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
DCHECK_LE(index, text().length());
- ptrdiff_t i = obscured() ? gfx::UTF16IndexToOffset(text(), 0, index) : index;
+ ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
CHECK_GE(i, 0);
// Clamp layout indices to the length of the text actually used for layout.
return std::min<size_t>(GetLayoutText().length(), i);
@@ -726,24 +743,22 @@ size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const {
return index;
DCHECK_LE(index, GetLayoutText().length());
- const size_t text_index = gfx::UTF16OffsetToIndex(text(), 0, index);
+ const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
DCHECK_LE(text_index, text().length());
return text_index;
}
-bool RenderTextWin::IsCursorablePosition(size_t position) {
- if (position == 0 || position == text().length())
+bool RenderTextWin::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
return true;
+ if (!IsValidLogicalIndex(index))
+ return false;
EnsureLayout();
-
- // Check that the index is at a valid code point (not mid-surrgate-pair),
- // that it is not truncated from layout text (its glyph is shown on screen),
- // and that its glyph has distinct bounds (not mid-multi-character-grapheme).
- // An example of a multi-character-grapheme that is not a surrogate-pair is:
- // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
- return gfx::IsValidCodePointIndex(text(), position) &&
- position < LayoutIndexToTextIndex(GetLayoutText().length()) &&
- GetGlyphBounds(position) != GetGlyphBounds(position - 1);
+ // Disallow indices amid multi-character graphemes by checking glyph bounds.
+ // These characters are not surrogate-pairs, but may yield a single glyph:
+ // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
+ // \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair.
+ return GetGlyphBounds(index) != GetGlyphBounds(index - 1);
}
void RenderTextWin::ResetLayout() {
@@ -799,7 +814,8 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
// Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
renderer.SetFontSmoothingSettings(
- smoothing_enabled, cleartype_enabled && !background_is_transparent());
+ smoothing_enabled, cleartype_enabled && !background_is_transparent(),
+ smoothing_enabled /* subpixel_positioning */);
ApplyCompositionAndSelectionStyles();
@@ -841,7 +857,7 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
for (size_t k = glyph_range.start(); k < glyph_range.end(); ++k) {
pos[k - glyph_range.start()].set(
SkIntToScalar(text_offset.x() + run->offsets[k].du + segment_x),
- SkIntToScalar(text_offset.y() + run->offsets[k].dv));
+ SkIntToScalar(text_offset.y() - run->offsets[k].dv));
segment_x += run->advance_widths[k];
}
pos.back().set(SkIntToScalar(text_offset.x() + segment_x),
@@ -858,8 +874,13 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
const Range intersection =
colors().GetRange(it).Intersect(segment->char_range);
const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection);
+ // The range may be empty if a portion of a multi-character grapheme is
+ // selected, yielding two colors for a single glyph. For now, this just
+ // paints the glyph with a single style, but it should paint it twice,
+ // clipped according to selection bounds. See http://crbug.com/366786
+ if (colored_glyphs.is_empty())
+ continue;
DCHECK(glyph_range.Contains(colored_glyphs));
- DCHECK(!colored_glyphs.is_empty());
const SkPoint& start_pos =
pos[colored_glyphs.start() - glyph_range.start()];
const SkPoint& end_pos =
@@ -876,6 +897,8 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
preceding_segment_widths += segment_width;
}
+
+ renderer.EndDiagonalStrike();
}
UndoCompositionAndSelectionStyles();
@@ -926,7 +949,7 @@ void RenderTextWin::ItemizeLogicalText() {
for (size_t run_break = 0; run_break < layout_text_length;) {
internal::TextRun* run = new internal::TextRun();
run->range.set_start(run_break);
- run->font = GetPrimaryFont();
+ run->font = font_list().GetPrimaryFont();
run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
(style.style(ITALIC) ? Font::ITALIC : 0);
DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(),
@@ -952,20 +975,8 @@ void RenderTextWin::ItemizeLogicalText() {
// This avoids using their fallback fonts for more characters than needed,
// in cases like "\x25B6 Media Title", etc. http://crbug.com/278913
if (run_break > run->range.start()) {
- const size_t run_start = run->range.start();
- const int32 run_length = static_cast<int32>(run_break - run_start);
- base::i18n::UTF16CharIterator iter(layout_text.c_str() + run_start,
- run_length);
- const UBlockCode first_block_code = ublock_getCode(iter.get());
- const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
- while (iter.Advance() && iter.array_pos() < run_length) {
- const UBlockCode current_block_code = ublock_getCode(iter.get());
- if (current_block_code != first_block_code &&
- (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
- run_break = run_start + iter.array_pos();
- break;
- }
- }
+ run_break =
+ FindUnusualCharacter(layout_text, run->range.start(), run_break);
}
DCHECK(IsValidCodePointIndex(layout_text, run_break));
@@ -1271,7 +1282,7 @@ SelectionModel RenderTextWin::LastSelectionModelInsideRun(
return SelectionModel(position, CURSOR_FORWARD);
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextWin;
}
diff --git a/chromium/ui/gfx/render_text_win.h b/chromium/ui/gfx/render_text_win.h
index 1a1ba4805cb..4e8caf6484d 100644
--- a/chromium/ui/gfx/render_text_win.h
+++ b/chromium/ui/gfx/render_text_win.h
@@ -80,7 +80,7 @@ class RenderTextWin : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/safe_integer_conversions.h b/chromium/ui/gfx/safe_integer_conversions.h
index 523b1f3441f..ea9fde726a8 100644
--- a/chromium/ui/gfx/safe_integer_conversions.h
+++ b/chromium/ui/gfx/safe_integer_conversions.h
@@ -1,54 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_SAFE_INTEGER_CONVERSIONS_H_
-#define UI_GFX_SAFE_INTEGER_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/safe_integer_conversions.h"
-#include <cmath>
-#include <limits>
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-inline int ClampToInt(float value) {
- if (value != value)
- return 0; // no int NaN.
- if (value >= std::numeric_limits<int>::max())
- return std::numeric_limits<int>::max();
- if (value <= std::numeric_limits<int>::min())
- return std::numeric_limits<int>::min();
- return static_cast<int>(value);
-}
-
-inline int ToFlooredInt(float value) {
- return ClampToInt(std::floor(value));
-}
-
-inline int ToCeiledInt(float value) {
- return ClampToInt(std::ceil(value));
-}
-
-inline int ToRoundedInt(float value) {
- float rounded;
- if (value >= 0.0f)
- rounded = std::floor(value + 0.5f);
- else
- rounded = std::ceil(value - 0.5f);
- return ClampToInt(rounded);
-}
-
-inline bool IsExpressibleAsInt(float value) {
- if (value != value)
- return false; // no int NaN.
- if (value > std::numeric_limits<int>::max())
- return false;
- if (value < std::numeric_limits<int>::min())
- return false;
- return true;
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_SAFE_INTEGER_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/safe_integer_conversions_unittest.cc b/chromium/ui/gfx/safe_integer_conversions_unittest.cc
deleted file mode 100644
index 1268f8bbf32..00000000000
--- a/chromium/ui/gfx/safe_integer_conversions_unittest.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/safe_integer_conversions.h"
-
-#include <limits>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace gfx {
-
-TEST(SafeIntegerConversions, ClampToInt) {
- EXPECT_EQ(0, ClampToInt(std::numeric_limits<float>::quiet_NaN()));
-
- float max = std::numeric_limits<int>::max();
- float min = std::numeric_limits<int>::min();
- float infinity = std::numeric_limits<float>::infinity();
-
- int int_max = std::numeric_limits<int>::max();
- int int_min = std::numeric_limits<int>::min();
-
- EXPECT_EQ(int_max, ClampToInt(infinity));
- EXPECT_EQ(int_max, ClampToInt(max));
- EXPECT_EQ(int_max, ClampToInt(max + 100));
-
- EXPECT_EQ(-100, ClampToInt(-100.5f));
- EXPECT_EQ(0, ClampToInt(0));
- EXPECT_EQ(100, ClampToInt(100.5f));
-
- EXPECT_EQ(int_min, ClampToInt(-infinity));
- EXPECT_EQ(int_min, ClampToInt(min));
- EXPECT_EQ(int_min, ClampToInt(min - 100));
-}
-
-TEST(SafeIntegerConversions, ToFlooredInt) {
- EXPECT_EQ(0, ToFlooredInt(std::numeric_limits<float>::quiet_NaN()));
-
- float max = std::numeric_limits<int>::max();
- float min = std::numeric_limits<int>::min();
- float infinity = std::numeric_limits<float>::infinity();
-
- int int_max = std::numeric_limits<int>::max();
- int int_min = std::numeric_limits<int>::min();
-
- EXPECT_EQ(int_max, ToFlooredInt(infinity));
- EXPECT_EQ(int_max, ToFlooredInt(max));
- EXPECT_EQ(int_max, ToFlooredInt(max + 100));
-
- EXPECT_EQ(-101, ToFlooredInt(-100.5f));
- EXPECT_EQ(0, ToFlooredInt(0));
- EXPECT_EQ(100, ToFlooredInt(100.5f));
-
- EXPECT_EQ(int_min, ToFlooredInt(-infinity));
- EXPECT_EQ(int_min, ToFlooredInt(min));
- EXPECT_EQ(int_min, ToFlooredInt(min - 100));
-}
-
-TEST(SafeIntegerConversions, ToCeiledInt) {
- EXPECT_EQ(0, ToCeiledInt(std::numeric_limits<float>::quiet_NaN()));
-
- float max = std::numeric_limits<int>::max();
- float min = std::numeric_limits<int>::min();
- float infinity = std::numeric_limits<float>::infinity();
-
- int int_max = std::numeric_limits<int>::max();
- int int_min = std::numeric_limits<int>::min();
-
- EXPECT_EQ(int_max, ToCeiledInt(infinity));
- EXPECT_EQ(int_max, ToCeiledInt(max));
- EXPECT_EQ(int_max, ToCeiledInt(max + 100));
-
- EXPECT_EQ(-100, ToCeiledInt(-100.5f));
- EXPECT_EQ(0, ToCeiledInt(0));
- EXPECT_EQ(101, ToCeiledInt(100.5f));
-
- EXPECT_EQ(int_min, ToCeiledInt(-infinity));
- EXPECT_EQ(int_min, ToCeiledInt(min));
- EXPECT_EQ(int_min, ToCeiledInt(min - 100));
-}
-
-TEST(SafeIntegerConversions, ToRoundedInt) {
- EXPECT_EQ(0, ToRoundedInt(std::numeric_limits<float>::quiet_NaN()));
-
- float max = std::numeric_limits<int>::max();
- float min = std::numeric_limits<int>::min();
- float infinity = std::numeric_limits<float>::infinity();
-
- int int_max = std::numeric_limits<int>::max();
- int int_min = std::numeric_limits<int>::min();
-
- EXPECT_EQ(int_max, ToRoundedInt(infinity));
- EXPECT_EQ(int_max, ToRoundedInt(max));
- EXPECT_EQ(int_max, ToRoundedInt(max + 100));
-
- EXPECT_EQ(-100, ToRoundedInt(-100.1f));
- EXPECT_EQ(-101, ToRoundedInt(-100.5f));
- EXPECT_EQ(-101, ToRoundedInt(-100.9f));
- EXPECT_EQ(0, ToRoundedInt(0));
- EXPECT_EQ(100, ToRoundedInt(100.1f));
- EXPECT_EQ(101, ToRoundedInt(100.5f));
- EXPECT_EQ(101, ToRoundedInt(100.9f));
-
- EXPECT_EQ(int_min, ToRoundedInt(-infinity));
- EXPECT_EQ(int_min, ToRoundedInt(min));
- EXPECT_EQ(int_min, ToRoundedInt(min - 100));
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/scoped_gobject.h b/chromium/ui/gfx/scoped_gobject.h
deleted file mode 100644
index 860849ec84e..00000000000
--- a/chromium/ui/gfx/scoped_gobject.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_SCOPED_GOBJECT_H_
-#define UI_GFX_SCOPED_GOBJECT_H_
-
-#include <glib-object.h>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace ui {
-
-// It's not legal C++ to have a templatized typedefs, so we wrap it in a
-// struct. When using this, you need to include ::Type. E.g.,
-// ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
-template<class T>
-struct ScopedGObject {
- // A helper class that will g_object_unref |p| when it goes out of scope.
- // This never adds a ref, it only unrefs.
- template<class U>
- struct GObjectUnrefer {
- void operator()(U* ptr) const {
- if (ptr)
- g_object_unref(ptr);
- }
- };
-
- typedef scoped_ptr_malloc<T, GObjectUnrefer<T> > Type;
-};
-
-} // namespace ui
-
-#endif // UI_GFX_SCOPED_GOBJECT_H_
diff --git a/chromium/ui/gfx/screen_android.cc b/chromium/ui/gfx/screen_android.cc
index e90bb76725d..9114b855453 100644
--- a/chromium/ui/gfx/screen_android.cc
+++ b/chromium/ui/gfx/screen_android.cc
@@ -43,6 +43,7 @@ class ScreenAndroid : public Screen {
gfx::Display display(0, bounds_in_dip);
if (!gfx::Display::HasForceDeviceScaleFactor())
display.set_device_scale_factor(device_scale_factor);
+ display.SetRotationAsDegree(device_info.GetRotationDegrees());
return display;
}
diff --git a/chromium/ui/gfx/screen_gtk.cc b/chromium/ui/gfx/screen_gtk.cc
deleted file mode 100644
index ac2464bbbd7..00000000000
--- a/chromium/ui/gfx/screen_gtk.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/screen.h"
-
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "ui/gfx/display.h"
-
-namespace {
-
-bool GetScreenWorkArea(gfx::Rect* out_rect) {
- gboolean ok;
- guchar* raw_data = NULL;
- gint data_len = 0;
- ok = gdk_property_get(gdk_get_default_root_window(), // a gdk window
- gdk_atom_intern("_NET_WORKAREA", FALSE), // property
- gdk_atom_intern("CARDINAL", FALSE), // property type
- 0, // byte offset into property
- 0xff, // property length to retrieve
- false, // delete property after retrieval?
- NULL, // returned property type
- NULL, // returned data format
- &data_len, // returned data len
- &raw_data); // returned data
- if (!ok)
- return false;
-
- // We expect to get four longs back: x, y, width, height.
- if (data_len < static_cast<gint>(4 * sizeof(glong))) {
- NOTREACHED();
- g_free(raw_data);
- return false;
- }
-
- glong* data = reinterpret_cast<glong*>(raw_data);
- gint x = data[0];
- gint y = data[1];
- gint width = data[2];
- gint height = data[3];
- g_free(raw_data);
-
- out_rect->SetRect(x, y, width, height);
- return true;
-}
-
-gfx::Display GetDisplayForMonitorNum(GdkScreen* screen, gint monitor_num) {
- GdkRectangle bounds;
- gdk_screen_get_monitor_geometry(screen, monitor_num, &bounds);
- // Use |monitor_num| as display id.
- gfx::Display display(monitor_num, gfx::Rect(bounds));
- if (gdk_screen_get_primary_monitor(screen) == monitor_num) {
- gfx::Rect rect;
- if (GetScreenWorkArea(&rect))
- display.set_work_area(gfx::IntersectRects(rect, display.bounds()));
- }
- return display;
-}
-
-gfx::Display GetMonitorAreaNearestWindow(gfx::NativeView view) {
- GdkScreen* screen = gdk_screen_get_default();
- gint monitor_num = 0;
- if (view && GTK_IS_WINDOW(view)) {
- GtkWidget* top_level = gtk_widget_get_toplevel(view);
- DCHECK(GTK_IS_WINDOW(top_level));
- GtkWindow* window = GTK_WINDOW(top_level);
- screen = gtk_window_get_screen(window);
- monitor_num = gdk_screen_get_monitor_at_window(
- screen,
- gtk_widget_get_window(top_level));
- }
- return GetDisplayForMonitorNum(screen, monitor_num);
-}
-
-class ScreenGtk : public gfx::Screen {
- public:
- ScreenGtk() {
- }
-
- virtual ~ScreenGtk() {
- }
-
- virtual bool IsDIPEnabled() OVERRIDE {
- return false;
- }
-
- virtual gfx::Point GetCursorScreenPoint() OVERRIDE {
- gint x, y;
- gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
- return gfx::Point(x, y);
- }
-
- // Returns the window under the cursor.
- virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE {
- GdkWindow* window = gdk_window_at_pointer(NULL, NULL);
- if (!window)
- return NULL;
-
- gpointer data = NULL;
- gdk_window_get_user_data(window, &data);
- GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
- if (!widget)
- return NULL;
- widget = gtk_widget_get_toplevel(widget);
- return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL;
- }
-
- virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point)
- OVERRIDE {
- NOTIMPLEMENTED();
- return NULL;
- }
-
- // Returns the number of displays.
- // Mirrored displays are excluded; this method is intended to return the
- // number of distinct, usable displays.
- virtual int GetNumDisplays() const OVERRIDE {
- // This query is kinda bogus for Linux -- do we want number of X screens?
- // The number of monitors Xinerama has? We'll just use whatever GDK uses.
- GdkScreen* screen = gdk_screen_get_default();
- return gdk_screen_get_n_monitors(screen);
- }
-
- virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint num_of_displays = gdk_screen_get_n_monitors(screen);
- std::vector<gfx::Display> all_displays;
- for (gint i = 0; i < num_of_displays; ++i)
- all_displays.push_back(GetDisplayForMonitorNum(screen, i));
- return all_displays;
- }
-
- // Returns the display nearest the specified window.
- virtual gfx::Display GetDisplayNearestWindow(
- gfx::NativeView view) const OVERRIDE {
- // Do not use the _NET_WORKAREA here, this is supposed to be an area on a
- // specific monitor, and _NET_WORKAREA is a hint from the WM that
- // generally spans across all monitors. This would make the work area
- // larger than the monitor.
- // TODO(danakj) This is a work-around as there is no standard way to get
- // this area, but it is a rect that we should be computing. The standard
- // means to compute this rect would be to watch all windows with
- // _NET_WM_STRUT(_PARTIAL) hints, and subtract their space from the
- // physical area of the display to construct a work area.
- // TODO(oshima): Implement Observer.
- return GetMonitorAreaNearestWindow(view);
- }
-
- // Returns the the display nearest the specified point.
- virtual gfx::Display GetDisplayNearestPoint(
- const gfx::Point& point) const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint monitor = gdk_screen_get_monitor_at_point(
- screen, point.x(), point.y());
- // TODO(oshima): Implement Observer.
- return GetDisplayForMonitorNum(screen, monitor);
- }
-
- // Returns the display that most closely intersects the provided bounds.
- virtual gfx::Display GetDisplayMatching(
- const gfx::Rect& match_rect) const OVERRIDE {
- std::vector<gfx::Display> displays = GetAllDisplays();
- gfx::Display maxIntersectDisplay;
- gfx::Rect maxIntersection;
- for (std::vector<gfx::Display>::iterator it = displays.begin();
- it != displays.end(); ++it) {
- gfx::Rect displayIntersection = it->bounds();
- displayIntersection.Intersect(match_rect);
- if (displayIntersection.size().GetArea() >
- maxIntersection.size().GetArea()) {
- maxIntersectDisplay = *it;
- maxIntersection = displayIntersection;
- }
- }
- return maxIntersectDisplay.is_valid() ?
- maxIntersectDisplay : GetPrimaryDisplay();
- }
-
- // Returns the primary display.
- virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint primary_monitor_index = gdk_screen_get_primary_monitor(screen);
- // TODO(oshima): Implement Observer.
- return GetDisplayForMonitorNum(screen, primary_monitor_index);
- }
-
- virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {
- // TODO(oshima): crbug.com/122863.
- }
-
- virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {
- // TODO(oshima): crbug.com/122863.
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ScreenGtk);
-};
-
-} // namespace
-
-namespace gfx {
-
-Screen* CreateNativeScreen() {
- return new ScreenGtk;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/screen_ios.mm b/chromium/ui/gfx/screen_ios.mm
index a2770298ca8..f630f00a9f0 100644
--- a/chromium/ui/gfx/screen_ios.mm
+++ b/chromium/ui/gfx/screen_ios.mm
@@ -69,7 +69,8 @@ class ScreenIos : public gfx::Screen {
// Returns the primary display.
virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
- UIScreen* mainScreen = [[UIScreen screens] objectAtIndex:0];
+ UIScreen* mainScreen = [UIScreen mainScreen];
+ CHECK(mainScreen);
gfx::Display display(0, gfx::Rect(mainScreen.bounds));
display.set_device_scale_factor([mainScreen scale]);
return display;
diff --git a/chromium/ui/gfx/screen_mac.mm b/chromium/ui/gfx/screen_mac.mm
index 51c0b665b7e..377c8592210 100644
--- a/chromium/ui/gfx/screen_mac.mm
+++ b/chromium/ui/gfx/screen_mac.mm
@@ -154,7 +154,10 @@ class ScreenMac : public gfx::Screen {
virtual gfx::Display GetDisplayNearestWindow(
gfx::NativeView view) const OVERRIDE {
- NSWindow* window = [view window];
+ NSWindow* window = nil;
+#if !defined(USE_AURA)
+ window = [view window];
+#endif
if (!window)
return GetPrimaryDisplay();
NSScreen* match_screen = [window screen];
@@ -209,8 +212,10 @@ class ScreenMac : public gfx::Screen {
namespace gfx {
+#if !defined(USE_AURA)
Screen* CreateNativeScreen() {
return new ScreenMac;
}
+#endif
}
diff --git a/chromium/ui/gfx/screen_win.cc b/chromium/ui/gfx/screen_win.cc
index 7903cc5fdd5..4530642e24b 100644
--- a/chromium/ui/gfx/screen_win.cc
+++ b/chromium/ui/gfx/screen_win.cc
@@ -19,13 +19,14 @@ MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) {
MONITORINFOEX monitor_info;
ZeroMemory(&monitor_info, sizeof(MONITORINFOEX));
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(monitor, &monitor_info);
+ GetMonitorInfo(monitor, &monitor_info);
return monitor_info;
}
gfx::Display GetDisplay(MONITORINFOEX& monitor_info) {
// TODO(oshima): Implement Observer.
- int64 id = static_cast<int64>(base::Hash(WideToUTF8(monitor_info.szDevice)));
+ int64 id = static_cast<int64>(
+ base::Hash(base::WideToUTF8(monitor_info.szDevice)));
gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor);
gfx::Display display(id, bounds);
display.set_work_area(gfx::Rect(monitor_info.rcWork));
@@ -64,7 +65,8 @@ bool ScreenWin::IsDIPEnabled() {
gfx::Point ScreenWin::GetCursorScreenPoint() {
POINT pt;
GetCursorPos(&pt);
- return gfx::Point(pt);
+ gfx::Point cursor_pos_pixels(pt);
+ return gfx::win::ScreenToDIPPoint(cursor_pos_pixels);
}
gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
@@ -74,7 +76,8 @@ gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
}
gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) {
- return GetNativeWindowFromHWND(WindowFromPoint(point.ToPOINT()));
+ gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
+ return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT()));
}
int ScreenWin::GetNumDisplays() const {
@@ -99,8 +102,8 @@ gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(
- MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info);
+ GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST),
+ &monitor_info);
return GetDisplay(monitor_info);
}
@@ -110,7 +113,7 @@ gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
MONITORINFOEX mi;
ZeroMemory(&mi, sizeof(MONITORINFOEX));
mi.cbSize = sizeof(mi);
- if (monitor && base::win::GetMonitorInfoWrapper(monitor, &mi)) {
+ if (monitor && GetMonitorInfo(monitor, &mi)) {
return GetDisplay(mi);
}
return gfx::Display();
@@ -129,7 +132,7 @@ gfx::Display ScreenWin::GetPrimaryDisplay() const {
gfx::Display display = GetDisplay(mi);
// TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
// once more of the app is DIP-aware.
- if (!IsInHighDPIMode()) {
+ if (!(IsInHighDPIMode() || IsHighDPIEnabled())) {
DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
}
@@ -145,27 +148,13 @@ void ScreenWin::RemoveObserver(DisplayObserver* observer) {
}
HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const {
-#if defined(USE_AURA)
NOTREACHED();
return NULL;
-#else
- return window;
-#endif // USE_AURA
}
NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
-#if defined(USE_AURA)
NOTREACHED();
return NULL;
-#else
- return hwnd;
-#endif // USE_AURA
}
-#if !defined(USE_AURA)
-Screen* CreateNativeScreen() {
- return new ScreenWin;
-}
-#endif // !USE_AURA
-
} // namespace gfx
diff --git a/chromium/ui/gfx/selection_model.h b/chromium/ui/gfx/selection_model.h
index d509e898a99..356416df9c3 100644
--- a/chromium/ui/gfx/selection_model.h
+++ b/chromium/ui/gfx/selection_model.h
@@ -73,19 +73,16 @@ class GFX_EXPORT SelectionModel {
size_t caret_pos() const { return selection_.end(); }
LogicalCursorDirection caret_affinity() const { return caret_affinity_; }
+ // WARNING: Generally the selection start should not be changed without
+ // considering the effect on the caret affinity.
+ void set_selection_start(size_t pos) { selection_.set_start(pos); }
+
bool operator==(const SelectionModel& sel) const;
bool operator!=(const SelectionModel& sel) const { return !(*this == sel); }
std::string ToString() const;
private:
- friend class RenderText;
-
- // TODO(benrg): Generally the selection start should not be changed without
- // considering the effect on the caret affinity. This setter is exposed only
- // to RenderText to discourage misuse, and should probably be removed.
- void set_selection_start(size_t pos) { selection_.set_start(pos); }
-
// Logical selection. The logical caret position is the end of the selection.
Range selection_;
diff --git a/chromium/ui/gfx/size.cc b/chromium/ui/gfx/size.cc
deleted file mode 100644
index aa003e8c6df..00000000000
--- a/chromium/ui/gfx/size.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/size.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class SizeBase<Size, int>;
-
-#if defined(OS_MACOSX)
-Size::Size(const CGSize& s)
- : SizeBase<Size, int>(s.width, s.height) {
-}
-
-Size& Size::operator=(const CGSize& s) {
- set_width(s.width);
- set_height(s.height);
- return *this;
-}
-#endif
-
-#if defined(OS_WIN)
-SIZE Size::ToSIZE() const {
- SIZE s;
- s.cx = width();
- s.cy = height();
- return s;
-}
-#elif defined(OS_MACOSX)
-CGSize Size::ToCGSize() const {
- return CGSizeMake(width(), height());
-}
-#endif
-
-std::string Size::ToString() const {
- return base::StringPrintf("%dx%d", width(), height());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/size.h b/chromium/ui/gfx/size.h
index c96f5897f3b..78457d5088d 100644
--- a/chromium/ui/gfx/size.h
+++ b/chromium/ui/gfx/size.h
@@ -1,67 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_SIZE_H_
-#define UI_GFX_SIZE_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size.h"
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/size_base.h"
-#include "ui/gfx/size_f.h"
-
-#if defined(OS_WIN)
-typedef struct tagSIZE SIZE;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-// A size has width and height values.
-class GFX_EXPORT Size : public SizeBase<Size, int> {
- public:
- Size() : SizeBase<Size, int>(0, 0) {}
- Size(int width, int height) : SizeBase<Size, int>(width, height) {}
-#if defined(OS_MACOSX)
- explicit Size(const CGSize& s);
-#endif
-
- ~Size() {}
-
-#if defined(OS_MACOSX)
- Size& operator=(const CGSize& s);
-#endif
-
-#if defined(OS_WIN)
- SIZE ToSIZE() const;
-#elif defined(OS_MACOSX)
- CGSize ToCGSize() const;
-#endif
-
- operator SizeF() const {
- return SizeF(width(), height());
- }
-
- std::string ToString() const;
-};
-
-inline bool operator==(const Size& lhs, const Size& rhs) {
- return lhs.width() == rhs.width() && lhs.height() == rhs.height();
-}
-
-inline bool operator!=(const Size& lhs, const Size& rhs) {
- return !(lhs == rhs);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class SizeBase<Size, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_H_
diff --git a/chromium/ui/gfx/size_base.h b/chromium/ui/gfx/size_base.h
deleted file mode 100644
index c8349dc4b77..00000000000
--- a/chromium/ui/gfx/size_base.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_SIZE_BASE_H_
-#define UI_GFX_SIZE_BASE_H_
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// A size has width and height values.
-template<typename Class, typename Type>
-class GFX_EXPORT SizeBase {
- public:
- Type width() const { return width_; }
- Type height() const { return height_; }
-
- Type GetArea() const { return width_ * height_; }
-
- void SetSize(Type width, Type height) {
- set_width(width);
- set_height(height);
- }
-
- void Enlarge(Type width, Type height) {
- set_width(width_ + width);
- set_height(height_ + height);
- }
-
- void set_width(Type width) {
- width_ = width < 0 ? 0 : width;
- }
- void set_height(Type height) {
- height_ = height < 0 ? 0 : height;
- }
-
- void SetToMin(const Class& other) {
- width_ = width_ <= other.width_ ? width_ : other.width_;
- height_ = height_ <= other.height_ ? height_ : other.height_;
- }
-
- void SetToMax(const Class& other) {
- width_ = width_ >= other.width_ ? width_ : other.width_;
- height_ = height_ >= other.height_ ? height_ : other.height_;
- }
-
- bool IsEmpty() const {
- return (width_ == 0) || (height_ == 0);
- }
-
- protected:
- SizeBase(Type width, Type height)
- : width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height) {
- }
-
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~SizeBase() {}
-
- private:
- Type width_;
- Type height_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_BASE_H_
diff --git a/chromium/ui/gfx/size_conversions.cc b/chromium/ui/gfx/size_conversions.cc
deleted file mode 100644
index eacbeb4fc8d..00000000000
--- a/chromium/ui/gfx/size_conversions.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/size_conversions.h"
-
-#include "ui/gfx/safe_integer_conversions.h"
-
-namespace gfx {
-
-Size ToFlooredSize(const SizeF& size) {
- int w = ToFlooredInt(size.width());
- int h = ToFlooredInt(size.height());
- return Size(w, h);
-}
-
-Size ToCeiledSize(const SizeF& size) {
- int w = ToCeiledInt(size.width());
- int h = ToCeiledInt(size.height());
- return Size(w, h);
-}
-
-Size ToRoundedSize(const SizeF& size) {
- int w = ToRoundedInt(size.width());
- int h = ToRoundedInt(size.height());
- return Size(w, h);
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/size_conversions.h b/chromium/ui/gfx/size_conversions.h
index af68195b55b..0ee67f417e8 100644
--- a/chromium/ui/gfx/size_conversions.h
+++ b/chromium/ui/gfx/size_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_SIZE_CONVERSIONS_H_
-#define UI_GFX_SIZE_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_f.h"
-
-namespace gfx {
-
-// Returns a Size with each component from the input SizeF floored.
-GFX_EXPORT Size ToFlooredSize(const SizeF& size);
-
-// Returns a Size with each component from the input SizeF ceiled.
-GFX_EXPORT Size ToCeiledSize(const SizeF& size);
-
-// Returns a Size with each component from the input SizeF rounded.
-GFX_EXPORT Size ToRoundedSize(const SizeF& size);
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/size_f.cc b/chromium/ui/gfx/size_f.cc
deleted file mode 100644
index 6eba8849b22..00000000000
--- a/chromium/ui/gfx/size_f.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/size_f.h"
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-template class SizeBase<SizeF, float>;
-
-std::string SizeF::ToString() const {
- return base::StringPrintf("%fx%f", width(), height());
-}
-
-SizeF ScaleSize(const SizeF& s, float x_scale, float y_scale) {
- SizeF scaled_s(s);
- scaled_s.Scale(x_scale, y_scale);
- return scaled_s;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/size_f.h b/chromium/ui/gfx/size_f.h
index b9065273c8e..0aabbcfcd53 100644
--- a/chromium/ui/gfx/size_f.h
+++ b/chromium/ui/gfx/size_f.h
@@ -1,54 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_SIZE_F_H_
-#define UI_GFX_SIZE_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size_f.h"
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/size_base.h"
-
-namespace gfx {
-
-// A floating version of gfx::Size.
-class GFX_EXPORT SizeF : public SizeBase<SizeF, float> {
- public:
- SizeF() : SizeBase<SizeF, float>(0, 0) {}
- SizeF(float width, float height) : SizeBase<SizeF, float>(width, height) {}
- ~SizeF() {}
-
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- SetSize(width() * x_scale, height() * y_scale);
- }
-
- std::string ToString() const;
-};
-
-inline bool operator==(const SizeF& lhs, const SizeF& rhs) {
- return lhs.width() == rhs.width() && lhs.height() == rhs.height();
-}
-
-inline bool operator!=(const SizeF& lhs, const SizeF& rhs) {
- return !(lhs == rhs);
-}
-
-GFX_EXPORT SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale);
-
-inline SizeF ScaleSize(const SizeF& p, float scale) {
- return ScaleSize(p, scale, scale);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class SizeBase<SizeF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_F_H_
diff --git a/chromium/ui/gfx/size_unittest.cc b/chromium/ui/gfx/size_unittest.cc
deleted file mode 100644
index 9f109b3f04b..00000000000
--- a/chromium/ui/gfx/size_unittest.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/size_base.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/size_f.h"
-
-namespace gfx {
-
-namespace {
-
-int TestSizeF(const SizeF& s) {
- return s.width();
-}
-
-} // namespace
-
-TEST(SizeTest, ToSizeF) {
- // Check that implicit conversion from integer to float compiles.
- Size a(10, 20);
- float width = TestSizeF(a);
- EXPECT_EQ(width, a.width());
-
- SizeF b(10, 20);
-
- EXPECT_EQ(a, b);
- EXPECT_EQ(b, a);
-}
-
-TEST(SizeTest, ToFlooredSize) {
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0, 0)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10, 10)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ToCeiledSize) {
- EXPECT_EQ(Size(0, 0), ToCeiledSize(SizeF(0, 0)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToCeiledSize(SizeF(10, 10)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ToRoundedSize) {
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0, 0)));
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10, 10)));
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ClampSize) {
- Size a;
-
- a = Size(3, 5);
- EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
- a.SetToMax(Size(2, 4));
- EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
- a.SetToMax(Size(3, 5));
- EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
- a.SetToMax(Size(4, 2));
- EXPECT_EQ(Size(4, 5).ToString(), a.ToString());
- a.SetToMax(Size(8, 10));
- EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
-
- a.SetToMin(Size(9, 11));
- EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
- a.SetToMin(Size(8, 10));
- EXPECT_EQ(Size(8, 10).ToString(), a.ToString());
- a.SetToMin(Size(11, 9));
- EXPECT_EQ(Size(8, 9).ToString(), a.ToString());
- a.SetToMin(Size(7, 11));
- EXPECT_EQ(Size(7, 9).ToString(), a.ToString());
- a.SetToMin(Size(3, 5));
- EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
-}
-
-TEST(SizeTest, ClampSizeF) {
- SizeF a;
-
- a = SizeF(3.5f, 5.5f);
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(2.5f, 4.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(3.5f, 5.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(4.5f, 2.5f));
- EXPECT_EQ(SizeF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(8.5f, 10.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(SizeF(9.5f, 11.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(8.5f, 10.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(11.5f, 9.5f));
- EXPECT_EQ(SizeF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(7.5f, 11.5f));
- EXPECT_EQ(SizeF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(3.5f, 5.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/skbitmap_operations.cc b/chromium/ui/gfx/skbitmap_operations.cc
index c89153692a4..d3b48271bbe 100644
--- a/chromium/ui/gfx/skbitmap_operations.cc
+++ b/chromium/ui/gfx/skbitmap_operations.cc
@@ -21,14 +21,12 @@
// static
SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
SkAutoLockPixels lock_image(image);
SkBitmap inverted;
- inverted.setConfig(SkBitmap::kARGB_8888_Config, image.width(), image.height(),
- 0);
- inverted.allocPixels();
+ inverted.allocN32Pixels(image.width(), image.height());
inverted.eraseARGB(0, 0, 0, 0);
for (int y = 0; y < image.height(); ++y) {
@@ -51,15 +49,13 @@ SkBitmap SkBitmapOperations::CreateSuperimposedBitmap(const SkBitmap& first,
DCHECK(first.width() == second.width());
DCHECK(first.height() == second.height());
DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
- DCHECK(first.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(first.colorType() == kPMColor_SkColorType);
SkAutoLockPixels lock_first(first);
SkAutoLockPixels lock_second(second);
SkBitmap superimposed;
- superimposed.setConfig(SkBitmap::kARGB_8888_Config,
- first.width(), first.height());
- superimposed.allocPixels();
+ superimposed.allocN32Pixels(first.width(), first.height());
superimposed.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(superimposed);
@@ -84,7 +80,7 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
DCHECK(first.width() == second.width());
DCHECK(first.height() == second.height());
DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
- DCHECK(first.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(first.colorType() == kPMColor_SkColorType);
// Optimize for case where we won't need to blend anything.
static const double alpha_min = 1.0 / 255;
@@ -98,9 +94,7 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
SkAutoLockPixels lock_second(second);
SkBitmap blended;
- blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), first.height(),
- 0);
- blended.allocPixels();
+ blended.allocN32Pixels(first.width(), first.height());
blended.eraseARGB(0, 0, 0, 0);
double first_alpha = 1 - alpha;
@@ -136,12 +130,11 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
DCHECK(rgb.width() == alpha.width());
DCHECK(rgb.height() == alpha.height());
DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel());
- DCHECK(rgb.config() == SkBitmap::kARGB_8888_Config);
- DCHECK(alpha.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(rgb.colorType() == kPMColor_SkColorType);
+ DCHECK(alpha.colorType() == kPMColor_SkColorType);
SkBitmap masked;
- masked.setConfig(SkBitmap::kARGB_8888_Config, rgb.width(), rgb.height(), 0);
- masked.allocPixels();
+ masked.allocN32Pixels(rgb.width(), rgb.height());
masked.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_rgb(rgb);
@@ -174,13 +167,11 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
const SkBitmap& image,
const SkBitmap& mask) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
- DCHECK(mask.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
+ DCHECK(mask.colorType() == kPMColor_SkColorType);
SkBitmap background;
- background.setConfig(
- SkBitmap::kARGB_8888_Config, mask.width(), mask.height(), 0);
- background.allocPixels();
+ background.allocN32Pixels(mask.width(), mask.height());
double bg_a = SkColorGetA(color);
double bg_r = SkColorGetR(color);
@@ -556,12 +547,10 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
HSLShift::kLineProcessors[H_op][S_op][L_op];
DCHECK(bitmap.empty() == false);
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
SkBitmap shifted;
- shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(),
- bitmap.height());
- shifted.allocPixels();
+ shifted.allocN32Pixels(bitmap.width(), bitmap.height());
shifted.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_bitmap(bitmap);
@@ -582,11 +571,10 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
int src_x, int src_y,
int dst_w, int dst_h) {
- DCHECK(source.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(source.colorType() == kPMColor_SkColorType);
SkBitmap cropped;
- cropped.setConfig(SkBitmap::kARGB_8888_Config, dst_w, dst_h, 0);
- cropped.allocPixels();
+ cropped.allocN32Pixels(dst_w, dst_h);
cropped.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_source(source);
@@ -635,9 +623,7 @@ SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
return bitmap;
SkBitmap result;
- result.setConfig(SkBitmap::kARGB_8888_Config,
- (bitmap.width() + 1) / 2, (bitmap.height() + 1) / 2);
- result.allocPixels();
+ result.allocN32Pixels((bitmap.width() + 1) / 2, (bitmap.height() + 1) / 2);
SkAutoLockPixels lock(bitmap);
@@ -702,10 +688,10 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
if (bitmap.isOpaque())
return bitmap;
+ SkImageInfo info = bitmap.info();
+ info.fAlphaType = kOpaque_SkAlphaType;
SkBitmap opaque_bitmap;
- opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height(),
- 0, kOpaque_SkAlphaType);
- opaque_bitmap.allocPixels();
+ opaque_bitmap.allocPixels(info);
{
SkAutoLockPixels bitmap_lock(bitmap);
@@ -725,12 +711,10 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
// static
SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
SkBitmap transposed;
- transposed.setConfig(
- SkBitmap::kARGB_8888_Config, image.height(), image.width(), 0);
- transposed.allocPixels();
+ transposed.allocN32Pixels(image.height(), image.width());
SkAutoLockPixels lock_image(image);
SkAutoLockPixels lock_transposed(transposed);
@@ -749,12 +733,10 @@ SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
// static
SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkColor c) {
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
SkBitmap color_mask;
- color_mask.setConfig(SkBitmap::kARGB_8888_Config,
- bitmap.width(), bitmap.height());
- color_mask.allocPixels();
+ color_mask.allocN32Pixels(bitmap.width(), bitmap.height());
color_mask.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(color_mask);
@@ -771,7 +753,7 @@ SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkBitmap SkBitmapOperations::CreateDropShadow(
const SkBitmap& bitmap,
const gfx::ShadowValues& shadows) {
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
// Shadow margin insets are negative values because they grow outside.
// Negate them here as grow direction is not important and only pixel value
@@ -779,10 +761,8 @@ SkBitmap SkBitmapOperations::CreateDropShadow(
gfx::Insets shadow_margin = -gfx::ShadowValue::GetMargin(shadows);
SkBitmap image_with_shadow;
- image_with_shadow.setConfig(SkBitmap::kARGB_8888_Config,
- bitmap.width() + shadow_margin.width(),
- bitmap.height() + shadow_margin.height());
- image_with_shadow.allocPixels();
+ image_with_shadow.allocN32Pixels(bitmap.width() + shadow_margin.width(),
+ bitmap.height() + shadow_margin.height());
image_with_shadow.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(image_with_shadow);
@@ -796,8 +776,8 @@ SkBitmap SkBitmapOperations::CreateDropShadow(
shadow.color());
skia::RefPtr<SkBlurImageFilter> filter =
- skia::AdoptRef(new SkBlurImageFilter(SkDoubleToScalar(shadow.blur()),
- SkDoubleToScalar(shadow.blur())));
+ skia::AdoptRef(SkBlurImageFilter::Create(
+ SkDoubleToScalar(shadow.blur()), SkDoubleToScalar(shadow.blur())));
paint.setImageFilter(filter.get());
canvas.saveLayer(0, &paint);
diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc
index bb7cde7b4ba..0a991df20aa 100644
--- a/chromium/ui/gfx/skia_util.cc
+++ b/chromium/ui/gfx/skia_util.cc
@@ -64,13 +64,16 @@ void TransformToFlattenedSkMatrix(const gfx::Transform& transform,
skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
SkShader::TileMode tile_mode,
const SkMatrix& local_matrix) {
- skia::RefPtr<SkShader> shader = skia::AdoptRef(SkShader::CreateBitmapShader(
- image_rep.sk_bitmap(), tile_mode, tile_mode));
- SkScalar scale_x = local_matrix.getScaleX();
- SkScalar scale_y = local_matrix.getScaleY();
- SkScalar bitmap_scale = SkFloatToScalar(image_rep.scale());
+ return CreateImageRepShaderForScale(image_rep, tile_mode, local_matrix,
+ image_rep.scale());
+}
- // Unscale matrix by |bitmap_scale| such that the bitmap is drawn at the
+skia::RefPtr<SkShader> CreateImageRepShaderForScale(
+ const gfx::ImageSkiaRep& image_rep,
+ SkShader::TileMode tile_mode,
+ const SkMatrix& local_matrix,
+ SkScalar scale) {
+ // Unscale matrix by |scale| such that the bitmap is drawn at the
// correct density.
// Convert skew and translation to pixel coordinates.
// Thus, for |bitmap_scale| = 2:
@@ -78,11 +81,12 @@ skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
// should be converted to
// x scale = 1, x translation = 2 pixels.
SkMatrix shader_scale = local_matrix;
- shader_scale.preScale(bitmap_scale, bitmap_scale);
- shader_scale.setScaleX(SkScalarDiv(scale_x, bitmap_scale));
- shader_scale.setScaleY(SkScalarDiv(scale_y, bitmap_scale));
+ shader_scale.preScale(scale, scale);
+ shader_scale.setScaleX(local_matrix.getScaleX() / scale);
+ shader_scale.setScaleY(local_matrix.getScaleY() / scale);
- shader->setLocalMatrix(shader_scale);
+ skia::RefPtr<SkShader> shader = skia::AdoptRef(SkShader::CreateBitmapShader(
+ image_rep.sk_bitmap(), tile_mode, tile_mode, &shader_scale));
return shader;
}
@@ -99,15 +103,20 @@ skia::RefPtr<SkShader> CreateGradientShader(int start_point,
grad_points, grad_colors, NULL, 2, SkShader::kRepeat_TileMode));
}
+static SkScalar RadiusToSigma(double radius) {
+ // This captures historically what skia did under the hood. Now skia accepts
+ // sigma, not radius, so we perform the conversion.
+ return radius > 0 ? SkDoubleToScalar(0.57735f * radius + 0.5) : 0;
+}
+
skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(
const std::vector<ShadowValue>& shadows) {
if (shadows.empty())
return skia::RefPtr<SkDrawLooper>();
- skia::RefPtr<SkLayerDrawLooper> looper =
- skia::AdoptRef(new SkLayerDrawLooper);
+ SkLayerDrawLooper::Builder looper_builder;
- looper->addLayer(); // top layer of the original.
+ looper_builder.addLayer(); // top layer of the original.
SkLayerDrawLooper::LayerInfo layer_info;
layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
@@ -123,19 +132,19 @@ skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(
// SkBlurMaskFilter's blur radius defines the range to extend the blur from
// original mask, which is half of blur amount as defined in ShadowValue.
skia::RefPtr<SkMaskFilter> blur_mask = skia::AdoptRef(
- SkBlurMaskFilter::Create(SkDoubleToScalar(shadow.blur() / 2),
- SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
+ RadiusToSigma(shadow.blur() / 2),
SkBlurMaskFilter::kHighQuality_BlurFlag));
skia::RefPtr<SkColorFilter> color_filter = skia::AdoptRef(
SkColorFilter::CreateModeFilter(shadow.color(),
SkXfermode::kSrcIn_Mode));
- SkPaint* paint = looper->addLayer(layer_info);
+ SkPaint* paint = looper_builder.addLayer(layer_info);
paint->setMaskFilter(blur_mask.get());
paint->setColorFilter(color_filter.get());
}
- return looper;
+ return skia::AdoptRef<SkDrawLooper>(looper_builder.detachLooper());
}
bool BitmapsAreEqual(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
diff --git a/chromium/ui/gfx/skia_util.h b/chromium/ui/gfx/skia_util.h
index 92c886a4309..0c759838b86 100644
--- a/chromium/ui/gfx/skia_util.h
+++ b/chromium/ui/gfx/skia_util.h
@@ -47,6 +47,13 @@ GFX_EXPORT skia::RefPtr<SkShader> CreateImageRepShader(
SkShader::TileMode tile_mode,
const SkMatrix& local_matrix);
+// Creates a bitmap shader for the image rep with the passed in scale factor.
+GFX_EXPORT skia::RefPtr<SkShader> CreateImageRepShaderForScale(
+ const gfx::ImageSkiaRep& image_rep,
+ SkShader::TileMode tile_mode,
+ const SkMatrix& local_matrix,
+ SkScalar scale);
+
// Creates a vertical gradient shader. The caller owns the shader.
// Example usage to avoid leaks:
GFX_EXPORT skia::RefPtr<SkShader> CreateGradientShader(int start_point,
diff --git a/chromium/ui/gfx/skia_utils_gtk.cc b/chromium/ui/gfx/skia_utils_gtk.cc
deleted file mode 100644
index f7f3a0aaf2b..00000000000
--- a/chromium/ui/gfx/skia_utils_gtk.cc
+++ /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.
-
-#include "ui/gfx/skia_utils_gtk.h"
-
-#include <gdk/gdk.h>
-
-namespace gfx {
-
-const int kSkiaToGDKMultiplier = 257;
-
-// GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
-// See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
-// To get back, we can just right shift by eight
-// (or, formulated differently, i == (i*257)/256 for all i < 256).
-
-SkColor GdkColorToSkColor(GdkColor color) {
- return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8);
-}
-
-GdkColor SkColorToGdkColor(SkColor color) {
- GdkColor gdk_color = {
- 0,
- static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier),
- static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier),
- static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier)
- };
- return gdk_color;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/skia_utils_gtk.h b/chromium/ui/gfx/skia_utils_gtk.h
deleted file mode 100644
index 6b74da246ea..00000000000
--- a/chromium/ui/gfx/skia_utils_gtk.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_SKIA_UTILS_GTK_H_
-#define UI_GFX_SKIA_UTILS_GTK_H_
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkColor GdkColor;
-
-namespace gfx {
-
-// Converts GdkColors to the ARGB layout Skia expects.
-GFX_EXPORT SkColor GdkColorToSkColor(GdkColor color);
-
-// Converts ARGB to GdkColor.
-GFX_EXPORT GdkColor SkColorToGdkColor(SkColor color);
-
-} // namespace gfx
-
-#endif // UI_GFX_SKIA_UTILS_GTK_H_
diff --git a/chromium/ui/gfx/skrect_conversion_unittest.cc b/chromium/ui/gfx/skrect_conversion_unittest.cc
new file mode 100644
index 00000000000..ef116c2a451
--- /dev/null
+++ b/chromium/ui/gfx/skrect_conversion_unittest.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
+
+namespace gfx {
+
+TEST(RectTest, SkiaRectConversions) {
+ Rect isrc(10, 20, 30, 40);
+ RectF fsrc(10.5f, 20.5f, 30.5f, 40.5f);
+
+ SkIRect skirect = RectToSkIRect(isrc);
+ EXPECT_EQ(isrc.ToString(), SkIRectToRect(skirect).ToString());
+
+ SkRect skrect = RectToSkRect(isrc);
+ EXPECT_EQ(gfx::RectF(isrc).ToString(), SkRectToRectF(skrect).ToString());
+
+ skrect = RectFToSkRect(fsrc);
+ EXPECT_EQ(fsrc.ToString(), SkRectToRectF(skrect).ToString());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/switches.cc b/chromium/ui/gfx/switches.cc
index 2f2eb9a3b82..2441a1483f5 100644
--- a/chromium/ui/gfx/switches.cc
+++ b/chromium/ui/gfx/switches.cc
@@ -6,11 +6,21 @@
namespace switches {
+// The ImageSkia looks up the resource pack with the closest available scale
+// factor instead of the actual device scale factor and then rescale on
+// ImageSkia side. This switch disables this feature.
+const char kDisableArbitraryScaleFactorInImageSkia[] =
+ "disable-arbitrary-scale-factor-in-image-skia";
+
// Let text glyphs have X-positions that aren't snapped to the pixel grid in
// the browser UI.
const char kEnableBrowserTextSubpixelPositioning[] =
"enable-browser-text-subpixel-positioning";
+// Uses the HarfBuzz port of RenderText on all platforms.
+const char kEnableHarfBuzzRenderText[] =
+ "enable-harfbuzz-rendertext";
+
// Enable text glyphs to have X-positions that aren't snapped to the pixel grid
// in webkit renderers.
const char kEnableWebkitTextSubpixelPositioning[] =
@@ -19,7 +29,4 @@ const char kEnableWebkitTextSubpixelPositioning[] =
// Overrides the device scale factor for the browser UI and the contents.
const char kForceDeviceScaleFactor[] = "force-device-scale-factor";
-// Enables/Disables High DPI support (windows)
-const char kHighDPISupport[] = "high-dpi-support";
-
} // namespace switches
diff --git a/chromium/ui/gfx/switches.h b/chromium/ui/gfx/switches.h
index c5629f249c4..1b6e10b7560 100644
--- a/chromium/ui/gfx/switches.h
+++ b/chromium/ui/gfx/switches.h
@@ -9,10 +9,12 @@
namespace switches {
+GFX_EXPORT extern const char kAllowArbitraryScaleFactorInImageSkia[];
+GFX_EXPORT extern const char kDisableArbitraryScaleFactorInImageSkia[];
GFX_EXPORT extern const char kEnableBrowserTextSubpixelPositioning[];
+GFX_EXPORT extern const char kEnableHarfBuzzRenderText[];
GFX_EXPORT extern const char kEnableWebkitTextSubpixelPositioning[];
GFX_EXPORT extern const char kForceDeviceScaleFactor[];
-GFX_EXPORT extern const char kHighDPISupport[];
} // namespace switches
diff --git a/chromium/ui/gfx/sys_color_change_listener.cc b/chromium/ui/gfx/sys_color_change_listener.cc
index d5646b3a81c..4a394aea5ee 100644
--- a/chromium/ui/gfx/sys_color_change_listener.cc
+++ b/chromium/ui/gfx/sys_color_change_listener.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 "ui/gfx/color_utils.h"
#include "ui/gfx/sys_color_change_listener.h"
#if defined(OS_WIN)
@@ -12,6 +11,8 @@
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
+#include "ui/gfx/color_utils.h"
+
#if defined(OS_WIN)
#include "ui/gfx/win/singleton_hwnd.h"
#endif
diff --git a/chromium/ui/gfx/text_constants.h b/chromium/ui/gfx/text_constants.h
index 4ac788e6109..47c91cf5f14 100644
--- a/chromium/ui/gfx/text_constants.h
+++ b/chromium/ui/gfx/text_constants.h
@@ -10,34 +10,25 @@ namespace gfx {
// TODO(msw): Distinguish between logical character stops and glyph stops?
// TODO(msw): Merge with base::i18n::BreakIterator::BreakType.
enum BreakType {
- // Stop cursor movement on neighboring characters.
- CHARACTER_BREAK = 0,
- // Stop cursor movement on nearest word boundaries.
- WORD_BREAK,
- // Stop cursor movement on line ends as shown on screen.
- LINE_BREAK,
+ CHARACTER_BREAK = 0, // Stop cursor movement on neighboring characters.
+ WORD_BREAK, // Stop cursor movement on nearest word boundaries.
+ LINE_BREAK, // Stop cursor movement on line ends as shown on screen.
};
// Horizontal text alignment modes.
enum HorizontalAlignment {
- // Align the text's left edge with that of its display area.
- ALIGN_LEFT = 0,
- // Align the text's center with that of its display area.
- ALIGN_CENTER,
- // Align the text's right edge with that of its display area.
- ALIGN_RIGHT,
+ ALIGN_LEFT = 0, // Align the text's left edge with that of its display area.
+ ALIGN_CENTER, // Align the text's center with that of its display area.
+ ALIGN_RIGHT, // Align the text's right edge with that of its display area.
+ ALIGN_TO_HEAD, // Align the text to its first strong character's direction.
};
// The directionality modes used to determine the base text direction.
enum DirectionalityMode {
- // Use the first strong character's direction.
- DIRECTIONALITY_FROM_TEXT = 0,
- // Use the UI locale's text reading direction.
- DIRECTIONALITY_FROM_UI,
- // Use LTR regardless of content or UI locale.
- DIRECTIONALITY_FORCE_LTR,
- // Use RTL regardless of content or UI locale.
- DIRECTIONALITY_FORCE_RTL,
+ DIRECTIONALITY_FROM_TEXT = 0, // Use the first strong character's direction.
+ DIRECTIONALITY_FROM_UI, // Use the UI locale's text reading direction.
+ DIRECTIONALITY_FORCE_LTR, // Use LTR regardless of content or UI locale.
+ DIRECTIONALITY_FORCE_RTL, // Use RTL regardless of content or UI locale.
};
// Text styles and adornments.
@@ -51,6 +42,16 @@ enum TextStyle {
NUM_TEXT_STYLES,
};
+// Elision behaviors of text that exceeds constrained dimensions.
+enum ElideBehavior {
+ TRUNCATE = 0, // Do not elide or fade; the text may be truncated at the end.
+ ELIDE_HEAD, // Add an ellipsis at the start of the string.
+ ELIDE_MIDDLE, // Add an ellipsis in the middle of the string.
+ ELIDE_TAIL, // Add an ellipsis at the end of the string.
+ ELIDE_EMAIL, // Add ellipses to username and domain substrings.
+ FADE_TAIL, // Fade the string's end opposite of its horizontal alignment.
+};
+
} // namespace gfx
#endif // UI_GFX_TEXT_CONSTANTS_H_
diff --git a/chromium/ui/gfx/text_elider.cc b/chromium/ui/gfx/text_elider.cc
index 5b9469614f2..8c07bdecd5f 100644
--- a/chromium/ui/gfx/text_elider.cc
+++ b/chromium/ui/gfx/text_elider.cc
@@ -21,135 +21,29 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/escape.h"
-#include "net/base/net_util.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
-#include "url/gurl.h"
-namespace gfx {
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
-// U+2026 in utf8
-const char kEllipsis[] = "\xE2\x80\xA6";
-const base::char16 kEllipsisUTF16[] = { 0x2026, 0 };
-const base::char16 kForwardSlash = '/';
+namespace gfx {
namespace {
-// Helper class to split + elide text, while respecting UTF16 surrogate pairs.
-class StringSlicer {
- public:
- StringSlicer(const base::string16& text,
- const base::string16& ellipsis,
- bool elide_in_middle)
- : text_(text),
- ellipsis_(ellipsis),
- elide_in_middle_(elide_in_middle) {
- }
-
- // Cuts |text_| to be |length| characters long. If |elide_in_middle_| is true,
- // the middle of the string is removed to leave equal-length pieces from the
- // beginning and end of the string; otherwise, the end of the string is
- // removed and only the beginning remains. If |insert_ellipsis| is true,
- // then an ellipsis character will be inserted at the cut point.
- base::string16 CutString(size_t length, bool insert_ellipsis) {
- const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_
- : base::string16();
-
- if (!elide_in_middle_)
- return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text;
-
- // We put the extra character, if any, before the cut.
- const size_t half_length = length / 2;
- const size_t prefix_length = FindValidBoundaryBefore(length - half_length);
- const size_t suffix_start_guess = text_.length() - half_length;
- const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess);
- const size_t suffix_length =
- half_length - (suffix_start_guess - suffix_start);
- return text_.substr(0, prefix_length) + ellipsis_text +
- text_.substr(suffix_start, suffix_length);
- }
-
- private:
- // Returns a valid cut boundary at or before |index|.
- size_t FindValidBoundaryBefore(size_t index) const {
- DCHECK_LE(index, text_.length());
- if (index != text_.length())
- U16_SET_CP_START(text_.data(), 0, index);
- return index;
- }
-
- // Returns a valid cut boundary at or after |index|.
- size_t FindValidBoundaryAfter(size_t index) const {
- DCHECK_LE(index, text_.length());
- if (index != text_.length())
- U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length());
- return index;
- }
-
- // The text to be sliced.
- const base::string16& text_;
-
- // Ellipsis string to use.
- const base::string16& ellipsis_;
-
- // If true, the middle of the string will be elided.
- bool elide_in_middle_;
-
- DISALLOW_COPY_AND_ASSIGN(StringSlicer);
-};
-
-// Build a path from the first |num_components| elements in |path_elements|.
-// Prepends |path_prefix|, appends |filename|, inserts ellipsis if appropriate.
-base::string16 BuildPathFromComponents(
- const base::string16& path_prefix,
- const std::vector<base::string16>& path_elements,
- const base::string16& filename,
- size_t num_components) {
- // Add the initial elements of the path.
- base::string16 path = path_prefix;
-
- // Build path from first |num_components| elements.
- for (size_t j = 0; j < num_components; ++j)
- path += path_elements[j] + kForwardSlash;
-
- // Add |filename|, ellipsis if necessary.
- if (num_components != (path_elements.size() - 1))
- path += base::string16(kEllipsisUTF16) + kForwardSlash;
- path += filename;
-
- return path;
-}
-
-// Takes a prefix (Domain, or Domain+subdomain) and a collection of path
-// components and elides if possible. Returns a string containing the longest
-// possible elided path, or an empty string if elision is not possible.
-base::string16 ElideComponentizedPath(
- const base::string16& url_path_prefix,
- const std::vector<base::string16>& url_path_elements,
- const base::string16& url_filename,
- const base::string16& url_query,
- const FontList& font_list,
- float available_pixel_width) {
- const size_t url_path_number_of_elements = url_path_elements.size();
-
- CHECK(url_path_number_of_elements);
- for (size_t i = url_path_number_of_elements - 1; i > 0; --i) {
- base::string16 elided_path = BuildPathFromComponents(url_path_prefix,
- url_path_elements, url_filename, i);
- if (available_pixel_width >= GetStringWidthF(elided_path, font_list))
- return ElideText(elided_path + url_query, font_list,
- available_pixel_width, ELIDE_AT_END);
- }
-
- return base::string16();
-}
-
-} // namespace
-
+// Elides a well-formed email address (e.g. username@domain.com) to fit into
+// |available_pixel_width| using the specified |font_list|.
+// This function guarantees that the string returned will contain at least one
+// character, other than the ellipses, on either side of the '@'. If it is
+// impossible to achieve these requirements: only an ellipsis will be returned.
+// If possible: this elides only the username portion of the |email|. Otherwise,
+// the domain is elided in the middle so that it splits the available width
+// equally with the elided username (should the username be short enough that it
+// doesn't need half the available width: the elided domain will occupy that
+// extra width).
base::string16 ElideEmail(const base::string16& email,
const FontList& font_list,
float available_pixel_width) {
@@ -191,8 +85,7 @@ base::string16 ElideEmail(const base::string16& email,
std::min(available_domain_width,
std::max(available_pixel_width - full_username_width,
available_pixel_width / 2));
- domain = ElideText(domain, font_list, desired_domain_width,
- ELIDE_IN_MIDDLE);
+ domain = ElideText(domain, font_list, desired_domain_width, ELIDE_MIDDLE);
// Failing to elide the domain such that at least one character remains
// (other than the ellipsis itself) remains: return a single ellipsis.
if (domain.length() <= 1U)
@@ -203,206 +96,61 @@ base::string16 ElideEmail(const base::string16& email,
// is guaranteed to fit with at least one character remaining given all the
// precautions taken earlier).
available_pixel_width -= GetStringWidthF(domain, font_list);
- username = ElideText(username, font_list, available_pixel_width,
- ELIDE_AT_END);
-
+ username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL);
return username + kAtSignUTF16 + domain;
}
-// TODO(pkasting): http://crbug.com/77883 This whole function gets
-// kerning/ligatures/etc. issues potentially wrong by assuming that the width of
-// a rendered string is always the sum of the widths of its substrings. Also I
-// suspect it could be made simpler.
-base::string16 ElideUrl(const GURL& url,
- const FontList& font_list,
- float available_pixel_width,
- const std::string& languages) {
- // Get a formatted string and corresponding parsing of the url.
- url_parse::Parsed parsed;
- const base::string16 url_string =
- net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- net::UnescapeRule::SPACES, &parsed, NULL, NULL);
- if (available_pixel_width <= 0)
- return url_string;
-
- // If non-standard, return plain eliding.
- if (!url.IsStandard())
- return ElideText(url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
-
- // Now start eliding url_string to fit within available pixel width.
- // Fist pass - check to see whether entire url_string fits.
- const float pixel_width_url_string = GetStringWidthF(url_string, font_list);
- if (available_pixel_width >= pixel_width_url_string)
- return url_string;
-
- // Get the path substring, including query and reference.
- const size_t path_start_index = parsed.path.begin;
- const size_t path_len = parsed.path.len;
- base::string16 url_path_query_etc = url_string.substr(path_start_index);
- base::string16 url_path = url_string.substr(path_start_index, path_len);
-
- // Return general elided text if url minus the query fits.
- const base::string16 url_minus_query =
- url_string.substr(0, path_start_index + path_len);
- if (available_pixel_width >= GetStringWidthF(url_minus_query, font_list))
- return ElideText(url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
-
- // Get Host.
- base::string16 url_host = UTF8ToUTF16(url.host());
-
- // Get domain and registry information from the URL.
- base::string16 url_domain = UTF8ToUTF16(
- net::registry_controlled_domains::GetDomainAndRegistry(
- url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
- if (url_domain.empty())
- url_domain = url_host;
-
- // Add port if required.
- if (!url.port().empty()) {
- url_host += UTF8ToUTF16(":" + url.port());
- url_domain += UTF8ToUTF16(":" + url.port());
- }
-
- // Get sub domain.
- base::string16 url_subdomain;
- const size_t domain_start_index = url_host.find(url_domain);
- if (domain_start_index != base::string16::npos)
- url_subdomain = url_host.substr(0, domain_start_index);
- const base::string16 kWwwPrefix = UTF8ToUTF16("www.");
- if ((url_subdomain == kWwwPrefix || url_subdomain.empty() ||
- url.SchemeIsFile())) {
- url_subdomain.clear();
- }
-
- // If this is a file type, the path is now defined as everything after ":".
- // For example, "C:/aa/aa/bb", the path is "/aa/bb/cc". Interesting, the
- // domain is now C: - this is a nice hack for eliding to work pleasantly.
- if (url.SchemeIsFile()) {
- // Split the path string using ":"
- std::vector<base::string16> file_path_split;
- base::SplitString(url_path, ':', &file_path_split);
- if (file_path_split.size() > 1) { // File is of type "file:///C:/.."
- url_host.clear();
- url_domain.clear();
- url_subdomain.clear();
-
- const base::string16 kColon = UTF8ToUTF16(":");
- url_host = url_domain = file_path_split.at(0).substr(1) + kColon;
- url_path_query_etc = url_path = file_path_split.at(1);
- }
- }
+} // namespace
- // Second Pass - remove scheme - the rest fits.
- const float pixel_width_url_host = GetStringWidthF(url_host, font_list);
- const float pixel_width_url_path = GetStringWidthF(url_path_query_etc,
- font_list);
- if (available_pixel_width >=
- pixel_width_url_host + pixel_width_url_path)
- return url_host + url_path_query_etc;
-
- // Third Pass: Subdomain, domain and entire path fits.
- const float pixel_width_url_domain = GetStringWidthF(url_domain, font_list);
- const float pixel_width_url_subdomain =
- GetStringWidthF(url_subdomain, font_list);
- if (available_pixel_width >=
- pixel_width_url_subdomain + pixel_width_url_domain +
- pixel_width_url_path)
- return url_subdomain + url_domain + url_path_query_etc;
-
- // Query element.
- base::string16 url_query;
- const float kPixelWidthDotsTrailer = GetStringWidthF(
- base::string16(kEllipsisUTF16), font_list);
- if (parsed.query.is_nonempty()) {
- url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin);
- if (available_pixel_width >=
- (pixel_width_url_subdomain + pixel_width_url_domain +
- pixel_width_url_path - GetStringWidthF(url_query, font_list))) {
- return ElideText(url_subdomain + url_domain + url_path_query_etc,
- font_list, available_pixel_width, ELIDE_AT_END);
- }
- }
+// U+2026 in utf8
+const char kEllipsis[] = "\xE2\x80\xA6";
+const base::char16 kEllipsisUTF16[] = { 0x2026, 0 };
+const base::char16 kForwardSlash = '/';
- // Parse url_path using '/'.
- std::vector<base::string16> url_path_elements;
- base::SplitString(url_path, kForwardSlash, &url_path_elements);
-
- // Get filename - note that for a path ending with /
- // such as www.google.com/intl/ads/, the file name is ads/.
- size_t url_path_number_of_elements = url_path_elements.size();
- DCHECK(url_path_number_of_elements != 0);
- base::string16 url_filename;
- if ((url_path_elements.at(url_path_number_of_elements - 1)).length() > 0) {
- url_filename = *(url_path_elements.end() - 1);
- } else if (url_path_number_of_elements > 1) { // Path ends with a '/'.
- url_filename = url_path_elements.at(url_path_number_of_elements - 2) +
- kForwardSlash;
- url_path_number_of_elements--;
- }
- DCHECK(url_path_number_of_elements != 0);
-
- const size_t kMaxNumberOfUrlPathElementsAllowed = 1024;
- if (url_path_number_of_elements <= 1 ||
- url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
- // No path to elide, or too long of a path (could overflow in loop below)
- // Just elide this as a text string.
- return ElideText(url_subdomain + url_domain + url_path_query_etc, font_list,
- available_pixel_width, ELIDE_AT_END);
- }
+StringSlicer::StringSlicer(const base::string16& text,
+ const base::string16& ellipsis,
+ bool elide_in_middle,
+ bool elide_at_beginning)
+ : text_(text),
+ ellipsis_(ellipsis),
+ elide_in_middle_(elide_in_middle),
+ elide_at_beginning_(elide_at_beginning) {
+}
- // Start eliding the path and replacing elements by ".../".
- const base::string16 kEllipsisAndSlash =
- base::string16(kEllipsisUTF16) + kForwardSlash;
- const float pixel_width_ellipsis_slash =
- GetStringWidthF(kEllipsisAndSlash, font_list);
-
- // Check with both subdomain and domain.
- base::string16 elided_path =
- ElideComponentizedPath(url_subdomain + url_domain, url_path_elements,
- url_filename, url_query, font_list,
- available_pixel_width);
- if (!elided_path.empty())
- return elided_path;
-
- // Check with only domain.
- // If a subdomain is present, add an ellipsis before domain.
- // This is added only if the subdomain pixel width is larger than
- // the pixel width of kEllipsis. Otherwise, subdomain remains,
- // which means that this case has been resolved earlier.
- base::string16 url_elided_domain = url_subdomain + url_domain;
- if (pixel_width_url_subdomain > kPixelWidthDotsTrailer) {
- if (!url_subdomain.empty())
- url_elided_domain = kEllipsisAndSlash[0] + url_domain;
- else
- url_elided_domain = url_domain;
-
- elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
- url_filename, url_query, font_list,
- available_pixel_width);
-
- if (!elided_path.empty())
- return elided_path;
- }
+base::string16 StringSlicer::CutString(size_t length, bool insert_ellipsis) {
+ const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_
+ : base::string16();
+
+ if (elide_at_beginning_)
+ return ellipsis_text +
+ text_.substr(FindValidBoundaryBefore(text_.length() - length));
+
+ if (!elide_in_middle_)
+ return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text;
+
+ // We put the extra character, if any, before the cut.
+ const size_t half_length = length / 2;
+ const size_t prefix_length = FindValidBoundaryBefore(length - half_length);
+ const size_t suffix_start_guess = text_.length() - half_length;
+ const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess);
+ const size_t suffix_length =
+ half_length - (suffix_start_guess - suffix_start);
+ return text_.substr(0, prefix_length) + ellipsis_text +
+ text_.substr(suffix_start, suffix_length);
+}
- // Return elided domain/.../filename anyway.
- base::string16 final_elided_url_string(url_elided_domain);
- const float url_elided_domain_width = GetStringWidthF(url_elided_domain,
- font_list);
-
- // A hack to prevent trailing ".../...".
- if ((available_pixel_width - url_elided_domain_width) >
- pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
- GetStringWidthF(ASCIIToUTF16("UV"), font_list)) {
- final_elided_url_string += BuildPathFromComponents(base::string16(),
- url_path_elements, url_filename, 1);
- } else {
- final_elided_url_string += url_path;
- }
+size_t StringSlicer::FindValidBoundaryBefore(size_t index) const {
+ DCHECK_LE(index, text_.length());
+ if (index != text_.length())
+ U16_SET_CP_START(text_.data(), 0, index);
+ return index;
+}
- return ElideText(final_elided_url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
+size_t StringSlicer::FindValidBoundaryAfter(size_t index) const {
+ DCHECK_LE(index, text_.length());
+ if (index != text_.length())
+ U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length());
+ return index;
}
base::string16 ElideFilename(const base::FilePath& filename,
@@ -426,8 +174,8 @@ base::string16 ElideFilename(const base::FilePath& filename,
return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16);
if (rootname.empty() || extension.empty()) {
- const base::string16 elided_name = ElideText(filename_utf16, font_list,
- available_pixel_width, ELIDE_AT_END);
+ const base::string16 elided_name =
+ ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_TAIL);
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
@@ -442,14 +190,13 @@ base::string16 ElideFilename(const base::FilePath& filename,
if (ext_width >= available_pixel_width) {
const base::string16 elided_name = ElideText(
- rootname + extension, font_list, available_pixel_width,
- ELIDE_IN_MIDDLE);
+ rootname + extension, font_list, available_pixel_width, ELIDE_MIDDLE);
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
float available_root_width = available_pixel_width - ext_width;
base::string16 elided_name =
- ElideText(rootname, font_list, available_root_width, ELIDE_AT_END);
+ ElideText(rootname, font_list, available_root_width, ELIDE_TAIL);
elided_name += extension;
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
@@ -457,16 +204,19 @@ base::string16 ElideFilename(const base::FilePath& filename,
base::string16 ElideText(const base::string16& text,
const FontList& font_list,
float available_pixel_width,
- ElideBehavior elide_behavior) {
- if (text.empty())
+ ElideBehavior behavior) {
+ DCHECK_NE(behavior, FADE_TAIL);
+ if (text.empty() || behavior == FADE_TAIL)
return text;
+ if (behavior == ELIDE_EMAIL)
+ return ElideEmail(text, font_list, available_pixel_width);
const float current_text_pixel_width = GetStringWidthF(text, font_list);
- const bool elide_in_middle = (elide_behavior == ELIDE_IN_MIDDLE);
- const bool insert_ellipsis = (elide_behavior != TRUNCATE_AT_END);
-
+ const bool elide_in_middle = (behavior == ELIDE_MIDDLE);
+ const bool elide_at_beginning = (behavior == ELIDE_HEAD);
+ const bool insert_ellipsis = (behavior != TRUNCATE);
const base::string16 ellipsis = base::string16(kEllipsisUTF16);
- StringSlicer slicer(text, ellipsis, elide_in_middle);
+ StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
// Pango will return 0 width for absurdly long strings. Cut the string in
// half and try again.
@@ -476,9 +226,10 @@ base::string16 ElideText(const base::string16& text,
// return positive numbers again. Detecting that is probably not worth it
// (eliding way too much from a ridiculous string is probably still
// ridiculous), but we should check other widths for bogus values as well.
- if (current_text_pixel_width <= 0 && !text.empty()) {
- const base::string16 cut = slicer.CutString(text.length() / 2, false);
- return ElideText(cut, font_list, available_pixel_width, elide_behavior);
+ if (current_text_pixel_width <= 0) {
+ const base::string16 cut =
+ slicer.CutString(text.length() / 2, insert_ellipsis);
+ return ElideText(cut, font_list, available_pixel_width, behavior);
}
if (current_text_pixel_width <= available_pixel_width)
@@ -493,103 +244,30 @@ base::string16 ElideText(const base::string16& text,
size_t hi = text.length() - 1;
size_t guess;
for (guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) {
- // We check the length of the whole desired string at once to ensure we
+ // We check the width of the whole desired string at once to ensure we
// handle kerning/ligatures/etc. correctly.
+ // TODO(skanuj) : Handle directionality of ellipsis based on adjacent
+ // characters. See crbug.com/327963.
const base::string16 cut = slicer.CutString(guess, insert_ellipsis);
- const float guess_length = GetStringWidthF(cut, font_list);
- // Check again that we didn't hit a Pango width overflow. If so, cut the
- // current string in half and start over.
- if (guess_length <= 0) {
- return ElideText(slicer.CutString(guess / 2, false),
- font_list, available_pixel_width, elide_behavior);
- }
- if (guess_length > available_pixel_width)
+ const float guess_width = GetStringWidthF(cut, font_list);
+ if (guess_width == available_pixel_width)
+ break;
+ if (guess_width > available_pixel_width) {
hi = guess - 1;
- else
+ // Move back if we are on loop terminating condition, and guess is wider
+ // than available.
+ if (hi < lo)
+ lo = hi;
+ } else {
lo = guess + 1;
+ }
}
return slicer.CutString(guess, insert_ellipsis);
}
-base::string16 ElideText(const base::string16& text,
- const Font& font,
- float available_pixel_width,
- ElideBehavior elide_behavior) {
- return ElideText(text, FontList(font), available_pixel_width, elide_behavior);
-}
-
-SortedDisplayURL::SortedDisplayURL(const GURL& url,
- const std::string& languages) {
- net::AppendFormattedHost(url, languages, &sort_host_);
- base::string16 host_minus_www = net::StripWWW(sort_host_);
- url_parse::Parsed parsed;
- display_url_ =
- net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- net::UnescapeRule::SPACES, &parsed, &prefix_end_, NULL);
- if (sort_host_.length() > host_minus_www.length()) {
- prefix_end_ += sort_host_.length() - host_minus_www.length();
- sort_host_.swap(host_minus_www);
- }
-}
-
-SortedDisplayURL::SortedDisplayURL() : prefix_end_(0) {
-}
-
-SortedDisplayURL::~SortedDisplayURL() {
-}
-
-int SortedDisplayURL::Compare(const SortedDisplayURL& other,
- icu::Collator* collator) const {
- // Compare on hosts first. The host won't contain 'www.'.
- UErrorCode compare_status = U_ZERO_ERROR;
- UCollationResult host_compare_result = collator->compare(
- static_cast<const UChar*>(sort_host_.c_str()),
- static_cast<int>(sort_host_.length()),
- static_cast<const UChar*>(other.sort_host_.c_str()),
- static_cast<int>(other.sort_host_.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- if (host_compare_result != 0)
- return host_compare_result;
-
- // Hosts match, compare on the portion of the url after the host.
- base::string16 path = this->AfterHost();
- base::string16 o_path = other.AfterHost();
- compare_status = U_ZERO_ERROR;
- UCollationResult path_compare_result = collator->compare(
- static_cast<const UChar*>(path.c_str()),
- static_cast<int>(path.length()),
- static_cast<const UChar*>(o_path.c_str()),
- static_cast<int>(o_path.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- if (path_compare_result != 0)
- return path_compare_result;
-
- // Hosts and paths match, compare on the complete url. This'll push the www.
- // ones to the end.
- compare_status = U_ZERO_ERROR;
- UCollationResult display_url_compare_result = collator->compare(
- static_cast<const UChar*>(display_url_.c_str()),
- static_cast<int>(display_url_.length()),
- static_cast<const UChar*>(other.display_url_.c_str()),
- static_cast<int>(other.display_url_.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- return display_url_compare_result;
-}
-
-base::string16 SortedDisplayURL::AfterHost() const {
- const size_t slash_index = display_url_.find(sort_host_, prefix_end_);
- if (slash_index == base::string16::npos) {
- NOTREACHED();
- return base::string16();
- }
- return display_url_.substr(slash_index + sort_host_.length());
-}
-
-bool ElideString(const base::string16& input, int max_len,
+bool ElideString(const base::string16& input,
+ int max_len,
base::string16* output) {
DCHECK_GE(max_len, 0);
if (static_cast<int>(input.length()) <= max_len) {
@@ -915,7 +593,7 @@ int RectangleText::Finalize() {
// Remove trailing whitespace from the last line or remove the last line
// completely, if it's just whitespace.
if (!insufficient_height_ && !lines_->empty()) {
- TrimWhitespace(lines_->back(), TRIM_TRAILING, &lines_->back());
+ base::TrimWhitespace(lines_->back(), base::TRIM_TRAILING, &lines_->back());
if (lines_->back().empty() && !last_line_ended_in_lf_)
lines_->pop_back();
}
@@ -943,9 +621,10 @@ void RectangleText::AddLine(const base::string16& line) {
if (truncate) {
// Trim trailing whitespace from the line that was added.
const int line = lines_->size() - lines_added;
- TrimWhitespace(lines_->at(line), TRIM_TRAILING, &lines_->at(line));
+ base::TrimWhitespace(lines_->at(line), base::TRIM_TRAILING,
+ &lines_->at(line));
}
- if (ContainsOnlyWhitespace(word)) {
+ if (base::ContainsOnlyChars(word, base::kWhitespaceUTF16)) {
// Skip the first space if the previous line was carried over.
current_width_ = 0;
current_line_.clear();
@@ -967,11 +646,10 @@ int RectangleText::WrapWord(const base::string16& word) {
bool first_fragment = true;
while (!insufficient_height_ && !text.empty()) {
base::string16 fragment =
- ElideText(text, font_list_, available_pixel_width_,
- TRUNCATE_AT_END);
+ ElideText(text, font_list_, available_pixel_width_, TRUNCATE);
// At least one character has to be added at every line, even if the
// available space is too small.
- if(fragment.empty())
+ if (fragment.empty())
fragment = text.substr(0, 1);
if (!first_fragment && NewLine())
lines_added++;
@@ -999,7 +677,7 @@ int RectangleText::AddWordOverflow(const base::string16& word) {
lines_added += WrapWord(word);
} else {
const ElideBehavior elide_behavior =
- (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_AT_END : TRUNCATE_AT_END);
+ (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE);
const base::string16 elided_word =
ElideText(word, font_list_, available_pixel_width_, elide_behavior);
AddToCurrentLine(elided_word);
@@ -1012,7 +690,7 @@ int RectangleText::AddWordOverflow(const base::string16& word) {
int RectangleText::AddWord(const base::string16& word) {
int lines_added = 0;
base::string16 trimmed;
- TrimWhitespace(word, TRIM_TRAILING, &trimmed);
+ base::TrimWhitespace(word, base::TRIM_TRAILING, &trimmed);
const float trimmed_width = GetStringWidthF(trimmed, font_list_);
if (trimmed_width <= available_pixel_width_) {
// Word can be made to fit, no need to fragment it.
diff --git a/chromium/ui/gfx/text_elider.h b/chromium/ui/gfx/text_elider.h
index 4eaca828c7d..a416fda779e 100644
--- a/chromium/ui/gfx/text_elider.h
+++ b/chromium/ui/gfx/text_elider.h
@@ -12,9 +12,8 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
-#include "third_party/icu/source/i18n/unicode/coll.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/text_constants.h"
class GURL;
@@ -23,65 +22,52 @@ class FilePath;
}
namespace gfx {
-class Font;
class FontList;
GFX_EXPORT extern const char kEllipsis[];
GFX_EXPORT extern const base::char16 kEllipsisUTF16[];
+GFX_EXPORT extern const base::char16 kForwardSlash;
-// Elides a well-formed email address (e.g. username@domain.com) to fit into
-// |available_pixel_width| using the specified |font_list|.
-// This function guarantees that the string returned will contain at least one
-// character, other than the ellipses, on either side of the '@'. If it is
-// impossible to achieve these requirements: only an ellipsis will be returned.
-// If possible: this elides only the username portion of the |email|. Otherwise,
-// the domain is elided in the middle so that it splits the available width
-// equally with the elided username (should the username be short enough that it
-// doesn't need half the available width: the elided domain will occupy that
-// extra width).
-GFX_EXPORT base::string16 ElideEmail(const base::string16& email,
- const gfx::FontList& font_list,
- float available_pixel_width);
-
-// This function takes a GURL object and elides it. It returns a string
-// which composed of parts from subdomain, domain, path, filename and query.
-// A "..." is added automatically at the end if the elided string is bigger
-// than the |available_pixel_width|. For |available_pixel_width| == 0, a
-// formatted, but un-elided, string is returned. |languages| is a comma
-// separated list of ISO 639 language codes and is used to determine what
-// characters are understood by a user. It should come from
-// |prefs::kAcceptLanguages|.
-//
-// Note: in RTL locales, if the URL returned by this function is going to be
-// displayed in the UI, then it is likely that the string needs to be marked
-// as an LTR string (using base::i18n::WrapStringWithLTRFormatting()) so that it
-// is displayed properly in an RTL context. Please refer to
-// http://crbug.com/6487 for more information.
-GFX_EXPORT base::string16 ElideUrl(const GURL& url,
- const gfx::FontList& font_list,
- float available_pixel_width,
- const std::string& languages);
-
-enum ElideBehavior {
- // Add ellipsis at the end of the string.
- ELIDE_AT_END,
- // Add ellipsis in the middle of the string.
- ELIDE_IN_MIDDLE,
- // Truncate the end of the string.
- TRUNCATE_AT_END
+// Helper class to split + elide text, while respecting UTF16 surrogate pairs.
+class StringSlicer {
+ public:
+ StringSlicer(const base::string16& text,
+ const base::string16& ellipsis,
+ bool elide_in_middle,
+ bool elide_at_beginning);
+
+ // Cuts |text_| to be |length| characters long. If |elide_in_middle_| is true,
+ // the middle of the string is removed to leave equal-length pieces from the
+ // beginning and end of the string; otherwise, the end of the string is
+ // removed and only the beginning remains. If |insert_ellipsis| is true,
+ // then an ellipsis character will be inserted at the cut point.
+ base::string16 CutString(size_t length, bool insert_ellipsis);
+
+ private:
+ // Returns a valid cut boundary at or before/after |index|.
+ size_t FindValidBoundaryBefore(size_t index) const;
+ size_t FindValidBoundaryAfter(size_t index) const;
+
+ // The text to be sliced.
+ const base::string16& text_;
+
+ // Ellipsis string to use.
+ const base::string16& ellipsis_;
+
+ // If true, the middle of the string will be elided.
+ bool elide_in_middle_;
+
+ // If true, the beginning of the string will be elided.
+ bool elide_at_beginning_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringSlicer);
};
-// Elides |text| to fit in |available_pixel_width| according to the specified
-// |elide_behavior|.
+// Elides |text| to fit the |available_pixel_width| with the specified behavior.
GFX_EXPORT base::string16 ElideText(const base::string16& text,
const gfx::FontList& font_list,
float available_pixel_width,
ElideBehavior elide_behavior);
-// Obsolete version. Use the above version which takes gfx::FontList.
-GFX_EXPORT base::string16 ElideText(const base::string16& text,
- const gfx::Font& font,
- float available_pixel_width,
- ElideBehavior elide_behavior);
// Elide a filename to fit a given pixel width, with an emphasis on not hiding
// the extension unless we have to. If filename contains a path, the path will
@@ -93,45 +79,9 @@ GFX_EXPORT base::string16 ElideFilename(const base::FilePath& filename,
const gfx::FontList& font_list,
float available_pixel_width);
-// SortedDisplayURL maintains a string from a URL suitable for display to the
-// use. SortedDisplayURL also provides a function used for comparing two
-// SortedDisplayURLs for use in visually ordering the SortedDisplayURLs.
-//
-// SortedDisplayURL is relatively cheap and supports value semantics.
-class GFX_EXPORT SortedDisplayURL {
- public:
- SortedDisplayURL(const GURL& url, const std::string& languages);
- SortedDisplayURL();
- ~SortedDisplayURL();
-
- // Compares this SortedDisplayURL to |url| using |collator|. Returns a value
- // < 0, = 1 or > 0 as to whether this url is less then, equal to or greater
- // than the supplied url.
- int Compare(const SortedDisplayURL& other, icu::Collator* collator) const;
-
- // Returns the display string for the URL.
- const base::string16& display_url() const { return display_url_; }
-
- private:
- // Returns everything after the host. This is used by Compare if the hosts
- // match.
- base::string16 AfterHost() const;
-
- // Host name minus 'www.'. Used by Compare.
- base::string16 sort_host_;
-
- // End of the prefix (spec and separator) in display_url_.
- size_t prefix_end_;
-
- base::string16 display_url_;
-
- DISALLOW_COPY_AND_ASSIGN(SortedDisplayURL);
-};
-
-// Functions to elide strings when the font information is unknown. As
-// opposed to the above functions, the ElideString() and
-// ElideRectangleString() functions operate in terms of character units,
-// not pixels.
+// Functions to elide strings when the font information is unknown. As opposed
+// to the above functions, ElideString() and ElideRectangleString() operate in
+// terms of character units, not pixels.
// If the size of |input| is more than |max_len|, this function returns
// true and |input| is shortened into |output| by removing chars in the
diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc
index 5fa74cbd101..0b6bcad7f5a 100644
--- a/chromium/ui/gfx/text_elider_unittest.cc
+++ b/chromium/ui/gfx/text_elider_unittest.cc
@@ -15,7 +15,12 @@
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
-#include "url/gurl.h"
+
+using base::ASCIIToUTF16;
+using base::UTF16ToUTF8;
+using base::UTF16ToWide;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
namespace gfx {
@@ -32,8 +37,8 @@ struct FileTestcase {
};
struct UTF16Testcase {
- const string16 input;
- const string16 output;
+ const base::string16 input;
+ const base::string16 output;
};
struct TestData {
@@ -42,24 +47,12 @@ struct TestData {
const int compare_result;
};
-void RunUrlTest(Testcase* testcases, size_t num_testcases) {
- static const FontList font_list;
- for (size_t i = 0; i < num_testcases; ++i) {
- const GURL url(testcases[i].input);
- // Should we test with non-empty language list?
- // That's kinda redundant with net_util_unittests.
- const float available_width =
- GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list);
- EXPECT_EQ(UTF8ToUTF16(testcases[i].output),
- ElideUrl(url, font_list, available_width, std::string()));
- }
-}
-
} // namespace
// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF
// that calls [NSString sizeWithFont] returns the rounded string width.
-#if defined(OS_IOS)
+// TODO(338784): Enable this on android.
+#if defined(OS_IOS) || defined(OS_ANDROID)
#define MAYBE_ElideEmail DISABLED_ElideEmail
#else
#define MAYBE_ElideEmail ElideEmail
@@ -111,16 +104,21 @@ TEST(TextEliderTest, MAYBE_ElideEmail) {
const FontList font_list;
for (size_t i = 0; i < arraysize(testcases); ++i) {
- const string16 expected_output = UTF8ToUTF16(testcases[i].output);
+ const base::string16 expected_output = UTF8ToUTF16(testcases[i].output);
EXPECT_EQ(expected_output,
- ElideEmail(
- UTF8ToUTF16(testcases[i].input),
- font_list,
- GetStringWidthF(expected_output, font_list)));
+ ElideText(UTF8ToUTF16(testcases[i].input), font_list,
+ GetStringWidthF(expected_output, font_list),
+ ELIDE_EMAIL));
}
}
-TEST(TextEliderTest, ElideEmailMoreSpace) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideEmailMoreSpace DISABLED_ElideEmailMoreSpace
+#else
+#define MAYBE_ElideEmailMoreSpace ElideEmailMoreSpace
+#endif
+TEST(TextEliderTest, MAYBE_ElideEmailMoreSpace) {
const int test_width_factors[] = {
100,
10000,
@@ -139,141 +137,17 @@ TEST(TextEliderTest, ElideEmailMoreSpace) {
font_list.GetExpectedTextWidth(test_width_factors[i]);
for (size_t j = 0; j < arraysize(test_emails); ++j) {
// Extra space is available: the email should not be elided.
- const string16 test_email = UTF8ToUTF16(test_emails[j]);
- EXPECT_EQ(test_email, ElideEmail(test_email, font_list, test_width));
+ const base::string16 test_email = UTF8ToUTF16(test_emails[j]);
+ EXPECT_EQ(test_email,
+ ElideText(test_email, font_list, test_width, ELIDE_EMAIL));
}
}
}
-// Test eliding of commonplace URLs.
-TEST(TextEliderTest, TestGeneralEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"http://www.google.com/intl/en/ads/",
- "www.google.com/intl/en/ads/"},
- {"http://www.google.com/intl/en/ads/", "www.google.com/intl/en/ads/"},
- {"http://www.google.com/intl/en/ads/",
- "google.com/intl/" + kEllipsisStr + "/ads/"},
- {"http://www.google.com/intl/en/ads/",
- "google.com/" + kEllipsisStr + "/ads/"},
- {"http://www.google.com/intl/en/ads/", "google.com/" + kEllipsisStr},
- {"http://www.google.com/intl/en/ads/", "goog" + kEllipsisStr},
- {"https://subdomain.foo.com/bar/filename.html",
- "subdomain.foo.com/bar/filename.html"},
- {"https://subdomain.foo.com/bar/filename.html",
- "subdomain.foo.com/" + kEllipsisStr + "/filename.html"},
- {"http://subdomain.foo.com/bar/filename.html",
- kEllipsisStr + "foo.com/" + kEllipsisStr + "/filename.html"},
- {"http://www.google.com/intl/en/ads/?aLongQueryWhichIsNotRequired",
- "www.google.com/intl/en/ads/?aLongQ" + kEllipsisStr},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// When there is very little space available, the elision code will shorten
-// both path AND file name to an ellipsis - ".../...". To avoid this result,
-// there is a hack in place that simply treats them as one string in this
-// case.
-TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) {
- const std::string kEllipsisStr(kEllipsis);
-
- // Very little space, would cause double ellipsis.
- FontList font_list;
- GURL url("http://battersbox.com/directory/foo/peter_paul_and_mary.html");
- float available_width = GetStringWidthF(
- UTF8ToUTF16("battersbox.com/" + kEllipsisStr + "/" + kEllipsisStr),
- font_list);
-
- // Create the expected string, after elision. Depending on font size, the
- // directory might become /dir... or /di... or/d... - it never should be
- // shorter than that. (If it is, the font considers d... to be longer
- // than .../... - that should never happen).
- ASSERT_GT(GetStringWidthF(UTF8ToUTF16(kEllipsisStr + "/" + kEllipsisStr),
- font_list),
- GetStringWidthF(UTF8ToUTF16("d" + kEllipsisStr), font_list));
- GURL long_url("http://battersbox.com/directorynameisreallylongtoforcetrunc");
- string16 expected =
- ElideUrl(long_url, font_list, available_width, std::string());
- // Ensure that the expected result still contains part of the directory name.
- ASSERT_GT(expected.length(), std::string("battersbox.com/d").length());
- EXPECT_EQ(expected,
- ElideUrl(url, font_list, available_width, std::string()));
-
- // More space available - elide directories, partially elide filename.
- Testcase testcases[] = {
- {"http://battersbox.com/directory/foo/peter_paul_and_mary.html",
- "battersbox.com/" + kEllipsisStr + "/peter" + kEllipsisStr},
- };
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// Test eliding of empty strings, URLs with ports, passwords, queries, etc.
-TEST(TextEliderTest, TestMoreEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"http://www.google.com/foo?bar", "www.google.com/foo?bar"},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/foo?" + kEllipsisStr},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/foo" + kEllipsisStr},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/fo" + kEllipsisStr},
- {"http://a.b.com/pathname/c?d", "a.b.com/" + kEllipsisStr + "/c?d"},
- {"", ""},
- {"http://foo.bar..example.com...hello/test/filename.html",
- "foo.bar..example.com...hello/" + kEllipsisStr + "/filename.html"},
- {"http://foo.bar../", "foo.bar.."},
- {"http://xn--1lq90i.cn/foo", "\xe5\x8c\x97\xe4\xba\xac.cn/foo"},
- {"http://me:mypass@secrethost.com:99/foo?bar#baz",
- "secrethost.com:99/foo?bar#baz"},
- {"http://me:mypass@ss%xxfdsf.com/foo", "ss%25xxfdsf.com/foo"},
- {"mailto:elgoato@elgoato.com", "mailto:elgoato@elgoato.com"},
- {"javascript:click(0)", "javascript:click(0)"},
- {"https://chess.eecs.berkeley.edu:4430/login/arbitfilename",
- "chess.eecs.berkeley.edu:4430/login/arbitfilename"},
- {"https://chess.eecs.berkeley.edu:4430/login/arbitfilename",
- kEllipsisStr + "berkeley.edu:4430/" + kEllipsisStr + "/arbitfilename"},
-
- // Unescaping.
- {"http://www/%E4%BD%A0%E5%A5%BD?q=%E4%BD%A0%E5%A5%BD#\xe4\xbd\xa0",
- "www/\xe4\xbd\xa0\xe5\xa5\xbd?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
-
- // Invalid unescaping for path. The ref will always be valid UTF-8. We don't
- // bother to do too many edge cases, since these are handled by the escaper
- // unittest.
- {"http://www/%E4%A0%E5%A5%BD?q=%E4%BD%A0%E5%A5%BD#\xe4\xbd\xa0",
- "www/%E4%A0%E5%A5%BD?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// Test eliding of file: URLs.
-TEST(TextEliderTest, TestFileURLEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"file:///C:/path1/path2/path3/filename",
- "file:///C:/path1/path2/path3/filename"},
- {"file:///C:/path1/path2/path3/filename",
- "C:/path1/path2/path3/filename"},
-// GURL parses "file:///C:path" differently on windows than it does on posix.
-#if defined(OS_WIN)
- {"file:///C:path1/path2/path3/filename",
- "C:/path1/path2/" + kEllipsisStr + "/filename"},
- {"file:///C:path1/path2/path3/filename",
- "C:/path1/" + kEllipsisStr + "/filename"},
- {"file:///C:path1/path2/path3/filename",
- "C:/" + kEllipsisStr + "/filename"},
-#endif
- {"file://filer/foo/bar/file", "filer/foo/bar/file"},
- {"file://filer/foo/bar/file", "filer/foo/" + kEllipsisStr + "/file"},
- {"file://filer/foo/bar/file", "filer/" + kEllipsisStr + "/file"},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF
// that calls [NSString sizeWithFont] returns the rounded string width.
-#if defined(OS_IOS)
+// TODO(338784): Enable this on android.
+#if defined(OS_IOS) || defined(OS_ANDROID)
#define MAYBE_TestFilenameEliding DISABLED_TestFilenameEliding
#else
#define MAYBE_TestFilenameEliding TestFilenameEliding
@@ -320,14 +194,20 @@ TEST(TextEliderTest, MAYBE_TestFilenameEliding) {
static const FontList font_list;
for (size_t i = 0; i < arraysize(testcases); ++i) {
base::FilePath filepath(testcases[i].input);
- string16 expected = UTF8ToUTF16(testcases[i].output);
+ base::string16 expected = UTF8ToUTF16(testcases[i].output);
expected = base::i18n::GetDisplayStringInLTRDirectionality(expected);
EXPECT_EQ(expected, ElideFilename(filepath, font_list,
GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list)));
}
}
-TEST(TextEliderTest, ElideTextTruncate) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextTruncate DISABLED_ElideTextTruncate
+#else
+#define MAYBE_ElideTextTruncate ElideTextTruncate
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextTruncate) {
const FontList font_list;
const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
struct TestData {
@@ -344,13 +224,19 @@ TEST(TextEliderTest, ElideTextTruncate) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
- cases[i].width, TRUNCATE_AT_END);
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, TRUNCATE);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
}
}
-TEST(TextEliderTest, ElideTextEllipsis) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextEllipsis DISABLED_ElideTextEllipsis
+#else
+#define MAYBE_ElideTextEllipsis ElideTextEllipsis
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextEllipsis) {
const FontList font_list;
const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
const char* kEllipsis = "\xE2\x80\xA6";
@@ -370,79 +256,132 @@ TEST(TextEliderTest, ElideTextEllipsis) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
- cases[i].width, ELIDE_AT_END);
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, ELIDE_TAIL);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
}
}
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextEllipsisFront DISABLED_ElideTextEllipsisFront
+#else
+#define MAYBE_ElideTextEllipsisFront ElideTextEllipsisFront
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextEllipsisFront) {
+ const FontList font_list;
+ const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
+ const std::string kEllipsisStr(kEllipsis);
+ const float kEllipsisWidth =
+ GetStringWidthF(UTF8ToUTF16(kEllipsis), font_list);
+ const float kEllipsis23Width =
+ GetStringWidthF(UTF8ToUTF16(kEllipsisStr + "23"), font_list);
+ struct TestData {
+ const char* input;
+ float width;
+ const base::string16 output;
+ } cases[] = {
+ { "", 0, base::string16() },
+ { "Test", 0, base::string16() },
+ { "Test", kEllipsisWidth, UTF8ToUTF16(kEllipsisStr) },
+ { "", kTestWidth, base::string16() },
+ { "Tes", kTestWidth, ASCIIToUTF16("Tes") },
+ { "Test", kTestWidth, ASCIIToUTF16("Test") },
+ { "Test123", kEllipsis23Width, UTF8ToUTF16(kEllipsisStr + "23") },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, ELIDE_HEAD);
+ EXPECT_EQ(cases[i].output, result);
+ }
+}
+
// Checks that all occurrences of |first_char| are followed by |second_char| and
// all occurrences of |second_char| are preceded by |first_char| in |text|.
-static void CheckSurrogatePairs(const string16& text,
- char16 first_char,
- char16 second_char) {
+static void CheckSurrogatePairs(const base::string16& text,
+ base::char16 first_char,
+ base::char16 second_char) {
size_t index = text.find_first_of(first_char);
- while (index != string16::npos) {
+ while (index != base::string16::npos) {
EXPECT_LT(index, text.length() - 1);
EXPECT_EQ(second_char, text[index + 1]);
index = text.find_first_of(first_char, index + 1);
}
index = text.find_first_of(second_char);
- while (index != string16::npos) {
+ while (index != base::string16::npos) {
EXPECT_GT(index, 0U);
EXPECT_EQ(first_char, text[index - 1]);
index = text.find_first_of(second_char, index + 1);
}
}
-TEST(TextEliderTest, ElideTextSurrogatePairs) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextSurrogatePairs DISABLED_ElideTextSurrogatePairs
+#else
+#define MAYBE_ElideTextSurrogatePairs ElideTextSurrogatePairs
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextSurrogatePairs) {
const FontList font_list;
// The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
// two characters forming a surrogate pair 0x0001D11E.
const std::string kSurrogate = "\xF0\x9D\x84\x9E";
- const string16 kTestString =
+ const base::string16 kTestString =
UTF8ToUTF16(kSurrogate + "ab" + kSurrogate + kSurrogate + "cd");
const float kTestStringWidth = GetStringWidthF(kTestString, font_list);
- const char16 kSurrogateFirstChar = kTestString[0];
- const char16 kSurrogateSecondChar = kTestString[1];
- string16 result;
+ const base::char16 kSurrogateFirstChar = kTestString[0];
+ const base::char16 kSurrogateSecondChar = kTestString[1];
+ base::string16 result;
// Elide |kTextString| to all possible widths and check that no instance of
// |kSurrogate| was split in two.
for (float width = 0; width <= kTestStringWidth; width++) {
- result = ElideText(kTestString, font_list, width, TRUNCATE_AT_END);
+ result = ElideText(kTestString, font_list, width, TRUNCATE);
+ CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
+
+ result = ElideText(kTestString, font_list, width, ELIDE_TAIL);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
- result = ElideText(kTestString, font_list, width, ELIDE_AT_END);
+ result = ElideText(kTestString, font_list, width, ELIDE_MIDDLE);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
- result = ElideText(kTestString, font_list, width, ELIDE_IN_MIDDLE);
+ result = ElideText(kTestString, font_list, width, ELIDE_HEAD);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
}
}
-TEST(TextEliderTest, ElideTextLongStrings) {
- const string16 kEllipsisStr = UTF8ToUTF16(kEllipsis);
- string16 data_scheme(UTF8ToUTF16("data:text/plain,"));
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextLongStrings DISABLED_ElideTextLongStrings
+#else
+#define MAYBE_ElideTextLongStrings ElideTextLongStrings
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextLongStrings) {
+ const base::string16 kEllipsisStr = UTF8ToUTF16(kEllipsis);
+ base::string16 data_scheme(UTF8ToUTF16("data:text/plain,"));
size_t data_scheme_length = data_scheme.length();
- string16 ten_a(10, 'a');
- string16 hundred_a(100, 'a');
- string16 thousand_a(1000, 'a');
- string16 ten_thousand_a(10000, 'a');
- string16 hundred_thousand_a(100000, 'a');
- string16 million_a(1000000, 'a');
+ base::string16 ten_a(10, 'a');
+ base::string16 hundred_a(100, 'a');
+ base::string16 thousand_a(1000, 'a');
+ base::string16 ten_thousand_a(10000, 'a');
+ base::string16 hundred_thousand_a(100000, 'a');
+ base::string16 million_a(1000000, 'a');
+
+ // TODO(gbillock): Improve these tests by adding more string diversity and
+ // doing string compares instead of length compares. See bug 338836.
size_t number_of_as = 156;
- string16 long_string_end(
- data_scheme + string16(number_of_as, 'a') + kEllipsisStr);
+ base::string16 long_string_end(
+ data_scheme + base::string16(number_of_as, 'a') + kEllipsisStr);
UTF16Testcase testcases_end[] = {
- {data_scheme + ten_a, data_scheme + ten_a},
- {data_scheme + hundred_a, data_scheme + hundred_a},
- {data_scheme + thousand_a, long_string_end},
- {data_scheme + ten_thousand_a, long_string_end},
- {data_scheme + hundred_thousand_a, long_string_end},
- {data_scheme + million_a, long_string_end},
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_end },
+ { data_scheme + ten_thousand_a, long_string_end },
+ { data_scheme + hundred_thousand_a, long_string_end },
+ { data_scheme + million_a, long_string_end },
};
const FontList font_list;
@@ -451,85 +390,58 @@ TEST(TextEliderTest, ElideTextLongStrings) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_end[i].output.size(),
- ElideText(
- testcases_end[i].input,
- font_list,
- GetStringWidthF(testcases_end[i].output, font_list),
- ELIDE_AT_END).size());
+ ElideText(testcases_end[i].input, font_list,
+ GetStringWidthF(testcases_end[i].output, font_list),
+ ELIDE_TAIL).size());
EXPECT_EQ(kEllipsisStr,
ElideText(testcases_end[i].input, font_list, ellipsis_width,
- ELIDE_AT_END));
+ ELIDE_TAIL));
}
size_t number_of_trailing_as = (data_scheme_length + number_of_as) / 2;
- string16 long_string_middle(data_scheme +
- string16(number_of_as - number_of_trailing_as, 'a') + kEllipsisStr +
- string16(number_of_trailing_as, 'a'));
+ base::string16 long_string_middle(data_scheme +
+ base::string16(number_of_as - number_of_trailing_as, 'a') + kEllipsisStr +
+ base::string16(number_of_trailing_as, 'a'));
UTF16Testcase testcases_middle[] = {
- {data_scheme + ten_a, data_scheme + ten_a},
- {data_scheme + hundred_a, data_scheme + hundred_a},
- {data_scheme + thousand_a, long_string_middle},
- {data_scheme + ten_thousand_a, long_string_middle},
- {data_scheme + hundred_thousand_a, long_string_middle},
- {data_scheme + million_a, long_string_middle},
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_middle },
+ { data_scheme + ten_thousand_a, long_string_middle },
+ { data_scheme + hundred_thousand_a, long_string_middle },
+ { data_scheme + million_a, long_string_middle },
};
for (size_t i = 0; i < arraysize(testcases_middle); ++i) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_middle[i].output.size(),
- ElideText(
- testcases_middle[i].input,
- font_list,
- GetStringWidthF(testcases_middle[i].output, font_list),
- ELIDE_AT_END).size());
+ ElideText(testcases_middle[i].input, font_list,
+ GetStringWidthF(testcases_middle[i].output, font_list),
+ ELIDE_MIDDLE).size());
EXPECT_EQ(kEllipsisStr,
ElideText(testcases_middle[i].input, font_list, ellipsis_width,
- ELIDE_AT_END));
+ ELIDE_MIDDLE));
}
-}
-
-// Verifies display_url is set correctly.
-TEST(TextEliderTest, SortedDisplayURL) {
- SortedDisplayURL d_url(GURL("http://www.google.com"), std::string());
- EXPECT_EQ("www.google.com", UTF16ToASCII(d_url.display_url()));
-}
-
-// Verifies DisplayURL::Compare works correctly.
-TEST(TextEliderTest, SortedDisplayURLCompare) {
- UErrorCode create_status = U_ZERO_ERROR;
- scoped_ptr<icu::Collator> collator(
- icu::Collator::createInstance(create_status));
- if (!U_SUCCESS(create_status))
- return;
-
- TestData tests[] = {
- // IDN comparison. Hosts equal, so compares on path.
- { "http://xn--1lq90i.cn/a", "http://xn--1lq90i.cn/b", -1},
- // Because the host and after host match, this compares the full url.
- { "http://www.x/b", "http://x/b", -1 },
-
- // Because the host and after host match, this compares the full url.
- { "http://www.a:1/b", "http://a:1/b", 1 },
-
- // The hosts match, so these end up comparing on the after host portion.
- { "http://www.x:0/b", "http://x:1/b", -1 },
- { "http://www.x/a", "http://x/b", -1 },
- { "http://x/b", "http://www.x/a", 1 },
-
- // Trivial Equality.
- { "http://a/", "http://a/", 0 },
-
- // Compares just hosts.
- { "http://www.a/", "http://b/", -1 },
+ base::string16 long_string_beginning(
+ kEllipsisStr + base::string16(number_of_as, 'a'));
+ UTF16Testcase testcases_beginning[] = {
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_beginning },
+ { data_scheme + ten_thousand_a, long_string_beginning },
+ { data_scheme + hundred_thousand_a, long_string_beginning },
+ { data_scheme + million_a, long_string_beginning },
};
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- SortedDisplayURL url1(GURL(tests[i].a), std::string());
- SortedDisplayURL url2(GURL(tests[i].b), std::string());
- EXPECT_EQ(tests[i].compare_result, url1.Compare(url2, collator.get()));
- EXPECT_EQ(-tests[i].compare_result, url2.Compare(url1, collator.get()));
+ for (size_t i = 0; i < arraysize(testcases_beginning); ++i) {
+ EXPECT_EQ(testcases_beginning[i].output.size(),
+ ElideText(
+ testcases_beginning[i].input, font_list,
+ GetStringWidthF(testcases_beginning[i].output, font_list),
+ ELIDE_HEAD).size());
+ EXPECT_EQ(kEllipsisStr,
+ ElideText(testcases_beginning[i].input, font_list, ellipsis_width,
+ ELIDE_HEAD));
}
}
@@ -553,7 +465,7 @@ TEST(TextEliderTest, ElideString) {
{ "Hello, my name is Tom", 100, false, "Hello, my name is Tom" }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 output;
+ base::string16 output;
EXPECT_EQ(cases[i].result,
ElideString(UTF8ToUTF16(cases[i].input),
cases[i].max_len, &output));
@@ -561,7 +473,13 @@ TEST(TextEliderTest, ElideString) {
}
}
-TEST(TextEliderTest, ElideRectangleText) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleText DISABLED_ElideRectangleText
+#else
+#define MAYBE_ElideRectangleText ElideRectangleText
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleText) {
const FontList font_list;
const int line_height = font_list.GetHeight();
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -601,7 +519,7 @@ TEST(TextEliderTest, ElideRectangleText) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0,
ElideRectangleText(UTF8ToUTF16(cases[i].input),
font_list,
@@ -618,7 +536,14 @@ TEST(TextEliderTest, ElideRectangleText) {
}
}
-TEST(TextEliderTest, ElideRectangleTextPunctuation) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextPunctuation \
+ DISABLED_ElideRectangleTextPunctuation
+#else
+#define MAYBE_ElideRectangleTextPunctuation ElideRectangleTextPunctuation
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextPunctuation) {
const FontList font_list;
const int line_height = font_list.GetHeight();
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -639,7 +564,7 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
const WordWrapBehavior wrap_behavior =
(cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS);
EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
@@ -658,10 +583,17 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) {
}
}
-TEST(TextEliderTest, ElideRectangleTextLongWords) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextLongWords DISABLED_ElideRectangleTextLongWords
+#else
+#define MAYBE_ElideRectangleTextLongWords ElideRectangleTextLongWords
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextLongWords) {
const FontList font_list;
const int kAvailableHeight = 1000;
- const string16 kElidedTesting = UTF8ToUTF16(std::string("Tes") + kEllipsis);
+ const base::string16 kElidedTesting =
+ UTF8ToUTF16(std::string("Tes") + kEllipsis);
const float elided_width = GetStringWidthF(kElidedTesting, font_list);
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -702,7 +634,7 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
ElideRectangleText(UTF8ToUTF16(cases[i].input),
font_list,
@@ -722,7 +654,14 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) {
// fail because the truncated integer width is returned for the string
// and the accumulation of the truncated values causes the elide function
// to wrap incorrectly.
-TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextCheckLineWidth \
+ DISABLED_ElideRectangleTextCheckLineWidth
+#else
+#define MAYBE_ElideRectangleTextCheckLineWidth ElideRectangleTextCheckLineWidth
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextCheckLineWidth) {
FontList font_list;
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Use a specific font to expose the line width exceeding problem.
@@ -731,7 +670,7 @@ TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
const float kAvailableWidth = 235;
const int kAvailableHeight = 1000;
const char text[] = "that Russian place we used to go to after fencing";
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(0, ElideRectangleText(UTF8ToUTF16(text),
font_list,
kAvailableWidth,
@@ -816,7 +755,7 @@ TEST(TextEliderTest, ElideRectangleString) {
{ "Hi, my name is\nTom", 2, 20, false, "Hi, my name is\nTom" },
{ "Hi, my name is Tom", 1, 40, false, "Hi, my name is Tom" },
};
- string16 output;
+ base::string16 output;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
@@ -898,7 +837,7 @@ TEST(TextEliderTest, ElideRectangleStringNotStrict) {
{ "Hi, my name_is\nDick", 2, 20, false, "Hi, my name_is\nDick" },
{ "Hi, my name_is Dick", 1, 40, false, "Hi, my name_is Dick" },
};
- string16 output;
+ base::string16 output;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
@@ -910,17 +849,17 @@ TEST(TextEliderTest, ElideRectangleStringNotStrict) {
TEST(TextEliderTest, ElideRectangleWide16) {
// Two greek words separated by space.
- const string16 str(WideToUTF16(
+ const base::string16 str(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
- const string16 out1(WideToUTF16(
+ const base::string16 out1(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\n"
L"\x03cc\x03c3\x03bc\x03b9\n"
L"..."));
- const string16 out2(WideToUTF16(
+ const base::string16 out2(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9\x03bf\x03c2\x0020\n"
L"\x0399\x03c3\x03c4\x03cc\x03c2"));
- string16 output;
+ base::string16 output;
EXPECT_TRUE(ElideRectangleString(str, 2, 4, true, &output));
EXPECT_EQ(out1, output);
EXPECT_FALSE(ElideRectangleString(str, 2, 12, true, &output));
@@ -929,19 +868,19 @@ TEST(TextEliderTest, ElideRectangleWide16) {
TEST(TextEliderTest, ElideRectangleWide32) {
// Four U+1D49C MATHEMATICAL SCRIPT CAPITAL A followed by space "aaaaa".
- const string16 str(UTF8ToUTF16(
+ const base::string16 str(UTF8ToUTF16(
"\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C"
" aaaaa"));
- const string16 out(UTF8ToUTF16(
+ const base::string16 out(UTF8ToUTF16(
"\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\n"
"\xF0\x9D\x92\x9C \naaa\n..."));
- string16 output;
+ base::string16 output;
EXPECT_TRUE(ElideRectangleString(str, 3, 3, true, &output));
EXPECT_EQ(out, output);
}
TEST(TextEliderTest, TruncateString) {
- string16 string = ASCIIToUTF16("foooooey bxxxar baz");
+ base::string16 string = ASCIIToUTF16("foooooey bxxxar baz");
// Make sure it doesn't modify the string if length > string length.
EXPECT_EQ(string, TruncateString(string, 100));
diff --git a/chromium/ui/gfx/text_utils_unittest.cc b/chromium/ui/gfx/text_utils_unittest.cc
index 1090b388b04..0c0127fc123 100644
--- a/chromium/ui/gfx/text_utils_unittest.cc
+++ b/chromium/ui/gfx/text_utils_unittest.cc
@@ -6,11 +6,12 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/font_list.h"
namespace gfx {
namespace {
-const char16 kAcceleratorChar = '&';
+const base::char16 kAcceleratorChar = '&';
TEST(TextUtilsTest, RemoveAcceleratorChar) {
struct TestData {
@@ -48,15 +49,33 @@ TEST(TextUtilsTest, RemoveAcceleratorChar) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
int accelerated_char_pos;
int accelerated_char_span;
- base::string16 result = RemoveAcceleratorChar(UTF8ToUTF16(cases[i].input),
- kAcceleratorChar,
- &accelerated_char_pos,
- &accelerated_char_span);
- EXPECT_EQ(result, UTF8ToUTF16(cases[i].output));
+ base::string16 result = RemoveAcceleratorChar(
+ base::UTF8ToUTF16(cases[i].input),
+ kAcceleratorChar,
+ &accelerated_char_pos,
+ &accelerated_char_span);
+ EXPECT_EQ(result, base::UTF8ToUTF16(cases[i].output));
EXPECT_EQ(accelerated_char_pos, cases[i].accelerated_char_pos);
EXPECT_EQ(accelerated_char_span, cases[i].accelerated_char_span);
}
}
+// Disabled on Ozone since there are no fonts: crbug.com/320050
+#if defined(USE_OZONE)
+#define MAYBE_GetStringWidth DISABLED_GetStringWidth
+#else
+#define MAYBE_GetStringWidth GetStringWidth
+#endif
+TEST(TextUtilsTest, MAYBE_GetStringWidth) {
+ FontList font_list;
+ EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0);
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("a"), font_list),
+ GetStringWidth(base::string16(), font_list));
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("ab"), font_list),
+ GetStringWidth(base::ASCIIToUTF16("a"), font_list));
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("abc"), font_list),
+ GetStringWidth(base::ASCIIToUTF16("ab"), font_list));
+}
+
} // namespace
} // namespace gfx
diff --git a/chromium/ui/gfx/transform.h b/chromium/ui/gfx/transform.h
index 5e3b8303340..5440aac71f5 100644
--- a/chromium/ui/gfx/transform.h
+++ b/chromium/ui/gfx/transform.h
@@ -89,6 +89,9 @@ class GFX_EXPORT Transform {
// to |this|.
void Scale(SkMScalar x, SkMScalar y);
void Scale3d(SkMScalar x, SkMScalar y, SkMScalar z);
+ gfx::Vector2dF Scale2d() const {
+ return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
+ }
// Applies the current transformation on a translation and assigns the result
// to |this|.
@@ -136,6 +139,11 @@ class GFX_EXPORT Transform {
// translation.
bool IsIdentityOrIntegerTranslation() const;
+ // Returns true if the matrix had only scaling components.
+ bool IsScale2d() const {
+ return !(matrix_.getType() & ~SkMatrix44::kScale_Mask);
+ }
+
// Returns true if the matrix is has only scaling and translation components.
bool IsScaleOrTranslation() const {
int mask = SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask;
diff --git a/chromium/ui/gfx/utf16_indexing_unittest.cc b/chromium/ui/gfx/utf16_indexing_unittest.cc
index da2f8f5b56c..f93d6693660 100644
--- a/chromium/ui/gfx/utf16_indexing_unittest.cc
+++ b/chromium/ui/gfx/utf16_indexing_unittest.cc
@@ -9,8 +9,9 @@ namespace gfx {
TEST(UTF16IndexingTest, IndexOffsetConversions) {
// Valid surrogate pair surrounded by unpaired surrogates
- const char16 foo[] = {0xDC00, 0xD800, 0xD800, 0xDFFF, 0xDFFF, 0xDBFF, 0};
- const string16 s(foo);
+ const base::char16 foo[] =
+ {0xDC00, 0xD800, 0xD800, 0xDFFF, 0xDFFF, 0xDBFF, 0};
+ const base::string16 s(foo);
const size_t the_invalid_index = 3;
for (size_t i = 0; i <= s.length(); ++i)
EXPECT_EQ(i != the_invalid_index, IsValidCodePointIndex(s, i));
diff --git a/chromium/ui/gfx/vector2d.cc b/chromium/ui/gfx/vector2d.cc
deleted file mode 100644
index 9e685e45d1d..00000000000
--- a/chromium/ui/gfx/vector2d.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/vector2d.h"
-
-#include <cmath>
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-bool Vector2d::IsZero() const {
- return x_ == 0 && y_ == 0;
-}
-
-void Vector2d::Add(const Vector2d& other) {
- x_ += other.x_;
- y_ += other.y_;
-}
-
-void Vector2d::Subtract(const Vector2d& other) {
- x_ -= other.x_;
- y_ -= other.y_;
-}
-
-int64 Vector2d::LengthSquared() const {
- return static_cast<int64>(x_) * x_ + static_cast<int64>(y_) * y_;
-}
-
-float Vector2d::Length() const {
- return static_cast<float>(std::sqrt(static_cast<double>(LengthSquared())));
-}
-
-std::string Vector2d::ToString() const {
- return base::StringPrintf("[%d %d]", x_, y_);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/vector2d.h b/chromium/ui/gfx/vector2d.h
index 8dd76324d1a..c0eefd23943 100644
--- a/chromium/ui/gfx/vector2d.h
+++ b/chromium/ui/gfx/vector2d.h
@@ -1,91 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Defines a simple integer vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d.h"
-#ifndef UI_GFX_VECTOR2D_H_
-#define UI_GFX_VECTOR2D_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector2d {
- public:
- Vector2d() : x_(0), y_(0) {}
- Vector2d(int x, int y) : x_(x), y_(y) {}
-
- int x() const { return x_; }
- void set_x(int x) { x_ = x; }
-
- int y() const { return y_; }
- void set_y(int y) { y_ = y; }
-
- // True if both components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector2d& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector2d& other);
-
- void operator+=(const Vector2d& other) { Add(other); }
- void operator-=(const Vector2d& other) { Subtract(other); }
-
- void SetToMin(const Vector2d& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- }
-
- void SetToMax(const Vector2d& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- }
-
- // Gives the square of the diagonal length of the vector. Since this is
- // cheaper to compute than Length(), it is useful when you want to compare
- // relative lengths of different vectors without needing the actual lengths.
- int64 LengthSquared() const;
- // Gives the diagonal length of the vector.
- float Length() const;
-
- std::string ToString() const;
-
- operator Vector2dF() const { return Vector2dF(x_, y_); }
-
- private:
- int x_;
- int y_;
-};
-
-inline bool operator==(const Vector2d& lhs, const Vector2d& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline Vector2d operator-(const Vector2d& v) {
- return Vector2d(-v.x(), -v.y());
-}
-
-inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) {
- Vector2d result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) {
- Vector2d result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_H_
diff --git a/chromium/ui/gfx/vector2d_conversions.cc b/chromium/ui/gfx/vector2d_conversions.cc
deleted file mode 100644
index 457e9f708a2..00000000000
--- a/chromium/ui/gfx/vector2d_conversions.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/vector2d_conversions.h"
-
-#include "ui/gfx/safe_integer_conversions.h"
-
-namespace gfx {
-
-Vector2d ToFlooredVector2d(const Vector2dF& vector2d) {
- int x = ToFlooredInt(vector2d.x());
- int y = ToFlooredInt(vector2d.y());
- return Vector2d(x, y);
-}
-
-Vector2d ToCeiledVector2d(const Vector2dF& vector2d) {
- int x = ToCeiledInt(vector2d.x());
- int y = ToCeiledInt(vector2d.y());
- return Vector2d(x, y);
-}
-
-Vector2d ToRoundedVector2d(const Vector2dF& vector2d) {
- int x = ToRoundedInt(vector2d.x());
- int y = ToRoundedInt(vector2d.y());
- return Vector2d(x, y);
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/vector2d_conversions.h b/chromium/ui/gfx/vector2d_conversions.h
index 509a4567d10..5417e1c3f21 100644
--- a/chromium/ui/gfx/vector2d_conversions.h
+++ b/chromium/ui/gfx/vector2d_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_VECTOR2D_CONVERSIONS_H_
-#define UI_GFX_VECTOR2D_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-// Returns a Vector2d with each component from the input Vector2dF floored.
-GFX_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d);
-
-// Returns a Vector2d with each component from the input Vector2dF ceiled.
-GFX_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d);
-
-// Returns a Vector2d with each component from the input Vector2dF rounded.
-GFX_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d);
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/vector2d_f.cc b/chromium/ui/gfx/vector2d_f.cc
deleted file mode 100644
index 2ad267074b3..00000000000
--- a/chromium/ui/gfx/vector2d_f.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/vector2d_f.h"
-
-#include <cmath>
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-std::string Vector2dF::ToString() const {
- return base::StringPrintf("[%f %f]", x_, y_);
-}
-
-bool Vector2dF::IsZero() const {
- return x_ == 0 && y_ == 0;
-}
-
-void Vector2dF::Add(const Vector2dF& other) {
- x_ += other.x_;
- y_ += other.y_;
-}
-
-void Vector2dF::Subtract(const Vector2dF& other) {
- x_ -= other.x_;
- y_ -= other.y_;
-}
-
-double Vector2dF::LengthSquared() const {
- return static_cast<double>(x_) * x_ + static_cast<double>(y_) * y_;
-}
-
-float Vector2dF::Length() const {
- return static_cast<float>(std::sqrt(LengthSquared()));
-}
-
-void Vector2dF::Scale(float x_scale, float y_scale) {
- x_ *= x_scale;
- y_ *= y_scale;
-}
-
-double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs) {
- return static_cast<double>(lhs.x()) * rhs.y() -
- static_cast<double>(lhs.y()) * rhs.x();
-}
-
-double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs) {
- return static_cast<double>(lhs.x()) * rhs.x() +
- static_cast<double>(lhs.y()) * rhs.y();
-}
-
-Vector2dF ScaleVector2d(const Vector2dF& v, float x_scale, float y_scale) {
- Vector2dF scaled_v(v);
- scaled_v.Scale(x_scale, y_scale);
- return scaled_v;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/vector2d_f.h b/chromium/ui/gfx/vector2d_f.h
index 289b9b7a8d1..28a51d3da85 100644
--- a/chromium/ui/gfx/vector2d_f.h
+++ b/chromium/ui/gfx/vector2d_f.h
@@ -1,112 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Defines a simple float vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d_f.h"
-#ifndef UI_GFX_VECTOR2D_F_H_
-#define UI_GFX_VECTOR2D_F_H_
-
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector2dF {
- public:
- Vector2dF() : x_(0), y_(0) {}
- Vector2dF(float x, float y) : x_(x), y_(y) {}
-
- float x() const { return x_; }
- void set_x(float x) { x_ = x; }
-
- float y() const { return y_; }
- void set_y(float y) { y_ = y; }
-
- // True if both components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector2dF& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector2dF& other);
-
- void operator+=(const Vector2dF& other) { Add(other); }
- void operator-=(const Vector2dF& other) { Subtract(other); }
-
- void SetToMin(const Vector2dF& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- }
-
- void SetToMax(const Vector2dF& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- }
-
- // Gives the square of the diagonal length of the vector.
- double LengthSquared() const;
- // Gives the diagonal length of the vector.
- float Length() const;
-
- // Scale the x and y components of the vector by |scale|.
- void Scale(float scale) { Scale(scale, scale); }
- // Scale the x and y components of the vector by |x_scale| and |y_scale|
- // respectively.
- void Scale(float x_scale, float y_scale);
-
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
-};
-
-inline bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) {
- return !(lhs == rhs);
-}
-
-inline Vector2dF operator-(const Vector2dF& v) {
- return Vector2dF(-v.x(), -v.y());
-}
-
-inline Vector2dF operator+(const Vector2dF& lhs, const Vector2dF& rhs) {
- Vector2dF result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) {
- Vector2dF result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-// Return the cross product of two vectors.
-GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
-
-// Return the dot product of two vectors.
-GFX_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
-
-// Return a vector that is |v| scaled by the given scale factors along each
-// axis.
-GFX_EXPORT Vector2dF ScaleVector2d(const Vector2dF& v,
- float x_scale,
- float y_scale);
-
-// Return a vector that is |v| scaled by the given scale factor.
-inline Vector2dF ScaleVector2d(const Vector2dF& v, float scale) {
- return ScaleVector2d(v, scale, scale);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_F_H_
diff --git a/chromium/ui/gfx/vector2d_unittest.cc b/chromium/ui/gfx/vector2d_unittest.cc
deleted file mode 100644
index 5d9e21ea66d..00000000000
--- a/chromium/ui/gfx/vector2d_unittest.cc
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cmath>
-#include <limits>
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-TEST(Vector2dTest, ConversionToFloat) {
- Vector2d i(3, 4);
- Vector2dF f = i;
- EXPECT_EQ(i, f);
-}
-
-TEST(Vector2dTest, IsZero) {
- Vector2d int_zero(0, 0);
- Vector2d int_nonzero(2, -2);
- Vector2dF float_zero(0, 0);
- Vector2dF float_nonzero(0.1f, -0.1f);
-
- EXPECT_TRUE(int_zero.IsZero());
- EXPECT_FALSE(int_nonzero.IsZero());
- EXPECT_TRUE(float_zero.IsZero());
- EXPECT_FALSE(float_nonzero.IsZero());
-}
-
-TEST(Vector2dTest, Add) {
- Vector2d i1(3, 5);
- Vector2d i2(4, -1);
-
- const struct {
- Vector2d expected;
- Vector2d actual;
- } int_tests[] = {
- { Vector2d(3, 5), i1 + Vector2d() },
- { Vector2d(3 + 4, 5 - 1), i1 + i2 },
- { Vector2d(3 - 4, 5 + 1), i1 - i2 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i)
- EXPECT_EQ(int_tests[i].expected.ToString(),
- int_tests[i].actual.ToString());
-
- Vector2dF f1(3.1f, 5.1f);
- Vector2dF f2(4.3f, -1.3f);
-
- const struct {
- Vector2dF expected;
- Vector2dF actual;
- } float_tests[] = {
- { Vector2dF(3.1F, 5.1F), f1 + Vector2d() },
- { Vector2dF(3.1F, 5.1F), f1 + Vector2dF() },
- { Vector2dF(3.1f + 4.3f, 5.1f - 1.3f), f1 + f2 },
- { Vector2dF(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
-}
-
-TEST(Vector2dTest, Negative) {
- const struct {
- Vector2d expected;
- Vector2d actual;
- } int_tests[] = {
- { Vector2d(0, 0), -Vector2d(0, 0) },
- { Vector2d(-3, -3), -Vector2d(3, 3) },
- { Vector2d(3, 3), -Vector2d(-3, -3) },
- { Vector2d(-3, 3), -Vector2d(3, -3) },
- { Vector2d(3, -3), -Vector2d(-3, 3) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_tests); ++i)
- EXPECT_EQ(int_tests[i].expected.ToString(),
- int_tests[i].actual.ToString());
-
- const struct {
- Vector2dF expected;
- Vector2dF actual;
- } float_tests[] = {
- { Vector2dF(0, 0), -Vector2d(0, 0) },
- { Vector2dF(-0.3f, -0.3f), -Vector2dF(0.3f, 0.3f) },
- { Vector2dF(0.3f, 0.3f), -Vector2dF(-0.3f, -0.3f) },
- { Vector2dF(-0.3f, 0.3f), -Vector2dF(0.3f, -0.3f) },
- { Vector2dF(0.3f, -0.3f), -Vector2dF(-0.3f, 0.3f) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
-}
-
-TEST(Vector2dTest, Scale) {
- float double_values[][4] = {
- { 4.5f, 1.2f, 3.3f, 5.6f },
- { 4.5f, -1.2f, 3.3f, 5.6f },
- { 4.5f, 1.2f, 3.3f, -5.6f },
- { 4.5f, 1.2f, -3.3f, -5.6f },
- { -4.5f, 1.2f, 3.3f, 5.6f },
- { -4.5f, 1.2f, 0, 5.6f },
- { -4.5f, 1.2f, 3.3f, 0 },
- { 4.5f, 0, 3.3f, 5.6f },
- { 0, 1.2f, 3.3f, 5.6f }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(double_values); ++i) {
- Vector2dF v(double_values[i][0], double_values[i][1]);
- v.Scale(double_values[i][2], double_values[i][3]);
- EXPECT_EQ(v.x(), double_values[i][0] * double_values[i][2]);
- EXPECT_EQ(v.y(), double_values[i][1] * double_values[i][3]);
-
- Vector2dF v2 = ScaleVector2d(
- gfx::Vector2dF(double_values[i][0], double_values[i][1]),
- double_values[i][2], double_values[i][3]);
- EXPECT_EQ(double_values[i][0] * double_values[i][2], v2.x());
- EXPECT_EQ(double_values[i][1] * double_values[i][3], v2.y());
- }
-
- float single_values[][3] = {
- { 4.5f, 1.2f, 3.3f },
- { 4.5f, -1.2f, 3.3f },
- { 4.5f, 1.2f, 3.3f },
- { 4.5f, 1.2f, -3.3f },
- { -4.5f, 1.2f, 3.3f },
- { -4.5f, 1.2f, 0 },
- { -4.5f, 1.2f, 3.3f },
- { 4.5f, 0, 3.3f },
- { 0, 1.2f, 3.3f }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(single_values); ++i) {
- Vector2dF v(single_values[i][0], single_values[i][1]);
- v.Scale(single_values[i][2]);
- EXPECT_EQ(v.x(), single_values[i][0] * single_values[i][2]);
- EXPECT_EQ(v.y(), single_values[i][1] * single_values[i][2]);
-
- Vector2dF v2 = ScaleVector2d(
- gfx::Vector2dF(double_values[i][0], double_values[i][1]),
- double_values[i][2]);
- EXPECT_EQ(single_values[i][0] * single_values[i][2], v2.x());
- EXPECT_EQ(single_values[i][1] * single_values[i][2], v2.y());
- }
-}
-
-TEST(Vector2dTest, Length) {
- int int_values[][2] = {
- { 0, 0 },
- { 10, 20 },
- { 20, 10 },
- { -10, -20 },
- { -20, 10 },
- { 10, -20 },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(int_values); ++i) {
- int v0 = int_values[i][0];
- int v1 = int_values[i][1];
- double length_squared =
- static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
- double length = std::sqrt(length_squared);
- Vector2d vector(v0, v1);
- EXPECT_EQ(static_cast<float>(length_squared), vector.LengthSquared());
- EXPECT_EQ(static_cast<float>(length), vector.Length());
- }
-
- float float_values[][2] = {
- { 0, 0 },
- { 10.5f, 20.5f },
- { 20.5f, 10.5f },
- { -10.5f, -20.5f },
- { -20.5f, 10.5f },
- { 10.5f, -20.5f },
- // A large vector that fails if the Length function doesn't use
- // double precision internally.
- { 1236278317862780234892374893213178027.12122348904204230f,
- 335890352589839028212313231225425134332.38123f },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_values); ++i) {
- double v0 = float_values[i][0];
- double v1 = float_values[i][1];
- double length_squared =
- static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
- double length = std::sqrt(length_squared);
- Vector2dF vector(v0, v1);
- EXPECT_DOUBLE_EQ(length_squared, vector.LengthSquared());
- EXPECT_FLOAT_EQ(static_cast<float>(length), vector.Length());
- }
-}
-
-TEST(Vector2dTest, ClampVector2d) {
- Vector2d a;
-
- a = Vector2d(3, 5);
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
- a.SetToMax(Vector2d(2, 4));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
- a.SetToMax(Vector2d(3, 5));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
- a.SetToMax(Vector2d(4, 2));
- EXPECT_EQ(Vector2d(4, 5).ToString(), a.ToString());
- a.SetToMax(Vector2d(8, 10));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
-
- a.SetToMin(Vector2d(9, 11));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
- a.SetToMin(Vector2d(8, 10));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
- a.SetToMin(Vector2d(11, 9));
- EXPECT_EQ(Vector2d(8, 9).ToString(), a.ToString());
- a.SetToMin(Vector2d(7, 11));
- EXPECT_EQ(Vector2d(7, 9).ToString(), a.ToString());
- a.SetToMin(Vector2d(3, 5));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
-}
-
-TEST(Vector2dTest, ClampVector2dF) {
- Vector2dF a;
-
- a = Vector2dF(3.5f, 5.5f);
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(2.5f, 4.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(3.5f, 5.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(4.5f, 2.5f));
- EXPECT_EQ(Vector2dF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(8.5f, 10.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(Vector2dF(9.5f, 11.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(8.5f, 10.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(11.5f, 9.5f));
- EXPECT_EQ(Vector2dF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(7.5f, 11.5f));
- EXPECT_EQ(Vector2dF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(3.5f, 5.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/vector3d_f.cc b/chromium/ui/gfx/vector3d_f.cc
deleted file mode 100644
index 233e0542673..00000000000
--- a/chromium/ui/gfx/vector3d_f.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/vector3d_f.h"
-
-#include <cmath>
-
-#include "base/strings/stringprintf.h"
-
-namespace gfx {
-
-Vector3dF::Vector3dF()
- : x_(0),
- y_(0),
- z_(0) {
-}
-
-Vector3dF::Vector3dF(float x, float y, float z)
- : x_(x),
- y_(y),
- z_(z) {
-}
-
-Vector3dF::Vector3dF(const Vector2dF& other)
- : x_(other.x()),
- y_(other.y()),
- z_(0) {
-}
-
-std::string Vector3dF::ToString() const {
- return base::StringPrintf("[%f %f %f]", x_, y_, z_);
-}
-
-bool Vector3dF::IsZero() const {
- return x_ == 0 && y_ == 0 && z_ == 0;
-}
-
-void Vector3dF::Add(const Vector3dF& other) {
- x_ += other.x_;
- y_ += other.y_;
- z_ += other.z_;
-}
-
-void Vector3dF::Subtract(const Vector3dF& other) {
- x_ -= other.x_;
- y_ -= other.y_;
- z_ -= other.z_;
-}
-
-double Vector3dF::LengthSquared() const {
- return static_cast<double>(x_) * x_ + static_cast<double>(y_) * y_ +
- static_cast<double>(z_) * z_;
-}
-
-float Vector3dF::Length() const {
- return static_cast<float>(std::sqrt(LengthSquared()));
-}
-
-void Vector3dF::Scale(float x_scale, float y_scale, float z_scale) {
- x_ *= x_scale;
- y_ *= y_scale;
- z_ *= z_scale;
-}
-
-void Vector3dF::Cross(const Vector3dF& other) {
- float x = y_ * other.z() - z_ * other.y();
- float y = z_ * other.x() - x_ * other.z();
- float z = x_ * other.y() - y_ * other.x();
- x_ = x;
- y_ = y;
- z_ = z;
-}
-
-float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
- return lhs.x() * rhs.x() + lhs.y() * rhs.y() + lhs.z() * rhs.z();
-}
-
-Vector3dF ScaleVector3d(const Vector3dF& v,
- float x_scale,
- float y_scale,
- float z_scale) {
- Vector3dF scaled_v(v);
- scaled_v.Scale(x_scale, y_scale, z_scale);
- return scaled_v;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/vector3d_f.h b/chromium/ui/gfx/vector3d_f.h
index 0e91a362eca..ad0445fc258 100644
--- a/chromium/ui/gfx/vector3d_f.h
+++ b/chromium/ui/gfx/vector3d_f.h
@@ -1,124 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Defines a simple float vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector3d_f.h"
-#ifndef UI_GFX_VECTOR3D_F_H_
-#define UI_GFX_VECTOR3D_F_H_
-
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector3dF {
- public:
- Vector3dF();
- Vector3dF(float x, float y, float z);
-
- explicit Vector3dF(const Vector2dF& other);
-
- float x() const { return x_; }
- void set_x(float x) { x_ = x; }
-
- float y() const { return y_; }
- void set_y(float y) { y_ = y; }
-
- float z() const { return z_; }
- void set_z(float z) { z_ = z; }
-
- // True if all components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector3dF& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector3dF& other);
-
- void operator+=(const Vector3dF& other) { Add(other); }
- void operator-=(const Vector3dF& other) { Subtract(other); }
-
- void SetToMin(const Vector3dF& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- z_ = z_ <= other.z_ ? z_ : other.z_;
- }
-
- void SetToMax(const Vector3dF& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- z_ = z_ >= other.z_ ? z_ : other.z_;
- }
-
- // Gives the square of the diagonal length of the vector.
- double LengthSquared() const;
- // Gives the diagonal length of the vector.
- float Length() const;
-
- // Scale all components of the vector by |scale|.
- void Scale(float scale) { Scale(scale, scale, scale); }
- // Scale the each component of the vector by the given scale factors.
- void Scale(float x_scale, float y_scale, float z_scale);
-
- // Take the cross product of this vector with |other| and become the result.
- void Cross(const Vector3dF& other);
-
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
- float z_;
-};
-
-inline bool operator==(const Vector3dF& lhs, const Vector3dF& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
-}
-
-inline Vector3dF operator-(const Vector3dF& v) {
- return Vector3dF(-v.x(), -v.y(), -v.z());
-}
-
-inline Vector3dF operator+(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector3dF operator-(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-// Return the cross product of two vectors.
-inline Vector3dF CrossProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Cross(rhs);
- return result;
-}
-
-// Return the dot product of two vectors.
-GFX_EXPORT float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs);
-
-// Return a vector that is |v| scaled by the given scale factors along each
-// axis.
-GFX_EXPORT Vector3dF ScaleVector3d(const Vector3dF& v,
- float x_scale,
- float y_scale,
- float z_scale);
-
-// Return a vector that is |v| scaled by the given scale factor.
-inline Vector3dF ScaleVector3d(const Vector3dF& v, float scale) {
- return ScaleVector3d(v, scale, scale, scale);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR3D_F_H_
diff --git a/chromium/ui/gfx/vector3d_unittest.cc b/chromium/ui/gfx/vector3d_unittest.cc
deleted file mode 100644
index 5b3bd7e91bf..00000000000
--- a/chromium/ui/gfx/vector3d_unittest.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <cmath>
-#include <limits>
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-TEST(Vector3dTest, IsZero) {
- gfx::Vector3dF float_zero(0, 0, 0);
- gfx::Vector3dF float_nonzero(0.1f, -0.1f, 0.1f);
-
- EXPECT_TRUE(float_zero.IsZero());
- EXPECT_FALSE(float_nonzero.IsZero());
-}
-
-TEST(Vector3dTest, Add) {
- gfx::Vector3dF f1(3.1f, 5.1f, 2.7f);
- gfx::Vector3dF f2(4.3f, -1.3f, 8.1f);
-
- const struct {
- gfx::Vector3dF expected;
- gfx::Vector3dF actual;
- } float_tests[] = {
- { gfx::Vector3dF(3.1F, 5.1F, 2.7f), f1 + gfx::Vector3dF() },
- { gfx::Vector3dF(3.1f + 4.3f, 5.1f - 1.3f, 2.7f + 8.1f), f1 + f2 },
- { gfx::Vector3dF(3.1f - 4.3f, 5.1f + 1.3f, 2.7f - 8.1f), f1 - f2 }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
-}
-
-TEST(Vector3dTest, Negative) {
- const struct {
- gfx::Vector3dF expected;
- gfx::Vector3dF actual;
- } float_tests[] = {
- { gfx::Vector3dF(-0.0f, -0.0f, -0.0f), -gfx::Vector3dF(0, 0, 0) },
- { gfx::Vector3dF(-0.3f, -0.3f, -0.3f), -gfx::Vector3dF(0.3f, 0.3f, 0.3f) },
- { gfx::Vector3dF(0.3f, 0.3f, 0.3f), -gfx::Vector3dF(-0.3f, -0.3f, -0.3f) },
- { gfx::Vector3dF(-0.3f, 0.3f, -0.3f), -gfx::Vector3dF(0.3f, -0.3f, 0.3f) },
- { gfx::Vector3dF(0.3f, -0.3f, -0.3f), -gfx::Vector3dF(-0.3f, 0.3f, 0.3f) },
- { gfx::Vector3dF(-0.3f, -0.3f, 0.3f), -gfx::Vector3dF(0.3f, 0.3f, -0.3f) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
-}
-
-TEST(Vector3dTest, Scale) {
- float triple_values[][6] = {
- { 4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f },
- { 4.5f, -1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
- { 4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
- { 4.5f, -1.2f -1.8f, 3.3f, 5.6f, 4.2f },
-
- { 4.5f, 1.2f, 1.8f, 3.3f, -5.6f, -4.2f },
- { 4.5f, 1.2f, 1.8f, -3.3f, -5.6f, -4.2f },
- { 4.5f, 1.2f, -1.8f, 3.3f, -5.6f, -4.2f },
- { 4.5f, 1.2f, -1.8f, -3.3f, -5.6f, -4.2f },
-
- { -4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f },
- { -4.5f, 1.2f, 1.8f, 0, 5.6f, 4.2f },
- { -4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
- { -4.5f, 1.2f, -1.8f, 0, 5.6f, 4.2f },
-
- { -4.5f, 1.2f, 1.8f, 3.3f, 0, 4.2f },
- { 4.5f, 0, 1.8f, 3.3f, 5.6f, 4.2f },
- { -4.5f, 1.2f, -1.8f, 3.3f, 0, 4.2f },
- { 4.5f, 0, -1.8f, 3.3f, 5.6f, 4.2f },
- { -4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 0 },
- { -4.5f, 1.2f, -1.8f, 3.3f, 5.6f, 0 },
-
- { 0, 1.2f, 0, 3.3f, 5.6f, 4.2f },
- { 0, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(triple_values); ++i) {
- gfx::Vector3dF v(triple_values[i][0],
- triple_values[i][1],
- triple_values[i][2]);
- v.Scale(triple_values[i][3], triple_values[i][4], triple_values[i][5]);
- EXPECT_EQ(triple_values[i][0] * triple_values[i][3], v.x());
- EXPECT_EQ(triple_values[i][1] * triple_values[i][4], v.y());
- EXPECT_EQ(triple_values[i][2] * triple_values[i][5], v.z());
-
- Vector3dF v2 = ScaleVector3d(
- gfx::Vector3dF(triple_values[i][0],
- triple_values[i][1],
- triple_values[i][2]),
- triple_values[i][3], triple_values[i][4], triple_values[i][5]);
- EXPECT_EQ(triple_values[i][0] * triple_values[i][3], v2.x());
- EXPECT_EQ(triple_values[i][1] * triple_values[i][4], v2.y());
- EXPECT_EQ(triple_values[i][2] * triple_values[i][5], v2.z());
- }
-
- float single_values[][4] = {
- { 4.5f, 1.2f, 1.8f, 3.3f },
- { 4.5f, -1.2f, 1.8f, 3.3f },
- { 4.5f, 1.2f, -1.8f, 3.3f },
- { 4.5f, -1.2f, -1.8f, 3.3f },
- { -4.5f, 1.2f, 3.3f },
- { -4.5f, 1.2f, 0 },
- { -4.5f, 1.2f, 1.8f, 3.3f },
- { -4.5f, 1.2f, 1.8f, 0 },
- { 4.5f, 0, 1.8f, 3.3f },
- { 0, 1.2f, 1.8f, 3.3f },
- { 4.5f, 0, 1.8f, 3.3f },
- { 0, 1.2f, 1.8f, 3.3f },
- { 4.5f, 1.2f, 0, 3.3f },
- { 4.5f, 1.2f, 0, 3.3f }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(single_values); ++i) {
- gfx::Vector3dF v(single_values[i][0],
- single_values[i][1],
- single_values[i][2]);
- v.Scale(single_values[i][3]);
- EXPECT_EQ(single_values[i][0] * single_values[i][3], v.x());
- EXPECT_EQ(single_values[i][1] * single_values[i][3], v.y());
- EXPECT_EQ(single_values[i][2] * single_values[i][3], v.z());
-
- Vector3dF v2 = ScaleVector3d(
- gfx::Vector3dF(single_values[i][0],
- single_values[i][1],
- single_values[i][2]),
- single_values[i][3]);
- EXPECT_EQ(single_values[i][0] * single_values[i][3], v2.x());
- EXPECT_EQ(single_values[i][1] * single_values[i][3], v2.y());
- EXPECT_EQ(single_values[i][2] * single_values[i][3], v2.z());
- }
-}
-
-TEST(Vector3dTest, Length) {
- float float_values[][3] = {
- { 0, 0, 0 },
- { 10.5f, 20.5f, 8.5f },
- { 20.5f, 10.5f, 8.5f },
- { 8.5f, 20.5f, 10.5f },
- { 10.5f, 8.5f, 20.5f },
- { -10.5f, -20.5f, -8.5f },
- { -20.5f, 10.5f, -8.5f },
- { -8.5f, -20.5f, -10.5f },
- { -10.5f, -8.5f, -20.5f },
- { 10.5f, -20.5f, 8.5f },
- { -10.5f, 20.5f, 8.5f },
- { 10.5f, -20.5f, -8.5f },
- { -10.5f, 20.5f, -8.5f },
- // A large vector that fails if the Length function doesn't use
- // double precision internally.
- { 1236278317862780234892374893213178027.12122348904204230f,
- 335890352589839028212313231225425134332.38123f,
- 27861786423846742743236423478236784678.236713617231f }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(float_values); ++i) {
- double v0 = float_values[i][0];
- double v1 = float_values[i][1];
- double v2 = float_values[i][2];
- double length_squared =
- static_cast<double>(v0) * v0 +
- static_cast<double>(v1) * v1 +
- static_cast<double>(v2) * v2;
- double length = std::sqrt(length_squared);
- gfx::Vector3dF vector(v0, v1, v2);
- EXPECT_DOUBLE_EQ(length_squared, vector.LengthSquared());
- EXPECT_FLOAT_EQ(static_cast<float>(length), vector.Length());
- }
-}
-
-TEST(Vector3dTest, DotProduct) {
- const struct {
- float expected;
- gfx::Vector3dF input1;
- gfx::Vector3dF input2;
- } tests[] = {
- { 0, gfx::Vector3dF(1, 0, 0), gfx::Vector3dF(0, 1, 1) },
- { 0, gfx::Vector3dF(0, 1, 0), gfx::Vector3dF(1, 0, 1) },
- { 0, gfx::Vector3dF(0, 0, 1), gfx::Vector3dF(1, 1, 0) },
-
- { 3, gfx::Vector3dF(1, 1, 1), gfx::Vector3dF(1, 1, 1) },
-
- { 1.2f, gfx::Vector3dF(1.2f, -1.2f, 1.2f), gfx::Vector3dF(1, 1, 1) },
- { 1.2f, gfx::Vector3dF(1, 1, 1), gfx::Vector3dF(1.2f, -1.2f, 1.2f) },
-
- { 38.72f,
- gfx::Vector3dF(1.1f, 2.2f, 3.3f), gfx::Vector3dF(4.4f, 5.5f, 6.6f) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- float actual = gfx::DotProduct(tests[i].input1, tests[i].input2);
- EXPECT_EQ(tests[i].expected, actual);
- }
-}
-
-TEST(Vector3dTest, CrossProduct) {
- const struct {
- gfx::Vector3dF expected;
- gfx::Vector3dF input1;
- gfx::Vector3dF input2;
- } tests[] = {
- { Vector3dF(), Vector3dF(), Vector3dF(1, 1, 1) },
- { Vector3dF(), Vector3dF(1, 1, 1), Vector3dF() },
- { Vector3dF(), Vector3dF(1, 1, 1), Vector3dF(1, 1, 1) },
- { Vector3dF(),
- Vector3dF(1.6f, 10.6f, -10.6f),
- Vector3dF(1.6f, 10.6f, -10.6f) },
-
- { Vector3dF(1, -1, 0), Vector3dF(1, 1, 1), Vector3dF(0, 0, 1) },
- { Vector3dF(-1, 0, 1), Vector3dF(1, 1, 1), Vector3dF(0, 1, 0) },
- { Vector3dF(0, 1, -1), Vector3dF(1, 1, 1), Vector3dF(1, 0, 0) },
-
- { Vector3dF(-1, 1, 0), Vector3dF(0, 0, 1), Vector3dF(1, 1, 1) },
- { Vector3dF(1, 0, -1), Vector3dF(0, 1, 0), Vector3dF(1, 1, 1) },
- { Vector3dF(0, -1, 1), Vector3dF(1, 0, 0), Vector3dF(1, 1, 1) }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- Vector3dF actual = gfx::CrossProduct(tests[i].input1, tests[i].input2);
- EXPECT_EQ(tests[i].expected.ToString(), actual.ToString());
- }
-}
-
-TEST(Vector3dFTest, ClampVector3dF) {
- Vector3dF a;
-
- a = Vector3dF(3.5f, 5.5f, 7.5f);
- EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(2, 4.5f, 6.5f));
- EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(3.5f, 5.5f, 7.5f));
- EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(4.5f, 2, 6.5f));
- EXPECT_EQ(Vector3dF(4.5f, 5.5f, 7.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(3.5f, 6.5f, 6.5f));
- EXPECT_EQ(Vector3dF(4.5f, 6.5f, 7.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(3.5f, 5.5f, 8.5f));
- EXPECT_EQ(Vector3dF(4.5f, 6.5f, 8.5f).ToString(), a.ToString());
- a.SetToMax(Vector3dF(8.5f, 10.5f, 12.5f));
- EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
-
- a.SetToMin(Vector3dF(9.5f, 11.5f, 13.5f));
- EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
- a.SetToMin(Vector3dF(8.5f, 10.5f, 12.5f));
- EXPECT_EQ(Vector3dF(8.5f, 10.5f, 12.5f).ToString(), a.ToString());
- a.SetToMin(Vector3dF(7.5f, 11.5f, 13.5f));
- EXPECT_EQ(Vector3dF(7.5f, 10.5f, 12.5f).ToString(), a.ToString());
- a.SetToMin(Vector3dF(9.5f, 9.5f, 13.5f));
- EXPECT_EQ(Vector3dF(7.5f, 9.5f, 12.5f).ToString(), a.ToString());
- a.SetToMin(Vector3dF(9.5f, 11.5f, 11.5f));
- EXPECT_EQ(Vector3dF(7.5f, 9.5f, 11.5f).ToString(), a.ToString());
- a.SetToMin(Vector3dF(3.5f, 5.5f, 7.5f));
- EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/win/dpi.cc b/chromium/ui/gfx/win/dpi.cc
index 6bc25dee646..e562a086c9a 100644
--- a/chromium/ui/gfx/win/dpi.cc
+++ b/chromium/ui/gfx/win/dpi.cc
@@ -20,6 +20,8 @@ namespace {
int kDefaultDPIX = 96;
int kDefaultDPIY = 96;
+bool force_highdpi_for_testing = false;
+
BOOL IsProcessDPIAwareWrapper() {
typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
IsProcessDPIAwarePtr is_process_dpi_aware_func =
@@ -33,33 +35,81 @@ BOOL IsProcessDPIAwareWrapper() {
float g_device_scale_factor = 0.0f;
float GetUnforcedDeviceScaleFactor() {
+ // If the global device scale factor is initialized use it. This is to ensure
+ // we use the same scale factor across all callsites. We don't use the
+ // GetDeviceScaleFactor function here because it fires a DCHECK if the
+ // g_device_scale_factor global is 0.
+ if (g_device_scale_factor)
+ return g_device_scale_factor;
return static_cast<float>(gfx::GetDPI().width()) /
static_cast<float>(kDefaultDPIX);
}
-float GetModernUIScaleWrapper() {
- float result = 1.0f;
- typedef float(WINAPI *GetModernUIScalePtr)(VOID);
- HMODULE lib = LoadLibraryA("metro_driver.dll");
- if (lib) {
- GetModernUIScalePtr func =
- reinterpret_cast<GetModernUIScalePtr>(
- GetProcAddress(lib, "GetModernUIScale"));
- if (func)
- result = func();
- FreeLibrary(lib);
+// Duplicated from Win8.1 SDK ShellScalingApi.h
+typedef enum PROCESS_DPI_AWARENESS {
+ PROCESS_DPI_UNAWARE = 0,
+ PROCESS_SYSTEM_DPI_AWARE = 1,
+ PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+
+typedef enum MONITOR_DPI_TYPE {
+ MDT_EFFECTIVE_DPI = 0,
+ MDT_ANGULAR_DPI = 1,
+ MDT_RAW_DPI = 2,
+ MDT_DEFAULT = MDT_EFFECTIVE_DPI
+} MONITOR_DPI_TYPE;
+
+// Win8.1 supports monitor-specific DPI scaling.
+bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
+ typedef BOOL(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
+ SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
+ reinterpret_cast<SetProcessDpiAwarenessPtr>(
+ GetProcAddress(GetModuleHandleA("user32.dll"),
+ "SetProcessDpiAwarenessInternal"));
+ if (set_process_dpi_awareness_func) {
+ HRESULT hr = set_process_dpi_awareness_func(value);
+ if (SUCCEEDED(hr)) {
+ VLOG(1) << "SetProcessDpiAwareness succeeded.";
+ return true;
+ } else if (hr == E_ACCESSDENIED) {
+ LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. "
+ "Function called twice, or manifest was used.";
+ }
}
- return result;
+ return false;
+}
+
+// This function works for Windows Vista through Win8. Win8.1 must use
+// SetProcessDpiAwareness[Wrapper]
+BOOL SetProcessDPIAwareWrapper() {
+ typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
+ SetProcessDPIAwarePtr set_process_dpi_aware_func =
+ reinterpret_cast<SetProcessDPIAwarePtr>(
+ GetProcAddress(GetModuleHandleA("user32.dll"),
+ "SetProcessDPIAware"));
+ return set_process_dpi_aware_func &&
+ set_process_dpi_aware_func();
+}
+
+DWORD ReadRegistryValue(HKEY root,
+ const wchar_t* base_key,
+ const wchar_t* value_name,
+ DWORD default_value) {
+ base::win::RegKey reg_key(HKEY_CURRENT_USER,
+ base_key,
+ KEY_QUERY_VALUE);
+ DWORD value;
+ if (reg_key.Valid() &&
+ reg_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) {
+ return value;
+ }
+ return default_value;
}
} // namespace
namespace gfx {
-float GetModernUIScale() {
- return GetModernUIScaleWrapper();
-}
-
void InitDeviceScaleFactor(float scale) {
DCHECK_NE(0.0f, scale);
g_device_scale_factor = scale;
@@ -91,14 +141,18 @@ float GetDPIScale() {
return 1.0;
}
+void ForceHighDPISupportForTesting(float scale) {
+ g_device_scale_factor = scale;
+}
+
bool IsHighDPIEnabled() {
+ // Flag stored in HKEY_CURRENT_USER\SOFTWARE\\Google\\Chrome\\Profile,
+ // under the DWORD value high-dpi-support.
// Default is disabled.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kHighDPISupport)) {
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kHighDPISupport).compare("1") == 0;
- }
- return false;
+ static DWORD value = ReadRegistryValue(
+ HKEY_CURRENT_USER, gfx::win::kRegistryProfilePath,
+ gfx::win::kHighDPISupportW, TRUE);
+ return value != 0;
}
bool IsInHighDPIMode() {
@@ -107,31 +161,25 @@ bool IsInHighDPIMode() {
void EnableHighDPISupport() {
if (IsHighDPIEnabled() &&
- (base::win::GetVersion() < base::win::VERSION_WIN8_1)) {
- typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
- SetProcessDPIAwarePtr set_process_dpi_aware_func =
- reinterpret_cast<SetProcessDPIAwarePtr>(
- GetProcAddress(GetModuleHandleA("user32.dll"),
- "SetProcessDPIAware"));
- if (set_process_dpi_aware_func)
- set_process_dpi_aware_func();
+ !SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) {
+ SetProcessDPIAwareWrapper();
}
}
namespace win {
+GFX_EXPORT const wchar_t kRegistryProfilePath[] =
+ L"Software\\Google\\Chrome\\Profile";
+GFX_EXPORT const wchar_t kHighDPISupportW[] = L"high-dpi-support";
+
float GetDeviceScaleFactor() {
DCHECK_NE(0.0f, g_device_scale_factor);
return g_device_scale_factor;
}
Point ScreenToDIPPoint(const Point& pixel_point) {
- static float scaling_factor =
- GetDeviceScaleFactor() > GetUnforcedDeviceScaleFactor() ?
- 1.0f / GetDeviceScaleFactor() :
- 1.0f;
return ToFlooredPoint(ScalePoint(pixel_point,
- scaling_factor));
+ 1.0f / GetDeviceScaleFactor()));
}
Point DIPToScreenPoint(const Point& dip_point) {
@@ -145,9 +193,17 @@ Rect ScreenToDIPRect(const Rect& pixel_bounds) {
}
Rect DIPToScreenRect(const Rect& dip_bounds) {
- // TODO(kevers): Switch to non-deprecated method for float to int conversions.
- return ToFlooredRectDeprecated(
- ScaleRect(dip_bounds, GetDeviceScaleFactor()));
+ // We scale the origin by the scale factor and round up via ceil. This
+ // ensures that we get the original logical origin back when we scale down.
+ // We round the size down after scaling. It may be better to round this up
+ // on the same lines as the origin.
+ // TODO(ananta)
+ // Investigate if rounding size up on the same lines as origin is workable.
+ return gfx::Rect(
+ gfx::ToCeiledPoint(gfx::ScalePoint(
+ dip_bounds.origin(), GetDeviceScaleFactor())),
+ gfx::ToFlooredSize(gfx::ScaleSize(
+ dip_bounds.size(), GetDeviceScaleFactor())));
}
Size ScreenToDIPSize(const Size& size_in_pixels) {
@@ -164,31 +220,8 @@ int GetSystemMetricsInDIP(int metric) {
GetDeviceScaleFactor() + 0.5);
}
-double GetUndocumentedDPIScale() {
- // TODO(girard): Remove this code when chrome is DPIAware.
- static double scale = -1.0;
- if (scale == -1.0) {
- scale = 1.0;
- if (!IsProcessDPIAwareWrapper()) {
- base::win::RegKey key(HKEY_CURRENT_USER,
- L"Control Panel\\Desktop\\WindowMetrics",
- KEY_QUERY_VALUE);
- if (key.Valid()) {
- DWORD value = 0;
- if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) {
- scale = static_cast<double>(value) / kDefaultDPIX;
- }
- }
- }
- }
- return scale;
-}
-
-double GetUndocumentedDPITouchScale() {
- static double scale =
- (base::win::GetVersion() < base::win::VERSION_WIN8_1) ?
- GetUndocumentedDPIScale() : 1.0;
- return scale;
+bool IsDeviceScaleFactorSet() {
+ return g_device_scale_factor != 0.0f;
}
} // namespace win
diff --git a/chromium/ui/gfx/win/dpi.h b/chromium/ui/gfx/win/dpi.h
index 772944f50f9..9dcf3802456 100644
--- a/chromium/ui/gfx/win/dpi.h
+++ b/chromium/ui/gfx/win/dpi.h
@@ -22,14 +22,9 @@ GFX_EXPORT void InitDeviceScaleFactor(float scale);
GFX_EXPORT Size GetDPI();
// Gets the scale factor of the display. For example, if the display DPI is
-// 96 then the scale factor is 1.0. Note that this is the "desktop" scale, which
-// may be differnt than GetModernUIScale().
+// 96 then the scale factor is 1.0.
GFX_EXPORT float GetDPIScale();
-// Gets the scale factor of the modern (metro) UI display. Returns 1.0 for
-// unscaled or "not running on win8+"
-GFX_EXPORT float GetModernUIScale();
-
// Tests to see if the command line flag "--high-dpi-support" is set.
GFX_EXPORT bool IsHighDPIEnabled();
@@ -37,6 +32,8 @@ GFX_EXPORT bool IsInHighDPIMode();
GFX_EXPORT void EnableHighDPISupport();
+GFX_EXPORT void ForceHighDPISupportForTesting(float scale);
+
// TODO(kevers|girard): Move above methods into win namespace.
namespace win {
@@ -59,18 +56,12 @@ GFX_EXPORT Size DIPToScreenSize(const Size& dip_size);
// GetSystemMetrics for the given |metric|, then converts the result to DIP.
GFX_EXPORT int GetSystemMetricsInDIP(int metric);
-// Sometimes the OS secretly scales apps that are not DPIAware. This is not
-// visible through standard OS calls like GetWindowPos(), or through
-// GetDPIScale().
-// Returns the scale factor of the display, where 96 DPI is 1.0.
-// (Avoid this function... use GetDPIScale() instead.)
-// TODO(girard): Remove this once DPIAware is enabled - http://crbug.com/149881
-GFX_EXPORT double GetUndocumentedDPIScale();
-
-// Win7 and Win8 send touch events scaled according to the current DPI
-// scaling. Win8.1 corrects this, and sends touch events in DPI units.
-// This function returns the appropriate scaling factor for touch events.
-GFX_EXPORT double GetUndocumentedDPITouchScale();
+// Returns true if the global device scale factor has been explicitly set for
+// the process.
+GFX_EXPORT bool IsDeviceScaleFactorSet();
+
+GFX_EXPORT extern const wchar_t kRegistryProfilePath[];
+GFX_EXPORT extern const wchar_t kHighDPISupportW[];
} // namespace win
} // namespace gfx
diff --git a/chromium/ui/gfx/win/hwnd_util.cc b/chromium/ui/gfx/win/hwnd_util.cc
index fec39d4fe59..050aa9b733f 100644
--- a/chromium/ui/gfx/win/hwnd_util.cc
+++ b/chromium/ui/gfx/win/hwnd_util.cc
@@ -24,7 +24,7 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
if (hmon) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
- base::win::GetMonitorInfoWrapper(hmon, &mi);
+ GetMonitorInfo(hmon, &mi);
Rect window_rect(bounds);
Rect monitor_rect(mi.rcWork);
Rect new_window_rect = window_rect;
@@ -54,23 +54,23 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
MSVC_DISABLE_OPTIMIZE();
void CrashOutOfMemory() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
void CrashAccessDenied() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
// Crash isn't one of the ones we commonly see.
void CrashOther() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
MSVC_ENABLE_OPTIMIZE();
} // namespace
-string16 GetClassName(HWND window) {
+base::string16 GetClassName(HWND window) {
// GetClassNameW will return a truncated result (properly null terminated) if
// the given buffer is not large enough. So, it is not possible to determine
// that we got the entire class name if the result is exactly equal to the
@@ -150,7 +150,7 @@ void CenterAndSizeWindow(HWND parent,
if (monitor) {
MONITORINFO mi = {0};
mi.cbSize = sizeof(mi);
- base::win::GetMonitorInfoWrapper(monitor, &mi);
+ GetMonitorInfo(monitor, &mi);
center_bounds = mi.rcWork;
} else {
NOTREACHED() << "Unable to get default monitor";
@@ -200,16 +200,17 @@ void CheckWindowCreated(HWND hwnd) {
CrashOther();
break;
}
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
}
void ShowSystemMenu(HWND window) {
RECT rect;
GetWindowRect(window, &rect);
- Point point = Point(rect.left, rect.top);
+ Point point = Point(base::i18n::IsRTL() ? rect.right : rect.left, rect.top);
static const int kSystemMenuOffset = 10;
- point.Offset(kSystemMenuOffset, kSystemMenuOffset);
+ point.Offset(base::i18n::IsRTL() ? -kSystemMenuOffset : kSystemMenuOffset,
+ kSystemMenuOffset);
ShowSystemMenuAtPoint(window, point);
}
diff --git a/chromium/ui/gfx/win/hwnd_util.h b/chromium/ui/gfx/win/hwnd_util.h
index 472daccd82e..2afd660f5d8 100644
--- a/chromium/ui/gfx/win/hwnd_util.h
+++ b/chromium/ui/gfx/win/hwnd_util.h
@@ -15,8 +15,8 @@ class Point;
class Size;
// A version of the GetClassNameW API that returns the class name in an
-// string16. An empty result indicates a failure to get the class name.
-GFX_EXPORT string16 GetClassName(HWND hwnd);
+// base::string16. An empty result indicates a failure to get the class name.
+GFX_EXPORT base::string16 GetClassName(HWND hwnd);
// Useful for subclassing a HWND. Returns the previous window procedure.
GFX_EXPORT WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc);
diff --git a/chromium/ui/gfx/win/msg_util.h b/chromium/ui/gfx/win/msg_util.h
new file mode 100644
index 00000000000..a5d241b1234
--- /dev/null
+++ b/chromium/ui/gfx/win/msg_util.h
@@ -0,0 +1,2283 @@
+// 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_GFX_WIN_MSG_UTIL_H_
+#define UI_GFX_WIN_MSG_UTIL_H_
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+// Based on WTL version 8.0 atlcrack.h
+
+// This differs from the original atlcrack.h by removing usage of CPoint,
+// CSize, etc.
+
+///////////////////////////////////////////////////////////////////////////////
+// Message map macro for cracked handlers
+
+// Note about message maps with cracked handlers:
+// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX.
+// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl
+// derived classes,
+// but must use BEGIN_MSG_MAP_EX for classes that don't derive from
+// CWindowImpl/CDialogImpl.
+
+#define CR_BEGIN_MSG_MAP_EX(theClass) \
+ public: \
+ BOOL m_bMsgHandled; \
+ /* "handled" management for cracked handlers */ \
+ BOOL IsMsgHandled() const { return m_bMsgHandled; } \
+ void SetMsgHandled(BOOL bHandled) { m_bMsgHandled = bHandled; } \
+ BOOL ProcessWindowMessage(HWND hWnd, \
+ UINT uMsg, \
+ WPARAM wParam, \
+ LPARAM lParam, \
+ LRESULT& lResult, \
+ DWORD dwMsgMapID = 0) { \
+ BOOL bOldMsgHandled = m_bMsgHandled; \
+ BOOL bRet = _ProcessWindowMessage( \
+ hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
+ m_bMsgHandled = bOldMsgHandled; \
+ return bRet; \
+ } \
+ BOOL _ProcessWindowMessage(HWND hWnd, \
+ UINT uMsg, \
+ WPARAM wParam, \
+ LPARAM lParam, \
+ LRESULT& lResult, \
+ DWORD dwMsgMapID) { \
+ BOOL bHandled = TRUE; \
+ hWnd; \
+ uMsg; \
+ wParam; \
+ lParam; \
+ lResult; \
+ bHandled; \
+ switch (dwMsgMapID) { \
+ case 0:
+
+// Replacement for atlwin.h's END_MSG_MAP for removing ATL usage.
+#define CR_END_MSG_MAP() \
+ break; \
+ default: \
+ NOTREACHED() << "Invalid message map ID: " << dwMsgMapID; \
+ break; \
+ } \
+ return FALSE; \
+ }
+
+#define CR_GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam))
+#define CR_GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam))
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard Windows message macros
+
+// int OnCreate(LPCREATESTRUCT lpCreateStruct)
+#define CR_MSG_WM_CREATE(func) \
+ if (uMsg == WM_CREATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
+#define CR_MSG_WM_INITDIALOG(func) \
+ if (uMsg == WM_INITDIALOG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct)
+#define CR_MSG_WM_COPYDATA(func) \
+ if (uMsg == WM_COPYDATA) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroy()
+#define CR_MSG_WM_DESTROY(func) \
+ if (uMsg == WM_DESTROY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMove(CPoint ptPos)
+#define CR_MSG_WM_MOVE(func) \
+ if (uMsg == WM_MOVE) { \
+ SetMsgHandled(TRUE); \
+ func(gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSize(UINT nType, gfx::Size size)
+#define CR_MSG_WM_SIZE(func) \
+ if (uMsg == WM_SIZE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Size(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther)
+#define CR_MSG_WM_ACTIVATE(func) \
+ if (uMsg == WM_ACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFocus(CWindow wndOld)
+#define CR_MSG_WM_SETFOCUS(func) \
+ if (uMsg == WM_SETFOCUS) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKillFocus(CWindow wndFocus)
+#define CR_MSG_WM_KILLFOCUS(func) \
+ if (uMsg == WM_KILLFOCUS) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnable(BOOL bEnable)
+#define CR_MSG_WM_ENABLE(func) \
+ if (uMsg == WM_ENABLE) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaint(CDCHandle dc)
+#define CR_MSG_WM_PAINT(func) \
+ if (uMsg == WM_PAINT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnClose()
+#define CR_MSG_WM_CLOSE(func) \
+ if (uMsg == WM_CLOSE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff)
+#define CR_MSG_WM_QUERYENDSESSION(func) \
+ if (uMsg == WM_QUERYENDSESSION) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryOpen()
+#define CR_MSG_WM_QUERYOPEN(func) \
+ if (uMsg == WM_QUERYOPEN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnEraseBkgnd(CDCHandle dc)
+#define CR_MSG_WM_ERASEBKGND(func) \
+ if (uMsg == WM_ERASEBKGND) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysColorChange()
+#define CR_MSG_WM_SYSCOLORCHANGE(func) \
+ if (uMsg == WM_SYSCOLORCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEndSession(BOOL bEnding, UINT uLogOff)
+#define CR_MSG_WM_ENDSESSION(func) \
+ if (uMsg == WM_ENDSESSION) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnShowWindow(BOOL bShow, UINT nStatus)
+#define CR_MSG_WM_SHOWWINDOW(func) \
+ if (uMsg == WM_SHOWWINDOW) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (int)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit)
+#define CR_MSG_WM_CTLCOLOREDIT(func) \
+ if (uMsg == WM_CTLCOLOREDIT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define CR_MSG_WM_CTLCOLORLISTBOX(func) \
+ if (uMsg == WM_CTLCOLORLISTBOX) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button)
+#define CR_MSG_WM_CTLCOLORBTN(func) \
+ if (uMsg == WM_CTLCOLORBTN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define CR_MSG_WM_CTLCOLORDLG(func) \
+ if (uMsg == WM_CTLCOLORDLG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define CR_MSG_WM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == WM_CTLCOLORSCROLLBAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define CR_MSG_WM_CTLCOLORSTATIC(func) \
+ if (uMsg == WM_CTLCOLORSTATIC) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
+#define CR_MSG_WM_SETTINGCHANGE(func) \
+ if (uMsg == WM_SETTINGCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPCTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDevModeChange(LPCTSTR lpDeviceName)
+#define CR_MSG_WM_DEVMODECHANGE(func) \
+ if (uMsg == WM_DEVMODECHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((LPCTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivateApp(BOOL bActive, DWORD dwThreadID)
+#define CR_MSG_WM_ACTIVATEAPP(func) \
+ if (uMsg == WM_ACTIVATEAPP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnFontChange()
+#define CR_MSG_WM_FONTCHANGE(func) \
+ if (uMsg == WM_FONTCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimeChange()
+#define CR_MSG_WM_TIMECHANGE(func) \
+ if (uMsg == WM_TIMECHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCancelMode()
+#define CR_MSG_WM_CANCELMODE(func) \
+ if (uMsg == WM_CANCELMODE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message)
+#define CR_MSG_WM_SETCURSOR(func) \
+ if (uMsg == WM_SETCURSOR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message)
+#define CR_MSG_WM_MOUSEACTIVATE(func) \
+ if (uMsg == WM_MOUSEACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChildActivate()
+#define CR_MSG_WM_CHILDACTIVATE(func) \
+ if (uMsg == WM_CHILDACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI)
+#define CR_MSG_WM_GETMINMAXINFO(func) \
+ if (uMsg == WM_GETMINMAXINFO) { \
+ SetMsgHandled(TRUE); \
+ func((LPMINMAXINFO)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnIconEraseBkgnd(CDCHandle dc)
+#define CR_MSG_WM_ICONERASEBKGND(func) \
+ if (uMsg == WM_ICONERASEBKGND) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSpoolerStatus(UINT nStatus, UINT nJobs)
+#define CR_MSG_WM_SPOOLERSTATUS(func) \
+ if (uMsg == WM_SPOOLERSTATUS) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (UINT)LOWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define CR_MSG_WM_DRAWITEM(func) \
+ if (uMsg == WM_DRAWITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+#define CR_MSG_WM_MEASUREITEM(func) \
+ if (uMsg == WM_MEASUREITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define CR_MSG_WM_DELETEITEM(func) \
+ if (uMsg == WM_DELETEITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define CR_MSG_WM_CHARTOITEM(func) \
+ if (uMsg == WM_CHARTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define CR_MSG_WM_VKEYTOITEM(func) \
+ if (uMsg == WM_VKEYTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HCURSOR OnQueryDragIcon()
+#define CR_MSG_WM_QUERYDRAGICON(func) \
+ if (uMsg == WM_QUERYDRAGICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+#define CR_MSG_WM_COMPAREITEM(func) \
+ if (uMsg == WM_COMPAREITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCompacting(UINT nCpuTime)
+#define CR_MSG_WM_COMPACTING(func) \
+ if (uMsg == WM_COMPACTING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct)
+#define CR_MSG_WM_NCCREATE(func) \
+ if (uMsg == WM_NCCREATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcDestroy()
+#define CR_MSG_WM_NCDESTROY(func) \
+ if (uMsg == WM_NCDESTROY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam)
+#define CR_MSG_WM_NCCALCSIZE(func) \
+ if (uMsg == WM_NCCALCSIZE) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((BOOL)wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnNcHitTest(gfx::Point point)
+#define CR_MSG_WM_NCHITTEST(func) \
+ if (uMsg == WM_NCHITTEST) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcPaint(CRgn rgn)
+#define CR_MSG_WM_NCPAINT(func) \
+ if (uMsg == WM_NCPAINT) { \
+ SetMsgHandled(TRUE); \
+ func((HRGN)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcActivate(BOOL bActive)
+#define CR_MSG_WM_NCACTIVATE(func) \
+ if (uMsg == WM_NCACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((BOOL)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnGetDlgCode(LPMSG lpMsg)
+#define CR_MSG_WM_GETDLGCODE(func) \
+ if (uMsg == WM_GETDLGCODE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMouseMove(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCMOUSEMOVE(func) \
+ if (uMsg == WM_NCMOUSEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDown(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONDOWN(func) \
+ if (uMsg == WM_NCLBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonUp(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONUP(func) \
+ if (uMsg == WM_NCLBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDblClk(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCLBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDown(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCRBUTTONDOWN(func) \
+ if (uMsg == WM_NCRBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonUp(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCRBUTTONUP(func) \
+ if (uMsg == WM_NCRBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDblClk(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCRBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCRBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDown(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONDOWN(func) \
+ if (uMsg == WM_NCMBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonUp(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONUP(func) \
+ if (uMsg == WM_NCMBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDblClk(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCMBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_KEYDOWN(func) \
+ if (uMsg == WM_KEYDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_KEYUP(func) \
+ if (uMsg == WM_KEYUP) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_CHAR(func) \
+ if (uMsg == WM_CHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_DEADCHAR(func) \
+ if (uMsg == WM_DEADCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSKEYDOWN(func) \
+ if (uMsg == WM_SYSKEYDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSKEYUP(func) \
+ if (uMsg == WM_SYSKEYUP) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSCHAR(func) \
+ if (uMsg == WM_SYSCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSDEADCHAR(func) \
+ if (uMsg == WM_SYSDEADCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysCommand(UINT nID, LPARAM lParam)
+#define CR_MSG_WM_SYSCOMMAND(func) \
+ if (uMsg == WM_SYSCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTCard(UINT idAction, DWORD dwActionData)
+#define CR_MSG_WM_TCARD(func) \
+ if (uMsg == WM_TCARD) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimer(UINT_PTR nIDEvent)
+#define CR_MSG_WM_TIMER(func) \
+ if (uMsg == WM_TIMER) { \
+ SetMsgHandled(TRUE); \
+ func((UINT_PTR)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define CR_MSG_WM_HSCROLL(func) \
+ if (uMsg == WM_HSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define CR_MSG_WM_VSCROLL(func) \
+ if (uMsg == WM_VSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenu(CMenu menu)
+#define CR_MSG_WM_INITMENU(func) \
+ if (uMsg == WM_INITMENU) { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenuPopup(CMenu menuPopup, UINT nIndex, BOOL bSysMenu)
+#define CR_MSG_WM_INITMENUPOPUP(func) \
+ if (uMsg == WM_INITMENUPOPUP) { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenu menu)
+#define CR_MSG_WM_MENUSELECT(func) \
+ if (uMsg == WM_MENUSELECT) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu menu)
+#define CR_MSG_WM_MENUCHAR(func) \
+ if (uMsg == WM_MENUCHAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = \
+ func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh)
+#define CR_MSG_WM_NOTIFY(func) \
+ if (uMsg == WM_NOTIFY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterIdle(UINT nWhy, CWindow wndWho)
+#define CR_MSG_WM_ENTERIDLE(func) \
+ if (uMsg == WM_ENTERIDLE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseMove(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MOUSEMOVE(func) \
+ if (uMsg == WM_MOUSEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+#define CR_MSG_WM_MOUSEWHEEL(func) \
+ if (uMsg == WM_MOUSEWHEEL) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), \
+ (short)HIWORD(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONDOWN(func) \
+ if (uMsg == WM_LBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONUP(func) \
+ if (uMsg == WM_LBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONDBLCLK(func) \
+ if (uMsg == WM_LBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONDOWN(func) \
+ if (uMsg == WM_RBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONUP(func) \
+ if (uMsg == WM_RBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONDBLCLK(func) \
+ if (uMsg == WM_RBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONDOWN(func) \
+ if (uMsg == WM_MBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONUP(func) \
+ if (uMsg == WM_MBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONDBLCLK(func) \
+ if (uMsg == WM_MBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define CR_MSG_WM_PARENTNOTIFY(func) \
+ if (uMsg == WM_PARENTNOTIFY) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate)
+#define CR_MSG_WM_MDIACTIVATE(func) \
+ if (uMsg == WM_MDIACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderFormat(UINT nFormat)
+#define CR_MSG_WM_RENDERFORMAT(func) \
+ if (uMsg == WM_RENDERFORMAT) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderAllFormats()
+#define CR_MSG_WM_RENDERALLFORMATS(func) \
+ if (uMsg == WM_RENDERALLFORMATS) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroyClipboard()
+#define CR_MSG_WM_DESTROYCLIPBOARD(func) \
+ if (uMsg == WM_DESTROYCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawClipboard()
+#define CR_MSG_WM_DRAWCLIPBOARD(func) \
+ if (uMsg == WM_DRAWCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct)
+#define CR_MSG_WM_PAINTCLIPBOARD(func) \
+ if (uMsg == WM_PAINTCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define CR_MSG_WM_VSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_VSCROLLCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnContextMenu(CWindow wnd, CPoint point)
+#define CR_MSG_WM_CONTEXTMENU(func) \
+ if (uMsg == WM_CONTEXTMENU) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect)
+#define CR_MSG_WM_SIZECLIPBOARD(func) \
+ if (uMsg == WM_SIZECLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString)
+#define CR_MSG_WM_ASKCBFORMATNAME(func) \
+ if (uMsg == WM_ASKCBFORMATNAME) { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (LPTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter)
+#define CR_MSG_WM_CHANGECBCHAIN(func) \
+ if (uMsg == WM_CHANGECBCHAIN) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define CR_MSG_WM_HSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_HSCROLLCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryNewPalette()
+#define CR_MSG_WM_QUERYNEWPALETTE(func) \
+ if (uMsg == WM_QUERYNEWPALETTE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteChanged(CWindow wndFocus)
+#define CR_MSG_WM_PALETTECHANGED(func) \
+ if (uMsg == WM_PALETTECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteIsChanging(CWindow wndPalChg)
+#define CR_MSG_WM_PALETTEISCHANGING(func) \
+ if (uMsg == WM_PALETTEISCHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDropFiles(HDROP hDropInfo)
+#define CR_MSG_WM_DROPFILES(func) \
+ if (uMsg == WM_DROPFILES) { \
+ SetMsgHandled(TRUE); \
+ func((HDROP)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanging(LPWINDOWPOS lpWndPos)
+#define CR_MSG_WM_WINDOWPOSCHANGING(func) \
+ if (uMsg == WM_WINDOWPOSCHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanged(LPWINDOWPOS lpWndPos)
+#define CR_MSG_WM_WINDOWPOSCHANGED(func) \
+ if (uMsg == WM_WINDOWPOSCHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitMenuLoop(BOOL fIsTrackPopupMenu)
+#define CR_MSG_WM_EXITMENULOOP(func) \
+ if (uMsg == WM_EXITMENULOOP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu)
+#define CR_MSG_WM_ENTERMENULOOP(func) \
+ if (uMsg == WM_ENTERMENULOOP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define CR_MSG_WM_STYLECHANGED(func) \
+ if (uMsg == WM_STYLECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define CR_MSG_WM_STYLECHANGING(func) \
+ if (uMsg == WM_STYLECHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizing(UINT fwSide, LPRECT pRect)
+#define CR_MSG_WM_SIZING(func) \
+ if (uMsg == WM_SIZING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMoving(UINT fwSide, LPRECT pRect)
+#define CR_MSG_WM_MOVING(func) \
+ if (uMsg == WM_MOVING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCaptureChanged(CWindow wnd)
+#define CR_MSG_WM_CAPTURECHANGED(func) \
+ if (uMsg == WM_CAPTURECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnDeviceChange(UINT nEventType, DWORD dwData)
+#define CR_MSG_WM_DEVICECHANGE(func) \
+ if (uMsg == WM_DEVICECHANGE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (DWORD)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_MSG_WM_COMMAND(func) \
+ if (uMsg == WM_COMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDisplayChange(UINT uBitsPerPixel, gfx::Size sizeScreen)
+#define CR_MSG_WM_DISPLAYCHANGE(func) \
+ if (uMsg == WM_DISPLAYCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Size(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterSizeMove()
+#define CR_MSG_WM_ENTERSIZEMOVE(func) \
+ if (uMsg == WM_ENTERSIZEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitSizeMove()
+#define CR_MSG_WM_EXITSIZEMOVE(func) \
+ if (uMsg == WM_EXITSIZEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HFONT OnGetFont()
+#define CR_MSG_WM_GETFONT(func) \
+ if (uMsg == WM_GETFONT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnGetHotKey()
+#define CR_MSG_WM_GETHOTKEY(func) \
+ if (uMsg == WM_GETHOTKEY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnGetIcon()
+#define CR_MSG_WM_GETICON(func) \
+ if (uMsg == WM_GETICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetText(int cchTextMax, LPTSTR lpszText)
+#define CR_MSG_WM_GETTEXT(func) \
+ if (uMsg == WM_GETTEXT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetTextLength()
+#define CR_MSG_WM_GETTEXTLENGTH(func) \
+ if (uMsg == WM_GETTEXTLENGTH) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHelp(LPHELPINFO lpHelpInfo)
+#define CR_MSG_WM_HELP(func) \
+ if (uMsg == WM_HELP) { \
+ SetMsgHandled(TRUE); \
+ func((LPHELPINFO)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey)
+#define CR_MSG_WM_HOTKEY(func) \
+ if (uMsg == WM_HOTKEY) { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout)
+#define CR_MSG_WM_INPUTLANGCHANGE(func) \
+ if (uMsg == WM_INPUTLANGCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (HKL)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout)
+#define CR_MSG_WM_INPUTLANGCHANGEREQUEST(func) \
+ if (uMsg == WM_INPUTLANGCHANGEREQUEST) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (HKL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus)
+#define CR_MSG_WM_NEXTDLGCTL(func) \
+ if (uMsg == WM_NEXTDLGCTL) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)LOWORD(lParam), wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu)
+#define CR_MSG_WM_NEXTMENU(func) \
+ if (uMsg == WM_NEXTMENU) { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (LPMDINEXTMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnNotifyFormat(CWindow wndFrom, int nCommand)
+#define CR_MSG_WM_NOTIFYFORMAT(func) \
+ if (uMsg == WM_NOTIFYFORMAT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (int)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD dwData)
+#define CR_MSG_WM_POWERBROADCAST(func) \
+ if (uMsg == WM_POWERBROADCAST) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((DWORD)wParam, (DWORD)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrint(CDCHandle dc, UINT uFlags)
+#define CR_MSG_WM_PRINT(func) \
+ if (uMsg == WM_PRINT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrintClient(CDCHandle dc, UINT uFlags)
+#define CR_MSG_WM_PRINTCLIENT(func) \
+ if (uMsg == WM_PRINTCLIENT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError)
+#define CR_MSG_WM_RASDIALEVENT(func) \
+ if (uMsg == WM_RASDIALEVENT) { \
+ SetMsgHandled(TRUE); \
+ func((RASCONNSTATE)wParam, (DWORD)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFont(CFont font, BOOL bRedraw)
+#define CR_MSG_WM_SETFONT(func) \
+ if (uMsg == WM_SETFONT) { \
+ SetMsgHandled(TRUE); \
+ func((HFONT)wParam, (BOOL)LOWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetHotKey(int nVirtKey, UINT uFlags)
+#define CR_MSG_WM_SETHOTKEY(func) \
+ if (uMsg == WM_SETHOTKEY) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), \
+ (UINT)HIBYTE(LOWORD(wParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnSetIcon(UINT uType, HICON hIcon)
+#define CR_MSG_WM_SETICON(func) \
+ if (uMsg == WM_SETICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetRedraw(BOOL bRedraw)
+#define CR_MSG_WM_SETREDRAW(func) \
+ if (uMsg == WM_SETREDRAW) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetText(LPCTSTR lpstrText)
+#define CR_MSG_WM_SETTEXT(func) \
+ if (uMsg == WM_SETTEXT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCTSTR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUserChanged()
+#define CR_MSG_WM_USERCHANGED(func) \
+ if (uMsg == WM_USERCHANGED) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// New NT4 & NT5 messages
+
+#if (_WIN32_WINNT >= 0x0400)
+
+// void OnMouseHover(WPARAM wParam, CPoint ptPos)
+#define CR_MSG_WM_MOUSEHOVER(func) \
+ if (uMsg == WM_MOUSEHOVER) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseLeave()
+#define CR_MSG_WM_MOUSELEAVE(func) \
+ if (uMsg == WM_MOUSELEAVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0400 */
+
+#if (WINVER >= 0x0500)
+
+// void OnMenuRButtonUp(WPARAM wParam, CMenu menu)
+#define CR_MSG_WM_MENURBUTTONUP(func) \
+ if (uMsg == WM_MENURBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuDrag(WPARAM wParam, CMenu menu)
+#define CR_MSG_WM_MENUDRAG(func) \
+ if (uMsg == WM_MENUDRAG) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(wParam, (HMENU)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info)
+#define CR_MSG_WM_MENUGETOBJECT(func) \
+ if (uMsg == WM_MENUGETOBJECT) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((PMENUGETOBJECTINFO)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUnInitMenuPopup(UINT nID, CMenu menu)
+#define CR_MSG_WM_UNINITMENUPOPUP(func) \
+ if (uMsg == WM_UNINITMENUPOPUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(lParam), (HMENU)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuCommand(WPARAM nIndex, CMenu menu)
+#define CR_MSG_WM_MENUCOMMAND(func) \
+ if (uMsg == WM_MENUCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* WINVER >= 0x0500 */
+
+#if (_WIN32_WINNT >= 0x0500)
+
+// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys)
+#define CR_MSG_WM_APPCOMMAND(func) \
+ if (uMsg == WM_APPCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, \
+ GET_APPCOMMAND_LPARAM(lParam), \
+ GET_DEVICE_LPARAM(lParam), \
+ GET_KEYSTATE_LPARAM(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONDOWN(func) \
+ if (uMsg == WM_NCXBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONUP(func) \
+ if (uMsg == WM_NCXBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCXBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONDOWN(func) \
+ if (uMsg == WM_XBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONUP(func) \
+ if (uMsg == WM_XBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONDBLCLK(func) \
+ if (uMsg == WM_XBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeUIState(WORD nAction, WORD nState)
+#define CR_MSG_WM_CHANGEUISTATE(func) \
+ if (uMsg == WM_CHANGEUISTATE) { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUpdateUIState(WORD nAction, WORD nState)
+#define CR_MSG_WM_UPDATEUISTATE(func) \
+ if (uMsg == WM_UPDATEUISTATE) { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnQueryUIState()
+#define CR_MSG_WM_QUERYUISTATE(func) \
+ if (uMsg == WM_QUERYUISTATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif // (_WIN32_WINNT >= 0x0500)
+
+#if (_WIN32_WINNT >= 0x0501)
+
+// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput)
+#define CR_MSG_WM_INPUT(func) \
+ if (uMsg == WM_INPUT) { \
+ SetMsgHandled(TRUE); \
+ func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_UNICHAR(func) \
+ if (uMsg == WM_UNICHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ if (IsMsgHandled()) { \
+ lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \
+ return TRUE; \
+ } \
+ }
+
+// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION
+// nSessionID)
+#define CR_MSG_WM_WTSSESSION_CHANGE(func) \
+ if (uMsg == WM_WTSSESSION_CHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// OnThemeChanged()
+#define CR_MSG_WM_THEMECHANGED(func) \
+ if (uMsg == WM_THEMECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0501 */
+
+///////////////////////////////////////////////////////////////////////////////
+// ATL defined messages
+
+// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData)
+#define CR_MSG_WM_FORWARDMSG(func) \
+ if (uMsg == WM_FORWARDMSG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Dialog specific messages
+
+// LRESULT OnDMGetDefID()
+#define MSG_DM_GETDEFID(func) \
+ if (uMsg == DM_GETDEFID) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMSetDefID(UINT DefID)
+#define MSG_DM_SETDEFID(func) \
+ if (uMsg == DM_SETDEFID) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMReposition()
+#define MSG_DM_REPOSITION(func) \
+ if (uMsg == DM_REPOSITION) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Reflected messages
+
+// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define MSG_OCM_COMMAND(func) \
+ if (uMsg == OCM_COMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh)
+#define MSG_OCM_NOTIFY(func) \
+ if (uMsg == OCM_NOTIFY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define MSG_OCM_PARENTNOTIFY(func) \
+ if (uMsg == OCM_PARENTNOTIFY) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define MSG_OCM_DRAWITEM(func) \
+ if (uMsg == OCM_DRAWITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT
+// lpMeasureItemStruct)
+#define MSG_OCM_MEASUREITEM(func) \
+ if (uMsg == OCM_MEASUREITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT
+// lpCompareItemStruct)
+#define MSG_OCM_COMPAREITEM(func) \
+ if (uMsg == OCM_COMPAREITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define MSG_OCM_DELETEITEM(func) \
+ if (uMsg == OCM_DELETEITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define MSG_OCM_VKEYTOITEM(func) \
+ if (uMsg == OCM_VKEYTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define MSG_OCM_CHARTOITEM(func) \
+ if (uMsg == OCM_CHARTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_HSCROLL(func) \
+ if (uMsg == OCM_HSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_VSCROLL(func) \
+ if (uMsg == OCM_VSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit)
+#define MSG_OCM_CTLCOLOREDIT(func) \
+ if (uMsg == OCM_CTLCOLOREDIT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define MSG_OCM_CTLCOLORLISTBOX(func) \
+ if (uMsg == OCM_CTLCOLORLISTBOX) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button)
+#define MSG_OCM_CTLCOLORBTN(func) \
+ if (uMsg == OCM_CTLCOLORBTN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define MSG_OCM_CTLCOLORDLG(func) \
+ if (uMsg == OCM_CTLCOLORDLG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define MSG_OCM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == OCM_CTLCOLORSCROLLBAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define MSG_OCM_CTLCOLORSTATIC(func) \
+ if (uMsg == OCM_CTLCOLORSTATIC) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Edit specific messages
+
+// void OnClear()
+#define CR_MSG_WM_CLEAR(func) \
+ if (uMsg == WM_CLEAR) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCopy()
+#define CR_MSG_WM_COPY(func) \
+ if (uMsg == WM_COPY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCut()
+#define CR_MSG_WM_CUT(func) \
+ if (uMsg == WM_CUT) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaste()
+#define CR_MSG_WM_PASTE(func) \
+ if (uMsg == WM_PASTE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUndo()
+#define CR_MSG_WM_UNDO(func) \
+ if (uMsg == WM_UNDO) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Generic message handlers
+
+// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define CR_MESSAGE_HANDLER_EX(msg, func) \
+ if (uMsg == msg) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define CR_MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \
+ if (uMsg >= msgFirst && uMsg <= msgLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Commands and notifications
+
+// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_COMMAND && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && \
+ LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && \
+ LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && \
+ LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX( \
+ idFirst, idLast, code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && \
+ LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#define CR_DEFLATE_RECT(rect, by) \
+ { \
+ (rect)->left += (by)->left; \
+ (rect)->top += (by)->top; \
+ (rect)->right -= (by)->right; \
+ (rect)->bottom -= (by)->bottom; \
+ }
+
+#define CR_POINT_INITIALIZER_FROM_LPARAM(lparam) \
+ { LOWORD(lparam), HIWORD(lparam) }
+
+#endif // UI_GFX_WIN_MSG_UTIL_H_
diff --git a/chromium/ui/gfx/win/singleton_hwnd.cc b/chromium/ui/gfx/win/singleton_hwnd.cc
index 2de6a8b8a16..fc4d11f2d5e 100644
--- a/chromium/ui/gfx/win/singleton_hwnd.cc
+++ b/chromium/ui/gfx/win/singleton_hwnd.cc
@@ -37,8 +37,7 @@ BOOL SingletonHwnd::ProcessWindowMessage(HWND window,
}
SingletonHwnd::SingletonHwnd() {
- if (!base::MessageLoop::current() ||
- base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
+ if (!base::MessageLoopForUI::IsCurrent()) {
// Creating this window in (e.g.) a renderer inhibits shutdown on
// Windows. See http://crbug.com/230122 and http://crbug.com/236039.
DLOG(ERROR) << "Cannot create windows on non-UI thread!";
diff --git a/chromium/ui/gfx/win/window_impl.cc b/chromium/ui/gfx/win/window_impl.cc
index 7f0c232ae61..ff9fe57cf9d 100644
--- a/chromium/ui/gfx/win/window_impl.cc
+++ b/chromium/ui/gfx/win/window_impl.cc
@@ -97,7 +97,7 @@ ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) {
}
// No class found, need to register one.
- string16 name = string16(WindowImpl::kBaseClassName) +
+ base::string16 name = base::string16(WindowImpl::kBaseClassName) +
base::IntToString16(registered_count_++);
WNDCLASSEX window_class;
@@ -226,10 +226,14 @@ HICON WindowImpl::GetDefaultWindowIcon() const {
LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
LRESULT result = 0;
+ HWND hwnd = hwnd_;
+ if (message == WM_NCDESTROY)
+ hwnd_ = NULL;
+
// Handle the message if it's in our message map; otherwise, let the system
// handle it.
- if (!ProcessWindowMessage(hwnd_, message, w_param, l_param, result))
- result = DefWindowProc(hwnd_, message, w_param, l_param);
+ if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result))
+ result = DefWindowProc(hwnd, message, w_param, l_param);
return result;
}
diff --git a/chromium/ui/gfx/win/window_impl.h b/chromium/ui/gfx/win/window_impl.h
index 1825c0b2f00..8206562935f 100644
--- a/chromium/ui/gfx/win/window_impl.h
+++ b/chromium/ui/gfx/win/window_impl.h
@@ -5,17 +5,13 @@
#ifndef UI_GFX_WIN_WINDOW_IMPL_H_
#define UI_GFX_WIN_WINDOW_IMPL_H_
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlmisc.h>
-#include <atlcrack.h>
-
#include <string>
#include "base/logging.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/win/msg_util.h"
namespace gfx {
diff --git a/chromium/ui/gfx/x/BUILD.gn b/chromium/ui/gfx/x/BUILD.gn
new file mode 100644
index 00000000000..d7ae7ed4ab9
--- /dev/null
+++ b/chromium/ui/gfx/x/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+component("x") {
+ output_name = "gfx_x11"
+
+ sources = [
+ "x11_atom_cache.cc",
+ "x11_atom_cache.h",
+ "x11_connection.cc",
+ "x11_connection.h",
+ "x11_error_tracker.cc",
+ "x11_error_tracker.h",
+ "x11_switches.cc",
+ "x11_switches.h",
+ "x11_types.cc",
+ "x11_types.h",
+ ]
+
+ defines = [
+ "GFX_IMPLEMENTATION",
+ ]
+
+ configs += [
+ "//build/config/linux:x11",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
diff --git a/chromium/ui/gfx/x/gfx_x11.gyp b/chromium/ui/gfx/x/gfx_x11.gyp
new file mode 100644
index 00000000000..5be65ff1789
--- /dev/null
+++ b/chromium/ui/gfx/x/gfx_x11.gyp
@@ -0,0 +1,38 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ 'use_x11': 1, # It is necessary to explicitly set use_x11 here to make sure
+ # that the exclusion rules in filename_rules.gypi do not
+ # exclude the x11* files.
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'gfx_x11',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../build/linux/system.gyp:x11',
+ ],
+ 'defines': [
+ 'GFX_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'x11_atom_cache.cc',
+ 'x11_atom_cache.h',
+ 'x11_connection.cc',
+ 'x11_connection.h',
+ 'x11_error_tracker.cc',
+ 'x11_error_tracker.h',
+ 'x11_switches.cc',
+ 'x11_switches.h',
+ 'x11_types.cc',
+ 'x11_types.h',
+ ],
+ },
+ ]
+}
diff --git a/chromium/ui/gfx/x/x11_atom_cache.cc b/chromium/ui/gfx/x/x11_atom_cache.cc
index da75c0be34e..c9f52ca2aaa 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.cc
+++ b/chromium/ui/gfx/x/x11_atom_cache.cc
@@ -5,20 +5,21 @@
#include "ui/gfx/x/x11_atom_cache.h"
#include <X11/Xatom.h>
+#include <X11/Xlib.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
namespace ui {
-X11AtomCache::X11AtomCache(Display* xdisplay, const char** to_cache)
+X11AtomCache::X11AtomCache(XDisplay* xdisplay, const char** to_cache)
: xdisplay_(xdisplay),
uncached_atoms_allowed_(false) {
int cache_count = 0;
for (const char** i = to_cache; *i != NULL; i++)
cache_count++;
- scoped_ptr< ::Atom[]> cached_atoms(new ::Atom[cache_count]);
+ scoped_ptr<Atom[]> cached_atoms(new Atom[cache_count]);
// Grab all the atoms we need now to minimize roundtrips to the X11 server.
XInternAtoms(xdisplay_,
@@ -31,11 +32,11 @@ X11AtomCache::X11AtomCache(Display* xdisplay, const char** to_cache)
X11AtomCache::~X11AtomCache() {}
-::Atom X11AtomCache::GetAtom(const char* name) const {
- std::map<std::string, ::Atom>::const_iterator it = cached_atoms_.find(name);
+Atom X11AtomCache::GetAtom(const char* name) const {
+ std::map<std::string, Atom>::const_iterator it = cached_atoms_.find(name);
if (uncached_atoms_allowed_ && it == cached_atoms_.end()) {
- ::Atom atom = XInternAtom(xdisplay_, name, false);
+ Atom atom = XInternAtom(xdisplay_, name, false);
cached_atoms_.insert(std::make_pair(name, atom));
return atom;
}
diff --git a/chromium/ui/gfx/x/x11_atom_cache.h b/chromium/ui/gfx/x/x11_atom_cache.h
index fefa64205d0..6a29df720c6 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.h
+++ b/chromium/ui/gfx/x/x11_atom_cache.h
@@ -5,16 +5,14 @@
#ifndef UI_GFX_X_X11_ATOM_CACHE_H_
#define UI_GFX_X_X11_ATOM_CACHE_H_
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-
#include <map>
#include <string>
-#include <X11/Xlib.h>
+#include "base/basictypes.h"
+#include "ui/gfx/gfx_export.h"
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
+typedef unsigned long Atom;
+typedef struct _XDisplay XDisplay;
namespace ui {
@@ -25,22 +23,22 @@ namespace ui {
class GFX_EXPORT X11AtomCache {
public:
// Preinterns the NULL terminated list of string |to_cache_ on |xdisplay|.
- X11AtomCache(Display* xdisplay, const char** to_cache);
+ X11AtomCache(XDisplay* xdisplay, const char** to_cache);
~X11AtomCache();
// Returns the pre-interned Atom without having to go to the x server.
- ::Atom GetAtom(const char*) const;
+ Atom GetAtom(const char*) const;
// When an Atom isn't in the list of items we've cached, we should look it
// up, cache it locally, and then return the result.
void allow_uncached_atoms() { uncached_atoms_allowed_ = true; }
private:
- Display* xdisplay_;
+ XDisplay* xdisplay_;
bool uncached_atoms_allowed_;
- mutable std::map<std::string, ::Atom> cached_atoms_;
+ mutable std::map<std::string, Atom> cached_atoms_;
DISALLOW_COPY_AND_ASSIGN(X11AtomCache);
};
diff --git a/chromium/ui/gfx/x/x11_connection.cc b/chromium/ui/gfx/x/x11_connection.cc
new file mode 100644
index 00000000000..c5ee77f40d8
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_connection.cc
@@ -0,0 +1,17 @@
+// 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/gfx/x/x11_connection.h"
+
+#include <X11/Xlib.h>
+
+#include "ui/gfx/x/x11_types.h"
+
+namespace gfx {
+
+bool InitializeThreadedX11() {
+ return XInitThreads() && gfx::GetXDisplay();
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/x/x11_connection.h b/chromium/ui/gfx/x/x11_connection.h
new file mode 100644
index 00000000000..06ca89fe800
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_connection.h
@@ -0,0 +1,18 @@
+// 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_GFX_X_X11_CONNECTION_H_
+#define UI_GFX_X_X11_CONNECTION_H_
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Initializes thread support for X11, and opens a connection to the display.
+// Return false if either fails, and true otherwise.
+GFX_EXPORT bool InitializeThreadedX11();
+
+} // namespace gfx
+
+#endif // UI_GFX_X_X11_CONNECTION_H_
diff --git a/chromium/ui/gfx/x/x11_error_tracker.cc b/chromium/ui/gfx/x/x11_error_tracker.cc
new file mode 100644
index 00000000000..110f79ccd02
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_error_tracker.cc
@@ -0,0 +1,45 @@
+// 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 "base/logging.h"
+#include "ui/gfx/x/x11_error_tracker.h"
+
+#include "ui/gfx/x/x11_types.h"
+
+namespace {
+
+unsigned char g_x11_error_code = 0;
+static gfx::X11ErrorTracker* g_handler = NULL;
+
+int X11ErrorHandler(Display* display, XErrorEvent* error) {
+ g_x11_error_code = error->error_code;
+ return 0;
+}
+}
+
+namespace gfx {
+
+X11ErrorTracker::X11ErrorTracker() {
+ // This is a poor-man's check for incorrect usage. It disallows nested
+ // X11ErrorTracker instances on the same thread.
+ DCHECK(g_handler == NULL);
+ g_handler = this;
+ XSync(GetXDisplay(), False);
+ old_handler_ = XSetErrorHandler(X11ErrorHandler);
+ g_x11_error_code = 0;
+}
+
+X11ErrorTracker::~X11ErrorTracker() {
+ g_handler = NULL;
+ XSetErrorHandler(old_handler_);
+}
+
+bool X11ErrorTracker::FoundNewError() {
+ XSync(GetXDisplay(), False);
+ unsigned char error = g_x11_error_code;
+ g_x11_error_code = 0;
+ return error != 0;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/x/x11_error_tracker.h b/chromium/ui/gfx/x/x11_error_tracker.h
new file mode 100644
index 00000000000..efcac0c7099
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_error_tracker.h
@@ -0,0 +1,36 @@
+// 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_GFX_X_X11_ERROR_TRACKER_H_
+#define UI_GFX_X_X11_ERROR_TRACKER_H_
+
+#include <X11/Xlib.h>
+
+#include "base/basictypes.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// X11ErrorTracker catches X11 errors in a non-fatal way. It does so by
+// temporarily changing the X11 error handler. The old error handler is
+// restored when the tracker is destroyed.
+class GFX_EXPORT X11ErrorTracker {
+ public:
+ X11ErrorTracker();
+ ~X11ErrorTracker();
+
+ // Returns whether an X11 error happened since this function was last called
+ // (or since the creation of the tracker). This is potentially expensive,
+ // since this causes a sync with the X server.
+ bool FoundNewError();
+
+ private:
+ XErrorHandler old_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11ErrorTracker);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_X_X11_ERROR_TRACKER_H_
diff --git a/chromium/ui/gfx/x/x11_switches.cc b/chromium/ui/gfx/x/x11_switches.cc
new file mode 100644
index 00000000000..bda0ad3c557
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_switches.cc
@@ -0,0 +1,15 @@
+// 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/gfx/x/x11_switches.h"
+
+namespace switches {
+
+#if !defined(OS_CHROMEOS)
+// Which X11 display to connect to. Emulates the GTK+ "--display=" command line
+// argument.
+const char kX11Display[] = "display";
+#endif
+
+} // namespace switches
diff --git a/chromium/ui/gfx/x/x11_switches.h b/chromium/ui/gfx/x/x11_switches.h
new file mode 100644
index 00000000000..4044c514154
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_switches.h
@@ -0,0 +1,18 @@
+// 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_GFX_X_X11_SWITCHES_H_
+#define UI_GFX_X_X11_SWITCHES_H_
+
+#include "ui/gfx/gfx_export.h"
+
+namespace switches {
+
+#if !defined(OS_CHROMEOS)
+GFX_EXPORT extern const char kX11Display[];
+#endif
+
+} // namespace switches
+
+#endif // UI_GFX_X_X11_SWITCHES_H_
diff --git a/chromium/ui/gfx/x/x11_types.cc b/chromium/ui/gfx/x/x11_types.cc
index 48ce6416b69..54a0816c652 100644
--- a/chromium/ui/gfx/x/x11_types.cc
+++ b/chromium/ui/gfx/x/x11_types.cc
@@ -6,12 +6,27 @@
#include <X11/Xlib.h>
+#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
+#include "ui/gfx/x/x11_switches.h"
namespace gfx {
XDisplay* GetXDisplay() {
- return base::MessagePumpForUI::GetDefaultXDisplay();
+ static XDisplay* display = NULL;
+ if (!display)
+ display = OpenNewXDisplay();
+ return display;
+}
+
+XDisplay* OpenNewXDisplay() {
+#if defined(OS_CHROMEOS)
+ return XOpenDisplay(NULL);
+#else
+ std::string display_str = base::CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kX11Display);
+ return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str());
+#endif
}
void PutARGBImage(XDisplay* display,
diff --git a/chromium/ui/gfx/x/x11_types.h b/chromium/ui/gfx/x/x11_types.h
index 0f96fdc6a89..b9f1f9c1fce 100644
--- a/chromium/ui/gfx/x/x11_types.h
+++ b/chromium/ui/gfx/x/x11_types.h
@@ -20,6 +20,9 @@ namespace gfx {
// chrome codebase to get the display from window.
GFX_EXPORT XDisplay* GetXDisplay();
+// This opens a new X11 XDisplay*, taking command line arguments into account.
+GFX_EXPORT XDisplay* OpenNewXDisplay();
+
// Return the number of bits-per-pixel for a pixmap of the given depth
GFX_EXPORT int BitsPerPixelForPixmapDepth(XDisplay* display, int depth);
diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn
new file mode 100644
index 00000000000..f63d580aed8
--- /dev/null
+++ b/chromium/ui/gl/BUILD.gn
@@ -0,0 +1,341 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+gl_binding_output_dir = target_gen_dir
+
+config("gl_config") {
+ if (use_x11) {
+ defines = [ "GL_GLEXT_PROTOTYPES" ]
+ }
+
+ # TODO(brettw) this should be removed and the the files using the generated
+ # GL bindings should use the path inside the gen directory.
+ include_dirs = [ gl_binding_output_dir ]
+}
+
+component("gl") {
+ output_name = "gl_wrapper" # Avoid colliding with OS X"s libGL.dylib.
+
+ sources = [
+ "android/gl_jni_registrar.cc",
+ "android/gl_jni_registrar.h",
+ "android/scoped_java_surface.cc",
+ "android/scoped_java_surface.h",
+ "android/surface_texture.cc",
+ "android/surface_texture.h",
+ "android/surface_texture_listener.cc",
+ "android/surface_texture_listener.h",
+ "android/surface_texture_tracker.cc",
+ "android/surface_texture_tracker.h",
+ "gl_bindings.h",
+ "gl_bindings_skia_in_process.cc",
+ "gl_bindings_skia_in_process.h",
+ "gl_context.cc",
+ "gl_context.h",
+ "gl_context_android.cc",
+ "gl_context_mac.mm",
+ "gl_context_osmesa.cc",
+ "gl_context_osmesa.h",
+ "gl_context_stub.cc",
+ "gl_context_stub.h",
+ "gl_context_stub_with_extensions.cc",
+ "gl_context_stub_with_extensions.h",
+ "gl_context_win.cc",
+ "gl_export.h",
+ "gl_fence.cc",
+ "gl_fence.h",
+ "gl_gl_api_implementation.cc",
+ "gl_gl_api_implementation.h",
+ "gl_image.cc",
+ "gl_image.h",
+ "gl_image_android.cc",
+ "gl_image_mac.cc",
+ "gl_image_shm.cc",
+ "gl_image_shm.h",
+ "gl_image_stub.cc",
+ "gl_image_stub.h",
+ "gl_image_win.cc",
+ "gl_implementation.cc",
+ "gl_implementation.h",
+ "gl_implementation_android.cc",
+ "gl_implementation_mac.cc",
+ "gl_implementation_win.cc",
+ "gl_osmesa_api_implementation.cc",
+ "gl_osmesa_api_implementation.h",
+ "gl_share_group.cc",
+ "gl_share_group.h",
+ "gl_state_restorer.cc",
+ "gl_state_restorer.h",
+ "gl_surface.cc",
+ "gl_surface.h",
+ "gl_surface_android.cc",
+ "gl_surface_mac.cc",
+ "gl_surface_stub.cc",
+ "gl_surface_stub.h",
+ "gl_surface_win.cc",
+ "gl_surface_osmesa.cc",
+ "gl_surface_osmesa.h",
+ "gl_switches.cc",
+ "gl_switches.h",
+ "gl_version_info.cc",
+ "gl_version_info.h",
+ "gpu_switching_manager.cc",
+ "gpu_switching_manager.h",
+ "scoped_binders.cc",
+ "scoped_binders.h",
+ "scoped_make_current.cc",
+ "scoped_make_current.h",
+ "sync_control_vsync_provider.cc",
+ "sync_control_vsync_provider.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_gl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_gl.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_osmesa.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_osmesa.h",
+ ]
+
+ defines = [ "GL_IMPLEMENTATION" ]
+
+ include_dirs = [
+ "//third_party/switfshader/include",
+ "//third_party/khronos",
+ "//third_party/mesa/src/include",
+ gl_binding_output_dir,
+ ]
+
+ all_dependent_configs = [ ":gl_config" ]
+
+ deps = [
+ ":generate_gl_bindings",
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//gpu/command_buffer/common",
+ "//third_party/mesa:mesa_headers",
+ "//skia",
+ "//ui/events/platform",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ # TODO(GYP) hook up once this is converted.
+ forward_dependent_configs_from = [ "//third_party/mesa:mesa_headers" ]
+
+ if (is_win || is_android || is_linux) {
+ sources += [
+ "egl_util.cc",
+ "egl_util.h",
+ "gl_context_egl.cc",
+ "gl_context_egl.h",
+ "gl_image_egl.cc",
+ "gl_image_egl.h",
+ "gl_surface_egl.cc",
+ "gl_surface_egl.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_egl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_egl.h",
+ ]
+ }
+ if (is_android || is_linux) {
+ sources += [
+ "gl_implementation_osmesa.cc",
+ "gl_implementation_osmesa.h",
+ ]
+ }
+ if (use_x11) {
+ sources += [
+ "gl_context_glx.cc",
+ "gl_context_glx.h",
+ "gl_context_x11.cc",
+ "gl_glx_api_implementation.cc",
+ "gl_glx_api_implementation.h",
+ "gl_image_glx.cc",
+ "gl_image_glx.h",
+ "gl_image_x11.cc",
+ "gl_implementation_x11.cc",
+ "gl_surface_glx.cc",
+ "gl_surface_glx.h",
+ "gl_surface_x11.cc",
+ "gl_egl_api_implementation.cc",
+ "gl_egl_api_implementation.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_glx.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_glx.h",
+ ]
+
+ configs += [
+ "//build/config/linux:x11",
+ "//build/config/linux:xcomposite",
+ "//build/config/linux:xext",
+ ]
+
+ deps += [
+ "//ui/gfx:gfx_x11",
+ ]
+ }
+ if (is_win) {
+ sources += [
+ "gl_context_wgl.cc",
+ "gl_context_wgl.h",
+ "gl_egl_api_implementation.cc",
+ "gl_egl_api_implementation.h",
+ "gl_surface_wgl.cc",
+ "gl_surface_wgl.h",
+ "gl_wgl_api_implementation.cc",
+ "gl_wgl_api_implementation.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_wgl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_wgl.h",
+ ]
+
+ libs = [ "dwmapi.lib" ]
+ ldflags = [ "/DELAYLOAD:dwmapi.dll" ]
+ }
+ if (is_mac) {
+ sources += [
+ "gl_context_cgl.cc",
+ "gl_context_cgl.h",
+ "gl_image_io_surface.cc",
+ "gl_image_io_surface.h",
+ "scoped_cgl.cc",
+ "scoped_cgl.h",
+ ]
+
+ libs = [
+ "IOSurface.framework",
+ "OpenGL.framework",
+ ]
+ }
+ if (is_android) {
+ sources += [
+ "gl_egl_api_implementation.cc",
+ "gl_egl_api_implementation.h",
+ "gl_image_android_native_buffer.cc",
+ "gl_image_android_native_buffer.h",
+ "gl_image_surface_texture.cc",
+ "gl_image_surface_texture.h",
+ ]
+
+ defines += [
+ "GL_GLEXT_PROTOTYPES",
+ "EGL_EGLEXT_PROTOTYPES",
+ ]
+
+ libs = [ "android" ]
+
+ deps += [
+ ":gl_jni_headers",
+ ]
+ }
+ if (use_ozone) {
+ sources += [
+ "gl_context_ozone.cc",
+ "gl_image_ozone.cc",
+ "gl_implementation_ozone.cc",
+ "gl_surface_ozone.cc",
+ ]
+ deps += [
+ "//ui/gfx/ozone",
+ "//ui/ozone",
+ ]
+ }
+
+ # TODO(GYP) enable this dependency once its written.
+ #if (is_android && !android_webview_build) {
+ # deps += [ "//ui/android:ui_java" ]
+ #}
+}
+
+action("generate_gl_bindings") {
+ visibility = ":*" # Only targets in this file can see this.
+
+ script = "generate_bindings.py"
+
+ # TODO(brettw) make this dynamic. The GYP version calls "generate_bindings.py
+ # --inputs" to get the list here. What should happen is that the script
+ # should generate a .d file, which we should declare here. That will
+ # eliminate the need bot both hardcoding the list here or calling the script
+ # during GN-time.
+ source_prereqs = [
+ "EGL/eglextchromium.h",
+ "GL/glextchromium.h",
+ "//third_party/mesa/src/include/GL/glext.h",
+ "//third_party/khronos/GLES2/gl2ext.h",
+ "//gpu/GLES2/gl2chromium.h",
+ "//gpu/GLES2/gl2extchromium.h",
+ "//third_party/khronos/EGL/eglext.h",
+ "//third_party/mesa/src/include/GL/wglext.h",
+ "//third_party/mesa/src/include/GL/glx.h",
+ "//third_party/mesa/src/include/GL/glxext.h",
+ ]
+
+ outputs = [
+ "$gl_binding_output_dir/gl_bindings_autogen_egl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_egl.h",
+ "$gl_binding_output_dir/gl_bindings_api_autogen_egl.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_gl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_gl.h",
+ "$gl_binding_output_dir/gl_bindings_api_autogen_gl.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_glx.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_glx.h",
+ "$gl_binding_output_dir/gl_bindings_api_autogen_glx.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_mock.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_mock.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_osmesa.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_osmesa.h",
+ "$gl_binding_output_dir/gl_bindings_api_autogen_osmesa.h",
+ "$gl_binding_output_dir/gl_bindings_autogen_wgl.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_wgl.h",
+ "$gl_binding_output_dir/gl_bindings_api_autogen_wgl.h",
+ "$gl_binding_output_dir/gl_mock_autogen_gl.h",
+ ]
+
+ args = [
+ "--header-paths=" +
+ rebase_path("//third_party/khronos", root_build_dir) + ":" +
+ rebase_path("//third_party/mesa/src/include", root_build_dir) + ":" +
+ rebase_path("//ui/gl", root_build_dir) + ":" +
+ rebase_path("//gpu", root_build_dir),
+ rebase_path(gl_binding_output_dir, root_build_dir),
+ ]
+}
+
+config("gl_unittest_utils_config") {
+ include_dirs = [ gl_binding_output_dir ]
+}
+
+source_set("gl_unittest_utils") {
+ sources = [
+ "gl_mock.h",
+ "gl_mock.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_mock.cc",
+ "$gl_binding_output_dir/gl_bindings_autogen_mock.h",
+ "$gl_binding_output_dir/gl_mock_autogen_gl.h",
+ ]
+
+ configs += [ "//third_party/khronos:khronos_headers" ]
+ direct_dependent_configs = [ ":gl_unittest_utils_config" ]
+
+ deps = [
+ ":gl",
+ "//testing/gmock",
+ ]
+}
+
+if (is_android) {
+ generate_jar_jni("surface_jni_headers") {
+ jni_package = "ui/gl"
+ classes = [ "android/view/Surface.class" ]
+ }
+
+ generate_jni("gl_jni_headers") {
+ deps = [ ":surface_jni_headers" ]
+ forward_dependent_configs_from = [ ":surface_jni_headers" ]
+ sources = [
+ "../android/java/src/org/chromium/ui/gl/SurfaceTextureListener.java",
+ "../android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java",
+ ]
+ jni_package = "ui/gl"
+ }
+}
diff --git a/chromium/ui/gl/DEPS b/chromium/ui/gl/DEPS
index d0d2812b16a..961a38badc0 100644
--- a/chromium/ui/gl/DEPS
+++ b/chromium/ui/gl/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+third_party/khronos",
"+third_party/mesa/src/include",
"+third_party/skia",
+ "+ui/events",
"+ui/gfx",
"+ui/ozone",
]
diff --git a/chromium/ui/gl/OWNERS b/chromium/ui/gl/OWNERS
index 6f39d70c6bf..2b844f0248f 100644
--- a/chromium/ui/gl/OWNERS
+++ b/chromium/ui/gl/OWNERS
@@ -1,2 +1,3 @@
kbr@chromium.org
piman@chromium.org
+sievers@chromium.org
diff --git a/chromium/ui/gl/PRESUBMIT.py b/chromium/ui/gl/PRESUBMIT.py
new file mode 100644
index 00000000000..67ad99164bc
--- /dev/null
+++ b/chromium/ui/gl/PRESUBMIT.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Top-level presubmit script for ui/gl/.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def GetPreferredTryMasters(project, change):
+ return {
+ 'tryserver.chromium.gpu': {
+ 'linux_gpu': set(['defaulttests']),
+ 'mac_gpu': set(['defaulttests']),
+ 'win_gpu': set(['defaulttests']),
+ }
+ }
diff --git a/chromium/ui/gl/android/OWNERS b/chromium/ui/gl/android/OWNERS
deleted file mode 100644
index 17338220dad..00000000000
--- a/chromium/ui/gl/android/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-sievers@chromium.org
diff --git a/chromium/ui/gl/android/surface_texture.cc b/chromium/ui/gl/android/surface_texture.cc
index 35f9b47288b..3f55cbdaa75 100644
--- a/chromium/ui/gl/android/surface_texture.cc
+++ b/chromium/ui/gl/android/surface_texture.cc
@@ -26,12 +26,25 @@ bool GlContextMethodsAvailable() {
namespace gfx {
-SurfaceTexture::SurfaceTexture(int texture_id) {
+scoped_refptr<SurfaceTexture> SurfaceTexture::Create(int texture_id) {
JNIEnv* env = base::android::AttachCurrentThread();
- j_surface_texture_.Reset(
+ return new SurfaceTexture(
Java_SurfaceTexturePlatformWrapper_create(env, texture_id));
}
+scoped_refptr<SurfaceTexture> SurfaceTexture::CreateSingleBuffered(
+ int texture_id) {
+ DCHECK(IsSingleBufferModeSupported());
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return new SurfaceTexture(
+ Java_SurfaceTexturePlatformWrapper_createSingleBuffered(env, texture_id));
+}
+
+SurfaceTexture::SurfaceTexture(
+ const base::android::ScopedJavaLocalRef<jobject>& j_surface_texture) {
+ j_surface_texture_.Reset(j_surface_texture);
+}
+
SurfaceTexture::~SurfaceTexture() {
JNIEnv* env = base::android::AttachCurrentThread();
Java_SurfaceTexturePlatformWrapper_destroy(env, j_surface_texture_.obj());
@@ -52,6 +65,13 @@ void SurfaceTexture::UpdateTexImage() {
j_surface_texture_.obj());
}
+void SurfaceTexture::ReleaseTexImage() {
+ DCHECK(IsSingleBufferModeSupported());
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_SurfaceTexturePlatformWrapper_releaseTexImage(env,
+ j_surface_texture_.obj());
+}
+
void SurfaceTexture::GetTransformMatrix(float mtx[16]) {
JNIEnv* env = base::android::AttachCurrentThread();
@@ -103,12 +123,20 @@ void SurfaceTexture::DetachFromGLContext() {
ANativeWindow* SurfaceTexture::CreateSurface() {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaSurface surface(this);
+ // Note: This ensures that any local references used by
+ // ANativeWindow_fromSurface are released immediately. This is needed as a
+ // workaround for https://code.google.com/p/android/issues/detail?id=68174
+ base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
ANativeWindow* native_window = ANativeWindow_fromSurface(
env, surface.j_surface().obj());
return native_window;
}
// static
+bool SurfaceTexture::IsSingleBufferModeSupported() {
+ return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
+}
+
bool SurfaceTexture::RegisterSurfaceTexture(JNIEnv* env) {
return RegisterNativesImpl(env);
}
diff --git a/chromium/ui/gl/android/surface_texture.h b/chromium/ui/gl/android/surface_texture.h
index 62e375f796f..05bc5a36b43 100644
--- a/chromium/ui/gl/android/surface_texture.h
+++ b/chromium/ui/gl/android/surface_texture.h
@@ -21,7 +21,9 @@ namespace gfx {
class GL_EXPORT SurfaceTexture
: public base::RefCountedThreadSafe<SurfaceTexture>{
public:
- explicit SurfaceTexture(int texture_id);
+ static scoped_refptr<SurfaceTexture> Create(int texture_id);
+
+ static scoped_refptr<SurfaceTexture> CreateSingleBuffered(int texture_id);
// Set the listener callback, which will be invoked on the same thread that
// is being called from here for registration.
@@ -33,6 +35,13 @@ class GL_EXPORT SurfaceTexture
// Update the texture image to the most recent frame from the image stream.
void UpdateTexImage();
+ // Release the texture content. This is needed only in single buffered mode
+ // to allow the image content producer to take ownership
+ // of the image buffer.
+ // This is *only* supported on SurfaceTexture instantiated via
+ // |CreateSingleBuffered(...)|.
+ void ReleaseTexImage();
+
// Retrieve the 4x4 texture coordinate transform matrix associated with the
// texture image set by the most recent call to updateTexImage.
void GetTransformMatrix(float mtx[16]);
@@ -57,8 +66,16 @@ class GL_EXPORT SurfaceTexture
return j_surface_texture_;
}
+ // This should only be used to guard the SurfaceTexture instantiated via
+ // |CreateSingleBuffered(...)|
+ static bool IsSingleBufferModeSupported();
+
static bool RegisterSurfaceTexture(JNIEnv* env);
+ protected:
+ explicit SurfaceTexture(
+ const base::android::ScopedJavaLocalRef<jobject>& j_surface_texture);
+
private:
friend class base::RefCountedThreadSafe<SurfaceTexture>;
~SurfaceTexture();
diff --git a/chromium/ui/gl/android/surface_texture_listener.cc b/chromium/ui/gl/android/surface_texture_listener.cc
index 8e2f89c5256..b47116a8455 100644
--- a/chromium/ui/gl/android/surface_texture_listener.cc
+++ b/chromium/ui/gl/android/surface_texture_listener.cc
@@ -5,10 +5,8 @@
#include "ui/gl/android/surface_texture_listener.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "jni/SurfaceTextureListener_jni.h"
-#include "ui/gl/android/surface_texture.h"
namespace gfx {
diff --git a/chromium/ui/gl/android/surface_texture_tracker.cc b/chromium/ui/gl/android/surface_texture_tracker.cc
new file mode 100644
index 00000000000..d0ff16add92
--- /dev/null
+++ b/chromium/ui/gl/android/surface_texture_tracker.cc
@@ -0,0 +1,26 @@
+// 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/gl/android/surface_texture_tracker.h"
+
+#include "base/logging.h"
+
+namespace gfx {
+namespace {
+SurfaceTextureTracker* g_instance = NULL;
+} // namespace
+
+// static
+SurfaceTextureTracker* SurfaceTextureTracker::GetInstance() {
+ DCHECK(g_instance);
+ return g_instance;
+}
+
+// static
+void SurfaceTextureTracker::InitInstance(SurfaceTextureTracker* tracker) {
+ DCHECK(!g_instance);
+ g_instance = tracker;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/android/surface_texture_tracker.h b/chromium/ui/gl/android/surface_texture_tracker.h
new file mode 100644
index 00000000000..a86f144c273
--- /dev/null
+++ b/chromium/ui/gl/android/surface_texture_tracker.h
@@ -0,0 +1,32 @@
+// 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_GL_ANDROID_SURFACE_TEXTURE_TRACKER_H_
+#define UI_GL_ANDROID_SURFACE_TEXTURE_TRACKER_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/gl/gl_export.h"
+
+namespace gfx {
+
+class SurfaceTexture;
+
+// This interface is used to take ownership of preallocated surface textures
+// with specific ids.
+class GL_EXPORT SurfaceTextureTracker {
+ public:
+ static SurfaceTextureTracker* GetInstance();
+ static void InitInstance(SurfaceTextureTracker* tracker);
+
+ virtual scoped_refptr<SurfaceTexture> AcquireSurfaceTexture(
+ int primary_id,
+ int secondary_id) = 0;
+
+ protected:
+ virtual ~SurfaceTextureTracker() {}
+};
+
+} // namespace gfx
+
+#endif // UI_GL_ANDROID_SURFACE_TEXTURE_TRACKER_H_
diff --git a/chromium/ui/gl/generate_bindings.py b/chromium/ui/gl/generate_bindings.py
index 98c75028bb5..248e4ff1d31 100755
--- a/chromium/ui/gl/generate_bindings.py
+++ b/chromium/ui/gl/generate_bindings.py
@@ -11,6 +11,26 @@ import collections
import re
import sys
+"""In case there are multiple versions of the same function, one that's listed
+first takes priority if its conditions are met. If the function is an extension
+function, finding the extension from the extension string is a condition for
+binding it. The last version of the function is treated as a fallback option in
+case no other versions were bound, so a non-null function pointer in the
+bindings does not guarantee that the function is supported.
+
+Function binding conditions can be specified manually by supplying a versions
+array instead of the names array. Each version has the following keys:
+ name: Mandatory. Name of the function. Multiple versions can have the same
+ name but different conditions.
+ gl_versions: List of GL versions where the function is found.
+ extensions: Extensions where the function is found. If not specified, the
+ extensions are determined based on GL header files.
+ If the function exists in an extension header, you may specify
+ an empty array to prevent making that a condition for binding.
+
+By default, the function gets its name from the first name in its names or
+versions array. This can be overridden by supplying a 'known_as' key.
+"""
GL_FUNCTIONS = [
{ 'return_type': 'void',
'names': ['glActiveTexture'],
@@ -79,10 +99,12 @@ GL_FUNCTIONS = [
'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
'names': ['glBufferData'],
- 'arguments': 'GLenum target, GLsizei size, const void* data, GLenum usage', },
+ 'arguments':
+ 'GLenum target, GLsizeiptr size, const void* data, GLenum usage', },
{ 'return_type': 'void',
'names': ['glBufferSubData'],
- 'arguments': 'GLenum target, GLint offset, GLsizei size, const void* data', },
+ 'arguments':
+ 'GLenum target, GLintptr offset, GLsizeiptr size, const void* data', },
{ 'return_type': 'GLenum',
'names': ['glCheckFramebufferStatusEXT',
'glCheckFramebufferStatus'],
@@ -313,11 +335,13 @@ GL_FUNCTIONS = [
'names': ['glGetIntegerv'],
'arguments': 'GLenum pname, GLint* params', },
{ 'return_type': 'void',
- 'names': ['glGetProgramBinary', 'glGetProgramBinaryOES'],
+ 'known_as': 'glGetProgramBinary',
+ 'versions': [{ 'name': 'glGetProgramBinaryOES' },
+ { 'name': 'glGetProgramBinary',
+ 'extensions': ['GL_ARB_get_program_binary'] },
+ { 'name': 'glGetProgramBinary' }],
'arguments': 'GLuint program, GLsizei bufSize, GLsizei* length, '
- 'GLenum* binaryFormat, GLvoid* binary',
- 'other_extensions': ['ARB_get_program_binary',
- 'OES_get_program_binary'] },
+ 'GLenum* binaryFormat, GLvoid* binary' },
{ 'return_type': 'void',
'names': ['glGetProgramiv'],
'arguments': 'GLuint program, GLenum pname, GLint* params', },
@@ -404,6 +428,9 @@ GL_FUNCTIONS = [
{ 'return_type': 'void',
'names': ['glHint'],
'arguments': 'GLenum target, GLenum mode', },
+{ 'return_type': 'void',
+ 'names': ['glInsertEventMarkerEXT'],
+ 'arguments': 'GLsizei length, const char* marker', },
{ 'return_type': 'GLboolean',
'names': ['glIsBuffer'],
'arguments': 'GLuint buffer', },
@@ -435,7 +462,8 @@ GL_FUNCTIONS = [
'names': ['glLinkProgram'],
'arguments': 'GLuint program', },
{ 'return_type': 'void*',
- 'names': ['glMapBuffer', 'glMapBufferOES'],
+ 'known_as': 'glMapBuffer',
+ 'names': ['glMapBufferOES', 'glMapBuffer'],
'arguments': 'GLenum target, GLenum access', },
{ 'return_type': 'void*',
'names': ['glMapBufferRange'],
@@ -454,15 +482,24 @@ GL_FUNCTIONS = [
'names': ['glPolygonOffset'],
'arguments': 'GLfloat factor, GLfloat units', },
{ 'return_type': 'void',
- 'names': ['glProgramBinary', 'glProgramBinaryOES'],
+ 'names': ['glPopGroupMarkerEXT'],
+ 'arguments': 'void', },
+{ 'return_type': 'void',
+ 'known_as': 'glProgramBinary',
+ 'versions': [{ 'name': 'glProgramBinaryOES' },
+ { 'name': 'glProgramBinary',
+ 'extensions': ['GL_ARB_get_program_binary'] },
+ { 'name': 'glProgramBinary' }],
'arguments': 'GLuint program, GLenum binaryFormat, '
- 'const GLvoid* binary, GLsizei length',
- 'other_extensions': ['ARB_get_program_binary',
- 'OES_get_program_binary'] },
+ 'const GLvoid* binary, GLsizei length' },
+{ 'return_type': 'void',
+ 'versions': [{ 'name': 'glProgramParameteri',
+ 'extensions': ['GL_ARB_get_program_binary'] },
+ { 'name': 'glProgramParameteri' }],
+ 'arguments': 'GLuint program, GLenum pname, GLint value' },
{ 'return_type': 'void',
- 'names': ['glProgramParameteri'],
- 'arguments': 'GLuint program, GLenum pname, GLint value',
- 'other_extensions': ['ARB_get_program_binary'] },
+ 'names': ['glPushGroupMarkerEXT'],
+ 'arguments': 'GLsizei length, const char* marker', },
{ 'return_type': 'void',
'names': ['glQueryCounter'],
'arguments': 'GLuint id, GLenum target', },
@@ -477,10 +514,27 @@ GL_FUNCTIONS = [
{ 'return_type': 'void',
'names': ['glReleaseShaderCompiler'],
'arguments': 'void', },
+# Multisampling API is different in different GL versions, some require an
+# explicit resolve step for renderbuffers and/or FBO texture attachments and
+# some do not. Multiple alternatives might be present in a single
+# implementation, which require different use of the API and may have
+# different performance (explicit resolve performing worse, for example).
+# So even though the function signature is the same across versions, we split
+# their definitions so that the function to use can be chosen correctly at a
+# higher level.
+# TODO(oetuaho@nvidia.com): Some of these might still be possible to combine.
+# This could also fix weirdness in the mock bindings that's caused by the same
+# function name appearing multiple times.
+# This is the ES3 function, which requires explicit resolve:
{ 'return_type': 'void',
'names': ['glRenderbufferStorageMultisample'],
'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
'GLsizei width, GLsizei height', },
+# In desktop GL, EXT and core versions both have an explicit resolve step,
+# though desktop core GL implicitly resolves when drawing to a window.
+# TODO(oetuaho@nvidia.com): Right now this function also doubles as ES2 EXT
+# function, which has implicit resolve, and for which the fallback is wrong.
+# Fix this.
{ 'return_type': 'void',
'names': ['glRenderbufferStorageMultisampleEXT',
'glRenderbufferStorageMultisample'],
@@ -511,8 +565,8 @@ GL_FUNCTIONS = [
'const void* binary, GLsizei length', },
{ 'return_type': 'void',
'names': ['glShaderSource'],
- 'arguments':
- 'GLuint shader, GLsizei count, const char* const* str, const GLint* length',
+ 'arguments': 'GLuint shader, GLsizei count, const char* const* str, '
+ 'const GLint* length',
'logging_code': """
GL_SERVICE_LOG_CODE_BLOCK({
for (GLsizei ii = 0; ii < count; ++ii) {
@@ -636,7 +690,8 @@ GL_FUNCTIONS = [
'arguments': 'GLint location, GLsizei count, '
'GLboolean transpose, const GLfloat* value', },
{ 'return_type': 'GLboolean',
- 'names': ['glUnmapBuffer', 'glUnmapBufferOES'],
+ 'known_as': 'glUnmapBuffer',
+ 'names': ['glUnmapBufferOES', 'glUnmapBuffer'],
'arguments': 'GLenum target', },
{ 'return_type': 'void',
'names': ['glUseProgram'],
@@ -711,52 +766,75 @@ GL_FUNCTIONS = [
'names': ['glClientWaitSync'],
'arguments':
'GLsync sync, GLbitfield flags, GLuint64 timeout', },
+{ 'return_type': 'GLenum',
+ 'names': ['glWaitSync'],
+ 'arguments':
+ 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
{ 'return_type': 'void',
- 'names': ['glDrawArraysInstancedANGLE', 'glDrawArraysInstancedARB'],
+ 'known_as': 'glDrawArraysInstancedANGLE',
+ 'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE',
+ 'glDrawArraysInstanced'],
'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
{ 'return_type': 'void',
- 'names': ['glDrawElementsInstancedANGLE', 'glDrawElementsInstancedARB'],
+ 'known_as': 'glDrawElementsInstancedANGLE',
+ 'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE',
+ 'glDrawElementsInstanced'],
'arguments':
'GLenum mode, GLsizei count, GLenum type, const void* indices, '
'GLsizei primcount', },
{ 'return_type': 'void',
- 'names': ['glVertexAttribDivisorANGLE', 'glVertexAttribDivisorARB'],
+ 'known_as': 'glVertexAttribDivisorANGLE',
+ 'names': ['glVertexAttribDivisorARB', 'glVertexAttribDivisorANGLE',
+ 'glVertexAttribDivisor'],
'arguments':
'GLuint index, GLuint divisor', },
{ 'return_type': 'void',
- 'names': ['glGenVertexArraysOES',
- 'glGenVertexArraysAPPLE',
- 'glGenVertexArrays'],
- 'arguments': 'GLsizei n, GLuint* arrays',
- 'other_extensions': ['OES_vertex_array_object',
- 'APPLE_vertex_array_object',
- 'ARB_vertex_array_object'] },
-{ 'return_type': 'void',
- 'names': ['glDeleteVertexArraysOES',
- 'glDeleteVertexArraysAPPLE',
- 'glDeleteVertexArrays'],
- 'arguments': 'GLsizei n, const GLuint* arrays',
- 'other_extensions': ['OES_vertex_array_object',
- 'APPLE_vertex_array_object',
- 'ARB_vertex_array_object'] },
-{ 'return_type': 'void',
- 'names': ['glBindVertexArrayOES',
- 'glBindVertexArrayAPPLE',
- 'glBindVertexArray'],
- 'arguments': 'GLuint array',
- 'other_extensions': ['OES_vertex_array_object',
- 'APPLE_vertex_array_object',
- 'ARB_vertex_array_object'] },
+ 'known_as': 'glGenVertexArraysOES',
+ 'versions': [{ 'name': 'glGenVertexArrays',
+ 'gl_versions': ['gl3', 'gl4'] },
+ { 'name': 'glGenVertexArrays',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glGenVertexArraysOES' },
+ { 'name': 'glGenVertexArraysAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLsizei n, GLuint* arrays', },
+{ 'return_type': 'void',
+ 'known_as': 'glDeleteVertexArraysOES',
+ 'versions': [{ 'name': 'glDeleteVertexArrays',
+ 'gl_versions': ['gl3', 'gl4'] },
+ { 'name': 'glDeleteVertexArrays',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glDeleteVertexArraysOES' },
+ { 'name': 'glDeleteVertexArraysAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLsizei n, const GLuint* arrays' },
+{ 'return_type': 'void',
+ 'known_as': 'glBindVertexArrayOES',
+ 'versions': [{ 'name': 'glBindVertexArray',
+ 'gl_versions': ['gl3', 'gl4'] },
+ { 'name': 'glBindVertexArray',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glBindVertexArrayOES' },
+ { 'name': 'glBindVertexArrayAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLuint array' },
{ 'return_type': 'GLboolean',
- 'names': ['glIsVertexArrayOES',
- 'glIsVertexArrayAPPLE',
- 'glIsVertexArray'],
- 'arguments': 'GLuint array',
- 'other_extensions': ['OES_vertex_array_object',
- 'APPLE_vertex_array_object',
- 'ARB_vertex_array_object'] },
-{ 'return_type': 'void',
- 'names': ['glDiscardFramebufferEXT', 'glInvalidateFramebuffer'],
+ 'known_as': 'glIsVertexArrayOES',
+ 'versions': [{ 'name': 'glIsVertexArray',
+ 'gl_versions': ['gl3', 'gl4'] },
+ { 'name': 'glIsVertexArray',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glIsVertexArrayOES' },
+ { 'name': 'glIsVertexArrayAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLuint array' },
+{ 'return_type': 'void',
+ 'known_as': 'glDiscardFramebufferEXT',
+ 'versions': [{ 'name': 'glInvalidateFramebuffer',
+ 'gl_versions': ['es3'],
+ 'extensions': [] },
+ { 'name': 'glDiscardFramebufferEXT',
+ 'gl_versions': ['es1', 'es2'] }],
'arguments': 'GLenum target, GLsizei numAttachments, '
'const GLenum* attachments' },
]
@@ -832,15 +910,16 @@ EGL_FUNCTIONS = [
'arguments':
'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
{ 'return_type': 'EGLImageKHR',
- 'names': ['eglCreateImageKHR'],
+ 'versions': [{ 'name': 'eglCreateImageKHR',
+ 'extensions':
+ ['EGL_KHR_image_base', 'EGL_KHR_gl_texture_2D_image'] }],
'arguments':
'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, '
- 'const EGLint* attrib_list',
- 'other_extensions': ['EGL_KHR_image_base'] },
+ 'const EGLint* attrib_list' },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglDestroyImageKHR'],
- 'arguments': 'EGLDisplay dpy, EGLImageKHR image',
- 'other_extensions': ['EGL_KHR_image_base'] },
+ 'versions': [{ 'name' : 'eglDestroyImageKHR',
+ 'extensions': ['EGL_KHR_image_base'] }],
+ 'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
{ 'return_type': 'EGLSurface',
'names': ['eglCreateWindowSurface'],
'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
@@ -938,23 +1017,23 @@ EGL_FUNCTIONS = [
'arguments':
'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
{ 'return_type': 'EGLSyncKHR',
- 'names': ['eglCreateSyncKHR'],
- 'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list',
- 'other_extensions': ['EGL_KHR_fence_sync'] },
+ 'versions': [{ 'name': 'eglCreateSyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
{ 'return_type': 'EGLint',
- 'names': ['eglClientWaitSyncKHR'],
+ 'versions': [{ 'name': 'eglClientWaitSyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
- 'EGLTimeKHR timeout',
- 'other_extensions': ['EGL_KHR_fence_sync'] },
+ 'EGLTimeKHR timeout' },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglGetSyncAttribKHR'],
+ 'versions': [{ 'name': 'eglGetSyncAttribKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, '
- 'EGLint* value',
- 'other_extensions': ['EGL_KHR_fence_sync'] },
+ 'EGLint* value' },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglDestroySyncKHR'],
- 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync',
- 'other_extensions': ['EGL_KHR_fence_sync'] },
+ 'versions': [{ 'name': 'eglDestroySyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
{ 'return_type': 'EGLBoolean',
'names': ['eglGetSyncValuesCHROMIUM'],
'arguments':
@@ -962,9 +1041,9 @@ EGL_FUNCTIONS = [
'EGLuint64CHROMIUM* ust, EGLuint64CHROMIUM* msc, '
'EGLuint64CHROMIUM* sbc', },
{ 'return_type': 'EGLint',
- 'names': ['eglWaitSyncKHR'],
- 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags',
- 'other_extensions': ['EGL_KHR_wait_sync'] },
+ 'versions': [{ 'name': 'eglWaitSyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' }
]
WGL_FUNCTIONS = [
@@ -1214,7 +1293,7 @@ FUNCTION_SETS = [
[GLX_FUNCTIONS, 'glx', ['GL/glx.h', 'GL/glxext.h'], []],
]
-def GenerateHeader(file, functions, set_name, used_extension_functions):
+def GenerateHeader(file, functions, set_name, used_extensions):
"""Generates gl_bindings_autogen_x.h"""
# Write file header.
@@ -1239,12 +1318,12 @@ class GLContext;
file.write('\n')
for func in functions:
file.write('typedef %s (GL_BINDING_CALL *%sProc)(%s);\n' %
- (func['return_type'], func['names'][0], func['arguments']))
+ (func['return_type'], func['known_as'], func['arguments']))
# Write declarations for booleans indicating which extensions are available.
file.write('\n')
file.write("struct Extensions%s {\n" % set_name.upper())
- for extension, ext_functions in used_extension_functions:
+ for extension in sorted(used_extensions):
file.write(' bool b_%s;\n' % extension)
file.write('};\n')
file.write('\n')
@@ -1252,7 +1331,7 @@ class GLContext;
# Write Procs struct.
file.write("struct Procs%s {\n" % set_name.upper())
for func in functions:
- file.write(' %sProc %sFn;\n' % (func['names'][0], func['names'][0]))
+ file.write(' %sProc %sFn;\n' % (func['known_as'], func['known_as']))
file.write('};\n')
file.write('\n')
@@ -1266,7 +1345,7 @@ class GLContext;
""" % {'name': set_name.upper()})
for func in functions:
file.write(' virtual %s %sFn(%s) = 0;\n' %
- (func['return_type'], func['names'][0], func['arguments']))
+ (func['return_type'], func['known_as'], func['arguments']))
file.write('};\n')
file.write('\n')
@@ -1277,14 +1356,14 @@ class GLContext;
file.write('\n')
for func in functions:
file.write('#define %s ::gfx::g_current_%s_context->%sFn\n' %
- (func['names'][0], set_name.lower(), func['names'][0]))
+ (func['known_as'], set_name.lower(), func['known_as']))
file.write('\n')
file.write('#endif // UI_GFX_GL_GL_BINDINGS_AUTOGEN_%s_H_\n' %
set_name.upper())
-def GenerateAPIHeader(file, functions, set_name, used_extension_functions):
+def GenerateAPIHeader(file, functions, set_name):
"""Generates gl_bindings_api_autogen_x.h"""
# Write file header.
@@ -1300,12 +1379,12 @@ def GenerateAPIHeader(file, functions, set_name, used_extension_functions):
# Write API declaration.
for func in functions:
file.write(' virtual %s %sFn(%s) OVERRIDE;\n' %
- (func['return_type'], func['names'][0], func['arguments']))
+ (func['return_type'], func['known_as'], func['arguments']))
file.write('\n')
-def GenerateMockHeader(file, functions, set_name, used_extension_functions):
+def GenerateMockHeader(file, functions, set_name):
"""Generates gl_mock_autogen_x.h"""
# Write file header.
@@ -1327,37 +1406,12 @@ def GenerateMockHeader(file, functions, set_name, used_extension_functions):
if len(args):
arg_count = func['arguments'].count(',') + 1
file.write(' MOCK_METHOD%d(%s, %s(%s));\n' %
- (arg_count, func['names'][0][2:], func['return_type'], args))
-
- file.write('\n')
-
-
-def GenerateInterfaceHeader(
- file, functions, set_name, used_extension_functions):
- """Generates gl_interface_autogen_x.h"""
-
- # Write file header.
- file.write(
-"""// 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.
-
-// This file is automatically generated.
-
-""" % {'name': set_name.upper()})
-
- # Write API declaration.
- for func in functions:
- args = func['arguments']
- if args == 'void':
- args = ''
- file.write(' virtual %s %s(%s) = 0;\n' %
- (func['return_type'], func['names'][0][2:], args))
+ (arg_count, func['known_as'][2:], func['return_type'], args))
file.write('\n')
-def GenerateSource(file, functions, set_name, used_extension_functions):
+def GenerateSource(file, functions, set_name, used_extensions):
"""Generates gl_bindings_autogen_x.cc"""
# Write file header.
@@ -1374,6 +1428,7 @@ def GenerateSource(file, functions, set_name, used_extension_functions):
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_version_info.h"
#include "ui/gl/gl_%s_api_implementation.h"
using gpu::gles2::GLES2Util;
@@ -1381,67 +1436,150 @@ using gpu::gles2::GLES2Util;
namespace gfx {
""" % set_name.lower())
- # Write definitions of function pointers.
file.write('\n')
file.write('static bool g_debugBindingsInitialized;\n')
file.write('Driver%s g_driver_%s;\n' % (set_name.upper(), set_name.lower()))
file.write('\n')
- # Write function to initialize the core function pointers. The code assumes
- # any non-NULL pointer returned by GetGLCoreProcAddress() is valid, although
- # it may be overwritten by an extension function pointer later.
+ # Write stub functions that take the place of some functions before a context
+ # is initialized. This is done to provide clear asserts on debug build and to
+ # avoid crashing in case of a bug on release build.
file.write('\n')
- file.write('void Driver%s::InitializeBindings() {\n' %
+ for func in functions:
+ unique_names = set([version['name'] for version in func['versions']])
+ if len(unique_names) > 1:
+ file.write('%s %sNotBound(%s) {\n' %
+ (func['return_type'], func['known_as'], func['arguments']))
+ file.write(' NOTREACHED();\n')
+ return_type = func['return_type'].lower()
+ # Returning 0 works for booleans, integers and pointers.
+ if return_type != 'void':
+ file.write(' return 0;\n')
+ file.write('}\n')
+
+ # Write function to initialize the function pointers that are always the same
+ # and to initialize bindings where choice of the function depends on the
+ # extension string or the GL version to point to stub functions.
+ file.write('\n')
+ file.write('void Driver%s::InitializeStaticBindings() {\n' %
set_name.upper())
+
+ def WriteFuncBinding(file, known_as, version_name):
+ file.write(
+ ' fn.%sFn = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' %
+ (known_as, known_as, version_name))
+
for func in functions:
- first_name = func['names'][0]
- for i, name in enumerate(func['names']):
- if i:
- file.write(' if (!fn.%sFn)\n ' % first_name)
- file.write(
- ' fn.%sFn = reinterpret_cast<%sProc>('
- 'GetGLCoreProcAddress("%s"));\n' %
- (first_name, first_name, name))
+ unique_names = set([version['name'] for version in func['versions']])
+ if len(unique_names) == 1:
+ WriteFuncBinding(file, func['known_as'], func['known_as'])
+ else:
+ file.write(' fn.%sFn = reinterpret_cast<%sProc>(%sNotBound);\n' %
+ (func['known_as'], func['known_as'], func['known_as']))
+
file.write('}\n')
file.write('\n')
- # Write function to initialize the extension function pointers. This function
- # uses a current context to query which extensions are actually supported.
- file.write("""void Driver%s::InitializeExtensionBindings(
- GLContext* context) {
+ # Write function to initialize bindings where choice of the function depends
+ # on the extension string or the GL version.
+ file.write("""void Driver%s::InitializeDynamicBindings(GLContext* context) {
+ DCHECK(context && context->IsCurrent(NULL));
+ const GLVersionInfo* ver ALLOW_UNUSED = context->GetVersionInfo();
+ std::string extensions ALLOW_UNUSED = context->GetExtensions();
+ extensions += " ";
+
""" % set_name.upper())
- file.write(' DCHECK(context && context->IsCurrent(NULL));\n')
- for extension, ext_functions in used_extension_functions:
- file.write(' ext.b_%s = context->HasExtension("%s");\n' %
+ for extension in sorted(used_extensions):
+ # Extra space at the end of the extension name is intentional, it is used
+ # as a separator
+ file.write(' ext.b_%s = extensions.find("%s ") != std::string::npos;\n' %
(extension, extension))
- file.write(' if (ext.b_%s) {\n' %
- (extension))
- queried_entry_points = set()
- for entry_point_name, function_name in ext_functions:
- # Replace the pointer unconditionally unless this extension has several
- # alternatives for the same entry point (e.g.,
- # GL_ARB_blend_func_extended).
- if entry_point_name in queried_entry_points:
- file.write(' if (!fn.%sFn)\n ' % entry_point_name)
- file.write(
- ' fn.%sFn = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' %
- (entry_point_name, entry_point_name, function_name))
- queried_entry_points.add(entry_point_name)
- file.write(' }\n')
+
+ def WrapOr(cond):
+ if ' || ' in cond:
+ return '(%s)' % cond
+ return cond
+
+ def WrapAnd(cond):
+ if ' && ' in cond:
+ return '(%s)' % cond
+ return cond
+
+ def VersionCondition(version):
+ conditions = []
+ if 'gl_versions' in version:
+ gl_versions = version['gl_versions']
+ version_cond = ' || '.join(['ver->is_%s' % gl for gl in gl_versions])
+ conditions.append(WrapOr(version_cond))
+ if 'extensions' in version and version['extensions']:
+ ext_cond = ' || '.join(['ext.b_%s' % e for e in version['extensions']])
+ conditions.append(WrapOr(ext_cond))
+ return ' && '.join(conditions)
+
+ def WriteConditionalFuncBinding(file, func):
+ # Functions with only one version are always bound unconditionally
+ assert len(func['versions']) > 1
+ known_as = func['known_as']
+ i = 0
+ first_version = True
+ while i < len(func['versions']):
+ version = func['versions'][i]
+ cond = VersionCondition(version)
+ combined_conditions = [WrapAnd(cond)]
+ last_version = i + 1 == len(func['versions'])
+ while not last_version and \
+ func['versions'][i + 1]['name'] == version['name']:
+ i += 1
+ combinable_cond = VersionCondition(func['versions'][i])
+ combined_conditions.append(WrapAnd(combinable_cond))
+ last_version = i + 1 == len(func['versions'])
+ if len(combined_conditions) > 1:
+ if [1 for cond in combined_conditions if cond == '']:
+ cond = ''
+ else:
+ cond = ' || '.join(combined_conditions)
+ # Don't make the last possible binding conditional on anything else but
+ # that the function isn't already bound to avoid verbose specification
+ # of functions which have both ARB and core versions with the same name,
+ # and to be able to bind to mock extension functions in unit tests which
+ # call InitializeDynamicGLBindings with a stub context that doesn't have
+ # extensions in its extension string.
+ # TODO(oetuaho@nvidia.com): Get rid of the fallback.
+ # http://crbug.com/325668
+ if cond != '' and not last_version:
+ if not first_version:
+ file.write(' if (!fn.%sFn && (%s))\n ' % (known_as, cond))
+ else:
+ file.write(' if (%s)\n ' % cond)
+ elif not first_version:
+ file.write(' if (!fn.%sFn)\n ' % known_as)
+ WriteFuncBinding(file, known_as, version['name'])
+ i += 1
+ first_version = False
+
+ for func in functions:
+ unique_names = set([version['name'] for version in func['versions']])
+ if len(unique_names) > 1:
+ file.write('\n')
+ file.write(' fn.%sFn = 0;\n' % func['known_as'])
+ file.write(' debug_fn.%sFn = 0;\n' % func['known_as'])
+ WriteConditionalFuncBinding(file, func)
+
+ # Some new function pointers have been added, so update them in debug bindings
+ file.write('\n')
file.write(' if (g_debugBindingsInitialized)\n')
- file.write(' UpdateDebugExtensionBindings();\n')
+ file.write(' InitializeDebugBindings();\n')
file.write('}\n')
file.write('\n')
# Write logging wrappers for each function.
file.write('extern "C" {\n')
for func in functions:
- names = func['names']
return_type = func['return_type']
arguments = func['arguments']
file.write('\n')
file.write('static %s GL_BINDING_CALL Debug_%s(%s) {\n' %
- (return_type, names[0], arguments))
+ (return_type, func['known_as'], arguments))
argument_names = re.sub(
r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
argument_names = re.sub(
@@ -1463,9 +1601,9 @@ namespace gfx {
log_argument_names)
log_argument_names = re.sub(
r'CONSTVOID_([a-zA-Z0-9_]+)',
- r'static_cast<const void*>(\1)', log_argument_names);
+ 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);
+ r'CONSTCHAR_([a-zA-Z0-9_]+)', r'\1', log_argument_names)
log_argument_names = re.sub(
r'GLenum_([a-zA-Z0-9_]+)', r'GLES2Util::GetStringEnum(\1)',
log_argument_names)
@@ -1478,7 +1616,7 @@ namespace gfx {
log_argument_names = ''
else:
log_argument_names = " << " + log_argument_names
- function_name = names[0]
+ function_name = func['known_as']
if return_type == 'void':
file.write(' GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
(function_name, log_argument_names))
@@ -1494,7 +1632,7 @@ namespace gfx {
if 'logging_code' in func:
file.write("%s\n" % func['logging_code'])
else:
- file.write(' GL_SERVICE_LOG("GL_RESULT: " << result);\n');
+ file.write(' GL_SERVICE_LOG("GL_RESULT: " << result);\n')
file.write(' return result;\n')
file.write('}\n')
file.write('} // extern "C"\n')
@@ -1504,7 +1642,7 @@ namespace gfx {
file.write('void Driver%s::InitializeDebugBindings() {\n' %
set_name.upper())
for func in functions:
- first_name = func['names'][0]
+ first_name = func['known_as']
file.write(' if (!debug_fn.%sFn) {\n' % first_name)
file.write(' debug_fn.%sFn = fn.%sFn;\n' % (first_name, first_name))
file.write(' fn.%sFn = Debug_%s;\n' % (first_name, first_name))
@@ -1512,20 +1650,6 @@ namespace gfx {
file.write(' g_debugBindingsInitialized = true;\n')
file.write('}\n')
- # Write function to update the debug function pointers to extension functions
- # after the extensions have been initialized.
- file.write('\n')
- file.write('void Driver%s::UpdateDebugExtensionBindings() {\n' %
- set_name.upper())
- for extension, ext_functions in used_extension_functions:
- for name, _ in ext_functions:
- file.write(' if (debug_fn.%sFn != fn.%sFn &&\n' % (name, name))
- file.write(' fn.%sFn != Debug_%s) {\n' % (name, name))
- file.write(' debug_fn.%sFn = fn.%sFn;\n' % (name, name))
- file.write(' fn.%sFn = Debug_%s;\n' % (name, name))
- file.write(' }\n')
- file.write('}\n')
-
# Write function to clear all function pointers.
file.write('\n')
file.write("""void Driver%s::ClearBindings() {
@@ -1533,21 +1657,24 @@ namespace gfx {
}
""" % set_name.upper())
- # Write GLApiBase functions
- for func in functions:
- names = func['names']
- return_type = func['return_type']
- arguments = func['arguments']
- file.write('\n')
- file.write('%s %sApiBase::%sFn(%s) {\n' %
- (return_type, set_name.upper(), names[0], arguments))
+ def MakeArgNames(arguments):
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)
if argument_names == 'void' or argument_names == '':
argument_names = ''
- function_name = names[0]
+ return argument_names
+
+ # Write GLApiBase functions
+ for func in functions:
+ function_name = func['known_as']
+ return_type = func['return_type']
+ arguments = func['arguments']
+ file.write('\n')
+ file.write('%s %sApiBase::%sFn(%s) {\n' %
+ (return_type, set_name.upper(), function_name, arguments))
+ argument_names = MakeArgNames(arguments)
if return_type == 'void':
file.write(' driver_->fn.%sFn(%s);\n' %
(function_name, argument_names))
@@ -1558,19 +1685,13 @@ namespace gfx {
# Write TraceGLApi functions
for func in functions:
- names = func['names']
+ function_name = func['known_as']
return_type = func['return_type']
arguments = func['arguments']
file.write('\n')
file.write('%s Trace%sApi::%sFn(%s) {\n' %
- (return_type, set_name.upper(), names[0], arguments))
- 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)
- if argument_names == 'void' or argument_names == '':
- argument_names = ''
- function_name = names[0]
+ (return_type, set_name.upper(), function_name, arguments))
+ argument_names = MakeArgNames(arguments)
file.write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::%s")\n' %
function_name)
if return_type == 'void':
@@ -1581,12 +1702,77 @@ namespace gfx {
(set_name.lower(), function_name, argument_names))
file.write('}\n')
+ # Write NoContextGLApi functions
+ if set_name.upper() == "GL":
+ for func in functions:
+ function_name = func['known_as']
+ return_type = func['return_type']
+ arguments = func['arguments']
+ file.write('\n')
+ file.write('%s NoContextGLApi::%sFn(%s) {\n' %
+ (return_type, function_name, arguments))
+ argument_names = MakeArgNames(arguments)
+ no_context_error = "Trying to call %s() without current GL context" % function_name
+ file.write(' NOTREACHED() << "%s";\n' % no_context_error)
+ file.write(' LOG(ERROR) << "%s";\n' % no_context_error)
+ default_value = { 'GLenum': 'static_cast<GLenum>(0)',
+ 'GLuint': '0U',
+ 'GLint': '0',
+ 'GLboolean': 'GL_FALSE',
+ 'GLbyte': '0',
+ 'GLubyte': '0',
+ 'GLbutfield': '0',
+ 'GLushort': '0',
+ 'GLsizei': '0',
+ 'GLfloat': '0.0f',
+ 'GLdouble': '0.0',
+ 'GLsync': 'NULL'}
+ if return_type.endswith('*'):
+ file.write(' return NULL;\n')
+ elif return_type != 'void':
+ file.write(' return %s;\n' % default_value[return_type])
+ file.write('}\n')
+
file.write('\n')
file.write('} // namespace gfx\n')
-def GenerateMockSource(file, functions):
- """Generates functions that invoke a mock GLInterface"""
+def GetUniquelyNamedFunctions(functions):
+ uniquely_named_functions = {}
+
+ for func in functions:
+ for version in func['versions']:
+ uniquely_named_functions[version['name']] = ({
+ 'name': version['name'],
+ 'return_type': func['return_type'],
+ 'arguments': func['arguments'],
+ 'known_as': func['known_as']
+ })
+ return uniquely_named_functions
+
+
+def GenerateMockBindingsHeader(file, functions):
+ """Headers for functions that invoke MockGLInterface members"""
+
+ file.write(
+"""// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is automatically generated.
+
+""")
+ uniquely_named_functions = GetUniquelyNamedFunctions(functions)
+
+ for key in sorted(uniquely_named_functions.iterkeys()):
+ func = uniquely_named_functions[key]
+ file.write('static %s GL_BINDING_CALL Mock_%s(%s);\n' %
+ (func['return_type'], func['name'], func['arguments']))
+
+
+def GenerateMockBindingsSource(file, functions):
+ """Generates functions that invoke MockGLInterface members and a
+ GetGLProcAddress function that returns addresses to those functions."""
file.write(
"""// Copyright (c) 2011 The Chromium Authors. All rights reserved.
@@ -1597,25 +1783,38 @@ def GenerateMockSource(file, functions):
#include <string.h>
-#include "ui/gl/gl_interface.h"
+#include "ui/gl/gl_mock.h"
namespace gfx {
+
+// This is called mainly to prevent the compiler combining the code of mock
+// functions with identical contents, so that their function pointers will be
+// different.
+void MakeFunctionUnique(const char *func_name) {
+ VLOG(2) << "Calling mock " << func_name;
+}
+
""")
- # Write function that trampoline into the GLInterface.
- for func in functions:
+ # Write functions that trampoline into the set MockGLInterface instance.
+ uniquely_named_functions = GetUniquelyNamedFunctions(functions)
+ sorted_function_names = sorted(uniquely_named_functions.iterkeys())
+
+ for key in sorted_function_names:
+ func = uniquely_named_functions[key]
file.write('\n')
- file.write('%s GL_BINDING_CALL Mock_%s(%s) {\n' %
- (func['return_type'], func['names'][0], func['arguments']))
- argument_names = re.sub(r'(const )?[a-zA-Z0-9]+((\s*const\s*)?\*)* ([a-zA-Z0-9]+)', r'\4',
- func['arguments'])
+ file.write('%s GL_BINDING_CALL MockGLInterface::Mock_%s(%s) {\n' %
+ (func['return_type'], func['name'], func['arguments']))
+ file.write(' MakeFunctionUnique("%s");\n' % func['name'])
+ arg_re = r'(const )?[a-zA-Z0-9]+((\s*const\s*)?\*)* ([a-zA-Z0-9]+)'
+ argument_names = re.sub(arg_re, r'\4', func['arguments'])
if argument_names == 'void':
argument_names = ''
- function_name = func['names'][0][2:]
+ function_name = func['known_as'][2:]
if func['return_type'] == 'void':
- file.write(' GLInterface::GetGLInterface()->%s(%s);\n' %
+ file.write(' interface_->%s(%s);\n' %
(function_name, argument_names))
else:
- file.write(' return GLInterface::GetGLInterface()->%s(%s);\n' %
+ file.write(' return interface_->%s(%s);\n' %
(function_name, argument_names))
file.write('}\n')
@@ -1629,14 +1828,15 @@ namespace gfx {
# Write a function to lookup a mock GL function based on its name.
file.write('\n')
- file.write('void* GL_BINDING_CALL GetMockGLProcAddress(const char* name) {\n')
- for func in functions:
- first_name = func['names'][0]
- file.write(' if (strcmp(name, "%s") == 0)\n' % first_name)
- file.write(' return reinterpret_cast<void*>(Mock_%s);\n' % first_name)
+ file.write('void* GL_BINDING_CALL ' +
+ 'MockGLInterface::GetGLProcAddress(const char* name) {\n')
+ for key in sorted_function_names:
+ name = uniquely_named_functions[key]['name']
+ file.write(' if (strcmp(name, "%s") == 0)\n' % name)
+ file.write(' return reinterpret_cast<void*>(Mock_%s);\n' % name)
# Always return a non-NULL pointer like some EGL implementations do.
file.write(' return reinterpret_cast<void*>(&MockInvalidFunction);\n')
- file.write('}\n');
+ file.write('}\n')
file.write('\n')
file.write('} // namespace gfx\n')
@@ -1719,65 +1919,54 @@ def LooksLikeExtensionFunction(function):
return vendor is not None and not vendor.group(1) in ['GL', 'API', 'DC']
-def GetUsedExtensionFunctions(functions, extension_headers, extra_extensions):
- """Determine which functions belong to extensions.
+def FillExtensionsFromHeaders(functions, extension_headers, extra_extensions):
+ """Determine which functions belong to extensions based on extension headers,
+ and fill in this information to the functions table for functions that don't
+ already have the information.
Args:
- functions: List of (return type, function names, arguments).
+ functions: List of (return type, function versions, arguments).
extension_headers: List of header file names.
+ extra_extensions: Extensions to add to the list.
Returns:
- List of (extension name, [function name alternatives]) sorted with least
- preferred extensions first.
+ Set of used extensions.
"""
# Parse known extensions.
extensions = GetExtensionFunctions(extension_headers)
functions_to_extensions = GetFunctionToExtensionMap(extensions)
- # Collect all used extension functions.
- used_extension_functions = collections.defaultdict(lambda: [])
+ # Fill in the extension information.
+ used_extensions = set()
for func in functions:
- for name in func['names']:
- # Make sure we know about all extension functions.
- if (LooksLikeExtensionFunction(name) and
- not name in functions_to_extensions):
+ for version in func['versions']:
+ name = version['name']
+ # Make sure we know about all extensions and extension functions.
+ if 'extensions' in version:
+ used_extensions.update(version['extensions'])
+ elif name in functions_to_extensions:
+ # If there are multiple versions with the same name, assume that they
+ # already have all the correct conditions, we can't just blindly add
+ # the same extension conditions to all of them
+ if len([v for v in func['versions'] if v['name'] == name]) == 1:
+ version['extensions'] = functions_to_extensions[name]
+ used_extensions.update(version['extensions'])
+ elif LooksLikeExtensionFunction(name):
raise RuntimeError('%s looks like an extension function but does not '
'belong to any of the known extensions.' % name)
- if name in functions_to_extensions:
- extensions = functions_to_extensions[name][:]
- if 'other_extensions' in func:
- extensions.extend(func['other_extensions'])
- for extension in extensions:
- used_extension_functions[extension].append((func['names'][0], name))
# Add extensions that do not have any functions.
- used_extension_functions.update(dict(
- [(e, []) for e in extra_extensions if e not in used_extension_functions]))
+ used_extensions.update(extra_extensions)
- def ExtensionSortKey(name):
- # Prefer ratified extensions and EXTs.
- preferences = ['_ARB_', '_OES_', '_EXT_', '']
- for i, category in enumerate(preferences):
- if category in name:
- return -i
- used_extension_functions = sorted(used_extension_functions.items(),
- key = lambda item: ExtensionSortKey(item[0]))
- return used_extension_functions
+ return used_extensions
def ResolveHeader(header, header_paths):
paths = header_paths.split(':')
- # Always use a path for Chromium-specific extensions. They are extracted
- # to separate files.
- paths.append('.')
- paths.append('../../gpu')
-
- root = os.path.abspath(os.path.dirname(__file__))
-
for path in paths:
result = os.path.join(path, header)
if not os.path.isabs(path):
- result = os.path.relpath(os.path.join(root, result), os.getcwd())
+ result = os.path.relpath(os.path.join(os.getcwd(), result), os.getcwd())
if os.path.exists(result):
# Always use forward slashes as path separators. Otherwise backslashes
# may be incorrectly interpreted as escape characters.
@@ -1801,47 +1990,59 @@ def main(argv):
print ResolveHeader(header, options.header_paths)
return 0
+ directory = '.'
if len(args) >= 1:
- dir = args[0]
- else:
- dir = '.'
+ directory = args[0]
for [functions, set_name, extension_headers, extensions] in FUNCTION_SETS:
+ # Function names can be specified in two ways (list of unique names or list
+ # of versions with different binding conditions). Fill in the data to the
+ # versions list in case it is missing, so that can be used from here on:
+ for func in functions:
+ assert 'versions' in func or 'names' in func, 'Function with no names'
+ if 'versions' not in func:
+ func['versions'] = [{'name': n} for n in func['names']]
+ # Use the first version's name unless otherwise specified
+ if 'known_as' not in func:
+ func['known_as'] = func['versions'][0]['name']
+ # Make sure that 'names' is not accidentally used instead of 'versions'
+ if 'names' in func:
+ del func['names']
+
extension_headers = [ResolveHeader(h, options.header_paths)
for h in extension_headers]
- used_extension_functions = GetUsedExtensionFunctions(
+ used_extensions = FillExtensionsFromHeaders(
functions, extension_headers, extensions)
header_file = open(
- os.path.join(dir, 'gl_bindings_autogen_%s.h' % set_name), 'wb')
- GenerateHeader(header_file, functions, set_name, used_extension_functions)
+ os.path.join(directory, 'gl_bindings_autogen_%s.h' % set_name), 'wb')
+ GenerateHeader(header_file, functions, set_name, used_extensions)
header_file.close()
header_file = open(
- os.path.join(dir, 'gl_bindings_api_autogen_%s.h' % set_name), 'wb')
- GenerateAPIHeader(
- header_file, functions, set_name, used_extension_functions)
+ os.path.join(directory, 'gl_bindings_api_autogen_%s.h' % set_name),
+ 'wb')
+ GenerateAPIHeader(header_file, functions, set_name)
header_file.close()
source_file = open(
- os.path.join(dir, 'gl_bindings_autogen_%s.cc' % set_name), 'wb')
- GenerateSource(source_file, functions, set_name, used_extension_functions)
+ os.path.join(directory, 'gl_bindings_autogen_%s.cc' % set_name), 'wb')
+ GenerateSource(source_file, functions, set_name, used_extensions)
source_file.close()
- header_file = open(
- os.path.join(dir, 'gl_interface_autogen_%s.h' % set_name), 'wb')
- GenerateInterfaceHeader(
- header_file, functions, set_name, used_extension_functions)
- header_file.close()
+ header_file = open(
+ os.path.join(directory, 'gl_mock_autogen_gl.h'), 'wb')
+ GenerateMockHeader(header_file, GL_FUNCTIONS, 'gl')
+ header_file.close()
- header_file = open(
- os.path.join(dir, 'gl_mock_autogen_%s.h' % set_name), 'wb')
- GenerateMockHeader(
- header_file, functions, set_name, used_extension_functions)
- header_file.close()
+ header_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.h'),
+ 'wb')
+ GenerateMockBindingsHeader(header_file, GL_FUNCTIONS)
+ header_file.close()
- source_file = open(os.path.join(dir, 'gl_bindings_autogen_mock.cc'), 'wb')
- GenerateMockSource(source_file, GL_FUNCTIONS)
+ source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
+ 'wb')
+ GenerateMockBindingsSource(source_file, GL_FUNCTIONS)
source_file.close()
return 0
diff --git a/chromium/ui/gl/gl.gyp b/chromium/ui/gl/gl.gyp
index da89782ced7..59e82a6e339 100644
--- a/chromium/ui/gl/gl.gyp
+++ b/chromium/ui/gl/gl.gyp
@@ -19,6 +19,7 @@
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/third_party/mesa/mesa.gyp:mesa_headers',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
],
'variables': {
'gl_binding_output_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/gl',
@@ -28,6 +29,7 @@
],
'include_dirs': [
'<(DEPTH)/third_party/swiftshader/include',
+ '<(DEPTH)/third_party/khronos',
'<(DEPTH)/third_party/mesa/src/include',
'<(gl_binding_output_dir)',
],
@@ -39,7 +41,7 @@
'export_dependent_settings': [
'<(DEPTH)/third_party/mesa/mesa.gyp:mesa_headers',
],
- 'sources': [
+ 'sources': [
'android/gl_jni_registrar.cc',
'android/gl_jni_registrar.h',
'android/scoped_java_surface.cc',
@@ -48,6 +50,8 @@
'android/surface_texture.h',
'android/surface_texture_listener.cc',
'android/surface_texture_listener.h',
+ 'android/surface_texture_tracker.cc',
+ 'android/surface_texture_tracker.h',
'gl_bindings.h',
'gl_bindings_skia_in_process.cc',
'gl_bindings_skia_in_process.h',
@@ -60,6 +64,8 @@
'gl_context_osmesa.h',
'gl_context_stub.cc',
'gl_context_stub.h',
+ 'gl_context_stub_with_extensions.cc',
+ 'gl_context_stub_with_extensions.h',
'gl_context_win.cc',
'gl_context_x11.cc',
'gl_export.h',
@@ -81,14 +87,10 @@
'gl_implementation.cc',
'gl_implementation.h',
'gl_implementation_android.cc',
- 'gl_implementation_linux.cc',
- 'gl_implementation_linux.h',
'gl_implementation_ozone.cc',
'gl_implementation_mac.cc',
'gl_implementation_win.cc',
'gl_implementation_x11.cc',
- 'gl_interface.cc',
- 'gl_interface.h',
'gl_osmesa_api_implementation.cc',
'gl_osmesa_api_implementation.h',
'gl_share_group.cc',
@@ -97,6 +99,7 @@
'gl_state_restorer.h',
'gl_surface.cc',
'gl_surface.h',
+ 'gl_surface_android.cc',
'gl_surface_mac.cc',
'gl_surface_stub.cc',
'gl_surface_stub.h',
@@ -104,12 +107,13 @@
'gl_surface_x11.cc',
'gl_surface_osmesa.cc',
'gl_surface_osmesa.h',
+ 'gl_surface_ozone.cc',
'gl_switches.cc',
'gl_switches.h',
+ 'gl_version_info.cc',
+ 'gl_version_info.h',
'gpu_switching_manager.cc',
'gpu_switching_manager.h',
- 'io_surface_support_mac.cc',
- 'io_surface_support_mac.h',
'scoped_binders.cc',
'scoped_binders.h',
'scoped_make_current.cc',
@@ -118,10 +122,8 @@
'sync_control_vsync_provider.h',
'<(gl_binding_output_dir)/gl_bindings_autogen_gl.cc',
'<(gl_binding_output_dir)/gl_bindings_autogen_gl.h',
- '<(gl_binding_output_dir)/gl_bindings_autogen_mock.cc',
'<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.cc',
'<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_gl.h',
],
# hard_dependency is necessary for this target because it has actions
# that generate header files included by dependent targets. The header
@@ -134,7 +136,7 @@
'variables': {
'generator_path': 'generate_bindings.py',
# Prefer khronos EGL/GLES headers by listing that path first.
- 'header_paths': '../../third_party/khronos:../../third_party/mesa/src/include',
+ 'header_paths': '../../third_party/khronos:../../third_party/mesa/src/include:.:../../gpu',
},
'inputs': [
'<(generator_path)',
@@ -151,22 +153,14 @@
'<(gl_binding_output_dir)/gl_bindings_autogen_glx.h',
'<(gl_binding_output_dir)/gl_bindings_api_autogen_glx.h',
'<(gl_binding_output_dir)/gl_bindings_autogen_mock.cc',
+ '<(gl_binding_output_dir)/gl_bindings_autogen_mock.h',
'<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.cc',
'<(gl_binding_output_dir)/gl_bindings_autogen_osmesa.h',
'<(gl_binding_output_dir)/gl_bindings_api_autogen_osmesa.h',
'<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc',
'<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h',
'<(gl_binding_output_dir)/gl_bindings_api_autogen_wgl.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_egl.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_gl.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_glx.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_osmesa.h',
- '<(gl_binding_output_dir)/gl_interface_autogen_wgl.h',
- '<(gl_binding_output_dir)/gl_mock_autogen_egl.h',
'<(gl_binding_output_dir)/gl_mock_autogen_gl.h',
- '<(gl_binding_output_dir)/gl_mock_autogen_glx.h',
- '<(gl_binding_output_dir)/gl_mock_autogen_osmesa.h',
- '<(gl_binding_output_dir)/gl_mock_autogen_wgl.h',
],
'action': [
'python',
@@ -183,6 +177,8 @@
'egl_util.h',
'gl_context_egl.cc',
'gl_context_egl.h',
+ 'gl_image_egl.cc',
+ 'gl_image_egl.h',
'gl_surface_egl.cc',
'gl_surface_egl.h',
'gl_egl_api_implementation.cc',
@@ -194,6 +190,12 @@
'<(DEPTH)/third_party/khronos',
],
}],
+ ['OS in ("android", "linux")', {
+ 'sources': [
+ 'gl_implementation_osmesa.cc',
+ 'gl_implementation_osmesa.h',
+ ],
+ }],
['use_x11 == 1', {
'sources': [
'gl_context_glx.cc',
@@ -214,12 +216,13 @@
'GL_GLEXT_PROTOTYPES',
],
},
- 'link_settings': {
- 'libraries': [
- '-lX11',
- '-lXcomposite',
- ],
- },
+ 'dependencies': [
+ '<(DEPTH)/build/linux/system.gyp:x11',
+ '<(DEPTH)/build/linux/system.gyp:xcomposite',
+ '<(DEPTH)/build/linux/system.gyp:xext',
+ '<(DEPTH)/ui/events/platform/events_platform.gyp:events_platform',
+ '<(DEPTH)/ui/gfx/x/gfx_x11.gyp:gfx_x11',
+ ],
}],
['OS=="win"', {
'sources': [
@@ -256,15 +259,12 @@
'gl_context_cgl.h',
'gl_image_io_surface.cc',
'gl_image_io_surface.h',
- 'gl_surface_cgl.cc',
- 'gl_surface_cgl.h',
- 'gl_context_nsview.mm',
- 'gl_context_nsview.h',
- 'gl_surface_nsview.mm',
- 'gl_surface_nsview.h',
+ 'scoped_cgl.cc',
+ 'scoped_cgl.h',
],
'link_settings': {
'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/IOSurface.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
],
},
@@ -274,8 +274,10 @@
'gl_jni_headers',
],
'sources': [
- 'gl_image_egl.cc',
- 'gl_image_egl.h',
+ 'gl_image_android_native_buffer.cc',
+ 'gl_image_android_native_buffer.h',
+ 'gl_image_surface_texture.cc',
+ 'gl_image_surface_texture.h',
],
'link_settings': {
'libraries': [
@@ -283,7 +285,6 @@
],
},
'sources!': [
- 'gl_context_osmesa.cc',
'system_monitor_posix.cc',
],
'defines': [
@@ -299,6 +300,11 @@
'../ozone/ozone.gyp:ozone',
],
}],
+ ['OS=="android" and android_webview_build==0', {
+ 'dependencies': [
+ '../android/ui_android.gyp:ui_java',
+ ],
+ }],
],
},
{
@@ -324,6 +330,8 @@
'sources': [
'gl_mock.h',
'gl_mock.cc',
+ '<(gl_binding_output_dir)/gl_bindings_autogen_mock.cc',
+ '<(gl_binding_output_dir)/gl_bindings_autogen_mock.h',
'<(gl_binding_output_dir)/gl_mock_autogen_gl.h',
],
},
@@ -337,7 +345,6 @@
'variables': {
'jni_gen_package': 'ui/gl',
'input_java_class': 'android/view/Surface.class',
- 'jni_generator_ptr_type': 'long',
},
'includes': [ '../../build/jar_file_jni_generator.gypi' ],
},
@@ -353,7 +360,6 @@
],
'variables': {
'jni_gen_package': 'ui/gl',
- 'jni_generator_ptr_type': 'long',
},
'includes': [ '../../build/jni_generator.gypi' ],
},
diff --git a/chromium/ui/gl/gl_bindings.h b/chromium/ui/gl/gl_bindings.h
index debb0748046..23182bce17b 100644
--- a/chromium/ui/gl/gl_bindings.h
+++ b/chromium/ui/gl/gl_bindings.h
@@ -74,6 +74,7 @@
#define GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM 0x9241
#define GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM 0x9242
#define GL_UNPACK_COLORSPACE_CONVERSION_CHROMIUM 0x9243
+#define GL_BIND_GENERATES_RESOURCE_CHROMIUM 0x9244
// GL_CHROMIUM_gpu_memory_manager
#define GL_TEXTURE_POOL_CHROMIUM 0x6000
@@ -127,6 +128,14 @@
#define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x84F5
#define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x84F6
+// GL_CHROMIUM_sync_query
+#define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7
+
+// GL_CHROMIUM_image
+#define GL_IMAGE_ROWBYTES_CHROMIUM 0x78F0
+#define GL_IMAGE_MAP_CHROMIUM 0x78F1
+#define GL_IMAGE_SCANOUT_CHROMIUM 0x78F2
+
// GL_OES_texure_3D
#define GL_SAMPLER_3D_OES 0x8B5F
@@ -148,6 +157,17 @@
// GL_OES_compressed_ETC1_RGB8_texture
#define GL_ETC1_RGB8_OES 0x8D64
+// GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+
+// GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+
// GL_OES_vertex_array_object
#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
@@ -225,28 +245,30 @@ typedef uint64 EGLuint64CHROMIUM;
namespace gfx {
struct GL_EXPORT DriverGL {
- void Initialize();
- void InitializeExtensions(GLContext* context);
+ void InitializeStaticBindings();
+ void InitializeCustomDynamicBindings(GLContext* context);
void InitializeDebugBindings();
+ void InitializeNullDrawBindings();
+ // TODO(danakj): Remove this when all test suites are using null-draw.
+ bool HasInitializedNullDrawBindings();
+ bool SetNullDrawBindingsEnabled(bool enabled);
void ClearBindings();
- void UpdateDebugExtensionBindings();
ProcsGL fn;
ProcsGL orig_fn;
ProcsGL debug_fn;
ExtensionsGL ext;
+ bool null_draw_bindings_enabled;
private:
- void InitializeBindings();
- void InitializeExtensionBindings(GLContext* context);
+ void InitializeDynamicBindings(GLContext* context);
};
struct GL_EXPORT DriverOSMESA {
- void InitializeBindings();
- void InitializeExtensionBindings(GLContext* context);
+ void InitializeStaticBindings();
+ void InitializeDynamicBindings(GLContext* context);
void InitializeDebugBindings();
void ClearBindings();
- void UpdateDebugExtensionBindings();
ProcsOSMESA fn;
ProcsOSMESA debug_fn;
@@ -255,11 +277,10 @@ struct GL_EXPORT DriverOSMESA {
#if defined(OS_WIN)
struct GL_EXPORT DriverWGL {
- void InitializeBindings();
- void InitializeExtensionBindings(GLContext* context);
+ void InitializeStaticBindings();
+ void InitializeDynamicBindings(GLContext* context);
void InitializeDebugBindings();
void ClearBindings();
- void UpdateDebugExtensionBindings();
ProcsWGL fn;
ProcsWGL debug_fn;
@@ -269,11 +290,10 @@ struct GL_EXPORT DriverWGL {
#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || defined(USE_OZONE)
struct GL_EXPORT DriverEGL {
- void InitializeBindings();
- void InitializeExtensionBindings(GLContext* context);
+ void InitializeStaticBindings();
+ void InitializeDynamicBindings(GLContext* context);
void InitializeDebugBindings();
void ClearBindings();
- void UpdateDebugExtensionBindings();
ProcsEGL fn;
ProcsEGL debug_fn;
@@ -283,11 +303,10 @@ struct GL_EXPORT DriverEGL {
#if defined(USE_X11)
struct GL_EXPORT DriverGLX {
- void InitializeBindings();
- void InitializeExtensionBindings(GLContext* context);
+ void InitializeStaticBindings();
+ void InitializeDynamicBindings(GLContext* context);
void InitializeDebugBindings();
void ClearBindings();
- void UpdateDebugExtensionBindings();
ProcsGLX fn;
ProcsGLX debug_fn;
@@ -329,9 +348,6 @@ GL_EXPORT extern DriverEGL g_driver_egl;
#endif
-// Find an entry point to the mock GL implementation.
-void* GL_BINDING_CALL GetMockGLProcAddress(const char* name);
-
} // namespace gfx
#endif // UI_GL_GL_BINDINGS_H_
diff --git a/chromium/ui/gl/gl_bindings_skia_in_process.cc b/chromium/ui/gl/gl_bindings_skia_in_process.cc
index 9c2cea6a07e..0e2dfe56ba4 100644
--- a/chromium/ui/gl/gl_bindings_skia_in_process.cc
+++ b/chromium/ui/gl/gl_bindings_skia_in_process.cc
@@ -187,6 +187,11 @@ GLvoid StubGLDisableVertexAttribArray(GLuint index) {
glDisableVertexAttribArray(index);
}
+GLvoid StubGLDiscardFramebuffer(GLenum target, GLsizei numAttachments,
+ const GLenum *attachments) {
+ glDiscardFramebufferEXT(target, numAttachments, attachments);
+}
+
GLvoid StubGLDrawArrays(GLenum mode, GLint first, GLsizei count) {
glDrawArrays(mode, first, count);
}
@@ -346,6 +351,10 @@ GLint StubGLGetUniformLocation(GLuint program, const char* name) {
return glGetUniformLocation(program, name);
}
+GLvoid StubGLInsertEventMarker(GLsizei length, const char* marker) {
+ glInsertEventMarkerEXT(length, marker);
+}
+
GLvoid StubGLLineWidth(GLfloat width) {
glLineWidth(width);
}
@@ -362,6 +371,14 @@ GLvoid StubGLPixelStorei(GLenum pname, GLint param) {
glPixelStorei(pname, param);
}
+GLvoid StubGLPopGroupMarker() {
+ glPopGroupMarkerEXT();
+}
+
+GLvoid StubGLPushGroupMarker(GLsizei length, const char* marker) {
+ glPushGroupMarkerEXT(length, marker);
+}
+
GLvoid StubGLQueryCounter(GLuint id, GLenum target) {
glQueryCounter(id, target);
}
@@ -557,20 +574,20 @@ GLvoid StubGLViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
namespace gfx {
GrGLInterface* CreateInProcessSkiaGLBinding() {
- GrGLBinding binding;
+ GrGLStandard standard;
switch (gfx::GetGLImplementation()) {
case gfx::kGLImplementationNone:
NOTREACHED();
return NULL;
case gfx::kGLImplementationDesktopGL:
case gfx::kGLImplementationAppleGL:
- binding = kDesktop_GrGLBinding;
+ standard = kGL_GrGLStandard;
break;
case gfx::kGLImplementationOSMesaGL:
- binding = kDesktop_GrGLBinding;
+ standard = kGL_GrGLStandard;
break;
case gfx::kGLImplementationEGLGLES2:
- binding = kES2_GrGLBinding;
+ standard = kGLES_GrGLStandard;
break;
case gfx::kGLImplementationMockGL:
NOTREACHED();
@@ -581,132 +598,142 @@ GrGLInterface* CreateInProcessSkiaGLBinding() {
}
GrGLInterface* interface = new GrGLInterface;
-
- interface->fBindingsExported = binding;
- interface->fActiveTexture = StubGLActiveTexture;
- interface->fAttachShader = StubGLAttachShader;
- interface->fBeginQuery = StubGLBeginQuery;
- interface->fBindAttribLocation = StubGLBindAttribLocation;
- interface->fBindBuffer = StubGLBindBuffer;
- interface->fBindFragDataLocation = StubGLBindFragDataLocation;
- interface->fBindTexture = StubGLBindTexture;
- interface->fBindVertexArray = StubGLBindVertexArray;
- interface->fBlendColor = StubGLBlendColor;
- interface->fBlendFunc = StubGLBlendFunc;
- interface->fBufferData = StubGLBufferData;
- interface->fBufferSubData = StubGLBufferSubData;
- interface->fClear = StubGLClear;
- interface->fClearColor = StubGLClearColor;
- interface->fClearStencil = StubGLClearStencil;
- interface->fColorMask = StubGLColorMask;
- interface->fCompileShader = StubGLCompileShader;
- interface->fCompressedTexImage2D = StubGLCompressedTexImage2D;
- interface->fCopyTexSubImage2D = StubGLCopyTexSubImage2D;
- interface->fCreateProgram = StubGLCreateProgram;
- interface->fCreateShader = StubGLCreateShader;
- interface->fCullFace = StubGLCullFace;
- interface->fDeleteBuffers = StubGLDeleteBuffers;
- interface->fDeleteProgram = StubGLDeleteProgram;
- interface->fDeleteQueries = StubGLDeleteQueries;
- interface->fDeleteShader = StubGLDeleteShader;
- interface->fDeleteTextures = StubGLDeleteTextures;
- interface->fDeleteVertexArrays = StubGLDeleteVertexArrays;
- interface->fDepthMask = StubGLDepthMask;
- interface->fDisable = StubGLDisable;
- interface->fDisableVertexAttribArray = StubGLDisableVertexAttribArray;
- interface->fDrawArrays = StubGLDrawArrays;
- interface->fDrawBuffer = StubGLDrawBuffer;
- interface->fDrawBuffers = StubGLDrawBuffers;
- interface->fDrawElements = StubGLDrawElements;
- interface->fEnable = StubGLEnable;
- interface->fEnableVertexAttribArray = StubGLEnableVertexAttribArray;
- interface->fEndQuery = StubGLEndQuery;
- interface->fFinish = StubGLFinish;
- interface->fFlush = StubGLFlush;
- interface->fFrontFace = StubGLFrontFace;
- interface->fGenBuffers = StubGLGenBuffers;
- interface->fGenQueries = StubGLGenQueries;
- interface->fGenTextures = StubGLGenTextures;
- interface->fGenVertexArrays = StubGLGenVertexArrays;
- interface->fGetBufferParameteriv = StubGLGetBufferParameteriv;
- interface->fGetError = StubGLGetError;
- interface->fGetIntegerv = StubGLGetIntegerv;
- interface->fGetQueryiv = StubGLGetQueryiv;
- interface->fGetQueryObjecti64v = StubGLGetQueryObjecti64v;
- interface->fGetQueryObjectiv = StubGLGetQueryObjectiv;
- interface->fGetQueryObjectui64v = StubGLGetQueryObjectui64v;
- interface->fGetQueryObjectuiv = StubGLGetQueryObjectuiv;
- interface->fGetProgramInfoLog = StubGLGetProgramInfoLog;
- interface->fGetProgramiv = StubGLGetProgramiv;
- interface->fGetShaderInfoLog = StubGLGetShaderInfoLog;
- interface->fGetShaderiv = StubGLGetShaderiv;
- interface->fGetString = StubGLGetString;
- interface->fGetTexLevelParameteriv = StubGLGetTexLevelParameteriv;
- interface->fGetUniformLocation = StubGLGetUniformLocation;
- interface->fLineWidth = StubGLLineWidth;
- interface->fLinkProgram = StubGLLinkProgram;
- interface->fPixelStorei = StubGLPixelStorei;
- interface->fQueryCounter = StubGLQueryCounter;
- interface->fReadBuffer = StubGLReadBuffer;
- interface->fReadPixels = StubGLReadPixels;
- interface->fScissor = StubGLScissor;
- interface->fShaderSource = StubGLShaderSource;
- interface->fStencilFunc = StubGLStencilFunc;
- interface->fStencilFuncSeparate = StubGLStencilFuncSeparate;
- interface->fStencilMask = StubGLStencilMask;
- interface->fStencilMaskSeparate = StubGLStencilMaskSeparate;
- interface->fStencilOp = StubGLStencilOp;
- interface->fStencilOpSeparate = StubGLStencilOpSeparate;
- interface->fTexImage2D = StubGLTexImage2D;
- interface->fTexParameteri = StubGLTexParameteri;
- interface->fTexParameteriv = StubGLTexParameteriv;
- interface->fTexSubImage2D = StubGLTexSubImage2D;
- interface->fTexStorage2D = StubGLTexStorage2D;
- interface->fUniform1f = StubGLUniform1f;
- interface->fUniform1i = StubGLUniform1i;
- interface->fUniform1fv = StubGLUniform1fv;
- interface->fUniform1iv = StubGLUniform1iv;
- interface->fUniform2f = StubGLUniform2f;
- interface->fUniform2i = StubGLUniform2i;
- interface->fUniform2fv = StubGLUniform2fv;
- interface->fUniform2iv = StubGLUniform2iv;
- interface->fUniform3f = StubGLUniform3f;
- interface->fUniform3i = StubGLUniform3i;
- interface->fUniform3fv = StubGLUniform3fv;
- interface->fUniform3iv = StubGLUniform3iv;
- interface->fUniform4f = StubGLUniform4f;
- interface->fUniform4i = StubGLUniform4i;
- interface->fUniform4fv = StubGLUniform4fv;
- interface->fUniform4iv = StubGLUniform4iv;
- interface->fUniformMatrix2fv = StubGLUniformMatrix2fv;
- interface->fUniformMatrix3fv = StubGLUniformMatrix3fv;
- interface->fUniformMatrix4fv = StubGLUniformMatrix4fv;
- interface->fUseProgram = StubGLUseProgram;
- interface->fVertexAttrib4fv = StubGLVertexAttrib4fv;
- interface->fVertexAttribPointer = StubGLVertexAttribPointer;
- interface->fViewport = StubGLViewport;
- interface->fBindFramebuffer = StubGLBindFramebuffer;
- interface->fBindRenderbuffer = StubGLBindRenderbuffer;
- interface->fCheckFramebufferStatus = StubGLCheckFramebufferStatus;
- interface->fDeleteFramebuffers = StubGLDeleteFramebuffers;
- interface->fDeleteRenderbuffers = StubGLDeleteRenderbuffers;
- interface->fFramebufferRenderbuffer = StubGLFramebufferRenderbuffer;
- interface->fFramebufferTexture2D = StubGLFramebufferTexture2D;
- interface->fFramebufferTexture2DMultisample =
+ interface->fStandard = standard;
+ interface->fExtensions.init(standard,
+ StubGLGetString,
+ NULL,
+ StubGLGetIntegerv);
+
+ GrGLInterface::Functions* functions = &interface->fFunctions;
+ functions->fActiveTexture = StubGLActiveTexture;
+ functions->fAttachShader = StubGLAttachShader;
+ functions->fBeginQuery = StubGLBeginQuery;
+ functions->fBindAttribLocation = StubGLBindAttribLocation;
+ functions->fBindBuffer = StubGLBindBuffer;
+ functions->fBindFragDataLocation = StubGLBindFragDataLocation;
+ functions->fBindTexture = StubGLBindTexture;
+ functions->fBindVertexArray = StubGLBindVertexArray;
+ functions->fBlendColor = StubGLBlendColor;
+ functions->fBlendFunc = StubGLBlendFunc;
+ functions->fBufferData = StubGLBufferData;
+ functions->fBufferSubData = StubGLBufferSubData;
+ functions->fClear = StubGLClear;
+ functions->fClearColor = StubGLClearColor;
+ functions->fClearStencil = StubGLClearStencil;
+ functions->fColorMask = StubGLColorMask;
+ functions->fCompileShader = StubGLCompileShader;
+ functions->fCompressedTexImage2D = StubGLCompressedTexImage2D;
+ functions->fCopyTexSubImage2D = StubGLCopyTexSubImage2D;
+ functions->fCreateProgram = StubGLCreateProgram;
+ functions->fCreateShader = StubGLCreateShader;
+ functions->fCullFace = StubGLCullFace;
+ functions->fDeleteBuffers = StubGLDeleteBuffers;
+ functions->fDeleteProgram = StubGLDeleteProgram;
+ functions->fDeleteQueries = StubGLDeleteQueries;
+ functions->fDeleteShader = StubGLDeleteShader;
+ functions->fDeleteTextures = StubGLDeleteTextures;
+ functions->fDeleteVertexArrays = StubGLDeleteVertexArrays;
+ functions->fDepthMask = StubGLDepthMask;
+ functions->fDisable = StubGLDisable;
+ functions->fDisableVertexAttribArray = StubGLDisableVertexAttribArray;
+ functions->fDiscardFramebuffer = StubGLDiscardFramebuffer;
+ functions->fDrawArrays = StubGLDrawArrays;
+ functions->fDrawBuffer = StubGLDrawBuffer;
+ functions->fDrawBuffers = StubGLDrawBuffers;
+ functions->fDrawElements = StubGLDrawElements;
+ functions->fEnable = StubGLEnable;
+ functions->fEnableVertexAttribArray = StubGLEnableVertexAttribArray;
+ functions->fEndQuery = StubGLEndQuery;
+ functions->fFinish = StubGLFinish;
+ functions->fFlush = StubGLFlush;
+ functions->fFrontFace = StubGLFrontFace;
+ functions->fGenBuffers = StubGLGenBuffers;
+ functions->fGenQueries = StubGLGenQueries;
+ functions->fGenTextures = StubGLGenTextures;
+ functions->fGenVertexArrays = StubGLGenVertexArrays;
+ functions->fGetBufferParameteriv = StubGLGetBufferParameteriv;
+ functions->fGetError = StubGLGetError;
+ functions->fGetIntegerv = StubGLGetIntegerv;
+ functions->fGetQueryiv = StubGLGetQueryiv;
+ functions->fGetQueryObjecti64v = StubGLGetQueryObjecti64v;
+ functions->fGetQueryObjectiv = StubGLGetQueryObjectiv;
+ functions->fGetQueryObjectui64v = StubGLGetQueryObjectui64v;
+ functions->fGetQueryObjectuiv = StubGLGetQueryObjectuiv;
+ functions->fGetProgramInfoLog = StubGLGetProgramInfoLog;
+ functions->fGetProgramiv = StubGLGetProgramiv;
+ functions->fGetShaderInfoLog = StubGLGetShaderInfoLog;
+ functions->fGetShaderiv = StubGLGetShaderiv;
+ functions->fGetString = StubGLGetString;
+ functions->fGetTexLevelParameteriv = StubGLGetTexLevelParameteriv;
+ functions->fGetUniformLocation = StubGLGetUniformLocation;
+ functions->fInsertEventMarker = StubGLInsertEventMarker;
+ functions->fLineWidth = StubGLLineWidth;
+ functions->fLinkProgram = StubGLLinkProgram;
+ functions->fPixelStorei = StubGLPixelStorei;
+ functions->fPopGroupMarker = StubGLPopGroupMarker;
+ functions->fPushGroupMarker = StubGLPushGroupMarker;
+ functions->fQueryCounter = StubGLQueryCounter;
+ functions->fReadBuffer = StubGLReadBuffer;
+ functions->fReadPixels = StubGLReadPixels;
+ functions->fScissor = StubGLScissor;
+ functions->fShaderSource = StubGLShaderSource;
+ functions->fStencilFunc = StubGLStencilFunc;
+ functions->fStencilFuncSeparate = StubGLStencilFuncSeparate;
+ functions->fStencilMask = StubGLStencilMask;
+ functions->fStencilMaskSeparate = StubGLStencilMaskSeparate;
+ functions->fStencilOp = StubGLStencilOp;
+ functions->fStencilOpSeparate = StubGLStencilOpSeparate;
+ functions->fTexImage2D = StubGLTexImage2D;
+ functions->fTexParameteri = StubGLTexParameteri;
+ functions->fTexParameteriv = StubGLTexParameteriv;
+ functions->fTexSubImage2D = StubGLTexSubImage2D;
+ functions->fTexStorage2D = StubGLTexStorage2D;
+ functions->fUniform1f = StubGLUniform1f;
+ functions->fUniform1i = StubGLUniform1i;
+ functions->fUniform1fv = StubGLUniform1fv;
+ functions->fUniform1iv = StubGLUniform1iv;
+ functions->fUniform2f = StubGLUniform2f;
+ functions->fUniform2i = StubGLUniform2i;
+ functions->fUniform2fv = StubGLUniform2fv;
+ functions->fUniform2iv = StubGLUniform2iv;
+ functions->fUniform3f = StubGLUniform3f;
+ functions->fUniform3i = StubGLUniform3i;
+ functions->fUniform3fv = StubGLUniform3fv;
+ functions->fUniform3iv = StubGLUniform3iv;
+ functions->fUniform4f = StubGLUniform4f;
+ functions->fUniform4i = StubGLUniform4i;
+ functions->fUniform4fv = StubGLUniform4fv;
+ functions->fUniform4iv = StubGLUniform4iv;
+ functions->fUniformMatrix2fv = StubGLUniformMatrix2fv;
+ functions->fUniformMatrix3fv = StubGLUniformMatrix3fv;
+ functions->fUniformMatrix4fv = StubGLUniformMatrix4fv;
+ functions->fUseProgram = StubGLUseProgram;
+ functions->fVertexAttrib4fv = StubGLVertexAttrib4fv;
+ functions->fVertexAttribPointer = StubGLVertexAttribPointer;
+ functions->fViewport = StubGLViewport;
+ functions->fBindFramebuffer = StubGLBindFramebuffer;
+ functions->fBindRenderbuffer = StubGLBindRenderbuffer;
+ functions->fCheckFramebufferStatus = StubGLCheckFramebufferStatus;
+ functions->fDeleteFramebuffers = StubGLDeleteFramebuffers;
+ functions->fDeleteRenderbuffers = StubGLDeleteRenderbuffers;
+ functions->fFramebufferRenderbuffer = StubGLFramebufferRenderbuffer;
+ functions->fFramebufferTexture2D = StubGLFramebufferTexture2D;
+ functions->fFramebufferTexture2DMultisample =
StubGLFramebufferTexture2DMultisample;
- interface->fGenFramebuffers = StubGLGenFramebuffers;
- interface->fGenRenderbuffers = StubGLGenRenderbuffers;
- interface->fGetFramebufferAttachmentParameteriv =
+ functions->fGenFramebuffers = StubGLGenFramebuffers;
+ functions->fGenRenderbuffers = StubGLGenRenderbuffers;
+ functions->fGetFramebufferAttachmentParameteriv =
StubGLGetFramebufferAttachmentParameteriv;
- interface->fGetRenderbufferParameteriv = StubGLGetRenderbufferParameteriv;
- interface->fRenderbufferStorage = StubGLRenderbufferStorage;
- interface->fRenderbufferStorageMultisample =
+ functions->fGetRenderbufferParameteriv = StubGLGetRenderbufferParameteriv;
+ functions->fRenderbufferStorage = StubGLRenderbufferStorage;
+ functions->fRenderbufferStorageMultisample =
StubGLRenderbufferStorageMultisample;
- interface->fBlitFramebuffer = StubGLBlitFramebuffer;
- interface->fMapBuffer = StubGLMapBuffer;
- interface->fUnmapBuffer = StubGLUnmapBuffer;
- interface->fBindFragDataLocationIndexed =
+ functions->fBlitFramebuffer = StubGLBlitFramebuffer;
+ functions->fMapBuffer = StubGLMapBuffer;
+ functions->fUnmapBuffer = StubGLUnmapBuffer;
+ functions->fBindFragDataLocationIndexed =
StubGLBindFragDataLocationIndexed;
+
return interface;
}
diff --git a/chromium/ui/gl/gl_context.cc b/chromium/ui/gl/gl_context.cc
index 1bc4d122d1c..533b7d3146e 100644
--- a/chromium/ui/gl/gl_context.cc
+++ b/chromium/ui/gl/gl_context.cc
@@ -14,6 +14,7 @@
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_switches.h"
+#include "ui/gl/gl_version_info.h"
namespace gfx {
@@ -25,6 +26,32 @@ base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky
current_real_context_ = LAZY_INSTANCE_INITIALIZER;
} // namespace
+GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() : canceled_(false) {}
+
+GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() {
+ if (!canceled_ && GetCurrent()) {
+ GetCurrent()->ReleaseCurrent(NULL);
+ }
+}
+
+void GLContext::ScopedReleaseCurrent::Cancel() {
+ canceled_ = true;
+}
+
+GLContext::FlushEvent::FlushEvent() {
+}
+
+GLContext::FlushEvent::~FlushEvent() {
+}
+
+void GLContext::FlushEvent::Signal() {
+ flag_.Set();
+}
+
+bool GLContext::FlushEvent::IsSignaled() {
+ return flag_.IsSet();
+}
+
GLContext::GLContext(GLShareGroup* share_group) : share_group_(share_group) {
if (!share_group_.get())
share_group_ = new GLShareGroup;
@@ -39,6 +66,13 @@ GLContext::~GLContext() {
}
}
+scoped_refptr<GLContext::FlushEvent> GLContext::SignalFlush() {
+ DCHECK(IsCurrent(NULL));
+ scoped_refptr<FlushEvent> flush_event = new FlushEvent();
+ flush_events_.push_back(flush_event);
+ return flush_event;
+}
+
bool GLContext::GetTotalGpuMemory(size_t* bytes) {
DCHECK(bytes);
*bytes = 0;
@@ -58,6 +92,20 @@ std::string GLContext::GetExtensions() {
return std::string(ext ? ext : "");
}
+std::string GLContext::GetGLVersion() {
+ DCHECK(IsCurrent(NULL));
+ const char *version =
+ reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ return std::string(version ? version : "");
+}
+
+std::string GLContext::GetGLRenderer() {
+ DCHECK(IsCurrent(NULL));
+ const char *renderer =
+ reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ return std::string(renderer ? renderer : "");
+}
+
bool GLContext::HasExtension(const char* name) {
std::string extensions = GetExtensions();
extensions += " ";
@@ -68,6 +116,16 @@ bool GLContext::HasExtension(const char* name) {
return extensions.find(delimited_name) != std::string::npos;
}
+const GLVersionInfo* GLContext::GetVersionInfo() {
+ if(!version_info_) {
+ std::string version = GetGLVersion();
+ std::string renderer = GetGLRenderer();
+ version_info_ = scoped_ptr<GLVersionInfo>(
+ new GLVersionInfo(version.c_str(), renderer.c_str()));
+ }
+ return version_info_.get();
+}
+
GLShareGroup* GLContext::share_group() {
return share_group_.get();
}
@@ -100,6 +158,12 @@ GLContext* GLContext::GetRealCurrent() {
void GLContext::SetCurrent(GLSurface* surface) {
current_context_.Pointer()->Set(surface ? this : NULL);
GLSurface::SetCurrent(surface);
+ // Leave the real GL api current so that unit tests work correctly.
+ // TODO(sievers): Remove this, but needs all gpu_unittest classes
+ // to create and make current a context.
+ if (!surface && GetGLImplementation() != kGLImplementationMockGL) {
+ SetGLApiToNoContext();
+ }
}
GLStateRestorer* GLContext::GetGLStateRestorer() {
@@ -114,14 +178,14 @@ bool GLContext::WasAllocatedUsingRobustnessExtension() {
return false;
}
-bool GLContext::InitializeExtensionBindings() {
+bool GLContext::InitializeDynamicBindings() {
DCHECK(IsCurrent(NULL));
static bool initialized = false;
if (initialized)
return initialized;
- initialized = InitializeGLExtensionBindings(GetGLImplementation(), this);
+ initialized = InitializeDynamicGLBindings(GetGLImplementation(), this);
if (!initialized)
- LOG(ERROR) << "Could not initialize extension bindings.";
+ LOG(ERROR) << "Could not initialize dynamic bindings.";
return initialized;
}
@@ -147,6 +211,12 @@ void GLContext::SetRealGLApi() {
SetGLToRealGLApi();
}
+void GLContext::OnFlush() {
+ for (size_t n = 0; n < flush_events_.size(); n++)
+ flush_events_[n]->Signal();
+ flush_events_.clear();
+}
+
GLContextReal::GLContextReal(GLShareGroup* share_group)
: GLContext(share_group) {}
diff --git a/chromium/ui/gl/gl_context.h b/chromium/ui/gl/gl_context.h
index 3eb390fce5c..323b373347b 100644
--- a/chromium/ui/gl/gl_context.h
+++ b/chromium/ui/gl/gl_context.h
@@ -6,10 +6,12 @@
#define UI_GL_GL_CONTEXT_H_
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/cancellation_flag.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_state_restorer.h"
#include "ui/gl/gpu_preference.h"
@@ -18,6 +20,7 @@ namespace gfx {
class GLSurface;
class VirtualGLApi;
+struct GLVersionInfo;
// Encapsulates an OpenGL context, hiding platform specific management.
class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
@@ -31,6 +34,25 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
virtual bool Initialize(
GLSurface* compatible_surface, GpuPreference gpu_preference) = 0;
+ class FlushEvent : public base::RefCountedThreadSafe<FlushEvent> {
+ public:
+ bool IsSignaled();
+
+ private:
+ friend class base::RefCountedThreadSafe<FlushEvent>;
+ friend class GLContext;
+ FlushEvent();
+ virtual ~FlushEvent();
+ void Signal();
+
+ base::CancellationFlag flag_;
+ };
+
+ // Needs to be called with this context current. It will return a FlushEvent
+ // that is initially unsignaled, but will transition to signaled after the
+ // next glFlush() or glFinish() occurs in this context.
+ scoped_refptr<FlushEvent> SignalFlush();
+
// Destroys the GL context.
virtual void Destroy() = 0;
@@ -76,6 +98,10 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
// context must be current.
bool HasExtension(const char* name);
+ // Returns version info of the underlying GL context. The context must be
+ // current.
+ const GLVersionInfo* GetVersionInfo();
+
GLShareGroup* share_group();
// Create a GL context that is compatible with the given surface.
@@ -103,17 +129,38 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
// being released or destroyed.
void OnReleaseVirtuallyCurrent(GLContext* virtual_context);
+ // Returns the GL version string. The context must be current.
+ virtual std::string GetGLVersion();
+
+ // Returns the GL renderer string. The context must be current.
+ virtual std::string GetGLRenderer();
+
+ // Called when glFlush()/glFinish() is called with this context current.
+ void OnFlush();
+
protected:
virtual ~GLContext();
+ // Will release the current context when going out of scope, unless canceled.
+ class ScopedReleaseCurrent {
+ public:
+ ScopedReleaseCurrent();
+ ~ScopedReleaseCurrent();
+
+ void Cancel();
+
+ private:
+ bool canceled_;
+ };
+
// Sets the GL api to the real hardware API (vs the VirtualAPI)
static void SetRealGLApi();
virtual void SetCurrent(GLSurface* surface);
- // Initialize function pointers to extension functions in the GL
- // implementation. Should be called immediately after this context is made
- // current.
- bool InitializeExtensionBindings();
+ // Initialize function pointers to functions where the bound version depends
+ // on GL version or supported extensions. Should be called immediately after
+ // this context is made current.
+ bool InitializeDynamicBindings();
// Returns the last real (non-virtual) GLContext made current.
static GLContext* GetRealCurrent();
@@ -127,6 +174,9 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
scoped_refptr<GLShareGroup> share_group_;
scoped_ptr<VirtualGLApi> virtual_gl_api_;
scoped_ptr<GLStateRestorer> state_restorer_;
+ scoped_ptr<GLVersionInfo> version_info_;
+
+ std::vector<scoped_refptr<FlushEvent> > flush_events_;
DISALLOW_COPY_AND_ASSIGN(GLContext);
};
diff --git a/chromium/ui/gl/gl_context_android.cc b/chromium/ui/gl/gl_context_android.cc
index a9e888b203d..2b918929ddd 100644
--- a/chromium/ui/gl/gl_context_android.cc
+++ b/chromium/ui/gl/gl_context_android.cc
@@ -10,6 +10,7 @@
#include "base/sys_info.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_context_osmesa.h"
#include "ui/gl/gl_context_stub.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
@@ -75,16 +76,24 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
GLShareGroup* share_group,
GLSurface* compatible_surface,
GpuPreference gpu_preference) {
- if (GetGLImplementation() == kGLImplementationMockGL)
- return scoped_refptr<GLContext>(new GLContextStub());
-
scoped_refptr<GLContext> context;
- if (compatible_surface->GetHandle())
- context = new GLContextEGL(share_group);
- else
- context = new GLNonOwnedContext(share_group);
+ switch (GetGLImplementation()) {
+ case kGLImplementationMockGL:
+ return scoped_refptr<GLContext>(new GLContextStub());
+ case kGLImplementationOSMesaGL:
+ context = new GLContextOSMesa(share_group);
+ break;
+ default:
+ if (compatible_surface->GetHandle())
+ context = new GLContextEGL(share_group);
+ else
+ context = new GLNonOwnedContext(share_group);
+ break;
+ }
+
if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
+
return context;
}
@@ -108,27 +117,33 @@ bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) {
// Now we take a default of 1/8th of memory on high-memory devices,
// and gradually scale that back for low-memory devices (to be nicer
// to other apps so they don't get killed). Examples:
- // Nexus 4/10(2GB) 256MB
- // Droid Razr M(1GB) 91MB
- // Galaxy Nexus(1GB) 85MB
- // Xoom(1GB) 85MB
- // Nexus S(low-end) 8MB
+ // Nexus 4/10(2GB) 256MB (normally 128MB)
+ // Droid Razr M(1GB) 114MB (normally 57MB)
+ // Galaxy Nexus(1GB) 100MB (normally 50MB)
+ // Xoom(1GB) 100MB (normally 50MB)
+ // Nexus S(low-end) 12MB (normally 8MB)
+ // Note that the compositor now uses only some of this memory for
+ // pre-painting and uses the rest only for 'emergencies'.
static size_t limit_bytes = 0;
if (limit_bytes == 0) {
+ // NOTE: Non-low-end devices use only 50% of these limits,
+ // except during 'emergencies' where 100% can be used.
if (!base::android::SysUtils::IsLowEndDevice()) {
if (physical_memory_mb >= 1536)
- limit_bytes = physical_memory_mb / 8;
+ limit_bytes = physical_memory_mb / 8; // >192MB
else if (physical_memory_mb >= 1152)
- limit_bytes = physical_memory_mb / 10;
+ limit_bytes = physical_memory_mb / 8; // >144MB
else if (physical_memory_mb >= 768)
- limit_bytes = physical_memory_mb / 12;
+ limit_bytes = physical_memory_mb / 10; // >76MB
else
- limit_bytes = physical_memory_mb / 16;
+ limit_bytes = physical_memory_mb / 12; // <64MB
} else {
// Low-end devices have 512MB or less memory by definition
// so we hard code the limit rather than relying on the heuristics
// above. Low-end devices use 4444 textures so we can use a lower limit.
- limit_bytes = 8;
+ // NOTE: Low-end uses 2/3 (67%) of this memory in practice, so we have
+ // increased the limit to 12 (8MB, or 12MB in emergencies).
+ limit_bytes = 12;
}
limit_bytes = limit_bytes * 1024 * 1024;
}
diff --git a/chromium/ui/gl/gl_context_cgl.cc b/chromium/ui/gl/gl_context_cgl.cc
index 0b63b4b3ea8..999c921b9ee 100644
--- a/chromium/ui/gl/gl_context_cgl.cc
+++ b/chromium/ui/gl/gl_context_cgl.cc
@@ -13,7 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_cgl.h"
+#include "ui/gl/gl_surface.h"
#include "ui/gl/gpu_switching_manager.h"
namespace gfx {
@@ -178,6 +178,7 @@ bool GLContextCGL::MakeCurrent(GLSurface* surface) {
if (IsCurrent(surface))
return true;
+ ScopedReleaseCurrent release_current;
TRACE_EVENT0("gpu", "GLContextCGL::MakeCurrent");
if (CGLSetCurrentContext(
@@ -190,8 +191,7 @@ bool GLContextCGL::MakeCurrent(GLSurface* surface) {
SetRealGLApi();
SetCurrent(surface);
- if (!InitializeExtensionBindings()) {
- ReleaseCurrent(surface);
+ if (!InitializeDynamicBindings()) {
return false;
}
@@ -200,6 +200,7 @@ bool GLContextCGL::MakeCurrent(GLSurface* surface) {
return false;
}
+ release_current.Cancel();
return true;
}
diff --git a/chromium/ui/gl/gl_context_egl.cc b/chromium/ui/gl/gl_context_egl.cc
index cd6b534d403..2554f8c5b1d 100644
--- a/chromium/ui/gl/gl_context_egl.cc
+++ b/chromium/ui/gl/gl_context_egl.cc
@@ -93,6 +93,7 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) {
if (IsCurrent(surface))
return true;
+ ScopedReleaseCurrent release_current;
TRACE_EVENT2("gpu", "GLContextEGL::MakeCurrent",
"context", context_,
"surface", surface);
@@ -115,8 +116,7 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) {
SetRealGLApi();
SetCurrent(surface);
- if (!InitializeExtensionBindings()) {
- ReleaseCurrent(surface);
+ if (!InitializeDynamicBindings()) {
return false;
}
@@ -125,6 +125,7 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) {
return false;
}
+ release_current.Cancel();
return true;
}
diff --git a/chromium/ui/gl/gl_context_glx.cc b/chromium/ui/gl/gl_context_glx.cc
index 407d60048f4..d5ab073e40d 100644
--- a/chromium/ui/gl/gl_context_glx.cc
+++ b/chromium/ui/gl/gl_context_glx.cc
@@ -19,20 +19,6 @@ extern "C" {
namespace gfx {
-namespace {
-
-// scoped_ptr functor for XFree(). Use as follows:
-// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
-// where "XVisualInfo" is any X type that is freed with XFree.
-class ScopedPtrXFree {
- public:
- void operator()(void* x) const {
- ::XFree(x);
- }
-};
-
-} // namespace
-
GLContextGLX::GLContextGLX(GLShareGroup* share_group)
: GLContextReal(share_group),
context_(NULL),
@@ -112,6 +98,7 @@ bool GLContextGLX::MakeCurrent(GLSurface* surface) {
if (IsCurrent(surface))
return true;
+ ScopedReleaseCurrent release_current;
TRACE_EVENT0("gpu", "GLContextGLX::MakeCurrent");
if (!glXMakeContextCurrent(
display_,
@@ -127,19 +114,18 @@ bool GLContextGLX::MakeCurrent(GLSurface* surface) {
SetRealGLApi();
SetCurrent(surface);
- if (!InitializeExtensionBindings()) {
- ReleaseCurrent(surface);
+ if (!InitializeDynamicBindings()) {
Destroy();
return false;
}
if (!surface->OnMakeCurrent(this)) {
LOG(ERROR) << "Could not make current.";
- ReleaseCurrent(surface);
Destroy();
return false;
}
+ release_current.Cancel();
return true;
}
diff --git a/chromium/ui/gl/gl_context_mac.mm b/chromium/ui/gl/gl_context_mac.mm
index 5a497cda47d..4b9c8dd732b 100644
--- a/chromium/ui/gl/gl_context_mac.mm
+++ b/chromium/ui/gl/gl_context_mac.mm
@@ -8,7 +8,6 @@
#include "base/memory/scoped_ptr.h"
#include "third_party/mesa/src/include/GL/osmesa.h"
#include "ui/gl/gl_context_cgl.h"
-#include "ui/gl/gl_context_nsview.h"
#include "ui/gl/gl_context_osmesa.h"
#include "ui/gl/gl_context_stub.h"
#include "ui/gl/gl_implementation.h"
@@ -28,10 +27,11 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
case kGLImplementationDesktopGL:
case kGLImplementationAppleGL: {
scoped_refptr<GLContext> context;
- if (compatible_surface->IsOffscreen())
- context = new GLContextCGL(share_group);
- else
- context = new GLContextNSView(share_group);
+ // Note that with virtualization we might still be able to make current
+ // a different onscreen surface with this context later. But we should
+ // always be creating the context with an offscreen surface first.
+ DCHECK(compatible_surface->IsOffscreen());
+ context = new GLContextCGL(share_group);
if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
diff --git a/chromium/ui/gl/gl_context_nsview.h b/chromium/ui/gl/gl_context_nsview.h
deleted file mode 100644
index 5492dc18c2e..00000000000
--- a/chromium/ui/gl/gl_context_nsview.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GL_GL_CONTEXT_NSVIEW_H_
-#define UI_GL_GL_CONTEXT_NSVIEW_H_
-
-#import <AppKit/NSOpenGL.h>
-
-#include "base/compiler_specific.h"
-#include "base/mac/scoped_nsobject.h"
-#include "ui/gl/gl_context.h"
-
-namespace gfx {
-
-class GLSurface;
-
-// GLContextNSView encapsulates an NSView-based GLContext. This is paired with
-// the GLSurfaceNSView class.
-class GLContextNSView : public GLContextReal {
- public:
- explicit GLContextNSView(GLShareGroup* group);
-
- // GLContext:
- virtual bool Initialize(GLSurface* surface,
- GpuPreference gpu_preference) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual bool MakeCurrent(GLSurface* surface) OVERRIDE;
- virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE;
- virtual bool IsCurrent(GLSurface* surface) OVERRIDE;
- virtual void* GetHandle() OVERRIDE;
- virtual void SetSwapInterval(int interval) OVERRIDE;
-
- // Flush the |context_|. Swaps buffers.
- void FlushBuffer();
-
- private:
- virtual ~GLContextNSView();
-
- base::scoped_nsobject<NSOpenGLContext> context_;
- GpuPreference gpu_preference_;
-
- DISALLOW_COPY_AND_ASSIGN(GLContextNSView);
-};
-
-} // namespace gfx
-
-#endif // UI_GL_GL_CONTEXT_NSVIEW_H_
diff --git a/chromium/ui/gl/gl_context_nsview.mm b/chromium/ui/gl/gl_context_nsview.mm
deleted file mode 100644
index dd7a5a64851..00000000000
--- a/chromium/ui/gl/gl_context_nsview.mm
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/gl_context_nsview.h"
-
-#include <vector>
-
-#import <AppKit/NSOpenGL.h>
-#import <AppKit/NSView.h>
-
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "ui/gl/gl_surface_nsview.h"
-
-namespace gfx {
-
-GLContextNSView::GLContextNSView(GLShareGroup* group)
- : GLContextReal(group) {
-}
-
-GLContextNSView::~GLContextNSView() {
-}
-
-bool GLContextNSView::Initialize(GLSurface* surface,
- GpuPreference gpu_preference) {
- DCHECK(!context_) << "NSGLContext was previously initialized.";
- gpu_preference_ = gpu_preference;
-
- std::vector<NSOpenGLPixelFormatAttribute> attributes;
- attributes.push_back(NSOpenGLPFAAccelerated);
- attributes.push_back(NSOpenGLPFADoubleBuffer);
- attributes.push_back(0);
-
- base::scoped_nsobject<NSOpenGLPixelFormat> pixel_format;
- pixel_format.reset([[NSOpenGLPixelFormat alloc]
- initWithAttributes:&attributes.front()]);
- if (!pixel_format) {
- LOG(ERROR) << "NSOpenGLPixelFormat initWithAttributes failed.";
- return false;
- }
-
- context_.reset([[NSOpenGLContext alloc] initWithFormat:pixel_format
- shareContext:nil]);
- if (!context_) {
- LOG(ERROR) << "NSOpenGLContext initWithFormat failed";
- return false;
- }
-
- return true;
-}
-
-void GLContextNSView::Destroy() {
- context_.reset(nil);
-}
-
-bool GLContextNSView::MakeCurrent(GLSurface* surface) {
- TRACE_EVENT0("gpu", "GLContextNSView::MakeCurrent");
- AcceleratedWidget view =
- static_cast<AcceleratedWidget>(surface->GetHandle());
- // Only set the context's view if the view is parented.
- // I.e. it is a valid drawable.
- if ([view window])
- [context_ setView:view];
- [context_ makeCurrentContext];
-
- SetRealGLApi();
- SetCurrent(surface);
-
- if (!surface->OnMakeCurrent(this)) {
- LOG(ERROR) << "Unable to make gl context current.";
- return false;
- }
-
- return true;
-}
-
-void GLContextNSView::ReleaseCurrent(GLSurface* surface) {
- [NSOpenGLContext clearCurrentContext];
-}
-
-bool GLContextNSView::IsCurrent(GLSurface* surface) {
- return context_ == [NSOpenGLContext currentContext];
-}
-
-void* GLContextNSView::GetHandle() {
- return context_;
-}
-
-void GLContextNSView::SetSwapInterval(int interval) {
- DCHECK(interval == 0 || interval == 1);
- GLint swap = interval;
- [context_ setValues:&swap forParameter:NSOpenGLCPSwapInterval];
-}
-
-void GLContextNSView::FlushBuffer() {
- [context_ flushBuffer];
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gl/gl_context_osmesa.cc b/chromium/ui/gl/gl_context_osmesa.cc
index cb71aa57a7e..524fe42bb17 100644
--- a/chromium/ui/gl/gl_context_osmesa.cc
+++ b/chromium/ui/gl/gl_context_osmesa.cc
@@ -52,6 +52,7 @@ bool GLContextOSMesa::MakeCurrent(GLSurface* surface) {
gfx::Size size = surface->GetSize();
+ ScopedReleaseCurrent release_current;
if (!OSMesaMakeCurrent(context_,
surface->GetHandle(),
GL_UNSIGNED_BYTE,
@@ -69,8 +70,7 @@ bool GLContextOSMesa::MakeCurrent(GLSurface* surface) {
OSMesaPixelStore(OSMESA_Y_UP, 0);
SetCurrent(surface);
- if (!InitializeExtensionBindings()) {
- ReleaseCurrent(surface);
+ if (!InitializeDynamicBindings()) {
return false;
}
@@ -79,6 +79,7 @@ bool GLContextOSMesa::MakeCurrent(GLSurface* surface) {
return false;
}
+ release_current.Cancel();
return true;
}
@@ -87,6 +88,7 @@ void GLContextOSMesa::ReleaseCurrent(GLSurface* surface) {
return;
SetCurrent(NULL);
+ // TODO: Calling with NULL here does not work to release the context.
OSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0);
}
diff --git a/chromium/ui/gl/gl_context_stub.cc b/chromium/ui/gl/gl_context_stub.cc
index 56fb3c72efb..faf957b1e77 100644
--- a/chromium/ui/gl/gl_context_stub.cc
+++ b/chromium/ui/gl/gl_context_stub.cc
@@ -17,6 +17,7 @@ void GLContextStub::Destroy() {}
bool GLContextStub::MakeCurrent(GLSurface* surface) {
SetCurrent(surface);
+ SetRealGLApi();
return true;
}
@@ -39,6 +40,10 @@ std::string GLContextStub::GetExtensions() {
return std::string();
}
+std::string GLContextStub::GetGLRenderer() {
+ return std::string("CHROMIUM");
+}
+
GLContextStub::~GLContextStub() {}
} // namespace gfx
diff --git a/chromium/ui/gl/gl_context_stub.h b/chromium/ui/gl/gl_context_stub.h
index 8fca5b71dcc..d57e02e61c6 100644
--- a/chromium/ui/gl/gl_context_stub.h
+++ b/chromium/ui/gl/gl_context_stub.h
@@ -24,6 +24,7 @@ class GL_EXPORT GLContextStub : public GLContextReal {
virtual void* GetHandle() OVERRIDE;
virtual void SetSwapInterval(int interval) OVERRIDE;
virtual std::string GetExtensions() OVERRIDE;
+ virtual std::string GetGLRenderer() OVERRIDE;
protected:
virtual ~GLContextStub();
diff --git a/chromium/ui/gl/gl_context_stub_with_extensions.cc b/chromium/ui/gl/gl_context_stub_with_extensions.cc
new file mode 100644
index 00000000000..1065df789fb
--- /dev/null
+++ b/chromium/ui/gl/gl_context_stub_with_extensions.cc
@@ -0,0 +1,30 @@
+// 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/gl/gl_context_stub_with_extensions.h"
+
+namespace gfx {
+
+void GLContextStubWithExtensions::AddExtensionsString(const char* extensions) {
+ if (extensions == NULL)
+ return;
+
+ if (extensions_.size() != 0)
+ extensions_ += ' ';
+ extensions_ += extensions;
+}
+
+std::string GLContextStubWithExtensions::GetExtensions() {
+ return extensions_;
+}
+
+void GLContextStubWithExtensions::SetGLVersionString(const char* version_str) {
+ version_str_ = std::string(version_str ? version_str : "");
+}
+
+std::string GLContextStubWithExtensions::GetGLVersion() {
+ return version_str_;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_context_stub_with_extensions.h b/chromium/ui/gl/gl_context_stub_with_extensions.h
new file mode 100644
index 00000000000..e048990663b
--- /dev/null
+++ b/chromium/ui/gl/gl_context_stub_with_extensions.h
@@ -0,0 +1,37 @@
+// 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_GL_GL_CONTEXT_STUB_WITH_EXTENSIONS_H_
+#define UI_GL_GL_CONTEXT_STUB_WITH_EXTENSIONS_H_
+
+#include "ui/gl/gl_context_stub.h"
+
+namespace gfx {
+
+// Lightweight GLContext stub implementation that returns a constructed
+// extensions string. We use this to create a context that we can use to
+// initialize GL extensions with, without actually creating a platform context.
+class GL_EXPORT GLContextStubWithExtensions : public gfx::GLContextStub {
+ public:
+ GLContextStubWithExtensions() {}
+ virtual std::string GetExtensions() OVERRIDE;
+
+ void AddExtensionsString(const char* extensions);
+ void SetGLVersionString(const char* version_str);
+
+ protected:
+ virtual std::string GetGLVersion() OVERRIDE;
+
+ virtual ~GLContextStubWithExtensions() {}
+
+ private:
+ std::string extensions_;
+ std::string version_str_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLContextStubWithExtensions);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_GL_CONTEXT_STUB_WITH_EXTENSIONS_H_
diff --git a/chromium/ui/gl/gl_context_wgl.cc b/chromium/ui/gl/gl_context_wgl.cc
index 8ee90dd8ff3..abe47e4f9f7 100644
--- a/chromium/ui/gl/gl_context_wgl.cc
+++ b/chromium/ui/gl/gl_context_wgl.cc
@@ -74,6 +74,7 @@ bool GLContextWGL::MakeCurrent(GLSurface* surface) {
if (IsCurrent(surface))
return true;
+ ScopedReleaseCurrent release_current;
TRACE_EVENT0("gpu", "GLContextWGL::MakeCurrent");
if (!wglMakeCurrent(static_cast<HDC>(surface->GetHandle()), context_)) {
@@ -85,8 +86,7 @@ bool GLContextWGL::MakeCurrent(GLSurface* surface) {
SetRealGLApi();
SetCurrent(surface);
- if (!InitializeExtensionBindings()) {
- ReleaseCurrent(surface);
+ if (!InitializeDynamicBindings()) {
return false;
}
@@ -95,6 +95,7 @@ bool GLContextWGL::MakeCurrent(GLSurface* surface) {
return false;
}
+ release_current.Cancel();
return true;
}
diff --git a/chromium/ui/gl/gl_egl_api_implementation.cc b/chromium/ui/gl/gl_egl_api_implementation.cc
index 43aa138a3f8..b3b55b8ff8f 100644
--- a/chromium/ui/gl/gl_egl_api_implementation.cc
+++ b/chromium/ui/gl/gl_egl_api_implementation.cc
@@ -9,8 +9,8 @@ namespace gfx {
RealEGLApi* g_real_egl;
-void InitializeGLBindingsEGL() {
- g_driver_egl.InitializeBindings();
+void InitializeStaticGLBindingsEGL() {
+ g_driver_egl.InitializeStaticBindings();
if (!g_real_egl) {
g_real_egl = new RealEGLApi();
}
@@ -18,8 +18,8 @@ void InitializeGLBindingsEGL() {
g_current_egl_context = g_real_egl;
}
-void InitializeGLExtensionBindingsEGL(GLContext* context) {
- g_driver_egl.InitializeExtensionBindings(context);
+void InitializeDynamicGLBindingsEGL(GLContext* context) {
+ g_driver_egl.InitializeDynamicBindings(context);
}
void InitializeDebugGLBindingsEGL() {
diff --git a/chromium/ui/gl/gl_egl_api_implementation.h b/chromium/ui/gl/gl_egl_api_implementation.h
index 96860cf30b0..aef46ee31c6 100644
--- a/chromium/ui/gl/gl_egl_api_implementation.h
+++ b/chromium/ui/gl/gl_egl_api_implementation.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_EGL_API_IMPLEMENTATION_H_
-#define UI_GL_EGL_API_IMPLEMENTATION_H_
+#ifndef UI_GL_GL_EGL_API_IMPLEMENTATION_H_
+#define UI_GL_GL_EGL_API_IMPLEMENTATION_H_
#include "base/compiler_specific.h"
#include "gl_bindings.h"
@@ -14,8 +14,8 @@ namespace gfx {
class GLContext;
struct GLWindowSystemBindingInfo;
-void InitializeGLBindingsEGL();
-void InitializeGLExtensionBindingsEGL(GLContext* context);
+void InitializeStaticGLBindingsEGL();
+void InitializeDynamicGLBindingsEGL(GLContext* context);
void InitializeDebugGLBindingsEGL();
void ClearGLBindingsEGL();
bool GetGLWindowSystemBindingInfoEGL(GLWindowSystemBindingInfo* info);
@@ -60,7 +60,7 @@ class GL_EXPORT TraceEGLApi : public EGLApi {
} // namespace gfx
-#endif // UI_GL_EGL_API_IMPLEMENTATION_H_
+#endif // UI_GL_GL_EGL_API_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gl_fence.cc b/chromium/ui/gl/gl_fence.cc
index 9b85300fabd..073e6eea314 100644
--- a/chromium/ui/gl/gl_fence.cc
+++ b/chromium/ui/gl/gl_fence.cc
@@ -7,12 +7,13 @@
#include "base/compiler_specific.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_version_info.h"
namespace {
class GLFenceNVFence: public gfx::GLFence {
public:
- GLFenceNVFence() {
+ GLFenceNVFence(bool flush) {
// What if either of these GL calls fails? TestFenceNV will return true.
// See spec:
// http://www.opengl.org/registry/specs/NV/fence.txt
@@ -25,7 +26,11 @@ class GLFenceNVFence: public gfx::GLFence {
// We will arbitrarily return TRUE for consistency.
glGenFencesNV(1, &fence_);
glSetFenceNV(fence_, GL_ALL_COMPLETED_NV);
- glFlush();
+ if (flush) {
+ glFlush();
+ } else {
+ flush_event_ = gfx::GLContext::GetCurrent()->SignalFlush();
+ }
}
virtual bool HasCompleted() OVERRIDE {
@@ -33,7 +38,15 @@ class GLFenceNVFence: public gfx::GLFence {
}
virtual void ClientWait() OVERRIDE {
- glFinishFenceNV(fence_);
+ if (!flush_event_ || flush_event_->IsSignaled()) {
+ glFinishFenceNV(fence_);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
+ }
+
+ virtual void ServerWait() OVERRIDE {
+ ClientWait();
}
private:
@@ -42,13 +55,18 @@ class GLFenceNVFence: public gfx::GLFence {
}
GLuint fence_;
+ scoped_refptr<gfx::GLContext::FlushEvent> flush_event_;
};
class GLFenceARBSync: public gfx::GLFence {
public:
- GLFenceARBSync() {
+ GLFenceARBSync(bool flush) {
sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
+ if (flush) {
+ glFlush();
+ } else {
+ flush_event_ = gfx::GLContext::GetCurrent()->SignalFlush();
+ }
}
virtual bool HasCompleted() OVERRIDE {
@@ -63,7 +81,19 @@ class GLFenceARBSync: public gfx::GLFence {
}
virtual void ClientWait() OVERRIDE {
- glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
+ if (!flush_event_ || flush_event_->IsSignaled()) {
+ glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
+ }
+
+ virtual void ServerWait() OVERRIDE {
+ if (!flush_event_ || flush_event_->IsSignaled()) {
+ glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
}
private:
@@ -72,15 +102,20 @@ class GLFenceARBSync: public gfx::GLFence {
}
GLsync sync_;
+ scoped_refptr<gfx::GLContext::FlushEvent> flush_event_;
};
#if !defined(OS_MACOSX)
class EGLFenceSync : public gfx::GLFence {
public:
- EGLFenceSync() {
+ EGLFenceSync(bool flush) {
display_ = eglGetCurrentDisplay();
sync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL);
- glFlush();
+ if (flush) {
+ glFlush();
+ } else {
+ flush_event_ = gfx::GLContext::GetCurrent()->SignalFlush();
+ }
}
virtual bool HasCompleted() OVERRIDE {
@@ -91,11 +126,25 @@ class EGLFenceSync : public gfx::GLFence {
}
virtual void ClientWait() OVERRIDE {
- EGLint flags = 0;
- EGLTimeKHR time = EGL_FOREVER_KHR;
- eglClientWaitSyncKHR(display_, sync_, flags, time);
+ if (!flush_event_ || flush_event_->IsSignaled()) {
+ EGLint flags = 0;
+ EGLTimeKHR time = EGL_FOREVER_KHR;
+ eglClientWaitSyncKHR(display_, sync_, flags, time);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
+ }
+
+ virtual void ServerWait() OVERRIDE {
+ if (!flush_event_ || flush_event_->IsSignaled()) {
+ EGLint flags = 0;
+ eglWaitSyncKHR(display_, sync_, flags);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
}
+
private:
virtual ~EGLFenceSync() {
eglDestroySyncKHR(display_, sync_);
@@ -103,9 +152,28 @@ class EGLFenceSync : public gfx::GLFence {
EGLSyncKHR sync_;
EGLDisplay display_;
+ scoped_refptr<gfx::GLContext::FlushEvent> flush_event_;
};
#endif // !OS_MACOSX
+// static
+gfx::GLFence* CreateFence(bool flush) {
+ DCHECK(gfx::GLContext::GetCurrent())
+ << "Trying to create fence with no context";
+
+ // Prefer ARB_sync which supports server-side wait.
+ if (gfx::g_driver_gl.ext.b_GL_ARB_sync ||
+ gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es3)
+ return new GLFenceARBSync(flush);
+#if !defined(OS_MACOSX)
+ if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync)
+ return new EGLFenceSync(flush);
+#endif
+ if (gfx::g_driver_gl.ext.b_GL_NV_fence)
+ return new GLFenceNVFence(flush);
+ return NULL;
+}
+
} // namespace
namespace gfx {
@@ -116,17 +184,12 @@ GLFence::GLFence() {
GLFence::~GLFence() {
}
-// static
GLFence* GLFence::Create() {
-#if !defined(OS_MACOSX)
- if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync)
- return new EGLFenceSync();
-#endif
- if (gfx::g_driver_gl.ext.b_GL_NV_fence)
- return new GLFenceNVFence();
- if (gfx::g_driver_gl.ext.b_GL_ARB_sync)
- return new GLFenceARBSync();
- return NULL;
+ return CreateFence(true);
+}
+
+GLFence* GLFence::CreateWithoutFlush() {
+ return CreateFence(false);
}
} // namespace gfx
diff --git a/chromium/ui/gl/gl_fence.h b/chromium/ui/gl/gl_fence.h
index d4f3218d52f..021f3456f13 100644
--- a/chromium/ui/gl/gl_fence.h
+++ b/chromium/ui/gl/gl_fence.h
@@ -16,9 +16,20 @@ class GL_EXPORT GLFence {
virtual ~GLFence();
static GLFence* Create();
+
+ // Creates a fence that is not guaranteed to signal until the current context
+ // is flushed. It is illegal to call Client/ServerWait() on a fence without
+ // having explicitly called glFlush() or glFinish() in the originating
+ // context.
+ static GLFence* CreateWithoutFlush();
+
virtual bool HasCompleted() = 0;
virtual void ClientWait() = 0;
+ // Will block the server if supported, but might fall back to blocking the
+ // client.
+ virtual void ServerWait() = 0;
+
protected:
static bool IsContextLost();
diff --git a/chromium/ui/gl/gl_gl_api_implementation.cc b/chromium/ui/gl/gl_gl_api_implementation.cc
index eade3cedaf5..2973388a276 100644
--- a/chromium/ui/gl/gl_gl_api_implementation.cc
+++ b/chromium/ui/gl/gl_gl_api_implementation.cc
@@ -14,15 +14,21 @@
#include "ui/gl/gl_state_restorer.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_switches.h"
+#include "ui/gl/gl_version_info.h"
namespace gfx {
// The GL Api being used. This could be g_real_gl or gl_trace_gl
-static GLApi* g_gl;
+static GLApi* g_gl = NULL;
// A GL Api that calls directly into the driver.
-static RealGLApi* g_real_gl;
+static RealGLApi* g_real_gl = NULL;
+// A GL Api that does nothing but warn about illegal GL calls without a context
+// current.
+static NoContextGLApi* g_no_context_gl = NULL;
// A GL Api that calls TRACE and then calls another GL api.
-static TraceGLApi* g_trace_gl;
+static TraceGLApi* g_trace_gl = NULL;
+// GL version used when initializing dynamic bindings.
+static GLVersionInfo* g_version_info = NULL;
namespace {
@@ -40,7 +46,28 @@ static inline GLenum GetTexInternalFormat(GLenum internal_format,
GLenum type) {
GLenum gl_internal_format = GetInternalFormat(internal_format);
- if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ // g_version_info must be initialized when this function is bound.
+ DCHECK(gfx::g_version_info);
+ if (type == GL_FLOAT && gfx::g_version_info->is_angle &&
+ gfx::g_version_info->is_es2) {
+ // It's possible that the texture is using a sized internal format, and
+ // ANGLE exposing GLES2 API doesn't support those.
+ // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
+ // support.
+ // http://code.google.com/p/angleproject/issues/detail?id=556
+ switch (format) {
+ case GL_RGBA:
+ gl_internal_format = GL_RGBA;
+ break;
+ case GL_RGB:
+ gl_internal_format = GL_RGB;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (gfx::g_version_info->is_es)
return gl_internal_format;
if (type == GL_FLOAT) {
@@ -104,7 +131,7 @@ static void GL_BINDING_CALL CustomTexImage2D(
GLenum gl_internal_format = GetTexInternalFormat(
internalformat, format, type);
GLenum gl_type = GetTexType(type);
- return g_driver_gl.orig_fn.glTexImage2DFn(
+ g_driver_gl.orig_fn.glTexImage2DFn(
target, level, gl_internal_format, width, height, border, format, gl_type,
pixels);
}
@@ -113,7 +140,7 @@ static void GL_BINDING_CALL CustomTexSubImage2D(
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLenum type, const void* pixels) {
GLenum gl_type = GetTexType(type);
- return g_driver_gl.orig_fn.glTexSubImage2DFn(
+ g_driver_gl.orig_fn.glTexSubImage2DFn(
target, level, xoffset, yoffset, width, height, format, gl_type, pixels);
}
@@ -121,14 +148,14 @@ static void GL_BINDING_CALL CustomTexStorage2DEXT(
GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
GLsizei height) {
GLenum gl_internal_format = GetInternalFormat(internalformat);
- return g_driver_gl.orig_fn.glTexStorage2DEXTFn(
+ g_driver_gl.orig_fn.glTexStorage2DEXTFn(
target, levels, gl_internal_format, width, height);
}
static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
GLenum gl_internal_format = GetInternalFormat(internalformat);
- return g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
+ g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
target, gl_internal_format, width, height);
}
@@ -140,39 +167,101 @@ static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
GLsizei height) {
GLenum gl_internal_format = GetInternalFormat(internalformat);
- return g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
+ g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
target, samples, gl_internal_format, width, height);
}
} // anonymous namespace
-void DriverGL::Initialize() {
- InitializeBindings();
-}
+void DriverGL::InitializeCustomDynamicBindings(GLContext* context) {
+ InitializeDynamicBindings(context);
-void DriverGL::InitializeExtensions(GLContext* context) {
- InitializeExtensionBindings(context);
- orig_fn = fn;
+ DCHECK(orig_fn.glTexImage2DFn == NULL);
+ orig_fn.glTexImage2DFn = fn.glTexImage2DFn;
fn.glTexImage2DFn =
reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
+
+ DCHECK(orig_fn.glTexSubImage2DFn == NULL);
+ orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn;
fn.glTexSubImage2DFn =
reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
+
+ DCHECK(orig_fn.glTexStorage2DEXTFn == NULL);
+ orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn;
fn.glTexStorage2DEXTFn =
reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
+
+ DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL);
+ orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn;
fn.glRenderbufferStorageEXTFn =
reinterpret_cast<glRenderbufferStorageEXTProc>(
CustomRenderbufferStorageEXT);
+
+ DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL);
+ orig_fn.glRenderbufferStorageMultisampleEXTFn =
+ fn.glRenderbufferStorageMultisampleEXTFn;
fn.glRenderbufferStorageMultisampleEXTFn =
reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
CustomRenderbufferStorageMultisampleEXT);
}
-void InitializeGLBindingsGL() {
+static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) {
+ if (!g_driver_gl.null_draw_bindings_enabled)
+ g_driver_gl.orig_fn.glClearFn(mask);
+}
+
+static void GL_BINDING_CALL
+NullDrawDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
+ if (!g_driver_gl.null_draw_bindings_enabled)
+ g_driver_gl.orig_fn.glDrawArraysFn(mode, first, count);
+}
+
+static void GL_BINDING_CALL NullDrawDrawElementsFn(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const void* indices) {
+ if (!g_driver_gl.null_draw_bindings_enabled)
+ g_driver_gl.orig_fn.glDrawElementsFn(mode, count, type, indices);
+}
+
+void DriverGL::InitializeNullDrawBindings() {
+ DCHECK(orig_fn.glClearFn == NULL);
+ orig_fn.glClearFn = fn.glClearFn;
+ fn.glClearFn = NullDrawClearFn;
+
+ DCHECK(orig_fn.glDrawArraysFn == NULL);
+ orig_fn.glDrawArraysFn = fn.glDrawArraysFn;
+ fn.glDrawArraysFn = NullDrawDrawArraysFn;
+
+ DCHECK(orig_fn.glDrawElementsFn == NULL);
+ orig_fn.glDrawElementsFn = fn.glDrawElementsFn;
+ fn.glDrawElementsFn = NullDrawDrawElementsFn;
+
+ null_draw_bindings_enabled = true;
+}
+
+bool DriverGL::HasInitializedNullDrawBindings() {
+ return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL &&
+ orig_fn.glDrawElementsFn != NULL;
+}
+
+bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) {
+ DCHECK(orig_fn.glClearFn != NULL);
+ DCHECK(orig_fn.glDrawArraysFn != NULL);
+ DCHECK(orig_fn.glDrawElementsFn != NULL);
+
+ bool before = null_draw_bindings_enabled;
+ null_draw_bindings_enabled = enabled;
+ return before;
+}
+
+void InitializeStaticGLBindingsGL() {
g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
- g_driver_gl.Initialize();
+ g_driver_gl.InitializeStaticBindings();
if (!g_real_gl) {
g_real_gl = new RealGLApi();
g_trace_gl = new TraceGLApi(g_real_gl);
+ g_no_context_gl = new NoContextGLApi();
}
g_real_gl->Initialize(&g_driver_gl);
g_gl = g_real_gl;
@@ -195,14 +284,33 @@ void SetGLToRealGLApi() {
SetGLApi(g_gl);
}
-void InitializeGLExtensionBindingsGL(GLContext* context) {
- g_driver_gl.InitializeExtensions(context);
+void SetGLApiToNoContext() {
+ SetGLApi(g_no_context_gl);
+}
+
+void InitializeDynamicGLBindingsGL(GLContext* context) {
+ g_driver_gl.InitializeCustomDynamicBindings(context);
+ DCHECK(context && context->IsCurrent(NULL) && !g_version_info);
+ g_version_info = new GLVersionInfo(context->GetGLVersion().c_str(),
+ context->GetGLRenderer().c_str());
}
void InitializeDebugGLBindingsGL() {
g_driver_gl.InitializeDebugBindings();
}
+void InitializeNullDrawGLBindingsGL() {
+ g_driver_gl.InitializeNullDrawBindings();
+}
+
+bool HasInitializedNullDrawGLBindingsGL() {
+ return g_driver_gl.HasInitializedNullDrawBindings();
+}
+
+bool SetNullDrawGLBindingsEnabledGL(bool enabled) {
+ return g_driver_gl.SetNullDrawBindingsEnabled(enabled);
+}
+
void ClearGLBindingsGL() {
if (g_real_gl) {
delete g_real_gl;
@@ -212,12 +320,20 @@ void ClearGLBindingsGL() {
delete g_trace_gl;
g_trace_gl = NULL;
}
+ if (g_no_context_gl) {
+ delete g_no_context_gl;
+ g_no_context_gl = NULL;
+ }
g_gl = NULL;
g_driver_gl.ClearBindings();
if (g_current_gl_context_tls) {
delete g_current_gl_context_tls;
g_current_gl_context_tls = NULL;
}
+ if (g_version_info) {
+ delete g_version_info;
+ g_version_info = NULL;
+ }
}
GLApi::GLApi() {
@@ -239,6 +355,11 @@ void GLApiBase::InitializeBase(DriverGL* driver) {
driver_ = driver;
}
+void GLApiBase::SignalFlush() {
+ DCHECK(GLContext::GetCurrent());
+ GLContext::GetCurrent()->OnFlush();
+}
+
RealGLApi::RealGLApi() {
}
@@ -249,9 +370,25 @@ void RealGLApi::Initialize(DriverGL* driver) {
InitializeBase(driver);
}
+void RealGLApi::glFlushFn() {
+ GLApiBase::glFlushFn();
+ GLApiBase::SignalFlush();
+}
+
+void RealGLApi::glFinishFn() {
+ GLApiBase::glFinishFn();
+ GLApiBase::SignalFlush();
+}
+
TraceGLApi::~TraceGLApi() {
}
+NoContextGLApi::NoContextGLApi() {
+}
+
+NoContextGLApi::~NoContextGLApi() {
+}
+
VirtualGLApi::VirtualGLApi()
: real_context_(NULL),
current_context_(NULL) {
@@ -305,17 +442,17 @@ bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
// new context.
DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR));
- current_context_ = virtual_context;
// Set all state that is different from the real state
- // NOTE: !!! This is a temporary implementation that just restores all
- // state to let us test that it works.
- // TODO: ASAP, change this to something that only restores the state
- // needed for individual GL calls.
GLApi* temp = GetCurrentGLApi();
SetGLToRealGLApi();
- if (virtual_context->GetGLStateRestorer()->IsInitialized())
- virtual_context->GetGLStateRestorer()->RestoreState();
+ if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
+ virtual_context->GetGLStateRestorer()->RestoreState(
+ (current_context_ && !switched_contexts)
+ ? current_context_->GetGLStateRestorer()
+ : NULL);
+ }
SetGLApi(temp);
+ current_context_ = virtual_context;
}
SetGLApi(this);
@@ -341,4 +478,14 @@ const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
}
}
+void VirtualGLApi::glFlushFn() {
+ GLApiBase::glFlushFn();
+ GLApiBase::SignalFlush();
+}
+
+void VirtualGLApi::glFinishFn() {
+ GLApiBase::glFinishFn();
+ GLApiBase::SignalFlush();
+}
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_gl_api_implementation.h b/chromium/ui/gl/gl_gl_api_implementation.h
index d925b939909..aff59265c9f 100644
--- a/chromium/ui/gl/gl_gl_api_implementation.h
+++ b/chromium/ui/gl/gl_gl_api_implementation.h
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_GL_API_IMPLEMENTATION_H_
-#define UI_GL_GL_API_IMPLEMENTATION_H_
+#ifndef UI_GL_GL_GL_API_IMPLEMENTATION_H_
+#define UI_GL_GL_GL_API_IMPLEMENTATION_H_
#include "base/compiler_specific.h"
#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_export.h"
namespace gpu {
namespace gles2 {
@@ -19,14 +18,19 @@ namespace gfx {
class GLContext;
class GLSurface;
-void InitializeGLBindingsGL();
-void InitializeGLExtensionBindingsGL(GLContext* context);
+void InitializeStaticGLBindingsGL();
+void InitializeDynamicGLBindingsGL(GLContext* context);
void InitializeDebugGLBindingsGL();
+void InitializeNullDrawGLBindingsGL();
+// TODO(danakj): Remove this when all test suites are using null-draw.
+bool HasInitializedNullDrawGLBindingsGL();
+bool SetNullDrawGLBindingsEnabledGL(bool enabled);
void ClearGLBindingsGL();
void SetGLToRealGLApi();
void SetGLApi(GLApi* api);
+void SetGLApiToNoContext();
-class GL_EXPORT GLApiBase : public GLApi {
+class GLApiBase : public GLApi {
public:
// Include the auto-generated part of this class. We split this because
// it means we can easily edit the non-auto generated parts right here in
@@ -37,20 +41,25 @@ class GL_EXPORT GLApiBase : public GLApi {
GLApiBase();
virtual ~GLApiBase();
void InitializeBase(DriverGL* driver);
+ void SignalFlush();
DriverGL* driver_;
};
// Implemenents the GL API by calling directly into the driver.
-class GL_EXPORT RealGLApi : public GLApiBase {
+class RealGLApi : public GLApiBase {
public:
RealGLApi();
virtual ~RealGLApi();
void Initialize(DriverGL* driver);
+
+ private:
+ virtual void glFinishFn() OVERRIDE;
+ virtual void glFlushFn() OVERRIDE;
};
// Inserts a TRACE for every GL call.
-class GL_EXPORT TraceGLApi : public GLApi {
+class TraceGLApi : public GLApi {
public:
TraceGLApi(GLApi* gl_api) : gl_api_(gl_api) { }
virtual ~TraceGLApi();
@@ -64,10 +73,22 @@ class GL_EXPORT TraceGLApi : public GLApi {
GLApi* gl_api_;
};
+// Catches incorrect usage when GL calls are made without a current context.
+class NoContextGLApi : public GLApi {
+ public:
+ NoContextGLApi();
+ virtual ~NoContextGLApi();
+
+ // Include the auto-generated part of this class. We split this because
+ // it means we can easily edit the non-auto generated parts right here in
+ // this file instead of having to edit some template or the code generator.
+ #include "gl_bindings_api_autogen_gl.h"
+};
+
// Implementents the GL API using co-operative state restoring.
// Assumes there is only one real GL context and that multiple virtual contexts
// are implemented above it. Restores the needed state from the current context.
-class GL_EXPORT VirtualGLApi : public GLApiBase {
+class VirtualGLApi : public GLApiBase {
public:
VirtualGLApi();
virtual ~VirtualGLApi();
@@ -78,10 +99,12 @@ class GL_EXPORT VirtualGLApi : public GLApiBase {
void OnReleaseVirtuallyCurrent(GLContext* virtual_context);
+private:
// Overridden functions from GLApiBase
virtual const GLubyte* glGetStringFn(GLenum name) OVERRIDE;
+ virtual void glFinishFn() OVERRIDE;
+ virtual void glFlushFn() OVERRIDE;
- private:
// The real context we're running on.
GLContext* real_context_;
@@ -94,4 +117,4 @@ class GL_EXPORT VirtualGLApi : public GLApiBase {
} // namespace gfx
-#endif // UI_GL_GL_API_IMPLEMENTATION_H_
+#endif // UI_GL_GL_GL_API_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gl_glx_api_implementation.cc b/chromium/ui/gl/gl_glx_api_implementation.cc
index 4a43534ec78..0392c397fd7 100644
--- a/chromium/ui/gl/gl_glx_api_implementation.cc
+++ b/chromium/ui/gl/gl_glx_api_implementation.cc
@@ -9,8 +9,8 @@ namespace gfx {
RealGLXApi* g_real_glx;
-void InitializeGLBindingsGLX() {
- g_driver_glx.InitializeBindings();
+void InitializeStaticGLBindingsGLX() {
+ g_driver_glx.InitializeStaticBindings();
if (!g_real_glx) {
g_real_glx = new RealGLXApi();
}
@@ -18,8 +18,8 @@ void InitializeGLBindingsGLX() {
g_current_glx_context = g_real_glx;
}
-void InitializeGLExtensionBindingsGLX(GLContext* context) {
- g_driver_glx.InitializeExtensionBindings(context);
+void InitializeDynamicGLBindingsGLX(GLContext* context) {
+ g_driver_glx.InitializeDynamicBindings(context);
}
void InitializeDebugGLBindingsGLX() {
@@ -81,6 +81,7 @@ bool GetGLWindowSystemBindingInfoGLX(GLWindowSystemBindingInfo* info) {
info->version = version;
if (extensions)
info->extensions = extensions;
+ info->direct_rendering = !!glXIsDirect(display, glXGetCurrentContext());
return true;
}
diff --git a/chromium/ui/gl/gl_glx_api_implementation.h b/chromium/ui/gl/gl_glx_api_implementation.h
index 97542ded48a..634db4eaf4d 100644
--- a/chromium/ui/gl/gl_glx_api_implementation.h
+++ b/chromium/ui/gl/gl_glx_api_implementation.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_GLX_API_IMPLEMENTATION_H_
-#define UI_GL_GLX_API_IMPLEMENTATION_H_
+#ifndef UI_GL_GL_GLX_API_IMPLEMENTATION_H_
+#define UI_GL_GL_GLX_API_IMPLEMENTATION_H_
#include "base/compiler_specific.h"
#include "gl_bindings.h"
@@ -14,8 +14,8 @@ namespace gfx {
class GLContext;
struct GLWindowSystemBindingInfo;
-void InitializeGLBindingsGLX();
-void InitializeGLExtensionBindingsGLX(GLContext* context);
+void InitializeStaticGLBindingsGLX();
+void InitializeDynamicGLBindingsGLX(GLContext* context);
void InitializeDebugGLBindingsGLX();
void ClearGLBindingsGLX();
bool GetGLWindowSystemBindingInfoGLX(GLWindowSystemBindingInfo* info);
@@ -59,7 +59,7 @@ class GL_EXPORT TraceGLXApi : public GLXApi {
} // namespace gfx
-#endif // UI_GL_GLX_API_IMPLEMENTATION_H_
+#endif // UI_GL_GL_GLX_API_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gl_image.cc b/chromium/ui/gl/gl_image.cc
index ea41f7946b4..967f53c31d5 100644
--- a/chromium/ui/gl/gl_image.cc
+++ b/chromium/ui/gl/gl_image.cc
@@ -10,23 +10,6 @@ namespace gfx {
GLImage::GLImage() {}
-bool GLImage::BindTexImage(unsigned target) {
- NOTIMPLEMENTED();
- return false;
-}
-
-void GLImage::ReleaseTexImage(unsigned target) {
- NOTIMPLEMENTED();
-}
-
-void GLImage::WillUseTexImage() {
- NOTIMPLEMENTED();
-}
-
-void GLImage::DidUseTexImage() {
- NOTIMPLEMENTED();
-}
-
void GLImage::SetReleaseAfterUse() {
// Default no-op implementation for workaround.
}
diff --git a/chromium/ui/gl/gl_image.h b/chromium/ui/gl/gl_image.h
index 08d2be60a5a..7798423da12 100644
--- a/chromium/ui/gl/gl_image.h
+++ b/chromium/ui/gl/gl_image.h
@@ -28,16 +28,22 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> {
virtual gfx::Size GetSize() = 0;
// Bind image to texture currently bound to |target|.
- virtual bool BindTexImage(unsigned target);
+ virtual bool BindTexImage(unsigned target) = 0;
// Release image from texture currently bound to |target|.
- virtual void ReleaseTexImage(unsigned target);
+ virtual void ReleaseTexImage(unsigned target) = 0;
// Called before the texture is used for drawing.
- virtual void WillUseTexImage();
+ virtual void WillUseTexImage() = 0;
// Called after the texture has been used for drawing.
- virtual void DidUseTexImage();
+ virtual void DidUseTexImage() = 0;
+
+ // Called before the texture image data will be modified.
+ virtual void WillModifyTexImage() = 0;
+
+ // Called after the texture image data has been modified.
+ virtual void DidModifyTexImage() = 0;
// Indicate that image should be released after use.
// (For an Android work-around only).
diff --git a/chromium/ui/gl/gl_image_android.cc b/chromium/ui/gl/gl_image_android.cc
index e56dc2d074b..a619c850178 100644
--- a/chromium/ui/gl/gl_image_android.cc
+++ b/chromium/ui/gl/gl_image_android.cc
@@ -5,9 +5,10 @@
#include "ui/gl/gl_image.h"
#include "base/debug/trace_event.h"
-#include "ui/gl/gl_image_egl.h"
+#include "ui/gl/gl_image_android_native_buffer.h"
#include "ui/gl/gl_image_shm.h"
#include "ui/gl/gl_image_stub.h"
+#include "ui/gl/gl_image_surface_texture.h"
#include "ui/gl/gl_implementation.h"
namespace gfx {
@@ -41,8 +42,17 @@ scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
return image;
}
- case EGL_CLIENT_BUFFER: {
- scoped_refptr<GLImageEGL> image(new GLImageEGL(size));
+ case ANDROID_NATIVE_BUFFER: {
+ scoped_refptr<GLImageAndroidNativeBuffer> image(
+ new GLImageAndroidNativeBuffer(size));
+ if (!image->Initialize(buffer))
+ return NULL;
+
+ return image;
+ }
+ case SURFACE_TEXTURE_BUFFER: {
+ scoped_refptr<GLImageSurfaceTexture> image(
+ new GLImageSurfaceTexture(size));
if (!image->Initialize(buffer))
return NULL;
diff --git a/chromium/ui/gl/gl_image_android_native_buffer.cc b/chromium/ui/gl/gl_image_android_native_buffer.cc
new file mode 100644
index 00000000000..6d11497b2a3
--- /dev/null
+++ b/chromium/ui/gl/gl_image_android_native_buffer.cc
@@ -0,0 +1,118 @@
+// 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/gl/gl_image_android_native_buffer.h"
+
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace gfx {
+
+GLImageAndroidNativeBuffer::GLImageAndroidNativeBuffer(gfx::Size size)
+ : GLImageEGL(size),
+ release_after_use_(false),
+ in_use_(false),
+ target_(0),
+ egl_image_for_unbind_(EGL_NO_IMAGE_KHR),
+ texture_id_for_unbind_(0) {}
+
+GLImageAndroidNativeBuffer::~GLImageAndroidNativeBuffer() { Destroy(); }
+
+bool GLImageAndroidNativeBuffer::Initialize(gfx::GpuMemoryBufferHandle buffer) {
+ DCHECK(buffer.native_buffer);
+
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ return GLImageEGL::Initialize(
+ EGL_NATIVE_BUFFER_ANDROID, buffer.native_buffer, attrs);
+}
+
+void GLImageAndroidNativeBuffer::Destroy() {
+ if (egl_image_for_unbind_ != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
+ egl_image_for_unbind_);
+ egl_image_for_unbind_ = EGL_NO_IMAGE_KHR;
+ }
+ if (texture_id_for_unbind_) {
+ glDeleteTextures(1, &texture_id_for_unbind_);
+ texture_id_for_unbind_ = 0;
+ }
+
+ GLImageEGL::Destroy();
+}
+
+bool GLImageAndroidNativeBuffer::BindTexImage(unsigned target) {
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+
+ if (target == GL_TEXTURE_RECTANGLE_ARB) {
+ LOG(ERROR) << "EGLImage cannot be bound to TEXTURE_RECTANGLE_ARB target";
+ return false;
+ }
+
+ if (target_ && target_ != target) {
+ LOG(ERROR) << "EGLImage can only be bound to one target";
+ return false;
+ }
+ target_ = target;
+
+ // Defer ImageTargetTexture2D if not currently in use.
+ if (!in_use_)
+ return true;
+
+ glEGLImageTargetTexture2DOES(target_, egl_image_);
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+ return true;
+}
+
+void GLImageAndroidNativeBuffer::WillUseTexImage() {
+ DCHECK(egl_image_);
+ DCHECK(!in_use_);
+ in_use_ = true;
+ glEGLImageTargetTexture2DOES(target_, egl_image_);
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+}
+
+void GLImageAndroidNativeBuffer::DidUseTexImage() {
+ DCHECK(in_use_);
+ in_use_ = false;
+
+ if (!release_after_use_)
+ return;
+
+ if (egl_image_for_unbind_ == EGL_NO_IMAGE_KHR) {
+ DCHECK_EQ(0u, texture_id_for_unbind_);
+ glGenTextures(1, &texture_id_for_unbind_);
+
+ {
+ ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_for_unbind_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ char zero[4] = {0, };
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
+ }
+
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ // Need to pass current EGL rendering context to eglCreateImageKHR for
+ // target type EGL_GL_TEXTURE_2D_KHR.
+ egl_image_for_unbind_ = eglCreateImageKHR(
+ GLSurfaceEGL::GetHardwareDisplay(),
+ eglGetCurrentContext(),
+ EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(texture_id_for_unbind_),
+ attrs);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_for_unbind_)
+ << "Error creating EGLImage: " << eglGetError();
+ }
+
+ glEGLImageTargetTexture2DOES(target_, egl_image_for_unbind_);
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+}
+
+void GLImageAndroidNativeBuffer::SetReleaseAfterUse() {
+ release_after_use_ = true;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_android_native_buffer.h b/chromium/ui/gl/gl_image_android_native_buffer.h
new file mode 100644
index 00000000000..28fe5c1ed9d
--- /dev/null
+++ b/chromium/ui/gl/gl_image_android_native_buffer.h
@@ -0,0 +1,40 @@
+// 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_GL_GL_IMAGE_ANDROID_NATIVE_BUFFER_H_
+#define UI_GL_GL_IMAGE_ANDROID_NATIVE_BUFFER_H_
+
+#include "ui/gl/gl_image_egl.h"
+
+namespace gfx {
+
+class GL_EXPORT GLImageAndroidNativeBuffer : public GLImageEGL {
+ public:
+ explicit GLImageAndroidNativeBuffer(gfx::Size size);
+
+ bool Initialize(gfx::GpuMemoryBufferHandle buffer);
+
+ // Overridden from GLImage:
+ virtual void Destroy() OVERRIDE;
+ virtual bool BindTexImage(unsigned target) OVERRIDE;
+ virtual void WillUseTexImage() OVERRIDE;
+ virtual void DidUseTexImage() OVERRIDE;
+ virtual void SetReleaseAfterUse() OVERRIDE;
+
+ protected:
+ virtual ~GLImageAndroidNativeBuffer();
+
+ private:
+ bool release_after_use_;
+ bool in_use_;
+ unsigned target_;
+ EGLImageKHR egl_image_for_unbind_;
+ GLuint texture_id_for_unbind_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLImageAndroidNativeBuffer);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_GL_IMAGE_ANDROID_NATIVE_BUFFER_H_
diff --git a/chromium/ui/gl/gl_image_egl.cc b/chromium/ui/gl/gl_image_egl.cc
index 997ac7a0e74..5531c8d4528 100644
--- a/chromium/ui/gl/gl_image_egl.cc
+++ b/chromium/ui/gl/gl_image_egl.cc
@@ -4,36 +4,24 @@
#include "ui/gl/gl_image_egl.h"
-#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
namespace gfx {
GLImageEGL::GLImageEGL(gfx::Size size)
- : egl_image_(EGL_NO_IMAGE_KHR),
- size_(size),
- release_after_use_(false),
- in_use_(false),
- target_(0) {
-}
-
-GLImageEGL::~GLImageEGL() {
- Destroy();
-}
-
-bool GLImageEGL::Initialize(gfx::GpuMemoryBufferHandle buffer) {
- DCHECK(buffer.native_buffer);
- EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
- EGL_NONE,
- };
- egl_image_ = eglCreateImageKHR(
- GLSurfaceEGL::GetHardwareDisplay(),
- EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID,
- buffer.native_buffer,
- attrs);
-
+ : egl_image_(EGL_NO_IMAGE_KHR), size_(size) {}
+
+GLImageEGL::~GLImageEGL() { Destroy(); }
+
+bool GLImageEGL::Initialize(EGLenum target,
+ EGLClientBuffer buffer,
+ const EGLint* attrs) {
+ DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
+ egl_image_ = eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
+ EGL_NO_CONTEXT,
+ target,
+ buffer,
+ attrs);
if (egl_image_ == EGL_NO_IMAGE_KHR) {
EGLint error = eglGetError();
LOG(ERROR) << "Error creating EGLImage: " << error;
@@ -44,84 +32,19 @@ bool GLImageEGL::Initialize(gfx::GpuMemoryBufferHandle buffer) {
}
void GLImageEGL::Destroy() {
- if (egl_image_ == EGL_NO_IMAGE_KHR)
- return;
-
- EGLBoolean success = eglDestroyImageKHR(
- GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
-
- if (success == EGL_FALSE) {
- EGLint error = eglGetError();
- LOG(ERROR) << "Error destroying EGLImage: " << error;
+ if (egl_image_ != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
+ egl_image_ = EGL_NO_IMAGE_KHR;
}
-
- egl_image_ = EGL_NO_IMAGE_KHR;
}
-gfx::Size GLImageEGL::GetSize() {
- return size_;
-}
+gfx::Size GLImageEGL::GetSize() { return size_; }
bool GLImageEGL::BindTexImage(unsigned target) {
- if (egl_image_ == EGL_NO_IMAGE_KHR) {
- LOG(ERROR) << "NULL EGLImage in BindTexImage";
- return false;
- }
-
- if (target == GL_TEXTURE_RECTANGLE_ARB) {
- LOG(ERROR) << "EGLImage cannot be bound to TEXTURE_RECTANGLE_ARB target";
- return false;
- }
-
- if (target_ && target_ != target) {
- LOG(ERROR) << "EGLImage can only be bound to one target";
- return false;
- }
- target_ = target;
-
- // Defer ImageTargetTexture2D if not currently in use.
- if (!in_use_)
- return true;
-
- glEGLImageTargetTexture2DOES(target_, egl_image_);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+ glEGLImageTargetTexture2DOES(target, egl_image_);
DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
return true;
}
-void GLImageEGL::ReleaseTexImage(unsigned target) {
- // Nothing to do here as image is released after each use or there is no need
- // to release image.
-}
-
-void GLImageEGL::WillUseTexImage() {
- DCHECK(egl_image_);
- DCHECK(!in_use_);
- in_use_ = true;
- glEGLImageTargetTexture2DOES(target_, egl_image_);
- DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
-}
-
-void GLImageEGL::DidUseTexImage() {
- DCHECK(in_use_);
- in_use_ = false;
-
- if (!release_after_use_)
- return;
-
- char zero[4] = { 0, };
- glTexImage2D(target_,
- 0,
- GL_RGBA,
- 1,
- 1,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- &zero);
-}
-
-void GLImageEGL::SetReleaseAfterUse() {
- release_after_use_ = true;
-}
-
} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_egl.h b/chromium/ui/gl/gl_image_egl.h
index 31dd008059a..1339654acbe 100644
--- a/chromium/ui/gl/gl_image_egl.h
+++ b/chromium/ui/gl/gl_image_egl.h
@@ -5,7 +5,7 @@
#ifndef UI_GL_GL_IMAGE_EGL_H_
#define UI_GL_GL_IMAGE_EGL_H_
-#include "ui/gl/gl_bindings.h" // for EGLImageKHR
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image.h"
namespace gfx {
@@ -14,27 +14,25 @@ class GL_EXPORT GLImageEGL : public GLImage {
public:
explicit GLImageEGL(gfx::Size size);
- bool Initialize(gfx::GpuMemoryBufferHandle buffer);
+ bool Initialize(EGLenum target, EGLClientBuffer buffer, const EGLint* attrs);
- // Implement GLImage.
+ // Overridden from GLImage:
virtual void Destroy() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual bool BindTexImage(unsigned target) OVERRIDE;
- virtual void ReleaseTexImage(unsigned target) OVERRIDE;
- virtual void WillUseTexImage() OVERRIDE;
- virtual void DidUseTexImage() OVERRIDE;
- virtual void SetReleaseAfterUse() OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE {}
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
protected:
virtual ~GLImageEGL();
- private:
EGLImageKHR egl_image_;
gfx::Size size_;
- bool release_after_use_;
- bool in_use_;
- unsigned target_;
+ private:
DISALLOW_COPY_AND_ASSIGN(GLImageEGL);
};
diff --git a/chromium/ui/gl/gl_image_glx.cc b/chromium/ui/gl/gl_image_glx.cc
index c7b2522eb38..4b7e883781c 100644
--- a/chromium/ui/gl/gl_image_glx.cc
+++ b/chromium/ui/gl/gl_image_glx.cc
@@ -12,6 +12,7 @@ extern "C" {
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_glx.h"
@@ -20,13 +21,10 @@ namespace gfx {
namespace {
// scoped_ptr functor for XFree(). Use as follows:
-// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
+// scoped_ptr<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
-class ScopedPtrXFree {
- public:
- void operator()(void* x) const {
- ::XFree(x);
- }
+struct ScopedPtrXFree {
+ void operator()(void* x) const { ::XFree(x); }
};
int BindToTextureFormat(int depth) {
@@ -46,15 +44,12 @@ int TextureFormat(int depth) {
} // namespace anonymous
GLImageGLX::GLImageGLX(gfx::PluginWindowHandle window)
- : display_(base::MessagePumpForUI::GetDefaultXDisplay()),
- window_(window),
- pixmap_(0),
- glx_pixmap_(0) {
-}
+ : display_(gfx::GetXDisplay()),
+ window_(window),
+ pixmap_(0),
+ glx_pixmap_(0) {}
-GLImageGLX::~GLImageGLX() {
- Destroy();
-}
+GLImageGLX::~GLImageGLX() { Destroy(); }
bool GLImageGLX::Initialize() {
if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) {
@@ -71,14 +66,11 @@ bool GLImageGLX::Initialize() {
XVisualInfo templ;
templ.visualid = XVisualIDFromVisual(attributes.visual);
int num_visinfo = 0;
- scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visinfo(
- XGetVisualInfo(display_,
- VisualIDMask,
- &templ,
- &num_visinfo));
+ scoped_ptr<XVisualInfo, ScopedPtrXFree> visinfo(
+ XGetVisualInfo(display_, VisualIDMask, &templ, &num_visinfo));
if (!visinfo.get()) {
- LOG(ERROR) << "XGetVisualInfo failed for visual id " <<
- templ.visualid << ".";
+ LOG(ERROR) << "XGetVisualInfo failed for visual id " << templ.visualid
+ << ".";
return false;
}
if (!num_visinfo) {
@@ -87,19 +79,14 @@ bool GLImageGLX::Initialize() {
}
int config_attribs[] = {
- static_cast<int>(GLX_VISUAL_ID),
- static_cast<int>(visinfo->visualid),
- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
- GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT,
- BindToTextureFormat(visinfo->depth), GL_TRUE,
- 0
- };
+ static_cast<int>(GLX_VISUAL_ID), static_cast<int>(visinfo->visualid),
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT,
+ BindToTextureFormat(visinfo->depth), GL_TRUE,
+ 0};
int num_elements = 0;
- scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
- glXChooseFBConfig(display_,
- DefaultScreen(display_),
- config_attribs,
- &num_elements));
+ scoped_ptr<GLXFBConfig, ScopedPtrXFree> config(glXChooseFBConfig(
+ display_, DefaultScreen(display_), config_attribs, &num_elements));
if (!config.get()) {
LOG(ERROR) << "glXChooseFBConfig failed.";
return false;
@@ -125,16 +112,11 @@ bool GLImageGLX::Initialize() {
return false;
}
- int pixmap_attribs[] = {
- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
- GLX_TEXTURE_FORMAT_EXT, TextureFormat(visinfo->depth),
- 0
- };
- glx_pixmap_ = glXCreatePixmap(
- display_,
- *config.get(),
- pixmap_,
- pixmap_attribs);
+ int pixmap_attribs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_TEXTURE_FORMAT_EXT, TextureFormat(visinfo->depth),
+ 0};
+ glx_pixmap_ =
+ glXCreatePixmap(display_, *config.get(), pixmap_, pixmap_attribs);
if (!glx_pixmap_) {
LOG(ERROR) << "glXCreatePixmap failed.";
return false;
@@ -155,9 +137,7 @@ void GLImageGLX::Destroy() {
}
}
-gfx::Size GLImageGLX::GetSize() {
- return size_;
-}
+gfx::Size GLImageGLX::GetSize() { return size_; }
bool GLImageGLX::BindTexImage(unsigned target) {
if (!glx_pixmap_)
@@ -178,10 +158,4 @@ void GLImageGLX::ReleaseTexImage(unsigned target) {
glXReleaseTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT);
}
-void GLImageGLX::WillUseTexImage() {
-}
-
-void GLImageGLX::DidUseTexImage() {
-}
-
} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_glx.h b/chromium/ui/gl/gl_image_glx.h
index fcd8fd19a38..d94520200d8 100644
--- a/chromium/ui/gl/gl_image_glx.h
+++ b/chromium/ui/gl/gl_image_glx.h
@@ -18,13 +18,15 @@ class GL_EXPORT GLImageGLX : public GLImage {
virtual bool Initialize();
- // Implement GLImage.
+ // Overridden from GLImage:
virtual void Destroy() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual bool BindTexImage(unsigned target) OVERRIDE;
virtual void ReleaseTexImage(unsigned target) OVERRIDE;
- virtual void WillUseTexImage() OVERRIDE;
- virtual void DidUseTexImage() OVERRIDE;
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
protected:
virtual ~GLImageGLX();
diff --git a/chromium/ui/gl/gl_image_io_surface.cc b/chromium/ui/gl/gl_image_io_surface.cc
index 23a77778981..566b05e4cc7 100644
--- a/chromium/ui/gl/gl_image_io_surface.cc
+++ b/chromium/ui/gl/gl_image_io_surface.cc
@@ -6,22 +6,19 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
-#include "ui/gl/io_surface_support_mac.h"
+
+// Note that this must be included after gl_bindings.h to avoid conflicts.
+#include <OpenGL/CGLIOSurface.h>
namespace gfx {
GLImageIOSurface::GLImageIOSurface(gfx::Size size)
- : io_surface_support_(IOSurfaceSupport::Initialize()),
- size_(size) {
- CHECK(io_surface_support_);
-}
+ : size_(size) {}
-GLImageIOSurface::~GLImageIOSurface() {
- Destroy();
-}
+GLImageIOSurface::~GLImageIOSurface() { Destroy(); }
bool GLImageIOSurface::Initialize(gfx::GpuMemoryBufferHandle buffer) {
- io_surface_.reset(io_surface_support_->IOSurfaceLookup(buffer.io_surface_id));
+ io_surface_.reset(IOSurfaceLookup(buffer.io_surface_id));
if (!io_surface_) {
LOG(ERROR) << "IOSurface lookup failed";
return false;
@@ -30,12 +27,7 @@ bool GLImageIOSurface::Initialize(gfx::GpuMemoryBufferHandle buffer) {
return true;
}
-void GLImageIOSurface::Destroy() {
-}
-
-gfx::Size GLImageIOSurface::GetSize() {
- return size_;
-}
+gfx::Size GLImageIOSurface::GetSize() { return size_; }
bool GLImageIOSurface::BindTexImage(unsigned target) {
if (target != GL_TEXTURE_RECTANGLE_ARB) {
@@ -45,20 +37,19 @@ bool GLImageIOSurface::BindTexImage(unsigned target) {
return false;
}
- CGLContextObj cgl_context = static_cast<CGLContextObj>(
- GLContext::GetCurrent()->GetHandle());
+ CGLContextObj cgl_context =
+ static_cast<CGLContextObj>(GLContext::GetCurrent()->GetHandle());
DCHECK(io_surface_);
- CGLError cgl_error = io_surface_support_->CGLTexImageIOSurface2D(
- cgl_context,
- target,
- GL_RGBA,
- size_.width(),
- size_.height(),
- GL_BGRA,
- GL_UNSIGNED_INT_8_8_8_8_REV,
- io_surface_.get(),
- 0);
+ CGLError cgl_error = CGLTexImageIOSurface2D(cgl_context,
+ target,
+ GL_RGBA,
+ size_.width(),
+ size_.height(),
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ io_surface_.get(),
+ 0);
if (cgl_error != kCGLNoError) {
LOG(ERROR) << "Error in CGLTexImageIOSurface2D";
return false;
@@ -67,13 +58,4 @@ bool GLImageIOSurface::BindTexImage(unsigned target) {
return true;
}
-void GLImageIOSurface::ReleaseTexImage(unsigned target) {
-}
-
-void GLImageIOSurface::WillUseTexImage() {
-}
-
-void GLImageIOSurface::DidUseTexImage() {
-}
-
} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_io_surface.h b/chromium/ui/gl/gl_image_io_surface.h
index 177098282a6..7825e7da08c 100644
--- a/chromium/ui/gl/gl_image_io_surface.h
+++ b/chromium/ui/gl/gl_image_io_surface.h
@@ -5,11 +5,11 @@
#ifndef UI_GL_GL_IMAGE_IO_SURFACE_H_
#define UI_GL_GL_IMAGE_IO_SURFACE_H_
+#include <IOSurface/IOSurfaceAPI.h>
+
#include "base/mac/scoped_cftyperef.h"
#include "ui/gl/gl_image.h"
-class IOSurfaceSupport;
-
namespace gfx {
class GL_EXPORT GLImageIOSurface : public GLImage {
@@ -18,20 +18,21 @@ class GL_EXPORT GLImageIOSurface : public GLImage {
bool Initialize(gfx::GpuMemoryBufferHandle buffer);
- // Implement GLImage.
- virtual void Destroy() OVERRIDE;
+ // Overridden from GLImage:
+ virtual void Destroy() OVERRIDE {}
virtual gfx::Size GetSize() OVERRIDE;
virtual bool BindTexImage(unsigned target) OVERRIDE;
- virtual void ReleaseTexImage(unsigned target) OVERRIDE;
- virtual void WillUseTexImage() OVERRIDE;
- virtual void DidUseTexImage() OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE {}
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
protected:
virtual ~GLImageIOSurface();
private:
- IOSurfaceSupport* io_surface_support_;
- base::ScopedCFTypeRef<CFTypeRef> io_surface_;
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
gfx::Size size_;
DISALLOW_COPY_AND_ASSIGN(GLImageIOSurface);
diff --git a/chromium/ui/gl/gl_image_shm.cc b/chromium/ui/gl/gl_image_shm.cc
index 076b1fcb793..75ef453eade 100644
--- a/chromium/ui/gl/gl_image_shm.cc
+++ b/chromium/ui/gl/gl_image_shm.cc
@@ -6,7 +6,12 @@
#include "base/debug/trace_event.h"
#include "base/process/process_handle.h"
-#include "ui/gl/gl_bindings.h"
+#include "ui/gl/scoped_binders.h"
+
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+#include "ui/gl/gl_surface_egl.h"
+#endif
namespace gfx {
@@ -64,12 +69,17 @@ GLenum BytesPerPixel(unsigned internalformat) {
GLImageShm::GLImageShm(gfx::Size size, unsigned internalformat)
: size_(size),
- internalformat_(internalformat) {
+ internalformat_(internalformat)
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+ ,
+ egl_texture_id_(0u),
+ egl_image_(EGL_NO_IMAGE_KHR)
+#endif
+{
}
-GLImageShm::~GLImageShm() {
- Destroy();
-}
+GLImageShm::~GLImageShm() { Destroy(); }
bool GLImageShm::Initialize(gfx::GpuMemoryBufferHandle buffer) {
if (!ValidFormat(internalformat_)) {
@@ -96,12 +106,22 @@ bool GLImageShm::Initialize(gfx::GpuMemoryBufferHandle buffer) {
}
void GLImageShm::Destroy() {
-}
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+ if (egl_image_ != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
+ egl_image_ = EGL_NO_IMAGE_KHR;
+ }
-gfx::Size GLImageShm::GetSize() {
- return size_;
+ if (egl_texture_id_) {
+ glDeleteTextures(1, &egl_texture_id_);
+ egl_texture_id_ = 0u;
+ }
+#endif
}
+gfx::Size GLImageShm::GetSize() { return size_; }
+
bool GLImageShm::BindTexImage(unsigned target) {
TRACE_EVENT0("gpu", "GLImageShm::BindTexImage");
DCHECK(shared_memory_);
@@ -115,6 +135,65 @@ bool GLImageShm::BindTexImage(unsigned target) {
}
DCHECK(shared_memory_->memory());
+
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+ if (target == GL_TEXTURE_EXTERNAL_OES) {
+ if (egl_image_ == EGL_NO_IMAGE_KHR) {
+ DCHECK_EQ(0u, egl_texture_id_);
+ glGenTextures(1, &egl_texture_id_);
+
+ {
+ ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0, // mip level
+ TextureFormat(internalformat_),
+ size_.width(),
+ size_.height(),
+ 0, // border
+ DataFormat(internalformat_),
+ DataType(internalformat_),
+ shared_memory_->memory());
+ }
+
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ // Need to pass current EGL rendering context to eglCreateImageKHR for
+ // target type EGL_GL_TEXTURE_2D_KHR.
+ egl_image_ =
+ eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
+ eglGetCurrentContext(),
+ EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
+ attrs);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
+ << "Error creating EGLImage: " << eglGetError();
+ } else {
+ ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
+
+ glTexSubImage2D(GL_TEXTURE_2D,
+ 0, // mip level
+ 0, // x-offset
+ 0, // y-offset
+ size_.width(),
+ size_.height(),
+ DataFormat(internalformat_),
+ DataType(internalformat_),
+ shared_memory_->memory());
+ }
+
+ glEGLImageTargetTexture2DOES(target, egl_image_);
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+ shared_memory_->Unmap();
+ return true;
+ }
+#endif
+
+ DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
glTexImage2D(target,
0, // mip level
TextureFormat(internalformat_),
@@ -129,13 +208,4 @@ bool GLImageShm::BindTexImage(unsigned target) {
return true;
}
-void GLImageShm::ReleaseTexImage(unsigned target) {
-}
-
-void GLImageShm::WillUseTexImage() {
-}
-
-void GLImageShm::DidUseTexImage() {
-}
-
} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_shm.h b/chromium/ui/gl/gl_image_shm.h
index efff1ed52bc..079bab90d0a 100644
--- a/chromium/ui/gl/gl_image_shm.h
+++ b/chromium/ui/gl/gl_image_shm.h
@@ -6,6 +6,7 @@
#define UI_GL_GL_IMAGE_SHM_H_
#include "base/memory/scoped_ptr.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image.h"
namespace gfx {
@@ -20,9 +21,11 @@ class GL_EXPORT GLImageShm : public GLImage {
virtual void Destroy() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual bool BindTexImage(unsigned target) OVERRIDE;
- virtual void ReleaseTexImage(unsigned target) OVERRIDE;
- virtual void WillUseTexImage() OVERRIDE;
- virtual void DidUseTexImage() OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE {}
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
protected:
virtual ~GLImageShm();
@@ -31,6 +34,11 @@ class GL_EXPORT GLImageShm : public GLImage {
scoped_ptr<base::SharedMemory> shared_memory_;
gfx::Size size_;
unsigned internalformat_;
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
+ defined(USE_OZONE)
+ GLuint egl_texture_id_;
+ EGLImageKHR egl_image_;
+#endif
DISALLOW_COPY_AND_ASSIGN(GLImageShm);
};
diff --git a/chromium/ui/gl/gl_image_stub.cc b/chromium/ui/gl/gl_image_stub.cc
index 36781f82346..d789ce50e68 100644
--- a/chromium/ui/gl/gl_image_stub.cc
+++ b/chromium/ui/gl/gl_image_stub.cc
@@ -6,31 +6,12 @@
namespace gfx {
-GLImageStub::GLImageStub() {
-}
+GLImageStub::GLImageStub() {}
-GLImageStub::~GLImageStub() {
- Destroy();
-}
+GLImageStub::~GLImageStub() { Destroy(); }
-void GLImageStub::Destroy() {
-}
+gfx::Size GLImageStub::GetSize() { return gfx::Size(1, 1); }
-gfx::Size GLImageStub::GetSize() {
- return gfx::Size(1, 1);
-}
-
-bool GLImageStub::BindTexImage(unsigned target) {
- return true;
-}
-
-void GLImageStub::ReleaseTexImage(unsigned target) {
-}
-
-void GLImageStub::WillUseTexImage() {
-}
-
-void GLImageStub::DidUseTexImage() {
-}
+bool GLImageStub::BindTexImage(unsigned target) { return true; }
} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_stub.h b/chromium/ui/gl/gl_image_stub.h
index e72ec3efc09..5f2fdb2fe70 100644
--- a/chromium/ui/gl/gl_image_stub.h
+++ b/chromium/ui/gl/gl_image_stub.h
@@ -14,13 +14,15 @@ class GL_EXPORT GLImageStub : public GLImage {
public:
GLImageStub();
- // Implement GLImage.
- virtual void Destroy() OVERRIDE;
+ // Overridden from GLImage:
+ virtual void Destroy() OVERRIDE {}
virtual gfx::Size GetSize() OVERRIDE;
virtual bool BindTexImage(unsigned target) OVERRIDE;
- virtual void ReleaseTexImage(unsigned target) OVERRIDE;
- virtual void WillUseTexImage() OVERRIDE;
- virtual void DidUseTexImage() OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE {}
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
protected:
virtual ~GLImageStub();
diff --git a/chromium/ui/gl/gl_image_surface_texture.cc b/chromium/ui/gl/gl_image_surface_texture.cc
new file mode 100644
index 00000000000..8d0a0e7e22b
--- /dev/null
+++ b/chromium/ui/gl/gl_image_surface_texture.cc
@@ -0,0 +1,75 @@
+// 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/gl/gl_image_surface_texture.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/gl/android/surface_texture.h"
+#include "ui/gl/android/surface_texture_tracker.h"
+
+namespace gfx {
+
+GLImageSurfaceTexture::GLImageSurfaceTexture(gfx::Size size)
+ : size_(size), texture_id_(0) {}
+
+GLImageSurfaceTexture::~GLImageSurfaceTexture() { Destroy(); }
+
+bool GLImageSurfaceTexture::Initialize(gfx::GpuMemoryBufferHandle buffer) {
+ DCHECK(!surface_texture_);
+ surface_texture_ =
+ SurfaceTextureTracker::GetInstance()->AcquireSurfaceTexture(
+ buffer.surface_texture_id.primary_id,
+ buffer.surface_texture_id.secondary_id);
+ return !!surface_texture_;
+}
+
+void GLImageSurfaceTexture::Destroy() {
+ surface_texture_ = NULL;
+ texture_id_ = 0;
+}
+
+gfx::Size GLImageSurfaceTexture::GetSize() { return size_; }
+
+bool GLImageSurfaceTexture::BindTexImage(unsigned target) {
+ TRACE_EVENT0("gpu", "GLImageSurfaceTexture::BindTexImage");
+
+ if (target != GL_TEXTURE_EXTERNAL_OES) {
+ LOG(ERROR)
+ << "Surface texture can only be bound to TEXTURE_EXTERNAL_OES target";
+ return false;
+ }
+
+ GLint texture_id;
+ glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
+ DCHECK(texture_id);
+
+ if (texture_id_ && texture_id_ != texture_id) {
+ LOG(ERROR) << "Surface texture can only be bound to one texture ID";
+ return false;
+ }
+
+ DCHECK(surface_texture_);
+ if (texture_id != texture_id_) {
+ // Note: Surface textures used as gpu memory buffers are created with an
+ // initial dummy texture id of 0. We need to call DetachFromGLContext() here
+ // to detach from the dummy texture before we can attach to a real texture
+ // id. DetachFromGLContext() will delete the texture for the current
+ // attachment point so it's important that this is never called when
+ // attached to a real texture id. Detaching from the dummy texture id should
+ // not cause any problems as the GL should silently ignore 0 when passed to
+ // glDeleteTextures.
+ DCHECK_EQ(0, texture_id_);
+ surface_texture_->DetachFromGLContext();
+
+ // This will attach the surface texture to the texture currently bound to
+ // GL_TEXTURE_EXTERNAL_OES target.
+ surface_texture_->AttachToGLContext();
+ texture_id_ = texture_id;
+ }
+
+ surface_texture_->UpdateTexImage();
+ return true;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_image_surface_texture.h b/chromium/ui/gl/gl_image_surface_texture.h
new file mode 100644
index 00000000000..0b771a37f8b
--- /dev/null
+++ b/chromium/ui/gl/gl_image_surface_texture.h
@@ -0,0 +1,45 @@
+// 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_GL_GL_IMAGE_SURFACE_TEXTURE_H_
+#define UI_GL_GL_IMAGE_SURFACE_TEXTURE_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image.h"
+
+namespace gfx {
+
+class SurfaceTexture;
+
+class GL_EXPORT GLImageSurfaceTexture : public GLImage {
+ public:
+ explicit GLImageSurfaceTexture(gfx::Size size);
+
+ bool Initialize(gfx::GpuMemoryBufferHandle buffer);
+
+ // Overridden from GLImage:
+ virtual void Destroy() OVERRIDE;
+ virtual gfx::Size GetSize() OVERRIDE;
+ virtual bool BindTexImage(unsigned target) OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE {}
+ virtual void WillUseTexImage() OVERRIDE {}
+ virtual void DidUseTexImage() OVERRIDE {}
+ virtual void WillModifyTexImage() OVERRIDE {}
+ virtual void DidModifyTexImage() OVERRIDE {}
+
+ protected:
+ virtual ~GLImageSurfaceTexture();
+
+ private:
+ scoped_refptr<SurfaceTexture> surface_texture_;
+ gfx::Size size_;
+ GLint texture_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLImageSurfaceTexture);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_GL_IMAGE_SURFACE_TEXTURE_H_
diff --git a/chromium/ui/gl/gl_implementation.cc b/chromium/ui/gl/gl_implementation.cc
index d8de8c26913..9d6b34ea1c7 100644
--- a/chromium/ui/gl/gl_implementation.cc
+++ b/chromium/ui/gl/gl_implementation.cc
@@ -11,6 +11,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_gl_api_implementation.h"
namespace gfx {
@@ -45,21 +46,6 @@ void CleanupNativeLibraries(void* unused) {
}
}
-bool ExportsCoreFunctionsFromGetProcAddress(GLImplementation implementation) {
- switch (GetGLImplementation()) {
- case kGLImplementationDesktopGL:
- case kGLImplementationOSMesaGL:
- case kGLImplementationAppleGL:
- case kGLImplementationMockGL:
- return true;
- case kGLImplementationEGLGLES2:
- return false;
- default:
- NOTREACHED();
- return true;
- }
-}
-
}
base::ThreadLocalPointer<GLApi>* g_current_gl_context_tls = NULL;
@@ -137,7 +123,7 @@ void SetGLGetProcAddressProc(GLGetProcAddressProc proc) {
g_get_proc_address = proc;
}
-void* GetGLCoreProcAddress(const char* name) {
+void* GetGLProcAddress(const char* name) {
DCHECK(g_gl_implementation != kGLImplementationNone);
if (g_libraries) {
@@ -148,8 +134,7 @@ void* GetGLCoreProcAddress(const char* name) {
return proc;
}
}
- if (ExportsCoreFunctionsFromGetProcAddress(g_gl_implementation) &&
- g_get_proc_address) {
+ if (g_get_proc_address) {
void* proc = g_get_proc_address(name);
if (proc)
return proc;
@@ -158,17 +143,25 @@ void* GetGLCoreProcAddress(const char* name) {
return NULL;
}
-void* GetGLProcAddress(const char* name) {
- DCHECK(g_gl_implementation != kGLImplementationNone);
+void InitializeNullDrawGLBindings() {
+ // This is platform independent, so it does not need to live in a platform
+ // specific implementation file.
+ InitializeNullDrawGLBindingsGL();
+}
- void* proc = GetGLCoreProcAddress(name);
- if (!proc && g_get_proc_address) {
- proc = g_get_proc_address(name);
- if (proc)
- return proc;
- }
+bool HasInitializedNullDrawGLBindings() {
+ return HasInitializedNullDrawGLBindingsGL();
+}
- return proc;
+DisableNullDrawGLBindings::DisableNullDrawGLBindings() {
+ initial_enabled_ = SetNullDrawGLBindingsEnabledGL(false);
}
+DisableNullDrawGLBindings::~DisableNullDrawGLBindings() {
+ SetNullDrawGLBindingsEnabledGL(initial_enabled_);
+}
+
+GLWindowSystemBindingInfo::GLWindowSystemBindingInfo()
+ : direct_rendering(true) {}
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_implementation.h b/chromium/ui/gl/gl_implementation.h
index 212978270d6..7319b47c4dc 100644
--- a/chromium/ui/gl/gl_implementation.h
+++ b/chromium/ui/gl/gl_implementation.h
@@ -27,10 +27,12 @@ enum GLImplementation {
kGLImplementationMockGL
};
-struct GLWindowSystemBindingInfo {
+struct GL_EXPORT GLWindowSystemBindingInfo {
+ GLWindowSystemBindingInfo();
std::string vendor;
std::string version;
std::string extensions;
+ bool direct_rendering;
};
void GetAllowedGLImplementations(std::vector<GLImplementation>* impls);
@@ -42,15 +44,34 @@ typedef void* (*GLGetProcAddressProc)(const char* name);
#endif
// Initialize a particular GL implementation.
-GL_EXPORT bool InitializeGLBindings(GLImplementation implementation);
+GL_EXPORT bool InitializeStaticGLBindings(GLImplementation implementation);
-// Initialize extension function bindings for a GL implementation.
-GL_EXPORT bool InitializeGLExtensionBindings(GLImplementation implementation,
- GLContext* context);
+// Initialize function bindings that depend on the context for a GL
+// implementation.
+GL_EXPORT bool InitializeDynamicGLBindings(GLImplementation implementation,
+ GLContext* context);
// Initialize Debug logging wrappers for GL bindings.
void InitializeDebugGLBindings();
+// Initialize stub methods for drawing operations in the GL bindings. The
+// null draw bindings default to enabled, so that draw operations do nothing.
+void InitializeNullDrawGLBindings();
+
+// TODO(danakj): Remove this when all test suites are using null-draw.
+GL_EXPORT bool HasInitializedNullDrawGLBindings();
+
+// Once initialized, instantiating this turns the stub methods for drawing
+// operations off allowing drawing will occur while the object is alive.
+class GL_EXPORT DisableNullDrawGLBindings {
+ public:
+ DisableNullDrawGLBindings();
+ ~DisableNullDrawGLBindings();
+
+ private:
+ bool initial_enabled_;
+};
+
GL_EXPORT void ClearGLBindings();
// Set the current GL implementation.
@@ -76,14 +97,16 @@ void AddGLNativeLibrary(base::NativeLibrary library);
void UnloadGLNativeLibraries();
// Set an additional function that will be called to find GL entry points.
-void SetGLGetProcAddressProc(GLGetProcAddressProc proc);
-
-// Find a core (non-extension) entry point in the current GL implementation. On
-// EGL based implementations core entry points will not be queried through
-// GLGetProcAddressProc.
-void* GetGLCoreProcAddress(const char* name);
-
-// Find an entry point in the current GL implementation.
+// Exported so that tests may set the function used in the mock implementation.
+GL_EXPORT void SetGLGetProcAddressProc(GLGetProcAddressProc proc);
+
+// Find an entry point in the current GL implementation. Note that the function
+// may return a non-null pointer to something else than the GL function if an
+// unsupported function is queried. Spec-compliant eglGetProcAddress and
+// glxGetProcAddress are allowed to return garbage for unsupported functions,
+// and when querying functions from the EGL library supplied by Android, it may
+// return a function that prints a log message about the function being
+// unsupported.
void* GetGLProcAddress(const char* name);
// Return information about the GL window system binding implementation (e.g.,
diff --git a/chromium/ui/gl/gl_implementation_android.cc b/chromium/ui/gl/gl_implementation_android.cc
index f644866b3d8..77dcb90f396 100644
--- a/chromium/ui/gl/gl_implementation_android.cc
+++ b/chromium/ui/gl/gl_implementation_android.cc
@@ -9,9 +9,11 @@
#include "base/native_library.h"
#include "base/path_service.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_egl_api_implementation.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_implementation_osmesa.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
namespace gfx {
@@ -27,39 +29,26 @@ void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
}
-base::NativeLibrary LoadLibrary(const base::FilePath& filename) {
- std::string error;
- base::NativeLibrary library = base::LoadNativeLibrary(filename, &error);
- if (!library) {
- DVLOG(1) << "Failed to load " << filename.MaybeAsASCII() << ": " << error;
- return NULL;
- }
- return library;
-}
-
-base::NativeLibrary LoadLibrary(const char* filename) {
- return LoadLibrary(base::FilePath(filename));
-}
-
} // namespace
void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationEGLGLES2);
+ impls->push_back(kGLImplementationOSMesaGL);
}
-bool InitializeGLBindings(GLImplementation implementation) {
+bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
- if (GetGLImplementation() != kGLImplementationNone)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
switch (implementation) {
case kGLImplementationEGLGLES2: {
- base::NativeLibrary gles_library = LoadLibrary("libGLESv2.so");
+ base::NativeLibrary gles_library =
+ LoadLibraryAndPrintError("libGLESv2.so");
if (!gles_library)
return false;
- base::NativeLibrary egl_library = LoadLibrary("libEGL.so");
+ base::NativeLibrary egl_library = LoadLibraryAndPrintError("libEGL.so");
if (!egl_library) {
base::UnloadNativeLibrary(gles_library);
return false;
@@ -81,8 +70,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(gles_library);
SetGLImplementation(kGLImplementationEGLGLES2);
- InitializeGLBindingsGL();
- InitializeGLBindingsEGL();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsEGL();
// These two functions take single precision float rather than double
// precision float parameters in GLES.
@@ -90,31 +79,44 @@ bool InitializeGLBindings(GLImplementation implementation) {
::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
break;
}
+ case kGLImplementationOSMesaGL:
+ InitializeStaticGLBindingsOSMesaGL();
+ break;
case kGLImplementationMockGL: {
- SetGLGetProcAddressProc(GetMockGLProcAddress);
SetGLImplementation(kGLImplementationMockGL);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
default:
- NOTIMPLEMENTED() << "InitializeGLBindings on Android";
+ NOTIMPLEMENTED() << "InitializeStaticGLBindings on Android";
return false;
}
return true;
}
-bool InitializeGLExtensionBindings(GLImplementation implementation,
- GLContext* context) {
+bool InitializeDynamicGLBindings(GLImplementation implementation,
+ GLContext* context) {
switch (implementation) {
case kGLImplementationEGLGLES2:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsEGL(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsEGL(context);
+ break;
+ case kGLImplementationOSMesaGL:
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsOSMESA(context);
break;
case kGLImplementationMockGL:
- InitializeGLExtensionBindingsGL(context);
+ if (!context) {
+ scoped_refptr<GLContextStubWithExtensions> mock_context(
+ new GLContextStubWithExtensions());
+ mock_context->SetGLVersionString("opengl es 3.0");
+ InitializeDynamicGLBindingsGL(mock_context.get());
+ } else
+ InitializeDynamicGLBindingsGL(context);
break;
default:
+ NOTREACHED() << "InitializeDynamicGLBindings on Android";
return false;
}
@@ -122,11 +124,15 @@ bool InitializeGLExtensionBindings(GLImplementation implementation,
}
void InitializeDebugGLBindings() {
+ InitializeDebugGLBindingsEGL();
+ InitializeDebugGLBindingsGL();
+ InitializeDebugGLBindingsOSMESA();
}
void ClearGLBindings() {
ClearGLBindingsEGL();
ClearGLBindingsGL();
+ ClearGLBindingsOSMESA();
SetGLImplementation(kGLImplementationNone);
UnloadGLNativeLibraries();
diff --git a/chromium/ui/gl/gl_implementation_linux.cc b/chromium/ui/gl/gl_implementation_linux.cc
deleted file mode 100644
index ba7a8094be9..00000000000
--- a/chromium/ui/gl/gl_implementation_linux.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/gl_implementation_linux.h"
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/native_library.h"
-#include "base/path_service.h"
-#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_gl_api_implementation.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_osmesa_api_implementation.h"
-
-namespace gfx {
-
-// Load a library, printing an error message on failure.
-base::NativeLibrary LoadLibrary(const base::FilePath& filename) {
- std::string error;
- base::NativeLibrary library = base::LoadNativeLibrary(filename, &error);
- if (!library) {
- DVLOG(1) << "Failed to load " << filename.MaybeAsASCII() << ": " << error;
- return NULL;
- }
- return library;
-}
-
-base::NativeLibrary LoadLibrary(const char* filename) {
- return LoadLibrary(base::FilePath(filename));
-}
-
-bool InitializeGLBindingsOSMesaGL() {
- base::FilePath module_path;
- if (!PathService::Get(base::DIR_MODULE, &module_path)) {
- LOG(ERROR) << "PathService::Get failed.";
- return false;
- }
-
- base::NativeLibrary library = LoadLibrary(module_path.Append("libosmesa.so"));
- if (!library)
- return false;
-
- GLGetProcAddressProc get_proc_address =
- reinterpret_cast<GLGetProcAddressProc>(
- base::GetFunctionPointerFromNativeLibrary(library,
- "OSMesaGetProcAddress"));
- if (!get_proc_address) {
- LOG(ERROR) << "OSMesaGetProcAddress not found.";
- base::UnloadNativeLibrary(library);
- return false;
- }
-
- SetGLGetProcAddressProc(get_proc_address);
- AddGLNativeLibrary(library);
- SetGLImplementation(kGLImplementationOSMesaGL);
-
- InitializeGLBindingsGL();
- InitializeGLBindingsOSMESA();
- return true;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gl/gl_implementation_linux.h b/chromium/ui/gl/gl_implementation_linux.h
deleted file mode 100644
index 31b57980327..00000000000
--- a/chromium/ui/gl/gl_implementation_linux.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/files/file_path.h"
-#include "base/native_library.h"
-
-namespace gfx {
-
-bool InitializeGLBindingsOSMesaGL();
-base::NativeLibrary LoadLibrary(const char* filename);
-base::NativeLibrary LoadLibrary(const base::FilePath& filename);
-
-} // namespace gfx
diff --git a/chromium/ui/gl/gl_implementation_mac.cc b/chromium/ui/gl/gl_implementation_mac.cc
index 36bb7e37e50..10114061dce 100644
--- a/chromium/ui/gl/gl_implementation_mac.cc
+++ b/chromium/ui/gl/gl_implementation_mac.cc
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "base/threading/thread_restrictions.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
@@ -26,12 +27,11 @@ void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationOSMesaGL);
}
-bool InitializeGLBindings(GLImplementation implementation) {
+bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
- if (GetGLImplementation() != kGLImplementationNone)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
// Allow the main thread or another to initialize these bindings
// after instituting restrictions on I/O. Going forward they will
@@ -77,8 +77,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(library);
SetGLImplementation(kGLImplementationOSMesaGL);
- InitializeGLBindingsGL();
- InitializeGLBindingsOSMESA();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsOSMESA();
break;
}
case kGLImplementationDesktopGL:
@@ -93,13 +93,12 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(library);
SetGLImplementation(implementation);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
case kGLImplementationMockGL: {
- SetGLGetProcAddressProc(GetMockGLProcAddress);
SetGLImplementation(kGLImplementationMockGL);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
default:
@@ -109,19 +108,25 @@ bool InitializeGLBindings(GLImplementation implementation) {
return true;
}
-bool InitializeGLExtensionBindings(GLImplementation implementation,
+bool InitializeDynamicGLBindings(GLImplementation implementation,
GLContext* context) {
switch (implementation) {
case kGLImplementationOSMesaGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsOSMESA(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsOSMESA(context);
break;
case kGLImplementationDesktopGL:
case kGLImplementationAppleGL:
- InitializeGLExtensionBindingsGL(context);
+ InitializeDynamicGLBindingsGL(context);
break;
case kGLImplementationMockGL:
- InitializeGLExtensionBindingsGL(context);
+ if (!context) {
+ scoped_refptr<GLContextStubWithExtensions> mock_context(
+ new GLContextStubWithExtensions());
+ mock_context->SetGLVersionString("3.0");
+ InitializeDynamicGLBindingsGL(mock_context.get());
+ } else
+ InitializeDynamicGLBindingsGL(context);
break;
default:
return false;
diff --git a/chromium/ui/gl/gl_implementation_osmesa.cc b/chromium/ui/gl/gl_implementation_osmesa.cc
new file mode 100644
index 00000000000..90de6909b91
--- /dev/null
+++ b/chromium/ui/gl/gl_implementation_osmesa.cc
@@ -0,0 +1,64 @@
+// 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/gl/gl_implementation_osmesa.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_gl_api_implementation.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_osmesa_api_implementation.h"
+
+namespace gfx {
+
+base::NativeLibrary LoadLibraryAndPrintError(const base::FilePath& filename) {
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary library = base::LoadNativeLibrary(filename, &error);
+ if (!library) {
+ LOG(ERROR) << "Failed to load " << filename.MaybeAsASCII() << ": "
+ << error.ToString();
+ return NULL;
+ }
+ return library;
+}
+
+base::NativeLibrary LoadLibraryAndPrintError(const char* filename) {
+ return LoadLibraryAndPrintError(base::FilePath(filename));
+}
+
+bool InitializeStaticGLBindingsOSMesaGL() {
+ base::FilePath module_path;
+ if (!PathService::Get(base::DIR_MODULE, &module_path)) {
+ LOG(ERROR) << "PathService::Get failed.";
+ return false;
+ }
+
+ base::FilePath library_path = module_path.Append("libosmesa.so");
+ base::NativeLibrary library = LoadLibraryAndPrintError(library_path);
+ if (!library)
+ return false;
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<GLGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "OSMesaGetProcAddress"));
+ if (!get_proc_address) {
+ LOG(ERROR) << "OSMesaGetProcAddress not found.";
+ base::UnloadNativeLibrary(library);
+ return false;
+ }
+
+ SetGLGetProcAddressProc(get_proc_address);
+ AddGLNativeLibrary(library);
+ SetGLImplementation(kGLImplementationOSMesaGL);
+
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsOSMESA();
+ return true;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_implementation_osmesa.h b/chromium/ui/gl/gl_implementation_osmesa.h
new file mode 100644
index 00000000000..595c24edc7a
--- /dev/null
+++ b/chromium/ui/gl/gl_implementation_osmesa.h
@@ -0,0 +1,19 @@
+// 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_GL_GL_IMPLEMENTATION_OSMESA_
+#define UI_GL_GL_IMPLEMENTATION_OSMESA_
+
+#include "base/files/file_path.h"
+#include "base/native_library.h"
+
+namespace gfx {
+
+bool InitializeStaticGLBindingsOSMesaGL();
+base::NativeLibrary LoadLibraryAndPrintError(const char* filename);
+base::NativeLibrary LoadLibraryAndPrintError(const base::FilePath& filename);
+
+} // namespace gfx
+
+#endif // UI_GL_GL_IMPLEMENTATION_OSMESA_
diff --git a/chromium/ui/gl/gl_implementation_ozone.cc b/chromium/ui/gl/gl_implementation_ozone.cc
index 10ab44d5b25..ca71d75d37f 100644
--- a/chromium/ui/gl/gl_implementation_ozone.cc
+++ b/chromium/ui/gl/gl_implementation_ozone.cc
@@ -3,14 +3,15 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_egl_api_implementation.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_implementation_linux.h"
+#include "ui/gl/gl_implementation_osmesa.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
#include "ui/ozone/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
namespace gfx {
@@ -32,25 +33,24 @@ void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationOSMesaGL);
}
-bool InitializeGLBindings(GLImplementation implementation) {
+bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
- if (GetGLImplementation() != kGLImplementationNone)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
switch (implementation) {
case kGLImplementationOSMesaGL:
- return InitializeGLBindingsOSMesaGL();
+ return InitializeStaticGLBindingsOSMesaGL();
case kGLImplementationEGLGLES2:
- ui::OzonePlatform::Initialize();
- if (!gfx::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings(
+ ui::OzonePlatform::InitializeForGPU();
+ if (!ui::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings(
base::Bind(&AddGLNativeLibrary),
base::Bind(&SetGLGetProcAddressProc)))
return false;
SetGLImplementation(kGLImplementationEGLGLES2);
- InitializeGLBindingsGL();
- InitializeGLBindingsEGL();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsEGL();
// These two functions take single precision float rather than double
// precision float parameters in GLES.
@@ -58,9 +58,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
break;
case kGLImplementationMockGL: {
- SetGLGetProcAddressProc(GetMockGLProcAddress);
SetGLImplementation(kGLImplementationMockGL);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
default:
@@ -72,19 +71,25 @@ bool InitializeGLBindings(GLImplementation implementation) {
return true;
}
-bool InitializeGLExtensionBindings(GLImplementation implementation,
- GLContext* context) {
+bool InitializeDynamicGLBindings(GLImplementation implementation,
+ GLContext* context) {
switch (implementation) {
case kGLImplementationOSMesaGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsOSMESA(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsOSMESA(context);
break;
case kGLImplementationEGLGLES2:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsEGL(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsEGL(context);
break;
case kGLImplementationMockGL:
- InitializeGLExtensionBindingsGL(context);
+ if (!context) {
+ scoped_refptr<GLContextStubWithExtensions> mock_context(
+ new GLContextStubWithExtensions());
+ mock_context->SetGLVersionString("3.0");
+ InitializeDynamicGLBindingsGL(mock_context.get());
+ } else
+ InitializeDynamicGLBindingsGL(context);
break;
default:
return false;
diff --git a/chromium/ui/gl/gl_implementation_win.cc b/chromium/ui/gl/gl_implementation_win.cc
index 87328a306f8..ea3df874851 100644
--- a/chromium/ui/gl/gl_implementation_win.cc
+++ b/chromium/ui/gl/gl_implementation_win.cc
@@ -17,10 +17,12 @@
#include "base/threading/thread_restrictions.h"
#include "base/win/windows_version.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_egl_api_implementation.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
+#include "ui/gl/gl_surface_wgl.h"
#include "ui/gl/gl_wgl_api_implementation.h"
#if defined(ENABLE_SWIFTSHADER)
@@ -106,12 +108,11 @@ void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationOSMesaGL);
}
-bool InitializeGLBindings(GLImplementation implementation) {
+bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
- if (GetGLImplementation() != kGLImplementationNone)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
// Allow the main thread or another to initialize these bindings
// after instituting restrictions on I/O. Going forward they will
@@ -148,8 +149,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(library);
SetGLImplementation(kGLImplementationOSMesaGL);
- InitializeGLBindingsGL();
- InitializeGLBindingsOSMESA();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsOSMESA();
break;
}
case kGLImplementationEGLGLES2: {
@@ -234,8 +235,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(gles_library);
SetGLImplementation(kGLImplementationEGLGLES2);
- InitializeGLBindingsGL();
- InitializeGLBindingsEGL();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsEGL();
// These two functions take single precision float rather than double
// precision float parameters in GLES.
@@ -244,8 +245,6 @@ bool InitializeGLBindings(GLImplementation implementation) {
break;
}
case kGLImplementationDesktopGL: {
- // When using Windows OpenGL, first try wglGetProcAddress and then
- // Windows GetProcAddress.
base::NativeLibrary library = base::LoadNativeLibrary(
base::FilePath(L"opengl32.dll"), NULL);
if (!library) {
@@ -267,14 +266,52 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(library);
SetGLImplementation(kGLImplementationDesktopGL);
- InitializeGLBindingsGL();
- InitializeGLBindingsWGL();
+ // Initialize GL surface and get some functions needed for the context
+ // creation below.
+ if (!GLSurfaceWGL::InitializeOneOff()) {
+ LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
+ return false;
+ }
+ wglCreateContextProc wglCreateContextFn =
+ reinterpret_cast<wglCreateContextProc>(
+ GetGLProcAddress("wglCreateContext"));
+ wglDeleteContextProc wglDeleteContextFn =
+ reinterpret_cast<wglDeleteContextProc>(
+ GetGLProcAddress("wglDeleteContext"));
+ wglMakeCurrentProc wglMakeCurrentFn =
+ reinterpret_cast<wglMakeCurrentProc>(
+ GetGLProcAddress("wglMakeCurrent"));
+
+ // Create a temporary GL context to bind to entry points. This is needed
+ // because wglGetProcAddress is specified to return NULL for all queries
+ // if a context is not current in MSDN documentation, and the static
+ // bindings may contain functions that need to be queried with
+ // wglGetProcAddress. OpenGL wiki further warns that other error values
+ // than NULL could also be returned from wglGetProcAddress on some
+ // implementations, so we need to clear the WGL bindings and reinitialize
+ // them after the context creation.
+ HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
+ if (!gl_context) {
+ LOG(ERROR) << "Failed to create temporary context.";
+ return false;
+ }
+ if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
+ LOG(ERROR) << "Failed to make temporary GL context current.";
+ wglDeleteContextFn(gl_context);
+ return false;
+ }
+
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsWGL();
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(gl_context);
+
break;
}
case kGLImplementationMockGL: {
- SetGLGetProcAddressProc(GetMockGLProcAddress);
SetGLImplementation(kGLImplementationMockGL);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
default:
@@ -284,23 +321,29 @@ bool InitializeGLBindings(GLImplementation implementation) {
return true;
}
-bool InitializeGLExtensionBindings(GLImplementation implementation,
+bool InitializeDynamicGLBindings(GLImplementation implementation,
GLContext* context) {
switch (implementation) {
case kGLImplementationOSMesaGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsOSMESA(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsOSMESA(context);
break;
case kGLImplementationEGLGLES2:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsEGL(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsEGL(context);
break;
case kGLImplementationDesktopGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsWGL(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsWGL(context);
break;
case kGLImplementationMockGL:
- InitializeGLExtensionBindingsGL(context);
+ if (!context) {
+ scoped_refptr<GLContextStubWithExtensions> mock_context(
+ new GLContextStubWithExtensions());
+ mock_context->SetGLVersionString("3.0");
+ InitializeDynamicGLBindingsGL(mock_context.get());
+ } else
+ InitializeDynamicGLBindingsGL(context);
break;
default:
return false;
@@ -334,7 +377,6 @@ bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
default:
return false;
}
- return false;
}
} // namespace gfx
diff --git a/chromium/ui/gl/gl_implementation_x11.cc b/chromium/ui/gl/gl_implementation_x11.cc
index 01ee655ff11..176f7d27892 100644
--- a/chromium/ui/gl/gl_implementation_x11.cc
+++ b/chromium/ui/gl/gl_implementation_x11.cc
@@ -8,11 +8,12 @@
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_egl_api_implementation.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_glx_api_implementation.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_implementation_linux.h"
+#include "ui/gl/gl_implementation_osmesa.h"
#include "ui/gl/gl_osmesa_api_implementation.h"
#include "ui/gl/gl_switches.h"
@@ -30,6 +31,15 @@ void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
}
+#if defined(OS_OPENBSD)
+const char kGLLibraryName[] = "libGL.so";
+#else
+const char kGLLibraryName[] = "libGL.so.1";
+#endif
+
+const char kGLESv2LibraryName[] = "libGLESv2.so.2";
+const char kEGLLibraryName[] = "libEGL.so.1";
+
} // namespace
void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
@@ -38,12 +48,11 @@ void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
impls->push_back(kGLImplementationOSMesaGL);
}
-bool InitializeGLBindings(GLImplementation implementation) {
+bool InitializeStaticGLBindings(GLImplementation implementation) {
// Prevent reinitialization with a different implementation. Once the gpu
// unit tests have initialized with kGLImplementationMock, we don't want to
// later switch to another GL implementation.
- if (GetGLImplementation() != kGLImplementationNone)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
// Allow the main thread or another to initialize these bindings
// after instituting restrictions on I/O. Going forward they will
@@ -53,21 +62,17 @@ bool InitializeGLBindings(GLImplementation implementation) {
switch (implementation) {
case kGLImplementationOSMesaGL:
- return InitializeGLBindingsOSMesaGL();
+ return InitializeStaticGLBindingsOSMesaGL();
case kGLImplementationDesktopGL: {
base::NativeLibrary library = NULL;
const CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kTestGLLib))
- library = LoadLibrary(command_line->GetSwitchValueASCII(
- switches::kTestGLLib).c_str());
+ library = LoadLibraryAndPrintError(
+ command_line->GetSwitchValueASCII(switches::kTestGLLib).c_str());
if (!library) {
-#if defined(OS_OPENBSD)
- library = LoadLibrary("libGL.so");
-#else
- library = LoadLibrary("libGL.so.1");
-#endif
+ library = LoadLibraryAndPrintError(kGLLibraryName);
}
if (!library)
@@ -87,15 +92,17 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(library);
SetGLImplementation(kGLImplementationDesktopGL);
- InitializeGLBindingsGL();
- InitializeGLBindingsGLX();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsGLX();
break;
}
case kGLImplementationEGLGLES2: {
- base::NativeLibrary gles_library = LoadLibrary("libGLESv2.so.2");
+ base::NativeLibrary gles_library =
+ LoadLibraryAndPrintError(kGLESv2LibraryName);
if (!gles_library)
return false;
- base::NativeLibrary egl_library = LoadLibrary("libEGL.so.1");
+ base::NativeLibrary egl_library =
+ LoadLibraryAndPrintError(kEGLLibraryName);
if (!egl_library) {
base::UnloadNativeLibrary(gles_library);
return false;
@@ -117,8 +124,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
AddGLNativeLibrary(gles_library);
SetGLImplementation(kGLImplementationEGLGLES2);
- InitializeGLBindingsGL();
- InitializeGLBindingsEGL();
+ InitializeStaticGLBindingsGL();
+ InitializeStaticGLBindingsEGL();
// These two functions take single precision float rather than double
// precision float parameters in GLES.
@@ -127,9 +134,8 @@ bool InitializeGLBindings(GLImplementation implementation) {
break;
}
case kGLImplementationMockGL: {
- SetGLGetProcAddressProc(GetMockGLProcAddress);
SetGLImplementation(kGLImplementationMockGL);
- InitializeGLBindingsGL();
+ InitializeStaticGLBindingsGL();
break;
}
default:
@@ -140,23 +146,29 @@ bool InitializeGLBindings(GLImplementation implementation) {
return true;
}
-bool InitializeGLExtensionBindings(GLImplementation implementation,
+bool InitializeDynamicGLBindings(GLImplementation implementation,
GLContext* context) {
switch (implementation) {
case kGLImplementationOSMesaGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsOSMESA(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsOSMESA(context);
break;
case kGLImplementationDesktopGL:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsGLX(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsGLX(context);
break;
case kGLImplementationEGLGLES2:
- InitializeGLExtensionBindingsGL(context);
- InitializeGLExtensionBindingsEGL(context);
+ InitializeDynamicGLBindingsGL(context);
+ InitializeDynamicGLBindingsEGL(context);
break;
case kGLImplementationMockGL:
- InitializeGLExtensionBindingsGL(context);
+ if (!context) {
+ scoped_refptr<GLContextStubWithExtensions> mock_context(
+ new GLContextStubWithExtensions());
+ mock_context->SetGLVersionString("3.0");
+ InitializeDynamicGLBindingsGL(mock_context.get());
+ } else
+ InitializeDynamicGLBindingsGL(context);
break;
default:
return false;
diff --git a/chromium/ui/gl/gl_interface.cc b/chromium/ui/gl/gl_interface.cc
deleted file mode 100644
index 0cb61e71649..00000000000
--- a/chromium/ui/gl/gl_interface.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/gl_interface.h"
-
-namespace gfx {
-
-GLInterface* GLInterface::interface_;
-
-void GLInterface::SetGLInterface(GLInterface* gl_interface) {
- interface_ = gl_interface;
-}
-
-GLInterface* GLInterface::GetGLInterface() {
- return interface_;
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gl/gl_interface.h b/chromium/ui/gl/gl_interface.h
deleted file mode 100644
index 7f1ba8f8660..00000000000
--- a/chromium/ui/gl/gl_interface.h
+++ /dev/null
@@ -1,35 +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_GL_GL_INTERFACE_H_
-#define UI_GL_GL_INTERFACE_H_
-
-// This file implements glue to a GL interface so we can mock it for unit
-// testing. It has to be Desktop GL, not GLES2 as it is used to test the service
-// side code.
-
-#include "ui/gl/gl_bindings.h"
-
-namespace gfx {
-
-class GL_EXPORT GLInterface {
- public:
- virtual ~GLInterface() {}
-
- static void SetGLInterface(GLInterface* gl_interface);
-
- static GLInterface* GetGLInterface();
-
- // Include the auto-generated part of this class. We split this because
- // it means we can easily edit the non-auto generated parts right here in
- // this file instead of having to edit some template or the code generator.
- #include "gl_interface_autogen_gl.h"
-
- private:
- static GLInterface* interface_;
-};
-
-} // namespace gfx
-
-#endif // UI_GL_GL_INTERFACE_H_
diff --git a/chromium/ui/gl/gl_mock.cc b/chromium/ui/gl/gl_mock.cc
index f145c77874c..3b835792202 100644
--- a/chromium/ui/gl/gl_mock.cc
+++ b/chromium/ui/gl/gl_mock.cc
@@ -12,4 +12,10 @@ MockGLInterface::MockGLInterface() {
MockGLInterface::~MockGLInterface() {
}
+MockGLInterface* MockGLInterface::interface_;
+
+void MockGLInterface::SetGLInterface(MockGLInterface* gl_interface) {
+ interface_ = gl_interface;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_mock.h b/chromium/ui/gl/gl_mock.h
index 39ccb5f184c..b678a5e8791 100644
--- a/chromium/ui/gl/gl_mock.h
+++ b/chromium/ui/gl/gl_mock.h
@@ -2,26 +2,42 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This file implements mock GL Interface for unit testing. It has to mock
-// Desktop GL, not GLES2 as it is used to test the service side code.
+// This file implements mock GL Interface for unit testing. The interface
+// corresponds to the set of functionally distinct GL functions defined in
+// generate_bindings.py, which may originate from either desktop GL or GLES.
#ifndef UI_GL_GL_MOCK_H_
#define UI_GL_GL_MOCK_H_
#include "testing/gmock/include/gmock/gmock.h"
-#include "ui/gl/gl_interface.h"
+#include "ui/gl/gl_bindings.h"
namespace gfx {
-class MockGLInterface : public GLInterface {
+class MockGLInterface {
public:
MockGLInterface();
virtual ~MockGLInterface();
- // Include the auto-generated part of this class. We split this because
+ // Set the functions called from the mock GL implementation for the purposes
+ // of testing.
+ static void SetGLInterface(MockGLInterface* gl_interface);
+
+ // Find an entry point to the mock GL implementation.
+ static void* GL_BINDING_CALL GetGLProcAddress(const char* name);
+
+ // Include the auto-generated parts of this class. We split this because
// it means we can easily edit the non-auto generated parts right here in
// this file instead of having to edit some template or the code generator.
+
+ // Member functions
#include "gl_mock_autogen_gl.h"
+
+ private:
+ static MockGLInterface* interface_;
+
+ // Static mock functions that invoke the member functions of interface_.
+ #include "gl_bindings_autogen_mock.h"
};
} // namespace gfx
diff --git a/chromium/ui/gl/gl_osmesa_api_implementation.cc b/chromium/ui/gl/gl_osmesa_api_implementation.cc
index 5b32d22ef1d..f23c2997b3d 100644
--- a/chromium/ui/gl/gl_osmesa_api_implementation.cc
+++ b/chromium/ui/gl/gl_osmesa_api_implementation.cc
@@ -8,8 +8,8 @@ namespace gfx {
RealOSMESAApi* g_real_osmesa;
-void InitializeGLBindingsOSMESA() {
- g_driver_osmesa.InitializeBindings();
+void InitializeStaticGLBindingsOSMESA() {
+ g_driver_osmesa.InitializeStaticBindings();
if (!g_real_osmesa) {
g_real_osmesa = new RealOSMESAApi();
}
@@ -17,8 +17,8 @@ void InitializeGLBindingsOSMESA() {
g_current_osmesa_context = g_real_osmesa;
}
-void InitializeGLExtensionBindingsOSMESA(GLContext* context) {
- g_driver_osmesa.InitializeExtensionBindings(context);
+void InitializeDynamicGLBindingsOSMESA(GLContext* context) {
+ g_driver_osmesa.InitializeDynamicBindings(context);
}
void InitializeDebugGLBindingsOSMESA() {
diff --git a/chromium/ui/gl/gl_osmesa_api_implementation.h b/chromium/ui/gl/gl_osmesa_api_implementation.h
index 9d00b126680..66f4a3496a9 100644
--- a/chromium/ui/gl/gl_osmesa_api_implementation.h
+++ b/chromium/ui/gl/gl_osmesa_api_implementation.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_OSMESA_API_IMPLEMENTATION_H_
-#define UI_GL_OSMESA_API_IMPLEMENTATION_H_
+#ifndef UI_GL_GL_OSMESA_API_IMPLEMENTATION_H_
+#define UI_GL_GL_OSMESA_API_IMPLEMENTATION_H_
#include "base/compiler_specific.h"
#include "ui/gl/gl_bindings.h"
@@ -13,8 +13,8 @@ namespace gfx {
class GLContext;
-void InitializeGLBindingsOSMESA();
-void InitializeGLExtensionBindingsOSMESA(GLContext* context);
+void InitializeStaticGLBindingsOSMESA();
+void InitializeDynamicGLBindingsOSMESA(GLContext* context);
void InitializeDebugGLBindingsOSMESA();
void ClearGLBindingsOSMESA();
@@ -57,7 +57,7 @@ class GL_EXPORT TraceOSMESAApi : public OSMESAApi {
} // namespace gfx
-#endif // UI_GL_OSMESA_API_IMPLEMENTATION_H_
+#endif // UI_GL_GL_OSMESA_API_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gl_state_restorer.h b/chromium/ui/gl/gl_state_restorer.h
index 6d8791f3c16..7edc9989134 100644
--- a/chromium/ui/gl/gl_state_restorer.h
+++ b/chromium/ui/gl/gl_state_restorer.h
@@ -18,8 +18,9 @@ class GL_EXPORT GLStateRestorer {
virtual ~GLStateRestorer();
virtual bool IsInitialized() = 0;
- virtual void RestoreState() = 0;
+ virtual void RestoreState(const GLStateRestorer* prev_state) = 0;
virtual void RestoreAllTextureUnitBindings() = 0;
+ virtual void RestoreActiveTextureUnitBinding(unsigned int target) = 0;
virtual void RestoreFramebufferBindings() = 0;
DISALLOW_COPY_AND_ASSIGN(GLStateRestorer);
diff --git a/chromium/ui/gl/gl_surface.cc b/chromium/ui/gl/gl_surface.cc
index f09aa35924d..92b2b45ce23 100644
--- a/chromium/ui/gl/gl_surface.cc
+++ b/chromium/ui/gl/gl_surface.cc
@@ -14,6 +14,11 @@
#include "base/threading/thread_local.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_switches.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#endif
namespace gfx {
@@ -24,9 +29,7 @@ base::LazyInstance<base::ThreadLocalPointer<GLSurface> >::Leaky
// static
bool GLSurface::InitializeOneOff() {
- static bool initialized = false;
- if (initialized)
- return true;
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
TRACE_EVENT0("gpu", "GLSurface::InitializeOneOff");
@@ -34,12 +37,16 @@ bool GLSurface::InitializeOneOff() {
GetAllowedGLImplementations(&allowed_impls);
DCHECK(!allowed_impls.empty());
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+
// The default implementation is always the first one in list.
GLImplementation impl = allowed_impls[0];
bool fallback_to_osmesa = false;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) {
+ if (cmd->HasSwitch(switches::kOverrideUseGLWithOSMesaForTests)) {
+ impl = kGLImplementationOSMesaGL;
+ } else if (cmd->HasSwitch(switches::kUseGL)) {
std::string requested_implementation_name =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
+ cmd->GetSwitchValueASCII(switches::kUseGL);
if (requested_implementation_name == "any") {
fallback_to_osmesa = true;
} else if (requested_implementation_name == "swiftshader") {
@@ -55,24 +62,103 @@ bool GLSurface::InitializeOneOff() {
}
}
- initialized = InitializeGLBindings(impl) && InitializeOneOffInternal();
+ bool gpu_service_logging = cmd->HasSwitch(switches::kEnableGPUServiceLogging);
+ bool disable_gl_drawing = cmd->HasSwitch(switches::kDisableGLDrawingForTests);
+
+ return InitializeOneOffImplementation(
+ impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing);
+}
+
+// static
+bool GLSurface::InitializeOneOffImplementation(GLImplementation impl,
+ bool fallback_to_osmesa,
+ bool gpu_service_logging,
+ bool disable_gl_drawing) {
+ bool initialized =
+ InitializeStaticGLBindings(impl) && InitializeOneOffInternal();
if (!initialized && fallback_to_osmesa) {
ClearGLBindings();
- initialized = InitializeGLBindings(kGLImplementationOSMesaGL) &&
+ initialized = InitializeStaticGLBindings(kGLImplementationOSMesaGL) &&
InitializeOneOffInternal();
}
+ if (!initialized)
+ ClearGLBindings();
if (initialized) {
DVLOG(1) << "Using "
<< GetGLImplementationName(GetGLImplementation())
<< " GL implementation.";
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableGPUServiceLogging))
+ if (gpu_service_logging)
InitializeDebugGLBindings();
+ if (disable_gl_drawing)
+ InitializeNullDrawGLBindings();
}
return initialized;
}
+// static
+void GLSurface::InitializeOneOffForTests() {
+ DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
+
+#if defined(USE_X11)
+ XInitThreads();
+#endif
+
+ bool use_osmesa = true;
+
+ // We usually use OSMesa as this works on all bots. The command line can
+ // override this behaviour to use hardware GL.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGpuInTests))
+ use_osmesa = false;
+
+#if defined(OS_ANDROID)
+ // On Android we always use hardware GL.
+ use_osmesa = false;
+#endif
+
+ std::vector<GLImplementation> allowed_impls;
+ GetAllowedGLImplementations(&allowed_impls);
+ DCHECK(!allowed_impls.empty());
+
+ GLImplementation impl = allowed_impls[0];
+ if (use_osmesa)
+ impl = kGLImplementationOSMesaGL;
+
+ DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL))
+ << "kUseGL has not effect in tests";
+
+ bool fallback_to_osmesa = false;
+ bool gpu_service_logging = false;
+ bool disable_gl_drawing = true;
+
+ CHECK(InitializeOneOffImplementation(
+ impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing));
+}
+
+// static
+void GLSurface::InitializeOneOffWithMockBindingsForTests() {
+ DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL))
+ << "kUseGL has not effect in tests";
+
+ // This method may be called multiple times in the same process to set up
+ // mock bindings in different ways.
+ ClearGLBindings();
+
+ bool fallback_to_osmesa = false;
+ bool gpu_service_logging = false;
+ bool disable_gl_drawing = false;
+
+ CHECK(InitializeOneOffImplementation(kGLImplementationMockGL,
+ fallback_to_osmesa,
+ gpu_service_logging,
+ disable_gl_drawing));
+}
+
+// static
+void GLSurface::InitializeDynamicMockBindingsForTests(GLContext* context) {
+ CHECK(InitializeDynamicGLBindings(kGLImplementationMockGL, context));
+}
+
GLSurface::GLSurface() {}
bool GLSurface::Initialize() {
@@ -93,18 +179,8 @@ bool GLSurface::DeferDraws() {
return false;
}
-std::string GLSurface::GetExtensions() {
- return std::string();
-}
-
-bool GLSurface::HasExtension(const char* name) {
- std::string extensions = GetExtensions();
- extensions += " ";
-
- std::string delimited_name(name);
- delimited_name += " ";
-
- return extensions.find(delimited_name) != std::string::npos;
+bool GLSurface::SupportsPostSubBuffer() {
+ return false;
}
unsigned int GLSurface::GetBackingFrameBufferObject() {
@@ -210,8 +286,8 @@ bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) {
return surface_->PostSubBuffer(x, y, width, height);
}
-std::string GLSurfaceAdapter::GetExtensions() {
- return surface_->GetExtensions();
+bool GLSurfaceAdapter::SupportsPostSubBuffer() {
+ return surface_->SupportsPostSubBuffer();
}
gfx::Size GLSurfaceAdapter::GetSize() {
diff --git a/chromium/ui/gl/gl_surface.h b/chromium/ui/gl/gl_surface.h
index 8eaf60dab28..70336ba6df8 100644
--- a/chromium/ui/gl/gl_surface.h
+++ b/chromium/ui/gl/gl_surface.h
@@ -12,6 +12,7 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/gl_export.h"
+#include "ui/gl/gl_implementation.h"
namespace gfx {
@@ -56,11 +57,8 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
// Get the underlying platform specific surface "handle".
virtual void* GetHandle() = 0;
- // Returns space separated list of surface specific extensions.
- // The surface must be current.
- virtual std::string GetExtensions();
-
- bool HasExtension(const char* name);
+ // Returns whether or not the surface supports PostSubBuffer.
+ virtual bool SupportsPostSubBuffer();
// Returns the internal frame buffer object name if the surface is backed by
// FBO. Otherwise returns 0.
@@ -69,8 +67,15 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
// Copy part of the backbuffer to the frontbuffer.
virtual bool PostSubBuffer(int x, int y, int width, int height);
+ // Initialize GL bindings.
static bool InitializeOneOff();
+ // Unit tests should call these instead of InitializeOneOff() to set up
+ // GL bindings appropriate for tests.
+ static void InitializeOneOffForTests();
+ static void InitializeOneOffWithMockBindingsForTests();
+ static void InitializeDynamicMockBindingsForTests(GLContext* context);
+
// Called after a context is made current with this surface. Returns false
// on error.
virtual bool OnMakeCurrent(GLContext* context);
@@ -109,6 +114,10 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
protected:
virtual ~GLSurface();
+ static bool InitializeOneOffImplementation(GLImplementation impl,
+ bool fallback_to_osmesa,
+ bool gpu_service_logging,
+ bool disable_gl_drawing);
static bool InitializeOneOffInternal();
static void SetCurrent(GLSurface* surface);
@@ -135,7 +144,7 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
virtual bool IsOffscreen() OVERRIDE;
virtual bool SwapBuffers() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
- virtual std::string GetExtensions() OVERRIDE;
+ virtual bool SupportsPostSubBuffer() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual void* GetHandle() OVERRIDE;
virtual unsigned int GetBackingFrameBufferObject() OVERRIDE;
diff --git a/chromium/ui/gl/gl_surface_android.cc b/chromium/ui/gl/gl_surface_android.cc
new file mode 100644
index 00000000000..1304b385bd6
--- /dev/null
+++ b/chromium/ui/gl/gl_surface_android.cc
@@ -0,0 +1,90 @@
+// 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/gl/gl_surface.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "third_party/khronos/EGL/egl.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_osmesa.h"
+#include "ui/gl/gl_surface_stub.h"
+
+namespace gfx {
+
+// static
+bool GLSurface::InitializeOneOffInternal() {
+ switch (GetGLImplementation()) {
+ case kGLImplementationEGLGLES2:
+ if (!GLSurfaceEGL::InitializeOneOff()) {
+ LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
+ return false;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+// static
+scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
+ gfx::AcceleratedWidget window) {
+ CHECK_NE(kGLImplementationNone, GetGLImplementation());
+ if (GetGLImplementation() == kGLImplementationOSMesaGL) {
+ scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
+ if (!surface->Initialize())
+ return NULL;
+ return surface;
+ }
+ DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
+ if (window != kNullAcceleratedWidget) {
+ scoped_refptr<GLSurface> surface = new NativeViewGLSurfaceEGL(window);
+ if (surface->Initialize())
+ return surface;
+ } else {
+ scoped_refptr<GLSurface> surface = new GLSurfaceStub();
+ if (surface->Initialize())
+ return surface;
+ }
+ return NULL;
+}
+
+// static
+scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
+ const gfx::Size& size) {
+ CHECK_NE(kGLImplementationNone, GetGLImplementation());
+ switch (GetGLImplementation()) {
+ case kGLImplementationOSMesaGL: {
+ scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(1, size));
+ if (!surface->Initialize())
+ return NULL;
+
+ return surface;
+ }
+ case kGLImplementationEGLGLES2: {
+ scoped_refptr<GLSurface> surface;
+ if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
+ (size.width() == 0 && size.height() == 0)) {
+ surface = new SurfacelessEGL(size);
+ } else {
+ surface = new PbufferGLSurfaceEGL(size);
+ }
+
+ if (!surface->Initialize())
+ return NULL;
+ return surface;
+ }
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
+ return EGL_DEFAULT_DISPLAY;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_cgl.cc b/chromium/ui/gl/gl_surface_cgl.cc
deleted file mode 100644
index 6c35693bdcc..00000000000
--- a/chromium/ui/gl/gl_surface_cgl.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/gl_surface_cgl.h"
-
-#include <OpenGL/CGLRenderers.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gpu_switching_manager.h"
-
-namespace gfx {
-
-namespace {
-CGLPixelFormatObj g_pixel_format;
-}
-
-GLSurfaceCGL::GLSurfaceCGL() {}
-
-bool GLSurfaceCGL::InitializeOneOff() {
- static bool initialized = false;
- if (initialized)
- return true;
-
- // This is called from the sandbox warmup code on Mac OS X.
- // GPU-related stuff is very slow without this, probably because
- // the sandbox prevents loading graphics drivers or some such.
- std::vector<CGLPixelFormatAttribute> attribs;
- if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
- // Avoid switching to the discrete GPU just for this pixel
- // format selection.
- attribs.push_back(kCGLPFAAllowOfflineRenderers);
- }
- if (GetGLImplementation() == kGLImplementationAppleGL) {
- attribs.push_back(kCGLPFARendererID);
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(
- kCGLRendererGenericFloatID));
- }
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
-
- CGLPixelFormatObj format;
- GLint num_pixel_formats;
- if (CGLChoosePixelFormat(&attribs.front(),
- &format,
- &num_pixel_formats) != kCGLNoError) {
- LOG(ERROR) << "Error choosing pixel format.";
- return false;
- }
- if (!format) {
- LOG(ERROR) << "format == 0.";
- return false;
- }
- CGLReleasePixelFormat(format);
- DCHECK_NE(num_pixel_formats, 0);
- initialized = true;
- return true;
-}
-
-void* GLSurfaceCGL::GetPixelFormat() {
- return g_pixel_format;
-}
-
-GLSurfaceCGL::~GLSurfaceCGL() {}
-
-NoOpGLSurfaceCGL::NoOpGLSurfaceCGL(const gfx::Size& size)
- : size_(size) {
-}
-
-bool NoOpGLSurfaceCGL::Initialize() {
- return true;
-}
-
-void NoOpGLSurfaceCGL::Destroy() {
-}
-
-bool NoOpGLSurfaceCGL::IsOffscreen() {
- return true;
-}
-
-bool NoOpGLSurfaceCGL::SwapBuffers() {
- NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurfaceCGL.";
- return false;
-}
-
-gfx::Size NoOpGLSurfaceCGL::GetSize() {
- return size_;
-}
-
-void* NoOpGLSurfaceCGL::GetHandle() {
- return NULL;
-}
-
-void* NoOpGLSurfaceCGL::GetDisplay() {
- return NULL;
-}
-
-NoOpGLSurfaceCGL::~NoOpGLSurfaceCGL() {
- Destroy();
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_cgl.h b/chromium/ui/gl/gl_surface_cgl.h
deleted file mode 100644
index 4786acdb4a0..00000000000
--- a/chromium/ui/gl/gl_surface_cgl.h
+++ /dev/null
@@ -1,56 +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_GL_GL_SURFACE_CGL_H_
-#define UI_GL_GL_SURFACE_CGL_H_
-
-#include "ui/gfx/size.h"
-#include "ui/gl/gl_surface.h"
-
-namespace gfx {
-
-// Base class for CGL surfaces.
-class GLSurfaceCGL : public GLSurface {
- public:
- GLSurfaceCGL();
-
- static bool InitializeOneOff();
- static void* GetPixelFormat();
-
- protected:
- virtual ~GLSurfaceCGL();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GLSurfaceCGL);
-};
-
-// A "no-op" surface. It is not required that a CGLContextObj have an
-// associated drawable (pbuffer or fullscreen context) in order to be
-// made current. Everywhere this surface type is used, we allocate an
-// FBO at the user level as the drawable of the associated context.
-class GL_EXPORT NoOpGLSurfaceCGL : public GLSurfaceCGL {
- public:
- explicit NoOpGLSurfaceCGL(const gfx::Size& size);
-
- // Implement GLSurface.
- virtual bool Initialize() OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual bool IsOffscreen() OVERRIDE;
- virtual bool SwapBuffers() OVERRIDE;
- virtual gfx::Size GetSize() OVERRIDE;
- virtual void* GetHandle() OVERRIDE;
- virtual void* GetDisplay() OVERRIDE;
-
- protected:
- virtual ~NoOpGLSurfaceCGL();
-
- private:
- gfx::Size size_;
-
- DISALLOW_COPY_AND_ASSIGN(NoOpGLSurfaceCGL);
-};
-
-} // namespace gfx
-
-#endif // UI_GL_GL_SURFACE_CGL_H_
diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc
index 3f8923ae895..6cf38160431 100644
--- a/chromium/ui/gl/gl_surface_egl.cc
+++ b/chromium/ui/gl/gl_surface_egl.cc
@@ -12,11 +12,12 @@
#include <android/native_window_jni.h>
#endif
-#include "base/command_line.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "build/build_config.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
@@ -33,13 +34,11 @@ extern "C" {
#endif
#if defined (USE_OZONE)
-#include "ui/gfx/ozone/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
#endif
-// From ANGLE's egl/eglext.h.
-#if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
-#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
- reinterpret_cast<EGLNativeDisplayType>(-2)
+#if !defined(EGL_FIXED_SIZE_ANGLE)
+#define EGL_FIXED_SIZE_ANGLE 0x3201
#endif
using ui::GetLastEGLErrorString;
@@ -55,6 +54,7 @@ EGLNativeDisplayType g_native_display;
const char* g_egl_extensions = NULL;
bool g_egl_create_context_robustness_supported = false;
bool g_egl_sync_control_supported = false;
+bool g_egl_window_fixed_size_supported = false;
bool g_egl_surfaceless_context_supported = false;
class EGLSyncControlVSyncProvider
@@ -102,27 +102,7 @@ bool GLSurfaceEGL::InitializeOneOff() {
if (initialized)
return true;
-#if defined(USE_X11)
- g_native_display = base::MessagePumpForUI::GetDefaultXDisplay();
-#elif defined(OS_WIN)
- g_native_display = EGL_DEFAULT_DISPLAY;
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11) &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableD3D11)) {
- g_native_display = EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
- }
-#elif defined(USE_OZONE)
- gfx::SurfaceFactoryOzone* surface_factory =
- gfx::SurfaceFactoryOzone::GetInstance();
- if (surface_factory->InitializeHardware() !=
- gfx::SurfaceFactoryOzone::INITIALIZED) {
- LOG(ERROR) << "OZONE failed to initialize hardware";
- return false;
- }
- g_native_display = reinterpret_cast<EGLNativeDisplayType>(
- surface_factory->GetNativeDisplay());
-#else
- g_native_display = EGL_DEFAULT_DISPLAY;
-#endif
+ g_native_display = GetPlatformDefaultEGLNativeDisplay();
g_display = eglGetDisplay(g_native_display);
if (!g_display) {
LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
@@ -149,7 +129,8 @@ bool GLSurfaceEGL::InitializeOneOff() {
#if defined(USE_OZONE)
const EGLint* config_attribs =
- surface_factory->GetEGLSurfaceProperties(kConfigAttribs);
+ ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
+ kConfigAttribs);
#else
const EGLint* config_attribs = kConfigAttribs;
#endif
@@ -185,7 +166,16 @@ bool GLSurfaceEGL::InitializeOneOff() {
HasEGLExtension("EGL_EXT_create_context_robustness");
g_egl_sync_control_supported =
HasEGLExtension("EGL_CHROMIUM_sync_control");
+ g_egl_window_fixed_size_supported =
+ HasEGLExtension("EGL_ANGLE_window_fixed_size");
+ // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
+ // workaround, since code written for Android WebView takes different paths
+ // based on whether GL surface objects have underlying EGL surface handles,
+ // conflicting with the use of surfaceless. See https://crbug.com/382349
+#if defined(OS_ANDROID)
+ DCHECK(!g_egl_surfaceless_context_supported);
+#else
// Check if SurfacelessEGL is supported.
g_egl_surfaceless_context_supported =
HasEGLExtension("EGL_KHR_surfaceless_context");
@@ -206,6 +196,7 @@ bool GLSurfaceEGL::InitializeOneOff() {
context->ReleaseCurrent(surface.get());
}
}
+#endif
initialized = true;
@@ -236,50 +227,63 @@ bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
return g_egl_create_context_robustness_supported;
}
+bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
+ return g_egl_surfaceless_context_supported;
+}
+
GLSurfaceEGL::~GLSurfaceEGL() {}
-NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(gfx::AcceleratedWidget window)
+NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
: window_(window),
surface_(NULL),
supports_post_sub_buffer_(false),
- config_(NULL) {
+ config_(NULL),
+ size_(1, 1) {
#if defined(OS_ANDROID)
if (window)
ANativeWindow_acquire(window);
#endif
+
+#if defined(OS_WIN)
+ RECT windowRect;
+ if (GetClientRect(window_, &windowRect))
+ size_ = gfx::Rect(windowRect).size();
+#endif
}
bool NativeViewGLSurfaceEGL::Initialize() {
- return Initialize(NULL);
+ return Initialize(scoped_ptr<VSyncProvider>());
}
-bool NativeViewGLSurfaceEGL::Initialize(VSyncProvider* sync_provider) {
+bool NativeViewGLSurfaceEGL::Initialize(
+ scoped_ptr<VSyncProvider> sync_provider) {
DCHECK(!surface_);
- scoped_ptr<VSyncProvider> vsync_provider(sync_provider);
-
- if (window_ == kNullAcceleratedWidget) {
- LOG(ERROR) << "Trying to create surface without window.";
- return false;
- }
if (!GetDisplay()) {
LOG(ERROR) << "Trying to create surface with invalid display.";
return false;
}
- static const EGLint egl_window_attributes_sub_buffer[] = {
- EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_TRUE,
- EGL_NONE
- };
+ std::vector<EGLint> egl_window_attributes;
+ if (g_egl_window_fixed_size_supported) {
+ egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
+ egl_window_attributes.push_back(EGL_TRUE);
+ egl_window_attributes.push_back(EGL_WIDTH);
+ egl_window_attributes.push_back(size_.width());
+ egl_window_attributes.push_back(EGL_HEIGHT);
+ egl_window_attributes.push_back(size_.height());
+ }
+
+ if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
+ egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
+ egl_window_attributes.push_back(EGL_TRUE);
+ }
+
+ egl_window_attributes.push_back(EGL_NONE);
// Create a surface for the native window.
surface_ = eglCreateWindowSurface(
- GetDisplay(),
- GetConfig(),
- window_,
- gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer ?
- egl_window_attributes_sub_buffer :
- NULL);
+ GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
if (!surface_) {
LOG(ERROR) << "eglCreateWindowSurface failed with error "
@@ -296,7 +300,7 @@ bool NativeViewGLSurfaceEGL::Initialize(VSyncProvider* sync_provider) {
supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
if (sync_provider)
- vsync_provider_.swap(vsync_provider);
+ vsync_provider_.reset(sync_provider.release());
else if (g_egl_sync_control_supported)
vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
return true;
@@ -394,6 +398,10 @@ bool NativeViewGLSurfaceEGL::IsOffscreen() {
}
bool NativeViewGLSurfaceEGL::SwapBuffers() {
+ TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
+ "width", GetSize().width(),
+ "height", GetSize().height());
+
if (!eglSwapBuffers(GetDisplay(), surface_)) {
DVLOG(1) << "eglSwapBuffers failed with error "
<< GetLastEGLErrorString();
@@ -420,6 +428,8 @@ bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
if (size == GetSize())
return true;
+ size_ = size;
+
scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
GLContext* current_context = GLContext::GetCurrent();
bool was_current =
@@ -453,13 +463,8 @@ EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
return surface_;
}
-std::string NativeViewGLSurfaceEGL::GetExtensions() {
- std::string extensions = GLSurface::GetExtensions();
- if (supports_post_sub_buffer_) {
- extensions += extensions.empty() ? "" : " ";
- extensions += "GL_CHROMIUM_post_sub_buffer";
- }
- return extensions;
+bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
+ return supports_post_sub_buffer_;
}
bool NativeViewGLSurfaceEGL::PostSubBuffer(
@@ -492,6 +497,10 @@ void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
: size_(size),
surface_(NULL) {
+ // Some implementations of Pbuffer do not support having a 0 size. For such
+ // cases use a (1, 1) surface.
+ if (size_.GetArea() == 0)
+ size_.SetSize(1, 1);
}
bool PbufferGLSurfaceEGL::Initialize() {
@@ -503,12 +512,6 @@ bool PbufferGLSurfaceEGL::Initialize() {
return false;
}
- if (size_.GetArea() == 0) {
- LOG(ERROR) << "Error: surface has zero area "
- << size_.width() << " x " << size_.height();
- return false;
- }
-
// Allocate the new pbuffer surface before freeing the old one to ensure
// they have different addresses. If they have the same address then a
// future call to MakeCurrent might early out because it appears the current
@@ -660,111 +663,4 @@ void* SurfacelessEGL::GetShareHandle() {
SurfacelessEGL::~SurfacelessEGL() {
}
-#if defined(ANDROID) || defined(USE_OZONE)
-
-// A thin subclass of |GLSurfaceOSMesa| that can be used in place
-// of a native hardware-provided surface when a native surface
-// provider is not available.
-class GLSurfaceOSMesaHeadless : public GLSurfaceOSMesa {
- public:
- explicit GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window);
-
- virtual bool IsOffscreen() OVERRIDE;
- virtual bool SwapBuffers() OVERRIDE;
-
- protected:
- virtual ~GLSurfaceOSMesaHeadless();
-
- private:
-
- DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesaHeadless);
-};
-
-bool GLSurfaceOSMesaHeadless::IsOffscreen() { return false; }
-
-bool GLSurfaceOSMesaHeadless::SwapBuffers() { return true; }
-
-GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless(gfx::AcceleratedWidget window)
- : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)) {
- DCHECK(window);
-}
-
-GLSurfaceOSMesaHeadless::~GLSurfaceOSMesaHeadless() { Destroy(); }
-
-// static
-bool GLSurface::InitializeOneOffInternal() {
- if (GetGLImplementation() == kGLImplementationOSMesaGL) {
- return true;
- }
- DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
-
- if (!GLSurfaceEGL::InitializeOneOff()) {
- LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
- return false;
- }
- return true;
-}
-
-// static
-scoped_refptr<GLSurface>
-GLSurface::CreateViewGLSurface(gfx::AcceleratedWidget window) {
-
- if (GetGLImplementation() == kGLImplementationOSMesaGL) {
- scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless(window));
- if (!surface->Initialize())
- return NULL;
- return surface;
- }
- DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
- if (window) {
- scoped_refptr<NativeViewGLSurfaceEGL> surface;
- VSyncProvider* sync_provider = NULL;
-#if defined(USE_OZONE)
- window = gfx::SurfaceFactoryOzone::GetInstance()->RealizeAcceleratedWidget(
- window);
- sync_provider =
- gfx::SurfaceFactoryOzone::GetInstance()->GetVSyncProvider(window);
-#endif
- surface = new NativeViewGLSurfaceEGL(window);
- if(surface->Initialize(sync_provider))
- return surface;
- } else {
- scoped_refptr<GLSurface> surface = new GLSurfaceStub();
- if (surface->Initialize())
- return surface;
- }
- return NULL;
-}
-
-// static
-scoped_refptr<GLSurface>
-GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) {
- switch (GetGLImplementation()) {
- case kGLImplementationOSMesaGL: {
- scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(1, size));
- if (!surface->Initialize())
- return NULL;
-
- return surface;
- }
- case kGLImplementationEGLGLES2: {
- scoped_refptr<GLSurface> surface;
- if (g_egl_surfaceless_context_supported &&
- (size.width() == 0 && size.height() == 0)) {
- surface = new SurfacelessEGL(size);
- } else
- surface = new PbufferGLSurfaceEGL(size);
-
- if (!surface->Initialize())
- return NULL;
- return surface;
- }
- default:
- NOTREACHED();
- return NULL;
- }
-}
-
-#endif
-
} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_egl.h b/chromium/ui/gl/gl_surface_egl.h
index 0acc9af52a2..4c2892822ec 100644
--- a/chromium/ui/gl/gl_surface_egl.h
+++ b/chromium/ui/gl/gl_surface_egl.h
@@ -13,7 +13,6 @@
#include "base/compiler_specific.h"
#include "base/time/time.h"
-#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_bindings.h"
@@ -21,6 +20,9 @@
namespace gfx {
+// Get default EGL display for GLSurfaceEGL (differs by platform).
+EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay();
+
// Interface for EGL surface.
class GL_EXPORT GLSurfaceEGL : public GLSurface {
public:
@@ -39,6 +41,7 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
static const char* GetEGLExtensions();
static bool HasEGLExtension(const char* name);
static bool IsCreateContextRobustnessSupported();
+ static bool IsEGLSurfacelessContextSupported();
protected:
virtual ~GLSurfaceEGL();
@@ -50,7 +53,7 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
// Encapsulates an EGL surface bound to a view.
class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
public:
- explicit NativeViewGLSurfaceEGL(gfx::AcceleratedWidget window);
+ explicit NativeViewGLSurfaceEGL(EGLNativeWindowType window);
// Implement GLSurface.
virtual EGLConfig GetConfig() OVERRIDE;
@@ -62,23 +65,24 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
virtual bool SwapBuffers() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual EGLSurface GetHandle() OVERRIDE;
- virtual std::string GetExtensions() OVERRIDE;
+ virtual bool SupportsPostSubBuffer() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
virtual VSyncProvider* GetVSyncProvider() OVERRIDE;
// Create a NativeViewGLSurfaceEGL with an externally provided VSyncProvider.
// Takes ownership of the VSyncProvider.
- virtual bool Initialize(VSyncProvider* sync_provider);
+ virtual bool Initialize(scoped_ptr<VSyncProvider> sync_provider);
protected:
virtual ~NativeViewGLSurfaceEGL();
void SetHandle(EGLSurface surface);
private:
- gfx::AcceleratedWidget window_;
+ EGLNativeWindowType window_;
EGLSurface surface_;
bool supports_post_sub_buffer_;
EGLConfig config_;
+ gfx::Size size_;
scoped_ptr<VSyncProvider> vsync_provider_;
diff --git a/chromium/ui/gl/gl_surface_glx.cc b/chromium/ui/gl/gl_surface_glx.cc
index 8f0fe89e715..58f97f5e3a5 100644
--- a/chromium/ui/gl/gl_surface_glx.cc
+++ b/chromium/ui/gl/gl_surface_glx.cc
@@ -21,6 +21,8 @@ extern "C" {
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "third_party/mesa/src/include/GL/osmesa.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11_connection.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
@@ -31,10 +33,9 @@ namespace gfx {
namespace {
// scoped_ptr functor for XFree(). Use as follows:
-// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
+// scoped_ptr<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
-class ScopedPtrXFree {
- public:
+struct ScopedPtrXFree {
void operator()(void* x) const {
::XFree(x);
}
@@ -165,7 +166,7 @@ class SGIVideoSyncProviderThreadShim {
visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
int visual_info_count = 0;
- scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
+ scoped_ptr<XVisualInfo, ScopedPtrXFree> visual_info_list(
XGetVisualInfo(display_, VisualIDMask,
&visual_info_template, &visual_info_count));
@@ -300,73 +301,6 @@ SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
// goes up (rather than on-demand when we start the thread).
Display* SGIVideoSyncProviderThreadShim::display_ = NULL;
-#if defined(TOOLKIT_GTK)
-// A mechanism for forwarding XExpose events from one window to another.
-// Because in the workaround for http://crbug.com/145600 the child window
-// is placed on top of the parent window, only the child window will receive
-// all expose events. These need to be forwared to the parent window to inform
-// it that it should paint.
-class XExposeEventForwarder : public base::MessagePumpObserver {
- public:
- XExposeEventForwarder() {}
- virtual ~XExposeEventForwarder() {
- DCHECK(child_to_parent_map_.empty());
- }
- void AddParentChildPair(gfx::AcceleratedWidget parent_window,
- gfx::AcceleratedWidget child_window) {
- if (child_to_parent_map_.empty())
- base::MessagePumpX11::Current()->AddObserver(this);
-
- DCHECK(child_to_parent_map_.find(child_window) ==
- child_to_parent_map_.end());
- child_to_parent_map_.insert(std::make_pair(
- child_window, parent_window));
- }
- void RemoveParentChildPair(gfx::AcceleratedWidget parent_window,
- gfx::AcceleratedWidget child_window) {
- DCHECK(child_to_parent_map_.find(child_window) !=
- child_to_parent_map_.end());
- child_to_parent_map_.erase(child_window);
-
- if (child_to_parent_map_.empty())
- base::MessagePumpX11::Current()->RemoveObserver(this);
- }
-
- private:
- virtual base::EventStatus WillProcessEvent (
- const base::NativeEvent& xevent) OVERRIDE {
- if (xevent->type != Expose)
- return base::EVENT_CONTINUE;
-
- WindowMap::const_iterator found = child_to_parent_map_.find(
- xevent->xexpose.window);
- if (found == child_to_parent_map_.end())
- return base::EVENT_CONTINUE;
-
- gfx::AcceleratedWidget target_window = found->second;
- XEvent forwarded_event = *xevent;
- forwarded_event.xexpose.window = target_window;
- XSendEvent(g_display, target_window, False, ExposureMask,
- &forwarded_event);
- return base::EVENT_CONTINUE;
- }
- virtual void DidProcessEvent(const base::NativeEvent& xevent) OVERRIDE {
- }
-
- typedef std::map<gfx::AcceleratedWidget, gfx::AcceleratedWidget> WindowMap;
- WindowMap child_to_parent_map_;
-
- DISALLOW_COPY_AND_ASSIGN(XExposeEventForwarder);
-};
-
-static base::LazyInstance<XExposeEventForwarder> g_xexpose_event_forwarder =
- LAZY_INSTANCE_INITIALIZER;
-
-// Do not use this workaround when running in test harnesses that do not have
-// a message loop or do not have a TYPE_GPU message loop.
-bool g_create_child_windows = false;
-#endif
-
} // namespace
GLSurfaceGLX::GLSurfaceGLX() {}
@@ -381,22 +315,8 @@ bool GLSurfaceGLX::InitializeOneOff() {
// SGIVideoSyncProviderShim (if instantiated) will issue X commands on
// it's own thread.
- XInitThreads();
-
-#if defined(TOOLKIT_GTK)
- // Be sure to use the X display handle and not the GTK display handle if this
- // is the GPU process.
- g_create_child_windows =
- base::MessageLoop::current() &&
- base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU;
-
- if (g_create_child_windows)
- g_display = base::MessagePumpX11::GetDefaultXDisplay();
- else
- g_display = base::MessagePumpForUI::GetDefaultXDisplay();
-#else
- g_display = base::MessagePumpForUI::GetDefaultXDisplay();
-#endif
+ gfx::InitializeThreadedX11();
+ g_display = gfx::GetXDisplay();
if (!g_display) {
LOG(ERROR) << "XOpenDisplay failed.";
@@ -428,7 +348,7 @@ bool GLSurfaceGLX::InitializeOneOff() {
HasGLXExtension("GLX_SGI_video_sync");
if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported)
- SGIVideoSyncProviderThreadShim::display_ = XOpenDisplay(NULL);
+ SGIVideoSyncProviderThreadShim::display_ = gfx::OpenNewXDisplay();
initialized = true;
return true;
@@ -470,79 +390,14 @@ void* GLSurfaceGLX::GetDisplay() {
GLSurfaceGLX::~GLSurfaceGLX() {}
-#if defined(TOOLKIT_GTK)
-bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) {
- backbuffer_allocated_ = allocated;
- AdjustBufferAllocation();
- return true;
-}
-
-void NativeViewGLSurfaceGLX::SetFrontbufferAllocation(bool allocated) {
- frontbuffer_allocated_ = allocated;
- AdjustBufferAllocation();
-}
-
-void NativeViewGLSurfaceGLX::AdjustBufferAllocation() {
- if (!g_create_child_windows)
- return;
-
- if (frontbuffer_allocated_ || backbuffer_allocated_)
- CreateChildWindow();
- else
- DestroyChildWindow();
-}
-
-void NativeViewGLSurfaceGLX::CreateChildWindow() {
- DCHECK(g_create_child_windows);
-
- if (child_window_)
- return;
-
- XSetWindowAttributes set_window_attributes;
- set_window_attributes.event_mask = ExposureMask;
- child_window_ = XCreateWindow(
- g_display, parent_window_, 0, 0, size_.width(), size_.height(), 0,
- CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
- &set_window_attributes);
- g_xexpose_event_forwarder.Pointer()->AddParentChildPair(
- parent_window_, child_window_);
-
- XMapWindow(g_display, child_window_);
- XFlush(g_display);
-}
-
-void NativeViewGLSurfaceGLX::DestroyChildWindow() {
- if (!child_window_)
- return;
-
- g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair(
- parent_window_, child_window_);
- XDestroyWindow(g_display, child_window_);
- XFlush(g_display);
- child_window_ = 0;
-}
-#endif
-
NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
: parent_window_(window),
-#if defined(TOOLKIT_GTK)
- child_window_(0),
- dummy_window_(0),
- backbuffer_allocated_(true),
- frontbuffer_allocated_(true),
-#endif
+ window_(0),
config_(NULL) {
}
gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const {
-#if defined(TOOLKIT_GTK)
- if (g_create_child_windows) {
- if (child_window_)
- return child_window_;
- return dummy_window_;
- }
-#endif
- return parent_window_;
+ return window_;
}
bool NativeViewGLSurfaceGLX::Initialize() {
@@ -553,19 +408,34 @@ bool NativeViewGLSurfaceGLX::Initialize() {
return false;
}
size_ = gfx::Size(attributes.width, attributes.height);
-
- gfx::AcceleratedWidget window_for_vsync = parent_window_;
-
-#if defined(TOOLKIT_GTK)
- if (g_create_child_windows) {
- dummy_window_ = XCreateWindow(
- g_display,
- RootWindow(g_display, XScreenNumberOfScreen(attributes.screen)),
- 0, 0, 1, 1, 0, CopyFromParent, InputOutput, attributes.visual, 0, NULL);
- window_for_vsync = dummy_window_;
- CreateChildWindow();
+ // Create a child window, with a CopyFromParent visual (to avoid inducing
+ // extra blits in the driver), that we can resize exactly in Resize(),
+ // correctly ordered with GL, so that we don't have invalid transient states.
+ // See https://crbug.com/326995.
+ window_ = XCreateWindow(g_display,
+ parent_window_,
+ 0,
+ 0,
+ size_.width(),
+ size_.height(),
+ 0,
+ CopyFromParent,
+ InputOutput,
+ CopyFromParent,
+ 0,
+ NULL);
+ XMapWindow(g_display, window_);
+
+ ui::PlatformEventSource* event_source =
+ ui::PlatformEventSource::GetInstance();
+ // Can be NULL in tests, when we don't care about Exposes.
+ if (event_source) {
+ XSelectInput(g_display, window_, ExposureMask);
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
}
-#endif
+ XFlush(g_display);
+
+ gfx::AcceleratedWidget window_for_vsync = window_;
if (g_glx_oml_sync_control_supported)
vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync));
@@ -576,22 +446,34 @@ bool NativeViewGLSurfaceGLX::Initialize() {
}
void NativeViewGLSurfaceGLX::Destroy() {
-#if defined(TOOLKIT_GTK)
- DestroyChildWindow();
- if (dummy_window_)
- XDestroyWindow(g_display, dummy_window_);
- dummy_window_ = 0;
-#endif
+ if (window_) {
+ ui::PlatformEventSource* event_source =
+ ui::PlatformEventSource::GetInstance();
+ if (event_source)
+ event_source->RemovePlatformEventDispatcher(this);
+ XDestroyWindow(g_display, window_);
+ XFlush(g_display);
+ }
+}
+
+bool NativeViewGLSurfaceGLX::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return event->type == Expose && event->xexpose.window == window_;
+}
+
+uint32_t NativeViewGLSurfaceGLX::DispatchEvent(const ui::PlatformEvent& event) {
+ XEvent forwarded_event = *event;
+ forwarded_event.xexpose.window = parent_window_;
+ XSendEvent(g_display, parent_window_, False, ExposureMask,
+ &forwarded_event);
+ XFlush(g_display);
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
}
bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
-#if defined(TOOLKIT_GTK)
- if (child_window_) {
- XResizeWindow(g_display, child_window_, size.width(), size.height());
- XFlush(g_display);
- }
-#endif
size_ = size;
+ glXWaitGL();
+ XResizeWindow(g_display, window_, size.width(), size.height());
+ glXWaitX();
return true;
}
@@ -600,6 +482,10 @@ bool NativeViewGLSurfaceGLX::IsOffscreen() {
}
bool NativeViewGLSurfaceGLX::SwapBuffers() {
+ TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers",
+ "width", GetSize().width(),
+ "height", GetSize().height());
+
glXSwapBuffers(g_display, GetDrawableHandle());
return true;
}
@@ -612,13 +498,8 @@ void* NativeViewGLSurfaceGLX::GetHandle() {
return reinterpret_cast<void*>(GetDrawableHandle());
}
-std::string NativeViewGLSurfaceGLX::GetExtensions() {
- std::string extensions = GLSurface::GetExtensions();
- if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) {
- extensions += extensions.empty() ? "" : " ";
- extensions += "GL_CHROMIUM_post_sub_buffer";
- }
- return extensions;
+bool NativeViewGLSurfaceGLX::SupportsPostSubBuffer() {
+ return gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer;
}
void* NativeViewGLSurfaceGLX::GetConfig() {
@@ -638,17 +519,17 @@ void* NativeViewGLSurfaceGLX::GetConfig() {
XWindowAttributes attributes;
if (!XGetWindowAttributes(
g_display,
- parent_window_,
+ window_,
&attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " <<
- parent_window_ << ".";
+ window_ << ".";
return NULL;
}
int visual_id = XVisualIDFromVisual(attributes.visual);
int num_elements = 0;
- scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
+ scoped_ptr<GLXFBConfig, ScopedPtrXFree> configs(
glXGetFBConfigs(g_display,
DefaultScreen(g_display),
&num_elements));
@@ -693,17 +574,6 @@ VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
return vsync_provider_.get();
}
-NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
- : parent_window_(0),
-#if defined(TOOLKIT_GTK)
- child_window_(0),
- dummy_window_(0),
- backbuffer_allocated_(true),
- frontbuffer_allocated_(true),
-#endif
- config_(NULL) {
-}
-
NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
Destroy();
}
@@ -712,6 +582,10 @@ PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
: size_(size),
config_(NULL),
pbuffer_(0) {
+ // Some implementations of Pbuffer do not support having a 0 size. For such
+ // cases use a (1, 1) surface.
+ if (size_.GetArea() == 0)
+ size_.SetSize(1, 1);
}
bool PbufferGLSurfaceGLX::Initialize() {
@@ -730,7 +604,7 @@ bool PbufferGLSurfaceGLX::Initialize() {
};
int num_elements = 0;
- scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
+ scoped_ptr<GLXFBConfig, ScopedPtrXFree> configs(
glXChooseFBConfig(g_display,
DefaultScreen(g_display),
config_attributes,
diff --git a/chromium/ui/gl/gl_surface_glx.h b/chromium/ui/gl/gl_surface_glx.h
index c41f4ef178c..37c835c7e16 100644
--- a/chromium/ui/gl/gl_surface_glx.h
+++ b/chromium/ui/gl/gl_surface_glx.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gfx/vsync_provider.h"
@@ -48,7 +49,8 @@ class GL_EXPORT GLSurfaceGLX : public GLSurface {
};
// A surface used to render to a view.
-class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
+class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX,
+ public ui::PlatformEventDispatcher {
public:
explicit NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window);
@@ -60,49 +62,27 @@ class GL_EXPORT NativeViewGLSurfaceGLX : public GLSurfaceGLX {
virtual bool SwapBuffers() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual void* GetHandle() OVERRIDE;
- virtual std::string GetExtensions() OVERRIDE;
+ virtual bool SupportsPostSubBuffer() OVERRIDE;
virtual void* GetConfig() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
virtual VSyncProvider* GetVSyncProvider() OVERRIDE;
protected:
- NativeViewGLSurfaceGLX();
virtual ~NativeViewGLSurfaceGLX();
private:
// The handle for the drawable to make current or swap.
gfx::AcceleratedWidget GetDrawableHandle() const;
+ // PlatformEventDispatcher implementation
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
// Window passed in at creation. Always valid.
gfx::AcceleratedWidget parent_window_;
-#if defined(TOOLKIT_GTK)
- // Some NVIDIA drivers don't allow deleting GLX windows separately from their
- // parent X windows. Work around this by creating a child X window to the
- // window passed in to the constructor, creating the GLX window against the
- // child window, and then destroying the child window to destroy the GLX
- // window.
- // http://crbug.com/145600
- void CreateChildWindow();
- void DestroyChildWindow();
-
- // Destroy the child window when both the front and back buffers are
- // deallocated.
- virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE;
- virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE;
- void AdjustBufferAllocation();
-
- // Child window which is used with GLX, and is discarded when it is
- // backgrounded.
- gfx::AcceleratedWidget child_window_;
-
- // Dummy 1x1 window which is supplied to glXMakeCurrent when making
- // the context current while its output surface is destroyed.
- gfx::AcceleratedWidget dummy_window_;
-
- bool backbuffer_allocated_;
- bool frontbuffer_allocated_;
-#endif
+ // Child window, used to control resizes so that they're in-order with GL.
+ gfx::AcceleratedWidget window_;
void* config_;
gfx::Size size_;
diff --git a/chromium/ui/gl/gl_surface_mac.cc b/chromium/ui/gl/gl_surface_mac.cc
index d6bf072fd5b..dd5fa0ed8e4 100644
--- a/chromium/ui/gl/gl_surface_mac.cc
+++ b/chromium/ui/gl/gl_surface_mac.cc
@@ -4,24 +4,100 @@
#include "ui/gl/gl_surface.h"
+#include <OpenGL/CGLRenderers.h>
+
+#include "base/basictypes.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/mesa/src/include/GL/osmesa.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_cgl.h"
#include "ui/gl/gl_surface_osmesa.h"
#include "ui/gl/gl_surface_stub.h"
-#include "ui/gl/gl_surface_nsview.h"
+#include "ui/gl/gpu_switching_manager.h"
namespace gfx {
+namespace {
+
+// A "no-op" surface. It is not required that a CGLContextObj have an
+// associated drawable (pbuffer or fullscreen context) in order to be
+// made current. Everywhere this surface type is used, we allocate an
+// FBO at the user level as the drawable of the associated context.
+class GL_EXPORT NoOpGLSurface : public GLSurface {
+ public:
+ explicit NoOpGLSurface(const gfx::Size& size) : size_(size) {}
+
+ // Implement GLSurface.
+ virtual bool Initialize() OVERRIDE { return true; }
+ virtual void Destroy() OVERRIDE {}
+ virtual bool IsOffscreen() OVERRIDE { return true; }
+ virtual bool SwapBuffers() OVERRIDE {
+ NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurface.";
+ return false;
+ }
+ virtual gfx::Size GetSize() OVERRIDE { return size_; }
+ virtual void* GetHandle() OVERRIDE { return NULL; }
+ virtual void* GetDisplay() OVERRIDE { return NULL; }
+
+ protected:
+ virtual ~NoOpGLSurface() {}
+
+ private:
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(NoOpGLSurface);
+};
+
+// static
+bool InitializeOneOffForSandbox() {
+ static bool initialized = false;
+ if (initialized)
+ return true;
+
+ // This is called from the sandbox warmup code on Mac OS X.
+ // GPU-related stuff is very slow without this, probably because
+ // the sandbox prevents loading graphics drivers or some such.
+ std::vector<CGLPixelFormatAttribute> attribs;
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ // Avoid switching to the discrete GPU just for this pixel
+ // format selection.
+ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ }
+ if (GetGLImplementation() == kGLImplementationAppleGL) {
+ attribs.push_back(kCGLPFARendererID);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(
+ kCGLRendererGenericFloatID));
+ }
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+
+ CGLPixelFormatObj format;
+ GLint num_pixel_formats;
+ if (CGLChoosePixelFormat(&attribs.front(),
+ &format,
+ &num_pixel_formats) != kCGLNoError) {
+ LOG(ERROR) << "Error choosing pixel format.";
+ return false;
+ }
+ if (!format) {
+ LOG(ERROR) << "format == 0.";
+ return false;
+ }
+ CGLReleasePixelFormat(format);
+ DCHECK_NE(num_pixel_formats, 0);
+ initialized = true;
+ return true;
+}
+
+} // namespace
bool GLSurface::InitializeOneOffInternal() {
switch (GetGLImplementation()) {
case kGLImplementationDesktopGL:
case kGLImplementationAppleGL:
- if (!GLSurfaceCGL::InitializeOneOff()) {
+ if (!InitializeOneOffForSandbox()) {
LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed.";
return false;
}
@@ -38,11 +114,8 @@ scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
switch (GetGLImplementation()) {
case kGLImplementationDesktopGL:
case kGLImplementationAppleGL: {
- scoped_refptr<GLSurface> surface(new GLSurfaceNSView(window));
- if (!surface->Initialize())
- return NULL;
-
- return surface;
+ NOTIMPLEMENTED() << "No onscreen support on Mac.";
+ return NULL;
}
case kGLImplementationMockGL:
return new GLSurfaceStub;
@@ -66,7 +139,7 @@ scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
}
case kGLImplementationDesktopGL:
case kGLImplementationAppleGL: {
- scoped_refptr<GLSurface> surface(new NoOpGLSurfaceCGL(size));
+ scoped_refptr<GLSurface> surface(new NoOpGLSurface(size));
if (!surface->Initialize())
return NULL;
diff --git a/chromium/ui/gl/gl_surface_nsview.h b/chromium/ui/gl/gl_surface_nsview.h
deleted file mode 100644
index 5562ca106ab..00000000000
--- a/chromium/ui/gl/gl_surface_nsview.h
+++ /dev/null
@@ -1,47 +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_GL_GL_SURFACE_NSVIEW_H_
-#define UI_GL_GL_SURFACE_NSVIEW_H_
-
-#include "base/compiler_specific.h"
-#include "ui/gfx/size.h"
-#include "ui/gl/gl_surface.h"
-
-namespace gfx {
-
-class GLContextNSView;
-
-// GLSurfaceNSView provides an implementation of the the GLSurface interface
-// that is backed by an NSView. This interface pairs with the GLContextNSView
-// class, and the NSView is expected to use this context for drawing.
-class GL_EXPORT GLSurfaceNSView : public GLSurface {
- public:
- explicit GLSurfaceNSView(AcceleratedWidget view);
-
- // GLSurface:
- virtual void Destroy() OVERRIDE;
- virtual bool IsOffscreen() OVERRIDE;
- virtual bool SwapBuffers() OVERRIDE;
- virtual gfx::Size GetSize() OVERRIDE;
- virtual void* GetHandle() OVERRIDE;
-
- // Allow the surface to call back to context when in need of |FlushBuffer|.
- virtual bool OnMakeCurrent(GLContext* context) OVERRIDE;
-
- private:
- virtual ~GLSurfaceNSView();
-
- // Weak. An |NSView*|.
- AcceleratedWidget view_;
-
- // Weak. Associated context.
- GLContextNSView* context_;
-
- DISALLOW_COPY_AND_ASSIGN(GLSurfaceNSView);
-};
-
-} // namespace gfx
-
-#endif // UI_GL_GL_SURFACE_NSVIEW_H_
diff --git a/chromium/ui/gl/gl_surface_nsview.mm b/chromium/ui/gl/gl_surface_nsview.mm
deleted file mode 100644
index ded07197108..00000000000
--- a/chromium/ui/gl/gl_surface_nsview.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/gl_surface_nsview.h"
-
-#import <AppKit/NSOpenGL.h>
-#import <AppKit/NSView.h>
-
-#include "ui/gl/gl_context_nsview.h"
-
-namespace gfx {
-
-GLSurfaceNSView::GLSurfaceNSView(AcceleratedWidget view)
- : view_(view),
- context_(NULL) {
-}
-
-GLSurfaceNSView::~GLSurfaceNSView() {
-}
-
-void GLSurfaceNSView::Destroy() {
-}
-
-bool GLSurfaceNSView::IsOffscreen() {
- return false;
-}
-
-bool GLSurfaceNSView::SwapBuffers() {
- context_->FlushBuffer();
- return true;
-}
-
-gfx::Size GLSurfaceNSView::GetSize() {
- return gfx::Size(NSSizeToCGSize([view_ bounds].size));
-}
-
-void* GLSurfaceNSView::GetHandle() {
- return view_;
-}
-
-bool GLSurfaceNSView::OnMakeCurrent(GLContext* context) {
- context_ = static_cast<GLContextNSView *>(context);
- return true;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_osmesa.cc b/chromium/ui/gl/gl_surface_osmesa.cc
index 9a556bc9982..58d955be002 100644
--- a/chromium/ui/gl/gl_surface_osmesa.cc
+++ b/chromium/ui/gl/gl_surface_osmesa.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/logging.h"
+#include "third_party/mesa/src/include/GL/osmesa.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_osmesa.h"
@@ -13,6 +14,10 @@ namespace gfx {
GLSurfaceOSMesa::GLSurfaceOSMesa(unsigned format, const gfx::Size& size)
: format_(format),
size_(size) {
+ // Implementations of OSMesa surface do not support having a 0 size. In such
+ // cases use a (1, 1) surface.
+ if (size_.GetArea() == 0)
+ size_.SetSize(1, 1);
}
bool GLSurfaceOSMesa::Initialize() {
@@ -82,4 +87,13 @@ GLSurfaceOSMesa::~GLSurfaceOSMesa() {
Destroy();
}
+bool GLSurfaceOSMesaHeadless::IsOffscreen() { return false; }
+
+bool GLSurfaceOSMesaHeadless::SwapBuffers() { return true; }
+
+GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless()
+ : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)) {}
+
+GLSurfaceOSMesaHeadless::~GLSurfaceOSMesaHeadless() { Destroy(); }
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_osmesa.h b/chromium/ui/gl/gl_surface_osmesa.h
index a823231fa0c..b4b48274913 100644
--- a/chromium/ui/gl/gl_surface_osmesa.h
+++ b/chromium/ui/gl/gl_surface_osmesa.h
@@ -39,6 +39,23 @@ class GL_EXPORT GLSurfaceOSMesa : public GLSurface {
DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesa);
};
+// A thin subclass of |GLSurfaceOSMesa| that can be used in place
+// of a native hardware-provided surface when a native surface
+// provider is not available.
+class GLSurfaceOSMesaHeadless : public GLSurfaceOSMesa {
+ public:
+ explicit GLSurfaceOSMesaHeadless();
+
+ virtual bool IsOffscreen() OVERRIDE;
+ virtual bool SwapBuffers() OVERRIDE;
+
+ protected:
+ virtual ~GLSurfaceOSMesaHeadless();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesaHeadless);
+};
+
} // namespace gfx
#endif // UI_GL_GL_SURFACE_OSMESA_H_
diff --git a/chromium/ui/gl/gl_surface_ozone.cc b/chromium/ui/gl/gl_surface_ozone.cc
new file mode 100644
index 00000000000..437226163db
--- /dev/null
+++ b/chromium/ui/gl/gl_surface_ozone.cc
@@ -0,0 +1,143 @@
+// 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/gl/gl_surface.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_osmesa.h"
+#include "ui/gl/gl_surface_stub.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace gfx {
+
+namespace {
+
+// A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
+class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
+ public:
+ GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface)
+ : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
+ ozone_surface_(ozone_surface.Pass()) {}
+
+ virtual bool Resize(const gfx::Size& size) OVERRIDE {
+ if (!ozone_surface_->ResizeNativeWindow(size))
+ return false;
+
+ return NativeViewGLSurfaceEGL::Resize(size);
+ }
+ virtual bool SwapBuffers() OVERRIDE {
+ if (!NativeViewGLSurfaceEGL::SwapBuffers())
+ return false;
+
+ return ozone_surface_->OnSwapBuffers();
+ }
+
+ private:
+ virtual ~GLSurfaceOzoneEGL() {
+ Destroy(); // EGL surface must be destroyed before SurfaceOzone
+ }
+
+ // The native surface. Deleting this is allowed to free the EGLNativeWindow.
+ scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL);
+};
+
+} // namespace
+
+// static
+bool GLSurface::InitializeOneOffInternal() {
+ switch (GetGLImplementation()) {
+ case kGLImplementationEGLGLES2:
+ if (ui::SurfaceFactoryOzone::GetInstance()->InitializeHardware() !=
+ ui::SurfaceFactoryOzone::INITIALIZED) {
+ LOG(ERROR) << "Ozone failed to initialize hardware";
+ return false;
+ }
+
+ if (!GLSurfaceEGL::InitializeOneOff()) {
+ LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
+ return false;
+ }
+
+ return true;
+ case kGLImplementationOSMesaGL:
+ case kGLImplementationMockGL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// static
+scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
+ gfx::AcceleratedWidget window) {
+ if (GetGLImplementation() == kGLImplementationOSMesaGL) {
+ scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
+ if (!surface->Initialize())
+ return NULL;
+ return surface;
+ }
+ DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
+ if (window != kNullAcceleratedWidget) {
+ scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
+ ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
+ window);
+ if (!surface_ozone)
+ return NULL;
+
+ scoped_ptr<VSyncProvider> vsync_provider =
+ surface_ozone->CreateVSyncProvider();
+ scoped_refptr<GLSurfaceOzoneEGL> surface =
+ new GLSurfaceOzoneEGL(surface_ozone.Pass());
+ if (!surface->Initialize(vsync_provider.Pass()))
+ return NULL;
+ return surface;
+ } else {
+ scoped_refptr<GLSurface> surface = new GLSurfaceStub();
+ if (surface->Initialize())
+ return surface;
+ }
+ return NULL;
+}
+
+// static
+scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
+ const gfx::Size& size) {
+ switch (GetGLImplementation()) {
+ case kGLImplementationOSMesaGL: {
+ scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(1, size));
+ if (!surface->Initialize())
+ return NULL;
+
+ return surface;
+ }
+ case kGLImplementationEGLGLES2: {
+ scoped_refptr<GLSurface> surface;
+ if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
+ (size.width() == 0 && size.height() == 0)) {
+ surface = new SurfacelessEGL(size);
+ } else
+ surface = new PbufferGLSurfaceEGL(size);
+
+ if (!surface->Initialize())
+ return NULL;
+ return surface;
+ }
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
+ return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_wgl.cc b/chromium/ui/gl/gl_surface_wgl.cc
index 7e1c3a7ad1f..23391eada1e 100644
--- a/chromium/ui/gl/gl_surface_wgl.cc
+++ b/chromium/ui/gl/gl_surface_wgl.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_surface_wgl.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "ui/gl/gl_bindings.h"
@@ -164,25 +165,6 @@ bool GLSurfaceWGL::InitializeOneOff() {
if (!wgl_display->Init())
return false;
- // Create a temporary GL context to bind to extension entry points.
- HGLRC gl_context = wglCreateContext(wgl_display->device_context());
- if (!gl_context) {
- LOG(ERROR) << "Failed to create temporary context.";
- return false;
- }
- if (!wglMakeCurrent(wgl_display->device_context(), gl_context)) {
- LOG(ERROR) << "Failed to make temporary GL context current.";
- wglDeleteContext(gl_context);
- return false;
- }
- // Get bindings to extension functions that cannot be acquired without a
- // current context.
- InitializeGLBindingsGL();
- InitializeGLBindingsWGL();
-
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(gl_context);
-
g_display = wgl_display.release();
initialized = true;
return true;
@@ -267,6 +249,10 @@ bool NativeViewGLSurfaceWGL::IsOffscreen() {
}
bool NativeViewGLSurfaceWGL::SwapBuffers() {
+ TRACE_EVENT2("gpu", "NativeViewGLSurfaceWGL:RealSwapBuffers",
+ "width", GetSize().width(),
+ "height", GetSize().height());
+
// Resize the child window to match the parent before swapping. Do not repaint
// it as it moves.
RECT rect;
@@ -299,6 +285,10 @@ PbufferGLSurfaceWGL::PbufferGLSurfaceWGL(const gfx::Size& size)
: size_(size),
device_context_(NULL),
pbuffer_(NULL) {
+ // Some implementations of Pbuffer do not support having a 0 size. For such
+ // cases use a (1, 1) surface.
+ if (size_.GetArea() == 0)
+ size_.SetSize(1, 1);
}
PbufferGLSurfaceWGL::~PbufferGLSurfaceWGL() {
diff --git a/chromium/ui/gl/gl_surface_win.cc b/chromium/ui/gl/gl_surface_win.cc
index ff2ed84267c..c0a223b7608 100644
--- a/chromium/ui/gl/gl_surface_win.cc
+++ b/chromium/ui/gl/gl_surface_win.cc
@@ -6,12 +6,14 @@
#include <dwmapi.h>
+#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
#include "third_party/mesa/src/include/GL/osmesa.h"
#include "ui/gfx/frame_time.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface_egl.h"
@@ -19,6 +21,12 @@
#include "ui/gl/gl_surface_stub.h"
#include "ui/gl/gl_surface_wgl.h"
+// From ANGLE's egl/eglext.h.
+#if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
+#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
+ reinterpret_cast<EGLNativeDisplayType>(-2)
+#endif
+
namespace gfx {
// This OSMesa GL surface can use GDI to swap the contents of the buffer to a
@@ -33,7 +41,7 @@ class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
virtual void Destroy() OVERRIDE;
virtual bool IsOffscreen() OVERRIDE;
virtual bool SwapBuffers() OVERRIDE;
- virtual std::string GetExtensions() OVERRIDE;
+ virtual bool SupportsPostSubBuffer() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
private:
@@ -83,7 +91,7 @@ class DWMVSyncProvider : public VSyncProvider {
};
// Helper routine that does one-off initialization like determining the
-// pixel format and initializing the GL bindings.
+// pixel format.
bool GLSurface::InitializeOneOffInternal() {
switch (GetGLImplementation()) {
case kGLImplementationDesktopGL:
@@ -171,11 +179,8 @@ bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
return true;
}
-std::string NativeViewGLSurfaceOSMesa::GetExtensions() {
- std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions();
- extensions += extensions.empty() ? "" : " ";
- extensions += "GL_CHROMIUM_post_sub_buffer";
- return extensions;
+bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
+ return true;
}
bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
@@ -228,12 +233,13 @@ scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
return surface;
}
case kGLImplementationEGLGLES2: {
+ DCHECK(window != gfx::kNullAcceleratedWidget);
scoped_refptr<NativeViewGLSurfaceEGL> surface(
new NativeViewGLSurfaceEGL(window));
- DWMVSyncProvider* sync_provider = NULL;
+ scoped_ptr<VSyncProvider> sync_provider;
if (base::win::GetVersion() >= base::win::VERSION_VISTA)
- sync_provider = new DWMVSyncProvider;
- if (!surface->Initialize(sync_provider))
+ sync_provider.reset(new DWMVSyncProvider);
+ if (!surface->Initialize(sync_provider.Pass()))
return NULL;
return surface;
@@ -288,4 +294,11 @@ scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
}
}
+EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11))
+ return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
+
+ return EGL_DEFAULT_DISPLAY;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_surface_x11.cc b/chromium/ui/gl/gl_surface_x11.cc
index 5053a56531e..a5d5aab7812 100644
--- a/chromium/ui/gl/gl_surface_x11.cc
+++ b/chromium/ui/gl/gl_surface_x11.cc
@@ -9,6 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "third_party/mesa/src/include/GL/osmesa.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface_egl.h"
@@ -18,10 +20,6 @@
namespace gfx {
-namespace {
-Display* g_osmesa_display;
-} // namespace
-
// This OSMesa GL surface can use XLib to swap the contents of the buffer to a
// view.
class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
@@ -36,13 +34,14 @@ class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
virtual bool Resize(const gfx::Size& new_size) OVERRIDE;
virtual bool IsOffscreen() OVERRIDE;
virtual bool SwapBuffers() OVERRIDE;
- virtual std::string GetExtensions() OVERRIDE;
+ virtual bool SupportsPostSubBuffer() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
protected:
virtual ~NativeViewGLSurfaceOSMesa();
private:
+ Display* xdisplay_;
GC window_graphics_context_;
gfx::AcceleratedWidget window_;
GC pixmap_graphics_context_;
@@ -80,21 +79,23 @@ bool GLSurface::InitializeOneOffInternal() {
NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
gfx::AcceleratedWidget window)
- : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)),
- window_graphics_context_(0),
- window_(window),
- pixmap_graphics_context_(0),
- pixmap_(0) {
- DCHECK(window);
+ : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)),
+ xdisplay_(gfx::GetXDisplay()),
+ window_graphics_context_(0),
+ window_(window),
+ pixmap_graphics_context_(0),
+ pixmap_(0) {
+ DCHECK(xdisplay_);
+ DCHECK(window_);
}
+// static
bool NativeViewGLSurfaceOSMesa::InitializeOneOff() {
static bool initialized = false;
if (initialized)
return true;
- g_osmesa_display = base::MessagePumpForUI::GetDefaultXDisplay();
- if (!g_osmesa_display) {
+ if (!gfx::GetXDisplay()) {
LOG(ERROR) << "XOpenDisplay failed.";
return false;
}
@@ -107,10 +108,7 @@ bool NativeViewGLSurfaceOSMesa::Initialize() {
if (!GLSurfaceOSMesa::Initialize())
return false;
- window_graphics_context_ = XCreateGC(g_osmesa_display,
- window_,
- 0,
- NULL);
+ window_graphics_context_ = XCreateGC(xdisplay_, window_, 0, NULL);
if (!window_graphics_context_) {
LOG(ERROR) << "XCreateGC failed.";
Destroy();
@@ -122,21 +120,21 @@ bool NativeViewGLSurfaceOSMesa::Initialize() {
void NativeViewGLSurfaceOSMesa::Destroy() {
if (pixmap_graphics_context_) {
- XFreeGC(g_osmesa_display, pixmap_graphics_context_);
+ XFreeGC(xdisplay_, pixmap_graphics_context_);
pixmap_graphics_context_ = NULL;
}
if (pixmap_) {
- XFreePixmap(g_osmesa_display, pixmap_);
+ XFreePixmap(xdisplay_, pixmap_);
pixmap_ = 0;
}
if (window_graphics_context_) {
- XFreeGC(g_osmesa_display, window_graphics_context_);
+ XFreeGC(xdisplay_, window_graphics_context_);
window_graphics_context_ = NULL;
}
- XSync(g_osmesa_display, False);
+ XSync(xdisplay_, False);
}
bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) {
@@ -144,23 +142,23 @@ bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) {
return false;
XWindowAttributes attributes;
- if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
+ if (!XGetWindowAttributes(xdisplay_, window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
return false;
}
// Destroy the previous pixmap and graphics context.
if (pixmap_graphics_context_) {
- XFreeGC(g_osmesa_display, pixmap_graphics_context_);
+ XFreeGC(xdisplay_, pixmap_graphics_context_);
pixmap_graphics_context_ = NULL;
}
if (pixmap_) {
- XFreePixmap(g_osmesa_display, pixmap_);
+ XFreePixmap(xdisplay_, pixmap_);
pixmap_ = 0;
}
// Recreate a pixmap to hold the frame.
- pixmap_ = XCreatePixmap(g_osmesa_display,
+ pixmap_ = XCreatePixmap(xdisplay_,
window_,
new_size.width(),
new_size.height(),
@@ -171,7 +169,7 @@ bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) {
}
// Recreate a graphics context for the pixmap.
- pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL);
+ pixmap_graphics_context_ = XCreateGC(xdisplay_, pixmap_, 0, NULL);
if (!pixmap_graphics_context_) {
LOG(ERROR) << "XCreateGC failed";
return false;
@@ -185,16 +183,20 @@ bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
}
bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
+ TRACE_EVENT2("gpu", "NativeViewGLSurfaceOSMesa:RealSwapBuffers",
+ "width", GetSize().width(),
+ "height", GetSize().height());
+
gfx::Size size = GetSize();
XWindowAttributes attributes;
- if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
+ if (!XGetWindowAttributes(xdisplay_, window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
return false;
}
// Copy the frame into the pixmap.
- gfx::PutARGBImage(g_osmesa_display,
+ gfx::PutARGBImage(xdisplay_,
attributes.visual,
attributes.depth,
pixmap_,
@@ -204,22 +206,22 @@ bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
size.height());
// Copy the pixmap to the window.
- XCopyArea(g_osmesa_display,
+ XCopyArea(xdisplay_,
pixmap_,
window_,
window_graphics_context_,
- 0, 0,
- size.width(), size.height(),
- 0, 0);
+ 0,
+ 0,
+ size.width(),
+ size.height(),
+ 0,
+ 0);
return true;
}
-std::string NativeViewGLSurfaceOSMesa::GetExtensions() {
- std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions();
- extensions += extensions.empty() ? "" : " ";
- extensions += "GL_CHROMIUM_post_sub_buffer";
- return extensions;
+bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
+ return true;
}
bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
@@ -230,13 +232,13 @@ bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
y = size.height() - y - height;
XWindowAttributes attributes;
- if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
+ if (!XGetWindowAttributes(xdisplay_, window_, &attributes)) {
LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
return false;
}
// Copy the frame into the pixmap.
- gfx::PutARGBImage(g_osmesa_display,
+ gfx::PutARGBImage(xdisplay_,
attributes.visual,
attributes.depth,
pixmap_,
@@ -244,19 +246,24 @@ bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
static_cast<const uint8*>(GetHandle()),
size.width(),
size.height(),
- x, y,
- x, y,
+ x,
+ y,
+ x,
+ y,
width,
height);
// Copy the pixmap to the window.
- XCopyArea(g_osmesa_display,
+ XCopyArea(xdisplay_,
pixmap_,
window_,
window_graphics_context_,
- x, y,
- width, height,
- x, y);
+ x,
+ y,
+ width,
+ height,
+ x,
+ y);
return true;
}
@@ -285,6 +292,7 @@ scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
return surface;
}
case kGLImplementationEGLGLES2: {
+ DCHECK(window != gfx::kNullAcceleratedWidget);
scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL(window));
if (!surface->Initialize())
return NULL;
@@ -333,4 +341,8 @@ scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
}
}
+EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
+ return gfx::GetXDisplay();
+}
+
} // namespace gfx
diff --git a/chromium/ui/gl/gl_switches.cc b/chromium/ui/gl/gl_switches.cc
index 5ac514878b4..7eaa3d8c464 100644
--- a/chromium/ui/gl/gl_switches.cc
+++ b/chromium/ui/gl/gl_switches.cc
@@ -18,9 +18,6 @@ const char kGLImplementationMockName[] = "mock";
namespace switches {
-// Enables use of D3D11 when available.
-const char kEnableD3D11[] = "enable-d3d11";
-
// Disables use of D3D11.
const char kDisableD3D11[] = "disable-d3d11";
@@ -49,34 +46,35 @@ const char kSwiftShaderPath[] = "swiftshader-path";
// context will never be lost in any situations, say, a GPU reset.
const char kGpuNoContextLost[] = "gpu-no-context-lost";
-// Add a delay in milliseconds to the gpu swap buffer completion signal.
-// Simulates a slow GPU.
-const char kGpuSwapDelay[] = "gpu-swap-delay";
-
// Indicates whether the dual GPU switching is supported or not.
const char kSupportsDualGpus[] = "supports-dual-gpus";
-// Overwrite the default GPU automatic switching behavior to force on
-// integrated GPU or discrete GPU.
-const char kGpuSwitching[] = "gpu-switching";
-
-const char kGpuSwitchingOptionNameForceIntegrated[] = "force_integrated";
-const char kGpuSwitchingOptionNameForceDiscrete[] = "force_discrete";
-
// Flag used for Linux tests: for desktop GL bindings, try to load this GL
// library first, but fall back to regular library if loading fails.
const char kTestGLLib[] = "test-gl-lib";
+// Use hardware gpu, if available, for tests.
+const char kUseGpuInTests[] = "use-gpu-in-tests";
+
+// Disables GL drawing operations which produce pixel output. With this
+// the GL output will not be correct but tests will run faster.
+const char kDisableGLDrawingForTests[] = "disable-gl-drawing-for-tests";
+
+// Forces the use of OSMesa instead of hardware gpu.
+const char kOverrideUseGLWithOSMesaForTests[] =
+ "override-use-gl-with-osmesa-for-tests";
+
// This is the list of switches passed from this file that are passed from the
// GpuProcessHost to the GPU Process. Add your switch to this list if you need
// to read it in the GPU process, else don't add it.
const char* kGLSwitchesCopiedFromGpuProcessHost[] = {
kDisableGpuVsync,
- kEnableD3D11,
kDisableD3D11,
kEnableGPUServiceLogging,
kEnableGPUServiceTracing,
kGpuNoContextLost,
+ kDisableGLDrawingForTests,
+ kOverrideUseGLWithOSMesaForTests,
};
const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches =
arraysize(kGLSwitchesCopiedFromGpuProcessHost);
diff --git a/chromium/ui/gl/gl_switches.h b/chromium/ui/gl/gl_switches.h
index 57590d7bd87..2824cec374e 100644
--- a/chromium/ui/gl/gl_switches.h
+++ b/chromium/ui/gl/gl_switches.h
@@ -23,27 +23,23 @@ extern const char kGLImplementationMockName[];
namespace switches {
-GL_EXPORT extern const char kEnableD3D11[];
GL_EXPORT extern const char kDisableD3D11[];
GL_EXPORT extern const char kDisableGpuVsync[];
GL_EXPORT extern const char kEnableGPUServiceLogging[];
GL_EXPORT extern const char kEnableGPUClientLogging[];
GL_EXPORT extern const char kEnableGPUServiceTracing[];
GL_EXPORT extern const char kGpuNoContextLost[];
-GL_EXPORT extern const char kGpuSwapDelay[];
GL_EXPORT extern const char kSupportsDualGpus[];
-GL_EXPORT extern const char kGpuSwitching[];
-
-// The GPU switching names that can be passed to --gpu-switching.
-GL_EXPORT extern const char kGpuSwitchingOptionNameForceIntegrated[];
-GL_EXPORT extern const char kGpuSwitchingOptionNameForceDiscrete[];
-// The last one (automatic) is not used as commandline switch option.
-GL_EXPORT extern const char kGpuSwitchingOptionNameAutomatic[];
GL_EXPORT extern const char kUseGL[];
GL_EXPORT extern const char kSwiftShaderPath[];
GL_EXPORT extern const char kTestGLLib[];
+GL_EXPORT extern const char kUseGpuInTests[];
+
+// These flags are used by the test harness code, not passed in by users.
+GL_EXPORT extern const char kDisableGLDrawingForTests[];
+GL_EXPORT extern const char kOverrideUseGLWithOSMesaForTests[];
GL_EXPORT extern const char* kGLSwitchesCopiedFromGpuProcessHost[];
GL_EXPORT extern const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches;
diff --git a/chromium/ui/gl/gl_version_info.cc b/chromium/ui/gl/gl_version_info.cc
new file mode 100644
index 00000000000..996c44f22cf
--- /dev/null
+++ b/chromium/ui/gl/gl_version_info.cc
@@ -0,0 +1,42 @@
+// 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/gl/gl_version_info.h"
+
+#include "base/strings/string_util.h"
+
+namespace gfx {
+
+GLVersionInfo::GLVersionInfo(const char* version_str, const char* renderer_str)
+ : is_es(false),
+ is_es1(false),
+ is_es2(false),
+ is_es3(false),
+ is_gl1(false),
+ is_gl2(false),
+ is_gl3(false),
+ is_gl4(false),
+ is_angle(false) {
+ if (version_str) {
+ std::string lstr(StringToLowerASCII(std::string(version_str)));
+ is_es = (lstr.substr(0, 9) == "opengl es");
+ if (is_es) {
+ is_es1 = (lstr.substr(9, 2) == "-c" && lstr.substr(13, 2) == "1.");
+ is_es2 = (lstr.substr(9, 3) == " 2.");
+ is_es3 = (lstr.substr(9, 3) == " 3.");
+ } else {
+ is_gl2 = (lstr.substr(0, 2) == "2.");
+ is_gl3 = (lstr.substr(0, 2) == "3.");
+ is_gl4 = (lstr.substr(0, 2) == "4.");
+ // In early GL versions, GetString output format is implementation
+ // dependent.
+ is_gl1 = !is_gl2 && !is_gl3 && !is_gl4;
+ }
+ }
+ if (renderer_str) {
+ is_angle = StartsWithASCII(renderer_str, "ANGLE", true);
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/gl_version_info.h b/chromium/ui/gl/gl_version_info.h
new file mode 100644
index 00000000000..13b323faaf3
--- /dev/null
+++ b/chromium/ui/gl/gl_version_info.h
@@ -0,0 +1,36 @@
+// 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_GL_GL_VERSION_INFO_H_
+#define UI_GL_GL_VERSION_INFO_H_
+
+#include <string>
+#include "base/basictypes.h"
+
+namespace gfx {
+
+struct GLVersionInfo {
+ GLVersionInfo(const char* version_str, const char* renderer_str);
+
+ // New flags, such as is_gl4_4 could be introduced as needed.
+ // For now, this level of granularity is enough.
+ bool is_es;
+ bool is_es1;
+ bool is_es2;
+ bool is_es3;
+
+ bool is_gl1;
+ bool is_gl2;
+ bool is_gl3;
+ bool is_gl4;
+
+ bool is_angle;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GLVersionInfo);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_GL_VERSION_INFO_H_
diff --git a/chromium/ui/gl/gl_wgl_api_implementation.cc b/chromium/ui/gl/gl_wgl_api_implementation.cc
index e3f71d83592..889a53f1b8d 100644
--- a/chromium/ui/gl/gl_wgl_api_implementation.cc
+++ b/chromium/ui/gl/gl_wgl_api_implementation.cc
@@ -9,8 +9,8 @@ namespace gfx {
RealWGLApi* g_real_wgl;
-void InitializeGLBindingsWGL() {
- g_driver_wgl.InitializeBindings();
+void InitializeStaticGLBindingsWGL() {
+ g_driver_wgl.InitializeStaticBindings();
if (!g_real_wgl) {
g_real_wgl = new RealWGLApi();
}
@@ -18,8 +18,8 @@ void InitializeGLBindingsWGL() {
g_current_wgl_context = g_real_wgl;
}
-void InitializeGLExtensionBindingsWGL(GLContext* context) {
- g_driver_wgl.InitializeExtensionBindings(context);
+void InitializeDynamicGLBindingsWGL(GLContext* context) {
+ g_driver_wgl.InitializeDynamicBindings(context);
}
void InitializeDebugGLBindingsWGL() {
diff --git a/chromium/ui/gl/gl_wgl_api_implementation.h b/chromium/ui/gl/gl_wgl_api_implementation.h
index 9e1188903ae..07a52756f52 100644
--- a/chromium/ui/gl/gl_wgl_api_implementation.h
+++ b/chromium/ui/gl/gl_wgl_api_implementation.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_WGL_API_IMPLEMENTATION_H_
-#define UI_GL_WGL_API_IMPLEMENTATION_H_
+#ifndef UI_GL_GL_WGL_API_IMPLEMENTATION_H_
+#define UI_GL_GL_WGL_API_IMPLEMENTATION_H_
#include "base/compiler_specific.h"
#include "ui/gl/gl_bindings.h"
@@ -14,8 +14,8 @@ namespace gfx {
class GLContext;
struct GLWindowSystemBindingInfo;
-void InitializeGLBindingsWGL();
-void InitializeGLExtensionBindingsWGL(GLContext* context);
+void InitializeStaticGLBindingsWGL();
+void InitializeDynamicGLBindingsWGL(GLContext* context);
void InitializeDebugGLBindingsWGL();
void ClearGLBindingsWGL();
bool GetGLWindowSystemBindingInfoWGL(GLWindowSystemBindingInfo* info);
@@ -59,7 +59,7 @@ class GL_EXPORT TraceWGLApi : public WGLApi {
} // namespace gfx
-#endif // UI_GL_WGL_API_IMPLEMENTATION_H_
+#endif // UI_GL_GL_WGL_API_IMPLEMENTATION_H_
diff --git a/chromium/ui/gl/gpu_preference.h b/chromium/ui/gl/gpu_preference.h
index 48e2903859b..8d0303620dc 100644
--- a/chromium/ui/gl/gpu_preference.h
+++ b/chromium/ui/gl/gpu_preference.h
@@ -16,7 +16,8 @@ namespace gfx {
// implemented on more operating systems.
enum GpuPreference {
PreferIntegratedGpu,
- PreferDiscreteGpu
+ PreferDiscreteGpu,
+ GpuPreferenceLast = PreferDiscreteGpu
};
} // namespace gfx
diff --git a/chromium/ui/gl/io_surface_support_mac.cc b/chromium/ui/gl/io_surface_support_mac.cc
deleted file mode 100644
index a7aeae85f8e..00000000000
--- a/chromium/ui/gl/io_surface_support_mac.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <dlfcn.h>
-
-#include "base/memory/singleton.h"
-#include "ui/gl/io_surface_support_mac.h"
-
-typedef CFTypeRef (*IOSurfaceCreateProcPtr)(CFDictionaryRef properties);
-typedef uint32 (*IOSurfaceGetIDProcPtr)(CFTypeRef io_surface);
-typedef CFTypeRef (*IOSurfaceLookupProcPtr)(uint32 io_surface_id);
-typedef mach_port_t (*IOSurfaceCreateMachPortProcPtr)(CFTypeRef io_surface);
-typedef CFTypeRef (*IOSurfaceLookupFromMachPortProcPtr)(mach_port_t port);
-typedef size_t (*IOSurfaceGetWidthPtr)(CFTypeRef io_surface);
-typedef size_t (*IOSurfaceGetHeightPtr)(CFTypeRef io_surface);
-typedef size_t (*IOSurfaceGetBytesPerRowPtr)(CFTypeRef io_surface);
-typedef void* (*IOSurfaceGetBaseAddressPtr)(CFTypeRef io_surface);
-typedef IOReturn (*IOSurfaceLockPtr)(CFTypeRef io_surface,
- uint32 options,
- uint32* seed);
-typedef IOReturn (*IOSurfaceUnlockPtr)(CFTypeRef io_surface,
- uint32 options,
- uint32* seed);
-
-typedef CGLError (*CGLTexImageIOSurface2DProcPtr)(CGLContextObj ctx,
- GLenum target,
- GLenum internal_format,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- CFTypeRef io_surface,
- GLuint plane);
-typedef CFTypeRef (*CVPixelBufferGetIOSurfaceProcPtr)(
- CVPixelBufferRef pixel_buffer);
-
-class IOSurfaceSupportImpl : public IOSurfaceSupport {
- public:
- static IOSurfaceSupportImpl* GetInstance();
-
- bool InitializedSuccessfully() {
- return initialized_successfully_;
- }
-
- virtual CFStringRef GetKIOSurfaceWidth() OVERRIDE;
- virtual CFStringRef GetKIOSurfaceHeight() OVERRIDE;
- virtual CFStringRef GetKIOSurfaceBytesPerElement() OVERRIDE;
- virtual CFStringRef GetKIOSurfacePixelFormat() OVERRIDE;
- virtual CFStringRef GetKIOSurfaceIsGlobal() OVERRIDE;
-
- virtual CFTypeRef IOSurfaceCreate(CFDictionaryRef properties) OVERRIDE;
- virtual uint32 IOSurfaceGetID(CFTypeRef io_surface) OVERRIDE;
- virtual CFTypeRef IOSurfaceLookup(uint32 io_surface_id) OVERRIDE;
- virtual mach_port_t IOSurfaceCreateMachPort(CFTypeRef io_surface) OVERRIDE;
- virtual CFTypeRef IOSurfaceLookupFromMachPort(mach_port_t port) OVERRIDE;
-
- virtual size_t IOSurfaceGetWidth(CFTypeRef io_surface) OVERRIDE;
- virtual size_t IOSurfaceGetHeight(CFTypeRef io_surface) OVERRIDE;
- virtual size_t IOSurfaceGetBytesPerRow(CFTypeRef io_surface) OVERRIDE;
- virtual void* IOSurfaceGetBaseAddress(CFTypeRef io_surface) OVERRIDE;
-
- virtual IOReturn IOSurfaceLock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) OVERRIDE;
- virtual IOReturn IOSurfaceUnlock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) OVERRIDE;
-
- virtual CGLError CGLTexImageIOSurface2D(CGLContextObj ctx,
- GLenum target,
- GLenum internal_format,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- CFTypeRef io_surface,
- GLuint plane) OVERRIDE;
-
- virtual CFTypeRef CVPixelBufferGetIOSurface(
- CVPixelBufferRef pixel_buffer) OVERRIDE;
-
- private:
- IOSurfaceSupportImpl();
- virtual ~IOSurfaceSupportImpl();
-
- void CloseLibraryHandles();
-
- void* iosurface_handle_;
- void* opengl_handle_;
- void* core_video_handle_;
- CFStringRef k_io_surface_width_;
- CFStringRef k_io_surface_height_;
- CFStringRef k_io_surface_bytes_per_element_;
- CFStringRef k_io_surface_pixel_format_;
- CFStringRef k_io_surface_is_global_;
- IOSurfaceCreateProcPtr io_surface_create_;
- IOSurfaceGetIDProcPtr io_surface_get_id_;
- IOSurfaceLookupProcPtr io_surface_lookup_;
- IOSurfaceCreateMachPortProcPtr io_surface_create_mach_port_;
- IOSurfaceLookupFromMachPortProcPtr io_surface_lookup_from_mach_port_;
- IOSurfaceGetWidthPtr io_surface_get_width_;
- IOSurfaceGetHeightPtr io_surface_get_height_;
- IOSurfaceGetBytesPerRowPtr io_surface_get_bytes_per_row_;
- IOSurfaceGetBaseAddressPtr io_surface_get_base_address_;
- IOSurfaceLockPtr io_surface_lock_;
- IOSurfaceUnlockPtr io_surface_unlock_;
- CGLTexImageIOSurface2DProcPtr cgl_tex_image_io_surface_2d_;
- CVPixelBufferGetIOSurfaceProcPtr cv_pixel_buffer_get_io_surface_;
- bool initialized_successfully_;
-
- friend struct DefaultSingletonTraits<IOSurfaceSupportImpl>;
- DISALLOW_COPY_AND_ASSIGN(IOSurfaceSupportImpl);
-};
-
-IOSurfaceSupportImpl* IOSurfaceSupportImpl::GetInstance() {
- IOSurfaceSupportImpl* impl = Singleton<IOSurfaceSupportImpl>::get();
- if (impl->InitializedSuccessfully())
- return impl;
- return NULL;
-}
-
-CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceWidth() {
- return k_io_surface_width_;
-}
-
-CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceHeight() {
- return k_io_surface_height_;
-}
-
-CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceBytesPerElement() {
- return k_io_surface_bytes_per_element_;
-}
-
-CFStringRef IOSurfaceSupportImpl::GetKIOSurfacePixelFormat() {
- return k_io_surface_pixel_format_;
-}
-
-CFStringRef IOSurfaceSupportImpl::GetKIOSurfaceIsGlobal() {
- return k_io_surface_is_global_;
-}
-
-CFTypeRef IOSurfaceSupportImpl::IOSurfaceCreate(CFDictionaryRef properties) {
- return io_surface_create_(properties);
-}
-
-uint32 IOSurfaceSupportImpl::IOSurfaceGetID(
- CFTypeRef io_surface) {
- return io_surface_get_id_(io_surface);
-}
-
-CFTypeRef IOSurfaceSupportImpl::IOSurfaceLookup(uint32 io_surface_id) {
- return io_surface_lookup_(io_surface_id);
-}
-
-mach_port_t IOSurfaceSupportImpl::IOSurfaceCreateMachPort(
- CFTypeRef io_surface) {
- return io_surface_create_mach_port_(io_surface);
-}
-
-CFTypeRef IOSurfaceSupportImpl::IOSurfaceLookupFromMachPort(mach_port_t port) {
- return io_surface_lookup_from_mach_port_(port);
-}
-
-size_t IOSurfaceSupportImpl::IOSurfaceGetWidth(CFTypeRef io_surface) {
- return io_surface_get_width_(io_surface);
-}
-
-size_t IOSurfaceSupportImpl::IOSurfaceGetHeight(CFTypeRef io_surface) {
- return io_surface_get_height_(io_surface);
-}
-
-size_t IOSurfaceSupportImpl::IOSurfaceGetBytesPerRow(CFTypeRef io_surface) {
- return io_surface_get_bytes_per_row_(io_surface);
-}
-
-void* IOSurfaceSupportImpl::IOSurfaceGetBaseAddress(CFTypeRef io_surface) {
- return io_surface_get_base_address_(io_surface);
-}
-
-IOReturn IOSurfaceSupportImpl::IOSurfaceLock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) {
- return io_surface_lock_(io_surface, options, seed);
-}
-
-IOReturn IOSurfaceSupportImpl::IOSurfaceUnlock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) {
- return io_surface_unlock_(io_surface, options, seed);
-}
-
-CGLError IOSurfaceSupportImpl::CGLTexImageIOSurface2D(CGLContextObj ctx,
- GLenum target,
- GLenum internal_format,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- CFTypeRef io_surface,
- GLuint plane) {
- return cgl_tex_image_io_surface_2d_(ctx,
- target,
- internal_format,
- width,
- height,
- format,
- type,
- io_surface,
- plane);
-}
-
-CFTypeRef IOSurfaceSupportImpl::CVPixelBufferGetIOSurface(
- CVPixelBufferRef pixel_buffer) {
- return cv_pixel_buffer_get_io_surface_(pixel_buffer);
-}
-
-IOSurfaceSupportImpl::IOSurfaceSupportImpl()
- : iosurface_handle_(NULL),
- opengl_handle_(NULL),
- core_video_handle_(NULL),
- k_io_surface_width_(NULL),
- k_io_surface_height_(NULL),
- k_io_surface_bytes_per_element_(NULL),
- k_io_surface_pixel_format_(NULL),
- k_io_surface_is_global_(NULL),
- io_surface_create_(NULL),
- io_surface_get_id_(NULL),
- io_surface_lookup_(NULL),
- io_surface_create_mach_port_(NULL),
- io_surface_lookup_from_mach_port_(NULL),
- io_surface_get_width_(NULL),
- io_surface_get_height_(NULL),
- io_surface_get_bytes_per_row_(NULL),
- io_surface_get_base_address_(NULL),
- io_surface_lock_(NULL),
- io_surface_unlock_(NULL),
- cgl_tex_image_io_surface_2d_(NULL),
- cv_pixel_buffer_get_io_surface_(NULL),
- initialized_successfully_(false) {
- iosurface_handle_ = dlopen(
- "/System/Library/Frameworks/IOSurface.framework/IOSurface",
- RTLD_LAZY | RTLD_LOCAL);
- opengl_handle_ = dlopen(
- "/System/Library/Frameworks/OpenGL.framework/OpenGL",
- RTLD_LAZY | RTLD_LOCAL);
- core_video_handle_ = dlopen(
- "/System/Library/Frameworks/CoreVideo.framework/CoreVideo",
- RTLD_LAZY | RTLD_LOCAL);
- if (!iosurface_handle_ ||
- !opengl_handle_ ||
- !core_video_handle_) {
- CloseLibraryHandles();
- return;
- }
-
- void* surface_width_ptr = dlsym(iosurface_handle_, "kIOSurfaceWidth");
- void* surface_height_ptr = dlsym(iosurface_handle_, "kIOSurfaceHeight");
- void* surface_bytes_per_element_ptr =
- dlsym(iosurface_handle_, "kIOSurfaceBytesPerElement");
- void* surface_pixel_format_ptr =
- dlsym(iosurface_handle_, "kIOSurfacePixelFormat");
- void* surface_is_global_ptr =
- dlsym(iosurface_handle_, "kIOSurfaceIsGlobal");
- void* surface_create_ptr = dlsym(iosurface_handle_, "IOSurfaceCreate");
- void* surface_get_id_ptr = dlsym(iosurface_handle_, "IOSurfaceGetID");
- void* surface_lookup_ptr = dlsym(iosurface_handle_, "IOSurfaceLookup");
- void* surface_create_mach_port_ptr =
- dlsym(iosurface_handle_, "IOSurfaceCreateMachPort");
- void* surface_lookup_from_mach_port_ptr =
- dlsym(iosurface_handle_, "IOSurfaceLookupFromMachPort");
- void* io_surface_get_width_ptr =
- dlsym(iosurface_handle_, "IOSurfaceGetWidth");
- void* io_surface_get_height_ptr =
- dlsym(iosurface_handle_, "IOSurfaceGetHeight");
- void* io_surface_get_bytes_per_row_ptr =
- dlsym(iosurface_handle_, "IOSurfaceGetBytesPerRow");
- void* io_surface_get_base_address_ptr =
- dlsym(iosurface_handle_, "IOSurfaceGetBaseAddress");
- void* io_surface_lock_ptr = dlsym(iosurface_handle_, "IOSurfaceLock");
- void* io_surface_unlock_ptr = dlsym(iosurface_handle_, "IOSurfaceUnlock");
- void* tex_image_io_surface_2d_ptr =
- dlsym(opengl_handle_, "CGLTexImageIOSurface2D");
- void* cv_pixel_buffer_get_io_surface =
- dlsym(core_video_handle_, "CVPixelBufferGetIOSurface");
- if (!surface_width_ptr ||
- !surface_height_ptr ||
- !surface_bytes_per_element_ptr ||
- !surface_pixel_format_ptr ||
- !surface_is_global_ptr ||
- !surface_create_ptr ||
- !surface_get_id_ptr ||
- !surface_lookup_ptr ||
- !surface_create_mach_port_ptr ||
- !surface_lookup_from_mach_port_ptr ||
- !io_surface_get_width_ptr ||
- !io_surface_get_height_ptr ||
- !io_surface_get_bytes_per_row_ptr ||
- !io_surface_get_base_address_ptr ||
- !io_surface_lock_ptr ||
- !io_surface_unlock_ptr ||
- !tex_image_io_surface_2d_ptr ||
- !cv_pixel_buffer_get_io_surface) {
- CloseLibraryHandles();
- return;
- }
-
- k_io_surface_width_ = *static_cast<CFStringRef*>(surface_width_ptr);
- k_io_surface_height_ = *static_cast<CFStringRef*>(surface_height_ptr);
- k_io_surface_bytes_per_element_ =
- *static_cast<CFStringRef*>(surface_bytes_per_element_ptr);
- k_io_surface_pixel_format_ =
- *static_cast<CFStringRef*>(surface_pixel_format_ptr);
- k_io_surface_is_global_ = *static_cast<CFStringRef*>(surface_is_global_ptr);
- io_surface_create_ = reinterpret_cast<IOSurfaceCreateProcPtr>(
- surface_create_ptr);
- io_surface_get_id_ =
- reinterpret_cast<IOSurfaceGetIDProcPtr>(surface_get_id_ptr);
- io_surface_lookup_ =
- reinterpret_cast<IOSurfaceLookupProcPtr>(surface_lookup_ptr);
- io_surface_create_mach_port_ =
- reinterpret_cast<IOSurfaceCreateMachPortProcPtr>(
- surface_create_mach_port_ptr);
- io_surface_lookup_from_mach_port_ =
- reinterpret_cast<IOSurfaceLookupFromMachPortProcPtr>(
- surface_lookup_from_mach_port_ptr);
- io_surface_get_width_ =
- reinterpret_cast<IOSurfaceGetWidthPtr>(
- io_surface_get_width_ptr);
- io_surface_get_height_ =
- reinterpret_cast<IOSurfaceGetHeightPtr>(
- io_surface_get_height_ptr);
- io_surface_get_bytes_per_row_ =
- reinterpret_cast<IOSurfaceGetBytesPerRowPtr>(
- io_surface_get_bytes_per_row_ptr);
- io_surface_get_base_address_ =
- reinterpret_cast<IOSurfaceGetBaseAddressPtr>(
- io_surface_get_base_address_ptr);
- io_surface_lock_ = reinterpret_cast<IOSurfaceLockPtr>(io_surface_lock_ptr);
- io_surface_unlock_ = reinterpret_cast<IOSurfaceUnlockPtr>(
- io_surface_unlock_ptr);
- cgl_tex_image_io_surface_2d_ =
- reinterpret_cast<CGLTexImageIOSurface2DProcPtr>(
- tex_image_io_surface_2d_ptr);
- cv_pixel_buffer_get_io_surface_ =
- reinterpret_cast<CVPixelBufferGetIOSurfaceProcPtr>(
- cv_pixel_buffer_get_io_surface);
- initialized_successfully_ = true;
-}
-
-IOSurfaceSupportImpl::~IOSurfaceSupportImpl() {
- CloseLibraryHandles();
-}
-
-void IOSurfaceSupportImpl::CloseLibraryHandles() {
- if (iosurface_handle_) {
- dlclose(iosurface_handle_);
- iosurface_handle_ = NULL;
- }
- if (opengl_handle_) {
- dlclose(opengl_handle_);
- opengl_handle_ = NULL;
- }
- if (core_video_handle_) {
- dlclose(core_video_handle_);
- core_video_handle_ = NULL;
- }
-}
-
-IOSurfaceSupport* IOSurfaceSupport::Initialize() {
- return IOSurfaceSupportImpl::GetInstance();
-}
-
-IOSurfaceSupport::IOSurfaceSupport() {
-}
-
-IOSurfaceSupport::~IOSurfaceSupport() {
-}
-
diff --git a/chromium/ui/gl/io_surface_support_mac.h b/chromium/ui/gl/io_surface_support_mac.h
deleted file mode 100644
index d8699c833a7..00000000000
--- a/chromium/ui/gl/io_surface_support_mac.h
+++ /dev/null
@@ -1,83 +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_GL_IO_SURFACE_SUPPORT_MAC_H_
-#define UI_GL_IO_SURFACE_SUPPORT_MAC_H_
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreVideo/CoreVideo.h>
-#include <mach/mach.h>
-#include <OpenGL/OpenGL.h>
-
-#include "base/basictypes.h"
-#include "ui/gl/gl_export.h"
-
-// This Mac OS X-specific class provides dynamically-linked access to
-// IOSurface.framework, which is only available on 10.6 and later.
-// Since Chromium is built on 10.5 we must dynamically look up all of
-// the entry points we need in this framework.
-
-// See IOSurface/IOSurfaceAPI.h and OpenGL/CGLIOSurface.h on 10.6 for
-// documentation of the fields and methods of this class.
-
-class GL_EXPORT IOSurfaceSupport {
- public:
- // Returns an instance of the IOSurfaceSupport class if the
- // operating system supports it, NULL otherwise. It is safe to call
- // this multiple times.
- static IOSurfaceSupport* Initialize();
-
- virtual CFStringRef GetKIOSurfaceWidth() = 0;
- virtual CFStringRef GetKIOSurfaceHeight() = 0;
- virtual CFStringRef GetKIOSurfaceBytesPerElement() = 0;
- virtual CFStringRef GetKIOSurfacePixelFormat() = 0;
- virtual CFStringRef GetKIOSurfaceIsGlobal() = 0;
-
- virtual CFTypeRef IOSurfaceCreate(CFDictionaryRef properties) = 0;
-
- // The following two APIs assume the IOSurface was created with the
- // kIOSurfaceIsGlobal key set to true
- virtual uint32 IOSurfaceGetID(CFTypeRef io_surface) = 0;
- virtual CFTypeRef IOSurfaceLookup(uint32 io_surface_id) = 0;
-
- // The following two APIs are more robust and secure, but
- // unfortunately it looks like it will be a lot of work to correctly
- // transmit a mach port from process to process (possibly requiring
- // a side channel for or extension of the Chrome IPC mechanism)
- virtual mach_port_t IOSurfaceCreateMachPort(CFTypeRef io_surface) = 0;
- virtual CFTypeRef IOSurfaceLookupFromMachPort(mach_port_t port) = 0;
-
- virtual size_t IOSurfaceGetWidth(CFTypeRef io_surface) = 0;
- virtual size_t IOSurfaceGetHeight(CFTypeRef io_surface) = 0;
- virtual size_t IOSurfaceGetBytesPerRow(CFTypeRef io_surface) = 0;
- virtual void* IOSurfaceGetBaseAddress(CFTypeRef io_surface) = 0;
-
- virtual IOReturn IOSurfaceLock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) = 0;
- virtual IOReturn IOSurfaceUnlock(CFTypeRef io_surface,
- uint32 options,
- uint32* seed) = 0;
-
- virtual CGLError CGLTexImageIOSurface2D(CGLContextObj ctx,
- GLenum target,
- GLenum internal_format,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type,
- CFTypeRef io_surface,
- GLuint plane) = 0;
-
- virtual CFTypeRef CVPixelBufferGetIOSurface(
- CVPixelBufferRef pixel_buffer) = 0;
-
- protected:
- IOSurfaceSupport();
- virtual ~IOSurfaceSupport();
-
- DISALLOW_COPY_AND_ASSIGN(IOSurfaceSupport);
-};
-
-#endif // UI_GL_IO_SURFACE_SUPPORT_MAC_H_
diff --git a/chromium/ui/gl/scoped_binders.cc b/chromium/ui/gl/scoped_binders.cc
index eef92c10733..bb2b2901056 100644
--- a/chromium/ui/gl/scoped_binders.cc
+++ b/chromium/ui/gl/scoped_binders.cc
@@ -59,7 +59,7 @@ ScopedTextureBinder::~ScopedTextureBinder() {
if (state_restorer_) {
DCHECK(!!GLContext::GetCurrent());
DCHECK_EQ(state_restorer_, GLContext::GetCurrent()->GetGLStateRestorer());
- state_restorer_->RestoreAllTextureUnitBindings();
+ state_restorer_->RestoreActiveTextureUnitBinding(target_);
} else {
glBindTexture(target_, old_id_);
}
diff --git a/chromium/ui/gl/scoped_cgl.cc b/chromium/ui/gl/scoped_cgl.cc
new file mode 100644
index 00000000000..18eb9808de1
--- /dev/null
+++ b/chromium/ui/gl/scoped_cgl.cc
@@ -0,0 +1,27 @@
+// 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 "base/logging.h"
+#include "ui/gl/scoped_cgl.h"
+
+namespace gfx {
+
+ScopedCGLSetCurrentContext::ScopedCGLSetCurrentContext(CGLContextObj context) {
+ CGLContextObj previous_context = CGLGetCurrentContext();
+ // It is possible for the previous context to have a zero reference count,
+ // because making a context current does not increment the reference count.
+ // In that case, do not restore the previous context.
+ if (previous_context && CGLGetContextRetainCount(previous_context)) {
+ previous_context_.reset(previous_context, base::scoped_policy::RETAIN);
+ }
+ CGLError error = CGLSetCurrentContext(context);
+ DCHECK_EQ(error, kCGLNoError) << "CGLSetCurrentContext should never fail";
+}
+
+ScopedCGLSetCurrentContext::~ScopedCGLSetCurrentContext() {
+ CGLError error = CGLSetCurrentContext(previous_context_);
+ DCHECK_EQ(error, kCGLNoError) << "CGLSetCurrentContext should never fail";
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gl/scoped_cgl.h b/chromium/ui/gl/scoped_cgl.h
new file mode 100644
index 00000000000..81e1e6ea360
--- /dev/null
+++ b/chromium/ui/gl/scoped_cgl.h
@@ -0,0 +1,56 @@
+// 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_GL_SCOPED_CGL_H_
+#define UI_GL_SCOPED_CGL_H_
+
+#include <OpenGL/OpenGL.h>
+
+#include "base/mac/scoped_typeref.h"
+#include "ui/gl/gl_export.h"
+
+namespace base {
+
+template<>
+struct ScopedTypeRefTraits<CGLContextObj> {
+ static void Retain(CGLContextObj object) {
+ CGLRetainContext(object);
+ }
+ static void Release(CGLContextObj object) {
+ CGLReleaseContext(object);
+ }
+};
+
+template<>
+struct ScopedTypeRefTraits<CGLPixelFormatObj> {
+ static void Retain(CGLPixelFormatObj object) {
+ CGLRetainPixelFormat(object);
+ }
+ static void Release(CGLPixelFormatObj object) {
+ CGLReleasePixelFormat(object);
+ }
+};
+
+} // namespace base
+
+namespace gfx {
+
+class GL_EXPORT ScopedCGLSetCurrentContext {
+ public:
+ explicit ScopedCGLSetCurrentContext(CGLContextObj context);
+ ~ScopedCGLSetCurrentContext();
+ private:
+ // Note that if a context is destroyed when it is current, then the current
+ // context is changed to NULL. Take out a reference on |previous_context_| to
+ // preserve this behavior (when this falls out of scope, |previous_context_|
+ // will be made current, then released, so NULL will be current if that
+ // release destroys the context).
+ base::ScopedTypeRef<CGLContextObj> previous_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCGLSetCurrentContext);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_SCOPED_CGL_H_
diff --git a/chromium/ui/gl/sync_control_vsync_provider.cc b/chromium/ui/gl/sync_control_vsync_provider.cc
index 89b194f8b6e..66d3734f58e 100644
--- a/chromium/ui/gl/sync_control_vsync_provider.cc
+++ b/chromium/ui/gl/sync_control_vsync_provider.cc
@@ -24,7 +24,7 @@ const double kRelativeIntervalDifferenceThreshold = 0.05;
namespace gfx {
SyncControlVSyncProvider::SyncControlVSyncProvider()
- : VSyncProvider(), last_media_stream_counter_(0) {
+ : VSyncProvider(), last_media_stream_counter_(0), invalid_msc_(false) {
// On platforms where we can't get an accurate reading on the refresh
// rate we fall back to the assumption that we're displaying 60 frames
// per second.
@@ -54,9 +54,11 @@ void SyncControlVSyncProvider::GetVSyncParameters(
// Both Intel and Mali drivers will return TRUE for GetSyncValues
// but a value of 0 for MSC if they cannot access the CRTC data structure
// associated with the surface. crbug.com/231945
- if (media_stream_counter == 0) {
- LOG(ERROR) << "glXGetSyncValuesOML should not return TRUE with a "
- << "media stream counter of 0.";
+ bool prev_invalid_msc = invalid_msc_;
+ invalid_msc_ = (media_stream_counter == 0);
+ if (invalid_msc_) {
+ LOG_IF(ERROR, !prev_invalid_msc) << "glXGetSyncValuesOML "
+ "should not return TRUE with a media stream counter of 0.";
return;
}
@@ -123,16 +125,23 @@ void SyncControlVSyncProvider::GetVSyncParameters(
if (relative_change < kRelativeIntervalDifferenceThreshold) {
if (new_interval.InMicroseconds() < kMinVsyncIntervalUs ||
new_interval.InMicroseconds() > kMaxVsyncIntervalUs) {
- LOG(FATAL) << "Calculated bogus refresh interval of "
- << new_interval.InMicroseconds() << " us. "
- << "Last time base of " << last_timebase_.ToInternalValue()
- << " us. "
- << "Current time base of " << timebase.ToInternalValue()
- << " us. "
- << "Last media stream count of "
- << last_media_stream_counter_ << ". "
- << "Current media stream count of " << media_stream_counter
- << ".";
+#if defined(USE_ASH)
+ // On ash platforms (ChromeOS essentially), the real refresh interval is
+ // queried from XRandR, regardless of the value calculated here, and
+ // this value is overriden by ui::CompositorVSyncManager. The log
+ // should not be fatal in this case. Reconsider all this when XRandR
+ // support is added to non-ash platforms.
+ // http://crbug.com/340851
+ LOG(ERROR)
+#else
+ LOG(FATAL)
+#endif // USE_ASH
+ << "Calculated bogus refresh interval="
+ << new_interval.InMicroseconds()
+ << " us., last_timebase_=" << last_timebase_.ToInternalValue()
+ << " us., timebase=" << timebase.ToInternalValue()
+ << " us., last_media_stream_counter_=" << last_media_stream_counter_
+ << ", media_stream_counter=" << media_stream_counter;
} else {
last_good_interval_ = new_interval;
}
diff --git a/chromium/ui/gl/sync_control_vsync_provider.h b/chromium/ui/gl/sync_control_vsync_provider.h
index 1eb7bb9861b..edee2b080e6 100644
--- a/chromium/ui/gl/sync_control_vsync_provider.h
+++ b/chromium/ui/gl/sync_control_vsync_provider.h
@@ -31,6 +31,7 @@ class SyncControlVSyncProvider : public VSyncProvider {
base::TimeTicks last_timebase_;
uint64 last_media_stream_counter_;
base::TimeDelta last_good_interval_;
+ bool invalid_msc_;
// A short history of the last few computed intervals.
// We use this to filter out the noise in the computation resulting
diff --git a/chromium/ui/keyboard/DEPS b/chromium/ui/keyboard/DEPS
index 69c820c1776..d8ce9fb4ce2 100644
--- a/chromium/ui/keyboard/DEPS
+++ b/chromium/ui/keyboard/DEPS
@@ -5,6 +5,9 @@ include_rules = [
"+ui/aura",
"+ui/base",
"+ui/compositor",
+ "+ui/events",
"+ui/gfx",
+ "+ui/gl/gl_surface.h", # To initialize GL for tests.
"+ui/test",
+ "+ui/wm",
]
diff --git a/chromium/ui/keyboard/keyboard.cc b/chromium/ui/keyboard/keyboard.cc
index 7825c7931cf..436b93595f9 100644
--- a/chromium/ui/keyboard/keyboard.cc
+++ b/chromium/ui/keyboard/keyboard.cc
@@ -5,68 +5,18 @@
#include "ui/keyboard/keyboard.h"
#include "base/files/file_path.h"
-#include "base/memory/singleton.h"
#include "base/path_service.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/web_ui_controller_factory.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/keyboard/keyboard_constants.h"
-#include "ui/keyboard/keyboard_ui_controller.h"
-#include "url/gurl.h"
-namespace {
-
-using content::BrowserContext;
-using content::WebUI;
-using content::WebUIController;
-
-class KeyboardWebUIControllerFactory : public content::WebUIControllerFactory {
- public:
- // |WebUIControllerFactory| implementation:
- virtual content::WebUI::TypeID GetWebUIType(
- content::BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
- if (url == GURL(keyboard::kKeyboardWebUIURL))
- return const_cast<KeyboardWebUIControllerFactory*>(this);
-
- return WebUI::kNoWebUI;
- }
- virtual bool UseWebUIForURL(content::BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
- return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
- }
- virtual bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
- return UseWebUIForURL(browser_context, url);
- }
- virtual content::WebUIController* CreateWebUIControllerForURL(
- content::WebUI* web_ui,
- const GURL& url) const OVERRIDE {
- if (url == GURL(keyboard::kKeyboardWebUIURL))
- return new keyboard::KeyboardUIController(web_ui);
- return NULL;
- }
-
- static KeyboardWebUIControllerFactory* GetInstance() {
- return Singleton<KeyboardWebUIControllerFactory>::get();
- }
-
- protected:
- KeyboardWebUIControllerFactory() {}
- virtual ~KeyboardWebUIControllerFactory() {}
-
- private:
- friend struct DefaultSingletonTraits<KeyboardWebUIControllerFactory>;
-
- DISALLOW_COPY_AND_ASSIGN(KeyboardWebUIControllerFactory);
-};
+namespace keyboard {
-} // namespace
+static bool initialized = false;
-namespace keyboard {
+void ResetKeyboardForTesting() {
+ initialized = false;
+}
void InitializeKeyboard() {
- static bool initialized = false;
if (initialized)
return;
initialized = true;
@@ -77,9 +27,6 @@ void InitializeKeyboard() {
FILE_PATH_LITERAL("keyboard_resources.pak"));
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
pak_file, ui::SCALE_FACTOR_100P);
-
- content::WebUIControllerFactory::RegisterFactory(
- KeyboardWebUIControllerFactory::GetInstance());
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard.gyp b/chromium/ui/keyboard/keyboard.gyp
index 4ea3b09808b..e780048b3ec 100644
--- a/chromium/ui/keyboard/keyboard.gyp
+++ b/chromium/ui/keyboard/keyboard.gyp
@@ -43,10 +43,12 @@
'../../skia/skia.gyp:skia',
'../../url/url.gyp:url_lib',
'../aura/aura.gyp:aura',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../events/events.gyp:events',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../wm/wm.gyp:wm',
'keyboard_resources',
],
'defines': [
@@ -62,13 +64,11 @@
'keyboard_controller_observer.h',
'keyboard_controller_proxy.cc',
'keyboard_controller_proxy.h',
+ 'keyboard_layout_manager.h',
+ 'keyboard_layout_manager.cc',
'keyboard_export.h',
'keyboard_switches.cc',
'keyboard_switches.h',
- 'keyboard_ui_controller.cc',
- 'keyboard_ui_controller.h',
- 'keyboard_ui_handler.cc',
- 'keyboard_ui_handler.h',
'keyboard_util.cc',
'keyboard_util.h',
]
@@ -85,17 +85,21 @@
'../../url/url.gyp:url_lib',
'../aura/aura.gyp:aura',
'../aura/aura.gyp:aura_test_support',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
+ '../compositor/compositor.gyp:compositor_test_support',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:run_ui_unittests',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../resources/ui_resources.gyp:ui_test_pak',
+ '../wm/wm.gyp:wm',
'keyboard',
],
'sources': [
+ 'test/run_all_unittests.cc',
'keyboard_controller_unittest.cc',
],
'conditions': [
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
],
diff --git a/chromium/ui/keyboard/keyboard.h b/chromium/ui/keyboard/keyboard.h
index ce14a0b98b0..a0aed8aee09 100644
--- a/chromium/ui/keyboard/keyboard.h
+++ b/chromium/ui/keyboard/keyboard.h
@@ -10,11 +10,15 @@
namespace keyboard {
// Initializes the keyboard module. This includes adding the necessary pak files
-// for loading resources used in for the virtual keyboard, and registers
-// a WebUIControllerFactory for creating a WebUIController necessary for the
-// virtual keyboard. This becomes a no-op after the first call.
+// for loading resources used in for the virtual keyboard. This becomes a no-op
+// after the first call.
KEYBOARD_EXPORT void InitializeKeyboard();
+// Resets the keyboard to an uninitialized state. Required for
+// BrowserWithTestWindowTest tests as they tear down the controller factory
+// after each test yet resume testing in the same process.
+KEYBOARD_EXPORT void ResetKeyboardForTesting();
+
} // namespace keyboard
#endif // UI_KEYBOARD_KEYBOARD_H_
diff --git a/chromium/ui/keyboard/keyboard_constants.cc b/chromium/ui/keyboard/keyboard_constants.cc
index 35f81300633..b13a604f3d1 100644
--- a/chromium/ui/keyboard/keyboard_constants.cc
+++ b/chromium/ui/keyboard/keyboard_constants.cc
@@ -6,7 +6,7 @@
namespace keyboard {
-const char kKeyboardWebUIURL[] = "chrome://keyboard";
-const char kKeyboardWebUIHost[] = "keyboard";
+const char kKeyboardURL[] = "chrome://keyboard";
+const char kKeyboardHost[] = "keyboard";
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_constants.h b/chromium/ui/keyboard/keyboard_constants.h
index eff96eadf50..75607c1ee63 100644
--- a/chromium/ui/keyboard/keyboard_constants.h
+++ b/chromium/ui/keyboard/keyboard_constants.h
@@ -9,11 +9,11 @@
namespace keyboard {
-// The URL of the keyboard WebUI.
-KEYBOARD_EXPORT extern const char kKeyboardWebUIURL[];
+// The URL of the keyboard extension.
+KEYBOARD_EXPORT extern const char kKeyboardURL[];
-// The host of the keyboard WebUI URL.
-KEYBOARD_EXPORT extern const char kKeyboardWebUIHost[];
+// The host of the keyboard extension URL.
+KEYBOARD_EXPORT extern const char kKeyboardHost[];
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc
index ca8e54fcc4a..1685451d32f 100644
--- a/chromium/ui/keyboard/keyboard_controller.cc
+++ b/chromium/ui/keyboard/keyboard_controller.cc
@@ -6,35 +6,70 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "ui/aura/layout_manager.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/browser/render_widget_host_view.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
-#include "ui/base/ime/text_input_type.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/keyboard/keyboard_controller_proxy.h"
+#include "ui/keyboard/keyboard_layout_manager.h"
#include "ui/keyboard/keyboard_switches.h"
#include "ui/keyboard/keyboard_util.h"
+#include "ui/wm/core/masked_window_targeter.h"
+
+#if defined(OS_CHROMEOS)
+#include "base/process/launch.h"
+#include "base/sys_info.h"
+#endif
namespace {
const int kHideKeyboardDelayMs = 100;
-gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds) {
- const float kKeyboardHeightRatio =
- keyboard::IsKeyboardUsabilityExperimentEnabled() ? 1.0f : 0.3f;
- return gfx::Rect(
- window_bounds.x(),
- window_bounds.y() + window_bounds.height() * (1 - kKeyboardHeightRatio),
- window_bounds.width(),
- window_bounds.height() * kKeyboardHeightRatio);
-}
+// The virtual keyboard show/hide animation duration.
+const int kAnimationDurationMs = 200;
+
+// The opacity of virtual keyboard container when show animation starts or
+// hide animation finishes.
+const float kAnimationStartOrAfterHideOpacity = 0.2f;
+
+// Event targeter for the keyboard container.
+class KeyboardContainerTargeter : public wm::MaskedWindowTargeter {
+ public:
+ KeyboardContainerTargeter(aura::Window* container,
+ keyboard::KeyboardControllerProxy* proxy)
+ : wm::MaskedWindowTargeter(container),
+ proxy_(proxy) {
+ }
+
+ virtual ~KeyboardContainerTargeter() {}
+
+ private:
+ // wm::MaskedWindowTargeter:
+ virtual bool GetHitTestMask(aura::Window* window,
+ gfx::Path* mask) const OVERRIDE {
+ if (proxy_ && !proxy_->HasKeyboardWindow())
+ return true;
+ gfx::Rect keyboard_bounds = proxy_ ? proxy_->GetKeyboardWindow()->bounds() :
+ keyboard::DefaultKeyboardBoundsFromWindowBounds(window->bounds());
+ mask->addRect(RectToSkRect(keyboard_bounds));
+ return true;
+ }
+
+ keyboard::KeyboardControllerProxy* proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardContainerTargeter);
+};
// The KeyboardWindowDelegate makes sure the keyboard-window does not get focus.
// This is necessary to make sure that the synthetic key-events reach the target
@@ -69,17 +104,19 @@ class KeyboardWindowDelegate : public aura::WindowDelegate {
virtual void OnCaptureLost() OVERRIDE {}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {}
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
- virtual void OnWindowDestroying() OVERRIDE {}
- virtual void OnWindowDestroyed() OVERRIDE { delete this; }
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { delete this; }
virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
- virtual bool HasHitTestMask() const OVERRIDE { return true; }
+ virtual bool HasHitTestMask() const OVERRIDE {
+ return !proxy_ || proxy_->HasKeyboardWindow();
+ }
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {
+ if (proxy_ && !proxy_->HasKeyboardWindow())
+ return;
gfx::Rect keyboard_bounds = proxy_ ? proxy_->GetKeyboardWindow()->bounds() :
- KeyboardBoundsFromWindowBounds(bounds_);
+ keyboard::DefaultKeyboardBoundsFromWindowBounds(bounds_);
mask->addRect(RectToSkRect(keyboard_bounds));
}
- virtual void DidRecreateLayer(ui::Layer* old_layer,
- ui::Layer* new_layer) OVERRIDE {}
gfx::Rect bounds_;
keyboard::KeyboardControllerProxy* proxy_;
@@ -87,63 +124,80 @@ class KeyboardWindowDelegate : public aura::WindowDelegate {
DISALLOW_COPY_AND_ASSIGN(KeyboardWindowDelegate);
};
+void ToggleTouchEventLogging(bool enable) {
+#if defined(OS_CHROMEOS)
+ if (!base::SysInfo::IsRunningOnChromeOS())
+ return;
+ CommandLine command(
+ base::FilePath("/opt/google/touchscreen/toggle_touch_event_logging"));
+ if (enable)
+ command.AppendArg("1");
+ else
+ command.AppendArg("0");
+ VLOG(1) << "Running " << command.GetCommandLineString();
+ base::LaunchOptions options;
+ options.wait = true;
+ base::LaunchProcess(command, options, NULL);
+#endif
+}
+
} // namespace
namespace keyboard {
-// LayoutManager for the virtual keyboard container. Manages a single window
-// (the virtual keyboard) and keeps it positioned at the bottom of the
-// owner window.
-class KeyboardLayoutManager : public aura::LayoutManager {
+// Observer for both keyboard show and hide animations. It should be owned by
+// KeyboardController.
+class CallbackAnimationObserver : public ui::LayerAnimationObserver {
public:
- explicit KeyboardLayoutManager(KeyboardController* controller)
- : controller_(controller), keyboard_(NULL) {
- }
-
- // Overridden from aura::LayoutManager
- virtual void OnWindowResized() OVERRIDE {
- if (keyboard_ && !controller_->proxy()->resizing_from_contents())
- ResizeKeyboardToDefault(keyboard_);
- }
- virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
- DCHECK(!keyboard_);
- keyboard_ = child;
- ResizeKeyboardToDefault(keyboard_);
- }
- virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
- virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
- virtual void OnChildWindowVisibilityChanged(aura::Window* child,
- bool visible) OVERRIDE {}
- virtual void SetChildBounds(aura::Window* child,
- const gfx::Rect& requested_bounds) OVERRIDE {
- // SetChildBounds can be invoked by resizing from the container or by
- // resizing from the contents (through window.resizeTo call in JS).
- // The flag resizing_from_contents() is used to determine the keyboard is
- // resizing from which.
- if (controller_->proxy()->resizing_from_contents()) {
- controller_->NotifyKeyboardBoundsChanging(requested_bounds);
- SetChildBoundsDirect(child, requested_bounds);
- }
- }
+ CallbackAnimationObserver(ui::LayerAnimator* animator,
+ base::Callback<void(void)> callback);
+ virtual ~CallbackAnimationObserver();
private:
- void ResizeKeyboardToDefault(aura::Window* child) {
- gfx::Rect keyboard_bounds = KeyboardBoundsFromWindowBounds(
- controller_->GetContainerWindow()->bounds());
- SetChildBoundsDirect(child, keyboard_bounds);
- }
+ // Overridden from ui::LayerAnimationObserver:
+ virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq) OVERRIDE;
+ virtual void OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* seq) OVERRIDE;
+ virtual void OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* seq) OVERRIDE {}
- KeyboardController* controller_;
- aura::Window* keyboard_;
+ ui::LayerAnimator* animator_;
+ base::Callback<void(void)> callback_;
- DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
+ DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
};
+CallbackAnimationObserver::CallbackAnimationObserver(
+ ui::LayerAnimator* animator, base::Callback<void(void)> callback)
+ : animator_(animator), callback_(callback) {
+}
+
+CallbackAnimationObserver::~CallbackAnimationObserver() {
+ animator_->RemoveObserver(this);
+}
+
+void CallbackAnimationObserver::OnLayerAnimationEnded(
+ ui::LayerAnimationSequence* seq) {
+ if (animator_->is_animating())
+ return;
+ animator_->RemoveObserver(this);
+ callback_.Run();
+}
+
+void CallbackAnimationObserver::OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* seq) {
+ animator_->RemoveObserver(this);
+}
+
+// static
+KeyboardController* KeyboardController::instance_ = NULL;
+
KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
: proxy_(proxy),
input_method_(NULL),
keyboard_visible_(false),
lock_keyboard_(false),
+ type_(ui::TEXT_INPUT_TYPE_NONE),
weak_factory_(this) {
CHECK(proxy);
input_method_ = proxy_->GetInputMethod();
@@ -151,24 +205,34 @@ KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
}
KeyboardController::~KeyboardController() {
- if (container_) {
+ if (container_)
container_->RemoveObserver(this);
- // Remove the keyboard window from the children because the keyboard window
- // is owned by proxy and it should be destroyed by proxy.
- if (container_->Contains(proxy_->GetKeyboardWindow()))
- container_->RemoveChild(proxy_->GetKeyboardWindow());
- }
if (input_method_)
input_method_->RemoveObserver(this);
+ ResetWindowInsets();
+}
+
+// static
+void KeyboardController::ResetInstance(KeyboardController* controller) {
+ if (instance_ && instance_ != controller)
+ delete instance_;
+ instance_ = controller;
+}
+
+// static
+KeyboardController* KeyboardController::GetInstance() {
+ return instance_;
}
aura::Window* KeyboardController::GetContainerWindow() {
if (!container_.get()) {
container_.reset(new aura::Window(
new KeyboardWindowDelegate(proxy_.get())));
+ container_->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
+ new KeyboardContainerTargeter(container_.get(), proxy_.get())));
container_->SetName("KeyboardContainer");
container_->set_owned_by_parent(false);
- container_->Init(ui::LAYER_NOT_DRAWN);
+ container_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
container_->AddObserver(this);
container_->SetLayoutManager(new KeyboardLayoutManager(this));
}
@@ -177,15 +241,50 @@ aura::Window* KeyboardController::GetContainerWindow() {
void KeyboardController::NotifyKeyboardBoundsChanging(
const gfx::Rect& new_bounds) {
- if (proxy_->GetKeyboardWindow()->IsVisible()) {
+ current_keyboard_bounds_ = new_bounds;
+ if (proxy_->HasKeyboardWindow() && proxy_->GetKeyboardWindow()->IsVisible()) {
FOR_EACH_OBSERVER(KeyboardControllerObserver,
observer_list_,
OnKeyboardBoundsChanging(new_bounds));
+ if (keyboard::IsKeyboardOverscrollEnabled()) {
+ // Adjust the height of the viewport for visible windows on the primary
+ // display.
+ // TODO(kevers): Add EnvObserver to properly initialize insets if a
+ // window is created while the keyboard is visible.
+ scoped_ptr<content::RenderWidgetHostIterator> widgets(
+ content::RenderWidgetHost::GetRenderWidgetHosts());
+ aura::Window *keyboard_window = proxy_->GetKeyboardWindow();
+ aura::Window *root_window = keyboard_window->GetRootWindow();
+ while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
+ content::RenderWidgetHostView* view = widget->GetView();
+ // Can be NULL, e.g. if the RenderWidget is being destroyed or
+ // the render process crashed.
+ if (view) {
+ aura::Window *window = view->GetNativeView();
+ if (window != keyboard_window &&
+ window->GetRootWindow() == root_window) {
+ gfx::Rect window_bounds = window->GetBoundsInScreen();
+ gfx::Rect intersect = gfx::IntersectRects(window_bounds,
+ new_bounds);
+ int overlap = intersect.height();
+ if (overlap > 0 && overlap < window_bounds.height())
+ view->SetInsets(gfx::Insets(0, 0, overlap, 0));
+ else
+ view->SetInsets(gfx::Insets(0, 0, 0, 0));
+ // TODO(kevers): Add window observer to native window to update
+ // insets on a window move or resize.
+ }
+ }
+ }
+ } else {
+ ResetWindowInsets();
+ }
}
}
void KeyboardController::HideKeyboard(HideReason reason) {
keyboard_visible_ = false;
+ ToggleTouchEventLogging(true);
keyboard::LogKeyboardControlEvent(
reason == HIDE_REASON_AUTOMATIC ?
@@ -194,7 +293,23 @@ void KeyboardController::HideKeyboard(HideReason reason) {
NotifyKeyboardBoundsChanging(gfx::Rect());
- proxy_->HideKeyboardContainer(container_.get());
+ set_lock_keyboard(false);
+
+ ui::LayerAnimator* container_animator = container_->layer()->GetAnimator();
+ animation_observer_.reset(new CallbackAnimationObserver(
+ container_animator,
+ base::Bind(&KeyboardController::HideAnimationFinished,
+ base::Unretained(this))));
+ container_animator->AddObserver(animation_observer_.get());
+
+ ui::ScopedLayerAnimationSettings settings(container_animator);
+ settings.SetTweenType(gfx::Tween::EASE_OUT);
+ settings.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
+ gfx::Transform transform;
+ transform.Translate(0, proxy_->GetKeyboardWindow()->bounds().height());
+ container_->SetTransform(transform);
+ container_->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
}
void KeyboardController::AddObserver(KeyboardControllerObserver* observer) {
@@ -205,14 +320,20 @@ void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
observer_list_.RemoveObserver(observer);
}
+void KeyboardController::ShowKeyboard(bool lock) {
+ set_lock_keyboard(lock);
+ ShowKeyboardInternal();
+}
+
void KeyboardController::OnWindowHierarchyChanged(
const HierarchyChangeParams& params) {
if (params.new_parent && params.target == container_.get())
OnTextInputStateChanged(proxy_->GetInputMethod()->GetTextInputClient());
}
-void KeyboardController::SetOverrideContentUrl(const GURL& url) {
- proxy_->SetOverrideContentUrl(url);
+void KeyboardController::Reload() {
+ if (proxy_->HasKeyboardWindow())
+ proxy_->ReloadKeyboardIfNeeded();
}
void KeyboardController::OnTextInputStateChanged(
@@ -220,44 +341,15 @@ void KeyboardController::OnTextInputStateChanged(
if (!container_.get())
return;
- bool was_showing = keyboard_visible_;
- bool should_show = was_showing;
- ui::TextInputType type =
- client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
- if (type == ui::TEXT_INPUT_TYPE_NONE &&
- !IsKeyboardUsabilityExperimentEnabled() &&
- !lock_keyboard_) {
- should_show = false;
- } else {
- if (container_->children().empty()) {
- keyboard::MarkKeyboardLoadStarted();
- aura::Window* keyboard = proxy_->GetKeyboardWindow();
- keyboard->Show();
- container_->AddChild(keyboard);
- }
- if (type != ui::TEXT_INPUT_TYPE_NONE)
- proxy_->SetUpdateInputType(type);
- container_->parent()->StackChildAtTop(container_.get());
- should_show = true;
+ if (IsKeyboardUsabilityExperimentEnabled()) {
+ ShowKeyboardInternal();
+ return;
}
- if (was_showing != should_show) {
- if (should_show) {
- keyboard_visible_ = true;
-
- // If the controller is in the process of hiding the keyboard, do not log
- // the stat here since the keyboard will not actually be shown.
- if (!WillHideKeyboard())
- keyboard::LogKeyboardControlEvent(keyboard::KEYBOARD_CONTROL_SHOW);
-
- weak_factory_.InvalidateWeakPtrs();
- if (container_->IsVisible())
- return;
-
- NotifyKeyboardBoundsChanging(container_->children()[0]->bounds());
+ type_ = client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
- proxy_->ShowKeyboardContainer(container_.get());
- } else {
+ if (type_ == ui::TEXT_INPUT_TYPE_NONE && !lock_keyboard_) {
+ if (keyboard_visible_) {
// Set the visibility state here so that any queries for visibility
// before the timer fires returns the correct future value.
keyboard_visible_ = false;
@@ -267,10 +359,19 @@ void KeyboardController::OnTextInputStateChanged(
weak_factory_.GetWeakPtr(), HIDE_REASON_AUTOMATIC),
base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs));
}
+ } else {
+ // Abort a pending keyboard hide.
+ if (WillHideKeyboard()) {
+ weak_factory_.InvalidateWeakPtrs();
+ keyboard_visible_ = true;
+ }
+ proxy_->SetUpdateInputType(type_);
+ // Do not explicitly show the Virtual keyboard unless it is in the process
+ // of hiding. Instead, the virtual keyboard is shown in response to a user
+ // gesture (mouse or touch) that is received while an element has input
+ // focus. Showing the keyboard requires an explicit call to
+ // OnShowImeIfNeeded.
}
- // TODO(bryeung): whenever the TextInputClient changes we need to notify the
- // keyboard (with the TextInputType) so that it can reset it's state (e.g.
- // abandon compositions in progress)
}
void KeyboardController::OnInputMethodDestroyed(
@@ -279,8 +380,104 @@ void KeyboardController::OnInputMethodDestroyed(
input_method_ = NULL;
}
+void KeyboardController::OnShowImeIfNeeded() {
+ ShowKeyboardInternal();
+}
+
+void KeyboardController::ShowKeyboardInternal() {
+ if (!container_.get())
+ return;
+
+ if (container_->children().empty()) {
+ keyboard::MarkKeyboardLoadStarted();
+ aura::Window* keyboard = proxy_->GetKeyboardWindow();
+ keyboard->Show();
+ container_->AddChild(keyboard);
+ keyboard->set_owned_by_parent(false);
+ }
+
+ proxy_->ReloadKeyboardIfNeeded();
+
+ if (keyboard_visible_ || proxy_->GetKeyboardWindow()->bounds().height() == 0)
+ return;
+
+ keyboard_visible_ = true;
+
+ // If the controller is in the process of hiding the keyboard, do not log
+ // the stat here since the keyboard will not actually be shown.
+ if (!WillHideKeyboard())
+ keyboard::LogKeyboardControlEvent(keyboard::KEYBOARD_CONTROL_SHOW);
+
+ weak_factory_.InvalidateWeakPtrs();
+
+ // If |container_| has hide animation, its visibility is set to false when
+ // hide animation finished. So even if the container is visible at this
+ // point, it may in the process of hiding. We still need to show keyboard
+ // container in this case.
+ if (container_->IsVisible() &&
+ !container_->layer()->GetAnimator()->is_animating())
+ return;
+
+ ToggleTouchEventLogging(false);
+ ui::LayerAnimator* container_animator = container_->layer()->GetAnimator();
+
+ // If the container is not animating, makes sure the position and opacity
+ // are at begin states for animation.
+ if (!container_animator->is_animating()) {
+ gfx::Transform transform;
+ transform.Translate(0, proxy_->GetKeyboardWindow()->bounds().height());
+ container_->SetTransform(transform);
+ container_->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
+ }
+
+ container_animator->set_preemption_strategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ animation_observer_.reset(new CallbackAnimationObserver(
+ container_animator,
+ base::Bind(&KeyboardController::ShowAnimationFinished,
+ base::Unretained(this))));
+ container_animator->AddObserver(animation_observer_.get());
+
+ proxy_->ShowKeyboardContainer(container_.get());
+
+ {
+ // Scope the following animation settings as we don't want to animate
+ // visibility change that triggered by a call to the base class function
+ // ShowKeyboardContainer with these settings. The container should become
+ // visible immediately.
+ ui::ScopedLayerAnimationSettings settings(container_animator);
+ settings.SetTweenType(gfx::Tween::EASE_IN);
+ settings.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
+ container_->SetTransform(gfx::Transform());
+ container_->layer()->SetOpacity(1.0);
+ }
+}
+
+void KeyboardController::ResetWindowInsets() {
+ const gfx::Insets insets;
+ scoped_ptr<content::RenderWidgetHostIterator> widgets(
+ content::RenderWidgetHost::GetRenderWidgetHosts());
+ while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
+ content::RenderWidgetHostView* view = widget->GetView();
+ if (view)
+ view->SetInsets(insets);
+ }
+}
+
bool KeyboardController::WillHideKeyboard() const {
return weak_factory_.HasWeakPtrs();
}
+void KeyboardController::ShowAnimationFinished() {
+ // Notify observers after animation finished to prevent reveal desktop
+ // background during animation.
+ NotifyKeyboardBoundsChanging(proxy_->GetKeyboardWindow()->bounds());
+ proxy_->EnsureCaretInWorkArea();
+}
+
+void KeyboardController::HideAnimationFinished() {
+ proxy_->HideKeyboardContainer(container_.get());
+}
+
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_controller.h b/chromium/ui/keyboard/keyboard_controller.h
index e5cfbe5d847..7bd8e2f8723 100644
--- a/chromium/ui/keyboard/keyboard_controller.h
+++ b/chromium/ui/keyboard/keyboard_controller.h
@@ -11,15 +11,14 @@
#include "base/observer_list.h"
#include "ui/aura/window_observer.h"
#include "ui/base/ime/input_method_observer.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/rect.h"
#include "ui/keyboard/keyboard_export.h"
#include "url/gurl.h"
namespace aura {
class Window;
}
-namespace gfx {
-class Rect;
-}
namespace ui {
class InputMethod;
class TextInputClient;
@@ -27,9 +26,9 @@ class TextInputClient;
namespace keyboard {
+class CallbackAnimationObserver;
class KeyboardControllerObserver;
class KeyboardControllerProxy;
-class KeyboardLayoutManager;
// Provides control of the virtual keyboard, including providing a container
// and controlling visibility.
@@ -52,9 +51,14 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// KeyboardController.
aura::Window* GetContainerWindow();
- // Sets the override content url. This is used by for input view for extension
- // IMEs.
- void SetOverrideContentUrl(const GURL& url);
+ // Whether the container window for the keyboard has been initialized.
+ bool keyboard_container_initialized() const {
+ return container_.get() != NULL;
+ }
+
+ // Reloads the content of the keyboard. No-op if the keyboard content is not
+ // loaded yet.
+ void Reload();
// Hides virtual keyboard and notifies observer bounds change.
// This function should be called with a delay to avoid layout flicker
@@ -73,6 +77,27 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
void set_lock_keyboard(bool lock) { lock_keyboard_ = lock; }
+ // Force the keyboard to show up if not showing and lock the keyboard if
+ // |lock| is true.
+ void ShowKeyboard(bool lock);
+
+ // Sets the active keyboard controller. KeyboardController takes ownership of
+ // the instance. Calling ResetIntance with a new instance destroys the
+ // previous one. May be called with NULL to clear the instance.
+ static void ResetInstance(KeyboardController* controller);
+
+ // Retrieve the active keyboard controller.
+ static KeyboardController* GetInstance();
+
+ // Returns true if keyboard is currently visible.
+ bool keyboard_visible() { return keyboard_visible_; }
+
+ // Returns the current keyboard bounds. When the keyboard is not shown,
+ // an empty rectangle will get returned.
+ const gfx::Rect& current_keyboard_bounds() {
+ return current_keyboard_bounds_;
+ }
+
private:
// For access to Observer methods for simulation.
friend class KeyboardControllerTest;
@@ -92,20 +117,42 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
const ui::TextInputClient* client) OVERRIDE;
virtual void OnInputMethodDestroyed(
const ui::InputMethod* input_method) OVERRIDE;
+ virtual void OnShowImeIfNeeded() OVERRIDE;
+
+ // Show virtual keyboard immediately with animation.
+ void ShowKeyboardInternal();
+
+ // Clears any insets on web content windows.
+ void ResetWindowInsets();
// Returns true if keyboard is scheduled to hide.
bool WillHideKeyboard() const;
+ // Called when show and hide animation finished successfully. If the animation
+ // is aborted, it won't be called.
+ void ShowAnimationFinished();
+ void HideAnimationFinished();
+
scoped_ptr<KeyboardControllerProxy> proxy_;
scoped_ptr<aura::Window> container_;
+ // CallbackAnimationObserver should destructed before container_ because it
+ // uses container_'s animator.
+ scoped_ptr<CallbackAnimationObserver> animation_observer_;
+
ui::InputMethod* input_method_;
bool keyboard_visible_;
bool lock_keyboard_;
+ ui::TextInputType type_;
ObserverList<KeyboardControllerObserver> observer_list_;
base::WeakPtrFactory<KeyboardController> weak_factory_;
+ // The currently used keyboard position.
+ gfx::Rect current_keyboard_bounds_;
+
+ static KeyboardController* instance_;
+
DISALLOW_COPY_AND_ASSIGN(KeyboardController);
};
diff --git a/chromium/ui/keyboard/keyboard_controller_proxy.cc b/chromium/ui/keyboard/keyboard_controller_proxy.cc
index fb6f04d9ede..dec2b0f3518 100644
--- a/chromium/ui/keyboard/keyboard_controller_proxy.cc
+++ b/chromium/ui/keyboard/keyboard_controller_proxy.cc
@@ -4,54 +4,26 @@
#include "ui/keyboard/keyboard_controller_proxy.h"
+#include "base/command_line.h"
#include "base/values.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_view.h"
#include "content/public/browser/web_ui.h"
#include "content/public/common/bindings_policy.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/text_input_client.h"
#include "ui/keyboard/keyboard_constants.h"
+#include "ui/keyboard/keyboard_switches.h"
+#include "ui/keyboard/keyboard_util.h"
+#include "ui/wm/core/shadow.h"
namespace {
-// Converts ui::TextInputType to string.
-std::string TextInputTypeToString(ui::TextInputType type) {
- switch (type) {
- case ui::TEXT_INPUT_TYPE_NONE:
- return "none";
- case ui::TEXT_INPUT_TYPE_PASSWORD:
- return "password";
- case ui::TEXT_INPUT_TYPE_EMAIL:
- return "email";
- case ui::TEXT_INPUT_TYPE_NUMBER:
- return "number";
- case ui::TEXT_INPUT_TYPE_TELEPHONE:
- return "tel";
- case ui::TEXT_INPUT_TYPE_URL:
- return "url";
- case ui::TEXT_INPUT_TYPE_DATE:
- return "date";
- case ui::TEXT_INPUT_TYPE_TEXT:
- case ui::TEXT_INPUT_TYPE_SEARCH:
- case ui::TEXT_INPUT_TYPE_DATE_TIME:
- case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL:
- case ui::TEXT_INPUT_TYPE_MONTH:
- case ui::TEXT_INPUT_TYPE_TIME:
- case ui::TEXT_INPUT_TYPE_WEEK:
- case ui::TEXT_INPUT_TYPE_TEXT_AREA:
- case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE:
- case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD:
- return "text";
- }
- NOTREACHED();
- return "";
-}
-
// The WebContentsDelegate for the keyboard.
// The delegate deletes itself when the keyboard is destroyed.
class KeyboardContentsDelegate : public content::WebContentsDelegate,
@@ -80,13 +52,15 @@ class KeyboardContentsDelegate : public content::WebContentsDelegate,
virtual void MoveContents(content::WebContents* source,
const gfx::Rect& pos) OVERRIDE {
aura::Window* keyboard = proxy_->GetKeyboardWindow();
+ // keyboard window must have been added to keyboard container window at this
+ // point. Otherwise, wrong keyboard bounds is used and may cause problem as
+ // described in crbug.com/367788.
+ DCHECK(keyboard->parent());
gfx::Rect bounds = keyboard->bounds();
int new_height = pos.height();
bounds.set_y(bounds.y() + bounds.height() - new_height);
bounds.set_height(new_height);
- proxy_->set_resizing_from_contents(true);
keyboard->SetBounds(bounds);
- proxy_->set_resizing_from_contents(false);
}
// Overridden from content::WebContentsDelegate:
@@ -96,9 +70,8 @@ class KeyboardContentsDelegate : public content::WebContentsDelegate,
proxy_->RequestAudioInput(web_contents, request, callback);
}
-
// Overridden from content::WebContentsObserver:
- virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE {
+ virtual void WebContentsDestroyed() OVERRIDE {
delete this;
}
@@ -112,33 +85,25 @@ class KeyboardContentsDelegate : public content::WebContentsDelegate,
namespace keyboard {
KeyboardControllerProxy::KeyboardControllerProxy()
- : default_url_(kKeyboardWebUIURL), resizing_from_contents_(false) {
+ : default_url_(kKeyboardURL) {
}
KeyboardControllerProxy::~KeyboardControllerProxy() {
}
-const GURL& KeyboardControllerProxy::GetValidUrl() {
- return override_url_.is_valid() ? override_url_ : default_url_;
-}
-
-void KeyboardControllerProxy::SetOverrideContentUrl(const GURL& url) {
- if (override_url_ == url)
- return;
-
- override_url_ = url;
- // Restores the keyboard window size to default.
- aura::Window* container = GetKeyboardWindow()->parent();
- CHECK(container);
- container->layout_manager()->OnWindowResized();
-
- ReloadContents();
+const GURL& KeyboardControllerProxy::GetVirtualKeyboardUrl() {
+ if (keyboard::IsInputViewEnabled()) {
+ const GURL& override_url = GetOverrideContentUrl();
+ return override_url.is_valid() ? override_url : default_url_;
+ } else {
+ return default_url_;
+ }
}
-void KeyboardControllerProxy::ReloadContents() {
+void KeyboardControllerProxy::LoadContents(const GURL& url) {
if (keyboard_contents_) {
content::OpenURLParams params(
- GetValidUrl(),
+ url,
content::Referrer(),
SINGLETON_TAB,
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
@@ -152,13 +117,19 @@ aura::Window* KeyboardControllerProxy::GetKeyboardWindow() {
content::BrowserContext* context = GetBrowserContext();
keyboard_contents_.reset(content::WebContents::Create(
content::WebContents::CreateParams(context,
- content::SiteInstance::CreateForURL(context, GetValidUrl()))));
+ content::SiteInstance::CreateForURL(context,
+ GetVirtualKeyboardUrl()))));
keyboard_contents_->SetDelegate(new KeyboardContentsDelegate(this));
SetupWebContents(keyboard_contents_.get());
- ReloadContents();
+ LoadContents(GetVirtualKeyboardUrl());
+ keyboard_contents_->GetNativeView()->AddObserver(this);
}
- return keyboard_contents_->GetView()->GetNativeView();
+ return keyboard_contents_->GetNativeView();
+}
+
+bool KeyboardControllerProxy::HasKeyboardWindow() const {
+ return keyboard_contents_;
}
void KeyboardControllerProxy::ShowKeyboardContainer(aura::Window* container) {
@@ -172,20 +143,57 @@ void KeyboardControllerProxy::HideKeyboardContainer(aura::Window* container) {
}
void KeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) {
- content::WebUI* webui = keyboard_contents_ ?
- keyboard_contents_->GetCommittedWebUI() : NULL;
-
- if (webui &&
- (0 != (webui->GetBindings() & content::BINDINGS_POLICY_WEB_UI))) {
- // Only call OnTextInputBoxFocused function if it is a web ui keyboard,
- // not an extension based keyboard.
- base::DictionaryValue input_context;
- input_context.SetString("type", TextInputTypeToString(type));
- webui->CallJavascriptFunction("OnTextInputBoxFocused", input_context);
+}
+
+void KeyboardControllerProxy::EnsureCaretInWorkArea() {
+ if (GetInputMethod()->GetTextInputClient()) {
+ aura::Window* keyboard_window = GetKeyboardWindow();
+ aura::Window* root_window = keyboard_window->GetRootWindow();
+ gfx::Rect available_bounds = root_window->bounds();
+ gfx::Rect keyboard_bounds = keyboard_window->bounds();
+ available_bounds.set_height(available_bounds.height() -
+ keyboard_bounds.height());
+ GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(available_bounds);
+ }
+}
+
+void KeyboardControllerProxy::LoadSystemKeyboard() {
+ DCHECK(keyboard_contents_);
+ if (keyboard_contents_->GetURL() != default_url_) {
+ // TODO(bshe): The height of system virtual keyboard and IME virtual
+ // keyboard may different. The height needs to be restored too.
+ LoadContents(default_url_);
+ }
+}
+
+void KeyboardControllerProxy::ReloadKeyboardIfNeeded() {
+ DCHECK(keyboard_contents_);
+ if (keyboard_contents_->GetURL() != GetVirtualKeyboardUrl()) {
+ LoadContents(GetVirtualKeyboardUrl());
}
}
void KeyboardControllerProxy::SetupWebContents(content::WebContents* contents) {
}
+void KeyboardControllerProxy::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ if (!shadow_) {
+ shadow_.reset(new wm::Shadow());
+ shadow_->Init(wm::Shadow::STYLE_ACTIVE);
+ shadow_->layer()->SetVisible(true);
+ DCHECK(keyboard_contents_->GetNativeView()->parent());
+ keyboard_contents_->GetNativeView()->parent()->layer()->Add(
+ shadow_->layer());
+ }
+
+ shadow_->SetContentBounds(new_bounds);
+}
+
+void KeyboardControllerProxy::OnWindowDestroyed(aura::Window* window) {
+ window->RemoveObserver(this);
+}
+
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_controller_proxy.h b/chromium/ui/keyboard/keyboard_controller_proxy.h
index c028b74ddcb..d7886e2d91a 100644
--- a/chromium/ui/keyboard/keyboard_controller_proxy.h
+++ b/chromium/ui/keyboard/keyboard_controller_proxy.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/common/media_stream_request.h"
+#include "ui/aura/window_observer.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/keyboard/keyboard_export.h"
@@ -24,13 +25,30 @@ class Rect;
namespace ui {
class InputMethod;
}
+namespace wm {
+class Shadow;
+}
namespace keyboard {
// A proxy used by the KeyboardController to get access to the virtual
// keyboard window.
-class KEYBOARD_EXPORT KeyboardControllerProxy {
+class KEYBOARD_EXPORT KeyboardControllerProxy : public aura::WindowObserver {
public:
+ class TestApi {
+ public:
+ explicit TestApi(KeyboardControllerProxy* proxy) : proxy_(proxy) {}
+
+ const content::WebContents* keyboard_contents() {
+ return proxy_->keyboard_contents_.get();
+ }
+
+ private:
+ KeyboardControllerProxy* proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestApi);
+ };
+
KeyboardControllerProxy();
virtual ~KeyboardControllerProxy();
@@ -38,17 +56,9 @@ class KEYBOARD_EXPORT KeyboardControllerProxy {
// with the proxy.
virtual aura::Window* GetKeyboardWindow();
- // Sets the override content url.
- void SetOverrideContentUrl(const GURL& url);
-
- // Whether the keyboard window is resizing from its web contents.
- bool resizing_from_contents() const { return resizing_from_contents_; }
-
- // Sets the flag of whether the keyboard window is resizing from
- // its web contents.
- void set_resizing_from_contents(bool resizing) {
- resizing_from_contents_ = resizing;
- }
+ // Whether the keyboard window is created. The keyboard window is tied to a
+ // WebContent so we can just check if the WebContent is created or not.
+ virtual bool HasKeyboardWindow() const;
// Gets the InputMethod that will provide notifications about changes in the
// text input context.
@@ -69,11 +79,28 @@ class KEYBOARD_EXPORT KeyboardControllerProxy {
// necesasry animation, or delay the visibility change as it desires.
virtual void HideKeyboardContainer(aura::Window* container);
- // Updates the type of the focused text input box. The default implementation
- // calls OnTextInputBoxFocused javascript function through webui to update the
- // type the of focused input box.
+ // Updates the type of the focused text input box.
virtual void SetUpdateInputType(ui::TextInputType type);
+ // Ensures caret in current work area (not occluded by virtual keyboard
+ // window).
+ virtual void EnsureCaretInWorkArea();
+
+ // Loads system virtual keyboard. Noop if the current virtual keyboard is
+ // system virtual keyboard.
+ virtual void LoadSystemKeyboard();
+
+ // Reloads virtual keyboard URL if the current keyboard's web content URL is
+ // different. The URL can be different if user switch from password field to
+ // any other type input field.
+ // At password field, the system virtual keyboard is forced to load even if
+ // the current IME provides a customized virtual keyboard. This is needed to
+ // prevent IME virtual keyboard logging user's password. Once user switch to
+ // other input fields, the virtual keyboard should switch back to the IME
+ // provided keyboard, or keep using the system virtual keyboard if IME doesn't
+ // provide one.
+ virtual void ReloadKeyboardIfNeeded();
+
protected:
// Gets the BrowserContext to use for creating the WebContents hosting the
// keyboard.
@@ -85,20 +112,25 @@ class KEYBOARD_EXPORT KeyboardControllerProxy {
// loading the keyboard page.
virtual void SetupWebContents(content::WebContents* contents);
+ // aura::WindowObserver overrides:
+ virtual void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
private:
- // Reloads the web contents to the valid url from GetValidUrl().
- void ReloadContents();
+ friend class TestApi;
- // Gets the valid url from default url or override url.
- const GURL& GetValidUrl();
+ // Loads the web contents for the given |url|.
+ void LoadContents(const GURL& url);
+
+ // Gets the virtual keyboard URL (either the default URL or IME override URL).
+ const GURL& GetVirtualKeyboardUrl();
const GURL default_url_;
- GURL override_url_;
scoped_ptr<content::WebContents> keyboard_contents_;
-
- // Whether the current keyboard window is resizing from its web content.
- bool resizing_from_contents_;
+ scoped_ptr<wm::Shadow> shadow_;
DISALLOW_COPY_AND_ASSIGN(KeyboardControllerProxy);
};
diff --git a/chromium/ui/keyboard/keyboard_controller_unittest.cc b/chromium/ui/keyboard/keyboard_controller_unittest.cc
index d79c9ba3d82..a39bee8ef32 100644
--- a/chromium/ui/keyboard/keyboard_controller_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_controller_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/keyboard/keyboard_controller.h"
+
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
@@ -9,23 +11,49 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/layout_manager.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_helper.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/ime/dummy_text_input_client.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_factory.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/compositor/compositor.h"
#include "ui/compositor/layer_type.h"
-#include "ui/gfx/rect.h"
-#include "ui/keyboard/keyboard_controller.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/keyboard/keyboard_controller_proxy.h"
#include "ui/keyboard/keyboard_switches.h"
+#include "ui/keyboard/keyboard_util.h"
+#include "ui/wm/core/default_activation_client.h"
namespace keyboard {
namespace {
+// Steps a layer animation until it is completed. Animations must be enabled.
+void RunAnimationForLayer(ui::Layer* layer) {
+ // Animations must be enabled for stepping to work.
+ ASSERT_NE(ui::ScopedAnimationDurationScaleMode::duration_scale_mode(),
+ ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+ ui::LayerAnimatorTestController controller(layer->GetAnimator());
+ // Multiple steps are required to complete complex animations.
+ // TODO(vollick): This should not be necessary. crbug.com/154017
+ while (controller.animator()->is_animating()) {
+ controller.StartThreadedAnimationsIfNeeded();
+ base::TimeTicks step_time = controller.animator()->last_step_time();
+ controller.animator()->Step(step_time +
+ base::TimeDelta::FromMilliseconds(1000));
+ }
+}
+
// An event handler that focuses a window when it is clicked/touched on. This is
// used to match the focus manger behaviour in ash and views.
class TestFocusController : public ui::EventHandler {
@@ -56,12 +84,8 @@ class TestFocusController : public ui::EventHandler {
class TestKeyboardControllerProxy : public KeyboardControllerProxy {
public:
TestKeyboardControllerProxy()
- : window_(new aura::Window(&delegate_)),
- input_method_(ui::CreateInputMethod(NULL,
- gfx::kNullAcceleratedWidget)) {
- window_->Init(ui::LAYER_NOT_DRAWN);
- window_->set_owned_by_parent(false);
- }
+ : input_method_(
+ ui::CreateInputMethod(NULL, gfx::kNullAcceleratedWidget)) {}
virtual ~TestKeyboardControllerProxy() {
// Destroy the window before the delegate.
@@ -69,7 +93,15 @@ class TestKeyboardControllerProxy : public KeyboardControllerProxy {
}
// Overridden from KeyboardControllerProxy:
- virtual aura::Window* GetKeyboardWindow() OVERRIDE { return window_.get(); }
+ virtual bool HasKeyboardWindow() const OVERRIDE { return window_; }
+ virtual aura::Window* GetKeyboardWindow() OVERRIDE {
+ if (!window_) {
+ window_.reset(new aura::Window(&delegate_));
+ window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window_->set_owned_by_parent(false);
+ }
+ return window_.get();
+ }
virtual content::BrowserContext* GetBrowserContext() OVERRIDE { return NULL; }
virtual ui::InputMethod* GetInputMethod() OVERRIDE {
return input_method_.get();
@@ -77,6 +109,8 @@ class TestKeyboardControllerProxy : public KeyboardControllerProxy {
virtual void RequestAudioInput(content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) OVERRIDE { return; }
+ virtual void LoadSystemKeyboard() OVERRIDE {};
+ virtual void ReloadKeyboardIfNeeded() OVERRIDE {};
private:
scoped_ptr<aura::Window> window_;
@@ -107,67 +141,6 @@ class EventObserver : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(EventObserver);
};
-class TestTextInputClient : public ui::TextInputClient {
- public:
- explicit TestTextInputClient(ui::TextInputType type)
- : type_(type) {}
- virtual ~TestTextInputClient() {}
-
- private:
- // Overridden from ui::TextInputClient:
- virtual void SetCompositionText(
- const ui::CompositionText& composition) OVERRIDE {}
- virtual void ConfirmCompositionText() OVERRIDE {}
- virtual void ClearCompositionText() OVERRIDE {}
- virtual void InsertText(const base::string16& text) OVERRIDE {}
- virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {}
- virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
- return static_cast<gfx::NativeWindow>(NULL);
- }
- virtual ui::TextInputType GetTextInputType() const OVERRIDE {
- return type_;
- }
- virtual ui::TextInputMode GetTextInputMode() const OVERRIDE {
- return ui::TEXT_INPUT_MODE_DEFAULT;
- }
- virtual bool CanComposeInline() const OVERRIDE { return false; }
- virtual gfx::Rect GetCaretBounds() const OVERRIDE { return gfx::Rect(); }
-
- virtual bool GetCompositionCharacterBounds(
- uint32 index,
- gfx::Rect* rect) const OVERRIDE {
- return false;
- }
- virtual bool HasCompositionText() const OVERRIDE { return false; }
- virtual bool GetTextRange(gfx::Range* range) const OVERRIDE { return false; }
- virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE {
- return false;
- }
- virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE {
- return false;
- }
- virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE {
- return false;
- }
- virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; }
- virtual bool GetTextFromRange(const gfx::Range& range,
- base::string16* text) const OVERRIDE {
- return false;
- }
- virtual void OnInputMethodChanged() OVERRIDE {}
- virtual bool ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) OVERRIDE { return false; }
- virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE {}
- virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {}
- virtual void OnCandidateWindowShown() OVERRIDE {}
- virtual void OnCandidateWindowUpdated() OVERRIDE {}
- virtual void OnCandidateWindowHidden() OVERRIDE {}
-
- ui::TextInputType type_;
-
- DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
-};
-
class KeyboardContainerObserver : public aura::WindowObserver {
public:
explicit KeyboardContainerObserver(aura::Window* window) : window_(window) {
@@ -197,17 +170,29 @@ class KeyboardControllerTest : public testing::Test {
virtual ~KeyboardControllerTest() {}
virtual void SetUp() OVERRIDE {
+ // The ContextFactory must exist before any Compositors are created.
+ bool enable_pixel_output = false;
+ ui::ContextFactory* context_factory =
+ ui::InitializeContextFactoryForTests(enable_pixel_output);
+
aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
- aura_test_helper_->SetUp();
+ aura_test_helper_->SetUp(context_factory);
+ new wm::DefaultActivationClient(aura_test_helper_->root_window());
ui::SetUpInputMethodFactoryForTesting();
+ if (::switches::IsTextInputFocusManagerEnabled())
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL);
focus_controller_.reset(new TestFocusController(root_window()));
proxy_ = new TestKeyboardControllerProxy();
controller_.reset(new KeyboardController(proxy_));
}
virtual void TearDown() OVERRIDE {
+ controller_.reset();
focus_controller_.reset();
+ if (::switches::IsTextInputFocusManagerEnabled())
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL);
aura_test_helper_->TearDown();
+ ui::TerminateContextFactoryForTests();
}
aura::Window* root_window() { return aura_test_helper_->root_window(); }
@@ -215,11 +200,31 @@ class KeyboardControllerTest : public testing::Test {
KeyboardController* controller() { return controller_.get(); }
void ShowKeyboard() {
- TestTextInputClient test_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
- controller_->OnTextInputStateChanged(&test_text_input_client);
+ test_text_input_client_.reset(
+ new ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT));
+ SetFocus(test_text_input_client_.get());
}
protected:
+ void SetFocus(ui::TextInputClient* client) {
+ ui::InputMethod* input_method = proxy()->GetInputMethod();
+ if (::switches::IsTextInputFocusManagerEnabled()) {
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(client);
+ input_method->OnTextInputTypeChanged(client);
+ } else {
+ input_method->SetFocusedTextInputClient(client);
+ }
+ if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
+ input_method->ShowImeIfNeeded();
+ if (proxy_->GetKeyboardWindow()->bounds().height() == 0) {
+ // Set initial bounds for test keyboard window.
+ proxy_->GetKeyboardWindow()->SetBounds(
+ KeyboardBoundsFromWindowBounds(
+ controller()->GetContainerWindow()->bounds(), 100));
+ }
+ }
+ }
+
bool WillHideKeyboard() {
return controller_->WillHideKeyboard();
}
@@ -231,23 +236,33 @@ class KeyboardControllerTest : public testing::Test {
private:
KeyboardControllerProxy* proxy_;
scoped_ptr<KeyboardController> controller_;
-
+ scoped_ptr<ui::TextInputClient> test_text_input_client_;
DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
};
TEST_F(KeyboardControllerTest, KeyboardSize) {
aura::Window* container(controller()->GetContainerWindow());
- gfx::Rect bounds(0, 0, 100, 100);
- container->SetBounds(bounds);
+ aura::Window* keyboard(proxy()->GetKeyboardWindow());
+ container->SetBounds(gfx::Rect(0, 0, 200, 100));
+
+ container->AddChild(keyboard);
+ const gfx::Rect& before_bounds = keyboard->bounds();
+ // The initial keyboard should be positioned at the bottom of container and
+ // has 0 height.
+ ASSERT_EQ(gfx::Rect(0, 100, 200, 0), before_bounds);
- const gfx::Rect& before_bounds = proxy()->GetKeyboardWindow()->bounds();
gfx::Rect new_bounds(
- before_bounds.x(), before_bounds.y(),
- before_bounds.width() / 2, before_bounds.height() / 2);
+ before_bounds.x(), before_bounds.y() - 50,
+ before_bounds.width(), 50);
+
+ keyboard->SetBounds(new_bounds);
+ ASSERT_EQ(new_bounds, keyboard->bounds());
- // The KeyboardController's LayoutManager shouldn't let this happen
- proxy()->GetKeyboardWindow()->SetBounds(new_bounds);
- ASSERT_EQ(before_bounds, proxy()->GetKeyboardWindow()->bounds());
+ // Mock a screen rotation.
+ container->SetBounds(gfx::Rect(0, 0, 100, 200));
+ // The above call should resize keyboard to new width while keeping the old
+ // height.
+ ASSERT_EQ(gfx::Rect(0, 150, 100, 50), keyboard->bounds());
}
// Tests that tapping/clicking inside the keyboard does not give it focus.
@@ -255,7 +270,7 @@ TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
const gfx::Rect& root_bounds = root_window()->bounds();
aura::test::EventCountDelegate delegate;
scoped_ptr<aura::Window> window(new aura::Window(&delegate));
- window->Init(ui::LAYER_NOT_DRAWN);
+ window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
window->SetBounds(root_bounds);
root_window()->AddChild(window.get());
window->Show();
@@ -292,18 +307,88 @@ TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
generator.MoveMouseTo(gfx::Point());
generator.ClickLeftButton();
EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
+ keyboard_container->RemovePreTargetHandler(&observer);
+}
+
+TEST_F(KeyboardControllerTest, EventHitTestingInContainer) {
+ const gfx::Rect& root_bounds = root_window()->bounds();
+ aura::test::EventCountDelegate delegate;
+ scoped_ptr<aura::Window> window(new aura::Window(&delegate));
+ window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window->SetBounds(root_bounds);
+ root_window()->AddChild(window.get());
+ window->Show();
+ window->Focus();
+
+ aura::Window* keyboard_container(controller()->GetContainerWindow());
+ keyboard_container->SetBounds(root_bounds);
+
+ root_window()->AddChild(keyboard_container);
+ keyboard_container->Show();
+
+ ShowKeyboard();
+
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(keyboard_container->IsVisible());
+ EXPECT_TRUE(window->HasFocus());
+ EXPECT_FALSE(keyboard_container->HasFocus());
+
+ // Make sure hit testing works correctly while the keyboard is visible.
+ aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
+ ui::EventTarget* root = root_window();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+ gfx::Point location = keyboard_window->bounds().CenterPoint();
+ ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, location, location, ui::EF_NONE,
+ ui::EF_NONE);
+ EXPECT_EQ(keyboard_window, targeter->FindTargetForEvent(root, &mouse1));
+
+ location.set_y(keyboard_window->bounds().y() - 5);
+ ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, location, location, ui::EF_NONE,
+ ui::EF_NONE);
+ EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse2));
+}
+
+TEST_F(KeyboardControllerTest, KeyboardWindowCreation) {
+ const gfx::Rect& root_bounds = root_window()->bounds();
+ aura::test::EventCountDelegate delegate;
+ scoped_ptr<aura::Window> window(new aura::Window(&delegate));
+ window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ window->SetBounds(root_bounds);
+ root_window()->AddChild(window.get());
+ window->Show();
+ window->Focus();
+
+ aura::Window* keyboard_container(controller()->GetContainerWindow());
+ keyboard_container->SetBounds(root_bounds);
+
+ root_window()->AddChild(keyboard_container);
+ keyboard_container->Show();
+
+ EXPECT_FALSE(proxy()->HasKeyboardWindow());
+
+ ui::EventTarget* root = root_window();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+ gfx::Point location(root_window()->bounds().width() / 2,
+ root_window()->bounds().height() - 10);
+ ui::MouseEvent mouse(
+ ui::ET_MOUSE_MOVED, location, location, ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse));
+ EXPECT_FALSE(proxy()->HasKeyboardWindow());
+
+ EXPECT_EQ(
+ controller()->GetContainerWindow(),
+ controller()->GetContainerWindow()->GetEventHandlerForPoint(location));
+ EXPECT_FALSE(proxy()->HasKeyboardWindow());
}
TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
const gfx::Rect& root_bounds = root_window()->bounds();
- ui::InputMethod* input_method = proxy()->GetInputMethod();
- TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient input_client_2(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
- TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
- input_method->SetFocusedTextInputClient(&input_client_0);
+ ui::DummyTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient input_client_2(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
+ ui::DummyTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
aura::Window* keyboard_container(controller()->GetContainerWindow());
scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
@@ -311,9 +396,11 @@ TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
keyboard_container->SetBounds(root_bounds);
root_window()->AddChild(keyboard_container);
+ SetFocus(&input_client_0);
+
EXPECT_TRUE(keyboard_container->IsVisible());
- input_method->SetFocusedTextInputClient(&no_input_client_0);
+ SetFocus(&no_input_client_0);
// Keyboard should not immediately hide itself. It is delayed to avoid layout
// flicker when the focus of input field quickly change.
EXPECT_TRUE(keyboard_container->IsVisible());
@@ -322,14 +409,14 @@ TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
base::MessageLoop::current()->Run();
EXPECT_FALSE(keyboard_container->IsVisible());
- input_method->SetFocusedTextInputClient(&input_client_1);
+ SetFocus(&input_client_1);
EXPECT_TRUE(keyboard_container->IsVisible());
// Schedule to hide keyboard.
- input_method->SetFocusedTextInputClient(&no_input_client_1);
+ SetFocus(&no_input_client_1);
EXPECT_TRUE(WillHideKeyboard());
// Cancel keyboard hide.
- input_method->SetFocusedTextInputClient(&input_client_2);
+ SetFocus(&input_client_2);
EXPECT_FALSE(WillHideKeyboard());
EXPECT_TRUE(keyboard_container->IsVisible());
@@ -338,12 +425,10 @@ TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
TEST_F(KeyboardControllerTest, AlwaysVisibleWhenLocked) {
const gfx::Rect& root_bounds = root_window()->bounds();
- ui::InputMethod* input_method = proxy()->GetInputMethod();
- TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
- TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
- input_method->SetFocusedTextInputClient(&input_client_0);
+ ui::DummyTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
+ ui::DummyTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
aura::Window* keyboard_container(controller()->GetContainerWindow());
scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
@@ -351,24 +436,26 @@ TEST_F(KeyboardControllerTest, AlwaysVisibleWhenLocked) {
keyboard_container->SetBounds(root_bounds);
root_window()->AddChild(keyboard_container);
+ SetFocus(&input_client_0);
+
EXPECT_TRUE(keyboard_container->IsVisible());
// Lock keyboard.
controller()->set_lock_keyboard(true);
- input_method->SetFocusedTextInputClient(&no_input_client_0);
+ SetFocus(&no_input_client_0);
// Keyboard should not try to hide itself as it is locked.
EXPECT_TRUE(keyboard_container->IsVisible());
EXPECT_FALSE(WillHideKeyboard());
- input_method->SetFocusedTextInputClient(&input_client_1);
+ SetFocus(&input_client_1);
EXPECT_TRUE(keyboard_container->IsVisible());
// Unlock keyboard.
controller()->set_lock_keyboard(false);
// Keyboard should hide when focus on no input client.
- input_method->SetFocusedTextInputClient(&no_input_client_1);
+ SetFocus(&no_input_client_1);
EXPECT_TRUE(WillHideKeyboard());
// Wait for hide keyboard to finish.
@@ -376,32 +463,113 @@ TEST_F(KeyboardControllerTest, AlwaysVisibleWhenLocked) {
EXPECT_FALSE(keyboard_container->IsVisible());
}
-TEST_F(KeyboardControllerTest, KeyboardResizingFromContents) {
- aura::Window* keyboard_container = controller()->GetContainerWindow();
- aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
- keyboard_container->SetBounds(gfx::Rect(800, 600));
- keyboard_container->AddChild(keyboard_window);
+class KeyboardControllerAnimationTest : public KeyboardControllerTest,
+ public KeyboardControllerObserver {
+ public:
+ KeyboardControllerAnimationTest() {}
+ virtual ~KeyboardControllerAnimationTest() {}
- // Default keyboard size.
- EXPECT_EQ(180, keyboard_window->bounds().height());
+ virtual void SetUp() OVERRIDE {
+ // We cannot short-circuit animations for this test.
+ ui::ScopedAnimationDurationScaleMode normal_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+
+ KeyboardControllerTest::SetUp();
+
+ const gfx::Rect& root_bounds = root_window()->bounds();
+ keyboard_container()->SetBounds(root_bounds);
+ root_window()->AddChild(keyboard_container());
+ controller()->AddObserver(this);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ controller()->RemoveObserver(this);
+ KeyboardControllerTest::TearDown();
+ }
+
+ protected:
+ // KeyboardControllerObserver overrides
+ virtual void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) OVERRIDE {
+ notified_bounds_ = new_bounds;
+ }
+
+ const gfx::Rect& notified_bounds() { return notified_bounds_; }
- // Resizes from contents when flag is unset.
- keyboard_window->SetBounds(gfx::Rect(100, 80));
- EXPECT_EQ(180, keyboard_window->bounds().height());
+ aura::Window* keyboard_container() {
+ return controller()->GetContainerWindow();
+ }
+
+ aura::Window* keyboard_window() {
+ return proxy()->GetKeyboardWindow();
+ }
+
+ private:
+ gfx::Rect notified_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardControllerAnimationTest);
+};
+
+// Tests virtual keyboard has correct show and hide animation.
+TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
+ ui::Layer* layer = keyboard_container()->layer();
+ ShowKeyboard();
- // Resizes from contents when flag is set.
- proxy()->set_resizing_from_contents(true);
- keyboard_window->SetBounds(gfx::Rect(100, 80));
- EXPECT_EQ(80, keyboard_window->bounds().height());
+ // Keyboard container and window should immediately become visible before
+ // animation starts.
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float show_start_opacity = layer->opacity();
+ gfx::Transform transform;
+ transform.Translate(0, keyboard_window()->bounds().height());
+ EXPECT_EQ(transform, layer->transform());
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+
+ RunAnimationForLayer(layer);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float show_end_opacity = layer->opacity();
+ EXPECT_LT(show_start_opacity, show_end_opacity);
+ EXPECT_EQ(gfx::Transform(), layer->transform());
+ // KeyboardController should notify the bounds of keyboard window to its
+ // observers after show animation finished.
+ EXPECT_EQ(keyboard_window()->bounds(), notified_bounds());
+
+ // Directly hide keyboard without delay.
+ controller()->HideKeyboard(KeyboardController::HIDE_REASON_AUTOMATIC);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_container()->layer()->visible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float hide_start_opacity = layer->opacity();
+ // KeyboardController should notify the bounds of keyboard window to its
+ // observers before hide animation starts.
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+
+ RunAnimationForLayer(layer);
+ EXPECT_FALSE(keyboard_container()->IsVisible());
+ EXPECT_FALSE(keyboard_container()->layer()->visible());
+ EXPECT_FALSE(keyboard_window()->IsVisible());
+ float hide_end_opacity = layer->opacity();
+ EXPECT_GT(hide_start_opacity, hide_end_opacity);
+ EXPECT_EQ(transform, layer->transform());
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+}
- // Resizes from container when flag is set.
- keyboard_container->SetBounds(gfx::Rect(400, 300));
- EXPECT_EQ(80, keyboard_window->bounds().height());
+// Show keyboard during keyboard hide animation should abort the hide animation
+// and the keyboard should animate in.
+// Test for crbug.com/333284.
+TEST_F(KeyboardControllerAnimationTest, ContainerShowWhileHide) {
+ ui::Layer* layer = keyboard_container()->layer();
+ ShowKeyboard();
+ RunAnimationForLayer(layer);
- // Resizes from container when flag is unset.
- proxy()->set_resizing_from_contents(false);
- keyboard_container->SetBounds(gfx::Rect(800, 600));
- EXPECT_EQ(180, keyboard_window->bounds().height());
+ controller()->HideKeyboard(KeyboardController::HIDE_REASON_AUTOMATIC);
+ // Before hide animation finishes, show keyboard again.
+ ShowKeyboard();
+ RunAnimationForLayer(layer);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ EXPECT_EQ(1.0, layer->opacity());
+ EXPECT_EQ(gfx::Transform(), layer->transform());
}
class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
@@ -422,18 +590,17 @@ class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
TEST_F(KeyboardControllerUsabilityTest, KeyboardAlwaysVisibleInUsabilityTest) {
const gfx::Rect& root_bounds = root_window()->bounds();
- ui::InputMethod* input_method = proxy()->GetInputMethod();
- TestTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
- TestTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
- input_method->SetFocusedTextInputClient(&input_client);
+ ui::DummyTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
+ ui::DummyTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
aura::Window* keyboard_container(controller()->GetContainerWindow());
keyboard_container->SetBounds(root_bounds);
root_window()->AddChild(keyboard_container);
+ SetFocus(&input_client);
EXPECT_TRUE(keyboard_container->IsVisible());
- input_method->SetFocusedTextInputClient(&no_input_client);
+ SetFocus(&no_input_client);
// Keyboard should not hide itself after lost focus.
EXPECT_TRUE(keyboard_container->IsVisible());
EXPECT_FALSE(WillHideKeyboard());
diff --git a/chromium/ui/keyboard/keyboard_layout_manager.cc b/chromium/ui/keyboard/keyboard_layout_manager.cc
new file mode 100644
index 00000000000..d7faf0fa7ab
--- /dev/null
+++ b/chromium/ui/keyboard/keyboard_layout_manager.cc
@@ -0,0 +1,63 @@
+// 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/keyboard/keyboard_layout_manager.h"
+
+#include "ui/compositor/layer_animator.h"
+#include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_controller_proxy.h"
+#include "ui/keyboard/keyboard_util.h"
+
+namespace keyboard {
+
+// Overridden from aura::LayoutManager
+void KeyboardLayoutManager::OnWindowResized() {
+ if (keyboard_) {
+ gfx::Rect window_bounds = controller_->GetContainerWindow()->bounds();
+ // Keep the same height when window resize. It usually get called when
+ // screen rotate.
+ int height = keyboard_->bounds().height();
+ keyboard_->SetBounds(gfx::Rect(
+ window_bounds.x(),
+ window_bounds.bottom() - height,
+ window_bounds.width(),
+ height));
+ }
+}
+
+void KeyboardLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
+ DCHECK(!keyboard_);
+ keyboard_ = child;
+ keyboard_->SetBounds(DefaultKeyboardBoundsFromWindowBounds(
+ controller_->GetContainerWindow()->bounds()));
+}
+
+void KeyboardLayoutManager::SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) {
+ // SetChildBounds can be invoked by resizing from the container or by
+ // resizing from the contents (through window.resizeTo call in JS).
+ // The flag resizing_from_contents() is used to determine the source of the
+ // resize.
+ DCHECK(child == keyboard_);
+
+ ui::LayerAnimator* animator =
+ controller_->GetContainerWindow()->layer()->GetAnimator();
+ // Stops previous animation if a window resize is requested during animation.
+ if (animator->is_animating())
+ animator->StopAnimating();
+
+ gfx::Rect old_bounds = child->bounds();
+ SetChildBoundsDirect(child, requested_bounds);
+ if (old_bounds.height() == 0 && child->bounds().height() != 0) {
+ // The window height is set to 0 initially. If the height of |old_bounds| is
+ // 0 and the new bounds is not 0, it probably means window.resizeTo is
+ // called to set the window height. We should try to show keyboard again in
+ // case the show keyboard request is called before the height is set.
+ controller_->ShowKeyboard(false);
+ } else {
+ controller_->NotifyKeyboardBoundsChanging(requested_bounds);
+ }
+}
+
+} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_layout_manager.h b/chromium/ui/keyboard/keyboard_layout_manager.h
new file mode 100644
index 00000000000..bc13f16c9c4
--- /dev/null
+++ b/chromium/ui/keyboard/keyboard_layout_manager.h
@@ -0,0 +1,43 @@
+// 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_KEYBOARD_KEYBOARD_LAYOUT_MANAGER_H_
+#define UI_KEYBOARD_KEYBOARD_LAYOUT_MANAGER_H_
+
+#include "ui/aura/layout_manager.h"
+#include "ui/aura/window.h"
+
+namespace keyboard {
+
+class KeyboardController;
+
+// LayoutManager for the virtual keyboard container. Manages a single window
+// (the virtual keyboard) and keeps it positioned at the bottom of the
+// owner window.
+class KeyboardLayoutManager : public aura::LayoutManager {
+ public:
+ explicit KeyboardLayoutManager(KeyboardController* controller)
+ : controller_(controller), keyboard_(NULL) {
+ }
+
+ // Overridden from aura::LayoutManager
+ virtual void OnWindowResized() OVERRIDE;
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) OVERRIDE {}
+ virtual void SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE;
+
+ private:
+ KeyboardController* controller_;
+ aura::Window* keyboard_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
+};
+
+} // namespace keyboard
+
+#endif // UI_KEYBOARD_KEYBOARD_LAYOUT_MANAGER_H_
diff --git a/chromium/ui/keyboard/keyboard_resources.grd b/chromium/ui/keyboard/keyboard_resources.grd
index 1fbf9684ffd..ffcbda553ab 100644
--- a/chromium/ui/keyboard/keyboard_resources.grd
+++ b/chromium/ui/keyboard/keyboard_resources.grd
@@ -15,62 +15,45 @@
</outputs>
<release seq="1">
<includes>
- <include name="IDR_KEYBOARD_API_ADAPTER_JS" file="resources/api_adapter.js" type="BINDATA" />
- <include name="IDR_KEYBOARD_CONSTANTS_JS" file="resources/constants.js" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_ALTKEY" file="resources/elements/kb-altkey.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_ALTKEY_CONTAINER" file="resources/elements/kb-altkey-container.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_ALTKEY_DATA" file="resources/elements/kb-altkey-data.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_ALTKEY_SET" file="resources/elements/kb-altkey-set.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEY" file="resources/elements/kb-key.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEY_BASE" file="resources/elements/kb-key-base.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEY_CODES" file="resources/elements/kb-key-codes.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEY_IMPORT" file="resources/elements/kb-key-import.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEY_SEQUENCE" file="resources/elements/kb-key-sequence.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEYBOARD" file="resources/elements/kb-keyboard.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_KEYSET" file="resources/elements/kb-keyset.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY" file="resources/elements/kb-modifier-key.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU" file="resources/elements/kb-options-menu.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_ROW" file="resources/elements/kb-row.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_ELEMENTS_SHIFT_KEY" file="resources/elements/kb-shift-key.html" type="BINDATA" />
<include name="IDR_KEYBOARD_FUNCTION_KEY_ROW" file="resources/layouts/function-key-row.html" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_BACK" file="resources/images/back.svg" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_BACKSPACE" file="resources/images/backspace.png" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_BRIGHTNESS_DOWN" file="resources/images/brightness-down.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_BRIGHTNESS_UP" file="resources/images/brightness-up.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_CHANGE_WINDOW" file="resources/images/change-window.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_DOWN" file="resources/images/down.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_FORWARD" file="resources/images/forward.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_FULLSCREEN" file="resources/images/fullscreen.svg" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_HIDE_KEYBOARD" file="resources/images/hide-keyboard.png" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_KEYBOARD" file="resources/images/keyboard.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_LEFT" file="resources/images/left.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_MICROPHONE" file="resources/images/microphone.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_MICROPHONE_GREEN" file="resources/images/microphone-green.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_MUTE" file="resources/images/mute.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_RELOAD" file="resources/images/reload.svg" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_RETURN" file="resources/images/return.png" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_RIGHT" file="resources/images/right.svg" type="BINDATA" />
- <include name="IDR_KEYBOARD_IMAGES_SEARCH" file="resources/images/search.svg" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_SEARCH" file="resources/images/search.png" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_SHIFT" file="resources/images/shift.png" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_SHUTDOWN" file="resources/images/shutdown.svg" type="BINDATA" />
+ <include name="IDR_KEYBOARD_IMAGES_TAB" file="resources/images/tab.png" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_UP" file="resources/images/up.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_VOLUME_DOWN" file="resources/images/volume-down.svg" type="BINDATA" />
<include name="IDR_KEYBOARD_IMAGES_VOLUME_UP" file="resources/images/volume-up.svg" type="BINDATA" />
- <!-- Don't flatten html file here. Otherwise, webui keyboard will not load the correct css file. -->
- <include name="IDR_KEYBOARD_INDEX" file="resources/index.html" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_KEYBOARD_LAYOUTS_DVORAK" file="resources/layouts/dvorak.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_LAYOUTS_LATIN_ACCENTS" file="resources/layouts/latin-accents.js" type="BINDATA" />
+ <include name="IDR_KEYBOARD_INDEX" file="resources/index.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_KEYBOARD_JS" file="resources/keyboard.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_KEYBOARD_LAYOUTS_NUMERIC" file="resources/layouts/numeric.html" type="BINDATA" />
<include name="IDR_KEYBOARD_LAYOUTS_QWERTY" file="resources/layouts/qwerty.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_LAYOUTS_SYMBOL_ALTKEYS" file="resources/layouts/symbol-altkeys.js" type="BINDATA" />
<include name="IDR_KEYBOARD_LAYOUTS_SYSTEM_QWERTY" file="resources/layouts/system-qwerty.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_MAIN_JS" file="resources/main.js" type="BINDATA" />
<include name="IDR_KEYBOARD_MANIFEST" file="resources/manifest.json" type="BINDATA" />
<include name="IDR_KEYBOARD_MAIN_CSS" file="resources/main.css" type="BINDATA" />
<include name="IDR_KEYBOARD_POLYMER_LOADER" file="resources/polymer_loader.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_KEYBOARD_ROBOTO_BOLD_TTF" file="resources/roboto_bold.ttf" type="BINDATA" />
+ <include name="IDR_KEYBOARD_SOUNDS_KEYPRESS_DELETE" file="resources/sounds/keypress-delete.wav" type="BINDATA" />
+ <include name="IDR_KEYBOARD_SOUNDS_KEYPRESS_RETURN" file="resources/sounds/keypress-return.wav" type="BINDATA" />
+ <include name="IDR_KEYBOARD_SOUNDS_KEYPRESS_SPACEBAR" file="resources/sounds/keypress-spacebar.wav" type="BINDATA" />
+ <include name="IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD" file="resources/sounds/keypress-standard.wav" type="BINDATA" />
<include name="IDR_KEYBOARD_SPACEBAR_ROW" file="resources/layouts/spacebar-row.html" type="BINDATA" />
- <include name="IDR_KEYBOARD_VOICE_INPUT_JS" file="resources/voice_input.js" type="BINDATA" />
- <include name="IDR_KEYBOARD_WEBUI_INDEX" file="resources/webui_index.html" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_KEYBOARD_WEBUI_API_ADAPTER_JS" file="resources/webui/api_adapter.js" type="BINDATA" />
- <include name="IDR_KEYBOARD_WEBUI_CONSTANTS_JS" file="resources/webui/constants.js" type="BINDATA" />
- <include name="IDR_KEYBOARD_WEBUI_MAIN_CSS" file="resources/webui/main.css" type="BINDATA" />
- <include name="IDR_KEYBOARD_WEBUI_QWERTY" file="resources/layouts/webui_qwerty.html" type="BINDATA" />
</includes>
</release>
</grit>
diff --git a/chromium/ui/keyboard/keyboard_switches.cc b/chromium/ui/keyboard/keyboard_switches.cc
index aeecf37b070..c0f9bc5705e 100644
--- a/chromium/ui/keyboard/keyboard_switches.cc
+++ b/chromium/ui/keyboard/keyboard_switches.cc
@@ -9,7 +9,18 @@ namespace switches {
const char kEnableSwipeSelection[] = "enable-swipe-selection";
+const char kDisableInputView[] = "disable-input-view";
+const char kEnableInputView[] = "enable-input-view";
+const char kEnableExperimentalInputViewFeatures[] =
+ "enable-experimental-input-view-features";
+
const char kEnableVirtualKeyboard[] = "enable-virtual-keyboard";
+
+const char kDisableVirtualKeyboardOverscroll[] =
+ "disable-virtual-keyboard-overscroll";
+const char kEnableVirtualKeyboardOverscroll[] =
+ "enable-virtual-keyboard-overscroll";
+
const char kKeyboardUsabilityExperiment[] = "keyboard-usability-experiment";
} // namespace switches
diff --git a/chromium/ui/keyboard/keyboard_switches.h b/chromium/ui/keyboard/keyboard_switches.h
index 04d4e737024..46b4010448c 100644
--- a/chromium/ui/keyboard/keyboard_switches.h
+++ b/chromium/ui/keyboard/keyboard_switches.h
@@ -13,9 +13,29 @@ namespace switches {
// Enables the swipe selection feature on the virtual keyboard.
KEYBOARD_EXPORT extern const char kEnableSwipeSelection[];
+// Disables IME extension APIs from overriding the URL for specifying the
+// contents of the virtual keyboard container.
+KEYBOARD_EXPORT extern const char kDisableInputView[];
+
+// Enables an IME extension API to set a URL for specifying the contents
+// of the virtual keyboard container.
+KEYBOARD_EXPORT extern const char kEnableInputView[];
+
+// Enables experimental features for IME extensions.
+KEYBOARD_EXPORT extern const char kEnableExperimentalInputViewFeatures[];
+
// Enables the virtual keyboard.
KEYBOARD_EXPORT extern const char kEnableVirtualKeyboard[];
+// Disabled overscrolling of web content when the virtual keyboard is displayed.
+// If disabled, the work area is resized to restrict windows from overlapping
+// with the keybaord area.
+KEYBOARD_EXPORT extern const char kDisableVirtualKeyboardOverscroll[];
+
+// Enable overscrolling of web content when the virtual keyboard is displayed
+// to provide access to content that would otherwise be occluded.
+KEYBOARD_EXPORT extern const char kEnableVirtualKeyboardOverscroll[];
+
// Enables the keyboard usability experiment. This is an experimental mode for
// testing the usability of various experimental keyboard layouts.
KEYBOARD_EXPORT extern const char kKeyboardUsabilityExperiment[];
diff --git a/chromium/ui/keyboard/keyboard_ui_controller.cc b/chromium/ui/keyboard/keyboard_ui_controller.cc
deleted file mode 100644
index 1c37cdf35a4..00000000000
--- a/chromium/ui/keyboard/keyboard_ui_controller.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/keyboard/keyboard_ui_controller.h"
-
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "grit/keyboard_resources.h"
-#include "ui/keyboard/keyboard_constants.h"
-#include "ui/keyboard/keyboard_ui_handler.h"
-
-namespace {
-
-content::WebUIDataSource* CreateKeyboardUIDataSource() {
- content::WebUIDataSource* source =
- content::WebUIDataSource::Create(keyboard::kKeyboardWebUIHost);
-
- source->SetDefaultResource(IDR_KEYBOARD_WEBUI_INDEX);
- source->AddResourcePath("elements/kb-altkey.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY);
- source->AddResourcePath("elements/kb-altkey-container.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY_CONTAINER);
- source->AddResourcePath("elements/kb-altkey-data.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY_DATA);
- source->AddResourcePath("elements/kb-altkey-set.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY_SET);
- source->AddResourcePath("elements/kb-key.html", IDR_KEYBOARD_ELEMENTS_KEY);
- source->AddResourcePath("elements/kb-key-base.html",
- IDR_KEYBOARD_ELEMENTS_KEY_BASE);
- source->AddResourcePath("elements/kb-key-codes.html",
- IDR_KEYBOARD_ELEMENTS_KEY_CODES);
- source->AddResourcePath("elements/kb-keyboard.html",
- IDR_KEYBOARD_ELEMENTS_KEYBOARD);
- source->AddResourcePath("elements/kb-keyset.html",
- IDR_KEYBOARD_ELEMENTS_KEYSET);
- source->AddResourcePath("elements/kb-modifier-key.html",
- IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY);
- source->AddResourcePath("elements/kb-options-menu.html",
- IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU);
- source->AddResourcePath("elements/kb-row.html", IDR_KEYBOARD_ELEMENTS_ROW);
- source->AddResourcePath("elements/kb-shift-key.html",
- IDR_KEYBOARD_ELEMENTS_SHIFT_KEY);
- source->AddResourcePath("images/back.svg",
- IDR_KEYBOARD_IMAGES_BACK);
- source->AddResourcePath("images/brightness-down.svg",
- IDR_KEYBOARD_IMAGES_BRIGHTNESS_DOWN);
- source->AddResourcePath("images/brightness-up.svg",
- IDR_KEYBOARD_IMAGES_BRIGHTNESS_UP);
- source->AddResourcePath("images/change-window.svg",
- IDR_KEYBOARD_IMAGES_CHANGE_WINDOW);
- source->AddResourcePath("images/down.svg",
- IDR_KEYBOARD_IMAGES_DOWN);
- source->AddResourcePath("images/forward.svg",
- IDR_KEYBOARD_IMAGES_FORWARD);
- source->AddResourcePath("images/fullscreen.svg",
- IDR_KEYBOARD_IMAGES_FULLSCREEN);
- source->AddResourcePath("images/left.svg",
- IDR_KEYBOARD_IMAGES_LEFT);
- source->AddResourcePath("images/microphone.svg",
- IDR_KEYBOARD_IMAGES_MICROPHONE);
- source->AddResourcePath("images/microphone-green.svg",
- IDR_KEYBOARD_IMAGES_MICROPHONE_GREEN);
- source->AddResourcePath("images/mute.svg",
- IDR_KEYBOARD_IMAGES_MUTE);
- source->AddResourcePath("images/reload.svg",
- IDR_KEYBOARD_IMAGES_RELOAD);
- source->AddResourcePath("images/right.svg",
- IDR_KEYBOARD_IMAGES_RIGHT);
- source->AddResourcePath("images/search.svg",
- IDR_KEYBOARD_IMAGES_SEARCH);
- source->AddResourcePath("images/shutdown.svg",
- IDR_KEYBOARD_IMAGES_SHUTDOWN);
- source->AddResourcePath("images/up.svg",
- IDR_KEYBOARD_IMAGES_UP);
- source->AddResourcePath("images/volume-down.svg",
- IDR_KEYBOARD_IMAGES_VOLUME_DOWN);
- source->AddResourcePath("images/volume-up.svg",
- IDR_KEYBOARD_IMAGES_VOLUME_UP);
- source->AddResourcePath("layouts/latin-accents.js",
- IDR_KEYBOARD_LAYOUTS_LATIN_ACCENTS);
- source->AddResourcePath("layouts/numeric.html", IDR_KEYBOARD_LAYOUTS_NUMERIC);
- source->AddResourcePath("layouts/system-qwerty.html",
- IDR_KEYBOARD_LAYOUTS_SYSTEM_QWERTY);
- source->AddResourcePath("main.js", IDR_KEYBOARD_MAIN_JS);
- source->AddResourcePath("polymer_loader.js", IDR_KEYBOARD_POLYMER_LOADER);
- source->AddResourcePath("voice_input.js", IDR_KEYBOARD_VOICE_INPUT_JS);
-
- // These files are specific to the WebUI version
- source->AddResourcePath("api_adapter.js", IDR_KEYBOARD_WEBUI_API_ADAPTER_JS);
- source->AddResourcePath("constants.js", IDR_KEYBOARD_WEBUI_CONSTANTS_JS);
- source->AddResourcePath("layouts/qwerty.html", IDR_KEYBOARD_WEBUI_QWERTY);
- source->AddResourcePath("main.css", IDR_KEYBOARD_WEBUI_MAIN_CSS);
-
- return source;
-}
-
-} // namespace
-
-namespace keyboard {
-
-KeyboardUIController::KeyboardUIController(content::WebUI* web_ui)
- : WebUIController(web_ui) {
- content::BrowserContext* browser_context =
- web_ui->GetWebContents()->GetBrowserContext();
- web_ui->AddMessageHandler(new KeyboardUIHandler());
- content::WebUIDataSource::Add(
- browser_context,
- CreateKeyboardUIDataSource());
-}
-
-KeyboardUIController::~KeyboardUIController() {}
-
-} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_ui_controller.h b/chromium/ui/keyboard/keyboard_ui_controller.h
deleted file mode 100644
index b06ec26c8e2..00000000000
--- a/chromium/ui/keyboard/keyboard_ui_controller.h
+++ /dev/null
@@ -1,29 +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_UI_CONTROLLER_H_
-#define UI_KEYBOARD_KEYBOARD_UI_CONTROLLER_H_
-
-#include "content/public/browser/web_ui_controller.h"
-#include "ui/keyboard/keyboard_export.h"
-
-namespace content {
-class WebUI;
-};
-
-namespace keyboard {
-
-// WebUIController for chrome://keyboard/.
-class KEYBOARD_EXPORT KeyboardUIController : public content::WebUIController {
- public:
- explicit KeyboardUIController(content::WebUI* web_ui);
- virtual ~KeyboardUIController();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(KeyboardUIController);
-};
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_KEYBOARD_UI_CONTROLLER_H_
diff --git a/chromium/ui/keyboard/keyboard_ui_handler.cc b/chromium/ui/keyboard/keyboard_ui_handler.cc
deleted file mode 100644
index 780e0be4aaf..00000000000
--- a/chromium/ui/keyboard/keyboard_ui_handler.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/keyboard/keyboard_ui_handler.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/browser/web_ui.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/keyboard/keyboard_controller.h"
-#include "ui/keyboard/keyboard_util.h"
-
-namespace keyboard {
-
-KeyboardUIHandler::KeyboardUIHandler() {
-}
-
-KeyboardUIHandler::~KeyboardUIHandler() {
-}
-
-void KeyboardUIHandler::RegisterMessages() {
- web_ui()->RegisterMessageCallback(
- "insertText",
- base::Bind(&KeyboardUIHandler::HandleInsertTextMessage,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "getInputContext",
- base::Bind(&KeyboardUIHandler::HandleGetInputContextMessage,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "sendKeyEvent",
- base::Bind(&KeyboardUIHandler::HandleSendKeyEventMessage,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "hideKeyboard",
- base::Bind(&KeyboardUIHandler::HandleHideKeyboard,
- base::Unretained(this)));
-}
-
-void KeyboardUIHandler::HandleInsertTextMessage(const base::ListValue* args) {
- string16 text;
- if (!args->GetString(0, &text)) {
- LOG(ERROR) << "insertText failed: bad argument";
- return;
- }
-
- aura::Window* root_window =
- web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow();
- if (!root_window) {
- LOG(ERROR) << "insertText failed: no root window";
- return;
- }
-
- if (!keyboard::InsertText(text, root_window))
- LOG(ERROR) << "insertText failed";
-}
-
-void KeyboardUIHandler::HandleGetInputContextMessage(
- const base::ListValue* args) {
- int request_id;
- if (!args->GetInteger(0, &request_id)) {
- LOG(ERROR) << "getInputContext failed: bad argument";
- return;
- }
- base::DictionaryValue results;
- results.SetInteger("requestId", request_id);
-
- aura::Window* root_window =
- web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow();
- if (!root_window) {
- LOG(ERROR) << "getInputContext failed: no root window";
- return;
- }
- ui::InputMethod* input_method =
- root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
- if (!input_method) {
- LOG(ERROR) << "getInputContext failed: no input method";
- return;
- }
-
- ui::TextInputClient* tic = input_method->GetTextInputClient();
- results.SetInteger("type",
- tic ? tic->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE);
-
- web_ui()->CallJavascriptFunction("GetInputContextCallback",
- results);
-}
-
-void KeyboardUIHandler::HandleSendKeyEventMessage(
- const base::ListValue* args) {
- const base::DictionaryValue* params = NULL;
- std::string type;
- int char_value;
- int key_code;
- std::string key_name;
- int modifiers;
-
- if (!args->GetDictionary(0, &params) ||
- !params->GetString("type", &type) ||
- !params->GetInteger("charValue", &char_value) ||
- !params->GetInteger("keyCode", &key_code) ||
- !params->GetString("keyName", &key_name) ||
- !params->GetInteger("modifiers", &modifiers)) {
- LOG(ERROR) << "SendKeyEvent failed: bad argument";
- return;
- }
-
- aura::WindowEventDispatcher* dispatcher =
- web_ui()->GetWebContents()->GetView()->GetNativeView()->GetDispatcher();
- if (!dispatcher) {
- LOG(ERROR) << "sendKeyEvent failed: no dispatcher";
- return;
- }
-
- if (!keyboard::SendKeyEvent(type,
- char_value,
- key_code,
- key_name,
- modifiers,
- dispatcher)) {
- LOG(ERROR) << "sendKeyEvent failed";
- }
-}
-
-void KeyboardUIHandler::HandleHideKeyboard(const base::ListValue* args) {
- // TODO(stevet): Call into the keyboard controller to hide the keyboard
- // directly.
- NOTIMPLEMENTED();
- return;
-}
-
-} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_ui_handler.h b/chromium/ui/keyboard/keyboard_ui_handler.h
deleted file mode 100644
index 3c14f7473e5..00000000000
--- a/chromium/ui/keyboard/keyboard_ui_handler.h
+++ /dev/null
@@ -1,45 +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_UI_HANDLER_H_
-#define UI_KEYBOARD_KEYBOARD_UI_HANDLER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace keyboard {
-
-// The WebUI handler for chrome://keyboard. Inserts text into the currently
-// focused TextInputClient.
-class KeyboardUIHandler : public content::WebUIMessageHandler {
- public:
- KeyboardUIHandler();
- virtual ~KeyboardUIHandler();
-
- private:
- // |content::WebUIMessageHandler| implementation:
- virtual void RegisterMessages() OVERRIDE;
-
- // Callback for the "insertText" message.
- void HandleInsertTextMessage(const base::ListValue* args);
-
- // Callback for the "getInputContext" message. The first element in
- // |args| should be an integer representing request ID.
- void HandleGetInputContextMessage(const base::ListValue* args);
-
- // Callback for the "sendKeyEvent" message. The first element in |args| is a
- // dictionary containing an event type, the character being pressed or
- // released, a virtual key code, and the state of the shift key.
- void HandleSendKeyEventMessage(const base::ListValue* args);
-
- // Callback for the "hideKeyboard" message.
- void HandleHideKeyboard(const base::ListValue* args);
-
- DISALLOW_COPY_AND_ASSIGN(KeyboardUIHandler);
-};
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_KEYBOARD_UI_HANDLER_H_
diff --git a/chromium/ui/keyboard/keyboard_util.cc b/chromium/ui/keyboard/keyboard_util.cc
index bdb049df32c..de9e2e4e1d7 100644
--- a/chromium/ui/keyboard/keyboard_util.cc
+++ b/chromium/ui/keyboard/keyboard_util.cc
@@ -14,10 +14,12 @@
#include "grit/keyboard_resources.h"
#include "grit/keyboard_resources_map.h"
#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event_processor.h"
#include "ui/keyboard/keyboard_switches.h"
+#include "url/gurl.h"
namespace {
@@ -25,24 +27,91 @@ const char kKeyDown[] ="keydown";
const char kKeyUp[] = "keyup";
void SendProcessKeyEvent(ui::EventType type,
- aura::WindowEventDispatcher* dispatcher) {
- ui::TranslatedKeyEvent event(type == ui::ET_KEY_PRESSED,
- ui::VKEY_PROCESSKEY,
- ui::EF_NONE);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
+ aura::WindowTreeHost* host) {
+ ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::EF_NONE, false);
+ event.SetTranslated(true);
+ ui::EventDispatchDetails details =
+ host->event_processor()->OnEventFromSource(&event);
+ CHECK(!details.dispatcher_destroyed);
}
base::LazyInstance<base::Time> g_keyboard_load_time_start =
LAZY_INSTANCE_INITIALIZER;
+bool g_accessibility_keyboard_enabled = false;
+
+base::LazyInstance<GURL> g_override_content_url = LAZY_INSTANCE_INITIALIZER;
+
+bool g_touch_keyboard_enabled = false;
+
+keyboard::KeyboardOverscrolOverride g_keyboard_overscroll_override =
+ keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE;
+
+keyboard::KeyboardShowOverride g_keyboard_show_override =
+ keyboard::KEYBOARD_SHOW_OVERRIDE_NONE;
+
} // namespace
namespace keyboard {
+gfx::Rect DefaultKeyboardBoundsFromWindowBounds(
+ const gfx::Rect& window_bounds) {
+ // Initialize default keyboard height to 0. The keyboard window height should
+ // only be set by window.resizeTo in virtual keyboard web contents. Otherwise,
+ // the default height may conflict with the new height and causing some
+ // strange animation issues. For keyboard usability experiments, a full screen
+ // virtual keyboard window is always preferred.
+ int keyboard_height =
+ keyboard::IsKeyboardUsabilityExperimentEnabled() ?
+ window_bounds.height() : 0;
+
+ return KeyboardBoundsFromWindowBounds(window_bounds, keyboard_height);
+}
+
+gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds,
+ int keyboard_height) {
+ return gfx::Rect(
+ window_bounds.x(),
+ window_bounds.bottom() - keyboard_height,
+ window_bounds.width(),
+ keyboard_height);
+}
+
+void SetAccessibilityKeyboardEnabled(bool enabled) {
+ g_accessibility_keyboard_enabled = enabled;
+}
+
+bool GetAccessibilityKeyboardEnabled() {
+ return g_accessibility_keyboard_enabled;
+}
+
+void SetTouchKeyboardEnabled(bool enabled) {
+ g_touch_keyboard_enabled = enabled;
+}
+
+bool GetTouchKeyboardEnabled() {
+ return g_touch_keyboard_enabled;
+}
+
+std::string GetKeyboardLayout() {
+ // TODO(bshe): layout string is currently hard coded. We should use more
+ // standard keyboard layouts.
+ return GetAccessibilityKeyboardEnabled() ? "system-qwerty" : "qwerty";
+}
+
bool IsKeyboardEnabled() {
+ // Accessibility setting prioritized over policy setting.
+ if (g_accessibility_keyboard_enabled)
+ return true;
+ // Policy strictly disables showing a virtual keyboard.
+ if (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED)
+ return false;
+ // Check if any of the flags are enabled.
return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableVirtualKeyboard) ||
- IsKeyboardUsabilityExperimentEnabled();
+ switches::kEnableVirtualKeyboard) ||
+ IsKeyboardUsabilityExperimentEnabled() ||
+ g_touch_keyboard_enabled ||
+ (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
}
bool IsKeyboardUsabilityExperimentEnabled() {
@@ -50,6 +119,54 @@ bool IsKeyboardUsabilityExperimentEnabled() {
switches::kKeyboardUsabilityExperiment);
}
+bool IsKeyboardOverscrollEnabled() {
+ if (!IsKeyboardEnabled())
+ return false;
+
+ // Users of the accessibility on-screen keyboard are likely to be using mouse
+ // input, which may interfere with overscrolling.
+ if (g_accessibility_keyboard_enabled)
+ return false;
+
+ // If overscroll enabled override is set, use it instead. Currently
+ // login / out-of-box disable keyboard overscroll. http://crbug.com/363635
+ if (g_keyboard_overscroll_override != KEYBOARD_OVERSCROLL_OVERRIDE_NONE) {
+ return g_keyboard_overscroll_override ==
+ KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED;
+ }
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableVirtualKeyboardOverscroll)) {
+ return false;
+ }
+ return true;
+}
+
+void SetKeyboardOverscrollOverride(KeyboardOverscrolOverride override) {
+ g_keyboard_overscroll_override = override;
+}
+
+void SetKeyboardShowOverride(KeyboardShowOverride override) {
+ g_keyboard_show_override = override;
+}
+
+bool IsInputViewEnabled() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableInputView))
+ return true;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableInputView))
+ return false;
+ // Default value if no command line flags specified.
+ return true;
+}
+
+bool IsExperimentalInputViewEnabled() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalInputViewFeatures)) {
+ return true;
+ }
+ return false;
+}
+
bool InsertText(const base::string16& text, aura::Window* root_window) {
if (!root_window)
return false;
@@ -74,8 +191,8 @@ bool InsertText(const base::string16& text, aura::Window* root_window) {
// ui::TextInputClient from that (see above in InsertText()).
bool MoveCursor(int swipe_direction,
int modifier_flags,
- aura::WindowEventDispatcher* dispatcher) {
- if (!dispatcher)
+ aura::WindowTreeHost* host) {
+ if (!host)
return false;
ui::KeyboardCode codex = ui::VKEY_UNKNOWN;
ui::KeyboardCode codey = ui::VKEY_UNKNOWN;
@@ -92,17 +209,23 @@ bool MoveCursor(int swipe_direction,
// First deal with the x movement.
if (codex != ui::VKEY_UNKNOWN) {
ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codex, modifier_flags, 0);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
+ ui::EventDispatchDetails details =
+ host->event_processor()->OnEventFromSource(&press_event);
+ CHECK(!details.dispatcher_destroyed);
ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codex, modifier_flags, 0);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
+ details = host->event_processor()->OnEventFromSource(&release_event);
+ CHECK(!details.dispatcher_destroyed);
}
// Then deal with the y movement.
if (codey != ui::VKEY_UNKNOWN) {
ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codey, modifier_flags, 0);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event);
+ ui::EventDispatchDetails details =
+ host->event_processor()->OnEventFromSource(&press_event);
+ CHECK(!details.dispatcher_destroyed);
ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codey, modifier_flags, 0);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event);
+ details = host->event_processor()->OnEventFromSource(&release_event);
+ CHECK(!details.dispatcher_destroyed);
}
return true;
}
@@ -112,7 +235,7 @@ bool SendKeyEvent(const std::string type,
int key_code,
std::string key_name,
int modifiers,
- aura::WindowEventDispatcher* dispatcher) {
+ aura::WindowTreeHost* host) {
ui::EventType event_type = ui::ET_UNKNOWN;
if (type == kKeyDown)
event_type = ui::ET_KEY_PRESSED;
@@ -127,16 +250,16 @@ bool SendKeyEvent(const std::string type,
// Handling of special printable characters (e.g. accented characters) for
// which there is no key code.
if (event_type == ui::ET_KEY_RELEASED) {
- ui::InputMethod* input_method = dispatcher->window()->GetProperty(
+ ui::InputMethod* input_method = host->window()->GetProperty(
aura::client::kRootWindowInputMethodKey);
if (!input_method)
return false;
ui::TextInputClient* tic = input_method->GetTextInputClient();
- SendProcessKeyEvent(ui::ET_KEY_PRESSED, dispatcher);
+ SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
tic->InsertChar(static_cast<uint16>(key_value), ui::EF_NONE);
- SendProcessKeyEvent(ui::ET_KEY_RELEASED, dispatcher);
+ SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
}
} else {
if (event_type == ui::ET_KEY_RELEASED) {
@@ -155,7 +278,9 @@ bool SendKeyEvent(const std::string type,
}
ui::KeyEvent event(event_type, code, key_name, modifiers, false);
- dispatcher->AsRootWindowHostDelegate()->OnHostKeyEvent(&event);
+ ui::EventDispatchDetails details =
+ host->event_processor()->OnEventFromSource(&event);
+ CHECK(!details.dispatcher_destroyed);
}
return true;
}
@@ -166,6 +291,11 @@ const void MarkKeyboardLoadStarted() {
}
const void MarkKeyboardLoadFinished() {
+ // Possible to get a load finished without a start if navigating directly to
+ // chrome://keyboard.
+ if (!g_keyboard_load_time_start.Get().ToInternalValue())
+ return;
+
// It should not be possible to finish loading the keyboard without starting
// to load it first.
DCHECK(g_keyboard_load_time_start.Get().ToInternalValue());
@@ -185,31 +315,9 @@ const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
// necessary to have a custom path for the extension path, so the resource
// map cannot be used directly.
static const GritResourceMap kKeyboardResources[] = {
- {"keyboard/api_adapter.js", IDR_KEYBOARD_API_ADAPTER_JS},
- {"keyboard/constants.js", IDR_KEYBOARD_CONSTANTS_JS},
- {"keyboard/elements/kb-altkey.html", IDR_KEYBOARD_ELEMENTS_ALTKEY},
- {"keyboard/elements/kb-altkey-container.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY_CONTAINER},
- {"keyboard/elements/kb-altkey-data.html",
- IDR_KEYBOARD_ELEMENTS_ALTKEY_DATA},
- {"keyboard/elements/kb-altkey-set.html", IDR_KEYBOARD_ELEMENTS_ALTKEY_SET},
- {"keyboard/elements/kb-key.html", IDR_KEYBOARD_ELEMENTS_KEY},
- {"keyboard/elements/kb-key-base.html", IDR_KEYBOARD_ELEMENTS_KEY_BASE},
- {"keyboard/elements/kb-key-codes.html", IDR_KEYBOARD_ELEMENTS_KEY_CODES},
- {"keyboard/elements/kb-key-import.html",
- IDR_KEYBOARD_ELEMENTS_KEY_IMPORT},
- {"keyboard/elements/kb-key-sequence.html",
- IDR_KEYBOARD_ELEMENTS_KEY_SEQUENCE},
- {"keyboard/elements/kb-keyboard.html", IDR_KEYBOARD_ELEMENTS_KEYBOARD},
- {"keyboard/elements/kb-keyset.html", IDR_KEYBOARD_ELEMENTS_KEYSET},
- {"keyboard/elements/kb-modifier-key.html",
- IDR_KEYBOARD_ELEMENTS_MODIFIER_KEY},
- {"keyboard/elements/kb-options-menu.html",
- IDR_KEYBOARD_ELEMENTS_OPTIONS_MENU},
- {"keyboard/elements/kb-row.html", IDR_KEYBOARD_ELEMENTS_ROW},
- {"keyboard/elements/kb-shift-key.html", IDR_KEYBOARD_ELEMENTS_SHIFT_KEY},
{"keyboard/layouts/function-key-row.html", IDR_KEYBOARD_FUNCTION_KEY_ROW},
{"keyboard/images/back.svg", IDR_KEYBOARD_IMAGES_BACK},
+ {"keyboard/images/backspace.png", IDR_KEYBOARD_IMAGES_BACKSPACE},
{"keyboard/images/brightness-down.svg",
IDR_KEYBOARD_IMAGES_BRIGHTNESS_DOWN},
{"keyboard/images/brightness-up.svg", IDR_KEYBOARD_IMAGES_BRIGHTNESS_UP},
@@ -217,6 +325,7 @@ const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
{"keyboard/images/down.svg", IDR_KEYBOARD_IMAGES_DOWN},
{"keyboard/images/forward.svg", IDR_KEYBOARD_IMAGES_FORWARD},
{"keyboard/images/fullscreen.svg", IDR_KEYBOARD_IMAGES_FULLSCREEN},
+ {"keyboard/images/hide-keyboard.png", IDR_KEYBOARD_IMAGES_HIDE_KEYBOARD},
{"keyboard/images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD},
{"keyboard/images/left.svg", IDR_KEYBOARD_IMAGES_LEFT},
{"keyboard/images/microphone.svg", IDR_KEYBOARD_IMAGES_MICROPHONE},
@@ -224,32 +333,47 @@ const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
IDR_KEYBOARD_IMAGES_MICROPHONE_GREEN},
{"keyboard/images/mute.svg", IDR_KEYBOARD_IMAGES_MUTE},
{"keyboard/images/reload.svg", IDR_KEYBOARD_IMAGES_RELOAD},
+ {"keyboard/images/return.png", IDR_KEYBOARD_IMAGES_RETURN},
{"keyboard/images/right.svg", IDR_KEYBOARD_IMAGES_RIGHT},
- {"keyboard/images/search.svg", IDR_KEYBOARD_IMAGES_SEARCH},
+ {"keyboard/images/search.png", IDR_KEYBOARD_IMAGES_SEARCH},
+ {"keyboard/images/shift.png", IDR_KEYBOARD_IMAGES_SHIFT},
{"keyboard/images/shutdown.svg", IDR_KEYBOARD_IMAGES_SHUTDOWN},
+ {"keyboard/images/tab.png", IDR_KEYBOARD_IMAGES_TAB},
{"keyboard/images/up.svg", IDR_KEYBOARD_IMAGES_UP},
{"keyboard/images/volume-down.svg", IDR_KEYBOARD_IMAGES_VOLUME_DOWN},
{"keyboard/images/volume-up.svg", IDR_KEYBOARD_IMAGES_VOLUME_UP},
{"keyboard/index.html", IDR_KEYBOARD_INDEX},
- {"keyboard/layouts/dvorak.html", IDR_KEYBOARD_LAYOUTS_DVORAK},
- {"keyboard/layouts/latin-accents.js", IDR_KEYBOARD_LAYOUTS_LATIN_ACCENTS},
+ {"keyboard/keyboard.js", IDR_KEYBOARD_JS},
{"keyboard/layouts/numeric.html", IDR_KEYBOARD_LAYOUTS_NUMERIC},
{"keyboard/layouts/qwerty.html", IDR_KEYBOARD_LAYOUTS_QWERTY},
- {"keyboard/layouts/symbol-altkeys.js",
- IDR_KEYBOARD_LAYOUTS_SYMBOL_ALTKEYS},
{"keyboard/layouts/system-qwerty.html", IDR_KEYBOARD_LAYOUTS_SYSTEM_QWERTY},
{"keyboard/layouts/spacebar-row.html", IDR_KEYBOARD_SPACEBAR_ROW},
- {"keyboard/main.js", IDR_KEYBOARD_MAIN_JS},
{"keyboard/manifest.json", IDR_KEYBOARD_MANIFEST},
{"keyboard/main.css", IDR_KEYBOARD_MAIN_CSS},
{"keyboard/polymer_loader.js", IDR_KEYBOARD_POLYMER_LOADER},
- {"keyboard/voice_input.js", IDR_KEYBOARD_VOICE_INPUT_JS},
+ {"keyboard/roboto_bold.ttf", IDR_KEYBOARD_ROBOTO_BOLD_TTF},
+ {"keyboard/sounds/keypress-delete.wav",
+ IDR_KEYBOARD_SOUNDS_KEYPRESS_DELETE},
+ {"keyboard/sounds/keypress-return.wav",
+ IDR_KEYBOARD_SOUNDS_KEYPRESS_RETURN},
+ {"keyboard/sounds/keypress-spacebar.wav",
+ IDR_KEYBOARD_SOUNDS_KEYPRESS_SPACEBAR},
+ {"keyboard/sounds/keypress-standard.wav",
+ IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD},
};
static const size_t kKeyboardResourcesSize = arraysize(kKeyboardResources);
*size = kKeyboardResourcesSize;
return kKeyboardResources;
}
+void SetOverrideContentUrl(const GURL& url) {
+ g_override_content_url.Get() = url;
+}
+
+const GURL& GetOverrideContentUrl() {
+ return g_override_content_url.Get();
+}
+
void LogKeyboardControlEvent(KeyboardControlEvent event) {
UMA_HISTOGRAM_ENUMERATION(
"VirtualKeyboard.KeyboardControlEvent",
diff --git a/chromium/ui/keyboard/keyboard_util.h b/chromium/ui/keyboard/keyboard_util.h
index 232127320b0..c2b31b8819d 100644
--- a/chromium/ui/keyboard/keyboard_util.h
+++ b/chromium/ui/keyboard/keyboard_util.h
@@ -14,6 +14,12 @@
struct GritResourceMap;
+namespace aura {
+class WindowTreeHost;
+}
+
+class GURL;
+
namespace keyboard {
// Enumeration of swipe directions.
@@ -32,12 +38,67 @@ enum KeyboardControlEvent {
KEYBOARD_CONTROL_MAX,
};
+// An enumeration of keyboard overscroll override value.
+enum KeyboardOverscrolOverride {
+ KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED = 0,
+ KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED,
+ KEYBOARD_OVERSCROLL_OVERRIDE_NONE,
+};
+
+// An enumeration of keyboard policy settings.
+enum KeyboardShowOverride {
+ KEYBOARD_SHOW_OVERRIDE_DISABLED = 0,
+ KEYBOARD_SHOW_OVERRIDE_ENABLED,
+ KEYBOARD_SHOW_OVERRIDE_NONE,
+};
+
+// Gets the default keyboard bounds from |window_bounds|.
+KEYBOARD_EXPORT gfx::Rect DefaultKeyboardBoundsFromWindowBounds(
+ const gfx::Rect& window_bounds);
+
+// Gets the caculated keyboard bounds from |window_bounds|. The keyboard height
+// is specified by |keyboard_height|.
+KEYBOARD_EXPORT gfx::Rect KeyboardBoundsFromWindowBounds(
+ const gfx::Rect& window_bounds, int keyboard_height);
+
+// Sets the state of the a11y onscreen keyboard.
+KEYBOARD_EXPORT void SetAccessibilityKeyboardEnabled(bool enabled);
+
+// Gets the state of the a11y onscreen keyboard.
+KEYBOARD_EXPORT bool GetAccessibilityKeyboardEnabled();
+
+// Sets the state of the touch onscreen keyboard.
+KEYBOARD_EXPORT void SetTouchKeyboardEnabled(bool enabled);
+
+// Gets the state of the touch onscreen keyboard.
+KEYBOARD_EXPORT bool GetTouchKeyboardEnabled();
+
+// Gets the default keyboard layout.
+KEYBOARD_EXPORT std::string GetKeyboardLayout();
+
// Returns true if the virtual keyboard is enabled.
KEYBOARD_EXPORT bool IsKeyboardEnabled();
// Returns true if the keyboard usability test is enabled.
KEYBOARD_EXPORT bool IsKeyboardUsabilityExperimentEnabled();
+// Returns true if keyboard overscroll mode is enabled.
+KEYBOARD_EXPORT bool IsKeyboardOverscrollEnabled();
+
+// Sets temporary keyboard overscroll override.
+KEYBOARD_EXPORT void SetKeyboardOverscrollOverride(
+ KeyboardOverscrolOverride override);
+
+// Sets policy override on whether to show the keyboard.
+KEYBOARD_EXPORT void SetKeyboardShowOverride(KeyboardShowOverride override);
+
+// Returns true if an IME extension can specify a custom input view for the
+// virtual keyboard window.
+KEYBOARD_EXPORT bool IsInputViewEnabled();
+
+// Returns true if experimental features are enabled for IME input-views.
+KEYBOARD_EXPORT bool IsExperimentalInputViewEnabled();
+
// Insert |text| into the active TextInputClient associated with |root_window|,
// if there is one. Returns true if |text| was successfully inserted. Note
// that this may convert |text| into ui::KeyEvents for injection in some
@@ -49,7 +110,7 @@ KEYBOARD_EXPORT bool InsertText(const base::string16& text,
// successfully moved according to |swipe_direction|.
KEYBOARD_EXPORT bool MoveCursor(int swipe_direction,
int modifier_flags,
- aura::WindowEventDispatcher* dispatcher);
+ aura::WindowTreeHost* host);
// Sends a fabricated key event, where |type| is the event type, |key_value|
// is the unicode value of the character, |key_code| is the legacy key code
@@ -62,7 +123,7 @@ KEYBOARD_EXPORT bool SendKeyEvent(std::string type,
int key_code,
std::string key_name,
int modifiers,
- aura::WindowEventDispatcher* dispatcher);
+ aura::WindowTreeHost* host);
// Marks that the keyboard load has started. This is used to measure the time it
// takes to fully load the keyboard. This should be called before
@@ -78,6 +139,13 @@ KEYBOARD_EXPORT const void MarkKeyboardLoadFinished();
KEYBOARD_EXPORT const GritResourceMap* GetKeyboardExtensionResources(
size_t* size);
+// 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();
+
// Logs the keyboard control event as a UMA stat.
void LogKeyboardControlEvent(KeyboardControlEvent event);
diff --git a/chromium/ui/keyboard/resources/api_adapter.js b/chromium/ui/keyboard/resources/api_adapter.js
index 934a7600463..e169b551392 100644
--- a/chromium/ui/keyboard/resources/api_adapter.js
+++ b/chromium/ui/keyboard/resources/api_adapter.js
@@ -30,7 +30,32 @@ function sendKeyEvent(event) {
chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError);
}
+(function(scope) {
+ var keyboardLocked_ = false;
+
+ /**
+ * Check the lock state of virtual keyboard.
+ * @return {boolean} True if virtual keyboard is locked.
+ */
+ function keyboardLocked() {
+ return keyboardLocked_;
+ }
+
+ /**
+ * Lock or unlock virtual keyboard.
+ * @param {boolean} lock Whether or not to lock the virtual keyboard.
+ */
+ function lockKeyboard(lock) {
+ keyboardLocked_ = lock;
+ chrome.virtualKeyboardPrivate.lockKeyboard(lock);
+ }
+
+ scope.keyboardLocked = keyboardLocked;
+ scope.lockKeyboard = lockKeyboard;
+})(this);
+
function hideKeyboard() {
+ lockKeyboard(false);
chrome.virtualKeyboardPrivate.hideKeyboard(logIfError);
}
@@ -38,6 +63,12 @@ function keyboardLoaded() {
chrome.virtualKeyboardPrivate.keyboardLoaded(logIfError);
}
+function getKeyboardConfig(callback) {
+ chrome.virtualKeyboardPrivate.getKeyboardConfig(function (config) {
+ callback(config);
+ });
+}
+
chrome.virtualKeyboardPrivate.onTextInputBoxFocused.addListener(
function (inputContext) {
$('keyboard').inputTypeValue = inputContext.type;
diff --git a/chromium/ui/keyboard/resources/constants.js b/chromium/ui/keyboard/resources/constants.js
index e80507ee7c7..b4401895ec9 100644
--- a/chromium/ui/keyboard/resources/constants.js
+++ b/chromium/ui/keyboard/resources/constants.js
@@ -2,36 +2,112 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+var RowAlignment = {
+ STRETCH: "stretch",
+ LEFT: "left",
+ RIGHT: "right",
+ CENTER: "center",
+}
+
/**
- * Aspect ratio of keyboard.
+ * Ratio of key height and font size.
* @type {number}
*/
-var ASPECT_RATIO = 4.5;
+var FONT_SIZE_RATIO = 2.5;
/**
- * Ratio of key height and font size.
- * @type {number}
+ * @type {enum}
+ * Possible layout alignments.
*/
-var FONT_SIZE_RATIO = 3;
+var LayoutAlignment = {
+ CENTER: "center",
+ STRETCH: "stretch",
+};
/**
- * The number of rows in each keyset.
- * @type {number}
+ * The enumerations of key sounds.
+ * @const
+ * @type {enum}
*/
-// TODO(bshe): The number of rows should equal to the number of kb-row elements
-// in kb-keyset. Remove this variable once figure out how to calculate the
-// number from keysets.
-var ROW_LENGTH = 4;
+var Sound = {
+ NONE: "none",
+ DEFAULT: "keypress-standard",
+};
/**
* The enumeration of swipe directions.
* @const
* @type {Enum}
*/
-var SWIPE_DIRECTION = {
+var SwipeDirection = {
RIGHT: 0x1,
LEFT: 0x2,
UP: 0x4,
DOWN: 0x8
};
+/**
+ * The ratio between the width and height of the key when in portrait mode.
+ * @type {number}
+ */
+var KEY_ASPECT_RATIO_PORTRAIT = 1;
+
+/**
+ * The ratio between the width and height of the key when in landscape mode.
+ * @type {number}
+ */
+var KEY_ASPECT_RATIO_LANDSCAPE = 1.46;
+
+/**
+ * The ratio between the height and width of the compact keyboard.
+ * @type {number}
+ */
+var DEFAULT_KEYBOARD_ASPECT_RATIO = 0.41;
+
+/**
+ * The default weight of a key.
+ * @type {number}
+ */
+var DEFAULT_KEY_WEIGHT = 100;
+
+/**
+ * The default volume for keyboard sounds.
+ * @type {number}
+ */
+var DEFAULT_VOLUME = 0.2;
+
+/**
+ * The top padding on each key.
+ * @type {number}
+ */
+// TODO(rsadam): Remove this variable once figure out how to calculate this
+// number before the key is rendered.
+var KEY_PADDING_TOP = 1;
+var KEY_PADDING_BOTTOM = 1;
+
+/**
+ * The greatest distance between a key and a touch point for a PointerEvent
+ * to be processed.
+ * @type {number}
+ */
+var MAX_TOUCH_FUZZ_DISTANCE = 20;
+
+/**
+ * The maximum number of extra pixels before a resize is triggered.
+ * @type {number}
+ */
+var RESIZE_THRESHOLD = 20;
+
+/**
+ * The size of the pool to use for playing audio sounds on key press. This is to
+ * enable the same sound to be overlayed, for example, when a repeat key is
+ * pressed.
+ * @type {number}
+ */
+var SOUND_POOL_SIZE = 10;
+
+/**
+ * Whether or not to enable sounds on key press.
+ * @type {boolean}
+ */
+var SOUND_ENABLED = false;
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-container.html b/chromium/ui/keyboard/resources/elements/kb-altkey-container.html
index 552c70fedb0..8ed1dc58862 100644
--- a/chromium/ui/keyboard/resources/elements/kb-altkey-container.html
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-container.html
@@ -5,12 +5,11 @@
-->
<polymer-element name="kb-altkey-container" attributes="keyset"
- on-pointerup="{{up}}">
+ on-pointerup="{{up}}" on-pointerout="{{out}}">
<template>
<style>
:host {
-webkit-box-flex: 1;
- background-color: rgba(0, 0, 0, 0.6);
bottom: 0;
left: 0;
position: absolute;
@@ -20,30 +19,4 @@
</style>
<content select="#{{keyset}}"></content>
</template>
- <script>
- Polymer('kb-altkey-container', {
- resetActiveElement: function() {
- var activeAccentKeySet = this.querySelector('#' + this.keyset);
- var offset = activeAccentKeySet.offset;
- var element = activeAccentKeySet.firstElementChild;
- while (offset) {
- element = element.nextElementSibling;
- offset--;
- }
- element.classList.add('active');
- },
- up: function(detail) {
- this.hidden = true;
- this.resetActiveElement();
- this.keyset = null;
- },
-
- hiddenChanged: function() {
- this.fire('stateChange', {
- state: 'candidatePopupVisibility',
- value: !!this.hidden
- });
- },
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-container.js b/chromium/ui/keyboard/resources/elements/kb-altkey-container.js
new file mode 100644
index 00000000000..a184348a4a0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-container.js
@@ -0,0 +1,35 @@
+// 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.
+
+Polymer('kb-altkey-container', {
+ resetActiveElement: function() {
+ var activeAccentKeySet = this.querySelector('#' + this.keyset);
+ var offset = activeAccentKeySet.offset;
+ var element = activeAccentKeySet.firstElementChild;
+ while (offset) {
+ element = element.nextElementSibling;
+ offset--;
+ }
+ element.classList.add('active');
+ },
+ up: function(detail) {
+ this.hidden = true;
+ this.resetActiveElement();
+ this.keyset = null;
+ },
+ out: function(event) {
+ // Check if touch is outside container boundaries.
+ if(!(this.compareDocumentPosition(event.relatedTarget)
+ & Node.DOCUMENT_POSITION_CONTAINED_BY)) {
+ this.hidden = true;
+ }
+ },
+
+ hiddenChanged: function() {
+ this.fire('stateChange', {
+ state: 'candidatePopupVisibility',
+ value: !!this.hidden
+ });
+ },
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-data.html b/chromium/ui/keyboard/resources/elements/kb-altkey-data.html
index 67f793ad4b1..63b8fadd48c 100644
--- a/chromium/ui/keyboard/resources/elements/kb-altkey-data.html
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-data.html
@@ -5,128 +5,4 @@
-->
<polymer-element name="kb-altkey-data" attributes="char list">
-<script>
- (function() {
- var altKeys = {};
- var idMap = {};
-
- /**
- * Creates a unique identifier based on the key provided.
- * This identifier is of the form 'idHASH' where HASH is
- * the concatenation of the keycodes of every character in the string.
- * @param {string} key Key for which we want an identifier.
- * @return {string} The unique id for key.
- */
- function createId(key) {
- var hash = key.split('').map(
- // Returns the key code for the character.
- function(character) {
- return character.charCodeAt(0);
- }
- ).join('');
- return 'id' + hash;
- }
-
- Polymer('kb-altkey-data', {
-
- /**
- * Retrieves a list of alternative keys to display on a long-press.
- * @param {string} char The base character.
- * @param {boolean=} opt_force If true, force the creation of a list
- * even if empty. Used when constructing a set of alternates for keys
- * with hintTexts.
- * @return {?Object.{id: string, list: string}}
- */
- getAltkeys: function(char, opt_force) {
- var id = idMap[char];
- if (id) {
- return {
- 'id': id,
- 'keys': altKeys[id]
- };
- }
- if (opt_force) {
- return {
- 'id': createId(char),
- 'keys': []
- };
- }
- },
-
- /**
- * Registers lists of alternative keys displayed on a long-press.
- * @param {Object.<string, Array.<string>>} data Mapping of characters to
- * lists of alternatives.
- */
- registerAltkeys: function(data) {
- for (var key in data) {
- var id = idMap[key];
- if (!id)
- idMap[key] = id = createId(key);
- altKeys[id] = data[key];
- }
- },
-
- /**
- * Creates a list of alternate candidates to display in a popup on a
- * long-press.
- * @param {string} char The base character.
- * @param {number} maxLeftOffset Limits the number of candidates
- * displayed to the left of the base character to prevent running
- * past the left edge of the keyboard.
- * @param {number} maxRightOffset Limits the number of candidates
- * displayed to the right of the base character to prvent running
- * past the right edge of the keyboard.
- * @param {string=} opt_additionalKeys Optional list of additional keys
- * to include in the candidates list.
- */
- createAltkeySet: function(char,
- maxLeftOffset,
- maxRightOffset,
- opt_additionalKeys) {
- var altKeys = this.getAltkeys(char, true /* forced */);
- if (altKeys) {
- var list = altKeys.keys;
- if (opt_additionalKeys)
- list = opt_additionalKeys.split('').concat(list);
- list = [char].concat(list);
-
- var set = document.createElement('kb-altkey-set');
- // Candiates are approximately in decreasing order of usage, and are
- // arranged in a single row in the popup display. To reduce the
- // expected length of the drag gesture for selecting a candidate,
- // more likely candidates are placed in the center of the popup,
- // which is achieved by alternately appending and prepending
- // candiates in the alternatives popup.
- var prepend = false;
- var leftOffset = 0;
- var rightOffset = 0;
- for (var i = 0; i < list.length; i++) {
- var key = document.createElement('kb-altkey');
- key.textContent = list[i];
- if (prepend) {
- set.insertBefore(key, set.firstChild);
- leftOffset++;
- } else {
- set.appendChild(key);
- rightOffset++;
- }
- prepend = !prepend;
- // Verify that there is room remaining for an additional character.
- if (leftOffset == maxLeftOffset && rightOffset == maxRightOffset)
- break;
- if (leftOffset == maxLeftOffset)
- prepend = false;
- else if (rightOffset == maxRightOffset)
- prepend = true;
- }
- set.id = altKeys.id;
- set.offset = leftOffset;
- return set;
- }
- },
-
- });
- })();
-</script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-data.js b/chromium/ui/keyboard/resources/elements/kb-altkey-data.js
new file mode 100644
index 00000000000..e45cb319a59
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-data.js
@@ -0,0 +1,126 @@
+// 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.
+
+(function() {
+ var altKeys = {};
+ var idMap = {};
+
+ /**
+ * Creates a unique identifier based on the key provided.
+ * This identifier is of the form 'idHASH' where HASH is
+ * the concatenation of the keycodes of every character in the string.
+ * @param {string} key Key for which we want an identifier.
+ * @return {string} The unique id for key.
+ */
+ function createId(key) {
+ var hash = key.split('').map(
+ // Returns the key code for the character.
+ function(character) {
+ return character.charCodeAt(0);
+ }
+ ).join('');
+ return 'id' + hash;
+ }
+
+ Polymer('kb-altkey-data', {
+
+ /**
+ * Retrieves a list of alternative keys to display on a long-press.
+ * @param {string} char The base character.
+ * @param {boolean=} opt_force If true, force the creation of a list
+ * even if empty. Used when constructing a set of alternates for keys
+ * with hintTexts.
+ * @return {?Object.{id: string, list: string}}
+ */
+ getAltkeys: function(char, opt_force) {
+ var id = idMap[char];
+ if (id) {
+ return {
+ 'id': id,
+ 'keys': altKeys[id]
+ };
+ }
+ if (opt_force) {
+ return {
+ 'id': createId(char),
+ 'keys': []
+ };
+ }
+ },
+
+ /**
+ * Registers lists of alternative keys displayed on a long-press.
+ * @param {Object.<string, Array.<string>>} data Mapping of characters to
+ * lists of alternatives.
+ */
+ registerAltkeys: function(data) {
+ for (var key in data) {
+ var id = idMap[key];
+ if (!id)
+ idMap[key] = id = createId(key);
+ altKeys[id] = data[key];
+ }
+ },
+
+ /**
+ * Creates a list of alternate candidates to display in a popup on a
+ * long-press.
+ * @param {string} char The base character.
+ * @param {number} maxLeftOffset Limits the number of candidates
+ * displayed to the left of the base character to prevent running
+ * past the left edge of the keyboard.
+ * @param {number} maxRightOffset Limits the number of candidates
+ * displayed to the right of the base character to prvent running
+ * past the right edge of the keyboard.
+ * @param {string=} opt_additionalKeys Optional list of additional keys
+ * to include in the candidates list.
+ */
+ createAltkeySet: function(char,
+ maxLeftOffset,
+ maxRightOffset,
+ opt_additionalKeys) {
+ var altKeys = this.getAltkeys(char, true /* forced */);
+ if (altKeys) {
+ var list = altKeys.keys;
+ if (opt_additionalKeys)
+ list = opt_additionalKeys.split('').concat(list);
+ list = [char].concat(list);
+
+ var set = document.createElement('kb-altkey-set');
+ // Candiates are approximately in decreasing order of usage, and are
+ // arranged in a single row in the popup display. To reduce the
+ // expected length of the drag gesture for selecting a candidate,
+ // more likely candidates are placed in the center of the popup,
+ // which is achieved by alternately appending and prepending
+ // candiates in the alternatives popup.
+ var prepend = false;
+ var leftOffset = 0;
+ var rightOffset = 0;
+ for (var i = 0; i < list.length; i++) {
+ var key = document.createElement('kb-altkey');
+ key.textContent = list[i];
+ if (prepend) {
+ set.insertBefore(key, set.firstChild);
+ leftOffset++;
+ } else {
+ set.appendChild(key);
+ rightOffset++;
+ }
+ prepend = !prepend;
+ // Verify that there is room remaining for an additional character.
+ if (leftOffset == maxLeftOffset && rightOffset == maxRightOffset)
+ break;
+ if (leftOffset == maxLeftOffset)
+ prepend = false;
+ else if (rightOffset == maxRightOffset)
+ prepend = true;
+ }
+ set.id = altKeys.id;
+ set.offset = leftOffset;
+ return set;
+ }
+ },
+
+ });
+})();
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-set.html b/chromium/ui/keyboard/resources/elements/kb-altkey-set.html
index 85ca1b06afc..dd471792eea 100644
--- a/chromium/ui/keyboard/resources/elements/kb-altkey-set.html
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-set.html
@@ -4,11 +4,14 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-altkey-set" attributes="offset char">
+<polymer-element name="kb-altkey-set" attributes="offset char"
+ on-pointerout="{{out}}">
<template>
<style>
:host {
- background-color: #3b3b3e;
+ -webkit-box-shadow: 0 0 12px 5px rgba(204, 204, 204, 0.65),
+ 0 3px 4px 4px rgba(136, 136, 136, 0.65);
+ background-color: #ffffff;
border-radius: 2px;
display: -webkit-box;
text-align: center;
@@ -17,9 +20,4 @@
</style>
<content select="*"></content>
</template>
- <script>
- Polymer('kb-altkey-set', {
- offset: 0,
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey-set.js b/chromium/ui/keyboard/resources/elements/kb-altkey-set.js
new file mode 100644
index 00000000000..09e0ef720f0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey-set.js
@@ -0,0 +1,10 @@
+// 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.
+
+Polymer('kb-altkey-set', {
+ offset: 0,
+ out: function(e) {
+ e.stopPropagation();
+ }
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey.html b/chromium/ui/keyboard/resources/elements/kb-altkey.html
index 276ca5c1191..1d4cc4ed69e 100644
--- a/chromium/ui/keyboard/resources/elements/kb-altkey.html
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey.html
@@ -13,31 +13,32 @@
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
- border-left: 1px solid rgba(0, 0, 0, 0.15);
- border-top: 2px solid #4b4b4e;
display: -webkit-box;
position: relative;
}
- :host.active {
- background-color: #848490;
- border-top: 1px solid #848490;
+ :host(.active) {
+ background-color: #dddddd
}
- :host:first-child {
+ :host(:first-child) {
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
- :host:last-child {
+ :host(:not(:first-child)) .key{
+ border-left: solid 2px #dddddd;
+ }
+
+ :host(:last-child) {
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
- ::part(key) {
+ :host .key {
bottom: 0;
- color: #ffffff;
- font-family: 'Open Sans', 'Noto Sans UI', sans-serif;
+ color: #666666;
+ font-family: roboto-bold;
font-weight: 100;
height: 1.2em;
left: 0;
@@ -48,57 +49,8 @@
text-align: center;
}
</style>
- <div part="key">
+ <div class="key">
<content></content>
</div>
</template>
- <script>
- /**
- * Filter out mouse/touch movements internal to this node. When moving
- * inside a node, the event should be filter out.
- * @param {Node} node The accent key node which receives event.
- * @param {event} event A pointer move event.
- * @return {boolean} True if event is external to node.
- */
- function isRelevantEvent(node, event) {
- return !(node.compareDocumentPosition(event.relatedTarget)
- & Node.DOCUMENT_POSITION_CONTAINED_BY);
- };
- Polymer('kb-altkey', {
- over: function(event) {
- if (isRelevantEvent(this, event)) {
- // Dragging over an accent key is equivalent to pressing on the accent
- // key.
- this.fire('key-down', {});
- }
- },
-
- out: function(event) {
- if (isRelevantEvent(this, event)) {
- this.classList.remove('active');
- }
- },
-
- up: function(event) {
- var detail = {
- char: this.charValue
- };
- this.fire('key-up', detail);
- },
-
- // TODO(bshe): kb-altkey should extend from kb-key-base.
- autoRelease: function() {
- },
-
- /**
- * Character value associated with the key. Typically, the value is a
- * single character, but may be multi-character in cases like a ".com"
- * button.
- * @return {string}
- */
- get charValue() {
- return this.char || this.textContent;
- }
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-altkey.js b/chromium/ui/keyboard/resources/elements/kb-altkey.js
new file mode 100644
index 00000000000..ee70a5e1ada
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-altkey.js
@@ -0,0 +1,52 @@
+// 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.
+
+/**
+ * Filter out mouse/touch movements internal to this node. When moving
+ * inside a node, the event should be filter out.
+ * @param {Node} node The accent key node which receives event.
+ * @param {event} event A pointer move event.
+ * @return {boolean} True if event is external to node.
+ */
+ function isRelevantEvent(node, event) {
+ return !(node.compareDocumentPosition(event.relatedTarget)
+ & Node.DOCUMENT_POSITION_CONTAINED_BY);
+};
+Polymer('kb-altkey', {
+ over: function(event) {
+ if (isRelevantEvent(this, event)) {
+ // Dragging over an accent key is equivalent to pressing on the accent
+ // key.
+ this.fire('key-down', {});
+ }
+ },
+
+ out: function(event) {
+ if (isRelevantEvent(this, event)) {
+ this.classList.remove('active');
+ }
+ },
+
+ up: function(event) {
+ var detail = {
+ char: this.charValue
+ };
+ this.fire('key-up', detail);
+ },
+
+ // TODO(bshe): kb-altkey should extend from kb-key-base.
+ autoRelease: function() {
+ },
+
+ /**
+ * Character value associated with the key. Typically, the value is a
+ * single character, but may be multi-character in cases like a ".com"
+ * button.
+ * @return {string}
+ */
+ get charValue() {
+ return this.char || this.textContent;
+ }
+});
+
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-base.html b/chromium/ui/keyboard/resources/elements/kb-key-base.html
index 21d25149c3b..c1649b862c0 100644
--- a/chromium/ui/keyboard/resources/elements/kb-key-base.html
+++ b/chromium/ui/keyboard/resources/elements/kb-key-base.html
@@ -4,233 +4,6 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-key-base"
- on-pointerdown="{{down}}" on-pointerup="{{up}}" on-pointerout="{{out}}"
- attributes="char invert repeat hintText toKeyset toLayout">
- <script>
- /**
- * The long-press delay in milliseconds before long-press handler is
- * invoked.
- * @const
- * @type {number}
- */
- var LONGPRESS_DELAY_MSEC = 500;
-
- /**
- * The maximum number of elements in one keyset rule.
- * @const
- * @type {number}
- */
- var MAXIMUM_NUM_OF_RULE_ELEMENTS = 3;
-
- /**
- * The minumum number of elements in one keyset rule.
- * @const
- * @type {number}
- */
- var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
-
- /**
- * The index of event type element in the splitted keyset rule.
- * @const
- * @type {number}
- */
- var EVENT_TYPE = 0;
-
- /**
- * The index of toKeyset element in the splitted keyset rule.
- * @const
- * @type {number}
- */
- var TO_KEYSET = 1;
-
- /**
- * The index of nextKeyset element in the splitted keyset rule.
- * @const
- * @type {number}
- */
- var NEXT_KEYSET = 2;
-
- /**
- * The index offset of toKeyset and nextKeyset elements in splitted keyset
- * rule array and the array in keysetRules.
- * @const
- * @type {number}
- */
- var OFFSET = 1;
-
- /**
- * The minumum number of elements in one keyset rule.
- * @const {number}
- */
- var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
-
- Polymer('kb-key-base', {
- repeat: false,
- invert: false,
- longPressTimer: null,
- pointerId: undefined,
-
- /**
- * The keyset transition rules. It defines which keyset to transit to on
- * which key events. It consists at most four rules (down, up, long, dbl).
- * If no rule is defined for a key event, the event wont trigger a keyset
- * change.
- * @type {Object.<string, Array.<string>}
- */
- keysetRules: null,
-
- ready: function() {
- if (this.toKeyset) {
- // Parsing keyset rules from toKeyset attribute string.
- // An rule can be defined as: (down|up|long|dbl):keysetid[:keysetid]
- // and each rule are separated by a semicolon. The first element
- // defines the event this rule applies to. The second element defines
- // what keyset to transit to after event received. The third optional
- // element defines what keyset to transit to after a key is pressed in
- // the new keyset. It is useful when you want to transit to a not
- // locked keyset. For example, after transit to a upper case keyset,
- // it may make sense to transit back to lower case after user typed
- // any key at the upper case keyset.
- var rules =
- this.toKeyset.replace(/(\r\n|\n|\r| )/g, '').split(';');
- this.keysetRules = {};
- var self = this;
- rules.forEach(function(element) {
- if (element == '')
- return;
- var keyValues = element.split(':', MAXIMUM_NUM_OF_RULE_ELEMENTS);
- if (keyValues.length < MINIMUM_NUM_OF_RULE_ELEMENTS) {
- console.error('Invalid keyset rules: ' + element);
- return;
- }
- self.keysetRules[keyValues[EVENT_TYPE]] = [keyValues[TO_KEYSET],
- (keyValues[NEXT_KEYSET] ? keyValues[NEXT_KEYSET] : null)];
- });
- }
- },
-
- down: function(event) {
- this.pointerId = event.pointerId;
- var detail = this.populateDetails('down');
- this.fire('key-down', detail);
- this.longPressTimer = this.generateLongPressTimer();
- },
- out: function(event) {
- this.classList.remove('active');
- clearTimeout(this.longPressTimer);
- },
- up: function(event) {
- this.generateKeyup();
- },
-
- /**
- * Releases the pressed key programmatically and fires key-up event. This
- * should be called if a second key is pressed while the first key is not
- * released yet.
- */
- autoRelease: function() {
- this.generateKeyup();
- },
-
- /**
- * Drops the pressed key.
- */
- dropKey: function() {
- this.classList.remove('active');
- clearTimeout(this.longPressTimer);
- this.pointerId = undefined;
- },
-
- /**
- * Populates details for this key, and then fires a key-up event.
- */
- generateKeyup: function() {
- if (this.pointerId === undefined)
- return;
-
- // Invalidates the pointerId so the subsequent pointerup event is a
- // noop.
- this.pointerId = undefined;
- clearTimeout(this.longPressTimer);
- var detail = this.populateDetails('up');
- this.fire('key-up', detail);
- },
-
- /**
- * Character value associated with the key. Typically, the value is a
- * single character, but may be multi-character in cases like a ".com"
- * button.
- * @return {string}
- */
- get charValue() {
- return this.invert ? this.hintText : (this.char || this.textContent);
- },
-
- /**
- * Hint text value associated with the key. Typically, the value is a
- * single character.
- * @return {string}
- */
- get hintTextValue() {
- return this.invert ? (this.char || this.textContent) : this.hintText;
- },
-
- /**
- * Handles a swipe flick that originated from this key.
- * @param {detail} The details of the swipe.
- */
- onFlick: function(detail) {
- if (!(detail.direction & SWIPE_DIRECTION.UP) || !this.hintTextValue)
- return;
- var typeDetails = {char: this.hintTextValue};
- this.fire('type-key', typeDetails);
- },
-
- /**
- * Returns a subset of the key attributes.
- * @param {string} caller The id of the function which called
- * populateDetails.
- */
- populateDetails: function(caller) {
- var detail = {
- char: this.charValue,
- toLayout: this.toLayout,
- repeat: this.repeat
- };
-
- switch (caller) {
- case ('up'):
- if (this.keysetRules && this.keysetRules.up != undefined) {
- detail.toKeyset = this.keysetRules.up[TO_KEYSET - OFFSET];
- detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET];
- }
- break;
- case ('down'):
- if (this.keysetRules && this.keysetRules.down != undefined) {
- detail.toKeyset = this.keysetRules.down[TO_KEYSET - OFFSET];
- detail.nextKeyset = this.keysetRules.down[NEXT_KEYSET - OFFSET];
- }
- break;
- default:
- break;
- }
- return detail;
- },
-
- generateLongPressTimer: function() {
- return this.asyncMethod(function() {
- var detail = {
- char: this.charValue,
- hintText: this.hintTextValue
- };
- if (this.keysetRules && this.keysetRules.long != undefined) {
- detail.toKeyset = this.keysetRules.long[TO_KEYSET - OFFSET];
- detail.nextKeyset = this.keysetRules.long[NEXT_KEYSET - OFFSET];
- }
- this.fire('key-longpress', detail);
- }, null, LONGPRESS_DELAY_MSEC);
- },
- });
- </script>
+<polymer-element name="kb-key-base" on-pointerout="{{out}}" attributes="char
+ invert repeat hintText toKeyset toLayout">
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-base.js b/chromium/ui/keyboard/resources/elements/kb-key-base.js
new file mode 100644
index 00000000000..ed6b527d765
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-key-base.js
@@ -0,0 +1,228 @@
+// 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.
+
+/**
+ * The long-press delay in milliseconds before long-press handler is
+ * invoked.
+ * @const
+ * @type {number}
+ */
+var LONGPRESS_DELAY_MSEC = 500;
+
+/**
+ * The maximum number of elements in one keyset rule.
+ * @const
+ * @type {number}
+ */
+var MAXIMUM_NUM_OF_RULE_ELEMENTS = 3;
+
+/**
+ * The minumum number of elements in one keyset rule.
+ * @const
+ * @type {number}
+ */
+var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
+
+/**
+ * The index of event type element in the splitted keyset rule.
+ * @const
+ * @type {number}
+ */
+var EVENT_TYPE = 0;
+
+/**
+ * The index of toKeyset element in the splitted keyset rule.
+ * @const
+ * @type {number}
+ */
+var TO_KEYSET = 1;
+
+/**
+ * The index of nextKeyset element in the splitted keyset rule.
+ * @const
+ * @type {number}
+ */
+var NEXT_KEYSET = 2;
+
+/**
+ * The index offset of toKeyset and nextKeyset elements in splitted keyset
+ * rule array and the array in keysetRules.
+ * @const
+ * @type {number}
+ */
+var OFFSET = 1;
+
+/**
+ * The minumum number of elements in one keyset rule.
+ * @const {number}
+ */
+var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
+
+Polymer('kb-key-base', {
+ repeat: false,
+ invert: false,
+ longPressTimer: null,
+ pointerId: undefined,
+
+ /**
+ * The keyset transition rules. It defines which keyset to transit to on
+ * which key events. It consists at most four rules (down, up, long, dbl).
+ * If no rule is defined for a key event, the event wont trigger a keyset
+ * change.
+ * @type {Object.<string, Array.<string>}
+ */
+ keysetRules: null,
+
+ ready: function() {
+ if (this.toKeyset) {
+ // Parsing keyset rules from toKeyset attribute string.
+ // An rule can be defined as: (down|up|long|dbl):keysetid[:keysetid]
+ // and each rule are separated by a semicolon. The first element
+ // defines the event this rule applies to. The second element defines
+ // what keyset to transit to after event received. The third optional
+ // element defines what keyset to transit to after a key is pressed in
+ // the new keyset. It is useful when you want to transit to a not
+ // locked keyset. For example, after transit to a upper case keyset,
+ // it may make sense to transit back to lower case after user typed
+ // any key at the upper case keyset.
+ var rules =
+ this.toKeyset.replace(/(\r\n|\n|\r| )/g, '').split(';');
+ this.keysetRules = {};
+ var self = this;
+ rules.forEach(function(element) {
+ if (element == '')
+ return;
+ var keyValues = element.split(':', MAXIMUM_NUM_OF_RULE_ELEMENTS);
+ if (keyValues.length < MINIMUM_NUM_OF_RULE_ELEMENTS) {
+ console.error('Invalid keyset rules: ' + element);
+ return;
+ }
+ self.keysetRules[keyValues[EVENT_TYPE]] = [keyValues[TO_KEYSET],
+ (keyValues[NEXT_KEYSET] ? keyValues[NEXT_KEYSET] : null)];
+ });
+ }
+ },
+
+ down: function(event) {
+ this.pointerId = event.pointerId;
+ var detail = this.populateDetails('down');
+ this.fire('key-down', detail);
+ this.longPressTimer = this.generateLongPressTimer();
+ },
+ out: function(event) {
+ this.classList.remove('active');
+ clearTimeout(this.longPressTimer);
+ },
+ up: function(event) {
+ this.generateKeyup();
+ },
+
+ /**
+ * Releases the pressed key programmatically and fires key-up event. This
+ * should be called if a second key is pressed while the first key is not
+ * released yet.
+ */
+ autoRelease: function() {
+ this.generateKeyup();
+ },
+
+ /**
+ * Drops the pressed key.
+ */
+ dropKey: function() {
+ this.classList.remove('active');
+ clearTimeout(this.longPressTimer);
+ this.pointerId = undefined;
+ },
+
+ /**
+ * Populates details for this key, and then fires a key-up event.
+ */
+ generateKeyup: function() {
+ if (this.pointerId === undefined)
+ return;
+
+ // Invalidates the pointerId so the subsequent pointerup event is a
+ // noop.
+ this.pointerId = undefined;
+ clearTimeout(this.longPressTimer);
+ var detail = this.populateDetails('up');
+ this.fire('key-up', detail);
+ },
+
+ /**
+ * Character value associated with the key. Typically, the value is a
+ * single character, but may be multi-character in cases like a ".com"
+ * button.
+ * @return {string}
+ */
+ get charValue() {
+ return this.invert ? this.hintText : (this.char || this.textContent);
+ },
+
+ /**
+ * Hint text value associated with the key. Typically, the value is a
+ * single character.
+ * @return {string}
+ */
+ get hintTextValue() {
+ return this.invert ? (this.char || this.textContent) : this.hintText;
+ },
+
+ /**
+ * Handles a swipe flick that originated from this key.
+ * @param {detail} The details of the swipe.
+ */
+ onFlick: function(detail) {
+ if (!(detail.direction & SwipeDirection.UP) || !this.hintTextValue)
+ return;
+ var typeDetails = {char: this.hintTextValue};
+ this.fire('type-key', typeDetails);
+ },
+
+ /**
+ * Returns a subset of the key attributes.
+ * @param {string} caller The id of the function which called
+ * populateDetails.
+ */
+ populateDetails: function(caller) {
+ var detail = {
+ char: this.charValue,
+ toLayout: this.toLayout,
+ repeat: this.repeat
+ };
+
+ switch (caller) {
+ case ('up'):
+ if (this.keysetRules && this.keysetRules.up != undefined) {
+ detail.toKeyset = this.keysetRules.up[TO_KEYSET - OFFSET];
+ detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET];
+ }
+ break;
+ case ('down'):
+ if (this.keysetRules && this.keysetRules.down != undefined) {
+ detail.toKeyset = this.keysetRules.down[TO_KEYSET - OFFSET];
+ detail.nextKeyset = this.keysetRules.down[NEXT_KEYSET - OFFSET];
+ }
+ break;
+ default:
+ break;
+ }
+ return detail;
+ },
+
+ generateLongPressTimer: function() {
+ return this.async(function() {
+ var detail = {
+ char: this.charValue,
+ hintText: this.hintTextValue
+ };
+ if (this.keysetRules && this.keysetRules.long != undefined) {
+ detail.toKeyset = this.keysetRules.long[TO_KEYSET - OFFSET];
+ detail.nextKeyset = this.keysetRules.long[NEXT_KEYSET - OFFSET];
+ }
+ this.fire('key-longpress', detail);
+ }, null, LONGPRESS_DELAY_MSEC);
+ },
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-codes.html b/chromium/ui/keyboard/resources/elements/kb-key-codes.html
index d99a00fcf73..8fc0ee8547c 100644
--- a/chromium/ui/keyboard/resources/elements/kb-key-codes.html
+++ b/chromium/ui/keyboard/resources/elements/kb-key-codes.html
@@ -5,229 +5,4 @@
-->
<polymer-element name="kb-key-codes">
-<script>
- (function() {
-
- // Flag values for ctrl, alt and shift as defined by EventFlags
- // in "event_constants.h".
- // @enum {number}
- var Modifier = {
- NONE: 0,
- ALT: 8,
- CONTROL: 4,
- SHIFT: 2
- }
-
- // Each virtual key event is assigned a unique ID.
- var nextRequestID = 0;
-
- // Keycodes have been deprecated in the KeyEvent specification, but are
- // nonetheless required to support legacy web content. The Keycodes in the
- // following table are based on subset of US-EN 101-key keyboard. These
- // codes are used in the absence of explicit keycodes for kb-key and
- // kb-keysequence elements. Keyboard layout authors may explicitly set the
- // keyCode attribute for kb-key or kb-keysequence elements to refer to
- // indices in this table in order to emulate a physical keyboard with an
- // alternate layout. Not all keys on a virtual keyboard are required to
- // have keyCodes. The shiftModifier specifies whether to always include or
- // exclude the shift modifer when sending key events for this key. If it's
- // undefined, it will defer to state of the keyboard.
- // TODO(rsadam): Correctly propagate shutdown keycode. This is currently
- // ignored due to chromoting (crbug/146609)
- var keyCodes = {
- '\b': {keyCode: 0x08, keyName: 'Backspace', shiftModifier: false},
- '\t': {keyCode: 0x09, keyName: 'Tab', shiftModifier: false},
- '\n': {keyCode: 0x0D, keyName: 'Enter', shiftModifier: false},
- 'Esc': {keyCode: 0x1B, keyName: 'Escape', shiftModifier: false},
- ' ': {keyCode: 0x20, keyName: 'Space', shiftModifier: false},
- 'Arrow-Left': {keyCode: 0x25, keyName: 'ArrowLeft',
- shiftModifier: undefined},
- 'Arrow-Up': {keyCode: 0x26, keyName: 'ArrowUp', shiftModifier: undefined},
- 'Arrow-Right': {keyCode: 0x27, keyName: 'ArrowRight',
- shiftModifier: undefined},
- 'Arrow-Down': {keyCode: 0x28, keyName: 'ArrowDown',
- shiftModifier: undefined},
- '0': {keyCode: 0x30, keyName: 'Digit0', shiftModifier: false},
- ')': {keyCode: 0x30, keyName: 'Digit0', shiftModifier: true},
- '1': {keyCode: 0x31, keyName: 'Digit1', shiftModifier: false},
- '!': {keyCode: 0x31, keyName: 'Digit1', shiftModifier: true},
- '2': {keyCode: 0x32, keyName: 'Digit2', shiftModifier: false},
- '@': {keyCode: 0x32, keyName: 'Digit2', shiftModifier: true},
- '3': {keyCode: 0x33, keyName: 'Digit3', shiftModifier: false},
- '#': {keyCode: 0x33, keyName: 'Digit3', shiftModifier: true},
- '4': {keyCode: 0x34, keyName: 'Digit4', shiftModifier: false},
- '$': {keyCode: 0x34, keyName: 'Digit4', shiftModifier: true},
- '5': {keyCode: 0x35, keyName: 'Digit5', shiftModifier: false},
- '%': {keyCode: 0x35, keyName: 'Digit5', shiftModifier: true},
- '6': {keyCode: 0x36, keyName: 'Digit6', shiftModifier: false},
- '^': {keyCode: 0x36, keyName: 'Digit6', shiftModifier: true},
- '7': {keyCode: 0x37, keyName: 'Digit7', shiftModifier: false},
- '&': {keyCode: 0x37, keyName: 'Digit7', shiftModifier: true},
- '8': {keyCode: 0x38, keyName: 'Digit8', shiftModifier: false},
- '*': {keyCode: 0x38, keyName: 'Digit8', shiftModifier: true},
- '9': {keyCode: 0x39, keyName: 'Digit9', shiftModifier: false},
- '(': {keyCode: 0x39, keyName: 'Digit9', shiftModifier: true},
- 'a': {keyCode: 0x41, keyName: 'KeyA', shiftModifier: false},
- 'A': {keyCode: 0x41, keyName: 'KeyA', shiftModifier: true},
- 'b': {keyCode: 0x42, keyName: 'KeyB', shiftModifier: false},
- 'B': {keyCode: 0x42, keyName: 'KeyB', shiftModifier: true},
- 'c': {keyCode: 0x43, keyName: 'KeyC', shiftModifier: false},
- 'C': {keyCode: 0x43, keyName: 'KeyC', shiftModifier: true},
- 'd': {keyCode: 0x44, keyName: 'KeyD', shiftModifier: false},
- 'D': {keyCode: 0x44, keyName: 'KeyD', shiftModifier: true},
- 'e': {keyCode: 0x45, keyName: 'KeyE', shiftModifier: false},
- 'E': {keyCode: 0x45, keyName: 'KeyE', shiftModifier: true},
- 'f': {keyCode: 0x46, keyName: 'KeyF', shiftModifier: false},
- 'F': {keyCode: 0x46, keyName: 'KeyF', shiftModifier: true},
- 'g': {keyCode: 0x47, keyName: 'KeyG', shiftModifier: false},
- 'G': {keyCode: 0x47, keyName: 'KeyG', shiftModifier: true},
- 'h': {keyCode: 0x48, keyName: 'KeyH', shiftModifier: false},
- 'H': {keyCode: 0x48, keyName: 'KeyH', shiftModifier: true},
- 'i': {keyCode: 0x49, keyName: 'KeyI', shiftModifier: false},
- 'I': {keyCode: 0x49, keyName: 'KeyI', shiftModifier: true},
- 'j': {keyCode: 0x4A, keyName: 'KeyJ', shiftModifier: false},
- 'J': {keyCode: 0x4A, keyName: 'KeyJ', shiftModifier: true},
- 'k': {keyCode: 0x4B, keyName: 'KeyK', shiftModifier: false},
- 'K': {keyCode: 0x4B, keyName: 'KeyK', shiftModifier: true},
- 'l': {keyCode: 0x4C, keyName: 'KeyL', shiftModifier: false},
- 'L': {keyCode: 0x4C, keyName: 'KeyL', shiftModifier: true},
- 'm': {keyCode: 0x4D, keyName: 'KeyM', shiftModifier: false},
- 'M': {keyCode: 0x4D, keyName: 'KeyM', shiftModifier: true},
- 'n': {keyCode: 0x4E, keyName: 'KeyN', shiftModifier: false},
- 'N': {keyCode: 0x4E, keyName: 'KeyN', shiftModifier: true},
- 'o': {keyCode: 0x4F, keyName: 'KeyO', shiftModifier: false},
- 'O': {keyCode: 0x4F, keyName: 'KeyO', shiftModifier: true},
- 'p': {keyCode: 0x50, keyName: 'KeyP', shiftModifier: false},
- 'P': {keyCode: 0x50, keyName: 'KeyP', shiftModifier: true},
- 'q': {keyCode: 0x51, keyName: 'KeyQ', shiftModifier: false},
- 'Q': {keyCode: 0x51, keyName: 'KeyQ', shiftModifier: true},
- 'r': {keyCode: 0x52, keyName: 'KeyR', shiftModifier: false},
- 'R': {keyCode: 0x52, keyName: 'KeyR', shiftModifier: true},
- 's': {keyCode: 0x53, keyName: 'KeyS', shiftModifier: false},
- 'S': {keyCode: 0x53, keyName: 'KeyS', shiftModifier: true},
- 't': {keyCode: 0x54, keyName: 'KeyT', shiftModifier: false},
- 'T': {keyCode: 0x54, keyName: 'KeyT', shiftModifier: true},
- 'u': {keyCode: 0x55, keyName: 'KeyU', shiftModifier: false},
- 'U': {keyCode: 0x55, keyName: 'KeyU', shiftModifier: true},
- 'v': {keyCode: 0x56, keyName: 'KeyV', shiftModifier: false},
- 'V': {keyCode: 0x56, keyName: 'KeyV', shiftModifier: true},
- 'w': {keyCode: 0x57, keyName: 'KeyW', shiftModifier: false},
- 'W': {keyCode: 0x57, keyName: 'KeyW', shiftModifier: true},
- 'x': {keyCode: 0x58, keyName: 'KeyX', shiftModifier: false},
- 'X': {keyCode: 0x58, keyName: 'KeyX', shiftModifier: true},
- 'y': {keyCode: 0x59, keyName: 'KeyY', shiftModifier: false},
- 'Y': {keyCode: 0x59, keyName: 'KeyY', shiftModifier: true},
- 'z': {keyCode: 0x5A, keyName: 'KeyZ', shiftModifier: false},
- 'Z': {keyCode: 0x5A, keyName: 'KeyZ', shiftModifier: true},
- 'Fullscreen': {keyCode: 0x7A, shiftModifier: false},
- 'Shutdown': {keyCode: 0x98, shiftModifier: false},
- 'Back': {keyCode: 0xA6, shiftModifier: false},
- 'Forward': {keyCode: 0xA7, shiftModifier: false},
- 'Reload': {keyCode: 0xA8, shiftModifier: false},
- 'Search': {keyCode: 0xAA, shiftModifier: false},
- 'Mute': {keyCode: 0xAD, keyName: 'VolumeMute', shiftModifier: false},
- 'Volume-Down': {keyCode: 0xAE, keyName: 'VolumeDown',
- shiftModifier: false},
- 'Volume-Up': {keyCode: 0xAF, keyName: 'VolumeUp', shiftModifier: false},
- 'Change-Window': {keyCode: 0xB6, shiftModifier: false},
- ';': {keyCode: 0xBA, keyName: 'Semicolon', shiftModifier: false},
- ':': {keyCode: 0xBA, keyName: 'Semicolon',shiftModifier: true},
- '=': {keyCode: 0xBB, keyName: 'Equal', shiftModifier: false},
- '+': {keyCode: 0xBB, keyName: 'Equal', shiftModifier: true},
- ',': {keyCode: 0xBC, keyName: 'Comma', shiftModifier: false},
- '<': {keyCode: 0xBC, keyName: 'Comma', shiftModifier: true},
- '-': {keyCode: 0xBD, keyName: 'Minus', shiftModifier: false},
- '_': {keyCode: 0xBD, keyName: 'Minus', shiftModifier: true},
- '.': {keyCode: 0xBE, keyName: 'Period', shiftModifier: false},
- '>': {keyCode: 0xBE, keyName: 'Period', shiftModifier: true},
- '/': {keyCode: 0xBF, keyName: 'Slash', shiftModifier: false},
- '?': {keyCode: 0xBF, keyName: 'Slash', shiftModifier: true},
- '`': {keyCode: 0xC0, keyName: 'Backquote', shiftModifier: false},
- '~': {keyCode: 0xC0, keyName: 'Backquote', shiftModifier: true},
- 'Brightness-Down': {keyCode: 0xD8, keyName: 'BrightnessDown',
- shiftModifier: false},
- 'Brightness-Up': {keyCode: 0xD9, keyName: 'BrightnessUp',
- shiftModifier: false},
- '[': {keyCode: 0xDB, keyName: 'BracketLeft', shiftModifier: false},
- '{': {keyCode: 0xDB, keyName: 'BracketLeft', shiftModifier: true},
- '\\': {keyCode: 0xDC, keyName: 'Backslash', shiftModifier: false},
- '|': {keyCode: 0xDC, keyName: 'Backslash', shiftModifier: true},
- ']': {keyCode: 0xDD, keyName: 'BracketRight', shiftModifier: false},
- '}': {keyCode: 0xDD, keyName: 'BracketRight', shiftModifier: true},
- '\'': {keyCode: 0xDE, keyName: 'Quote', shiftModifier: false},
- '"': {keyCode: 0xDE, keyName: 'Quote', shiftModifier: true},
- };
-
- Polymer('kb-key-codes', {
- /**
- * Retrieves the keyCode and status of the shift modifier.
- * @param {string} id ID of an entry in the code table.
- * @return {keyCode: numeric, shiftModifier: boolean}
- */
- GetKeyCodeAndModifiers: function(id) {
- var entry = keyCodes[id];
- if (entry) {
- return {
- keyCode: entry.keyCode,
- keyName: entry.keyName || 'Unidentified',
- shiftModifier: entry.shiftModifier
- };
- }
- if (id.length != 1)
- return;
- // Special case of accented characters.
- return {
- keyCode: 0,
- keyName: 'Unidentified',
- shiftModifier: false
- };
- },
-
- /**
- * Creates a virtual key event for use with the keyboard extension API.
- * See http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent.
- * @param {Object} detail Attribute of the key being pressed or released.
- * @param {string} type The type of key event, which may be keydown
- * or keyup.
- * @return {?KeyboardEvent} A KeyboardEvent object, or undefined on
- * failure.
- */
- createVirtualKeyEvent: function(detail, type) {
- var char = detail.char;
- var keyCode = detail.keyCode;
- var keyName = detail.keyName;
- // The shift modifier is handled specially. Some charactares like '+'
- // {keyCode: 0xBB, shiftModifier: true}, are available on non-upper
- // keysets, and so we rely on caching the correct shiftModifier. If
- // the cached value of the shiftModifier is undefined, we defer to
- // the shiftModifier in the detail.
- var shiftModifier = detail.shiftModifier;
- if (keyCode == undefined || keyName == undefined) {
- var state = this.GetKeyCodeAndModifiers(char);
- if (state) {
- keyCode = keyCode || state.keyCode;
- keyName = keyName || state.keyName;
- shiftModifier = (state.shiftModifier == undefined) ?
- shiftModifier : state.shiftModifier;
- } else {
- // Keycode not defined.
- return;
- }
- }
- var modifiers = Modifier.NONE;
- modifiers = shiftModifier ? modifiers | Modifier.SHIFT : modifiers;
- modifiers = detail.controlModifier ?
- modifiers | Modifier.CONTROL : modifiers;
- modifiers = detail.altModifier ? modifiers | Modifier.ALT : modifiers;
- return {
- type: type,
- charValue: char.charCodeAt(0),
- keyCode: keyCode,
- keyName: keyName,
- modifiers: modifiers
- };
- },
- });
- })();
-</script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-codes.js b/chromium/ui/keyboard/resources/elements/kb-key-codes.js
new file mode 100644
index 00000000000..103fe4448e4
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-key-codes.js
@@ -0,0 +1,227 @@
+// 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.
+
+(function() {
+
+ // Flag values for ctrl, alt and shift as defined by EventFlags
+ // in "event_constants.h".
+ // @enum {number}
+ var Modifier = {
+ NONE: 0,
+ ALT: 8,
+ CONTROL: 4,
+ SHIFT: 2
+ }
+
+ // Each virtual key event is assigned a unique ID.
+ var nextRequestID = 0;
+
+ // Keycodes have been deprecated in the KeyEvent specification, but are
+ // nonetheless required to support legacy web content. The Keycodes in the
+ // following table are based on subset of US-EN 101-key keyboard. These
+ // codes are used in the absence of explicit keycodes for kb-key and
+ // kb-keysequence elements. Keyboard layout authors may explicitly set the
+ // keyCode attribute for kb-key or kb-keysequence elements to refer to
+ // indices in this table in order to emulate a physical keyboard with an
+ // alternate layout. Not all keys on a virtual keyboard are required to
+ // have keyCodes. The shiftModifier specifies whether to always include or
+ // exclude the shift modifer when sending key events for this key. If it's
+ // undefined, it will defer to state of the keyboard.
+ // TODO(rsadam): Correctly propagate shutdown keycode. This is currently
+ // ignored due to chromoting (crbug/146609)
+ var keyCodes = {
+ '\b': {keyCode: 0x08, keyName: 'Backspace', shiftModifier: false},
+ '\t': {keyCode: 0x09, keyName: 'Tab', shiftModifier: false},
+ '\n': {keyCode: 0x0D, keyName: 'Enter', shiftModifier: false},
+ 'Esc': {keyCode: 0x1B, keyName: 'Escape', shiftModifier: false},
+ ' ': {keyCode: 0x20, keyName: 'Space', shiftModifier: false},
+ 'Arrow-Left': {keyCode: 0x25, keyName: 'ArrowLeft',
+ shiftModifier: undefined},
+ 'Arrow-Up': {keyCode: 0x26, keyName: 'ArrowUp', shiftModifier: undefined},
+ 'Arrow-Right': {keyCode: 0x27, keyName: 'ArrowRight',
+ shiftModifier: undefined},
+ 'Arrow-Down': {keyCode: 0x28, keyName: 'ArrowDown',
+ shiftModifier: undefined},
+ '0': {keyCode: 0x30, keyName: 'Digit0', shiftModifier: false},
+ ')': {keyCode: 0x30, keyName: 'Digit0', shiftModifier: true},
+ '1': {keyCode: 0x31, keyName: 'Digit1', shiftModifier: false},
+ '!': {keyCode: 0x31, keyName: 'Digit1', shiftModifier: true},
+ '2': {keyCode: 0x32, keyName: 'Digit2', shiftModifier: false},
+ '@': {keyCode: 0x32, keyName: 'Digit2', shiftModifier: true},
+ '3': {keyCode: 0x33, keyName: 'Digit3', shiftModifier: false},
+ '#': {keyCode: 0x33, keyName: 'Digit3', shiftModifier: true},
+ '4': {keyCode: 0x34, keyName: 'Digit4', shiftModifier: false},
+ '$': {keyCode: 0x34, keyName: 'Digit4', shiftModifier: true},
+ '5': {keyCode: 0x35, keyName: 'Digit5', shiftModifier: false},
+ '%': {keyCode: 0x35, keyName: 'Digit5', shiftModifier: true},
+ '6': {keyCode: 0x36, keyName: 'Digit6', shiftModifier: false},
+ '^': {keyCode: 0x36, keyName: 'Digit6', shiftModifier: true},
+ '7': {keyCode: 0x37, keyName: 'Digit7', shiftModifier: false},
+ '&': {keyCode: 0x37, keyName: 'Digit7', shiftModifier: true},
+ '8': {keyCode: 0x38, keyName: 'Digit8', shiftModifier: false},
+ '*': {keyCode: 0x38, keyName: 'Digit8', shiftModifier: true},
+ '9': {keyCode: 0x39, keyName: 'Digit9', shiftModifier: false},
+ '(': {keyCode: 0x39, keyName: 'Digit9', shiftModifier: true},
+ 'a': {keyCode: 0x41, keyName: 'KeyA', shiftModifier: false},
+ 'A': {keyCode: 0x41, keyName: 'KeyA', shiftModifier: true},
+ 'b': {keyCode: 0x42, keyName: 'KeyB', shiftModifier: false},
+ 'B': {keyCode: 0x42, keyName: 'KeyB', shiftModifier: true},
+ 'c': {keyCode: 0x43, keyName: 'KeyC', shiftModifier: false},
+ 'C': {keyCode: 0x43, keyName: 'KeyC', shiftModifier: true},
+ 'd': {keyCode: 0x44, keyName: 'KeyD', shiftModifier: false},
+ 'D': {keyCode: 0x44, keyName: 'KeyD', shiftModifier: true},
+ 'e': {keyCode: 0x45, keyName: 'KeyE', shiftModifier: false},
+ 'E': {keyCode: 0x45, keyName: 'KeyE', shiftModifier: true},
+ 'f': {keyCode: 0x46, keyName: 'KeyF', shiftModifier: false},
+ 'F': {keyCode: 0x46, keyName: 'KeyF', shiftModifier: true},
+ 'g': {keyCode: 0x47, keyName: 'KeyG', shiftModifier: false},
+ 'G': {keyCode: 0x47, keyName: 'KeyG', shiftModifier: true},
+ 'h': {keyCode: 0x48, keyName: 'KeyH', shiftModifier: false},
+ 'H': {keyCode: 0x48, keyName: 'KeyH', shiftModifier: true},
+ 'i': {keyCode: 0x49, keyName: 'KeyI', shiftModifier: false},
+ 'I': {keyCode: 0x49, keyName: 'KeyI', shiftModifier: true},
+ 'j': {keyCode: 0x4A, keyName: 'KeyJ', shiftModifier: false},
+ 'J': {keyCode: 0x4A, keyName: 'KeyJ', shiftModifier: true},
+ 'k': {keyCode: 0x4B, keyName: 'KeyK', shiftModifier: false},
+ 'K': {keyCode: 0x4B, keyName: 'KeyK', shiftModifier: true},
+ 'l': {keyCode: 0x4C, keyName: 'KeyL', shiftModifier: false},
+ 'L': {keyCode: 0x4C, keyName: 'KeyL', shiftModifier: true},
+ 'm': {keyCode: 0x4D, keyName: 'KeyM', shiftModifier: false},
+ 'M': {keyCode: 0x4D, keyName: 'KeyM', shiftModifier: true},
+ 'n': {keyCode: 0x4E, keyName: 'KeyN', shiftModifier: false},
+ 'N': {keyCode: 0x4E, keyName: 'KeyN', shiftModifier: true},
+ 'o': {keyCode: 0x4F, keyName: 'KeyO', shiftModifier: false},
+ 'O': {keyCode: 0x4F, keyName: 'KeyO', shiftModifier: true},
+ 'p': {keyCode: 0x50, keyName: 'KeyP', shiftModifier: false},
+ 'P': {keyCode: 0x50, keyName: 'KeyP', shiftModifier: true},
+ 'q': {keyCode: 0x51, keyName: 'KeyQ', shiftModifier: false},
+ 'Q': {keyCode: 0x51, keyName: 'KeyQ', shiftModifier: true},
+ 'r': {keyCode: 0x52, keyName: 'KeyR', shiftModifier: false},
+ 'R': {keyCode: 0x52, keyName: 'KeyR', shiftModifier: true},
+ 's': {keyCode: 0x53, keyName: 'KeyS', shiftModifier: false},
+ 'S': {keyCode: 0x53, keyName: 'KeyS', shiftModifier: true},
+ 't': {keyCode: 0x54, keyName: 'KeyT', shiftModifier: false},
+ 'T': {keyCode: 0x54, keyName: 'KeyT', shiftModifier: true},
+ 'u': {keyCode: 0x55, keyName: 'KeyU', shiftModifier: false},
+ 'U': {keyCode: 0x55, keyName: 'KeyU', shiftModifier: true},
+ 'v': {keyCode: 0x56, keyName: 'KeyV', shiftModifier: false},
+ 'V': {keyCode: 0x56, keyName: 'KeyV', shiftModifier: true},
+ 'w': {keyCode: 0x57, keyName: 'KeyW', shiftModifier: false},
+ 'W': {keyCode: 0x57, keyName: 'KeyW', shiftModifier: true},
+ 'x': {keyCode: 0x58, keyName: 'KeyX', shiftModifier: false},
+ 'X': {keyCode: 0x58, keyName: 'KeyX', shiftModifier: true},
+ 'y': {keyCode: 0x59, keyName: 'KeyY', shiftModifier: false},
+ 'Y': {keyCode: 0x59, keyName: 'KeyY', shiftModifier: true},
+ 'z': {keyCode: 0x5A, keyName: 'KeyZ', shiftModifier: false},
+ 'Z': {keyCode: 0x5A, keyName: 'KeyZ', shiftModifier: true},
+ 'Fullscreen': {keyCode: 0x7A, shiftModifier: false},
+ 'Shutdown': {keyCode: 0x98, shiftModifier: false},
+ 'Back': {keyCode: 0xA6, shiftModifier: false},
+ 'Forward': {keyCode: 0xA7, shiftModifier: false},
+ 'Reload': {keyCode: 0xA8, shiftModifier: false},
+ 'Search': {keyCode: 0xAA, shiftModifier: false},
+ 'Mute': {keyCode: 0xAD, keyName: 'VolumeMute', shiftModifier: false},
+ 'Volume-Down': {keyCode: 0xAE, keyName: 'VolumeDown',
+ shiftModifier: false},
+ 'Volume-Up': {keyCode: 0xAF, keyName: 'VolumeUp', shiftModifier: false},
+ 'Change-Window': {keyCode: 0xB6, shiftModifier: false},
+ ';': {keyCode: 0xBA, keyName: 'Semicolon', shiftModifier: false},
+ ':': {keyCode: 0xBA, keyName: 'Semicolon',shiftModifier: true},
+ '=': {keyCode: 0xBB, keyName: 'Equal', shiftModifier: false},
+ '+': {keyCode: 0xBB, keyName: 'Equal', shiftModifier: true},
+ ',': {keyCode: 0xBC, keyName: 'Comma', shiftModifier: false},
+ '<': {keyCode: 0xBC, keyName: 'Comma', shiftModifier: true},
+ '-': {keyCode: 0xBD, keyName: 'Minus', shiftModifier: false},
+ '_': {keyCode: 0xBD, keyName: 'Minus', shiftModifier: true},
+ '.': {keyCode: 0xBE, keyName: 'Period', shiftModifier: false},
+ '>': {keyCode: 0xBE, keyName: 'Period', shiftModifier: true},
+ '/': {keyCode: 0xBF, keyName: 'Slash', shiftModifier: false},
+ '?': {keyCode: 0xBF, keyName: 'Slash', shiftModifier: true},
+ '`': {keyCode: 0xC0, keyName: 'Backquote', shiftModifier: false},
+ '~': {keyCode: 0xC0, keyName: 'Backquote', shiftModifier: true},
+ 'Brightness-Down': {keyCode: 0xD8, keyName: 'BrightnessDown',
+ shiftModifier: false},
+ 'Brightness-Up': {keyCode: 0xD9, keyName: 'BrightnessUp',
+ shiftModifier: false},
+ '[': {keyCode: 0xDB, keyName: 'BracketLeft', shiftModifier: false},
+ '{': {keyCode: 0xDB, keyName: 'BracketLeft', shiftModifier: true},
+ '\\': {keyCode: 0xDC, keyName: 'Backslash', shiftModifier: false},
+ '|': {keyCode: 0xDC, keyName: 'Backslash', shiftModifier: true},
+ ']': {keyCode: 0xDD, keyName: 'BracketRight', shiftModifier: false},
+ '}': {keyCode: 0xDD, keyName: 'BracketRight', shiftModifier: true},
+ '\'': {keyCode: 0xDE, keyName: 'Quote', shiftModifier: false},
+ '"': {keyCode: 0xDE, keyName: 'Quote', shiftModifier: true},
+ };
+
+ Polymer('kb-key-codes', {
+ /**
+ * Retrieves the keyCode and status of the shift modifier.
+ * @param {string} id ID of an entry in the code table.
+ * @return {keyCode: numeric, shiftModifier: boolean}
+ */
+ GetKeyCodeAndModifiers: function(id) {
+ var entry = keyCodes[id];
+ if (entry) {
+ return {
+ keyCode: entry.keyCode,
+ keyName: entry.keyName || 'Unidentified',
+ shiftModifier: entry.shiftModifier
+ };
+ }
+ if (id.length != 1)
+ return;
+ // Special case of accented characters.
+ return {
+ keyCode: 0,
+ keyName: 'Unidentified',
+ shiftModifier: false
+ };
+ },
+
+ /**
+ * Creates a virtual key event for use with the keyboard extension API.
+ * See http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent.
+ * @param {Object} detail Attribute of the key being pressed or released.
+ * @param {string} type The type of key event, which may be keydown
+ * or keyup.
+ * @return {?KeyboardEvent} A KeyboardEvent object, or undefined on
+ * failure.
+ */
+ createVirtualKeyEvent: function(detail, type) {
+ var char = detail.char;
+ var keyCode = detail.keyCode;
+ var keyName = detail.keyName;
+ // The shift modifier is handled specially. Some charactares like '+'
+ // {keyCode: 0xBB, shiftModifier: true}, are available on non-upper
+ // keysets, and so we rely on caching the correct shiftModifier. If
+ // the cached value of the shiftModifier is undefined, we defer to
+ // the shiftModifier in the detail.
+ var shiftModifier = detail.shiftModifier;
+ if (keyCode == undefined || keyName == undefined) {
+ var state = this.GetKeyCodeAndModifiers(char);
+ if (state) {
+ keyCode = keyCode || state.keyCode;
+ keyName = keyName || state.keyName;
+ shiftModifier = (state.shiftModifier == undefined) ?
+ shiftModifier : state.shiftModifier;
+ } else {
+ // Keycode not defined.
+ return;
+ }
+ }
+ var modifiers = Modifier.NONE;
+ modifiers = shiftModifier ? modifiers | Modifier.SHIFT : modifiers;
+ modifiers = detail.controlModifier ?
+ modifiers | Modifier.CONTROL : modifiers;
+ modifiers = detail.altModifier ? modifiers | Modifier.ALT : modifiers;
+ return {
+ type: type,
+ charValue: char.charCodeAt(0),
+ keyCode: keyCode,
+ keyName: keyName,
+ modifiers: modifiers
+ };
+ },
+ });
+})();
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-import.html b/chromium/ui/keyboard/resources/elements/kb-key-import.html
index 1174eb45eed..e703b25195a 100644
--- a/chromium/ui/keyboard/resources/elements/kb-key-import.html
+++ b/chromium/ui/keyboard/resources/elements/kb-key-import.html
@@ -12,23 +12,4 @@
}
</style>
</template>
- <script>
- Polymer('kb-key-import', {
- /**
- * The id of the document fragment that will be imported.
- */
- importId: null,
-
- /**
- * Import content from a document fragment.
- * @param {!DocumentFragment} content Document fragment that contains
- * the content to import.
- */
- importDoc: function(content) {
- var id = this.getAttribute('importId');
- var fragment = content.querySelector('#' + id);
- return fragment && fragment.content ? fragment.content : fragment;
- }
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-import.js b/chromium/ui/keyboard/resources/elements/kb-key-import.js
new file mode 100644
index 00000000000..a06774ca95d
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-key-import.js
@@ -0,0 +1,22 @@
+// 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.
+
+Polymer('kb-key-import', {
+ /**
+ * The id of the document fragment that will be imported.
+ */
+ importId: null,
+
+ /**
+ * Import content from a document fragment.
+ * @param {!DocumentFragment} content Document fragment that contains
+ * the content to import.
+ */
+ importDoc: function(content) {
+ var id = this.getAttribute('importId');
+ var fragment = content.querySelector('#' + id);
+ return fragment && fragment.content ? fragment.content : fragment;
+ }
+});
+
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-sequence.html b/chromium/ui/keyboard/resources/elements/kb-key-sequence.html
index b0bbc233496..212e4279f9c 100644
--- a/chromium/ui/keyboard/resources/elements/kb-key-sequence.html
+++ b/chromium/ui/keyboard/resources/elements/kb-key-sequence.html
@@ -4,8 +4,8 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-key-sequence"
- attributes="keys hintTexts keyCodes invert">
+<polymer-element name="kb-key-sequence" attributes="keys hintTexts keyCodes
+ invert">
<template>
<style>
:host {
@@ -13,61 +13,4 @@
}
</style>
</template>
- <script>
- (function() {
-
- var metadata = null;
-
- function getKeyCodeAndModifiers(keyCodeIndex) {
- if (!metadata)
- metadata = document.createElement('kb-key-codes');
- return metadata.GetKeyCodeAndModifiers(keyCodeIndex);
- }
-
- Polymer('kb-key-sequence', {
- /**
- * Generates the DOM structure to replace (expand) this kb-key-sequence.
- */
- generateDom: function() {
- var replacement = document.createDocumentFragment();
- var newKeys = this.getAttribute('keys');
- var newHintTexts = this.getAttribute('hintTexts');
- var keyCodes = this.getAttribute('hintCodes') || newKeys;
- var invert = this.getAttribute('invert');
- if (newKeys) {
- if (newHintTexts && newKeys.length != newHintTexts.length) {
- console.error('keys and hintTexts do not match');
- return;
- }
- if (keyCodes && newKeys.length != keyCodes.length) {
- console.error('keys and keyCodes do not match');
- return;
- }
-
- for (var i = 0; i < newKeys.length; i++) {
- var key = document.createElement('kb-key');
- key.innerText = newKeys[i];
- key.accents = newKeys[i];
- if (newHintTexts)
- key.hintText = newHintTexts[i];
- var keyCodeIndex = keyCodes[i];
- if (invert) {
- key.invert = true;
- key.char = newKeys[i];
- keyCodeIndex = key.hintText;
- }
- var state = getKeyCodeAndModifiers(keyCodeIndex);
- if (state) {
- key.keyCode = state.keyCode;
- key.keyName = state.keyName;
- key.shiftModifier = state.shiftModifier;
- }
- replacement.appendChild(key);
- }
- }
- return replacement;
- }
- });
- })();
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-key-sequence.js b/chromium/ui/keyboard/resources/elements/kb-key-sequence.js
new file mode 100644
index 00000000000..7bd4d490042
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-key-sequence.js
@@ -0,0 +1,60 @@
+// 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.
+
+(function() {
+
+ var metadata = null;
+
+ function getKeyCodeAndModifiers(keyCodeIndex) {
+ if (!metadata)
+ metadata = document.createElement('kb-key-codes');
+ return metadata.GetKeyCodeAndModifiers(keyCodeIndex);
+ }
+
+ Polymer('kb-key-sequence', {
+ /**
+ * Generates the DOM structure to replace (expand) this kb-key-sequence.
+ */
+ generateDom: function() {
+ var replacement = document.createDocumentFragment();
+ var newKeys = this.getAttribute('keys');
+ var newHintTexts = this.getAttribute('hintTexts');
+ var keyCodes = this.getAttribute('hintCodes') || newKeys;
+ var invert = this.getAttribute('invert');
+ if (newKeys) {
+ if (newHintTexts && newKeys.length != newHintTexts.length) {
+ console.error('keys and hintTexts do not match');
+ return;
+ }
+ if (keyCodes && newKeys.length != keyCodes.length) {
+ console.error('keys and keyCodes do not match');
+ return;
+ }
+
+ for (var i = 0; i < newKeys.length; i++) {
+ var key = document.createElement('kb-key');
+ key.innerText = newKeys[i];
+ key.accents = newKeys[i];
+ if (newHintTexts)
+ key.hintText = newHintTexts[i];
+ var keyCodeIndex = keyCodes[i];
+ if (invert) {
+ key.invert = true;
+ key.char = newKeys[i];
+ keyCodeIndex = key.hintText;
+ }
+ var state = getKeyCodeAndModifiers(keyCodeIndex);
+ if (state) {
+ key.keyCode = state.keyCode;
+ key.keyName = state.keyName;
+ key.shiftModifier = state.shiftModifier;
+ }
+ replacement.appendChild(key);
+ }
+ }
+ return replacement;
+ }
+ });
+})();
+
diff --git a/chromium/ui/keyboard/resources/elements/kb-key.html b/chromium/ui/keyboard/resources/elements/kb-key.html
index 447c491af88..902eb3c854a 100644
--- a/chromium/ui/keyboard/resources/elements/kb-key.html
+++ b/chromium/ui/keyboard/resources/elements/kb-key.html
@@ -4,220 +4,113 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-key" extends="kb-key-base"
- attributes="image imageSize keyCode keyName shiftModifier weight">
+<polymer-element name="kb-key" extends="kb-key-base" attributes="image keyCode
+ keyName shiftModifier sound stretch weight">
<template>
<style>
:host {
- /* TODO(kevers): A regression in the Polymer library broke
- * handling of {{}} in CSS rules. Switch back to
- * "-webkit-box-flex: {{weight}}" once the regression is fixed
- * (https://github.com/Polymer/polymer/issues/270). */
- -webkit-box-flex: 100;
- background-color: #3b3b3e;
- /* TODO(rsadam): remove when {{}} regression is fixed */
+ background-color: #ffffff;
+ border-radius: 1px;
+ border-style: solid;
+ border-width: 0px 0px;
+ color: #666666;
+ font-family: roboto-bold;
+ font-weight: 100;
+ }
+
+ :host .key {
background-image: none;
- background-position: center center;
+ background-position: center;
background-repeat: no-repeat;
- /* TODO(rsadam): remove when {{}} regression is fixed */
- background-size: 50%;
- border-top: 2px solid #4b4b4e;
- border-radius: 2px;
- color: #ffffff;
- display: -webkit-box;
- font-family: 'Open Sans', 'Noto Sans UI', sans-serif;
- font-weight: 300;
- margin-left: 0.25em;
- position: relative;
- }
-
- ::part(key) {
+ background-size: contain;
bottom: 0;
height: 1.2em;
left: 0;
margin: auto;
- padding-left: 0.7em;
- padding-right: 0.7em;
position: absolute;
right: 0;
+ text-align: center;
top: 0;
}
- ::part(hint) {
- color: #7c7c7c;
+ :host([align=left]) .key {
+ padding-left: 1em;
+ }
+
+ /* TODO(rsadam@): Remove when we fully switch to native shadow dom. */
+ /* TODO(rsadam@): Move shift key rules to kb-shift-key. */
+ kb-shift-key .key,
+ :host(kb-shift-key) .key {
+ height: 70%;
+ width: auto;
+ }
+
+ :host([image].cursor) .key {
+ height: 85%;
+ }
+
+ :host([image]) .key {
+ height: 30%;
+ }
+
+ :host([image].tab) .key {
+ height: 40%;
+ }
+
+ :host .hint,
+ :host([invert]) key {
+ color: #bababa;
+ }
+
+ :host .hint {
font-size: 70%;
position: absolute;
right: 7%;
top: 5%;
}
- :host[invert] ::part(key) {
- color: #7c7c7c;
+ :host-context(.hide-hint-text) .hint {
+ display: none;
+ }
+
+ :host([invert]) .hint {
+ color: #666666;
+ }
+
+ :host(.dark) {
+ font-size: 70%;
+ }
+
+ :host(.dark.active) {
+ background-color: #cccccc;
+ }
+
+ :host(.active) {
+ background-color: #dddddd;
+ background-size: cover;
+ }
+
+ :host(.dark:not(.active)) {
+ background-color: #555555;
}
- :host[invert] ::part(hint) {
- color: #ffffff;
+ :host(:not(.dark):not(.active)) {
+ background-color: #ffffff;
+ background-size: cover;
}
</style>
- <div id="key" part="key">
+ <div id="key" class="key">
<content></content>
</div>
- <div part="hint">{{hintText}}</div>
+ <div class="hint" part="hint">{{hintText}}</div>
</template>
- <script>
- Polymer('kb-key', {
- /**
- * The background image to display on this key. Does not display an
- * image if this is the empty string.
- * @type {string}
- */
- image: "",
-
- /**
- * The background image size to use if an image is specified. The size
- * is provided as a string, for example, "50%".
- * @type {string}
- */
- imageSize: "",
-
- /**
- * Key codes have been deprecated in DOM3 key events, but are required
- * for legacy web content. The key codes depend on the position of the
- * key on the keyboard and is independent of which modifier keys (shift,
- * alt, ...) are active.
- * @type {number|undefined}
- */
- keyCode: undefined,
-
- /**
- * Name of the key as defined in the DOM3 specification for key events.
- * Like the keyCode, the keyName is independent of the state of the
- * modifier keys.
- * @type {string|undefined}
- */
- keyName: undefined,
-
- /**
- * Whether the shift key is pressed when producing the key value.
- * @type {boolean}
- */
- shiftModifier: false,
- /**
- * Weighting to use for layout in order to properly size the key.
- * Keys with a high weighting are wider than normal keys.
- * @type {number}
- */
- weight: 100,
-
- /**
- * Called when the image attribute changes. This is used to set the
- * background image of the key.
- * TODO(rsadam): Remove when polymer {{}} syntax regression is fixed.
- */
- imageChanged: function() {
- if (!this.image)
- this.style.backgroundImage = "none";
- else
- this.style.backgroundImage = "url(images/" + this.image + ".svg)";
- },
-
- /**
- * Called when the image attribute changes. This is used to set the
- * background image of the key.
- * TODO(rsadam): Remove when polymer {{}} syntax regression is fixed.
- */
- imageSizeChanged: function() {
- this.style.backgroundSize = this.imageSize;
- },
-
- /**
- * Returns a subset of the key attributes.
- * @param {string} caller The id of the function that called
- * populateDetails.
- * @return {Object} Mapping of attributes for the key element.
- */
- populateDetails: function(caller) {
- var details = this.super([caller]);
- details.keyCode = this.keyCode;
- details.keyName = this.keyName;
- details.shiftModifier = this.shiftModifier;
- return details;
- },
-
- /**
- * Adjusts the CSS rules for rendering the key to reflect the new
- * weight. The preferred way is to use {{weight}} directly in the CSS
- * rules; however, this is currently broken in the Polymer library.
- * TODO(kevers): Cleanup once handling of {{}} in CSS rules is fixed.
- */
- weightChanged: function() {
- if (this.weight > 0)
- this.style['webkitBoxFlex'] = this.weight;
- },
- });
- </script>
</polymer-element>
<!-- Special keys -->
<polymer-element name="kb-abc-key" class="symbol dark" char="Invalid"
extends="kb-key" weight="125">
- <script>
- Polymer('kb-abc-key', {
- populateDetails: function(caller) {
- var detail = this.super([caller]);
- switch (caller) {
- case ('down'):
- detail.relegateToShift = true;
- break;
- default:
- break;
- }
- return detail;
- }
- });
- </script>
</polymer-element>
<polymer-element name="kb-hide-keyboard-key" class="hide-keyboard dark"
- char="Invalid" extends="kb-key">
- <script>
- Polymer('kb-hide-keyboard-key', {
- /**
- * Timer for a long press event which triggers the display of a keyboard
- * options menu.
- * @type {?Function}
- */
- longPressTimer: undefined,
-
- down: function(event) {
- var self = this;
- this.longPressTimer = this.asyncMethod(function() {
- if (self.longPressTimer) {
- clearTimeout(self.longPressTimer);
- self.longPressTimer = undefined;
- var details = {
- left: this.offsetLeft,
- top: this.offsetTop,
- width: this.clientWidth,
- };
- this.fire('show-options', details);
- }
- }, null, LONGPRESS_DELAY_MSEC);
- },
-
- /** @override */
- ready: function() {
- this.super();
- this.image = "keyboard";
- },
-
- up: function(event) {
- if (this.longPressTimer) {
- clearTimeout(this.longPressTimer);
- hideKeyboard();
- this.longPressTimer = undefined;
- }
- }
- });
- </script>
+ align="center" attributes="showMenu" char="Invalid" extends="kb-key">
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-key.js b/chromium/ui/keyboard/resources/elements/kb-key.js
new file mode 100644
index 00000000000..17ff1ae317a
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-key.js
@@ -0,0 +1,114 @@
+// 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.
+
+Polymer('kb-key', {
+ /**
+ * The background image to display on this key. Does not display an
+ * image if this is the empty string.
+ * @type {string}
+ */
+ image: "",
+
+ /**
+ * The background image size to use if an image is specified. The size
+ * is provided as a string, for example, "50%".
+ * @type {string}
+ */
+ imageSize: "",
+
+ /**
+ * Key codes have been deprecated in DOM3 key events, but are required
+ * for legacy web content. The key codes depend on the position of the
+ * key on the keyboard and is independent of which modifier keys (shift,
+ * alt, ...) are active.
+ * @type {number|undefined}
+ */
+ keyCode: undefined,
+
+ /**
+ * Name of the key as defined in the DOM3 specification for key events.
+ * Like the keyCode, the keyName is independent of the state of the
+ * modifier keys.
+ * @type {string|undefined}
+ */
+ keyName: undefined,
+
+ /**
+ * Whether the shift key is pressed when producing the key value.
+ * @type {boolean}
+ */
+ shiftModifier: false,
+
+ /**
+ * The sound to play when this key is pressed.
+ * @type {Sound}
+ */
+ sound: Sound.DEFAULT,
+
+ /**
+ * Whether the key can be stretched to accomodate pixel rounding errors.
+ */
+ stretch: false,
+
+ /**
+ * Weighting to use for layout in order to properly size the key.
+ * Keys with a high weighting are wider than normal keys.
+ * @type {number}
+ */
+ weight: DEFAULT_KEY_WEIGHT,
+
+ /**
+ * Called when the image attribute changes. This is used to set the
+ * background image of the key.
+ * TODO(rsadam): Remove when polymer {{}} syntax regression is fixed.
+ */
+ imageChanged: function() {
+ if (!this.image) {
+ this.$.key.style.backgroundImage = "none";
+ } else {
+ // If no extension provided, default to svg.
+ var image =
+ this.image.split('.').length > 1 ? this.image : this.image + ".svg";
+ this.$.key.style.backgroundImage =
+ "url(images/" + image + ")";
+ }
+ },
+
+ /**
+ * Returns a subset of the key attributes.
+ * @param {string} caller The id of the function that called
+ * populateDetails.
+ * @return {Object} Mapping of attributes for the key element.
+ */
+ populateDetails: function(caller) {
+ var details = this.super([caller]);
+ details.keyCode = this.keyCode;
+ details.keyName = this.keyName;
+ details.shiftModifier = this.shiftModifier;
+ details.sound = this.sound;
+ return details;
+ },
+});
+;
+
+Polymer('kb-abc-key', {
+ populateDetails: function(caller) {
+ var detail = this.super([caller]);
+ switch (caller) {
+ case ('down'):
+ detail.relegateToShift = true;
+ break;
+ default:
+ break;
+ }
+ return detail;
+ }
+});
+;
+
+Polymer('kb-hide-keyboard-key', {
+ up: function(event) {
+ hideKeyboard();
+ },
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-keyboard.html b/chromium/ui/keyboard/resources/elements/kb-keyboard.html
index d47ca6d9ebe..b0b3ca6f15e 100644
--- a/chromium/ui/keyboard/resources/elements/kb-keyboard.html
+++ b/chromium/ui/keyboard/resources/elements/kb-keyboard.html
@@ -9,15 +9,22 @@
on-key-longpress="{{keyLongpress}}" on-pointerup="{{up}}"
on-pointerdown="{{down}}" on-pointerout="{{out}}"
on-enable-sel="{{enableSel}}" on-enable-dbl="{{enableDbl}}"
- on-key-out="{{keyOut}}" on-show-options="{{showOptions}}"
- on-set-layout="{{setLayout}}" on-type-key="{{type}}"
- attributes="keyset layout inputType inputTypeToLayoutMap">
+ on-key-out="{{keyOut}}" on-set-layout="{{setLayout}}" on-type-key="{{type}}"
+ attributes="inputType inputTypeToLayoutMap keyset layout volume">
<template>
<style>
- @host {
- * {
- position: relative;
- }
+ :host {
+ -webkit-user-select: none;
+ background-color: #eeeeee;
+ bottom: 0;
+ cursor: default;
+ left: 0;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
}
</style>
<!-- The ID for a keyset follows the naming convention of combining the
@@ -26,954 +33,7 @@
-- allowing the shift and spacebar keys to be common across multiple
-- keyboard layouts.
-->
- <content id="content" select="#{{layout}}-{{keyset}}"></content>
- <kb-keyboard-overlay id="overlay" hidden></kb-keyboard-overlay>
+ <content select="kb-keyset" id="content"></content>
<kb-key-codes id="keyCodeMetadata"></kb-key-codes>
</template>
- <script>
- /**
- * The repeat delay in milliseconds before a key starts repeating. Use the
- * same rate as Chromebook.
- * (See chrome/browser/chromeos/language_preferences.cc)
- * @const
- * @type {number}
- */
- var REPEAT_DELAY_MSEC = 500;
-
- /**
- * The repeat interval or number of milliseconds between subsequent
- * keypresses. Use the same rate as Chromebook.
- * @const
- * @type {number}
- */
- var REPEAT_INTERVAL_MSEC = 50;
-
- /**
- * The double click/tap interval.
- * @const
- * @type {number}
- */
- var DBL_INTERVAL_MSEC = 300;
-
- /**
- * The index of the name of the keyset when searching for all keysets.
- * @const
- * @type {number}
- */
- var REGEX_KEYSET_INDEX = 1;
-
- /**
- * The integer number of matches when searching for keysets.
- * @const
- * @type {number}
- */
- var REGEX_MATCH_COUNT = 2;
-
- /**
- * The boolean to decide if keyboard should transit to upper case keyset
- * when spacebar is pressed. If a closing punctuation is followed by a
- * spacebar, keyboard should automatically transit to upper case.
- * @type {boolean}
- */
- var enterUpperOnSpace = false;
-
- /**
- * A structure to track the currently repeating key on the keyboard.
- */
- var repeatKey = {
-
- /**
- * The timer for the delay before repeating behaviour begins.
- * @type {number|undefined}
- */
- timer: undefined,
-
- /**
- * The interval timer for issuing keypresses of a repeating key.
- * @type {number|undefined}
- */
- interval: undefined,
-
- /**
- * The key which is currently repeating.
- * @type {BaseKey|undefined}
- */
- key: undefined,
-
- /**
- * Cancel the repeat timers of the currently active key.
- */
- cancel: function() {
- clearTimeout(this.timer);
- clearInterval(this.interval);
- this.timer = undefined;
- this.interval = undefined;
- this.key = undefined;
- }
- };
-
- /**
- * The minimum movement interval needed to trigger cursor move on
- * horizontal and vertical way.
- * @const
- * @type {number}
- */
- var MIN_SWIPE_DIST_X = 50;
- var MIN_SWIPE_DIST_Y = 20;
-
- /**
- * The maximum swipe distance that will trigger hintText of a key
- * to be typed.
- * @const
- * @type {number}
- */
- var MAX_SWIPE_FLICK_DIST = 60;
-
- /**
- * The boolean to decide if it is swipe in process or finished.
- * @type {boolean}
- */
- var swipeInProgress = false;
-
- // Flag values for ctrl, alt and shift as defined by EventFlags
- // in "event_constants.h".
- // @enum {number}
- var Modifier = {
- NONE: 0,
- ALT: 8,
- CONTROL: 4,
- SHIFT: 2
- };
-
- /**
- * A structure to track the current swipe status.
- */
- var swipeTracker = {
- /**
- * The latest PointerMove event in the swipe.
- * @type {Object}
- */
- currentEvent: undefined,
-
- /**
- * Whether or not a swipe changes direction.
- * @type {false}
- */
- isComplex: false,
-
- /**
- * The count of horizontal and vertical movement.
- * @type {number}
- */
- offset_x : 0,
- offset_y : 0,
-
- /**
- * Last touch coordinate.
- * @type {number}
- */
- pre_x : 0,
- pre_y : 0,
-
- /**
- * The PointerMove event which triggered the swipe.
- * @type {Object}
- */
- startEvent: undefined,
-
- /**
- * The flag of current modifier key.
- * @type {number}
- */
- swipeFlags : 0,
-
- /**
- * Current swipe direction.
- * @type {number}
- */
- swipeDirection : 0,
-
- /**
- * The number of times we've swiped within a single swipe.
- * @type {number}
- */
- swipeIndex: 0,
-
- /**
- * Returns the combined direction of the x and y offsets.
- * @return {number} The latest direction.
- */
- getOffsetDirection: function() {
- // TODO (rsadam): Use angles to figure out the direction.
- var direction = 0;
- // Checks for horizontal swipe.
- if (Math.abs(this.offset_x) > MIN_SWIPE_DIST_X) {
- if (this.offset_x > 0) {
- direction |= SWIPE_DIRECTION.RIGHT;
- } else {
- direction |= SWIPE_DIRECTION.LEFT;
- }
- }
- // Checks for vertical swipe.
- if (Math.abs(this.offset_y) > MIN_SWIPE_DIST_Y) {
- if (this.offset_y < 0) {
- direction |= SWIPE_DIRECTION.UP;
- } else {
- direction |= SWIPE_DIRECTION.DOWN;
- }
- }
- return direction;
- },
-
- /**
- * Populates the swipe update details.
- * @param {boolean} endSwipe Whether this is the final event for this
- * swipe.
- * @return {Object} The current state of the swipeTracker.
- */
- populateDetails: function(endSwipe) {
- var detail = {};
- detail.direction = this.swipeDirection;
- detail.index = this.swipeIndex;
- detail.status = this.swipeStatus;
- detail.endSwipe = endSwipe;
- detail.startEvent = this.startEvent;
- detail.currentEvent = this.currentEvent;
- detail.isComplex = this.isComplex;
- return detail;
- },
-
- /**
- * Reset all the values when swipe finished.
- */
- resetAll: function() {
- this.offset_x = 0;
- this.offset_y = 0;
- this.pre_x = 0;
- this.pre_y = 0;
- this.swipeFlags = 0;
- this.swipeDirection = 0;
- this.swipeIndex = 0;
- this.startEvent = undefined;
- this.currentEvent = undefined;
- this.isComplex = false;
- },
-
- /**
- * Updates the swipe path with the current event.
- * @param {Object} event The PointerEvent that triggered this update.
- * @return {boolean} Whether or not to notify swipe observers.
- */
- update: function(event) {
- if(!event.isPrimary)
- return false;
- // Update priors.
- this.offset_x += event.screenX - this.pre_x;
- this.offset_y += event.screenY - this.pre_y;
- this.pre_x = event.screenX;
- this.pre_y = event.screenY;
-
- // Check if movement crosses minimum thresholds in each direction.
- var direction = this.getOffsetDirection();
- if (direction == 0)
- return false;
- // If swipeIndex is zero the current event is triggering the swipe.
- if (this.swipeIndex == 0) {
- this.startEvent = event;
- } else if (direction != this.swipeDirection) {
- // Toggle the isComplex flag.
- this.isComplex = true;
- }
- // Update the swipe tracker.
- this.swipeDirection = direction;
- this.offset_x = 0;
- this.offset_y = 0;
- this.currentEvent = event;
- this.swipeIndex++;
- return true;
- },
-
- };
-
- Polymer('kb-keyboard', {
- alt: null,
- control: null,
- dblDetail_: null,
- dblTimer_: null,
- inputType: null,
- lastPressedKey: null,
- shift: null,
- swipeHandler: null,
- voiceInput_: null,
-
- /**
- * The default input type to keyboard layout map. The key must be one of
- * the input box type values.
- * @type {object}
- */
- inputTypeToLayoutMap: {
- number: "numeric",
- text: "qwerty",
- password: "qwerty"
- },
-
- /**
- * Changes the current keyset.
- * @param {Object} detail The detail of the event that called this
- * function.
- */
- changeKeyset: function(detail) {
- if (detail.relegateToShift && this.shift) {
- this.keyset = this.shift.textKeyset;
- this.activeKeyset.nextKeyset = undefined;
- return true;
- }
- var toKeyset = detail.toKeyset;
- if (toKeyset) {
- this.keyset = toKeyset;
- this.activeKeyset.nextKeyset = detail.nextKeyset;
- return true;
- }
- return false;
- },
-
- ready: function() {
- this.voiceInput_ = new VoiceInput(this);
- this.swipeHandler = this.move.bind(this);
- },
-
- /**
- * Registers a callback for state change events. Lazy initializes a
- * mutation observer used to detect when the keyset selection is changed.
- * @param{!Function} callback Callback function to register.
- */
- addKeysetChangedObserver: function(callback) {
- if (!this.keysetChangedObserver) {
- var target = this.$.content;
- var self = this;
- var observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(m) {
- if (m.type == 'attributes' && m.attributeName == 'select') {
- var value = m.target.getAttribute('select');
- self.fire('stateChange', {
- state: 'keysetChanged',
- value: value
- });
- }
- });
- });
-
- observer.observe(target, {
- attributes: true,
- childList: true,
- subtree: true
- });
- this.keysetChangedObserver = observer;
-
- }
- this.addEventListener('stateChange', callback);
- },
-
- /**
- * Called when the type of focused input box changes. If a keyboard layout
- * is defined for the current input type, that layout will be loaded.
- * Otherwise, the keyboard layout for 'text' type will be loaded.
- */
- inputTypeChanged: function() {
- // TODO(bshe): Toggle visibility of some keys in a keyboard layout
- // according to the input type.
- var layout = this.inputTypeToLayoutMap[this.inputType];
- if (!layout)
- layout = this.inputTypeToLayoutMap.text;
- this.layout = layout;
- },
-
- /**
- * When double click/tap event is enabled, the second key-down and key-up
- * events on the same key should be skipped. Return true when the event
- * with |detail| should be skipped.
- * @param {Object} detail The detail of key-up or key-down event.
- */
- skipEvent: function(detail) {
- if (this.dblDetail_) {
- if (this.dblDetail_.char != detail.char) {
- // The second key down is not on the same key. Double click/tap
- // should be ignored.
- this.dblDetail_ = null;
- clearTimeout(this.dblTimer_);
- } else if (this.dblDetail_.clickCount == 1) {
- return true;
- }
- }
- return false;
- },
-
- /**
- * Handles a swipe update.
- * param {Object} detail The swipe update details.
- */
- onSwipeUpdate: function(detail) {
- var direction = detail.direction;
- if (!direction)
- console.error("Swipe direction cannot be: " + direction);
- // Triggers swipe editting if it's a purely horizontal swipe.
- if (!(direction & (SWIPE_DIRECTION.UP | SWIPE_DIRECTION.DOWN))) {
- // Nothing to do if the swipe has ended.
- if (detail.endSwipe)
- return;
- var modifiers = 0;
- // TODO (rsadam): This doesn't take into account index shifts caused
- // by vertical swipes.
- if (detail.index % 2 != 0) {
- modifiers |= Modifier.SHIFT;
- modifiers |= Modifier.CONTROL;
- }
- MoveCursor(direction, modifiers);
- return;
- }
- // Triggers swipe hintText if it's a purely vertical swipe.
- if (!(direction & (SWIPE_DIRECTION.LEFT | SWIPE_DIRECTION.RIGHT))) {
- // Check if event is relevant to us.
- if ((!detail.endSwipe) || (detail.isComplex))
- return;
- // Too long a swipe.
- var distance = Math.abs(detail.startEvent.screenY -
- detail.currentEvent.screenY);
- if (distance > MAX_SWIPE_FLICK_DIST)
- return;
- var triggerKey = detail.startEvent.target;
- if (triggerKey && triggerKey.onFlick)
- triggerKey.onFlick(detail);
- }
- },
-
- /**
- * This function is bound to swipeHandler. Updates the current swipe
- * status so that PointerEvents can be converted to Swipe events.
- * @param {PointerEvent} event.
- */
- move: function(event) {
- if (!swipeTracker.update(event))
- return;
- // Conversion was successful, swipe is now in progress.
- swipeInProgress = true;
- if (this.lastPressedKey) {
- this.lastPressedKey.classList.remove('active');
- this.lastPressedKey = null;
- }
- this.onSwipeUpdate(swipeTracker.populateDetails(false));
- },
-
- /**
- * Handles key-down event that is sent by kb-key-base.
- * @param {CustomEvent} event The key-down event dispatched by
- * kb-key-base.
- * @param {Object} detail The detail of pressed kb-key.
- */
- keyDown: function(event, detail) {
- if (this.skipEvent(detail))
- return;
-
- if (this.lastPressedKey) {
- this.lastPressedKey.classList.remove('active');
- this.lastPressedKey.autoRelease();
- }
- this.lastPressedKey = event.target;
- this.lastPressedKey.classList.add('active');
- repeatKey.cancel();
-
- var char = detail.char;
- switch(char) {
- case 'Shift':
- this.classList.remove('caps-locked');
- break;
- case 'Alt':
- case 'Ctrl':
- var modifier = char.toLowerCase() + "-active";
- // Removes modifier if already active.
- if (this.classList.contains(modifier))
- this.classList.remove(modifier);
- break;
- default:
- // Notify shift key.
- if (this.shift)
- this.shift.onNonControlKeyDown();
- if (this.ctrl)
- this.ctrl.onNonControlKeyDown();
- if (this.alt)
- this.alt.onNonControlKeyDown();
- break;
- }
- if(this.changeKeyset(detail))
- return;
- if (detail.repeat) {
- this.keyTyped(detail);
- this.onNonControlKeyTyped();
- repeatKey.key = this.lastPressedKey;
- var self = this;
- repeatKey.timer = setTimeout(function() {
- repeatKey.timer = undefined;
- repeatKey.interval = setInterval(function() {
- self.keyTyped(detail);
- }, REPEAT_INTERVAL_MSEC);
- }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
- }
- },
-
- /**
- * Handles key-out event that is sent by kb-shift-key.
- * @param {CustomEvent} event The key-out event dispatched by
- * kb-shift-key.
- * @param {Object} detail The detail of pressed kb-shift-key.
- */
- keyOut: function(event, detail) {
- this.changeKeyset(detail);
- },
-
- /**
- * Enable/start double click/tap event recognition.
- * @param {CustomEvent} event The enable-dbl event dispatched by
- * kb-shift-key.
- * @param {Object} detail The detail of pressed kb-shift-key.
- */
- enableDbl: function(event, detail) {
- if (!this.dblDetail_) {
- this.dblDetail_ = detail;
- this.dblDetail_.clickCount = 0;
- var self = this;
- this.dblTimer_ = setTimeout(function() {
- self.dblDetail_.callback = null;
- self.dblDetail_ = null;
- }, DBL_INTERVAL_MSEC);
- }
- },
-
- /**
- * Enable the selection while swipe.
- * @param {CustomEvent} event The enable-dbl event dispatched by
- * kb-shift-key.
- */
- enableSel: function(event) {
- // TODO(rsadam): Disabled for now. May come back if we revert swipe
- // selection to not do word selection.
- },
-
- /**
- * Handles pointerdown event. This is used for swipe selection process.
- * to get the start pre_x and pre_y. And also add a pointermove handler
- * to start handling the swipe selection event.
- * @param {PointerEvent} event The pointerup event that received by
- * kb-keyboard.
- */
- down: function(event) {
- if (event.isPrimary) {
- swipeTracker.pre_x = event.screenX;
- swipeTracker.pre_y = event.screenY;
- this.addEventListener("pointermove", this.swipeHandler, false);
- }
- },
-
- /**
- * Handles pointerup event. This is used for double tap/click events.
- * @param {PointerEvent} event The pointerup event that bubbled to
- * kb-keyboard.
- */
- up: function(event) {
- // When touch typing, it is very possible that finger moves slightly out
- // of the key area before releases. The key should not be dropped in
- // this case.
- if (this.lastPressedKey &&
- this.lastPressedKey.pointerId == event.pointerId) {
- this.lastPressedKey.autoRelease();
- }
-
- if (this.dblDetail_) {
- this.dblDetail_.clickCount++;
- if (this.dblDetail_.clickCount == 2) {
- this.dblDetail_.callback();
- this.changeKeyset(this.dblDetail_);
- clearTimeout(this.dblTimer_);
-
- this.classList.add('caps-locked');
-
- this.dblDetail_ = null;
- }
- }
-
- // TODO(zyaozhujun): There are some edge cases to deal with later.
- // (for instance, what if a second finger trigger a down and up
- // event sequence while swiping).
- // When pointer up from the screen, a swipe selection session finished,
- // all the data should be reset to prepare for the next session.
- if (event.isPrimary && swipeInProgress) {
- swipeInProgress = false;
- this.onSwipeUpdate(swipeTracker.populateDetails(true))
- swipeTracker.resetAll();
- }
- this.removeEventListener('pointermove', this.swipeHandler, false);
- },
-
- /**
- * Handles PointerOut event. This is used for when a swipe gesture goes
- * outside of the keyboard window.
- * @param {Object} event The pointerout event that bubbled to the
- * kb-keyboard.
- */
- out: function(event) {
- // Ignore if triggered from one of the keys.
- if (this.compareDocumentPosition(event.relatedTarget) &
- Node.DOCUMENT_POSITION_CONTAINED_BY)
- return;
- if (swipeInProgress)
- this.onSwipeUpdate(swipeTracker.populateDetails(true))
- // Touched outside of the keyboard area, so disables swipe.
- swipeInProgress = false;
- swipeTracker.resetAll();
- this.removeEventListener('pointermove', this.swipeHandler, false);
- },
-
- /**
- * Handles a TypeKey event. This is used for when we programmatically
- * want to type a specific key.
- * @param {CustomEvent} event The TypeKey event that bubbled to the
- * kb-keyboard.
- */
- type: function(event) {
- this.keyTyped(event.detail);
- },
-
- /**
- * Handles key-up event that is sent by kb-key-base.
- * @param {CustomEvent} event The key-up event dispatched by kb-key-base.
- * @param {Object} detail The detail of pressed kb-key.
- */
- keyUp: function(event, detail) {
- if (this.skipEvent(detail))
- return;
- if (swipeInProgress)
- return;
- if (detail.activeModifier) {
- var modifier = detail.activeModifier.toLowerCase() + "-active";
- this.classList.add(modifier);
- }
- // Adds the current keyboard modifiers to the detail.
- if (this.ctrl)
- detail.controlModifier = this.ctrl.isActive();
- if (this.alt)
- detail.altModifier = this.alt.isActive();
- if (this.lastPressedKey)
- this.lastPressedKey.classList.remove('active');
- // Keyset transition key. This is needed to transition from upper
- // to lower case when we are not in caps mode, as well as when
- // we're ending chording.
- this.changeKeyset(detail);
-
- if (this.lastPressedKey &&
- this.lastPressedKey.charValue != event.target.charValue) {
- return;
- }
- if (repeatKey.key == event.target) {
- repeatKey.cancel();
- this.lastPressedKey = null;
- return;
- }
- var toLayoutId = detail.toLayout;
- // Layout transition key.
- if (toLayoutId)
- this.layout = toLayoutId;
- var char = detail.char;
- this.lastPressedKey = null;
- // Characters that should not be typed.
- switch(char) {
- case 'Invalid':
- case 'Shift':
- case 'Ctrl':
- case 'Alt':
- enterUpperOnSpace = false;
- swipeTracker.swipeFlags = 0;
- return;
- case 'Microphone':
- this.voiceInput_.onDown();
- return;
- default:
- break;
- }
- // Tries to type the character. Resorts to insertText if that fails.
- if(!this.keyTyped(detail))
- insertText(char);
- // Post-typing logic.
- switch(char) {
- case ' ':
- if(enterUpperOnSpace) {
- enterUpperOnSpace = false;
- if (this.shift) {
- var shiftDetail = this.shift.onSpaceAfterPunctuation();
- // Check if transition defined.
- this.changeKeyset(shiftDetail);
- } else {
- console.error('Capitalization on space after punctuation \
- enabled, but cannot find target keyset.');
- }
- // Immediately return to maintain shift-state. Space is a
- // non-control key and would otherwise trigger a reset of the
- // shift key, causing a transition to lower case.
- // TODO(rsadam): Add unit test after Polymer uprev complete.
- return;
- }
- break;
- case '.':
- case '?':
- case '!':
- enterUpperOnSpace = this.shouldUpperOnSpace();
- break;
- default:
- break;
- }
- // Reset control keys.
- this.onNonControlKeyTyped();
- },
-
- /*
- * Handles key-longpress event that is sent by kb-key-base.
- * @param {CustomEvent} event The key-longpress event dispatched by
- * kb-key-base.
- * @param {Object} detail The detail of pressed key.
- */
- keyLongpress: function(event, detail) {
- // If the gesture is long press, remove the pointermove listener.
- this.removeEventListener('pointermove', this.swipeHandler, false);
- // Keyset transtion key.
- if (this.changeKeyset(detail)) {
- // Locks the keyset before removing active to prevent flicker.
- this.classList.add('caps-locked');
- // Makes last pressed key inactive if transit to a new keyset on long
- // press.
- if (this.lastPressedKey)
- this.lastPressedKey.classList.remove('active');
- }
- },
-
- /**
- * Whether we should transit to upper case when seeing a space after
- * punctuation.
- * @return {boolean}
- */
- shouldUpperOnSpace: function() {
- // TODO(rsadam): Add other input types in which we should not
- // transition to upper after a space.
- return this.inputTypeValue != 'password';
- },
-
- /**
- * Show menu for selecting a keyboard layout.
- * @param {!Event} event The triggering event.
- * @param {{left: number, top: number, width: number}} details Location of
- * the button that triggered the popup.
- */
- showOptions: function(event, details) {
- var overlay = this.$.overlay;
- if (!overlay) {
- console.error('Missing overlay.');
- return;
- }
- var menu = overlay.$.options;
- if (!menu) {
- console.error('Missing options menu.');
- }
-
- menu.hidden = false;
- overlay.hidden = false;
- var left = details.left + details.width - menu.clientWidth;
- var top = details.top - menu.clientHeight;
- menu.style.left = left + 'px';
- menu.style.top = top + 'px';
- },
-
- /**
- * Handler for the 'set-layout' event.
- * @param {!Event} event The triggering event.
- * @param {{layout: string}} details Details of the event, which contains
- * the name of the layout to activate.
- */
- setLayout: function(event, details) {
- this.layout = details.layout;
- },
-
- /**
- * Handles a change in the keyboard layout. Auto-selects the default
- * keyset for the new layout.
- */
- layoutChanged: function() {
- if (!this.selectDefaultKeyset()) {
- this.fire('stateChange', {state: 'loadingKeyset'});
-
- // Keyset selection fails if the keysets have not been loaded yet.
- var keysets = document.querySelector('#' + this.layout);
- if (keysets && keysets.content) {
- var content = flattenKeysets(keysets.content);
- this.appendChild(content);
- this.selectDefaultKeyset();
- } else {
- // Add link for the keysets if missing from the document. Force
- // a layout change after resolving the import of the link.
- var query = 'link[id=' + this.layout + ']';
- if (!document.querySelector(query)) {
- // Layout has not beeen loaded yet.
- var link = document.createElement('link');
- link.id = this.layout;
- link.setAttribute('rel', 'import');
- link.setAttribute('href', 'layouts/' + this.layout + '.html');
- document.head.appendChild(link);
-
- // Load content for the new link element.
- var self = this;
- HTMLImports.importer.load(document, function() {
- HTMLImports.parser.parseLink(link);
- self.layoutChanged();
- });
- }
- }
- }
- },
-
- /**
- * Notifies the modifier keys that a non-control key was typed. This
- * lets them reset sticky behaviour. A non-control key is defined as
- * any key that is not Control, Alt, or Shift.
- */
- onNonControlKeyTyped: function() {
- if (this.shift)
- this.shift.onNonControlKeyTyped();
- if (this.ctrl)
- this.ctrl.onNonControlKeyTyped();
- if (this.alt)
- this.alt.onNonControlKeyTyped();
- this.classList.remove('ctrl-active');
- this.classList.remove('alt-active');
- },
-
- /**
- * Id for the active keyset.
- * @type {string}
- */
- get activeKeysetId() {
- return this.layout + '-' + this.keyset;
- },
-
- /**
- * The active keyset DOM object.
- * @type {kb-keyset}
- */
- get activeKeyset() {
- return this.querySelector('#' + this.activeKeysetId);
- },
-
- /**
- * The current input type.
- * @type {string}
- */
- get inputTypeValue() {
- return this.inputType;
- },
-
- /**
- * Changes the input type if it's different from the current
- * type, else resets the keyset to the default keyset.
- * @type {string}
- */
- set inputTypeValue(value) {
- if (value == this.inputType)
- this.selectDefaultKeyset();
- else
- this.inputType = value;
- },
-
- /**
- * The keyboard is ready for input once the target keyset appears
- * in the distributed nodes for the keyboard.
- * @return {boolean} Indicates if the keyboard is ready for input.
- */
- isReady: function() {
- var keyset = this.activeKeyset;
- if (!keyset)
- return false;
- var content = this.$.content.getDistributedNodes()[0];
- return content == keyset;
- },
-
- /**
- * Generates fabricated key events to simulate typing on a
- * physical keyboard.
- * @param {Object} detail Attributes of the key being typed.
- * @return {boolean} Whether the key type succeeded.
- */
- keyTyped: function(detail) {
- var builder = this.$.keyCodeMetadata;
- if (this.shift)
- detail.shiftModifier = this.shift.isActive();
- if (this.ctrl)
- detail.controlModifier = this.ctrl.isActive();
- if (this.alt)
- detail.altModifier = this.alt.isActive();
- var downEvent = builder.createVirtualKeyEvent(detail, "keydown");
- if (downEvent) {
- sendKeyEvent(downEvent);
- sendKeyEvent(builder.createVirtualKeyEvent(detail, "keyup"));
- return true;
- }
- return false;
- },
-
- /**
- * Selects the default keyset for a layout.
- * @return {boolean} True if successful. This method can fail if the
- * keysets corresponding to the layout have not been injected.
- */
- selectDefaultKeyset: function() {
- var keysets = this.querySelectorAll('kb-keyset');
- // Full name of the keyset is of the form 'layout-keyset'.
- var regex = new RegExp('^' + this.layout + '-(.+)');
- var keysetsLoaded = false;
- for (var i = 0; i < keysets.length; i++) {
- var matches = keysets[i].id.match(regex);
- if (matches && matches.length == REGEX_MATCH_COUNT) {
- keysetsLoaded = true;
- // Without both tests for a default keyset, it is possible to get
- // into a state where multiple layouts are displayed. A
- // reproducable test case is do the following set of keyset
- // transitions: qwerty -> system -> dvorak -> qwerty.
- // TODO(kevers): Investigate why this is the case.
- if (keysets[i].isDefault ||
- keysets[i].getAttribute('isDefault') == 'true') {
- this.keyset = matches[REGEX_KEYSET_INDEX];
- this.classList.remove('caps-locked');
- this.classList.remove('alt-active');
- this.classList.remove('ctrl-active');
- // Caches shift key.
- this.shift = this.querySelector('kb-shift-key');
- if (this.shift)
- this.shift.reset();
- // Caches control key.
- this.ctrl = this.querySelector('kb-modifier-key[char=Ctrl]');
- if (this.ctrl)
- this.ctrl.reset();
- // Caches alt key.
- this.alt = this.querySelector('kb-modifier-key[char=Alt]');
- if (this.alt)
- this.alt.reset();
- this.fire('stateChange', {
- state: 'keysetLoaded',
- value: this.keyset,
- });
- keyboardLoaded();
- return true;
- }
- }
- }
- if (keysetsLoaded)
- console.error('No default keyset found for ' + this.layout);
- return false;
- }
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-keyboard.js b/chromium/ui/keyboard/resources/elements/kb-keyboard.js
new file mode 100644
index 00000000000..5933271ef26
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-keyboard.js
@@ -0,0 +1,977 @@
+// 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.
+
+/**
+ * The repeat delay in milliseconds before a key starts repeating. Use the
+ * same rate as Chromebook.
+ * (See chrome/browser/chromeos/language_preferences.cc)
+ * @const
+ * @type {number}
+ */
+var REPEAT_DELAY_MSEC = 500;
+
+/**
+ * The repeat interval or number of milliseconds between subsequent
+ * keypresses. Use the same rate as Chromebook.
+ * @const
+ * @type {number}
+ */
+var REPEAT_INTERVAL_MSEC = 50;
+
+/**
+ * The double click/tap interval.
+ * @const
+ * @type {number}
+ */
+var DBL_INTERVAL_MSEC = 300;
+
+/**
+ * The index of the name of the keyset when searching for all keysets.
+ * @const
+ * @type {number}
+ */
+var REGEX_KEYSET_INDEX = 1;
+
+/**
+ * The integer number of matches when searching for keysets.
+ * @const
+ * @type {number}
+ */
+var REGEX_MATCH_COUNT = 2;
+
+/**
+ * The boolean to decide if keyboard should transit to upper case keyset
+ * when spacebar is pressed. If a closing punctuation is followed by a
+ * spacebar, keyboard should automatically transit to upper case.
+ * @type {boolean}
+ */
+var enterUpperOnSpace = false;
+
+/**
+ * A structure to track the currently repeating key on the keyboard.
+ */
+var repeatKey = {
+
+ /**
+ * The timer for the delay before repeating behaviour begins.
+ * @type {number|undefined}
+ */
+ timer: undefined,
+
+ /**
+ * The interval timer for issuing keypresses of a repeating key.
+ * @type {number|undefined}
+ */
+ interval: undefined,
+
+ /**
+ * The key which is currently repeating.
+ * @type {BaseKey|undefined}
+ */
+ key: undefined,
+
+ /**
+ * Cancel the repeat timers of the currently active key.
+ */
+ cancel: function() {
+ clearTimeout(this.timer);
+ clearInterval(this.interval);
+ this.timer = undefined;
+ this.interval = undefined;
+ this.key = undefined;
+ }
+};
+
+/**
+ * The minimum movement interval needed to trigger cursor move on
+ * horizontal and vertical way.
+ * @const
+ * @type {number}
+ */
+var MIN_SWIPE_DIST_X = 50;
+var MIN_SWIPE_DIST_Y = 20;
+
+/**
+ * The maximum swipe distance that will trigger hintText of a key
+ * to be typed.
+ * @const
+ * @type {number}
+ */
+var MAX_SWIPE_FLICK_DIST = 60;
+
+/**
+ * The boolean to decide if it is swipe in process or finished.
+ * @type {boolean}
+ */
+var swipeInProgress = false;
+
+// Flag values for ctrl, alt and shift as defined by EventFlags
+// in "event_constants.h".
+// @enum {number}
+var Modifier = {
+ NONE: 0,
+ ALT: 8,
+ CONTROL: 4,
+ SHIFT: 2
+};
+
+/**
+ * A structure to track the current swipe status.
+ */
+var swipeTracker = {
+ /**
+ * The latest PointerMove event in the swipe.
+ * @type {Object}
+ */
+ currentEvent: undefined,
+
+ /**
+ * Whether or not a swipe changes direction.
+ * @type {false}
+ */
+ isComplex: false,
+
+ /**
+ * The count of horizontal and vertical movement.
+ * @type {number}
+ */
+ offset_x : 0,
+ offset_y : 0,
+
+ /**
+ * Last touch coordinate.
+ * @type {number}
+ */
+ pre_x : 0,
+ pre_y : 0,
+
+ /**
+ * The PointerMove event which triggered the swipe.
+ * @type {Object}
+ */
+ startEvent: undefined,
+
+ /**
+ * The flag of current modifier key.
+ * @type {number}
+ */
+ swipeFlags : 0,
+
+ /**
+ * Current swipe direction.
+ * @type {number}
+ */
+ swipeDirection : 0,
+
+ /**
+ * The number of times we've swiped within a single swipe.
+ * @type {number}
+ */
+ swipeIndex: 0,
+
+ /**
+ * Returns the combined direction of the x and y offsets.
+ * @return {number} The latest direction.
+ */
+ getOffsetDirection: function() {
+ // TODO (rsadam): Use angles to figure out the direction.
+ var direction = 0;
+ // Checks for horizontal swipe.
+ if (Math.abs(this.offset_x) > MIN_SWIPE_DIST_X) {
+ if (this.offset_x > 0) {
+ direction |= SwipeDirection.RIGHT;
+ } else {
+ direction |= SwipeDirection.LEFT;
+ }
+ }
+ // Checks for vertical swipe.
+ if (Math.abs(this.offset_y) > MIN_SWIPE_DIST_Y) {
+ if (this.offset_y < 0) {
+ direction |= SwipeDirection.UP;
+ } else {
+ direction |= SwipeDirection.DOWN;
+ }
+ }
+ return direction;
+ },
+
+ /**
+ * Populates the swipe update details.
+ * @param {boolean} endSwipe Whether this is the final event for this
+ * swipe.
+ * @return {Object} The current state of the swipeTracker.
+ */
+ populateDetails: function(endSwipe) {
+ var detail = {};
+ detail.direction = this.swipeDirection;
+ detail.index = this.swipeIndex;
+ detail.status = this.swipeStatus;
+ detail.endSwipe = endSwipe;
+ detail.startEvent = this.startEvent;
+ detail.currentEvent = this.currentEvent;
+ detail.isComplex = this.isComplex;
+ return detail;
+ },
+
+ /**
+ * Reset all the values when swipe finished.
+ */
+ resetAll: function() {
+ this.offset_x = 0;
+ this.offset_y = 0;
+ this.pre_x = 0;
+ this.pre_y = 0;
+ this.swipeFlags = 0;
+ this.swipeDirection = 0;
+ this.swipeIndex = 0;
+ this.startEvent = undefined;
+ this.currentEvent = undefined;
+ this.isComplex = false;
+ },
+
+ /**
+ * Updates the swipe path with the current event.
+ * @param {Object} event The PointerEvent that triggered this update.
+ * @return {boolean} Whether or not to notify swipe observers.
+ */
+ update: function(event) {
+ if(!event.isPrimary)
+ return false;
+ // Update priors.
+ this.offset_x += event.screenX - this.pre_x;
+ this.offset_y += event.screenY - this.pre_y;
+ this.pre_x = event.screenX;
+ this.pre_y = event.screenY;
+
+ // Check if movement crosses minimum thresholds in each direction.
+ var direction = this.getOffsetDirection();
+ if (direction == 0)
+ return false;
+ // If swipeIndex is zero the current event is triggering the swipe.
+ if (this.swipeIndex == 0) {
+ this.startEvent = event;
+ } else if (direction != this.swipeDirection) {
+ // Toggle the isComplex flag.
+ this.isComplex = true;
+ }
+ // Update the swipe tracker.
+ this.swipeDirection = direction;
+ this.offset_x = 0;
+ this.offset_y = 0;
+ this.currentEvent = event;
+ this.swipeIndex++;
+ return true;
+ },
+
+};
+
+Polymer('kb-keyboard', {
+ alt: null,
+ config: null,
+ control: null,
+ dblDetail_: null,
+ dblTimer_: null,
+ inputType: null,
+ lastPressedKey: null,
+ shift: null,
+ sounds: {},
+ stale: true,
+ swipeHandler: null,
+ voiceInput_: null,
+ //TODO(rsadam@): Add a control to let users change this.
+ volume: DEFAULT_VOLUME,
+
+ /**
+ * The default input type to keyboard layout map. The key must be one of
+ * the input box type values.
+ * @type {object}
+ */
+ inputTypeToLayoutMap: {
+ number: "numeric",
+ text: "qwerty",
+ password: "qwerty"
+ },
+
+ /**
+ * Caches the specified sound on the keyboard.
+ * @param {string} soundId The name of the .wav file in the "sounds"
+ directory.
+ */
+ addSound: function(soundId) {
+ // Check if already loaded.
+ if (soundId == Sound.NONE || this.sounds[soundId])
+ return;
+ var pool = [];
+ for (var i = 0; i < SOUND_POOL_SIZE; i++) {
+ var audio = document.createElement('audio');
+ audio.preload = "auto";
+ audio.id = soundId;
+ audio.src = "../sounds/" + soundId + ".wav";
+ audio.volume = this.volume;
+ pool.push(audio);
+ }
+ this.sounds[soundId] = pool;
+ },
+
+ /**
+ * Changes the current keyset.
+ * @param {Object} detail The detail of the event that called this
+ * function.
+ */
+ changeKeyset: function(detail) {
+ if (detail.relegateToShift && this.shift) {
+ this.keyset = this.shift.textKeyset;
+ this.activeKeyset.nextKeyset = undefined;
+ return true;
+ }
+ var toKeyset = detail.toKeyset;
+ if (toKeyset) {
+ this.keyset = toKeyset;
+ this.activeKeyset.nextKeyset = detail.nextKeyset;
+ return true;
+ }
+ return false;
+ },
+
+ keysetChanged: function() {
+ var keyset = this.activeKeyset;
+ // Show the keyset if it has been initialized.
+ if (keyset)
+ keyset.show();
+ },
+
+ configChanged: function() {
+ this.layout = this.config.layout;
+ },
+
+ ready: function() {
+ this.voiceInput_ = new VoiceInput(this);
+ this.swipeHandler = this.move.bind(this);
+ var self = this;
+ getKeyboardConfig(function(config) {
+ self.config = config;
+ });
+ },
+
+ /**
+ * Registers a callback for state change events.
+ * @param{!Function} callback Callback function to register.
+ */
+ addKeysetChangedObserver: function(callback) {
+ this.addEventListener('stateChange', callback);
+ },
+
+ /**
+ * Called when the type of focused input box changes. If a keyboard layout
+ * is defined for the current input type, that layout will be loaded.
+ * Otherwise, the keyboard layout for 'text' type will be loaded.
+ */
+ inputTypeChanged: function() {
+ // Disable layout switching at accessbility mode.
+ if (this.config && this.config.a11ymode)
+ return;
+
+ // TODO(bshe): Toggle visibility of some keys in a keyboard layout
+ // according to the input type.
+ var layout = this.inputTypeToLayoutMap[this.inputType];
+ if (!layout)
+ layout = this.inputTypeToLayoutMap.text;
+ this.layout = layout;
+ },
+
+ /**
+ * When double click/tap event is enabled, the second key-down and key-up
+ * events on the same key should be skipped. Return true when the event
+ * with |detail| should be skipped.
+ * @param {Object} detail The detail of key-up or key-down event.
+ */
+ skipEvent: function(detail) {
+ if (this.dblDetail_) {
+ if (this.dblDetail_.char != detail.char) {
+ // The second key down is not on the same key. Double click/tap
+ // should be ignored.
+ this.dblDetail_ = null;
+ clearTimeout(this.dblTimer_);
+ } else if (this.dblDetail_.clickCount == 1) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Handles a swipe update.
+ * param {Object} detail The swipe update details.
+ */
+ onSwipeUpdate: function(detail) {
+ var direction = detail.direction;
+ if (!direction)
+ console.error("Swipe direction cannot be: " + direction);
+ // Triggers swipe editting if it's a purely horizontal swipe.
+ if (!(direction & (SwipeDirection.UP | SwipeDirection.DOWN))) {
+ // Nothing to do if the swipe has ended.
+ if (detail.endSwipe)
+ return;
+ var modifiers = 0;
+ // TODO (rsadam): This doesn't take into account index shifts caused
+ // by vertical swipes.
+ if (detail.index % 2 != 0) {
+ modifiers |= Modifier.SHIFT;
+ modifiers |= Modifier.CONTROL;
+ }
+ MoveCursor(direction, modifiers);
+ return;
+ }
+ // Triggers swipe hintText if it's a purely vertical swipe.
+ if (this.activeKeyset.flick &&
+ !(direction & (SwipeDirection.LEFT | SwipeDirection.RIGHT))) {
+ // Check if event is relevant to us.
+ if ((!detail.endSwipe) || (detail.isComplex))
+ return;
+ // Too long a swipe.
+ var distance = Math.abs(detail.startEvent.screenY -
+ detail.currentEvent.screenY);
+ if (distance > MAX_SWIPE_FLICK_DIST)
+ return;
+ var triggerKey = detail.startEvent.target;
+ if (triggerKey && triggerKey.onFlick)
+ triggerKey.onFlick(detail);
+ }
+ },
+
+ /**
+ * This function is bound to swipeHandler. Updates the current swipe
+ * status so that PointerEvents can be converted to Swipe events.
+ * @param {PointerEvent} event.
+ */
+ move: function(event) {
+ if (!swipeTracker.update(event))
+ return;
+ // Conversion was successful, swipe is now in progress.
+ swipeInProgress = true;
+ if (this.lastPressedKey) {
+ this.lastPressedKey.classList.remove('active');
+ this.lastPressedKey = null;
+ }
+ this.onSwipeUpdate(swipeTracker.populateDetails(false));
+ },
+
+ /**
+ * Handles key-down event that is sent by kb-key-base.
+ * @param {CustomEvent} event The key-down event dispatched by
+ * kb-key-base.
+ * @param {Object} detail The detail of pressed kb-key.
+ */
+ keyDown: function(event, detail) {
+ if (this.skipEvent(detail))
+ return;
+
+ if (this.lastPressedKey) {
+ this.lastPressedKey.classList.remove('active');
+ this.lastPressedKey.autoRelease();
+ }
+ this.lastPressedKey = event.target;
+ this.lastPressedKey.classList.add('active');
+ repeatKey.cancel();
+ this.playSound(detail.sound);
+
+ var char = detail.char;
+ switch(char) {
+ case 'Shift':
+ this.classList.remove('caps-locked');
+ break;
+ case 'Alt':
+ case 'Ctrl':
+ var modifier = char.toLowerCase() + "-active";
+ // Removes modifier if already active.
+ if (this.classList.contains(modifier))
+ this.classList.remove(modifier);
+ break;
+ case 'Invalid':
+ // Not all Invalid keys are transition keys. Reset control keys if
+ // we pressed a transition key.
+ if (event.target.toKeyset || detail.relegateToShift)
+ this.onNonControlKeyTyped();
+ break;
+ default:
+ // Notify shift key.
+ if (this.shift)
+ this.shift.onNonControlKeyDown();
+ if (this.ctrl)
+ this.ctrl.onNonControlKeyDown();
+ if (this.alt)
+ this.alt.onNonControlKeyDown();
+ break;
+ }
+ if(this.changeKeyset(detail))
+ return;
+ if (detail.repeat) {
+ this.keyTyped(detail);
+ this.onNonControlKeyTyped();
+ repeatKey.key = this.lastPressedKey;
+ var self = this;
+ repeatKey.timer = setTimeout(function() {
+ repeatKey.timer = undefined;
+ repeatKey.interval = setInterval(function() {
+ self.playSound(detail.sound);
+ self.keyTyped(detail);
+ }, REPEAT_INTERVAL_MSEC);
+ }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
+ }
+ },
+
+ /**
+ * Handles key-out event that is sent by kb-shift-key.
+ * @param {CustomEvent} event The key-out event dispatched by
+ * kb-shift-key.
+ * @param {Object} detail The detail of pressed kb-shift-key.
+ */
+ keyOut: function(event, detail) {
+ this.changeKeyset(detail);
+ },
+
+ /**
+ * Enable/start double click/tap event recognition.
+ * @param {CustomEvent} event The enable-dbl event dispatched by
+ * kb-shift-key.
+ * @param {Object} detail The detail of pressed kb-shift-key.
+ */
+ enableDbl: function(event, detail) {
+ if (!this.dblDetail_) {
+ this.dblDetail_ = detail;
+ this.dblDetail_.clickCount = 0;
+ var self = this;
+ this.dblTimer_ = setTimeout(function() {
+ self.dblDetail_.callback = null;
+ self.dblDetail_ = null;
+ }, DBL_INTERVAL_MSEC);
+ }
+ },
+
+ /**
+ * Enable the selection while swipe.
+ * @param {CustomEvent} event The enable-dbl event dispatched by
+ * kb-shift-key.
+ */
+ enableSel: function(event) {
+ // TODO(rsadam): Disabled for now. May come back if we revert swipe
+ // selection to not do word selection.
+ },
+
+ /**
+ * Handles pointerdown event. This is used for swipe selection process.
+ * to get the start pre_x and pre_y. And also add a pointermove handler
+ * to start handling the swipe selection event.
+ * @param {PointerEvent} event The pointerup event that received by
+ * kb-keyboard.
+ */
+ down: function(event) {
+ var layout = getKeysetLayout(this.activeKeysetId);
+ var key = layout.findClosestKey(event.clientX, event.clientY);
+ if (key)
+ key.down(event);
+ if (event.isPrimary) {
+ swipeTracker.pre_x = event.screenX;
+ swipeTracker.pre_y = event.screenY;
+ this.addEventListener("pointermove", this.swipeHandler, false);
+ }
+ },
+
+ /**
+ * Handles pointerup event. This is used for double tap/click events.
+ * @param {PointerEvent} event The pointerup event that bubbled to
+ * kb-keyboard.
+ */
+ up: function(event) {
+ var layout = getKeysetLayout(this.activeKeysetId);
+ var key = layout.findClosestKey(event.clientX, event.clientY);
+ if (key)
+ key.up(event);
+ // When touch typing, it is very possible that finger moves slightly out
+ // of the key area before releases. The key should not be dropped in
+ // this case.
+ // TODO(rsadam@) Change behaviour such that the key drops and the second
+ // key gets pressed.
+ if (this.lastPressedKey &&
+ this.lastPressedKey.pointerId == event.pointerId) {
+ this.lastPressedKey.autoRelease();
+ }
+
+ if (this.dblDetail_) {
+ this.dblDetail_.clickCount++;
+ if (this.dblDetail_.clickCount == 2) {
+ this.dblDetail_.callback();
+ this.changeKeyset(this.dblDetail_);
+ clearTimeout(this.dblTimer_);
+
+ this.classList.add('caps-locked');
+
+ this.dblDetail_ = null;
+ }
+ }
+
+ // TODO(zyaozhujun): There are some edge cases to deal with later.
+ // (for instance, what if a second finger trigger a down and up
+ // event sequence while swiping).
+ // When pointer up from the screen, a swipe selection session finished,
+ // all the data should be reset to prepare for the next session.
+ if (event.isPrimary && swipeInProgress) {
+ swipeInProgress = false;
+ this.onSwipeUpdate(swipeTracker.populateDetails(true))
+ swipeTracker.resetAll();
+ }
+ this.removeEventListener('pointermove', this.swipeHandler, false);
+ },
+
+ /**
+ * Handles PointerOut event. This is used for when a swipe gesture goes
+ * outside of the keyboard window.
+ * @param {Object} event The pointerout event that bubbled to the
+ * kb-keyboard.
+ */
+ out: function(event) {
+ repeatKey.cancel();
+ // Ignore if triggered from one of the keys.
+ if (this.compareDocumentPosition(event.relatedTarget) &
+ Node.DOCUMENT_POSITION_CONTAINED_BY)
+ return;
+ if (swipeInProgress)
+ this.onSwipeUpdate(swipeTracker.populateDetails(true))
+ // Touched outside of the keyboard area, so disables swipe.
+ swipeInProgress = false;
+ swipeTracker.resetAll();
+ this.removeEventListener('pointermove', this.swipeHandler, false);
+ },
+
+ /**
+ * Handles a TypeKey event. This is used for when we programmatically
+ * want to type a specific key.
+ * @param {CustomEvent} event The TypeKey event that bubbled to the
+ * kb-keyboard.
+ */
+ type: function(event) {
+ this.keyTyped(event.detail);
+ },
+
+ /**
+ * Handles key-up event that is sent by kb-key-base.
+ * @param {CustomEvent} event The key-up event dispatched by kb-key-base.
+ * @param {Object} detail The detail of pressed kb-key.
+ */
+ keyUp: function(event, detail) {
+ if (this.skipEvent(detail))
+ return;
+ if (swipeInProgress)
+ return;
+ if (detail.activeModifier) {
+ var modifier = detail.activeModifier.toLowerCase() + "-active";
+ this.classList.add(modifier);
+ }
+ // Adds the current keyboard modifiers to the detail.
+ if (this.ctrl)
+ detail.controlModifier = this.ctrl.isActive();
+ if (this.alt)
+ detail.altModifier = this.alt.isActive();
+ if (this.lastPressedKey)
+ this.lastPressedKey.classList.remove('active');
+ // Keyset transition key. This is needed to transition from upper
+ // to lower case when we are not in caps mode, as well as when
+ // we're ending chording.
+ this.changeKeyset(detail);
+
+ if (this.lastPressedKey &&
+ this.lastPressedKey.charValue != event.target.charValue) {
+ return;
+ }
+ if (repeatKey.key == event.target) {
+ repeatKey.cancel();
+ this.lastPressedKey = null;
+ return;
+ }
+ var toLayoutId = detail.toLayout;
+ // Layout transition key.
+ if (toLayoutId)
+ this.layout = toLayoutId;
+ var char = detail.char;
+ this.lastPressedKey = null;
+ // Characters that should not be typed.
+ switch(char) {
+ case 'Invalid':
+ case 'Shift':
+ case 'Ctrl':
+ case 'Alt':
+ enterUpperOnSpace = false;
+ swipeTracker.swipeFlags = 0;
+ return;
+ case 'Microphone':
+ this.voiceInput_.onDown();
+ return;
+ default:
+ break;
+ }
+ // Tries to type the character. Resorts to insertText if that fails.
+ if(!this.keyTyped(detail))
+ insertText(char);
+ // Post-typing logic.
+ switch(char) {
+ case '\n':
+ case ' ':
+ if(enterUpperOnSpace) {
+ enterUpperOnSpace = false;
+ if (this.shift) {
+ var shiftDetail = this.shift.onSpaceAfterPunctuation();
+ // Check if transition defined.
+ this.changeKeyset(shiftDetail);
+ } else {
+ console.error('Capitalization on space after punctuation \
+ enabled, but cannot find target keyset.');
+ }
+ // Immediately return to maintain shift-state. Space is a
+ // non-control key and would otherwise trigger a reset of the
+ // shift key, causing a transition to lower case.
+ return;
+ }
+ break;
+ case '.':
+ case '?':
+ case '!':
+ enterUpperOnSpace = this.shouldUpperOnSpace();
+ break;
+ default:
+ enterUpperOnSpace = false;
+ break;
+ }
+ // Reset control keys.
+ this.onNonControlKeyTyped();
+ },
+
+ /*
+ * Handles key-longpress event that is sent by kb-key-base.
+ * @param {CustomEvent} event The key-longpress event dispatched by
+ * kb-key-base.
+ * @param {Object} detail The detail of pressed key.
+ */
+ keyLongpress: function(event, detail) {
+ // If the gesture is long press, remove the pointermove listener.
+ this.removeEventListener('pointermove', this.swipeHandler, false);
+ // Keyset transtion key.
+ if (this.changeKeyset(detail)) {
+ // Locks the keyset before removing active to prevent flicker.
+ this.classList.add('caps-locked');
+ // Makes last pressed key inactive if transit to a new keyset on long
+ // press.
+ if (this.lastPressedKey)
+ this.lastPressedKey.classList.remove('active');
+ }
+ },
+
+ /**
+ * Plays the specified sound.
+ * @param {Sound} sound The id of the audio tag.
+ */
+ playSound: function(sound) {
+ if (!SOUND_ENABLED || !sound || sound == Sound.NONE)
+ return;
+ var pool = this.sounds[sound];
+ if (!pool) {
+ console.error("Cannot find audio tag: " + sound);
+ return;
+ }
+ // Search the sound pool for a free resource.
+ for (var i = 0; i < pool.length; i++) {
+ if (pool[i].paused) {
+ pool[i].play();
+ return;
+ }
+ }
+ },
+
+ /**
+ * Whether we should transit to upper case when seeing a space after
+ * punctuation.
+ * @return {boolean}
+ */
+ shouldUpperOnSpace: function() {
+ // TODO(rsadam): Add other input types in which we should not
+ // transition to upper after a space.
+ return this.inputTypeValue != 'password';
+ },
+
+ /**
+ * Handler for the 'set-layout' event.
+ * @param {!Event} event The triggering event.
+ * @param {{layout: string}} details Details of the event, which contains
+ * the name of the layout to activate.
+ */
+ setLayout: function(event, details) {
+ this.layout = details.layout;
+ },
+
+ /**
+ * Handles a change in the keyboard layout. Auto-selects the default
+ * keyset for the new layout.
+ */
+ layoutChanged: function() {
+ this.stale = true;
+ if (!this.selectDefaultKeyset()) {
+ console.error('No default keyset found for layout: ' + this.layout);
+ return;
+ }
+ this.activeKeyset.show();
+ },
+
+ /**
+ * Notifies the modifier keys that a non-control key was typed. This
+ * lets them reset sticky behaviour. A non-control key is defined as
+ * any key that is not Control, Alt, or Shift.
+ */
+ onNonControlKeyTyped: function() {
+ if (this.shift)
+ this.shift.onNonControlKeyTyped();
+ if (this.ctrl)
+ this.ctrl.onNonControlKeyTyped();
+ if (this.alt)
+ this.alt.onNonControlKeyTyped();
+ this.classList.remove('ctrl-active');
+ this.classList.remove('alt-active');
+ },
+
+ /**
+ * Callback function for when volume is changed.
+ */
+ volumeChanged: function() {
+ var toChange = Object.keys(this.sounds);
+ for (var i = 0; i < toChange.length; i++) {
+ var pool = this.sounds[toChange[i]];
+ for (var j = 0; j < pool.length; j++) {
+ pool[j].volume = this.volume;
+ }
+ }
+ },
+
+ /**
+ * Id for the active keyset.
+ * @type {string}
+ */
+ get activeKeysetId() {
+ return this.layout + '-' + this.keyset;
+ },
+
+ /**
+ * The active keyset DOM object.
+ * @type {kb-keyset}
+ */
+ get activeKeyset() {
+ return this.querySelector('#' + this.activeKeysetId);
+ },
+
+ /**
+ * The current input type.
+ * @type {string}
+ */
+ get inputTypeValue() {
+ return this.inputType;
+ },
+
+ /**
+ * Changes the input type if it's different from the current
+ * type, else resets the keyset to the default keyset.
+ * @type {string}
+ */
+ set inputTypeValue(value) {
+ if (value == this.inputType)
+ this.selectDefaultKeyset();
+ else
+ this.inputType = value;
+ },
+
+ /**
+ * The keyboard is ready for input once the target keyset appears
+ * in the distributed nodes for the keyboard.
+ * @return {boolean} Indicates if the keyboard is ready for input.
+ */
+ isReady: function() {
+ var keyset = this.activeKeyset;
+ if (!keyset)
+ return false;
+ var nodes = this.$.content.getDistributedNodes();
+ for (var i = 0; i < nodes.length; i++) {
+ if (nodes[i].id && nodes[i].id == keyset.id)
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Generates fabricated key events to simulate typing on a
+ * physical keyboard.
+ * @param {Object} detail Attributes of the key being typed.
+ * @return {boolean} Whether the key type succeeded.
+ */
+ keyTyped: function(detail) {
+ var builder = this.$.keyCodeMetadata;
+ if (this.ctrl)
+ detail.controlModifier = this.ctrl.isActive();
+ if (this.alt)
+ detail.altModifier = this.alt.isActive();
+ var downEvent = builder.createVirtualKeyEvent(detail, "keydown");
+ if (downEvent) {
+ sendKeyEvent(downEvent);
+ sendKeyEvent(builder.createVirtualKeyEvent(detail, "keyup"));
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Selects the default keyset for a layout.
+ * @return {boolean} True if successful. This method can fail if the
+ * keysets corresponding to the layout have not been injected.
+ */
+ selectDefaultKeyset: function() {
+ var keysets = this.querySelectorAll('kb-keyset');
+ // Full name of the keyset is of the form 'layout-keyset'.
+ var regex = new RegExp('^' + this.layout + '-(.+)');
+ var keysetsLoaded = false;
+ for (var i = 0; i < keysets.length; i++) {
+ var matches = keysets[i].id.match(regex);
+ if (matches && matches.length == REGEX_MATCH_COUNT) {
+ keysetsLoaded = true;
+ // Without both tests for a default keyset, it is possible to get
+ // into a state where multiple layouts are displayed. A
+ // reproducable test case is do the following set of keyset
+ // transitions: qwerty -> system -> dvorak -> qwerty.
+ // TODO(kevers): Investigate why this is the case.
+ if (keysets[i].isDefault ||
+ keysets[i].getAttribute('isDefault') == 'true') {
+ this.keyset = matches[REGEX_KEYSET_INDEX];
+ this.classList.remove('caps-locked');
+ this.classList.remove('alt-active');
+ this.classList.remove('ctrl-active');
+ // Caches shift key.
+ this.shift = this.querySelector('kb-shift-key');
+ if (this.shift)
+ this.shift.reset();
+ // Caches control key.
+ this.ctrl = this.querySelector('kb-modifier-key[char=Ctrl]');
+ if (this.ctrl)
+ this.ctrl.reset();
+ // Caches alt key.
+ this.alt = this.querySelector('kb-modifier-key[char=Alt]');
+ if (this.alt)
+ this.alt.reset();
+ this.fire('stateChange', {
+ state: 'keysetLoaded',
+ value: this.keyset,
+ });
+ keyboardLoaded();
+ return true;
+ }
+ }
+ }
+ if (keysetsLoaded)
+ console.error('No default keyset found for ' + this.layout);
+ return false;
+ }
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-keyset.html b/chromium/ui/keyboard/resources/elements/kb-keyset.html
index 1089385e26e..94940642884 100644
--- a/chromium/ui/keyboard/resources/elements/kb-keyset.html
+++ b/chromium/ui/keyboard/resources/elements/kb-keyset.html
@@ -4,80 +4,18 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-keyset" attributes="nextKeyset isDefault"
- on-key-up="{{keyUp}}" on-key-longpress="{{keyLongpress}}">
+<polymer-element name="kb-keyset" attributes="align flick isDefault nextKeyset
+ pitch weightRight weightTop weightBottom" on-key-up="{{keyUp}}"
+ on-key-longpress="{{keyLongpress}}">
<template>
<style>
- :host {
- -webkit-box-flex: 1;
- -webkit-box-orient: vertical;
- display: -webkit-box;
+ :host(:not(.activeKeyset)) {
+ display: none;
}
</style>
<content select="kb-row"></content>
<content select="kb-altkey-container" id="altkeyContainer"
touch-action="none"></content>
- <kb-altkey-data id="altkeyMetadata"></kb-altkey-data>
+ <kb-altkey-data id="altkeyMetadata"></kb-altkey-data>
</template>
- <script>
- Polymer('kb-keyset', {
- isDefault: false,
- nextKeyset: undefined,
- // TODO(bshe): support select keyset on down, long and dbl events.
- keyUp: function(event, detail) {
- switch (detail.char) {
- case 'Shift':
- case 'Alt':
- case 'Ctrl':
- return;
- default:
- break;
- }
- if (!detail.toKeyset)
- detail.toKeyset = this.nextKeyset;
- },
- keyLongpress: function(event, detail) {
- if (!detail.char)
- return;
-
- var altkeyContainer = this.$.altkeyContainer.getDistributedNodes()[0];
- if (!altkeyContainer)
- return;
-
- var altkeyMetadata = this.$.altkeyMetadata;
- var altkeys = altkeyMetadata.getAltkeys(detail.char,
- !!detail.hintText);
- if (!altkeys)
- return;
-
- var id = altkeys.id;
- var activeAltKeySet = altkeyContainer.querySelector('#' + id);
- if (!activeAltKeySet) {
- var keyWidth = event.target.clientWidth;
- var leftMargin = event.target.offsetLeft;
- var maxLeftOffset = Math.round(leftMargin / keyWidth);
- var rightMargin = this.clientWidth - leftMargin - keyWidth;
- var maxRightOffset = Math.round(rightMargin / keyWidth);
- activeAltKeySet = altkeyMetadata.createAltkeySet(detail.char,
- maxLeftOffset,
- maxRightOffset,
- detail.hintText);
- altkeyContainer.appendChild(activeAltKeySet);
- }
-
- altkeyContainer.keyset = id;
- event.target.dropKey();
- activeAltKeySet.style.width = event.target.clientWidth *
- activeAltKeySet.childElementCount + 'px';
- activeAltKeySet.style.height = event.target.clientHeight + 'px';
- activeAltKeySet.style.top = event.target.offsetTop + 'px';
- var leftOffset = activeAltKeySet.offset * event.target.clientWidth;
- activeAltKeySet.style.left = event.target.offsetLeft - leftOffset +
- 'px';
- var nodes = activeAltKeySet.childNodes;
- nodes[activeAltKeySet.offset].classList.add('active');
- altkeyContainer.hidden = false;
- }
- });
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-keyset.js b/chromium/ui/keyboard/resources/elements/kb-keyset.js
new file mode 100644
index 00000000000..60a0a015e67
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-keyset.js
@@ -0,0 +1,104 @@
+// 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.
+
+Polymer('kb-keyset', {
+ align: "center",
+ // Propagate flick gestures to keys in this keyset.
+ flick: true,
+ isDefault: false,
+ nextKeyset: undefined,
+ // Weight offsets for positioning the keyset.
+ weightBottom: 15,
+ weightLeft: 10,
+ weightRight: 10,
+ weightTop: 6,
+
+ /**
+ * Weight assigned to space between keys, of the form "xPitch yPitch".
+ * Defaults to xPitch = yPitch if it's only a single number.
+ * @type {string}
+ */
+ pitch: "10",
+
+ /**
+ * Expands kb-key-sequences into individual keys.
+ */
+ flattenKeyset: function() {
+ var keySequences = this.querySelectorAll('kb-key-sequence');
+ if (keySequences.length != 0) {
+ keySequences.array().forEach(function(element) {
+ var generatedDom = element.generateDom();
+ element.parentNode.replaceChild(generatedDom, element);
+ });
+ }
+ },
+
+ // TODO(bshe): support select keyset on down, long and dbl events.
+ keyUp: function(event, detail) {
+ switch (detail.char) {
+ case 'Shift':
+ case 'Alt':
+ case 'Ctrl':
+ case 'Invalid':
+ return;
+ default:
+ break;
+ }
+ if (!detail.toKeyset)
+ detail.toKeyset = this.nextKeyset;
+ },
+ keyLongpress: function(event, detail) {
+ if (!detail.char)
+ return;
+
+ var altkeyContainer = this.$.altkeyContainer.getDistributedNodes()[0];
+ if (!altkeyContainer)
+ return;
+
+ var altkeyMetadata = this.$.altkeyMetadata;
+ var altkeys = altkeyMetadata.getAltkeys(detail.char,
+ !!detail.hintText);
+ if (!altkeys)
+ return;
+
+ var id = altkeys.id;
+ var activeAltKeySet = altkeyContainer.querySelector('#' + id);
+ if (!activeAltKeySet) {
+ var keyWidth = event.target.clientWidth;
+ var leftMargin = event.target.offsetLeft;
+ var maxLeftOffset = Math.round(leftMargin / keyWidth);
+ var rightMargin = this.clientWidth - leftMargin - keyWidth;
+ var maxRightOffset = Math.round(rightMargin / keyWidth);
+ activeAltKeySet = altkeyMetadata.createAltkeySet(detail.char,
+ maxLeftOffset,
+ maxRightOffset,
+ detail.hintText);
+ altkeyContainer.appendChild(activeAltKeySet);
+ }
+
+ altkeyContainer.keyset = id;
+ event.target.dropKey();
+ activeAltKeySet.style.width = event.target.clientWidth *
+ activeAltKeySet.childElementCount + 'px';
+ activeAltKeySet.style.height = event.target.clientHeight + 'px';
+ activeAltKeySet.style.top = event.target.offsetTop + 'px';
+ var leftOffset = activeAltKeySet.offset * event.target.clientWidth;
+ activeAltKeySet.style.left = event.target.offsetLeft - leftOffset +
+ 'px';
+ var nodes = activeAltKeySet.childNodes;
+ nodes[activeAltKeySet.offset].classList.add('active');
+ altkeyContainer.hidden = false;
+ },
+
+ show: function() {
+ var old = $('keyboard').querySelector('.activeKeyset');
+ if (old && old != this)
+ old.classList.remove('activeKeyset');
+ this.classList.add('activeKeyset');
+ this.fire('stateChange', {
+ state: 'keysetChanged',
+ value: this.id
+ });
+ },
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-modifier-key.html b/chromium/ui/keyboard/resources/elements/kb-modifier-key.html
index adba4765562..1a742ccec5d 100644
--- a/chromium/ui/keyboard/resources/elements/kb-modifier-key.html
+++ b/chromium/ui/keyboard/resources/elements/kb-modifier-key.html
@@ -6,137 +6,4 @@
<polymer-element name="kb-modifier-key" class="unlocked dark" extends="kb-key"
on-pointerout="{{out}}">
- <script>
- (function () {
-
- /**
- * The possible states of the key.
- * @const
- * @type {Enum}
- */
- var KEY_STATES = {
- PRESSED: "pressed", // Key-down.
- UNLOCKED: "unlocked", // Default state.
- TAPPED: "tapped", // Key-down followed by key-up.
- CHORDING: "chording", // Chording mode.
- };
-
- /**
- * A map of the state of all modifier keys.
- * @type {Object}
- */
- var states = {};
-
- Polymer('kb-modifier-key', {
- up: function(event) {
- if (this.state == KEY_STATES.PRESSED)
- this.state = KEY_STATES.TAPPED;
- else
- this.state = KEY_STATES.UNLOCKED;
- this.super([event]);
- },
-
- down: function(event) {
- // First transition state so that populateDetails generates
- // correct data.
- switch (this.state) {
- case KEY_STATES.UNLOCKED:
- this.state = KEY_STATES.PRESSED;
- break;
- case KEY_STATES.TAPPED:
- this.state = KEY_STATES.UNLOCKED;
- break;
- case KEY_STATES.PRESSED:
- case KEY_STATES.CHORDING:
- // We pressed another key at the same time,
- // so ignore second press.
- return;
- default:
- console.error("Undefined key state: " + state);
- break;
- }
- this.super([event]);
- },
-
- /**
- * Returns whether the modifier for this key is active.
- * @return {boolean}
- */
- isActive: function() {
- return this.state != KEY_STATES.UNLOCKED;
- },
-
- /**
- * Notifies key that a non-control keyed down.
- * A control key is defined as one of shift, control or alt.
- */
- onNonControlKeyDown: function() {
- switch(this.state) {
- case (KEY_STATES.PRESSED):
- this.state = KEY_STATES.CHORDING;
- break;
- }
- },
-
- /**
- * Notifies key that a non-control keyed was typed.
- * A control key is defined as one of shift, control or alt.
- */
- onNonControlKeyTyped: function() {
- switch(this.state) {
- case (KEY_STATES.TAPPED):
- this.state = KEY_STATES.UNLOCKED;
- break;
- }
- },
-
- /**
- * Called on a pointer-out event. Ends chording.
- * @param {event} event The pointer-out event.
- */
- out: function(event) {
- // TODO(rsadam): Add chording event so that we don't reset
- // when shift-chording.
- if (this.state == KEY_STATES.CHORDING) {
- this.state = KEY_STATES.UNLOCKED;
- }
- },
-
- /*
- * Overrides the autoRelease function to enable chording.
- */
- autoRelease: function() {
- },
-
- populateDetails: function(caller) {
- var detail = this.super([caller]);
- if (this.state != KEY_STATES.UNLOCKED)
- detail.activeModifier = this.charValue;
- return detail;
- },
-
- /**
- * Resets the modifier key state.
- */
- reset: function() {
- this.state = KEY_STATES.UNLOCKED;
- },
-
- get state() {
- var key = this.charValue;
- if (!key)
- console.error("missing key for kb-modifier-key state: " + this);
- // All keys default to the unlock state.
- if (!(key in states))
- states[key] = KEY_STATES.UNLOCKED;
- return states[key];
- },
-
- set state(value) {
- var key = this.charValue;
- states[key] = value;
- }
- });
- })();
- </script>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-modifier-key.js b/chromium/ui/keyboard/resources/elements/kb-modifier-key.js
new file mode 100644
index 00000000000..0f9fd8a1da0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-modifier-key.js
@@ -0,0 +1,135 @@
+// 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.
+
+(function () {
+
+ /**
+ * The possible states of the key.
+ * @const
+ * @type {Enum}
+ */
+ var KEY_STATES = {
+ PRESSED: "pressed", // Key-down.
+ UNLOCKED: "unlocked", // Default state.
+ TAPPED: "tapped", // Key-down followed by key-up.
+ CHORDING: "chording", // Chording mode.
+ };
+
+ /**
+ * A map of the state of all modifier keys.
+ * @type {Object}
+ */
+ var states = {};
+
+ Polymer('kb-modifier-key', {
+ up: function(event) {
+ if (this.state == KEY_STATES.PRESSED)
+ this.state = KEY_STATES.TAPPED;
+ else
+ this.state = KEY_STATES.UNLOCKED;
+ this.super([event]);
+ },
+
+ down: function(event) {
+ // First transition state so that populateDetails generates
+ // correct data.
+ switch (this.state) {
+ case KEY_STATES.UNLOCKED:
+ this.state = KEY_STATES.PRESSED;
+ break;
+ case KEY_STATES.TAPPED:
+ this.state = KEY_STATES.UNLOCKED;
+ break;
+ case KEY_STATES.PRESSED:
+ case KEY_STATES.CHORDING:
+ // We pressed another key at the same time,
+ // so ignore second press.
+ return;
+ default:
+ console.error("Undefined key state: " + state);
+ break;
+ }
+ this.super([event]);
+ },
+
+ /**
+ * Returns whether the modifier for this key is active.
+ * @return {boolean}
+ */
+ isActive: function() {
+ return this.state != KEY_STATES.UNLOCKED;
+ },
+
+ /**
+ * Notifies key that a non-control keyed down.
+ * A control key is defined as one of shift, control or alt.
+ */
+ onNonControlKeyDown: function() {
+ switch(this.state) {
+ case (KEY_STATES.PRESSED):
+ this.state = KEY_STATES.CHORDING;
+ break;
+ }
+ },
+
+ /**
+ * Notifies key that a non-control keyed was typed.
+ * A control key is defined as one of shift, control or alt.
+ */
+ onNonControlKeyTyped: function() {
+ switch(this.state) {
+ case (KEY_STATES.TAPPED):
+ this.state = KEY_STATES.UNLOCKED;
+ break;
+ }
+ },
+
+ /**
+ * Called on a pointer-out event. Ends chording.
+ * @param {event} event The pointer-out event.
+ */
+ out: function(event) {
+ // TODO(rsadam): Add chording event so that we don't reset
+ // when shift-chording.
+ if (this.state == KEY_STATES.CHORDING) {
+ this.state = KEY_STATES.UNLOCKED;
+ }
+ },
+
+ /*
+ * Overrides the autoRelease function to enable chording.
+ */
+ autoRelease: function() {
+ },
+
+ populateDetails: function(caller) {
+ var detail = this.super([caller]);
+ if (this.state != KEY_STATES.UNLOCKED)
+ detail.activeModifier = this.charValue;
+ return detail;
+ },
+
+ /**
+ * Resets the modifier key state.
+ */
+ reset: function() {
+ this.state = KEY_STATES.UNLOCKED;
+ },
+
+ get state() {
+ var key = this.charValue;
+ if (!key)
+ console.error("missing key for kb-modifier-key state: " + this);
+ // All keys default to the unlock state.
+ if (!(key in states))
+ states[key] = KEY_STATES.UNLOCKED;
+ return states[key];
+ },
+
+ set state(value) {
+ var key = this.charValue;
+ states[key] = value;
+ }
+ });
+})();
diff --git a/chromium/ui/keyboard/resources/elements/kb-options-menu.html b/chromium/ui/keyboard/resources/elements/kb-options-menu.html
deleted file mode 100644
index f33bd3c82bb..00000000000
--- a/chromium/ui/keyboard/resources/elements/kb-options-menu.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!--
- -- Copyright 2013 The Chromium Authors. All rights reserved.
- -- Use of this source code is governed by a BSD-style license that can be
- -- found in the LICENSE file.
- -->
-
-<polymer-element name="kb-options-menu-item" attributes="layout label active"
- on-pointerup="up" on-pointerover="over" on-pointerout="out">
- <template>
- <style>
- @host {
- * {
- -webkit-padding-end: 5px;
- -webkit-padding-start: 5px;
- color: #fff;
- display: -webkit-box;
- font-family: 'Open Sans', 'Noto Sans UI', sans-serif;
- font-weight: 300;
- height: 28px;
- }
- *.active {
- background-color: #848490;
- }
- </style>
- <span>{{label}}</span>
- </template>
- <script>
- Polymer('kb-options-menu-item', {
- /**
- * Layout to select on a key press.
- */
- layout: null,
-
- up: function(event) {
- if (this.layout == 'none')
- hideKeyboard();
- else
- this.fire('set-layout', {layout: this.layout});
- this.hidden = true;
- },
-
- over: function(event) {
- this.classList.add('active');
- },
-
- out: function(event) {
- this.classList.remove('active');
- },
- });
- </script>
-</polymer>
-
-<polymer-element name="kb-options-menu">
- <template>
- <style>
- @host {
- * {
- -webkit-box-orient: vertical;
- background-color: #3b3b3e;
- border-radius: 2px;
- display: -webkit-box;
- left: 0;
- position: absolute;
- top: 0;
- z-index: 1;
- }
- }
- </style>
- <!-- TODO(kevers): This is a temporary placeholder to enable testing
- -- of layout switching. Deprecate once a decision is reached on
- -- a more permanent solution for layout selection. -->
- <kb-options-menu-item layout="system-qwerty" label="System QWERTY">
- </kb-options-menu-item>
- <kb-options-menu-item layout="qwerty" label="QWERTY">
- </kb-options-menu-item>
- <kb-options-menu-item layout="dvorak" label="Dvorak">
- </kb-options-menu-item>
- <kb-options-menu-item layout="none" label="Hide keyboard">
- </kb-options-menu-item>
- </template>
- <script>
- Polymer('kb-options-menu', {});
- </script>
-</polymer>
-
-<polymer-element name="kb-keyboard-overlay" attributes="keyset"
- on-pointerup="up">
- <template>
- <style>
- @host {
- * {
- background-color: rgba(0, 0, 0, 0.6);
- bottom: 0;
- left: 0;
- position: absolute;
- right: 0;
- top: 0;
- }
- }
- </style>
- <!-- Insert popups here. -->
- <kb-options-menu id="options" hidden></kb-options-menu>
- </template>
- <script>
- Polymer('kb-keyboard-overlay', {
- up: function() {
- this.hidden = true;
- }
- });
- </script>
-</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-row.html b/chromium/ui/keyboard/resources/elements/kb-row.html
index 0398587daa2..6d0f254fe3e 100644
--- a/chromium/ui/keyboard/resources/elements/kb-row.html
+++ b/chromium/ui/keyboard/resources/elements/kb-row.html
@@ -1,31 +1,22 @@
<!--
- -- Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ -- Copyright 2013 The Chromium Authors. All rights reserved.
-- Use of this source code is governed by a BSD-style license that can be
-- found in the LICENSE file.
-->
-<polymer-element name="kb-row">
+<polymer-element name="kb-row" attributes="align weight">
<template>
<style>
- @host {
- * {
- -webkit-box-flex: 1;
- display: -webkit-box;
- text-align: center;
- margin-right: 0.25em;
- margin-top: 0.25em;
- }
- *:last-of-type {
- margin-bottom: 0.25em;
- }
- }
- content::-webkit-distributed(kb-key) {
- -webkit-flex: 1 auto;
- }
+ :host() {
+ text-align: center;
+ margin-right: 0.25em;
+ margin-top: 0.25em;
+ }
+ :host(:last-of-type) {
+ margin-bottom: 0.25em;
+ }
</style>
<content select="*"></content>
</template>
- <script>
- Polymer('kb-row');
- </script>
+
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-row.js b/chromium/ui/keyboard/resources/elements/kb-row.js
new file mode 100644
index 00000000000..d32a94f47cf
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-row.js
@@ -0,0 +1,8 @@
+// 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.
+
+Polymer('kb-row', {
+ align: RowAlignment.STRETCH,
+ weight: DEFAULT_KEY_WEIGHT,
+});
diff --git a/chromium/ui/keyboard/resources/elements/kb-shift-key.html b/chromium/ui/keyboard/resources/elements/kb-shift-key.html
index 4778b622134..dca707af116 100644
--- a/chromium/ui/keyboard/resources/elements/kb-shift-key.html
+++ b/chromium/ui/keyboard/resources/elements/kb-shift-key.html
@@ -4,251 +4,32 @@
-- found in the LICENSE file.
-->
-<polymer-element name="kb-shift-key"
- attributes="lowerCaseKeysetId upperCaseKeysetId"
- class="shift dark" char="Shift" on-pointerout="{{out}}" extends="kb-key">
- <script>
- (function () {
-
- /**
- * The possible states of the shift key.
- * Unlocked is the default state. Locked for capslocked, pressed is a
- * key-down and tapped for a key-down followed by an immediate key-up.
- * @const
- * @type {Enum}
- */
- var KEY_STATES = {
- PRESSED: "pressed", // Key-down on shift key.
- LOCKED: "locked", // Key is capslocked.
- UNLOCKED: "unlocked", // Default state.
- TAPPED: "tapped", // Key-down followed by key-up.
- CHORDING: "chording" // Key-down followed by other keys.
- };
-
- /**
- * The pointerdown event on shiftkey that may eventually trigger chording
- * state. pointerId and eventTarget are the two fields that is used now.
- * @type {PointerEvent}
- */
- var enterChordingEvent = undefined;
-
- /**
- * Uses a closure to define one long press timer among all shift keys
- * regardless of the layout they are in.
- * @type {function}
- */
- var shiftLongPressTimer = undefined;
-
- /**
- * The current state of the shift key.
- * @type {Enum}
- */
- var state = KEY_STATES.UNLOCKED;
-
- Polymer('kb-shift-key', {
- /**
- * Defines how capslock effects keyset transition. We always transition
- * from the lowerCaseKeysetId to the upperCaseKeysetId if capslock is
- * on.
- * @type {string}
- */
- lowerCaseKeysetId: 'lower',
- upperCaseKeysetId: 'upper',
-
- up: function(event) {
- if (state == KEY_STATES.CHORDING &&
- event.pointerId != enterChordingEvent.pointerId) {
- // Disables all other pointer events on shift keys when chording.
- return;
- }
- switch (state) {
- case KEY_STATES.PRESSED:
- state = KEY_STATES.TAPPED;
- break;
- case KEY_STATES.CHORDING:
- // Leaves chording only if the pointer that triggered it is
- // released.
- state = KEY_STATES.UNLOCKED;
- break;
- default:
- break;
- }
- // When releasing the shift key, it is not the same shift key that was
- // pressed. Updates the pointerId of the releasing shift key to make
- // sure key-up event fires correctly in kb-key-base.
- this.pointerId = enterChordingEvent.pointerId;
- this.super([event]);
- },
-
- out: function(event) {
- // Sliding off the shift key while chording is treated as a key-up.
- // Note that we switch to a new keyset on shift keydown, and a finger
- // movement on the new shift key will trigger this function being
- // called on the old shift key. We should not end chording in that
- // case.
- if (state == KEY_STATES.CHORDING &&
- event.pointerId == enterChordingEvent.pointerId &&
- event.target != enterChordingEvent.target) {
- state = KEY_STATES.UNLOCKED;
- var detail = this.populateDetails('out');
- this.fire("key-out", detail);
- }
- },
-
- down: function(event) {
- // First transition state so that populateDetails generates
- // correct data.
- switch (state) {
- case KEY_STATES.UNLOCKED:
- state = KEY_STATES.PRESSED;
- break;
- case KEY_STATES.TAPPED:
- case KEY_STATES.LOCKED:
- state = KEY_STATES.UNLOCKED;
- break;
- case KEY_STATES.PRESSED:
- case KEY_STATES.CHORDING:
- // We pressed another shift key at the same time,
- // so ignore second press.
- return;
- default:
- console.error("Undefined shift key state: " + state);
- break;
- }
- enterChordingEvent = event;
- // Trigger parent behaviour.
- this.super([event]);
- this.fire('enable-sel');
- // Populate double click transition details.
- var detail = {};
- detail.char = this.char || this.textContent;
- detail.toKeyset = this.upperCaseKeysetId;
- detail.nextKeyset = undefined;
- detail.callback = this.onDoubleClick;
- this.fire('enable-dbl', detail);
- },
-
- generateLongPressTimer: function() {
- return this.asyncMethod(function() {
- var detail = this.populateDetails();
- if (state == KEY_STATES.LOCKED) {
- // We don't care about the longpress if we are already
- // capitalized.
- return;
- } else {
- state = KEY_STATES.LOCKED;
- detail.toKeyset = this.upperCaseKeysetId;
- detail.nextKeyset = undefined;
- }
- this.fire('key-longpress', detail);
- }, null, LONGPRESS_DELAY_MSEC);
- },
-
- // @return Whether the shift modifier is currently active.
- isActive: function() {
- return state != KEY_STATES.UNLOCKED;
- },
-
- /**
- * Callback function for when a double click is triggered.
- */
- onDoubleClick: function() {
- state = KEY_STATES.LOCKED;
- },
-
- /**
- * Notifies shift key that a non-control key was pressed down.
- * A control key is defined as one of shift, control or alt.
- */
- onNonControlKeyDown: function() {
- switch (state) {
- case (KEY_STATES.PRESSED):
- state = KEY_STATES.CHORDING;
- // Disable longpress timer.
- clearTimeout(shiftLongPressTimer);
- break;
- default:
- break;
- }
- },
-
- /**
- * Notifies key that a non-control keyed was typed.
- * A control key is defined as one of shift, control or alt.
- */
- onNonControlKeyTyped: function() {
- if (state == KEY_STATES.TAPPED)
- state = KEY_STATES.UNLOCKED;
- },
-
- /**
- * Callback function for when a space is pressed after punctuation.
- * @return {Object} The keyset transitions the keyboard should make.
- */
- onSpaceAfterPunctuation: function() {
- var detail = {};
- detail.toKeyset = this.upperCaseKeysetId;
- detail.nextKeyset = this.lowerCaseKeysetId;
- state = KEY_STATES.TAPPED;
- return detail;
- },
-
- populateDetails: function(caller) {
- var detail = this.super([caller]);
- switch(state) {
- case(KEY_STATES.LOCKED):
- detail.toKeyset = this.upperCaseKeysetId;
- break;
- case(KEY_STATES.UNLOCKED):
- detail.toKeyset = this.lowerCaseKeysetId;
- break;
- case(KEY_STATES.PRESSED):
- detail.toKeyset = this.upperCaseKeysetId;
- break;
- case(KEY_STATES.TAPPED):
- detail.toKeyset = this.upperCaseKeysetId;
- detail.nextKeyset = this.lowerCaseKeysetId;
- break;
- case(KEY_STATES.CHORDING):
- detail.toKeyset = this.lowerCaseKeysetId;
- break;
- default:
- break;
- }
- return detail;
- },
-
- /**
- * Resets the shift key state.
- */
- reset: function() {
- state = KEY_STATES.UNLOCKED;
- },
-
- /**
- * Overrides longPressTimer for the shift key.
- */
- get longPressTimer() {
- return shiftLongPressTimer;
- },
-
- set longPressTimer(timer) {
- shiftLongPressTimer = timer;
- },
-
- get state() {
- return state;
- },
-
- get textKeyset() {
- switch (state) {
- case KEY_STATES.UNLOCKED:
- return this.lowerCaseKeysetId;
- default:
- return this.upperCaseKeysetId;
- }
- },
- });
- })();
- </script>
+<polymer-element name="kb-shift-key" attributes="lowerCaseKeysetId
+ upperCaseKeysetId" class="shift dark" char="Shift" image="shift.png"
+ on-pointerout="{{out}}" extends="kb-key">
+ <template>
+ <style>
+ .shift-light-wrapper {
+ top: 6px;
+ height: 10%;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ width: 100%;
+ }
+
+ .shift-light {
+ background-color: #cccccc;
+ border: none;
+ height: 4px;
+ margin: 0 6px 0 auto;
+ position: relative;
+ width: 4px;
+ }
+ </style>
+ <div class="shift-light-wrapper">
+ <div class="shift-light"> </div>
+ </div>
+ <shadow></shadow>
+ </template>
</polymer-element>
diff --git a/chromium/ui/keyboard/resources/elements/kb-shift-key.js b/chromium/ui/keyboard/resources/elements/kb-shift-key.js
new file mode 100644
index 00000000000..4ebb633304d
--- /dev/null
+++ b/chromium/ui/keyboard/resources/elements/kb-shift-key.js
@@ -0,0 +1,246 @@
+// 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.
+
+(function () {
+
+ /**
+ * The possible states of the shift key.
+ * Unlocked is the default state. Locked for capslocked, pressed is a
+ * key-down and tapped for a key-down followed by an immediate key-up.
+ * @const
+ * @type {Enum}
+ */
+ var KEY_STATES = {
+ PRESSED: "pressed", // Key-down on shift key.
+ LOCKED: "locked", // Key is capslocked.
+ UNLOCKED: "unlocked", // Default state.
+ TAPPED: "tapped", // Key-down followed by key-up.
+ CHORDING: "chording" // Key-down followed by other keys.
+ };
+
+ /**
+ * The pointerdown event on shiftkey that may eventually trigger chording
+ * state. pointerId and eventTarget are the two fields that is used now.
+ * @type {PointerEvent}
+ */
+ var enterChordingEvent = undefined;
+
+ /**
+ * Uses a closure to define one long press timer among all shift keys
+ * regardless of the layout they are in.
+ * @type {function}
+ */
+ var shiftLongPressTimer = undefined;
+
+ /**
+ * The current state of the shift key.
+ * @type {Enum}
+ */
+ var state = KEY_STATES.UNLOCKED;
+
+ Polymer('kb-shift-key', {
+ /**
+ * Defines how capslock effects keyset transition. We always transition
+ * from the lowerCaseKeysetId to the upperCaseKeysetId if capslock is
+ * on.
+ * @type {string}
+ */
+ lowerCaseKeysetId: 'lower',
+ upperCaseKeysetId: 'upper',
+
+ up: function(event) {
+ if (state == KEY_STATES.CHORDING &&
+ event.pointerId != enterChordingEvent.pointerId) {
+ // Disables all other pointer events on shift keys when chording.
+ return;
+ }
+ switch (state) {
+ case KEY_STATES.PRESSED:
+ state = KEY_STATES.TAPPED;
+ break;
+ case KEY_STATES.CHORDING:
+ // Leaves chording only if the pointer that triggered it is
+ // released.
+ state = KEY_STATES.UNLOCKED;
+ break;
+ default:
+ break;
+ }
+ // When releasing the shift key, it is not the same shift key that was
+ // pressed. Updates the pointerId of the releasing shift key to make
+ // sure key-up event fires correctly in kb-key-base.
+ this.pointerId = enterChordingEvent.pointerId;
+ this.super([event]);
+ },
+
+ out: function(event) {
+ // Sliding off the shift key while chording is treated as a key-up.
+ // Note that we switch to a new keyset on shift keydown, and a finger
+ // movement on the new shift key will trigger this function being
+ // called on the old shift key. We should not end chording in that
+ // case.
+ if (state == KEY_STATES.CHORDING &&
+ event.pointerId == enterChordingEvent.pointerId &&
+ event.target != enterChordingEvent.target) {
+ state = KEY_STATES.UNLOCKED;
+ var detail = this.populateDetails('out');
+ this.fire("key-out", detail);
+ }
+ },
+
+ down: function(event) {
+ // First transition state so that populateDetails generates
+ // correct data.
+ switch (state) {
+ case KEY_STATES.UNLOCKED:
+ state = KEY_STATES.PRESSED;
+ break;
+ case KEY_STATES.TAPPED:
+ case KEY_STATES.LOCKED:
+ state = KEY_STATES.UNLOCKED;
+ break;
+ case KEY_STATES.PRESSED:
+ case KEY_STATES.CHORDING:
+ // We pressed another shift key at the same time,
+ // so ignore second press.
+ return;
+ default:
+ console.error("Undefined shift key state: " + state);
+ break;
+ }
+ enterChordingEvent = event;
+ // Trigger parent behaviour.
+ this.super([event]);
+ this.fire('enable-sel');
+ // Populate double click transition details.
+ var detail = {};
+ detail.char = this.char || this.textContent;
+ detail.toKeyset = this.upperCaseKeysetId;
+ detail.nextKeyset = undefined;
+ detail.callback = this.onDoubleClick;
+ this.fire('enable-dbl', detail);
+ },
+
+ generateLongPressTimer: function() {
+ return this.async(function() {
+ var detail = this.populateDetails();
+ if (state == KEY_STATES.LOCKED) {
+ // We don't care about the longpress if we are already
+ // capitalized.
+ return;
+ } else {
+ state = KEY_STATES.LOCKED;
+ detail.toKeyset = this.upperCaseKeysetId;
+ detail.nextKeyset = undefined;
+ }
+ this.fire('key-longpress', detail);
+ }, null, LONGPRESS_DELAY_MSEC);
+ },
+
+ // @return Whether the shift modifier is currently active.
+ isActive: function() {
+ return state != KEY_STATES.UNLOCKED;
+ },
+
+ /**
+ * Callback function for when a double click is triggered.
+ */
+ onDoubleClick: function() {
+ state = KEY_STATES.LOCKED;
+ },
+
+ /**
+ * Notifies shift key that a non-control key was pressed down.
+ * A control key is defined as one of shift, control or alt.
+ */
+ onNonControlKeyDown: function() {
+ switch (state) {
+ case (KEY_STATES.PRESSED):
+ state = KEY_STATES.CHORDING;
+ // Disable longpress timer.
+ clearTimeout(shiftLongPressTimer);
+ break;
+ default:
+ break;
+ }
+ },
+
+ /**
+ * Notifies key that a non-control keyed was typed.
+ * A control key is defined as one of shift, control or alt.
+ */
+ onNonControlKeyTyped: function() {
+ if (state == KEY_STATES.TAPPED)
+ state = KEY_STATES.UNLOCKED;
+ },
+
+ /**
+ * Callback function for when a space is pressed after punctuation.
+ * @return {Object} The keyset transitions the keyboard should make.
+ */
+ onSpaceAfterPunctuation: function() {
+ var detail = {};
+ detail.toKeyset = this.upperCaseKeysetId;
+ detail.nextKeyset = this.lowerCaseKeysetId;
+ state = KEY_STATES.TAPPED;
+ return detail;
+ },
+
+ populateDetails: function(caller) {
+ var detail = this.super([caller]);
+ switch(state) {
+ case(KEY_STATES.LOCKED):
+ detail.toKeyset = this.upperCaseKeysetId;
+ break;
+ case(KEY_STATES.UNLOCKED):
+ detail.toKeyset = this.lowerCaseKeysetId;
+ break;
+ case(KEY_STATES.PRESSED):
+ detail.toKeyset = this.upperCaseKeysetId;
+ break;
+ case(KEY_STATES.TAPPED):
+ detail.toKeyset = this.upperCaseKeysetId;
+ detail.nextKeyset = this.lowerCaseKeysetId;
+ break;
+ case(KEY_STATES.CHORDING):
+ detail.toKeyset = this.lowerCaseKeysetId;
+ break;
+ default:
+ break;
+ }
+ return detail;
+ },
+
+ /**
+ * Resets the shift key state.
+ */
+ reset: function() {
+ state = KEY_STATES.UNLOCKED;
+ },
+
+ /**
+ * Overrides longPressTimer for the shift key.
+ */
+ get longPressTimer() {
+ return shiftLongPressTimer;
+ },
+
+ set longPressTimer(timer) {
+ shiftLongPressTimer = timer;
+ },
+
+ get state() {
+ return state;
+ },
+
+ get textKeyset() {
+ switch (state) {
+ case KEY_STATES.UNLOCKED:
+ return this.lowerCaseKeysetId;
+ default:
+ return this.upperCaseKeysetId;
+ }
+ },
+ });
+})();
diff --git a/chromium/ui/keyboard/resources/images/back.svg b/chromium/ui/keyboard/resources/images/back.svg
index 33d519a7f55..61895dc4ae1 100644
--- a/chromium/ui/keyboard/resources/images/back.svg
+++ b/chromium/ui/keyboard/resources/images/back.svg
@@ -24,4 +24,4 @@
d="m 0,0 -6.845,0 2.8,2.8 -1.132,1.132 -4.697,-4.699 4.688,-4.764 1.14,1.122 L -6.81,-1.6 0,-1.6 0,0 z"
inkscape:connector-curvature="0"
id="path14"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></svg> \ No newline at end of file
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></svg>
diff --git a/chromium/ui/keyboard/resources/images/backspace.png b/chromium/ui/keyboard/resources/images/backspace.png
new file mode 100644
index 00000000000..9c7b9979e84
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/backspace.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/down.svg b/chromium/ui/keyboard/resources/images/down.svg
index 45f6466e6e1..5d9d928857b 100644
--- a/chromium/ui/keyboard/resources/images/down.svg
+++ b/chromium/ui/keyboard/resources/images/down.svg
@@ -24,4 +24,4 @@
d="M 0,0 3.57,-3.57 7.199,0"
inkscape:connector-curvature="0"
id="path14"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg> \ No newline at end of file
+ style="fill:none;stroke:#555555;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg>
diff --git a/chromium/ui/keyboard/resources/images/hide-keyboard.png b/chromium/ui/keyboard/resources/images/hide-keyboard.png
new file mode 100644
index 00000000000..a47b82342e1
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/hide-keyboard.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/left.svg b/chromium/ui/keyboard/resources/images/left.svg
index 0d31feb576e..0780e945cd5 100644
--- a/chromium/ui/keyboard/resources/images/left.svg
+++ b/chromium/ui/keyboard/resources/images/left.svg
@@ -24,4 +24,4 @@
d="M 0,0 -3.57,-3.57 0,-7.199"
inkscape:connector-curvature="0"
id="path14"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg> \ No newline at end of file
+ style="fill:none;stroke:#555555;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg>
diff --git a/chromium/ui/keyboard/resources/images/return.png b/chromium/ui/keyboard/resources/images/return.png
new file mode 100644
index 00000000000..df1b7db7eb0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/return.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/right.svg b/chromium/ui/keyboard/resources/images/right.svg
index 09f2e28c72f..d79bfca5edc 100644
--- a/chromium/ui/keyboard/resources/images/right.svg
+++ b/chromium/ui/keyboard/resources/images/right.svg
@@ -24,4 +24,4 @@
d="M 0,0 3.57,3.57 0,7.199"
inkscape:connector-curvature="0"
id="path14"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg> \ No newline at end of file
+ style="fill:none;stroke:#555555;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg>
diff --git a/chromium/ui/keyboard/resources/images/search.png b/chromium/ui/keyboard/resources/images/search.png
new file mode 100644
index 00000000000..1e67e246ba4
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/search.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/search.svg b/chromium/ui/keyboard/resources/images/search.svg
deleted file mode 100644
index 0a2fa51f5cc..00000000000
--- a/chromium/ui/keyboard/resources/images/search.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
- "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
- width="97.000000pt" height="58.000000pt" viewBox="0 0 97.000000 58.000000"
- preserveAspectRatio="xMidYMid meet">
-<g transform="translate(0.000000,58.000000) scale(0.100000,-0.100000)"
-fill="#ffffff" stroke="none">
-<path d="M385 395 c-34 -33 -35 -102 -2 -133 27 -26 78 -38 102 -25 13 8 26 0
-60 -36 42 -44 45 -45 62 -28 17 17 16 20 -28 61 -38 37 -44 47 -37 66 11 30
--7 86 -35 105 -34 24 -94 19 -122 -10z m110 -35 c35 -39 -6 -99 -59 -86 -16 4
--31 17 -37 33 -22 58 54 100 96 53z"/>
-</g>
-</svg>
diff --git a/chromium/ui/keyboard/resources/images/shift.png b/chromium/ui/keyboard/resources/images/shift.png
new file mode 100644
index 00000000000..4458fda48e1
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/shift.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/tab.png b/chromium/ui/keyboard/resources/images/tab.png
new file mode 100644
index 00000000000..49745deda6d
--- /dev/null
+++ b/chromium/ui/keyboard/resources/images/tab.png
Binary files differ
diff --git a/chromium/ui/keyboard/resources/images/up.svg b/chromium/ui/keyboard/resources/images/up.svg
index 3b55bd7a08a..408e062af3b 100644
--- a/chromium/ui/keyboard/resources/images/up.svg
+++ b/chromium/ui/keyboard/resources/images/up.svg
@@ -24,4 +24,4 @@
d="M 0,0 -3.57,3.57 -7.199,0"
inkscape:connector-curvature="0"
id="path14"
- style="fill:none;stroke:#ffffff;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg> \ No newline at end of file
+ style="fill:none;stroke:#555555;stroke-width:1.60000002;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></svg>
diff --git a/chromium/ui/keyboard/resources/index.html b/chromium/ui/keyboard/resources/index.html
index 16733ba6b7d..d4416001ee7 100644
--- a/chromium/ui/keyboard/resources/index.html
+++ b/chromium/ui/keyboard/resources/index.html
@@ -9,38 +9,28 @@
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="main.css">
- <script src="constants.js"></script>
<script src="polymer_loader.js"></script>
- <script src="api_adapter.js"></script>
- <script src="voice_input.js"></script>
- <script src="main.js"></script>
-
- <!-- TODO(kevers): Dynamically load alternative keys based on locale. -->
- <script src="layouts/latin-accents.js"></script>
- <script src="layouts/symbol-altkeys.js"></script>
-
- <link rel="import" href="elements/kb-altkey-container.html">
- <link rel="import" href="elements/kb-altkey.html">
- <link rel="import" href="elements/kb-altkey-data.html">
- <link rel="import" href="elements/kb-altkey-set.html">
- <link rel="import" href="elements/kb-key-codes.html">
- <link rel="import" href="elements/kb-key-base.html">
- <link rel="import" href="elements/kb-key.html">
- <link rel="import" href="elements/kb-keyboard.html">
- <link rel="import" href="elements/kb-keyset.html">
- <link rel="import" href="elements/kb-modifier-key.html">
- <link rel="import" href="elements/kb-row.html">
- <link rel="import" href="elements/kb-shift-key.html">
- <link rel="import" href="elements/kb-key-sequence.html">
- <link rel="import" href="elements/kb-key-import.html">
- <link rel="import" href="elements/kb-options-menu.html">
- <!-- New layouts are dynamically loaded on demand. The link elements are
- -- inserted here.
- -->
+ <script src="keyboard.js"></script>
+ <include src="elements/kb-altkey-container.html">
+ <include src="elements/kb-altkey.html">
+ <include src="elements/kb-altkey-data.html">
+ <include src="elements/kb-altkey-set.html">
+ <include src="elements/kb-key-codes.html">
+ <include src="elements/kb-key-base.html">
+ <include src="elements/kb-key.html">
+ <include src="elements/kb-keyboard.html">
+ <include src="elements/kb-keyset.html">
+ <include src="elements/kb-modifier-key.html">
+ <include src="elements/kb-row.html">
+ <include src="elements/kb-shift-key.html">
+ <include src="elements/kb-key-sequence.html">
+ <include src="elements/kb-key-import.html">
</head>
<body>
- <!-- TODO(bshe): initial input type should not be hard coded to text. -->
- <kb-keyboard id="keyboard" touch-action="none" inputType="text">
+ <kb-keyboard id="keyboard" touch-action="none">
+ <include src="layouts/numeric.html">
+ <include src="layouts/qwerty.html">
+ <include src="layouts/system-qwerty.html">
</kb-keyboard>
</body>
</html>
diff --git a/chromium/ui/keyboard/resources/keyboard.js b/chromium/ui/keyboard/resources/keyboard.js
new file mode 100644
index 00000000000..4fe9fa59c8f
--- /dev/null
+++ b/chromium/ui/keyboard/resources/keyboard.js
@@ -0,0 +1,26 @@
+// 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 src="constants.js"></include>
+<include src="api_adapter.js"></include>
+<include src="touch_fuzzing.js"></include>
+<include src="voice_input.js"></include>
+<include src="main.js"></include>
+//TODO(kevers): Dynamically load alternative keys based on locale.
+<include src="layouts/latin-accents.js"></include>
+<include src="layouts/symbol-altkeys.js"></include>
+<include src="elements/kb-altkey-container.js"></include>
+<include src="elements/kb-altkey-set.js"></include>
+<include src="elements/kb-key-codes.js"></include>
+<include src="elements/kb-key-sequence.js"></include>
+<include src="elements/kb-altkey-data.js"></include>
+<include src="elements/kb-key-base.js"></include>
+<include src="elements/kb-key.js"></include>
+<include src="elements/kb-keyset.js"></include>
+<include src="elements/kb-row.js"></include>
+<include src="elements/kb-altkey.js"></include>
+<include src="elements/kb-keyboard.js"></include>
+<include src="elements/kb-key-import.js"></include>
+<include src="elements/kb-modifier-key.js"></include>
+<include src="elements/kb-shift-key.js"></include>
+
diff --git a/chromium/ui/keyboard/resources/layouts/dvorak.html b/chromium/ui/keyboard/resources/layouts/dvorak.html
index d3d9ee440d1..7d1acc88ff3 100644
--- a/chromium/ui/keyboard/resources/layouts/dvorak.html
+++ b/chromium/ui/keyboard/resources/layouts/dvorak.html
@@ -33,7 +33,7 @@
<kb-key-import importId="spacebar-row"></kb-key-import>
<kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
align="right" weight="130">#123</kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
+ <kb-hide-keyboard-key>hide</kb-hide-keyboard-key>
</kb-row>
<kb-altkey-container hidden>
</kb-altkey-container>
@@ -65,7 +65,7 @@
<kb-key-import importId="spacebar-row"></kb-key-import>
<kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid"
align="right" weight="130">#123</kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
+ <kb-hide-keyboard-key>hide</kb-hide-keyboard-key>
</kb-row>
<kb-altkey-container hidden>
</kb-altkey-container>
@@ -96,7 +96,7 @@
<kb-abc-key align="left" weight="130">abc</kb-abc-key>
<kb-key-import importId="spacebar-row"></kb-key-import>
<kb-abc-key align="right" weight="130">abc</kb-abc-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
+ <kb-hide-keyboard-key>hide</kb-hide-keyboard-key>
</kb-row>
<kb-altkey-container hidden>
</kb-altkey-container>
@@ -133,7 +133,7 @@
<kb-abc-key align="left" weight="130">abc</kb-abc-key>
<kb-key-import importId="spacebar-row"></kb-key-import>
<kb-abc-key align="right" weight="130">abc</kb-abc-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
+ <kb-hide-keyboard-key>hide</kb-hide-keyboard-key>
</kb-row>
</kb-keyset>
-</template> \ No newline at end of file
+</template>
diff --git a/chromium/ui/keyboard/resources/layouts/function-key-row.html b/chromium/ui/keyboard/resources/layouts/function-key-row.html
index ef70914c6db..96dfe20e311 100644
--- a/chromium/ui/keyboard/resources/layouts/function-key-row.html
+++ b/chromium/ui/keyboard/resources/layouts/function-key-row.html
@@ -5,21 +5,25 @@
-->
<template>
- <kb-key class="esc dark" char="Esc">esc</kb-key>
- <kb-key class="back dark" char="Back" image="back"></kb-key>
- <kb-key class="forward dark" char="Forward" image="forward"></kb-key>
- <kb-key class="reload dark" char="Reload" image="reload"></kb-key>
- <kb-key class="fullscreen dark" char="Fullscreen"
+ <kb-key class="esc dark" stretch weight="110" char="Esc">esc</kb-key>
+ <kb-key class="back dark" stretch weight="110" char="Back" image="back">
+ </kb-key>
+ <kb-key class="forward dark" stretch weight="110" char="Forward"
+ image="forward"> </kb-key>
+ <kb-key class="reload dark" stretch weight="110" char="Reload" image="reload">
+ </kb-key>
+ <kb-key class="fullscreen stretch dark" weight="110" char="Fullscreen"
image="fullscreen"></kb-key>
- <kb-key class="change-window dark" char="Change-Window"
+ <kb-key class="change-window dark" stretch weight="110" char="Change-Window"
image="change-window"></kb-key>
- <kb-key class="brightness-down dark" repeat char="Brightness-Down"
- image="brightness-down"></kb-key>
- <kb-key class="brightness-up dark" repeat char="Brightness-Up"
- image="brightness-up"></kb-key>
- <kb-key class="mute dark" char="Mute" image="mute"></kb-key>
- <kb-key class="volume-down dark" repeat char="Volume-Down"
- image="volume-down"></kb-key>
- <kb-key class="volume-up dark" repeat char="Volume-Up"
+ <kb-key class="brightness-down dark" stretch weight="110" repeat
+ char="Brightness-Down" image="brightness-down"></kb-key>
+ <kb-key class="brightness-up dark" stretch weight="110" repeat
+ char="Brightness-Up" image="brightness-up"></kb-key>
+ <kb-key class="mute dark" char="Mute" stretch weight="110"
+ image="mute"></kb-key>
+ <kb-key class="volume-down dark" stretch weight="110"
+ repeat char="Volume-Down" image="volume-down"></kb-key>
+ <kb-key class="volume-up dark" stretch weight="110" repeat char="Volume-Up"
image="volume-up"></kb-key>
</template>
diff --git a/chromium/ui/keyboard/resources/layouts/latin-accents.js b/chromium/ui/keyboard/resources/layouts/latin-accents.js
index e395ea881d6..2492a1bddf5 100644
--- a/chromium/ui/keyboard/resources/layouts/latin-accents.js
+++ b/chromium/ui/keyboard/resources/layouts/latin-accents.js
@@ -74,7 +74,7 @@ var lowercaseAccents = {
'\u016B'], // Lowercase U macron
};
-document.addEventListener('WebComponentsReady', function() {
+document.addEventListener('polymer-ready', function() {
var altkeyMetadata = document.createElement('kb-altkey-data');
altkeyMetadata.registerAltkeys(uppercaseAccents);
altkeyMetadata.registerAltkeys(lowercaseAccents);
diff --git a/chromium/ui/keyboard/resources/layouts/numeric.html b/chromium/ui/keyboard/resources/layouts/numeric.html
index 6375f734a5f..71e023ad0d9 100644
--- a/chromium/ui/keyboard/resources/layouts/numeric.html
+++ b/chromium/ui/keyboard/resources/layouts/numeric.html
@@ -4,25 +4,24 @@
-- found in the LICENSE file.
-->
-<template>
- <kb-keyset id="numeric-symbol" isDefault=true>
- <kb-row>
- <kb-key>1</kb-key><kb-key>2</kb-key><kb-key>3</kb-key>
- <kb-key class="dark">-</kb-key>
- </kb-row>
- <kb-row>
- <kb-key>4</kb-key><kb-key>5</kb-key><kb-key>6</kb-key>
- <kb-key class="dark">,</kb-key>
- </kb-row>
- <kb-row>
- <kb-key>7</kb-key><kb-key>8</kb-key><kb-key>9</kb-key>
- <kb-key char="&#x0008;" repeat class="dark">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key char=" " class="dark">space</kb-key>
- <kb-key>0</kb-key>
- <kb-key class="dark">.</kb-key>
- <kb-key char="&#x0009;" class="dark">next</kb-key>
- </kb-row>
- </kb-keyset>
-</template>
+<kb-keyset id="numeric-symbol" isDefault=true>
+ <kb-row>
+ <kb-key>1</kb-key><kb-key>2</kb-key><kb-key>3</kb-key>
+ <kb-key class="dark">-</kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-key>4</kb-key><kb-key>5</kb-key><kb-key>6</kb-key>
+ <kb-key class="dark">,</kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-key>7</kb-key><kb-key>8</kb-key><kb-key>9</kb-key>
+ <kb-key char="&#x0008;" repeat class="dark">backspace</kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-key char=" " class="dark">space</kb-key>
+ <kb-key>0</kb-key>
+ <kb-key class="dark">.</kb-key>
+ <kb-key char="&#x0009;" class="dark">next</kb-key>
+ </kb-row>
+</kb-keyset>
+
diff --git a/chromium/ui/keyboard/resources/layouts/qwerty.html b/chromium/ui/keyboard/resources/layouts/qwerty.html
index b8f83f1c0c1..3c357caab1f 100644
--- a/chromium/ui/keyboard/resources/layouts/qwerty.html
+++ b/chromium/ui/keyboard/resources/layouts/qwerty.html
@@ -4,151 +4,142 @@
-- found in the LICENSE file.
-->
-<link id="spacebar-row" rel="import" href="spacebar-row.html">
-<template>
- <kb-keyset id="qwerty-upper">
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="120">tab</kb-key>
- <kb-key-sequence keys="QWERTYUIOP" hintTexts="1234567890">
- </kb-key-sequence>
- <kb-key class="dark" char="&#x0008;" repeat align="right"
- weight="140">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key-sequence keys="ASDFGHJKL"></kb-key-sequence>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-shift-key weight="180" align="left">shift</kb-shift-key>
- <kb-key-sequence keys="ZXCVBNM"></kb-key-sequence>
- <kb-key invert hintText="!" char=",">,</kb-key>
- <kb-key invert hintText="?" char=".">.</kb-key>
- <kb-shift-key weight="180" align="right">shift</kb-shift-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="left" weight="130">#123</kb-key>
- <kb-key-import importId="spacebar-row"></kb-key-import>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="right" weight="130">#123</kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
+<kb-keyset id="qwerty-upper" flick=false pitch="10 20">
+ <kb-row class="hide-hint-text">
+ <kb-key-sequence keys="QWERTYUIOP" hintTexts="1234567890"></kb-key-sequence>
+ <kb-key class="dark" char="&#x0008;" image="backspace.png"
+ repeat sound="keypress-delete" stretch weight="110"></kb-key>
+ </kb-row>
+ <kb-row align="right">
+ <kb-key-sequence keys="ASDFGHJKL"></kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" weight="175"></kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-shift-key weight="105" align="left"></kb-shift-key>
+ <kb-key-sequence keys="ZXCVBNM!?"></kb-key-sequence>
+ <kb-shift-key weight="105" stretch align="right"></kb-shift-key>
+ </kb-row>
+ <kb-row>
+ <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
+ align="center" weight="105">?123</kb-key>
+ <kb-key class="dark">_</kb-key>
+ <kb-key class="dark" stretch>/</kb-key>
+ <kb-key char=" " class="space" sound="keypress-spacebar" weight="540">
+ English (US)
+ </kb-key>
+ <kb-key class="dark">,</kb-key>
+ <kb-key class="dark">.</kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch weight="105">
+ </kb-hide-keyboard-key>
+ </kb-row>
+ <kb-altkey-container hidden>
+ </kb-altkey-container>
+</kb-keyset>
- <kb-keyset id="qwerty-lower" isDefault=true>
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="120">tab</kb-key>
- <kb-key-sequence keys="qwertyuiop" hintTexts="1234567890">
- </kb-key-sequence>
- <kb-key class="dark" char="&#x0008;" repeat align="right"
- weight="140">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key-sequence keys="asdfghjkl"></kb-key-sequence>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-shift-key weight="180" align="left">shift</kb-shift-key>
- <kb-key-sequence keys="zxcvbnm"></kb-key-sequence>
- <kb-key hintText="!">,</kb-key><kb-key hintText="?">.</kb-key>
- <kb-shift-key weight="180" align="right">shift</kb-shift-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="left" weight="130">#123</kb-key>
- <kb-key-import importId="spacebar-row"></kb-key-import>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="right" weight="130">#123</kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
+<kb-keyset id="qwerty-lower" flick=false isDefault=true pitch="10 20">
+ <kb-row class="hide-hint-text">
+ <kb-key-sequence keys="qwertyuiop" hintTexts="1234567890"></kb-key-sequence>
+ <kb-key class="dark" char="&#x0008;" repeat stretch align="right"
+ image="backspace.png" sound="keypress-delete" weight="110"></kb-key>
+ </kb-row>
+ <kb-row align="right">
+ <kb-key-sequence keys="asdfghjkl"></kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" weight="175"></kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-shift-key weight="105" align="left"></kb-shift-key>
+ <kb-key-sequence keys="zxcvbnm!?"></kb-key-sequence>
+ <kb-shift-key stretch weight="105" align="right"></kb-shift-key>
+ </kb-row>
+ <kb-row>
+ <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
+ align="center" weight="105">?123</kb-key>
+ <kb-key class="dark">-</kb-key>
+ <kb-key class="dark" stretch>/</kb-key>
+ <kb-key char=" " class="space" sound="keypress-spacebar" weight="540">
+ English (US)
+ </kb-key>
+ <kb-key class="dark">,</kb-key>
+ <kb-key class="dark">.</kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch weight="105">
+ </kb-hide-keyboard-key>
+ </kb-row>
+ <kb-altkey-container hidden>
+ </kb-altkey-container>
+</kb-keyset>
- <kb-keyset id="qwerty-symbol">
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="120">tab</kb-key>
- <kb-key>1</kb-key><kb-key>2</kb-key>
- <kb-key>3</kb-key><kb-key>4</kb-key>
- <kb-key>5</kb-key><kb-key>6</kb-key><kb-key>7</kb-key>
- <kb-key>8</kb-key><kb-key>9</kb-key><kb-key>0</kb-key>
- <kb-key class="dark" char="&#x0008;" repeat align="right"
- weight="140">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key>@</kb-key><kb-key>#</kb-key><kb-key>$</kb-key>
- <kb-key>%</kb-key><kb-key>&</kb-key>
- <kb-key>*</kb-key><kb-key>/</kb-key>
- <kb-key>(</kb-key><kb-key>)</kb-key>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" toKeyset="down:more" char="Invalid" align="left"
- weight="180">more</kb-key>
- <kb-key>:</kb-key><kb-key>;</kb-key><kb-key>-</kb-key><kb-key>'</kb-key>
- <kb-key>"</kb-key><kb-key>!</kb-key>
- <kb-key>?</kb-key><kb-key>,</kb-key><kb-key>.</kb-key>
- <kb-key class="dark" toKeyset="down:more" char="Invalid" align="right"
- weight="180">more</kb-key>
- </kb-row>
- <kb-row>
- <kb-abc-key align="left" weight="130">abc</kb-abc-key>
- <kb-key-import importId="spacebar-row"></kb-key-import>
- <kb-abc-key align="right" weight="130">abc</kb-abc-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
+<kb-keyset id="qwerty-symbol" pitch="10 20">
+ <kb-row>
+ <kb-key-sequence keys="1234567890"></kb-key-sequence>
+ <kb-key class="dark" char="&#x0008;" align="right" image="backspace.png"
+ repeat sound="keypress-delete" stretch weight="110"></kb-key>
+ </kb-row>
+ <kb-row align="right">
+ <kb-key-sequence keys="@#$%&-+()"></kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" weight="175"></kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-key class="dark" toKeyset="down:more" char="Invalid" align="center"
+ weight="105">~[&lt;</kb-key>
+ <kb-key-sequence keys="\=*&quot;':;!?"></kb-key-sequence>
+ <kb-key class="dark" toKeyset="down:more" char="Invalid" align="center"
+ stretch weight="105">~[&lt;</kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-abc-key align="center" weight="105">ABC</kb-abc-key>
+ <kb-key class="dark">_</kb-key>
+ <kb-key class="dark" stretch>/</kb-key>
+ <kb-key char=" " class="space" sound="keypress-spacebar" weight="540">
+ English (US)
+ </kb-key>
+ <kb-key class="dark">,</kb-key>
+ <kb-key class="dark">.</kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch weight="105">
+ </kb-hide-keyboard-key>
+ </kb-row>
+ <kb-altkey-container hidden>
+ </kb-altkey-container>
+</kb-keyset>
+
+<kb-keyset id="qwerty-more" pitch="10 20">
+ <kb-row>
+ <kb-key-sequence
+ keys="~`|&#x2022;&radic;&Pi;&divide;&times;&para;&Delta;">
+ </kb-key-sequence>
+ <kb-key class="dark" align="right" char="&#x0008;" image="backspace.png"
+ repeat sound="keypress-delete" stretch weight="110"></kb-key>
+ </kb-row>
+ <kb-row align="right">
+ <kb-key-sequence
+ keys="&pound;&#x00A2;&#x20AC;&yen;^&deg;={}">
+ </kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" weight="175"></kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
+ align="center" weight="105">?123</kb-key>
+ <kb-key-sequence
+ keys="\&#x00A9;&#x00AE;&#x2122;&#8453;[]&iexcl;&iquest;">
+ </kb-key-sequence>
+ <kb-key stretch class="dark" toKeyset="down:symbol" char="Invalid"
+ align="center" weight="105">?123</kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-abc-key align="center" weight="105">ABC</kb-abc-key>
+ <kb-key class="dark">&lt;</kb-key>
+ <kb-key class="dark" stretch>&gt;</kb-key>
+ <kb-key char=" " class="space" sound="keypress-spacebar" weight="540">
+ English (US)
+ </kb-key>
+ <kb-key class="dark">,</kb-key>
+ <kb-key class="dark">.</kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch weight="105">
+ </kb-hide-keyboard-key>
+ </kb-row>
+</kb-keyset>
- <kb-keyset id="qwerty-more">
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="120">tab</kb-key>
- <kb-key>~</kb-key><kb-key>`</kb-key><kb-key>|</kb-key><kb-key>^</kb-key>
- <kb-key>+</kb-key><kb-key>=</kb-key><kb-key>{</kb-key><kb-key>}</kb-key>
- <kb-key>&#x003C;</kb-key><kb-key>&#x003E;</kb-key>
- <kb-key class="dark" char="&#x0008;" repeat align="right"
- weight="140">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key>&#x00A3;</kb-key><kb-key>&#x00A2;</kb-key>
- <kb-key>&#x20AC;</kb-key><kb-key>&#x2122;</kb-key>
- <kb-key>&#x00A9;</kb-key><kb-key>&#x00AE;</kb-key>
- <kb-key>\</kb-key><kb-key>[</kb-key>
- <kb-key>]</kb-key>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="left" weight="180">#123</kb-key>
- <kb-key>&#x00D7;</kb-key><kb-key>&#x00F7;</kb-key>
- <kb-key>_</kb-key><kb-key>&#x00A7;</kb-key>
- <kb-key>&#x00B6;</kb-key><kb-key>&#x00A1;</kb-key>
- <kb-key>&#x00BF;</kb-key><kb-key>&#x2022;</kb-key>
- <kb-key>&#x0394;</kb-key>
- <kb-key class="dark" toKeyset="down:symbol" char="Invalid"
- align="right" weight="180">#123</kb-key>
- </kb-row>
- <kb-row>
- <kb-abc-key align="left" weight="130">abc</kb-abc-key>
- <kb-key-import importId="spacebar-row"></kb-key-import>
- <kb-abc-key align="right" weight="130">abc</kb-abc-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- </kb-keyset>
-</template>
diff --git a/chromium/ui/keyboard/resources/layouts/spacebar-row.html b/chromium/ui/keyboard/resources/layouts/spacebar-row.html
index b4b0e8b4999..960630750d2 100644
--- a/chromium/ui/keyboard/resources/layouts/spacebar-row.html
+++ b/chromium/ui/keyboard/resources/layouts/spacebar-row.html
@@ -6,5 +6,5 @@
<template>
<kb-key class="dotcom dark" align="left">.com</kb-key>
- <kb-key char=" " class="space dark" weight="800"></kb-key>
+ <kb-key char=" " class="space" weight="800"></kb-key>
</template>
diff --git a/chromium/ui/keyboard/resources/layouts/symbol-altkeys.js b/chromium/ui/keyboard/resources/layouts/symbol-altkeys.js
index a123dbf2a5d..521ec1c682e 100644
--- a/chromium/ui/keyboard/resources/layouts/symbol-altkeys.js
+++ b/chromium/ui/keyboard/resources/layouts/symbol-altkeys.js
@@ -40,7 +40,7 @@ var symbolAltKeys = {
'.com' : ['.net','.org','.gov']
};
-document.addEventListener('WebComponentsReady', function() {
+document.addEventListener('polymer-ready', function() {
var altkeyMetadata = document.createElement('kb-altkey-data');
altkeyMetadata.registerAltkeys(symbolAltKeys);
});
diff --git a/chromium/ui/keyboard/resources/layouts/system-qwerty.html b/chromium/ui/keyboard/resources/layouts/system-qwerty.html
index 53bd3ae95d9..ae301c7e956 100644
--- a/chromium/ui/keyboard/resources/layouts/system-qwerty.html
+++ b/chromium/ui/keyboard/resources/layouts/system-qwerty.html
@@ -4,108 +4,108 @@
-- found in the LICENSE file.
-->
-<link id="spacebar-row" rel="import" href="spacebar-row.html">
-<link id="function-key-row" rel="import" href="function-key-row.html">
+<kb-keyset id="system-qwerty-upper" align="center">
+ <kb-row>
+ <kb-key-sequence invert=true keys="`1234567890-="
+ hintTexts="~!@#$%^&*()_+"> </kb-key-sequence>
+ <kb-key class="dark" char="&#x0008;" repeat align="right"
+ image="backspace.png" sound="keypress-delete" stretch weight="190">
+ </kb-key>
+ </kb-row>
+ <kb-row align="left">
+ <kb-key class="dark tab" char="&#x0009;" align="center"
+ image="tab.png" weight="155"></kb-key>
+ <kb-key-sequence keys="QWERTYUIOP"></kb-key-sequence>
+ <kb-key-sequence invert=true keys="[]\"
+ hintTexts="{}|"></kb-key-sequence>
+ </kb-row>
+ <kb-row>
+ <kb-key class="search dark" char="Search" image='search.png'
+ weight="210"> </kb-key>
+ <kb-key-sequence keys="ASDFGHJKL"></kb-key-sequence>
+ <kb-key-sequence invert=true keys=";&apos;" hintTexts=':"'>
+ </kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" stretch weight="170"></kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-shift-key weight="265" align="left"></kb-shift-key>
+ <kb-key-sequence keys="ZXCVBNM"></kb-key-sequence>
+ <kb-key-sequence invert=true keys=",./" hintTexts="<>?">
+ </kb-key-sequence>
+ <kb-shift-key stretch weight="135" align="right"></kb-shift-key>
+ </kb-row>
+ <kb-row>
+ <kb-modifier-key class="dark" stretch weight="150" char="Ctrl"
+ align="left">ctrl</kb-modifier-key>
+ <kb-modifier-key class="dark" stretch weight="150" char="Alt"
+ align="left">alt</kb-modifier-key>
+ <kb-key char=" " class="space" sound="keypress-spacebar" weight="760">
+ English (US)
+ </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Left" image="left"
+ weight="75"> </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Up" image="up"
+ weight="75"></kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Down" image="down"
+ weight="75"> </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Right" image="right"
+ weight="75"></kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch>
+ </kb-hide-keyboard-key>
+ </kb-row>
+ <kb-altkey-container hidden>
+ </kb-altkey-container>
+</kb-keyset>
-<template>
- <kb-keyset id="system-qwerty-upper">
- <kb-row>
- <kb-key-import importId="function-key-row"></kb-key-import>
- </kb-row>
- <kb-row>
- <kb-key-sequence invert=true keys="'1234567890-="
- hintTexts="~!@#$%^&*()_+"> </kb-key-sequence>
- <kb-key class="dark" char="&#x0008;" repeat align="right"
- weight="160">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="160">tab</kb-key>
- <kb-key-sequence keys="QWERTYUIOP"></kb-key-sequence>
- <kb-key-sequence invert=true keys="[]\"
- hintTexts="{}|"></kb-key-sequence>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key-sequence keys="ASDFGHJKL"></kb-key-sequence>
- <kb-key-sequence invert=true keys=";&apos;" hintTexts=':"'>
- </kb-key-sequence>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-shift-key weight="230" align="left">shift</kb-shift-key>
- <kb-key-sequence keys="ZXCVBNM"></kb-key-sequence>
- <kb-key-sequence invert=true keys=",./" hintTexts="<>?">
- </kb-key-sequence>
- <kb-shift-key weight="230" align="right">shift</kb-shift-key>
- </kb-row>
- <kb-row>
- <kb-modifier-key class="dark" weight="150" char="Ctrl"
- align="left">ctrl</kb-modifier-key>
- <kb-modifier-key class="dark" weight="150" char="Alt"
- align="left">alt</kb-modifier-key>
- <kb-key char=" " class="space dark" weight="760"></kb-key>
- <kb-key class="dark" repeat char="Arrow-Left" image="left"
- weight="75"> </kb-key>
- <kb-key class="dark" repeat char="Arrow-Up" image="up"
- weight="75"></kb-key>
- <kb-key class="dark" repeat char="Arrow-Down" image="down"
- weight="75"> </kb-key>
- <kb-key class="dark" repeat char="Arrow-Right" image="right"
- weight="75"></kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
-
- <kb-keyset id="system-qwerty-lower" isDefault=true>
- <kb-row>
- <kb-key-import importId="function-key-row"></kb-key-import>
- </kb-row>
- <kb-row>
- <kb-key-sequence keys="'1234567890-=" hintTexts="~!@#$%^&*()_+">
- </kb-key-sequence>
- <kb-key class="dark" weight="160" char="&#x0008;"
- repeat align="right">backspace</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="dark" char="&#x0009;" align="left"
- weight="160">tab</kb-key>
- <kb-key-sequence keys="qwertyuiop"></kb-key-sequence>
- <kb-key-sequence keys="[]\" hintTexts="{}|"></kb-key-sequence>
- </kb-row>
- <kb-row>
- <kb-key class="microphone dark" char="Microphone" weight="150"></kb-key>
- <kb-key-sequence keys="asdfghjkl"></kb-key-sequence>
- <kb-key-sequence keys=";&apos;" hintTexts=':"'></kb-key-sequence>
- <kb-key class="dark" char="&#x000A;" align="right"
- weight="210">enter</kb-key>
- </kb-row>
- <kb-row>
- <kb-shift-key weight="230" align="left">shift</kb-shift-key>
- <kb-key-sequence keys="zxcvbnm"></kb-key-sequence>
- <kb-key-sequence keys=",./" hintTexts="<>?"></kb-key-sequence>
- <kb-shift-key weight="230" align="right">shift</kb-shift-key>
- </kb-row>
- <kb-row>
- <kb-modifier-key class="symbol dark" weight="150" char="Ctrl"
- align="left">ctrl</kb-modifier-key>
- <kb-modifier-key class="symbol dark" weight="150" char="Alt"
- align="left">alt</kb-modifier-key>
- <kb-key char=" " class="space dark" weight="760"></kb-key>
- <kb-key class="dark" repeat char="Arrow-Left" image="left"
- weight="75"> </kb-key>
- <kb-key class="dark" repeat char="Arrow-Up" image="up"
- weight="75"></kb-key>
- <kb-key class="dark" repeat char="Arrow-Down" image="down"
- weight="75"> </kb-key>
- <kb-key class="dark" repeat char="Arrow-Right" image="right"
- weight="75"></kb-key>
- <kb-hide-keyboard-key></kb-hide-keyboard-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
-</template> \ No newline at end of file
+<kb-keyset id="system-qwerty-lower" align="center" isDefault=true>
+ <kb-row>
+ <kb-key-sequence keys="`1234567890-=" hintTexts="~!@#$%^&*()_+">
+ </kb-key-sequence>
+ <kb-key class="dark" weight="190" char="&#x0008;"
+ image="backspace.png" repeat sound="keypress-delete" stretch
+ align="right"></kb-key>
+ </kb-row>
+ <kb-row align="left">
+ <kb-key class="dark tab" char="&#x0009;" align="center"
+ image="tab.png" weight="155"></kb-key>
+ <kb-key-sequence keys="qwertyuiop"></kb-key-sequence>
+ <kb-key-sequence keys="[]\" hintTexts="{}|"></kb-key-sequence>
+ </kb-row>
+ <kb-row>
+ <kb-key class="search dark" char="Search" image='search.png'
+ weight="210"></kb-key>
+ <kb-key-sequence keys="asdfghjkl"></kb-key-sequence>
+ <kb-key-sequence keys=";&apos;" hintTexts=':"'></kb-key-sequence>
+ <kb-key class="dark" char="&#x000A;" align="right"
+ image="return.png" sound="keypress-return" stretch weight="170">
+ </kb-key>
+ </kb-row>
+ <kb-row>
+ <kb-shift-key weight="265" align="left"></kb-shift-key>
+ <kb-key-sequence keys="zxcvbnm"></kb-key-sequence>
+ <kb-key-sequence keys=",./" hintTexts="<>?"></kb-key-sequence>
+ <kb-shift-key stretch weight="135" align="right"></kb-shift-key>
+ </kb-row>
+ <kb-row>
+ <kb-modifier-key class="symbol dark" stretch weight="150" char="Ctrl"
+ align="left">ctrl</kb-modifier-key>
+ <kb-modifier-key class="symbol dark" stretch weight="150" char="Alt"
+ align="left">alt</kb-modifier-key>
+ <kb-key char=" " sound="keypress-spacebar" class="space" weight="760">
+ English (US)
+ </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Left" image="left"
+ weight="75"> </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Up" image="up"
+ weight="75"></kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Down" image="down"
+ weight="75"> </kb-key>
+ <kb-key class="cursor dark" repeat char="Arrow-Right" image="right"
+ weight="75"></kb-key>
+ <kb-hide-keyboard-key image="hide-keyboard.png" stretch>
+ </kb-hide-keyboard-key>
+ </kb-row>
+ <kb-altkey-container hidden>
+ </kb-altkey-container>
+</kb-keyset>
diff --git a/chromium/ui/keyboard/resources/layouts/webui_qwerty.html b/chromium/ui/keyboard/resources/layouts/webui_qwerty.html
deleted file mode 100644
index 2763307d708..00000000000
--- a/chromium/ui/keyboard/resources/layouts/webui_qwerty.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!--
- -- Copyright 2013 The Chromium Authors. All rights reserved.
- -- Use of this source code is governed by a BSD-style license that can be
- -- found in the LICENSE file.
- -->
-
-<template>
- <kb-keyset id="qwerty-upper">
- <kb-row class="top">
- <kb-key>Q</kb-key><kb-key>W</kb-key><kb-key>E</kb-key><kb-key>R</kb-key>
- <kb-key>T</kb-key><kb-key>Y</kb-key><kb-key>U</kb-key>
- <kb-key>I</kb-key><kb-key>O</kb-key><kb-key>P</kb-key>
- </kb-row>
- <kb-row>
- <div class="half-key-spacer"></div>
- <kb-key>A</kb-key><kb-key>S</kb-key><kb-key>D</kb-key><kb-key>F</kb-key>
- <kb-key>G</kb-key><kb-key>H</kb-key><kb-key>J</kb-key><kb-key>K</kb-key>
- <kb-key>L</kb-key>
- <div class="half-key-spacer"></div>
- </kb-row>
- <kb-row>
- <kb-shift-key class="padded-left-special" weight="1.4">shift</kb-shift-key>
- <kb-key>Z</kb-key><kb-key>X</kb-key><kb-key>C</kb-key><kb-key>V</kb-key>
- <kb-key>B</kb-key><kb-key>N</kb-key><kb-key>M</kb-key>
- <kb-key class="backspace padded-right-special dark" char="&#x0008;" repeat>delete</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid">?123</kb-key>
- <kb-key class="microphone dark" char="Microphone"></kb-key>
- <kb-key class="dark">,</kb-key>
- <kb-key class="space dark" char=" "></kb-key>
- <kb-key class="dark">.</kb-key>
- <kb-key class="return dark" char="&#000A;">enter</kb-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
-
- <kb-keyset id="qwerty-lower" isDefault=true>
- <kb-row class="top">
- <kb-key>q</kb-key><kb-key>w</kb-key><kb-key>e</kb-key><kb-key>r</kb-key>
- <kb-key>t</kb-key><kb-key>y</kb-key><kb-key>u</kb-key>
- <kb-key>i</kb-key><kb-key>o</kb-key><kb-key>p</kb-key>
- </kb-row>
- <kb-row>
- <div class="half-key-spacer"></div>
- <kb-key>a</kb-key><kb-key>s</kb-key><kb-key>d</kb-key><kb-key>f</kb-key>
- <kb-key>g</kb-key><kb-key>h</kb-key><kb-key>j</kb-key><kb-key>k</kb-key>
- <kb-key>l</kb-key>
- <div class="half-key-spacer"></div>
- </kb-row>
- <kb-row>
- <kb-shift-key class="padded-left-special" weight="1.4">shift</kb-shift-key>
- <kb-key>z</kb-key><kb-key>x</kb-key><kb-key>c</kb-key><kb-key>v</kb-key>
- <kb-key>b</kb-key><kb-key>n</kb-key><kb-key>m</kb-key>
- <kb-key class="backspace padded-right-special dark" char="&#x0008;" repeat>delete</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="symbol dark" toKeyset="down:symbol" char="Invalid">?123</kb-key>
- <kb-key class="microphone dark" char="Microphone"></kb-key>
- <kb-key class="dark">,</kb-key>
- <kb-key class="space dark" char=" "></kb-key>
- <kb-key class="dark">.</kb-key>
- <kb-key class='return dark' char="&#x000A;">enter</kb-key>
- </kb-row>
- <kb-altkey-container hidden>
- </kb-altkey-container>
- </kb-keyset>
-
- <kb-keyset id="qwerty-symbol">
- <kb-row class="top">
- <kb-key>1</kb-key><kb-key>2</kb-key><kb-key>3</kb-key><kb-key>4</kb-key>
- <kb-key>5</kb-key><kb-key>6</kb-key><kb-key>7</kb-key><kb-key>8</kb-key>
- <kb-key>9</kb-key><kb-key>0</kb-key>
- </kb-row>
- <kb-row>
- <kb-key>@</kb-key><kb-key>$</kb-key><kb-key>&</kb-key><kb-key>:</kb-key><kb-key>;</kb-key>
- <kb-key>/</kb-key><kb-key>(</kb-key><kb-key>)</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="left-more padded-left-special dark" toKeyset="down:more" char="Invalid">more</kb-key>
- <kb-key>"</kb-key><kb-key>'</kb-key><kb-key>-</kb-key>
- <kb-key>+</kb-key><kb-key>!</kb-key><kb-key>?</kb-key>
- <kb-key class="backspace padded-right-special dark" char="&#x0008;" repeat>delete</kb-key>
- </kb-row>
- <kb-row>
- <kb-abc-key>abc</kb-abc-key>
- <kb-key class="microphone dark" char="Microphone"></kb-key>
- <kb-key class="dark">,</kb-key>
- <kb-key class="space dark" char=" "></kb-key>
- <kb-key class="dark">.</kb-key>
- <kb-key class='return dark' char="&#x000A;">enter</kb-key>
- </kb-row>
- </kb-keyset>
-
- <kb-keyset id="qwerty-more">
- <kb-row class="top">
- <kb-key>&#x20AC;</kb-key><kb-key>&#x00A3;</kb-key><kb-key>&#x00A2;</kb-key>
- <kb-key>&#x2022;</kb-key><kb-key>&#x00B6;</kb-key><kb-key>|</kb-key>
- <kb-key>{</kb-key><kb-key>}</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="tab padded-left-special dark" char="&#x0009;">tab</kb-key>
- <kb-key>#</kb-key><kb-key>%</kb-key><kb-key>^</kb-key><kb-key>*</kb-key>
- <kb-key>\</kb-key><kb-key>&#x003C;</kb-key><kb-key>&#x003E;</kb-key>
- </kb-row>
- <kb-row>
- <kb-key class="left-more padded-left-special dark" toKeyset="down:symbol" char="Invalid">?123</kb-key>
- <kb-key>`</kb-key><kb-key>~</kb-key><kb-key>_</kb-key><kb-key>=</kb-key>
- <kb-key>[</kb-key><kb-key>]</kb-key>
- <kb-key class="backspace padded-right-special dark" char="&#x0008;" repeat>delete</kb-key>
- </kb-row>
- <kb-row>
- <kb-abc-key>abc</kb-abc-key>
- <kb-key class="microphone dark" char="Microphone"></kb-key>
- <kb-key class="dark">,</kb-key>
- <kb-key class="space dark" char=" "></kb-key>
- <kb-key class="dark">.</kb-key>
- <kb-key class='return dark' char="&#x000A;">enter</kb-key>
- </kb-row>
- </kb-keyset>
-</template>
diff --git a/chromium/ui/keyboard/resources/main.css b/chromium/ui/keyboard/resources/main.css
index e2c672adc7e..dfea91ea6b4 100644
--- a/chromium/ui/keyboard/resources/main.css
+++ b/chromium/ui/keyboard/resources/main.css
@@ -4,64 +4,40 @@
found in the LICENSE file.
*/
-body {
- -webkit-box-pack: center;
- -webkit-user-select: none;
- background-color: #0b0b0b;
- display: -webkit-box;
- margin: 0;
- overflow: hidden;
- padding: 0;
-}
-
-kb-keyboard {
- -webkit-box-orient: vertical;
- display: -webkit-box;
- max-width: 1280px;
- width: 1280px;
+@font-face {
+ font-family: roboto-bold;
+ src: url(roboto_bold.ttf);
}
+/**
+ * TODO(rsadam@): Remove all these rules once we switch to native
+ * shadow dom.
+ */
kb-keyboard.ctrl-active kb-modifier-key[char=Ctrl],
-kb-keyboard.alt-active kb-modifier-key[char=Alt] {
- color: lightblue;
+kb-keyboard.alt-active kb-modifier-key[char=Alt],
+kb-keyboard.caps-locked kb-shift-key.dark {
+ -webkit-box-shadow: inset 0 0 3px 2px #aaaaaa;
+ background-color: #cccccc;
}
/**
* Controls whether the shift key should be highlighted or not.
-* Only highlights if we are in the upper keyset, but not capslocked.
*/
-kb-keyboard:not(.caps-locked)[keyset=upper] kb-shift-key {
- color: lightblue;
+kb-keyboard[keyset="upper"] kb-shift-key.dark /deep/
+ .shift-light {
+ background-color: #4285f4;
}
-*.dark {
- background-color: #2a2a2c;
- border-top: 2px solid #3a3a3c;
+.space,
+.dark {
font-size: 70%;
- margin-left: 0.35em;
}
-
-.caps-locked kb-shift-key,
-.active {
- background-color: #848490 !important;
- border-top: 2px solid #A9A9AF !important;
- /* Do not use box shadow until performance improves
- * http://code.google.com/p/chromium/issues/detail?id=99045
- box-shadow: 0px 0px 15px #fff;
- */
+.dark:not(.active),
+:not(kb-altkey-set) > :not(.dark).active {
+ background-color: #dddddd;
}
-/**
- * The microphone key is handled separately from other images since the image
- * displayed changes depending on whether it's pressed or not.
- */
-.microphone {
- background-image: url('images/microphone.svg');
- background-position: 4%;
- background-size: 25% !important;
+.space {
+ color: #bbbbbb;
}
-
-.audio .microphone {
- background-image: url('images/microphone-green.svg');
-} \ No newline at end of file
diff --git a/chromium/ui/keyboard/resources/main.js b/chromium/ui/keyboard/resources/main.js
index 69975f6c95b..76306b00cc5 100644
--- a/chromium/ui/keyboard/resources/main.js
+++ b/chromium/ui/keyboard/resources/main.js
@@ -1,15 +1,584 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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.
+(function(exports) {
+ /**
+ * Alignment options for a keyset.
+ * @param {Object=} opt_keyset The keyset to calculate the dimensions for.
+ * Defaults to the current active keyset.
+ */
+ var AlignmentOptions = function(opt_keyset) {
+ var keyboard = document.getElementById('keyboard');
+ var keyset = opt_keyset || keyboard.activeKeyset;
+ this.calculate(keyset);
+ }
+
+ AlignmentOptions.prototype = {
+ /**
+ * The width of a regular key in logical pixels.
+ * @type {number}
+ */
+ keyWidth: 0,
+
+ /**
+ * The horizontal space between two keys in logical pixels.
+ * @type {number}
+ */
+ pitchX: 0,
+
+ /**
+ * The vertical space between two keys in logical pixels.
+ * @type {number}
+ */
+ pitchY: 0,
+
+ /**
+ * The width in logical pixels the row should expand within.
+ * @type {number}
+ */
+ availableWidth: 0,
+
+ /**
+ * The x-coordinate in logical pixels of the left most edge of the keyset.
+ * @type {number}
+ */
+ offsetLeft: 0,
+
+ /**
+ * The x-coordinate of the right most edge in logical pixels of the keyset.
+ * @type {number}
+ */
+ offsetRight: 0,
+
+ /**
+ * The height in logical pixels of all keys.
+ * @type {number}
+ */
+ keyHeight: 0,
+
+ /**
+ * The height in logical pixels the keyset should stretch to fit.
+ * @type {number}
+ */
+ availableHeight: 0,
+
+ /**
+ * The y-coordinate in logical pixels of the top most edge of the keyset.
+ * @type {number}
+ */
+ offsetTop: 0,
+
+ /**
+ * The y-coordinate in logical pixels of the bottom most edge of the keyset.
+ * @type {number}
+ */
+ offsetBottom: 0,
+
+ /**
+ * The ideal width of the keyboard container.
+ * @type {number}
+ */
+ width: 0,
+
+ /**
+ * The ideal height of the keyboard container.
+ * @type {number}
+ */
+ height: 0,
+
+ /**
+ * Recalculates the alignment options for a specific keyset.
+ * @param {Object} keyset The keyset to align.
+ */
+ calculate: function (keyset) {
+ var rows = keyset.querySelectorAll('kb-row').array();
+ // Pick candidate row. This is the row with the most keys.
+ var row = rows[0];
+ var candidateLength = rows[0].childElementCount;
+ for (var i = 1; i < rows.length; i++) {
+ if (rows[i].childElementCount > candidateLength &&
+ rows[i].align == RowAlignment.STRETCH) {
+ row = rows[i];
+ candidateLength = rows[i].childElementCount;
+ }
+ }
+ var allKeys = row.children;
+
+ // Calculates widths first.
+ // Weight of a single interspace.
+ var pitches = keyset.pitch.split();
+ var pitchWeightX;
+ var pitchWeightY;
+ pitchWeightX = parseFloat(pitches[0]);
+ pitchWeightY = pitches.length < 2 ? pitchWeightX : parseFloat(pitch[1]);
+
+ // Sum of all keys in the current row.
+ var keyWeightSumX = 0;
+ for (var i = 0; i < allKeys.length; i++) {
+ keyWeightSumX += allKeys[i].weight;
+ }
+
+ var interspaceWeightSumX = (allKeys.length -1) * pitchWeightX;
+ // Total weight of the row in X.
+ var totalWeightX = keyWeightSumX + interspaceWeightSumX +
+ keyset.weightLeft + keyset.weightRight;
+ var keyAspectRatio = getKeyAspectRatio();
+ var totalWeightY = (pitchWeightY * (rows.length - 1)) +
+ keyset.weightTop +
+ keyset.weightBottom;
+ for (var i = 0; i < rows.length; i++) {
+ totalWeightY += rows[i].weight / keyAspectRatio;
+ }
+ // Calculate width and height of the window.
+ var bounds = exports.getKeyboardBounds();
+
+ this.width = bounds.width;
+ this.height = bounds.height;
+ var pixelPerWeightX = bounds.width/totalWeightX;
+ var pixelPerWeightY = bounds.height/totalWeightY;
+
+ if (keyset.align == LayoutAlignment.CENTER) {
+ if (totalWeightX/bounds.width < totalWeightY/bounds.height) {
+ pixelPerWeightY = bounds.height/totalWeightY;
+ pixelPerWeightX = pixelPerWeightY;
+ this.width = Math.floor(pixelPerWeightX * totalWeightX)
+ } else {
+ pixelPerWeightX = bounds.width/totalWeightX;
+ pixelPerWeightY = pixelPerWeightX;
+ this.height = Math.floor(pixelPerWeightY * totalWeightY);
+ }
+ }
+ // Calculate pitch.
+ this.pitchX = Math.floor(pitchWeightX * pixelPerWeightX);
+ this.pitchY = Math.floor(pitchWeightY * pixelPerWeightY);
+
+ // Convert weight to pixels on x axis.
+ this.keyWidth = Math.floor(DEFAULT_KEY_WEIGHT * pixelPerWeightX);
+ var offsetLeft = Math.floor(keyset.weightLeft * pixelPerWeightX);
+ var offsetRight = Math.floor(keyset.weightRight * pixelPerWeightX);
+ this.availableWidth = this.width - offsetLeft - offsetRight;
+
+ // Calculates weight to pixels on the y axis.
+ var weightY = Math.floor(DEFAULT_KEY_WEIGHT / keyAspectRatio);
+ this.keyHeight = Math.floor(weightY * pixelPerWeightY);
+ var offsetTop = Math.floor(keyset.weightTop * pixelPerWeightY);
+ var offsetBottom = Math.floor(keyset.weightBottom * pixelPerWeightY);
+ this.availableHeight = this.height - offsetTop - offsetBottom;
+
+ var dX = bounds.width - this.width;
+ this.offsetLeft = offsetLeft + Math.floor(dX/2);
+ this.offsetRight = offsetRight + Math.ceil(dX/2)
+
+ var dY = bounds.height - this.height;
+ this.offsetBottom = offsetBottom + dY;
+ this.offsetTop = offsetTop;
+ },
+ };
+
+ /**
+ * A simple binary search.
+ * @param {Array} array The array to search.
+ * @param {number} start The start index.
+ * @param {number} end The end index.
+ * @param {Function<Object>:number} The test function used for searching.
+ * @private
+ * @return {number} The index of the search, or -1 if it was not found.
+ */
+ function binarySearch_(array, start, end, testFn) {
+ if (start > end) {
+ // No match found.
+ return -1;
+ }
+ var mid = Math.floor((start+end)/2);
+ var result = testFn(mid);
+ if (result == 0)
+ return mid;
+ if (result < 0)
+ return binarySearch_(array, start, mid - 1, testFn);
+ else
+ return binarySearch_(array, mid + 1, end, testFn);
+ }
+
+ /**
+ * Calculate width and height of the window.
+ * @private
+ * @return {Array.<String, number>} The bounds of the keyboard container.
+ */
+ function getKeyboardBounds_() {
+ return {
+ "width": screen.width,
+ "height": screen.height * DEFAULT_KEYBOARD_ASPECT_RATIO
+ };
+ }
+
+ /**
+ * Calculates the desired key aspect ratio based on screen size.
+ * @return {number} The aspect ratio to use.
+ */
+ function getKeyAspectRatio() {
+ return (screen.width > screen.height) ?
+ KEY_ASPECT_RATIO_LANDSCAPE : KEY_ASPECT_RATIO_PORTRAIT;
+ }
+
+ /**
+ * Callback function for when the window is resized.
+ */
+ var onResize = function() {
+ var keyboard = $('keyboard');
+ keyboard.stale = true;
+ var keyset = keyboard.activeKeyset;
+ if (keyset)
+ realignAll();
+ };
+
+ /**
+ * Updates a specific key to the position specified.
+ * @param {Object} key The key to update.
+ * @param {number} width The new width of the key.
+ * @param {number} height The new height of the key.
+ * @param {number} left The left corner of the key.
+ * @param {number} top The top corner of the key.
+ */
+ function updateKey(key, width, height, left, top) {
+ key.style.position = 'absolute';
+ key.style.width = width + 'px';
+ key.style.height = (height - KEY_PADDING_TOP - KEY_PADDING_BOTTOM) + 'px';
+ key.style.left = left + 'px';
+ key.style.top = (top + KEY_PADDING_TOP) + 'px';
+ }
-var onResize = function() {
- var x = window.innerWidth;
- var y = window.innerHeight;
- var height = (x > ASPECT_RATIO * y) ? y : Math.floor(x / ASPECT_RATIO);
- keyboard.style.height = height + 'px';
- keyboard.style.width = Math.floor(ASPECT_RATIO * height) + 'px';
- keyboard.style.fontSize = (height / FONT_SIZE_RATIO / ROW_LENGTH) + 'px';
-};
+ /**
+ * Returns the key closest to given x-coordinate
+ * @param {Array.<kb-key>} allKeys Sorted array of all possible key
+ * candidates.
+ * @param {number} x The x-coordinate.
+ * @param {number} pitch The pitch of the row.
+ * @param {boolean} alignLeft whether to search with respect to the left or
+ * or right edge.
+ * @return {?kb-key}
+ */
+ function findClosestKey(allKeys, x, pitch, alignLeft) {
+ // Test function.
+ var testFn = function(i) {
+ var ERROR_THRESH = 1;
+ var key = allKeys[i];
+ var left = parseFloat(key.style.left);
+ if (!alignLeft)
+ left += parseFloat(key.style.width);
+ var deltaRight = 0.5*(parseFloat(key.style.width) + pitch)
+ deltaLeft = 0.5 * pitch;
+ if (i > 0)
+ deltaLeft += 0.5*parseFloat(allKeys[i-1].style.width);
+ var high = Math.ceil(left + deltaRight) + ERROR_THRESH;
+ var low = Math.floor(left - deltaLeft) - ERROR_THRESH;
+ if (x <= high && x >= low)
+ return 0;
+ return x >= high? 1 : -1;
+ }
+ var index = exports.binarySearch(allKeys, 0, allKeys.length -1, testFn);
+ return index > 0 ? allKeys[index] : null;
+ }
+
+ /**
+ * Redistributes the total width amongst the keys in the range provided.
+ * @param {Array.<kb-key>} allKeys Ordered list of keys to stretch.
+ * @param {AlignmentOptions} params Options for aligning the keyset.
+ * @param {number} xOffset The x-coordinate of the key who's index is start.
+ * @param {number} width The total extraneous width to distribute.
+ * @param {number} keyHeight The height of each key.
+ * @param {number} yOffset The y-coordinate of the top edge of the row.
+ */
+ function redistribute(allKeys, params, xOffset, width, keyHeight, yOffset) {
+ var availableWidth = width - (allKeys.length - 1) * params.pitchX;
+ var stretchWeight = 0;
+ var nStretch = 0;
+ for (var i = 0; i < allKeys.length; i++) {
+ var key = allKeys[i];
+ if (key.stretch) {
+ stretchWeight += key.weight;
+ nStretch++;
+ } else if (key.weight == DEFAULT_KEY_WEIGHT) {
+ availableWidth -= params.keyWidth;
+ } else {
+ availableWidth -=
+ Math.floor(key.weight/DEFAULT_KEY_WEIGHT * params.keyWidth);
+ }
+ }
+ if (stretchWeight <= 0)
+ console.error("Cannot stretch row without a stretchable key");
+ // Rounding error to distribute.
+ var pixelsPerWeight = availableWidth / stretchWeight;
+ for (var i = 0; i < allKeys.length; i++) {
+ var key = allKeys[i];
+ var keyWidth = params.keyWidth;
+ if (key.weight != DEFAULT_KEY_WEIGHT) {
+ keyWidth =
+ Math.floor(key.weight/DEFAULT_KEY_WEIGHT * params.keyWidth);
+ }
+ if (key.stretch) {
+ nStretch--;
+ if (nStretch > 0) {
+ keyWidth = Math.floor(key.weight * pixelsPerWeight);
+ availableWidth -= keyWidth;
+ } else {
+ keyWidth = availableWidth;
+ }
+ }
+ updateKey(key, keyWidth, keyHeight, xOffset, yOffset)
+ xOffset += keyWidth + params.pitchX;
+ }
+ }
+
+ /**
+ * Aligns a row such that the spacebar is perfectly aligned with the row above
+ * it. A precondition is that all keys in this row can be stretched as needed.
+ * @param {!kb-row} row The current row to be aligned.
+ * @param {!kb-row} prevRow The row above the current row.
+ * @param {!AlignmentOptions} params Options for aligning the keyset.
+ * @param {number} keyHeight The height of the keys in this row.
+ * @param {number} heightOffset The height offset caused by the rows above.
+ */
+ function realignSpacebarRow(row, prevRow, params, keyHeight, heightOffset) {
+ var allKeys = row.children;
+ var stretchWeightBeforeSpace = 0;
+ var stretchBefore = 0;
+ var stretchWeightAfterSpace = 0;
+ var stretchAfter = 0;
+ var spaceIndex = -1;
+
+ for (var i=0; i< allKeys.length; i++) {
+ if (spaceIndex == -1) {
+ if (allKeys[i].classList.contains('space')) {
+ spaceIndex = i;
+ continue;
+ } else {
+ stretchWeightBeforeSpace += allKeys[i].weight;
+ stretchBefore++;
+ }
+ } else {
+ stretchWeightAfterSpace += allKeys[i].weight;
+ stretchAfter++;
+ }
+ }
+ if (spaceIndex == -1) {
+ console.error("No spacebar found in this row.");
+ return;
+ }
+ var totalWeight = stretchWeightBeforeSpace +
+ stretchWeightAfterSpace +
+ allKeys[spaceIndex].weight;
+ var widthForKeys = params.availableWidth -
+ (params.pitchX * (allKeys.length - 1 ))
+ // Number of pixels to assign per unit weight.
+ var pixelsPerWeight = widthForKeys/totalWeight;
+ // Predicted left edge of the space bar.
+ var spacePredictedLeft = params.offsetLeft +
+ (spaceIndex * params.pitchX) +
+ (stretchWeightBeforeSpace * pixelsPerWeight);
+ var prevRowKeys = prevRow.children;
+ // Find closest keys to the spacebar in order to align it to them.
+ var leftKey =
+ findClosestKey(prevRowKeys, spacePredictedLeft, params.pitchX, true);
+
+ var spacePredictedRight = spacePredictedLeft +
+ allKeys[spaceIndex].weight * (params.keyWidth/100);
+
+ var rightKey =
+ findClosestKey(prevRowKeys, spacePredictedRight, params.pitchX, false);
+
+ var yOffset = params.offsetTop + heightOffset;
+ // Fix left side.
+ var leftEdge = parseFloat(leftKey.style.left);
+ var leftWidth = leftEdge - params.offsetLeft - params.pitchX;
+ var leftKeys = allKeys.array().slice(0, spaceIndex);
+ redistribute(leftKeys,
+ params,
+ params.offsetLeft,
+ leftWidth,
+ keyHeight,
+ yOffset);
+ // Fix right side.
+ var rightEdge = parseFloat(rightKey.style.left) +
+ parseFloat(rightKey.style.width);
+ var spacebarWidth = rightEdge - leftEdge;
+ updateKey(allKeys[spaceIndex],
+ spacebarWidth,
+ keyHeight,
+ leftEdge,
+ yOffset);
+ var rightWidth =
+ params.availableWidth - (rightEdge - params.offsetLeft + params.pitchX);
+ var rightKeys = allKeys.array().slice(spaceIndex + 1);
+ redistribute(rightKeys,
+ params,
+ rightEdge + params.pitchX,//xOffset.
+ rightWidth,
+ keyHeight,
+ yOffset);
+ }
+
+ /**
+ * Realigns a given row based on the parameters provided.
+ * @param {!kb-row} row The row to realign.
+ * @param {!AlignmentOptions} params The parameters used to align the keyset.
+ * @param {number} The height of the keys.
+ * @param {number} heightOffset The offset caused by rows above it.
+ */
+ function realignRow(row, params, keyHeight, heightOffset) {
+ var all = row.children;
+ var nStretch = 0;
+ var stretchWeightSum = 0;
+ var allSum = 0;
+ // Keeps track of where to distribute pixels caused by round off errors.
+ var deltaWidth = [];
+ for (var i = 0; i < all.length; i++) {
+ deltaWidth.push(0)
+ var key = all[i];
+ if (key.weight == DEFAULT_KEY_WEIGHT){
+ allSum += params.keyWidth;
+ } else {
+ var width =
+ Math.floor((params.keyWidth/DEFAULT_KEY_WEIGHT) * key.weight);
+ allSum += width;
+ }
+ if (!key.stretch)
+ continue;
+ nStretch++;
+ stretchWeightSum += key.weight;
+ }
+ var nRegular = all.length - nStretch;
+ // Extra space.
+ var extra = params.availableWidth -
+ allSum -
+ (params.pitchX * (all.length -1));
+ var xOffset = params.offsetLeft;
+
+ var alignment = row.align;
+ switch (alignment) {
+ case RowAlignment.STRETCH:
+ var extraPerWeight = extra/stretchWeightSum;
+ for (var i = 0; i < all.length; i++) {
+ if (!all[i].stretch)
+ continue;
+ var delta = Math.floor(all[i].weight * extraPerWeight);
+ extra -= delta;
+ deltaWidth[i] = delta;
+ // All left-over pixels assigned to right most stretchable key.
+ nStretch--;
+ if (nStretch == 0)
+ deltaWidth[i] += extra;
+ }
+ break;
+ case RowAlignment.CENTER:
+ xOffset += Math.floor(extra/2)
+ break;
+ case RowAlignment.RIGHT:
+ xOffset += extra;
+ break;
+ default:
+ break;
+ };
+
+ var yOffset = params.offsetTop + heightOffset;
+ var left = xOffset;
+ for (var i = 0; i < all.length; i++) {
+ var key = all[i];
+ var width = params.keyWidth;
+ if (key.weight != DEFAULT_KEY_WEIGHT)
+ width = Math.floor((params.keyWidth/DEFAULT_KEY_WEIGHT) * key.weight)
+ width += deltaWidth[i];
+ updateKey(key, width, keyHeight, left, yOffset)
+ left += (width + params.pitchX);
+ }
+ }
+
+ /**
+ * Realigns the keysets in all layouts of the keyboard.
+ */
+ function realignAll() {
+ resizeKeyboardContainer()
+ var keyboard = $('keyboard');
+ var layoutParams = {};
+ var idToLayout = function(id) {
+ var parts = id.split('-');
+ parts.pop();
+ return parts.join('-');
+ }
+
+ var keysets = keyboard.querySelectorAll('kb-keyset').array();
+ for (var i=0; i< keysets.length; i++) {
+ var keyset = keysets[i];
+ var layout = idToLayout(keyset.id);
+ // Caches the layouts size parameters since all keysets in the same layout
+ // will have the same specs.
+ if (!(layout in layoutParams))
+ layoutParams[layout] = new AlignmentOptions(keyset);
+ realignKeyset(keyset, layoutParams[layout]);
+ }
+ exports.recordKeysets();
+ }
+
+ /**
+ * Realigns the keysets in the current layout of the keyboard.
+ */
+ function realign() {
+ var keyboard = $('keyboard');
+ var params = new AlignmentOptions();
+ // Check if current window bounds are accurate.
+ resizeKeyboardContainer(params)
+ var layout = keyboard.layout;
+ var keysets =
+ keyboard.querySelectorAll('kb-keyset[id^=' + layout + ']').array();
+ for (var i = 0; i<keysets.length ; i++) {
+ realignKeyset(keysets[i], params);
+ }
+ keyboard.stale = false;
+ exports.recordKeysets();
+ }
+
+ /*
+ * Realigns a given keyset.
+ * @param {Object} keyset The keyset to realign.
+ * @param {!AlignmentOptions} params The parameters used to align the keyset.
+ */
+ function realignKeyset(keyset, params) {
+ var rows = keyset.querySelectorAll('kb-row').array();
+ keyset.style.fontSize = (params.availableHeight /
+ FONT_SIZE_RATIO / rows.length) + 'px';
+ var heightOffset = 0;
+ for (var i = 0; i < rows.length; i++) {
+ var row = rows[i];
+ var rowHeight =
+ Math.floor(params.keyHeight * (row.weight / DEFAULT_KEY_WEIGHT));
+ if (row.querySelector('.space') && (i > 1)) {
+ realignSpacebarRow(row, rows[i-1], params, rowHeight, heightOffset)
+ } else {
+ realignRow(row, params, rowHeight, heightOffset);
+ }
+ heightOffset += (rowHeight + params.pitchY);
+ }
+ }
+
+ /**
+ * Resizes the keyboard container if needed.
+ * @params {AlignmentOptions=} opt_params Optional parameters to use. Defaults
+ * to the parameters of the current active keyset.
+ */
+ function resizeKeyboardContainer(opt_params) {
+ var params = opt_params ? opt_params : new AlignmentOptions();
+ if (Math.abs(window.innerHeight - params.height) > RESIZE_THRESHOLD) {
+ // Cannot resize more than 50% of screen height due to crbug.com/338829.
+ window.resizeTo(params.width, params.height);
+ }
+ }
+
+ addEventListener('resize', onResize);
+ addEventListener('load', onResize);
+
+ exports.getKeyboardBounds = getKeyboardBounds_;
+ exports.binarySearch = binarySearch_;
+ exports.realignAll = realignAll;
+})(this);
/**
* Recursively replace all kb-key-import elements with imported documents.
@@ -30,38 +599,38 @@ function importHTML(content) {
}
/**
- * Replace all kb-key-sequence elements with generated kb-key elements.
- * @param {!DocumentFragment} importedContent The imported dom structure.
- */
-function expandHTML(importedContent) {
- var keySequences = importedContent.querySelectorAll('kb-key-sequence');
- if (keySequences.length != 0) {
- keySequences.array().forEach(function(element) {
- var generatedDom = element.generateDom();
- element.parentNode.replaceChild(generatedDom, element);
+ * Flatten the keysets which represents a keyboard layout.
+ */
+function flattenKeysets() {
+ var keysets = $('keyboard').querySelectorAll('kb-keyset');
+ if (keysets.length > 0) {
+ keysets.array().forEach(function(element) {
+ element.flattenKeyset();
});
}
}
-/**
- * Flatten the keysets which represents a keyboard layout. It has two steps:
- * 1) Replace all kb-key-import elements with imported document that associated
- * with linkid.
- * 2) Replace all kb-key-sequence elements with generated DOM structures.
- * @param {!Document} content Document to process.
- */
-function flattenKeysets(content) {
- var importedContent = importHTML(content);
- expandHTML(importedContent);
- return importedContent;
+function resolveAudio() {
+ var keyboard = $('keyboard');
+ keyboard.addSound(Sound.DEFAULT);
+ var nodes = keyboard.querySelectorAll('[sound]').array();
+ // Get id's of all unique sounds.
+ for (var i = 0; i < nodes.length; i++) {
+ var id = nodes[i].getAttribute('sound');
+ keyboard.addSound(id);
+ }
}
-addEventListener('resize', onResize);
-
-addEventListener('load', onResize);
-
// Prevents all default actions of touch. Keyboard should use its own gesture
// recognizer.
addEventListener('touchstart', function(e) { e.preventDefault() });
addEventListener('touchend', function(e) { e.preventDefault() });
addEventListener('touchmove', function(e) { e.preventDefault() });
+addEventListener('polymer-ready', function(e) {
+ flattenKeysets();
+ resolveAudio();
+});
+addEventListener('stateChange', function(e) {
+ if (e.detail.value == $('keyboard').activeKeysetId)
+ realignAll();
+})
diff --git a/chromium/ui/keyboard/resources/polymer_loader.js b/chromium/ui/keyboard/resources/polymer_loader.js
index f39ea61fae2..e11d7c777d6 100644
--- a/chromium/ui/keyboard/resources/polymer_loader.js
+++ b/chromium/ui/keyboard/resources/polymer_loader.js
@@ -1,11 +1,5 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
-// This is necessary because polymer currently doesn't handle the configuration
-// where native Custom Elements are available but native Shadow DOM is not.
-// TODO(bshe): remove this line when polymer supports the configuration.
-document.register = undefined;
-
-<include src="../../../third_party/polymer/platform.js"></include>
-<include src="../../../third_party/polymer/polymer.js"></include>
+<include src="../../../third_party/polymer/platform/platform.js"></include>
+<include src="../../../third_party/polymer/polymer/polymer.js"></include>
diff --git a/chromium/ui/keyboard/resources/roboto_bold.ttf b/chromium/ui/keyboard/resources/roboto_bold.ttf
new file mode 100644
index 00000000000..aaf374d2cc0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/roboto_bold.ttf
Binary files differ
diff --git a/chromium/ui/keyboard/resources/sounds/keypress-delete.wav b/chromium/ui/keyboard/resources/sounds/keypress-delete.wav
new file mode 100644
index 00000000000..fb8b0189402
--- /dev/null
+++ b/chromium/ui/keyboard/resources/sounds/keypress-delete.wav
Binary files differ
diff --git a/chromium/ui/keyboard/resources/sounds/keypress-return.wav b/chromium/ui/keyboard/resources/sounds/keypress-return.wav
new file mode 100644
index 00000000000..491333bad11
--- /dev/null
+++ b/chromium/ui/keyboard/resources/sounds/keypress-return.wav
Binary files differ
diff --git a/chromium/ui/keyboard/resources/sounds/keypress-spacebar.wav b/chromium/ui/keyboard/resources/sounds/keypress-spacebar.wav
new file mode 100644
index 00000000000..2d58c6d78c0
--- /dev/null
+++ b/chromium/ui/keyboard/resources/sounds/keypress-spacebar.wav
Binary files differ
diff --git a/chromium/ui/keyboard/resources/sounds/keypress-standard.wav b/chromium/ui/keyboard/resources/sounds/keypress-standard.wav
new file mode 100644
index 00000000000..aa54b4c2ee1
--- /dev/null
+++ b/chromium/ui/keyboard/resources/sounds/keypress-standard.wav
Binary files differ
diff --git a/chromium/ui/keyboard/resources/touch_fuzzing.js b/chromium/ui/keyboard/resources/touch_fuzzing.js
new file mode 100644
index 00000000000..7a6a2ce5c88
--- /dev/null
+++ b/chromium/ui/keyboard/resources/touch_fuzzing.js
@@ -0,0 +1,449 @@
+// 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.
+
+
+(function(exports) {
+ /**
+ * Orientation of a line.
+ * @enum {boolean}
+ */
+ var Orientation = {
+ VERTICAL: false,
+ HORIZONTAL: true
+ }
+
+ /**
+ * Map from keysetId to layout.
+ * @type {Map<String,KeysetLayout>}
+ * @private
+ */
+ var layouts = {};
+
+ /**
+ * Container for storing a keyset's layout.
+ */
+ var KeysetLayout = function() {
+ this.keys = [];
+ }
+
+ KeysetLayout.prototype = {
+ /**
+ * All keys in the keyset.
+ * @type {Array<Key>}
+ */
+ keys: undefined,
+
+ /**
+ * Spacial partitioning of all keys in the keyset.
+ * @type {DecisionNode}
+ */
+ tree: undefined,
+
+ /**
+ * Add a key to the keyset.
+ */
+ add: function(key) {
+ this.keys.push(key);
+ },
+
+ /**
+ * Regenerates a decision tree using the keys in the keyset.
+ */
+ regenerateTree: function() {
+ // Split using horizontal lines first, as keyboards tend to be
+ // row-centric.
+ var splits = findSplits(this.keys, Orientation.HORIZONTAL);
+ this.tree = createBinaryTree(0, splits.length - 1, splits);
+ if (this.tree)
+ this.tree.populate(this.keys);
+ },
+
+ /**
+ * Searches the tree for the key closest to the point provided.
+ * @param {number} x The x-coordinate.
+ * @param {number} y The y-coordinate.
+ * @return {?kb-key} The key, or null if none found.
+ */
+ findClosestKey: function(x, y) {
+ var closestNode = this.tree.findClosestNode(x, y);
+ var key = closestNode.data;
+ if (!key)
+ return;
+ // Ignore touches that aren't close.
+ return key.distanceTo(x,y) <= MAX_TOUCH_FUZZ_DISTANCE ?
+ key.key : null;
+ },
+
+ /**
+ * Returns the position data of all keys in this keyset.
+ * @return {Array<Map>}
+ */
+ getLayout: function() {
+ return this.keys.map(function(key) {
+ return key.toMap();
+ });
+ },
+ };
+
+ /**
+ * Container for caching a key's data.
+ * @param {Object} key The key to cache.
+ * @param {number} left The x-coordinate of the left edge of the key.
+ * @param {number} top The y-coordinate of the top edge of the key.
+ * @param {number} width The width of the key in px.
+ * @param {number} height The height of the key in px.
+ */
+ var Key = function(key) {
+ this.key = key;
+ var style = key.style;
+ this.top = parseFloat(style.top) - KEY_PADDING_TOP;
+ this.left = parseFloat(style.left);
+ this.right = this.left + parseFloat(style.width);
+ this.bottom = this.top + parseFloat(style.height) + KEY_PADDING_TOP
+ + KEY_PADDING_BOTTOM;
+ }
+
+ Key.prototype = {
+ /**
+ * Manhattan distance from the the provided point to the key.
+ * @param {number} x The x-coordinate of the point.
+ * @param {number} y The y-coordinate of the point.
+ * @return {number}.
+ */
+ distanceTo: function (x, y) {
+ return Math.abs(this.intersect(new Line(x))) +
+ Math.abs(this.intersect(new Line(y, true)));
+ },
+
+ /**
+ * Checks whether the key intersects with the line provided.
+ * @param {!Line} line The line.
+ * @return {number} Zero if it intersects, signed manhattan distance if it
+ * does not.
+ */
+ intersect: function(line) {
+ var min = line.rotated ? this.top : this.left;
+ var max = line.rotated ? this.bottom : this.right;
+ return (line.c > max) ? line.c - max : Math.min(0, line.c - min);
+ },
+
+ /**
+ * Returns the Key as a map.
+ * @return {Map<String,number>}
+ */
+ toMap: function() {
+ return {
+ 'x': this.left,
+ 'y': this.top,
+ 'width': this.right - this.left,
+ 'height': this.bottom - this.bottom,
+ }
+ },
+ };
+
+ /**
+ * Object representing the line y = c or x = c.
+ * @param {number} The x or y coordinate of the intersection line depending on
+ * on orientation.
+ * @param {Orientation} orientation The orientation of the line.
+ */
+ var Line = function(c, orientation) {
+ this.c = c;
+ this.rotated = orientation;
+ };
+
+ Line.prototype = {
+ /**
+ * The position of the provided point in relation to the line.
+ * @param {number} x The x-coordinate of the point.
+ * @param {number} y The y-coordinate of the point.
+ * @return {number} Zero if they intersect, negative if the point is before
+ * the line, positive if it's after.
+ */
+ testPoint: function (x, y) {
+ var c = this.rotated ? y : x;
+ return this.c == c ? 0 : c - this.c;
+ },
+
+ test: function (key) {
+ // Key already provides an intersect method. If the key is to the right of
+ // the line, then the line is to the left of the key.
+ return -1 * key.intersect(this);
+ },
+ };
+
+ /**
+ * A node used to split 2D space.
+ * @param {Line} The line to split the space with.
+ */
+ var DecisionNode = function(line) {
+ this.decision = line;
+ };
+
+ DecisionNode.prototype = {
+ /**
+ * The test whether to proceed in the left or right branch.
+ * @type {Line}
+ */
+ decision: undefined,
+
+ /**
+ * The branch for nodes that failed the decision test.
+ * @type {?DecisionNode}
+ */
+ fail: undefined,
+
+ /**
+ * The branch for nodes that passed the decision test.
+ * @type {?DecisionNode}
+ */
+ pass: undefined,
+
+ /**
+ * Finds the node closest to the point provided.
+ * @param {number} x The x-coordinate.
+ * @param {number} y The y-coordinate.
+ * @return {DecisionNode | LeafNode}
+ */
+ findClosestNode: function(x, y) {
+ return this.search(function(node){
+ return node.decision.testPoint(x,y) >= 0;
+ });
+ },
+
+ /**
+ * Populates the decision tree with elements.
+ * @param {Array{Key}} The child elements.
+ */
+ populate: function(data) {
+ if (!data.length)
+ return;
+ var pass = [];
+ var fail = [];
+ for (var i = 0; i< data.length; i++) {
+ var result = this.decision.test(data[i]);
+ // Add to both branches if result == 0.
+ if (result >= 0)
+ pass.push(data[i]);
+ if (result <= 0)
+ fail.push(data[i]);
+ }
+ var currentRotation = this.decision.rotated;
+ /**
+ * Splits the tree further such that each leaf has exactly one data point.
+ * @param {Array} array The data points.
+ * @return {DecisionNode | LeafNode} The new branch for the tree.
+ */
+ var updateBranch = function(array) {
+ if (array.length == 1) {
+ return new LeafNode(array[0]);
+ } else {
+ var splits = findSplits(array, !currentRotation)
+ var tree = createBinaryTree(0, splits.length - 1, splits);
+ tree.populate(array);
+ return tree;
+ }
+ };
+ // All elements that passed the decision test.
+ if (pass.length > 0) {
+ if (this.pass)
+ this.pass.populate(pass);
+ else
+ this.pass = updateBranch(pass);
+ }
+ // All elements that failed the decision test.
+ if (fail.length > 0) {
+ if (this.fail)
+ this.fail.populate(fail);
+ else
+ this.fail = updateBranch(fail);
+ }
+ },
+
+ /**
+ * Searches for the first leaf that matches the search function.
+ * @param {Function<DecisionNode>: Boolean} searchFn The function used to
+ * determine whether to search in the left or right subtree.
+ * @param {DecisionNode | LeafNode} The node that most closely matches the
+ * search parameters.
+ */
+ search: function(searchFn) {
+ if (searchFn(this)) {
+ return this.pass ? this.pass.search(searchFn) : this;
+ }
+ return this.fail ? this.fail.search(searchFn) : this;
+ },
+
+ /**
+ * Tests whether the key belongs in the left or right branch of this node.
+ * @param {Key} key The key being tested.
+ * @return {boolean} Whether it belongs in the right branch.
+ */
+ test: function(key) {
+ return this.decision.testKey(key)
+ },
+ };
+
+ /**
+ * Structure representing a leaf in the decision tree. It contains a single
+ * data point.
+ */
+ var LeafNode = function(data) {
+ this.data = data;
+ };
+
+ LeafNode.prototype = {
+ search: function() {
+ return this;
+ },
+ };
+
+ /**
+ * Converts the array to a binary tree.
+ * @param {number} start The start index.
+ * @param {number} end The end index.
+ * @param {Array} nodes The array to convert.
+ * @return {DecisionNode}
+ */
+ var createBinaryTree = function(start, end, nodes) {
+ if (start > end)
+ return;
+ var midpoint = Math.floor((end + start)/2);
+ var root = new DecisionNode(nodes[midpoint]);
+ root.fail = createBinaryTree(start, midpoint - 1, nodes);
+ root.pass = createBinaryTree(midpoint + 1, end, nodes);
+ return root;
+ };
+
+ /**
+ * Calculates the optimum split points on the specified axis.
+ * @param {Array<Keys>} allKeys All keys in the keyset.
+ * @param {Partition=} axis Whether to split on the y-axis instead.
+ * @return {Array<Line>} The optimum split points.
+ */
+ var findSplits = function(allKeys, orientation) {
+ /**
+ * Returns the minimum edge on the key.
+ * @param {Key} The key.
+ * @return {number}
+ */
+ var getMin = function(key) {
+ return orientation == Orientation.HORIZONTAL ? key.top : key.left;
+ };
+
+ /**
+ * Returns the maximum edge on the key.
+ * @param {Key} The key.
+ */
+ var getMax = function(key) {
+ return orientation == Orientation.HORIZONTAL ? key.bottom : key.right;
+ };
+
+ /**
+ * Returns a duplicate free version of array.
+ * @param {Array} array A sorted array.
+ * @return {Array} Sorted array without duplicates.
+ */
+ var unique = function(array) {
+ var result = [];
+ for (var i = 0; i< array.length; i++) {
+ if (i == 0 || result[result.length -1] != array[i])
+ result.push(array[i]);
+ }
+ return result;
+ };
+
+ /**
+ * Creates an array of zeroes.
+ * @param {number} length The length of the array.
+ * @return {Array{number}}
+ */
+ var zeroes = function(length) {
+ var array = new Array(length);
+ for (var i = 0; i < length; i++) {
+ array[i] = 0;
+ }
+ return array;
+ }
+ // All edges of keys.
+ var edges = [];
+ for (var i = 0; i < allKeys.length; i++) {
+ var key = allKeys[i];
+ var min = getMin(key);
+ var max = getMax(key);
+ edges.push(min);
+ edges.push(max);
+ }
+ // Array.sort() sorts lexicographically by default.
+ edges.sort(function(a, b) {
+ return a - b;
+ });
+ edges = unique(edges);
+ // Container for projection sum from edge i to edge i + 1.
+ var intervalWeight = zeroes(edges.length);
+
+ for (var i = 0; i < allKeys.length; i++) {
+ var key = allKeys[i];
+ var min = getMin(key);
+ var max = getMax(key);
+ var index =
+ exports.binarySearch(edges, 0, edges.length - 1, function(index) {
+ var edge = edges[index];
+ return edge == min ? 0 : min - edge;
+ });
+ if (index < 0 || min != edges[index]) {
+ console.error("Unable to split keys.");
+ return;
+ }
+ // Key can span multiple edges.
+ for (var j = index; j < edges.length && edges[j] < max; j++) {
+ intervalWeight[j] ++;
+ }
+ }
+
+ var splits = [];
+ // Min and max are bad splits.
+ for (var i = 1; i < intervalWeight.length - 1; i++) {
+ if (intervalWeight[i] < intervalWeight[i - 1]) {
+ var mid = Math.abs((edges[i] + edges[i+1]) / 2)
+ splits.push(new Line(mid, orientation));
+ }
+ }
+ return splits;
+ }
+
+ /**
+ * Caches the layout of current keysets.
+ */
+ function recordKeysets_() {
+ layouts = {};
+ var keysets = $('keyboard').querySelectorAll('kb-keyset').array();
+ for (var i = 0; i < keysets.length; i++) {
+ var keyset = keysets[i];
+ var layout = new KeysetLayout();
+ var rows = keyset.querySelectorAll('kb-row').array();
+ for (var j = 0; j < rows.length; j++) {
+ var row = rows[j];
+ var nodes = row.children;
+ for (var k = 0 ; k < nodes.length; k++) {
+ layout.add(new Key(nodes[k]));
+ }
+ }
+ layout.regenerateTree();
+ layouts[keyset.id] = layout;
+ }
+ };
+
+ /**
+ * Returns the layout of the keyset.
+ * @param{!String} id The id of the keyset.
+ * @private
+ */
+ var getKeysetLayout_ = function(id) {
+ return layouts[id];
+ };
+
+ exports.getKeysetLayout = getKeysetLayout_;
+ exports.recordKeysets = recordKeysets_;
+})(this);
diff --git a/chromium/ui/keyboard/resources/webui/api_adapter.js b/chromium/ui/keyboard/resources/webui/api_adapter.js
deleted file mode 100644
index 206f60dd8af..00000000000
--- a/chromium/ui/keyboard/resources/webui/api_adapter.js
+++ /dev/null
@@ -1,89 +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.
-
-function insertText(text) {
- chrome.send('insertText', [ text ]);
-}
-
-function sendKeyEvent(event) {
- chrome.send('sendKeyEvent', [ event ]);
-}
-
-function hideKeyboard() {
- chrome.send('hideKeyboard');
-}
-
-function keyboardLoaded() {
- chrome.send('keyboardLoaded');
-}
-
-(function(exports) {
- /**
- * An array to save callbacks of each request.
- * @type {Array.<function(Object)>}
- */
- var requestIdCallbackMap = [];
-
- /**
- * An incremental integer that represents a unique requestId.
- * @type {number}
- */
- var requestId = 0;
-
- /**
- * Called when a text input box gets focus.
- * @param {object} inputContext Describes an input context. It only contains
- * the type of text input box at present and only "password", "number" and
- * "text" are supported.
- */
- function OnTextInputBoxFocused(inputContext) {
- // Do not want to use the system keyboard for passwords in webui.
- if (inputContext.type == 'password')
- inputContext.type = 'text';
- keyboard.inputTypeValue = inputContext.type;
- }
-
- /**
- * Gets the context of the focused input field. The context is returned as a
- * paramter in the |callback|.
- * @param {function(Object)} callback The callback function after the webui
- * function finished.
- * @return {number} The ID of the new request.
- */
- function GetInputContext(callback) {
- var id = requestId;
- requestIdCallbackMap[id] = callback;
- chrome.send('getInputContext', [ id ]);
- requestId++;
- return id;
- }
-
- /**
- * Cancel the callback specified by requestId.
- * @param {number} requestId The requestId of the callback that about to
- * cancel.
- */
- function CancelRequest(requestId) {
- requestIdCallbackMap[requestId] = undefined;
- }
-
- /**
- * Webui function callback. Any call to chrome.send('getInputContext', [id])
- * should trigger this function being called with the parameter
- * inputContext.requestId == id.
- * @param {Object} inputContext The context of focused input field. Note we
- * only have type(input box type) and requestId fields now.
- */
- function GetInputContextCallback(inputContext) {
- var requestId = inputContext.requestId;
- if (!requestIdCallbackMap[requestId])
- return;
- requestIdCallbackMap[requestId](inputContext);
- }
-
- exports.OnTextInputBoxFocused = OnTextInputBoxFocused;
- exports.getInputContext = GetInputContext;
- exports.cancelRequest = CancelRequest;
- exports.GetInputContextCallback = GetInputContextCallback;
-})(this);
diff --git a/chromium/ui/keyboard/resources/webui/constants.js b/chromium/ui/keyboard/resources/webui/constants.js
deleted file mode 100644
index 94ccfb2f96e..00000000000
--- a/chromium/ui/keyboard/resources/webui/constants.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-/**
- * Aspect ratio of keyboard.
- * @type {number}
- */
-var ASPECT_RATIO = 2.0;
-
-/**
- * Ratio of key height and font size.
- * @type {number}
- */
-var FONT_SIZE_RATIO = 2;
-
-/**
- * The number of rows in each keyset.
- * @type {number}
- */
-// TODO(bshe): The number of rows should equal to the number of kb-row elements
-// in kb-keyset. Remove this variable once figure out how to calculate the
-// number from keysets.
-
-var ROW_LENGTH = 4;
diff --git a/chromium/ui/keyboard/resources/webui/main.css b/chromium/ui/keyboard/resources/webui/main.css
deleted file mode 100644
index e14611d3d33..00000000000
--- a/chromium/ui/keyboard/resources/webui/main.css
+++ /dev/null
@@ -1,172 +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.
-*/
-
-body {
- -webkit-box-pack: center;
- -webkit-user-select: none;
- background-color: #0b0b0b;
- display: -webkit-box;
- margin: 0;
- overflow: hidden;
- padding: 0;
-}
-
-kb-keyboard {
- -webkit-box-orient: vertical;
- display: -webkit-box;
-}
-
-kb-abc-key,
-kb-shift-key,
-kb-key {
- background-color: #3b3b3e;
- background-position: center center;
- background-repeat: no-repeat;
- background-size: contain;
- border-top: 2px solid #4b4b4e;
- border-radius: 1px;
- color: #ffffff;
- display: -webkit-box;
- font-family: 'Open Sans', sans-serif;
- font-weight: 600;
- margin-left: 0.2em;
- position: relative;
-}
-
-kb-abc-key::x-key,
-kb-shift-key::x-key,
-kb-key::x-key {
- bottom: 0;
- height: 1.2em;
- left: 0;
- margin: auto;
- padding-left: 0.5em;
- padding-right: 0.5em;
- position: absolute;
- right: 0;
- top: 0;
-}
-
-kb-key::x-hinttext {
- color: #7c7c7c;
- font-size: 70%;
- position: absolute;
- right: 7%;
- top: 5%;
-}
-
-kb-key::x-key[inverted] {
- color: #7c7c7c;
-}
-
-kb-key::x-hinttext[inverted] {
- color: #ffffff;
-}
-
-kb-abc-key.dark,
-kb-shift-key.dark,
-kb-key.dark {
- background-color: #2a2a2c;
- border-top: 2px solid #3a3a3c;
-}
-
-kb-altkey::x-key {
- bottom: 0;
- height: 1.2em;
- left: 0;
- margin: auto;
- position: absolute;
- right: 0;
- top: 0;
- text-align: center;
-}
-
-/* Left and right-side special keys with a character letter next to them need
- * additional padding.
- * */
-kb-abc-key.padded-left-special,
-kb-shift-key.padded-left-special,
-kb-key.padded-left-special {
- margin-right: 2px;
-}
-
-kb-abc-key.padded-right-special,
-kb-shift-key.padded-right-special,
-kb-key.padded-right-special {
- margin-left: 5px;
-}
-
-kb-row.top {
- margin-top: 5px !important;
-}
-
-.active {
- background-color: #848490 !important;
- border-top: 2px solid #A9A9AF !important;
- /* Do not use box shadow until performance improves
- * http://code.google.com/p/chromium/issues/detail?id=99045
- * box-shadow: 0px 0px 15px #fff;
- * */
-}
-
-.at,
-.com,
-.comma,
-.hide,
-.microphone,
-.period,
-.tab {
- -webkit-box-flex: 1.3 !important;
-}
-
-.symbol,
-.return {
- -webkit-box-flex: 1.5 !important;
-}
-
-.backspace {
- -webkit-box-flex: 1.7 !important;
-}
-
-.left-more {
- -webkit-box-flex: 1.4 !important;
-}
-
-.right-more {
- -webkit-box-flex: 1.6 !important;
-}
-
-.space {
- -webkit-box-flex: 4.8 !important;
-}
-
-.bar {
- -webkit-box-flex: 0.6 !important;
-}
-
-.backspace,
-.tab,
-.return,
-.shift,
-.left-more,
-.right-more,
-.symbol {
- font-size: 55%;
- font-weight: 200;
-}
-
-.microphone {
- background-image: url('images/microphone.svg');
-}
-
-.audio .microphone {
- background-image: url('images/microphone-green.svg');
-}
-
-.half-key-spacer {
- -webkit-box-flex: 0.5;
- margin-left: 4px;
-}
diff --git a/chromium/ui/keyboard/resources/webui_index.html b/chromium/ui/keyboard/resources/webui_index.html
deleted file mode 100644
index bdc81167fc3..00000000000
--- a/chromium/ui/keyboard/resources/webui_index.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<!--
- -- Copyright 2013 The Chromium Authors. All rights reserved.
- -- Use of this source code is governed by a BSD-style license that can be
- -- found in the LICENSE file.
- -->
-
-<!--
- -- To avoid unintentionally break webui keyboard when changing extension
- -- keyboard, creates this file and uses it as index.html for webui keyboard.
- -- TODO(bshe): remove this file when dynamic layout loading is fixed
- -- (http://www.crbug.com/260278).
- -->
-
-<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
- <link rel="stylesheet" href="main.css">
- <script src="constants.js"></script>
- <script src="polymer_loader.js"></script>
- <script src="api_adapter.js"></script>
- <script src="voice_input.js"></script>
- <link rel="import" href="elements/kb-altkey.html">
- <link rel="import" href="elements/kb-altkey-container.html">
- <link rel="import" href="elements/kb-altkey-data.html">
- <link rel="import" href="elements/kb-altkey-set.html">
- <link rel="import" href="elements/kb-key-codes.html">
- <link rel="import" href="elements/kb-key-base.html">
- <link rel="import" href="elements/kb-key.html">
- <link rel="import" href="elements/kb-keyboard.html">
- <link rel="import" href="elements/kb-keyset.html">
- <link rel="import" href="elements/kb-row.html">
- <link rel="import" href="elements/kb-shift-key.html">
- <link id="numeric" rel="import" href="layouts/numeric.html">
- <link id="qwerty" rel="import" href="layouts/qwerty.html">
- <!--TODO(stevet): Import 'Open Sans' font. -->
- <script src="main.js"></script>
- <script src="layouts/latin-accents.js"></script>
- </head>
- <body>
- <kb-keyboard id="keyboard" touch-action="none" layout="qwerty">
- </kb-keyboard>
- </body>
-</html>
diff --git a/chromium/ui/message_center/DEPS b/chromium/ui/message_center/DEPS
index 97925033c9a..b20b0ae1fa9 100644
--- a/chromium/ui/message_center/DEPS
+++ b/chromium/ui/message_center/DEPS
@@ -2,8 +2,8 @@ include_rules = [
"+grit/ui_resources.h",
"+grit/ui_strings.h",
"+skia/ext",
- "+third_party/GTM", # For Mac utility classes.
"+third_party/skia",
+ "+ui/accessibility",
"+ui/aura",
"+ui/base",
"+ui/compositor",
diff --git a/chromium/ui/message_center/cocoa/notification_controller.h b/chromium/ui/message_center/cocoa/notification_controller.h
index 47f1e87b67d..61a5e2f0666 100644
--- a/chromium/ui/message_center/cocoa/notification_controller.h
+++ b/chromium/ui/message_center/cocoa/notification_controller.h
@@ -37,6 +37,9 @@ MESSAGE_CENTER_EXPORT
// The button that invokes |-close:|, in the upper-right corner.
base::scoped_nsobject<HoverImageButton> closeButton_;
+ // The small icon associated with the notification, on the bottom right.
+ base::scoped_nsobject<NSImageView> smallImage_;
+
// The large icon associated with the notification, on the left side.
base::scoped_nsobject<NSImageView> icon_;
@@ -84,6 +87,7 @@ MESSAGE_CENTER_EXPORT
@end
@interface MCNotificationController (TestingInterface)
+- (NSImageView*)smallImageView;
- (NSImageView*)iconView;
@end
diff --git a/chromium/ui/message_center/cocoa/notification_controller.mm b/chromium/ui/message_center/cocoa/notification_controller.mm
index 0a46050e7b2..d492d9becf4 100644
--- a/chromium/ui/message_center/cocoa/notification_controller.mm
+++ b/chromium/ui/message_center/cocoa/notification_controller.mm
@@ -4,6 +4,8 @@
#import "ui/message_center/cocoa/notification_controller.h"
+#include <algorithm>
+
#include "base/mac/foundation_util.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
@@ -49,16 +51,50 @@
[gfx::SkColorToCalibratedNSColor(message_center::kProgressBarSliceColor) set];
[path fill];
}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ double progressValue = 0.0;
+ if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ progressValue = [self doubleValue];
+ } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
+ progressValue = [self minValue];
+ } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) {
+ progressValue = [self maxValue];
+ } else {
+ return [super accessibilityAttributeValue:attribute];
+ }
+
+ return [NSString stringWithFormat:@"%lf", progressValue];
+}
@end
////////////////////////////////////////////////////////////////////////////////
+@interface MCNotificationButton : NSButton
+@end
+
+@implementation MCNotificationButton
+// drawRect: needs to fill the button with a background, otherwise we don't get
+// subpixel antialiasing.
+- (void)drawRect:(NSRect)dirtyRect {
+ NSColor* color = gfx::SkColorToCalibratedNSColor(
+ message_center::kNotificationBackgroundColor);
+ [color set];
+ NSRectFill(dirtyRect);
+ [super drawRect:dirtyRect];
+}
+@end
@interface MCNotificationButtonCell : NSButtonCell {
BOOL hovered_;
}
@end
+////////////////////////////////////////////////////////////////////////////////
@implementation MCNotificationButtonCell
+- (BOOL)isOpaque {
+ return YES;
+}
+
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
// Else mouseEntered: and mouseExited: won't be called and hovered_ won't be
// valid.
@@ -182,10 +218,24 @@
@interface AccessibilityIgnoredBox : NSBox
@end
+// Ignore this element, but expose its children to accessibility.
@implementation AccessibilityIgnoredBox
- (BOOL)accessibilityIsIgnored {
return YES;
}
+
+// Pretend this element has no children.
+// TODO(petewil): Until we have alt text available, we will hide the children of
+// the box also. Remove this override once alt text is set (by using
+// NSAccessibilityDescriptionAttribute).
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ // If we get a request for NSAccessibilityChildrenAttribute, return an empty
+ // array to pretend we have no children.
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
+ return @[];
+ else
+ return [super accessibilityAttributeValue:attribute];
+}
@end
////////////////////////////////////////////////////////////////////////////////
@@ -200,11 +250,14 @@
// Creates a box that shows a border when the icon is not big enough to fill the
// space.
-- (NSBox*)createImageBox;
+- (NSBox*)createImageBox:(const gfx::Image&)notificationImage;
// Initializes the closeButton_ ivar with the configured button.
- (void)configureCloseButtonInFrame:(NSRect)rootFrame;
+// Initializes the smallImage_ ivar with the appropriate frame.
+- (void)configureSmallImageInFrame:(NSRect)rootFrame;
+
// Initializes title_ in the given frame.
- (void)configureTitleInFrame:(NSRect)rootFrame;
@@ -226,10 +279,18 @@
// Returns the wrapped text that could fit within the content rect with not
// more than the given number of lines. The wrapped text would be painted using
// the given font. The Ellipsis could be added at the end of the last line if
-// it is too long.
-- (string16)wrapText:(const string16&)text
- forFont:(NSFont*)font
- maxNumberOfLines:(size_t)lines;
+// it is too long. Outputs the number of lines computed in the actualLines
+// parameter.
+- (base::string16)wrapText:(const base::string16&)text
+ forFont:(NSFont*)font
+ maxNumberOfLines:(size_t)lines
+ actualLines:(size_t*)actualLines;
+
+// Same as above without outputting the lines formatted.
+- (base::string16)wrapText:(const base::string16&)text
+ forFont:(NSFont*)font
+ maxNumberOfLines:(size_t)lines;
+
@end
////////////////////////////////////////////////////////////////////////////////
@@ -264,16 +325,21 @@
[self configureCloseButtonInFrame:rootFrame];
[rootView addSubview:closeButton_];
+ // Create the small image.
+ [rootView addSubview:[self createSmallImageInFrame:rootFrame]];
+
+ NSRect contentFrame = [self currentContentRect];
+
// Create the title.
- [self configureTitleInFrame:rootFrame];
+ [self configureTitleInFrame:contentFrame];
[rootView addSubview:title_];
// Create the message body.
- [self configureBodyInFrame:rootFrame];
+ [self configureBodyInFrame:contentFrame];
[rootView addSubview:message_];
// Create the context message body.
- [self configureContextMessageInFrame:rootFrame];
+ [self configureContextMessageInFrame:contentFrame];
[rootView addSubview:contextMessage_];
// Populate the data.
@@ -288,6 +354,8 @@
message_center::kNotificationPreferredImageWidth,
message_center::kNotificationIconSize);
+ [smallImage_ setImage:notification_->small_image().AsNSImage()];
+
// Update the icon.
[icon_ setImage:notification_->icon().AsNSImage()];
@@ -311,26 +379,44 @@
message_center::kTextTopPadding - messageBottomGap - contextMessageTopGap;
// Set the title and recalculate the frame.
+ size_t actualTitleLines = 0;
[title_ setString:base::SysUTF16ToNSString(
[self wrapText:notification_->title()
- forFont:[title_ font]
- maxNumberOfLines:message_center::kTitleLineLimit])];
+ forFont:[title_ font]
+ maxNumberOfLines:message_center::kMaxTitleLines
+ actualLines:&actualTitleLines])];
[title_ sizeToFit];
NSRect titleFrame = [title_ frame];
titleFrame.origin.y = NSMaxY(rootFrame) - titlePadding - NSHeight(titleFrame);
+ // The number of message lines depends on the number of context message lines
+ // and the lines within the title, and whether an image exists.
+ int messageLineLimit = message_center::kMessageExpandedLineLimit;
+ if (actualTitleLines > 1)
+ messageLineLimit -= (actualTitleLines - 1) * 2;
+ if (!notification_->image().IsEmpty()) {
+ messageLineLimit /= 2;
+ if (!notification_->context_message().empty())
+ messageLineLimit -= message_center::kContextMessageLineLimit;
+ }
+ if (messageLineLimit < 0)
+ messageLineLimit = 0;
+
// Set the message and recalculate the frame.
[message_ setString:base::SysUTF16ToNSString(
[self wrapText:notification_->message()
forFont:[message_ font]
- maxNumberOfLines:message_center::kMessageExpandedLineLimit])];
+ maxNumberOfLines:messageLineLimit])];
[message_ sizeToFit];
NSRect messageFrame = [message_ frame];
// If there are list items, then the message_ view should not be displayed.
const std::vector<message_center::NotificationItem>& items =
notification->items();
- if (items.size() > 0) {
+ // If there are list items, don't show the main message. Also if the message
+ // is empty, mark it as hidden and set 0 height, so it doesn't take up any
+ // space (size to fit leaves it 15 px tall.
+ if (items.size() > 0 || notification_->message().empty()) {
[message_ setHidden:YES];
messageFrame.origin.y = titleFrame.origin.y;
messageFrame.size.height = 0;
@@ -392,9 +478,9 @@
[[itemView textContainer] setWidthTracksTextView:NO];
// Construct the text from the title and message.
- string16 text =
+ base::string16 text =
items[i].title + base::UTF8ToUTF16(" ") + items[i].message;
- string16 ellidedText =
+ base::string16 ellidedText =
[self wrapText:text forFont:font maxNumberOfLines:1];
[itemView setString:base::SysUTF16ToNSString(ellidedText)];
@@ -478,8 +564,8 @@
NSRect buttonFrame = frame;
buttonFrame.origin = NSMakePoint(0, y);
buttonFrame.size.height = message_center::kButtonHeight;
- base::scoped_nsobject<NSButton> button(
- [[NSButton alloc] initWithFrame:buttonFrame]);
+ base::scoped_nsobject<MCNotificationButton> button(
+ [[MCNotificationButton alloc] initWithFrame:buttonFrame]);
base::scoped_nsobject<MCNotificationButtonCell> cell(
[[MCNotificationButtonCell alloc]
initTextCell:base::SysUTF16ToNSString(buttonInfo.title)]);
@@ -607,7 +693,7 @@
return imageBox.autorelease();
}
-- (NSBox*)createImageBox:(gfx::Image)notificationImage {
+- (NSBox*)createImageBox:(const gfx::Image&)notificationImage {
using message_center::kNotificationImageBorderSize;
using message_center::kNotificationPreferredImageWidth;
using message_center::kNotificationPreferredImageHeight;
@@ -624,8 +710,8 @@
// Images with non-preferred aspect ratios get a border on all sides.
gfx::Size idealSize = gfx::Size(
kNotificationPreferredImageWidth, kNotificationPreferredImageHeight);
- gfx::Size scaledSize = message_center::GetImageSizeForWidth(
- kNotificationPreferredImageWidth, notificationImage.Size());
+ gfx::Size scaledSize = message_center::GetImageSizeForContainerSize(
+ idealSize, notificationImage.Size());
if (scaledSize != idealSize) {
NSSize borderSize =
NSMakeSize(kNotificationImageBorderSize, kNotificationImageBorderSize);
@@ -643,11 +729,15 @@
}
- (void)configureCloseButtonInFrame:(NSRect)rootFrame {
- closeButton_.reset([[HoverImageButton alloc] initWithFrame:NSMakeRect(
- NSMaxX(rootFrame) - message_center::kControlButtonSize,
- NSMaxY(rootFrame) - message_center::kControlButtonSize,
- message_center::kControlButtonSize,
- message_center::kControlButtonSize)]);
+ // The close button is configured to be the same size as the small image.
+ int closeButtonOriginOffset =
+ message_center::kSmallImageSize + message_center::kSmallImagePadding;
+ NSRect closeButtonFrame =
+ NSMakeRect(NSMaxX(rootFrame) - closeButtonOriginOffset,
+ NSMaxY(rootFrame) - closeButtonOriginOffset,
+ message_center::kSmallImageSize,
+ message_center::kSmallImageSize);
+ closeButton_.reset([[HoverImageButton alloc] initWithFrame:closeButtonFrame]);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
[closeButton_ setDefaultImage:
rb.GetNativeImageNamed(IDR_NOTIFICATION_CLOSE).ToNSImage()];
@@ -670,20 +760,47 @@
forAttribute:NSAccessibilityTitleAttribute];
}
-- (void)configureTitleInFrame:(NSRect)rootFrame {
- NSRect frame = [self currentContentRect];
- frame.size.height = 0;
- title_.reset([self newLabelWithFrame:frame]);
+- (NSView*)createSmallImageInFrame:(NSRect)rootFrame {
+ int smallImageXOffset =
+ message_center::kSmallImagePadding + message_center::kSmallImageSize;
+ NSRect boxFrame =
+ NSMakeRect(NSMaxX(rootFrame) - smallImageXOffset,
+ NSMinY(rootFrame) + message_center::kSmallImagePadding,
+ message_center::kSmallImageSize,
+ message_center::kSmallImageSize);
+
+ // Put the smallImage inside another box which can hide it from accessibility
+ // until we have some alt text to go with it. Once we have alt text, remove
+ // the box, and set NSAccessibilityDescriptionAttribute with it.
+ base::scoped_nsobject<NSBox> imageBox(
+ [[AccessibilityIgnoredBox alloc] initWithFrame:boxFrame]);
+ [self configureCustomBox:imageBox];
+ [imageBox setAutoresizingMask:NSViewMinYMargin];
+
+ NSRect smallImageFrame =
+ NSMakeRect(0,0,
+ message_center::kSmallImageSize,
+ message_center::kSmallImageSize);
+
+ smallImage_.reset([[NSImageView alloc] initWithFrame:smallImageFrame]);
+ [smallImage_ setImageScaling:NSImageScaleProportionallyUpOrDown];
+ [imageBox setContentView:smallImage_];
+
+ return imageBox.autorelease();
+}
+
+- (void)configureTitleInFrame:(NSRect)contentFrame {
+ contentFrame.size.height = 0;
+ title_.reset([self newLabelWithFrame:contentFrame]);
[title_ setAutoresizingMask:NSViewMinYMargin];
[title_ setTextColor:gfx::SkColorToCalibratedNSColor(
message_center::kRegularTextColor)];
[title_ setFont:[NSFont messageFontOfSize:message_center::kTitleFontSize]];
}
-- (void)configureBodyInFrame:(NSRect)rootFrame {
- NSRect frame = [self currentContentRect];
- frame.size.height = 0;
- message_.reset([self newLabelWithFrame:frame]);
+- (void)configureBodyInFrame:(NSRect)contentFrame {
+ contentFrame.size.height = 0;
+ message_.reset([self newLabelWithFrame:contentFrame]);
[message_ setAutoresizingMask:NSViewMinYMargin];
[message_ setTextColor:gfx::SkColorToCalibratedNSColor(
message_center::kRegularTextColor)];
@@ -691,10 +808,9 @@
[NSFont messageFontOfSize:message_center::kMessageFontSize]];
}
-- (void)configureContextMessageInFrame:(NSRect)rootFrame {
- NSRect frame = [self currentContentRect];
- frame.size.height = 0;
- contextMessage_.reset([self newLabelWithFrame:frame]);
+- (void)configureContextMessageInFrame:(NSRect)contentFrame {
+ contentFrame.size.height = 0;
+ contextMessage_.reset([self newLabelWithFrame:contentFrame]);
[contextMessage_ setAutoresizingMask:NSViewMinYMargin];
[contextMessage_ setTextColor:gfx::SkColorToCalibratedNSColor(
message_center::kDimTextColor)];
@@ -704,7 +820,13 @@
- (NSTextView*)newLabelWithFrame:(NSRect)frame {
NSTextView* label = [[NSTextView alloc] initWithFrame:frame];
- [label setDrawsBackground:NO];
+
+ // The labels MUST draw their background so that subpixel antialiasing can
+ // happen on the text.
+ [label setDrawsBackground:YES];
+ [label setBackgroundColor:gfx::SkColorToCalibratedNSColor(
+ message_center::kNotificationBackgroundColor)];
+
[label setEditable:NO];
[label setSelectable:NO];
[label setTextContainerInset:NSMakeSize(0.0f, 0.0f)];
@@ -715,43 +837,63 @@
- (NSRect)currentContentRect {
DCHECK(icon_);
DCHECK(closeButton_);
+ DCHECK(smallImage_);
NSRect iconFrame, contentFrame;
NSDivideRect([[self view] bounds], &iconFrame, &contentFrame,
NSWidth([icon_ frame]) + message_center::kIconToTextPadding,
NSMinXEdge);
- contentFrame.size.width -= NSWidth([closeButton_ frame]);
+ // The content area is between the icon on the left and the control area
+ // on the right.
+ int controlAreaWidth =
+ std::max(NSWidth([closeButton_ frame]), NSWidth([smallImage_ frame]));
+ contentFrame.size.width -=
+ 2 * message_center::kSmallImagePadding + controlAreaWidth;
return contentFrame;
}
-- (string16)wrapText:(const string16&)text
- forFont:(NSFont*)nsfont
- maxNumberOfLines:(size_t)lines {
- if (text.empty())
- return text;
+- (base::string16)wrapText:(const base::string16&)text
+ forFont:(NSFont*)nsfont
+ maxNumberOfLines:(size_t)lines
+ actualLines:(size_t*)actualLines {
+ *actualLines = 0;
+ if (text.empty() || lines == 0)
+ return base::string16();
gfx::FontList font_list((gfx::Font(nsfont)));
int width = NSWidth([self currentContentRect]);
int height = (lines + 1) * font_list.GetHeight();
- std::vector<string16> wrapped;
+ std::vector<base::string16> wrapped;
gfx::ElideRectangleText(text, font_list, width, height,
gfx::WRAP_LONG_WORDS, &wrapped);
// This could be possible when the input text contains only spaces.
if (wrapped.empty())
- return string16();
+ return base::string16();
if (wrapped.size() > lines) {
// Add an ellipsis to the last line. If this ellipsis makes the last line
// too wide, that line will be further elided by the gfx::ElideText below.
- string16 last = wrapped[lines - 1] + UTF8ToUTF16(gfx::kEllipsis);
+ base::string16 last =
+ wrapped[lines - 1] + base::UTF8ToUTF16(gfx::kEllipsis);
if (gfx::GetStringWidth(last, font_list) > width)
- last = gfx::ElideText(last, font_list, width, gfx::ELIDE_AT_END);
+ last = gfx::ElideText(last, font_list, width, gfx::ELIDE_TAIL);
wrapped.resize(lines - 1);
wrapped.push_back(last);
}
+ *actualLines = wrapped.size();
return lines == 1 ? wrapped[0] : JoinString(wrapped, '\n');
}
+- (base::string16)wrapText:(const base::string16&)text
+ forFont:(NSFont*)nsfont
+ maxNumberOfLines:(size_t)lines {
+ size_t unused;
+ return [self wrapText:text
+ forFont:nsfont
+ maxNumberOfLines:lines
+ actualLines:&unused];
+}
+
@end
diff --git a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm b/chromium/ui/message_center/cocoa/notification_controller_unittest.mm
index 7b4d23551fb..91d1b1b694a 100644
--- a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm
+++ b/chromium/ui/message_center/cocoa/notification_controller_unittest.mm
@@ -9,13 +9,17 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#import "ui/base/cocoa/hover_image_button.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#include "ui/message_center/fake_message_center.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_types.h"
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+
namespace {
class MockMessageCenter : public message_center::FakeMessageCenter {
@@ -62,6 +66,10 @@ class MockMessageCenter : public message_center::FakeMessageCenter {
return closeButton_.get();
}
+- (NSImageView*)smallImageView {
+ return smallImage_.get();
+}
+
- (NSButton*)secondButton {
// The buttons are in Cocoa-y-order, so the 2nd button is first.
NSView* view = [[bottomView_ subviews] objectAtIndex:0];
@@ -115,11 +123,13 @@ TEST_F(NotificationControllerTest, BasicLayout) {
ASCIIToUTF16("Added to circles"),
ASCIIToUTF16("Jonathan and 5 others"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
- notification->set_icon(gfx::Image([TestIcon() retain]));
+ gfx::Image testIcon([TestIcon() retain]);
+ notification->set_icon(testIcon);
+ notification->set_small_image(testIcon);
base::scoped_nsobject<MCNotificationController> controller(
[[MCNotificationController alloc] initWithNotification:notification.get()
@@ -127,6 +137,7 @@ TEST_F(NotificationControllerTest, BasicLayout) {
[controller view];
EXPECT_EQ(TestIcon(), [[controller iconView] image]);
+ EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
EXPECT_EQ(base::SysNSStringToUTF16([[controller titleView] string]),
notification->title());
EXPECT_EQ(base::SysNSStringToUTF16([[controller messageView] string]),
@@ -145,7 +156,7 @@ TEST_F(NotificationControllerTest, OverflowText) {
"notification. Are you really going to read this "
"entire thing?"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -163,10 +174,10 @@ TEST_F(NotificationControllerTest, Close) {
new message_center::Notification(
message_center::NOTIFICATION_TYPE_SIMPLE,
"an_id",
- string16(),
- string16(),
+ base::string16(),
+ base::string16(),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -193,7 +204,7 @@ TEST_F(NotificationControllerTest, Update) {
ASCIIToUTF16("This message isn't too long and should fit in the"
"default bounds."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -206,11 +217,15 @@ TEST_F(NotificationControllerTest, Update) {
EXPECT_EQ(NSHeight([[controller view] frame]),
message_center::kNotificationIconSize);
EXPECT_FALSE([[controller iconView] image]);
+ EXPECT_FALSE([[controller smallImageView] image]);
// Update the icon.
- notification->set_icon(gfx::Image([TestIcon() retain]));
+ gfx::Image testIcon([TestIcon() retain]);
+ notification->set_icon(testIcon);
+ notification->set_small_image(testIcon);
[controller updateNotification:notification.get()];
EXPECT_EQ(TestIcon(), [[controller iconView] image]);
+ EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
EXPECT_EQ(NSHeight([[controller view] frame]),
message_center::kNotificationIconSize);
}
@@ -226,10 +241,10 @@ TEST_F(NotificationControllerTest, Buttons) {
new message_center::Notification(
message_center::NOTIFICATION_TYPE_BASE_FORMAT,
"an_id",
- string16(),
- string16(),
+ base::string16(),
+ base::string16(),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
optional,
NULL));
@@ -251,10 +266,10 @@ TEST_F(NotificationControllerTest, Image) {
new message_center::Notification(
message_center::NOTIFICATION_TYPE_BASE_FORMAT,
"an_id",
- string16(),
- string16(),
+ base::string16(),
+ base::string16(),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -297,7 +312,7 @@ TEST_F(NotificationControllerTest, List) {
UTF8ToUTF16("Notification Title"),
UTF8ToUTF16("Notification Message - should be hidden"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
optional,
NULL));
@@ -317,4 +332,110 @@ TEST_F(NotificationControllerTest, List) {
NSMinY([[controller titleView] frame]));
}
+TEST_F(NotificationControllerTest, NoMessage) {
+ message_center::RichNotificationData optional;
+ optional.context_message = UTF8ToUTF16("Context Message");
+
+ scoped_ptr<message_center::Notification> notification(
+ new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_BASE_FORMAT,
+ "an_id",
+ UTF8ToUTF16("Notification Title"),
+ UTF8ToUTF16(""),
+ gfx::Image(),
+ base::string16(),
+ DummyNotifierId(),
+ optional,
+ NULL));
+
+ MockMessageCenter message_center;
+ base::scoped_nsobject<MCNotificationController> controller(
+ [[MCNotificationController alloc] initWithNotification:notification.get()
+ messageCenter:&message_center]);
+ [controller view];
+
+ EXPECT_FALSE([[controller titleView] isHidden]);
+ EXPECT_TRUE([[controller messageView] isHidden]);
+ EXPECT_FALSE([[controller contextMessageView] isHidden]);
+}
+
+TEST_F(NotificationControllerTest, MessageSize) {
+ message_center::RichNotificationData data;
+ std::string id("id");
+ NotifierId notifier_id(NotifierId::APPLICATION, "notifier");
+ scoped_ptr<Notification> notification(new Notification(
+ NOTIFICATION_TYPE_BASE_FORMAT,
+ id,
+ base::UTF8ToUTF16(""),
+ ASCIIToUTF16("And\neven\nthe\nmessage is long.\nThis sure is wordy"),
+ gfx::Image(),
+ base::string16() /* display_source */,
+ notifier_id,
+ data,
+ NULL /* delegate */));
+
+ base::scoped_nsobject<MCNotificationController> controller(
+ [[MCNotificationController alloc] initWithNotification:notification.get()
+ messageCenter:NULL]);
+
+ // Set up the default layout.
+ [controller view];
+
+ auto compute_message_lines = ^{
+ NSString* string = [[[controller messageView] textStorage] string];
+ unsigned numberOfLines, index, stringLength = [string length];
+ for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
+ index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
+
+ return numberOfLines;
+ };
+
+ // Message and no title: 5 lines.
+ EXPECT_EQ(5u, compute_message_lines());
+
+ // Message and one line title: 5 lines.
+ notification->set_title(ASCIIToUTF16("one line"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(5u, compute_message_lines());
+
+ // Message and two line title: 3 lines.
+ notification->set_title(ASCIIToUTF16("two\nlines"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(3u, compute_message_lines());
+
+ // Message, image and no title: 2 lines.
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bitmap.allocPixels();
+ bitmap.eraseColor(SK_ColorGREEN);
+ notification->set_title(ASCIIToUTF16(""));
+ notification->set_image(gfx::Image::CreateFrom1xBitmap(bitmap));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(2u, compute_message_lines());
+
+ // Message, image and one line title: 2 lines.
+ notification->set_title(ASCIIToUTF16("one line"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(2u, compute_message_lines());
+
+ // Message, image and two line title: 1 lines.
+ notification->set_title(ASCIIToUTF16("two\nlines"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(1u, compute_message_lines());
+
+ // Same as above, but context message takes away from message lines.
+ notification->set_context_message(base::UTF8ToUTF16("foo"));
+ notification->set_title(ASCIIToUTF16(""));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(1u, compute_message_lines());
+
+ notification->set_title(ASCIIToUTF16("one line"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(1u, compute_message_lines());
+
+ notification->set_title(ASCIIToUTF16("two\nlines"));
+ [controller updateNotification:notification.get()];
+ EXPECT_EQ(0u, compute_message_lines());
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/cocoa/opaque_views.h b/chromium/ui/message_center/cocoa/opaque_views.h
new file mode 100644
index 00000000000..1a2f3b02354
--- /dev/null
+++ b/chromium/ui/message_center/cocoa/opaque_views.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
+#define UI_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+
+// MCDropDown is the same as an NSPopupButton except that it fills its
+// background with a settable color.
+@interface MCDropDown : NSPopUpButton {
+ @private
+ base::scoped_nsobject<NSColor> backgroundColor_;
+}
+
+// Gets and sets the bubble's background color.
+- (NSColor*)backgroundColor;
+- (void)setBackgroundColor:(NSColor*)backgroundColor;
+@end
+
+// MCTextField fills its background with an opaque color. It also configures
+// the view to have a plan appearance, without bezel, border, editing, etc.
+@interface MCTextField : NSTextField {
+ @private
+ base::scoped_nsobject<NSColor> backgroundColor_;
+}
+
+// Use this method to create the text field. The color is required so it
+// can correctly subpixel antialias.
+- (id)initWithFrame:(NSRect)frameRect backgroundColor:(NSColor*)color;
+@end
+
+#endif // UI_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
diff --git a/chromium/ui/message_center/cocoa/opaque_views.mm b/chromium/ui/message_center/cocoa/opaque_views.mm
new file mode 100644
index 00000000000..b6e054f519a
--- /dev/null
+++ b/chromium/ui/message_center/cocoa/opaque_views.mm
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/message_center/cocoa/opaque_views.h"
+
+@implementation MCDropDown
+// The view must be opaque to render subpixel antialiasing.
+- (BOOL)isOpaque {
+ return YES;
+}
+
+// The view must also fill its background to render subpixel antialiasing.
+- (void)drawRect:(NSRect)dirtyRect {
+ [backgroundColor_ set];
+ NSRectFill(dirtyRect);
+ [super drawRect:dirtyRect];
+}
+
+- (NSColor*)backgroundColor {
+ return backgroundColor_;
+}
+
+- (void)setBackgroundColor:(NSColor*)backgroundColor {
+ backgroundColor_.reset([backgroundColor retain]);
+}
+@end
+
+@implementation MCTextField
+- (id)initWithFrame:(NSRect)frameRect backgroundColor:(NSColor*)color {
+ self = [self initWithFrame:frameRect];
+ if (self) {
+ [self setBackgroundColor:color];
+ backgroundColor_.reset([color retain]);
+ }
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect {
+ self = [super initWithFrame:frameRect];
+ if (self) {
+ [self setAutoresizingMask:NSViewMinYMargin];
+ [self setBezeled:NO];
+ [self setBordered:NO];
+ [self setEditable:NO];
+ [self setSelectable:NO];
+ [self setDrawsBackground:YES];
+ }
+ return self;
+}
+
+// The view must be opaque to render subpixel antialiasing.
+- (BOOL)isOpaque {
+ return YES;
+}
+
+// The view must also fill its background to render subpixel antialiasing.
+- (void)drawRect:(NSRect)dirtyRect {
+ [backgroundColor_ set];
+ NSRectFill(dirtyRect);
+ [super drawRect:dirtyRect];
+}
+@end
diff --git a/chromium/ui/message_center/cocoa/popup_collection.mm b/chromium/ui/message_center/cocoa/popup_collection.mm
index fb220199a34..adc4f6216d6 100644
--- a/chromium/ui/message_center/cocoa/popup_collection.mm
+++ b/chromium/ui/message_center/cocoa/popup_collection.mm
@@ -191,7 +191,8 @@ class PopupCollectionObserver : public message_center::MessageCenterObserver {
bounds.origin.y = y;
[popup showWithAnimation:bounds];
[popups_ addObject:popup];
- messageCenter_->DisplayedNotification(notification->id());
+ messageCenter_->DisplayedNotification(
+ notification->id(), message_center::DISPLAY_SOURCE_POPUP);
return YES;
}
@@ -201,9 +202,11 @@ class PopupCollectionObserver : public message_center::MessageCenterObserver {
}
- (void)updateNotification:(const std::string&)notificationID {
- // The notification may not be on screen.
- if ([self indexOfPopupWithNotificationID:notificationID] == NSNotFound)
+ // The notification may not be on screen. Create it if needed.
+ if ([self indexOfPopupWithNotificationID:notificationID] == NSNotFound) {
+ [self layoutNewNotifications];
return;
+ }
// Don't bother with the update if the notification is going to be removed.
if (pendingRemoveNotificationIDs_.find(notificationID) !=
diff --git a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm b/chromium/ui/message_center/cocoa/popup_collection_unittest.mm
index 445673d1a5f..d85b158945f 100644
--- a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm
+++ b/chromium/ui/message_center/cocoa/popup_collection_unittest.mm
@@ -10,19 +10,20 @@
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#import "ui/message_center/cocoa/notification_controller.h"
#import "ui/message_center/cocoa/popup_controller.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/notification.h"
+using base::ASCIIToUTF16;
+
namespace message_center {
class PopupCollectionTest : public ui::CocoaTest {
public:
- PopupCollectionTest()
- : message_loop_(base::MessageLoop::TYPE_UI) {
+ PopupCollectionTest() {
message_center::MessageCenter::Initialize();
center_ = message_center::MessageCenter::Get();
collection_.reset(
@@ -56,7 +57,7 @@ class PopupCollectionTest : public ui::CocoaTest {
ASCIIToUTF16("This is the first notification to"
" be displayed"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -68,7 +69,7 @@ class PopupCollectionTest : public ui::CocoaTest {
ASCIIToUTF16("Two"),
ASCIIToUTF16("This is the second notification."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -85,7 +86,7 @@ class PopupCollectionTest : public ui::CocoaTest {
"set the screen size too small or "
"if the notification is way too big"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -109,7 +110,7 @@ class PopupCollectionTest : public ui::CocoaTest {
nested_run_loop_.reset();
}
- base::MessageLoop message_loop_;
+ base::MessageLoopForUI message_loop_;
scoped_ptr<base::RunLoop> nested_run_loop_;
message_center::MessageCenter* center_;
base::scoped_nsobject<MCPopupCollection> collection_;
@@ -140,7 +141,7 @@ TEST_F(PopupCollectionTest, AttemptFourOneOffscreen) {
ASCIIToUTF16("Four"),
ASCIIToUTF16("This is the fourth notification."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -189,7 +190,7 @@ TEST_F(PopupCollectionTest, LayoutSpacing) {
ASCIIToUTF16("Four"),
ASCIIToUTF16("This is the fourth notification."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
optional,
NULL));
@@ -227,7 +228,7 @@ TEST_F(PopupCollectionTest, TinyScreen) {
ASCIIToUTF16("This is the first notification to"
" be displayed"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -249,7 +250,7 @@ TEST_F(PopupCollectionTest, TinyScreen) {
"very very very very very very very "
"long notification."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -293,7 +294,7 @@ TEST_F(PopupCollectionTest, UpdateIconAndBody) {
"updated to have a significantly "
"longer body"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -312,6 +313,43 @@ TEST_F(PopupCollectionTest, UpdateIconAndBody) {
EXPECT_EQ("3", [[popups objectAtIndex:2] notificationID]);
}
+TEST_F(PopupCollectionTest, UpdatePriority) {
+ scoped_ptr<message_center::Notification> notification;
+ notification.reset(new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_SIMPLE,
+ "1",
+ ASCIIToUTF16("One"),
+ ASCIIToUTF16("This notification should not yet toast."),
+ gfx::Image(),
+ base::string16(),
+ DummyNotifierId(),
+ message_center::RichNotificationData(),
+ NULL));
+ notification->set_priority(-1);
+
+ center_->AddNotification(notification.Pass());
+ WaitForAnimationEnded();
+ NSArray* popups = [collection_ popups];
+ EXPECT_EQ(0u, [popups count]);
+
+ // Raise priority -1 to 1. Notification should display.
+ notification.reset(new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_SIMPLE,
+ "1",
+ ASCIIToUTF16("One"),
+ ASCIIToUTF16("This notification should now toast"),
+ gfx::Image(),
+ base::string16(),
+ DummyNotifierId(),
+ message_center::RichNotificationData(),
+ NULL));
+ notification->set_priority(1);
+
+ center_->UpdateNotification("1", notification.Pass());
+ WaitForAnimationEnded();
+ EXPECT_EQ(1u, [popups count]);
+}
+
TEST_F(PopupCollectionTest, CloseCollectionBeforeNewPopupAnimationEnds) {
// Add a notification and don't wait for the animation to finish.
scoped_ptr<message_center::Notification> notification;
@@ -322,7 +360,7 @@ TEST_F(PopupCollectionTest, CloseCollectionBeforeNewPopupAnimationEnds) {
ASCIIToUTF16("This is the first notification to"
" be displayed"),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -355,7 +393,7 @@ TEST_F(PopupCollectionTest, CloseCollectionBeforeUpdatePopupAnimationEnds) {
ASCIIToUTF16("One"),
ASCIIToUTF16("New message."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
diff --git a/chromium/ui/message_center/cocoa/popup_controller.mm b/chromium/ui/message_center/cocoa/popup_controller.mm
index 30badc79bfe..0f22937b86d 100644
--- a/chromium/ui/message_center/cocoa/popup_controller.mm
+++ b/chromium/ui/message_center/cocoa/popup_controller.mm
@@ -13,13 +13,6 @@
#import "ui/message_center/cocoa/popup_collection.h"
#include "ui/message_center/message_center.h"
-#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-enum {
- NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
-};
-#endif // MAC_OS_X_VERSION_10_7
-
////////////////////////////////////////////////////////////////////////////////
@interface MCPopupController (Private)
diff --git a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm b/chromium/ui/message_center/cocoa/popup_controller_unittest.mm
index e443e04cc29..73e142ba714 100644
--- a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm
+++ b/chromium/ui/message_center/cocoa/popup_controller_unittest.mm
@@ -8,9 +8,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#include "ui/message_center/notification.h"
+using base::ASCIIToUTF16;
+
namespace message_center {
class PopupControllerTest : public ui::CocoaTest {
@@ -24,7 +26,7 @@ TEST_F(PopupControllerTest, Creation) {
ASCIIToUTF16("Added to circles"),
ASCIIToUTF16("Jonathan and 5 others"),
gfx::Image(),
- string16(),
+ base::string16(),
message_center::NotifierId(),
message_center::RichNotificationData(),
NULL));
diff --git a/chromium/ui/message_center/cocoa/settings_controller.h b/chromium/ui/message_center/cocoa/settings_controller.h
index 522e7e7f607..2efa944b630 100644
--- a/chromium/ui/message_center/cocoa/settings_controller.h
+++ b/chromium/ui/message_center/cocoa/settings_controller.h
@@ -9,6 +9,7 @@
#import "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
+#import "ui/message_center/cocoa/opaque_views.h"
#import "ui/message_center/cocoa/settings_entry_view.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/notifier_settings.h"
@@ -29,6 +30,8 @@ class NotifierSettingsObserverMac : public NotifierSettingsObserver {
virtual void UpdateIconImage(const NotifierId& notifier_id,
const gfx::Image& icon) OVERRIDE;
virtual void NotifierGroupChanged() OVERRIDE;
+ virtual void NotifierEnabledChanged(const NotifierId& notifier_id,
+ bool enabled) OVERRIDE;
private:
MCSettingsController* settings_controller_; // weak, owns this
@@ -53,7 +56,7 @@ MESSAGE_CENTER_EXPORT
base::scoped_nsobject<NSTextField> detailsText_;
// The profile switcher.
- base::scoped_nsobject<NSPopUpButton> groupDropDownButton_;
+ base::scoped_nsobject<MCDropDown> groupDropDownButton_;
// Container for all the checkboxes.
base::scoped_nsobject<NSScrollView> scrollView_;
diff --git a/chromium/ui/message_center/cocoa/settings_controller.mm b/chromium/ui/message_center/cocoa/settings_controller.mm
index 82f2c46188f..a3af1fc79f3 100644
--- a/chromium/ui/message_center/cocoa/settings_controller.mm
+++ b/chromium/ui/message_center/cocoa/settings_controller.mm
@@ -13,6 +13,7 @@
#include "grit/ui_strings.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/base/l10n/l10n_util.h"
+#import "ui/message_center/cocoa/opaque_views.h"
#import "ui/message_center/cocoa/settings_entry_view.h"
#import "ui/message_center/cocoa/tray_view_controller.h"
#include "ui/message_center/message_center_style.h"
@@ -81,6 +82,9 @@ void NotifierSettingsObserverMac::NotifierGroupChanged() {
[settings_controller_ updateView];
}
+void NotifierSettingsObserverMac::NotifierEnabledChanged(
+ const NotifierId& notifier_id, bool enabled) {}
+
} // namespace message_center
@implementation MCSettingsController
@@ -104,12 +108,11 @@ void NotifierSettingsObserverMac::NotifierGroupChanged() {
}
- (NSTextField*)newLabelWithFrame:(NSRect)frame {
- NSTextField* label = [[NSTextField alloc] initWithFrame:frame];
- [label setDrawsBackground:NO];
- [label setBezeled:NO];
- [label setEditable:NO];
- [label setSelectable:NO];
- [label setAutoresizingMask:NSViewMinYMargin];
+ NSColor* color = gfx::SkColorToCalibratedNSColor(
+ message_center::kMessageCenterBackgroundColor);
+ MCTextField* label =
+ [[MCTextField alloc] initWithFrame:frame backgroundColor:color];
+
return label;
}
@@ -141,7 +144,6 @@ void NotifierSettingsObserverMac::NotifierGroupChanged() {
NSWidth(fullFrame),
NSHeight(fullFrame));
settingsText_.reset([self newLabelWithFrame:headerFrame]);
- [settingsText_ setAutoresizingMask:NSViewMinYMargin];
[settingsText_ setTextColor:
gfx::SkColorToCalibratedNSColor(message_center::kRegularTextColor)];
[settingsText_
@@ -161,7 +163,6 @@ void NotifierSettingsObserverMac::NotifierGroupChanged() {
NSWidth(fullFrame),
NSHeight(fullFrame));
detailsText_.reset([self newLabelWithFrame:subheaderFrame]);
- [detailsText_ setAutoresizingMask:NSViewMinYMargin];
[detailsText_ setTextColor:
gfx::SkColorToCalibratedNSColor(message_center::kDimTextColor)];
[detailsText_
@@ -186,17 +187,20 @@ void NotifierSettingsObserverMac::NotifierGroupChanged() {
NSWidth(fullFrame),
NSHeight(fullFrame));
groupDropDownButton_.reset(
- [[NSPopUpButton alloc] initWithFrame:dropDownButtonFrame
- pullsDown:YES]);
+ [[MCDropDown alloc] initWithFrame:dropDownButtonFrame pullsDown:YES]);
+ [groupDropDownButton_
+ setBackgroundColor:gfx::SkColorToCalibratedNSColor(
+ message_center::kMessageCenterBackgroundColor)];
[groupDropDownButton_ setAction:@selector(notifierGroupSelectionChanged:)];
[groupDropDownButton_ setTarget:self];
// Add a dummy item for pull-down.
[groupDropDownButton_ addItemWithTitle:@""];
- string16 title;
+ base::string16 title;
for (size_t i = 0; i < groupCount; ++i) {
const message_center::NotifierGroup& group =
provider_->GetNotifierGroupAt(i);
- string16 item = group.login_info.empty() ? group.name : group.login_info;
+ base::string16 item =
+ group.login_info.empty() ? group.name : group.login_info;
[groupDropDownButton_ addItemWithTitle:base::SysUTF16ToNSString(item)];
if (provider_->IsNotifierGroupActiveAt(i)) {
title = item;
diff --git a/chromium/ui/message_center/cocoa/settings_controller_unittest.mm b/chromium/ui/message_center/cocoa/settings_controller_unittest.mm
index 74f9f0712cf..c686fcfe6b2 100644
--- a/chromium/ui/message_center/cocoa/settings_controller_unittest.mm
+++ b/chromium/ui/message_center/cocoa/settings_controller_unittest.mm
@@ -5,7 +5,7 @@
#import "ui/message_center/cocoa/settings_controller.h"
#include "base/strings/utf_string_conversions.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#include "ui/message_center/fake_notifier_settings_provider.h"
@implementation MCSettingsController (TestingInterface)
diff --git a/chromium/ui/message_center/cocoa/settings_entry_view.mm b/chromium/ui/message_center/cocoa/settings_entry_view.mm
index 0607247f874..ab73d98c74e 100644
--- a/chromium/ui/message_center/cocoa/settings_entry_view.mm
+++ b/chromium/ui/message_center/cocoa/settings_entry_view.mm
@@ -56,6 +56,23 @@ const int kCorrectedIconTextPadding =
const int kCorrectedEntryRightPadding =
kInternalHorizontalSpacing - kIntrinsicLearnMorePadding;
+////////////////////////////////////////////////////////////////////////////////
+
+@interface MCSettingsButton : NSButton
+@end
+
+@implementation MCSettingsButton
+// drawRect: needs to fill the button with a background, otherwise we don't get
+// subpixel antialiasing.
+- (void)drawRect:(NSRect)dirtyRect {
+ NSColor* color = gfx::SkColorToCalibratedNSColor(
+ message_center::kMessageCenterBackgroundColor);
+ [color set];
+ NSRectFill(dirtyRect);
+ [super drawRect:dirtyRect];
+}
+@end
+
@interface MCSettingsButtonCell : NSButtonCell {
// A checkbox's regular image is the checkmark image. This additional image
// is used for the favicon or app icon shown next to the checkmark.
@@ -65,6 +82,10 @@ const int kCorrectedEntryRightPadding =
@end
@implementation MCSettingsButtonCell
+- (BOOL)isOpaque {
+ return YES;
+}
+
- (void)setExtraImage:(NSImage*)extraImage {
extraImage_.reset([extraImage retain]);
}
@@ -133,7 +154,6 @@ const int kCorrectedEntryRightPadding =
@end
@implementation MCSettingsEntryView
-
- (id)initWithController:(MCSettingsController*)controller
notifier:(message_center::Notifier*)notifier
frame:(NSRect)frame
@@ -218,7 +238,7 @@ const int kCorrectedEntryRightPadding =
}
if (!checkbox_.get()) {
- checkbox_.reset([[NSButton alloc] initWithFrame:checkboxFrame]);
+ checkbox_.reset([[MCSettingsButton alloc] initWithFrame:checkboxFrame]);
[self addSubview:checkbox_];
} else {
[checkbox_ setFrame:checkboxFrame];
diff --git a/chromium/ui/message_center/cocoa/status_item_view.h b/chromium/ui/message_center/cocoa/status_item_view.h
index 4262f3139ce..5d2bd63f1c4 100644
--- a/chromium/ui/message_center/cocoa/status_item_view.h
+++ b/chromium/ui/message_center/cocoa/status_item_view.h
@@ -14,14 +14,14 @@
namespace message_center {
// Callback block for when the status item is clicked.
-typedef void(^StatusItemClickedCallack)();
+typedef void(^StatusItemClickedCallback)();
} // namespace message_center
// This view is meant to be used with a NSStatusItem. It will fire a callback
// when it is clicked. It draws a small icon and the unread count, if greater
// than zero, to the icon's right. It can also paint the highlight background
-// pattern outisde of a mouse event sequence, for when an attached window is
+// pattern outside of a mouse event sequence, for when an attached window is
// open.
MESSAGE_CENTER_EXPORT
@interface MCStatusItemView : NSView {
@@ -30,7 +30,7 @@ MESSAGE_CENTER_EXPORT
base::scoped_nsobject<NSStatusItem> statusItem_;
// Callback issued when the status item is clicked.
- base::mac::ScopedBlock<message_center::StatusItemClickedCallack> callback_;
+ base::mac::ScopedBlock<message_center::StatusItemClickedCallback> callback_;
// The unread count number to be drawn next to the icon.
size_t unreadCount_;
@@ -46,7 +46,7 @@ MESSAGE_CENTER_EXPORT
BOOL inMouseEventSequence_;
}
-@property(copy, nonatomic) message_center::StatusItemClickedCallack callback;
+@property(copy, nonatomic) message_center::StatusItemClickedCallback callback;
@property(nonatomic) BOOL highlight;
// Designated initializer. Creates a new NSStatusItem in the system menubar.
diff --git a/chromium/ui/message_center/cocoa/status_item_view.mm b/chromium/ui/message_center/cocoa/status_item_view.mm
index 7a8f4c2984f..cf93bddd654 100644
--- a/chromium/ui/message_center/cocoa/status_item_view.mm
+++ b/chromium/ui/message_center/cocoa/status_item_view.mm
@@ -50,12 +50,12 @@ const CGFloat kMargin = 5;
return unreadCount_;
}
-- (message_center::StatusItemClickedCallack)callback {
+- (message_center::StatusItemClickedCallback)callback {
return callback_.get();
}
-- (void)setCallback:(message_center::StatusItemClickedCallack)callback {
- callback_.reset(Block_copy(callback));
+- (void)setCallback:(message_center::StatusItemClickedCallback)callback {
+ callback_.reset(callback, base::scoped_policy::RETAIN);
}
- (void)setUnreadCount:(size_t)unreadCount withQuietMode:(BOOL)quietMode {
diff --git a/chromium/ui/message_center/cocoa/status_item_view_unittest.mm b/chromium/ui/message_center/cocoa/status_item_view_unittest.mm
index 424d20f3514..f673a1182f2 100644
--- a/chromium/ui/message_center/cocoa/status_item_view_unittest.mm
+++ b/chromium/ui/message_center/cocoa/status_item_view_unittest.mm
@@ -5,7 +5,7 @@
#import "ui/message_center/cocoa/status_item_view.h"
#include "base/mac/scoped_nsobject.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
class StatusItemViewTest : public ui::CocoaTest {
public:
diff --git a/chromium/ui/message_center/cocoa/tray_controller_unittest.mm b/chromium/ui/message_center/cocoa/tray_controller_unittest.mm
index 516cf8fc5c5..285e8b67f75 100644
--- a/chromium/ui/message_center/cocoa/tray_controller_unittest.mm
+++ b/chromium/ui/message_center/cocoa/tray_controller_unittest.mm
@@ -6,7 +6,7 @@
#include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_tray.h"
diff --git a/chromium/ui/message_center/cocoa/tray_view_controller.h b/chromium/ui/message_center/cocoa/tray_view_controller.h
index d5f9f1f8876..5d5b3af83e9 100644
--- a/chromium/ui/message_center/cocoa/tray_view_controller.h
+++ b/chromium/ui/message_center/cocoa/tray_view_controller.h
@@ -46,6 +46,12 @@ MESSAGE_CENTER_EXPORT
// The "Notifications" label at the top.
base::scoped_nsobject<NSTextField> title_;
+ // The 1px horizontal divider between the scroll view and the title bar.
+ base::scoped_nsobject<NSBox> divider_;
+
+ // The "Nothing to see here" label in an empty message center.
+ base::scoped_nsobject<NSTextField> emptyDescription_;
+
// The scroll view that contains all the notifications in its documentView.
base::scoped_nsobject<NSScrollView> scrollView_;
@@ -157,6 +163,8 @@ MESSAGE_CENTER_EXPORT
// Testing API /////////////////////////////////////////////////////////////////
@interface MCTrayViewController (TestingAPI)
+- (NSBox*)divider;
+- (NSTextField*)emptyDescription;
- (NSScrollView*)scrollView;
- (HoverImageButton*)pauseButton;
- (HoverImageButton*)clearAllButton;
diff --git a/chromium/ui/message_center/cocoa/tray_view_controller.mm b/chromium/ui/message_center/cocoa/tray_view_controller.mm
index a1994ecddda..93bac88d803 100644
--- a/chromium/ui/message_center/cocoa/tray_view_controller.mm
+++ b/chromium/ui/message_center/cocoa/tray_view_controller.mm
@@ -14,6 +14,7 @@
#import "ui/base/cocoa/hover_image_button.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/resource/resource_bundle.h"
+#import "ui/message_center/cocoa/opaque_views.h"
#import "ui/message_center/cocoa/notification_controller.h"
#import "ui/message_center/cocoa/settings_controller.h"
#include "ui/message_center/message_center.h"
@@ -55,7 +56,7 @@ const int kBackButtonSize = 16;
// Step 1: hide all notifications pending removal with fade-out animation.
- (void)hideNotificationsPendingRemoval;
-// Step 2: move up all remaining notfications to take over the available space
+// Step 2: move up all remaining notifications to take over the available space
// due to hiding notifications. The scroll view and the window remain unchanged.
- (void)moveUpRemainingNotifications;
@@ -66,7 +67,7 @@ const int kBackButtonSize = 16;
// "Clear All" is clicked.
- (void)clearOneNotification;
-// When all visible notificatons slide out, re-enable controls and remove
+// When all visible notifications slide out, re-enable controls and remove
// notifications from the message center.
- (void)finalizeClearAll;
@@ -204,7 +205,8 @@ const CGFloat kTrayBottomMargin = 75;
[[scrollView_ documentView] addSubview:[controller view]];
[notifications_ addObject:controller]; // Transfer ownership.
- messageCenter_->DisplayedNotification((*it)->id());
+ messageCenter_->DisplayedNotification(
+ (*it)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER);
notification = controller.get();
} else {
@@ -359,6 +361,14 @@ const CGFloat kTrayBottomMargin = 75;
// Testing API /////////////////////////////////////////////////////////////////
+- (NSBox*)divider {
+ return divider_.get();
+}
+
+- (NSTextField*)emptyDescription {
+ return emptyDescription_.get();
+}
+
- (NSScrollView*)scrollView {
return scrollView_.get();
}
@@ -392,14 +402,12 @@ const CGFloat kTrayBottomMargin = 75;
// Create the "Notifications" label at the top of the tray.
NSFont* font = [NSFont labelFontOfSize:message_center::kTitleFontSize];
- title_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]);
- [title_ setAutoresizingMask:NSViewMinYMargin];
- [title_ setBezeled:NO];
- [title_ setBordered:NO];
- [title_ setDrawsBackground:NO];
- [title_ setEditable:NO];
+ NSColor* color = gfx::SkColorToCalibratedNSColor(
+ message_center::kMessageCenterBackgroundColor);
+ title_.reset(
+ [[MCTextField alloc] initWithFrame:NSZeroRect backgroundColor:color]);
+
[title_ setFont:font];
- [title_ setSelectable:NO];
[title_ setStringValue:
l10n_util::GetNSString(IDS_MESSAGE_CENTER_FOOTER_TITLE)];
[title_ setTextColor:gfx::SkColorToCalibratedNSColor(
@@ -445,16 +453,17 @@ const CGFloat kTrayBottomMargin = 75;
[[self view] addSubview:backButton_];
// Create the divider line between the control area and the notifications.
- base::scoped_nsobject<NSBox> divider(
+ divider_.reset(
[[NSBox alloc] initWithFrame:NSMakeRect(0, 0, NSWidth([view frame]), 1)]);
- [divider setAutoresizingMask:NSViewMinYMargin];
- [divider setBorderType:NSNoBorder];
- [divider setBoxType:NSBoxCustom];
- [divider setContentViewMargins:NSZeroSize];
- [divider setFillColor:gfx::SkColorToCalibratedNSColor(
+ [divider_ setAutoresizingMask:NSViewMinYMargin];
+ [divider_ setBorderType:NSNoBorder];
+ [divider_ setBoxType:NSBoxCustom];
+ [divider_ setContentViewMargins:NSZeroSize];
+ [divider_ setFillColor:gfx::SkColorToCalibratedNSColor(
message_center::kFooterDelimiterColor)];
- [divider setTitlePosition:NSNoTitle];
- [view addSubview:divider];
+ [divider_ setTitlePosition:NSNoTitle];
+ [view addSubview:divider_];
+
auto getButtonFrame = ^NSRect(CGFloat maxX, NSImage* image) {
NSSize size = [image size];
@@ -524,13 +533,45 @@ const CGFloat kTrayBottomMargin = 75;
[pauseButton_ setAction:@selector(toggleQuietMode:)];
configureButton(pauseButton_);
[view addSubview:pauseButton_];
+
+ // Create the description field for the empty message center. Initially it is
+ // invisible.
+ emptyDescription_.reset(
+ [[MCTextField alloc] initWithFrame:NSZeroRect backgroundColor:color]);
+
+ NSFont* smallFont =
+ [NSFont labelFontOfSize:message_center::kEmptyCenterFontSize];
+ [emptyDescription_ setFont:smallFont];
+ [emptyDescription_ setStringValue:
+ l10n_util::GetNSString(IDS_MESSAGE_CENTER_NO_MESSAGES)];
+ [emptyDescription_ setTextColor:gfx::SkColorToCalibratedNSColor(
+ message_center::kDimTextColor)];
+ [emptyDescription_ sizeToFit];
+ [emptyDescription_ setHidden:YES];
+
+ [view addSubview:emptyDescription_];
}
- (void)updateTrayViewAndWindow {
- CGFloat scrollContentHeight = 0;
+ CGFloat scrollContentHeight = message_center::kMinScrollViewHeight;
if ([notifications_ count]) {
+ [emptyDescription_ setHidden:YES];
+ [scrollView_ setHidden:NO];
+ [divider_ setHidden:NO];
scrollContentHeight = NSMaxY([[[notifications_ lastObject] view] frame]) +
message_center::kMarginBetweenItems;;
+ } else {
+ [emptyDescription_ setHidden:NO];
+ [scrollView_ setHidden:YES];
+ [divider_ setHidden:YES];
+
+ NSRect centeredFrame = [emptyDescription_ frame];
+ NSPoint centeredOrigin = NSMakePoint(
+ floor((NSWidth([[self view] frame]) - NSWidth(centeredFrame))/2 + 0.5),
+ floor((scrollContentHeight - NSHeight(centeredFrame))/2 + 0.5));
+
+ centeredFrame.origin = centeredOrigin;
+ [emptyDescription_ setFrame:centeredFrame];
}
// Resize the scroll view's content.
@@ -620,7 +661,8 @@ const CGFloat kTrayBottomMargin = 75;
// Fade-out those notifications pending removal.
for (MCNotificationController* notification in notifications_.get()) {
- if (messageCenter_->HasNotification([notification notificationID]))
+ if (messageCenter_->FindVisibleNotificationById(
+ [notification notificationID]))
continue;
[notificationsPendingRemoval_ addObject:notification];
[animationDataArray addObject:@{
diff --git a/chromium/ui/message_center/cocoa/tray_view_controller_unittest.mm b/chromium/ui/message_center/cocoa/tray_view_controller_unittest.mm
index cb649f9bdf6..9496177bd3b 100644
--- a/chromium/ui/message_center/cocoa/tray_view_controller_unittest.mm
+++ b/chromium/ui/message_center/cocoa/tray_view_controller_unittest.mm
@@ -8,7 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#import "ui/base/test/ui_cocoa_test_helper.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
#include "ui/message_center/fake_notifier_settings_provider.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_impl.h"
@@ -16,13 +16,14 @@
#include "ui/message_center/notification.h"
#include "ui/message_center/notifier_settings.h"
+using base::ASCIIToUTF16;
+
namespace message_center {
class TrayViewControllerTest : public ui::CocoaTest {
public:
TrayViewControllerTest()
- : center_(NULL),
- message_loop_(base::MessageLoop::TYPE_UI) {
+ : center_(NULL) {
}
virtual void SetUp() OVERRIDE {
@@ -61,7 +62,7 @@ class TrayViewControllerTest : public ui::CocoaTest {
message_center::MessageCenter* center_; // Weak, global.
- base::MessageLoop message_loop_;
+ base::MessageLoopForUI message_loop_;
scoped_ptr<base::RunLoop> nested_run_loop_;
base::scoped_nsobject<MCTrayViewController> tray_;
};
@@ -76,7 +77,7 @@ TEST_F(TrayViewControllerTest, AddRemoveOne) {
ASCIIToUTF16("First notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -97,7 +98,10 @@ TEST_F(TrayViewControllerTest, AddRemoveOne) {
center_->RemoveNotification("1", true);
[tray_ onMessageCenterTrayChanged];
EXPECT_EQ(0u, [[view subviews] count]);
- EXPECT_CGFLOAT_EQ(0, NSHeight([view frame]));
+ // The empty tray is now 100px tall to accommodate
+ // the empty message.
+ EXPECT_CGFLOAT_EQ(message_center::kMinScrollViewHeight,
+ NSHeight([view frame]));
}
TEST_F(TrayViewControllerTest, AddThreeClearAll) {
@@ -110,7 +114,7 @@ TEST_F(TrayViewControllerTest, AddThreeClearAll) {
ASCIIToUTF16("First notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -121,7 +125,7 @@ TEST_F(TrayViewControllerTest, AddThreeClearAll) {
ASCIIToUTF16("Second notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -132,7 +136,7 @@ TEST_F(TrayViewControllerTest, AddThreeClearAll) {
ASCIIToUTF16("Third notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -145,7 +149,10 @@ TEST_F(TrayViewControllerTest, AddThreeClearAll) {
[tray_ onMessageCenterTrayChanged];
EXPECT_EQ(0u, [[view subviews] count]);
- EXPECT_CGFLOAT_EQ(0, NSHeight([view frame]));
+ // The empty tray is now 100px tall to accommodate
+ // the empty message.
+ EXPECT_CGFLOAT_EQ(message_center::kMinScrollViewHeight,
+ NSHeight([view frame]));
}
TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) {
@@ -165,7 +172,7 @@ TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) {
ASCIIToUTF16("First notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -184,7 +191,7 @@ TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) {
ASCIIToUTF16("Second notification"),
ASCIIToUTF16("This is a simple test."),
gfx::Image(),
- string16(),
+ base::string16(),
DummyNotifierId(),
message_center::RichNotificationData(),
NULL));
@@ -241,6 +248,35 @@ TEST_F(TrayViewControllerTest, Settings) {
// The tray should be back at its previous height now.
EXPECT_EQ(trayHeight, NSHeight([[tray_ view] frame]));
+
+ // Clean up since this frame owns FakeNotifierSettingsProvider.
+ center_->SetNotifierSettingsProvider(NULL);
+}
+
+TEST_F(TrayViewControllerTest, EmptyCenter) {
+ EXPECT_FALSE([[tray_ emptyDescription] isHidden]);
+
+ // With no notifications, the divider should be hidden.
+ EXPECT_TRUE([[tray_ divider] isHidden]);
+ EXPECT_TRUE([[tray_ scrollView] isHidden]);
+
+ scoped_ptr<message_center::Notification> notification;
+ notification.reset(new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_SIMPLE,
+ "1",
+ ASCIIToUTF16("First notification"),
+ ASCIIToUTF16("This is a simple test."),
+ gfx::Image(),
+ base::string16(),
+ DummyNotifierId(),
+ message_center::RichNotificationData(),
+ NULL));
+ center_->AddNotification(notification.Pass());
+ [tray_ onMessageCenterTrayChanged];
+
+ EXPECT_FALSE([[tray_ divider] isHidden]);
+ EXPECT_FALSE([[tray_ scrollView] isHidden]);
+ EXPECT_TRUE([[tray_ emptyDescription] isHidden]);
}
} // namespace message_center
diff --git a/chromium/ui/message_center/dummy_message_center.cc b/chromium/ui/message_center/dummy_message_center.cc
index 54b30825113..df49992ad02 100644
--- a/chromium/ui/message_center/dummy_message_center.cc
+++ b/chromium/ui/message_center/dummy_message_center.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_switches.h"
-#include "ui/message_center/message_center_util.h"
// This file contains dummy implementation of MessageCenter and used to compile
// and link with Android and iOS implementations of Chrome which do not have
@@ -16,10 +14,6 @@
namespace message_center {
-bool IsRichNotificationEnabled() {
- return false;
-}
-
// static
void MessageCenter::Initialize() {
}
diff --git a/chromium/ui/message_center/fake_message_center.cc b/chromium/ui/message_center/fake_message_center.cc
index 7b1a093b316..946b2c75ba9 100644
--- a/chromium/ui/message_center/fake_message_center.cc
+++ b/chromium/ui/message_center/fake_message_center.cc
@@ -38,10 +38,6 @@ bool FakeMessageCenter::HasPopupNotifications() const {
return false;
}
-bool FakeMessageCenter::HasNotification(const std::string& id) {
- return false;
-}
-
bool FakeMessageCenter::IsQuietMode() const {
return false;
}
@@ -50,6 +46,11 @@ bool FakeMessageCenter::HasClickedListener(const std::string& id) {
return false;
}
+message_center::Notification* FakeMessageCenter::FindVisibleNotificationById(
+ const std::string& id) {
+ return NULL;
+}
+
const NotificationList::Notifications&
FakeMessageCenter::GetVisibleNotifications() {
return empty_notifications_;
@@ -95,9 +96,6 @@ void FakeMessageCenter::DisableNotificationsByNotifier(
const NotifierId& notifier_id) {
}
-void FakeMessageCenter::ExpandNotification(const std::string& id) {
-}
-
void FakeMessageCenter::ClickOnNotification(const std::string& id) {
}
@@ -109,7 +107,9 @@ void FakeMessageCenter::MarkSinglePopupAsShown(const std::string& id,
bool mark_notification_as_read) {
}
-void FakeMessageCenter::DisplayedNotification(const std::string& id) {
+void FakeMessageCenter::DisplayedNotification(
+ const std::string& id,
+ const DisplaySource source) {
}
void FakeMessageCenter::SetNotifierSettingsProvider(
diff --git a/chromium/ui/message_center/fake_message_center.h b/chromium/ui/message_center/fake_message_center.h
index 92e00146d58..22273b8c29c 100644
--- a/chromium/ui/message_center/fake_message_center.h
+++ b/chromium/ui/message_center/fake_message_center.h
@@ -26,9 +26,10 @@ class FakeMessageCenter : public MessageCenter {
virtual size_t NotificationCount() const OVERRIDE;
virtual size_t UnreadNotificationCount() const OVERRIDE;
virtual bool HasPopupNotifications() const OVERRIDE;
- virtual bool HasNotification(const std::string& id) OVERRIDE;
virtual bool IsQuietMode() const OVERRIDE;
virtual bool HasClickedListener(const std::string& id) OVERRIDE;
+ virtual message_center::Notification* FindVisibleNotificationById(
+ const std::string& id) OVERRIDE;
virtual const NotificationList::Notifications& GetVisibleNotifications()
OVERRIDE;
virtual NotificationList::PopupNotifications GetPopupNotifications() OVERRIDE;
@@ -51,13 +52,14 @@ class FakeMessageCenter : public MessageCenter {
const gfx::Image& image) OVERRIDE;
virtual void DisableNotificationsByNotifier(
const NotifierId& notifier_id) OVERRIDE;
- virtual void ExpandNotification(const std::string& id) OVERRIDE;
virtual void ClickOnNotification(const std::string& id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& id,
int button_index) OVERRIDE;
virtual void MarkSinglePopupAsShown(const std::string& id,
bool mark_notification_as_read) OVERRIDE;
- virtual void DisplayedNotification(const std::string& id) OVERRIDE;
+ virtual void DisplayedNotification(
+ const std::string& id,
+ const DisplaySource source) OVERRIDE;
virtual void SetNotifierSettingsProvider(
NotifierSettingsProvider* provider) OVERRIDE;
virtual NotifierSettingsProvider* GetNotifierSettingsProvider() OVERRIDE;
diff --git a/chromium/ui/message_center/fake_message_center_tray_delegate.cc b/chromium/ui/message_center/fake_message_center_tray_delegate.cc
new file mode 100644
index 00000000000..17a5af62547
--- /dev/null
+++ b/chromium/ui/message_center/fake_message_center_tray_delegate.cc
@@ -0,0 +1,56 @@
+// 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/message_center/fake_message_center_tray_delegate.h"
+
+#include "base/message_loop/message_loop.h"
+#include "ui/message_center/message_center_tray.h"
+
+namespace message_center {
+
+FakeMessageCenterTrayDelegate::FakeMessageCenterTrayDelegate(
+ MessageCenter* message_center,
+ base::Closure quit_closure)
+ : tray_(new MessageCenterTray(this, message_center)),
+ quit_closure_(quit_closure),
+ displayed_first_run_balloon_(false) {}
+
+FakeMessageCenterTrayDelegate::~FakeMessageCenterTrayDelegate() {
+}
+
+void FakeMessageCenterTrayDelegate::OnMessageCenterTrayChanged() {
+}
+
+bool FakeMessageCenterTrayDelegate::ShowPopups() {
+ return false;
+}
+
+void FakeMessageCenterTrayDelegate::HidePopups() {
+}
+
+bool FakeMessageCenterTrayDelegate::ShowMessageCenter() {
+ return false;
+}
+
+void FakeMessageCenterTrayDelegate::HideMessageCenter() {
+}
+
+bool FakeMessageCenterTrayDelegate::ShowNotifierSettings() {
+ return false;
+}
+
+bool FakeMessageCenterTrayDelegate::IsContextMenuEnabled() const {
+ return false;
+}
+
+MessageCenterTray* FakeMessageCenterTrayDelegate::GetMessageCenterTray() {
+ return tray_.get();
+}
+
+void FakeMessageCenterTrayDelegate::DisplayFirstRunBalloon() {
+ displayed_first_run_balloon_ = true;
+ base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
+}
+
+} // namespace message_center
diff --git a/chromium/ui/message_center/fake_message_center_tray_delegate.h b/chromium/ui/message_center/fake_message_center_tray_delegate.h
new file mode 100644
index 00000000000..ff05c844ffd
--- /dev/null
+++ b/chromium/ui/message_center/fake_message_center_tray_delegate.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_MESSAGE_CENTER_FAKE_MESSAGE_CENTER_TRAY_DELEGATE_H_
+#define UI_MESSAGE_CENTER_FAKE_MESSAGE_CENTER_TRAY_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/message_center/message_center_tray_delegate.h"
+
+namespace message_center {
+
+class MessageCenter;
+class MessageCenterTray;
+
+// A message center tray delegate which does nothing.
+class FakeMessageCenterTrayDelegate : public MessageCenterTrayDelegate {
+ public:
+ FakeMessageCenterTrayDelegate(MessageCenter* message_center,
+ base::Closure quit_closure);
+ virtual ~FakeMessageCenterTrayDelegate();
+
+ bool displayed_first_run_balloon() const {
+ return displayed_first_run_balloon_;
+ }
+
+ // Overridden from MessageCenterTrayDelegate:
+ virtual void OnMessageCenterTrayChanged() OVERRIDE;
+ virtual bool ShowPopups() OVERRIDE;
+ virtual void HidePopups() OVERRIDE;
+ virtual bool ShowMessageCenter() OVERRIDE;
+ virtual void HideMessageCenter() OVERRIDE;
+ virtual bool ShowNotifierSettings() OVERRIDE;
+ virtual bool IsContextMenuEnabled() const OVERRIDE;
+ virtual MessageCenterTray* GetMessageCenterTray() OVERRIDE;
+ virtual void DisplayFirstRunBalloon() OVERRIDE;
+
+ private:
+ scoped_ptr<MessageCenterTray> tray_;
+ base::Closure quit_closure_;
+ bool displayed_first_run_balloon_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeMessageCenterTrayDelegate);
+};
+
+} // namespace message_center
+
+#endif // UI_MESSAGE_CENTER_FAKE_MESSAGE_CENTER_TRAY_DELEGATE_H_
diff --git a/chromium/ui/message_center/fake_notifier_settings_provider.cc b/chromium/ui/message_center/fake_notifier_settings_provider.cc
index c25f7a21873..79c153a8783 100644
--- a/chromium/ui/message_center/fake_notifier_settings_provider.cc
+++ b/chromium/ui/message_center/fake_notifier_settings_provider.cc
@@ -27,8 +27,8 @@ FakeNotifierSettingsProvider::FakeNotifierSettingsProvider(
notifier_settings_requested_count_(0u) {
NotifierGroupItem item;
item.group = new NotifierGroup(gfx::Image(),
- UTF8ToUTF16("Fake name"),
- UTF8ToUTF16("fake@email.com"),
+ base::UTF8ToUTF16("Fake name"),
+ base::UTF8ToUTF16("fake@email.com"),
true);
item.notifiers = notifiers;
items_.push_back(item);
diff --git a/chromium/ui/message_center/message_center.gyp b/chromium/ui/message_center/message_center.gyp
index 569f44737f1..6de3c5bf6ea 100644
--- a/chromium/ui/message_center/message_center.gyp
+++ b/chromium/ui/message_center/message_center.gyp
@@ -16,10 +16,11 @@
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../../skia/skia.gyp:skia',
'../../url/url.gyp:url_lib',
- '../base/strings/ui_strings.gyp:ui_strings',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../strings/ui_strings.gyp:ui_strings',
],
'defines': [
'MESSAGE_CENTER_IMPLEMENTATION',
@@ -27,6 +28,8 @@
'sources': [
'cocoa/notification_controller.h',
'cocoa/notification_controller.mm',
+ 'cocoa/opaque_views.h',
+ 'cocoa/opaque_views.mm',
'cocoa/popup_collection.h',
'cocoa/popup_collection.mm',
'cocoa/popup_controller.h',
@@ -52,14 +55,10 @@
'message_center_observer.h',
'message_center_style.cc',
'message_center_style.h',
- 'message_center_switches.cc',
- 'message_center_switches.h',
'message_center_tray.cc',
'message_center_tray.h',
'message_center_tray_delegate.h',
'message_center_types.h',
- 'message_center_util.cc',
- 'message_center_util.h',
'notification.cc',
'notification.h',
'notification_blocker.cc',
@@ -72,8 +71,6 @@
'notifier_settings.h',
'views/bounded_label.cc',
'views/bounded_label.h',
- 'views/group_view.cc',
- 'views/group_view.h',
'views/constants.h',
'views/message_bubble_base.cc',
'views/message_bubble_base.h',
@@ -88,6 +85,8 @@
'views/message_popup_collection.h',
'views/message_view.cc',
'views/message_view.h',
+ 'views/message_view_context_menu_controller.cc',
+ 'views/message_view_context_menu_controller.h',
'views/notifier_settings_view.cc',
'views/notifier_settings_view.h',
'views/notification_button.cc',
@@ -116,6 +115,7 @@
'dependencies': [
'../events/events.gyp:events',
'../views/views.gyp:views',
+ '../compositor/compositor.gyp:compositor',
],
}, {
'sources/': [
@@ -132,20 +132,9 @@
'views/message_popup_bubble.h',
],
}],
- ['OS=="mac"', {
- 'dependencies': [
- '../ui.gyp:ui_cocoa_third_party_toolkits',
- ],
- 'include_dirs': [
- '../../third_party/GTM',
- ],
- }],
- ['toolkit_views==1', {
- 'dependencies': [
- '../compositor/compositor.gyp:compositor',
- ],
- }],
- ['notifications==0', { # Android and iOS.
+ # iOS disables notifications altogether, Android implements its own
+ # notification UI manager instead of deferring to the message center.
+ ['notifications==0 or OS=="android"', {
'sources/': [
# Exclude everything except dummy impl.
['exclude', '\\.(cc|mm)$'],
@@ -155,6 +144,14 @@
}, { # notifications==1
'sources!': [ 'dummy_message_center.cc' ],
}],
+ # Include a minimal set of files required for notifications on Android.
+ ['OS=="android"', {
+ 'sources/': [
+ ['include', '^notification\\.cc$'],
+ ['include', '^notification_delegate\\.cc$'],
+ ['include', '^notifier_settings\\.cc$'],
+ ],
+ }],
],
}, # target_name: message_center
{
@@ -164,13 +161,16 @@
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
'message_center',
],
'sources': [
'fake_message_center.h',
'fake_message_center.cc',
+ 'fake_message_center_tray_delegate.h',
+ 'fake_message_center_tray_delegate.cc',
'fake_notifier_settings_provider.h',
'fake_notifier_settings_provider.cc',
],
@@ -181,15 +181,14 @@
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
- '../../chrome/chrome_resources.gyp:packed_resources',
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
'../../url/url.gyp:url_lib',
- '../../url/url.gyp:url_lib',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:run_ui_unittests',
+ '../resources/ui_resources.gyp:ui_test_pak',
'message_center',
'message_center_test_support',
],
@@ -203,18 +202,14 @@
'cocoa/tray_view_controller_unittest.mm',
'message_center_tray_unittest.cc',
'message_center_impl_unittest.cc',
+ 'notification_delegate_unittest.cc',
'notification_list_unittest.cc',
'test/run_all_unittests.cc',
],
'conditions': [
- ['desktop_linux == 1 or chromeos == 1 or OS=="ios"', {
- 'dependencies': [
- '../base/strings/ui_strings.gyp:ui_unittest_strings',
- ],
- }],
['OS=="mac"', {
'dependencies': [
- '../ui_unittests.gyp:ui_test_support',
+ '../gfx/gfx.gyp:gfx_test_support',
],
}],
['toolkit_views==1', {
@@ -229,6 +224,7 @@
'views/bounded_label_unittest.cc',
'views/message_center_view_unittest.cc',
'views/message_popup_collection_unittest.cc',
+ 'views/notification_view_unittest.cc',
'views/notifier_settings_view_unittest.cc',
],
}],
@@ -240,7 +236,7 @@
],
}],
# See http://crbug.com/162998#c4 for why this is needed.
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
'../../base/allocator/allocator.gyp:allocator',
],
diff --git a/chromium/ui/message_center/message_center.h b/chromium/ui/message_center/message_center.h
index 1b6cbae33c1..84824ab3776 100644
--- a/chromium/ui/message_center/message_center.h
+++ b/chromium/ui/message_center/message_center.h
@@ -8,12 +8,9 @@
#include <string>
#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "ui/gfx/native_widget_types.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/message_center_types.h"
#include "ui/message_center/notification_list.h"
-#include "ui/message_center/notification_types.h"
namespace base {
class DictionaryValue;
@@ -23,6 +20,16 @@ class DictionaryValue;
// [Add|Remove|Update]Notification to create and update notifications in the
// list. It also sends those changes to its observers when a notification
// is shown, closed, or clicked on.
+//
+// MessageCenter is agnostic of profiles; it uses the string returned by
+// message_center::Notification::id() to uniquely identify a notification. It is
+// the caller's responsibility to formulate the id so that 2 different
+// notification should have different ids. For example, if the caller supports
+// multiple profiles, then caller should encode both profile characteristics and
+// notification front end's notification id into a new id and set it into the
+// notification instance before passing that in. Consequently the id passed to
+// observers will be this unique id, which can be used with MessageCenter
+// interface but probably not higher level interfaces.
namespace message_center {
@@ -32,8 +39,6 @@ class MessagePopupCollectionTest;
class MessageCenterObserver;
class NotificationBlocker;
-class NotificationList;
-class NotifierSettingsDelegate;
class NotifierSettingsProvider;
class MESSAGE_CENTER_EXPORT MessageCenter {
@@ -56,10 +61,14 @@ class MESSAGE_CENTER_EXPORT MessageCenter {
virtual size_t NotificationCount() const = 0;
virtual size_t UnreadNotificationCount() const = 0;
virtual bool HasPopupNotifications() const = 0;
- virtual bool HasNotification(const std::string& id) = 0;
virtual bool IsQuietMode() const = 0;
virtual bool HasClickedListener(const std::string& id) = 0;
+ // Find the notification with the corresponding id. Returns NULL if not found.
+ // The returned instance is owned by the message center.
+ virtual message_center::Notification* FindVisibleNotificationById(
+ const std::string& id) = 0;
+
// Gets all notifications to be shown to the user in the message center. Note
// that queued changes due to the message center being open are not reflected
// in this list.
@@ -70,7 +79,7 @@ class MESSAGE_CENTER_EXPORT MessageCenter {
// VISIBILITY_TRANSIENT or VISIBILITY_SETTINGS.
virtual NotificationList::PopupNotifications GetPopupNotifications() = 0;
- // Management of NotificaitonBlockers.
+ // Management of NotificationBlockers.
virtual void AddNotificationBlocker(NotificationBlocker* blocker) = 0;
virtual void RemoveNotificationBlocker(NotificationBlocker* blocker) = 0;
@@ -103,16 +112,12 @@ class MESSAGE_CENTER_EXPORT MessageCenter {
int button_index,
const gfx::Image& image) = 0;
- // Operations happening especially from GUIs: click, expand, disable,
- // and settings.
+ // Operations happening especially from GUIs: click, disable, and settings.
// Searches through the notifications and disables any that match the
// extension id given.
virtual void DisableNotificationsByNotifier(
const NotifierId& notifier_id) = 0;
- // Reformat a notification to show its entire text content.
- virtual void ExpandNotification(const std::string& id) = 0;
-
// This should be called by UI classes when a notification is clicked to
// trigger the notification's delegate callback and also update the message
// center observers.
@@ -134,7 +139,9 @@ class MESSAGE_CENTER_EXPORT MessageCenter {
// This should be called by UI classes when a notification is first displayed
// to the user, in order to decrement the unread_count for the tray, and to
// notify observers that the notification is visible.
- virtual void DisplayedNotification(const std::string& id) = 0;
+ virtual void DisplayedNotification(
+ const std::string& id,
+ const DisplaySource source) = 0;
// Setter/getter of notifier settings provider. This will be a weak reference.
// This should be set at the initialization process. The getter may return
diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc
index 22c473d39d5..7f4f568ba62 100644
--- a/chromium/ui/message_center/message_center_impl.cc
+++ b/chromium/ui/message_center/message_center_impl.cc
@@ -178,6 +178,7 @@ void ChangeQueue::ApplyChanges(MessageCenter* message_center) {
void ChangeQueue::AddNotification(scoped_ptr<Notification> notification) {
std::string id = notification->id();
+
scoped_ptr<Change> change(
new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
Replace(id, change.Pass());
@@ -353,7 +354,9 @@ void PopupTimersController::TimerFinished(const std::string& id) {
message_center_->MarkSinglePopupAsShown(id, false);
}
-void PopupTimersController::OnNotificationDisplayed(const std::string& id) {
+void PopupTimersController::OnNotificationDisplayed(
+ const std::string& id,
+ const DisplaySource source) {
OnNotificationUpdated(id);
}
@@ -425,7 +428,9 @@ MessageCenterImpl::MessageCenterImpl()
notification_queue_.reset(new internal::ChangeQueue());
}
-MessageCenterImpl::~MessageCenterImpl() {}
+MessageCenterImpl::~MessageCenterImpl() {
+ SetNotifierSettingsProvider(NULL);
+}
void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
observer_list_.AddObserver(observer);
@@ -477,6 +482,18 @@ void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
OnBlockingStateChanged(blocker));
}
+void MessageCenterImpl::UpdateIconImage(
+ const NotifierId& notifier_id,const gfx::Image& icon) {}
+
+void MessageCenterImpl::NotifierGroupChanged() {}
+
+void MessageCenterImpl::NotifierEnabledChanged(
+ const NotifierId& notifier_id, bool enabled) {
+ if (!enabled) {
+ RemoveNotificationsForNotifierId(notifier_id);
+ }
+}
+
void MessageCenterImpl::SetVisibility(Visibility visibility) {
std::set<std::string> updated_ids;
notification_list_->SetMessageCenterVisible(
@@ -515,23 +532,19 @@ bool MessageCenterImpl::HasPopupNotifications() const {
notification_list_->HasPopupNotifications(blockers_);
}
-bool MessageCenterImpl::HasNotification(const std::string& id) {
- // This will return true if the notification with |id| is hidden by the
- // ChromeOS multi-profile feature. This would be harmless for now because
- // this check will be used from the UI, so the |id| for hidden profile won't
- // arrive here.
- // TODO(mukai): fix this if necessary.
- return notification_list_->HasNotification(id);
-}
-
bool MessageCenterImpl::IsQuietMode() const {
return notification_list_->quiet_mode();
}
bool MessageCenterImpl::HasClickedListener(const std::string& id) {
- NotificationDelegate* delegate =
+ scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
- return delegate && delegate->HasClickedListener();
+ return delegate.get() && delegate->HasClickedListener();
+}
+
+message_center::Notification* MessageCenterImpl::FindVisibleNotificationById(
+ const std::string& id) {
+ return notification_list_->GetNotificationById(id);
}
const NotificationList::Notifications&
@@ -548,7 +561,7 @@ NotificationList::PopupNotifications
// Client code interface.
void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
DCHECK(notification.get());
-
+ const std::string id = notification->id();
for (size_t i = 0; i < blockers_.size(); ++i)
blockers_[i]->CheckState();
@@ -560,8 +573,7 @@ void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
// Sometimes the notification can be added with the same id and the
// |notification_list| will replace the notification instead of adding new.
// This is essentially an update rather than addition.
- const std::string& id = notification->id();
- bool already_exists = notification_list_->HasNotification(id);
+ bool already_exists = (notification_list_->GetNotificationById(id) != NULL);
notification_list_->AddNotification(notification.Pass());
notification_cache_.Rebuild(
notification_list_->GetVisibleNotifications(blockers_));
@@ -627,18 +639,19 @@ void MessageCenterImpl::RemoveNotification(const std::string& id,
return;
}
- if (!HasNotification(id))
+ if (FindVisibleNotificationById(id) == NULL)
return;
- NotificationDelegate* delegate =
- notification_list_->GetNotificationDelegate(id);
- if (delegate)
- delegate->Close(by_user);
-
// In many cases |id| is a reference to an existing notification instance
// but the instance can be destructed in RemoveNotification(). Hence
// copies the id explicitly here.
std::string copied_id(id);
+
+ scoped_refptr<NotificationDelegate> delegate =
+ notification_list_->GetNotificationDelegate(copied_id);
+ if (delegate.get())
+ delegate->Close(by_user);
+
notification_list_->RemoveNotification(copied_id);
notification_cache_.Rebuild(
notification_list_->GetVisibleNotifications(blockers_));
@@ -647,6 +660,20 @@ void MessageCenterImpl::RemoveNotification(const std::string& id,
OnNotificationRemoved(copied_id, by_user));
}
+void MessageCenterImpl::RemoveNotificationsForNotifierId(
+ const NotifierId& notifier_id) {
+ NotificationList::Notifications notifications =
+ notification_list_->GetNotificationsByNotifierId(notifier_id);
+ for (NotificationList::Notifications::const_iterator iter =
+ notifications.begin(); iter != notifications.end(); ++iter) {
+ RemoveNotification((*iter)->id(), false);
+ }
+ if (!notifications.empty()) {
+ notification_cache_.Rebuild(
+ notification_list_->GetVisibleNotifications(blockers_));
+ }
+}
+
void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
// Using not |blockers_| but an empty list since it wants to remove literally
// all notifications.
@@ -666,8 +693,8 @@ void MessageCenterImpl::RemoveNotifications(
for (NotificationList::Notifications::const_iterator iter =
notifications.begin(); iter != notifications.end(); ++iter) {
ids.insert((*iter)->id());
- NotificationDelegate* delegate = (*iter)->delegate();
- if (delegate)
+ scoped_refptr<NotificationDelegate> delegate = (*iter)->delegate();
+ if (delegate.get())
delegate->Close(by_user);
notification_list_->RemoveNotification((*iter)->id());
}
@@ -749,38 +776,21 @@ void MessageCenterImpl::DisableNotificationsByNotifier(
// TODO(mukai): SetNotifierEnabled can just accept notifier_id?
Notifier notifier(notifier_id, base::string16(), true);
settings_provider_->SetNotifierEnabled(notifier, false);
- }
-
- NotificationList::Notifications notifications =
- notification_list_->GetNotificationsByNotifierId(notifier_id);
- for (NotificationList::Notifications::const_iterator iter =
- notifications.begin(); iter != notifications.end();) {
- std::string id = (*iter)->id();
- iter++;
- RemoveNotification(id, false);
- }
- if (!notifications.empty()) {
- notification_cache_.Rebuild(
- notification_list_->GetVisibleNotifications(blockers_));
+ // The settings provider will call back to remove the notifications
+ // belonging to the notifier id.
+ } else {
+ RemoveNotificationsForNotifierId(notifier_id);
}
}
-void MessageCenterImpl::ExpandNotification(const std::string& id) {
- if (!HasNotification(id))
- return;
- notification_list_->MarkNotificationAsExpanded(id);
- FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
- OnNotificationUpdated(id));
-}
-
void MessageCenterImpl::ClickOnNotification(const std::string& id) {
- if (!HasNotification(id))
+ if (FindVisibleNotificationById(id) == NULL)
return;
if (HasPopupNotifications())
MarkSinglePopupAsShown(id, true);
- NotificationDelegate* delegate =
+ scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
- if (delegate)
+ if (delegate.get())
delegate->Click();
FOR_EACH_OBSERVER(
MessageCenterObserver, observer_list_, OnNotificationClicked(id));
@@ -788,13 +798,13 @@ void MessageCenterImpl::ClickOnNotification(const std::string& id) {
void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
int button_index) {
- if (!HasNotification(id))
+ if (FindVisibleNotificationById(id) == NULL)
return;
if (HasPopupNotifications())
MarkSinglePopupAsShown(id, true);
- NotificationDelegate* delegate =
+ scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
- if (delegate)
+ if (delegate.get())
delegate->ButtonClick(button_index);
FOR_EACH_OBSERVER(
MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
@@ -803,7 +813,7 @@ void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
bool mark_notification_as_read) {
- if (!HasNotification(id))
+ if (FindVisibleNotificationById(id) == NULL)
return;
notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
notification_cache_.RecountUnread();
@@ -811,24 +821,34 @@ void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
}
-void MessageCenterImpl::DisplayedNotification(const std::string& id) {
- if (!HasNotification(id))
+void MessageCenterImpl::DisplayedNotification(
+ const std::string& id,
+ const DisplaySource source) {
+ if (FindVisibleNotificationById(id) == NULL)
return;
if (HasPopupNotifications())
notification_list_->MarkSinglePopupAsDisplayed(id);
notification_cache_.RecountUnread();
- NotificationDelegate* delegate =
+ scoped_refptr<NotificationDelegate> delegate =
notification_list_->GetNotificationDelegate(id);
- if (delegate)
+ if (delegate.get())
delegate->Display();
FOR_EACH_OBSERVER(
- MessageCenterObserver, observer_list_, OnNotificationDisplayed(id));
+ MessageCenterObserver,
+ observer_list_,
+ OnNotificationDisplayed(id, source));
}
void MessageCenterImpl::SetNotifierSettingsProvider(
NotifierSettingsProvider* provider) {
+ if (settings_provider_) {
+ settings_provider_->RemoveObserver(this);
+ settings_provider_ = NULL;
+ }
settings_provider_ = provider;
+ if (settings_provider_)
+ settings_provider_->AddObserver(this);
}
NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
diff --git a/chromium/ui/message_center/message_center_impl.h b/chromium/ui/message_center/message_center_impl.h
index faee6581804..f48f5dcd489 100644
--- a/chromium/ui/message_center/message_center_impl.h
+++ b/chromium/ui/message_center/message_center_impl.h
@@ -17,6 +17,7 @@
#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/message_center_types.h"
#include "ui/message_center/notification_blocker.h"
+#include "ui/message_center/notifier_settings.h"
namespace message_center {
class NotificationDelegate;
@@ -85,7 +86,9 @@ class MESSAGE_CENTER_EXPORT PopupTimersController
virtual ~PopupTimersController();
// MessageCenterObserver implementation.
- virtual void OnNotificationDisplayed(const std::string& id) OVERRIDE;
+ virtual void OnNotificationDisplayed(
+ const std::string& id,
+ const DisplaySource source) OVERRIDE;
virtual void OnNotificationUpdated(const std::string& id) OVERRIDE;
virtual void OnNotificationRemoved(const std::string& id, bool by_user)
OVERRIDE;
@@ -135,7 +138,8 @@ class MESSAGE_CENTER_EXPORT PopupTimersController
// The default implementation of MessageCenter.
class MessageCenterImpl : public MessageCenter,
- public NotificationBlocker::Observer {
+ public NotificationBlocker::Observer,
+ public message_center::NotifierSettingsObserver {
public:
MessageCenterImpl();
virtual ~MessageCenterImpl();
@@ -150,9 +154,10 @@ class MessageCenterImpl : public MessageCenter,
virtual size_t NotificationCount() const OVERRIDE;
virtual size_t UnreadNotificationCount() const OVERRIDE;
virtual bool HasPopupNotifications() const OVERRIDE;
- virtual bool HasNotification(const std::string& id) OVERRIDE;
virtual bool IsQuietMode() const OVERRIDE;
virtual bool HasClickedListener(const std::string& id) OVERRIDE;
+ virtual message_center::Notification* FindVisibleNotificationById(
+ const std::string& id) OVERRIDE;
virtual const NotificationList::Notifications& GetVisibleNotifications()
OVERRIDE;
virtual NotificationList::PopupNotifications GetPopupNotifications() OVERRIDE;
@@ -172,13 +177,14 @@ class MessageCenterImpl : public MessageCenter,
const gfx::Image& image) OVERRIDE;
virtual void DisableNotificationsByNotifier(
const NotifierId& notifier_id) OVERRIDE;
- virtual void ExpandNotification(const std::string& id) OVERRIDE;
virtual void ClickOnNotification(const std::string& id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& id,
int button_index) OVERRIDE;
virtual void MarkSinglePopupAsShown(const std::string& id,
bool mark_notification_as_read) OVERRIDE;
- virtual void DisplayedNotification(const std::string& id) OVERRIDE;
+ virtual void DisplayedNotification(
+ const std::string& id,
+ const DisplaySource source) OVERRIDE;
virtual void SetNotifierSettingsProvider(
NotifierSettingsProvider* provider) OVERRIDE;
virtual NotifierSettingsProvider* GetNotifierSettingsProvider() OVERRIDE;
@@ -191,6 +197,13 @@ class MessageCenterImpl : public MessageCenter,
// NotificationBlocker::Observer overrides:
virtual void OnBlockingStateChanged(NotificationBlocker* blocker) OVERRIDE;
+ // message_center::NotifierSettingsObserver overrides:
+ virtual void UpdateIconImage(const NotifierId& notifier_id,
+ const gfx::Image& icon) OVERRIDE;
+ virtual void NotifierGroupChanged() OVERRIDE;
+ virtual void NotifierEnabledChanged(const NotifierId& notifier_id,
+ bool enabled) OVERRIDE;
+
protected:
virtual void DisableTimersForTest() OVERRIDE;
@@ -198,7 +211,7 @@ class MessageCenterImpl : public MessageCenter,
struct NotificationCache {
NotificationCache();
~NotificationCache();
- void Rebuild(const NotificationList::Notifications& notificaitons);
+ void Rebuild(const NotificationList::Notifications& notifications);
void RecountUnread();
NotificationList::Notifications visible_notifications;
@@ -206,6 +219,7 @@ class MessageCenterImpl : public MessageCenter,
};
void RemoveNotifications(bool by_user, const NotificationBlockers& blockers);
+ void RemoveNotificationsForNotifierId(const NotifierId& notifier_id);
scoped_ptr<NotificationList> notification_list_;
NotificationCache notification_cache_;
diff --git a/chromium/ui/message_center/message_center_impl_unittest.cc b/chromium/ui/message_center/message_center_impl_unittest.cc
index b26c446be3b..913c8a2e33c 100644
--- a/chromium/ui/message_center/message_center_impl_unittest.cc
+++ b/chromium/ui/message_center/message_center_impl_unittest.cc
@@ -15,6 +15,9 @@
#include "ui/message_center/message_center_types.h"
#include "ui/message_center/notification_blocker.h"
#include "ui/message_center/notification_types.h"
+#include "ui/message_center/notifier_settings.h"
+
+using base::UTF8ToUTF16;
namespace message_center {
namespace {
@@ -27,7 +30,7 @@ class MessageCenterImplTest : public testing::Test,
virtual void SetUp() OVERRIDE {
MessageCenter::Initialize();
message_center_ = MessageCenter::Get();
- loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
+ loop_.reset(new base::MessageLoop);
run_loop_.reset(new base::RunLoop());
closure_ = run_loop_->QuitClosure();
}
@@ -40,16 +43,41 @@ class MessageCenterImplTest : public testing::Test,
}
MessageCenter* message_center() const { return message_center_; }
+ NotifierSettingsObserver* notifier_settings_observer() const {
+ return static_cast<NotifierSettingsObserver*>(message_center_impl());
+ }
+ MessageCenterImpl* message_center_impl() const {
+ return reinterpret_cast<MessageCenterImpl*>(message_center_);
+ }
+
base::RunLoop* run_loop() const { return run_loop_.get(); }
base::Closure closure() const { return closure_; }
protected:
Notification* CreateSimpleNotification(const std::string& id) {
- return CreateNotification(id, NOTIFICATION_TYPE_SIMPLE);
+ return CreateNotificationWithNotifierId(
+ id,
+ "app1",
+ NOTIFICATION_TYPE_SIMPLE);
+ }
+
+ Notification* CreateSimpleNotificationWithNotifierId(
+ const std::string& id, const std::string& notifier_id) {
+ return CreateNotificationWithNotifierId(
+ id,
+ notifier_id,
+ NOTIFICATION_TYPE_SIMPLE);
}
Notification* CreateNotification(const std::string& id,
message_center::NotificationType type) {
+ return CreateNotificationWithNotifierId(id, "app1", type);
+ }
+
+ Notification* CreateNotificationWithNotifierId(
+ const std::string& id,
+ const std::string& notifier_id,
+ message_center::NotificationType type) {
RichNotificationData optional_fields;
optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo")));
optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo")));
@@ -59,11 +87,12 @@ class MessageCenterImplTest : public testing::Test,
UTF8ToUTF16(id),
gfx::Image() /* icon */,
base::string16() /* display_source */,
- NotifierId(NotifierId::APPLICATION, "app1"),
+ NotifierId(NotifierId::APPLICATION, notifier_id),
optional_fields,
NULL);
}
+
private:
MessageCenter* message_center_;
scoped_ptr<base::MessageLoop> loop_;
@@ -588,8 +617,8 @@ TEST_F(MessageCenterImplTest, QueueUpdatesWithCenterVisible) {
message_center()->AddNotification(notification.Pass());
notification.reset(CreateSimpleNotification(id2));
message_center()->UpdateNotification(id, notification.Pass());
- EXPECT_TRUE(message_center()->HasNotification(id2));
- EXPECT_FALSE(message_center()->HasNotification(id));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
// Then open the message center.
message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER);
@@ -597,13 +626,13 @@ TEST_F(MessageCenterImplTest, QueueUpdatesWithCenterVisible) {
// Then update a notification; nothing should have happened.
notification.reset(CreateSimpleNotification(id));
message_center()->UpdateNotification(id2, notification.Pass());
- EXPECT_TRUE(message_center()->HasNotification(id2));
- EXPECT_FALSE(message_center()->HasNotification(id));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
// Close the message center; then the update should have propagated.
message_center()->SetVisibility(VISIBILITY_TRANSIENT);
- EXPECT_FALSE(message_center()->HasNotification(id2));
- EXPECT_TRUE(message_center()->HasNotification(id));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(id2));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(id));
}
TEST_F(MessageCenterImplTest, ComplexQueueing) {
@@ -618,10 +647,10 @@ TEST_F(MessageCenterImplTest, ComplexQueueing) {
message_center()->AddNotification(notification.Pass());
}
for (i = 0; i < 3; i++) {
- EXPECT_TRUE(message_center()->HasNotification(ids[i]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[i]));
}
for (; i < 5; i++) {
- EXPECT_FALSE(message_center()->HasNotification(ids[i]));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[i]));
}
notification.reset(CreateNotification(ids[4], NOTIFICATION_TYPE_PROGRESS));
@@ -651,20 +680,20 @@ TEST_F(MessageCenterImplTest, ComplexQueueing) {
message_center()->AddNotification(notification.Pass());
// The NL should still be the same: ["0", "1", "2", "4p"]
- EXPECT_TRUE(message_center()->HasNotification(ids[0]));
- EXPECT_TRUE(message_center()->HasNotification(ids[1]));
- EXPECT_TRUE(message_center()->HasNotification(ids[2]));
- EXPECT_FALSE(message_center()->HasNotification(ids[3]));
- EXPECT_TRUE(message_center()->HasNotification(ids[4]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[1]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[2]));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[3]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[4]));
EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 4u);
message_center()->SetVisibility(VISIBILITY_TRANSIENT);
- EXPECT_TRUE(message_center()->HasNotification(ids[0]));
- EXPECT_FALSE(message_center()->HasNotification(ids[1]));
- EXPECT_TRUE(message_center()->HasNotification(ids[2]));
- EXPECT_TRUE(message_center()->HasNotification(ids[3]));
- EXPECT_TRUE(message_center()->HasNotification(ids[4]));
- EXPECT_TRUE(message_center()->HasNotification("New id"));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0]));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[1]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[2]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[3]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[4]));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById("New id"));
EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 5u);
}
@@ -693,7 +722,7 @@ TEST_F(MessageCenterImplTest, QueuedDirectUpdates) {
message_center()->AddNotification(notification.Pass());
// The notification should be in the queue.
- EXPECT_FALSE(message_center()->HasNotification(id));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
// Now try setting the icon to a different size.
gfx::Size new_size(16, 16);
@@ -708,12 +737,12 @@ TEST_F(MessageCenterImplTest, QueuedDirectUpdates) {
message_center()->SetNotificationButtonIcon(id, 1, testImage);
// The notification should be in the queue.
- EXPECT_FALSE(message_center()->HasNotification(id));
+ EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
// Close the message center; then the update should have propagated.
message_center()->SetVisibility(VISIBILITY_TRANSIENT);
// The notification should no longer be in the queue.
- EXPECT_TRUE(message_center()->HasNotification(id));
+ EXPECT_TRUE(message_center()->FindVisibleNotificationById(id));
Notification* mc_notification =
*(message_center()->GetVisibleNotifications().begin());
@@ -741,7 +770,8 @@ TEST_F(MessageCenterImplTest, CachedUnreadCount) {
message_center()->GetVisibleNotifications();
for (NotificationList::Notifications::const_iterator iter =
notifications.begin(); iter != notifications.end(); ++iter) {
- message_center()->DisplayedNotification((*iter)->id());
+ message_center()->DisplayedNotification(
+ (*iter)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER);
}
EXPECT_EQ(0u, message_center()->UnreadNotificationCount());
@@ -758,5 +788,84 @@ TEST_F(MessageCenterImplTest, CachedUnreadCount) {
EXPECT_EQ(0u, message_center()->UnreadNotificationCount());
}
+TEST_F(MessageCenterImplTest, DisableNotificationsByNotifier) {
+ ASSERT_EQ(0u, message_center()->NotificationCount());
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id1-1", "app1")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id1-2", "app1")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-1", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-2", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-3", "app2")));
+ ASSERT_EQ(5u, message_center()->NotificationCount());
+
+ // Removing all of app1's notifications should only leave app2's.
+ message_center()->DisableNotificationsByNotifier(
+ NotifierId(NotifierId::APPLICATION, "app1"));
+ ASSERT_EQ(3u, message_center()->NotificationCount());
+
+ // Now we remove the remaining notifications.
+ message_center()->DisableNotificationsByNotifier(
+ NotifierId(NotifierId::APPLICATION, "app2"));
+ ASSERT_EQ(0u, message_center()->NotificationCount());
+}
+
+TEST_F(MessageCenterImplTest, NotifierEnabledChanged) {
+ ASSERT_EQ(0u, message_center()->NotificationCount());
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id1-1", "app1")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id1-2", "app1")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id1-3", "app1")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-1", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-2", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-3", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-4", "app2")));
+ message_center()->AddNotification(
+ scoped_ptr<Notification>(
+ CreateSimpleNotificationWithNotifierId("id2-5", "app2")));
+ ASSERT_EQ(8u, message_center()->NotificationCount());
+
+ // Enabling an extension should have no effect on the count.
+ notifier_settings_observer()->NotifierEnabledChanged(
+ NotifierId(NotifierId::APPLICATION, "app1"), true);
+ ASSERT_EQ(8u, message_center()->NotificationCount());
+
+ // Removing all of app2's notifications should only leave app1's.
+ notifier_settings_observer()->NotifierEnabledChanged(
+ NotifierId(NotifierId::APPLICATION, "app2"), false);
+ ASSERT_EQ(3u, message_center()->NotificationCount());
+
+ // Removal operations should be idempotent.
+ notifier_settings_observer()->NotifierEnabledChanged(
+ NotifierId(NotifierId::APPLICATION, "app2"), false);
+ ASSERT_EQ(3u, message_center()->NotificationCount());
+
+ // Now we remove the remaining notifications.
+ notifier_settings_observer()->NotifierEnabledChanged(
+ NotifierId(NotifierId::APPLICATION, "app1"), false);
+ ASSERT_EQ(0u, message_center()->NotificationCount());
+}
+
} // namespace internal
} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_observer.h b/chromium/ui/message_center/message_center_observer.h
index 901b60e54a1..202430d8165 100644
--- a/chromium/ui/message_center/message_center_observer.h
+++ b/chromium/ui/message_center/message_center_observer.h
@@ -42,7 +42,9 @@ class MESSAGE_CENTER_EXPORT MessageCenterObserver {
// Called when the notification associated with |notification_id| is actually
// displayed.
- virtual void OnNotificationDisplayed(const std::string& notification_id) {}
+ virtual void OnNotificationDisplayed(
+ const std::string& notification_id,
+ const DisplaySource source) {}
// Called when the notification center is shown or hidden.
virtual void OnCenterVisibilityChanged(Visibility visibility) {}
diff --git a/chromium/ui/message_center/message_center_style.cc b/chromium/ui/message_center/message_center_style.cc
index ab5a08cee82..793649a9514 100644
--- a/chromium/ui/message_center/message_center_style.cc
+++ b/chromium/ui/message_center/message_center_style.cc
@@ -26,17 +26,25 @@ const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250);
// Limits.
-gfx::Size GetImageSizeForWidth(int width, const gfx::Size& image_size) {
- gfx::Size size = image_size;
- if (width > 0 && !size.IsEmpty()) {
- double proportion = size.height() / static_cast<double>(size.width());
- size.SetSize(width, std::max(0.5 + width * proportion, 1.0));
- if (size.height() > kNotificationPreferredImageHeight) {
- int height = kNotificationPreferredImageHeight;
- size.SetSize(std::max(0.5 + height / proportion, 1.0), height);
- }
+gfx::Size GetImageSizeForContainerSize(const gfx::Size& container_size,
+ const gfx::Size& image_size) {
+ if (container_size.IsEmpty() || image_size.IsEmpty())
+ return gfx::Size();
+
+ gfx::Size scaled_size = image_size;
+ double proportion =
+ scaled_size.height() / static_cast<double>(scaled_size.width());
+ // We never want to return an empty image given a non-empty container and
+ // image, so round the height to 1.
+ scaled_size.SetSize(container_size.width(),
+ std::max(0.5 + container_size.width() * proportion, 1.0));
+ if (scaled_size.height() > container_size.height()) {
+ scaled_size.SetSize(
+ std::max(0.5 + container_size.height() / proportion, 1.0),
+ container_size.height());
}
- return size;
+
+ return scaled_size;
}
const size_t kNotificationMaximumItems = 5;
diff --git a/chromium/ui/message_center/message_center_style.h b/chromium/ui/message_center/message_center_style.h
index 6748683c685..738464ccffc 100644
--- a/chromium/ui/message_center/message_center_style.h
+++ b/chromium/ui/message_center/message_center_style.h
@@ -22,6 +22,8 @@ const int kNotificationImageBorderSize = 10;
const int kNotificationPreferredImageWidth = 360;
const int kNotificationPreferredImageHeight = 240;
const int kSettingsIconSize = 16;
+const int kSmallImageSize = 16;
+const int kSmallImagePadding = 4;
// Limits.
const size_t kMaxVisibleMessageCenterNotifications = 100;
@@ -29,6 +31,7 @@ const size_t kMaxVisiblePopupNotifications = 3;
// DIP dimension; H size of the whole card.
const int kNotificationWidth = 360;
+const int kMinScrollViewHeight = 100;
// Colors.
MESSAGE_CENTER_EXPORT extern const SkColor kMessageCenterBorderColor;
@@ -62,6 +65,7 @@ const int kIconBottomPadding = 16; // Minimum non-zero V space between icon
// Text sizes.
const int kTitleFontSize = 14; // For title only.
+const int kEmptyCenterFontSize = 13; // For empty message only.
const int kTitleLineHeight = 20; // In DIPs.
const int kMessageFontSize = 12; // For everything but title.
const int kMessageLineHeight = 18; // In DIPs.
@@ -77,9 +81,10 @@ extern const SkColor kFocusBorderColor; // The focus border.
// Limits.
-// Given the size of an image, returns the rect the image should be displayed
-// in, centered.
-gfx::Size GetImageSizeForWidth(int width, const gfx::Size& image_size);
+// Given the size of an image, returns the size of the properly scaled-up image
+// which fits into |container_size|.
+gfx::Size GetImageSizeForContainerSize(const gfx::Size& container_size,
+ const gfx::Size& image_size);
extern const int kNotificationMaximumImageHeight; // For image notifications.
extern const size_t kNotificationMaximumItems; // For list notifications.
@@ -107,10 +112,9 @@ const SkColor kProgressBarBackgroundColor = SkColorSetRGB(216, 216, 216);
const SkColor kProgressBarSliceColor = SkColorSetRGB(120, 120, 120);
// Line limits.
-const int kTitleLineLimit = 3;
-const int kExperimentalTitleLineLimit = 1;
+const int kMaxTitleLines = 2;
const int kMessageCollapsedLineLimit = 2;
-const int kMessageExpandedLineLimit = 7;
+const int kMessageExpandedLineLimit = 5;
const int kContextMessageLineLimit = 1;
// Around notifications ////////////////////////////////////////////////////////
diff --git a/chromium/ui/message_center/message_center_switches.cc b/chromium/ui/message_center/message_center_switches.cc
deleted file mode 100644
index 8d374f7e29a..00000000000
--- a/chromium/ui/message_center/message_center_switches.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/message_center/message_center_switches.h"
-
-namespace message_center {
-namespace switches {
-
-const char kDisableRichNotifications[] = "disable-rich-notifications";
-const char kEnableRichNotifications[] = "enable-rich-notifications";
-
-const char kEnableExperimentalNotificationUI[] =
- "enable-experimental-notification-ui";
-
-} // namespace switches
-} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_switches.h b/chromium/ui/message_center/message_center_switches.h
deleted file mode 100644
index 7e8158d5b94..00000000000
--- a/chromium/ui/message_center/message_center_switches.h
+++ /dev/null
@@ -1,31 +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_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_
-#define UI_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_
-
-#include "ui/message_center/message_center_export.h"
-
-namespace message_center {
-namespace switches {
-
-// Enables rich templated notifications and NotificationCenter. In ChromeOS,
-// this flag also means the new design of message center bubble and popups.
-// TODO(mukai): Remove this flag when we don't need to provide both of designs
-// anymore (i.e. the new design becomes default and no one complains about it).
-// Note that some classes should be removed and renamed as the result of
-// removing this class.
-// Affected class list:
-// - WebNotificationButtonView2: remove '2' suffix and replace the old one.
-// - WebNotificationButtonViewBase: merge into WebNotificationButtonView.
-MESSAGE_CENTER_EXPORT extern const char kEnableRichNotifications[];
-MESSAGE_CENTER_EXPORT extern const char kDisableRichNotifications[];
-
-// Enables experimental features that we don't want to ship yet.
-MESSAGE_CENTER_EXPORT extern const char kEnableExperimentalNotificationUI[];
-
-} // namespace switches
-} // namespace message_center
-
-#endif // UI_MESSAGE_CENTER_MESSAGE_CENTER_CONSTANTS_H_
diff --git a/chromium/ui/message_center/message_center_tray.cc b/chromium/ui/message_center/message_center_tray.cc
index 58e5868a1e8..671b9797cea 100644
--- a/chromium/ui/message_center/message_center_tray.cc
+++ b/chromium/ui/message_center/message_center_tray.cc
@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_strings.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_tray_delegate.h"
#include "ui/message_center/message_center_types.h"
@@ -15,6 +16,85 @@
namespace message_center {
+namespace {
+
+// Menu constants
+const int kTogglePermissionCommand = 0;
+const int kShowSettingsCommand = 1;
+
+// The model of the context menu for a notification card.
+class NotificationMenuModel : public ui::SimpleMenuModel,
+ public ui::SimpleMenuModel::Delegate {
+ public:
+ NotificationMenuModel(MessageCenterTray* tray,
+ const NotifierId& notifier_id,
+ const base::string16& display_source);
+ virtual ~NotificationMenuModel();
+
+ // Overridden from ui::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ private:
+ MessageCenterTray* tray_;
+ NotifierId notifier_id_;
+ DISALLOW_COPY_AND_ASSIGN(NotificationMenuModel);
+};
+
+NotificationMenuModel::NotificationMenuModel(
+ MessageCenterTray* tray,
+ const NotifierId& notifier_id,
+ const base::string16& display_source)
+ : ui::SimpleMenuModel(this),
+ tray_(tray),
+ notifier_id_(notifier_id) {
+ // Add 'disable notifications' menu item.
+ if (!display_source.empty()) {
+ AddItem(kTogglePermissionCommand,
+ l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_NOTIFIER_DISABLE,
+ display_source));
+ }
+ // Add settings menu item.
+ AddItem(kShowSettingsCommand,
+ l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS));
+}
+
+NotificationMenuModel::~NotificationMenuModel() {
+}
+
+bool NotificationMenuModel::IsCommandIdChecked(int command_id) const {
+ return false;
+}
+
+bool NotificationMenuModel::IsCommandIdEnabled(int command_id) const {
+ return tray_->delegate()->IsContextMenuEnabled();
+}
+
+bool NotificationMenuModel::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void NotificationMenuModel::ExecuteCommand(int command_id, int event_flags) {
+ switch (command_id) {
+ case kTogglePermissionCommand:
+ tray_->message_center()->DisableNotificationsByNotifier(notifier_id_);
+ break;
+ case kShowSettingsCommand:
+ tray_->ShowNotifierSettingsBubble();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace
+
MessageCenterTray::MessageCenterTray(
MessageCenterTrayDelegate* delegate,
message_center::MessageCenter* message_center)
@@ -116,6 +196,13 @@ void MessageCenterTray::ShowNotifierSettingsBubble() {
NotifyMessageCenterTrayChanged();
}
+scoped_ptr<ui::MenuModel> MessageCenterTray::CreateNotificationMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
+ return scoped_ptr<ui::MenuModel>(new NotificationMenuModel(
+ this, notifier_id, display_source));
+}
+
void MessageCenterTray::OnNotificationAdded(
const std::string& notification_id) {
OnMessageCenterChanged();
@@ -146,7 +233,8 @@ void MessageCenterTray::OnNotificationButtonClicked(
}
void MessageCenterTray::OnNotificationDisplayed(
- const std::string& notification_id) {
+ const std::string& notification_id,
+ const DisplaySource source) {
NotifyMessageCenterTrayChanged();
}
diff --git a/chromium/ui/message_center/message_center_tray.h b/chromium/ui/message_center/message_center_tray.h
index fed4eb14337..453941780ae 100644
--- a/chromium/ui/message_center/message_center_tray.h
+++ b/chromium/ui/message_center/message_center_tray.h
@@ -6,9 +6,15 @@
#define UI_MESSAGE_CENTER_MESSAGE_CENTER_TRAY_H_
#include "base/observer_list.h"
+#include "base/strings/string16.h"
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/message_center_tray_delegate.h"
+#include "ui/message_center/notifier_settings.h"
+
+namespace ui {
+class MenuModel;
+}
namespace message_center {
@@ -54,6 +60,11 @@ class MESSAGE_CENTER_EXPORT MessageCenterTray : public MessageCenterObserver {
// Toggles the visibility of the settings view in the message center bubble.
void ShowNotifierSettingsBubble();
+ // Creates a model for the context menu for a notification card.
+ scoped_ptr<ui::MenuModel> CreateNotificationMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source);
+
bool message_center_visible() { return message_center_visible_; }
bool popups_visible() { return popups_visible_; }
MessageCenterTrayDelegate* delegate() { return delegate_; }
@@ -74,7 +85,8 @@ class MESSAGE_CENTER_EXPORT MessageCenterTray : public MessageCenterObserver {
const std::string& notification_id,
int button_index) OVERRIDE;
virtual void OnNotificationDisplayed(
- const std::string& notification_id) OVERRIDE;
+ const std::string& notification_id,
+ const DisplaySource source) OVERRIDE;
virtual void OnQuietModeChanged(bool in_quiet_mode) OVERRIDE;
virtual void OnBlockingStateChanged(NotificationBlocker* blocker) OVERRIDE;
diff --git a/chromium/ui/message_center/message_center_tray_delegate.h b/chromium/ui/message_center/message_center_tray_delegate.h
index bd5c8855d88..d1d31ac23f0 100644
--- a/chromium/ui/message_center/message_center_tray_delegate.h
+++ b/chromium/ui/message_center/message_center_tray_delegate.h
@@ -37,6 +37,9 @@ class MESSAGE_CENTER_EXPORT MessageCenterTrayDelegate {
// Display the notifier settings as a bubble.
virtual bool ShowNotifierSettings() = 0;
+ // Returns true if the context menu for a notification is currently enabled.
+ virtual bool IsContextMenuEnabled() const = 0;
+
// Show a platform-specific UI that informs the user how to open the message
// center.
virtual void DisplayFirstRunBalloon() {}
diff --git a/chromium/ui/message_center/message_center_tray_unittest.cc b/chromium/ui/message_center/message_center_tray_unittest.cc
index f9f10e1807e..993e18879a9 100644
--- a/chromium/ui/message_center/message_center_tray_unittest.cc
+++ b/chromium/ui/message_center/message_center_tray_unittest.cc
@@ -6,9 +6,13 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/models/menu_model.h"
#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
#include "ui/message_center/notification_types.h"
+using base::ASCIIToUTF16;
+
namespace message_center {
namespace {
@@ -16,7 +20,8 @@ class MockDelegate : public MessageCenterTrayDelegate {
public:
MockDelegate()
: show_popups_success_(true),
- show_message_center_success_(true) {}
+ show_message_center_success_(true),
+ enable_context_menu_(true) {}
virtual ~MockDelegate() {}
virtual void OnMessageCenterTrayChanged() OVERRIDE {}
virtual bool ShowPopups() OVERRIDE {
@@ -28,7 +33,10 @@ class MockDelegate : public MessageCenterTrayDelegate {
}
virtual void HideMessageCenter() OVERRIDE {}
virtual bool ShowNotifierSettings() OVERRIDE {
- return false;
+ return true;
+ }
+ virtual bool IsContextMenuEnabled() const OVERRIDE {
+ return enable_context_menu_;
}
virtual MessageCenterTray* GetMessageCenterTray() OVERRIDE {
@@ -37,6 +45,7 @@ class MockDelegate : public MessageCenterTrayDelegate {
bool show_popups_success_;
bool show_message_center_success_;
+ bool enable_context_menu_;
private:
DISALLOW_COPY_AND_ASSIGN(MockDelegate);
@@ -240,4 +249,64 @@ TEST_F(MessageCenterTrayTest, ShowBubbleFails) {
ASSERT_FALSE(message_center_tray_->message_center_visible());
}
+TEST_F(MessageCenterTrayTest, ContextMenuTest) {
+ const std::string id1 = "id1";
+ const std::string id2 = "id2";
+ const std::string id3 = "id3";
+ AddNotification(id1);
+
+ base::string16 display_source = ASCIIToUTF16("www.test.org");
+ NotifierId notifier_id = DummyNotifierId();
+
+ NotifierId notifier_id2(NotifierId::APPLICATION, "sample-app");
+ scoped_ptr<Notification> notification(
+ new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
+ id2,
+ ASCIIToUTF16("Test Web Notification"),
+ ASCIIToUTF16("Notification message body."),
+ gfx::Image(),
+ base::string16() /* empty display source */,
+ notifier_id2,
+ message_center::RichNotificationData(),
+ NULL /* delegate */));
+ message_center_->AddNotification(notification.Pass());
+
+ AddNotification(id3);
+
+ scoped_ptr<ui::MenuModel> model(
+ message_center_tray_->CreateNotificationMenuModel(
+ notifier_id, display_source));
+ EXPECT_EQ(2, model->GetItemCount());
+ const int second_command = model->GetCommandIdAt(1);
+
+ // The second item is to open the settings.
+ EXPECT_TRUE(model->IsEnabledAt(0));
+ EXPECT_TRUE(model->IsEnabledAt(1));
+ model->ActivatedAt(1);
+ EXPECT_TRUE(message_center_tray_->message_center_visible());
+
+ message_center_tray_->HideMessageCenterBubble();
+
+ // The first item is to disable notifications from the notifier id. It also
+ // removes all notifications from the same notifier, i.e. id1 and id3.
+ model->ActivatedAt(0);
+ NotificationList::Notifications notifications =
+ message_center_->GetVisibleNotifications();
+ EXPECT_EQ(1u, notifications.size());
+ EXPECT_EQ(id2, (*notifications.begin())->id());
+
+ // Disables the context menu.
+ delegate_->enable_context_menu_ = false;
+
+ // id2 doesn't have the display source, so it don't have the menu item for
+ // disabling notifications.
+ model = message_center_tray_->CreateNotificationMenuModel(
+ notifier_id2, base::string16());
+ EXPECT_EQ(1, model->GetItemCount());
+ EXPECT_EQ(second_command, model->GetCommandIdAt(0));
+
+ // The command itself is disabled because delegate disables context menu.
+ EXPECT_FALSE(model->IsEnabledAt(0));
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_types.h b/chromium/ui/message_center/message_center_types.h
index 4cfe68e6fad..32f0f136c04 100644
--- a/chromium/ui/message_center/message_center_types.h
+++ b/chromium/ui/message_center/message_center_types.h
@@ -13,7 +13,15 @@ enum Visibility {
// When the message center view is being displayed.
VISIBILITY_MESSAGE_CENTER,
// When the settings view is being displayed.
- VISIBILITY_SETTINGS
+ VISIBILITY_SETTINGS,
+};
+
+// Identifies the source of a displayed notification.
+enum DisplaySource {
+ // Displayed from the message center.
+ DISPLAY_SOURCE_MESSAGE_CENTER = 0,
+ // Displayed as a popup.
+ DISPLAY_SOURCE_POPUP,
};
} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_util.cc b/chromium/ui/message_center/message_center_util.cc
deleted file mode 100644
index 43cd4849418..00000000000
--- a/chromium/ui/message_center/message_center_util.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/message_center/message_center_util.h"
-
-#include "base/command_line.h"
-#include "ui/message_center/message_center_switches.h"
-
-namespace message_center {
-
-// TODO(dimich): remove this function and the kEnableRichNotifications flag
-// when a time period in Canary indicates the new notifications are acceptable
-// for default behavior.
-bool IsRichNotificationEnabled() {
-#if defined(OS_CHROMEOS)
- return true;
-#elif !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(USE_AURA)
- return false;
-#endif
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableRichNotifications)) {
- return false;
- }
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableRichNotifications)) {
- return true;
- }
-
- return true;
-}
-
-bool IsExperimentalNotificationUIEnabled() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableExperimentalNotificationUI);
-}
-
-} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_util.h b/chromium/ui/message_center/message_center_util.h
deleted file mode 100644
index 88ec198430e..00000000000
--- a/chromium/ui/message_center/message_center_util.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_MESSAGE_CENTER_MESSAGE_CENTER_UTIL_H_
-#define UI_MESSAGE_CENTER_MESSAGE_CENTER_UTIL_H_
-
-#include "ui/message_center/message_center_export.h"
-
-namespace message_center {
-
-MESSAGE_CENTER_EXPORT bool IsRichNotificationEnabled();
-
-// If Rich Notificaitons are enabled by default on a platform, run the
-// corresponding tests on that platform.
-#if defined(OS_WIN) || defined(USE_AURA) || defined(OS_MACOSX)
-#define RUN_MESSAGE_CENTER_TESTS 1
-#endif
-
-MESSAGE_CENTER_EXPORT bool IsExperimentalNotificationUIEnabled();
-
-} // namespace message_center
-
-#endif // UI_MESSAGE_CENTER_MESSAGE_CENTER_UTIL_H_
diff --git a/chromium/ui/message_center/notification.cc b/chromium/ui/message_center/notification.cc
index 5e0f1b6d7c3..479beaab130 100644
--- a/chromium/ui/message_center/notification.cc
+++ b/chromium/ui/message_center/notification.cc
@@ -14,13 +14,13 @@ unsigned g_next_serial_number_ = 0;
namespace message_center {
-NotificationItem::NotificationItem(const string16& title,
- const string16& message)
+NotificationItem::NotificationItem(const base::string16& title,
+ const base::string16& message)
: title(title),
message(message) {
}
-ButtonInfo::ButtonInfo(const string16& title)
+ButtonInfo::ButtonInfo(const base::string16& title)
: title(title) {
}
@@ -36,9 +36,9 @@ RichNotificationData::RichNotificationData(const RichNotificationData& other)
: priority(other.priority),
never_timeout(other.never_timeout),
timestamp(other.timestamp),
- expanded_message(other.expanded_message),
context_message(other.context_message),
image(other.image),
+ small_image(other.small_image),
items(other.items),
progress(other.progress),
buttons(other.buttons),
@@ -50,10 +50,10 @@ RichNotificationData::~RichNotificationData() {}
Notification::Notification(NotificationType type,
const std::string& id,
- const string16& title,
- const string16& message,
+ const base::string16& title,
+ const base::string16& message,
const gfx::Image& icon,
- const string16& display_source,
+ const base::string16& display_source,
const NotifierId& notifier_id,
const RichNotificationData& optional_fields,
NotificationDelegate* delegate)
@@ -68,7 +68,6 @@ Notification::Notification(NotificationType type,
optional_fields_(optional_fields),
shown_as_popup_(false),
is_read_(false),
- is_expanded_(false),
delegate_(delegate) {}
Notification::Notification(const Notification& other)
@@ -83,7 +82,6 @@ Notification::Notification(const Notification& other)
optional_fields_(other.optional_fields_),
shown_as_popup_(other.shown_as_popup_),
is_read_(other.is_read_),
- is_expanded_(other.is_expanded_),
delegate_(other.delegate_) {}
Notification& Notification::operator=(const Notification& other) {
@@ -98,7 +96,6 @@ Notification& Notification::operator=(const Notification& other) {
optional_fields_ = other.optional_fields_;
shown_as_popup_ = other.shown_as_popup_;
is_read_ = other.is_read_;
- is_expanded_ = other.is_expanded_;
delegate_ = other.delegate_;
return *this;
@@ -113,7 +110,6 @@ bool Notification::IsRead() const {
void Notification::CopyState(Notification* base) {
shown_as_popup_ = base->shown_as_popup();
is_read_ = base->is_read_;
- is_expanded_ = base->is_expanded();
if (!delegate_.get())
delegate_ = base->delegate();
optional_fields_.never_timeout = base->never_timeout();
diff --git a/chromium/ui/message_center/notification.h b/chromium/ui/message_center/notification.h
index ff6f7d1a142..7a58363e75d 100644
--- a/chromium/ui/message_center/notification.h
+++ b/chromium/ui/message_center/notification.h
@@ -20,17 +20,17 @@
namespace message_center {
struct MESSAGE_CENTER_EXPORT NotificationItem {
- string16 title;
- string16 message;
+ base::string16 title;
+ base::string16 message;
- NotificationItem(const string16& title, const string16& message);
+ NotificationItem(const base::string16& title, const base::string16& message);
};
struct MESSAGE_CENTER_EXPORT ButtonInfo {
- string16 title;
+ base::string16 title;
gfx::Image icon;
- ButtonInfo(const string16& title);
+ ButtonInfo(const base::string16& title);
};
class MESSAGE_CENTER_EXPORT RichNotificationData {
@@ -42,9 +42,9 @@ class MESSAGE_CENTER_EXPORT RichNotificationData {
int priority;
bool never_timeout;
base::Time timestamp;
- string16 expanded_message;
- string16 context_message;
+ base::string16 context_message;
gfx::Image image;
+ gfx::Image small_image;
std::vector<NotificationItem> items;
int progress;
std::vector<ButtonInfo> buttons;
@@ -56,35 +56,40 @@ class MESSAGE_CENTER_EXPORT Notification {
public:
Notification(NotificationType type,
const std::string& id,
- const string16& title,
- const string16& message,
+ const base::string16& title,
+ const base::string16& message,
const gfx::Image& icon,
- const string16& display_source,
+ const base::string16& display_source,
const NotifierId& notifier_id,
const RichNotificationData& optional_fields,
NotificationDelegate* delegate);
Notification(const Notification& other);
- Notification& operator=(const Notification& other);
+
virtual ~Notification();
// Copies the internal on-memory state from |base|, i.e. shown_as_popup,
- // is_read, is_expanded, and never_timeout.
+ // is_read, and never_timeout.
void CopyState(Notification* base);
NotificationType type() const { return type_; }
void set_type(NotificationType type) { type_ = type; }
+ // Uniquely identifies a notification in the message center. For
+ // notification front ends that support multiple profiles, this id should
+ // identify a unique profile + frontend_notification_id combination. You can
+ // Use this id against the MessageCenter interface but not the
+ // NotificationUIManager interface.
const std::string& id() const { return id_; }
- const string16& title() const { return title_; }
- void set_title(const string16& title) { title_ = title; }
+ const base::string16& title() const { return title_; }
+ void set_title(const base::string16& title) { title_ = title; }
- const string16& message() const { return message_; }
- void set_message(const string16& message) { message_ = message; }
+ const base::string16& message() const { return message_; }
+ void set_message(const base::string16& message) { message_ = message; }
// A display string for the source of the notification.
- const string16& display_source() const { return display_source_; }
+ const base::string16& display_source() const { return display_source_; }
const NotifierId& notifier_id() const { return notifier_id_; }
@@ -101,17 +106,10 @@ class MESSAGE_CENTER_EXPORT Notification {
optional_fields_.timestamp = timestamp;
}
- const string16& expanded_message() const {
- return optional_fields_.expanded_message;
- }
- void set_expanded_message(const string16& expanded_message) {
- optional_fields_.expanded_message = expanded_message;
- }
-
- const string16& context_message() const {
+ const base::string16& context_message() const {
return optional_fields_.context_message;
}
- void set_context_message(const string16& context_message) {
+ void set_context_message(const base::string16& context_message) {
optional_fields_.context_message = context_message;
}
@@ -133,6 +131,11 @@ class MESSAGE_CENTER_EXPORT Notification {
const gfx::Image& image() const { return optional_fields_.image; }
void set_image(const gfx::Image& image) { optional_fields_.image = image; }
+ const gfx::Image& small_image() const { return optional_fields_.small_image; }
+ void set_small_image(const gfx::Image& image) {
+ optional_fields_.small_image = image;
+ }
+
// Buttons, with icons fetched asynchronously.
const std::vector<ButtonInfo>& buttons() const {
return optional_fields_.buttons;
@@ -151,10 +154,6 @@ class MESSAGE_CENTER_EXPORT Notification {
bool IsRead() const;
void set_is_read(bool read) { is_read_ = read; }
- // Expanded status in the message center (not the popups).
- bool is_expanded() const { return is_expanded_; }
- void set_is_expanded(bool expanded) { is_expanded_ = expanded; }
-
// 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_; }
@@ -201,19 +200,21 @@ class MESSAGE_CENTER_EXPORT Notification {
const base::Closure& click_callback);
protected:
+ Notification& operator=(const Notification& other);
+
// The type of notification we'd like displayed.
NotificationType type_;
std::string id_;
- string16 title_;
- string16 message_;
+ base::string16 title_;
+ base::string16 message_;
// Image data for the associated icon, used by Ash when available.
gfx::Image icon_;
// The display string for the source of the notification. Could be
// the same as origin_url_, or the name of an extension.
- string16 display_source_;
+ base::string16 display_source_;
private:
NotifierId notifier_id_;
@@ -221,7 +222,6 @@ class MESSAGE_CENTER_EXPORT Notification {
RichNotificationData optional_fields_;
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.
- bool is_expanded_; // True if this has been expanded in the message center.
// A proxy object that allows access back to the JavaScript object that
// represents the notification, for firing events.
diff --git a/chromium/ui/message_center/notification_delegate.cc b/chromium/ui/message_center/notification_delegate.cc
index 899cb2a1056..09ef959dbf0 100644
--- a/chromium/ui/message_center/notification_delegate.cc
+++ b/chromium/ui/message_center/notification_delegate.cc
@@ -6,10 +6,14 @@
namespace message_center {
+// NotificationDelegate:
+
bool NotificationDelegate::HasClickedListener() { return false; }
void NotificationDelegate::ButtonClick(int button_index) {}
+// HandleNotificationClickedDelegate:
+
HandleNotificationClickedDelegate::HandleNotificationClickedDelegate(
const base::Closure& closure)
: closure_(closure) {
@@ -39,4 +43,32 @@ void HandleNotificationClickedDelegate::Click() {
void HandleNotificationClickedDelegate::ButtonClick(int button_index) {
}
+// HandleNotificationButtonClickDelegate:
+
+HandleNotificationButtonClickDelegate::HandleNotificationButtonClickDelegate(
+ const ButtonClickCallback& button_callback)
+ : button_callback_(button_callback) {
+}
+
+HandleNotificationButtonClickDelegate::
+ ~HandleNotificationButtonClickDelegate() {
+}
+
+void HandleNotificationButtonClickDelegate::Display() {
+}
+
+void HandleNotificationButtonClickDelegate::Error() {
+}
+
+void HandleNotificationButtonClickDelegate::Close(bool by_user) {
+}
+
+void HandleNotificationButtonClickDelegate::Click() {
+}
+
+void HandleNotificationButtonClickDelegate::ButtonClick(int button_index) {
+ if (!button_callback_.is_null())
+ button_callback_.Run(button_index);
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/notification_delegate.h b/chromium/ui/message_center/notification_delegate.h
index 475304cc2c4..9c6c8a1c8bc 100644
--- a/chromium/ui/message_center/notification_delegate.h
+++ b/chromium/ui/message_center/notification_delegate.h
@@ -76,6 +76,32 @@ class MESSAGE_CENTER_EXPORT HandleNotificationClickedDelegate
DISALLOW_COPY_AND_ASSIGN(HandleNotificationClickedDelegate);
};
+// A notification delegate which invokes a callback when a notification button
+// has been clicked.
+class MESSAGE_CENTER_EXPORT HandleNotificationButtonClickDelegate
+ : public NotificationDelegate {
+ public:
+ typedef base::Callback<void(int)> ButtonClickCallback;
+
+ explicit HandleNotificationButtonClickDelegate(
+ const ButtonClickCallback& button_callback);
+
+ // message_center::NotificationDelegate overrides:
+ virtual void Display() OVERRIDE;
+ virtual void Error() OVERRIDE;
+ virtual void Close(bool by_user) OVERRIDE;
+ virtual void Click() OVERRIDE;
+ virtual void ButtonClick(int button_index) OVERRIDE;
+
+ protected:
+ virtual ~HandleNotificationButtonClickDelegate();
+
+ private:
+ ButtonClickCallback button_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleNotificationButtonClickDelegate);
+};
+
} // namespace message_center
#endif // UI_MESSAGE_CENTER_NOTIFICATION_DELEGATE_H_
diff --git a/chromium/ui/message_center/notification_delegate_unittest.cc b/chromium/ui/message_center/notification_delegate_unittest.cc
new file mode 100644
index 00000000000..6009fc86ad2
--- /dev/null
+++ b/chromium/ui/message_center/notification_delegate_unittest.cc
@@ -0,0 +1,71 @@
+// 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/message_center/notification_delegate.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace message_center {
+
+class NotificationDelegateTest : public testing::Test {
+ public:
+ NotificationDelegateTest();
+ virtual ~NotificationDelegateTest();
+
+ void ClickCallback();
+
+ int GetClickedCallbackAndReset();
+
+ private:
+ int callback_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationDelegateTest);
+};
+
+NotificationDelegateTest::NotificationDelegateTest() : callback_count_(0) {}
+
+NotificationDelegateTest::~NotificationDelegateTest() {}
+
+void NotificationDelegateTest::ClickCallback() {
+ ++callback_count_;
+}
+
+int NotificationDelegateTest::GetClickedCallbackAndReset() {
+ int result = callback_count_;
+ callback_count_ = 0;
+ return result;
+}
+
+TEST_F(NotificationDelegateTest, ClickedDelegate) {
+ scoped_refptr<HandleNotificationClickedDelegate> delegate(
+ new HandleNotificationClickedDelegate(
+ base::Bind(&NotificationDelegateTest::ClickCallback,
+ base::Unretained(this))));
+
+ EXPECT_TRUE(delegate->HasClickedListener());
+ delegate->Click();
+ EXPECT_EQ(1, GetClickedCallbackAndReset());
+
+ // ButtonClick doesn't call the callback.
+ delegate->ButtonClick(0);
+ EXPECT_EQ(0, GetClickedCallbackAndReset());
+}
+
+TEST_F(NotificationDelegateTest, NullClickedDelegate) {
+ scoped_refptr<HandleNotificationClickedDelegate> delegate(
+ new HandleNotificationClickedDelegate(base::Closure()));
+
+ EXPECT_FALSE(delegate->HasClickedListener());
+ delegate->Click();
+ EXPECT_EQ(0, GetClickedCallbackAndReset());
+
+ delegate->ButtonClick(0);
+ EXPECT_EQ(0, GetClickedCallbackAndReset());
+}
+
+}
diff --git a/chromium/ui/message_center/notification_list.cc b/chromium/ui/message_center/notification_list.cc
index 3ec0bfe2964..eac4345657e 100644
--- a/chromium/ui/message_center/notification_list.cc
+++ b/chromium/ui/message_center/notification_list.cc
@@ -9,8 +9,10 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "ui/gfx/image/image.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_blocker.h"
#include "ui/message_center/notification_types.h"
namespace message_center {
@@ -158,10 +160,6 @@ bool NotificationList::SetNotificationButtonIcon(
return true;
}
-bool NotificationList::HasNotification(const std::string& id) {
- return GetNotification(id) != notifications_.end();
-}
-
bool NotificationList::HasNotificationOfType(const std::string& id,
const NotificationType type) {
Notifications::iterator iter = GetNotification(id);
@@ -250,12 +248,6 @@ void NotificationList::MarkSinglePopupAsDisplayed(const std::string& id) {
(*iter)->set_is_read(true);
}
-void NotificationList::MarkNotificationAsExpanded(const std::string& id) {
- Notifications::iterator iter = GetNotification(id);
- if (iter != notifications_.end())
- (*iter)->set_is_expanded(true);
-}
-
NotificationDelegate* NotificationList::GetNotificationDelegate(
const std::string& id) {
Notifications::iterator iter = GetNotification(id);
@@ -275,6 +267,13 @@ void NotificationList::SetQuietMode(bool quiet_mode) {
}
}
+Notification* NotificationList::GetNotificationById(const std::string& id) {
+ Notifications::iterator iter = GetNotification(id);
+ if (iter != notifications_.end())
+ return *iter;
+ return NULL;
+}
+
NotificationList::Notifications NotificationList::GetVisibleNotifications(
const NotificationBlockers& blockers) const {
Notifications result;
diff --git a/chromium/ui/message_center/notification_list.h b/chromium/ui/message_center/notification_list.h
index 3ea8112eb3e..c07df613f66 100644
--- a/chromium/ui/message_center/notification_list.h
+++ b/chromium/ui/message_center/notification_list.h
@@ -9,28 +9,30 @@
#include <set>
#include <string>
-#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/native_widget_types.h"
+#include "base/gtest_prod_util.h"
#include "ui/message_center/message_center_export.h"
-#include "ui/message_center/notification.h"
#include "ui/message_center/notification_blocker.h"
#include "ui/message_center/notification_types.h"
namespace base {
class DictionaryValue;
+class TimeDelta;
}
-namespace message_center {
+namespace gfx {
+class Image;
+}
-class NotificationDelegate;
+namespace message_center {
namespace test {
class NotificationListTest;
}
+class Notification;
+class NotificationDelegate;
+struct NotifierId;
+
// Comparers used to auto-sort the lists of Notifications.
struct MESSAGE_CENTER_EXPORT ComparePriorityTimestampSerial {
bool operator()(Notification* n1, Notification* n2);
@@ -82,9 +84,6 @@ class MESSAGE_CENTER_EXPORT NotificationList {
int button_index,
const gfx::Image& image);
- // Returns true if |id| matches a notification in the list.
- bool HasNotification(const std::string& id);
-
// Returns true if |id| matches a notification in the list and that
// notification's type matches the given type.
bool HasNotificationOfType(const std::string& id,
@@ -112,9 +111,6 @@ class MESSAGE_CENTER_EXPORT NotificationList {
// Marks a specific popup item as displayed.
void MarkSinglePopupAsDisplayed(const std::string& id);
- // Marks the specified notification as expanded in the notification center.
- void MarkNotificationAsExpanded(const std::string& id);
-
NotificationDelegate* GetNotificationDelegate(const std::string& id);
bool quiet_mode() const { return quiet_mode_; }
@@ -126,6 +122,10 @@ class MESSAGE_CENTER_EXPORT NotificationList {
// specified time-delta from now.
void EnterQuietModeWithExpire(const base::TimeDelta& expires_in);
+ // Returns the notification with the corresponding id. If not found, returns
+ // NULL. Notification instance is owned by this list.
+ Notification* GetNotificationById(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 10c843fa9ae..637e95afaf5 100644
--- a/chromium/ui/message_center/notification_list_unittest.cc
+++ b/chromium/ui/message_center/notification_list_unittest.cc
@@ -15,6 +15,8 @@
#include "ui/message_center/notification_types.h"
#include "ui/message_center/notifier_settings.h"
+using base::UTF8ToUTF16;
+
namespace message_center {
class NotificationListTest : public testing::Test {
@@ -134,9 +136,9 @@ TEST_F(NotificationListTest, Basic) {
EXPECT_EQ(2u, notification_list()->UnreadCount(blockers()));
EXPECT_TRUE(notification_list()->HasPopupNotifications(blockers()));
- EXPECT_TRUE(notification_list()->HasNotification(id0));
- EXPECT_TRUE(notification_list()->HasNotification(id1));
- EXPECT_FALSE(notification_list()->HasNotification(id1 + "foo"));
+ EXPECT_TRUE(notification_list()->GetNotificationById(id0));
+ EXPECT_TRUE(notification_list()->GetNotificationById(id1));
+ EXPECT_FALSE(notification_list()->GetNotificationById(id1 + "foo"));
EXPECT_EQ(2u, GetPopupCounts());
diff --git a/chromium/ui/message_center/notifier_settings.cc b/chromium/ui/message_center/notifier_settings.cc
index 0e6fe9b0d39..26546118b9e 100644
--- a/chromium/ui/message_center/notifier_settings.cc
+++ b/chromium/ui/message_center/notifier_settings.cc
@@ -51,7 +51,7 @@ bool NotifierId::operator<(const NotifierId& other) const {
}
Notifier::Notifier(const NotifierId& notifier_id,
- const string16& name,
+ const base::string16& name,
bool enabled)
: notifier_id(notifier_id),
name(name),
@@ -62,8 +62,8 @@ Notifier::~Notifier() {
}
NotifierGroup::NotifierGroup(const gfx::Image& icon,
- const string16& name,
- const string16& login_info,
+ const base::string16& name,
+ const base::string16& login_info,
size_t index)
: icon(icon), name(name), login_info(login_info), index(index) {}
diff --git a/chromium/ui/message_center/notifier_settings.h b/chromium/ui/message_center/notifier_settings.h
index 7fe859a8d38..b0b11071c23 100644
--- a/chromium/ui/message_center/notifier_settings.h
+++ b/chromium/ui/message_center/notifier_settings.h
@@ -13,8 +13,7 @@
#include "ui/message_center/message_center_export.h"
#include "url/gurl.h"
-FORWARD_DECLARE_TEST(MessageCenterTrayBridgeTest,
- StatusItemOnlyAfterFirstNotification);
+class MessageCenterTrayBridgeTest;
namespace ash {
class WebNotificationTrayTest;
@@ -67,14 +66,13 @@ struct MESSAGE_CENTER_EXPORT NotifierId {
std::string profile_id;
private:
+ friend class ::MessageCenterTrayBridgeTest;
friend class MessageCenterTrayTest;
friend class test::MessagePopupCollectionTest;
friend class NotificationControllerTest;
friend class PopupCollectionTest;
friend class TrayViewControllerTest;
friend class ash::WebNotificationTrayTest;
- FRIEND_TEST_ALL_PREFIXES(::MessageCenterTrayBridgeTest,
- StatusItemOnlyAfterFirstNotification);
FRIEND_TEST_ALL_PREFIXES(PopupControllerTest, Creation);
FRIEND_TEST_ALL_PREFIXES(NotificationListTest, UnreadCountNoNegative);
FRIEND_TEST_ALL_PREFIXES(NotificationListTest, TestHasNotificationOfType);
@@ -86,14 +84,16 @@ struct MESSAGE_CENTER_EXPORT NotifierId {
// The struct to hold the information of notifiers. The information will be
// used by NotifierSettingsView.
struct MESSAGE_CENTER_EXPORT Notifier {
- Notifier(const NotifierId& notifier_id, const string16& name, bool enabled);
+ Notifier(const NotifierId& notifier_id,
+ const base::string16& name,
+ bool enabled);
~Notifier();
NotifierId notifier_id;
// The human-readable name of the notifier such like the extension name.
// It can be empty.
- string16 name;
+ base::string16 name;
// True if the source is allowed to send notifications. True is default.
bool enabled;
@@ -107,8 +107,8 @@ struct MESSAGE_CENTER_EXPORT Notifier {
struct MESSAGE_CENTER_EXPORT NotifierGroup {
NotifierGroup(const gfx::Image& icon,
- const string16& name,
- const string16& login_info,
+ const base::string16& name,
+ const base::string16& login_info,
size_t index);
~NotifierGroup();
@@ -116,10 +116,10 @@ struct MESSAGE_CENTER_EXPORT NotifierGroup {
const gfx::Image icon;
// Display name of a notifier group.
- const string16 name;
+ const base::string16 name;
// More display information about the notifier group.
- string16 login_info;
+ base::string16 login_info;
// Unique identifier for the notifier group so that they can be selected in
// the UI.
@@ -139,6 +139,10 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsObserver {
// Called when any change happens to the set of notifier groups.
virtual void NotifierGroupChanged() = 0;
+
+ // Called when a notifier is enabled or disabled.
+ virtual void NotifierEnabledChanged(const NotifierId& notifier_id,
+ bool enabled) = 0;
};
// A class used by NotifierSettingsView to integrate with a setting system
diff --git a/chromium/ui/message_center/views/bounded_label.cc b/chromium/ui/message_center/views/bounded_label.cc
index 2b8423b6865..99c66f80b77 100644
--- a/chromium/ui/message_center/views/bounded_label.cc
+++ b/chromium/ui/message_center/views/bounded_label.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/text_elider.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/controls/label.h"
namespace {
@@ -24,7 +25,7 @@ namespace message_center {
// InnerBoundedLabel is a views::Label subclass that does all of the work for
// BoundedLabel. It is kept private to prevent outside code from calling a
-// number of views::Label methods like setFont() that break BoundedLabel's
+// number of views::Label methods like SetFontList() that break BoundedLabel's
// caching but can't be overridden.
//
// TODO(dharcourt): Move the line limiting functionality to views::Label to make
@@ -40,7 +41,10 @@ class InnerBoundedLabel : public views::Label {
// Pass in a -1 width to use the preferred width, a -1 limit to skip limits.
int GetLinesForWidthAndLimit(int width, int limit);
gfx::Size GetSizeForWidthAndLines(int width, int lines);
- std::vector<string16> GetWrappedText(int width, int lines);
+ std::vector<base::string16> GetWrappedText(int width, int lines);
+
+ // Overridden from views::Label.
+ virtual void SetText(const base::string16& text) OVERRIDE;
protected:
// Overridden from views::Label.
@@ -57,7 +61,7 @@ class InnerBoundedLabel : public views::Label {
void SetCachedSize(std::pair<int, int> width_and_lines, gfx::Size size);
const BoundedLabel* owner_; // Weak reference.
- string16 wrapped_text_;
+ base::string16 wrapped_text_;
int wrapped_text_width_;
int wrapped_text_lines_;
std::map<int, int> lines_cache_;
@@ -108,8 +112,8 @@ gfx::Size InnerBoundedLabel::GetSizeForWidthAndLines(int width, int lines) {
int text_width = (width < 0) ? std::numeric_limits<int>::max() :
std::max(width - insets.width(), 0);
int text_height = std::numeric_limits<int>::max();
- std::vector<string16> wrapped = GetWrappedText(text_width, lines);
- gfx::Canvas::SizeStringInt(JoinString(wrapped, '\n'), font(),
+ std::vector<base::string16> wrapped = GetWrappedText(text_width, lines);
+ gfx::Canvas::SizeStringInt(JoinString(wrapped, '\n'), font_list(),
&text_width, &text_height,
owner_->GetLineHeight(),
GetTextFlags());
@@ -120,28 +124,25 @@ gfx::Size InnerBoundedLabel::GetSizeForWidthAndLines(int width, int lines) {
return size;
}
-std::vector<string16> InnerBoundedLabel::GetWrappedText(int width, int lines) {
+std::vector<base::string16> InnerBoundedLabel::GetWrappedText(int width,
+ int lines) {
// Short circuit simple case.
if (width == 0 || lines == 0)
- return std::vector<string16>();
+ return std::vector<base::string16>();
// Restrict line limit to ensure (lines + 1) * line_height <= INT_MAX and
// use it to calculate a reasonable text height.
int height = std::numeric_limits<int>::max();
if (lines > 0) {
- int line_height = std::max(font().GetHeight(), 2); // At least 2 pixels.
+ int line_height = std::max(font_list().GetHeight(),
+ 2); // At least 2 pixels.
int max_lines = std::numeric_limits<int>::max() / line_height - 1;
lines = std::min(lines, max_lines);
height = (lines + 1) * line_height;
}
- // Try to ensure that the width is no smaller than the width of the text's
- // characters to avoid the http://crbug.com/237700 infinite loop.
- // TODO(dharcourt): Remove when http://crbug.com/237700 is fixed.
- width = std::max(width, 2 * font().GetStringWidth(UTF8ToUTF16("W")));
-
// Wrap, using INT_MAX for -1 widths that indicate no wrapping.
- std::vector<string16> wrapped;
+ std::vector<base::string16> wrapped;
gfx::ElideRectangleText(text(), font_list(),
(width < 0) ? std::numeric_limits<int>::max() : width,
height, gfx::WRAP_LONG_WORDS, &wrapped);
@@ -151,9 +152,10 @@ std::vector<string16> InnerBoundedLabel::GetWrappedText(int width, int lines) {
// Add an ellipsis to the last line. If this ellipsis makes the last line
// too wide, that line will be further elided by the gfx::ElideText below,
// so for example "ABC" could become "ABC..." and then "AB...".
- string16 last = wrapped[lines - 1] + UTF8ToUTF16(gfx::kEllipsis);
- if (width > 0 && font().GetStringWidth(last) > width)
- last = gfx::ElideText(last, font(), width, gfx::ELIDE_AT_END);
+ base::string16 last =
+ wrapped[lines - 1] + base::UTF8ToUTF16(gfx::kEllipsis);
+ if (width > 0 && gfx::GetStringWidth(last, font_list()) > width)
+ last = gfx::ElideText(last, font_list(), width, gfx::ELIDE_TAIL);
wrapped.resize(lines - 1);
wrapped.push_back(last);
}
@@ -184,6 +186,11 @@ void InnerBoundedLabel::OnPaint(gfx::Canvas* canvas) {
}
}
+void InnerBoundedLabel::SetText(const base::string16& text) {
+ views::Label::SetText(text);
+ ClearCaches();
+}
+
int InnerBoundedLabel::GetTextFlags() {
int flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAK;
@@ -191,8 +198,11 @@ int InnerBoundedLabel::GetTextFlags() {
if (SkColorGetA(background_color()) != 0xFF)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- if (directionality_mode() ==
- views::Label::AUTO_DETECT_DIRECTIONALITY) {
+ if (directionality_mode() == gfx::DIRECTIONALITY_FORCE_LTR) {
+ flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
+ } else if (directionality_mode() == gfx::DIRECTIONALITY_FORCE_RTL) {
+ flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
+ } else if (directionality_mode() == gfx::DIRECTIONALITY_FROM_TEXT) {
base::i18n::TextDirection direction =
base::i18n::GetFirstStrongCharacterDirection(text());
if (direction == base::i18n::RIGHT_TO_LEFT)
@@ -257,14 +267,15 @@ void InnerBoundedLabel::SetCachedSize(std::pair<int, int> width_and_lines,
// BoundedLabel ///////////////////////////////////////////////////////////
-BoundedLabel::BoundedLabel(const string16& text, const gfx::FontList& font_list)
+BoundedLabel::BoundedLabel(const base::string16& text,
+ const gfx::FontList& font_list)
: line_limit_(-1) {
label_.reset(new InnerBoundedLabel(*this));
label_->SetFontList(font_list);
label_->SetText(text);
}
-BoundedLabel::BoundedLabel(const string16& text)
+BoundedLabel::BoundedLabel(const base::string16& text)
: line_limit_(-1) {
label_.reset(new InnerBoundedLabel(*this));
label_->SetText(text);
@@ -286,6 +297,10 @@ void BoundedLabel::SetLineLimit(int lines) {
line_limit_ = std::max(lines, -1);
}
+void BoundedLabel::SetText(const base::string16& text) {
+ label_->SetText(text);
+}
+
int BoundedLabel::GetLineHeight() const {
return label_->line_height();
}
@@ -307,25 +322,25 @@ int BoundedLabel::GetBaseline() const {
return label_->GetBaseline();
}
-gfx::Size BoundedLabel::GetPreferredSize() {
+gfx::Size BoundedLabel::GetPreferredSize() const {
return visible() ? label_->GetSizeForWidthAndLines(-1, -1) : gfx::Size();
}
-int BoundedLabel::GetHeightForWidth(int width) {
+int BoundedLabel::GetHeightForWidth(int width) const {
return visible() ?
label_->GetSizeForWidthAndLines(width, line_limit_).height() : 0;
}
-void BoundedLabel::Paint(gfx::Canvas* canvas) {
+void BoundedLabel::Paint(gfx::Canvas* canvas, const views::CullSet& cull_set) {
if (visible())
- label_->Paint(canvas);
+ label_->Paint(canvas, cull_set);
}
-bool BoundedLabel::HitTestRect(const gfx::Rect& rect) const {
- return label_->HitTestRect(rect);
+bool BoundedLabel::CanProcessEventsWithinSubtree() const {
+ return label_->CanProcessEventsWithinSubtree();
}
-void BoundedLabel::GetAccessibleState(ui::AccessibleViewState* state) {
+void BoundedLabel::GetAccessibleState(ui::AXViewState* state) {
label_->GetAccessibleState(state);
}
@@ -338,7 +353,7 @@ void BoundedLabel::OnNativeThemeChanged(const ui::NativeTheme* theme) {
label_->SetNativeTheme(theme);
}
-string16 BoundedLabel::GetWrappedTextForTest(int width, int lines) {
+base::string16 BoundedLabel::GetWrappedTextForTest(int width, int lines) {
return JoinString(label_->GetWrappedText(width, lines), '\n');
}
diff --git a/chromium/ui/message_center/views/bounded_label.h b/chromium/ui/message_center/views/bounded_label.h
index d6b2f49a519..9a9e6d4bc4c 100644
--- a/chromium/ui/message_center/views/bounded_label.h
+++ b/chromium/ui/message_center/views/bounded_label.h
@@ -33,13 +33,14 @@ class BoundedLabelTest;
// bounded_label.cc file for details.
class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View {
public:
- BoundedLabel(const string16& text, const gfx::FontList& font_list);
- BoundedLabel(const string16& text);
+ BoundedLabel(const base::string16& text, const gfx::FontList& font_list);
+ BoundedLabel(const base::string16& text);
virtual ~BoundedLabel();
void SetColors(SkColor textColor, SkColor backgroundColor);
void SetLineHeight(int height); // Pass in 0 for default height.
void SetLineLimit(int lines); // Pass in -1 for no limit.
+ void SetText(const base::string16& text); // Additionally clears caches.
int GetLineHeight() const;
int GetLineLimit() const;
@@ -48,13 +49,14 @@ class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View {
int GetLinesForWidthAndLimit(int width, int limit);
gfx::Size GetSizeForWidthAndLines(int width, int lines);
- // Overridden from views::View.
+ // views::View:
virtual int GetBaseline() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
+ virtual void Paint(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// Overridden from views::View.
@@ -64,7 +66,7 @@ class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View {
private:
friend class test::BoundedLabelTest;
- string16 GetWrappedTextForTest(int width, int lines);
+ base::string16 GetWrappedTextForTest(int width, int lines);
scoped_ptr<InnerBoundedLabel> label_;
int line_limit_;
diff --git a/chromium/ui/message_center/views/bounded_label_unittest.cc b/chromium/ui/message_center/views/bounded_label_unittest.cc
index bdfb0aceeb6..90452e2e1e3 100644
--- a/chromium/ui/message_center/views/bounded_label_unittest.cc
+++ b/chromium/ui/message_center/views/bounded_label_unittest.cc
@@ -23,9 +23,9 @@ namespace test {
class BoundedLabelTest : public testing::Test {
public:
BoundedLabelTest() {
- digit_pixels_ = gfx::GetStringWidth(UTF8ToUTF16("0"), font_list_);
- space_pixels_ = gfx::GetStringWidth(UTF8ToUTF16(" "), font_list_);
- ellipsis_pixels_ = gfx::GetStringWidth(UTF8ToUTF16("\xE2\x80\xA6"),
+ digit_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16("0"), font_list_);
+ space_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16(" "), font_list_);
+ ellipsis_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16("\xE2\x80\xA6"),
font_list_);
}
@@ -35,10 +35,10 @@ class BoundedLabelTest : public testing::Test {
// with an ellipses character (UTF8 "\xE2\x80\xA6") and returns a string16
// with the results. This allows test strings to be specified as ASCII const
// char* strings, making tests more readable and easier to write.
- string16 ToString(const char* string) {
- const string16 periods = UTF8ToUTF16("...");
- const string16 ellipses = UTF8ToUTF16("\xE2\x80\xA6");
- string16 result = UTF8ToUTF16(string);
+ base::string16 ToString(const char* string) {
+ const base::string16 periods = base::UTF8ToUTF16("...");
+ const base::string16 ellipses = base::UTF8ToUTF16("\xE2\x80\xA6");
+ base::string16 result = base::UTF8ToUTF16(string);
ReplaceSubstringsAfterOffset(&result, 0, periods, ellipses);
return result;
}
@@ -58,7 +58,7 @@ class BoundedLabelTest : public testing::Test {
}
// Exercise BounderLabel::GetWrappedText() using the fixture's test label.
- string16 GetWrappedText(int width) {
+ base::string16 GetWrappedText(int width) {
return label_->GetWrappedTextForTest(width, lines_);
}
@@ -71,7 +71,7 @@ class BoundedLabelTest : public testing::Test {
protected:
// Creates a label to test with. Returns this fixture, which can be used to
// test the newly created label using the exercise methods above.
- BoundedLabelTest& Label(string16 text, int lines) {
+ BoundedLabelTest& Label(base::string16 text, int lines) {
lines_ = lines;
label_.reset(new BoundedLabel(text, font_list_));
label_->SetLineLimit(lines_);
diff --git a/chromium/ui/message_center/views/constants.h b/chromium/ui/message_center/views/constants.h
index d03ec7f0b79..f2995dd45b5 100644
--- a/chromium/ui/message_center/views/constants.h
+++ b/chromium/ui/message_center/views/constants.h
@@ -31,8 +31,7 @@ const int kButtonTitleTopPadding = 0;
// Character limits: Displayed text will be subject to the line limits above,
// but we also remove trailing characters from text to reduce processing cost.
// Character limit = pixels per line * line limit / min. pixels per character.
-const size_t kTitleCharacterLimit =
- message_center::kNotificationWidth * message_center::kTitleLineLimit / 4;
+const int kMinPixelsPerTitleCharacter = 4;
const size_t kMessageCharacterLimit =
message_center::kNotificationWidth *
message_center::kMessageExpandedLineLimit / 3;
diff --git a/chromium/ui/message_center/views/group_view.cc b/chromium/ui/message_center/views/group_view.cc
deleted file mode 100644
index 384c2d2e7b4..00000000000
--- a/chromium/ui/message_center/views/group_view.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/message_center/views/group_view.h"
-
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_resources.h"
-#include "grit/ui_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/layout.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/gfx/text_elider.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_tray.h"
-#include "ui/message_center/message_center_util.h"
-#include "ui/message_center/notification.h"
-#include "ui/message_center/views/bounded_label.h"
-#include "ui/message_center/views/constants.h"
-#include "ui/message_center/views/notification_button.h"
-#include "ui/message_center/views/proportional_image_view.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
-namespace {
-
-// static
-views::Border* MakeTextBorder(int padding, int top, int bottom) {
- // Split the padding between the top and the bottom, then add the extra space.
- return views::Border::CreateEmptyBorder(padding / 2 + top,
- message_center::kTextLeftPadding,
- (padding + 1) / 2 + bottom,
- message_center::kTextRightPadding);
-}
-
-} // namespace
-
-namespace message_center {
-
-// GroupView ////////////////////////////////////////////////////////////
-
-GroupView::GroupView(MessageCenterController* controller,
- const NotifierId& notifier_id,
- const Notification& last_notification,
- const gfx::ImageSkia& group_icon,
- int group_size)
- : MessageView(this,
- last_notification.id(),
- notifier_id,
- last_notification.display_source()),
- controller_(controller),
- notifier_id_(notifier_id),
- display_source_(last_notification.display_source()),
- group_icon_(group_icon),
- group_size_(group_size),
- last_notification_id_(last_notification.id()),
- background_view_(NULL),
- top_view_(NULL),
- bottom_view_(NULL),
- title_view_(NULL),
- message_view_(NULL),
- context_message_view_(NULL),
- icon_view_(NULL)
-{
- std::vector<string16> accessible_lines;
- // TODO (dimich): move to MessageView
- // Create the opaque background that's above the view's shadow.
- background_view_ = new views::View();
- background_view_->set_background(
- views::Background::CreateSolidBackground(
- message_center::kNotificationBackgroundColor));
-
- // 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.
- top_view_ = new views::View();
- top_view_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
- top_view_->set_border(views::Border::CreateEmptyBorder(
- kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0));
-
- const gfx::FontList default_label_font_list = views::Label().font_list();
-
- // Create the title view if appropriate.
- const gfx::FontList& font_list =
- default_label_font_list.DeriveFontListWithSizeDelta(2);
- int padding = kTitleLineHeight - font_list.GetHeight();
-
- title_view_ = new BoundedLabel(
- gfx::TruncateString(string16(last_notification.title()),
- kTitleCharacterLimit),
- font_list);
- accessible_lines.push_back(last_notification.title());
- title_view_->SetLineHeight(kTitleLineHeight);
- title_view_->SetLineLimit(message_center::kTitleLineLimit);
- title_view_->SetColors(message_center::kRegularTextColor,
- kRegularTextBackgroundColor);
- title_view_->set_border(MakeTextBorder(padding, 3, 0));
- top_view_->AddChildView(title_view_);
-
- // Create the message view if appropriate.
- if (!last_notification.message().empty()) {
- int padding = kMessageLineHeight - default_label_font_list.GetHeight();
- message_view_ = new BoundedLabel(
- gfx::TruncateString(last_notification.message(),
- kMessageCharacterLimit));
- message_view_->SetLineHeight(kMessageLineHeight);
- message_view_->SetColors(message_center::kRegularTextColor,
- kDimTextBackgroundColor);
- message_view_->set_border(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(message_view_);
- accessible_lines.push_back(last_notification.message());
- }
-
- // Create the context message view if appropriate.
- if (!last_notification.context_message().empty()) {
- int padding = kMessageLineHeight - default_label_font_list.GetHeight();
- context_message_view_ = new BoundedLabel(gfx::TruncateString(
- last_notification.context_message(), kContextMessageCharacterLimit),
- default_label_font_list);
- context_message_view_->SetLineLimit(
- message_center::kContextMessageLineLimit);
- context_message_view_->SetLineHeight(kMessageLineHeight);
- context_message_view_->SetColors(message_center::kDimTextColor,
- kContextTextBackgroundColor);
- context_message_view_->set_border(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(context_message_view_);
- accessible_lines.push_back(last_notification.context_message());
- }
-
- // Create the notification icon view.
- icon_view_ =
- new ProportionalImageView(last_notification.icon().AsImageSkia());
- icon_view_->set_background(views::Background::CreateSolidBackground(
- kIconBackgroundColor));
-
- // Create the bottom_view_, which collects into a vertical box all content
- // below the notification icon except for the expandGroup button.
- bottom_view_ = new views::View();
- bottom_view_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
- // Create "N more.." action button
- views::View* separator = new views::ImageView();
- separator->set_border(views::Border::CreateSolidSidedBorder(
- 1, 0, 0, 0, kButtonSeparatorColor));
- bottom_view_->AddChildView(separator);
- more_button_ = new NotificationButton(this);
- string16 button_title =
- l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_MORE_FROM,
- base::IntToString16(group_size_),
- display_source_);
- more_button_->SetTitle(button_title);
- more_button_->SetIcon(group_icon_);
- bottom_view_->AddChildView(more_button_);
-
- // Put together the different content and control views. Layering those allows
- // for proper layout logic and it also allows the close button to
- // overlap the content as needed to provide large enough click and touch area.
- AddChildView(background_view_);
- AddChildView(top_view_);
- AddChildView(icon_view_);
- AddChildView(bottom_view_);
- AddChildView(close_button());
- set_accessible_name(JoinString(accessible_lines, '\n'));
-}
-
-GroupView::~GroupView() {
-}
-
-gfx::Size GroupView::GetPreferredSize() {
- int top_width = top_view_->GetPreferredSize().width();
- int bottom_width = bottom_view_->GetPreferredSize().width();
- int preferred_width = std::max(top_width, bottom_width) + GetInsets().width();
- return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
-}
-
-int GroupView::GetHeightForWidth(int width) {
- int content_width = width - GetInsets().width();
- int top_height = top_view_->GetHeightForWidth(content_width);
- int bottom_height = bottom_view_->GetHeightForWidth(content_width);
- int content_height = std::max(top_height, kIconSize) + bottom_height;
-
- // Adjust the height to make sure there is at least 16px of space below the
- // icon if there is any space there (<http://crbug.com/232966>).
- if (content_height > kIconSize)
- content_height = std::max(content_height,
- kIconSize + message_center::kIconBottomPadding);
-
- return content_height + GetInsets().height();
-}
-
-void GroupView::Layout() {
- gfx::Insets insets = GetInsets();
- int content_width = width() - insets.width();
- int content_right = width() - insets.right();
-
- // Background.
- background_view_->SetBounds(insets.left(), insets.top(),
- content_width, height() - insets.height());
-
- // Top views.
- int top_height = top_view_->GetHeightForWidth(content_width);
- top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height);
-
- // Icon.
- icon_view_->SetBounds(insets.left(), insets.top(), kIconSize, kIconSize);
-
- // Bottom views.
- int bottom_y = insets.top() + std::max(top_height, kIconSize);
- int bottom_height = bottom_view_->GetHeightForWidth(content_width);
- bottom_view_->SetBounds(insets.left(), bottom_y,
- content_width, bottom_height);
-
- // Close button.
- gfx::Size close_size(close_button()->GetPreferredSize());
- close_button()->SetBounds(content_right - close_size.width(), insets.top(),
- close_size.width(), close_size.height());
-}
-
-void GroupView::OnFocus() {
- MessageView::OnFocus();
- ScrollRectToVisible(GetLocalBounds());
-}
-
-gfx::NativeCursor GroupView::GetCursor(const ui::MouseEvent& event) {
-// If we ever have non-Aura views environment, this will fail compilation.
-#if defined(USE_AURA)
- return ui::kCursorHand;
-#endif
-}
-
-void GroupView::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (sender == more_button_) {
- controller_->ExpandGroup(notifier_id_);
- return;
- }
- // Let the superclass handle anything other than action buttons.
- // Warning: This may cause the GroupView itself to be deleted,
- // so don't do anything afterwards.
- MessageView::ButtonPressed(sender, event);
-}
-
-void GroupView::ClickOnNotification(const std::string& notification_id) {
- controller_->GroupBodyClicked(notification_id);
-}
-
-void GroupView::RemoveNotification(const std::string& notification_id,
- bool by_user) {
- controller_->RemoveGroup(notifier_id_);
-}
-
-void GroupView::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- controller_->DisableNotificationsFromThisSource(notifier_id);
-}
-
-void GroupView::ShowNotifierSettingsBubble() {
- controller_->ShowNotifierSettingsBubble();
-}
-
-} // namespace message_center
diff --git a/chromium/ui/message_center/views/group_view.h b/chromium/ui/message_center/views/group_view.h
deleted file mode 100644
index d2746a2546c..00000000000
--- a/chromium/ui/message_center/views/group_view.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_MESSAGE_CENTER_VIEWS_GROUP_VIEW_H_
-#define UI_MESSAGE_CENTER_VIEWS_GROUP_VIEW_H_
-
-#include "ui/gfx/image/image_skia.h"
-#include "ui/message_center/views/message_center_controller.h"
-#include "ui/message_center/views/message_center_view.h"
-#include "ui/message_center/views/message_view.h"
-
-namespace message_center {
-
-class BoundedLabel;
-class MessageCenter;
-class NotificationButton;
-
-// View that displays a placeholder representing several notifications and a
-// button to expand it into a set of individual notifications.
-class GroupView : public MessageView, public MessageViewController {
- public:
- // The group view currently shows the latest notificaiton w/o buttons
- // and a single button like "N more from XYZ".
- // Each GroupView has a notifier_id which it uses to report clicks and other
- // user actions to Client.
- GroupView(MessageCenterController* controller,
- const NotifierId& notifier_id,
- const Notification& last_notification,
- const gfx::ImageSkia& group_icon,
- int group_size);
-
- virtual ~GroupView();
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
-
- // Overridden from MessageView:
- virtual void ButtonPressed(views::Button* sender,
- const ui::Event& event) OVERRIDE;
-
- // Overridden from MessageViewController:
- virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
- virtual void RemoveNotification(const std::string& notification_id,
- bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
-
- private:
- MessageCenterController* controller_; // Weak, controls lifetime of views.
- NotifierId notifier_id_;
- string16 display_source_;
- gfx::ImageSkia group_icon_;
- int group_size_;
- std::string last_notification_id_;
-
- // Weak references to GroupView descendants owned by their parents.
- views::View* background_view_;
- views::View* top_view_;
- views::View* bottom_view_;
- BoundedLabel* title_view_;
- BoundedLabel* message_view_;
- BoundedLabel* context_message_view_;
- views::View* icon_view_;
- NotificationButton* more_button_;
-
- DISALLOW_COPY_AND_ASSIGN(GroupView);
-};
-
-} // namespace message_center
-
-#endif // UI_MESSAGE_CENTER_VIEWS_GROUP_VIEW_H_
diff --git a/chromium/ui/message_center/views/message_bubble_base.cc b/chromium/ui/message_center/views/message_bubble_base.cc
index e517c4af24d..c230c2d04ce 100644
--- a/chromium/ui/message_center/views/message_bubble_base.cc
+++ b/chromium/ui/message_center/views/message_bubble_base.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_util.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
diff --git a/chromium/ui/message_center/views/message_center_bubble.cc b/chromium/ui/message_center/views/message_center_bubble.cc
index 5886531b2db..ed93d7fa0c8 100644
--- a/chromium/ui/message_center/views/message_center_bubble.cc
+++ b/chromium/ui/message_center/views/message_center_bubble.cc
@@ -4,8 +4,9 @@
#include "ui/message_center/views/message_center_bubble.h"
+#include "grit/ui_strings.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_util.h"
#include "ui/message_center/views/message_center_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
@@ -21,7 +22,7 @@ class ContentsView : public views::View {
virtual ~ContentsView();
// Overridden from views::View:
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
protected:
// Overridden from views::View:
@@ -42,7 +43,7 @@ ContentsView::ContentsView(MessageCenterBubble* bubble, views::View* contents)
ContentsView::~ContentsView() {
}
-int ContentsView::GetHeightForWidth(int width) {
+int ContentsView::GetHeightForWidth(int width) const {
DCHECK_EQ(1, child_count());
int contents_width = std::max(width - GetInsets().width(), 0);
int contents_height = child_at(0)->GetHeightForWidth(contents_width);
@@ -63,7 +64,8 @@ MessageCenterBubble::MessageCenterBubble(MessageCenter* message_center,
: MessageBubbleBase(message_center, tray),
message_center_view_(NULL),
initially_settings_visible_(false),
- first_item_has_no_margin_(first_item_has_no_margin) {
+ first_item_has_no_margin_(first_item_has_no_margin),
+ title_(l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_TITLE)) {
}
MessageCenterBubble::~MessageCenterBubble() {
@@ -97,8 +99,9 @@ void MessageCenterBubble::InitializeContents(
tray(),
max_height(),
initially_settings_visible_,
- false /* MessageCenterBubble should be used only on ChromeOS.
- Message center is never shown top down in ChromeOS. */);
+ false, /* MessageCenterBubble should be used only on ChromeOS.
+ Message center is never shown top down in ChromeOS. */
+ title_);
bubble_view()->AddChildView(new ContentsView(this, message_center_view_));
// Resize the content of the bubble view to the given bubble size. This is
// necessary in case of the bubble border forcing a bigger size then the
diff --git a/chromium/ui/message_center/views/message_center_bubble.h b/chromium/ui/message_center/views/message_center_bubble.h
index 521bf4ac8e2..1173a95393b 100644
--- a/chromium/ui/message_center/views/message_center_bubble.h
+++ b/chromium/ui/message_center/views/message_center_bubble.h
@@ -55,6 +55,8 @@ class MESSAGE_CENTER_EXPORT MessageCenterBubble
// the used anchor.
bool first_item_has_no_margin_;
+ base::string16 title_;
+
DISALLOW_COPY_AND_ASSIGN(MessageCenterBubble);
};
diff --git a/chromium/ui/message_center/views/message_center_button_bar.cc b/chromium/ui/message_center/views/message_center_button_bar.cc
index 0816ffa29b1..8008115e705 100644
--- a/chromium/ui/message_center/views/message_center_button_bar.cc
+++ b/chromium/ui/message_center/views/message_center_button_bar.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/text_constants.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
+#include "ui/message_center/message_center_tray.h"
#include "ui/message_center/notifier_settings.h"
#include "ui/message_center/views/message_center_view.h"
#include "ui/views/controls/button/button.h"
@@ -50,7 +51,7 @@ class NotificationCenterButton : public views::ToggleImageButton {
protected:
// Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
private:
gfx::Size size_;
@@ -82,7 +83,7 @@ NotificationCenterButton::NotificationCenterButton(
gfx::Insets(1, 2, 2, 2)));
}
-gfx::Size NotificationCenterButton::GetPreferredSize() { return size_; }
+gfx::Size NotificationCenterButton::GetPreferredSize() const { return size_; }
// MessageCenterButtonBar /////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -90,17 +91,20 @@ MessageCenterButtonBar::MessageCenterButtonBar(
MessageCenterView* message_center_view,
MessageCenter* message_center,
NotifierSettingsProvider* notifier_settings_provider,
- bool settings_initially_visible)
+ bool settings_initially_visible,
+ const base::string16& title)
: message_center_view_(message_center_view),
message_center_(message_center),
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ close_bubble_button_(NULL),
+#endif
title_arrow_(NULL),
notification_label_(NULL),
button_container_(NULL),
close_all_button_(NULL),
settings_button_(NULL),
quiet_mode_button_(NULL) {
- if (get_use_acceleration_when_possible())
- SetPaintToLayer(true);
+ SetPaintToLayer(true);
set_background(
views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
@@ -117,11 +121,7 @@ MessageCenterButtonBar::MessageCenterButtonBar(
title_arrow_->SetFocusable(false);
AddChildView(title_arrow_);
- gfx::Font notification_label_font =
- ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
- notification_label_ = new views::Label(
- l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_TITLE),
- notification_label_font);
+ notification_label_ = new views::Label(title);
notification_label_->SetAutoColorReadabilityEnabled(false);
notification_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
notification_label_->SetEnabledColor(kRegularTextColor);
@@ -170,6 +170,20 @@ MessageCenterButtonBar::MessageCenterButtonBar(
IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL);
button_container_->AddChildView(settings_button_);
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ close_bubble_button_ = new views::ImageButton(this);
+ close_bubble_button_->SetImage(
+ views::Button::STATE_NORMAL,
+ resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_BUBBLE_CLOSE));
+ close_bubble_button_->SetImage(
+ views::Button::STATE_HOVERED,
+ resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_BUBBLE_CLOSE_HOVER));
+ close_bubble_button_->SetImage(
+ views::Button::STATE_PRESSED,
+ resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_BUBBLE_CLOSE_PRESSED));
+ AddChildView(close_bubble_button_);
+#endif
+
SetCloseAllButtonEnabled(!settings_initially_visible);
SetBackArrowVisible(settings_initially_visible);
ViewVisibilityChanged();
@@ -218,11 +232,24 @@ void MessageCenterButtonBar::ViewVisibilityChanged() {
0,
0);
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // The close-bubble button.
+ column->AddColumn(views::GridLayout::LEADING,
+ views::GridLayout::LEADING,
+ 0.0f,
+ views::GridLayout::USE_PREF,
+ 0,
+ 0);
+#endif
+
layout->StartRow(0, 0);
if (title_arrow_->visible())
layout->AddView(title_arrow_);
layout->AddView(notification_label_);
layout->AddView(button_container_);
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ layout->AddView(close_bubble_button_);
+#endif
}
MessageCenterButtonBar::~MessageCenterButtonBar() {}
@@ -263,6 +290,10 @@ void MessageCenterButtonBar::ButtonPressed(views::Button* sender,
else
message_center()->EnterQuietModeWithExpire(base::TimeDelta::FromDays(1));
quiet_mode_button_->SetToggled(message_center()->IsQuietMode());
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ } else if (sender == close_bubble_button_) {
+ message_center_view()->tray()->HideMessageCenterBubble();
+#endif
} else {
NOTREACHED();
}
diff --git a/chromium/ui/message_center/views/message_center_button_bar.h b/chromium/ui/message_center/views/message_center_button_bar.h
index 8190e3e2cc2..bc87dbed44e 100644
--- a/chromium/ui/message_center/views/message_center_button_bar.h
+++ b/chromium/ui/message_center/views/message_center_button_bar.h
@@ -30,7 +30,8 @@ class MessageCenterButtonBar : public views::View,
MessageCenterButtonBar(MessageCenterView* message_center_view,
MessageCenter* message_center,
NotifierSettingsProvider* notifier_settings_provider,
- bool settings_initially_visible);
+ bool settings_initially_visible,
+ const base::string16& title);
virtual ~MessageCenterButtonBar();
// Enables or disables all of the buttons in the center. This is used to
@@ -63,6 +64,15 @@ class MessageCenterButtonBar : public views::View,
MessageCenterView* message_center_view_; // Weak reference.
MessageCenter* message_center_; // Weak reference.
+ // |close_bubble_button_| closes the message center bubble. This is required
+ // for desktop Linux because the status icon doesn't toggle the bubble, and
+ // close-on-deactivation is off. This is a tentative solution. Once pkotwicz
+ // Fixes the problem of focus-follow-mouse, close-on-deactivation will be
+ // back and this field will be removed. See crbug.com/319516.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ views::ImageButton* close_bubble_button_;
+#endif
+
// Sub-views of the button bar.
NotificationCenterButton* title_arrow_;
views::Label* notification_label_;
diff --git a/chromium/ui/message_center/views/message_center_controller.h b/chromium/ui/message_center/views/message_center_controller.h
index c680c0eedb1..df413555b70 100644
--- a/chromium/ui/message_center/views/message_center_controller.h
+++ b/chromium/ui/message_center/views/message_center_controller.h
@@ -7,6 +7,9 @@
#include <string>
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/base/models/menu_model.h"
#include "ui/message_center/notifier_settings.h"
namespace message_center {
@@ -20,18 +23,14 @@ class MessageCenterController {
virtual void ClickOnNotification(const std::string& notification_id) = 0;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) = 0;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) = 0;
- virtual void ShowNotifierSettingsBubble() = 0;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) = 0;
virtual bool HasClickedListener(const std::string& notification_id) = 0;
virtual void ClickOnNotificationButton(const std::string& notification_id,
int button_index) = 0;
- virtual void ExpandNotification(const std::string& notification_id) = 0;
- virtual void GroupBodyClicked(const std::string& last_notification_id) = 0;
- virtual void ExpandGroup(const NotifierId& notifier_id) = 0;
- virtual void RemoveGroup(const NotifierId& notifier_id) = 0;
};
} // namespace message_center
-#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_CONTROLLER_H_ \ No newline at end of file
+#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_CONTROLLER_H_
diff --git a/chromium/ui/message_center/views/message_center_view.cc b/chromium/ui/message_center/views/message_center_view.cc
index ebdbf33b2d6..0f003ed050b 100644
--- a/chromium/ui/message_center/views/message_center_view.cc
+++ b/chromium/ui/message_center/views/message_center_view.cc
@@ -24,10 +24,9 @@
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/message_center_tray.h"
#include "ui/message_center/message_center_types.h"
-#include "ui/message_center/message_center_util.h"
-#include "ui/message_center/views/group_view.h"
#include "ui/message_center/views/message_center_button_bar.h"
#include "ui/message_center/views/message_view.h"
+#include "ui/message_center/views/message_view_context_menu_controller.h"
#include "ui/message_center/views/notification_view.h"
#include "ui/message_center/views/notifier_settings_view.h"
#include "ui/views/animation/bounds_animator.h"
@@ -51,80 +50,19 @@ const SkColor kNoNotificationsTextColor = SkColorSetRGB(0xb4, 0xb4, 0xb4);
const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0);
#endif
const int kAnimateClearingNextNotificationDelayMS = 40;
-const int kMinScrollViewHeight = 100;
const int kDefaultAnimationDurationMs = 120;
const int kDefaultFrameRateHz = 60;
-
-const int kMaxNotificationCountFromSingleDisplaySource = 1;
-
} // namespace
-// BoundedScrollView ///////////////////////////////////////////////////////////
-
-// A custom scroll view whose height has a minimum and maximum value and whose
-// scroll bar disappears when not needed.
-class BoundedScrollView : public views::ScrollView {
- public:
- BoundedScrollView(int min_height, int max_height);
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
- virtual void Layout() OVERRIDE;
-
- private:
- int min_height_;
- int max_height_;
-
- DISALLOW_COPY_AND_ASSIGN(BoundedScrollView);
-};
-
-BoundedScrollView::BoundedScrollView(int min_height, int max_height)
- : min_height_(min_height),
- max_height_(max_height) {
- set_notify_enter_exit_on_child(true);
- set_background(
- views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
- SetVerticalScrollBar(new views::OverlayScrollBar(false));
-}
-
-gfx::Size BoundedScrollView::GetPreferredSize() {
- gfx::Size size = contents()->GetPreferredSize();
- size.SetToMax(gfx::Size(size.width(), min_height_));
- size.SetToMin(gfx::Size(size.width(), max_height_));
- gfx::Insets insets = GetInsets();
- size.Enlarge(insets.width(), insets.height());
- return size;
-}
-
-int BoundedScrollView::GetHeightForWidth(int width) {
- gfx::Insets insets = GetInsets();
- width = std::max(0, width - insets.width());
- int height = contents()->GetHeightForWidth(width) + insets.height();
- return std::min(std::max(height, min_height_), max_height_);
-}
-
-void BoundedScrollView::Layout() {
- int content_width = width();
- int content_height = contents()->GetHeightForWidth(content_width);
- if (content_height > height()) {
- content_width = std::max(content_width - GetScrollBarWidth(), 0);
- content_height = contents()->GetHeightForWidth(content_width);
- }
- if (contents()->bounds().size() != gfx::Size(content_width, content_height))
- contents()->SetBounds(0, 0, content_width, content_height);
- views::ScrollView::Layout();
-}
-
class NoNotificationMessageView : public views::View {
public:
NoNotificationMessageView();
virtual ~NoNotificationMessageView();
// Overridden from views::View.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void Layout() OVERRIDE;
private:
@@ -149,11 +87,11 @@ NoNotificationMessageView::NoNotificationMessageView() {
NoNotificationMessageView::~NoNotificationMessageView() {
}
-gfx::Size NoNotificationMessageView::GetPreferredSize() {
+gfx::Size NoNotificationMessageView::GetPreferredSize() const {
return gfx::Size(kMinScrollViewHeight, label_->GetPreferredSize().width());
}
-int NoNotificationMessageView::GetHeightForWidth(int width) {
+int NoNotificationMessageView::GetHeightForWidth(int width) const {
return kMinScrollViewHeight;
}
@@ -174,8 +112,8 @@ class MessageListView : public views::View,
virtual ~MessageListView();
void AddNotificationAt(MessageView* view, int i);
- void RemoveNotificationAt(int i);
- void UpdateNotificationAt(MessageView* view, int i);
+ void RemoveNotification(MessageView* view);
+ void UpdateNotification(MessageView* view, const Notification& notification);
void SetRepositionTarget(const gfx::Rect& target_rect);
void ResetRepositionSession();
void ClearAllNotifications(const gfx::Rect& visible_scroll_rect);
@@ -183,9 +121,10 @@ class MessageListView : public views::View,
protected:
// Overridden from views::View.
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
- virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
+ virtual void PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) OVERRIDE;
virtual void ReorderChildLayers(ui::Layer* parent_layer) OVERRIDE;
// Overridden from views::BoundsAnimatorObserver.
@@ -194,14 +133,7 @@ class MessageListView : public views::View,
virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator) OVERRIDE;
private:
- // Returns the actual index for child of |index|.
- // MessageListView allows to slide down upper notifications, which means
- // that the upper ones should come above the lower ones if top_down is not
- // enabled. To achieve this, inversed order is adopted. The top most
- // notification is the last child, and the bottom most notification is the
- // first child.
- int GetActualIndex(int index);
- bool IsValidChild(views::View* child);
+ bool IsValidChild(const views::View* child) const;
void DoUpdateIfPossible();
// Animates all notifications below target upwards to align with the top of
@@ -249,7 +181,7 @@ MessageListView::MessageListView(MessageCenterView* message_center_view,
weak_ptr_factory_(this) {
views::BoxLayout* layout =
new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1);
- layout->set_spread_blank_space(true);
+ layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_FILL);
SetLayoutManager(layout);
// Set the margin to 0 for the layout. BoxLayout assumes the same margin
@@ -259,7 +191,7 @@ MessageListView::MessageListView(MessageCenterView* message_center_view,
gfx::Insets shadow_insets = MessageView::GetShadowInsets();
set_background(views::Background::CreateSolidBackground(
kMessageCenterBackgroundColor));
- set_border(views::Border::CreateEmptyBorder(
+ SetBorder(views::Border::CreateEmptyBorder(
top_down ? 0 : kMarginBetweenItems - shadow_insets.top(), /* top */
kMarginBetweenItems - shadow_insets.left(), /* left */
top_down ? kMarginBetweenItems - shadow_insets.bottom() : 0, /* bottom */
@@ -290,8 +222,22 @@ void MessageListView::Layout() {
}
}
-void MessageListView::AddNotificationAt(MessageView* view, int i) {
- AddChildViewAt(view, GetActualIndex(i));
+void MessageListView::AddNotificationAt(MessageView* view, int index) {
+ // |index| refers to a position in a subset of valid children. |real_index|
+ // in a list includes the invalid children, so we compute the real index by
+ // walking the list until |index| number of valid children are encountered,
+ // or to the end of the list.
+ int real_index = 0;
+ while (real_index < child_count()) {
+ if (IsValidChild(child_at(real_index))) {
+ --index;
+ if (index < 0)
+ break;
+ }
+ ++real_index;
+ }
+
+ AddChildViewAt(view, real_index);
if (GetContentsBounds().IsEmpty())
return;
@@ -299,43 +245,41 @@ void MessageListView::AddNotificationAt(MessageView* view, int i) {
DoUpdateIfPossible();
}
-void MessageListView::RemoveNotificationAt(int i) {
- views::View* child = child_at(GetActualIndex(i));
+void MessageListView::RemoveNotification(MessageView* view) {
+ DCHECK_EQ(view->parent(), this);
if (GetContentsBounds().IsEmpty()) {
- delete child;
+ delete view;
} else {
- if (child->layer()) {
- deleting_views_.insert(child);
+ if (view->layer()) {
+ deleting_views_.insert(view);
} else {
if (animator_.get())
- animator_->StopAnimatingView(child);
- delete child;
+ animator_->StopAnimatingView(view);
+ delete view;
}
DoUpdateIfPossible();
}
}
-void MessageListView::UpdateNotificationAt(MessageView* view, int i) {
- int actual_index = GetActualIndex(i);
- views::View* child = child_at(actual_index);
+void MessageListView::UpdateNotification(MessageView* view,
+ const Notification& notification) {
+ int index = GetIndexOf(view);
+ DCHECK_LE(0, index); // GetIndexOf is negative if not a child.
+
if (animator_.get())
- animator_->StopAnimatingView(child);
- gfx::Rect old_bounds = child->bounds();
- if (deleting_views_.find(child) != deleting_views_.end())
- deleting_views_.erase(child);
- if (deleted_when_done_.find(child) != deleted_when_done_.end())
- deleted_when_done_.erase(child);
- delete child;
- AddChildViewAt(view, actual_index);
- view->SetBounds(old_bounds.x(), old_bounds.y(), old_bounds.width(),
- view->GetHeightForWidth(old_bounds.width()));
+ animator_->StopAnimatingView(view);
+ if (deleting_views_.find(view) != deleting_views_.end())
+ deleting_views_.erase(view);
+ if (deleted_when_done_.find(view) != deleted_when_done_.end())
+ deleted_when_done_.erase(view);
+ view->UpdateWithNotification(notification);
DoUpdateIfPossible();
}
-gfx::Size MessageListView::GetPreferredSize() {
+gfx::Size MessageListView::GetPreferredSize() const {
int width = 0;
for (int i = 0; i < child_count(); i++) {
- views::View* child = child_at(i);
+ const views::View* child = child_at(i);
if (IsValidChild(child))
width = std::max(width, child->GetPreferredSize().width());
}
@@ -344,7 +288,7 @@ gfx::Size MessageListView::GetPreferredSize() {
GetHeightForWidth(width + GetInsets().width()));
}
-int MessageListView::GetHeightForWidth(int width) {
+int MessageListView::GetHeightForWidth(int width) const {
if (fixed_height_ > 0)
return fixed_height_;
@@ -352,7 +296,7 @@ int MessageListView::GetHeightForWidth(int width) {
int height = 0;
int padding = 0;
for (int i = 0; i < child_count(); ++i) {
- views::View* child = child_at(i);
+ const views::View* child = child_at(i);
if (!IsValidChild(child))
continue;
height += child->GetHeightForWidth(width) + padding;
@@ -362,12 +306,13 @@ int MessageListView::GetHeightForWidth(int width) {
return height + GetInsets().height();
}
-void MessageListView::PaintChildren(gfx::Canvas* canvas) {
+void MessageListView::PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) {
// Paint in the inversed order. Otherwise upper notification may be
// hidden by the lower one.
for (int i = child_count() - 1; i >= 0; --i) {
if (!child_at(i)->layer())
- child_at(i)->Paint(canvas);
+ child_at(i)->Paint(canvas, cull_set);
}
}
@@ -446,16 +391,12 @@ void MessageListView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
GetWidget()->SynthesizeMouseMoveEvent();
}
-int MessageListView::GetActualIndex(int index) {
- for (int i = 0; i < child_count() && i <= index; ++i)
- index += IsValidChild(child_at(i)) ? 0 : 1;
- return std::min(index, child_count());
-}
-
-bool MessageListView::IsValidChild(views::View* child) {
+bool MessageListView::IsValidChild(const views::View* child) const {
return child->visible() &&
- deleting_views_.find(child) == deleting_views_.end() &&
- deleted_when_done_.find(child) == deleted_when_done_.end();
+ deleting_views_.find(const_cast<views::View*>(child)) ==
+ deleting_views_.end() &&
+ deleted_when_done_.find(const_cast<views::View*>(child)) ==
+ deleted_when_done_.end();
}
void MessageListView::DoUpdateIfPossible() {
@@ -594,7 +535,8 @@ MessageCenterView::MessageCenterView(MessageCenter* message_center,
MessageCenterTray* tray,
int max_height,
bool initially_settings_visible,
- bool top_down)
+ bool top_down,
+ const base::string16& title)
: message_center_(message_center),
tray_(tray),
scroller_(NULL),
@@ -606,7 +548,8 @@ MessageCenterView::MessageCenterView(MessageCenter* message_center,
source_height_(0),
target_view_(NULL),
target_height_(0),
- is_closing_(false) {
+ is_closing_(false),
+ context_menu_controller_(new MessageViewContextMenuController(this)) {
message_center_->AddObserver(this);
set_notify_enter_exit_on_child(true);
set_background(views::Background::CreateSolidBackground(
@@ -617,18 +560,20 @@ MessageCenterView::MessageCenterView(MessageCenter* message_center,
button_bar_ = new MessageCenterButtonBar(this,
message_center,
notifier_settings_provider,
- initially_settings_visible);
+ initially_settings_visible,
+ title);
const int button_height = button_bar_->GetPreferredSize().height();
- scroller_ =
- new BoundedScrollView(kMinScrollViewHeight, max_height - button_height);
+ scroller_ = new views::ScrollView();
+ scroller_->ClipHeightTo(kMinScrollViewHeight, max_height - button_height);
+ scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
+ scroller_->set_background(
+ views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
- if (get_use_acceleration_when_possible()) {
- scroller_->SetPaintToLayer(true);
- scroller_->SetFillsBoundsOpaquely(false);
- scroller_->layer()->SetMasksToBounds(true);
- }
+ scroller_->SetPaintToLayer(true);
+ scroller_->SetFillsBoundsOpaquely(false);
+ scroller_->layer()->SetMasksToBounds(true);
empty_list_view_.reset(new NoNotificationMessageView);
empty_list_view_->set_owned_by_client();
@@ -670,65 +615,15 @@ void MessageCenterView::SetNotifications(
notification_views_.clear();
- // Count how many times each Notifier is encountered. We group Notifications
- // by NotifierId.
- std::map<NotifierId, int> groups;
int index = 0;
+ for (NotificationList::Notifications::const_iterator iter =
+ notifications.begin(); iter != notifications.end(); ++iter) {
+ AddNotificationAt(*(*iter), index++);
- if (IsExperimentalNotificationUIEnabled()) {
- for (NotificationList::Notifications::const_iterator iter =
- notifications.begin(); iter != notifications.end(); ++iter) {
- NotifierId group_id = (*iter)->notifier_id();
- std::map<NotifierId, int>::iterator group_iter = groups.find(group_id);
- if (group_iter != groups.end())
- group_iter->second++;
- else
- groups[group_id] = 1;
- }
-
- // TODO(dimich): Find a better group icon. Preferably associated with
- // the group (notifier icon?).
- gfx::ImageSkia* group_icon = ui::ResourceBundle::GetSharedInstance().
- GetImageSkiaNamed(IDR_FOLDER_CLOSED);
-
- for (NotificationList::Notifications::const_iterator iter =
- notifications.begin(); iter != notifications.end(); ++iter) {
- // See if the notification's NotifierId is encountered too many
- // times - in this case replace all notifications from this source with
- // a synthetic placeholder that says "N more". Mark the NotifierId
- // as "seen" by setting count to 0 so the subsequent notificaitons from
- // the same source are ignored.
- std::map<NotifierId, int>::iterator group_iter =
- groups.find((*iter)->notifier_id());
- // We should have collected all groups in the loop above.
- DCHECK(group_iter != groups.end());
-
- if (group_iter->second > kMaxNotificationCountFromSingleDisplaySource) {
- AddGroupPlaceholder(group_iter->first,
- *(*iter),
- group_icon ? *group_icon : gfx::ImageSkia(),
- group_iter->second,
- index++);
- group_iter->second = 0; // Mark.
- } else if (group_iter->second == 0) { // Marked, skip.
- continue;
- } else { // Ungrouped notifications
- AddNotificationAt(*(*iter), index++);
- }
-
- message_center_->DisplayedNotification((*iter)->id());
- if (notification_views_.size() >= kMaxVisibleMessageCenterNotifications)
- break;
- }
- } else {
- for (NotificationList::Notifications::const_iterator iter =
- notifications.begin(); iter != notifications.end(); ++iter) {
- AddNotificationAt(*(*iter), index++);
-
- message_center_->DisplayedNotification((*iter)->id());
- if (notification_views_.size() >= kMaxVisibleMessageCenterNotifications)
- break;
- }
+ message_center_->DisplayedNotification(
+ (*iter)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER);
+ if (notification_views_.size() >= kMaxVisibleMessageCenterNotifications)
+ break;
}
NotificationsChanged();
@@ -854,10 +749,10 @@ void MessageCenterView::Layout() {
if (is_scrollable) {
// Draw separator line on the top of the button bar if it is on the bottom
// or draw it at the bottom if the bar is on the top.
- button_bar_->set_border(views::Border::CreateSolidSidedBorder(
+ button_bar_->SetBorder(views::Border::CreateSolidSidedBorder(
top_down_ ? 0 : 1, 0, top_down_ ? 1 : 0, 0, kFooterDelimiterColor));
} else {
- button_bar_->set_border(views::Border::CreateEmptyBorder(
+ button_bar_->SetBorder(views::Border::CreateEmptyBorder(
top_down_ ? 0 : 1, 0, top_down_ ? 1 : 0, 0));
}
button_bar_->SchedulePaint();
@@ -870,7 +765,7 @@ void MessageCenterView::Layout() {
GetWidget()->GetRootView()->SchedulePaint();
}
-gfx::Size MessageCenterView::GetPreferredSize() {
+gfx::Size MessageCenterView::GetPreferredSize() const {
if (settings_transition_animation_ &&
settings_transition_animation_->is_animating()) {
int content_width = std::max(source_view_->GetPreferredSize().width(),
@@ -882,14 +777,14 @@ gfx::Size MessageCenterView::GetPreferredSize() {
int width = 0;
for (int i = 0; i < child_count(); ++i) {
- views::View* child = child_at(0);
+ const views::View* child = child_at(0);
if (child->visible())
width = std::max(width, child->GetPreferredSize().width());
}
return gfx::Size(width, GetHeightForWidth(width));
}
-int MessageCenterView::GetHeightForWidth(int width) {
+int MessageCenterView::GetHeightForWidth(int width) const {
if (settings_transition_animation_ &&
settings_transition_animation_->is_animating()) {
int content_height = target_height_;
@@ -927,7 +822,6 @@ void MessageCenterView::OnMouseExited(const ui::MouseEvent& event) {
NotificationsChanged();
}
-// TODO(dimich): update for GROUP_VIEW
void MessageCenterView::OnNotificationAdded(const std::string& id) {
int index = 0;
const NotificationList::Notifications& notifications =
@@ -945,7 +839,6 @@ void MessageCenterView::OnNotificationAdded(const std::string& id) {
NotificationsChanged();
}
-// TODO(dimich): update for GROUP_VIEW
void MessageCenterView::OnNotificationRemoved(const std::string& id,
bool by_user) {
NotificationViewsMap::iterator view_iter = notification_views_.find(id);
@@ -953,6 +846,7 @@ void MessageCenterView::OnNotificationRemoved(const std::string& id,
return;
NotificationView* view = view_iter->second;
int index = message_list_view_->GetIndexOf(view);
+ DCHECK_LE(0, index);
if (by_user) {
message_list_view_->SetRepositionTarget(view->bounds());
// Moves the keyboard focus to the next notification if the removed
@@ -976,38 +870,27 @@ void MessageCenterView::OnNotificationRemoved(const std::string& id,
}
}
}
- message_list_view_->RemoveNotificationAt(index);
+ message_list_view_->RemoveNotification(view);
notification_views_.erase(view_iter);
NotificationsChanged();
}
-// TODO(dimich): update for GROUP_VIEW
void MessageCenterView::OnNotificationUpdated(const std::string& id) {
NotificationViewsMap::const_iterator view_iter = notification_views_.find(id);
if (view_iter == notification_views_.end())
return;
NotificationView* view = view_iter->second;
- size_t index = message_list_view_->GetIndexOf(view);
- DCHECK(index >= 0);
// TODO(dimich): add MessageCenter::GetVisibleNotificationById(id)
const NotificationList::Notifications& notifications =
message_center_->GetVisibleNotifications();
for (NotificationList::Notifications::const_iterator iter =
notifications.begin(); iter != notifications.end(); ++iter) {
if ((*iter)->id() == id) {
- bool expanded = true;
- if (IsExperimentalNotificationUIEnabled())
- expanded = (*iter)->is_expanded();
- NotificationView* view =
- NotificationView::Create(this,
- *(*iter),
- expanded,
- false); // Not creating a top-level
- // notification.
- view->set_scroller(scroller_);
- message_list_view_->UpdateNotificationAt(view, index);
- notification_views_[id] = view;
- NotificationsChanged();
+ int old_width = view->width();
+ int old_height = view->GetHeightForWidth(old_width);
+ message_list_view_->UpdateNotification(view, **iter);
+ if (view->GetHeightForWidth(old_width) != old_height)
+ NotificationsChanged();
break;
}
}
@@ -1023,13 +906,10 @@ void MessageCenterView::RemoveNotification(const std::string& notification_id,
message_center_->RemoveNotification(notification_id, by_user);
}
-void MessageCenterView::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- message_center_->DisableNotificationsByNotifier(notifier_id);
-}
-
-void MessageCenterView::ShowNotifierSettingsBubble() {
- tray_->ShowNotifierSettingsBubble();
+scoped_ptr<ui::MenuModel> MessageCenterView::CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
+ return tray_->CreateNotificationMenuModel(notifier_id, display_source);
}
bool MessageCenterView::HasClickedListener(const std::string& notification_id) {
@@ -1042,41 +922,6 @@ void MessageCenterView::ClickOnNotificationButton(
message_center_->ClickOnNotificationButton(notification_id, button_index);
}
-void MessageCenterView::ExpandNotification(const std::string& notification_id) {
- message_center_->ExpandNotification(notification_id);
-}
-
-void MessageCenterView::GroupBodyClicked(
- const std::string& last_notification_id) {
- message_center_->ClickOnNotification(last_notification_id);
-}
-
-// When clicked on the "N more" button, perform some reasonable action.
-// TODO(dimich): find out what the reasonable action could be.
-void MessageCenterView::ExpandGroup(const NotifierId& notifier_id) {
- NOTIMPLEMENTED();
-}
-
-// Click on Close button on a GroupView should remove all notifications
-// represented by this GroupView.
-void MessageCenterView::RemoveGroup(const NotifierId& notifier_id) {
- std::vector<std::string> notifications_to_remove;
-
- // Can not remove notifications while iterating the list. Collect the ids
- // and then run separate loop to remove notifications.
- const NotificationList::Notifications& notifications =
- message_center_->GetVisibleNotifications();
- for (NotificationList::Notifications::const_iterator iter =
- notifications.begin(); iter != notifications.end(); ++iter) {
- if ((*iter)->notifier_id() == notifier_id)
- notifications_to_remove.push_back((*iter)->id());
- }
-
- for (size_t i = 0; i < notifications_to_remove.size(); ++i)
- // "by_user" = true
- message_center_->RemoveNotification(notifications_to_remove[i], true);
-}
-
void MessageCenterView::AnimationEnded(const gfx::Animation* animation) {
DCHECK_EQ(animation, settings_transition_animation_.get());
@@ -1117,46 +962,18 @@ void MessageCenterView::AnimationCanceled(const gfx::Animation* animation) {
AnimationEnded(animation);
}
-
-void MessageCenterView::AddMessageViewAt(MessageView* view, int index) {
- view->set_scroller(scroller_);
- message_list_view_->AddNotificationAt(view, index);
-}
-
-void MessageCenterView::AddGroupPlaceholder(
- const NotifierId& group_id,
- const Notification& last_notification,
- const gfx::ImageSkia& group_icon,
- int group_size,
- int index) {
- GroupView* view = new GroupView(this,
- group_id,
- last_notification,
- group_icon,
- group_size);
- group_views_.push_back(view);
- AddMessageViewAt(view, index);
-}
-
void MessageCenterView::AddNotificationAt(const Notification& notification,
int index) {
- // NotificationViews are expanded by default here until
- // http://crbug.com/217902 is fixed. TODO(dharcourt): Fix.
- bool expanded = true;
- if (IsExperimentalNotificationUIEnabled())
- expanded = notification.is_expanded();
NotificationView* view =
- NotificationView::Create(this,
- notification,
- expanded,
- false); // Not creating a top-level
- // notification.
+ NotificationView::Create(this, notification, false); // Not top-level.
+ view->set_context_menu_controller(context_menu_controller_.get());
notification_views_[notification.id()] = view;
- AddMessageViewAt(view, index);
+ view->set_scroller(scroller_);
+ message_list_view_->AddNotificationAt(view, index);
}
void MessageCenterView::NotificationsChanged() {
- bool no_message_views = notification_views_.empty() && group_views_.empty();
+ bool no_message_views = notification_views_.empty();
// When the child view is removed from the hierarchy, its focus is cleared.
// In this case we want to save which view has focus so that the user can
diff --git a/chromium/ui/message_center/views/message_center_view.h b/chromium/ui/message_center/views/message_center_view.h
index b64f770a8e6..94dd139213c 100644
--- a/chromium/ui/message_center/views/message_center_view.h
+++ b/chromium/ui/message_center/views/message_center_view.h
@@ -5,7 +5,6 @@
#ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_VIEW_H_
#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_VIEW_H_
-#include "ui/views/view.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/message_center/message_center_export.h"
@@ -14,6 +13,7 @@
#include "ui/message_center/views/message_center_controller.h"
#include "ui/message_center/views/message_view.h"
#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
namespace gfx {
class MultiAnimation;
@@ -25,7 +25,6 @@ class Button;
namespace message_center {
-class GroupView;
class MessageCenter;
class MessageCenterBubble;
class NotificationCenterButton;
@@ -33,6 +32,7 @@ class MessageCenterButtonBar;
class MessageCenterTray;
class MessageCenterView;
class MessageView;
+class MessageViewContextMenuController;
class MessageListView;
class NotificationView;
class NotifierSettingsView;
@@ -48,7 +48,8 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
MessageCenterTray* tray,
int max_height,
bool initially_settings_visible,
- bool top_down);
+ bool top_down,
+ const base::string16& title);
virtual ~MessageCenterView();
void SetNotifications(const NotificationList::Notifications& notifications);
@@ -61,14 +62,15 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
void SetSettingsVisible(bool visible);
void OnSettingsChanged();
bool settings_visible() const { return settings_visible_; }
+ MessageCenterTray* tray() { return tray_; }
void SetIsClosing(bool is_closing);
protected:
// Overridden from views::View:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
@@ -82,17 +84,12 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) OVERRIDE;
virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& notification_id,
int button_index) OVERRIDE;
- virtual void ExpandNotification(const std::string& notification_id) OVERRIDE;
- virtual void GroupBodyClicked(const std::string& last_notification_id)
- OVERRIDE;
- virtual void ExpandGroup(const NotifierId& notifier_id) OVERRIDE;
- virtual void RemoveGroup(const NotifierId& notifier_id) OVERRIDE;
// Overridden from gfx::AnimationDelegate:
virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
@@ -102,12 +99,6 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
private:
friend class MessageCenterViewTest;
- void AddMessageViewAt(MessageView* view, int index);
- void AddGroupPlaceholder(const NotifierId& group_id,
- const Notification& notification,
- const gfx::ImageSkia& group_icon,
- int group_size,
- int index);
void AddNotificationAt(const Notification& notification, int index);
void NotificationsChanged();
void SetNotificationViewForTest(MessageView* view);
@@ -115,16 +106,11 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
MessageCenter* message_center_; // Weak reference.
MessageCenterTray* tray_; // Weak reference.
- // Map notification_id->NotificationView*. It contains all NotificaitonViews
+ // Map notification_id->NotificationView*. It contains all NotificationViews
// currently displayed in MessageCenter.
typedef std::map<std::string, NotificationView*> NotificationViewsMap;
NotificationViewsMap notification_views_; // Weak.
- // List of all GroupViews. GroupView is responsible for multiple Notifications
- // from the same source.
- typedef std::list<GroupView*> GroupViews;
- GroupViews group_views_; // Weak.
-
// Child views.
views::ScrollView* scroller_;
scoped_ptr<MessageListView> message_list_view_;
@@ -151,6 +137,8 @@ class MESSAGE_CENTER_EXPORT MessageCenterView : public views::View,
// ignored.
bool is_closing_;
+ scoped_ptr<MessageViewContextMenuController> context_menu_controller_;
+
DISALLOW_COPY_AND_ASSIGN(MessageCenterView);
};
diff --git a/chromium/ui/message_center/views/message_center_view_unittest.cc b/chromium/ui/message_center/views/message_center_view_unittest.cc
index cd44e2dec66..3335ed8c52b 100644
--- a/chromium/ui/message_center/views/message_center_view_unittest.cc
+++ b/chromium/ui/message_center/views/message_center_view_unittest.cc
@@ -40,8 +40,8 @@ class MockNotificationView : public NotificationView {
Test* test);
virtual ~MockNotificationView();
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual void Layout() OVERRIDE;
private:
@@ -53,20 +53,20 @@ class MockNotificationView : public NotificationView {
MockNotificationView::MockNotificationView(MessageCenterController* controller,
const Notification& notification,
Test* test)
- : NotificationView(controller, notification, true),
+ : NotificationView(controller, notification),
test_(test) {
}
MockNotificationView::~MockNotificationView() {
}
-gfx::Size MockNotificationView::GetPreferredSize() {
+gfx::Size MockNotificationView::GetPreferredSize() const {
test_->RegisterCall(GET_PREFERRED_SIZE);
DCHECK(child_count() > 0);
return NotificationView::GetPreferredSize();
}
-int MockNotificationView::GetHeightForWidth(int width) {
+int MockNotificationView::GetHeightForWidth(int width) const {
test_->RegisterCall(GET_HEIGHT_FOR_WIDTH);
DCHECK(child_count() > 0);
return NotificationView::GetHeightForWidth(width);
@@ -98,17 +98,12 @@ class MessageCenterViewTest : public testing::Test,
virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) OVERRIDE;
virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& notification_id,
int button_index) OVERRIDE;
- virtual void ExpandNotification(const std::string& notification_id) OVERRIDE;
- virtual void GroupBodyClicked(const std::string& last_notification_id)
- OVERRIDE;
- virtual void ExpandGroup(const NotifierId& notifier_id) OVERRIDE;
- virtual void RemoveGroup(const NotifierId& notifier_id) OVERRIDE;
// Overridden from MockNotificationView::Test
virtual void RegisterCall(CallType type) OVERRIDE;
@@ -136,10 +131,10 @@ void MessageCenterViewTest::SetUp() {
// Create a dummy notification.
Notification notification(NOTIFICATION_TYPE_SIMPLE,
std::string("notification id"),
- UTF8ToUTF16("title"),
- UTF8ToUTF16("message"),
+ base::UTF8ToUTF16("title"),
+ base::UTF8ToUTF16("message"),
gfx::Image(),
- UTF8ToUTF16("display source"),
+ base::UTF8ToUTF16("display source"),
NotifierId(NotifierId::APPLICATION, "extension_id"),
message_center::RichNotificationData(),
NULL);
@@ -149,8 +144,9 @@ void MessageCenterViewTest::SetUp() {
notifications.insert(&notification);
// Then create a new MessageCenterView with that single notification.
+ base::string16 title;
message_center_view_.reset(new MessageCenterView(
- &message_center_, NULL, 100, false, /*top_down =*/false));
+ &message_center_, NULL, 100, false, /*top_down =*/false, title));
message_center_view_->SetNotifications(notifications);
// Remove and delete the NotificationView now owned by the MessageCenterView's
@@ -191,15 +187,12 @@ void MessageCenterViewTest::RemoveNotification(
NOTREACHED();
}
-void MessageCenterViewTest::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- // For this test, this method should not be invoked.
- NOTREACHED();
-}
-
-void MessageCenterViewTest::ShowNotifierSettingsBubble() {
+scoped_ptr<ui::MenuModel> MessageCenterViewTest::CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
// For this test, this method should not be invoked.
NOTREACHED();
+ return scoped_ptr<ui::MenuModel>();
}
bool MessageCenterViewTest::HasClickedListener(
@@ -214,36 +207,14 @@ void MessageCenterViewTest::ClickOnNotificationButton(
NOTREACHED();
}
-void MessageCenterViewTest::ExpandNotification(
- const std::string& notification_id) {
- // For this test, this method should not be invoked.
- NOTREACHED();
-}
-
-void MessageCenterViewTest::GroupBodyClicked(
- const std::string& last_notification_id) {
- // For this test, this method should not be invoked.
- NOTREACHED();
-}
-
-void MessageCenterViewTest::ExpandGroup(const NotifierId& notifier_id) {
- // For this test, this method should not be invoked.
- NOTREACHED();
-}
-
-void MessageCenterViewTest::RemoveGroup(const NotifierId& notifier_id) {
- // For this test, this method should not be invoked.
- NOTREACHED();
-}
-
void MessageCenterViewTest::RegisterCall(CallType type) {
callCounts_[type] += 1;
}
void MessageCenterViewTest::LogBounds(int depth, views::View* view) {
- string16 inset;
+ base::string16 inset;
for (int i = 0; i < depth; ++i)
- inset.append(UTF8ToUTF16(" "));
+ inset.append(base::UTF8ToUTF16(" "));
gfx::Rect bounds = view->bounds();
DVLOG(0) << inset << bounds.width() << " x " << bounds.height()
<< " @ " << bounds.x() << ", " << bounds.y();
diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc
index cc8c79b4656..d1116d6f346 100644
--- a/chromium/ui/message_center/views/message_popup_collection.cc
+++ b/chromium/ui/message_center/views/message_popup_collection.cc
@@ -13,16 +13,16 @@
#include "base/run_loop.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/screen.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/message_center_tray.h"
-#include "ui/message_center/message_center_util.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_list.h"
+#include "ui/message_center/views/message_view_context_menu_controller.h"
#include "ui/message_center/views/notification_view.h"
#include "ui/message_center/views/toast_contents_view.h"
#include "ui/views/background.h"
@@ -64,42 +64,24 @@ MessagePopupCollection::MessagePopupCollection(gfx::NativeView parent,
: parent_(parent),
message_center_(message_center),
tray_(tray),
+ display_id_(gfx::Display::kInvalidDisplayID),
+ screen_(NULL),
defer_counter_(0),
latest_toast_entered_(NULL),
user_is_closing_toasts_by_clicking_(false),
first_item_has_no_margin_(first_item_has_no_margin),
+ context_menu_controller_(new MessageViewContextMenuController(this)),
weak_factory_(this) {
DCHECK(message_center_);
defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>);
message_center_->AddObserver(this);
- gfx::Screen* screen = NULL;
- gfx::Display display;
- if (!parent_) {
- // On Win+Aura, we don't have a parent since the popups currently show up
- // on the Windows desktop, not in the Aura/Ash desktop. This code will
- // display the popups on the primary display.
- screen = gfx::Screen::GetNativeScreen();
- display = screen->GetPrimaryDisplay();
- } else {
- screen = gfx::Screen::GetScreenFor(parent_);
- display = screen->GetDisplayNearestWindow(parent_);
- }
- screen->AddObserver(this);
-
- display_id_ = display.id();
- work_area_ = display.work_area();
- ComputePopupAlignment(work_area_, display.bounds());
-
- // We should not update before work area and popup alignment are computed.
- DoUpdateIfPossible();
}
MessagePopupCollection::~MessagePopupCollection() {
weak_factory_.InvalidateWeakPtrs();
- gfx::Screen* screen = parent_ ?
- gfx::Screen::GetScreenFor(parent_) : gfx::Screen::GetNativeScreen();
- screen->RemoveObserver(this);
+ if (screen_)
+ screen_->RemoveObserver(this);
message_center_->RemoveObserver(this);
CloseAllWidgets();
@@ -116,13 +98,10 @@ void MessagePopupCollection::RemoveNotification(
message_center_->RemoveNotification(notification_id, by_user);
}
-void MessagePopupCollection::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- message_center_->DisableNotificationsByNotifier(notifier_id);
-}
-
-void MessagePopupCollection::ShowNotifierSettingsBubble() {
- tray_->ShowNotifierSettingsBubble();
+scoped_ptr<ui::MenuModel> MessagePopupCollection::CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
+ return tray_->CreateNotificationMenuModel(notifier_id, display_source);
}
bool MessagePopupCollection::HasClickedListener(
@@ -136,29 +115,6 @@ void MessagePopupCollection::ClickOnNotificationButton(
message_center_->ClickOnNotificationButton(notification_id, button_index);
}
-void MessagePopupCollection::ExpandNotification(
- const std::string& notification_id) {
- message_center_->ExpandNotification(notification_id);
-}
-
-void MessagePopupCollection::GroupBodyClicked(
- const std::string& last_notification_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
-// When clicked on the "N more" button, perform some reasonable action.
-// TODO(dimich): find out what the reasonable action could be.
-void MessagePopupCollection::ExpandGroup(const NotifierId& notifier_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
-void MessagePopupCollection::RemoveGroup(const NotifierId& notifier_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
void MessagePopupCollection::MarkAllPopupsShown() {
std::set<std::string> closed_ids = CloseAllWidgets();
for (std::set<std::string>::iterator iter = closed_ids.begin();
@@ -186,14 +142,11 @@ void MessagePopupCollection::UpdateWidgets() {
if (FindToast((*iter)->id()))
continue;
- bool expanded = true;
- if (IsExperimentalNotificationUIEnabled())
- expanded = (*iter)->is_expanded();
NotificationView* view =
NotificationView::Create(NULL,
*(*iter),
- expanded,
true); // Create top-level notification.
+ view->set_context_menu_controller(context_menu_controller_.get());
int view_height = ToastContentsView::GetToastSizeForView(view).height();
int height_available = top_down ? work_area_.bottom() - base : base;
@@ -230,10 +183,11 @@ void MessagePopupCollection::UpdateWidgets() {
if (views::ViewsDelegate::views_delegate) {
views::ViewsDelegate::views_delegate->NotifyAccessibilityEvent(
- toast, ui::AccessibilityTypes::EVENT_ALERT);
+ toast, ui::AX_EVENT_ALERT);
}
- message_center_->DisplayedNotification((*iter)->id());
+ message_center_->DisplayedNotification(
+ (*iter)->id(), message_center::DISPLAY_SOURCE_POPUP);
}
}
@@ -496,24 +450,22 @@ void MessagePopupCollection::OnNotificationUpdated(
for (NotificationList::PopupNotifications::iterator iter =
notifications.begin(); iter != notifications.end(); ++iter) {
- if ((*iter)->id() != notification_id)
- continue;
+ Notification* notification = *iter;
+ DCHECK(notification);
+ ToastContentsView* toast_contents_view = *toast_iter;
+ DCHECK(toast_contents_view);
- bool expanded = true;
- if (IsExperimentalNotificationUIEnabled())
- expanded = (*iter)->is_expanded();
+ if (notification->id() != notification_id)
+ continue;
const RichNotificationData& optional_fields =
- (*iter)->rich_notification_data();
+ notification->rich_notification_data();
bool a11y_feedback_for_updates =
optional_fields.should_make_spoken_feedback_for_popup_updates;
- NotificationView* view =
- NotificationView::Create(*toast_iter,
- *(*iter),
- expanded,
- true); // Create top-level notification.
- (*toast_iter)->SetContents(view, a11y_feedback_for_updates);
+ toast_contents_view->UpdateContents(*notification,
+ a11y_feedback_for_updates);
+
updated = true;
}
@@ -556,6 +508,28 @@ void MessagePopupCollection::DecrementDeferCounter() {
// deferred tasks are even able to run)
// Then, see if there is vacant space for new toasts.
void MessagePopupCollection::DoUpdateIfPossible() {
+ if (!screen_) {
+ gfx::Display display;
+ if (!parent_) {
+ // On Win+Aura, we don't have a parent since the popups currently show up
+ // on the Windows desktop, not in the Aura/Ash desktop. This code will
+ // display the popups on the primary display.
+ screen_ = gfx::Screen::GetNativeScreen();
+ display = screen_->GetPrimaryDisplay();
+ } else {
+ screen_ = gfx::Screen::GetScreenFor(parent_);
+ display = screen_->GetDisplayNearestWindow(parent_);
+ }
+ screen_->AddObserver(this);
+
+ display_id_ = display.id();
+ // |work_area_| can be set already and it should not be overwritten here.
+ if (work_area_.IsEmpty()) {
+ work_area_ = display.work_area();
+ ComputePopupAlignment(work_area_, display.bounds());
+ }
+ }
+
if (defer_counter_ > 0)
return;
@@ -587,18 +561,24 @@ void MessagePopupCollection::SetDisplayInfo(const gfx::Rect& work_area,
RepositionWidgets();
}
-void MessagePopupCollection::OnDisplayBoundsChanged(
- const gfx::Display& display) {
- if (display.id() != display_id_)
- return;
-
- SetDisplayInfo(display.work_area(), display.bounds());
-}
-
void MessagePopupCollection::OnDisplayAdded(const gfx::Display& new_display) {
}
void MessagePopupCollection::OnDisplayRemoved(const gfx::Display& old_display) {
+ if (display_id_ == old_display.id() && !parent_) {
+ gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ display_id_ = display.id();
+ SetDisplayInfo(display.work_area(), display.bounds());
+ }
+}
+
+void MessagePopupCollection::OnDisplayMetricsChanged(
+ const gfx::Display& display, uint32_t metrics) {
+ if (display.id() != display_id_)
+ return;
+
+ if (metrics & DISPLAY_METRIC_BOUNDS || metrics & DISPLAY_METRIC_WORK_AREA)
+ SetDisplayInfo(display.work_area(), display.bounds());
}
views::Widget* MessagePopupCollection::GetWidgetForTest(const std::string& id)
diff --git a/chromium/ui/message_center/views/message_popup_collection.h b/chromium/ui/message_center/views/message_popup_collection.h
index 48345d80d75..955af32ddb5 100644
--- a/chromium/ui/message_center/views/message_popup_collection.h
+++ b/chromium/ui/message_center/views/message_popup_collection.h
@@ -35,6 +35,10 @@ class WebNotificationTrayTest;
FORWARD_DECLARE_TEST(WebNotificationTrayTest, ManyPopupNotifications);
}
+namespace gfx {
+class Screen;
+}
+
namespace message_center {
namespace test {
class MessagePopupCollectionTest;
@@ -42,6 +46,7 @@ class MessagePopupCollectionTest;
class MessageCenter;
class MessageCenterTray;
+class MessageViewContextMenuController;
enum PopupAlignment {
POPUP_ALIGNMENT_TOP = 1 << 0,
@@ -74,17 +79,12 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) OVERRIDE;
virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& notification_id,
int button_index) OVERRIDE;
- virtual void ExpandNotification(const std::string& notification_id) OVERRIDE;
- virtual void GroupBodyClicked(const std::string& last_notification_id)
- OVERRIDE;
- virtual void ExpandGroup(const NotifierId& notifier_id) OVERRIDE;
- virtual void RemoveGroup(const NotifierId& notifier_id) OVERRIDE;
void MarkAllPopupsShown();
@@ -111,7 +111,7 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// Updates |work_area_| and re-calculates the alignment of notification toasts
// rearranging them if necessary.
- // This is separated from methods from OnDisplayBoundsChanged(), since
+ // This is separated from methods from OnDisplayMetricsChanged(), since
// sometimes the display info has to be specified directly. One example is
// shelf's auto-hide change. When the shelf in ChromeOS is temporarily shown
// from auto hide status, it doesn't change the display's work area but the
@@ -120,9 +120,10 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
const gfx::Rect& screen_bounds);
// Overridden from gfx::DislayObserver:
- virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE;
virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
+ virtual void OnDisplayMetricsChanged(const gfx::Display& display,
+ uint32_t metrics) OVERRIDE;
// Used by ToastContentsView to locate itself.
gfx::NativeView parent() const { return parent_; }
@@ -188,6 +189,7 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
Toasts toasts_;
gfx::Rect work_area_;
int64 display_id_;
+ gfx::Screen* screen_;
// Specifies which corner of the screen popups should show up. This should
// ideally be the same corner the notification area (systray) is at.
@@ -216,6 +218,8 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// True if the first item should not have spacing against the tray.
bool first_item_has_no_margin_;
+ scoped_ptr<MessageViewContextMenuController> context_menu_controller_;
+
// Gives out weak pointers to toast contents views which have an unrelated
// lifetime. Must remain the last member variable.
base::WeakPtrFactory<MessagePopupCollection> weak_factory_;
diff --git a/chromium/ui/message_center/views/message_popup_collection_unittest.cc b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
index f763b516743..eacc6807726 100644
--- a/chromium/ui/message_center/views/message_popup_collection_unittest.cc
+++ b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
@@ -87,10 +87,10 @@ class MessagePopupCollectionTest : public views::ViewsTestBase {
scoped_ptr<Notification> notification(
new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
id,
- UTF8ToUTF16("test title"),
- UTF8ToUTF16("test message"),
+ base::UTF8ToUTF16("test title"),
+ base::UTF8ToUTF16("test message"),
gfx::Image(),
- string16() /* display_source */,
+ base::string16() /* display_source */,
NotifierId(),
message_center::RichNotificationData(),
NULL /* delegate */));
@@ -358,7 +358,7 @@ TEST_F(MessagePopupCollectionTest, DetectMouseHover) {
views::WidgetDelegateView* toast1 = GetToast(id1);
EXPECT_TRUE(toast1 != NULL);
- ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
// Test that mouse detection logic works in presence of out-of-order events.
toast0->OnMouseEntered(event);
@@ -393,7 +393,7 @@ TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) {
views::WidgetDelegateView* toast1 = GetToast(id1);
ASSERT_TRUE(toast1 != NULL);
- ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), 0, 0);
toast1->OnMouseEntered(event);
static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved(
id1, true);
diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc
index ccf1074b2e6..11ff5485f86 100644
--- a/chromium/ui/message_center/views/message_view.cc
+++ b/chromium/ui/message_center/views/message_view.cc
@@ -6,7 +6,7 @@
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
@@ -14,15 +14,14 @@
#include "ui/gfx/canvas.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_util.h"
#include "ui/message_center/views/padded_button.h"
-#include "ui/views/context_menu_controller.h"
+#include "ui/views/background.h"
#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/controls/image_view.h"
#include "ui/views/controls/scroll_view.h"
+#include "ui/views/focus/focus_manager.h"
#include "ui/views/painter.h"
#include "ui/views/shadow_border.h"
-#include "ui/views/widget/widget.h"
namespace {
@@ -32,161 +31,48 @@ const int kCloseIconRightPadding = 5;
const int kShadowOffset = 1;
const int kShadowBlur = 4;
-// Menu constants
-const int kTogglePermissionCommand = 0;
-const int kShowSettingsCommand = 1;
-
-// A dropdown menu for notifications.
-class MenuModel : public ui::SimpleMenuModel,
- public ui::SimpleMenuModel::Delegate {
- public:
- MenuModel(message_center::MessageViewController* controller,
- message_center::NotifierId notifier_id,
- const string16& display_source);
- virtual ~MenuModel();
-
- // Overridden from ui::SimpleMenuModel::Delegate:
- virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- private:
- message_center::MessageViewController* controller_;
- message_center::NotifierId notifier_id_;
- DISALLOW_COPY_AND_ASSIGN(MenuModel);
-};
-
-MenuModel::MenuModel(message_center::MessageViewController* controller,
- message_center::NotifierId notifier_id,
- const string16& display_source)
- : ui::SimpleMenuModel(this),
- controller_(controller),
- notifier_id_(notifier_id) {
- // Add 'disable notifications' menu item.
- if (!display_source.empty()) {
- AddItem(kTogglePermissionCommand,
- l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_NOTIFIER_DISABLE,
- display_source));
- }
- // Add settings menu item.
- AddItem(kShowSettingsCommand,
- l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS));
-}
-
-MenuModel::~MenuModel() {
-}
-
-bool MenuModel::IsItemForCommandIdDynamic(int command_id) const {
- return false;
-}
-
-bool MenuModel::IsCommandIdChecked(int command_id) const {
- return false;
-}
-
-bool MenuModel::IsCommandIdEnabled(int command_id) const {
- return true;
-}
-
-bool MenuModel::GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) {
- return false;
-}
-
-void MenuModel::ExecuteCommand(int command_id, int event_flags) {
- switch (command_id) {
- case kTogglePermissionCommand:
- controller_->DisableNotificationsFromThisSource(notifier_id_);
- break;
- case kShowSettingsCommand:
- controller_->ShowNotifierSettingsBubble();
- break;
- default:
- NOTREACHED();
- }
-}
-
} // namespace
namespace message_center {
-class MessageViewContextMenuController : public views::ContextMenuController {
- public:
- MessageViewContextMenuController(MessageViewController* controller,
- const NotifierId& notifier_id,
- const string16& display_source);
- virtual ~MessageViewContextMenuController();
-
- protected:
- // Overridden from views::ContextMenuController:
- virtual void ShowContextMenuForView(views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) OVERRIDE;
-
- MessageViewController* controller_; // Weak, owns us.
- NotifierId notifier_id_;
- string16 display_source_;
-};
-
-MessageViewContextMenuController::MessageViewContextMenuController(
- MessageViewController* controller,
- const NotifierId& notifier_id,
- const string16& display_source)
- : controller_(controller),
- notifier_id_(notifier_id),
- display_source_(display_source) {
-}
-
-MessageViewContextMenuController::~MessageViewContextMenuController() {
-}
-
-void MessageViewContextMenuController::ShowContextMenuForView(
- views::View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) {
- MenuModel menu_model(controller_, notifier_id_, display_source_);
- if (menu_model.GetItemCount() == 0)
- return;
-
- views::MenuRunner menu_runner(&menu_model);
-
- ignore_result(menu_runner.RunMenuAt(
- source->GetWidget()->GetTopLevelWidget(),
- NULL,
- gfx::Rect(point, gfx::Size()),
- views::MenuItemView::TOPRIGHT,
- source_type,
- views::MenuRunner::HAS_MNEMONICS));
-}
-
MessageView::MessageView(MessageViewController* controller,
const std::string& notification_id,
const NotifierId& notifier_id,
- const string16& display_source)
+ const gfx::ImageSkia& small_image,
+ const base::string16& display_source)
: controller_(controller),
notification_id_(notification_id),
notifier_id_(notifier_id),
- context_menu_controller_(
- new MessageViewContextMenuController(controller,
- notifier_id,
- display_source)),
- scroller_(NULL) {
+ background_view_(NULL),
+ scroller_(NULL),
+ display_source_(display_source) {
SetFocusable(true);
- set_context_menu_controller(context_menu_controller_.get());
+
+ // Create the opaque background that's above the view's shadow.
+ background_view_ = new views::View();
+ background_view_->set_background(
+ views::Background::CreateSolidBackground(kNotificationBackgroundColor));
+ AddChildView(background_view_);
+
+ views::ImageView* small_image_view = new views::ImageView();
+ small_image_view->SetImage(small_image);
+ small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
+ // The small image view should be added to view hierarchy by the derived
+ // class. This ensures that it is on top of other views.
+ small_image_view->set_owned_by_client();
+ small_image_view_.reset(small_image_view);
PaddedButton *close = new PaddedButton(this);
close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding);
close->SetNormalImage(IDR_NOTIFICATION_CLOSE);
close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER);
close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED);
- close->set_owned_by_client();
close->set_animate_on_state_change(false);
close->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
+ // The close button should be added to view hierarchy by the derived class.
+ // This ensures that it is on top of other views.
+ close->set_owned_by_client();
close_button_.reset(close);
focus_painter_ = views::Painter::CreateSolidFocusPainter(
@@ -197,6 +83,11 @@ MessageView::MessageView(MessageViewController* controller,
MessageView::~MessageView() {
}
+void MessageView::UpdateWithNotification(const Notification& notification) {
+ small_image_view_->SetImage(notification.small_image().AsImageSkia());
+ display_source_ = notification.display_source();
+}
+
// static
gfx::Insets MessageView::GetShadowInsets() {
return gfx::Insets(kShadowBlur / 2 - kShadowOffset,
@@ -206,10 +97,11 @@ gfx::Insets MessageView::GetShadowInsets() {
}
void MessageView::CreateShadowBorder() {
- set_border(new views::ShadowBorder(kShadowBlur,
- message_center::kShadowColor,
- kShadowOffset, // Vertical offset.
- 0)); // Horizontal offset.
+ SetBorder(scoped_ptr<views::Border>(
+ new views::ShadowBorder(kShadowBlur,
+ message_center::kShadowColor,
+ kShadowOffset, // Vertical offset.
+ 0))); // Horizontal offset.
}
bool MessageView::IsCloseButtonFocused() {
@@ -221,8 +113,8 @@ void MessageView::RequestFocusOnCloseButton() {
close_button_->RequestFocus();
}
-void MessageView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
+void MessageView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_BUTTON;
state->name = accessible_name_;
}
@@ -261,6 +153,8 @@ bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
}
void MessageView::OnPaint(gfx::Canvas* canvas) {
+ DCHECK_EQ(this, close_button_->parent());
+ DCHECK_EQ(this, small_image_view_->parent());
SlideOutView::OnPaint(canvas);
views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
@@ -277,6 +171,29 @@ void MessageView::OnBlur() {
SchedulePaint();
}
+void MessageView::Layout() {
+ gfx::Rect content_bounds = GetContentsBounds();
+
+ // Background.
+ background_view_->SetBoundsRect(content_bounds);
+
+ // Close button.
+ gfx::Size close_size(close_button_->GetPreferredSize());
+ gfx::Rect close_rect(content_bounds.right() - close_size.width(),
+ content_bounds.y(),
+ close_size.width(),
+ close_size.height());
+ close_button_->SetBoundsRect(close_rect);
+
+ gfx::Size small_image_size(small_image_view_->GetPreferredSize());
+ gfx::Rect small_image_rect(small_image_size);
+ small_image_rect.set_origin(gfx::Point(
+ content_bounds.right() - small_image_size.width() - kSmallImagePadding,
+ content_bounds.bottom() - small_image_size.height() -
+ kSmallImagePadding));
+ small_image_view_->SetBoundsRect(small_image_rect);
+}
+
void MessageView::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_TAP) {
controller_->ClickOnNotification(notification_id_);
diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h
index ba42e3fc73c..04f4d97a06b 100644
--- a/chromium/ui/message_center/views/message_view.h
+++ b/chromium/ui/message_center/views/message_view.h
@@ -13,8 +13,13 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/slide_out_view.h"
+namespace ui {
+class MenuModel;
+}
+
namespace views {
class ImageButton;
+class ImageView;
class Painter;
class ScrollView;
}
@@ -28,29 +33,29 @@ class MessageViewController {
virtual void ClickOnNotification(const std::string& notification_id) = 0;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) = 0;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) = 0;
- virtual void ShowNotifierSettingsBubble() = 0;
};
-class MessageViewContextMenuController;
-
// Individual notifications constants.
const int kPaddingBetweenItems = 10;
const int kPaddingHorizontal = 18;
const int kWebNotificationButtonWidth = 32;
const int kWebNotificationIconSize = 40;
-// An abstract class that forms the basis of a view for a notification entry.
+// An base class for a notification entry. Contains background, close button
+// and other elements shared by derived notification views.
class MESSAGE_CENTER_EXPORT MessageView : public views::SlideOutView,
public views::ButtonListener {
public:
MessageView(MessageViewController* controller,
const std::string& notification_id,
const NotifierId& notifier_id,
- const string16& display_source);
+ const gfx::ImageSkia& small_image,
+ const base::string16& display_source);
virtual ~MessageView();
+ // Updates this view with the new data contained in the notification.
+ virtual void UpdateWithNotification(const Notification& notification);
+
// Returns the insets for the shadow it will have for rich notification.
static gfx::Insets GetShadowInsets();
@@ -60,16 +65,19 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::SlideOutView,
bool IsCloseButtonFocused();
void RequestFocusOnCloseButton();
- void set_accessible_name(const string16& name) { accessible_name_ = name; }
+ void set_accessible_name(const base::string16& accessible_name) {
+ accessible_name_ = accessible_name;
+ }
// Overridden from views::View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
+ virtual void Layout() OVERRIDE;
// Overridden from ui::EventHandler:
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
@@ -81,11 +89,13 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::SlideOutView,
void set_scroller(views::ScrollView* scroller) { scroller_ = scroller; }
std::string notification_id() { return notification_id_; }
NotifierId notifier_id() { return notifier_id_; }
+ const base::string16& display_source() const { return display_source_; }
protected:
// Overridden from views::SlideOutView:
virtual void OnSlideOut() OVERRIDE;
+ views::ImageView* small_image() { return small_image_view_.get(); }
views::ImageButton* close_button() { return close_button_.get(); }
views::ScrollView* scroller() { return scroller_; }
@@ -93,11 +103,14 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::SlideOutView,
MessageViewController* controller_;
std::string notification_id_;
NotifierId notifier_id_;
- scoped_ptr<MessageViewContextMenuController> context_menu_controller_;
+ views::View* background_view_; // Owned by views hierarchy.
scoped_ptr<views::ImageButton> close_button_;
+ scoped_ptr<views::ImageView> small_image_view_;
views::ScrollView* scroller_;
- string16 accessible_name_;
+ base::string16 accessible_name_;
+
+ base::string16 display_source_;
scoped_ptr<views::Painter> focus_painter_;
diff --git a/chromium/ui/message_center/views/message_view_context_menu_controller.cc b/chromium/ui/message_center/views/message_view_context_menu_controller.cc
new file mode 100644
index 00000000000..3edaa29faa7
--- /dev/null
+++ b/chromium/ui/message_center/views/message_view_context_menu_controller.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/message_center/views/message_view_context_menu_controller.h"
+
+#include "ui/base/models/menu_model.h"
+#include "ui/message_center/views/message_center_controller.h"
+#include "ui/message_center/views/message_view.h"
+#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/widget/widget.h"
+
+namespace message_center {
+
+MessageViewContextMenuController::MessageViewContextMenuController(
+ MessageCenterController* controller)
+ : controller_(controller) {
+}
+
+MessageViewContextMenuController::~MessageViewContextMenuController() {
+}
+
+void MessageViewContextMenuController::ShowContextMenuForView(
+ views::View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) {
+ // Assumes that the target view has to be MessageView.
+ MessageView* message_view = static_cast<MessageView*>(source);
+ scoped_ptr<ui::MenuModel> menu_model(controller_->CreateMenuModel(
+ message_view->notifier_id(), message_view->display_source()));
+
+ if (!menu_model || menu_model->GetItemCount() == 0)
+ return;
+
+ views::MenuRunner menu_runner(menu_model.get());
+
+ ignore_result(menu_runner.RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
+ NULL,
+ gfx::Rect(point, gfx::Size()),
+ views::MENU_ANCHOR_TOPRIGHT,
+ source_type,
+ views::MenuRunner::HAS_MNEMONICS));
+}
+
+} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_view_context_menu_controller.h b/chromium/ui/message_center/views/message_view_context_menu_controller.h
new file mode 100644
index 00000000000..5ee39de1a07
--- /dev/null
+++ b/chromium/ui/message_center/views/message_view_context_menu_controller.h
@@ -0,0 +1,34 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_
+#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/context_menu_controller.h"
+
+namespace message_center {
+class MessageCenterController;
+
+class MessageViewContextMenuController : public views::ContextMenuController {
+ public:
+ explicit MessageViewContextMenuController(
+ MessageCenterController* controller);
+ virtual ~MessageViewContextMenuController();
+
+ private:
+ // Overridden from views::ContextMenuController:
+ virtual void ShowContextMenuForView(views::View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) OVERRIDE;
+
+ MessageCenterController* controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageViewContextMenuController);
+};
+
+} // namespace message_center
+
+#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_
diff --git a/chromium/ui/message_center/views/notification_button.cc b/chromium/ui/message_center/views/notification_button.cc
index 7ef5295ad22..75219e8d3dc 100644
--- a/chromium/ui/message_center/views/notification_button.cc
+++ b/chromium/ui/message_center/views/notification_button.cc
@@ -48,13 +48,13 @@ void NotificationButton::SetIcon(const gfx::ImageSkia& image) {
icon_->SetImage(image);
icon_->SetHorizontalAlignment(views::ImageView::LEADING);
icon_->SetVerticalAlignment(views::ImageView::LEADING);
- icon_->set_border(views::Border::CreateEmptyBorder(
+ icon_->SetBorder(views::Border::CreateEmptyBorder(
message_center::kButtonIconTopPadding, 0, 0, 0));
AddChildViewAt(icon_, 0);
}
}
-void NotificationButton::SetTitle(const string16& title) {
+void NotificationButton::SetTitle(const base::string16& title) {
if (title_ != NULL)
delete title_; // This removes the title from this view's children.
if (title.empty()) {
@@ -64,19 +64,19 @@ void NotificationButton::SetTitle(const string16& title) {
title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
title_->SetEnabledColor(message_center::kRegularTextColor);
title_->SetBackgroundColor(kRegularTextBackgroundColor);
- title_->set_border(views::Border::CreateEmptyBorder(
- kButtonTitleTopPadding, 0, 0, 0));
+ title_->SetBorder(
+ views::Border::CreateEmptyBorder(kButtonTitleTopPadding, 0, 0, 0));
AddChildView(title_);
}
SetAccessibleName(title);
}
-gfx::Size NotificationButton::GetPreferredSize() {
+gfx::Size NotificationButton::GetPreferredSize() const {
return gfx::Size(message_center::kNotificationWidth,
message_center::kButtonHeight);
}
-int NotificationButton::GetHeightForWidth(int width) {
+int NotificationButton::GetHeightForWidth(int width) const {
return message_center::kButtonHeight;
}
@@ -98,6 +98,14 @@ void NotificationButton::OnBlur() {
SchedulePaint();
}
+void NotificationButton::ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) {
+ // We disable view hierarchy change detection in the parent
+ // because it resets the hoverstate, which we do not want
+ // when we update the view to contain a new label or image.
+ views::View::ViewHierarchyChanged(details);
+}
+
void NotificationButton::StateChanged() {
if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
set_background(views::Background::CreateSolidBackground(
diff --git a/chromium/ui/message_center/views/notification_button.h b/chromium/ui/message_center/views/notification_button.h
index 7d3c52ce1ea..b5ac0f12981 100644
--- a/chromium/ui/message_center/views/notification_button.h
+++ b/chromium/ui/message_center/views/notification_button.h
@@ -24,14 +24,16 @@ class NotificationButton : public views::CustomButton {
virtual ~NotificationButton();
void SetIcon(const gfx::ImageSkia& icon);
- void SetTitle(const string16& title);
+ void SetTitle(const base::string16& title);
// Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
+ virtual void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) OVERRIDE;
// Overridden from views::CustomButton:
virtual void StateChanged() OVERRIDE;
diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc
index 4a5d67326be..be77657f6e0 100644
--- a/chromium/ui/message_center/views/notification_view.cc
+++ b/chromium/ui/message_center/views/notification_view.cc
@@ -5,10 +5,12 @@
#include "ui/message_center/views/notification_view.h"
#include "base/command_line.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
@@ -18,8 +20,6 @@
#include "ui/gfx/text_elider.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_switches.h"
-#include "ui/message_center/message_center_util.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_types.h"
#include "ui/message_center/views/bounded_label.h"
@@ -37,35 +37,27 @@
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/native_cursor.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
namespace {
// Dimensions.
const int kProgressBarWidth = message_center::kNotificationWidth -
message_center::kTextLeftPadding - message_center::kTextRightPadding;
const int kProgressBarBottomPadding = 0;
-const int kExpandIconBottomPadding = 8;
-const int kExpandIconRightPadding = 11;
-
-// static
-views::Background* MakeBackground(
- SkColor color = message_center::kNotificationBackgroundColor) {
- return views::Background::CreateSolidBackground(color);
-}
// static
-views::Border* MakeEmptyBorder(int top, int left, int bottom, int right) {
+scoped_ptr<views::Border> MakeEmptyBorder(int top,
+ int left,
+ int bottom,
+ int right) {
return views::Border::CreateEmptyBorder(top, left, bottom, right);
}
// static
-views::Border* MakeTextBorder(int padding, int top, int bottom) {
+scoped_ptr<views::Border> MakeTextBorder(int padding, int top, int bottom) {
// Split the padding between the top and the bottom, then add the extra space.
return MakeEmptyBorder(padding / 2 + top,
message_center::kTextLeftPadding,
@@ -74,7 +66,7 @@ views::Border* MakeTextBorder(int padding, int top, int bottom) {
}
// static
-views::Border* MakeProgressBarBorder(int top, int bottom) {
+scoped_ptr<views::Border> MakeProgressBarBorder(int top, int bottom) {
return MakeEmptyBorder(top,
message_center::kTextLeftPadding,
bottom,
@@ -82,7 +74,9 @@ views::Border* MakeProgressBarBorder(int top, int bottom) {
}
// static
-views::Border* MakeSeparatorBorder(int top, int left, SkColor color) {
+scoped_ptr<views::Border> MakeSeparatorBorder(int top,
+ int left,
+ SkColor color) {
return views::Border::CreateSolidSidedBorder(top, left, 0, 0, color);
}
@@ -90,16 +84,12 @@ views::Border* MakeSeparatorBorder(int top, int left, SkColor color) {
// Return true if and only if the image is null or has alpha.
bool HasAlpha(gfx::ImageSkia& image, views::Widget* widget) {
// Determine which bitmap to use.
- ui::ScaleFactor factor = ui::SCALE_FACTOR_100P;
- if (widget) {
+ float factor = 1.0f;
+ if (widget)
factor = ui::GetScaleFactorForNativeView(widget->GetNativeView());
- if (factor == ui::SCALE_FACTOR_NONE)
- factor = ui::SCALE_FACTOR_100P;
- }
// Extract that bitmap's alpha and look for a non-opaque pixel there.
- SkBitmap bitmap =
- image.GetRepresentation(ui::GetImageScale(factor)).sk_bitmap();
+ SkBitmap bitmap = image.GetRepresentation(factor).sk_bitmap();
if (!bitmap.isNull()) {
SkBitmap alpha;
bitmap.extractAlpha(&alpha);
@@ -175,19 +165,20 @@ views::View* MakeNotificationImage(const gfx::Image& image, gfx::Size size) {
container->set_background(views::Background::CreateSolidBackground(
message_center::kImageBackgroundColor));
- views::View* proportional_image_view =
- new message_center::ProportionalImageView(image.AsImageSkia());
-
gfx::Size ideal_size(
message_center::kNotificationPreferredImageWidth,
message_center::kNotificationPreferredImageHeight);
- gfx::Size scaled_size = message_center::GetImageSizeForWidth(
- message_center::kNotificationPreferredImageWidth, image.Size());
+ gfx::Size scaled_size =
+ message_center::GetImageSizeForContainerSize(ideal_size, image.Size());
+
+ views::View* proportional_image_view =
+ new message_center::ProportionalImageView(image.AsImageSkia(),
+ ideal_size);
// This calculation determines that the new image would have the correct
// height for width.
if (ideal_size != scaled_size) {
- proportional_image_view->set_border(views::Border::CreateSolidBorder(
+ proportional_image_view->SetBorder(views::Border::CreateSolidBorder(
message_center::kNotificationImageBorderSize, SK_ColorTRANSPARENT));
}
@@ -204,7 +195,7 @@ class NotificationProgressBar : public views::ProgressBar {
private:
// Overriden from View
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(NotificationProgressBar);
@@ -216,7 +207,7 @@ NotificationProgressBar::NotificationProgressBar() {
NotificationProgressBar::~NotificationProgressBar() {
}
-gfx::Size NotificationProgressBar::GetPreferredSize() {
+gfx::Size NotificationProgressBar::GetPreferredSize() const {
gfx::Size pref_size(kProgressBarWidth, message_center::kProgressBarThickness);
gfx::Insets insets = GetInsets();
pref_size.Enlarge(insets.width(), insets.height());
@@ -265,7 +256,6 @@ namespace message_center {
// static
NotificationView* NotificationView::Create(MessageCenterController* controller,
const Notification& notification,
- bool expanded,
bool top_level) {
switch (notification.type()) {
case NOTIFICATION_TYPE_BASE_FORMAT:
@@ -287,7 +277,7 @@ NotificationView* NotificationView::Create(MessageCenterController* controller,
// Currently all roads lead to the generic NotificationView.
NotificationView* notification_view =
- new NotificationView(controller, notification, expanded);
+ new NotificationView(controller, notification);
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Don't create shadows for notification toasts on linux wih aura.
@@ -299,192 +289,86 @@ NotificationView* NotificationView::Create(MessageCenterController* controller,
return notification_view;
}
+void NotificationView::CreateOrUpdateViews(const Notification& notification) {
+ CreateOrUpdateTitleView(notification);
+ CreateOrUpdateMessageView(notification);
+ CreateOrUpdateContextMessageView(notification);
+ CreateOrUpdateProgressBarView(notification);
+ CreateOrUpdateListItemViews(notification);
+ CreateOrUpdateIconView(notification);
+ CreateOrUpdateImageView(notification);
+ CreateOrUpdateActionButtonViews(notification);
+}
+
+void NotificationView::SetAccessibleName(const Notification& notification) {
+ std::vector<base::string16> accessible_lines;
+ accessible_lines.push_back(notification.title());
+ accessible_lines.push_back(notification.message());
+ accessible_lines.push_back(notification.context_message());
+ std::vector<NotificationItem> items = notification.items();
+ for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
+ accessible_lines.push_back(items[i].title + base::ASCIIToUTF16(" ") +
+ items[i].message);
+ }
+ set_accessible_name(JoinString(accessible_lines, '\n'));
+}
+
NotificationView::NotificationView(MessageCenterController* controller,
- const Notification& notification,
- bool expanded)
+ const Notification& notification)
: MessageView(this,
notification.id(),
notification.notifier_id(),
+ notification.small_image().AsImageSkia(),
notification.display_source()),
controller_(controller),
clickable_(notification.clickable()),
- is_expanded_(expanded) {
- std::vector<string16> accessible_lines;
-
- // Create the opaque background that's above the view's shadow.
- background_view_ = new views::View();
- background_view_->set_background(MakeBackground());
-
+ top_view_(NULL),
+ title_view_(NULL),
+ message_view_(NULL),
+ context_message_view_(NULL),
+ icon_view_(NULL),
+ bottom_view_(NULL),
+ image_view_(NULL),
+ progress_bar_view_(NULL) {
// 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.
top_view_ = new views::View();
top_view_->SetLayoutManager(
new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
- top_view_->set_border(MakeEmptyBorder(
- kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0));
-
- const gfx::FontList default_label_font_list = views::Label().font_list();
-
- // Create the title view if appropriate.
- title_view_ = NULL;
- if (!notification.title().empty()) {
- const gfx::FontList& font_list =
- default_label_font_list.DeriveFontListWithSizeDelta(2);
- int padding = kTitleLineHeight - font_list.GetHeight();
- title_view_ = new BoundedLabel(
- gfx::TruncateString(notification.title(), kTitleCharacterLimit),
- font_list);
- title_view_->SetLineHeight(kTitleLineHeight);
- title_view_->SetLineLimit(IsExperimentalNotificationUIEnabled() ?
- message_center::kExperimentalTitleLineLimit :
- message_center::kTitleLineLimit);
- title_view_->SetColors(message_center::kRegularTextColor,
- kRegularTextBackgroundColor);
- title_view_->set_border(MakeTextBorder(padding, 3, 0));
- top_view_->AddChildView(title_view_);
- accessible_lines.push_back(notification.title());
- }
-
- // Create the message view if appropriate.
- message_view_ = NULL;
- if (!notification.message().empty()) {
- int padding = kMessageLineHeight - default_label_font_list.GetHeight();
- message_view_ = new BoundedLabel(
- gfx::TruncateString(notification.message(), kMessageCharacterLimit));
- message_view_->SetLineHeight(kMessageLineHeight);
- message_view_->SetVisible(!is_expanded_ || !notification.items().size());
- message_view_->SetColors(message_center::kRegularTextColor,
- kDimTextBackgroundColor);
- message_view_->set_border(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(message_view_);
- accessible_lines.push_back(notification.message());
- }
-
- // Create the context message view if appropriate.
- context_message_view_ = NULL;
- if (!notification.context_message().empty()) {
- int padding = kMessageLineHeight - default_label_font_list.GetHeight();
- context_message_view_ =
- new BoundedLabel(gfx::TruncateString(notification.context_message(),
- kContextMessageCharacterLimit),
- default_label_font_list);
- context_message_view_->SetLineLimit(
- message_center::kContextMessageLineLimit);
- context_message_view_->SetLineHeight(kMessageLineHeight);
- context_message_view_->SetColors(message_center::kDimTextColor,
- kContextTextBackgroundColor);
- context_message_view_->set_border(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(context_message_view_);
- accessible_lines.push_back(notification.context_message());
- }
-
- // Create the progress bar view.
- progress_bar_view_ = NULL;
- if (notification.type() == NOTIFICATION_TYPE_PROGRESS) {
- progress_bar_view_ = new NotificationProgressBar();
- progress_bar_view_->set_border(MakeProgressBarBorder(
- message_center::kProgressBarTopPadding, kProgressBarBottomPadding));
- progress_bar_view_->SetValue(notification.progress() / 100.0);
- top_view_->AddChildView(progress_bar_view_);
- }
-
- // Create the list item views (up to a maximum).
- int padding = kMessageLineHeight - default_label_font_list.GetHeight();
- std::vector<NotificationItem> items = notification.items();
- for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
- ItemView* item_view = new ItemView(items[i]);
- item_view->SetVisible(is_expanded_);
- item_view->set_border(MakeTextBorder(padding, i ? 0 : 4, 0));
- item_views_.push_back(item_view);
- top_view_->AddChildView(item_view);
- accessible_lines.push_back(
- items[i].title + base::ASCIIToUTF16(" ") + items[i].message);
- }
-
- // Create the notification icon view.
- gfx::ImageSkia icon = notification.icon().AsImageSkia();
- if (notification.type() == NOTIFICATION_TYPE_SIMPLE &&
- (icon.width() != kIconSize ||
- icon.height() != kIconSize ||
- HasAlpha(icon, GetWidget()))) {
- views::ImageView* icon_view = new views::ImageView();
- icon_view->SetImage(icon);
- icon_view->SetImageSize(gfx::Size(kLegacyIconSize, kLegacyIconSize));
- icon_view->SetHorizontalAlignment(views::ImageView::CENTER);
- icon_view->SetVerticalAlignment(views::ImageView::CENTER);
- icon_view_ = icon_view;
- } else {
- icon_view_ = new ProportionalImageView(icon);
- }
-
- icon_view_->set_background(MakeBackground(kIconBackgroundColor));
-
+ top_view_->SetBorder(
+ MakeEmptyBorder(kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0));
+ AddChildView(top_view_);
// Create the bottom_view_, which collects into a vertical box all content
- // below the notification icon except for the expand button.
+ // below the notification icon.
bottom_view_ = new views::View();
bottom_view_->SetLayoutManager(
new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+ AddChildView(bottom_view_);
- // Create the image view if appropriate.
- image_view_ = NULL;
- if (!notification.image().IsEmpty()) {
- gfx::Size image_size(
- kNotificationPreferredImageWidth, kNotificationPreferredImageHeight);
- image_view_ = MakeNotificationImage(notification.image(), image_size);
- image_view_->SetVisible(is_expanded_);
- bottom_view_->AddChildView(image_view_);
- }
-
- // Create action buttons if appropriate.
- std::vector<ButtonInfo> buttons = notification.buttons();
- for (size_t i = 0; i < buttons.size(); ++i) {
- views::View* separator = new views::ImageView();
- separator->set_border(MakeSeparatorBorder(1, 0, kButtonSeparatorColor));
- bottom_view_->AddChildView(separator);
- NotificationButton* button = new NotificationButton(this);
- ButtonInfo button_info = buttons[i];
- button->SetTitle(button_info.title);
- button->SetIcon(button_info.icon.AsImageSkia());
- action_buttons_.push_back(button);
- bottom_view_->AddChildView(button);
- }
-
- // Create expand button
- expand_button_ = new PaddedButton(this);
- expand_button_->SetPadding(-kExpandIconRightPadding,
- -kExpandIconBottomPadding);
- expand_button_->SetNormalImage(IDR_NOTIFICATION_EXPAND);
- expand_button_->SetHoveredImage(IDR_NOTIFICATION_EXPAND_HOVER);
- expand_button_->SetPressedImage(IDR_NOTIFICATION_EXPAND_PRESSED);
- expand_button_->set_animate_on_state_change(false);
- expand_button_->SetAccessibleName(l10n_util::GetStringUTF16(
- IDS_MESSAGE_CENTER_EXPAND_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
+ CreateOrUpdateViews(notification);
// Put together the different content and control views. Layering those allows
- // for proper layout logic and it also allows the close and expand buttons to
- // overlap the content as needed to provide large enough click and touch areas
- // (<http://crbug.com/168822> and <http://crbug.com/168856>).
- AddChildView(background_view_);
- AddChildView(top_view_);
- AddChildView(icon_view_);
- AddChildView(bottom_view_);
+ // for proper layout logic and it also allows the close button and small
+ // image to overlap the content as needed to provide large enough click and
+ // touch areas (<http://crbug.com/168822> and <http://crbug.com/168856>).
+ AddChildView(small_image());
AddChildView(close_button());
- AddChildView(expand_button_);
- set_accessible_name(JoinString(accessible_lines, '\n'));
+ SetAccessibleName(notification);
}
NotificationView::~NotificationView() {
}
-gfx::Size NotificationView::GetPreferredSize() {
- int top_width = top_view_->GetPreferredSize().width();
+gfx::Size NotificationView::GetPreferredSize() const {
+ int top_width = top_view_->GetPreferredSize().width() +
+ icon_view_->GetPreferredSize().width();
int bottom_width = bottom_view_->GetPreferredSize().width();
int preferred_width = std::max(top_width, bottom_width) + GetInsets().width();
return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
}
-int NotificationView::GetHeightForWidth(int width) {
+int NotificationView::GetHeightForWidth(int width) const {
// Get the height assuming no line limit changes.
int content_width = width - GetInsets().width();
int top_height = top_view_->GetHeightForWidth(content_width);
@@ -494,8 +378,13 @@ int NotificationView::GetHeightForWidth(int width) {
// line limit would be different for the specified width than it currently is.
// TODO(dharcourt): Avoid BoxLayout and directly compute the correct height.
if (message_view_) {
+ int title_lines = 0;
+ if (title_view_) {
+ title_lines = title_view_->GetLinesForWidthAndLimit(width,
+ kMaxTitleLines);
+ }
int used_limit = message_view_->GetLineLimit();
- int correct_limit = GetMessageLineLimit(width);
+ int correct_limit = GetMessageLineLimit(title_lines, width);
if (used_limit != correct_limit) {
top_height -= GetMessageHeight(content_width, used_limit);
top_height += GetMessageHeight(content_width, correct_limit);
@@ -514,17 +403,18 @@ int NotificationView::GetHeightForWidth(int width) {
}
void NotificationView::Layout() {
+ MessageView::Layout();
gfx::Insets insets = GetInsets();
int content_width = width() - insets.width();
- int content_right = width() - insets.right();
// Before any resizing, set or adjust the number of message lines.
+ int title_lines = 0;
+ if (title_view_) {
+ title_lines =
+ title_view_->GetLinesForWidthAndLimit(width(), kMaxTitleLines);
+ }
if (message_view_)
- message_view_->SetLineLimit(GetMessageLineLimit(width()));
-
- // Background.
- background_view_->SetBounds(insets.left(), insets.top(),
- content_width, height() - insets.height());
+ message_view_->SetLineLimit(GetMessageLineLimit(title_lines, width()));
// Top views.
int top_height = top_view_->GetHeightForWidth(content_width);
@@ -538,18 +428,6 @@ void NotificationView::Layout() {
int bottom_height = bottom_view_->GetHeightForWidth(content_width);
bottom_view_->SetBounds(insets.left(), bottom_y,
content_width, bottom_height);
-
- // Close button.
- gfx::Size close_size(close_button()->GetPreferredSize());
- close_button()->SetBounds(content_right - close_size.width(), insets.top(),
- close_size.width(), close_size.height());
-
- // Expand button.
- gfx::Size expand_size(expand_button_->GetPreferredSize());
- int expand_y = bottom_y - expand_size.height();
- expand_button_->SetVisible(IsExpansionNeeded(width()));
- expand_button_->SetBounds(content_right - expand_size.width(), expand_y,
- expand_size.width(), expand_size.height());
}
void NotificationView::OnFocus() {
@@ -571,9 +449,9 @@ views::View* NotificationView::GetEventHandlerForRect(const gfx::Rect& rect) {
// 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_);
+ std::vector<views::View*> buttons(action_buttons_.begin(),
+ action_buttons_.end());
buttons.push_back(close_button());
- buttons.push_back(expand_button_);
for (size_t i = 0; i < buttons.size(); ++i) {
gfx::Point point_in_child = point;
@@ -589,38 +467,33 @@ gfx::NativeCursor NotificationView::GetCursor(const ui::MouseEvent& event) {
if (!clickable_ || !controller_->HasClickedListener(notification_id()))
return views::View::GetCursor(event);
-#if defined(USE_AURA)
- return ui::kCursorHand;
-#elif defined(OS_WIN)
- static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND);
- return g_hand_cursor;
-#endif
+ return views::GetNativeHandCursor();
+}
+
+void NotificationView::UpdateWithNotification(
+ const Notification& notification) {
+ MessageView::UpdateWithNotification(notification);
+
+ CreateOrUpdateViews(notification);
+ SetAccessibleName(notification);
+ Layout();
+ SchedulePaint();
}
void NotificationView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
+ // Certain operations can cause |this| to be destructed, so copy the members
+ // we send to other parts of the code.
+ // TODO(dewittj): Remove this hack.
+ std::string id(notification_id());
// See if the button pressed was an action button.
for (size_t i = 0; i < action_buttons_.size(); ++i) {
if (sender == action_buttons_[i]) {
- controller_->ClickOnNotificationButton(notification_id(), i);
+ controller_->ClickOnNotificationButton(id, i);
return;
}
}
- // Adjust notification subviews for expansion.
- if (sender == expand_button_) {
- if (message_view_ && item_views_.size())
- message_view_->SetVisible(false);
- for (size_t i = 0; i < item_views_.size(); ++i)
- item_views_[i]->SetVisible(true);
- if (image_view_)
- image_view_->SetVisible(true);
-
- is_expanded_ = true;
- controller_->ExpandNotification(notification_id());
- return;
- }
-
// Let the superclass handled anything other than action buttons.
// Warning: This may cause the NotificationView itself to be deleted,
// so don't do anything afterwards.
@@ -636,34 +509,256 @@ void NotificationView::RemoveNotification(const std::string& notification_id,
controller_->RemoveNotification(notification_id, by_user);
}
-void NotificationView::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- controller_->DisableNotificationsFromThisSource(notifier_id);
+void NotificationView::CreateOrUpdateTitleView(
+ const Notification& notification) {
+ if (notification.title().empty()) {
+ if (title_view_) {
+ // Deletion will also remove |title_view_| from its parent.
+ delete title_view_;
+ title_view_ = NULL;
+ }
+ return;
+ }
+
+ DCHECK(top_view_ != NULL);
+
+ const gfx::FontList& font_list =
+ views::Label().font_list().DeriveWithSizeDelta(2);
+
+ int title_character_limit =
+ kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter;
+
+ if (!title_view_) {
+ int padding = kTitleLineHeight - font_list.GetHeight();
+
+ title_view_ = new BoundedLabel(
+ gfx::TruncateString(notification.title(), title_character_limit),
+ font_list);
+ title_view_->SetLineHeight(kTitleLineHeight);
+ title_view_->SetLineLimit(kMaxTitleLines);
+ title_view_->SetColors(message_center::kRegularTextColor,
+ kRegularTextBackgroundColor);
+ title_view_->SetBorder(MakeTextBorder(padding, 3, 0));
+ top_view_->AddChildView(title_view_);
+ } else {
+ title_view_->SetText(
+ gfx::TruncateString(notification.title(), title_character_limit));
+ }
+}
+
+void NotificationView::CreateOrUpdateMessageView(
+ const Notification& notification) {
+ if (notification.message().empty()) {
+ if (message_view_) {
+ // Deletion will also remove |message_view_| from its parent.
+ delete message_view_;
+ message_view_ = NULL;
+ }
+ return;
+ }
+
+ DCHECK(top_view_ != NULL);
+
+ if (!message_view_) {
+ int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
+ message_view_ = new BoundedLabel(
+ gfx::TruncateString(notification.message(), kMessageCharacterLimit));
+ message_view_->SetLineHeight(kMessageLineHeight);
+ message_view_->SetColors(message_center::kRegularTextColor,
+ kDimTextBackgroundColor);
+ message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
+ top_view_->AddChildView(message_view_);
+ } else {
+ message_view_->SetText(
+ gfx::TruncateString(notification.message(), kMessageCharacterLimit));
+ }
+
+ message_view_->SetVisible(!notification.items().size());
}
-void NotificationView::ShowNotifierSettingsBubble() {
- controller_->ShowNotifierSettingsBubble();
+void NotificationView::CreateOrUpdateContextMessageView(
+ const Notification& notification) {
+ if (notification.context_message().empty()) {
+ if (context_message_view_) {
+ // Deletion will also remove |context_message_view_| from its parent.
+ delete context_message_view_;
+ context_message_view_ = NULL;
+ }
+ return;
+ }
+
+ DCHECK(top_view_ != NULL);
+
+ if (!context_message_view_) {
+ int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
+ context_message_view_ = new BoundedLabel(gfx::TruncateString(
+ notification.context_message(), kContextMessageCharacterLimit));
+ context_message_view_->SetLineLimit(
+ message_center::kContextMessageLineLimit);
+ context_message_view_->SetLineHeight(kMessageLineHeight);
+ context_message_view_->SetColors(message_center::kDimTextColor,
+ kContextTextBackgroundColor);
+ context_message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
+ top_view_->AddChildView(context_message_view_);
+ } else {
+ context_message_view_->SetText(gfx::TruncateString(
+ notification.context_message(), kContextMessageCharacterLimit));
+ }
}
-bool NotificationView::IsExpansionNeeded(int width) {
- return (!is_expanded_ &&
- (image_view_ ||
- item_views_.size() ||
- IsMessageExpansionNeeded(width)));
+void NotificationView::CreateOrUpdateProgressBarView(
+ const Notification& notification) {
+ if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
+ if (progress_bar_view_) {
+ // Deletion will also remove |progress_bar_view_| from its parent.
+ delete progress_bar_view_;
+ progress_bar_view_ = NULL;
+ }
+ return;
+ }
+
+ DCHECK(top_view_ != NULL);
+
+ if (!progress_bar_view_) {
+ progress_bar_view_ = new NotificationProgressBar();
+ progress_bar_view_->SetBorder(MakeProgressBarBorder(
+ message_center::kProgressBarTopPadding, kProgressBarBottomPadding));
+ top_view_->AddChildView(progress_bar_view_);
+ }
+
+ progress_bar_view_->SetValue(notification.progress() / 100.0);
+ progress_bar_view_->SetVisible(!notification.items().size());
}
-bool NotificationView::IsMessageExpansionNeeded(int width) {
- int current = GetMessageLines(width, GetMessageLineLimit(width));
- int expanded = GetMessageLines(width,
- message_center::kMessageExpandedLineLimit);
- return current < expanded;
+void NotificationView::CreateOrUpdateListItemViews(
+ const Notification& notification) {
+ for (size_t i = 0; i < item_views_.size(); ++i)
+ delete item_views_[i];
+ item_views_.clear();
+
+ int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
+ std::vector<NotificationItem> items = notification.items();
+
+ if (items.size() == 0)
+ return;
+
+ DCHECK(top_view_);
+ for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
+ ItemView* item_view = new ItemView(items[i]);
+ item_view->SetBorder(MakeTextBorder(padding, i ? 0 : 4, 0));
+ item_views_.push_back(item_view);
+ top_view_->AddChildView(item_view);
+ }
}
-int NotificationView::GetMessageLineLimit(int width) {
- // Expanded notifications get a larger limit, except for image notifications,
- // whose images must be kept flush against their icons.
- if (is_expanded_ && !image_view_)
- return message_center::kMessageExpandedLineLimit;
+void NotificationView::CreateOrUpdateIconView(
+ const Notification& notification) {
+ if (icon_view_) {
+ delete icon_view_;
+ icon_view_ = NULL;
+ }
+
+ // TODO(dewittj): Detect a compatible update and use the existing icon view.
+ gfx::ImageSkia icon = notification.icon().AsImageSkia();
+ if (notification.type() == NOTIFICATION_TYPE_SIMPLE &&
+ (icon.width() != kIconSize || icon.height() != kIconSize ||
+ HasAlpha(icon, GetWidget()))) {
+ views::ImageView* icon_view = new views::ImageView();
+ icon_view->SetImage(icon);
+ icon_view->SetImageSize(gfx::Size(kLegacyIconSize, kLegacyIconSize));
+ icon_view->SetHorizontalAlignment(views::ImageView::CENTER);
+ icon_view->SetVerticalAlignment(views::ImageView::CENTER);
+ icon_view_ = icon_view;
+ } else {
+ icon_view_ =
+ new ProportionalImageView(icon, gfx::Size(kIconSize, kIconSize));
+ }
+
+ icon_view_->set_background(
+ views::Background::CreateSolidBackground(kIconBackgroundColor));
+
+ AddChildView(icon_view_);
+}
+
+void NotificationView::CreateOrUpdateImageView(
+ const Notification& notification) {
+ if (image_view_) {
+ delete image_view_;
+ image_view_ = NULL;
+ }
+
+ DCHECK(bottom_view_);
+ DCHECK_EQ(this, bottom_view_->parent());
+
+ // TODO(dewittj): Detect a compatible update and use the existing image view.
+ if (!notification.image().IsEmpty()) {
+ gfx::Size image_size(kNotificationPreferredImageWidth,
+ kNotificationPreferredImageHeight);
+ image_view_ = MakeNotificationImage(notification.image(), image_size);
+ bottom_view_->AddChildViewAt(image_view_, 0);
+ }
+}
+
+void NotificationView::CreateOrUpdateActionButtonViews(
+ const Notification& notification) {
+ std::vector<ButtonInfo> buttons = notification.buttons();
+ bool new_buttons = action_buttons_.size() != buttons.size();
+
+ if (new_buttons || buttons.size() == 0) {
+ // STLDeleteElements also clears the container.
+ STLDeleteElements(&separators_);
+ STLDeleteElements(&action_buttons_);
+ }
+
+ DCHECK(bottom_view_);
+ DCHECK_EQ(this, bottom_view_->parent());
+
+ for (size_t i = 0; i < buttons.size(); ++i) {
+ ButtonInfo button_info = buttons[i];
+ if (new_buttons) {
+ views::View* separator = new views::ImageView();
+ separator->SetBorder(MakeSeparatorBorder(1, 0, kButtonSeparatorColor));
+ separators_.push_back(separator);
+ bottom_view_->AddChildView(separator);
+ NotificationButton* button = new NotificationButton(this);
+ button->SetTitle(button_info.title);
+ button->SetIcon(button_info.icon.AsImageSkia());
+ action_buttons_.push_back(button);
+ bottom_view_->AddChildView(button);
+ } else {
+ action_buttons_[i]->SetTitle(button_info.title);
+ action_buttons_[i]->SetIcon(button_info.icon.AsImageSkia());
+ action_buttons_[i]->SchedulePaint();
+ action_buttons_[i]->Layout();
+ }
+ }
+
+ if (new_buttons) {
+ Layout();
+ views::Widget* widget = GetWidget();
+ if (widget != NULL) {
+ widget->SetSize(widget->GetContentsView()->GetPreferredSize());
+ GetWidget()->SynthesizeMouseMoveEvent();
+ }
+ }
+}
+
+int NotificationView::GetMessageLineLimit(int title_lines, int width) const {
+ // Image notifications require that the image must be kept flush against
+ // their icons, but we can allow more text if no image.
+ int effective_title_lines = std::max(0, title_lines - 1);
+ int line_reduction_from_title = (image_view_ ? 1 : 2) * effective_title_lines;
+ if (!image_view_) {
+ // Title lines are counted as twice as big as message lines for the purpose
+ // of this calculation.
+ // The effect from the title reduction here should be:
+ // * 0 title lines: 5 max lines message.
+ // * 1 title line: 5 max lines message.
+ // * 2 title lines: 3 max lines message.
+ return std::max(
+ 0,
+ message_center::kMessageExpandedLineLimit - line_reduction_from_title);
+ }
int message_line_limit = message_center::kMessageCollapsedLineLimit;
@@ -674,16 +769,17 @@ int NotificationView::GetMessageLineLimit(int width) {
message_center::kContextMessageLineLimit);
}
- DCHECK_GT(message_line_limit, 0);
- return message_line_limit;
-}
+ // The effect from the title reduction here should be:
+ // * 0 title lines: 2 max lines message + context message.
+ // * 1 title line: 2 max lines message + context message.
+ // * 2 title lines: 1 max lines message + context message.
+ message_line_limit =
+ std::max(0, message_line_limit - line_reduction_from_title);
-int NotificationView::GetMessageLines(int width, int limit) {
- return message_view_ ?
- message_view_->GetLinesForWidthAndLimit(width, limit) : 0;
+ return message_line_limit;
}
-int NotificationView::GetMessageHeight(int width, int limit) {
+int NotificationView::GetMessageHeight(int width, int limit) const {
return message_view_ ?
message_view_->GetSizeForWidthAndLines(width, limit).height() : 0;
}
diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h
index ba47dda9706..2d6913124cc 100644
--- a/chromium/ui/message_center/views/notification_view.h
+++ b/chromium/ui/message_center/views/notification_view.h
@@ -19,6 +19,7 @@ namespace message_center {
class BoundedLabel;
class MessageCenter;
class MessageCenterController;
+class NotificationButton;
class NotificationView;
class PaddedButton;
@@ -38,14 +39,12 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
// |controller| may be NULL, but has to be set before the view is shown.
static NotificationView* Create(MessageCenterController* controller,
const Notification& notification,
- bool expanded,
bool top_level);
-
- virtual ~NotificationView();
+ virtual ~NotificationView();
// Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void ScrollRectToVisible(const gfx::Rect& rect) OVERRIDE;
@@ -53,6 +52,8 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
// Overridden from MessageView:
+ virtual void UpdateWithNotification(
+ const Notification& notification) OVERRIDE;
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
@@ -60,9 +61,6 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
void set_controller(MessageCenterController* controller) {
controller_ = controller;
@@ -70,24 +68,37 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
protected:
NotificationView(MessageCenterController* controller,
- const Notification& notification,
- bool expanded);
+ const Notification& notification);
private:
- bool IsExpansionNeeded(int width);
- bool IsMessageExpansionNeeded(int width);
- int GetMessageLineLimit(int width);
- int GetMessageLines(int width, int limit);
- int GetMessageHeight(int width, int limit);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, CreateOrUpdateTest);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestLineLimits);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonsStateTest);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonCountTest);
+
+ friend class NotificationViewTest;
+
+ void CreateOrUpdateViews(const Notification& notification);
+ void SetAccessibleName(const Notification& notification);
+
+ void CreateOrUpdateTitleView(const Notification& notification);
+ void CreateOrUpdateMessageView(const Notification& notification);
+ void CreateOrUpdateContextMessageView(const Notification& notification);
+ void CreateOrUpdateProgressBarView(const Notification& notification);
+ void CreateOrUpdateListItemViews(const Notification& notification);
+ void CreateOrUpdateIconView(const Notification& notification);
+ void CreateOrUpdateImageView(const Notification& notification);
+ void CreateOrUpdateActionButtonViews(const Notification& notification);
+
+ int GetMessageLineLimit(int title_lines, int width) const;
+ int GetMessageHeight(int width, int limit) const;
MessageCenterController* controller_; // Weak, lives longer then views.
// Describes whether the view should display a hand pointer or not.
bool clickable_;
- bool is_expanded_;
// Weak references to NotificationView descendants owned by their parents.
- views::View* background_view_;
views::View* top_view_;
BoundedLabel* title_view_;
BoundedLabel* message_view_;
@@ -97,8 +108,8 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
views::View* bottom_view_;
views::View* image_view_;
views::ProgressBar* progress_bar_view_;
- std::vector<views::View*> action_buttons_;
- PaddedButton* expand_button_;
+ std::vector<NotificationButton*> action_buttons_;
+ std::vector<views::View*> separators_;
DISALLOW_COPY_AND_ASSIGN(NotificationView);
};
diff --git a/chromium/ui/message_center/views/notification_view_unittest.cc b/chromium/ui/message_center/views/notification_view_unittest.cc
new file mode 100644
index 00000000000..b6d67526905
--- /dev/null
+++ b/chromium/ui/message_center/views/notification_view_unittest.cc
@@ -0,0 +1,323 @@
+// 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/message_center/views/notification_view.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_list.h"
+#include "ui/message_center/notification_types.h"
+#include "ui/message_center/views/message_center_controller.h"
+#include "ui/message_center/views/notification_button.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace message_center {
+
+/* Test fixture ***************************************************************/
+
+class NotificationViewTest : public views::ViewsTestBase,
+ public MessageCenterController {
+ public:
+ NotificationViewTest();
+ virtual ~NotificationViewTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ views::Widget* widget() { return notification_view_->GetWidget(); }
+ NotificationView* notification_view() { return notification_view_.get(); }
+ Notification* notification() { return notification_.get(); }
+ RichNotificationData* data() { return data_.get(); }
+
+ // Overridden from MessageCenterController:
+ virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
+ virtual void RemoveNotification(const std::string& notification_id,
+ bool by_user) OVERRIDE;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) OVERRIDE;
+ virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
+ virtual void ClickOnNotificationButton(const std::string& notification_id,
+ int button_index) OVERRIDE;
+
+ protected:
+ const gfx::Image CreateTestImage(int width, int height) {
+ return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height));
+ }
+
+ const SkBitmap CreateBitmap(int width, int height) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseRGB(0, 255, 0);
+ return bitmap;
+ }
+
+ std::vector<ButtonInfo> CreateButtons(int number) {
+ ButtonInfo info(base::ASCIIToUTF16("Test button title."));
+ info.icon = CreateTestImage(4, 4);
+ return std::vector<ButtonInfo>(number, info);
+ }
+
+ void CheckVerticalOrderInNotification() {
+ std::vector<views::View*> vertical_order;
+ vertical_order.push_back(notification_view()->top_view_);
+ vertical_order.push_back(notification_view()->image_view_);
+ std::copy(notification_view()->action_buttons_.begin(),
+ notification_view()->action_buttons_.end(),
+ std::back_inserter(vertical_order));
+ std::vector<views::View*>::iterator current = vertical_order.begin();
+ std::vector<views::View*>::iterator last = current++;
+ while (current != vertical_order.end()) {
+ gfx::Point last_point = (*last)->bounds().origin();
+ views::View::ConvertPointToTarget(
+ (*last), notification_view(), &last_point);
+
+ gfx::Point current_point = (*current)->bounds().origin();
+ views::View::ConvertPointToTarget(
+ (*current), notification_view(), &current_point);
+
+ EXPECT_LT(last_point.y(), current_point.y());
+ last = current++;
+ }
+ }
+
+ void UpdateNotificationViews() {
+ notification_view()->CreateOrUpdateViews(*notification());
+ notification_view()->Layout();
+ }
+
+ private:
+ scoped_ptr<RichNotificationData> data_;
+ scoped_ptr<Notification> notification_;
+ scoped_ptr<NotificationView> notification_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationViewTest);
+};
+
+NotificationViewTest::NotificationViewTest() {
+}
+
+NotificationViewTest::~NotificationViewTest() {
+}
+
+void NotificationViewTest::SetUp() {
+ views::ViewsTestBase::SetUp();
+ // Create a dummy notification.
+ SkBitmap bitmap;
+ data_.reset(new RichNotificationData());
+ notification_.reset(
+ new Notification(NOTIFICATION_TYPE_BASE_FORMAT,
+ std::string("notification id"),
+ base::UTF8ToUTF16("title"),
+ base::UTF8ToUTF16("message"),
+ CreateTestImage(80, 80),
+ base::UTF8ToUTF16("display source"),
+ NotifierId(NotifierId::APPLICATION, "extension_id"),
+ *data_,
+ NULL));
+ notification_->set_small_image(CreateTestImage(16, 16));
+ notification_->set_image(CreateTestImage(320, 240));
+
+ // Then create a new NotificationView with that single notification.
+ notification_view_.reset(
+ NotificationView::Create(this, *notification_, true));
+ notification_view_->set_owned_by_client();
+
+ views::Widget::InitParams init_params(
+ CreateParams(views::Widget::InitParams::TYPE_POPUP));
+ views::Widget* widget = new views::Widget();
+ widget->Init(init_params);
+ widget->SetContentsView(notification_view_.get());
+ widget->SetSize(notification_view_->GetPreferredSize());
+}
+
+void NotificationViewTest::TearDown() {
+ widget()->Close();
+ notification_view_.reset();
+ views::ViewsTestBase::TearDown();
+}
+
+void NotificationViewTest::ClickOnNotification(
+ const std::string& notification_id) {
+ // For this test, this method should not be invoked.
+ NOTREACHED();
+}
+
+void NotificationViewTest::RemoveNotification(
+ const std::string& notification_id,
+ bool by_user) {
+ // For this test, this method should not be invoked.
+ NOTREACHED();
+}
+
+scoped_ptr<ui::MenuModel> NotificationViewTest::CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
+ // For this test, this method should not be invoked.
+ NOTREACHED();
+ return scoped_ptr<ui::MenuModel>();
+}
+
+bool NotificationViewTest::HasClickedListener(
+ const std::string& notification_id) {
+ return true;
+}
+
+void NotificationViewTest::ClickOnNotificationButton(
+ const std::string& notification_id,
+ int button_index) {
+ // For this test, this method should not be invoked.
+ NOTREACHED();
+}
+
+/* Unit tests *****************************************************************/
+
+TEST_F(NotificationViewTest, CreateOrUpdateTest) {
+ EXPECT_TRUE(NULL != notification_view()->title_view_);
+ EXPECT_TRUE(NULL != notification_view()->message_view_);
+ EXPECT_TRUE(NULL != notification_view()->icon_view_);
+ EXPECT_TRUE(NULL != notification_view()->image_view_);
+
+ notification()->set_image(gfx::Image());
+ notification()->set_title(base::ASCIIToUTF16(""));
+ notification()->set_message(base::ASCIIToUTF16(""));
+ notification()->set_icon(gfx::Image());
+
+ notification_view()->CreateOrUpdateViews(*notification());
+ EXPECT_TRUE(NULL == notification_view()->title_view_);
+ EXPECT_TRUE(NULL == notification_view()->message_view_);
+ EXPECT_TRUE(NULL == notification_view()->image_view_);
+ // We still expect an icon view for all layouts.
+ EXPECT_TRUE(NULL != notification_view()->icon_view_);
+}
+
+TEST_F(NotificationViewTest, TestLineLimits) {
+ notification()->set_image(CreateTestImage(0, 0));
+ notification()->set_context_message(base::ASCIIToUTF16(""));
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360));
+ EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360));
+ EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360));
+
+ notification()->set_image(CreateTestImage(2, 2));
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_EQ(2, notification_view()->GetMessageLineLimit(0, 360));
+ EXPECT_EQ(2, notification_view()->GetMessageLineLimit(1, 360));
+ EXPECT_EQ(1, notification_view()->GetMessageLineLimit(2, 360));
+
+ notification()->set_context_message(base::UTF8ToUTF16("foo"));
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_TRUE(notification_view()->context_message_view_ != NULL);
+
+ EXPECT_EQ(1, notification_view()->GetMessageLineLimit(0, 360));
+ EXPECT_EQ(1, notification_view()->GetMessageLineLimit(1, 360));
+ EXPECT_EQ(0, notification_view()->GetMessageLineLimit(2, 360));
+}
+
+TEST_F(NotificationViewTest, UpdateButtonsStateTest) {
+ notification()->set_buttons(CreateButtons(2));
+ notification_view()->CreateOrUpdateViews(*notification());
+ widget()->Show();
+
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[0]->background());
+
+ // Now construct a mouse move event 1 pixel inside the boundary of the action
+ // button.
+ gfx::Point cursor_location(1, 1);
+ views::View::ConvertPointToWidget(notification_view()->action_buttons_[0],
+ &cursor_location);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED,
+ cursor_location,
+ cursor_location,
+ ui::EF_NONE,
+ ui::EF_NONE);
+ widget()->OnMouseEvent(&move);
+
+ EXPECT_TRUE(NULL != notification_view()->action_buttons_[0]->background());
+
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_TRUE(NULL != notification_view()->action_buttons_[0]->background());
+
+ // Now construct a mouse move event 1 pixel outside the boundary of the
+ // widget.
+ cursor_location = gfx::Point(-1, -1);
+ move = ui::MouseEvent(ui::ET_MOUSE_MOVED,
+ cursor_location,
+ cursor_location,
+ ui::EF_NONE,
+ ui::EF_NONE);
+ widget()->OnMouseEvent(&move);
+
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[0]->background());
+}
+
+TEST_F(NotificationViewTest, UpdateButtonCountTest) {
+ notification()->set_buttons(CreateButtons(2));
+ notification_view()->CreateOrUpdateViews(*notification());
+ widget()->Show();
+
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[0]->background());
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[1]->background());
+
+ // Now construct a mouse move event 1 pixel inside the boundary of the action
+ // button.
+ gfx::Point cursor_location(1, 1);
+ views::View::ConvertPointToWidget(notification_view()->action_buttons_[0],
+ &cursor_location);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED,
+ cursor_location,
+ cursor_location,
+ ui::EF_NONE,
+ ui::EF_NONE);
+ widget()->OnMouseEvent(&move);
+
+ EXPECT_TRUE(NULL != notification_view()->action_buttons_[0]->background());
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[1]->background());
+
+ notification()->set_buttons(CreateButtons(1));
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_TRUE(NULL != notification_view()->action_buttons_[0]->background());
+ EXPECT_EQ(1u, notification_view()->action_buttons_.size());
+
+ // Now construct a mouse move event 1 pixel outside the boundary of the
+ // widget.
+ cursor_location = gfx::Point(-1, -1);
+ move = ui::MouseEvent(ui::ET_MOUSE_MOVED,
+ cursor_location,
+ cursor_location,
+ ui::EF_NONE,
+ ui::EF_NONE);
+ widget()->OnMouseEvent(&move);
+
+ EXPECT_TRUE(NULL == notification_view()->action_buttons_[0]->background());
+}
+
+TEST_F(NotificationViewTest, ViewOrderingTest) {
+ // Tests that views are created in the correct vertical order.
+ notification()->set_buttons(CreateButtons(2));
+
+ // Layout the initial views.
+ UpdateNotificationViews();
+
+ // Double-check that vertical order is correct.
+ CheckVerticalOrderInNotification();
+
+ // Tests that views remain in that order even after an update.
+ UpdateNotificationViews();
+ CheckVerticalOrderInNotification();
+}
+
+} // namespace message_center
diff --git a/chromium/ui/message_center/views/notifier_settings_view.cc b/chromium/ui/message_center/views/notifier_settings_view.cc
index e345d93e501..a282ccbe04a 100644
--- a/chromium/ui/message_center/views/notifier_settings_view.cc
+++ b/chromium/ui/message_center/views/notifier_settings_view.cc
@@ -28,6 +28,7 @@
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/controls/button/text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
@@ -41,10 +42,6 @@
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#endif
-
namespace message_center {
namespace settings {
@@ -141,8 +138,8 @@ class EntryView : public views::View {
// views::View:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
@@ -171,14 +168,14 @@ void EntryView::Layout() {
content->SetBounds(0, y, content_width, content_height);
}
-gfx::Size EntryView::GetPreferredSize() {
+gfx::Size EntryView::GetPreferredSize() const {
DCHECK_EQ(1, child_count());
gfx::Size size = child_at(0)->GetPreferredSize();
size.SetToMax(gfx::Size(settings::kWidth, settings::kEntryHeight));
return size;
}
-void EntryView::GetAccessibleState(ui::AccessibleViewState* state) {
+void EntryView::GetAccessibleState(ui::AXViewState* state) {
DCHECK_EQ(1, child_count());
child_at(0)->GetAccessibleState(state);
}
@@ -295,7 +292,7 @@ NotifierSettingsView::NotifierButton::NotifierButton(
notifier_(notifier),
icon_view_(new views::ImageView()),
name_view_(new views::Label(notifier_->name)),
- checkbox_(new views::Checkbox(string16())),
+ checkbox_(new views::Checkbox(base::string16())),
learn_more_(NULL) {
DCHECK(provider);
DCHECK(notifier);
@@ -333,7 +330,7 @@ NotifierSettingsView::NotifierButton::NotifierButton(
(settings::kLearnMoreTargetHeight - settings::kLearnMoreSize) / 2;
// The image itself is quite small, this large invisible border creates a
// much bigger click target.
- learn_more_->set_border(
+ learn_more_->SetBorder(
views::Border::CreateEmptyBorder(learn_more_border_height,
learn_more_border_width,
learn_more_border_height,
@@ -384,7 +381,8 @@ void NotifierSettingsView::NotifierButton::SendLearnMorePressedForTest() {
return;
gfx::Point point(110, 120);
ui::MouseEvent pressed(
- ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON);
+ ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
ButtonPressed(learn_more_, pressed);
}
@@ -405,7 +403,7 @@ void NotifierSettingsView::NotifierButton::ButtonPressed(
}
void NotifierSettingsView::NotifierButton::GetAccessibleState(
- ui::AccessibleViewState* state) {
+ ui::AXViewState* state) {
static_cast<views::View*>(checkbox_)->GetAccessibleState(state);
}
@@ -486,17 +484,15 @@ NotifierSettingsView::NotifierSettingsView(NotifierSettingsProvider* provider)
SetFocusable(true);
set_background(
views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
- if (get_use_acceleration_when_possible())
- SetPaintToLayer(true);
+ SetPaintToLayer(true);
- gfx::Font title_font =
- ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont);
title_label_ = new views::Label(
l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL),
- title_font);
+ ui::ResourceBundle::GetSharedInstance().GetFontList(
+ ui::ResourceBundle::MediumFont));
title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
title_label_->SetMultiLine(true);
- title_label_->set_border(
+ title_label_->SetBorder(
views::Border::CreateEmptyBorder(kComputedTitleTopMargin,
settings::kTitleMargin,
kComputedTitleBottomMargin,
@@ -545,6 +541,9 @@ void NotifierSettingsView::NotifierGroupChanged() {
UpdateContentsView(notifiers);
}
+void NotifierSettingsView::NotifierEnabledChanged(const NotifierId& notifier_id,
+ bool enabled) {}
+
void NotifierSettingsView::UpdateContentsView(
const std::vector<Notifier*>& notifiers) {
buttons_.clear();
@@ -571,7 +570,7 @@ void NotifierSettingsView::UpdateContentsView(
top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
top_label->SetMultiLine(true);
- top_label->set_border(views::Border::CreateEmptyBorder(
+ top_label->SetBorder(views::Border::CreateEmptyBorder(
0,
settings::kTitleMargin + kMenuButtonInnateMargin,
0,
@@ -580,7 +579,7 @@ void NotifierSettingsView::UpdateContentsView(
if (need_account_switcher) {
const NotifierGroup& active_group = provider_->GetActiveNotifierGroup();
- string16 notifier_group_text = active_group.login_info.empty() ?
+ base::string16 notifier_group_text = active_group.login_info.empty() ?
active_group.name : active_group.login_info;
notifier_group_selector_ =
new views::MenuButton(NULL, notifier_group_text, this, true);
@@ -598,7 +597,8 @@ void NotifierSettingsView::UpdateContentsView(
selector_border->SetInsets(gfx::Insets(
kMenuButtonVerticalPadding, kMenuButtonLeftPadding,
kMenuButtonVerticalPadding, kMenuButtonRightPadding));
- notifier_group_selector_->set_border(selector_border.release());
+ notifier_group_selector_->SetBorder(
+ selector_border.PassAs<views::Border>());
notifier_group_selector_->SetFocusPainter(scoped_ptr<views::Painter>());
notifier_group_selector_->set_animate_on_state_change(false);
notifier_group_selector_->SetFocusable(true);
@@ -616,17 +616,17 @@ void NotifierSettingsView::UpdateContentsView(
// border on the last notifier, as the spec leaves a space for it.
scoped_ptr<views::Border> entry_border;
if (i == notifier_count - 1) {
- entry_border.reset(views::Border::CreateEmptyBorder(
- 0, 0, settings::kEntrySeparatorHeight, 0));
+ entry_border = views::Border::CreateEmptyBorder(
+ 0, 0, settings::kEntrySeparatorHeight, 0);
} else {
- entry_border.reset(views::Border::CreateSolidSidedBorder(
- 0,
- 0,
- settings::kEntrySeparatorHeight,
- 0,
- settings::kEntrySeparatorColor));
+ entry_border =
+ views::Border::CreateSolidSidedBorder(0,
+ 0,
+ settings::kEntrySeparatorHeight,
+ 0,
+ settings::kEntrySeparatorColor);
}
- entry->set_border(entry_border.release());
+ entry->SetBorder(entry_border.Pass());
entry->SetFocusable(true);
contents_view->AddChildView(entry);
buttons_.insert(button);
@@ -656,7 +656,7 @@ void NotifierSettingsView::Layout() {
scroller_->SetBounds(0, title_height, width(), height() - title_height);
}
-gfx::Size NotifierSettingsView::GetMinimumSize() {
+gfx::Size NotifierSettingsView::GetMinimumSize() const {
gfx::Size size(settings::kWidth, settings::kMinimumHeight);
int total_height = title_label_->GetPreferredSize().height() +
scroller_->contents()->GetPreferredSize().height();
@@ -665,7 +665,7 @@ gfx::Size NotifierSettingsView::GetMinimumSize() {
return size;
}
-gfx::Size NotifierSettingsView::GetPreferredSize() {
+gfx::Size NotifierSettingsView::GetPreferredSize() const {
gfx::Size preferred_size;
gfx::Size title_size = title_label_->GetPreferredSize();
gfx::Size content_size = scroller_->contents()->GetPreferredSize();
@@ -717,7 +717,7 @@ void NotifierSettingsView::OnMenuButtonClicked(views::View* source,
notifier_group_menu_runner_->RunMenuAt(GetWidget(),
notifier_group_selector_,
menu_anchor,
- views::MenuItemView::BUBBLE_ABOVE,
+ views::MENU_ANCHOR_BUBBLE_ABOVE,
ui::MENU_SOURCE_MOUSE,
views::MenuRunner::CONTEXT_MENU))
return;
diff --git a/chromium/ui/message_center/views/notifier_settings_view.h b/chromium/ui/message_center/views/notifier_settings_view.h
index 665bed0a155..994fa50a6e9 100644
--- a/chromium/ui/message_center/views/notifier_settings_view.h
+++ b/chromium/ui/message_center/views/notifier_settings_view.h
@@ -43,6 +43,8 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView
virtual void UpdateIconImage(const NotifierId& notifier_id,
const gfx::Image& icon) OVERRIDE;
virtual void NotifierGroupChanged() OVERRIDE;
+ virtual void NotifierEnabledChanged(const NotifierId& notifier_id,
+ bool enabled) OVERRIDE;
void set_provider(NotifierSettingsProvider* new_provider) {
provider_ = new_provider;
@@ -71,7 +73,7 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* button,
const ui::Event& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
bool ShouldHaveLearnMoreButton() const;
// Helper function to reset the layout when the view has substantially
@@ -95,8 +97,8 @@ class MESSAGE_CENTER_EXPORT NotifierSettingsView
// Overridden from views::View:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
diff --git a/chromium/ui/message_center/views/padded_button.cc b/chromium/ui/message_center/views/padded_button.cc
index 182cde698c9..add465b1720 100644
--- a/chromium/ui/message_center/views/padded_button.cc
+++ b/chromium/ui/message_center/views/padded_button.cc
@@ -50,7 +50,7 @@ void PaddedButton::SetPressedImage(int resource_id) {
resource_id));
}
-gfx::Size PaddedButton::GetPreferredSize() {
+gfx::Size PaddedButton::GetPreferredSize() const {
return gfx::Size(message_center::kControlButtonSize,
message_center::kControlButtonSize);
}
@@ -66,8 +66,6 @@ void PaddedButton::OnPaint(gfx::Canvas* canvas) {
if (!background_image_.isNull())
canvas->DrawImageInt(background_image_, position.x(), position.y());
canvas->DrawImageInt(image, position.x(), position.y());
- if (!overlay_image_.isNull())
- canvas->DrawImageInt(overlay_image_, position.x(), position.y());
}
views::Painter::PaintFocusPainter(this, canvas, focus_painter());
}
diff --git a/chromium/ui/message_center/views/padded_button.h b/chromium/ui/message_center/views/padded_button.h
index 04ae5c1d36b..c420621e9a1 100644
--- a/chromium/ui/message_center/views/padded_button.h
+++ b/chromium/ui/message_center/views/padded_button.h
@@ -24,7 +24,7 @@ class PaddedButton : public views::ImageButton {
virtual ~PaddedButton();
// Overridden from views::ImageButton:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
@@ -49,4 +49,4 @@ class PaddedButton : public views::ImageButton {
} // namespace message_center
-#endif // UI_MESSAGE_CENTER_VIEWS_PADDED_BUTTON_H_ \ No newline at end of file
+#endif // UI_MESSAGE_CENTER_VIEWS_PADDED_BUTTON_H_
diff --git a/chromium/ui/message_center/views/proportional_image_view.cc b/chromium/ui/message_center/views/proportional_image_view.cc
index 1e52fa34cef..8ec9b32e6dc 100644
--- a/chromium/ui/message_center/views/proportional_image_view.cc
+++ b/chromium/ui/message_center/views/proportional_image_view.cc
@@ -9,55 +9,52 @@
namespace message_center {
-ProportionalImageView::ProportionalImageView(const gfx::ImageSkia& image)
- : image_(image) {
-}
+ProportionalImageView::ProportionalImageView(const gfx::ImageSkia& image,
+ const gfx::Size& max_size)
+ : image_(image), max_size_(max_size) {}
-ProportionalImageView::~ProportionalImageView() {
-}
+ProportionalImageView::~ProportionalImageView() {}
-gfx::Size ProportionalImageView::GetPreferredSize() {
- gfx::Insets insets = GetInsets();
- gfx::Rect rect = gfx::Rect(GetImageSizeForWidth(image_.width()));
- rect.Inset(-insets);
- return rect.size();
-}
+gfx::Size ProportionalImageView::GetPreferredSize() const { return max_size_; }
-int ProportionalImageView::GetHeightForWidth(int width) {
- // The border will count against the width available for the image
- // and towards the height taken by the image.
- gfx::Insets insets = GetInsets();
- int inset_width = width - insets.width();
- return GetImageSizeForWidth(inset_width).height() + insets.height();
+int ProportionalImageView::GetHeightForWidth(int width) const {
+ return max_size_.height();
}
void ProportionalImageView::OnPaint(gfx::Canvas* canvas) {
views::View::OnPaint(canvas);
- gfx::Size draw_size(GetImageSizeForWidth(width() - GetInsets().width()));
- if (!draw_size.IsEmpty()) {
- gfx::Rect draw_bounds = GetContentsBounds();
- draw_bounds.ClampToCenteredSize(draw_size);
-
- gfx::Size image_size(image_.size());
- if (image_size == draw_size) {
- canvas->DrawImageInt(image_, draw_bounds.x(), draw_bounds.y());
- } else {
- // Resize case
- SkPaint paint;
- paint.setFilterBitmap(true);
- canvas->DrawImageInt(image_, 0, 0,
- image_size.width(), image_size.height(),
- draw_bounds.x(), draw_bounds.y(),
- draw_size.width(), draw_size.height(),
- true, paint);
- }
+ gfx::Size draw_size = GetImageDrawingSize();
+
+ if (draw_size.IsEmpty())
+ return;
+
+ gfx::Rect draw_bounds = GetContentsBounds();
+ draw_bounds.ClampToCenteredSize(draw_size);
+
+ gfx::Size image_size(image_.size());
+
+ if (image_size == draw_size) {
+ canvas->DrawImageInt(image_, draw_bounds.x(), draw_bounds.y());
+ } else {
+ SkPaint paint;
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+
+ // This call resizes the image while drawing into the canvas.
+ canvas->DrawImageInt(
+ image_,
+ 0, 0, image_size.width(), image_size.height(),
+ draw_bounds.x(), draw_bounds.y(), draw_size.width(), draw_size.height(),
+ true,
+ paint);
}
}
-gfx::Size ProportionalImageView::GetImageSizeForWidth(int width) {
- gfx::Size size = visible() ? image_.size() : gfx::Size();
- return message_center::GetImageSizeForWidth(width, size);
+gfx::Size ProportionalImageView::GetImageDrawingSize() {
+ if (!visible())
+ return gfx::Size();
+ return message_center::GetImageSizeForContainerSize(
+ GetContentsBounds().size(), image_.size());
}
} // namespace message_center
diff --git a/chromium/ui/message_center/views/proportional_image_view.h b/chromium/ui/message_center/views/proportional_image_view.h
index 42f6dc2b346..7c1be9243c2 100644
--- a/chromium/ui/message_center/views/proportional_image_view.h
+++ b/chromium/ui/message_center/views/proportional_image_view.h
@@ -13,18 +13,19 @@ namespace message_center {
// ProportionalImageViews center their images to preserve their proportion.
class ProportionalImageView : public views::View {
public:
- ProportionalImageView(const gfx::ImageSkia& image);
+ ProportionalImageView(const gfx::ImageSkia& image, const gfx::Size& max_size);
virtual ~ProportionalImageView();
// Overridden from views::View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
private:
- gfx::Size GetImageSizeForWidth(int width);
+ gfx::Size GetImageDrawingSize();
gfx::ImageSkia image_;
+ gfx::Size max_size_;
DISALLOW_COPY_AND_ASSIGN(ProportionalImageView);
};
diff --git a/chromium/ui/message_center/views/toast_contents_view.cc b/chromium/ui/message_center/views/toast_contents_view.cc
index 6c139343ba5..e5de6a25100 100644
--- a/chromium/ui/message_center/views/toast_contents_view.cc
+++ b/chromium/ui/message_center/views/toast_contents_view.cc
@@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/display.h"
@@ -24,10 +24,12 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
-#if defined(OS_WIN) && defined(USE_ASH)
+#if defined(OS_WIN)
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
+using gfx::Screen;
+
namespace message_center {
namespace {
@@ -40,7 +42,7 @@ const int kFadeInOutDuration = 200;
} // namespace.
// static
-gfx::Size ToastContentsView::GetToastSizeForView(views::View* view) {
+gfx::Size ToastContentsView::GetToastSizeForView(const views::View* view) {
int width = kNotificationWidth + view->GetInsets().width();
return gfx::Size(width, view->GetHeightForWidth(width));
}
@@ -84,7 +86,16 @@ void ToastContentsView::SetContents(MessageView* view,
// 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(ui::AccessibilityTypes::EVENT_ALERT, false);
+ NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false);
+}
+
+void ToastContentsView::UpdateContents(const Notification& notification,
+ bool a11y_feedback_for_updates) {
+ DCHECK_GT(child_count(), 0);
+ MessageView* message_view = static_cast<MessageView*>(child_at(0));
+ message_view->UpdateWithNotification(notification);
+ if (a11y_feedback_for_updates)
+ NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false);
}
void ToastContentsView::RevealWithAnimation(gfx::Point origin) {
@@ -152,7 +163,7 @@ void ToastContentsView::StartFadeIn() {
fade_animation_->Stop();
GetWidget()->SetOpacity(0);
- GetWidget()->Show();
+ GetWidget()->ShowInactive();
fade_animation_->Reset(0);
fade_animation_->Show();
}
@@ -172,16 +183,16 @@ void ToastContentsView::OnBoundsAnimationEndedOrCancelled(
const gfx::Animation* animation) {
if (is_closing_ && closing_animation_ == animation && GetWidget()) {
views::Widget* widget = GetWidget();
-#if defined(USE_AURA)
+
// TODO(dewittj): This is a workaround to prevent a nasty bug where
// closing a transparent widget doesn't actually remove the window,
// causing entire areas of the screen to become unresponsive to clicks.
// See crbug.com/243469
widget->Hide();
-# if defined(OS_WIN)
+#if defined(OS_WIN)
widget->SetOpacity(0xFF);
-# endif
#endif
+
widget->Close();
}
@@ -225,14 +236,6 @@ void ToastContentsView::WindowClosing() {
collection_->ForgetToast(this);
}
-bool ToastContentsView::CanActivate() const {
-#if defined(OS_WIN) && defined(USE_AURA)
- return true;
-#else
- return false;
-#endif
-}
-
void ToastContentsView::OnDisplayChanged() {
views::Widget* widget = GetWidget();
if (!widget)
@@ -242,8 +245,10 @@ void ToastContentsView::OnDisplayChanged() {
if (!native_view || !collection_.get())
return;
- collection_->OnDisplayBoundsChanged(gfx::Screen::GetScreenFor(
- native_view)->GetDisplayNearestWindow(native_view));
+ collection_->OnDisplayMetricsChanged(
+ Screen::GetScreenFor(native_view)->GetDisplayNearestWindow(native_view),
+ gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+ gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
}
void ToastContentsView::OnWorkAreaChanged() {
@@ -255,8 +260,9 @@ void ToastContentsView::OnWorkAreaChanged() {
if (!native_view || !collection_.get())
return;
- collection_->OnDisplayBoundsChanged(gfx::Screen::GetScreenFor(
- native_view)->GetDisplayNearestWindow(native_view));
+ collection_->OnDisplayMetricsChanged(
+ Screen::GetScreenFor(native_view)->GetDisplayNearestWindow(native_view),
+ gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
}
// views::View
@@ -277,14 +283,14 @@ void ToastContentsView::Layout() {
}
}
-gfx::Size ToastContentsView::GetPreferredSize() {
+gfx::Size ToastContentsView::GetPreferredSize() const {
return child_count() ? GetToastSizeForView(child_at(0)) : gfx::Size();
}
-void ToastContentsView::GetAccessibleState(ui::AccessibleViewState* state) {
+void ToastContentsView::GetAccessibleState(ui::AXViewState* state) {
if (child_count() > 0)
child_at(0)->GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+ state->role = ui::AX_ROLE_WINDOW;
}
void ToastContentsView::ClickOnNotification(
@@ -300,15 +306,13 @@ void ToastContentsView::RemoveNotification(
collection_->RemoveNotification(notification_id, by_user);
}
-void ToastContentsView::DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) {
- if (collection_)
- collection_->DisableNotificationsFromThisSource(notifier_id);
-}
-
-void ToastContentsView::ShowNotifierSettingsBubble() {
- if (collection_)
- collection_->ShowNotifierSettingsBubble();
+scoped_ptr<ui::MenuModel> ToastContentsView::CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) {
+ // Should not reach, the context menu should be handled in
+ // MessagePopupCollection.
+ NOTREACHED();
+ return scoped_ptr<ui::MenuModel>();
}
bool ToastContentsView::HasClickedListener(
@@ -325,43 +329,17 @@ void ToastContentsView::ClickOnNotificationButton(
collection_->ClickOnNotificationButton(notification_id, button_index);
}
-void ToastContentsView::ExpandNotification(
- const std::string& notification_id) {
- if (collection_)
- collection_->ExpandNotification(notification_id);
-}
-
-void ToastContentsView::GroupBodyClicked(
- const std::string& last_notification_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
-// When clicked on the "N more" button, perform some reasonable action.
-// TODO(dimich): find out what the reasonable action could be.
-void ToastContentsView::ExpandGroup(const NotifierId& notifier_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
-void ToastContentsView::RemoveGroup(const NotifierId& notifier_id) {
- // No group views in popup collection.
- NOTREACHED();
-}
-
void ToastContentsView::CreateWidget(gfx::NativeView parent) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.keep_on_top = true;
if (parent)
params.parent = parent;
- else
- params.top_level = true;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.delegate = this;
views::Widget* widget = new views::Widget();
widget->set_focus_on_creation(false);
-#if defined(OS_WIN) && defined(USE_ASH)
+#if defined(OS_WIN)
// We want to ensure that this toast always goes to the native desktop,
// not the Ash desktop (since there is already another toast contents view
// there.
diff --git a/chromium/ui/message_center/views/toast_contents_view.h b/chromium/ui/message_center/views/toast_contents_view.h
index 3a609ca99a6..1b39d81d6f4 100644
--- a/chromium/ui/message_center/views/toast_contents_view.h
+++ b/chromium/ui/message_center/views/toast_contents_view.h
@@ -39,7 +39,7 @@ class ToastContentsView : public views::WidgetDelegateView,
public gfx::AnimationDelegate {
public:
// Computes the size of a toast assuming it will host the given view.
- static gfx::Size GetToastSizeForView(views::View* view);
+ static gfx::Size GetToastSizeForView(const views::View* view);
ToastContentsView(const std::string& notification_id,
base::WeakPtr<MessagePopupCollection> collection);
@@ -50,6 +50,9 @@ class ToastContentsView : public views::WidgetDelegateView,
// accessibility message should be read after this update.
void SetContents(MessageView* view, bool a11y_feedback_for_updates);
+ void UpdateContents(const Notification& notification,
+ bool a11y_feedback_for_updates);
+
// Shows the new toast for the first time, animated.
// |origin| is the right-bottom corner of the toast.
void RevealWithAnimation(gfx::Point origin);
@@ -71,25 +74,20 @@ class ToastContentsView : public views::WidgetDelegateView,
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
// Overridden from MessageCenterController:
virtual void ClickOnNotification(const std::string& notification_id) OVERRIDE;
virtual void RemoveNotification(const std::string& notification_id,
bool by_user) OVERRIDE;
- virtual void DisableNotificationsFromThisSource(
- const NotifierId& notifier_id) OVERRIDE;
- virtual void ShowNotifierSettingsBubble() OVERRIDE;
+ virtual scoped_ptr<ui::MenuModel> CreateMenuModel(
+ const NotifierId& notifier_id,
+ const base::string16& display_source) OVERRIDE;
virtual bool HasClickedListener(const std::string& notification_id) OVERRIDE;
virtual void ClickOnNotificationButton(const std::string& notification_id,
int button_index) OVERRIDE;
- virtual void ExpandNotification(const std::string& notification_id) OVERRIDE;
- virtual void GroupBodyClicked(const std::string& last_notification_id)
- OVERRIDE;
- virtual void ExpandGroup(const NotifierId& notifier_id) OVERRIDE;
- virtual void RemoveGroup(const NotifierId& notifier_id) OVERRIDE;
// Overridden from gfx::AnimationDelegate:
virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
@@ -99,7 +97,6 @@ class ToastContentsView : public views::WidgetDelegateView,
// Overridden from views::WidgetDelegate:
virtual views::View* GetContentsView() OVERRIDE;
virtual void WindowClosing() OVERRIDE;
- virtual bool CanActivate() const OVERRIDE;
virtual void OnDisplayChanged() OVERRIDE;
virtual void OnWorkAreaChanged() OVERRIDE;
diff --git a/chromium/ui/metro_viewer/BUILD.gn b/chromium/ui/metro_viewer/BUILD.gn
new file mode 100644
index 00000000000..c2a623d75b2
--- /dev/null
+++ b/chromium/ui/metro_viewer/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+source_set("metro_viewer") {
+ sources = [
+ "ime_types.cc",
+ "ime_types.h",
+ "metro_viewer_message_generator.cc",
+ "metro_viewer_message_generator.h",
+ "metro_viewer_messages.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
diff --git a/chromium/ui/metro_viewer/OWNERS b/chromium/ui/metro_viewer/OWNERS
index 176a54eb9a4..63607cc97b6 100644
--- a/chromium/ui/metro_viewer/OWNERS
+++ b/chromium/ui/metro_viewer/OWNERS
@@ -1,8 +1,12 @@
# Changes to IPC messages require a security review to avoid introducing
# new sandbox escapes.
per-file *_messages*.h=set noparent
-per-file *_messages*.h=cdn@chromium.org
per-file *_messages*.h=cevans@chromium.org
+per-file *_messages*.h=dcheng@chromium.org
+per-file *_messages*.h=inferno@chromium.org
per-file *_messages*.h=jln@chromium.org
per-file *_messages*.h=jschuh@chromium.org
+per-file *_messages*.h=kenrb@chromium.org
+per-file *_messages*.h=nasko@chromium.org
+per-file *_messages*.h=palmer@chromium.org
per-file *_messages*.h=tsepez@chromium.org
diff --git a/chromium/ui/metro_viewer/ime_types.h b/chromium/ui/metro_viewer/ime_types.h
index 8b3e2911163..0fb701d58e3 100644
--- a/chromium/ui/metro_viewer/ime_types.h
+++ b/chromium/ui/metro_viewer/ime_types.h
@@ -28,7 +28,7 @@ struct UnderlineInfo {
struct Composition {
Composition();
~Composition();
- string16 text;
+ base::string16 text;
int32 selection_start;
int32 selection_end;
std::vector<UnderlineInfo> underlines;
diff --git a/chromium/ui/metro_viewer/metro_viewer_messages.h b/chromium/ui/metro_viewer/metro_viewer_messages.h
index e30554c6ba4..e619607fbad 100644
--- a/chromium/ui/metro_viewer/metro_viewer_messages.h
+++ b/chromium/ui/metro_viewer/metro_viewer_messages.h
@@ -17,23 +17,33 @@
IPC_ENUM_TRAITS(ui::EventType)
IPC_ENUM_TRAITS(ui::EventFlags)
+// Contains the parameters sent for a mousebutton message.
+IPC_STRUCT_BEGIN(MetroViewerHostMsg_MouseButtonParams)
+
+ IPC_STRUCT_MEMBER(int32, x)
+ IPC_STRUCT_MEMBER(int32, y)
+ IPC_STRUCT_MEMBER(int32, extra)
+ IPC_STRUCT_MEMBER(ui::EventType, event_type)
+ IPC_STRUCT_MEMBER(uint32, flags)
+ IPC_STRUCT_MEMBER(ui::EventFlags, changed_button)
+ IPC_STRUCT_MEMBER(bool, is_horizontal_wheel)
+
+IPC_STRUCT_END()
+
// Messages sent from the viewer to the browser:
// Inform the browser of the surface to target for compositing.
-IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_SetTargetSurface,
- gfx::NativeViewId /* target hwnd */)
+IPC_MESSAGE_CONTROL2(MetroViewerHostMsg_SetTargetSurface,
+ gfx::NativeViewId /* target hwnd */,
+ float /* device scale */)
// Informs the browser that the mouse moved.
IPC_MESSAGE_CONTROL3(MetroViewerHostMsg_MouseMoved,
int32, /* x-coordinate */
int32, /* y-coordinate */
int32 /* flags */)
// Informs the brower that a mouse button was pressed.
-IPC_MESSAGE_CONTROL5(MetroViewerHostMsg_MouseButton,
- int32, /* x-coordinate */
- int32, /* y-coordinate */
- int32, /* extra */
- ui::EventType, /* event type */
- ui::EventFlags /* event flags */)
+IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_MouseButton,
+ MetroViewerHostMsg_MouseButtonParams)
// Informs the browser that a key was pressed.
IPC_MESSAGE_CONTROL4(MetroViewerHostMsg_KeyDown,
uint32, /* virtual key */
@@ -54,6 +64,9 @@ IPC_MESSAGE_CONTROL4(MetroViewerHostMsg_Character,
// Informs the browser that the Metro window has been activated.
IPC_MESSAGE_CONTROL0(MetroViewerHostMsg_WindowActivated);
+// Informs the browser that the user has completed an edge gesture.
+IPC_MESSAGE_CONTROL0(MetroViewerHostMsg_EdgeGesture)
+
IPC_MESSAGE_CONTROL4(MetroViewerHostMsg_TouchDown,
int32, /* x-coordinate */
int32, /* y-coordinate */
@@ -103,7 +116,7 @@ IPC_MESSAGE_CONTROL0(MetroViewerHostMsg_MetroExit);
// Requests the viewer to open a URL in desktop mode.
IPC_MESSAGE_CONTROL2(MetroViewerHostMsg_OpenURLOnDesktop,
base::FilePath, /* shortcut */
- string16 /* url */);
+ base::string16 /* url */);
// Requests the viewer to change the pointer to a new cursor.
IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_SetCursor,
@@ -114,19 +127,19 @@ IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_SetCursor,
IPC_STRUCT_BEGIN(MetroViewerHostMsg_SaveAsDialogParams)
// The title of the file save dialog if any.
- IPC_STRUCT_MEMBER(string16, title)
+ IPC_STRUCT_MEMBER(base::string16, title)
// The suggested file name.
IPC_STRUCT_MEMBER(base::FilePath, suggested_name)
// The save as filter to be used.
- IPC_STRUCT_MEMBER(string16, filter)
+ IPC_STRUCT_MEMBER(base::string16, filter)
// The filter index.
IPC_STRUCT_MEMBER(uint32, filter_index)
// The default extension.
- IPC_STRUCT_MEMBER(string16, default_extension)
+ IPC_STRUCT_MEMBER(base::string16, default_extension)
IPC_STRUCT_END()
@@ -136,14 +149,14 @@ IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_DisplayFileSaveAs,
// Requests the viewer to display the file open dialog.
IPC_MESSAGE_CONTROL4(MetroViewerHostMsg_DisplayFileOpen,
- string16, /* title */
- string16, /* filter */
+ base::string16, /* title */
+ base::string16, /* filter */
base::FilePath, /* Default path */
bool) /* allow_multi_select */
// Requests the viewer to display the select folder dialog.
IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_DisplaySelectFolder,
- string16) /* title */
+ base::string16) /* title */
// Sent to the viewer process to set the cursor position.
IPC_MESSAGE_CONTROL2(MetroViewerHostMsg_SetCursorPos,
@@ -155,10 +168,10 @@ IPC_MESSAGE_CONTROL2(MetroViewerHostMsg_SetCursorPos,
IPC_MESSAGE_CONTROL0(MetroViewerHostMsg_SetCursorPosAck)
IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_OpenURL,
- string16) /* url */
+ base::string16) /* url */
IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_SearchRequest,
- string16) /* search_string */
+ base::string16) /* search_string */
// Sent from the metro viewer process to the browser process to indicate that
// the viewer window size has changed.
@@ -176,7 +189,7 @@ IPC_STRUCT_TRAITS_END()
// composition string.
IPC_MESSAGE_CONTROL4(
MetroViewerHostMsg_ImeCompositionChanged,
- string16, /* text */
+ base::string16, /* text */
int32, /* selection_start */
int32, /* selection_end */
std::vector<metro_viewer::UnderlineInfo>) /* underlines */
@@ -189,7 +202,7 @@ IPC_MESSAGE_CONTROL1(
// Sent from the metro viewer process to the browser process to commit strings.
IPC_MESSAGE_CONTROL1(MetroViewerHostMsg_ImeTextCommitted,
- string16) /* text */
+ base::string16) /* text */
// Sent from the metro viewer process to the browser process to notify that the
// active text input source is changed.
diff --git a/chromium/ui/native_theme/BUILD.gn b/chromium/ui/native_theme/BUILD.gn
new file mode 100644
index 00000000000..3a9a104847d
--- /dev/null
+++ b/chromium/ui/native_theme/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("native_theme") {
+ sources = [
+ "common_theme.cc",
+ "common_theme.h",
+ "fallback_theme.cc",
+ "fallback_theme.h",
+ "native_theme.cc",
+ "native_theme.h",
+ "native_theme_android.cc",
+ "native_theme_android.h",
+ "native_theme_base.cc",
+ "native_theme_base.h",
+ "native_theme_mac.h",
+ "native_theme_mac.mm",
+ "native_theme_observer.cc",
+ "native_theme_observer.h",
+ "native_theme_switches.cc",
+ "native_theme_switches.h",
+ "native_theme_win.cc",
+ "native_theme_win.h",
+ ]
+
+ if (use_aura) {
+ sources += [
+ "native_theme_aura.cc",
+ "native_theme_aura.h",
+ ]
+
+ if (is_win) {
+ sources += [
+ "native_theme_aurawin.cc",
+ "native_theme_aurawin.h",
+ ]
+ }
+ }
+
+ defines = [
+ "NATIVE_THEME_IMPLEMENTATION",
+ ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/resources",
+ ]
+}
diff --git a/chromium/ui/native_theme/common_theme.cc b/chromium/ui/native_theme/common_theme.cc
index 5442a07df3e..facd814d341 100644
--- a/chromium/ui/native_theme/common_theme.cc
+++ b/chromium/ui/native_theme/common_theme.cc
@@ -8,6 +8,7 @@
#include "grit/ui_resources.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect.h"
@@ -32,6 +33,12 @@ const SkColor kEnabledMenuItemForegroundColor = SK_ColorBLACK;
const SkColor kDisabledMenuItemForegroundColor = SkColorSetRGB(161, 161, 146);
const SkColor kHoverMenuItemBackgroundColor =
SkColorSetARGB(204, 255, 255, 255);
+// Button:
+const SkColor kButtonHoverBackgroundColor = SkColorSetRGB(0xEA, 0xEA, 0xEA);
+const SkColor kBlueButtonEnabledColor = SK_ColorWHITE;
+const SkColor kBlueButtonDisabledColor = SK_ColorWHITE;
+const SkColor kBlueButtonHighlightColor = SK_ColorWHITE;
+const SkColor kBlueButtonHoverColor = SK_ColorWHITE;
} // namespace
@@ -70,12 +77,31 @@ bool CommonThemeGetSystemColor(NativeTheme::ColorId color_id, SkColor* color) {
case NativeTheme::kColorId_DisabledMenuItemForegroundColor:
*color = kDisabledMenuItemForegroundColor;
break;
+ case NativeTheme::kColorId_DisabledEmphasizedMenuItemForegroundColor:
+ *color = SK_ColorBLACK;
+ break;
case NativeTheme::kColorId_SelectedMenuItemForegroundColor:
*color = SK_ColorWHITE;
break;
case NativeTheme::kColorId_ButtonDisabledColor:
*color = kDisabledMenuItemForegroundColor;
break;
+ // Button
+ case NativeTheme::kColorId_ButtonHoverBackgroundColor:
+ *color = kButtonHoverBackgroundColor;
+ break;
+ case NativeTheme::kColorId_BlueButtonEnabledColor:
+ *color = kBlueButtonEnabledColor;
+ break;
+ case NativeTheme::kColorId_BlueButtonDisabledColor:
+ *color = kBlueButtonDisabledColor;
+ break;
+ case NativeTheme::kColorId_BlueButtonHighlightColor:
+ *color = kBlueButtonHighlightColor;
+ break;
+ case NativeTheme::kColorId_BlueButtonHoverColor:
+ *color = kBlueButtonHoverColor;
+ break;
default:
return false;
}
@@ -97,6 +123,10 @@ gfx::Size CommonThemeGetPartSize(NativeTheme::Part part,
const NativeTheme::ExtraParams& extra) {
gfx::Size size;
switch (part) {
+ case NativeTheme::kComboboxArrow:
+ return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ IDR_MENU_DROPARROW).Size();
+
case NativeTheme::kMenuCheck: {
const gfx::ImageSkia* check =
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
@@ -111,6 +141,12 @@ gfx::Size CommonThemeGetPartSize(NativeTheme::Part part,
return size;
}
+void CommonThemePaintComboboxArrow(SkCanvas* canvas, const gfx::Rect& rect) {
+ gfx::ImageSkia* arrow = ui::ResourceBundle::GetSharedInstance().
+ GetImageSkiaNamed(IDR_MENU_DROPARROW);
+ CommonThemeCreateCanvas(canvas)->DrawImageInt(*arrow, rect.x(), rect.y());
+}
+
void CommonThemePaintMenuSeparator(
SkCanvas* canvas,
const gfx::Rect& rect,
@@ -164,4 +200,14 @@ void CommonThemePaintMenuItemBackground(SkCanvas* canvas,
canvas->drawRect(gfx::RectToSkRect(rect), paint);
}
+// static
+scoped_ptr<gfx::Canvas> CommonThemeCreateCanvas(SkCanvas* sk_canvas) {
+ // TODO(pkotwicz): Do something better and don't infer device
+ // scale factor from canvas scale.
+ SkMatrix m = sk_canvas->getTotalMatrix();
+ float device_scale = static_cast<float>(SkScalarAbs(m.getScaleX()));
+ return scoped_ptr<gfx::Canvas>(
+ gfx::Canvas::CreateCanvasWithoutScaling(sk_canvas, device_scale));
+}
+
} // namespace ui
diff --git a/chromium/ui/native_theme/common_theme.h b/chromium/ui/native_theme/common_theme.h
index c91f4899c82..a8db60f0fb4 100644
--- a/chromium/ui/native_theme/common_theme.h
+++ b/chromium/ui/native_theme/common_theme.h
@@ -5,10 +5,15 @@
#ifndef UI_NATIVE_THEME_COMMON_THEME_H_
#define UI_NATIVE_THEME_COMMON_THEME_H_
+#include "base/memory/scoped_ptr.h"
#include "ui/native_theme/native_theme.h"
class SkCanvas;
+namespace gfx {
+class Canvas;
+}
+
namespace ui {
// Drawing code that is common for all platforms.
@@ -23,6 +28,10 @@ gfx::Size NATIVE_THEME_EXPORT CommonThemeGetPartSize(
NativeTheme::State state,
const NativeTheme::ExtraParams& extra);
+void NATIVE_THEME_EXPORT CommonThemePaintComboboxArrow(
+ SkCanvas* canvas,
+ const gfx::Rect& rect);
+
void NATIVE_THEME_EXPORT CommonThemePaintMenuSeparator(
SkCanvas* canvas,
const gfx::Rect& rect,
@@ -39,6 +48,10 @@ void NATIVE_THEME_EXPORT CommonThemePaintMenuItemBackground(
NativeTheme::State state,
const gfx::Rect& rect);
+// Creates a gfx::Canvas wrapping an SkCanvas.
+scoped_ptr<gfx::Canvas> NATIVE_THEME_EXPORT CommonThemeCreateCanvas(
+ SkCanvas* sk_canvas);
+
} // namespace ui
#endif // UI_NATIVE_THEME_COMMON_THEME_H_
diff --git a/chromium/ui/native_theme/fallback_theme.cc b/chromium/ui/native_theme/fallback_theme.cc
index 6eb68643579..127243fdde0 100644
--- a/chromium/ui/native_theme/fallback_theme.cc
+++ b/chromium/ui/native_theme/fallback_theme.cc
@@ -7,7 +7,6 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "ui/gfx/color_utils.h"
-#include "ui/gfx/skia_utils_gtk.h"
#include "ui/native_theme/common_theme.h"
namespace ui {
@@ -22,8 +21,6 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
// This implementation returns hardcoded colors.
static const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
- // Menu:
- static const SkColor kMenuBackgroundColor = SK_ColorWHITE;
// Windows:
static const SkColor kWindowBackgroundColor = SK_ColorWHITE;
// Dialogs:
@@ -34,26 +31,10 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
// Button:
static const SkColor kButtonBackgroundColor = SkColorSetRGB(0xDE, 0xDE, 0xDE);
static const SkColor kButtonEnabledColor = SkColorSetRGB(0x22, 0x22, 0x22);
- static const SkColor kButtonDisabledColor = SkColorSetRGB(0x99, 0x99, 0x99);
static const SkColor kButtonHighlightColor = SkColorSetRGB(0, 0, 0);
static const SkColor kButtonHoverColor = kButtonEnabledColor;
- // MenuItem:
- static const SkColor kEnabledMenuItemForegroundColor = kButtonEnabledColor;
- static const SkColor kDisabledMenuItemForegroundColor = kButtonDisabledColor;
- static const SkColor kFocusedMenuItemBackgroundColor =
- SkColorSetRGB(0xF1, 0xF1, 0xF1);
- static const SkColor kHoverMenuItemBackgroundColor =
- SkColorSetARGB(204, 255, 255, 255);
- static const SkColor kMenuSeparatorColor = SkColorSetRGB(0xED, 0xED, 0xED);
- static const SkColor kEnabledMenuButtonBorderColor =
- SkColorSetARGB(36, 0, 0, 0);
- static const SkColor kFocusedMenuButtonBorderColor =
- SkColorSetARGB(72, 0, 0, 0);
- static const SkColor kHoverMenuButtonBorderColor =
- SkColorSetARGB(72, 0, 0, 0);
// Label:
static const SkColor kLabelEnabledColor = kButtonEnabledColor;
- static const SkColor kLabelDisabledColor = kButtonDisabledColor;
static const SkColor kLabelBackgroundColor = SK_ColorWHITE;
// Textfield:
static const SkColor kTextfieldDefaultColor = SK_ColorBLACK;
@@ -65,6 +46,9 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
static const SkColor kTextfieldSelectionColor =
color_utils::AlphaBlend(SK_ColorBLACK,
kTextfieldSelectionBackgroundFocused, 0xdd);
+ // Tooltip
+ static const SkColor kTooltipBackground = 0xFFFFFFCC;
+ static const SkColor kTooltipTextColor = kLabelEnabledColor;
// Tree
static const SkColor kTreeBackground = SK_ColorWHITE;
static const SkColor kTreeTextColor = SK_ColorBLACK;
@@ -80,6 +64,31 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
SkColorSetRGB(0xEE, 0xEE, 0xEE);
static const SkColor kTableGroupingIndicatorColor =
SkColorSetRGB(0xCC, 0xCC, 0xCC);
+ // Results Tables
+ static const SkColor kResultsTableHoveredBackground =
+ color_utils::AlphaBlend(kTextfieldSelectionBackgroundFocused,
+ kTextfieldDefaultBackground, 0x40);
+ static const SkColor kResultsTableNormalText = color_utils::AlphaBlend(
+ SK_ColorBLACK, kTextfieldDefaultBackground, 0xDD);
+ static const SkColor kResultsTableHoveredText = color_utils::AlphaBlend(
+ SK_ColorBLACK, kResultsTableHoveredBackground, 0xDD);
+ static const SkColor kResultsTableSelectedText = color_utils::AlphaBlend(
+ SK_ColorBLACK, kTextfieldSelectionBackgroundFocused, 0xDD);
+ static const SkColor kResultsTableNormalDimmedText = color_utils::AlphaBlend(
+ SK_ColorBLACK, kTextfieldDefaultBackground, 0xBB);
+ static const SkColor kResultsTableHoveredDimmedText = color_utils::AlphaBlend(
+ SK_ColorBLACK, kResultsTableHoveredBackground, 0xBB);
+ static const SkColor kResultsTableSelectedDimmedText =
+ color_utils::AlphaBlend(
+ SK_ColorBLACK, kTextfieldSelectionBackgroundFocused, 0xBB);
+ static const SkColor kResultsTableSelectedOrHoveredUrl =
+ SkColorSetARGB(0xff, 0x00, 0x66, 0x22);
+ static const SkColor kResultsTableNormalDivider = color_utils::AlphaBlend(
+ kResultsTableNormalText, kTextfieldDefaultBackground, 0x34);
+ static const SkColor kResultsTableHoveredDivider = color_utils::AlphaBlend(
+ kResultsTableHoveredText, kResultsTableHoveredBackground, 0x34);
+ static const SkColor kResultsTabSelectedDivider = color_utils::AlphaBlend(
+ kResultsTableSelectedText, kTextfieldSelectionBackgroundFocused, 0x34);
SkColor color;
if (CommonThemeGetSystemColor(color_id, &color))
@@ -105,38 +114,16 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
return kButtonBackgroundColor;
case kColorId_ButtonEnabledColor:
return kButtonEnabledColor;
- case kColorId_ButtonDisabledColor:
- return kButtonDisabledColor;
case kColorId_ButtonHighlightColor:
return kButtonHighlightColor;
case kColorId_ButtonHoverColor:
return kButtonHoverColor;
- // MenuItem
- case kColorId_EnabledMenuItemForegroundColor:
- return kEnabledMenuItemForegroundColor;
- case kColorId_DisabledMenuItemForegroundColor:
- return kDisabledMenuItemForegroundColor;
- case kColorId_SelectedMenuItemForegroundColor:
- return kEnabledMenuItemForegroundColor;
- case kColorId_FocusedMenuItemBackgroundColor:
- return kFocusedMenuItemBackgroundColor;
- case kColorId_HoverMenuItemBackgroundColor:
- return kHoverMenuItemBackgroundColor;
- case kColorId_MenuSeparatorColor:
- return kMenuSeparatorColor;
- case kColorId_EnabledMenuButtonBorderColor:
- return kEnabledMenuButtonBorderColor;
- case kColorId_FocusedMenuButtonBorderColor:
- return kFocusedMenuButtonBorderColor;
- case kColorId_HoverMenuButtonBorderColor:
- return kHoverMenuButtonBorderColor;
-
// Label
case kColorId_LabelEnabledColor:
return kLabelEnabledColor;
case kColorId_LabelDisabledColor:
- return kLabelDisabledColor;
+ return GetSystemColor(kColorId_ButtonDisabledColor);
case kColorId_LabelBackgroundColor:
return kLabelBackgroundColor;
@@ -154,6 +141,12 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
case kColorId_TextfieldSelectionBackgroundFocused:
return kTextfieldSelectionBackgroundFocused;
+ // Tooltip
+ case kColorId_TooltipBackground:
+ return kTooltipBackground;
+ case kColorId_TooltipText:
+ return kTooltipTextColor;
+
// Tree
case kColorId_TreeBackground:
return kTreeBackground;
@@ -182,9 +175,38 @@ SkColor FallbackTheme::GetSystemColor(ColorId color_id) const {
case kColorId_TableGroupingIndicatorColor:
return kTableGroupingIndicatorColor;
- case kColorId_MenuBackgroundColor:
- return kMenuBackgroundColor;
- case kColorId_MenuBorderColor:
+ // Results Tables
+ case kColorId_ResultsTableNormalBackground:
+ return kTextfieldDefaultBackground;
+ case kColorId_ResultsTableHoveredBackground:
+ return kResultsTableHoveredBackground;
+ case kColorId_ResultsTableSelectedBackground:
+ return kTextfieldSelectionBackgroundFocused;
+ case kColorId_ResultsTableNormalText:
+ return kResultsTableNormalText;
+ case kColorId_ResultsTableHoveredText:
+ return kResultsTableHoveredText;
+ case kColorId_ResultsTableSelectedText:
+ return kResultsTableSelectedText;
+ case kColorId_ResultsTableNormalDimmedText:
+ return kResultsTableNormalDimmedText;
+ case kColorId_ResultsTableHoveredDimmedText:
+ return kResultsTableHoveredDimmedText;
+ case kColorId_ResultsTableSelectedDimmedText:
+ return kResultsTableSelectedDimmedText;
+ case kColorId_ResultsTableNormalUrl:
+ return kTextfieldSelectionColor;
+ case kColorId_ResultsTableHoveredUrl:
+ case kColorId_ResultsTableSelectedUrl:
+ return kResultsTableSelectedOrHoveredUrl;
+ case kColorId_ResultsTableNormalDivider:
+ return kResultsTableNormalDivider;
+ case kColorId_ResultsTableHoveredDivider:
+ return kResultsTableHoveredDivider;
+ case kColorId_ResultsTableSelectedDivider:
+ return kResultsTabSelectedDivider;
+
+ default:
NOTREACHED();
break;
}
diff --git a/chromium/ui/native_theme/native_theme.cc b/chromium/ui/native_theme/native_theme.cc
index 8cb845cc306..94a1eeff98c 100644
--- a/chromium/ui/native_theme/native_theme.cc
+++ b/chromium/ui/native_theme/native_theme.cc
@@ -4,6 +4,8 @@
#include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/native_theme_observer.h"
+
namespace ui {
void NativeTheme::SetScrollbarColors(unsigned inactive_color,
@@ -17,6 +19,19 @@ void NativeTheme::SetScrollbarColors(unsigned inactive_color,
// NativeTheme::instance() is implemented in the platform specific source files,
// such as native_theme_win.cc or native_theme_linux.cc
+void NativeTheme::AddObserver(NativeThemeObserver* observer) {
+ native_theme_observers_.AddObserver(observer);
+}
+
+void NativeTheme::RemoveObserver(NativeThemeObserver* observer) {
+ native_theme_observers_.RemoveObserver(observer);
+}
+
+void NativeTheme::NotifyObservers() {
+ FOR_EACH_OBSERVER(NativeThemeObserver, native_theme_observers_,
+ OnNativeThemeUpdated(this));
+}
+
NativeTheme::NativeTheme()
: thumb_inactive_color_(0xeaeaea),
thumb_active_color_(0xf4f4f4),
diff --git a/chromium/ui/native_theme/native_theme.gyp b/chromium/ui/native_theme/native_theme.gyp
index 9fbe897d969..4cd287758e1 100644
--- a/chromium/ui/native_theme/native_theme.gyp
+++ b/chromium/ui/native_theme/native_theme.gyp
@@ -14,9 +14,10 @@
'../../base/base.gyp:base',
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
],
'defines': [
'NATIVE_THEME_IMPLEMENTATION',
@@ -32,12 +33,16 @@
'native_theme_android.h',
'native_theme_aura.cc',
'native_theme_aura.h',
+ 'native_theme_aurawin.cc',
+ 'native_theme_aurawin.h',
'native_theme_base.cc',
'native_theme_base.h',
- 'native_theme_gtk.cc',
- 'native_theme_gtk.h',
'native_theme_mac.h',
'native_theme_mac.mm',
+ 'native_theme_observer.cc',
+ 'native_theme_observer.h',
+ 'native_theme_switches.cc',
+ 'native_theme_switches.h',
'native_theme_win.cc',
'native_theme_win.h',
],
diff --git a/chromium/ui/native_theme/native_theme.h b/chromium/ui/native_theme/native_theme.h
index 98974145570..b43dea72b55 100644
--- a/chromium/ui/native_theme/native_theme.h
+++ b/chromium/ui/native_theme/native_theme.h
@@ -5,6 +5,7 @@
#ifndef UI_NATIVE_THEME_NATIVE_THEME_H_
#define UI_NATIVE_THEME_NATIVE_THEME_H_
+#include "base/observer_list.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/native_theme/native_theme_export.h"
@@ -18,6 +19,8 @@ class Size;
namespace ui {
+class NativeThemeObserver;
+
// This class supports drawing UI controls (like buttons, text fields, lists,
// comboboxes, etc) that look like the native UI controls of the underlying
// platform, such as Windows or Linux. It also supplies default colors for
@@ -39,6 +42,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
public:
// The part to be painted / sized.
enum Part {
+ kComboboxArrow,
kCheckbox,
kInnerSpinButton,
kMenuList,
@@ -66,6 +70,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
kScrollbarVerticalTrack,
kScrollbarHorizontalGripper,
kScrollbarVerticalGripper,
+ // The corner is drawn when there is both a horizontal and vertical
+ // scrollbar.
+ kScrollbarCorner,
kSliderTrack,
kSliderThumb,
kTabPanelBackground,
@@ -78,11 +85,12 @@ class NATIVE_THEME_EXPORT NativeTheme {
// The state of the part.
enum State {
- kDisabled,
- kHovered,
- kNormal,
- kPressed,
- kMaxState,
+ // IDs defined as specific values for use in arrays.
+ kDisabled = 0,
+ kHovered = 1,
+ kNormal = 2,
+ kPressed = 3,
+ kMaxState = 4,
};
// Each structure below holds extra information needed when painting a given
@@ -216,6 +224,15 @@ class NATIVE_THEME_EXPORT NativeTheme {
const gfx::Rect& rect,
const ExtraParams& extra) const = 0;
+ // Paint part during state transition, used for overlay scrollbar state
+ // transition animation.
+ virtual void PaintStateTransition(SkCanvas* canvas,
+ Part part,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const { }
+
// Supports theme specific colors.
void SetScrollbarColors(unsigned inactive_color,
unsigned active_color,
@@ -236,9 +253,15 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_ButtonDisabledColor,
kColorId_ButtonHighlightColor,
kColorId_ButtonHoverColor,
+ kColorId_ButtonHoverBackgroundColor,
+ kColorId_BlueButtonEnabledColor,
+ kColorId_BlueButtonDisabledColor,
+ kColorId_BlueButtonHighlightColor,
+ kColorId_BlueButtonHoverColor,
// MenuItem
kColorId_EnabledMenuItemForegroundColor,
kColorId_DisabledMenuItemForegroundColor,
+ kColorId_DisabledEmphasizedMenuItemForegroundColor,
kColorId_SelectedMenuItemForegroundColor,
kColorId_FocusedMenuItemBackgroundColor,
kColorId_HoverMenuItemBackgroundColor,
@@ -260,6 +283,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_TextfieldReadOnlyBackground,
kColorId_TextfieldSelectionColor,
kColorId_TextfieldSelectionBackgroundFocused,
+ // Tooltip
+ kColorId_TooltipBackground,
+ kColorId_TooltipText,
// Tree
kColorId_TreeBackground,
kColorId_TreeText,
@@ -276,6 +302,22 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_TableSelectionBackgroundFocused,
kColorId_TableSelectionBackgroundUnfocused,
kColorId_TableGroupingIndicatorColor,
+ // Results Tables, such as the chrome omnibox.
+ kColorId_ResultsTableNormalBackground,
+ kColorId_ResultsTableHoveredBackground,
+ kColorId_ResultsTableSelectedBackground,
+ kColorId_ResultsTableNormalText,
+ kColorId_ResultsTableHoveredText,
+ kColorId_ResultsTableSelectedText,
+ kColorId_ResultsTableNormalDimmedText,
+ kColorId_ResultsTableHoveredDimmedText,
+ kColorId_ResultsTableSelectedDimmedText,
+ kColorId_ResultsTableNormalUrl,
+ kColorId_ResultsTableHoveredUrl,
+ kColorId_ResultsTableSelectedUrl,
+ kColorId_ResultsTableNormalDivider,
+ kColorId_ResultsTableHoveredDivider,
+ kColorId_ResultsTableSelectedDivider,
// TODO(benrg): move other hardcoded colors here.
};
@@ -289,6 +331,13 @@ class NATIVE_THEME_EXPORT NativeTheme {
// function, returning the port's subclass.
static NativeTheme* instance();
+ // Add or remove observers to be notified when the native theme changes.
+ void AddObserver(NativeThemeObserver* observer);
+ void RemoveObserver(NativeThemeObserver* observer);
+
+ // Notify observers of native theme changes.
+ void NotifyObservers();
+
protected:
NativeTheme();
virtual ~NativeTheme();
@@ -297,6 +346,10 @@ class NATIVE_THEME_EXPORT NativeTheme {
unsigned int thumb_active_color_;
unsigned int track_color_;
+ private:
+ // Observers to notify when the native theme changes.
+ ObserverList<NativeThemeObserver> native_theme_observers_;
+
DISALLOW_COPY_AND_ASSIGN(NativeTheme);
};
diff --git a/chromium/ui/native_theme/native_theme_android.cc b/chromium/ui/native_theme/native_theme_android.cc
index 884bc7e3561..5fe2632a7e4 100644
--- a/chromium/ui/native_theme/native_theme_android.cc
+++ b/chromium/ui/native_theme/native_theme_android.cc
@@ -9,10 +9,12 @@
namespace ui {
+#if !defined(USE_AURA)
// static
NativeTheme* NativeTheme::instance() {
return NativeThemeAndroid::instance();
}
+#endif
// static
NativeThemeAndroid* NativeThemeAndroid::instance() {
diff --git a/chromium/ui/native_theme/native_theme_aura.cc b/chromium/ui/native_theme/native_theme_aura.cc
index c4e87243585..bc873bf1093 100644
--- a/chromium/ui/native_theme/native_theme_aura.cc
+++ b/chromium/ui/native_theme/native_theme_aura.cc
@@ -4,19 +4,70 @@
#include "ui/native_theme/native_theme_aura.h"
+#include <limits>
+
#include "base/logging.h"
#include "grit/ui_resources.h"
#include "ui/base/layout.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/nine_image_painter_factory.h"
+#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/nine_image_painter.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skbitmap_operations.h"
+#include "ui/gfx/skia_util.h"
#include "ui/native_theme/common_theme.h"
+#include "ui/native_theme/native_theme_switches.h"
+
+using gfx::NineImagePainter;
+
+#define EMPTY_IMAGE_GRID { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
namespace ui {
+namespace {
+
+const int kScrollbarThumbImages[NativeTheme::kMaxState][9] = {
+ EMPTY_IMAGE_GRID,
+ IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_HOVER),
+ IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_NORMAL),
+ IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_PRESSED)
+};
+
+const int kScrollbarArrowButtonImages[NativeTheme::kMaxState][9] = {
+ EMPTY_IMAGE_GRID,
+ IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER),
+ IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL),
+ IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED)
+};
+
+const uint8 kScrollbarOverlayThumbFillAlphas[NativeTheme::kMaxState] = {
+ 0, // Does not matter, will not paint for disabled state.
+ 178, // Hover state, opacity 70%, alpha would be 0.7 * 255.
+ 140, // Normal state, opacity 55%, alpha would be 0.55 * 255.
+ 178 // Pressed state, opacity 70%, alpha would be 0.7 * 255.
+};
+
+const uint8 kScrollbarOverlayThumbStrokeAlphas[NativeTheme::kMaxState] = {
+ 0, // Does not matter, will not paint for disabled state.
+ 51, // Hover state, opacity 20%, alpha would be 0.2 * 255.
+ 38, // Normal state, opacity 15%, alpha would be 0.15 * 255.
+ 51 // Pressed state, opacity 20%, alpha would be 0.2 * 255.
+};
+
+const int kScrollbarOverlayThumbStrokeImages[9] =
+ IMAGE_GRID_NO_CENTER(IDR_SCROLLBAR_OVERLAY_THUMB_STROKE);
+
+const int kScrollbarOverlayThumbFillImages[9] =
+ IMAGE_GRID(IDR_SCROLLBAR_OVERLAY_THUMB_FILL);
+
+const int kScrollbarTrackImages[9] = IMAGE_GRID(IDR_SCROLLBAR_BASE);
+
+} // namespace
+
+#if !defined(OS_WIN)
// static
NativeTheme* NativeTheme::instance() {
return NativeThemeAura::instance();
@@ -27,10 +78,20 @@ NativeThemeAura* NativeThemeAura::instance() {
CR_DEFINE_STATIC_LOCAL(NativeThemeAura, s_native_theme, ());
return &s_native_theme;
}
+#endif
NativeThemeAura::NativeThemeAura() {
// We don't draw scrollbar buttons.
+#if defined(OS_CHROMEOS)
set_scrollbar_button_length(0);
+#endif
+
+ // Images and alphas declarations assume the following order.
+ COMPILE_ASSERT(kDisabled == 0, states_unexepctedly_changed);
+ COMPILE_ASSERT(kHovered == 1, states_unexepctedly_changed);
+ COMPILE_ASSERT(kNormal == 2, states_unexepctedly_changed);
+ COMPILE_ASSERT(kPressed == 3, states_unexepctedly_changed);
+ COMPILE_ASSERT(kMaxState == 4, states_unexepctedly_changed);
}
NativeThemeAura::~NativeThemeAura() {
@@ -69,156 +130,201 @@ void NativeThemeAura::PaintMenuItemBackground(
CommonThemePaintMenuItemBackground(canvas, state, rect);
}
+void NativeThemeAura::PaintArrowButton(
+ SkCanvas* gc,
+ const gfx::Rect& rect,
+ Part direction,
+ State state) const {
+ if (direction == kInnerSpinButton) {
+ FallbackTheme::PaintArrowButton(gc, rect, direction, state);
+ return;
+ }
+ PaintPainter(GetOrCreatePainter(
+ kScrollbarArrowButtonImages, state,
+ scrollbar_arrow_button_painters_),
+ gc, rect);
+
+ // Aura-win uses slightly different arrow colors.
+ SkColor arrow_color = GetArrowColor(state);
+ switch (state) {
+ case kHovered:
+ case kNormal:
+ arrow_color = SkColorSetRGB(0x50, 0x50, 0x50);
+ break;
+ case kPressed:
+ arrow_color = SK_ColorWHITE;
+ default:
+ break;
+ }
+ PaintArrow(gc, rect, direction, arrow_color);
+}
+
void NativeThemeAura::PaintScrollbarTrack(
- SkCanvas* canvas,
+ SkCanvas* sk_canvas,
Part part,
State state,
const ScrollbarTrackExtraParams& extra_params,
const gfx::Rect& rect) const {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- if (part == kScrollbarVerticalTrack) {
- int center_offset = 0;
- int center_height = rect.height();
-
- if (rect.y() == extra_params.track_y) {
- // TODO(derat): Honor |state| instead of only using the highlighted images
- // after updating WebKit so we can draw the entire track in one go instead
- // of as two separate pieces: otherwise, only the portion of the scrollbar
- // that the mouse is over gets the highlighted state.
- gfx::ImageSkia* top = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_VERTICAL_TOP_H);
- DrawTiledImage(canvas, *top,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y(), top->width(), top->height());
- center_offset += top->height();
- center_height -= top->height();
- }
+ // Overlay Scrollbar should never paint a scrollbar track.
+ DCHECK(!IsOverlayScrollbarEnabled());
+ if (!scrollbar_track_painter_)
+ scrollbar_track_painter_ = CreateNineImagePainter(kScrollbarTrackImages);
+ PaintPainter(scrollbar_track_painter_.get(), sk_canvas, rect);
+}
- if (rect.y() + rect.height() ==
- extra_params.track_y + extra_params.track_height) {
- gfx::ImageSkia* bottom = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_VERTICAL_BOTTOM_H);
- DrawTiledImage(canvas, *bottom,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y() + rect.height() - bottom->height(),
- bottom->width(), bottom->height());
- center_height -= bottom->height();
- }
+void NativeThemeAura::PaintScrollbarThumb(SkCanvas* sk_canvas,
+ Part part,
+ State state,
+ const gfx::Rect& rect) const {
+ gfx::Rect thumb_rect(rect);
+ if (IsOverlayScrollbarEnabled()) {
+ // Overlay scrollbar has no track, just paint thumb directly.
+ // Do not paint if state is disabled.
+ if (state == kDisabled)
+ return;
- if (center_height > 0) {
- gfx::ImageSkia* center = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_VERTICAL_CENTER_H);
- DrawTiledImage(canvas, *center,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y() + center_offset,
- center->width(), center_height);
- }
- } else {
- int center_offset = 0;
- int center_width = rect.width();
-
- if (rect.x() == extra_params.track_x) {
- gfx::ImageSkia* left = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_HORIZONTAL_LEFT_H);
- DrawTiledImage(canvas, *left,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y(), left->width(), left->height());
- center_offset += left->width();
- center_width -= left->width();
+ if (!scrollbar_overlay_thumb_painter_) {
+ scrollbar_overlay_thumb_painter_ =
+ CreateDualPainter(kScrollbarOverlayThumbFillImages,
+ kScrollbarOverlayThumbFillAlphas,
+ kScrollbarOverlayThumbStrokeImages,
+ kScrollbarOverlayThumbStrokeAlphas);
}
- if (rect.x() + rect.width() ==
- extra_params.track_x + extra_params.track_width) {
- gfx::ImageSkia* right = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_HORIZONTAL_RIGHT_H);
- DrawTiledImage(canvas, *right,
- 0, 0, 1.0, 1.0,
- rect.x() + rect.width() - right->width(), rect.y(),
- right->width(), right->height());
- center_width -= right->width();
- }
+ PaintDualPainter(
+ scrollbar_overlay_thumb_painter_.get(), sk_canvas, thumb_rect, state);
+ return;
+ }
+ // If there are no scrollbuttons then provide some padding so that thumb
+ // doesn't touch the top of the track.
+ const int extra_padding = (scrollbar_button_length() == 0) ? 2 : 0;
+ if (part == NativeTheme::kScrollbarVerticalThumb)
+ thumb_rect.Inset(2, extra_padding, 2, extra_padding);
+ else
+ thumb_rect.Inset(extra_padding, 2, extra_padding, 2);
+ PaintPainter(GetOrCreatePainter(
+ kScrollbarThumbImages, state, scrollbar_thumb_painters_),
+ sk_canvas,
+ thumb_rect);
+}
- if (center_width > 0) {
- gfx::ImageSkia* center = rb.GetImageSkiaNamed(
- IDR_SCROLL_BASE_HORIZONTAL_CENTER_H);
- DrawTiledImage(canvas, *center,
- 0, 0, 1.0, 1.0,
- rect.x() + center_offset, rect.y(),
- center_width, center->height());
- }
+void NativeThemeAura::PaintScrollbarThumbStateTransition(
+ SkCanvas* canvas,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const {
+ // Only Overlay scrollbars should have state transition animation.
+ DCHECK(IsOverlayScrollbarEnabled());
+ if (!scrollbar_overlay_thumb_painter_) {
+ scrollbar_overlay_thumb_painter_ =
+ CreateDualPainter(kScrollbarOverlayThumbFillImages,
+ kScrollbarOverlayThumbFillAlphas,
+ kScrollbarOverlayThumbStrokeImages,
+ kScrollbarOverlayThumbStrokeAlphas);
}
+
+ PaintDualPainterTransition(scrollbar_overlay_thumb_painter_.get(),
+ canvas,
+ rect,
+ startState,
+ endState,
+ progress);
}
-void NativeThemeAura::PaintScrollbarThumb(SkCanvas* canvas,
- Part part,
- State state,
- const gfx::Rect& rect) const {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- if (part == kScrollbarVerticalThumb) {
- int top_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_VERTICAL_TOP_H :
- state == kPressed ? IDR_SCROLL_THUMB_VERTICAL_TOP_P :
- IDR_SCROLL_THUMB_VERTICAL_TOP;
- gfx::ImageSkia* top = rb.GetImageSkiaNamed(top_resource_id);
- DrawTiledImage(canvas, *top,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y(), top->width(), top->height());
-
- int bottom_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_VERTICAL_BOTTOM_H :
- state == kPressed ? IDR_SCROLL_THUMB_VERTICAL_BOTTOM_P :
- IDR_SCROLL_THUMB_VERTICAL_BOTTOM;
- gfx::ImageSkia* bottom = rb.GetImageSkiaNamed(bottom_resource_id);
- DrawTiledImage(canvas, *bottom,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y() + rect.height() - bottom->height(),
- bottom->width(), bottom->height());
-
- if (rect.height() > top->height() + bottom->height()) {
- int center_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_VERTICAL_CENTER_H :
- state == kPressed ? IDR_SCROLL_THUMB_VERTICAL_CENTER_P :
- IDR_SCROLL_THUMB_VERTICAL_CENTER;
- gfx::ImageSkia* center = rb.GetImageSkiaNamed(center_resource_id);
- DrawTiledImage(canvas, *center,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y() + top->height(),
- center->width(),
- rect.height() - top->height() - bottom->height());
- }
- } else {
- int left_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_HORIZONTAL_LEFT_H :
- state == kPressed ? IDR_SCROLL_THUMB_HORIZONTAL_LEFT_P :
- IDR_SCROLL_THUMB_HORIZONTAL_LEFT;
- gfx::ImageSkia* left = rb.GetImageSkiaNamed(left_resource_id);
- DrawTiledImage(canvas, *left,
- 0, 0, 1.0, 1.0,
- rect.x(), rect.y(), left->width(), left->height());
-
- int right_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_HORIZONTAL_RIGHT_H :
- state == kPressed ? IDR_SCROLL_THUMB_HORIZONTAL_RIGHT_P :
- IDR_SCROLL_THUMB_HORIZONTAL_RIGHT;
- gfx::ImageSkia* right = rb.GetImageSkiaNamed(right_resource_id);
- DrawTiledImage(canvas, *right,
- 0, 0, 1.0, 1.0,
- rect.x() + rect.width() - right->width(), rect.y(),
- right->width(), right->height());
-
- if (rect.width() > left->width() + right->width()) {
- int center_resource_id =
- state == kHovered ? IDR_SCROLL_THUMB_HORIZONTAL_CENTER_H :
- state == kPressed ? IDR_SCROLL_THUMB_HORIZONTAL_CENTER_P :
- IDR_SCROLL_THUMB_HORIZONTAL_CENTER;
- gfx::ImageSkia* center = rb.GetImageSkiaNamed(center_resource_id);
- DrawTiledImage(canvas, *center,
- 0, 0, 1.0, 1.0,
- rect.x() + left->width(), rect.y(),
- rect.width() - left->width() - right->width(),
- center->height());
- }
+void NativeThemeAura::PaintScrollbarCorner(SkCanvas* canvas,
+ State state,
+ const gfx::Rect& rect) const {
+ // Overlay Scrollbar should never paint a scrollbar corner.
+ DCHECK(!IsOverlayScrollbarEnabled());
+ SkPaint paint;
+ paint.setColor(SkColorSetRGB(0xF1, 0xF1, 0xF1));
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawIRect(RectToSkIRect(rect), paint);
+}
+
+NineImagePainter* NativeThemeAura::GetOrCreatePainter(
+ const int images[kMaxState][9],
+ State state,
+ scoped_ptr<NineImagePainter> painters[kMaxState]) const {
+ if (painters[state])
+ return painters[state].get();
+ if (images[state][0] == 0) {
+ // Must always provide normal state images.
+ DCHECK_NE(kNormal, state);
+ return GetOrCreatePainter(images, kNormal, painters);
}
+ painters[state] = CreateNineImagePainter(images[state]);
+ return painters[state].get();
+}
+
+void NativeThemeAura::PaintPainter(NineImagePainter* painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect) const {
+ DCHECK(painter);
+ scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
+ painter->Paint(canvas.get(), rect);
+}
+
+scoped_ptr<NativeThemeAura::DualPainter> NativeThemeAura::CreateDualPainter(
+ const int fill_image_ids[9],
+ const uint8 fill_alphas[kMaxState],
+ const int stroke_image_ids[9],
+ const uint8 stroke_alphas[kMaxState]) const {
+ scoped_ptr<NativeThemeAura::DualPainter> dual_painter(
+ new NativeThemeAura::DualPainter(CreateNineImagePainter(fill_image_ids),
+ fill_alphas,
+ CreateNineImagePainter(stroke_image_ids),
+ stroke_alphas));
+ return dual_painter.Pass();
+}
+
+void NativeThemeAura::PaintDualPainter(
+ NativeThemeAura::DualPainter* dual_painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect,
+ State state) const {
+ DCHECK(dual_painter);
+ scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
+ dual_painter->fill_painter->Paint(
+ canvas.get(), rect, dual_painter->fill_alphas[state]);
+ dual_painter->stroke_painter->Paint(
+ canvas.get(), rect, dual_painter->stroke_alphas[state]);
}
+void NativeThemeAura::PaintDualPainterTransition(
+ NativeThemeAura::DualPainter* dual_painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect,
+ State startState,
+ State endState,
+ double progress) const {
+ DCHECK(dual_painter);
+ scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
+ uint8 fill_alpha = dual_painter->fill_alphas[startState] +
+ (dual_painter->fill_alphas[endState] -
+ dual_painter->fill_alphas[startState]) *
+ progress;
+ uint8 stroke_alpha = dual_painter->stroke_alphas[startState] +
+ (dual_painter->stroke_alphas[endState] -
+ dual_painter->stroke_alphas[startState]) *
+ progress;
+
+ dual_painter->fill_painter->Paint(canvas.get(), rect, fill_alpha);
+ dual_painter->stroke_painter->Paint(canvas.get(), rect, stroke_alpha);
+}
+
+NativeThemeAura::DualPainter::DualPainter(
+ scoped_ptr<NineImagePainter> fill_painter,
+ const uint8 fill_alphas[kMaxState],
+ scoped_ptr<NineImagePainter> stroke_painter,
+ const uint8 stroke_alphas[kMaxState])
+ : fill_painter(fill_painter.Pass()),
+ fill_alphas(fill_alphas),
+ stroke_painter(stroke_painter.Pass()),
+ stroke_alphas(stroke_alphas) {}
+
+NativeThemeAura::DualPainter::~DualPainter() {}
+
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_aura.h b/chromium/ui/native_theme/native_theme_aura.h
index b3417b353ce..b63556c0284 100644
--- a/chromium/ui/native_theme/native_theme_aura.h
+++ b/chromium/ui/native_theme/native_theme_aura.h
@@ -9,6 +9,10 @@
#include "base/compiler_specific.h"
#include "ui/native_theme/fallback_theme.h"
+namespace gfx {
+class NineImagePainter;
+}
+
namespace ui {
// Aura implementation of native theme support.
@@ -16,7 +20,7 @@ class NATIVE_THEME_EXPORT NativeThemeAura : public FallbackTheme {
public:
static NativeThemeAura* instance();
- private:
+ protected:
NativeThemeAura();
virtual ~NativeThemeAura();
@@ -30,16 +34,92 @@ class NATIVE_THEME_EXPORT NativeThemeAura : public FallbackTheme {
State state,
const gfx::Rect& rect,
const MenuListExtraParams& menu_list) const OVERRIDE;
+ virtual void PaintArrowButton(SkCanvas* gc,
+ const gfx::Rect& rect,
+ Part direction,
+ State state) const OVERRIDE;
virtual void PaintScrollbarTrack(
- SkCanvas* canvas,
+ SkCanvas* sk_canvas,
Part part,
State state,
const ScrollbarTrackExtraParams& extra_params,
const gfx::Rect& rect) const OVERRIDE;
- virtual void PaintScrollbarThumb(SkCanvas* canvas,
+ virtual void PaintScrollbarThumb(SkCanvas* sk_canvas,
Part part,
State state,
const gfx::Rect& rect) const OVERRIDE;
+ virtual void PaintScrollbarCorner(SkCanvas* canvas,
+ State state,
+ const gfx::Rect& rect) const OVERRIDE;
+
+ virtual void PaintScrollbarThumbStateTransition(SkCanvas* canvas,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const
+ OVERRIDE;
+
+ // Returns the NineImagePainter used to paint the specified state, creating if
+ // necessary. If no image is provided for the specified state the normal state
+ // images are used.
+ gfx::NineImagePainter* GetOrCreatePainter(
+ const int image_ids[kMaxState][9],
+ State state,
+ scoped_ptr<gfx::NineImagePainter> painters[kMaxState]) const;
+
+ // Paints |painter| into the canvas using |rect|.
+ void PaintPainter(gfx::NineImagePainter* painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect) const;
+
+ mutable scoped_ptr<gfx::NineImagePainter> scrollbar_track_painter_;
+
+ mutable scoped_ptr<gfx::NineImagePainter>
+ scrollbar_thumb_painters_[kMaxState];
+
+ mutable scoped_ptr<gfx::NineImagePainter>
+ scrollbar_arrow_button_painters_[kMaxState];
+
+ private:
+ struct DualPainter {
+ // For overlay scrollbar thumbs, fill and stroke are controlled separately,
+ // and each state is achieved by painting with different opacity. This
+ // struct bundles information of painter generated using assets and alpha
+ // value associated with each state, so that a DualPainter for overlay
+ // scrollbar thumb would only need state as input to paint correctly.
+ DualPainter(scoped_ptr<gfx::NineImagePainter> fill_painter,
+ const uint8 fill_alphas[kMaxState],
+ scoped_ptr<gfx::NineImagePainter> stroke_painter,
+ const uint8 stroke_alphas[kMaxState]);
+ ~DualPainter();
+
+ scoped_ptr<gfx::NineImagePainter> fill_painter;
+ const uint8* const fill_alphas;
+ scoped_ptr<gfx::NineImagePainter> stroke_painter;
+ const uint8* const stroke_alphas;
+ };
+
+ // Returns DualPainter from specific fill and stroke, creating if necessary.
+ scoped_ptr<DualPainter> CreateDualPainter(
+ const int fill_image_ids[9],
+ const uint8 fill_alphas[kMaxState],
+ const int stroke_image_ids[9],
+ const uint8 stroke_alphas[kMaxState]) const;
+
+ // Paints |dualPainter| into the canvas using |rect| and specific alpha.
+ void PaintDualPainter(DualPainter* dual_painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect,
+ State state) const;
+
+ void PaintDualPainterTransition(DualPainter* dual_painter,
+ SkCanvas* sk_canvas,
+ const gfx::Rect& rect,
+ State startState,
+ State endState,
+ double progress) const;
+
+ mutable scoped_ptr<DualPainter> scrollbar_overlay_thumb_painter_;
DISALLOW_COPY_AND_ASSIGN(NativeThemeAura);
};
diff --git a/chromium/ui/native_theme/native_theme_aurawin.cc b/chromium/ui/native_theme/native_theme_aurawin.cc
new file mode 100644
index 00000000000..3cc01e5b0fd
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_aurawin.cc
@@ -0,0 +1,86 @@
+// 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/native_theme/native_theme_aurawin.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/native_theme/common_theme.h"
+#include "ui/native_theme/native_theme_win.h"
+
+namespace ui {
+
+namespace {
+
+bool IsScrollbarPart(NativeTheme::Part part) {
+ switch (part) {
+ case NativeTheme::kScrollbarDownArrow:
+ case NativeTheme::kScrollbarLeftArrow:
+ case NativeTheme::kScrollbarRightArrow:
+ case NativeTheme::kScrollbarUpArrow:
+ case NativeTheme::kScrollbarHorizontalThumb:
+ case NativeTheme::kScrollbarVerticalThumb:
+ case NativeTheme::kScrollbarHorizontalTrack:
+ case NativeTheme::kScrollbarVerticalTrack:
+ case NativeTheme::kScrollbarHorizontalGripper:
+ case NativeTheme::kScrollbarVerticalGripper:
+ case NativeTheme::kScrollbarCorner:
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+// static
+NativeTheme* NativeTheme::instance() {
+ return NativeThemeAuraWin::instance();
+}
+
+// static
+NativeThemeAura* NativeThemeAura::instance() {
+ return NativeThemeAuraWin::instance();
+}
+
+// static
+NativeThemeAuraWin* NativeThemeAuraWin::instance() {
+ CR_DEFINE_STATIC_LOCAL(NativeThemeAuraWin, s_native_theme, ());
+ return &s_native_theme;
+}
+
+NativeThemeAuraWin::NativeThemeAuraWin() {
+}
+
+NativeThemeAuraWin::~NativeThemeAuraWin() {
+}
+
+void NativeThemeAuraWin::Paint(SkCanvas* canvas,
+ Part part,
+ State state,
+ const gfx::Rect& rect,
+ const ExtraParams& extra) const {
+ if (IsScrollbarPart(part) &&
+ NativeThemeWin::instance()->IsUsingHighContrastTheme()) {
+ NativeThemeWin::instance()->Paint(canvas, part, state, rect, extra);
+ return;
+ }
+
+ NativeThemeAura::Paint(canvas, part, state, rect, extra);
+}
+
+gfx::Size NativeThemeAuraWin::GetPartSize(Part part,
+ State state,
+ const ExtraParams& extra) const {
+ gfx::Size part_size = CommonThemeGetPartSize(part, state, extra);
+ if (!part_size.IsEmpty())
+ return part_size;
+
+ // We want aura on windows to use the same size for scrollbars as we would in
+ // the native theme.
+ if (IsScrollbarPart(part))
+ return NativeThemeWin::instance()->GetPartSize(part, state, extra);
+
+ return NativeThemeAura::GetPartSize(part, state, extra);
+}
+
+} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_aurawin.h b/chromium/ui/native_theme/native_theme_aurawin.h
new file mode 100644
index 00000000000..0b3a29e3cab
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_aurawin.h
@@ -0,0 +1,37 @@
+// 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_NATIVE_THEME_NATIVE_THEME_AURAWIN_H_
+#define UI_NATIVE_THEME_NATIVE_THEME_AURAWIN_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/native_theme/native_theme_aura.h"
+
+namespace ui {
+
+// Aura implementation of native theme support.
+class NATIVE_THEME_EXPORT NativeThemeAuraWin : public NativeThemeAura {
+ public:
+ static NativeThemeAuraWin* instance();
+
+ private:
+ NativeThemeAuraWin();
+ virtual ~NativeThemeAuraWin();
+
+ // Overridden from NativeThemeBase:
+ virtual gfx::Size GetPartSize(Part part,
+ State state,
+ const ExtraParams& extra) const OVERRIDE;
+ virtual void Paint(SkCanvas* canvas,
+ Part part,
+ State state,
+ const gfx::Rect& rect,
+ const ExtraParams& extra) const OVERRIDE;
+ DISALLOW_COPY_AND_ASSIGN(NativeThemeAuraWin);
+};
+
+} // namespace ui
+
+#endif // UI_NATIVE_THEME_NATIVE_THEME_AURAWIN_H_
diff --git a/chromium/ui/native_theme/native_theme_base.cc b/chromium/ui/native_theme/native_theme_base.cc
index 3f88ddd8387..1272af7ecd1 100644
--- a/chromium/ui/native_theme/native_theme_base.cc
+++ b/chromium/ui/native_theme/native_theme_base.cc
@@ -20,6 +20,7 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
+#include "ui/native_theme/common_theme.h"
namespace {
@@ -89,6 +90,10 @@ namespace ui {
gfx::Size NativeThemeBase::GetPartSize(Part part,
State state,
const ExtraParams& extra) const {
+ gfx::Size size = CommonThemeGetPartSize(part, state, extra);
+ if (!size.IsEmpty())
+ return size;
+
switch (part) {
// Please keep these in the order of NativeTheme::Part.
case kCheckbox:
@@ -156,6 +161,31 @@ gfx::Size NativeThemeBase::GetPartSize(Part part,
return gfx::Size();
}
+void NativeThemeBase::PaintStateTransition(SkCanvas* canvas,
+ Part part,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const {
+ if (rect.IsEmpty())
+ return;
+
+ // Currently state transition is animation only working for overlay scrollbars
+ // on Aura platforms.
+ switch (part) {
+ case kScrollbarHorizontalThumb:
+ case kScrollbarVerticalThumb:
+ PaintScrollbarThumbStateTransition(
+ canvas, startState, endState, progress, rect);
+ break;
+ default:
+ NOTREACHED() << "Does not support state transition for this part:"
+ << part;
+ break;
+ }
+ return;
+}
+
void NativeThemeBase::Paint(SkCanvas* canvas,
Part part,
State state,
@@ -166,6 +196,9 @@ void NativeThemeBase::Paint(SkCanvas* canvas,
switch (part) {
// Please keep these in the order of NativeTheme::Part.
+ case kComboboxArrow:
+ CommonThemePaintComboboxArrow(canvas, rect);
+ break;
case kCheckbox:
PaintCheckbox(canvas, state, rect, extra.button);
break;
@@ -218,6 +251,9 @@ void NativeThemeBase::Paint(SkCanvas* canvas,
// Invoked by views scrollbar code, don't care about for non-win
// implementations, so no NOTIMPLEMENTED.
break;
+ case kScrollbarCorner:
+ PaintScrollbarCorner(canvas, state, rect);
+ break;
case kSliderTrack:
PaintSliderTrack(canvas, state, rect, extra.slider);
break;
@@ -252,15 +288,7 @@ NativeThemeBase::~NativeThemeBase() {
void NativeThemeBase::PaintArrowButton(
SkCanvas* canvas,
const gfx::Rect& rect, Part direction, State state) const {
- int widthMiddle, lengthMiddle;
SkPaint paint;
- if (direction == kScrollbarUpArrow || direction == kScrollbarDownArrow) {
- widthMiddle = rect.width() / 2 + 1;
- lengthMiddle = rect.height() / 2 + 1;
- } else {
- lengthMiddle = rect.width() / 2 + 1;
- widthMiddle = rect.height() / 2 + 1;
- }
// Calculate button color.
SkScalar trackHSV[3];
@@ -335,11 +363,24 @@ void NativeThemeBase::PaintArrowButton(
paint.setColor(OutlineColor(trackHSV, thumbHSV));
canvas->drawPath(outline, paint);
- // If the button is disabled or read-only, the arrow is drawn with the
- // outline color.
- if (state != kDisabled)
- paint.setColor(SK_ColorBLACK);
+ PaintArrow(canvas, rect, direction, GetArrowColor(state));
+}
+
+void NativeThemeBase::PaintArrow(SkCanvas* gc,
+ const gfx::Rect& rect,
+ Part direction,
+ SkColor color) const {
+ int width_middle, length_middle;
+ if (direction == kScrollbarUpArrow || direction == kScrollbarDownArrow) {
+ width_middle = rect.width() / 2 + 1;
+ length_middle = rect.height() / 2 + 1;
+ } else {
+ length_middle = rect.width() / 2 + 1;
+ width_middle = rect.height() / 2 + 1;
+ }
+ SkPaint paint;
+ paint.setColor(color);
paint.setAntiAlias(false);
paint.setStyle(SkPaint::kFill_Style);
@@ -348,22 +389,22 @@ void NativeThemeBase::PaintArrowButton(
// looking arrows without anti-aliasing.
switch (direction) {
case kScrollbarUpArrow:
- path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle + 2);
+ path.moveTo(rect.x() + width_middle - 4, rect.y() + length_middle + 2);
path.rLineTo(7, 0);
path.rLineTo(-4, -4);
break;
case kScrollbarDownArrow:
- path.moveTo(rect.x() + widthMiddle - 4, rect.y() + lengthMiddle - 3);
+ path.moveTo(rect.x() + width_middle - 4, rect.y() + length_middle - 3);
path.rLineTo(7, 0);
path.rLineTo(-4, 4);
break;
case kScrollbarRightArrow:
- path.moveTo(rect.x() + lengthMiddle - 3, rect.y() + widthMiddle - 4);
+ path.moveTo(rect.x() + length_middle - 3, rect.y() + width_middle - 4);
path.rLineTo(0, 7);
path.rLineTo(4, -4);
break;
case kScrollbarLeftArrow:
- path.moveTo(rect.x() + lengthMiddle + 1, rect.y() + widthMiddle - 5);
+ path.moveTo(rect.x() + length_middle + 1, rect.y() + width_middle - 5);
path.rLineTo(0, 9);
path.rLineTo(-4, -4);
break;
@@ -372,7 +413,7 @@ void NativeThemeBase::PaintArrowButton(
}
path.close();
- canvas->drawPath(path, paint);
+ gc->drawPath(path, paint);
}
void NativeThemeBase::PaintScrollbarTrack(SkCanvas* canvas,
@@ -475,6 +516,16 @@ void NativeThemeBase::PaintScrollbarThumb(SkCanvas* canvas,
}
}
+void NativeThemeBase::PaintScrollbarCorner(SkCanvas* canvas,
+ State state,
+ const gfx::Rect& rect) const {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawIRect(RectToSkIRect(rect), paint);
+}
+
void NativeThemeBase::PaintCheckbox(SkCanvas* canvas,
State state,
const gfx::Rect& rect,
@@ -577,7 +628,7 @@ SkRect NativeThemeBase::PaintCheckboxRadioCommon(
SkColor colors[3] = {startEndColors[0], startEndColors[0], startEndColors[1]};
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
- gradient_bounds, colors, NULL, 3, SkShader::kClamp_TileMode, NULL));
+ gradient_bounds, colors, NULL, 3, SkShader::kClamp_TileMode));
SkPaint paint;
paint.setAntiAlias(true);
paint.setShader(shader.get());
@@ -664,7 +715,7 @@ void NativeThemeBase::PaintButton(SkCanvas* canvas,
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
- gradient_bounds, colors, NULL, 2, SkShader::kClamp_TileMode, NULL));
+ gradient_bounds, colors, NULL, 2, SkShader::kClamp_TileMode));
paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
paint.setShader(shader.get());
@@ -931,12 +982,7 @@ void NativeThemeBase::DrawImageInt(
SkCanvas* sk_canvas, const gfx::ImageSkia& image,
int src_x, int src_y, int src_w, int src_h,
int dest_x, int dest_y, int dest_w, int dest_h) const {
- // TODO(pkotwicz): Do something better and don't infer device
- // scale factor from canvas scale.
- SkMatrix m = sk_canvas->getTotalMatrix();
- float device_scale = static_cast<float>(SkScalarAbs(m.getScaleX()));
- scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvasWithoutScaling(
- sk_canvas, device_scale));
+ scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
canvas->DrawImageInt(image, src_x, src_y, src_w, src_h,
dest_x, dest_y, dest_w, dest_h, true);
}
@@ -945,12 +991,7 @@ void NativeThemeBase::DrawTiledImage(SkCanvas* sk_canvas,
const gfx::ImageSkia& image,
int src_x, int src_y, float tile_scale_x, float tile_scale_y,
int dest_x, int dest_y, int w, int h) const {
- // TODO(pkotwicz): Do something better and don't infer device
- // scale factor from canvas scale.
- SkMatrix m = sk_canvas->getTotalMatrix();
- float device_scale = static_cast<float>(SkScalarAbs(m.getScaleX()));
- scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvasWithoutScaling(
- sk_canvas, device_scale));
+ scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
canvas->TileImageInt(image, src_x, src_y, tile_scale_x,
tile_scale_y, dest_x, dest_y, w, h);
}
@@ -965,6 +1006,17 @@ SkColor NativeThemeBase::SaturateAndBrighten(SkScalar* hsv,
return SkHSVToColor(color);
}
+SkColor NativeThemeBase::GetArrowColor(State state) const {
+ if (state != kDisabled)
+ return SK_ColorBLACK;
+
+ SkScalar track_hsv[3];
+ SkColorToHSV(track_color_, track_hsv);
+ SkScalar thumb_hsv[3];
+ SkColorToHSV(thumb_inactive_color_, thumb_hsv);
+ return OutlineColor(track_hsv, thumb_hsv);
+}
+
void NativeThemeBase::DrawVertLine(SkCanvas* canvas,
int x,
int y1,
diff --git a/chromium/ui/native_theme/native_theme_base.h b/chromium/ui/native_theme/native_theme_base.h
index 9e314c333d6..e0a877ff12a 100644
--- a/chromium/ui/native_theme/native_theme_base.h
+++ b/chromium/ui/native_theme/native_theme_base.h
@@ -7,10 +7,12 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "skia/ext/platform_canvas.h"
#include "ui/native_theme/native_theme.h"
namespace gfx {
+class Canvas;
class ImageSkia;
class Rect;
class Size;
@@ -31,6 +33,13 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
const gfx::Rect& rect,
const ExtraParams& extra) const OVERRIDE;
+ virtual void PaintStateTransition(SkCanvas* canvas,
+ Part part,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const OVERRIDE;
+
protected:
NativeThemeBase();
virtual ~NativeThemeBase();
@@ -56,6 +65,10 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
State state,
const gfx::Rect& rect) const;
+ virtual void PaintScrollbarCorner(SkCanvas* canvas,
+ State state,
+ const gfx::Rect& rect) const;
+
virtual void PaintCheckbox(
SkCanvas* canvas,
State state,
@@ -121,10 +134,17 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
const gfx::Rect& rect,
const ProgressBarExtraParams& progress_bar) const;
- protected:
+ virtual void PaintScrollbarThumbStateTransition(
+ SkCanvas* canvas,
+ State startState,
+ State endState,
+ double progress,
+ const gfx::Rect& rect) const {}
+
void set_scrollbar_button_length(unsigned int length) {
scrollbar_button_length_ = length;
}
+ int scrollbar_button_length() const { return scrollbar_button_length_; }
bool IntersectsClipRectInt(SkCanvas* canvas,
int x, int y, int w, int h) const;
@@ -142,6 +162,16 @@ class NATIVE_THEME_EXPORT NativeThemeBase : public NativeTheme {
SkColor SaturateAndBrighten(SkScalar* hsv,
SkScalar saturate_amount,
SkScalar brighten_amount) const;
+
+ // Paints the arrow used on the scrollbar and spinner.
+ void PaintArrow(SkCanvas* canvas,
+ const gfx::Rect& rect,
+ Part direction,
+ SkColor color) const;
+
+ // Returns the color used to draw the arrow.
+ SkColor GetArrowColor(State state) const;
+
private:
void DrawVertLine(SkCanvas* canvas,
int x,
diff --git a/chromium/ui/native_theme/native_theme_gtk.cc b/chromium/ui/native_theme/native_theme_gtk.cc
deleted file mode 100644
index e74976678d8..00000000000
--- a/chromium/ui/native_theme/native_theme_gtk.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/native_theme/native_theme_gtk.h"
-
-#include <gtk/gtk.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "ui/gfx/skia_utils_gtk.h"
-
-namespace {
-
-const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
-
-// Theme colors returned by GetSystemColor().
-
-// FocusableBorder:
-const SkColor kFocusedBorderColor = SkColorSetRGB(0x4D, 0x90, 0xFE);
-const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xD9, 0xD9, 0xD9);
-
-// MenuItem
-const SkColor kFocusedMenuItemBackgroundColor = SkColorSetARGB(13, 0, 0, 0);
-const SkColor kHoverMenuItemBackgroundColor = SkColorSetRGB(204, 204, 204);
-
-// MenuButton
-const SkColor kEnabledMenuButtonBorderColor = SkColorSetARGB(36, 0, 0, 0);
-const SkColor kFocusedMenuButtonBorderColor = SkColorSetARGB(72, 0, 0, 0);
-const SkColor kHoverMenuButtonBorderColor = SkColorSetARGB(72, 0, 0, 0);
-
-// Button:
-const SkColor kButtonBackgroundColor = SkColorSetRGB(0xde, 0xde, 0xde);
-const SkColor kButtonEnabledColor = SkColorSetRGB(6, 45, 117);
-const SkColor kButtonDisabledColor = SkColorSetRGB(161, 161, 146);
-const SkColor kButtonHighlightColor = SkColorSetARGB(200, 255, 255, 255);
-const SkColor kButtonHoverColor = kButtonEnabledColor;
-
-} // namespace
-
-namespace ui {
-
-// static
-NativeTheme* NativeTheme::instance() {
- return NativeThemeGtk::instance();
-}
-
-// static
-NativeThemeGtk* NativeThemeGtk::instance() {
- CR_DEFINE_STATIC_LOCAL(NativeThemeGtk, s_native_theme, ());
- return &s_native_theme;
-}
-
-SkColor NativeThemeGtk::GetSystemColor(ColorId color_id) const {
- switch (color_id) {
- case kColorId_DialogBackground:
- // TODO(benrg): This code used to call gtk_widget_get_style() on the
- // widget being styled. After refactoring, that widget is not available
- // and we have to call gtk_widget_get_default_style(). Unfortunately,
- // it turns out that this breaks everything (chromium bug 105609,
- // chromium-os bug 23461). Need to figure out the right thing and do it.
- return gfx::GdkColorToSkColor(
- gtk_widget_get_default_style()->bg[GTK_STATE_NORMAL]);
-
- // FocusableBorder:
- case kColorId_FocusedBorderColor:
- return kFocusedBorderColor;
- case kColorId_UnfocusedBorderColor:
- return kUnfocusedBorderColor;
-
- // MenuItem
- case kColorId_FocusedMenuItemBackgroundColor:
- return kFocusedMenuItemBackgroundColor;
- case kColorId_HoverMenuItemBackgroundColor:
- return kHoverMenuItemBackgroundColor;
- case kColorId_EnabledMenuButtonBorderColor:
- return kEnabledMenuButtonBorderColor;
- case kColorId_FocusedMenuButtonBorderColor:
- return kFocusedMenuButtonBorderColor;
- case kColorId_HoverMenuButtonBorderColor:
- return kHoverMenuButtonBorderColor;
-
- // Button:
- case kColorId_ButtonBackgroundColor:
- return kButtonBackgroundColor;
- case kColorId_ButtonEnabledColor:
- return kButtonEnabledColor;
- case kColorId_ButtonDisabledColor:
- return kButtonDisabledColor;
- case kColorId_ButtonHighlightColor:
- return kButtonHighlightColor;
- case kColorId_ButtonHoverColor:
- return kButtonHoverColor;
-
- default:
- NOTREACHED() << "Invalid color_id: " << color_id;
- break;
- }
- return kInvalidColorIdColor;
-}
-
-NativeThemeGtk::NativeThemeGtk() {
-}
-
-NativeThemeGtk::~NativeThemeGtk() {
-}
-
-} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_gtk.h b/chromium/ui/native_theme/native_theme_gtk.h
deleted file mode 100644
index 05f5a8cd7b4..00000000000
--- a/chromium/ui/native_theme/native_theme_gtk.h
+++ /dev/null
@@ -1,28 +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_NATIVE_THEME_NATIVE_THEME_GTK_H_
-#define UI_NATIVE_THEME_NATIVE_THEME_GTK_H_
-
-#include "ui/native_theme/native_theme_base.h"
-
-namespace ui {
-
-// GTK implementation of native theme support.
-class NativeThemeGtk : public NativeThemeBase {
- public:
- static NativeThemeGtk* instance();
-
- virtual SkColor GetSystemColor(ColorId color_id) const OVERRIDE;
-
- private:
- NativeThemeGtk();
- virtual ~NativeThemeGtk();
-
- DISALLOW_COPY_AND_ASSIGN(NativeThemeGtk);
-};
-
-} // namespace ui
-
-#endif // UI_NATIVE_THEME_NATIVE_THEME_GTK_H_
diff --git a/chromium/ui/native_theme/native_theme_mac.h b/chromium/ui/native_theme/native_theme_mac.h
index 20378426db5..d65825cbcbf 100644
--- a/chromium/ui/native_theme/native_theme_mac.h
+++ b/chromium/ui/native_theme/native_theme_mac.h
@@ -5,12 +5,14 @@
#ifndef UI_NATIVE_THEME_NATIVE_THEME_MAC_H_
#define UI_NATIVE_THEME_NATIVE_THEME_MAC_H_
-#include "ui/native_theme/native_theme_base.h"
+#include "ui/native_theme/fallback_theme.h"
+#include "ui/native_theme/native_theme_export.h"
namespace ui {
// Mac implementation of native theme support.
-class NativeThemeMac : public NativeThemeBase {
+// TODO(tapted): This should not use FallbackTheme. http://crbug.com/379086.
+class NativeThemeMac : public FallbackTheme {
public:
static NativeThemeMac* instance();
diff --git a/chromium/ui/native_theme/native_theme_mac.mm b/chromium/ui/native_theme/native_theme_mac.mm
index c3152a8d145..39f7dfc0162 100644
--- a/chromium/ui/native_theme/native_theme_mac.mm
+++ b/chromium/ui/native_theme/native_theme_mac.mm
@@ -36,7 +36,8 @@ SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
case kColorId_DialogBackground:
return kDialogBackgroundColor;
default:
- NOTREACHED() << "Invalid color_id: " << color_id;
+ NOTIMPLEMENTED() << " Invalid color_id: " << color_id;
+ return FallbackTheme::GetSystemColor(color_id);
}
return kInvalidColorIdColor;
diff --git a/chromium/ui/native_theme/native_theme_observer.cc b/chromium/ui/native_theme/native_theme_observer.cc
new file mode 100644
index 00000000000..f516a762027
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_observer.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/native_theme/native_theme_observer.h"
+
+namespace ui {
+
+NativeThemeObserver::~NativeThemeObserver() {}
+
+} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_observer.h b/chromium/ui/native_theme/native_theme_observer.h
new file mode 100644
index 00000000000..d38d66368a3
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_observer.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_NATIVE_THEME_NATIVE_THEME_OBSERVER_H_
+#define UI_NATIVE_THEME_NATIVE_THEME_OBSERVER_H_
+
+#include "ui/native_theme/native_theme_export.h"
+
+namespace ui {
+
+class NativeTheme;
+
+// Observers which are notified when the native theme changes.
+class NATIVE_THEME_EXPORT NativeThemeObserver {
+ public:
+ // Called when the native theme changes. The observed theme is passed so that
+ // observers may handle changes to their associated native theme instances.
+ virtual void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) = 0;
+
+ protected:
+ virtual ~NativeThemeObserver();
+};
+
+} // namespace ui
+
+#endif // UI_NATIVE_THEME_NATIVE_THEME_OBSERVER_H_
diff --git a/chromium/ui/native_theme/native_theme_switches.cc b/chromium/ui/native_theme/native_theme_switches.cc
new file mode 100644
index 00000000000..ba46d18b6c8
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_switches.cc
@@ -0,0 +1,31 @@
+// 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 "base/command_line.h"
+#include "ui/native_theme/native_theme_switches.h"
+
+namespace switches {
+
+// Enables overlay scrollbars on Aura or Linux. Does nothing on Mac.
+const char kEnableOverlayScrollbar[] = "enable-overlay-scrollbar";
+
+// Disables overlay scrollbars on Aura or Linux. Does nothing on Mac.
+const char kDisableOverlayScrollbar[] = "disable-overlay-scrollbar";
+
+} // namespace switches
+
+namespace ui {
+
+bool IsOverlayScrollbarEnabled() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ if (command_line.HasSwitch(switches::kDisableOverlayScrollbar))
+ return false;
+ else if (command_line.HasSwitch(switches::kEnableOverlayScrollbar))
+ return true;
+
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme_switches.h b/chromium/ui/native_theme/native_theme_switches.h
new file mode 100644
index 00000000000..026ee70eca3
--- /dev/null
+++ b/chromium/ui/native_theme/native_theme_switches.h
@@ -0,0 +1,25 @@
+// 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.
+
+// Defines all the command-line switches used by native theme
+
+#ifndef UI_NATIVE_THEME_NATIVE_THEME_SWITCHES_H_
+#define UI_NATIVE_THEME_NATIVE_THEME_SWITCHES_H_
+
+#include "ui/native_theme/native_theme_export.h"
+
+namespace switches {
+
+NATIVE_THEME_EXPORT extern const char kDisableOverlayScrollbar[];
+NATIVE_THEME_EXPORT extern const char kEnableOverlayScrollbar[];
+
+} // namespace switches
+
+namespace ui {
+
+NATIVE_THEME_EXPORT bool IsOverlayScrollbarEnabled();
+
+} // namespace ui
+
+#endif // UI_NATIVE_THEME_NATIVE_THEME_SWITCHES_H_
diff --git a/chromium/ui/native_theme/native_theme_win.cc b/chromium/ui/native_theme/native_theme_win.cc
index 74b4f14a261..5bd78f3558f 100644
--- a/chromium/ui/native_theme/native_theme_win.cc
+++ b/chromium/ui/native_theme/native_theme_win.cc
@@ -11,7 +11,6 @@
#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/memory/scoped_handle.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
@@ -27,7 +26,6 @@
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/sys_color_change_listener.h"
#include "ui/gfx/win/dpi.h"
#include "ui/native_theme/common_theme.h"
@@ -50,6 +48,7 @@ const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xd9, 0xd9, 0xd9);
const SkColor kButtonBackgroundColor = SkColorSetRGB(0xde, 0xde, 0xde);
const SkColor kButtonHighlightColor = SkColorSetARGB(200, 255, 255, 255);
const SkColor kButtonHoverColor = SkColorSetRGB(6, 45, 117);
+const SkColor kButtonHoverBackgroundColor = SkColorSetRGB(0xEA, 0xEA, 0xEA);
// MenuItem:
const SkColor kEnabledMenuItemForegroundColor = SkColorSetRGB(6, 45, 117);
const SkColor kDisabledMenuItemForegroundColor = SkColorSetRGB(161, 161, 146);
@@ -87,16 +86,17 @@ void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
temp_bitmap.setPixels(buffer);
SkBitmap bitmap;
- temp_bitmap.copyTo(&bitmap, temp_bitmap.config());
- skia::RefPtr<SkShader> shader = skia::AdoptRef(
- SkShader::CreateBitmapShader(
- bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
+ temp_bitmap.copyTo(&bitmap);
// Align the pattern with the upper corner of |align_rect|.
- SkMatrix matrix;
- matrix.setTranslate(SkIntToScalar(align_rect.left),
- SkIntToScalar(align_rect.top));
- shader->setLocalMatrix(matrix);
+ SkMatrix local_matrix;
+ local_matrix.setTranslate(SkIntToScalar(align_rect.left),
+ SkIntToScalar(align_rect.top));
+ skia::RefPtr<SkShader> shader =
+ skia::AdoptRef(SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode,
+ &local_matrix));
paint->setShader(shader.get());
}
@@ -127,14 +127,6 @@ RECT InsetRect(const RECT* rect, int size) {
return result.ToRECT();
}
-// Returns true if using a high contrast theme.
-bool UsingHighContrastTheme() {
- HIGHCONTRAST result;
- result.cbSize = sizeof(HIGHCONTRAST);
- return SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) &&
- (result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON;
-}
-
} // namespace
namespace ui {
@@ -145,6 +137,18 @@ bool NativeThemeWin::IsThemingActive() const {
return false;
}
+bool NativeThemeWin::IsUsingHighContrastTheme() const {
+ if (is_using_high_contrast_valid_)
+ return is_using_high_contrast_;
+ HIGHCONTRAST result;
+ result.cbSize = sizeof(HIGHCONTRAST);
+ is_using_high_contrast_ =
+ SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) &&
+ (result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON;
+ is_using_high_contrast_valid_ = true;
+ return is_using_high_contrast_;
+}
+
HRESULT NativeThemeWin::GetThemeColor(ThemeName theme,
int part_id,
int state_id,
@@ -208,16 +212,6 @@ bool NativeThemeWin::IsClassicTheme(ThemeName name) const {
return !GetThemeHandle(name);
}
-// TODO(sky): seems like we should default to NativeThemeWin, but that currently
-// breaks a couple of tests (FocusTraversalTest.NormalTraversal in
-// views_unittests).
-#if !defined(USE_AURA)
-// static
-NativeTheme* NativeTheme::instance() {
- return NativeThemeWin::instance();
-}
-#endif
-
// static
NativeThemeWin* NativeThemeWin::instance() {
CR_DEFINE_STATIC_LOCAL(NativeThemeWin, s_native_theme, ());
@@ -233,7 +227,6 @@ gfx::Size NativeThemeWin::GetPartSize(Part part,
// The GetThemePartSize call below returns the default size without
// accounting for user customization (crbug/218291).
- SIZE size;
switch (part) {
case kScrollbarDownArrow:
case kScrollbarLeftArrow:
@@ -242,14 +235,18 @@ gfx::Size NativeThemeWin::GetPartSize(Part part,
case kScrollbarHorizontalThumb:
case kScrollbarVerticalThumb:
case kScrollbarHorizontalTrack:
- case kScrollbarVerticalTrack:
- size.cx = size.cy = gfx::win::GetSystemMetricsInDIP(SM_CXVSCROLL);
- return gfx::Size(size.cx, size.cy);
+ case kScrollbarVerticalTrack: {
+ int size = gfx::win::GetSystemMetricsInDIP(SM_CXVSCROLL);
+ if (size == 0)
+ size = 17;
+ return gfx::Size(size, size);
+ }
}
int part_id = GetWindowsPart(part, state, extra);
int state_id = GetWindowsState(part, state, extra);
+ SIZE size;
HDC hdc = GetDC(NULL);
HRESULT hr = GetThemePartSize(GetThemeName(part), hdc, part_id, state_id,
NULL, TS_TRUE, &size);
@@ -286,6 +283,9 @@ void NativeThemeWin::Paint(SkCanvas* canvas,
return;
switch (part) {
+ case kComboboxArrow:
+ CommonThemePaintComboboxArrow(canvas, rect);
+ return;
case kMenuPopupGutter:
CommonThemePaintMenuGutter(canvas, rect);
return;
@@ -349,7 +349,9 @@ NativeThemeWin::NativeThemeWin()
set_theme_properties_(NULL),
is_theme_active_(NULL),
get_theme_int_(NULL),
- color_change_listener_(this) {
+ color_change_listener_(this),
+ is_using_high_contrast_(false),
+ is_using_high_contrast_valid_(false) {
if (theme_dll_) {
draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
GetProcAddress(theme_dll_, "DrawThemeBackground"));
@@ -389,6 +391,8 @@ NativeThemeWin::~NativeThemeWin() {
void NativeThemeWin::OnSysColorChange() {
UpdateSystemColors();
+ is_using_high_contrast_valid_ = false;
+ NotifyObservers();
}
void NativeThemeWin::UpdateSystemColors() {
@@ -451,6 +455,9 @@ void NativeThemeWin::PaintDirect(SkCanvas* canvas,
PaintScrollbarTrack(canvas, hdc, part, state, rect,
extra.scrollbar_track);
break;
+ case kScrollbarCorner:
+ canvas->drawColor(SK_ColorWHITE, SkXfermode::kSrc_Mode);
+ break;
case kScrollbarHorizontalThumb:
case kScrollbarVerticalThumb:
case kScrollbarHorizontalGripper:
@@ -519,12 +526,16 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
return kButtonHighlightColor;
case kColorId_ButtonHoverColor:
return kButtonHoverColor;
+ case kColorId_ButtonHoverBackgroundColor:
+ return kButtonHoverBackgroundColor;
// MenuItem
case kColorId_EnabledMenuItemForegroundColor:
return kEnabledMenuItemForegroundColor;
case kColorId_DisabledMenuItemForegroundColor:
return kDisabledMenuItemForegroundColor;
+ case kColorId_DisabledEmphasizedMenuItemForegroundColor:
+ return SK_ColorBLACK;
case kColorId_FocusedMenuItemBackgroundColor:
return kFocusedMenuItemBackgroundColor;
case kColorId_MenuSeparatorColor:
@@ -565,7 +576,7 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
case kColorId_TreeSelectionBackgroundFocused:
return system_colors_[COLOR_HIGHLIGHT];
case kColorId_TreeSelectionBackgroundUnfocused:
- return system_colors_[UsingHighContrastTheme() ?
+ return system_colors_[IsUsingHighContrastTheme() ?
COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
case kColorId_TreeArrow:
return system_colors_[COLOR_WINDOWTEXT];
@@ -582,11 +593,55 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
case kColorId_TableSelectionBackgroundFocused:
return system_colors_[COLOR_HIGHLIGHT];
case kColorId_TableSelectionBackgroundUnfocused:
- return system_colors_[UsingHighContrastTheme() ?
+ return system_colors_[IsUsingHighContrastTheme() ?
COLOR_MENUHIGHLIGHT : COLOR_BTNFACE];
case kColorId_TableGroupingIndicatorColor:
return system_colors_[COLOR_GRAYTEXT];
+ // Results Tables
+ case kColorId_ResultsTableNormalBackground:
+ return system_colors_[COLOR_WINDOW];
+ case kColorId_ResultsTableHoveredBackground:
+ return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHT],
+ system_colors_[COLOR_WINDOW], 0x40);
+ case kColorId_ResultsTableSelectedBackground:
+ return system_colors_[COLOR_HIGHLIGHT];
+ case kColorId_ResultsTableNormalText:
+ case kColorId_ResultsTableHoveredText:
+ return system_colors_[COLOR_WINDOWTEXT];
+ case kColorId_ResultsTableSelectedText:
+ return system_colors_[COLOR_HIGHLIGHTTEXT];
+ case kColorId_ResultsTableNormalDimmedText:
+ return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
+ system_colors_[COLOR_WINDOW], 0x80);
+ case kColorId_ResultsTableHoveredDimmedText:
+ return color_utils::AlphaBlend(
+ system_colors_[COLOR_WINDOWTEXT],
+ GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x80);
+ case kColorId_ResultsTableSelectedDimmedText:
+ return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
+ system_colors_[COLOR_HIGHLIGHT], 0x80);
+ case kColorId_ResultsTableNormalUrl:
+ return color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0),
+ system_colors_[COLOR_WINDOW]);
+ case kColorId_ResultsTableHoveredUrl:
+ return color_utils::GetReadableColor(
+ SkColorSetRGB(0, 128, 0),
+ GetSystemColor(kColorId_ResultsTableHoveredBackground));
+ case kColorId_ResultsTableSelectedUrl:
+ return color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0),
+ system_colors_[COLOR_HIGHLIGHT]);
+ case kColorId_ResultsTableNormalDivider:
+ return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT],
+ system_colors_[COLOR_WINDOW], 0x34);
+ case kColorId_ResultsTableHoveredDivider:
+ return color_utils::AlphaBlend(
+ system_colors_[COLOR_WINDOWTEXT],
+ GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x34);
+ case kColorId_ResultsTableSelectedDivider:
+ return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
+ system_colors_[COLOR_HIGHLIGHT], 0x34);
+
default:
NOTREACHED();
break;
@@ -609,6 +664,8 @@ void NativeThemeWin::PaintIndirect(SkCanvas* canvas,
skia::BitmapPlatformDevice::Create(
rect.width(), rect.height(), false, NULL));
DCHECK(device);
+ if (!device)
+ return;
SkCanvas offscreen_canvas(device.get());
DCHECK(skia::SupportsPlatformPaint(&offscreen_canvas));
@@ -649,7 +706,7 @@ void NativeThemeWin::PaintIndirect(SkCanvas* canvas,
const SkBitmap& hdc_bitmap =
offscreen_canvas.getDevice()->accessBitmap(false);
SkBitmap bitmap;
- hdc_bitmap.copyTo(&bitmap, SkBitmap::kARGB_8888_Config);
+ hdc_bitmap.copyTo(&bitmap, kPMColor_SkColorType);
// Post-process the pixels to fix up the alpha values (see big comment above).
const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder);
diff --git a/chromium/ui/native_theme/native_theme_win.h b/chromium/ui/native_theme/native_theme_win.h
index 5542f20d0a3..408818fb657 100644
--- a/chromium/ui/native_theme/native_theme_win.h
+++ b/chromium/ui/native_theme/native_theme_win.h
@@ -54,6 +54,9 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
bool IsThemingActive() const;
+ // Returns true if a high contrast theme is being used.
+ bool IsUsingHighContrastTheme() const;
+
HRESULT GetThemeColor(ThemeName theme,
int part_id,
int state_id,
@@ -356,6 +359,12 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme,
gfx::ScopedSysColorChangeListener color_change_listener_;
mutable std::map<int, SkColor> system_colors_;
+ // Is a high contrast theme active?
+ mutable bool is_using_high_contrast_;
+
+ // Is |is_using_high_contrast_| valid?
+ mutable bool is_using_high_contrast_valid_;
+
DISALLOW_COPY_AND_ASSIGN(NativeThemeWin);
};
diff --git a/chromium/ui/native_theme/native_theme_win_unittest.cc b/chromium/ui/native_theme/native_theme_win_unittest.cc
deleted file mode 100644
index a2bd6aaee98..00000000000
--- a/chromium/ui/native_theme/native_theme_win_unittest.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/native_theme/native_theme_win.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ui {
-
-TEST(NativeThemeTest, Init) {
- ASSERT_TRUE(NativeThemeWin::instance() != NULL);
-}
-
-} // namespace ui
diff --git a/chromium/ui/oak/DEPS b/chromium/ui/oak/DEPS
deleted file mode 100644
index 82dec32cf3b..00000000000
--- a/chromium/ui/oak/DEPS
+++ /dev/null
@@ -1,10 +0,0 @@
-include_rules = [
- "+grit/ash_strings.h",
- "+grit/ui_resources.h",
- "+grit/ui_strings.h",
- "+skia/ext",
- "+ui/aura",
- "+ui/base",
- "+ui/gfx",
- "+ui/views",
-]
diff --git a/chromium/ui/oak/oak.gyp b/chromium/ui/oak/oak.gyp
deleted file mode 100644
index 00a8dfc0e41..00000000000
--- a/chromium/ui/oak/oak.gyp
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
-
- 'targets': [
- {
- 'target_name': 'oak',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../skia/skia.gyp:skia',
- '../../url/url.gyp:url_lib',
- '../aura/aura.gyp:aura',
- '../compositor/compositor.gyp:compositor',
- '../events/events.gyp:events',
- '../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
- '../views/views.gyp:views',
- ],
- 'defines': [
- 'OAK_IMPLEMENTATION',
- ],
- 'sources': [
- # All .cc, .h under oak, except unittests
- 'oak.h',
- 'oak_aura_window_display.cc',
- 'oak_aura_window_display.h',
- 'oak_export.h',
- 'oak_pretty_print.cc',
- 'oak_pretty_print.h',
- 'oak_tree_model.cc',
- 'oak_tree_model.h',
- 'oak_window.cc',
- 'oak_window.h',
- 'oak_details_model.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- },
- ],
-}
diff --git a/chromium/ui/oak/oak.h b/chromium/ui/oak/oak.h
deleted file mode 100644
index 0ffdc853234..00000000000
--- a/chromium/ui/oak/oak.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OAK_OAK_H_
-#define UI_OAK_OAK_H_
-
-#include "ui/oak/oak_export.h"
-
-namespace oak {
-
-// Shows the Oak window. Refocuses an existing one.
-OAK_EXPORT void ShowOakWindowWithContext(gfx::NativeView context);
-
-} // namespace oak
-
-#endif // UI_OAK_OAK_H_
diff --git a/chromium/ui/oak/oak_aura_window_display.cc b/chromium/ui/oak/oak_aura_window_display.cc
deleted file mode 100644
index e751a332393..00000000000
--- a/chromium/ui/oak/oak_aura_window_display.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/oak/oak_aura_window_display.h"
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/aura/window.h"
-#include "ui/base/models/table_model_observer.h"
-#include "ui/oak/oak_pretty_print.h"
-
-namespace oak {
-namespace internal {
-namespace {
-enum {
-ROW_ID = 0,
-ROW_DELEGATE,
-ROW_TYPE,
-ROW_NAME,
-ROW_TITLE,
-ROW_TRANSPARENT,
-ROW_LAYER,
-ROW_VISIBLE,
-ROW_BOUNDS,
-ROW_BOUNDSINROOTWINDOW,
-ROW_TRANSFORM,
-ROW_PARENT,
-ROW_ROOTWINDOW,
-ROW_TRANSIENTCHILDREN,
-ROW_TRANSIENTPARENT,
-ROW_USERDATA,
-ROW_IGNOREEVENTS,
-ROW_CANFOCUS,
-ROW_HITTESTBOUNDSOVERRIDEOUTER,
-ROW_HITTESTBOUNDSOVERRIDEINNER,
-ROW_COUNT
-};
-
-// aura::Window-specific pretty printing.
-base::string16 PropertyWithWindowType(int type) {
- std::string property = "Type: ";
- switch (type) {
- case aura::client::WINDOW_TYPE_UNKNOWN:
- property.append("WINDOW_TYPE_UNKNOWN");
- break;
- case aura::client::WINDOW_TYPE_NORMAL:
- property.append("WINDOW_TYPE_NORMAL");
- break;
- case aura::client::WINDOW_TYPE_POPUP:
- property.append("WINDOW_TYPE_POPUP");
- break;
- case aura::client::WINDOW_TYPE_CONTROL:
- property.append("WINDOW_TYPE_CONTROL");
- break;
- case aura::client::WINDOW_TYPE_PANEL:
- property.append("WINDOW_TYPE_PANEL");
- break;
- case aura::client::WINDOW_TYPE_MENU:
- property.append("WINDOW_TYPE_MENU");
- break;
- case aura::client::WINDOW_TYPE_TOOLTIP:
- property.append("WINDOW_TYPE_TOOLTIP");
- break;
- default:
- NOTREACHED();
- break;
- }
- return ASCIIToUTF16(property);
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// OakAuraWindowDisplay, public:
-
-OakAuraWindowDisplay::OakAuraWindowDisplay() : observer_(NULL), window_(NULL) {
-}
-
-OakAuraWindowDisplay::~OakAuraWindowDisplay() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakAuraWindowDisplay, OakDetailsModel overrides:
-
-void OakAuraWindowDisplay::SetValue(aura::Window* window) {
- window_ = window;
- observer_->OnModelChanged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakAuraWindowDisplay, ui::TableModel implementation:
-
-int OakAuraWindowDisplay::RowCount() {
- return ROW_COUNT;
-}
-
-base::string16 OakAuraWindowDisplay::GetText(int row, int column_id) {
- if (!window_)
- return base::string16();
-
- base::string16 text;
- switch (row) {
- case ROW_ID:
- return PropertyWithInteger("Id: ", window_->id());
- case ROW_DELEGATE:
- return PropertyWithVoidStar("Delegate: ", window_->delegate());
- case ROW_TYPE:
- return PropertyWithWindowType(window_->type());
- case ROW_NAME:
- return ASCIIToUTF16("Name: " + window_->name());
- case ROW_TITLE:
- return ASCIIToUTF16("Title: ") + window_->title();
- case ROW_TRANSPARENT:
- return PropertyWithBool("Transparent: ", window_->transparent());
- case ROW_LAYER:
- return PropertyWithVoidStar("Layer: ", window_->layer());
- case ROW_VISIBLE:
- return PropertyWithBool("Visible: ", window_->IsVisible());
- case ROW_BOUNDS:
- return PropertyWithBounds("Bounds: ", window_->bounds());
- case ROW_BOUNDSINROOTWINDOW:
- return PropertyWithBounds("Bounds in Root Window: ",
- window_->GetBoundsInRootWindow());
- case ROW_TRANSFORM:
- return ASCIIToUTF16("Transform:");
- case ROW_PARENT:
- return PropertyWithVoidStar("Parent: ", window_->parent());
- case ROW_ROOTWINDOW:
- return PropertyWithVoidStar("Root Window: ", window_->GetRootWindow());
- case ROW_TRANSIENTCHILDREN:
- return PropertyWithInteger("Transient Children: ",
- window_->transient_children().size());
- case ROW_TRANSIENTPARENT:
- return PropertyWithVoidStar("Transient Parent: ",
- window_->transient_parent());
- case ROW_USERDATA:
- return PropertyWithVoidStar("User Data: ", window_->user_data());
- case ROW_IGNOREEVENTS:
- return PropertyWithBool("Can receive events: ",
- window_->CanReceiveEvents());
- case ROW_CANFOCUS:
- return PropertyWithBool("Can Focus: ", window_->CanFocus());
- case ROW_HITTESTBOUNDSOVERRIDEOUTER:
- return PropertyWithInsets("Hit test bounds override outer: ",
- window_->hit_test_bounds_override_outer_mouse());
- case ROW_HITTESTBOUNDSOVERRIDEINNER:
- return PropertyWithInsets("Hit test bounds override inner: ",
- window_->hit_test_bounds_override_inner());
- default:
- NOTREACHED();
- break;
- }
- return base::string16();
-}
-
-void OakAuraWindowDisplay::SetObserver(ui::TableModelObserver* observer) {
- observer_ = observer;
-}
-
-} // namespace internal
-} // namespace oak
diff --git a/chromium/ui/oak/oak_aura_window_display.h b/chromium/ui/oak/oak_aura_window_display.h
deleted file mode 100644
index cc78c867fe9..00000000000
--- a/chromium/ui/oak/oak_aura_window_display.h
+++ /dev/null
@@ -1,37 +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_OAK_OAK_AURA_WINDOW_DISPLAY_H_
-#define UI_OAK_OAK_AURA_WINDOW_DISPLAY_H_
-
-#include "base/compiler_specific.h"
-#include "ui/oak/oak_details_model.h"
-
-namespace oak {
-namespace internal {
-
-class OakAuraWindowDisplay : public OakDetailsModel {
- public:
- OakAuraWindowDisplay();
- virtual ~OakAuraWindowDisplay();
-
- private:
- // Overridden from OakDetailsModel:
- virtual void SetValue(aura::Window* window) OVERRIDE;
-
- // Overridden from ui::TableModel:
- virtual int RowCount() OVERRIDE;
- virtual base::string16 GetText(int row, int column_id) OVERRIDE;
- virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
-
- ui::TableModelObserver* observer_;
- aura::Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(OakAuraWindowDisplay);
-};
-
-} // namespace internal
-} // namespace oak
-
-#endif // UI_OAK_OAK_AURA_WINDOW_DISPLAY_H_
diff --git a/chromium/ui/oak/oak_details_model.h b/chromium/ui/oak/oak_details_model.h
deleted file mode 100644
index eb558aa0956..00000000000
--- a/chromium/ui/oak/oak_details_model.h
+++ /dev/null
@@ -1,33 +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_OAK_OAK_DETAILS_MODEL_H_
-#define UI_OAK_OAK_DETAILS_MODEL_H_
-
-#include "ui/base/models/table_model.h"
-
-namespace aura {
-class Window;
-}
-
-namespace oak {
-namespace internal {
-
-class OakDetailsModel : public ui::TableModel {
- public:
- virtual ~OakDetailsModel() {}
-
- virtual void SetValue(aura::Window* window) = 0;
-
- protected:
- OakDetailsModel() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OakDetailsModel);
-};
-
-} // namespace internal
-} // namespace oak
-
-#endif // UI_OAK_OAK_DETAILS_MODEL_H_
diff --git a/chromium/ui/oak/oak_export.h b/chromium/ui/oak/oak_export.h
deleted file mode 100644
index 726366c6a70..00000000000
--- a/chromium/ui/oak/oak_export.h
+++ /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.
-
-#ifndef UI_OAK_OAK_EXPORT_H_
-#define UI_OAK_OAK_EXPORT_H_
-
-// Defines AURA_EXPORT so that functionality implemented by the aura module
-// can be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(OAK_IMPLEMENTATION)
-#define OAK_EXPORT __declspec(dllexport)
-#else
-#define OAK_EXPORT __declspec(dllimport)
-#endif // defined(OAK_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(OAK_IMPLEMENTATION)
-#define OAK_EXPORT __attribute__((visibility("default")))
-#else
-#define OAK_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define OAK_EXPORT
-#endif
-
-#endif // UI_OAK_OAK_EXPORT_H_
diff --git a/chromium/ui/oak/oak_pretty_print.cc b/chromium/ui/oak/oak_pretty_print.cc
deleted file mode 100644
index 0fb7dd41e4b..00000000000
--- a/chromium/ui/oak/oak_pretty_print.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/oak/oak_pretty_print.h"
-
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect.h"
-
-namespace oak {
-namespace internal {
-
-base::string16 PropertyWithInteger(const std::string& prefix, int value) {
- return ASCIIToUTF16(prefix) + base::IntToString16(value);
-}
-
-base::string16 PropertyWithVoidStar(const std::string& prefix, void* ptr) {
- unsigned int cast_ptr =
- static_cast<unsigned int>(reinterpret_cast<intptr_t>(ptr));
- return ASCIIToUTF16(
- prefix + "0x" + (ptr ? base::StringPrintf("%x", cast_ptr) : "0"));
-}
-
-base::string16 PropertyWithBool(const std::string& prefix, bool value) {
- return ASCIIToUTF16(prefix + (value ? "true" : "false"));
-}
-
-base::string16 PropertyWithBounds(const std::string& prefix,
- const gfx::Rect& bounds) {
- return ASCIIToUTF16(prefix + bounds.ToString());
-}
-
-base::string16 PropertyWithInsets(const std::string& prefix,
- const gfx::Insets& insets) {
- return ASCIIToUTF16(prefix + insets.ToString());
-}
-
-} // namespace internal
-} // namespace oak
diff --git a/chromium/ui/oak/oak_pretty_print.h b/chromium/ui/oak/oak_pretty_print.h
deleted file mode 100644
index ee294aa2928..00000000000
--- a/chromium/ui/oak/oak_pretty_print.h
+++ /dev/null
@@ -1,31 +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_OAK_OAK_PRETTY_PRINT_H_
-#define UI_OAK_OAK_PRETTY_PRINT_H_
-
-#include "base/strings/string16.h"
-
-namespace gfx {
-class Insets;
-class Rect;
-}
-
-namespace oak {
-namespace internal {
-
-// Functions that return a string consisting of a prefix and the supplied value
-// converted to a pretty string representation.
-base::string16 PropertyWithInteger(const std::string& prefix, int value);
-base::string16 PropertyWithVoidStar(const std::string& prefix, void* ptr);
-base::string16 PropertyWithBool(const std::string& prefix, bool value);
-base::string16 PropertyWithBounds(const std::string& prefix,
- const gfx::Rect& bounds);
-base::string16 PropertyWithInsets(const std::string& prefix,
- const gfx::Insets& insets);
-
-} // namespace internal
-} // namespace oak
-
-#endif // UI_OAK_OAK_PRETTY_PRINT_H_
diff --git a/chromium/ui/oak/oak_tree_model.cc b/chromium/ui/oak/oak_tree_model.cc
deleted file mode 100644
index 375c3c0fcbd..00000000000
--- a/chromium/ui/oak/oak_tree_model.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/oak/oak_tree_model.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/models/tree_node_model.h"
-
-namespace oak {
-namespace internal {
-
-base::string16 GetNodeTitleForWindow(aura::Window* window) {
- std::string window_name = window->name();
- if (window_name.empty())
- window_name.append("Unnamed window");
- return ASCIIToUTF16(window_name);
-}
-
-void AddChildWindows(aura::Window* parent_window, WindowNode* parent_node) {
- aura::Window::Windows::const_iterator it = parent_window->children().begin();
- for (; it != parent_window->children().end(); ++it) {
- WindowNode* child_node = new WindowNode(GetNodeTitleForWindow(*it), *it);
- parent_node->Add(child_node, parent_node->child_count());
- AddChildWindows(*it, child_node);
- }
-}
-
-TreeOfWindows* GenerateModel(aura::Window* root) {
- WindowNode* root_node = new WindowNode(GetNodeTitleForWindow(root), root);
- TreeOfWindows* tree = new TreeOfWindows(root_node);
- AddChildWindows(root, root_node);
- return tree;
-}
-
-} // namespace internal
-} // namespace oak
diff --git a/chromium/ui/oak/oak_tree_model.h b/chromium/ui/oak/oak_tree_model.h
deleted file mode 100644
index f68912d8b84..00000000000
--- a/chromium/ui/oak/oak_tree_model.h
+++ /dev/null
@@ -1,26 +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_OAK_OAK_TREE_MODEL_H_
-#define UI_OAK_OAK_TREE_MODEL_H_
-
-#include "base/compiler_specific.h"
-#include "ui/base/models/tree_node_model.h"
-
-namespace aura {
-class Window;
-}
-
-namespace oak {
-namespace internal {
-
-typedef ui::TreeNodeWithValue<aura::Window*> WindowNode;
-typedef ui::TreeNodeModel<WindowNode> TreeOfWindows;
-
-TreeOfWindows* GenerateModel(aura::Window* root);
-
-} // namespace internal
-} // namespace oak
-
-#endif // UI_OAK_OAK_TREE_MODEL_H_
diff --git a/chromium/ui/oak/oak_window.cc b/chromium/ui/oak/oak_window.cc
deleted file mode 100644
index 64c6e422757..00000000000
--- a/chromium/ui/oak/oak_window.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/oak/oak_window.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_resources.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image.h"
-#include "ui/oak/oak.h"
-#include "ui/oak/oak_aura_window_display.h"
-#include "ui/views/controls/table/table_view.h"
-#include "ui/views/controls/tree/tree_view.h"
-#include "ui/views/layout/layout_constants.h"
-#include "ui/views/widget/widget.h"
-
-namespace oak {
-namespace internal {
-namespace {
-const SkColor kBorderColor = SkColorSetRGB(0xCC, 0xCC, 0xCC);
-} // namespace
-
-// static
-views::Widget* OakWindow::instance = NULL;
-
-////////////////////////////////////////////////////////////////////////////////
-// OakWindow, public:
-
-OakWindow::OakWindow() : tree_container_(NULL) {}
-
-OakWindow::~OakWindow() {
- // The tree/table need to be destroyed before the model.
- tree_.reset();
- details_.reset();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakWindow, views::WidgetDelegateView implementation:
-
-bool OakWindow::CanResize() const {
- return true;
-}
-
-bool OakWindow::CanMaximize() const {
- return true;
-}
-
-base::string16 OakWindow::GetWindowTitle() const {
- return ASCIIToUTF16("Oak");
-}
-
-views::View* OakWindow::GetContentsView() {
- return this;
-}
-
-gfx::ImageSkia OakWindow::GetWindowIcon() {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- return *rb.GetImageNamed(IDR_OAK).ToImageSkia();
-}
-
-bool OakWindow::ShouldShowWindowIcon() const {
- return true;
-}
-
-void OakWindow::DeleteDelegate() {
- instance = NULL;
- delete this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakWindow, views::View overrides:
-
-void OakWindow::OnPaint(gfx::Canvas* canvas) {
- canvas->DrawColor(SK_ColorWHITE);
- canvas->FillRect(separator_rect_, kBorderColor);
-}
-
-void OakWindow::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && details.child == this)
- Init();
-}
-
-void OakWindow::Layout() {
- gfx::Rect content_bounds = GetLocalBounds();
- content_bounds.Inset(views::kPanelHorizMargin, views::kPanelVertMargin);
-
- int tree_height =
- (content_bounds.height() / 2) - views::kUnrelatedControlVerticalSpacing;
- gfx::Rect tree_bounds = content_bounds;
- tree_bounds.set_height(tree_height);
- tree_container_->SetBoundsRect(tree_bounds);
-
- separator_rect_ = content_bounds;
- separator_rect_.set_y(
- tree_bounds.bottom() + views::kRelatedControlVerticalSpacing);
- separator_rect_.set_height(1);
-
- gfx::Rect details_bounds = content_bounds;
- details_bounds.set_y(
- separator_rect_.bottom() + views::kRelatedControlVerticalSpacing);
- details_bounds.set_height(content_bounds.bottom() - details_bounds.y());
- details_container_->SetBoundsRect(details_bounds);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakWindow, views::TreeViewController implementation:
-
-void OakWindow::OnTreeViewSelectionChanged(views::TreeView* tree) {
- details_model_->SetValue(tree_model_->AsNode(tree->GetSelectedNode())->value);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OakWindow, private:
-
-void OakWindow::Init() {
- tree_model_.reset(
- GenerateModel(GetWidget()->GetNativeView()->GetRootWindow()));
- tree_.reset(new views::TreeView);
- tree_->set_owned_by_client();
- tree_->SetController(this);
- tree_->SetModel(tree_model_.get());
- tree_container_ = tree_->CreateParentIfNecessary();
- AddChildView(tree_container_);
-
- details_model_.reset(new OakAuraWindowDisplay);
- std::vector<ui::TableColumn> columns;
- columns.push_back(ui::TableColumn());
- details_.reset(new views::TableView(details_model_.get(),
- columns,
- views::TEXT_ONLY,
- true));
- details_->set_owned_by_client();
- details_container_ = details_->CreateParentIfNecessary();
- details_->SetModel(details_model_.get());
- AddChildView(details_container_);
-
- OnTreeViewSelectionChanged(tree_.get());
-}
-
-} // namespace internal
-
-void ShowOakWindowWithContext(gfx::NativeView context) {
- if (!internal::OakWindow::instance) {
- // TODO(erg): Do we want to reuse this window in times with a different
- // context? For now, this is OK, but if we ever use Oak outside of the ash
- // shell, we run into crbug.com/165759.
- internal::OakWindow::instance =
- views::Widget::CreateWindowWithContextAndBounds(
- new internal::OakWindow, context, gfx::Rect(10, 10, 500, 500));
- }
- internal::OakWindow::instance->Show();
-}
-
-} // namespace oak
diff --git a/chromium/ui/oak/oak_window.h b/chromium/ui/oak/oak_window.h
deleted file mode 100644
index 087334e2226..00000000000
--- a/chromium/ui/oak/oak_window.h
+++ /dev/null
@@ -1,67 +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_OAK_OAK_WINDOW_H_
-#define UI_OAK_OAK_WINDOW_H_
-
-#include "ui/oak/oak_tree_model.h"
-#include "ui/views/controls/tree/tree_view_controller.h"
-#include "ui/views/widget/widget_delegate.h"
-
-namespace views {
-class TableView;
-}
-
-namespace oak {
-namespace internal {
-
-class OakTreeModel;
-class OakDetailsModel;
-
-class OakWindow : public views::WidgetDelegateView,
- public views::TreeViewController {
- public:
- OakWindow();
- virtual ~OakWindow();
-
- static views::Widget* instance;
-
- // Overridden from views::WidgetDelegateView:
- virtual bool CanResize() const OVERRIDE;
- virtual bool CanMaximize() const OVERRIDE;
- virtual base::string16 GetWindowTitle() const OVERRIDE;
- virtual views::View* GetContentsView() OVERRIDE;
- virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
- virtual bool ShouldShowWindowIcon() const OVERRIDE;
- virtual void DeleteDelegate() OVERRIDE;
-
- private:
- // Overridden from views::View:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual void Layout() OVERRIDE;
-
- // Overridden from views::TreeViewController:
- virtual void OnTreeViewSelectionChanged(views::TreeView* tree) OVERRIDE;
-
- void Init();
-
- scoped_ptr<views::TreeView> tree_;
- scoped_ptr<TreeOfWindows> tree_model_;
- views::View* tree_container_;
-
- gfx::Rect separator_rect_;
-
- scoped_ptr<views::TableView> details_;
- scoped_ptr<OakDetailsModel> details_model_;
- views::View* details_container_;
-
- DISALLOW_COPY_AND_ASSIGN(OakWindow);
-};
-
-} // namespace internal
-} // namespace oak
-
-#endif // UI_OAK_OAK_WINDOW_H_
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
new file mode 100644
index 00000000000..a2d3f4712b7
--- /dev/null
+++ b/chromium/ui/ozone/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ui/ozone/ozone.gni")
+
+declare_args() {
+ # The default platform for Ozone.
+ ozone_platform = "test"
+}
+
+platform_list_file = "$target_gen_dir/ozone_platform_list.cc"
+
+component("ozone") {
+ sources = [
+ platform_list_file,
+ # common/chromeos files are excluded automatically when building with
+ # chromeos=0, by exclusion rules in filename_rules.gypi due to the
+ # "chromeos" folder name.
+ "common/chromeos/native_display_delegate_ozone.cc",
+ "common/chromeos/native_display_delegate_ozone.h",
+ "ozone_platform.cc",
+ "ozone_platform.h",
+ "ozone_switches.cc",
+ "ozone_switches.h",
+ ]
+
+ defines = [ "OZONE_IMPLEMENTATION" ]
+
+ deps = [
+ ":generate_ozone_platform_list",
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/events",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gfx/ozone",
+ ]
+}
+
+# TODO(GYP) implement the ozone platforms. This should check the various
+# ozone_platform_*flags, and add deps and add to the ozone_platforms list for
+# the script below.
+ozone_platforms = ""
+
+action("generate_ozone_platform_list") {
+ script = "generate_ozone_platform_list.py"
+ outputs = [ platform_list_file ]
+
+ args = [
+ "--output_file=" + rebase_path(platform_list_file, root_build_dir),
+ "--default=$ozone_platform",
+ ozone_platforms,
+ ]
+}
diff --git a/chromium/ui/ozone/DEPS b/chromium/ui/ozone/DEPS
index 8cb61f5e0a4..734601935b3 100644
--- a/chromium/ui/ozone/DEPS
+++ b/chromium/ui/ozone/DEPS
@@ -1,4 +1,6 @@
include_rules = [
+ "+ui/display/types",
"+ui/events",
"+ui/gfx",
+ "+ui/base/cursor",
]
diff --git a/chromium/ui/ozone/OWNERS b/chromium/ui/ozone/OWNERS
index 77f21b5cae7..479c4d806cc 100644
--- a/chromium/ui/ozone/OWNERS
+++ b/chromium/ui/ozone/OWNERS
@@ -1 +1,2 @@
rjkroege@chromium.org
+spang@chromium.org
diff --git a/chromium/ui/ozone/common/README b/chromium/ui/ozone/common/README
new file mode 100644
index 00000000000..1ab9e678cbe
--- /dev/null
+++ b/chromium/ui/ozone/common/README
@@ -0,0 +1,2 @@
+This directory contains code that is used by multiple platforms, but is not part
+of the public platform API. This code should not be used outside of ui/ozone.
diff --git a/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.cc b/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.cc
new file mode 100644
index 00000000000..2efc18d7446
--- /dev/null
+++ b/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.cc
@@ -0,0 +1,95 @@
+// 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/ozone/common/chromeos/native_display_delegate_ozone.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+NativeDisplayDelegateOzone::NativeDisplayDelegateOzone() {}
+
+NativeDisplayDelegateOzone::~NativeDisplayDelegateOzone() {}
+
+void NativeDisplayDelegateOzone::Initialize() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::GrabServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::UngrabServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::SyncWithServer() {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::SetBackgroundColor(uint32_t color_argb) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::ForceDPMSOn() {
+ NOTIMPLEMENTED();
+}
+
+std::vector<ui::DisplaySnapshot*> NativeDisplayDelegateOzone::GetDisplays() {
+ NOTIMPLEMENTED();
+ return std::vector<ui::DisplaySnapshot*>();
+}
+
+void NativeDisplayDelegateOzone::AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeDisplayDelegateOzone::Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateOzone::CreateFrameBuffer(const gfx::Size& size) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeDisplayDelegateOzone::GetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState* state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool NativeDisplayDelegateOzone::SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+std::vector<ui::ColorCalibrationProfile>
+NativeDisplayDelegateOzone::GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) {
+ NOTIMPLEMENTED();
+ return std::vector<ui::ColorCalibrationProfile>();
+}
+
+bool NativeDisplayDelegateOzone::SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateOzone::AddObserver(NativeDisplayObserver* observer) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateOzone::RemoveObserver(
+ NativeDisplayObserver* observer) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.h b/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.h
new file mode 100644
index 00000000000..cb61bd7c14f
--- /dev/null
+++ b/chromium/ui/ozone/common/chromeos/native_display_delegate_ozone.h
@@ -0,0 +1,51 @@
+// 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_OZONE_COMMON_CHROMEOS_NATIVE_DISPLAY_DELEGATE_OZONE_H_
+#define UI_OZONE_COMMON_CHROMEOS_NATIVE_DISPLAY_DELEGATE_OZONE_H_
+
+#include "base/macros.h"
+#include "ui/display/types/chromeos/native_display_delegate.h"
+
+namespace ui {
+
+class NativeDisplayDelegateOzone : public NativeDisplayDelegate {
+ public:
+ NativeDisplayDelegateOzone();
+ virtual ~NativeDisplayDelegateOzone();
+
+ // NativeDisplayDelegate overrides:
+ virtual void Initialize() OVERRIDE;
+ virtual void GrabServer() OVERRIDE;
+ virtual void UngrabServer() OVERRIDE;
+ virtual void SyncWithServer() OVERRIDE;
+ virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE;
+ virtual void ForceDPMSOn() OVERRIDE;
+ virtual std::vector<ui::DisplaySnapshot*> GetDisplays() OVERRIDE;
+ virtual void AddMode(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode) OVERRIDE;
+ virtual bool Configure(const ui::DisplaySnapshot& output,
+ const ui::DisplayMode* mode,
+ const gfx::Point& origin) OVERRIDE;
+ virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE;
+ virtual bool GetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState* state) OVERRIDE;
+ virtual bool SetHDCPState(const ui::DisplaySnapshot& output,
+ ui::HDCPState state) OVERRIDE;
+ virtual std::vector<ui::ColorCalibrationProfile>
+ GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) OVERRIDE;
+ virtual bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) OVERRIDE;
+ virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeDisplayDelegateOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_CHROMEOS_NATIVE_DISPLAY_DELEGATE_OZONE_H_
diff --git a/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.cc b/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.cc
new file mode 100644
index 00000000000..92f4ff9fd6d
--- /dev/null
+++ b/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.cc
@@ -0,0 +1,20 @@
+// 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/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+TouchscreenDeviceManagerOzone::TouchscreenDeviceManagerOzone() {}
+
+TouchscreenDeviceManagerOzone::~TouchscreenDeviceManagerOzone() {}
+
+std::vector<TouchscreenDevice> TouchscreenDeviceManagerOzone::GetDevices() {
+ NOTIMPLEMENTED();
+ return std::vector<TouchscreenDevice>();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h b/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h
new file mode 100644
index 00000000000..db0c00edbf2
--- /dev/null
+++ b/chromium/ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h
@@ -0,0 +1,27 @@
+// 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_OZONE_COMMON_TOUCHSCREEN_DEVICE_MANAGER_OZONE_H_
+#define UI_OZONE_COMMON_TOUCHSCREEN_DEVICE_MANAGER_OZONE_H_
+
+#include "base/macros.h"
+#include "ui/display/types/chromeos/touchscreen_device_manager.h"
+
+namespace ui {
+
+class TouchscreenDeviceManagerOzone : public TouchscreenDeviceManager {
+ public:
+ TouchscreenDeviceManagerOzone();
+ virtual ~TouchscreenDeviceManagerOzone();
+
+ // TouchscreenDeviceManager:
+ virtual std::vector<TouchscreenDevice> GetDevices() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TouchscreenDeviceManagerOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_COMMON_TOUCHSCREEN_DEVICE_MANAGER_OZONE_H_
diff --git a/chromium/ui/ozone/generate_constructor_list.py b/chromium/ui/ozone/generate_constructor_list.py
new file mode 100755
index 00000000000..42a07e2e17f
--- /dev/null
+++ b/chromium/ui/ozone/generate_constructor_list.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# 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.
+
+"""Code generator for PlatformObject<> constructor list.
+
+This script takes as arguments a list of platform names as a text file and
+a list of types and generates a C++ source file containing a list of
+the constructors for that object in platform order.
+
+Example Output: ./ui/ozone/generate_constructor_list.py \
+ --platform test \
+ --platform dri \
+ --export OZONE_EXPORT \
+ --namespace ui \
+ --typename OzonePlatform \
+ --include '"ui/ozone/ozone_platform.h"'
+
+ // DO NOT MODIFY. GENERATED BY generate_constructor_list.py
+
+ #include "ui/ozone/platform_object_internal.h"
+
+ #include "ui/ozone/ozone_platform.h"
+
+ namespace ui {
+
+ OzonePlatform* CreateOzonePlatformTest();
+ OzonePlatform* CreateOzonePlatformDri();
+
+ } // namespace ui
+
+ namespace ui {
+
+ typedef ui::OzonePlatform* (*OzonePlatformConstructor)();
+
+ template <> const OzonePlatformConstructor
+ PlatformConstructorList<ui::OzonePlatform>::kConstructors[] = {
+ &ui::CreateOzonePlatformTest,
+ &ui::CreateOzonePlatformDri,
+ };
+
+ template class OZONE_EXPORT PlatformObject<ui::OzonePlatform>;
+
+ } // namespace ui
+"""
+
+import optparse
+import os
+import collections
+import re
+import sys
+import string
+
+
+def GetTypedefName(typename):
+ """Determine typedef name of constructor for typename.
+
+ This is just typename + "Constructor".
+ """
+
+ return typename + 'Constructor'
+
+
+def GetConstructorName(typename, platform):
+ """Determine name of static constructor function from platform name.
+
+ This is just "Create" + typename + platform.
+ """
+
+ return 'Create' + typename + string.capitalize(platform)
+
+
+def GenerateConstructorList(out, namespace, export, typenames, platforms,
+ includes):
+ """Generate static array containing a list of constructors."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_constructor_list.py\n')
+ out.write('\n')
+
+ out.write('#include "ui/ozone/platform_object_internal.h"\n')
+ out.write('\n')
+
+ for include in includes:
+ out.write('#include %(include)s\n' % {'include': include})
+ out.write('\n')
+
+ out.write('namespace %(namespace)s {\n' % {'namespace': namespace})
+ out.write('\n')
+
+ # Declarations of constructor functions.
+ for typename in typenames:
+ for platform in platforms:
+ constructor = GetConstructorName(typename, platform)
+ out.write('%(typename)s* %(constructor)s();\n'
+ % {'typename': typename,
+ 'constructor': constructor})
+ out.write('\n')
+
+ out.write('} // namespace %(namespace)s\n' % {'namespace': namespace})
+ out.write('\n')
+
+ out.write('namespace ui {\n')
+ out.write('\n')
+
+ # Handy typedefs for constructor types.
+ for typename in typenames:
+ out.write('typedef %(typename)s* (*%(typedef)s)();\n'
+ % {'typename': namespace + '::' + typename,
+ 'typedef': GetTypedefName(typename)})
+ out.write('\n')
+
+ # The actual constructor lists.
+ for typename in typenames:
+ out.write('template <> const %(typedef)s\n'
+ % {'typedef': GetTypedefName(typename)})
+ out.write('PlatformConstructorList<%(typename)s>::kConstructors[] = {\n'
+ % {'typename': namespace + '::' + typename})
+ for platform in platforms:
+ constructor = GetConstructorName(typename, platform)
+ out.write(' &%(namespace)s::%(constructor)s,\n'
+ % {'namespace': namespace, 'constructor': constructor})
+ out.write('};\n')
+ out.write('\n')
+
+ # Exported template instantiation.
+ for typename in typenames:
+ out.write('template class %(export)s PlatformObject<%(typename)s>;\n'
+ % {'export': export, 'typename': namespace + '::' + typename})
+ out.write('\n')
+
+ out.write('} // namespace ui\n')
+ out.write('\n')
+
+
+def main(argv):
+ parser = optparse.OptionParser()
+ parser.add_option('--namespace', default='ozone')
+ parser.add_option('--export', default='OZONE_EXPORT')
+ parser.add_option('--platform_list')
+ parser.add_option('--output_cc')
+ parser.add_option('--include', action='append', default=[])
+ parser.add_option('--platform', action='append', default=[])
+ parser.add_option('--typename', action='append', default=[])
+ options, _ = parser.parse_args(argv)
+
+ platforms = list(options.platform)
+ typenames = list(options.typename)
+ includes = list(options.include)
+
+ if options.platform_list:
+ platforms = open(options.platform_list, 'r').read().strip().split('\n')
+
+ # Write to standard output or file specified by --output_cc.
+ out_cc = sys.stdout
+ if options.output_cc:
+ out_cc = open(options.output_cc, 'wb')
+
+ GenerateConstructorList(out_cc, options.namespace, options.export,
+ typenames, platforms, includes)
+
+ if options.output_cc:
+ out_cc.close()
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/chromium/ui/ozone/generate_ozone_platform_list.py b/chromium/ui/ozone/generate_ozone_platform_list.py
index df85a1eab92..d47c398259b 100755
--- a/chromium/ui/ozone/generate_ozone_platform_list.py
+++ b/chromium/ui/ozone/generate_ozone_platform_list.py
@@ -6,26 +6,47 @@
"""Code generator for Ozone platform list.
This script takes as arguments a list of platform names and generates a C++
-source file containing a list of those platforms. Each list entry contains the
-name and a function pointer to the initializer for that platform.
+source file containing a list of those platforms.
+
+Each platform gets an integer identifier that is used to find objects for that
+platform (particularly constructors for platform-specific objects).
Example Output: ./generate_ozone_platform_list.py --default wayland dri wayland
- #include "ui/ozone/ozone_platform_list.h"
+ // platform_list.txt
+
+ wayland
+ dri
+
+ // platform_list.h
+
+ #ifndef UI_OZONE_PLATFORM_LIST_H_
+ #define UI_OZONE_PLATFORM_LIST_H_
namespace ui {
- OzonePlatform* CreateOzonePlatformDri();
- OzonePlatform* CreateOzonePlatformWayland();
+ const int kPlatformWayland = 0;
+ const int kPlatformDri = 1;
- const OzonePlatformListEntry kOzonePlatforms[] = {
- { "wayland", &CreateOzonePlatformWayland },
- { "dri", &CreateOzonePlatformDri },
- };
+ extern const char *kPlatformNames[kPlatformCount];
+
+ } // namespace ui
- const int kOzonePlatformCount = 2;
+ // platform_list.cc
+
+ #include "ui/ozone/platform_list.h"
+
+ namespace ui {
+
+ const char *kPlatformNames[] = {
+ "wayland", // kPlatformWayland
+ "dri", // kPlatformDri
+ };
} // namespace ui
+
+ #endif // UI_OZONE_PLATFORM_LIST_H_
+
"""
import optparse
@@ -36,63 +57,118 @@ import sys
import string
-def GetConstructorName(name):
+def GetConstantName(name):
"""Determine name of static constructor function from platform name.
We just capitalize the platform name and prepend "CreateOzonePlatform".
"""
- return 'CreateOzonePlatform' + string.capitalize(name)
+ return 'kPlatform' + string.capitalize(name)
-def GeneratePlatformList(out, platforms):
- """Generate static array containing a list of ozone platforms."""
+def GeneratePlatformListText(out, platforms):
+ """Generate text file with list of platform names, in platform id order."""
+
+ for platform in platforms:
+ out.write(platform)
+ out.write('\n')
+
+ out.write('\n')
- out.write('#include "ui/ozone/ozone_platform_list.h"\n')
+
+def GeneratePlatformListHeader(out, platforms):
+ """Generate ids of ozone platforms & declaration of static names array."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_ozone_platform_list.py\n')
+ out.write('\n')
+
+ out.write('#ifndef UI_OZONE_PLATFORM_LIST_H_\n')
+ out.write('#define UI_OZONE_PLATFORM_LIST_H_\n')
out.write('\n')
out.write('namespace ui {\n')
out.write('\n')
# Prototypes for platform initializers.
- for platform in platforms:
- out.write('OzonePlatform* %s();\n' % GetConstructorName(platform))
+ for plat_id, plat_name in enumerate(platforms):
+ out.write('const int %s = %d;\n' % (GetConstantName(plat_name), plat_id))
out.write('\n')
- # List of platform names and initializers.
- out.write('const OzonePlatformListEntry kOzonePlatforms[] = {\n')
- for platform in platforms:
- out.write(' { "%s", &%s },\n' % (platform, GetConstructorName(platform)))
- out.write('};\n')
+ # Platform count.
+ out.write('const int kPlatformCount = %d;\n' % len(platforms))
+ out.write('\n')
+
+ # Declaration for names list.
+ out.write('extern const char* kPlatformNames[kPlatformCount];\n')
+ out.write('\n')
+
+ out.write('} // namespace ui\n')
+ out.write('\n')
+
+ out.write('#endif // UI_OZONE_PLATFORM_LIST_H_\n')
+ out.write('\n')
+
+
+def GeneratePlatformListSource(out, platforms):
+ """Generate static array containing a list of ozone platforms."""
+
+ out.write('// DO NOT MODIFY. GENERATED BY generate_ozone_platform_list.py\n')
+ out.write('\n')
+
+ out.write('#include "ui/ozone/platform_list.h"\n')
+ out.write('\n')
+
+ out.write('namespace ui {\n')
out.write('\n')
- out.write('const int kOzonePlatformCount = %d;\n' % len(platforms))
+ # Definition of names list.
+ out.write('const char* kPlatformNames[] = {\n')
+
+ # Prototypes for platform initializers.
+ for plat_name in platforms:
+ out.write(' "%s", // %s\n' % (plat_name, GetConstantName(plat_name)))
+ out.write('};\n')
out.write('\n')
out.write('} // namespace ui\n')
+ out.write('\n')
def main(argv):
parser = optparse.OptionParser()
- parser.add_option('--output_file')
+ parser.add_option('--output_cc')
+ parser.add_option('--output_h')
+ parser.add_option('--output_txt')
parser.add_option('--default')
options, platforms = parser.parse_args(argv)
- # Write to standard output or file specified by --output_file.
- out = sys.stdout
- if options.output_file:
- out = open(options.output_file, 'wb')
-
# Reorder the platforms when --default is specified.
# The default platform must appear first in the platform list.
if options.default and options.default in platforms:
platforms.remove(options.default)
platforms.insert(0, options.default)
- GeneratePlatformList(out, platforms)
-
- if options.output_file:
- out.close()
+ # Write to standard output or file specified by --output_{cc,h}.
+ out_cc = sys.stdout
+ out_h = sys.stdout
+ out_txt = sys.stdout
+ if options.output_cc:
+ out_cc = open(options.output_cc, 'wb')
+ if options.output_h:
+ out_h = open(options.output_h, 'wb')
+ if options.output_txt:
+ out_txt = open(options.output_txt, 'wb')
+
+ GeneratePlatformListText(out_txt, platforms)
+ GeneratePlatformListHeader(out_h, platforms)
+ GeneratePlatformListSource(out_cc, platforms)
+
+ if options.output_cc:
+ out_cc.close()
+ if options.output_h:
+ out_h.close()
+ if options.output_txt:
+ out_txt.close()
return 0
diff --git a/chromium/ui/ozone/ozone.gni b/chromium/ui/ozone/ozone.gni
new file mode 100644
index 00000000000..a777f59a861
--- /dev/null
+++ b/chromium/ui/ozone/ozone.gni
@@ -0,0 +1,18 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+if (use_ozone) {
+ # Enable built-in ozone platforms if ozone is enabled.
+ ozone_platform_caca = false
+ ozone_platform_dri = true
+ ozone_platform_ozonex = false
+ ozone_platform_test = true
+} else {
+ ozone_platform_caca = false
+ ozone_platform_dri = false
+ ozone_platform_ozonex = false
+ ozone_platform_test = false
+}
diff --git a/chromium/ui/ozone/ozone.gyp b/chromium/ui/ozone/ozone.gyp
index 03f5b2eecd0..74cb523d8a9 100644
--- a/chromium/ui/ozone/ozone.gyp
+++ b/chromium/ui/ozone/ozone.gyp
@@ -8,37 +8,88 @@
'external_ozone_platforms': [],
'external_ozone_platform_files': [],
'external_ozone_platform_deps': [],
+ 'external_ozone_platform_unittest_deps': [],
+ 'internal_ozone_platforms': [],
+ 'internal_ozone_platform_deps': [],
+ 'internal_ozone_platform_unittest_deps': [],
},
'targets': [
{
+ 'target_name': 'ozone_base',
+ 'type': '<(component)',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'OZONE_BASE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'public/cursor_factory_ozone.cc',
+ 'public/cursor_factory_ozone.h',
+ 'public/event_factory_ozone.cc',
+ 'public/event_factory_ozone.h',
+ 'public/gpu_platform_support.cc',
+ 'public/gpu_platform_support.h',
+ 'public/gpu_platform_support_host.cc',
+ 'public/gpu_platform_support_host.h',
+ 'public/overlay_candidates_ozone.cc',
+ 'public/overlay_candidates_ozone.h',
+ 'public/surface_factory_ozone.cc',
+ 'public/surface_factory_ozone.h',
+ 'public/surface_ozone_canvas.h',
+ 'public/surface_ozone_egl.h',
+ ],
+ },
+ {
'target_name': 'ozone',
'type': '<(component)',
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/ui/events/events.gyp:events',
+ '<(DEPTH)/ui/events/ozone/events_ozone.gyp:events_ozone',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
'<(DEPTH)/skia/skia.gyp:skia',
'<@(external_ozone_platform_deps)',
+ '<@(internal_ozone_platform_deps)',
+ 'ozone_base',
],
'defines': [
'OZONE_IMPLEMENTATION',
],
'variables': {
- 'platform_list_file': '<(SHARED_INTERMEDIATE_DIR)/ui/ozone/ozone_platform_list.cc',
+ 'platform_list_cc_file': '<(INTERMEDIATE_DIR)/ui/ozone/platform_list.cc',
+ 'platform_list_h_file': '<(SHARED_INTERMEDIATE_DIR)/ui/ozone/platform_list.h',
+ 'platform_list_txt_file': '<(SHARED_INTERMEDIATE_DIR)/ui/ozone/platform_list.txt',
+ 'constructor_list_cc_file': '<(INTERMEDIATE_DIR)/ui/ozone/constructor_list.cc',
'ozone_platforms': [
'<@(external_ozone_platforms)',
+ '<@(internal_ozone_platforms)',
],
},
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
'sources': [
- '<(platform_list_file)',
+ '<(platform_list_cc_file)',
+ '<(platform_list_h_file)',
+ '<(constructor_list_cc_file)',
+
+ # common/chromeos files are excluded automatically when building with
+ # chromeos=0, by exclusion rules in filename_rules.gypi due to the
+ # 'chromeos' folder name.
+ 'common/chromeos/native_display_delegate_ozone.cc',
+ 'common/chromeos/native_display_delegate_ozone.h',
+ 'common/chromeos/touchscreen_device_manager_ozone.cc',
+ 'common/chromeos/touchscreen_device_manager_ozone.h',
'ozone_platform.cc',
'ozone_platform.h',
'ozone_switches.cc',
'ozone_switches.h',
- 'platform/dri/ozone_platform_dri.cc',
- 'platform/dri/ozone_platform_dri.h',
- 'platform/test/ozone_platform_test.cc',
- 'platform/test/ozone_platform_test.h',
+ 'platform_selection.cc',
+ 'platform_selection.h',
'<@(external_ozone_platform_files)',
],
'actions': [
@@ -51,41 +102,98 @@
'<(generator_path)',
],
'outputs': [
- '<(platform_list_file)',
+ '<(platform_list_cc_file)',
+ '<(platform_list_h_file)',
+ '<(platform_list_txt_file)',
],
'action': [
'python',
'<(generator_path)',
- '--output_file=<(platform_list_file)',
+ '--output_cc=<(platform_list_cc_file)',
+ '--output_h=<(platform_list_h_file)',
+ '--output_txt=<(platform_list_txt_file)',
'--default=<(ozone_platform)',
'<@(ozone_platforms)',
],
},
+ {
+ 'action_name': 'generate_constructor_list',
+ 'variables': {
+ 'generator_path': 'generate_constructor_list.py',
+ },
+ 'inputs': [
+ '<(generator_path)',
+ '<(platform_list_txt_file)',
+ ],
+ 'outputs': [
+ '<(constructor_list_cc_file)',
+ ],
+ 'action': [
+ 'python',
+ '<(generator_path)',
+ '--platform_list=<(platform_list_txt_file)',
+ '--output_cc=<(constructor_list_cc_file)',
+ '--namespace=ui',
+ '--typename=OzonePlatform',
+ '--include="ui/ozone/ozone_platform.h"'
+ ],
+ },
],
'conditions': [
- ['<(ozone_platform_dri)==1', {
- 'variables': {
- 'ozone_platforms': [
- 'dri'
- ]
- }
- }, { # ozone_platform_dri==0
+ ['use_udev == 0', {
'sources/': [
- ['exclude', '^platform/dri/'],
- ]
+ ['exclude', '_udev\\.(h|cc)$'],
+ ],
}],
- ['<(ozone_platform_test)==1', {
- 'variables': {
- 'ozone_platforms': [
- 'test'
- ],
- }
- }, { # ozone_platform_test==0
- 'sources/': [
- ['exclude', '^platform/test/'],
- ]
+ ['chromeos==1', {
+ 'dependencies': [
+ '<(DEPTH)/ui/display/display.gyp:display_types',
+ ],
}],
- ]
+ ],
+ },
+ {
+ 'target_name': 'ozone_unittests',
+ 'type': '<(gtest_target_type)',
+ 'sources': [
+ 'run_all_unittests.cc',
+ ],
+ 'dependencies': [
+ 'ozone',
+ 'ozone_base',
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../testing/gtest.gyp:gtest',
+ '<@(external_ozone_platform_unittest_deps)',
+ '<@(internal_ozone_platform_unittest_deps)',
+ ],
},
],
+ 'conditions': [
+ ['<(ozone_platform_caca) == 1', {
+ 'includes': [
+ 'platform/caca/caca.gypi',
+ ],
+ }],
+ ['<(ozone_platform_dri) == 1 or <(ozone_platform_gbm) == 1', {
+ 'includes': [
+ 'platform/dri/dri.gypi',
+ ],
+ }],
+ ['<(ozone_platform_egltest) == 1', {
+ 'includes': [
+ 'platform/egltest/egltest.gypi',
+ ],
+ }],
+ ['<(ozone_platform_gbm) == 1', {
+ 'includes': [
+ 'platform/dri/gbm.gypi',
+ ],
+ }],
+ ['<(ozone_platform_test) == 1', {
+ 'includes': [
+ 'platform/test/test.gypi',
+ ],
+ }],
+ ],
}
diff --git a/chromium/ui/ozone/ozone_base_export.h b/chromium/ui/ozone/ozone_base_export.h
new file mode 100644
index 00000000000..d3df39bc298
--- /dev/null
+++ b/chromium/ui/ozone/ozone_base_export.h
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_OZONE_BASE_EXPORT_H_
+#define UI_OZONE_OZONE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(OZONE_BASE_IMPLEMENTATION)
+#define OZONE_BASE_EXPORT __declspec(dllexport)
+#else
+#define OZONE_BASE_EXPORT __declspec(dllimport)
+#endif // defined(OZONE_BASE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(OZONE_BASE_IMPLEMENTATION)
+#define OZONE_BASE_EXPORT __attribute__((visibility("default")))
+#else
+#define OZONE_BASE_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define OZONE_BASE_EXPORT
+#endif
+
+#endif // UI_OZONE_OZONE_BASE_EXPORT_H_
diff --git a/chromium/ui/ozone/ozone_platform.cc b/chromium/ui/ozone/ozone_platform.cc
index a0840058ed4..35855649793 100644
--- a/chromium/ui/ozone/ozone_platform.cc
+++ b/chromium/ui/ozone/ozone_platform.cc
@@ -3,57 +3,71 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "ui/ozone/ozone_platform.h"
-#include "ui/ozone/ozone_platform_list.h"
#include "ui/ozone/ozone_switches.h"
+#include "ui/ozone/platform_object.h"
+#include "ui/ozone/platform_selection.h"
namespace ui {
namespace {
-// Helper to construct an OzonePlatform by name using the platform list.
-OzonePlatform* CreatePlatform(const std::string& platform_name) {
- // The first platform is the defualt.
- if (platform_name == "default" && kOzonePlatformCount > 0)
- return kOzonePlatforms[0].constructor();
+bool g_platform_initialized_ui = false;
+bool g_platform_initialized_gpu = false;
- // Otherwise, search for a matching platform in the list.
- for (int i = 0; i < kOzonePlatformCount; ++i)
- if (platform_name == kOzonePlatforms[i].name)
- return kOzonePlatforms[i].constructor();
-
- LOG(FATAL) << "Invalid ozone platform: " << platform_name;
- return NULL; // not reached
}
-// Returns the name of the platform to use (value of --ozone-platform flag).
-std::string GetRequestedPlatform() {
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kOzonePlatform))
- return "default";
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kOzonePlatform);
+OzonePlatform::OzonePlatform() {
+ CHECK(!instance_) << "There should only be a single OzonePlatform.";
+ instance_ = this;
+ g_platform_initialized_ui = false;
+ g_platform_initialized_gpu = false;
}
-} // namespace
-
-OzonePlatform::OzonePlatform() {}
-
OzonePlatform::~OzonePlatform() {
- gfx::SurfaceFactoryOzone::SetInstance(NULL);
- ui::EventFactoryOzone::SetInstance(NULL);
+ CHECK_EQ(instance_, this);
+ instance_ = NULL;
+}
+
+// static
+void OzonePlatform::InitializeForUI() {
+ CreateInstance();
+ if (g_platform_initialized_ui)
+ return;
+ g_platform_initialized_ui = true;
+ instance_->InitializeUI();
}
// static
-void OzonePlatform::Initialize() {
- if (instance_)
+void OzonePlatform::InitializeForGPU() {
+ CreateInstance();
+ if (g_platform_initialized_gpu)
return;
+ g_platform_initialized_gpu = true;
+ instance_->InitializeGPU();
+}
+
+// static
+OzonePlatform* OzonePlatform::GetInstance() {
+ CHECK(instance_) << "OzonePlatform is not initialized";
+ return instance_;
+}
- instance_ = CreatePlatform(GetRequestedPlatform());
+// static
+void OzonePlatform::CreateInstance() {
+ if (!instance_) {
+ TRACE_EVENT1("ozone",
+ "OzonePlatform::Initialize",
+ "platform",
+ GetOzonePlatformName());
+ scoped_ptr<OzonePlatform> platform =
+ PlatformObject<OzonePlatform>::Create();
- // Inject ozone interfaces.
- gfx::SurfaceFactoryOzone::SetInstance(instance_->GetSurfaceFactoryOzone());
- ui::EventFactoryOzone::SetInstance(instance_->GetEventFactoryOzone());
+ // TODO(spang): Currently need to leak this object.
+ CHECK_EQ(instance_, platform.release());
+ }
}
// static
diff --git a/chromium/ui/ozone/ozone_platform.h b/chromium/ui/ozone/ozone_platform.h
index 519d8b2f103..710eb9daf49 100644
--- a/chromium/ui/ozone/ozone_platform.h
+++ b/chromium/ui/ozone/ozone_platform.h
@@ -6,12 +6,18 @@
#define UI_OZONE_OZONE_PLATFORM_H_
#include "base/memory/scoped_ptr.h"
-#include "ui/events/ozone/event_factory_ozone.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
#include "ui/ozone/ozone_export.h"
namespace ui {
+class CursorFactoryOzone;
+class EventFactoryOzone;
+class NativeDisplayDelegate;
+class SurfaceFactoryOzone;
+class TouchscreenDeviceManager;
+class GpuPlatformSupport;
+class GpuPlatformSupportHost;
+
// Base class for Ozone platform implementations.
//
// Ozone platforms must override this class and implement the virtual
@@ -31,17 +37,36 @@ class OZONE_EXPORT OzonePlatform {
OzonePlatform();
virtual ~OzonePlatform();
- // Initialize the platform. Once complete, SurfaceFactoryOzone &
- // EventFactoryOzone will be set.
- static void Initialize();
+ // Initializes the subsystems/resources necessary for the UI process (e.g.
+ // events, surface, etc.)
+ static void InitializeForUI();
+
+ // Initializes the subsystems/resources necessary for the GPU process.
+ static void InitializeForGPU();
+
+ static OzonePlatform* GetInstance();
// Factory getters to override in subclasses. The returned objects will be
// injected into the appropriate layer at startup. Subclasses should not
// inject these objects themselves. Ownership is retained by OzonePlatform.
- virtual gfx::SurfaceFactoryOzone* GetSurfaceFactoryOzone() = 0;
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() = 0;
virtual ui::EventFactoryOzone* GetEventFactoryOzone() = 0;
+ virtual ui::CursorFactoryOzone* GetCursorFactoryOzone() = 0;
+ virtual ui::GpuPlatformSupport* GetGpuPlatformSupport() = 0;
+ virtual ui::GpuPlatformSupportHost* GetGpuPlatformSupportHost() = 0;
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<ui::NativeDisplayDelegate>
+ CreateNativeDisplayDelegate() = 0;
+ virtual scoped_ptr<ui::TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() = 0;
+#endif
private:
+ virtual void InitializeUI() = 0;
+ virtual void InitializeGPU() = 0;
+
+ static void CreateInstance();
+
static OzonePlatform* instance_;
DISALLOW_COPY_AND_ASSIGN(OzonePlatform);
diff --git a/chromium/ui/ozone/ozone_platform_list.h b/chromium/ui/ozone/ozone_platform_list.h
deleted file mode 100644
index 2689c259125..00000000000
--- a/chromium/ui/ozone/ozone_platform_list.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_OZONE_PLATFORM_LIST_H_
-#define UI_OZONE_OZONE_PLATFORM_LIST_H_
-
-namespace ui {
-
-class OzonePlatform;
-
-typedef OzonePlatform* (*OzonePlatformConstructor)();
-
-struct OzonePlatformListEntry {
- const char* name;
- OzonePlatformConstructor constructor;
-};
-
-extern const OzonePlatformListEntry kOzonePlatforms[];
-
-extern const int kOzonePlatformCount;
-
-} // namespace ui
-
-#endif // UI_OZONE_OZONE_PLATFORM_LIST_H_
diff --git a/chromium/ui/ozone/platform/README b/chromium/ui/ozone/platform/README
new file mode 100644
index 00000000000..cc91d3b7ead
--- /dev/null
+++ b/chromium/ui/ozone/platform/README
@@ -0,0 +1,2 @@
+This directory contains implementations of platforms. Each platform implements
+the interfaces from ui/ozone/public for the rest of chromium.
diff --git a/chromium/ui/ozone/platform/caca/DEPS b/chromium/ui/ozone/platform/caca/DEPS
new file mode 100644
index 00000000000..46d48b30e10
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/skia",
+]
diff --git a/chromium/ui/ozone/platform/caca/OWNERS b/chromium/ui/ozone/platform/caca/OWNERS
new file mode 100644
index 00000000000..0d77c0eae94
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/OWNERS
@@ -0,0 +1 @@
+dnicoara@chromium.org
diff --git a/chromium/ui/ozone/platform/caca/caca.gypi b/chromium/ui/ozone/platform/caca/caca.gypi
new file mode 100644
index 00000000000..8c1b55d2a7d
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca.gypi
@@ -0,0 +1,45 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_caca',
+ ],
+ 'internal_ozone_platforms': [
+ 'caca'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_caca',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../events/events.gyp:events',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lcaca',
+ ],
+ },
+ 'sources': [
+ 'caca_connection.cc',
+ 'caca_connection.h',
+ 'caca_event_factory.cc',
+ 'caca_event_factory.h',
+ 'caca_surface_factory.cc',
+ 'caca_surface_factory.h',
+ 'ozone_platform_caca.cc',
+ 'ozone_platform_caca.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/ozone/platform/caca/caca_connection.cc b/chromium/ui/ozone/platform/caca/caca_connection.cc
new file mode 100644
index 00000000000..49b51a45c86
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_connection.cc
@@ -0,0 +1,40 @@
+// 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/ozone/platform/caca/caca_connection.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+// TODO(dnicoara) As an optimization, |bitmap_size_| should be scaled based on
+// |physical_size_| and font size.
+CacaConnection::CacaConnection()
+ : canvas_(NULL),
+ display_(NULL),
+ physical_size_(160, 48),
+ bitmap_size_(800, 600) {}
+
+CacaConnection::~CacaConnection() {
+ if (display_) {
+ caca_free_display(display_);
+ caca_free_canvas(canvas_);
+ }
+}
+
+void CacaConnection::Initialize() {
+ if (display_)
+ return;
+
+ canvas_ = caca_create_canvas(physical_size_.width(), physical_size_.height());
+ display_ = caca_create_display(canvas_);
+
+ physical_size_.SetSize(caca_get_canvas_width(canvas_),
+ caca_get_canvas_height(canvas_));
+
+ caca_set_cursor(display_, 1);
+ caca_set_display_title(display_, "Ozone Content Shell");
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/caca/caca_connection.h b/chromium/ui/ozone/platform/caca/caca_connection.h
new file mode 100644
index 00000000000..dbe194358ef
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_connection.h
@@ -0,0 +1,47 @@
+// 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_OZONE_PLATFORM_CACA_CACA_CONNECTION_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_CONNECTION_H_
+
+#include <caca.h>
+
+#include "base/macros.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+// Basic initialization of Libcaca. This needs to be shared between SFO and EFO
+// since both need the |display_| to draw and process events respectively.
+// Note, |canvas_| needs to be here since it is needed for creating a
+// |display_|.
+class CacaConnection {
+ public:
+ CacaConnection();
+ ~CacaConnection();
+
+ void Initialize();
+
+ // This is the Caca canvas size.
+ gfx::Size physical_size() const { return physical_size_; }
+ gfx::Size bitmap_size() const { return bitmap_size_; }
+ caca_display_t* display() const { return display_; }
+
+ private:
+ caca_canvas_t* canvas_;
+ caca_display_t* display_;
+
+ // Size of the console in characters. This can be changed by setting
+ // CACA_GEOMETRY environment variable.
+ gfx::Size physical_size_;
+
+ // Size of the backing buffer we draw into. Size in pixels.
+ gfx::Size bitmap_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaConnection);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_CONNECTION_H_
diff --git a/chromium/ui/ozone/platform/caca/caca_event_factory.cc b/chromium/ui/ozone/platform/caca/caca_event_factory.cc
new file mode 100644
index 00000000000..c17e5a4f965
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_event_factory.cc
@@ -0,0 +1,232 @@
+// 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/ozone/platform/caca/caca_event_factory.h"
+
+#include <caca.h>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/ozone/platform/caca/caca_connection.h"
+
+namespace ui {
+
+namespace {
+
+ui::KeyboardCode GetKeyboardCode(const caca_event_t& event) {
+ // List of special mappings the Caca provides.
+ static const ui::KeyboardCode kCacaKeyMap[] = {
+ ui::VKEY_UNKNOWN,
+ ui::VKEY_A,
+ ui::VKEY_B,
+ ui::VKEY_C,
+ ui::VKEY_D,
+ ui::VKEY_E,
+ ui::VKEY_F,
+ ui::VKEY_G,
+ ui::VKEY_BACK,
+ ui::VKEY_TAB,
+ ui::VKEY_J,
+ ui::VKEY_K,
+ ui::VKEY_L,
+ ui::VKEY_RETURN,
+ ui::VKEY_N,
+ ui::VKEY_O,
+ ui::VKEY_P,
+ ui::VKEY_Q,
+ ui::VKEY_R,
+ ui::VKEY_PAUSE,
+ ui::VKEY_T,
+ ui::VKEY_U,
+ ui::VKEY_V,
+ ui::VKEY_W,
+ ui::VKEY_X,
+ ui::VKEY_Y,
+ ui::VKEY_Z,
+ ui::VKEY_ESCAPE,
+ ui::VKEY_DELETE,
+ ui::VKEY_UP,
+ ui::VKEY_DOWN,
+ ui::VKEY_LEFT,
+ ui::VKEY_RIGHT,
+ ui::VKEY_INSERT,
+ ui::VKEY_HOME,
+ ui::VKEY_END,
+ ui::VKEY_PRIOR,
+ ui::VKEY_NEXT,
+ ui::VKEY_F1,
+ ui::VKEY_F2,
+ ui::VKEY_F3,
+ ui::VKEY_F4,
+ ui::VKEY_F5,
+ ui::VKEY_F6,
+ ui::VKEY_F7,
+ ui::VKEY_F8,
+ ui::VKEY_F9,
+ ui::VKEY_F10,
+ ui::VKEY_F11,
+ ui::VKEY_F12,
+ };
+
+ int key_code = caca_get_event_key_ch(&event);
+ if (key_code >= 'a' && key_code <= 'z')
+ return static_cast<ui::KeyboardCode>(key_code - ('a' - 'A'));
+ if (key_code >= '0' && key_code <= 'Z')
+ return static_cast<ui::KeyboardCode>(key_code);
+ if (static_cast<unsigned int>(key_code) < arraysize(kCacaKeyMap))
+ return kCacaKeyMap[key_code];
+
+ return ui::VKEY_UNKNOWN;
+}
+
+int ModifierFromKey(const caca_event_t& event) {
+ int key_code = caca_get_event_key_ch(&event);
+ if (key_code >= 'A' && key_code <= 'Z')
+ return ui::EF_SHIFT_DOWN;
+ if ((key_code >= CACA_KEY_CTRL_A && key_code <= CACA_KEY_CTRL_G) ||
+ (key_code >= CACA_KEY_CTRL_J && key_code <= CACA_KEY_CTRL_L) ||
+ (key_code >= CACA_KEY_CTRL_N && key_code <= CACA_KEY_CTRL_R) ||
+ (key_code >= CACA_KEY_CTRL_T && key_code <= CACA_KEY_CTRL_Z))
+ return ui::EF_CONTROL_DOWN;
+
+ return ui::EF_NONE;
+}
+
+int ModifierFromButton(const caca_event_t& event) {
+ switch (caca_get_event_mouse_button(&event)) {
+ case 1:
+ return ui::EF_LEFT_MOUSE_BUTTON;
+ case 2:
+ return ui::EF_RIGHT_MOUSE_BUTTON;
+ case 3:
+ return ui::EF_MIDDLE_MOUSE_BUTTON;
+ }
+ return 0;
+}
+
+// Translate coordinates to bitmap coordinates.
+gfx::PointF TranslateLocation(const gfx::PointF& location,
+ CacaConnection* connection) {
+ gfx::Size physical_size = connection->physical_size();
+ gfx::Size bitmap_size = connection->bitmap_size();
+ return gfx::PointF(
+ location.x() * bitmap_size.width() / physical_size.width(),
+ location.y() * bitmap_size.height() / physical_size.height());
+}
+
+ui::EventType GetEventTypeFromNative(const caca_event_t& event) {
+ switch (caca_get_event_type(&event)) {
+ case CACA_EVENT_KEY_PRESS:
+ return ui::ET_KEY_PRESSED;
+ case CACA_EVENT_KEY_RELEASE:
+ return ui::ET_KEY_RELEASED;
+ case CACA_EVENT_MOUSE_PRESS:
+ return ui::ET_MOUSE_PRESSED;
+ case CACA_EVENT_MOUSE_RELEASE:
+ return ui::ET_MOUSE_RELEASED;
+ case CACA_EVENT_MOUSE_MOTION:
+ return ui::ET_MOUSE_MOVED;
+ default:
+ return ui::ET_UNKNOWN;
+ }
+}
+
+} // namespace
+
+CacaEventFactory::CacaEventFactory(CacaConnection* connection)
+ : connection_(connection),
+ weak_ptr_factory_(this),
+ delay_(base::TimeDelta::FromMilliseconds(10)),
+ modifier_flags_(0) {
+}
+
+CacaEventFactory::~CacaEventFactory() {
+}
+
+void CacaEventFactory::WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) {
+ NOTIMPLEMENTED();
+}
+
+void CacaEventFactory::OnDispatcherListChanged() {
+ ScheduleEventProcessing();
+}
+
+void CacaEventFactory::ScheduleEventProcessing() {
+ // Caca uses a poll based event retrieval. Since we don't want to block we'd
+ // either need to spin up a new thread or just poll. For simplicity just poll
+ // for a message every |delay_| time delta.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CacaEventFactory::TryProcessingEvent,
+ weak_ptr_factory_.GetWeakPtr()),
+ delay_);
+}
+
+void CacaEventFactory::TryProcessingEvent() {
+ caca_event_t event;
+ int event_mask = CACA_EVENT_KEY_PRESS | CACA_EVENT_KEY_RELEASE |
+ CACA_EVENT_MOUSE_PRESS | CACA_EVENT_MOUSE_RELEASE |
+ CACA_EVENT_MOUSE_MOTION;
+ if (connection_->display() &&
+ caca_get_event(connection_->display(), event_mask, &event, 0)) {
+
+ ui::EventType type = GetEventTypeFromNative(event);
+ bool pressed = type == ui::ET_KEY_PRESSED || type == ui::ET_MOUSE_PRESSED;
+
+ switch (type) {
+ case ui::ET_KEY_PRESSED:
+ case ui::ET_KEY_RELEASED: {
+ if (pressed)
+ modifier_flags_ |= ModifierFromKey(event);
+ else
+ modifier_flags_ &= ~ModifierFromKey(event);
+
+ ui::KeyEvent key_event(
+ type, GetKeyboardCode(event), modifier_flags_, true);
+ DispatchEvent(&key_event);
+ break;
+ }
+ case ui::ET_MOUSE_MOVED:
+ last_cursor_location_.SetPoint(caca_get_event_mouse_x(&event),
+ caca_get_event_mouse_y(&event));
+ // Update cursor location.
+ caca_gotoxy(caca_get_canvas(connection_->display()),
+ last_cursor_location_.x(),
+ last_cursor_location_.y());
+ // fallthrough
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED: {
+ int flags = 0;
+ int changed_flags = 0;
+ if (type != ui::ET_MOUSE_MOVED) {
+ if (pressed) {
+ changed_flags = ModifierFromButton(event);
+ modifier_flags_ |= changed_flags;
+ } else {
+ modifier_flags_ &= ~changed_flags;
+ }
+ // On release the button pressed is removed from |modifier_flags_|,
+ // but sending the event needs it set.
+ flags = modifier_flags_ | changed_flags;
+ }
+ gfx::PointF location = TranslateLocation(last_cursor_location_,
+ connection_);
+ ui::MouseEvent mouse_event(
+ type, location, location, flags, changed_flags);
+ DispatchEvent(&mouse_event);
+ break;
+ }
+ default:
+ NOTIMPLEMENTED();
+ break;
+ }
+ }
+
+ ScheduleEventProcessing();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/caca/caca_event_factory.h b/chromium/ui/ozone/platform/caca/caca_event_factory.h
new file mode 100644
index 00000000000..f732f00865f
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_event_factory.h
@@ -0,0 +1,54 @@
+// 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_OZONE_PLATFORM_CACA_CACA_EVENT_FACTORY_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_EVENT_FACTORY_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/public/event_factory_ozone.h"
+
+namespace ui {
+
+class CacaConnection;
+
+class CacaEventFactory : public EventFactoryOzone,
+ public PlatformEventSource {
+ public:
+ CacaEventFactory(CacaConnection* connection);
+ virtual ~CacaEventFactory();
+
+ // ui::EventFactoryOzone:
+ virtual void WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) OVERRIDE;
+
+ private:
+ // PlatformEventSource:
+ virtual void OnDispatcherListChanged() OVERRIDE;
+
+ void ScheduleEventProcessing();
+
+ void TryProcessingEvent();
+
+ CacaConnection* connection_; // Not owned.
+
+ base::WeakPtrFactory<CacaEventFactory> weak_ptr_factory_;
+
+ // Delay between event polls.
+ base::TimeDelta delay_;
+
+ // Keep track of last cursor position to dispatch correct mouse push/release
+ // events.
+ gfx::PointF last_cursor_location_;
+
+ int modifier_flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaEventFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_EVENT_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/caca/caca_surface_factory.cc b/chromium/ui/ozone/platform/caca/caca_surface_factory.cc
new file mode 100644
index 00000000000..58b5e640c90
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_surface_factory.cc
@@ -0,0 +1,147 @@
+// 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/ozone/platform/caca/caca_surface_factory.h"
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/platform/caca/caca_connection.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
+
+class CacaSurface : public ui::SurfaceOzoneCanvas {
+ public:
+ CacaSurface(CacaConnection* connection);
+ virtual ~CacaSurface();
+
+ bool Initialize();
+
+ // ui::SurfaceOzoneCanvas overrides:
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE;
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE;
+ virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ private:
+ CacaConnection* connection_; // Not owned.
+
+ caca_dither_t* dither_;
+
+ skia::RefPtr<SkSurface> surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacaSurface);
+};
+
+CacaSurface::CacaSurface(CacaConnection* connection)
+ : connection_(connection) {}
+
+CacaSurface::~CacaSurface() {
+ caca_free_dither(dither_);
+}
+
+bool CacaSurface::Initialize() {
+ SkImageInfo info = SkImageInfo::Make(connection_->bitmap_size().width(),
+ connection_->bitmap_size().height(),
+ kPMColor_SkColorType,
+ kPremul_SkAlphaType);
+
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
+ if (!surface_) {
+ LOG(ERROR) << "Failed to create SkCanvas";
+ return false;
+ }
+
+ dither_ = caca_create_dither(
+ info.bytesPerPixel() * 8,
+ info.width(),
+ info.height(),
+ info.minRowBytes(),
+ 0x00ff0000,
+ 0x0000ff00,
+ 0x000000ff,
+ 0xff000000);
+
+ return true;
+}
+
+skia::RefPtr<SkCanvas> CacaSurface::GetCanvas() {
+ return skia::SharePtr<SkCanvas>(surface_->getCanvas());
+}
+
+void CacaSurface::ResizeCanvas(const gfx::Size& viewport_size) {
+ NOTIMPLEMENTED();
+}
+
+void CacaSurface::PresentCanvas(const gfx::Rect& damage) {
+ SkImageInfo info;
+ size_t row_bytes;
+ const void* pixels = surface_->peekPixels(&info, &row_bytes);
+
+ caca_canvas_t* canvas = caca_get_canvas(connection_->display());
+ caca_dither_bitmap(canvas, 0, 0,
+ caca_get_canvas_width(canvas),
+ caca_get_canvas_height(canvas),
+ dither_,
+ static_cast<const uint8_t*>(pixels));
+ caca_refresh_display(connection_->display());
+}
+
+scoped_ptr<gfx::VSyncProvider> CacaSurface::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>();
+}
+
+} // namespace
+
+CacaSurfaceFactory::CacaSurfaceFactory(CacaConnection* connection)
+ : state_(UNINITIALIZED),
+ connection_(connection) {
+}
+
+CacaSurfaceFactory::~CacaSurfaceFactory() {
+ if (state_ == INITIALIZED)
+ ShutdownHardware();
+}
+
+ui::SurfaceFactoryOzone::HardwareState
+CacaSurfaceFactory::InitializeHardware() {
+ connection_->Initialize();
+ state_ = INITIALIZED;
+ return state_;
+}
+
+void CacaSurfaceFactory::ShutdownHardware() {
+ CHECK_EQ(INITIALIZED, state_);
+ state_ = UNINITIALIZED;
+}
+
+gfx::AcceleratedWidget CacaSurfaceFactory::GetAcceleratedWidget() {
+ return kDefaultWidgetHandle;
+}
+
+bool CacaSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ NOTREACHED();
+ return false;
+}
+
+scoped_ptr<ui::SurfaceOzoneCanvas> CacaSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ CHECK_EQ(INITIALIZED, state_);
+ CHECK_EQ(kDefaultWidgetHandle, widget);
+
+ scoped_ptr<CacaSurface> canvas(new CacaSurface(connection_));
+ CHECK(canvas->Initialize());
+ return canvas.PassAs<ui::SurfaceOzoneCanvas>();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/caca/caca_surface_factory.h b/chromium/ui/ozone/platform/caca/caca_surface_factory.h
new file mode 100644
index 00000000000..a07033ae54b
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/caca_surface_factory.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_CACA_CACA_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_CACA_CACA_SURFACE_FACTORY_H_
+
+#include <caca.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace gfx {
+class SurfaceOzone;
+}
+
+namespace ui {
+
+class CacaConnection;
+
+class CacaSurfaceFactory : public ui::SurfaceFactoryOzone {
+ public:
+ CacaSurfaceFactory(CacaConnection* connection);
+ virtual ~CacaSurfaceFactory();
+
+ // ui::SurfaceFactoryOzone overrides:
+ virtual HardwareState InitializeHardware() OVERRIDE;
+ virtual void ShutdownHardware() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+ virtual scoped_ptr<ui::SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+
+ private:
+ HardwareState state_;
+
+ CacaConnection* connection_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(CacaSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_CACA_SURFACE_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/caca/ozone_platform_caca.cc b/chromium/ui/ozone/platform/caca/ozone_platform_caca.cc
new file mode 100644
index 00000000000..3a27b4434e3
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/ozone_platform_caca.cc
@@ -0,0 +1,77 @@
+// 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/ozone/platform/caca/ozone_platform_caca.h"
+
+#include "ui/ozone/ozone_platform.h"
+#include "ui/ozone/platform/caca/caca_connection.h"
+#include "ui/ozone/platform/caca/caca_event_factory.h"
+#include "ui/ozone/platform/caca/caca_surface_factory.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/ozone/common/chromeos/native_display_delegate_ozone.h"
+#include "ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+#endif
+
+namespace ui {
+
+namespace {
+
+class OzonePlatformCaca : public OzonePlatform {
+ public:
+ OzonePlatformCaca() {}
+ virtual ~OzonePlatformCaca() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE {
+ return event_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return NULL; // no GPU support
+ }
+
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+ virtual scoped_ptr<TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() OVERRIDE {
+ return scoped_ptr<TouchscreenDeviceManager>(
+ new TouchscreenDeviceManagerOzone());
+ }
+#endif
+
+ virtual void InitializeUI() OVERRIDE {
+ surface_factory_ozone_.reset(new CacaSurfaceFactory(&connection_));
+ event_factory_ozone_.reset(new CacaEventFactory(&connection_));
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {}
+
+ private:
+ CacaConnection connection_;
+ scoped_ptr<CacaSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<CacaEventFactory> event_factory_ozone_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformCaca);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformCaca() { return new OzonePlatformCaca; }
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/caca/ozone_platform_caca.h b/chromium/ui/ozone/platform/caca/ozone_platform_caca.h
new file mode 100644
index 00000000000..bf1f7352088
--- /dev/null
+++ b/chromium/ui/ozone/platform/caca/ozone_platform_caca.h
@@ -0,0 +1,17 @@
+// 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_OZONE_PLATFORM_CACA_OZONE_PLATFORM_CACA_H_
+#define UI_OZONE_PLATFORM_CACA_OZONE_PLATFORM_CACA_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformCaca();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CACA_OZONE_PLATFORM_CACA_H_
diff --git a/chromium/ui/ozone/platform/dri/DEPS b/chromium/ui/ozone/platform/dri/DEPS
new file mode 100644
index 00000000000..ee54c22bef5
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+skia/ext",
+ "+third_party/skia",
+]
diff --git a/chromium/ui/ozone/platform/dri/OWNERS b/chromium/ui/ozone/platform/dri/OWNERS
new file mode 100644
index 00000000000..0d77c0eae94
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/OWNERS
@@ -0,0 +1 @@
+dnicoara@chromium.org
diff --git a/chromium/ui/ozone/platform/dri/buffer_data.cc b/chromium/ui/ozone/platform/dri/buffer_data.cc
new file mode 100644
index 00000000000..a2ea1b38cc2
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/buffer_data.cc
@@ -0,0 +1,71 @@
+// 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/ozone/platform/dri/buffer_data.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+// Pixel configuration for the current buffer format.
+// TODO(dnicoara) These will need to change once we query the hardware for
+// supported configurations.
+const uint8_t kColorDepth = 24;
+const uint8_t kPixelDepth = 32;
+
+BufferData::BufferData(DriWrapper* dri, gbm_bo* buffer)
+ : dri_(dri),
+ handle_(gbm_bo_get_handle(buffer).u32),
+ framebuffer_(0) {
+ // Register the buffer with the controller. This will allow us to scan out the
+ // buffer once we're done drawing into it. If we can't register the buffer
+ // then there's no point in having BufferData associated with it.
+ if (!dri_->AddFramebuffer(gbm_bo_get_width(buffer),
+ gbm_bo_get_height(buffer),
+ kColorDepth,
+ kPixelDepth,
+ gbm_bo_get_stride(buffer),
+ handle_,
+ &framebuffer_)) {
+ LOG(ERROR) << "Failed to register buffer";
+ }
+}
+
+BufferData::~BufferData() {
+ if (framebuffer_)
+ dri_->RemoveFramebuffer(framebuffer_);
+}
+
+// static
+BufferData* BufferData::CreateData(DriWrapper* dri,
+ gbm_bo* buffer) {
+ BufferData* data = new BufferData(dri, buffer);
+ if (!data->framebuffer()) {
+ delete data;
+ return NULL;
+ }
+
+ // GBM can destroy the buffers at any time as long as they aren't locked. This
+ // sets a callback such that we can clean up all our state when GBM destroys
+ // the buffer.
+ gbm_bo_set_user_data(buffer, data, BufferData::Destroy);
+
+ return data;
+}
+
+// static
+void BufferData::Destroy(gbm_bo* buffer, void* data) {
+ BufferData* bd = static_cast<BufferData*>(data);
+ delete bd;
+}
+
+// static
+BufferData* BufferData::GetData(gbm_bo* buffer) {
+ return static_cast<BufferData*>(gbm_bo_get_user_data(buffer));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/buffer_data.h b/chromium/ui/ozone/platform/dri/buffer_data.h
new file mode 100644
index 00000000000..2f3422d38bc
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/buffer_data.h
@@ -0,0 +1,53 @@
+// 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_OZONE_PLATFORM_DRI_BUFFER_DATA_H_
+#define UI_OZONE_PLATFORM_DRI_BUFFER_DATA_H_
+
+#include "base/memory/scoped_ptr.h"
+
+struct gbm_bo;
+
+namespace ui {
+
+class DriWrapper;
+
+// This class is used to tag a gbm buffer with custom information needed
+// for presentation with the surface factory.
+class BufferData {
+ public:
+ // When we create the BufferData we need to register the buffer. Once
+ // successfully registered, the |framebuffer_| field will hold the ID of the
+ // buffer. The controller will use this ID when scanning out the buffer. On
+ // creation we will also associate the BufferData with the buffer.
+ static BufferData* CreateData(DriWrapper* dri, gbm_bo* buffer);
+
+ // Callback used by GBM to destroy the BufferData associated with a buffer.
+ static void Destroy(gbm_bo* buffer, void* data);
+
+ // Returns the BufferData associated with |buffer|. NULL if no data is
+ // associated.
+ static BufferData* GetData(gbm_bo* buffer);
+
+ uint32_t framebuffer() const { return framebuffer_; }
+ uint32_t handle() const { return handle_; }
+
+ private:
+ BufferData(DriWrapper* dri, gbm_bo* buffer);
+ ~BufferData();
+
+ DriWrapper* dri_;
+
+ uint32_t handle_;
+
+ // ID provided by the controller when the buffer is registered. This ID is
+ // used when scanning out the buffer.
+ uint32_t framebuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferData);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_BUFFER_DATA_H_
diff --git a/chromium/ui/ozone/platform/dri/chromeos/DEPS b/chromium/ui/ozone/platform/dri/chromeos/DEPS
new file mode 100644
index 00000000000..0ab14717d97
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/display/util",
+]
diff --git a/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.cc b/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.cc
new file mode 100644
index 00000000000..707cb91b7c2
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.cc
@@ -0,0 +1,17 @@
+// 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/ozone/platform/dri/chromeos/display_mode_dri.h"
+
+namespace ui {
+
+DisplayModeDri::DisplayModeDri(const drmModeModeInfo& mode)
+ : DisplayMode(gfx::Size(mode.hdisplay, mode.vdisplay),
+ mode.flags & DRM_MODE_FLAG_INTERLACE,
+ mode.vrefresh),
+ mode_info_(mode) {}
+
+DisplayModeDri::~DisplayModeDri() {}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.h b/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.h
new file mode 100644
index 00000000000..ab50df28d77
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/display_mode_dri.h
@@ -0,0 +1,33 @@
+// 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_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_MODE_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_MODE_DRI_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+
+#include "ui/display/types/chromeos/display_mode.h"
+
+namespace ui {
+
+class DisplayModeDri : public DisplayMode {
+ public:
+ DisplayModeDri(const drmModeModeInfo& mode);
+ virtual ~DisplayModeDri();
+
+ // Native details about this mode. Only used internally in the DRI
+ // implementation.
+ drmModeModeInfo mode_info() const { return mode_info_; }
+
+ private:
+ drmModeModeInfo mode_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayModeDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_MODE_DRI_H_
diff --git a/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.cc b/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.cc
new file mode 100644
index 00000000000..b14c590376a
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.cc
@@ -0,0 +1,127 @@
+// 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/ozone/platform/dri/chromeos/display_snapshot_dri.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/display/util/edid_parser.h"
+#include "ui/ozone/platform/dri/chromeos/display_mode_dri.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+namespace {
+
+DisplayConnectionType GetDisplayType(drmModeConnector* connector) {
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ return DISPLAY_CONNECTION_TYPE_VGA;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_DVIA:
+ return DISPLAY_CONNECTION_TYPE_DVI;
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ return DISPLAY_CONNECTION_TYPE_INTERNAL;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ return DISPLAY_CONNECTION_TYPE_DISPLAYPORT;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ return DISPLAY_CONNECTION_TYPE_HDMI;
+ default:
+ return DISPLAY_CONNECTION_TYPE_UNKNOWN;
+ }
+}
+
+bool IsAspectPreserving(DriWrapper* drm, drmModeConnector* connector) {
+ drmModePropertyRes* property = drm->GetProperty(connector, "scaling mode");
+ if (property) {
+ for (int j = 0; j < property->count_enums; ++j) {
+ if (property->enums[j].value ==
+ connector->prop_values[property->prop_id] &&
+ strcmp(property->enums[j].name, "Full aspect") == 0) {
+ drm->FreeProperty(property);
+ return true;
+ }
+ }
+
+ drm->FreeProperty(property);
+ }
+
+ return false;
+}
+
+} // namespace
+
+DisplaySnapshotDri::DisplaySnapshotDri(
+ DriWrapper* drm,
+ drmModeConnector* connector,
+ drmModeCrtc* crtc,
+ uint32_t index)
+ : DisplaySnapshot(index,
+ false,
+ gfx::Point(crtc->x, crtc->y),
+ gfx::Size(connector->mmWidth, connector->mmHeight),
+ GetDisplayType(connector),
+ IsAspectPreserving(drm, connector),
+ false,
+ std::string(),
+ std::vector<const DisplayMode*>(),
+ NULL,
+ NULL),
+ connector_(connector->connector_id),
+ crtc_(crtc->crtc_id),
+ dpms_property_(drm->GetProperty(connector, "DPMS")) {
+ drmModePropertyBlobRes* edid_blob = drm->GetPropertyBlob(connector, "EDID");
+
+ if (edid_blob) {
+ std::vector<uint8_t> edid(
+ static_cast<uint8_t*>(edid_blob->data),
+ static_cast<uint8_t*>(edid_blob->data) + edid_blob->length);
+
+ has_proper_display_id_ = GetDisplayIdFromEDID(edid, index, &display_id_);
+ ParseOutputDeviceData(edid, NULL, &display_name_);
+ ParseOutputOverscanFlag(edid, &overscan_flag_);
+
+ drm->FreePropertyBlob(edid_blob);
+ } else {
+ VLOG(1) << "Failed to get EDID blob for connector "
+ << connector->connector_id;
+ }
+
+ for (int i = 0; i < connector->count_modes; ++i) {
+ drmModeModeInfo& mode = connector->modes[i];
+ modes_.push_back(new DisplayModeDri(mode));
+
+ if (crtc->mode_valid && SameMode(crtc->mode, mode))
+ current_mode_ = modes_.back();
+
+ if (mode.type & DRM_MODE_TYPE_PREFERRED)
+ native_mode_ = modes_.back();
+ }
+}
+
+DisplaySnapshotDri::~DisplaySnapshotDri() {
+ if (dpms_property_)
+ drmModeFreeProperty(dpms_property_);
+}
+
+std::string DisplaySnapshotDri::ToString() const {
+ return base::StringPrintf(
+ "[type=%d, connector=%" PRIu32 ", crtc=%" PRIu32 ", mode=%s, dim=%s]",
+ type_,
+ connector_,
+ crtc_,
+ current_mode_ ? current_mode_->ToString().c_str() : "NULL",
+ physical_size_.ToString().c_str());
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.h b/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.h
new file mode 100644
index 00000000000..1f69af47ed9
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/display_snapshot_dri.h
@@ -0,0 +1,47 @@
+// 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_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_SNAPSHOT_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_SNAPSHOT_DRI_H_
+
+#include "ui/display/types/chromeos/display_snapshot.h"
+
+typedef struct _drmModeConnector drmModeConnector;
+typedef struct _drmModeCrtc drmModeCrtc;
+typedef struct _drmModeProperty drmModePropertyRes;
+
+namespace ui {
+
+class DriWrapper;
+
+class DisplaySnapshotDri : public DisplaySnapshot {
+ public:
+ DisplaySnapshotDri(DriWrapper* drm,
+ drmModeConnector* connector,
+ drmModeCrtc* crtc,
+ uint32_t index);
+ virtual ~DisplaySnapshotDri();
+
+ // Native properties of a display used by the DRI implementation in
+ // configuring this display.
+ uint32_t connector() const { return connector_; }
+ uint32_t crtc() const { return crtc_; }
+ drmModePropertyRes* dpms_property() const { return dpms_property_; }
+
+ // DisplaySnapshot overrides:
+ virtual std::string ToString() const OVERRIDE;
+
+ private:
+ uint32_t connector_;
+ uint32_t crtc_;
+ drmModePropertyRes* dpms_property_;
+ std::string name_;
+ bool overscan_flag_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplaySnapshotDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_CHROMEOS_DISPLAY_SNAPSHOT_DRI_H_
diff --git a/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.cc b/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.cc
new file mode 100644
index 00000000000..66a5cf3136a
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.cc
@@ -0,0 +1,189 @@
+// 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/ozone/platform/dri/chromeos/native_display_delegate_dri.h"
+
+#include "base/bind.h"
+#include "ui/display/types/chromeos/native_display_observer.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/platform/dri/chromeos/display_mode_dri.h"
+#include "ui/ozone/platform/dri/chromeos/display_snapshot_dri.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+
+namespace ui {
+
+namespace {
+const size_t kMaxDisplayCount = 2;
+} // namespace
+
+NativeDisplayDelegateDri::NativeDisplayDelegateDri(
+ DriWrapper* dri,
+ ScreenManager* screen_manager,
+ DeviceManager* device_manager)
+ : dri_(dri),
+ screen_manager_(screen_manager),
+ device_manager_(device_manager) {
+}
+
+NativeDisplayDelegateDri::~NativeDisplayDelegateDri() {
+ device_manager_->RemoveObserver(this);
+}
+
+void NativeDisplayDelegateDri::Initialize() {
+ device_manager_->AddObserver(this);
+}
+
+void NativeDisplayDelegateDri::GrabServer() {}
+
+void NativeDisplayDelegateDri::UngrabServer() {}
+
+void NativeDisplayDelegateDri::SyncWithServer() {}
+
+void NativeDisplayDelegateDri::SetBackgroundColor(uint32_t color_argb) {
+ NOTIMPLEMENTED();
+}
+
+void NativeDisplayDelegateDri::ForceDPMSOn() {
+ for (size_t i = 0; i < cached_displays_.size(); ++i) {
+ DisplaySnapshotDri* dri_output = cached_displays_[i];
+ if (dri_output->dpms_property())
+ dri_->SetProperty(dri_output->connector(),
+ dri_output->dpms_property()->prop_id,
+ DRM_MODE_DPMS_ON);
+ }
+}
+
+std::vector<DisplaySnapshot*> NativeDisplayDelegateDri::GetDisplays() {
+ ScopedVector<DisplaySnapshotDri> old_displays(cached_displays_.Pass());
+ cached_modes_.clear();
+
+ drmModeRes* resources = drmModeGetResources(dri_->get_fd());
+ DCHECK(resources) << "Failed to get DRM resources";
+ ScopedVector<HardwareDisplayControllerInfo> displays =
+ GetAvailableDisplayControllerInfos(dri_->get_fd(), resources);
+ for (size_t i = 0;
+ i < displays.size() && cached_displays_.size() < kMaxDisplayCount; ++i) {
+ DisplaySnapshotDri* display = new DisplaySnapshotDri(
+ dri_, displays[i]->connector(), displays[i]->crtc(), i);
+ cached_displays_.push_back(display);
+ // Modes can be shared between different displays, so we need to keep track
+ // of them independently for cleanup.
+ cached_modes_.insert(cached_modes_.end(),
+ display->modes().begin(),
+ display->modes().end());
+ }
+
+ drmModeFreeResources(resources);
+
+ NotifyScreenManager(cached_displays_.get(), old_displays.get());
+
+ std::vector<DisplaySnapshot*> generic_displays(cached_displays_.begin(),
+ cached_displays_.end());
+ return generic_displays;
+}
+
+void NativeDisplayDelegateDri::AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) {}
+
+bool NativeDisplayDelegateDri::Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) {
+ const DisplaySnapshotDri& dri_output =
+ static_cast<const DisplaySnapshotDri&>(output);
+
+ VLOG(1) << "DRM configuring: crtc=" << dri_output.crtc()
+ << " connector=" << dri_output.connector()
+ << " origin=" << origin.ToString()
+ << " size=" << (mode ? mode->size().ToString() : "0x0");
+
+ if (mode) {
+ if (!screen_manager_->ConfigureDisplayController(
+ dri_output.crtc(),
+ dri_output.connector(),
+ static_cast<const DisplayModeDri*>(mode)->mode_info())) {
+ VLOG(1) << "Failed to configure: crtc=" << dri_output.crtc()
+ << " connector=" << dri_output.connector();
+ return false;
+ }
+ } else {
+ if (!screen_manager_->DisableDisplayController(dri_output.crtc(),
+ dri_output.connector())) {
+ VLOG(1) << "Failed to disable crtc=" << dri_output.crtc();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void NativeDisplayDelegateDri::CreateFrameBuffer(const gfx::Size& size) {}
+
+bool NativeDisplayDelegateDri::GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool NativeDisplayDelegateDri::SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+std::vector<ui::ColorCalibrationProfile>
+NativeDisplayDelegateDri::GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) {
+ NOTIMPLEMENTED();
+ return std::vector<ui::ColorCalibrationProfile>();
+}
+
+bool NativeDisplayDelegateDri::SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeDisplayDelegateDri::AddObserver(NativeDisplayObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void NativeDisplayDelegateDri::RemoveObserver(NativeDisplayObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void NativeDisplayDelegateDri::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::DISPLAY)
+ return;
+
+ if (event.action_type() == DeviceEvent::CHANGE) {
+ VLOG(1) << "Got display changed event";
+ FOR_EACH_OBSERVER(
+ NativeDisplayObserver, observers_, OnConfigurationChanged());
+ }
+}
+
+void NativeDisplayDelegateDri::NotifyScreenManager(
+ const std::vector<DisplaySnapshotDri*>& new_displays,
+ const std::vector<DisplaySnapshotDri*>& old_displays) const {
+ for (size_t i = 0; i < old_displays.size(); ++i) {
+ bool found = false;
+ for (size_t j = 0; j < new_displays.size(); ++j) {
+ if (old_displays[i]->connector() == new_displays[j]->connector() &&
+ old_displays[i]->crtc() == new_displays[j]->crtc()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ screen_manager_->RemoveDisplayController(old_displays[i]->crtc(),
+ old_displays[i]->connector());
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h b/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h
new file mode 100644
index 00000000000..a48d1a5bc8e
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/chromeos/native_display_delegate_dri.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_OZONE_PLATFORM_DRI_CHROMEOS_NATIVE_DISPLAY_DELEGATE_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_CHROMEOS_NATIVE_DISPLAY_DELEGATE_DRI_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/display/types/chromeos/native_display_delegate.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+
+namespace ui {
+
+class DeviceManager;
+class DisplaySnapshotDri;
+class DriWrapper;
+class ScreenManager;
+
+class NativeDisplayDelegateDri
+ : public NativeDisplayDelegate, DeviceEventObserver {
+ public:
+ NativeDisplayDelegateDri(DriWrapper* dri,
+ ScreenManager* screen_manager,
+ DeviceManager* device_manager);
+ virtual ~NativeDisplayDelegateDri();
+
+ // NativeDisplayDelegate overrides:
+ virtual void Initialize() OVERRIDE;
+ virtual void GrabServer() OVERRIDE;
+ virtual void UngrabServer() OVERRIDE;
+ virtual void SyncWithServer() OVERRIDE;
+ virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE;
+ virtual void ForceDPMSOn() OVERRIDE;
+ virtual std::vector<DisplaySnapshot*> GetDisplays() OVERRIDE;
+ virtual void AddMode(const DisplaySnapshot& output,
+ const DisplayMode* mode) OVERRIDE;
+ virtual bool Configure(const DisplaySnapshot& output,
+ const DisplayMode* mode,
+ const gfx::Point& origin) OVERRIDE;
+ virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE;
+ virtual bool GetHDCPState(const DisplaySnapshot& output,
+ HDCPState* state) OVERRIDE;
+ virtual bool SetHDCPState(const DisplaySnapshot& output,
+ HDCPState state) OVERRIDE;
+ virtual std::vector<ui::ColorCalibrationProfile>
+ GetAvailableColorCalibrationProfiles(
+ const ui::DisplaySnapshot& output) OVERRIDE;
+ virtual bool SetColorCalibrationProfile(
+ const ui::DisplaySnapshot& output,
+ ui::ColorCalibrationProfile new_profile) OVERRIDE;
+ virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE;
+
+ // DeviceEventObserver overrides:
+ virtual void OnDeviceEvent(const DeviceEvent& event) OVERRIDE;
+
+ private:
+ // Notify ScreenManager of all the displays that were present before the
+ // update but are gone after the update.
+ void NotifyScreenManager(
+ const std::vector<DisplaySnapshotDri*>& new_displays,
+ const std::vector<DisplaySnapshotDri*>& old_displays) const;
+
+ DriWrapper* dri_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+ DeviceManager* device_manager_; // Not owned.
+ ScopedVector<const DisplayMode> cached_modes_;
+ ScopedVector<DisplaySnapshotDri> cached_displays_;
+ ObserverList<NativeDisplayObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeDisplayDelegateDri);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_CHROMEOS_NATIVE_DISPLAY_DELEGATE_DRI_H_
diff --git a/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.cc b/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.cc
new file mode 100644
index 00000000000..d03aac1e53c
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.cc
@@ -0,0 +1,67 @@
+// 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/ozone/platform/dri/cursor_factory_evdev_dri.h"
+
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+
+namespace ui {
+
+CursorFactoryEvdevDri::CursorFactoryEvdevDri(DriSurfaceFactory* dri)
+ : dri_(dri) {
+ // TODO(dnicoara) Assume the first widget since at this point there are no
+ // widgets initialized.
+ cursor_window_ = DriSurfaceFactory::kDefaultWidgetHandle;
+ cursor_location_ = gfx::PointF(2560 / 2, 1700 / 2); // TODO(spang): Argh!
+}
+
+CursorFactoryEvdevDri::~CursorFactoryEvdevDri() {}
+
+void CursorFactoryEvdevDri::SetBitmapCursor(
+ gfx::AcceleratedWidget widget,
+ scoped_refptr<BitmapCursorOzone> cursor) {
+ if (cursor_ == cursor)
+ return;
+
+ cursor_ = cursor;
+ if (cursor_)
+ dri_->SetHardwareCursor(
+ cursor_window_, cursor_->bitmap(), bitmap_location());
+ else
+ dri_->UnsetHardwareCursor(cursor_window_);
+}
+
+void CursorFactoryEvdevDri::MoveCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) {
+ if (widget != cursor_window_)
+ dri_->UnsetHardwareCursor(cursor_window_);
+
+ cursor_window_ = widget;
+ cursor_location_ = location;
+
+ gfx::Size size = dri_->GetWidgetSize(cursor_window_);
+ cursor_location_.SetToMax(gfx::PointF(0, 0));
+ cursor_location_.SetToMin(gfx::PointF(size.width(), size.height()));
+
+ if (cursor_)
+ dri_->MoveHardwareCursor(cursor_window_, bitmap_location());
+}
+
+void CursorFactoryEvdevDri::MoveCursor(const gfx::Vector2dF& delta) {
+ MoveCursorTo(cursor_window_, cursor_location_ + delta);
+}
+
+gfx::AcceleratedWidget CursorFactoryEvdevDri::GetCursorWindow() {
+ return cursor_window_;
+}
+
+gfx::PointF CursorFactoryEvdevDri::location() { return cursor_location_; }
+
+gfx::Point CursorFactoryEvdevDri::bitmap_location() {
+ return gfx::ToFlooredPoint(cursor_location_) -
+ cursor_->hotspot().OffsetFromOrigin();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.h b/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.h
new file mode 100644
index 00000000000..da132199668
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/cursor_factory_evdev_dri.h
@@ -0,0 +1,58 @@
+// 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_OZONE_PLATFORM_DRI_CURSOR_FACTORY_EVDEV_DRI_H_
+#define UI_OZONE_PLATFORM_DRI_CURSOR_FACTORY_EVDEV_DRI_H_
+
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+class DriSurfaceFactory;
+}
+
+namespace ui {
+
+class CursorFactoryEvdevDri : public BitmapCursorFactoryOzone,
+ public CursorDelegateEvdev {
+ public:
+ CursorFactoryEvdevDri(DriSurfaceFactory* dri);
+ virtual ~CursorFactoryEvdevDri();
+
+ // BitmapCursorFactoryOzone:
+ virtual gfx::AcceleratedWidget GetCursorWindow() OVERRIDE;
+ virtual void SetBitmapCursor(gfx::AcceleratedWidget widget,
+ scoped_refptr<BitmapCursorOzone> cursor)
+ OVERRIDE;
+
+ // CursorDelegateEvdev:
+ virtual void MoveCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) OVERRIDE;
+ virtual void MoveCursor(const gfx::Vector2dF& delta) OVERRIDE;
+ virtual gfx::PointF location() OVERRIDE;
+
+ private:
+ // The location of the bitmap (the cursor location is the hotspot location).
+ gfx::Point bitmap_location();
+
+ // The DRI implementation for setting the hardware cursor.
+ DriSurfaceFactory* dri_;
+
+ // The current cursor bitmap.
+ scoped_refptr<BitmapCursorOzone> cursor_;
+
+ // The window under the cursor.
+ gfx::AcceleratedWidget cursor_window_;
+
+ // The location of the cursor within the window.
+ gfx::PointF cursor_location_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_CURSOR_FACTORY_EVDEV_DRI_H_
diff --git a/chromium/ui/ozone/platform/dri/dri.gypi b/chromium/ui/ozone/platform/dri/dri.gypi
new file mode 100644
index 00000000000..3e10ca7b8bc
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri.gypi
@@ -0,0 +1,97 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_dri',
+ ],
+ 'internal_ozone_platform_unittest_deps': [
+ 'ozone_platform_dri_unittests',
+ ],
+ 'internal_ozone_platforms': [
+ 'dri',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_dri',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../build/linux/system.gyp:dridrm',
+ '../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
+ '../display/display.gyp:display_types',
+ '../display/display.gyp:display_util',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone_evdev',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'chromeos/display_mode_dri.cc',
+ 'chromeos/display_mode_dri.h',
+ 'chromeos/display_snapshot_dri.cc',
+ 'chromeos/display_snapshot_dri.h',
+ 'chromeos/native_display_delegate_dri.cc',
+ 'chromeos/native_display_delegate_dri.h',
+ 'cursor_factory_evdev_dri.cc',
+ 'cursor_factory_evdev_dri.h',
+ 'dri_buffer.cc',
+ 'dri_buffer.h',
+ 'dri_surface.cc',
+ 'dri_surface.h',
+ 'dri_surface_factory.cc',
+ 'dri_surface_factory.h',
+ 'dri_util.cc',
+ 'dri_util.h',
+ 'dri_vsync_provider.cc',
+ 'dri_vsync_provider.h',
+ 'dri_wrapper.cc',
+ 'dri_wrapper.h',
+ 'hardware_display_controller.cc',
+ 'hardware_display_controller.h',
+ 'ozone_platform_dri.cc',
+ 'ozone_platform_dri.h',
+ 'screen_manager.cc',
+ 'screen_manager.h',
+ 'scanout_surface.h',
+ 'virtual_terminal_manager.cc',
+ 'virtual_terminal_manager.h',
+ ],
+ },
+ {
+ 'target_name': 'ozone_platform_dri_unittests',
+ 'type': 'none',
+ 'dependencies': [
+ '../../build/linux/system.gyp:dridrm',
+ '../../skia/skia.gyp:skia',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'export_dependent_settings': [
+ '../../build/linux/system.gyp:dridrm',
+ '../../skia/skia.gyp:skia',
+ '../gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'direct_dependent_settings': {
+ 'sources': [
+ 'dri_surface_factory_unittest.cc',
+ 'dri_surface_unittest.cc',
+ 'hardware_display_controller_unittest.cc',
+ 'screen_manager_unittest.cc',
+ 'test/mock_dri_surface.cc',
+ 'test/mock_dri_surface.h',
+ 'test/mock_dri_wrapper.cc',
+ 'test/mock_dri_wrapper.h',
+ 'test/mock_surface_generator.cc',
+ 'test/mock_surface_generator.h',
+ ],
+ },
+ },
+ ],
+}
diff --git a/chromium/ui/ozone/platform/dri/dri_buffer.cc b/chromium/ui/ozone/platform/dri/dri_buffer.cc
new file mode 100644
index 00000000000..f3dc1b903f3
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_buffer.cc
@@ -0,0 +1,140 @@
+// 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/ozone/platform/dri/dri_buffer.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+namespace {
+
+// Modesetting cannot happen from a buffer with transparencies. Return the size
+// of a pixel without alpha.
+uint8_t GetColorDepth(SkColorType type) {
+ switch (type) {
+ case kUnknown_SkColorType:
+ case kAlpha_8_SkColorType:
+ return 0;
+ case kIndex_8_SkColorType:
+ return 8;
+ case kRGB_565_SkColorType:
+ return 16;
+ case kARGB_4444_SkColorType:
+ return 12;
+ case kPMColor_SkColorType:
+ return 24;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+void DestroyDumbBuffer(int fd, uint32_t handle) {
+ struct drm_mode_destroy_dumb destroy_request;
+ destroy_request.handle = handle;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+}
+
+bool CreateDumbBuffer(DriWrapper* dri,
+ const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels) {
+ struct drm_mode_create_dumb request;
+ request.width = info.width();
+ request.height = info.height();
+ request.bpp = info.bytesPerPixel() << 3;
+ request.flags = 0;
+
+ if (drmIoctl(dri->get_fd(), DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
+ DLOG(ERROR) << "Cannot create dumb buffer (" << errno << ") "
+ << strerror(errno);
+ return false;
+ }
+
+ *handle = request.handle;
+ *stride = request.pitch;
+
+ struct drm_mode_map_dumb map_request;
+ map_request.handle = request.handle;
+ if (drmIoctl(dri->get_fd(), DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
+ DLOG(ERROR) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
+ << strerror(errno);
+ DestroyDumbBuffer(dri->get_fd(), request.handle);
+ return false;
+ }
+
+ *pixels = mmap(0,
+ request.size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ dri->get_fd(),
+ map_request.offset);
+ if (*pixels == MAP_FAILED) {
+ DLOG(ERROR) << "Cannot mmap dumb buffer (" << errno << ") "
+ << strerror(errno);
+ DestroyDumbBuffer(dri->get_fd(), request.handle);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+DriBuffer::DriBuffer(DriWrapper* dri)
+ : dri_(dri), handle_(0), framebuffer_(0) {}
+
+DriBuffer::~DriBuffer() {
+ if (!surface_)
+ return;
+
+ if (framebuffer_)
+ dri_->RemoveFramebuffer(framebuffer_);
+
+ SkImageInfo info;
+ void* pixels = const_cast<void*>(surface_->peekPixels(&info, NULL));
+ if (!pixels)
+ return;
+
+ munmap(pixels, info.getSafeSize(stride_));
+ DestroyDumbBuffer(dri_->get_fd(), handle_);
+}
+
+bool DriBuffer::Initialize(const SkImageInfo& info) {
+ void* pixels = NULL;
+ if (!CreateDumbBuffer(dri_, info, &handle_, &stride_, &pixels)) {
+ DLOG(ERROR) << "Cannot allocate drm dumb buffer";
+ return false;
+ }
+
+ if (!dri_->AddFramebuffer(info.width(),
+ info.height(),
+ GetColorDepth(info.colorType()),
+ info.bytesPerPixel() << 3,
+ stride_,
+ handle_,
+ &framebuffer_)) {
+ DLOG(ERROR) << "Failed to register framebuffer: " << strerror(errno);
+ return false;
+ }
+
+ surface_ = skia::AdoptRef(SkSurface::NewRasterDirect(info, pixels, stride_));
+ if (!surface_) {
+ DLOG(ERROR) << "Cannot install Skia pixels for drm buffer";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_buffer.h b/chromium/ui/ozone/platform/dri/dri_buffer.h
new file mode 100644
index 00000000000..abed28e0039
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_buffer.h
@@ -0,0 +1,57 @@
+// 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_OZONE_PLATFORM_DRI_DRI_BUFFER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_BUFFER_H_
+
+#include "base/macros.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/ozone_export.h"
+
+class SkCanvas;
+
+namespace ui {
+
+class DriWrapper;
+
+// Wrapper for a DRM allocated buffer. Keeps track of the native properties of
+// the buffer and wraps the pixel memory into a SkSurface which can be used to
+// draw into using Skia.
+class OZONE_EXPORT DriBuffer {
+ public:
+ DriBuffer(DriWrapper* dri);
+ virtual ~DriBuffer();
+
+ uint32_t stride() const { return stride_; }
+ uint32_t handle() const { return handle_; }
+ uint32_t framebuffer() const { return framebuffer_; }
+ SkCanvas* canvas() { return surface_->getCanvas(); }
+
+ // Allocates the backing pixels and wraps them in |surface_|. |info| is used
+ // to describe the buffer characteristics (size, color format).
+ virtual bool Initialize(const SkImageInfo& info);
+
+ protected:
+ DriWrapper* dri_; // Not owned.
+
+ // Wrapper around the native pixel memory.
+ skia::RefPtr<SkSurface> surface_;
+
+ // Length of a row of pixels.
+ uint32_t stride_;
+
+ // Buffer handle used by the DRM allocator.
+ uint32_t handle_;
+
+ // Buffer ID used by the DRM modesettings API. This is set when the buffer is
+ // registered with the CRTC.
+ uint32_t framebuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriBuffer);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_BUFFER_H_
diff --git a/chromium/ui/ozone/platform/dri/dri_surface.cc b/chromium/ui/ozone/platform/dri/dri_surface.cc
new file mode 100644
index 00000000000..d6b4f5996b2
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface.cc
@@ -0,0 +1,80 @@
+// 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/ozone/platform/dri/dri_surface.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+DriSurface::DriSurface(
+ DriWrapper* dri, const gfx::Size& size)
+ : dri_(dri),
+ bitmaps_(),
+ front_buffer_(0),
+ size_(size) {
+}
+
+DriSurface::~DriSurface() {
+}
+
+bool DriSurface::Initialize() {
+ for (size_t i = 0; i < arraysize(bitmaps_); ++i) {
+ bitmaps_[i].reset(CreateBuffer());
+ // TODO(dnicoara) Should select the configuration based on what the
+ // underlying system supports.
+ SkImageInfo info = SkImageInfo::Make(size_.width(),
+ size_.height(),
+ kPMColor_SkColorType,
+ kPremul_SkAlphaType);
+ if (!bitmaps_[i]->Initialize(info)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uint32_t DriSurface::GetFramebufferId() const {
+ CHECK(backbuffer());
+ return backbuffer()->framebuffer();
+}
+
+uint32_t DriSurface::GetHandle() const {
+ CHECK(backbuffer());
+ return backbuffer()->handle();
+}
+
+// This call is made after the hardware just started displaying our back buffer.
+// We need to update our pointer reference and synchronize the two buffers.
+void DriSurface::SwapBuffers() {
+ CHECK(frontbuffer());
+ CHECK(backbuffer());
+
+ // Update our front buffer pointer.
+ front_buffer_ ^= 1;
+}
+
+gfx::Size DriSurface::Size() const {
+ return size_;
+}
+
+SkCanvas* DriSurface::GetDrawableForWidget() {
+ CHECK(backbuffer());
+ return backbuffer()->canvas();
+}
+
+DriBuffer* DriSurface::CreateBuffer() { return new DriBuffer(dri_); }
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_surface.h b/chromium/ui/ozone/platform/dri/dri_surface.h
new file mode 100644
index 00000000000..2abae45811e
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface.h
@@ -0,0 +1,64 @@
+// 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_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+
+class SkCanvas;
+
+namespace ui {
+
+class DriBuffer;
+class DriWrapper;
+
+// An implementation of ScanoutSurface which uses dumb buffers (used for
+// software rendering).
+class OZONE_EXPORT DriSurface : public ScanoutSurface {
+ public:
+ DriSurface(DriWrapper* dri, const gfx::Size& size);
+ virtual ~DriSurface();
+
+ // Get a Skia canvas for a backbuffer.
+ SkCanvas* GetDrawableForWidget();
+
+ // ScanoutSurface:
+ virtual bool Initialize() OVERRIDE;
+ virtual uint32_t GetFramebufferId() const OVERRIDE;
+ virtual uint32_t GetHandle() const OVERRIDE;
+ virtual void SwapBuffers() OVERRIDE;
+ virtual gfx::Size Size() const OVERRIDE;
+
+ private:
+ DriBuffer* frontbuffer() const { return bitmaps_[front_buffer_].get(); }
+ DriBuffer* backbuffer() const { return bitmaps_[front_buffer_ ^ 1].get(); }
+
+ // Used to create the backing buffers.
+ virtual DriBuffer* CreateBuffer();
+
+ // Stores the connection to the graphics card. Pointer not owned by this
+ // class.
+ DriWrapper* dri_;
+
+ // The actual buffers used for painting.
+ scoped_ptr<DriBuffer> bitmaps_[2];
+
+ // Keeps track of which bitmap is |buffers_| is the frontbuffer.
+ int front_buffer_;
+
+ // Surface size.
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_SURFACE_H_
diff --git a/chromium/ui/ozone/platform/dri/dri_surface_factory.cc b/chromium/ui/ozone/platform/dri/dri_surface_factory.cc
new file mode 100644
index 00000000000..bbfb6e2e8ff
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface_factory.cc
@@ -0,0 +1,252 @@
+// 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/ozone/platform/dri/dri_surface_factory.h"
+
+#include <errno.h>
+
+#include "base/debug/trace_event.h"
+#include "base/message_loop/message_loop.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/dri_vsync_provider.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+// TODO(dnicoara) Read the cursor plane size from the hardware.
+const gfx::Size kCursorSize(64, 64);
+
+void UpdateCursorImage(DriSurface* cursor, const SkBitmap& image) {
+ SkRect damage;
+ image.getBounds(&damage);
+
+ // Clear to transparent in case |image| is smaller than the canvas.
+ SkCanvas* canvas = cursor->GetDrawableForWidget();
+ canvas->clear(SK_ColorTRANSPARENT);
+
+ SkRect clip;
+ clip.set(
+ 0, 0, canvas->getDeviceSize().width(), canvas->getDeviceSize().height());
+ canvas->clipRect(clip, SkRegion::kReplace_Op);
+ canvas->drawBitmapRectToRect(image, &damage, damage);
+}
+
+class DriSurfaceAdapter : public ui::SurfaceOzoneCanvas {
+ public:
+ DriSurfaceAdapter(const base::WeakPtr<HardwareDisplayController>& controller);
+ virtual ~DriSurfaceAdapter();
+
+ // SurfaceOzoneCanvas:
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE;
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE;
+ virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ private:
+ void UpdateNativeSurface(const gfx::Rect& damage);
+
+ skia::RefPtr<SkSurface> surface_;
+ gfx::Rect last_damage_;
+ base::WeakPtr<HardwareDisplayController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceAdapter);
+};
+
+DriSurfaceAdapter::DriSurfaceAdapter(
+ const base::WeakPtr<HardwareDisplayController>& controller)
+ : controller_(controller) {
+}
+
+DriSurfaceAdapter::~DriSurfaceAdapter() {
+}
+
+skia::RefPtr<SkCanvas> DriSurfaceAdapter::GetCanvas() {
+ return skia::SharePtr(surface_->getCanvas());
+}
+
+void DriSurfaceAdapter::ResizeCanvas(const gfx::Size& viewport_size) {
+ SkImageInfo info = SkImageInfo::MakeN32(
+ viewport_size.width(), viewport_size.height(), kOpaque_SkAlphaType);
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
+}
+
+void DriSurfaceAdapter::PresentCanvas(const gfx::Rect& damage) {
+ CHECK(base::MessageLoopForUI::IsCurrent());
+ if (!controller_)
+ return;
+
+ UpdateNativeSurface(damage);
+ controller_->SchedulePageFlip();
+ controller_->WaitForPageFlipEvent();
+}
+
+scoped_ptr<gfx::VSyncProvider> DriSurfaceAdapter::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>(new DriVSyncProvider(controller_));
+}
+
+void DriSurfaceAdapter::UpdateNativeSurface(const gfx::Rect& damage) {
+ SkCanvas* canvas = static_cast<DriSurface*>(controller_->surface())
+ ->GetDrawableForWidget();
+
+ // The DriSurface is double buffered, so the current back buffer is
+ // missing the previous update. Expand damage region.
+ SkRect real_damage = RectToSkRect(UnionRects(damage, last_damage_));
+
+ // Copy damage region.
+ skia::RefPtr<SkImage> image = skia::AdoptRef(surface_->newImageSnapshot());
+ image->draw(canvas, &real_damage, real_damage, NULL);
+
+ last_damage_ = damage;
+}
+
+} // namespace
+
+// static
+const gfx::AcceleratedWidget DriSurfaceFactory::kDefaultWidgetHandle = 1;
+
+DriSurfaceFactory::DriSurfaceFactory(DriWrapper* drm,
+ ScreenManager* screen_manager)
+ : drm_(drm),
+ screen_manager_(screen_manager),
+ state_(UNINITIALIZED),
+ allocated_widgets_(0) {
+}
+
+DriSurfaceFactory::~DriSurfaceFactory() {
+ if (state_ == INITIALIZED)
+ ShutdownHardware();
+}
+
+ui::SurfaceFactoryOzone::HardwareState DriSurfaceFactory::InitializeHardware() {
+ if (state_ != UNINITIALIZED)
+ return state_;
+
+ if (drm_->get_fd() < 0) {
+ LOG(ERROR) << "Failed to create DRI connection";
+ state_ = FAILED;
+ return state_;
+ }
+
+ cursor_surface_.reset(CreateSurface(kCursorSize));
+ if (!cursor_surface_->Initialize()) {
+ LOG(ERROR) << "Failed to initialize cursor surface";
+ state_ = FAILED;
+ return state_;
+ }
+
+ state_ = INITIALIZED;
+ return state_;
+}
+
+void DriSurfaceFactory::ShutdownHardware() {
+ CHECK(state_ == INITIALIZED);
+ state_ = UNINITIALIZED;
+}
+
+gfx::AcceleratedWidget DriSurfaceFactory::GetAcceleratedWidget() {
+ CHECK(state_ != FAILED);
+
+ // We're not using 0 since other code assumes that a 0 AcceleratedWidget is an
+ // invalid widget.
+ return ++allocated_widgets_;
+}
+
+scoped_ptr<ui::SurfaceOzoneCanvas> DriSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) {
+ CHECK(state_ == INITIALIZED);
+ // Initial cursor set.
+ ResetCursor(w);
+
+ return scoped_ptr<ui::SurfaceOzoneCanvas>(
+ new DriSurfaceAdapter(screen_manager_->GetDisplayController(w)));
+}
+
+bool DriSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ return false;
+}
+
+gfx::Size DriSurfaceFactory::GetWidgetSize(gfx::AcceleratedWidget w) {
+ base::WeakPtr<HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(w);
+ if (controller)
+ return gfx::Size(controller->get_mode().hdisplay,
+ controller->get_mode().vdisplay);
+
+ return gfx::Size(0, 0);
+}
+
+void DriSurfaceFactory::SetHardwareCursor(gfx::AcceleratedWidget window,
+ const SkBitmap& image,
+ const gfx::Point& location) {
+ cursor_bitmap_ = image;
+ cursor_location_ = location;
+
+ if (state_ != INITIALIZED)
+ return;
+
+ ResetCursor(window);
+}
+
+void DriSurfaceFactory::MoveHardwareCursor(gfx::AcceleratedWidget window,
+ const gfx::Point& location) {
+ cursor_location_ = location;
+
+ if (state_ != INITIALIZED)
+ return;
+
+ base::WeakPtr<HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(window);
+ if (controller)
+ controller->MoveCursor(location);
+}
+
+void DriSurfaceFactory::UnsetHardwareCursor(gfx::AcceleratedWidget window) {
+ cursor_bitmap_.reset();
+
+ if (state_ != INITIALIZED)
+ return;
+
+ ResetCursor(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DriSurfaceFactory private
+
+DriSurface* DriSurfaceFactory::CreateSurface(const gfx::Size& size) {
+ return new DriSurface(drm_, size);
+}
+
+void DriSurfaceFactory::ResetCursor(gfx::AcceleratedWidget w) {
+ base::WeakPtr<HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(w);
+
+ if (!cursor_bitmap_.empty()) {
+ // Draw new cursor into backbuffer.
+ UpdateCursorImage(cursor_surface_.get(), cursor_bitmap_);
+
+ // Reset location & buffer.
+ if (controller) {
+ controller->MoveCursor(cursor_location_);
+ controller->SetCursor(cursor_surface_.get());
+ }
+ } else {
+ // No cursor set.
+ if (controller)
+ controller->UnsetCursor();
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_surface_factory.h b/chromium/ui/ozone/platform/dri/dri_surface_factory.h
new file mode 100644
index 00000000000..69ec5df243d
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface_factory.h
@@ -0,0 +1,85 @@
+// 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_OZONE_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+class SurfaceOzoneCanvas;
+}
+
+namespace ui {
+
+class DriSurface;
+class DriWrapper;
+class HardwareDisplayController;
+class ScreenManager;
+
+// SurfaceFactoryOzone implementation on top of DRM/KMS using dumb buffers.
+// This implementation is used in conjunction with the software rendering
+// path.
+class OZONE_EXPORT DriSurfaceFactory : public ui::SurfaceFactoryOzone {
+ public:
+ static const gfx::AcceleratedWidget kDefaultWidgetHandle;
+
+ DriSurfaceFactory(DriWrapper* drm, ScreenManager* screen_manager);
+ virtual ~DriSurfaceFactory();
+
+ // SurfaceFactoryOzone overrides:
+ virtual HardwareState InitializeHardware() OVERRIDE;
+ virtual void ShutdownHardware() OVERRIDE;
+
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+
+ virtual scoped_ptr<ui::SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) OVERRIDE;
+
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ gfx::Size GetWidgetSize(gfx::AcceleratedWidget w);
+
+ void SetHardwareCursor(gfx::AcceleratedWidget window,
+ const SkBitmap& image,
+ const gfx::Point& location);
+
+ void MoveHardwareCursor(gfx::AcceleratedWidget window,
+ const gfx::Point& location);
+
+ void UnsetHardwareCursor(gfx::AcceleratedWidget window);
+
+ protected:
+ // Draw the last set cursor & update the cursor plane.
+ void ResetCursor(gfx::AcceleratedWidget w);
+
+ virtual DriSurface* CreateSurface(const gfx::Size& size);
+
+ DriWrapper* drm_; // Not owned.
+ ScreenManager* screen_manager_; // Not owned.
+ HardwareState state_;
+
+ // Active outputs.
+ int allocated_widgets_;
+
+ scoped_ptr<DriSurface> cursor_surface_;
+
+ SkBitmap cursor_bitmap_;
+ gfx::Point cursor_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_SURFACE_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/dri/dri_surface_factory_unittest.cc b/chromium/ui/ozone/platform/dri/dri_surface_factory_unittest.cc
new file mode 100644
index 00000000000..13d81cbc84e
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface_factory_unittest.cc
@@ -0,0 +1,202 @@
+// 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 <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/test/mock_dri_surface.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_surface_generator.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace {
+
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+// SSFO would normally allocate DRM resources. We can't rely on having a DRM
+// backend to allocate and display our buffers. Thus, we replace these
+// resources with stubs. For DRM calls, we simply use stubs that do nothing and
+// for buffers we use the default SkBitmap allocator.
+class MockDriSurfaceFactory : public ui::DriSurfaceFactory {
+ public:
+ MockDriSurfaceFactory(ui::DriWrapper* dri, ui::ScreenManager* screen_manager)
+ : DriSurfaceFactory(dri, screen_manager), dri_(dri) {}
+ virtual ~MockDriSurfaceFactory() {};
+
+ const std::vector<ui::MockDriSurface*>& get_surfaces() const {
+ return surfaces_;
+ }
+
+ private:
+ virtual ui::DriSurface* CreateSurface(const gfx::Size& size) OVERRIDE {
+ ui::MockDriSurface* surface = new ui::MockDriSurface(dri_, size);
+ surfaces_.push_back(surface);
+ return surface;
+ }
+
+ ui::DriWrapper* dri_;
+ std::vector<ui::MockDriSurface*> surfaces_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriSurfaceFactory);
+};
+
+class MockScreenManager : public ui::ScreenManager {
+ public:
+ MockScreenManager(ui::DriWrapper* dri,
+ ui::ScanoutSurfaceGenerator* surface_generator)
+ : ScreenManager(dri, surface_generator),
+ dri_(dri) {}
+ virtual ~MockScreenManager() {}
+
+ // Normally we'd use DRM to figure out the controller configuration. But we
+ // can't use DRM in unit tests, so we just create a fake configuration.
+ virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE {
+ ConfigureDisplayController(1, 2, kDefaultMode);
+ }
+
+ private:
+ ui::DriWrapper* dri_; // Not owned.
+ std::vector<ui::MockDriSurface*> surfaces_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(MockScreenManager);
+};
+
+} // namespace
+
+class DriSurfaceFactoryTest : public testing::Test {
+ public:
+ DriSurfaceFactoryTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ protected:
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_ptr<ui::MockDriWrapper> dri_;
+ scoped_ptr<ui::MockSurfaceGenerator> surface_generator_;
+ scoped_ptr<MockScreenManager> screen_manager_;
+ scoped_ptr<MockDriSurfaceFactory> factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactoryTest);
+};
+
+void DriSurfaceFactoryTest::SetUp() {
+ message_loop_.reset(new base::MessageLoopForUI);
+ dri_.reset(new ui::MockDriWrapper(3));
+ surface_generator_.reset(new ui::MockSurfaceGenerator(dri_.get()));
+ screen_manager_.reset(new MockScreenManager(dri_.get(),
+ surface_generator_.get()));
+ factory_.reset(new MockDriSurfaceFactory(dri_.get(), screen_manager_.get()));
+}
+
+void DriSurfaceFactoryTest::TearDown() {
+ factory_.reset();
+ message_loop_.reset();
+}
+
+TEST_F(DriSurfaceFactoryTest, FailInitialization) {
+ dri_->fail_init();
+ EXPECT_EQ(ui::SurfaceFactoryOzone::FAILED, factory_->InitializeHardware());
+}
+
+TEST_F(DriSurfaceFactoryTest, SuccessfulInitialization) {
+ EXPECT_EQ(ui::SurfaceFactoryOzone::INITIALIZED,
+ factory_->InitializeHardware());
+}
+
+TEST_F(DriSurfaceFactoryTest, SuccessfulWidgetRealization) {
+ EXPECT_EQ(ui::SurfaceFactoryOzone::INITIALIZED,
+ factory_->InitializeHardware());
+
+ gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
+ EXPECT_EQ(ui::DriSurfaceFactory::kDefaultWidgetHandle, w);
+
+ EXPECT_TRUE(factory_->CreateCanvasForWidget(w));
+}
+
+TEST_F(DriSurfaceFactoryTest, CheckNativeSurfaceContents) {
+ EXPECT_EQ(ui::SurfaceFactoryOzone::INITIALIZED,
+ factory_->InitializeHardware());
+
+ gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
+ EXPECT_EQ(ui::DriSurfaceFactory::kDefaultWidgetHandle, w);
+
+ scoped_ptr<ui::SurfaceOzoneCanvas> surface =
+ factory_->CreateCanvasForWidget(w);
+
+ surface->ResizeCanvas(
+ gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay));
+ surface->GetCanvas()->drawColor(SK_ColorWHITE);
+ surface->PresentCanvas(
+ gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2));
+
+ const std::vector<ui::DriBuffer*>& bitmaps =
+ surface_generator_->surfaces()[0]->bitmaps();
+
+ SkBitmap image;
+ bitmaps[1]->canvas()->readPixels(&image, 0, 0);
+
+ // Make sure the updates are correctly propagated to the native surface.
+ for (int i = 0; i < image.height(); ++i) {
+ for (int j = 0; j < image.width(); ++j) {
+ if (j < kDefaultMode.hdisplay / 2 && i < kDefaultMode.vdisplay / 2)
+ EXPECT_EQ(SK_ColorWHITE, image.getColor(j, i));
+ else
+ EXPECT_EQ(SK_ColorBLACK, image.getColor(j, i));
+ }
+ }
+}
+
+TEST_F(DriSurfaceFactoryTest, SetCursorImage) {
+ EXPECT_EQ(ui::SurfaceFactoryOzone::INITIALIZED,
+ factory_->InitializeHardware());
+
+ gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
+ EXPECT_EQ(ui::DriSurfaceFactory::kDefaultWidgetHandle, w);
+
+ scoped_ptr<ui::SurfaceOzoneCanvas> surf = factory_->CreateCanvasForWidget(w);
+ EXPECT_TRUE(surf);
+
+ SkBitmap image;
+ SkImageInfo info = SkImageInfo::Make(
+ 6, 4, kN32_SkColorType, kPremul_SkAlphaType);
+ image.allocPixels(info);
+ image.eraseColor(SK_ColorWHITE);
+
+ factory_->SetHardwareCursor(w, image, gfx::Point(4, 2));
+ const std::vector<ui::MockDriSurface*>& surfaces = factory_->get_surfaces();
+
+ // The first surface is the cursor surface since it is allocated early in the
+ // initialization process.
+ const std::vector<ui::DriBuffer*>& bitmaps = surfaces[0]->bitmaps();
+
+ // The surface should have been initialized to a double-buffered surface.
+ EXPECT_EQ(2u, bitmaps.size());
+
+ SkBitmap cursor;
+ bitmaps[1]->canvas()->readPixels(&cursor, 0, 0);
+
+ // Check that the frontbuffer is displaying the right image as set above.
+ for (int i = 0; i < cursor.height(); ++i) {
+ for (int j = 0; j < cursor.width(); ++j) {
+ if (j < info.width() && i < info.height())
+ EXPECT_EQ(SK_ColorWHITE, cursor.getColor(j, i));
+ else
+ EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+ cursor.getColor(j, i));
+ }
+ }
+}
diff --git a/chromium/ui/ozone/platform/dri/dri_surface_unittest.cc b/chromium/ui/ozone/platform/dri/dri_surface_unittest.cc
new file mode 100644
index 00000000000..397e54f0b95
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_surface_unittest.cc
@@ -0,0 +1,118 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkDevice.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/test/mock_dri_surface.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+
+namespace {
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+} // namespace
+
+class DriSurfaceTest : public testing::Test {
+ public:
+ DriSurfaceTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ scoped_ptr<ui::MockDriWrapper> drm_;
+ scoped_ptr<ui::HardwareDisplayController> controller_;
+ scoped_ptr<ui::MockDriSurface> surface_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceTest);
+};
+
+void DriSurfaceTest::SetUp() {
+ drm_.reset(new ui::MockDriWrapper(3));
+ controller_.reset(new ui::HardwareDisplayController(drm_.get(), 1, 1));
+
+ surface_.reset(new ui::MockDriSurface(
+ drm_.get(), gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
+}
+
+void DriSurfaceTest::TearDown() {
+ surface_.reset();
+ controller_.reset();
+ drm_.reset();
+}
+
+TEST_F(DriSurfaceTest, FailInitialization) {
+ surface_->set_initialize_expectation(false);
+ EXPECT_FALSE(surface_->Initialize());
+}
+
+TEST_F(DriSurfaceTest, SuccessfulInitialization) {
+ EXPECT_TRUE(surface_->Initialize());
+}
+
+TEST_F(DriSurfaceTest, CheckFBIDOnSwap) {
+ EXPECT_TRUE(surface_->Initialize());
+ controller_->BindSurfaceToController(surface_.PassAs<ui::ScanoutSurface>(),
+ kDefaultMode);
+
+ // Check that the framebuffer ID is correct.
+ EXPECT_EQ(2u, controller_->surface()->GetFramebufferId());
+
+ controller_->surface()->SwapBuffers();
+
+ EXPECT_EQ(1u, controller_->surface()->GetFramebufferId());
+}
+
+TEST_F(DriSurfaceTest, CheckPixelPointerOnSwap) {
+ EXPECT_TRUE(surface_->Initialize());
+
+ void* bitmap_pixels1 = surface_->GetDrawableForWidget()->getDevice()
+ ->accessBitmap(false).getPixels();
+
+ surface_->SwapBuffers();
+
+ void* bitmap_pixels2 = surface_->GetDrawableForWidget()->getDevice()
+ ->accessBitmap(false).getPixels();
+
+ // Check that once the buffers have been swapped the drawable's underlying
+ // pixels have been changed.
+ EXPECT_NE(bitmap_pixels1, bitmap_pixels2);
+}
+
+TEST_F(DriSurfaceTest, CheckCorrectBufferSync) {
+ EXPECT_TRUE(surface_->Initialize());
+
+ SkCanvas* canvas = surface_->GetDrawableForWidget();
+ SkRect clip;
+ // Modify part of the canvas.
+ clip.set(0, 0,
+ canvas->getDeviceSize().width() / 2,
+ canvas->getDeviceSize().height() / 2);
+ canvas->clipRect(clip, SkRegion::kReplace_Op);
+
+ canvas->drawColor(SK_ColorWHITE);
+
+ surface_->SwapBuffers();
+
+ // Verify that the modified contents have been copied over on swap (make sure
+ // the 2 buffers have the same content).
+ for (int i = 0; i < canvas->getDeviceSize().height(); ++i) {
+ for (int j = 0; j < canvas->getDeviceSize().width(); ++j) {
+ if (i < clip.height() && j < clip.width())
+ EXPECT_EQ(SK_ColorWHITE,
+ canvas->getDevice()->accessBitmap(false).getColor(j, i));
+ else
+ EXPECT_EQ(SK_ColorBLACK,
+ canvas->getDevice()->accessBitmap(false).getColor(j, i));
+ }
+ }
+}
diff --git a/chromium/ui/ozone/platform/dri/dri_util.cc b/chromium/ui/ozone/platform/dri/dri_util.cc
new file mode 100644
index 00000000000..b3eab02b41a
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_util.cc
@@ -0,0 +1,125 @@
+// 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/ozone/platform/dri/dri_util.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drmMode.h>
+
+namespace ui {
+
+namespace {
+
+bool IsCrtcInUse(uint32_t crtc,
+ const ScopedVector<HardwareDisplayControllerInfo>& displays) {
+ for (size_t i = 0; i < displays.size(); ++i) {
+ if (crtc == displays[i]->crtc()->crtc_id)
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t GetCrtc(int fd,
+ drmModeConnector* connector,
+ drmModeRes* resources,
+ const ScopedVector<HardwareDisplayControllerInfo>& displays) {
+ // If the connector already has an encoder try to re-use.
+ if (connector->encoder_id) {
+ drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoder_id);
+ if (encoder) {
+ if (encoder->crtc_id && !IsCrtcInUse(encoder->crtc_id, displays)) {
+ uint32_t crtc = encoder->crtc_id;
+ drmModeFreeEncoder(encoder);
+ return crtc;
+ }
+ drmModeFreeEncoder(encoder);
+ }
+ }
+
+ // Try to find an encoder for the connector.
+ for (int i = 0; i < connector->count_encoders; ++i) {
+ drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoders[i]);
+ if (!encoder)
+ continue;
+
+ for (int j = 0; j < resources->count_crtcs; ++j) {
+ // Check if the encoder is compatible with this CRTC
+ if (!(encoder->possible_crtcs & (1 << j)) ||
+ IsCrtcInUse(resources->crtcs[j], displays)) {
+ continue;
+ }
+
+ drmModeFreeEncoder(encoder);
+ return resources->crtcs[j];
+ }
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ return 0;
+}
+
+} // namespace
+
+HardwareDisplayControllerInfo::HardwareDisplayControllerInfo(
+ drmModeConnector* connector,
+ drmModeCrtc* crtc)
+ : connector_(connector),
+ crtc_(crtc) {}
+
+HardwareDisplayControllerInfo::~HardwareDisplayControllerInfo() {
+ drmModeFreeConnector(connector_);
+ drmModeFreeCrtc(crtc_);
+}
+
+ScopedVector<HardwareDisplayControllerInfo>
+GetAvailableDisplayControllerInfos(int fd, drmModeRes* resources) {
+ ScopedVector<HardwareDisplayControllerInfo> displays;
+
+ for (int i = 0; i < resources->count_connectors; ++i) {
+ drmModeConnector* connector = drmModeGetConnector(
+ fd, resources->connectors[i]);
+
+ if (!connector)
+ continue;
+
+ if (connector->connection != DRM_MODE_CONNECTED ||
+ connector->count_modes == 0) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ uint32_t crtc_id = GetCrtc(fd, connector, resources, displays);
+ if (!crtc_id) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ drmModeCrtc* crtc = drmModeGetCrtc(fd, crtc_id);
+ displays.push_back(new HardwareDisplayControllerInfo(connector, crtc));
+ }
+
+ return displays.Pass();
+}
+
+bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs) {
+ return lhs.clock == rhs.clock &&
+ lhs.hdisplay == rhs.hdisplay &&
+ lhs.vdisplay == rhs.vdisplay &&
+ lhs.vrefresh == rhs.vrefresh &&
+ lhs.hsync_start == rhs.hsync_start &&
+ lhs.hsync_end == rhs.hsync_end &&
+ lhs.htotal == rhs.htotal &&
+ lhs.hskew == rhs.hskew &&
+ lhs.vsync_start == rhs.vsync_start &&
+ lhs.vsync_end == rhs.vsync_end &&
+ lhs.vtotal == rhs.vtotal &&
+ lhs.vscan == rhs.vscan &&
+ lhs.flags == rhs.flags &&
+ strcmp(lhs.name, rhs.name) == 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_util.h b/chromium/ui/ozone/platform/dri/dri_util.h
new file mode 100644
index 00000000000..174d2aae657
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_util.h
@@ -0,0 +1,44 @@
+// 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_OZONE_PLATFORM_DRI_DRI_UTIL_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_UTIL_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+
+typedef struct _drmModeConnector drmModeConnector;
+typedef struct _drmModeCrtc drmModeCrtc;
+typedef struct _drmModeModeInfo drmModeModeInfo;
+typedef struct _drmModeRes drmModeRes;
+
+namespace ui {
+
+// Representation of the information required to initialize and configure a
+// native display.
+class HardwareDisplayControllerInfo {
+ public:
+ HardwareDisplayControllerInfo(drmModeConnector* connector, drmModeCrtc* crtc);
+ ~HardwareDisplayControllerInfo();
+
+ drmModeConnector* connector() const { return connector_; }
+ drmModeCrtc* crtc() const { return crtc_; }
+
+ private:
+ drmModeConnector* connector_;
+ drmModeCrtc* crtc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerInfo);
+};
+
+// Looks-up and parses the native display configurations returning all available
+// displays.
+ScopedVector<HardwareDisplayControllerInfo>
+GetAvailableDisplayControllerInfos(int fd, drmModeRes* resources);
+
+bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_UTIL_H_
diff --git a/chromium/ui/ozone/platform/dri/dri_vsync_provider.cc b/chromium/ui/ozone/platform/dri/dri_vsync_provider.cc
new file mode 100644
index 00000000000..6679d38937c
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_vsync_provider.cc
@@ -0,0 +1,38 @@
+// 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/ozone/platform/dri/dri_vsync_provider.h"
+
+#include "base/time/time.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+DriVSyncProvider::DriVSyncProvider(
+ const base::WeakPtr<HardwareDisplayController>& controller)
+ : controller_(controller) {
+}
+
+DriVSyncProvider::~DriVSyncProvider() {}
+
+void DriVSyncProvider::GetVSyncParameters(const UpdateVSyncCallback& callback) {
+ if (!controller_)
+ return;
+
+ // The value is invalid, so we can't update the parameters.
+ if (controller_->get_time_of_last_flip() == 0 ||
+ controller_->get_mode().vrefresh == 0)
+ return;
+
+ // Stores the time of the last refresh.
+ base::TimeTicks timebase =
+ base::TimeTicks::FromInternalValue(controller_->get_time_of_last_flip());
+ // Stores the refresh rate.
+ base::TimeDelta interval =
+ base::TimeDelta::FromSeconds(1) / controller_->get_mode().vrefresh;
+
+ callback.Run(timebase, interval);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_vsync_provider.h b/chromium/ui/ozone/platform/dri/dri_vsync_provider.h
new file mode 100644
index 00000000000..77ec1782172
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_vsync_provider.h
@@ -0,0 +1,30 @@
+// 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_OZONE_PLATFORM_IMPL_DRI_VSYNC_PROVIDER_H_
+#define UI_OZONE_PLATFORM_IMPL_DRI_VSYNC_PROVIDER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/vsync_provider.h"
+
+namespace ui {
+
+class HardwareDisplayController;
+
+class DriVSyncProvider : public gfx::VSyncProvider {
+ public:
+ DriVSyncProvider(const base::WeakPtr<HardwareDisplayController>& controller);
+ virtual ~DriVSyncProvider();
+
+ virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) OVERRIDE;
+
+ private:
+ base::WeakPtr<HardwareDisplayController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(DriVSyncProvider);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_IMPL_DRI_VSYNC_PROVIDER_H_
diff --git a/chromium/ui/ozone/platform/dri/dri_wrapper.cc b/chromium/ui/ozone/platform/dri/dri_wrapper.cc
new file mode 100644
index 00000000000..5231bd0ea02
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_wrapper.cc
@@ -0,0 +1,164 @@
+// 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/ozone/platform/dri/dri_wrapper.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+
+namespace ui {
+
+DriWrapper::DriWrapper(const char* device_path) {
+ fd_ = open(device_path, O_RDWR | O_CLOEXEC);
+}
+
+DriWrapper::~DriWrapper() {
+ if (fd_ >= 0)
+ close(fd_);
+}
+
+drmModeCrtc* DriWrapper::GetCrtc(uint32_t crtc_id) {
+ CHECK(fd_ >= 0);
+ return drmModeGetCrtc(fd_, crtc_id);
+}
+
+void DriWrapper::FreeCrtc(drmModeCrtc* crtc) {
+ drmModeFreeCrtc(crtc);
+}
+
+bool DriWrapper::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ uint32_t* connectors,
+ drmModeModeInfo* mode) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCrtc(fd_, crtc_id, framebuffer, 0, 0, connectors, 1, mode);
+}
+
+bool DriWrapper::SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCrtc(fd_,
+ crtc->crtc_id,
+ crtc->buffer_id,
+ crtc->x,
+ crtc->y,
+ connectors,
+ 1,
+ &crtc->mode);
+}
+
+bool DriWrapper::DisableCrtc(uint32_t crtc_id) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCrtc(fd_, crtc_id, 0, 0, 0, NULL, 0, NULL);
+}
+
+bool DriWrapper::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ CHECK(fd_ >= 0);
+ return !drmModeAddFB(fd_,
+ width,
+ height,
+ depth,
+ bpp,
+ stride,
+ handle,
+ framebuffer);
+}
+
+bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
+ CHECK(fd_ >= 0);
+ return !drmModeRmFB(fd_, framebuffer);
+}
+
+bool DriWrapper::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) {
+ CHECK(fd_ >= 0);
+ return !drmModePageFlip(fd_,
+ crtc_id,
+ framebuffer,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ data);
+}
+
+drmModePropertyRes* DriWrapper::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ for (int i = 0; i < connector->count_props; ++i) {
+ drmModePropertyRes* property = drmModeGetProperty(fd_, connector->props[i]);
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0)
+ return property;
+
+ drmModeFreeProperty(property);
+ }
+
+ return NULL;
+}
+
+bool DriWrapper::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ CHECK(fd_ >= 0);
+ return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
+}
+
+void DriWrapper::FreeProperty(drmModePropertyRes* prop) {
+ drmModeFreeProperty(prop);
+}
+
+drmModePropertyBlobRes* DriWrapper::GetPropertyBlob(drmModeConnector* connector,
+ const char* name) {
+ CHECK(fd_ >= 0);
+ for (int i = 0; i < connector->count_props; ++i) {
+ drmModePropertyRes* property = drmModeGetProperty(fd_, connector->props[i]);
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0 &&
+ property->flags & DRM_MODE_PROP_BLOB) {
+ drmModePropertyBlobRes* blob =
+ drmModeGetPropertyBlob(fd_, connector->prop_values[i]);
+ drmModeFreeProperty(property);
+ return blob;
+ }
+
+ drmModeFreeProperty(property);
+ }
+
+ return NULL;
+}
+
+void DriWrapper::FreePropertyBlob(drmModePropertyBlobRes* blob) {
+ drmModeFreePropertyBlob(blob);
+}
+
+bool DriWrapper::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height) {
+ CHECK(fd_ >= 0);
+ return !drmModeSetCursor(fd_, crtc_id, handle, width, height);
+}
+
+bool DriWrapper::MoveCursor(uint32_t crtc_id, int x, int y) {
+ CHECK(fd_ >= 0);
+ return !drmModeMoveCursor(fd_, crtc_id, x, y);
+}
+
+void DriWrapper::HandleEvent(drmEventContext& event) {
+ CHECK(fd_ >= 0);
+ drmHandleEvent(fd_, &event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/dri_wrapper.h b/chromium/ui/ozone/platform/dri/dri_wrapper.h
new file mode 100644
index 00000000000..014d143ec57
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/dri_wrapper.h
@@ -0,0 +1,127 @@
+// 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_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
+#define UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "ui/ozone/ozone_export.h"
+
+typedef struct _drmEventContext drmEventContext;
+typedef struct _drmModeConnector drmModeConnector;
+typedef struct _drmModeCrtc drmModeCrtc;
+typedef struct _drmModeModeInfo drmModeModeInfo;
+typedef struct _drmModeProperty drmModePropertyRes;
+typedef struct _drmModePropertyBlob drmModePropertyBlobRes;
+
+namespace ui {
+
+// Wraps DRM calls into a nice interface. Used to provide different
+// implementations of the DRM calls. For the actual implementation the DRM API
+// would be called. In unit tests this interface would be stubbed.
+class OZONE_EXPORT DriWrapper {
+ public:
+ DriWrapper(const char* device_path);
+ virtual ~DriWrapper();
+
+ // Get the CRTC state. This is generally used to save state before using the
+ // CRTC. When the user finishes using the CRTC, the user should restore the
+ // CRTC to it's initial state. Use |SetCrtc| to restore the state.
+ virtual drmModeCrtc* GetCrtc(uint32_t crtc_id);
+
+ // Frees the CRTC mode object.
+ virtual void FreeCrtc(drmModeCrtc* crtc);
+
+ // Used to configure CRTC with ID |crtc_id| to use the connector in
+ // |connectors|. The CRTC will be configured with mode |mode| and will display
+ // the framebuffer with ID |framebuffer|. Before being able to display the
+ // framebuffer, it should be registered with the CRTC using |AddFramebuffer|.
+ virtual bool SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ uint32_t* connectors,
+ drmModeModeInfo* mode);
+
+ // Used to set a specific configuration to the CRTC. Normally this function
+ // would be called with a CRTC saved state (from |GetCrtc|) to restore it to
+ // its original configuration.
+ virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors);
+
+ virtual bool DisableCrtc(uint32_t crtc_id);
+
+ // Register a buffer with the CRTC. On successful registration, the CRTC will
+ // assign a framebuffer ID to |framebuffer|.
+ virtual bool AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer);
+
+ // Deregister the given |framebuffer|.
+ virtual bool RemoveFramebuffer(uint32_t framebuffer);
+
+ // Schedules a pageflip for CRTC |crtc_id|. This function will return
+ // immediately. Upon completion of the pageflip event, the CRTC will be
+ // displaying the buffer with ID |framebuffer| and will have a DRM event
+ // queued on |fd_|. |data| is a generic pointer to some information the user
+ // will receive when processing the pageflip event.
+ virtual bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, void* data);
+
+ // Returns the property with name |name| associated with |connector|. Returns
+ // NULL if property not found. If the returned value is valid, it must be
+ // released using FreeProperty().
+ virtual drmModePropertyRes* GetProperty(drmModeConnector* connector,
+ const char* name);
+
+ // Sets the value of property with ID |property_id| to |value|. The property
+ // is applied to the connector with ID |connector_id|.
+ virtual bool SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value);
+
+ // Frees |prop| and any resources it allocated when it was created. |prop|
+ // must be a valid object.
+ virtual void FreeProperty(drmModePropertyRes* prop);
+
+ // Return a binary blob associated with |connector|. The binary blob is
+ // associated with the property with name |name|. Return NULL if the property
+ // could not be found or if the property does not have a binary blob. If valid
+ // the returned object must be freed using FreePropertyBlob().
+ virtual drmModePropertyBlobRes* GetPropertyBlob(drmModeConnector* connector,
+ const char* name);
+
+ // Frees |blob| and any resources allocated when it was created. |blob| must
+ // be a valid object.
+ virtual void FreePropertyBlob(drmModePropertyBlobRes* blob);
+
+ // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the
+ // cursor size pointed by |handle|.
+ virtual bool SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height);
+
+
+ // Move the cursor on CRTC |crtc_id| to (x, y);
+ virtual bool MoveCursor(uint32_t crtc_id, int x, int y);
+
+ virtual void HandleEvent(drmEventContext& event);
+
+ int get_fd() const { return fd_; }
+
+ protected:
+ // The file descriptor associated with this wrapper. All DRM operations will
+ // be performed using this FD.
+ int fd_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DriWrapper);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/dri/gbm.gypi b/chromium/ui/ozone/platform/dri/gbm.gypi
new file mode 100644
index 00000000000..91c0e872794
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/gbm.gypi
@@ -0,0 +1,43 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_gbm',
+ ],
+ 'internal_ozone_platforms': [
+ 'gbm',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_gbm',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../build/linux/system.gyp:dridrm',
+ '../../build/linux/system.gyp:gbm',
+ '../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'buffer_data.cc',
+ 'buffer_data.h',
+ 'gbm_surface.cc',
+ 'gbm_surface.h',
+ 'gbm_surface_factory.cc',
+ 'gbm_surface_factory.h',
+ 'ozone_platform_gbm.cc',
+ 'ozone_platform_gbm.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/ozone/platform/dri/gbm_surface.cc b/chromium/ui/ozone/platform/dri/gbm_surface.cc
new file mode 100644
index 00000000000..99f0ae7016f
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/gbm_surface.cc
@@ -0,0 +1,112 @@
+// 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/ozone/platform/dri/gbm_surface.h"
+
+#include <gbm.h>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/ozone/platform/dri/buffer_data.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+GbmSurface::GbmSurface(gbm_device* device,
+ DriWrapper* dri,
+ const gfx::Size& size)
+ : gbm_device_(device),
+ dri_(dri),
+ size_(size),
+ native_surface_(NULL),
+ buffers_(),
+ front_buffer_(0) {
+ for (size_t i = 0; i < arraysize(buffers_); ++i)
+ buffers_[i] = NULL;
+}
+
+GbmSurface::~GbmSurface() {
+ for (size_t i = 0; i < arraysize(buffers_); ++i) {
+ if (buffers_[i]) {
+ gbm_surface_release_buffer(native_surface_, buffers_[i]);
+ }
+ }
+
+ if (native_surface_)
+ gbm_surface_destroy(native_surface_);
+}
+
+bool GbmSurface::Initialize() {
+ // TODO(dnicoara) Check underlying system support for pixel format.
+ native_surface_ = gbm_surface_create(
+ gbm_device_,
+ size_.width(),
+ size_.height(),
+ GBM_BO_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+
+ if (!native_surface_)
+ return false;
+
+ dumb_buffer_.reset(new DriBuffer(dri_));
+ if (!dumb_buffer_->Initialize(SkImageInfo::MakeN32Premul(size_.width(),
+ size_.height())))
+ return false;
+
+ return true;
+}
+
+uint32_t GbmSurface::GetFramebufferId() const {
+ if (!buffers_[front_buffer_ ^ 1])
+ return dumb_buffer_->framebuffer();
+
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]);
+ CHECK(data);
+ return data->framebuffer();
+}
+
+uint32_t GbmSurface::GetHandle() const {
+ if (!buffers_[front_buffer_ ^ 1])
+ return dumb_buffer_->handle();
+
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]);
+ CHECK(data);
+ return data->handle();
+}
+
+gfx::Size GbmSurface::Size() const {
+ return size_;
+}
+
+void GbmSurface::SwapBuffers() {
+ // If there was a frontbuffer, is no longer active. Release it back to GBM.
+ if (buffers_[front_buffer_])
+ gbm_surface_release_buffer(native_surface_, buffers_[front_buffer_]);
+
+ // Update the index to the frontbuffer.
+ front_buffer_ ^= 1;
+ // We've just released it. Since GBM doesn't guarantee we'll get the same
+ // buffer back, we set it to NULL so we don't keep track of objects that may
+ // have been destroyed.
+ buffers_[front_buffer_ ^ 1] = NULL;
+}
+
+void GbmSurface::LockCurrentDrawable() {
+ CHECK(native_surface_);
+ // Lock the buffer we want to display.
+ buffers_[front_buffer_ ^ 1] = gbm_surface_lock_front_buffer(native_surface_);
+
+ BufferData* data = BufferData::GetData(buffers_[front_buffer_ ^ 1]);
+ // If it is a new buffer, it won't have any data associated with it. So we
+ // create it. On creation it will associate itself with the buffer and
+ // register the buffer.
+ if (!data) {
+ data = BufferData::CreateData(dri_, buffers_[front_buffer_ ^ 1]);
+ DCHECK(data) << "Failed to associate the buffer with the controller";
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/gbm_surface.h b/chromium/ui/ozone/platform/dri/gbm_surface.h
new file mode 100644
index 00000000000..8a33ab5e997
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/gbm_surface.h
@@ -0,0 +1,75 @@
+// 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_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+
+struct gbm_bo;
+struct gbm_device;
+struct gbm_surface;
+
+namespace ui {
+
+class DriBuffer;
+class DriWrapper;
+
+// Implement the ScanoutSurface interface on top of GBM (Generic Buffer
+// Manager). GBM provides generic access to hardware accelerated surfaces which
+// can be used in association with EGL to provide accelerated drawing.
+class GbmSurface : public ScanoutSurface {
+ public:
+ GbmSurface(gbm_device* device, DriWrapper* dri, const gfx::Size& size);
+ virtual ~GbmSurface();
+
+ // ScanoutSurface:
+ virtual bool Initialize() OVERRIDE;
+ virtual uint32_t GetFramebufferId() const OVERRIDE;
+ virtual uint32_t GetHandle() const OVERRIDE;
+ virtual gfx::Size Size() const OVERRIDE;
+ virtual void SwapBuffers() OVERRIDE;
+
+ // Before scheduling the backbuffer to be scanned out we need to "lock" it.
+ // When we lock it, GBM will give a pointer to a buffer representing the
+ // backbuffer. It will also update its information on which buffers can not be
+ // used for drawing. The buffer will be released when the page flip event
+ // occurs (see SwapBuffers). This is called from GbmSurfaceFactory before
+ // scheduling a page flip.
+ void LockCurrentDrawable();
+
+ gbm_surface* native_surface() { return native_surface_; };
+
+ private:
+ gbm_device* gbm_device_;
+
+ DriWrapper* dri_;
+
+ gfx::Size size_;
+
+ // The native GBM surface. In EGL this represents the EGLNativeWindowType.
+ gbm_surface* native_surface_;
+
+ // Backing GBM buffers. One is the current front buffer. The other is the
+ // current backbuffer that is pending scan out.
+ gbm_bo* buffers_[2];
+
+ // Index to the front buffer.
+ int front_buffer_;
+
+ // We can't lock (and get) an accelerated buffer from the GBM surface until
+ // after something draws into it. But modesetting needs to happen earlier,
+ // before an actual window is created and draws. So, we create a dumb buffer
+ // for this purpose.
+ scoped_ptr<DriBuffer> dumb_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_H_
diff --git a/chromium/ui/ozone/platform/dri/gbm_surface_factory.cc b/chromium/ui/ozone/platform/dri/gbm_surface_factory.cc
new file mode 100644
index 00000000000..5eb93fc427e
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/gbm_surface_factory.cc
@@ -0,0 +1,187 @@
+// 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/ozone/platform/dri/gbm_surface_factory.h"
+
+#include <EGL/egl.h>
+#include <gbm.h>
+
+#include "base/files/file_path.h"
+#include "ui/ozone/platform/dri/buffer_data.h"
+#include "ui/ozone/platform/dri/dri_vsync_provider.h"
+#include "ui/ozone/platform/dri/gbm_surface.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+namespace {
+
+class GbmSurfaceAdapter : public ui::SurfaceOzoneEGL {
+ public:
+ GbmSurfaceAdapter(const base::WeakPtr<HardwareDisplayController>& controller);
+ virtual ~GbmSurfaceAdapter();
+
+ // SurfaceOzoneEGL:
+ virtual intptr_t GetNativeWindow() OVERRIDE;
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE;
+ virtual bool OnSwapBuffers() OVERRIDE;
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE;
+
+ private:
+ base::WeakPtr<HardwareDisplayController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceAdapter);
+};
+
+GbmSurfaceAdapter::GbmSurfaceAdapter(
+ const base::WeakPtr<HardwareDisplayController>& controller)
+ : controller_(controller) {}
+
+GbmSurfaceAdapter::~GbmSurfaceAdapter() {}
+
+intptr_t GbmSurfaceAdapter::GetNativeWindow() {
+ if (!controller_)
+ return 0;
+
+ return reinterpret_cast<intptr_t>(
+ static_cast<GbmSurface*>(controller_->surface())->native_surface());
+}
+
+bool GbmSurfaceAdapter::ResizeNativeWindow(const gfx::Size& viewport_size) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool GbmSurfaceAdapter::OnSwapBuffers() {
+ if (!controller_)
+ return false;
+
+ static_cast<GbmSurface*>(controller_->surface())->LockCurrentDrawable();
+ if (controller_->SchedulePageFlip()) {
+ controller_->WaitForPageFlipEvent();
+ return true;
+ }
+
+ return false;
+}
+
+scoped_ptr<gfx::VSyncProvider> GbmSurfaceAdapter::CreateVSyncProvider() {
+ return scoped_ptr<gfx::VSyncProvider>(new DriVSyncProvider(controller_));
+}
+
+} // namespace
+
+GbmSurfaceFactory::GbmSurfaceFactory(DriWrapper* dri,
+ gbm_device* device,
+ ScreenManager* screen_manager)
+ : DriSurfaceFactory(dri, screen_manager),
+ device_(device) {}
+
+GbmSurfaceFactory::~GbmSurfaceFactory() {}
+
+intptr_t GbmSurfaceFactory::GetNativeDisplay() {
+ CHECK(state_ == INITIALIZED);
+ return reinterpret_cast<intptr_t>(device_);
+}
+
+const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
+ const int32* desired_list) {
+ static const int32 kConfigAttribs[] = {
+ EGL_BUFFER_SIZE, 32,
+ EGL_ALPHA_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_RED_SIZE, 8,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ return kConfigAttribs;
+}
+
+bool GbmSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary gles_library = base::LoadNativeLibrary(
+ base::FilePath("libGLESv2.so.2"),
+ &error);
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary egl_library = base::LoadNativeLibrary(
+ base::FilePath("libEGL.so.1"),
+ &error);
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<GLGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ egl_library, "eglGetProcAddress"));
+ if (!get_proc_address) {
+ LOG(ERROR) << "eglGetProcAddress not found.";
+ base::UnloadNativeLibrary(egl_library);
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ set_gl_get_proc_address.Run(get_proc_address);
+ add_gl_library.Run(egl_library);
+ add_gl_library.Run(gles_library);
+
+ return true;
+}
+
+scoped_ptr<ui::SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget w) {
+ CHECK(state_ == INITIALIZED);
+ ResetCursor(w);
+
+ return scoped_ptr<ui::SurfaceOzoneEGL>(
+ new GbmSurfaceAdapter(screen_manager_->GetDisplayController(w)));
+}
+
+gfx::NativeBufferOzone GbmSurfaceFactory::CreateNativeBuffer(
+ gfx::Size size,
+ BufferFormat format) {
+ uint32_t gbm_format = 0;
+ switch (format) {
+ case SurfaceFactoryOzone::UNKNOWN:
+ return 0;
+ // TODO(alexst): Setting this to XRGB for now to allow presentation
+ // as a primary plane but disallowing overlay transparency. Address this
+ // to allow both use cases.
+ case SurfaceFactoryOzone::RGBA_8888:
+ gbm_format = GBM_FORMAT_XRGB8888;
+ break;
+ case SurfaceFactoryOzone::RGB_888:
+ gbm_format = GBM_FORMAT_RGB888;
+ break;
+ }
+ gbm_bo* buffer_object =
+ gbm_bo_create(device_,
+ size.width(),
+ size.height(),
+ gbm_format,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ if (!buffer_object)
+ return 0;
+
+ BufferData* data = BufferData::CreateData(drm_, buffer_object);
+ DCHECK(data) << "Failed to associate the buffer with the controller";
+
+ return reinterpret_cast<gfx::NativeBufferOzone>(buffer_object);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/gbm_surface_factory.h b/chromium/ui/ozone/platform/dri/gbm_surface_factory.h
new file mode 100644
index 00000000000..da624bf0875
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/gbm_surface_factory.h
@@ -0,0 +1,42 @@
+// 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_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_
+
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+
+struct gbm_device;
+
+namespace ui {
+
+class GbmSurfaceFactory : public DriSurfaceFactory {
+ public:
+ GbmSurfaceFactory(DriWrapper* dri,
+ gbm_device* device,
+ ScreenManager* screen_manager);
+ virtual ~GbmSurfaceFactory();
+
+ // DriSurfaceFactory:
+ virtual intptr_t GetNativeDisplay() OVERRIDE;
+ virtual const int32_t* GetEGLSurfaceProperties(
+ const int32_t* desired_list) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+ virtual scoped_ptr<ui::SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget w) OVERRIDE;
+ virtual gfx::NativeBufferOzone CreateNativeBuffer(
+ gfx::Size size,
+ BufferFormat format) OVERRIDE;
+
+ private:
+ gbm_device* device_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_GBM_SURFACE_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/dri/hardware_display_controller.cc b/chromium/ui/ozone/platform/dri/hardware_display_controller.cc
new file mode 100644
index 00000000000..4b00c6efdc0
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/hardware_display_controller.cc
@@ -0,0 +1,168 @@
+// 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/ozone/platform/dri/hardware_display_controller.h"
+
+#include <drm.h>
+#include <errno.h>
+#include <string.h>
+#include <xf86drm.h>
+
+#include "base/basictypes.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+
+namespace ui {
+
+namespace {
+
+// DRM callback on page flip events. This callback is triggered after the
+// page flip has happened and the backbuffer is now the new frontbuffer
+// The old frontbuffer is no longer used by the hardware and can be used for
+// future draw operations.
+//
+// |device| will contain a reference to the |ScanoutSurface| object which
+// the event belongs to.
+//
+// TODO(dnicoara) When we have a FD handler for the DRM calls in the message
+// loop, we can move this function in the handler.
+void HandlePageFlipEvent(int fd,
+ unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds,
+ void* controller) {
+ TRACE_EVENT0("dri", "HandlePageFlipEvent");
+ static_cast<HardwareDisplayController*>(controller)
+ ->OnPageFlipEvent(frame, seconds, useconds);
+}
+
+} // namespace
+
+HardwareDisplayController::HardwareDisplayController(
+ DriWrapper* drm,
+ uint32_t connector_id,
+ uint32_t crtc_id)
+ : drm_(drm),
+ connector_id_(connector_id),
+ crtc_id_(crtc_id),
+ surface_(),
+ time_of_last_flip_(0),
+ is_disabled_(true) {}
+
+HardwareDisplayController::~HardwareDisplayController() {
+ // Reset the cursor.
+ UnsetCursor();
+ UnbindSurfaceFromController();
+}
+
+bool
+HardwareDisplayController::BindSurfaceToController(
+ scoped_ptr<ScanoutSurface> surface, drmModeModeInfo mode) {
+ CHECK(surface);
+
+ if (!drm_->SetCrtc(crtc_id_,
+ surface->GetFramebufferId(),
+ &connector_id_,
+ &mode)) {
+ LOG(ERROR) << "Failed to modeset: error='" << strerror(errno)
+ << "' crtc=" << crtc_id_ << " connector=" << connector_id_
+ << " framebuffer_id=" << surface->GetFramebufferId()
+ << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
+ << mode.vrefresh;
+ return false;
+ }
+
+ surface_.reset(surface.release());
+ mode_ = mode;
+ is_disabled_ = false;
+ return true;
+}
+
+void HardwareDisplayController::UnbindSurfaceFromController() {
+ drm_->SetCrtc(crtc_id_, 0, 0, NULL);
+ surface_.reset();
+ memset(&mode_, 0, sizeof(mode_));
+ is_disabled_ = true;
+}
+
+bool HardwareDisplayController::Enable() {
+ CHECK(surface_);
+ if (is_disabled_) {
+ scoped_ptr<ScanoutSurface> surface(surface_.release());
+ return BindSurfaceToController(surface.Pass(), mode_);
+ }
+
+ return true;
+}
+
+void HardwareDisplayController::Disable() {
+ drm_->SetCrtc(crtc_id_, 0, 0, NULL);
+ is_disabled_ = true;
+}
+
+bool HardwareDisplayController::SchedulePageFlip() {
+ CHECK(surface_);
+ if (!is_disabled_ && !drm_->PageFlip(crtc_id_,
+ surface_->GetFramebufferId(),
+ this)) {
+ LOG(ERROR) << "Cannot page flip: " << strerror(errno);
+ return false;
+ }
+
+ return true;
+}
+
+void HardwareDisplayController::WaitForPageFlipEvent() {
+ TRACE_EVENT0("dri", "WaitForPageFlipEvent");
+
+ if (is_disabled_)
+ return;
+
+ drmEventContext drm_event;
+ drm_event.version = DRM_EVENT_CONTEXT_VERSION;
+ drm_event.page_flip_handler = HandlePageFlipEvent;
+ drm_event.vblank_handler = NULL;
+
+ // Wait for the page-flip to complete.
+ drm_->HandleEvent(drm_event);
+}
+
+void HardwareDisplayController::OnPageFlipEvent(unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds) {
+ time_of_last_flip_ =
+ static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
+ useconds;
+
+ surface_->SwapBuffers();
+}
+
+bool HardwareDisplayController::SetCursor(ScanoutSurface* surface) {
+ bool ret = drm_->SetCursor(crtc_id_,
+ surface->GetHandle(),
+ surface->Size().width(),
+ surface->Size().height());
+ surface->SwapBuffers();
+ return ret;
+}
+
+bool HardwareDisplayController::UnsetCursor() {
+ return drm_->SetCursor(crtc_id_, 0, 0, 0);
+}
+
+bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
+ if (is_disabled_)
+ return true;
+
+ return drm_->MoveCursor(crtc_id_, location.x(), location.y());
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/hardware_display_controller.h b/chromium/ui/ozone/platform/dri/hardware_display_controller.h
new file mode 100644
index 00000000000..b6ac900c44d
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/hardware_display_controller.h
@@ -0,0 +1,182 @@
+// 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_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
+#define UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <xf86drmMode.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+class ScanoutSurface;
+
+// The HDCOz will handle modesettings and scannout operations for hardware
+// devices.
+//
+// In the DRM world there are 3 components that need to be paired up to be able
+// to display an image to the monitor: CRTC (cathode ray tube controller),
+// encoder and connector. The CRTC determines which framebuffer to read, when
+// to scanout and where to scanout. Encoders converts the stream from the CRTC
+// to the appropriate format for the connector. The connector is the physical
+// connection that monitors connect to.
+//
+// There is no 1:1:1 pairing for these components. It is possible for an encoder
+// to be compatible to multiple CRTCs and each connector can be used with
+// multiple encoders. In addition, it is possible to use one CRTC with multiple
+// connectors such that we can display the same image on multiple monitors.
+//
+// For example, the following configuration shows 2 different screens being
+// initialized separately.
+// ------------- -------------
+// | Connector | | Connector |
+// | HDMI | | VGA |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | Encoder1 | | Encoder2 |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | CRTC1 | | CRTC2 |
+// ------------- -------------
+//
+// In the following configuration 2 different screens are associated with the
+// same CRTC, so on scanout the same framebuffer will be displayed on both
+// monitors.
+// ------------- -------------
+// | Connector | | Connector |
+// | HDMI | | VGA |
+// ------------- -------------
+// ^ ^
+// | |
+// ------------- -------------
+// | Encoder1 | | Encoder2 |
+// ------------- -------------
+// ^ ^
+// | |
+// ----------------------
+// | CRTC1 |
+// ----------------------
+//
+// Note that it is possible to have more connectors than CRTCs which means that
+// only a subset of connectors can be active independently, showing different
+// framebuffers. Though, in this case, it would be possible to have all
+// connectors active if some use the same CRTC to mirror the display.
+//
+// TODO(dnicoara) Need to have a way to detect events (such as monitor
+// connected or disconnected).
+class OZONE_EXPORT HardwareDisplayController
+ : public base::SupportsWeakPtr<HardwareDisplayController> {
+ public:
+ HardwareDisplayController(DriWrapper* drm,
+ uint32_t connector_id,
+ uint32_t crtc_id);
+
+ ~HardwareDisplayController();
+
+ // Associate the HDCO with a surface implementation and initialize it.
+ bool BindSurfaceToController(scoped_ptr<ScanoutSurface> surface,
+ drmModeModeInfo mode);
+
+ void UnbindSurfaceFromController();
+
+ // Reconfigures the CRTC with the current surface and mode.
+ bool Enable();
+
+ // Disables the CRTC.
+ void Disable();
+
+ // Schedules the |surface_|'s framebuffer to be displayed on the next vsync
+ // event. The event will be posted on the graphics card file descriptor |fd_|
+ // and it can be read and processed by |drmHandleEvent|. That function can
+ // define the callback for the page flip event. A generic data argument will
+ // be presented to the callback. We use that argument to pass in the HDCO
+ // object the event belongs to.
+ //
+ // Between this call and the callback, the framebuffer used in this call
+ // should not be modified in any way as it would cause screen tearing if the
+ // hardware performed the flip. Note that the frontbuffer should also not
+ // be modified as it could still be displayed.
+ //
+ // Note that this function does not block. Also, this function should not be
+ // called again before the page flip occurrs.
+ //
+ // Returns true if the page flip was successfully registered, false otherwise.
+ bool SchedulePageFlip();
+
+ // TODO(dnicoara) This should be on the MessageLoop when Ozone can have
+ // BeginFrame can be triggered explicitly by Ozone.
+ void WaitForPageFlipEvent();
+
+ // Called when the page flip event occurred. The event is provided by the
+ // kernel when a VBlank event finished. This allows the controller to
+ // update internal state and propagate the update to the surface.
+ // The tuple (seconds, useconds) represents the event timestamp. |seconds|
+ // represents the number of seconds while |useconds| represents the
+ // microseconds (< 1 second) in the timestamp.
+ void OnPageFlipEvent(unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds);
+
+ // Set the hardware cursor to show the contents of |surface|.
+ bool SetCursor(ScanoutSurface* surface);
+
+ bool UnsetCursor();
+
+ // Moves the hardware cursor to |location|.
+ bool MoveCursor(const gfx::Point& location);
+
+ const drmModeModeInfo& get_mode() const { return mode_; };
+ uint32_t connector_id() const { return connector_id_; }
+ uint32_t crtc_id() const { return crtc_id_; }
+ ScanoutSurface* surface() const {
+ return surface_.get();
+ };
+
+ uint64_t get_time_of_last_flip() const {
+ return time_of_last_flip_;
+ };
+
+ private:
+ // Object containing the connection to the graphics device and wraps the API
+ // calls to control it.
+ DriWrapper* drm_;
+
+ // TODO(dnicoara) Need to allow a CRTC to have multiple connectors.
+ uint32_t connector_id_;
+
+ uint32_t crtc_id_;
+
+ // TODO(dnicoara) Need to store all the modes.
+ drmModeModeInfo mode_;
+
+ scoped_ptr<ScanoutSurface> surface_;
+
+ uint64_t time_of_last_flip_;
+
+ // Keeps track of the CRTC state. If a surface has been bound, then the value
+ // is set to false. Otherwise it is true.
+ bool is_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
diff --git a/chromium/ui/ozone/platform/dri/hardware_display_controller_unittest.cc b/chromium/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
new file mode 100644
index 00000000000..25169453b2d
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
@@ -0,0 +1,112 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/test/mock_dri_surface.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+
+namespace {
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay);
+
+} // namespace
+
+class HardwareDisplayControllerTest : public testing::Test {
+ public:
+ HardwareDisplayControllerTest() {}
+ virtual ~HardwareDisplayControllerTest() {}
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+ protected:
+ scoped_ptr<ui::HardwareDisplayController> controller_;
+ scoped_ptr<ui::MockDriWrapper> drm_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerTest);
+};
+
+void HardwareDisplayControllerTest::SetUp() {
+ drm_.reset(new ui::MockDriWrapper(3));
+ controller_.reset(new ui::HardwareDisplayController(drm_.get(), 1, 1));
+}
+
+void HardwareDisplayControllerTest::TearDown() {
+ controller_.reset();
+ drm_.reset();
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateAfterSurfaceIsBound) {
+ scoped_ptr<ui::ScanoutSurface> surface(
+ new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ EXPECT_TRUE(controller_->surface() != NULL);
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
+ scoped_ptr<ui::ScanoutSurface> surface(
+ new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ EXPECT_TRUE(controller_->surface() != NULL);
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
+ drm_->set_set_crtc_expectation(false);
+
+ scoped_ptr<ui::ScanoutSurface> surface(
+ new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_FALSE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ EXPECT_EQ(NULL, controller_->surface());
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
+ drm_->set_page_flip_expectation(false);
+
+ scoped_ptr<ui::ScanoutSurface> surface(
+ new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ EXPECT_FALSE(controller_->SchedulePageFlip());
+}
+
+TEST_F(HardwareDisplayControllerTest, VerifyNoDRMCallsWhenDisabled) {
+ scoped_ptr<ui::ScanoutSurface> surface(
+ new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ controller_->Disable();
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ EXPECT_EQ(0, drm_->get_page_flip_call_count());
+
+ surface.reset(new ui::MockDriSurface(drm_.get(), kDefaultModeSize));
+
+ EXPECT_TRUE(surface->Initialize());
+ EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass(),
+ kDefaultMode));
+ EXPECT_TRUE(controller_->SchedulePageFlip());
+ EXPECT_EQ(1, drm_->get_page_flip_call_count());
+}
diff --git a/chromium/ui/ozone/platform/dri/ozone_platform_dri.cc b/chromium/ui/ozone/platform/dri/ozone_platform_dri.cc
index 9feb9a2e3e7..1a703300bbb 100644
--- a/chromium/ui/ozone/platform/dri/ozone_platform_dri.cc
+++ b/chromium/ui/ozone/platform/dri/ozone_platform_dri.cc
@@ -4,21 +4,117 @@
#include "ui/ozone/platform/dri/ozone_platform_dri.h"
+#include "base/at_exit.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/ozone/ozone_platform.h"
+#include "ui/ozone/platform/dri/cursor_factory_evdev_dri.h"
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/dri_surface_factory.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/virtual_terminal_manager.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+#include "ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h"
+#endif
namespace ui {
-OzonePlatformDri::OzonePlatformDri() {}
+namespace {
+
+const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
+
+class DriSurfaceGenerator : public ScanoutSurfaceGenerator {
+ public:
+ DriSurfaceGenerator(DriWrapper* dri) : dri_(dri) {}
+ virtual ~DriSurfaceGenerator() {}
+
+ virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE {
+ return new DriSurface(dri_, size);
+ }
+
+ private:
+ DriWrapper* dri_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(DriSurfaceGenerator);
+};
+
+// OzonePlatform for Linux DRI (Direct Rendering Infrastructure)
+//
+// This platform is Linux without any display server (no X, wayland, or
+// anything). This means chrome alone owns the display and input devices.
+class OzonePlatformDri : public OzonePlatform {
+ public:
+ OzonePlatformDri()
+ : vt_manager_(new VirtualTerminalManager()),
+ dri_(new DriWrapper(kDefaultGraphicsCardPath)),
+ surface_generator_(new DriSurfaceGenerator(dri_.get())),
+ screen_manager_(new ScreenManager(dri_.get(),
+ surface_generator_.get())),
+ device_manager_(CreateDeviceManager()) {
+ base::AtExitManager::RegisterTask(
+ base::Bind(&base::DeletePointer<OzonePlatformDri>, this));
+ }
+ virtual ~OzonePlatformDri() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE {
+ return event_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return NULL; // no GPU support
+ }
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateDri(
+ dri_.get(), screen_manager_.get(), device_manager_.get()));
+ }
+ virtual scoped_ptr<TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() OVERRIDE {
+ return scoped_ptr<TouchscreenDeviceManager>(
+ new TouchscreenDeviceManagerOzone());
+ }
+#endif
+ virtual void InitializeUI() OVERRIDE {
+ surface_factory_ozone_.reset(
+ new DriSurfaceFactory(dri_.get(), screen_manager_.get()));
+ cursor_factory_ozone_.reset(
+ new CursorFactoryEvdevDri(surface_factory_ozone_.get()));
+ event_factory_ozone_.reset(new EventFactoryEvdev(
+ cursor_factory_ozone_.get(), device_manager_.get()));
+ }
+
+ virtual void InitializeGPU() OVERRIDE {}
+
+ private:
+ scoped_ptr<VirtualTerminalManager> vt_manager_;
+ scoped_ptr<DriWrapper> dri_;
+ scoped_ptr<DriSurfaceGenerator> surface_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DeviceManager> device_manager_;
-OzonePlatformDri::~OzonePlatformDri() {}
+ scoped_ptr<DriSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<CursorFactoryEvdevDri> cursor_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
-gfx::SurfaceFactoryOzone* OzonePlatformDri::GetSurfaceFactoryOzone() {
- return &surface_factory_ozone_;
-}
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformDri);
+};
-ui::EventFactoryOzone* OzonePlatformDri::GetEventFactoryOzone() {
- return &event_factory_ozone_;
-}
+} // namespace
OzonePlatform* CreateOzonePlatformDri() { return new OzonePlatformDri; }
diff --git a/chromium/ui/ozone/platform/dri/ozone_platform_dri.h b/chromium/ui/ozone/platform/dri/ozone_platform_dri.h
index 64df1cc357c..a63a0541dd9 100644
--- a/chromium/ui/ozone/platform/dri/ozone_platform_dri.h
+++ b/chromium/ui/ozone/platform/dri/ozone_platform_dri.h
@@ -5,30 +5,9 @@
#ifndef UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_DRI_H_
#define UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_DRI_H_
-#include "ui/events/ozone/evdev/event_factory.h"
-#include "ui/gfx/ozone/dri/dri_surface_factory.h"
-#include "ui/ozone/ozone_platform.h"
-
namespace ui {
-// OzonePlatform for Linux DRI (Direct Rendering Infrastructure)
-//
-// This platform is Linux without any display server (no X, wayland, or
-// anything). This means chrome alone owns the display and input devices.
-class OzonePlatformDri : public OzonePlatform {
- public:
- OzonePlatformDri();
- virtual ~OzonePlatformDri();
-
- virtual gfx::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE;
- virtual ui::EventFactoryOzone* GetEventFactoryOzone() OVERRIDE;
-
- private:
- gfx::DriSurfaceFactory surface_factory_ozone_;
- ui::EventFactoryEvdev event_factory_ozone_;
-
- DISALLOW_COPY_AND_ASSIGN(OzonePlatformDri);
-};
+class OzonePlatform;
// Constructor hook for use in ozone_platform_list.cc
OzonePlatform* CreateOzonePlatformDri();
diff --git a/chromium/ui/ozone/platform/dri/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/dri/ozone_platform_gbm.cc
new file mode 100644
index 00000000000..440614bcaf7
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/ozone_platform_gbm.cc
@@ -0,0 +1,146 @@
+// 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/ozone/platform/dri/ozone_platform_gbm.h"
+
+#include <dlfcn.h>
+#include <gbm.h>
+#include <stdlib.h>
+
+#include "base/at_exit.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/ozone/ozone_platform.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/gbm_surface.h"
+#include "ui/ozone/platform/dri/gbm_surface_factory.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/virtual_terminal_manager.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/ozone/common/chromeos/native_display_delegate_ozone.h"
+#include "ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+#endif
+
+namespace ui {
+
+namespace {
+
+const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
+
+class GbmSurfaceGenerator : public ScanoutSurfaceGenerator {
+ public:
+ GbmSurfaceGenerator(DriWrapper* dri)
+ : dri_(dri),
+ glapi_lib_(dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL)),
+ device_(gbm_create_device(dri_->get_fd())) {}
+ virtual ~GbmSurfaceGenerator() {
+ gbm_device_destroy(device_);
+ if (glapi_lib_)
+ dlclose(glapi_lib_);
+ }
+
+ gbm_device* device() const { return device_; }
+
+ virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE {
+ return new GbmSurface(device_, dri_, size);
+ }
+
+ private:
+ DriWrapper* dri_; // Not owned.
+
+ // HACK: gbm drivers have broken linkage
+ void *glapi_lib_;
+
+ gbm_device* device_;
+
+ DISALLOW_COPY_AND_ASSIGN(GbmSurfaceGenerator);
+};
+
+class OzonePlatformGbm : public OzonePlatform {
+ public:
+ OzonePlatformGbm() {
+ base::AtExitManager::RegisterTask(
+ base::Bind(&base::DeletePointer<OzonePlatformGbm>, this));
+ }
+ virtual ~OzonePlatformGbm() {}
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE {
+ return event_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return gpu_platform_support_.get()
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return gpu_platform_support_host_.get();
+ }
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+ virtual scoped_ptr<TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() OVERRIDE {
+ return scoped_ptr<TouchscreenDeviceManager>(
+ new TouchscreenDeviceManagerOzone());
+ }
+#endif
+ virtual void InitializeUI() OVERRIDE {
+ vt_manager_.reset(new VirtualTerminalManager());
+ // Needed since the browser process creates the accelerated widgets and that
+ // happens through SFO.
+ surface_factory_ozone_.reset(new GbmSurfaceFactory(NULL, NULL, NULL));
+
+ device_manager_ = CreateDeviceManager();
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ event_factory_ozone_.reset(new EventFactoryEvdev(
+ NULL, device_manager_.get()));
+
+ gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {
+ dri_.reset(new DriWrapper(kDefaultGraphicsCardPath));
+ surface_generator_.reset(new GbmSurfaceGenerator(dri_.get()));
+ screen_manager_.reset(new ScreenManager(dri_.get(),
+ surface_generator_.get()));
+ surface_factory_ozone_.reset(
+ new GbmSurfaceFactory(dri_.get(),
+ surface_generator_->device(),
+ screen_manager_.get()));
+
+ gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
+ }
+
+ private:
+ scoped_ptr<VirtualTerminalManager> vt_manager_;
+ scoped_ptr<DriWrapper> dri_;
+ scoped_ptr<GbmSurfaceGenerator> surface_generator_;
+ scoped_ptr<ScreenManager> screen_manager_;
+ scoped_ptr<DeviceManager> device_manager_;
+
+ scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+
+ scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
+ scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformGbm() { return new OzonePlatformGbm; }
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/ozone_platform_gbm.h b/chromium/ui/ozone/platform/dri/ozone_platform_gbm.h
new file mode 100644
index 00000000000..47f5ca7d05b
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/ozone_platform_gbm.h
@@ -0,0 +1,17 @@
+// 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_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_
+#define UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformGbm();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_OZONE_PLATFORM_GBM_H_
diff --git a/chromium/ui/ozone/platform/dri/scanout_surface.h b/chromium/ui/ozone/platform/dri/scanout_surface.h
new file mode 100644
index 00000000000..d362ae18e81
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/scanout_surface.h
@@ -0,0 +1,84 @@
+// 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_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_
+
+#include <stdint.h>
+
+namespace gfx {
+class Size;
+}
+
+namespace ui {
+
+// ScanoutSurface is an interface for a surface that can be scanned out to a
+// monitor using the DRM/KMS API. Implementations will store the internal state
+// associated with the drawing surface. Implementations are also required to
+// performs all the needed operations to initialize and update the drawing
+// surface.
+//
+// The typical usage pattern is:
+// -----------------------------------------------------------------------------
+// HardwareDisplayController controller;
+// // Initialize controller
+//
+// ScanoutSurface* surface = new ScanoutSurfaceImpl(size);
+// surface.Initialize();
+// controller.BindSurfaceToController(surface);
+//
+// while (true) {
+// DrawIntoSurface(surface);
+// controller.SchedulePageFlip();
+//
+// Wait for page flip event. The DRM page flip handler will call
+// surface.SwapBuffers();
+// }
+//
+// delete surface;
+// -----------------------------------------------------------------------------
+// In the above example the wait consists of reading a DRM pageflip event from
+// the graphics card file descriptor. This is done by calling |drmHandleEvent|,
+// which will read and process the event. |drmHandleEvent| will call a callback
+// registered by |SchedulePageFlip| which will update the internal state.
+//
+// |SchedulePageFlip| can also be used to limit drawing to the screen's vsync
+// since page flips only happen on vsync. In a threaded environment a message
+// loop would listen on the graphics card file descriptor for an event and
+// |drmHandleEvent| would be called from the message loop. The event handler
+// would also be responsible for updating the renderer's state and signal that
+// it is OK to start drawing the next frame.
+class ScanoutSurface {
+ public:
+ virtual ~ScanoutSurface() {}
+
+ // Used to allocate all necessary buffers for this surface. If the
+ // initialization succeeds, the device is ready to be used for drawing
+ // operations.
+ // Returns true if the initialization is successful, false otherwise.
+ virtual bool Initialize() = 0;
+
+ // Swaps the back buffer with the front buffer.
+ virtual void SwapBuffers() = 0;
+
+ // Returns the ID of the current backbuffer.
+ virtual uint32_t GetFramebufferId() const = 0;
+
+ // Returns the handle of the current backbuffer.
+ virtual uint32_t GetHandle() const = 0;
+
+ // Returns the surface size.
+ virtual gfx::Size Size() const = 0;
+};
+
+class ScanoutSurfaceGenerator {
+ public:
+ virtual ~ScanoutSurfaceGenerator() {}
+
+ virtual ScanoutSurface* Create(const gfx::Size& size) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_SCANOUT_SURFACE_H_
diff --git a/chromium/ui/ozone/platform/dri/screen_manager.cc b/chromium/ui/ozone/platform/dri/screen_manager.cc
new file mode 100644
index 00000000000..3c1655c77d2
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/screen_manager.cc
@@ -0,0 +1,137 @@
+// 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/ozone/platform/dri/screen_manager.h"
+
+#include <xf86drmMode.h>
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/dri/dri_util.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/scanout_surface.h"
+
+namespace ui {
+
+ScreenManager::ScreenManager(
+ DriWrapper* dri, ScanoutSurfaceGenerator* surface_generator)
+ : dri_(dri), surface_generator_(surface_generator), last_added_widget_(0) {
+}
+
+ScreenManager::~ScreenManager() {
+ STLDeleteContainerPairSecondPointers(
+ controllers_.begin(), controllers_.end());
+}
+
+void ScreenManager::RemoveDisplayController(uint32_t crtc, uint32_t connector) {
+ HardwareDisplayControllerMap::iterator it =
+ FindDisplayController(crtc, connector);
+ if (it != controllers_.end()) {
+ delete it->second;
+ controllers_.erase(it);
+ }
+}
+
+bool ScreenManager::ConfigureDisplayController(uint32_t crtc,
+ uint32_t connector,
+ const drmModeModeInfo& mode) {
+ HardwareDisplayControllerMap::iterator it =
+ FindDisplayController(crtc, connector);
+ HardwareDisplayController* controller = NULL;
+ if (it != controllers_.end()) {
+ if (SameMode(mode, it->second->get_mode()))
+ return it->second->Enable();
+
+ controller = it->second;
+ controller->UnbindSurfaceFromController();
+ }
+
+ if (it == controllers_.end()) {
+ controller = new HardwareDisplayController(dri_, connector, crtc);
+ controllers_.insert(std::make_pair(++last_added_widget_, controller));
+ }
+
+ // Create a surface suitable for the current controller.
+ scoped_ptr<ScanoutSurface> surface(
+ surface_generator_->Create(gfx::Size(mode.hdisplay, mode.vdisplay)));
+
+ if (!surface->Initialize()) {
+ LOG(ERROR) << "Failed to initialize surface";
+ return false;
+ }
+
+ // Bind the surface to the controller. This will register the backing buffers
+ // with the hardware CRTC such that we can show the buffers and performs the
+ // initial modeset. The controller takes ownership of the surface.
+ if (!controller->BindSurfaceToController(surface.Pass(), mode)) {
+ LOG(ERROR) << "Failed to bind surface to controller";
+ return false;
+ }
+
+ return true;
+}
+
+bool ScreenManager::DisableDisplayController(uint32_t crtc,
+ uint32_t connector) {
+ HardwareDisplayControllerMap::iterator it =
+ FindDisplayController(crtc, connector);
+ if (it != controllers_.end()) {
+ it->second->Disable();
+ return true;
+ }
+
+ return false;
+}
+
+base::WeakPtr<HardwareDisplayController> ScreenManager::GetDisplayController(
+ gfx::AcceleratedWidget widget) {
+ // TODO(dnicoara): Remove hack once TestScreen uses a simple Ozone display
+ // configuration reader and ScreenManager is called from there to create the
+ // one display needed by the content_shell target.
+ if (controllers_.empty() && last_added_widget_ == 0)
+ ForceInitializationOfPrimaryDisplay();
+
+ HardwareDisplayControllerMap::iterator it = controllers_.find(widget);
+ if (it != controllers_.end())
+ return it->second->AsWeakPtr();
+
+ return base::WeakPtr<HardwareDisplayController>();
+}
+
+ScreenManager::HardwareDisplayControllerMap::iterator
+ScreenManager::FindDisplayController(uint32_t crtc, uint32_t connector) {
+ for (HardwareDisplayControllerMap::iterator it = controllers_.begin();
+ it != controllers_.end();
+ ++it) {
+ if (it->second->connector_id() == connector &&
+ it->second->crtc_id() == crtc)
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+void ScreenManager::ForceInitializationOfPrimaryDisplay() {
+ drmModeRes* resources = drmModeGetResources(dri_->get_fd());
+ DCHECK(resources) << "Failed to get DRM resources";
+ ScopedVector<HardwareDisplayControllerInfo> displays =
+ GetAvailableDisplayControllerInfos(dri_->get_fd(), resources);
+ drmModeFreeResources(resources);
+
+ CHECK_NE(0u, displays.size());
+
+ drmModePropertyRes* dpms =
+ dri_->GetProperty(displays[0]->connector(), "DPMS");
+ if (dpms)
+ dri_->SetProperty(displays[0]->connector()->connector_id,
+ dpms->prop_id,
+ DRM_MODE_DPMS_ON);
+
+ ConfigureDisplayController(displays[0]->crtc()->crtc_id,
+ displays[0]->connector()->connector_id,
+ displays[0]->connector()->modes[0]);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/screen_manager.h b/chromium/ui/ozone/platform/dri/screen_manager.h
new file mode 100644
index 00000000000..fbe7bbb75df
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/screen_manager.h
@@ -0,0 +1,83 @@
+// 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_OZONE_PLATFORM_DRI_SCREEN_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_SCREEN_MANAGER_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+typedef struct _drmModeModeInfo drmModeModeInfo;
+
+namespace gfx {
+class Point;
+class Rect;
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DriWrapper;
+class ScanoutSurfaceGenerator;
+
+// Responsible for keeping track of active displays and configuring them.
+class OZONE_EXPORT ScreenManager {
+ public:
+ ScreenManager(DriWrapper* dri, ScanoutSurfaceGenerator* surface_generator);
+ virtual ~ScreenManager();
+
+ // Remove a display controller from the list of active controllers. The
+ // controller is removed since it was disconnected.
+ void RemoveDisplayController(uint32_t crtc, uint32_t connector);
+
+ // Configure (and add if not present) a display controller. The display
+ // controller is identified by (|crtc|, |connector|) and the controller is
+ // modeset using |mode|.
+ bool ConfigureDisplayController(uint32_t crtc,
+ uint32_t connector,
+ const drmModeModeInfo& mode);
+
+ // Disable the display controller identified by (|crtc|, |connector|). Note,
+ // the controller may still be connected, so this does not remove the
+ // controller.
+ bool DisableDisplayController(uint32_t crtc, uint32_t connector);
+
+ // Returns a reference to the display controller associated with |widget|.
+ // This returns a weak reference since the display controller may be destroyed
+ // at any point in time, but the changes are propagated to the compositor much
+ // later (Compositor owns SurfaceOzone*, which is responsible for updating the
+ // display surface).
+ base::WeakPtr<HardwareDisplayController> GetDisplayController(
+ gfx::AcceleratedWidget widget);
+
+ private:
+ typedef std::map<gfx::AcceleratedWidget, HardwareDisplayController*>
+ HardwareDisplayControllerMap;
+
+ // Returns an iterator into |controllers_| for the controller identified by
+ // (|crtc|, |connector|).
+ HardwareDisplayControllerMap::iterator FindDisplayController(
+ uint32_t crtc, uint32_t connector);
+
+ // On non CrOS builds there is no display configurator to look-up available
+ // displays and initialize the HDCs. In such cases this is called internally
+ // to initialize a display.
+ virtual void ForceInitializationOfPrimaryDisplay();
+
+ DriWrapper* dri_; // Not owned.
+ ScanoutSurfaceGenerator* surface_generator_; // Not owned.
+ // Mapping between an accelerated widget and an active display.
+ HardwareDisplayControllerMap controllers_;
+ gfx::AcceleratedWidget last_added_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_SCREEN_MANAGER_H_
diff --git a/chromium/ui/ozone/platform/dri/screen_manager_unittest.cc b/chromium/ui/ozone/platform/dri/screen_manager_unittest.cc
new file mode 100644
index 00000000000..0851000a385
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/screen_manager_unittest.cc
@@ -0,0 +1,116 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+#include "ui/ozone/platform/dri/screen_manager.h"
+#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_surface_generator.h"
+
+namespace {
+
+// Create a basic mode for a 6x4 screen.
+const drmModeModeInfo kDefaultMode =
+ {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
+
+class MockScreenManager : public ui::ScreenManager {
+ public:
+ MockScreenManager(ui::DriWrapper* dri,
+ ui::ScanoutSurfaceGenerator* surface_generator)
+ : ScreenManager(dri, surface_generator), dri_(dri) {}
+
+ virtual void ForceInitializationOfPrimaryDisplay() OVERRIDE {}
+
+ private:
+ ui::DriWrapper* dri_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockScreenManager);
+};
+
+} // namespace
+
+class ScreenManagerTest : public testing::Test {
+ public:
+ ScreenManagerTest() {}
+ virtual ~ScreenManagerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ dri_.reset(new ui::MockDriWrapper(3));
+ surface_generator_.reset(new ui::MockSurfaceGenerator(dri_.get()));
+ screen_manager_.reset(new MockScreenManager(
+ dri_.get(), surface_generator_.get()));
+ }
+ virtual void TearDown() OVERRIDE {
+ screen_manager_.reset();
+ dri_.reset();
+ }
+
+ protected:
+ scoped_ptr<ui::MockDriWrapper> dri_;
+ scoped_ptr<ui::MockSurfaceGenerator> surface_generator_;
+ scoped_ptr<MockScreenManager> screen_manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenManagerTest);
+};
+
+TEST_F(ScreenManagerTest, CheckWithNoControllers) {
+ EXPECT_FALSE(screen_manager_->GetDisplayController(1));
+}
+
+TEST_F(ScreenManagerTest, CheckWithValidController) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+ base::WeakPtr<ui::HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(1);
+
+ EXPECT_TRUE(controller);
+ EXPECT_EQ(1u, controller->crtc_id());
+ EXPECT_EQ(2u, controller->connector_id());
+}
+
+TEST_F(ScreenManagerTest, CheckWithInvalidId) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(1));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(2));
+}
+
+TEST_F(ScreenManagerTest, CheckForSecondValidController) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+ screen_manager_->ConfigureDisplayController(3, 4, kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(1));
+ EXPECT_TRUE(screen_manager_->GetDisplayController(2));
+}
+
+TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+ base::WeakPtr<ui::HardwareDisplayController> controller =
+ screen_manager_->GetDisplayController(1);
+
+ EXPECT_TRUE(controller);
+ screen_manager_->RemoveDisplayController(1, 2);
+ EXPECT_FALSE(controller);
+}
+
+TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(1));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(2));
+}
+
+TEST_F(ScreenManagerTest, CheckChangingMode) {
+ screen_manager_->ConfigureDisplayController(1, 2, kDefaultMode);
+ drmModeModeInfo new_mode = kDefaultMode;
+ new_mode.vdisplay = 10;
+ screen_manager_->ConfigureDisplayController(1, 2, new_mode);
+
+ EXPECT_TRUE(screen_manager_->GetDisplayController(1));
+ EXPECT_FALSE(screen_manager_->GetDisplayController(2));
+ drmModeModeInfo mode = screen_manager_->GetDisplayController(1)->get_mode();
+ EXPECT_EQ(new_mode.vdisplay, mode.vdisplay);
+ EXPECT_EQ(new_mode.hdisplay, mode.hdisplay);
+}
diff --git a/chromium/ui/ozone/platform/dri/test/mock_dri_surface.cc b/chromium/ui/ozone/platform/dri/test/mock_dri_surface.cc
new file mode 100644
index 00000000000..4e0131110f5
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_dri_surface.cc
@@ -0,0 +1,53 @@
+// 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/ozone/platform/dri/test/mock_dri_surface.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/dri_buffer.h"
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+namespace {
+
+class MockDriBuffer : public DriBuffer {
+ public:
+ MockDriBuffer(DriWrapper* dri, bool initialize_expectation)
+ : DriBuffer(dri), initialize_expectation_(initialize_expectation) {}
+ virtual ~MockDriBuffer() { surface_.clear(); }
+
+ virtual bool Initialize(const SkImageInfo& info) OVERRIDE {
+ if (!initialize_expectation_)
+ return false;
+
+ dri_->AddFramebuffer(
+ info.width(), info.height(), 24, 32, stride_, handle_, &framebuffer_);
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
+ surface_->getCanvas()->clear(SK_ColorBLACK);
+
+ return true;
+ }
+
+ private:
+ bool initialize_expectation_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriBuffer);
+};
+
+} // namespace
+
+MockDriSurface::MockDriSurface(DriWrapper* dri, const gfx::Size& size)
+ : DriSurface(dri, size), dri_(dri), initialize_expectation_(true) {}
+
+MockDriSurface::~MockDriSurface() {}
+
+DriBuffer* MockDriSurface::CreateBuffer() {
+ MockDriBuffer* bitmap = new MockDriBuffer(dri_, initialize_expectation_);
+ bitmaps_.push_back(bitmap);
+
+ return bitmap;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/test/mock_dri_surface.h b/chromium/ui/ozone/platform/dri/test/mock_dri_surface.h
new file mode 100644
index 00000000000..61b9a9f7757
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_dri_surface.h
@@ -0,0 +1,45 @@
+// 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_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_SURFACE_H_
+#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_SURFACE_H_
+
+#include <vector>
+
+#include "ui/ozone/platform/dri/dri_surface.h"
+
+namespace gfx {
+class Size;
+} // namespace gfx
+
+namespace ui {
+
+class DriBuffer;
+class DriWrapper;
+
+class MockDriSurface : public DriSurface {
+ public:
+ MockDriSurface(DriWrapper* dri, const gfx::Size& size);
+ virtual ~MockDriSurface();
+
+ const std::vector<ui::DriBuffer*>& bitmaps() const { return bitmaps_; }
+ void set_initialize_expectation(bool state) {
+ initialize_expectation_ = state;
+ }
+
+ private:
+ // DriSurface:
+ virtual ui::DriBuffer* CreateBuffer() OVERRIDE;
+
+ DriWrapper* dri_; // Not owned.
+ std::vector<DriBuffer*> bitmaps_; // Not owned.
+
+ bool initialize_expectation_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_SURFACE_H_
diff --git a/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.cc b/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
new file mode 100644
index 00000000000..f950db2152f
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
@@ -0,0 +1,113 @@
+// 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/ozone/platform/dri/test/mock_dri_wrapper.h"
+
+#include <xf86drmMode.h>
+
+#include "ui/ozone/platform/dri/dri_surface.h"
+#include "ui/ozone/platform/dri/hardware_display_controller.h"
+
+namespace ui {
+
+MockDriWrapper::MockDriWrapper(int fd)
+ : DriWrapper(""),
+ get_crtc_call_count_(0),
+ free_crtc_call_count_(0),
+ restore_crtc_call_count_(0),
+ add_framebuffer_call_count_(0),
+ remove_framebuffer_call_count_(0),
+ page_flip_call_count_(0),
+ set_crtc_expectation_(true),
+ add_framebuffer_expectation_(true),
+ page_flip_expectation_(true) {
+ fd_ = fd;
+}
+
+MockDriWrapper::~MockDriWrapper() {
+ fd_ = -1;
+}
+
+drmModeCrtc* MockDriWrapper::GetCrtc(uint32_t crtc_id) {
+ get_crtc_call_count_++;
+ return new drmModeCrtc;
+}
+
+void MockDriWrapper::FreeCrtc(drmModeCrtc* crtc) {
+ free_crtc_call_count_++;
+ delete crtc;
+}
+
+bool MockDriWrapper::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ uint32_t* connectors,
+ drmModeModeInfo* mode) {
+ return set_crtc_expectation_;
+}
+
+bool MockDriWrapper::SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) {
+ restore_crtc_call_count_++;
+ return true;
+}
+
+bool MockDriWrapper::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ add_framebuffer_call_count_++;
+ *framebuffer = add_framebuffer_call_count_;
+ return add_framebuffer_expectation_;
+}
+
+bool MockDriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
+ remove_framebuffer_call_count_++;
+ return true;
+}
+
+bool MockDriWrapper::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) {
+ page_flip_call_count_++;
+ static_cast<ui::HardwareDisplayController*>(data)->surface()->SwapBuffers();
+ return page_flip_expectation_;
+}
+
+bool MockDriWrapper::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ return true;
+}
+
+void MockDriWrapper::FreeProperty(drmModePropertyRes* prop) {
+ delete prop;
+}
+
+drmModePropertyBlobRes* MockDriWrapper::GetPropertyBlob(
+ drmModeConnector* connector,
+ const char* name) {
+ return new drmModePropertyBlobRes;
+}
+
+void MockDriWrapper::FreePropertyBlob(drmModePropertyBlobRes* blob) {
+ delete blob;
+}
+
+bool MockDriWrapper::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height) {
+ return true;
+}
+
+bool MockDriWrapper::MoveCursor(uint32_t crtc_id, int x, int y) {
+ return true;
+}
+
+void MockDriWrapper::HandleEvent(drmEventContext& event) {
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.h b/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.h
new file mode 100644
index 00000000000..791d55c2ecd
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_dri_wrapper.h
@@ -0,0 +1,85 @@
+// 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_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
+#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
+
+#include "ui/ozone/platform/dri/dri_wrapper.h"
+
+namespace ui {
+
+// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
+class MockDriWrapper : public ui::DriWrapper {
+ public:
+ MockDriWrapper(int fd);
+ virtual ~MockDriWrapper();
+
+ int get_get_crtc_call_count() const { return get_crtc_call_count_; }
+ int get_free_crtc_call_count() const { return free_crtc_call_count_; }
+ int get_restore_crtc_call_count() const { return restore_crtc_call_count_; }
+ int get_add_framebuffer_call_count() const {
+ return add_framebuffer_call_count_;
+ }
+ int get_remove_framebuffer_call_count() const {
+ return remove_framebuffer_call_count_;
+ }
+ int get_page_flip_call_count() const { return page_flip_call_count_; }
+ void fail_init() { fd_ = -1; }
+ void set_set_crtc_expectation(bool state) { set_crtc_expectation_ = state; }
+ void set_page_flip_expectation(bool state) { page_flip_expectation_ = state; }
+ void set_add_framebuffer_expectation(bool state) {
+ add_framebuffer_expectation_ = state;
+ }
+
+ // DriWrapper:
+ virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE;
+ virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE;
+ virtual bool SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ uint32_t* connectors,
+ drmModeModeInfo* mode) OVERRIDE;
+ virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE;
+ virtual bool AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) OVERRIDE;
+ virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE;
+ virtual bool PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ void* data) OVERRIDE;
+ virtual bool SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) OVERRIDE;
+ virtual void FreeProperty(drmModePropertyRes* prop) OVERRIDE;
+ virtual drmModePropertyBlobRes* GetPropertyBlob(drmModeConnector* connector,
+ const char* name) OVERRIDE;
+ virtual void FreePropertyBlob(drmModePropertyBlobRes* blob) OVERRIDE;
+ virtual bool SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height) OVERRIDE;
+ virtual bool MoveCursor(uint32_t crtc_id, int x, int y) OVERRIDE;
+ virtual void HandleEvent(drmEventContext& event) OVERRIDE;
+
+ private:
+ int get_crtc_call_count_;
+ int free_crtc_call_count_;
+ int restore_crtc_call_count_;
+ int add_framebuffer_call_count_;
+ int remove_framebuffer_call_count_;
+ int page_flip_call_count_;
+
+ bool set_crtc_expectation_;
+ bool add_framebuffer_expectation_;
+ bool page_flip_expectation_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/dri/test/mock_surface_generator.cc b/chromium/ui/ozone/platform/dri/test/mock_surface_generator.cc
new file mode 100644
index 00000000000..97df5bdbd2c
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_surface_generator.cc
@@ -0,0 +1,18 @@
+// 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/ozone/platform/dri/test/mock_surface_generator.h"
+
+namespace ui {
+
+MockSurfaceGenerator::MockSurfaceGenerator(DriWrapper* dri) : dri_(dri) {}
+
+MockSurfaceGenerator::~MockSurfaceGenerator() {}
+
+ScanoutSurface* MockSurfaceGenerator::Create(const gfx::Size& size) {
+ surfaces_.push_back(new MockDriSurface(dri_, size));
+ return surfaces_.back();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/test/mock_surface_generator.h b/chromium/ui/ozone/platform/dri/test/mock_surface_generator.h
new file mode 100644
index 00000000000..d9b77f8620d
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/test/mock_surface_generator.h
@@ -0,0 +1,40 @@
+// 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_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_
+#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_
+
+#include <vector>
+
+#include "ui/ozone/platform/dri/test/mock_dri_surface.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace ui {
+
+class DriWrapper;
+
+class MockSurfaceGenerator : public ScanoutSurfaceGenerator {
+ public:
+ MockSurfaceGenerator(DriWrapper* dri);
+ virtual ~MockSurfaceGenerator();
+
+ std::vector<MockDriSurface*> surfaces() const { return surfaces_; }
+
+ // ScanoutSurfaceGenerator:
+ virtual ScanoutSurface* Create(const gfx::Size& size) OVERRIDE;
+
+ private:
+ DriWrapper* dri_; // Not owned.
+
+ std::vector<MockDriSurface*> surfaces_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSurfaceGenerator);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_TEST_MOCK_SURFACE_GENERATOR_H_
diff --git a/chromium/ui/ozone/platform/dri/virtual_terminal_manager.cc b/chromium/ui/ozone/platform/dri/virtual_terminal_manager.cc
new file mode 100644
index 00000000000..efd83504577
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/virtual_terminal_manager.cc
@@ -0,0 +1,75 @@
+// 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/ozone/platform/dri/virtual_terminal_manager.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+
+namespace ui {
+
+namespace {
+
+const char kTTYDevice[] = "/dev/tty1";
+
+const int kVT = 1;
+
+} // namespace
+
+VirtualTerminalManager::VirtualTerminalManager() {
+ // Use the current console.
+ fd_ = open(kTTYDevice, O_RDWR | O_CLOEXEC, 0);
+ if (fd_ < 0)
+ LOG(ERROR) << "Failed to open '" << kTTYDevice << "' " << strerror(errno);
+
+ if (ioctl(fd_, VT_ACTIVATE, kVT) || ioctl(fd_, VT_WAITACTIVE, kVT))
+ LOG(ERROR) << "Failed to switch to VT: " << kVT
+ << " error: " << strerror(errno);;
+
+ if (ioctl(fd_, KDGETMODE, &vt_mode_))
+ LOG(ERROR) << "Failed to get VT mode: " << strerror(errno);
+
+ if (ioctl(fd_, KDSETMODE, KD_GRAPHICS))
+ LOG(ERROR) << "Failed to set graphics mode: " << strerror(errno);
+
+ if (tcgetattr(fd_, &terminal_attributes_))
+ LOG(ERROR) << "Failed to get terminal attributes";
+
+ // Stop the TTY from processing keys and echo-ing them to the terminal.
+ struct termios raw_attributes = terminal_attributes_;
+ cfmakeraw(&raw_attributes);
+ raw_attributes.c_oflag |= OPOST;
+ if (tcsetattr(fd_, TCSANOW, &raw_attributes))
+ LOG(ERROR) << "Failed to set raw attributes";
+
+ if (ioctl(fd_, KDGKBMODE, &previous_keyboard_mode_))
+ LOG(ERROR) << "Failed to get keyboard mode";
+
+ if (ioctl(fd_, KDSKBMODE, K_OFF) && ioctl(fd_, KDSKBMODE, K_RAW))
+ LOG(ERROR) << "Failed to set keyboard mode";
+}
+
+VirtualTerminalManager::~VirtualTerminalManager() {
+ if (fd_ < 0)
+ return;
+
+ if (ioctl(fd_, KDSETMODE, &vt_mode_))
+ LOG(ERROR) << "Failed to restore VT mode";
+
+ if (ioctl(fd_, KDSKBMODE, previous_keyboard_mode_))
+ LOG(ERROR) << "Failed to restore keyboard mode";
+
+ if (tcsetattr(fd_, TCSANOW, &terminal_attributes_))
+ LOG(ERROR) << "Failed to restore terminal attributes";
+
+ close(fd_);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/dri/virtual_terminal_manager.h b/chromium/ui/ozone/platform/dri/virtual_terminal_manager.h
new file mode 100644
index 00000000000..11af0b0c2a2
--- /dev/null
+++ b/chromium/ui/ozone/platform/dri/virtual_terminal_manager.h
@@ -0,0 +1,31 @@
+// 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_OZONE_PLATFORM_DRI_VIRTUAL_TERMINAL_MANAGER_H_
+#define UI_OZONE_PLATFORM_DRI_VIRTUAL_TERMINAL_MANAGER_H_
+
+#include <termios.h>
+
+#include "base/basictypes.h"
+
+namespace ui {
+
+class VirtualTerminalManager {
+ public:
+ VirtualTerminalManager();
+ ~VirtualTerminalManager();
+
+ private:
+
+ int fd_;
+ int vt_mode_;
+ int previous_keyboard_mode_;
+ struct termios terminal_attributes_;
+
+ DISALLOW_COPY_AND_ASSIGN(VirtualTerminalManager);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_DRI_VIRTUAL_TERMINAL_MANAGER_H_
diff --git a/chromium/ui/ozone/platform/egltest/eglplatform_shim.h b/chromium/ui/ozone/platform/egltest/eglplatform_shim.h
new file mode 100644
index 00000000000..ce7cce9838f
--- /dev/null
+++ b/chromium/ui/ozone/platform/egltest/eglplatform_shim.h
@@ -0,0 +1,58 @@
+// 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 __eglplatform_shim_h_
+#define __eglplatform_shim_h_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHIM_EXPORT __attribute__((visibility("default")))
+
+// Simple integral native window identifier.
+// NB: Unlike EGLNativeWindowType, this will be shipped between processes.
+typedef int ShimNativeWindowId;
+#define SHIM_NO_WINDOW_ID ((ShimNativeWindowId)0)
+
+// Opaque versions of EGL types (as used by ozone).
+typedef intptr_t ShimEGLNativeDisplayType;
+typedef intptr_t ShimEGLNativeWindowType;
+
+// QueryString targets
+#define SHIM_EGL_LIBRARY 0x1001
+#define SHIM_GLES_LIBRARY 0x1002
+
+// CreateWindow / QueryWindow attributes
+#define SHIM_WINDOW_WIDTH 0x0001
+#define SHIM_WINDOW_HEIGHT 0x0002
+
+// Query global implementation information.
+SHIM_EXPORT const char* ShimQueryString(int name);
+
+// Init/terminate library.
+SHIM_EXPORT bool ShimInitialize(void);
+SHIM_EXPORT bool ShimTerminate(void);
+
+// Create window handle & query window properties (called from browser process).
+SHIM_EXPORT ShimNativeWindowId ShimCreateWindow(void);
+SHIM_EXPORT bool ShimQueryWindow(ShimNativeWindowId window_id,
+ int attribute,
+ int* value);
+SHIM_EXPORT bool ShimDestroyWindow(ShimNativeWindowId window_id);
+
+// Manage actual EGL platform objects (called from GPU process).
+SHIM_EXPORT ShimEGLNativeDisplayType ShimGetNativeDisplay(void);
+SHIM_EXPORT ShimEGLNativeWindowType
+ ShimGetNativeWindow(ShimNativeWindowId native_window_id);
+SHIM_EXPORT bool ShimReleaseNativeWindow(ShimEGLNativeWindowType native_window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __eglplatform_shim_h */
diff --git a/chromium/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc b/chromium/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc
new file mode 100644
index 00000000000..af1228d0fc0
--- /dev/null
+++ b/chromium/ui/ozone/platform/egltest/eglplatform_shim_xeleven.cc
@@ -0,0 +1,106 @@
+// 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/ozone/platform/egltest/eglplatform_shim.h"
+
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+Display* g_display;
+
+const int kDefaultX = 0;
+const int kDefaultY = 0;
+const int kDefaultWidth = 800;
+const int kDefaultHeight = 600;
+const int kDefaultBorderWidth = 0;
+
+const char* ShimQueryString(int name) {
+ switch (name) {
+ case SHIM_EGL_LIBRARY:
+ return "libEGL.so.1";
+ case SHIM_GLES_LIBRARY:
+ return "libGLESv2.so.2";
+ default:
+ return NULL;
+ }
+}
+
+bool ShimInitialize(void) {
+ g_display = XOpenDisplay(NULL);
+ return g_display != NULL;
+}
+
+bool ShimTerminate(void) {
+ XCloseDisplay(g_display);
+ return true;
+}
+
+ShimNativeWindowId ShimCreateWindow(void) {
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.event_mask = 0;
+
+ Window window = XCreateWindow(g_display,
+ DefaultRootWindow(g_display),
+ kDefaultX,
+ kDefaultY,
+ kDefaultWidth,
+ kDefaultHeight,
+ kDefaultBorderWidth,
+ CopyFromParent,
+ InputOutput,
+ CopyFromParent,
+ CWEventMask,
+ &swa);
+
+ XMapWindow(g_display, window);
+ XStoreName(g_display, window, "EGL test");
+ XFlush(g_display);
+
+ return window;
+}
+
+bool ShimQueryWindow(ShimNativeWindowId window_id, int attribute, int* value) {
+ XWindowAttributes window_attributes;
+ switch (attribute) {
+ case SHIM_WINDOW_WIDTH:
+ XGetWindowAttributes(g_display, window_id, &window_attributes);
+ *value = window_attributes.width;
+ return true;
+ case SHIM_WINDOW_HEIGHT:
+ XGetWindowAttributes(g_display, window_id, &window_attributes);
+ *value = window_attributes.height;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ShimDestroyWindow(ShimNativeWindowId window_id) {
+ XDestroyWindow(g_display, window_id);
+ return true;
+}
+
+ShimEGLNativeDisplayType ShimGetNativeDisplay(void) {
+ return reinterpret_cast<ShimEGLNativeDisplayType>(g_display);
+}
+
+ShimEGLNativeWindowType ShimGetNativeWindow(
+ ShimNativeWindowId native_window_id) {
+ return native_window_id;
+}
+
+bool ShimReleaseNativeWindow(ShimEGLNativeWindowType native_window) {
+ return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/chromium/ui/ozone/platform/egltest/egltest.gypi b/chromium/ui/ozone/platform/egltest/egltest.gypi
new file mode 100644
index 00000000000..220099efa6e
--- /dev/null
+++ b/chromium/ui/ozone/platform/egltest/egltest.gypi
@@ -0,0 +1,107 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_egltest',
+ ],
+ 'internal_ozone_platforms': [
+ 'egltest'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_egltest',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone_evdev',
+ '../gfx/gfx.gyp:gfx',
+ 'eglplatform_shim',
+ ],
+ 'sources': [
+ 'ozone_platform_egltest.cc',
+ 'ozone_platform_egltest.h',
+ ],
+ },
+ {
+ 'target_name': 'eglplatform_shim',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
+ },
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'hard_dependency': 1,
+ 'actions': [
+ {
+ 'variables': {
+ 'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libeglplatform_shim.h',
+ 'output_cc': '<(INTERMEDIATE_DIR)/libeglplatform_shim_loader.cc',
+ 'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+ },
+ 'action_name': 'generate_libeglplatform_shim_loader',
+ 'inputs': [
+ '<(generator)',
+ ],
+ 'outputs': [
+ '<(output_h)',
+ '<(output_cc)',
+ ],
+ 'action': ['python',
+ '<(generator)',
+ '--name', 'LibeglplatformShimLoader',
+ '--output-h', '<(output_h)',
+ '--output-cc', '<(output_cc)',
+ '--header', '"ui/ozone/platform/egltest/eglplatform_shim.h"',
+ 'ShimQueryString',
+ 'ShimInitialize',
+ 'ShimTerminate',
+ 'ShimCreateWindow',
+ 'ShimQueryWindow',
+ 'ShimDestroyWindow',
+ 'ShimGetNativeDisplay',
+ 'ShimGetNativeWindow',
+ 'ShimReleaseNativeWindow',
+ ],
+ 'message': 'Generating libeglplatform_shim library loader',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+ 'conditions': [
+ ['ozone_platform_ozonex == 1', {
+ 'targets': [
+ {
+ 'target_name': 'eglplatform_shim_x11',
+ 'type': 'loadable_module',
+ 'product_name': 'eglplatform_shim',
+ 'product_extension': 'so.1',
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ ],
+ 'sources': [
+ 'eglplatform_shim.h',
+ 'eglplatform_shim_xeleven.cc',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.cc
new file mode 100644
index 00000000000..8179aa49135
--- /dev/null
+++ b/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -0,0 +1,304 @@
+// 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/ozone/platform/egltest/ozone_platform_egltest.h"
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "library_loaders/libeglplatform_shim.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/ozone_platform.h"
+#include "ui/ozone/ozone_switches.h"
+#include "ui/ozone/platform/test/file_surface_factory.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/gpu_platform_support.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/ozone/common/chromeos/native_display_delegate_ozone.h"
+#include "ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+#endif
+
+#include <EGL/egl.h>
+
+namespace ui {
+
+namespace {
+
+const char kEglplatformShim[] = "EGLPLATFORM_SHIM";
+const char kEglplatformShimDefault[] = "libeglplatform_shim.so.1";
+const char kDefaultEglSoname[] = "libEGL.so.1";
+const char kDefaultGlesSoname[] = "libGLESv2.so.2";
+
+// Get the library soname to load.
+std::string GetShimLibraryName() {
+ std::string library;
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->GetVar(kEglplatformShim, &library))
+ return library;
+ return kEglplatformShimDefault;
+}
+
+// EGL surface wrapper for libeglplatform_shim.
+//
+// This just manages the native window lifetime using
+// ShimGetNativeWindow & ShimReleaseNativeWindow.
+class SurfaceOzoneEgltest : public SurfaceOzoneEGL {
+ public:
+ SurfaceOzoneEgltest(ShimNativeWindowId window_id,
+ LibeglplatformShimLoader* eglplatform_shim)
+ : eglplatform_shim_(eglplatform_shim) {
+ native_window_ = eglplatform_shim_->ShimGetNativeWindow(window_id);
+ }
+ virtual ~SurfaceOzoneEgltest() {
+ CHECK(eglplatform_shim_->ShimReleaseNativeWindow(native_window_));
+ }
+
+ virtual intptr_t GetNativeWindow() OVERRIDE { return native_window_; }
+
+ virtual bool OnSwapBuffers() OVERRIDE { return true; }
+
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) OVERRIDE {
+ return true;
+ }
+
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
+ return scoped_ptr<gfx::VSyncProvider>();
+ }
+
+ private:
+ LibeglplatformShimLoader* eglplatform_shim_;
+ intptr_t native_window_;
+};
+
+// EGL surface factory for libeglplatform_shim.
+//
+// This finds the right EGL/GLES2 libraries for loading, and creates
+// a single native window via ShimCreateWindow for drawing
+// into.
+class SurfaceFactoryEgltest : public ui::SurfaceFactoryOzone {
+ public:
+ SurfaceFactoryEgltest(LibeglplatformShimLoader* eglplatform_shim)
+ : eglplatform_shim_(eglplatform_shim), window_id_(SHIM_NO_WINDOW_ID) {}
+ virtual ~SurfaceFactoryEgltest() { DestroySingleWindow(); }
+
+ // Create the window.
+ bool CreateSingleWindow();
+ void DestroySingleWindow();
+
+ // SurfaceFactoryOzone:
+ virtual HardwareState InitializeHardware() OVERRIDE;
+ virtual void ShutdownHardware() OVERRIDE;
+ virtual intptr_t GetNativeDisplay() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) OVERRIDE;
+ virtual const int32* GetEGLSurfaceProperties(
+ const int32* desired_list) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ private:
+ LibeglplatformShimLoader* eglplatform_shim_;
+
+ // TODO(spang): Remove once we have a windowing API. This limits to 1 window.
+ ShimNativeWindowId window_id_;
+};
+
+bool SurfaceFactoryEgltest::CreateSingleWindow() {
+ window_id_ = eglplatform_shim_->ShimCreateWindow();
+ return (window_id_ != SHIM_NO_WINDOW_ID);
+}
+
+void SurfaceFactoryEgltest::DestroySingleWindow() {
+ if (window_id_ != SHIM_NO_WINDOW_ID)
+ CHECK(eglplatform_shim_->ShimDestroyWindow(window_id_));
+}
+
+SurfaceFactoryEgltest::HardwareState
+SurfaceFactoryEgltest::InitializeHardware() {
+ return INITIALIZED;
+}
+
+void SurfaceFactoryEgltest::ShutdownHardware() {
+}
+
+intptr_t SurfaceFactoryEgltest::GetNativeDisplay() {
+ return eglplatform_shim_->ShimGetNativeDisplay();
+}
+
+gfx::AcceleratedWidget SurfaceFactoryEgltest::GetAcceleratedWidget() {
+ if (window_id_ == SHIM_NO_WINDOW_ID && !CreateSingleWindow())
+ LOG(FATAL) << "failed to create window";
+ return window_id_;
+}
+
+scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryEgltest::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ return make_scoped_ptr<SurfaceOzoneEGL>(
+ new SurfaceOzoneEgltest(widget, eglplatform_shim_));
+}
+
+bool SurfaceFactoryEgltest::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ const char* egl_soname = eglplatform_shim_->ShimQueryString(SHIM_EGL_LIBRARY);
+ const char* gles_soname =
+ eglplatform_shim_->ShimQueryString(SHIM_GLES_LIBRARY);
+ if (!egl_soname)
+ egl_soname = kDefaultEglSoname;
+ if (!gles_soname)
+ gles_soname = kDefaultGlesSoname;
+
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary egl_library =
+ base::LoadNativeLibrary(base::FilePath(egl_soname), &error);
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary gles_library =
+ base::LoadNativeLibrary(base::FilePath(gles_soname), &error);
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ base::UnloadNativeLibrary(egl_library);
+ return false;
+ }
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<GLGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(egl_library,
+ "eglGetProcAddress"));
+ if (!get_proc_address) {
+ LOG(ERROR) << "eglGetProcAddress not found.";
+ base::UnloadNativeLibrary(egl_library);
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ set_gl_get_proc_address.Run(get_proc_address);
+ add_gl_library.Run(egl_library);
+ add_gl_library.Run(gles_library);
+ return true;
+}
+
+const int32* SurfaceFactoryEgltest::GetEGLSurfaceProperties(
+ const int32* desired_list) {
+ static const int32 broken_props[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_NONE,
+ };
+ return broken_props;
+}
+
+// Test platform for EGL.
+//
+// This is a tiny EGL-based platform. Creation of the native window is
+// handled by a separate library called eglplatform_shim.so.1 because
+// this itself is platform specific and we want to test out multiple
+// hardware platforms.
+class OzonePlatformEgltest : public OzonePlatform {
+ public:
+ OzonePlatformEgltest() : shim_initialized_(false) {}
+ virtual ~OzonePlatformEgltest() {
+ if (shim_initialized_)
+ eglplatform_shim_.ShimTerminate();
+ }
+
+ void LoadShim() {
+ std::string library = GetShimLibraryName();
+
+ if (eglplatform_shim_.Load(library))
+ return;
+
+ base::FilePath module_path;
+ if (!PathService::Get(base::DIR_MODULE, &module_path))
+ LOG(ERROR) << "failed to get DIR_MODULE from PathService";
+ base::FilePath library_path = module_path.Append(library);
+
+ if (eglplatform_shim_.Load(library_path.value()))
+ return;
+
+ LOG(FATAL) << "failed to load " << library;
+ }
+
+ void Initialize() {
+ LoadShim();
+ shim_initialized_ = eglplatform_shim_.ShimInitialize();
+ }
+
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE {
+ return event_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return gpu_platform_support_.get();
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return gpu_platform_support_host_.get();
+ }
+
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+ virtual scoped_ptr<TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() OVERRIDE {
+ return scoped_ptr<TouchscreenDeviceManager>(
+ new TouchscreenDeviceManagerOzone());
+ }
+#endif
+
+ virtual void InitializeUI() OVERRIDE {
+ device_manager_ = CreateDeviceManager();
+ surface_factory_ozone_.reset(new SurfaceFactoryEgltest(&eglplatform_shim_));
+ event_factory_ozone_.reset(
+ new EventFactoryEvdev(NULL, device_manager_.get()));
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {
+ surface_factory_ozone_.reset(new SurfaceFactoryEgltest(&eglplatform_shim_));
+ gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
+ }
+
+ private:
+ LibeglplatformShimLoader eglplatform_shim_;
+ scoped_ptr<DeviceManager> device_manager_;
+ scoped_ptr<SurfaceFactoryEgltest> surface_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
+ scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+
+ bool shim_initialized_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformEgltest);
+};
+
+} // namespace
+
+OzonePlatform* CreateOzonePlatformEgltest() {
+ OzonePlatformEgltest* platform = new OzonePlatformEgltest;
+ platform->Initialize();
+ return platform;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.h b/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.h
new file mode 100644
index 00000000000..fb49be50274
--- /dev/null
+++ b/chromium/ui/ozone/platform/egltest/ozone_platform_egltest.h
@@ -0,0 +1,17 @@
+// 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_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
+#define UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformEgltest();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_EGLTEST_H_
diff --git a/chromium/ui/ozone/platform/test/DEPS b/chromium/ui/ozone/platform/test/DEPS
new file mode 100644
index 00000000000..41cd997bd46
--- /dev/null
+++ b/chromium/ui/ozone/platform/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/skia/include",
+]
diff --git a/chromium/ui/ozone/platform/test/file_surface_factory.cc b/chromium/ui/ozone/platform/test/file_surface_factory.cc
new file mode 100644
index 00000000000..ab1e67cbaad
--- /dev/null
+++ b/chromium/ui/ozone/platform/test/file_surface_factory.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/test/file_surface_factory.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/location.h"
+#include "base/stl_util.h"
+#include "base/threading/worker_pool.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+
+namespace ui {
+
+namespace {
+
+void WriteDataToFile(const base::FilePath& location, const SkBitmap& bitmap) {
+ std::vector<unsigned char> png_data;
+ gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, true, &png_data);
+ base::WriteFile(location,
+ reinterpret_cast<const char*>(vector_as_array(&png_data)),
+ png_data.size());
+}
+
+class FileSurface : public SurfaceOzoneCanvas {
+ public:
+ FileSurface(const base::FilePath& location) : location_(location) {}
+ virtual ~FileSurface() {}
+
+ // SurfaceOzoneCanvas overrides:
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) OVERRIDE {
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(
+ viewport_size.width(), viewport_size.height())));
+ }
+ virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE {
+ return skia::SharePtr(surface_->getCanvas());
+ }
+ virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE {
+ SkBitmap bitmap;
+ bitmap.setInfo(surface_->getCanvas()->imageInfo());
+
+ // TODO(dnicoara) Use SkImage instead to potentially avoid a copy.
+ // See crbug.com/361605 for details.
+ if (surface_->getCanvas()->readPixels(&bitmap, 0, 0)) {
+ base::WorkerPool::PostTask(
+ FROM_HERE, base::Bind(&WriteDataToFile, location_, bitmap), true);
+ }
+ }
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
+ return scoped_ptr<gfx::VSyncProvider>();
+ }
+
+ private:
+ base::FilePath location_;
+ skia::RefPtr<SkSurface> surface_;
+};
+
+} // namespace
+
+FileSurfaceFactory::FileSurfaceFactory(const base::FilePath& dump_location)
+ : location_(dump_location) {
+ CHECK(!base::DirectoryExists(location_)) << "Location cannot be a directory ("
+ << location_.value() << ")";
+ CHECK(!base::PathExists(location_) || base::PathIsWritable(location_));
+}
+
+FileSurfaceFactory::~FileSurfaceFactory() {
+}
+
+SurfaceFactoryOzone::HardwareState FileSurfaceFactory::InitializeHardware() {
+ return INITIALIZED;
+}
+
+void FileSurfaceFactory::ShutdownHardware() {
+}
+
+gfx::AcceleratedWidget FileSurfaceFactory::GetAcceleratedWidget() {
+ return 1;
+}
+
+scoped_ptr<SurfaceOzoneCanvas> FileSurfaceFactory::CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) {
+ return make_scoped_ptr<SurfaceOzoneCanvas>(new FileSurface(location_));
+}
+
+bool FileSurfaceFactory::LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/test/file_surface_factory.h b/chromium/ui/ozone/platform/test/file_surface_factory.h
new file mode 100644
index 00000000000..54ab1046e26
--- /dev/null
+++ b/chromium/ui/ozone/platform/test/file_surface_factory.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class OZONE_BASE_EXPORT FileSurfaceFactory : public SurfaceFactoryOzone {
+ public:
+ explicit FileSurfaceFactory(const base::FilePath& dump_location);
+ virtual ~FileSurfaceFactory();
+
+ private:
+ // SurfaceFactoryOzone:
+ virtual HardwareState InitializeHardware() OVERRIDE;
+ virtual void ShutdownHardware() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget w) OVERRIDE;
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
+
+ base::FilePath location_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSurfaceFactory);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_TEST_FILE_SURFACE_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/test/ozone_platform_test.cc b/chromium/ui/ozone/platform/test/ozone_platform_test.cc
index 860837e998a..fa0cedb24f9 100644
--- a/chromium/ui/ozone/platform/test/ozone_platform_test.cc
+++ b/chromium/ui/ozone/platform/test/ozone_platform_test.cc
@@ -6,23 +6,80 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/ozone/ozone_platform.h"
#include "ui/ozone/ozone_switches.h"
+#include "ui/ozone/platform/test/file_surface_factory.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/ozone/common/chromeos/native_display_delegate_ozone.h"
+#include "ui/ozone/common/chromeos/touchscreen_device_manager_ozone.h"
+#endif
namespace ui {
-OzonePlatformTest::OzonePlatformTest(const base::FilePath& dump_file)
- : surface_factory_ozone_(dump_file) {}
+namespace {
-OzonePlatformTest::~OzonePlatformTest() {}
+// OzonePlatform for testing
+//
+// This platform dumps images to a file for testing purposes.
+class OzonePlatformTest : public OzonePlatform {
+ public:
+ OzonePlatformTest(const base::FilePath& dump_file) : file_path_(dump_file) {}
+ virtual ~OzonePlatformTest() {}
-gfx::SurfaceFactoryOzone* OzonePlatformTest::GetSurfaceFactoryOzone() {
- return &surface_factory_ozone_;
-}
+ // OzonePlatform:
+ virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
+ return surface_factory_ozone_.get();
+ }
+ virtual EventFactoryOzone* GetEventFactoryOzone() OVERRIDE {
+ return event_factory_ozone_.get();
+ }
+ virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
+ return cursor_factory_ozone_.get();
+ }
+ virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
+ return NULL; // no GPU support
+ }
+ virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
+ return NULL; // no GPU support
+ }
-ui::EventFactoryOzone* OzonePlatformTest::GetEventFactoryOzone() {
- return &event_factory_ozone_;
-}
+#if defined(OS_CHROMEOS)
+ virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ OVERRIDE {
+ return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateOzone());
+ }
+ virtual scoped_ptr<TouchscreenDeviceManager>
+ CreateTouchscreenDeviceManager() OVERRIDE {
+ return scoped_ptr<TouchscreenDeviceManager>(
+ new TouchscreenDeviceManagerOzone());
+ }
+#endif
+
+ virtual void InitializeUI() OVERRIDE {
+ device_manager_ = CreateDeviceManager();
+ surface_factory_ozone_.reset(new FileSurfaceFactory(file_path_));
+ event_factory_ozone_.reset(
+ new EventFactoryEvdev(NULL, device_manager_.get()));
+ cursor_factory_ozone_.reset(new CursorFactoryOzone());
+ }
+
+ virtual void InitializeGPU() OVERRIDE {}
+
+ private:
+ scoped_ptr<DeviceManager> device_manager_;
+ scoped_ptr<FileSurfaceFactory> surface_factory_ozone_;
+ scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
+ scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
+ base::FilePath file_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(OzonePlatformTest);
+};
+
+} // namespace
OzonePlatform* CreateOzonePlatformTest() {
CommandLine* cmd = CommandLine::ForCurrentProcess();
diff --git a/chromium/ui/ozone/platform/test/ozone_platform_test.h b/chromium/ui/ozone/platform/test/ozone_platform_test.h
index bb199a3be67..fb25fd69f55 100644
--- a/chromium/ui/ozone/platform/test/ozone_platform_test.h
+++ b/chromium/ui/ozone/platform/test/ozone_platform_test.h
@@ -5,30 +5,9 @@
#ifndef UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
#define UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
-#include "base/files/file_path.h"
-#include "ui/events/ozone/evdev/event_factory.h"
-#include "ui/gfx/ozone/impl/file_surface_factory.h"
-#include "ui/ozone/ozone_platform.h"
-
namespace ui {
-// OzonePlatform for testing
-//
-// This platform dumps images to a file for testing purposes.
-class OzonePlatformTest : public OzonePlatform {
- public:
- OzonePlatformTest(const base::FilePath& dump_file);
- virtual ~OzonePlatformTest();
-
- virtual gfx::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE;
- virtual ui::EventFactoryOzone* GetEventFactoryOzone() OVERRIDE;
-
- private:
- gfx::FileSurfaceFactory surface_factory_ozone_;
- ui::EventFactoryEvdev event_factory_ozone_;
-
- DISALLOW_COPY_AND_ASSIGN(OzonePlatformTest);
-};
+class OzonePlatform;
// Constructor hook for use in ozone_platform_list.cc
OzonePlatform* CreateOzonePlatformTest();
diff --git a/chromium/ui/ozone/platform/test/test.gypi b/chromium/ui/ozone/platform/test/test.gypi
new file mode 100644
index 00000000000..c75c840f1e6
--- /dev/null
+++ b/chromium/ui/ozone/platform/test/test.gypi
@@ -0,0 +1,35 @@
+# 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.
+
+{
+ 'variables': {
+ 'internal_ozone_platform_deps': [
+ 'ozone_platform_test',
+ ],
+ 'internal_ozone_platforms': [
+ 'test'
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ozone_platform_test',
+ 'type': 'static_library',
+ 'defines': [
+ 'OZONE_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../events/events.gyp:events',
+ '../events/ozone/events_ozone.gyp:events_ozone_evdev',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'sources': [
+ 'file_surface_factory.cc',
+ 'file_surface_factory.h',
+ 'ozone_platform_test.cc',
+ 'ozone_platform_test.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/ozone/platform_constructor_list.h b/chromium/ui/ozone/platform_constructor_list.h
new file mode 100644
index 00000000000..4f2fa98cbf8
--- /dev/null
+++ b/chromium/ui/ozone/platform_constructor_list.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
+#define UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/platform_list.h"
+
+namespace ui {
+
+template <class T>
+struct PlatformConstructorList {
+ typedef T* (*Constructor)();
+ static const Constructor kConstructors[kPlatformCount];
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_CONSTRUCTOR_LIST_H_
diff --git a/chromium/ui/ozone/platform_object.h b/chromium/ui/ozone/platform_object.h
new file mode 100644
index 00000000000..3d3a65ae524
--- /dev/null
+++ b/chromium/ui/ozone/platform_object.h
@@ -0,0 +1,34 @@
+// 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_OZONE_PLATFORM_OBJECT_H_
+#define UI_OZONE_PLATFORM_OBJECT_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace ui {
+
+// Create an instance of platform specific object.
+//
+// This calls a static constructor function based on the --ozone-platform flag.
+//
+// For the platform called "foo", PlatformObject<PlatformWidget> will ultimately
+// call the function with signature
+//
+// Bar* CreatePlatformWidgetFoo();
+//
+// A definition of this function for each compiled platform must be provided, or
+// link errors will result.
+//
+// To find the right constructor function, this uses static data defined in the
+// source file generated by the generate_constructor_list.py.
+template <class T>
+class PlatformObject {
+ public:
+ static scoped_ptr<T> Create();
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_OBJECT_H_
diff --git a/chromium/ui/ozone/platform_object_internal.h b/chromium/ui/ozone/platform_object_internal.h
new file mode 100644
index 00000000000..68a42b35ba1
--- /dev/null
+++ b/chromium/ui/ozone/platform_object_internal.h
@@ -0,0 +1,31 @@
+// 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_OZONE_PLATFORM_OBJECT_INTERNAL_H_
+#define UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform_constructor_list.h"
+#include "ui/ozone/platform_object.h"
+#include "ui/ozone/platform_selection.h"
+
+namespace ui {
+
+template <class T>
+scoped_ptr<T> PlatformObject<T>::Create() {
+ typedef typename PlatformConstructorList<T>::Constructor Constructor;
+
+ // Determine selected platform (from --ozone-platform flag, or default).
+ int platform = GetOzonePlatformId();
+
+ // Look up the constructor in the constructor list.
+ Constructor constructor = PlatformConstructorList<T>::kConstructors[platform];
+
+ // Call the constructor.
+ return make_scoped_ptr(constructor());
+}
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
diff --git a/chromium/ui/ozone/platform_selection.cc b/chromium/ui/ozone/platform_selection.cc
new file mode 100644
index 00000000000..7e462099396
--- /dev/null
+++ b/chromium/ui/ozone/platform_selection.cc
@@ -0,0 +1,52 @@
+// 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/ozone/platform_selection.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "ui/ozone/ozone_switches.h"
+#include "ui/ozone/platform_list.h"
+
+namespace ui {
+
+namespace {
+
+// Returns the name of the platform to use (value of --ozone-platform flag).
+std::string GetPlatformName() {
+ // The first platform is the default.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kOzonePlatform) &&
+ kPlatformCount > 0)
+ return kPlatformNames[0];
+ return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kOzonePlatform);
+}
+
+int g_selected_platform = -1;
+
+} // namespace
+
+int GetOzonePlatformId() {
+ if (g_selected_platform >= 0)
+ return g_selected_platform;
+
+ std::string platform_name = GetPlatformName();
+
+ // Search for a matching platform in the list.
+ for (int platform_id = 0; platform_id < kPlatformCount; ++platform_id) {
+ if (platform_name == kPlatformNames[platform_id]) {
+ g_selected_platform = platform_id;
+ return g_selected_platform;
+ }
+ }
+
+ LOG(FATAL) << "Invalid ozone platform: " << platform_name;
+ return -1; // not reached
+}
+
+const char* GetOzonePlatformName() {
+ return kPlatformNames[GetOzonePlatformId()];
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform_selection.h b/chromium/ui/ozone/platform_selection.h
new file mode 100644
index 00000000000..5a1229fc769
--- /dev/null
+++ b/chromium/ui/ozone/platform_selection.h
@@ -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.
+
+#ifndef UI_OZONE_PLATFORM_SELECTION_H_
+#define UI_OZONE_PLATFORM_SELECTION_H_
+
+#include "ui/ozone/ozone_export.h"
+#include "ui/ozone/platform_list.h"
+
+namespace ui {
+
+// Get active platform id (by parsing --ozone-platform flag).
+OZONE_EXPORT int GetOzonePlatformId();
+
+// Get active platform name.
+OZONE_EXPORT const char* GetOzonePlatformName();
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SELECTION_H_
diff --git a/chromium/ui/ozone/public/DEPS b/chromium/ui/ozone/public/DEPS
new file mode 100644
index 00000000000..717f3aeed17
--- /dev/null
+++ b/chromium/ui/ozone/public/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+skia/ext",
+]
diff --git a/chromium/ui/ozone/public/README b/chromium/ui/ozone/public/README
new file mode 100644
index 00000000000..27e1b3b6f92
--- /dev/null
+++ b/chromium/ui/ozone/public/README
@@ -0,0 +1,2 @@
+This directory contains the platform API exposed to higher level components such
+as content. These interfaces can be used outside of ui/ozone.
diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.cc b/chromium/ui/ozone/public/cursor_factory_ozone.cc
new file mode 100644
index 00000000000..c50f55eac21
--- /dev/null
+++ b/chromium/ui/ozone/public/cursor_factory_ozone.cc
@@ -0,0 +1,59 @@
+// 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/ozone/public/cursor_factory_ozone.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+// static
+CursorFactoryOzone* CursorFactoryOzone::impl_ = NULL;
+
+CursorFactoryOzone::CursorFactoryOzone() {
+ CHECK(!impl_) << "There should only be a single CursorFactoryOzone.";
+ impl_ = this;
+}
+
+CursorFactoryOzone::~CursorFactoryOzone() {
+ CHECK_EQ(impl_, this);
+ impl_ = NULL;
+}
+
+CursorFactoryOzone* CursorFactoryOzone::GetInstance() {
+ CHECK(impl_) << "No CursorFactoryOzone implementation set.";
+ return impl_;
+}
+
+PlatformCursor CursorFactoryOzone::GetDefaultCursor(int type) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+PlatformCursor CursorFactoryOzone::CreateImageCursor(
+ const SkBitmap& bitmap,
+ const gfx::Point& hotspot) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void CursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+void CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+void CursorFactoryOzone::SetCursor(gfx::AcceleratedWidget widget,
+ PlatformCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+gfx::AcceleratedWidget CursorFactoryOzone::GetCursorWindow() {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.h b/chromium/ui/ozone/public/cursor_factory_ozone.h
new file mode 100644
index 00000000000..5c044849117
--- /dev/null
+++ b/chromium/ui/ozone/public/cursor_factory_ozone.h
@@ -0,0 +1,59 @@
+// 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_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
+#define UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+typedef void* PlatformCursor;
+
+class OZONE_BASE_EXPORT CursorFactoryOzone {
+ public:
+ CursorFactoryOzone();
+ virtual ~CursorFactoryOzone();
+
+ // Returns the singleton instance.
+ static CursorFactoryOzone* GetInstance();
+
+ // Return the default cursor of the specified type. The types are listed in
+ // ui/base/cursor/cursor.h. Default cursors are managed by the implementation
+ // and must live indefinitely; there's no way to know when to free them.
+ virtual PlatformCursor GetDefaultCursor(int type);
+
+ // Return a image cursor from the specified image & hotspot. Image cursors
+ // are referenced counted and have an initial refcount of 1. Therefore, each
+ // CreateImageCursor call must be matched with a call to UnrefImageCursor.
+ virtual PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
+ const gfx::Point& hotspot);
+
+ // Increment platform image cursor refcount.
+ virtual void RefImageCursor(PlatformCursor cursor);
+
+ // Decrement platform image cursor refcount.
+ virtual void UnrefImageCursor(PlatformCursor cursor);
+
+ // Change the active cursor for an AcceleratedWidget.
+ // TODO(spang): Move this.
+ virtual void SetCursor(gfx::AcceleratedWidget widget, PlatformCursor cursor);
+
+ // Returns the window on which the cursor is active.
+ // TODO(dnicoara) Move this once the WindowTreeHost refactoring finishes and
+ // WindowTreeHost::CanDispatchEvent() is no longer present.
+ virtual gfx::AcceleratedWidget GetCursorWindow();
+
+ private:
+ static CursorFactoryOzone* impl_; // not owned
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_CURSOR_FACTORY_OZONE_H_
diff --git a/chromium/ui/ozone/public/event_factory_ozone.cc b/chromium/ui/ozone/public/event_factory_ozone.cc
new file mode 100644
index 00000000000..85ecf3ceddc
--- /dev/null
+++ b/chromium/ui/ozone/public/event_factory_ozone.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/public/event_factory_ozone.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+// static
+EventFactoryOzone* EventFactoryOzone::impl_ = NULL;
+
+EventFactoryOzone::EventFactoryOzone() {
+ CHECK(!impl_) << "There should only be a single EventFactoryOzone";
+ impl_ = this;
+}
+
+EventFactoryOzone::~EventFactoryOzone() {
+ CHECK_EQ(impl_, this);
+ impl_ = NULL;
+}
+
+EventFactoryOzone* EventFactoryOzone::GetInstance() {
+ CHECK(impl_) << "No EventFactoryOzone implementation set.";
+ return impl_;
+}
+
+void EventFactoryOzone::WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/event_factory_ozone.h b/chromium/ui/ozone/public/event_factory_ozone.h
new file mode 100644
index 00000000000..bbca9fdf107
--- /dev/null
+++ b/chromium/ui/ozone/public/event_factory_ozone.h
@@ -0,0 +1,50 @@
+// 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_OZONE_PUBLIC_EVENT_FACTORY_OZONE_H_
+#define UI_OZONE_PUBLIC_EVENT_FACTORY_OZONE_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump_libevent.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace gfx {
+class PointF;
+}
+
+namespace ui {
+
+class Event;
+
+// Creates and dispatches |ui.Event|'s. Ozone assumes that events arrive on file
+// descriptors with one |EventConverterOzone| instance for each descriptor.
+// Ozone presumes that the set of file descriptors can vary at runtime so this
+// class supports dynamically adding and removing |EventConverterOzone|
+// instances as necessary.
+class OZONE_BASE_EXPORT EventFactoryOzone {
+ public:
+ EventFactoryOzone();
+ virtual ~EventFactoryOzone();
+
+ // Warp the cursor to a location within an AccelerateWidget.
+ // If the cursor actually moves, the implementation must dispatch a mouse
+ // move event with the new location.
+ virtual void WarpCursorTo(gfx::AcceleratedWidget widget,
+ const gfx::PointF& location);
+
+ // Returns the singleton instance.
+ static EventFactoryOzone* GetInstance();
+
+ private:
+ static EventFactoryOzone* impl_; // not owned
+
+ DISALLOW_COPY_AND_ASSIGN(EventFactoryOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_EVENT_FACTORY_OZONE_H_
diff --git a/chromium/ui/ozone/public/gpu_platform_support.cc b/chromium/ui/ozone/public/gpu_platform_support.cc
new file mode 100644
index 00000000000..db4148f58a8
--- /dev/null
+++ b/chromium/ui/ozone/public/gpu_platform_support.cc
@@ -0,0 +1,34 @@
+// 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/ozone/public/gpu_platform_support.h"
+
+#include "base/logging.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace ui {
+
+namespace {
+
+// No-op implementation of GpuPlatformSupport.
+class StubGpuPlatformSupport : public GpuPlatformSupport {
+ public:
+ // GpuPlatformSupport:
+ virtual void OnChannelEstablished(IPC::Sender* sender) {}
+ bool OnMessageReceived(const IPC::Message&) OVERRIDE { return false; }
+};
+
+} // namespace
+
+GpuPlatformSupport::GpuPlatformSupport() {
+}
+
+GpuPlatformSupport::~GpuPlatformSupport() {
+}
+
+GpuPlatformSupport* CreateStubGpuPlatformSupport() {
+ return new StubGpuPlatformSupport;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/gpu_platform_support.h b/chromium/ui/ozone/public/gpu_platform_support.h
new file mode 100644
index 00000000000..6aba7faf825
--- /dev/null
+++ b/chromium/ui/ozone/public/gpu_platform_support.h
@@ -0,0 +1,31 @@
+// 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_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
+#define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
+
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sender.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+// Platform-specific object to support a GPU process.
+//
+// See GpuPlatformSupportHost for more context.
+class OZONE_BASE_EXPORT GpuPlatformSupport : public IPC::Listener {
+ public:
+ GpuPlatformSupport();
+ virtual ~GpuPlatformSupport();
+
+ // Called when the GPU process is spun up & channel established.
+ virtual void OnChannelEstablished(IPC::Sender* sender) = 0;
+};
+
+// Create a stub implementation.
+OZONE_BASE_EXPORT GpuPlatformSupport* CreateStubGpuPlatformSupport();
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_H_
diff --git a/chromium/ui/ozone/public/gpu_platform_support_host.cc b/chromium/ui/ozone/public/gpu_platform_support_host.cc
new file mode 100644
index 00000000000..1a75efd5af5
--- /dev/null
+++ b/chromium/ui/ozone/public/gpu_platform_support_host.cc
@@ -0,0 +1,37 @@
+// 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/ozone/public/gpu_platform_support_host.h"
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "ui/ozone/ozone_export.h"
+
+namespace ui {
+
+namespace {
+
+// No-op implementations of GpuPlatformSupportHost.
+class StubGpuPlatformSupportHost : public GpuPlatformSupportHost {
+ public:
+ // GpuPlatformSupportHost:
+ virtual void OnChannelEstablished(int host_id, IPC::Sender* sender) OVERRIDE {
+ }
+ virtual void OnChannelDestroyed(int host_id) OVERRIDE {}
+ virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE { return false; }
+};
+
+} // namespace
+
+GpuPlatformSupportHost::GpuPlatformSupportHost() {
+}
+
+GpuPlatformSupportHost::~GpuPlatformSupportHost() {
+}
+
+GpuPlatformSupportHost* CreateStubGpuPlatformSupportHost() {
+ return new StubGpuPlatformSupportHost;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/gpu_platform_support_host.h b/chromium/ui/ozone/public/gpu_platform_support_host.h
new file mode 100644
index 00000000000..700b75b6052
--- /dev/null
+++ b/chromium/ui/ozone/public/gpu_platform_support_host.h
@@ -0,0 +1,40 @@
+// 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_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
+#define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
+
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sender.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace ui {
+
+// Platform-specific object to support a GPU process host.
+//
+// ChromeOS on bare hardware will do display configuration and cursor
+// movement from the GPU process. This provides a conduit for the
+// messages needed to make this work.
+//
+// Under X11, we don't need any GPU messages for display configuration.
+// That's why there's no real functionality here: it's purely mechanism
+// to support additional messages needed by specific platforms.
+class OZONE_BASE_EXPORT GpuPlatformSupportHost : public IPC::Listener {
+ public:
+ GpuPlatformSupportHost();
+ virtual ~GpuPlatformSupportHost();
+
+ // Called when the GPU process is spun up & channel established.
+ virtual void OnChannelEstablished(int host_id, IPC::Sender* sender) = 0;
+
+ // Called when the GPU process is destroyed.
+ virtual void OnChannelDestroyed(int host_id) = 0;
+};
+
+// create a stub implementation.
+OZONE_BASE_EXPORT GpuPlatformSupportHost* CreateStubGpuPlatformSupportHost();
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
diff --git a/chromium/ui/ozone/public/overlay_candidates_ozone.cc b/chromium/ui/ozone/public/overlay_candidates_ozone.cc
new file mode 100644
index 00000000000..006f4b2319f
--- /dev/null
+++ b/chromium/ui/ozone/public/overlay_candidates_ozone.cc
@@ -0,0 +1,28 @@
+// 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/ozone/public/overlay_candidates_ozone.h"
+
+#include <stdlib.h>
+
+namespace ui {
+
+OverlayCandidatesOzone::OverlaySurfaceCandidate::OverlaySurfaceCandidate()
+ : transform(gfx::OVERLAY_TRANSFORM_NONE),
+ format(SurfaceFactoryOzone::UNKNOWN),
+ overlay_handled(false) {
+}
+
+OverlayCandidatesOzone::OverlaySurfaceCandidate::~OverlaySurfaceCandidate() {
+}
+
+void OverlayCandidatesOzone::CheckOverlaySupport(
+ OverlaySurfaceCandidateList* surfaces) {
+ NOTREACHED();
+}
+
+OverlayCandidatesOzone::~OverlayCandidatesOzone() {
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/overlay_candidates_ozone.h b/chromium/ui/ozone/public/overlay_candidates_ozone.h
new file mode 100644
index 00000000000..e33de564837
--- /dev/null
+++ b/chromium/ui/ozone/public/overlay_candidates_ozone.h
@@ -0,0 +1,56 @@
+// 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_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
+#define UI_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "ui/gfx/rect_f.h"
+#include "ui/ozone/ozone_base_export.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+// This class can be used to answer questions about possible overlay
+// configurations for a particular output device. We get an instance of this
+// class from SurfaceFactoryOzone given an AcceleratedWidget.
+class OZONE_BASE_EXPORT OverlayCandidatesOzone {
+ public:
+ struct OverlaySurfaceCandidate {
+ OverlaySurfaceCandidate();
+ ~OverlaySurfaceCandidate();
+
+ // Transformation to apply to layer during composition.
+ gfx::OverlayTransform transform;
+ // Format of the buffer to composite.
+ SurfaceFactoryOzone::BufferFormat format;
+ // Rect on the display to position the overlay to.
+ gfx::Rect display_rect;
+ // Crop within the buffer to be placed inside |display_rect|.
+ gfx::RectF crop_rect;
+ // Stacking order of the overlay plane relative to the main surface,
+ // which is 0. Signed to allow for "underlays".
+ int plane_z_order;
+
+ // To be modified by the implementer if this candidate can go into
+ // an overlay.
+ bool overlay_handled;
+ };
+
+ typedef std::vector<OverlaySurfaceCandidate> OverlaySurfaceCandidateList;
+
+ // A list of possible overlay candidates is presented to this function.
+ // The expected result is that those candidates that can be in a separate
+ // plane are marked with |overlay_handled| set to true, otherwise they are
+ // to be tranditionally composited.
+ virtual void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces);
+
+ virtual ~OverlayCandidatesOzone();
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_OVERLAY_CANDIDATES_OZONE_H_
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc
new file mode 100644
index 00000000000..9d33be43524
--- /dev/null
+++ b/chromium/ui/ozone/public/surface_factory_ozone.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+#include <stdlib.h>
+
+#include "base/command_line.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+// static
+SurfaceFactoryOzone* SurfaceFactoryOzone::impl_ = NULL;
+
+SurfaceFactoryOzone::SurfaceFactoryOzone() {
+ CHECK(!impl_) << "There should only be a single SurfaceFactoryOzone.";
+ impl_ = this;
+}
+
+SurfaceFactoryOzone::~SurfaceFactoryOzone() {
+ CHECK_EQ(impl_, this);
+ impl_ = NULL;
+}
+
+SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() {
+ CHECK(impl_) << "No SurfaceFactoryOzone implementation set.";
+ return impl_;
+}
+
+intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
+ return 0;
+}
+
+scoped_ptr<SurfaceOzoneEGL> SurfaceFactoryOzone::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget) {
+ NOTIMPLEMENTED();
+ return scoped_ptr<SurfaceOzoneEGL>();
+}
+
+scoped_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget) {
+ NOTIMPLEMENTED();
+ return scoped_ptr<SurfaceOzoneCanvas>();
+}
+
+const int32* SurfaceFactoryOzone::GetEGLSurfaceProperties(
+ const int32* desired_attributes) {
+ return desired_attributes;
+}
+
+ui::OverlayCandidatesOzone* SurfaceFactoryOzone::GetOverlayCandidates(
+ gfx::AcceleratedWidget w) {
+ return NULL;
+}
+
+void SurfaceFactoryOzone::ScheduleOverlayPlane(
+ gfx::AcceleratedWidget w,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ ui::NativeBufferOzone buffer,
+ const gfx::Rect& display_bounds,
+ gfx::RectF crop_rect) {
+ NOTREACHED();
+}
+
+ui::NativeBufferOzone SurfaceFactoryOzone::CreateNativeBuffer(
+ gfx::Size size,
+ BufferFormat format) {
+ return 0;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h
new file mode 100644
index 00000000000..4702d69a59d
--- /dev/null
+++ b/chromium/ui/ozone/public/surface_factory_ozone.h
@@ -0,0 +1,163 @@
+// 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_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
+#define UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/native_library.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/rect.h"
+#include "ui/ozone/ozone_base_export.h"
+
+class SkBitmap;
+class SkCanvas;
+
+namespace ui {
+
+typedef intptr_t NativeBufferOzone;
+class OverlayCandidatesOzone;
+class SurfaceOzoneCanvas;
+class SurfaceOzoneEGL;
+
+// The Ozone interface allows external implementations to hook into Chromium to
+// provide a system specific implementation. The Ozone interface supports two
+// drawing modes: 1) accelerated drawing through EGL and 2) software drawing
+// through Skia.
+//
+// If you want to paint on a window with ozone, you need to create a
+// SurfaceOzoneEGL or SurfaceOzoneCanvas for that window. The platform can
+// support software, EGL, or both for painting on the window.
+// The following functionality is specific to the drawing mode and may not have
+// any meaningful implementation in the other mode. An implementation must
+// provide functionality for at least one mode.
+//
+// 1) Accelerated Drawing (EGL path):
+//
+// The following functions are specific to EGL:
+// - GetNativeDisplay
+// - LoadEGLGLES2Bindings
+// - GetEGLSurfaceProperties (optional if the properties match the default
+// Chromium ones).
+// - CreateEGLSurfaceForWidget
+//
+// 2) Software Drawing (Skia):
+//
+// The following function is specific to the software path:
+// - CreateCanvasForWidget
+//
+// The accelerated path can optionally provide support for the software drawing
+// path.
+//
+// The remaining functions are not covered since they are needed in both drawing
+// modes (See comments bellow for descriptions).
+class OZONE_BASE_EXPORT SurfaceFactoryOzone {
+ public:
+ // Describes the state of the hardware after initialization.
+ enum HardwareState {
+ UNINITIALIZED,
+ INITIALIZED,
+ FAILED,
+ };
+
+ // Describes overlay buffer format.
+ // TODO: this is a placeholder for now and will be populated with more
+ // formats once we know what sorts of content, video, etc. we can support.
+ enum BufferFormat {
+ UNKNOWN,
+ RGBA_8888,
+ RGB_888,
+ };
+
+ typedef void* (*GLGetProcAddressProc)(const char* name);
+ typedef base::Callback<void(base::NativeLibrary)> AddGLLibraryCallback;
+ typedef base::Callback<void(GLGetProcAddressProc)>
+ SetGLGetProcAddressProcCallback;
+
+ SurfaceFactoryOzone();
+ virtual ~SurfaceFactoryOzone();
+
+ // Returns the singleton instance.
+ static SurfaceFactoryOzone* GetInstance();
+
+ // Configures the display hardware. Must be called from within the GPU
+ // process before the sandbox has been activated.
+ virtual HardwareState InitializeHardware() = 0;
+
+ // Cleans up display hardware state. Call this from within the GPU process.
+ // This method must be safe to run inside of the sandbox.
+ virtual void ShutdownHardware() = 0;
+
+ // Returns native platform display handle. This is used to obtain the EGL
+ // display connection for the native display.
+ virtual intptr_t GetNativeDisplay();
+
+ // Obtains an AcceleratedWidget backed by a native Linux framebuffer.
+ // The returned AcceleratedWidget is an opaque token that must realized
+ // before it can be used to create a GL surface.
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
+
+ // Create SurfaceOzoneEGL for the specified gfx::AcceleratedWidget.
+ //
+ // Note: When used from content, this is called in the GPU process. The
+ // platform must support creation of SurfaceOzoneEGL from the GPU process
+ // using only the handle contained in gfx::AcceleratedWidget.
+ virtual scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget widget);
+
+ // Create SurfaceOzoneCanvas for the specified gfx::AcceleratedWidget.
+ //
+ // Note: The platform must support creation of SurfaceOzoneCanvas from the
+ // Browser Process using only the handle contained in gfx::AcceleratedWidget.
+ virtual scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+ gfx::AcceleratedWidget widget);
+
+ // Sets up GL bindings for the native surface. Takes two callback parameters
+ // that allow Ozone to register the GL bindings.
+ virtual bool LoadEGLGLES2Bindings(
+ AddGLLibraryCallback add_gl_library,
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) = 0;
+
+ // Returns an array of EGL properties, which can be used in any EGL function
+ // used to select a display configuration. Note that all properties should be
+ // immediately followed by the corresponding desired value and array should be
+ // terminated with EGL_NONE. Ownership of the array is not transferred to
+ // caller. desired_list contains list of desired EGL properties and values.
+ virtual const int32* GetEGLSurfaceProperties(const int32* desired_list);
+
+ // Get the hal struct to check for overlay support.
+ virtual OverlayCandidatesOzone* GetOverlayCandidates(
+ gfx::AcceleratedWidget w);
+
+ // Sets the overlay plane to switch to at the next page flip.
+ // |plane_z_order| specifies the stacking order of the plane relative to the
+ // main framebuffer located at index 0.
+ // |plane_transform| specifies how the buffer is to be transformed during.
+ // composition.
+ // |buffer| to be presented by the overlay.
+ // |display_bounds| specify where it is supposed to be on the screen.
+ // |crop_rect| specifies the region within the buffer to be placed inside
+ // |display_bounds|.
+ virtual void ScheduleOverlayPlane(gfx::AcceleratedWidget w,
+ int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ ui::NativeBufferOzone buffer,
+ const gfx::Rect& display_bounds,
+ gfx::RectF crop_rect);
+
+ // Cleate a single native buffer to be used for overlay planes.
+ virtual ui::NativeBufferOzone CreateNativeBuffer(gfx::Size size,
+ BufferFormat format);
+
+ private:
+ static SurfaceFactoryOzone* impl_; // not owned
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
diff --git a/chromium/ui/ozone/public/surface_ozone_canvas.h b/chromium/ui/ozone/public/surface_ozone_canvas.h
new file mode 100644
index 00000000000..d02338b70e1
--- /dev/null
+++ b/chromium/ui/ozone/public/surface_ozone_canvas.h
@@ -0,0 +1,56 @@
+// 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_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
+#define UI_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "skia/ext/refptr.h"
+#include "ui/ozone/ozone_base_export.h"
+
+class SkCanvas;
+
+namespace gfx {
+class Size;
+class VSyncProvider;
+}
+
+namespace ui {
+
+// The platform-specific part of an software output. The class is intended
+// for use when no EGL/GLES2 acceleration is possible.
+// This class owns any bits that the ozone implementation needs freed when
+// the software output is destroyed.
+class OZONE_BASE_EXPORT SurfaceOzoneCanvas {
+ public:
+ virtual ~SurfaceOzoneCanvas() {}
+
+ // Returns an SkCanvas for drawing on the window.
+ virtual skia::RefPtr<SkCanvas> GetCanvas() = 0;
+
+ // Attempts to resize the canvas to match the viewport size. After
+ // resizing, the compositor must call GetCanvas() to get the next
+ // canvas - this invalidates any previous canvas from GetCanvas().
+ virtual void ResizeCanvas(const gfx::Size& viewport_size) = 0;
+
+ // Present the current canvas. After presenting, the compositor must
+ // call GetCanvas() to get the next canvas - this invalidates any
+ // previous canvas from GetCanvas().
+ //
+ // The implementation may assume that any pixels outside the damage
+ // rectangle are unchanged since the previous call to PresentCanvas().
+ virtual void PresentCanvas(const gfx::Rect& damage) = 0;
+
+ // Returns a gfx::VsyncProvider for this surface. Note that this may be
+ // called after we have entered the sandbox so if there are operations (e.g.
+ // opening a file descriptor providing vsync events) that must be done
+ // outside of the sandbox, they must have been completed in
+ // InitializeHardware. Returns an empty scoped_ptr on error.
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_OZONE_CANVAS_H_
diff --git a/chromium/ui/ozone/public/surface_ozone_egl.h b/chromium/ui/ozone/public/surface_ozone_egl.h
new file mode 100644
index 00000000000..fa7e43a3ef1
--- /dev/null
+++ b/chromium/ui/ozone/public/surface_ozone_egl.h
@@ -0,0 +1,49 @@
+// 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_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
+#define UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_base_export.h"
+
+namespace gfx {
+class Size;
+class VSyncProvider;
+}
+
+namespace ui {
+
+// The platform-specific part of an EGL surface.
+//
+// This class owns any bits that the ozone implementation needs freed when
+// the EGL surface is destroyed.
+class OZONE_BASE_EXPORT SurfaceOzoneEGL {
+ public:
+ virtual ~SurfaceOzoneEGL() {}
+
+ // Returns the EGL native window for rendering onto this surface.
+ // This can be used to to create a GLSurface.
+ virtual intptr_t /* EGLNativeWindowType */ GetNativeWindow() = 0;
+
+ // Attempts to resize the EGL native window to match the viewport
+ // size.
+ virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) = 0;
+
+ // Called after we swap buffers. This is usually a no-op but can
+ // be used to present the new front buffer if the platform requires this.
+ virtual bool OnSwapBuffers() = 0;
+
+ // Returns a gfx::VsyncProvider for this surface. Note that this may be
+ // called after we have entered the sandbox so if there are operations (e.g.
+ // opening a file descriptor providing vsync events) that must be done
+ // outside of the sandbox, they must have been completed in
+ // InitializeHardware. Returns an empty scoped_ptr on error.
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() = 0;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
diff --git a/chromium/ui/ozone/run_all_unittests.cc b/chromium/ui/ozone/run_all_unittests.cc
new file mode 100644
index 00000000000..32270992bb7
--- /dev/null
+++ b/chromium/ui/ozone/run_all_unittests.cc
@@ -0,0 +1,45 @@
+// 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 "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+
+namespace {
+
+class OzoneTestSuite : public base::TestSuite {
+ public:
+ OzoneTestSuite(int argc, char** argv);
+
+ protected:
+ // base::TestSuite:
+ virtual void Initialize() OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OzoneTestSuite);
+};
+
+OzoneTestSuite::OzoneTestSuite(int argc, char** argv)
+ : base::TestSuite(argc, argv) {}
+
+void OzoneTestSuite::Initialize() {
+ base::TestSuite::Initialize();
+}
+
+void OzoneTestSuite::Shutdown() {
+ base::TestSuite::Shutdown();
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ OzoneTestSuite test_suite(argc, argv);
+
+ return base::LaunchUnitTests(argc,
+ argv,
+ base::Bind(&OzoneTestSuite::Run,
+ base::Unretained(&test_suite)));
+}
diff --git a/chromium/ui/resources/BUILD.gn b/chromium/ui/resources/BUILD.gn
new file mode 100644
index 00000000000..96ee870fc4e
--- /dev/null
+++ b/chromium/ui/resources/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//tools/grit/grit_rule.gni")
+
+grit("resources") {
+ output_name = "ui_resources"
+ source = "ui_resources.grd"
+}
+
+grit("unscaled_resources") {
+ output_name = "ui_unscaled_resources"
+ source = "ui_unscaled_resources.grd"
+}
diff --git a/chromium/ui/resources/default_100_percent/ash/status_network.png b/chromium/ui/resources/default_100_percent/ash/status_network.png
deleted file mode 100644
index 7c7cbc15c66..00000000000
--- a/chromium/ui/resources/default_100_percent/ash/status_network.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/ash/status_volume.png b/chromium/ui/resources/default_100_percent/ash/status_volume.png
deleted file mode 100644
index 4f57e989760..00000000000
--- a/chromium/ui/resources/default_100_percent/ash/status_volume.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/app_list_apps_icon.png b/chromium/ui/resources/default_100_percent/common/app_list_apps_icon.png
new file mode 100644
index 00000000000..e7790809498
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/app_list_apps_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/app_list_experimental_icon.png b/chromium/ui/resources/default_100_percent/common/app_list_experimental_icon.png
new file mode 100644
index 00000000000..3d6f7021332
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/app_list_experimental_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/app_list_notifications_icon.png b/chromium/ui/resources/default_100_percent/common/app_list_notifications_icon.png
new file mode 100644
index 00000000000..f88eea7c19c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/app_list_notifications_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/app_list_search_icon.png b/chromium/ui/resources/default_100_percent/common/app_list_search_icon.png
new file mode 100644
index 00000000000..a48f79096a4
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/app_list_search_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/win/app_list_user_indicator.png b/chromium/ui/resources/default_100_percent/common/app_list_user_indicator.png
index 77f58588790..77f58588790 100644
--- a/chromium/ui/resources/default_100_percent/win/app_list_user_indicator.png
+++ b/chromium/ui/resources/default_100_percent/common/app_list_user_indicator.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_center.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_left.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_right.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png
new file mode 100644
index 00000000000..e764f566207
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_center.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png
new file mode 100644
index 00000000000..e2d5fb2cb2c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_center.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_left.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_right.png
new file mode 100644
index 00000000000..a1b295fd411
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_base_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png
new file mode 100644
index 00000000000..9a7a1e88c8e
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png
new file mode 100644
index 00000000000..3a2ee9158ab
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png
new file mode 100644
index 00000000000..a2c7253306c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_center.png
new file mode 100644
index 00000000000..5c87bea82ac
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_left.png
new file mode 100644
index 00000000000..5dece07626b
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_right.png
new file mode 100644
index 00000000000..5dece07626b
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top.png
new file mode 100644
index 00000000000..9a7a1e88c8e
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png
new file mode 100644
index 00000000000..96bef5e21a5
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png
new file mode 100644
index 00000000000..816deb45213
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png
new file mode 100644
index 00000000000..37cfa861071
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png
new file mode 100644
index 00000000000..7bca659509d
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png
new file mode 100644
index 00000000000..577b607985f
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png
new file mode 100644
index 00000000000..37cfa861071
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png
new file mode 100644
index 00000000000..37cfa861071
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png
new file mode 100644
index 00000000000..37cfa861071
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png
new file mode 100644
index 00000000000..bdde2bd25fc
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png
new file mode 100644
index 00000000000..952854f3c10
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom.png
new file mode 100644
index 00000000000..d5a3af30e78
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png
new file mode 100644
index 00000000000..3d84e27aaad
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png
new file mode 100644
index 00000000000..1cf50cbc1b4
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_center.png
new file mode 100644
index 00000000000..da9e5bc3c77
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_left.png
new file mode 100644
index 00000000000..2067ed4b2e4
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_right.png
new file mode 100644
index 00000000000..9efb9805785
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top.png
new file mode 100644
index 00000000000..a3fe6cf7eff
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_left.png
new file mode 100644
index 00000000000..b5486b0ad77
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_right.png
new file mode 100644
index 00000000000..893d1632687
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_hover_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom.png
new file mode 100644
index 00000000000..fdf2a5ff662
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png
new file mode 100644
index 00000000000..872a22a3eee
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png
new file mode 100644
index 00000000000..ddb1a425f9e
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_center.png
new file mode 100644
index 00000000000..b6b9554d2ee
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_left.png
new file mode 100644
index 00000000000..dce815df06a
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_right.png
new file mode 100644
index 00000000000..d624b81928f
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top.png
new file mode 100644
index 00000000000..eb524508c57
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_left.png
new file mode 100644
index 00000000000..f3ff1af57f5
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_right.png
new file mode 100644
index 00000000000..961efe9c9b6
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_normal_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png
new file mode 100644
index 00000000000..363575efd2d
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png
new file mode 100644
index 00000000000..b3261d0dca6
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png
new file mode 100644
index 00000000000..9b7b7fc694b
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_center.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_center.png
new file mode 100644
index 00000000000..c9500412385
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_left.png
new file mode 100644
index 00000000000..ea162226883
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_right.png
new file mode 100644
index 00000000000..c4059bf162e
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top.png
new file mode 100644
index 00000000000..82f7e42417c
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png
new file mode 100644
index 00000000000..4b732503a68
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png
new file mode 100644
index 00000000000..b0add673dd0
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/back_arrow.png b/chromium/ui/resources/default_100_percent/common/back_arrow.png
new file mode 100644
index 00000000000..0334cafe4f0
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/back_arrow.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/buy_with_google_button.png b/chromium/ui/resources/default_100_percent/common/buy_with_google_button.png
deleted file mode 100644
index be05ba29166..00000000000
--- a/chromium/ui/resources/default_100_percent/common/buy_with_google_button.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/buy_with_google_button_hover.png b/chromium/ui/resources/default_100_percent/common/buy_with_google_button_hover.png
deleted file mode 100644
index 3e862d2b2b4..00000000000
--- a/chromium/ui/resources/default_100_percent/common/buy_with_google_button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png b/chromium/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png
deleted file mode 100644
index 821f0de714a..00000000000
--- a/chromium/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/forward_arrow.png b/chromium/ui/resources/default_100_percent/common/forward_arrow.png
new file mode 100644
index 00000000000..a0a6b0deb2b
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/forward_arrow.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png
deleted file mode 100644
index 0657fe93842..00000000000
--- a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png
deleted file mode 100644
index 85ef5b21218..00000000000
--- a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_bubble_close.png b/chromium/ui/resources/default_100_percent/common/notification_bubble_close.png
new file mode 100644
index 00000000000..02e1f91ee0b
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/notification_bubble_close.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_bubble_close_hover.png b/chromium/ui/resources/default_100_percent/common/notification_bubble_close_hover.png
new file mode 100644
index 00000000000..aeafd962eb7
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/notification_bubble_close_hover.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_bubble_close_pressed.png b/chromium/ui/resources/default_100_percent/common/notification_bubble_close_pressed.png
new file mode 100644
index 00000000000..1c4ad59f6c4
--- /dev/null
+++ b/chromium/ui/resources/default_100_percent/common/notification_bubble_close_pressed.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_expand.png b/chromium/ui/resources/default_100_percent/common/notification_expand.png
deleted file mode 100644
index 3609644c5fd..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_expand.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_expand_hover.png b/chromium/ui/resources/default_100_percent/common/notification_expand_hover.png
deleted file mode 100644
index 6a3c27f7ab4..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_expand_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_expand_pressed.png b/chromium/ui/resources/default_100_percent/common/notification_expand_pressed.png
deleted file mode 100644
index 6d92d152905..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_expand_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm.png
index f4ef091cfc8..8c164099860 100644
--- a/chromium/ui/resources/default_100_percent/common/pointers/xterm.png
+++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png
index fdeec95832d..2dedbc0d27a 100644
--- a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png
+++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/text_selection_handle.png b/chromium/ui/resources/default_100_percent/common/text_selection_handle.png
deleted file mode 100644
index d2796fdca22..00000000000
--- a/chromium/ui/resources/default_100_percent/common/text_selection_handle.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_center.png
deleted file mode 100644
index 364e50724ee..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_left.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_left.png
deleted file mode 100644
index ab93d06c73d..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_right.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_right.png
deleted file mode 100644
index 1ab07e61770..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png
deleted file mode 100644
index cb9eefff8ba..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_center.png
deleted file mode 100644
index d2a01d3b922..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_top.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_top.png
deleted file mode 100644
index 1a28fa879d8..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_base_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png
deleted file mode 100644
index 791dae1b0ea..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png
deleted file mode 100644
index 07a56c1eeb1..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png
deleted file mode 100644
index c7f965f66cf..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png
deleted file mode 100644
index 7357419be04..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png
deleted file mode 100644
index 61fca6cbd0b..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png
deleted file mode 100644
index 9e230f2570f..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png
deleted file mode 100644
index 5a64385a527..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png
deleted file mode 100644
index b42f04666e7..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png
deleted file mode 100644
index d0a915775c9..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png
deleted file mode 100644
index 9eac5654771..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png
deleted file mode 100644
index d72c49e0936..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png
deleted file mode 100644
index da8fbcb05c6..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png
deleted file mode 100644
index 9323fd342b5..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png
deleted file mode 100644
index 3583680c0dd..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png
deleted file mode 100644
index 57e686f8a8e..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png
deleted file mode 100644
index 2b25dbdf533..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png
deleted file mode 100644
index 48e46056d76..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png b/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png
deleted file mode 100644
index c57cd54dd4f..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/oak.png b/chromium/ui/resources/default_100_percent/oak.png
deleted file mode 100644
index 49954798da7..00000000000
--- a/chromium/ui/resources/default_100_percent/oak.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/radialmenu_back.png b/chromium/ui/resources/default_100_percent/radialmenu_back.png
deleted file mode 100644
index 7fa19bb609e..00000000000
--- a/chromium/ui/resources/default_100_percent/radialmenu_back.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/radialmenu_forward.png b/chromium/ui/resources/default_100_percent/radialmenu_forward.png
deleted file mode 100644
index a354d2c308e..00000000000
--- a/chromium/ui/resources/default_100_percent/radialmenu_forward.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/radialmenu_options.png b/chromium/ui/resources/default_100_percent/radialmenu_options.png
deleted file mode 100644
index fcdb8e25948..00000000000
--- a/chromium/ui/resources/default_100_percent/radialmenu_options.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/radialmenu_reload.png b/chromium/ui/resources/default_100_percent/radialmenu_reload.png
deleted file mode 100644
index 9866d731e71..00000000000
--- a/chromium/ui/resources/default_100_percent/radialmenu_reload.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/app_list_apps_icon.png b/chromium/ui/resources/default_200_percent/common/app_list_apps_icon.png
new file mode 100644
index 00000000000..919a97a813d
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/app_list_apps_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/app_list_experimental_icon.png b/chromium/ui/resources/default_200_percent/common/app_list_experimental_icon.png
new file mode 100644
index 00000000000..3c999d6e661
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/app_list_experimental_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/app_list_notifications_icon.png b/chromium/ui/resources/default_200_percent/common/app_list_notifications_icon.png
new file mode 100644
index 00000000000..3565a6ed971
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/app_list_notifications_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/app_list_search_icon.png b/chromium/ui/resources/default_200_percent/common/app_list_search_icon.png
new file mode 100644
index 00000000000..e422c2628d1
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/app_list_search_icon.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/win/app_list_user_indicator.png b/chromium/ui/resources/default_200_percent/common/app_list_user_indicator.png
index 9fb3a484c00..9fb3a484c00 100644
--- a/chromium/ui/resources/default_200_percent/win/app_list_user_indicator.png
+++ b/chromium/ui/resources/default_200_percent/common/app_list_user_indicator.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_center.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_left.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_right.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png
new file mode 100644
index 00000000000..e3675d14754
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_hover_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_center.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_normal_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png
new file mode 100644
index 00000000000..4bcc4192860
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_arrow_button_base_pressed_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_center.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_left.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_right.png
new file mode 100644
index 00000000000..1142874a68b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_base_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png
new file mode 100644
index 00000000000..78d9c0f4238
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png
new file mode 100644
index 00000000000..9617a5d873e
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png
new file mode 100644
index 00000000000..69b617cd1ed
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_center.png
new file mode 100644
index 00000000000..56d451e9f5d
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_left.png
new file mode 100644
index 00000000000..535837d81cc
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_right.png
new file mode 100644
index 00000000000..535837d81cc
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top.png
new file mode 100644
index 00000000000..78d9c0f4238
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png
new file mode 100644
index 00000000000..07231fdb1e8
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png
new file mode 100644
index 00000000000..136af2ce36c
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_fill_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png
new file mode 100644
index 00000000000..592784704d3
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png
new file mode 100644
index 00000000000..6ad0393309f
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png
new file mode 100644
index 00000000000..f7fb94dc208
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png
new file mode 100644
index 00000000000..592784704d3
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png
new file mode 100644
index 00000000000..592784704d3
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png
new file mode 100644
index 00000000000..592784704d3
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png
new file mode 100644
index 00000000000..84a594dc470
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png
new file mode 100644
index 00000000000..75f5bde9855
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_overlay_thumb_stroke_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom.png
new file mode 100644
index 00000000000..ecc7e25656f
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png
new file mode 100644
index 00000000000..28816610e7c
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png
new file mode 100644
index 00000000000..56a724951d7
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_center.png
new file mode 100644
index 00000000000..9b07f25c190
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_left.png
new file mode 100644
index 00000000000..90a332f4dd0
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_right.png
new file mode 100644
index 00000000000..d30b0fe9840
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top.png
new file mode 100644
index 00000000000..abb57cb6ba8
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_left.png
new file mode 100644
index 00000000000..63568f76253
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_right.png
new file mode 100644
index 00000000000..c45383062d7
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_hover_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom.png
new file mode 100644
index 00000000000..10f29432eb7
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png
new file mode 100644
index 00000000000..036e4b166f7
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png
new file mode 100644
index 00000000000..849ffa15d2f
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_center.png
new file mode 100644
index 00000000000..8cac7210461
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_left.png
new file mode 100644
index 00000000000..4640e0e885e
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_right.png
new file mode 100644
index 00000000000..e8d841cad8b
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top.png
new file mode 100644
index 00000000000..84edfe03596
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_left.png
new file mode 100644
index 00000000000..216fd0379d2
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_right.png
new file mode 100644
index 00000000000..85638513014
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_normal_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png
new file mode 100644
index 00000000000..5e0a53085f7
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png
new file mode 100644
index 00000000000..41c42c99127
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png
new file mode 100644
index 00000000000..200d8ab0262
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_bottom_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_center.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_center.png
new file mode 100644
index 00000000000..e1ad2b90f83
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_center.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_left.png
new file mode 100644
index 00000000000..424b47a224e
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_right.png
new file mode 100644
index 00000000000..3c3e8e1f79f
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top.png
new file mode 100644
index 00000000000..b8021023b84
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png
new file mode 100644
index 00000000000..003f8fc21ba
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_left.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png
new file mode 100644
index 00000000000..c0912e56137
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/aura_scrollbar_thumb_base_pressed_top_right.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/back_arrow.png b/chromium/ui/resources/default_200_percent/common/back_arrow.png
new file mode 100644
index 00000000000..e1f212f8f35
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/back_arrow.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/buy_with_google_button.png b/chromium/ui/resources/default_200_percent/common/buy_with_google_button.png
deleted file mode 100644
index f9e10f2cec5..00000000000
--- a/chromium/ui/resources/default_200_percent/common/buy_with_google_button.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/buy_with_google_button_hover.png b/chromium/ui/resources/default_200_percent/common/buy_with_google_button_hover.png
deleted file mode 100644
index c977e1eb646..00000000000
--- a/chromium/ui/resources/default_200_percent/common/buy_with_google_button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png b/chromium/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png
deleted file mode 100644
index 4ccbc6bfa3f..00000000000
--- a/chromium/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/forward_arrow.png b/chromium/ui/resources/default_200_percent/common/forward_arrow.png
new file mode 100644
index 00000000000..85ebf170bb3
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/forward_arrow.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png
deleted file mode 100644
index ba7b149c7b3..00000000000
--- a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png b/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png
deleted file mode 100644
index 6202dbf7935..00000000000
--- a/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_bubble_close.png b/chromium/ui/resources/default_200_percent/common/notification_bubble_close.png
new file mode 100644
index 00000000000..80f4b9c2533
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/notification_bubble_close.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_bubble_close_hover.png b/chromium/ui/resources/default_200_percent/common/notification_bubble_close_hover.png
new file mode 100644
index 00000000000..743d005ee4e
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/notification_bubble_close_hover.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_bubble_close_pressed.png b/chromium/ui/resources/default_200_percent/common/notification_bubble_close_pressed.png
new file mode 100644
index 00000000000..07b69ccdbe1
--- /dev/null
+++ b/chromium/ui/resources/default_200_percent/common/notification_bubble_close_pressed.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_expand.png b/chromium/ui/resources/default_200_percent/common/notification_expand.png
deleted file mode 100644
index 0d405b843cc..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_expand.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_expand_hover.png b/chromium/ui/resources/default_200_percent/common/notification_expand_hover.png
deleted file mode 100644
index d84ba6dbfc1..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_expand_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_expand_pressed.png b/chromium/ui/resources/default_200_percent/common/notification_expand_pressed.png
deleted file mode 100644
index 745098297cb..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_expand_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/pointers/xterm.png b/chromium/ui/resources/default_200_percent/common/pointers/xterm.png
index 667d0b2f4cc..ecd9b61462c 100644
--- a/chromium/ui/resources/default_200_percent/common/pointers/xterm.png
+++ b/chromium/ui/resources/default_200_percent/common/pointers/xterm.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png b/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png
index fb41bb3fb81..b95e553d1df 100644
--- a/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png
+++ b/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/text_selection_handle.png b/chromium/ui/resources/default_200_percent/common/text_selection_handle.png
deleted file mode 100644
index bc36ad2886d..00000000000
--- a/chromium/ui/resources/default_200_percent/common/text_selection_handle.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_center.png
deleted file mode 100644
index eacc9bcc659..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_left.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_left.png
deleted file mode 100644
index 48bb2605b5b..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_right.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_right.png
deleted file mode 100644
index 6e32c65b694..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png
deleted file mode 100644
index 25143313fd3..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_center.png
deleted file mode 100644
index 456691f0419..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_top.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_top.png
deleted file mode 100644
index 867bb395b64..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_bottom.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_bottom.png
deleted file mode 100644
index aa92ca1762d..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_top.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_top.png
deleted file mode 100644
index 561c1f00894..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_base_vertical_normal_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png
deleted file mode 100644
index e9cba2373b4..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png
deleted file mode 100644
index 157e5caf290..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png
deleted file mode 100644
index 7f6104108fa..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png
deleted file mode 100644
index 676d59e921a..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png
deleted file mode 100644
index 49ce1a31eea..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png
deleted file mode 100644
index 97f2d41e648..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_normal_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png
deleted file mode 100644
index 26d890d3350..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png
deleted file mode 100644
index a601b853529..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png
deleted file mode 100644
index 255b98cf361..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_horizontal_pressed_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png
deleted file mode 100644
index ee4533ea599..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png
deleted file mode 100644
index af5de77a8c1..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png
deleted file mode 100644
index f626685eb3a..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png
deleted file mode 100644
index cdca6046e1a..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png
deleted file mode 100644
index 79daaeeee67..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png
deleted file mode 100644
index 7cd4b78dad3..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_normal_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png
deleted file mode 100644
index 34406fb56c0..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png
deleted file mode 100644
index a7cb36de20d..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png b/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png
deleted file mode 100644
index 55bcbf17a31..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/aura_scrollbar_thumb_vertical_pressed_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png
deleted file mode 100644
index e27e68bbd7e..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png
deleted file mode 100644
index d3a44be3935..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png
deleted file mode 100644
index 5a9deb1c33f..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_center.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_center.png
deleted file mode 100644
index 548c82d3da0..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_left.png
deleted file mode 100644
index 8894317e84e..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_right.png
deleted file mode 100644
index 8a42d94fd45..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top.png
deleted file mode 100644
index a2aea02fa0a..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png
deleted file mode 100644
index 58b309f4352..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png
deleted file mode 100644
index e4f647ce383..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png
deleted file mode 100644
index aadf054497c..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png
deleted file mode 100644
index 590d6dc4b24..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png
deleted file mode 100644
index fd1454d6bcb..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_center.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_center.png
deleted file mode 100644
index 6f7c4be2ac9..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_left.png
deleted file mode 100644
index b62174f5de5..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_right.png
deleted file mode 100644
index 92ec84d6374..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top.png
deleted file mode 100644
index cf281814a5f..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png
deleted file mode 100644
index 0b480bed8fa..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png b/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png
deleted file mode 100644
index 09dd32b891b..00000000000
--- a/chromium/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_center.png
deleted file mode 100644
index 3aff0653251..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_left.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_left.png
deleted file mode 100644
index 64beab3403a..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right.png
deleted file mode 100644
index 7b3a99abc1b..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right_fix.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right_fix.png
deleted file mode 100644
index fdb46b89323..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_hover_right_fix.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_center.png
deleted file mode 100644
index eeac60a91cb..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_left.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_left.png
deleted file mode 100644
index 4fa1d6487ac..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_right.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_right.png
deleted file mode 100644
index a295d0091d1..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_horizontal_normal_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_hover_edge.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_hover_edge.png
deleted file mode 100644
index 6c08ec44f1f..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_hover_edge.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_normal_edge.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_normal_edge.png
deleted file mode 100644
index 8673071c8a1..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_normal_edge.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom.png
deleted file mode 100644
index bb29561ea58..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom_fix.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom_fix.png
deleted file mode 100644
index 7de281d49c8..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_bottom_fix.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_center.png
deleted file mode 100644
index be67767563f..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_top.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_top.png
deleted file mode 100644
index 09a232fe2dd..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_bottom.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_bottom.png
deleted file mode 100644
index 2deb678cd9f..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_center.png
deleted file mode 100644
index ebf5e06f9d3..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_top.png b/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_top.png
deleted file mode 100644
index 974149b755c..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_base_vertical_normal_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_center.png
deleted file mode 100644
index 10be4528c21..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_left.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_left.png
deleted file mode 100644
index e6d985cbb91..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_right.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_right.png
deleted file mode 100644
index d6f4764fd28..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_center.png
deleted file mode 100644
index 119ef1cfd9d..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_left.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_left.png
deleted file mode 100644
index e96a21653b1..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_right.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_right.png
deleted file mode 100644
index 66c4fe1c8b0..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_normal_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_center.png
deleted file mode 100644
index 14b23b1a78d..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_left.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_left.png
deleted file mode 100644
index 7901436ac1d..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_right.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_right.png
deleted file mode 100644
index 1ad67e64de9..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_horizontal_pressed_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_bottom.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_bottom.png
deleted file mode 100644
index b370356e216..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_center.png
deleted file mode 100644
index d72c49e0936..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_top.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_top.png
deleted file mode 100644
index e4302384a45..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_bottom.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_bottom.png
deleted file mode 100644
index 86d16e2a0cb..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_center.png
deleted file mode 100644
index 3583680c0dd..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_top.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_top.png
deleted file mode 100644
index ae3748f4b69..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_normal_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_bottom.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_bottom.png
deleted file mode 100644
index 182f7d90c0c..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_center.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_center.png
deleted file mode 100644
index 48e46056d76..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_top.png b/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_top.png
deleted file mode 100644
index 3e5370dd1bc..00000000000
--- a/chromium/ui/resources/touch_100_percent/scrollbar_thumb_vertical_pressed_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom.png
deleted file mode 100644
index e27e68bbd7e..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_left.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_left.png
deleted file mode 100644
index 53b1ef3c5ec..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_right.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_right.png
deleted file mode 100644
index b80be9944f3..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_center.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_center.png
deleted file mode 100644
index 548c82d3da0..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_left.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_left.png
deleted file mode 100644
index 6599f7ee987..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_right.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_right.png
deleted file mode 100644
index bb66d7f2e58..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_top.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_top.png
deleted file mode 100644
index a2aea02fa0a..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_top_left.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_top_left.png
deleted file mode 100644
index 125bb2b7b22..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_hover_top_right.png b/chromium/ui/resources/touch_100_percent/textbutton_hover_top_right.png
deleted file mode 100644
index e472596c637..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_hover_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom.png
deleted file mode 100644
index aadf054497c..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_left.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_left.png
deleted file mode 100644
index 747dbd931fb..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_right.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_right.png
deleted file mode 100644
index 4c4efb1c329..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_center.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_center.png
deleted file mode 100644
index 6f7c4be2ac9..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_left.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_left.png
deleted file mode 100644
index b62174f5de5..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_right.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_right.png
deleted file mode 100644
index 92ec84d6374..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_top.png
deleted file mode 100644
index cf281814a5f..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_left.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_left.png
deleted file mode 100644
index 51e66e2050e..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_right.png b/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_right.png
deleted file mode 100644
index 0e3035d7912..00000000000
--- a/chromium/ui/resources/touch_100_percent/textbutton_pressed_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/ui_resources.grd b/chromium/ui/resources/ui_resources.grd
index 8fd038e060a..4096fe269d4 100644
--- a/chromium/ui/resources/ui_resources.grd
+++ b/chromium/ui/resources/ui_resources.grd
@@ -8,37 +8,38 @@
<output filename="grit/ui_resources_map.h" type="resource_map_header" context="default_100_percent" />
<output filename="ui_resources_100_percent.pak" type="data_package" context="default_100_percent" />
<output filename="ui_resources_200_percent.pak" type="data_package" context="default_200_percent" />
- <output filename="ui_resources_touch_100_percent.pak" type="data_package" context="touch_100_percent" />
- <output filename="ui_resources_touch_140_percent.pak" type="data_package" context="touch_140_percent" />
- <output filename="ui_resources_touch_180_percent.pak" type="data_package" context="touch_180_percent" />
</outputs>
<release seq="1">
<structures fallback_to_low_resolution="true">
<!-- KEEP THESE IN ALPHABETICAL ORDER! DO NOT ADD TO RANDOM PLACES JUST
BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE
SAME CONDITIONALS. -->
- <if expr="pp_ifdef('enable_app_list')">
+ <if expr="enable_app_list">
+ <structure type="chrome_scaled_image" name="IDR_APP_LIST_APPS_ICON" file="common/app_list_apps_icon.png" />
+ <structure type="chrome_scaled_image" name="IDR_APP_LIST_EXPERIMENTAL_ICON" file="common/app_list_experimental_icon.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_BACKGROUND" file="common/app_list_progress_bar_background.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_LEFT" file="common/app_list_progress_bar_left.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_CENTER" file="common/app_list_progress_bar_center.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_RIGHT" file="common/app_list_progress_bar_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_APP_LIST_NOTIFICATIONS_ICON" file="common/app_list_notifications_icon.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_HOVER" file="common/app_list_tools_hover.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_NORMAL" file="common/app_list_tools_normal.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_PRESSED" file="common/app_list_tools_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_FOLDER_BACK_NORMAL" file="common/app_list_folder_back_normal.png" />
+ <structure type="chrome_scaled_image" name="IDR_APP_LIST_SEARCH_ICON" file="common/app_list_search_icon.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_ON" file="common/app_list_mic_on.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_OFF" file="common/app_list_mic_off.png" />
<structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_RECORDING" file="common/app_list_mic_recording.png" />
- <if expr="is_win">
- <structure type="chrome_scaled_image" name="IDR_APP_LIST_USER_INDICATOR" file="win/app_list_user_indicator.png" />
+ <if expr="is_win or desktop_linux">
+ <structure type="chrome_scaled_image" name="IDR_APP_LIST_USER_INDICATOR" file="common/app_list_user_indicator.png" />
</if>
</if>
- <structure type="chrome_scaled_image" name="IDR_APP_TOP_CENTER" file="app_top_center.png" />
- <if expr="pp_ifdef('toolkit_views')">
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_APP_TOP_CENTER" file="app_top_center.png" />
<structure type="chrome_scaled_image" name="IDR_APP_TOP_LEFT" file="app_top_left.png" />
<structure type="chrome_scaled_image" name="IDR_APP_TOP_RIGHT" file="app_top_right.png" />
</if>
- <if expr="is_linux and pp_ifdef('use_aura')">
+ <if expr="is_linux and use_aura">
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_ALIAS" file="common/pointers/alias_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_CELL" file="common/pointers/cell_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_COL_RESIZE" file="common/pointers/sb_h_double_arrow_big.png" />
@@ -47,7 +48,6 @@
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_CROSSHAIR" file="common/pointers/crosshair_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_EAST_RESIZE" file="common/pointers/sb_h_double_arrow_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_EAST_WEST_RESIZE" file="common/pointers/sb_h_double_arrow_big.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_FLEUR" file="common/pointers/fleur_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_HAND" file="common/pointers/hand2_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_HELP" file="common/pointers/help_big.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_BIG_IBEAM" file="common/pointers/xterm_big.png" />
@@ -78,7 +78,6 @@
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_CROSSHAIR" file="common/pointers/crosshair.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_EAST_RESIZE" file="common/pointers/sb_h_double_arrow.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_EAST_WEST_RESIZE" file="common/pointers/sb_h_double_arrow.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_FLEUR" file="common/pointers/fleur.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_HAND" file="common/pointers/hand2.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_HELP" file="common/pointers/help.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_IBEAM" file="common/pointers/xterm.png" />
@@ -102,92 +101,76 @@
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_GRAB" file="common/pointers/fleur.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_CURSOR_GRABBING" file="common/pointers/hand3.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM" file="common/window_shadow_active_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT" file="common/window_shadow_active_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT" file="common/window_shadow_active_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_LEFT" file="common/window_shadow_active_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_RIGHT" file="common/window_shadow_active_right.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP" file="common/window_shadow_active_top.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP_LEFT" file="common/window_shadow_active_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT" file="common/window_shadow_active_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM" file="common/window_shadow_inactive_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT" file="common/window_shadow_inactive_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT" file="common/window_shadow_inactive_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_LEFT" file="common/window_shadow_inactive_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_RIGHT" file="common/window_shadow_inactive_right.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP" file="common/window_shadow_inactive_top.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP_LEFT" file="common/window_shadow_inactive_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT" file="common/window_shadow_inactive_top_right.png" />
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM" file="common/window_shadow_active_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT" file="common/window_shadow_active_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT" file="common/window_shadow_active_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_LEFT" file="common/window_shadow_active_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_RIGHT" file="common/window_shadow_active_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP" file="common/window_shadow_active_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP_LEFT" file="common/window_shadow_active_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT" file="common/window_shadow_active_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM" file="common/window_shadow_inactive_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT" file="common/window_shadow_inactive_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT" file="common/window_shadow_inactive_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_LEFT" file="common/window_shadow_inactive_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_RIGHT" file="common/window_shadow_inactive_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP" file="common/window_shadow_inactive_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP_LEFT" file="common/window_shadow_inactive_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT" file="common/window_shadow_inactive_top_right.png" />
+ </if>
+ <structure type="chrome_scaled_image" name="IDR_BACK_ARROW" file="common/back_arrow.png" />
+ <structure type="chrome_scaled_image" name="IDR_FORWARD_ARROW" file="common/forward_arrow.png" />
<structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_BADGE_CENTER" file="common/browser_action_badge_center.png" />
<structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_BADGE_LEFT" file="common/browser_action_badge_left.png" />
<structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_BADGE_RIGHT" file="common/browser_action_badge_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_B" file="bubble_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_BL" file="bubble_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_BR" file="bubble_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_B_ARROW" file="bubble_pointer_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_L" file="bubble_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_L_ARROW" file="bubble_pointer_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_R" file="bubble_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_R_ARROW" file="bubble_pointer_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_T" file="bubble_top.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_TL" file="bubble_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_TR" file="bubble_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_T_ARROW" file="bubble_pointer_top.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_DISABLED" file="common/button_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_HOVER" file="common/button_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_NORMAL" file="common/button_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_PRESSED" file="common/button_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_HOVER" file="common/button_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_NORMAL" file="common/button.png" />
- <structure type="chrome_scaled_image" name="IDR_BUTTON_PRESSED" file="common/button_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BUY_WITH_GOOGLE_BUTTON" file="common/buy_with_google_button.png" />
- <structure type="chrome_scaled_image" name="IDR_BUY_WITH_GOOGLE_BUTTON_H" file="common/buy_with_google_button_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BUY_WITH_GOOGLE_BUTTON_P" file="common/buy_with_google_button_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_DISABLED" file="common/blue_button_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_HOVER" file="common/blue_button_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_NORMAL" file="common/blue_button_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_PRESSED" file="common/blue_button_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_HOVER" file="common/blue_button_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_NORMAL" file="common/blue_button.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_PRESSED" file="common/blue_button_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX" file="common/checkbox.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED" file="common/checkbox_checked.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_DISABLED" file="common/checkbox_checked_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_HOVER" file="common/checkbox_checked_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_PRESSED" file="common/checkbox_checked_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_DISABLED" file="common/checkbox_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED" file="common/checkbox_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED" file="common/checkbox_focused_checked.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED_HOVER" file="common/checkbox_focused_checked_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED_PRESSED" file="common/checkbox_focused_checked_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_HOVER" file="common/checkbox_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_PRESSED" file="common/checkbox_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_HOVER" file="common/checkbox_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_CHECKBOX_PRESSED" file="common/checkbox_pressed.png" />
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_B" file="bubble_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_BL" file="bubble_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_BR" file="bubble_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_B_ARROW" file="bubble_pointer_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_L" file="bubble_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_L_ARROW" file="bubble_pointer_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_R" file="bubble_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_R_ARROW" file="bubble_pointer_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_T" file="bubble_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_TL" file="bubble_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_TR" file="bubble_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUBBLE_T_ARROW" file="bubble_pointer_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_DISABLED" file="common/button_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_HOVER" file="common/button_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_NORMAL" file="common/button_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_PRESSED" file="common/button_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_HOVER" file="common/button_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_NORMAL" file="common/button.png" />
+ <structure type="chrome_scaled_image" name="IDR_BUTTON_PRESSED" file="common/button_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_DISABLED" file="common/blue_button_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_HOVER" file="common/blue_button_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_NORMAL" file="common/blue_button_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_PRESSED" file="common/blue_button_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_HOVER" file="common/blue_button_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_NORMAL" file="common/blue_button.png" />
+ <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_PRESSED" file="common/blue_button_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX" file="common/checkbox.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED" file="common/checkbox_checked.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_DISABLED" file="common/checkbox_checked_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_HOVER" file="common/checkbox_checked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_PRESSED" file="common/checkbox_checked_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_DISABLED" file="common/checkbox_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED" file="common/checkbox_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED" file="common/checkbox_focused_checked.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED_HOVER" file="common/checkbox_focused_checked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_CHECKED_PRESSED" file="common/checkbox_focused_checked_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_HOVER" file="common/checkbox_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_FOCUSED_PRESSED" file="common/checkbox_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_HOVER" file="common/checkbox_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_CHECKBOX_PRESSED" file="common/checkbox_pressed.png" />
+ </if>
<structure type="chrome_scaled_image" name="IDR_CHECKMARK" file="common/checkmark.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO" file="common/radio.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED" file="common/radio_checked.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_DISABLED" file="common/radio_checked_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_HOVER" file="common/radio_checked_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_PRESSED" file="common/radio_checked_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_DISABLED" file="common/radio_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED" file="common/radio_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED" file="common/radio_focused_checked.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED_HOVER" file="common/radio_focused_checked_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED_PRESSED" file="common/radio_focused_checked_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_HOVER" file="common/radio_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_PRESSED" file="common/radio_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_HOVER" file="common/radio_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_RADIO_PRESSED" file="common/radio_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE" file="common/text_selection_handle_small.png" />
- <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_COPY" file="common/drag_tip_copy.png" />
- <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_MOVE" file="common/drag_tip_move.png" />
- <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_LINK" file="common/drag_tip_link.png" />
- <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_NODROP" file="common/drag_tip_nodrop.png" />
- <if expr="pp_ifdef('desktop_linux')">
+ <if expr="desktop_linux">
<structure type="chrome_scaled_image" name="IDR_CLOSE" file="linux/linux_close.png" />
</if>
- <if expr="not pp_ifdef('desktop_linux') and pp_ifdef('toolkit_views')">
+ <if expr="not desktop_linux and toolkit_views">
<structure type="chrome_scaled_image" name="IDR_CLOSE" file="close.png" />
</if>
<structure type="chrome_scaled_image" name="IDR_CLOSE_2" file="close_2.png" />
@@ -197,119 +180,125 @@
<structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG" file="close_dialog.png" />
<structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_H" file="close_dialog_hover.png" />
<structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_P" file="close_dialog_pressed.png" />
- <if expr="pp_ifdef('desktop_linux')">
+ <if expr="desktop_linux">
<structure type="chrome_scaled_image" name="IDR_CLOSE_H" file="linux/linux_close_hover.png" />
<structure type="chrome_scaled_image" name="IDR_CLOSE_P" file="linux/linux_close_pressed.png" />
</if>
- <if expr="not pp_ifdef('desktop_linux') and pp_ifdef('toolkit_views')">
+ <if expr="not desktop_linux and toolkit_views">
<structure type="chrome_scaled_image" name="IDR_CLOSE_H" file="close_hover.png" />
<structure type="chrome_scaled_image" name="IDR_CLOSE_P" file="close_pressed.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM" file="common/combobox_button_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM" file="common/combobox_button_bottom_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM" file="common/combobox_button_bottom_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_LEFT" file="common/combobox_button_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_RIGHT" file="common/combobox_button_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_CENTER" file="common/combobox_button_center.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_CENTER" file="common/combobox_button_center_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_CENTER" file="common/combobox_button_center_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_LEFT" file="common/combobox_button_center_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_LEFT" file="common/combobox_button_center_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_LEFT" file="common/combobox_button_center_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_RIGHT" file="common/combobox_button_center_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_RIGHT" file="common/combobox_button_center_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_RIGHT" file="common/combobox_button_center_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_BOTTOM" file="common/combobox_button_menu_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_CENTER" file="common/combobox_button_menu_center.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_CENTER" file="common/combobox_button_menu_center_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_CENTER" file="common/combobox_button_menu_center_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_TOP" file="common/combobox_button_menu_top.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_TOP" file="common/combobox_button_menu_top_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_TOP" file="common/combobox_button_menu_top_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP" file="common/combobox_button_top.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP" file="common/combobox_button_top_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP" file="common/combobox_button_top_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_LEFT" file="common/combobox_button_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_LEFT" file="common/combobox_button_top_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_LEFT" file="common/combobox_button_top_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_RIGHT" file="common/combobox_button_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_RIGHT" file="common/combobox_button_top_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_RIGHT" file="common/combobox_button_top_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM" file="common/combobox_button_bottom_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM" file="common/combobox_button_bottom_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM" file="common/combobox_button_bottom_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_CENTER" file="common/combobox_button_center_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_CENTER" file="common/combobox_button_center_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_CENTER" file="common/combobox_button_center_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_LEFT" file="common/combobox_button_center_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_LEFT" file="common/combobox_button_center_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_LEFT" file="common/combobox_button_center_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_RIGHT" file="common/combobox_button_center_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_RIGHT" file="common/combobox_button_center_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_RIGHT" file="common/combobox_button_center_right_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_CENTER" file="common/combobox_button_menu_center_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_CENTER" file="common/combobox_button_menu_center_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_CENTER" file="common/combobox_button_menu_center_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_TOP" file="common/combobox_button_menu_top_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_TOP" file="common/combobox_button_menu_top_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_TOP" file="common/combobox_button_menu_top_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP" file="common/combobox_button_top_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP" file="common/combobox_button_top_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP" file="common/combobox_button_top_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_LEFT" file="common/combobox_button_top_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_LEFT" file="common/combobox_button_top_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_LEFT" file="common/combobox_button_top_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_RIGHT" file="common/combobox_button_top_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_RIGHT" file="common/combobox_button_top_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_RIGHT" file="common/combobox_button_top_right_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_CENTER" file="content_bottom_center.png" />
- <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_LEFT_CORNER" file="content_bottom_left_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_RIGHT_CORNER" file="content_bottom_right_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_CONTENT_LEFT_SIDE" file="content_left_side.png" />
- <structure type="chrome_scaled_image" name="IDR_CONTENT_RIGHT_SIDE" file="content_right_side.png" />
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM" file="common/combobox_button_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM" file="common/combobox_button_bottom_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM" file="common/combobox_button_bottom_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_LEFT" file="common/combobox_button_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_RIGHT" file="common/combobox_button_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_CENTER" file="common/combobox_button_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_CENTER" file="common/combobox_button_center_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_CENTER" file="common/combobox_button_center_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_LEFT" file="common/combobox_button_center_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_LEFT" file="common/combobox_button_center_left_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_LEFT" file="common/combobox_button_center_left_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_RIGHT" file="common/combobox_button_center_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_RIGHT" file="common/combobox_button_center_right_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_RIGHT" file="common/combobox_button_center_right_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_BOTTOM" file="common/combobox_button_menu_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_CENTER" file="common/combobox_button_menu_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_CENTER" file="common/combobox_button_menu_center_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_CENTER" file="common/combobox_button_menu_center_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_TOP" file="common/combobox_button_menu_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_TOP" file="common/combobox_button_menu_top_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_TOP" file="common/combobox_button_menu_top_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP" file="common/combobox_button_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP" file="common/combobox_button_top_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP" file="common/combobox_button_top_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_LEFT" file="common/combobox_button_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_LEFT" file="common/combobox_button_top_left_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_LEFT" file="common/combobox_button_top_left_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_RIGHT" file="common/combobox_button_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_RIGHT" file="common/combobox_button_top_right_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_RIGHT" file="common/combobox_button_top_right_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM" file="common/combobox_button_bottom_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM" file="common/combobox_button_bottom_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM" file="common/combobox_button_bottom_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_CENTER" file="common/combobox_button_center_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_CENTER" file="common/combobox_button_center_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_CENTER" file="common/combobox_button_center_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_LEFT" file="common/combobox_button_center_left_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_LEFT" file="common/combobox_button_center_left_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_LEFT" file="common/combobox_button_center_left_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_RIGHT" file="common/combobox_button_center_right_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_RIGHT" file="common/combobox_button_center_right_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_RIGHT" file="common/combobox_button_center_right_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_CENTER" file="common/combobox_button_menu_center_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_CENTER" file="common/combobox_button_menu_center_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_CENTER" file="common/combobox_button_menu_center_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_TOP" file="common/combobox_button_menu_top_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_TOP" file="common/combobox_button_menu_top_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_TOP" file="common/combobox_button_menu_top_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP" file="common/combobox_button_top_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP" file="common/combobox_button_top_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP" file="common/combobox_button_top_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_LEFT" file="common/combobox_button_top_left_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_LEFT" file="common/combobox_button_top_left_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_LEFT" file="common/combobox_button_top_left_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_RIGHT" file="common/combobox_button_top_right_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_RIGHT" file="common/combobox_button_top_right_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_RIGHT" file="common/combobox_button_top_right_focused_pressed.png" />
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_CENTER" file="content_bottom_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_LEFT_CORNER" file="content_bottom_left_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_RIGHT_CORNER" file="content_bottom_right_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_CONTENT_LEFT_SIDE" file="content_left_side.png" />
+ <structure type="chrome_scaled_image" name="IDR_CONTENT_RIGHT_SIDE" file="content_right_side.png" />
+ </if>
<structure type="chrome_scaled_image" name="IDR_DEFAULT_FAVICON" file="common/default_favicon.png" />
<structure type="chrome_scaled_image" name="IDR_DEFAULT_FAVICON_32" file="common/default_favicon_32.png" />
<structure type="chrome_scaled_image" name="IDR_DEFAULT_FAVICON_64" file="common/default_favicon_64.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" />
- <structure type="chrome_scaled_image" name="IDR_FOLDER_OPEN" file="common/folder_open.png" />
- <structure type="chrome_scaled_image" name="IDR_FOLDER_OPEN_RTL" file="common/folder_open_rtl.png" />
- <structure type="chrome_scaled_image" name="IDR_FRAME" file="frame_default.png" />
- <structure type="chrome_scaled_image" name="IDR_FRAME_APP_PANEL" file="frame_app_panel_default.png" />
- <structure type="chrome_scaled_image" name="IDR_FRAME_INACTIVE" file="frame_default_inactive.png" />
- <if expr="pp_ifdef('desktop_linux')">
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_FOLDER_OPEN" file="common/folder_open.png" />
+ <structure type="chrome_scaled_image" name="IDR_FOLDER_OPEN_RTL" file="common/folder_open_rtl.png" />
+ <structure type="chrome_scaled_image" name="IDR_FRAME" file="frame_default.png" />
+ <structure type="chrome_scaled_image" name="IDR_FRAME_APP_PANEL" file="frame_app_panel_default.png" />
+ <structure type="chrome_scaled_image" name="IDR_FRAME_INACTIVE" file="frame_default_inactive.png" />
+ </if>
+ <if expr="desktop_linux">
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="linux/linux_maximize.png" />
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="linux/linux_maximize_hover.png" />
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="linux/linux_maximize_pressed.png" />
</if>
- <if expr="not pp_ifdef('desktop_linux') and pp_ifdef('toolkit_views')">
+ <if expr="not desktop_linux and toolkit_views">
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="maximize.png" />
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="maximize_hover.png" />
<structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="maximize_pressed.png" />
</if>
- <if expr="pp_ifdef('toolkit_views')">
+ <if expr="toolkit_views">
<structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="common/menu_hierarchy_arrow.png" />
<structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW_DARK_BACKGROUND" file="common/menu_hierarchy_arrow_white.png" />
</if>
- <if expr="is_macosx or is_ios">
+ <if expr="(is_macosx or is_ios) and not toolkit_views">
<structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="mac/menu_hierarchy_arrow.png" />
</if>
- <if expr="pp_ifdef('toolkit_views')">
+ <if expr="toolkit_views">
<structure type="chrome_scaled_image" name="IDR_MENU_CHECK" file="cros/menu_check.png" />
<structure type="chrome_scaled_image" name="IDR_MENU_CHECK_CHECKED" file="common/menu_check.png" />
<structure type="chrome_scaled_image" name="IDR_MENU_CHECK_CHECKED_DARK_BACKGROUND" file="common/menu_check_white.png" />
@@ -329,121 +318,210 @@
</if>
<structure type="chrome_scaled_image" name="IDR_MENU_DROPARROW" file="cros/menu_droparrow.png" />
<structure type="chrome_scaled_image" name="IDR_MESSAGE_CLOSE" file="common/message_close.png" />
- <if expr="pp_ifdef('desktop_linux')">
+ <if expr="desktop_linux">
<structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="linux/linux_minimize.png" />
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="linux/linux_minimize_hover.png" />
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="linux/linux_minimize_pressed.png" />
</if>
- <if expr="not pp_ifdef('desktop_linux') and pp_ifdef('toolkit_views')">
+ <if expr="not desktop_linux and toolkit_views">
<structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="minimize.png" />
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="minimize_hover.png" />
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="minimize_pressed.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW" file="common/notification_arrow.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_HOVER" file="common/notification_arrow_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_PRESSED" file="common/notification_arrow_pressed.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS" file="common/notification_advanced_settings.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS_HOVER" file="common/notification_advanced_settings_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS_PRESSED" file="common/notification_advanced_settings_pressed.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL" file="common/notification_clear_all.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_DISABLED" file="common/notification_clear_all_disabled.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_HOVER" file="common/notification_clear_all_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_PRESSED" file="common/notification_clear_all_pressed.png"/>
- <if expr="is_win">
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="win/notification_close.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="win/notification_close_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="win/notification_close_pressed.png"/>
- </if>
- <if expr="not is_win">
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="common/notification_close.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="common/notification_close_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="common/notification_close_pressed.png"/>
- </if>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EXPAND" file="common/notification_expand.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EXPAND_HOVER" file="common/notification_expand_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EXPAND_PRESSED" file="common/notification_expand_pressed.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB" file="common/notification_do_not_disturb.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER" file="common/notification_do_not_disturb_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED" file="common/notification_do_not_disturb_pressed.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS" file="common/notification_settings.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_HOVER" file="common/notification_settings_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_PRESSED" file="common/notification_settings_pressed.png"/>
- <if expr="pp_ifdef('use_aura')">
- <structure type="chrome_scaled_image" name="IDR_OAK" file="oak.png" />
- </if>
- <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_HOVER" file="cros/action_box_button_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_NORMAL" file="cros/action_box_button_normal.png" />
- <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_PRESSED" file="cros/action_box_button_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_LEFT_CORNER" file="panel_top_left_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_RIGHT_CORNER" file="panel_top_right_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_LEFT_CORNER" file="panel_bottom_left_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_RIGHT_CORNER" file="panel_bottom_right_corner.png" />
- <if expr="is_posix and not is_macosx and not is_ios and not pp_ifdef('use_aura')">
+ <if expr="toolkit_views or is_macosx or is_ios">
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW" file="common/notification_arrow.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_HOVER" file="common/notification_arrow_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_PRESSED" file="common/notification_arrow_pressed.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS" file="common/notification_advanced_settings.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS_HOVER" file="common/notification_advanced_settings_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ADVANCED_SETTINGS_PRESSED" file="common/notification_advanced_settings_pressed.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL" file="common/notification_clear_all.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_DISABLED" file="common/notification_clear_all_disabled.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_HOVER" file="common/notification_clear_all_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_PRESSED" file="common/notification_clear_all_pressed.png"/>
+ <if expr="is_win">
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="win/notification_close.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="win/notification_close_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="win/notification_close_pressed.png"/>
+ </if>
+ <if expr="not is_win">
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="common/notification_close.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="common/notification_close_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="common/notification_close_pressed.png"/>
+ </if>
+ <if expr="desktop_linux and use_aura">
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_BUBBLE_CLOSE" file="common/notification_bubble_close.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_BUBBLE_CLOSE_HOVER" file="common/notification_bubble_close_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_BUBBLE_CLOSE_PRESSED" file="common/notification_bubble_close_pressed.png"/>
+ </if>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB" file="common/notification_do_not_disturb.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER" file="common/notification_do_not_disturb_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED" file="common/notification_do_not_disturb_pressed.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS" file="common/notification_settings.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_HOVER" file="common/notification_settings_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_PRESSED" file="common/notification_settings_pressed.png"/>
+ </if>
+ <if expr="not is_android and not is_ios">
+ <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_HOVER" file="cros/action_box_button_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_NORMAL" file="cros/action_box_button_normal.png" />
+ <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_PRESSED" file="cros/action_box_button_pressed.png" />
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_LEFT_CORNER" file="panel_top_left_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_RIGHT_CORNER" file="panel_top_right_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_LEFT_CORNER" file="panel_bottom_left_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_RIGHT_CORNER" file="panel_bottom_right_corner.png" />
+ </if>
+ <if expr="is_posix and not is_macosx and not is_ios and not use_aura">
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BAR" file="linux/linux-progress-bar.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_LEFT" file="linux/linux-progress-border-left.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_RIGHT" file="linux/linux-progress-border-right.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_VALUE" file="linux/linux-progress-value.png" />
</if>
- <if expr="pp_ifdef('use_aura')">
+ <if expr="use_aura">
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BAR" file="linux/linux-progress-bar.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_LEFT" file="linux/linux-progress-border-left.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_RIGHT" file="linux/linux-progress-border-right.png" />
<structure type="chrome_scaled_image" name="IDR_PROGRESS_VALUE" file="linux/linux-progress-value.png" />
-
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_HORIZONTAL_CENTER_H" file="cros/aura_scrollbar_base_horizontal_hover_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_HORIZONTAL_LEFT_H" file="cros/aura_scrollbar_base_horizontal_hover_left.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_HORIZONTAL_RIGHT_H" file="cros/aura_scrollbar_base_horizontal_hover_right.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_VERTICAL_BOTTOM_H" file="cros/aura_scrollbar_base_vertical_hover_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_VERTICAL_CENTER_H" file="cros/aura_scrollbar_base_vertical_hover_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_BASE_VERTICAL_TOP_H" file="cros/aura_scrollbar_base_vertical_hover_top.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_CENTER" file="cros/aura_scrollbar_thumb_horizontal_normal_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_CENTER_H" file="cros/aura_scrollbar_thumb_horizontal_hover_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_CENTER_P" file="cros/aura_scrollbar_thumb_horizontal_pressed_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_LEFT" file="cros/aura_scrollbar_thumb_horizontal_normal_left.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_LEFT_H" file="cros/aura_scrollbar_thumb_horizontal_hover_left.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_LEFT_P" file="cros/aura_scrollbar_thumb_horizontal_pressed_left.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_RIGHT" file="cros/aura_scrollbar_thumb_horizontal_normal_right.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_RIGHT_H" file="cros/aura_scrollbar_thumb_horizontal_hover_right.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_HORIZONTAL_RIGHT_P" file="cros/aura_scrollbar_thumb_horizontal_pressed_right.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_BOTTOM" file="cros/aura_scrollbar_thumb_vertical_normal_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_BOTTOM_H" file="cros/aura_scrollbar_thumb_vertical_hover_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_BOTTOM_P" file="cros/aura_scrollbar_thumb_vertical_pressed_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_CENTER" file="cros/aura_scrollbar_thumb_vertical_normal_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_CENTER_H" file="cros/aura_scrollbar_thumb_vertical_hover_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_CENTER_P" file="cros/aura_scrollbar_thumb_vertical_pressed_center.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_TOP" file="cros/aura_scrollbar_thumb_vertical_normal_top.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_TOP_H" file="cros/aura_scrollbar_thumb_vertical_hover_top.png" />
- <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_TOP_P" file="cros/aura_scrollbar_thumb_vertical_pressed_top.png" />
- </if>
- <if expr="pp_ifdef('desktop_linux')">
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_RADIO" file="common/radio.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED" file="common/radio_checked.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_DISABLED" file="common/radio_checked_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_HOVER" file="common/radio_checked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_CHECKED_PRESSED" file="common/radio_checked_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_DISABLED" file="common/radio_inactive.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED" file="common/radio_focused.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED" file="common/radio_focused_checked.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED_HOVER" file="common/radio_focused_checked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_CHECKED_PRESSED" file="common/radio_focused_checked_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_HOVER" file="common/radio_focused_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_FOCUSED_PRESSED" file="common/radio_focused_pressed.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_HOVER" file="common/radio_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_RADIO_PRESSED" file="common/radio_pressed.png" />
+ </if>
+ <if expr="desktop_linux">
<structure type="chrome_scaled_image" name="IDR_RESTORE" file="linux/linux_restore.png" />
<structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="linux/linux_restore_hover.png" />
<structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="linux/linux_restore_pressed.png" />
</if>
- <if expr="not pp_ifdef('desktop_linux') and pp_ifdef('toolkit_views')">
+ <if expr="not desktop_linux and toolkit_views">
<structure type="chrome_scaled_image" name="IDR_RESTORE" file="restore.png" />
<structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="restore_hover.png" />
<structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="restore_pressed.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM" file="common/textbutton_hover_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_LEFT" file="common/textbutton_hover_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_RIGHT" file="common/textbutton_hover_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_CENTER" file="common/textbutton_hover_center.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_LEFT" file="common/textbutton_hover_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_RIGHT" file="common/textbutton_hover_right.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP" file="common/textbutton_hover_top.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP_LEFT" file="common/textbutton_hover_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP_RIGHT" file="common/textbutton_hover_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM" file="common/textbutton_pressed_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM_LEFT" file="common/textbutton_pressed_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM_RIGHT" file="common/textbutton_pressed_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_CENTER" file="common/textbutton_pressed_center.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_LEFT" file="common/textbutton_pressed_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_RIGHT" file="common/textbutton_pressed_right.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP" file="common/textbutton_pressed_top.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_LEFT" file="common/textbutton_pressed_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_RIGHT" file="common/textbutton_pressed_top_right.png" />
+ <if expr="use_aura">
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_BOTTOM" file="common/aura_scrollbar_arrow_button_base_hover_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_BOTTOM_LEFT" file="common/aura_scrollbar_arrow_button_base_hover_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_BOTTOM_RIGHT" file="common/aura_scrollbar_arrow_button_base_hover_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_CENTER" file="common/aura_scrollbar_arrow_button_base_hover_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_LEFT" file="common/aura_scrollbar_arrow_button_base_hover_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_RIGHT" file="common/aura_scrollbar_arrow_button_base_hover_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_TOP" file="common/aura_scrollbar_arrow_button_base_hover_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_TOP_LEFT" file="common/aura_scrollbar_arrow_button_base_hover_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER_TOP_RIGHT" file="common/aura_scrollbar_arrow_button_base_hover_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_BOTTOM" file="common/aura_scrollbar_arrow_button_base_normal_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_BOTTOM_LEFT" file="common/aura_scrollbar_arrow_button_base_normal_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_BOTTOM_RIGHT" file="common/aura_scrollbar_arrow_button_base_normal_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_CENTER" file="common/aura_scrollbar_arrow_button_base_normal_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_LEFT" file="common/aura_scrollbar_arrow_button_base_normal_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_RIGHT" file="common/aura_scrollbar_arrow_button_base_normal_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_TOP" file="common/aura_scrollbar_arrow_button_base_normal_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_TOP_LEFT" file="common/aura_scrollbar_arrow_button_base_normal_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL_TOP_RIGHT" file="common/aura_scrollbar_arrow_button_base_normal_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_BOTTOM" file="common/aura_scrollbar_arrow_button_base_pressed_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_BOTTOM_LEFT" file="common/aura_scrollbar_arrow_button_base_pressed_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_BOTTOM_RIGHT" file="common/aura_scrollbar_arrow_button_base_pressed_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_CENTER" file="common/aura_scrollbar_arrow_button_base_pressed_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_LEFT" file="common/aura_scrollbar_arrow_button_base_pressed_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_RIGHT" file="common/aura_scrollbar_arrow_button_base_pressed_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_TOP" file="common/aura_scrollbar_arrow_button_base_pressed_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_TOP_LEFT" file="common/aura_scrollbar_arrow_button_base_pressed_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED_TOP_RIGHT" file="common/aura_scrollbar_arrow_button_base_pressed_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_BOTTOM" file="common/aura_scrollbar_base_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_BOTTOM_LEFT" file="common/aura_scrollbar_base_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_BOTTOM_RIGHT" file="common/aura_scrollbar_base_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_CENTER" file="common/aura_scrollbar_base_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_LEFT" file="common/aura_scrollbar_base_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_RIGHT" file="common/aura_scrollbar_base_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_TOP" file="common/aura_scrollbar_base_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_TOP_LEFT" file="common/aura_scrollbar_base_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_BASE_TOP_RIGHT" file="common/aura_scrollbar_base_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_BOTTOM" file="common/aura_scrollbar_overlay_thumb_fill_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_BOTTOM_LEFT" file="common/aura_scrollbar_overlay_thumb_fill_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_BOTTOM_RIGHT" file="common/aura_scrollbar_overlay_thumb_fill_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_CENTER" file="common/aura_scrollbar_overlay_thumb_fill_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_LEFT" file="common/aura_scrollbar_overlay_thumb_fill_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_RIGHT" file="common/aura_scrollbar_overlay_thumb_fill_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_TOP" file="common/aura_scrollbar_overlay_thumb_fill_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_TOP_LEFT" file="common/aura_scrollbar_overlay_thumb_fill_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_FILL_TOP_RIGHT" file="common/aura_scrollbar_overlay_thumb_fill_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_BOTTOM" file="common/aura_scrollbar_overlay_thumb_stroke_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_BOTTOM_LEFT" file="common/aura_scrollbar_overlay_thumb_stroke_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_BOTTOM_RIGHT" file="common/aura_scrollbar_overlay_thumb_stroke_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_LEFT" file="common/aura_scrollbar_overlay_thumb_stroke_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_RIGHT" file="common/aura_scrollbar_overlay_thumb_stroke_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_TOP" file="common/aura_scrollbar_overlay_thumb_stroke_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_TOP_LEFT" file="common/aura_scrollbar_overlay_thumb_stroke_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_OVERLAY_THUMB_STROKE_TOP_RIGHT" file="common/aura_scrollbar_overlay_thumb_stroke_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_BOTTOM" file="common/aura_scrollbar_thumb_base_hover_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_BOTTOM_LEFT" file="common/aura_scrollbar_thumb_base_hover_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_BOTTOM_RIGHT" file="common/aura_scrollbar_thumb_base_hover_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_CENTER" file="common/aura_scrollbar_thumb_base_hover_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_LEFT" file="common/aura_scrollbar_thumb_base_hover_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_RIGHT" file="common/aura_scrollbar_thumb_base_hover_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_TOP" file="common/aura_scrollbar_thumb_base_hover_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_TOP_LEFT" file="common/aura_scrollbar_thumb_base_hover_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_HOVER_TOP_RIGHT" file="common/aura_scrollbar_thumb_base_hover_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_BOTTOM" file="common/aura_scrollbar_thumb_base_normal_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_BOTTOM_LEFT" file="common/aura_scrollbar_thumb_base_normal_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_BOTTOM_RIGHT" file="common/aura_scrollbar_thumb_base_normal_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_CENTER" file="common/aura_scrollbar_thumb_base_normal_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_LEFT" file="common/aura_scrollbar_thumb_base_normal_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_RIGHT" file="common/aura_scrollbar_thumb_base_normal_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_TOP" file="common/aura_scrollbar_thumb_base_normal_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_TOP_LEFT" file="common/aura_scrollbar_thumb_base_normal_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_NORMAL_TOP_RIGHT" file="common/aura_scrollbar_thumb_base_normal_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_BOTTOM" file="common/aura_scrollbar_thumb_base_pressed_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_BOTTOM_LEFT" file="common/aura_scrollbar_thumb_base_pressed_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_BOTTOM_RIGHT" file="common/aura_scrollbar_thumb_base_pressed_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_CENTER" file="common/aura_scrollbar_thumb_base_pressed_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_LEFT" file="common/aura_scrollbar_thumb_base_pressed_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_RIGHT" file="common/aura_scrollbar_thumb_base_pressed_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_TOP" file="common/aura_scrollbar_thumb_base_pressed_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_TOP_LEFT" file="common/aura_scrollbar_thumb_base_pressed_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_SCROLLBAR_THUMB_BASE_PRESSED_TOP_RIGHT" file="common/aura_scrollbar_thumb_base_pressed_top_right.png" />
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM" file="common/textbutton_hover_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_LEFT" file="common/textbutton_hover_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_BOTTOM_RIGHT" file="common/textbutton_hover_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_CENTER" file="common/textbutton_hover_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_LEFT" file="common/textbutton_hover_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_RIGHT" file="common/textbutton_hover_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP" file="common/textbutton_hover_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP_LEFT" file="common/textbutton_hover_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_HOVER_TOP_RIGHT" file="common/textbutton_hover_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM" file="common/textbutton_pressed_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM_LEFT" file="common/textbutton_pressed_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_BOTTOM_RIGHT" file="common/textbutton_pressed_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_CENTER" file="common/textbutton_pressed_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_LEFT" file="common/textbutton_pressed_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_RIGHT" file="common/textbutton_pressed_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP" file="common/textbutton_pressed_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_LEFT" file="common/textbutton_pressed_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_RIGHT" file="common/textbutton_pressed_top_right.png" />
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE" file="common/text_selection_handle_small.png" />
+ </if>
<structure type="chrome_scaled_image" name="IDR_THROBBER" file="throbber.png" />
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_COPY" file="common/drag_tip_copy.png" />
+ <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_MOVE" file="common/drag_tip_move.png" />
+ <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_LINK" file="common/drag_tip_link.png" />
+ <structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_NODROP" file="common/drag_tip_nodrop.png" />
+ </if>
<if expr="is_macosx or is_ios">
<structure type="chrome_scaled_image" name="IDR_TRAY_ATTENTION" file="mac/notification_tray_attention.png"/>
<structure type="chrome_scaled_image" name="IDR_TRAY_ATTENTION_PRESSED" file="mac/notification_tray_attention_pressed.png"/>
@@ -454,38 +532,42 @@
<structure type="chrome_scaled_image" name="IDR_TRAY_EMPTY" file="mac/notification_tray_empty.png"/>
<structure type="chrome_scaled_image" name="IDR_TRAY_EMPTY_PRESSED" file="mac/notification_tray_empty_pressed.png"/>
</if>
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_CENTER" file="common/window_bottom_center.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_LEFT_CORNER" file="common/window_bottom_left_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_RIGHT_CORNER" file="common/window_bottom_right_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_LEFT_SIDE" file="common/window_left_side.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_RIGHT_SIDE" file="common/window_right_side.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_CENTER" file="common/window_top_center.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_LEFT_CORNER" file="common/window_top_left_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_RIGHT_CORNER" file="common/window_top_right_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM" file="common/window_bubble_shadow_big_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT" file="common/window_bubble_shadow_big_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT" file="common/window_bubble_shadow_big_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT" file="common/window_bubble_shadow_big_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT" file="common/window_bubble_shadow_big_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP" file="common/window_bubble_shadow_big_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT" file="common/window_bubble_shadow_big_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT" file="common/window_bubble_shadow_big_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM" file="common/window_bubble_shadow_spike_big_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT" file="common/window_bubble_shadow_spike_big_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT" file="common/window_bubble_shadow_spike_big_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP" file="common/window_bubble_shadow_spike_big_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM" file="common/window_bubble_shadow_small_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT" file="common/window_bubble_shadow_small_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT" file="common/window_bubble_shadow_small_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT" file="common/window_bubble_shadow_small_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT" file="common/window_bubble_shadow_small_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP" file="common/window_bubble_shadow_small_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT" file="common/window_bubble_shadow_small_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT" file="common/window_bubble_shadow_small_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM" file="common/window_bubble_shadow_spike_small_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT" file="common/window_bubble_shadow_spike_small_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT" file="common/window_bubble_shadow_spike_small_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP" file="common/window_bubble_shadow_spike_small_top.png" />
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_CENTER" file="common/window_bottom_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_LEFT_CORNER" file="common/window_bottom_left_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BOTTOM_RIGHT_CORNER" file="common/window_bottom_right_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_LEFT_SIDE" file="common/window_left_side.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_RIGHT_SIDE" file="common/window_right_side.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_CENTER" file="common/window_top_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_LEFT_CORNER" file="common/window_top_left_corner.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_RIGHT_CORNER" file="common/window_top_right_corner.png" />
+ </if>
+ <if expr="toolkit_views">
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM" file="common/window_bubble_shadow_big_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT" file="common/window_bubble_shadow_big_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT" file="common/window_bubble_shadow_big_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT" file="common/window_bubble_shadow_big_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT" file="common/window_bubble_shadow_big_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP" file="common/window_bubble_shadow_big_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT" file="common/window_bubble_shadow_big_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT" file="common/window_bubble_shadow_big_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM" file="common/window_bubble_shadow_spike_big_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT" file="common/window_bubble_shadow_spike_big_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT" file="common/window_bubble_shadow_spike_big_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP" file="common/window_bubble_shadow_spike_big_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM" file="common/window_bubble_shadow_small_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT" file="common/window_bubble_shadow_small_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT" file="common/window_bubble_shadow_small_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT" file="common/window_bubble_shadow_small_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT" file="common/window_bubble_shadow_small_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP" file="common/window_bubble_shadow_small_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT" file="common/window_bubble_shadow_small_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT" file="common/window_bubble_shadow_small_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM" file="common/window_bubble_shadow_spike_small_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT" file="common/window_bubble_shadow_spike_small_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT" file="common/window_bubble_shadow_spike_small_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP" file="common/window_bubble_shadow_spike_small_top.png" />
+ </if>
</structures>
</release>
</grit>
diff --git a/chromium/ui/resources/ui_resources.gyp b/chromium/ui/resources/ui_resources.gyp
index dbc800c9629..34b3c14617c 100644
--- a/chromium/ui/resources/ui_resources.gyp
+++ b/chromium/ui/resources/ui_resources.gyp
@@ -41,12 +41,9 @@
'target_name': 'ui_test_pak',
'type': 'none',
'dependencies': [
- '../base/strings/ui_strings.gyp:ui_strings',
+ '../strings/ui_strings.gyp:ui_strings',
'ui_resources',
],
- 'variables': {
- 'repack_path': '../../tools/grit/grit/format/repack.py',
- },
'actions': [
{
'action_name': 'repack_ui_test_pack',
@@ -57,16 +54,62 @@
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/webui_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings/ui_strings_en-US.pak',
],
+ 'pak_output': '<(PRODUCT_DIR)/ui_test.pak',
},
- 'inputs': [
- '<(repack_path)',
- '<@(pak_inputs)',
+ 'includes': [ '../../build/repack_action.gypi' ],
+ },
+ ],
+ 'conditions': [
+ ['OS != "mac"', {
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/ui',
+ 'files': [
+ '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources_100_percent.pak',
+ ],
+ },
],
- 'outputs': [
- '<(PRODUCT_DIR)/ui_test.pak',
+ }],
+ ['OS == "ios"', {
+ 'actions': [
+ {
+ 'action_name': 'copy_ui_test_pak',
+ 'message': 'Copying ui_test.pak into locale.pak',
+ 'inputs': [
+ '<(PRODUCT_DIR)/ui_test.pak',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/ui/en.lproj/locale.pak',
+ ],
+ 'action': [
+ 'python',
+ '../../build/cp.py',
+ '<@(_inputs)',
+ '<@(_outputs)'
+ ],
+ },
],
- 'action': ['python', '<(repack_path)', '<@(_outputs)', '<@(pak_inputs)'],
- },
+ }],
+ ['OS != "mac" and OS !="ios"', {
+ 'actions': [
+ {
+ 'action_name': 'copy_ui_test_pak',
+ 'message': 'Copying ui_test.pak into en-US.pak',
+ 'inputs': [
+ '<(PRODUCT_DIR)/ui_test.pak',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/ui/en-US.pak',
+ ],
+ 'action': [
+ 'python',
+ '../../build/cp.py',
+ '<@(_inputs)',
+ '<@(_outputs)'
+ ],
+ },
+ ],
+ }],
],
},
],
diff --git a/chromium/ui/shell_dialogs/DEPS b/chromium/ui/shell_dialogs/DEPS
index acb8514c82d..9d4f4134342 100644
--- a/chromium/ui/shell_dialogs/DEPS
+++ b/chromium/ui/shell_dialogs/DEPS
@@ -4,4 +4,5 @@ include_rules = [
"+ui/aura",
"+ui/base",
"+ui/gfx",
+ "+win8/viewer",
]
diff --git a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
index e121fbfbd16..9ccd1bbc456 100644
--- a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
@@ -30,9 +30,7 @@ BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
DCHECK(!IsRunningDialogForOwner(owner));
// The owner must be a top level window, otherwise we could end up with two
// entries in our map for the same top level window.
- // TODO(scottmg): This should be re-enabled when Chrome Frame is removed.
- // http://crbug.com/310264
- // DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
+ DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
RunState run_state;
run_state.dialog_thread = CreateDialogThread();
run_state.owner = owner;
diff --git a/chromium/ui/shell_dialogs/gtk/OWNERS b/chromium/ui/shell_dialogs/gtk/OWNERS
deleted file mode 100644
index 0573e6b64cb..00000000000
--- a/chromium/ui/shell_dialogs/gtk/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-erg@chromium.org
-estade@chromium.org
diff --git a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.cc b/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.cc
deleted file mode 100644
index c7e80c1a38c..00000000000
--- a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.cc
+++ /dev/null
@@ -1,92 +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.
-//
-// This file implements common select dialog functionality between GTK and KDE.
-
-#include "ui/shell_dialogs/gtk/select_file_dialog_impl.h"
-
-#include "base/environment.h"
-#include "base/file_util.h"
-#include "base/nix/xdg_util.h"
-#include "base/threading/thread_restrictions.h"
-
-namespace {
-
-enum UseKdeFileDialogStatus {
- UNKNOWN,
- NO_KDE,
- YES_KDE
-};
-
-UseKdeFileDialogStatus use_kde_ = UNKNOWN;
-
-} // namespace
-
-namespace ui {
-
-base::FilePath* SelectFileDialogImpl::last_saved_path_ = NULL;
-base::FilePath* SelectFileDialogImpl::last_opened_path_ = NULL;
-
-// static
-SelectFileDialog* CreateLinuxSelectFileDialog(
- SelectFileDialog::Listener* listener,
- SelectFilePolicy* policy) {
- if (use_kde_ == UNKNOWN) {
- // Start out assumimg we are not going to use KDE.
- use_kde_ = NO_KDE;
-
- // Check to see if KDE is the desktop environment.
- scoped_ptr<base::Environment> env(base::Environment::Create());
- base::nix::DesktopEnvironment desktop =
- base::nix::GetDesktopEnvironment(env.get());
- if (desktop == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
- desktop == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
- // Check to see if the user dislikes the KDE file dialog.
- if (!env->HasVar("NO_CHROME_KDE_FILE_DIALOG")) {
- // Check to see if the KDE dialog works.
- if (SelectFileDialogImpl::CheckKDEDialogWorksOnUIThread()) {
- use_kde_ = YES_KDE;
- }
- }
- }
- }
-
- if (use_kde_ == NO_KDE)
- return SelectFileDialogImpl::NewSelectFileDialogImplGTK(listener, policy);
-
- scoped_ptr<base::Environment> env(base::Environment::Create());
- base::nix::DesktopEnvironment desktop =
- base::nix::GetDesktopEnvironment(env.get());
- return SelectFileDialogImpl::NewSelectFileDialogImplKDE(
- listener, policy, desktop);
-}
-
-SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener,
- ui::SelectFilePolicy* policy)
- : SelectFileDialog(listener, policy),
- file_type_index_(0),
- type_(SELECT_NONE) {
- if (!last_saved_path_) {
- last_saved_path_ = new base::FilePath();
- last_opened_path_ = new base::FilePath();
- }
-}
-
-SelectFileDialogImpl::~SelectFileDialogImpl() { }
-
-void SelectFileDialogImpl::ListenerDestroyed() {
- listener_ = NULL;
-}
-
-bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const {
- return parents_.find(parent_window) != parents_.end();
-}
-
-bool SelectFileDialogImpl::CallDirectoryExistsOnUIThread(
- const base::FilePath& path) {
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- return base::DirectoryExists(path);
-}
-
-} // namespace ui
diff --git a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.h b/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.h
deleted file mode 100644
index ebe497fb6f6..00000000000
--- a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl.h
+++ /dev/null
@@ -1,89 +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.
-//
-// This file implements common select dialog functionality between GTK and KDE.
-
-#ifndef UI_SHELL_DIALOGS_GTK_SELECT_FILE_DIALOG_IMPL_H_
-#define UI_SHELL_DIALOGS_GTK_SELECT_FILE_DIALOG_IMPL_H_
-
-#include <set>
-
-#include "base/compiler_specific.h"
-#include "base/nix/xdg_util.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-
-namespace ui {
-
-// Shared implementation SelectFileDialog used by SelectFileDialogImplGTK
-class SelectFileDialogImpl : public SelectFileDialog {
- public:
- // Factory method for creating a GTK-styled SelectFileDialogImpl
- static SelectFileDialogImpl* NewSelectFileDialogImplGTK(
- Listener* listener,
- ui::SelectFilePolicy* policy);
- // Factory method for creating a KDE-styled SelectFileDialogImpl
- static SelectFileDialogImpl* NewSelectFileDialogImplKDE(
- Listener* listener,
- ui::SelectFilePolicy* policy,
- base::nix::DesktopEnvironment desktop);
-
- // Returns true if the SelectFileDialog class returned by
- // NewSelectFileDialogImplKDE will actually work.
- static bool CheckKDEDialogWorksOnUIThread();
-
- // BaseShellDialog implementation.
- virtual bool IsRunning(gfx::NativeWindow parent_window) const OVERRIDE;
- virtual void ListenerDestroyed() OVERRIDE;
-
- protected:
- explicit SelectFileDialogImpl(Listener* listener,
- ui::SelectFilePolicy* policy);
- virtual ~SelectFileDialogImpl();
-
- // SelectFileDialog implementation.
- // |params| is user data we pass back via the Listener interface.
- virtual void SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) = 0;
-
- // Wrapper for base::DirectoryExists() that allow access on the UI
- // thread. Use this only in the file dialog functions, where it's ok
- // because the file dialog has to do many stats anyway. One more won't
- // hurt too badly and it's likely already cached.
- bool CallDirectoryExistsOnUIThread(const base::FilePath& path);
-
- // The file filters.
- FileTypeInfo file_types_;
-
- // The index of the default selected file filter.
- // Note: This starts from 1, not 0.
- size_t file_type_index_;
-
- // The set of all parent windows for which we are currently running dialogs.
- std::set<GtkWindow*> parents_;
-
- // The type of dialog we are showing the user.
- Type type_;
-
- // These two variables track where the user last saved a file or opened a
- // file so that we can display future dialogs with the same starting path.
- static base::FilePath* last_saved_path_;
- static base::FilePath* last_opened_path_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
-};
-
-SelectFileDialog* CreateLinuxSelectFileDialog(
- SelectFileDialog::Listener* listener,
- SelectFilePolicy* policy);
-
-} // namespace ui
-
-#endif // UI_SHELL_DIALOGS_GTK_SELECT_FILE_DIALOG_IMPL_H_
diff --git a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_gtk.cc b/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_gtk.cc
deleted file mode 100644
index ecb97dcd794..00000000000
--- a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_gtk.cc
+++ /dev/null
@@ -1,596 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <gtk/gtk.h>
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "grit/ui_strings.h"
-#include "ui/base/gtk/gtk_signal.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/shell_dialogs/gtk/select_file_dialog_impl.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-
-namespace {
-
-// Makes sure that .jpg also shows .JPG.
-gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
- std::string* file_extension) {
- return EndsWith(file_info->filename, *file_extension, false);
-}
-
-// Deletes |data| when gtk_file_filter_add_custom() is done with it.
-void OnFileFilterDataDestroyed(std::string* file_extension) {
- delete file_extension;
-}
-
-// Implementation of SelectFileDialog that shows a Gtk common dialog for
-// choosing a file or folder. This acts as a modal dialog.
-class SelectFileDialogImplGTK : public ui::SelectFileDialogImpl {
- public:
- explicit SelectFileDialogImplGTK(Listener* listener,
- ui::SelectFilePolicy* policy);
-
- protected:
- virtual ~SelectFileDialogImplGTK();
-
- // SelectFileDialog implementation.
- // |params| is user data we pass back via the Listener interface.
- virtual void SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) OVERRIDE;
-
- private:
- virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
-
- // Add the filters from |file_types_| to |chooser|.
- void AddFilters(GtkFileChooser* chooser);
-
- // Notifies the listener that a single file was chosen.
- void FileSelected(GtkWidget* dialog, const base::FilePath& path);
-
- // Notifies the listener that multiple files were chosen.
- void MultiFilesSelected(GtkWidget* dialog,
- const std::vector<base::FilePath>& files);
-
- // Notifies the listener that no file was chosen (the action was canceled).
- // Dialog is passed so we can find that |params| pointer that was passed to
- // us when we were told to show the dialog.
- void FileNotSelected(GtkWidget* dialog);
-
- GtkWidget* CreateSelectFolderDialog(
- Type type,
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent);
-
- GtkWidget* CreateFileOpenDialog(const std::string& title,
- const base::FilePath& default_path, gfx::NativeWindow parent);
-
- GtkWidget* CreateMultiFileOpenDialog(const std::string& title,
- const base::FilePath& default_path, gfx::NativeWindow parent);
-
- GtkWidget* CreateSaveAsDialog(const std::string& title,
- const base::FilePath& default_path, gfx::NativeWindow parent);
-
- // Removes and returns the |params| associated with |dialog| from
- // |params_map_|.
- void* PopParamsForDialog(GtkWidget* dialog);
-
- // Take care of internal data structures when a file dialog is destroyed.
- void FileDialogDestroyed(GtkWidget* dialog);
-
- // Check whether response_id corresponds to the user cancelling/closing the
- // dialog. Used as a helper for the below callbacks.
- bool IsCancelResponse(gint response_id);
-
- // Common function for OnSelectSingleFileDialogResponse and
- // OnSelectSingleFolderDialogResponse.
- void SelectSingleFileHelper(GtkWidget* dialog,
- gint response_id,
- bool allow_folder);
-
- // Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
- GtkWidget* CreateFileOpenHelper(const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent);
-
- // Callback for when the user responds to a Save As or Open File dialog.
- CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void,
- OnSelectSingleFileDialogResponse, int);
-
- // Callback for when the user responds to a Select Folder dialog.
- CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void,
- OnSelectSingleFolderDialogResponse, int);
-
- // Callback for when the user responds to a Open Multiple Files dialog.
- CHROMEGTK_CALLBACK_1(SelectFileDialogImplGTK, void,
- OnSelectMultiFileDialogResponse, int);
-
- // Callback for when the file chooser gets destroyed.
- CHROMEGTK_CALLBACK_0(SelectFileDialogImplGTK, void, OnFileChooserDestroy);
-
- // Callback for when we update the preview for the selection.
- CHROMEGTK_CALLBACK_0(SelectFileDialogImplGTK, void, OnUpdatePreview);
-
- // A map from dialog windows to the |params| user data associated with them.
- std::map<GtkWidget*, void*> params_map_;
-
- // The GtkImage widget for showing previews of selected images.
- GtkWidget* preview_;
-
- // All our dialogs.
- std::set<GtkWidget*> dialogs_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImplGTK);
-};
-
-// The size of the preview we display for selected image files. We set height
-// larger than width because generally there is more free space vertically
-// than horiztonally (setting the preview image will alway expand the width of
-// the dialog, but usually not the height). The image's aspect ratio will always
-// be preserved.
-static const int kPreviewWidth = 256;
-static const int kPreviewHeight = 512;
-
-SelectFileDialogImplGTK::SelectFileDialogImplGTK(Listener* listener,
- ui::SelectFilePolicy* policy)
- : SelectFileDialogImpl(listener, policy),
- preview_(NULL) {
-}
-
-SelectFileDialogImplGTK::~SelectFileDialogImplGTK() {
- while (dialogs_.begin() != dialogs_.end()) {
- gtk_widget_destroy(*(dialogs_.begin()));
- }
-}
-
-bool SelectFileDialogImplGTK::HasMultipleFileTypeChoicesImpl() {
- return file_types_.extensions.size() > 1;
-}
-
-// We ignore |default_extension|.
-void SelectFileDialogImplGTK::SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) {
- type_ = type;
- // |owning_window| can be null when user right-clicks on a downloadable item
- // and chooses 'Open Link in New Tab' when 'Ask where to save each file
- // before downloading.' preference is turned on. (http://crbug.com/29213)
- if (owning_window)
- parents_.insert(owning_window);
-
- std::string title_string = UTF16ToUTF8(title);
-
- file_type_index_ = file_type_index;
- if (file_types)
- file_types_ = *file_types;
- else
- file_types_.include_all_files = true;
-
- GtkWidget* dialog = NULL;
- switch (type) {
- case SELECT_FOLDER:
- case SELECT_UPLOAD_FOLDER:
- dialog = CreateSelectFolderDialog(type, title_string, default_path,
- owning_window);
- break;
- case SELECT_OPEN_FILE:
- dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
- break;
- case SELECT_OPEN_MULTI_FILE:
- dialog = CreateMultiFileOpenDialog(title_string, default_path,
- owning_window);
- break;
- case SELECT_SAVEAS_FILE:
- dialog = CreateSaveAsDialog(title_string, default_path, owning_window);
- break;
- default:
- NOTREACHED();
- return;
- }
- g_signal_connect(dialog, "delete-event",
- G_CALLBACK(gtk_widget_hide_on_delete), NULL);
- dialogs_.insert(dialog);
-
- preview_ = gtk_image_new();
- g_signal_connect(dialog, "destroy",
- G_CALLBACK(OnFileChooserDestroyThunk), this);
- g_signal_connect(dialog, "update-preview",
- G_CALLBACK(OnUpdatePreviewThunk), this);
- gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview_);
-
- params_map_[dialog] = params;
-
- // Set window-to-parent modality by adding the dialog to the same window
- // group as the parent.
- gtk_window_group_add_window(gtk_window_get_group(owning_window),
- GTK_WINDOW(dialog));
- gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
-
- gtk_widget_show_all(dialog);
-}
-
-void SelectFileDialogImplGTK::AddFilters(GtkFileChooser* chooser) {
- for (size_t i = 0; i < file_types_.extensions.size(); ++i) {
- GtkFileFilter* filter = NULL;
- std::set<std::string> fallback_labels;
-
- for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
- const std::string& current_extension = file_types_.extensions[i][j];
- if (!current_extension.empty()) {
- if (!filter)
- filter = gtk_file_filter_new();
- scoped_ptr<std::string> file_extension(
- new std::string("." + current_extension));
- fallback_labels.insert(std::string("*").append(*file_extension));
- gtk_file_filter_add_custom(
- filter,
- GTK_FILE_FILTER_FILENAME,
- reinterpret_cast<GtkFileFilterFunc>(FileFilterCaseInsensitive),
- file_extension.release(),
- reinterpret_cast<GDestroyNotify>(OnFileFilterDataDestroyed));
- }
- }
- // We didn't find any non-empty extensions to filter on.
- if (!filter)
- continue;
-
- // The description vector may be blank, in which case we are supposed to
- // use some sort of default description based on the filter.
- if (i < file_types_.extension_description_overrides.size()) {
- gtk_file_filter_set_name(filter, UTF16ToUTF8(
- file_types_.extension_description_overrides[i]).c_str());
- } else {
- // There is no system default filter description so we use
- // the extensions themselves if the description is blank.
- std::vector<std::string> fallback_labels_vector(fallback_labels.begin(),
- fallback_labels.end());
- std::string fallback_label = JoinString(fallback_labels_vector, ',');
- gtk_file_filter_set_name(filter, fallback_label.c_str());
- }
-
- gtk_file_chooser_add_filter(chooser, filter);
- if (i == file_type_index_ - 1)
- gtk_file_chooser_set_filter(chooser, filter);
- }
-
- // Add the *.* filter, but only if we have added other filters (otherwise it
- // is implied).
- if (file_types_.include_all_files && !file_types_.extensions.empty()) {
- GtkFileFilter* filter = gtk_file_filter_new();
- gtk_file_filter_add_pattern(filter, "*");
- gtk_file_filter_set_name(filter,
- l10n_util::GetStringUTF8(IDS_SAVEAS_ALL_FILES).c_str());
- gtk_file_chooser_add_filter(chooser, filter);
- }
-}
-
-void SelectFileDialogImplGTK::FileSelected(GtkWidget* dialog,
- const base::FilePath& path) {
- if (type_ == SELECT_SAVEAS_FILE) {
- *last_saved_path_ = path.DirName();
- } else if (type_ == SELECT_OPEN_FILE || type_ == SELECT_FOLDER ||
- type_ == SELECT_UPLOAD_FOLDER) {
- *last_opened_path_ = path.DirName();
- } else {
- NOTREACHED();
- }
-
- if (listener_) {
- GtkFileFilter* selected_filter =
- gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
- GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog));
- int idx = g_slist_index(filters, selected_filter);
- g_slist_free(filters);
- listener_->FileSelected(path, idx + 1, PopParamsForDialog(dialog));
- }
- gtk_widget_destroy(dialog);
-}
-
-void SelectFileDialogImplGTK::MultiFilesSelected(GtkWidget* dialog,
- const std::vector<base::FilePath>& files) {
- *last_opened_path_ = files[0].DirName();
-
- if (listener_)
- listener_->MultiFilesSelected(files, PopParamsForDialog(dialog));
- gtk_widget_destroy(dialog);
-}
-
-void SelectFileDialogImplGTK::FileNotSelected(GtkWidget* dialog) {
- void* params = PopParamsForDialog(dialog);
- if (listener_)
- listener_->FileSelectionCanceled(params);
- gtk_widget_destroy(dialog);
-}
-
-GtkWidget* SelectFileDialogImplGTK::CreateFileOpenHelper(
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent) {
- GtkWidget* dialog =
- gtk_file_chooser_dialog_new(title.c_str(), parent,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
- AddFilters(GTK_FILE_CHOOSER(dialog));
-
- if (!default_path.empty()) {
- if (CallDirectoryExistsOnUIThread(default_path)) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
- } else {
- // If the file doesn't exist, this will just switch to the correct
- // directory. That's good enough.
- gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
- }
- } else if (!last_opened_path_->empty()) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- last_opened_path_->value().c_str());
- }
- return dialog;
-}
-
-GtkWidget* SelectFileDialogImplGTK::CreateSelectFolderDialog(
- Type type,
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent) {
- std::string title_string = title;
- if (title_string.empty()) {
- title_string = (type == SELECT_UPLOAD_FOLDER) ?
- l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE) :
- l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
- }
- std::string accept_button_label = (type == SELECT_UPLOAD_FOLDER) ?
- l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON) :
- GTK_STOCK_OPEN;
-
- GtkWidget* dialog =
- gtk_file_chooser_dialog_new(title_string.c_str(), parent,
- GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- accept_button_label.c_str(),
- GTK_RESPONSE_ACCEPT,
- NULL);
-
- if (!default_path.empty()) {
- gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
- default_path.value().c_str());
- } else if (!last_opened_path_->empty()) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- last_opened_path_->value().c_str());
- }
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
- g_signal_connect(dialog, "response",
- G_CALLBACK(OnSelectSingleFolderDialogResponseThunk), this);
- return dialog;
-}
-
-GtkWidget* SelectFileDialogImplGTK::CreateFileOpenDialog(
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent) {
- std::string title_string = !title.empty() ? title :
- l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE);
-
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
- g_signal_connect(dialog, "response",
- G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this);
- return dialog;
-}
-
-GtkWidget* SelectFileDialogImplGTK::CreateMultiFileOpenDialog(
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent) {
- std::string title_string = !title.empty() ? title :
- l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE);
-
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
- g_signal_connect(dialog, "response",
- G_CALLBACK(OnSelectMultiFileDialogResponseThunk), this);
- return dialog;
-}
-
-GtkWidget* SelectFileDialogImplGTK::CreateSaveAsDialog(const std::string& title,
- const base::FilePath& default_path, gfx::NativeWindow parent) {
- std::string title_string = !title.empty() ? title :
- l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
-
- GtkWidget* dialog =
- gtk_file_chooser_dialog_new(title_string.c_str(), parent,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
-
- AddFilters(GTK_FILE_CHOOSER(dialog));
- if (!default_path.empty()) {
- // Since the file may not already exist, we use
- // set_current_folder() followed by set_current_name(), as per the
- // recommendation of the GTK docs.
- if (CallDirectoryExistsOnUIThread(default_path)) {
- gtk_file_chooser_set_current_folder(
- GTK_FILE_CHOOSER(dialog), default_path.value().c_str());
- gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "");
- } else {
- gtk_file_chooser_set_current_folder(
- GTK_FILE_CHOOSER(dialog), default_path.DirName().value().c_str());
- gtk_file_chooser_set_current_name(
- GTK_FILE_CHOOSER(dialog), default_path.BaseName().value().c_str());
- }
- } else if (!last_saved_path_->empty()) {
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
- last_saved_path_->value().c_str());
- }
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
- TRUE);
- g_signal_connect(dialog, "response",
- G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this);
- return dialog;
-}
-
-void* SelectFileDialogImplGTK::PopParamsForDialog(GtkWidget* dialog) {
- std::map<GtkWidget*, void*>::iterator iter = params_map_.find(dialog);
- DCHECK(iter != params_map_.end());
- void* params = iter->second;
- params_map_.erase(iter);
- return params;
-}
-
-void SelectFileDialogImplGTK::FileDialogDestroyed(GtkWidget* dialog) {
- dialogs_.erase(dialog);
-
- // Parent may be NULL in a few cases: 1) on shutdown when
- // AllBrowsersClosed() trigger this handler after all the browser
- // windows got destroyed, or 2) when the parent tab has been opened by
- // 'Open Link in New Tab' context menu on a downloadable item and
- // the tab has no content (see the comment in SelectFile as well).
- GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
- if (!parent)
- return;
- std::set<GtkWindow*>::iterator iter = parents_.find(parent);
- if (iter != parents_.end())
- parents_.erase(iter);
- else
- NOTREACHED();
-}
-
-bool SelectFileDialogImplGTK::IsCancelResponse(gint response_id) {
- bool is_cancel = response_id == GTK_RESPONSE_CANCEL ||
- response_id == GTK_RESPONSE_DELETE_EVENT;
- if (is_cancel)
- return true;
-
- DCHECK(response_id == GTK_RESPONSE_ACCEPT);
- return false;
-}
-
-void SelectFileDialogImplGTK::SelectSingleFileHelper(GtkWidget* dialog,
- gint response_id,
- bool allow_folder) {
- if (IsCancelResponse(response_id)) {
- FileNotSelected(dialog);
- return;
- }
-
- gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
- if (!filename) {
- FileNotSelected(dialog);
- return;
- }
-
- base::FilePath path(filename);
- g_free(filename);
-
- if (allow_folder) {
- FileSelected(dialog, path);
- return;
- }
-
- if (CallDirectoryExistsOnUIThread(path))
- FileNotSelected(dialog);
- else
- FileSelected(dialog, path);
-}
-
-void SelectFileDialogImplGTK::OnSelectSingleFileDialogResponse(
- GtkWidget* dialog, int response_id) {
- SelectSingleFileHelper(dialog, response_id, false);
-}
-
-void SelectFileDialogImplGTK::OnSelectSingleFolderDialogResponse(
- GtkWidget* dialog, int response_id) {
- SelectSingleFileHelper(dialog, response_id, true);
-}
-
-void SelectFileDialogImplGTK::OnSelectMultiFileDialogResponse(GtkWidget* dialog,
- int response_id) {
- if (IsCancelResponse(response_id)) {
- FileNotSelected(dialog);
- return;
- }
-
- GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
- if (!filenames) {
- FileNotSelected(dialog);
- return;
- }
-
- std::vector<base::FilePath> filenames_fp;
- for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) {
- base::FilePath path(static_cast<char*>(iter->data));
- g_free(iter->data);
- if (CallDirectoryExistsOnUIThread(path))
- continue;
- filenames_fp.push_back(path);
- }
- g_slist_free(filenames);
-
- if (filenames_fp.empty()) {
- FileNotSelected(dialog);
- return;
- }
- MultiFilesSelected(dialog, filenames_fp);
-}
-
-void SelectFileDialogImplGTK::OnFileChooserDestroy(GtkWidget* dialog) {
- FileDialogDestroyed(dialog);
-}
-
-void SelectFileDialogImplGTK::OnUpdatePreview(GtkWidget* chooser) {
- gchar* filename = gtk_file_chooser_get_preview_filename(
- GTK_FILE_CHOOSER(chooser));
- if (!filename)
- return;
- // This will preserve the image's aspect ratio.
- GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
- kPreviewHeight, NULL);
- g_free(filename);
- if (pixbuf) {
- gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
- g_object_unref(pixbuf);
- }
- gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser),
- pixbuf ? TRUE : FALSE);
-}
-
-} // namespace
-
-namespace ui {
-
-SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplGTK(
- Listener* listener, ui::SelectFilePolicy* policy) {
- return new SelectFileDialogImplGTK(listener, policy);
-}
-
-} // namespace ui
diff --git a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_kde.cc b/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_kde.cc
deleted file mode 100644
index e41c327bc32..00000000000
--- a/chromium/ui/shell_dialogs/gtk/select_file_dialog_impl_kde.cc
+++ /dev/null
@@ -1,485 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <set>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/nix/mime_util_xdg.h"
-#include "base/nix/xdg_util.h"
-#include "base/process/launch.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/worker_pool.h"
-#include "grit/ui_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/shell_dialogs/gtk/select_file_dialog_impl.h"
-
-// These conflict with base/tracked_objects.h, so need to come last.
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-namespace {
-
-std::string GetTitle(const std::string& title, int message_id) {
- return title.empty() ? l10n_util::GetStringUTF8(message_id) : title;
-}
-
-const char kKdialogBinary[] = "kdialog";
-
-// Implementation of SelectFileDialog that shows a KDE common dialog for
-// choosing a file or folder. This acts as a modal dialog.
-class SelectFileDialogImplKDE : public ui::SelectFileDialogImpl {
- public:
- SelectFileDialogImplKDE(Listener* listener,
- ui::SelectFilePolicy* policy,
- base::nix::DesktopEnvironment desktop);
-
- protected:
- virtual ~SelectFileDialogImplKDE();
-
- // SelectFileDialog implementation.
- // |params| is user data we pass back via the Listener interface.
- virtual void SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) OVERRIDE;
-
- private:
- virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
-
- struct KDialogParams {
- // This constructor can only be run from the UI thread.
- KDialogParams(const std::string& type,
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent,
- bool file_operation,
- bool multiple_selection,
- void* kdialog_params,
- void(SelectFileDialogImplKDE::* callback)(const std::string&,
- int,
- void*))
- : type(type),
- title(title),
- default_path(default_path),
- parent(parent),
- file_operation(file_operation),
- multiple_selection(multiple_selection),
- kdialog_params(kdialog_params),
- ui_loop_proxy(
- base::MessageLoopForUI::current()->message_loop_proxy()),
- callback(callback) {}
-
- std::string type;
- std::string title;
- base::FilePath default_path;
- gfx::NativeWindow parent;
- bool file_operation;
- bool multiple_selection;
- void* kdialog_params;
- scoped_refptr<base::MessageLoopProxy> ui_loop_proxy;
-
- void (SelectFileDialogImplKDE::*callback)(const std::string&, int, void*);
- };
-
- // Get the filters from |file_types_| and concatenate them into
- // |filter_string|.
- std::string GetMimeTypeFilterString();
-
- // Get KDialog command line representing the Argv array for KDialog.
- void GetKDialogCommandLine(const std::string& type, const std::string& title,
- const base::FilePath& default_path, gfx::NativeWindow parent,
- bool file_operation, bool multiple_selection, CommandLine* command_line);
-
- // Call KDialog on a worker thread and post results back to the caller
- // thread.
- void CallKDialogOutput(const KDialogParams& params);
-
- // Notifies the listener that a single file was chosen.
- void FileSelected(const base::FilePath& path, void* params);
-
- // Notifies the listener that multiple files were chosen.
- void MultiFilesSelected(const std::vector<base::FilePath>& files,
- void* params);
-
- // Notifies the listener that no file was chosen (the action was canceled).
- // Dialog is passed so we can find that |params| pointer that was passed to
- // us when we were told to show the dialog.
- void FileNotSelected(void *params);
-
- void CreateSelectFolderDialog(Type type,
- const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params);
-
- void CreateFileOpenDialog(const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params);
-
- void CreateMultiFileOpenDialog(const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params);
-
- void CreateSaveAsDialog(const std::string& title,
- const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params);
-
- // Common function for OnSelectSingleFileDialogResponse and
- // OnSelectSingleFolderDialogResponse.
- void SelectSingleFileHelper(const std::string& output, int exit_code,
- void* params, bool allow_folder);
-
- void OnSelectSingleFileDialogResponse(const std::string& output,
- int exit_code, void* params);
- void OnSelectMultiFileDialogResponse(const std::string& output,
- int exit_code, void* params);
- void OnSelectSingleFolderDialogResponse(const std::string& output,
- int exit_code, void* params);
-
- // Should be either DESKTOP_ENVIRONMENT_KDE3 or DESKTOP_ENVIRONMENT_KDE4.
- base::nix::DesktopEnvironment desktop_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImplKDE);
-};
-
-SelectFileDialogImplKDE::SelectFileDialogImplKDE(
- Listener* listener,
- ui::SelectFilePolicy* policy,
- base::nix::DesktopEnvironment desktop)
- : SelectFileDialogImpl(listener, policy),
- desktop_(desktop) {
- DCHECK(desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
- desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE4);
-}
-
-SelectFileDialogImplKDE::~SelectFileDialogImplKDE() {
-}
-
-// We ignore |default_extension|.
-void SelectFileDialogImplKDE::SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) {
- type_ = type;
- // |owning_window| can be null when user right-clicks on a downloadable item
- // and chooses 'Open Link in New Tab' when 'Ask where to save each file
- // before downloading.' preference is turned on. (http://crbug.com/29213)
- if (owning_window)
- parents_.insert(owning_window);
-
- std::string title_string = UTF16ToUTF8(title);
-
- file_type_index_ = file_type_index;
- if (file_types)
- file_types_ = *file_types;
- else
- file_types_.include_all_files = true;
-
- switch (type) {
- case SELECT_FOLDER:
- case SELECT_UPLOAD_FOLDER:
- CreateSelectFolderDialog(type, title_string, default_path,
- owning_window, params);
- return;
- case SELECT_OPEN_FILE:
- CreateFileOpenDialog(title_string, default_path, owning_window,
- params);
- return;
- case SELECT_OPEN_MULTI_FILE:
- CreateMultiFileOpenDialog(title_string, default_path,
- owning_window, params);
- return;
- case SELECT_SAVEAS_FILE:
- CreateSaveAsDialog(title_string, default_path, owning_window,
- params);
- return;
- default:
- NOTREACHED();
- return;
- }
-}
-
-bool SelectFileDialogImplKDE::HasMultipleFileTypeChoicesImpl() {
- return file_types_.extensions.size() > 1;
-}
-
-std::string SelectFileDialogImplKDE::GetMimeTypeFilterString() {
- std::string filter_string;
- // We need a filter set because the same mime type can appear multiple times.
- std::set<std::string> filter_set;
- for (size_t i = 0; i < file_types_.extensions.size(); ++i) {
- for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
- if (!file_types_.extensions[i][j].empty()) {
- std::string mime_type = base::nix::GetFileMimeType(
- base::FilePath("name").ReplaceExtension(
- file_types_.extensions[i][j]));
- filter_set.insert(mime_type);
- }
- }
- }
- // Add the *.* filter, but only if we have added other filters (otherwise it
- // is implied).
- if (file_types_.include_all_files && !file_types_.extensions.empty())
- filter_set.insert("application/octet-stream");
- // Create the final output string.
- filter_string.clear();
- for (std::set<std::string>::iterator it = filter_set.begin();
- it != filter_set.end(); ++it) {
- filter_string.append(*it + " ");
- }
- return filter_string;
-}
-
-void SelectFileDialogImplKDE::CallKDialogOutput(const KDialogParams& params) {
- CommandLine::StringVector cmd_vector;
- cmd_vector.push_back(kKdialogBinary);
- CommandLine command_line(cmd_vector);
- GetKDialogCommandLine(params.type, params.title, params.default_path,
- params.parent, params.file_operation,
- params.multiple_selection, &command_line);
- std::string output;
- int exit_code;
- // Get output from KDialog
- base::GetAppOutputWithExitCode(command_line, &output, &exit_code);
- if (!output.empty())
- output.erase(output.size() - 1);
- // Now the dialog is no longer showing. We can erase its parent from the
- // parent set.
- std::set<GtkWindow*>::iterator iter = parents_.find(params.parent);
- if (iter != parents_.end())
- parents_.erase(iter);
- params.ui_loop_proxy->PostTask(FROM_HERE,
- base::Bind(params.callback, this, output, exit_code,
- params.kdialog_params));
-}
-
-void SelectFileDialogImplKDE::GetKDialogCommandLine(const std::string& type,
- const std::string& title, const base::FilePath& path,
- gfx::NativeWindow parent, bool file_operation, bool multiple_selection,
- CommandLine* command_line) {
- CHECK(command_line);
-
- // Attach to the current Chrome window.
- GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET((parent)));
- int window_id = GDK_DRAWABLE_XID(gdk_window);
- command_line->AppendSwitchNative(
- desktop_ == base::nix::DESKTOP_ENVIRONMENT_KDE3 ? "--embed" : "--attach",
- base::IntToString(window_id));
- // Set the correct title for the dialog.
- if (!title.empty())
- command_line->AppendSwitchNative("--title", title);
- // Enable multiple file selection if we need to.
- if (multiple_selection) {
- command_line->AppendSwitch("--multiple");
- command_line->AppendSwitch("--separate-output");
- }
- command_line->AppendSwitch(type);
- // The path should never be empty. If it is, set it to PWD.
- if (path.empty())
- command_line->AppendArgPath(base::FilePath("."));
- else
- command_line->AppendArgPath(path);
- // Depending on the type of the operation we need, get the path to the
- // file/folder and set up mime type filters.
- if (file_operation)
- command_line->AppendArg(GetMimeTypeFilterString());
- VLOG(1) << "KDialog command line: " << command_line->GetCommandLineString();
-}
-
-void SelectFileDialogImplKDE::FileSelected(const base::FilePath& path,
- void* params) {
- if (type_ == SELECT_SAVEAS_FILE)
- *last_saved_path_ = path.DirName();
- else if (type_ == SELECT_OPEN_FILE)
- *last_opened_path_ = path.DirName();
- else if (type_ == SELECT_FOLDER)
- *last_opened_path_ = path;
- else
- NOTREACHED();
- if (listener_) { // What does the filter index actually do?
- // TODO(dfilimon): Get a reasonable index value from somewhere.
- listener_->FileSelected(path, 1, params);
- }
-}
-
-void SelectFileDialogImplKDE::MultiFilesSelected(
- const std::vector<base::FilePath>& files, void* params) {
- *last_opened_path_ = files[0].DirName();
- if (listener_)
- listener_->MultiFilesSelected(files, params);
-}
-
-void SelectFileDialogImplKDE::FileNotSelected(void* params) {
- if (listener_)
- listener_->FileSelectionCanceled(params);
-}
-
-void SelectFileDialogImplKDE::CreateSelectFolderDialog(
- Type type, const std::string& title, const base::FilePath& default_path,
- gfx::NativeWindow parent, void *params) {
- int title_message_id = (type == SELECT_UPLOAD_FOLDER) ?
- IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE :
- IDS_SELECT_FOLDER_DIALOG_TITLE;
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(
- &SelectFileDialogImplKDE::CallKDialogOutput,
- this,
- KDialogParams(
- "--getexistingdirectory",
- GetTitle(title, title_message_id),
- default_path.empty() ? *last_opened_path_ : default_path,
- parent, false, false, params,
- &SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse)),
- true);
-}
-
-void SelectFileDialogImplKDE::CreateFileOpenDialog(
- const std::string& title, const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params) {
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(
- &SelectFileDialogImplKDE::CallKDialogOutput,
- this,
- KDialogParams(
- "--getopenfilename",
- GetTitle(title, IDS_OPEN_FILE_DIALOG_TITLE),
- default_path.empty() ? *last_opened_path_ : default_path,
- parent, true, false, params,
- &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse)),
- true);
-}
-
-void SelectFileDialogImplKDE::CreateMultiFileOpenDialog(
- const std::string& title, const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params) {
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(
- &SelectFileDialogImplKDE::CallKDialogOutput,
- this,
- KDialogParams(
- "--getopenfilename",
- GetTitle(title, IDS_OPEN_FILES_DIALOG_TITLE),
- default_path.empty() ? *last_opened_path_ : default_path,
- parent, true, true, params,
- &SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse)),
- true);
-}
-
-void SelectFileDialogImplKDE::CreateSaveAsDialog(
- const std::string& title, const base::FilePath& default_path,
- gfx::NativeWindow parent, void* params) {
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(
- &SelectFileDialogImplKDE::CallKDialogOutput,
- this,
- KDialogParams(
- "--getsavefilename",
- GetTitle(title, IDS_SAVE_AS_DIALOG_TITLE),
- default_path.empty() ? *last_saved_path_ : default_path,
- parent, true, false, params,
- &SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse)),
- true);
-}
-
-void SelectFileDialogImplKDE::SelectSingleFileHelper(const std::string& output,
- int exit_code, void* params, bool allow_folder) {
- VLOG(1) << "[kdialog] SingleFileResponse: " << output;
- if (exit_code != 0 || output.empty()) {
- FileNotSelected(params);
- return;
- }
-
- base::FilePath path(output);
- if (allow_folder) {
- FileSelected(path, params);
- return;
- }
-
- if (CallDirectoryExistsOnUIThread(path))
- FileNotSelected(params);
- else
- FileSelected(path, params);
-}
-
-void SelectFileDialogImplKDE::OnSelectSingleFileDialogResponse(
- const std::string& output, int exit_code, void* params) {
- SelectSingleFileHelper(output, exit_code, params, false);
-}
-
-void SelectFileDialogImplKDE::OnSelectSingleFolderDialogResponse(
- const std::string& output, int exit_code, void* params) {
- SelectSingleFileHelper(output, exit_code, params, true);
-}
-
-void SelectFileDialogImplKDE::OnSelectMultiFileDialogResponse(
- const std::string& output, int exit_code, void* params) {
- VLOG(1) << "[kdialog] MultiFileResponse: " << output;
-
- if (exit_code != 0 || output.empty()) {
- FileNotSelected(params);
- return;
- }
-
- std::vector<std::string> filenames;
- Tokenize(output, "\n", &filenames);
- std::vector<base::FilePath> filenames_fp;
- for (std::vector<std::string>::iterator iter = filenames.begin();
- iter != filenames.end(); ++iter) {
- base::FilePath path(*iter);
- if (CallDirectoryExistsOnUIThread(path))
- continue;
- filenames_fp.push_back(path);
- }
-
- if (filenames_fp.empty()) {
- FileNotSelected(params);
- return;
- }
- MultiFilesSelected(filenames_fp, params);
-}
-
-} // namespace
-
-namespace ui {
-
-// static
-bool SelectFileDialogImpl::CheckKDEDialogWorksOnUIThread() {
- // No choice. UI thread can't continue without an answer here. Fortunately we
- // only do this once, the first time a file dialog is displayed.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- CommandLine::StringVector cmd_vector;
- cmd_vector.push_back(kKdialogBinary);
- cmd_vector.push_back("--version");
- CommandLine command_line(cmd_vector);
- std::string dummy;
- return base::GetAppOutput(command_line, &dummy);
-}
-
-// static
-SelectFileDialogImpl* SelectFileDialogImpl::NewSelectFileDialogImplKDE(
- Listener* listener,
- ui::SelectFilePolicy* policy,
- base::nix::DesktopEnvironment desktop) {
- return new SelectFileDialogImplKDE(listener, policy, desktop);
-}
-
-} // namespace ui
diff --git a/chromium/ui/shell_dialogs/print_settings_dialog_win.cc b/chromium/ui/shell_dialogs/print_settings_dialog_win.cc
deleted file mode 100644
index f3f89b3ed71..00000000000
--- a/chromium/ui/shell_dialogs/print_settings_dialog_win.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/shell_dialogs/print_settings_dialog_win.h"
-
-#include "base/bind.h"
-#include "base/threading/thread.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#endif
-
-namespace ui {
-
-PrintSettingsDialogWin::PrintSettingsDialogWin(
- PrintSettingsDialogWin::Observer* observer)
- : observer_(observer) {
-}
-
-PrintSettingsDialogWin::~PrintSettingsDialogWin() {
-}
-
-void PrintSettingsDialogWin::GetPrintSettings(PrintDialogFunc print_dialog_func,
- HWND owning_window,
- PRINTDLGEX* dialog_options) {
- DCHECK(observer_);
-
- ExecutePrintSettingsParams execute_params(BeginRun(owning_window),
- owning_window,
- print_dialog_func,
- dialog_options);
- execute_params.run_state.dialog_thread->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(
- &PrintSettingsDialogWin::ExecutePrintSettings, this, execute_params));
-}
-
-void PrintSettingsDialogWin::ExecutePrintSettings(
- const ExecutePrintSettingsParams& params) {
- HRESULT hr = (*params.print_dialog_func)(params.dialog_options);
- params.ui_proxy->PostTask(
- FROM_HERE,
- base::Bind(
- &PrintSettingsDialogWin::PrintSettingsCompleted, this, hr, params));
-}
-
-void PrintSettingsDialogWin::PrintSettingsCompleted(
- HRESULT hresult,
- const ExecutePrintSettingsParams& params) {
- EndRun(params.run_state);
- if (hresult != S_OK)
- observer_->PrintSettingsCancelled(params.dialog_options);
- else
- observer_->PrintSettingsConfirmed(params.dialog_options);
-}
-
-} // namespace ui
diff --git a/chromium/ui/shell_dialogs/print_settings_dialog_win.h b/chromium/ui/shell_dialogs/print_settings_dialog_win.h
deleted file mode 100644
index 6a1efed5899..00000000000
--- a/chromium/ui/shell_dialogs/print_settings_dialog_win.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_SHELL_DIALOGS_PRINT_SETTINGS_DIALOG_WIN_H_
-#define UI_SHELL_DIALOGS_PRINT_SETTINGS_DIALOG_WIN_H_
-
-#include <ocidl.h>
-#include <commdlg.h>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "ui/shell_dialogs/base_shell_dialog_win.h"
-#include "ui/shell_dialogs/shell_dialogs_export.h"
-
-namespace ui {
-
-// A thin wrapper around the native window print dialog that uses
-// BaseShellDialog to have the dialog run on a background thread.
-class SHELL_DIALOGS_EXPORT PrintSettingsDialogWin
- : public base::RefCountedThreadSafe<PrintSettingsDialogWin>,
- public BaseShellDialogImpl {
- public:
- class SHELL_DIALOGS_EXPORT Observer {
- public:
- virtual void PrintSettingsConfirmed(PRINTDLGEX* dialog_options) = 0;
- virtual void PrintSettingsCancelled(PRINTDLGEX* dialog_options) = 0;
- };
- typedef HRESULT(__stdcall* PrintDialogFunc)(PRINTDLGEX*);
-
- explicit PrintSettingsDialogWin(Observer* observer);
- virtual ~PrintSettingsDialogWin();
-
- // Called to open the system print dialog on a background thread.
- // |print_dialog_func| should generally be ::PrintDlgEx, however alternate
- // functions are used for testing. |owning_window| is the parent HWND, and
- // |dialog_options| is passed to |print_dialog_func|.
- void GetPrintSettings(
- PrintDialogFunc print_dialog_func,
- HWND owning_window,
- PRINTDLGEX* dialog_options);
-
- private:
- // A struct for holding all the state necessary for displaying the print
- // settings dialog.
- struct ExecutePrintSettingsParams {
- ExecutePrintSettingsParams(RunState run_state,
- HWND owner,
- PrintDialogFunc print_dialog_func,
- PRINTDLGEX* dialog_options)
- : run_state(run_state),
- owner(owner),
- print_dialog_func(print_dialog_func),
- dialog_options(dialog_options),
- ui_proxy(base::MessageLoopForUI::current()->message_loop_proxy()) {}
-
- RunState run_state;
- HWND owner;
- PrintDialogFunc print_dialog_func;
- PRINTDLGEX* dialog_options;
- scoped_refptr<base::MessageLoopProxy> ui_proxy;
- };
-
- // Runs the print dialog. Should be run on the the BaseShellDialogImpl thread.
- // Posts back to PrintSettingsCompleted on the UI thread on completion.
- void ExecutePrintSettings(const ExecutePrintSettingsParams& params);
-
- // Handler for the result of the print settings dialog. Should be run on the
- // UI thread, and notifies the observer of the result of the dialog.
- void PrintSettingsCompleted(HRESULT hresult,
- const ExecutePrintSettingsParams& params);
-
- // Observer that's notified when the dialog is confirmed or cancelled.
- Observer* observer_;
-
- DISALLOW_COPY_AND_ASSIGN(PrintSettingsDialogWin);
-};
-
-} // namespace ui
-
-#endif // UI_SHELL_DIALOGS_PRINT_SETTINGS_DIALOG_WIN_H_
diff --git a/chromium/ui/shell_dialogs/select_file_dialog.cc b/chromium/ui/shell_dialogs/select_file_dialog.cc
index 06dd13ef29a..e0449a7b0a3 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog.cc
@@ -18,11 +18,9 @@
#include "ui/shell_dialogs/select_file_dialog_win.h"
#elif defined(OS_MACOSX)
#include "ui/shell_dialogs/select_file_dialog_mac.h"
-#elif defined(TOOLKIT_GTK)
-#include "ui/shell_dialogs/gtk/select_file_dialog_impl.h"
#elif defined(OS_ANDROID)
#include "ui/shell_dialogs/select_file_dialog_android.h"
-#elif defined(USE_AURA) && !defined(USE_ASH) && defined(OS_LINUX)
+#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "ui/shell_dialogs/linux_shell_dialog.h"
#endif
@@ -78,7 +76,7 @@ scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
return dialog;
}
-#if defined(USE_AURA) && !defined(USE_ASH) && defined(OS_LINUX)
+#if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
const ui::LinuxShellDialog* shell_dialogs = ui::LinuxShellDialog::instance();
if (shell_dialogs)
return shell_dialogs->CreateSelectFileDialog(listener, policy);
@@ -90,13 +88,12 @@ scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
return CreateWinSelectFileDialog(listener, policy);
#elif defined(OS_MACOSX) && !defined(USE_AURA)
return CreateMacSelectFileDialog(listener, policy);
-#elif defined(TOOLKIT_GTK)
- return CreateLinuxSelectFileDialog(listener, policy);
#elif defined(OS_ANDROID)
return CreateAndroidSelectFileDialog(listener, policy);
-#endif
-
+#else
+ NOTIMPLEMENTED();
return NULL;
+#endif
}
void SelectFileDialog::SelectFile(
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_android.cc b/chromium/ui/shell_dialogs/select_file_dialog_android.cc
index 290d5091ef6..af15c977b0b 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_android.cc
@@ -40,8 +40,6 @@ void SelectFileDialogImpl::OnFileSelected(JNIEnv* env,
file_info.display_name = file_name;
listener_->FileSelectedWithExtraInfo(file_info, 0, NULL);
}
-
- is_running_ = false;
}
void SelectFileDialogImpl::OnFileNotSelected(
@@ -49,12 +47,10 @@ void SelectFileDialogImpl::OnFileNotSelected(
jobject java_object) {
if (listener_)
listener_->FileSelectionCanceled(NULL);
-
- is_running_ = false;
}
bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow) const {
- return is_running_;
+ return listener_;
}
void SelectFileDialogImpl::ListenerDestroyed() {
@@ -89,7 +85,6 @@ void SelectFileDialogImpl::SelectFileImpl(
accept_types_java.obj(),
accept_types.second,
owning_window->GetJavaObject().obj());
- is_running_ = true;
}
bool SelectFileDialogImpl::RegisterSelectFileDialog(JNIEnv* env) {
@@ -101,7 +96,7 @@ SelectFileDialogImpl::~SelectFileDialogImpl() {
SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener,
SelectFilePolicy* policy)
- : SelectFileDialog(listener, policy), is_running_(false) {
+ : SelectFileDialog(listener, policy) {
JNIEnv* env = base::android::AttachCurrentThread();
java_object_.Reset(
Java_SelectFileDialog_create(env, reinterpret_cast<intptr_t>(this)));
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_android.h b/chromium/ui/shell_dialogs/select_file_dialog_android.h
index 26903086c7d..1b09d1e36d3 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_android.h
+++ b/chromium/ui/shell_dialogs/select_file_dialog_android.h
@@ -53,9 +53,6 @@ class SelectFileDialogImpl : public SelectFileDialog {
base::android::ScopedJavaGlobalRef<jobject> java_object_;
- // Stores the state whether select_file_dialog is running.
- bool is_running_;
-
DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
};
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.cc b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
index 1f8e36458bc..00a1f7e1168 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
@@ -26,16 +26,14 @@
#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "grit/ui_strings.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/shell_dialogs/base_shell_dialog_win.h"
#include "ui/shell_dialogs/shell_dialogs_delegate.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/remote_root_window_host_win.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#endif
+#include "win8/viewer/metro_viewer_process_host.h"
namespace {
@@ -85,7 +83,7 @@ bool CallGetSaveFileName(OPENFILENAME* ofn) {
// Distinguish directories from regular files.
bool IsDirectory(const base::FilePath& path) {
- base::PlatformFileInfo file_info;
+ base::File::Info file_info;
return base::GetFileInfo(path, &file_info) ?
file_info.is_directory : path.EndsWithSeparator();
}
@@ -171,7 +169,7 @@ std::wstring FormatFilterForExtensions(
include_all_files = true;
desc = l10n_util::GetStringFUTF16(
IDS_APP_SAVEAS_EXTENSION_FORMAT,
- base::i18n::ToUpper(WideToUTF16(ext_name)),
+ base::i18n::ToUpper(base::WideToUTF16(ext_name)),
ext_name);
}
if (desc.empty())
@@ -517,7 +515,8 @@ class SelectFileDialogImpl : public ui::SelectFileDialog,
// Returns the filter to be used while displaying the open/save file dialog.
// This is computed from the extensions for the file types being opened.
- base::string16 GetFilterForFileTypes(const FileTypeInfo& file_types);
+ // |file_types| can be NULL in which case the returned filter will be empty.
+ base::string16 GetFilterForFileTypes(const FileTypeInfo* file_types);
bool has_multiple_file_type_choices_;
@@ -545,16 +544,15 @@ void SelectFileDialogImpl::SelectFileImpl(
void* params) {
has_multiple_file_type_choices_ =
file_types ? file_types->extensions.size() > 1 : true;
-#if defined(USE_AURA)
// If the owning_window passed in is in metro then we need to forward the
// file open/save operations to metro.
if (GetShellDialogsDelegate() &&
GetShellDialogsDelegate()->IsWindowInMetro(owning_window)) {
if (type == SELECT_SAVEAS_FILE) {
- aura::HandleSaveFile(
- UTF16ToWide(title),
+ win8::MetroViewerProcessHost::HandleSaveFile(
+ title,
default_path,
- GetFilterForFileTypes(*file_types),
+ GetFilterForFileTypes(file_types),
file_type_index,
default_extension,
base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
@@ -563,20 +561,20 @@ void SelectFileDialogImpl::SelectFileImpl(
base::Unretained(listener_)));
return;
} else if (type == SELECT_OPEN_FILE) {
- aura::HandleOpenFile(
- UTF16ToWide(title),
+ win8::MetroViewerProcessHost::HandleOpenFile(
+ title,
default_path,
- GetFilterForFileTypes(*file_types),
+ GetFilterForFileTypes(file_types),
base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
base::Unretained(listener_)),
base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
base::Unretained(listener_)));
return;
} else if (type == SELECT_OPEN_MULTI_FILE) {
- aura::HandleOpenMultipleFiles(
- UTF16ToWide(title),
+ win8::MetroViewerProcessHost::HandleOpenMultipleFiles(
+ title,
default_path,
- GetFilterForFileTypes(*file_types),
+ GetFilterForFileTypes(file_types),
base::Bind(&ui::SelectFileDialog::Listener::MultiFilesSelected,
base::Unretained(listener_)),
base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
@@ -590,8 +588,8 @@ void SelectFileDialogImpl::SelectFileImpl(
title_string = l10n_util::GetStringUTF16(
IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE);
}
- aura::HandleSelectFolder(
- UTF16ToWide(title_string),
+ win8::MetroViewerProcessHost::HandleSelectFolder(
+ title_string,
base::Bind(&ui::SelectFileDialog::Listener::FileSelected,
base::Unretained(listener_)),
base::Bind(&ui::SelectFileDialog::Listener::FileSelectionCanceled,
@@ -600,12 +598,10 @@ void SelectFileDialogImpl::SelectFileImpl(
}
}
HWND owner = owning_window && owning_window->GetRootWindow()
- ? owning_window->GetDispatcher()->host()->GetAcceleratedWidget() : NULL;
-#else
- HWND owner = owning_window;
-#endif
- ExecuteSelectParams execute_params(type, UTF16ToWide(title), default_path,
- file_types, file_type_index,
+ ? owning_window->GetHost()->GetAcceleratedWidget() : NULL;
+
+ ExecuteSelectParams execute_params(type, title,
+ default_path, file_types, file_type_index,
default_extension, BeginRun(owner),
owner, params);
execute_params.run_state.dialog_thread->message_loop()->PostTask(
@@ -619,13 +615,9 @@ bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
}
bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow owning_window) const {
-#if defined(USE_AURA)
if (!owning_window->GetRootWindow())
return false;
- HWND owner = owning_window->GetDispatcher()->host()->GetAcceleratedWidget();
-#else
- HWND owner = owning_window;
-#endif
+ HWND owner = owning_window->GetHost()->GetAcceleratedWidget();
return listener_ && IsRunningDialogForOwner(owner);
}
@@ -637,7 +629,7 @@ void SelectFileDialogImpl::ListenerDestroyed() {
void SelectFileDialogImpl::ExecuteSelectFile(
const ExecuteSelectParams& params) {
- base::string16 filter = GetFilterForFileTypes(params.file_types);
+ base::string16 filter = GetFilterForFileTypes(&params.file_types);
base::FilePath path = params.default_path;
bool success = false;
@@ -647,8 +639,7 @@ void SelectFileDialogImpl::ExecuteSelectFile(
if (title.empty() && params.type == SELECT_UPLOAD_FOLDER) {
// If it's for uploading don't use default dialog title to
// make sure we clearly tell it's for uploading.
- title = UTF16ToWide(
- l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE));
+ title = l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE);
}
success = RunSelectFolderDialog(title,
params.run_state.owner,
@@ -881,10 +872,13 @@ bool SelectFileDialogImpl::RunOpenMultiFileDialog(
}
base::string16 SelectFileDialogImpl::GetFilterForFileTypes(
- const FileTypeInfo& file_types) {
+ const FileTypeInfo* file_types) {
+ if (!file_types)
+ return base::string16();
+
std::vector<base::string16> exts;
- for (size_t i = 0; i < file_types.extensions.size(); ++i) {
- const std::vector<base::string16>& inner_exts = file_types.extensions[i];
+ for (size_t i = 0; i < file_types->extensions.size(); ++i) {
+ const std::vector<base::string16>& inner_exts = file_types->extensions[i];
base::string16 ext_string;
for (size_t j = 0; j < inner_exts.size(); ++j) {
if (!ext_string.empty())
@@ -896,8 +890,8 @@ base::string16 SelectFileDialogImpl::GetFilterForFileTypes(
}
return FormatFilterForExtensions(
exts,
- file_types.extension_description_overrides,
- file_types.include_all_files);
+ file_types->extension_description_overrides,
+ file_types->include_all_files);
}
} // namespace
diff --git a/chromium/ui/shell_dialogs/shell_dialogs.gyp b/chromium/ui/shell_dialogs/shell_dialogs.gyp
index 2df94354eb1..3cc00938d74 100644
--- a/chromium/ui/shell_dialogs/shell_dialogs.gyp
+++ b/chromium/ui/shell_dialogs/shell_dialogs.gyp
@@ -14,8 +14,8 @@
'../../base/base.gyp:base',
'../../base/base.gyp:base_i18n',
'../../skia/skia.gyp:skia',
- '../base/strings/ui_strings.gyp:ui_strings',
- '../ui.gyp:ui',
+ '../base/ui_base.gyp:ui_base',
+ '../strings/ui_strings.gyp:ui_strings',
],
'defines': [
'SHELL_DIALOGS_IMPLEMENTATION',
@@ -27,14 +27,8 @@
'base_shell_dialog.h',
'base_shell_dialog_win.cc',
'base_shell_dialog_win.h',
- 'gtk/select_file_dialog_impl.cc',
- 'gtk/select_file_dialog_impl.h',
- 'gtk/select_file_dialog_impl_gtk.cc',
- 'gtk/select_file_dialog_impl_kde.cc',
'linux_shell_dialog.cc',
'linux_shell_dialog.h',
- 'print_settings_dialog_win.cc',
- 'print_settings_dialog_win.h',
'select_file_dialog.cc',
'select_file_dialog.h',
'select_file_dialog_android.cc',
@@ -64,7 +58,7 @@
['OS=="android"',
{
'dependencies': [
- '../ui.gyp:ui_base_jni_headers',
+ '../base/ui_base.gyp:ui_base_jni_headers',
],
'include_dirs': [
'<(SHARED_INTERMEDIATE_DIR)/ui',
@@ -83,7 +77,28 @@
],
}
],
+ ['OS=="win"',
+ {
+ 'dependencies': [
+ '../../win8/win8.gyp:metro_viewer',
+ ],
+ }
+ ],
],
}, # target_name: shell_dialogs
+ {
+ 'target_name': 'shell_dialogs_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../base/base.gyp:run_all_unittests',
+ '../../testing/gtest.gyp:gtest',
+ 'shell_dialogs',
+ ],
+ 'sources': [
+ 'select_file_dialog_win_unittest.cc',
+ ],
+ },
],
}
diff --git a/chromium/ui/snapshot/BUILD.gn b/chromium/ui/snapshot/BUILD.gn
new file mode 100644
index 00000000000..78a28237d0f
--- /dev/null
+++ b/chromium/ui/snapshot/BUILD.gn
@@ -0,0 +1,95 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("snapshot") {
+ sources = [
+ "snapshot.h",
+ "snapshot_android.cc",
+ "snapshot_async.cc",
+ "snapshot_async.h",
+ "snapshot_aura.cc",
+ "snapshot_export.h",
+ "snapshot_ios.mm",
+ "snapshot_mac.mm",
+ "snapshot_win.cc",
+ "snapshot_win.h",
+ ]
+
+ defines = [ "SNAPSHOT_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ if (use_aura || is_android) {
+ deps += [
+ "//cc",
+ "//gpu/command_buffer/common",
+ ]
+ } else {
+ sources -= [
+ "snapshot_async.cc",
+ "snapshot_async.h",
+ ]
+ }
+
+ if (use_aura) {
+ deps += [
+ #"//ui/aura", TODO(GYP)
+ "//ui/compositor",
+ ]
+ } else {
+ sources -= [
+ "snapshot_aura.cc"
+ ]
+ }
+}
+
+# TODO(GYP) enable this when all targets are converted and it links
+#test("snapshot_unittests") {
+# sources = [
+# "snapshot_aura_unittest.cc",
+# "snapshot_mac_unittest.mm",
+# "test/run_all_unittests.cc",
+# ]
+#
+# deps = [
+# "//base",
+# "//base/allocator",
+# "//base/test:test_support",
+# "//skia",
+# "//testing/gtest",
+# "//ui/base",
+# "//ui/gfx",
+# "//ui/gfx/geometry",
+# ]
+#
+# if (use_aura) {
+# deps += [
+# #"//ui/aura:test_support", TODO(GYP)
+# "//ui/compositor",
+# "//ui/compositor:test_support",
+# ]
+# } else {
+# sources -= [ "snapshot_aura_unittest.cc" ]
+# }
+#}
+
+if (is_win) {
+ source_set("test_support") {
+ sources = [
+ "test/snapshot_desktop.h",
+ "test/snapshot_desktop_win.cc",
+ ]
+ deps = [
+ ":snapshot",
+ ]
+ }
+}
diff --git a/chromium/ui/snapshot/DEPS b/chromium/ui/snapshot/DEPS
index f4c16623e5a..f6768d1fc01 100644
--- a/chromium/ui/snapshot/DEPS
+++ b/chromium/ui/snapshot/DEPS
@@ -1,4 +1,6 @@
include_rules = [
+ "+cc",
+ "-cc/surfaces",
"+skia/ext",
"+third_party/skia",
"+ui/aura",
@@ -6,4 +8,5 @@ include_rules = [
"+ui/compositor",
"+ui/gfx",
"+ui/gl",
+ "+ui/wm",
]
diff --git a/chromium/ui/snapshot/snapshot.gyp b/chromium/ui/snapshot/snapshot.gyp
index b96567ad579..3aa1fcaba69 100644
--- a/chromium/ui/snapshot/snapshot.gyp
+++ b/chromium/ui/snapshot/snapshot.gyp
@@ -11,10 +11,11 @@
'target_name': 'snapshot',
'type': '<(component)',
'dependencies': [
- '../../skia/skia.gyp:skia',
'../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
],
'defines': [
'SNAPSHOT_IMPLEMENTATION',
@@ -22,9 +23,10 @@
'sources': [
'snapshot.h',
'snapshot_android.cc',
+ 'snapshot_async.cc',
+ 'snapshot_async.h',
'snapshot_aura.cc',
'snapshot_export.h',
- 'snapshot_gtk.cc',
'snapshot_ios.mm',
'snapshot_mac.mm',
'snapshot_win.cc',
@@ -34,6 +36,18 @@
'..',
],
'conditions': [
+ ['use_aura==1 or OS=="android"', {
+ 'dependencies': [
+ '../../cc/cc.gyp:cc',
+ '../../gpu/gpu.gyp:command_buffer_common',
+ ],
+ }],
+ ['use_aura!=1 and OS!="android"', {
+ 'sources!': [
+ 'snapshot_async.cc',
+ 'snapshot_async.h',
+ ],
+ }],
['use_aura==1', {
'dependencies': [
'../aura/aura.gyp:aura',
@@ -50,8 +64,9 @@
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest',
+ '../base/ui_base.gyp:ui_base',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
'snapshot'
],
'sources': [
@@ -66,10 +81,11 @@
'../aura/aura.gyp:aura_test_support',
'../compositor/compositor.gyp:compositor',
'../compositor/compositor.gyp:compositor_test_support',
+ '../wm/wm.gyp:wm',
],
}],
# See http://crbug.com/162998#c4 for why this is needed.
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
'dependencies': [
'../../base/allocator/allocator.gyp:allocator',
],
diff --git a/chromium/ui/snapshot/snapshot.h b/chromium/ui/snapshot/snapshot.h
index 356309d86ac..e547e4748dd 100644
--- a/chromium/ui/snapshot/snapshot.h
+++ b/chromium/ui/snapshot/snapshot.h
@@ -7,18 +7,30 @@
#include <vector>
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_memory.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/snapshot/snapshot_export.h"
+namespace base {
+class TaskRunner;
+}
+
namespace gfx {
class Rect;
+class Image;
+class Size;
}
namespace ui {
-// Grabs a snapshot of the window/view. No security checks are done.
-// This is intended to be used for debugging purposes where no BrowserProcess
-// instance is available (ie. tests). DO NOT use in a result of user action.
+// Grabs a snapshot of the window/view. No security checks are done. This is
+// intended to be used for debugging purposes where no BrowserProcess instance
+// is available (ie. tests). This function is synchronous, so it should NOT be
+// used in a result of user action. Support for async vs synchronous
+// GrabWindowSnapshot differs by platform. To be most general, use the
+// synchronous function first and if it returns false call the async one.
SNAPSHOT_EXPORT bool GrabWindowSnapshot(
gfx::NativeWindow window,
std::vector<unsigned char>* png_representation,
@@ -29,6 +41,30 @@ SNAPSHOT_EXPORT bool GrabViewSnapshot(
std::vector<unsigned char>* png_representation,
const gfx::Rect& snapshot_bounds);
+typedef base::Callback<void(const gfx::Image& snapshot)>
+ GrabWindowSnapshotAsyncCallback;
+// GrabWindowSnapshotAndScaleAsync() copies snapshot of |source_rect| from
+// window and scales it to |target_size| asynchronously.
+SNAPSHOT_EXPORT void GrabWindowSnapshotAndScaleAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncCallback& callback);
+
+typedef base::Callback<void(scoped_refptr<base::RefCountedBytes> png_data)>
+ GrabWindowSnapshotAsyncPNGCallback;
+SNAPSHOT_EXPORT void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback);
+SNAPSHOT_EXPORT void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback);
+
} // namespace ui
#endif // UI_SNAPSHOT_SNAPSHOT_H_
diff --git a/chromium/ui/snapshot/snapshot_android.cc b/chromium/ui/snapshot/snapshot_android.cc
index f175a87ce74..aec755516c8 100644
--- a/chromium/ui/snapshot/snapshot_android.cc
+++ b/chromium/ui/snapshot/snapshot_android.cc
@@ -4,11 +4,17 @@
#include "ui/snapshot/snapshot.h"
+#include "base/bind.h"
+#include "cc/output/copy_output_request.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/android/view_android.h"
#include "ui/base/android/window_android.h"
+#include "ui/base/android/window_android_compositor.h"
#include "ui/gfx/display.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/screen.h"
+#include "ui/snapshot/snapshot_async.h"
namespace ui {
@@ -22,14 +28,67 @@ bool GrabViewSnapshot(gfx::NativeView view,
bool GrabWindowSnapshot(gfx::NativeWindow window,
std::vector<unsigned char>* png_representation,
const gfx::Rect& snapshot_bounds) {
- gfx::Display display =
+ // Not supported in Android. Callers should fall back to the async version.
+ return false;
+}
+
+static void MakeAsyncCopyRequest(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) {
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateBitmapRequest(callback);
+
+ const gfx::Display& display =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
- gfx::Rect scaled_bounds =
- gfx::ScaleToEnclosingRect(snapshot_bounds,
- display.device_scale_factor());
- return window->GrabSnapshot(
- scaled_bounds.x(), scaled_bounds.y(), scaled_bounds.width(),
- scaled_bounds.height(), png_representation);
+ float device_scale_factor = display.device_scale_factor();
+ gfx::Rect source_rect_in_pixel =
+ gfx::ToEnclosingRect(gfx::ScaleRect(source_rect, device_scale_factor));
+
+ // Account for the toolbar offset.
+ gfx::Vector2dF offset = window->content_offset();
+ gfx::Rect adjusted_source_rect(gfx::ToRoundedPoint(
+ gfx::PointF(source_rect_in_pixel.x() + offset.x(),
+ source_rect_in_pixel.y() + offset.y())),
+ source_rect_in_pixel.size());
+
+ request->set_area(adjusted_source_rect);
+ window->GetCompositor()->RequestCopyOfOutputOnRootLayer(request.Pass());
+}
+
+void GrabWindowSnapshotAndScaleAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncCallback& callback) {
+ MakeAsyncCopyRequest(window,
+ source_rect,
+ base::Bind(&SnapshotAsync::ScaleCopyOutputResult,
+ callback,
+ target_size,
+ background_task_runner));
+}
+
+void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ MakeAsyncCopyRequest(window,
+ source_rect,
+ base::Bind(&SnapshotAsync::EncodeCopyOutputResult,
+ callback,
+ background_task_runner));
+}
+
+void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ GrabWindowSnapshotAsync(
+ view->GetWindowAndroid(), source_rect, background_task_runner, callback);
}
} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_async.cc b/chromium/ui/snapshot/snapshot_async.cc
new file mode 100644
index 00000000000..5f18225fcf4
--- /dev/null
+++ b/chromium/ui/snapshot/snapshot_async.cc
@@ -0,0 +1,103 @@
+// 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/snapshot/snapshot_async.h"
+
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/task_runner_util.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/skbitmap_operations.h"
+
+namespace ui {
+
+namespace {
+
+void OnFrameScalingFinished(const GrabWindowSnapshotAsyncCallback& callback,
+ const SkBitmap& scaled_bitmap) {
+ callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap)));
+}
+
+SkBitmap ScaleBitmap(const SkBitmap& input_bitmap,
+ const gfx::Size& target_size) {
+ return skia::ImageOperations::Resize(input_bitmap,
+ skia::ImageOperations::RESIZE_GOOD,
+ target_size.width(),
+ target_size.height(),
+ static_cast<SkBitmap::Allocator*>(NULL));
+}
+
+scoped_refptr<base::RefCountedBytes> EncodeBitmap(const SkBitmap& bitmap) {
+ scoped_refptr<base::RefCountedBytes> png_data(new base::RefCountedBytes);
+ SkAutoLockPixels lock(bitmap);
+ unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());
+#if SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8
+ gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_BGRA;
+#elif SK_A32_SHIFT == 24 && SK_B32_SHIFT == 16 && SK_G32_SHIFT == 8
+ gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_RGBA;
+#else
+#error Unknown color format
+#endif
+ if (!gfx::PNGCodec::Encode(pixels,
+ kColorFormat,
+ gfx::Size(bitmap.width(), bitmap.height()),
+ base::checked_cast<int>(bitmap.rowBytes()),
+ true,
+ std::vector<gfx::PNGCodec::Comment>(),
+ &png_data->data())) {
+ return scoped_refptr<base::RefCountedBytes>();
+ }
+ return png_data;
+}
+
+} // namespace
+
+void SnapshotAsync::ScaleCopyOutputResult(
+ const GrabWindowSnapshotAsyncCallback& callback,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ if (result->IsEmpty()) {
+ callback.Run(gfx::Image());
+ return;
+ }
+
+ // TODO(sergeyu): Potentially images can be scaled on GPU before reading it
+ // from GPU. Image scaling is implemented in content::GlHelper, but it's can't
+ // be used here because it's not in content/public. Move the scaling code
+ // somewhere so that it can be reused here.
+ base::PostTaskAndReplyWithResult(
+ background_task_runner,
+ FROM_HERE,
+ base::Bind(ScaleBitmap, *result->TakeBitmap(), target_size),
+ base::Bind(&OnFrameScalingFinished, callback));
+}
+
+void SnapshotAsync::EncodeCopyOutputResult(
+ const GrabWindowSnapshotAsyncPNGCallback& callback,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ if (result->IsEmpty()) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+ return;
+ }
+
+ // TODO(sergeyu): Potentially images can be scaled on GPU before reading it
+ // from GPU. Image scaling is implemented in content::GlHelper, but it's can't
+ // be used here because it's not in content/public. Move the scaling code
+ // somewhere so that it can be reused here.
+ base::PostTaskAndReplyWithResult(
+ background_task_runner,
+ FROM_HERE,
+ base::Bind(EncodeBitmap, *result->TakeBitmap()),
+ callback);
+}
+
+} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_async.h b/chromium/ui/snapshot/snapshot_async.h
new file mode 100644
index 00000000000..41da62ba2ac
--- /dev/null
+++ b/chromium/ui/snapshot/snapshot_async.h
@@ -0,0 +1,42 @@
+// 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_SNAPSHOT_SNAPSHOT_ASYNC_H_
+#define UI_SNAPSHOT_SNAPSHOT_ASYNC_H_
+
+#include "cc/output/copy_output_result.h"
+#include "ui/snapshot/snapshot.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace gfx {
+class Size;
+}
+
+namespace ui {
+
+// Helper methods for async snapshots to convert a cc::CopyOutputResult into a
+// ui::GrabWindowSnapshot callback.
+class SnapshotAsync {
+ public:
+ static void ScaleCopyOutputResult(
+ const GrabWindowSnapshotAsyncCallback& callback,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ scoped_ptr<cc::CopyOutputResult> result);
+
+ static void EncodeCopyOutputResult(
+ const GrabWindowSnapshotAsyncPNGCallback& callback,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ scoped_ptr<cc::CopyOutputResult> result);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SnapshotAsync);
+};
+
+} // namespace ui
+
+#endif // UI_SNAPSHOT_SNAPSHOT_ASYNC_H_
diff --git a/chromium/ui/snapshot/snapshot_aura.cc b/chromium/ui/snapshot/snapshot_aura.cc
index 1cebfe9be08..911ad358f7b 100644
--- a/chromium/ui/snapshot/snapshot_aura.cc
+++ b/chromium/ui/snapshot/snapshot_aura.cc
@@ -4,23 +4,16 @@
#include "ui/snapshot/snapshot.h"
-#include "base/logging.h"
-#include "base/safe_numerics.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/task_runner_util.h"
+#include "cc/output/copy_output_request.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/rect_f.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/skbitmap_operations.h"
-#include "ui/gfx/transform.h"
+#include "ui/snapshot/snapshot_async.h"
namespace ui {
@@ -33,58 +26,53 @@ bool GrabViewSnapshot(gfx::NativeView view,
bool GrabWindowSnapshot(gfx::NativeWindow window,
std::vector<unsigned char>* png_representation,
const gfx::Rect& snapshot_bounds) {
- ui::Compositor* compositor = window->layer()->GetCompositor();
-
- gfx::RectF read_pixels_bounds = snapshot_bounds;
-
- // We must take into account the window's position on the desktop.
- read_pixels_bounds.Offset(
- window->GetBoundsInRootWindow().origin().OffsetFromOrigin());
- aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
- if (dispatcher)
- dispatcher->GetRootTransform().TransformRect(&read_pixels_bounds);
-
- gfx::Rect read_pixels_bounds_in_pixel =
- gfx::ToEnclosingRect(read_pixels_bounds);
-
- // Sometimes (i.e. when using Aero on Windows) the compositor's size is
- // smaller than the window bounds. So trim appropriately.
- read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size()));
+ // Not supported in Aura. Callers should fall back to the async version.
+ return false;
+}
- DCHECK_LE(0, read_pixels_bounds.x());
- DCHECK_LE(0, read_pixels_bounds.y());
+static void MakeAsyncCopyRequest(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) {
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateBitmapRequest(callback);
+ request->set_area(source_rect);
+ window->layer()->RequestCopyOfOutput(request.Pass());
+}
- SkBitmap bitmap;
- if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel))
- return false;
+void GrabWindowSnapshotAndScaleAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncCallback& callback) {
+ MakeAsyncCopyRequest(window,
+ source_rect,
+ base::Bind(&SnapshotAsync::ScaleCopyOutputResult,
+ callback,
+ target_size,
+ background_task_runner));
+}
- gfx::Display display =
- gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window);
- switch (display.rotation()) {
- case gfx::Display::ROTATE_0:
- break;
- case gfx::Display::ROTATE_90:
- bitmap = SkBitmapOperations::Rotate(
- bitmap, SkBitmapOperations::ROTATION_270_CW);
- break;
- case gfx::Display::ROTATE_180:
- bitmap = SkBitmapOperations::Rotate(
- bitmap, SkBitmapOperations::ROTATION_180_CW);
- break;
- case gfx::Display::ROTATE_270:
- bitmap = SkBitmapOperations::Rotate(
- bitmap, SkBitmapOperations::ROTATION_90_CW);
- break;
- }
+void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ MakeAsyncCopyRequest(window,
+ source_rect,
+ base::Bind(&SnapshotAsync::EncodeCopyOutputResult,
+ callback,
+ background_task_runner));
+}
- unsigned char* pixels = reinterpret_cast<unsigned char*>(
- bitmap.pixelRef()->pixels());
- return gfx::PNGCodec::Encode(
- pixels, gfx::PNGCodec::FORMAT_BGRA,
- gfx::Size(bitmap.width(), bitmap.height()),
- base::checked_numeric_cast<int>(bitmap.rowBytes()),
- true, std::vector<gfx::PNGCodec::Comment>(),
- png_representation);
+void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ GrabWindowSnapshotAsync(view, source_rect, background_task_runner, callback);
}
+
} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_aura_unittest.cc b/chromium/ui/snapshot/snapshot_aura_unittest.cc
index da46bcc0e0f..5fe05a840f8 100644
--- a/chromium/ui/snapshot/snapshot_aura_unittest.cc
+++ b/chromium/ui/snapshot/snapshot_aura_unittest.cc
@@ -4,14 +4,19 @@
#include "ui/snapshot/snapshot.h"
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_helper.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
+#include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/image/image.h"
@@ -19,10 +24,14 @@
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/transform.h"
#include "ui/gl/gl_implementation.h"
+#include "ui/wm/core/default_activation_client.h"
namespace ui {
namespace {
-const SkColor kPaintColor = SK_ColorRED;
+
+SkColor GetExpectedColorForPoint(int x, int y) {
+ return SkColorSetRGB(std::min(x, 255), std::min(y, 255), 0);
+}
// Paint simple rectangle on the specified aura window.
class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate {
@@ -35,7 +44,10 @@ class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate {
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- canvas->FillRect(gfx::Rect(window_size_), kPaintColor);
+ for (int y = 0; y < window_size_.height(); ++y) {
+ for (int x = 0; x < window_size_.width(); ++x)
+ canvas->FillRect(gfx::Rect(x, y, 1, 1), GetExpectedColorForPoint(x, y));
+ }
}
private:
@@ -44,18 +56,27 @@ class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate {
DISALLOW_COPY_AND_ASSIGN(TestPaintingWindowDelegate);
};
-size_t GetFailedPixelsCount(const gfx::Image& image) {
+size_t GetFailedPixelsCountWithScaleFactor(const gfx::Image& image,
+ int scale_factor) {
const SkBitmap* bitmap = image.ToSkBitmap();
uint32* bitmap_data = reinterpret_cast<uint32*>(
bitmap->pixelRef()->pixels());
size_t result = 0;
- for (int i = 0; i < bitmap->width() * bitmap->height(); ++i) {
- if (static_cast<SkColor>(bitmap_data[i]) != kPaintColor)
- ++result;
+ for (int y = 0; y < bitmap->height(); y += scale_factor) {
+ for (int x = 0; x < bitmap->width(); x += scale_factor) {
+ if (static_cast<SkColor>(bitmap_data[x + y * bitmap->width()]) !=
+ GetExpectedColorForPoint(x / scale_factor, y / scale_factor)) {
+ ++result;
+ }
+ }
}
return result;
}
+size_t GetFailedPixelsCount(const gfx::Image& image) {
+ return GetFailedPixelsCountWithScaleFactor(image, 1);
+}
+
} // namespace
class SnapshotAuraTest : public testing::Test {
@@ -65,9 +86,17 @@ class SnapshotAuraTest : public testing::Test {
virtual void SetUp() OVERRIDE {
testing::Test::SetUp();
+
+ // The ContextFactory must exist before any Compositors are created.
+ // Snapshot test tests real drawing and readback, so needs pixel output.
+ bool enable_pixel_output = true;
+ ui::ContextFactory* context_factory =
+ ui::InitializeContextFactoryForTests(enable_pixel_output);
+
helper_.reset(
new aura::test::AuraTestHelper(base::MessageLoopForUI::current()));
- helper_->SetUp();
+ helper_->SetUp(context_factory);
+ new ::wm::DefaultActivationClient(helper_->root_window());
}
virtual void TearDown() OVERRIDE {
@@ -75,18 +104,18 @@ class SnapshotAuraTest : public testing::Test {
delegate_.reset();
helper_->RunAllPendingInMessageLoop();
helper_->TearDown();
+ ui::TerminateContextFactoryForTests();
testing::Test::TearDown();
}
protected:
aura::Window* test_window() { return test_window_.get(); }
aura::Window* root_window() { return helper_->root_window(); }
- aura::WindowEventDispatcher* dispatcher() { return helper_->dispatcher(); }
aura::TestScreen* test_screen() { return helper_->test_screen(); }
void WaitForDraw() {
- dispatcher()->compositor()->ScheduleDraw();
- ui::DrawWaiterForTest::Wait(dispatcher()->compositor());
+ helper_->host()->compositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(helper_->host()->compositor());
}
void SetupTestWindow(const gfx::Rect& window_bounds) {
@@ -96,14 +125,59 @@ class SnapshotAuraTest : public testing::Test {
}
gfx::Image GrabSnapshotForTestWindow() {
- std::vector<unsigned char> png_representation;
- gfx::Rect local_bounds(test_window_->bounds().size());
- ui::GrabWindowSnapshot(test_window(), &png_representation, local_bounds);
- return gfx::Image::CreateFrom1xPNGBytes(
- &(png_representation[0]), png_representation.size());
+ gfx::Rect source_rect(test_window_->bounds().size());
+ aura::Window::ConvertRectToTarget(
+ test_window(), root_window(), &source_rect);
+
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner(
+ new base::TestSimpleTaskRunner());
+ scoped_refptr<SnapshotHolder> holder(new SnapshotHolder);
+ ui::GrabWindowSnapshotAsync(
+ root_window(),
+ source_rect,
+ task_runner,
+ base::Bind(&SnapshotHolder::SnapshotCallback, holder));
+
+ // Wait for copy response.
+ WaitForDraw();
+ // Run internal snapshot callback to scale/rotate response image.
+ task_runner->RunUntilIdle();
+ // Run SnapshotHolder callback.
+ helper_->RunAllPendingInMessageLoop();
+
+ if (holder->completed())
+ return holder->image();
+
+ // Callback never called.
+ NOTREACHED();
+ return gfx::Image();
}
private:
+ class SnapshotHolder : public base::RefCountedThreadSafe<SnapshotHolder> {
+ public:
+ SnapshotHolder() : completed_(false) {}
+
+ void SnapshotCallback(scoped_refptr<base::RefCountedBytes> png_data) {
+ DCHECK(!completed_);
+ image_ = gfx::Image::CreateFrom1xPNGBytes(&(png_data->data()[0]),
+ png_data->size());
+ completed_ = true;
+ }
+ bool completed() const {
+ return completed_;
+ };
+ const gfx::Image& image() const { return image_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<SnapshotHolder>;
+
+ virtual ~SnapshotHolder() {}
+
+ gfx::Image image_;
+ bool completed_;
+ };
+
scoped_ptr<aura::test::AuraTestHelper> helper_;
scoped_ptr<aura::Window> test_window_;
scoped_ptr<TestPaintingWindowDelegate> delegate_;
@@ -128,8 +202,7 @@ TEST_F(SnapshotAuraTest, PartialBounds) {
WaitForDraw();
gfx::Image snapshot = GrabSnapshotForTestWindow();
- EXPECT_EQ(test_bounds.size().ToString(),
- snapshot.Size().ToString());
+ EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
}
@@ -141,8 +214,7 @@ TEST_F(SnapshotAuraTest, Rotated) {
WaitForDraw();
gfx::Image snapshot = GrabSnapshotForTestWindow();
- EXPECT_EQ(test_bounds.size().ToString(),
- snapshot.Size().ToString());
+ EXPECT_EQ(test_bounds.size().ToString(), snapshot.Size().ToString());
EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
}
@@ -156,7 +228,6 @@ TEST_F(SnapshotAuraTest, UIScale) {
// Snapshot always captures the physical pixels.
gfx::SizeF snapshot_size(test_bounds.size());
- snapshot_size.Scale(1.0f / kUIScale);
gfx::Image snapshot = GrabSnapshotForTestWindow();
EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
@@ -178,7 +249,7 @@ TEST_F(SnapshotAuraTest, DeviceScaleFactor) {
gfx::Image snapshot = GrabSnapshotForTestWindow();
EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
snapshot.Size().ToString());
- EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
+ EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
}
TEST_F(SnapshotAuraTest, RotateAndUIScale) {
@@ -192,7 +263,6 @@ TEST_F(SnapshotAuraTest, RotateAndUIScale) {
// Snapshot always captures the physical pixels.
gfx::SizeF snapshot_size(test_bounds.size());
- snapshot_size.Scale(1.0f / kUIScale);
gfx::Image snapshot = GrabSnapshotForTestWindow();
EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
@@ -212,12 +282,12 @@ TEST_F(SnapshotAuraTest, RotateAndUIScaleAndScaleFactor) {
// Snapshot always captures the physical pixels.
gfx::SizeF snapshot_size(test_bounds.size());
- snapshot_size.Scale(2.0f / kUIScale);
+ snapshot_size.Scale(2.0f);
gfx::Image snapshot = GrabSnapshotForTestWindow();
EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
snapshot.Size().ToString());
- EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
+ EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
}
} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_gtk.cc b/chromium/ui/snapshot/snapshot_gtk.cc
deleted file mode 100644
index 8a2f8c1edd7..00000000000
--- a/chromium/ui/snapshot/snapshot_gtk.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/snapshot/snapshot.h"
-
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/rect.h"
-
-namespace {
-
-cairo_status_t SnapshotCallback(void* closure,
- const unsigned char* data,
- unsigned int length) {
- std::vector<unsigned char>* png_representation =
- static_cast<std::vector<unsigned char>*>(closure);
-
- size_t old_size = png_representation->size();
- png_representation->resize(old_size + length);
- memcpy(&(*png_representation)[old_size], data, length);
- return CAIRO_STATUS_SUCCESS;
-}
-
-} // namespace
-
-namespace ui {
-
-bool GrabViewSnapshot(gfx::NativeView view_handle,
- std::vector<unsigned char>* png_representation,
- const gfx::Rect& snapshot_bounds) {
- GdkWindow* gdk_window = gtk_widget_get_window(view_handle);
- Display* display = GDK_WINDOW_XDISPLAY(gdk_window);
- XID win = GDK_WINDOW_XID(gdk_window);
-
- gfx::Rect window_bounds;
- if (ui::GetWindowRect(win, &window_bounds) == 0) {
- LOG(ERROR) << "Couldn't get window bounds";
- return false;
- }
-
- DCHECK_LE(snapshot_bounds.right(), window_bounds.width());
- DCHECK_LE(snapshot_bounds.bottom(), window_bounds.height());
-
- ui::XScopedImage image(XGetImage(
- display, win, snapshot_bounds.x(), snapshot_bounds.y(),
- snapshot_bounds.width(), snapshot_bounds.height(), AllPlanes, ZPixmap));
- if (!image.get()) {
- LOG(ERROR) << "Couldn't get image";
- return false;
- }
- if (image->depth != 24) {
- LOG(ERROR)<< "Unsupported image depth " << image->depth;
- return false;
- }
- cairo_surface_t* surface =
- cairo_image_surface_create_for_data(
- reinterpret_cast<unsigned char*>(image->data),
- CAIRO_FORMAT_RGB24,
- image->width,
- image->height,
- image->bytes_per_line);
-
- if (!surface) {
- LOG(ERROR) << "Unable to create Cairo surface from XImage data";
- return false;
- }
- cairo_surface_write_to_png_stream(
- surface, SnapshotCallback, png_representation);
- cairo_surface_destroy(surface);
-
- return true;
-}
-
-bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
- std::vector<unsigned char>* png_representation,
- const gfx::Rect& snapshot_bounds) {
- return GrabViewSnapshot(GTK_WIDGET(window_handle), png_representation,
- snapshot_bounds);
-}
-
-} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_ios.mm b/chromium/ui/snapshot/snapshot_ios.mm
index b373a0367b5..872b4865123 100644
--- a/chromium/ui/snapshot/snapshot_ios.mm
+++ b/chromium/ui/snapshot/snapshot_ios.mm
@@ -4,6 +4,8 @@
#include "ui/snapshot/snapshot.h"
+#include "base/callback.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -22,4 +24,29 @@ bool GrabWindowSnapshot(gfx::NativeWindow window,
return false;
}
+void GrabWindowSnapshotAndScaleAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& snapshot_bounds,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ GrabWindowSnapshotAsyncCallback callback) {
+ callback.Run(gfx::Image());
+}
+
+void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+}
+
+void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+}
+
} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_mac.mm b/chromium/ui/snapshot/snapshot_mac.mm
index abd87286a2d..aa94fe5c4d5 100644
--- a/chromium/ui/snapshot/snapshot_mac.mm
+++ b/chromium/ui/snapshot/snapshot_mac.mm
@@ -6,9 +6,12 @@
#import <Cocoa/Cocoa.h>
+#include "base/callback.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/task_runner.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -72,4 +75,30 @@ bool GrabWindowSnapshot(gfx::NativeWindow window,
snapshot_bounds);
}
+void GrabWindowSnapshotAndScaleAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& snapshot_bounds,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ GrabWindowSnapshotAsyncCallback callback) {
+ callback.Run(gfx::Image());
+}
+
+void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+}
+
+void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ return GrabViewSnapshotAsync([[window contentView] superview], source_rect,
+ background_task_runner, callback);
+}
+
} // namespace ui
diff --git a/chromium/ui/snapshot/snapshot_win.cc b/chromium/ui/snapshot/snapshot_win.cc
index 8c2ff3bd5bf..29a6be20548 100644
--- a/chromium/ui/snapshot/snapshot_win.cc
+++ b/chromium/ui/snapshot/snapshot_win.cc
@@ -4,6 +4,7 @@
#include "ui/snapshot/snapshot_win.h"
+#include "base/callback.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
@@ -103,6 +104,7 @@ bool GrabHwndSnapshot(HWND window_handle,
} // namespace internal
#if !defined(USE_AURA)
+
bool GrabViewSnapshot(gfx::NativeView view_handle,
std::vector<unsigned char>* png_representation,
const gfx::Rect& snapshot_bounds) {
@@ -116,6 +118,33 @@ bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
return internal::GrabHwndSnapshot(window_handle, snapshot_bounds,
png_representation);
}
+
+void GrapWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& snapshot_bounds,
+ const gfx::Size& target_size,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ GrabWindowSnapshotAsyncCallback callback) {
+ callback.Run(gfx::Image());
+}
+
+void GrabViewSnapshotAsync(
+ gfx::NativeView view,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+}
+
+
+void GrabWindowSnapshotAsync(
+ gfx::NativeWindow window,
+ const gfx::Rect& source_rect,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ const GrabWindowSnapshotAsyncPNGCallback& callback) {
+ callback.Run(scoped_refptr<base::RefCountedBytes>());
+}
+
#endif // !defined(USE_AURA)
} // namespace ui
diff --git a/chromium/ui/strings/BUILD.gn b/chromium/ui/strings/BUILD.gn
new file mode 100644
index 00000000000..0b4cfc8be46
--- /dev/null
+++ b/chromium/ui/strings/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//tools/grit/grit_rule.gni")
+
+# Meta target that includes both ui_strings and app_locale_settings. Most
+# targets want both. You can depend on the individually if you need to.
+group("strings") {
+ deps = [
+ ":ui_strings",
+ ":app_locale_settings",
+ ]
+}
+
+grit("ui_strings") {
+ source = "ui_strings.grd"
+}
+
+grit("app_locale_settings") {
+ source = "app_locale_settings.grd"
+}
diff --git a/chromium/ui/base/strings/OWNERS b/chromium/ui/strings/OWNERS
index 72e8ffc0db8..72e8ffc0db8 100644
--- a/chromium/ui/base/strings/OWNERS
+++ b/chromium/ui/strings/OWNERS
diff --git a/chromium/ui/strings/app_locale_settings.grd b/chromium/ui/strings/app_locale_settings.grd
new file mode 100644
index 00000000000..ee41ac3516d
--- /dev/null
+++ b/chromium/ui/strings/app_locale_settings.grd
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1">
+ <outputs>
+ <output filename="grit/app_locale_settings.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="app_locale_settings_am.pak" type="data_package" lang="am" />
+ <output filename="app_locale_settings_ar.pak" type="data_package" lang="ar" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_ast.pak" type="data_package" lang="ast" />
+ </if>
+ <output filename="app_locale_settings_bg.pak" type="data_package" lang="bg" />
+ <output filename="app_locale_settings_bn.pak" type="data_package" lang="bn" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_bs.pak" type="data_package" lang="bs" />
+ </if>
+ <output filename="app_locale_settings_ca.pak" type="data_package" lang="ca" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
+ </if>
+ <output filename="app_locale_settings_cs.pak" type="data_package" lang="cs" />
+ <output filename="app_locale_settings_da.pak" type="data_package" lang="da" />
+ <output filename="app_locale_settings_de.pak" type="data_package" lang="de" />
+ <output filename="app_locale_settings_el.pak" type="data_package" lang="el" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_en-AU.pak" type="data_package" lang="en-AU" />
+ </if>
+ <output filename="app_locale_settings_en-GB.pak" type="data_package" lang="en-GB" />
+ <output filename="app_locale_settings_en-US.pak" type="data_package" lang="en" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_eo.pak" type="data_package" lang="eo" />
+ </if>
+ <output filename="app_locale_settings_es.pak" type="data_package" lang="es" />
+ <if expr="is_ios">
+ <!-- iOS uses es-MX for es-419 -->
+ <output filename="app_locale_settings_es-MX.pak" type="data_package" lang="es-419" />
+ </if>
+ <if expr="not is_ios">
+ <output filename="app_locale_settings_es-419.pak" type="data_package" lang="es-419" />
+ </if>
+ <output filename="app_locale_settings_et.pak" type="data_package" lang="et" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_eu.pak" type="data_package" lang="eu" />
+ </if>
+ <output filename="app_locale_settings_fa.pak" type="data_package" lang="fa" />
+ <output filename="app_locale_settings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
+ <output filename="app_locale_settings_fi.pak" type="data_package" lang="fi" />
+ <output filename="app_locale_settings_fil.pak" type="data_package" lang="fil" />
+ <output filename="app_locale_settings_fr.pak" type="data_package" lang="fr" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_gl.pak" type="data_package" lang="gl" />
+ </if>
+ <output filename="app_locale_settings_gu.pak" type="data_package" lang="gu" />
+ <output filename="app_locale_settings_he.pak" type="data_package" lang="he" />
+ <output filename="app_locale_settings_hi.pak" type="data_package" lang="hi" />
+ <output filename="app_locale_settings_hr.pak" type="data_package" lang="hr" />
+ <output filename="app_locale_settings_hu.pak" type="data_package" lang="hu" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_hy.pak" type="data_package" lang="hy" />
+ <output filename="app_locale_settings_ia.pak" type="data_package" lang="ia" />
+ </if>
+ <output filename="app_locale_settings_id.pak" type="data_package" lang="id" />
+ <output filename="app_locale_settings_it.pak" type="data_package" lang="it" />
+ <output filename="app_locale_settings_ja.pak" type="data_package" lang="ja" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_ka.pak" type="data_package" lang="ka" />
+ </if>
+ <output filename="app_locale_settings_kn.pak" type="data_package" lang="kn" />
+ <output filename="app_locale_settings_ko.pak" type="data_package" lang="ko" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_ku.pak" type="data_package" lang="ku" />
+ <output filename="app_locale_settings_kw.pak" type="data_package" lang="kw" />
+ </if>
+ <output filename="app_locale_settings_lt.pak" type="data_package" lang="lt" />
+ <output filename="app_locale_settings_lv.pak" type="data_package" lang="lv" />
+ <output filename="app_locale_settings_ml.pak" type="data_package" lang="ml" />
+ <output filename="app_locale_settings_mr.pak" type="data_package" lang="mr" />
+ <output filename="app_locale_settings_ms.pak" type="data_package" lang="ms" />
+ <output filename="app_locale_settings_nl.pak" type="data_package" lang="nl" />
+ <!-- The translation console uses 'no' for Norwegian Bokmål. It should
+ be 'nb'. -->
+ <output filename="app_locale_settings_nb.pak" type="data_package" lang="no" />
+ <output filename="app_locale_settings_pl.pak" type="data_package" lang="pl" />
+ <if expr="is_ios">
+ <!-- iOS uses pt for pt-BR -->
+ <output filename="app_locale_settings_pt.pak" type="data_package" lang="pt-BR" />
+ </if>
+ <if expr="not is_ios">
+ <output filename="app_locale_settings_pt-BR.pak" type="data_package" lang="pt-BR" />
+ </if>
+ <output filename="app_locale_settings_pt-PT.pak" type="data_package" lang="pt-PT" />
+ <output filename="app_locale_settings_ro.pak" type="data_package" lang="ro" />
+ <output filename="app_locale_settings_ru.pak" type="data_package" lang="ru" />
+ <output filename="app_locale_settings_sk.pak" type="data_package" lang="sk" />
+ <output filename="app_locale_settings_sl.pak" type="data_package" lang="sl" />
+ <output filename="app_locale_settings_sr.pak" type="data_package" lang="sr" />
+ <output filename="app_locale_settings_sv.pak" type="data_package" lang="sv" />
+ <output filename="app_locale_settings_sw.pak" type="data_package" lang="sw" />
+ <output filename="app_locale_settings_ta.pak" type="data_package" lang="ta" />
+ <output filename="app_locale_settings_te.pak" type="data_package" lang="te" />
+ <output filename="app_locale_settings_th.pak" type="data_package" lang="th" />
+ <output filename="app_locale_settings_tr.pak" type="data_package" lang="tr" />
+ <if expr="use_third_party_translations">
+ <output filename="app_locale_settings_ug.pak" type="data_package" lang="ug" />
+ </if>
+ <output filename="app_locale_settings_uk.pak" type="data_package" lang="uk" />
+ <output filename="app_locale_settings_vi.pak" type="data_package" lang="vi" />
+ <output filename="app_locale_settings_zh-CN.pak" type="data_package" lang="zh-CN" />
+ <output filename="app_locale_settings_zh-TW.pak" type="data_package" lang="zh-TW" />
+ </outputs>
+ <translations>
+ <file path="translations/app_locale_settings_am.xtb" lang="am" />
+ <file path="translations/app_locale_settings_ar.xtb" lang="ar" />
+ <file path="translations/app_locale_settings_bg.xtb" lang="bg" />
+ <file path="translations/app_locale_settings_bn.xtb" lang="bn" />
+ <file path="translations/app_locale_settings_ca.xtb" lang="ca" />
+ <file path="translations/app_locale_settings_cs.xtb" lang="cs" />
+ <file path="translations/app_locale_settings_da.xtb" lang="da" />
+ <file path="translations/app_locale_settings_de.xtb" lang="de" />
+ <file path="translations/app_locale_settings_el.xtb" lang="el" />
+ <file path="translations/app_locale_settings_en-GB.xtb" lang="en-GB" />
+ <file path="translations/app_locale_settings_es.xtb" lang="es" />
+ <file path="translations/app_locale_settings_es-419.xtb" lang="es-419" />
+ <file path="translations/app_locale_settings_et.xtb" lang="et" />
+ <file path="translations/app_locale_settings_fa.xtb" lang="fa" />
+ <file path="translations/app_locale_settings_fi.xtb" lang="fi" />
+ <file path="translations/app_locale_settings_fil.xtb" lang="fil" />
+ <file path="translations/app_locale_settings_fr.xtb" lang="fr" />
+ <file path="translations/app_locale_settings_gu.xtb" lang="gu" />
+ <file path="translations/app_locale_settings_he.xtb" lang="he" />
+ <file path="translations/app_locale_settings_hi.xtb" lang="hi" />
+ <file path="translations/app_locale_settings_hr.xtb" lang="hr" />
+ <file path="translations/app_locale_settings_hu.xtb" lang="hu" />
+ <file path="translations/app_locale_settings_id.xtb" lang="id" />
+ <file path="translations/app_locale_settings_it.xtb" lang="it" />
+ <file path="translations/app_locale_settings_ja.xtb" lang="ja" />
+ <file path="translations/app_locale_settings_kn.xtb" lang="kn" />
+ <file path="translations/app_locale_settings_ko.xtb" lang="ko" />
+ <file path="translations/app_locale_settings_lt.xtb" lang="lt" />
+ <file path="translations/app_locale_settings_lv.xtb" lang="lv" />
+ <file path="translations/app_locale_settings_ml.xtb" lang="ml" />
+ <file path="translations/app_locale_settings_mr.xtb" lang="mr" />
+ <file path="translations/app_locale_settings_ms.xtb" lang="ms" />
+ <file path="translations/app_locale_settings_nl.xtb" lang="nl" />
+ <file path="translations/app_locale_settings_nb.xtb" lang="no" />
+ <file path="translations/app_locale_settings_pl.xtb" lang="pl" />
+ <file path="translations/app_locale_settings_pt-BR.xtb" lang="pt-BR" />
+ <file path="translations/app_locale_settings_pt-PT.xtb" lang="pt-PT" />
+ <file path="translations/app_locale_settings_ro.xtb" lang="ro" />
+ <file path="translations/app_locale_settings_ru.xtb" lang="ru" />
+ <file path="translations/app_locale_settings_sk.xtb" lang="sk" />
+ <file path="translations/app_locale_settings_sl.xtb" lang="sl" />
+ <file path="translations/app_locale_settings_sr.xtb" lang="sr" />
+ <file path="translations/app_locale_settings_sv.xtb" lang="sv" />
+ <file path="translations/app_locale_settings_sw.xtb" lang="sw" />
+ <file path="translations/app_locale_settings_ta.xtb" lang="ta" />
+ <file path="translations/app_locale_settings_te.xtb" lang="te" />
+ <file path="translations/app_locale_settings_th.xtb" lang="th" />
+ <file path="translations/app_locale_settings_tr.xtb" lang="tr" />
+ <file path="translations/app_locale_settings_uk.xtb" lang="uk" />
+ <file path="translations/app_locale_settings_vi.xtb" lang="vi" />
+ <file path="translations/app_locale_settings_zh-CN.xtb" lang="zh-CN" />
+ <file path="translations/app_locale_settings_zh-TW.xtb" lang="zh-TW" />
+ </translations>
+ <release seq="1" allow_pseudo="false">
+ <messages fallback_to_english="true">
+ <!-- The UI font used in native UI components (e.g. menu). 'default'
+ indicates that the font obtained from the system be used.
+ Otherwise, the system default UI font will be overriden with
+ the family specified. This should be default for locales
+ other than Indian locales.
+ TODO(jungshik): This and IDS_UI_FONT_SIZE_SCALER are only used
+ on Windows now and are likely to be so in the future because Mac and
+ Linux fonts do not have the issue Windows fonts for some locales
+ (Indian) have. In that case, this need to be enclosed
+ by platform-dependent if-clause. -->
+ <if expr="is_win">
+ <!-- Limit minimum UI font size to 5 by default. -->
+ <message name="IDS_MINIMUM_UI_FONT_SIZE" use_name_for_id="true">
+ 5
+ </message>
+
+ <message name="IDS_UI_FONT_FAMILY" use_name_for_id="true">
+ default
+ </message>
+ <!-- For Windows XP -->
+ <message name="IDS_UI_FONT_FAMILY_XP" use_name_for_id="true">
+ default
+ </message>
+
+ <!-- To get the actual UI font size for native UI components
+ (e.g. menu), the system UI font size is scaled with this value/100.
+ This should be 100 for most locales. -->
+ <message name="IDS_UI_FONT_SIZE_SCALER" use_name_for_id="true">
+ 100
+ </message>
+ <!-- For Windows XP -->
+ <message name="IDS_UI_FONT_SIZE_SCALER_XP" use_name_for_id="true">
+ 100
+ </message>
+
+ <!-- The font used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
+ 'Segoe UI', Tahoma, sans-serif
+ </message>
+ <!-- The font used in Web UI on Windows XP (e.g. History). -->
+ <message name="IDS_WEB_FONT_FAMILY_XP" use_name_for_id="true">
+ Tahoma, sans-serif
+ </message>
+
+ <!-- The relative font size in % used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
+ 75%
+ </message>
+ <!-- The relative font size in % used in web-style native pages
+ on Windows earlier than Vista (e.g. History). -->
+ <message name="IDS_WEB_FONT_SIZE_XP" use_name_for_id="true">
+ 75%
+ </message>
+ </if>
+ <if expr="is_macosx or is_ios">
+ <!-- The font used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
+ 'Lucida Grande', sans-serif
+ </message>
+
+ <!-- The relative font size in % used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
+ 75%
+ </message>
+ </if>
+ <if expr="(desktop_linux or is_android) and not chromeos">
+ <!-- The font used in Web UI (e.g. History). Note that these are only
+ backups. We try to use the system font if possible. -->
+ <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
+ Arial, sans-serif
+ </message>
+
+ <!-- The relative font size in % used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
+ 75%
+ </message>
+ </if>
+ <!-- For Chrome OS -->
+ <if expr="chromeos">
+ <!-- The font name like: 'Font Name, 10' -->
+ <message name="IDS_UI_FONT_FAMILY_CROS" use_name_for_id="true">
+ Noto Sans UI,ui-sans, 12px
+ </message>
+
+ <!-- The font used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
+ 'Noto Sans UI', sans-serif
+ </message>
+
+ <!-- The relative font size in % used in Web UI (e.g. History). -->
+ <message name="IDS_WEB_FONT_SIZE" use_name_for_id="true">
+ 75%
+ </message>
+ </if>
+ </messages>
+ </release>
+</grit>
diff --git a/chromium/ui/strings/translations/app_locale_settings_am.xtb b/chromium/ui/strings/translations/app_locale_settings_am.xtb
new file mode 100644
index 00000000000..38622189be2
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_am.xtb
@@ -0,0 +1,8 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+<translation id="IDS_UI_FONT_FAMILY_XP">abyssinica sil</translation>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Abyssinica SIL, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_ar.xtb b/chromium/ui/strings/translations/app_locale_settings_ar.xtb
new file mode 100644
index 00000000000..6eb1ddc20ee
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_ar.xtb
@@ -0,0 +1,9 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Naskh Arabic UI, ui-sans, 13px</translation>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Naskh Arabic UI, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_bg.xtb b/chromium/ui/strings/translations/app_locale_settings_bg.xtb
index ebab4736462..ebab4736462 100644
--- a/chromium/ui/base/strings/app_locale_settings_bg.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_bg.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_bn.xtb b/chromium/ui/strings/translations/app_locale_settings_bn.xtb
new file mode 100644
index 00000000000..3777caa060e
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_bn.xtb
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bn">
+<if expr="is_win">
+ <translation id="IDS_UI_FONT_FAMILY">Vrinda</translation>
+ <translation id="IDS_UI_FONT_FAMILY_XP">Vrinda</translation>
+ <translation id="IDS_UI_FONT_SIZE_SCALER_XP">160</translation>
+ <translation id="IDS_UI_FONT_SIZE_SCALER">120</translation>
+ <translation id="IDS_WEB_FONT_SIZE_XP">110%</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">Vrinda</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Vrinda</translation>
+</if>
+<if expr="desktop_linux and not chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Lohit Bengali</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Bengali UI, ui-sans, 13px</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Bengali UI, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ca.xtb b/chromium/ui/strings/translations/app_locale_settings_ca.xtb
index 1438d89736b..1438d89736b 100644
--- a/chromium/ui/base/strings/app_locale_settings_ca.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_ca.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_cs.xtb b/chromium/ui/strings/translations/app_locale_settings_cs.xtb
index 2d95130b933..2d95130b933 100644
--- a/chromium/ui/base/strings/app_locale_settings_cs.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_cs.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_da.xtb b/chromium/ui/strings/translations/app_locale_settings_da.xtb
index 751fa4a8b98..751fa4a8b98 100644
--- a/chromium/ui/base/strings/app_locale_settings_da.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_da.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_de.xtb b/chromium/ui/strings/translations/app_locale_settings_de.xtb
index 91de7f5115b..91de7f5115b 100644
--- a/chromium/ui/base/strings/app_locale_settings_de.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_de.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_el.xtb b/chromium/ui/strings/translations/app_locale_settings_el.xtb
index 6e5e7d8157a..6e5e7d8157a 100644
--- a/chromium/ui/base/strings/app_locale_settings_el.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_el.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_en-GB.xtb b/chromium/ui/strings/translations/app_locale_settings_en-GB.xtb
index 0fb2133a32a..0fb2133a32a 100644
--- a/chromium/ui/base/strings/app_locale_settings_en-GB.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_en-GB.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_es-419.xtb b/chromium/ui/strings/translations/app_locale_settings_es-419.xtb
index 2fe4770c0d6..2fe4770c0d6 100644
--- a/chromium/ui/base/strings/app_locale_settings_es-419.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_es-419.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_es.xtb b/chromium/ui/strings/translations/app_locale_settings_es.xtb
index 64022ecf43c..64022ecf43c 100644
--- a/chromium/ui/base/strings/app_locale_settings_es.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_es.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_et.xtb b/chromium/ui/strings/translations/app_locale_settings_et.xtb
index 5244dfd4bfd..5244dfd4bfd 100644
--- a/chromium/ui/base/strings/app_locale_settings_et.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_et.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_fa.xtb b/chromium/ui/strings/translations/app_locale_settings_fa.xtb
index 386e0aeb95e..386e0aeb95e 100644
--- a/chromium/ui/base/strings/app_locale_settings_fa.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_fa.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_fi.xtb b/chromium/ui/strings/translations/app_locale_settings_fi.xtb
index 4691cd56eaf..4691cd56eaf 100644
--- a/chromium/ui/base/strings/app_locale_settings_fi.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_fi.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_fil.xtb b/chromium/ui/strings/translations/app_locale_settings_fil.xtb
index 443630e740a..443630e740a 100644
--- a/chromium/ui/base/strings/app_locale_settings_fil.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_fil.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_fr.xtb b/chromium/ui/strings/translations/app_locale_settings_fr.xtb
index 63026a3ad03..63026a3ad03 100644
--- a/chromium/ui/base/strings/app_locale_settings_fr.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_fr.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_gu.xtb b/chromium/ui/strings/translations/app_locale_settings_gu.xtb
index 36e499834fc..36e499834fc 100644
--- a/chromium/ui/base/strings/app_locale_settings_gu.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_gu.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_he.xtb b/chromium/ui/strings/translations/app_locale_settings_he.xtb
index 55450118f8a..55450118f8a 100644
--- a/chromium/ui/base/strings/app_locale_settings_he.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_he.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_hi.xtb b/chromium/ui/strings/translations/app_locale_settings_hi.xtb
new file mode 100644
index 00000000000..c7ddf75ba7d
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_hi.xtb
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+<translation id="IDS_UI_FONT_SIZE_SCALER_XP">140</translation>
+<translation id="IDS_UI_FONT_SIZE_SCALER">125</translation>
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Devanagari UI,ui-sans, 13px</translation>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Devanagari UI,sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_hr.xtb b/chromium/ui/strings/translations/app_locale_settings_hr.xtb
index 26f99d08e94..26f99d08e94 100644
--- a/chromium/ui/base/strings/app_locale_settings_hr.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_hr.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_hu.xtb b/chromium/ui/strings/translations/app_locale_settings_hu.xtb
index 7ef9a5e0bbe..7ef9a5e0bbe 100644
--- a/chromium/ui/base/strings/app_locale_settings_hu.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_hu.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_id.xtb b/chromium/ui/strings/translations/app_locale_settings_id.xtb
index aa34783a27c..aa34783a27c 100644
--- a/chromium/ui/base/strings/app_locale_settings_id.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_id.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_it.xtb b/chromium/ui/strings/translations/app_locale_settings_it.xtb
index a6ac8d46363..a6ac8d46363 100644
--- a/chromium/ui/base/strings/app_locale_settings_it.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_it.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_ja.xtb b/chromium/ui/strings/translations/app_locale_settings_ja.xtb
new file mode 100644
index 00000000000..51a6c245370
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_ja.xtb
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">MotoyaG04Gothic,Noto Sans UI,IPAPGothic,ui-sans, 13px</translation>
+<if expr="is_win">
+ <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,Meiryo,'MS PGothic',sans-serif</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,Meiryo,'MS PGothic',sans-serif</translation>
+</if>
+<if expr="is_macosx or is_ios">
+ <translation id="IDS_WEB_FONT_FAMILY">Helvetica,Hiragino Kaku Gothic Pro,sans-serif</translation>
+</if>
+<if expr="desktop_linux and not chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">VL PGothic,Sazanami Gothic,Kochi Gothic,sans-serif</translation>
+</if>
+<if expr="chromeos and _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">MotoyaG04Gothic, Noto Sans UI, sans-serif</translation>
+</if>
+<if expr="chromeos and not _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, IPAPGothic, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_kn.xtb b/chromium/ui/strings/translations/app_locale_settings_kn.xtb
new file mode 100644
index 00000000000..a5d7bb96fc6
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_kn.xtb
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="kn">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<if expr="is_win">
+ <translation id="IDS_UI_FONT_SIZE_SCALER_XP">142</translation>
+ <translation id="IDS_UI_FONT_SIZE_SCALER">130</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Kannada UI,ui-sans, 13px</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Kannada UI, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_ko.xtb b/chromium/ui/strings/translations/app_locale_settings_ko.xtb
new file mode 100644
index 00000000000..f8da3731d29
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_ko.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,NanumGothic,ui-sans, 13px</translation>
+<if expr="is_win">
+ <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Malgun Gothic',Gulim,sans-serif</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Malgun Gothic',Gulim,sans-serif</translation>
+</if>
+<if expr="is_macosx or is_ios">
+ <translation id="IDS_WEB_FONT_FAMILY">Helvetica,AppleGothic,sans-serif</translation>
+</if>
+<if expr="desktop_linux and not chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">NanumGothic,UnDotum,Baekmuk Gulim,sans-serif</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, NanumGothic, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_lt.xtb b/chromium/ui/strings/translations/app_locale_settings_lt.xtb
index 5804ae2a34c..5804ae2a34c 100644
--- a/chromium/ui/base/strings/app_locale_settings_lt.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_lt.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_lv.xtb b/chromium/ui/strings/translations/app_locale_settings_lv.xtb
index a0a1c477043..a0a1c477043 100644
--- a/chromium/ui/base/strings/app_locale_settings_lv.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_lv.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_ml.xtb b/chromium/ui/strings/translations/app_locale_settings_ml.xtb
new file mode 100644
index 00000000000..9df3a5aa451
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_ml.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ml">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<if expr="is_win">
+ <translation id="IDS_UI_FONT_FAMILY_XP">kartika</translation>
+ <translation id="IDS_UI_FONT_SIZE_SCALER_XP">150</translation>
+ <translation id="IDS_UI_FONT_SIZE_SCALER">120</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,AnjaliOldLipi,Rachana,Kartika</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,AnjaliOldLipi,Rachana,Kartika</translation>
+</if>
+<if expr="desktop_linux and not chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Arial,AnjaliOldLipi,Rachana,Kartika,sans-serif</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Malayalam UI,ui-sans, 13px</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Malayalam UI, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_mr.xtb b/chromium/ui/strings/translations/app_locale_settings_mr.xtb
new file mode 100644
index 00000000000..1e0754fca80
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_mr.xtb
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="mr">
+<translation id="IDS_UI_FONT_SIZE_SCALER_XP">140</translation>
+<translation id="IDS_UI_FONT_SIZE_SCALER">125</translation>
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Devanagari UI,ui-sans, 13px</translation>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Devanagari UI,sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_ms.xtb b/chromium/ui/strings/translations/app_locale_settings_ms.xtb
index 518685dd52f..518685dd52f 100644
--- a/chromium/ui/base/strings/app_locale_settings_ms.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_ms.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_nb.xtb b/chromium/ui/strings/translations/app_locale_settings_nb.xtb
index 913638ba4e9..913638ba4e9 100644
--- a/chromium/ui/base/strings/app_locale_settings_nb.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_nb.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_nl.xtb b/chromium/ui/strings/translations/app_locale_settings_nl.xtb
index e78241066f9..e78241066f9 100644
--- a/chromium/ui/base/strings/app_locale_settings_nl.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_nl.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_pl.xtb b/chromium/ui/strings/translations/app_locale_settings_pl.xtb
index 4519e3de389..4519e3de389 100644
--- a/chromium/ui/base/strings/app_locale_settings_pl.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_pl.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_pt-BR.xtb b/chromium/ui/strings/translations/app_locale_settings_pt-BR.xtb
index e95eb56bb7b..e95eb56bb7b 100644
--- a/chromium/ui/base/strings/app_locale_settings_pt-BR.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_pt-BR.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_pt-PT.xtb b/chromium/ui/strings/translations/app_locale_settings_pt-PT.xtb
index 1dcf557a081..1dcf557a081 100644
--- a/chromium/ui/base/strings/app_locale_settings_pt-PT.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_pt-PT.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_ro.xtb b/chromium/ui/strings/translations/app_locale_settings_ro.xtb
index 9e434933f16..9e434933f16 100644
--- a/chromium/ui/base/strings/app_locale_settings_ro.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_ro.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_ru.xtb b/chromium/ui/strings/translations/app_locale_settings_ru.xtb
index c4a621b9fdd..c4a621b9fdd 100644
--- a/chromium/ui/base/strings/app_locale_settings_ru.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_ru.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_sk.xtb b/chromium/ui/strings/translations/app_locale_settings_sk.xtb
index 00750d31cd0..00750d31cd0 100644
--- a/chromium/ui/base/strings/app_locale_settings_sk.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_sk.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_sl.xtb b/chromium/ui/strings/translations/app_locale_settings_sl.xtb
index 489b7e46ba0..489b7e46ba0 100644
--- a/chromium/ui/base/strings/app_locale_settings_sl.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_sl.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_sr.xtb b/chromium/ui/strings/translations/app_locale_settings_sr.xtb
index 38f6f354db5..38f6f354db5 100644
--- a/chromium/ui/base/strings/app_locale_settings_sr.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_sr.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_sv.xtb b/chromium/ui/strings/translations/app_locale_settings_sv.xtb
index ddea3dcce5d..ddea3dcce5d 100644
--- a/chromium/ui/base/strings/app_locale_settings_sv.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_sv.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_sw.xtb b/chromium/ui/strings/translations/app_locale_settings_sw.xtb
index b7750886d22..b7750886d22 100644
--- a/chromium/ui/base/strings/app_locale_settings_sw.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_sw.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_ta.xtb b/chromium/ui/strings/translations/app_locale_settings_ta.xtb
new file mode 100644
index 00000000000..9051adc2c9e
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_ta.xtb
@@ -0,0 +1,8 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ta">
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Tamil UI,ui-sans, 13px</translation>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Tamil UI,sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_te.xtb b/chromium/ui/strings/translations/app_locale_settings_te.xtb
new file mode 100644
index 00000000000..8346fb01302
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_te.xtb
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="te">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<if expr="is_win">
+<translation id="IDS_UI_FONT_SIZE_SCALER_XP">145</translation>
+<translation id="IDS_UI_FONT_SIZE_SCALER">130</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI, Noto Sans Telugu UI,ui-sans, 13px</translation>
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans Telugu UI, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_th.xtb b/chromium/ui/strings/translations/app_locale_settings_th.xtb
new file mode 100644
index 00000000000..9c6b6f53ea5
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_th.xtb
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans Thai UI,ui-sans, 13px</translation>
+<if expr="is_win">
+ <translation id="IDS_WEB_FONT_FAMILY">Tahoma,sans-serif</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Tahoma,sans-serif</translation>
+</if>
+<if expr="desktop_linux and not chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Norasi,Waree,Garuda,Loma,sans-serif</translation>
+</if>
+<if expr="chromeos">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI,Noto Sans Thai UI,sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/base/strings/app_locale_settings_tr.xtb b/chromium/ui/strings/translations/app_locale_settings_tr.xtb
index 9a299515338..9a299515338 100644
--- a/chromium/ui/base/strings/app_locale_settings_tr.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_tr.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_uk.xtb b/chromium/ui/strings/translations/app_locale_settings_uk.xtb
index f0db52c6692..f0db52c6692 100644
--- a/chromium/ui/base/strings/app_locale_settings_uk.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_uk.xtb
diff --git a/chromium/ui/base/strings/app_locale_settings_vi.xtb b/chromium/ui/strings/translations/app_locale_settings_vi.xtb
index b2957daa924..b2957daa924 100644
--- a/chromium/ui/base/strings/app_locale_settings_vi.xtb
+++ b/chromium/ui/strings/translations/app_locale_settings_vi.xtb
diff --git a/chromium/ui/strings/translations/app_locale_settings_zh-CN.xtb b/chromium/ui/strings/translations/app_locale_settings_zh-CN.xtb
new file mode 100644
index 00000000000..e9c4026a6d6
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_zh-CN.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiGB18030,MYingHeiB5HK,ui-sans, 13px</translation>
+<if expr="is_win">
+ <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
+</if>
+<if expr="is_macosx or is_ios">
+ <translation id="IDS_WEB_FONT_FAMILY">Helvetica,STHeiti,sans-serif</translation>
+</if>
+<if expr="chromeos and _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiGB18030, MYingHeiB5HK, sans-serif</translation>
+</if>
+<if expr="chromeos and not _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/app_locale_settings_zh-TW.xtb b/chromium/ui/strings/translations/app_locale_settings_zh-TW.xtb
new file mode 100644
index 00000000000..05c69e30af4
--- /dev/null
+++ b/chromium/ui/strings/translations/app_locale_settings_zh-TW.xtb
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+<translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiB5HK,MYingHeiGB18030,ui-sans, 13px</translation>
+<if expr="is_win">
+ <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
+ <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
+</if>
+<if expr="is_macosx or is_ios">
+ <translation id="IDS_WEB_FONT_FAMILY">Helvetica,Heiti TC,sans-serif</translation>
+</if>
+<if expr="chromeos and _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiB5HK, MYingHeiGB18030, sans-serif</translation>
+</if>
+<if expr="chromeos and not _google_chrome">
+ <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
+</if>
+</translationbundle>
diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb
new file mode 100644
index 00000000000..7a500a9891c
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_am.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">አቃፊ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">ጨርስ</translation>
+<translation id="5341849548509163798">ከ<ph name="NUMBER_MANY"/> ሰዓቶች በፊት</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> ሴኮንድ ይቀራል</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> ሴኮንድ ይቀራል</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> ደቂቃ ይቀራል</translation>
+<translation id="1801827354178857021">ክፍለ ጊዜ</translation>
+<translation id="1190609913194133056">የማሳወቂያ ማዕከል</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> ደቂቃዎች ቀርተዋል</translation>
+<translation id="5613020302032141669">ግራ ቀስት</translation>
+<translation id="4971687151119236543">የሚዲያ ቀዳሚ ትራክ</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ፋይል(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918">ከ<ph name="NUMBER_ZERO"/> ደቂቃ በፊት</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> ሴኮንድ</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ሰዓቶች ይቀራሉ</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">ይቅር</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> ባ</translation>
+<translation id="3660179305079774227">የላይ ቀስት</translation>
+<translation id="3969863827134279083">ወደላይ አውጣ</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> ሁለተኛ ግራ</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> ሜባ/ሰ</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ሰዓት</translation>
+<translation id="3990502903496589789">የቀኝ ጠርዝ</translation>
+<translation id="9038489124413477075">ያልተሰየመ አቃፊ</translation>
+<translation id="1940483897317142625">ወደ የመስመር መጨረሻ ሰርዝ</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> ደቂቃ</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ቀኖች ይቀራሉ</translation>
+<translation id="932327136139879170">መነሻ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> ደቂቃ ይቀራል</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ቀኖች ይቀራሉ</translation>
+<translation id="6390842777729054533">ከ<ph name="NUMBER_ZERO"/> ሴኮንድ በፊት</translation>
+<translation id="3909791450649380159">&amp;ቁረጥ</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> ደቂቃዎች ቀርተዋል</translation>
+<translation id="688711909580084195">ርዕስ-አልባ ድረ-ገጽ</translation>
+<translation id="3353284378027041011">ከ<ph name="NUMBER_FEW"/> ቀኖች በፊት</translation>
+<translation id="5076340679995252485">&amp;ለጥፍ</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> ቴባ</translation>
+<translation id="7139614227326422685">ቃል ወደ ቀኝ ውሰድ</translation>
+<translation id="364720409959344976">የሚሰቀል ዓቃፊ ይምረጡ</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">ከ<ph name="NUMBER_TWO"/> ደቂቃ በፊት</translation>
+<translation id="3234408098842461169">ዝቅዝቅ ቀስት</translation>
+<translation id="3087734570205094154">ግርጌ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> ሰከንዶች ቀርተዋል</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> ደቂቃ ይቀራል</translation>
+<translation id="1860796786778352021">ማሳወቂያ ዝጋ</translation>
+<translation id="6364916375976753737">ወደ ግራ ሸብልል</translation>
+<translation id="2629089419211541119">ከ<ph name="NUMBER_ONE"/> ሰዓት በፊት</translation>
+<translation id="4218160142017529598">ወደኋላ ሰርዝ</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> ደቂቃዎች</translation>
+<translation id="6982279413068714821">ከ<ph name="NUMBER_DEFAULT"/> ደቂቃ በፊት</translation>
+<translation id="6945221475159498467">ይምረጡ</translation>
+<translation id="6620110761915583480">ፋይል አስቀምጥ</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ሰከንዶች</translation>
+<translation id="8924469368910458384">ወደ የመስመር መጀመሪያ ሰርዝ</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ሰዓት</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> ደቂቃ ቀርቷል</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> ደቂቃ</translation>
+<translation id="8210608804940886430">ወደታች አንቀሳቅስ</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ቀኖች</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ሰዓቶች ይቀራሉ</translation>
+<translation id="5329858601952122676">&amp;ሠርዝ</translation>
+<translation id="6556866813142980365">ድገም</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ሴኮንድ</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> ኪባ</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> ደቂቃዎች</translation>
+<translation id="7275974018215686543">ከ<ph name="NUMBER_MANY"/> ሴኮንድ በፊት</translation>
+<translation id="7781829728241885113">ትናንት</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> ደቂቃዎች</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> ደቂቃ ይቀራል</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> ሰከንዶች ቀርተዋል</translation>
+<translation id="6903282483217634857">ወደ ቀኝ ውሰድ</translation>
+<translation id="6659594942844771486">ትር</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> ሜባ</translation>
+<translation id="4988273303304146523">ከ<ph name="NUMBER_DEFAULT"/> ቀን በፊት</translation>
+<translation id="8428213095426709021">ቅንብሮች</translation>
+<translation id="2497284189126895209">ሁሉም ፋይሎች</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> ደቂቃዎች ቀርተዋል</translation>
+<translation id="5110450810124758964">ከ<ph name="NUMBER_ONE"/> ቀን በፊት</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ሴኮንድ</translation>
+<translation id="4320177379694898372">ምንም የበይነመረብ ግንኙነት የለም</translation>
+<translation id="7814458197256864873">&amp;ቅዳ</translation>
+<translation id="3889424535448813030">ቀኝ ቀስት</translation>
+<translation id="4229495110203539533">ከ<ph name="NUMBER_ONE"/> ሴኮንድ በፊት</translation>
+<translation id="2544782972264605588">ከ<ph name="NUMBER_DEFAULT"/> ሴኮንድ በፊት</translation>
+<translation id="6829324100069873704">ወደ ማሳወቂያዎች ተመለስ።</translation>
+<translation id="6528179044667508675">አትረብሽ</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ሰከንዶች</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> ደቂቃ</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> ሰዓት ይቀራል</translation>
+<translation id="7135556860107312402">ማሳወቂያዎች ከሚከተሉት እንዲመጡ ፍቀድ፦</translation>
+<translation id="2479520428668657293">ወደ ቀኝ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ሰዓቶች</translation>
+<translation id="1398853756734560583">አስፋ</translation>
+<translation id="4250229828105606438">ቅጽበታዊ ገጽ እይታ</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ሰዓቶች</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> ደቂቃ ይቀራል</translation>
+<translation id="2557207087669398617">ወደ የመስመር መጀመሪያ ውሰድ</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> ጊባ</translation>
+<translation id="1901303067676059328">&amp;ሁሉንም ምረጥ</translation>
+<translation id="2168039046890040389">ወደላይ አንቀሳቅስ</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> ደቂቃ</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ቀን</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> ደቂቃ</translation>
+<translation id="6122334925474904337">ቃል ወደ ቀኝ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> ደቂቃ</translation>
+<translation id="8448317557906454022">ከ<ph name="NUMBER_ZERO"/> ሴኮንድ በፊት</translation>
+<translation id="4927753642311223124">እዚህ ምንም የሚታይ ነገር የለም፣ ይቀጥሉ።</translation>
+<translation id="2482878487686419369">ማስታወቂያዎች</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> ቀን</translation>
+<translation id="3183922693828471536">ወደ እዚህ ሸብልል</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">ወደታች አውርድ</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ሰዓቶች</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> ኪባ/ሰ</translation>
+<translation id="8394908167088220973">ሚዲያ አጫውት/ለአፍታ አቁም</translation>
+<translation id="2148716181193084225">ዛሬ</translation>
+<translation id="7960078400008666149">ለአንድ ሰዓት አትረብሽ</translation>
+<translation id="4373894838514502496">ከ<ph name="NUMBER_FEW"/> ደቂቃ በፊት</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ቀኖች</translation>
+<translation id="2190355936436201913">(ባዶ)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ሰዓት ይቀራል</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ሴኮንድ ይቀራል</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">ወደ ቀኝ ሸብልል</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ሰዓት ይቀራል</translation>
+<translation id="1413622004203049571">ከ<ph name="NOTIFIER_NAME"/> የሚመጡ ማሳወቂያዎችን አሰናክል</translation>
+<translation id="2666092431469916601">ላይ</translation>
+<translation id="2538759511191347839">ወደ የመስመር መጨረሻ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="928465423150706909">ወደ የመስመር መጨረሻ ውሰድ</translation>
+<translation id="8331626408530291785">ወደ ላይ ሸብልል</translation>
+<translation id="7907591526440419938">ፋይል ክፈት</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> ቀን ይቀራል</translation>
+<translation id="2803313416453193357">አቃፊ ክፈት</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">ከ<ph name="NUMBER_DEFAULT"/> ሰዓት በፊት</translation>
+<translation id="815598010540052116">ወደ ታች ሸብልል</translation>
+<translation id="6808150112686056157">ሚዲያ አቁም</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> ደቂቃ ይቀራል</translation>
+<translation id="3157931365184549694">እነበረበት መልስ</translation>
+<translation id="5349525451964472598">ወደ ግራ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="1781701194097416995">ቃል ወደ ግራ ውሰድ</translation>
+<translation id="1243314992276662751">ስቀል</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ቀን ይቀራል</translation>
+<translation id="8179976553408161302">አስገባ</translation>
+<translation id="8471049483003785219">ቃል ወደ ግራ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="945522503751344254">ግብረ መልስ ላክ</translation>
+<translation id="9170848237812810038">&amp;ቀልብስ</translation>
+<translation id="1285266685456062655">ከ<ph name="NUMBER_FEW"/> ሰዓቶች በፊት</translation>
+<translation id="6918245111648057970">ከሚከተሉት ውስጥ ለእያንዳንዱ ተጠቃሚ ማሳወቂያዎችን ይፍቀዱ፦</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ሴኮንድ</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> ሰከንዶች ቀርተዋል</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> ደቂቃዎች ቀርተዋል</translation>
+<translation id="6358975074282722691">ከ<ph name="NUMBER_TWO"/> ሴኮንድ በፊት</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> ፔታ</translation>
+<translation id="2983818520079887040">ቅንብሮች ...</translation>
+<translation id="6845383723252244143">አቃፊ ምረጥ</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ሰከንዶች</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> ሰከንዶች ቀርተዋል</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ሴኮንድ</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">ከ<ph name="NUMBER_MANY"/> ቀኖች በፊት</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ቀኖች</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ሰዓት</translation>
+<translation id="2679312662830811292">ከ<ph name="NUMBER_ONE"/> ደቂቃ በፊት</translation>
+<translation id="8788572795284305350">ከ<ph name="NUMBER_ZERO"/> ሰዓት በፊት</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> ጊባ/ሰ</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ቀን</translation>
+<translation id="2704295676501803339">ወደ ግራ ውሰድ</translation>
+<translation id="9098468523912235228">ከ<ph name="NUMBER_DEFAULT"/> ሴኮንድ በፊት</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> ሴኮንድ ይቀራል</translation>
+<translation id="566737009157135450">ቃለል ወደኋላ ሰርዝ</translation>
+<translation id="436869212180315161">ተጫን</translation>
+<translation id="4860787810836767172">ከ<ph name="NUMBER_FEW"/> ሴኮንድ በፊት</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> ቴባ/ሰ</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> ደቂቃዎች</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> ደቂቃዎች ቀርተዋል</translation>
+<translation id="6040143037577758943">ዝጋ</translation>
+<translation id="1101671447232096497">ከ<ph name="NUMBER_MANY"/> ደቂቃ በፊት</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> ባ/ሰ</translation>
+<translation id="7649070708921625228">እገዛ</translation>
+<translation id="2405367043325750948">ወደፊት ሰርዝ</translation>
+<translation id="6699343763173986273">የሚዲያ ቀጣይ ትራክ</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> ሰከንዶች ቀርተዋል</translation>
+<translation id="8226233771743600312">ለአንድ ቀን አትረብሽ</translation>
+<translation id="4252565523989510616">ቃል ወደፊት ሰርዝ</translation>
+<translation id="7457942297256758195">ሁሉንም አጽዳ</translation>
+<translation id="822618367988303761">ከ<ph name="NUMBER_TWO"/> ቀኖች በፊት</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> ደቂቃ</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ቀን ይቀራል</translation>
+<translation id="6786750046913594791">አቃፊ ዝጋ</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> ደቂቃዎች</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ሰዓቶች ይቀራሉ</translation>
+<translation id="8959208747503200525">ከ<ph name="NUMBER_TWO"/> ሰዓቶች በፊት</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ሴኮንድ</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ሴኮንድ</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ሰከንዶች</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ቀን ይቀራል</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> ፔባ/ሰ</translation>
+<translation id="2743387203779672305">ወደ ቅንጥብ ሰሌዳ ገልብጥ</translation>
+<translation id="8371695176452482769">አሁን ይናገሩ</translation>
+<translation id="1167268268675672572">ወደ የመስመር መጀመሪያ ውሰድ እና ምርጫ ቀይር</translation>
+<translation id="6965382102122355670">ይሁን</translation>
+<translation id="7850320739366109486">አትረብሽ</translation>
+<translation id="6978839998405419496">ከ<ph name="NUMBER_ZERO"/> ቀን በፊት</translation>
+<translation id="5941711191222866238">አሳንስ</translation>
+<translation id="6394627529324717982">ኮማ</translation>
+<translation id="3036649622769666520">ፋይሎች ክፈት</translation>
+<translation id="8328145009876646418">የግራ ጠርዝ</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ሰከንዶች</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb
new file mode 100644
index 00000000000..f6c3b9ead4b
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ar.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+<translation id="4820616160060340806">‏المفتاح Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">مجلد <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">‏مفتاح Ins</translation>
+<translation id="6135826906199951471">‏مفتاح Del (حذف)</translation>
+<translation id="528468243742722775">‏مفتاح End</translation>
+<translation id="5341849548509163798">قبل <ph name="NUMBER_MANY"/> ساعة</translation>
+<translation id="6310545596129886942">عدد الثواني المتبقية <ph name="NUMBER_FEW"/></translation>
+<translation id="9213479837033539041">عدد الثواني المتبقية: <ph name="NUMBER_MANY"/></translation>
+<translation id="1209866192426315618">عدد الدقائق المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="1801827354178857021">الفترة</translation>
+<translation id="1190609913194133056">مركز الإشعارات</translation>
+<translation id="7470933019269157899">عدد الدقائق المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="5613020302032141669">مفتاح سهم إلى اليسار</translation>
+<translation id="4971687151119236543">المقطع الصوتي السابق للوسائط</translation>
+<translation id="8602707065186045623">ملف <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918">قبل <ph name="NUMBER_ZERO"/> دقيقة</translation>
+<translation id="7121570032414343252">عدد الثواني: <ph name="NUMBER_TWO"/></translation>
+<translation id="7511635910912978956">عدد الساعات المتبقية: <ph name="NUMBER_FEW"/></translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">إلغاء</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> بايت</translation>
+<translation id="3660179305079774227">مفتاح سهم إلى أعلى</translation>
+<translation id="3969863827134279083">تحريك لأعلى</translation>
+<translation id="7062130397825382308">يتبقى <ph name="NUMBER_ONE"/> ثانية</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> ميغابايات/ثانية</translation>
+<translation id="5608669887400696928">عدد الساعات: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3990502903496589789">الحافة اليسرى</translation>
+<translation id="9038489124413477075">مجلد بدون اسم</translation>
+<translation id="1940483897317142625">حذف إلى نهاية السطر</translation>
+<translation id="8507996248087185956">عدد الدقائق: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3520476450377425184">عدد الأيام المتبقيّة <ph name="NUMBER_MANY"/></translation>
+<translation id="932327136139879170">الصفحة الرئيسية</translation>
+<translation id="5600907569873192868">عدد الدقائق المتبقية: <ph name="NUMBER_MANY"/></translation>
+<translation id="8666066831007952346">عدد الأيام المتبقية <ph name="NUMBER_TWO"/></translation>
+<translation id="6390842777729054533">عدد الثواني المتبقية: <ph name="NUMBER_ZERO"/></translation>
+<translation id="3909791450649380159">&amp;قص</translation>
+<translation id="2560788951337264832">عدد الدقائق المتبقية: <ph name="NUMBER_ZERO"/></translation>
+<translation id="688711909580084195">صفحة ويب بدون عنوان</translation>
+<translation id="3353284378027041011">قبل <ph name="NUMBER_FEW"/> يوم</translation>
+<translation id="5076340679995252485">ل&amp;صق</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> تيرابايت</translation>
+<translation id="7139614227326422685">الانتقال كلمة يمينًا</translation>
+<translation id="364720409959344976">حدد مجلدًا للتحميل</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">قبل <ph name="NUMBER_TWO"/> دقيقة</translation>
+<translation id="3234408098842461169">مفتاح سهم إلى أسفل</translation>
+<translation id="3087734570205094154">أسفل</translation>
+<translation id="8828991073132329143">يتبقى <ph name="NUMBER_MANY"/> ثانية</translation>
+<translation id="5935630983280450497">عدد الدقائق المتبقية: <ph name="NUMBER_ONE"/></translation>
+<translation id="1860796786778352021">إغلاق الإشعار</translation>
+<translation id="6364916375976753737">التمرير إلى اليمين</translation>
+<translation id="2629089419211541119">قبل <ph name="NUMBER_ONE"/> ساعة</translation>
+<translation id="4218160142017529598">حذف للخلف</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> دقيقة</translation>
+<translation id="6982279413068714821">قبل <ph name="NUMBER_DEFAULT"/> دقيقة</translation>
+<translation id="6945221475159498467">تحديد</translation>
+<translation id="6620110761915583480">حفظ الملف</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> بلا ثوانٍ</translation>
+<translation id="8924469368910458384">حذف إلى بداية السطر</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ساعة</translation>
+<translation id="7836361698254323868">عدد الدقائق المتبقية: <ph name="NUMBER_ONE"/></translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> دقيقة</translation>
+<translation id="8210608804940886430">صفحة إلى أسفل</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> يومًا</translation>
+<translation id="7163503212501929773">عدد الساعات المتبقية: <ph name="NUMBER_MANY"/></translation>
+<translation id="5329858601952122676">&amp;حذف</translation>
+<translation id="6556866813142980365">إعادة</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ثانية</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> كيلوبايت</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> دقيقة</translation>
+<translation id="7275974018215686543">قبل <ph name="NUMBER_MANY"/> ثانية</translation>
+<translation id="7781829728241885113">أمس</translation>
+<translation id="3424538384153559412">دقيقتان (<ph name="NUMBER_TWO"/>)</translation>
+<translation id="50960180632766478">عدد الدقائق المتبقية: <ph name="NUMBER_FEW"/></translation>
+<translation id="5517291721709019259">يتبقى <ph name="NUMBER_FEW"/> ثواني</translation>
+<translation id="6903282483217634857">الانتقال يمينًا</translation>
+<translation id="6659594942844771486">علامة تبويب</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> ميغابايت</translation>
+<translation id="4988273303304146523">قبل <ph name="NUMBER_DEFAULT"/> يوم</translation>
+<translation id="8428213095426709021">الإعدادات</translation>
+<translation id="2497284189126895209">الملفّات كلّها</translation>
+<translation id="7487278341251176613">عدد الدقائق المتبقية: <ph name="NUMBER_TWO"/></translation>
+<translation id="5110450810124758964">قبل <ph name="NUMBER_ONE"/> يوم</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ثانية</translation>
+<translation id="4320177379694898372">لا يتوفر اتصال بالإنترنت</translation>
+<translation id="7814458197256864873">&amp;نسخ</translation>
+<translation id="3889424535448813030">مفتاح سهم إلى اليمين</translation>
+<translation id="4229495110203539533">قبل <ph name="NUMBER_ONE"/> ثانية</translation>
+<translation id="2544782972264605588">عدد الثواني المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6829324100069873704">الرجوع إلى الإشعارات</translation>
+<translation id="6528179044667508675">الرجاء عدم الإزعاج</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ثانية</translation>
+<translation id="290555789621781773">عدد الدقائق: <ph name="NUMBER_TWO"/></translation>
+<translation id="5149131957118398098">متبقٍ <ph name="NUMBER_ZERO"/> ساعة</translation>
+<translation id="7135556860107312402">السماح بالإشعارات من الجهات التالية:</translation>
+<translation id="2479520428668657293">الانتقال يمينًا وتعديل التحديد</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ساعات</translation>
+<translation id="1398853756734560583">تكبير</translation>
+<translation id="4250229828105606438">لقطة شاشة</translation>
+<translation id="6690744523875189208">عدد الساعات: <ph name="NUMBER_TWO"/></translation>
+<translation id="5260878308685146029">عدد الدقائق المتبقية: <ph name="NUMBER_TWO"/></translation>
+<translation id="2557207087669398617">الانتقال إلى بداية السطر</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> غيغابايت</translation>
+<translation id="1901303067676059328">تح&amp;ديد الكلّ</translation>
+<translation id="2168039046890040389">صفحة إلى أعلى</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> دقيقة</translation>
+<translation id="9107059250669762581">عدد الأيام <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> دقيقة</translation>
+<translation id="6122334925474904337">الانتقال كلمة يمينًا وتعديل التحديد</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> دقيقة واحدة</translation>
+<translation id="8448317557906454022">قبل <ph name="NUMBER_ZERO"/> ثانية</translation>
+<translation id="4927753642311223124">ليس هناك شيء تراه هنا، انتقل إلى مكان آخر.</translation>
+<translation id="2482878487686419369">الاشعارات</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> يوم</translation>
+<translation id="3183922693828471536">التمرير إلى هنا</translation>
+<translation id="4552416320897244156">‏مفتاح PgDwn (صفحة إلى أسفل)</translation>
+<translation id="3066573403916685335">الانتقال لأسفل</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ساعة</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> كيلوبايت/ثانية</translation>
+<translation id="8394908167088220973">تشغيل/إيقاف الوسائط</translation>
+<translation id="2148716181193084225">اليوم</translation>
+<translation id="7960078400008666149">الرجاء عدم الإزعاج لمدة ساعة واحدة</translation>
+<translation id="4373894838514502496">قبل <ph name="NUMBER_FEW"/> دقيقة</translation>
+<translation id="4115153316875436289">عدد الأيام: <ph name="NUMBER_TWO"/></translation>
+<translation id="2190355936436201913">(فارغ)</translation>
+<translation id="1164369517022005061">عدد الساعات المتبقية: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="152482086482215392">عدد الثواني المتبقية: <ph name="NUMBER_ONE"/></translation>
+<translation id="8447116497070723931">‏مفتاح PgUp (صفحة إلى أعلى)</translation>
+<translation id="4588090240171750605">التمرير إلى اليسار</translation>
+<translation id="7414887922320653780">عدد الساعات المتبقية: <ph name="NUMBER_ONE"/></translation>
+<translation id="1413622004203049571">تعطيل الإشعارات من <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">أعلى</translation>
+<translation id="2538759511191347839">الانتقال إلى نهاية السطر وتعديل التحديد</translation>
+<translation id="928465423150706909">الانتقال إلى نهاية السطر</translation>
+<translation id="8331626408530291785">التمرير إلى أعلى</translation>
+<translation id="7907591526440419938">فتح ملف</translation>
+<translation id="2864069933652346933">متبقٍ <ph name="NUMBER_ZERO"/> يوم</translation>
+<translation id="2803313416453193357">فتح المجلد</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">قبل <ph name="NUMBER_DEFAULT"/> ساعة</translation>
+<translation id="815598010540052116">التمرير إلى أسفل</translation>
+<translation id="6808150112686056157">إيقاف الوسائط</translation>
+<translation id="1308727876662951186">متبقٍ <ph name="NUMBER_ZERO"/> دقيقة</translation>
+<translation id="3157931365184549694">استعادة</translation>
+<translation id="5349525451964472598">الانتقال ي</translation>
+<translation id="1781701194097416995">الانتقال كلمة يسارًا</translation>
+<translation id="1243314992276662751">تحميل</translation>
+<translation id="50030952220075532">عدد الأيام المتبقية <ph name="NUMBER_ONE"/></translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">الانتقال كلمة يسارًا وتعديل التحديد</translation>
+<translation id="945522503751344254">إرسال تعليقات</translation>
+<translation id="9170848237812810038">&amp;إلغاء</translation>
+<translation id="1285266685456062655">قبل <ph name="NUMBER_FEW"/> ساعة</translation>
+<translation id="6918245111648057970">السماح بإشعارات مما يلي لكل مستخدم:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ثانية واحدة</translation>
+<translation id="1270251962578273213">يتبقى ثانيتان (<ph name="NUMBER_TWO"/>)</translation>
+<translation id="3994835489895548312">عدد الدقائق المتبقية: <ph name="NUMBER_MANY"/></translation>
+<translation id="6358975074282722691">قبل <ph name="NUMBER_TWO"/> ثانية</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> بيتابايت</translation>
+<translation id="2983818520079887040">الإعدادات...</translation>
+<translation id="6845383723252244143">تحديد مجلد</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ثوانٍ</translation>
+<translation id="5368780922436099921">يتبقى <ph name="NUMBER_ZERO"/> ثانية</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ثوانٍ</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">قبل <ph name="NUMBER_MANY"/> يوم</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> أيام</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ساعة</translation>
+<translation id="2679312662830811292">قبل <ph name="NUMBER_ONE"/> دقيقة</translation>
+<translation id="8788572795284305350">قبل <ph name="NUMBER_ZERO"/> ساعة</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> غيغابايت/ثانية</translation>
+<translation id="6644971472240498405">عدد الأيام <ph name="NUMBER_ONE"/></translation>
+<translation id="2704295676501803339">الانتقال يسارًا</translation>
+<translation id="9098468523912235228">قبل <ph name="NUMBER_DEFAULT"/> ثانية</translation>
+<translation id="494645311413743213">عدد الثواني المتبقية: <ph name="NUMBER_TWO"/></translation>
+<translation id="566737009157135450">حذف كلمة للخلف</translation>
+<translation id="436869212180315161">اضغط</translation>
+<translation id="4860787810836767172">قبل <ph name="NUMBER_FEW"/> ثانية</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> تيرابايت/ثانية</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> بلا دقائق</translation>
+<translation id="1858722859751911017">عدد الدقائق المتبقية: <ph name="NUMBER_FEW"/></translation>
+<translation id="6040143037577758943">إغلاق</translation>
+<translation id="1101671447232096497">قبل <ph name="NUMBER_MANY"/> دقيقة</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> بايت/ثانية</translation>
+<translation id="7649070708921625228">مساعدة</translation>
+<translation id="2405367043325750948">حذف للأمام</translation>
+<translation id="6699343763173986273">المقطع الصوتي التالي للوسائط</translation>
+<translation id="5445120697129764393">يتبقى <ph name="NUMBER_DEFAULT"/> ثانية</translation>
+<translation id="8226233771743600312">الرجاء عدم الإزعاج لمدة يوم واحد</translation>
+<translation id="4252565523989510616">حذف كلمة للأمام</translation>
+<translation id="7457942297256758195">محو الكل</translation>
+<translation id="822618367988303761">قبل <ph name="NUMBER_TWO"/> يوم</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> دقيقة</translation>
+<translation id="1963692530539281474">عدد الأيام المتبقية <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6786750046913594791">إغلاق المجلد</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> دقائق</translation>
+<translation id="5906719743126878045">عدد الساعات المتبقية: <ph name="NUMBER_TWO"/></translation>
+<translation id="8959208747503200525">قبل <ph name="NUMBER_TWO"/> ساعة</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> من الثواني</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ثانية</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ثانية</translation>
+<translation id="3759876923365568382">عدد الأيام المتبقية <ph name="NUMBER_FEW"/></translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> بيتابايت/ثانية</translation>
+<translation id="2743387203779672305">نسخ إلى الحافظة</translation>
+<translation id="8371695176452482769">تحدث الآن</translation>
+<translation id="1167268268675672572">الانتقال إلى بداية السطر وتعديل التحديد</translation>
+<translation id="6965382102122355670">موافق</translation>
+<translation id="7850320739366109486">الرجاء عدم الإزعاج</translation>
+<translation id="6978839998405419496">قبل <ph name="NUMBER_ZERO"/> يوم</translation>
+<translation id="5941711191222866238">تصغير</translation>
+<translation id="6394627529324717982">فاصلة</translation>
+<translation id="3036649622769666520">فتح الملفات</translation>
+<translation id="8328145009876646418">الحافة اليمنى</translation>
+<translation id="7372005818821648611">ثانيتان (<ph name="NUMBER_TWO"/>)</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb
new file mode 100644
index 00000000000..94b57988dff
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_bg.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Папка „<ph name="FOLDER_NAME"/>“</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798">преди <ph name="NUMBER_MANY"/> часа</translation>
+<translation id="6310545596129886942">Остават <ph name="NUMBER_FEW"/> сек</translation>
+<translation id="9213479837033539041">Остават <ph name="NUMBER_MANY"/> сек</translation>
+<translation id="1209866192426315618">Остават <ph name="NUMBER_DEFAULT"/> минути</translation>
+<translation id="1801827354178857021">Период</translation>
+<translation id="1190609913194133056">Център за известия</translation>
+<translation id="7470933019269157899">Остават <ph name="NUMBER_DEFAULT"/> минути</translation>
+<translation id="5613020302032141669">Стрелка наляво</translation>
+<translation id="4971687151119236543">Мултимедия, предишният запис</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> файл (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек</translation>
+<translation id="7511635910912978956">Остават <ph name="NUMBER_FEW"/> часа</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Отказ</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> Б</translation>
+<translation id="3660179305079774227">Стрелка нагоре</translation>
+<translation id="3969863827134279083">Преместване нагоре</translation>
+<translation id="7062130397825382308">Остава <ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> МБ/сек</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> часа</translation>
+<translation id="3990502903496589789">Десн край</translation>
+<translation id="9038489124413477075">Папка без име</translation>
+<translation id="1940483897317142625">Изтриване до края на реда</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин</translation>
+<translation id="3520476450377425184">Остават <ph name="NUMBER_MANY"/> дни</translation>
+<translation id="932327136139879170">Начална страница</translation>
+<translation id="5600907569873192868">Остават <ph name="NUMBER_MANY"/> мин</translation>
+<translation id="8666066831007952346">Остават <ph name="NUMBER_TWO"/> дни</translation>
+<translation id="6390842777729054533">Остават <ph name="NUMBER_ZERO"/> сек</translation>
+<translation id="3909791450649380159">Изрязва&amp;не</translation>
+<translation id="2560788951337264832">Остават <ph name="NUMBER_ZERO"/> минути</translation>
+<translation id="688711909580084195">Неозаглавена уеб страница</translation>
+<translation id="3353284378027041011">преди <ph name="NUMBER_FEW"/> дни</translation>
+<translation id="5076340679995252485">&amp;Поставяне</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> ТБ</translation>
+<translation id="7139614227326422685">Преместване надясно с една дума</translation>
+<translation id="364720409959344976">Избиране на папка за качване</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">преди <ph name="NUMBER_TWO"/> мин</translation>
+<translation id="3234408098842461169">Стрелка надолу</translation>
+<translation id="3087734570205094154">Най-долу</translation>
+<translation id="8828991073132329143">Остават <ph name="NUMBER_MANY"/> секунди</translation>
+<translation id="5935630983280450497">Остава <ph name="NUMBER_ONE"/> мин</translation>
+<translation id="1860796786778352021">Затваряне на известието</translation>
+<translation id="6364916375976753737">Превъртане наляво</translation>
+<translation id="2629089419211541119">преди <ph name="NUMBER_ONE"/> час/а</translation>
+<translation id="4218160142017529598">Изтриване назад</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> минути</translation>
+<translation id="6982279413068714821">преди <ph name="NUMBER_DEFAULT"/> мин</translation>
+<translation id="6945221475159498467">Изберете</translation>
+<translation id="6620110761915583480">Запазване на файл</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> секунди</translation>
+<translation id="8924469368910458384">Изтриване до началото на реда</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Остава <ph name="NUMBER_ONE"/> минута</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин</translation>
+<translation id="8210608804940886430">Страница надолу</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> дни</translation>
+<translation id="7163503212501929773">Остават <ph name="NUMBER_MANY"/> часа</translation>
+<translation id="5329858601952122676">&amp;Изтриване</translation>
+<translation id="6556866813142980365">Възстановяване</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KБ</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> минути</translation>
+<translation id="7275974018215686543">преди <ph name="NUMBER_MANY"/> сек</translation>
+<translation id="7781829728241885113">Вчера</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> минути</translation>
+<translation id="50960180632766478">Остават <ph name="NUMBER_FEW"/> мин</translation>
+<translation id="5517291721709019259">Остават <ph name="NUMBER_FEW"/> секунди</translation>
+<translation id="6903282483217634857">Преместване надясно</translation>
+<translation id="6659594942844771486">Раздел</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> МБ</translation>
+<translation id="4988273303304146523">преди <ph name="NUMBER_DEFAULT"/> дни</translation>
+<translation id="8428213095426709021">Настройки</translation>
+<translation id="2497284189126895209">Всички файлове</translation>
+<translation id="7487278341251176613">Остават <ph name="NUMBER_TWO"/> минути</translation>
+<translation id="5110450810124758964">преди <ph name="NUMBER_ONE"/> ден/дни</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек</translation>
+<translation id="4320177379694898372">Няма връзка с интернет</translation>
+<translation id="7814458197256864873">&amp;Копиране</translation>
+<translation id="3889424535448813030">Стрелка надясно</translation>
+<translation id="4229495110203539533">преди <ph name="NUMBER_ONE"/> сек</translation>
+<translation id="2544782972264605588">Остават <ph name="NUMBER_DEFAULT"/> сек</translation>
+<translation id="6829324100069873704">Назад към известията</translation>
+<translation id="6528179044667508675">Не безпокойте</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> секунди</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Разрешаване на известията от следните неща:</translation>
+<translation id="2479520428668657293">Преместване надясно и промяна на избраното</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> часа</translation>
+<translation id="1398853756734560583">Увеличаване</translation>
+<translation id="4250229828105606438">Eкранна снимка</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> часа</translation>
+<translation id="5260878308685146029">Остават <ph name="NUMBER_TWO"/> мин</translation>
+<translation id="2557207087669398617">Преместване до началото на реда</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> ГБ</translation>
+<translation id="1901303067676059328">&amp;Избиране на всички</translation>
+<translation id="2168039046890040389">Страница нагоре</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> дни</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин</translation>
+<translation id="6122334925474904337">Преместване надясно с една дума и промяна на избраното</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> минута</translation>
+<translation id="8448317557906454022">преди <ph name="NUMBER_ZERO"/> сек</translation>
+<translation id="4927753642311223124">Тук няма нищо, продължете нататък.</translation>
+<translation id="2482878487686419369">Известия</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Превъртане до тук</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Преместване надолу</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> часа</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> КБ/сек</translation>
+<translation id="8394908167088220973">Мултимедия, пускане/пауза</translation>
+<translation id="2148716181193084225">Днес</translation>
+<translation id="7960078400008666149">Не безпокойте за един час</translation>
+<translation id="4373894838514502496">преди <ph name="NUMBER_FEW"/> мин</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дни</translation>
+<translation id="2190355936436201913">(празно)</translation>
+<translation id="1164369517022005061">Остават <ph name="NUMBER_DEFAULT"/> часа</translation>
+<translation id="152482086482215392">Остава <ph name="NUMBER_ONE"/> сек</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Превъртане надясно</translation>
+<translation id="7414887922320653780">Остава <ph name="NUMBER_ONE"/> час</translation>
+<translation id="1413622004203049571">Деактивиране на известията от <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Най-горе</translation>
+<translation id="2538759511191347839">Преместване до края на реда и промяна на избраното</translation>
+<translation id="928465423150706909">Преместване до края на реда</translation>
+<translation id="8331626408530291785">Превъртане нагоре</translation>
+<translation id="7907591526440419938">Отваряне на файл</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Отваряне на папката</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">преди <ph name="NUMBER_DEFAULT"/> часа</translation>
+<translation id="815598010540052116">Превъртане надолу</translation>
+<translation id="6808150112686056157">Мултимедия, стоп</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Възстановяване</translation>
+<translation id="5349525451964472598">Преместване наляво и промяна на избраното</translation>
+<translation id="1781701194097416995">Преместване наляво с една дума</translation>
+<translation id="1243314992276662751">Качване</translation>
+<translation id="50030952220075532">Остава <ph name="NUMBER_ONE"/> ден</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Преместване наляво с една дума и промяна на избраното</translation>
+<translation id="945522503751344254">Изпращане на отзиви</translation>
+<translation id="9170848237812810038">&amp;Отмяна</translation>
+<translation id="1285266685456062655">преди <ph name="NUMBER_FEW"/> часа</translation>
+<translation id="6918245111648057970">Разрешаване на известията от следните неща за всеки потребител:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1270251962578273213">Остават <ph name="NUMBER_TWO"/> секунди</translation>
+<translation id="3994835489895548312">Остават <ph name="NUMBER_MANY"/> минути</translation>
+<translation id="6358975074282722691">преди <ph name="NUMBER_TWO"/> сек</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> ПБ</translation>
+<translation id="2983818520079887040">Настройки...</translation>
+<translation id="6845383723252244143">Избор на папка</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунди</translation>
+<translation id="5368780922436099921">Остават <ph name="NUMBER_ZERO"/> секунди</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">преди <ph name="NUMBER_MANY"/> дни</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> дни</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> час</translation>
+<translation id="2679312662830811292">преди <ph name="NUMBER_ONE"/> мин</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> ГБ/сек</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ден</translation>
+<translation id="2704295676501803339">Преместване наляво</translation>
+<translation id="9098468523912235228">преди <ph name="NUMBER_DEFAULT"/> сек</translation>
+<translation id="494645311413743213">Остават <ph name="NUMBER_TWO"/> сек</translation>
+<translation id="566737009157135450">Изтриване назад дума по дума</translation>
+<translation id="436869212180315161">Натиснете</translation>
+<translation id="4860787810836767172">преди <ph name="NUMBER_FEW"/> сек</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> ТБ/сек</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> минути</translation>
+<translation id="1858722859751911017">Остават <ph name="NUMBER_FEW"/> минути</translation>
+<translation id="6040143037577758943">Затваряне</translation>
+<translation id="1101671447232096497">преди <ph name="NUMBER_MANY"/> мин</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> Б/сек</translation>
+<translation id="7649070708921625228">Помощ</translation>
+<translation id="2405367043325750948">Изтриване напред</translation>
+<translation id="6699343763173986273">Мултимедия, следващият запис</translation>
+<translation id="5445120697129764393">Остават <ph name="NUMBER_DEFAULT"/> секунди</translation>
+<translation id="8226233771743600312">Не безпокойте за един ден</translation>
+<translation id="4252565523989510616">Изтриване напред дума по дума</translation>
+<translation id="7457942297256758195">Изчистване на всички</translation>
+<translation id="822618367988303761">преди <ph name="NUMBER_TWO"/> дни</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин</translation>
+<translation id="1963692530539281474">Остават <ph name="NUMBER_DEFAULT"/> дни</translation>
+<translation id="6786750046913594791">Затваряне на папката</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> минути</translation>
+<translation id="5906719743126878045">Остават <ph name="NUMBER_TWO"/> часа</translation>
+<translation id="8959208747503200525">преди <ph name="NUMBER_TWO"/> часа</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> секунди</translation>
+<translation id="3759876923365568382">Остават <ph name="NUMBER_FEW"/> дни</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> ПБ/сек</translation>
+<translation id="2743387203779672305">Копиране в буферната памет</translation>
+<translation id="8371695176452482769">Говорете сега</translation>
+<translation id="1167268268675672572">Преместване до началото на реда и промяна на избраното</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Не безпокойте</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Намаляване</translation>
+<translation id="6394627529324717982">Запетая</translation>
+<translation id="3036649622769666520">Отваряне на файлове</translation>
+<translation id="8328145009876646418">Ляв край</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> секунди</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb
new file mode 100644
index 00000000000..8f66271b293
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_bn.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bn">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> ফোল্ডার</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> সেকেন্ড বাকি</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> সেকেন্ড বাকি</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> মিনিট বাকি</translation>
+<translation id="1801827354178857021">পূর্ণচ্ছেদ</translation>
+<translation id="1190609913194133056">বিজ্ঞপ্তি কেন্দ্র</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> মিনিট বাকি</translation>
+<translation id="5613020302032141669">Left Arrow</translation>
+<translation id="4971687151119236543">মিডিয়া পূর্ববর্তী ট্র্যাক</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ফাইল (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> সেকেন্ড</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ঘন্টা বাকি</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">বাতিল</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Up Arrow</translation>
+<translation id="3969863827134279083">উপরে যান</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> সেকেন্ড বাকি</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ঘন্টা</translation>
+<translation id="3990502903496589789">ডান প্রান্ত</translation>
+<translation id="9038489124413477075">নামবিহীন ফোল্ডার</translation>
+<translation id="1940483897317142625">লাইনের শেষ পর্যন্ত মুছে ফেলুন</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> মিনিট</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> দিন বাকি</translation>
+<translation id="932327136139879170">হোম</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> মিনিট বাকি</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> দিন বাকি</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> সেকেন্ড বাকি</translation>
+<translation id="3909791450649380159">ছেদ&amp;ন</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> মিনিট বাকি</translation>
+<translation id="688711909580084195">শিরোনামহীন ওয়েবপৃষ্ঠা</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;প্রতিলেপন</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">ডানদিকে শব্দ সরান</translation>
+<translation id="364720409959344976">আপলোড করার জন্য ফোল্ডার নির্বাচন করুন</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Down Arrow</translation>
+<translation id="3087734570205094154">নীচে</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> সেকেন্ড বাকি</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> মিনিট বাকি</translation>
+<translation id="1860796786778352021">বিজ্ঞপ্তি বন্ধ করা হয়েছে</translation>
+<translation id="6364916375976753737">বাম দিকে স্ক্রোল করুন</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">পিছনের দিকে মুছুন</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> মিনিট</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> মিনিট আগে</translation>
+<translation id="6945221475159498467">নির্বাচন</translation>
+<translation id="6620110761915583480">ফাইল সংরক্ষণ করুন</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> সেকেন্ড</translation>
+<translation id="8924469368910458384">লাইনের শুরু পর্যন্ত মুছে ফেলুন</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> মিনিট বাকি</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> মিনিট</translation>
+<translation id="8210608804940886430">পৃষ্ঠা উপরে</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> দিন</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ঘন্টা বাকি</translation>
+<translation id="5329858601952122676">&amp;মুছুন</translation>
+<translation id="6556866813142980365">পুনরায় করুন</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> সেকেন্ড</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> মিনিট</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">গতকাল</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> মিনিট</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> মিনিট বাকি</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> সেকেন্ড বাকি</translation>
+<translation id="6903282483217634857">ডানদিকে সরান</translation>
+<translation id="6659594942844771486">ট্যাব</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> দিন আগে</translation>
+<translation id="8428213095426709021">সেটিংস</translation>
+<translation id="2497284189126895209">সকল ফাইল</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> মিনিট বাকি</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> সেকেন্ড</translation>
+<translation id="4320177379694898372">কোনো ইন্টারনেট সংযোগ নেই</translation>
+<translation id="7814458197256864873">&amp;অনুলিপি</translation>
+<translation id="3889424535448813030">Right Arrow</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> সেকেন্ড বাকি</translation>
+<translation id="6829324100069873704">বিজ্ঞপ্তিগুলিতে ফিরে যান</translation>
+<translation id="6528179044667508675">বিরক্ত করবেন না</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> সেকেন্ড</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> মিনিট</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">নিম্নলিখিত থেকে বিজ্ঞপ্তিগুলি মঞ্জুরি করুন:</translation>
+<translation id="2479520428668657293">ডানদিকে সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ঘন্টা</translation>
+<translation id="1398853756734560583">বড় করুন</translation>
+<translation id="4250229828105606438">স্ক্রীনশট</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ঘন্টা</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> মিনিট বাকি</translation>
+<translation id="2557207087669398617">লাইনের শুরু পর্যন্ত সরান</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;সকল নির্বাচন করুন</translation>
+<translation id="2168039046890040389">পৃষ্ঠা নীচে</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> দিন</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> মিনিট</translation>
+<translation id="6122334925474904337">শব্দকে ডানদিকে সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> মিনিট</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">এখানে দেখার কিছু নেই , এগিয়ে যান৷</translation>
+<translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">এখান পর্যন্ত স্ক্রোল করুন</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">নীচে যান</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ঘন্টা</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">মিডিয়া প্লে করুন/বিরতি</translation>
+<translation id="2148716181193084225">আজ</translation>
+<translation id="7960078400008666149">এক ঘন্টার জন্য বিরক্ত করবেন না</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> দিন</translation>
+<translation id="2190355936436201913">(খালি)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ঘন্টা বাকি</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> সেকেন্ড বাকি</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">ডান দিকে স্ক্রোল করুন</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ঘন্টা বাকি</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> এর থেকে বিজ্ঞপ্তিগুলি অক্ষম করুন</translation>
+<translation id="2666092431469916601">শীর্ষ</translation>
+<translation id="2538759511191347839">লাইনের শেষ অবধি সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="928465423150706909">লাইনের শেষ পর্যন্ত সরান</translation>
+<translation id="8331626408530291785">উপরে স্ক্রোল করুন</translation>
+<translation id="7907591526440419938">খোলা ফাইল</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">ফোল্ডার খুলুন</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ঘন্টা আগে</translation>
+<translation id="815598010540052116">নীচে স্ক্রোল করুন</translation>
+<translation id="6808150112686056157">মিডিয়া থামান</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">পুনরুদ্ধার করুন</translation>
+<translation id="5349525451964472598">বামদিকে সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="1781701194097416995">শব্দকে বামদিকে সরান</translation>
+<translation id="1243314992276662751">আপলোড</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> দিন বাকি</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">শব্দকে বামদিকে সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="945522503751344254">প্রতিক্রিয়া পাঠান</translation>
+<translation id="9170848237812810038">&amp;পূর্বাবস্থায় ফিরুন</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">প্রত্যেক ব্যবহারকারীর জন্য নিম্নলিখিত থেকে বিজ্ঞপ্তি মঞ্জুর করুন:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> সেকেন্ড</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> সেকেন্ড বাকি</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> মিনিট বাকি</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">সেটিংস...</translation>
+<translation id="6845383723252244143">ফোল্ডার নির্বাচন করুন</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> সেকেন্ড</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> সেকেন্ড বাকি</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> সেকেন্ড</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> দিন</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ঘন্টা</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> দিন</translation>
+<translation id="2704295676501803339">বামদিকে সরান</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> সেকেন্ড আগে</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> সেকেন্ড বাকি</translation>
+<translation id="566737009157135450">পিছনের দিকে শব্দকে মুছুন</translation>
+<translation id="436869212180315161">টিপুন</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> মিনিট</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> মিনিট বাকি</translation>
+<translation id="6040143037577758943">বন্ধ</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">সহায়তা</translation>
+<translation id="2405367043325750948">সামনের দিকে মুছুন</translation>
+<translation id="6699343763173986273">মিডিয়া পরবর্তী ট্র্যাক</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> সেকেন্ড বাকি</translation>
+<translation id="8226233771743600312">এক দিনের জন্য বিরক্ত করবেন না</translation>
+<translation id="4252565523989510616">শব্দকে সামনের দিকে মুছুন</translation>
+<translation id="7457942297256758195">সমস্ত সাফ করুন</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> মিনিট</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> দিন বাকি</translation>
+<translation id="6786750046913594791">ফোল্ডার বন্ধ করুন</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> মিনিট</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ঘন্টা বাকি</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> সেকেন্ড</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> সেকেন্ড</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> সেকেন্ড</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> দিন বাকি</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">ক্লিপবোর্ডে অনুলিপি করুন</translation>
+<translation id="8371695176452482769">এখনই বলুন</translation>
+<translation id="1167268268675672572">লাইনের শুরু পর্যন্ত সরান এবং নির্বাচন পরিবর্তন করুন</translation>
+<translation id="6965382102122355670">ওকে</translation>
+<translation id="7850320739366109486">বিরক্ত করবেন না</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">ছোট করুন</translation>
+<translation id="6394627529324717982">কমা</translation>
+<translation id="3036649622769666520">খোলা ফাইল</translation>
+<translation id="8328145009876646418">বাম প্রান্ত</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> সেকেন্ড</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb
new file mode 100644
index 00000000000..ea85bb1d7e4
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ca.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+<translation id="4820616160060340806">Ordre+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Supr</translation>
+<translation id="528468243742722775">Fi</translation>
+<translation id="5341849548509163798">Fa <ph name="NUMBER_MANY"/> hores</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> segons restants</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> segons restants</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuts restants</translation>
+<translation id="1801827354178857021">Punt</translation>
+<translation id="1190609913194133056">Centre de notificacions</translation>
+<translation id="7470933019269157899">Queden <ph name="NUMBER_DEFAULT"/> minuts</translation>
+<translation id="5613020302032141669">Fletxa esquerra</translation>
+<translation id="4971687151119236543">Fitxer multimèdia: pista anterior</translation>
+<translation id="8602707065186045623">Fitxer <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> segons</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hores restants</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancel·la</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Fletxa amunt</translation>
+<translation id="3969863827134279083">Mou cap amunt</translation>
+<translation id="7062130397825382308">Queda <ph name="NUMBER_ONE"/> segon.</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hores</translation>
+<translation id="3990502903496589789">Extrem dret</translation>
+<translation id="9038489124413477075">Carpeta sense nom</translation>
+<translation id="1940483897317142625">Suprimeix fins al final de la línia</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuts</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dies restants</translation>
+<translation id="932327136139879170">Pàgina d'inici</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuts restants</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dies restants</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> segons restants</translation>
+<translation id="3909791450649380159">Re&amp;talla</translation>
+<translation id="2560788951337264832">Queden <ph name="NUMBER_ZERO"/> minuts</translation>
+<translation id="688711909580084195">Pàgina web sense títol</translation>
+<translation id="3353284378027041011">Fa <ph name="NUMBER_FEW"/> dies</translation>
+<translation id="5076340679995252485">Engan&amp;xa</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mou la paraula a la dreta</translation>
+<translation id="364720409959344976">Selecció d'una carpeta per penjar</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Fa <ph name="NUMBER_TWO"/> minuts</translation>
+<translation id="3234408098842461169">Fletxa avall</translation>
+<translation id="3087734570205094154">Part inferior</translation>
+<translation id="8828991073132329143">Queden <ph name="NUMBER_MANY"/> segons</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut restant</translation>
+<translation id="1860796786778352021">Tanca la notificació</translation>
+<translation id="6364916375976753737">Desplaçament a l'esquerra</translation>
+<translation id="2629089419211541119">Fa <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="4218160142017529598">Suprimeix cap enrere</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuts</translation>
+<translation id="6982279413068714821">Fa <ph name="NUMBER_DEFAULT"/> minuts</translation>
+<translation id="6945221475159498467">Selecciona</translation>
+<translation id="6620110761915583480">Desa el fitxer</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segons</translation>
+<translation id="8924469368910458384">Suprimeix fins al començament de la línia</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Queda <ph name="NUMBER_ONE"/> minut</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8210608804940886430">Av Pàg</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dies</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hores restants</translation>
+<translation id="5329858601952122676">&amp;Suprimeix</translation>
+<translation id="6556866813142980365">Refés</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> segons</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minuts</translation>
+<translation id="7275974018215686543">Fa <ph name="NUMBER_MANY"/> segons</translation>
+<translation id="7781829728241885113">Ahir</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuts</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuts restants</translation>
+<translation id="5517291721709019259">Queden <ph name="NUMBER_FEW"/> segons</translation>
+<translation id="6903282483217634857">Mou a la dreta</translation>
+<translation id="6659594942844771486">Pestanya</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Fa <ph name="NUMBER_DEFAULT"/> dies</translation>
+<translation id="8428213095426709021">Configuració</translation>
+<translation id="2497284189126895209">Tots els fitxers</translation>
+<translation id="7487278341251176613">Queden <ph name="NUMBER_TWO"/> minuts</translation>
+<translation id="5110450810124758964">Fa <ph name="NUMBER_ONE"/> dia</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segon</translation>
+<translation id="4320177379694898372">No hi ha connexió a Internet</translation>
+<translation id="7814458197256864873">&amp;Copia</translation>
+<translation id="3889424535448813030">Fletxa dreta</translation>
+<translation id="4229495110203539533">Fa <ph name="NUMBER_ONE"/> segon</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> segons restants</translation>
+<translation id="6829324100069873704">Torna a les notificacions</translation>
+<translation id="6528179044667508675">No molesteu</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segons</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuts</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Permet notificacions de les fonts següents:</translation>
+<translation id="2479520428668657293">Mou a la dreta i modifica la selecció</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hores</translation>
+<translation id="1398853756734560583">Maximitza</translation>
+<translation id="4250229828105606438">Captura de pantalla</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hores</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuts restants</translation>
+<translation id="2557207087669398617">Mou al començament de la línia</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Selecciona-ho &amp;tot</translation>
+<translation id="2168039046890040389">Re Pàg</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dies</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuts</translation>
+<translation id="6122334925474904337">Mou la paraula a la dreta i modifica la selecció</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8448317557906454022">Fa <ph name="NUMBER_ZERO"/> segons</translation>
+<translation id="4927753642311223124">No hi ha cap notificació, podeu continuar.</translation>
+<translation id="2482878487686419369">Notificacions</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Desplaçament fins aquí</translation>
+<translation id="4552416320897244156">Av Pàg</translation>
+<translation id="3066573403916685335">Mou cap avall</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hores</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Fitxer multimèdia: reprodueix/posa en pausa</translation>
+<translation id="2148716181193084225">Avui</translation>
+<translation id="7960078400008666149">No molesteu durant una hora</translation>
+<translation id="4373894838514502496">Fa <ph name="NUMBER_FEW"/> minuts</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dies</translation>
+<translation id="2190355936436201913">(buit)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hores restants</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> segon restant</translation>
+<translation id="8447116497070723931">Re Pàg</translation>
+<translation id="4588090240171750605">Desplaçament a la dreta</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hores restants</translation>
+<translation id="1413622004203049571">Desactiva les notificacions de <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Superior</translation>
+<translation id="2538759511191347839">Mou al final de la línia i modifica la selecció</translation>
+<translation id="928465423150706909">Mou al final de la línia</translation>
+<translation id="8331626408530291785">Desplaçament amunt</translation>
+<translation id="7907591526440419938">Obre un fitxer</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Obre la carpeta</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Fa <ph name="NUMBER_DEFAULT"/> hores</translation>
+<translation id="815598010540052116">Desplaçament avall</translation>
+<translation id="6808150112686056157">Fitxer multimèdia: atura</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaura</translation>
+<translation id="5349525451964472598">Mou a l'esquerra i modifica la selecció</translation>
+<translation id="1781701194097416995">Mou la paraula a l'esquerra</translation>
+<translation id="1243314992276662751">Penja</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restant</translation>
+<translation id="8179976553408161302">Retorn</translation>
+<translation id="8471049483003785219">Mou la paraula a l'esquerra i modifica la selecció</translation>
+<translation id="945522503751344254">Envia comentaris</translation>
+<translation id="9170848237812810038">&amp;Desfés</translation>
+<translation id="1285266685456062655">Fa <ph name="NUMBER_FEW"/> hores</translation>
+<translation id="6918245111648057970">Permet les notificacions de les opcions següents per a cada usuari:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segon</translation>
+<translation id="1270251962578273213">Queden <ph name="NUMBER_TWO"/> segons</translation>
+<translation id="3994835489895548312">Queden <ph name="NUMBER_MANY"/> minuts</translation>
+<translation id="6358975074282722691">Fa <ph name="NUMBER_TWO"/> segons</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Configuració...</translation>
+<translation id="6845383723252244143">Selecció d'una carpeta</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segons</translation>
+<translation id="5368780922436099921">Queden <ph name="NUMBER_ZERO"/> segons</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> segons</translation>
+<translation id="5583640892426849032">Retrocés</translation>
+<translation id="5263972071113911534">Fa <ph name="NUMBER_MANY"/> dies</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dies</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
+<translation id="2679312662830811292">Fa <ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
+<translation id="2704295676501803339">Mou a l'esquerra</translation>
+<translation id="9098468523912235228">Fa <ph name="NUMBER_DEFAULT"/> segons</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> segons restants</translation>
+<translation id="566737009157135450">Suprimeix la paraula cap enrere</translation>
+<translation id="436869212180315161">Prem</translation>
+<translation id="4860787810836767172">Fa <ph name="NUMBER_FEW"/> segons</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuts</translation>
+<translation id="1858722859751911017">Queden <ph name="NUMBER_FEW"/> minuts</translation>
+<translation id="6040143037577758943">Tanca</translation>
+<translation id="1101671447232096497">Fa <ph name="NUMBER_MANY"/> minuts</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ajuda</translation>
+<translation id="2405367043325750948">Suprimeix cap endavant</translation>
+<translation id="6699343763173986273">Fitxer multimèdia: pista següent</translation>
+<translation id="5445120697129764393">Queden <ph name="NUMBER_DEFAULT"/> segons.</translation>
+<translation id="8226233771743600312">No molesteu durant un dia</translation>
+<translation id="4252565523989510616">Suprimeix la paraula cap endavant</translation>
+<translation id="7457942297256758195">Esborra-ho tot</translation>
+<translation id="822618367988303761">Fa <ph name="NUMBER_TWO"/> dies</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuts</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dies restants</translation>
+<translation id="6786750046913594791">Tanca la carpeta</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuts</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hores restants</translation>
+<translation id="8959208747503200525">Fa <ph name="NUMBER_TWO"/> hores</translation>
+<translation id="8400147561352026160">Maj+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> segons</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> segons</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segons</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dies restants</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copia al porta-retalls</translation>
+<translation id="8371695176452482769">Parleu ara</translation>
+<translation id="1167268268675672572">Mou al començament de la línia i modifica la selecció</translation>
+<translation id="6965382102122355670">D'acord</translation>
+<translation id="7850320739366109486">No molesteu</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimitza</translation>
+<translation id="6394627529324717982">Coma</translation>
+<translation id="3036649622769666520">Obre fitxers</translation>
+<translation id="8328145009876646418">Extrem esquerre</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segons</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb
new file mode 100644
index 00000000000..047d6b9db81
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_cs.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+<translation id="4820616160060340806">Příkaz + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Složka <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Klávesa Ins</translation>
+<translation id="6135826906199951471">Klávesa Del</translation>
+<translation id="528468243742722775">Klávesa End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942">Zbývá: <ph name="NUMBER_FEW"/> s</translation>
+<translation id="9213479837033539041">Zbývá: <ph name="NUMBER_MANY"/> s</translation>
+<translation id="1209866192426315618">Zbývá: <ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="1801827354178857021">Období</translation>
+<translation id="1190609913194133056">Centrum oznámení</translation>
+<translation id="7470933019269157899">Zbývá <ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="5613020302032141669">Klávesa šipka vlevo</translation>
+<translation id="4971687151119236543">Média – předchozí skladba</translation>
+<translation id="8602707065186045623">Soubor <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
+<translation id="7511635910912978956">Zbývá: <ph name="NUMBER_FEW"/> hod</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Zrušit</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Klávesa šipka nahoru</translation>
+<translation id="3969863827134279083">Přesunout nahoru</translation>
+<translation id="7062130397825382308">Zbývá <ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hod</translation>
+<translation id="3990502903496589789">Pravý okraj</translation>
+<translation id="9038489124413477075">Nepojmenovaná složka</translation>
+<translation id="1940483897317142625">Smazat do konce řádku</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minut</translation>
+<translation id="3520476450377425184">Zbývá: <ph name="NUMBER_MANY"/> dnů</translation>
+<translation id="932327136139879170">Domovská stránka</translation>
+<translation id="5600907569873192868">Zbývá: <ph name="NUMBER_MANY"/> min</translation>
+<translation id="8666066831007952346">Zbývá: <ph name="NUMBER_TWO"/> dny</translation>
+<translation id="6390842777729054533">Zbývá: <ph name="NUMBER_ZERO"/> s</translation>
+<translation id="3909791450649380159">Vyjmou&amp;t</translation>
+<translation id="2560788951337264832">Zbývá <ph name="NUMBER_ZERO"/> minut</translation>
+<translation id="688711909580084195">Nepojmenovaná webová stránka</translation>
+<translation id="3353284378027041011">Před <ph name="NUMBER_FEW"/> dny</translation>
+<translation id="5076340679995252485">Vložit</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Přesunout slovo doprava</translation>
+<translation id="364720409959344976">Vyberte složku pro nahrávání</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Klávesa šipka dolů</translation>
+<translation id="3087734570205094154">Až dolů</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">Zbývá: <ph name="NUMBER_ONE"/> min</translation>
+<translation id="1860796786778352021">Zavřít oznámení</translation>
+<translation id="6364916375976753737">Posuv doleva</translation>
+<translation id="2629089419211541119">Před <ph name="NUMBER_ONE"/> hodinou</translation>
+<translation id="4218160142017529598">Smazat zpět</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="6982279413068714821">před <ph name="NUMBER_DEFAULT"/> minutami</translation>
+<translation id="6945221475159498467">Vybrat</translation>
+<translation id="6620110761915583480">Uložit soubor</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> s</translation>
+<translation id="8924469368910458384">Smazat k začátku řádku</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Zbývá <ph name="NUMBER_ONE"/> minuta</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Klávesa PageDown</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dnů</translation>
+<translation id="7163503212501929773">Zbývá: <ph name="NUMBER_MANY"/> hod</translation>
+<translation id="5329858601952122676">&amp;Smazat</translation>
+<translation id="6556866813142980365">Opakovat</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> min</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Včera</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> min</translation>
+<translation id="50960180632766478">Zbývá: <ph name="NUMBER_FEW"/> min</translation>
+<translation id="5517291721709019259">Zbývají <ph name="NUMBER_FEW"/> sekundy</translation>
+<translation id="6903282483217634857">Přesunout doprava</translation>
+<translation id="6659594942844771486">Karta</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Před <ph name="NUMBER_DEFAULT"/> dny</translation>
+<translation id="8428213095426709021">Nastavení</translation>
+<translation id="2497284189126895209">Všechny soubory</translation>
+<translation id="7487278341251176613">Zbývají <ph name="NUMBER_TWO"/> minuty</translation>
+<translation id="5110450810124758964">Před <ph name="NUMBER_ONE"/> dnem</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
+<translation id="4320177379694898372">Žádné připojení k internetu</translation>
+<translation id="7814458197256864873">&amp;Kopírovat</translation>
+<translation id="3889424535448813030">Klávesa šipka vpravo</translation>
+<translation id="4229495110203539533">Před <ph name="NUMBER_ONE"/> sekundou</translation>
+<translation id="2544782972264605588">Zbývá: <ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="6829324100069873704">Přejít zpět k oznámením</translation>
+<translation id="6528179044667508675">Nerušit</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Povolit oznámení z následujících zdrojů:</translation>
+<translation id="2479520428668657293">Přesunout doprava a změnit výběr</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hod</translation>
+<translation id="1398853756734560583">Maximalizovat</translation>
+<translation id="4250229828105606438">Snímek obrazovky</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hod</translation>
+<translation id="5260878308685146029">Zbývá: <ph name="NUMBER_TWO"/> min</translation>
+<translation id="2557207087669398617">Přesunout na začátek řádku</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;Vybrat vše</translation>
+<translation id="2168039046890040389">Klávesa PageUp</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dnů</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min</translation>
+<translation id="6122334925474904337">Přesunout slovo doprava a změnit výběr</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Tady není nic k vidění, rozejděte se.</translation>
+<translation id="2482878487686419369">Oznámení</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Posunout sem</translation>
+<translation id="4552416320897244156">Klávesa PgDwn</translation>
+<translation id="3066573403916685335">Posunout dolů</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hod</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Média – přehrát/pozastavit</translation>
+<translation id="2148716181193084225">Dnes</translation>
+<translation id="7960078400008666149">Nerušit jednu hodinu</translation>
+<translation id="4373894838514502496">před <ph name="NUMBER_FEW"/> minutami</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dnů</translation>
+<translation id="2190355936436201913">(prázdné)</translation>
+<translation id="1164369517022005061">Zbývá: <ph name="NUMBER_DEFAULT"/> hod</translation>
+<translation id="152482086482215392">Zbývá: <ph name="NUMBER_ONE"/> s</translation>
+<translation id="8447116497070723931">Klávesa PgUp</translation>
+<translation id="4588090240171750605">Posuv doprava</translation>
+<translation id="7414887922320653780">Zbývá: <ph name="NUMBER_ONE"/> hod</translation>
+<translation id="1413622004203049571">Deaktivovat oznámení ze služby <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Nahoru</translation>
+<translation id="2538759511191347839">Přesunout na konec řádku a změnit výběr</translation>
+<translation id="928465423150706909">Přesunout na konec řádku</translation>
+<translation id="8331626408530291785">Posuv nahoru</translation>
+<translation id="7907591526440419938">Otevřít soubor</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Otevřít složku</translation>
+<translation id="1293699935367580298">Klávesa Esc</translation>
+<translation id="2797524280730715045">Před <ph name="NUMBER_DEFAULT"/> hodinami</translation>
+<translation id="815598010540052116">Posuv dolů</translation>
+<translation id="6808150112686056157">Média – zastavit</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Obnovit</translation>
+<translation id="5349525451964472598">Přesunout doleva a upravit výběr</translation>
+<translation id="1781701194097416995">Přesunout slovo doleva</translation>
+<translation id="1243314992276662751">Nahrát</translation>
+<translation id="50030952220075532">Zbývá: <ph name="NUMBER_ONE"/> den</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Přesunout slovo doleva a upravit výběr</translation>
+<translation id="945522503751344254">Odeslat zpětnou vazbu</translation>
+<translation id="9170848237812810038">Z&amp;pět</translation>
+<translation id="1285266685456062655">Před <ph name="NUMBER_FEW"/> hodinami</translation>
+<translation id="6918245111648057970">Povolit oznámení z následujících zdrojů pro všechny uživatele:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> s</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">Zbývá <ph name="NUMBER_MANY"/> minut</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Nastavení...</translation>
+<translation id="6845383723252244143">Vybrat složku</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> s</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dnů</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hod</translation>
+<translation id="2679312662830811292">Před <ph name="NUMBER_ONE"/> minutou</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> den</translation>
+<translation id="2704295676501803339">Přesunout doleva</translation>
+<translation id="9098468523912235228">Před <ph name="NUMBER_DEFAULT"/> sekundami</translation>
+<translation id="494645311413743213">Zbývá: <ph name="NUMBER_TWO"/> s</translation>
+<translation id="566737009157135450">Smazat slovo zpět</translation>
+<translation id="436869212180315161">Tisk</translation>
+<translation id="4860787810836767172">Před <ph name="NUMBER_FEW"/> sekundami</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> min</translation>
+<translation id="1858722859751911017">Zbývají <ph name="NUMBER_FEW"/> minuty</translation>
+<translation id="6040143037577758943">Zavřít</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Nápověda</translation>
+<translation id="2405367043325750948">Smazat vpřed</translation>
+<translation id="6699343763173986273">Média – další skladba</translation>
+<translation id="5445120697129764393">Zbývá <ph name="NUMBER_DEFAULT"/> sekund</translation>
+<translation id="8226233771743600312">Nerušit jeden den</translation>
+<translation id="4252565523989510616">Smazat slovo vpřed</translation>
+<translation id="7457942297256758195">Vymazat vše</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
+<translation id="1963692530539281474">Zbývá: <ph name="NUMBER_DEFAULT"/> dnů</translation>
+<translation id="6786750046913594791">Zavřít složku</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> min</translation>
+<translation id="5906719743126878045">Zbývá: <ph name="NUMBER_TWO"/> hod</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> s</translation>
+<translation id="3759876923365568382">Zbývá: <ph name="NUMBER_FEW"/> dnů</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Zkopírovat do schránky</translation>
+<translation id="8371695176452482769">Mluvte</translation>
+<translation id="1167268268675672572">Přesunout na začátek řádku a upravit výběr</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Nerušit</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimalizovat</translation>
+<translation id="6394627529324717982">Čárka</translation>
+<translation id="3036649622769666520">Otevřít soubory</translation>
+<translation id="8328145009876646418">Levý okraj</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> s</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb
new file mode 100644
index 00000000000..e9291312567
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_da.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+<translation id="4820616160060340806">Kommando+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> timer siden</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sek. tilbage</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sek. tilbage</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutter tilbage</translation>
+<translation id="1801827354178857021">Periode</translation>
+<translation id="1190609913194133056">Underretningcenter</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutter tilbage</translation>
+<translation id="5613020302032141669">Venstrepil</translation>
+<translation id="4971687151119236543">Medie: Forrige nummer</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek.</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timer tilbage</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Annuller</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Pil opad</translation>
+<translation id="3969863827134279083">Flyt op</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> sekund tilbage</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sek.</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timer</translation>
+<translation id="3990502903496589789">Højre kant</translation>
+<translation id="9038489124413477075">Unavngiven mappe</translation>
+<translation id="1940483897317142625">Slet til slutningen af linjen</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutter</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dage tilbage</translation>
+<translation id="932327136139879170">Start</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutter tilbage</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dage tilbage</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sek. tilbage</translation>
+<translation id="3909791450649380159">Kli&amp;p</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutter tilbage</translation>
+<translation id="688711909580084195">Ikke-navngivet webside</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dage siden</translation>
+<translation id="5076340679995252485">&amp;Indsæt</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Flyt til højre efter ordet</translation>
+<translation id="364720409959344976">Vælg den mappe, der skal uploades</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minutter siden</translation>
+<translation id="3234408098842461169">Pil nedad</translation>
+<translation id="3087734570205094154">Bund</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> sekunder tilbage</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutter tilbage</translation>
+<translation id="1860796786778352021">Luk underretning</translation>
+<translation id="6364916375976753737">Scroll Left</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> time siden</translation>
+<translation id="4218160142017529598">Slet bagud</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutter</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutter siden</translation>
+<translation id="6945221475159498467">Vælg</translation>
+<translation id="6620110761915583480">Gem fil</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
+<translation id="8924469368910458384">Slet til begyndelsen af linjen</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut tilbage</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8210608804940886430">Side ned</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dage</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timer tilbage</translation>
+<translation id="5329858601952122676">&amp;Slet</translation>
+<translation id="6556866813142980365">Gør det igen</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sek.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutter</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> sekunder siden</translation>
+<translation id="7781829728241885113">I går</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutter</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutter tilbage</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> sekunder tilbage</translation>
+<translation id="6903282483217634857">Flyt til højre</translation>
+<translation id="6659594942844771486">Fane</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dage siden</translation>
+<translation id="8428213095426709021">Indstillinger</translation>
+<translation id="2497284189126895209">Alle filer</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutter tilbage</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dag siden</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek.</translation>
+<translation id="4320177379694898372">Ingen internetforbindelse</translation>
+<translation id="7814458197256864873">&amp;Kopier</translation>
+<translation id="3889424535448813030">Højrepil</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekund siden</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sek. tilbage</translation>
+<translation id="6829324100069873704">Gå tilbage til underretninger</translation>
+<translation id="6528179044667508675">Vil ikke forstyrres</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutter</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Tillad underretninger fra følgende:</translation>
+<translation id="2479520428668657293">Flyt til højre, og rediger markering</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timer</translation>
+<translation id="1398853756734560583">Maksimér</translation>
+<translation id="4250229828105606438">Skærmbillede</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timer</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutter tilbage</translation>
+<translation id="2557207087669398617">Flyt til begyndelsen af linjen</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Vælg &amp;alle</translation>
+<translation id="2168039046890040389">Side op</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dage</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutter</translation>
+<translation id="6122334925474904337">Flyt ordet til højre, og rediger markering</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> sekunder siden</translation>
+<translation id="4927753642311223124">Der er intet at se her, så du kan bare gå videre.</translation>
+<translation id="2482878487686419369">Underretninger</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Scroll hertil</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Flyt ned</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timer</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/sek.</translation>
+<translation id="8394908167088220973">Medie: Afspil/Pause</translation>
+<translation id="2148716181193084225">I dag</translation>
+<translation id="7960078400008666149">Vil ikke forstyrres i en time</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minutter siden</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dage</translation>
+<translation id="2190355936436201913">(tom)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timer tilbage</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sek. tilbage</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Scroll til højre</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> timer tilbage</translation>
+<translation id="1413622004203049571">Deaktiver underretninger fra <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Top</translation>
+<translation id="2538759511191347839">Flyt til slutningen af ​​linjen, og rediger markering</translation>
+<translation id="928465423150706909">Flyt til slutningen af ​​linjen</translation>
+<translation id="8331626408530291785">Scroll Up</translation>
+<translation id="7907591526440419938">Åbn fil</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Åbn mappe</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> timer siden</translation>
+<translation id="815598010540052116">Scroll Down</translation>
+<translation id="6808150112686056157">Medie: Stop</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Gendan</translation>
+<translation id="5349525451964472598">Flyt til venstre, og rediger markering</translation>
+<translation id="1781701194097416995">Flyt til venstre efter ordet</translation>
+<translation id="1243314992276662751">Upload</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dage tilbage</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Flyt ord til venstre, og rediger markering</translation>
+<translation id="945522503751344254">Send feedback</translation>
+<translation id="9170848237812810038">&amp;Fortryd</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> timer siden</translation>
+<translation id="6918245111648057970">Tillad underretninger fra følgende for hver bruger:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> sekunder tilbage</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutter tilbage</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> sekunder siden</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Indstillinger...</translation>
+<translation id="6845383723252244143">Vælg mappe</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> sekunder tilbage</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek.</translation>
+<translation id="5583640892426849032">Returtast</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> dage siden</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dage</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> time</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minut siden</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sek.</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>dag</translation>
+<translation id="2704295676501803339">Flyt til vestre</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekunder siden</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sek. tilbage</translation>
+<translation id="566737009157135450">Slet baglæns med et ord</translation>
+<translation id="436869212180315161">Tryk</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> sekunder siden</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sek.</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutter</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutter tilbage</translation>
+<translation id="6040143037577758943">Luk</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minutter siden</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sek.</translation>
+<translation id="7649070708921625228">Hjælp</translation>
+<translation id="2405367043325750948">Slet fremad</translation>
+<translation id="6699343763173986273">Medie: Næste nummer</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> sekunder tilbage</translation>
+<translation id="8226233771743600312">Vil ikke forstyrres i et døgn</translation>
+<translation id="4252565523989510616">Slet fremad med et ord</translation>
+<translation id="7457942297256758195">Ryd alle</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dage siden</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutter</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dage tilbage</translation>
+<translation id="6786750046913594791">Luk mappe</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutter</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timer tilbage</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> timer siden</translation>
+<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sek.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dage tilbage</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sek.</translation>
+<translation id="2743387203779672305">Kopiér til udklipsholderen</translation>
+<translation id="8371695176452482769">Indtal nu</translation>
+<translation id="1167268268675672572">Flyt til begyndelsen af linjen, og rediger markering</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Vil ikke forstyrres</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimer</translation>
+<translation id="6394627529324717982">Komma</translation>
+<translation id="3036649622769666520">Åbn filer</translation>
+<translation id="8328145009876646418">Venstre kant</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb
new file mode 100644
index 00000000000..e3069aa1430
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_de.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+<translation id="4820616160060340806">Befehltaste+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Ordner <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Einfg</translation>
+<translation id="6135826906199951471">Entf</translation>
+<translation id="528468243742722775">Ende</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> Sekunden übrig</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> Sekunden übrig</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> Minuten übrig</translation>
+<translation id="1801827354178857021">Zeitraum</translation>
+<translation id="1190609913194133056">Benachrichtigungscenter</translation>
+<translation id="7470933019269157899">Noch <ph name="NUMBER_DEFAULT"/> Minuten</translation>
+<translation id="5613020302032141669">Linkspfeil</translation>
+<translation id="4971687151119236543">Medien – vorheriger Titel</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-Datei (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> Sekunden</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> Stunden übrig</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Abbrechen</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Aufwärtspfeil</translation>
+<translation id="3969863827134279083">Nach oben</translation>
+<translation id="7062130397825382308">Noch <ph name="NUMBER_ONE"/> Sekunde</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> Stunden</translation>
+<translation id="3990502903496589789">Rechter Rand</translation>
+<translation id="9038489124413477075">Unbenannter Ordner</translation>
+<translation id="1940483897317142625">Bis zum Zeilenende löschen</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> Minuten</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> Tage übrig</translation>
+<translation id="932327136139879170">Privat</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> Minuten übrig</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> Tage übrig</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> Sekunden übrig</translation>
+<translation id="3909791450649380159">&amp;Ausschneiden</translation>
+<translation id="2560788951337264832">Noch <ph name="NUMBER_ZERO"/> Minuten</translation>
+<translation id="688711909580084195">Unbenannte Webseite</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Einfügen</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Ein Wort nach rechts</translation>
+<translation id="364720409959344976">Ordner zum Hochladen auswählen</translation>
+<translation id="4999762576397546063">Strg+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Abwärtspfeil</translation>
+<translation id="3087734570205094154">Unten</translation>
+<translation id="8828991073132329143">Noch <ph name="NUMBER_MANY"/> Sekunden</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> Minute übrig</translation>
+<translation id="1860796786778352021">Benachrichtigung schließen</translation>
+<translation id="6364916375976753737">Nach links blättern</translation>
+<translation id="2629089419211541119">Vor <ph name="NUMBER_ONE"/> Stunde</translation>
+<translation id="4218160142017529598">Letztes Zeichen löschen</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> Minuten</translation>
+<translation id="6982279413068714821">Vor <ph name="NUMBER_DEFAULT"/> Minuten</translation>
+<translation id="6945221475159498467">Auswählen</translation>
+<translation id="6620110761915583480">Datei speichern</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> Sekunden</translation>
+<translation id="8924469368910458384">Bis zum Zeilenanfang löschen</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Noch <ph name="NUMBER_ONE"/> Minute</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> Minute</translation>
+<translation id="8210608804940886430">Nach unten</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> Tage</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> Stunden übrig</translation>
+<translation id="5329858601952122676">&amp;Löschen</translation>
+<translation id="6556866813142980365">Wiederholen</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> Sekunden</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> Minuten</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Gestern</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> Minuten</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> Minuten übrig</translation>
+<translation id="5517291721709019259">Noch <ph name="NUMBER_FEW"/> Sekunden</translation>
+<translation id="6903282483217634857">Nach rechts</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Vor <ph name="NUMBER_DEFAULT"/> Tagen</translation>
+<translation id="8428213095426709021">Einstellungen</translation>
+<translation id="2497284189126895209">Alle Dateien</translation>
+<translation id="7487278341251176613">Noch <ph name="NUMBER_TWO"/> Minuten</translation>
+<translation id="5110450810124758964">Vor <ph name="NUMBER_ONE"/> Tag</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> Sekunde</translation>
+<translation id="4320177379694898372">Keine Internetverbindung</translation>
+<translation id="7814458197256864873">&amp;Kopieren</translation>
+<translation id="3889424535448813030">Rechtspfeil</translation>
+<translation id="4229495110203539533">Vor <ph name="NUMBER_ONE"/> Sekunde</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> Sekunden übrig</translation>
+<translation id="6829324100069873704">Zurück zu den Benachrichtigungen</translation>
+<translation id="6528179044667508675">Nicht stören</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> Sekunden</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> Minuten</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Alle Benachrichtigungen zulassen von:</translation>
+<translation id="2479520428668657293">Nach rechts und Auswahl ändern</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> Stunden</translation>
+<translation id="1398853756734560583">Vergrößern</translation>
+<translation id="4250229828105606438">Screenshot</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> Stunden</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> Minuten übrig</translation>
+<translation id="2557207087669398617">Zum Zeilenanfang</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;Alles auswählen</translation>
+<translation id="2168039046890040389">Nach oben</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> Tage</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> Minuten</translation>
+<translation id="6122334925474904337">Ein Wort nach rechts und Auswahl ändern</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> Minute</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Sie haben keine Benachrichtigungen.</translation>
+<translation id="2482878487686419369">Benachrichtigungen</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Hierher blättern</translation>
+<translation id="4552416320897244156">BildAb</translation>
+<translation id="3066573403916685335">Nach unten</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> Stunden</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Medien – Wiedergabe/Pause</translation>
+<translation id="2148716181193084225">Heute</translation>
+<translation id="7960078400008666149">1 Stunde nicht stören</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> Tage</translation>
+<translation id="2190355936436201913">(leer)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> Stunden übrig</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> Sekunde übrig</translation>
+<translation id="8447116497070723931">BildAuf</translation>
+<translation id="4588090240171750605">Nach rechts blättern</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> Stunde übrig</translation>
+<translation id="1413622004203049571">Benachrichtigungen von <ph name="NOTIFIER_NAME"/> deaktivieren</translation>
+<translation id="2666092431469916601">Oben</translation>
+<translation id="2538759511191347839">Zum Zeilenende und Auswahl ändern</translation>
+<translation id="928465423150706909">Zum Zeilenende</translation>
+<translation id="8331626408530291785">Nach oben blättern</translation>
+<translation id="7907591526440419938">Datei öffnen</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Ordner öffnen</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Vor <ph name="NUMBER_DEFAULT"/> Stunden</translation>
+<translation id="815598010540052116">Nach unten blättern</translation>
+<translation id="6808150112686056157">Medien – Stopp</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Wiederherstellen</translation>
+<translation id="5349525451964472598">Nach links und Auswahl ändern</translation>
+<translation id="1781701194097416995">Ein Wort nach links</translation>
+<translation id="1243314992276662751">Hochladen</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> Tag übrig</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Ein Wort nach links und Auswahl ändern</translation>
+<translation id="945522503751344254">Feedback geben</translation>
+<translation id="9170848237812810038">&amp;Rückgängig</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Benachrichtigungen von Folgendem für jeden Nutzer zulassen:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> Sekunde</translation>
+<translation id="1270251962578273213">Noch <ph name="NUMBER_TWO"/> Sekunden</translation>
+<translation id="3994835489895548312">Noch <ph name="NUMBER_MANY"/> Minuten</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Einstellungen...</translation>
+<translation id="6845383723252244143">Ordner auswählen</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> Sekunden</translation>
+<translation id="5368780922436099921">Noch <ph name="NUMBER_ZERO"/> Sekunden</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> Sekunden</translation>
+<translation id="5583640892426849032">Rücktaste</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> Tage</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> Stunde</translation>
+<translation id="2679312662830811292">Vor <ph name="NUMBER_ONE"/> Minute</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> Tag</translation>
+<translation id="2704295676501803339">Nach links</translation>
+<translation id="9098468523912235228">Vor <ph name="NUMBER_DEFAULT"/> Sekunden</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> Sekunden übrig</translation>
+<translation id="566737009157135450">Letztes Wort löschen</translation>
+<translation id="436869212180315161">Klicken</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> Minuten</translation>
+<translation id="1858722859751911017">Noch <ph name="NUMBER_FEW"/> Minuten</translation>
+<translation id="6040143037577758943">Schließen</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> Byte/s</translation>
+<translation id="7649070708921625228">Hilfe</translation>
+<translation id="2405367043325750948">Nächstes Zeichen löschen</translation>
+<translation id="6699343763173986273">Medien – nächster Titel</translation>
+<translation id="5445120697129764393">Noch <ph name="NUMBER_DEFAULT"/> Sekunden</translation>
+<translation id="8226233771743600312">1 Tag nicht stören</translation>
+<translation id="4252565523989510616">Nächstes Wort löschen</translation>
+<translation id="7457942297256758195">Alle löschen</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> Minuten</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> Tage übrig</translation>
+<translation id="6786750046913594791">Ordner schließen</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> Minuten</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> Stunden übrig</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Umschalt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> Sekunden</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> Sekunden</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> Sekunden</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> Tage übrig</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">In Zwischenablage kopieren</translation>
+<translation id="8371695176452482769">Jetzt sprechen</translation>
+<translation id="1167268268675672572">Zum Zeilenanfang und Auswahl ändern</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Nicht stören</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Verkleinern</translation>
+<translation id="6394627529324717982">Komma</translation>
+<translation id="3036649622769666520">Dateien öffnen</translation>
+<translation id="8328145009876646418">Linker Rand</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> Sekunden</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb
new file mode 100644
index 00000000000..85028dbb2a2
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_el.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+<translation id="4820616160060340806">Εντολή+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Φάκελος <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798">Πριν από <ph name="NUMBER_MANY"/> ώρες</translation>
+<translation id="6310545596129886942">Υπολείπονται <ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
+<translation id="9213479837033539041">Υπολείπονται <ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
+<translation id="1209866192426315618">υπολείπονται <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
+<translation id="1801827354178857021">Περίοδος</translation>
+<translation id="1190609913194133056">Κέντρο ειδοποιήσεων</translation>
+<translation id="7470933019269157899">Υπολείπονται <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
+<translation id="5613020302032141669">Αριστερό βέλος</translation>
+<translation id="4971687151119236543">Προηγούμενο κομμάτι πολυμέσων</translation>
+<translation id="8602707065186045623">Αρχείο <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
+<translation id="7511635910912978956">Υπολείπονται <ph name="NUMBER_FEW"/> ώρες</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Ακύρωση</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> Β</translation>
+<translation id="3660179305079774227">Πάνω βέλος</translation>
+<translation id="3969863827134279083">Μετακίνηση επάνω</translation>
+<translation id="7062130397825382308">Απομένει <ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ώρες</translation>
+<translation id="3990502903496589789">Δεξιά άκρη</translation>
+<translation id="9038489124413477075">Φάκελος χωρίς όνομα</translation>
+<translation id="1940483897317142625">Διαγραφή έως το τέλος της γραμμής</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> λεπτά</translation>
+<translation id="3520476450377425184">Υπολείπονται <ph name="NUMBER_MANY"/> ημέρες</translation>
+<translation id="932327136139879170">Αρχική σελίδα</translation>
+<translation id="5600907569873192868">Υπολείπονται <ph name="NUMBER_MANY"/> λεπτά</translation>
+<translation id="8666066831007952346">Υπολείπονται <ph name="NUMBER_TWO"/> ημέρες</translation>
+<translation id="6390842777729054533">Υπολείπονται <ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
+<translation id="3909791450649380159">Απο&amp;κοπή</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Ιστοσελίδα χωρίς τίτλο</translation>
+<translation id="3353284378027041011">Πριν από <ph name="NUMBER_FEW"/> ημέρες</translation>
+<translation id="5076340679995252485">&amp;Επικόλληση</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Μετακίνηση στην επόμενη λέξη δεξιά</translation>
+<translation id="364720409959344976">Επιλέξτε φάκελο για μεταφόρτωση</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Πριν από <ph name="NUMBER_TWO"/> λεπτά</translation>
+<translation id="3234408098842461169">Κάτω βέλος</translation>
+<translation id="3087734570205094154">Κάτω</translation>
+<translation id="8828991073132329143">Απομένουν <ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
+<translation id="5935630983280450497">Υπολείπεται <ph name="NUMBER_ONE"/> λεπτό</translation>
+<translation id="1860796786778352021">Κλείσιμο ειδοποίησης</translation>
+<translation id="6364916375976753737">Κύλιση αριστερά</translation>
+<translation id="2629089419211541119">Πριν από <ph name="NUMBER_ONE"/> ώρα</translation>
+<translation id="4218160142017529598">Διαγραφή προς τα πίσω</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> λεπτά</translation>
+<translation id="6982279413068714821">Πριν από <ph name="NUMBER_DEFAULT"/> λεπτά</translation>
+<translation id="6945221475159498467">Επιλογή</translation>
+<translation id="6620110761915583480">Αποθήκευση Αρχείου</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
+<translation id="8924469368910458384">Διαγραφή έως την αρχή της γραμμής</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Υπολείπεται <ph name="NUMBER_ONE"/> λεπτό</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> λεπτό</translation>
+<translation id="8210608804940886430">Επόμενη σελίδα</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ημέρες</translation>
+<translation id="7163503212501929773">Υπολείπονται <ph name="NUMBER_MANY"/> ώρες</translation>
+<translation id="5329858601952122676">&amp;Διαγραφή</translation>
+<translation id="6556866813142980365">Επανάληψη ενέργειας</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> λεπτά</translation>
+<translation id="7275974018215686543">Πριν από <ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
+<translation id="7781829728241885113">Χθες</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> λεπτά</translation>
+<translation id="50960180632766478">Υπολείπονται <ph name="NUMBER_FEW"/> λεπτά</translation>
+<translation id="5517291721709019259">Απομένουν <ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
+<translation id="6903282483217634857">Μετακίνηση δεξιά</translation>
+<translation id="6659594942844771486">Καρτέλα</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Πριν από <ph name="NUMBER_DEFAULT"/> ημέρες</translation>
+<translation id="8428213095426709021">Ρυθμίσεις</translation>
+<translation id="2497284189126895209">Όλα τα αρχεία</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964">Πριν από <ph name="NUMBER_ONE"/> ημέρα</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
+<translation id="4320177379694898372">Χωρίς σύνδεση στο διαδίκτυο</translation>
+<translation id="7814458197256864873">&amp;Αντιγραφή</translation>
+<translation id="3889424535448813030">Δεξιό βέλος</translation>
+<translation id="4229495110203539533">Πριν από <ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
+<translation id="2544782972264605588">Υπολείπονται <ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
+<translation id="6829324100069873704">Επιστροφή στις ειδοποιήσεις</translation>
+<translation id="6528179044667508675">Μην ενοχλείτε</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> λεπτά</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Να επιτρέπονται ειδοποιήσεις από:</translation>
+<translation id="2479520428668657293">Μετακίνηση δεξιά και τροποποίηση επιλογής</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ώρες</translation>
+<translation id="1398853756734560583">Μεγιστοποίηση</translation>
+<translation id="4250229828105606438">Στιγμιότυπο οθόνης</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ώρες</translation>
+<translation id="5260878308685146029">Υπολείπονται <ph name="NUMBER_TWO"/> λεπτά</translation>
+<translation id="2557207087669398617">Μετακίνηση στην αρχή της γραμμής</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Επιλογή όλ&amp;ων</translation>
+<translation id="2168039046890040389">Προηγούμενη σελίδα</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ημέρες</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> λεπτά</translation>
+<translation id="6122334925474904337">Μετακίνηση στην επόμενη λέξη δεξιά και τροποποίηση επιλογής</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> λεπτό</translation>
+<translation id="8448317557906454022">Πριν από <ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
+<translation id="4927753642311223124">Δεν υπάρχει τίποτα να δείτε εδώ, συνεχίστε με αυτό που κάνατε.</translation>
+<translation id="2482878487686419369">Ειδοποιήσεις</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Κύλιση εδώ</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Μετακίνηση κάτω</translation>
+<translation id="7052633198403197513">Πλήκτρο F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ώρες</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Αναπαραγωγή/παύση πολυμέσων</translation>
+<translation id="2148716181193084225">Σήμερα</translation>
+<translation id="7960078400008666149">Μην ενοχλείτε για μία ώρα</translation>
+<translation id="4373894838514502496">Πριν από <ph name="NUMBER_FEW"/> λεπτά</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ημέρες</translation>
+<translation id="2190355936436201913">(κενό)</translation>
+<translation id="1164369517022005061">Υπολείπονται <ph name="NUMBER_DEFAULT"/> ώρες</translation>
+<translation id="152482086482215392">Υπολείπεται <ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Κύλιση δεξιά</translation>
+<translation id="7414887922320653780">Υπολείπεται <ph name="NUMBER_ONE"/> ώρα</translation>
+<translation id="1413622004203049571">Απενεργοποίηση ειδοποιήσεων από <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Κορυφή</translation>
+<translation id="2538759511191347839">Μετακίνηση στο τέλος της γραμμής και τροποποίηση επιλογής</translation>
+<translation id="928465423150706909">Μετακίνηση στο τέλος της γραμμής</translation>
+<translation id="8331626408530291785">Κύλιση επάνω</translation>
+<translation id="7907591526440419938">Άνοιγμα αρχείου</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Άνοιγμα φακέλου</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Πριν από <ph name="NUMBER_DEFAULT"/> ώρες</translation>
+<translation id="815598010540052116">Κύλιση κάτω</translation>
+<translation id="6808150112686056157">Διακοπή πολυμέσων</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Επαναφορά</translation>
+<translation id="5349525451964472598">Μετακίνηση αριστερά και τροποποίηση επιλογής</translation>
+<translation id="1781701194097416995">Μετακίνηση στην προηγούμενη λέξη προς τα αριστερά</translation>
+<translation id="1243314992276662751">Μεταφόρτωση</translation>
+<translation id="50030952220075532">Υπολείπεται <ph name="NUMBER_ONE"/> ημέρα</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Μετακίνηση στην προηγούμενη λέξη προς τα αριστερά και τροποποίηση επιλογής</translation>
+<translation id="945522503751344254">Αποστολή σχολίων</translation>
+<translation id="9170848237812810038">Αναί&amp;ρεση</translation>
+<translation id="1285266685456062655">Πριν από <ph name="NUMBER_FEW"/> ώρες</translation>
+<translation id="6918245111648057970">Να επιτρέπονται οι ειδοποιήσεις από τις παρακάτω πηγές για κάθε χρήστη:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> δευτερόλεπτο</translation>
+<translation id="1270251962578273213">Απομένουν <ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691">Πριν από <ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Ρυθμίσεις...</translation>
+<translation id="6845383723252244143">Επιλογή Φακέλου</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
+<translation id="5368780922436099921">Απομένουν <ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
+<translation id="5583640892426849032">Πλήκτρο Backspace</translation>
+<translation id="5263972071113911534">Πριν από <ph name="NUMBER_MANY"/> ημέρες</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ημέρες</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ώρα</translation>
+<translation id="2679312662830811292">Πριν από <ph name="NUMBER_ONE"/> λεπτό</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ημέρα</translation>
+<translation id="2704295676501803339">Μετακίνηση αριστερά</translation>
+<translation id="9098468523912235228">Πριν από <ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
+<translation id="494645311413743213">Υπολείπονται <ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
+<translation id="566737009157135450">Διαγραφή λέξης προς τα πίσω</translation>
+<translation id="436869212180315161">Πιέστε</translation>
+<translation id="4860787810836767172">Πριν από <ph name="NUMBER_FEW"/> δευτερόλεπτα</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> λεπτά</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Κλείσιμο</translation>
+<translation id="1101671447232096497">Πριν από <ph name="NUMBER_MANY"/> λεπτά</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Βοήθεια</translation>
+<translation id="2405367043325750948">Διαγραφή προς τα εμπρός</translation>
+<translation id="6699343763173986273">Επόμενο κομμάτι πολυμέσων</translation>
+<translation id="5445120697129764393">Απομένουν <ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
+<translation id="8226233771743600312">Μην ενοχλείτε για μία ημέρα</translation>
+<translation id="4252565523989510616">Διαγραφή επόμενης λέξης προς τα εμπρός</translation>
+<translation id="7457942297256758195">Διαγραφή όλων</translation>
+<translation id="822618367988303761">Πριν από <ph name="NUMBER_TWO"/> ημέρες</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> λεπτά</translation>
+<translation id="1963692530539281474">Υπολείπονται <ph name="NUMBER_DEFAULT"/> ημέρες</translation>
+<translation id="6786750046913594791">Κλείσιμο φακέλου</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> λεπτά</translation>
+<translation id="5906719743126878045">Υπολείπονται <ph name="NUMBER_TWO"/> ώρες</translation>
+<translation id="8959208747503200525">Πριν από <ph name="NUMBER_TWO"/> ώρες</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> δευτερόλεπτα</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> δευτερόλεπτα</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> δευτερόλεπτα</translation>
+<translation id="3759876923365568382">Υπολείπονται <ph name="NUMBER_FEW"/> ημέρες</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Αντιγραφή στο πρόχειρο</translation>
+<translation id="8371695176452482769">Μιλήστε τώρα</translation>
+<translation id="1167268268675672572">Μετακίνηση στην αρχή της γραμμής και τροποποίηση επιλογής</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Μην ενοχλείτε</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Ελαχιστοποίηση</translation>
+<translation id="6394627529324717982">Κόμμα</translation>
+<translation id="3036649622769666520">Άνοιγμα Αρχείων</translation>
+<translation id="8328145009876646418">Αριστερή άκρη</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> δευτερόλεπτα</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
new file mode 100644
index 00000000000..31d630a3cd4
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> mins left</translation>
+<translation id="1801827354178857021">Period</translation>
+<translation id="1190609913194133056">Notification Centre</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutes left</translation>
+<translation id="5613020302032141669">Left Arrow</translation>
+<translation id="4971687151119236543">Media Previous Track</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancel</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Up Arrow</translation>
+<translation id="3969863827134279083">Move Up</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> second left</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> hours</translation>
+<translation id="3990502903496589789">Right Edge</translation>
+<translation id="9038489124413477075">Unnamed Folder</translation>
+<translation id="1940483897317142625">Delete To End Of Line</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mins</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
+<translation id="932327136139879170">Home</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">Cu&amp;t</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Untitled Web Page</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Paste</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Move Word Right</translation>
+<translation id="364720409959344976">Select Folder to Upload</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Down Arrow</translation>
+<translation id="3087734570205094154">Bottom</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min left</translation>
+<translation id="1860796786778352021">Notification close</translation>
+<translation id="6364916375976753737">Scroll Left</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">Delete Backward</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutes</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">Select</translation>
+<translation id="6620110761915583480">Save File</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Delete To Beginning Of Line</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute left</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
+<translation id="5329858601952122676">&amp;Delete</translation>
+<translation id="6556866813142980365">Redo</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Yesterday</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Move Right</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">Settings</translation>
+<translation id="2497284189126895209">All Files</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
+<translation id="4320177379694898372">No internet connection</translation>
+<translation id="7814458197256864873">&amp;Copy</translation>
+<translation id="3889424535448813030">Right Arrow</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> secs left</translation>
+<translation id="6829324100069873704">Go back to notifications</translation>
+<translation id="6528179044667508675">Do not disturb</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> seconds</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Allow notifications from the following:</translation>
+<translation id="2479520428668657293">Move Right And Modify Selection</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
+<translation id="1398853756734560583">Maximise</translation>
+<translation id="4250229828105606438">Screenshot</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
+<translation id="2557207087669398617">Move To Beginning Of Line</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Select &amp;all</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> days</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">Move Word Right And Modify Selection</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Nothing to see here, move along.</translation>
+<translation id="2482878487686419369">Notifications</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Scroll to Here</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Move Down</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Media Play/Pause</translation>
+<translation id="2148716181193084225">Today</translation>
+<translation id="7960078400008666149">Do not disturb for one hour</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
+<translation id="2190355936436201913">(empty)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hours left</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec left</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Scroll Right</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hour left</translation>
+<translation id="1413622004203049571">Disable notifications from <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Top</translation>
+<translation id="2538759511191347839">Move To End Of Line And Modify Selection</translation>
+<translation id="928465423150706909">Move To End Of Line</translation>
+<translation id="8331626408530291785">Scroll Up</translation>
+<translation id="7907591526440419938">Open File</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Open folder</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">Scroll Down</translation>
+<translation id="6808150112686056157">Media Stop</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restore</translation>
+<translation id="5349525451964472598">Move Left And Modify Selection</translation>
+<translation id="1781701194097416995">Move Word Left</translation>
+<translation id="1243314992276662751">Upload</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> day left</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Move Word Left And Modify Selection</translation>
+<translation id="945522503751344254">Send feedback</translation>
+<translation id="9170848237812810038">&amp;Undo</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Allow notifications from the following for each user:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> second</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Settings...</translation>
+<translation id="6845383723252244143">Select Folder</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hour</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> day</translation>
+<translation id="2704295676501803339">Move Left</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
+<translation id="566737009157135450">Delete Word Backward</translation>
+<translation id="436869212180315161">Press</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Close</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Help</translation>
+<translation id="2405367043325750948">Delete Forward</translation>
+<translation id="6699343763173986273">Media Next Track</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> seconds left</translation>
+<translation id="8226233771743600312">Do not disturb for one day</translation>
+<translation id="4252565523989510616">Delete Word Forward</translation>
+<translation id="7457942297256758195">Clear All</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> days left</translation>
+<translation id="6786750046913594791">Close folder</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secs</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copy to clipboard</translation>
+<translation id="8371695176452482769">Speak now</translation>
+<translation id="1167268268675672572">Move To Beginning Of Line And Modify Selection</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Do Not Disturb</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimise</translation>
+<translation id="6394627529324717982">Comma</translation>
+<translation id="3036649622769666520">Open Files</translation>
+<translation id="8328145009876646418">Left Edge</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb
new file mode 100644
index 00000000000..5acb5944e13
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Insert</translation>
+<translation id="6135826906199951471">Supr</translation>
+<translation id="528468243742722775">Fin</translation>
+<translation id="5341849548509163798">Hace <ph name="NUMBER_MANY"/> horas</translation>
+<translation id="6310545596129886942">Faltan <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="9213479837033539041">Faltan <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="1209866192426315618">Faltan <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="1801827354178857021">Período</translation>
+<translation id="1190609913194133056">Centro de notificaciones</translation>
+<translation id="7470933019269157899">Faltan <ph name="NUMBER_DEFAULT"/> minutos.</translation>
+<translation id="5613020302032141669">Flecha izquierda</translation>
+<translation id="4971687151119236543">Pista multimedia anterior</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Archivo (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
+<translation id="7511635910912978956">Faltan <ph name="NUMBER_FEW"/> horas</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Flecha arriba</translation>
+<translation id="3969863827134279083">Subir</translation>
+<translation id="7062130397825382308">Falta <ph name="NUMBER_ONE"/> segundo.</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> de MB</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="3990502903496589789">Borde derecho</translation>
+<translation id="9038489124413477075">Carpeta sin nombre</translation>
+<translation id="1940483897317142625">Eliminar hasta el final de la línea</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="3520476450377425184">Faltan <ph name="NUMBER_MANY"/> días</translation>
+<translation id="932327136139879170">Página principal</translation>
+<translation id="5600907569873192868">Faltan <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="8666066831007952346">Faltan <ph name="NUMBER_TWO"/> días</translation>
+<translation id="6390842777729054533">Faltan <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="3909791450649380159">Cor&amp;tar</translation>
+<translation id="2560788951337264832">Faltan <ph name="NUMBER_ZERO"/> minutos.</translation>
+<translation id="688711909580084195">Página web sin título</translation>
+<translation id="3353284378027041011">Hace <ph name="NUMBER_FEW"/> días</translation>
+<translation id="5076340679995252485">&amp;Pegar</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mover una palabra a la derecha</translation>
+<translation id="364720409959344976">Seleccionar carpeta para cargar</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Hace <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="3234408098842461169">Flecha abajo</translation>
+<translation id="3087734570205094154">Inferior</translation>
+<translation id="8828991073132329143">Faltan <ph name="NUMBER_MANY"/> segundos.</translation>
+<translation id="5935630983280450497">Falta <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="1860796786778352021">Cerrar notificación</translation>
+<translation id="6364916375976753737">Desplazar hacia la izquierda</translation>
+<translation id="2629089419211541119">Hace <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="4218160142017529598">Eliminar anterior</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6982279413068714821">Hace <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6945221475159498467">Seleccionar</translation>
+<translation id="6620110761915583480">Guardar archivo</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Eliminar hasta el principio de la línea</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Falta <ph name="NUMBER_ONE"/> minuto.</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Avanzar página</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> días</translation>
+<translation id="7163503212501929773">Faltan <ph name="NUMBER_MANY"/> horas</translation>
+<translation id="5329858601952122676">&amp;Suprimir</translation>
+<translation id="6556866813142980365">Rehacer</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543">Hace <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="7781829728241885113">Ayer</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478">Faltan <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="5517291721709019259">Faltan <ph name="NUMBER_FEW"/> segundos.</translation>
+<translation id="6903282483217634857">Mover hacia la derecha</translation>
+<translation id="6659594942844771486">Pestaña</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Hace <ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="8428213095426709021">Configuración</translation>
+<translation id="2497284189126895209">Todos los archivos</translation>
+<translation id="7487278341251176613">Faltan <ph name="NUMBER_TWO"/> minutos.</translation>
+<translation id="5110450810124758964">Hace <ph name="NUMBER_ONE"/> día</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="4320177379694898372">Sin conexión a Internet</translation>
+<translation id="7814458197256864873">&amp;Copiar</translation>
+<translation id="3889424535448813030">Flecha derecha</translation>
+<translation id="4229495110203539533">Hace <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="2544782972264605588">Faltan <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="6829324100069873704">Volver a las notificaciones</translation>
+<translation id="6528179044667508675">No molestar</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Permitir notificaciones de:</translation>
+<translation id="2479520428668657293">Mover hacia la derecha y modificar selección</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
+<translation id="1398853756734560583">Maximizar</translation>
+<translation id="4250229828105606438">Captura de pantalla</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
+<translation id="5260878308685146029">Faltan <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="2557207087669398617">Mover hasta el principio de la línea</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
+<translation id="2168039046890040389">Retroceder página</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6122334925474904337">Mover una palabra hacia la derecha y modificar selección</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022">Hace <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="4927753642311223124">No hay ningún elemento que mostrar.</translation>
+<translation id="2482878487686419369">Notificaciones</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Desplazarse hasta aquí</translation>
+<translation id="4552416320897244156">AvPág</translation>
+<translation id="3066573403916685335">Bajar</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Reproducir o pausar contenido multimedia</translation>
+<translation id="2148716181193084225">Hoy</translation>
+<translation id="7960078400008666149">No molestar durante una hora</translation>
+<translation id="4373894838514502496">Hace <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> días</translation>
+<translation id="2190355936436201913">(vacío)</translation>
+<translation id="1164369517022005061">Faltan <ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="152482086482215392">Falta <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="8447116497070723931">RePág</translation>
+<translation id="4588090240171750605">Desplazar a la derecha</translation>
+<translation id="7414887922320653780">Falta <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Superior</translation>
+<translation id="2538759511191347839">Mover hasta el final de la línea y modificar selección</translation>
+<translation id="928465423150706909">Mover hasta el final de la línea</translation>
+<translation id="8331626408530291785">Desplazar hacia arriba</translation>
+<translation id="7907591526440419938">Abrir archivo</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Abrir carpeta</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Hace <ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="815598010540052116">Desplazar hacia abajo</translation>
+<translation id="6808150112686056157">Detener contenido multimedia</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaurar</translation>
+<translation id="5349525451964472598">Mover hacia la izquierda y modificar selección</translation>
+<translation id="1781701194097416995">Mover una palabra a la izquierda</translation>
+<translation id="1243314992276662751">Cargar</translation>
+<translation id="50030952220075532">Falta <ph name="NUMBER_ONE"/> día</translation>
+<translation id="8179976553408161302">Intro</translation>
+<translation id="8471049483003785219">Mover una palabra a la izquierda y modificar selección</translation>
+<translation id="945522503751344254">Enviar comentarios</translation>
+<translation id="9170848237812810038">&amp;Deshacer</translation>
+<translation id="1285266685456062655">Hace <ph name="NUMBER_FEW"/> horas</translation>
+<translation id="6918245111648057970">Permitir notificaciones para cada usuario de lo siguiente:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1270251962578273213">Faltan <ph name="NUMBER_TWO"/> segundos.</translation>
+<translation id="3994835489895548312">Faltan <ph name="NUMBER_MANY"/> minutos.</translation>
+<translation id="6358975074282722691">Hace <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Configuración...</translation>
+<translation id="6845383723252244143">Seleccionar carpeta</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921">Faltan <ph name="NUMBER_ZERO"/> segundos.</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
+<translation id="5583640892426849032">Tecla de retroceso</translation>
+<translation id="5263972071113911534">Hace <ph name="NUMBER_MANY"/> días</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> días</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
+<translation id="2679312662830811292">Hace <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> día</translation>
+<translation id="2704295676501803339">Mover hacia la izquierda</translation>
+<translation id="9098468523912235228">Hace <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="494645311413743213">Faltan <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="566737009157135450">Eliminar palabra anterior</translation>
+<translation id="436869212180315161">Hacer clic</translation>
+<translation id="4860787810836767172">Hace <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">Faltan <ph name="NUMBER_FEW"/> minutos.</translation>
+<translation id="6040143037577758943">Cerrar</translation>
+<translation id="1101671447232096497">Hace <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ayuda</translation>
+<translation id="2405367043325750948">Eliminar siguiente</translation>
+<translation id="6699343763173986273">Pista multimedia siguiente</translation>
+<translation id="5445120697129764393">Faltan <ph name="NUMBER_DEFAULT"/> segundos.</translation>
+<translation id="8226233771743600312">No molestar durante un día</translation>
+<translation id="4252565523989510616">Eliminar palabra siguiente</translation>
+<translation id="7457942297256758195">Borrar todo</translation>
+<translation id="822618367988303761">Hace <ph name="NUMBER_TWO"/> días</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="1963692530539281474">Faltan <ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="6786750046913594791">Cerrar carpeta</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045">Faltan <ph name="NUMBER_TWO"/> horas</translation>
+<translation id="8959208747503200525">Hace <ph name="NUMBER_TWO"/> horas</translation>
+<translation id="8400147561352026160">Mayús+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382">Faltan <ph name="NUMBER_FEW"/> días</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copiar al portapapeles</translation>
+<translation id="8371695176452482769">Hablar ahora</translation>
+<translation id="1167268268675672572">Mover hasta el principio de la línea y modificar selección</translation>
+<translation id="6965382102122355670">Aceptar</translation>
+<translation id="7850320739366109486">No molestar</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimizar</translation>
+<translation id="6394627529324717982">Coma</translation>
+<translation id="3036649622769666520">Abrir archivos</translation>
+<translation id="8328145009876646418">Borde izquierdo</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb
new file mode 100644
index 00000000000..0a86bda401d
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_es.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Insert</translation>
+<translation id="6135826906199951471">Supr</translation>
+<translation id="528468243742722775">Fin</translation>
+<translation id="5341849548509163798">hace <ph name="NUMBER_MANY"/> horas</translation>
+<translation id="6310545596129886942">Quedan <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="9213479837033539041">Quedan <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="1209866192426315618">Quedan <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="1801827354178857021">Periodo</translation>
+<translation id="1190609913194133056">Centro de notificaciones</translation>
+<translation id="7470933019269157899">Quedan <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="5613020302032141669">Flecha izquierda</translation>
+<translation id="4971687151119236543">Pista anterior multimedia</translation>
+<translation id="8602707065186045623">Archivo <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
+<translation id="7511635910912978956">Quedan <ph name="NUMBER_FEW"/> horas</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Flecha arriba</translation>
+<translation id="3969863827134279083">Mover hacia arriba</translation>
+<translation id="7062130397825382308">Queda <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="3990502903496589789">Borde derecho</translation>
+<translation id="9038489124413477075">Carpeta sin nombre</translation>
+<translation id="1940483897317142625">Eliminar hasta el final de la línea</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="3520476450377425184">Quedan <ph name="NUMBER_MANY"/> días</translation>
+<translation id="932327136139879170">Página principal</translation>
+<translation id="5600907569873192868">Quedan <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="8666066831007952346">Quedan <ph name="NUMBER_TWO"/> días</translation>
+<translation id="6390842777729054533">Quedan <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="3909791450649380159">Cor&amp;tar</translation>
+<translation id="2560788951337264832">Quedan <ph name="NUMBER_ZERO"/> minutos</translation>
+<translation id="688711909580084195">Página web sin título</translation>
+<translation id="3353284378027041011">hace <ph name="NUMBER_FEW"/> días</translation>
+<translation id="5076340679995252485">&amp;Pegar</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mover una palabra a la derecha</translation>
+<translation id="364720409959344976">Seleccionar una carpeta para subirla</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">hace <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="3234408098842461169">Flecha abajo</translation>
+<translation id="3087734570205094154">Inferior</translation>
+<translation id="8828991073132329143">Quedan <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="5935630983280450497">Queda <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="1860796786778352021">Cerrar notificación</translation>
+<translation id="6364916375976753737">Desplazar hacia la izquierda</translation>
+<translation id="2629089419211541119">hace <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="4218160142017529598">Eliminar anterior</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6982279413068714821">hace <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6945221475159498467">Seleccionar</translation>
+<translation id="6620110761915583480">Guardar archivo</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="8924469368910458384">Eliminar hasta el inicio de la línea</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Queda <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Avanzar página</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> días</translation>
+<translation id="7163503212501929773">Quedan <ph name="NUMBER_MANY"/> horas</translation>
+<translation id="5329858601952122676">&amp;Suprimir</translation>
+<translation id="6556866813142980365">Rehacer</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="7275974018215686543">hace <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="7781829728241885113">Ayer</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="50960180632766478">Quedan <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="5517291721709019259">Quedan <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="6903282483217634857">Mover hacia la derecha</translation>
+<translation id="6659594942844771486">Pestaña</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">hace <ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="8428213095426709021">Configuración</translation>
+<translation id="2497284189126895209">Todos los archivos</translation>
+<translation id="7487278341251176613">Quedan <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="5110450810124758964">hace <ph name="NUMBER_ONE"/> día</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="4320177379694898372">No hay conexión a Internet</translation>
+<translation id="7814458197256864873">&amp;Copiar</translation>
+<translation id="3889424535448813030">Flecha derecha</translation>
+<translation id="4229495110203539533">hace <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="2544782972264605588">Quedan <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="6829324100069873704">Volver a las notificaciones</translation>
+<translation id="6528179044667508675">No molestar</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Permitir notificaciones de:</translation>
+<translation id="2479520428668657293">Mover hacia la derecha y modificar selección</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
+<translation id="1398853756734560583">Maximizar</translation>
+<translation id="4250229828105606438">Captura de pantalla</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
+<translation id="5260878308685146029">Quedan <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="2557207087669398617">Mover hasta el inicio de la línea</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
+<translation id="2168039046890040389">Retroceder página</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6122334925474904337">Mover una palabra a la derecha y modificar selección</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022">hace <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="4927753642311223124">Aquí no hay nada que ver, circulen...</translation>
+<translation id="2482878487686419369">Notificaciones</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Desplazarse hasta aquí</translation>
+<translation id="4552416320897244156">AvPág</translation>
+<translation id="3066573403916685335">Mover hacia abajo</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Pausar/Reproducir contenido multimedia</translation>
+<translation id="2148716181193084225">Hoy</translation>
+<translation id="7960078400008666149">No molestar durante una hora</translation>
+<translation id="4373894838514502496">hace <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> días</translation>
+<translation id="2190355936436201913">(vacío)</translation>
+<translation id="1164369517022005061">Quedan <ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="152482086482215392">Queda <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="8447116497070723931">RePág</translation>
+<translation id="4588090240171750605">Desplazar a la derecha</translation>
+<translation id="7414887922320653780">Queda <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Superior</translation>
+<translation id="2538759511191347839">Mover hasta el final de la línea y modificar selección</translation>
+<translation id="928465423150706909">Mover hasta el final de la línea</translation>
+<translation id="8331626408530291785">Desplazar hacia arriba</translation>
+<translation id="7907591526440419938">Abrir archivo</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Abrir carpeta</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">hace <ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="815598010540052116">Desplazar hacia abajo</translation>
+<translation id="6808150112686056157">Detener contenido multimedia</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaurar</translation>
+<translation id="5349525451964472598">Mover hacia la izquierda y modificar selección</translation>
+<translation id="1781701194097416995">Mover una palabra a la izquierda</translation>
+<translation id="1243314992276662751">Subir</translation>
+<translation id="50030952220075532">Queda <ph name="NUMBER_ONE"/> día</translation>
+<translation id="8179976553408161302">Intro</translation>
+<translation id="8471049483003785219">Mover una palabra a la izquierda y modificar selección</translation>
+<translation id="945522503751344254">Enviar comentarios</translation>
+<translation id="9170848237812810038">&amp;Deshacer</translation>
+<translation id="1285266685456062655">hace <ph name="NUMBER_FEW"/> horas</translation>
+<translation id="6918245111648057970">Permitir que cada usuario reciba notificaciones de:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1270251962578273213">Quedan <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="3994835489895548312">Quedan <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6358975074282722691">hace <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Configuración...</translation>
+<translation id="6845383723252244143">Seleccionar carpeta</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="5368780922436099921">Quedan <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
+<translation id="5583640892426849032">Tecla de retroceso</translation>
+<translation id="5263972071113911534">hace <ph name="NUMBER_MANY"/> días</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> días</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
+<translation id="2679312662830811292">hace <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> día</translation>
+<translation id="2704295676501803339">Mover hacia la izquierda</translation>
+<translation id="9098468523912235228">hace <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="494645311413743213">Quedan <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="566737009157135450">Eliminar palabra anterior</translation>
+<translation id="436869212180315161">Pulsar</translation>
+<translation id="4860787810836767172">hace <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
+<translation id="1858722859751911017">Quedan <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="6040143037577758943">Cerrar</translation>
+<translation id="1101671447232096497">hace <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ayuda</translation>
+<translation id="2405367043325750948">Eliminar siguiente</translation>
+<translation id="6699343763173986273">Siguiente pista multimedia</translation>
+<translation id="5445120697129764393">Quedan <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="8226233771743600312">No molestar durante un día</translation>
+<translation id="4252565523989510616">Eliminar palabra siguiente</translation>
+<translation id="7457942297256758195">Borrar todo</translation>
+<translation id="822618367988303761">hace <ph name="NUMBER_TWO"/> días</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="1963692530539281474">Quedan <ph name="NUMBER_DEFAULT"/> días</translation>
+<translation id="6786750046913594791">Cerrar carpeta</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="5906719743126878045">Quedan <ph name="NUMBER_TWO"/> horas</translation>
+<translation id="8959208747503200525">hace <ph name="NUMBER_TWO"/> horas</translation>
+<translation id="8400147561352026160">Mayús+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="3759876923365568382">Quedan <ph name="NUMBER_FEW"/> días</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copiar al portapapeles</translation>
+<translation id="8371695176452482769">Habla ahora</translation>
+<translation id="1167268268675672572">Mover hasta el inicio de la línea y modificar selección</translation>
+<translation id="6965382102122355670">Aceptar</translation>
+<translation id="7850320739366109486">No molestar</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimizar</translation>
+<translation id="6394627529324717982">Coma</translation>
+<translation id="3036649622769666520">Abrir archivos</translation>
+<translation id="8328145009876646418">Borde izquierdo</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb
new file mode 100644
index 00000000000..4eb30e056d6
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_et.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="et">
+<translation id="4820616160060340806">Käsk + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Kaust <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> tundi tagasi</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekundit jäänud</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekundit jäänud</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutit jäänud</translation>
+<translation id="1801827354178857021">Periood</translation>
+<translation id="1190609913194133056">Märguannete keskus</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutit on jäänud</translation>
+<translation id="5613020302032141669">Vasaknool</translation>
+<translation id="4971687151119236543">Meediumi eelmine lugu</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fail (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekundit</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> tundi jäänud</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Tühista</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Ülesnool</translation>
+<translation id="3969863827134279083">Liiguta üles</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> sekund jäänud</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> tundi</translation>
+<translation id="3990502903496589789">Parem serv</translation>
+<translation id="9038489124413477075">Nimeta kaust</translation>
+<translation id="1940483897317142625">Kustuta rea lõpuni</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutit</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/>päeva jäänud</translation>
+<translation id="932327136139879170">Kodu</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutit jäänud</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> päeva jäänud</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekundit jäänud</translation>
+<translation id="3909791450649380159">Lõ&amp;ika</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutit on jäänud</translation>
+<translation id="688711909580084195">Nimeta veebileht</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> päeva tagasi</translation>
+<translation id="5076340679995252485">&amp;Kleebi</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Liiguta sõna võrra paremale</translation>
+<translation id="364720409959344976">Kausta valimine üleslaadimiseks</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minutit tagasi</translation>
+<translation id="3234408098842461169">Allanool</translation>
+<translation id="3087734570205094154">Alaserv</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> sekundit jäänud</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutit jäänud</translation>
+<translation id="1860796786778352021">Märguande sulgemine</translation>
+<translation id="6364916375976753737">Keri vasakule</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> tund tagasi</translation>
+<translation id="4218160142017529598">Kustuta tagasisuunas</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutit</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutit tagasi</translation>
+<translation id="6945221475159498467">Vali</translation>
+<translation id="6620110761915583480">Faili salvestamine</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Kustuta rea alguseni</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut on jäänud</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8210608804940886430">Lehekülje lõppu</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> päeva</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> tundi jäänud</translation>
+<translation id="5329858601952122676">&amp;Kustuta</translation>
+<translation id="6556866813142980365">Tee uuesti</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekundit</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> sekundit tagasi</translation>
+<translation id="7781829728241885113">Eile</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutit jäänud</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> sekundit jäänud</translation>
+<translation id="6903282483217634857">Liiguta paremale</translation>
+<translation id="6659594942844771486">Vaheleht</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> päeva tagasi</translation>
+<translation id="8428213095426709021">Seaded</translation>
+<translation id="2497284189126895209">Kõik failid</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutit on jäänud</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> päev tagasi</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekundit</translation>
+<translation id="4320177379694898372">Interneti-ühendus puudub</translation>
+<translation id="7814458197256864873">&amp;Kopeeri</translation>
+<translation id="3889424535448813030">Paremnool</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekund tagasi</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekundit jäänud</translation>
+<translation id="6829324100069873704">Tagasi märguannete juurde</translation>
+<translation id="6528179044667508675">Mitte segada</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundit</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutit</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Luba märguanded järgmistest kohtadest:</translation>
+<translation id="2479520428668657293">Liiguta paremale ja muuda valikut</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> tundi</translation>
+<translation id="1398853756734560583">Maksimeeri</translation>
+<translation id="4250229828105606438">Ekraanipilt</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> tundi</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutit jäänud</translation>
+<translation id="2557207087669398617">Liiguta rea algusesse</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Vali &amp;kõik</translation>
+<translation id="2168039046890040389">Lehekülje üles</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> päeva</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutit</translation>
+<translation id="6122334925474904337">Liiguta sõna võrra paremale ja muuda valikut</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> sekundit tagasi</translation>
+<translation id="4927753642311223124">Siin pole ühtegi märguannet, liikuge edasi.</translation>
+<translation id="2482878487686419369">Märguanded</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Keri siia</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Liiguta allapoole</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> tundi</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Meediumi esitamine/peatamine</translation>
+<translation id="2148716181193084225">Täna</translation>
+<translation id="7960078400008666149">Mitte segada üks tund</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minutit tagasi</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> päeva</translation>
+<translation id="2190355936436201913">(tühi)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> tundi jäänud</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekundit jäänud</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Keri paremale</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> tundi jäänud</translation>
+<translation id="1413622004203049571">Keela märguanded: <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Üles</translation>
+<translation id="2538759511191347839">Liiguta rea lõppu ja muuda valikut</translation>
+<translation id="928465423150706909">Liiguta rea lõppu</translation>
+<translation id="8331626408530291785">Keri üles</translation>
+<translation id="7907591526440419938">Faili avamine</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Kausta avamine</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> tundi tagasi</translation>
+<translation id="815598010540052116">Keri alla</translation>
+<translation id="6808150112686056157">Meediumi peatamine</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Taasta</translation>
+<translation id="5349525451964472598">Liiguta vasakule ja muuda valikut</translation>
+<translation id="1781701194097416995">Liiguta sõna võrra vasakule</translation>
+<translation id="1243314992276662751">Laadi üles</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> päev jäänud</translation>
+<translation id="8179976553408161302">Sisestusklahv</translation>
+<translation id="8471049483003785219">Liiguta sõna võrra vasakule ja muuda valikut</translation>
+<translation id="945522503751344254">Saada tagasisidet</translation>
+<translation id="9170848237812810038">&amp;Võta tagasi</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> tundi tagasi</translation>
+<translation id="6918245111648057970">Luba järgmised märguanded iga kasutaja puhul:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> sekundit jäänud</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutit on jäänud</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> sekundit tagasi</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Seaded...</translation>
+<translation id="6845383723252244143">Kausta valimine</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> sekundit jäänud</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekundit</translation>
+<translation id="5583640892426849032">Tagasilükkeklahv</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> päeva tagasi</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> päeva</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> tund</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minut tagasi</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> päev</translation>
+<translation id="2704295676501803339">Liiguta vasakule</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekundit tagasi</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekundit jäänud</translation>
+<translation id="566737009157135450">Kustuta sõna tagasisuunas</translation>
+<translation id="436869212180315161">Vajuta</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> sekundit tagasi</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutit on jäänud</translation>
+<translation id="6040143037577758943">Sule</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minutit tagasi</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Abi</translation>
+<translation id="2405367043325750948">Kustuta edasisuunas</translation>
+<translation id="6699343763173986273">Meediumi järgmine lugu</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> sekundit jäänud</translation>
+<translation id="8226233771743600312">Mitte segada üks päev</translation>
+<translation id="4252565523989510616">Kustuta sõna edasisuunas</translation>
+<translation id="7457942297256758195">Kustuta kõik</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> päeva tagasi</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutit</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> päeva jäänud</translation>
+<translation id="6786750046913594791">Kausta sulgemine</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> tundi jäänud</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> tundi tagasi</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekundit</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekundit</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> päeva jäänud</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopeeri lõikelauale</translation>
+<translation id="8371695176452482769">Alustage rääkimist</translation>
+<translation id="1167268268675672572">Liiguta rea algusesse ja muuda valikut</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Mitte segada</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimeeri</translation>
+<translation id="6394627529324717982">Koma</translation>
+<translation id="3036649622769666520">Failide avamine</translation>
+<translation id="8328145009876646418">Vasak serv</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb
new file mode 100644
index 00000000000..a15a6160352
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_fa.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fa">
+<translation id="4820616160060340806">فرمان+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">پوشه <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">حذف</translation>
+<translation id="528468243742722775">پایان</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> دقیقه مانده</translation>
+<translation id="1801827354178857021">دوره زمانی</translation>
+<translation id="1190609913194133056">مرکز اعلان</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> دقیقه باقیمانده</translation>
+<translation id="5613020302032141669">پیکان چپ</translation>
+<translation id="4971687151119236543">آهنگ قبلی رسانه</translation>
+<translation id="8602707065186045623">فایل <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">لغو</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> بایت</translation>
+<translation id="3660179305079774227">پیکان بالا</translation>
+<translation id="3969863827134279083">حرکت به بالا</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> ثانیه باقی مانده است</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> مگابایت/ثانیه</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ساعت</translation>
+<translation id="3990502903496589789">حاشیه راست</translation>
+<translation id="9038489124413477075">پوشه بدون نام</translation>
+<translation id="1940483897317142625">حذف تا پایان خط</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> دقیقه</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
+<translation id="932327136139879170">منزل</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">&amp;برش</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> دقیقه باقیمانده</translation>
+<translation id="688711909580084195">صفحهٔ وب بدون عنوان</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;جاگذاری</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> ترابایت</translation>
+<translation id="7139614227326422685">حرکت به کلمه راست</translation>
+<translation id="364720409959344976">انتخاب پوشه برای آپلود</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">پیکان پایین</translation>
+<translation id="3087734570205094154">پایین</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> دقیقه مانده</translation>
+<translation id="1860796786778352021">بستن اعلان</translation>
+<translation id="6364916375976753737">پیمایش به چپ</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ساعت قبل</translation>
+<translation id="4218160142017529598">حذف به سمت عقب</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> دقیقه</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> دقیقه قبل</translation>
+<translation id="6945221475159498467">انتخاب</translation>
+<translation id="6620110761915583480">ذخیره کردن فایل</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ثانیه</translation>
+<translation id="8924469368910458384">حذف تا ابتدای خط</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> دقیقه باقیمانده</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> دقیقه</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
+<translation id="5329858601952122676">&amp;حذف</translation>
+<translation id="6556866813142980365">انجام مجدد</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> کیلوبایت</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> دقیقه</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">دیروز</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> دقیقه</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">حرکت به راست</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> مگابایت</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> روز قبل</translation>
+<translation id="8428213095426709021">تنظیمات</translation>
+<translation id="2497284189126895209">همه فایل‌ها</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> دقیقه باقیمانده</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> روز قبل</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ثانیه</translation>
+<translation id="4320177379694898372">اتصال اینترنت وجود ندارد</translation>
+<translation id="7814458197256864873">&amp;کپی</translation>
+<translation id="3889424535448813030">پیکان راست</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> ثانیه قبل</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> ثانیه مانده</translation>
+<translation id="6829324100069873704">بازگشت به اعلان‌ها</translation>
+<translation id="6528179044667508675">مزاحم نشوید</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ثانیه</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">اعلان موارد زیر مجاز باشد:</translation>
+<translation id="2479520428668657293">حرکت به راست و اصلاح انتخاب</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
+<translation id="1398853756734560583">بزرگ کردن</translation>
+<translation id="4250229828105606438">عکس از صفحه نمایش</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
+<translation id="2557207087669398617">حرکت به ابتدای خط</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> گیگابایت</translation>
+<translation id="1901303067676059328">انتخاب &amp;همه</translation>
+<translation id="2168039046890040389">صفحه بالا</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> روز</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">حرکت به کلمه راست و اصلاح انتخاب</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> دقیقه</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">اینجا خبری نیست، برگردید.</translation>
+<translation id="2482878487686419369">اعلام ها</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">پیمایش به اینجا</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">حرکت به پایین</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> کیلوبایت/ثانیه</translation>
+<translation id="8394908167088220973">پخش/توقف موقت رسانه</translation>
+<translation id="2148716181193084225">امروز</translation>
+<translation id="7960078400008666149">یک ساعت مزاحم نشوید</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
+<translation id="2190355936436201913">(خالی)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ساعت مانده</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ثانیه مانده</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">پیمایش به راست</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ساعت مانده</translation>
+<translation id="1413622004203049571">غیرفعال کردن اعلان‌ها از <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">بالا</translation>
+<translation id="2538759511191347839">حرکت به انتهای خط و اصلاح انتخاب</translation>
+<translation id="928465423150706909">حرکت به انتهای خط</translation>
+<translation id="8331626408530291785">پیمایش به بالا</translation>
+<translation id="7907591526440419938">باز کردن فایل</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">بازکردن پوشه</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ساعت قبل</translation>
+<translation id="815598010540052116">پیمایش به پایین</translation>
+<translation id="6808150112686056157">توقف رسانه</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">بازیابی</translation>
+<translation id="5349525451964472598">حرکت به چپ و اصلاح انتخاب</translation>
+<translation id="1781701194097416995">حرکت به کلمه چپ</translation>
+<translation id="1243314992276662751">آپلود</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> روز مانده</translation>
+<translation id="8179976553408161302">ورود</translation>
+<translation id="8471049483003785219">حرکت به کلمه چپ و اصلاح انتخاب</translation>
+<translation id="945522503751344254">ارسال بازخورد</translation>
+<translation id="9170848237812810038">&amp;واگرد</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">دریافت اعلان از موارد زیر برای هر کاربر مجاز است:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ثانیه</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> دقیقه باقیمانده</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> پتابایت</translation>
+<translation id="2983818520079887040">تنظیمات...</translation>
+<translation id="6845383723252244143">انتخاب پوشه</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ثانیه</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ساعت</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> گیگابایت/ثانیه</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> روز</translation>
+<translation id="2704295676501803339">حرکت به چپ</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> ثانیه قبل</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
+<translation id="566737009157135450">حذف کلمه قبلی</translation>
+<translation id="436869212180315161">فشار دادن</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> ترابایت/ثانیه</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> دقیقه</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> دقیقه باقیمانده</translation>
+<translation id="6040143037577758943">بستن</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> بایت/ثانیه</translation>
+<translation id="7649070708921625228">راهنما</translation>
+<translation id="2405367043325750948">حذف به سمت جلو</translation>
+<translation id="6699343763173986273">آهنگ بعدی رسانه</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> ثانیه باقی مانده است</translation>
+<translation id="8226233771743600312">یک روز مزاحم نشوید</translation>
+<translation id="4252565523989510616">حذف کلمه بعدی</translation>
+<translation id="7457942297256758195">پاک کردن همه</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> روز مانده</translation>
+<translation id="6786750046913594791">بستن پوشه</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> دقیقه</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ثانیه</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ثانیه</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> پتابایت/ثانیه</translation>
+<translation id="2743387203779672305">کپی در کلیپ‌بورد</translation>
+<translation id="8371695176452482769">اکنون صحبت کنید</translation>
+<translation id="1167268268675672572">حرکت به ابتدای خط و اصلاح انتخاب</translation>
+<translation id="6965382102122355670">تأیید</translation>
+<translation id="7850320739366109486">مزاحم نشوید</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">کوچک کردن</translation>
+<translation id="6394627529324717982">کاما</translation>
+<translation id="3036649622769666520">باز کردن فایل‌ها</translation>
+<translation id="8328145009876646418">حاشیه چپ</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ثانیه</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb
new file mode 100644
index 00000000000..d347f9a433b
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_fi.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Kansio <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekuntia jäljellä</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekuntia jäljellä</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuuttia jäljellä</translation>
+<translation id="1801827354178857021">Jakso</translation>
+<translation id="1190609913194133056">Ilmoituskeskus</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuuttia jäljellä</translation>
+<translation id="5613020302032141669">Nuoli vas.</translation>
+<translation id="4971687151119236543">Media: edellinen kappale</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-tiedosto (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekuntia</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> tuntia jäljellä</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Peruuta</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> t</translation>
+<translation id="3660179305079774227">Nuoli yl.</translation>
+<translation id="3969863827134279083">Siirrä ylös</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> sekunti jäljellä</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> Mt/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> tuntia</translation>
+<translation id="3990502903496589789">Oikea reuna</translation>
+<translation id="9038489124413477075">Nimetön kansio</translation>
+<translation id="1940483897317142625">Poista rivin loppuun asti</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuuttia</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> päivää jäljellä</translation>
+<translation id="932327136139879170">Etusivu</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuuttia jäljellä</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> päivää jäljellä</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekuntia jäljellä</translation>
+<translation id="3909791450649380159">L&amp;eikkaa</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Nimetön verkkosivu</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Liitä</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> Tt</translation>
+<translation id="7139614227326422685">Siirrä sanan oikealle puolelle</translation>
+<translation id="364720409959344976">Valitse lähetettävä kansio</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Nuoli al.</translation>
+<translation id="3087734570205094154">Alaosa</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minuuttia jäljellä</translation>
+<translation id="1860796786778352021">Ilmoitus sulje</translation>
+<translation id="6364916375976753737">Vieritä vasemmalle</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> tunti sitten</translation>
+<translation id="4218160142017529598">Poista taaksepäin</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuuttia</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuuttia sitten</translation>
+<translation id="6945221475159498467">Valitse</translation>
+<translation id="6620110761915583480">Tallenna tiedosto</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekuntia</translation>
+<translation id="8924469368910458384">Poista rivin alkuun asti</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuutti jäljellä</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuuttia</translation>
+<translation id="8210608804940886430">Sivu alas</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> päivää</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> tuntia jäljellä</translation>
+<translation id="5329858601952122676">&amp;Poista</translation>
+<translation id="6556866813142980365">Tee uudelleen</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekuntia</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kt</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Eilen</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuuttia jäljellä</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Siirrä oikealle</translation>
+<translation id="6659594942844771486">Välilehti</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> Mt</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> päivää sitten</translation>
+<translation id="8428213095426709021">Asetukset</translation>
+<translation id="2497284189126895209">Kaikki tiedostot</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> päivä sitten</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekuntia</translation>
+<translation id="4320177379694898372">Ei internetyhteyttä</translation>
+<translation id="7814458197256864873">K&amp;opioi</translation>
+<translation id="3889424535448813030">Nuoli oik.</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sekunti sitten</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekuntia jäljellä</translation>
+<translation id="6829324100069873704">Palaa ilmoituksiin</translation>
+<translation id="6528179044667508675">Älä häiritse</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekuntia</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuuttia</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Salli ilmoitukset seuraavista:</translation>
+<translation id="2479520428668657293">Siirrä oikealle ja muokkaa valintaa</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> tuntia</translation>
+<translation id="1398853756734560583">Suurenna</translation>
+<translation id="4250229828105606438">Kuvakaappaus</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> tuntia</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuuttia jäljellä</translation>
+<translation id="2557207087669398617">Siirrä rivin alkuun</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> Gt</translation>
+<translation id="1901303067676059328">Valitse &amp;kaikki</translation>
+<translation id="2168039046890040389">Sivu ylös</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> päivää</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuuttia</translation>
+<translation id="6122334925474904337">Siirrä sanan oikealle puolelle ja muokkaa valintaa</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuutti</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Täällä ei ole mitään nähtävää.</translation>
+<translation id="2482878487686419369">Ilmoitukset</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Vieritä tähän</translation>
+<translation id="4552416320897244156">Sivu alas</translation>
+<translation id="3066573403916685335">Siirrä alas</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> tuntia</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kt/s</translation>
+<translation id="8394908167088220973">Media: toista/keskeytä</translation>
+<translation id="2148716181193084225">Tänään</translation>
+<translation id="7960078400008666149">Älä häiritse tuntiin</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> päivää</translation>
+<translation id="2190355936436201913">(tyhjä)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> tuntia jäljellä</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekuntia jäljellä</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Vieritä oikealle</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> tuntia jäljellä</translation>
+<translation id="1413622004203049571">Poista ilmoitukset käytöstä sovellukselta <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Yleisin</translation>
+<translation id="2538759511191347839">Siirrä rivin loppuun ja muokkaa valintaa</translation>
+<translation id="928465423150706909">Siirrä rivin loppuun</translation>
+<translation id="8331626408530291785">Vieritä ylös</translation>
+<translation id="7907591526440419938">Avaa tiedosto</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Avaa kansio</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> tuntia sitten</translation>
+<translation id="815598010540052116">Vieritä alas</translation>
+<translation id="6808150112686056157">Media: pysäytä</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Palauta</translation>
+<translation id="5349525451964472598">Siirrä vasemmalle ja muokkaa valintaa</translation>
+<translation id="1781701194097416995">Siirrä sanan vasemmalle puolelle</translation>
+<translation id="1243314992276662751">Lähetä</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> päivää jäljellä</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Siirrä sanan vasemmalle puolelle ja muokkaa valintaa</translation>
+<translation id="945522503751344254">Lähetä palautetta</translation>
+<translation id="9170848237812810038">K&amp;umoa</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Salli seuraavat ilmoitukset kaikilta käyttäjiltä:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunti</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> Pt</translation>
+<translation id="2983818520079887040">Asetukset...</translation>
+<translation id="6845383723252244143">Valitse kansio</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekuntia</translation>
+<translation id="5583640892426849032">Askelpalautin</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> päivää</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> tuntia</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuutti sitten</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> Gt/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> päivää</translation>
+<translation id="2704295676501803339">Siirrä vasemmalle</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> sekuntia sitten</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekuntia jäljellä</translation>
+<translation id="566737009157135450">Poista edellinen sana</translation>
+<translation id="436869212180315161">Paina</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> Tt/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuuttia</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Sulje</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> t/s</translation>
+<translation id="7649070708921625228">Ohje</translation>
+<translation id="2405367043325750948">Poista eteenpäin</translation>
+<translation id="6699343763173986273">Media: seuraava kappale</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> sekuntia jäljellä</translation>
+<translation id="8226233771743600312">Älä häiritse päivään</translation>
+<translation id="4252565523989510616">Poista seuraava sana</translation>
+<translation id="7457942297256758195">Tyhjennä kaikki</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuuttia</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> päivää jäljellä</translation>
+<translation id="6786750046913594791">Sulje kansio</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> tuntia jäljellä</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekuntia</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekuntia</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> päivää jäljellä</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> Pt/s</translation>
+<translation id="2743387203779672305">Kopioi leikepöydälle</translation>
+<translation id="8371695176452482769">Puhu nyt</translation>
+<translation id="1167268268675672572">Siirrä rivin alkuun ja muokkaa valintaa</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Älä häiritse</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Pienennä</translation>
+<translation id="6394627529324717982">Pilkku</translation>
+<translation id="3036649622769666520">Avaa tiedostot</translation>
+<translation id="8328145009876646418">Vasen reuna</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb
new file mode 100644
index 00000000000..117b6f6887e
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_fil.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Wakas na</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> mga oras ang nakalipas</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/>nalalabing seg</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> mga natitirang segundo</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> nalalabing mga minuto</translation>
+<translation id="1801827354178857021">Panahon</translation>
+<translation id="1190609913194133056">Notification Center</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> (na) minuto ang natitira</translation>
+<translation id="5613020302032141669">KAliwang Arrow</translation>
+<translation id="4971687151119236543">Nakaraang Track ng Media</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> segundo</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> natitirang oras</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Ikansela</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> (na) B</translation>
+<translation id="3660179305079774227">Up Arrow</translation>
+<translation id="3969863827134279083">Lumipat Pataas</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> segundo ang natitira</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> (na) MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> mga oras</translation>
+<translation id="3990502903496589789">Tamang Lamang</translation>
+<translation id="9038489124413477075">Walang Pangalan na Folder</translation>
+<translation id="1940483897317142625">Tanggalin Papunta Sa Dulo Ng Linya</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mga minuto</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> mga nalalabing araw</translation>
+<translation id="932327136139879170">Home</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> natitirang minuto</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> natitirang mga araw</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> mga natitirang segundo</translation>
+<translation id="3909791450649380159">Al&amp;isin</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Walang Pamagat na Webpage</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> araw ang nakalipas</translation>
+<translation id="5076340679995252485">&amp;Ilagay</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> (na) TB</translation>
+<translation id="7139614227326422685">Lumipat Sa Kanan Ng Salita</translation>
+<translation id="364720409959344976">Pumili ng Folder na I-a-upload</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuto ang nakalipas</translation>
+<translation id="3234408098842461169">Down Arrow</translation>
+<translation id="3087734570205094154">Sa ilalim</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> natitirang minuto</translation>
+<translation id="1860796786778352021">Isara ang notification</translation>
+<translation id="6364916375976753737">Mag-scroll Pakaliwa</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> oras ang nakalipas</translation>
+<translation id="4218160142017529598">Tanggalin Ang Nakaraan (Na Salita)</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> (na) minuto</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuto ang nakalipas</translation>
+<translation id="6945221475159498467">Pumili</translation>
+<translation id="6620110761915583480">I-save ang File</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> na segundo</translation>
+<translation id="8924469368910458384">Tanggalin Papunta Sa Umpisa Ng Linya</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto ang natitira</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> mga araw</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> mga oras na nalalabi</translation>
+<translation id="5329858601952122676">&amp;Tanggalin</translation>
+<translation id="6556866813142980365">Redo</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> (na) minuto</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> segundo ang nakalipas</translation>
+<translation id="7781829728241885113">Kahapon</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuto</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> natitirang minuto</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Lumipat Pakanan</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> (na) MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> araw ang nakalipas</translation>
+<translation id="8428213095426709021">Mga Setting</translation>
+<translation id="2497284189126895209">Lahat ng Mga File</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> araw ang nakalipas</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="4320177379694898372">Walang koneksyon sa internet</translation>
+<translation id="7814458197256864873">&amp;Kopyahin</translation>
+<translation id="3889424535448813030">Right Arrow</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> segundo ang nakalipas</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> mga natitirang segundo</translation>
+<translation id="6829324100069873704">Bumalik sa mga notification</translation>
+<translation id="6528179044667508675">Huwag istorbohin</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> (na) segundo</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuto</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Payagan ang mga notification mula sa sumusunod:</translation>
+<translation id="2479520428668657293">Lumipat Pakanan At Baguhin ang Pinili</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/>mga oras</translation>
+<translation id="1398853756734560583">Maximize</translation>
+<translation id="4250229828105606438">Screenshot</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> mga oras</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> natitirang minuto</translation>
+<translation id="2557207087669398617">Lumipat Sa Umpisa Ng Linya</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> (na) GB</translation>
+<translation id="1901303067676059328">Piliin ang &amp;lahat</translation>
+<translation id="2168039046890040389">Pataas</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> mga araw</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mga minuto</translation>
+<translation id="6122334925474904337">Lumipat Sa Kanan ng Salita At Baguhin ang Pinili</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> segundo ang nakalipas</translation>
+<translation id="4927753642311223124">Walang makikita rito, magpatuloy.</translation>
+<translation id="2482878487686419369">Mga Abiso</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Mag-scroll dito</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Lumipat Pababa</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> mga oras</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">I-Play/I-Pause ang Media</translation>
+<translation id="2148716181193084225">Ngayon</translation>
+<translation id="7960078400008666149">Huwag istorbohin sa loob ng isang oras</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuto ang nakalipas</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> mga araw</translation>
+<translation id="2190355936436201913">(walang laman)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> mga natitirang oras</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> natitirang segundo</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Mag-scroll Pakanan</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> natitirang oras</translation>
+<translation id="1413622004203049571">I-disable ang mga notification mula sa <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Tuktok</translation>
+<translation id="2538759511191347839">Lumipat Papunta Sa Dulo ng Linya At Baguhin ang Pinili</translation>
+<translation id="928465423150706909">Lumipat Sa Dulo Ng Linya</translation>
+<translation id="8331626408530291785">Mag-scroll Pataas</translation>
+<translation id="7907591526440419938">Buksan ang File</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Buksan ang folder</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> na oras ang nakalipas</translation>
+<translation id="815598010540052116">Mag-scroll Pababa</translation>
+<translation id="6808150112686056157">Media Ihinto</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Ipanumbalik</translation>
+<translation id="5349525451964472598">Lumipat Pakaliwa At Baguhin ang Pinili</translation>
+<translation id="1781701194097416995">Lumipat Sa Kaliwa Ng Salita</translation>
+<translation id="1243314992276662751">I-upload</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> natitirang araw</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Lumipat Sa Kaliwa Ng Salita At Baguhin ang Pinili</translation>
+<translation id="945522503751344254">Magpadala ng feedback...</translation>
+<translation id="9170848237812810038">&amp;I-undo</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> (na) oras ang nakalipas</translation>
+<translation id="6918245111648057970">Payagan ang mga notification mula sa sumusunod para sa bawat user:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> segundo ang nakalipas</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> (na) PB</translation>
+<translation id="2983818520079887040">Mga Setting...</translation>
+<translation id="6845383723252244143">Piliin ang Folder</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> (na) segundo</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> araw ang nakalipas</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> mga araw</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> oras</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto ang nakalipas</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> (na) GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> araw</translation>
+<translation id="2704295676501803339">Lumipat Pakaliwa</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> segundo ang nakalipas</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> mga natitirang segundo</translation>
+<translation id="566737009157135450">Tanggalin Ang Nakaraang Salita</translation>
+<translation id="436869212180315161">Pindutin</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> segundo ang nakalipas</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> (na) TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> na minuto</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Isara</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuto ang nakalipas</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> (na) B/s</translation>
+<translation id="7649070708921625228">Tulong</translation>
+<translation id="2405367043325750948">Tanggalin Ang Susunod (Na Salita)</translation>
+<translation id="6699343763173986273">Susunod na Track ng Media</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> (na) segundo ang natitira</translation>
+<translation id="8226233771743600312">Huwag istorbohin sa loob ng isang araw</translation>
+<translation id="4252565523989510616">Tanggalin Ang Susunod Na Salita</translation>
+<translation id="7457942297256758195">I-clear Lahat</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> araw ang nakalipas</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mga minuto</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> mga natitirang araw</translation>
+<translation id="6786750046913594791">Isara ang folder</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> (na) minuto</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> mga oras na nalalabi</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> oras ang nakalipas</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> (na) segundo</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> mga natitirang araw</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> (na) PB/s</translation>
+<translation id="2743387203779672305">Kopyahin sa clipboard</translation>
+<translation id="8371695176452482769">Magsalita ngayon</translation>
+<translation id="1167268268675672572">Lumipat Sa Umpisa Ng Linya At Baguhin ang Pinili</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Huwag Istorbohin</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimize</translation>
+<translation id="6394627529324717982">Kuwit</translation>
+<translation id="3036649622769666520">Buksan ang Mga File</translation>
+<translation id="8328145009876646418">Kalwang Edge</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundo</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb
new file mode 100644
index 00000000000..fae9e0956a5
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_fr.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+<translation id="4820616160060340806">Commande + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Dossier <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Insér.</translation>
+<translation id="6135826906199951471">Suppr</translation>
+<translation id="528468243742722775">Fin</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secondes restantes</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secondes restantes</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutes restantes</translation>
+<translation id="1801827354178857021">Période</translation>
+<translation id="1190609913194133056">Centre de notification</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutes restantes</translation>
+<translation id="5613020302032141669">Gauche</translation>
+<translation id="4971687151119236543">Contenu multimédia : titre précédent</translation>
+<translation id="8602707065186045623">Fichier <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secondes</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> heures restantes</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Annuler</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> o</translation>
+<translation id="3660179305079774227">Haut</translation>
+<translation id="3969863827134279083">Déplacer vers le haut</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> seconde restante</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> Mo/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> heures</translation>
+<translation id="3990502903496589789">Côté droit</translation>
+<translation id="9038489124413477075">Dossier sans nom</translation>
+<translation id="1940483897317142625">Supprimer jusqu'à la fin de la ligne</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutes</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> jours restants</translation>
+<translation id="932327136139879170">Accueil</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutes restantes</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> jours restants</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secondes restantes</translation>
+<translation id="3909791450649380159">Cou&amp;per</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Page Web sans titre</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">C&amp;oller</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> To</translation>
+<translation id="7139614227326422685">Déplacer jusqu'au prochain mot sur la droite</translation>
+<translation id="364720409959344976">Sélectionner le dossier d'importation</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">il y a <ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="3234408098842461169">Bas</translation>
+<translation id="3087734570205094154">Bas</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minute restante</translation>
+<translation id="1860796786778352021">Fermer la notification</translation>
+<translation id="6364916375976753737">Défilement vers la gauche</translation>
+<translation id="2629089419211541119">il y a <ph name="NUMBER_ONE"/> heure</translation>
+<translation id="4218160142017529598">Supprimer en arrière</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutes</translation>
+<translation id="6982279413068714821">il y a <ph name="NUMBER_DEFAULT"/> minutes</translation>
+<translation id="6945221475159498467">Sélectionner</translation>
+<translation id="6620110761915583480">Enregistrer le fichier</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Supprimer jusqu'au début de la ligne</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute restante</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minute</translation>
+<translation id="8210608804940886430">Page suivante</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> jours</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> heures restantes</translation>
+<translation id="5329858601952122676">&amp;Supprimer</translation>
+<translation id="6556866813142980365">Rétablir</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secondes</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> Ko</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Hier</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutes restantes</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Déplacer vers la droite</translation>
+<translation id="6659594942844771486">Onglet</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> Mo</translation>
+<translation id="4988273303304146523">il y a <ph name="NUMBER_DEFAULT"/> jours</translation>
+<translation id="8428213095426709021">Paramètres</translation>
+<translation id="2497284189126895209">Tous les fichiers</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964">il y a <ph name="NUMBER_ONE"/> jour</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> seconde</translation>
+<translation id="4320177379694898372">Aucune connexion Internet.</translation>
+<translation id="7814458197256864873">&amp;Copier</translation>
+<translation id="3889424535448813030">Droite</translation>
+<translation id="4229495110203539533">il y a <ph name="NUMBER_ONE"/> seconde</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> secondes restantes</translation>
+<translation id="6829324100069873704">Revenir aux notifications</translation>
+<translation id="6528179044667508675">Ne pas déranger</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secondes</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Autoriser les notifications des éléments suivants :</translation>
+<translation id="2479520428668657293">Déplacer vers la droite et modifier la sélection</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> heures</translation>
+<translation id="1398853756734560583">Agrandir</translation>
+<translation id="4250229828105606438">Capture d'écran</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> heures</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutes restantes</translation>
+<translation id="2557207087669398617">Déplacer vers le début de la ligne</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> Go</translation>
+<translation id="1901303067676059328">&amp;Tout sélectionner</translation>
+<translation id="2168039046890040389">Page précédente</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> jours</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="6122334925474904337">Déplacer jusqu'au prochain mot sur la droite et modifier la sélection</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Aucune notification</translation>
+<translation id="2482878487686419369">Notifications</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Défilement jusqu'ici</translation>
+<translation id="4552416320897244156">PgSuiv</translation>
+<translation id="3066573403916685335">Déplacer vers le bas</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> heures</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> Ko/s</translation>
+<translation id="8394908167088220973">Contenu multimédia : lecture/pause</translation>
+<translation id="2148716181193084225">Aujourd'hui</translation>
+<translation id="7960078400008666149">Ne pas déranger pendant une heure</translation>
+<translation id="4373894838514502496">il y a <ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> jours</translation>
+<translation id="2190355936436201913">(vide)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> heures restantes</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seconde restante</translation>
+<translation id="8447116497070723931">PgPréc</translation>
+<translation id="4588090240171750605">Défilement vers la droite</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> heure restante</translation>
+<translation id="1413622004203049571">Désactiver les notifications <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">En haut</translation>
+<translation id="2538759511191347839">Déplacer à la fin de la ligne et modifier la sélection</translation>
+<translation id="928465423150706909">Déplacer à la fin de la ligne</translation>
+<translation id="8331626408530291785">Défilement vers le haut</translation>
+<translation id="7907591526440419938">Ouvrir le fichier</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Ouvrir le dossier</translation>
+<translation id="1293699935367580298">Échap</translation>
+<translation id="2797524280730715045">il y a <ph name="NUMBER_DEFAULT"/> heures</translation>
+<translation id="815598010540052116">Défilement vers le bas</translation>
+<translation id="6808150112686056157">Contenu multimédia : arrêt</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaurer</translation>
+<translation id="5349525451964472598">Déplacer vers la gauche et modifier la sélection</translation>
+<translation id="1781701194097416995">Déplacer jusqu'au mot précédent sur la gauche</translation>
+<translation id="1243314992276662751">Importer</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> jour restant</translation>
+<translation id="8179976553408161302">Entrée</translation>
+<translation id="8471049483003785219">Déplacer jusqu'au mot précédent sur la gauche et modifier la sélection</translation>
+<translation id="945522503751344254">Envoyer le commentaire</translation>
+<translation id="9170848237812810038">Ann&amp;uler</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Autoriser les notifications issues des éléments suivants pour chaque utilisateur :</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> seconde</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> Po</translation>
+<translation id="2983818520079887040">Paramètres...</translation>
+<translation id="6845383723252244143">Sélectionner un dossier</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secondes</translation>
+<translation id="5583640892426849032">Retour</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> jours</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> heure</translation>
+<translation id="2679312662830811292">il y a <ph name="NUMBER_ONE"/> minute</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> Go/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> jour</translation>
+<translation id="2704295676501803339">Déplacer vers la gauche</translation>
+<translation id="9098468523912235228">il y a <ph name="NUMBER_DEFAULT"/> secondes</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secondes restantes</translation>
+<translation id="566737009157135450">Supprimer un mot en arrière</translation>
+<translation id="436869212180315161">Cliquer</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> To/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Fermer</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> o/s</translation>
+<translation id="7649070708921625228">Aide</translation>
+<translation id="2405367043325750948">Supprimer vers l'avant</translation>
+<translation id="6699343763173986273">Contenu multimédia : titre suivant</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> secondes restantes</translation>
+<translation id="8226233771743600312">Ne pas déranger pendant un jour</translation>
+<translation id="4252565523989510616">Supprimer un mot vers l'avant</translation>
+<translation id="7457942297256758195">Tout effacer</translation>
+<translation id="822618367988303761">il y a <ph name="NUMBER_TWO"/> jours</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> jours restants</translation>
+<translation id="6786750046913594791">Fermer le dossier</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> heures restantes</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Maj+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secondes</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secondes</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> jours restants</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> Po/s</translation>
+<translation id="2743387203779672305">Copier dans le Presse-papier</translation>
+<translation id="8371695176452482769">Parlez maintenant</translation>
+<translation id="1167268268675672572">Déplacer au début de la ligne et modifier la sélection</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Ne pas déranger</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Réduire</translation>
+<translation id="6394627529324717982">Virgule</translation>
+<translation id="3036649622769666520">Ouvrir les fichiers</translation>
+<translation id="8328145009876646418">Côté gauche</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb
new file mode 100644
index 00000000000..868e771b017
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_gu.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="gu">
+<translation id="4820616160060340806">કમાન્ડ+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> ફોલ્ડર</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">સમાપ્ત</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> સેકંડ બાકી</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> સેકન્ડ બાકી</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> મિનિટ બાકી</translation>
+<translation id="1801827354178857021">સમયગાળો</translation>
+<translation id="1190609913194133056">સૂચના કેન્દ્ર</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> મિનિટ બાકી</translation>
+<translation id="5613020302032141669">ડાબો એરો</translation>
+<translation id="4971687151119236543">મીડિયા પહેલાંનું ટ્રૅક</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ફાઇલ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> મિનિટ પહેલા</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> સેકંડ</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> કલાક બાકી</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">રદ કરો</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> અબજ</translation>
+<translation id="3660179305079774227">ઉપર એરો</translation>
+<translation id="3969863827134279083">ઉપર ખસેડો</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> સેકંડ બાકી</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> કલાક</translation>
+<translation id="3990502903496589789">જમણી કિનારી</translation>
+<translation id="9038489124413477075">અનામાંકિત ફોલ્ડર</translation>
+<translation id="1940483897317142625">લીટીના અંત સુધીનું કાઢી નાખો</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> મિનિટ</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> દિવસ બાકી</translation>
+<translation id="932327136139879170">હોમ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> મિનિટ બાકી</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> દિવસ બાકી</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> સેકન્ડ બાકી</translation>
+<translation id="3909791450649380159">કા&amp;પો</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> મિનિટ બાકી</translation>
+<translation id="688711909580084195">શીર્ષક વિનાનું વેબપૃષ્ઠ </translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">પેસ્ટ કરો</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">શબ્દની જમણી બાજુએ ખસેડો</translation>
+<translation id="364720409959344976">અપલોડ કરવા માટે ફોલ્ડર પસંદ કરો</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">નીચલો એરો</translation>
+<translation id="3087734570205094154">તળિયું</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> સેકંડ બાકી</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> મિનિટ બાકી</translation>
+<translation id="1860796786778352021">સૂચના બંધ છે</translation>
+<translation id="6364916375976753737">ડાબે સ્ક્રોલ કરો</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">પાછળનું કાઢી નાખો</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> મિનિટ</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">પસંદ કરો</translation>
+<translation id="6620110761915583480">ફાઇલ સાચવો</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> સેકંડ</translation>
+<translation id="8924469368910458384">લીટીની શરૂઆત સુધીનું કાઢી નાખો</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> કલાક</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> મિનિટ બાકી</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> મિનિટ</translation>
+<translation id="8210608804940886430">પૃષ્ઠ નીચે</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> દિવસ</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> કલાક બાકી</translation>
+<translation id="5329858601952122676">&amp;કાઢી નાખો</translation>
+<translation id="6556866813142980365">ફરી કરો</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> સેકંડ</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> મિનિટ</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">ગઈ કાલે</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> મિનિટ</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> મિનિટ બાકી</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> સેકંડ બાકી</translation>
+<translation id="6903282483217634857">જમણી બાજુએ ખસેડો</translation>
+<translation id="6659594942844771486">ટૅબ</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/>MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="2497284189126895209">બધી ફાઇલો</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> મિનિટ બાકી</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> સેકન્ડ</translation>
+<translation id="4320177379694898372">કોઈ ઇન્ટરનેટ કનેક્શન નથી</translation>
+<translation id="7814458197256864873">&amp;કૉપિ કરો</translation>
+<translation id="3889424535448813030">જમણો એરો</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> સેકંડ બાકી</translation>
+<translation id="6829324100069873704">સૂચનાઓ પર પાછા જાઓ</translation>
+<translation id="6528179044667508675">ખલેલ પાડશો નહીં</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> સેકંડ</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> મિનિટ</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> કલાક બાકી</translation>
+<translation id="7135556860107312402">નીચેના પરથી સૂચનાઓને મંજૂરી આપો:</translation>
+<translation id="2479520428668657293">જમણી બાજુએ ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> કલાક</translation>
+<translation id="1398853756734560583">મોટું કરો</translation>
+<translation id="4250229828105606438">સ્ક્રીનશૉટ</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> કલાક</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> મિનિટ બાકી</translation>
+<translation id="2557207087669398617">લીટીની શરૂઆતમાં ખસેડો</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;બધા પસંદ કરો</translation>
+<translation id="2168039046890040389">પૃષ્ઠ ઉપર</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> મિનિટ</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> દિવસ</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> મિનિટ્સ</translation>
+<translation id="6122334925474904337">શબ્દની જમણી બાજુએ ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> મિનિટ</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">અહીં જોવા માટે કંઈ નથી, આગળ વધો.</translation>
+<translation id="2482878487686419369">સૂચનાઓ</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> દિવસ</translation>
+<translation id="3183922693828471536">અહીં સુધી સ્ક્રોલ કરો</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">નીચે ખસેડો</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> કલાક</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">મીડિયા ચલાવો/થોભાવો</translation>
+<translation id="2148716181193084225">આજે</translation>
+<translation id="7960078400008666149">એક કલાક માટે ખલેલ પાડશો નહીં</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> દિવસ</translation>
+<translation id="2190355936436201913">(ખાલી)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> કલાક બાકી</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> સેકન્ડ બાકી</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">જમણે સ્ક્રોલ કરો</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> કલાક બાકી</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> તરફથી સૂચનાઓ અક્ષમ કરો</translation>
+<translation id="2666092431469916601">ઉપર</translation>
+<translation id="2538759511191347839">લીટીની અંતમાં ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="928465423150706909">લીટીના અંતમાં ખસેડો</translation>
+<translation id="8331626408530291785">ઉપર સ્ક્રોલ કરો</translation>
+<translation id="7907591526440419938">ફાઇલ ખોલો</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> દિવસ બાકી</translation>
+<translation id="2803313416453193357">ફોલ્ડર ખોલો</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">નીચે સ્ક્રોલ કરો</translation>
+<translation id="6808150112686056157">મીડિયા સ્ટોપ</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> મિનિટ બાકી</translation>
+<translation id="3157931365184549694">પુનઃસ્થાપિત કરો</translation>
+<translation id="5349525451964472598">ડાબે ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="1781701194097416995">શબ્દની ડાબી બાજુએ ખસેડો</translation>
+<translation id="1243314992276662751">અપલોડ કરો</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> દિવસ બાકી</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">શબ્દની ડાબી બાજુએ ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="945522503751344254">પ્રતિસાદ મોકલો</translation>
+<translation id="9170848237812810038">&amp;પૂર્વવત્ કરો</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">દરેક વપરાશકર્તા માટે નીચેનામાંથી સૂચનાઓની પરવાનગી આપો:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> સેકંડ</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> સેકંડ બાકી</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> મિનિટ બાકી</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">સેટિંગ્સ...</translation>
+<translation id="6845383723252244143">ફોલ્ડર પસંદ કરો</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> સેકંડ</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> સેકંડ બાકી</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> સેકંડ</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> દિવસ</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> કલાક</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> કલાક પહેલા</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> દિવસ</translation>
+<translation id="2704295676501803339">ડાબે ખસેડો</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> સેકન્ડ બાકી</translation>
+<translation id="566737009157135450">શબ્દની પાછળનું કાઢી નાખો</translation>
+<translation id="436869212180315161">દબાવો</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> મિનિટ</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> મિનિટ બાકી</translation>
+<translation id="6040143037577758943">બંધ કરો</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">સહાય</translation>
+<translation id="2405367043325750948">આગળનું કાઢી નાખો</translation>
+<translation id="6699343763173986273">મીડિયા આગલો ટ્રૅક</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> સેકંડ બાકી</translation>
+<translation id="8226233771743600312">એક દિવસ માટે ખલેલ પાડશો નહીં</translation>
+<translation id="4252565523989510616">શબ્દની આગળનું કાઢી નાખો</translation>
+<translation id="7457942297256758195">બધું સાફ કરો</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> મિનિટ</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> દિવસ બાકી</translation>
+<translation id="6786750046913594791">ફોલ્ડર બંધ કરો</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> મિનિટ</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> કલાક બાકી</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> સેકંડ</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> સેકંડ</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> સેકંડ</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> દિવસ બાકી</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">ક્લિપબોર્ડ પર કૉપિ કરો</translation>
+<translation id="8371695176452482769">હવે બોલો</translation>
+<translation id="1167268268675672572">લીટીની શરૂઆતમાં ખસેડો અને પસંદગી સંશોધિત કરો</translation>
+<translation id="6965382102122355670">ઓકે</translation>
+<translation id="7850320739366109486">ખલેલ પાડશો નહીં</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> દિવસ પહેલા</translation>
+<translation id="5941711191222866238">નાનું કરો</translation>
+<translation id="6394627529324717982">અલ્પવિરામ</translation>
+<translation id="3036649622769666520">ફાઇલો ખોલો</translation>
+<translation id="8328145009876646418">ડાબી કિનારી</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> સેકંડ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb
new file mode 100644
index 00000000000..c8ea6a92f30
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_hi.xtb
@@ -0,0 +1,223 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+<translation id="4820616160060340806">आदेश+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> फ़ोल्डर</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">समाप्त</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> घंटे पहले</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> mins left</translation>
+<translation id="1801827354178857021">अवधि</translation>
+<translation id="1190609913194133056">सूचना केंद्र</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> मिनट शेष</translation>
+<translation id="5613020302032141669">बायां तीर</translation>
+<translation id="4971687151119236543">मीडिया पिछला ट्रैक</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> फ़ाइल (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> सेकंड</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">रद्द करें</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> बाइट</translation>
+<translation id="3660179305079774227">ऊपर तीर</translation>
+<translation id="3969863827134279083">ऊपर ले जाएं</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> सेकंड शेष</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> घंटे</translation>
+<translation id="3990502903496589789">दायां सिरा</translation>
+<translation id="9038489124413477075">अनाम फ़ोल्डर</translation>
+<translation id="1940483897317142625">पंक्ति के अंत तक हटाएं</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> मिनट</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
+<translation id="932327136139879170">मुख्यपृष्ठ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">&amp;काटें</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> मिनट शेष</translation>
+<translation id="688711909580084195">शीर्षक-रहित वेबपृष्ठ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> दिन पहले</translation>
+<translation id="5076340679995252485">&amp;चिपकाएं</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">शब्द के दाईं ओर ले जाएं</translation>
+<translation id="364720409959344976">अपलोड करने के लिए फ़ोल्‍डर चुनें</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">नीचे तीर</translation>
+<translation id="3087734570205094154">नीचे</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> मिनट शेष</translation>
+<translation id="1860796786778352021">सूचना बंद करें</translation>
+<translation id="6364916375976753737">बाएं स्क्रॉल करें</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> घंटे पहले</translation>
+<translation id="4218160142017529598">पीछे की ओर का शब्द हटाएं</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> मिनट</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">चुनें</translation>
+<translation id="6620110761915583480">फ़ाइल सहेजें</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> सेकंड</translation>
+<translation id="8924469368910458384">पंक्ति की शुरुआत तक हटाएं</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> घंटे</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> मिनट शेष</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> मिनट</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> दिन</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
+<translation id="5329858601952122676">&amp;हटाएं</translation>
+<translation id="6556866813142980365">पुन: करें</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> सेकंड</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> मिनट</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> सेकंड पहले</translation>
+<translation id="7781829728241885113">बीता कल</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> मिनट</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">दाईं ओर ले जाएं</translation>
+<translation id="6659594942844771486">टैब</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> दिन पहले</translation>
+<translation id="8428213095426709021">सेटिंग</translation>
+<translation id="2497284189126895209">सभी फ़ाइलें</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> मिनट शेष</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> दिन पहले</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> सेकंड</translation>
+<translation id="4320177379694898372">कोई इंटरनेट कनेक्‍शन नहीं</translation>
+<translation id="7814458197256864873">&amp;प्रतिलिपि बनाएं</translation>
+<translation id="3889424535448813030">दायां तीर</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> सेकंड पहले
+</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> सेकंड शेष</translation>
+<translation id="6829324100069873704">सूचनाओं पर वापस जाएं</translation>
+<translation id="6528179044667508675">परेशान न करें</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> सेकंड</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> मिनट</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">निम्न से आने वाली सूचनाओं की अनुमति दें:</translation>
+<translation id="2479520428668657293">दाईं ओर ले जाएं और चयन बदलें</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> घंटे</translation>
+<translation id="1398853756734560583">बड़ा करें</translation>
+<translation id="4250229828105606438">स्क्रीनशॉट</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> घंटे</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
+<translation id="2557207087669398617">पंक्ति के प्रारंभ में ले जाएं</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;सभी को चुनें</translation>
+<translation id="2168039046890040389">पृष्ठ ऊपर</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> मिनट</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> दिन</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> मिनट</translation>
+<translation id="6122334925474904337">शब्द के दाईं ओर ले जाएं और चयन बदलें</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> मिनट</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">यहां देखने के लिए कुछ भी नहीं है, आगे चलें.</translation>
+<translation id="2482878487686419369">अधिसूचनाएं</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> दिन</translation>
+<translation id="3183922693828471536">यहां तक स्क्रॉल करें</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">नीचे ले जाएं</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> घंटे</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">मीडिया चलाएं/रोकें</translation>
+<translation id="2148716181193084225">आज</translation>
+<translation id="7960078400008666149">एक घंटे तक परेशान न करें</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> दिन</translation>
+<translation id="2190355936436201913">(खाली)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> hours left</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> सेकंड शेष</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">दाएं स्क्रॉल करें</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> घंटे शेष</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> से सूचनाएं अक्षम करें</translation>
+<translation id="2666092431469916601">शीर्ष</translation>
+<translation id="2538759511191347839">पंक्ति के अंत में ले जाएं और चयन बदलें</translation>
+<translation id="928465423150706909">पंक्ति के अंत में ले जाएं</translation>
+<translation id="8331626408530291785">ऊपर स्क्रॉल करें</translation>
+<translation id="7907591526440419938">फ़ाइल खोलें</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">फ़ोल्डर खोलें</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> घंटे पहले</translation>
+<translation id="815598010540052116">नीचे स्क्रॉल करें</translation>
+<translation id="6808150112686056157">मीडिया रोकें</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">पुनर्स्थापित करें</translation>
+<translation id="5349525451964472598">बाईं ओर ले जाएं और चयन बदलें</translation>
+<translation id="1781701194097416995">शब्द के बाईं ओर ले जाएं</translation>
+<translation id="1243314992276662751">अपलोड करें</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> दिन शेष</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">शब्द के बाईं ओर ले जाएं और चयन बदलें</translation>
+<translation id="945522503751344254">सुझाव भेजें</translation>
+<translation id="9170848237812810038">&amp;पूर्ववत् करें</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> घंटे पहले</translation>
+<translation id="6918245111648057970">प्रत्येक उपयोगकर्ता के लिए निम्न में से सूचनाओं की अनुमति दें:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> सेकंड</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> मिनट शेष</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">सेटिंग...</translation>
+<translation id="6845383723252244143">फ़ोल्डर को चुनें</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> सेकंड</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> सेकंड</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> दिन पहले</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> दिन</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/>घंटा</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> मिनट पहले
+</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> घंटे पहले</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> दिन</translation>
+<translation id="2704295676501803339">बाईं ओर ले जाएं</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> सेकंड पहले</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
+<translation id="566737009157135450">पीछे की ओर एक शब्द हटाएं</translation>
+<translation id="436869212180315161">दबाएं</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> मिनट</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> मिनट शेष</translation>
+<translation id="6040143037577758943">बंद करें</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">सहायता</translation>
+<translation id="2405367043325750948">आगे की ओर हटाएं</translation>
+<translation id="6699343763173986273">मीडिया अगला ट्रैक</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> seconds left</translation>
+<translation id="8226233771743600312">एक दिन तक परेशान न करें</translation>
+<translation id="4252565523989510616">आगे की ओर एक शब्द हटाएं</translation>
+<translation id="7457942297256758195">सभी साफ़ करें</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> दिन पहले</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> मिनट</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> days left</translation>
+<translation id="6786750046913594791">फ़ोल्डर बंद करें</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> मिनट</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> घंटे पहले</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> सेकंड</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> सेकंड</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> सेकंड</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">क्लिपबोर्ड पर प्रतिलिपि बनाएं</translation>
+<translation id="8371695176452482769">अब बोलें</translation>
+<translation id="1167268268675672572">पंक्ति के प्रारंभ में ले जाएं और चयन बदलें</translation>
+<translation id="6965382102122355670">ठीक</translation>
+<translation id="7850320739366109486">परेशान न करें</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> दिन पहले</translation>
+<translation id="5941711191222866238">छोटा करें</translation>
+<translation id="6394627529324717982">अल्पविराम</translation>
+<translation id="3036649622769666520">फ़ाइलें खोलें</translation>
+<translation id="8328145009876646418">बायां सिरा</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> सेकंड</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb
new file mode 100644
index 00000000000..11facf00507
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_hr.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+<translation id="4820616160060340806">Naredba + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mapa <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942">Preostalo sekundi: <ph name="NUMBER_FEW"/></translation>
+<translation id="9213479837033539041">Preostalo sekundi: <ph name="NUMBER_MANY"/></translation>
+<translation id="1209866192426315618">Preostalo minuta: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="1801827354178857021">Razdoblje</translation>
+<translation id="1190609913194133056">Centar za obavijesti</translation>
+<translation id="7470933019269157899">Preostalo minuta: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="5613020302032141669">Strelica lijevo</translation>
+<translation id="4971687151119236543">Prethodni zapis Medija</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Datoteka (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252">Broj sekundi: <ph name="NUMBER_TWO"/></translation>
+<translation id="7511635910912978956">Preostali sati: <ph name="NUMBER_FEW"/></translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Odustani</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Strelica prema gore</translation>
+<translation id="3969863827134279083">Premjesti prema gore</translation>
+<translation id="7062130397825382308">Preostalo <ph name="NUMBER_ONE"/> s</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928">Broj sati: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3990502903496589789">Desni rub</translation>
+<translation id="9038489124413477075">Neimenovana mapa</translation>
+<translation id="1940483897317142625">Izbriši do kraja retka</translation>
+<translation id="8507996248087185956">Broj minuta: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3520476450377425184">Preostalo dana: <ph name="NUMBER_MANY"/></translation>
+<translation id="932327136139879170">Početna stranica</translation>
+<translation id="5600907569873192868">Preostalo minuta: <ph name="NUMBER_MANY"/></translation>
+<translation id="8666066831007952346">Preostalo dana: <ph name="NUMBER_TWO"/></translation>
+<translation id="6390842777729054533">Preostalo sekundi: <ph name="NUMBER_ZERO"/></translation>
+<translation id="3909791450649380159">Iz&amp;reži</translation>
+<translation id="2560788951337264832">Preostalo minuta: <ph name="NUMBER_ZERO"/></translation>
+<translation id="688711909580084195">Web-stranica bez naslova</translation>
+<translation id="3353284378027041011">Prije <ph name="NUMBER_FEW"/> dana</translation>
+<translation id="5076340679995252485">&amp;Zalijepi</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Premjesti riječ udesno</translation>
+<translation id="364720409959344976">Odabir mape za prijenos</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Prije <ph name="NUMBER_TWO"/> minute</translation>
+<translation id="3234408098842461169">Strelica dolje</translation>
+<translation id="3087734570205094154">Donji</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">Preostalo minuta: <ph name="NUMBER_ONE"/></translation>
+<translation id="1860796786778352021">Zatvaranje obavijesti</translation>
+<translation id="6364916375976753737">Pomakni se lijevo</translation>
+<translation id="2629089419211541119">Prije <ph name="NUMBER_ONE"/> sat</translation>
+<translation id="4218160142017529598">Izbriši unatrag</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuta</translation>
+<translation id="6982279413068714821">Prije <ph name="NUMBER_DEFAULT"/> minuta</translation>
+<translation id="6945221475159498467">Odaberi</translation>
+<translation id="6620110761915583480">Spremi datoteku</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Izbriši do početka retka</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Preostalo minuta: <ph name="NUMBER_ONE"/></translation>
+<translation id="2953767478223974804">Broj minuta: <ph name="NUMBER_ONE"/></translation>
+<translation id="8210608804940886430">Stranica prema dolje</translation>
+<translation id="1572103024875503863">Broj dana: <ph name="NUMBER_MANY"/></translation>
+<translation id="7163503212501929773">Preostalo sati: <ph name="NUMBER_MANY"/></translation>
+<translation id="5329858601952122676">&amp;Obriši</translation>
+<translation id="6556866813142980365">Ponovi</translation>
+<translation id="8088823334188264070">Sekundi: <ph name="NUMBER_MANY"/></translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Danas</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478">Preostalo minuta: <ph name="NUMBER_FEW"/></translation>
+<translation id="5517291721709019259">Preostalo <ph name="NUMBER_FEW"/> s</translation>
+<translation id="6903282483217634857">Premjesti udesno</translation>
+<translation id="6659594942844771486">Kartica</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Prije <ph name="NUMBER_DEFAULT"/> dana</translation>
+<translation id="8428213095426709021">Postavke</translation>
+<translation id="2497284189126895209">Sve datoteke</translation>
+<translation id="7487278341251176613">Preostalo minuta: <ph name="NUMBER_TWO"/></translation>
+<translation id="5110450810124758964">Prije <ph name="NUMBER_ONE"/> dan</translation>
+<translation id="2820806154655529776">Broj sekundi: <ph name="NUMBER_ONE"/></translation>
+<translation id="4320177379694898372">Nema internetske veze</translation>
+<translation id="7814458197256864873">&amp;Kopiraj</translation>
+<translation id="3889424535448813030">Strelica desno</translation>
+<translation id="4229495110203539533">Prije <ph name="NUMBER_ONE"/> sekundu</translation>
+<translation id="2544782972264605588">Preostalo sekundi: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6829324100069873704">Natrag na obavijesti</translation>
+<translation id="6528179044667508675">Ne ometaj</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundi</translation>
+<translation id="290555789621781773">Broj minuta: <ph name="NUMBER_TWO"/></translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Omogućite obavijesti iz sljedećih izvora:</translation>
+<translation id="2479520428668657293">Premjesti udesno i izmijeni odabir</translation>
+<translation id="8112886015144590373">Broj sati: <ph name="NUMBER_FEW"/></translation>
+<translation id="1398853756734560583">Maksimiziraj</translation>
+<translation id="4250229828105606438">Snimka zaslona</translation>
+<translation id="6690744523875189208">Broj sati: <ph name="NUMBER_TWO"/></translation>
+<translation id="5260878308685146029">Preostalo minuta: <ph name="NUMBER_TWO"/></translation>
+<translation id="2557207087669398617">Premjesti na početak retka</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Odaberi &amp;sve</translation>
+<translation id="2168039046890040389">Stranica prema gore</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581">Broj dana: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734">Broj minuta: <ph name="NUMBER_MANY"/></translation>
+<translation id="6122334925474904337">Premjesti riječ udesno i izmijeni odabir</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Nema nikakvih obavijesti.</translation>
+<translation id="2482878487686419369">Obavijesti</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Pomakni ovdje</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Premjesti dolje</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401">Sati: <ph name="NUMBER_MANY"/></translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Reproduciraj/pauziraj Medije</translation>
+<translation id="2148716181193084225">Danas</translation>
+<translation id="7960078400008666149">Ne ometaj jedan sat</translation>
+<translation id="4373894838514502496">Prije <ph name="NUMBER_FEW"/> min</translation>
+<translation id="4115153316875436289">Dana: <ph name="NUMBER_TWO"/></translation>
+<translation id="2190355936436201913">(prazno)</translation>
+<translation id="1164369517022005061">Preostalo sati: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="152482086482215392">Preostalo sekundi: <ph name="NUMBER_ONE"/></translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Pomakni se desno</translation>
+<translation id="7414887922320653780">Preostalo sati: <ph name="NUMBER_ONE"/></translation>
+<translation id="1413622004203049571">Onemogući obavijesti pošiljatelja <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Gornji</translation>
+<translation id="2538759511191347839">Premjesti na kraj retka i izmijeni odabir</translation>
+<translation id="928465423150706909">Premjesti na kraj retka</translation>
+<translation id="8331626408530291785">Pomakni se gore</translation>
+<translation id="7907591526440419938">Otvori datoteku</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Otvori mapu</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Prije <ph name="NUMBER_DEFAULT"/> sati</translation>
+<translation id="815598010540052116">Pomakni se dolje</translation>
+<translation id="6808150112686056157">Zaustavi Medije</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Vrati</translation>
+<translation id="5349525451964472598">Premjesti ulijevo i izmijeni odabir</translation>
+<translation id="1781701194097416995">Premjesti riječ ulijevo</translation>
+<translation id="1243314992276662751">Prenesi</translation>
+<translation id="50030952220075532">Preostalo dana: <ph name="NUMBER_ONE"/></translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Premjesti riječ ulijevo i izmijeni odabir</translation>
+<translation id="945522503751344254">Slanje povratnih informacija</translation>
+<translation id="9170848237812810038">&amp;Poništi</translation>
+<translation id="1285266685456062655">Prije <ph name="NUMBER_FEW"/> sata</translation>
+<translation id="6918245111648057970">Za svakog korisnika dozvoli obavijesti sljedećih usluga:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">Preostalo minuta: <ph name="NUMBER_MANY"/></translation>
+<translation id="6358975074282722691">Prije <ph name="NUMBER_TWO"/> sekunde</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Postavke...</translation>
+<translation id="6845383723252244143">Odabir mape</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunde</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396">Broj sekundi: <ph name="NUMBER_FEW"/></translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920">Broj dana: <ph name="NUMBER_FEW"/></translation>
+<translation id="5116333507878097773">Broj sati: <ph name="NUMBER_ONE"/></translation>
+<translation id="2679312662830811292">Prije <ph name="NUMBER_ONE"/> minutu</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>dan</translation>
+<translation id="2704295676501803339">Premjesti ulijevo</translation>
+<translation id="9098468523912235228">Prije <ph name="NUMBER_DEFAULT"/> sekundi</translation>
+<translation id="494645311413743213">Preostalo sekundi <ph name="NUMBER_TWO"/></translation>
+<translation id="566737009157135450">Izbriši prethodnu riječ</translation>
+<translation id="436869212180315161">Pritisnite</translation>
+<translation id="4860787810836767172">Prije <ph name="NUMBER_FEW"/> sek</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">Preostalo minuta: <ph name="NUMBER_FEW"/></translation>
+<translation id="6040143037577758943">Zatvori</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Pomoć</translation>
+<translation id="2405367043325750948">Izbriši prema naprijed</translation>
+<translation id="6699343763173986273">Sljedeći zapis Medija</translation>
+<translation id="5445120697129764393">Preostalo <ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="8226233771743600312">Ne ometaj jedan dan</translation>
+<translation id="4252565523989510616">Izbriši sljedeću riječ</translation>
+<translation id="7457942297256758195">Očisti sve</translation>
+<translation id="822618367988303761">Prije <ph name="NUMBER_TWO"/> dana</translation>
+<translation id="4745438305783437565">Broj minuta: <ph name="NUMBER_FEW"/></translation>
+<translation id="1963692530539281474">Preostalo dana: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6786750046913594791">Zatvori mapu</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
+<translation id="5906719743126878045">Preostalo sati: <ph name="NUMBER_TWO"/></translation>
+<translation id="8959208747503200525">Prije <ph name="NUMBER_TWO"/> sata</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940">Sekundi: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="4197700912384709145">Sekundi: <ph name="NUMBER_ZERO"/></translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382">Preostalo dana: <ph name="NUMBER_FEW"/></translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopiraj u međuspremnik</translation>
+<translation id="8371695176452482769">Govorite sad</translation>
+<translation id="1167268268675672572">Pomakni na početak retka i izmijeni odabir</translation>
+<translation id="6965382102122355670">U redu</translation>
+<translation id="7850320739366109486">Ne ometaj</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimiziraj</translation>
+<translation id="6394627529324717982">Zarez</translation>
+<translation id="3036649622769666520">Otvori datoteke</translation>
+<translation id="8328145009876646418">Lijevi rub</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb
new file mode 100644
index 00000000000..b306ff542fa
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_hu.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> mappa</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Befejezés</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> másodperc van hátra</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> másodperc van hátra</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> perc van hátra</translation>
+<translation id="1801827354178857021">Időszak</translation>
+<translation id="1190609913194133056">Értesítési központ</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> perc van hátra</translation>
+<translation id="5613020302032141669">Bal nyíl</translation>
+<translation id="4971687151119236543">Előző szám</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> fájl (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> másodperc</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> óra van hátra</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Mégse</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> bájt</translation>
+<translation id="3660179305079774227">Felfelé nyíl</translation>
+<translation id="3969863827134279083">Fel</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> másodperc van hátra</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> óra</translation>
+<translation id="3990502903496589789">Jobb sarok</translation>
+<translation id="9038489124413477075">Név nélküli mappa</translation>
+<translation id="1940483897317142625">Törlés a sor végéig</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> perc</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> nap van hátra</translation>
+<translation id="932327136139879170">Főoldal</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> perc van hátra</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> nap van hátra</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> másodperc van hátra</translation>
+<translation id="3909791450649380159">Ki&amp;vágás</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> perc van hátra</translation>
+<translation id="688711909580084195">Névtelen weboldal</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Beillesztés</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Egy szóval jobbra</translation>
+<translation id="364720409959344976">Mappa kiválasztása a feltöltéshez</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Lefelé nyíl</translation>
+<translation id="3087734570205094154">Alja</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> perc van hátra</translation>
+<translation id="1860796786778352021">Értesítés bezárása</translation>
+<translation id="6364916375976753737">Görgetés balra</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> órája</translation>
+<translation id="4218160142017529598">Törlés visszafelé</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> perc</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> perce</translation>
+<translation id="6945221475159498467">Kiválasztás</translation>
+<translation id="6620110761915583480">Fájl mentése</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> másodperc</translation>
+<translation id="8924469368910458384">Törlés a sor elejéig</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> perc van hátra</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> perc</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> nap</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> óra van hátra</translation>
+<translation id="5329858601952122676">&amp;Törlés</translation>
+<translation id="6556866813142980365">Újra</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> másodperc</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> perc</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Tegnap</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> perc</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> perc van hátra</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Jobbra</translation>
+<translation id="6659594942844771486">Lap</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> napja</translation>
+<translation id="8428213095426709021">Beállítások</translation>
+<translation id="2497284189126895209">Minden fájl</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> perc van hátra</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> napja</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> másodperc</translation>
+<translation id="4320177379694898372">Nincs internetkapcsolat</translation>
+<translation id="7814458197256864873">&amp;Másolás</translation>
+<translation id="3889424535448813030">Jobb nyíl</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> másodperce</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> másodperc van hátra</translation>
+<translation id="6829324100069873704">Vissza az értesítésekhez</translation>
+<translation id="6528179044667508675">Ne zavarj</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> másodperc</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> perc</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Értesítések engedélyezése a következőtől:</translation>
+<translation id="2479520428668657293">Jobbra és kijelölés módosítása</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> óra</translation>
+<translation id="1398853756734560583">Teljes méret</translation>
+<translation id="4250229828105606438">Képernyőkép</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> óra</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> perc van hátra</translation>
+<translation id="2557207087669398617">Sor elejére</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Össz&amp;es kiválasztása</translation>
+<translation id="2168039046890040389">Oldal fel</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> nap</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> perc</translation>
+<translation id="6122334925474904337">Egy szóval jobbra és kijelölés módosítása</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> perc</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Itt nincs semmi, továbbmehet.</translation>
+<translation id="2482878487686419369">Értesítések</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Görgessen ide</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Le</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> óra</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Lejátszás/szüneteltetés</translation>
+<translation id="2148716181193084225">Ma</translation>
+<translation id="7960078400008666149">Ne zavarj egy óráig</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> nap</translation>
+<translation id="2190355936436201913">(üres)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> óra van hátra</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> másodperc van hátra</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Görgetés jobbra</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> óra van hátra</translation>
+<translation id="1413622004203049571">A(z) <ph name="NOTIFIER_NAME"/> értesítéseinek kikapcsolása</translation>
+<translation id="2666092431469916601">Felülre</translation>
+<translation id="2538759511191347839">Sor végére és kijelölés módosítása</translation>
+<translation id="928465423150706909">Sor végére</translation>
+<translation id="8331626408530291785">Görgetés felfelé</translation>
+<translation id="7907591526440419938">Fájl megnyitása</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Mappa megnyitása</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> órája</translation>
+<translation id="815598010540052116">Görgetés lefelé</translation>
+<translation id="6808150112686056157">Leállítás</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Visszaállítás</translation>
+<translation id="5349525451964472598">Lefelé és kijelölés módosítása</translation>
+<translation id="1781701194097416995">Egy szóval lefelé</translation>
+<translation id="1243314992276662751">Feltöltés</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> nap van hátra</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Egy szóval balra és kijelölés módosítása</translation>
+<translation id="945522503751344254">Visszajelzés küldése</translation>
+<translation id="9170848237812810038">&amp;Visszavonás</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Értesítések engedélyezése mindegyik felhasználónak a következőtől:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> másodperc</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> perc van hátra</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Beállítások...</translation>
+<translation id="6845383723252244143">Mappa választása</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> másodperc</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> másodperc</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> nap</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> óra</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> perce</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> nap</translation>
+<translation id="2704295676501803339">Balra</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> másodperce</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> másodperc van hátra.</translation>
+<translation id="566737009157135450">Szó törlése visszafelé</translation>
+<translation id="436869212180315161">Sajtó</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> perc</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> perc van hátra</translation>
+<translation id="6040143037577758943">Bezárás</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Súgó</translation>
+<translation id="2405367043325750948">Törlés előrefelé</translation>
+<translation id="6699343763173986273">Következő szám</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> másodperc van hátra</translation>
+<translation id="8226233771743600312">Ne zavarj egy napig</translation>
+<translation id="4252565523989510616">Szó törlése előrefelé</translation>
+<translation id="7457942297256758195">Összes törlése</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> perc</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> nap van hátra</translation>
+<translation id="6786750046913594791">Mappa bezárása</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> perc</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> óra van hátra</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> másodperc</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> másodperc</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> másodperc</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> nap van hátra</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Másolás a vágólapra</translation>
+<translation id="8371695176452482769">Most beszéljen</translation>
+<translation id="1167268268675672572">Sor elejére és kijelölés módosítása</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Ne zavarj</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Kicsinyítés</translation>
+<translation id="6394627529324717982">Vessző</translation>
+<translation id="3036649622769666520">Fájlok megnyitása</translation>
+<translation id="8328145009876646418">Bal sarok</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> másodperc</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb
new file mode 100644
index 00000000000..62ee3841735
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_id.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Berakhir</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> jam yang lalu</translation>
+<translation id="6310545596129886942">Tersisa <ph name="NUMBER_FEW"/> detik</translation>
+<translation id="9213479837033539041">Tersisa <ph name="NUMBER_MANY"/> detik</translation>
+<translation id="1209866192426315618">Tersisa <ph name="NUMBER_DEFAULT"/> menit</translation>
+<translation id="1801827354178857021">Periode</translation>
+<translation id="1190609913194133056">Pusat Pemberitahuan</translation>
+<translation id="7470933019269157899">Tersisa <ph name="NUMBER_DEFAULT"/> menit</translation>
+<translation id="5613020302032141669">Panah Kiri</translation>
+<translation id="4971687151119236543">Lacak Media Sebelumnya</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> File (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> detik</translation>
+<translation id="7511635910912978956">Tersisa <ph name="NUMBER_FEW"/> jam</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Batal</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Panah Atas</translation>
+<translation id="3969863827134279083">Pindah ke Atas</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> detik lagi</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/dtk</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> jam</translation>
+<translation id="3990502903496589789">Tepi Kanan</translation>
+<translation id="9038489124413477075">Folder Tanpa Nama</translation>
+<translation id="1940483897317142625">Hapus Sampai Akhir Baris</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> menit</translation>
+<translation id="3520476450377425184">Tersisa <ph name="NUMBER_MANY"/> hari</translation>
+<translation id="932327136139879170">Beranda</translation>
+<translation id="5600907569873192868">Tersisa <ph name="NUMBER_MANY"/> menit</translation>
+<translation id="8666066831007952346">Tersisa <ph name="NUMBER_TWO"/> hari</translation>
+<translation id="6390842777729054533">Tersisa <ph name="NUMBER_ZERO"/> detik</translation>
+<translation id="3909791450649380159">Po&amp;tong</translation>
+<translation id="2560788951337264832">Tersisa <ph name="NUMBER_ZERO"/> menit</translation>
+<translation id="688711909580084195">Laman Web Tanpa Judul</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> hari yang lalu</translation>
+<translation id="5076340679995252485">Tem&amp;pel</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Pindahkan ke Kanan Kata</translation>
+<translation id="364720409959344976">Pilih Folder untuk Diunggah</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mnt. yang lalu</translation>
+<translation id="3234408098842461169">Panah Bawah</translation>
+<translation id="3087734570205094154">Bawah</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">Tersisa <ph name="NUMBER_ONE"/> menit</translation>
+<translation id="1860796786778352021">Tutup pemberitahuan</translation>
+<translation id="6364916375976753737">Gulir ke Kiri</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> jam yang lalu</translation>
+<translation id="4218160142017529598">Hapus dari Belakang</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> menit</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mnt. yang lalu</translation>
+<translation id="6945221475159498467">Pilih</translation>
+<translation id="6620110761915583480">Simpan File</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> detik</translation>
+<translation id="8924469368910458384">Hapus Sampai Awal Baris</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Tersisa <ph name="NUMBER_ONE"/> menit</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> menit</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> hari</translation>
+<translation id="7163503212501929773">Tersisa <ph name="NUMBER_MANY"/> jam</translation>
+<translation id="5329858601952122676">&amp;Hapus</translation>
+<translation id="6556866813142980365">Urungkan</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> detik</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> menit</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> dtk. yang lalu</translation>
+<translation id="7781829728241885113">Kemarin</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> menit</translation>
+<translation id="50960180632766478">Tersisa <ph name="NUMBER_FEW"/> menit</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Pindah ke Kanan</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> hari yang lalu</translation>
+<translation id="8428213095426709021">Setelan</translation>
+<translation id="2497284189126895209">Semua Jenis File</translation>
+<translation id="7487278341251176613">Tersisa <ph name="NUMBER_TWO"/> menit</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> hari yang lalu</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> detik</translation>
+<translation id="4320177379694898372">Tidak ada sambungan internet</translation>
+<translation id="7814458197256864873">&amp;Salin</translation>
+<translation id="3889424535448813030">Panah Kanan</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> dtk. yang lalu</translation>
+<translation id="2544782972264605588">Tersisa <ph name="NUMBER_DEFAULT"/> detik</translation>
+<translation id="6829324100069873704">Kembali ke pemberitahuan</translation>
+<translation id="6528179044667508675">Jangan ganggu</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> detik</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> menit</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Izinkan pemberitahuan dari yang berikut:</translation>
+<translation id="2479520428668657293">Pindah ke Kanan dan Ubah Pilihan</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> jam</translation>
+<translation id="1398853756734560583">Perbesar</translation>
+<translation id="4250229828105606438">Tangkapan layar</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> jam</translation>
+<translation id="5260878308685146029">Tersisa <ph name="NUMBER_TWO"/> menit</translation>
+<translation id="2557207087669398617">Pindah ke Awal Baris</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Pilih semu&amp;a</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> hari</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> menit</translation>
+<translation id="6122334925474904337">Pindah ke Kanan Kata dan Ubah Pilihan</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> menit</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> dtk. yang lalu</translation>
+<translation id="4927753642311223124">Tidak ada apa-apa di sini, lihat yang lain saja.</translation>
+<translation id="2482878487686419369">Pemberitahuan</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Gulir ke Sini</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Turunkan</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> jam</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/dtk</translation>
+<translation id="8394908167088220973">Putar/Jeda Media</translation>
+<translation id="2148716181193084225">Hari ini</translation>
+<translation id="7960078400008666149">Jangan ganggu selama satu jam</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mnt. yang lalu</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> hari</translation>
+<translation id="2190355936436201913">(kosong)</translation>
+<translation id="1164369517022005061">Tersisa <ph name="NUMBER_DEFAULT"/> jam</translation>
+<translation id="152482086482215392">Tersisa <ph name="NUMBER_ONE"/> detik</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Gulir ke Kanan</translation>
+<translation id="7414887922320653780">Tersisa <ph name="NUMBER_ONE"/> jam</translation>
+<translation id="1413622004203049571">Nonaktifkan pemberitahuan dari <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Atas</translation>
+<translation id="2538759511191347839">Pindah ke Akhir Baris dan Ubah Pilihan</translation>
+<translation id="928465423150706909">Pindah ke Akhir Baris</translation>
+<translation id="8331626408530291785">Gulir ke Atas</translation>
+<translation id="7907591526440419938">Buka File</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Buka folder</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> jam yang lalu</translation>
+<translation id="815598010540052116">Gulir ke Bawah</translation>
+<translation id="6808150112686056157">Hentikan Media</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Pulihkan</translation>
+<translation id="5349525451964472598">Pindah ke Kiri dan Ubah Pilihan</translation>
+<translation id="1781701194097416995">Pindah ke Kiri Kata</translation>
+<translation id="1243314992276662751">Unggah</translation>
+<translation id="50030952220075532">Tersisa <ph name="NUMBER_ONE"/> hari</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Pindah ke Kiri Kata dan Ubah Pilihan</translation>
+<translation id="945522503751344254">Kirim masukan</translation>
+<translation id="9170848237812810038">&amp;Urung</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> jam yang lalu</translation>
+<translation id="6918245111648057970">Mengizinkan pemberitahuan dari yang berikut untuk tiap pengguna:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> detik</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">Tersisa <ph name="NUMBER_MANY"/> menit</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> dtk. yang lalu</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Setelan...</translation>
+<translation id="6845383723252244143">Pilih Folder</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> detik</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> detik</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> hari yang lalu</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> hari</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> jam</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> mnt. yang lalu</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/dtk</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> hari</translation>
+<translation id="2704295676501803339">Pindah ke Kiri</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> dtk. yang lalu</translation>
+<translation id="494645311413743213">Tersisa <ph name="NUMBER_TWO"/> detik</translation>
+<translation id="566737009157135450">Hapus dari Belakang Per Kata</translation>
+<translation id="436869212180315161">Tekan</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> dtk. yang lalu</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/dtk</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> menit</translation>
+<translation id="1858722859751911017">Tersisa <ph name="NUMBER_FEW"/> menit</translation>
+<translation id="6040143037577758943">Tutup</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mnt. yang lalu</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/dtk</translation>
+<translation id="7649070708921625228">Bantuan</translation>
+<translation id="2405367043325750948">Hapus dari Depan</translation>
+<translation id="6699343763173986273">Lacak Media Berikutnya</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> detik lagi</translation>
+<translation id="8226233771743600312">Jangan ganggu selama satu hari</translation>
+<translation id="4252565523989510616">Hapus dari Depan Per Kata</translation>
+<translation id="7457942297256758195">Hapus Semua</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> hari yang lalu</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> menit</translation>
+<translation id="1963692530539281474">Tersisa <ph name="NUMBER_DEFAULT"/> hari</translation>
+<translation id="6786750046913594791">Tutup folder</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> menit</translation>
+<translation id="5906719743126878045">Tersisa <ph name="NUMBER_TWO"/> jam</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> jam yang lalu</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> detik</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> detik</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> detik</translation>
+<translation id="3759876923365568382">Tersisa <ph name="NUMBER_FEW"/> hari</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/dtk</translation>
+<translation id="2743387203779672305">Salin ke papan klip</translation>
+<translation id="8371695176452482769">Bicaralah sekarang</translation>
+<translation id="1167268268675672572">Pindah ke Awal Baris dan Ubah Pilihan</translation>
+<translation id="6965382102122355670">Oke</translation>
+<translation id="7850320739366109486">Jangan Ganggu</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Perkecil</translation>
+<translation id="6394627529324717982">Koma</translation>
+<translation id="3036649622769666520">Buka File</translation>
+<translation id="8328145009876646418">Tepi Kiri</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> detik</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb
new file mode 100644
index 00000000000..605e7b37be0
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_it.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Cartella <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Canc</translation>
+<translation id="528468243742722775">Fine</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> ore fa</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sec. rimanenti</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sec. rimanenti</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min. rimanenti</translation>
+<translation id="1801827354178857021">Periodo</translation>
+<translation id="1190609913194133056">Centro notifiche</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuti rimanenti</translation>
+<translation id="5613020302032141669">Freccia sinistra</translation>
+<translation id="4971687151119236543">Traccia precedente contenuti multimediali</translation>
+<translation id="8602707065186045623">File <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sec.</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ore rimanenti</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Annulla</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Freccia SU</translation>
+<translation id="3969863827134279083">Sposta su</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> secondo rimasto</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ore</translation>
+<translation id="3990502903496589789">Margine destro</translation>
+<translation id="9038489124413477075">Cartella senza nome</translation>
+<translation id="1940483897317142625">Elimina fino a fine riga</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> giorni rimanenti</translation>
+<translation id="932327136139879170">Home page</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min. rimanenti</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> giorni rimanenti</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sec. rimanenti</translation>
+<translation id="3909791450649380159">T&amp;aglia</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Pagina web senza titolo</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> giorni fa</translation>
+<translation id="5076340679995252485">&amp;Incolla</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Sposta di una parola a destra</translation>
+<translation id="364720409959344976">Seleziona la cartella da caricare</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuti fa</translation>
+<translation id="3234408098842461169">Freccia GIÙ</translation>
+<translation id="3087734570205094154">In basso</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> secondi rimasti</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min. rimanente</translation>
+<translation id="1860796786778352021">Chiusura notifica</translation>
+<translation id="6364916375976753737">Scorri a sinistra</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ora fa</translation>
+<translation id="4218160142017529598">Elimina indietro</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuti</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuti fa</translation>
+<translation id="6945221475159498467">Seleziona</translation>
+<translation id="6620110761915583480">Salva file</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> secondi</translation>
+<translation id="8924469368910458384">Elimina fino a inizio riga</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto rimanente</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8210608804940886430">Pagina giù</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> giorni</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ore rimanenti</translation>
+<translation id="5329858601952122676">&amp;Elimina</translation>
+<translation id="6556866813142980365">Ripeti</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sec.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secondi fa</translation>
+<translation id="7781829728241885113">Ieri</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min. rimanenti</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> secondi rimasti</translation>
+<translation id="6903282483217634857">Sposta a destra</translation>
+<translation id="6659594942844771486">TAB</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> giorni fa</translation>
+<translation id="8428213095426709021">Impostazioni</translation>
+<translation id="2497284189126895209">Tutti i file</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> giorno fa</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec.</translation>
+<translation id="4320177379694898372">Nessuna connessione Internet</translation>
+<translation id="7814458197256864873">&amp;Copia</translation>
+<translation id="3889424535448813030">Freccia destra</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> secondo fa</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sec. rimanenti</translation>
+<translation id="6829324100069873704">Torna alle notifiche</translation>
+<translation id="6528179044667508675">Non disturbare</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secondi</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Consenti notifiche da:</translation>
+<translation id="2479520428668657293">Sposta a destra e modifica selezione</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ore</translation>
+<translation id="1398853756734560583">Ingrandisci</translation>
+<translation id="4250229828105606438">Screenshot</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ore</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min. rimanenti</translation>
+<translation id="2557207087669398617">Sposta fino a inizio riga</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Seleziona &amp;tutto</translation>
+<translation id="2168039046890040389">Pagina su</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> giorni</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6122334925474904337">Sposta di una parola a destra e modifica selezione</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secondi fa</translation>
+<translation id="4927753642311223124">Nessuna notifica.</translation>
+<translation id="2482878487686419369">Notifiche</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Scorri fino a qui</translation>
+<translation id="4552416320897244156">PGGIÙ</translation>
+<translation id="3066573403916685335">Sposta giù</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ore</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Play/Pausa contenuti multimediali</translation>
+<translation id="2148716181193084225">Oggi</translation>
+<translation id="7960078400008666149">Non disturbare per un'ora</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuti fa</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> giorni</translation>
+<translation id="2190355936436201913">(vuoto)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ore rimanenti</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec. rimanente</translation>
+<translation id="8447116497070723931">PGSU</translation>
+<translation id="4588090240171750605">Scorri a destra</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ora rimanente</translation>
+<translation id="1413622004203049571">Disabilita notifiche da <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">In alto</translation>
+<translation id="2538759511191347839">Sposta fino a fine riga e modifica selezione</translation>
+<translation id="928465423150706909">Sposta fino a fine riga</translation>
+<translation id="8331626408530291785">Scorri verso l'alto</translation>
+<translation id="7907591526440419938">Apri file</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Apri cartella</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ore fa</translation>
+<translation id="815598010540052116">Scorri verso il basso</translation>
+<translation id="6808150112686056157">Interrompi contenuti multimediali</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Ripristina</translation>
+<translation id="5349525451964472598">Sposta a sinistra e modifica selezione</translation>
+<translation id="1781701194097416995">Sposta di una parola a sinistra</translation>
+<translation id="1243314992276662751">Carica</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> giorno rimanente</translation>
+<translation id="8179976553408161302">Invio</translation>
+<translation id="8471049483003785219">Sposta di una parola a sinistra e modifica selezione</translation>
+<translation id="945522503751344254">Invia feedback</translation>
+<translation id="9170848237812810038">&amp;Annulla</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ore fa</translation>
+<translation id="6918245111648057970">Consenti a ogni utente di ricevere le notifiche di:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> secondo</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> secondi rimasti</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secondi fa</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Impostazioni...</translation>
+<translation id="6845383723252244143">Seleziona cartella</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> secondi rimasti</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sec.</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> giorni fa</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> giorni</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ora</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto fa</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> giorno</translation>
+<translation id="2704295676501803339">Sposta a sinistra</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secondi fa</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sec. rimanenti</translation>
+<translation id="566737009157135450">Elimina una parola indietro</translation>
+<translation id="436869212180315161">Premi</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secondi fa</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Chiudi</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuti fa</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Guida</translation>
+<translation id="2405367043325750948">Elimina avanti</translation>
+<translation id="6699343763173986273">Traccia successiva contenuti multimediali</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> secondi rimasti</translation>
+<translation id="8226233771743600312">Non disturbare per un giorno</translation>
+<translation id="4252565523989510616">Elimina una parola avanti</translation>
+<translation id="7457942297256758195">Cancella tutto</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> giorni fa</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> giorni rimanenti</translation>
+<translation id="6786750046913594791">Chiudi cartella</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ore rimanenti</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> ore fa</translation>
+<translation id="8400147561352026160">Maiusc+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sec.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sec.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> giorni rimanenti</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copia negli appunti</translation>
+<translation id="8371695176452482769">Parla adesso</translation>
+<translation id="1167268268675672572">Sposta fino a inizio riga e modifica selezione</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Non disturbare</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Riduci a icona</translation>
+<translation id="6394627529324717982">Virgola</translation>
+<translation id="3036649622769666520">Apri file</translation>
+<translation id="8328145009876646418">Margine sinistro</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb
new file mode 100644
index 00000000000..e00b11c3f66
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_iw.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="iw">
+<translation id="4820616160060340806">פקודה+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">תיקייה <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798">לפני <ph name="NUMBER_MANY"/> שעות</translation>
+<translation id="6310545596129886942">נותרו <ph name="NUMBER_FEW"/> שניות</translation>
+<translation id="9213479837033539041">נותרו <ph name="NUMBER_MANY"/> שניות</translation>
+<translation id="1209866192426315618">נותרו <ph name="NUMBER_DEFAULT"/> דקות</translation>
+<translation id="1801827354178857021">תקופה</translation>
+<translation id="1190609913194133056">מרכז התראות</translation>
+<translation id="7470933019269157899">נותרו <ph name="NUMBER_DEFAULT"/> דקות</translation>
+<translation id="5613020302032141669">חץ לשמאל</translation>
+<translation id="4971687151119236543">רצועה קודמת במדיה</translation>
+<translation id="8602707065186045623">קובץ <ph name="SAVEAS_EXTENSION_TYPE"/> (<ph name="SAVEAS_EXTENSION_NAME"/>.)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> שניות</translation>
+<translation id="7511635910912978956">נותרו <ph name="NUMBER_FEW"/> שעות</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">ביטול</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">חץ למעלה</translation>
+<translation id="3969863827134279083">עלה למעלה</translation>
+<translation id="7062130397825382308">נותרה שנייה <ph name="NUMBER_ONE"/></translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> שעות</translation>
+<translation id="3990502903496589789">קצה ימני</translation>
+<translation id="9038489124413477075">תיקייה ללא שם</translation>
+<translation id="1940483897317142625">מחק עד סוף השורה</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> דקות</translation>
+<translation id="3520476450377425184">נותרו <ph name="NUMBER_MANY"/> ימים</translation>
+<translation id="932327136139879170">בית</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> דקות נותרו</translation>
+<translation id="8666066831007952346">נותרו <ph name="NUMBER_TWO"/> ימים</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> שניות נותרו</translation>
+<translation id="3909791450649380159">גז&amp;ור</translation>
+<translation id="2560788951337264832">נותרו <ph name="NUMBER_ZERO"/> דקות</translation>
+<translation id="688711909580084195">דף אינטרנט ללא כותרת</translation>
+<translation id="3353284378027041011">לפני <ph name="NUMBER_FEW"/> ימים</translation>
+<translation id="5076340679995252485">&amp;הדבק</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">עבור ימינה למילה</translation>
+<translation id="364720409959344976">בחירת תיקיה להעלאה</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">לפני <ph name="NUMBER_TWO"/> דקות</translation>
+<translation id="3234408098842461169">חץ למטה</translation>
+<translation id="3087734570205094154">תחתית</translation>
+<translation id="8828991073132329143">נותרו <ph name="NUMBER_MANY"/> שניות</translation>
+<translation id="5935630983280450497">נותרה <ph name="NUMBER_ONE"/> דקה</translation>
+<translation id="1860796786778352021">סגירת הודעה</translation>
+<translation id="6364916375976753737">גלול שמאלה</translation>
+<translation id="2629089419211541119">לפני <ph name="NUMBER_ONE"/> שעה</translation>
+<translation id="4218160142017529598">מחק לאחור</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> דקות</translation>
+<translation id="6982279413068714821">לפני <ph name="NUMBER_DEFAULT"/> דקות</translation>
+<translation id="6945221475159498467">בחר</translation>
+<translation id="6620110761915583480">שמור קובץ</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> שניות</translation>
+<translation id="8924469368910458384">מחק עד תחילת השורה</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">נותרה דקה <ph name="NUMBER_ONE"/></translation>
+<translation id="2953767478223974804">דקה <ph name="NUMBER_ONE"/></translation>
+<translation id="8210608804940886430">דף למטה</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ימים</translation>
+<translation id="7163503212501929773">נותרו <ph name="NUMBER_MANY"/> שעות</translation>
+<translation id="5329858601952122676">&amp;מחק</translation>
+<translation id="6556866813142980365">בצע מחדש</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> שניות</translation>
+<translation id="8901569739625249689">‏<ph name="QUANTITY"/> KB‏</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> דקות</translation>
+<translation id="7275974018215686543">לפני <ph name="NUMBER_MANY"/> שניות</translation>
+<translation id="7781829728241885113">אתמול</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> דקות</translation>
+<translation id="50960180632766478">נותרו <ph name="NUMBER_FEW"/> דקות</translation>
+<translation id="5517291721709019259">נותרו <ph name="NUMBER_FEW"/> שניות</translation>
+<translation id="6903282483217634857">עבור ימינה</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">לפני <ph name="NUMBER_DEFAULT"/> ימים</translation>
+<translation id="8428213095426709021">הגדרות</translation>
+<translation id="2497284189126895209">כל הקבצים</translation>
+<translation id="7487278341251176613">נותרו <ph name="NUMBER_TWO"/> דקות</translation>
+<translation id="5110450810124758964">לפני <ph name="NUMBER_ONE"/> ימים</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> שניה</translation>
+<translation id="4320177379694898372">אין חיבור לאינטרנט</translation>
+<translation id="7814458197256864873">&amp;העתק</translation>
+<translation id="3889424535448813030">חץ לימין</translation>
+<translation id="4229495110203539533">לפני <ph name="NUMBER_ONE"/> שניות</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> שניות נותרו</translation>
+<translation id="6829324100069873704">חזור להודעות</translation>
+<translation id="6528179044667508675">נא לא להפריע</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> שניות</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> דקות</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">אפשר התראות ממקורות אלה:</translation>
+<translation id="2479520428668657293">עבור ימינה ושנה את הבחירה</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> שעות</translation>
+<translation id="1398853756734560583">הגדל</translation>
+<translation id="4250229828105606438">צילום מסך</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> שעות</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> דקות נותרו</translation>
+<translation id="2557207087669398617">עבור לתחילת השורה</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">בחר &amp;הכל</translation>
+<translation id="2168039046890040389">דף למעלה</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ימים</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> דקות</translation>
+<translation id="6122334925474904337">עבור ימינה למילה ושנה את הבחירה</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> דקה</translation>
+<translation id="8448317557906454022">לפני <ph name="NUMBER_ZERO"/> שניות</translation>
+<translation id="4927753642311223124">אין התראות להצגה, המשך הלאה.</translation>
+<translation id="2482878487686419369">התראות</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">גלול ל'כאן'</translation>
+<translation id="4552416320897244156">דף למטה</translation>
+<translation id="3066573403916685335">רד למטה</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> שעות</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s‎</translation>
+<translation id="8394908167088220973">הפעלה/השהיה של המדיה</translation>
+<translation id="2148716181193084225">היום</translation>
+<translation id="7960078400008666149">נא לא להפריע למשך שעה</translation>
+<translation id="4373894838514502496">לפני <ph name="NUMBER_FEW"/> דקות</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ימים</translation>
+<translation id="2190355936436201913">(ריק)</translation>
+<translation id="1164369517022005061">נותרו <ph name="NUMBER_DEFAULT"/> שעות</translation>
+<translation id="152482086482215392">נותרה שנייה <ph name="NUMBER_ONE"/></translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">גלול ימינה</translation>
+<translation id="7414887922320653780">נותרו <ph name="NUMBER_ONE"/> שעות</translation>
+<translation id="1413622004203049571">השבת הודעות מאת <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">למעלה</translation>
+<translation id="2538759511191347839">עבור לסוף השורה ושנה את הבחירה</translation>
+<translation id="928465423150706909">עבור לסוף השורה</translation>
+<translation id="8331626408530291785">גלול למעלה</translation>
+<translation id="7907591526440419938">פתח קובץ</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">פתח את התיקייה</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">לפני <ph name="NUMBER_DEFAULT"/> שעות</translation>
+<translation id="815598010540052116">גלול למטה</translation>
+<translation id="6808150112686056157">עצור מדיה</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">שחזר</translation>
+<translation id="5349525451964472598">עבור שמאלה ושנה את הבחירה</translation>
+<translation id="1781701194097416995">עבור שמאלה למילה</translation>
+<translation id="1243314992276662751">העלה</translation>
+<translation id="50030952220075532">נותר יום <ph name="NUMBER_ONE"/></translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">עבור שמאלה למילה ושנה את הבחירה</translation>
+<translation id="945522503751344254">שלח משוב</translation>
+<translation id="9170848237812810038">&amp;ביטול</translation>
+<translation id="1285266685456062655">לפני <ph name="NUMBER_FEW"/> שעות</translation>
+<translation id="6918245111648057970">אפשר קבלת הודעות מהגורמים הבאים עבור כל משתמש:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> שנייה</translation>
+<translation id="1270251962578273213">נותרו <ph name="NUMBER_TWO"/> שניות</translation>
+<translation id="3994835489895548312">נותרו <ph name="NUMBER_MANY"/> דקות</translation>
+<translation id="6358975074282722691">לפני <ph name="NUMBER_TWO"/> שניות</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">הגדרות...</translation>
+<translation id="6845383723252244143">בחר תיקייה</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> שניות</translation>
+<translation id="5368780922436099921">נותרו <ph name="NUMBER_ZERO"/> שניות</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> שניות</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">לפני <ph name="NUMBER_MANY"/> ימים</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ימים</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> שעה</translation>
+<translation id="2679312662830811292">לפני <ph name="NUMBER_ONE"/> דקות</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405">יום <ph name="NUMBER_ONE"/></translation>
+<translation id="2704295676501803339">עבור שמאלה</translation>
+<translation id="9098468523912235228">לפני <ph name="NUMBER_DEFAULT"/> שניות</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> שניות נותרו</translation>
+<translation id="566737009157135450">מחק מילה אחת לאחור</translation>
+<translation id="436869212180315161">לחץ</translation>
+<translation id="4860787810836767172">לפני <ph name="NUMBER_FEW"/> שניות</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> דקות</translation>
+<translation id="1858722859751911017">נותרו <ph name="NUMBER_FEW"/> דקות</translation>
+<translation id="6040143037577758943">סגור</translation>
+<translation id="1101671447232096497">לפני <ph name="NUMBER_MANY"/> דקות</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">עזרה</translation>
+<translation id="2405367043325750948">מחק קדימה</translation>
+<translation id="6699343763173986273">הרצועה הבאה במדיה</translation>
+<translation id="5445120697129764393">נותרו <ph name="NUMBER_DEFAULT"/> שניות</translation>
+<translation id="8226233771743600312">נא לא להפריע ליום אחד</translation>
+<translation id="4252565523989510616">מחק מילה אחת קדימה</translation>
+<translation id="7457942297256758195">נקה הכל</translation>
+<translation id="822618367988303761">לפני <ph name="NUMBER_TWO"/> ימים</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> דקות</translation>
+<translation id="1963692530539281474">נותרו <ph name="NUMBER_DEFAULT"/> ימים</translation>
+<translation id="6786750046913594791">סגור את התיקייה</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> דקות</translation>
+<translation id="5906719743126878045">נותרו <ph name="NUMBER_TWO"/> שעות</translation>
+<translation id="8959208747503200525">לפני <ph name="NUMBER_TWO"/> שעות</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> שניות</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> שניות</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> שניות</translation>
+<translation id="3759876923365568382">נותרו <ph name="NUMBER_FEW"/> ימים</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">העתק ללוח</translation>
+<translation id="8371695176452482769">דבר עכשיו</translation>
+<translation id="1167268268675672572">עבור לתחילת השורה ושנה את הבחירה</translation>
+<translation id="6965382102122355670">אישור</translation>
+<translation id="7850320739366109486">נא לא להפריע</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">מזער</translation>
+<translation id="6394627529324717982">פסיק</translation>
+<translation id="3036649622769666520">פתח קבצים</translation>
+<translation id="8328145009876646418">קצה שמאלי</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> שניות</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb
new file mode 100644
index 00000000000..44e51fe6a7f
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ja.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">フォルダ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Insert</translation>
+<translation id="6135826906199951471">Delete</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 時間前</translation>
+<translation id="6310545596129886942">残り <ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="9213479837033539041">残り <ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="1209866192426315618">残り <ph name="NUMBER_DEFAULT"/> 分</translation>
+<translation id="1801827354178857021">期間</translation>
+<translation id="1190609913194133056">通知センター</translation>
+<translation id="7470933019269157899">残り <ph name="NUMBER_DEFAULT"/> 分</translation>
+<translation id="5613020302032141669">左矢印キー</translation>
+<translation id="4971687151119236543">メディアの前のトラック</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ファイル (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="7511635910912978956">残り <ph name="NUMBER_FEW"/> 時間</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">キャンセル</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">上矢印キー</translation>
+<translation id="3969863827134279083">上に移動</translation>
+<translation id="7062130397825382308">残り <ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/秒</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 時間</translation>
+<translation id="3990502903496589789">右端</translation>
+<translation id="9038489124413477075">名前のないフォルダ</translation>
+<translation id="1940483897317142625">行末まで削除</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分</translation>
+<translation id="3520476450377425184">残り <ph name="NUMBER_MANY"/> 日</translation>
+<translation id="932327136139879170">ホーム</translation>
+<translation id="5600907569873192868">残り <ph name="NUMBER_MANY"/> 分</translation>
+<translation id="8666066831007952346">残り <ph name="NUMBER_TWO"/> 日</translation>
+<translation id="6390842777729054533">残り <ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="3909791450649380159">切り取り(&amp;T)</translation>
+<translation id="2560788951337264832">残り <ph name="NUMBER_ZERO"/> 分</translation>
+<translation id="688711909580084195">無題のウェブページ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 日前</translation>
+<translation id="5076340679995252485">貼り付け(&amp;P)</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">右の単語に移動</translation>
+<translation id="364720409959344976">アップロードするフォルダを選択</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分前</translation>
+<translation id="3234408098842461169">下矢印キー</translation>
+<translation id="3087734570205094154">下</translation>
+<translation id="8828991073132329143">残り <ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="5935630983280450497">残り <ph name="NUMBER_ONE"/> 分</translation>
+<translation id="1860796786778352021">通知を閉じる</translation>
+<translation id="6364916375976753737">左にスクロール</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 時間前</translation>
+<translation id="4218160142017529598">後方削除</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分前</translation>
+<translation id="6945221475159498467">選択</translation>
+<translation id="6620110761915583480">ファイルを保存</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="8924469368910458384">行頭まで削除</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">残り <ph name="NUMBER_ONE"/> 分</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> 分</translation>
+<translation id="8210608804940886430">次のページへ</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> 日</translation>
+<translation id="7163503212501929773">残り <ph name="NUMBER_MANY"/> 時間</translation>
+<translation id="5329858601952122676">削除(&amp;D)</translation>
+<translation id="6556866813142980365">やり直す</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
+<translation id="7781829728241885113">昨日</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分</translation>
+<translation id="50960180632766478">残り <ph name="NUMBER_FEW"/> 分</translation>
+<translation id="5517291721709019259">残り <ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="6903282483217634857">右に移動</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 日前</translation>
+<translation id="8428213095426709021">設定</translation>
+<translation id="2497284189126895209">すべてのファイル</translation>
+<translation id="7487278341251176613">残り <ph name="NUMBER_TWO"/> 分</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 日前</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="4320177379694898372">インターネットに接続されていません</translation>
+<translation id="7814458197256864873">コピー(&amp;C)</translation>
+<translation id="3889424535448813030">右矢印キー</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
+<translation id="2544782972264605588">残り <ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="6829324100069873704">通知に戻る</translation>
+<translation id="6528179044667508675">通知を一時的にミュート</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> 分</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">次の通知を許可:</translation>
+<translation id="2479520428668657293">右に移動して選択範囲を変更</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> 時間</translation>
+<translation id="1398853756734560583">最大化</translation>
+<translation id="4250229828105606438">スクリーンショット</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> 時間</translation>
+<translation id="5260878308685146029">残り <ph name="NUMBER_TWO"/> 分</translation>
+<translation id="2557207087669398617">行頭に移動</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">すべて選択(&amp;A)</translation>
+<translation id="2168039046890040389">前のページへ</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 日</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> 分</translation>
+<translation id="6122334925474904337">右の単語に移動して選択範囲を変更</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
+<translation id="4927753642311223124">表示する通知はありません。続行してください。</translation>
+<translation id="2482878487686419369">通知</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">ここまでスクロール</translation>
+<translation id="4552416320897244156">PageDown</translation>
+<translation id="3066573403916685335">下に移動</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> 時間</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/秒</translation>
+<translation id="8394908167088220973">メディアの再生/一時停止</translation>
+<translation id="2148716181193084225">今日</translation>
+<translation id="7960078400008666149">通知を 1 時間ミュート</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分前</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> 日</translation>
+<translation id="2190355936436201913">(なし)</translation>
+<translation id="1164369517022005061">残り <ph name="NUMBER_DEFAULT"/> 時間</translation>
+<translation id="152482086482215392">残り <ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="8447116497070723931">PageUp</translation>
+<translation id="4588090240171750605">右にスクロール</translation>
+<translation id="7414887922320653780">残り <ph name="NUMBER_ONE"/> 時間</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> からの通知を無効にする</translation>
+<translation id="2666092431469916601">一番上</translation>
+<translation id="2538759511191347839">行末に移動して選択範囲を変更</translation>
+<translation id="928465423150706909">行末に移動</translation>
+<translation id="8331626408530291785">上にスクロール</translation>
+<translation id="7907591526440419938">ファイルを開く</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">フォルダを開く</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 時間前</translation>
+<translation id="815598010540052116">下にスクロール</translation>
+<translation id="6808150112686056157">メディアの停止</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">復元</translation>
+<translation id="5349525451964472598">左に移動して選択範囲を変更</translation>
+<translation id="1781701194097416995">左の単語に移動</translation>
+<translation id="1243314992276662751">アップロード</translation>
+<translation id="50030952220075532">残り <ph name="NUMBER_ONE"/> 日</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">左の単語に移動して選択範囲を変更</translation>
+<translation id="945522503751344254">フィードバックを送信</translation>
+<translation id="9170848237812810038">取消(&amp;U)</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 時間前</translation>
+<translation id="6918245111648057970">ユーザーごとに次の通知を許可:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="1270251962578273213">残り <ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="3994835489895548312">残り <ph name="NUMBER_MANY"/> 分</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">設定...</translation>
+<translation id="6845383723252244143">フォルダを選択</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="5368780922436099921">残り <ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 日前</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> 日</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> 時間</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分前</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/秒</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> 日</translation>
+<translation id="2704295676501803339">左に移動</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
+<translation id="494645311413743213">残り <ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="566737009157135450">後方の単語を削除</translation>
+<translation id="436869212180315161">押す</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/秒</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分</translation>
+<translation id="1858722859751911017">残り <ph name="NUMBER_FEW"/> 分</translation>
+<translation id="6040143037577758943">閉じる</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分前</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/秒</translation>
+<translation id="7649070708921625228">ヘルプ</translation>
+<translation id="2405367043325750948">前方削除</translation>
+<translation id="6699343763173986273">メディアの次のトラック</translation>
+<translation id="5445120697129764393">残り <ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="8226233771743600312">通知を 1 日間ミュート</translation>
+<translation id="4252565523989510616">前方の単語を削除</translation>
+<translation id="7457942297256758195">すべて消去</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 日前</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> 分</translation>
+<translation id="1963692530539281474">残り <ph name="NUMBER_DEFAULT"/> 日</translation>
+<translation id="6786750046913594791">フォルダを閉じる</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分</translation>
+<translation id="5906719743126878045">残り <ph name="NUMBER_TWO"/> 時間</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 時間前</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="3759876923365568382">残り <ph name="NUMBER_FEW"/> 日</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/秒</translation>
+<translation id="2743387203779672305">クリップボードにコピー</translation>
+<translation id="8371695176452482769">お話しください</translation>
+<translation id="1167268268675672572">行頭に移動して選択範囲を変更</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">通知を一時的にミュート</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">最小化</translation>
+<translation id="6394627529324717982">カンマ</translation>
+<translation id="3036649622769666520">ファイルを開く</translation>
+<translation id="8328145009876646418">左端</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb
new file mode 100644
index 00000000000..3695e76229a
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_kn.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="kn">
+<translation id="4820616160060340806">ಕಮಾಂಡ್+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">ಫೋಲ್ಡರ್ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">ಅಂತ್ಯ</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="1801827354178857021">ಅವಧಿ</translation>
+<translation id="1190609913194133056">ಅಧಿಸೂಚನೆಯ ಕೇಂದ್ರ</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="5613020302032141669">ಎಡ ಬಾಣದ ಗುರುತು</translation>
+<translation id="4971687151119236543">ಮೀಡಿಯಾದ ಹಿಂದಿನ ಟ್ರ್ಯಾಕ್</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ಫೈಲ್ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ಗಂಟೆಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">ರದ್ದುಮಾಡು</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">ಮೇಲಿನ ಬಾಣದ ಗುರುತು</translation>
+<translation id="3969863827134279083">ಮೇಲಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡ್ ಉಳಿದಿದೆ</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ಗಂಟೆಗಳು</translation>
+<translation id="3990502903496589789">ಬಲ ತುದಿ</translation>
+<translation id="9038489124413477075">ಹೆಸರಿಸದ ಫೋಲ್ಡರ್</translation>
+<translation id="1940483897317142625">ಸಾಲಿನ ಕೊನೆಯವರೆಗೆ ಅಳಿಸಿ</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="932327136139879170">ಮುಖಪುಟ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="3909791450649380159">ಕತ್ತರಿ&amp;ಸು</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="688711909580084195">ಶೀರ್ಷಿಕೆರಹಿತ ವೆಬ್‌ಪುಟ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;ಅಂಟಿಸಿ</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">ಪದವನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="364720409959344976">ಅಪ್‌ಲೋಡ್ ಮಾಡಲು ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">ಕೆಳಗಿನ ಬಾಣದ ಗುರುತು</translation>
+<translation id="3087734570205094154">ಕೆಳಗೆ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡ್‍ಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="1860796786778352021">ಅಧಿಸೂಚನೆ ಮುಚ್ಚು</translation>
+<translation id="6364916375976753737">ಎಡಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">ಹಿಮ್ಮುಖವಾಗಿ ಅಳಿಸಿ</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> ನಿಮಿಷಗಳು</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">ಆಯ್ಕೆಮಾಡಿ</translation>
+<translation id="6620110761915583480">ಫೈಲ್ ಉಳಿಸು</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="8924469368910458384">ಸಾಲಿನ ಪ್ರಾರಂಭದವರೆಗೆ ಅಳಿಸಿ</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> ನಿಮಿಷ ಉಳಿದಿದೆ</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> ನಿಮಿಷ</translation>
+<translation id="8210608804940886430">ಪುಟ ಕೆಳಗೆ</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ದಿನಗಳು</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="5329858601952122676">&amp;ಅಳಿಸು</translation>
+<translation id="6556866813142980365">ಮತ್ತೆಮಾಡು</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">ನಿನ್ನೆ</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡ್‍ಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6903282483217634857">ಬಲಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="6659594942844771486">ಟ್ಯಾಬ್</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">ಸೆಟ್ಟಿಂಗ್‌ಗಳು</translation>
+<translation id="2497284189126895209">ಎಲ್ಲ ಫೈಲ್‌ಗಳು</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡು</translation>
+<translation id="4320177379694898372">ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ</translation>
+<translation id="7814458197256864873">&amp;ನಕಲಿಸಿ</translation>
+<translation id="3889424535448813030">ಬಲ ಬಾಣದ ಗುರುತು</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="6829324100069873704">ಅಧಿಸೂಚನೆಗಳಿಗೆ ಹಿಂತಿರುಗಿ</translation>
+<translation id="6528179044667508675">ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">ಕೆಳಗಿನವುಗಳಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ಅನುಮತಿಸಿ:</translation>
+<translation id="2479520428668657293">ಬಲಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ಗಂಟೆಗಳು</translation>
+<translation id="1398853756734560583">ಗರಿಷ್ಠಗೊಳಿಸು</translation>
+<translation id="4250229828105606438">ಸ್ಕ್ರೀನ್‌ಶಾಟ್</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ಗಂಟೆಗಳು</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="2557207087669398617">ಸಾಲಿನ ಪ್ರಾರಂಭಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;ಎಲ್ಲ ಆಯ್ಕೆ ಮಾಡಿ</translation>
+<translation id="2168039046890040389">ಪುಟ ಮೇಲೆ</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ದಿನಗಳು</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು</translation>
+<translation id="6122334925474904337">ಪದವನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> ನಿಮಿಷ</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">ಇಲ್ಲಿ ನೋಡಲು ಏನೂ ಇಲ್ಲ, ಮುಂದೆ ಸಾಗಿ.</translation>
+<translation id="2482878487686419369">ಸೂಚನೆಗಳು</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">ಇಲ್ಲಿಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">ಕೆಳಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ಗಂಟೆಗಳು</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s </translation>
+<translation id="8394908167088220973">ಮೀಡಿಯಾ ಪ್ಲೇ/ವಿರಾಮ</translation>
+<translation id="2148716181193084225">ಇಂದು</translation>
+<translation id="7960078400008666149">ಒಂದು ಗಂಟೆಯ ಕಾಲ ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ದಿನಗಳು</translation>
+<translation id="2190355936436201913">(ಖಾಲಿ)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">ಬಲಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> ಅವರ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ</translation>
+<translation id="2666092431469916601">ಮೇಲೆ</translation>
+<translation id="2538759511191347839">ಸಾಲಿನ ಅಂತ್ಯಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="928465423150706909">ಸಾಲಿನ ಅಂತ್ಯಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="8331626408530291785">ಮೇಲೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
+<translation id="7907591526440419938">ಫೈಲ್ ತೆರೆಯಿರಿ</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">ಫೋಲ್ಡರ್ ತೆರೆಯಿರಿ</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">ಕೆಳಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation>
+<translation id="6808150112686056157">ಮೀಡಿಯಾ ನಿಲುಗಡೆ</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">ಮರುಸ್ಥಾಪನೆ</translation>
+<translation id="5349525451964472598">ಎಡಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="1781701194097416995">ಪದವನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="1243314992276662751">ಅಪ್‌ಲೋಡ್</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">ಪದವನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="945522503751344254">ಪ್ರತಿಕ್ರಿಯೆಯನ್ನು ಕಳುಹಿಸಿ</translation>
+<translation id="9170848237812810038">&amp;ರದ್ದುಮಾಡು</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">ಪ್ರತಿ ಬಳಕೆದಾರರಿಗಾಗಿ ಈ ಕೆಳಗಿನವುಗಳಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ಅನುಮತಿಸಿ:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> ಸೆಕೆಂಡ್</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡ್‍ಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">ಸೆಟ್ಟಿಂಗ್‌ಗಳು...</translation>
+<translation id="6845383723252244143">ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡ್‍ಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ದಿನಗಳು</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ಗಂಟೆ</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ದಿನ</translation>
+<translation id="2704295676501803339">ಎಡಕ್ಕೆ ಸರಿಸಿ</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="566737009157135450">ಪದವನ್ನು ಹಿಂದಕ್ಕೆ ಅಳಿಸಿ</translation>
+<translation id="436869212180315161">ಒತ್ತಿರಿ</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> ನಿಮಿಷಗಳು</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6040143037577758943">ಮುಚ್ಚು</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">ಸಹಾಯ</translation>
+<translation id="2405367043325750948">ಮುಂದಕ್ಕೆ ಅಳಿಸಿ</translation>
+<translation id="6699343763173986273">ಮೀಡಿಯಾದ ಮುಂದಿನ ಟ್ರ್ಯಾಕ್</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡ್‍ಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="8226233771743600312">ಒಂದು ದಿನದವರೆಗೆ ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
+<translation id="4252565523989510616">ಪದದ ಮುಂದಕ್ಕೆ ಅಳಿಸಿ</translation>
+<translation id="7457942297256758195">ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6786750046913594791">ಫೋಲ್ಡರ್ ಮುಚ್ಚಿರಿ</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> ನಿಮಿಷಗಳು</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ಗಂಟೆಗಳು ಉಳಿದಿದೆ</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> ಸೆಕೆಂಡುಗಳು</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ದಿನಗಳು ಉಳಿದಿವೆ</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ</translation>
+<translation id="8371695176452482769">ಈಗ ಮಾತನಾಡಿ</translation>
+<translation id="1167268268675672572">ಸಾಲಿನ ಪ್ರಾರಂಭಕ್ಕೆ ಸರಿಸಿ ಮತ್ತು ಆಯ್ಕೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ</translation>
+<translation id="6965382102122355670">ಸರಿ</translation>
+<translation id="7850320739366109486">ಅಡಚಣೆ ಮಾಡಬೇಡಿ</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">ಕುಗ್ಗಿಸು</translation>
+<translation id="6394627529324717982">ಅರ್ಧವಿರಾಮ</translation>
+<translation id="3036649622769666520">ಫೈಲ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ</translation>
+<translation id="8328145009876646418">ಎಡ ಬದಿ</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> ಸೆಕೆಂಡುಗಳು</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb
new file mode 100644
index 00000000000..ef6a069fff4
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ko.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> 폴더</translation>
+<translation id="1871244248791675517">Insert</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/>시간 전</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/>초 남음</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/>초 남음</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/>분 남음</translation>
+<translation id="1801827354178857021">기간</translation>
+<translation id="1190609913194133056">알림 센터</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/>분 남음</translation>
+<translation id="5613020302032141669">왼쪽 화살표</translation>
+<translation id="4971687151119236543">미디어 이전 트랙</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 파일(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/>초</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/>시간 남음</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">취소</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/>B</translation>
+<translation id="3660179305079774227">위쪽 화살표</translation>
+<translation id="3969863827134279083">위로 이동</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/>초 남음</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/>MB/초</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/>시간</translation>
+<translation id="3990502903496589789">오른쪽 모서리</translation>
+<translation id="9038489124413477075">이름이 없는 폴더</translation>
+<translation id="1940483897317142625">마지막 줄까지 삭제</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/>분</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/>일 남음</translation>
+<translation id="932327136139879170">홈</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/>분</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/>일 남음</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/>초 남음</translation>
+<translation id="3909791450649380159">잘라내기(&amp;T)</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">제목 없는 웹페이지</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/>일 전</translation>
+<translation id="5076340679995252485">붙여넣기(&amp;P)</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/>TB</translation>
+<translation id="7139614227326422685">단어 오른쪽으로 이동</translation>
+<translation id="364720409959344976">업로드할 폴더 선택</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/>분 전</translation>
+<translation id="3234408098842461169">아래 화살표</translation>
+<translation id="3087734570205094154">맨 아래</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/>초 남음</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/>분 남음</translation>
+<translation id="1860796786778352021">알림 닫기</translation>
+<translation id="6364916375976753737">왼쪽으로 스크롤</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/>시간 전</translation>
+<translation id="4218160142017529598">이전 삭제</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/>분</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/>분 전</translation>
+<translation id="6945221475159498467">선택</translation>
+<translation id="6620110761915583480">파일 저장</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/>초</translation>
+<translation id="8924469368910458384">첫 줄까지 삭제</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minute left</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/>분</translation>
+<translation id="8210608804940886430">페이지 아래로</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/>일</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/>시간 남음</translation>
+<translation id="5329858601952122676">삭제(&amp;D)</translation>
+<translation id="6556866813142980365">다시실행</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/>초</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/>KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/>분</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/>초 전</translation>
+<translation id="7781829728241885113">어제</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/>분</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/>분 남음</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/>초 남음</translation>
+<translation id="6903282483217634857">오른쪽으로 이동</translation>
+<translation id="6659594942844771486">탭</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/>MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/>일 전</translation>
+<translation id="8428213095426709021">설정</translation>
+<translation id="2497284189126895209">모든 파일</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/>일 전</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/>초</translation>
+<translation id="4320177379694898372">인터넷에 연결되지 않음</translation>
+<translation id="7814458197256864873">복사(&amp;C)</translation>
+<translation id="3889424535448813030">오른쪽 화살표</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/>초 전</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/>초 남음</translation>
+<translation id="6829324100069873704">알림으로 돌아가기</translation>
+<translation id="6528179044667508675">알림 일시중지</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/>초</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/>분</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">다음 항목에 알림 허용:</translation>
+<translation id="2479520428668657293">오른쪽으로 이동 및 선택사항 수정</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/>시간</translation>
+<translation id="1398853756734560583">최대화</translation>
+<translation id="4250229828105606438">캡처화면</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/>시간</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/>분 남음</translation>
+<translation id="2557207087669398617">첫 줄로 이동</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/>GB</translation>
+<translation id="1901303067676059328">전체 선택(&amp;A)</translation>
+<translation id="2168039046890040389">페이지 위로</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/>일</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/>분</translation>
+<translation id="6122334925474904337">오른쪽으로 이동 및 선택사항 수정</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/>분</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/>초 전</translation>
+<translation id="4927753642311223124">표시할 내용이 없습니다.</translation>
+<translation id="2482878487686419369">알림</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">여기로 스크롤</translation>
+<translation id="4552416320897244156">PageDown</translation>
+<translation id="3066573403916685335">아래로 이동</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/>시간</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/>KB/초</translation>
+<translation id="8394908167088220973">미디어 재생/일시중지</translation>
+<translation id="2148716181193084225">오늘</translation>
+<translation id="7960078400008666149">1시간 동안 알림 일시중지</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/>분 전</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/>일</translation>
+<translation id="2190355936436201913">(비어있음)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/>시간 남음</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/>초 남음</translation>
+<translation id="8447116497070723931">PageUp</translation>
+<translation id="4588090240171750605">오른쪽 스크롤</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/>시간 남음</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/>의 알림 사용 중지</translation>
+<translation id="2666092431469916601">맨 위</translation>
+<translation id="2538759511191347839">마지막 줄로 이동 및 선택사항 수정</translation>
+<translation id="928465423150706909">마지막 줄로 이동</translation>
+<translation id="8331626408530291785">위로 스크롤</translation>
+<translation id="7907591526440419938">파일 열기</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">폴더 열기</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/>시간 전</translation>
+<translation id="815598010540052116">아래로 스크롤</translation>
+<translation id="6808150112686056157">미디어 중지</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">복구</translation>
+<translation id="5349525451964472598">왼쪽으로 이동 및 선택사항 수정</translation>
+<translation id="1781701194097416995">단어 왼쪽으로 이동</translation>
+<translation id="1243314992276662751">업로드</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/>일 남음</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">단어 왼쪽으로 이동 및 선택사항 수정</translation>
+<translation id="945522503751344254">의견 보내기</translation>
+<translation id="9170848237812810038">실행 취소(&amp;U)</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/>시간 전</translation>
+<translation id="6918245111648057970">사용자별로 다음 알림 허용:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/>초</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/>초 남음</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/>초 전</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/>PB</translation>
+<translation id="2983818520079887040">설정...</translation>
+<translation id="6845383723252244143">폴더 선택</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/>초</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/>초 남음</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/>초</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/>일 전</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/>일</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/>시간</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/>분 전</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/>GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/>일</translation>
+<translation id="2704295676501803339">왼쪽으로 이동</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/>초 전</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/>초 남음</translation>
+<translation id="566737009157135450">이전 단어 삭제</translation>
+<translation id="436869212180315161">누르기</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/>초 전</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/>TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/>분</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">닫기</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/>분 전</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/>B/s</translation>
+<translation id="7649070708921625228">도움말</translation>
+<translation id="2405367043325750948">다음 삭제</translation>
+<translation id="6699343763173986273">미디어 다음 트랙</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/>초 남음</translation>
+<translation id="8226233771743600312">하루 동안 알림 일시중지</translation>
+<translation id="4252565523989510616">다음 단어 삭제</translation>
+<translation id="7457942297256758195">모두 지우기</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/>일 전</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/>분</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/>일 남음</translation>
+<translation id="6786750046913594791">폴더 닫기</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/>분</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/>시간 남음</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/>시간 전</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/>초</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/>초</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/>초</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/>일 남음</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/>PB/s</translation>
+<translation id="2743387203779672305">클립보드로 복사</translation>
+<translation id="8371695176452482769">지금 말하기</translation>
+<translation id="1167268268675672572">첫 줄로 이동 및 선택사항 수정</translation>
+<translation id="6965382102122355670">확인</translation>
+<translation id="7850320739366109486">알림 일시중지</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">최소화</translation>
+<translation id="6394627529324717982">콤마</translation>
+<translation id="3036649622769666520">파일 열기</translation>
+<translation id="8328145009876646418">왼쪽 모서리</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/>초</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb
new file mode 100644
index 00000000000..4581d4dbc7a
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_lt.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+<translation id="4820616160060340806">„Command“ + „<ph name="KEY_COMBO_NAME"/>“</translation>
+<translation id="8806053966018712535">Aplankas „<ph name="FOLDER_NAME"/>“</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Pabaiga</translation>
+<translation id="5341849548509163798">Prieš <ph name="NUMBER_MANY"/> val.</translation>
+<translation id="6310545596129886942">liko <ph name="NUMBER_FEW"/> sek.</translation>
+<translation id="9213479837033539041">liko <ph name="NUMBER_MANY"/> sek.</translation>
+<translation id="1209866192426315618">liko <ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="1801827354178857021">Laikotarpis</translation>
+<translation id="1190609913194133056">Pranešimų centras</translation>
+<translation id="7470933019269157899">Liko <ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="5613020302032141669">Rodyklė į kairę</translation>
+<translation id="4971687151119236543">Ankstesnis medijos takelis</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> failas (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek.</translation>
+<translation id="7511635910912978956">liko <ph name="NUMBER_FEW"/> valandos (-ų)</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Atšaukti</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Rodyklė „Aukštyn“</translation>
+<translation id="3969863827134279083">Perkelti į viršų</translation>
+<translation id="7062130397825382308">Liko <ph name="NUMBER_ONE"/> sekundė</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> val.</translation>
+<translation id="3990502903496589789">Dešinysis kraštas</translation>
+<translation id="9038489124413477075">Aplankas be pavadinimo</translation>
+<translation id="1940483897317142625">Trinti iki eilutės pabaigos</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="3520476450377425184">liko <ph name="NUMBER_MANY"/> dienos (-ų)</translation>
+<translation id="932327136139879170">Kontaktinė namų informacija</translation>
+<translation id="5600907569873192868">liko <ph name="NUMBER_MANY"/> min.</translation>
+<translation id="8666066831007952346">liko <ph name="NUMBER_TWO"/> dienos (-ų)</translation>
+<translation id="6390842777729054533">liko <ph name="NUMBER_ZERO"/> sek.</translation>
+<translation id="3909791450649380159">Iškir&amp;pti</translation>
+<translation id="2560788951337264832">Liko <ph name="NUMBER_ZERO"/> min.</translation>
+<translation id="688711909580084195">Tinklalapis be pavadinimo</translation>
+<translation id="3353284378027041011">Prieš <ph name="NUMBER_FEW"/> dienas (-ų)</translation>
+<translation id="5076340679995252485">&amp;Įklijuoti</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Perkelti per vieną žodį į dešinę</translation>
+<translation id="364720409959344976">Pasirinkite norimą įkelti aplanką</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Prieš <ph name="NUMBER_TWO"/> min.</translation>
+<translation id="3234408098842461169">Rodyklė „Žemyn“</translation>
+<translation id="3087734570205094154">Apačia</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">liko <ph name="NUMBER_ONE"/> min.</translation>
+<translation id="1860796786778352021">Uždaryti pranešimus</translation>
+<translation id="6364916375976753737">Slinkti į kairę</translation>
+<translation id="2629089419211541119">Prieš <ph name="NUMBER_ONE"/> val.</translation>
+<translation id="4218160142017529598">Trinti atgal</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="6982279413068714821">Prieš <ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="6945221475159498467">Pasirinkti</translation>
+<translation id="6620110761915583480">Išsaugoti failą</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sek.</translation>
+<translation id="8924469368910458384">Trinti iki eilutės pradžios</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Liko <ph name="NUMBER_ONE"/> min.</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8210608804940886430">Puslapį žemyn</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dienos</translation>
+<translation id="7163503212501929773">liko <ph name="NUMBER_MANY"/> valandos (-ų)</translation>
+<translation id="5329858601952122676">&amp;Pašalinti</translation>
+<translation id="6556866813142980365">Grąžinti</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sek.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> min.</translation>
+<translation id="7275974018215686543">Prieš <ph name="NUMBER_MANY"/> sek.</translation>
+<translation id="7781829728241885113">Vakar</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> min.</translation>
+<translation id="50960180632766478">liko <ph name="NUMBER_FEW"/> min.</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Perkelti į dešinę</translation>
+<translation id="6659594942844771486">Skirtukas</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Prieš <ph name="NUMBER_DEFAULT"/> dienas (-ų)</translation>
+<translation id="8428213095426709021">Nustatymai</translation>
+<translation id="2497284189126895209">Visi failai</translation>
+<translation id="7487278341251176613">Liko <ph name="NUMBER_TWO"/> min.</translation>
+<translation id="5110450810124758964">Prieš <ph name="NUMBER_ONE"/> dieną</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek.</translation>
+<translation id="4320177379694898372">Nėra interneto ryšio</translation>
+<translation id="7814458197256864873">&amp;Kopijuoti</translation>
+<translation id="3889424535448813030">Rodyklė į dešinę</translation>
+<translation id="4229495110203539533">Prieš <ph name="NUMBER_ONE"/> sek.</translation>
+<translation id="2544782972264605588">liko <ph name="NUMBER_DEFAULT"/> sek.</translation>
+<translation id="6829324100069873704">Atgal į pranešimus</translation>
+<translation id="6528179044667508675">Netrukdyti</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sek.</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Leisti pranešimus iš šių plėtinių:</translation>
+<translation id="2479520428668657293">Perkelti į dešinę ir pakeisti pažymėtą tekstą</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> valandos (-ų)</translation>
+<translation id="1398853756734560583">Išskleisti</translation>
+<translation id="4250229828105606438">Ekrano kopija</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> valandos (-ų)</translation>
+<translation id="5260878308685146029">liko <ph name="NUMBER_TWO"/> min.</translation>
+<translation id="2557207087669398617">Perkelti į eilutės pradžią</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Pasirinkti &amp;viską</translation>
+<translation id="2168039046890040389">Puslapį į viršų</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dienos</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6122334925474904337">Perkelti per vieną žodį į dešinę ir pakeisti pažymėtą tekstą</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8448317557906454022">Prieš <ph name="NUMBER_ZERO"/> sek.</translation>
+<translation id="4927753642311223124">Čia nieko nėra, slinkite toliau.</translation>
+<translation id="2482878487686419369">Pranešimai</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Slinkti iki čia</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Perkelti žemyn</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> valandos (-ų)</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB per sek.</translation>
+<translation id="8394908167088220973">Leisti / pristabdyti mediją</translation>
+<translation id="2148716181193084225">Šiandien</translation>
+<translation id="7960078400008666149">Netrukdyti vieną valandą</translation>
+<translation id="4373894838514502496">Prieš <ph name="NUMBER_FEW"/> min.</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dienos</translation>
+<translation id="2190355936436201913">(tuščias)</translation>
+<translation id="1164369517022005061">liko <ph name="NUMBER_DEFAULT"/> valandos (-ų)</translation>
+<translation id="152482086482215392">liko <ph name="NUMBER_ONE"/> sek.</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Slinkti į dešinę</translation>
+<translation id="7414887922320653780">liko <ph name="NUMBER_ONE"/> val.</translation>
+<translation id="1413622004203049571">Išjungti pranešimus nuo <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Į viršų</translation>
+<translation id="2538759511191347839">Perkelti į eilutės pabaigą ir pakeisti pažymėtą tekstą</translation>
+<translation id="928465423150706909">Perkelti į eilutės pabaigą</translation>
+<translation id="8331626408530291785">Slinkti į viršų</translation>
+<translation id="7907591526440419938">Atidaryti failą</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Atidaryti aplanką</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Prieš <ph name="NUMBER_DEFAULT"/> val.</translation>
+<translation id="815598010540052116">Slinkti žemyn</translation>
+<translation id="6808150112686056157">Sustabdyti mediją</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Atkurti</translation>
+<translation id="5349525451964472598">Perkelti į kairę ir pakeisti pažymėtą tekstą</translation>
+<translation id="1781701194097416995">Perkelti per vieną žodį į kairę</translation>
+<translation id="1243314992276662751">Įkelti</translation>
+<translation id="50030952220075532">liko <ph name="NUMBER_ONE"/> diena</translation>
+<translation id="8179976553408161302">Įvesti</translation>
+<translation id="8471049483003785219">Perkelti per vieną žodį į kairę ir pakeisti pažymėtą tekstą</translation>
+<translation id="945522503751344254">Siųsti atsiliepimą</translation>
+<translation id="9170848237812810038">&amp;Atšaukti</translation>
+<translation id="1285266685456062655">Prieš <ph name="NUMBER_FEW"/> val.</translation>
+<translation id="6918245111648057970">Kiekvienam naudotojui leisti pranešimus iš nurodyto:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sek.</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">Liko <ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6358975074282722691">Prieš <ph name="NUMBER_TWO"/> sek.</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Nustatymai...</translation>
+<translation id="6845383723252244143">Pasirinkti aplanką</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sek.</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek.</translation>
+<translation id="5583640892426849032">Grįžties klavišas</translation>
+<translation id="5263972071113911534">Prieš <ph name="NUMBER_MANY"/> dienas (-ų)</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dienos</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> val.</translation>
+<translation id="2679312662830811292">Prieš <ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> diena</translation>
+<translation id="2704295676501803339">Perkelti į kairę</translation>
+<translation id="9098468523912235228">Prieš <ph name="NUMBER_DEFAULT"/> sek.</translation>
+<translation id="494645311413743213">liko <ph name="NUMBER_TWO"/> sek.</translation>
+<translation id="566737009157135450">Trinti žodį atgal</translation>
+<translation id="436869212180315161">Spustelėti</translation>
+<translation id="4860787810836767172">Prieš <ph name="NUMBER_FEW"/> sek.</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> min.</translation>
+<translation id="1858722859751911017">Liko <ph name="NUMBER_FEW"/> min.</translation>
+<translation id="6040143037577758943">Uždaryti</translation>
+<translation id="1101671447232096497">Prieš <ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Žinynas</translation>
+<translation id="2405367043325750948">Trinti pirmyn</translation>
+<translation id="6699343763173986273">Kitas medijos takelis</translation>
+<translation id="5445120697129764393">Liko <ph name="NUMBER_DEFAULT"/> sekundžių</translation>
+<translation id="8226233771743600312">Netrukdyti vieną dieną</translation>
+<translation id="4252565523989510616">Trinti žodį pirmyn</translation>
+<translation id="7457942297256758195">Išvalyti viską</translation>
+<translation id="822618367988303761">Prieš <ph name="NUMBER_TWO"/> dienas</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
+<translation id="1963692530539281474">liko <ph name="NUMBER_DEFAULT"/> dienos (-ų)</translation>
+<translation id="6786750046913594791">Uždaryti aplanką</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> min.</translation>
+<translation id="5906719743126878045">liko <ph name="NUMBER_TWO"/> valandos (-ų)</translation>
+<translation id="8959208747503200525">Prieš <ph name="NUMBER_TWO"/> val.</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sek.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sek.</translation>
+<translation id="3759876923365568382">liko <ph name="NUMBER_FEW"/> dienos (-ų)</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopijuoti į iškarpinę</translation>
+<translation id="8371695176452482769">Kalbėti dabar</translation>
+<translation id="1167268268675672572">Perkelti į eilutės pradžią ir pakeisti pažymėtą tekstą</translation>
+<translation id="6965382102122355670">Gerai</translation>
+<translation id="7850320739366109486">Netrukdyti</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Sumažinti</translation>
+<translation id="6394627529324717982">Kablelis</translation>
+<translation id="3036649622769666520">Atidaryti failus</translation>
+<translation id="8328145009876646418">Kairysis kraštas</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sek.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb
new file mode 100644
index 00000000000..b0552794dec
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_lv.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mape <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Iespraušana</translation>
+<translation id="6135826906199951471">Dzēst</translation>
+<translation id="528468243742722775">Beigas</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekundes atlikušas</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekundes atlikušas</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minūtes atlikušas</translation>
+<translation id="1801827354178857021">Periods</translation>
+<translation id="1190609913194133056">Paziņojumu centrs</translation>
+<translation id="7470933019269157899">Atlikušas <ph name="NUMBER_DEFAULT"/> minūtes</translation>
+<translation id="5613020302032141669">Kreisā bulta</translation>
+<translation id="4971687151119236543">Multivide — iepriekšējā dziesma</translation>
+<translation id="8602707065186045623">Fails <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekundes</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> stundas atlikušas</translation>
+<translation id="5948410903763073882">Alt +<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Atcelt</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Bulta augšup</translation>
+<translation id="3969863827134279083">Pārvietot augšup</translation>
+<translation id="7062130397825382308">Atlikusi <ph name="NUMBER_ONE"/> sekunde</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> stundas</translation>
+<translation id="3990502903496589789">Labā puse</translation>
+<translation id="9038489124413477075">Mape bez nosaukuma</translation>
+<translation id="1940483897317142625">Dzēst līdz rindiņas beigām</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minūtes</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dienas atlikušas</translation>
+<translation id="932327136139879170">Sākums</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minūtes atlikušas</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dienas atlikušas</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekundes atlikušas</translation>
+<translation id="3909791450649380159">Izgrie&amp;zt</translation>
+<translation id="2560788951337264832">Atlikusi <ph name="NUMBER_ZERO"/> minūšu</translation>
+<translation id="688711909580084195">Tīmekļa lapa bez nosaukuma</translation>
+<translation id="3353284378027041011">Pirms <ph name="NUMBER_FEW"/> dienām</translation>
+<translation id="5076340679995252485">&amp;Ielīmēt</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Pārvietot pa labi par vienu vārdu</translation>
+<translation id="364720409959344976">Augšupielādējamās mapes atlase</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Bulta Lejup</translation>
+<translation id="3087734570205094154">Apakšā</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minūtes atlikušas</translation>
+<translation id="1860796786778352021">Paziņojuma aizvēršana</translation>
+<translation id="6364916375976753737">Ritināt pa kreisi</translation>
+<translation id="2629089419211541119">Pirms <ph name="NUMBER_ONE"/> stundas</translation>
+<translation id="4218160142017529598">Dzēst iepriekšējo</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minūtes</translation>
+<translation id="6982279413068714821">Pirms <ph name="NUMBER_DEFAULT"/> minūtēm</translation>
+<translation id="6945221475159498467">Atlasīt</translation>
+<translation id="6620110761915583480">Saglabāt failu</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunžu</translation>
+<translation id="8924469368910458384">Dzēst līdz rindiņas sākumam</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Atlikusi <ph name="NUMBER_ONE"/> minūte</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minūtes</translation>
+<translation id="8210608804940886430">Lejup</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dienas</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/>stundas atlikušas</translation>
+<translation id="5329858601952122676">Dzēst</translation>
+<translation id="6556866813142980365">Atcelt atsaukšanu</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekundes</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Vakar</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minūtes atlikušas</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Pārvietot pa labi</translation>
+<translation id="6659594942844771486">Cilne</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Pirms <ph name="NUMBER_DEFAULT"/> dienām</translation>
+<translation id="8428213095426709021">Iestatījumi</translation>
+<translation id="2497284189126895209">Visi faili</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964">Pirms <ph name="NUMBER_ONE"/> dienas</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekundes</translation>
+<translation id="4320177379694898372">Nav interneta savienojuma.</translation>
+<translation id="7814458197256864873">Ko&amp;pēt</translation>
+<translation id="3889424535448813030">Labā bulta</translation>
+<translation id="4229495110203539533">Pirms <ph name="NUMBER_ONE"/> sekundes</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekundes atlikušas</translation>
+<translation id="6829324100069873704">Atgriezties paziņojumos</translation>
+<translation id="6528179044667508675">Netraucēt</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundes</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minūtes</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Atļaut paziņojumu saņemšanu no:</translation>
+<translation id="2479520428668657293">Pārvietot pa labi un mainīt atlasi</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> stundas</translation>
+<translation id="1398853756734560583">Maksimizēt</translation>
+<translation id="4250229828105606438">Ekrānuzņēmums</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> stundas</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minūtes atlikušas</translation>
+<translation id="2557207087669398617">Pārvietot uz rindiņas sākumu</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Izvēlēties visus</translation>
+<translation id="2168039046890040389">Augšup</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/>dienas</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minūtes</translation>
+<translation id="6122334925474904337">Pārvietot pa labi par vienu vārdu un mainīt atlasi</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minūte</translation>
+<translation id="8448317557906454022">Pirms <ph name="NUMBER_ZERO"/> sekundēm</translation>
+<translation id="4927753642311223124">Te nekā nav, varat doties tālāk!</translation>
+<translation id="2482878487686419369">Paziņojumi</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Ritināt šeit</translation>
+<translation id="4552416320897244156">Lejup</translation>
+<translation id="3066573403916685335">Pārvietot lejup</translation>
+<translation id="7052633198403197513">taustiņš F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> stundas</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Multivide — atskaņot/apturēt</translation>
+<translation id="2148716181193084225">Šodien</translation>
+<translation id="7960078400008666149">Netraucēt stundu</translation>
+<translation id="4373894838514502496">Pirms <ph name="NUMBER_FEW"/> minūtēm</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dienas</translation>
+<translation id="2190355936436201913">(tukšs)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> stundas atlikušas</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekundes atlikušas</translation>
+<translation id="8447116497070723931">Augšup</translation>
+<translation id="4588090240171750605">Ritināt pa labi</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> stundas atlikušas</translation>
+<translation id="1413622004203049571">Atspējot paziņojumu saņemšanu no: <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Augša</translation>
+<translation id="2538759511191347839">Pārvietot uz rindiņas beigām un mainīt atlasi</translation>
+<translation id="928465423150706909">Pārvietot uz rindiņas beigām</translation>
+<translation id="8331626408530291785">Ritināt augšup</translation>
+<translation id="7907591526440419938">Atvērt failu</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Atvērt mapi</translation>
+<translation id="1293699935367580298">Atsolis</translation>
+<translation id="2797524280730715045">Pirms <ph name="NUMBER_DEFAULT"/> stundām</translation>
+<translation id="815598010540052116">Ritināt lejup</translation>
+<translation id="6808150112686056157">Multivide — pārtraukt</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Atjaunot</translation>
+<translation id="5349525451964472598">Pārvietot pa kreisi un mainīt atlasi</translation>
+<translation id="1781701194097416995">Pārvietot pa kreisi par vienu vārdu</translation>
+<translation id="1243314992276662751">Augšupielādēt</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dienas atlikušas</translation>
+<translation id="8179976553408161302">Ievadīt</translation>
+<translation id="8471049483003785219">Pārvietot pa kreisi par vienu vārdu un mainīt atlasi</translation>
+<translation id="945522503751344254">Sūtīt atsauksmes</translation>
+<translation id="9170848237812810038">&amp;Atsaukt</translation>
+<translation id="1285266685456062655">Pirms <ph name="NUMBER_FEW"/> stundām</translation>
+<translation id="6918245111648057970">Atļaut paziņojumus visiem lietotājiem no:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunde</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Iestatījumi...</translation>
+<translation id="6845383723252244143">Atlasīt mapi</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundes</translation>
+<translation id="5368780922436099921">Atlikusi <ph name="NUMBER_ZERO"/> sekunžu</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekundes</translation>
+<translation id="5583640892426849032">Atkāpšanās taustiņš</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dienas</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> stunda</translation>
+<translation id="2679312662830811292">Pirms <ph name="NUMBER_ONE"/> minūtes</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> diena</translation>
+<translation id="2704295676501803339">Pārvietot pa kreisi</translation>
+<translation id="9098468523912235228">Pirms <ph name="NUMBER_DEFAULT"/> sekundēm</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekundes atlikušas</translation>
+<translation id="566737009157135450">Dzēst iepriekšējo vārdu</translation>
+<translation id="436869212180315161">Nospiediet</translation>
+<translation id="4860787810836767172">Pirms <ph name="NUMBER_FEW"/> sekundēm</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minūšu</translation>
+<translation id="1858722859751911017">Atlikušas <ph name="NUMBER_FEW"/> minūtes</translation>
+<translation id="6040143037577758943">Aizvērt</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Palīdzība</translation>
+<translation id="2405367043325750948">Dzēst nākamo</translation>
+<translation id="6699343763173986273">Multivide — nākamā dziesma</translation>
+<translation id="5445120697129764393">Atlikušas <ph name="NUMBER_DEFAULT"/> sekundes</translation>
+<translation id="8226233771743600312">Netraucēt dienu</translation>
+<translation id="4252565523989510616">Dzēst nākamo vārdu</translation>
+<translation id="7457942297256758195">Notīrīt visu</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minūtes</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dienas atlikušas</translation>
+<translation id="6786750046913594791">Aizvērt mapi</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minūtes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/>stundas atlikušas</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekundes</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekundes</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dienas atlikušas</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopēt starpliktuvē</translation>
+<translation id="8371695176452482769">Runājiet tūlīt</translation>
+<translation id="1167268268675672572">Pārvietot uz rindiņas sākumu un mainīt atlasi</translation>
+<translation id="6965382102122355670">Labi</translation>
+<translation id="7850320739366109486">Netraucēt</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimizēt</translation>
+<translation id="6394627529324717982">Komats</translation>
+<translation id="3036649622769666520">Atvērt failus</translation>
+<translation id="8328145009876646418">Kreisā mala</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb
new file mode 100644
index 00000000000..fbd684d1ab0
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ml.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ml">
+<translation id="4820616160060340806">കമാൻഡ്+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">ഫോൾഡർ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">അവസാനം</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> സെക്കന്റ്‍ ശേഷിക്കുന്നു</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> സെക്കന്റ്‍ അവശേഷിക്കുന്നു</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="1801827354178857021">കാലയളവ്</translation>
+<translation id="1190609913194133056">അറിയിപ്പ് കേന്ദ്രം</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="5613020302032141669">ഇടത് ആരോ അടയാളം</translation>
+<translation id="4971687151119236543">മുമ്പത്തെ മീഡിയ ട്രാക്ക്</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ഫയല്‍ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> സെക്കന്റ്</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> മണിക്കൂര്‍‍ അവശേഷിക്കുന്നു</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">റദ്ദാക്കൂ</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">മുകളിലേക്കുള്ള അമ്പടയാളം</translation>
+<translation id="3969863827134279083">മുകളിലേക്ക് നീക്കുക</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> മണിക്കൂര്‍</translation>
+<translation id="3990502903496589789">വലത് അഗ്രം</translation>
+<translation id="9038489124413477075">പേരിടാത്ത ഫോൾഡർ</translation>
+<translation id="1940483897317142625">വരിയുടെ അവസാനം വരെ ഇല്ലാതാക്കുക</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ്</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ദിവസം‍ ശേഷിക്കുന്നു</translation>
+<translation id="932327136139879170">ഹോം</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ദിവസം അവശേഷിക്കുന്നു</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="3909791450649380159">&amp;മുറിക്കുക</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="688711909580084195">ശീർഷകമില്ലാത്ത വെബ്‌പേജ്</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;ഒട്ടിക്കുക</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">വലതുവശത്തുള്ള പദത്തിലേക്ക് നീക്കുക</translation>
+<translation id="364720409959344976">അപ്‌ലോഡുചെയ്യുന്നതിന് ഫോൾഡർ തിരഞ്ഞെടുക്കുക</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">താഴേക്കുള്ള ആരോ അടയാളം</translation>
+<translation id="3087734570205094154">താഴെ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="1860796786778352021">അറിയിപ്പ് അടയ്‌ക്കൽ</translation>
+<translation id="6364916375976753737">ഇടത്തേക്ക് സ്ക്രോള്‍ ചെയ്യുക</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">പുറകിലേക്ക് ഇല്ലാതാക്കുക</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> മിനിറ്റ്</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">തിരഞ്ഞെടുക്കുക</translation>
+<translation id="6620110761915583480">ഫയല്‍‌ സംരക്ഷിക്കുക</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> സെക്കൻഡ്</translation>
+<translation id="8924469368910458384">വരിയുടെ തുടക്കം വരെ ഇല്ലാതാക്കുക</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> മിനിറ്റ്</translation>
+<translation id="8210608804940886430">താഴെയുള്ള പേജുകള്‍</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ദിവസം</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
+<translation id="5329858601952122676">&amp;ഇല്ലാതാക്കൂ</translation>
+<translation id="6556866813142980365">വീണ്ടുംചെയ്യുക</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> സെക്കന്റ്</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> മിനിറ്റ്</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">ഇന്നലെ</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> മിനിറ്റ്</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> മിനിറ്റ്‍ അവശേഷിക്കുന്നു</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="6903282483217634857">വലതുവശത്തേക്ക് നീക്കുക</translation>
+<translation id="6659594942844771486">ടാബ്</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">ക്രമീകരണം</translation>
+<translation id="2497284189126895209">എല്ലാ ഫയലുകളും</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> സെക്കന്റ്</translation>
+<translation id="4320177379694898372">ഇന്റർനെറ്റ് കണക്ഷനൊന്നുമില്ല</translation>
+<translation id="7814458197256864873">&amp;പകര്‍ത്തൂ</translation>
+<translation id="3889424535448813030">വലതുഭാഗത്തെ അമ്പടയാളം</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="6829324100069873704">അറിയിപ്പുകളിലേക്ക് തിരിച്ചുപോവുക</translation>
+<translation id="6528179044667508675">ശല്യപ്പെടുത്തരുത്</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> സെക്കൻഡ്</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> മിനിറ്റ്</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">ഇനിപ്പറയുന്നതിൽ നിന്നുള്ള അറിയിപ്പുകൾ അനുവദിക്കുക:</translation>
+<translation id="2479520428668657293">വലതുവശത്തേക്ക് നീക്കി തിരഞ്ഞെടുത്തത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> മണിക്കൂര്‍</translation>
+<translation id="1398853756734560583">വലുതാക്കുക</translation>
+<translation id="4250229828105606438">സ്‌ക്രീൻഷോട്ട്</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> മണിക്കൂര്‍</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> മിനിറ്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="2557207087669398617">വരിയുടെ തുടക്കത്തിലേക്ക് നീക്കുക</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">എല്ലാം &amp;തിരഞ്ഞെടുക്കൂ</translation>
+<translation id="2168039046890040389">പേജ് മുകളിലേയ്ക്ക്</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ദിവസം</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> മിനിറ്റ്</translation>
+<translation id="6122334925474904337">വലതുവശത്തുള്ള പദത്തിലേക്ക് നീക്കി തിരഞ്ഞെടുത്തത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> മിനിറ്റ്</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">ഇവിടെ കാണുന്നതിനായി ഒന്നുമില്ല, തുടരുക.</translation>
+<translation id="2482878487686419369">വിജ്ഞാപനങ്ങള്‍‌</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">ഇവിടെ സ്ക്രോള്‍ ചെയ്യുക</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">താഴേക്ക് നീക്കുക</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> മണിക്കൂര്‍</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">മീഡിയ പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക</translation>
+<translation id="2148716181193084225">ഇന്ന്</translation>
+<translation id="7960078400008666149">ഒരു മണിക്കൂർ നേരത്തേക്ക് ശല്യപ്പെടുത്തരുത്</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ദിവസം</translation>
+<translation id="2190355936436201913">(ശൂന്യം)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> മണിക്കൂര്‍ അവശേഷിക്കുന്നു</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">വലത്തോട്ട് സ്ക്രോള്‍ ചെയ്യുക</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> എന്നതിൽ നിന്നുള്ള അറിയിപ്പുകൾ പ്രവർത്തനരഹിതമാക്കുക</translation>
+<translation id="2666092431469916601">മുകളിലേക്ക്</translation>
+<translation id="2538759511191347839">വരിയുടെ അവസാനത്തിലേക്ക് നീക്കി തിരഞ്ഞെടുത്തത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="928465423150706909">വരിയുടെ അവസാനത്തിലേക്ക് നീക്കുക</translation>
+<translation id="8331626408530291785">മുകളിലേക്ക് സ്ക്രോള്‍ ചെയ്യൂ</translation>
+<translation id="7907591526440419938">ഫയല്‍ തുറക്കുക</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">ഫോൾഡർ തുറക്കുക</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">താഴേക്ക് സ്ക്രോള്‍ചെയ്യൂ</translation>
+<translation id="6808150112686056157">മീഡിയ ‌നിർത്തുക</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
+<translation id="5349525451964472598">ഇടത് വശത്തേക്ക് നീക്കി തിരഞ്ഞെടുത്തത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="1781701194097416995">ഇടതുവശത്തുള്ള പദത്തിലേക്ക് നീക്കുക</translation>
+<translation id="1243314992276662751">അപ്‌ലോഡുചെയ്യുക</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ദിവസം അവശേഷിക്കുന്നു</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">ഇടതുവശത്തുള്ള പദത്തിലേക്ക് നീക്കി തിരഞ്ഞെടുത്ത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="945522503751344254">ഫീഡ്ബാക്ക് അയയ്ക്കുക</translation>
+<translation id="9170848237812810038">‍&amp;പൂര്‍വാവസ്ഥയിലാക്കുക</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">ഇനിപ്പറയുന്നതിൽ നിന്ന് ഓരോ ഉപയോക്താവിനും അറിയിപ്പുകൾ അനുവദിക്കുക:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> സെക്കൻഡ്</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">ക്രമീകരണങ്ങള്‍...</translation>
+<translation id="6845383723252244143">ഫോള്‍ഡര്‍ തിരഞ്ഞെടുക്കുക</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> സെക്കൻഡ്</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> സെക്കന്റ്</translation>
+<translation id="5583640892426849032">ബാക്ക്‌സ്പെയ്‌സ്</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ദിവസം</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> മണിക്കൂര്‍</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ദിവസം</translation>
+<translation id="2704295676501803339">ഇടതുവശത്തേക്ക് നീക്കുക</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ് മുമ്പ്</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> സെക്കന്റ് അവശേഷിക്കുന്നു</translation>
+<translation id="566737009157135450">പദം പുറകിലേക്ക് ഇല്ലാതാക്കുക</translation>
+<translation id="436869212180315161">അമര്‍ത്തുക</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> മിനിറ്റ്</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> മിനിറ്റ് ശേഷിക്കുന്നു</translation>
+<translation id="6040143037577758943">അടയ്ക്കുക</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">സഹായം</translation>
+<translation id="2405367043325750948">മുമ്പിലേക്ക് ഇല്ലാതാക്കുക</translation>
+<translation id="6699343763173986273">അടുത്ത മീഡിയ ട്രാക്ക്</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> നിമിഷം ശേഷിക്കുന്നു</translation>
+<translation id="8226233771743600312">ഒരു ദിവസത്തേക്ക് ശല്യപ്പെടുത്തരുത്</translation>
+<translation id="4252565523989510616">പദം മുമ്പിലേക്ക് ഇല്ലാതാക്കുക</translation>
+<translation id="7457942297256758195">എല്ലാം മായ്‌ക്കുക</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> മിനിറ്റ്</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ദിവസം അവശേഷിക്കുന്നു</translation>
+<translation id="6786750046913594791">ഫോൾഡർ അടയ്ക്കുക</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> മിനിറ്റ്</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> മണിക്കൂര്‍ ശേഷിക്കുന്നു</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> സെക്കന്റ്</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> സെക്കന്റ്</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> സെക്കൻഡ്</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ദിവസം‍ അവശേഷിക്കുന്നു</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക</translation>
+<translation id="8371695176452482769">ഇപ്പോള്‍ സംസാരിക്കുക</translation>
+<translation id="1167268268675672572">വരിയുടെ തുടക്കത്തിലേക്ക് നീക്കി തിരഞ്ഞെടുത്തത് പരിഷ്‌ക്കരിക്കുക</translation>
+<translation id="6965382102122355670">ശരി</translation>
+<translation id="7850320739366109486">ശല്യം ചെയ്യരുത്</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">ചെറുതാക്കുക‍</translation>
+<translation id="6394627529324717982">കോമ</translation>
+<translation id="3036649622769666520">ഫയലുകള്‍‌ തുറക്കുക</translation>
+<translation id="8328145009876646418">ഇടത് അഗ്രം</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> സെക്കൻഡ്</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb
new file mode 100644
index 00000000000..b917df4164e
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_mr.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="mr">
+<translation id="4820616160060340806">आदेश+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> फोल्डर</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">समाप्त</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> से बाकी</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> से बाकी</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> मिनिटे बाकी</translation>
+<translation id="1801827354178857021">पूर्णविराम</translation>
+<translation id="1190609913194133056">सूचना केंद्र</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> मिनिटे शिल्लक</translation>
+<translation id="5613020302032141669">Left Arrow</translation>
+<translation id="4971687151119236543">मीडिया मागील ट्रॅक</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> फाइल (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> से</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> तास बाकी</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">रद्द करा</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Up Arrow</translation>
+<translation id="3969863827134279083">वर हलवा</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> सेकंद शिल्लक</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> तास</translation>
+<translation id="3990502903496589789">उजवा काठ</translation>
+<translation id="9038489124413477075">अनामित फोल्डर</translation>
+<translation id="1940483897317142625">ओळीच्या समाप्तीपर्यंत हटवा</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> मि</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> दिवस बाकी</translation>
+<translation id="932327136139879170">मुख्यपृष्ठ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> मि बाकी</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> दिवस बाकी</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> से बाकी</translation>
+<translation id="3909791450649380159">क&amp;ट करा</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> मिनिटे शिल्लक</translation>
+<translation id="688711909580084195">अशीर्षकांकीत वेबपृष्‍ठ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;पेस्ट करा</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">शब्द उजवीकडे हलवा</translation>
+<translation id="364720409959344976">अपलोड करण्यासाठी फोल्डर निवडा</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Down Arrow</translation>
+<translation id="3087734570205094154">तळाकडील</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> सेकंद शिल्लक</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> मि बाकी</translation>
+<translation id="1860796786778352021">सूचना बंद</translation>
+<translation id="6364916375976753737">डावीकडे स्क्रोल करा</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">मागील हटवा</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> मिनिटे</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">निवडा</translation>
+<translation id="6620110761915583480">फाइल जतन करा</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> सेकंद</translation>
+<translation id="8924469368910458384">ओळीच्या सुरुवातीपर्यंत हटवा</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> मिनिट शिल्लक</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> मि</translation>
+<translation id="8210608804940886430">पृष्ठ खाली</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> दिवस</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> तास बाकी</translation>
+<translation id="5329858601952122676">&amp;हटवा</translation>
+<translation id="6556866813142980365">पुन्हा करा</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> से</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> मिनिटे</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">काल</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> मिनिटे</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> मि बाकी</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> सेकंद शिल्लक</translation>
+<translation id="6903282483217634857">उजवीकडे हलवा</translation>
+<translation id="6659594942844771486">टॅब</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">सेटिंग्ज</translation>
+<translation id="2497284189126895209">सर्व फाइल</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> मिनिटे शिल्लक</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> से</translation>
+<translation id="4320177379694898372">कोणतेही इंटरनेट कनेक्शन नाही</translation>
+<translation id="7814458197256864873">&amp;कॉपी करा</translation>
+<translation id="3889424535448813030">Right Arrow</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> से बाकी</translation>
+<translation id="6829324100069873704">सूचनांवर परत जा</translation>
+<translation id="6528179044667508675">व्यत्यय आणू नका</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> सेकंद</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> मि</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">खालील लोकांकडील सूचनांना अनुमत करा:</translation>
+<translation id="2479520428668657293">उजवीकडे हलवा आणि निवड सुधारित करा</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> तास</translation>
+<translation id="1398853756734560583">वाढवा</translation>
+<translation id="4250229828105606438">स्क्रीनशॉट</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> तास</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> मि बाकी</translation>
+<translation id="2557207087669398617">ओळीच्या सुरुवातीस हलवा</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;सर्व निवडा</translation>
+<translation id="2168039046890040389">पृष्ठ वर</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> दिवस</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> मि</translation>
+<translation id="6122334925474904337">शब्द उजवीकडे हलवा आणि निवड सुधारित करा</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> मिनिट</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">येथे पाहण्यासाठी काही नाही, पुढे चला.</translation>
+<translation id="2482878487686419369">सूचना</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">येथे स्क्रोल करा</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">खाली हलवा</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> तास</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">मीडिया प्ले करा/विराम द्या</translation>
+<translation id="2148716181193084225">आज</translation>
+<translation id="7960078400008666149">एक तास व्यत्यय आणू नका</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> दिवस</translation>
+<translation id="2190355936436201913">(रिक्त)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> तास बाकी</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> से बाकी</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">उजवे स्क्रोल करा</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> तास बाकी</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> वरील सूचना अक्षम करा</translation>
+<translation id="2666092431469916601">शीर्ष</translation>
+<translation id="2538759511191347839">ओळीच्या समाप्तीवर हलवा आणि निवड सुधारित करा</translation>
+<translation id="928465423150706909">ओळीच्या समाप्तीवर हलवा</translation>
+<translation id="8331626408530291785">वर स्क्रोल करा</translation>
+<translation id="7907591526440419938">फाइल उघडा</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">फोल्डर उघडा</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">खाली स्क्रोल करा</translation>
+<translation id="6808150112686056157">मीडिया थांबवा</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">पुनर्संचयित करा</translation>
+<translation id="5349525451964472598">डावीकडे हलवा आणि निवड सुधारित करा</translation>
+<translation id="1781701194097416995">शब्द डावीकडे हलवा</translation>
+<translation id="1243314992276662751">अपलोड करा</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> दिवस बाकी</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">शब्द डावीकडे हलवा आणि निवड सुधारित करा</translation>
+<translation id="945522503751344254">अभिप्राय पाठवा</translation>
+<translation id="9170848237812810038">&amp;पूर्ववत करा</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">प्रत्येक वापरकर्त्यासाठी खालील मधून सूचनांना अनुमती द्या:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> सेकंद</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> सेकंद शिल्लक</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> मिनिटे शिल्लक</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">सेटिंग्ज...</translation>
+<translation id="6845383723252244143">फोल्डर निवडा</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> सेकंद</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> सेकंद शिल्लक</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> से</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> दिवस</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> तास</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> दिवस</translation>
+<translation id="2704295676501803339">डावीकडे हलवा</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> से बाकी</translation>
+<translation id="566737009157135450">मागचा शब्द हटवा</translation>
+<translation id="436869212180315161">दाबा</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> मिनिटे</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> मिनिटे शिल्लक</translation>
+<translation id="6040143037577758943">बंद करा</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">मदत</translation>
+<translation id="2405367043325750948">पुढचा हटवा</translation>
+<translation id="6699343763173986273">मीडिया पुढील ट्रॅक</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> सेकंद शिल्लक</translation>
+<translation id="8226233771743600312">एक दिवस व्यत्यय आणू नका</translation>
+<translation id="4252565523989510616">पुढचा शब्द हटवा</translation>
+<translation id="7457942297256758195">सर्व साफ करा</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> मि</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> दिवस बाकी</translation>
+<translation id="6786750046913594791">फोल्डर बंद करा</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> मिनिटे</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> तास बाकी</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> से</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> से</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> सेकंद</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> दिवस बाकी</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">क्लिपबोर्डवर कॉपी करा</translation>
+<translation id="8371695176452482769">आता बोला</translation>
+<translation id="1167268268675672572">ओळीच्या सुरुवातीवर हलवा आणि निवड सुधारित करा</translation>
+<translation id="6965382102122355670">ठिक आहे</translation>
+<translation id="7850320739366109486">व्यत्यय आणू नका</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">लहान करा</translation>
+<translation id="6394627529324717982">स्वल्पविराम</translation>
+<translation id="3036649622769666520">फायली उघडा</translation>
+<translation id="8328145009876646418">डावे काठ</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> सेकंद</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb
new file mode 100644
index 00000000000..06e25430a4c
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ms.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ms">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> jam yang lalu</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> saat lagi</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> saat lagi</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minit lagi</translation>
+<translation id="1801827354178857021">Tempoh</translation>
+<translation id="1190609913194133056">Pusat Pemberitahuan</translation>
+<translation id="7470933019269157899">Tinggal <ph name="NUMBER_DEFAULT"/> minit</translation>
+<translation id="5613020302032141669">Anak Panah Kiri</translation>
+<translation id="4971687151119236543">Lagu Media Sebelumnya</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fail (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> minit yang lalu</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> saat</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> jam lagi</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Batal</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Anak Panah Atas</translation>
+<translation id="3969863827134279083">Alihkan ke Atas</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> saat lagi</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> jam</translation>
+<translation id="3990502903496589789">Tepi Kanan</translation>
+<translation id="9038489124413477075">Folder Tanpa Nama</translation>
+<translation id="1940483897317142625">Padamkan Hingga Hujung Baris</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> mins</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> hari lagi</translation>
+<translation id="932327136139879170">Laman Utama</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minit lagi</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> hari lagi</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> saat lagi</translation>
+<translation id="3909791450649380159">Po&amp;tong</translation>
+<translation id="2560788951337264832">Tinggal <ph name="NUMBER_ZERO"/> minit</translation>
+<translation id="688711909580084195">Laman Web Tidak Bertajuk</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> hari yang lalu</translation>
+<translation id="5076340679995252485">&amp;Tampal</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Alihkan Perkataan ke Kanan</translation>
+<translation id="364720409959344976">Pilih Folder untuk Dimuat Naik</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minit lalu</translation>
+<translation id="3234408098842461169">Anak Panah Bawah</translation>
+<translation id="3087734570205094154">Bawah</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> saat lagi</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minit lagi</translation>
+<translation id="1860796786778352021">Tutup Pemberitahuan</translation>
+<translation id="6364916375976753737">Tatal Ke Kiri</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> jam yang lalu</translation>
+<translation id="4218160142017529598">Padamkan ke Belakang</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minit</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minit yang lalu</translation>
+<translation id="6945221475159498467">Pilih</translation>
+<translation id="6620110761915583480">Simpan Fail</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> saat</translation>
+<translation id="8924469368910458384">Padamkan Hingga Permulaan Baris</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> jam</translation>
+<translation id="7836361698254323868">Tinggal <ph name="NUMBER_ONE"/> minit</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minit</translation>
+<translation id="8210608804940886430">Ke Bawah Halaman</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> hari</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> jam lagi</translation>
+<translation id="5329858601952122676">&amp;Padam</translation>
+<translation id="6556866813142980365">Buat semula</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> saat</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minit</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> saat yang lalu</translation>
+<translation id="7781829728241885113">Semalam</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minit</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minit lagi</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> saat lagi</translation>
+<translation id="6903282483217634857">Alihkan Ke Kanan</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> hari yang lalu</translation>
+<translation id="8428213095426709021">Tetapan</translation>
+<translation id="2497284189126895209">Semua Fail</translation>
+<translation id="7487278341251176613">Tinggal <ph name="NUMBER_TWO"/> minit</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> hari yang lalu</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> saat</translation>
+<translation id="4320177379694898372">Tiada sambungan Internet</translation>
+<translation id="7814458197256864873">&amp;Salin</translation>
+<translation id="3889424535448813030">Anak Panah Kanan</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> saat yang lalu</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> saat lagi</translation>
+<translation id="6829324100069873704">Kembali ke pemberitahuan</translation>
+<translation id="6528179044667508675">Jangan ganggu</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> saat</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> jam lagi</translation>
+<translation id="7135556860107312402">Benarkan pemberitahuan daripada yang berikut:</translation>
+<translation id="2479520428668657293">Alihkan Ke Kanan Dan Ubah Suai Pilihan</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> jam</translation>
+<translation id="1398853756734560583">Maksimumkan</translation>
+<translation id="4250229828105606438">Tangkapan skrin</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> jam</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minit lagi</translation>
+<translation id="2557207087669398617">Alihkan Ke Permulaan Baris</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Pilih &amp;semua</translation>
+<translation id="2168039046890040389">Halaman Ke Atas</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> hari</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">Alihkan Perkataan ke Kanan Dan Ubah Suai Pilihan</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minit</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> saat yang lalu</translation>
+<translation id="4927753642311223124">Tiada apa-apa untuk dilihat di sini, teruskan.</translation>
+<translation id="2482878487686419369">Pemberitahuan</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> hari</translation>
+<translation id="3183922693828471536">Tatal ke Sini</translation>
+<translation id="4552416320897244156">BwhHlmn</translation>
+<translation id="3066573403916685335">Alihkan Ke Bawah</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> jam</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Main/Jeda Media</translation>
+<translation id="2148716181193084225">Hari ini</translation>
+<translation id="7960078400008666149">Jangan ganggu selama sejam</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minit yang lalu</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> hari</translation>
+<translation id="2190355936436201913">(kosong)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> jam lagi</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> saat lagi</translation>
+<translation id="8447116497070723931">AtsHlmn</translation>
+<translation id="4588090240171750605">Tatal ke Kanan</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> jam lagi</translation>
+<translation id="1413622004203049571">Lumpuhkan pemberitahuan daripada <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Atas</translation>
+<translation id="2538759511191347839">Alihkan Ke Hujung Baris Dan Ubah Suai Pilihan</translation>
+<translation id="928465423150706909">Alihkan Ke Hujung Baris</translation>
+<translation id="8331626408530291785">Tatal Ke Atas</translation>
+<translation id="7907591526440419938">Buka Fail</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> hari lagi</translation>
+<translation id="2803313416453193357">Buka folder</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> jam lalu</translation>
+<translation id="815598010540052116">Tatal Ke Bawah</translation>
+<translation id="6808150112686056157">Media Berhenti</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> minit lagi</translation>
+<translation id="3157931365184549694">Pulihkan</translation>
+<translation id="5349525451964472598">Alihkan Ke Kiri Dan Ubah Suai Pilihan</translation>
+<translation id="1781701194097416995">Alihkan Perkataan Ke Kiri</translation>
+<translation id="1243314992276662751">Muat naik</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> hari lagi</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Alihkan Perkataan Ke Kiri dan Ubah Suai Pilihan</translation>
+<translation id="945522503751344254">Hantar maklum balas</translation>
+<translation id="9170848237812810038">&amp;Buat asal</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> jam yang lalu</translation>
+<translation id="6918245111648057970">Benarkan pemberitahuan daripada yang berikut untuk setiap pengguna:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> saat</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> saat lagi</translation>
+<translation id="3994835489895548312">Tinggal <ph name="NUMBER_MANY"/> minit</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> saat yang lalu</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Tetapan...</translation>
+<translation id="6845383723252244143">Pilih Folder</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> saat</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> saat lagi</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> saat</translation>
+<translation id="5583640892426849032">Undur ruang</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> hari yang lalu</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> hari</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> jam</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minit yang lalu</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> jam yang lalu</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> hari</translation>
+<translation id="2704295676501803339">Alihkan Ke Kiri</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> saat yang lalu</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> saat lagi</translation>
+<translation id="566737009157135450">Padamkan Perkataan Ke Belakang</translation>
+<translation id="436869212180315161">Tekan</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> saat yang lalu</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minit</translation>
+<translation id="1858722859751911017">Tinggal <ph name="NUMBER_FEW"/> minit</translation>
+<translation id="6040143037577758943">Tutup</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minit yang lalu</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Bantuan</translation>
+<translation id="2405367043325750948">Padamkan Ke Hadapan</translation>
+<translation id="6699343763173986273">Lagu Media Seterusnya</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> saat lagi</translation>
+<translation id="8226233771743600312">Jangan ganggu selama sehari</translation>
+<translation id="4252565523989510616">Padamkan Perkataan Ke Hadapan</translation>
+<translation id="7457942297256758195">Kosongkan Semua</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> hari yang lalu</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> hari lagi</translation>
+<translation id="6786750046913594791">Tutup folder</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minit</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> jam lagi</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> jam yang lalu</translation>
+<translation id="8400147561352026160">Anjak+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> saat</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> saat</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> saat</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> hari lagi</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Salin ke papan keratan</translation>
+<translation id="8371695176452482769">Cakap sekarang</translation>
+<translation id="1167268268675672572">Alihkan Ke Permulaan Baris Dan Ubah Suai Pilihan</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Jangan Ganggu</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> hari yang lalu</translation>
+<translation id="5941711191222866238">Minimumkan</translation>
+<translation id="6394627529324717982">Koma</translation>
+<translation id="3036649622769666520">Buka Fail</translation>
+<translation id="8328145009876646418">Tepi Kiri</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> saat</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb
new file mode 100644
index 00000000000..eb6c0977095
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_nl.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Map <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> uur geleden</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> seconden resterend</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> seconden resterend</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuten resterend</translation>
+<translation id="1801827354178857021">Periode</translation>
+<translation id="1190609913194133056">Meldingscentrum</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuten resterend</translation>
+<translation id="5613020302032141669">Pijl-links</translation>
+<translation id="4971687151119236543">Vorige track voor media</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-bestand (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seconden</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> uur resterend</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Annuleren</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Pijl-omhoog</translation>
+<translation id="3969863827134279083">Naar boven</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> seconde resterend</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> uur</translation>
+<translation id="3990502903496589789">Rechterzijde</translation>
+<translation id="9038489124413477075">Naamloze map</translation>
+<translation id="1940483897317142625">Verwijderen tot einde van regel</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuten</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dagen resterend</translation>
+<translation id="932327136139879170">Startpagina</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuten resterend</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dagen resterend</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> seconden resterend</translation>
+<translation id="3909791450649380159">&amp;Knippen</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minuten resterend</translation>
+<translation id="688711909580084195">Naamloze webpagina</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dagen geleden</translation>
+<translation id="5076340679995252485">&amp;Plakken</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Eén woord naar rechts</translation>
+<translation id="364720409959344976">Map voor uploaden selecteren</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> minuten geleden</translation>
+<translation id="3234408098842461169">Pijl-omlaag</translation>
+<translation id="3087734570205094154">Onderaan</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconden resterend</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minuut resterend</translation>
+<translation id="1860796786778352021">Melding sluiten</translation>
+<translation id="6364916375976753737">Naar links bladeren</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> uur geleden</translation>
+<translation id="4218160142017529598">Achterwaarts verwijderen</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuten</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minuten geleden</translation>
+<translation id="6945221475159498467">Selecteren</translation>
+<translation id="6620110761915583480">Bestand opslaan</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconden</translation>
+<translation id="8924469368910458384">Verwijderen tot begin van regel</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuut resterend</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuut</translation>
+<translation id="8210608804940886430">Pagina omlaag</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dagen</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> uur resterend</translation>
+<translation id="5329858601952122676">Verwij&amp;deren</translation>
+<translation id="6556866813142980365">Opnieuw</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seconden</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> seconden geleden</translation>
+<translation id="7781829728241885113">Gisteren</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuten</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuten resterend</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconden resterend</translation>
+<translation id="6903282483217634857">Naar rechts verplaatsen</translation>
+<translation id="6659594942844771486">Tabblad</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dagen geleden</translation>
+<translation id="8428213095426709021">Instellingen</translation>
+<translation id="2497284189126895209">Alle bestanden</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minuten resterend</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dag geleden</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
+<translation id="4320177379694898372">Geen internetverbinding</translation>
+<translation id="7814458197256864873">&amp;Kopiëren</translation>
+<translation id="3889424535448813030">Pijl-rechts</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> seconde geleden</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> seconden resterend</translation>
+<translation id="6829324100069873704">Terug naar meldingen</translation>
+<translation id="6528179044667508675">Niet storen</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> seconden</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuten</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Meldingen toestaan van het volgende:</translation>
+<translation id="2479520428668657293">Naar rechts verplaatsen en selectie aanpassen</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> uur</translation>
+<translation id="1398853756734560583">Maximaliseren</translation>
+<translation id="4250229828105606438">Screenshot</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> uur</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuten resterend</translation>
+<translation id="2557207087669398617">Naar begin van regel verplaatsen</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;Alles selecteren</translation>
+<translation id="2168039046890040389">Pagina omhoog</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dagen</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuten</translation>
+<translation id="6122334925474904337">Eén woord naar rechts verplaatsen en selectie aanpassen</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuut</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> seconden geleden</translation>
+<translation id="4927753642311223124">Er zijn geen meldingen.</translation>
+<translation id="2482878487686419369">Meldingen</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Hiernaartoe bladeren</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Naar beneden</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> uur</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Media afspelen/onderbreken</translation>
+<translation id="2148716181193084225">Vandaag</translation>
+<translation id="7960078400008666149">Een uur niet storen</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> minuten geleden</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dagen</translation>
+<translation id="2190355936436201913">(leeg)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> uur resterend</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seconde resterend</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Naar rechts bladeren</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> uur resterend</translation>
+<translation id="1413622004203049571">Meldingen van <ph name="NOTIFIER_NAME"/> uitschakelen</translation>
+<translation id="2666092431469916601">Boven</translation>
+<translation id="2538759511191347839">Naar einde van regel verplaatsen en selectie aanpassen</translation>
+<translation id="928465423150706909">Naar einde van regel verplaatsen</translation>
+<translation id="8331626408530291785">Omhoog bladeren</translation>
+<translation id="7907591526440419938">Bestand openen</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Map openen</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> uur geleden</translation>
+<translation id="815598010540052116">Omlaag bladeren</translation>
+<translation id="6808150112686056157">Media stoppen</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Herstellen</translation>
+<translation id="5349525451964472598">Naar links verplaatsen en selectie aanpassen</translation>
+<translation id="1781701194097416995">Eén woord naar links verplaatsen</translation>
+<translation id="1243314992276662751">Uploaden</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag resterend</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Eén woord naar links verplaatsen en selectie aanpassen</translation>
+<translation id="945522503751344254">Feedback verzenden</translation>
+<translation id="9170848237812810038">&amp;Ongedaan maken</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> uur geleden</translation>
+<translation id="6918245111648057970">Melden van het volgende toestaan voor elke gebruiker:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> seconde</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconden resterend</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minuten resterend</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> seconden geleden</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Instellingen...</translation>
+<translation id="6845383723252244143">Map selecteren</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconden resterend</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seconden</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> dagen geleden</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dagen</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> uur</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuut geleden</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
+<translation id="2704295676501803339">Naar links verplaatsen</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> seconden geleden</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> seconden resterend</translation>
+<translation id="566737009157135450">Het voorgaande woord verwijderen</translation>
+<translation id="436869212180315161">Drukken</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> seconden geleden</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuten</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minuten resterend</translation>
+<translation id="6040143037577758943">Sluiten</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> minuten geleden</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Help</translation>
+<translation id="2405367043325750948">Voorwaarts verwijderen</translation>
+<translation id="6699343763173986273">Volgende track voor media</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> seconden resterend</translation>
+<translation id="8226233771743600312">Een dag niet storen</translation>
+<translation id="4252565523989510616">Het volgende woord verwijderen</translation>
+<translation id="7457942297256758195">Alles wissen</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dagen geleden</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuten</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dagen resterend</translation>
+<translation id="6786750046913594791">Map sluiten</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> uur resterend</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> uur geleden</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seconden</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seconden</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dagen resterend</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopiëren naar klembord</translation>
+<translation id="8371695176452482769">Begin nu te spreken</translation>
+<translation id="1167268268675672572">Naar begin van regel verplaatsen en selectie aanpassen</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Niet storen</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimaliseren</translation>
+<translation id="6394627529324717982">Komma</translation>
+<translation id="3036649622769666520">Bestanden openen</translation>
+<translation id="8328145009876646418">Linkerzijde</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconden</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb
new file mode 100644
index 00000000000..08f31702815
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_no.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+<translation id="4820616160060340806">Kommando + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekunder igjen</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekunder igjen</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutter igjen</translation>
+<translation id="1801827354178857021">Periode</translation>
+<translation id="1190609913194133056">Varselsenter</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutter igjen</translation>
+<translation id="5613020302032141669">Pil venstre</translation>
+<translation id="4971687151119236543">Media – forrige spor</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekunder</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timer igjen</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Pil opp</translation>
+<translation id="3969863827134279083">Flytt opp</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> sekund igjen</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB per sek.</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timer</translation>
+<translation id="3990502903496589789">Høyre kant</translation>
+<translation id="9038489124413477075">Mappe uten navn</translation>
+<translation id="1940483897317142625">Slett til slutten av linjen</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutter</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dager igjen</translation>
+<translation id="932327136139879170">Start</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutter igjen</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dager igjen</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekunder igjen</translation>
+<translation id="3909791450649380159">Klipp u&amp;t</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutter igjen</translation>
+<translation id="688711909580084195">Nettside uten tittel</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Lim inn</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Flytt ett ord til høyre</translation>
+<translation id="364720409959344976">Velg mappen du vil laste opp</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Pil ned</translation>
+<translation id="3087734570205094154">Bunn</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> sekunder igjen</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutt igjen</translation>
+<translation id="1860796786778352021">Lukk varsel</translation>
+<translation id="6364916375976753737">Rull mot venstre</translation>
+<translation id="2629089419211541119">For <ph name="NUMBER_ONE"/> time siden</translation>
+<translation id="4218160142017529598">Slett bakover</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutter</translation>
+<translation id="6982279413068714821">For <ph name="NUMBER_DEFAULT"/> minutter siden</translation>
+<translation id="6945221475159498467">Velg</translation>
+<translation id="6620110761915583480">Lagre fil</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
+<translation id="8924469368910458384">Slett til begynnelsen av linjen</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minutt igjen</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minutt</translation>
+<translation id="8210608804940886430">Ned 1 s.</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dager</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timer igjen</translation>
+<translation id="5329858601952122676">&amp;Slett</translation>
+<translation id="6556866813142980365">Gjør om</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekunder</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutter</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">I går</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutter</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutter igjen</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> sekunder igjen</translation>
+<translation id="6903282483217634857">Flytt til høyre</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">For <ph name="NUMBER_DEFAULT"/> dager siden</translation>
+<translation id="8428213095426709021">Innstillinger</translation>
+<translation id="2497284189126895209">Alle filer</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutter igjen</translation>
+<translation id="5110450810124758964">For <ph name="NUMBER_ONE"/> dag siden</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="4320177379694898372">Ingen Internett-tilkobling</translation>
+<translation id="7814458197256864873">&amp;Kopier</translation>
+<translation id="3889424535448813030">Pil høyre</translation>
+<translation id="4229495110203539533">For <ph name="NUMBER_ONE"/> sekund siden</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekunder igjen</translation>
+<translation id="6829324100069873704">Gå tilbake til varsler</translation>
+<translation id="6528179044667508675">Ikke forstyrr</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutter</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Tillat varsler fra følgende:</translation>
+<translation id="2479520428668657293">Flytt til høyre og endre merkingen</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timer</translation>
+<translation id="1398853756734560583">Maksimer</translation>
+<translation id="4250229828105606438">Skjermdump</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timer</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutter igjen</translation>
+<translation id="2557207087669398617">Flytt til begynnelsen av linjen</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Marker &amp;alt</translation>
+<translation id="2168039046890040389">Opp 1 s.</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dager</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutter</translation>
+<translation id="6122334925474904337">Flytt ett ord til høyre og endre merkingen</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minutt</translation>
+<translation id="8448317557906454022">For <ph name="NUMBER_ZERO"/> sekunder siden</translation>
+<translation id="4927753642311223124">Her er det ikke noe nytt. Men intet nytt er jo godt nytt!</translation>
+<translation id="2482878487686419369">Varsler</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Rull hit</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Flytt ned</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timer</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB per sek</translation>
+<translation id="8394908167088220973">Media – spill av / pause</translation>
+<translation id="2148716181193084225">I dag</translation>
+<translation id="7960078400008666149">Ikke forstyrr i én time</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dager</translation>
+<translation id="2190355936436201913">(tom)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timer igjen</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekund igjen</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Rull mot høyre</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> time igjen</translation>
+<translation id="1413622004203049571">Deaktiver varsler fra <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Topp</translation>
+<translation id="2538759511191347839">Flytt til slutten av linjen og endre merkingen</translation>
+<translation id="928465423150706909">Flytt til slutten av linjen</translation>
+<translation id="8331626408530291785">Rull opp</translation>
+<translation id="7907591526440419938">Åpne filen</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Åpne mappen</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">For <ph name="NUMBER_DEFAULT"/> timer siden</translation>
+<translation id="815598010540052116">Rull ned</translation>
+<translation id="6808150112686056157">Media – stopp</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Gjenopprett</translation>
+<translation id="5349525451964472598">Flytt til venstre og endre merkingen</translation>
+<translation id="1781701194097416995">Flytt ett ord til venstre</translation>
+<translation id="1243314992276662751">Last opp</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag igjen</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Flytt ett ord til venstre og endre merkingen</translation>
+<translation id="945522503751344254">Gi tilbakemelding</translation>
+<translation id="9170848237812810038">&amp;Angre</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Tillat varsler fra følgende for hver bruker:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> sekunder igjen</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutter igjen</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Innstillinger</translation>
+<translation id="6845383723252244143">Velg mappe</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> sekunder igjen</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekunder</translation>
+<translation id="5583640892426849032">Tilbake-tasten</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dager</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> time</translation>
+<translation id="2679312662830811292">For <ph name="NUMBER_ONE"/> minutt siden</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB per sek</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
+<translation id="2704295676501803339">Flytt til venstre</translation>
+<translation id="9098468523912235228">For <ph name="NUMBER_DEFAULT"/> sekunder siden</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekunder igjen</translation>
+<translation id="566737009157135450">Slett ett ord bakover</translation>
+<translation id="436869212180315161">Trykk</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB per sek</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutter</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutter igjen</translation>
+<translation id="6040143037577758943">Lukk</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B per sek</translation>
+<translation id="7649070708921625228">Hjelp</translation>
+<translation id="2405367043325750948">Slett fremover</translation>
+<translation id="6699343763173986273">Media – neste spor</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> sekunder igjen</translation>
+<translation id="8226233771743600312">Ikke forstyrr i en dag</translation>
+<translation id="4252565523989510616">Slett ett ord fremover</translation>
+<translation id="7457942297256758195">Fjern alle</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutter</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dager igjen</translation>
+<translation id="6786750046913594791">Lukk mappen</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutter</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timer igjen</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekunder</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dager igjen</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB per sek</translation>
+<translation id="2743387203779672305">Kopiér til utklippstavlen</translation>
+<translation id="8371695176452482769">Snakk nå</translation>
+<translation id="1167268268675672572">Flytt til begynnelsen av linjen og endre merkingen</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Ikke forstyrr</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimer</translation>
+<translation id="6394627529324717982">Komma</translation>
+<translation id="3036649622769666520">Åpne filer</translation>
+<translation id="8328145009876646418">Venstre kant</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb
new file mode 100644
index 00000000000..81080223fd5
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_pl.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folder <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sek</translation>
+<translation id="9213479837033539041">Pozostało: <ph name="NUMBER_MANY"/> sek</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="1801827354178857021">Okres</translation>
+<translation id="1190609913194133056">Centrum powiadomień</translation>
+<translation id="7470933019269157899">Pozostało <ph name="NUMBER_DEFAULT"/> minut</translation>
+<translation id="5613020302032141669">Strzałka w lewo</translation>
+<translation id="4971687151119236543">Poprzedni utwór multimedialny</translation>
+<translation id="8602707065186045623">Plik <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> godz</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Anuluj</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Strzałka w górę</translation>
+<translation id="3969863827134279083">Przejdź do góry</translation>
+<translation id="7062130397825382308">Pozostała <ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> godz.</translation>
+<translation id="3990502903496589789">Krawędź po prawej</translation>
+<translation id="9038489124413477075">Folder bez nazwy</translation>
+<translation id="1940483897317142625">Usuń do końca wiersza</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dni</translation>
+<translation id="932327136139879170">Strona główna</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dni</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sek</translation>
+<translation id="3909791450649380159">Wy&amp;tnij</translation>
+<translation id="2560788951337264832">Pozostało <ph name="NUMBER_ZERO"/> minut</translation>
+<translation id="688711909580084195">Strona internetowa bez tytułu</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> dni temu</translation>
+<translation id="5076340679995252485">&amp;Wklej</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Przejdź o słowo w prawo</translation>
+<translation id="364720409959344976">Wybierz folder do przesłania</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> min temu</translation>
+<translation id="3234408098842461169">Strzałka w dół</translation>
+<translation id="3087734570205094154">Na dół</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min do końca</translation>
+<translation id="1860796786778352021">Zamknięcie powiadomienia</translation>
+<translation id="6364916375976753737">Przewiń w lewo</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> godz. temu</translation>
+<translation id="4218160142017529598">Usuń przed kursorem</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuty</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> min temu</translation>
+<translation id="6945221475159498467">Wybierz</translation>
+<translation id="6620110761915583480">Zapisz plik</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Usuń do początku wiersza</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Pozostała <ph name="NUMBER_ONE"/> minuta</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Strona w dół</translation>
+<translation id="1572103024875503863">Liczba dni: <ph name="NUMBER_MANY"/></translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> godz</translation>
+<translation id="5329858601952122676">&amp;Usuń</translation>
+<translation id="6556866813142980365">Ponów</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Wczoraj</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min</translation>
+<translation id="5517291721709019259">Pozostały <ph name="NUMBER_FEW"/> sekundy</translation>
+<translation id="6903282483217634857">Przejdź w prawo</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dni temu</translation>
+<translation id="8428213095426709021">Ustawienia</translation>
+<translation id="2497284189126895209">Wszystkie pliki</translation>
+<translation id="7487278341251176613">Pozostały <ph name="NUMBER_TWO"/> minuty</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dzień temu</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
+<translation id="4320177379694898372">Brak połączenia z internetem</translation>
+<translation id="7814458197256864873">&amp;Kopiuj</translation>
+<translation id="3889424535448813030">Strzałka w prawo</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> s temu</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sek</translation>
+<translation id="6829324100069873704">Wróć do powiadomień</translation>
+<translation id="6528179044667508675">Nie przeszkadzać</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekundy</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Zezwalaj na powiadomienia z:</translation>
+<translation id="2479520428668657293">Przejdź w prawo i zmodyfikuj zaznaczenie</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> godz.</translation>
+<translation id="1398853756734560583">Maksymalizuj</translation>
+<translation id="4250229828105606438">Zrzut ekranu</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> godz.</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min</translation>
+<translation id="2557207087669398617">Przejdź na początek wiersza</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Zaznacz &amp;wszystko</translation>
+<translation id="2168039046890040389">Strona do góry</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581">Liczba dni: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min</translation>
+<translation id="6122334925474904337">Przejdź o słowo w prawo i zmodyfikuj zaznaczenie</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Nic tu nie ma.</translation>
+<translation id="2482878487686419369">Powiadomienia</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Przewiń tutaj</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Przejdź w dół</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> godz.</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Odtwórz/wstrzymaj multimedia</translation>
+<translation id="2148716181193084225">Dzisiaj</translation>
+<translation id="7960078400008666149">Nie przeszkadzać przez godzinę</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> min temu</translation>
+<translation id="4115153316875436289">Liczba dni: <ph name="NUMBER_TWO"/></translation>
+<translation id="2190355936436201913">(puste)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> godz</translation>
+<translation id="152482086482215392">Pozostała <ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Przewiń w prawo</translation>
+<translation id="7414887922320653780">Pozostała <ph name="NUMBER_ONE"/> godzina</translation>
+<translation id="1413622004203049571">Wyłącz powiadomienia z <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Do góry</translation>
+<translation id="2538759511191347839">Przejdź na koniec wiersza i zmodyfikuj zaznaczenie</translation>
+<translation id="928465423150706909">Przejdź na koniec wiersza</translation>
+<translation id="8331626408530291785">Przewiń w górę</translation>
+<translation id="7907591526440419938">Otwórz plik</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Otwórz folder</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> godz. temu</translation>
+<translation id="815598010540052116">Przewiń w dół</translation>
+<translation id="6808150112686056157">Zatrzymaj multimedia</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Przywróć</translation>
+<translation id="5349525451964472598">Przejdź w lewo i zmodyfikuj zaznaczenie</translation>
+<translation id="1781701194097416995">Przejdź o słowo w lewo</translation>
+<translation id="1243314992276662751">Prześlij</translation>
+<translation id="50030952220075532">Pozostał <ph name="NUMBER_ONE"/> dzień</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Przejdź o słowo w lewo i zmodyfikuj zaznaczenie</translation>
+<translation id="945522503751344254">Wyślij zgłoszenie</translation>
+<translation id="9170848237812810038">&amp;Cofnij</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> godz. temu</translation>
+<translation id="6918245111648057970">Zezwól na powiadomienia dla każdego użytkownika z:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">Pozostało <ph name="NUMBER_MANY"/> minut</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Ustawienia</translation>
+<translation id="6845383723252244143">Wybierz folder</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundy</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920">Liczba dni: <ph name="NUMBER_FEW"/></translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> godz.</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min temu</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dzień</translation>
+<translation id="2704295676501803339">Przejdź w lewo</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> s temu</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sek</translation>
+<translation id="566737009157135450">Usuń słowo przed kursorem</translation>
+<translation id="436869212180315161">Kliknij</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> s temu</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">Pozostały <ph name="NUMBER_FEW"/> minuty</translation>
+<translation id="6040143037577758943">Zamknij</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Pomoc</translation>
+<translation id="2405367043325750948">Usuń za kursorem</translation>
+<translation id="6699343763173986273">Następny utwór multimedialny</translation>
+<translation id="5445120697129764393">Pozostało <ph name="NUMBER_DEFAULT"/> sekund</translation>
+<translation id="8226233771743600312">Nie przeszkadzać przez jeden dzień</translation>
+<translation id="4252565523989510616">Usuń słowo za kursorem</translation>
+<translation id="7457942297256758195">Wyczyść wszystkie</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> dni temu</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dni</translation>
+<translation id="6786750046913594791">Zamknij folder</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuty</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> godz</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dni</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Skopiuj do schowka</translation>
+<translation id="8371695176452482769">Mów teraz</translation>
+<translation id="1167268268675672572">Przejdź na początek wiersza i zmodyfikuj zaznaczenie</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Nie przeszkadzać</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimalizuj</translation>
+<translation id="6394627529324717982">Przecinek</translation>
+<translation id="3036649622769666520">Otwórz pliki</translation>
+<translation id="8328145009876646418">Krawędź po lewej</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
new file mode 100644
index 00000000000..0a5b85bbc9f
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+<translation id="4820616160060340806">Comando+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Pasta <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> segundos restantes</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> segundos restantes</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minutos restantes</translation>
+<translation id="1801827354178857021">Período</translation>
+<translation id="1190609913194133056">Central de Notificações</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minutos restantes</translation>
+<translation id="5613020302032141669">Seta para a esquerda</translation>
+<translation id="4971687151119236543">Faixa anterior da mídia</translation>
+<translation id="8602707065186045623">Arquivo <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> s</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> horas restantes</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> bytes</translation>
+<translation id="3660179305079774227">Seta para cima</translation>
+<translation id="3969863827134279083">Mover para cima</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> segundo restante</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="3990502903496589789">Borda direita</translation>
+<translation id="9038489124413477075">Pasta sem nome</translation>
+<translation id="1940483897317142625">Excluir até o fim da linha</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dias restantes</translation>
+<translation id="932327136139879170">Início</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minutos restantes</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dias restantes</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> segundos restantes</translation>
+<translation id="3909791450649380159">&amp;Recortar</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Página da web sem título</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Colar</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mover para palavra à direita</translation>
+<translation id="364720409959344976">Selecionar pasta para upload</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Seta para baixo</translation>
+<translation id="3087734570205094154">Parte inferior</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minutos restantes</translation>
+<translation id="1860796786778352021">Fechar notificação</translation>
+<translation id="6364916375976753737">Percorrer à esquerda</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hora atrás</translation>
+<translation id="4218160142017529598">Excluir para trás</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> minutos atrás</translation>
+<translation id="6945221475159498467">Selecionar</translation>
+<translation id="6620110761915583480">Salvar arquivo</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="8924469368910458384">Excluir até o começo da linha</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minuto restante</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8210608804940886430">Página para baixo</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dias</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> horas restantes</translation>
+<translation id="5329858601952122676">&amp;Excluir</translation>
+<translation id="6556866813142980365">Refazer</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> s</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Ontem</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minutos restantes</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Mover para a direita</translation>
+<translation id="6659594942844771486">Guia</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> dias atrás</translation>
+<translation id="8428213095426709021">Configurações</translation>
+<translation id="2497284189126895209">Todos os arquivos</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> dia atrás</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> s</translation>
+<translation id="4320177379694898372">Sem conexão com a Internet</translation>
+<translation id="7814458197256864873">Co&amp;piar</translation>
+<translation id="3889424535448813030">Seta para a direita</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> segundo atrás</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> segundos restantes</translation>
+<translation id="6829324100069873704">Voltar para notificações</translation>
+<translation id="6528179044667508675">Não perturbe</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Permitir as seguintes notificações:</translation>
+<translation id="2479520428668657293">Mover para a direita e modificar seleção</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
+<translation id="1398853756734560583">Maximizar</translation>
+<translation id="4250229828105606438">Captura de tela</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minutos restantes</translation>
+<translation id="2557207087669398617">Mover para o início da linha</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Selecionar &amp;tudo</translation>
+<translation id="2168039046890040389">Página para cima</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dias</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6122334925474904337">Mover para palavra à direita e modificar seleção</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Nada para ver aqui, siga em frente.</translation>
+<translation id="2482878487686419369">Notificações</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Percorrer até aqui</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Mover para baixo</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Reproduzir/pausar mídia</translation>
+<translation id="2148716181193084225">Hoje</translation>
+<translation id="7960078400008666149">Não perturbe por uma hora</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dias</translation>
+<translation id="2190355936436201913">(vazio)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> horas restantes</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> segundo restante</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Percorrer à direita</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hora restante</translation>
+<translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Parte superior</translation>
+<translation id="2538759511191347839">Mover para o fim da linha e modificar seleção</translation>
+<translation id="928465423150706909">Mover para o fim da linha</translation>
+<translation id="8331626408530291785">Percorrer para cima</translation>
+<translation id="7907591526440419938">Abrir arquivo</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Abrir pasta</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> horas atrás</translation>
+<translation id="815598010540052116">Percorrer para baixo</translation>
+<translation id="6808150112686056157">Parar mídia</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaurar</translation>
+<translation id="5349525451964472598">Mover para a esquerda e modificar seleção</translation>
+<translation id="1781701194097416995">Mover para palavra à esquerda</translation>
+<translation id="1243314992276662751">Fazer upload</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restante</translation>
+<translation id="8179976553408161302">Entrar</translation>
+<translation id="8471049483003785219">Mover para palavra à esquerda e modificar seleção</translation>
+<translation id="945522503751344254">Enviar comentários</translation>
+<translation id="9170848237812810038">&amp;Desfazer</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Permitir as seguintes notificações para cada usuário:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Configurações...</translation>
+<translation id="6845383723252244143">Selecionar pasta</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> s</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dias</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> minuto atrás</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
+<translation id="2704295676501803339">Mover para a esquerda</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> segundos atrás</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> segundos restantes</translation>
+<translation id="566737009157135450">Excluir palavra anterior</translation>
+<translation id="436869212180315161">Apertar</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minutes left</translation>
+<translation id="6040143037577758943">Fechar</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ajuda</translation>
+<translation id="2405367043325750948">Excluir para frente</translation>
+<translation id="6699343763173986273">Próxima faixa da mídia</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> segundos restantes</translation>
+<translation id="8226233771743600312">Não perturbe por um dia</translation>
+<translation id="4252565523989510616">Excluir palavra da frente</translation>
+<translation id="7457942297256758195">Limpar tudo</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dias restantes</translation>
+<translation id="6786750046913594791">Fechar pasta</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> horas restantes</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> s</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dias restantes</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copiar para a área de trabalho</translation>
+<translation id="8371695176452482769">Fale agora</translation>
+<translation id="1167268268675672572">Mover para o começo da linha e modificar seleção</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Não Perturbe</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimizar</translation>
+<translation id="6394627529324717982">Vírgula</translation>
+<translation id="3036649622769666520">Abrir arquivos</translation>
+<translation id="8328145009876646418">Borda esquerda</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
new file mode 100644
index 00000000000..fe4be36a725
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Pasta <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798">Há <ph name="NUMBER_MANY"/> horas</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> seg. restantes</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> seg. restantes</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> min. restantes</translation>
+<translation id="1801827354178857021">Período</translation>
+<translation id="1190609913194133056">Centro de Notificações</translation>
+<translation id="7470933019269157899">Faltam <ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="5613020302032141669">Seta para a esquerda</translation>
+<translation id="4971687151119236543">Faixa anterior de multimédia</translation>
+<translation id="8602707065186045623">Ficheiro <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> seg.</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> horas restantes</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Seta para cima</translation>
+<translation id="3969863827134279083">Mover para cima</translation>
+<translation id="7062130397825382308">Falta <ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="3990502903496589789">Margem direita</translation>
+<translation id="9038489124413477075">Pasta sem nome</translation>
+<translation id="1940483897317142625">Eliminar para o fim da linha</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dias restantes</translation>
+<translation id="932327136139879170">Página inicial</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> min. restantes</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dias restantes</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> seg. restantes</translation>
+<translation id="3909791450649380159">Cor&amp;tar</translation>
+<translation id="2560788951337264832">Faltam <ph name="NUMBER_ZERO"/> minutos</translation>
+<translation id="688711909580084195">Página Web Sem Nome</translation>
+<translation id="3353284378027041011">Há <ph name="NUMBER_FEW"/> dias</translation>
+<translation id="5076340679995252485">C&amp;olar</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mover palavra para a direita</translation>
+<translation id="364720409959344976">Selecionar Pasta a Carregar</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Há <ph name="NUMBER_TWO"/> min.</translation>
+<translation id="3234408098842461169">Seta para baixo</translation>
+<translation id="3087734570205094154">Parte inferior</translation>
+<translation id="8828991073132329143">Faltam <ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min. restante</translation>
+<translation id="1860796786778352021">Fechar notificação</translation>
+<translation id="6364916375976753737">Deslocar-se para a esquerda</translation>
+<translation id="2629089419211541119">Há <ph name="NUMBER_ONE"/> hora</translation>
+<translation id="4218160142017529598">Eliminar para trás</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minutos</translation>
+<translation id="6982279413068714821">Há <ph name="NUMBER_DEFAULT"/> min.</translation>
+<translation id="6945221475159498467">Seleccionar</translation>
+<translation id="6620110761915583480">Guardar ficheiro</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="8924469368910458384">Eliminar para o início da linha</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Falta <ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8210608804940886430">Página para baixo</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dias</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> horas restantes</translation>
+<translation id="5329858601952122676">E&amp;liminar</translation>
+<translation id="6556866813142980365">Refazer</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> seg.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="7275974018215686543">Há <ph name="NUMBER_MANY"/> seg.</translation>
+<translation id="7781829728241885113">Ontem</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> min. restantes</translation>
+<translation id="5517291721709019259">Faltam <ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="6903282483217634857">Mover para a direita</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Há <ph name="NUMBER_DEFAULT"/> dias</translation>
+<translation id="8428213095426709021">Definições</translation>
+<translation id="2497284189126895209">Todos os ficheiros</translation>
+<translation id="7487278341251176613">Faltam <ph name="NUMBER_TWO"/> minutos</translation>
+<translation id="5110450810124758964">Há <ph name="NUMBER_ONE"/> dia</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> seg.</translation>
+<translation id="4320177379694898372">Sem ligação à Internet</translation>
+<translation id="7814458197256864873">&amp;Copiar</translation>
+<translation id="3889424535448813030">Seta para a direita</translation>
+<translation id="4229495110203539533">Há <ph name="NUMBER_ONE"/> seg.</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> seg. restantes</translation>
+<translation id="6829324100069873704">Voltar às notificações</translation>
+<translation id="6528179044667508675">Não incomodar</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min.</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Permitir notificações de:</translation>
+<translation id="2479520428668657293">Mover para a direita e modificar seleção</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> horas</translation>
+<translation id="1398853756734560583">Maximizar</translation>
+<translation id="4250229828105606438">Captura de ecrã</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> horas</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> min. restantes</translation>
+<translation id="2557207087669398617">Mover para o início da linha</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Seleccion&amp;ar tudo</translation>
+<translation id="2168039046890040389">Página para cima</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dias</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6122334925474904337">Mover palavra para a direita e modificar seleção</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuto</translation>
+<translation id="8448317557906454022">Há <ph name="NUMBER_ZERO"/> seg.</translation>
+<translation id="4927753642311223124">Nada de novo a apresentar por aqui.</translation>
+<translation id="2482878487686419369">Notificações</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Deslocar-se para aqui</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Mover para baixo</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> horas</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Reproduzir/interromper multimédia</translation>
+<translation id="2148716181193084225">Hoje</translation>
+<translation id="7960078400008666149">Não incomodar durante uma hora</translation>
+<translation id="4373894838514502496">Há <ph name="NUMBER_FEW"/> min.</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dias</translation>
+<translation id="2190355936436201913">(vazio)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> horas restantes</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> seg. restante</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Deslocar-se para a direita</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hora restante</translation>
+<translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Parte superior</translation>
+<translation id="2538759511191347839">Mover para o fim da linha e modificar seleção</translation>
+<translation id="928465423150706909">Mover para o fim da linha</translation>
+<translation id="8331626408530291785">Deslocar-se para cima</translation>
+<translation id="7907591526440419938">Abrir ficheiro</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Abrir pasta</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Há <ph name="NUMBER_DEFAULT"/> horas</translation>
+<translation id="815598010540052116">Deslocar-se para baixo</translation>
+<translation id="6808150112686056157">Parar multimédia</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Restaurar</translation>
+<translation id="5349525451964472598">Mover para a esquerda e modificar seleção</translation>
+<translation id="1781701194097416995">Mover palavra para a esquerda</translation>
+<translation id="1243314992276662751">Carregar</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dia restante</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Mover palavra para a esquerda e modificar seleção</translation>
+<translation id="945522503751344254">Enviar comentários</translation>
+<translation id="9170848237812810038">An&amp;ular</translation>
+<translation id="1285266685456062655">Há <ph name="NUMBER_FEW"/> horas</translation>
+<translation id="6918245111648057970">Permitir as seguintes notificações para cada utilizador:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> segundo</translation>
+<translation id="1270251962578273213">Faltam <ph name="NUMBER_TWO"/> segundos</translation>
+<translation id="3994835489895548312">Faltam <ph name="NUMBER_MANY"/> minutos</translation>
+<translation id="6358975074282722691">Há <ph name="NUMBER_TWO"/> seg.</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Definições...</translation>
+<translation id="6845383723252244143">Seleccionar pasta</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> segundos</translation>
+<translation id="5368780922436099921">Faltam <ph name="NUMBER_ZERO"/> segundos</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> seg.</translation>
+<translation id="5583640892426849032">Retrocesso</translation>
+<translation id="5263972071113911534">Há <ph name="NUMBER_MANY"/> dias</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dias</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hora</translation>
+<translation id="2679312662830811292">Há <ph name="NUMBER_ONE"/> min.</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dia</translation>
+<translation id="2704295676501803339">Mover para a esquerda</translation>
+<translation id="9098468523912235228">Há <ph name="NUMBER_DEFAULT"/> seg.</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> seg. restantes</translation>
+<translation id="566737009157135450">Eliminar uma palavra para trás</translation>
+<translation id="436869212180315161">Premir</translation>
+<translation id="4860787810836767172">Há <ph name="NUMBER_FEW"/> seg.</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutos</translation>
+<translation id="1858722859751911017">Faltam <ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="6040143037577758943">Fechar</translation>
+<translation id="1101671447232096497">Há <ph name="NUMBER_MANY"/> min.</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ajuda</translation>
+<translation id="2405367043325750948">Eliminar para a frente</translation>
+<translation id="6699343763173986273">Faixa seguinte de multimédia</translation>
+<translation id="5445120697129764393">Faltam <ph name="NUMBER_DEFAULT"/> segundos</translation>
+<translation id="8226233771743600312">Não incomodar durante um dia</translation>
+<translation id="4252565523989510616">Eliminar uma palavra para a frente</translation>
+<translation id="7457942297256758195">Limpar Tudo</translation>
+<translation id="822618367988303761">Há <ph name="NUMBER_TWO"/> dias</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min.</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dias restantes</translation>
+<translation id="6786750046913594791">Fechar pasta</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutos</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> horas restantes</translation>
+<translation id="8959208747503200525">Há <ph name="NUMBER_TWO"/> horas</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> seg.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> seg.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> segundos</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dias restantes</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copiar para a área de transferência</translation>
+<translation id="8371695176452482769">Falar agora</translation>
+<translation id="1167268268675672572">Mover para o início da linha e modificar seleção</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Não incomodar</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimizar</translation>
+<translation id="6394627529324717982">Vírgula</translation>
+<translation id="3036649622769666520">Abrir ficheiros</translation>
+<translation id="8328145009876646418">Margem esquerda</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> segundos</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb
new file mode 100644
index 00000000000..18183f1161c
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ro.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Dosarul <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Sfârșit</translation>
+<translation id="5341849548509163798">Acum <ph name="NUMBER_MANY"/> ore</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secunde rămase</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secunde rămase</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> de minute rămase</translation>
+<translation id="1801827354178857021">Punct</translation>
+<translation id="1190609913194133056">Centrul pentru notificări</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minute rămase</translation>
+<translation id="5613020302032141669">Săgeată spre stânga</translation>
+<translation id="4971687151119236543">Melodia anterioară din conținutul media</translation>
+<translation id="8602707065186045623">Fișier <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918">Acum <ph name="NUMBER_ZERO"/> minute</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secunde</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ore rămase</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Anulați</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Săgeată în sus</translation>
+<translation id="3969863827134279083">Mutați în sus</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> secundă rămasă</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> de ore</translation>
+<translation id="3990502903496589789">Marginea dreaptă</translation>
+<translation id="9038489124413477075">Dosar fără nume</translation>
+<translation id="1940483897317142625">Ștergeți până la sfârșitul rândului</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> de minute</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> zile rămase</translation>
+<translation id="932327136139879170">Pagina de pornire</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minute rămase</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> zile rămase</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secunde rămase</translation>
+<translation id="3909791450649380159">&amp;Tăiați</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minute rămase</translation>
+<translation id="688711909580084195">Pagină web fără titlu</translation>
+<translation id="3353284378027041011">Acum <ph name="NUMBER_FEW"/> zile</translation>
+<translation id="5076340679995252485">&amp;Inserați</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Mutați la cuvântul următor</translation>
+<translation id="364720409959344976">Selectați un dosar de încărcat</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Acum <ph name="NUMBER_TWO"/> minute</translation>
+<translation id="3234408098842461169">Săgeată în jos</translation>
+<translation id="3087734570205094154">Jos</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> secunde rămase</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut rămas</translation>
+<translation id="1860796786778352021">Buton de închidere a notificării</translation>
+<translation id="6364916375976753737">Derulați spre stânga</translation>
+<translation id="2629089419211541119">Acum <ph name="NUMBER_ONE"/> oră</translation>
+<translation id="4218160142017529598">Ștergeți înapoi</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minute</translation>
+<translation id="6982279413068714821">Acum <ph name="NUMBER_DEFAULT"/> de minute</translation>
+<translation id="6945221475159498467">Selectați</translation>
+<translation id="6620110761915583480">Salvați fișierul</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> secunde</translation>
+<translation id="8924469368910458384">Ștergeți până la începutul rândului</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> ore</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut rămas</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8210608804940886430">O pagină mai jos</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> zile</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ore rămase</translation>
+<translation id="5329858601952122676">&amp;Ștergeți</translation>
+<translation id="6556866813142980365">Repetați</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secunde</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KO</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543">Acum <ph name="NUMBER_MANY"/> secunde</translation>
+<translation id="7781829728241885113">Ieri</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minute</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minute rămase</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> secunde rămase</translation>
+<translation id="6903282483217634857">Mutați spre dreapta</translation>
+<translation id="6659594942844771486">Filă</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Acum <ph name="NUMBER_DEFAULT"/> de zile</translation>
+<translation id="8428213095426709021">Setări</translation>
+<translation id="2497284189126895209">Toate fișierele</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minute rămase</translation>
+<translation id="5110450810124758964">Acum <ph name="NUMBER_ONE"/> zi</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> secundă</translation>
+<translation id="4320177379694898372">Fără conexiune la internet</translation>
+<translation id="7814458197256864873">&amp;Copiați</translation>
+<translation id="3889424535448813030">Săgeată spre dreapta</translation>
+<translation id="4229495110203539533">Acum <ph name="NUMBER_ONE"/> secundă</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> de secunde rămase</translation>
+<translation id="6829324100069873704">Reveniți la notificări</translation>
+<translation id="6528179044667508675">Nu deranja</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> secunde</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minute</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> ore rămase</translation>
+<translation id="7135556860107312402">Permiteți notificările de la următoarele:</translation>
+<translation id="2479520428668657293">Mutați spre dreapta și modificați selecția</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ore</translation>
+<translation id="1398853756734560583">Maximizați</translation>
+<translation id="4250229828105606438">Captură de ecran</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ore</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minute rămase</translation>
+<translation id="2557207087669398617">Mutați la începutul rândului</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Select&amp;ați tot</translation>
+<translation id="2168039046890040389">O pagină mai sus</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> minute</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> de zile</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minute</translation>
+<translation id="6122334925474904337">Mutați la cuvântul următor și modificați selecția</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8448317557906454022">Acum <ph name="NUMBER_ZERO"/> secunde</translation>
+<translation id="4927753642311223124">Nimic de văzut aici, treceți mai departe.</translation>
+<translation id="2482878487686419369">Notificări</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> zile</translation>
+<translation id="3183922693828471536">Derulați până aici</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Mutați în jos</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ore</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KO/s</translation>
+<translation id="8394908167088220973">Redați/întrerupeți conținutul media</translation>
+<translation id="2148716181193084225">Astăzi</translation>
+<translation id="7960078400008666149">Nu deranja o oră</translation>
+<translation id="4373894838514502496">Acum <ph name="NUMBER_FEW"/> minute</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> zile</translation>
+<translation id="2190355936436201913">(gol)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> de ore rămase</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> secundă rămasă</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Derulați spre dreapta</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> oră rămasă</translation>
+<translation id="1413622004203049571">Dezactivați notificările de la <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Sus</translation>
+<translation id="2538759511191347839">Mutați la sfârșitul rândului și modificați selecția</translation>
+<translation id="928465423150706909">Mutați la sfârșitul rândului</translation>
+<translation id="8331626408530291785">Derulați în sus</translation>
+<translation id="7907591526440419938">Deschideți fișierul</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> zile rămase</translation>
+<translation id="2803313416453193357">Deschideți dosarul</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Acum <ph name="NUMBER_DEFAULT"/> de ore</translation>
+<translation id="815598010540052116">Derulați în jos</translation>
+<translation id="6808150112686056157">Opriți conținutul media</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> minute rămase</translation>
+<translation id="3157931365184549694">Restabiliți</translation>
+<translation id="5349525451964472598">Mutați spre stânga și modificați selecția</translation>
+<translation id="1781701194097416995">Mutați la cuvântul anterior</translation>
+<translation id="1243314992276662751">Încărcați</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> zi rămasă</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Mutați la cuvântul anterior și modificați selecția</translation>
+<translation id="945522503751344254">Trimiteți feedback</translation>
+<translation id="9170848237812810038">&amp;Anulați</translation>
+<translation id="1285266685456062655">Acum <ph name="NUMBER_FEW"/> ore</translation>
+<translation id="6918245111648057970">Permiteți notificări de la următoarele servicii pentru fiecare utilizator:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> secundă</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> secunde rămase</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> de minute rămase</translation>
+<translation id="6358975074282722691">Acum <ph name="NUMBER_TWO"/> secunde</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Setări...</translation>
+<translation id="6845383723252244143">Selectați dosarul</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> secunde</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> secunde rămase</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secunde</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">Acum <ph name="NUMBER_MANY"/> zile</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> zile</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> oră</translation>
+<translation id="2679312662830811292">Acum <ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8788572795284305350">Acum <ph name="NUMBER_ZERO"/> ore</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> zi</translation>
+<translation id="2704295676501803339">Mutați spre stânga</translation>
+<translation id="9098468523912235228">Acum <ph name="NUMBER_DEFAULT"/> de secunde</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secunde rămase</translation>
+<translation id="566737009157135450">Ștergeți înapoi un cuvânt</translation>
+<translation id="436869212180315161">Apăsați</translation>
+<translation id="4860787810836767172">Acum <ph name="NUMBER_FEW"/> secunde</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minute</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minute rămase</translation>
+<translation id="6040143037577758943">Închideți</translation>
+<translation id="1101671447232096497">Acum <ph name="NUMBER_MANY"/> minute</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Ajutor</translation>
+<translation id="2405367043325750948">Ștergeți înainte</translation>
+<translation id="6699343763173986273">Melodia următoare din conținutul media</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> de secunde rămase</translation>
+<translation id="8226233771743600312">Nu deranja o zi</translation>
+<translation id="4252565523989510616">Ștergeți înainte un cuvânt</translation>
+<translation id="7457942297256758195">Ștergeți tot</translation>
+<translation id="822618367988303761">Acum <ph name="NUMBER_TWO"/> zile</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minute</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> de zile rămase</translation>
+<translation id="6786750046913594791">Închideți dosarul</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ore rămase</translation>
+<translation id="8959208747503200525">Acum <ph name="NUMBER_TWO"/> ore</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> de secunde</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secunde</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> zile rămase</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Copiați în clipboard</translation>
+<translation id="8371695176452482769">Rostiți acum</translation>
+<translation id="1167268268675672572">Mutați la începutul rândului și modificați selecția</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Nu deranja</translation>
+<translation id="6978839998405419496">Acum <ph name="NUMBER_ZERO"/> zile</translation>
+<translation id="5941711191222866238">Minimizați</translation>
+<translation id="6394627529324717982">Virgulă</translation>
+<translation id="3036649622769666520">Deschideți fișierele</translation>
+<translation id="8328145009876646418">Marginea stângă</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> secunde</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
new file mode 100644
index 00000000000..c81b31e85c5
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Папка <ph name="FOLDER_NAME"/>.</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">Завершить</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> сек.</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> мин.</translation>
+<translation id="1801827354178857021">Период</translation>
+<translation id="1190609913194133056">Центр оповещений</translation>
+<translation id="7470933019269157899">Осталось <ph name="NUMBER_DEFAULT"/> минут</translation>
+<translation id="5613020302032141669">Стрелка влево</translation>
+<translation id="4971687151119236543">Предыдущий трек</translation>
+<translation id="8602707065186045623">Файл <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек.</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> ч.</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Отмена</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> Б</translation>
+<translation id="3660179305079774227">Стрелка вверх</translation>
+<translation id="3969863827134279083">Перейти вверх</translation>
+<translation id="7062130397825382308">Осталась <ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> МБ/с</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ч.</translation>
+<translation id="3990502903496589789">Правый край</translation>
+<translation id="9038489124413477075">Без названия</translation>
+<translation id="1940483897317142625">Удалить текст до конца строки</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин.</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> дн.</translation>
+<translation id="932327136139879170">Главная страница</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> мин.</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> дн.</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> сек.</translation>
+<translation id="3909791450649380159">Выре&amp;зать</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Страница без названия</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> дн. назад</translation>
+<translation id="5076340679995252485">&amp;Вставить</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> ТБ</translation>
+<translation id="7139614227326422685">Перейти вправо к следующему слову</translation>
+<translation id="364720409959344976">Выберите папку для загрузки</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Стрелка вниз</translation>
+<translation id="3087734570205094154">Низ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> мин.</translation>
+<translation id="1860796786778352021">Закрыть оповещение</translation>
+<translation id="6364916375976753737">Прокрутка влево</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ч. назад</translation>
+<translation id="4218160142017529598">Удалить предыдущий символ</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> мин.</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> мин. назад</translation>
+<translation id="6945221475159498467">Выбрать</translation>
+<translation id="6620110761915583480">Сохранить файл</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> сек.</translation>
+<translation id="8924469368910458384">Удалить текст до начала строки</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Осталась <ph name="NUMBER_ONE"/> минута</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин.</translation>
+<translation id="8210608804940886430">Прокрутка вниз</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> дн.</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> ч.</translation>
+<translation id="5329858601952122676">&amp;Удалить</translation>
+<translation id="6556866813142980365">Повторить</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> КБ</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> мин.</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Вчера</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> мин.</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="5517291721709019259">Осталось <ph name="NUMBER_FEW"/> секунды</translation>
+<translation id="6903282483217634857">Перейти вправо</translation>
+<translation id="6659594942844771486">Вкладка</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> МБ</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> дн. назад</translation>
+<translation id="8428213095426709021">Настройки</translation>
+<translation id="2497284189126895209">Все файлы</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> дн. назад</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="4320177379694898372">Нет подключения к Интернету</translation>
+<translation id="7814458197256864873">&amp;Копировать</translation>
+<translation id="3889424535448813030">Стрелка вправо</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> с. назад</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="6829324100069873704">Назад к оповещениям</translation>
+<translation id="6528179044667508675">Не беспокоить</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин.</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Разрешить оповещения от:</translation>
+<translation id="2479520428668657293">Перейти вправо и изменить выделение</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ч.</translation>
+<translation id="1398853756734560583">Развернуть</translation>
+<translation id="4250229828105606438">Скриншот</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ч.</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> мин.</translation>
+<translation id="2557207087669398617">Перейти к началу строки</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> ГБ</translation>
+<translation id="1901303067676059328">Выделить &amp;все</translation>
+<translation id="2168039046890040389">Вверх</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> дн.</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин.</translation>
+<translation id="6122334925474904337">Перейти вправо к следующему слову и изменить выделение</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> мин.</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Оповещений нет.</translation>
+<translation id="2482878487686419369">Оповещения</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Прокрутить до этого места</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Перейти вниз</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ч.</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> КБ/с</translation>
+<translation id="8394908167088220973">Воспроизведение/пауза</translation>
+<translation id="2148716181193084225">Сегодня</translation>
+<translation id="7960078400008666149">Не беспокоить (1 час)</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> мин. назад</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дня</translation>
+<translation id="2190355936436201913">(пусто)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> ч.</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Прокрутка вправо</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> ч.</translation>
+<translation id="1413622004203049571">Отключить оповещения от <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Наверх</translation>
+<translation id="2538759511191347839">Перейти к концу строки и изменить выделение</translation>
+<translation id="928465423150706909">Перейти к концу строки</translation>
+<translation id="8331626408530291785">Прокрутка вверх</translation>
+<translation id="7907591526440419938">Открытие файла</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Открыть папку.</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ч. назад</translation>
+<translation id="815598010540052116">Прокрутка вниз</translation>
+<translation id="6808150112686056157">Остановить</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Восстановить</translation>
+<translation id="5349525451964472598">Перейти влево и изменить выделение</translation>
+<translation id="1781701194097416995">Перейти влево к следующему слову</translation>
+<translation id="1243314992276662751">Загрузить</translation>
+<translation id="50030952220075532">Остался <ph name="NUMBER_ONE"/> день</translation>
+<translation id="8179976553408161302">ВВОД</translation>
+<translation id="8471049483003785219">Перейти влево к следующему слову и изменить выделение</translation>
+<translation id="945522503751344254">Отправить отзыв</translation>
+<translation id="9170848237812810038">&amp;Отменить</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ч. назад</translation>
+<translation id="6918245111648057970">Разрешить оповещения для каждого пользователя:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> ПБ</translation>
+<translation id="2983818520079887040">Настройки...</translation>
+<translation id="6845383723252244143">Выбор папки</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="5583640892426849032">Клавиша возврата (Backspace)</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> дн.</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> час</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> мин. назад</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> ГБ/с</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> день</translation>
+<translation id="2704295676501803339">Перейти влево</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> с. назад</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> сек.</translation>
+<translation id="566737009157135450">Удалить предыдущее слово</translation>
+<translation id="436869212180315161">Нажать</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> с. назад</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> ТБ/с</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> мин.</translation>
+<translation id="1858722859751911017">Осталось <ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="6040143037577758943">Закрыть</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> Б/с</translation>
+<translation id="7649070708921625228">Справка</translation>
+<translation id="2405367043325750948">Удалить следующий символ</translation>
+<translation id="6699343763173986273">Следующий трек</translation>
+<translation id="5445120697129764393">Осталось <ph name="NUMBER_DEFAULT"/> секунд</translation>
+<translation id="8226233771743600312">Не беспокоить (1 день)</translation>
+<translation id="4252565523989510616">Удалить следующее слово</translation>
+<translation id="7457942297256758195">Очистить все</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> дн.</translation>
+<translation id="6786750046913594791">Закрыть папку.</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> ч.</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> сек.</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> дн.</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> ПБ/с</translation>
+<translation id="2743387203779672305">Скопировать в буфер</translation>
+<translation id="8371695176452482769">Говорите</translation>
+<translation id="1167268268675672572">Перейти к началу строки и изменить выделение</translation>
+<translation id="6965382102122355670">ОК</translation>
+<translation id="7850320739366109486">Не беспокоить</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Свернуть</translation>
+<translation id="6394627529324717982">Запятая</translation>
+<translation id="3036649622769666520">Открытие файлов</translation>
+<translation id="8328145009876646418">Левый край</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> сек.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb
new file mode 100644
index 00000000000..b7c1b1a4daa
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_sk.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Priečinok <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942">Počet zvyšných sekúnd: <ph name="NUMBER_FEW"/></translation>
+<translation id="9213479837033539041">Počet zvyšných sekúnd: <ph name="NUMBER_MANY"/></translation>
+<translation id="1209866192426315618">Počet zvyšných minút: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="1801827354178857021">Bodka</translation>
+<translation id="1190609913194133056">Centrum upozornení</translation>
+<translation id="7470933019269157899">Zostáva <ph name="NUMBER_DEFAULT"/> minút</translation>
+<translation id="5613020302032141669">Šípka doľava</translation>
+<translation id="4971687151119236543">Média – predchádzajúca stopa</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> Súbor (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252">Počet sekúnd: <ph name="NUMBER_TWO"/></translation>
+<translation id="7511635910912978956">Počet zvyšných hodín: <ph name="NUMBER_FEW"/></translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Zrušiť</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Šípka nahor</translation>
+<translation id="3969863827134279083">Presunúť nahor</translation>
+<translation id="7062130397825382308">Zostáva <ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928">Počet hodín: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3990502903496589789">Pravý okraj</translation>
+<translation id="9038489124413477075">Priečinok bez názvu</translation>
+<translation id="1940483897317142625">Odstrániť po koniec riadka</translation>
+<translation id="8507996248087185956">Počet minút: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3520476450377425184">Počet zvyšných dní: <ph name="NUMBER_MANY"/></translation>
+<translation id="932327136139879170">Domov</translation>
+<translation id="5600907569873192868">Počet zvyšných minút: <ph name="NUMBER_MANY"/></translation>
+<translation id="8666066831007952346">Počet zvyšných dní: <ph name="NUMBER_TWO"/></translation>
+<translation id="6390842777729054533">Počet zvyšných sekúnd: <ph name="NUMBER_ZERO"/></translation>
+<translation id="3909791450649380159">&amp;Vystrihnúť</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Nepomenovaná webová stránka</translation>
+<translation id="3353284378027041011">Pred <ph name="NUMBER_FEW"/> dňami</translation>
+<translation id="5076340679995252485">&amp;Vložiť</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Presunúť slovo doprava</translation>
+<translation id="364720409959344976">Výber priečinka na nahranie</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Šípka nadol</translation>
+<translation id="3087734570205094154">Spodok</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">Počet zvyšných minút: <ph name="NUMBER_ONE"/></translation>
+<translation id="1860796786778352021">Zavrieť upozornenie</translation>
+<translation id="6364916375976753737">Rolovať doľava</translation>
+<translation id="2629089419211541119">Pred <ph name="NUMBER_ONE"/> hod</translation>
+<translation id="4218160142017529598">Odstrániť predchádzajúci znak</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="6982279413068714821">Pred <ph name="NUMBER_DEFAULT"/> minútami</translation>
+<translation id="6945221475159498467">Vybrať</translation>
+<translation id="6620110761915583480">Uložiť súbor</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekúnd</translation>
+<translation id="8924469368910458384">Odstrániť po začiatok riadka</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Zostáva <ph name="NUMBER_ONE"/> minúta</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minúta</translation>
+<translation id="8210608804940886430">Stránkovať nadol</translation>
+<translation id="1572103024875503863">Počet dní: <ph name="NUMBER_MANY"/></translation>
+<translation id="7163503212501929773">Počet zvyšných hodín: <ph name="NUMBER_MANY"/></translation>
+<translation id="5329858601952122676">&amp;Odstrániť</translation>
+<translation id="6556866813142980365">Znova</translation>
+<translation id="8088823334188264070">Počet sekúnd: <ph name="NUMBER_MANY"/></translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Včera</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minúty</translation>
+<translation id="50960180632766478">Počet zvyšných minút: <ph name="NUMBER_FEW"/></translation>
+<translation id="5517291721709019259">Zostávajú <ph name="NUMBER_FEW"/> sekundy</translation>
+<translation id="6903282483217634857">Presunúť doprava</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Pred <ph name="NUMBER_DEFAULT"/> dňami</translation>
+<translation id="8428213095426709021">Nastavenia</translation>
+<translation id="2497284189126895209">Všetky súbory</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964">Pred <ph name="NUMBER_ONE"/> dňom</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="4320177379694898372">Žiadne internetové pripojenie</translation>
+<translation id="7814458197256864873">&amp;Kopírovať</translation>
+<translation id="3889424535448813030">Šípka doprava</translation>
+<translation id="4229495110203539533">Pred <ph name="NUMBER_ONE"/> s</translation>
+<translation id="2544782972264605588">Počet zvyšných sekúnd: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6829324100069873704">Prejsť späť na upozornenia</translation>
+<translation id="6528179044667508675">Nerušiť</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="290555789621781773">Počet minút: <ph name="NUMBER_TWO"/></translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Povoliť prijímanie upozornení od:</translation>
+<translation id="2479520428668657293">Presunúť doprava a upraviť výber</translation>
+<translation id="8112886015144590373">Počet hodín: <ph name="NUMBER_FEW"/></translation>
+<translation id="1398853756734560583">Maximalizovať</translation>
+<translation id="4250229828105606438">Snímka obrazovky</translation>
+<translation id="6690744523875189208">Počet hodín: <ph name="NUMBER_TWO"/></translation>
+<translation id="5260878308685146029">Počet zvyšných minút: <ph name="NUMBER_TWO"/></translation>
+<translation id="2557207087669398617">Presunúť na začiatok riadka</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Vybrať &amp;všetko</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581">Počet dní: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734">Počet minút: <ph name="NUMBER_MANY"/></translation>
+<translation id="6122334925474904337">Presunúť slovo doprava a upraviť výber</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minúta</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Tu sa nič nenachádza, pokračujte ďalej.</translation>
+<translation id="2482878487686419369">Upozornenia</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Rolovať na toto miesto</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Presunúť nadol</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401">Počet hodín: <ph name="NUMBER_MANY"/></translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/s</translation>
+<translation id="8394908167088220973">Média – prehrať / pozastaviť</translation>
+<translation id="2148716181193084225">Dnes</translation>
+<translation id="7960078400008666149">Nerušiť jednu hodinu</translation>
+<translation id="4373894838514502496">Pred <ph name="NUMBER_FEW"/> min</translation>
+<translation id="4115153316875436289">Počet dní: <ph name="NUMBER_TWO"/></translation>
+<translation id="2190355936436201913">(prázdne)</translation>
+<translation id="1164369517022005061">Počet zvyšných hodín: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="152482086482215392">Zostáva <ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Rolovať doprava</translation>
+<translation id="7414887922320653780">Zostáva <ph name="NUMBER_ONE"/> hodina</translation>
+<translation id="1413622004203049571">Zakázať upozornenia od <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Vrch</translation>
+<translation id="2538759511191347839">Presunúť na koniec riadka a upraviť výber</translation>
+<translation id="928465423150706909">Presunúť na koniec riadka</translation>
+<translation id="8331626408530291785">Rolovať nahor</translation>
+<translation id="7907591526440419938">Otvoriť súbor</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Otvoriť priečinok</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Pred <ph name="NUMBER_DEFAULT"/> hodinami</translation>
+<translation id="815598010540052116">Rolovať nadol</translation>
+<translation id="6808150112686056157">Médiá – zastaviť</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Obnoviť</translation>
+<translation id="5349525451964472598">Presunúť doľava a upraviť výber</translation>
+<translation id="1781701194097416995">Presunúť slovo doľava</translation>
+<translation id="1243314992276662751">Nahrať</translation>
+<translation id="50030952220075532">Zostáva <ph name="NUMBER_ONE"/> deň</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Presunúť slovo doľava a upraviť výber</translation>
+<translation id="945522503751344254">Poslať spätnú väzbu</translation>
+<translation id="9170848237812810038">&amp;Naspäť</translation>
+<translation id="1285266685456062655">Pred <ph name="NUMBER_FEW"/> hodinami</translation>
+<translation id="6918245111648057970">Povoliť upozornenia na nasledujúce položky pre každého používateľa:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1270251962578273213">Zostávajú <ph name="NUMBER_TWO"/> sekundy</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Nastavenia...</translation>
+<translation id="6845383723252244143">Vybrať priečinok</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekundy</translation>
+<translation id="5368780922436099921">Zostáva <ph name="NUMBER_ZERO"/> sekúnd</translation>
+<translation id="1095623615273566396">Počet sekúnd: <ph name="NUMBER_FEW"/></translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920">Počet dní: <ph name="NUMBER_FEW"/></translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hodina</translation>
+<translation id="2679312662830811292">Pred <ph name="NUMBER_ONE"/> min</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> deň</translation>
+<translation id="2704295676501803339">Presunúť doľava</translation>
+<translation id="9098468523912235228">Pred <ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="494645311413743213">Počet zvyšných sekúnd: <ph name="NUMBER_TWO"/></translation>
+<translation id="566737009157135450">Odstrániť predchádzajúce slovo</translation>
+<translation id="436869212180315161">Stlačiť</translation>
+<translation id="4860787810836767172">Pred <ph name="NUMBER_FEW"/> s</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minút</translation>
+<translation id="1858722859751911017">Zostávajú <ph name="NUMBER_FEW"/> minúty</translation>
+<translation id="6040143037577758943">Zatvoriť</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Pomocník</translation>
+<translation id="2405367043325750948">Odstrániť nasledujúci znak</translation>
+<translation id="6699343763173986273">Média – ďalšia stopa</translation>
+<translation id="5445120697129764393">Zostáva <ph name="NUMBER_DEFAULT"/> sekúnd</translation>
+<translation id="8226233771743600312">Nerušiť jeden deň</translation>
+<translation id="4252565523989510616">Odstrániť nasledujúce slovo</translation>
+<translation id="7457942297256758195">Vymazať všetky</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565">Počet minút: <ph name="NUMBER_FEW"/></translation>
+<translation id="1963692530539281474">Počet zvyšných dní: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6786750046913594791">Zatvoriť priečinok</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minúty</translation>
+<translation id="5906719743126878045">Počet zvyšných hodín: <ph name="NUMBER_TWO"/></translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940">Počet sekúnd: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="4197700912384709145">Počet sekúnd: <ph name="NUMBER_ZERO"/></translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382">Počet zvyšných dní: <ph name="NUMBER_FEW"/></translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopírovať do schránky</translation>
+<translation id="8371695176452482769">Začnite hovoriť</translation>
+<translation id="1167268268675672572">Presunúť na začiatok riadka a upraviť výber</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Nerušiť</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimalizovať</translation>
+<translation id="6394627529324717982">Čiarka</translation>
+<translation id="3036649622769666520">Otvoriť súbory</translation>
+<translation id="8328145009876646418">Ľavý okraj</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekundy</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb
new file mode 100644
index 00000000000..7a04caf3728
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_sl.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mapa <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798">Pred <ph name="NUMBER_MANY"/> h</translation>
+<translation id="6310545596129886942">še <ph name="NUMBER_FEW"/> sek</translation>
+<translation id="9213479837033539041">še <ph name="NUMBER_MANY"/> sekund</translation>
+<translation id="1209866192426315618">še <ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="1801827354178857021">Obdobje</translation>
+<translation id="1190609913194133056">Središče za obvestila</translation>
+<translation id="7470933019269157899">še <ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="5613020302032141669">Puščica levo</translation>
+<translation id="4971687151119236543">Prejšnja skladba</translation>
+<translation id="8602707065186045623">Datoteka <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sek</translation>
+<translation id="7511635910912978956">še <ph name="NUMBER_FEW"/> h</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Prekliči</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Puščica gor</translation>
+<translation id="3969863827134279083">Premik gor</translation>
+<translation id="7062130397825382308">Še <ph name="NUMBER_ONE"/> sekundo</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> h</translation>
+<translation id="3990502903496589789">Desni rob</translation>
+<translation id="9038489124413477075">Neimenovana mapa</translation>
+<translation id="1940483897317142625">Brisanje do konca vrstice</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="3520476450377425184">še <ph name="NUMBER_MANY"/> dni</translation>
+<translation id="932327136139879170">Domov</translation>
+<translation id="5600907569873192868">še <ph name="NUMBER_MANY"/> minut</translation>
+<translation id="8666066831007952346">še <ph name="NUMBER_TWO"/> dni</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">Izrež&amp;i</translation>
+<translation id="2560788951337264832">še <ph name="NUMBER_ZERO"/> min</translation>
+<translation id="688711909580084195">Spletna stran brez naslova</translation>
+<translation id="3353284378027041011">Pred <ph name="NUMBER_FEW"/> dnevi</translation>
+<translation id="5076340679995252485">&amp;Prilepi</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Premik besede desno</translation>
+<translation id="364720409959344976">Izberite mapo, ki jo želite prenesti</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Pred <ph name="NUMBER_TWO"/> min</translation>
+<translation id="3234408098842461169">Puščica dol</translation>
+<translation id="3087734570205094154">Na dno</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">še <ph name="NUMBER_ONE"/> min</translation>
+<translation id="1860796786778352021">Zapri obvestilo</translation>
+<translation id="6364916375976753737">Pomik levo</translation>
+<translation id="2629089419211541119">Pred <ph name="NUMBER_ONE"/> h</translation>
+<translation id="4218160142017529598">Brisanje nazaj</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="6982279413068714821">Pred <ph name="NUMBER_DEFAULT"/> min</translation>
+<translation id="6945221475159498467">Izberi</translation>
+<translation id="6620110761915583480">Shrani datoteko</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Brisanje do začetka vrstice</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">še <ph name="NUMBER_ONE"/> min</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">Stran dol</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
+<translation id="7163503212501929773">še <ph name="NUMBER_MANY"/> ur</translation>
+<translation id="5329858601952122676">&amp;Izbriši</translation>
+<translation id="6556866813142980365">Uveljavi</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543">Pred <ph name="NUMBER_MANY"/> s</translation>
+<translation id="7781829728241885113">Včeraj</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuti</translation>
+<translation id="50960180632766478">še <ph name="NUMBER_FEW"/> min</translation>
+<translation id="5517291721709019259">Še <ph name="NUMBER_FEW"/> sekunde</translation>
+<translation id="6903282483217634857">Premik desno</translation>
+<translation id="6659594942844771486">Tabulator</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Pred <ph name="NUMBER_DEFAULT"/> dnevi</translation>
+<translation id="8428213095426709021">Nastavitve</translation>
+<translation id="2497284189126895209">Vse datoteke</translation>
+<translation id="7487278341251176613">še <ph name="NUMBER_TWO"/> min</translation>
+<translation id="5110450810124758964">Pred <ph name="NUMBER_ONE"/> dnevom</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sek</translation>
+<translation id="4320177379694898372">Ni internetne povezave</translation>
+<translation id="7814458197256864873">&amp;Kopiraj</translation>
+<translation id="3889424535448813030">Puščica desno</translation>
+<translation id="4229495110203539533">Pred <ph name="NUMBER_ONE"/> s</translation>
+<translation id="2544782972264605588">še <ph name="NUMBER_DEFAULT"/> sek</translation>
+<translation id="6829324100069873704">Nazaj na obvestila</translation>
+<translation id="6528179044667508675">Ne moti</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> min</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Omogočanje obvestil teh aplikacij:</translation>
+<translation id="2479520428668657293">Premik desno in sprememba izbire</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ur</translation>
+<translation id="1398853756734560583">Povečaj</translation>
+<translation id="4250229828105606438">Posnetek zaslona</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> uri</translation>
+<translation id="5260878308685146029">še <ph name="NUMBER_TWO"/> min</translation>
+<translation id="2557207087669398617">Premik na začetek vrstice</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Izberi &amp;vse</translation>
+<translation id="2168039046890040389">Stran gor</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dni</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">Premik besede desno in sprememba izbire</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minuta</translation>
+<translation id="8448317557906454022">Pred <ph name="NUMBER_ZERO"/> s</translation>
+<translation id="4927753642311223124">Tu ni ničesar, pomaknite se naprej.</translation>
+<translation id="2482878487686419369">Obvestila</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Pomik do sem</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Premik dol</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ur</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Ustavitev/začasna ustavitev</translation>
+<translation id="2148716181193084225">Danes</translation>
+<translation id="7960078400008666149">Ne moti eno uro</translation>
+<translation id="4373894838514502496">Pred <ph name="NUMBER_FEW"/> min</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dni</translation>
+<translation id="2190355936436201913">(prazno)</translation>
+<translation id="1164369517022005061">še <ph name="NUMBER_DEFAULT"/> h</translation>
+<translation id="152482086482215392">še <ph name="NUMBER_ONE"/> sek</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Pomik desno</translation>
+<translation id="7414887922320653780">še <ph name="NUMBER_ONE"/> ura</translation>
+<translation id="1413622004203049571">Izklop obvestil za <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Na vrh</translation>
+<translation id="2538759511191347839">Premik na konec vrstice in sprememba izbire</translation>
+<translation id="928465423150706909">Premik na konec vrstice</translation>
+<translation id="8331626408530291785">Pomik gor</translation>
+<translation id="7907591526440419938">Odpri datoteko</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Odpri mapo</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Pred <ph name="NUMBER_DEFAULT"/> h</translation>
+<translation id="815598010540052116">Pomik dol</translation>
+<translation id="6808150112686056157">Ustavitev</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Obnovi</translation>
+<translation id="5349525451964472598">Premik levo in sprememba izbire</translation>
+<translation id="1781701194097416995">Premik besede levo</translation>
+<translation id="1243314992276662751">Prenesi</translation>
+<translation id="50030952220075532">še <ph name="NUMBER_ONE"/> dan</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Premik besede levo in sprememba izbire</translation>
+<translation id="945522503751344254">Pošlji povratne informacije</translation>
+<translation id="9170848237812810038">&amp;Razveljavi</translation>
+<translation id="1285266685456062655">Pred <ph name="NUMBER_FEW"/> h</translation>
+<translation id="6918245111648057970">Za vsakega uporabnika dovoli obvestila naslednjih storitev:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekunda</translation>
+<translation id="1270251962578273213">Še <ph name="NUMBER_TWO"/> sekundi</translation>
+<translation id="3994835489895548312">še <ph name="NUMBER_MANY"/> min</translation>
+<translation id="6358975074282722691">Pred <ph name="NUMBER_TWO"/> s</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Nastavitve ...</translation>
+<translation id="6845383723252244143">Izberite mapo</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunde</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sek</translation>
+<translation id="5583640892426849032">Vračalka</translation>
+<translation id="5263972071113911534">Pred <ph name="NUMBER_MANY"/> dnevi</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dni</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> h</translation>
+<translation id="2679312662830811292">Pred <ph name="NUMBER_ONE"/> min</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dan</translation>
+<translation id="2704295676501803339">Premik levo</translation>
+<translation id="9098468523912235228">Pred <ph name="NUMBER_DEFAULT"/> s</translation>
+<translation id="494645311413743213">še <ph name="NUMBER_TWO"/> sek</translation>
+<translation id="566737009157135450">Brisanje besede nazaj</translation>
+<translation id="436869212180315161">Pritisnite</translation>
+<translation id="4860787810836767172">Pred <ph name="NUMBER_FEW"/> s</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">še <ph name="NUMBER_FEW"/> min</translation>
+<translation id="6040143037577758943">Zapri</translation>
+<translation id="1101671447232096497">Pred <ph name="NUMBER_MANY"/> min</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Pomoč</translation>
+<translation id="2405367043325750948">Brisanje naprej</translation>
+<translation id="6699343763173986273">Naslednja skladba</translation>
+<translation id="5445120697129764393">Še <ph name="NUMBER_DEFAULT"/> sekund</translation>
+<translation id="8226233771743600312">Ne moti en dan</translation>
+<translation id="4252565523989510616">Brisanje besede naprej</translation>
+<translation id="7457942297256758195">Izbriši vse</translation>
+<translation id="822618367988303761">Pred <ph name="NUMBER_TWO"/> dnevoma</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> min</translation>
+<translation id="1963692530539281474">še <ph name="NUMBER_DEFAULT"/> dni</translation>
+<translation id="6786750046913594791">Zapri mapo</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minute</translation>
+<translation id="5906719743126878045">še <ph name="NUMBER_TWO"/> uri</translation>
+<translation id="8959208747503200525">Pred <ph name="NUMBER_TWO"/> h</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sek</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekund</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382">še <ph name="NUMBER_FEW"/> dni</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Kopiraj v odložišče</translation>
+<translation id="8371695176452482769">Začnite govoriti</translation>
+<translation id="1167268268675672572">Premik na začetek vrstice in sprememba izbire</translation>
+<translation id="6965382102122355670">V redu</translation>
+<translation id="7850320739366109486">Ne moti</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Pomanjšaj</translation>
+<translation id="6394627529324717982">Vejica</translation>
+<translation id="3036649622769666520">Odpri datoteke</translation>
+<translation id="8328145009876646418">Levi rob</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekundi</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb
new file mode 100644
index 00000000000..a3f8e1a1114
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_sr.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Директоријум <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942">Преостало <ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="9213479837033539041">Преостало <ph name="NUMBER_MANY"/> сек.</translation>
+<translation id="1209866192426315618">Преостало <ph name="NUMBER_DEFAULT"/> мин.</translation>
+<translation id="1801827354178857021">Тачка</translation>
+<translation id="1190609913194133056">Центар за обавештења</translation>
+<translation id="7470933019269157899">Преостало је <ph name="NUMBER_DEFAULT"/> минута</translation>
+<translation id="5613020302032141669">Стрелица налево</translation>
+<translation id="4971687151119236543">Претходна песма медија</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> датотека (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> сек.</translation>
+<translation id="7511635910912978956">Преостало сати: <ph name="NUMBER_FEW"/></translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Откажи</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Стрелица нагоре</translation>
+<translation id="3969863827134279083">Помери нагоре</translation>
+<translation id="7062130397825382308">Још <ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928">Сати: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3990502903496589789">Десна ивица</translation>
+<translation id="9038489124413477075">Неименовани директоријум</translation>
+<translation id="1940483897317142625">Избриши до краја реда</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> мин.</translation>
+<translation id="3520476450377425184">Преостало <ph name="NUMBER_MANY"/> дана</translation>
+<translation id="932327136139879170">Почетна</translation>
+<translation id="5600907569873192868">Преостало <ph name="NUMBER_MANY"/> мин.</translation>
+<translation id="8666066831007952346">Преостало <ph name="NUMBER_TWO"/> дана</translation>
+<translation id="6390842777729054533">Преостало <ph name="NUMBER_ZERO"/> сек.</translation>
+<translation id="3909791450649380159">Ис&amp;еци</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Веб-страница без наслова</translation>
+<translation id="3353284378027041011">Пре <ph name="NUMBER_FEW"/> дана</translation>
+<translation id="5076340679995252485">&amp;Налепи</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Помери удесно за реч</translation>
+<translation id="364720409959344976">Избор директоријума за отпремање</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">Пре <ph name="NUMBER_TWO"/> минута</translation>
+<translation id="3234408098842461169">Стрелица надоле</translation>
+<translation id="3087734570205094154">Дно</translation>
+<translation id="8828991073132329143">Још <ph name="NUMBER_MANY"/> секунди</translation>
+<translation id="5935630983280450497">Преостао <ph name="NUMBER_ONE"/> мин.</translation>
+<translation id="1860796786778352021">Затвори обавештење</translation>
+<translation id="6364916375976753737">Помери налево</translation>
+<translation id="2629089419211541119">Пре <ph name="NUMBER_ONE"/> сат</translation>
+<translation id="4218160142017529598">Избриши уназад</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> мин</translation>
+<translation id="6982279413068714821">Пре <ph name="NUMBER_DEFAULT"/> минута</translation>
+<translation id="6945221475159498467">Изабери</translation>
+<translation id="6620110761915583480">Чување датотеке</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> секунди</translation>
+<translation id="8924469368910458384">Избриши до почетка реда</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Преостао је <ph name="NUMBER_ONE"/> минут</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> мин.</translation>
+<translation id="8210608804940886430">Страница надоле</translation>
+<translation id="1572103024875503863">Дана: <ph name="NUMBER_MANY"/></translation>
+<translation id="7163503212501929773">Преостало сати: <ph name="NUMBER_MANY"/></translation>
+<translation id="5329858601952122676">&amp;Избриши</translation>
+<translation id="6556866813142980365">Понови</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> сек.</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> минута</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Јуче</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> минута</translation>
+<translation id="50960180632766478">Преостало <ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="5517291721709019259">Још <ph name="NUMBER_FEW"/> секунде</translation>
+<translation id="6903282483217634857">Помери удесно</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">Пре <ph name="NUMBER_DEFAULT"/> дана</translation>
+<translation id="8428213095426709021">Подешавања</translation>
+<translation id="2497284189126895209">Све датотеке</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964">Пре <ph name="NUMBER_ONE"/> дан</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="4320177379694898372">Нема интернет везе</translation>
+<translation id="7814458197256864873">&amp;Копирај</translation>
+<translation id="3889424535448813030">Стрелица надесно</translation>
+<translation id="4229495110203539533">Пре <ph name="NUMBER_ONE"/> секунду</translation>
+<translation id="2544782972264605588">Преостало <ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="6829324100069873704">Вратите се на обавештења</translation>
+<translation id="6528179044667508675">Не узнемиравај</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> сек</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> мин.</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Дозволи обавештења из следећих извора:</translation>
+<translation id="2479520428668657293">Помери удесно и измени избор</translation>
+<translation id="8112886015144590373">Сати: <ph name="NUMBER_FEW"/></translation>
+<translation id="1398853756734560583">Увећај</translation>
+<translation id="4250229828105606438">Снимак екрана</translation>
+<translation id="6690744523875189208">Сати: <ph name="NUMBER_TWO"/></translation>
+<translation id="5260878308685146029">Преостало <ph name="NUMBER_TWO"/> мин.</translation>
+<translation id="2557207087669398617">Помери на почетак реда</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Изабери &amp;све</translation>
+<translation id="2168039046890040389">Страница нагоре</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581">Дана: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> мин.</translation>
+<translation id="6122334925474904337">Помери удесно за реч и измени избор</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> минут</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Нема шта да се види овде. Наставите даље.</translation>
+<translation id="2482878487686419369">Обавештења</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Помери се овде</translation>
+<translation id="4552416320897244156">Page Down</translation>
+<translation id="3066573403916685335">Помери надоле</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401">Сати: <ph name="NUMBER_MANY"/></translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Пуштање/паузирање медија</translation>
+<translation id="2148716181193084225">Данас</translation>
+<translation id="7960078400008666149">Не узнемиравај у периоду од сат времена</translation>
+<translation id="4373894838514502496">Пре <ph name="NUMBER_FEW"/> минута</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> дана</translation>
+<translation id="2190355936436201913">(празно)</translation>
+<translation id="1164369517022005061">Преостало сати: <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="152482086482215392">Преостала <ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="8447116497070723931">Page Up</translation>
+<translation id="4588090240171750605">Помери надесно</translation>
+<translation id="7414887922320653780">Преостао <ph name="NUMBER_ONE"/> сат</translation>
+<translation id="1413622004203049571">Онемогући обавештења од <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Врх</translation>
+<translation id="2538759511191347839">Помери до краја реда и измени избор</translation>
+<translation id="928465423150706909">Помери до краја реда</translation>
+<translation id="8331626408530291785">Помери нагоре</translation>
+<translation id="7907591526440419938">Отварање датотеке</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Отворите директоријум</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Пре <ph name="NUMBER_DEFAULT"/> сата</translation>
+<translation id="815598010540052116">Помери надоле</translation>
+<translation id="6808150112686056157">Заустављање медија</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Поново отвори</translation>
+<translation id="5349525451964472598">Помери улево и измени избор</translation>
+<translation id="1781701194097416995">Помери улево за реч</translation>
+<translation id="1243314992276662751">Отпреми</translation>
+<translation id="50030952220075532">Преостао <ph name="NUMBER_ONE"/> дан</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Помери улево за реч и измени избор</translation>
+<translation id="945522503751344254">Пошаљи повратне информације</translation>
+<translation id="9170848237812810038">&amp;Опозови</translation>
+<translation id="1285266685456062655">Пре <ph name="NUMBER_FEW"/> сата</translation>
+<translation id="6918245111648057970">Омогући обавештења следећих производа за сваког корисника:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1270251962578273213">Још <ph name="NUMBER_TWO"/> секунде</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691">Пре <ph name="NUMBER_TWO"/> секунде</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Подешавања...</translation>
+<translation id="6845383723252244143">Избор директоријума</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунде</translation>
+<translation id="5368780922436099921">Још <ph name="NUMBER_ZERO"/> секунди</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920">Дана: <ph name="NUMBER_FEW"/></translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> сат</translation>
+<translation id="2679312662830811292">Пре <ph name="NUMBER_ONE"/> минут</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> дан</translation>
+<translation id="2704295676501803339">Помери улево</translation>
+<translation id="9098468523912235228">Пре <ph name="NUMBER_DEFAULT"/> секунди</translation>
+<translation id="494645311413743213">Преостало <ph name="NUMBER_TWO"/> сек.</translation>
+<translation id="566737009157135450">Избриши реч уназад</translation>
+<translation id="436869212180315161">Притисните</translation>
+<translation id="4860787810836767172">Пре <ph name="NUMBER_FEW"/> секунде</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> минута</translation>
+<translation id="1858722859751911017">Преостала су <ph name="NUMBER_FEW"/> минута</translation>
+<translation id="6040143037577758943">Затвори</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Помоћ</translation>
+<translation id="2405367043325750948">Избриши унапред</translation>
+<translation id="6699343763173986273">Следећа песма медија</translation>
+<translation id="5445120697129764393">Још <ph name="NUMBER_DEFAULT"/> секунди</translation>
+<translation id="8226233771743600312">Не узнемиравај у периоду од једног дана</translation>
+<translation id="4252565523989510616">Избриши реч унапред</translation>
+<translation id="7457942297256758195">Обриши све</translation>
+<translation id="822618367988303761">Пре <ph name="NUMBER_TWO"/> дана</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> мин.</translation>
+<translation id="1963692530539281474">Преостало <ph name="NUMBER_DEFAULT"/> дана</translation>
+<translation id="6786750046913594791">Затворите директоријум</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> минута</translation>
+<translation id="5906719743126878045">Преостало сати: <ph name="NUMBER_TWO"/></translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> сек.</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> секунди</translation>
+<translation id="3759876923365568382">Преостало <ph name="NUMBER_FEW"/> дана</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Копирај у меморију</translation>
+<translation id="8371695176452482769">Почните да говорите</translation>
+<translation id="1167268268675672572">Помери на почетак реда и измени избор</translation>
+<translation id="6965382102122355670">Потврди</translation>
+<translation id="7850320739366109486">Не узнемиравај</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Смањи</translation>
+<translation id="6394627529324717982">Зарез</translation>
+<translation id="3036649622769666520">Отварање датотека</translation>
+<translation id="8328145009876646418">Лева ивица</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> секунде</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb
new file mode 100644
index 00000000000..98700bfcb8a
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_sv.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> sekunder kvar</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> sekunder kvar</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> minuter kvar</translation>
+<translation id="1801827354178857021">Period</translation>
+<translation id="1190609913194133056">Meddelandecenter</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> minuter kvar</translation>
+<translation id="5613020302032141669">Vänsterpil</translation>
+<translation id="4971687151119236543">Föregående spår</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>-fil (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> sekunder</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> timmar kvar</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Uppil</translation>
+<translation id="3969863827134279083">Flytta upp</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> sekund kvar</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sek</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> timmar</translation>
+<translation id="3990502903496589789">Högerkant</translation>
+<translation id="9038489124413477075">Namnlös mapp</translation>
+<translation id="1940483897317142625">Radera till slutet av raden</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> minuter</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> dagar kvar</translation>
+<translation id="932327136139879170">Startsida</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> minuter kvar</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> dagar kvar</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> sekunder kvar</translation>
+<translation id="3909791450649380159">&amp;Klipp ut</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minuter kvar</translation>
+<translation id="688711909580084195">Namnlös webbsida</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">K&amp;listra in</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Flytta ett ord åt höger</translation>
+<translation id="364720409959344976">Välj en mapp för överföring</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Nedpil</translation>
+<translation id="3087734570205094154">Nederst</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> sekunder kvar</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> minut kvar</translation>
+<translation id="1860796786778352021">Meddelande om stängning</translation>
+<translation id="6364916375976753737">Rulla åt vänster</translation>
+<translation id="2629089419211541119">För <ph name="NUMBER_ONE"/> timme sedan</translation>
+<translation id="4218160142017529598">Radera bakåt</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> minuter</translation>
+<translation id="6982279413068714821">För <ph name="NUMBER_DEFAULT"/> minuter sedan</translation>
+<translation id="6945221475159498467">Välj</translation>
+<translation id="6620110761915583480">Spara fil</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> sekunder</translation>
+<translation id="8924469368910458384">Radera till radens början</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> minut kvar</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dagar</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> timmar kvar</translation>
+<translation id="5329858601952122676">&amp;Ta bort</translation>
+<translation id="6556866813142980365">Upprepa</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> sekunder</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> kB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minuter</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Igår</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minuter</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> minuter kvar</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> sekunder kvar</translation>
+<translation id="6903282483217634857">Flytta åt höger</translation>
+<translation id="6659594942844771486">Flik</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523">För <ph name="NUMBER_DEFAULT"/> dagar sedan</translation>
+<translation id="8428213095426709021">Inställningar</translation>
+<translation id="2497284189126895209">Alla filer</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minuter kvar</translation>
+<translation id="5110450810124758964">För <ph name="NUMBER_ONE"/> dag sedan</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="4320177379694898372">Ingen internetanslutning</translation>
+<translation id="7814458197256864873">&amp;Kopiera</translation>
+<translation id="3889424535448813030">Högerpil</translation>
+<translation id="4229495110203539533">För <ph name="NUMBER_ONE"/> sekund sedan</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> sekunder kvar</translation>
+<translation id="6829324100069873704">Gå tillbaka till meddelanden</translation>
+<translation id="6528179044667508675">Stör inte</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> minuter</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Tillåt meddelanden från följande:</translation>
+<translation id="2479520428668657293">Flytta åt höger och ändra markeringen</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> timmar</translation>
+<translation id="1398853756734560583">Maximera</translation>
+<translation id="4250229828105606438">Skärmdump</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> timmar</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> minuter kvar</translation>
+<translation id="2557207087669398617">Flytta till radens början</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Välj &amp;alla</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> dagar</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> minuter</translation>
+<translation id="6122334925474904337">Flytta ett ord åt höger och ändra markeringen</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minut</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Här finns inget att se, fortsätt.</translation>
+<translation id="2482878487686419369">Aviseringar</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Rulla hit</translation>
+<translation id="4552416320897244156">Page Down</translation>
+<translation id="3066573403916685335">Flytta ner</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> timmar</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> kB/sek</translation>
+<translation id="8394908167088220973">Spela upp/Pausa</translation>
+<translation id="2148716181193084225">Idag</translation>
+<translation id="7960078400008666149">Stör inte i en timme</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> dagar</translation>
+<translation id="2190355936436201913">(tom)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> timmar kvar</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sekund kvar</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Rulla åt höger</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> timmar kvar</translation>
+<translation id="1413622004203049571">Inaktivera aviseringar från <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Överst</translation>
+<translation id="2538759511191347839">Flytta till slutet av raden och ändra markeringen</translation>
+<translation id="928465423150706909">Flytta till slutet av raden</translation>
+<translation id="8331626408530291785">Rulla uppåt</translation>
+<translation id="7907591526440419938">Öppna fil</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Öppna mappen</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">För <ph name="NUMBER_DEFAULT"/> timmar sedan</translation>
+<translation id="815598010540052116">Rulla nedåt</translation>
+<translation id="6808150112686056157">Stoppa</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Återställ</translation>
+<translation id="5349525451964472598">Flytta åt vänster och ändra markeringen</translation>
+<translation id="1781701194097416995">Flytta ett ord åt vänster</translation>
+<translation id="1243314992276662751">Överför</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> dag kvar</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Flytta ett ord åt vänster och ändra markeringen</translation>
+<translation id="945522503751344254">Skicka synpunkter</translation>
+<translation id="9170848237812810038">&amp;Ångra</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Tillåt meddelanden från följande personer för alla användare:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> sekund</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> sekunder kvar</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minuter kvar</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Inställningar...</translation>
+<translation id="6845383723252244143">Välj mapp</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> sekunder</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> sekunder kvar</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> sekunder</translation>
+<translation id="5583640892426849032">Backsteg</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> dagar</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> timme</translation>
+<translation id="2679312662830811292">För <ph name="NUMBER_ONE"/> minut sedan</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sek</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> dag</translation>
+<translation id="2704295676501803339">Flytta åt vänster</translation>
+<translation id="9098468523912235228">För <ph name="NUMBER_DEFAULT"/> sekunder sedan</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> sekunder kvar</translation>
+<translation id="566737009157135450">Radera ett ord bakåt</translation>
+<translation id="436869212180315161">Pressen</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sek</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minuter</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> minuter kvar</translation>
+<translation id="6040143037577758943">Stäng</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sek</translation>
+<translation id="7649070708921625228">Hjälp</translation>
+<translation id="2405367043325750948">Radera framåt</translation>
+<translation id="6699343763173986273">Nästa spår</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> sekunder kvar</translation>
+<translation id="8226233771743600312">Stör inte i en dag</translation>
+<translation id="4252565523989510616">Radera ett ord framåt</translation>
+<translation id="7457942297256758195">Ta bort alla</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> minuter</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> dagar kvar</translation>
+<translation id="6786750046913594791">Stäng mappen</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minuter</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> timmar kvar</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Skift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> sekunder</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> sekunder</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> sekunder</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> dagar kvar</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sek</translation>
+<translation id="2743387203779672305">Kopiera till Urklipp</translation>
+<translation id="8371695176452482769">Prata nu</translation>
+<translation id="1167268268675672572">Flytta till radens början och ändra markeringen</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Stör inte</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Minimera</translation>
+<translation id="6394627529324717982">Komma</translation>
+<translation id="3036649622769666520">Öppna filer</translation>
+<translation id="8328145009876646418">Vänsterkant</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> sekunder</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb
new file mode 100644
index 00000000000..6def4605a74
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_sw.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sw">
+<translation id="4820616160060340806">Amri+ <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Folda ya <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Futa</translation>
+<translation id="528468243742722775">Mwisho</translation>
+<translation id="5341849548509163798">Saa <ph name="NUMBER_MANY"/> zilizopita</translation>
+<translation id="6310545596129886942">zimesalia sekunde <ph name="NUMBER_FEW"/></translation>
+<translation id="9213479837033539041">zimesalia sekunde <ph name="NUMBER_MANY"/></translation>
+<translation id="1209866192426315618">zimesalia dakika <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="1801827354178857021">Muda</translation>
+<translation id="1190609913194133056">Kituo cha Arifa</translation>
+<translation id="7470933019269157899">Zimesalia dakika <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="5613020302032141669">Mshale Kushoto</translation>
+<translation id="4971687151119236543">Wimbo wa Awali wa Media</translation>
+<translation id="8602707065186045623">Faili ya <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918">dakika <ph name="NUMBER_ZERO"/> zilizopita</translation>
+<translation id="7121570032414343252">zimesalia sekunde <ph name="NUMBER_TWO"/></translation>
+<translation id="7511635910912978956">zimesalia saa <ph name="NUMBER_FEW"/></translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Ghairi</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658">B <ph name="QUANTITY"/></translation>
+<translation id="3660179305079774227">Mshale Juu</translation>
+<translation id="3969863827134279083">Sogeza Juu</translation>
+<translation id="7062130397825382308">Imesalia sekunde <ph name="NUMBER_ONE"/></translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928">saa <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3990502903496589789">Ncha ya Kulia</translation>
+<translation id="9038489124413477075">Folda isiyo na jina</translation>
+<translation id="1940483897317142625">Futa Hadi Mwisho Wa Mstari</translation>
+<translation id="8507996248087185956">dakika <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="3520476450377425184">zimesalia siku <ph name="NUMBER_MANY"/></translation>
+<translation id="932327136139879170">Mwanzo</translation>
+<translation id="5600907569873192868">zimesalia dakika <ph name="NUMBER_MANY"/></translation>
+<translation id="8666066831007952346">zimesalia siku <ph name="NUMBER_TWO"/></translation>
+<translation id="6390842777729054533">zimesalia sekunde <ph name="NUMBER_ZERO"/></translation>
+<translation id="3909791450649380159">&amp;Kata</translation>
+<translation id="2560788951337264832">Zimesalia dakika <ph name="NUMBER_ZERO"/></translation>
+<translation id="688711909580084195">Ukurasa wa Wavuti usio na Kichwa</translation>
+<translation id="3353284378027041011">siku <ph name="NUMBER_FEW"/> zilizopita</translation>
+<translation id="5076340679995252485">&amp;Bandika</translation>
+<translation id="7460907917090416791">TB <ph name="QUANTITY"/></translation>
+<translation id="7139614227326422685">Sogeza Upande Wa Kulia Wa Neno</translation>
+<translation id="364720409959344976">Chagua Folda ya Kupakia</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016">dakika <ph name="NUMBER_TWO"/> zilizopita</translation>
+<translation id="3234408098842461169">Mshale Chini</translation>
+<translation id="3087734570205094154">Chini</translation>
+<translation id="8828991073132329143">Zimesalia sekunde <ph name="NUMBER_MANY"/></translation>
+<translation id="5935630983280450497">imesalia dakika <ph name="NUMBER_ONE"/></translation>
+<translation id="1860796786778352021">Funga arifa</translation>
+<translation id="6364916375976753737">Sogeza Kushoto</translation>
+<translation id="2629089419211541119">saa <ph name="NUMBER_ONE"/> lililopita</translation>
+<translation id="4218160142017529598">Futa Kuelekea Nyuma</translation>
+<translation id="2994641463185352298">Dakika <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6982279413068714821">dakika <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
+<translation id="6945221475159498467">Chagua</translation>
+<translation id="6620110761915583480">Hifadhi Faili</translation>
+<translation id="4349181486102621992">Sekunde <ph name="NUMBER_ZERO"/></translation>
+<translation id="8924469368910458384">Futa Hadi Mwanzo Wa Mstari</translation>
+<translation id="6719684875142564568">saa <ph name="NUMBER_ZERO"/></translation>
+<translation id="7836361698254323868">Imesalia dakika <ph name="NUMBER_ONE"/></translation>
+<translation id="2953767478223974804">dakika <ph name="NUMBER_ONE"/></translation>
+<translation id="8210608804940886430">Ukurasa mmoja chini</translation>
+<translation id="1572103024875503863">siku <ph name="NUMBER_MANY"/></translation>
+<translation id="7163503212501929773">zimesalia saa <ph name="NUMBER_MANY"/></translation>
+<translation id="5329858601952122676">&amp;Futa</translation>
+<translation id="6556866813142980365">Rudia</translation>
+<translation id="8088823334188264070">sekunde <ph name="NUMBER_MANY"/></translation>
+<translation id="8901569739625249689">KB <ph name="QUANTITY"/></translation>
+<translation id="7712011264267466734">Dakika <ph name="NUMBER_MANY"/></translation>
+<translation id="7275974018215686543">sekunde <ph name="NUMBER_MANY"/> zilizopita</translation>
+<translation id="7781829728241885113">Jana</translation>
+<translation id="3424538384153559412">Dakika <ph name="NUMBER_TWO"/></translation>
+<translation id="50960180632766478">zimesalia dakika <ph name="NUMBER_FEW"/></translation>
+<translation id="5517291721709019259">Zimesalia sekunde <ph name="NUMBER_FEW"/></translation>
+<translation id="6903282483217634857">Sogeza Kulia</translation>
+<translation id="6659594942844771486">Kichupo</translation>
+<translation id="3049748772180311791">MB <ph name="QUANTITY"/></translation>
+<translation id="4988273303304146523">siku <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
+<translation id="8428213095426709021">Mipangilio</translation>
+<translation id="2497284189126895209">Faili zote</translation>
+<translation id="7487278341251176613">Zimesalia dakika <ph name="NUMBER_TWO"/></translation>
+<translation id="5110450810124758964">siku <ph name="NUMBER_ONE"/> iliyopita</translation>
+<translation id="2820806154655529776">sekunde <ph name="NUMBER_ONE"/></translation>
+<translation id="4320177379694898372">Hakuna muunganisho wa intaneti</translation>
+<translation id="7814458197256864873">&amp;Nakili</translation>
+<translation id="3889424535448813030">Mshale Kulia</translation>
+<translation id="4229495110203539533">sekunde <ph name="NUMBER_ONE"/> iliyopita</translation>
+<translation id="2544782972264605588">zimesalia sekunde <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6829324100069873704">Rudi kwenye arifa</translation>
+<translation id="6528179044667508675">Usinisumbue</translation>
+<translation id="5066177358602611309">Sekunde <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="290555789621781773">dakika <ph name="NUMBER_TWO"/></translation>
+<translation id="5149131957118398098">Zimesalia saa <ph name="NUMBER_ZERO"/></translation>
+<translation id="7135556860107312402">Ruhusu arifa kutoka kwa:</translation>
+<translation id="2479520428668657293">Sogeza Kulia Na Ubadilisha Uteuzi</translation>
+<translation id="8112886015144590373">saa <ph name="NUMBER_FEW"/></translation>
+<translation id="1398853756734560583">Tanua</translation>
+<translation id="4250229828105606438">Picha ya skrini</translation>
+<translation id="6690744523875189208">saa <ph name="NUMBER_TWO"/></translation>
+<translation id="5260878308685146029">zimesalia dakika <ph name="NUMBER_TWO"/></translation>
+<translation id="2557207087669398617">Sogeza Hadi Mwanzo Wa Mstari</translation>
+<translation id="3757388668994797779">GB <ph name="QUANTITY"/></translation>
+<translation id="1901303067676059328">Chagua &amp;yote</translation>
+<translation id="2168039046890040389">Ukurasa mmoja juu</translation>
+<translation id="7363290921156020669">dakika <ph name="NUMBER_ZERO"/></translation>
+<translation id="9107059250669762581">siku <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6463061331681402734">dakika <ph name="NUMBER_MANY"/></translation>
+<translation id="6122334925474904337">Sogeza Upande Wa Kulia Wa Neno Na Ubadilishe Uteuzi</translation>
+<translation id="7634624804467787019">Dakika <ph name="NUMBER_ONE"/></translation>
+<translation id="8448317557906454022">sekunde <ph name="NUMBER_ZERO"/> zilizopita</translation>
+<translation id="4927753642311223124">Hakuna cha kuangalia hapa, endelea.</translation>
+<translation id="2482878487686419369">Arifa</translation>
+<translation id="6357135709975569075">siku <ph name="NUMBER_ZERO"/></translation>
+<translation id="3183922693828471536">Sogeza Hadi Hapa</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Sogeza Chini</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401">saa <ph name="NUMBER_MANY"/></translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Cheza Media/Sitisha</translation>
+<translation id="2148716181193084225">Leo</translation>
+<translation id="7960078400008666149">Usinisumbue kwa saa moja</translation>
+<translation id="4373894838514502496">dakika <ph name="NUMBER_FEW"/> zilizopita</translation>
+<translation id="4115153316875436289">siku <ph name="NUMBER_TWO"/></translation>
+<translation id="2190355936436201913">(tupu)</translation>
+<translation id="1164369517022005061">Zimesalia saa <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="152482086482215392">imesalia sekunde <ph name="NUMBER_ONE"/></translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Sogeza Kulia</translation>
+<translation id="7414887922320653780">limesalia saa <ph name="NUMBER_ONE"/></translation>
+<translation id="1413622004203049571">Zima arifa kutoka <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Ya Juu</translation>
+<translation id="2538759511191347839">Sogeza Hadi Mwisho Wa Mstari Na Ubadilishe Uteuzi</translation>
+<translation id="928465423150706909">Sogeza Mwisho Wa Mstari</translation>
+<translation id="8331626408530291785">Sogeza Juu</translation>
+<translation id="7907591526440419938">Fungua Faili</translation>
+<translation id="2864069933652346933">zimesalia siku <ph name="NUMBER_ZERO"/></translation>
+<translation id="2803313416453193357">Fungua folda</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045">Saa <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
+<translation id="815598010540052116">Sogeza Chini</translation>
+<translation id="6808150112686056157">Simamisha Media</translation>
+<translation id="1308727876662951186">zimesalia dakika <ph name="NUMBER_ZERO"/></translation>
+<translation id="3157931365184549694">Rejesha</translation>
+<translation id="5349525451964472598">Sogeza Kushoto Na Ubadilishe Uteuzi</translation>
+<translation id="1781701194097416995">Sogeza Upande Wa Kulia Wa Neno</translation>
+<translation id="1243314992276662751">Pakia</translation>
+<translation id="50030952220075532">imesalia siku <ph name="NUMBER_ONE"/></translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Sogeza Upande Wa Kulia Wa Neno Na Ubadilishe Uteuzi</translation>
+<translation id="945522503751344254">Tuma maoni</translation>
+<translation id="9170848237812810038">&amp;Tendua</translation>
+<translation id="1285266685456062655">Saa <ph name="NUMBER_FEW"/> zilizopita</translation>
+<translation id="6918245111648057970">Ruhusu arifa kutoka kwa wafuatao kwa kila mtumiaji:</translation>
+<translation id="5489830104927132166">Sekunde <ph name="NUMBER_ONE"/></translation>
+<translation id="1270251962578273213">Zimesalia sekunde <ph name="NUMBER_TWO"/></translation>
+<translation id="3994835489895548312">Zimesalia dakika <ph name="NUMBER_MANY"/></translation>
+<translation id="6358975074282722691">sekunde <ph name="NUMBER_TWO"/> zilizopita</translation>
+<translation id="520299402983819650">PB <ph name="QUANTITY"/></translation>
+<translation id="2983818520079887040">Mipangilio...</translation>
+<translation id="6845383723252244143">Chagua Folda</translation>
+<translation id="7600770490873519066">Sekunde <ph name="NUMBER_FEW"/></translation>
+<translation id="5368780922436099921">Zimesalia saa <ph name="NUMBER_ZERO"/></translation>
+<translation id="1095623615273566396">sekunde <ph name="NUMBER_FEW"/></translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534">siku <ph name="NUMBER_MANY"/> zilizopita</translation>
+<translation id="8355915647418390920">siku <ph name="NUMBER_FEW"/></translation>
+<translation id="5116333507878097773">saa <ph name="NUMBER_ONE"/></translation>
+<translation id="2679312662830811292">dakika <ph name="NUMBER_ONE"/> iliyopita</translation>
+<translation id="8788572795284305350">Saa <ph name="NUMBER_ZERO"/> zilizopita</translation>
+<translation id="3740362395218339114">GB/s <ph name="QUANTITY"/></translation>
+<translation id="6644971472240498405">siku <ph name="NUMBER_ONE"/></translation>
+<translation id="2704295676501803339">Sogeza Kushoto</translation>
+<translation id="9098468523912235228">sekunde <ph name="NUMBER_DEFAULT"/> zilizopita</translation>
+<translation id="494645311413743213">zimesalia sekunde <ph name="NUMBER_TWO"/></translation>
+<translation id="566737009157135450">Futa Neno Kwa Kuelekea Nyuma</translation>
+<translation id="436869212180315161">Bofya</translation>
+<translation id="4860787810836767172">sekunde <ph name="NUMBER_FEW"/> zilizopita</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074">Dakika <ph name="NUMBER_ZERO"/></translation>
+<translation id="1858722859751911017">Zimesalia dakika <ph name="NUMBER_FEW"/></translation>
+<translation id="6040143037577758943">Funga</translation>
+<translation id="1101671447232096497">dakika <ph name="NUMBER_MANY"/> zilizopita</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">Usaidizi</translation>
+<translation id="2405367043325750948">Futa Ukielekea Upande Wa Mbele</translation>
+<translation id="6699343763173986273">Wimbo Unaofuata kwenye Media</translation>
+<translation id="5445120697129764393">Zimesalia sekunde <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="8226233771743600312">Usinisumbue kwa siku moja</translation>
+<translation id="4252565523989510616">Futa Neno Ukielekea Upande Wa Mbele</translation>
+<translation id="7457942297256758195">Futa Zote</translation>
+<translation id="822618367988303761">siku <ph name="NUMBER_TWO"/> zilizopita</translation>
+<translation id="4745438305783437565">dakika <ph name="NUMBER_FEW"/></translation>
+<translation id="1963692530539281474">Zimesalia siku <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="6786750046913594791">Funga Folda</translation>
+<translation id="7509440305564869263">Dakika <ph name="NUMBER_FEW"/></translation>
+<translation id="5906719743126878045">zimesalia saa <ph name="NUMBER_TWO"/></translation>
+<translation id="8959208747503200525">Saa <ph name="NUMBER_TWO"/> zilizopita</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940">sekunde <ph name="NUMBER_DEFAULT"/></translation>
+<translation id="4197700912384709145">sekunde <ph name="NUMBER_ZERO"/></translation>
+<translation id="27199337101878275">Sekunde <ph name="NUMBER_MANY"/></translation>
+<translation id="3759876923365568382">zimesalia siku <ph name="NUMBER_FEW"/></translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">Nakili kwenye ubao wa kunakili</translation>
+<translation id="8371695176452482769">Ongea sasa</translation>
+<translation id="1167268268675672572">Sogeza Hadi Mwanzo Wa Mstari Na Ubadilishe Uteuzi</translation>
+<translation id="6965382102122355670">Sawa</translation>
+<translation id="7850320739366109486">Usinisumbue</translation>
+<translation id="6978839998405419496">siku <ph name="NUMBER_ZERO"/> zilizopita</translation>
+<translation id="5941711191222866238">Punguza</translation>
+<translation id="6394627529324717982">Koma</translation>
+<translation id="3036649622769666520">Fungua Mafaili</translation>
+<translation id="8328145009876646418">Ncha ya Kushoto</translation>
+<translation id="7372005818821648611">Sekunde <ph name="NUMBER_TWO"/></translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb
new file mode 100644
index 00000000000..779a073193f
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_ta.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ta">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> கோப்புறை</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942">இன்னும் <ph name="NUMBER_FEW"/> வினாடிகள் உள்ளன</translation>
+<translation id="9213479837033539041">இன்னும் <ph name="NUMBER_MANY"/> நொடிகள் உள்ளன</translation>
+<translation id="1209866192426315618">இன்னும் <ph name="NUMBER_DEFAULT"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="1801827354178857021">காலம்</translation>
+<translation id="1190609913194133056">அறிவிப்பு மையம்</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="5613020302032141669">இடது அம்பு</translation>
+<translation id="4971687151119236543">ஊடகத்தின் முந்தைய டிராக்</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/>கோப்பு(.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> வினாடிகள்</translation>
+<translation id="7511635910912978956">இன்னும் <ph name="NUMBER_FEW"/> மணிநேரம் உள்ளது</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">ரத்து செய்</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> பை</translation>
+<translation id="3660179305079774227">மேல்நோக்கிய அம்பு</translation>
+<translation id="3969863827134279083">மேலே நகர்த்து</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> வினாடி உள்ளது</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> மெ.பை/வி</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> மணி நேரம்</translation>
+<translation id="3990502903496589789">வலது விளிம்பு</translation>
+<translation id="9038489124413477075">பெயரிடப்படாதக் கோப்புறை</translation>
+<translation id="1940483897317142625">வரியின் இறுதிவரை நீக்கு</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள்</translation>
+<translation id="3520476450377425184">இன்னும் <ph name="NUMBER_MANY"/> நாட்கள் உள்ளன</translation>
+<translation id="932327136139879170">முகப்பு</translation>
+<translation id="5600907569873192868">இன்னும் <ph name="NUMBER_MANY"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="8666066831007952346">இன்னும் <ph name="NUMBER_TWO"/> நாட்கள் உள்ளன</translation>
+<translation id="6390842777729054533">இன்னும் <ph name="NUMBER_ZERO"/> வினாடிகள் உள்ளன</translation>
+<translation id="3909791450649380159">வெட்&amp;டு</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="688711909580084195">தலைப்பிடாத வலைப்பக்கம்</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;ஒட்டு</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> டெ.பை</translation>
+<translation id="7139614227326422685">வார்த்தையின் வலதுபுறம் நகர்த்து</translation>
+<translation id="364720409959344976">பதிவேற்றுவதற்குக் கோப்புறையைத் தேர்ந்தெடு</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation>
+<translation id="3087734570205094154">கீழே</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> வினாடிகள் உள்ளன</translation>
+<translation id="5935630983280450497">இன்னும் <ph name="NUMBER_ONE"/> நிமிடம் உள்ளது</translation>
+<translation id="1860796786778352021">அறிவிப்பை மூடு</translation>
+<translation id="6364916375976753737">இடப்புறம் உருட்டு</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">பின்னோக்கி நீக்கு</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> நிமிடங்கள்</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">தேர்ந்தெடு</translation>
+<translation id="6620110761915583480">கோப்பைச் சேமி</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> வினாடிகள்</translation>
+<translation id="8924469368910458384">வரியின் துவக்கம்வரை நீக்கு</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> நிமிடம் உள்ளது</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> நிமிடம்</translation>
+<translation id="8210608804940886430">பக்கத்தின் கீழே</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> நாட்கள்</translation>
+<translation id="7163503212501929773">இன்னும் <ph name="NUMBER_MANY"/> மணிநேரம் உள்ளது</translation>
+<translation id="5329858601952122676">&amp;நீக்கு</translation>
+<translation id="6556866813142980365">மீண்டும் செய்</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> நொடிகள்</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> கி.பை.</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> நிமிடங்கள்</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">நேற்று</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> நிமிடங்கள்</translation>
+<translation id="50960180632766478">இன்னும் <ph name="NUMBER_FEW"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> வினாடிகள் உள்ளன</translation>
+<translation id="6903282483217634857">வலதுபுறமாக நகர்த்து</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> மெ.பை</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">அமைப்புகள்</translation>
+<translation id="2497284189126895209">அனைத்து கோப்புகளும்</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> நொடி</translation>
+<translation id="4320177379694898372">இணைய இணைப்பு இல்லை</translation>
+<translation id="7814458197256864873">&amp;நகலெடு</translation>
+<translation id="3889424535448813030">வலது அம்பு</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588">இன்னும் <ph name="NUMBER_DEFAULT"/> வினாடிகள் உள்ளன</translation>
+<translation id="6829324100069873704">அறிவிப்புகளுக்குச் செல்</translation>
+<translation id="6528179044667508675">தொந்தரவு செய்ய வேண்டாம்</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> வினாடிகள்</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> நிமிடங்கள்</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">பின்வருபவற்றிலிருந்து வரும் அறிவிப்புகளை அனுமதி:</translation>
+<translation id="2479520428668657293">வலதுபுறமாக நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> மணி நேரம்</translation>
+<translation id="1398853756734560583">பெரிதாக்கு</translation>
+<translation id="4250229828105606438">ஸ்கிரீன் ஷாட்</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> மணி நேரம்</translation>
+<translation id="5260878308685146029">இன்னும் <ph name="NUMBER_TWO"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="2557207087669398617">வரியின் துவக்கத்திற்கு நகர்த்து</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">அ&amp;னைத்தையும் தேர்ந்தெடு</translation>
+<translation id="2168039046890040389">பக்கத்தின் மேலே</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> நாட்கள்</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> நிமிடங்கள்</translation>
+<translation id="6122334925474904337">வார்த்தையின் வலதுபுறம் நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> நிமிடம்</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">பார்க்க இங்கு எதுவுமில்லை, தொடரவும்.</translation>
+<translation id="2482878487686419369">அறிவிக்கைகள்</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">இங்கே உருட்டு</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">கீழே நகர்த்து</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> மணிநேரம்</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> கி.பை./வி</translation>
+<translation id="8394908167088220973">ஊடகத்தை இயக்கு/இடைநிறுத்து</translation>
+<translation id="2148716181193084225">இன்று</translation>
+<translation id="7960078400008666149">ஒரு மணிநேரத்திற்குத் தொந்தரவு செய்ய வேண்டாம்</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> நாட்கள்</translation>
+<translation id="2190355936436201913">(காலி)</translation>
+<translation id="1164369517022005061">இன்னும் <ph name="NUMBER_DEFAULT"/> மணிநேரம் உள்ளது</translation>
+<translation id="152482086482215392">இன்னும் <ph name="NUMBER_ONE"/> நொடிகள் உள்ளன</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">வலப்புறம் உருட்டு</translation>
+<translation id="7414887922320653780">இன்னும் <ph name="NUMBER_ONE"/> மணிநேரம் உள்ளது</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> இடமிருந்து வரும் அறிவிப்புகளை முடக்கு</translation>
+<translation id="2666092431469916601">மேலே</translation>
+<translation id="2538759511191347839">வரியின் இறுதிக்கு நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="928465423150706909">வரியின் இறுதிக்கு நகர்த்து</translation>
+<translation id="8331626408530291785">மேலே உருட்டு</translation>
+<translation id="7907591526440419938">கோப்பைத் திற</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">கோப்புறையைத் திற</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">கீழே உருட்டு</translation>
+<translation id="6808150112686056157">ஊடகத்தை நிறுத்து</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">மீட்டமை</translation>
+<translation id="5349525451964472598">இடதுபுறமாக நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="1781701194097416995">வார்த்தையின் இடதுபுறம் நகர்த்து</translation>
+<translation id="1243314992276662751">பதிவேற்று</translation>
+<translation id="50030952220075532">இன்னும் <ph name="NUMBER_ONE"/> நாட்கள் உள்ளன</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">வார்த்தையின் இடதுபுறம் நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="945522503751344254">பின்னூட்டம் அனுப்புக</translation>
+<translation id="9170848237812810038">&amp;செயல்தவிர்</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">ஒவ்வொரு பயனருக்கும் பின்வருபவையிலிருந்து அறிவிப்புகளை அனுமதி:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> வினாடி</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> வினாடிகள் உள்ளன</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> பெ.பை</translation>
+<translation id="2983818520079887040">அமைப்புகள்...</translation>
+<translation id="6845383723252244143">கோப்புறையைத் தேர்ந்தெடு</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> வினாடிகள்</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> வினாடிகள் உள்ளன</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> நொடிகள்</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> நாட்கள்</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> மணி நேரம்</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> ஜி.பை/வி</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> நாள்</translation>
+<translation id="2704295676501803339">இடதுபுறமாக நகர்த்து</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> வினாடிகள் உள்ளன</translation>
+<translation id="566737009157135450">வார்த்தையைப் பின்னோக்கி நீக்கு</translation>
+<translation id="436869212180315161">அழுத்து</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> டெ.பை/வி</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> நிமிடங்கள்</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> நிமிடங்கள் உள்ளன</translation>
+<translation id="6040143037577758943">மூடு</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> பை/வி</translation>
+<translation id="7649070708921625228">உதவி</translation>
+<translation id="2405367043325750948">முன்புறமாக நீக்கு</translation>
+<translation id="6699343763173986273">ஊடகத்தின் அடுத்த டிராக்</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> வினாடிகள் உள்ளன</translation>
+<translation id="8226233771743600312">ஒரு நாள் தொந்தரவு செய்ய வேண்டாம்</translation>
+<translation id="4252565523989510616">வார்த்தையை முன்புறமாக நீக்கு</translation>
+<translation id="7457942297256758195">அனைத்தையும் அழி</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> நிமிடங்கள்</translation>
+<translation id="1963692530539281474">இன்னும் <ph name="NUMBER_DEFAULT"/> நாட்கள் உள்ளன</translation>
+<translation id="6786750046913594791">கோப்புறையை மூடு</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> நிமிடங்கள்</translation>
+<translation id="5906719743126878045">இன்னும் <ph name="NUMBER_TWO"/> மணிநேரம் உள்ளது</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> நொடிகள்</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> நொடிகள்</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> வினாடிகள்</translation>
+<translation id="3759876923365568382">இன்னும் <ph name="NUMBER_FEW"/> நாட்கள் உள்ளன</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> பெ.பை/வி</translation>
+<translation id="2743387203779672305">கிளிப்போர்டுக்கு நகலெடு</translation>
+<translation id="8371695176452482769">இப்போது பேசுக</translation>
+<translation id="1167268268675672572">வரியின் துவக்கத்திற்கு நகர்ந்து தேர்வை மாற்று</translation>
+<translation id="6965382102122355670">சரி</translation>
+<translation id="7850320739366109486">தொந்தரவு செய்ய வேண்டாம்</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">சிறிதாக்கு</translation>
+<translation id="6394627529324717982">கமா</translation>
+<translation id="3036649622769666520">கோப்புகளைத் திற</translation>
+<translation id="8328145009876646418">இடதுபுற முனை</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> வினாடிகள்</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb
new file mode 100644
index 00000000000..e39dde993dc
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_te.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="te">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">ఫోల్డర్ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">ముగింపు</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="1801827354178857021">వ్యవధి</translation>
+<translation id="1190609913194133056">నోటిఫికేషన్ కేంద్రం</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="5613020302032141669">ఎడమ బాణం</translation>
+<translation id="4971687151119236543">మీడియా మునుపటి ట్రాక్</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> ఫైల్ (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> సెకన్లు</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> గంటలు మిగిలి ఉన్నాయి</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">రద్దు చెయ్యి</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">ఎగువ బాణం</translation>
+<translation id="3969863827134279083">పైకి తరలించండి</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> సెకను మిగిలి ఉంది</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> గంటలు</translation>
+<translation id="3990502903496589789">కుడి సరిహద్దు</translation>
+<translation id="9038489124413477075">పేరులేని ఫోల్డర్</translation>
+<translation id="1940483897317142625">పంక్తి చివరికి తొలగించండి</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> నిమిషాలు</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> రోజులు మిగిలి ఉన్నాయి</translation>
+<translation id="932327136139879170">హోమ్</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> నిమిషాలు మిగిలాయి</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> రోజులు మిగిలి ఉన్నాయి</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
+<translation id="3909791450649380159">క&amp;త్తిరించు</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="688711909580084195">శీర్షికలేని వెబ్‌పేజీ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;అతికించు</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">పదం కుడివైపుకి తరలించండి</translation>
+<translation id="364720409959344976">అప్‌లోడ్ చేయడానికి ఫోల్డర్‌ని ఎంచుకోండి</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">క్రింది బాణం</translation>
+<translation id="3087734570205094154">దిగువ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> సెకన్ల సమయం మిగిలి ఉంది</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="1860796786778352021">నోటిఫికేషన్‌ను మూసివేయి</translation>
+<translation id="6364916375976753737">ఎడమకి స్క్రోల్ చేయి</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">వెనుకకు తొలగించండి</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> నిమిషాలు</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> mins ago</translation>
+<translation id="6945221475159498467">ఎంచుకోండి</translation>
+<translation id="6620110761915583480">ఫైల్‌ను సేవ్ చేయి</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> సెకన్లు</translation>
+<translation id="8924469368910458384">పంక్తి మొదటికి తొలగించండి</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> నిమిషం మిగిలి ఉంది</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> నిమిషం</translation>
+<translation id="8210608804940886430">పేజీ క్రిందికి</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> రోజులు</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> గంటలు మిగిలి ఉన్నాయి</translation>
+<translation id="5329858601952122676">&amp;తొలగించు</translation>
+<translation id="6556866813142980365">చర్య పునరావృతం</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> సెకన్లు</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> నిమిషాలు</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">నిన్న</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> నిమిషాలు</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> నిమిషాలు మిగిలిలాయి</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> సెకన్ల సమయం మిగిలి ఉంది</translation>
+<translation id="6903282483217634857">కుడివైపు తరలించండి</translation>
+<translation id="6659594942844771486">టాబ్</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> days ago</translation>
+<translation id="8428213095426709021">సెట్టింగ్‌లు</translation>
+<translation id="2497284189126895209">మొత్తం ఫైళ్లు</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> సెకను</translation>
+<translation id="4320177379694898372">ఇంటర్నెట్ కనెక్షన్ లేదు</translation>
+<translation id="7814458197256864873">&amp;కాపీ</translation>
+<translation id="3889424535448813030">కుడి బాణం</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> సెకన్లు మిగిలాయి</translation>
+<translation id="6829324100069873704">నోటిఫికేషన్‌లకు తిరిగి వెళ్లు</translation>
+<translation id="6528179044667508675">అంతరాయం కలిగించవద్దు</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> సెకన్లు</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> నిమిషాలు</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">వీటి నుండి నోటిఫికేషన్‌లను అనుమతించు:</translation>
+<translation id="2479520428668657293">కుడివైపు తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> గంటలు</translation>
+<translation id="1398853756734560583">గరిష్ఠీకరించు</translation>
+<translation id="4250229828105606438">స్క్రీన్‌షాట్</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> గంటలు</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> నిమిషాలు మిగిలాయి</translation>
+<translation id="2557207087669398617">పంక్తి మొదటికి తరలించండి</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">&amp;అన్నీ ఎంచుకోండి</translation>
+<translation id="2168039046890040389">పేజీ పైకి</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> రోజులు</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> నిమిషాలు</translation>
+<translation id="6122334925474904337">పదం కుడివైపుకి తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> నిమిషం</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">ఇక్కడ చూడటానికి ఏమీ లేదు, కొనసాగండి.</translation>
+<translation id="2482878487686419369">ప్రకటనలు</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">ఇక్కడ స్క్రోల్ చెయ్యండి</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">క్రిందికి తరలించండి</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> గంటలు</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/సె</translation>
+<translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation>
+<translation id="2148716181193084225">ఈ రోజు</translation>
+<translation id="7960078400008666149">ఒక గంటపాటు అంతరాయం కలిగించవద్దు</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> రోజులు</translation>
+<translation id="2190355936436201913">(ఖాళీ)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> గంటలు మిగిలాయి</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">కుడికి స్క్రోల్ చెయ్యి</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> గంటలు మిగిలా యి</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> నుండి వచ్చే నోటిఫికేషన్‌లను నిలిపివేయి</translation>
+<translation id="2666092431469916601">పైన</translation>
+<translation id="2538759511191347839">పంక్తి చివరికి తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="928465423150706909">పంక్తి చివరికి తరలించండి</translation>
+<translation id="8331626408530291785">పైకి స్క్రోల్ చెయ్యి</translation>
+<translation id="7907591526440419938">ఫైల్‌ను తెరువు</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">ఫోల్డర్‌ను తెరవండి</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> hours ago</translation>
+<translation id="815598010540052116">క్రిందికి స్క్రోల్ చేయి</translation>
+<translation id="6808150112686056157">మీడియా ఆపివేయి</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">పునరుద్ధరించు</translation>
+<translation id="5349525451964472598">ఎడమవైపు తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="1781701194097416995">పదం ఎడమవైపుకి తరలించండి</translation>
+<translation id="1243314992276662751">అప్‌లోడ్ చేయి</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> రోజులు మిగిలి ఉన్నాయి</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">పదం ఎడమవైపుకు తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="945522503751344254">అభిప్రాయాన్ని పంపండి</translation>
+<translation id="9170848237812810038">&amp;అన్డు</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">ప్రతి వినియోగదారు కోసం కింది వారి నుండి నోటిఫికేషన్‌లను అనుమతించు:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> సెకను</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> సెకన్ల సమయం మిగిలి ఉంది</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">సెట్టింగ్‌లు...</translation>
+<translation id="6845383723252244143">ఫోల్డర్‌ను ఎంచుకో</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> సెకన్లు</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> సెకన్ల సమయం మిగిలి ఉంది</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> సెకన్లు</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> రోజులు</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> గంట</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> రోజు</translation>
+<translation id="2704295676501803339">ఎడమవైపుకు తరలించండి</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> secs ago</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> సెకన్లు మిగిలి ఉన్నాయి</translation>
+<translation id="566737009157135450">పదం నుండి వెనుకవైపుకు తొలగించండి</translation>
+<translation id="436869212180315161">నొక్కు</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> నిమిషాలు</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> నిమిషాలు మిగిలి ఉన్నాయి</translation>
+<translation id="6040143037577758943">మూసివేయి</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">సహాయం</translation>
+<translation id="2405367043325750948">ముందుకు తొలగించండి</translation>
+<translation id="6699343763173986273">మీడియా తదుపరి ట్రాక్</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> సెకన్ల సమయం మిగిలి ఉంది</translation>
+<translation id="8226233771743600312">ఒక రోజుపాటు అంతరాయం కలిగించవద్దు</translation>
+<translation id="4252565523989510616">పదం నుండి ముందువైపుకు తొలగించండి</translation>
+<translation id="7457942297256758195">అన్నీ క్లియర్ చేయి</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> నిమిషాలు</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> రోజులు మిగిలాయి</translation>
+<translation id="6786750046913594791">ఫోల్డర్‌ను మూసివేయండి</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> నిమిషాలు</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> గంటలు మిగిలి ఉన్నాయి</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> సెకన్లు</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> సెకన్లు</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> సెకన్లు</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> రోజులు మిగిలాయి</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">క్లిప్‌బోర్డ్‌కు కాపీ చేయి</translation>
+<translation id="8371695176452482769">ఇప్పుడు మాట్లాడండి</translation>
+<translation id="1167268268675672572">పంక్తి మొదటికి తరలించి, ఎంపికను సవరించండి</translation>
+<translation id="6965382102122355670">సరే</translation>
+<translation id="7850320739366109486">అంతరాయం కలిగించవద్దు</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">కనిష్టీకరించు</translation>
+<translation id="6394627529324717982">కామా</translation>
+<translation id="3036649622769666520">ఫైళ్ళను తెరువు</translation>
+<translation id="8328145009876646418">ఎడమ హద్దు</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> సెకన్లు</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb
new file mode 100644
index 00000000000..b557838471d
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_th.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+<translation id="4820616160060340806">คำสั่ง+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">โฟลเดอร์ <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> ชั่วโมงที่ผ่านมา</translation>
+<translation id="6310545596129886942">เหลือ <ph name="NUMBER_FEW"/> วินาที</translation>
+<translation id="9213479837033539041">เหลือ <ph name="NUMBER_MANY"/> วินาที</translation>
+<translation id="1209866192426315618">เหลือ <ph name="NUMBER_DEFAULT"/> นาที</translation>
+<translation id="1801827354178857021">ระยะเวลา</translation>
+<translation id="1190609913194133056">ศูนย์การแจ้งเตือน</translation>
+<translation id="7470933019269157899">เหลือ <ph name="NUMBER_DEFAULT"/> นาที</translation>
+<translation id="5613020302032141669">ลูกศรซ้าย</translation>
+<translation id="4971687151119236543">แทร็กก่อนหน้าของสื่อ</translation>
+<translation id="8602707065186045623">ไฟล์ <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> วินาที</translation>
+<translation id="7511635910912978956">เหลือ <ph name="NUMBER_FEW"/> ชั่วโมง</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">ยกเลิก</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">ลูกศรขึ้น</translation>
+<translation id="3969863827134279083">เลื่อนขึ้น</translation>
+<translation id="7062130397825382308">เหลือ <ph name="NUMBER_ONE"/> วินาที</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/วินาที</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> ชั่วโมง</translation>
+<translation id="3990502903496589789">ขอบขวา</translation>
+<translation id="9038489124413477075">โฟลเดอร์ที่ไม่มีชื่อ</translation>
+<translation id="1940483897317142625">ลบจนสุดบรรทัด</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> นาที</translation>
+<translation id="3520476450377425184">เหลือ <ph name="NUMBER_MANY"/> วัน</translation>
+<translation id="932327136139879170">หน้าแรก</translation>
+<translation id="5600907569873192868">เหลือ <ph name="NUMBER_MANY"/> นาที</translation>
+<translation id="8666066831007952346">เหลือ <ph name="NUMBER_TWO"/> วัน</translation>
+<translation id="6390842777729054533">เหลือ <ph name="NUMBER_ZERO"/> วินาที</translation>
+<translation id="3909791450649380159">&amp;ตัด</translation>
+<translation id="2560788951337264832">เหลือ <ph name="NUMBER_ZERO"/> นาที</translation>
+<translation id="688711909580084195">หน้าเว็บที่ไม่มีชื่อ</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> วันที่ผ่านมา</translation>
+<translation id="5076340679995252485">&amp;วาง</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">เลื่อนไปทางขวาทีละคำ</translation>
+<translation id="364720409959344976">เลือกโฟลเดอร์เพื่ออัปโหลด</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> นาทีที่ผ่านมา</translation>
+<translation id="3234408098842461169">ลูกศรลง</translation>
+<translation id="3087734570205094154">ด้านล่าง</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497">เหลือ <ph name="NUMBER_ONE"/> นาที</translation>
+<translation id="1860796786778352021">ปิดการแจ้งเตือน</translation>
+<translation id="6364916375976753737">เลื่อนทางซ้าย</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> ชั่วโมงที่ผ่านมา</translation>
+<translation id="4218160142017529598">ลบย้อนหลัง</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> นาที</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> นาทีที่ผ่านมา</translation>
+<translation id="6945221475159498467">เลือก</translation>
+<translation id="6620110761915583480">บันทึกไฟล์</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">ลบจนถึงจุดเริ่มต้นบรรทัด</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">เหลือ <ph name="NUMBER_ONE"/> นาที</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> นาที</translation>
+<translation id="8210608804940886430">เลื่อนหน้าลง</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> วัน</translation>
+<translation id="7163503212501929773">เหลือ <ph name="NUMBER_MANY"/> ชั่วโมง</translation>
+<translation id="5329858601952122676">&amp;ลบ</translation>
+<translation id="6556866813142980365">ทำซ้ำ</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> วินาที</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> วินาทีที่ผ่านมา</translation>
+<translation id="7781829728241885113">เมื่อวานนี้</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478">เหลือ <ph name="NUMBER_FEW"/> นาที</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">เลื่อนไปทางขวา</translation>
+<translation id="6659594942844771486">แท็บ</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> วันที่ผ่านมา</translation>
+<translation id="8428213095426709021">การตั้งค่า</translation>
+<translation id="2497284189126895209">ไฟล์ทั้งหมด</translation>
+<translation id="7487278341251176613">เหลือ <ph name="NUMBER_TWO"/> นาที</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> วันที่ผ่านมา</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> วินาที</translation>
+<translation id="4320177379694898372">ไม่มีการเชื่อมต่ออินเทอร์เน็ต</translation>
+<translation id="7814458197256864873">&amp;คัดลอก</translation>
+<translation id="3889424535448813030">ลูกศรขวา</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> วินาทีที่ผ่านมา</translation>
+<translation id="2544782972264605588">เหลือ <ph name="NUMBER_DEFAULT"/> วินาที</translation>
+<translation id="6829324100069873704">กลับไปที่การแจ้งเตือน</translation>
+<translation id="6528179044667508675">ห้ามรบกวน</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> วินาที</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> นาที</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">อนุญาตให้มีการแจ้งเตือนจากรายการต่อไปนี้</translation>
+<translation id="2479520428668657293">เลื่อนไปทางขวาและปรับการเลือก</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> ชั่วโมง</translation>
+<translation id="1398853756734560583">ย่อ</translation>
+<translation id="4250229828105606438">ภาพหน้าจอ</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> ชั่วโมง</translation>
+<translation id="5260878308685146029">เหลือ <ph name="NUMBER_TWO"/> นาที</translation>
+<translation id="2557207087669398617">เลื่อนไปจุดเริ่มต้นบรรทัด</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">เลือก&amp;ทั้งหมด</translation>
+<translation id="2168039046890040389">เลื่อนหน้าขึ้น</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> วัน</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> นาที</translation>
+<translation id="6122334925474904337">เลื่อนไปทางขวาทีละคำและปรับการเลือก</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> นาที</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> วินาทีที่ผ่านมา</translation>
+<translation id="4927753642311223124">ที่นี่ไม่มีอะไรต้องดู ไปต่อได้</translation>
+<translation id="2482878487686419369">การแจ้งเตือน</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">เลื่อนมาที่นี่</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">เลื่อนลง</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> ชั่วโมง</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/วินาที</translation>
+<translation id="8394908167088220973">เล่น/หยุดสื่อชั่วคราว</translation>
+<translation id="2148716181193084225">วันนี้</translation>
+<translation id="7960078400008666149">ห้ามรบกวนเป็นเวลาหนึ่งชั่วโมง</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> นาทีที่ผ่านมา</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> วัน</translation>
+<translation id="2190355936436201913">(ว่างเปล่า)</translation>
+<translation id="1164369517022005061">เหลือ <ph name="NUMBER_DEFAULT"/> ชั่วโมง</translation>
+<translation id="152482086482215392">เหลือ <ph name="NUMBER_ONE"/> วินาที</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">เลื่อนทางขวา</translation>
+<translation id="7414887922320653780">เหลือ <ph name="NUMBER_ONE"/> ชั่วโมง</translation>
+<translation id="1413622004203049571">ปิดการแจ้งเตือนจาก <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">ด้านบน</translation>
+<translation id="2538759511191347839">เลื่อนไปสุดบรรทัดและปรับการเลือก</translation>
+<translation id="928465423150706909">เลื่อนไปสุดบรรทัด</translation>
+<translation id="8331626408530291785">เลื่อนขึ้น</translation>
+<translation id="7907591526440419938">เปิดไฟล์</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">เปิดโฟลเดอร์</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> ชั่วโมงที่ผ่านมา</translation>
+<translation id="815598010540052116">เลื่อนลง</translation>
+<translation id="6808150112686056157">หยุดสื่อ</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">คืนค่า</translation>
+<translation id="5349525451964472598">เลื่อนไปทางซ้ายและปรับการเลือก</translation>
+<translation id="1781701194097416995">เลื่อนไปทางซ้ายทีละคำ</translation>
+<translation id="1243314992276662751">อัปโหลด</translation>
+<translation id="50030952220075532">เหลือ <ph name="NUMBER_ONE"/> วัน</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">เลื่อนไปทางซ้ายทีละคำและปรับการเลือก</translation>
+<translation id="945522503751344254">ส่งความคิดเห็น</translation>
+<translation id="9170848237812810038">เ&amp;ลิกทำ</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> ชั่วโมงที่ผ่านมา</translation>
+<translation id="6918245111648057970">อนุญาตให้มีการแจ้งเตือนจากรายการต่อไปนี้สำหรับผู้ใช้แต่ละคน:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> วินาที</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312">เหลือ <ph name="NUMBER_MANY"/> นาที</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> วินาทีที่ผ่านมา</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">การตั้งค่า...</translation>
+<translation id="6845383723252244143">เลือกโฟลเดอร์</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> วินาที</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> วันที่ผ่านมา</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> วัน</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> ชั่วโมง</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> นาทีที่ผ่านมา</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/วินาที</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> วัน</translation>
+<translation id="2704295676501803339">เลื่อนไปทางซ้าย</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> วินาทีที่ผ่านมา</translation>
+<translation id="494645311413743213">เหลือ <ph name="NUMBER_TWO"/> วินาที</translation>
+<translation id="566737009157135450">ลบคำย้อนหลัง</translation>
+<translation id="436869212180315161">กด</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> วินาทีที่ผ่านมา</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/วินาที</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">เหลือ <ph name="NUMBER_FEW"/> นาที</translation>
+<translation id="6040143037577758943">ปิด</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> นาทีที่ผ่านมา</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/วินาที</translation>
+<translation id="7649070708921625228">ช่วยเหลือ</translation>
+<translation id="2405367043325750948">ลบไปข้างหน้า</translation>
+<translation id="6699343763173986273">แทร็กถัดไปของสื่อ</translation>
+<translation id="5445120697129764393">เหลือ <ph name="NUMBER_DEFAULT"/> วินาที</translation>
+<translation id="8226233771743600312">ห้ามรบกวนเป็นเวลาหนึ่งวัน</translation>
+<translation id="4252565523989510616">ลบคำไปข้างหน้า</translation>
+<translation id="7457942297256758195">ล้างทั้งหมด</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> วันที่ผ่านมา</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> นาที</translation>
+<translation id="1963692530539281474">เหลือ <ph name="NUMBER_DEFAULT"/> วัน</translation>
+<translation id="6786750046913594791">ปิดโฟลเดอร์</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045">เหลือ <ph name="NUMBER_TWO"/> ชั่วโมง</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> ชั่วโมงที่ผ่านมา</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> วินาที</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> วินาที</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382">เหลือ <ph name="NUMBER_FEW"/> วัน</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/วินาที</translation>
+<translation id="2743387203779672305">คัดลอกไว้ที่คลิปบอร์ด</translation>
+<translation id="8371695176452482769">เชิญพูดเลย</translation>
+<translation id="1167268268675672572">เลื่อนไปจุดเริ่มต้นของบรรทัดและปรับการเลือก</translation>
+<translation id="6965382102122355670">ตกลง</translation>
+<translation id="7850320739366109486">ห้ามรบกวน</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">ย่อ</translation>
+<translation id="6394627529324717982">จุลภาค</translation>
+<translation id="3036649622769666520">เปิดไฟล์</translation>
+<translation id="8328145009876646418">ขอบซ้าย</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb
new file mode 100644
index 00000000000..91879a06074
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_tr.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/> klasörü</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> saat önce</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> saniye kaldı</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> saniye kaldı</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> dakika kaldı</translation>
+<translation id="1801827354178857021">Dönem</translation>
+<translation id="1190609913194133056">Bildirim Merkezi</translation>
+<translation id="7470933019269157899"><ph name="NUMBER_DEFAULT"/> dakika kaldı</translation>
+<translation id="5613020302032141669">Sol Ok</translation>
+<translation id="4971687151119236543">Medya Önceki Parça</translation>
+<translation id="8602707065186045623">Dosyayı <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> saniye</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> saat kaldı</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">İptal</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Yukarı Ok</translation>
+<translation id="3969863827134279083">Yukarı Git</translation>
+<translation id="7062130397825382308"><ph name="NUMBER_ONE"/> second left</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/sn</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> saat</translation>
+<translation id="3990502903496589789">Sağ Kenar</translation>
+<translation id="9038489124413477075">Adsız Klasör</translation>
+<translation id="1940483897317142625">Satırın Sonuna Kadar Sil</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> dakika</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> gün kaldı</translation>
+<translation id="932327136139879170">Ana Sayfa</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> dakika kaldı</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> gün kaldı</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> saniye kaldı</translation>
+<translation id="3909791450649380159">&amp;Kes</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> dakika kaldı</translation>
+<translation id="688711909580084195">Başlıksız Web Sayfası</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> gün önce</translation>
+<translation id="5076340679995252485">&amp;Yapıştır</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Bir Kelime Sağa Git</translation>
+<translation id="364720409959344976">Yüklenecek Klasörü Seçin</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> dakika önce</translation>
+<translation id="3234408098842461169">Aşağı Ok</translation>
+<translation id="3087734570205094154">Alt</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> dakika kaldı</translation>
+<translation id="1860796786778352021">Bildirimi kapat</translation>
+<translation id="6364916375976753737">Sola Kaydır</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> saat önce</translation>
+<translation id="4218160142017529598">Geriye Doğru Sil</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> dakika</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> dakika önce</translation>
+<translation id="6945221475159498467">Seç</translation>
+<translation id="6620110761915583480">Dosyayı Kaydet</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Satırın Başına Kadar Sil</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868"><ph name="NUMBER_ONE"/> dakika kaldı</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> dakika</translation>
+<translation id="8210608804940886430">Page Down</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> gün</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> saat kaldı</translation>
+<translation id="5329858601952122676">&amp;Sil</translation>
+<translation id="6556866813142980365">Yeniden Yap</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> saniye</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> saniye önce</translation>
+<translation id="7781829728241885113">Dün</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> dakika kaldı</translation>
+<translation id="5517291721709019259"><ph name="NUMBER_FEW"/> seconds left</translation>
+<translation id="6903282483217634857">Sağa Git</translation>
+<translation id="6659594942844771486">Sekme</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> gün önce</translation>
+<translation id="8428213095426709021">Ayarlar</translation>
+<translation id="2497284189126895209">Tüm Dosyalar</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> dakika kaldı</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> gün önce</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> saniye</translation>
+<translation id="4320177379694898372">İnternet bağlantısı yok</translation>
+<translation id="7814458197256864873">K&amp;opyala</translation>
+<translation id="3889424535448813030">Sağ Ok</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> saniye önce</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> saniye kaldı</translation>
+<translation id="6829324100069873704">Bildirimlere geri dön</translation>
+<translation id="6528179044667508675">Rahatsız etmeyin</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> saniye</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> dakika</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Şunlardan gelen bildirimlere izin ver:</translation>
+<translation id="2479520428668657293">Sağa Git ve Seçimi Değiştir</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> saat</translation>
+<translation id="1398853756734560583">Büyüt</translation>
+<translation id="4250229828105606438">Ekran görüntüsü</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> saat</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> dakika kaldı</translation>
+<translation id="2557207087669398617">Satırın Başına Git</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Tümünü &amp;seç</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> gün</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> dakika</translation>
+<translation id="6122334925474904337">Bir Kelime Sağa Git ve Seçimi Değiştir</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> minute</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> saniye önce</translation>
+<translation id="4927753642311223124">Burada görülecek bir şey yok, devam edin.</translation>
+<translation id="2482878487686419369">Bildirimler</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Buraya Kaydır</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Aşağı Git</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> saat</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/sn</translation>
+<translation id="8394908167088220973">Medyayı Oynat/Duraklat</translation>
+<translation id="2148716181193084225">Bugün</translation>
+<translation id="7960078400008666149">Bir saat süreyle rahatsız etmeyin</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> dakika önce</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> gün</translation>
+<translation id="2190355936436201913">(boş)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> saat kaldı</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> saniye kaldı</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Sağa Kaydır</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> saat kaldı</translation>
+<translation id="1413622004203049571"><ph name="NOTIFIER_NAME"/> bildirimlerini devre dışı bırak</translation>
+<translation id="2666092431469916601">Üst</translation>
+<translation id="2538759511191347839">Satırın Sonuna Git ve Seçimi Değiştir</translation>
+<translation id="928465423150706909">Satırın Sonuna Git</translation>
+<translation id="8331626408530291785">Yukarı Kaydır</translation>
+<translation id="7907591526440419938">Dosya Aç</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Klasörü aç</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> saat önce</translation>
+<translation id="815598010540052116">Aşağı Kaydır</translation>
+<translation id="6808150112686056157">Medyayı Durdur</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Geri yükle</translation>
+<translation id="5349525451964472598">Sola Git ve Seçimi Değiştir</translation>
+<translation id="1781701194097416995">Bir Kelime Sola Git</translation>
+<translation id="1243314992276662751">Yükle</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> gün kaldı</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Bir Kelime Sola Git ve Seçimi Değiştir</translation>
+<translation id="945522503751344254">Geri bildirim gönder</translation>
+<translation id="9170848237812810038">&amp;Geri al</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> saat önce</translation>
+<translation id="6918245111648057970">Her bir kullanıcı için şunlardan gelen bildirimlere izin ver:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> second</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> dakika kaldı</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> saniye önce</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Ayarlar...</translation>
+<translation id="6845383723252244143">Klasörü Seçin</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> seconds</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> saniye</translation>
+<translation id="5583640892426849032">Geri al tuşu</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> gün önce</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> gün</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> saat</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> dakika önce</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/sn</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> gün</translation>
+<translation id="2704295676501803339">Sola Git</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> saniye önce</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> saniye kaldı</translation>
+<translation id="566737009157135450">Geriye Doğru Bir Kelime Sil</translation>
+<translation id="436869212180315161">Basın</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> saniye önce</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/sn</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017"><ph name="NUMBER_FEW"/> dakika kaldı</translation>
+<translation id="6040143037577758943">Kapat</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> dakika önce</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/sn</translation>
+<translation id="7649070708921625228">Yardım</translation>
+<translation id="2405367043325750948">İleriye Doğru Sil</translation>
+<translation id="6699343763173986273">Medya Sonraki Parça</translation>
+<translation id="5445120697129764393"><ph name="NUMBER_DEFAULT"/> saniye kaldı</translation>
+<translation id="8226233771743600312">Bir gün süreyle rahatsız etmeyin</translation>
+<translation id="4252565523989510616">İleriye Doğru Bir Kelime Sil</translation>
+<translation id="7457942297256758195">Tümünü Temizle</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> gün önce</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> dakika</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> gün kaldı</translation>
+<translation id="6786750046913594791">Klasörü kapat</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> minutes</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> saat kaldı</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> saat önce</translation>
+<translation id="8400147561352026160">ÜstKrkt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> saniye</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> saniye</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> gün kaldı</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/sn</translation>
+<translation id="2743387203779672305">Panoya kopyala</translation>
+<translation id="8371695176452482769">Şimdi konuşun</translation>
+<translation id="1167268268675672572">Satırın Başına Git ve Seçimi Değiştir</translation>
+<translation id="6965382102122355670">Tamam</translation>
+<translation id="7850320739366109486">Rahatsız Etmeyin</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Simge durumuna küçült</translation>
+<translation id="6394627529324717982">Virgül</translation>
+<translation id="3036649622769666520">Dosya Aç</translation>
+<translation id="8328145009876646418">Sol Kenar</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb
new file mode 100644
index 00000000000..0ebb4139ab7
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_uk.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Папка <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> сек. залишилось</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
+<translation id="1209866192426315618">Залишилось <ph name="NUMBER_DEFAULT"/> хв.</translation>
+<translation id="1801827354178857021">Період</translation>
+<translation id="1190609913194133056">Центр сповіщень</translation>
+<translation id="7470933019269157899">Залишилося <ph name="NUMBER_DEFAULT"/> хвилини</translation>
+<translation id="5613020302032141669">Курсор ліворуч</translation>
+<translation id="4971687151119236543">Попередня композиція</translation>
+<translation id="8602707065186045623">файл <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> годин залишилось</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Скасувати</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> б</translation>
+<translation id="3660179305079774227">Курсор угору</translation>
+<translation id="3969863827134279083">Перемістити курсор угору</translation>
+<translation id="7062130397825382308">Залишилася <ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> Мб/сек.</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> годин</translation>
+<translation id="3990502903496589789">Правий край</translation>
+<translation id="9038489124413477075">Папка без назви</translation>
+<translation id="1940483897317142625">Видалити символи до кінця рядка</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> хв.</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
+<translation id="932327136139879170">Домашня сторінка</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">Вирізат&amp;и</translation>
+<translation id="2560788951337264832"><ph name="NUMBER_ZERO"/> minutes left</translation>
+<translation id="688711909580084195">Веб-сторінка без назви</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> дн. тому</translation>
+<translation id="5076340679995252485">&amp;Вставити</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> Тб</translation>
+<translation id="7139614227326422685">Перемістити курсор на одне слово праворуч</translation>
+<translation id="364720409959344976">Виберіть папку для завантаження</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Курсор униз</translation>
+<translation id="3087734570205094154">Низ</translation>
+<translation id="8828991073132329143"><ph name="NUMBER_MANY"/> seconds left</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> хв. залишилась</translation>
+<translation id="1860796786778352021">Закрити сповіщення</translation>
+<translation id="6364916375976753737">Прокрутка вліво</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> год. тому</translation>
+<translation id="4218160142017529598">Видалити символи перед курсором</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> хв</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> хв. тому</translation>
+<translation id="6945221475159498467">Вибрати</translation>
+<translation id="6620110761915583480">Зберегти файл</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> seconds</translation>
+<translation id="8924469368910458384">Видалити символи до початку рядка</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Залишилася <ph name="NUMBER_ONE"/> хвилина</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> хв.</translation>
+<translation id="8210608804940886430">Сторінка вниз</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
+<translation id="5329858601952122676">&amp;Видалити</translation>
+<translation id="6556866813142980365">Повторити</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> Кб</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> minutes</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Учора</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> minutes</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> хв. залишилось</translation>
+<translation id="5517291721709019259">Залишилося <ph name="NUMBER_FEW"/> секунди</translation>
+<translation id="6903282483217634857">Перемістити курсор праворуч</translation>
+<translation id="6659594942844771486">Вкладка</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> Мб</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> дн. тому</translation>
+<translation id="8428213095426709021">Налаштування</translation>
+<translation id="2497284189126895209">Усі файли</translation>
+<translation id="7487278341251176613"><ph name="NUMBER_TWO"/> minutes left</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> день тому</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> сек.</translation>
+<translation id="4320177379694898372">Немає з’єднання з Інтернетом</translation>
+<translation id="7814458197256864873">&amp;Копіювати</translation>
+<translation id="3889424535448813030">Курсор праворуч</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> сек. тому</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> сек. залишилось</translation>
+<translation id="6829324100069873704">Повернутися до сповіщень</translation>
+<translation id="6528179044667508675">Не турбувати</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> с</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Дозволити сповіщення з перелічених нижче джерел.</translation>
+<translation id="2479520428668657293">Перемістити курсор праворуч і змінити виділений фрагмент</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> годин</translation>
+<translation id="1398853756734560583">Збільшити</translation>
+<translation id="4250229828105606438">Знімок екрана</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
+<translation id="2557207087669398617">Перемістити курсор на початок рядка</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> Гб</translation>
+<translation id="1901303067676059328">Вибрати &amp;всі</translation>
+<translation id="2168039046890040389">Сторінка вгору</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> днів</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">Перемістити курсор на одне слово праворуч і змінити виділений фрагмент</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> хвилина</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Сповіщень немає.</translation>
+<translation id="2482878487686419369">Сповіщення</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Прокрутка до цього місця</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">Перемістити курсор униз</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> годин</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> Кб/сек.</translation>
+<translation id="8394908167088220973">Відтворити чи призупинити</translation>
+<translation id="2148716181193084225">Сьогодні</translation>
+<translation id="7960078400008666149">Не турбувати впродовж однієї години</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> хв. тому</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
+<translation id="2190355936436201913">(пусто)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> годин залишилось</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> сек. залишилась</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">Прокрутка вправо</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> година залишилась</translation>
+<translation id="1413622004203049571">Вимкнути сповіщення від <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Верх</translation>
+<translation id="2538759511191347839">Перемістити курсор у кінець рядка та змінити виділений фрагмент</translation>
+<translation id="928465423150706909">Перемістити курсор у кінець рядка</translation>
+<translation id="8331626408530291785">Прокрутка вгору</translation>
+<translation id="7907591526440419938">Відкрити файл</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Відкрити папку</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> год. тому</translation>
+<translation id="815598010540052116">Прокрутка вниз</translation>
+<translation id="6808150112686056157">Зупинити</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Відновити</translation>
+<translation id="5349525451964472598">Перемістити курсор ліворуч і змінити виділений фрагмент</translation>
+<translation id="1781701194097416995">Перемістити курсор на одне слово ліворуч</translation>
+<translation id="1243314992276662751">Завантажити</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> день залишився</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Перемістити курсор на одне слово ліворуч і змінити виділений фрагмент</translation>
+<translation id="945522503751344254">Надіслати відгук</translation>
+<translation id="9170848237812810038">&amp;Скасувати</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> год. тому</translation>
+<translation id="6918245111648057970">Дозволити сповіщення для кожного користувача:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> секунда</translation>
+<translation id="1270251962578273213"><ph name="NUMBER_TWO"/> seconds left</translation>
+<translation id="3994835489895548312"><ph name="NUMBER_MANY"/> minutes left</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> Пб</translation>
+<translation id="2983818520079887040">Налаштування...</translation>
+<translation id="6845383723252244143">Вибір папки</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> секунди</translation>
+<translation id="5368780922436099921"><ph name="NUMBER_ZERO"/> seconds left</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> сек.</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> днів</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> година</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> хв. тому</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> Гб/сек.</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> день</translation>
+<translation id="2704295676501803339">Перемістити курсор ліворуч</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> сек. тому</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
+<translation id="566737009157135450">Видалити слово перед курсором</translation>
+<translation id="436869212180315161">Натиснути</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> сек. тому</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> Тб/сек.</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> minutes</translation>
+<translation id="1858722859751911017">Залишилося <ph name="NUMBER_FEW"/> хвилини</translation>
+<translation id="6040143037577758943">Закрити</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> б/сек.</translation>
+<translation id="7649070708921625228">Довідка</translation>
+<translation id="2405367043325750948">Видалити символи після курсора</translation>
+<translation id="6699343763173986273">Наступна композиція</translation>
+<translation id="5445120697129764393">Залишилося <ph name="NUMBER_DEFAULT"/> секунд</translation>
+<translation id="8226233771743600312">Не турбувати впродовж одного дня</translation>
+<translation id="4252565523989510616">Видалити слово після курсора</translation>
+<translation id="7457942297256758195">Очистити все</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> хв.</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> днів залишилось</translation>
+<translation id="6786750046913594791">Закрити папку</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> хвилини</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> сек.</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> seconds</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> днів залишилось</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> Пб/сек.</translation>
+<translation id="2743387203779672305">Копіювати в буфер</translation>
+<translation id="8371695176452482769">Диктуйте</translation>
+<translation id="1167268268675672572">Перемістити курсор на початок рядка та змінити виділений фрагмент</translation>
+<translation id="6965382102122355670">ОК</translation>
+<translation id="7850320739366109486">Не турбувати</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Зменшити</translation>
+<translation id="6394627529324717982">Кома</translation>
+<translation id="3036649622769666520">Відкрити файли</translation>
+<translation id="8328145009876646418">Лівий край</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> seconds</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb
new file mode 100644
index 00000000000..660bec8777f
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_vi.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+<translation id="4820616160060340806">Command+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">Thư mục <ph name="FOLDER_NAME"/></translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> hours ago</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> giây còn lại</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> giây còn lại</translation>
+<translation id="1209866192426315618"><ph name="NUMBER_DEFAULT"/> phút còn lại</translation>
+<translation id="1801827354178857021">Khoảng thời gian</translation>
+<translation id="1190609913194133056">Trung tâm thông báo</translation>
+<translation id="7470933019269157899">Còn lại <ph name="NUMBER_DEFAULT"/> phút</translation>
+<translation id="5613020302032141669">Mũi tên Trái</translation>
+<translation id="4971687151119236543">Bản nhạc trước của trình phát phương tiện</translation>
+<translation id="8602707065186045623">Tệp <ph name="SAVEAS_EXTENSION_TYPE"/> (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> giây</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> giờ còn lại</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">Hủy</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">Phím mũi tên Lên</translation>
+<translation id="3969863827134279083">Di chuyển lên</translation>
+<translation id="7062130397825382308">Còn <ph name="NUMBER_ONE"/> giây</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/giây</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> giờ</translation>
+<translation id="3990502903496589789">Cạnh bên Phải</translation>
+<translation id="9038489124413477075">Thư mục không có tên</translation>
+<translation id="1940483897317142625">Xóa đến cuối dòng</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> phút</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> ngày còn lại</translation>
+<translation id="932327136139879170">Trang chủ</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> phút còn lại</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> ngày còn lại</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> giây còn lại</translation>
+<translation id="3909791450649380159">Cắ&amp;t</translation>
+<translation id="2560788951337264832">Còn lại <ph name="NUMBER_ZERO"/> phút</translation>
+<translation id="688711909580084195">Trang web không có tiêu đề</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> days ago</translation>
+<translation id="5076340679995252485">&amp;Dán</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">Di chuyển sang bên phải từ</translation>
+<translation id="364720409959344976">Chọn thư mục để tải lên</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> mins ago</translation>
+<translation id="3234408098842461169">Phím mũi tên Xuống</translation>
+<translation id="3087734570205094154">Bên dưới</translation>
+<translation id="8828991073132329143">Còn <ph name="NUMBER_MANY"/> giây</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> phút còn lại</translation>
+<translation id="1860796786778352021">Đóng thông báo</translation>
+<translation id="6364916375976753737">Cuộn qua Trái</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> hour ago</translation>
+<translation id="4218160142017529598">Xóa lùi</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> phút</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> phút trước</translation>
+<translation id="6945221475159498467">Chọn</translation>
+<translation id="6620110761915583480">Lưu Tệp</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> giây</translation>
+<translation id="8924469368910458384">Xóa đến đầu dòng</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">Còn lại <ph name="NUMBER_ONE"/> phút</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> phút</translation>
+<translation id="8210608804940886430">Trang Dưới</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> ngày</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> giờ còn lại</translation>
+<translation id="5329858601952122676">&amp;Xoá</translation>
+<translation id="6556866813142980365">Làm lại</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> giây</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> phút</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> secs ago</translation>
+<translation id="7781829728241885113">Hôm qua</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> phút</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> phút còn lại</translation>
+<translation id="5517291721709019259">Còn <ph name="NUMBER_FEW"/> giây</translation>
+<translation id="6903282483217634857">Di chuyển sang phải</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> ngày trước</translation>
+<translation id="8428213095426709021">Cài đặt</translation>
+<translation id="2497284189126895209">Tất cả Tệp tin</translation>
+<translation id="7487278341251176613">Còn lại <ph name="NUMBER_TWO"/> phút</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> day ago</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> giây</translation>
+<translation id="4320177379694898372">Không có kết nối Internet</translation>
+<translation id="7814458197256864873">Sao &amp;chép</translation>
+<translation id="3889424535448813030">Phím mũi tên Phải</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> sec ago</translation>
+<translation id="2544782972264605588"><ph name="NUMBER_DEFAULT"/> giây còn lại</translation>
+<translation id="6829324100069873704">Quay lại thông báo</translation>
+<translation id="6528179044667508675">Không làm phiền</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> giây</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> phút</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">Cho phép thông báo từ:</translation>
+<translation id="2479520428668657293">Di chuyển sang phải và sửa đổi lựa chọn</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> giờ</translation>
+<translation id="1398853756734560583">Phóng to</translation>
+<translation id="4250229828105606438">Ảnh chụp màn hình</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> giờ</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> phút còn lại</translation>
+<translation id="2557207087669398617">Di chuyển tới đầu dòng</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">Chọn &amp;tất cả</translation>
+<translation id="2168039046890040389">Page Up</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> ngày</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> phút</translation>
+<translation id="6122334925474904337">Di chuyển sang bên phải từ và sửa đổi lựa chọn</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> phút</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> secs ago</translation>
+<translation id="4927753642311223124">Không có nội dung nào để xem ở đây, hãy tiếp tục.</translation>
+<translation id="2482878487686419369">Thông báo</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">Cuộn tới Đây</translation>
+<translation id="4552416320897244156">Trang Dưới</translation>
+<translation id="3066573403916685335">Di chuyển xuống</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> giờ</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">Phát/Tạm dừng trình phát phương tiện</translation>
+<translation id="2148716181193084225">Hôm nay</translation>
+<translation id="7960078400008666149">Không làm phiền trong một giờ</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> mins ago</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> ngày</translation>
+<translation id="2190355936436201913">(trống)</translation>
+<translation id="1164369517022005061"><ph name="NUMBER_DEFAULT"/> giờ còn lại</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> giây còn lại</translation>
+<translation id="8447116497070723931">Trang Trên</translation>
+<translation id="4588090240171750605">Cuộn qua Phải</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> giờ còn lại</translation>
+<translation id="1413622004203049571">Tắt thông báo từ <ph name="NOTIFIER_NAME"/></translation>
+<translation id="2666092431469916601">Hàng đầu</translation>
+<translation id="2538759511191347839">Di chuyển đến cuối dòng và sửa đổi lựa chọn</translation>
+<translation id="928465423150706909">Di chuyển đến cuối dòng</translation>
+<translation id="8331626408530291785">Cuộn Lên</translation>
+<translation id="7907591526440419938">Mở Tệp</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">Mở thư mục</translation>
+<translation id="1293699935367580298">Thoát</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> giờ trước</translation>
+<translation id="815598010540052116">Cuộn Xuống</translation>
+<translation id="6808150112686056157">Dừng trình phát phương tiện</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">Khôi phục</translation>
+<translation id="5349525451964472598">Di chuyển sang trái và sửa đổi lựa chọn</translation>
+<translation id="1781701194097416995">Di chuyển sang bên trái từ</translation>
+<translation id="1243314992276662751">Tải lên</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> ngày còn lại</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">Di chuyển sang bên trái từ và sửa đổi lựa chọn</translation>
+<translation id="945522503751344254">Gửi phản hồi</translation>
+<translation id="9170848237812810038">H&amp;oàn tác</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> hours ago</translation>
+<translation id="6918245111648057970">Cho phép thông báo từ mục sau đối với mỗi người dùng:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> giây</translation>
+<translation id="1270251962578273213">Còn <ph name="NUMBER_TWO"/> giây</translation>
+<translation id="3994835489895548312">Còn lại <ph name="NUMBER_MANY"/> phút</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> secs ago</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">Cài đặt...</translation>
+<translation id="6845383723252244143">Chọn Thư mục</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> giây</translation>
+<translation id="5368780922436099921">Còn <ph name="NUMBER_ZERO"/> giây</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> giây</translation>
+<translation id="5583640892426849032">Backspace</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> days ago</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> ngày</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> giờ</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> min ago</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/giây</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> ngày</translation>
+<translation id="2704295676501803339">Di chuyển sang trái</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> giây trước</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> giây còn lại</translation>
+<translation id="566737009157135450">Xóa lùi từ</translation>
+<translation id="436869212180315161">Nhấp vào</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> secs ago</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/giây</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> phút</translation>
+<translation id="1858722859751911017">Còn lại <ph name="NUMBER_FEW"/> phút</translation>
+<translation id="6040143037577758943">Đóng</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> mins ago</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/giây</translation>
+<translation id="7649070708921625228">Trợ giúp</translation>
+<translation id="2405367043325750948">Xóa tiến</translation>
+<translation id="6699343763173986273">Bản nhạc tiếp theo của trình phát phương tiện</translation>
+<translation id="5445120697129764393">Còn <ph name="NUMBER_DEFAULT"/> giây</translation>
+<translation id="8226233771743600312">Không làm phiền trong một ngày</translation>
+<translation id="4252565523989510616">Xóa tiến từ</translation>
+<translation id="7457942297256758195">Xóa tất cả</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> days ago</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> phút</translation>
+<translation id="1963692530539281474"><ph name="NUMBER_DEFAULT"/> ngày còn lại</translation>
+<translation id="6786750046913594791">Đóng thư mục</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> phút</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> giờ còn lại</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> hours ago</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> giây</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> giây</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> giây</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> ngày còn lại</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/giây</translation>
+<translation id="2743387203779672305">Sao chép vào khay nhớ tạm</translation>
+<translation id="8371695176452482769">Nói ngay bây giờ</translation>
+<translation id="1167268268675672572">Di chuyển tới đầu dòng và sửa đổi lựa chọn</translation>
+<translation id="6965382102122355670">OK</translation>
+<translation id="7850320739366109486">Không làm phiền</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">Thu nhỏ</translation>
+<translation id="6394627529324717982">Dấu phẩy</translation>
+<translation id="3036649622769666520">Mở Tệp</translation>
+<translation id="8328145009876646418">Cạnh Bên trái</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> giây</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
new file mode 100644
index 00000000000..bb06bc54a1a
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+<translation id="4820616160060340806">命令键 + <ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8806053966018712535">文件夹“<ph name="FOLDER_NAME"/>”</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">End</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 小时前</translation>
+<translation id="6310545596129886942"><ph name="NUMBER_FEW"/> secs left</translation>
+<translation id="9213479837033539041"><ph name="NUMBER_MANY"/> secs left</translation>
+<translation id="1209866192426315618">还有 <ph name="NUMBER_DEFAULT"/> 分钟</translation>
+<translation id="1801827354178857021">期间</translation>
+<translation id="1190609913194133056">通知中心</translation>
+<translation id="7470933019269157899">还剩 <ph name="NUMBER_DEFAULT"/> 分钟</translation>
+<translation id="5613020302032141669">向左箭头</translation>
+<translation id="4971687151119236543">媒体上一曲</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 文件 (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> secs</translation>
+<translation id="7511635910912978956"><ph name="NUMBER_FEW"/> hours left</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">取消</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">向上箭头</translation>
+<translation id="3969863827134279083">上移</translation>
+<translation id="7062130397825382308">还剩<ph name="NUMBER_ONE"/>秒</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/s</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 小时</translation>
+<translation id="3990502903496589789">右边缘</translation>
+<translation id="9038489124413477075">未命名的文件夹</translation>
+<translation id="1940483897317142625">删除至行末</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分钟</translation>
+<translation id="3520476450377425184"><ph name="NUMBER_MANY"/> days left</translation>
+<translation id="932327136139879170">家庭</translation>
+<translation id="5600907569873192868"><ph name="NUMBER_MANY"/> mins left</translation>
+<translation id="8666066831007952346"><ph name="NUMBER_TWO"/> days left</translation>
+<translation id="6390842777729054533"><ph name="NUMBER_ZERO"/> secs left</translation>
+<translation id="3909791450649380159">剪切(&amp;T)</translation>
+<translation id="2560788951337264832">还剩 <ph name="NUMBER_ZERO"/> 分钟</translation>
+<translation id="688711909580084195">无标题网页</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 天前</translation>
+<translation id="5076340679995252485">粘贴(&amp;P)</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">右移一个字</translation>
+<translation id="364720409959344976">选择要上传的文件夹</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分钟前</translation>
+<translation id="3234408098842461169">向下箭头</translation>
+<translation id="3087734570205094154">底部</translation>
+<translation id="8828991073132329143">还剩<ph name="NUMBER_MANY"/>秒</translation>
+<translation id="5935630983280450497"><ph name="NUMBER_ONE"/> min left</translation>
+<translation id="1860796786778352021">关闭通知</translation>
+<translation id="6364916375976753737">向左滚动</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 小时前</translation>
+<translation id="4218160142017529598">向前删除</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分钟</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分钟前</translation>
+<translation id="6945221475159498467">选择</translation>
+<translation id="6620110761915583480">保存文件</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="8924469368910458384">删除至行首</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">还剩 <ph name="NUMBER_ONE"/> 分钟</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> min</translation>
+<translation id="8210608804940886430">向下翻页</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> days</translation>
+<translation id="7163503212501929773"><ph name="NUMBER_MANY"/> hours left</translation>
+<translation id="5329858601952122676">删除(&amp;D)</translation>
+<translation id="6556866813142980365">重做</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> secs</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分钟</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
+<translation id="7781829728241885113">昨天</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分钟</translation>
+<translation id="50960180632766478"><ph name="NUMBER_FEW"/> mins left</translation>
+<translation id="5517291721709019259">还剩<ph name="NUMBER_FEW"/>秒</translation>
+<translation id="6903282483217634857">右移</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 天前</translation>
+<translation id="8428213095426709021">设置</translation>
+<translation id="2497284189126895209">所有文件</translation>
+<translation id="7487278341251176613">还剩 <ph name="NUMBER_TWO"/> 分钟</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 天前</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> sec</translation>
+<translation id="4320177379694898372">未连接到互联网</translation>
+<translation id="7814458197256864873">复制(&amp;C)</translation>
+<translation id="3889424535448813030">向右箭头</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
+<translation id="2544782972264605588">还有 <ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="6829324100069873704">返回通知</translation>
+<translation id="6528179044667508675">请勿打扰</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> mins</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">允许以下来源的通知:</translation>
+<translation id="2479520428668657293">右移并更改选择范围</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> hours</translation>
+<translation id="1398853756734560583">最大化</translation>
+<translation id="4250229828105606438">屏幕截图</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> hours</translation>
+<translation id="5260878308685146029"><ph name="NUMBER_TWO"/> mins left</translation>
+<translation id="2557207087669398617">移至行首</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">全选(&amp;A)</translation>
+<translation id="2168039046890040389">向上翻页</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 天</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> mins</translation>
+<translation id="6122334925474904337">右移一个字并更改选择范围</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分钟</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
+<translation id="4927753642311223124">这里没有任何通知,往前走吧。</translation>
+<translation id="2482878487686419369">通知</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">滚动到此处</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">下移</translation>
+<translation id="7052633198403197513">F1</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> hours</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
+<translation id="8394908167088220973">媒体播放/暂停</translation>
+<translation id="2148716181193084225">今天</translation>
+<translation id="7960078400008666149">1 小时内请勿打扰</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分钟前</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> days</translation>
+<translation id="2190355936436201913">(空)</translation>
+<translation id="1164369517022005061">还有 <ph name="NUMBER_DEFAULT"/> 小时</translation>
+<translation id="152482086482215392"><ph name="NUMBER_ONE"/> sec left</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">向右滚动</translation>
+<translation id="7414887922320653780"><ph name="NUMBER_ONE"/> hour left</translation>
+<translation id="1413622004203049571">停用来自“<ph name="NOTIFIER_NAME"/>”的通知</translation>
+<translation id="2666092431469916601">顶部</translation>
+<translation id="2538759511191347839">移至行末并更改选择范围</translation>
+<translation id="928465423150706909">移至行末</translation>
+<translation id="8331626408530291785">向上滚动</translation>
+<translation id="7907591526440419938">打开文件</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">打开文件夹</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 小时前</translation>
+<translation id="815598010540052116">向下滚动</translation>
+<translation id="6808150112686056157">媒体停止</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">恢复</translation>
+<translation id="5349525451964472598">左移并更改选择范围</translation>
+<translation id="1781701194097416995">左移一个字</translation>
+<translation id="1243314992276662751">上传</translation>
+<translation id="50030952220075532"><ph name="NUMBER_ONE"/> day left</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">左移一个字并更改选择范围</translation>
+<translation id="945522503751344254">发送反馈</translation>
+<translation id="9170848237812810038">撤消(&amp;U)</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 小时前</translation>
+<translation id="6918245111648057970">对于每位用户,允许接收下列源发出的通知:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="1270251962578273213">还剩<ph name="NUMBER_TWO"/>秒</translation>
+<translation id="3994835489895548312">还剩 <ph name="NUMBER_MANY"/> 分钟</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">设置...</translation>
+<translation id="6845383723252244143">选择文件夹</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="5368780922436099921">还剩<ph name="NUMBER_ZERO"/>秒</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> secs</translation>
+<translation id="5583640892426849032">退格</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 天前</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> days</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> hour</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分钟前</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/s</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> day</translation>
+<translation id="2704295676501803339">左移</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
+<translation id="494645311413743213"><ph name="NUMBER_TWO"/> secs left</translation>
+<translation id="566737009157135450">向前删除一个字</translation>
+<translation id="436869212180315161">按</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/s</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分钟</translation>
+<translation id="1858722859751911017">还剩 <ph name="NUMBER_FEW"/> 分钟</translation>
+<translation id="6040143037577758943">关闭</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分钟前</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/s</translation>
+<translation id="7649070708921625228">帮助</translation>
+<translation id="2405367043325750948">向后删除</translation>
+<translation id="6699343763173986273">媒体下一曲</translation>
+<translation id="5445120697129764393">还剩<ph name="NUMBER_DEFAULT"/>秒</translation>
+<translation id="8226233771743600312">1 天内请勿打扰</translation>
+<translation id="4252565523989510616">向后删除一个字</translation>
+<translation id="7457942297256758195">全部清除</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 天前</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> mins</translation>
+<translation id="1963692530539281474">还有 <ph name="NUMBER_DEFAULT"/> 天</translation>
+<translation id="6786750046913594791">关闭文件夹</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分钟</translation>
+<translation id="5906719743126878045"><ph name="NUMBER_TWO"/> hours left</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 小时前</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> secs</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> secs</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="3759876923365568382"><ph name="NUMBER_FEW"/> days left</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/s</translation>
+<translation id="2743387203779672305">复制到剪贴板</translation>
+<translation id="8371695176452482769">请开始说话</translation>
+<translation id="1167268268675672572">移至行首并更改选择范围</translation>
+<translation id="6965382102122355670">确定</translation>
+<translation id="7850320739366109486">请勿打扰</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">最小化</translation>
+<translation id="6394627529324717982">逗号</translation>
+<translation id="3036649622769666520">打开文件</translation>
+<translation id="8328145009876646418">左边缘</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
new file mode 100644
index 00000000000..bffb3685045
--- /dev/null
+++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
@@ -0,0 +1,221 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+<translation id="4820616160060340806">Command + <ph name="KEY_COMBO_NAME"/> 鍵</translation>
+<translation id="8806053966018712535"><ph name="FOLDER_NAME"/>資料夾</translation>
+<translation id="1871244248791675517">Ins</translation>
+<translation id="6135826906199951471">Del</translation>
+<translation id="528468243742722775">結束</translation>
+<translation id="5341849548509163798"><ph name="NUMBER_MANY"/> 小時前</translation>
+<translation id="6310545596129886942">剩下 <ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="9213479837033539041">剩下 <ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="1209866192426315618">剩下 <ph name="NUMBER_DEFAULT"/> 分鐘</translation>
+<translation id="1801827354178857021">期間</translation>
+<translation id="1190609913194133056">通知中心</translation>
+<translation id="7470933019269157899">剩下 <ph name="NUMBER_DEFAULT"/> 分鐘</translation>
+<translation id="5613020302032141669">向左鍵</translation>
+<translation id="4971687151119236543">上一首媒體曲目</translation>
+<translation id="8602707065186045623"><ph name="SAVEAS_EXTENSION_TYPE"/> 檔案 (.<ph name="SAVEAS_EXTENSION_NAME"/>)</translation>
+<translation id="542155483965056918"><ph name="NUMBER_ZERO"/> mins ago</translation>
+<translation id="7121570032414343252"><ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="7511635910912978956">剩下 <ph name="NUMBER_FEW"/> 小時</translation>
+<translation id="5948410903763073882">Alt+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7658239707568436148">取消</translation>
+<translation id="7222373446505536781">F11</translation>
+<translation id="1761785978543082658"><ph name="QUANTITY"/> B</translation>
+<translation id="3660179305079774227">向上鍵</translation>
+<translation id="3969863827134279083">上移</translation>
+<translation id="7062130397825382308">剩下 <ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="1809410197924942083"><ph name="QUANTITY"/> MB/秒</translation>
+<translation id="5608669887400696928"><ph name="NUMBER_DEFAULT"/> 小時</translation>
+<translation id="3990502903496589789">右邊緣</translation>
+<translation id="9038489124413477075">未命名的資料夾</translation>
+<translation id="1940483897317142625">刪除到行尾</translation>
+<translation id="8507996248087185956"><ph name="NUMBER_DEFAULT"/> 分鐘</translation>
+<translation id="3520476450377425184">剩下 <ph name="NUMBER_MANY"/> 天</translation>
+<translation id="932327136139879170">首頁</translation>
+<translation id="5600907569873192868">剩下 <ph name="NUMBER_MANY"/> 分鐘</translation>
+<translation id="8666066831007952346">剩下 <ph name="NUMBER_TWO"/> 天</translation>
+<translation id="6390842777729054533">剩下 <ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="3909791450649380159">剪下(&amp;T)</translation>
+<translation id="2560788951337264832">剩下 <ph name="NUMBER_ZERO"/> 分鐘</translation>
+<translation id="688711909580084195">無標題網頁</translation>
+<translation id="3353284378027041011"><ph name="NUMBER_FEW"/> 天前</translation>
+<translation id="5076340679995252485">貼上(&amp;P)</translation>
+<translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
+<translation id="7139614227326422685">右移到文字分行</translation>
+<translation id="364720409959344976">選取要上傳的資料夾</translation>
+<translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="7770995925463083016"><ph name="NUMBER_TWO"/> 分鐘前</translation>
+<translation id="3234408098842461169">向下鍵</translation>
+<translation id="3087734570205094154">置底</translation>
+<translation id="8828991073132329143">剩下 <ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="5935630983280450497">剩下 <ph name="NUMBER_ONE"/> 分鐘</translation>
+<translation id="1860796786778352021">通知關閉</translation>
+<translation id="6364916375976753737">向左捲動</translation>
+<translation id="2629089419211541119"><ph name="NUMBER_ONE"/> 小時前</translation>
+<translation id="4218160142017529598">向後刪除</translation>
+<translation id="2994641463185352298"><ph name="NUMBER_DEFAULT"/> 分鐘</translation>
+<translation id="6982279413068714821"><ph name="NUMBER_DEFAULT"/> 分鐘前</translation>
+<translation id="6945221475159498467">選取</translation>
+<translation id="6620110761915583480">儲存檔案</translation>
+<translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="8924469368910458384">刪除到行首</translation>
+<translation id="6719684875142564568"><ph name="NUMBER_ZERO"/> hours</translation>
+<translation id="7836361698254323868">剩下 <ph name="NUMBER_ONE"/> 分鐘</translation>
+<translation id="2953767478223974804"><ph name="NUMBER_ONE"/> 分鐘</translation>
+<translation id="8210608804940886430">向下翻頁</translation>
+<translation id="1572103024875503863"><ph name="NUMBER_MANY"/> 天</translation>
+<translation id="7163503212501929773">剩下 <ph name="NUMBER_MANY"/> 小時</translation>
+<translation id="5329858601952122676">刪除(&amp;D)</translation>
+<translation id="6556866813142980365">重做</translation>
+<translation id="8088823334188264070"><ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="8901569739625249689"><ph name="QUANTITY"/> KB</translation>
+<translation id="7712011264267466734"><ph name="NUMBER_MANY"/> 分鐘</translation>
+<translation id="7275974018215686543"><ph name="NUMBER_MANY"/> 秒前</translation>
+<translation id="7781829728241885113">昨天</translation>
+<translation id="3424538384153559412"><ph name="NUMBER_TWO"/> 分鐘</translation>
+<translation id="50960180632766478">剩下 <ph name="NUMBER_FEW"/> 分鐘</translation>
+<translation id="5517291721709019259">剩下 <ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="6903282483217634857">右移</translation>
+<translation id="6659594942844771486">Tab</translation>
+<translation id="3049748772180311791"><ph name="QUANTITY"/> MB</translation>
+<translation id="4988273303304146523"><ph name="NUMBER_DEFAULT"/> 天前</translation>
+<translation id="8428213095426709021">設定</translation>
+<translation id="2497284189126895209">所有檔案</translation>
+<translation id="7487278341251176613">剩下 <ph name="NUMBER_TWO"/> 分鐘</translation>
+<translation id="5110450810124758964"><ph name="NUMBER_ONE"/> 天前</translation>
+<translation id="2820806154655529776"><ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="4320177379694898372">沒有網際網路連線</translation>
+<translation id="7814458197256864873">複製(&amp;C)</translation>
+<translation id="3889424535448813030">向右鍵</translation>
+<translation id="4229495110203539533"><ph name="NUMBER_ONE"/> 秒前</translation>
+<translation id="2544782972264605588">剩下 <ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="6829324100069873704">返回通知</translation>
+<translation id="6528179044667508675">請勿打擾</translation>
+<translation id="5066177358602611309"><ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="290555789621781773"><ph name="NUMBER_TWO"/> 分鐘</translation>
+<translation id="5149131957118398098"><ph name="NUMBER_ZERO"/> hours left</translation>
+<translation id="7135556860107312402">允許接收下列來源發出的通知:</translation>
+<translation id="2479520428668657293">右移並修改選取範圍</translation>
+<translation id="8112886015144590373"><ph name="NUMBER_FEW"/> 小時</translation>
+<translation id="1398853756734560583">放到最大</translation>
+<translation id="4250229828105606438">螢幕擷取畫面</translation>
+<translation id="6690744523875189208"><ph name="NUMBER_TWO"/> 小時</translation>
+<translation id="5260878308685146029">剩下 <ph name="NUMBER_TWO"/> 分鐘</translation>
+<translation id="2557207087669398617">移到行首</translation>
+<translation id="3757388668994797779"><ph name="QUANTITY"/> GB</translation>
+<translation id="1901303067676059328">選取全部(&amp;A)</translation>
+<translation id="2168039046890040389">向上翻頁</translation>
+<translation id="7363290921156020669"><ph name="NUMBER_ZERO"/> mins</translation>
+<translation id="9107059250669762581"><ph name="NUMBER_DEFAULT"/> 天</translation>
+<translation id="6463061331681402734"><ph name="NUMBER_MANY"/> 分鐘</translation>
+<translation id="6122334925474904337">右移到文字分行並修改選取範圍</translation>
+<translation id="7634624804467787019"><ph name="NUMBER_ONE"/> 分鐘</translation>
+<translation id="8448317557906454022"><ph name="NUMBER_ZERO"/> 秒前</translation>
+<translation id="4927753642311223124">這裡沒有任何通知訊息,以後再來看看吧!</translation>
+<translation id="2482878487686419369">通知</translation>
+<translation id="6357135709975569075"><ph name="NUMBER_ZERO"/> days</translation>
+<translation id="3183922693828471536">捲動至此</translation>
+<translation id="4552416320897244156">PgDwn</translation>
+<translation id="3066573403916685335">下移</translation>
+<translation id="7052633198403197513">F1 鍵</translation>
+<translation id="2052389551707911401"><ph name="NUMBER_MANY"/> 小時</translation>
+<translation id="8677655579646609597"><ph name="QUANTITY"/> KB/秒</translation>
+<translation id="8394908167088220973">媒體播放/暫停</translation>
+<translation id="2148716181193084225">今天</translation>
+<translation id="7960078400008666149">1 小時內請勿打擾</translation>
+<translation id="4373894838514502496"><ph name="NUMBER_FEW"/> 分鐘前</translation>
+<translation id="4115153316875436289"><ph name="NUMBER_TWO"/> 天</translation>
+<translation id="2190355936436201913">(空白)</translation>
+<translation id="1164369517022005061">剩下 <ph name="NUMBER_DEFAULT"/> 小時</translation>
+<translation id="152482086482215392">剩下 <ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="8447116497070723931">PgUp</translation>
+<translation id="4588090240171750605">向右捲動</translation>
+<translation id="7414887922320653780">剩下 <ph name="NUMBER_ONE"/> 小時</translation>
+<translation id="1413622004203049571">停用「<ph name="NOTIFIER_NAME"/>」的通知</translation>
+<translation id="2666092431469916601">置頂</translation>
+<translation id="2538759511191347839">移到行尾並修改選取範圍</translation>
+<translation id="928465423150706909">移到行尾</translation>
+<translation id="8331626408530291785">向上捲動</translation>
+<translation id="7907591526440419938">開啟檔案</translation>
+<translation id="2864069933652346933"><ph name="NUMBER_ZERO"/> days left</translation>
+<translation id="2803313416453193357">開啟資料夾</translation>
+<translation id="1293699935367580298">Esc</translation>
+<translation id="2797524280730715045"><ph name="NUMBER_DEFAULT"/> 小時前</translation>
+<translation id="815598010540052116">向下捲動</translation>
+<translation id="6808150112686056157">停止媒體播放</translation>
+<translation id="1308727876662951186"><ph name="NUMBER_ZERO"/> mins left</translation>
+<translation id="3157931365184549694">還原</translation>
+<translation id="5349525451964472598">左移並修改選取範圍</translation>
+<translation id="1781701194097416995">左移到文字分行</translation>
+<translation id="1243314992276662751">上傳</translation>
+<translation id="50030952220075532">剩下 <ph name="NUMBER_ONE"/> 天</translation>
+<translation id="8179976553408161302">Enter</translation>
+<translation id="8471049483003785219">左移到文字分行並修改選取範圍</translation>
+<translation id="945522503751344254">提供意見</translation>
+<translation id="9170848237812810038">取消(&amp;U)</translation>
+<translation id="1285266685456062655"><ph name="NUMBER_FEW"/> 小時前</translation>
+<translation id="6918245111648057970">允許接收下列使用者發出的通知:</translation>
+<translation id="5489830104927132166"><ph name="NUMBER_ONE"/> 秒</translation>
+<translation id="1270251962578273213">剩下 <ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="3994835489895548312">剩下 <ph name="NUMBER_MANY"/> 分鐘</translation>
+<translation id="6358975074282722691"><ph name="NUMBER_TWO"/> 秒前</translation>
+<translation id="520299402983819650"><ph name="QUANTITY"/> PB</translation>
+<translation id="2983818520079887040">設定...</translation>
+<translation id="6845383723252244143">選取資料夾</translation>
+<translation id="7600770490873519066"><ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="5368780922436099921">剩下 <ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="1095623615273566396"><ph name="NUMBER_FEW"/> 秒</translation>
+<translation id="5583640892426849032">Backspace 鍵</translation>
+<translation id="5263972071113911534"><ph name="NUMBER_MANY"/> 天前</translation>
+<translation id="8355915647418390920"><ph name="NUMBER_FEW"/> 天</translation>
+<translation id="5116333507878097773"><ph name="NUMBER_ONE"/> 小時</translation>
+<translation id="2679312662830811292"><ph name="NUMBER_ONE"/> 分鐘前</translation>
+<translation id="8788572795284305350"><ph name="NUMBER_ZERO"/> hours ago</translation>
+<translation id="3740362395218339114"><ph name="QUANTITY"/> GB/秒</translation>
+<translation id="6644971472240498405"><ph name="NUMBER_ONE"/> 天</translation>
+<translation id="2704295676501803339">左移</translation>
+<translation id="9098468523912235228"><ph name="NUMBER_DEFAULT"/> 秒前</translation>
+<translation id="494645311413743213">剩下 <ph name="NUMBER_TWO"/> 秒</translation>
+<translation id="566737009157135450">向後刪除文字</translation>
+<translation id="436869212180315161">按下</translation>
+<translation id="4860787810836767172"><ph name="NUMBER_FEW"/> 秒前</translation>
+<translation id="2297836609126180313"><ph name="QUANTITY"/> TB/秒</translation>
+<translation id="6956540737482608074"><ph name="NUMBER_ZERO"/> 分鐘</translation>
+<translation id="1858722859751911017">剩下 <ph name="NUMBER_FEW"/> 分鐘</translation>
+<translation id="6040143037577758943">關閉</translation>
+<translation id="1101671447232096497"><ph name="NUMBER_MANY"/> 分鐘前</translation>
+<translation id="6142413573757616983"><ph name="QUANTITY"/> B/秒</translation>
+<translation id="7649070708921625228">說明</translation>
+<translation id="2405367043325750948">向前刪除</translation>
+<translation id="6699343763173986273">下一首媒體曲目</translation>
+<translation id="5445120697129764393">剩下 <ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="8226233771743600312">1 天內請勿打擾</translation>
+<translation id="4252565523989510616">向前刪除文字</translation>
+<translation id="7457942297256758195">全部清除</translation>
+<translation id="822618367988303761"><ph name="NUMBER_TWO"/> 天前</translation>
+<translation id="4745438305783437565"><ph name="NUMBER_FEW"/> 分鐘</translation>
+<translation id="1963692530539281474">剩下 <ph name="NUMBER_DEFAULT"/> 天</translation>
+<translation id="6786750046913594791">關閉資料夾</translation>
+<translation id="7509440305564869263"><ph name="NUMBER_FEW"/> 分鐘</translation>
+<translation id="5906719743126878045">剩下 <ph name="NUMBER_TWO"/> 小時</translation>
+<translation id="8959208747503200525"><ph name="NUMBER_TWO"/> 小時前</translation>
+<translation id="8400147561352026160">Shift+<ph name="KEY_COMBO_NAME"/></translation>
+<translation id="8421864404045570940"><ph name="NUMBER_DEFAULT"/> 秒</translation>
+<translation id="4197700912384709145"><ph name="NUMBER_ZERO"/> 秒</translation>
+<translation id="27199337101878275"><ph name="NUMBER_MANY"/> 秒</translation>
+<translation id="3759876923365568382">剩下 <ph name="NUMBER_FEW"/> 天</translation>
+<translation id="6907759265145635167"><ph name="QUANTITY"/> PB/秒</translation>
+<translation id="2743387203779672305">複製到剪貼簿</translation>
+<translation id="8371695176452482769">請說話</translation>
+<translation id="1167268268675672572">移到行首並修改選取範圍</translation>
+<translation id="6965382102122355670">確定</translation>
+<translation id="7850320739366109486">請勿打擾</translation>
+<translation id="6978839998405419496"><ph name="NUMBER_ZERO"/> days ago</translation>
+<translation id="5941711191222866238">縮到最小</translation>
+<translation id="6394627529324717982">逗號</translation>
+<translation id="3036649622769666520">開啟檔案</translation>
+<translation id="8328145009876646418">左邊緣</translation>
+<translation id="7372005818821648611"><ph name="NUMBER_TWO"/> 秒</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd
new file mode 100644
index 00000000000..78c33613c6f
--- /dev/null
+++ b/chromium/ui/strings/ui_strings.grd
@@ -0,0 +1,2198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file contains definitions of resources that will be translated for
+each locale. Specifically, these are UI strings that are used by app/ that
+need to be translated for each locale.-->
+
+<grit base_dir="." latest_public_release="0" current_release="1"
+ source_lang_id="en" enc_check="möl">
+ <outputs>
+ <!-- TODO add each of your output files. Modify the three below, and add
+ your own for your various languages. See the user's guide
+ (http://wiki/Main/GritUsersGuide) for more details.
+ Note that all output references are relative to the output directory
+ which is specified at build time. -->
+ <output filename="grit/ui_strings.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="ui_strings_am.pak" type="data_package" lang="am" />
+ <output filename="ui_strings_ar.pak" type="data_package" lang="ar" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_ast.pak" type="data_package" lang="ast" />
+ </if>
+ <output filename="ui_strings_bg.pak" type="data_package" lang="bg" />
+ <output filename="ui_strings_bn.pak" type="data_package" lang="bn" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_bs.pak" type="data_package" lang="bs" />
+ </if>
+ <output filename="ui_strings_ca.pak" type="data_package" lang="ca" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
+ </if>
+ <output filename="ui_strings_cs.pak" type="data_package" lang="cs" />
+ <output filename="ui_strings_da.pak" type="data_package" lang="da" />
+ <output filename="ui_strings_de.pak" type="data_package" lang="de" />
+ <output filename="ui_strings_el.pak" type="data_package" lang="el" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_en-AU.pak" type="data_package" lang="en-AU" />
+ </if>
+ <output filename="ui_strings_en-GB.pak" type="data_package" lang="en-GB" />
+ <output filename="ui_strings_en-US.pak" type="data_package" lang="en" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_eo.pak" type="data_package" lang="eo" />
+ </if>
+ <output filename="ui_strings_es.pak" type="data_package" lang="es" />
+ <if expr="is_ios">
+ <!-- iOS uses es-MX for es-419 -->
+ <output filename="ui_strings_es-MX.pak" type="data_package" lang="es-419" />
+ </if>
+ <if expr="not is_ios">
+ <output filename="ui_strings_es-419.pak" type="data_package" lang="es-419" />
+ </if>
+ <output filename="ui_strings_et.pak" type="data_package" lang="et" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_eu.pak" type="data_package" lang="eu" />
+ </if>
+ <output filename="ui_strings_fa.pak" type="data_package" lang="fa" />
+ <output filename="ui_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
+ <output filename="ui_strings_fi.pak" type="data_package" lang="fi" />
+ <output filename="ui_strings_fil.pak" type="data_package" lang="fil" />
+ <output filename="ui_strings_fr.pak" type="data_package" lang="fr" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_gl.pak" type="data_package" lang="gl" />
+ </if>
+ <output filename="ui_strings_gu.pak" type="data_package" lang="gu" />
+ <output filename="ui_strings_he.pak" type="data_package" lang="he" />
+ <output filename="ui_strings_hi.pak" type="data_package" lang="hi" />
+ <output filename="ui_strings_hr.pak" type="data_package" lang="hr" />
+ <output filename="ui_strings_hu.pak" type="data_package" lang="hu" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_hy.pak" type="data_package" lang="hy" />
+ <output filename="ui_strings_ia.pak" type="data_package" lang="ia" />
+ </if>
+ <output filename="ui_strings_id.pak" type="data_package" lang="id" />
+ <output filename="ui_strings_it.pak" type="data_package" lang="it" />
+ <output filename="ui_strings_ja.pak" type="data_package" lang="ja" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_ka.pak" type="data_package" lang="ka" />
+ </if>
+ <output filename="ui_strings_kn.pak" type="data_package" lang="kn" />
+ <output filename="ui_strings_ko.pak" type="data_package" lang="ko" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_ku.pak" type="data_package" lang="ku" />
+ <output filename="ui_strings_kw.pak" type="data_package" lang="kw" />
+ </if>
+ <output filename="ui_strings_lt.pak" type="data_package" lang="lt" />
+ <output filename="ui_strings_lv.pak" type="data_package" lang="lv" />
+ <output filename="ui_strings_ml.pak" type="data_package" lang="ml" />
+ <output filename="ui_strings_mr.pak" type="data_package" lang="mr" />
+ <output filename="ui_strings_ms.pak" type="data_package" lang="ms" />
+ <output filename="ui_strings_nl.pak" type="data_package" lang="nl" />
+ <!-- The translation console uses 'no' for Norwegian Bokmål. It should
+ be 'nb'. -->
+ <output filename="ui_strings_nb.pak" type="data_package" lang="no" />
+ <output filename="ui_strings_pl.pak" type="data_package" lang="pl" />
+ <if expr="is_ios">
+ <!-- iOS uses pt for pt-BR -->
+ <output filename="ui_strings_pt.pak" type="data_package" lang="pt-BR" />
+ </if>
+ <if expr="not is_ios">
+ <output filename="ui_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
+ </if>
+ <output filename="ui_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
+ <output filename="ui_strings_ro.pak" type="data_package" lang="ro" />
+ <output filename="ui_strings_ru.pak" type="data_package" lang="ru" />
+ <output filename="ui_strings_sk.pak" type="data_package" lang="sk" />
+ <output filename="ui_strings_sl.pak" type="data_package" lang="sl" />
+ <output filename="ui_strings_sr.pak" type="data_package" lang="sr" />
+ <output filename="ui_strings_sv.pak" type="data_package" lang="sv" />
+ <output filename="ui_strings_sw.pak" type="data_package" lang="sw" />
+ <output filename="ui_strings_ta.pak" type="data_package" lang="ta" />
+ <output filename="ui_strings_te.pak" type="data_package" lang="te" />
+ <output filename="ui_strings_th.pak" type="data_package" lang="th" />
+ <output filename="ui_strings_tr.pak" type="data_package" lang="tr" />
+ <if expr="use_third_party_translations">
+ <output filename="ui_strings_ug.pak" type="data_package" lang="ug" />
+ </if>
+ <output filename="ui_strings_uk.pak" type="data_package" lang="uk" />
+ <output filename="ui_strings_vi.pak" type="data_package" lang="vi" />
+ <output filename="ui_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
+ <output filename="ui_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
+ </outputs>
+ <translations>
+ <file path="translations/ui_strings_am.xtb" lang="am" />
+ <file path="translations/ui_strings_ar.xtb" lang="ar" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_ast.xtb" lang="ast" />
+ </if>
+ <file path="translations/ui_strings_bg.xtb" lang="bg" />
+ <file path="translations/ui_strings_bn.xtb" lang="bn" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_bs.xtb" lang="bs" />
+ </if>
+ <file path="translations/ui_strings_ca.xtb" lang="ca" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_ca-valencia.xtb" lang="ca@valencia" />
+ </if>
+ <file path="translations/ui_strings_cs.xtb" lang="cs" />
+ <file path="translations/ui_strings_da.xtb" lang="da" />
+ <file path="translations/ui_strings_de.xtb" lang="de" />
+ <file path="translations/ui_strings_el.xtb" lang="el" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_en-AU.xtb" lang="en-AU" />
+ </if>
+ <file path="translations/ui_strings_en-GB.xtb" lang="en-GB" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_eo.xtb" lang="eo" />
+ </if>
+ <file path="translations/ui_strings_es.xtb" lang="es" />
+ <file path="translations/ui_strings_es-419.xtb" lang="es-419" />
+ <file path="translations/ui_strings_et.xtb" lang="et" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_eu.xtb" lang="eu" />
+ </if>
+ <file path="translations/ui_strings_fa.xtb" lang="fa" />
+ <file path="translations/ui_strings_fi.xtb" lang="fi" />
+ <file path="translations/ui_strings_fil.xtb" lang="fil" />
+ <file path="translations/ui_strings_fr.xtb" lang="fr" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_gl.xtb" lang="gl" />
+ </if>
+ <file path="translations/ui_strings_gu.xtb" lang="gu" />
+ <file path="translations/ui_strings_hi.xtb" lang="hi" />
+ <file path="translations/ui_strings_hr.xtb" lang="hr" />
+ <file path="translations/ui_strings_hu.xtb" lang="hu" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_hy.xtb" lang="hy" />
+ <file path="../../third_party/launchpad_translations/ui_strings_ia.xtb" lang="ia" />
+ </if>
+ <file path="translations/ui_strings_id.xtb" lang="id" />
+ <file path="translations/ui_strings_it.xtb" lang="it" />
+ <!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
+ <file path="translations/ui_strings_iw.xtb" lang="he" />
+ <file path="translations/ui_strings_ja.xtb" lang="ja" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_ka.xtb" lang="ka" />
+ </if>
+ <file path="translations/ui_strings_kn.xtb" lang="kn" />
+ <file path="translations/ui_strings_ko.xtb" lang="ko" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_ku.xtb" lang="ku" />
+ <file path="../../third_party/launchpad_translations/ui_strings_kw.xtb" lang="kw" />
+ </if>
+ <file path="translations/ui_strings_lt.xtb" lang="lt" />
+ <file path="translations/ui_strings_lv.xtb" lang="lv" />
+ <file path="translations/ui_strings_ml.xtb" lang="ml" />
+ <file path="translations/ui_strings_mr.xtb" lang="mr" />
+ <file path="translations/ui_strings_ms.xtb" lang="ms" />
+ <file path="translations/ui_strings_nl.xtb" lang="nl" />
+ <file path="translations/ui_strings_no.xtb" lang="no" />
+ <file path="translations/ui_strings_pl.xtb" lang="pl" />
+ <file path="translations/ui_strings_pt-BR.xtb" lang="pt-BR" />
+ <file path="translations/ui_strings_pt-PT.xtb" lang="pt-PT" />
+ <file path="translations/ui_strings_ro.xtb" lang="ro" />
+ <file path="translations/ui_strings_ru.xtb" lang="ru" />
+ <file path="translations/ui_strings_sk.xtb" lang="sk" />
+ <file path="translations/ui_strings_sl.xtb" lang="sl" />
+ <file path="translations/ui_strings_sr.xtb" lang="sr" />
+ <file path="translations/ui_strings_sv.xtb" lang="sv" />
+ <file path="translations/ui_strings_sw.xtb" lang="sw" />
+ <file path="translations/ui_strings_ta.xtb" lang="ta" />
+ <file path="translations/ui_strings_te.xtb" lang="te" />
+ <file path="translations/ui_strings_th.xtb" lang="th" />
+ <file path="translations/ui_strings_tr.xtb" lang="tr" />
+ <if expr="use_third_party_translations">
+ <file path="../../third_party/launchpad_translations/ui_strings_ug.xtb" lang="ug" />
+ </if>
+ <file path="translations/ui_strings_uk.xtb" lang="uk" />
+ <file path="translations/ui_strings_vi.xtb" lang="vi" />
+ <file path="translations/ui_strings_zh-CN.xtb" lang="zh-CN" />
+ <file path="translations/ui_strings_zh-TW.xtb" lang="zh-TW" />
+ </translations>
+ <release seq="1" allow_pseudo="false">
+ <messages fallback_to_english="true">
+
+ <!-- time format -->
+ <message name="IDS_TIME_SECS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_SECS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_SECS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_SECS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_SECS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_SECS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_SECS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_SECS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_SECS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_SECS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_SECS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_LONG_SECS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_LONG_SECS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_LONG_SECS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_SECS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_SECS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_LONG_SECS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_LONG_SECS_2ND_DEFAULT"
+ desc="Second part of 'xx minutes yy seconds' time format. This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_LONG_SECS_2ND_SINGULAR"
+ desc="Second part of 'xx minutes yy seconds' time format where yy (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_2NDS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_LONG_SECS_2ND_ZERO"
+ desc="Second part of 'xx minutes yy seconds' time format where yy (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_2ND_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_SECS_2ND_TWO"
+ desc="Second part of 'xx minutes yy seconds' time format where yy (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_2ND_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_SECS_2ND_FEW"
+ desc="Second part of 'xx minutes yy seconds' time format where yy (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_2ND_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_LONG_SECS_2ND_MANY"
+ desc="Second part of 'xx minutes yy seconds' time format where yy (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_LONG_SECS_2ND_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_MINS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_MINS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_MINS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_MINS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_MINS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_MINS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_MINS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_MINS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_MINS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_MINS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_MINS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_LONG_MINS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_LONG_MINS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_LONG_MINS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_LONG_MINS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_LONG_MINS_1ST_DEFAULT"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there). This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes '''
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_LONG_MINS_1ST_SINGULAR"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute '''
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_1ST_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_LONG_MINS_1ST_ZERO"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes '''
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_1ST_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_1ST_TWO"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes '''
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_1ST_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_1ST_FEW"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes '''
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_1ST_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_LONG_MINS_1ST_MANY"
+ desc="First part of 'xx minutes yy seconds' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes '''
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_1ST_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_LONG_MINS_2ND_DEFAULT"
+ desc="Second part of 'xx hours yy minutes' time format. This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_LONG_MINS_2ND_SINGULAR"
+ desc="Second part of 'xx hours yy minutes' time format where yy (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_2ND_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_LONG_MINS_2ND_ZERO"
+ desc="Second part of 'xx hours yy minutes' time format where yy (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_2ND_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_2ND_TWO"
+ desc="Second part of 'xx hours yy minutes' time format where yy (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_2ND_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_LONG_MINS_2ND_FEW"
+ desc="Second part of 'xx hours yy minutes' time format where yy (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_2ND_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_LONG_MINS_2ND_MANY"
+ desc="Second part of 'xx hours yy minutes' time format where yy (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_LONG_MINS_2ND_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_HOURS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_HOURS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_HOURS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_HOURS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_HOURS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_HOURS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_HOURS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_HOURS_1ST_DEFAULT"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there). This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours '''
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_HOURS_1ST_SINGULAR"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour '''
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_HOURS_1ST_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_HOURS_1ST_ZERO"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours '''
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_HOURS_1ST_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_1ST_TWO"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours '''
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_1ST_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_1ST_FEW"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours '''
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_1ST_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_HOURS_1ST_MANY"
+ desc="First part of 'xx hours yy minutes' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours '''
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_HOURS_1ST_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_HOURS_2ND_DEFAULT"
+ desc="Second part of 'xx days yy hours' time format. This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_HOURS_2ND_SINGULAR"
+ desc="Second part of 'xx days yy hours' time format where yy (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_HOURS_2ND_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_HOURS_2ND_ZERO"
+ desc="Second part of 'xx days yy hours' time format where yy (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_HOURS_2ND_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_2ND_TWO"
+ desc="Second part of 'xx days yy hours' time format where yy (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_2ND_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_HOURS_2ND_FEW"
+ desc="Second part of 'xx days yy hours' time format where yy (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_HOURS_2ND_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_HOURS_2ND_MANY"
+ desc="Second part of 'xx days yy hours' time format where yy (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_HOURS_2ND_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_DAYS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_DAYS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_DAYS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_DAYS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_DAYS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_DAYS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_DAYS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_DAYS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_DAYS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_DAYS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_DAYS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_DAYS_1ST_DEFAULT"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there). This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days '''
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_DAYS_1ST_SINGULAR"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ONE) is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day '''
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_DAYS_1ST_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_DAYS_1ST_ZERO"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_ZERO) is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days '''
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_DAYS_1ST_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_DAYS_1ST_TWO"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_TWO) is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days '''
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_DAYS_1ST_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_DAYS_1ST_FEW"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_FEW) is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days '''
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_DAYS_1ST_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_DAYS_1ST_MANY"
+ desc="First part of 'xx days yy hours' time format (including the space between first and second part, if the language requires a space there) where xx (NUMBER_MANY) is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days '''
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_DAYS_1ST_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_REMAINING_SECS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_SECS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_SECS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_SECS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_SECS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_SECS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_REMAINING_LONG_SECS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_LONG_SECS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_SECS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_LONG_SECS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_SECS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_LONG_SECS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_SECS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_LONG_SECS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_SECS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_LONG_SECS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_SECS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_REMAINING_MINS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_MINS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_MINS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_MINS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_MINS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_MINS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_MINS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_MINS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_MINS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_MINS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_MINS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <message name="IDS_TIME_REMAINING_LONG_MINS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_LONG_MINS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_LONG_MINS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_LONG_MINS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_LONG_MINS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <message name="IDS_TIME_REMAINING_HOURS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_HOURS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_HOURS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_HOURS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_HOURS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_HOURS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_HOURS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_HOURS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_HOURS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_HOURS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_HOURS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_REMAINING_DAYS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days left
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_REMAINING_DAYS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day left
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_REMAINING_DAYS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_REMAINING_DAYS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days left
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_REMAINING_DAYS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_DAYS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days left
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_DAYS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_REMAINING_DAYS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days left
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_REMAINING_DAYS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_REMAINING_DAYS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days left
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_REMAINING_DAYS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <message name="IDS_TIME_ELAPSED_SECS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs ago
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_ELAPSED_SECS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec ago
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_SECS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_ELAPSED_SECS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs ago
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_SECS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_SECS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs ago
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_SECS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_SECS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs ago
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_SECS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_ELAPSED_SECS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs ago
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_ELAPSED_SECS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_ELAPSED_MINS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins ago
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_ELAPSED_MINS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min ago
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_MINS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_ELAPSED_MINS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins ago
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_MINS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_MINS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins ago
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_MINS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_MINS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins ago
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_MINS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_ELAPSED_MINS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins ago
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_ELAPSED_MINS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_ELAPSED_HOURS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours ago
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_ELAPSED_HOURS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour ago
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_ELAPSED_HOURS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours ago
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_HOURS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours ago
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_HOURS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours ago
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_ELAPSED_HOURS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours ago
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+
+ <message name="IDS_TIME_ELAPSED_DAYS_DEFAULT"
+ desc="This is necessary for every language. It is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11..19.">
+ <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days ago
+ </message>
+
+ <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message name="IDS_TIME_ELAPSED_DAYS_SINGULAR"
+ desc="NUMBER_ONE is a one or one-like number: 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1, 21, 31, ... (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, ... (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada.">
+ <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day ago
+ </message>
+ </if>
+ <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_SINGULAR"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ar', 'ro', 'lv']">
+ <message name="IDS_TIME_ELAPSED_DAYS_ZERO"
+ desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+ <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days ago
+ </message>
+ </if>
+ <if expr="lang not in ['ar', 'ro', 'lv']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_ZERO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ga', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_DAYS_TWO"
+ desc="NUMBER_TWO is a two or two-like/dual number: 2 (Arabic and Irish) or 2, 102, 202 ... (Slovenian). For other languages, do NOT translate.">
+ <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days ago
+ </message>
+ </if>
+ <if expr="lang not in ['ga', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_TWO"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message name="IDS_TIME_ELAPSED_DAYS_FEW"
+ desc="NUMBER_FEW is a few or few-like number in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+ <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days ago
+ </message>
+ </if>
+ <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+ <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_FEW"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <if expr="lang == 'ar'">
+ <message name="IDS_TIME_ELAPSED_DAYS_MANY"
+ desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+ <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days ago
+ </message>
+ </if>
+ <if expr="lang != 'ar'">
+ <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_MANY"
+ desc="">
+ NA
+ </message>
+ </if>
+
+ <message name="IDS_PAST_TIME_TODAY" desc="Relative day today">
+ Today
+ </message>
+ <message name="IDS_PAST_TIME_YESTERDAY" desc="Relative day yesterday">
+ Yesterday
+ </message>
+
+ <!-- Menus -->
+ <message name="IDS_APP_MENU_EMPTY_SUBMENU" desc="Used when a submenu has no entries">
+ (empty)
+ </message>
+
+ <!-- General application strings -->
+ <if expr="is_win or is_ios">
+ <message name="IDS_APP_UNTITLED_SHORTCUT_FILE_NAME" desc="The name of the Internet Shortcut file created for URLs dragged that have no title">
+ Untitled Webpage
+ </message>
+ </if>
+ <if expr="is_win">
+ <message name="IDS_APP_SAVEAS_ALL_FILES" desc="Save As dialog box default text">
+ All Files
+ </message>
+ <message name="IDS_APP_SAVEAS_EXTENSION_FORMAT" desc="Save As dialog box extension format text">
+ <ph name="SAVEAS_EXTENSION_TYPE">$1<ex>EXE</ex></ph> File (.<ph name="SAVEAS_EXTENSION_NAME">$2<ex>exe</ex></ph>)
+ </message>
+ </if>
+ <message name="IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE" desc="The default title for the Select Upload Folder dialog.">
+ Select Folder to Upload
+ </message>
+
+ <if expr="is_macosx">
+ <message name="IDS_SELECT_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog.">
+ Select
+ </message>
+ <message name="IDS_SELECT_UPLOAD_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog for uploading.">
+ Upload
+ </message>
+ </if>
+
+ <!-- File chooser dialog default titles (only used on Linux) -->
+ <message name="IDS_SELECT_FOLDER_DIALOG_TITLE" desc="The default title for the Select Folder file chooser dialog.">
+ Select Folder
+ </message>
+ <message name="IDS_SAVE_AS_DIALOG_TITLE" desc="The default title for the Save As file chooser dialog.">
+ Save File
+ </message>
+ <message name="IDS_OPEN_FILE_DIALOG_TITLE" desc="The default title for the Open File file chooser dialog (single file).">
+ Open File
+ </message>
+ <message name="IDS_OPEN_FILES_DIALOG_TITLE" desc="The default title for the Open File file chooser dialog (multiple files).">
+ Open Files
+ </message>
+ <message name="IDS_SAVEAS_ALL_FILES" desc="Save As dialog box default text">
+ All Files
+ </message>
+ <message name="IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON" desc="Button label text for Upload Folder dialog">
+ Upload
+ </message>
+
+ <!--Accessible name/action strings-->
+ <message name="IDS_APP_ACCACTION_PRESS" desc="The accessible default action for a button.">
+ Press
+ </message>
+ <message name="IDS_APP_ACCNAME_CLOSE" desc="The accessible name for the Close button.">
+ Close
+ </message>
+ <message name="IDS_APP_ACCNAME_MINIMIZE" desc="The accessible name for the Minimize button.">
+ Minimize
+ </message>
+ <message name="IDS_APP_ACCNAME_MAXIMIZE" desc="The accessible name for the Maximize button.">
+ Maximize
+ </message>
+ <message name="IDS_APP_ACCNAME_RESTORE" desc="The accessible name for the Restore button.">
+ Restore
+ </message>
+
+ <!-- Scroll Bar Context Menu Labels -->
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE" desc="The label for the 'Scroll Here' item">
+ Scroll to Here
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE" desc="The label for the 'Left Edge' item">
+ Left Edge
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE" desc="The label for the 'Right Edge' item">
+ Right Edge
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME" desc="The label for the 'Top' item">
+ Top
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLEND" desc="The label for the 'Bottom' item">
+ Bottom
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP" desc="The label for the 'Page Up' item">
+ Page Up
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN" desc="The label for the 'Page Down' item">
+ Page Down
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT" desc="The label for the 'Scroll Left' item">
+ Scroll Left
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT" desc="The label for the 'Scroll Left' item">
+ Scroll Right
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLUP" desc="The label for the 'Scroll Up' item">
+ Scroll Up
+ </message>
+ <message name="IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN" desc="The label for the 'Scroll Down' item">
+ Scroll Down
+ </message>
+
+ <!-- Textfield context menu item labels. -->
+ <message name="IDS_APP_UNDO" desc="The text label of the Undo menu item">
+ &amp;Undo
+ </message>
+ <message name="IDS_APP_CUT" desc="The text label of the Cut menu item">
+ Cu&amp;t
+ </message>
+ <message name="IDS_APP_COPY" desc="The text label of the Copy menu item">
+ &amp;Copy
+ </message>
+ <message name="IDS_APP_PASTE" desc="The text label of the Paste menu item">
+ &amp;Paste
+ </message>
+ <message name="IDS_APP_DELETE" desc="The text label of the Delete menu item">
+ &amp;Delete
+ </message>
+ <message name="IDS_APP_SELECT_ALL" desc="The text label of the Select All menu item">
+ Select &amp;all
+ </message>
+
+ <!-- Textfield editing commands; their actual string contents are unused. -->
+ <!-- These match third_party/WebKit/Source/core/editing/EditorCommand.cpp. -->
+ <message name="IDS_DELETE_BACKWARD" desc="A command to delete backward.">
+ Delete Backward
+ </message>
+ <message name="IDS_DELETE_FORWARD" desc="A command to delete forward.">
+ Delete Forward
+ </message>
+ <message name="IDS_DELETE_TO_BEGINNING_OF_LINE" desc="A command to delete to the beginning of the line.">
+ Delete To Beginning Of Line
+ </message>
+ <message name="IDS_DELETE_TO_END_OF_LINE" desc="A command to delete to the end of the line.">
+ Delete To End Of Line
+ </message>
+ <message name="IDS_DELETE_WORD_BACKWARD" desc="A command to delete backward by a word.">
+ Delete Word Backward
+ </message>
+ <message name="IDS_DELETE_WORD_FORWARD" desc="A command to delete forward by a word.">
+ Delete Word Forward
+ </message>
+ <message name="IDS_MOVE_DOWN" desc="A command to move the cursor down.">
+ Move Down
+ </message>
+ <message name="IDS_MOVE_LEFT" desc="A command to move the cursor left.">
+ Move Left
+ </message>
+ <message name="IDS_MOVE_LEFT_AND_MODIFY_SELECTION" desc="A command to move the cursor left and modify the selection.">
+ Move Left And Modify Selection
+ </message>
+ <message name="IDS_MOVE_RIGHT" desc="A command to move the cursor right.">
+ Move Right
+ </message>
+ <message name="IDS_MOVE_RIGHT_AND_MODIFY_SELECTION" desc="A command to move the cursor right and modify the selection.">
+ Move Right And Modify Selection
+ </message>
+ <message name="IDS_MOVE_WORD_LEFT" desc="A command to move the cursor left to the next word break.">
+ Move Word Left
+ </message>
+ <message name="IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION" desc="A command to move the cursor left to the next word break and modify the selection.">
+ Move Word Left And Modify Selection
+ </message>
+ <message name="IDS_MOVE_WORD_RIGHT" desc="A command to move the cursor right to the next word break.">
+ Move Word Right
+ </message>
+ <message name="IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION" desc="A command to move the cursor right to the next word break and modify the selection.">
+ Move Word Right And Modify Selection
+ </message>
+ <message name="IDS_MOVE_TO_BEGINNING_OF_LINE" desc="A command to move the cursor to the beginning of the line.">
+ Move To Beginning Of Line
+ </message>
+ <message name="IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION" desc="A command to move the cursor to the beginning of the line and modify the selection.">
+ Move To Beginning Of Line And Modify Selection
+ </message>
+ <message name="IDS_MOVE_TO_END_OF_LINE" desc="A command to move the cursor to the end of the line.">
+ Move To End Of Line
+ </message>
+ <message name="IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION" desc="A command to move the cursor to the end of the line and modify the selection.">
+ Move To End Of Line And Modify Selection
+ </message>
+ <message name="IDS_MOVE_UP" desc="A command to move the cursor up.">
+ Move Up
+ </message>
+ <message name="IDS_APP_REDO" desc="A command to redo an action.">
+ Redo
+ </message>
+
+ <!-- Generic terms -->
+ <message name="IDS_APP_OK" desc="Used for Ok on buttons">
+ OK
+ </message>
+ <message name="IDS_APP_CANCEL" desc="Used for Cancel on buttons">
+ Cancel
+ </message>
+ <message name="IDS_APP_CLOSE" desc="A generic term for Close on buttons and menus.">
+ Close
+ </message>
+
+ <!-- Key names -->
+ <message name="IDS_APP_ESC_KEY" desc="Escape key">
+ Esc
+ </message>
+ <message name="IDS_APP_TAB_KEY" desc="Tab key">
+ Tab
+ </message>
+ <message name="IDS_APP_INSERT_KEY" desc="Insert key">
+ Ins
+ </message>
+ <message name="IDS_APP_HOME_KEY" desc="Home key">
+ Home
+ </message>
+ <message name="IDS_APP_DELETE_KEY" desc="Delete key">
+ Del
+ </message>
+ <message name="IDS_APP_END_KEY" desc="End key">
+ End
+ </message>
+ <message name="IDS_APP_PAGEUP_KEY" desc="Page up key">
+ PgUp
+ </message>
+ <message name="IDS_APP_PAGEDOWN_KEY" desc="Page down key">
+ PgDwn
+ </message>
+ <message name="IDS_APP_LEFT_ARROW_KEY" desc="Left arrow key">
+ Left Arrow
+ </message>
+ <message name="IDS_APP_RIGHT_ARROW_KEY" desc="Right arrow key">
+ Right Arrow
+ </message>
+ <message name="IDS_APP_UP_ARROW_KEY" desc="Up arrow key">
+ Up Arrow
+ </message>
+ <message name="IDS_APP_DOWN_ARROW_KEY" desc="Down arrow key">
+ Down Arrow
+ </message>
+ <message name="IDS_APP_ENTER_KEY" desc="Enter key">
+ Enter
+ </message>
+ <message name="IDS_APP_F1_KEY" desc="F1 key">
+ F1
+ </message>
+ <message name="IDS_APP_F11_KEY" desc="F11 key">
+ F11
+ </message>
+ <message name="IDS_APP_BACKSPACE_KEY" desc="Backspace key">
+ Backspace
+ </message>
+ <message name="IDS_APP_COMMA_KEY" desc="Comma key">
+ Comma
+ </message>
+ <message name="IDS_APP_PERIOD_KEY" desc="Period key">
+ Period
+ </message>
+ <message name="IDS_APP_MEDIA_NEXT_TRACK_KEY" desc="Media next track key">
+ Media Next Track
+ </message>
+ <message name="IDS_APP_MEDIA_PLAY_PAUSE_KEY" desc="Media play pause key">
+ Media Play/Pause
+ </message>
+ <message name="IDS_APP_MEDIA_PREV_TRACK_KEY" desc="Media previous track key">
+ Media Previous Track
+ </message>
+ <message name="IDS_APP_MEDIA_STOP_KEY" desc="Media stop key">
+ Media Stop
+ </message>
+
+ <!-- Shortcut Modifiers -->
+ <message name="IDS_APP_CONTROL_MODIFIER" desc="Control key shortcut modifier">
+ Ctrl+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
+ </message>
+ <message name="IDS_APP_ALT_MODIFIER" desc="Alt key shortcut modifier">
+ Alt+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
+ </message>
+ <message name="IDS_APP_SHIFT_MODIFIER" desc="Shift key shortcut modifier">
+ Shift+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
+ </message>
+ <message name="IDS_APP_COMMAND_MODIFIER" desc="Command key shortcut modifier">
+ Command+<ph name="KEY_COMBO_NAME">$1<ex>C</ex></ph>
+ </message>
+
+ <!-- Byte size units -->
+ <message name="IDS_APP_BYTES" desc="Units tag indicating a quantity of bytes">
+ <ph name="QUANTITY">$1<ex>42</ex></ph> B
+ </message>
+ <message name="IDS_APP_KIBIBYTES" desc="Units tag indicating a quantity of kilobytes">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> KB
+ </message>
+ <message name="IDS_APP_MEBIBYTES" desc="Units tag indicating a quantity of megabytes">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> MB
+ </message>
+ <message name="IDS_APP_GIBIBYTES" desc="Units tag indicating a quantity of gigabytes">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> GB
+ </message>
+ <message name="IDS_APP_TEBIBYTES" desc="Units tag indicating a quantity of terabytes">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> TB
+ </message>
+ <message name="IDS_APP_PEBIBYTES" desc="Units tag indicating a quantity of petabytes">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> PB
+ </message>
+ <message name="IDS_APP_BYTES_PER_SECOND" desc="Units tag indicating a speed of bytes/second">
+ <ph name="QUANTITY">$1<ex>42</ex></ph> B/s
+ </message>
+ <message name="IDS_APP_KIBIBYTES_PER_SECOND" desc="Units tag indicating a speed of kilobytes/second">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> KB/s
+ </message>
+ <message name="IDS_APP_MEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of megabytes/second">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> MB/s
+ </message>
+ <message name="IDS_APP_GIBIBYTES_PER_SECOND" desc="Units tag indicating a speed of gigabytes/second">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> GB/s
+ </message>
+ <message name="IDS_APP_TEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of terabytes/second">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> TB/s
+ </message>
+ <message name="IDS_APP_PEBIBYTES_PER_SECOND" desc="Units tag indicating a speed of petabytes/second">
+ <ph name="QUANTITY">$1<ex>42.0</ex></ph> PB/s
+ </message>
+
+ <!-- Message center -->
+ <if expr="use_ash">
+ <message name="IDS_MESSAGE_CENTER_ACCESSIBLE_NAME" desc="The accessible name for the Notification Center window.">
+ Notification Center
+ </message>
+ </if>
+ <message name="IDS_MESSAGE_CENTER_NOTIFIER_DISABLE" desc="The menu entry for disabling a notifier from a notification.">
+ Disable notifications from <ph name="notifier_name">$1<ex>Notification Galore!</ex></ph>
+ </message>
+ <message name="IDS_MESSAGE_CENTER_FOOTER_TITLE" desc="The label in the footer of the message center">
+ Notifications
+ </message>
+ <message name="IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL" desc="The button label for visiting the appropriate settings page in the footer of the message center.">
+ Settings
+ </message>
+ <if expr="is_macosx">
+ <message name="IDS_MESSAGE_CENTER_SETTINGS_GO_BACK_BUTTON_TOOLTIP" desc="The tooltip on back button that returns from settings to the notification list.">
+ Go back to notifications
+ </message>
+ </if>
+ <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog.">
+ Allow notifications from the following:
+ </message>
+ <message name="IDS_MESSAGE_CENTER_SETTINGS_DESCRIPTION_MULTIUSER" desc="The label to describe the settings dialog if there is more than one user.">
+ Allow notifications from the following for each user:
+ </message>
+ <message name="IDS_MESSAGE_CENTER_SETTINGS" desc="The menu entry or button for visiting the appropriate settings page.">
+ Settings...
+ </message>
+ <message name="IDS_MESSAGE_CENTER_CLEAR_ALL" desc="The button for clearing all notifications.">
+ Clear All
+ </message>
+ <if expr="not use_titlecase">
+ <message name="IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP" desc="The tooltip text for the do not disturb button.">
+ Do not disturb
+ </message>
+ </if>
+ <if expr="use_titlecase">
+ <message name="IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP" desc="In Title Case: The tooltip text for the do not disturb button.">
+ Do Not Disturb
+ </message>
+ </if>
+ <message name="IDS_MESSAGE_CENTER_NO_MESSAGES" desc="The message displayed in the message center when there are no notifications.">
+ Nothing to see here, move along.
+ </message>
+ <message name="IDS_MESSAGE_CENTER_QUIET_MODE" desc="The button label for do not disturb mode.">
+ Do not disturb
+ </message>
+ <message name="IDS_MESSAGE_CENTER_QUIET_MODE_1HOUR" desc="The button label to enter do not disturb mode in one hour.">
+ Do not disturb for one hour
+ </message>
+ <message name="IDS_MESSAGE_CENTER_QUIET_MODE_1DAY" desc="The button label to enter do not disturb mode in one day.">
+ Do not disturb for one day
+ </message>
+ <message name="IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME" desc="The spoken feedback text for the close button in a notification. Usually 'button' is suffixed to this text automatically.">
+ Notification close
+ </message>
+ <if expr="chromeos">
+ <message name="IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME" desc="The name of screenshot notifier that is a system component">
+ Screenshot
+ </message>
+ <message name="IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_COPY_SCREENSHOT_TO_CLIPBOARD" desc="The button label for the screenshot notification which copies the screenshot image to clipboard on click.">
+ Copy to clipboard
+ </message>
+ </if>
+
+ <!-- App list -->
+ <message name="IDS_APP_LIST_HELP" desc="The menu entry to show the app list help UI.">
+ Help
+ </message>
+ <message name="IDS_APP_LIST_OPEN_SETTINGS" desc="The menu entry to show the settings UI.">
+ Settings
+ </message>
+ <message name="IDS_APP_LIST_OPEN_FEEDBACK" desc="The menu entry to show the feedback UI.">
+ Send feedback
+ </message>
+ <message name="IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER" desc="The placeholder text for app list folder name.">
+ Unnamed Folder
+ </message>
+ <message name="IDS_APP_LIST_FOLDER_BUTTON_ACCESSIBILE_NAME" desc="The spoken feedback text for navigating to a folder button in top level app list">
+ Folder <ph name="folder_name">$1<ex>OEM Apps</ex></ph>
+ </message>
+ <message name="IDS_APP_LIST_FOLDER_OPEN_FOLDER_ACCESSIBILE_NAME" desc="The spoken feedback text for opening an app launcher folder">
+ Open folder
+ </message>
+ <message name="IDS_APP_LIST_FOLDER_CLOSE_FOLDER_ACCESSIBILE_NAME" desc="The spoken feedback text for closing an app launcher folder">
+ Close folder
+ </message>
+ <message name="IDS_APP_LIST_SPEECH_HINT_TEXT" desc="The text label in the speech recognition UI to ask the user to speak the search query">
+ Speak now
+ </message>
+ <message name="IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT" desc="The text label in the speech recognition UI to show the speech recognition can't start because of network error.">
+ No internet connection
+ </message>
+ </messages>
+ </release>
+</grit>
diff --git a/chromium/ui/strings/ui_strings.gyp b/chromium/ui/strings/ui_strings.gyp
new file mode 100644
index 00000000000..02ae903d16d
--- /dev/null
+++ b/chromium/ui/strings/ui_strings.gyp
@@ -0,0 +1,40 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ 'grit_base_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui',
+ },
+ 'targets': [
+ {
+ 'target_name': 'ui_strings',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'ui_strings',
+ 'variables': {
+ 'grit_grd_file': 'ui_strings.grd',
+ 'grit_out_dir': '<(grit_base_out_dir)/ui_strings',
+ },
+ 'includes': [ '../../build/grit_action.gypi' ],
+ },
+ {
+ 'action_name': 'app_locale_settings',
+ 'variables': {
+ 'grit_grd_file': 'app_locale_settings.grd',
+ 'grit_out_dir': '<(grit_base_out_dir)/app_locale_settings',
+ },
+ 'includes': [ '../../build/grit_action.gypi' ],
+ },
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(grit_base_out_dir)/app_locale_settings',
+ '<(grit_base_out_dir)/ui_strings',
+ ],
+ },
+ },
+ ],
+}
diff --git a/chromium/ui/surface/BUILD.gn b/chromium/ui/surface/BUILD.gn
new file mode 100644
index 00000000000..3b25e0eae06
--- /dev/null
+++ b/chromium/ui/surface/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+component("surface") {
+ sources = [
+ "accelerated_surface_mac.cc",
+ "accelerated_surface_mac.h",
+ "surface_export.h",
+ "transport_dib.cc",
+ "transport_dib.h",
+ "transport_dib_posix.cc",
+ "transport_dib_win.cc",
+ ]
+
+ defines = [ "SURFACE_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/base",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ ]
+
+ if (use_x11) {
+ include_dirs = [ "//third_party/khronos" ]
+ }
+}
diff --git a/chromium/ui/surface/DEPS b/chromium/ui/surface/DEPS
index f4a3ec8864c..b0e7abb49de 100644
--- a/chromium/ui/surface/DEPS
+++ b/chromium/ui/surface/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+media/base",
"+skia/ext",
"+third_party/skia",
"+ui/base",
diff --git a/chromium/ui/surface/accelerated_surface_mac.cc b/chromium/ui/surface/accelerated_surface_mac.cc
index 5c63de72dac..2fbd47adaef 100644
--- a/chromium/ui/surface/accelerated_surface_mac.cc
+++ b/chromium/ui/surface/accelerated_surface_mac.cc
@@ -11,9 +11,11 @@
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
-#include "ui/gl/io_surface_support_mac.h"
#include "ui/gl/scoped_make_current.h"
+// Note that this must be included after gl_bindings.h to avoid conflicts.
+#include <OpenGL/CGLIOSurface.h>
+
AcceleratedSurface::AcceleratedSurface()
: io_surface_id_(0),
allocate_fbo_(false),
@@ -29,9 +31,8 @@ bool AcceleratedSurface::Initialize(
gfx::GpuPreference gpu_preference) {
allocate_fbo_ = allocate_fbo;
- // Ensure GL is initialized before trying to create an offscreen GL context.
- if (!gfx::GLSurface::InitializeOneOff())
- return false;
+ // GL should be initialized by content::SupportsCoreAnimationPlugins().
+ DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone);
// Drawing to IOSurfaces via OpenGL only works with Apple's GL and
// not with the OSMesa software renderer.
@@ -193,10 +194,6 @@ uint32 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) {
if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL)
return 0;
- IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
- if (!io_surface_support)
- return 0;
-
ui::ScopedMakeCurrent make_current(gl_context_.get(), gl_surface_.get());
if (!make_current.Succeeded())
return 0;
@@ -220,24 +217,18 @@ uint32 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) {
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
- AddIntegerValue(properties,
- io_surface_support->GetKIOSurfaceWidth(),
- clamped_size.width());
- AddIntegerValue(properties,
- io_surface_support->GetKIOSurfaceHeight(),
- clamped_size.height());
- AddIntegerValue(properties,
- io_surface_support->GetKIOSurfaceBytesPerElement(), 4);
- AddBooleanValue(properties,
- io_surface_support->GetKIOSurfaceIsGlobal(), true);
+ AddIntegerValue(properties, kIOSurfaceWidth, clamped_size.width());
+ AddIntegerValue(properties, kIOSurfaceHeight, clamped_size.height());
+ AddIntegerValue(properties, kIOSurfaceBytesPerElement, 4);
+ AddBooleanValue(properties, kIOSurfaceIsGlobal, true);
// I believe we should be able to unreference the IOSurfaces without
// synchronizing with the browser process because they are
// ultimately reference counted by the operating system.
- io_surface_.reset(io_surface_support->IOSurfaceCreate(properties));
+ io_surface_.reset(IOSurfaceCreate(properties));
// Don't think we need to identify a plane.
GLuint plane = 0;
- CGLError error = io_surface_support->CGLTexImageIOSurface2D(
+ CGLError error = CGLTexImageIOSurface2D(
static_cast<CGLContextObj>(gl_context_->GetHandle()),
target,
GL_RGBA,
@@ -266,7 +257,7 @@ uint32 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) {
// make our IOSurfaces global and send back their identifiers. On
// the browser process side the identifier is reconstituted into an
// IOSurface for on-screen rendering.
- io_surface_id_ = io_surface_support->IOSurfaceGetID(io_surface_);
+ io_surface_id_ = IOSurfaceGetID(io_surface_);
return io_surface_id_;
}
diff --git a/chromium/ui/surface/accelerated_surface_mac.h b/chromium/ui/surface/accelerated_surface_mac.h
index 0fbcbdb30d3..f5ee11cc9d6 100644
--- a/chromium/ui/surface/accelerated_surface_mac.h
+++ b/chromium/ui/surface/accelerated_surface_mac.h
@@ -6,6 +6,7 @@
#define UI_SURFACE_ACCELERATED_SURFACE_MAC_H_
#include <CoreFoundation/CoreFoundation.h>
+#include <IOSurface/IOSurfaceAPI.h>
#include "base/callback.h"
#include "base/mac/scoped_cftyperef.h"
@@ -118,7 +119,7 @@ class SURFACE_EXPORT AcceleratedSurface {
// to the shared region (IOSurface).
scoped_refptr<gfx::GLSurface> gl_surface_;
scoped_refptr<gfx::GLContext> gl_context_;
- base::ScopedCFTypeRef<CFTypeRef> io_surface_;
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
// The id of |io_surface_| or 0 if that's NULL.
uint32 io_surface_id_;
diff --git a/chromium/ui/surface/accelerated_surface_transformer_win.cc b/chromium/ui/surface/accelerated_surface_transformer_win.cc
deleted file mode 100644
index 0706a1ad4e5..00000000000
--- a/chromium/ui/surface/accelerated_surface_transformer_win.cc
+++ /dev/null
@@ -1,736 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/accelerated_surface_transformer_win.h"
-
-#include <vector>
-
-#include "accelerated_surface_transformer_win_hlsl_compiled.h"
-#include "base/debug/trace_event.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-#include "ui/surface/d3d9_utils_win.h"
-#include "ui/surface/surface_export.h"
-
-using base::win::ScopedComPtr;
-using std::vector;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoY8UV44;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertUV44toU2V2;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsOneTexture;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch2Pixels;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch4Pixels;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsOneTexture;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch4PixelsScale2;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoY;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoU;
-using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoV;
-
-namespace d3d_utils = ui_surface_d3d9_utils;
-
-namespace {
-
-struct Vertex {
- float x, y, z, w;
- float u, v;
-};
-
-const static D3DVERTEXELEMENT9 g_vertexElements[] = {
- { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 },
- { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
- D3DDECL_END()
-};
-
-class ScopedRenderTargetRestorer {
- public:
- ScopedRenderTargetRestorer(IDirect3DDevice9* device,
- int render_target_id)
- : device_(device),
- target_id_(render_target_id) {
- device_->GetRenderTarget(target_id_, original_render_target_.Receive());
- }
- ~ScopedRenderTargetRestorer() {
- device_->SetRenderTarget(target_id_, original_render_target_);
- }
- private:
- ScopedComPtr<IDirect3DDevice9> device_;
- int target_id_;
- ScopedComPtr<IDirect3DSurface9> original_render_target_;
-};
-
-// Calculate the number necessary to transform |src_subrect| into |dst_size|
-// by repeating downsampling of the image of |src_subrect| by a factor no more
-// than 2.
-int GetResampleCount(const gfx::Rect& src_subrect,
- const gfx::Size& dst_size) {
- // At least one copy is required, since the back buffer itself is not
- // lockable.
- int min_resample_count = 1;
- int width_count = 0;
- int width = src_subrect.width();
- while (width > dst_size.width()) {
- ++width_count;
- width >>= 1;
- }
- int height_count = 0;
- int height = src_subrect.height();
- while (height > dst_size.height()) {
- ++height_count;
- height >>= 1;
- }
- return std::max(std::max(width_count, height_count),
- min_resample_count);
-}
-
-// Returns half the size of |size| no smaller than |min_size|.
-gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size,
- const gfx::Size& min_size) {
- return gfx::Size(std::max(min_size.width(), size.width() / 2),
- std::max(min_size.height(), size.height() / 2));
-}
-
-} // namespace
-
-AcceleratedSurfaceTransformer::AcceleratedSurfaceTransformer()
- : device_supports_multiple_render_targets_(false),
- vertex_shader_sources_(),
- pixel_shader_sources_() {
-
- // Associate passes with actual shader programs.
- vertex_shader_sources_[ONE_TEXTURE] = kVsOneTexture;
- pixel_shader_sources_[ONE_TEXTURE] = kPsOneTexture;
-
- vertex_shader_sources_[RGB_TO_YV12_FAST__PASS_1_OF_2] = kVsFetch4Pixels;
- pixel_shader_sources_[RGB_TO_YV12_FAST__PASS_1_OF_2] = kPsConvertRGBtoY8UV44;
-
- vertex_shader_sources_[RGB_TO_YV12_FAST__PASS_2_OF_2] = kVsFetch2Pixels;
- pixel_shader_sources_[RGB_TO_YV12_FAST__PASS_2_OF_2] = kPsConvertUV44toU2V2;
-
- vertex_shader_sources_[RGB_TO_YV12_SLOW__PASS_1_OF_3] = kVsFetch4Pixels;
- pixel_shader_sources_[RGB_TO_YV12_SLOW__PASS_1_OF_3] = kPsConvertRGBtoY;
-
- vertex_shader_sources_[RGB_TO_YV12_SLOW__PASS_2_OF_3] = kVsFetch4PixelsScale2;
- pixel_shader_sources_[RGB_TO_YV12_SLOW__PASS_2_OF_3] = kPsConvertRGBtoU;
-
- vertex_shader_sources_[RGB_TO_YV12_SLOW__PASS_3_OF_3] = kVsFetch4PixelsScale2;
- pixel_shader_sources_[RGB_TO_YV12_SLOW__PASS_3_OF_3] = kPsConvertRGBtoV;
-
- COMPILE_ASSERT(NUM_SHADERS == 6, must_initialize_shader_sources);
-}
-
-bool AcceleratedSurfaceTransformer::Init(IDirect3DDevice9* device) {
- bool result = DoInit(device);
- if (!result) {
- ReleaseAll();
- }
- return result;
-}
-
-bool AcceleratedSurfaceTransformer::DoInit(IDirect3DDevice9* device) {
- device_ = device;
-
- {
- D3DCAPS9 caps;
- HRESULT hr = device->GetDeviceCaps(&caps);
- if (FAILED(hr))
- return false;
-
- device_supports_multiple_render_targets_ = (caps.NumSimultaneousRTs >= 2);
-
- // Log statistics about which paths we take.
- UMA_HISTOGRAM_BOOLEAN("GPU.AcceleratedSurfaceTransformerCanUseMRT",
- device_supports_multiple_render_targets());
- }
-
- // Force compilation of all shaders that could be used on this GPU.
- if (!CompileShaderCombo(ONE_TEXTURE))
- return false;
-
- if (device_supports_multiple_render_targets()) {
- if (!CompileShaderCombo(RGB_TO_YV12_FAST__PASS_1_OF_2) ||
- !CompileShaderCombo(RGB_TO_YV12_FAST__PASS_2_OF_2)) {
- return false;
- }
- } else {
- if (!CompileShaderCombo(RGB_TO_YV12_SLOW__PASS_1_OF_3) ||
- !CompileShaderCombo(RGB_TO_YV12_SLOW__PASS_2_OF_3) ||
- !CompileShaderCombo(RGB_TO_YV12_SLOW__PASS_3_OF_3)) {
- return false;
- }
- }
- COMPILE_ASSERT(NUM_SHADERS == 6, must_compile_at_doinit);
-
- ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration;
- HRESULT hr = device_->CreateVertexDeclaration(g_vertexElements,
- vertex_declaration.Receive());
- if (FAILED(hr))
- return false;
- hr = device_->SetVertexDeclaration(vertex_declaration);
- if (FAILED(hr))
- return false;
-
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::CompileShaderCombo(
- ShaderCombo shader) {
- if (!vertex_shaders_[shader]) {
- HRESULT hr = device_->CreateVertexShader(
- reinterpret_cast<const DWORD*>(vertex_shader_sources_[shader]),
- vertex_shaders_[shader].Receive());
-
- if (FAILED(hr))
- return false;
-
- for (int i = 0; i < NUM_SHADERS; ++i) {
- if (vertex_shader_sources_[i] == vertex_shader_sources_[shader] &&
- i != shader) {
- vertex_shaders_[i] = vertex_shaders_[shader];
- }
- }
- }
-
- if (!pixel_shaders_[shader]) {
- HRESULT hr = device_->CreatePixelShader(
- reinterpret_cast<const DWORD*>(pixel_shader_sources_[shader]),
- pixel_shaders_[shader].Receive());
-
- if (FAILED(hr))
- return false;
-
- for (int i = 0; i < NUM_SHADERS; ++i) {
- if (pixel_shader_sources_[i] == pixel_shader_sources_[shader] &&
- i != shader) {
- pixel_shaders_[i] = pixel_shaders_[shader];
- }
- }
- }
-
- return true;
-}
-
-void AcceleratedSurfaceTransformer::ReleaseAll() {
- for (int i = 0; i < NUM_SHADERS; i++) {
- vertex_shaders_[i] = NULL;
- pixel_shaders_[i] = NULL;
- }
-
- user_scratch_texture_ = NULL;
- uv_scratch_texture_ = NULL;
- y_scratch_surface_ = NULL;
- u_scratch_surface_ = NULL;
- v_scratch_surface_ = NULL;
- for (int i = 0; i < arraysize(scaler_scratch_surfaces_); i++)
- scaler_scratch_surfaces_[i] = NULL;
-
- device_ = NULL;
-}
-void AcceleratedSurfaceTransformer::DetachAll() {
- for (int i = 0; i < NUM_SHADERS; i++) {
- vertex_shaders_[i].Detach();
- pixel_shaders_[i].Detach();
- }
-
- user_scratch_texture_.Detach();
- uv_scratch_texture_.Detach();
- y_scratch_surface_.Detach();
- u_scratch_surface_.Detach();
- v_scratch_surface_.Detach();
- for (int i = 0; i < arraysize(scaler_scratch_surfaces_); i++)
- scaler_scratch_surfaces_[i].Detach();
-
- device_.Detach();
-}
-
-bool AcceleratedSurfaceTransformer::CopyInverted(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size) {
- return CopyWithTextureScale(src_texture, dst_surface, dst_size, 1.0f, -1.0f);
-}
-
-bool AcceleratedSurfaceTransformer::Copy(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size) {
- return CopyWithTextureScale(src_texture, dst_surface, dst_size, 1.0f, 1.0f);
-}
-
-bool AcceleratedSurfaceTransformer::CopyWithTextureScale(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size,
- float texture_scale_x,
- float texture_scale_y) {
-
- if (!SetShaderCombo(ONE_TEXTURE))
- return false;
-
- // Set the kTextureScale vertex shader constant, which is assigned to
- // register 1.
- float texture_scale[4] = {texture_scale_x, texture_scale_y, 0, 0};
- device()->SetVertexShaderConstantF(1, texture_scale, 1);
-
- ScopedRenderTargetRestorer render_target_restorer(device(), 0);
- device()->SetRenderTarget(0, dst_surface);
- device()->SetTexture(0, src_texture);
-
- D3DVIEWPORT9 viewport = {
- 0, 0,
- dst_size.width(), dst_size.height(),
- 0, 1
- };
- device()->SetViewport(&viewport);
-
- if (d3d_utils::GetSize(src_texture) == dst_size) {
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
- } else {
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- }
- device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
- device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-
- DrawScreenAlignedQuad(dst_size);
-
- // Clear surface references.
- device()->SetTexture(0, NULL);
- return true;
-}
-
-void AcceleratedSurfaceTransformer::DrawScreenAlignedQuad(
- const gfx::Size& size) {
- const float target_size[4] = { size.width(), size.height(), 0, 0};
-
- // Set the uniform shader constant |kRenderTargetSize|, which is bound
- // to register c0.
- device()->SetVertexShaderConstantF(0, target_size, 1);
-
- // We always send down the same vertices. The vertex program will take
- // care of doing resolution-dependent position adjustment.
- Vertex vertices[] = {
- { -1, +1, 0.5f, 1, 0, 0 },
- { +1, +1, 0.5f, 1, 1, 0 },
- { +1, -1, 0.5f, 1, 1, 1 },
- { -1, -1, 0.5f, 1, 0, 1 }
- };
-
- device()->BeginScene();
- device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,
- 2,
- vertices,
- sizeof(vertices[0]));
- device()->EndScene();
-
-}
-
-bool AcceleratedSurfaceTransformer::GetIntermediateTexture(
- const gfx::Size& size,
- IDirect3DTexture9** texture,
- IDirect3DSurface9** texture_level_zero) {
- if (!d3d_utils::CreateOrReuseRenderTargetTexture(device(),
- size,
- &user_scratch_texture_,
- texture_level_zero))
- return false;
-
- *texture = ScopedComPtr<IDirect3DTexture9>(user_scratch_texture_).Detach();
- return true;
-}
-
-// Resize an RGB surface using repeated linear interpolation.
-bool AcceleratedSurfaceTransformer::ResizeBilinear(
- IDirect3DSurface9* src_surface,
- const gfx::Rect& src_subrect,
- IDirect3DSurface9* dst_surface,
- const gfx::Rect& dst_rect) {
- COMPILE_ASSERT(arraysize(scaler_scratch_surfaces_) == 2, surface_count);
-
- gfx::Size src_size = src_subrect.size();
- gfx::Size dst_size = dst_rect.size();
-
- if (src_size.IsEmpty() || dst_size.IsEmpty())
- return false;
-
- HRESULT hr = S_OK;
- // Set up intermediate buffers needed for downsampling.
- const int resample_count = GetResampleCount(src_subrect, dst_size);
- const gfx::Size half_size =
- GetHalfSizeNoLessThan(src_subrect.size(), dst_size);
- if (resample_count > 1) {
- if (!d3d_utils::CreateOrReuseLockableSurface(device(),
- half_size,
- &scaler_scratch_surfaces_[0]))
- return false;
- }
- if (resample_count > 2) {
- const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size);
- if (!d3d_utils::CreateOrReuseLockableSurface(device(),
- quarter_size,
- &scaler_scratch_surfaces_[1]))
- return false;
- }
-
- // Repeat downsampling the surface until its size becomes identical to
- // |dst_size|. We keep the factor of each downsampling no more than two
- // because using a factor more than two can introduce aliasing.
- RECT read_rect = src_subrect.ToRECT();
- gfx::Size write_size = half_size;
- int read_buffer_index = 1;
- int write_buffer_index = 0;
- for (int i = 0; i < resample_count; ++i) {
- TRACE_EVENT0("gpu", "StretchRect");
- IDirect3DSurface9* read_buffer =
- (i == 0) ? src_surface : scaler_scratch_surfaces_[read_buffer_index];
- IDirect3DSurface9* write_buffer;
- RECT write_rect;
- if (i == resample_count - 1) {
- write_buffer = dst_surface;
- write_rect = dst_rect.ToRECT();
- } else {
- write_buffer = scaler_scratch_surfaces_[write_buffer_index];
- write_rect = gfx::Rect(write_size).ToRECT();
- }
-
- hr = device()->StretchRect(read_buffer,
- &read_rect,
- write_buffer,
- &write_rect,
- D3DTEXF_LINEAR);
-
- if (FAILED(hr))
- return false;
- read_rect = write_rect;
- write_size = GetHalfSizeNoLessThan(write_size, dst_size);
- std::swap(read_buffer_index, write_buffer_index);
- }
-
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::TransformRGBToYV12(
- IDirect3DTexture9* src_surface,
- const gfx::Size& dst_size,
- IDirect3DSurface9** dst_y,
- IDirect3DSurface9** dst_u,
- IDirect3DSurface9** dst_v) {
- gfx::Size packed_y_size;
- gfx::Size packed_uv_size;
- if (!AllocYUVBuffers(dst_size, &packed_y_size, &packed_uv_size,
- dst_y, dst_u, dst_v)) {
- return false;
- }
-
- if (device_supports_multiple_render_targets()) {
- return TransformRGBToYV12_MRT(src_surface,
- dst_size,
- packed_y_size,
- packed_uv_size,
- *dst_y,
- *dst_u,
- *dst_v);
- } else {
- return TransformRGBToYV12_WithoutMRT(src_surface,
- dst_size,
- packed_y_size,
- packed_uv_size,
- *dst_y,
- *dst_u,
- *dst_v);
- }
-}
-
-bool AcceleratedSurfaceTransformer::ReadFast(IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride) {
- // TODO(nick): Compared to GetRenderTargetData, LockRect+memcpy is 50% faster
- // on some systems, but 100x slower on others. We should have logic here to
- // choose the best path, probably by adaptively trying both and picking the
- // faster one. http://crbug.com/168532
- return ReadByGetRenderTargetData(gpu_surface, dst, dst_bytes_per_row,
- dst_num_rows, dst_stride);
-}
-
-bool AcceleratedSurfaceTransformer::ReadByLockAndCopy(
- IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride) {
- D3DLOCKED_RECT locked_rect;
- {
- TRACE_EVENT0("gpu", "LockRect");
- HRESULT hr = gpu_surface->LockRect(&locked_rect, NULL,
- D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to lock surface";
- return false;
- }
- }
-
- {
- TRACE_EVENT0("gpu", "memcpy");
- uint8* dst_row = dst;
- uint8* src_row = reinterpret_cast<uint8*>(locked_rect.pBits);
- for (int i = 0; i < dst_num_rows; i++) {
- memcpy(dst_row, src_row, dst_bytes_per_row);
- src_row += locked_rect.Pitch;
- dst_row += dst_stride;
- }
- }
- gpu_surface->UnlockRect();
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::ReadByGetRenderTargetData(
- IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride) {
- HRESULT hr = 0;
- ScopedComPtr<IDirect3DSurface9> system_surface;
- gfx::Size src_size = d3d_utils::GetSize(gpu_surface);
-
- // Depending on pitch and alignment, we might be able to wrap |dst| in an
- // offscreen- plain surface for a direct copy.
- const bool direct_copy = (dst_stride == dst_bytes_per_row &&
- src_size.width() * 4 == dst_bytes_per_row &&
- dst_num_rows >= src_size.height());
-
- {
- TRACE_EVENT0("gpu", "CreateOffscreenPlainSurface");
- HANDLE handle = reinterpret_cast<HANDLE>(dst);
- hr = device()->CreateOffscreenPlainSurface(src_size.width(),
- src_size.height(),
- D3DFMT_A8R8G8B8,
- D3DPOOL_SYSTEMMEM,
- system_surface.Receive(),
- direct_copy ? &handle : NULL);
- if (!SUCCEEDED(hr)) {
- LOG(ERROR) << "Failed to create offscreen plain surface.";
- return false;
- }
- }
-
- {
- TRACE_EVENT0("gpu", "GetRenderTargetData");
- hr = device()->GetRenderTargetData(gpu_surface, system_surface);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed GetRenderTargetData";
- return false;
- }
- }
-
- if (direct_copy) {
- // We're done: |system_surface| is a wrapper around |dst|.
- return true;
- } else {
- // Extra memcpy required from |system_surface| to |dst|.
- return ReadByLockAndCopy(system_surface, dst, dst_bytes_per_row,
- dst_num_rows, dst_stride);
- }
-}
-
-bool AcceleratedSurfaceTransformer::AllocYUVBuffers(
- const gfx::Size& dst_size,
- gfx::Size* y_size,
- gfx::Size* uv_size,
- IDirect3DSurface9** dst_y,
- IDirect3DSurface9** dst_u,
- IDirect3DSurface9** dst_v) {
-
- // Y is full height, packed into 4 components.
- *y_size = gfx::Size((dst_size.width() + 3) / 4, dst_size.height());
-
- // U and V are half the size (rounded up) of Y.
- *uv_size = gfx::Size((y_size->width() + 1) / 2, (y_size->height() + 1) / 2);
-
- if (!d3d_utils::CreateOrReuseLockableSurface(device(), *y_size,
- &y_scratch_surface_)) {
- return false;
- }
- if (!d3d_utils::CreateOrReuseLockableSurface(device(), *uv_size,
- &u_scratch_surface_)) {
- return false;
- }
- if (!d3d_utils::CreateOrReuseLockableSurface(device(), *uv_size,
- &v_scratch_surface_)) {
- return false;
- }
-
- *dst_y = ScopedComPtr<IDirect3DSurface9>(y_scratch_surface_).Detach();
- *dst_u = ScopedComPtr<IDirect3DSurface9>(u_scratch_surface_).Detach();
- *dst_v = ScopedComPtr<IDirect3DSurface9>(v_scratch_surface_).Detach();
-
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::TransformRGBToYV12_MRT(
- IDirect3DTexture9* src_surface,
- const gfx::Size& dst_size,
- const gfx::Size& packed_y_size,
- const gfx::Size& packed_uv_size,
- IDirect3DSurface9* dst_y,
- IDirect3DSurface9* dst_u,
- IDirect3DSurface9* dst_v) {
- TRACE_EVENT0("gpu", "RGBToYV12_MRT");
-
- ScopedRenderTargetRestorer color0_restorer(device(), 0);
- ScopedRenderTargetRestorer color1_restorer(device(), 1);
-
- // Create an intermediate surface to hold the UUVV values. This is color
- // target 1 for the first pass, and texture 0 for the second pass. Its
- // values are not read afterwards.
-
- ScopedComPtr<IDirect3DSurface9> uv_as_surface;
- if (!d3d_utils::CreateOrReuseRenderTargetTexture(device(),
- packed_y_size,
- &uv_scratch_texture_,
- uv_as_surface.Receive())) {
- return false;
- }
-
- // Clamping is required if (dst_size.width() % 8 != 0) or if
- // (dst_size.height != 0), so we set it always. Both passes rely on this.
- device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
- device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-
- /////////////////////////////////////////
- // Pass 1: RGB --(scaled)--> YYYY + UUVV
- SetShaderCombo(RGB_TO_YV12_FAST__PASS_1_OF_2);
-
- // Enable bilinear filtering if scaling is required. The filtering will take
- // place entirely in the first pass.
- if (d3d_utils::GetSize(src_surface) != dst_size) {
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- } else {
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
- }
-
- device()->SetTexture(0, src_surface);
- device()->SetRenderTarget(0, dst_y);
- device()->SetRenderTarget(1, uv_as_surface);
- DrawScreenAlignedQuad(dst_size);
-
- /////////////////////////////////////////
- // Pass 2: UUVV -> UUUU + VVVV
- SetShaderCombo(RGB_TO_YV12_FAST__PASS_2_OF_2);
-
- // The second pass uses bilinear minification to achieve vertical scaling,
- // so enable it always.
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
-
- device()->SetTexture(0, uv_scratch_texture_);
- device()->SetRenderTarget(0, dst_u);
- device()->SetRenderTarget(1, dst_v);
- DrawScreenAlignedQuad(packed_y_size);
-
- // Clear surface references.
- device()->SetTexture(0, NULL);
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::TransformRGBToYV12_WithoutMRT(
- IDirect3DTexture9* src_surface,
- const gfx::Size& dst_size,
- const gfx::Size& packed_y_size,
- const gfx::Size& packed_uv_size,
- IDirect3DSurface9* dst_y,
- IDirect3DSurface9* dst_u,
- IDirect3DSurface9* dst_v) {
- TRACE_EVENT0("gpu", "RGBToYV12_WithoutMRT");
-
- ScopedRenderTargetRestorer color0_restorer(device(), 0);
-
- ScopedComPtr<IDirect3DTexture9> scaled_src_surface;
-
- // If scaling is requested, do it to a temporary texture. The MRT path
- // gets a scale for free, so we need to support it here too (even though
- // it's an extra operation).
- if (d3d_utils::GetSize(src_surface) == dst_size) {
- scaled_src_surface = src_surface;
- } else {
- ScopedComPtr<IDirect3DSurface9> dst_level0;
- if (!d3d_utils::CreateOrReuseRenderTargetTexture(
- device(), dst_size, &uv_scratch_texture_, dst_level0.Receive())) {
- return false;
- }
- if (!Copy(src_surface, dst_level0, dst_size)) {
- return false;
- }
- scaled_src_surface = uv_scratch_texture_;
- }
-
- // Input texture is the same for all three passes.
- device()->SetTexture(0, scaled_src_surface);
-
- // Clamping is required if (dst_size.width() % 8 != 0) or if
- // (dst_size.height != 0), so we set it always. All passes rely on this.
- device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
- device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
-
- /////////////////////
- // Pass 1: RGB -> Y.
- SetShaderCombo(RGB_TO_YV12_SLOW__PASS_1_OF_3);
-
- // Pass 1 just needs point sampling.
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
-
- device()->SetRenderTarget(0, dst_y);
- DrawScreenAlignedQuad(dst_size);
-
- // Passes 2 and 3 rely on bilinear minification to downsample U and V.
- device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
- device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
-
- /////////////////////
- // Pass 2: RGB -> U.
- SetShaderCombo(RGB_TO_YV12_SLOW__PASS_2_OF_3);
- device()->SetRenderTarget(0, dst_u);
- DrawScreenAlignedQuad(dst_size);
-
- /////////////////////
- // Pass 3: RGB -> V.
- SetShaderCombo(RGB_TO_YV12_SLOW__PASS_3_OF_3);
- device()->SetRenderTarget(0, dst_v);
- DrawScreenAlignedQuad(dst_size);
-
- // Clear surface references.
- device()->SetTexture(0, NULL);
- return true;
-}
-
-IDirect3DDevice9* AcceleratedSurfaceTransformer::device() {
- return device_;
-}
-
-bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) {
- // Compile shaders on first use, if needed. Normally the compilation should
- // already have happened at Init() time, but test code might force
- // us down an unusual path.
- if (!CompileShaderCombo(combo))
- return false;
-
- HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]);
- if (!SUCCEEDED(hr))
- return false;
- hr = device()->SetPixelShader(pixel_shaders_[combo]);
- if (!SUCCEEDED(hr))
- return false;
- return true;
-}
diff --git a/chromium/ui/surface/accelerated_surface_transformer_win.h b/chromium/ui/surface/accelerated_surface_transformer_win.h
deleted file mode 100644
index b04d0ab6977..00000000000
--- a/chromium/ui/surface/accelerated_surface_transformer_win.h
+++ /dev/null
@@ -1,228 +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_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
-#define UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
-
-#include <d3d9.h>
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
-#include "ui/surface/surface_export.h"
-
-namespace gfx {
-class Size;
-class Rect;
-} // namespace gfx
-
-// Provides useful image filtering operations that are implemented
-// efficiently on DirectX9-class hardware using fragment programs.
-class SURFACE_EXPORT AcceleratedSurfaceTransformer {
- public:
- // Constructs an uninitialized surface transformer. Call Init() before
- // using the resulting object.
- AcceleratedSurfaceTransformer();
-
- // Init() initializes the transformer to operate on a device. This must be
- // called before any other method of this class, and it must be called
- // again after ReleaseAll() or DetachAll() before the class is used.
- //
- // Returns true if successful.
- bool Init(IDirect3DDevice9* device);
-
- // ReleaseAll() releases all direct3d resource references.
- void ReleaseAll();
-
- // DetachAll() leaks all direct3d resource references. This exists in order to
- // work around particular driver bugs, and should only be called at shutdown.
- // TODO(ncarter): Update the leak expectations before checkin.
- void DetachAll();
-
- // Draw a textured quad to a surface, flipping orientation in the y direction.
- bool CopyInverted(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size);
-
- // Draw a textured quad to a surface.
- bool Copy(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size);
-
- // Get an intermediate buffer of a particular |size|, that can be used as the
- // output of one transformation and the to another. The returned surface
- // belongs to an internal cache, and is invalidated by a subsequent call to
- // this method.
- bool GetIntermediateTexture(
- const gfx::Size& size,
- IDirect3DTexture9** texture,
- IDirect3DSurface9** texture_level_zero);
-
- // Resize a surface using repeated bilinear interpolation.
- bool ResizeBilinear(
- IDirect3DSurface9* src_surface,
- const gfx::Rect& src_subrect,
- IDirect3DSurface9* dst_surface,
- const gfx::Rect& dst_subrect);
-
- // Color format conversion from RGB to planar YV12 (also known as YUV420).
- //
- // YV12 is effectively a twelve bit per pixel format consisting of a full-
- // size y (luminance) plane and half-width, half-height u and v (blue and
- // red chrominance) planes. This method will allocate three lockable surfaces,
- // one for each plane, and return them via the arguments |dst_y|, |dst_u|,
- // and |dst_v|. These surface will be created with an ARGB D3DFORMAT, but
- // should be interpreted as the appropriate single-byte format when locking.
- //
- // The dimensions of the outputs (when interpreted as single-component data)
- // are as follows:
- // |dst_y| : width and height exactly |dst_size|
- // |dst_u| : width and height are each half of |dst_size|, rounded up.
- // |dst_v| : width and height are each half of |dst_size|, rounded up.
- //
- // If |src_texture|'s dimensions do not match |dst_size|, the source will be
- // bilinearly interpolated during conversion.
- //
- // Returns true if successful. Caller must be certain to release the surfaces
- // even if this function returns false. The returned surfaces belong to an
- // internal cache, and are invalidated by a subsequent call to this method.
- bool TransformRGBToYV12(
- IDirect3DTexture9* src_texture,
- const gfx::Size& dst_size,
- IDirect3DSurface9** dst_y,
- IDirect3DSurface9** dst_u,
- IDirect3DSurface9** dst_v);
-
- // Synchronously copy from a D3D surface into a caller-allocated buffer. This
- // will dispatch to one of a couple techniques, depending on which is
- // determined to be the faster method for the current device.
- bool ReadFast(IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride);
-
- // Do a read using a particular technique. Which of these is faster depends on
- // the hardware. Intended for testing; production code ought to call
- // ReadFast().
- bool ReadByLockAndCopy(IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride);
- bool ReadByGetRenderTargetData(IDirect3DSurface9* gpu_surface,
- uint8* dst,
- int dst_bytes_per_row,
- int dst_num_rows,
- int dst_stride);
-
- private:
- friend class AcceleratedSurfaceTransformerTest;
- FRIEND_TEST_ALL_PREFIXES(AcceleratedSurfaceTransformerTest, Init);
-
- enum ShaderCombo {
- ONE_TEXTURE,
- RGB_TO_YV12_FAST__PASS_1_OF_2,
- RGB_TO_YV12_FAST__PASS_2_OF_2,
- RGB_TO_YV12_SLOW__PASS_1_OF_3,
- RGB_TO_YV12_SLOW__PASS_2_OF_3,
- RGB_TO_YV12_SLOW__PASS_3_OF_3,
- NUM_SHADERS
- };
-
- // Efficient RGB->YV12 in two passes, but requires a device capable of writing
- // multiple render targets at the same time.
- //
- // Returns true if successful.
- bool TransformRGBToYV12_MRT(
- IDirect3DTexture9* src_surface,
- const gfx::Size& dst_size,
- const gfx::Size& packed_y_size,
- const gfx::Size& packed_uv_size,
- IDirect3DSurface9* dst_y,
- IDirect3DSurface9* dst_u,
- IDirect3DSurface9* dst_v);
-
- // Slower, less efficient RGB->YV12; does not require the device to have
- // multiple render target capability. Runs at about half speed of the fast
- // path.
- //
- // Returns true if successful.
- bool TransformRGBToYV12_WithoutMRT(
- IDirect3DTexture9* src_surface,
- const gfx::Size& dst_size,
- const gfx::Size& packed_y_size,
- const gfx::Size& packed_uv_size,
- IDirect3DSurface9* dst_y,
- IDirect3DSurface9* dst_u,
- IDirect3DSurface9* dst_v);
-
- // Helper to allocate appropriately size YUV buffers, accounting for various
- // roundings. The sizes of the buffers (in terms of ARGB pixels) are returned
- // as |packed_y_size| and |packed_uv_size|.
- //
- // Returns true if successful. Caller must be certain to release the surfaces
- // even if this function returns false. The returned belong to an internal
- // cache.
- bool AllocYUVBuffers(
- const gfx::Size& dst_size,
- gfx::Size* packed_y_size,
- gfx::Size* packed_uv_size,
- IDirect3DSurface9** dst_y,
- IDirect3DSurface9** dst_u,
- IDirect3DSurface9** dst_v);
-
- bool CopyWithTextureScale(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size,
- float texture_scale_x,
- float texture_scale_y);
-
- // Set the active vertex and pixel shader combination.
- //
- // Returns true if successful.
- bool SetShaderCombo(ShaderCombo combo);
-
- // Compiles a vertex and pixel shader combination, if not already compiled.
- //
- // Returns true if successful.
- bool CompileShaderCombo(ShaderCombo shader_combo_name);
-
- bool DoInit(IDirect3DDevice9* device);
-
- void DrawScreenAlignedQuad(const gfx::Size& dst_size);
-
- bool device_supports_multiple_render_targets() const {
- return device_supports_multiple_render_targets_;
- }
-
- IDirect3DDevice9* device();
-
- base::win::ScopedComPtr<IDirect3DDevice9> device_;
- base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shaders_[NUM_SHADERS];
- base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shaders_[NUM_SHADERS];
-
- // Temporary and scratch surfaces; cached to avoid frequent reallocation.
- base::win::ScopedComPtr<IDirect3DTexture9> user_scratch_texture_;
- base::win::ScopedComPtr<IDirect3DTexture9> uv_scratch_texture_;
- base::win::ScopedComPtr<IDirect3DSurface9> y_scratch_surface_;
- base::win::ScopedComPtr<IDirect3DSurface9> u_scratch_surface_;
- base::win::ScopedComPtr<IDirect3DSurface9> v_scratch_surface_;
- base::win::ScopedComPtr<IDirect3DSurface9> scaler_scratch_surfaces_[2];
-
- bool device_supports_multiple_render_targets_;
- const BYTE* vertex_shader_sources_[NUM_SHADERS];
- const BYTE* pixel_shader_sources_[NUM_SHADERS];
- DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceTransformer);
-};
-
-#endif // UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
diff --git a/chromium/ui/surface/accelerated_surface_transformer_win.hlsl b/chromium/ui/surface/accelerated_surface_transformer_win.hlsl
deleted file mode 100644
index aa105ceccea..00000000000
--- a/chromium/ui/surface/accelerated_surface_transformer_win.hlsl
+++ /dev/null
@@ -1,300 +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.
-
-// @gyp_namespace(ui_surface)
-// Compiles into C++ as 'accelerated_surface_transformer_win_hlsl_compiled.h'
-
-struct Vertex {
- float4 position : POSITION;
- float2 texCoord : TEXCOORD0;
-};
-
-texture t;
-sampler s;
-
-extern uniform float2 kRenderTargetSize : c0;
-extern uniform float2 kTextureScale : c1;
-
-// @gyp_compile(vs_2_0, vsOneTexture)
-//
-// Passes a position and texture coordinate to the pixel shader.
-Vertex vsOneTexture(Vertex input) {
- // Texture scale is typically just 1 (to do nothing) or -1 (to flip).
- input.texCoord = ((2 * (input.texCoord - 0.5) * kTextureScale) + 1) / 2;
- input.position.x += -1 / kRenderTargetSize.x;
- input.position.y += 1 / kRenderTargetSize.y;
- return input;
-};
-
-// @gyp_compile(ps_2_0, psOneTexture)
-//
-// Samples a texture at the given texture coordinate and returns the result.
-float4 psOneTexture(float2 texCoord : TEXCOORD0) : COLOR0 {
- return tex2D(s, texCoord);
-};
-
-// Return |value| rounded up to the nearest multiple of |multiple|.
-float alignTo(float value, float multiple) {
- // |multiple| is usually a compile-time constant; this check allows
- // the compiler to avoid the fmod when possible.
- if (multiple == 1)
- return value;
-
- // Biasing the value provides numeric stability. We expect |value| to
- // be an integer; this prevents 4.001 from being rounded up to 8.
- float biased_value = value - 0.5;
- return biased_value + multiple - fmod(biased_value, multiple);
-}
-
-float4 packForByteOrder(float4 value) {
- return value.bgra;
-}
-
-// Adjust the input vertex to address the correct range of texels. This depends
-// on the value of the shader constant |kRenderTargetSize|, as well as an
-// alignment factor |align| that effectively specifies the footprint of the
-// texel samples done by this shader pass, and is used to correct when that
-// footprint size doesn't align perfectly with the actual input size.
-Vertex adjustForAlignmentAndPacking(Vertex vtx, float2 align) {
- float src_width = kRenderTargetSize.x;
- float src_height = kRenderTargetSize.y;
-
- // Because our caller expects to be sampling |align.x| many pixels from src at
- // a time, if src's width isn't evenly divisible by |align.x|, it is necessary
- // to pretend that the source is slightly bigger than it is.
- float bloated_src_width = alignTo(src_width, align.x);
- float bloated_src_height = alignTo(src_height, align.y);
-
- // When bloated_src_width != src_width, we'll adjust the texture coordinates
- // to sample past the edge of the vtx; clamping will produce extra copies of
- // the last row.
- float texture_x_scale = bloated_src_width / src_width;
- float texture_y_scale = bloated_src_height / src_height;
-
- // Adjust positions so that we're addressing full fragments in the output, per
- // the top-left filling convention. The shifts would be equivalent to
- // 1/dst_width and 1/dst_height, if we were to calculate those explicitly.
- vtx.position.x -= align.x / bloated_src_width;
- vtx.position.y += align.y / bloated_src_height;
-
- // Apply the texture scale
- vtx.texCoord.x *= texture_x_scale;
- vtx.texCoord.y *= texture_y_scale;
-
- return vtx;
-}
-
-///////////////////////////////////////////////////////////////////////
-// RGB24 to YV12 in two passes; writing two 8888 targets each pass.
-//
-// YV12 is full-resolution luma and half-resolution blue/red chroma.
-//
-// (original)
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// |
-// | (y plane) (temporary)
-// | YYYY YYYY UVUV UVUV
-// +--> { YYYY YYYY + UVUV UVUV }
-// YYYY YYYY UVUV UVUV
-// First YYYY YYYY UVUV UVUV
-// pass YYYY YYYY UVUV UVUV
-// YYYY YYYY UVUV UVUV
-// |
-// | (u plane) (v plane)
-// Second | UUUU VVVV
-// pass +--> { UUUU + VVVV }
-// UUUU VVVV
-//
-///////////////////////////////////////////////////////////////////////
-
-// Phase one of RGB24->YV12 conversion: vsFetch4Pixels/psConvertRGBtoY8UV44
-//
-// @gyp_compile(vs_2_0, vsFetch4Pixels)
-// @gyp_compile(ps_2_0, psConvertRGBtoY8UV44)
-//
-// Writes four source pixels at a time to a full-size Y plane and a half-width
-// interleaved UV plane. After execution, the Y plane is complete but the UV
-// planes still need to be de-interleaved and vertically scaled.
-//
-void vsFetch4Pixels(in Vertex vertex,
- out float4 position : POSITION,
- out float2 texCoord0 : TEXCOORD0,
- out float2 texCoord1 : TEXCOORD1,
- out float2 texCoord2 : TEXCOORD2,
- out float2 texCoord3 : TEXCOORD3) {
- Vertex adjusted = adjustForAlignmentAndPacking(vertex, float2(4, 1));
-
- // Set up four taps, aligned to texel centers if the src's true size is
- // |kRenderTargetSize|, and doing bilinear interpolation otherwise.
- float2 one_texel_x = float2(1 / kRenderTargetSize.x, 0);
- position = adjusted.position;
- texCoord0 = adjusted.texCoord - 1.5f * one_texel_x;
- texCoord1 = adjusted.texCoord - 0.5f * one_texel_x;
- texCoord2 = adjusted.texCoord + 0.5f * one_texel_x;
- texCoord3 = adjusted.texCoord + 1.5f * one_texel_x;
-};
-
-struct YV16QuadPixel
-{
- float4 YYYY : COLOR0;
- float4 UUVV : COLOR1;
-};
-
-// Color conversion constants.
-static const float3x1 rgb_to_y = float3x1( +0.257f, +0.504f, +0.098f );
-static const float3x1 rgb_to_u = float3x1( -0.148f, -0.291f, +0.439f );
-static const float3x1 rgb_to_v = float3x1( +0.439f, -0.368f, -0.071f );
-static const float y_bias = 0.0625f;
-static const float uv_bias = 0.5f;
-
-YV16QuadPixel psConvertRGBtoY8UV44(float2 texCoord0 : TEXCOORD0,
- float2 texCoord1 : TEXCOORD1,
- float2 texCoord2 : TEXCOORD2,
- float2 texCoord3 : TEXCOORD3) {
- // Load the four texture samples into a matrix.
- float4x3 rgb_quad_pixel = float4x3(tex2D(s, texCoord0).rgb,
- tex2D(s, texCoord1).rgb,
- tex2D(s, texCoord2).rgb,
- tex2D(s, texCoord3).rgb);
-
- // RGB -> Y conversion (x4).
- float4 yyyy = mul(rgb_quad_pixel, rgb_to_y) + y_bias;
-
- // Average adjacent texture samples while converting RGB->UV. This is the same
- // as color converting then averaging, but slightly less math. These values
- // will be in the range [-0.439f, +0.439f] and still need to have the bias
- // term applied.
- float2x3 rgb_double_pixel = float2x3(rgb_quad_pixel[0] + rgb_quad_pixel[1],
- rgb_quad_pixel[2] + rgb_quad_pixel[3]);
- float2 uu = mul(rgb_double_pixel, rgb_to_u / 2);
- float2 vv = mul(rgb_double_pixel, rgb_to_v / 2);
-
- // Package the result to account for BGRA byte ordering.
- YV16QuadPixel result;
- result.YYYY = packForByteOrder(yyyy);
- result.UUVV.xyzw = float4(uu, vv) + uv_bias; // Apply uv bias.
- return result;
-};
-
-// Phase two of RGB24->YV12 conversion: vsFetch2Pixels/psConvertUV44toU2V2
-//
-// @gyp_compile(vs_2_0, vsFetch2Pixels)
-// @gyp_compile(ps_2_0, psConvertUV44toU2V2)
-//
-// Deals with UV only. Input is interleaved UV pixels, already scaled
-// horizontally, packed two per RGBA texel. Output is two color planes U and V,
-// packed four to a RGBA pixel.
-//
-// Vertical scaling happens via a half-texel offset and bilinear interpolation
-// during texture sampling.
-void vsFetch2Pixels(in Vertex vertex,
- out float4 position : POSITION,
- out float2 texCoord0 : TEXCOORD0,
- out float2 texCoord1 : TEXCOORD1) {
- // We fetch two texels in the horizontal direction, and scale by 2 in the
- // vertical direction.
- Vertex adjusted = adjustForAlignmentAndPacking(vertex, float2(2, 2));
-
- // Setup the two texture coordinates. No need to adjust texCoord.y; it's
- // already at the mid-way point between the two rows. Horizontally, we'll
- // fetch two texels so that we have enough data to fill our output.
- float2 one_texel_x = float2(1 / kRenderTargetSize.x, 0);
- position = adjusted.position;
- texCoord0 = adjusted.texCoord - 0.5f * one_texel_x;
- texCoord1 = adjusted.texCoord + 0.5f * one_texel_x;
-};
-
-struct UV8QuadPixel {
- float4 UUUU : COLOR0;
- float4 VVVV : COLOR1;
-};
-
-UV8QuadPixel psConvertUV44toU2V2(float2 texCoord0 : TEXCOORD0,
- float2 texCoord1 : TEXCOORD1) {
- // We're just sampling two pixels and unswizzling them. There's no need to do
- // vertical scaling with math, since bilinear interpolation in the sampler
- // takes care of that.
- float4 lo_uuvv = tex2D(s, texCoord0);
- float4 hi_uuvv = tex2D(s, texCoord1);
- UV8QuadPixel result;
- result.UUUU = packForByteOrder(float4(lo_uuvv.xy, hi_uuvv.xy));
- result.VVVV = packForByteOrder(float4(lo_uuvv.zw, hi_uuvv.zw));
- return result;
-};
-
-
-///////////////////////////////////////////////////////////////////////
-// RGB24 to YV12 in three passes, without MRT: one pass per output color plane.
-// vsFetch4Pixels is the common vertex shader for all three passes.
-//
-// Note that this technique will not do full bilinear filtering on its RGB
-// input (you'd get correctly filtered Y, but aliasing in U and V).
-//
-// Pass 1: vsFetch4Pixels + psConvertRGBToY
-// Pass 2: vsFetch4Pixels_Scale2 + psConvertRGBToU
-// Pass 3: vsFetch4Pixels_Scale2 + psConvertRGBToV
-//
-// @gyp_compile(vs_2_0, vsFetch4Pixels_Scale2)
-// @gyp_compile(ps_2_0, psConvertRGBtoY)
-// @gyp_compile(ps_2_0, psConvertRGBtoU)
-// @gyp_compile(ps_2_0, psConvertRGBtoV)
-//
-///////////////////////////////////////////////////////////////////////
-void vsFetch4Pixels_Scale2(in Vertex vertex,
- out float4 position : POSITION,
- out float2 texCoord0 : TEXCOORD0,
- out float2 texCoord1 : TEXCOORD1,
- out float2 texCoord2 : TEXCOORD2,
- out float2 texCoord3 : TEXCOORD3) {
- Vertex adjusted = adjustForAlignmentAndPacking(vertex, float2(8, 2));
-
- // Set up four taps, each of which samples a 2x2 texel quad at the midpoint.
- float2 one_texel_x = float2(1 / kRenderTargetSize.x, 0);
- position = adjusted.position;
- texCoord0 = adjusted.texCoord - 3 * one_texel_x;
- texCoord1 = adjusted.texCoord - 1 * one_texel_x;
- texCoord2 = adjusted.texCoord + 1 * one_texel_x;
- texCoord3 = adjusted.texCoord + 3 * one_texel_x;
-};
-
-// RGB -> Y, four samples at a time.
-float4 psConvertRGBtoY(float2 texCoord0 : TEXCOORD0,
- float2 texCoord1 : TEXCOORD1,
- float2 texCoord2 : TEXCOORD2,
- float2 texCoord3 : TEXCOORD3) : COLOR0 {
- float4x3 rgb_quad_pixel = float4x3(tex2D(s, texCoord0).rgb,
- tex2D(s, texCoord1).rgb,
- tex2D(s, texCoord2).rgb,
- tex2D(s, texCoord3).rgb);
- return packForByteOrder(mul(rgb_quad_pixel, rgb_to_y) + y_bias);
-}
-
-// RGB -> U, four samples at a time.
-float4 psConvertRGBtoU(float2 texCoord0 : TEXCOORD0,
- float2 texCoord1 : TEXCOORD1,
- float2 texCoord2 : TEXCOORD2,
- float2 texCoord3 : TEXCOORD3) : COLOR0 {
- float4x3 rgb_quad_pixel = float4x3(tex2D(s, texCoord0).rgb,
- tex2D(s, texCoord1).rgb,
- tex2D(s, texCoord2).rgb,
- tex2D(s, texCoord3).rgb);
- return packForByteOrder(mul(rgb_quad_pixel, rgb_to_u) + uv_bias);
-}
-
-// RGB -> V, four samples at a time.
-float4 psConvertRGBtoV(float2 texCoord0 : TEXCOORD0,
- float2 texCoord1 : TEXCOORD1,
- float2 texCoord2 : TEXCOORD2,
- float2 texCoord3 : TEXCOORD3) : COLOR0 {
- float4x3 rgb_quad_pixel = float4x3(tex2D(s, texCoord0).rgb,
- tex2D(s, texCoord1).rgb,
- tex2D(s, texCoord2).rgb,
- tex2D(s, texCoord3).rgb);
- return packForByteOrder(mul(rgb_quad_pixel, rgb_to_v) + uv_bias);
-}
diff --git a/chromium/ui/surface/accelerated_surface_transformer_win_unittest.cc b/chromium/ui/surface/accelerated_surface_transformer_win_unittest.cc
deleted file mode 100644
index 968720fe068..00000000000
--- a/chromium/ui/surface/accelerated_surface_transformer_win_unittest.cc
+++ /dev/null
@@ -1,895 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <d3d9.h>
-#include <random>
-
-#include "base/basictypes.h"
-#include "base/file_util.h"
-#include "base/hash.h"
-#include "base/scoped_native_library.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
-#include "media/base/simd/convert_rgb_to_yuv.h"
-#include "media/base/yuv_convert.h"
-#include "skia/ext/image_operations.h"
-#include "testing/gtest/include/gtest/gtest-param-test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/rect.h"
-#include "ui/surface/accelerated_surface_transformer_win.h"
-#include "ui/surface/accelerated_surface_win.h"
-#include "ui/surface/d3d9_utils_win.h"
-
-namespace d3d_utils = ui_surface_d3d9_utils;
-
-using base::win::ScopedComPtr;
-using std::uniform_int_distribution;
-
-namespace {
-
-// Debug flag, useful when hacking on tests.
-const bool kDumpImagesOnFailure = false;
-
-SkBitmap ToSkBitmap(IDirect3DSurface9* surface, bool is_single_channel) {
- D3DLOCKED_RECT locked_rect;
- EXPECT_HRESULT_SUCCEEDED(
- surface->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
-
- SkBitmap result;
- gfx::Size size = d3d_utils::GetSize(surface);
- if (is_single_channel)
- size = gfx::Size(size.width() * 4, size.height());
- result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height(),
- 0, kOpaque_SkAlphaType);
- result.allocPixels();
- result.lockPixels();
- for (int y = 0; y < size.height(); ++y) {
- uint8* row8 = reinterpret_cast<uint8*>(locked_rect.pBits) +
- (y * locked_rect.Pitch);
- if (is_single_channel) {
- for (int x = 0; x < size.width(); ++x) {
- *result.getAddr32(x, y) = SkColorSetRGB(row8[x], row8[x], row8[x]);
- }
- } else {
- uint32* row32 = reinterpret_cast<uint32*>(row8);
- for (int x = 0; x < size.width(); ++x) {
- *result.getAddr32(x, y) = row32[x] | 0xFF000000;
- }
- }
- }
- result.unlockPixels();
- result.setImmutable();
- surface->UnlockRect();
- return result;
-}
-
-bool WritePNGFile(const SkBitmap& bitmap, const base::FilePath& file_path) {
- std::vector<unsigned char> png_data;
- const bool discard_transparency = true;
- if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
- discard_transparency,
- &png_data) &&
- base::CreateDirectory(file_path.DirName())) {
- char* data = reinterpret_cast<char*>(&png_data[0]);
- int size = static_cast<int>(png_data.size());
- return file_util::WriteFile(file_path, data, size) == size;
- }
- return false;
-}
-
-} // namespace
-
-// Test fixture for AcceleratedSurfaceTransformer.
-//
-// This class is parameterized so that it runs only on Vista+. See
-// WindowsVersionIfVistaOrBetter() for details on this works.
-class AcceleratedSurfaceTransformerTest : public testing::TestWithParam<int> {
- public:
- AcceleratedSurfaceTransformerTest() : color_error_tolerance_(0) {};
-
- IDirect3DDevice9Ex* device() { return device_.get(); }
-
- virtual void SetUp() {
- if (!d3d_module_.is_valid()) {
- if (!d3d_utils::LoadD3D9(&d3d_module_)) {
- GTEST_FAIL() << "Could not load d3d9.dll";
- return;
- }
- }
- if (!d3d_utils::CreateDevice(d3d_module_,
- D3DDEVTYPE_HAL,
- D3DPRESENT_INTERVAL_IMMEDIATE,
- device_.Receive())) {
- GTEST_FAIL() << "Could not create Direct3D device.";
- return;
- }
-
- SeedRandom("default");
- }
-
- virtual void TearDown() {
- device_ = NULL;
- }
-
- // Gets a human-readable identifier of the graphics hardware being used,
- // intended for use inside of SCOPED_TRACE().
- std::string GetAdapterInfo() {
- ScopedComPtr<IDirect3D9> d3d;
- EXPECT_HRESULT_SUCCEEDED(device()->GetDirect3D(d3d.Receive()));
- D3DADAPTER_IDENTIFIER9 info;
- EXPECT_HRESULT_SUCCEEDED(d3d->GetAdapterIdentifier(0, 0, &info));
- return base::StringPrintf(
- "Running on graphics hardware: %s", info.Description);
- }
-
- void SeedRandom(const char* seed) {
- rng_.seed(base::Hash(seed));
- random_dword_.reset();
- }
-
- // Driver workaround: on an Intel GPU (Mobile Intel 965 Express), it seems
- // necessary to flush between drawing and locking, for the synchronization
- // to behave properly.
- void BeforeLockWorkaround() {
- EXPECT_HRESULT_SUCCEEDED(
- device()->Present(0, 0, 0, 0));
- }
-
- void WarnOnMissingFeatures(AcceleratedSurfaceTransformer* gpu_ops) {
- // Prints a single warning line if some tests are feature-dependent
- // and the feature is not supported by the current GPU.
- if (!gpu_ops->device_supports_multiple_render_targets()) {
- LOG(WARNING) << "MRT not supported, some tests will be skipped. "
- << GetAdapterInfo();
- }
- }
-
- // Locks and fills a surface with a checkerboard pattern where the colors
- // are random but the total image pattern is horizontally and vertically
- // symmetric.
- void FillSymmetricRandomCheckerboard(
- IDirect3DSurface9* lockable_surface,
- const gfx::Size& size,
- int checker_square_size) {
-
- D3DLOCKED_RECT locked_rect;
- ASSERT_HRESULT_SUCCEEDED(
- lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD));
- DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
- ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
- int pitch = locked_rect.Pitch / sizeof(DWORD);
-
- for (int y = 0; y < (size.height() + 1) / 2; y += checker_square_size) {
- for (int x = 0; x < (size.width() + 1) / 2; x += checker_square_size) {
- DWORD color = RandomColor();
- int y_limit = std::min(size.height() / 2, y + checker_square_size - 1);
- int x_limit = std::min(size.width() / 2, x + checker_square_size - 1);
- for (int y_lo = y; y_lo <= y_limit; y_lo++) {
- for (int x_lo = x; x_lo <= x_limit; x_lo++) {
- int y_hi = size.height() - 1 - y_lo;
- int x_hi = size.width() - 1 - x_lo;
- surface[x_lo + y_lo*pitch] = color;
- surface[x_lo + y_hi*pitch] = color;
- surface[x_hi + y_lo*pitch] = color;
- surface[x_hi + y_hi*pitch] = color;
- }
- }
- }
- }
-
- lockable_surface->UnlockRect();
- }
-
- void FillRandomCheckerboard(
- IDirect3DSurface9* lockable_surface,
- const gfx::Size& size,
- int checker_square_size) {
-
- D3DLOCKED_RECT locked_rect;
- ASSERT_HRESULT_SUCCEEDED(
- lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD));
- DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
- ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
- int pitch = locked_rect.Pitch / sizeof(DWORD);
-
- for (int y = 0; y <= size.height(); y += checker_square_size) {
- for (int x = 0; x <= size.width(); x += checker_square_size) {
- DWORD color = RandomColor();
- int y_limit = std::min(size.height(), y + checker_square_size);
- int x_limit = std::min(size.width(), x + checker_square_size);
- for (int square_y = y; square_y < y_limit; square_y++) {
- for (int square_x = x; square_x < x_limit; square_x++) {
- surface[square_x + square_y*pitch] = color;
- }
- }
- }
- }
-
- lockable_surface->UnlockRect();
- }
-
- // Approximate color-equality check. Allows for some rounding error.
- bool AssertSameColor(DWORD color_a, DWORD color_b) {
- if (color_a == color_b)
- return true;
- uint8* a = reinterpret_cast<uint8*>(&color_a);
- uint8* b = reinterpret_cast<uint8*>(&color_b);
- int max_error = 0;
- for (int i = 0; i < 4; i++)
- max_error = std::max(max_error,
- std::abs(static_cast<int>(a[i]) - b[i]));
-
- if (max_error <= color_error_tolerance())
- return true;
-
- std::string expected_color =
- base::StringPrintf("%3d, %3d, %3d, %3d", a[0], a[1], a[2], a[3]);
- std::string actual_color =
- base::StringPrintf("%3d, %3d, %3d, %3d", b[0], b[1], b[2], b[3]);
- EXPECT_EQ(expected_color, actual_color)
- << "Componentwise color difference was "
- << max_error << "; max allowed is " << color_error_tolerance();
-
- return false;
- }
-
-bool AssertSameColor(uint8 color_a, uint8 color_b) {
- if (color_a == color_b)
- return true;
- int max_error = std::abs((int) color_a - (int) color_b);
- if (max_error <= color_error_tolerance())
- return true;
- ADD_FAILURE() << "Colors not equal: "
- << base::StringPrintf("0x%x", color_a)
- << " vs. " << base::StringPrintf("0x%x", color_b);
- return false;
- }
-
- // Asserts that an image is symmetric with respect to itself: both
- // horizontally and vertically, within the tolerance of AssertSameColor.
- void AssertSymmetry(IDirect3DSurface9* lockable_surface,
- const gfx::Size& size) {
- BeforeLockWorkaround();
-
- D3DLOCKED_RECT locked_rect;
- ASSERT_HRESULT_SUCCEEDED(
- lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
- ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD));
- int pitch = locked_rect.Pitch / sizeof(DWORD);
- DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits);
- for (int y_lo = 0; y_lo < size.height() / 2; y_lo++) {
- int y_hi = size.height() - 1 - y_lo;
- for (int x_lo = 0; x_lo < size.width() / 2; x_lo++) {
- int x_hi = size.width() - 1 - x_lo;
- if (!AssertSameColor(surface[x_lo + y_lo*pitch],
- surface[x_hi + y_lo*pitch])) {
- lockable_surface->UnlockRect();
- GTEST_FAIL() << "Pixels (" << x_lo << ", " << y_lo << ") vs. "
- << "(" << x_hi << ", " << y_lo << ")";
- }
- if (!AssertSameColor(surface[x_hi + y_lo*pitch],
- surface[x_hi + y_hi*pitch])) {
- lockable_surface->UnlockRect();
- GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_lo << ") vs. "
- << "(" << x_hi << ", " << y_hi << ")";
- }
- if (!AssertSameColor(surface[x_hi + y_hi*pitch],
- surface[x_lo + y_hi*pitch])) {
- lockable_surface->UnlockRect();
- GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_hi << ") vs. "
- << "(" << x_lo << ", " << y_hi << ")";
- }
- }
- }
- lockable_surface->UnlockRect();
- }
-
- // Asserts that the actual image is a bit-identical, vertically mirrored
- // copy of the expected image.
- void AssertIsInvertedCopy(const gfx::Size& size,
- IDirect3DSurface9* expected,
- IDirect3DSurface9* actual) {
- BeforeLockWorkaround();
-
- D3DLOCKED_RECT locked_expected, locked_actual;
- ASSERT_HRESULT_SUCCEEDED(
- expected->LockRect(&locked_expected, NULL, D3DLOCK_READONLY));
- ASSERT_HRESULT_SUCCEEDED(
- actual->LockRect(&locked_actual, NULL, D3DLOCK_READONLY));
- ASSERT_EQ(0, locked_expected.Pitch % sizeof(DWORD));
- int pitch = locked_expected.Pitch / sizeof(DWORD);
- DWORD* expected_image = reinterpret_cast<DWORD*>(locked_expected.pBits);
- DWORD* actual_image = reinterpret_cast<DWORD*>(locked_actual.pBits);
- for (int y = 0; y < size.height(); y++) {
- int y_actual = size.height() - 1 - y;
- for (int x = 0; x < size.width(); ++x)
- if (!AssertSameColor(expected_image[y*pitch + x],
- actual_image[y_actual*pitch + x])) {
- expected->UnlockRect();
- actual->UnlockRect();
- GTEST_FAIL() << "Pixels (" << x << ", " << y << ") vs. "
- << "(" << x << ", " << y_actual << ")";
- }
- }
- expected->UnlockRect();
- actual->UnlockRect();
- }
-
- protected:
- DWORD RandomColor() {
- return random_dword_(rng_);
- }
-
- void set_color_error_tolerance(int value) {
- color_error_tolerance_ = value;
- }
-
- int color_error_tolerance() {
- return color_error_tolerance_;
- }
-
- void DoResizeBilinearTest(AcceleratedSurfaceTransformer* gpu_ops,
- const gfx::Size& src_size,
- const gfx::Size& dst_size,
- int checkerboard_size) {
-
- SCOPED_TRACE(
- base::StringPrintf(
- "Resizing %dx%d -> %dx%d at checkerboard size of %d",
- src_size.width(), src_size.height(),
- dst_size.width(), dst_size.height(),
- checkerboard_size));
-
- set_color_error_tolerance(4);
-
- base::win::ScopedComPtr<IDirect3DSurface9> src, dst;
- ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(
- device(), src_size, &src))
- << "Could not create src render target";
- ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(
- device(), dst_size, &dst))
- << "Could not create dst render target";
-
- FillSymmetricRandomCheckerboard(src, src_size, checkerboard_size);
-
- ASSERT_TRUE(gpu_ops->ResizeBilinear(src, gfx::Rect(src_size), dst,
- gfx::Rect(dst_size)));
-
- AssertSymmetry(dst, dst_size);
- }
-
- void CreateRandomCheckerboardTexture(
- const gfx::Size& size,
- int checkerboard_size,
- base::win::ScopedComPtr<IDirect3DSurface9>* reference_surface,
- base::win::ScopedComPtr<IDirect3DTexture9>* result) {
- base::win::ScopedComPtr<IDirect3DSurface9> dst;
- ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(device(), size,
- reference_surface));
- ASSERT_TRUE(d3d_utils::CreateOrReuseRenderTargetTexture(device(), size,
- result, dst.Receive()));
- FillRandomCheckerboard(*reference_surface, size, checkerboard_size);
- ASSERT_HRESULT_SUCCEEDED(
- device()->StretchRect(
- *reference_surface, NULL, dst, NULL, D3DTEXF_NONE));
- }
-
- void AssertSame(int width_in_bytes, int height, uint8* reference,
- IDirect3DSurface9* lockable) {
- BeforeLockWorkaround();
-
- D3DLOCKED_RECT locked_rect;
- ASSERT_HRESULT_SUCCEEDED(
- lockable->LockRect(&locked_rect, NULL, D3DLOCK_READONLY));
- uint8* actual = reinterpret_cast<uint8*>(locked_rect.pBits);
- for (int y = 0; y < height; ++y) {
- for (int x = 0; x < width_in_bytes; ++x) {
- if (!AssertSameColor(reference[y * width_in_bytes + x],
- actual[y * locked_rect.Pitch + x])) {
- lockable->UnlockRect();
- GTEST_FAIL() << "At pixel (" << x << ", " << y << ")";
- }
- }
- }
- lockable->UnlockRect();
- }
-
- void DoCopyInvertedTest(AcceleratedSurfaceTransformer* gpu_ops,
- const gfx::Size& size) {
-
- SCOPED_TRACE(base::StringPrintf(
- "CopyInverted @ %dx%d", size.width(), size.height()));
-
- set_color_error_tolerance(0);
-
- base::win::ScopedComPtr<IDirect3DSurface9> dst, reference_pattern;
- base::win::ScopedComPtr<IDirect3DTexture9> src;
-
- CreateRandomCheckerboardTexture(size, 1, &reference_pattern, &src);
-
- // Alloc a slightly larger image 75% of the time, to test that the
- // viewport is set properly.
- const int kAlign = 4;
- gfx::Size alloc_size((size.width() + kAlign - 1) / kAlign * kAlign,
- (size.height() + kAlign - 1) / kAlign * kAlign);
-
- ASSERT_TRUE(d3d_utils::CreateOrReuseLockableSurface(device(), alloc_size,
- &dst)) << "Could not create dst render target.";
-
- ASSERT_TRUE(gpu_ops->CopyInverted(src, dst, size));
- AssertIsInvertedCopy(size, reference_pattern, dst);
- }
-
-
- void DoYUVConversionTest(AcceleratedSurfaceTransformer* gpu_ops,
- const gfx::Size& src_size,
- int checkerboard_size) {
- // Test the non-MRT implementation, and the MRT implementation as well
- // (if supported by the device).
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(gpu_ops, src_size, src_size,
- checkerboard_size, false));
- if (gpu_ops->device_supports_multiple_render_targets()) {
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(gpu_ops, src_size, src_size,
- checkerboard_size, true));
- }
- }
-
- void DoYUVConversionScaleTest(AcceleratedSurfaceTransformer* gpu_ops,
- const gfx::Size& src_size,
- const gfx::Size& dst_size) {
- // Test the non-MRT implementation, and the MRT implementation as well
- // (if supported by the device).
- if (gpu_ops->device_supports_multiple_render_targets()) {
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(gpu_ops, src_size, dst_size, 4, true));
- }
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(gpu_ops, src_size, dst_size, 4, false));
- }
-
- void DoYUVConversionTest(AcceleratedSurfaceTransformer* gpu_ops,
- const gfx::Size& src_size,
- const gfx::Size& dst_size,
- int checkerboard_size,
- boolean use_multi_render_targets) {
- SCOPED_TRACE(
- base::StringPrintf(
- "YUV Converting %dx%d at checkerboard size of %d; MRT %s",
- src_size.width(), src_size.height(),
- checkerboard_size,
- use_multi_render_targets ? "enabled" : "disabled"));
-
-
- base::win::ScopedComPtr<IDirect3DTexture9> src;
- base::win::ScopedComPtr<IDirect3DSurface9> reference;
- base::win::ScopedComPtr<IDirect3DSurface9> dst_y, dst_u, dst_v;
-
- // TODO(ncarter): Use a better error metric that measures aggregate error
- // rather than simply max error. There seems to be slightly more error at
- // higher resolutions, maybe due to precision issues during rasterization
- // (or maybe more pixels = more test trials). Results are usually to an
- // error of 1, but we must use a tolerance of 3.
- set_color_error_tolerance(3);
- CreateRandomCheckerboardTexture(src_size, checkerboard_size, &reference,
- &src);
-
- gfx::Size packed_y_size, packed_uv_size;
-
- ASSERT_TRUE(gpu_ops->AllocYUVBuffers(dst_size,
- &packed_y_size,
- &packed_uv_size,
- dst_y.Receive(),
- dst_u.Receive(),
- dst_v.Receive()));
-
- // Actually do the conversion.
- if (use_multi_render_targets) {
- ASSERT_TRUE(gpu_ops->TransformRGBToYV12_MRT(src,
- dst_size,
- packed_y_size,
- packed_uv_size,
- dst_y,
- dst_u,
- dst_v));
- } else {
- ASSERT_TRUE(gpu_ops->TransformRGBToYV12_WithoutMRT(src,
- dst_size,
- packed_y_size,
- packed_uv_size,
- dst_y,
- dst_u,
- dst_v));
- }
-
- // UV size (in bytes/samples) is half, rounded up.
- gfx::Size uv_size((dst_size.width() + 1) / 2,
- (dst_size.height() + 1) / 2);
-
- // Generate a reference bitmap by calling a software implementation.
- SkBitmap reference_rgb = ToSkBitmap(reference, false);
- SkBitmap reference_rgb_scaled;
- if (dst_size == src_size) {
- reference_rgb_scaled = reference_rgb;
- } else {
- // We'll call Copy to do the bilinear scaling if needed.
- base::win::ScopedComPtr<IDirect3DSurface9> reference_scaled;
- ASSERT_TRUE(
- d3d_utils::CreateOrReuseLockableSurface(
- device(), dst_size, &reference_scaled));
- ASSERT_TRUE(gpu_ops->Copy(src, reference_scaled, dst_size));
- BeforeLockWorkaround();
- reference_rgb_scaled = ToSkBitmap(reference_scaled, false);
- }
-
- scoped_ptr<uint8[]> reference_y(new uint8[dst_size.GetArea()]);
- scoped_ptr<uint8[]> reference_u(new uint8[uv_size.GetArea()]);
- scoped_ptr<uint8[]> reference_v(new uint8[uv_size.GetArea()]);
- reference_rgb_scaled.lockPixels();
- media::ConvertRGB32ToYUV_SSE2_Reference(
- reinterpret_cast<uint8*>(reference_rgb_scaled.getAddr32(0, 0)),
- &reference_y[0],
- &reference_u[0],
- &reference_v[0],
- dst_size.width(),
- dst_size.height(),
- reference_rgb_scaled.rowBytes(),
- dst_size.width(),
- uv_size.width());
- reference_rgb_scaled.unlockPixels();
-
- // Check for equality of the reference and the actual.
- AssertSame(dst_size.width(), dst_size.height(), &reference_y[0], dst_y);
- AssertSame(uv_size.width(), uv_size.height(), &reference_u[0], dst_u);
- AssertSame(uv_size.width(), uv_size.height(), &reference_v[0], dst_v);
-
- if (kDumpImagesOnFailure && HasFatalFailure()) {
- // Note that this will dump the full u and v buffers, including
- // extra columns added due to packing. That means up to 7 extra
- // columns for uv, and up to 3 extra columns for y.
- WritePNGFile(reference_rgb,
- base::FilePath(FILE_PATH_LITERAL("test_fail_src.png")));
- WritePNGFile(reference_rgb_scaled,
- base::FilePath(
- FILE_PATH_LITERAL("test_fail_src_scaled.png")));
- WritePNGFile(ToSkBitmap(dst_y, true),
- base::FilePath(FILE_PATH_LITERAL("test_fail_y.png")));
- WritePNGFile(ToSkBitmap(dst_u, true),
- base::FilePath(FILE_PATH_LITERAL("test_fail_u.png")));
- WritePNGFile(ToSkBitmap(dst_v, true),
- base::FilePath(FILE_PATH_LITERAL("test_fail_v.png")));
- }
- }
-
- int color_error_tolerance_;
- uniform_int_distribution<DWORD> random_dword_;
- std::mt19937 rng_;
- base::ScopedNativeLibrary d3d_module_;
- base::win::ScopedComPtr<IDirect3DDevice9Ex> device_;
-};
-
-// Fails on some bots because Direct3D isn't allowed.
-TEST_P(AcceleratedSurfaceTransformerTest, Init) {
- SCOPED_TRACE(GetAdapterInfo());
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- WarnOnMissingFeatures(&gpu_ops);
-};
-
-// Fails on some bots because Direct3D isn't allowed.
-TEST_P(AcceleratedSurfaceTransformerTest, TestConsistentRandom) {
- // This behavior should be the same for every execution on every machine.
- // Otherwise tests might be flaky and impossible to debug.
- SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom");
- ASSERT_EQ(2922058934, RandomColor());
-
- SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom");
- ASSERT_EQ(2922058934, RandomColor());
- ASSERT_EQ(4050239976, RandomColor());
-
- SeedRandom("DifferentSeed");
- ASSERT_EQ(3904108833, RandomColor());
-}
-
-// Fails on some bots because Direct3D isn't allowed.
-TEST_P(AcceleratedSurfaceTransformerTest, CopyInverted) {
- // This behavior should be the same for every execution on every machine.
- // Otherwise tests might be flaky and impossible to debug.
- SCOPED_TRACE(GetAdapterInfo());
- SeedRandom("CopyInverted");
-
- AcceleratedSurfaceTransformer t;
- ASSERT_TRUE(t.Init(device()));
-
- uniform_int_distribution<int> size(1, 512);
-
- for (int i = 0; i < 100; ++i) {
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(size(rng_), size(rng_))))
- << "At iteration " << i;
- }
-}
-
-// Fails on some bots because Direct3D isn't allowed.
-// Fails on other bots because of ResizeBilinear symmetry failures.
-// Should pass, at least, on NVIDIA Quadro 600.
-TEST_P(AcceleratedSurfaceTransformerTest, MixedOperations) {
- SCOPED_TRACE(GetAdapterInfo());
- SeedRandom("MixedOperations");
-
- AcceleratedSurfaceTransformer t;
- ASSERT_TRUE(t.Init(device()));
-
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 2));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(20, 107)));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 5));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(64, 64), 5));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&t, gfx::Size(128, 128), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(3, 3), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(1412, 124)));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&t, gfx::Size(100, 200), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 2));
-
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(1512, 7)));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 5));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 8));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(1521, 3)));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&t, gfx::Size(140, 181), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(33, 712)));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 8), 8));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&t, gfx::Size(33, 2)));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&t, gfx::Size(200, 256), gfx::Size(126, 8), 8));
-}
-
-// Tests ResizeBilinear with 16K wide/hight src and dst surfaces.
-//
-// Fails on some bots because Direct3D isn't allowed.
-// Should pass, at least, on NVIDIA Quadro 600.
-TEST_P(AcceleratedSurfaceTransformerTest, LargeSurfaces) {
- SCOPED_TRACE(GetAdapterInfo());
- SeedRandom("LargeSurfaces");
-
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- D3DCAPS9 caps;
- ASSERT_HRESULT_SUCCEEDED(
- device()->GetDeviceCaps(&caps));
-
- SCOPED_TRACE(base::StringPrintf(
- "max texture size: %dx%d, max texture aspect: %d",
- caps.MaxTextureWidth, caps.MaxTextureHeight, caps.MaxTextureAspectRatio));
-
- const int w = caps.MaxTextureWidth;
- const int h = caps.MaxTextureHeight;
- const int lo = 256;
-
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops, gfx::Size(w, lo), gfx::Size(lo, lo), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, h), gfx::Size(lo, lo), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(w, lo), lo));
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(lo, h), lo));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&gpu_ops, gfx::Size(w, lo)));
- ASSERT_NO_FATAL_FAILURE(
- DoCopyInvertedTest(&gpu_ops, gfx::Size(lo, h)));
-
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(w, lo), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(lo, h), 1));
-
-}
-
-// Exercises ResizeBilinear with random minification cases where the
-// aspect ratio does not change.
-//
-// Fails on some bots because Direct3D isn't allowed.
-// Fails on other bots because of StretchRect symmetry failures.
-// Should pass, at least, on NVIDIA Quadro 600.
-TEST_P(AcceleratedSurfaceTransformerTest, MinifyUniform) {
- SCOPED_TRACE(GetAdapterInfo());
- SeedRandom("MinifyUniform");
-
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- const int dims[] = {21, 63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257};
- const int checkerboards[] = {1, 2, 3, 9};
- uniform_int_distribution<int> dim(0, arraysize(dims) - 1);
- uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1);
-
- for (int i = 0; i < 300; i++) {
- // Widths are picked so that dst is smaller than src.
- int dst_width = dims[dim(rng_)];
- int src_width = dims[dim(rng_)];
- if (src_width < dst_width)
- std::swap(dst_width, src_width);
-
- // src_height is picked to preserve aspect ratio.
- int dst_height = dims[dim(rng_)];
- int src_height = static_cast<int>(
- static_cast<int64>(src_width) * dst_height / dst_width);
-
- int checkerboard_size = checkerboards[checkerboard(rng_)];
-
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops,
- gfx::Size(src_width, src_height), // Src size (larger)
- gfx::Size(dst_width, dst_height), // Dst size (smaller)
- checkerboard_size)) << "Failed on iteration " << i;
- }
-};
-
-// Exercises ResizeBilinear with random magnification cases where the
-// aspect ratio does not change.
-//
-// This test relies on an assertion that resizing preserves symmetry in the
-// image, but for the current implementation of ResizeBilinear, this does not
-// seem to be true (fails on NVIDIA Quadro 600; passes on
-// Intel Mobile 965 Express)
-TEST_P(AcceleratedSurfaceTransformerTest, DISABLED_MagnifyUniform) {
- SCOPED_TRACE(GetAdapterInfo());
- SeedRandom("MagnifyUniform");
-
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- const int dims[] = {63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257};
- const int checkerboards[] = {1, 2, 3, 9};
- uniform_int_distribution<int> dim(0, arraysize(dims) - 1);
- uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1);
-
- for (int i = 0; i < 50; i++) {
- // Widths are picked so that src is smaller than dst.
- int dst_width = dims[dim(rng_)];
- int src_width = dims[dim(rng_)];
- if (dst_width < src_width)
- std::swap(src_width, dst_width);
-
- int dst_height = dims[dim(rng_)];
- int src_height = static_cast<int>(
- static_cast<int64>(src_width) * dst_height / dst_width);
-
- int checkerboard_size = checkerboards[checkerboard(rng_)];
-
- ASSERT_NO_FATAL_FAILURE(
- DoResizeBilinearTest(&gpu_ops,
- gfx::Size(src_width, src_height), // Src size (smaller)
- gfx::Size(dst_width, dst_height), // Dst size (larger)
- checkerboard_size)) << "Failed on iteration " << i;
- }
-};
-
-TEST_P(AcceleratedSurfaceTransformerTest, RGBtoYUV) {
- SeedRandom("RGBtoYUV");
-
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- // Start with some easy-to-debug cases. A checkerboard size of 1 is the
- // best test, but larger checkerboard sizes give more insight into where
- // a bug might be.
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 4));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 2));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(32, 32), 3));
-
- // All cases of width (mod 8) and height (mod 8), using 1x1 checkerboard.
- for (int w = 32; w < 40; ++w) {
- for (int h = 32; h < 40; ++h) {
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(w, h), 1));
- }
- }
-
- // All the very small sizes which require the most shifting in the
- // texture coordinates when doing alignment.
- for (int w = 1; w <= 9; ++w) {
- for (int h = 1; h <= 9; ++h) {
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(w, h), 1));
- }
- }
-
- // Random medium dimensions.
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(10, 142), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(124, 333), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(853, 225), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(231, 412), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(512, 128), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1024, 768), 1));
-
- // Common video/monitor resolutions
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(800, 768), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1024, 768), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1280, 720), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1280, 720), 2));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1920, 1080), 1));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(1920, 1080), 2));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionTest(&gpu_ops, gfx::Size(2048, 1536), 1));
-}
-
-TEST_P(AcceleratedSurfaceTransformerTest, RGBtoYUVScaled) {
- SeedRandom("RGBtoYUVScaled");
-
- AcceleratedSurfaceTransformer gpu_ops;
- ASSERT_TRUE(gpu_ops.Init(device()));
-
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(64, 64)));
-
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(16, 16)));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(24, 24)));
- ASSERT_NO_FATAL_FAILURE(
- DoYUVConversionScaleTest(&gpu_ops, gfx::Size(32, 32), gfx::Size(48, 48)));
-}
-
-namespace {
-
-// Used to suppress test on Windows versions prior to Vista.
-std::vector<int> WindowsVersionIfVistaOrBetter() {
- std::vector<int> result;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
- result.push_back(base::win::GetVersion());
- }
- return result;
-}
-
-} // namespace
-
-INSTANTIATE_TEST_CASE_P(VistaAndUp,
- AcceleratedSurfaceTransformerTest,
- ::testing::ValuesIn(WindowsVersionIfVistaOrBetter()));
diff --git a/chromium/ui/surface/accelerated_surface_win.cc b/chromium/ui/surface/accelerated_surface_win.cc
deleted file mode 100644
index a8b57c5a450..00000000000
--- a/chromium/ui/surface/accelerated_surface_win.cc
+++ /dev/null
@@ -1,1108 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/accelerated_surface_win.h"
-
-#include <windows.h>
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/files/file_path.h"
-#include "base/lazy_instance.h"
-#include "base/metrics/histogram.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/scoped_native_library.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/win/wrapped_window_proc.h"
-#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/win/shell.h"
-#include "ui/events/latency_info.h"
-#include "ui/gfx/frame_time.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/surface/accelerated_surface_transformer_win.h"
-#include "ui/surface/d3d9_utils_win.h"
-#include "ui/surface/surface_switches.h"
-
-namespace d3d_utils = ui_surface_d3d9_utils;
-
-namespace {
-
-UINT GetPresentationInterval() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
- return D3DPRESENT_INTERVAL_IMMEDIATE;
- else
- return D3DPRESENT_INTERVAL_ONE;
-}
-
-bool DoFirstShowPresentWithGDI() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDoFirstShowPresentWithGDI);
-}
-
-bool DoAllShowPresentWithGDI() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDoAllShowPresentWithGDI);
-}
-
-// Use a SurfaceReader to copy into one plane of the VideoFrame.
-bool CopyPlane(AcceleratedSurfaceTransformer* gpu_ops,
- IDirect3DSurface9* src_surface,
- media::VideoFrame* dst_frame,
- size_t plane_id) {
- int width_in_bytes = dst_frame->row_bytes(plane_id);
- return gpu_ops->ReadFast(src_surface, dst_frame->data(plane_id),
- width_in_bytes, dst_frame->rows(plane_id),
- dst_frame->row_bytes(plane_id));
-}
-
-} // namespace
-
-// A PresentThread is a thread that is dedicated to presenting surfaces to a
-// window. It owns a Direct3D device and a Direct3D query for this purpose.
-class PresentThread : public base::Thread,
- public base::RefCountedThreadSafe<PresentThread> {
- public:
- PresentThread(const char* name, uint64 adapter_luid);
-
- IDirect3DDevice9Ex* device() { return device_.get(); }
- IDirect3DQuery9* query() { return query_.get(); }
- AcceleratedSurfaceTransformer* surface_transformer() {
- return &surface_transformer_;
- }
-
- void SetAdapterLUID(uint64 adapter_luid);
- void InitDevice();
- void LockAndResetDevice();
- void ResetDevice();
- bool IsDeviceLost();
-
- base::Lock* lock() {
- return &lock_;
- }
-
- protected:
- virtual void Init();
- virtual void CleanUp();
-
- private:
- friend class base::RefCountedThreadSafe<PresentThread>;
-
- ~PresentThread();
-
- // The lock is taken while any thread is calling an AcceleratedPresenter
- // associated with this thread.
- base::Lock lock_;
-
- base::ScopedNativeLibrary d3d_module_;
- uint64 adapter_luid_;
- base::win::ScopedComPtr<IDirect3DDevice9Ex> device_;
-
- // This query is used to wait until a certain amount of progress has been
- // made by the GPU and it is safe for the producer to modify its shared
- // texture again.
- base::win::ScopedComPtr<IDirect3DQuery9> query_;
- AcceleratedSurfaceTransformer surface_transformer_;
-
- DISALLOW_COPY_AND_ASSIGN(PresentThread);
-};
-
-// There is a fixed sized pool of PresentThreads and therefore the maximum
-// number of Direct3D devices owned by those threads is bounded.
-class PresentThreadPool {
- public:
- static const int kNumPresentThreads = 4;
-
- PresentThreadPool();
- PresentThread* NextThread();
-
- void SetAdapterLUID(uint64 adapter_luid);
-
- private:
- base::Lock lock_;
- int next_thread_;
- scoped_refptr<PresentThread> present_threads_[kNumPresentThreads];
- uint64 adapter_luid_;
-
- DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
-};
-
-// A thread safe map of presenters by surface ID that returns presenters via
-// a scoped_refptr to keep them alive while they are referenced.
-class AcceleratedPresenterMap {
- public:
- AcceleratedPresenterMap();
- scoped_refptr<AcceleratedPresenter> CreatePresenter(
- gfx::PluginWindowHandle window);
- void RemovePresenter(const scoped_refptr<AcceleratedPresenter>& presenter);
- scoped_refptr<AcceleratedPresenter> GetPresenter(
- gfx::PluginWindowHandle window);
-
- // Destroy any D3D resources owned by the given present thread. Called on
- // the given present thread.
- void ResetPresentThread(PresentThread* present_thread);
-
- private:
- base::Lock lock_;
- typedef std::map<gfx::PluginWindowHandle, AcceleratedPresenter*> PresenterMap;
- PresenterMap presenters_;
- uint64 adapter_luid_;
- DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenterMap);
-};
-
-base::LazyInstance<PresentThreadPool>
- g_present_thread_pool = LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<AcceleratedPresenterMap>
- g_accelerated_presenter_map = LAZY_INSTANCE_INITIALIZER;
-
-PresentThread::PresentThread(const char* name, uint64 adapter_luid)
- : base::Thread(name),
- adapter_luid_(adapter_luid) {
-}
-
-void PresentThread::SetAdapterLUID(uint64 adapter_luid) {
- base::AutoLock locked(lock_);
-
- CHECK(message_loop() == base::MessageLoop::current());
-
- if (adapter_luid_ == adapter_luid)
- return;
-
- adapter_luid_ = adapter_luid;
- if (device_)
- ResetDevice();
-}
-
-void PresentThread::InitDevice() {
- lock_.AssertAcquired();
-
- if (device_)
- return;
-
- TRACE_EVENT0("gpu", "PresentThread::Init");
- d3d_utils::LoadD3D9(&d3d_module_);
- ResetDevice();
-}
-
-void PresentThread::LockAndResetDevice() {
- base::AutoLock locked(lock_);
- ResetDevice();
-}
-
-void PresentThread::ResetDevice() {
- TRACE_EVENT0("gpu", "PresentThread::ResetDevice");
-
- lock_.AssertAcquired();
-
- // The D3D device must be created on the present thread.
- CHECK(message_loop() == base::MessageLoop::current());
-
- // This will crash some Intel drivers but we can't render anything without
- // reseting the device, which would be disappointing.
- query_ = NULL;
- device_ = NULL;
- surface_transformer_.ReleaseAll();
-
- g_accelerated_presenter_map.Pointer()->ResetPresentThread(this);
-
- if (!d3d_utils::CreateDevice(d3d_module_,
- adapter_luid_,
- D3DDEVTYPE_HAL,
- GetPresentationInterval(),
- device_.Receive())) {
- return;
- }
-
- HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to create query";
- device_ = NULL;
- return;
- }
-
- if (!surface_transformer_.Init(device_)) {
- LOG(ERROR) << "Failed to initialize surface transformer";
- query_ = NULL;
- device_ = NULL;
- return;
- }
-}
-
-bool PresentThread::IsDeviceLost() {
- lock_.AssertAcquired();
-
- HRESULT hr = device_->CheckDeviceState(NULL);
- return FAILED(hr) || hr == S_PRESENT_MODE_CHANGED;
-}
-
-void PresentThread::Init() {
- TRACE_EVENT0("gpu", "Initialize thread");
-}
-
-void PresentThread::CleanUp() {
- // The D3D device and query are leaked because destroying the associated D3D
- // query crashes some Intel drivers.
- surface_transformer_.DetachAll();
- device_.Detach();
- query_.Detach();
-}
-
-PresentThread::~PresentThread() {
- Stop();
-}
-
-PresentThreadPool::PresentThreadPool() : next_thread_(0) {
-}
-
-PresentThread* PresentThreadPool::NextThread() {
- base::AutoLock locked(lock_);
-
- next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
- PresentThread* thread = present_threads_[next_thread_].get();
- if (!thread) {
- thread = new PresentThread(
- base::StringPrintf("PresentThread #%d", next_thread_).c_str(),
- adapter_luid_);
- thread->Start();
- present_threads_[next_thread_] = thread;
- }
-
- return thread;
-}
-
-void PresentThreadPool::SetAdapterLUID(uint64 adapter_luid) {
- base::AutoLock locked(lock_);
-
- adapter_luid_ = adapter_luid;
-
- for (int i = 0; i < kNumPresentThreads; ++i) {
- if (!present_threads_[i])
- continue;
-
- present_threads_[i]->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PresentThread::SetAdapterLUID,
- present_threads_[i],
- adapter_luid));
- }
-}
-
-AcceleratedPresenterMap::AcceleratedPresenterMap() {
-}
-
-scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::CreatePresenter(
- gfx::PluginWindowHandle window) {
- scoped_refptr<AcceleratedPresenter> presenter(
- new AcceleratedPresenter(window));
-
- base::AutoLock locked(lock_);
- DCHECK(presenters_.find(window) == presenters_.end());
- presenters_[window] = presenter.get();
-
- return presenter;
-}
-
-void AcceleratedPresenterMap::RemovePresenter(
- const scoped_refptr<AcceleratedPresenter>& presenter) {
- base::AutoLock locked(lock_);
- for (PresenterMap::iterator it = presenters_.begin();
- it != presenters_.end();
- ++it) {
- if (it->second == presenter.get()) {
- presenters_.erase(it);
- return;
- }
- }
-
- NOTREACHED();
-}
-
-scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::GetPresenter(
- gfx::PluginWindowHandle window) {
- base::AutoLock locked(lock_);
- PresenterMap::iterator it = presenters_.find(window);
- if (it == presenters_.end())
- return scoped_refptr<AcceleratedPresenter>();
-
- return it->second;
-}
-
-void AcceleratedPresenterMap::ResetPresentThread(
- PresentThread* present_thread) {
- base::AutoLock locked(lock_);
-
- for (PresenterMap::iterator it = presenters_.begin();
- it != presenters_.end();
- ++it) {
- it->second->ResetPresentThread(present_thread);
- }
-}
-
-AcceleratedPresenter::AcceleratedPresenter(gfx::PluginWindowHandle window)
- : present_thread_(g_present_thread_pool.Pointer()->NextThread()),
- window_(window),
- event_(false, false),
- hidden_(true),
- do_present_with_GDI_(DoAllShowPresentWithGDI() ||
- DoFirstShowPresentWithGDI()),
- is_session_locked_(false) {
-}
-
-// static
-void AcceleratedPresenter::SetAdapterLUID(uint64 adapter_luid) {
- return g_present_thread_pool.Pointer()->SetAdapterLUID(adapter_luid);
-}
-
-
-// static
-scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow(
- gfx::PluginWindowHandle window) {
- return g_accelerated_presenter_map.Pointer()->GetPresenter(window);
-}
-
-void AcceleratedPresenter::AsyncPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const ui::LatencyInfo& latency_info,
- const CompletionTask& completion_task) {
- if (!surface_handle) {
- TRACE_EVENT1("gpu", "EarlyOut_ZeroSurfaceHandle",
- "surface_handle", surface_handle);
- completion_task.Run(
- true, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo());
- return;
- }
-
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge,
- this,
- size,
- surface_handle,
- latency_info,
- completion_task));
-}
-
-void AcceleratedPresenter::Present(HDC dc) {
- TRACE_EVENT0("gpu", "Present");
-
- base::AutoLock locked(*present_thread_->lock());
-
- // If invalidated, do nothing. The window is gone.
- if (!window_)
- return;
-
- // Suspended or nothing has ever been presented.
- if (!swap_chain_)
- return;
-
- PresentWithGDI(dc);
-}
-
-void AcceleratedPresenter::AsyncCopyTo(
- const gfx::Rect& requested_src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge,
- this,
- requested_src_subrect,
- dst_size,
- base::MessageLoopProxy::current(),
- callback));
-}
-
-void AcceleratedPresenter::AsyncCopyToVideoFrame(
- const gfx::Rect& requested_src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge,
- this,
- requested_src_subrect,
- target,
- base::MessageLoopProxy::current(),
- callback));
-}
-
-void AcceleratedPresenter::DoCopyToAndAcknowledge(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
- SkBitmap target;
- bool result = DoCopyToARGB(src_subrect, dst_size, &target);
- if (!result)
- target.reset();
- callback_runner->PostTask(FROM_HERE, base::Bind(callback, result, target));
-}
-
-void AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const scoped_refptr<base::SingleThreadTaskRunner>& callback_runner,
- const base::Callback<void(bool)>& callback) {
-
- bool result = DoCopyToYUV(src_subrect, target);
- callback_runner->PostTask(FROM_HERE, base::Bind(callback, result));
-}
-
-bool AcceleratedPresenter::DoCopyToARGB(const gfx::Rect& requested_src_subrect,
- const gfx::Size& dst_size,
- SkBitmap* bitmap) {
- TRACE_EVENT2(
- "gpu", "CopyTo",
- "width", dst_size.width(),
- "height", dst_size.height());
-
- base::AutoLock locked(*present_thread_->lock());
-
- if (!swap_chain_)
- return false;
-
- AcceleratedSurfaceTransformer* gpu_ops =
- present_thread_->surface_transformer();
-
- base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
- HRESULT hr = swap_chain_->GetBackBuffer(0,
- D3DBACKBUFFER_TYPE_MONO,
- back_buffer.Receive());
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get back buffer";
- return false;
- }
-
- D3DSURFACE_DESC desc;
- hr = back_buffer->GetDesc(&desc);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get buffer description";
- return false;
- }
-
- const gfx::Size back_buffer_size(desc.Width, desc.Height);
- if (back_buffer_size.IsEmpty())
- return false;
-
- // With window resizing, it's possible that the back buffer is smaller than
- // the requested src subset. Clip to the actual back buffer.
- gfx::Rect src_subrect = requested_src_subrect;
- src_subrect.Intersect(gfx::Rect(back_buffer_size));
- base::win::ScopedComPtr<IDirect3DSurface9> final_surface;
- {
- if (!d3d_utils::CreateOrReuseLockableSurface(present_thread_->device(),
- dst_size,
- &final_surface)) {
- LOG(ERROR) << "Failed to create temporary lockable surface";
- return false;
- }
- }
-
- {
- // Let the surface transformer start the resize into |final_surface|.
- TRACE_EVENT0("gpu", "ResizeBilinear");
- if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect,
- final_surface, gfx::Rect(dst_size))) {
- LOG(ERROR) << "Failed to resize bilinear";
- return false;
- }
- }
-
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, dst_size.width(),
- dst_size.height(), 0, kOpaque_SkAlphaType);
- if (!bitmap->allocPixels())
- return false;
-
- // Copy |final_surface| to |bitmap|. This is always a synchronous operation.
- return gpu_ops->ReadFast(final_surface,
- reinterpret_cast<uint8*>(bitmap->getPixels()),
- bitmap->width() * bitmap->bytesPerPixel(),
- bitmap->height(),
- static_cast<int>(bitmap->rowBytes()));
-}
-
-bool AcceleratedPresenter::DoCopyToYUV(
- const gfx::Rect& requested_src_subrect,
- const scoped_refptr<media::VideoFrame>& frame) {
- gfx::Size dst_size = frame->coded_size();
- TRACE_EVENT2(
- "gpu", "CopyToYUV",
- "width", dst_size.width(),
- "height", dst_size.height());
-
- base::AutoLock locked(*present_thread_->lock());
-
- if (!swap_chain_)
- return false;
-
- AcceleratedSurfaceTransformer* gpu_ops =
- present_thread_->surface_transformer();
-
- base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
- HRESULT hr = swap_chain_->GetBackBuffer(0,
- D3DBACKBUFFER_TYPE_MONO,
- back_buffer.Receive());
- if (FAILED(hr))
- return false;
-
- D3DSURFACE_DESC desc;
- hr = back_buffer->GetDesc(&desc);
- if (FAILED(hr))
- return false;
-
- const gfx::Size back_buffer_size(desc.Width, desc.Height);
- if (back_buffer_size.IsEmpty())
- return false;
-
- // With window resizing, it's possible that the back buffer is smaller than
- // the requested src subset. Clip to the actual back buffer.
- gfx::Rect src_subrect = requested_src_subrect;
- src_subrect.Intersect(gfx::Rect(back_buffer_size));
- if (src_subrect.IsEmpty())
- return false;
-
- base::win::ScopedComPtr<IDirect3DSurface9> resized;
- base::win::ScopedComPtr<IDirect3DTexture9> resized_as_texture;
- if (!gpu_ops->GetIntermediateTexture(dst_size,
- resized_as_texture.Receive(),
- resized.Receive())) {
- return false;
- }
-
- // Shrink the source to fit entirely in the destination while preserving
- // aspect ratio. Fill in any margin with black.
- // TODO(nick): It would be more efficient all around to implement
- // letterboxing as a memset() on the dst.
- gfx::Rect letterbox = media::ComputeLetterboxRegion(gfx::Rect(dst_size),
- src_subrect.size());
- if (letterbox != gfx::Rect(dst_size)) {
- TRACE_EVENT0("gpu", "Letterbox");
- present_thread_->device()->ColorFill(resized, NULL, 0xFF000000);
- }
-
- {
- TRACE_EVENT0("gpu", "ResizeBilinear");
- if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, resized, letterbox))
- return false;
- }
-
- base::win::ScopedComPtr<IDirect3DSurface9> y, u, v;
- {
- TRACE_EVENT0("gpu", "TransformRGBToYV12");
- if (!gpu_ops->TransformRGBToYV12(resized_as_texture,
- dst_size,
- y.Receive(), u.Receive(), v.Receive())) {
- return false;
- }
- }
-
- if (!CopyPlane(gpu_ops, y, frame, media::VideoFrame::kYPlane))
- return false;
- if (!CopyPlane(gpu_ops, u, frame, media::VideoFrame::kUPlane))
- return false;
- if (!CopyPlane(gpu_ops, v, frame, media::VideoFrame::kVPlane))
- return false;
- return true;
-}
-
-void AcceleratedPresenter::Suspend() {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoSuspend,
- this));
-}
-
-void AcceleratedPresenter::WasHidden() {
- base::AutoLock locked(*present_thread_->lock());
- hidden_ = true;
-}
-
-void AcceleratedPresenter::ReleaseSurface() {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoReleaseSurface,
- this));
-}
-
-void AcceleratedPresenter::SetIsSessionLocked(bool locked) {
- is_session_locked_ = locked;
-}
-
-void AcceleratedPresenter::Invalidate() {
- // Make any pending or future presentation tasks do nothing. Once the last
- // last pending task has been ignored, the reference count on the presenter
- // will go to zero and the presenter, and potentially also the present thread
- // it has a reference count on, will be destroyed.
- base::AutoLock locked(*present_thread_->lock());
- window_ = NULL;
-}
-
-void AcceleratedPresenter::ResetPresentThread(
- PresentThread* present_thread) {
- TRACE_EVENT0("gpu", "ResetPresentThread");
-
- // present_thread_ can be accessed without the lock because it is immutable.
- if (present_thread_ != present_thread)
- return;
-
- present_thread_->lock()->AssertAcquired();
-
- source_texture_ = NULL;
- swap_chain_ = NULL;
- quantized_size_ = gfx::Size();
-}
-
-AcceleratedPresenter::~AcceleratedPresenter() {
-}
-
-bool AcceleratedPresenter::IsSwapChainInitialized() const {
- base::AutoLock locked(*present_thread_->lock());
-
- return !!swap_chain_;
-}
-
-void AcceleratedPresenter::DoPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const ui::LatencyInfo& latency_info,
- const CompletionTask& completion_task) {
- TRACE_EVENT2(
- "gpu", "DoPresentAndAcknowledge",
- "width", size.width(),
- "height", size.height());
-
- HRESULT hr;
-
- base::AutoLock locked(*present_thread_->lock());
-
- latency_info_.MergeWith(latency_info);
-
- // Initialize the device lazily since calling Direct3D can crash bots.
- present_thread_->InitDevice();
-
- if (!present_thread_->device()) {
- completion_task.Run(
- false, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo());
- TRACE_EVENT0("gpu", "EarlyOut_NoDevice");
- return;
- }
-
- // Ensure the task is acknowledged on early out after this point.
- base::ScopedClosureRunner scoped_completion_runner(
- base::Bind(completion_task,
- true,
- base::TimeTicks(),
- base::TimeDelta(),
- ui::LatencyInfo()));
-
- // If invalidated, do nothing, the window is gone.
- if (!window_) {
- TRACE_EVENT0("gpu", "EarlyOut_NoWindow");
- return;
- }
-
-#if !defined(USE_AURA)
- // If the window is a different size than the swap chain that is being
- // presented then drop the frame.
- gfx::Size window_size = GetWindowSize();
- bool size_mismatch = size != window_size;
- if (gfx::IsInHighDPIMode()) {
- // Check if the size mismatch is within allowable round off or truncation
- // error.
- gfx::Size dip_size = gfx::win::ScreenToDIPSize(window_size);
- gfx::Size pixel_size = gfx::win::DIPToScreenSize(dip_size);
- size_mismatch = abs(window_size.width() - size.width()) >
- abs(window_size.width() - pixel_size.width()) ||
- abs(window_size.height() - size.height()) >
- abs(window_size.height() - pixel_size.height());
- }
- if (hidden_ && size_mismatch) {
- TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize",
- "backwidth", size.width(), "backheight", size.height());
- TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize2",
- "windowwidth", window_size.width(),
- "windowheight", window_size.height());
- return;
- }
-#endif
- // Round up size so the swap chain is not continuously resized with the
- // surface, which could lead to memory fragmentation.
- const int kRound = 64;
- gfx::Size quantized_size(
- std::max(1, (size.width() + kRound - 1) / kRound * kRound),
- std::max(1, (size.height() + kRound - 1) / kRound * kRound));
-
- // Ensure the swap chain exists and is the same size (rounded up) as the
- // surface to be presented.
- if (!swap_chain_ || quantized_size_ != quantized_size) {
- TRACE_EVENT0("gpu", "CreateAdditionalSwapChain");
- quantized_size_ = quantized_size;
-
- D3DPRESENT_PARAMETERS parameters = { 0 };
- parameters.BackBufferWidth = quantized_size.width();
- parameters.BackBufferHeight = quantized_size.height();
- parameters.BackBufferCount = 1;
- parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
- parameters.hDeviceWindow = window_;
- parameters.Windowed = TRUE;
- parameters.Flags = 0;
- parameters.PresentationInterval = GetPresentationInterval();
- parameters.SwapEffect = D3DSWAPEFFECT_COPY;
-
- swap_chain_ = NULL;
- HRESULT hr = present_thread_->device()->CreateAdditionalSwapChain(
- &parameters,
- swap_chain_.Receive());
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to create swap chain "
- << quantized_size.width() << " x " <<quantized_size.height();
- return;
- }
- }
-
- if (!source_texture_.get()) {
- TRACE_EVENT0("gpu", "OpenSharedTexture");
- if (!d3d_utils::OpenSharedTexture(present_thread_->device(),
- surface_handle,
- size,
- source_texture_.Receive())) {
- LOG(ERROR) << "Failed to open shared texture";
- return;
- }
- }
-
- base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
- hr = source_texture_->GetSurfaceLevel(0, source_surface.Receive());
- if (FAILED(hr)) {
- TRACE_EVENT0("gpu", "EarlyOut_NoSurfaceLevel");
- LOG(ERROR) << "Failed to get source surface";
- return;
- }
-
- base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
- hr = swap_chain_->GetBackBuffer(0,
- D3DBACKBUFFER_TYPE_MONO,
- dest_surface.Receive());
- if (FAILED(hr)) {
- TRACE_EVENT0("gpu", "EarlyOut_NoBackbuffer");
- LOG(ERROR) << "Failed to get back buffer";
- return;
- }
-
- RECT rect = {
- 0, 0,
- size.width(), size.height()
- };
-
- {
- TRACE_EVENT0("gpu", "Copy");
-
- // Copy while flipping the source texture on the vertical axis.
- bool result = present_thread_->surface_transformer()->CopyInverted(
- source_texture_, dest_surface, size);
- if (!result) {
- LOG(ERROR) << "Failed to copy shared texture";
- return;
- }
- }
-
- hr = present_thread_->query()->Issue(D3DISSUE_END);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to issue query";
- return;
- }
-
- present_size_ = size;
-
- // If it is expected that Direct3D cannot be used reliably because the window
- // is resizing, fall back to presenting with GDI.
- if (CheckDirect3DWillWork()) {
- TRACE_EVENT0("gpu", "PresentD3D");
-
- hr = swap_chain_->Present(&rect, &rect, window_, NULL, 0);
-
- if (FAILED(hr)) {
- if (present_thread_->IsDeviceLost())
- present_thread_->ResetDevice();
- return;
- }
- } else {
- HDC dc = GetDC(window_);
- PresentWithGDI(dc);
- ReleaseDC(window_, dc);
- }
-
- latency_info_.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
-
- hidden_ = false;
-
- D3DDISPLAYMODE display_mode;
- hr = present_thread_->device()->GetDisplayMode(0, &display_mode);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get display mode";
- return;
- }
-
- D3DRASTER_STATUS raster_status;
- hr = swap_chain_->GetRasterStatus(&raster_status);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get raster status";
- return;
- }
-
- UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.AcceleratedSurfaceRefreshRate",
- display_mode.RefreshRate, 0, 121, 122);
-
- // I can't figure out how to determine how many scanlines are in the
- // vertical blank so clamp it such that scanline / height <= 1.
- int clamped_scanline = std::min(raster_status.ScanLine, display_mode.Height);
-
- // The Internet says that on some GPUs, the scanline is not available
- // while in the vertical blank.
- if (raster_status.InVBlank)
- clamped_scanline = display_mode.Height;
-
- // Figure out approximately how far back in time the last vsync was based on
- // the ratio of the raster scanline to the display height.
- base::TimeTicks last_vsync_time;
- base::TimeDelta refresh_period;
-
- if (display_mode.Height) {
- refresh_period = base::TimeDelta::FromMicroseconds(
- 1000000 / display_mode.RefreshRate);
- // If FrameTime is not high resolution, we use a timebase of zero to avoid
- // introducing jitter into our frame start times.
- if (gfx::FrameTime::TimestampsAreHighRes()) {
- base::TimeTicks current_time = gfx::FrameTime::Now();
- last_vsync_time = current_time -
- base::TimeDelta::FromMilliseconds((clamped_scanline * 1000) /
- (display_mode.RefreshRate * display_mode.Height));
- }
- }
-
- // Wait for the StretchRect to complete before notifying the GPU process
- // that it is safe to write to its backing store again.
- {
- TRACE_EVENT0("gpu", "spin");
-
- do {
- hr = present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH);
- if (hr == S_FALSE) {
- Sleep(1);
-
- if (present_thread_->IsDeviceLost()) {
- present_thread_->ResetDevice();
- return;
- }
- }
- } while (hr == S_FALSE);
- }
-
- scoped_completion_runner.Release();
- completion_task.Run(true, last_vsync_time, refresh_period, latency_info_);
- latency_info_.Clear();
-}
-
-void AcceleratedPresenter::DoSuspend() {
- base::AutoLock locked(*present_thread_->lock());
- swap_chain_ = NULL;
-}
-
-void AcceleratedPresenter::DoReleaseSurface() {
- base::AutoLock locked(*present_thread_->lock());
- present_thread_->InitDevice();
- source_texture_.Release();
-}
-
-void AcceleratedPresenter::PresentWithGDI(HDC dc) {
- TRACE_EVENT0("gpu", "PresentWithGDI");
-
- if (!present_thread_->device()) {
- LOG(ERROR) << "No device";
- return;
- }
-
- if (!swap_chain_) {
- LOG(ERROR) << "No swap chain";
- return;
- }
-
- base::win::ScopedComPtr<IDirect3DTexture9> system_texture;
- {
- TRACE_EVENT0("gpu", "CreateSystemTexture");
- HRESULT hr = present_thread_->device()->CreateTexture(
- quantized_size_.width(),
- quantized_size_.height(),
- 1,
- 0,
- D3DFMT_A8R8G8B8,
- D3DPOOL_SYSTEMMEM,
- system_texture.Receive(),
- NULL);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to create system memory texture";
- return;
- }
- }
-
- base::win::ScopedComPtr<IDirect3DSurface9> system_surface;
- HRESULT hr = system_texture->GetSurfaceLevel(0, system_surface.Receive());
- DCHECK(SUCCEEDED(hr));
-
- base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
- hr = swap_chain_->GetBackBuffer(0,
- D3DBACKBUFFER_TYPE_MONO,
- back_buffer.Receive());
- DCHECK(SUCCEEDED(hr));
-
- {
- TRACE_EVENT0("gpu", "GetRenderTargetData");
- hr = present_thread_->device()->GetRenderTargetData(back_buffer,
- system_surface);
-
- if (FAILED(hr)) {
- if (present_thread_->IsDeviceLost()) {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PresentThread::LockAndResetDevice, present_thread_));
- }
- return;
- }
-
- DCHECK(SUCCEEDED(hr));
- }
-
- D3DLOCKED_RECT locked_surface;
- hr = system_surface->LockRect(&locked_surface, NULL, D3DLOCK_READONLY);
- DCHECK(SUCCEEDED(hr));
-
- BITMAPINFO bitmap_info = {
- {
- sizeof(BITMAPINFOHEADER),
- quantized_size_.width(),
- -quantized_size_.height(),
- 1, // planes
- 32, // bitcount
- BI_RGB
- },
- {
- {0, 0, 0, 0}
- }
- };
-
- {
- TRACE_EVENT0("gpu", "StretchDIBits");
- StretchDIBits(dc,
- 0, 0,
- present_size_.width(),
- present_size_.height(),
- 0, 0,
- present_size_.width(),
- present_size_.height(),
- locked_surface.pBits,
- &bitmap_info,
- DIB_RGB_COLORS,
- SRCCOPY);
- }
-
- system_surface->UnlockRect();
-}
-
-gfx::Size AcceleratedPresenter::GetWindowSize() {
- RECT rect;
- GetClientRect(window_, &rect);
- return gfx::Rect(rect).size();
-}
-
-bool AcceleratedPresenter::CheckDirect3DWillWork() {
- // On a composited desktop, when the screen saver or logon screen are
- // active, D3D presents never make it to the window but GDI presents
- // do. If the session is locked GDI presents can be avoided since
- // the window gets a message on unlock and forces a repaint.
- if (!is_session_locked_ && ui::win::IsAeroGlassEnabled()) {
- // Failure to open the input desktop is a sign of running with a non-default
- // desktop.
- HDESK input_desktop = ::OpenInputDesktop(0, 0, GENERIC_READ);
- if (!input_desktop)
- return false;
- ::CloseDesktop(input_desktop);
- }
-
- gfx::Size window_size = GetWindowSize();
- if (window_size != last_window_size_ && last_window_size_.GetArea() != 0) {
- last_window_size_ = window_size;
- last_window_resize_time_ = base::Time::Now();
- return false;
- }
-
- if (do_present_with_GDI_ && hidden_) {
- if (DoFirstShowPresentWithGDI())
- do_present_with_GDI_ = false;
-
- return false;
- }
-
- return base::Time::Now() - last_window_resize_time_ >
- base::TimeDelta::FromMilliseconds(100);
-}
-
-AcceleratedSurface::AcceleratedSurface(gfx::PluginWindowHandle window)
- : presenter_(g_accelerated_presenter_map.Pointer()->CreatePresenter(
- window)) {
-}
-
-AcceleratedSurface::~AcceleratedSurface() {
- g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_);
- presenter_->Invalidate();
-}
-
-void AcceleratedSurface::Present(HDC dc) {
- presenter_->Present(dc);
-}
-
-bool AcceleratedSurface::IsReadyForCopy() const {
- return !!presenter_ && presenter_->IsSwapChainInitialized();
-}
-
-
-void AcceleratedSurface::AsyncCopyTo(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
- presenter_->AsyncCopyTo(src_subrect, dst_size, callback);
-}
-
-void AcceleratedSurface::AsyncCopyToVideoFrame(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) {
- presenter_->AsyncCopyToVideoFrame(src_subrect, target, callback);
-}
-
-void AcceleratedSurface::Suspend() {
- presenter_->Suspend();
-}
-
-void AcceleratedSurface::WasHidden() {
- presenter_->WasHidden();
-}
-
-void AcceleratedSurface::SetIsSessionLocked(bool locked) {
- presenter_->SetIsSessionLocked(locked);
-}
diff --git a/chromium/ui/surface/accelerated_surface_win.h b/chromium/ui/surface/accelerated_surface_win.h
deleted file mode 100644
index 7c4164b469b..00000000000
--- a/chromium/ui/surface/accelerated_surface_win.h
+++ /dev/null
@@ -1,222 +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_SURFACE_ACCELERATED_SURFACE_WIN_H_
-#define UI_SURFACE_ACCELERATED_SURFACE_WIN_H_
-
-#include <d3d9.h>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/time/time.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/events/latency_info.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
-#include "ui/surface/surface_export.h"
-
-class PresentThread;
-
-namespace gfx {
-class Rect;
-}
-
-namespace media {
-class VideoFrame;
-}
-
-class SURFACE_EXPORT AcceleratedPresenter
- : public base::RefCountedThreadSafe<AcceleratedPresenter> {
- public:
- typedef base::Callback<void(bool,
- base::TimeTicks,
- base::TimeDelta,
- const ui::LatencyInfo&)> CompletionTask;
-
- explicit AcceleratedPresenter(gfx::PluginWindowHandle window);
-
- static void SetAdapterLUID(uint64 adapter_luid);
-
- // Returns a thread safe reference to the presenter for the given window or
- // null is no such presenter exists. The thread safe refptr ensures the
- // presenter will not be destroyed. This can be called on any thread.
- static scoped_refptr<AcceleratedPresenter> GetForWindow(
- gfx::PluginWindowHandle window);
-
- // Schedule a frame to be presented. The completion callback will be invoked
- // when it is safe to write to the surface on another thread. The lock for
- // this surface will be held while the completion callback runs. This can be
- // called on any thread.
- void AsyncPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const ui::LatencyInfo& latency_info,
- const CompletionTask& completion_task);
-
- // Returns true if the swap chain has been created and initialized. This can
- // be called on any thread.
- bool IsSwapChainInitialized() const;
-
- // Schedule the presenter to free all its resources. This can be called on any
- // thread.
- void Suspend();
-
- // Indicates that the presenter has become invisible.
- void WasHidden();
-
- // Called when the Windows session is locked or unlocked.
- void SetIsSessionLocked(bool locked);
-
- // Schedule the presenter to release its reference to the shared surface.
- void ReleaseSurface();
-
- // The public member functions are called on the main thread.
- void Present(HDC dc);
- void AsyncCopyTo(const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback);
- void AsyncCopyToVideoFrame(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback);
- void Invalidate();
-
- // Destroy any D3D resources owned by the given present thread. Called on
- // the given present thread.
- void ResetPresentThread(PresentThread* present_thread);
-
- private:
- friend class base::RefCountedThreadSafe<AcceleratedPresenter>;
-
- ~AcceleratedPresenter();
-
- // These member functions are called on the PresentThread with which the
- // presenter has affinity.
- void DoPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const ui::LatencyInfo& latency_info,
- const CompletionTask& completion_task);
- void DoSuspend();
- void DoPresent(const base::Closure& composite_task);
- void DoReleaseSurface();
- void DoCopyToAndAcknowledge(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
- const base::Callback<void(bool, const SkBitmap&)>& callback);
- void DoCopyToVideoFrameAndAcknowledge(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const scoped_refptr<base::SingleThreadTaskRunner>& callback_runner,
- const base::Callback<void(bool)>& callback);
- bool DoCopyToYUV(const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& frame);
- bool DoCopyToARGB(const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- SkBitmap* bitmap);
-
- void PresentWithGDI(HDC dc);
- gfx::Size GetWindowSize();
-
- // This function tries to guess whether Direct3D will be able to reliably
- // present to the window. When the window is resizing, presenting with
- // Direct3D causes other regions of the window rendered with GDI to
- // flicker transparent / non-transparent.
- bool CheckDirect3DWillWork();
-
- // The thread with which this presenter has affinity.
- PresentThread* const present_thread_;
-
- // The window that is presented to.
- gfx::PluginWindowHandle window_;
-
- // UI thread can wait on this event to ensure a present is finished.
- base::WaitableEvent event_;
-
- // The current size of the swap chain. This is only accessed on the thread
- // with which the surface has affinity. The swap chain size is rounded up and
- // is not necessarily the same as the window size.
- gfx::Size quantized_size_;
-
- // The size of the window on the last present. This is used to trigger the
- // compositor instead of presenting the last frame in the case where the
- // window has been resized.
- gfx::Size present_size_;
-
- // This is a shared texture that is being presented from.
- base::win::ScopedComPtr<IDirect3DTexture9> source_texture_;
-
- // The swap chain is presented to the child window. Copy semantics
- // are used so it is possible to represent it to quickly validate the window.
- base::win::ScopedComPtr<IDirect3DSwapChain9> swap_chain_;
-
- // Whether the window is hidden or has not been presented to since it was
- // last hidden.
- bool hidden_;
-
- // Set to true if the first present after the tab is unhidden needs to be done
- // with GDI.
- bool do_present_with_GDI_;
-
- // Set to true when the Windows session is locked.
- bool is_session_locked_;
-
- // These are used to detect when the window is resizing. For some reason,
- // presenting with D3D while the window resizes causes those parts not
- // drawn with D3D (e.g. with GDI) to flicker visible / invisible.
- // http://crbug.com/120904
- gfx::Size last_window_size_;
- base::Time last_window_resize_time_;
-
- ui::LatencyInfo latency_info_;
-
- DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenter);
-};
-
-class SURFACE_EXPORT AcceleratedSurface {
- public:
- AcceleratedSurface(gfx::PluginWindowHandle window);
- ~AcceleratedSurface();
-
- // Synchronously present a frame with no acknowledgement.
- void Present(HDC dc);
-
- // Returns true if the surface is fully initialized and has been presented to
- // at least once.
- bool IsReadyForCopy() const;
-
- // Transfer the contents of the surface to an SkBitmap, and invoke a callback
- // with the result.
- void AsyncCopyTo(const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback);
-
- // Transfer the contents of the surface to an already-allocated YV12
- // VideoFrame, and invoke a callback to indicate success or failure.
- void AsyncCopyToVideoFrame(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback);
-
- // Temporarily release resources until a new surface is asynchronously
- // presented. Present will not be able to represent the last surface after
- // calling this and will return false.
- void Suspend();
-
- // Indicates that the surface has become invisible.
- void WasHidden();
-
- // Called when the Windows session in locked or unlocked.
- void SetIsSessionLocked(bool locked);
-
- private:
- const scoped_refptr<AcceleratedPresenter> presenter_;
- DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface);
-};
-
-#endif // UI_SURFACE_ACCELERATED_SURFACE_WIN_H_
diff --git a/chromium/ui/surface/compile_hlsl.py b/chromium/ui/surface/compile_hlsl.py
deleted file mode 100644
index 4cc96c41435..00000000000
--- a/chromium/ui/surface/compile_hlsl.py
+++ /dev/null
@@ -1,160 +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 optparse
-import os.path
-import re
-import subprocess
-import sys
-
-
-def ConvertToCamelCase(input):
- """Converts the input string from 'unix_hacker' style to 'CamelCase' style."""
- return ''.join(x[:1].upper() + x[1:] for x in input.split('_'))
-
-
-def ExtractShaderTargetNamesFromSource(source_hlsl_file):
- """Parses '@gyp_compile' and '@gyp_namespace' metadata from an .hlsl file."""
- # matches strings like // @gyp_compile(arg_a, arg_b) ...
- gyp_compile = re.compile(
- '^//\s*@gyp_compile\(\s*(?P<profile>[a-zA-Z0-9_]+)\s*,'
- '\s*(?P<function_name>[a-zA-Z0-9_]+)\s*\).*')
- # matches strings like // @gyp_namespace(arg_a) ...
- gyp_namespace = re.compile(
- '^//\s*@gyp_namespace\(\s*(?P<namespace>[a-zA-Z0-9_]+)\s*\).*')
-
- shader_targets = [] # tuples like ('vs_2_0', 'vertexMain')
- namespace = None
- with open(source_hlsl_file) as hlsl:
- for line_number, line in enumerate(hlsl.read().splitlines(), 1):
- m = gyp_compile.match(line)
- if m:
- shader_targets.append((m.group('profile'), m.group('function_name')))
- continue
- m = gyp_namespace.match(line)
- if m:
- namespace = m.group('namespace')
- continue
- if '@gyp' in line:
- print '%s(%d) : warning: ignoring malformed @gyp directive ' % (
- source_hlsl_file, line_number)
-
- if not shader_targets:
- print (
-"""%s(%d) : error: Reached end of file without finding @gyp_compile directive.
-
- By convention, each HLSL source must contain one or more @gyp_compile
- directives in its comments, as metadata informing the Chrome build tool
- which entry points should be compiled. For example, to specify compilation
- of a function named 'vertexMain' as a shader model 2 vertex shader:
-
- // @gyp_compile(vs_2_0, vertexMain)
-
- Or to compile a pixel shader 2.0 function named 'someOtherShader':
-
- // @gyp_compile(ps_2_0, someOtherShader)
-
- To wrap everything in a C++ namespace 'foo_bar', add a line somewhere like:
-
- // @gyp_namespace(foo_bar)
-
- (Namespaces are optional)
-""" % (source_hlsl_file, line_number))
- sys.exit(1)
- return (shader_targets, namespace)
-
-
-def GetCppVariableName(function_name):
- return 'k%s' % ConvertToCamelCase(function_name)
-
-
-def CompileMultipleHLSLShadersToOneHeaderFile(fxc_compiler_path,
- source_hlsl_file,
- namespace,
- shader_targets,
- target_header_file,
- target_cc_file):
- """Compiles specified shaders from an .hlsl file into a single C++ header."""
- header_output = []
- # Invoke the compiler one at a time to write the c++ header file,
- # then read that header file into |header_output|.
- for (compiler_profile, hlsl_function_name) in shader_targets:
- file_name_only = os.path.basename(source_hlsl_file)
- base_filename, _ = os.path.splitext(file_name_only)
- cpp_global_var_name = GetCppVariableName(hlsl_function_name)
-
- command = [fxc_compiler_path,
- source_hlsl_file, # From this HLSL file
- '/E', hlsl_function_name, # Compile one function
- '/T', compiler_profile, # As a vertex or pixel shader
- '/Vn', cpp_global_var_name, # Into a C++ constant thus named
- '/Fh', target_header_file, # Declared in this C++ header file.
- '/O3'] # Fast is better than slow.
- (out, err) = subprocess.Popen(command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- shell=False).communicate()
- if err:
- print 'Error while compiling %s in file %s' % (
- hlsl_function_name, source_hlsl_file)
- print err
- sys.exit(1)
- with open(target_header_file, 'r') as header:
- header_output.append(header.read())
-
- # Now, re-write the .h and .cc files with the concatenation of all
- # the individual passes.
- classname = '%sHLSL' % (ConvertToCamelCase(base_filename))
- preamble = '\n'.join([
- '/' * 77,
- '// This file is auto-generated from %s' % file_name_only,
- '//',
- "// To edit it directly would be a fool's errand.",
- '/' * 77,
- '',
- ''])
- with open(target_header_file, 'wb') as h:
- h.write(preamble)
- h.write('#pragma once\n')
- h.write('#include <windows.h>\n\n')
- if namespace:
- h.write('namespace %s {\n\n' % namespace)
- h.write('namespace %s {\n\n' % classname)
- for _, function_name in shader_targets:
- h.write('extern const BYTE %s[];\n' % GetCppVariableName(function_name))
- h.write('\n} // namespace %s\n' % classname)
- if namespace:
- h.write('\n} // namespace %s\n' % namespace)
-
- with open(target_cc_file, 'wb') as cc:
- cc.write(preamble)
- cc.write('#include "%s"\n\n' % os.path.basename(target_header_file))
- if namespace:
- cc.write('namespace %s {\n\n' % namespace)
- cc.write('namespace %s {\n\n' % classname)
- cc.write(''.join(header_output))
- cc.write('\n} // namespace %s\n' % classname)
- if namespace:
- cc.write('\n} // namespace %s\n' % namespace)
-
-
-if __name__ == '__main__':
- parser = optparse.OptionParser()
- parser.add_option('--shader_compiler_tool', dest='compiler')
- parser.add_option('--output_h_file', dest='header_file')
- parser.add_option('--output_cc_file', dest='cc_file')
- parser.add_option('--input_hlsl_file', dest='hlsl_file')
- (options, args) = parser.parse_args()
-
- hlsl_file = os.path.abspath(options.hlsl_file)
- shader_targets, namespace = ExtractShaderTargetNamesFromSource(hlsl_file)
-
- header_file = os.path.normpath(options.header_file)
- cc_file = os.path.normpath(options.cc_file)
- CompileMultipleHLSLShadersToOneHeaderFile(options.compiler,
- hlsl_file,
- namespace,
- shader_targets,
- header_file,
- cc_file)
diff --git a/chromium/ui/surface/d3d9_utils_win.cc b/chromium/ui/surface/d3d9_utils_win.cc
deleted file mode 100644
index da82b2f29d2..00000000000
--- a/chromium/ui/surface/d3d9_utils_win.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/d3d9_utils_win.h"
-
-#include "base/debug/trace_event.h"
-#include "base/files/file_path.h"
-#include "base/scoped_native_library.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/size.h"
-
-namespace {
-
-const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
-const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";
-typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
- IDirect3D9Ex **d3d);
-} // namespace
-
-namespace ui_surface_d3d9_utils {
-
-bool LoadD3D9(base::ScopedNativeLibrary* storage) {
- storage->Reset(
- base::LoadNativeLibrary(base::FilePath(kD3D9ModuleName), NULL));
- return storage->is_valid();
-}
-
-bool CreateDevice(const base::ScopedNativeLibrary& d3d_module,
- uint64 adapter_luid,
- D3DDEVTYPE device_type,
- uint32 presentation_interval,
- IDirect3DDevice9Ex** device) {
- Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
- d3d_module.GetFunctionPointer(kCreate3D9DeviceExName));
- if (!create_func)
- return false;
-
- base::win::ScopedComPtr<IDirect3D9Ex> d3d;
- HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive());
- if (FAILED(hr))
- return false;
-
- UINT adapter = D3DADAPTER_DEFAULT;
-
- if (adapter_luid) {
- UINT adapter_count = d3d->GetAdapterCount();
- for (adapter = 0; adapter < adapter_count; ++adapter) {
- LUID luid;
- HRESULT hr = d3d->GetAdapterLUID(adapter, &luid);
- if (FAILED(hr))
- return false;
-
- if (memcmp(&luid, &adapter_luid, sizeof(adapter_luid)) == 0)
- break;
- }
-
- if (adapter == adapter_count)
- return false;
- }
-
- // Any old window will do to create the device. In practice the window to
- // present to is an argument to IDirect3DDevice9::Present.
- HWND window = GetDesktopWindow();
-
- D3DPRESENT_PARAMETERS parameters = { 0 };
- parameters.BackBufferWidth = 1;
- parameters.BackBufferHeight = 1;
- parameters.BackBufferCount = 1;
- parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
- parameters.hDeviceWindow = window;
- parameters.Windowed = TRUE;
- parameters.Flags = 0;
- parameters.PresentationInterval = presentation_interval;
- parameters.SwapEffect = D3DSWAPEFFECT_COPY;
-
- hr = d3d->CreateDeviceEx(
- adapter,
- device_type,
- window,
- D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
- D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED,
- &parameters,
- NULL,
- device);
- return SUCCEEDED(hr);
-}
-
-bool OpenSharedTexture(IDirect3DDevice9* device,
- int64 surface_handle,
- const gfx::Size& size,
- IDirect3DTexture9** opened_texture) {
- TRACE_EVENT0("gpu", "OpenSharedTexture");
- HANDLE handle = reinterpret_cast<HANDLE>(surface_handle);
- HRESULT hr = device->CreateTexture(size.width(),
- size.height(),
- 1,
- D3DUSAGE_RENDERTARGET,
- D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- opened_texture,
- &handle);
- return SUCCEEDED(hr);
-}
-
-bool CreateOrReuseLockableSurface(
- IDirect3DDevice9* device,
- const gfx::Size& size,
- base::win::ScopedComPtr<IDirect3DSurface9>* surface) {
- if (!*surface || GetSize(*surface) != size) {
- TRACE_EVENT0("gpu", "CreateRenderTarget");
- surface->Release();
- HRESULT hr = device->CreateRenderTarget(
- size.width(),
- size.height(),
- D3DFMT_A8R8G8B8,
- D3DMULTISAMPLE_NONE,
- 0,
- TRUE,
- surface->Receive(),
- NULL);
- if (FAILED(hr))
- return false;
- }
- return true;
-}
-
-bool CreateOrReuseRenderTargetTexture(
- IDirect3DDevice9* device,
- const gfx::Size& size,
- base::win::ScopedComPtr<IDirect3DTexture9>* texture,
- IDirect3DSurface9** render_target) {
- if (!*texture || GetSize(*texture) != size) {
- TRACE_EVENT0("gpu", "CreateTexture");
- texture->Release();
- HRESULT hr = device->CreateTexture(
- size.width(),
- size.height(),
- 1, // Levels
- D3DUSAGE_RENDERTARGET,
- D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- texture->Receive(),
- NULL);
- if (!SUCCEEDED(hr))
- return false;
- }
- HRESULT hr = (*texture)->GetSurfaceLevel(0, render_target);
- return SUCCEEDED(hr);
-}
-
-gfx::Size GetSize(IDirect3DSurface9* surface) {
- D3DSURFACE_DESC surface_description;
- HRESULT hr = surface->GetDesc(&surface_description);
- if (FAILED(hr))
- return gfx::Size(0, 0);
- return gfx::Size(surface_description.Width, surface_description.Height);
-}
-
-gfx::Size GetSize(IDirect3DTexture9* texture) {
- D3DSURFACE_DESC surface_description;
- HRESULT hr = texture->GetLevelDesc(0, &surface_description);
- if (FAILED(hr))
- return gfx::Size(0, 0);
- return gfx::Size(surface_description.Width, surface_description.Height);
-}
-
-} // namespace ui_surface_d3d9_utils
diff --git a/chromium/ui/surface/d3d9_utils_win.h b/chromium/ui/surface/d3d9_utils_win.h
deleted file mode 100644
index 7934cb418d5..00000000000
--- a/chromium/ui/surface/d3d9_utils_win.h
+++ /dev/null
@@ -1,87 +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.
-
-// Helper functions that Direct3D 9Ex code a little easier to work with for
-// the ui/surface code.
-
-#ifndef UI_SURFACE_D3D9_UTILS_WIN_H_
-#define UI_SURFACE_D3D9_UTILS_WIN_H_
-
-#include <d3d9.h>
-
-#include "base/basictypes.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/surface/surface_export.h"
-
-namespace base {
-class ScopedNativeLibrary;
-}
-
-namespace gfx {
-class Size;
-}
-
-namespace ui_surface_d3d9_utils {
-
-// Visible for testing. Loads the Direct3D9 library. Returns true on success.
-SURFACE_EXPORT
-bool LoadD3D9(base::ScopedNativeLibrary* storage);
-
-// Visible for testing. Creates a Direct3D9 device suitable for use with the
-// accelerated surface code. Returns true on success.
-SURFACE_EXPORT
-bool CreateDevice(const base::ScopedNativeLibrary& d3d_module,
- uint64 adapter_luid,
- D3DDEVTYPE device_type,
- uint32 presentation_interval,
- IDirect3DDevice9Ex** device);
-
-// Calls the Vista+ (WDDM1.0) variant of CreateTexture that semantically opens a
-// texture allocated as shared. In this way textures allocated by another
-// process can be used by a D3D context in this process. The shared texture is
-// identified by its surface handle. The resulting texture is written into
-// |opened_texture|.
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool OpenSharedTexture(IDirect3DDevice9* device,
- int64 surface_handle,
- const gfx::Size& size,
- IDirect3DTexture9** opened_texture);
-
-// Ensures that |surface| is a lockable surface of a specified |size|. If
-// |*surface| is non-null and has dimensions that match |size|, it is reused.
-// Otherwise, a new resource is created and the old one (if any) is freed.
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool CreateOrReuseLockableSurface(
- IDirect3DDevice9* device,
- const gfx::Size& size,
- base::win::ScopedComPtr<IDirect3DSurface9>* surface);
-
-// Ensures that |texture| is a render target texture of a specified |size|. If
-// |*texture| is non-null and has dimensions that match |size|, it is reused.
-// Otherwise, a new resource is created and the old one (if any) is freed.
-//
-// A reference to level 0 of the resulting texture is placed into
-// |render_target|.
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool CreateOrReuseRenderTargetTexture(
- IDirect3DDevice9* device,
- const gfx::Size& size,
- base::win::ScopedComPtr<IDirect3DTexture9>* texture,
- IDirect3DSurface9** render_target);
-
-SURFACE_EXPORT
-gfx::Size GetSize(IDirect3DTexture9* texture);
-
-SURFACE_EXPORT
-gfx::Size GetSize(IDirect3DSurface9* surface);
-
-} // namespace ui_surface_d3d9_utils
-
-#endif // UI_SURFACE_D3D9_UTILS_WIN_H_
diff --git a/chromium/ui/surface/surface.gyp b/chromium/ui/surface/surface.gyp
index 57a0d2cc771..710575cffa6 100644
--- a/chromium/ui/surface/surface.gyp
+++ b/chromium/ui/surface/surface.gyp
@@ -6,49 +6,19 @@
'variables': {
'chromium_code': 1,
},
-
'target_defaults': {
'conditions': [
['use_x11 == 1', {
'include_dirs': [
- '<(DEPTH)/third_party/khronos',
+ '../../third_party/khronos',
],
}],
- # TODO(ncarter): Does hlsl compilation belong in a shared location?
- ['OS == "win"', {
- 'include_dirs': [
- '<(INTERMEDIATE_DIR)/hlsl',
- ],
- 'rules': [
- {
- 'variables': {
- 'fxc': '<(windows_sdk_path)/bin/x86/fxc.exe',
- 'h_file': '<(INTERMEDIATE_DIR)/hlsl/<(RULE_INPUT_ROOT)_hlsl_compiled.h',
- 'cc_file': '<(INTERMEDIATE_DIR)/hlsl/<(RULE_INPUT_ROOT)_hlsl_compiled.cc',
- },
- 'rule_name': 'compile_hlsl',
- 'extension': 'hlsl',
- 'inputs': [
- '<(fxc)',
- 'compile_hlsl.py'
- ],
- 'outputs': [
- '<(h_file)',
- '<(cc_file)',
- ],
- 'action': [
- 'python',
- 'compile_hlsl.py',
- '--shader_compiler_tool', '<(fxc)',
- '--output_h_file', '<(h_file)',
- '--output_cc_file', '<(cc_file)',
- '--input_hlsl_file', '<(RULE_INPUT_PATH)',
- ],
- 'msvs_cygwin_shell': 0,
- 'message': 'Generating shaders from <(RULE_INPUT_PATH)',
- 'process_outputs_as_sources': 1,
- },
- ],
+ ['OS == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/IOSurface.framework',
+ ],
+ },
}],
],
},
@@ -57,31 +27,19 @@
'target_name': 'surface',
'type': '<(component)',
'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '<(DEPTH)/media/media.gyp:media',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/ui/events/events.gyp:events_base',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
- '<(DEPTH)/ui/gl/gl.gyp:gl',
- '<(DEPTH)/ui/ui.gyp:ui',
+ '../../base/base.gyp:base',
+ '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../gl/gl.gyp:gl',
],
'sources': [
'accelerated_surface_mac.cc',
'accelerated_surface_mac.h',
- 'accelerated_surface_transformer_win.cc',
- 'accelerated_surface_transformer_win.h',
- 'accelerated_surface_transformer_win.hlsl',
- 'accelerated_surface_win.cc',
- 'accelerated_surface_win.h',
- 'd3d9_utils_win.cc',
- 'd3d9_utils_win.h',
'surface_export.h',
- 'surface_switches.h',
- 'surface_switches.cc',
'transport_dib.h',
'transport_dib.cc',
- 'transport_dib_gtk.cc',
'transport_dib_posix.cc',
'transport_dib_win.cc',
],
@@ -90,28 +48,4 @@
],
},
],
- 'conditions': [
- ['OS == "win"', {
- 'targets': [
- {
- 'target_name': 'surface_gpu_tests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/base/base.gyp:run_all_unittests',
- '<(DEPTH)/media/media.gyp:media',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- '<(DEPTH)/ui/events/events.gyp:events_base',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
- '<(DEPTH)/ui/ui.gyp:ui',
- 'surface',
- ],
- 'sources': [
- 'accelerated_surface_transformer_win_unittest.cc',
- ],
- },
- ],
- }],
- ],
}
diff --git a/chromium/ui/surface/surface_switches.cc b/chromium/ui/surface/surface_switches.cc
deleted file mode 100644
index ab8b608518d..00000000000
--- a/chromium/ui/surface/surface_switches.cc
+++ /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.
-
-#include "ui/surface/surface_switches.h"
-
-namespace switches {
-
-// Flags for enabling speculative fix for http://crbug.com/169848
-
-// Use GDI to do every first Present after the tab is unhidden.
-const char kDoAllShowPresentWithGDI[] = "all-show-present-with-GDI";
-
-// Use GDI to do the fist Present after the tab is unhidden.
-const char kDoFirstShowPresentWithGDI[] = "first-show-present-with-GDI";
-
-
-} // namespace switches
-
diff --git a/chromium/ui/surface/surface_switches.h b/chromium/ui/surface/surface_switches.h
deleted file mode 100644
index 13eabb52c30..00000000000
--- a/chromium/ui/surface/surface_switches.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_SURFACE_SURFACE_SWITCHES_H_
-#define UI_SURFACE_SURFACE_SWITCHES_H_
-
-#include "ui/surface/surface_export.h"
-
-// Defines all the command-line switches used by ui/surface.
-
-namespace switches {
-
-SURFACE_EXPORT extern const char kDoAllShowPresentWithGDI[];
-SURFACE_EXPORT extern const char kDoFirstShowPresentWithGDI[];
-
-} // namespace switches
-
-#endif // UI_SURFACE_SURFACE_SWITCHES_H_
diff --git a/chromium/ui/surface/transport_dib.h b/chromium/ui/surface/transport_dib.h
index 7ec7bb815f7..fa2d13283e1 100644
--- a/chromium/ui/surface/transport_dib.h
+++ b/chromium/ui/surface/transport_dib.h
@@ -6,17 +6,11 @@
#define UI_SURFACE_TRANSPORT_DIB_H_
#include "base/basictypes.h"
-#include "ui/surface/surface_export.h"
-
-#if !defined(TOOLKIT_GTK)
#include "base/memory/shared_memory.h"
-#endif
+#include "ui/surface/surface_export.h"
#if defined(OS_WIN)
#include <windows.h>
-#elif defined(TOOLKIT_GTK)
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/x/x11_types.h"
#endif
class SkCanvas;
@@ -74,41 +68,6 @@ class SURFACE_EXPORT TransportDIB {
// Returns a default, invalid handle, that is meant to indicate a missing
// Transport DIB.
static Handle DefaultHandleValue() { return NULL; }
-
- // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
- // ACTUALLY USED AS A REAL HANDLE.
- static Handle GetFakeHandleForTest() {
- static int fake_handle = 10;
- return reinterpret_cast<Handle>(fake_handle++);
- }
-#elif defined(TOOLKIT_GTK)
- typedef int Handle; // These two ints are SysV IPC shared memory keys
- struct Id {
- // Ensure that default initialized Ids are invalid.
- Id() : shmkey(-1) {
- }
-
- bool operator<(const Id& other) const {
- return shmkey < other.shmkey;
- }
-
- bool operator==(const Id& other) const {
- return shmkey == other.shmkey;
- }
-
- int shmkey;
- };
-
- // Returns a default, invalid handle, that is meant to indicate a missing
- // Transport DIB.
- static Handle DefaultHandleValue() { return -1; }
-
- // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
- // ACTUALLY USED AS A REAL HANDLE.
- static Handle GetFakeHandleForTest() {
- static int fake_handle = 10;
- return fake_handle++;
- }
#else // OS_POSIX
typedef base::SharedMemoryHandle Handle;
// On POSIX, the inode number of the backing file is used as an id.
@@ -121,13 +80,6 @@ class SURFACE_EXPORT TransportDIB {
// Returns a default, invalid handle, that is meant to indicate a missing
// Transport DIB.
static Handle DefaultHandleValue() { return Handle(); }
-
- // Returns a value that is ONLY USEFUL FOR TESTS WHERE IT WON'T BE
- // ACTUALLY USED AS A REAL HANDLE.
- static Handle GetFakeHandleForTest() {
- static int fake_handle = 10;
- return Handle(fake_handle++, false);
- }
#endif
// Create a new TransportDIB, returning NULL on failure.
@@ -187,39 +139,15 @@ class SURFACE_EXPORT TransportDIB {
// wire to give this transport DIB to another process.
Handle handle() const;
-#if defined(TOOLKIT_GTK)
- // Map the shared memory into the X server and return an id for the shared
- // segment.
- XID MapToX(XDisplay* connection);
-
- void IncreaseInFlightCounter() { inflight_counter_++; }
- // Decreases the inflight counter, and deletes the transport DIB if it is
- // detached.
- void DecreaseInFlightCounter();
-
- // Deletes this transport DIB and detaches the shared memory once the
- // |inflight_counter_| is zero.
- void Detach();
-#endif
-
private:
TransportDIB();
// Verifies that the dib can hold a canvas of the requested dimensions.
bool VerifyCanvasSize(int w, int h);
-#if defined(TOOLKIT_GTK)
- Id key_; // SysV shared memory id
- void* address_; // mapped address
- XSharedMemoryId x_shm_; // X id for the shared segment
- XDisplay* display_; // connection to the X server
- size_t inflight_counter_; // How many requests to the X server are in flight
- bool detached_; // If true, delete the transport DIB when it is idle
-#else
explicit TransportDIB(base::SharedMemoryHandle dib);
base::SharedMemory shared_memory_;
uint32 sequence_num_;
-#endif
size_t size_; // length, in bytes
DISALLOW_COPY_AND_ASSIGN(TransportDIB);
diff --git a/chromium/ui/surface/transport_dib_gtk.cc b/chromium/ui/surface/transport_dib_gtk.cc
deleted file mode 100644
index 61ec624c065..00000000000
--- a/chromium/ui/surface/transport_dib_gtk.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/transport_dib.h"
-
-// Desktop GTK Linux builds use the old-style SYSV SHM based DIBs.
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "skia/ext/platform_canvas.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/size.h"
-
-// The shmat system call uses this as it's invalid return address
-static void *const kInvalidAddress = (void*) -1;
-
-TransportDIB::TransportDIB()
- : address_(kInvalidAddress),
- x_shm_(0),
- display_(NULL),
- inflight_counter_(0),
- detached_(false),
- size_(0) {
-}
-
-TransportDIB::~TransportDIB() {
- if (address_ != kInvalidAddress) {
- shmdt(address_);
- address_ = kInvalidAddress;
- }
-
- if (x_shm_) {
- DCHECK(display_);
- ui::DetachSharedMemory(display_, x_shm_);
- }
-}
-
-// static
-TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
- const int shmkey = shmget(IPC_PRIVATE, size, 0600);
- if (shmkey == -1) {
- DLOG(ERROR) << "Failed to create SysV shared memory region"
- << " errno:" << errno;
- return NULL;
- } else {
- VLOG(1) << "Created SysV shared memory region " << shmkey;
- }
-
- void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
- // Here we mark the shared memory for deletion. Since we attached it in the
- // line above, it doesn't actually get deleted but, if we crash, this means
- // that the kernel will automatically clean it up for us.
- shmctl(shmkey, IPC_RMID, 0);
- if (address == kInvalidAddress)
- return NULL;
-
- TransportDIB* dib = new TransportDIB;
-
- dib->key_.shmkey = shmkey;
- dib->address_ = address;
- dib->size_ = size;
- return dib;
-}
-
-// static
-TransportDIB* TransportDIB::Map(Handle handle) {
- scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
- if (!dib->Map())
- return NULL;
- return dib.release();
-}
-
-// static
-TransportDIB* TransportDIB::CreateWithHandle(Handle shmkey) {
- TransportDIB* dib = new TransportDIB;
- dib->key_.shmkey = shmkey;
- return dib;
-}
-
-// static
-bool TransportDIB::is_valid_handle(Handle dib) {
- return dib >= 0;
-}
-
-// static
-bool TransportDIB::is_valid_id(Id id) {
- return id.shmkey != -1;
-}
-
-skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
- if ((address_ == kInvalidAddress && !Map()) || !VerifyCanvasSize(w, h))
- return NULL;
- return skia::CreatePlatformCanvas(w, h, true,
- reinterpret_cast<uint8_t*>(memory()),
- skia::RETURN_NULL_ON_FAILURE);
-}
-
-bool TransportDIB::Map() {
- if (!is_valid_id(key_))
- return false;
- if (address_ != kInvalidAddress)
- return true;
-
- struct shmid_ds shmst;
- if (shmctl(key_.shmkey, IPC_STAT, &shmst) == -1)
- return false;
-
- void* address = shmat(key_.shmkey, NULL /* desired address */, 0 /* flags */);
- if (address == kInvalidAddress)
- return false;
-
- address_ = address;
- size_ = shmst.shm_segsz;
- return true;
-}
-
-void* TransportDIB::memory() const {
- DCHECK_NE(address_, kInvalidAddress);
- return address_;
-}
-
-TransportDIB::Id TransportDIB::id() const {
- return key_;
-}
-
-TransportDIB::Handle TransportDIB::handle() const {
- return key_.shmkey;
-}
-
-XID TransportDIB::MapToX(XDisplay* display) {
- if (!x_shm_) {
- x_shm_ = ui::AttachSharedMemory(display, key_.shmkey);
- display_ = display;
- }
-
- return x_shm_;
-}
-
-void TransportDIB::DecreaseInFlightCounter() {
- CHECK(inflight_counter_);
- inflight_counter_--;
- if (!inflight_counter_ && detached_)
- delete this;
-}
-
-void TransportDIB::Detach() {
- CHECK(!detached_);
- detached_ = true;
- if (!inflight_counter_)
- delete this;
-}
-
diff --git a/chromium/ui/surface/transport_dib_posix.cc b/chromium/ui/surface/transport_dib_posix.cc
index 28095f2c940..284ed33034d 100644
--- a/chromium/ui/surface/transport_dib_posix.cc
+++ b/chromium/ui/surface/transport_dib_posix.cc
@@ -4,9 +4,6 @@
#include "ui/surface/transport_dib.h"
-// Desktop GTK Linux builds use the old-style SYSV SHM based DIBs.
-#if !defined(TOOLKIT_GTK)
-
#include <sys/stat.h>
#include <unistd.h>
@@ -111,6 +108,3 @@ TransportDIB::Id TransportDIB::id() const {
TransportDIB::Handle TransportDIB::handle() const {
return shared_memory_.handle();
}
-
-#endif // !defined(TOOLKIT_GTK)
-
diff --git a/chromium/ui/ui.gyp b/chromium/ui/ui.gyp
deleted file mode 100644
index 5d61dc44043..00000000000
--- a/chromium/ui/ui.gyp
+++ /dev/null
@@ -1,702 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- 'target_name': 'ui',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../base/base.gyp:base_static',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- '../third_party/libpng/libpng.gyp:libpng',
- '../third_party/zlib/zlib.gyp:zlib',
- '../url/url.gyp:url_lib',
- 'base/strings/ui_strings.gyp:ui_strings',
- 'events/events.gyp:events_base',
- 'gfx/gfx.gyp:gfx',
- 'resources/ui_resources.gyp:ui_resources',
- ],
- 'defines': [
- 'UI_IMPLEMENTATION',
- ],
- 'export_dependent_settings': [
- '../net/net.gyp:net',
- 'gfx/gfx.gyp:gfx',
- ],
- 'sources' : [
- 'base/accelerators/accelerator.cc',
- 'base/accelerators/accelerator.h',
- 'base/accelerators/accelerator_manager.cc',
- 'base/accelerators/accelerator_manager.h',
- 'base/accelerators/menu_label_accelerator_util_linux.cc',
- 'base/accelerators/menu_label_accelerator_util_linux.h',
- 'base/accelerators/platform_accelerator.h',
- 'base/accelerators/platform_accelerator_cocoa.h',
- 'base/accelerators/platform_accelerator_cocoa.mm',
- 'base/accelerators/platform_accelerator_gtk.cc',
- 'base/accelerators/platform_accelerator_gtk.h',
- 'base/accessibility/accessibility_types.h',
- 'base/accessibility/accessible_text_utils.cc',
- 'base/accessibility/accessible_text_utils.h',
- 'base/accessibility/accessible_view_state.cc',
- 'base/accessibility/accessible_view_state.h',
- 'base/android/ui_base_jni_registrar.cc',
- 'base/android/ui_base_jni_registrar.h',
- 'base/android/view_android.cc',
- 'base/android/view_android.h',
- 'base/android/window_android.cc',
- 'base/android/window_android.h',
- 'base/android/window_android_observer.h',
- 'base/base_window.cc',
- 'base/base_window.h',
- 'base/clipboard/clipboard.cc',
- 'base/clipboard/clipboard.h',
- 'base/clipboard/clipboard_android.cc',
- 'base/clipboard/clipboard_android_initialization.h',
- 'base/clipboard/clipboard_aura.cc',
- 'base/clipboard/clipboard_aurax11.cc',
- 'base/clipboard/clipboard_constants.cc',
- 'base/clipboard/clipboard_gtk.cc',
- 'base/clipboard/clipboard_mac.mm',
- 'base/clipboard/clipboard_types.h',
- 'base/clipboard/clipboard_util_win.cc',
- 'base/clipboard/clipboard_util_win.h',
- 'base/clipboard/clipboard_win.cc',
- 'base/clipboard/custom_data_helper.cc',
- 'base/clipboard/custom_data_helper.h',
- 'base/clipboard/custom_data_helper_linux.cc',
- 'base/clipboard/custom_data_helper_mac.mm',
- 'base/clipboard/scoped_clipboard_writer.cc',
- 'base/clipboard/scoped_clipboard_writer.h',
- 'base/cocoa/animation_utils.h',
- 'base/cocoa/appkit_utils.h',
- 'base/cocoa/appkit_utils.mm',
- 'base/cocoa/base_view.h',
- 'base/cocoa/base_view.mm',
- 'base/cocoa/cocoa_event_utils.h',
- 'base/cocoa/cocoa_event_utils.mm',
- 'base/cocoa/controls/blue_label_button.h',
- 'base/cocoa/controls/blue_label_button.mm',
- 'base/cocoa/controls/hover_image_menu_button.h',
- 'base/cocoa/controls/hover_image_menu_button.mm',
- 'base/cocoa/controls/hover_image_menu_button_cell.h',
- 'base/cocoa/controls/hover_image_menu_button_cell.mm',
- 'base/cocoa/controls/hyperlink_button_cell.h',
- 'base/cocoa/controls/hyperlink_button_cell.mm',
- 'base/cocoa/find_pasteboard.h',
- 'base/cocoa/find_pasteboard.mm',
- 'base/cocoa/flipped_view.h',
- 'base/cocoa/flipped_view.mm',
- 'base/cocoa/focus_tracker.h',
- 'base/cocoa/focus_tracker.mm',
- 'base/cocoa/focus_window_set.h',
- 'base/cocoa/focus_window_set.mm',
- 'base/cocoa/fullscreen_window_manager.h',
- 'base/cocoa/fullscreen_window_manager.mm',
- 'base/cocoa/hover_button.h',
- 'base/cocoa/hover_button.mm',
- 'base/cocoa/hover_image_button.h',
- 'base/cocoa/hover_image_button.mm',
- 'base/cocoa/menu_controller.h',
- 'base/cocoa/menu_controller.mm',
- 'base/cocoa/nib_loading.h',
- 'base/cocoa/nib_loading.mm',
- 'base/cocoa/nsgraphics_context_additions.h',
- 'base/cocoa/nsgraphics_context_additions.mm',
- 'base/cocoa/tracking_area.h',
- 'base/cocoa/tracking_area.mm',
- 'base/cocoa/underlay_opengl_hosting_window.h',
- 'base/cocoa/underlay_opengl_hosting_window.mm',
- 'base/cocoa/view_description.h',
- 'base/cocoa/view_description.mm',
- 'base/cocoa/window_size_constants.h',
- 'base/cocoa/window_size_constants.mm',
- 'base/cursor/cursor.cc',
- 'base/cursor/cursor.h',
- 'base/cursor/cursor_loader.h',
- 'base/cursor/cursor_loader_null.cc',
- 'base/cursor/cursor_loader_null.h',
- 'base/cursor/cursor_loader_win.cc',
- 'base/cursor/cursor_loader_win.h',
- 'base/cursor/cursor_loader_x11.cc',
- 'base/cursor/cursor_loader_x11.h',
- 'base/cursor/cursor_null.cc',
- 'base/cursor/cursor_win.cc',
- 'base/cursor/cursor_x11.cc',
- 'base/cursor/cursors_aura.cc',
- 'base/cursor/cursors_aura.h',
- 'base/default_theme_provider.cc',
- 'base/default_theme_provider.h',
- 'base/default_theme_provider_mac.mm',
- 'base/device_form_factor_android.cc',
- 'base/device_form_factor_desktop.cc',
- 'base/device_form_factor_ios.mm',
- 'base/device_form_factor.h',
- 'base/dragdrop/cocoa_dnd_util.h',
- 'base/dragdrop/cocoa_dnd_util.mm',
- 'base/dragdrop/drag_drop_types.h',
- 'base/dragdrop/drag_drop_types_win.cc',
- 'base/dragdrop/drag_source_win.cc',
- 'base/dragdrop/drag_source_win.h',
- 'base/dragdrop/drag_utils.cc',
- 'base/dragdrop/drag_utils.h',
- 'base/dragdrop/drag_utils_aura.cc',
- 'base/dragdrop/drag_utils_win.cc',
- 'base/dragdrop/drop_target_event.cc',
- 'base/dragdrop/drop_target_event.h',
- 'base/dragdrop/drop_target_win.cc',
- 'base/dragdrop/drop_target_win.h',
- 'base/dragdrop/gtk_dnd_util.cc',
- 'base/dragdrop/gtk_dnd_util.h',
- 'base/dragdrop/os_exchange_data.cc',
- 'base/dragdrop/os_exchange_data.h',
- 'base/dragdrop/os_exchange_data_provider_aura.cc',
- 'base/dragdrop/os_exchange_data_provider_aura.h',
- 'base/dragdrop/os_exchange_data_provider_aurax11.cc',
- 'base/dragdrop/os_exchange_data_provider_aurax11.h',
- 'base/dragdrop/os_exchange_data_provider_win.cc',
- 'base/dragdrop/os_exchange_data_provider_win.h',
- 'base/gtk/event_synthesis_gtk.cc',
- 'base/gtk/event_synthesis_gtk.h',
- 'base/gtk/focus_store_gtk.cc',
- 'base/gtk/focus_store_gtk.h',
- 'base/gtk/g_object_destructor_filo.cc',
- 'base/gtk/g_object_destructor_filo.h',
- 'base/gtk/gtk_expanded_container.cc',
- 'base/gtk/gtk_expanded_container.h',
- 'base/gtk/gtk_floating_container.cc',
- 'base/gtk/gtk_floating_container.h',
- 'base/gtk/gtk_hig_constants.h',
- 'base/gtk/gtk_screen_util.cc',
- 'base/gtk/gtk_screen_util.h',
- 'base/gtk/gtk_signal.h',
- 'base/gtk/gtk_signal_registrar.cc',
- 'base/gtk/gtk_signal_registrar.h',
- 'base/gtk/gtk_windowing.cc',
- 'base/gtk/gtk_windowing.h',
- 'base/gtk/owned_widget_gtk.cc',
- 'base/gtk/owned_widget_gtk.h',
- 'base/gtk/scoped_region.cc',
- 'base/gtk/scoped_region.h',
- 'base/hit_test.h',
- 'base/l10n/l10n_font_util.cc',
- 'base/l10n/l10n_font_util.h',
- 'base/l10n/l10n_util.cc',
- 'base/l10n/l10n_util.h',
- 'base/l10n/l10n_util_android.cc',
- 'base/l10n/l10n_util_android.h',
- 'base/l10n/l10n_util_collator.h',
- 'base/l10n/l10n_util_mac.h',
- 'base/l10n/l10n_util_mac.mm',
- 'base/l10n/l10n_util_plurals.cc',
- 'base/l10n/l10n_util_plurals.h',
- 'base/l10n/l10n_util_posix.cc',
- 'base/l10n/l10n_util_win.cc',
- 'base/l10n/l10n_util_win.h',
- 'base/l10n/time_format.cc',
- 'base/l10n/time_format.h',
- 'base/layout.cc',
- 'base/layout.h',
- 'base/layout_mac.mm',
- 'base/models/button_menu_item_model.cc',
- 'base/models/button_menu_item_model.h',
- 'base/models/combobox_model.cc',
- 'base/models/combobox_model.h',
- 'base/models/combobox_model_observer.h',
- 'base/models/dialog_model.cc',
- 'base/models/dialog_model.h',
- 'base/models/list_model.h',
- 'base/models/list_model_observer.h',
- 'base/models/list_selection_model.cc',
- 'base/models/list_selection_model.h',
- 'base/models/menu_model.cc',
- 'base/models/menu_model.h',
- 'base/models/menu_model_delegate.h',
- 'base/models/menu_separator_types.h',
- 'base/models/simple_menu_model.cc',
- 'base/models/simple_menu_model.h',
- 'base/models/table_model.cc',
- 'base/models/table_model.h',
- 'base/models/table_model_observer.h',
- 'base/models/tree_model.cc',
- 'base/models/tree_model.h',
- 'base/models/tree_node_iterator.h',
- 'base/models/tree_node_model.h',
- 'base/resource/data_pack.cc',
- 'base/resource/data_pack.h',
- 'base/resource/resource_bundle.cc',
- 'base/resource/resource_bundle.h',
- 'base/resource/resource_bundle_android.cc',
- 'base/resource/resource_bundle_auralinux.cc',
- 'base/resource/resource_bundle_gtk.cc',
- 'base/resource/resource_bundle_ios.mm',
- 'base/resource/resource_bundle_mac.mm',
- 'base/resource/resource_bundle_win.cc',
- 'base/resource/resource_bundle_win.h',
- 'base/resource/resource_data_dll_win.cc',
- 'base/resource/resource_data_dll_win.h',
- 'base/resource/resource_handle.h',
- 'base/text/bytes_formatting.cc',
- 'base/text/bytes_formatting.h',
- 'base/theme_provider.cc',
- 'base/theme_provider.h',
- 'base/touch/touch_device.cc',
- 'base/touch/touch_device.h',
- 'base/touch/touch_device_android.cc',
- 'base/touch/touch_device_aurax11.cc',
- 'base/touch/touch_device_ozone.cc',
- 'base/touch/touch_device_win.cc',
- 'base/touch/touch_editing_controller.cc',
- 'base/touch/touch_editing_controller.h',
- 'base/touch/touch_enabled.cc',
- 'base/touch/touch_enabled.h',
- 'base/ui_base_exports.cc',
- 'base/ui_base_paths.cc',
- 'base/ui_base_paths.h',
- 'base/ui_base_switches.cc',
- 'base/ui_base_switches.h',
- 'base/ui_base_switches_util.cc',
- 'base/ui_base_switches_util.h',
- 'base/ui_base_types.cc',
- 'base/ui_base_types.h',
- 'base/ui_export.h',
- 'base/view_prop.cc',
- 'base/view_prop.h',
- 'base/webui/jstemplate_builder.cc',
- 'base/webui/jstemplate_builder.h',
- 'base/webui/web_ui_util.cc',
- 'base/webui/web_ui_util.h',
- 'base/win/accessibility_ids_win.h',
- 'base/win/accessibility_misc_utils.cc',
- 'base/win/accessibility_misc_utils.h',
- 'base/win/atl_module.h',
- 'base/win/dpi_setup.cc',
- 'base/win/dpi_setup.h',
- 'base/win/foreground_helper.cc',
- 'base/win/foreground_helper.h',
- 'base/win/hidden_window.cc',
- 'base/win/hidden_window.h',
- 'base/win/hwnd_subclass.cc',
- 'base/win/hwnd_subclass.h',
- 'base/win/lock_state.cc',
- 'base/win/lock_state.h',
- 'base/win/message_box_win.cc',
- 'base/win/message_box_win.h',
- 'base/win/mouse_wheel_util.cc',
- 'base/win/mouse_wheel_util.h',
- 'base/win/scoped_ole_initializer.cc',
- 'base/win/scoped_ole_initializer.h',
- 'base/win/shell.cc',
- 'base/win/shell.h',
- 'base/win/touch_input.cc',
- 'base/win/touch_input.h',
- 'base/window_open_disposition.cc',
- 'base/window_open_disposition.h',
- 'base/work_area_watcher_observer.h',
- 'base/x/active_window_watcher_x.cc',
- 'base/x/active_window_watcher_x.h',
- 'base/x/active_window_watcher_x_observer.h',
- 'base/x/root_window_property_watcher_x.cc',
- 'base/x/root_window_property_watcher_x.h',
- 'base/x/selection_owner.cc',
- 'base/x/selection_owner.h',
- 'base/x/selection_requestor.cc',
- 'base/x/selection_requestor.h',
- 'base/x/selection_utils.cc',
- 'base/x/selection_utils.h',
- 'base/x/work_area_watcher_x.cc',
- 'base/x/work_area_watcher_x.h',
- 'base/x/x11_util.cc',
- 'base/x/x11_util.h',
- 'base/x/x11_util_internal.h',
- ],
- 'target_conditions': [
- ['OS == "ios"', {
- 'sources/': [
- ['include', '^base/l10n/l10n_util_mac\\.mm$'],
- ],
- }],
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'includes': [
- 'base/ime/ime.gypi',
- ],
- }, { # OS=="ios"
- # iOS only uses a subset of UI.
- 'sources/': [
- ['exclude', '\\.(cc|mm)$'],
- ['include', '_ios\\.(cc|mm)$'],
- ['include', '(^|/)ios/'],
- ['include', '^base/l10n/'],
- ['include', '^base/layout'],
- ['include', '^base/resource/'],
- ['include', '^base/ui_base_'],
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
- ],
- },
- }],
- ['toolkit_views==1', {
- 'dependencies': [
- 'events/events.gyp:events',
- ],
- }],
- ['use_aura==1', {
- 'sources/': [
- ['exclude', 'base/work_area_watcher_observer.h'],
- ['exclude', 'base/x/active_window_watcher_x.cc'],
- ['exclude', 'base/x/active_window_watcher_x.h'],
- ['exclude', 'base/x/active_window_watcher_x_observer.h'],
- ['exclude', 'base/x/root_window_property_watcher_x.cc'],
- ['exclude', 'base/x/root_window_property_watcher_x.h'],
- ['exclude', 'base/x/work_area_watcher_x.cc'],
- ['exclude', 'base/x/work_area_watcher_x.h'],
- ],
- 'dependencies': [
- 'events/events.gyp:events',
- ],
- }, { # use_aura!=1
- 'sources!': [
- 'base/cursor/cursor.cc',
- 'base/cursor/cursor.h',
- 'base/cursor/cursor_loader_x11.cc',
- 'base/cursor/cursor_loader_x11.h',
- 'base/cursor/cursor_win.cc',
- 'base/cursor/cursor_x11.cc',
- 'base/x/selection_owner.cc',
- 'base/x/selection_owner.h',
- 'base/x/selection_requestor.cc',
- 'base/x/selection_requestor.h',
- 'base/x/selection_utils.cc',
- 'base/x/selection_utils.h',
- ]
- }],
- ['use_aura==0 or OS!="linux"', {
- 'sources!': [
- 'base/resource/resource_bundle_auralinux.cc',
- ],
- }],
- ['use_aura==1 and OS=="win"', {
- 'sources/': [
- ['exclude', 'base/dragdrop/drag_utils_aura.cc'],
- ],
- }],
- ['use_glib == 1', {
- 'dependencies': [
- # font_gtk.cc uses fontconfig.
- '../build/linux/system.gyp:fontconfig',
- '../build/linux/system.gyp:glib',
- ],
- }],
- ['desktop_linux == 1 or chromeos == 1', {
- 'conditions': [
- ['toolkit_views==0 and use_aura==0', {
- # Note: because of gyp predence rules this has to be defined as
- # 'sources/' rather than 'sources!'.
- 'sources/': [
- ['exclude', '^base/dragdrop/drag_utils.cc'],
- ['exclude', '^base/dragdrop/drag_utils.h'],
- ['exclude', '^base/dragdrop/os_exchange_data.cc'],
- ['exclude', '^base/dragdrop/os_exchange_data.h'],
- ],
- }, {
- # Note: because of gyp predence rules this has to be defined as
- # 'sources/' rather than 'sources!'.
- 'sources/': [
- ['include', '^base/dragdrop/os_exchange_data.cc'],
- ],
- }],
- ],
- }],
- ['use_pango==1', {
- 'dependencies': [
- '../build/linux/system.gyp:pangocairo',
- ],
- }],
- ['use_x11==0 or use_clipboard_aurax11==1', {
- 'sources!': [
- 'base/clipboard/clipboard_aura.cc',
- ],
- }, {
- 'sources!': [
- 'base/clipboard/clipboard_aurax11.cc',
- ],
- }],
- ['chromeos==1 or (use_aura==1 and OS=="linux" and use_x11==0)', {
- 'sources!': [
- 'base/dragdrop/os_exchange_data_provider_aurax11.cc',
- 'base/touch/touch_device.cc',
- ],
- }, {
- 'sources!': [
- 'base/dragdrop/os_exchange_data_provider_aura.cc',
- 'base/dragdrop/os_exchange_data_provider_aura.h',
- 'base/touch/touch_device_aurax11.cc',
- ],
- }],
- ['OS=="win"', {
- 'sources!': [
- 'base/touch/touch_device.cc',
- ],
- 'include_dirs': [
- '../',
- '../third_party/wtl/include',
- ],
- # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int
- # C4324 is structure was padded due to __declspec(align()), which is
- # uninteresting.
- 'msvs_disabled_warnings': [ 4267, 4324 ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'DelayLoadDLLs': [
- 'd2d1.dll',
- 'd3d10_1.dll',
- 'dwmapi.dll',
- ],
- 'AdditionalDependencies': [
- 'd2d1.lib',
- 'd3d10_1.lib',
- 'dwmapi.lib',
- ],
- },
- },
- 'link_settings': {
- 'libraries': [
- '-limm32.lib',
- '-ld2d1.lib',
- '-ldwmapi.lib',
- '-loleacc.lib',
- ],
- },
- },{ # OS!="win"
- 'conditions': [
- ['use_aura==0', {
- 'sources!': [
- 'base/view_prop.cc',
- 'base/view_prop.h',
- ],
- }],
- ],
- 'sources!': [
- 'base/dragdrop/drag_drop_types.h',
- 'base/dragdrop/os_exchange_data.cc',
- ],
- 'sources/': [
- ['exclude', '^base/win/'],
- ],
- }],
- ['OS=="mac"', {
- 'dependencies': [
- '../third_party/mozilla/mozilla.gyp:mozilla',
- ],
- 'sources!': [
- 'base/dragdrop/drag_utils.cc',
- 'base/dragdrop/drag_utils.h',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Accelerate.framework',
- '$(SDKROOT)/System/Library/Frameworks/AudioUnit.framework',
- '$(SDKROOT)/System/Library/Frameworks/CoreVideo.framework',
- ],
- },
- }],
- ['use_x11==1', {
- 'all_dependent_settings': {
- 'ldflags': [
- '-L<(PRODUCT_DIR)',
- ],
- 'link_settings': {
- 'libraries': [
- '-lX11',
- '-lXcursor',
- '-lXrender', # For XRender* function calls in x11_util.cc.
- ],
- },
- },
- 'link_settings': {
- 'libraries': [
- '-lX11',
- '-lXcursor',
- '-lXrender', # For XRender* function calls in x11_util.cc.
- ],
- },
- 'dependencies': [
- '../build/linux/system.gyp:x11',
- '../build/linux/system.gyp:xext',
- '../build/linux/system.gyp:xfixes',
- ],
- }],
- ['use_ozone==0', {
- 'sources!': [
- 'base/cursor/cursor_null.cc',
- 'base/cursor/cursor_loader_null.cc',
- 'base/cursor/cursor_loader_null.h',
- ],
- }],
- ['toolkit_views==0', {
- 'sources!': [
- 'base/dragdrop/drop_target_event.cc',
- 'base/dragdrop/drop_target_event.h',
- ],
- }],
- ['OS=="android"', {
- 'sources!': [
- 'base/accessibility/accessible_text_utils.cc',
- 'base/accessibility/accessible_view_state.cc',
- 'base/default_theme_provider.cc',
- 'base/dragdrop/drag_utils.cc',
- 'base/dragdrop/drag_utils.h',
- 'base/l10n/l10n_font_util.cc',
- 'base/models/button_menu_item_model.cc',
- 'base/models/dialog_model.cc',
- 'base/theme_provider.cc',
- 'base/touch/touch_device.cc',
- 'base/touch/touch_editing_controller.cc',
- 'base/ui_base_types.cc',
- ],
- 'dependencies': [
- 'ui_base_jni_headers',
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/ui',
- ],
- 'link_settings': {
- 'libraries': [
- '-ljnigraphics',
- ],
- },
- }],
- ['OS=="android" and android_webview_build==0', {
- 'dependencies': [
- 'android/ui_android.gyp:ui_java',
- ],
- }],
- ['OS=="android" or OS=="ios"', {
- 'sources!': [
- 'base/device_form_factor_desktop.cc'
- ],
- }],
- ['OS=="linux"', {
- 'libraries': [
- '-ldl',
- ],
- }],
- ['use_system_icu==1', {
- # When using the system icu, the icu targets generate shim headers
- # which are included by public headers in the ui target, so we need
- # ui to be a hard dependency for all its users.
- 'hard_dependency': 1,
- }],
- ],
- },
- {
- 'target_name': 'webui_test_support',
- 'type': 'none',
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources',
- ]
- }
- },
- ],
- 'conditions': [
- ['OS=="android"' , {
- 'targets': [
- {
- 'target_name': 'ui_base_jni_headers',
- 'type': 'none',
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/ui',
- ],
- },
- 'sources': [
- 'android/java/src/org/chromium/ui/base/Clipboard.java',
- 'android/java/src/org/chromium/ui/base/LocalizationUtils.java',
- 'android/java/src/org/chromium/ui/base/SelectFileDialog.java',
- 'android/java/src/org/chromium/ui/base/ViewAndroid.java',
- 'android/java/src/org/chromium/ui/base/WindowAndroid.java',
- ],
- 'variables': {
- 'jni_gen_package': 'ui',
- 'jni_generator_ptr_type': 'long',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ['OS=="mac"', {
- 'targets': [
- {
- 'target_name': 'ui_cocoa_third_party_toolkits',
- 'type': '<(component)',
- 'sources': [
- # Build the necessary GTM sources
- '../third_party/GTM/AppKit/GTMFadeTruncatingTextFieldCell.h',
- '../third_party/GTM/AppKit/GTMFadeTruncatingTextFieldCell.m',
- '../third_party/GTM/AppKit/GTMIBArray.h',
- '../third_party/GTM/AppKit/GTMIBArray.m',
- '../third_party/GTM/AppKit/GTMKeyValueAnimation.h',
- '../third_party/GTM/AppKit/GTMKeyValueAnimation.m',
- '../third_party/GTM/AppKit/GTMNSAnimation+Duration.h',
- '../third_party/GTM/AppKit/GTMNSAnimation+Duration.m',
- '../third_party/GTM/AppKit/GTMNSBezierPath+CGPath.h',
- '../third_party/GTM/AppKit/GTMNSBezierPath+CGPath.m',
- '../third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h',
- '../third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.m',
- '../third_party/GTM/AppKit/GTMNSColor+Luminance.m',
- '../third_party/GTM/AppKit/GTMUILocalizer.h',
- '../third_party/GTM/AppKit/GTMUILocalizer.m',
- '../third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h',
- '../third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.m',
- '../third_party/GTM/Foundation/GTMNSNumber+64Bit.h',
- '../third_party/GTM/Foundation/GTMNSNumber+64Bit.m',
- '../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.h',
- '../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.m',
- ],
- 'include_dirs': [
- '..',
- '../third_party/GTM',
- '../third_party/GTM/AppKit',
- '../third_party/GTM/DebugUtils',
- '../third_party/GTM/Foundation',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
- '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
- ],
- },
- 'conditions': [
- ['component=="shared_library"', {
- # GTM is third-party code, so we don't want to add _EXPORT
- # annotations to it, so build it without -fvisibility=hidden
- # (else the interface class symbols will be hidden in a 64bit
- # build). Only do this in a component build, so that the shipping
- # chrome binary doesn't end up with unnecessarily exported
- # symbols.
- 'xcode_settings': {
- 'GCC_SYMBOLS_PRIVATE_EXTERN': 'NO',
- },
- }],
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/ui/ui_unittests.gyp b/chromium/ui/ui_unittests.gyp
index 560bc176981..f510872c7e3 100644
--- a/chromium/ui/ui_unittests.gyp
+++ b/chromium/ui/ui_unittests.gyp
@@ -8,73 +8,6 @@
},
'targets': [
{
- 'target_name': 'ui_test_support',
- 'dependencies': [
- '../base/base.gyp:base',
- '../skia/skia.gyp:skia',
- '../testing/gtest.gyp:gtest',
- 'gfx/gfx.gyp:gfx',
- ],
- 'sources': [
- 'base/test/cocoa_test_event_utils.h',
- 'base/test/cocoa_test_event_utils.mm',
- 'base/test/ui_cocoa_test_helper.h',
- 'base/test/ui_cocoa_test_helper.mm',
- 'base/test/ui_controls.h',
- 'base/test/ui_controls_aura.cc',
- 'base/test/ui_controls_gtk.cc',
- 'base/test/ui_controls_internal_win.cc',
- 'base/test/ui_controls_internal_win.h',
- 'base/test/ui_controls_mac.mm',
- 'base/test/ui_controls_win.cc',
- 'gfx/test/color_util.cc',
- 'gfx/test/color_util.h',
- ],
- 'include_dirs': [
- '../',
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'type': 'static_library',
- 'includes': [ 'base/ime/ime_test_support.gypi' ],
- }, { # OS=="ios"
- # None of the sources in this target are built on iOS, resulting in
- # link errors when building targets that depend on this target
- # because the static library isn't found. If this target is changed
- # to have sources that are built on iOS, the target should be changed
- # to be of type static_library on all platforms.
- 'type': 'none',
- # The cocoa files don't apply to iOS.
- 'sources/': [['exclude', 'cocoa']],
- }],
- ['chromeos==1', {
- 'dependencies': [
- '../chromeos/chromeos.gyp:chromeos_test_support_without_gmock',
- '../skia/skia.gyp:skia',
- ],
- }],
- ['use_aura==1', {
- 'sources!': [
- 'base/test/ui_controls_win.cc',
- ],
- }],
- ],
- },
- {
- 'target_name': 'run_ui_unittests',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- 'ui.gyp:ui',
- ],
- 'sources': [
- 'test/test_suite.cc',
- 'test/test_suite.h',
- 'test/run_all_unittests.cc',
- ],
- },
- {
'target_name': 'ui_unittests',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -85,15 +18,14 @@
'../testing/gtest.gyp:gtest',
'../third_party/icu/icu.gyp:icui18n',
'../third_party/icu/icu.gyp:icuuc',
- '../third_party/libpng/libpng.gyp:libpng',
'../url/url.gyp:url_lib',
- 'base/strings/ui_strings.gyp:ui_strings',
+ 'base/ui_base.gyp:ui_base',
+ 'base/ui_base.gyp:ui_base_test_support',
'events/events.gyp:events_base',
+ 'gfx/gfx.gyp:gfx_test_support',
'resources/ui_resources.gyp:ui_resources',
- 'run_ui_unittests',
- 'shell_dialogs/shell_dialogs.gyp:shell_dialogs',
- 'ui.gyp:ui',
- 'ui_test_support',
+ 'resources/ui_resources.gyp:ui_test_pak',
+ 'strings/ui_strings.gyp:ui_strings',
],
# iOS uses a small subset of ui. common_sources are the only files that
# are built on iOS.
@@ -107,49 +39,16 @@
'base/resource/data_pack_literal.cc',
'base/resource/data_pack_unittest.cc',
'base/resource/resource_bundle_unittest.cc',
- 'gfx/animation/animation_container_unittest.cc',
- 'gfx/animation/animation_unittest.cc',
- 'gfx/animation/multi_animation_unittest.cc',
- 'gfx/animation/slide_animation_unittest.cc',
- 'gfx/box_unittest.cc',
- 'gfx/codec/png_codec_unittest.cc',
- 'gfx/color_utils_unittest.cc',
- 'gfx/display_unittest.cc',
- 'gfx/font_unittest.cc',
- 'gfx/image/image_family_unittest.cc',
- 'gfx/image/image_skia_unittest.cc',
- 'gfx/image/image_unittest.cc',
- 'gfx/image/image_unittest_util.cc',
- 'gfx/image/image_unittest_util.h',
- 'gfx/image/image_unittest_util_ios.mm',
- 'gfx/image/image_unittest_util_mac.mm',
- 'gfx/insets_unittest.cc',
- 'gfx/matrix3_unittest.cc',
- 'gfx/point_unittest.cc',
- 'gfx/point3_unittest.cc',
- 'gfx/quad_unittest.cc',
- 'gfx/range/range_mac_unittest.mm',
- 'gfx/range/range_unittest.cc',
- 'gfx/range/range_win_unittest.cc',
- 'gfx/rect_unittest.cc',
- 'gfx/safe_integer_conversions_unittest.cc',
+ 'base/test/run_all_unittests.cc',
'gfx/screen_unittest.cc',
- 'gfx/shadow_value_unittest.cc',
- 'gfx/size_unittest.cc',
- 'gfx/skbitmap_operations_unittest.cc',
- 'gfx/text_elider_unittest.cc',
- 'gfx/text_utils_unittest.cc',
- 'gfx/vector2d_unittest.cc',
- 'gfx/vector3d_unittest.cc',
],
'all_sources': [
'<@(_common_sources)',
'base/accelerators/accelerator_manager_unittest.cc',
'base/accelerators/menu_label_accelerator_util_linux_unittest.cc',
- 'base/clipboard/clipboard_unittest.cc',
'base/clipboard/custom_data_helper_unittest.cc',
'base/cocoa/base_view_unittest.mm',
- 'base/cocoa/cocoa_event_utils_unittest.mm',
+ 'base/cocoa/cocoa_base_utils_unittest.mm',
'base/cocoa/controls/blue_label_button_unittest.mm',
'base/cocoa/controls/hover_image_menu_button_unittest.mm',
'base/cocoa/controls/hyperlink_button_cell_unittest.mm',
@@ -160,7 +59,6 @@
'base/cocoa/nsgraphics_context_additions_unittest.mm',
'base/cocoa/tracking_area_unittest.mm',
'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
- 'base/gtk/gtk_expanded_container_unittest.cc',
'base/models/list_model_unittest.cc',
'base/models/list_selection_model_unittest.cc',
'base/models/tree_node_model_unittest.cc',
@@ -168,26 +66,12 @@
'base/text/bytes_formatting_unittest.cc',
'base/view_prop_unittest.cc',
'base/webui/web_ui_util_unittest.cc',
- 'base/x/x11_util_unittest.cc',
- 'gfx/animation/tween_unittest.cc',
- 'gfx/blit_unittest.cc',
- 'gfx/break_list_unittest.cc',
- 'gfx/canvas_unittest.cc',
'gfx/canvas_unittest_mac.mm',
- 'gfx/codec/jpeg_codec_unittest.cc',
- 'gfx/color_analysis_unittest.cc',
- 'gfx/font_list_unittest.cc',
- 'gfx/image/image_mac_unittest.mm',
- 'gfx/image/image_util_unittest.cc',
- 'gfx/ozone/dri/hardware_display_controller_unittest.cc',
- 'gfx/ozone/dri/dri_surface_factory_unittest.cc',
- 'gfx/ozone/dri/dri_surface_unittest.cc',
'gfx/platform_font_mac_unittest.mm',
'gfx/render_text_unittest.cc',
- 'gfx/sequential_id_generator_unittest.cc',
- 'gfx/transform_util_unittest.cc',
- 'gfx/utf16_indexing_unittest.cc',
- 'shell_dialogs/select_file_dialog_win_unittest.cc',
+ ],
+ 'includes': [
+ 'display/display_unittests.gypi',
],
'include_dirs': [
'../',
@@ -204,18 +88,31 @@
],
# The ResourceBundle unittest expects a locale.pak file to exist in
# the bundle for English-US. Copy it in from where it was generated
- # by ui_strings.gyp:ui_unittest_strings.
+ # by ui_resources.gyp:ui_test_pak.
'mac_bundle_resources': [
- '<(PRODUCT_DIR)/ui_unittests_strings/en.lproj/locale.pak',
+ '<(PRODUCT_DIR)/ui/en.lproj/locale.pak',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'copy_test_data',
+ 'variables': {
+ 'test_data_files': [
+ 'base/test/data',
+ ],
+ 'test_data_prefix' : 'ui',
+ },
+ 'includes': [ '../build/copy_test_data_ios.gypi' ],
+ },
],
}],
['OS == "win"', {
'sources': [
- 'test/ui_unittests.rc',
'base/dragdrop/os_exchange_data_win_unittest.cc',
'base/win/hwnd_subclass_unittest.cc',
+ 'gfx/color_profile_win_unittest.cc',
'gfx/font_fallback_win_unittest.cc',
'gfx/icon_util_unittest.cc',
+ 'gfx/icon_util_unittests.rc',
'gfx/platform_font_win_unittest.cc',
],
'include_dirs': [
@@ -243,54 +140,27 @@
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
}],
- ['OS != "mac" and OS != "ios"', {
- 'sources': [
- 'gfx/transform_unittest.cc',
- 'gfx/interpolated_transform_unittest.cc',
- ],
- }],
- ['OS == "android" and gtest_target_type == "shared_library"', {
+ ['OS == "android"', {
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
],
}],
- ['desktop_linux == 1 or chromeos == 1 or OS == "ios"', {
- 'dependencies': [
- 'base/strings/ui_strings.gyp:ui_unittest_strings',
- ],
- }],
['use_pango == 1', {
'dependencies': [
- '../build/linux/system.gyp:fontconfig',
'../build/linux/system.gyp:pangocairo',
],
- 'sources': [
- 'gfx/platform_font_pango_unittest.cc',
- ],
'conditions': [
- ['linux_use_tcmalloc==1', {
+ ['use_allocator!="none"', {
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
],
}],
- ['toolkit_views==1', {
- 'sources!': [
- 'browser/ui/gtk/gtk_expanded_container_unittest.cc',
- ],
- }],
],
}],
['use_x11==1', {
'dependencies': [
'../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
- ],
- }],
- ['toolkit_uses_gtk == 1', {
- 'sources': [
- 'base/dragdrop/gtk_dnd_util_unittest.cc',
- ],
- 'dependencies': [
- '../build/linux/system.gyp:gtk',
+ 'events/platform/x11/x11_events_platform.gyp:x11_events_platform',
],
}],
['OS=="android" or OS=="ios"', {
@@ -308,6 +178,13 @@
'base/cursor/cursor_loader_x11_unittest.cc',
],
}],
+ ['OS=="mac"', {
+ 'dependencies': [
+ 'events/events.gyp:events_test_support',
+ 'gfx/gfx.gyp:gfx_test_support',
+ 'ui_unittests_bundle',
+ ],
+ }],
['use_aura==1 or toolkit_views==1', {
'sources': [
'base/dragdrop/os_exchange_data_unittest.cc',
@@ -316,30 +193,30 @@
'events/events.gyp:events',
'events/events.gyp:events_base',
'events/events.gyp:events_test_support',
+ 'events/platform/events_platform.gyp:events_platform',
],
}],
['use_aura==1', {
'sources!': [
- 'base/dialogs/select_file_dialog_win_unittest.cc',
'base/dragdrop/os_exchange_data_win_unittest.cc',
'gfx/screen_unittest.cc',
],
}],
- ['use_ozone==1', {
- 'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:dridrm',
- ],
- }],
['use_ozone==1 and use_pango==0', {
'sources!': [
- 'gfx/text_elider_unittest.cc',
- 'gfx/font_unittest.cc',
- 'gfx/font_list_unittest.cc',
'gfx/render_text_unittest.cc',
- 'gfx/canvas_unittest.cc',
],
}],
['chromeos==1', {
+ 'dependencies': [
+ '../chromeos/chromeos.gyp:chromeos',
+ 'aura/aura.gyp:aura_test_support',
+ 'chromeos/ui_chromeos.gyp:ui_chromeos',
+ 'events/events.gyp:gesture_detection',
+ ],
+ 'sources': [
+ 'chromeos/touch_exploration_controller_unittest.cc'
+ ],
'sources!': [
'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
],
@@ -357,10 +234,20 @@
},
],
'conditions': [
- # Special target to wrap a gtest_target_type==shared_library
- # ui_unittests into an android apk for execution.
- # See base.gyp for TODO(jrg)s about this strategy.
- ['OS == "android" and gtest_target_type == "shared_library"', {
+ # Mac target to build a test Framework bundle to mock out resource loading.
+ ['OS == "mac"', {
+ 'targets': [
+ {
+ 'target_name': 'ui_unittests_bundle',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'resources/ui_resources.gyp:ui_test_pak',
+ ],
+ 'includes': [ 'ui_unittests_bundle.gypi' ],
+ },
+ ],
+ }],
+ ['OS == "android"', {
'targets': [
{
'target_name': 'ui_unittests_apk',
@@ -370,7 +257,6 @@
],
'variables': {
'test_suite_name': 'ui_unittests',
- 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ui_unittests<(SHARED_LIB_SUFFIX)',
},
'includes': [ '../build/apk_test.gypi' ],
},
diff --git a/chromium/ui/ui_unittests.isolate b/chromium/ui/ui_unittests.isolate
index 55ce04a9d47..e9a927c35a1 100644
--- a/chromium/ui/ui_unittests.isolate
+++ b/chromium/ui/ui_unittests.isolate
@@ -12,4 +12,7 @@
},
}],
],
+ 'includes': [
+ '../third_party/icu/icu.isolate',
+ ],
}
diff --git a/chromium/ui/ui_unittests_bundle.gypi b/chromium/ui/ui_unittests_bundle.gypi
new file mode 100644
index 00000000000..94ef939713e
--- /dev/null
+++ b/chromium/ui/ui_unittests_bundle.gypi
@@ -0,0 +1,55 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file contains resources for the ui_unittests test bundle.
+# See chrome_dll_bundle.gypi for a description of the techniques here.
+{
+ 'product_name': 'ui_unittests Framework',
+ 'variables': {
+ 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui',
+
+ # There is no executable in the mock framework, and so nothing to strip.
+ 'mac_strip': 0,
+ },
+ 'mac_bundle': 1,
+ 'xcode_settings': {
+ 'CHROMIUM_BUNDLE_ID': 'com.google.ChromiumUITests',
+ 'DYLIB_COMPATIBILITY_VERSION': '1.0.0',
+ 'DYLIB_CURRENT_VERSION': '1.0.0',
+ 'DYLIB_INSTALL_NAME_BASE': '@executable_path/../Versions/1.0.0.0',
+ 'LD_DYLIB_INSTALL_NAME':
+ '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(WRAPPER_NAME)/$(PRODUCT_NAME)',
+ 'INFOPLIST_FILE': 'base/test/framework-Info.plist',
+ },
+ 'mac_bundle_resources': [
+ 'base/test/framework-Info.plist',
+ '<(PRODUCT_DIR)/ui_test.pak',
+ '<!@pymod_do_main(repack_locales -o -p <(OS) -g <(grit_out_dir) -s <(SHARED_INTERMEDIATE_DIR) -x <(SHARED_INTERMEDIATE_DIR) <(locales))',
+ ],
+ 'mac_bundle_resources!': [
+ 'base/test/framework-Info.plist',
+ ],
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'Symlink Resources',
+ 'action': [
+ 'ln',
+ '-fns',
+ 'Versions/A/Resources',
+ '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Resources'
+ ],
+ },
+ {
+ # Resource bundle pak names are hardcoded. This allows ui_test.pak to be
+ # found while running the ResourceBundle tests.
+ 'postbuild_name': 'Symlink chrome_100_percent for test',
+ 'action': [
+ 'ln',
+ '-fns',
+ 'ui_test.pak',
+ '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Versions/A/Resources/chrome_100_percent.pak'
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/v2/OWNERS b/chromium/ui/v2/OWNERS
index 9c070a52506..f2f57743695 100644
--- a/chromium/ui/v2/OWNERS
+++ b/chromium/ui/v2/OWNERS
@@ -1 +1 @@
-ben@chromium.org
+ben@chromium.org
diff --git a/chromium/ui/v2/src/v2_unittest.cc b/chromium/ui/v2/src/v2_unittest.cc
new file mode 100644
index 00000000000..0e6cdb72e77
--- /dev/null
+++ b/chromium/ui/v2/src/v2_unittest.cc
@@ -0,0 +1,16 @@
+// 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 "base/basictypes.h"
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv, base::Bind(&base::TestSuite::Run,
+ base::Unretained(&test_suite)));
+}
diff --git a/chromium/ui/v2/src/v2_unittests.cc b/chromium/ui/v2/src/v2_unittests.cc
deleted file mode 100644
index e384770d879..00000000000
--- a/chromium/ui/v2/src/v2_unittests.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_suite.h"
-
-int main(int argc, char** argv) {
- base::TestSuite test_suite(argc, argv);
- return base::LaunchUnitTests(
- argc, argv, base::Bind(&base::TestSuite::Run,
- base::Unretained(&test_suite)));
-}
diff --git a/chromium/ui/v2/v2.gyp b/chromium/ui/v2/v2.gyp
index 8c6ce16c302..b918f087aaa 100644
--- a/chromium/ui/v2/v2.gyp
+++ b/chromium/ui/v2/v2.gyp
@@ -20,6 +20,7 @@
'../compositor/compositor.gyp:compositor',
'../events/events.gyp:events',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
],
'defines': [
'V2_IMPLEMENTATION',
@@ -55,10 +56,11 @@
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'v2',
],
'sources': [
- 'src/v2_unittests.cc',
+ 'src/v2_unittest.cc',
'src/view_unittest.cc',
],
},
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index 7619dc0cb17..b29fbd88a07 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -4,13 +4,20 @@ include_rules = [
"+skia/ext",
"+third_party/iaccessible2",
"+third_party/skia",
+ "+ui/accessibility",
"+ui/aura",
"+ui/base",
"+ui/compositor",
+ "+ui/display",
"+ui/events",
"+ui/gfx",
- "+ui/ozone",
+ "+ui/gl/gl_surface.h", # To initialize GL for tests.
"+ui/native_theme",
+ "+ui/ozone",
+ "+ui/wm/core",
+ "+ui/wm/public",
+
+ "-testing/gmock",
]
specific_include_rules = {
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
new file mode 100644
index 00000000000..ae2df2068ab
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+#include "ui/aura/window.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_view_obj_wrapper.h"
+#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
+#include "ui/views/accessibility/ax_window_obj_wrapper.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+// static
+AXAuraObjCache* AXAuraObjCache::GetInstance() {
+ return Singleton<AXAuraObjCache>::get();
+}
+
+AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
+ return CreateInternal<AXViewObjWrapper>(view, view_to_id_map_);
+}
+
+AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(Widget* widget) {
+ return CreateInternal<AXWidgetObjWrapper>(widget, widget_to_id_map_);
+}
+
+AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(aura::Window* window) {
+ return CreateInternal<AXWindowObjWrapper>(window, window_to_id_map_);
+}
+
+int32 AXAuraObjCache::GetID(View* view) {
+ return GetIDInternal(view, view_to_id_map_);
+}
+
+int32 AXAuraObjCache::GetID(Widget* widget) {
+ return GetIDInternal(widget, widget_to_id_map_);
+}
+
+int32 AXAuraObjCache::GetID(aura::Window* window) {
+ return GetIDInternal(window, window_to_id_map_);
+}
+
+void AXAuraObjCache::Remove(View* view) {
+ RemoveInternal(view, view_to_id_map_);
+}
+
+void AXAuraObjCache::Remove(Widget* widget) {
+ RemoveInternal(widget, widget_to_id_map_);
+}
+
+void AXAuraObjCache::Remove(aura::Window* window) {
+ RemoveInternal(window, window_to_id_map_);
+}
+
+AXAuraObjWrapper* AXAuraObjCache::Get(int32 id) {
+ std::map<int32, AXAuraObjWrapper*>::iterator it = cache_.find(id);
+
+ if (it == cache_.end())
+ return NULL;
+
+ return it->second;
+}
+
+void AXAuraObjCache::Remove(int32 id) {
+ AXAuraObjWrapper* obj = Get(id);
+
+ if (id == -1 || !obj)
+ return;
+
+ cache_.erase(id);
+ delete obj;
+}
+
+AXAuraObjCache::AXAuraObjCache() : current_id_(1) {
+}
+
+AXAuraObjCache::~AXAuraObjCache() {
+ STLDeleteContainerPairSecondPointers(cache_.begin(), cache_.end());
+ cache_.clear();
+}
+
+template <typename AuraViewWrapper, typename AuraView>
+AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map) {
+ if (!aura_view)
+ return NULL;
+
+ typename std::map<AuraView*, int32>::iterator it =
+ aura_view_to_id_map.find(aura_view);
+
+ if (it != aura_view_to_id_map.end())
+ return Get(it->second);
+
+ AXAuraObjWrapper* wrapper = new AuraViewWrapper(aura_view);
+ aura_view_to_id_map[aura_view] = current_id_;
+ cache_[current_id_] = wrapper;
+ current_id_++;
+ return wrapper;
+}
+
+template<typename AuraView> int32 AXAuraObjCache::GetIDInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map) {
+ if (!aura_view)
+ return -1;
+
+ typename std::map<AuraView*, int32>::iterator it =
+ aura_view_to_id_map.find(aura_view);
+
+ if (it != aura_view_to_id_map.end())
+ return it->second;
+
+ return -1;
+}
+
+template<typename AuraView>
+void AXAuraObjCache::RemoveInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map) {
+ int32 id = GetID(aura_view);
+ if (id == -1)
+ return;
+ aura_view_to_id_map.erase(aura_view);
+ Remove(id);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
new file mode 100644
index 00000000000..6e5d9e829a9
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_CACHE_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_CACHE_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "ui/views/views_export.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace aura {
+class Window;
+} // namespace aura
+
+namespace views {
+class AXAuraObjWrapper;
+class View;
+class Widget;
+
+// A cache responsible for assigning id's to a set of interesting Aura views.
+class VIEWS_EXPORT AXAuraObjCache {
+ public:
+ // Get the single instance of this class.
+ static AXAuraObjCache* GetInstance();
+
+ // Get or create an entry in the cache based on an Aura view.
+ AXAuraObjWrapper* GetOrCreate(View* view);
+ AXAuraObjWrapper* GetOrCreate(Widget* widget);
+ AXAuraObjWrapper* GetOrCreate(aura::Window* window);
+
+ // Gets an id given an Aura view.
+ int32 GetID(View* view);
+ int32 GetID(Widget* widget);
+ int32 GetID(aura::Window* window);
+
+ // Gets the next unique id for this cache. Useful for non-Aura view backed
+ // views.
+ int32 GetNextID() { return current_id_++; }
+
+ // Removes an entry from this cache based on an Aura view.
+ void Remove(View* view);
+ void Remove(Widget* widget);
+ void Remove(aura::Window* window);
+
+ // Lookup a cached entry based on an id.
+ AXAuraObjWrapper* Get(int32 id);
+
+ // Remove a cached entry based on an id.
+ void Remove(int32 id);
+
+ private:
+ friend struct DefaultSingletonTraits<AXAuraObjCache>;
+
+ AXAuraObjCache();
+ virtual ~AXAuraObjCache();
+
+ template <typename AuraViewWrapper, typename AuraView>
+ AXAuraObjWrapper* CreateInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map);
+
+ template<typename AuraView> int32 GetIDInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map);
+
+ template<typename AuraView> void RemoveInternal(
+ AuraView* aura_view, std::map<AuraView*, int32>& aura_view_to_id_map);
+
+ std::map<views::View*, int32> view_to_id_map_;
+ std::map<views::Widget*, int32> widget_to_id_map_;
+ std::map<aura::Window*, int32> window_to_id_map_;
+
+ std::map<int32, AXAuraObjWrapper*> cache_;
+ int32 current_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXAuraObjCache);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_CACHE_H_
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
new file mode 100644
index 00000000000..00f9c593c0c
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_WRAPPER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_WRAPPER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "ui/views/views_export.h"
+
+namespace ui {
+struct AXNodeData;
+} // namespace ui
+
+namespace views {
+
+// An interface abstraction for Aura views that exposes the view-tree formed
+// by the implementing view types.
+class VIEWS_EXPORT AXAuraObjWrapper {
+ public:
+ virtual ~AXAuraObjWrapper() {}
+
+ // Traversal and serialization.
+ virtual AXAuraObjWrapper* GetParent() = 0;
+ virtual void GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) = 0;
+ virtual void Serialize(ui::AXNodeData* out_node_data) = 0;
+ virtual int32 GetID() = 0;
+
+ // Actions.
+ virtual void DoDefault() {}
+ virtual void Focus() {}
+ virtual void MakeVisible() {}
+ virtual void SetSelection(int32 start, int32 end) {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_AURA_OBJ_WRAPPER_H_
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
new file mode 100644
index 00000000000..b5c60775c75
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/ax_view_obj_wrapper.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+AXViewObjWrapper::AXViewObjWrapper(View* view) : view_(view) {
+ DCHECK(view->GetWidget());
+ if (view->GetWidget())
+ AXAuraObjCache::GetInstance()->GetOrCreate(view->GetWidget());
+}
+
+AXViewObjWrapper::~AXViewObjWrapper() {}
+
+AXAuraObjWrapper* AXViewObjWrapper::GetParent() {
+ AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
+ if (view_->parent())
+ return cache->GetOrCreate(view_->parent());
+
+ return cache->GetOrCreate(view_->GetWidget());
+}
+
+void AXViewObjWrapper::GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) {
+ // TODO(dtseng): Need to handle |Widget| child of |View|.
+ for (int i = 0; i < view_->child_count(); ++i) {
+ AXAuraObjWrapper* child =
+ AXAuraObjCache::GetInstance()->GetOrCreate(view_->child_at(i));
+ out_children->push_back(child);
+ }
+}
+
+void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
+ ui::AXViewState view_data;
+ view_->GetAccessibleState(&view_data);
+ out_node_data->id = GetID();
+ out_node_data->role = view_data.role;
+
+ out_node_data->state = view_data.state();
+ if (view_->HasFocus())
+ out_node_data->state |= 1 << ui::AX_STATE_FOCUSED;
+ if (view_->IsFocusable())
+ out_node_data->state |= 1 << ui::AX_STATE_FOCUSABLE;
+
+ out_node_data->location = view_->GetBoundsInScreen();
+
+ out_node_data->AddStringAttribute(
+ ui::AX_ATTR_NAME, base::UTF16ToUTF8(view_data.name));
+ out_node_data->AddStringAttribute(
+ ui::AX_ATTR_VALUE, base::UTF16ToUTF8(view_data.value));
+
+ out_node_data->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+ view_data.selection_start);
+ out_node_data->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+ view_data.selection_end);
+}
+
+int32 AXViewObjWrapper::GetID() {
+ return AXAuraObjCache::GetInstance()->GetID(view_);
+}
+
+void AXViewObjWrapper::DoDefault() {
+ gfx::Rect rect = view_->GetBoundsInScreen();
+ gfx::Point center = rect.CenterPoint();
+ view_->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED, center, center,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON));
+}
+
+void AXViewObjWrapper::Focus() {
+ view_->RequestFocus();
+}
+
+void AXViewObjWrapper::MakeVisible() {
+ // TODO(dtseng): Implement.
+}
+
+void AXViewObjWrapper::SetSelection(int32 start, int32 end) {
+ // TODO(dtseng): Implement.
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
new file mode 100644
index 00000000000..6838d07243c
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -0,0 +1,38 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_VIEW_OBJ_WRAPPER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_VIEW_OBJ_WRAPPER_H_
+
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+
+namespace views {
+class View;
+
+// Describes a |View| for use with other AX classes.
+class AXViewObjWrapper : public AXAuraObjWrapper {
+ public:
+ explicit AXViewObjWrapper(View* view);
+ virtual ~AXViewObjWrapper();
+
+ // AXAuraObjWrapper overrides.
+ virtual AXAuraObjWrapper* GetParent() OVERRIDE;
+ virtual void GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) OVERRIDE;
+ virtual void Serialize(ui::AXNodeData* out_node_data) OVERRIDE;
+ virtual int32 GetID() OVERRIDE;
+ virtual void DoDefault() OVERRIDE;
+ virtual void Focus() OVERRIDE;
+ virtual void MakeVisible() OVERRIDE;
+ virtual void SetSelection(int32 start, int32 end) OVERRIDE;
+
+ private:
+ View* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXViewObjWrapper);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_VIEW_OBJ_WRAPPER_H_
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
new file mode 100644
index 00000000000..36a3143e365
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
+
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+AXWidgetObjWrapper::AXWidgetObjWrapper(Widget* widget) : widget_(widget) {
+ widget->AddObserver(this);
+ widget->AddRemovalsObserver(this);
+}
+
+AXWidgetObjWrapper::~AXWidgetObjWrapper() {
+ widget_->RemoveObserver(this);
+ widget_->RemoveRemovalsObserver(this);
+ widget_ = NULL;
+}
+
+AXAuraObjWrapper* AXWidgetObjWrapper::GetParent() {
+ return AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetNativeView());
+}
+
+void AXWidgetObjWrapper::GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) {
+ out_children->push_back(
+ AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetRootView()));
+}
+
+void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
+ out_node_data->id = GetID();
+ out_node_data->role = ui::AX_ROLE_CLIENT;
+ out_node_data->location = widget_->GetWindowBoundsInScreen();
+ // TODO(dtseng): Set better states.
+ out_node_data->state = 0;
+}
+
+int32 AXWidgetObjWrapper::GetID() {
+ return AXAuraObjCache::GetInstance()->GetID(widget_);
+}
+
+void AXWidgetObjWrapper::OnWidgetDestroying(Widget* widget) {
+ AXAuraObjCache::GetInstance()->Remove(widget);
+}
+
+void AXWidgetObjWrapper::OnWillRemoveView(Widget* widget, View* view) {
+ AXAuraObjCache::GetInstance()->Remove(view);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
new file mode 100644
index 00000000000..61ff1e90f28
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_WIDGET_OBJ_WRAPPER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_WIDGET_OBJ_WRAPPER_H_
+
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/widget/widget_observer.h"
+#include "ui/views/widget/widget_removals_observer.h"
+
+namespace views {
+class Widget;
+
+// Describes a |Widget| for use with other AX classes.
+class AXWidgetObjWrapper : public AXAuraObjWrapper,
+ public WidgetObserver,
+ public WidgetRemovalsObserver {
+ public:
+ explicit AXWidgetObjWrapper(Widget* widget);
+ virtual ~AXWidgetObjWrapper();
+
+ // AXAuraObjWrapper overrides.
+ virtual AXAuraObjWrapper* GetParent() OVERRIDE;
+ virtual void GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) OVERRIDE;
+ virtual void Serialize(ui::AXNodeData* out_node_data) OVERRIDE;
+ virtual int32 GetID() OVERRIDE;
+
+ // WidgetObserver overrides.
+ virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
+
+ // WidgetRemovalsObserver overrides.
+ virtual void OnWillRemoveView(Widget* widget, View* view) OVERRIDE;
+
+ private:
+ Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXWidgetObjWrapper);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_WIDGET_OBJ_WRAPPER_H_
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
new file mode 100644
index 00000000000..b358de58c91
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/ax_window_obj_wrapper.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/aura/window.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+AXWindowObjWrapper::AXWindowObjWrapper(
+ aura::Window* window) : window_(window) {
+ window->AddObserver(this);
+}
+
+AXWindowObjWrapper::~AXWindowObjWrapper() {
+ window_->RemoveObserver(this);
+ window_ = NULL;
+}
+
+AXAuraObjWrapper* AXWindowObjWrapper::GetParent() {
+ if (!window_->parent())
+ return NULL;
+
+ return AXAuraObjCache::GetInstance()->GetOrCreate(window_->parent());
+}
+
+void AXWindowObjWrapper::GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) {
+ aura::Window::Windows children = window_->children();
+ for (size_t i = 0; i < children.size(); ++i) {
+ out_children->push_back(
+ AXAuraObjCache::GetInstance()->GetOrCreate(children[i]));
+ }
+
+ // Also consider any associated widgets as children.
+ Widget* widget = Widget::GetWidgetForNativeView(window_);
+ if (widget)
+ out_children->push_back(AXAuraObjCache::GetInstance()->GetOrCreate(widget));
+}
+
+void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
+ out_node_data->id = GetID();
+ out_node_data->role = ui::AX_ROLE_WINDOW;
+ // TODO(dtseng): Set better states.
+ out_node_data->state = 0;
+ out_node_data->location = window_->bounds();
+ out_node_data->AddStringAttribute(
+ ui::AX_ATTR_NAME, base::UTF16ToUTF8(window_->title()));
+}
+
+int32 AXWindowObjWrapper::GetID() {
+ return AXAuraObjCache::GetInstance()->GetID(window_);
+}
+
+void AXWindowObjWrapper::OnWindowDestroying(aura::Window* window) {
+ AXAuraObjCache::GetInstance()->Remove(window);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
new file mode 100644
index 00000000000..b3cd235cfb7
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_WINDOW_OBJ_WRAPPER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_WINDOW_OBJ_WRAPPER_H_
+
+#include "ui/aura/window_observer.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+
+namespace aura {
+class Window;
+} // namespace aura
+
+namespace views {
+
+// Describes a |Window| for use with other AX classes.
+class AXWindowObjWrapper : public AXAuraObjWrapper,
+ public aura::WindowObserver {
+ public:
+ explicit AXWindowObjWrapper(aura::Window* window);
+ virtual ~AXWindowObjWrapper();
+
+ // AXAuraObjWrapper overrides.
+ virtual AXAuraObjWrapper* GetParent() OVERRIDE;
+ virtual void GetChildren(
+ std::vector<AXAuraObjWrapper*>* out_children) OVERRIDE;
+ virtual void Serialize(ui::AXNodeData* out_node_data) OVERRIDE;
+ virtual int32 GetID() OVERRIDE;
+
+ // WindowObserver overrides.
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ private:
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXWindowObjWrapper);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_WINDOW_OBJ_WRAPPER_H_
diff --git a/chromium/ui/views/accessibility/native_view_accessibility.h b/chromium/ui/views/accessibility/native_view_accessibility.h
index 2fc4c4423b6..2b9f5927710 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility.h
+++ b/chromium/ui/views/accessibility/native_view_accessibility.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_ACCESSIBILITY_NATIVE_VIEW_ACCESSIBILITY_H_
#define UI_VIEWS_ACCESSIBILITY_NATIVE_VIEW_ACCESSIBILITY_H_
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
@@ -18,7 +18,7 @@ class VIEWS_EXPORT NativeViewAccessibility {
static NativeViewAccessibility* Create(View* view);
virtual void NotifyAccessibilityEvent(
- ui::AccessibilityTypes::Event event_type) {}
+ ui::AXEvent event_type) {}
virtual gfx::NativeViewAccessible GetNativeObject();
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win.cc b/chromium/ui/views/accessibility/native_view_accessibility_win.cc
index 3e20cbbc4a9..670de4dd8ec 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_win.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_win.cc
@@ -4,8 +4,8 @@
#include "ui/views/accessibility/native_view_accessibility_win.h"
-#include <UIAutomationClient.h>
#include <oleacc.h>
+#include <UIAutomationClient.h>
#include <set>
#include <vector>
@@ -15,8 +15,9 @@
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "third_party/iaccessible2/ia2_api_all.h"
-#include "ui/base/accessibility/accessible_text_utils.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/win/accessibility_ids_win.h"
#include "ui/base/win/accessibility_misc_utils.h"
#include "ui/base/win/atl_module.h"
@@ -26,8 +27,6 @@
#include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h"
-using ui::AccessibilityTypes;
-
namespace views {
namespace {
@@ -190,6 +189,7 @@ void AccessibleWebViewRegistry::QueryIAccessible2Interface(View* web_view) {
long NativeViewAccessibilityWin::next_unique_id_ = 1;
int NativeViewAccessibilityWin::view_storage_ids_[kMaxViewStorageIds] = {0};
int NativeViewAccessibilityWin::next_view_storage_id_index_ = 0;
+std::vector<int> NativeViewAccessibilityWin::alert_target_view_storage_ids_;
// static
NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
@@ -211,10 +211,11 @@ NativeViewAccessibilityWin::NativeViewAccessibilityWin()
}
NativeViewAccessibilityWin::~NativeViewAccessibilityWin() {
+ RemoveAlertTarget();
}
void NativeViewAccessibilityWin::NotifyAccessibilityEvent(
- ui::AccessibilityTypes::Event event_type) {
+ ui::AXEvent event_type) {
if (!view_)
return;
@@ -237,6 +238,10 @@ void NativeViewAccessibilityWin::NotifyAccessibilityEvent(
::NotifyWinEvent(MSAAEvent(event_type), hwnd, OBJID_CLIENT, child_id);
next_view_storage_id_index_ =
(next_view_storage_id_index_ + 1) % kMaxViewStorageIds;
+
+ // Keep track of views that are a target of an alert event.
+ if (event_type == ui::AX_EVENT_ALERT)
+ AddAlertTarget();
}
gfx::NativeViewAccessible NativeViewAccessibilityWin::GetNativeObject() {
@@ -557,9 +562,9 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accDefaultAction(
if (!view_)
return E_FAIL;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- string16 temp_action = state.default_action;
+ base::string16 temp_action = state.default_action;
if (!temp_action.empty()) {
*def_action = SysAllocString(temp_action.c_str());
@@ -578,7 +583,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accDescription(
if (!view_)
return E_FAIL;
- string16 temp_desc;
+ base::string16 temp_desc;
view_->GetTooltipText(gfx::Point(), &temp_desc);
if (!temp_desc.empty()) {
@@ -624,9 +629,9 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accKeyboardShortcut(
if (!view_)
return E_FAIL;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- string16 temp_key = state.keyboard_shortcut;
+ base::string16 temp_key = state.keyboard_shortcut;
if (!temp_key.empty()) {
*acc_key = SysAllocString(temp_key.c_str());
@@ -646,9 +651,9 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accName(
return E_FAIL;
// Retrieve the current view's name.
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- string16 temp_name = state.name;
+ base::string16 temp_name = state.name;
if (!temp_name.empty()) {
// Return name retrieved.
*name = SysAllocString(temp_name.c_str());
@@ -694,7 +699,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accRole(
if (!view_)
return E_FAIL;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
role->vt = VT_I4;
role->lVal = MSAARole(state.role);
@@ -733,9 +738,9 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accValue(VARIANT var_id,
return E_FAIL;
// Retrieve the current view's value.
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- string16 temp_value = state.value;
+ base::string16 temp_value = state.value;
if (!temp_value.empty()) {
// Return value retrieved.
@@ -758,7 +763,7 @@ STDMETHODIMP NativeViewAccessibilityWin::put_accValue(VARIANT var_id,
return E_FAIL;
// Return an error if the view can't set the value.
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
if (state.set_value_callback.is_null())
return E_FAIL;
@@ -782,9 +787,9 @@ STDMETHODIMP NativeViewAccessibilityWin::accSelect(
STDMETHODIMP NativeViewAccessibilityWin::get_accHelp(
VARIANT var_id, BSTR* help) {
- if (help)
- *help = NULL;
- return E_NOTIMPL;
+ base::string16 temp = base::UTF8ToUTF16(view_->GetClassName());
+ *help = SysAllocString(temp.c_str());
+ return S_OK;
}
STDMETHODIMP NativeViewAccessibilityWin::get_accHelpTopic(
@@ -815,7 +820,7 @@ STDMETHODIMP NativeViewAccessibilityWin::role(LONG* role) {
if (!role)
return E_INVALIDARG;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
*role = MSAARole(state.role);
return S_OK;
@@ -831,14 +836,14 @@ STDMETHODIMP NativeViewAccessibilityWin::get_states(AccessibleStates* states) {
if (!states)
return E_INVALIDARG;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
// There are only a couple of states we need to support
// in IAccessible2. If any more are added, we may want to
// add a helper function like MSAAState.
*states = IA2_STATE_OPAQUE;
- if (state.state & AccessibilityTypes::STATE_EDITABLE)
+ if (state.HasStateFlag(ui::AX_STATE_EDITABLE))
*states |= IA2_STATE_EDITABLE;
return S_OK;
@@ -866,6 +871,59 @@ STDMETHODIMP NativeViewAccessibilityWin::get_windowHandle(HWND* window_handle) {
return *window_handle ? S_OK : S_FALSE;
}
+STDMETHODIMP NativeViewAccessibilityWin::get_relationTargetsOfType(
+ BSTR type_bstr,
+ long max_targets,
+ IUnknown ***targets,
+ long *n_targets) {
+ if (!view_)
+ return E_FAIL;
+
+ if (!targets || !n_targets)
+ return E_INVALIDARG;
+
+ *n_targets = 0;
+ *targets = NULL;
+
+ // Only respond to requests for relations of type "alerts" on the
+ // root view.
+ base::string16 type(type_bstr);
+ if (type != L"alerts" || view_->parent())
+ return S_FALSE;
+
+ // Collect all of the alert views that are still valid.
+ std::vector<View*> alert_views;
+ ViewStorage* view_storage = ViewStorage::GetInstance();
+ for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
+ int view_storage_id = alert_target_view_storage_ids_[i];
+ View* view = view_storage->RetrieveView(view_storage_id);
+ if (!view || !view_->Contains(view))
+ continue;
+ alert_views.push_back(view);
+ }
+
+ long count = alert_views.size();
+ if (count == 0)
+ return S_FALSE;
+
+ // Don't return more targets than max_targets - but note that the caller
+ // is allowed to specify max_targets=0 to mean no limit.
+ if (max_targets > 0 && count > max_targets)
+ count = max_targets;
+
+ // Return the number of targets.
+ *n_targets = count;
+
+ // Allocate COM memory for the result array and populate it.
+ *targets = static_cast<IUnknown**>(
+ CoTaskMemAlloc(count * sizeof(IUnknown*)));
+ for (long i = 0; i < count; ++i) {
+ (*targets)[i] = alert_views[i]->GetNativeViewAccessible();
+ (*targets)[i]->AddRef();
+ }
+ return S_OK;
+}
+
//
// IAccessibleText
//
@@ -877,7 +935,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_nCharacters(LONG* n_characters) {
if (!n_characters)
return E_INVALIDARG;
- string16 text = TextForIAccessibleText();
+ base::string16 text = TextForIAccessibleText();
*n_characters = static_cast<LONG>(text.size());
return S_OK;
}
@@ -889,7 +947,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_caretOffset(LONG* offset) {
if (!offset)
return E_INVALIDARG;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
*offset = static_cast<LONG>(state.selection_end);
return S_OK;
@@ -902,7 +960,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_nSelections(LONG* n_selections) {
if (!n_selections)
return E_INVALIDARG;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
if (state.selection_start != state.selection_end)
*n_selections = 1;
@@ -920,7 +978,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_selection(LONG selection_index,
if (!start_offset || !end_offset || selection_index != 0)
return E_INVALIDARG;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
*start_offset = static_cast<LONG>(state.selection_start);
*end_offset = static_cast<LONG>(state.selection_end);
@@ -933,9 +991,9 @@ STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset,
if (!view_)
return E_FAIL;
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- string16 text_str = TextForIAccessibleText();
+ base::string16 text_str = TextForIAccessibleText();
LONG len = static_cast<LONG>(text_str.size());
if (start_offset == IA2_TEXT_OFFSET_LENGTH) {
@@ -963,7 +1021,8 @@ STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset,
if (end_offset > len)
return E_INVALIDARG;
- string16 substr = text_str.substr(start_offset, end_offset - start_offset);
+ base::string16 substr =
+ text_str.substr(start_offset, end_offset - start_offset);
if (substr.empty())
return S_FALSE;
@@ -989,7 +1048,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_textAtOffset(
return S_FALSE;
}
- const string16& text_str = TextForIAccessibleText();
+ const base::string16& text_str = TextForIAccessibleText();
*start_offset = FindBoundary(
text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
@@ -1015,7 +1074,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_textBeforeOffset(
return S_FALSE;
}
- const string16& text_str = TextForIAccessibleText();
+ const base::string16& text_str = TextForIAccessibleText();
*start_offset = FindBoundary(
text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
@@ -1040,7 +1099,7 @@ STDMETHODIMP NativeViewAccessibilityWin::get_textAfterOffset(
return S_FALSE;
}
- const string16& text_str = TextForIAccessibleText();
+ const base::string16& text_str = TextForIAccessibleText();
*start_offset = offset;
*end_offset = FindBoundary(
@@ -1071,11 +1130,12 @@ STDMETHODIMP NativeViewAccessibilityWin::QueryService(
if (!view_)
return E_FAIL;
- if (riid == IID_IAccessible2)
+ if (riid == IID_IAccessible2 || riid == IID_IAccessible2_2)
AccessibleWebViewRegistry::GetInstance()->EnableIAccessible2Support();
if (guidService == IID_IAccessible ||
guidService == IID_IAccessible2 ||
+ guidService == IID_IAccessible2_2 ||
guidService == IID_IAccessibleText) {
return QueryInterface(riid, object);
}
@@ -1100,13 +1160,14 @@ STDMETHODIMP NativeViewAccessibilityWin::GetPatternProvider(
<< " for pattern id: "
<< id;
if (id == UIA_ValuePatternId || id == UIA_TextPatternId) {
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
long role = MSAARole(state.role);
if (role == ROLE_SYSTEM_TEXT) {
DVLOG(1) << "Returning UIA text provider";
- base::win::UIATextProvider::CreateTextProvider(true, provider);
+ base::win::UIATextProvider::CreateTextProvider(
+ state.value, true, provider);
return S_OK;
}
}
@@ -1120,7 +1181,7 @@ STDMETHODIMP NativeViewAccessibilityWin::GetPropertyValue(PROPERTYID id,
<< " for property id: "
<< id;
if (id == UIA_ControlTypePropertyId) {
- ui::AccessibleViewState state;
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
long role = MSAARole(state.role);
if (role == ROLE_SYSTEM_TEXT) {
@@ -1149,27 +1210,25 @@ void NativeViewAccessibility::UnregisterWebView(View* web_view) {
AccessibleWebViewRegistry::GetInstance()->UnregisterWebView(web_view);
}
-int32 NativeViewAccessibilityWin::MSAAEvent(AccessibilityTypes::Event event) {
+int32 NativeViewAccessibilityWin::MSAAEvent(ui::AXEvent event) {
switch (event) {
- case AccessibilityTypes::EVENT_ALERT:
+ case ui::AX_EVENT_ALERT:
return EVENT_SYSTEM_ALERT;
- case AccessibilityTypes::EVENT_FOCUS:
+ case ui::AX_EVENT_FOCUS:
return EVENT_OBJECT_FOCUS;
- case AccessibilityTypes::EVENT_MENUSTART:
+ case ui::AX_EVENT_MENU_START:
return EVENT_SYSTEM_MENUSTART;
- case AccessibilityTypes::EVENT_MENUEND:
+ case ui::AX_EVENT_MENU_END:
return EVENT_SYSTEM_MENUEND;
- case AccessibilityTypes::EVENT_MENUPOPUPSTART:
+ case ui::AX_EVENT_MENU_POPUP_START:
return EVENT_SYSTEM_MENUPOPUPSTART;
- case AccessibilityTypes::EVENT_MENUPOPUPEND:
+ case ui::AX_EVENT_MENU_POPUP_END:
return EVENT_SYSTEM_MENUPOPUPEND;
- case AccessibilityTypes::EVENT_NAME_CHANGED:
+ case ui::AX_EVENT_TEXT_CHANGED:
return EVENT_OBJECT_NAMECHANGE;
- case AccessibilityTypes::EVENT_TEXT_CHANGED:
- return EVENT_OBJECT_VALUECHANGE;
- case AccessibilityTypes::EVENT_SELECTION_CHANGED:
+ case ui::AX_EVENT_SELECTION_CHANGED:
return IA2_EVENT_TEXT_CARET_MOVED;
- case AccessibilityTypes::EVENT_VALUE_CHANGED:
+ case ui::AX_EVENT_VALUE_CHANGED:
return EVENT_OBJECT_VALUECHANGE;
default:
// Not supported or invalid event.
@@ -1178,109 +1237,109 @@ int32 NativeViewAccessibilityWin::MSAAEvent(AccessibilityTypes::Event event) {
}
}
-int32 NativeViewAccessibilityWin::MSAARole(AccessibilityTypes::Role role) {
+int32 NativeViewAccessibilityWin::MSAARole(ui::AXRole role) {
switch (role) {
- case AccessibilityTypes::ROLE_ALERT:
+ case ui::AX_ROLE_ALERT:
return ROLE_SYSTEM_ALERT;
- case AccessibilityTypes::ROLE_APPLICATION:
+ case ui::AX_ROLE_APPLICATION:
return ROLE_SYSTEM_APPLICATION;
- case AccessibilityTypes::ROLE_BUTTONDROPDOWN:
+ case ui::AX_ROLE_BUTTON_DROP_DOWN:
return ROLE_SYSTEM_BUTTONDROPDOWN;
- case AccessibilityTypes::ROLE_BUTTONMENU:
+ case ui::AX_ROLE_POP_UP_BUTTON:
return ROLE_SYSTEM_BUTTONMENU;
- case AccessibilityTypes::ROLE_CHECKBUTTON:
+ case ui::AX_ROLE_CHECK_BOX:
return ROLE_SYSTEM_CHECKBUTTON;
- case AccessibilityTypes::ROLE_COMBOBOX:
+ case ui::AX_ROLE_COMBO_BOX:
return ROLE_SYSTEM_COMBOBOX;
- case AccessibilityTypes::ROLE_DIALOG:
+ case ui::AX_ROLE_DIALOG:
return ROLE_SYSTEM_DIALOG;
- case AccessibilityTypes::ROLE_GRAPHIC:
- return ROLE_SYSTEM_GRAPHIC;
- case AccessibilityTypes::ROLE_GROUPING:
+ case ui::AX_ROLE_GROUP:
return ROLE_SYSTEM_GROUPING;
- case AccessibilityTypes::ROLE_LINK:
+ case ui::AX_ROLE_IMAGE:
+ return ROLE_SYSTEM_GRAPHIC;
+ case ui::AX_ROLE_LINK:
return ROLE_SYSTEM_LINK;
- case AccessibilityTypes::ROLE_LOCATION_BAR:
+ case ui::AX_ROLE_LOCATION_BAR:
return ROLE_SYSTEM_GROUPING;
- case AccessibilityTypes::ROLE_MENUBAR:
+ case ui::AX_ROLE_MENU_BAR:
return ROLE_SYSTEM_MENUBAR;
- case AccessibilityTypes::ROLE_MENUITEM:
+ case ui::AX_ROLE_MENU_ITEM:
return ROLE_SYSTEM_MENUITEM;
- case AccessibilityTypes::ROLE_MENUPOPUP:
+ case ui::AX_ROLE_MENU_LIST_POPUP:
return ROLE_SYSTEM_MENUPOPUP;
- case AccessibilityTypes::ROLE_OUTLINE:
+ case ui::AX_ROLE_TREE:
return ROLE_SYSTEM_OUTLINE;
- case AccessibilityTypes::ROLE_OUTLINEITEM:
+ case ui::AX_ROLE_TREE_ITEM:
return ROLE_SYSTEM_OUTLINEITEM;
- case AccessibilityTypes::ROLE_PAGETAB:
+ case ui::AX_ROLE_TAB:
return ROLE_SYSTEM_PAGETAB;
- case AccessibilityTypes::ROLE_PAGETABLIST:
+ case ui::AX_ROLE_TAB_LIST:
return ROLE_SYSTEM_PAGETABLIST;
- case AccessibilityTypes::ROLE_PANE:
+ case ui::AX_ROLE_PANE:
return ROLE_SYSTEM_PANE;
- case AccessibilityTypes::ROLE_PROGRESSBAR:
+ case ui::AX_ROLE_PROGRESS_INDICATOR:
return ROLE_SYSTEM_PROGRESSBAR;
- case AccessibilityTypes::ROLE_PUSHBUTTON:
+ case ui::AX_ROLE_BUTTON:
return ROLE_SYSTEM_PUSHBUTTON;
- case AccessibilityTypes::ROLE_RADIOBUTTON:
+ case ui::AX_ROLE_RADIO_BUTTON:
return ROLE_SYSTEM_RADIOBUTTON;
- case AccessibilityTypes::ROLE_SCROLLBAR:
+ case ui::AX_ROLE_SCROLL_BAR:
return ROLE_SYSTEM_SCROLLBAR;
- case AccessibilityTypes::ROLE_SEPARATOR:
+ case ui::AX_ROLE_SPLITTER:
return ROLE_SYSTEM_SEPARATOR;
- case AccessibilityTypes::ROLE_SLIDER:
+ case ui::AX_ROLE_SLIDER:
return ROLE_SYSTEM_SLIDER;
- case AccessibilityTypes::ROLE_STATICTEXT:
+ case ui::AX_ROLE_STATIC_TEXT:
return ROLE_SYSTEM_STATICTEXT;
- case AccessibilityTypes::ROLE_TEXT:
+ case ui::AX_ROLE_TEXT_FIELD:
return ROLE_SYSTEM_TEXT;
- case AccessibilityTypes::ROLE_TITLEBAR:
+ case ui::AX_ROLE_TITLE_BAR:
return ROLE_SYSTEM_TITLEBAR;
- case AccessibilityTypes::ROLE_TOOLBAR:
+ case ui::AX_ROLE_TOOLBAR:
return ROLE_SYSTEM_TOOLBAR;
- case AccessibilityTypes::ROLE_WINDOW:
+ case ui::AX_ROLE_WINDOW:
return ROLE_SYSTEM_WINDOW;
- case AccessibilityTypes::ROLE_CLIENT:
+ case ui::AX_ROLE_CLIENT:
default:
// This is the default role for MSAA.
return ROLE_SYSTEM_CLIENT;
}
}
-int32 NativeViewAccessibilityWin::MSAAState(AccessibilityTypes::State state) {
+int32 NativeViewAccessibilityWin::MSAAState(const ui::AXViewState& state) {
// This maps MSAA states for get_accState(). See also the IAccessible2
// interface get_states().
int32 msaa_state = 0;
- if (state & AccessibilityTypes::STATE_CHECKED)
+ if (state.HasStateFlag(ui::AX_STATE_CHECKED))
msaa_state |= STATE_SYSTEM_CHECKED;
- if (state & AccessibilityTypes::STATE_COLLAPSED)
+ if (state.HasStateFlag(ui::AX_STATE_COLLAPSED))
msaa_state |= STATE_SYSTEM_COLLAPSED;
- if (state & AccessibilityTypes::STATE_DEFAULT)
+ if (state.HasStateFlag(ui::AX_STATE_DEFAULT))
msaa_state |= STATE_SYSTEM_DEFAULT;
- if (state & AccessibilityTypes::STATE_EXPANDED)
+ if (state.HasStateFlag(ui::AX_STATE_EXPANDED))
msaa_state |= STATE_SYSTEM_EXPANDED;
- if (state & AccessibilityTypes::STATE_HASPOPUP)
+ if (state.HasStateFlag(ui::AX_STATE_HASPOPUP))
msaa_state |= STATE_SYSTEM_HASPOPUP;
- if (state & AccessibilityTypes::STATE_HOTTRACKED)
+ if (state.HasStateFlag(ui::AX_STATE_HOVERED))
msaa_state |= STATE_SYSTEM_HOTTRACKED;
- if (state & AccessibilityTypes::STATE_INVISIBLE)
+ if (state.HasStateFlag(ui::AX_STATE_INVISIBLE))
msaa_state |= STATE_SYSTEM_INVISIBLE;
- if (state & AccessibilityTypes::STATE_LINKED)
+ if (state.HasStateFlag(ui::AX_STATE_LINKED))
msaa_state |= STATE_SYSTEM_LINKED;
- if (state & AccessibilityTypes::STATE_OFFSCREEN)
+ if (state.HasStateFlag(ui::AX_STATE_OFFSCREEN))
msaa_state |= STATE_SYSTEM_OFFSCREEN;
- if (state & AccessibilityTypes::STATE_PRESSED)
+ if (state.HasStateFlag(ui::AX_STATE_PRESSED))
msaa_state |= STATE_SYSTEM_PRESSED;
- if (state & AccessibilityTypes::STATE_PROTECTED)
+ if (state.HasStateFlag(ui::AX_STATE_PROTECTED))
msaa_state |= STATE_SYSTEM_PROTECTED;
- if (state & AccessibilityTypes::STATE_READONLY)
+ if (state.HasStateFlag(ui::AX_STATE_READ_ONLY))
msaa_state |= STATE_SYSTEM_READONLY;
- if (state & AccessibilityTypes::STATE_SELECTED)
+ if (state.HasStateFlag(ui::AX_STATE_SELECTED))
msaa_state |= STATE_SYSTEM_SELECTED;
- if (state & AccessibilityTypes::STATE_FOCUSED)
+ if (state.HasStateFlag(ui::AX_STATE_FOCUSED))
msaa_state |= STATE_SYSTEM_FOCUSED;
- if (state & AccessibilityTypes::STATE_UNAVAILABLE)
+ if (state.HasStateFlag(ui::AX_STATE_DISABLED))
msaa_state |= STATE_SYSTEM_UNAVAILABLE;
return msaa_state;
}
@@ -1339,22 +1398,22 @@ void NativeViewAccessibilityWin::SetState(
msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
// Add on any view-specific states.
- ui::AccessibleViewState view_state;
+ ui::AXViewState view_state;
view->GetAccessibleState(&view_state);
- msaa_state->lVal |= MSAAState(view_state.state);
+ msaa_state->lVal |= MSAAState(view_state);
}
-string16 NativeViewAccessibilityWin::TextForIAccessibleText() {
- ui::AccessibleViewState state;
+base::string16 NativeViewAccessibilityWin::TextForIAccessibleText() {
+ ui::AXViewState state;
view_->GetAccessibleState(&state);
- if (state.role == AccessibilityTypes::ROLE_TEXT)
+ if (state.role == ui::AX_ROLE_TEXT_FIELD)
return state.value;
else
return state.name;
}
void NativeViewAccessibilityWin::HandleSpecialTextOffset(
- const string16& text, LONG* offset) {
+ const base::string16& text, LONG* offset) {
if (*offset == IA2_TEXT_OFFSET_LENGTH) {
*offset = static_cast<LONG>(text.size());
} else if (*offset == IA2_TEXT_OFFSET_CARET) {
@@ -1378,7 +1437,7 @@ ui::TextBoundaryType NativeViewAccessibilityWin::IA2TextBoundaryToTextBoundary(
}
LONG NativeViewAccessibilityWin::FindBoundary(
- const string16& text,
+ const base::string16& text,
IA2TextBoundaryType ia2_boundary,
LONG start_offset,
ui::TextBoundaryDirection direction) {
@@ -1414,4 +1473,32 @@ void NativeViewAccessibilityWin::PopulateChildWidgetVector(
}
}
+void NativeViewAccessibilityWin::AddAlertTarget() {
+ ViewStorage* view_storage = ViewStorage::GetInstance();
+ for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
+ int view_storage_id = alert_target_view_storage_ids_[i];
+ View* view = view_storage->RetrieveView(view_storage_id);
+ if (view == view_)
+ return;
+ }
+ int view_storage_id = view_storage->CreateStorageID();
+ view_storage->StoreView(view_storage_id, view_);
+ alert_target_view_storage_ids_.push_back(view_storage_id);
+}
+
+void NativeViewAccessibilityWin::RemoveAlertTarget() {
+ ViewStorage* view_storage = ViewStorage::GetInstance();
+ size_t i = 0;
+ while (i < alert_target_view_storage_ids_.size()) {
+ int view_storage_id = alert_target_view_storage_ids_[i];
+ View* view = view_storage->RetrieveView(view_storage_id);
+ if (view == NULL || view == view_) {
+ alert_target_view_storage_ids_.erase(
+ alert_target_view_storage_ids_.begin() + i);
+ } else {
+ ++i;
+ }
+ }
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win.h b/chromium/ui/views/accessibility/native_view_accessibility_win.h
index 83d03dbe5d8..ef593612345 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_win.h
+++ b/chromium/ui/views/accessibility/native_view_accessibility_win.h
@@ -12,9 +12,10 @@
#include <UIAutomationCore.h>
#include <set>
+#include <vector>
#include "third_party/iaccessible2/ia2_api_all.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view.h"
@@ -38,7 +39,7 @@ namespace views {
class __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
NativeViewAccessibilityWin
: public CComObjectRootEx<CComMultiThreadModel>,
- public IDispatchImpl<IAccessible2, &IID_IAccessible2,
+ public IDispatchImpl<IAccessible2_2, &IID_IAccessible2_2,
&LIBID_IAccessible2Lib>,
public IAccessibleText,
public IServiceProvider,
@@ -47,20 +48,21 @@ NativeViewAccessibilityWin
public NativeViewAccessibility {
public:
BEGIN_COM_MAP(NativeViewAccessibilityWin)
- COM_INTERFACE_ENTRY2(IDispatch, IAccessible2)
- COM_INTERFACE_ENTRY2(IAccessible, IAccessible2)
+ COM_INTERFACE_ENTRY2(IDispatch, IAccessible2_2)
+ COM_INTERFACE_ENTRY(IAccessible)
COM_INTERFACE_ENTRY(IAccessible2)
- COM_INTERFACE_ENTRY(IAccessibleText)
- COM_INTERFACE_ENTRY(IServiceProvider)
+ COM_INTERFACE_ENTRY(IAccessible2_2)
COM_INTERFACE_ENTRY(IAccessibleEx)
+ COM_INTERFACE_ENTRY(IAccessibleText)
COM_INTERFACE_ENTRY(IRawElementProviderSimple)
+ COM_INTERFACE_ENTRY(IServiceProvider)
END_COM_MAP()
virtual ~NativeViewAccessibilityWin();
// NativeViewAccessibility.
virtual void NotifyAccessibilityEvent(
- ui::AccessibilityTypes::Event event_type) OVERRIDE;
+ ui::AXEvent event_type) OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeObject() OVERRIDE;
virtual void Destroy() OVERRIDE;
@@ -145,6 +147,11 @@ NativeViewAccessibilityWin
STDMETHODIMP get_windowHandle(HWND* window_handle);
+ STDMETHODIMP get_relationTargetsOfType(BSTR type,
+ long max_targets,
+ IUnknown ***targets,
+ long *n_targets);
+
//
// IAccessible2 methods not implemented.
//
@@ -152,6 +159,9 @@ NativeViewAccessibilityWin
STDMETHODIMP get_attributes(BSTR* attributes) {
return E_NOTIMPL;
}
+ STDMETHODIMP get_attribute(BSTR name, VARIANT* attribute) {
+ return E_NOTIMPL;
+ }
STDMETHODIMP get_indexInParent(LONG* index_in_parent) {
return E_NOTIMPL;
}
@@ -205,6 +215,10 @@ NativeViewAccessibilityWin
STDMETHODIMP get_locale(IA2Locale* locale) {
return E_NOTIMPL;
}
+ STDMETHODIMP get_accessibleWithCaret(IUnknown** accessible,
+ long* caret_offset) {
+ return E_NOTIMPL;
+ }
//
// IAccessibleText methods.
@@ -337,17 +351,17 @@ NativeViewAccessibilityWin
// Static methods
- // Returns a conversion from the event (as defined in accessibility_types.h)
+ // Returns a conversion from the event (as defined in ax_enums.idl)
// to an MSAA event.
- static int32 MSAAEvent(ui::AccessibilityTypes::Event event);
+ static int32 MSAAEvent(ui::AXEvent event);
- // Returns a conversion from the Role (as defined in accessibility_types.h)
+ // Returns a conversion from the Role (as defined in ax_enums.idl)
// to an MSAA role.
- static int32 MSAARole(ui::AccessibilityTypes::Role role);
+ static int32 MSAARole(ui::AXRole role);
- // Returns a conversion from the State (as defined in accessibility_types.h)
+ // Returns a conversion from the State (as defined in ax_enums.idl)
// to MSAA states set.
- static int32 MSAAState(ui::AccessibilityTypes::State state);
+ static int32 MSAAState(const ui::AXViewState& state);
protected:
NativeViewAccessibilityWin();
@@ -374,11 +388,11 @@ NativeViewAccessibilityWin
void SetState(VARIANT* msaa_state, View* view);
// Return the text to use for IAccessibleText.
- string16 TextForIAccessibleText();
+ base::string16 TextForIAccessibleText();
// If offset is a member of IA2TextSpecialOffsets this function updates the
// value of offset and returns, otherwise offset remains unchanged.
- void HandleSpecialTextOffset(const string16& text, LONG* offset);
+ void HandleSpecialTextOffset(const base::string16& text, LONG* offset);
// Convert from a IA2TextBoundaryType to a ui::TextBoundaryType.
ui::TextBoundaryType IA2TextBoundaryToTextBoundary(IA2TextBoundaryType type);
@@ -386,7 +400,7 @@ NativeViewAccessibilityWin
// Search forwards (direction == 1) or backwards (direction == -1)
// from the given offset until the given boundary is found, and
// return the offset of that boundary.
- LONG FindBoundary(const string16& text,
+ LONG FindBoundary(const base::string16& text,
IA2TextBoundaryType ia2_boundary,
LONG start_offset,
ui::TextBoundaryDirection direction);
@@ -396,6 +410,12 @@ NativeViewAccessibilityWin
// NativeViewHost.
void PopulateChildWidgetVector(std::vector<Widget*>* child_widgets);
+ // Adds this view to alert_target_view_storage_ids_.
+ void AddAlertTarget();
+
+ // Removes this view from alert_target_view_storage_ids_.
+ void RemoveAlertTarget();
+
// Give CComObject access to the class constructor.
template <class Base> friend class CComObject;
@@ -418,6 +438,11 @@ NativeViewAccessibilityWin
// Next index into |view_storage_ids_| to use.
static int next_view_storage_id_index_;
+ // A vector of view storage ids of views that have been the target of
+ // an alert event, in order to provide an api to quickly identify all
+ // open alerts.
+ static std::vector<int> alert_target_view_storage_ids_;
+
DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityWin);
};
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc
index 5bd5bed7b91..3edab8e258e 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc
@@ -7,14 +7,33 @@
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_variant.h"
+#include "third_party/iaccessible2/ia2_api_all.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
+using base::win::ScopedBstr;
+using base::win::ScopedComPtr;
+using base::win::ScopedVariant;
+
namespace views {
namespace test {
-typedef ViewsTestBase NativeViewAcccessibilityWinTest;
+class NativeViewAcccessibilityWinTest : public ViewsTestBase {
+ public:
+ NativeViewAcccessibilityWinTest() {}
+ virtual ~NativeViewAcccessibilityWinTest() {}
+
+ protected:
+ void GetIAccessible2InterfaceForView(View* view, IAccessible2_2** result) {
+ ScopedComPtr<IAccessible> view_accessible(
+ view->GetNativeViewAccessible());
+ ScopedComPtr<IServiceProvider> service_provider;
+ ASSERT_EQ(S_OK, view_accessible.QueryInterface(service_provider.Receive()));
+ ASSERT_EQ(S_OK,
+ service_provider->QueryService(IID_IAccessible2_2, result));
+ }
+};
TEST_F(NativeViewAcccessibilityWinTest, TextfieldAccessibility) {
Widget widget;
@@ -31,32 +50,32 @@ TEST_F(NativeViewAcccessibilityWinTest, TextfieldAccessibility) {
textfield->SetText(L"Value");
content->AddChildView(textfield);
- base::win::ScopedComPtr<IAccessible> content_accessible(
+ ScopedComPtr<IAccessible> content_accessible(
content->GetNativeViewAccessible());
LONG child_count = 0;
ASSERT_EQ(S_OK, content_accessible->get_accChildCount(&child_count));
ASSERT_EQ(1L, child_count);
- base::win::ScopedComPtr<IDispatch> textfield_dispatch;
- base::win::ScopedComPtr<IAccessible> textfield_accessible;
- base::win::ScopedVariant child_index(1);
+ ScopedComPtr<IDispatch> textfield_dispatch;
+ ScopedComPtr<IAccessible> textfield_accessible;
+ ScopedVariant child_index(1);
ASSERT_EQ(S_OK, content_accessible->get_accChild(
child_index, textfield_dispatch.Receive()));
ASSERT_EQ(S_OK, textfield_dispatch.QueryInterface(
textfield_accessible.Receive()));
- base::win::ScopedBstr name;
- base::win::ScopedVariant childid_self(CHILDID_SELF);
+ ScopedBstr name;
+ ScopedVariant childid_self(CHILDID_SELF);
ASSERT_EQ(S_OK, textfield_accessible->get_accName(
childid_self, name.Receive()));
ASSERT_STREQ(L"Name", name);
- base::win::ScopedBstr value;
+ ScopedBstr value;
ASSERT_EQ(S_OK, textfield_accessible->get_accValue(
childid_self, value.Receive()));
ASSERT_STREQ(L"Value", value);
- base::win::ScopedBstr new_value(L"New value");
+ ScopedBstr new_value(L"New value");
ASSERT_EQ(S_OK, textfield_accessible->put_accValue(childid_self, new_value));
ASSERT_STREQ(L"New value", textfield->text().c_str());
@@ -81,17 +100,16 @@ TEST_F(NativeViewAcccessibilityWinTest, UnattachedWebView) {
content->AddChildView(web_view);
NativeViewAccessibility::RegisterWebView(web_view);
- base::win::ScopedComPtr<IAccessible> web_view_accessible(
+ ScopedComPtr<IAccessible> web_view_accessible(
web_view->GetNativeViewAccessible());
- base::win::ScopedComPtr<IDispatch> result_dispatch;
- base::win::ScopedVariant child_index(-999);
+ ScopedComPtr<IDispatch> result_dispatch;
+ ScopedVariant child_index(-999);
ASSERT_EQ(E_FAIL, web_view_accessible->get_accChild(
child_index, result_dispatch.Receive()));
NativeViewAccessibility::UnregisterWebView(web_view);
}
-#if defined(USE_AURA)
TEST_F(NativeViewAcccessibilityWinTest, AuraOwnedWidgets) {
Widget widget;
Widget::InitParams init_params =
@@ -99,7 +117,7 @@ TEST_F(NativeViewAcccessibilityWinTest, AuraOwnedWidgets) {
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(init_params);
- base::win::ScopedComPtr<IAccessible> root_view_accessible(
+ ScopedComPtr<IAccessible> root_view_accessible(
widget.GetRootView()->GetNativeViewAccessible());
LONG child_count = 0;
@@ -110,7 +128,6 @@ TEST_F(NativeViewAcccessibilityWinTest, AuraOwnedWidgets) {
Widget::InitParams owned_init_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
owned_init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- owned_init_params.child = false;
owned_init_params.parent = widget.GetNativeView();
owned_widget.Init(owned_init_params);
owned_widget.Show();
@@ -118,7 +135,70 @@ TEST_F(NativeViewAcccessibilityWinTest, AuraOwnedWidgets) {
ASSERT_EQ(S_OK, root_view_accessible->get_accChildCount(&child_count));
ASSERT_EQ(2L, child_count);
}
-#endif
+
+TEST_F(NativeViewAcccessibilityWinTest, RetrieveAllAlerts) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(init_params);
+
+ View* content = new View;
+ widget.SetContentsView(content);
+
+ View* infobar = new View;
+ content->AddChildView(infobar);
+
+ View* infobar2 = new View;
+ content->AddChildView(infobar2);
+
+ View* root_view = content->parent();
+ ASSERT_EQ(NULL, root_view->parent());
+
+ ScopedComPtr<IAccessible2_2> root_view_accessible;
+ GetIAccessible2InterfaceForView(root_view, root_view_accessible.Receive());
+
+ ScopedComPtr<IAccessible2_2> infobar_accessible;
+ GetIAccessible2InterfaceForView(infobar, infobar_accessible.Receive());
+
+ ScopedComPtr<IAccessible2_2> infobar2_accessible;
+ GetIAccessible2InterfaceForView(infobar2, infobar2_accessible.Receive());
+
+ // Initially, there are no alerts
+ ScopedBstr alerts_bstr(L"alerts");
+ IUnknown** targets;
+ long n_targets;
+ ASSERT_EQ(S_FALSE, root_view_accessible->get_relationTargetsOfType(
+ alerts_bstr, 0, &targets, &n_targets));
+ ASSERT_EQ(0, n_targets);
+
+ // Fire alert events on the infobars.
+ infobar->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
+ infobar2->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
+
+ // Now calling get_relationTargetsOfType should retrieve the alerts.
+ ASSERT_EQ(S_OK, root_view_accessible->get_relationTargetsOfType(
+ alerts_bstr, 0, &targets, &n_targets));
+ ASSERT_EQ(2, n_targets);
+ ASSERT_TRUE(infobar_accessible.IsSameObject(targets[0]));
+ ASSERT_TRUE(infobar2_accessible.IsSameObject(targets[1]));
+ CoTaskMemFree(targets);
+
+ // If we set max_targets to 1, we should only get the first one.
+ ASSERT_EQ(S_OK, root_view_accessible->get_relationTargetsOfType(
+ alerts_bstr, 1, &targets, &n_targets));
+ ASSERT_EQ(1, n_targets);
+ ASSERT_TRUE(infobar_accessible.IsSameObject(targets[0]));
+ CoTaskMemFree(targets);
+
+ // If we delete the first view, we should only get the second one now.
+ delete infobar;
+ ASSERT_EQ(S_OK, root_view_accessible->get_relationTargetsOfType(
+ alerts_bstr, 0, &targets, &n_targets));
+ ASSERT_EQ(1, n_targets);
+ ASSERT_TRUE(infobar2_accessible.IsSameObject(targets[0]));
+ CoTaskMemFree(targets);
+}
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessible_pane_view.cc b/chromium/ui/views/accessible_pane_view.cc
index 35ca7bf6e83..a0bbd5665fc 100644
--- a/chromium/ui/views/accessible_pane_view.cc
+++ b/chromium/ui/views/accessible_pane_view.cc
@@ -5,7 +5,7 @@
#include "ui/views/accessible_pane_view.h"
#include "base/message_loop/message_loop.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/views/focus/focus_search.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/widget/widget.h"
@@ -207,8 +207,8 @@ void AccessiblePaneView::SetVisible(bool flag) {
View::SetVisible(flag);
}
-void AccessiblePaneView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PANE;
+void AccessiblePaneView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_PANE;
}
void AccessiblePaneView::RequestFocus() {
diff --git a/chromium/ui/views/accessible_pane_view.h b/chromium/ui/views/accessible_pane_view.h
index b3ab9b770e1..cde84a75243 100644
--- a/chromium/ui/views/accessible_pane_view.h
+++ b/chromium/ui/views/accessible_pane_view.h
@@ -44,7 +44,7 @@ class VIEWS_EXPORT AccessiblePaneView : public View,
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator)
OVERRIDE;
virtual void SetVisible(bool flag) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void RequestFocus() OVERRIDE;
// Overridden from FocusChangeListener:
diff --git a/chromium/ui/views/accessible_pane_view_unittest.cc b/chromium/ui/views/accessible_pane_view_unittest.cc
index 02778d6beb5..4468f2ffe3e 100644
--- a/chromium/ui/views/accessible_pane_view_unittest.cc
+++ b/chromium/ui/views/accessible_pane_view_unittest.cc
@@ -57,7 +57,7 @@ void TestBarView::ButtonPressed(Button* sender, const ui::Event& event) {
void TestBarView::Init() {
SetLayoutManager(new FillLayout());
- string16 label;
+ base::string16 label;
child_button_.reset(new LabelButton(this, label));
AddChildView(child_button_.get());
second_child_button_.reset(new LabelButton(this, label));
@@ -101,7 +101,6 @@ TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus) {
// This test will not work properly in Windows because it uses ::GetNextWindow
// on deactivate which is rather unpredictable where the focus will land.
-#if !defined(OS_WIN)||defined(USE_AURA)
TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) {
View* test_view_main = new View();
scoped_ptr<Widget> widget_main(new Widget());
@@ -145,7 +144,6 @@ TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) {
widget_main->CloseNow();
widget_main.reset();
}
-#endif // !defined(OS_WIN)||defined(USE_AURA)
TEST_F(AccessiblePaneViewTest, TwoSetPaneFocus) {
TestBarView* test_view = new TestBarView();
diff --git a/chromium/ui/views/animation/bounds_animator.cc b/chromium/ui/views/animation/bounds_animator.cc
index 839294ff74c..ba9412722e0 100644
--- a/chromium/ui/views/animation/bounds_animator.cc
+++ b/chromium/ui/views/animation/bounds_animator.cc
@@ -110,13 +110,12 @@ const SlideAnimation* BoundsAnimator::GetAnimationForView(View* view) {
return !IsAnimating(view) ? NULL : data_[view].animation;
}
-void BoundsAnimator::SetAnimationDelegate(View* view,
- AnimationDelegate* delegate,
- bool delete_when_done) {
+void BoundsAnimator::SetAnimationDelegate(
+ View* view,
+ scoped_ptr<AnimationDelegate> delegate) {
DCHECK(IsAnimating(view));
- data_[view].delegate = delegate;
- data_[view].delete_delegate_when_done = delete_when_done;
+ data_[view].delegate = delegate.release();
}
void BoundsAnimator::StopAnimatingView(View* view) {
@@ -177,10 +176,8 @@ void BoundsAnimator::CleanupData(bool send_cancel, Data* data, View* view) {
if (send_cancel && data->delegate)
data->delegate->AnimationCanceled(data->animation);
- if (data->delete_delegate_when_done) {
- delete static_cast<OwnedAnimationDelegate*>(data->delegate);
- data->delegate = NULL;
- }
+ delete data->delegate;
+ data->delegate = NULL;
if (data->animation) {
data->animation->set_delegate(NULL);
diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h
index 1688dd56235..1a88cdf0575 100644
--- a/chromium/ui/views/animation/bounds_animator.h
+++ b/chromium/ui/views/animation/bounds_animator.h
@@ -38,13 +38,6 @@ class View;
class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
public gfx::AnimationContainerObserver {
public:
- // If |delete_when_done| is set to true in |SetAnimationDelegate| the
- // |AnimationDelegate| must subclass this class.
- class OwnedAnimationDelegate : public gfx::AnimationDelegate {
- public:
- virtual ~OwnedAnimationDelegate() {}
- };
-
explicit BoundsAnimator(View* view);
virtual ~BoundsAnimator();
@@ -74,12 +67,9 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// Stops animating the specified view.
void StopAnimatingView(View* view);
- // Sets the delegate for the animation created for the specified view. If
- // |delete_when_done| is true the |delegate| is deleted when done and
- // |delegate| must subclass OwnedAnimationDelegate.
+ // Sets the delegate for the animation for the specified view.
void SetAnimationDelegate(View* view,
- gfx::AnimationDelegate* delegate,
- bool delete_when_done);
+ scoped_ptr<gfx::AnimationDelegate> delegate);
// Returns true if BoundsAnimator is animating the bounds of |view|.
bool IsAnimating(View* view) const;
@@ -95,6 +85,9 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// milliseconds.
void SetAnimationDuration(int duration_ms);
+ // Gets the currently used animation duration.
+ int GetAnimationDuration() const { return animation_duration_ms_; }
+
// Sets the tween type for new animations. Default is EASE_OUT.
void set_tween_type(gfx::Tween::Type type) { tween_type_ = type; }
@@ -108,13 +101,7 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
private:
// Tracks data about the view being animated.
struct Data {
- Data()
- : delete_delegate_when_done(false),
- animation(NULL),
- delegate(NULL) {}
-
- // If true the delegate is deleted when done.
- bool delete_delegate_when_done;
+ Data() : animation(NULL), delegate(NULL) {}
// The initial bounds.
gfx::Rect start_bounds;
@@ -125,7 +112,7 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// The animation. We own this.
gfx::SlideAnimation* animation;
- // Additional delegate for the animation, may be null.
+ // Delegate for the animation, may be null. We own this.
gfx::AnimationDelegate* delegate;
};
diff --git a/chromium/ui/views/animation/bounds_animator_unittest.cc b/chromium/ui/views/animation/bounds_animator_unittest.cc
index 0928fe665b0..6294d8a5912 100644
--- a/chromium/ui/views/animation/bounds_animator_unittest.cc
+++ b/chromium/ui/views/animation/bounds_animator_unittest.cc
@@ -32,7 +32,7 @@ class TestBoundsAnimator : public BoundsAnimator {
DISALLOW_COPY_AND_ASSIGN(TestBoundsAnimator);
};
-class OwnedDelegate : public BoundsAnimator::OwnedAnimationDelegate {
+class OwnedDelegate : public gfx::AnimationDelegate {
public:
OwnedDelegate() {}
@@ -110,12 +110,12 @@ class BoundsAnimatorTest : public testing::Test {
// Checks animate view to.
TEST_F(BoundsAnimatorTest, AnimateViewTo) {
- TestAnimationDelegate delegate;
gfx::Rect initial_bounds(0, 0, 10, 10);
child()->SetBoundsRect(initial_bounds);
gfx::Rect target_bounds(10, 10, 20, 20);
animator()->AnimateViewTo(child(), target_bounds);
- animator()->SetAnimationDelegate(child(), &delegate, false);
+ animator()->SetAnimationDelegate(
+ child(), scoped_ptr<gfx::AnimationDelegate>(new TestAnimationDelegate()));
// The animator should be animating now.
EXPECT_TRUE(animator()->IsAnimating());
@@ -136,7 +136,8 @@ TEST_F(BoundsAnimatorTest, AnimateViewTo) {
// Make sure an AnimationDelegate is deleted when canceled.
TEST_F(BoundsAnimatorTest, DeleteDelegateOnCancel) {
animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10));
- animator()->SetAnimationDelegate(child(), new OwnedDelegate(), true);
+ animator()->SetAnimationDelegate(
+ child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate()));
animator()->Cancel();
@@ -152,7 +153,8 @@ TEST_F(BoundsAnimatorTest, DeleteDelegateOnCancel) {
// scheduled.
TEST_F(BoundsAnimatorTest, DeleteDelegateOnNewAnimate) {
animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10));
- animator()->SetAnimationDelegate(child(), new OwnedDelegate(), true);
+ animator()->SetAnimationDelegate(
+ child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate()));
animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10));
@@ -166,7 +168,8 @@ TEST_F(BoundsAnimatorTest, StopAnimating) {
scoped_ptr<OwnedDelegate> delegate(new OwnedDelegate());
animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10));
- animator()->SetAnimationDelegate(child(), new OwnedDelegate(), true);
+ animator()->SetAnimationDelegate(
+ child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate()));
animator()->StopAnimatingView(child());
diff --git a/chromium/ui/views/background.cc b/chromium/ui/views/background.cc
index b37318dc2b4..bb2ddd0928e 100644
--- a/chromium/ui/views/background.cc
+++ b/chromium/ui/views/background.cc
@@ -94,12 +94,7 @@ Background* Background::CreateSolidBackground(SkColor color) {
//static
Background* Background::CreateStandardPanelBackground() {
// TODO(beng): Should be in NativeTheme.
-#if defined(USE_AURA)
return CreateSolidBackground(SK_ColorWHITE);
-#else
- return CreateVerticalGradientBackground(SkColorSetRGB(246, 250, 255),
- SkColorSetRGB(219, 235, 255));
-#endif
}
//static
diff --git a/chromium/ui/views/border.cc b/chromium/ui/views/border.cc
index f347c2a8369..0ff340642e0 100644
--- a/chromium/ui/views/border.cc
+++ b/chromium/ui/views/border.cc
@@ -133,36 +133,37 @@ Border::~Border() {
}
// static
-Border* Border::CreateSolidBorder(int thickness, SkColor color) {
- return new SolidBorder(thickness, color);
+scoped_ptr<Border> Border::NullBorder() {
+ return scoped_ptr<Border>();
}
// static
-Border* Border::CreateEmptyBorder(int top, int left, int bottom, int right) {
- return new EmptyBorder(top, left, bottom, right);
+scoped_ptr<Border> Border::CreateSolidBorder(int thickness, SkColor color) {
+ return scoped_ptr<Border>(new SolidBorder(thickness, color));
}
// static
-Border* Border::CreateSolidSidedBorder(int top,
- int left,
- int bottom,
- int right,
- SkColor color) {
- return new SidedSolidBorder(top, left, bottom, right, color);
+scoped_ptr<Border> Border::CreateEmptyBorder(int top,
+ int left,
+ int bottom,
+ int right) {
+ return scoped_ptr<Border>(new EmptyBorder(top, left, bottom, right));
}
// static
-Border* Border::CreateBorderPainter(Painter* painter,
- const gfx::Insets& insets) {
- return new BorderPainter(painter, insets);
+scoped_ptr<Border> Border::CreateSolidSidedBorder(int top,
+ int left,
+ int bottom,
+ int right,
+ SkColor color) {
+ return scoped_ptr<Border>(
+ new SidedSolidBorder(top, left, bottom, right, color));
}
-TextButtonBorder* Border::AsTextButtonBorder() {
- return NULL;
-}
-
-const TextButtonBorder* Border::AsTextButtonBorder() const {
- return NULL;
+// static
+scoped_ptr<Border> Border::CreateBorderPainter(Painter* painter,
+ const gfx::Insets& insets) {
+ return scoped_ptr<Border>(new BorderPainter(painter, insets));
}
} // namespace views
diff --git a/chromium/ui/views/border.h b/chromium/ui/views/border.h
index 2e9c56bf4bf..d2657c60c13 100644
--- a/chromium/ui/views/border.h
+++ b/chromium/ui/views/border.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_BORDER_H_
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/insets.h"
#include "ui/views/views_export.h"
@@ -26,7 +27,7 @@ class View;
//
// The border class is used to display a border around a view.
// To set a border on a view, just call SetBorder on the view, for example:
-// view->set_border(Border::CreateSolidBorder(1, SkColorSetRGB(25, 25, 112));
+// view->SetBorder(Border::CreateSolidBorder(1, SkColorSetRGB(25, 25, 112));
// Once set on a view, the border is owned by the view.
//
// IMPORTANT NOTE: not all views support borders at this point. In order to
@@ -36,34 +37,38 @@ class View;
//
////////////////////////////////////////////////////////////////////////////////
-class TextButtonBorder;
-
class VIEWS_EXPORT Border {
public:
Border();
virtual ~Border();
+ // Convenience for creating a scoped_ptr with no Border.
+ static scoped_ptr<Border> NullBorder();
+
// Creates a border that is a simple line of the specified thickness and
// color.
- static Border* CreateSolidBorder(int thickness, SkColor color);
+ static scoped_ptr<Border> CreateSolidBorder(int thickness, SkColor color);
// Creates a border for reserving space. The returned border does not
// paint anything.
- static Border* CreateEmptyBorder(int top, int left, int bottom, int right);
+ static scoped_ptr<Border> CreateEmptyBorder(int top,
+ int left,
+ int bottom,
+ int right);
// Creates a border of the specified color, and specified thickness on each
// side.
- static Border* CreateSolidSidedBorder(int top,
- int left,
- int bottom,
- int right,
- SkColor color);
+ static scoped_ptr<Border> CreateSolidSidedBorder(int top,
+ int left,
+ int bottom,
+ int right,
+ SkColor color);
// Creates a Border from the specified Painter. The border owns the painter,
// thus the painter is deleted when the Border is deleted.
// |insets| define size of an area allocated for a Border.
- static Border* CreateBorderPainter(Painter* painter,
- const gfx::Insets& insets);
+ static scoped_ptr<Border> CreateBorderPainter(Painter* painter,
+ const gfx::Insets& insets);
// Renders the border for the specified view.
virtual void Paint(const View& view, gfx::Canvas* canvas) = 0;
@@ -79,10 +84,6 @@ class VIEWS_EXPORT Border {
// content laid out relative to these images.
virtual gfx::Size GetMinimumSize() const = 0;
- // Manual RTTI for text buttons.
- virtual TextButtonBorder* AsTextButtonBorder();
- virtual const TextButtonBorder* AsTextButtonBorder() const;
-
private:
DISALLOW_COPY_AND_ASSIGN(Border);
};
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index aa9064ee970..03b422aefb2 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -156,7 +156,8 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
arrow_paint_type_(PAINT_NORMAL),
alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
shadow_(shadow),
- background_color_(color) {
+ background_color_(color),
+ use_theme_background_color_(false) {
DCHECK(shadow < SHADOW_COUNT);
images_ = GetBorderImages(shadow);
}
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 4fb961e6fb4..15f0f85f60d 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -136,6 +136,13 @@ class VIEWS_EXPORT BubbleBorder : public Border {
void set_background_color(SkColor color) { background_color_ = color; }
SkColor background_color() const { return background_color_; }
+ // If true, the background color should be determined by the host's
+ // NativeTheme.
+ void set_use_theme_background_color(bool use_theme_background_color) {
+ use_theme_background_color_ = use_theme_background_color;
+ }
+ bool use_theme_background_color() { return use_theme_background_color_; }
+
// Sets a desired pixel distance between the arrow tip and the outside edge of
// the neighboring border image. For example: |----offset----|
// '(' represents shadow around the '{' edge: ((({ ^ })))
@@ -178,6 +185,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
Shadow shadow_;
internal::BorderImages* images_;
SkColor background_color_;
+ bool use_theme_background_color_;
DISALLOW_COPY_AND_ASSIGN(BubbleBorder);
};
diff --git a/chromium/ui/views/bubble/bubble_delegate.cc b/chromium/ui/views/bubble/bubble_delegate.cc
index dbd0cae85fe..0eab071ad0c 100644
--- a/chromium/ui/views/bubble/bubble_delegate.cc
+++ b/chromium/ui/views/bubble/bubble_delegate.cc
@@ -4,8 +4,8 @@
#include "ui/views/bubble/bubble_delegate.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/gfx/animation/slide_animation.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/rect.h"
#include "ui/native_theme/native_theme.h"
@@ -18,9 +18,6 @@
#include "ui/base/win/shell.h"
#endif
-// The duration of the fade animation in milliseconds.
-static const int kHideFadeDurationMS = 200;
-
// The defaut margin between the content and the inside border, in pixels.
static const int kDefaultMargin = 6;
@@ -39,7 +36,8 @@ Widget* CreateBubbleWidget(BubbleDelegateView* bubble) {
bubble_params.parent = bubble->parent_window();
else if (bubble->anchor_widget())
bubble_params.parent = bubble->anchor_widget()->GetNativeView();
- bubble_params.can_activate = bubble->CanActivate();
+ bubble_params.activatable = bubble->CanActivate() ?
+ Widget::InitParams::ACTIVATABLE_YES : Widget::InitParams::ACTIVATABLE_NO;
bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget);
bubble_widget->Init(bubble_params);
return bubble_widget;
@@ -52,12 +50,10 @@ BubbleDelegateView::BubbleDelegateView()
close_on_deactivate_(true),
anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
anchor_widget_(NULL),
- move_with_anchor_(false),
arrow_(BubbleBorder::TOP_LEFT),
shadow_(BubbleBorder::SMALL_SHADOW),
color_explicitly_set_(false),
margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
- original_opacity_(255),
use_focusless_(false),
accept_events_(true),
border_accepts_events_(true),
@@ -74,12 +70,10 @@ BubbleDelegateView::BubbleDelegateView(
close_on_deactivate_(true),
anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()),
anchor_widget_(NULL),
- move_with_anchor_(false),
arrow_(arrow),
shadow_(BubbleBorder::SMALL_SHADOW),
color_explicitly_set_(false),
margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin),
- original_opacity_(255),
use_focusless_(false),
accept_events_(true),
border_accepts_events_(true),
@@ -91,6 +85,8 @@ BubbleDelegateView::BubbleDelegateView(
}
BubbleDelegateView::~BubbleDelegateView() {
+ if (GetWidget())
+ GetWidget()->RemoveObserver(this);
SetLayoutManager(NULL);
SetAnchorView(NULL);
}
@@ -102,11 +98,14 @@ Widget* BubbleDelegateView::CreateBubble(BubbleDelegateView* bubble_delegate) {
bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView());
Widget* bubble_widget = CreateBubbleWidget(bubble_delegate);
-#if defined(OS_WIN) && defined(USE_AURA)
+#if defined(OS_WIN)
// If glass is enabled, the bubble is allowed to extend outside the bounds of
// the parent frame and let DWM handle compositing. If not, then we don't
// want to allow the bubble to extend the frame because it will be clipped.
bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled());
+#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Linux clips bubble windows that extend outside their parent window bounds.
+ bubble_delegate->set_adjust_if_offscreen(false);
#endif
bubble_delegate->SizeToContents();
@@ -133,15 +132,19 @@ View* BubbleDelegateView::GetContentsView() {
NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView(
Widget* widget) {
BubbleFrameView* frame = new BubbleFrameView(margins());
+ // Note: In CreateBubble, the call to SizeToContents() will cause
+ // the relayout that this call requires.
+ frame->SetTitleFontList(GetTitleFontList());
BubbleBorder::Arrow adjusted_arrow = arrow();
if (base::i18n::IsRTL())
adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow);
- frame->SetBubbleBorder(new BubbleBorder(adjusted_arrow, shadow(), color()));
+ frame->SetBubbleBorder(scoped_ptr<BubbleBorder>(
+ new BubbleBorder(adjusted_arrow, shadow(), color())));
return frame;
}
-void BubbleDelegateView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_DIALOG;
+void BubbleDelegateView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_DIALOG;
}
void BubbleDelegateView::OnWidgetDestroying(Widget* widget) {
@@ -174,19 +177,15 @@ void BubbleDelegateView::OnWidgetActivationChanged(Widget* widget,
void BubbleDelegateView::OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) {
- if (anchor_widget() == widget) {
- if (move_with_anchor())
- SizeToContents();
- else
- GetWidget()->Close();
- }
+ if (anchor_widget() == widget)
+ SizeToContents();
}
View* BubbleDelegateView::GetAnchorView() const {
return ViewStorage::GetInstance()->RetrieveView(anchor_view_storage_id_);
}
-gfx::Rect BubbleDelegateView::GetAnchorRect() {
+gfx::Rect BubbleDelegateView::GetAnchorRect() const {
if (!GetAnchorView())
return anchor_rect_;
@@ -199,36 +198,6 @@ void BubbleDelegateView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
Widget* widget) const {
}
-void BubbleDelegateView::StartFade(bool fade_in) {
-#if defined(USE_AURA)
- // Use AURA's window layer animation instead of fading. This ensures that
- // hosts which rely on the layer animation callbacks to close the window
- // work correctly.
- if (fade_in)
- GetWidget()->Show();
- else
- GetWidget()->Close();
-#else
- fade_animation_.reset(new gfx::SlideAnimation(this));
- fade_animation_->SetSlideDuration(GetFadeDuration());
- fade_animation_->Reset(fade_in ? 0.0 : 1.0);
- if (fade_in) {
- original_opacity_ = 0;
- GetWidget()->SetOpacity(original_opacity_);
- GetWidget()->Show();
- fade_animation_->Show();
- } else {
- original_opacity_ = 255;
- fade_animation_->Hide();
- }
-#endif
-}
-
-void BubbleDelegateView::ResetFade() {
- fade_animation_.reset();
- GetWidget()->SetOpacity(original_opacity_);
-}
-
void BubbleDelegateView::SetAlignment(BubbleBorder::BubbleAlignment alignment) {
GetBubbleFrameView()->bubble_border()->set_alignment(alignment);
SizeToContents();
@@ -248,8 +217,6 @@ bool BubbleDelegateView::AcceleratorPressed(
const ui::Accelerator& accelerator) {
if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE)
return false;
- if (fade_animation_.get())
- fade_animation_->Reset();
GetWidget()->Close();
return true;
}
@@ -258,22 +225,6 @@ void BubbleDelegateView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
UpdateColorsFromTheme(theme);
}
-void BubbleDelegateView::AnimationEnded(const gfx::Animation* animation) {
- if (animation != fade_animation_.get())
- return;
- bool closed = fade_animation_->GetCurrentValue() == 0;
- fade_animation_->Reset();
- if (closed)
- GetWidget()->Close();
-}
-
-void BubbleDelegateView::AnimationProgressed(const gfx::Animation* animation) {
- if (animation != fade_animation_.get())
- return;
- DCHECK(fade_animation_->is_animating());
- GetWidget()->SetOpacity(fade_animation_->GetCurrentValue() * 255);
-}
-
void BubbleDelegateView::Init() {}
void BubbleDelegateView::SetAnchorView(View* anchor_view) {
@@ -298,7 +249,11 @@ void BubbleDelegateView::SetAnchorView(View* anchor_view) {
if (anchor_view)
view_storage->StoreView(anchor_view_storage_id_, anchor_view);
- if (GetWidget())
+ // Do not update anchoring for NULL views; this could indicate that our
+ // NativeWindow is being destroyed, so it would be dangerous for us to update
+ // our anchor bounds at that point. (It's safe to skip this, since if we were
+ // to update the bounds when |anchor_view| is NULL, the bubble won't move.)
+ if (anchor_view && GetWidget())
OnAnchorBoundsChanged();
}
@@ -321,19 +276,20 @@ BubbleFrameView* BubbleDelegateView::GetBubbleFrameView() const {
gfx::Rect BubbleDelegateView::GetBubbleBounds() {
// The argument rect has its origin at the bubble's arrow anchor point;
// its size is the preferred size of the bubble's client view (this view).
+ bool anchor_minimized = anchor_widget() && anchor_widget()->IsMinimized();
return GetBubbleFrameView()->GetUpdatedWindowBounds(GetAnchorRect(),
- GetPreferredSize(), adjust_if_offscreen_);
+ GetPreferredSize(), adjust_if_offscreen_ && !anchor_minimized);
}
-int BubbleDelegateView::GetFadeDuration() {
- return kHideFadeDurationMS;
+const gfx::FontList& BubbleDelegateView::GetTitleFontList() const {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ return rb.GetFontList(ui::ResourceBundle::MediumFont);
}
+
void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
- if (!color_explicitly_set_) {
- color_ = GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_WindowBackground);
- }
+ if (!color_explicitly_set_)
+ color_ = theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
set_background(Background::CreateSolidBackground(color()));
BubbleFrameView* frame_view = GetBubbleFrameView();
if (frame_view)
@@ -341,9 +297,12 @@ void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
}
void BubbleDelegateView::HandleVisibilityChanged(Widget* widget, bool visible) {
- if (widget == GetWidget() && visible && anchor_widget() &&
+ if (widget == GetWidget() && anchor_widget() &&
anchor_widget()->GetTopLevelWidget()) {
- anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
+ if (visible)
+ anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
+ else
+ anchor_widget()->GetTopLevelWidget()->EnableInactiveRendering();
}
}
diff --git a/chromium/ui/views/bubble/bubble_delegate.h b/chromium/ui/views/bubble/bubble_delegate.h
index 4bf8ff68c73..e61111b096d 100644
--- a/chromium/ui/views/bubble/bubble_delegate.h
+++ b/chromium/ui/views/bubble/bubble_delegate.h
@@ -6,15 +6,14 @@
#define UI_VIEWS_BUBBLE_BUBBLE_DELEGATE_H_
#include "base/gtest_prod_util.h"
-#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_observer.h"
namespace gfx {
+class FontList;
class Rect;
-class SlideAnimation;
}
namespace views {
@@ -24,7 +23,6 @@ class BubbleFrameView;
// BubbleDelegateView creates frame and client views for bubble Widgets.
// BubbleDelegateView itself is the client's contents view.
class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
- public gfx::AnimationDelegate,
public WidgetObserver {
public:
BubbleDelegateView();
@@ -40,7 +38,7 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
virtual bool ShouldShowCloseButton() const OVERRIDE;
virtual View* GetContentsView() OVERRIDE;
virtual NonClientFrameView* CreateNonClientFrameView(Widget* widget) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// WidgetObserver overrides:
virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
@@ -97,23 +95,13 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
bool adjust_if_offscreen() const { return adjust_if_offscreen_; }
void set_adjust_if_offscreen(bool adjust) { adjust_if_offscreen_ = adjust; }
- bool move_with_anchor() const { return move_with_anchor_; }
- void set_move_with_anchor(bool move) { move_with_anchor_ = move; }
-
// Get the arrow's anchor rect in screen space.
- virtual gfx::Rect GetAnchorRect();
+ virtual gfx::Rect GetAnchorRect() const;
// Allows delegates to provide custom parameters before widget initialization.
virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
Widget* widget) const;
- // Fade the bubble in or out by animation Widget transparency.
- // Fade-in calls Widget::Show; fade-out calls Widget::Close upon completion.
- void StartFade(bool fade_in);
-
- // Restores bubble opacity to its value before StartFade() was called.
- void ResetFade();
-
// Sets the bubble alignment relative to the anchor. This may only be called
// after calling CreateBubble.
void SetAlignment(BubbleBorder::BubbleAlignment alignment);
@@ -130,17 +118,14 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
// Get bubble bounds from the anchor rect and client view's preferred size.
virtual gfx::Rect GetBubbleBounds();
- // Returns the duration in milliseconds for the fade animation.
- virtual int GetFadeDuration();
+ // Return a FontList to use for the title of the bubble.
+ // (The default is MediumFont).
+ virtual const gfx::FontList& GetTitleFontList() const;
// View overrides:
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
- // gfx::AnimationDelegate overrides:
- virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
- virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
-
// Perform view initialization on the contents for bubble sizing.
virtual void Init();
@@ -158,6 +143,7 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
private:
friend class BubbleBorderDelegate;
+ friend class BubbleWindowTargeter;
FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CreateDelegate);
FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, NonClientHitTest);
@@ -168,9 +154,6 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
// Handles widget visibility changes.
void HandleVisibilityChanged(Widget* widget, bool visible);
- // Fade animation for bubble.
- scoped_ptr<gfx::SlideAnimation> fade_animation_;
-
// Flags controlling bubble closure on the escape key and deactivation.
bool close_on_esc_;
bool close_on_deactivate_;
@@ -182,10 +165,7 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
Widget* anchor_widget_;
// The anchor rect used in the absence of an anchor view.
- gfx::Rect anchor_rect_;
-
- // If true, the bubble will re-anchor (and may resize) with |anchor_widget_|.
- bool move_with_anchor_;
+ mutable gfx::Rect anchor_rect_;
// The arrow's location on the bubble.
BubbleBorder::Arrow arrow_;
@@ -203,12 +183,6 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
// Insets applied to the |anchor_view_| bounds.
gfx::Insets anchor_view_insets_;
- // Original opacity of the bubble.
- int original_opacity_;
-
- // The widget hosting the border for this bubble (non-Aura Windows only).
- Widget* border_widget_;
-
// If true, the bubble does not take focus on display; default is false.
bool use_focusless_;
diff --git a/chromium/ui/views/bubble/bubble_delegate_unittest.cc b/chromium/ui/views/bubble/bubble_delegate_unittest.cc
index 7e2c718f950..9070c2fe758 100644
--- a/chromium/ui/views/bubble/bubble_delegate_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_delegate_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/run_loop.h"
#include "ui/base/hit_test.h"
#include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/bubble/bubble_frame_view.h"
@@ -11,10 +10,6 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#endif
-
namespace views {
namespace {
@@ -39,8 +34,9 @@ class TestBubbleDelegateView : public BubbleDelegateView {
// BubbleDelegateView overrides:
virtual View* GetInitiallyFocusedView() OVERRIDE { return view_; }
- virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(200, 200); }
- virtual int GetFadeDuration() OVERRIDE { return 1; }
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
+ return gfx::Size(200, 200);
+ }
private:
View* view_;
@@ -105,12 +101,10 @@ TEST_F(BubbleDelegateTest, CloseAnchorWidget) {
EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
EXPECT_FALSE(bubble_observer.widget_closed());
-#if defined(USE_AURA)
// TODO(msw): Remove activation hack to prevent bookkeeping errors in:
// aura::test::TestActivationClient::OnWindowDestroyed().
scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
EXPECT_FALSE(bubble_observer.widget_closed());
-#endif
// Ensure that closing the anchor widget also closes the bubble itself.
anchor_widget->CloseNow();
@@ -198,12 +192,10 @@ TEST_F(BubbleDelegateTest, ResetAnchorWidget) {
EXPECT_NE(anchor_widget, bubble_delegate->anchor_widget());
EXPECT_FALSE(bubble_observer.widget_closed());
-#if defined(USE_AURA)
// TODO(msw): Remove activation hack to prevent bookkeeping errors in:
// aura::test::TestActivationClient::OnWindowDestroyed().
scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
EXPECT_FALSE(bubble_observer.widget_closed());
-#endif
// Ensure that closing the parent widget also closes the bubble itself.
parent_widget->CloseNow();
@@ -244,7 +236,7 @@ TEST_F(BubbleDelegateTest, NonClientHitTest) {
}
}
-TEST_F(BubbleDelegateTest, CloseWhenAnchorWidgetBoundsChanged) {
+TEST_F(BubbleDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) {
scoped_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
anchor_widget->GetContentsView(), BubbleBorder::NONE);
@@ -255,66 +247,7 @@ TEST_F(BubbleDelegateTest, CloseWhenAnchorWidgetBoundsChanged) {
bubble_widget->Show();
EXPECT_TRUE(bubble_widget->IsVisible());
anchor_widget->SetBounds(gfx::Rect(10, 10, 100, 100));
- EXPECT_FALSE(bubble_widget->IsVisible());
-}
-
-// This class provides functionality to verify that the BubbleView shows up
-// when we call BubbleDelegateView::StartFade(true) and is destroyed when we
-// call BubbleDelegateView::StartFade(false).
-class BubbleWidgetClosingTest : public BubbleDelegateTest,
- public views::WidgetObserver {
- public:
- BubbleWidgetClosingTest() : bubble_destroyed_(false) {
-#if defined(USE_AURA)
- aura::Env::CreateInstance();
- loop_.set_dispatcher(aura::Env::GetInstance()->GetDispatcher());
-#endif
- }
-
- virtual ~BubbleWidgetClosingTest() {}
-
- void Observe(views::Widget* widget) {
- widget->AddObserver(this);
- }
-
- // views::WidgetObserver overrides.
- virtual void OnWidgetDestroyed(Widget* widget) OVERRIDE {
- bubble_destroyed_ = true;
- widget->RemoveObserver(this);
- loop_.Quit();
- }
-
- bool bubble_destroyed() const { return bubble_destroyed_; }
-
- void RunNestedLoop() {
- loop_.Run();
- }
-
- private:
- bool bubble_destroyed_;
- base::RunLoop loop_;
-
- DISALLOW_COPY_AND_ASSIGN(BubbleWidgetClosingTest);
-};
-
-TEST_F(BubbleWidgetClosingTest, TestBubbleVisibilityAndClose) {
- scoped_ptr<Widget> anchor_widget(CreateTestWidget());
- TestBubbleDelegateView* bubble_delegate =
- new TestBubbleDelegateView(anchor_widget->GetContentsView());
- Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
- EXPECT_FALSE(bubble_widget->IsVisible());
-
- bubble_delegate->StartFade(true);
EXPECT_TRUE(bubble_widget->IsVisible());
-
- EXPECT_EQ(bubble_delegate->GetInitiallyFocusedView(),
- bubble_widget->GetFocusManager()->GetFocusedView());
-
- Observe(bubble_widget);
-
- bubble_delegate->StartFade(false);
- RunNestedLoop();
- EXPECT_TRUE(bubble_destroyed());
}
} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index 7e0fd5e745a..384c4fa46a8 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -12,6 +12,7 @@
#include "ui/gfx/path.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
+#include "ui/native_theme/native_theme.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/widget/widget.h"
@@ -20,10 +21,11 @@
namespace {
-// Padding, in pixels, for the title view, when it exists.
+// Insets for the title bar views in pixels.
const int kTitleTopInset = 12;
const int kTitleLeftInset = 19;
const int kTitleBottomInset = 12;
+const int kTitleRightInset = 7;
// Get the |vertical| or horizontal amount that |available_bounds| overflows
// |window_bounds|.
@@ -57,7 +59,8 @@ const char BubbleFrameView::kViewClassName[] = "BubbleFrameView";
// static
gfx::Insets BubbleFrameView::GetTitleInsets() {
- return gfx::Insets(kTitleTopInset, kTitleLeftInset, kTitleBottomInset, 0);
+ return gfx::Insets(kTitleTopInset, kTitleLeftInset,
+ kTitleBottomInset, kTitleRightInset);
}
BubbleFrameView::BubbleFrameView(const gfx::Insets& content_margins)
@@ -67,19 +70,20 @@ BubbleFrameView::BubbleFrameView(const gfx::Insets& content_margins)
close_(NULL),
titlebar_extra_view_(NULL) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- title_ = new Label(string16(), rb.GetFont(ui::ResourceBundle::MediumFont));
+ title_ = new Label(base::string16(),
+ rb.GetFontList(ui::ResourceBundle::MediumFont));
title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(title_);
- close_ = new LabelButton(this, string16());
+ close_ = new LabelButton(this, base::string16());
close_->SetImage(CustomButton::STATE_NORMAL,
*rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
close_->SetImage(CustomButton::STATE_HOVERED,
*rb.GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
close_->SetImage(CustomButton::STATE_PRESSED,
*rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
+ close_->SetBorder(scoped_ptr<Border>());
close_->SetSize(close_->GetPreferredSize());
- close_->set_border(NULL);
close_->SetVisible(false);
AddChildView(close_);
}
@@ -154,11 +158,15 @@ void BubbleFrameView::UpdateWindowIcon() {}
void BubbleFrameView::UpdateWindowTitle() {
title_->SetText(GetWidget()->widget_delegate()->ShouldShowWindowTitle() ?
- GetWidget()->widget_delegate()->GetWindowTitle() : string16());
+ GetWidget()->widget_delegate()->GetWindowTitle() : base::string16());
// Update the close button visibility too, otherwise it's not intialized.
ResetWindowControls();
}
+void BubbleFrameView::SetTitleFontList(const gfx::FontList& font_list) {
+ title_->SetFontList(font_list);
+}
+
gfx::Insets BubbleFrameView::GetInsets() const {
gfx::Insets insets = content_margins_;
const int title_height = title_->text().empty() ? 0 :
@@ -168,39 +176,40 @@ gfx::Insets BubbleFrameView::GetInsets() const {
return insets;
}
-gfx::Size BubbleFrameView::GetPreferredSize() {
+gfx::Size BubbleFrameView::GetPreferredSize() const {
return GetSizeForClientSize(GetWidget()->client_view()->GetPreferredSize());
}
-gfx::Size BubbleFrameView::GetMinimumSize() {
+gfx::Size BubbleFrameView::GetMinimumSize() const {
return GetSizeForClientSize(GetWidget()->client_view()->GetMinimumSize());
}
void BubbleFrameView::Layout() {
- gfx::Rect bounds(GetLocalBounds());
- bounds.Inset(border()->GetInsets());
- // Small additional insets yield the desired 10px visual close button insets.
- bounds.Inset(0, 0, close_->width() + 1, 0);
- close_->SetPosition(gfx::Point(bounds.right(), bounds.y() + 2));
-
- gfx::Rect title_bounds(bounds);
- title_bounds.Inset(kTitleLeftInset, kTitleTopInset, 0, 0);
+ gfx::Rect bounds(GetContentsBounds());
+ bounds.Inset(GetTitleInsets());
+ if (bounds.IsEmpty())
+ return;
+
+ // The close button top inset is actually smaller than the title top inset.
+ close_->SetPosition(gfx::Point(bounds.right() - close_->width(),
+ bounds.y() - 5));
+
gfx::Size title_size(title_->GetPreferredSize());
- const int title_width = std::max(0, close_->bounds().x() - title_bounds.x());
+ const int title_width = std::max(0, close_->x() - bounds.x());
title_size.SetToMin(gfx::Size(title_width, title_size.height()));
- title_bounds.set_size(title_size);
- title_->SetBoundsRect(title_bounds);
+ bounds.set_size(title_size);
+ title_->SetBoundsRect(bounds);
if (titlebar_extra_view_) {
- const int extra_width = close_->bounds().x() - title_->bounds().right();
+ const int extra_width = close_->x() - title_->bounds().right();
gfx::Size size = titlebar_extra_view_->GetPreferredSize();
size.SetToMin(gfx::Size(std::max(0, extra_width), size.height()));
gfx::Rect titlebar_extra_view_bounds(
- bounds.right() - size.width(),
- title_bounds.y(),
+ close_->x() - size.width(),
+ bounds.y(),
size.width(),
- title_bounds.height());
- titlebar_extra_view_bounds.Subtract(title_bounds);
+ bounds.height());
+ titlebar_extra_view_bounds.Subtract(bounds);
titlebar_extra_view_->SetBoundsRect(titlebar_extra_view_bounds);
}
}
@@ -220,17 +229,25 @@ void BubbleFrameView::OnThemeChanged() {
UpdateWindowIcon();
}
+void BubbleFrameView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ if (bubble_border_ && bubble_border_->use_theme_background_color()) {
+ bubble_border_->set_background_color(GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_DialogBackground));
+ SchedulePaint();
+ }
+}
+
void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == close_)
GetWidget()->Close();
}
-void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) {
- bubble_border_ = border;
- set_border(bubble_border_);
+void BubbleFrameView::SetBubbleBorder(scoped_ptr<BubbleBorder> border) {
+ bubble_border_ = border.get();
+ SetBorder(border.PassAs<Border>());
// Update the background, which relies on the border.
- set_background(new views::BubbleBackground(border));
+ set_background(new views::BubbleBackground(bubble_border_));
}
void BubbleFrameView::SetTitlebarExtraView(View* view) {
@@ -243,27 +260,23 @@ void BubbleFrameView::SetTitlebarExtraView(View* view) {
gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
gfx::Size client_size,
bool adjust_if_offscreen) {
- gfx::Insets insets(GetInsets());
- client_size.Enlarge(insets.width(), insets.height());
+ gfx::Size size(GetSizeForClientSize(client_size));
const BubbleBorder::Arrow arrow = bubble_border_->arrow();
if (adjust_if_offscreen && BubbleBorder::has_arrow(arrow)) {
+ // Try to mirror the anchoring if the bubble does not fit on the screen.
if (!bubble_border_->is_arrow_at_center(arrow)) {
- // Try to mirror the anchoring if the bubble does not fit on the screen.
- MirrorArrowIfOffScreen(true, anchor_rect, client_size);
- MirrorArrowIfOffScreen(false, anchor_rect, client_size);
+ MirrorArrowIfOffScreen(true, anchor_rect, size);
+ MirrorArrowIfOffScreen(false, anchor_rect, size);
} else {
- // Mirror as needed vertically if the arrow is on a horizontal edge and
- // vice-versa.
- MirrorArrowIfOffScreen(BubbleBorder::is_arrow_on_horizontal(arrow),
- anchor_rect,
- client_size);
- OffsetArrowIfOffScreen(anchor_rect, client_size);
+ const bool mirror_vertical = BubbleBorder::is_arrow_on_horizontal(arrow);
+ MirrorArrowIfOffScreen(mirror_vertical, anchor_rect, size);
+ OffsetArrowIfOffScreen(anchor_rect, size);
}
}
// Calculate the bounds with the arrow in its updated location and offset.
- return bubble_border_->GetBounds(anchor_rect, client_size);
+ return bubble_border_->GetBounds(anchor_rect, size);
}
gfx::Rect BubbleFrameView::GetAvailableScreenBounds(const gfx::Rect& rect) {
@@ -337,9 +350,8 @@ void BubbleFrameView::OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect,
SchedulePaint();
}
-gfx::Size BubbleFrameView::GetSizeForClientSize(const gfx::Size& client_size) {
- gfx::Size size(
- GetUpdatedWindowBounds(gfx::Rect(), client_size, false).size());
+gfx::Size BubbleFrameView::GetSizeForClientSize(
+ const gfx::Size& client_size) const {
// Accommodate the width of the title bar elements.
int title_bar_width = GetInsets().width() + border()->GetInsets().width();
if (!title_->text().empty())
@@ -348,7 +360,10 @@ gfx::Size BubbleFrameView::GetSizeForClientSize(const gfx::Size& client_size) {
title_bar_width += close_->width() + 1;
if (titlebar_extra_view_ != NULL)
title_bar_width += titlebar_extra_view_->GetPreferredSize().width();
+ gfx::Size size(client_size);
size.SetToMax(gfx::Size(title_bar_width, 0));
+ const gfx::Insets insets(GetInsets());
+ size.Enlarge(insets.width(), insets.height());
return size;
}
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index d033c8d0d10..a17a4f8f487 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -12,6 +12,10 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/window/non_client_view.h"
+namespace gfx {
+class FontList;
+}
+
namespace views {
class Label;
@@ -43,21 +47,26 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
virtual void UpdateWindowIcon() OVERRIDE;
virtual void UpdateWindowTitle() OVERRIDE;
+ // Set the FontList to be used for the title of the bubble.
+ // Caller must arrange to update the layout to have the call take effect.
+ void SetTitleFontList(const gfx::FontList& font_list);
+
// View overrides:
virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
virtual void OnThemeChanged() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// Overridden from ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
- // Use bubble_border() and SetBubbleBorder(), not border() and set_border().
+ // Use bubble_border() and SetBubbleBorder(), not border() and SetBorder().
BubbleBorder* bubble_border() const { return bubble_border_; }
- void SetBubbleBorder(BubbleBorder* border);
+ void SetBubbleBorder(scoped_ptr<BubbleBorder> border);
gfx::Insets content_margins() const { return content_margins_; }
@@ -89,7 +98,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
const gfx::Size& client_size);
// Calculates the size needed to accommodate the given client area.
- gfx::Size GetSizeForClientSize(const gfx::Size& client_size);
+ gfx::Size GetSizeForClientSize(const gfx::Size& client_size) const;
// The bubble border.
BubbleBorder* bubble_border_;
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index ef5d58d8b00..1bd9e348a18 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -23,7 +23,8 @@ class TestBubbleFrameView : public BubbleFrameView {
TestBubbleFrameView()
: BubbleFrameView(gfx::Insets(kMargin, kMargin, kMargin, kMargin)),
available_bounds_(gfx::Rect(0, 0, 1000, 1000)) {
- SetBubbleBorder(new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor));
+ SetBubbleBorder(scoped_ptr<views::BubbleBorder>(
+ new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor)));
}
virtual ~TestBubbleFrameView() {}
diff --git a/chromium/ui/views/bubble/bubble_window_targeter.cc b/chromium/ui/views/bubble/bubble_window_targeter.cc
new file mode 100644
index 00000000000..19e0c85f91a
--- /dev/null
+++ b/chromium/ui/views/bubble/bubble_window_targeter.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/bubble/bubble_window_targeter.h"
+
+#include "ui/aura/window.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+
+namespace views {
+
+BubbleWindowTargeter::BubbleWindowTargeter(BubbleDelegateView* bubble)
+ : wm::MaskedWindowTargeter(bubble->GetWidget()->GetNativeView()),
+ bubble_(bubble) {
+}
+
+BubbleWindowTargeter::~BubbleWindowTargeter() {
+}
+
+bool BubbleWindowTargeter::GetHitTestMask(aura::Window* window,
+ gfx::Path* mask) const {
+ mask->addRect(
+ gfx::RectToSkRect(bubble_->GetBubbleFrameView()->GetContentsBounds()));
+ return true;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_window_targeter.h b/chromium/ui/views/bubble/bubble_window_targeter.h
new file mode 100644
index 00000000000..45b1d5c551b
--- /dev/null
+++ b/chromium/ui/views/bubble/bubble_window_targeter.h
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/views_export.h"
+#include "ui/wm/core/masked_window_targeter.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+class BubbleDelegateView;
+
+// A convenient window-targeter that uses a mask based on the content-bounds of
+// the bubble-frame.
+class VIEWS_EXPORT BubbleWindowTargeter
+ : public NON_EXPORTED_BASE(wm::MaskedWindowTargeter) {
+ public:
+ explicit BubbleWindowTargeter(BubbleDelegateView* bubble);
+ virtual ~BubbleWindowTargeter();
+
+ private:
+ // wm::MaskedWindowTargeter:
+ virtual bool GetHitTestMask(aura::Window* window,
+ gfx::Path* mask) const OVERRIDE;
+
+ views::BubbleDelegateView* bubble_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleWindowTargeter);
+};
+
+} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc b/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc
new file mode 100644
index 00000000000..479f6e93d39
--- /dev/null
+++ b/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/bubble/bubble_window_targeter.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+class WidgetOwnsNativeBubble : public BubbleDelegateView {
+ public:
+ WidgetOwnsNativeBubble(View* content, BubbleBorder::Arrow arrow)
+ : BubbleDelegateView(content, arrow) {
+ }
+
+ virtual ~WidgetOwnsNativeBubble() {}
+
+ private:
+ // BubbleDelegateView:
+ virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
+ Widget* widget) const OVERRIDE {
+ params->ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetOwnsNativeBubble);
+};
+
+} // namespace
+
+class BubbleWindowTargeterTest : public ViewsTestBase {
+ public:
+ BubbleWindowTargeterTest()
+ : bubble_delegate_(NULL) {
+ }
+ virtual ~BubbleWindowTargeterTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ ViewsTestBase::SetUp();
+ CreateAnchorWidget();
+ CreateBubbleWidget();
+
+ anchor_widget()->Show();
+ bubble_widget()->Show();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ bubble_delegate_ = NULL;
+ bubble_widget_.reset();
+ anchor_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ Widget* anchor_widget() { return anchor_.get(); }
+ Widget* bubble_widget() { return bubble_widget_.get(); }
+ BubbleDelegateView* bubble_delegate() { return bubble_delegate_; }
+
+ private:
+ void CreateAnchorWidget() {
+ anchor_.reset(new Widget());
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ anchor_->Init(params);
+ }
+
+ void CreateBubbleWidget() {
+ bubble_delegate_ = new WidgetOwnsNativeBubble(
+ anchor_->GetContentsView(), BubbleBorder::NONE);
+ bubble_delegate_->set_color(SK_ColorGREEN);
+ bubble_widget_.reset(BubbleDelegateView::CreateBubble(bubble_delegate_));
+ }
+
+ scoped_ptr<Widget> anchor_;
+ scoped_ptr<Widget> bubble_widget_;
+ BubbleDelegateView* bubble_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleWindowTargeterTest);
+};
+
+TEST_F(BubbleWindowTargeterTest, HitTest) {
+ ui::EventTarget* root = bubble_widget()->GetNativeWindow()->GetRootWindow();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+ aura::Window* bubble_window = bubble_widget()->GetNativeWindow();
+ gfx::Rect bubble_bounds = bubble_window->GetBoundsInRootWindow();
+
+ {
+ bubble_delegate()->set_margins(gfx::Insets());
+ ui::MouseEvent move1(ui::ET_MOUSE_MOVED, bubble_bounds.origin(),
+ bubble_bounds.origin(), ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(bubble_window, targeter->FindTargetForEvent(root, &move1));
+ }
+ {
+ bubble_delegate()->set_margins(gfx::Insets(20, 20, 20, 20));
+ ui::MouseEvent move1(ui::ET_MOUSE_MOVED, bubble_bounds.origin(),
+ bubble_bounds.origin(), ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(bubble_window, targeter->FindTargetForEvent(root, &move1));
+ }
+
+ bubble_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
+ new BubbleWindowTargeter(bubble_delegate())));
+ {
+ bubble_delegate()->set_margins(gfx::Insets(20, 20, 20, 20));
+ ui::MouseEvent move1(ui::ET_MOUSE_MOVED, bubble_bounds.origin(),
+ bubble_bounds.origin(), ui::EF_NONE, ui::EF_NONE);
+ EXPECT_NE(bubble_window, targeter->FindTargetForEvent(root, &move1));
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc
index 3f947ab9134..243e58b3cfe 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.cc
+++ b/chromium/ui/views/bubble/tray_bubble_view.cc
@@ -11,7 +11,8 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_delegate.h"
@@ -22,6 +23,7 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/bubble/bubble_window_targeter.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
@@ -325,17 +327,14 @@ TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window,
mouse_actively_entered_(false) {
set_parent_window(parent_window);
set_notify_enter_exit_on_child(true);
- set_move_with_anchor(true);
set_close_on_deactivate(init_params.close_on_deactivate);
set_margins(gfx::Insets());
bubble_border_ = new TrayBubbleBorder(this, GetAnchorView(), params_);
- if (get_use_acceleration_when_possible()) {
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(true);
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(true);
- bubble_content_mask_.reset(
- new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius()));
- }
+ bubble_content_mask_.reset(
+ new TrayBubbleContentMask(bubble_border_->GetBorderCornerRadius()));
}
TrayBubbleView::~TrayBubbleView() {
@@ -350,17 +349,17 @@ void TrayBubbleView::InitializeAndShowBubble() {
SetAlignment(params_.arrow_alignment);
bubble_border_->UpdateArrowOffset();
- if (get_use_acceleration_when_possible())
- layer()->parent()->SetMaskLayer(bubble_content_mask_->layer());
+ layer()->parent()->SetMaskLayer(bubble_content_mask_->layer());
GetWidget()->Show();
+ GetWidget()->GetNativeWindow()->SetEventTargeter(
+ scoped_ptr<ui::EventTargeter>(new BubbleWindowTargeter(this)));
UpdateBubble();
}
void TrayBubbleView::UpdateBubble() {
SizeToContents();
- if (get_use_acceleration_when_possible())
- bubble_content_mask_->layer()->SetBounds(layer()->bounds());
+ bubble_content_mask_->layer()->SetBounds(layer()->bounds());
GetWidget()->GetRootView()->SchedulePaint();
}
@@ -390,11 +389,11 @@ gfx::Insets TrayBubbleView::GetBorderInsets() const {
void TrayBubbleView::Init() {
BoxLayout* layout = new BottomAlignedBoxLayout(this);
- layout->set_spread_blank_space(true);
+ layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_FILL);
SetLayoutManager(layout);
}
-gfx::Rect TrayBubbleView::GetAnchorRect() {
+gfx::Rect TrayBubbleView::GetAnchorRect() const {
if (!delegate_)
return gfx::Rect();
return delegate_->GetAnchorRect(anchor_widget(),
@@ -408,7 +407,7 @@ bool TrayBubbleView::CanActivate() const {
NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) {
BubbleFrameView* frame = new BubbleFrameView(margins());
- frame->SetBubbleBorder(bubble_border_);
+ frame->SetBubbleBorder(scoped_ptr<views::BubbleBorder>(bubble_border_));
return frame;
}
@@ -421,21 +420,21 @@ void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const {
mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds()));
}
-gfx::Size TrayBubbleView::GetPreferredSize() {
+gfx::Size TrayBubbleView::GetPreferredSize() const {
return gfx::Size(preferred_width_, GetHeightForWidth(preferred_width_));
}
-gfx::Size TrayBubbleView::GetMaximumSize() {
+gfx::Size TrayBubbleView::GetMaximumSize() const {
gfx::Size size = GetPreferredSize();
size.set_width(params_.max_width);
return size;
}
-int TrayBubbleView::GetHeightForWidth(int width) {
+int TrayBubbleView::GetHeightForWidth(int width) const {
int height = GetInsets().height();
width = std::max(width - GetInsets().width(), 0);
for (int i = 0; i < child_count(); ++i) {
- View* child = child_at(i);
+ const View* child = child_at(i);
if (child->visible())
height += child->GetHeightForWidth(width);
}
@@ -478,9 +477,9 @@ void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) {
delegate_->OnMouseExitedView();
}
-void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
+void TrayBubbleView::GetAccessibleState(ui::AXViewState* state) {
if (delegate_ && params_.can_activate) {
- state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+ state->role = ui::AX_ROLE_WINDOW;
state->name = delegate_->GetAccessibleNameForBubble();
}
}
@@ -500,8 +499,7 @@ void TrayBubbleView::ChildPreferredSizeChanged(View* child) {
void TrayBubbleView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
- if (get_use_acceleration_when_possible() && details.is_add &&
- details.child == this) {
+ if (details.is_add && details.child == this) {
details.parent->SetPaintToLayer(true);
details.parent->SetFillsBoundsOpaquely(true);
details.parent->layer()->SetMasksToBounds(true);
diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h
index 1e9d48298ea..54f6cc88033 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.h
+++ b/chromium/ui/views/bubble/tray_bubble_view.h
@@ -71,13 +71,14 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView,
// Called from GetAccessibleState(); should return the appropriate
// accessible name for the bubble.
- virtual string16 GetAccessibleNameForBubble() = 0;
+ virtual base::string16 GetAccessibleNameForBubble() = 0;
// Passes responsibility for BubbleDelegateView::GetAnchorRect to the
// delegate.
- virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
- AnchorType anchor_type,
- AnchorAlignment anchor_alignment) = 0;
+ virtual gfx::Rect GetAnchorRect(
+ views::Widget* anchor_widget,
+ AnchorType anchor_type,
+ AnchorAlignment anchor_alignment) const = 0;
// Called when a bubble wants to hide/destroy itself (e.g. last visible
// child view was closed).
@@ -153,15 +154,15 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView,
virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE;
// Overridden from views::BubbleDelegateView.
- virtual gfx::Rect GetAnchorRect() OVERRIDE;
+ virtual gfx::Rect GetAnchorRect() const OVERRIDE;
// Overridden from views::View.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
- virtual int GetHeightForWidth(int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Overridden from MouseWatcherListener
virtual void MouseMovedOutOfHost() OVERRIDE;
diff --git a/chromium/ui/views/button_drag_utils.cc b/chromium/ui/views/button_drag_utils.cc
index 9305a07d3b0..2c4f25ade3b 100644
--- a/chromium/ui/views/button_drag_utils.cc
+++ b/chromium/ui/views/button_drag_utils.cc
@@ -10,6 +10,7 @@
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/image/image.h"
#include "ui/views/controls/button/text_button.h"
#include "ui/views/drag_utils.h"
@@ -18,20 +19,29 @@
namespace button_drag_utils {
// Maximum width of the link drag image in pixels.
-static const int kLinkDragImageMaxWidth = 200;
+static const int kLinkDragImageMaxWidth = 150;
void SetURLAndDragImage(const GURL& url,
- const string16& title,
+ const base::string16& title,
const gfx::ImageSkia& icon,
+ const gfx::Point* press_pt,
ui::OSExchangeData* data,
views::Widget* widget) {
DCHECK(url.is_valid() && data);
-
data->SetURL(url, title);
+ SetDragImage(url, title, icon, press_pt, data, widget);
+}
+void SetDragImage(const GURL& url,
+ const base::string16& title,
+ const gfx::ImageSkia& icon,
+ const gfx::Point* press_pt,
+ ui::OSExchangeData* data,
+ views::Widget* widget) {
// Create a button to render the drag image for us.
views::TextButton button(NULL,
- title.empty() ? UTF8ToUTF16(url.spec()) : title);
+ title.empty() ? base::UTF8ToUTF16(url.spec())
+ : title);
button.set_max_width(kLinkDragImageMaxWidth);
if (icon.isNull()) {
button.SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageNamed(
@@ -42,12 +52,17 @@ void SetURLAndDragImage(const GURL& url,
gfx::Size prefsize = button.GetPreferredSize();
button.SetBounds(0, 0, prefsize.width(), prefsize.height());
+ gfx::Vector2d press_point;
+ if (press_pt)
+ press_point = press_pt->OffsetFromOrigin();
+ else
+ press_point = gfx::Vector2d(prefsize.width() / 2, prefsize.height() / 2);
+
// Render the image.
scoped_ptr<gfx::Canvas> canvas(
views::GetCanvasForDragImage(widget, prefsize));
button.PaintButton(canvas.get(), views::TextButton::PB_FOR_DRAG);
- drag_utils::SetDragImageOnDataObject(*canvas, prefsize,
- gfx::Vector2d(prefsize.width() / 2, prefsize.height() / 2), data);
+ drag_utils::SetDragImageOnDataObject(*canvas, press_point, data);
}
} // namespace button_drag_utils
diff --git a/chromium/ui/views/button_drag_utils.h b/chromium/ui/views/button_drag_utils.h
index 1f93c9517de..8f1a7eedf7d 100644
--- a/chromium/ui/views/button_drag_utils.h
+++ b/chromium/ui/views/button_drag_utils.h
@@ -12,6 +12,7 @@ class GURL;
namespace gfx {
class ImageSkia;
+class Point;
}
namespace ui {
@@ -25,13 +26,23 @@ class Widget;
namespace button_drag_utils {
// Sets url and title on data as well as setting a suitable image for dragging.
-// The image looks like that of the bookmark buttons.
+// The image looks like that of the bookmark buttons. |press_pt| is optional
+// offset; otherwise, it centers the drag image.
VIEWS_EXPORT void SetURLAndDragImage(const GURL& url,
- const string16& title,
+ const base::string16& title,
const gfx::ImageSkia& icon,
+ const gfx::Point* press_pt,
ui::OSExchangeData* data,
views::Widget* widget);
+// As above, but only sets the image.
+VIEWS_EXPORT void SetDragImage(const GURL& url,
+ const base::string16& title,
+ const gfx::ImageSkia& icon,
+ const gfx::Point* press_pt,
+ ui::OSExchangeData* data,
+ views::Widget* widget);
+
} // namespace drag_utils
#endif // UI_VIEWS_BUTTON_DRAG_UTILS_H_
diff --git a/chromium/ui/views/cocoa/bridged_content_view.h b/chromium/ui/views/cocoa/bridged_content_view.h
new file mode 100644
index 00000000000..e7c83f74af5
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_content_view.h
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
+#define UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
+
+#import <Cocoa/Cocoa.h>
+
+namespace views {
+class View;
+}
+
+// The NSView that sits as the root contentView of the NSWindow, whilst it has
+// a views::RootView present. Bridges requests from Cocoa to the hosted
+// views::View.
+@interface BridgedContentView : NSView {
+ @private
+ // Weak. The hosted RootView, owned by hostedView_->GetWidget().
+ views::View* hostedView_;
+}
+
+@property(readonly, nonatomic) views::View* hostedView;
+
+// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
+- (id)initWithView:(views::View*)viewToHost;
+
+// Clear the hosted view. For example, if it is about to be destroyed.
+- (void)clearView;
+
+@end
+
+#endif // UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm
new file mode 100644
index 00000000000..bd9a511a244
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_content_view.mm
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/views/cocoa/bridged_content_view.h"
+
+#include "base/logging.h"
+#include "ui/gfx/canvas_paint_mac.h"
+#include "ui/views/view.h"
+
+@implementation BridgedContentView
+
+@synthesize hostedView = hostedView_;
+
+- (id)initWithView:(views::View*)viewToHost {
+ DCHECK(viewToHost);
+ gfx::Rect bounds = viewToHost->bounds();
+ // To keep things simple, assume the origin is (0, 0) until there exists a use
+ // case for something other than that.
+ DCHECK(bounds.origin().IsOrigin());
+ NSRect initialFrame = NSMakeRect(0, 0, bounds.width(), bounds.height());
+ if ((self = [super initWithFrame:initialFrame]))
+ hostedView_ = viewToHost;
+
+ return self;
+}
+
+- (void)clearView {
+ hostedView_ = NULL;
+}
+
+// NSView implementation.
+
+- (void)setFrameSize:(NSSize)newSize {
+ [super setFrameSize:newSize];
+ if (!hostedView_)
+ return;
+
+ hostedView_->SetSize(gfx::Size(newSize.width, newSize.height));
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ if (!hostedView_)
+ return;
+
+ gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */);
+ hostedView_->Paint(&canvas, views::CullSet());
+}
+
+@end
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h
new file mode 100644
index 00000000000..59754d1d129
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget.h
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
+#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/ime/input_method_delegate.h"
+#include "ui/views/views_export.h"
+
+@class BridgedContentView;
+
+namespace ui {
+class InputMethod;
+}
+
+namespace views {
+
+class InputMethod;
+class View;
+
+// A bridge to an NSWindow managed by an instance of NativeWidgetMac or
+// DesktopNativeWidgetMac. Serves as a helper class to bridge requests from the
+// NativeWidgetMac to the Cocoa window. Behaves a bit like an aura::Window.
+class VIEWS_EXPORT BridgedNativeWidget : public internal::InputMethodDelegate {
+
+ public:
+ BridgedNativeWidget();
+ virtual ~BridgedNativeWidget();
+
+ // Initialize the bridge, "retains" ownership of |window|.
+ void Init(base::scoped_nsobject<NSWindow> window);
+
+ // Set or clears the views::View bridged by the content view. This does NOT
+ // take ownership of |view|.
+ void SetRootView(views::View* view);
+
+ // See widget.h for documentation.
+ InputMethod* CreateInputMethod();
+ ui::InputMethod* GetHostInputMethod();
+
+ BridgedContentView* ns_view() { return bridged_view_; }
+ NSWindow* ns_window() { return window_; }
+
+ // Overridden from internal::InputMethodDelegate:
+ virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE;
+
+ private:
+ base::scoped_nsobject<NSWindow> window_;
+ base::scoped_nsobject<BridgedContentView> bridged_view_;
+ scoped_ptr<ui::InputMethod> input_method_;
+
+ DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm
new file mode 100644
index 00000000000..e4b754f78d8
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget.mm
@@ -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.
+
+#import "ui/views/cocoa/bridged_native_widget.h"
+
+#include "base/logging.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/ui_base_switches_util.h"
+#import "ui/views/cocoa/bridged_content_view.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/ime/null_input_method.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+BridgedNativeWidget::BridgedNativeWidget() {
+}
+
+BridgedNativeWidget::~BridgedNativeWidget() {
+ SetRootView(NULL);
+}
+
+void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window) {
+ DCHECK(!window_);
+ window_.swap(window);
+}
+
+void BridgedNativeWidget::SetRootView(views::View* view) {
+ if (view == [bridged_view_ hostedView])
+ return;
+
+ [bridged_view_ clearView];
+ bridged_view_.reset();
+ // Note that there can still be references to the old |bridged_view_|
+ // floating around in Cocoa libraries at this point. However, references to
+ // the old views::View will be gone, so any method calls will become no-ops.
+
+ if (view) {
+ bridged_view_.reset([[BridgedContentView alloc] initWithView:view]);
+ // Objective C initializers can return nil. However, if |view| is non-NULL
+ // this should be treated as an error and caught early.
+ CHECK(bridged_view_);
+ }
+ [window_ setContentView:bridged_view_];
+}
+
+InputMethod* BridgedNativeWidget::CreateInputMethod() {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return new NullInputMethod();
+
+ return new InputMethodBridge(this, GetHostInputMethod(), true);
+}
+
+ui::InputMethod* BridgedNativeWidget::GetHostInputMethod() {
+ if (!input_method_) {
+ // Delegate is NULL because Mac IME does not need DispatchKeyEventPostIME
+ // callbacks.
+ input_method_ = ui::CreateInputMethod(NULL, nil);
+ }
+ return input_method_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidget, internal::InputMethodDelegate:
+
+void BridgedNativeWidget::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
+ // Mac key events don't go through this, but some unit tests that use
+ // MockInputMethod do.
+ Widget* widget = [bridged_view_ hostedView]->GetWidget();
+ widget->OnKeyEvent(const_cast<ui::KeyEvent*>(&key));
+ if (!key.handled() && widget->GetFocusManager())
+ widget->GetFocusManager()->OnKeyEvent(key);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
new file mode 100644
index 00000000000..6d30f41f13c
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -0,0 +1,117 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/views/cocoa/bridged_native_widget.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/memory/scoped_ptr.h"
+#import "testing/gtest_mac.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
+#import "ui/views/cocoa/bridged_content_view.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+class BridgedNativeWidgetTest : public ui::CocoaTest {
+ public:
+ BridgedNativeWidgetTest();
+ virtual ~BridgedNativeWidgetTest();
+
+ // testing::Test:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ // TODO(tapted): Make this a EventCountView from widget_unittest.cc.
+ scoped_ptr<views::View> view_;
+ scoped_ptr<BridgedNativeWidget> bridge_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest);
+};
+
+BridgedNativeWidgetTest::BridgedNativeWidgetTest() {
+}
+
+BridgedNativeWidgetTest::~BridgedNativeWidgetTest() {
+}
+
+void BridgedNativeWidgetTest::SetUp() {
+ ui::CocoaTest::SetUp();
+
+ view_.reset(new views::View);
+ bridge_.reset(new BridgedNativeWidget);
+ base::scoped_nsobject<NSWindow> window([test_window() retain]);
+ bridge_->Init(window);
+ bridge_->SetRootView(view_.get());
+
+ [test_window() makePretendKeyWindowAndSetFirstResponder:bridge_->ns_view()];
+}
+
+void BridgedNativeWidgetTest::TearDown() {
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+
+ bridge_.reset();
+ view_.reset();
+
+ ui::CocoaTest::TearDown();
+}
+
+// The TEST_VIEW macro expects the view it's testing to have a superview. In
+// these tests, the NSView bridge is a contentView, at the root. These mimic
+// what TEST_VIEW usually does.
+TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
+ base::scoped_nsobject<BridgedContentView> view([bridge_->ns_view() retain]);
+ EXPECT_NSEQ([test_window() contentView], view);
+ EXPECT_NSEQ(test_window(), [view window]);
+
+ // The superview of a contentView is an NSNextStepFrame.
+ EXPECT_TRUE([view superview]);
+ EXPECT_TRUE([view hostedView]);
+
+ // Destroying the C++ bridge should remove references to any C++ objects in
+ // the ObjectiveC object, and remove it from the hierarchy.
+ bridge_.reset();
+ EXPECT_FALSE([view hostedView]);
+ EXPECT_FALSE([view superview]);
+ EXPECT_FALSE([view window]);
+ EXPECT_FALSE([test_window() contentView]);
+}
+
+TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) {
+ [bridge_->ns_view() display];
+}
+
+// Test that resizing the window resizes the root view appropriately.
+TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
+ const int kTestNewWidth = 400;
+ const int kTestNewHeight = 300;
+
+ // |test_window()| is borderless, so these should align.
+ NSSize window_size = [test_window() frame].size;
+ EXPECT_EQ(view_->width(), static_cast<int>(window_size.width));
+ EXPECT_EQ(view_->height(), static_cast<int>(window_size.height));
+
+ // Make sure a resize actually occurs.
+ EXPECT_NE(kTestNewWidth, view_->width());
+ EXPECT_NE(kTestNewHeight, view_->height());
+
+ [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
+ display:NO];
+ EXPECT_EQ(kTestNewWidth, view_->width());
+ EXPECT_EQ(kTestNewHeight, view_->height());
+}
+
+TEST_F(BridgedNativeWidgetTest, CreateInputMethod) {
+ scoped_ptr<views::InputMethod> input_method(bridge_->CreateInputMethod());
+ EXPECT_TRUE(input_method);
+}
+
+TEST_F(BridgedNativeWidgetTest, GetHostInputMethod) {
+ EXPECT_TRUE(bridge_->GetHostInputMethod());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index 3c649f9718a..8c283da829d 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -32,18 +32,19 @@ const int kHueIndicatorSize = 5;
const int kBorderWidth = 1;
const int kTextfieldLengthInChars = 14;
-string16 GetColorText(SkColor color) {
- return ASCIIToUTF16(base::StringPrintf("#%02x%02x%02x",
- SkColorGetR(color),
- SkColorGetG(color),
- SkColorGetB(color)));
+base::string16 GetColorText(SkColor color) {
+ return base::ASCIIToUTF16(base::StringPrintf("#%02x%02x%02x",
+ SkColorGetR(color),
+ SkColorGetG(color),
+ SkColorGetB(color)));
}
-bool GetColorFromText(const string16& text, SkColor* result) {
+bool GetColorFromText(const base::string16& text, SkColor* result) {
if (text.size() != 6 && !(text.size() == 7 && text[0] == '#'))
return false;
- std::string input = UTF16ToUTF8((text.size() == 6) ? text : text.substr(1));
+ std::string input =
+ base::UTF16ToUTF8((text.size() == 6) ? text : text.substr(1));
std::vector<uint8> hex;
if (!base::HexStringToBytes(input, &hex))
return false;
@@ -125,7 +126,7 @@ class ColorChooserView::HueView : public LocatedEventHandlerView {
virtual void ProcessEventAtLocation(const gfx::Point& point) OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
ColorChooserView* chooser_view_;
@@ -163,7 +164,7 @@ void ColorChooserView::HueView::ProcessEventAtLocation(
SchedulePaint();
}
-gfx::Size ColorChooserView::HueView::GetPreferredSize() {
+gfx::Size ColorChooserView::HueView::GetPreferredSize() const {
// We put indicators on the both sides of the hue bar.
return gfx::Size(kHueBarWidth + kHueIndicatorSize * 2 + kBorderWidth * 2,
kSaturationValueSize + kBorderWidth * 2);
@@ -237,7 +238,7 @@ class ColorChooserView::SaturationValueView : public LocatedEventHandlerView {
virtual void ProcessEventAtLocation(const gfx::Point& point) OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
ColorChooserView* chooser_view_;
@@ -252,7 +253,7 @@ ColorChooserView::SaturationValueView::SaturationValueView(
: chooser_view_(chooser_view),
hue_(0) {
SetFocusable(false);
- set_border(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
+ SetBorder(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
}
void ColorChooserView::SaturationValueView::OnHueChanged(SkScalar hue) {
@@ -291,7 +292,7 @@ void ColorChooserView::SaturationValueView::ProcessEventAtLocation(
chooser_view_->OnSaturationValueChosen(saturation, value);
}
-gfx::Size ColorChooserView::SaturationValueView::GetPreferredSize() {
+gfx::Size ColorChooserView::SaturationValueView::GetPreferredSize() const {
return gfx::Size(kSaturationValueSize + kBorderWidth * 2,
kSaturationValueSize + kBorderWidth * 2);
}
@@ -348,7 +349,7 @@ class ColorChooserView::SelectedColorPatchView : public views::View {
ColorChooserView::SelectedColorPatchView::SelectedColorPatchView() {
SetFocusable(false);
SetVisible(true);
- set_border(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
+ SetBorder(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY));
}
void ColorChooserView::SelectedColorPatchView::SetColor(SkColor color) {
@@ -393,7 +394,7 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener,
GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
textfield_ = new Textfield();
- textfield_->SetController(this);
+ textfield_->set_controller(this);
textfield_->set_default_width_in_chars(kTextfieldLengthInChars);
layout->AddView(textfield_);
selected_color_patch_ = new SelectedColorPatchView();
@@ -454,7 +455,7 @@ View* ColorChooserView::GetContentsView() {
}
void ColorChooserView::ContentsChanged(Textfield* sender,
- const string16& new_contents) {
+ const base::string16& new_contents) {
SkColor color = SK_ColorBLACK;
if (GetColorFromText(new_contents, &color)) {
SkColorToHSV(color, hsv_);
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.h b/chromium/ui/views/color_chooser/color_chooser_view.h
index c77e0b66c17..e7fda323c87 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.h
+++ b/chromium/ui/views/color_chooser/color_chooser_view.h
@@ -55,7 +55,7 @@ class VIEWS_EXPORT ColorChooserView : public WidgetDelegateView,
// TextfieldController overrides:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE;
+ const base::string16& new_contents) OVERRIDE;
virtual bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) OVERRIDE;
diff --git a/chromium/ui/views/controls/button/blue_button.cc b/chromium/ui/views/controls/button/blue_button.cc
index 3e52afd896e..e3a9487ff6c 100644
--- a/chromium/ui/views/controls/button/blue_button.cc
+++ b/chromium/ui/views/controls/button/blue_button.cc
@@ -5,19 +5,13 @@
#include "ui/views/controls/button/blue_button.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/sys_color_change_listener.h"
#include "ui/views/controls/button/label_button_border.h"
namespace {
-// Insets for the unified blue_button images. This assumes that the images
-// are of a 9 grid, of 5x5 size each.
-const int kBlueButtonInsets = 5;
-
-// Default text and shadow colors for the blue button.
-const SkColor kBlueButtonTextColor = SK_ColorWHITE;
+// Default shadow color for the blue button.
const SkColor kBlueButtonShadowColor = SkColorSetRGB(0x53, 0x8C, 0xEA);
} // namespace
@@ -27,42 +21,11 @@ namespace views {
// static
const char BlueButton::kViewClassName[] = "views/BlueButton";
-BlueButton::BlueButton(ButtonListener* listener, const string16& text)
+BlueButton::BlueButton(ButtonListener* listener, const base::string16& text)
: LabelButton(listener, text) {
// Inherit STYLE_BUTTON insets, minimum size, alignment, etc.
SetStyle(STYLE_BUTTON);
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- const gfx::Insets insets(kBlueButtonInsets,
- kBlueButtonInsets,
- kBlueButtonInsets,
- kBlueButtonInsets);
-
- LabelButtonBorder* button_border = static_cast<LabelButtonBorder*>(border());
- button_border->SetPainter(false, STATE_NORMAL,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_NORMAL), insets));
- button_border->SetPainter(false, STATE_HOVERED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_HOVER), insets));
- button_border->SetPainter(false, STATE_PRESSED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_PRESSED), insets));
- button_border->SetPainter(false, STATE_DISABLED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
- button_border->SetPainter(true, STATE_NORMAL,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_NORMAL), insets));
- button_border->SetPainter(true, STATE_HOVERED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_HOVER), insets));
- button_border->SetPainter(true, STATE_PRESSED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_PRESSED), insets));
- button_border->SetPainter(true, STATE_DISABLED,
- Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ UpdateThemedBorder();
}
BlueButton::~BlueButton() {}
@@ -70,10 +33,18 @@ BlueButton::~BlueButton() {}
void BlueButton::ResetColorsFromNativeTheme() {
LabelButton::ResetColorsFromNativeTheme();
if (!gfx::IsInvertedColorScheme()) {
- for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state)
- SetTextColor(static_cast<ButtonState>(state), kBlueButtonTextColor);
- label()->SetShadowColors(kBlueButtonShadowColor, kBlueButtonShadowColor);
- label()->SetShadowOffset(0, 1);
+ SetTextColor(STATE_NORMAL, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonEnabledColor));
+ SetTextColor(STATE_HOVERED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonHoverColor));
+ SetTextColor(STATE_PRESSED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonHighlightColor));
+ SetTextColor(STATE_DISABLED, GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_BlueButtonDisabledColor));
+
+ // TODO(estade): this is not great on system themes.
+ label()->set_shadows(gfx::ShadowValues(1,
+ gfx::ShadowValue(gfx::Point(0, 1), 0, kBlueButtonShadowColor)));
}
}
@@ -81,4 +52,28 @@ const char* BlueButton::GetClassName() const {
return BlueButton::kViewClassName;
}
+scoped_ptr<LabelButtonBorder> BlueButton::CreateDefaultBorder() const {
+ // Insets for splitting the images.
+ const gfx::Insets insets(5, 5, 5, 5);
+ scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder(style()));
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ button_border->SetPainter(false, STATE_NORMAL, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_NORMAL), insets));
+ button_border->SetPainter(false, STATE_HOVERED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_HOVER), insets));
+ button_border->SetPainter(false, STATE_PRESSED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_PRESSED), insets));
+ button_border->SetPainter(false, STATE_DISABLED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ button_border->SetPainter(true, STATE_NORMAL, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_NORMAL), insets));
+ button_border->SetPainter(true, STATE_HOVERED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_HOVER), insets));
+ button_border->SetPainter(true, STATE_PRESSED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_PRESSED), insets));
+ button_border->SetPainter(true, STATE_DISABLED, Painter::CreateImagePainter(
+ *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
+ return button_border.Pass();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/button/blue_button.h b/chromium/ui/views/controls/button/blue_button.h
index a169fba85d1..8c83c007ec6 100644
--- a/chromium/ui/views/controls/button/blue_button.h
+++ b/chromium/ui/views/controls/button/blue_button.h
@@ -22,6 +22,7 @@ class VIEWS_EXPORT BlueButton : public LabelButton {
// Overridden from LabelButton:
virtual void ResetColorsFromNativeTheme() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
+ virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(BlueButton);
};
diff --git a/chromium/ui/views/controls/button/blue_button_unittest.cc b/chromium/ui/views/controls/button/blue_button_unittest.cc
new file mode 100644
index 00000000000..908e747d24c
--- /dev/null
+++ b/chromium/ui/views/controls/button/blue_button_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/button/blue_button.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace views {
+
+namespace {
+
+class TestBlueButton : public BlueButton {
+ public:
+ TestBlueButton() : BlueButton(NULL, base::ASCIIToUTF16("foo")) {}
+ virtual ~TestBlueButton() {}
+
+ using BlueButton::OnNativeThemeChanged;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestBlueButton);
+};
+
+} // namespace
+
+typedef ViewsTestBase BlueButtonTest;
+
+TEST_F(BlueButtonTest, Border) {
+ // Compared to a normal LabelButton...
+ LabelButton button(NULL, base::ASCIIToUTF16("foo"));
+ button.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), button.GetPreferredSize()));
+ gfx::Canvas button_canvas(button.bounds().size(), 1.0, true);
+ button.border()->Paint(button, &button_canvas);
+
+ // ... a special blue border should be used.
+ TestBlueButton blue_button;
+ blue_button.SetBoundsRect(gfx::Rect(gfx::Point(0, 0),
+ blue_button.GetPreferredSize()));
+ gfx::Canvas canvas(blue_button.bounds().size(), 1.0, true);
+ blue_button.border()->Paint(blue_button, &canvas);
+ EXPECT_EQ(button.GetText(), blue_button.GetText());
+ EXPECT_FALSE(gfx::BitmapsAreEqual(button_canvas.ExtractImageRep().sk_bitmap(),
+ canvas.ExtractImageRep().sk_bitmap()));
+
+ // Make sure it's still used after the native theme "changes".
+ blue_button.OnNativeThemeChanged(NULL);
+ gfx::Canvas canvas2(blue_button.bounds().size(), 1.0, true);
+ blue_button.border()->Paint(blue_button, &canvas2);
+
+ EXPECT_TRUE(gfx::BitmapsAreEqual(canvas.ExtractImageRep().sk_bitmap(),
+ canvas2.ExtractImageRep().sk_bitmap()));
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index 96e2e27432c..4e7f51b5450 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -5,31 +5,47 @@
#include "ui/views/controls/button/button.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
////////////////////////////////////////////////////////////////////////////////
+// Button, static public:
+
+// static
+Button::ButtonState Button::GetButtonStateFrom(ui::NativeTheme::State state) {
+ switch (state) {
+ case ui::NativeTheme::kDisabled: return Button::STATE_DISABLED;
+ case ui::NativeTheme::kHovered: return Button::STATE_HOVERED;
+ case ui::NativeTheme::kNormal: return Button::STATE_NORMAL;
+ case ui::NativeTheme::kPressed: return Button::STATE_PRESSED;
+ case ui::NativeTheme::kMaxState: NOTREACHED() << "Unknown state: " << state;
+ }
+ return Button::STATE_NORMAL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Button, public:
Button::~Button() {
}
-void Button::SetTooltipText(const string16& tooltip_text) {
+void Button::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
if (accessible_name_.empty())
accessible_name_ = tooltip_text_;
TooltipTextChanged();
}
-void Button::SetAccessibleName(const string16& name) {
+void Button::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
////////////////////////////////////////////////////////////////////////////////
// Button, View overrides:
-bool Button::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool Button::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
if (tooltip_text_.empty())
return false;
@@ -37,8 +53,8 @@ bool Button::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
return true;
}
-void Button::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
+void Button::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_BUTTON;
state->name = accessible_name_;
}
diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h
index d038015f870..37d639dd6a8 100644
--- a/chromium/ui/views/controls/button/button.h
+++ b/chromium/ui/views/controls/button/button.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
+#include "ui/native_theme/native_theme.h"
#include "ui/views/view.h"
namespace views {
@@ -42,21 +43,22 @@ class VIEWS_EXPORT Button : public View {
enum ButtonStyle {
STYLE_BUTTON = 0,
STYLE_TEXTBUTTON,
- STYLE_NATIVE_TEXTBUTTON,
STYLE_COUNT,
};
- void SetTooltipText(const string16& tooltip_text);
+ static ButtonState GetButtonStateFrom(ui::NativeTheme::State state);
+
+ void SetTooltipText(const base::string16& tooltip_text);
int tag() const { return tag_; }
void set_tag(int tag) { tag_ = tag; }
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// Construct the Button with a Listener. The listener can be NULL. This can be
@@ -72,10 +74,10 @@ class VIEWS_EXPORT Button : public View {
private:
// The text shown in a tooltip.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
// Accessibility data.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// The id tag associated with this button. Used to disambiguate buttons in
// the ButtonListener implementation.
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index ec33a47e2b1..22c5f88e2d6 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -5,7 +5,7 @@
#include "ui/views/controls/button/checkbox.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/painter.h"
@@ -15,15 +15,16 @@ namespace views {
// static
const char Checkbox::kViewClassName[] = "Checkbox";
-Checkbox::Checkbox(const string16& label)
+Checkbox::Checkbox(const base::string16& label)
: LabelButton(NULL, label),
checked_(false) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
- LabelButtonBorder* button_border = static_cast<LabelButtonBorder*>(border());
+ scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder(style()));
button_border->SetPainter(false, STATE_HOVERED, NULL);
button_border->SetPainter(false, STATE_PRESSED, NULL);
// Inset the trailing side by a couple pixels for the focus border.
button_border->set_insets(gfx::Insets(0, 0, 0, 2));
+ SetBorder(button_border.PassAs<Border>());
SetFocusable(true);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -93,10 +94,11 @@ const char* Checkbox::GetClassName() const {
return kViewClassName;
}
-void Checkbox::GetAccessibleState(ui::AccessibleViewState* state) {
+void Checkbox::GetAccessibleState(ui::AXViewState* state) {
LabelButton::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_CHECKBUTTON;
- state->state = checked() ? ui::AccessibilityTypes::STATE_CHECKED : 0;
+ state->role = ui::AX_ROLE_CHECK_BOX;
+ if (checked())
+ state->AddStateFlag(ui::AX_STATE_CHECKED);
}
void Checkbox::OnFocus() {
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index a603bd5b2dd..7bfd5bcf7d1 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -19,7 +19,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
public:
static const char kViewClassName[];
- explicit Checkbox(const string16& label);
+ explicit Checkbox(const base::string16& label);
virtual ~Checkbox();
// Sets a listener for this checkbox. Checkboxes aren't required to have them
@@ -34,7 +34,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// Overridden from LabelButton:
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
virtual const gfx::ImageSkia& GetImage(ButtonState for_state) OVERRIDE;
diff --git a/chromium/ui/views/controls/button/custom_button.cc b/chromium/ui/views/controls/button/custom_button.cc
index 2be2a2301e1..0e237a31273 100644
--- a/chromium/ui/views/controls/button/custom_button.cc
+++ b/chromium/ui/views/controls/button/custom_button.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/button/custom_button.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/animation/throb_animation.h"
@@ -101,7 +101,7 @@ void CustomButton::SetHotTracked(bool is_hot_tracked) {
SetState(is_hot_tracked ? STATE_HOVERED : STATE_NORMAL);
if (is_hot_tracked)
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
bool CustomButton::IsHotTracked() const {
@@ -199,6 +199,7 @@ bool CustomButton::OnKeyPressed(const ui::KeyEvent& event) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
} else {
@@ -216,6 +217,7 @@ bool CustomButton::OnKeyReleased(const ui::KeyEvent& event) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
return true;
@@ -260,6 +262,7 @@ bool CustomButton::AcceleratorPressed(const ui::Accelerator& accelerator) {
ui::MouseEvent synthetic_event(ui::ET_MOUSE_RELEASED,
gfx::Point(),
gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
NotifyClick(synthetic_event);
return true;
@@ -281,17 +284,17 @@ void CustomButton::OnDragDone() {
SetState(STATE_NORMAL);
}
-void CustomButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void CustomButton::GetAccessibleState(ui::AXViewState* state) {
Button::GetAccessibleState(state);
switch (state_) {
case STATE_HOVERED:
- state->state = ui::AccessibilityTypes::STATE_HOTTRACKED;
+ state->AddStateFlag(ui::AX_STATE_HOVERED);
break;
case STATE_PRESSED:
- state->state = ui::AccessibilityTypes::STATE_PRESSED;
+ state->AddStateFlag(ui::AX_STATE_PRESSED);
break;
case STATE_DISABLED:
- state->state = ui::AccessibilityTypes::STATE_UNAVAILABLE;
+ state->AddStateFlag(ui::AX_STATE_DISABLED);
break;
case STATE_NORMAL:
case STATE_COUNT:
diff --git a/chromium/ui/views/controls/button/custom_button.h b/chromium/ui/views/controls/button/custom_button.h
index 9ac502d3d96..4614a5c7323 100644
--- a/chromium/ui/views/controls/button/custom_button.h
+++ b/chromium/ui/views/controls/button/custom_button.h
@@ -18,8 +18,8 @@ namespace views {
class CustomButtonStateChangedDelegate;
-// A button with custom rendering. The common base class of ImageButton and
-// TextButton.
+// A button with custom rendering. The common base class of ImageButton,
+// LabelButton and TextButton.
// Note that this type of button is not focusable by default and will not be
// part of the focus chain. Call SetFocusable(true) to make it part of the
// focus chain.
@@ -84,7 +84,7 @@ class VIEWS_EXPORT CustomButton : public Button,
virtual void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type) OVERRIDE;
virtual void OnDragDone() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
// Overridden from gfx::AnimationDelegate:
diff --git a/chromium/ui/views/controls/button/custom_button_unittest.cc b/chromium/ui/views/controls/button/custom_button_unittest.cc
index f7b11e648ed..84836716701 100644
--- a/chromium/ui/views/controls/button/custom_button_unittest.cc
+++ b/chromium/ui/views/controls/button/custom_button_unittest.cc
@@ -5,6 +5,9 @@
#include "ui/views/controls/button/custom_button.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/test_cursor_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/layout.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/button/checkbox.h"
@@ -16,12 +19,6 @@
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_cursor_client.h"
-#include "ui/aura/window.h"
-#endif
-
namespace views {
namespace {
@@ -38,7 +35,6 @@ class TestCustomButton : public CustomButton {
DISALLOW_COPY_AND_ASSIGN(TestCustomButton);
};
-#if defined(USE_AURA)
void PerformGesture(CustomButton* button, ui::EventType event_type) {
ui::GestureEventDetails gesture_details(event_type, 0, 0);
base::TimeDelta time_stamp = base::TimeDelta::FromMicroseconds(0);
@@ -46,7 +42,6 @@ void PerformGesture(CustomButton* button, ui::EventType event_type) {
gesture_details, 1);
button->OnGestureEvent(&gesture_event);
}
-#endif // USE_AURA
} // namespace
@@ -63,10 +58,8 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
widget->Init(params);
widget->Show();
-#if defined(USE_AURA)
aura::test::TestCursorClient cursor_client(
widget->GetNativeView()->GetRootWindow());
-#endif
// Position the widget in a way so that it is under the cursor.
gfx::Point cursor = gfx::Screen::GetScreenFor(
@@ -80,10 +73,12 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
gfx::Point center(10, 10);
button->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED, center, center,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(CustomButton::STATE_PRESSED, button->state());
button->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED, center, center,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
@@ -99,7 +94,6 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
button->SetVisible(true);
EXPECT_EQ(CustomButton::STATE_HOVERED, button->state());
-#if defined(USE_AURA)
// In Aura views, no new hover effects are invoked if mouse events
// are disabled.
cursor_client.DisableMouseEvents();
@@ -115,10 +109,8 @@ TEST_F(CustomButtonTest, HoverStateOnVisibilityChange) {
button->SetVisible(true);
EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
-#endif
}
-#if defined(USE_AURA)
// Tests that gesture events correctly change the button state.
TEST_F(CustomButtonTest, GestureEventsSetState) {
// Create a widget so that the CustomButton can query the hover state
@@ -148,12 +140,10 @@ TEST_F(CustomButtonTest, GestureEventsSetState) {
EXPECT_EQ(CustomButton::STATE_NORMAL, button->state());
}
-#endif // USE_AURA
-
// Make sure all subclasses of CustomButton are correctly recognized
// as CustomButton.
TEST_F(CustomButtonTest, AsCustomButton) {
- string16 text;
+ base::string16 text;
TextButton text_button(NULL, text);
EXPECT_TRUE(CustomButton::AsCustomButton(&text_button));
@@ -176,7 +166,7 @@ TEST_F(CustomButtonTest, AsCustomButton) {
Link link(text);
EXPECT_FALSE(CustomButton::AsCustomButton(&link));
- Textfield textfield(Textfield::STYLE_DEFAULT);
+ Textfield textfield;
EXPECT_FALSE(CustomButton::AsCustomButton(&textfield));
}
diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc
index 6a842346d2c..ecbd4a10724 100644
--- a/chromium/ui/views/controls/button/image_button.cc
+++ b/chromium/ui/views/controls/button/image_button.cc
@@ -5,7 +5,7 @@
#include "ui/views/controls/button/image_button.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_operations.h"
@@ -60,14 +60,6 @@ void ImageButton::SetBackground(SkColor color,
*image, *mask);
}
-void ImageButton::SetOverlayImage(const gfx::ImageSkia* image) {
- if (!image) {
- overlay_image_ = gfx::ImageSkia();
- return;
- }
- overlay_image_ = *image;
-}
-
void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
VerticalAlignment v_align) {
h_alignment_ = h_align;
@@ -82,7 +74,7 @@ void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
////////////////////////////////////////////////////////////////////////////////
// ImageButton, View overrides:
-gfx::Size ImageButton::GetPreferredSize() {
+gfx::Size ImageButton::GetPreferredSize() const {
gfx::Size size = preferred_size_;
if (!images_[STATE_NORMAL].isNull()) {
size = gfx::Size(images_[STATE_NORMAL].width(),
@@ -116,9 +108,6 @@ void ImageButton::OnPaint(gfx::Canvas* canvas) {
canvas->DrawImageInt(background_image_, position.x(), position.y());
canvas->DrawImageInt(img, position.x(), position.y());
-
- if (!overlay_image_.isNull())
- canvas->DrawImageInt(overlay_image_, position.x(), position.y());
}
Painter::PaintFocusPainter(this, canvas, focus_painter());
@@ -206,7 +195,7 @@ void ToggleImageButton::SetToggled(bool toggled) {
toggled_ = toggled;
SchedulePaint();
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
}
void ToggleImageButton::SetToggledImage(ButtonState state,
@@ -220,7 +209,7 @@ void ToggleImageButton::SetToggledImage(ButtonState state,
}
}
-void ToggleImageButton::SetToggledTooltipText(const string16& tooltip) {
+void ToggleImageButton::SetToggledTooltipText(const base::string16& tooltip) {
toggled_tooltip_text_ = tooltip;
}
@@ -249,7 +238,7 @@ void ToggleImageButton::SetImage(ButtonState state,
// ToggleImageButton, View overrides:
bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
if (!toggled_ || toggled_tooltip_text_.empty())
return Button::GetTooltipText(p, tooltip);
@@ -257,7 +246,7 @@ bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
return true;
}
-void ToggleImageButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
ImageButton::GetAccessibleState(state);
GetTooltipText(gfx::Point(), &state->name);
}
diff --git a/chromium/ui/views/controls/button/image_button.h b/chromium/ui/views/controls/button/image_button.h
index 4977b06d398..fc02b8ac9ce 100644
--- a/chromium/ui/views/controls/button/image_button.h
+++ b/chromium/ui/views/controls/button/image_button.h
@@ -51,10 +51,6 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
const gfx::ImageSkia* image,
const gfx::ImageSkia* mask);
- // Set an |image| to draw on top of the normal / hot / pushed image.
- // Pass NULL for no image.
- void SetOverlayImage(const gfx::ImageSkia* image);
-
// Sets how the image is laid out within the button's bounds.
void SetImageAlignment(HorizontalAlignment h_align,
VerticalAlignment v_align);
@@ -73,7 +69,7 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
}
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -96,9 +92,6 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
gfx::ImageSkia background_image_;
- // Image to draw on top of normal / hot / pushed image. Usually empty.
- gfx::ImageSkia overlay_image_;
-
private:
FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, Basics);
FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, ImagePositionWithBorder);
@@ -145,7 +138,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
void SetToggledImage(ButtonState state, const gfx::ImageSkia* image);
// Set the tooltip text displayed when the button is toggled.
- void SetToggledTooltipText(const string16& tooltip);
+ void SetToggledTooltipText(const base::string16& tooltip);
// Overridden from ImageButton:
virtual const gfx::ImageSkia& GetImage(ButtonState state) const OVERRIDE;
@@ -154,8 +147,8 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
// The parent class's images_ member is used for the current images,
@@ -168,7 +161,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
// The parent class's tooltip_text_ is displayed when not toggled, and
// this one is shown when toggled.
- string16 toggled_tooltip_text_;
+ base::string16 toggled_tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(ToggleImageButton);
};
diff --git a/chromium/ui/views/controls/button/image_button_unittest.cc b/chromium/ui/views/controls/button/image_button_unittest.cc
index 995b2056de4..406d02c3ae2 100644
--- a/chromium/ui/views/controls/button/image_button_unittest.cc
+++ b/chromium/ui/views/controls/button/image_button_unittest.cc
@@ -60,25 +60,6 @@ TEST_F(ImageButtonTest, Basics) {
EXPECT_FALSE(button.GetImageToPaint().isNull());
EXPECT_EQ(10, button.GetImageToPaint().width());
EXPECT_EQ(20, button.GetImageToPaint().height());
-
- // Set an overlay image.
- gfx::ImageSkia overlay_image = CreateTestImage(12, 22);
- button.SetOverlayImage(&overlay_image);
- EXPECT_EQ(12, button.overlay_image_.width());
- EXPECT_EQ(22, button.overlay_image_.height());
-
- // By convention, preferred size doesn't change, even though pushed image
- // is bigger.
- EXPECT_EQ("10x20", button.GetPreferredSize().ToString());
-
- // We're still painting the normal image.
- EXPECT_FALSE(button.GetImageToPaint().isNull());
- EXPECT_EQ(10, button.GetImageToPaint().width());
- EXPECT_EQ(20, button.GetImageToPaint().height());
-
- // Reset the overlay image.
- button.SetOverlayImage(NULL);
- EXPECT_TRUE(button.overlay_image_.isNull());
}
TEST_F(ImageButtonTest, SetAndGetImage) {
@@ -116,11 +97,11 @@ TEST_F(ImageButtonTest, ImagePositionWithBorder) {
EXPECT_EQ(gfx::Point().ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(views::Border::CreateEmptyBorder(10, 5, 0, 0));
+ button.SetBorder(views::Border::CreateEmptyBorder(10, 5, 0, 0));
EXPECT_EQ(gfx::Point(5, 10).ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(NULL);
+ button.SetBorder(Border::NullBorder());
button.SetBounds(0, 0, 50, 50);
EXPECT_EQ(gfx::Point().ToString(),
button.ComputeImagePaintPosition(image).ToString());
@@ -129,7 +110,7 @@ TEST_F(ImageButtonTest, ImagePositionWithBorder) {
ImageButton::ALIGN_MIDDLE);
EXPECT_EQ(gfx::Point(15, 10).ToString(),
button.ComputeImagePaintPosition(image).ToString());
- button.set_border(views::Border::CreateEmptyBorder(10, 10, 0, 0));
+ button.SetBorder(views::Border::CreateEmptyBorder(10, 10, 0, 0));
EXPECT_EQ(gfx::Point(20, 15).ToString(),
button.ComputeImagePaintPosition(image).ToString());
}
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 30db5d13d9a..c0399147775 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -8,14 +8,17 @@
#include "grit/ui_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/sys_color_change_listener.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/painter.h"
#include "ui/views/window/dialog_delegate.h"
-#if defined(OS_WIN)
-#include "ui/native_theme/native_theme_win.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/linux_ui/linux_ui.h"
#endif
namespace {
@@ -23,9 +26,11 @@ namespace {
// The spacing between the icon and text.
const int kSpacing = 5;
+#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
// Default text and shadow colors for STYLE_BUTTON.
const SkColor kStyleButtonTextColor = SK_ColorBLACK;
const SkColor kStyleButtonShadowColor = SK_ColorWHITE;
+#endif
} // namespace
@@ -37,7 +42,7 @@ const int LabelButton::kHoverAnimationDurationMs = 170;
// static
const char LabelButton::kViewClassName[] = "LabelButton";
-LabelButton::LabelButton(ButtonListener* listener, const string16& text)
+LabelButton::LabelButton(ButtonListener* listener, const base::string16& text)
: CustomButton(listener),
image_(new ImageView()),
label_(new Label()),
@@ -45,9 +50,11 @@ LabelButton::LabelButton(ButtonListener* listener, const string16& text)
button_state_colors_(),
explicitly_set_colors_(),
is_default_(false),
- style_(STYLE_TEXTBUTTON) {
+ style_(STYLE_TEXTBUTTON),
+ border_is_themed_border_(true) {
SetAnimationDuration(kHoverAnimationDurationMs);
SetText(text);
+ SetFontList(gfx::FontList());
AddChildView(image_);
image_->set_interactive(false);
@@ -75,11 +82,11 @@ void LabelButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) {
UpdateImage();
}
-const string16& LabelButton::GetText() const {
+const base::string16& LabelButton::GetText() const {
return label_->text();
}
-void LabelButton::SetText(const string16& text) {
+void LabelButton::SetText(const base::string16& text) {
SetAccessibleName(text);
label_->SetText(text);
}
@@ -93,6 +100,14 @@ void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
explicitly_set_colors_[for_state] = true;
}
+void LabelButton::SetTextShadows(const gfx::ShadowValues& shadows) {
+ label_->set_shadows(shadows);
+}
+
+void LabelButton::SetTextSubpixelRenderingEnabled(bool enabled) {
+ label_->set_subpixel_rendering_enabled(enabled);
+}
+
bool LabelButton::GetTextMultiLine() const {
return label_->is_multi_line();
}
@@ -101,20 +116,27 @@ void LabelButton::SetTextMultiLine(bool text_multi_line) {
label_->SetMultiLine(text_multi_line);
}
-const gfx::Font& LabelButton::GetFont() const {
- return label_->font();
+const gfx::FontList& LabelButton::GetFontList() const {
+ return label_->font_list();
}
-void LabelButton::SetFont(const gfx::Font& font) {
- label_->SetFont(font);
+void LabelButton::SetFontList(const gfx::FontList& font_list) {
+ cached_normal_font_list_ = font_list;
+ cached_bold_font_list_ = font_list.DeriveWithStyle(
+ font_list.GetFontStyle() | gfx::Font::BOLD);
+
+ // STYLE_BUTTON uses bold text to indicate default buttons.
+ label_->SetFontList(
+ style_ == STYLE_BUTTON && is_default_ ?
+ cached_bold_font_list_ : cached_normal_font_list_);
}
-void LabelButton::SetElideBehavior(Label::ElideBehavior elide_behavior) {
+void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
label_->SetElideBehavior(elide_behavior);
}
gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const {
- return label_->horizontal_alignment();
+ return label_->GetHorizontalAlignment();
}
void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
@@ -122,6 +144,10 @@ void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
InvalidateLayout();
}
+void LabelButton::SetDirectionalityMode(gfx::DirectionalityMode mode) {
+ label_->set_directionality_mode(mode);
+}
+
void LabelButton::SetIsDefault(bool is_default) {
if (is_default == is_default_)
return;
@@ -131,20 +157,13 @@ void LabelButton::SetIsDefault(bool is_default) {
// STYLE_BUTTON uses bold text to indicate default buttons.
if (style_ == STYLE_BUTTON) {
- int style = label_->font().GetStyle();
- style = is_default ? style | gfx::Font::BOLD : style & ~gfx::Font::BOLD;
- label_->SetFont(label_->font().DeriveFont(0, style));
+ label_->SetFontList(
+ is_default ? cached_bold_font_list_ : cached_normal_font_list_);
}
}
void LabelButton::SetStyle(ButtonStyle style) {
- // Use the new button style instead of the native button style.
- // TODO(msw): Officialy deprecate and remove STYLE_NATIVE_TEXTBUTTON.
- if (style == STYLE_NATIVE_TEXTBUTTON)
- style = STYLE_BUTTON;
-
style_ = style;
- set_border(new LabelButtonBorder(style));
// Inset the button focus rect from the actual border; roughly match Windows.
if (style == STYLE_BUTTON) {
SetFocusPainter(scoped_ptr<Painter>());
@@ -152,34 +171,33 @@ void LabelButton::SetStyle(ButtonStyle style) {
SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
gfx::Insets(3, 3, 3, 3)));
}
- if (style == STYLE_BUTTON || style == STYLE_NATIVE_TEXTBUTTON) {
+ if (style == STYLE_BUTTON) {
label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
SetFocusable(true);
}
if (style == STYLE_BUTTON)
set_min_size(gfx::Size(70, 33));
- // Invalidate the layout to pickup the new insets from the border.
- InvalidateLayout();
- ResetColorsFromNativeTheme();
+
+ OnNativeThemeChanged(GetNativeTheme());
}
void LabelButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
focus_painter_ = focus_painter.Pass();
}
-gfx::Size LabelButton::GetPreferredSize() {
+gfx::Size LabelButton::GetPreferredSize() const {
// Use a temporary label copy for sizing to avoid calculation side-effects.
- gfx::Font font = GetFont();
- Label label(GetText(), font);
+ Label label(GetText(), cached_normal_font_list_);
+ label.set_shadows(label_->shadows());
label.SetMultiLine(GetTextMultiLine());
if (style() == STYLE_BUTTON) {
// Some text appears wider when rendered normally than when rendered bold.
// Accommodate the widest, as buttons may show bold and shouldn't resize.
const int current_width = label.GetPreferredSize().width();
- label.SetFont(font.DeriveFont(0, font.GetStyle() ^ gfx::Font::BOLD));
+ label.SetFontList(cached_bold_font_list_);
if (label.GetPreferredSize().width() < current_width)
- label.SetFont(font);
+ label.SetFontList(cached_normal_font_list_);
}
// Resize multi-line labels given the current limited available width.
@@ -197,7 +215,7 @@ gfx::Size LabelButton::GetPreferredSize() {
size.Enlarge(image_size.width() + insets.width(), insets.height());
// Make the size at least as large as the minimum size needed by the border.
- size.SetToMax(border()->GetMinimumSize());
+ size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
// Increase the minimum size monotonically with the preferred size.
size.SetToMax(min_size_);
@@ -217,17 +235,17 @@ void LabelButton::Layout() {
adjusted_alignment = (adjusted_alignment == gfx::ALIGN_LEFT) ?
gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
- gfx::Rect child_area(GetLocalBounds());
+ gfx::Rect child_area(GetChildAreaBounds());
child_area.Inset(GetInsets());
gfx::Size image_size(image_->GetPreferredSize());
- image_size.set_width(std::min(image_size.width(), child_area.width()));
- image_size.set_height(std::min(image_size.height(), child_area.height()));
+ image_size.SetToMin(child_area.size());
// The label takes any remaining width after sizing the image, unless both
// views are centered. In that case, using the tighter preferred label width
// avoids wasted space within the label that would look like awkward padding.
- gfx::Size label_size(child_area.size());
+ // Labels can paint over the full button height, including the border height.
+ gfx::Size label_size(child_area.width(), height());
if (!image_size.IsEmpty() && !label_size.IsEmpty()) {
label_size.set_width(
std::max(child_area.width() - image_size.width() - kSpacing, 0));
@@ -250,8 +268,8 @@ void LabelButton::Layout() {
image_origin.Offset(child_area.width() - image_size.width(), 0);
}
- gfx::Point label_origin(child_area.origin());
- if (!image_size.IsEmpty() &&adjusted_alignment != gfx::ALIGN_RIGHT)
+ gfx::Point label_origin(child_area.x(), 0);
+ if (!image_size.IsEmpty() && adjusted_alignment != gfx::ALIGN_RIGHT)
label_origin.set_x(image_origin.x() + image_size.width() + kSpacing);
image_->SetBoundsRect(gfx::Rect(image_origin, image_size));
@@ -262,6 +280,19 @@ const char* LabelButton::GetClassName() const {
return kViewClassName;
}
+scoped_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const {
+ return scoped_ptr<LabelButtonBorder>(new LabelButtonBorder(style_));
+}
+
+void LabelButton::SetBorder(scoped_ptr<Border> border) {
+ border_is_themed_border_ = false;
+ View::SetBorder(border.Pass());
+}
+
+gfx::Rect LabelButton::GetChildAreaBounds() {
+ return GetLocalBounds();
+}
+
void LabelButton::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
@@ -284,9 +315,9 @@ void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
params->button.indeterminate = false;
params->button.is_default = is_default_;
params->button.is_focused = HasFocus() && IsAccessibilityFocusable();
- params->button.has_border = style() == STYLE_NATIVE_TEXTBUTTON;
+ params->button.has_border = false;
params->button.classic_state = 0;
- params->button.background_color = label()->background_color();
+ params->button.background_color = label_->background_color();
}
void LabelButton::ResetColorsFromNativeTheme() {
@@ -300,26 +331,31 @@ void LabelButton::ResetColorsFromNativeTheme() {
// Certain styles do not change text color when hovered or pressed.
bool constant_text_color = false;
-#if defined(OS_WIN)
- constant_text_color |= (style() == STYLE_NATIVE_TEXTBUTTON &&
- theme == ui::NativeThemeWin::instance());
-#endif
-
// Use hardcoded colors for inverted color scheme support and STYLE_BUTTON.
if (gfx::IsInvertedColorScheme()) {
constant_text_color = true;
colors[STATE_NORMAL] = SK_ColorWHITE;
label_->SetBackgroundColor(SK_ColorBLACK);
+ label_->set_background(Background::CreateSolidBackground(SK_ColorBLACK));
label_->SetAutoColorReadabilityEnabled(true);
- label_->ClearEmbellishing();
+ label_->set_shadows(gfx::ShadowValues());
} else if (style() == STYLE_BUTTON) {
+ // TODO(erg): This is disabled on desktop linux because of the binary asset
+ // confusion. These details should either be pushed into ui::NativeThemeWin
+ // or should be obsoleted by rendering buttons with paint calls instead of
+ // with static assets. http://crbug.com/350498
+#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
constant_text_color = true;
colors[STATE_NORMAL] = kStyleButtonTextColor;
label_->SetBackgroundColor(theme->GetSystemColor(
ui::NativeTheme::kColorId_ButtonBackgroundColor));
label_->SetAutoColorReadabilityEnabled(false);
- label_->SetShadowColors(kStyleButtonShadowColor, kStyleButtonShadowColor);
- label_->SetShadowOffset(0, 1);
+ label_->set_shadows(gfx::ShadowValues(1,
+ gfx::ShadowValue(gfx::Point(0, 1), 0, kStyleButtonShadowColor)));
+#endif
+ label_->set_background(NULL);
+ } else {
+ label_->set_background(NULL);
}
if (constant_text_color)
@@ -337,6 +373,27 @@ void LabelButton::UpdateImage() {
image_->SetImage(GetImage(state()));
}
+void LabelButton::UpdateThemedBorder() {
+ // Don't override borders set by others.
+ if (!border_is_themed_border_)
+ return;
+
+ scoped_ptr<LabelButtonBorder> label_button_border = CreateDefaultBorder();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ views::LinuxUI* linux_ui = views::LinuxUI::instance();
+ if (linux_ui) {
+ SetBorder(linux_ui->CreateNativeBorder(
+ this, label_button_border.Pass()));
+ } else
+#endif
+ {
+ SetBorder(label_button_border.PassAs<Border>());
+ }
+
+ border_is_themed_border_ = true;
+}
+
void LabelButton::StateChanged() {
const gfx::Size previous_image_size(image_->GetPreferredSize());
UpdateImage();
@@ -354,6 +411,9 @@ void LabelButton::ChildPreferredSizeChanged(View* child) {
void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
ResetColorsFromNativeTheme();
+ UpdateThemedBorder();
+ // Invalidate the layout to pickup the new insets from the border.
+ InvalidateLayout();
}
ui::NativeTheme::Part LabelButton::GetThemePart() const {
@@ -378,13 +438,6 @@ ui::NativeTheme::State LabelButton::GetThemeState(
}
const gfx::Animation* LabelButton::GetThemeAnimation() const {
-#if defined(OS_WIN)
- if (style() == STYLE_NATIVE_TEXTBUTTON &&
- GetNativeTheme() == ui::NativeThemeWin::instance()) {
- return ui::NativeThemeWin::instance()->IsThemingActive() ?
- hover_animation_.get() : NULL;
- }
-#endif
return hover_animation_.get();
}
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index ad7e226ad5e..80beb3c90d5 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -8,7 +8,6 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/image_view.h"
@@ -17,6 +16,7 @@
namespace views {
+class LabelButtonBorder;
class Painter;
// LabelButton is an alternative to TextButton, it's not focusable by default.
@@ -28,7 +28,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
static const char kViewClassName[];
- LabelButton(ButtonListener* listener, const string16& text);
+ LabelButton(ButtonListener* listener, const base::string16& text);
virtual ~LabelButton();
// Get or set the image shown for the specified button state.
@@ -37,28 +37,37 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
void SetImage(ButtonState for_state, const gfx::ImageSkia& image);
// Get or set the text shown on the button.
- const string16& GetText() const;
- void SetText(const string16& text);
+ const base::string16& GetText() const;
+ virtual void SetText(const base::string16& text);
// Set the text color shown for the specified button state.
void SetTextColor(ButtonState for_state, SkColor color);
+ // Set drop shadows underneath the text.
+ void SetTextShadows(const gfx::ShadowValues& shadows);
+
+ // Sets whether subpixel rendering is used on the label.
+ void SetTextSubpixelRenderingEnabled(bool enabled);
+
// Get or set the text's multi-line property to break on '\n', etc.
bool GetTextMultiLine() const;
void SetTextMultiLine(bool text_multi_line);
- // Get or set the font used by this button.
- const gfx::Font& GetFont() const;
- void SetFont(const gfx::Font& font);
+ // Get or set the font list used by this button.
+ const gfx::FontList& GetFontList() const;
+ void SetFontList(const gfx::FontList& font_list);
// Set the elide behavior of this button.
- void SetElideBehavior(Label::ElideBehavior elide_behavior);
+ void SetElideBehavior(gfx::ElideBehavior elide_behavior);
// Get or set the horizontal alignment used for the button; reversed in RTL.
// The optional image will lead the text, unless the button is right-aligned.
gfx::HorizontalAlignment GetHorizontalAlignment() const;
void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
+ // Set the directionality mode used for the button text.
+ void SetDirectionalityMode(gfx::DirectionalityMode mode);
+
// Call set_min_size(gfx::Size()) to clear the monotonically increasing size.
void set_min_size(const gfx::Size& min_size) { min_size_ = min_size; }
void set_max_size(const gfx::Size& max_size) { max_size_ = max_size; }
@@ -72,9 +81,11 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
void SetStyle(ButtonStyle style);
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
+ Painter* focus_painter() { return focus_painter_.get(); }
// View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void SetBorder(scoped_ptr<Border> border) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
@@ -82,10 +93,15 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
ImageView* image() const { return image_; }
Label* label() const { return label_; }
+ // Returns the available area for the label and image. Subclasses can change
+ // these bounds if they need room to do manual painting.
+ virtual gfx::Rect GetChildAreaBounds();
+
// View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// Fill |params| with information about the button.
virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const;
@@ -93,9 +109,17 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// Resets colors from the NativeTheme, explicitly set colors are unchanged.
virtual void ResetColorsFromNativeTheme();
+ // Creates the default border for this button. This can be overridden by
+ // subclasses or by LinuxUI.
+ virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const;
+
// Updates the image view to contain the appropriate button state image.
void UpdateImage();
+ // Updates the border as per the NativeTheme, unless a different border was
+ // set with SetBorder.
+ void UpdateThemedBorder();
+
// NativeThemeDelegate:
virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
@@ -104,14 +128,13 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Label);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Image);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, LabelAndImage);
- FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Font);
+ FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, FontList);
// CustomButton:
virtual void StateChanged() OVERRIDE;
// View:
virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
- virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// NativeThemeDelegate:
virtual ui::NativeTheme::Part GetThemePart() const OVERRIDE;
@@ -127,6 +150,10 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
ImageView* image_;
Label* label_;
+ // The cached font lists in the normal and bold style.
+ gfx::FontList cached_normal_font_list_;
+ gfx::FontList cached_bold_font_list_;
+
// The images and colors for each button state.
gfx::ImageSkia button_state_images_[STATE_COUNT];
SkColor button_state_colors_[STATE_COUNT];
@@ -135,7 +162,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
bool explicitly_set_colors_[STATE_COUNT];
// |min_size_| increases monotonically with the preferred size.
- gfx::Size min_size_;
+ mutable gfx::Size min_size_;
// |max_size_| may be set to clamp the preferred size.
gfx::Size max_size_;
@@ -147,6 +174,9 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// The button's overall style.
ButtonStyle style_;
+ // True if current border was set by UpdateThemedBorder. Defaults to true.
+ bool border_is_themed_border_;
+
scoped_ptr<Painter> focus_painter_;
DISALLOW_COPY_AND_ASSIGN(LabelButton);
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index d124764fd76..23e9319ded3 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -31,36 +31,20 @@ const int kButtonInsets = 5;
const int kTextHoveredImages[] = IMAGE_GRID(IDR_TEXTBUTTON_HOVER);
const int kTextPressedImages[] = IMAGE_GRID(IDR_TEXTBUTTON_PRESSED);
-Button::ButtonState GetButtonState(ui::NativeTheme::State state) {
- switch (state) {
- case ui::NativeTheme::kDisabled: return Button::STATE_DISABLED;
- case ui::NativeTheme::kHovered: return Button::STATE_HOVERED;
- case ui::NativeTheme::kNormal: return Button::STATE_NORMAL;
- case ui::NativeTheme::kPressed: return Button::STATE_PRESSED;
- case ui::NativeTheme::kMaxState: NOTREACHED() << "Unknown state: " << state;
- }
- return Button::STATE_NORMAL;
-}
-
-// A helper function to paint the native theme or images as appropriate.
+// A helper function to paint the appropriate broder images.
void PaintHelper(LabelButtonBorder* border,
gfx::Canvas* canvas,
- const ui::NativeTheme* theme,
- ui::NativeTheme::Part part,
ui::NativeTheme::State state,
const gfx::Rect& rect,
const ui::NativeTheme::ExtraParams& extra) {
- if (border->style() == Button::STYLE_NATIVE_TEXTBUTTON) {
- theme->Paint(canvas->sk_canvas(), part, state, rect, extra);
- } else {
- Painter* painter =
- border->GetPainter(extra.button.is_focused, GetButtonState(state));
- // Paint any corresponding unfocused painter if there is no focused painter.
- if (!painter && extra.button.is_focused)
- painter = border->GetPainter(false, GetButtonState(state));
- if (painter)
- Painter::PaintPainterAt(canvas, painter, rect);
- }
+ Painter* painter =
+ border->GetPainter(extra.button.is_focused,
+ Button::GetButtonStateFrom(state));
+ // Paint any corresponding unfocused painter if there is no focused painter.
+ if (!painter && extra.button.is_focused)
+ painter = border->GetPainter(false, Button::GetButtonStateFrom(state));
+ if (painter)
+ Painter::PaintPainterAt(canvas, painter, rect);
}
} // namespace
@@ -105,8 +89,6 @@ LabelButtonBorder::LabelButtonBorder(Button::ButtonStyle style)
Painter::CreateImageGridPainter(kTextHoveredImages));
SetPainter(false, Button::STATE_PRESSED,
Painter::CreateImageGridPainter(kTextPressedImages));
- } else if (style == Button::STYLE_NATIVE_TEXTBUTTON) {
- set_insets(gfx::Insets(5, 12, 5, 12));
}
}
@@ -115,10 +97,8 @@ LabelButtonBorder::~LabelButtonBorder() {}
void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
const NativeThemeDelegate* native_theme_delegate =
static_cast<const LabelButton*>(&view);
- ui::NativeTheme::Part part = native_theme_delegate->GetThemePart();
gfx::Rect rect(native_theme_delegate->GetThemePaintRect());
ui::NativeTheme::ExtraParams extra;
- const ui::NativeTheme* theme = view.GetNativeTheme();
const gfx::Animation* animation = native_theme_delegate->GetThemeAnimation();
ui::NativeTheme::State state = native_theme_delegate->GetThemeState(&extra);
@@ -127,7 +107,7 @@ void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
const SkRect sk_rect = gfx::RectToSkRect(rect);
canvas->sk_canvas()->saveLayer(&sk_rect, NULL);
state = native_theme_delegate->GetBackgroundThemeState(&extra);
- PaintHelper(this, canvas, theme, part, state, rect, extra);
+ PaintHelper(this, canvas, state, rect, extra);
SkPaint paint;
skia::RefPtr<SkXfermode> sk_lerp_xfer =
@@ -135,18 +115,12 @@ void LabelButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
paint.setXfermode(sk_lerp_xfer.get());
canvas->sk_canvas()->saveLayer(&sk_rect, &paint);
state = native_theme_delegate->GetForegroundThemeState(&extra);
- PaintHelper(this, canvas, theme, part, state, rect, extra);
+ PaintHelper(this, canvas, state, rect, extra);
canvas->sk_canvas()->restore();
canvas->sk_canvas()->restore();
} else {
- PaintHelper(this, canvas, theme, part, state, rect, extra);
- }
-
- // For inverted color schemes, draw a solid fill with the button color.
- if (gfx::IsInvertedColorScheme()) {
- rect.Inset(insets_);
- canvas->FillRect(rect, extra.button.background_color);
+ PaintHelper(this, canvas, state, rect, extra);
}
}
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index fe2d1f670c1..74f77b702e6 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_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/views/controls/button/label_button.h"
+
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/size.h"
-#include "ui/views/controls/button/label_button.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace {
gfx::ImageSkia CreateTestImage(int width, int height) {
@@ -26,7 +30,7 @@ namespace views {
typedef ViewsTestBase LabelButtonTest;
TEST_F(LabelButtonTest, Init) {
- const string16 text(ASCIIToUTF16("abc"));
+ const base::string16 text(ASCIIToUTF16("abc"));
LabelButton button(NULL, text);
EXPECT_TRUE(button.GetImage(Button::STATE_NORMAL).isNull());
@@ -45,19 +49,19 @@ TEST_F(LabelButtonTest, Init) {
}
TEST_F(LabelButtonTest, Label) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
EXPECT_TRUE(button.GetText().empty());
- const gfx::Font font;
- const string16 short_text(ASCIIToUTF16("abcdefghijklm"));
- const string16 long_text(ASCIIToUTF16("abcdefghijklmnopqrstuvwxyz"));
- const int short_text_width = gfx::Canvas::GetStringWidth(short_text, font);
- const int long_text_width = gfx::Canvas::GetStringWidth(long_text, font);
+ const gfx::FontList font_list;
+ const base::string16 short_text(ASCIIToUTF16("abcdefghijklm"));
+ const base::string16 long_text(ASCIIToUTF16("abcdefghijklmnopqrstuvwxyz"));
+ const int short_text_width = gfx::GetStringWidth(short_text, font_list);
+ const int long_text_width = gfx::GetStringWidth(long_text, font_list);
// The width increases monotonically with string size (it does not shrink).
EXPECT_LT(button.GetPreferredSize().width(), short_text_width);
button.SetText(short_text);
- EXPECT_GT(button.GetPreferredSize().height(), font.GetHeight());
+ EXPECT_GT(button.GetPreferredSize().height(), font_list.GetHeight());
EXPECT_GT(button.GetPreferredSize().width(), short_text_width);
EXPECT_LT(button.GetPreferredSize().width(), long_text_width);
button.SetText(long_text);
@@ -76,7 +80,7 @@ TEST_F(LabelButtonTest, Label) {
}
TEST_F(LabelButtonTest, Image) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
const int small_size = 50, large_size = 100;
const gfx::ImageSkia small_image = CreateTestImage(small_size, small_size);
@@ -108,15 +112,15 @@ TEST_F(LabelButtonTest, Image) {
}
TEST_F(LabelButtonTest, LabelAndImage) {
- LabelButton button(NULL, string16());
+ LabelButton button(NULL, base::string16());
- const gfx::Font font;
- const string16 text(ASCIIToUTF16("abcdefghijklm"));
- const int text_width = gfx::Canvas::GetStringWidth(text, font);
+ const gfx::FontList font_list;
+ const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
+ const int text_width = gfx::GetStringWidth(text, font_list);
const int image_size = 50;
const gfx::ImageSkia image = CreateTestImage(image_size, image_size);
- ASSERT_LT(font.GetHeight(), image_size);
+ ASSERT_LT(font_list.GetHeight(), image_size);
// The width increases monotonically with content size (it does not shrink).
EXPECT_LT(button.GetPreferredSize().width(), text_width);
@@ -124,7 +128,7 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_LT(button.GetPreferredSize().height(), image_size);
button.SetText(text);
EXPECT_GT(button.GetPreferredSize().width(), text_width);
- EXPECT_GT(button.GetPreferredSize().height(), font.GetHeight());
+ EXPECT_GT(button.GetPreferredSize().height(), font_list.GetHeight());
EXPECT_LT(button.GetPreferredSize().width(), text_width + image_size);
EXPECT_LT(button.GetPreferredSize().height(), image_size);
button.SetImage(Button::STATE_NORMAL, image);
@@ -146,7 +150,7 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_EQ(gfx::ALIGN_RIGHT, button.GetHorizontalAlignment());
EXPECT_LT(button.label_->bounds().right(), button.image_->bounds().x());
- button.SetText(string16());
+ button.SetText(base::string16());
EXPECT_GT(button.GetPreferredSize().width(), text_width + image_size);
EXPECT_GT(button.GetPreferredSize().height(), image_size);
button.SetImage(Button::STATE_NORMAL, gfx::ImageSkia());
@@ -164,24 +168,25 @@ TEST_F(LabelButtonTest, LabelAndImage) {
EXPECT_LT(button.GetPreferredSize().height(), image_size);
}
-TEST_F(LabelButtonTest, Font) {
- const string16 text(ASCIIToUTF16("abc"));
+TEST_F(LabelButtonTest, FontList) {
+ const base::string16 text(ASCIIToUTF16("abc"));
LabelButton button(NULL, text);
- const gfx::Font original_font = button.GetFont();
- const gfx::Font large_font = original_font.DeriveFont(100);
+ const gfx::FontList original_font_list = button.GetFontList();
+ const gfx::FontList large_font_list =
+ original_font_list.DeriveWithSizeDelta(100);
const int original_width = button.GetPreferredSize().width();
const int original_height = button.GetPreferredSize().height();
// The button size increases when the font size is increased.
- button.SetFont(large_font);
+ button.SetFontList(large_font_list);
EXPECT_GT(button.GetPreferredSize().width(), original_width);
EXPECT_GT(button.GetPreferredSize().height(), original_height);
// The button returns to its original size when the minimal size is cleared
// and the original font size is restored.
button.set_min_size(gfx::Size());
- button.SetFont(original_font);
+ button.SetFontList(original_font_list);
EXPECT_EQ(original_width, button.GetPreferredSize().width());
EXPECT_EQ(original_height, button.GetPreferredSize().height());
}
diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc
index 728c0371f1c..29271cea51f 100644
--- a/chromium/ui/views/controls/button/menu_button.cc
+++ b/chromium/ui/views/controls/button/menu_button.cc
@@ -7,7 +7,7 @@
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
@@ -16,6 +16,7 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/text_constants.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button_listener.h"
#include "ui/views/mouse_constants.h"
@@ -43,10 +44,10 @@ const int MenuButton::kMenuMarkerPaddingRight = -1;
////////////////////////////////////////////////////////////////////////////////
MenuButton::MenuButton(ButtonListener* listener,
- const string16& text,
+ const base::string16& text,
MenuButtonListener* menu_button_listener,
bool show_menu_marker)
- : TextButton(listener, text),
+ : LabelButton(listener, text),
menu_visible_(false),
menu_offset_(kDefaultMenuOffsetX, kDefaultMenuOffsetY),
listener_(menu_button_listener),
@@ -54,7 +55,7 @@ MenuButton::MenuButton(ButtonListener* listener,
menu_marker_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_MENU_DROPARROW).ToImageSkia()),
destroyed_flag_(NULL) {
- set_alignment(TextButton::ALIGN_LEFT);
+ SetHorizontalAlignment(gfx::ALIGN_LEFT);
}
MenuButton::~MenuButton() {
@@ -133,8 +134,8 @@ bool MenuButton::Activate() {
return true;
}
-void MenuButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
- TextButton::PaintButton(canvas, mode);
+void MenuButton::OnPaint(gfx::Canvas* canvas) {
+ LabelButton::OnPaint(canvas);
if (show_menu_marker_)
PaintMenuMarker(canvas);
@@ -146,8 +147,8 @@ void MenuButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
//
////////////////////////////////////////////////////////////////////////////////
-gfx::Size MenuButton::GetPreferredSize() {
- gfx::Size prefsize = TextButton::GetPreferredSize();
+gfx::Size MenuButton::GetPreferredSize() const {
+ gfx::Size prefsize = LabelButton::GetPreferredSize();
if (show_menu_marker_) {
prefsize.Enlarge(menu_marker_->width() + kMenuMarkerPaddingLeft +
kMenuMarkerPaddingRight,
@@ -186,7 +187,7 @@ void MenuButton::OnMouseReleased(const ui::MouseEvent& event) {
HitTestPoint(event.location())) {
Activate();
} else {
- TextButton::OnMouseReleased(event);
+ LabelButton::OnMouseReleased(event);
}
}
@@ -202,12 +203,14 @@ void MenuButton::OnMouseExited(const ui::MouseEvent& event) {
}
void MenuButton::OnGestureEvent(ui::GestureEvent* event) {
- if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP) {
- if (Activate())
- event->StopPropagation();
+ if (state() != STATE_DISABLED && event->type() == ui::ET_GESTURE_TAP &&
+ !Activate()) {
+ // When |Activate()| returns |false|, it means that a menu is shown and
+ // has handled the gesture event. So, there is no need to further process
+ // the gesture event here.
return;
}
- TextButton::OnGestureEvent(event);
+ LabelButton::OnGestureEvent(event);
}
bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) {
@@ -220,16 +223,12 @@ bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) {
case ui::VKEY_UP:
case ui::VKEY_DOWN: {
// WARNING: we may have been deleted by the time Activate returns.
- bool ret = Activate();
-#if defined(USE_AURA)
- // This is to prevent the keyboard event from being dispatched twice.
- // The Activate function returns false in most cases. In AURA if the
- // keyboard event is not handled, we pass it to the default handler
- // which dispatches the event back to us causing the menu to get
- // displayed again.
- ret = true;
-#endif
- return ret;
+ Activate();
+ // This is to prevent the keyboard event from being dispatched twice. If
+ // the keyboard event is not handled, we pass it to the default handler
+ // which dispatches the event back to us causing the menu to get displayed
+ // again. Return true to prevent this.
+ return true;
}
default:
break;
@@ -244,11 +243,11 @@ bool MenuButton::OnKeyReleased(const ui::KeyEvent& event) {
return false;
}
-void MenuButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void MenuButton::GetAccessibleState(ui::AXViewState* state) {
CustomButton::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_BUTTONMENU;
+ state->role = ui::AX_ROLE_POP_UP_BUTTON;
state->default_action = l10n_util::GetStringUTF16(IDS_APP_ACCACTION_PRESS);
- state->state = ui::AccessibilityTypes::STATE_HASPOPUP;
+ state->AddStateFlag(ui::AX_STATE_HASPOPUP);
}
void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) {
@@ -267,6 +266,17 @@ void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) {
canvas->DrawImageInt(*menu_marker_, arrow_bounds.x(), arrow_bounds.y());
}
+gfx::Rect MenuButton::GetChildAreaBounds() {
+ gfx::Size s = size();
+
+ if (show_menu_marker_) {
+ s.set_width(s.width() - menu_marker_->width() - kMenuMarkerPaddingLeft -
+ kMenuMarkerPaddingRight);
+ }
+
+ return gfx::Rect(s);
+}
+
int MenuButton::GetMaximumScreenXCoordinate() {
if (!GetWidget()) {
NOTREACHED();
diff --git a/chromium/ui/views/controls/button/menu_button.h b/chromium/ui/views/controls/button/menu_button.h
index 2262dab4637..257d2f62ea9 100644
--- a/chromium/ui/views/controls/button/menu_button.h
+++ b/chromium/ui/views/controls/button/menu_button.h
@@ -9,9 +9,8 @@
#include "base/strings/string16.h"
#include "base/time/time.h"
-#include "ui/gfx/font.h"
#include "ui/views/background.h"
-#include "ui/views/controls/button/text_button.h"
+#include "ui/views/controls/button/label_button.h"
namespace views {
@@ -24,7 +23,7 @@ class MenuButtonListener;
// A button that shows a menu when the left mouse button is pushed
//
////////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT MenuButton : public TextButton {
+class VIEWS_EXPORT MenuButton : public LabelButton {
public:
static const char kViewClassName[];
@@ -34,7 +33,7 @@ class VIEWS_EXPORT MenuButton : public TextButton {
// Create a Button.
MenuButton(ButtonListener* listener,
- const string16& text,
+ const base::string16& text,
MenuButtonListener* menu_button_listener,
bool show_menu_marker);
virtual ~MenuButton();
@@ -51,24 +50,25 @@ class VIEWS_EXPORT MenuButton : public TextButton {
// Activate the button (called when the button is pressed).
virtual bool Activate();
- // Overridden from TextButton for the potential use of a drop marker.
- virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
-
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// Paint the menu marker image.
void PaintMenuMarker(gfx::Canvas* canvas);
+ // Overridden from LabelButton:
+ virtual gfx::Rect GetChildAreaBounds() OVERRIDE;
+
// True if the menu is currently visible.
bool menu_visible_;
diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc
new file mode 100644
index 00000000000..6a18b21b104
--- /dev/null
+++ b/chromium/ui/views/controls/button/menu_button_unittest.cc
@@ -0,0 +1,199 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/button/menu_button.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/button/menu_button_listener.h"
+#include "ui/views/test/views_test_base.h"
+
+using base::ASCIIToUTF16;
+
+namespace views {
+
+class MenuButtonTest : public ViewsTestBase {
+ public:
+ MenuButtonTest() : widget_(NULL), button_(NULL) {}
+ virtual ~MenuButtonTest() {}
+
+ virtual void TearDown() OVERRIDE {
+ if (widget_ && !widget_->IsClosed())
+ widget_->Close();
+
+ ViewsTestBase::TearDown();
+ }
+
+ Widget* widget() { return widget_; }
+ MenuButton* button() { return button_; }
+
+ protected:
+ // Creates a MenuButton with a ButtonListener. In this case, the MenuButton
+ // acts like a regular button.
+ void CreateMenuButtonWithButtonListener(ButtonListener* button_listener) {
+ CreateWidget();
+
+ const base::string16 label(ASCIIToUTF16("button"));
+ button_ = new MenuButton(button_listener, label, NULL, false);
+ button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+ widget_->SetContentsView(button_);
+
+ widget_->Show();
+ }
+
+ // Creates a MenuButton with a MenuButtonListener. In this case, when the
+ // MenuButton is pushed, it notifies the MenuButtonListener to open a
+ // drop-down menu.
+ void CreateMenuButtonWithMenuButtonListener(
+ MenuButtonListener* menu_button_listener) {
+ CreateWidget();
+
+ const base::string16 label(ASCIIToUTF16("button"));
+ button_ = new MenuButton(NULL, label, menu_button_listener, false);
+ button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+ widget_->SetContentsView(button_);
+
+ widget_->Show();
+ }
+
+ private:
+ void CreateWidget() {
+ DCHECK(!widget_);
+
+ widget_ = new Widget;
+ Widget::InitParams params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget_->Init(params);
+ }
+
+ Widget* widget_;
+ MenuButton* button_;
+};
+
+class TestButtonListener : public ButtonListener {
+ public:
+ TestButtonListener()
+ : last_sender_(NULL),
+ last_sender_state_(Button::STATE_NORMAL),
+ last_event_type_(ui::ET_UNKNOWN) {}
+ virtual ~TestButtonListener() {}
+
+ virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE {
+ last_sender_ = sender;
+ CustomButton* custom_button = CustomButton::AsCustomButton(sender);
+ DCHECK(custom_button);
+ last_sender_state_ = custom_button->state();
+ last_event_type_ = event.type();
+ }
+
+ Button* last_sender() { return last_sender_; }
+ Button::ButtonState last_sender_state() { return last_sender_state_; }
+ ui::EventType last_event_type() { return last_event_type_; }
+
+ private:
+ Button* last_sender_;
+ Button::ButtonState last_sender_state_;
+ ui::EventType last_event_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestButtonListener);
+};
+
+class TestMenuButtonListener : public MenuButtonListener {
+ public:
+ TestMenuButtonListener() {}
+ virtual ~TestMenuButtonListener() {}
+
+ virtual void OnMenuButtonClicked(View* source,
+ const gfx::Point& /*point*/) OVERRIDE {
+ last_source_ = source;
+ CustomButton* custom_button = CustomButton::AsCustomButton(source);
+ DCHECK(custom_button);
+ last_source_state_ = custom_button->state();
+ }
+
+ View* last_source() { return last_source_; }
+ Button::ButtonState last_source_state() { return last_source_state_; }
+
+ private:
+ View* last_source_;
+ Button::ButtonState last_source_state_;
+};
+
+// Tests if the listener is notified correctly, when a mouse click happens on a
+// MenuButton that has a regular ButtonListener.
+TEST_F(MenuButtonTest, ActivateNonDropDownOnMouseClick) {
+ scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
+ CreateMenuButtonWithButtonListener(button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.set_current_location(gfx::Point(10, 10));
+ generator.ClickLeftButton();
+
+ // Check that MenuButton has notified the listener on mouse-released event,
+ // while it was in hovered state.
+ EXPECT_EQ(button(), button_listener->last_sender());
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, button_listener->last_event_type());
+ EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
+}
+
+// Tests if the listener is notified correctly when a gesture tap happens on a
+// MenuButton that has a regular ButtonListener.
+TEST_F(MenuButtonTest, ActivateNonDropDownOnGestureTap) {
+ scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
+ CreateMenuButtonWithButtonListener(button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.GestureTapAt(gfx::Point(10, 10));
+
+ // Check that MenuButton has notified the listener on gesture tap event, while
+ // it was in hovered state.
+ EXPECT_EQ(button(), button_listener->last_sender());
+ EXPECT_EQ(ui::ET_GESTURE_TAP, button_listener->last_event_type());
+ EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
+}
+
+// Tests if the listener is notified correctly when a mouse click happens on a
+// MenuButton that has a MenuButtonListener.
+TEST_F(MenuButtonTest, ActivateDropDownOnMouseClick) {
+ scoped_ptr<TestMenuButtonListener> menu_button_listener(
+ new TestMenuButtonListener);
+ CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.set_current_location(gfx::Point(10, 10));
+ generator.ClickLeftButton();
+
+ // Check that MenuButton has notified the listener, while it was in pressed
+ // state.
+ EXPECT_EQ(button(), menu_button_listener->last_source());
+ EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
+}
+
+// Tests if the listener is notified correctly when a gesture tap happens on a
+// MenuButton that has a MenuButtonListener.
+TEST_F(MenuButtonTest, ActivateDropDownOnGestureTap) {
+ scoped_ptr<TestMenuButtonListener> menu_button_listener(
+ new TestMenuButtonListener);
+ CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
+
+ aura::test::EventGenerator generator(
+ widget()->GetNativeView()->GetRootWindow());
+
+ generator.GestureTapAt(gfx::Point(10, 10));
+
+ // Check that MenuButton has notified the listener, while it was in pressed
+ // state.
+ EXPECT_EQ(button(), menu_button_listener->last_source());
+ EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index 224e9893873..a015d5e1da8 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/widget/widget.h"
@@ -15,7 +15,7 @@ namespace views {
// static
const char RadioButton::kViewClassName[] = "RadioButton";
-RadioButton::RadioButton(const string16& label, int group_id)
+RadioButton::RadioButton(const base::string16& label, int group_id)
: Checkbox(label) {
SetGroup(group_id);
@@ -94,9 +94,9 @@ const char* RadioButton::GetClassName() const {
return kViewClassName;
}
-void RadioButton::GetAccessibleState(ui::AccessibleViewState* state) {
+void RadioButton::GetAccessibleState(ui::AXViewState* state) {
Checkbox::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_RADIOBUTTON;
+ state->role = ui::AX_ROLE_RADIO_BUTTON;
}
View* RadioButton::GetSelectedViewForGroup(int group) {
@@ -123,7 +123,7 @@ bool RadioButton::IsGroupFocusTraversable() const {
void RadioButton::OnFocus() {
Checkbox::OnFocus();
SetChecked(true);
- ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0, 0);
LabelButton::NotifyClick(event);
}
diff --git a/chromium/ui/views/controls/button/radio_button.h b/chromium/ui/views/controls/button/radio_button.h
index a7afff4ed41..edbb2c694cd 100644
--- a/chromium/ui/views/controls/button/radio_button.h
+++ b/chromium/ui/views/controls/button/radio_button.h
@@ -17,12 +17,12 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// The button's class name.
static const char kViewClassName[];
- RadioButton(const string16& label, int group_id);
+ RadioButton(const base::string16& label, int group_id);
virtual ~RadioButton();
// Overridden from View:
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual View* GetSelectedViewForGroup(int group) OVERRIDE;
virtual bool IsGroupFocusTraversable() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
@@ -30,7 +30,7 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// Overridden from Button:
virtual void NotifyClick(const ui::Event& event) OVERRIDE;
- // Overridden from TextButtonBase:
+ // Overridden from LabelButton:
virtual ui::NativeTheme::Part GetThemePart() const OVERRIDE;
// Overridden from Checkbox:
diff --git a/chromium/ui/views/controls/button/text_button.cc b/chromium/ui/views/controls/button/text_button.cc
index e829405b9f4..bf12f8e086d 100644
--- a/chromium/ui/views/controls/button/text_button.cc
+++ b/chromium/ui/views/controls/button/text_button.cc
@@ -88,14 +88,6 @@ void TextButtonBorder::SetInsets(const gfx::Insets& insets) {
insets_ = insets;
}
-TextButtonBorder* TextButtonBorder::AsTextButtonBorder() {
- return this;
-}
-
-const TextButtonBorder* TextButtonBorder::AsTextButtonBorder() const {
- return this;
-}
-
// TextButtonDefaultBorder ----------------------------------------------------
@@ -199,15 +191,10 @@ void TextButtonNativeThemeBorder::Paint(const View& view, gfx::Canvas* canvas) {
// TextButtonBase -------------------------------------------------------------
-TextButtonBase::TextButtonBase(ButtonListener* listener, const string16& text)
+TextButtonBase::TextButtonBase(ButtonListener* listener,
+ const base::string16& text)
: CustomButton(listener),
alignment_(ALIGN_LEFT),
- font_(ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::BaseFont)),
- has_text_shadow_(false),
- active_text_shadow_color_(0),
- inactive_text_shadow_color_(0),
- text_shadow_offset_(gfx::Point(1, 1)),
min_width_(0),
min_height_(0),
max_width_(0),
@@ -220,8 +207,6 @@ TextButtonBase::TextButtonBase(ButtonListener* listener, const string16& text)
use_hover_color_from_theme_(true),
focus_painter_(Painter::CreateDashedFocusPainter()) {
SetText(text);
- // OnNativeThemeChanged sets the color member variables.
- TextButtonBase::OnNativeThemeChanged(GetNativeTheme());
SetAnimationDuration(kHoverAnimationDurationMs);
}
@@ -239,7 +224,7 @@ void TextButtonBase::SetIsDefault(bool is_default) {
SchedulePaint();
}
-void TextButtonBase::SetText(const string16& text) {
+void TextButtonBase::SetText(const base::string16& text) {
if (text == text_)
return;
text_ = text;
@@ -247,8 +232,8 @@ void TextButtonBase::SetText(const string16& text) {
UpdateTextSize();
}
-void TextButtonBase::SetFont(const gfx::Font& font) {
- font_ = font;
+void TextButtonBase::SetFontList(const gfx::FontList& font_list) {
+ font_list_ = font_list;
UpdateTextSize();
}
@@ -274,21 +259,6 @@ void TextButtonBase::SetHoverColor(SkColor color) {
use_hover_color_from_theme_ = false;
}
-void TextButtonBase::SetTextShadowColors(SkColor active_color,
- SkColor inactive_color) {
- active_text_shadow_color_ = active_color;
- inactive_text_shadow_color_ = inactive_color;
- has_text_shadow_ = true;
-}
-
-void TextButtonBase::SetTextShadowOffset(int x, int y) {
- text_shadow_offset_.SetPoint(x, y);
-}
-
-void TextButtonBase::ClearEmbellishing() {
- has_text_shadow_ = false;
-}
-
void TextButtonBase::ClearMaxTextSize() {
max_text_size_ = text_size_;
}
@@ -306,7 +276,7 @@ void TextButtonBase::SetMultiLine(bool multi_line) {
}
}
-gfx::Size TextButtonBase::GetPreferredSize() {
+gfx::Size TextButtonBase::GetPreferredSize() const {
gfx::Insets insets = GetInsets();
// Use the max size to set the button boundaries.
@@ -326,7 +296,7 @@ gfx::Size TextButtonBase::GetPreferredSize() {
return prefsize;
}
-int TextButtonBase::GetHeightForWidth(int w) {
+int TextButtonBase::GetHeightForWidth(int w) const {
if (!multi_line_)
return View::GetHeightForWidth(w);
@@ -377,17 +347,51 @@ void TextButtonBase::UpdateTextSize() {
}
}
-void TextButtonBase::CalculateTextSize(gfx::Size* text_size, int max_width) {
- int h = font_.GetHeight();
+void TextButtonBase::CalculateTextSize(gfx::Size* text_size,
+ int max_width) const {
+ int h = font_list_.GetHeight();
int w = multi_line_ ? max_width : 0;
int flags = ComputeCanvasStringFlags();
if (!multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
- gfx::Canvas::SizeStringInt(text_, font_, &w, &h, 0, flags);
+ gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, 0, flags);
text_size->SetSize(w, h);
}
+void TextButtonBase::OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode) {
+ gfx::Rect text_bounds(GetTextBounds());
+ if (text_bounds.width() > 0) {
+ // Because the text button can (at times) draw multiple elements on the
+ // canvas, we can not mirror the button by simply flipping the canvas as
+ // doing this will mirror the text itself. Flipping the canvas will also
+ // make the icons look wrong because icons are almost always represented as
+ // direction-insensitive images and such images should never be flipped
+ // horizontally.
+ //
+ // Due to the above, we must perform the flipping manually for RTL UIs.
+ text_bounds.set_x(GetMirroredXForRect(text_bounds));
+
+ SkColor text_color = (show_multiple_icon_states_ &&
+ (state() == STATE_HOVERED || state() == STATE_PRESSED)) ?
+ color_hover_ : color_;
+
+ int draw_string_flags = gfx::Canvas::DefaultCanvasTextAlignment() |
+ ComputeCanvasStringFlags();
+
+ if (mode == PB_FOR_DRAG) {
+ // Disable sub-pixel rendering as background is transparent.
+ draw_string_flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
+ canvas->DrawStringRectWithHalo(text_, font_list_,
+ SK_ColorBLACK, SK_ColorWHITE,
+ text_bounds, draw_string_flags);
+ } else {
+ canvas->DrawStringRectWithFlags(text_, font_list_, text_color,
+ text_bounds, draw_string_flags);
+ }
+ }
+}
+
int TextButtonBase::ComputeCanvasStringFlags() const {
if (!multi_line_)
return 0;
@@ -475,59 +479,10 @@ void TextButtonBase::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
- gfx::Rect text_bounds(GetTextBounds());
- if (text_bounds.width() > 0) {
- // Because the text button can (at times) draw multiple elements on the
- // canvas, we can not mirror the button by simply flipping the canvas as
- // doing this will mirror the text itself. Flipping the canvas will also
- // make the icons look wrong because icons are almost always represented as
- // direction-insensitive images and such images should never be flipped
- // horizontally.
- //
- // Due to the above, we must perform the flipping manually for RTL UIs.
- text_bounds.set_x(GetMirroredXForRect(text_bounds));
-
- SkColor text_color = (show_multiple_icon_states_ &&
- (state() == STATE_HOVERED || state() == STATE_PRESSED)) ?
- color_hover_ : color_;
-
- int draw_string_flags = gfx::Canvas::DefaultCanvasTextAlignment() |
- ComputeCanvasStringFlags();
-
- if (mode == PB_FOR_DRAG) {
- // Disable sub-pixel rendering as background is transparent.
- draw_string_flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
-
-#if defined(OS_WIN)
- // TODO(erg): Either port DrawStringWithHalo to linux or find an
- // alternative here.
- canvas->DrawStringWithHalo(text_, font_, SK_ColorBLACK, SK_ColorWHITE,
- text_bounds.x(), text_bounds.y(), text_bounds.width(),
- text_bounds.height(), draw_string_flags);
-#else
- canvas->DrawStringInt(text_,
- font_,
- text_color,
- text_bounds.x(),
- text_bounds.y(),
- text_bounds.width(),
- text_bounds.height(),
- draw_string_flags);
-#endif
- } else {
- gfx::ShadowValues shadows;
- if (has_text_shadow_) {
- SkColor color = GetWidget()->IsActive() ? active_text_shadow_color_ :
- inactive_text_shadow_color_;
- shadows.push_back(gfx::ShadowValue(text_shadow_offset_, 0, color));
- }
- canvas->DrawStringWithShadows(text_, font_, text_color, text_bounds,
- 0, draw_string_flags, shadows);
- }
- }
+ OnPaintText(canvas, mode);
}
-gfx::Size TextButtonBase::GetMinimumSize() {
+gfx::Size TextButtonBase::GetMinimumSize() const {
return max_text_size_;
}
@@ -609,14 +564,15 @@ ui::NativeTheme::State TextButtonBase::GetForegroundThemeState(
// TextButton -----------------------------------------------------------------
-TextButton::TextButton(ButtonListener* listener, const string16& text)
+TextButton::TextButton(ButtonListener* listener, const base::string16& text)
: TextButtonBase(listener, text),
icon_placement_(ICON_ON_LEFT),
has_hover_icon_(false),
has_pushed_icon_(false),
icon_text_spacing_(kDefaultIconTextSpacing),
- ignore_minimum_size_(true) {
- set_border(new TextButtonDefaultBorder);
+ ignore_minimum_size_(true),
+ full_justification_(false) {
+ SetBorder(scoped_ptr<Border>(new TextButtonDefaultBorder));
SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
gfx::Insets(kFocusRectInset, kFocusRectInset,
kFocusRectInset, kFocusRectInset)));
@@ -642,7 +598,7 @@ void TextButton::SetPushedIcon(const gfx::ImageSkia& icon) {
SchedulePaint();
}
-gfx::Size TextButton::GetPreferredSize() {
+gfx::Size TextButton::GetPreferredSize() const {
gfx::Size prefsize(TextButtonBase::GetPreferredSize());
prefsize.Enlarge(icon_.width(), 0);
prefsize.set_height(std::max(prefsize.height(), icon_.height()));
@@ -657,8 +613,8 @@ gfx::Size TextButton::GetPreferredSize() {
#if defined(OS_WIN)
// Clamp the size returned to at least the minimum size.
if (!ignore_minimum_size_) {
- gfx::PlatformFontWin* platform_font =
- static_cast<gfx::PlatformFontWin*>(font_.platform_font());
+ gfx::PlatformFontWin* platform_font = static_cast<gfx::PlatformFontWin*>(
+ font_list_.GetPrimaryFont().platform_font());
prefsize.set_width(std::max(
prefsize.width(),
platform_font->horizontal_dlus_to_pixels(kMinWidthDLUs)));
@@ -675,22 +631,37 @@ gfx::Size TextButton::GetPreferredSize() {
}
void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
+ if (full_justification_ && icon_placement_ == ICON_ON_LEFT)
+ set_alignment(ALIGN_RIGHT);
+
TextButtonBase::PaintButton(canvas, mode);
+ OnPaintIcon(canvas, mode);
+}
+void TextButton::OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode) {
const gfx::ImageSkia& icon = GetImageToPaint();
if (icon.width() > 0) {
gfx::Rect text_bounds = GetTextBounds();
- int icon_x;
+ int icon_x = 0;
int spacing = text_.empty() ? 0 : icon_text_spacing_;
gfx::Insets insets = GetInsets();
- if (icon_placement_ == ICON_ON_LEFT) {
- icon_x = text_bounds.x() - icon.width() - spacing;
- } else if (icon_placement_ == ICON_ON_RIGHT) {
- icon_x = text_bounds.right() + spacing;
- } else { // ICON_CENTERED
- DCHECK(text_.empty());
- icon_x = (width() - insets.width() - icon.width()) / 2 + insets.left();
+ switch (icon_placement_) {
+ case ICON_ON_LEFT:
+ icon_x = full_justification_ ? insets.left()
+ : text_bounds.x() - icon.width() - spacing;
+ break;
+ case ICON_ON_RIGHT:
+ icon_x = full_justification_ ? width() - insets.right() - icon.width()
+ : text_bounds.right() + spacing;
+ break;
+ case ICON_CENTERED:
+ DCHECK(text_.empty());
+ icon_x = (width() - insets.width() - icon.width()) / 2 + insets.left();
+ break;
+ default:
+ NOTREACHED();
+ break;
}
int available_height = height() - insets.height();
@@ -707,6 +678,10 @@ void TextButton::set_ignore_minimum_size(bool ignore_minimum_size) {
ignore_minimum_size_ = ignore_minimum_size;
}
+void TextButton::set_full_justification(bool full_justification) {
+ full_justification_ = full_justification;
+}
+
const char* TextButton::GetClassName() const {
return kViewClassName;
}
diff --git a/chromium/ui/views/controls/button/text_button.h b/chromium/ui/views/controls/button/text_button.h
index 4dc61577803..49c4f3f8c17 100644
--- a/chromium/ui/views/controls/button/text_button.h
+++ b/chromium/ui/views/controls/button/text_button.h
@@ -11,7 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/custom_button.h"
@@ -35,10 +35,6 @@ class VIEWS_EXPORT TextButtonBorder : public Border {
virtual gfx::Size GetMinimumSize() const OVERRIDE;
private:
- // Border:
- virtual TextButtonBorder* AsTextButtonBorder() OVERRIDE;
- virtual const TextButtonBorder* AsTextButtonBorder() const OVERRIDE;
-
gfx::Insets insets_;
DISALLOW_COPY_AND_ASSIGN(TextButtonBorder);
@@ -112,8 +108,8 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
// Call SetText once per string in your set of possible values at button
// creation time, so that it can contain the largest of them and avoid
// resizing the button when the text changes.
- virtual void SetText(const string16& text);
- const string16& text() const { return text_; }
+ virtual void SetText(const base::string16& text);
+ const base::string16& text() const { return text_; }
enum TextAlignment {
ALIGN_LEFT,
@@ -143,24 +139,14 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
void set_min_width(int min_width) { min_width_ = min_width; }
void set_min_height(int min_height) { min_height_ = min_height; }
void set_max_width(int max_width) { max_width_ = max_width; }
- void SetFont(const gfx::Font& font);
- // Return the font used by this button.
- gfx::Font font() const { return font_; }
+ const gfx::FontList& font_list() const { return font_list_; }
+ void SetFontList(const gfx::FontList& font_list);
void SetEnabledColor(SkColor color);
void SetDisabledColor(SkColor color);
void SetHighlightColor(SkColor color);
void SetHoverColor(SkColor color);
- // Enables a drop shadow underneath the text.
- void SetTextShadowColors(SkColor active_color, SkColor inactive_color);
-
- // Sets the drop shadow's offset from the text.
- void SetTextShadowOffset(int x, int y);
-
- // Disables shadows.
- void ClearEmbellishing();
-
// Sets whether or not to show the hot and pushed states for the button icon
// (if present) in addition to the normal state. Defaults to true.
bool show_multiple_icon_states() const { return show_multiple_icon_states_; }
@@ -175,9 +161,9 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual void OnEnabledChanged() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
@@ -185,18 +171,23 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
protected:
- TextButtonBase(ButtonListener* listener, const string16& text);
+ TextButtonBase(ButtonListener* listener, const base::string16& text);
// Called when enabled or disabled state changes, or the colors for those
// states change.
virtual void UpdateColor();
// Updates text_size_ and max_text_size_ from the current text/font. This is
- // invoked when the font or text changes.
+ // invoked when the font list or text changes.
void UpdateTextSize();
// Calculate the size of the text size without setting any of the members.
- void CalculateTextSize(gfx::Size* text_size, int max_width);
+ void CalculateTextSize(gfx::Size* text_size, int max_width) const;
+
+ // Paint the button's text into the specified canvas. If |mode| is
+ // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
+ // can override this function to change only the text rendering.
+ virtual void OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode);
void set_color_enabled(SkColor color) { color_enabled_ = color; }
void set_color_disabled(SkColor color) { color_disabled_ = color; }
@@ -239,10 +230,10 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
gfx::Rect GetContentBounds(int extra_width) const;
// The text string that is displayed in the button.
- string16 text_;
+ base::string16 text_;
// The size of the text string.
- gfx::Size text_size_;
+ mutable gfx::Size text_size_;
// Track the size of the largest text string seen so far, so that
// changing text_ will not resize the button boundary.
@@ -251,16 +242,8 @@ class VIEWS_EXPORT TextButtonBase : public CustomButton,
// The alignment of the text string within the button.
TextAlignment alignment_;
- // The font used to paint the text.
- gfx::Font font_;
-
- // Flag indicating if a shadow should be drawn behind the text.
- bool has_text_shadow_;
- // Optional shadow text colors for active and inactive widget states.
- SkColor active_text_shadow_color_;
- SkColor inactive_text_shadow_color_;
- // Space between the text and its shadow. Defaults to (1,1).
- gfx::Point text_shadow_offset_;
+ // The font list used to paint the text.
+ gfx::FontList font_list_;
// The dimensions of the button will be at least these values.
int min_width_;
@@ -310,7 +293,7 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
// The button's class name.
static const char kViewClassName[];
- TextButton(ButtonListener* listener, const string16& text);
+ TextButton(ButtonListener* listener, const base::string16& text);
virtual ~TextButton();
void set_icon_text_spacing(int icon_text_spacing) {
@@ -340,14 +323,21 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
void set_ignore_minimum_size(bool ignore_minimum_size);
+ void set_full_justification(bool full_justification);
+
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// Overridden from TextButtonBase:
virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
protected:
+ // Paint the button's icon into the specified canvas. If |mode| is
+ // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
+ // can override this function to change only the icon rendering.
+ virtual void OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode);
+
gfx::ImageSkia icon() const { return icon_; }
virtual const gfx::ImageSkia& GetImageToPaint() const;
@@ -382,6 +372,10 @@ class VIEWS_EXPORT TextButton : public TextButtonBase {
// is true. Set to false to prevent narrower buttons.
bool ignore_minimum_size_;
+ // True if the icon and the text are aligned along both the left and right
+ // margins of the button.
+ bool full_justification_;
+
DISALLOW_COPY_AND_ASSIGN(TextButton);
};
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index 7feb5ffd0a7..b2a456d4906 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -4,10 +4,12 @@
#include "ui/views/controls/combobox/combobox.h"
+#include "base/bind.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
@@ -16,6 +18,8 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/text_utils.h"
+#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/color_constants.h"
@@ -23,6 +27,7 @@
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/focusable_border.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/menu_runner_handler.h"
#include "ui/views/controls/menu/submenu_view.h"
@@ -53,8 +58,6 @@ const int kDisclosureArrowButtonRightPadding = 12;
// Define the id of the first item in the menu (since it needs to be > 0)
const int kFirstMenuItemId = 1000;
-const SkColor kInvalidTextColor = SK_ColorWHITE;
-
// Used to indicate that no item is currently selected by the user.
const int kNoSelection = -1;
@@ -81,24 +84,6 @@ const int kFocusedPressedMenuButtonImages[] =
#undef MENU_IMAGE_GRID
-// The background to use for invalid comboboxes.
-class InvalidBackground : public Background {
- public:
- InvalidBackground() {}
- virtual ~InvalidBackground() {}
-
- // Overridden from Background:
- virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE {
- gfx::Rect bounds(view->GetLocalBounds());
- // Inset by 2 to leave 1 empty pixel between background and border.
- bounds.Inset(2, 2, 2, 2);
- canvas->FillRect(bounds, kWarningColor);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InvalidBackground);
-};
-
// The transparent button which holds a button state but is not rendered.
class TransparentButton : public CustomButton {
public:
@@ -108,6 +93,11 @@ class TransparentButton : public CustomButton {
}
virtual ~TransparentButton() {}
+ virtual bool OnMousePressed(const ui::MouseEvent& mouse_event) OVERRIDE {
+ parent()->RequestFocus();
+ return true;
+ }
+
double GetAnimationValue() const {
return hover_animation_->GetCurrentValue();
}
@@ -238,15 +228,14 @@ const char Combobox::kViewClassName[] = "views/Combobox";
Combobox::Combobox(ui::ComboboxModel* model)
: model_(model),
- style_(STYLE_SHOW_DROP_DOWN_ON_CLICK),
+ style_(STYLE_NORMAL),
listener_(NULL),
selected_index_(model_->GetDefaultIndex()),
invalid_(false),
- disclosure_arrow_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
- IDR_MENU_DROPARROW).ToImageSkia()),
dropdown_open_(false),
text_button_(new TransparentButton(this)),
- arrow_button_(new TransparentButton(this)) {
+ arrow_button_(new TransparentButton(this)),
+ weak_ptr_factory_(this) {
model_->AddObserver(this);
UpdateFromModel();
SetFocusable(true);
@@ -285,9 +274,9 @@ Combobox::~Combobox() {
}
// static
-const gfx::Font& Combobox::GetFont() {
+const gfx::FontList& Combobox::GetFontList() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- return rb.GetFont(ui::ResourceBundle::BaseFont);
+ return rb.GetFontList(ui::ResourceBundle::BaseFont);
}
void Combobox::SetStyle(Style style) {
@@ -295,8 +284,11 @@ void Combobox::SetStyle(Style style) {
return;
style_ = style;
+ if (style_ == STYLE_ACTION)
+ selected_index_ = 0;
UpdateBorder();
+ UpdateFromModel();
PreferredSizeChanged();
}
@@ -307,11 +299,17 @@ void Combobox::ModelChanged() {
}
void Combobox::SetSelectedIndex(int index) {
+ if (style_ == STYLE_ACTION)
+ return;
+
selected_index_ = index;
SchedulePaint();
}
bool Combobox::SelectValue(const base::string16& value) {
+ if (style_ == STYLE_ACTION)
+ return false;
+
for (int i = 0; i < model()->GetItemCount(); ++i) {
if (value == model()->GetItemAt(i)) {
SetSelectedIndex(i);
@@ -321,7 +319,7 @@ bool Combobox::SelectValue(const base::string16& value) {
return false;
}
-void Combobox::SetAccessibleName(const string16& name) {
+void Combobox::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
@@ -331,7 +329,6 @@ void Combobox::SetInvalid(bool invalid) {
invalid_ = invalid;
- set_background(invalid_ ? new InvalidBackground() : NULL);
UpdateBorder();
SchedulePaint();
}
@@ -350,13 +347,14 @@ void Combobox::Layout() {
int arrow_button_width = 0;
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK: {
+ case STYLE_NORMAL: {
arrow_button_width = width();
break;
}
- case STYLE_NOTIFY_ON_CLICK: {
+ case STYLE_ACTION: {
arrow_button_width = GetDisclosureArrowLeftPadding() +
- disclosure_arrow_->width() + GetDisclosureArrowRightPadding();
+ ArrowSize().width() +
+ GetDisclosureArrowRightPadding();
text_button_width = width() - arrow_button_width;
break;
}
@@ -377,10 +375,10 @@ bool Combobox::IsCommandEnabled(int id) const {
void Combobox::ExecuteCommand(int id) {
selected_index_ = MenuCommandToIndex(id);
- OnSelectionChanged();
+ OnPerformAction();
}
-bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) {
+bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) const {
return false;
}
@@ -393,26 +391,27 @@ int Combobox::GetSelectedRow() {
}
void Combobox::SetSelectedRow(int row) {
+ int prev_index = selected_index_;
SetSelectedIndex(row);
+ if (selected_index_ != prev_index)
+ OnPerformAction();
}
-string16 Combobox::GetTextForRow(int row) {
- return model()->IsItemSeparatorAt(row) ? string16() : model()->GetItemAt(row);
+base::string16 Combobox::GetTextForRow(int row) {
+ return model()->IsItemSeparatorAt(row) ? base::string16() :
+ model()->GetItemAt(row);
}
////////////////////////////////////////////////////////////////////////////////
// Combobox, View overrides:
-gfx::Size Combobox::GetPreferredSize() {
- if (content_size_.IsEmpty())
- UpdateFromModel();
-
+gfx::Size Combobox::GetPreferredSize() const {
// The preferred size will drive the local bounds which in turn is used to set
// the minimum width for the dropdown list.
gfx::Insets insets = GetInsets();
int total_width = std::max(kMinComboboxWidth, content_size_.width()) +
insets.width() + GetDisclosureArrowLeftPadding() +
- disclosure_arrow_->width() + GetDisclosureArrowRightPadding();
+ ArrowSize().width() + GetDisclosureArrowRightPadding();
return gfx::Size(total_width, content_size_.height() + insets.height());
}
@@ -475,7 +474,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
// Click the button only when the button style mode.
case ui::VKEY_SPACE:
- if (style_ == STYLE_NOTIFY_ON_CLICK) {
+ if (style_ == STYLE_ACTION) {
// When pressing space, the click event will be raised after the key is
// released.
text_button_->SetState(Button::STATE_PRESSED);
@@ -486,9 +485,9 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
// Click the button only when the button style mode.
case ui::VKEY_RETURN:
- if (style_ != STYLE_NOTIFY_ON_CLICK)
+ if (style_ != STYLE_ACTION)
return false;
- HandleClickEvent();
+ OnPerformAction();
break;
default:
@@ -498,34 +497,35 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
if (show_menu) {
UpdateFromModel();
ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD);
- } else if (new_index != selected_index_ && new_index != kNoSelection) {
+ } else if (new_index != selected_index_ && new_index != kNoSelection &&
+ style_ != STYLE_ACTION) {
DCHECK(!model()->IsItemSeparatorAt(new_index));
selected_index_ = new_index;
- OnSelectionChanged();
+ OnPerformAction();
}
return true;
}
bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
- if (style_ != STYLE_NOTIFY_ON_CLICK)
+ if (style_ != STYLE_ACTION)
return false; // crbug.com/127520
- if (e.key_code() == ui::VKEY_SPACE)
- HandleClickEvent();
+ if (e.key_code() == ui::VKEY_SPACE && style_ == STYLE_ACTION)
+ OnPerformAction();
return false;
}
void Combobox::OnPaint(gfx::Canvas* canvas) {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK: {
+ case STYLE_NORMAL: {
OnPaintBackground(canvas);
PaintText(canvas);
OnPaintBorder(canvas);
break;
}
- case STYLE_NOTIFY_ON_CLICK: {
+ case STYLE_ACTION: {
PaintButtons(canvas);
PaintText(canvas);
break;
@@ -548,23 +548,27 @@ void Combobox::OnBlur() {
SchedulePaint();
}
-void Combobox::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_COMBOBOX;
+void Combobox::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_COMBO_BOX;
state->name = accessible_name_;
state->value = model_->GetItemAt(selected_index_);
state->index = selected_index_;
state->count = model_->GetItemCount();
}
-void Combobox::OnModelChanged() {
+void Combobox::OnComboboxModelChanged(ui::ComboboxModel* model) {
+ DCHECK_EQ(model, model_);
ModelChanged();
}
void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
+ if (!enabled())
+ return;
+
RequestFocus();
if (sender == text_button_) {
- HandleClickEvent();
+ OnPerformAction();
} else {
DCHECK_EQ(arrow_button_, sender);
// TODO(hajimehoshi): Fix the problem that the arrow button blinks when
@@ -583,40 +587,50 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
}
void Combobox::UpdateFromModel() {
- int max_width = 0;
- const gfx::Font& font = Combobox::GetFont();
+ const gfx::FontList& font_list = Combobox::GetFontList();
MenuItemView* menu = new MenuItemView(this);
// MenuRunner owns |menu|.
dropdown_list_menu_runner_.reset(new MenuRunner(menu));
int num_items = model()->GetItemCount();
+ int width = 0;
+ bool text_item_appended = false;
for (int i = 0; i < num_items; ++i) {
+ // When STYLE_ACTION is used, the first item and the following separators
+ // are not added to the dropdown menu. It is assumed that the first item is
+ // always selected and rendered on the top of the action button.
if (model()->IsItemSeparatorAt(i)) {
- menu->AppendSeparator();
+ if (text_item_appended || style_ != STYLE_ACTION)
+ menu->AppendSeparator();
continue;
}
- string16 text = model()->GetItemAt(i);
+ base::string16 text = model()->GetItemAt(i);
// Inserting the Unicode formatting characters if necessary so that the
// text is displayed correctly in right-to-left UIs.
base::i18n::AdjustStringForLocaleDirection(&text);
- menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
- max_width = std::max(max_width, font.GetStringWidth(text));
+ if (style_ != STYLE_ACTION || i > 0) {
+ menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
+ text_item_appended = true;
+ }
+
+ if (style_ != STYLE_ACTION || i == selected_index_)
+ width = std::max(width, gfx::GetStringWidth(text, font_list));
}
- content_size_.SetSize(max_width, font.GetHeight());
+ content_size_.SetSize(width, font_list.GetHeight());
}
void Combobox::UpdateBorder() {
- FocusableBorder* border = new FocusableBorder();
- if (style_ == STYLE_NOTIFY_ON_CLICK)
+ scoped_ptr<FocusableBorder> border(new FocusableBorder());
+ if (style_ == STYLE_ACTION)
border->SetInsets(8, 13, 8, 13);
if (invalid_)
border->SetColor(kWarningColor);
- set_border(border);
+ SetBorder(border.PassAs<Border>());
}
void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const {
@@ -632,45 +646,52 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
int x = insets.left();
int y = insets.top();
int text_height = height() - insets.height();
- SkColor text_color = invalid() ? kInvalidTextColor :
- GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_LabelEnabledColor);
+ SkColor text_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_LabelEnabledColor);
DCHECK_GE(selected_index_, 0);
DCHECK_LT(selected_index_, model()->GetItemCount());
if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
selected_index_ = 0;
- string16 text = model()->GetItemAt(selected_index_);
+ base::string16 text = model()->GetItemAt(selected_index_);
- int disclosure_arrow_offset = width() - disclosure_arrow_->width() -
+ gfx::Size arrow_size = ArrowSize();
+ int disclosure_arrow_offset = width() - arrow_size.width() -
GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding();
- const gfx::Font& font = Combobox::GetFont();
- int text_width = font.GetStringWidth(text);
+ const gfx::FontList& font_list = Combobox::GetFontList();
+ int text_width = gfx::GetStringWidth(text, font_list);
if ((text_width + insets.width()) > disclosure_arrow_offset)
text_width = disclosure_arrow_offset - insets.width();
gfx::Rect text_bounds(x, y, text_width, text_height);
AdjustBoundsForRTLUI(&text_bounds);
- canvas->DrawStringInt(text, font, text_color, text_bounds);
+ canvas->DrawStringRect(text, font_list, text_color, text_bounds);
int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding();
gfx::Rect arrow_bounds(arrow_x,
- height() / 2 - disclosure_arrow_->height() / 2,
- disclosure_arrow_->width(),
- disclosure_arrow_->height());
+ height() / 2 - arrow_size.height() / 2,
+ arrow_size.width(),
+ arrow_size.height());
AdjustBoundsForRTLUI(&arrow_bounds);
- SkPaint paint;
- // This makes the arrow subtractive.
- if (invalid())
- paint.setXfermodeMode(SkXfermode::kDstOut_Mode);
- canvas->DrawImageInt(*disclosure_arrow_, arrow_bounds.x(), arrow_bounds.y(),
- paint);
+ // TODO(estade): hack alert! Remove this direct call into CommonTheme. For now
+ // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
+ // behavior. See crbug.com/384071
+ if (style_ == STYLE_ACTION) {
+ ui::CommonThemePaintComboboxArrow(canvas->sk_canvas(), arrow_bounds);
+ } else {
+ ui::NativeTheme::ExtraParams ignored;
+ GetNativeTheme()->Paint(canvas->sk_canvas(),
+ ui::NativeTheme::kComboboxArrow,
+ ui::NativeTheme::kNormal,
+ arrow_bounds,
+ ignored);
+ }
}
void Combobox::PaintButtons(gfx::Canvas* canvas) {
- DCHECK(style_ == STYLE_NOTIFY_ON_CLICK);
+ DCHECK(style_ == STYLE_ACTION);
gfx::ScopedCanvas scoped_canvas(canvas);
if (base::i18n::IsRTL()) {
@@ -739,10 +760,12 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
gfx::Rect lb = GetLocalBounds();
gfx::Point menu_position(lb.origin());
- // Inset the menu's requested position so the border of the menu lines up
- // with the border of the combobox.
- menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
- menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
+ if (style_ == STYLE_NORMAL) {
+ // Inset the menu's requested position so the border of the menu lines up
+ // with the border of the combobox.
+ menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
+ menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
+ }
lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
View::ConvertPointToScreen(this, &menu_position);
@@ -757,8 +780,10 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
arrow_button_->SetState(Button::STATE_PRESSED);
}
dropdown_open_ = true;
+ MenuAnchorPosition anchor_position =
+ style_ == STYLE_ACTION ? MENU_ANCHOR_TOPRIGHT : MENU_ANCHOR_TOPLEFT;
if (dropdown_list_menu_runner_->RunMenuAt(GetWidget(), NULL, bounds,
- MenuItemView::TOPLEFT, source_type,
+ anchor_position, source_type,
MenuRunner::COMBOBOX) ==
MenuRunner::MENU_DELETED) {
return;
@@ -774,12 +799,17 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
SetMouseHandler(NULL);
}
-void Combobox::OnSelectionChanged() {
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false);
+void Combobox::OnPerformAction() {
+ NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, false);
SchedulePaint();
+
+ // This combobox may be deleted by the listener.
+ base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
if (listener_)
- listener_->OnSelectedIndexChanged(this);
- // |this| may now be deleted.
+ listener_->OnPerformAction(this);
+
+ if (weak_ptr && style_ == STYLE_ACTION)
+ selected_index_ = 0;
}
int Combobox::MenuCommandToIndex(int menu_command_id) const {
@@ -792,9 +822,9 @@ int Combobox::MenuCommandToIndex(int menu_command_id) const {
int Combobox::GetDisclosureArrowLeftPadding() const {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK:
+ case STYLE_NORMAL:
return kDisclosureArrowLeftPadding;
- case STYLE_NOTIFY_ON_CLICK:
+ case STYLE_ACTION:
return kDisclosureArrowButtonLeftPadding;
}
NOTREACHED();
@@ -803,21 +833,31 @@ int Combobox::GetDisclosureArrowLeftPadding() const {
int Combobox::GetDisclosureArrowRightPadding() const {
switch (style_) {
- case STYLE_SHOW_DROP_DOWN_ON_CLICK:
+ case STYLE_NORMAL:
return kDisclosureArrowRightPadding;
- case STYLE_NOTIFY_ON_CLICK:
+ case STYLE_ACTION:
return kDisclosureArrowButtonRightPadding;
}
NOTREACHED();
return 0;
}
-void Combobox::HandleClickEvent() {
- if (style_ != STYLE_NOTIFY_ON_CLICK)
- return;
-
- if (listener_)
- listener_->OnComboboxTextButtonClicked(this);
+gfx::Size Combobox::ArrowSize() const {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // TODO(estade): hack alert! This should always use GetNativeTheme(). For now
+ // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
+ // behavior. See crbug.com/384071
+ const ui::NativeTheme* native_theme_for_arrow = style_ == STYLE_ACTION ?
+ ui::NativeTheme::instance() :
+ GetNativeTheme();
+#else
+ const ui::NativeTheme* native_theme_for_arrow = GetNativeTheme();
+#endif
+
+ ui::NativeTheme::ExtraParams ignored;
+ return native_theme_for_arrow->GetPartSize(ui::NativeTheme::kComboboxArrow,
+ ui::NativeTheme::kNormal,
+ ignored);
}
} // namespace views
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index 8ec45c9e211..22781a8ab1f 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "ui/base/models/combobox_model_observer.h"
#include "ui/gfx/animation/animation_delegate.h"
@@ -16,7 +17,7 @@
#include "ui/views/controls/prefix_delegate.h"
namespace gfx {
-class Font;
+class FontList;
class SlideAnimation;
}
@@ -36,10 +37,14 @@ class Painter;
class PrefixSelector;
// A non-editable combobox (aka a drop-down list or selector).
-// Combobox has two distinct parts, the drop down arrow and the text. When the
-// user clicks on the text the drop down is either shown
-// (STYLE_SHOW_DROP_DOWN_ON_CLICK) or the listener is notified
-// (STYLE_NOTIFY_ON_CLICK).
+// Combobox has two distinct parts, the drop down arrow and the text. Combobox
+// offers two distinct behaviors:
+// * STYLE_NORMAL: typical combobox, clicking on the text and/or button shows
+// the drop down, arrow keys change selection, selected index can be changed by
+// the user to something other than the first item.
+// * STYLE_ACTION: clicking on the text notifies the listener. The menu can be
+// shown only by clicking on the arrow. The selected index is always reverted to
+// 0 after the listener is notified.
class VIEWS_EXPORT Combobox : public MenuDelegate,
public PrefixDelegate,
public ui::ComboboxModelObserver,
@@ -47,8 +52,8 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
public:
// The style of the combobox.
enum Style {
- STYLE_SHOW_DROP_DOWN_ON_CLICK,
- STYLE_NOTIFY_ON_CLICK,
+ STYLE_NORMAL,
+ STYLE_ACTION,
};
// The combobox's class name.
@@ -58,7 +63,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
explicit Combobox(ui::ComboboxModel* model);
virtual ~Combobox();
- static const gfx::Font& GetFont();
+ static const gfx::FontList& GetFontList();
// Sets the listener which will be called when a selection has been made.
void set_listener(ComboboxListener* listener) { listener_ = listener; }
@@ -79,7 +84,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
ui::ComboboxModel* model() const { return model_; }
// Set the accessible name of the combobox.
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Visually marks the combobox as having an invalid value selected.
// When invalid, it paints with white text on a red background.
@@ -88,7 +93,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
bool invalid() const { return invalid_; }
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE;
@@ -96,7 +101,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual void Layout() OVERRIDE;
@@ -104,23 +109,26 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
virtual bool IsItemChecked(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
virtual void ExecuteCommand(int id) OVERRIDE;
- virtual bool GetAccelerator(int id, ui::Accelerator* accelerator) OVERRIDE;
+ virtual bool GetAccelerator(int id,
+ ui::Accelerator* accelerator) const OVERRIDE;
// Overridden from PrefixDelegate:
virtual int GetRowCount() OVERRIDE;
virtual int GetSelectedRow() OVERRIDE;
virtual void SetSelectedRow(int row) OVERRIDE;
- virtual string16 GetTextForRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
// Overriden from ComboboxModelObserver:
- virtual void OnModelChanged() OVERRIDE;
+ virtual void OnComboboxModelChanged(ui::ComboboxModel* model) OVERRIDE;
// Overriden from ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(ComboboxTest, Click);
+ FRIEND_TEST_ALL_PREFIXES(ComboboxTest, ClickButDisabled);
FRIEND_TEST_ALL_PREFIXES(ComboboxTest, NotifyOnClickWithMouse);
+ FRIEND_TEST_ALL_PREFIXES(ComboboxTest, ContentWidth);
// Updates the combobox's content from its model.
void UpdateFromModel();
@@ -141,7 +149,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
void ShowDropDownMenu(ui::MenuSourceType source_type);
// Called when the selection is changed by the user.
- void OnSelectionChanged();
+ void OnPerformAction();
+ void NotifyPerformAction();
+ void AfterPerformAction();
// Converts a menu command ID to a menu item index.
int MenuCommandToIndex(int menu_command_id) const;
@@ -149,6 +159,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
int GetDisclosureArrowLeftPadding() const;
int GetDisclosureArrowRightPadding() const;
+ // Returns the size of the disclosure arrow.
+ gfx::Size ArrowSize() const;
+
// Handles the clicking event.
void HandleClickEvent();
@@ -168,14 +181,11 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
bool invalid_;
// The accessible name of this combobox.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// A helper used to select entries by keyboard input.
scoped_ptr<PrefixSelector> selector_;
- // The disclosure arrow next to the currently selected item from the list.
- const gfx::ImageSkia* disclosure_arrow_;
-
// Responsible for showing the context menu.
scoped_ptr<MenuRunner> dropdown_list_menu_runner_;
@@ -191,7 +201,7 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
base::Time closed_time_;
// The maximum dimensions of the content in the dropdown
- gfx::Size content_size_;
+ mutable gfx::Size content_size_;
// The painters or images that are used when |style_| is STYLE_BUTTONS. The
// first index means the state of unfocused or focused.
@@ -209,6 +219,9 @@ class VIEWS_EXPORT Combobox : public MenuDelegate,
CustomButton* text_button_;
CustomButton* arrow_button_;
+ // Used for making calbacks.
+ base::WeakPtrFactory<Combobox> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(Combobox);
};
diff --git a/chromium/ui/views/controls/combobox/combobox_listener.h b/chromium/ui/views/controls/combobox/combobox_listener.h
index 2609f647023..2522e03c7d8 100644
--- a/chromium/ui/views/controls/combobox/combobox_listener.h
+++ b/chromium/ui/views/controls/combobox/combobox_listener.h
@@ -5,19 +5,24 @@
#ifndef UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
#define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
class Combobox;
-// An interface implemented by an object to let it know that the selected index
-// has changed.
-class ComboboxListener {
+// Interface used to notify consumers when something interesting happens to a
+// Combobox.
+class VIEWS_EXPORT ComboboxListener {
public:
- virtual void OnSelectedIndexChanged(Combobox* combobox) = 0;
-
- // Handles when the combobox's style is the button style and the button is
- // clicked.
- virtual void OnComboboxTextButtonClicked(Combobox* combobox) {}
+ // Invoked when the user does the appropriate gesture that some action should
+ // be performed. For both STYLE_NORMAL and STYLE_ACTION this is invoked if the
+ // user clicks on the menu button and then clicks an item. For STYLE_NORMAL
+ // this is also invoked when the menu is not showing and the does a gesture to
+ // change the selection (for example, presses the home or end keys). This is
+ // not invoked when the menu is shown and the user changes the selection
+ // without closing the menu.
+ virtual void OnPerformAction(Combobox* combobox) = 0;
protected:
virtual ~ComboboxListener() {}
diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc
index 7b68c4578e3..67625a2aea1 100644
--- a/chromium/ui/views/controls/combobox/combobox_unittest.cc
+++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc
@@ -8,8 +8,10 @@
#include "base/basictypes.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/text_input_client.h"
#include "ui/base/models/combobox_model.h"
#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/menu/menu_runner.h"
@@ -19,6 +21,8 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace {
@@ -27,15 +31,14 @@ namespace {
// shown or not.
class TestMenuRunnerHandler : public MenuRunnerHandler {
public:
- TestMenuRunnerHandler()
- : executed_(false) {}
+ TestMenuRunnerHandler() : executed_(false) {}
bool executed() const { return executed_; }
virtual MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) OVERRIDE {
executed_ = true;
@@ -55,8 +58,7 @@ class TestCombobox : public Combobox {
explicit TestCombobox(ui::ComboboxModel* model)
: Combobox(model),
key_handled_(false),
- key_received_(false) {
- }
+ key_received_(false) {}
virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
key_received_ = true;
@@ -94,7 +96,7 @@ class TestComboboxModel : public ui::ComboboxModel {
virtual int GetItemCount() const OVERRIDE {
return 10;
}
- virtual string16 GetItemAt(int index) OVERRIDE {
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
if (IsItemSeparatorAt(index)) {
NOTREACHED();
return ASCIIToUTF16("SEPARATOR");
@@ -115,13 +117,35 @@ class TestComboboxModel : public ui::ComboboxModel {
DISALLOW_COPY_AND_ASSIGN(TestComboboxModel);
};
+// A combobox model which refers to a vector.
+class VectorComboboxModel : public ui::ComboboxModel {
+ public:
+ explicit VectorComboboxModel(std::vector<std::string>* values)
+ : values_(values) {}
+ virtual ~VectorComboboxModel() {}
+
+ // ui::ComboboxModel:
+ virtual int GetItemCount() const OVERRIDE {
+ return (int)values_->size();
+ }
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
+ return ASCIIToUTF16(values_->at(index));
+ }
+ virtual bool IsItemSeparatorAt(int index) OVERRIDE {
+ return false;
+ }
+
+ private:
+ std::vector<std::string>* values_;
+};
+
class EvilListener : public ComboboxListener {
public:
- EvilListener() : deleted_(false) {};
+ EvilListener() : deleted_(false) {}
virtual ~EvilListener() {};
// ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE {
+ virtual void OnPerformAction(Combobox* combobox) OVERRIDE {
delete combobox;
deleted_ = true;
}
@@ -136,31 +160,29 @@ class EvilListener : public ComboboxListener {
class TestComboboxListener : public views::ComboboxListener {
public:
- TestComboboxListener()
- : on_selected_index_changed_called_(false),
- on_combobox_text_button_clicked_called_(false) {
- }
+ TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {}
virtual ~TestComboboxListener() {}
- virtual void OnSelectedIndexChanged(views::Combobox* combobox) OVERRIDE {
- on_selected_index_changed_called_ = true;
+ virtual void OnPerformAction(views::Combobox* combobox) OVERRIDE {
+ perform_action_index_ = combobox->selected_index();
+ actions_performed_++;
}
- virtual void OnComboboxTextButtonClicked(views::Combobox* combobox) OVERRIDE {
- on_combobox_text_button_clicked_called_ = true;
+ int perform_action_index() const {
+ return perform_action_index_;
}
- bool on_selected_index_changed_called() const {
- return on_selected_index_changed_called_;
+ bool on_perform_action_called() const {
+ return actions_performed_ > 0;
}
- bool on_combobox_text_button_clicked_called() const {
- return on_combobox_text_button_clicked_called_;
+ int actions_performed() const {
+ return actions_performed_;
}
private:
- bool on_selected_index_changed_called_;
- bool on_combobox_text_button_clicked_called_;
+ int perform_action_index_;
+ int actions_performed_;
private:
DISALLOW_COPY_AND_ASSIGN(TestComboboxListener);
@@ -170,7 +192,7 @@ class TestComboboxListener : public views::ComboboxListener {
class ComboboxTest : public ViewsTestBase {
public:
- ComboboxTest() : widget_(NULL), combobox_(NULL), input_method_(NULL) {}
+ ComboboxTest() : widget_(NULL), combobox_(NULL) {}
virtual void TearDown() OVERRIDE {
if (widget_)
@@ -193,11 +215,10 @@ class ComboboxTest : public ViewsTestBase {
widget_->SetContentsView(container);
container->AddChildView(combobox_);
- input_method_ = new MockInputMethod();
- widget_->ReplaceInputMethod(input_method_);
+ widget_->ReplaceInputMethod(new MockInputMethod);
// Assumes the Widget is always focused.
- input_method_->OnFocus();
+ widget_->GetInputMethod()->OnFocus();
combobox_->RequestFocus();
combobox_->SizeToPreferredSize();
@@ -210,7 +231,7 @@ class ComboboxTest : public ViewsTestBase {
void SendKeyEventWithType(ui::KeyboardCode key_code, ui::EventType type) {
ui::KeyEvent event(type, key_code, 0, false);
- input_method_->DispatchKeyEvent(event);
+ widget_->GetInputMethod()->DispatchKeyEvent(event);
}
View* GetFocusedView() {
@@ -220,10 +241,12 @@ class ComboboxTest : public ViewsTestBase {
void PerformClick(const gfx::Point& point) {
ui::MouseEvent pressed_event = ui::MouseEvent(ui::ET_MOUSE_PRESSED, point,
point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&pressed_event);
ui::MouseEvent released_event = ui::MouseEvent(ui::ET_MOUSE_RELEASED, point,
point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&released_event);
}
@@ -236,9 +259,6 @@ class ComboboxTest : public ViewsTestBase {
// Combobox does not take ownership of the model, hence it needs to be scoped.
scoped_ptr<TestComboboxModel> model_;
-
- // For testing input method related behaviors.
- MockInputMethod* input_method_;
};
TEST_F(ComboboxTest, KeyTest) {
@@ -435,15 +455,48 @@ TEST_F(ComboboxTest, SelectValue) {
EXPECT_EQ(1, combobox_->selected_index());
EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS")));
EXPECT_EQ(1, combobox_->selected_index());
+
+ // With the action style, the selected index is always 0.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
+ EXPECT_EQ(0, combobox_->selected_index());
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("JELLY")));
+ EXPECT_EQ(0, combobox_->selected_index());
+ EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS")));
+ EXPECT_EQ(0, combobox_->selected_index());
+}
+
+TEST_F(ComboboxTest, SelectIndexActionStyle) {
+ InitCombobox();
+
+ // With the action style, the selected index is always 0.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
+ combobox_->SetSelectedIndex(1);
+ EXPECT_EQ(0, combobox_->selected_index());
+ combobox_->SetSelectedIndex(2);
+ EXPECT_EQ(0, combobox_->selected_index());
+ combobox_->SetSelectedIndex(3);
+ EXPECT_EQ(0, combobox_->selected_index());
}
TEST_F(ComboboxTest, ListenerHandlesDelete) {
TestComboboxModel model;
- TestCombobox* combobox = new TestCombobox(&model); // Deleted on change.
- EvilListener evil_listener;
- combobox->set_listener(&evil_listener);
+
+ // |combobox| will be deleted on change.
+ TestCombobox* combobox = new TestCombobox(&model);
+ scoped_ptr<EvilListener> evil_listener(new EvilListener());
+ combobox->set_listener(evil_listener.get());
+ ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2));
+ EXPECT_TRUE(evil_listener->deleted());
+
+ // With STYLE_ACTION
+ // |combobox| will be deleted on change.
+ combobox = new TestCombobox(&model);
+ evil_listener.reset(new EvilListener());
+ combobox->set_listener(evil_listener.get());
+ combobox->SetStyle(Combobox::STYLE_ACTION);
ASSERT_NO_FATAL_FAILURE(combobox->ExecuteCommand(2));
- EXPECT_TRUE(evil_listener.deleted());
+ EXPECT_TRUE(evil_listener->deleted());
}
TEST_F(ComboboxTest, Click) {
@@ -462,24 +515,46 @@ TEST_F(ComboboxTest, Click) {
test_api.SetMenuRunnerHandler(menu_runner_handler.Pass());
PerformClick(gfx::Point(combobox_->x() + 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
EXPECT_TRUE(test_menu_runner_handler->executed());
}
+TEST_F(ComboboxTest, ClickButDisabled) {
+ InitCombobox();
+
+ TestComboboxListener listener;
+ combobox_->set_listener(&listener);
+
+ combobox_->Layout();
+ combobox_->SetEnabled(false);
+
+ // Click the left side, but nothing happens since the combobox is disabled.
+ TestMenuRunnerHandler* test_menu_runner_handler = new TestMenuRunnerHandler();
+ scoped_ptr<MenuRunnerHandler> menu_runner_handler(test_menu_runner_handler);
+ test::MenuRunnerTestAPI test_api(
+ combobox_->dropdown_list_menu_runner_.get());
+ test_api.SetMenuRunnerHandler(menu_runner_handler.Pass());
+ PerformClick(gfx::Point(combobox_->x() + 1,
+ combobox_->y() + combobox_->height() / 2));
+ EXPECT_FALSE(listener.on_perform_action_called());
+ EXPECT_FALSE(test_menu_runner_handler->executed());
+}
+
TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) {
InitCombobox();
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_SHOW_DROP_DOWN_ON_CLICK, the click event is ignored.
+ // With STYLE_NORMAL, the click event is ignored.
SendKeyEvent(ui::VKEY_RETURN);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
- // With STYLE_NOTIFY_ON_CLICK, the click event is notified.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // With STYLE_ACTION, the click event is notified.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
SendKeyEvent(ui::VKEY_RETURN);
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
@@ -488,18 +563,19 @@ TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_SHOW_DROP_DOWN_ON_CLICK, the click event is ignored.
+ // With STYLE_NORMAL, the click event is ignored.
SendKeyEvent(ui::VKEY_SPACE);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
- // With STYLE_NOTIFY_ON_CLICK, the click event is notified after releasing.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // With STYLE_ACTION, the click event is notified after releasing.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
SendKeyEvent(ui::VKEY_SPACE);
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED);
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
@@ -508,7 +584,7 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
TestComboboxListener listener;
combobox_->set_listener(&listener);
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
combobox_->Layout();
// Click the right side (arrow button). The menu is shown.
@@ -520,7 +596,7 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
PerformClick(gfx::Point(combobox_->x() + combobox_->width() - 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_FALSE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_FALSE(listener.on_perform_action_called());
EXPECT_TRUE(test_menu_runner_handler->executed());
// Click the left side (text button). The click event is notified.
@@ -531,8 +607,9 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
test_api->SetMenuRunnerHandler(menu_runner_handler.Pass());
PerformClick(gfx::Point(combobox_->x() + 1,
combobox_->y() + combobox_->height() / 2));
- EXPECT_TRUE(listener.on_combobox_text_button_clicked_called());
+ EXPECT_TRUE(listener.on_perform_action_called());
EXPECT_FALSE(test_menu_runner_handler->executed());
+ EXPECT_EQ(0, listener.perform_action_index());
}
TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
@@ -543,13 +620,74 @@ TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
EXPECT_FALSE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false)));
- // When the combobox's style is STYLE_NOTIFY_ON_CLICK, pressing events of
- // a space key or an enter key will be consumed.
- combobox_->SetStyle(Combobox::STYLE_NOTIFY_ON_CLICK);
+ // When the combobox's style is STYLE_ACTION, pressing events of a space key
+ // or an enter key will be consumed.
+ combobox_->SetStyle(Combobox::STYLE_ACTION);
EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0, false)));
EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, false)));
}
+TEST_F(ComboboxTest, ContentWidth) {
+ std::vector<std::string> values;
+ VectorComboboxModel model(&values);
+ TestCombobox combobox(&model);
+
+ std::string long_item = "this is the long item";
+ std::string short_item = "s";
+
+ values.resize(1);
+ values[0] = long_item;
+ combobox.ModelChanged();
+
+ const int long_item_width = combobox.content_size_.width();
+
+ values[0] = short_item;
+ combobox.ModelChanged();
+
+ const int short_item_width = combobox.content_size_.width();
+
+ values.resize(2);
+ values[0] = short_item;
+ values[1] = long_item;
+ combobox.ModelChanged();
+
+ // When the style is STYLE_NORMAL, the width will fit with the longest item.
+ combobox.SetStyle(Combobox::STYLE_NORMAL);
+ EXPECT_EQ(long_item_width, combobox.content_size_.width());
+
+ // When the style is STYLE_ACTION, the width will fit with the first items'
+ // width.
+ combobox.SetStyle(Combobox::STYLE_ACTION);
+ EXPECT_EQ(short_item_width, combobox.content_size_.width());
+}
+
+TEST_F(ComboboxTest, TypingPrefixNotifiesListener) {
+ InitCombobox();
+
+ TestComboboxListener listener;
+ combobox_->set_listener(&listener);
+
+ // Type the first character of the second menu item ("JELLY").
+ combobox_->GetTextInputClient()->InsertChar('J', ui::EF_NONE);
+ EXPECT_EQ(1, listener.actions_performed());
+ EXPECT_EQ(1, listener.perform_action_index());
+
+ // Type the second character of "JELLY", item shouldn't change and
+ // OnPerformAction() shouldn't be re-called.
+ combobox_->GetTextInputClient()->InsertChar('E', ui::EF_NONE);
+ EXPECT_EQ(1, listener.actions_performed());
+ EXPECT_EQ(1, listener.perform_action_index());
+
+ // Clears the typed text.
+ combobox_->OnBlur();
+
+ // Type the first character of "PEANUT BUTTER", which should change the
+ // selected index and perform an action.
+ combobox_->GetTextInputClient()->InsertChar('P', ui::EF_NONE);
+ EXPECT_EQ(2, listener.actions_performed());
+ EXPECT_EQ(2, listener.perform_action_index());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc
index 2bbf91cab9e..5b758f8e1c7 100644
--- a/chromium/ui/views/controls/image_view.cc
+++ b/chromium/ui/views/controls/image_view.cc
@@ -7,13 +7,25 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
#include "ui/views/painter.h"
namespace views {
+namespace {
+
+// Returns the pixels for the bitmap in |image| at scale |image_scale|.
+void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
+ DCHECK_NE(0.0f, image_scale);
+ const SkBitmap& bitmap = img.GetRepresentation(image_scale).sk_bitmap();
+ SkAutoLockPixels pixel_lock(bitmap);
+ return bitmap.getPixels();
+}
+
+} // namespace
+
ImageView::ImageView()
: image_size_set_(false),
horiz_alignment_(CENTER),
@@ -58,7 +70,7 @@ void ImageView::SetImageSize(const gfx::Size& image_size) {
PreferredSizeChanged();
}
-bool ImageView::GetImageSize(gfx::Size* image_size) {
+bool ImageView::GetImageSize(gfx::Size* image_size) const {
DCHECK(image_size);
if (image_size_set_)
*image_size = image_size_;
@@ -79,7 +91,7 @@ void ImageView::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
focus_painter_ = focus_painter.Pass();
}
-gfx::Size ImageView::GetPreferredSize() {
+gfx::Size ImageView::GetPreferredSize() const {
gfx::Insets insets = GetInsets();
if (image_size_set_) {
gfx::Size image_size;
@@ -99,8 +111,7 @@ bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
// the backing store but also the pixels of the last image we painted.
return image_.BackedBySameObjectAs(img) &&
last_paint_scale_ != 0.0f &&
- last_painted_bitmap_pixels_ ==
- img.GetRepresentation(last_paint_scale_).sk_bitmap().getPixels();
+ last_painted_bitmap_pixels_ == GetBitmapPixels(img, last_paint_scale_);
}
gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
@@ -150,8 +161,8 @@ void ImageView::OnPaint(gfx::Canvas* canvas) {
Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
-void ImageView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GRAPHIC;
+void ImageView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_IMAGE;
state->name = tooltip_text_;
}
@@ -177,15 +188,16 @@ ImageView::Alignment ImageView::GetVerticalAlignment() const {
return vert_alignment_;
}
-void ImageView::SetTooltipText(const string16& tooltip) {
+void ImageView::SetTooltipText(const base::string16& tooltip) {
tooltip_text_ = tooltip;
}
-string16 ImageView::GetTooltipText() const {
+base::string16 ImageView::GetTooltipText() const {
return tooltip_text_;
}
-bool ImageView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool ImageView::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
if (tooltip_text_.empty())
return false;
@@ -193,11 +205,10 @@ bool ImageView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
return true;
}
-bool ImageView::HitTestRect(const gfx::Rect& rect) const {
- return interactive_ ? View::HitTestRect(rect) : false;
+bool ImageView::CanProcessEventsWithinSubtree() const {
+ return interactive_;
}
-
void ImageView::OnPaintImage(gfx::Canvas* canvas) {
last_paint_scale_ = canvas->image_scale();
last_painted_bitmap_pixels_ = NULL;
@@ -212,15 +223,14 @@ void ImageView::OnPaintImage(gfx::Canvas* canvas) {
if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) {
// Resize case
SkPaint paint;
- paint.setFilterBitmap(true);
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
canvas->DrawImageInt(image_, 0, 0, image_.width(), image_.height(),
image_bounds.x(), image_bounds.y(), image_bounds.width(),
image_bounds.height(), true, paint);
} else {
canvas->DrawImageInt(image_, image_bounds.x(), image_bounds.y());
}
- last_painted_bitmap_pixels_ =
- image_.GetRepresentation(last_paint_scale_).sk_bitmap().getPixels();
+ last_painted_bitmap_pixels_ = GetBitmapPixels(image_, last_paint_scale_);
}
} // namespace views
diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h
index b0f4ce852ff..a05b106ecfa 100644
--- a/chromium/ui/views/controls/image_view.h
+++ b/chromium/ui/views/controls/image_view.h
@@ -55,7 +55,7 @@ class VIEWS_EXPORT ImageView : public View {
// Return the preferred size for the receiving view. Returns false if the
// preferred size is not defined, which means that the view uses the image
// size.
- bool GetImageSize(gfx::Size* image_size);
+ bool GetImageSize(gfx::Size* image_size) const;
// Returns the actual bounds of the visible image inside the view.
gfx::Rect GetImageBounds() const;
@@ -72,22 +72,22 @@ class VIEWS_EXPORT ImageView : public View {
Alignment GetVerticalAlignment() const;
// Set / Get the tooltip text.
- void SetTooltipText(const string16& tooltip);
- string16 GetTooltipText() const;
+ void SetTooltipText(const base::string16& tooltip);
+ base::string16 GetTooltipText() const;
void set_interactive(bool interactive) { interactive_ = interactive; }
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
// Overriden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
private:
void OnPaintImage(gfx::Canvas* canvas);
@@ -117,7 +117,7 @@ class VIEWS_EXPORT ImageView : public View {
Alignment vert_alignment_;
// The current tooltip text.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
// A flag controlling hit test handling for interactivity.
bool interactive_;
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index 7d4bc7e8470..648a0e660bc 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -14,27 +14,21 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/insets.h"
-#include "ui/gfx/shadow_value.h"
#include "ui/gfx/text_elider.h"
#include "ui/gfx/text_utils.h"
+#include "ui/gfx/utf16_indexing.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
namespace {
-// The padding for the focus border when rendering focused text.
-const int kFocusBorderPadding = 1;
const int kCachedSizeLimit = 10;
-
-gfx::FontList GetDefaultFontList() {
- return ui::ResourceBundle::GetSharedInstance().GetFontList(
- ui::ResourceBundle::BaseFont);
-}
+const base::char16 kPasswordReplacementChar = '*';
} // namespace
@@ -42,23 +36,20 @@ namespace views {
// static
const char Label::kViewClassName[] = "Label";
+const int Label::kFocusBorderPadding = 1;
Label::Label() {
- Init(string16(), GetDefaultFontList());
+ Init(base::string16(), gfx::FontList());
}
-Label::Label(const string16& text) {
- Init(text, GetDefaultFontList());
+Label::Label(const base::string16& text) {
+ Init(text, gfx::FontList());
}
-Label::Label(const string16& text, const gfx::FontList& font_list) {
+Label::Label(const base::string16& text, const gfx::FontList& font_list) {
Init(text, font_list);
}
-Label::Label(const string16& text, const gfx::Font& font) {
- Init(text, gfx::FontList(font));
-}
-
Label::~Label() {
}
@@ -69,18 +60,22 @@ void Label::SetFontList(const gfx::FontList& font_list) {
SchedulePaint();
}
-const gfx::Font& Label::font() const {
- return font_list_.GetPrimaryFont();
-}
-
-void Label::SetFont(const gfx::Font& font) {
- SetFontList(gfx::FontList(font));
+void Label::SetText(const base::string16& text) {
+ if (text != text_)
+ SetTextInternal(text);
}
-void Label::SetText(const string16& text) {
- if (text == text_)
- return;
+void Label::SetTextInternal(const base::string16& text) {
text_ = text;
+
+ if (is_obscured_) {
+ size_t obscured_text_length =
+ static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length()));
+ layout_text_.assign(obscured_text_length, kPasswordReplacementChar);
+ } else {
+ layout_text_ = text_;
+ }
+
ResetCachedSize();
PreferredSizeChanged();
SchedulePaint();
@@ -109,26 +104,10 @@ void Label::SetBackgroundColor(SkColor color) {
RecalculateColors();
}
-void Label::SetShadowColors(SkColor enabled_color, SkColor disabled_color) {
- enabled_shadow_color_ = enabled_color;
- disabled_shadow_color_ = disabled_color;
- has_shadow_ = true;
-}
-
-void Label::SetShadowOffset(int x, int y) {
- shadow_offset_.SetPoint(x, y);
-}
-
-void Label::ClearEmbellishing() {
- has_shadow_ = false;
-}
-
void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
- // If the View's UI layout is right-to-left and directionality_mode_ is
- // USE_UI_DIRECTIONALITY, we need to flip the alignment so that the alignment
- // settings take into account the text directionality.
- if (base::i18n::IsRTL() && (directionality_mode_ == USE_UI_DIRECTIONALITY) &&
- (alignment != gfx::ALIGN_CENTER)) {
+ // If the UI layout is right-to-left, flip the alignment direction.
+ if (base::i18n::IsRTL() &&
+ (alignment == gfx::ALIGN_LEFT || alignment == gfx::ALIGN_RIGHT)) {
alignment = (alignment == gfx::ALIGN_LEFT) ?
gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
}
@@ -138,6 +117,15 @@ void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
}
}
+gfx::HorizontalAlignment Label::GetHorizontalAlignment() const {
+ if (horizontal_alignment_ != gfx::ALIGN_TO_HEAD)
+ return horizontal_alignment_;
+
+ const base::i18n::TextDirection dir =
+ base::i18n::GetFirstStrongCharacterDirection(layout_text());
+ return dir == base::i18n::RIGHT_TO_LEFT ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
+}
+
void Label::SetLineHeight(int height) {
if (height != line_height_) {
line_height_ = height;
@@ -148,7 +136,8 @@ void Label::SetLineHeight(int height) {
}
void Label::SetMultiLine(bool multi_line) {
- DCHECK(!multi_line || elide_behavior_ != ELIDE_IN_MIDDLE);
+ DCHECK(!multi_line || (elide_behavior_ == gfx::ELIDE_TAIL ||
+ elide_behavior_ == gfx::TRUNCATE));
if (multi_line != is_multi_line_) {
is_multi_line_ = multi_line;
ResetCachedSize();
@@ -157,6 +146,13 @@ void Label::SetMultiLine(bool multi_line) {
}
}
+void Label::SetObscured(bool obscured) {
+ if (obscured != is_obscured_) {
+ is_obscured_ = obscured;
+ SetTextInternal(text_);
+ }
+}
+
void Label::SetAllowCharacterBreak(bool allow_character_break) {
if (allow_character_break != allow_character_break_) {
allow_character_break_ = allow_character_break;
@@ -166,8 +162,9 @@ void Label::SetAllowCharacterBreak(bool allow_character_break) {
}
}
-void Label::SetElideBehavior(ElideBehavior elide_behavior) {
- DCHECK(elide_behavior != ELIDE_IN_MIDDLE || !is_multi_line_);
+void Label::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
+ DCHECK(!is_multi_line_ || (elide_behavior_ == gfx::ELIDE_TAIL ||
+ elide_behavior_ == gfx::TRUNCATE));
if (elide_behavior != elide_behavior_) {
elide_behavior_ = elide_behavior;
ResetCachedSize();
@@ -176,18 +173,18 @@ void Label::SetElideBehavior(ElideBehavior elide_behavior) {
}
}
-void Label::SetTooltipText(const string16& tooltip_text) {
+void Label::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
}
void Label::SizeToFit(int max_width) {
DCHECK(is_multi_line_);
- std::vector<string16> lines;
- base::SplitString(text_, '\n', &lines);
+ std::vector<base::string16> lines;
+ base::SplitString(layout_text(), '\n', &lines);
int label_width = 0;
- for (std::vector<string16>::const_iterator iter = lines.begin();
+ for (std::vector<base::string16>::const_iterator iter = lines.begin();
iter != lines.end(); ++iter) {
label_width = std::max(label_width, gfx::GetStringWidth(*iter, font_list_));
}
@@ -201,17 +198,9 @@ void Label::SizeToFit(int max_width) {
SizeToPreferredSize();
}
-void Label::SetHasFocusBorder(bool has_focus_border) {
- has_focus_border_ = has_focus_border;
- if (is_multi_line_) {
- ResetCachedSize();
- PreferredSizeChanged();
- }
-}
-
gfx::Insets Label::GetInsets() const {
gfx::Insets insets = View::GetInsets();
- if (focusable() || has_focus_border_) {
+ if (focusable()) {
insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding,
kFocusBorderPadding, kFocusBorderPadding);
}
@@ -222,7 +211,7 @@ int Label::GetBaseline() const {
return GetInsets().top() + font_list_.GetBaseline();
}
-gfx::Size Label::GetPreferredSize() {
+gfx::Size Label::GetPreferredSize() const {
// Return a size of (0, 0) if the label is not visible and if the
// collapse_when_hidden_ flag is set.
// TODO(munjal): This logic probably belongs to the View class. But for now,
@@ -231,13 +220,27 @@ gfx::Size Label::GetPreferredSize() {
if (!visible() && collapse_when_hidden_)
return gfx::Size();
- gfx::Size prefsize(GetTextSize());
+ gfx::Size size(GetTextSize());
+ gfx::Insets insets = GetInsets();
+ size.Enlarge(insets.width(), insets.height());
+ return size;
+}
+
+gfx::Size Label::GetMinimumSize() const {
+ gfx::Size text_size(GetTextSize());
+ if ((!visible() && collapse_when_hidden_) || text_size.IsEmpty())
+ return gfx::Size();
+
+ gfx::Size size(gfx::GetStringWidth(base::string16(gfx::kEllipsisUTF16),
+ font_list_),
+ font_list_.GetHeight());
+ size.SetToMin(text_size); // The actual text may be shorter than an ellipsis.
gfx::Insets insets = GetInsets();
- prefsize.Enlarge(insets.width(), insets.height());
- return prefsize;
+ size.Enlarge(insets.width(), insets.height());
+ return size;
}
-int Label::GetHeightForWidth(int w) {
+int Label::GetHeightForWidth(int w) const {
if (!is_multi_line_)
return View::GetHeightForWidth(w);
@@ -253,7 +256,8 @@ int Label::GetHeightForWidth(int w) {
int h = font_list_.GetHeight();
const int flags = ComputeDrawStringFlags();
- gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
+ gfx::Canvas::SizeStringInt(
+ layout_text(), font_list_, &w, &h, line_height_, flags);
cached_heights_[cached_heights_cursor_] = gfx::Size(cache_width, h);
cached_heights_cursor_ = (cached_heights_cursor_ + 1) % kCachedSizeLimit;
return h + GetInsets().height();
@@ -278,11 +282,12 @@ View* Label::GetTooltipHandlerForPoint(const gfx::Point& point) {
return this;
}
-bool Label::HitTestRect(const gfx::Rect& rect) const {
+bool Label::CanProcessEventsWithinSubtree() const {
+ // Send events to the parent view for handling.
return false;
}
-bool Label::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool Label::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const {
DCHECK(tooltip);
// If a tooltip has been explicitly set, use it.
@@ -293,30 +298,30 @@ bool Label::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
// Show the full text if the text does not fit.
if (ShouldShowDefaultTooltip()) {
- *tooltip = text_;
+ *tooltip = layout_text();
return true;
}
return false;
}
-void Label::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_STATICTEXT;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
- state->name = text_;
+void Label::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_STATIC_TEXT;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+ state->name = layout_text();
}
void Label::PaintText(gfx::Canvas* canvas,
- const string16& text,
+ const base::string16& text,
const gfx::Rect& text_bounds,
int flags) {
- gfx::ShadowValues shadows;
- if (has_shadow_)
- shadows.push_back(gfx::ShadowValue(shadow_offset_, 0,
- enabled() ? enabled_shadow_color_ : disabled_shadow_color_));
- canvas->DrawStringRectWithShadows(text, font_list_,
- enabled() ? actual_enabled_color_ : actual_disabled_color_,
- text_bounds, line_height_, flags, shadows);
+ SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_;
+ if (elide_behavior_ == gfx::FADE_TAIL) {
+ canvas->DrawFadedString(text, font_list_, color, text_bounds, flags);
+ } else {
+ canvas->DrawStringRectWithShadows(text, font_list_, color, text_bounds,
+ line_height_, flags, shadows_);
+ }
if (HasFocus()) {
gfx::Rect focus_bounds = text_bounds;
@@ -339,8 +344,11 @@ gfx::Size Label::GetTextSize() const {
int flags = ComputeDrawStringFlags();
if (!is_multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
- gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
+ gfx::Canvas::SizeStringInt(
+ layout_text(), font_list_, &w, &h, line_height_, flags);
text_size_.SetSize(w, h);
+ const gfx::Insets shadow_margin = -gfx::ShadowValue::GetMargin(shadows_);
+ text_size_.Enlarge(shadow_margin.width(), shadow_margin.height());
text_size_valid_ = true;
}
@@ -358,7 +366,7 @@ void Label::OnPaint(gfx::Canvas* canvas) {
// interfere with that.
OnPaintBorder(canvas);
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
int flags = 0;
CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
@@ -369,23 +377,20 @@ void Label::OnNativeThemeChanged(const ui::NativeTheme* theme) {
UpdateColorsFromTheme(theme);
}
-void Label::Init(const string16& text, const gfx::FontList& font_list) {
+void Label::Init(const base::string16& text, const gfx::FontList& font_list) {
font_list_ = font_list;
enabled_color_set_ = disabled_color_set_ = background_color_set_ = false;
+ subpixel_rendering_enabled_ = true;
auto_color_readability_ = true;
UpdateColorsFromTheme(ui::NativeTheme::instance());
horizontal_alignment_ = gfx::ALIGN_CENTER;
line_height_ = 0;
is_multi_line_ = false;
+ is_obscured_ = false;
allow_character_break_ = false;
- elide_behavior_ = ELIDE_AT_END;
+ elide_behavior_ = gfx::ELIDE_TAIL;
collapse_when_hidden_ = false;
- directionality_mode_ = USE_UI_DIRECTIONALITY;
- has_focus_border_ = false;
- enabled_shadow_color_ = 0;
- disabled_shadow_color_ = 0;
- shadow_offset_.SetPoint(1, 1);
- has_shadow_ = false;
+ directionality_mode_ = gfx::DIRECTIONALITY_FROM_UI;
cached_heights_.resize(kCachedSizeLimit);
ResetCachedSize();
@@ -404,52 +409,50 @@ void Label::RecalculateColors() {
}
gfx::Rect Label::GetTextBounds() const {
- gfx::Rect available_rect(GetAvailableRect());
+ gfx::Rect available(GetAvailableRect());
gfx::Size text_size(GetTextSize());
- text_size.set_width(std::min(available_rect.width(), text_size.width()));
-
- gfx::Insets insets = GetInsets();
- gfx::Point text_origin(insets.left(), insets.top());
- switch (horizontal_alignment_) {
+ text_size.set_width(std::min(available.width(), text_size.width()));
+ gfx::Point origin(GetInsets().left(), GetInsets().top());
+ switch (GetHorizontalAlignment()) {
case gfx::ALIGN_LEFT:
break;
case gfx::ALIGN_CENTER:
- // We put any extra margin pixel on the left rather than the right. We
- // used to do this because measurement on Windows used
- // GetTextExtentPoint32(), which could report a value one too large on the
- // right; we now use DrawText(), and who knows if it can also do this.
- text_origin.Offset((available_rect.width() + 1 - text_size.width()) / 2,
- 0);
+ // Put any extra margin pixel on the left to match the legacy behavior
+ // from the use of GetTextExtentPoint32() on Windows.
+ origin.Offset((available.width() + 1 - text_size.width()) / 2, 0);
break;
case gfx::ALIGN_RIGHT:
- text_origin.set_x(available_rect.right() - text_size.width());
+ origin.set_x(available.right() - text_size.width());
break;
default:
NOTREACHED();
break;
}
- text_origin.Offset(0,
- std::max(0, (available_rect.height() - text_size.height())) / 2);
- return gfx::Rect(text_origin, text_size);
+ origin.Offset(0, std::max(0, (available.height() - text_size.height())) / 2);
+ return gfx::Rect(origin, text_size);
}
int Label::ComputeDrawStringFlags() const {
int flags = 0;
// We can't use subpixel rendering if the background is non-opaque.
- if (SkColorGetA(background_color_) != 0xFF)
+ if (SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- if (directionality_mode_ == AUTO_DETECT_DIRECTIONALITY) {
+ if (directionality_mode_ == gfx::DIRECTIONALITY_FORCE_LTR) {
+ flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
+ } else if (directionality_mode_ == gfx::DIRECTIONALITY_FORCE_RTL) {
+ flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
+ } else if (directionality_mode_ == gfx::DIRECTIONALITY_FROM_TEXT) {
base::i18n::TextDirection direction =
- base::i18n::GetFirstStrongCharacterDirection(text_);
+ base::i18n::GetFirstStrongCharacterDirection(layout_text());
if (direction == base::i18n::RIGHT_TO_LEFT)
flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY;
else
flags |= gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
}
- switch (horizontal_alignment_) {
+ switch (GetHorizontalAlignment()) {
case gfx::ALIGN_LEFT:
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
break;
@@ -459,6 +462,9 @@ int Label::ComputeDrawStringFlags() const {
case gfx::ALIGN_RIGHT:
flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
break;
+ default:
+ NOTREACHED();
+ break;
}
if (!is_multi_line_)
@@ -485,31 +491,25 @@ gfx::Rect Label::GetAvailableRect() const {
return bounds;
}
-void Label::CalculateDrawStringParams(string16* paint_text,
+void Label::CalculateDrawStringParams(base::string16* paint_text,
gfx::Rect* text_bounds,
int* flags) const {
DCHECK(paint_text && text_bounds && flags);
- // TODO(msw): Use ElideRectangleText to support eliding multi-line text. Once
- // this is done, we can set NO_ELLIPSIS unconditionally at the bottom.
- if (is_multi_line_ || (elide_behavior_ == NO_ELIDE)) {
- *paint_text = text_;
- } else if (elide_behavior_ == ELIDE_IN_MIDDLE) {
- *paint_text = gfx::ElideText(text_, font_list_, GetAvailableRect().width(),
- gfx::ELIDE_IN_MIDDLE);
- } else if (elide_behavior_ == ELIDE_AT_END) {
- *paint_text = gfx::ElideText(text_, font_list_, GetAvailableRect().width(),
- gfx::ELIDE_AT_END);
+ const bool forbid_ellipsis = elide_behavior_ == gfx::TRUNCATE ||
+ elide_behavior_ == gfx::FADE_TAIL;
+ if (is_multi_line_ || forbid_ellipsis) {
+ *paint_text = layout_text();
} else {
- DCHECK_EQ(ELIDE_AS_EMAIL, elide_behavior_);
- *paint_text = gfx::ElideEmail(text_, font_list_,
- GetAvailableRect().width());
+ *paint_text = gfx::ElideText(layout_text(), font_list_,
+ GetAvailableRect().width(), elide_behavior_);
}
*text_bounds = GetTextBounds();
*flags = ComputeDrawStringFlags();
- if (!is_multi_line_ || (elide_behavior_ == NO_ELIDE))
- *flags |= gfx::Canvas::NO_ELLIPSIS;
+ // TODO(msw): Elide multi-line text with ElideRectangleText instead.
+ if (!is_multi_line_ || forbid_ellipsis)
+ *flags |= gfx::Canvas::NO_ELLIPSIS;
}
void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
@@ -536,8 +536,9 @@ void Label::ResetCachedSize() {
}
bool Label::ShouldShowDefaultTooltip() const {
- return !is_multi_line_ &&
- gfx::GetStringWidth(text_, font_list_) > GetAvailableRect().width();
+ return !is_multi_line_ && !is_obscured_ &&
+ gfx::GetStringWidth(layout_text(), font_list_) >
+ GetAvailableRect().width();
}
} // namespace views
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 40534ff654f..f146b18d4af 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -13,61 +13,33 @@
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/font_list.h"
+#include "ui/gfx/shadow_value.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/view.h"
namespace views {
-/////////////////////////////////////////////////////////////////////////////
-//
-// Label class
-//
-// A label is a view subclass that can display a string.
-//
-/////////////////////////////////////////////////////////////////////////////
+// A view subclass that can display a string.
class VIEWS_EXPORT Label : public View {
public:
// Internal class name.
static const char kViewClassName[];
- // The following enum is used to indicate whether using the Chrome UI's
- // directionality as the label's directionality, or auto-detecting the label's
- // directionality.
- //
- // If the label text originates from the Chrome UI, we should use the Chrome
- // UI's directionality as the label's directionality.
- //
- // If the text originates from a web page, its directionality is determined
- // based on its first character with strong directionality, disregarding what
- // directionality the Chrome UI is.
- enum DirectionalityMode {
- USE_UI_DIRECTIONALITY = 0,
- AUTO_DETECT_DIRECTIONALITY
- };
-
- enum ElideBehavior {
- NO_ELIDE, // Do not elide the label text; truncate as needed.
- ELIDE_IN_MIDDLE, // Add ellipsis in the middle of the string as needed.
- ELIDE_AT_END, // Add ellipsis at the end of the string as needed.
- ELIDE_AS_EMAIL, // Elide while retaining username/domain chars as needed.
- };
+ // The padding for the focus border when rendering focused text.
+ static const int kFocusBorderPadding;
Label();
- explicit Label(const string16& text);
- Label(const string16& text, const gfx::FontList& font_list);
- Label(const string16& text, const gfx::Font& font); // OBSOLETE
+ explicit Label(const base::string16& text);
+ Label(const base::string16& text, const gfx::FontList& font_list);
virtual ~Label();
// Gets or sets the fonts used by this label.
const gfx::FontList& font_list() const { return font_list_; }
virtual void SetFontList(const gfx::FontList& font_list);
- // Obsolete gfx::Font version. Should use gfx::FontList version instead.
- const gfx::Font& font() const; // OBSOLETE
- virtual void SetFont(const gfx::Font& font); // OBSOLETE
// Get or set the label text.
- const string16& text() const { return text_; }
- void SetText(const string16& text);
+ const base::string16& text() const { return text_; }
+ virtual void SetText(const base::string16& text);
// Enables or disables auto-color-readability (enabled by default). If this
// is enabled, then calls to set any foreground or background color will
@@ -87,37 +59,30 @@ class VIEWS_EXPORT Label : public View {
void SetBackgroundColor(SkColor color);
SkColor background_color() const { return background_color_; }
- // Enables a drop shadow underneath the text.
- void SetShadowColors(SkColor enabled_color, SkColor disabled_color);
-
- // Sets the drop shadow's offset from the text.
- void SetShadowOffset(int x, int y);
+ // Set drop shadows underneath the text.
+ void set_shadows(const gfx::ShadowValues& shadows) {
+ shadows_ = shadows;
+ text_size_valid_ = false;
+ }
+ const gfx::ShadowValues& shadows() const { return shadows_; }
- // Disables shadows.
- void ClearEmbellishing();
+ // Sets whether subpixel rendering is used; the default is true, but this
+ // feature also requires an opaque background color.
+ void set_subpixel_rendering_enabled(bool subpixel_rendering_enabled) {
+ subpixel_rendering_enabled_ = subpixel_rendering_enabled;
+ }
- // Sets horizontal alignment. If the locale is RTL, and the directionality
- // mode is USE_UI_DIRECTIONALITY, the alignment is flipped around.
- //
- // Caveat: for labels originating from a web page, the directionality mode
- // should be reset to AUTO_DETECT_DIRECTIONALITY before the horizontal
- // alignment is set. Otherwise, the label's alignment specified as a parameter
- // will be flipped in RTL locales.
+ // Sets the horizontal alignment; the argument value is mirrored in RTL UI.
void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
+ gfx::HorizontalAlignment GetHorizontalAlignment() const;
- gfx::HorizontalAlignment horizontal_alignment() const {
- return horizontal_alignment_;
- }
-
- // Sets the directionality mode. The directionality mode is initialized to
- // USE_UI_DIRECTIONALITY when the label is constructed. USE_UI_DIRECTIONALITY
- // applies to every label that originates from the Chrome UI. However, if the
- // label originates from a web page, its directionality is auto-detected.
- void set_directionality_mode(DirectionalityMode mode) {
+ // Sets the directionality mode. The default value is DIRECTIONALITY_FROM_UI,
+ // which should be suitable for most text originating from UI string assets.
+ // Most text originating from web content should use DIRECTIONALITY_FROM_TEXT.
+ void set_directionality_mode(gfx::DirectionalityMode mode) {
directionality_mode_ = mode;
}
-
- DirectionalityMode directionality_mode() const {
+ gfx::DirectionalityMode directionality_mode() const {
return directionality_mode_;
}
@@ -131,20 +96,27 @@ class VIEWS_EXPORT Label : public View {
bool is_multi_line() const { return is_multi_line_; }
void SetMultiLine(bool multi_line);
+ // Get or set if the label text should be obscured before rendering (e.g.
+ // should "Password!" display as "*********"); default is false.
+ bool is_obscured() const { return is_obscured_; }
+ void SetObscured(bool obscured);
+
+ // Get the text as displayed to the user, respecting the 'obscured' flag.
+ const base::string16& layout_text() const { return layout_text_; }
+
// Sets whether the label text can be split on words.
// Default is false. This only works when is_multi_line is true.
void SetAllowCharacterBreak(bool allow_character_break);
- // Sets whether the label text should be elided in the middle or end (if
- // necessary). The default is to elide at the end.
- // NOTE: Eliding in the middle is not supported for multi-line strings.
- void SetElideBehavior(ElideBehavior elide_behavior);
+ // Sets the eliding or fading behavior, applied as necessary. The default is
+ // to elide at the end. Eliding is not well supported for multi-line labels.
+ void SetElideBehavior(gfx::ElideBehavior elide_behavior);
// Sets the tooltip text. Default behavior for a label (single-line) is to
// show the full text if it is wider than its bounds. Calling this overrides
// the default behavior and lets you set a custom tooltip. To revert to
// default behavior, call this with an empty string.
- void SetTooltipText(const string16& tooltip_text);
+ void SetTooltipText(const base::string16& tooltip_text);
// Resizes the label so its width is set to the width of the longest line and
// its height deduced accordingly.
@@ -160,33 +132,33 @@ class VIEWS_EXPORT Label : public View {
void set_collapse_when_hidden(bool value) { collapse_when_hidden_ = value; }
bool collapse_when_hidden() const { return collapse_when_hidden_; }
- void SetHasFocusBorder(bool has_focus_border);
-
- // Overridden from View:
+ // View:
virtual gfx::Insets GetInsets() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
// Overridden to compute the size required to display this label.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ // Returns the width of an ellipsis if the label is non-empty, or 0 otherwise.
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
// Returns the height necessary to display this label with the provided width.
// This method is used to layout multi-line labels. It is equivalent to
// GetPreferredSize().height() if the receiver is not multi-line.
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual View* GetTooltipHandlerForPoint(const gfx::Point& point) OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Gets the tooltip text for labels that are wider than their bounds, except
// when the label is multiline, in which case it just returns false (no
// tooltip). If a custom tooltip has been specified with SetTooltipText()
// it is returned instead.
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
protected:
// Called by Paint to paint the text. Override this to change how
// text is painted.
virtual void PaintText(gfx::Canvas* canvas,
- const string16& text,
+ const base::string16& text,
const gfx::Rect& text_bounds,
int flags);
@@ -207,12 +179,14 @@ class VIEWS_EXPORT Label : public View {
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawMultiLineString);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawSingleLineStringInRTL);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DrawMultiLineStringInRTL);
- FRIEND_TEST_ALL_PREFIXES(LabelTest, AutoDetectDirectionality);
-
- // Calls ComputeDrawStringFlags().
+ FRIEND_TEST_ALL_PREFIXES(LabelTest, DirectionalityFromText);
FRIEND_TEST_ALL_PREFIXES(LabelTest, DisableSubpixelRendering);
- void Init(const string16& text, const gfx::FontList& font_list);
+ // Sets both |text_| and |layout_text_| to appropriate values, taking
+ // the label's 'obscured' status into account.
+ void SetTextInternal(const base::string16& text);
+
+ void Init(const base::string16& text, const gfx::FontList& font_list);
void RecalculateColors();
@@ -224,7 +198,7 @@ class VIEWS_EXPORT Label : public View {
gfx::Rect GetAvailableRect() const;
// Returns parameters to be used for the DrawString call.
- void CalculateDrawStringParams(string16* paint_text,
+ void CalculateDrawStringParams(base::string16* paint_text,
gfx::Rect* text_bounds,
int* flags) const;
@@ -237,7 +211,8 @@ class VIEWS_EXPORT Label : public View {
bool ShouldShowDefaultTooltip() const;
- string16 text_;
+ base::string16 text_;
+ base::string16 layout_text_;
gfx::FontList font_list_;
SkColor requested_enabled_color_;
SkColor actual_enabled_color_;
@@ -250,39 +225,27 @@ class VIEWS_EXPORT Label : public View {
bool disabled_color_set_;
bool background_color_set_;
+ bool subpixel_rendering_enabled_;
bool auto_color_readability_;
mutable gfx::Size text_size_;
mutable bool text_size_valid_;
int line_height_;
bool is_multi_line_;
+ bool is_obscured_;
bool allow_character_break_;
- ElideBehavior elide_behavior_;
+ gfx::ElideBehavior elide_behavior_;
gfx::HorizontalAlignment horizontal_alignment_;
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
// Whether to collapse the label when it's not visible.
bool collapse_when_hidden_;
- // The following member variable is used to control whether the
- // directionality is auto-detected based on first strong directionality
- // character or is determined by chrome UI's locale.
- DirectionalityMode directionality_mode_;
- // When embedded in a larger control that is focusable, setting this flag
- // allows this view to reserve space for a focus border that it otherwise
- // might not have because it is not itself focusable.
- bool has_focus_border_;
-
- // Colors for shadow.
- SkColor enabled_shadow_color_;
- SkColor disabled_shadow_color_;
-
- // Space between text and shadow.
- gfx::Point shadow_offset_;
-
- // Should a shadow be drawn behind the text?
- bool has_shadow_;
+ // Controls whether the directionality is auto-detected based on first strong
+ // directionality character or is determined by the application UI's locale.
+ gfx::DirectionalityMode directionality_mode_;
+ gfx::ShadowValues shadows_;
// The cached heights to avoid recalculation in GetHeightForWidth().
- std::vector<gfx::Size> cached_heights_;
- int cached_heights_cursor_;
+ mutable std::vector<gfx::Size> cached_heights_;
+ mutable int cached_heights_cursor_;
DISALLOW_COPY_AND_ASSIGN(Label);
};
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index e2a37c3a167..8b16d0f6844 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -7,16 +7,25 @@
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/views/border.h"
+using base::ASCIIToUTF16;
+
namespace views {
// All text sizing measurements (width and height) should be greater than this.
const int kMinTextDimension = 4;
+// A test utility function to set the application default text direction.
+void SetRTL(bool rtl) {
+ // Override the current locale/direction.
+ base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
+ EXPECT_EQ(rtl, base::i18n::IsRTL());
+}
+
TEST(LabelTest, FontPropertySymbol) {
Label label;
std::string font_name("symbol");
@@ -39,7 +48,7 @@ TEST(LabelTest, FontPropertyArial) {
TEST(LabelTest, TextProperty) {
Label label;
- string16 test_text(ASCIIToUTF16("A random string."));
+ base::string16 test_text(ASCIIToUTF16("A random string."));
label.SetText(test_text);
EXPECT_EQ(test_text, label.text());
}
@@ -53,38 +62,45 @@ TEST(LabelTest, ColorProperty) {
}
TEST(LabelTest, AlignmentProperty) {
- Label label;
- bool reverse_alignment = base::i18n::IsRTL();
+ const bool was_rtl = base::i18n::IsRTL();
- label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
- EXPECT_EQ(reverse_alignment ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT,
- label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
- EXPECT_EQ(reverse_alignment ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
- label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
- EXPECT_EQ(gfx::ALIGN_CENTER, label.horizontal_alignment());
+ Label label;
+ for (size_t i = 0; i < 2; ++i) {
+ // Toggle the application default text direction (to try each direction).
+ SetRTL(!base::i18n::IsRTL());
+ bool reverse_alignment = base::i18n::IsRTL();
+
+ // The alignment should be flipped in RTL UI.
+ label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+ EXPECT_EQ(reverse_alignment ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT,
+ label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ EXPECT_EQ(reverse_alignment ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
+ label.GetHorizontalAlignment());
+ label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
+ EXPECT_EQ(gfx::ALIGN_CENTER, label.GetHorizontalAlignment());
+
+ for (size_t j = 0; j < 2; ++j) {
+ label.SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
+ const bool rtl = j == 0;
+ label.SetText(rtl ? base::WideToUTF16(L"\x5d0") : ASCIIToUTF16("A"));
+ EXPECT_EQ(rtl ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
+ label.GetHorizontalAlignment());
+ }
+ }
- // The label's alignment should not be flipped if the directionality mode is
- // AUTO_DETECT_DIRECTIONALITY.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
- EXPECT_EQ(gfx::ALIGN_RIGHT, label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
- EXPECT_EQ(gfx::ALIGN_LEFT, label.horizontal_alignment());
- label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
- EXPECT_EQ(gfx::ALIGN_CENTER, label.horizontal_alignment());
+ EXPECT_EQ(was_rtl, base::i18n::IsRTL());
}
TEST(LabelTest, DirectionalityModeProperty) {
Label label;
- EXPECT_EQ(Label::USE_UI_DIRECTIONALITY, label.directionality_mode());
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_UI, label.directionality_mode());
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- EXPECT_EQ(Label::AUTO_DETECT_DIRECTIONALITY, label.directionality_mode());
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_TEXT, label.directionality_mode());
- label.set_directionality_mode(Label::USE_UI_DIRECTIONALITY);
- EXPECT_EQ(Label::USE_UI_DIRECTIONALITY, label.directionality_mode());
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_UI);
+ EXPECT_EQ(gfx::DIRECTIONALITY_FROM_UI, label.directionality_mode());
}
TEST(LabelTest, MultiLineProperty) {
@@ -96,24 +112,59 @@ TEST(LabelTest, MultiLineProperty) {
EXPECT_FALSE(label.is_multi_line());
}
-TEST(LabelTest, TooltipProperty) {
+TEST(LabelTest, ObscuredProperty) {
Label label;
- string16 test_text(ASCIIToUTF16("My cool string."));
+ base::string16 test_text(ASCIIToUTF16("Password!"));
label.SetText(test_text);
- string16 tooltip;
+ // Should be false by default...
+ EXPECT_FALSE(label.is_obscured());
+ EXPECT_EQ(test_text, label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+
+ label.SetObscured(true);
+ EXPECT_TRUE(label.is_obscured());
+ EXPECT_EQ(ASCIIToUTF16("*********"), label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+
+ label.SetText(test_text + test_text);
+ EXPECT_EQ(ASCIIToUTF16("******************"), label.layout_text());
+ EXPECT_EQ(test_text + test_text, label.text());
+
+ label.SetObscured(false);
+ EXPECT_FALSE(label.is_obscured());
+ EXPECT_EQ(test_text + test_text, label.layout_text());
+ EXPECT_EQ(test_text + test_text, label.text());
+}
+
+TEST(LabelTest, ObscuredSurrogatePair) {
+ // 'MUSICAL SYMBOL G CLEF': represented in UTF-16 as two characters
+ // forming the surrogate pair 0x0001D11E.
+ Label label;
+ base::string16 test_text = base::UTF8ToUTF16("\xF0\x9D\x84\x9E");
+ label.SetText(test_text);
+
+ label.SetObscured(true);
+ EXPECT_EQ(ASCIIToUTF16("*"), label.layout_text());
+ EXPECT_EQ(test_text, label.text());
+}
+
+TEST(LabelTest, TooltipProperty) {
+ Label label;
+ label.SetText(ASCIIToUTF16("My cool string."));
+
+ base::string16 tooltip;
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(test_text, tooltip);
+ EXPECT_EQ(label.text(), tooltip);
- string16 tooltip_text(ASCIIToUTF16("The tooltip!"));
+ base::string16 tooltip_text(ASCIIToUTF16("The tooltip!"));
label.SetTooltipText(tooltip_text);
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
- string16 empty_text;
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(test_text, tooltip);
+ EXPECT_EQ(label.text(), tooltip);
// Make the label big enough to hold the text
// and expect there to be no tooltip.
@@ -125,13 +176,21 @@ TEST(LabelTest, TooltipProperty) {
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
// Clear out the tooltip.
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
// Shrink the bounds and the tooltip should come back.
label.SetBounds(0, 0, 1, 1);
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
- // Make the label multiline and there is no tooltip again.
+ // Make the label obscured and there is no tooltip.
+ label.SetObscured(true);
+ EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
+
+ // Obscuring the text shouldn't permanently clobber the tooltip.
+ label.SetObscured(false);
+ EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
+
+ // Make the label multiline and there is no tooltip.
label.SetMultiLine(true);
EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
@@ -140,25 +199,23 @@ TEST(LabelTest, TooltipProperty) {
EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
// Clear out the tooltip.
- label.SetTooltipText(empty_text);
+ label.SetTooltipText(base::string16());
}
TEST(LabelTest, Accessibility) {
Label label;
- string16 test_text(ASCIIToUTF16("My special text."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("My special text."));
- ui::AccessibleViewState state;
+ ui::AXViewState state;
label.GetAccessibleState(&state);
- EXPECT_EQ(ui::AccessibilityTypes::ROLE_STATICTEXT, state.role);
- EXPECT_EQ(test_text, state.name);
- EXPECT_TRUE(ui::AccessibilityTypes::STATE_READONLY & state.state);
+ EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, state.role);
+ EXPECT_EQ(label.text(), state.name);
+ EXPECT_TRUE(state.HasStateFlag(ui::AX_STATE_READ_ONLY));
}
TEST(LabelTest, SingleLineSizing) {
Label label;
- string16 test_text(ASCIIToUTF16("A not so random string in one line."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("A not so random string in one line."));
// GetPreferredSize
gfx::Size required_size = label.GetPreferredSize();
@@ -167,10 +224,8 @@ TEST(LabelTest, SingleLineSizing) {
// Test everything with borders.
gfx::Insets border(10, 20, 30, 40);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
// GetPreferredSize and borders.
label.SetBounds(0, 0, 0, 0);
@@ -183,28 +238,23 @@ TEST(LabelTest, SingleLineSizing) {
TEST(LabelTest, MultilineSmallAvailableWidthSizing) {
Label label;
- string16 test_text(ASCIIToUTF16("Too Wide."));
-
label.SetMultiLine(true);
label.SetAllowCharacterBreak(true);
- label.SetElideBehavior(Label::ELIDE_AT_END);
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Too Wide."));
// Check that Label can be laid out at a variety of small sizes,
// splitting the words into up to one character per line if necessary.
// Incorrect word splitting may cause infinite loops in text layout.
gfx::Size required_size = label.GetPreferredSize();
- for (int i = 1; i < required_size.width(); ++i) {
+ for (int i = 1; i < required_size.width(); ++i)
EXPECT_GT(label.GetHeightForWidth(i), 0);
- }
}
TEST(LabelTest, MultiLineSizing) {
Label label;
label.SetFocusable(false);
- string16 test_text(
+ label.SetText(
ASCIIToUTF16("A random string\nwith multiple lines\nand returns!"));
- label.SetText(test_text);
label.SetMultiLine(true);
// GetPreferredSize
@@ -248,10 +298,8 @@ TEST(LabelTest, MultiLineSizing) {
// Test everything with borders.
gfx::Insets border(10, 20, 30, 40);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
// SizeToFit and borders.
label.SizeToFit(0);
@@ -283,37 +331,23 @@ TEST(LabelTest, MultiLineSizing) {
required_size.width() + border.width());
}
-TEST(LabelTest, AutoDetectDirectionality) {
+TEST(LabelTest, DirectionalityFromText) {
Label label;
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ label.SetBounds(0, 0, 1000, 1000);
+ base::string16 paint_text;
+ gfx::Rect text_bounds;
+ int flags = -1;
// Test text starts with RTL character.
- string16 test_text(WideToUTF16(L" \x5d0\x5d1\x5d2 abc"));
- label.SetText(test_text);
- gfx::Size required_size(label.GetPreferredSize());
- gfx::Size extra(22, 8);
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
- required_size.height() + extra.height());
-
- string16 paint_text;
- gfx::Rect text_bounds;
- int flags;
+ label.SetText(base::WideToUTF16(L" \x5d0\x5d1\x5d2 abc"));
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_RTL_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY));
// Test text starts with LTR character.
- test_text = (WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
- label.SetText(test_text);
- required_size = label.GetPreferredSize();
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
- required_size.height() + extra.height());
-
+ label.SetText(base::WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
EXPECT_EQ(gfx::Canvas::FORCE_LTR_DIRECTIONALITY,
flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
@@ -323,28 +357,23 @@ TEST(LabelTest, AutoDetectDirectionality) {
TEST(LabelTest, DrawSingleLineString) {
Label label;
label.SetFocusable(false);
+ // Force a directionality to simplify alignment value testing.
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FORCE_LTR);
- // Turn off mirroring so that we don't need to figure out if
- // align right really means align left.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
-
- string16 test_text(ASCIIToUTF16("Here's a string with no returns."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Here's a string with no returns."));
gfx::Size required_size(label.GetPreferredSize());
gfx::Size extra(22, 8);
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
+ label.SetBounds(0, 0, required_size.width() + extra.width(),
required_size.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically.
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -360,7 +389,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -376,7 +405,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -389,19 +418,15 @@ TEST(LabelTest, DrawSingleLineString) {
// Test single line drawing with a border.
gfx::Insets border(39, 34, 8, 96);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
gfx::Size required_size_with_border(label.GetPreferredSize());
EXPECT_EQ(required_size.width() + border.width(),
required_size_with_border.width());
EXPECT_EQ(required_size.height() + border.height(),
required_size_with_border.height());
- label.SetBounds(0,
- 0,
- required_size_with_border.width() + extra.width(),
+ label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
required_size_with_border.height() + extra.height());
// Centered text with border.
@@ -409,7 +434,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically within the border.
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -425,7 +450,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -441,7 +466,7 @@ TEST(LabelTest, DrawSingleLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -453,33 +478,29 @@ TEST(LabelTest, DrawSingleLineString) {
gfx::Canvas::TEXT_ALIGN_RIGHT));
}
-// On Linux the underlying pango routines require a max height in order to
-// ellide multiline text. So until that can be resolved, we set all
-// multiline lables to not ellide in Linux only.
+// Pango needs a max height to elide multiline text; that is not supported here.
TEST(LabelTest, DrawMultiLineString) {
Label label;
label.SetFocusable(false);
+ // Force a directionality to simplify alignment value testing.
+ label.set_directionality_mode(gfx::DIRECTIONALITY_FORCE_LTR);
+ // Set a background color to prevent gfx::Canvas::NO_SUBPIXEL_RENDERING flags.
+ label.SetBackgroundColor(SK_ColorWHITE);
- // Turn off mirroring so that we don't need to figure out if
- // align right really means align left.
- label.set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
-
- string16 test_text(ASCIIToUTF16("Another string\nwith returns\n\n!"));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
label.SetMultiLine(true);
label.SizeToFit(0);
gfx::Size extra(50, 10);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -487,18 +508,17 @@ TEST(LabelTest, DrawMultiLineString) {
int expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_CENTER |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
gfx::Rect center_bounds(text_bounds);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -506,17 +526,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_LEFT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
@@ -524,21 +543,17 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_RIGHT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
// Test multiline drawing with a border.
gfx::Insets border(19, 92, 23, 2);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
label.SizeToFit(0);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
@@ -546,7 +561,7 @@ TEST(LabelTest, DrawMultiLineString) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -554,17 +569,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_CENTER |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -572,17 +586,16 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_LEFT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() + border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
@@ -590,11 +603,10 @@ TEST(LabelTest, DrawMultiLineString) {
expected_flags = gfx::Canvas::MULTI_LINE |
gfx::Canvas::TEXT_ALIGN_RIGHT |
gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
-#if defined(OS_WIN)
- EXPECT_EQ(expected_flags, flags);
-#else
- EXPECT_EQ(expected_flags | gfx::Canvas::NO_ELLIPSIS, flags);
+#if !defined(OS_WIN)
+ expected_flags |= gfx::Canvas::NO_ELLIPSIS;
#endif
+ EXPECT_EQ(expected_flags, expected_flags);
}
TEST(LabelTest, DrawSingleLineStringInRTL) {
@@ -604,23 +616,20 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- string16 test_text(ASCIIToUTF16("Here's a string with no returns."));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Here's a string with no returns."));
gfx::Size required_size(label.GetPreferredSize());
gfx::Size extra(22, 8);
- label.SetBounds(0,
- 0,
- required_size.width() + extra.width(),
+ label.SetBounds(0, 0, required_size.width() + extra.width(),
required_size.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
// Centered text.
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically.
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -636,7 +645,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -652,7 +661,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2 , text_bounds.y());
@@ -666,19 +675,15 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
// Test single line drawing with a border.
gfx::Insets border(39, 34, 8, 96);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
gfx::Size required_size_with_border(label.GetPreferredSize());
EXPECT_EQ(required_size.width() + border.width(),
required_size_with_border.width());
EXPECT_EQ(required_size.height() + border.height(),
required_size_with_border.height());
- label.SetBounds(0,
- 0,
- required_size_with_border.width() + extra.width(),
+ label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
required_size_with_border.height() + extra.height());
// Centered text with border.
@@ -686,7 +691,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be centered horizontally and vertically within the border.
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -702,7 +707,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be right aligned horizontally and centered vertically.
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -718,7 +723,7 @@ TEST(LabelTest, DrawSingleLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
// The text should be left aligned horizontally and centered vertically.
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
@@ -744,34 +749,28 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("he");
- string16 test_text(ASCIIToUTF16("Another string\nwith returns\n\n!"));
- label.SetText(test_text);
+ label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
label.SetMultiLine(true);
label.SizeToFit(0);
gfx::Size extra(50, 10);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
// Do some basic verifications for all three alignments.
- string16 paint_text;
+ base::string16 paint_text;
gfx::Rect text_bounds;
- int flags;
+ int flags = -1;
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width() / 2, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_CENTER |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
gfx::Rect center_bounds(text_bounds);
@@ -779,49 +778,38 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(extra.width(), text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_RIGHT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_RIGHT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(0, text_bounds.x());
EXPECT_EQ(extra.height() / 2, text_bounds.y());
EXPECT_GT(text_bounds.width(), kMinTextDimension);
EXPECT_GT(text_bounds.height(), kMinTextDimension);
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_LEFT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
// Test multiline drawing with a border.
gfx::Insets border(19, 92, 23, 2);
- label.set_border(Border::CreateEmptyBorder(border.top(),
- border.left(),
- border.bottom(),
- border.right()));
+ label.SetBorder(Border::CreateEmptyBorder(
+ border.top(), border.left(), border.bottom(), border.right()));
label.SizeToFit(0);
- label.SetBounds(label.x(),
- label.y(),
+ label.SetBounds(label.x(), label.y(),
label.width() + extra.width(),
label.height() + extra.height());
@@ -829,75 +817,64 @@ TEST(LabelTest, DrawMultiLineStringInRTL) {
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_CENTER |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_RIGHT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_RIGHT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
paint_text.clear();
text_bounds.SetRect(0, 0, 0, 0);
label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
- EXPECT_EQ(test_text, paint_text);
+ EXPECT_EQ(label.text(), paint_text);
EXPECT_EQ(border.left(), text_bounds.x());
EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
EXPECT_EQ(center_bounds.width(), text_bounds.width());
EXPECT_EQ(center_bounds.height(), text_bounds.height());
-#if defined(OS_WIN)
- EXPECT_EQ(gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_LEFT, flags);
-#else
- EXPECT_EQ(
- gfx::Canvas::MULTI_LINE |
- gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::NO_ELLIPSIS,
- flags);
+ EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
+ EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
+#if !defined(OS_WIN)
+ EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
#endif
// Reset Locale
base::i18n::SetICUDefaultLocale(locale);
}
-// Check that we disable subpixel rendering when a transparent background is
-// being used.
+// Ensure the subpixel rendering flag and background color alpha are respected.
TEST(LabelTest, DisableSubpixelRendering) {
Label label;
label.SetBackgroundColor(SK_ColorWHITE);
- EXPECT_EQ(
- 0, label.ComputeDrawStringFlags() & gfx::Canvas::NO_SUBPIXEL_RENDERING);
-
+ const int flag = gfx::Canvas::NO_SUBPIXEL_RENDERING;
+ EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
+ label.set_subpixel_rendering_enabled(false);
+ EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
+ label.set_subpixel_rendering_enabled(true);
+ EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
+ // Text cannot be drawn with subpixel rendering on transparent backgrounds.
label.SetBackgroundColor(SkColorSetARGB(64, 255, 255, 255));
- EXPECT_EQ(
- gfx::Canvas::NO_SUBPIXEL_RENDERING,
- label.ComputeDrawStringFlags() & gfx::Canvas::NO_SUBPIXEL_RENDERING);
+ EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
}
// Check that labels support GetTooltipHandlerForPoint.
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index d02a0b89c73..d8a08a40c92 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -8,27 +8,25 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/link_listener.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
const char Link::kViewClassName[] = "Link";
-Link::Link() : Label(string16()) {
+Link::Link() : Label(base::string16()) {
Init();
}
-Link::Link(const string16& title) : Label(title) {
+Link::Link(const base::string16& title) : Label(title) {
Init();
}
@@ -43,11 +41,6 @@ SkColor Link::GetDefaultEnabledColor() {
#endif
}
-void Link::OnEnabledChanged() {
- RecalculateFont();
- View::OnEnabledChanged();
-}
-
const char* Link::GetClassName() const {
return kViewClassName;
}
@@ -55,37 +48,13 @@ const char* Link::GetClassName() const {
gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
if (!enabled())
return gfx::kNullCursor;
-#if defined(USE_AURA)
- return ui::kCursorHand;
-#elif defined(OS_WIN)
- static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_HAND);
- return g_hand_cursor;
-#endif
-}
-
-void Link::OnPaint(gfx::Canvas* canvas) {
- Label::OnPaint(canvas);
-
- if (HasFocus())
- canvas->DrawFocusRect(GetLocalBounds());
-}
-
-void Link::OnFocus() {
- Label::OnFocus();
- // We render differently focused.
- SchedulePaint();
-}
-
-void Link::OnBlur() {
- Label::OnBlur();
- // We render differently focused.
- SchedulePaint();
+ return GetNativeHandCursor();
}
-bool Link::HitTestRect(const gfx::Rect& rect) const {
- // We need to allow clicks on the link. So we override the implementation in
- // Label and use the default implementation of View.
- return View::HitTestRect(rect);
+bool Link::CanProcessEventsWithinSubtree() const {
+ // Links need to be able to accept events (e.g., clicking) even though
+ // in general Labels do not.
+ return View::CanProcessEventsWithinSubtree();
}
bool Link::OnMousePressed(const ui::MouseEvent& event) {
@@ -139,17 +108,6 @@ bool Link::OnKeyPressed(const ui::KeyEvent& event) {
return true;
}
-bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
- // Make sure we don't process space or enter as accelerators.
- return (event.key_code() == ui::VKEY_SPACE) ||
- (event.key_code() == ui::VKEY_RETURN);
-}
-
-void Link::GetAccessibleState(ui::AccessibleViewState* state) {
- Label::GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_LINK;
-}
-
void Link::OnGestureEvent(ui::GestureEvent* event) {
if (!enabled())
return;
@@ -167,9 +125,45 @@ void Link::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
-void Link::SetFont(const gfx::Font& font) {
- Label::SetFont(font);
+bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
+ // Make sure we don't process space or enter as accelerators.
+ return (event.key_code() == ui::VKEY_SPACE) ||
+ (event.key_code() == ui::VKEY_RETURN);
+}
+
+void Link::GetAccessibleState(ui::AXViewState* state) {
+ Label::GetAccessibleState(state);
+ state->role = ui::AX_ROLE_LINK;
+}
+
+void Link::OnEnabledChanged() {
RecalculateFont();
+ View::OnEnabledChanged();
+}
+
+void Link::OnFocus() {
+ Label::OnFocus();
+ // We render differently focused.
+ SchedulePaint();
+}
+
+void Link::OnBlur() {
+ Label::OnBlur();
+ // We render differently focused.
+ SchedulePaint();
+}
+
+void Link::SetFontList(const gfx::FontList& font_list) {
+ Label::SetFontList(font_list);
+ RecalculateFont();
+}
+
+void Link::SetText(const base::string16& text) {
+ Label::SetText(text);
+ // Disable focusability for empty links. Otherwise Label::GetInsets() will
+ // give them an unconditional 1-px. inset on every side to allow for a focus
+ // border, when in this case we probably wanted zero width.
+ SetFocusable(!text.empty());
}
void Link::SetEnabledColor(SkColor color) {
@@ -205,7 +199,12 @@ void Link::Init() {
SetPressedColor(SK_ColorRED);
#endif
RecalculateFont();
- SetFocusable(true);
+
+ // Label::Init() calls SetText(), but if that's being called from Label(), our
+ // SetText() override will not be reached (because the constructed class is
+ // only a Label at the moment, not yet a Link). So so the set_focusable()
+ // call explicitly here.
+ SetFocusable(!text().empty());
}
void Link::SetPressed(bool pressed) {
@@ -220,11 +219,11 @@ void Link::SetPressed(bool pressed) {
void Link::RecalculateFont() {
// Underline the link iff it is enabled and |underline_| is true.
- const int style = font().GetStyle();
+ const int style = font_list().GetFontStyle();
const int intended_style = (enabled() && underline_) ?
(style | gfx::Font::UNDERLINE) : (style & ~gfx::Font::UNDERLINE);
if (style != intended_style)
- Label::SetFont(font().DeriveFont(0, intended_style));
+ Label::SetFontList(font_list().DeriveWithStyle(intended_style));
}
} // namespace views
diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h
index f6a876de863..4d5cf6b7afa 100644
--- a/chromium/ui/views/controls/link.h
+++ b/chromium/ui/views/controls/link.h
@@ -25,7 +25,7 @@ class LinkListener;
class VIEWS_EXPORT Link : public Label {
public:
Link();
- explicit Link(const string16& title);
+ explicit Link(const base::string16& title);
virtual ~Link();
static SkColor GetDefaultEnabledColor();
@@ -33,30 +33,26 @@ class VIEWS_EXPORT Link : public Label {
const LinkListener* listener() { return listener_; }
void set_listener(LinkListener* listener) { listener_ = listener; }
- // Overridden from View:
- virtual void OnEnabledChanged() OVERRIDE;
+ // Label:
virtual const char* GetClassName() const OVERRIDE;
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool SkipDefaultKeyEventProcessing(
const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
-
- // Overridden from ui::EventHandler:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
- // Overridden from Label:
- virtual void SetFont(const gfx::Font& font) OVERRIDE;
-
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnEnabledChanged() OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual void SetFontList(const gfx::FontList& font_list) OVERRIDE;
+ virtual void SetText(const base::string16& text) OVERRIDE;
virtual void SetEnabledColor(SkColor color) OVERRIDE;
+
void SetPressedColor(SkColor color);
void SetUnderline(bool underline);
diff --git a/chromium/ui/views/controls/menu/display_change_listener_mac.cc b/chromium/ui/views/controls/menu/display_change_listener_mac.cc
new file mode 100644
index 00000000000..d9dfeda5cfd
--- /dev/null
+++ b/chromium/ui/views/controls/menu/display_change_listener_mac.cc
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_runner.h"
+
+namespace views {
+namespace internal {
+
+// static
+DisplayChangeListener* DisplayChangeListener::Create(Widget*, MenuRunner*) {
+ return NULL;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu.cc b/chromium/ui/views/controls/menu/menu.cc
index 597dba4419f..0cffae8f50e 100644
--- a/chromium/ui/views/controls/menu/menu.cc
+++ b/chromium/ui/views/controls/menu/menu.cc
@@ -17,8 +17,8 @@ bool Menu::Delegate::IsItemDefault(int id) const {
return false;
}
-string16 Menu::Delegate::GetLabel(int id) const {
- return string16();
+base::string16 Menu::Delegate::GetLabel(int id) const {
+ return base::string16();
}
bool Menu::Delegate::GetAcceleratorInfo(int id, ui::Accelerator* accel) {
@@ -49,7 +49,7 @@ bool Menu::Delegate::IsCommandEnabled(int id) const {
return true;
}
-bool Menu::Delegate::GetContextualLabel(int id, string16* out) const {
+bool Menu::Delegate::GetContextualLabel(int id, base::string16* out) const {
return false;
}
@@ -76,14 +76,14 @@ Menu::~Menu() {
}
void Menu::AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type) {
AddMenuItem(-1, item_id, label, type);
}
void Menu::AddMenuItem(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type) {
if (type == SEPARATOR)
AddSeparator(index);
@@ -91,27 +91,27 @@ void Menu::AddMenuItem(int index,
AddMenuItemInternal(index, item_id, label, gfx::ImageSkia(), type);
}
-Menu* Menu::AppendSubMenu(int item_id, const string16& label) {
+Menu* Menu::AppendSubMenu(int item_id, const base::string16& label) {
return AddSubMenu(-1, item_id, label);
}
-Menu* Menu::AddSubMenu(int index, int item_id, const string16& label) {
+Menu* Menu::AddSubMenu(int index, int item_id, const base::string16& label) {
return AddSubMenuWithIcon(index, item_id, label, gfx::ImageSkia());
}
Menu* Menu::AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
return AddSubMenuWithIcon(-1, item_id, label, icon);
}
-void Menu::AppendMenuItemWithLabel(int item_id, const string16& label) {
+void Menu::AppendMenuItemWithLabel(int item_id, const base::string16& label) {
AddMenuItemWithLabel(-1, item_id, label);
}
void Menu::AddMenuItemWithLabel(int index,
int item_id,
- const string16& label) {
+ const base::string16& label) {
AddMenuItem(index, item_id, label, Menu::NORMAL);
}
@@ -120,7 +120,7 @@ void Menu::AppendDelegateMenuItem(int item_id) {
}
void Menu::AddDelegateMenuItem(int index, int item_id) {
- AddMenuItem(index, item_id, string16(), Menu::NORMAL);
+ AddMenuItem(index, item_id, base::string16(), Menu::NORMAL);
}
void Menu::AppendSeparator() {
@@ -128,14 +128,14 @@ void Menu::AppendSeparator() {
}
void Menu::AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
AddMenuItemWithIcon(-1, item_id, label, icon);
}
void Menu::AddMenuItemWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
AddMenuItemInternal(index, item_id, label, icon, Menu::NORMAL);
}
diff --git a/chromium/ui/views/controls/menu/menu.h b/chromium/ui/views/controls/menu/menu.h
index 5a774df7320..099a98ee543 100644
--- a/chromium/ui/views/controls/menu/menu.h
+++ b/chromium/ui/views/controls/menu/menu.h
@@ -45,7 +45,7 @@ class VIEWS_EXPORT Menu {
virtual bool IsItemDefault(int id) const;
// The string shown for the menu item.
- virtual string16 GetLabel(int id) const;
+ virtual base::string16 GetLabel(int id) const;
// The delegate needs to implement this function if it wants to display
// the shortcut text next to each menu item. If there is an accelerator
@@ -94,7 +94,7 @@ class VIEWS_EXPORT Menu {
// Controller
virtual bool SupportsCommand(int id) const;
virtual bool IsCommandEnabled(int id) const;
- virtual bool GetContextualLabel(int id, string16* out) const;
+ virtual bool GetContextualLabel(int id, base::string16* out) const;
virtual void ExecuteCommand(int id) {
}
@@ -151,35 +151,37 @@ class VIEWS_EXPORT Menu {
// label The text label shown.
// type The type of item.
void AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type);
void AddMenuItem(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
MenuItemType type);
// Append a submenu to this menu.
// The returned pointer is owned by this menu.
Menu* AppendSubMenu(int item_id,
- const string16& label);
- Menu* AddSubMenu(int index, int item_id, const string16& label);
+ const base::string16& label);
+ Menu* AddSubMenu(int index, int item_id, const base::string16& label);
// Append a submenu with an icon to this menu
// The returned pointer is owned by this menu.
// Unless the icon is empty, calling this function forces the Menu class
// to draw the menu, instead of relying on Windows.
Menu* AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
virtual Menu* AddSubMenuWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) = 0;
// This is a convenience for standard text label menu items where the label
// is provided with this call.
- void AppendMenuItemWithLabel(int item_id, const string16& label);
- void AddMenuItemWithLabel(int index, int item_id, const string16& label);
+ void AppendMenuItemWithLabel(int item_id, const base::string16& label);
+ void AddMenuItemWithLabel(int index,
+ int item_id,
+ const base::string16& label);
// This is a convenience for text label menu items where the label is
// provided by the delegate.
@@ -194,11 +196,11 @@ class VIEWS_EXPORT Menu {
// needs an icon. Calling this function forces the Menu class to draw
// the menu, instead of relying on Windows.
void AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
virtual void AddMenuItemWithIcon(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// Enables or disables the item with the specified id.
@@ -206,7 +208,7 @@ class VIEWS_EXPORT Menu {
virtual void EnableMenuItemAt(int index, bool enabled) = 0;
// Sets menu label at specified index.
- virtual void SetMenuLabel(int item_id, const string16& label) = 0;
+ virtual void SetMenuLabel(int item_id, const base::string16& label) = 0;
// Sets an icon for an item with a given item_id. Calling this function
// also forces the Menu class to draw the menu, instead of relying on Windows.
@@ -234,7 +236,7 @@ class VIEWS_EXPORT Menu {
virtual void AddMenuItemInternal(int index,
int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon,
MenuItemType type) = 0;
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 1c34ac0b3e0..9eaba83f6db 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -5,14 +5,11 @@
#include "ui/views/controls/menu/menu_config.h"
#include "build/build_config.h"
-#include "ui/base/layout.h"
-#include "ui/native_theme/native_theme.h"
namespace views {
MenuConfig::MenuConfig(const ui::NativeTheme* theme)
- : text_color(SK_ColorBLACK),
- arrow_color(SK_ColorBLACK),
+ : arrow_color(SK_ColorBLACK),
menu_vertical_border_size(3),
menu_horizontal_border_size(0),
submenu_horizontal_inset(3),
@@ -28,8 +25,6 @@ MenuConfig::MenuConfig(const ui::NativeTheme* theme)
check_width(16),
check_height(16),
radio_width(16),
- radio_height(16),
- arrow_height(9),
arrow_width(9),
gutter_width(0),
separator_height(11),
@@ -48,12 +43,6 @@ MenuConfig::MenuConfig(const ui::NativeTheme* theme)
native_theme(theme),
show_delay(400),
corner_radius(0) {
- // Use 40px tall menu items when running in touch optimized mode.
- // For Windows use 40px tall menu items when running in touch optimized mode.
- if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
- item_top_margin = item_no_icon_top_margin = 12;
- item_bottom_margin = item_no_icon_bottom_margin = 13;
- }
Init(theme);
}
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index 96eb21ac219..3cdbccdbf4d 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -6,7 +6,7 @@
#define UI_VIEWS_CONTROLS_MENU_MENU_CONFIG_H_
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/views_export.h"
namespace ui {
@@ -23,11 +23,8 @@ struct VIEWS_EXPORT MenuConfig {
static const MenuConfig& instance(const ui::NativeTheme* theme);
- // Font used by menus.
- gfx::Font font;
-
- // Normal text color.
- SkColor text_color;
+ // Font list used by menus.
+ gfx::FontList font_list;
// Color for the arrow to scroll bookmarks.
SkColor arrow_color;
@@ -70,12 +67,10 @@ struct VIEWS_EXPORT MenuConfig {
int check_width;
int check_height;
- // Size of the radio bullet.
+ // Width of the radio bullet.
int radio_width;
- int radio_height;
- // Size of the submenu arrow.
- int arrow_height;
+ // Width of the submenu arrow.
int arrow_width;
// Width of the gutter. Only used if render_gutter is true.
@@ -136,9 +131,7 @@ struct VIEWS_EXPORT MenuConfig {
void Init(const ui::NativeTheme* theme);
// TODO: temporary until we standardize.
-#if defined(USE_AURA)
void InitAura(const ui::NativeTheme* theme);
-#endif
};
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_aura.cc b/chromium/ui/views/controls/menu/menu_config_aura.cc
new file mode 100644
index 00000000000..2e464d22488
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_config_aura.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_config.h"
+
+#include "grit/ui_resources.h"
+#include "ui/base/layout.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/native_theme/native_theme_aura.h"
+#include "ui/views/controls/menu/menu_image_util.h"
+
+namespace views {
+
+namespace {
+#if defined(OS_CHROMEOS)
+static const int kMenuCornerRadiusForAura = 2;
+#else
+static const int kMenuCornerRadiusForAura = 0;
+#endif
+} // namespace
+
+#if !defined(OS_WIN)
+void MenuConfig::Init(const ui::NativeTheme* theme) {
+ if (theme == ui::NativeThemeAura::instance())
+ InitAura(theme);
+}
+#endif
+
+void MenuConfig::InitAura(const ui::NativeTheme* theme) {
+ submenu_horizontal_inset = 1;
+ arrow_to_edge_padding = 20;
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ arrow_width = rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).Width();
+ gfx::ImageSkia check = GetMenuCheckImage(false);
+ check_height = check.height();
+ item_min_height = 29;
+ separator_spacing_height = 7;
+ separator_lower_height = 8;
+ separator_upper_height = 8;
+ label_to_arrow_padding = 20;
+ label_to_minor_text_padding = 20;
+ always_use_icon_to_label_padding = true;
+ align_arrow_and_shortcut = true;
+ offset_context_menus = true;
+ corner_radius = kMenuCornerRadiusForAura;
+}
+
+#if !defined(OS_WIN)
+// static
+const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
+ static MenuConfig* views_instance = NULL;
+ if (!views_instance)
+ views_instance = new MenuConfig(theme ?
+ theme : ui::NativeTheme::instance());
+ return *views_instance;
+}
+#endif
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_mac.cc b/chromium/ui/views/controls/menu/menu_config_mac.cc
new file mode 100644
index 00000000000..dd38e72fe7e
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_config_mac.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_config.h"
+
+#include "grit/ui_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/native_theme/native_theme_mac.h"
+#include "ui/views/controls/menu/menu_image_util.h"
+
+namespace views {
+
+void MenuConfig::Init(const ui::NativeTheme* theme) {
+ NOTIMPLEMENTED();
+}
+
+// static
+const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
+ CR_DEFINE_STATIC_LOCAL(
+ MenuConfig, mac_instance, (theme ? theme : ui::NativeTheme::instance()));
+ return mac_instance;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_views.cc b/chromium/ui/views/controls/menu/menu_config_views.cc
deleted file mode 100644
index d0b48443711..00000000000
--- a/chromium/ui/views/controls/menu/menu_config_views.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_config.h"
-
-#include "grit/ui_resources.h"
-#include "ui/base/layout.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/native_theme/native_theme_aura.h"
-#include "ui/views/controls/menu/menu_image_util.h"
-
-namespace views {
-
-namespace {
-#if defined(OS_CHROMEOS)
-static const int kMenuCornerRadiusForAura = 2;
-#else
-static const int kMenuCornerRadiusForAura = 0;
-#endif
-} // namespace
-
-#if !defined(OS_WIN)
-void MenuConfig::Init(const ui::NativeTheme* theme) {
- if (theme == ui::NativeThemeAura::instance())
- InitAura(theme);
-}
-#endif
-
-void MenuConfig::InitAura(const ui::NativeTheme* theme) {
- text_color = theme->GetSystemColor(
- ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
- submenu_horizontal_inset = 1;
- arrow_to_edge_padding = 20;
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- arrow_width =
- rb.GetImageNamed(IDR_MENU_HIERARCHY_ARROW).ToImageSkia()->width();
- gfx::ImageSkia check = GetMenuCheckImage(false);
- check_height = check.height();
- item_min_height = 29;
- separator_spacing_height = 7;
- separator_lower_height = 8;
- separator_upper_height = 8;
- font = rb.GetFont(ResourceBundle::BaseFont);
- label_to_arrow_padding = 20;
- label_to_minor_text_padding = 20;
- always_use_icon_to_label_padding = true;
- align_arrow_and_shortcut = true;
- offset_context_menus = true;
- corner_radius = kMenuCornerRadiusForAura;
-}
-
-#if !defined(OS_WIN)
-// static
-const MenuConfig& MenuConfig::instance(const ui::NativeTheme* theme) {
- static MenuConfig* views_instance = NULL;
- if (!views_instance)
- views_instance = new MenuConfig(theme ?
- theme : ui::NativeTheme::instance());
- return *views_instance;
-}
-#endif
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_win.cc b/chromium/ui/views/controls/menu/menu_config_win.cc
index e0bde54c30b..4ef5fac3070 100644
--- a/chromium/ui/views/controls/menu/menu_config_win.cc
+++ b/chromium/ui/views/controls/menu/menu_config_win.cc
@@ -13,11 +13,8 @@
#include "base/win/win_util.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/gfx/color_utils.h"
-#include "ui/native_theme/native_theme_win.h"
-
-#if defined(USE_AURA)
#include "ui/native_theme/native_theme_aura.h"
-#endif
+#include "ui/native_theme/native_theme_win.h"
using ui::NativeTheme;
using ui::NativeThemeWin;
@@ -25,15 +22,10 @@ using ui::NativeThemeWin;
namespace views {
void MenuConfig::Init(const NativeTheme* theme) {
-#if defined(USE_AURA)
if (theme == ui::NativeThemeAura::instance()) {
InitAura(theme);
return;
}
-#endif
- text_color = NativeThemeWin::instance()->GetThemeColorWithDefault(
- NativeThemeWin::MENU, MENU_POPUPITEM, MPI_NORMAL, TMT_TEXTCOLOR,
- COLOR_MENUTEXT);
arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
@@ -43,7 +35,7 @@ void MenuConfig::Init(const NativeTheme* theme) {
{
base::win::ScopedHFONT new_font(CreateFontIndirect(&metrics.lfMenuFont));
DLOG_ASSERT(new_font.Get());
- font = gfx::Font(new_font);
+ font_list = gfx::FontList(gfx::Font(new_font));
}
NativeTheme::ExtraParams extra;
extra.menu_check.is_radio = false;
@@ -61,23 +53,18 @@ void MenuConfig::Init(const NativeTheme* theme) {
extra.menu_check.is_radio = true;
gfx::Size radio_size = NativeThemeWin::instance()->GetPartSize(
NativeTheme::kMenuCheck, NativeTheme::kNormal, extra);
- if (!radio_size.IsEmpty()) {
+ if (!radio_size.IsEmpty())
radio_width = radio_size.width();
- radio_height = radio_size.height();
- } else {
+ else
radio_width = GetSystemMetrics(SM_CXMENUCHECK);
- radio_height = GetSystemMetrics(SM_CYMENUCHECK);
- }
gfx::Size arrow_size = NativeThemeWin::instance()->GetPartSize(
NativeTheme::kMenuPopupArrow, NativeTheme::kNormal, extra);
if (!arrow_size.IsEmpty()) {
arrow_width = arrow_size.width();
- arrow_height = arrow_size.height();
} else {
// Sadly I didn't see a specify metrics for this.
arrow_width = GetSystemMetrics(SM_CXMENUCHECK);
- arrow_height = GetSystemMetrics(SM_CYMENUCHECK);
}
BOOL show_cues;
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 3b0e5d552c0..d5b5a84e8f1 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -4,23 +4,18 @@
#include "ui/views/controls/menu/menu_controller.h"
-#if defined(OS_WIN)
-#include <windowsx.h>
-#endif
-
#include "base/i18n/case_conversion.h"
#include "base/i18n/rtl.h"
-#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/event_constants.h"
+#include "ui/events/event.h"
#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/vector2d.h"
#include "ui/native_theme/native_theme.h"
@@ -28,32 +23,26 @@
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_host_root_view.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/drag_utils.h"
-#include "ui/views/event_utils.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/mouse_constants.h"
+#include "ui/views/view.h"
#include "ui/views/view_constants.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#endif
-
#if defined(OS_WIN)
-#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/base/win/internal_constants.h"
+#include "ui/gfx/win/dpi.h"
#include "ui/views/win/hwnd_util.h"
#endif
-#if defined(USE_X11)
-#include <X11/Xlib.h>
-#endif
-
using base::Time;
using base::TimeDelta;
using ui::OSExchangeData;
@@ -87,17 +76,17 @@ const int kBubbleTipSizeTopBottom = 11;
const float kMaximumLengthMovedToActivate = 4.0f;
// Returns true if the mnemonic of |menu| matches key.
-bool MatchesMnemonic(MenuItemView* menu, char16 key) {
- return menu->GetMnemonic() == key;
+bool MatchesMnemonic(MenuItemView* menu, base::char16 key) {
+ return key != 0 && menu->GetMnemonic() == key;
}
// Returns true if |menu| doesn't have a mnemonic and first character of the its
// title is |key|.
-bool TitleMatchesMnemonic(MenuItemView* menu, char16 key) {
+bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) {
if (menu->GetMnemonic())
return false;
- string16 lower_title = base::i18n::ToLower(menu->title());
+ base::string16 lower_title = base::i18n::ToLower(menu->title());
return !lower_title.empty() && lower_title[0] == key;
}
@@ -279,8 +268,9 @@ struct MenuController::SelectByCharDetails {
MenuController::State::State()
: item(NULL),
submenu_open(false),
- anchor(MenuItemView::TOPLEFT),
- context_menu(false) {}
+ anchor(MENU_ANCHOR_TOPLEFT),
+ context_menu(false) {
+}
MenuController::State::~State() {}
@@ -298,7 +288,7 @@ MenuItemView* MenuController::Run(Widget* parent,
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu,
int* result_event_flags) {
exit_type_ = EXIT_NONE;
@@ -385,7 +375,7 @@ MenuItemView* MenuController::Run(Widget* parent,
// Close any open menus.
SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
-#if defined(OS_WIN) && defined(USE_AURA)
+#if defined(OS_WIN)
// On Windows, if we select the menu item by touch and if the window at the
// location is another window on the same thread, that window gets a
// WM_MOUSEACTIVATE message and ends up activating itself, which is not
@@ -400,7 +390,7 @@ MenuItemView* MenuController::Run(Widget* parent,
HWND window = ::WindowFromPoint(cursor_pos);
if (::GetWindowThreadProcessId(window, NULL) ==
::GetCurrentThreadId()) {
- ::SetProp(window, views::kIgnoreTouchMouseActivateForWindow,
+ ::SetProp(window, ui::kIgnoreTouchMouseActivateForWindow,
reinterpret_cast<HANDLE>(true));
}
}
@@ -596,13 +586,11 @@ void MenuController::OnMouseEntered(SubmenuView* source,
// do anything here.
}
-#if defined(USE_AURA)
bool MenuController::OnMouseWheel(SubmenuView* source,
const ui::MouseWheelEvent& event) {
MenuPart part = GetMenuPart(source, event.location());
return part.submenu && part.submenu->OnMouseWheel(event);
}
-#endif
void MenuController::OnGestureEvent(SubmenuView* source,
ui::GestureEvent* event) {
@@ -809,6 +797,7 @@ void MenuController::OnWidgetDestroying(Widget* widget) {
DCHECK_EQ(owner_, widget);
owner_->RemoveObserver(this);
owner_ = NULL;
+ message_loop_->ClearOwner();
}
// static
@@ -875,7 +864,7 @@ void MenuController::SetSelection(MenuItemView* menu_item,
(MenuDepth(menu_item) != 1 ||
menu_item->GetType() != MenuItemView::SUBMENU)) {
menu_item->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
+ ui::AX_EVENT_FOCUS, true);
}
}
@@ -912,14 +901,7 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
#if defined(OS_WIN)
// We're going to close and we own the mouse capture. We need to repost the
// mouse down, otherwise the window the user clicked on won't get the event.
- if (!state_.item) {
- // We some times get an event after closing all the menus. Ignore it. Make
- // sure the menu is in fact not visible. If the menu is visible, then
- // we're in a bad state where we think the menu isn't visibile but it is.
- DCHECK(!source->GetWidget()->IsVisible());
- } else {
- RepostEvent(source, event);
- }
+ RepostEvent(source, event);
#endif
// And close.
@@ -936,14 +918,15 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
}
Cancel(exit_type);
-#if defined(USE_AURA) && !defined(OS_WIN)
+#if defined(OS_CHROMEOS)
// We're going to exit the menu and want to repost the event so that is
// is handled normally after the context menu has exited. We call
// RepostEvent after Cancel so that mouse capture has been released so
// that finding the event target is unaffected by the current capture.
RepostEvent(source, event);
#endif
-
+ // Do not repost events for Linux Aura because this behavior is more
+ // consistent with the behavior of other Linux apps.
return;
}
@@ -982,7 +965,7 @@ void MenuController::StartDrag(SubmenuView* source,
OSExchangeData data;
item->GetDelegate()->WriteDragData(item, &data);
- drag_utils::SetDragImageOnDataObject(*canvas, item->size(),
+ drag_utils::SetDragImageOnDataObject(*canvas,
press_loc.OffsetFromOrigin(),
&data);
StopScrolling();
@@ -1002,94 +985,6 @@ void MenuController::StartDrag(SubmenuView* source,
} // else case, someone canceled us, don't do anything
}
-#if defined(OS_WIN)
-bool MenuController::Dispatch(const MSG& msg) {
- DCHECK(blocking_run_);
-
- if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) {
- // We must translate/dispatch the message here, otherwise we would drop
- // the message on the floor.
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return false;
- }
-
- // NOTE: we don't get WM_ACTIVATE or anything else interesting in here.
- switch (msg.message) {
- case WM_CONTEXTMENU: {
- MenuItemView* item = pending_state_.item;
- if (item && item->GetRootMenuItem() != item) {
- gfx::Point screen_loc(0, item->height());
- View::ConvertPointToScreen(item, &screen_loc);
- ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
- if (GET_X_LPARAM(msg.lParam) == -1 && GET_Y_LPARAM(msg.lParam) == -1)
- source_type = ui::MENU_SOURCE_KEYBOARD;
- item->GetDelegate()->ShowContextMenu(item, item->GetCommand(),
- screen_loc, source_type);
- }
- return true;
- }
-
- // NOTE: focus wasn't changed when the menu was shown. As such, don't
- // dispatch key events otherwise the focused window will get the events.
- case WM_KEYDOWN: {
- bool result = OnKeyDown(ui::KeyboardCodeFromNative(msg));
- TranslateMessage(&msg);
- return result;
- }
- case WM_CHAR:
- return !SelectByChar(static_cast<char16>(msg.wParam));
- case WM_KEYUP:
- return true;
-
- case WM_SYSKEYUP:
- // We may have been shown on a system key, as such don't do anything
- // here. If another system key is pushed we'll get a WM_SYSKEYDOWN and
- // close the menu.
- return true;
-
- case WM_CANCELMODE:
- case WM_SYSKEYDOWN:
- // Exit immediately on system keys.
- Cancel(EXIT_ALL);
- return false;
-
- default:
- break;
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return exit_type_ == EXIT_NONE;
-}
-#elif defined(USE_AURA)
-bool MenuController::Dispatch(const base::NativeEvent& event) {
- if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) {
- aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
- return false;
- }
- // Activates mnemonics only when it it pressed without modifiers except for
- // caps and shift.
- int flags = ui::EventFlagsFromNative(event) &
- ~ui::EF_CAPS_LOCK_DOWN & ~ui::EF_SHIFT_DOWN;
- if (flags == ui::EF_NONE) {
- switch (ui::EventTypeFromNative(event)) {
- case ui::ET_KEY_PRESSED:
- if (!OnKeyDown(ui::KeyboardCodeFromNative(event)))
- return false;
-
- return !SelectByChar(ui::KeyboardCodeFromNative(event));
- case ui::ET_KEY_RELEASED:
- return true;
- default:
- break;
- }
- }
-
- aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
- return exit_type_ == EXIT_NONE;
-}
-#endif
-
bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
DCHECK(blocking_run_);
@@ -1124,7 +1019,7 @@ bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
break;
case ui::VKEY_F4:
- if (!accept_on_f4_)
+ if (!is_combobox_)
break;
// Fallthrough to accept on F4, so combobox menus match Windows behavior.
case ui::VKEY_RETURN:
@@ -1156,11 +1051,6 @@ bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
CloseSubmenu();
break;
-#if defined(OS_WIN)
- case VK_APPS:
- break;
-#endif
-
default:
break;
}
@@ -1191,8 +1081,9 @@ MenuController::MenuController(ui::NativeTheme* theme,
menu_config_(theme),
closing_event_time_(base::TimeDelta()),
menu_start_time_(base::TimeTicks()),
- accept_on_f4_(false),
- item_selected_by_touch_(false) {
+ is_combobox_(false),
+ item_selected_by_touch_(false),
+ message_loop_(MenuMessageLoop::Create()) {
active_instance_ = this;
}
@@ -1206,6 +1097,10 @@ MenuController::~MenuController() {
StopCancelAllTimer();
}
+void MenuController::RunMessageLoop(bool nested_menu) {
+ message_loop_->Run(this, owner_, nested_menu);
+}
+
MenuController::SendAcceleratorResultType
MenuController::SendAcceleratorToHotTrackedView() {
CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item);
@@ -1220,10 +1115,9 @@ MenuController::SendAcceleratorResultType
ACCELERATOR_PROCESSED : ACCELERATOR_PROCESSED_EXIT;
}
-void MenuController::UpdateInitialLocation(
- const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
- bool context_menu) {
+void MenuController::UpdateInitialLocation(const gfx::Rect& bounds,
+ MenuAnchorPosition position,
+ bool context_menu) {
pending_state_.context_menu = context_menu;
pending_state_.initial_bounds = bounds;
if (bounds.height() > 1) {
@@ -1234,10 +1128,10 @@ void MenuController::UpdateInitialLocation(
// Reverse anchor position for RTL languages.
if (base::i18n::IsRTL() &&
- (position == MenuItemView::TOPRIGHT ||
- position == MenuItemView::TOPLEFT)) {
- pending_state_.anchor = position == MenuItemView::TOPRIGHT ?
- MenuItemView::TOPLEFT : MenuItemView::TOPRIGHT;
+ (position == MENU_ANCHOR_TOPRIGHT || position == MENU_ANCHOR_TOPLEFT)) {
+ pending_state_.anchor = position == MENU_ANCHOR_TOPRIGHT
+ ? MENU_ANCHOR_TOPLEFT
+ : MENU_ANCHOR_TOPRIGHT;
} else {
pending_state_.anchor = position;
}
@@ -1246,7 +1140,7 @@ void MenuController::UpdateInitialLocation(
// avoid repeated system queries for the info.
pending_state_.monitor_bounds = GetScreen()->GetDisplayNearestPoint(
bounds.origin()).work_area();
-#if defined(USE_ASH)
+
if (!pending_state_.monitor_bounds.Contains(bounds)) {
// Use the monitor area if the work area doesn't contain the bounds. This
// handles showing a menu from the launcher.
@@ -1255,7 +1149,6 @@ void MenuController::UpdateInitialLocation(
if (monitor_area.Contains(bounds))
pending_state_.monitor_bounds = monitor_area;
}
-#endif
}
void MenuController::Accept(MenuItemView* item, int event_flags) {
@@ -1293,7 +1186,7 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source,
// if there is a sibling menu we should show.
gfx::Point screen_point(mouse_location);
View::ConvertPointToScreen(source_view, &screen_point);
- MenuItemView::AnchorPosition anchor;
+ MenuAnchorPosition anchor;
bool has_mnemonics;
MenuButton* button = NULL;
MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
@@ -1717,11 +1610,11 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
x += 1;
y = state_.initial_bounds.bottom();
- if (state_.anchor == MenuItemView::TOPRIGHT) {
+ if (state_.anchor == MENU_ANCHOR_TOPRIGHT) {
x = x + state_.initial_bounds.width() - pref.width();
if (menu_config.offset_context_menus && state_.context_menu)
x -= 1;
- } else if (state_.anchor == MenuItemView::BOTTOMCENTER) {
+ } else if (state_.anchor == MENU_ANCHOR_BOTTOMCENTER) {
x = x - (pref.width() - state_.initial_bounds.width()) / 2;
if (pref.height() >
state_.initial_bounds.y() + kCenteredContextMenuYOffset) {
@@ -1770,7 +1663,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
// The menu should never overlap the owning button. So move it.
// We use the anchor view style to determine the preferred position
// relative to the owning button.
- if (state_.anchor == MenuItemView::TOPLEFT) {
+ if (state_.anchor == MENU_ANCHOR_TOPLEFT) {
// The menu starts with the same x coordinate as the owning button.
if (x + state_.initial_bounds.width() + pref.width() >
state_.monitor_bounds.right())
@@ -1883,16 +1776,16 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
int max_height = state_.monitor_bounds.height();
// In case of bubbles, the maximum width is limited by the space
// between the display corner and the target area + the tip size.
- if (state_.anchor == MenuItemView::BUBBLE_LEFT) {
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT) {
max_width = owner_bounds.x() - state_.monitor_bounds.x() +
kBubbleTipSizeLeftRight;
- } else if (state_.anchor == MenuItemView::BUBBLE_RIGHT) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
max_width = state_.monitor_bounds.right() - owner_bounds.right() +
kBubbleTipSizeLeftRight;
- } else if (state_.anchor == MenuItemView::BUBBLE_ABOVE) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE) {
max_height = owner_bounds.y() - state_.monitor_bounds.y() +
kBubbleTipSizeTopBottom;
- } else if (state_.anchor == MenuItemView::BUBBLE_BELOW) {
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
max_height = state_.monitor_bounds.bottom() - owner_bounds.bottom() +
kBubbleTipSizeTopBottom;
}
@@ -1907,9 +1800,9 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
item->GetDelegate()->GetMaxWidthForMenu(item)));
int x, y;
- if (state_.anchor == MenuItemView::BUBBLE_ABOVE ||
- state_.anchor == MenuItemView::BUBBLE_BELOW) {
- if (state_.anchor == MenuItemView::BUBBLE_ABOVE)
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
+ state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE)
y = owner_bounds.y() - pref.height() + kBubbleTipSizeTopBottom;
else
y = owner_bounds.bottom() - kBubbleTipSizeTopBottom;
@@ -1924,7 +1817,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
pref.width() / 2 - x + x_old);
} else {
- if (state_.anchor == MenuItemView::BUBBLE_RIGHT)
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
x = owner_bounds.right() - kBubbleTipSizeLeftRight;
else
x = owner_bounds.x() - pref.width() + kBubbleTipSizeLeftRight;
@@ -2046,8 +1939,8 @@ void MenuController::CloseSubmenu() {
MenuController::SelectByCharDetails MenuController::FindChildForMnemonic(
MenuItemView* parent,
- char16 key,
- bool (*match_function)(MenuItemView* menu, char16 mnemonic)) {
+ base::char16 key,
+ bool (*match_function)(MenuItemView* menu, base::char16 mnemonic)) {
SubmenuView* submenu = parent->GetSubmenu();
DCHECK(submenu);
SelectByCharDetails details;
@@ -2098,9 +1991,9 @@ bool MenuController::AcceptOrSelect(MenuItemView* parent,
return false;
}
-bool MenuController::SelectByChar(char16 character) {
- char16 char_array[] = { character, 0 };
- char16 key = base::i18n::ToLower(char_array)[0];
+bool MenuController::SelectByChar(base::char16 character) {
+ base::char16 char_array[] = { character, 0 };
+ base::char16 key = base::i18n::ToLower(char_array)[0];
MenuItemView* item = pending_state_.item;
if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing())
item = item->GetParentMenuItem();
@@ -2116,61 +2009,114 @@ bool MenuController::SelectByChar(char16 character) {
if (details.first_match != -1)
return AcceptOrSelect(item, details);
- // If no mnemonics found, look at first character of titles.
- details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
- if (details.first_match != -1)
- return AcceptOrSelect(item, details);
+ if (is_combobox_) {
+ item->GetSubmenu()->GetTextInputClient()->InsertChar(character, 0);
+ } else {
+ // If no mnemonics found, look at first character of titles.
+ details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
+ if (details.first_match != -1)
+ return AcceptOrSelect(item, details);
+ }
return false;
}
void MenuController::RepostEvent(SubmenuView* source,
const ui::LocatedEvent& event) {
+ if (!event.IsMouseEvent()) {
+ // TODO(rbyers): Gesture event repost is tricky to get right
+ // crbug.com/170987.
+ DCHECK(event.IsGestureEvent());
+ return;
+ }
+
+#if defined(OS_WIN)
+ if (!state_.item) {
+ // We some times get an event after closing all the menus. Ignore it. Make
+ // sure the menu is in fact not visible. If the menu is visible, then
+ // we're in a bad state where we think the menu isn't visibile but it is.
+ DCHECK(!source->GetWidget()->IsVisible());
+ return;
+ }
+
+ state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture();
+#endif
+
gfx::Point screen_loc(event.location());
View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
-
gfx::NativeView native_view = source->GetWidget()->GetNativeView();
+ if (!native_view)
+ return;
+
gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc);
- if (!window)
- return;
-
#if defined(OS_WIN)
- // Release the capture.
- SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu();
- submenu->ReleaseCapture();
-
- gfx::NativeView view = submenu->GetWidget()->GetNativeView();
- if (view) {
- DWORD view_tid = GetWindowThreadProcessId(HWNDForNativeView(view), NULL);
- if (view_tid != GetWindowThreadProcessId(HWNDForNativeView(window), NULL)) {
+ // Convert screen_loc to pixels for the Win32 API's like WindowFromPoint,
+ // PostMessage/SendMessage to work correctly. These API's expect the
+ // coordinates to be in pixels.
+ // PostMessage() to metro windows isn't allowed (access will be denied). Don't
+ // try to repost with Win32 if the window under the mouse press is in metro.
+ if (!ViewsDelegate::views_delegate ||
+ !ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
+ gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc);
+ HWND target_window = window ? HWNDForNativeWindow(window) :
+ WindowFromPoint(screen_loc_pixels.ToPOINT());
+ HWND source_window = HWNDForNativeView(native_view);
+ if (!target_window || !source_window ||
+ GetWindowThreadProcessId(source_window, NULL) !=
+ GetWindowThreadProcessId(target_window, NULL)) {
// Even though we have mouse capture, windows generates a mouse event if
// the other window is in a separate thread. Only repost an event if
- // |view| was created on the same thread, else the target window can get
- // double events leading to bad behavior.
+ // |target_window| and |source_window| were created on the same thread,
+ // else double events can occur and lead to bad behavior.
return;
}
- }
-#endif
- scoped_ptr<ui::LocatedEvent> clone;
- if (event.IsMouseEvent()) {
- clone.reset(new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event)));
- } else if (event.IsGestureEvent()) {
- // TODO(rbyers): Gesture event repost is tricky to get right
- // crbug.com/170987.
- return;
- } else {
- NOTREACHED();
+ // Determine whether the click was in the client area or not.
+ // NOTE: WM_NCHITTEST coordinates are relative to the screen.
+ LPARAM coords = MAKELPARAM(screen_loc_pixels.x(), screen_loc_pixels.y());
+ LRESULT nc_hit_result = SendMessage(target_window, WM_NCHITTEST, 0, coords);
+ const bool client_area = nc_hit_result == HTCLIENT;
+
+ // TODO(sky): this isn't right. The event to generate should correspond with
+ // the event we just got. MouseEvent only tells us what is down, which may
+ // differ. Need to add ability to get changed button from MouseEvent.
+ int event_type;
+ int flags = event.flags();
+ if (flags & ui::EF_LEFT_MOUSE_BUTTON) {
+ event_type = client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
+ } else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) {
+ event_type = client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN;
+ } else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) {
+ event_type = client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN;
+ } else {
+ NOTREACHED();
+ return;
+ }
+
+ int window_x = screen_loc_pixels.x();
+ int window_y = screen_loc_pixels.y();
+ if (client_area) {
+ POINT pt = { window_x, window_y };
+ ScreenToClient(target_window, &pt);
+ window_x = pt.x;
+ window_y = pt.y;
+ }
+
+ WPARAM target = client_area ? event.native_event().wParam : nc_hit_result;
+ LPARAM window_coords = MAKELPARAM(window_x, window_y);
+ PostMessage(target_window, event_type, target, window_coords);
return;
}
- clone->set_location(screen_loc);
+#endif
+ // Non-Windows Aura or |window| is in metro mode.
+ if (!window)
+ return;
- RepostLocatedEvent(window, *clone);
+ message_loop_->RepostEventToWindow(event, window, screen_loc);
}
-
void MenuController::SetDropMenuItem(
MenuItemView* new_target,
MenuDelegate::DropPosition new_position) {
@@ -2230,12 +2176,13 @@ void MenuController::UpdateActiveMouseView(SubmenuView* event_source,
target_menu, active_mouse_view, &target_point);
ui::MouseEvent mouse_entered_event(ui::ET_MOUSE_ENTERED,
target_point, target_point,
- 0);
+ 0, 0);
active_mouse_view->OnMouseEntered(mouse_entered_event);
ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED,
target_point, target_point,
- event.flags());
+ event.flags(),
+ event.changed_button_flags());
active_mouse_view->OnMousePressed(mouse_pressed_event);
}
}
@@ -2245,7 +2192,8 @@ void MenuController::UpdateActiveMouseView(SubmenuView* event_source,
View::ConvertPointToTarget(target_menu, active_mouse_view, &target_point);
ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED,
target_point, target_point,
- event.flags());
+ event.flags(),
+ event.changed_button_flags());
active_mouse_view->OnMouseDragged(mouse_dragged_event);
}
}
@@ -2261,7 +2209,7 @@ void MenuController::SendMouseReleaseToActiveView(SubmenuView* event_source,
&target_loc);
View::ConvertPointFromScreen(active_mouse_view, &target_loc);
ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, target_loc, target_loc,
- event.flags());
+ event.flags(), event.changed_button_flags());
// Reset active mouse view before sending mouse released. That way if it calls
// back to us, we aren't in a weird state.
SetActiveMouseView(NULL);
@@ -2293,20 +2241,22 @@ View* MenuController::GetActiveMouseView() {
void MenuController::SetExitType(ExitType type) {
exit_type_ = type;
// Exit nested message loops as soon as possible. We do this as
- // MessageLoop::Dispatcher is only invoked before native events, which means
+ // MessagePumpDispatcher is only invoked before native events, which means
// its entirely possible for a Widget::CloseNow() task to be processed before
- // the next native message. By using QuitNow() we ensures the nested message
- // loop returns as soon as possible and avoids having deleted views classes
- // (such as widgets and rootviews) on the stack when the nested message loop
- // stops.
+ // the next native message. We quite the nested message loop as soon as
+ // possible to avoid having deleted views classes (such as widgets and
+ // rootviews) on the stack when the nested message loop stops.
//
- // It's safe to invoke QuitNow multiple times, it only effects the current
- // loop.
- bool quit_now = ShouldQuitNow() && exit_type_ != EXIT_NONE &&
+ // It's safe to invoke QuitNestedMessageLoop() multiple times, it only effects
+ // the current loop.
+ bool quit_now = message_loop_->ShouldQuitNow() && exit_type_ != EXIT_NONE &&
message_loop_depth_;
-
if (quit_now)
- base::MessageLoop::current()->QuitNow();
+ TerminateNestedMessageLoop();
+}
+
+void MenuController::TerminateNestedMessageLoop() {
+ message_loop_->QuitNow();
}
void MenuController::HandleMouseLocation(SubmenuView* source,
@@ -2341,4 +2291,10 @@ void MenuController::HandleMouseLocation(SubmenuView* source,
}
}
+gfx::Screen* MenuController::GetScreen() {
+ Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL;
+ return root ? gfx::Screen::GetScreenFor(root->GetNativeView())
+ : gfx::Screen::GetNativeScreen();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 1404d54e5d6..30c56f0f04b 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -13,30 +13,39 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/timer/timer.h"
+#include "ui/events/event.h"
#include "ui/events/event_constants.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
-#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/widget/widget_observer.h"
-namespace ui {
-class NativeTheme;
-class OSExchangeData;
+namespace base {
+class MessagePumpDispatcher;
}
namespace gfx {
class Screen;
}
+namespace ui {
+class NativeTheme;
+class OSExchangeData;
+class ScopedEventDispatcher;
+}
namespace views {
class MenuButton;
class MenuHostRootView;
+class MenuItemView;
+class MenuMessageLoop;
class MouseEvent;
class SubmenuView;
class View;
namespace internal {
class MenuControllerDelegate;
+class MenuEventDispatcher;
+class MenuMessagePumpDispatcher;
class MenuRunnerImpl;
}
@@ -45,8 +54,7 @@ class MenuRunnerImpl;
// MenuController is used internally by the various menu classes to manage
// showing, selecting and drag/drop for menus. All relevant events are
// forwarded to the MenuController from SubmenuView and MenuHost.
-class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
- public WidgetObserver {
+class VIEWS_EXPORT MenuController : public WidgetObserver {
public:
// Enumeration of how the menu should exit.
enum ExitType {
@@ -74,7 +82,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu,
int* event_flags);
@@ -84,8 +92,12 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Whether or not drag operation is in progress.
bool drag_in_progress() const { return drag_in_progress_; }
+ // Returns the owner of child windows.
+ // WARNING: this may be NULL.
+ Widget* owner() { return owner_; }
+
// Get the anchor position wich is used to show this menu.
- MenuItemView::AnchorPosition GetAnchorPosition() { return state_.anchor; }
+ MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }
// Cancels the current Run. See ExitType for a description of what happens
// with the various parameters.
@@ -101,7 +113,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Returns the time from the event which closed the menu - or 0.
base::TimeDelta closing_event_time() const { return closing_event_time_; }
- void set_accept_on_f4(bool accept_on_f4) { accept_on_f4_ = accept_on_f4; }
+ void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
// Various events, forwarded from the submenu.
//
@@ -112,9 +124,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
-#if defined(USE_AURA)
bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
-#endif
void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
bool GetDropFormats(
@@ -142,7 +152,10 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
static void TurnOffMenuSelectionHoldForTest();
private:
+ friend class internal::MenuEventDispatcher;
+ friend class internal::MenuMessagePumpDispatcher;
friend class internal::MenuRunnerImpl;
+ friend class MenuControllerTest;
friend class MenuHostRootView;
friend class MenuItemView;
friend class SubmenuView;
@@ -194,7 +207,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
gfx::Rect initial_bounds;
// Position of the initial menu.
- MenuItemView::AnchorPosition anchor;
+ MenuAnchorPosition anchor;
// The direction child menus have opened in.
std::list<bool> open_leading;
@@ -253,10 +266,6 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
const ui::LocatedEvent& event);
void StartDrag(SubmenuView* source, const gfx::Point& location);
- // Dispatcher method. This returns true if the menu was canceled, or
- // if the message is such that the menu should be closed.
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
// Key processing. The return value of this is returned from Dispatch.
// In other words, if this returns false (which happens if escape was
// pressed, or a matching mnemonic was found) the message loop returns.
@@ -279,7 +288,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
SendAcceleratorResultType SendAcceleratorToHotTrackedView();
void UpdateInitialLocation(const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu);
// Invoked when the user accepts the selected item. This is only used
@@ -416,8 +425,8 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// |match_function| is used to determine which menus match.
SelectByCharDetails FindChildForMnemonic(
MenuItemView* parent,
- char16 key,
- bool (*match_function)(MenuItemView* menu, char16 mnemonic));
+ base::char16 key,
+ bool (*match_function)(MenuItemView* menu, base::char16 mnemonic));
// Selects or accepts the appropriate menu item based on |details|. Returns
// true if |Accept| was invoked (which happens if there aren't multiple item
@@ -426,7 +435,7 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// Selects by mnemonic, and if that doesn't work tries the first character of
// the title. Returns true if a match was selected and the menu should exit.
- bool SelectByChar(char16 key);
+ bool SelectByChar(base::char16 key);
// For Windows and Aura we repost an event for some events that dismiss
// the context menu. The event is then reprocessed to cause its result
@@ -468,9 +477,12 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
void SetActiveMouseView(View* view);
View* GetActiveMouseView();
- // Sets exit type.
+ // Sets exit type. Calling this can terminate the active nested message-loop.
void SetExitType(ExitType type);
+ // Terminates the current nested message-loop.
+ void TerminateNestedMessageLoop();
+
// Returns true if SetExitType() should quit the message loop.
bool ShouldQuitNow() const;
@@ -584,12 +596,15 @@ class VIEWS_EXPORT MenuController : public base::MessageLoop::Dispatcher,
// screen coordinates). Otherwise this will be (0, 0).
gfx::Point menu_start_mouse_press_loc_;
- // Whether the menu should accept on F4, like Windows native Combobox menus.
- bool accept_on_f4_;
+ // Controls behavior differences between a combobox and other types of menu
+ // (like a context menu).
+ bool is_combobox_;
// Set to true if the menu item was selected by touch.
bool item_selected_by_touch_;
+ scoped_ptr<MenuMessageLoop> message_loop_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};
diff --git a/chromium/ui/views/controls/menu/menu_controller_aura.cc b/chromium/ui/views/controls/menu/menu_controller_aura.cc
deleted file mode 100644
index 48bf3118ff6..00000000000
--- a/chromium/ui/views/controls/menu/menu_controller_aura.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_controller.h"
-
-#include "base/run_loop.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/dispatcher_client.h"
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-namespace {
-
-// ActivationChangeObserverImpl is used to observe activation changes and close
-// the menu. Additionally it listens for the root window to be destroyed and
-// cancel the menu as well.
-class ActivationChangeObserverImpl
- : public aura::client::ActivationChangeObserver,
- public aura::WindowObserver,
- public ui::EventHandler {
- public:
- ActivationChangeObserverImpl(MenuController* controller,
- aura::Window* root)
- : controller_(controller),
- root_(root) {
- aura::client::GetActivationClient(root_)->AddObserver(this);
- root_->AddObserver(this);
- root_->AddPreTargetHandler(this);
- }
-
- virtual ~ActivationChangeObserverImpl() {
- Cleanup();
- }
-
- // aura::client::ActivationChangeObserver overrides:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- if (!controller_->drag_in_progress())
- controller_->CancelAll();
- }
-
- // aura::WindowObserver overrides:
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- Cleanup();
- }
-
- // ui::EventHandler overrides:
- virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
- controller_->CancelAll();
- }
-
- private:
- void Cleanup() {
- if (!root_)
- return;
- // The ActivationClient may have been destroyed by the time we get here.
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(root_);
- if (client)
- client->RemoveObserver(this);
- root_->RemovePreTargetHandler(this);
- root_->RemoveObserver(this);
- root_ = NULL;
- }
-
- MenuController* controller_;
- aura::Window* root_;
-
- DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
-};
-
-aura::Window* GetOwnerRootWindow(views::Widget* owner) {
- return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
-}
-
-} // namespace
-
-void MenuController::RunMessageLoop(bool nested_menu) {
- // |owner_| may be NULL.
- aura::Window* root = GetOwnerRootWindow(owner_);
- if (root) {
- scoped_ptr<ActivationChangeObserverImpl> observer;
- if (!nested_menu)
- observer.reset(new ActivationChangeObserverImpl(this, root));
- aura::client::GetDispatcherClient(root)->
- RunWithDispatcher(this, owner_->GetNativeWindow(), true);
- } else {
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow(loop);
- base::RunLoop run_loop(this);
- run_loop.Run();
- }
-}
-
-bool MenuController::ShouldQuitNow() const {
- aura::Window* root = GetOwnerRootWindow(owner_);
- return !aura::client::GetDragDropClient(root) ||
- !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
-}
-
-gfx::Screen* MenuController::GetScreen() {
- aura::Window* root = GetOwnerRootWindow(owner_);
- return root ?
- gfx::Screen::GetScreenFor(root) : gfx::Screen::GetNativeScreen();
-}
-
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
new file mode 100644
index 00000000000..1c98f95bc9c
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_controller.h"
+
+#include "base/run_loop.h"
+#include "ui/aura/scoped_window_targeter.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_targeter.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/wm/public/dispatcher_client.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#elif defined(USE_X11)
+#include <X11/Xlib.h>
+#undef Bool
+#undef None
+#include "ui/events/test/events_test_utils_x11.h"
+#elif defined(USE_OZONE)
+#include "ui/events/event.h"
+#endif
+
+namespace views {
+
+namespace {
+
+class TestMenuItemView : public MenuItemView {
+ public:
+ TestMenuItemView() : MenuItemView(NULL) {}
+ virtual ~TestMenuItemView() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
+};
+
+class TestPlatformEventSource : public ui::PlatformEventSource {
+ public:
+ TestPlatformEventSource() {}
+ virtual ~TestPlatformEventSource() {}
+
+ uint32_t Dispatch(const ui::PlatformEvent& event) {
+ return DispatchEvent(event);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
+};
+
+class TestNullTargeter : public ui::EventTargeter {
+ public:
+ TestNullTargeter() {}
+ virtual ~TestNullTargeter() {}
+
+ virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) OVERRIDE {
+ return NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
+};
+
+class TestDispatcherClient : public aura::client::DispatcherClient {
+ public:
+ TestDispatcherClient() : dispatcher_(NULL) {}
+ virtual ~TestDispatcherClient() {}
+
+ base::MessagePumpDispatcher* dispatcher() {
+ return dispatcher_;
+ }
+
+ // aura::client::DispatcherClient:
+ virtual void PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) OVERRIDE {
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
+ *quit_closure = run_loop->QuitClosure();
+ *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
+ base::Unretained(this),
+ base::Passed(&run_loop),
+ dispatcher);
+ }
+
+ private:
+ void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop,
+ base::MessagePumpDispatcher* dispatcher) {
+ base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
+ dispatcher);
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ run_loop->Run();
+ }
+
+ base::MessagePumpDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
+};
+
+} // namespace
+
+class MenuControllerTest : public ViewsTestBase {
+ public:
+ MenuControllerTest() : controller_(NULL) {}
+ virtual ~MenuControllerTest() {
+ ResetMenuController();
+ }
+
+ // Dispatches |count| number of items, each in a separate iteration of the
+ // message-loop, by posting a task.
+ void Step3_DispatchEvents(int count) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ controller_->exit_type_ = MenuController::EXIT_ALL;
+
+ DispatchEvent();
+ if (count) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step3_DispatchEvents,
+ base::Unretained(this),
+ count - 1));
+ } else {
+ EXPECT_TRUE(run_loop_->running());
+ run_loop_->Quit();
+ }
+ }
+
+ // Runs a nested message-loop that does not involve the menu itself.
+ void Step2_RunNestedLoop() {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step3_DispatchEvents,
+ base::Unretained(this),
+ 3));
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
+ }
+
+ void Step1_RunMenu() {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
+ base::Unretained(this)));
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ RunMenu(owner.get());
+ }
+
+ scoped_ptr<Widget> CreateOwnerWidget() {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+ widget->Show();
+
+ aura::client::SetDispatcherClient(
+ widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
+ return widget.Pass();
+ }
+
+ void RunMenu(views::Widget* owner) {
+ scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
+ ResetMenuController();
+ controller_ = new MenuController(NULL, true, NULL);
+ controller_->owner_ = owner;
+ controller_->showing_ = true;
+ controller_->SetSelection(menu_item.get(),
+ MenuController::SELECTION_UPDATE_IMMEDIATELY);
+ controller_->RunMessageLoop(false);
+ }
+
+#if defined(USE_X11)
+ void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
+ ui::ScopedXI2Event key_event;
+ key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
+ event_source_.Dispatch(key_event);
+ EXPECT_EQ(exit_type, controller_->exit_type());
+ controller_->exit_type_ = MenuController::EXIT_ALL;
+ DispatchEvent();
+ }
+#endif
+
+ void DispatchEvent() {
+#if defined(USE_X11)
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(xevent));
+ event_source_.Dispatch(&xevent);
+#elif defined(OS_WIN)
+ MSG msg;
+ memset(&msg, 0, sizeof(MSG));
+ dispatcher_client_.dispatcher()->Dispatch(msg);
+#elif defined(USE_OZONE)
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, true);
+ dispatcher_client_.dispatcher()->Dispatch(&event);
+#else
+#error Unsupported platform
+#endif
+ }
+
+ private:
+ void ResetMenuController() {
+ if (controller_) {
+ // These properties are faked by RunMenu for the purposes of testing and
+ // need to be undone before we call the destructor.
+ controller_->owner_ = NULL;
+ controller_->showing_ = false;
+ delete controller_;
+ controller_ = NULL;
+ }
+ }
+
+ // A weak pointer to the MenuController owned by this class.
+ MenuController* controller_;
+ scoped_ptr<base::RunLoop> run_loop_;
+ TestPlatformEventSource event_source_;
+ TestDispatcherClient dispatcher_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
+};
+
+TEST_F(MenuControllerTest, Basic) {
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+ base::MessageLoop::current());
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
+}
+
+#if defined(OS_LINUX) && defined(USE_X11)
+// Tests that an event targeter which blocks events will be honored by the menu
+// event dispatcher.
+TEST_F(MenuControllerTest, EventTargeter) {
+ {
+ // Verify that the menu handles the escape key under normal circumstances.
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
+ base::Unretained(this),
+ MenuController::EXIT_OUTERMOST));
+ RunMenu(owner.get());
+ }
+
+ {
+ // With the NULL targeter instantiated and assigned we expect the menu to
+ // not handle the key event.
+ scoped_ptr<Widget> owner(CreateOwnerWidget());
+ aura::ScopedWindowTargeter scoped_targeter(
+ owner->GetNativeWindow()->GetRootWindow(),
+ scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
+ message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
+ base::Unretained(this),
+ MenuController::EXIT_NONE));
+ RunMenu(owner.get());
+ }
+}
+#endif
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller_win.cc b/chromium/ui/views/controls/menu/menu_controller_win.cc
deleted file mode 100644
index bbf7e9b1366..00000000000
--- a/chromium/ui/views/controls/menu/menu_controller_win.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_controller.h"
-
-#include "base/run_loop.h"
-#include "ui/gfx/screen.h"
-
-namespace views {
-
-void MenuController::RunMessageLoop(bool nested_menu) {
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- base::MessageLoop::ScopedNestableTaskAllower allow(loop);
- base::RunLoop run_loop(this);
- run_loop.Run();
-}
-
-bool MenuController::ShouldQuitNow() const {
- return true;
-}
-
-gfx::Screen* MenuController::GetScreen() {
- return gfx::Screen::GetNativeScreen();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index 90ab5cbe1b2..6778545f415 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -2,9 +2,11 @@
// 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_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/events/event.h"
+#include "ui/views/controls/menu/menu_config.h"
+
namespace views {
MenuDelegate::~MenuDelegate() {}
@@ -13,14 +15,19 @@ bool MenuDelegate::IsItemChecked(int id) const {
return false;
}
-string16 MenuDelegate::GetLabel(int id) const {
- return string16();
+base::string16 MenuDelegate::GetLabel(int id) const {
+ return base::string16();
}
-const gfx::Font* MenuDelegate::GetLabelFont(int id) const {
+const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
return NULL;
}
+bool MenuDelegate::GetShouldUseDisabledEmphasizedForegroundColor(
+ int command_id) const {
+ return false;
+}
+
bool MenuDelegate::GetBackgroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const {
@@ -33,12 +40,12 @@ bool MenuDelegate::GetForegroundColor(int command_id,
return false;
}
-string16 MenuDelegate::GetTooltipText(int id,
+base::string16 MenuDelegate::GetTooltipText(int id,
const gfx::Point& screen_loc) const {
- return string16();
+ return base::string16();
}
-bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) {
+bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) const {
return false;
}
@@ -57,7 +64,11 @@ bool MenuDelegate::IsCommandEnabled(int id) const {
return true;
}
-bool MenuDelegate::GetContextualLabel(int id, string16* out) const {
+bool MenuDelegate::IsCommandVisible(int id) const {
+ return true;
+}
+
+bool MenuDelegate::GetContextualLabel(int id, base::string16* out) const {
return false;
}
@@ -126,7 +137,7 @@ int MenuDelegate::GetDragOperations(MenuItemView* sender) {
MenuItemView* MenuDelegate::GetSiblingMenu(MenuItemView* menu,
const gfx::Point& screen_point,
- MenuItemView::AnchorPosition* anchor,
+ MenuAnchorPosition* anchor,
bool* has_mnemonics,
MenuButton** button) {
return NULL;
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index f171d570b7e..fafccd790f9 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -10,23 +10,29 @@
#include "base/logging.h"
#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/menu/menu_types.h"
+#include "ui/views/views_export.h"
using ui::OSExchangeData;
namespace gfx {
-class Font;
+class FontList;
+class Point;
}
namespace ui {
class Accelerator;
+class DropTargetEvent;
}
namespace views {
class MenuButton;
+class MenuItemView;
// MenuDelegate --------------------------------------------------------------
@@ -61,14 +67,21 @@ class VIEWS_EXPORT MenuDelegate {
// The string shown for the menu item. This is only invoked when an item is
// added with an empty label.
- virtual string16 GetLabel(int id) const;
+ virtual base::string16 GetLabel(int id) const;
// The font for the menu item label.
- virtual const gfx::Font* GetLabelFont(int id) const;
+ virtual const gfx::FontList* GetLabelFontList(int id) const;
+
+ // Whether this item should be displayed with a bolder color when disabled.
+ virtual bool GetShouldUseDisabledEmphasizedForegroundColor(
+ int command_id) const;
// Override the text color of a given menu item dependent on the
// |command_id| and its |is_hovered| state. Returns true if it chooses to
// override the color.
+ //
+ // TODO(erg): Remove this interface. Injecting raw colors into the menu
+ // circumvents the NativeTheme.
virtual bool GetForegroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const;
@@ -76,17 +89,21 @@ class VIEWS_EXPORT MenuDelegate {
// Override the background color of a given menu item dependent on the
// |command_id| and its |is_hovered| state. Returns true if it chooses to
// override the color.
+ //
+ // TODO(erg): Remove this interface. Injecting raw colors into the menu
+ // circumvents the NativeTheme.
virtual bool GetBackgroundColor(int command_id,
bool is_hovered,
SkColor* override_color) const;
// The tooltip shown for the menu item. This is invoked when the user
// hovers over the item, and no tooltip text has been set for that item.
- virtual string16 GetTooltipText(int id, const gfx::Point& screen_loc) const;
+ virtual base::string16 GetTooltipText(int id,
+ const gfx::Point& screen_loc) const;
// If there is an accelerator for the menu item with id |id| it is set in
// |accelerator| and true is returned.
- virtual bool GetAccelerator(int id, ui::Accelerator* accelerator);
+ virtual bool GetAccelerator(int id, ui::Accelerator* accelerator) const;
// Shows the context menu with the specified id. This is invoked when the
// user does the appropriate gesture to show a context menu. The id
@@ -104,7 +121,8 @@ class VIEWS_EXPORT MenuDelegate {
// Controller
virtual bool SupportsCommand(int id) const;
virtual bool IsCommandEnabled(int id) const;
- virtual bool GetContextualLabel(int id, string16* out) const;
+ virtual bool IsCommandVisible(int id) const;
+ virtual bool GetContextualLabel(int id, base::string16* out) const;
virtual void ExecuteCommand(int id) {
}
@@ -202,7 +220,7 @@ class VIEWS_EXPORT MenuDelegate {
// The delegate owns the returned menu, not the controller.
virtual MenuItemView* GetSiblingMenu(MenuItemView* menu,
const gfx::Point& screen_point,
- MenuItemView::AnchorPosition* anchor,
+ MenuAnchorPosition* anchor,
bool* has_mnemonics,
MenuButton** button);
diff --git a/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc
new file mode 100644
index 00000000000..181ba241afe
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace internal {
+
+MenuEventDispatcher::MenuEventDispatcher(MenuController* controller)
+ : menu_controller_(controller) {}
+
+MenuEventDispatcher::~MenuEventDispatcher() {}
+
+bool MenuEventDispatcher::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return true;
+}
+
+uint32_t MenuEventDispatcher::DispatchEvent(const ui::PlatformEvent& event) {
+ bool should_quit = false;
+ bool should_perform_default = true;
+ bool should_process_event = true;
+
+ // Check if the event should be handled.
+ scoped_ptr<ui::Event> ui_event(ui::EventFromNative(event));
+ if (ui_event && menu_controller_->owner()) {
+ aura::Window* menu_window = menu_controller_->owner()->GetNativeWindow();
+ aura::Window* target_window = static_cast<aura::Window*>(
+ static_cast<ui::EventTarget*>(menu_window->GetRootWindow())->
+ GetEventTargeter()->FindTargetForEvent(menu_window,
+ ui_event.get()));
+ // TODO(flackr): The event shouldn't be handled if target_window is not
+ // menu_window, however the event targeter does not properly target the
+ // open menu. For now, we allow targeters to prevent handling by the menu.
+ if (!target_window)
+ should_process_event = false;
+ }
+
+ if (menu_controller_->exit_type() == MenuController::EXIT_ALL ||
+ menu_controller_->exit_type() == MenuController::EXIT_DESTROYED) {
+ should_quit = true;
+ } else if (should_process_event) {
+ switch (ui::EventTypeFromNative(event)) {
+ case ui::ET_KEY_PRESSED: {
+ if (!menu_controller_->OnKeyDown(ui::KeyboardCodeFromNative(event))) {
+ should_quit = true;
+ should_perform_default = false;
+ break;
+ }
+
+ // Do not check mnemonics if the Alt or Ctrl modifiers are pressed.
+ int flags = ui::EventFlagsFromNative(event);
+ if ((flags & (ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) == 0) {
+ char c = ui::GetCharacterFromKeyCode(
+ ui::KeyboardCodeFromNative(event), flags);
+ if (menu_controller_->SelectByChar(c)) {
+ should_quit = true;
+ should_perform_default = false;
+ break;
+ }
+ }
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ }
+ case ui::ET_KEY_RELEASED:
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (should_quit || menu_controller_->exit_type() != MenuController::EXIT_NONE)
+ menu_controller_->TerminateNestedMessageLoop();
+
+ return should_perform_default ? ui::POST_DISPATCH_PERFORM_DEFAULT
+ : ui::POST_DISPATCH_NONE;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h
new file mode 100644
index 00000000000..bdc76fd88ba
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_event_dispatcher_linux.h
@@ -0,0 +1,32 @@
+// 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 "base/macros.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+
+namespace views {
+
+class MenuController;
+
+namespace internal {
+
+// A message-pump dispatcher object used to dispatch events from the nested
+// message-loop initiated by the MenuController.
+class MenuEventDispatcher : public ui::PlatformEventDispatcher {
+ public:
+ explicit MenuEventDispatcher(MenuController* menu_controller);
+ virtual ~MenuEventDispatcher();
+
+ private:
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
+ MenuController* menu_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuEventDispatcher);
+};
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 4645e1ba6aa..2716ec8bb78 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -18,10 +18,6 @@
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/views/corewm/shadow_types.h"
-#endif
-
namespace views {
////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +45,8 @@ void MenuHost::InitMenuHost(Widget* parent,
bool rounded_border = menu_controller && menu_config.corner_radius > 0;
bool bubble_border = submenu_->GetScrollViewContainer() &&
submenu_->GetScrollViewContainer()->HasBubbleBorder();
- params.has_dropshadow = !bubble_border;
+ params.shadow_type = bubble_border ? Widget::InitParams::SHADOW_TYPE_NONE
+ : Widget::InitParams::SHADOW_TYPE_DROP;
params.opacity = (bubble_border || rounded_border) ?
Widget::InitParams::TRANSLUCENT_WINDOW :
Widget::InitParams::OPAQUE_WINDOW;
@@ -57,14 +54,7 @@ void MenuHost::InitMenuHost(Widget* parent,
params.bounds = bounds;
Init(params);
-#if defined(USE_AURA)
- if (bubble_border)
- SetShadowType(GetNativeView(), views::corewm::SHADOW_TYPE_NONE);
-#endif
-
SetContentsView(contents_view);
- if (bubble_border || rounded_border)
- SetOpacity(0);
ShowMenuHost(do_capture);
}
@@ -76,13 +66,11 @@ void MenuHost::ShowMenuHost(bool do_capture) {
// Doing a capture may make us get capture lost. Ignore it while we're in the
// process of showing.
base::AutoReset<bool> reseter(&ignore_capture_lost_, true);
- Show();
+ ShowInactive();
if (do_capture) {
-#if defined(USE_AURA)
// Cancel existing touches, so we don't miss some touch release/cancel
// events due to the menu taking capture.
- ui::GestureRecognizer::Get()->TransferEventsTo(GetNativeWindow(), NULL);
-#endif // USE_AURA
+ ui::GestureRecognizer::Get()->TransferEventsTo(NULL, NULL);
native_widget_private()->SetCapture();
}
}
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 2577d909b7b..3bce4a49b6e 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.cc
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.cc
@@ -51,17 +51,8 @@ void MenuHostRootView::OnMouseMoved(const ui::MouseEvent& event) {
}
bool MenuHostRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
-#if defined(USE_AURA)
- // Aura uses MenuController to forward events like other mouse events.
return GetMenuController() &&
GetMenuController()->OnMouseWheel(submenu_, event);
-#else
- // Windows uses focus_util_win::RerouteMouseWheel to forward events to
- // the right menu.
- // RootView::OnMouseWheel forwards to the focused view. We don't have a
- // focused view, so we need to override this then forward to the menu.
- return submenu_->OnMouseWheel(event);
-#endif
}
void MenuHostRootView::DispatchGestureEvent(ui::GestureEvent* event) {
diff --git a/chromium/ui/views/controls/menu/menu_image_util.cc b/chromium/ui/views/controls/menu/menu_image_util.cc
index a50980b3500..60315736fe2 100644
--- a/chromium/ui/views/controls/menu/menu_image_util.cc
+++ b/chromium/ui/views/controls/menu/menu_image_util.cc
@@ -54,7 +54,7 @@ class RadioButtonImageSource : public gfx::CanvasImageSource {
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
gradient_points, gradient_colors, NULL, arraysize(gradient_points),
- SkShader::kClamp_TileMode, NULL));
+ SkShader::kClamp_TileMode));
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
@@ -76,8 +76,7 @@ class RadioButtonImageSource : public gfx::CanvasImageSource {
shader = skia::AdoptRef(
SkGradientShader::CreateLinear(
selected_gradient_points, selected_gradient_colors, NULL,
- arraysize(selected_gradient_points),
- SkShader::kClamp_TileMode, NULL));
+ arraysize(selected_gradient_points), SkShader::kClamp_TileMode));
paint.setShader(shader.get());
paint.setStyle(SkPaint::kFill_Style);
canvas->sk_canvas()->drawCircle(radius, radius,
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 2adc1ad2f17..f24c61059c6 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -9,12 +9,15 @@
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/common_theme.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/image_view.h"
@@ -47,7 +50,7 @@ class EmptyMenuMenuItem : public MenuItemView {
}
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE {
+ base::string16* tooltip) const OVERRIDE {
// Empty menu items shouldn't have a tooltip.
return false;
}
@@ -116,7 +119,7 @@ void MenuItemView::ChildPreferredSizeChanged(View* child) {
}
bool MenuItemView::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
*tooltip = tooltip_;
if (!tooltip->empty())
return true;
@@ -147,15 +150,15 @@ bool MenuItemView::GetTooltipText(const gfx::Point& p,
return !tooltip->empty();
}
-void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_MENUITEM;
+void MenuItemView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_MENU_ITEM;
- string16 item_text;
+ base::string16 item_text;
if (IsContainer()) {
// The first child is taking over, just use its accessible name instead of
// |title_|.
View* child = child_at(0);
- ui::AccessibleViewState state;
+ ui::AXViewState state;
child->GetAccessibleState(&state);
item_text = state.name;
} else {
@@ -165,12 +168,12 @@ void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
switch (GetType()) {
case SUBMENU:
- state->state |= ui::AccessibilityTypes::STATE_HASPOPUP;
+ state->AddStateFlag(ui::AX_STATE_HASPOPUP);
break;
case CHECKBOX:
case RADIO:
- state->state |= GetDelegate()->IsItemChecked(GetCommand()) ?
- ui::AccessibilityTypes::STATE_CHECKED : 0;
+ if (GetDelegate()->IsItemChecked(GetCommand()))
+ state->AddStateFlag(ui::AX_STATE_CHECKED);
break;
case NORMAL:
case SEPARATOR:
@@ -181,22 +184,22 @@ void MenuItemView::GetAccessibleState(ui::AccessibleViewState* state) {
}
// static
-bool MenuItemView::IsBubble(MenuItemView::AnchorPosition anchor) {
- return anchor == MenuItemView::BUBBLE_LEFT ||
- anchor == MenuItemView::BUBBLE_RIGHT ||
- anchor == MenuItemView::BUBBLE_ABOVE ||
- anchor == MenuItemView::BUBBLE_BELOW;
+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;
}
// static
-string16 MenuItemView::GetAccessibleNameForMenuItem(
- const string16& item_text, const string16& minor_text) {
- string16 accessible_name = item_text;
+base::string16 MenuItemView::GetAccessibleNameForMenuItem(
+ const base::string16& item_text, const base::string16& minor_text) {
+ base::string16 accessible_name = item_text;
// Filter out the "&" for accessibility clients.
size_t index = 0;
- const char16 amp = '&';
- while ((index = accessible_name.find(amp, index)) != string16::npos &&
+ const base::char16 amp = '&';
+ while ((index = accessible_name.find(amp, index)) != base::string16::npos &&
index + 1 < accessible_name.length()) {
accessible_name.replace(index, accessible_name.length() - index,
accessible_name.substr(index + 1));
@@ -225,9 +228,9 @@ void MenuItemView::Cancel() {
MenuItemView* MenuItemView::AddMenuItemAt(
int index,
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style) {
@@ -251,6 +254,8 @@ MenuItemView* MenuItemView::AddMenuItemAt(
item->SetIcon(icon);
if (type == SUBMENU)
item->CreateSubmenu();
+ if (GetDelegate() && !GetDelegate()->IsCommandVisible(item_id))
+ item->SetVisible(false);
submenu_->AddChildViewAt(item, index);
return item;
}
@@ -271,51 +276,52 @@ void MenuItemView::RemoveMenuItemAt(int index) {
}
MenuItemView* MenuItemView::AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
Type type) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(),
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
gfx::ImageSkia(), type, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendSubMenu(int item_id,
- const string16& label) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(),
+ const base::string16& label) {
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
gfx::ImageSkia(), SUBMENU, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(), icon,
- SUBMENU, ui::NORMAL_SEPARATOR);
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
+ icon, SUBMENU, ui::NORMAL_SEPARATOR);
}
-MenuItemView* MenuItemView::AppendMenuItemWithLabel(int item_id,
- const string16& label) {
+MenuItemView* MenuItemView::AppendMenuItemWithLabel(
+ int item_id,
+ const base::string16& label) {
return AppendMenuItem(item_id, label, NORMAL);
}
MenuItemView* MenuItemView::AppendDelegateMenuItem(int item_id) {
- return AppendMenuItem(item_id, string16(), NORMAL);
+ return AppendMenuItem(item_id, base::string16(), NORMAL);
}
void MenuItemView::AppendSeparator() {
- AppendMenuItemImpl(0, string16(), string16(), string16(), gfx::ImageSkia(),
- SEPARATOR, ui::NORMAL_SEPARATOR);
+ AppendMenuItemImpl(0, base::string16(), base::string16(), base::string16(),
+ gfx::ImageSkia(), SEPARATOR, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon) {
- return AppendMenuItemImpl(item_id, label, string16(), string16(), icon,
- NORMAL, ui::NORMAL_SEPARATOR);
+ return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(),
+ icon, NORMAL, ui::NORMAL_SEPARATOR);
}
MenuItemView* MenuItemView::AppendMenuItemImpl(
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style) {
@@ -338,17 +344,17 @@ SubmenuView* MenuItemView::GetSubmenu() const {
return submenu_;
}
-void MenuItemView::SetTitle(const string16& title) {
+void MenuItemView::SetTitle(const base::string16& title) {
title_ = title;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
-void MenuItemView::SetSubtitle(const string16& subtitle) {
+void MenuItemView::SetSubtitle(const base::string16& subtitle) {
subtitle_ = subtitle;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
-void MenuItemView::SetMinorText(const string16& minor_text) {
+void MenuItemView::SetMinorText(const base::string16& minor_text) {
minor_text_ = minor_text;
invalidate_dimensions(); // Triggers preferred size recalculation.
}
@@ -358,7 +364,7 @@ void MenuItemView::SetSelected(bool selected) {
SchedulePaint();
}
-void MenuItemView::SetTooltip(const string16& tooltip, int item_id) {
+void MenuItemView::SetTooltip(const base::string16& tooltip, int item_id) {
MenuItemView* item = GetMenuItemByID(item_id);
DCHECK(item);
item->tooltip_ = tooltip;
@@ -399,13 +405,13 @@ void MenuItemView::OnPaint(gfx::Canvas* canvas) {
PaintButton(canvas, PB_NORMAL);
}
-gfx::Size MenuItemView::GetPreferredSize() {
+gfx::Size MenuItemView::GetPreferredSize() const {
const MenuItemDimensions& dimensions(GetDimensions());
return gfx::Size(dimensions.standard_width + dimensions.children_width,
dimensions.height);
}
-const MenuItemView::MenuItemDimensions& MenuItemView::GetDimensions() {
+const MenuItemView::MenuItemDimensions& MenuItemView::GetDimensions() const {
if (!is_dimensions_valid())
dimensions_ = CalculateDimensions();
DCHECK(is_dimensions_valid());
@@ -441,16 +447,16 @@ const MenuItemView* MenuItemView::GetRootMenuItem() const {
return item;
}
-char16 MenuItemView::GetMnemonic() {
+base::char16 MenuItemView::GetMnemonic() {
if (!GetRootMenuItem()->has_mnemonics_)
return 0;
size_t index = 0;
do {
index = title_.find('&', index);
- if (index != string16::npos) {
+ if (index != base::string16::npos) {
if (index + 1 != title_.size() && title_[index + 1] != '&') {
- char16 char_array[] = { title_[index + 1], 0 };
+ base::char16 char_array[] = { title_[index + 1], 0 };
// TODO(jshin): What about Turkish locale? See http://crbug.com/81719.
// If the mnemonic is capital I and the UI language is Turkish,
// lowercasing it results in 'small dotless i', which is different
@@ -459,7 +465,7 @@ char16 MenuItemView::GetMnemonic() {
}
index++;
}
- } while (index != string16::npos);
+ } while (index != base::string16::npos);
return 0;
}
@@ -685,14 +691,14 @@ int MenuItemView::GetDrawStringFlags() {
return flags;
}
-const gfx::Font& MenuItemView::GetFont() {
+const gfx::FontList& MenuItemView::GetFontList() const {
const MenuDelegate* delegate = GetDelegate();
if (delegate) {
- const gfx::Font* font = delegate->GetLabelFont(GetCommand());
- if (font)
- return *font;
+ const gfx::FontList* font_list = delegate->GetLabelFontList(GetCommand());
+ if (font_list)
+ return *font_list;
}
- return GetMenuConfig().font;
+ return GetMenuConfig().font_list;
}
void MenuItemView::AddEmptyMenus() {
@@ -738,13 +744,6 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
parent_menu_item_->GetSubmenu()->GetShowSelection(this) &&
(NonIconChildViewsCount() == 0));
- int icon_x = config.item_left_margin + left_icon_margin_;
- int top_margin = GetTopMargin();
- int bottom_margin = GetBottomMargin();
- int icon_y = top_margin + (height() - config.item_top_margin -
- bottom_margin - config.check_height) / 2;
- int icon_height = config.check_height;
- int available_height = height() - top_margin - bottom_margin;
MenuDelegate *delegate = GetDelegate();
// Render the background. As MenuScrollViewContainer draws the background, we
// only need the background when we want it to look different, as when we're
@@ -766,21 +765,27 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
ui::NativeTheme::ExtraParams());
}
+ const int icon_x = config.item_left_margin + left_icon_margin_;
+ const int top_margin = GetTopMargin();
+ const int bottom_margin = GetBottomMargin();
+ const int available_height = height() - top_margin - bottom_margin;
+
// Render the check.
if (type_ == CHECKBOX && delegate->IsItemChecked(GetCommand())) {
- gfx::ImageSkia check = GetMenuCheckImage(IsSelected());
+ gfx::ImageSkia check = GetMenuCheckImage(render_selection);
// Don't use config.check_width here as it's padded
// to force more padding (AURA).
- gfx::Rect check_bounds(icon_x, icon_y, check.width(), icon_height);
+ gfx::Rect check_bounds(icon_x,
+ top_margin + (available_height - check.height()) / 2,
+ check.width(),
+ check.height());
AdjustBoundsForRTLUI(&check_bounds);
canvas->DrawImageInt(check, check_bounds.x(), check_bounds.y());
} else if (type_ == RADIO) {
gfx::ImageSkia image =
GetRadioButtonImage(delegate->IsItemChecked(GetCommand()));
gfx::Rect radio_bounds(icon_x,
- top_margin +
- (height() - top_margin - bottom_margin -
- image.height()) / 2,
+ top_margin + (available_height - image.height()) / 2,
image.width(),
image.height());
AdjustBoundsForRTLUI(&radio_bounds);
@@ -788,12 +793,18 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
}
// Render the foreground.
- ui::NativeTheme::ColorId color_id =
- ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
+ ui::NativeTheme::ColorId color_id;
if (enabled()) {
color_id = render_selection ?
ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor:
ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor;
+ } else {
+ bool emphasized = delegate &&
+ delegate->GetShouldUseDisabledEmphasizedForegroundColor(
+ GetCommand());
+ color_id = emphasized ?
+ ui::NativeTheme::kColorId_DisabledEmphasizedMenuItemForegroundColor :
+ ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
}
SkColor fg_color = native_theme->GetSystemColor(color_id);
SkColor override_foreground_color;
@@ -802,7 +813,7 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
&override_foreground_color))
fg_color = override_foreground_color;
- const gfx::Font& font = GetFont();
+ const gfx::FontList& font_list = GetFontList();
int accel_width = parent_menu_item_->GetSubmenu()->max_minor_text_width();
int label_start = GetLabelStartForThisItem();
@@ -817,19 +828,15 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
int flags = GetDrawStringFlags();
if (mode == PB_FOR_DRAG)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- canvas->DrawStringInt(title(), font, fg_color,
- text_bounds.x(), text_bounds.y(), text_bounds.width(),
- text_bounds.height(), flags);
+ canvas->DrawStringRectWithFlags(title(), font_list, fg_color, text_bounds,
+ flags);
if (!subtitle_.empty()) {
- canvas->DrawStringInt(
+ canvas->DrawStringRectWithFlags(
subtitle_,
- font,
+ font_list,
GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_ButtonDisabledColor),
- text_bounds.x(),
- text_bounds.y() + GetFont().GetHeight(),
- text_bounds.width(),
- text_bounds.height(),
+ text_bounds + gfx::Vector2d(0, font_list.GetHeight()),
flags);
}
@@ -837,24 +844,23 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
// Render the submenu indicator (arrow).
if (HasSubmenu()) {
+ gfx::ImageSkia arrow = GetSubmenuArrowImage(render_selection);
gfx::Rect arrow_bounds(this->width() - config.arrow_width -
config.arrow_to_edge_padding,
- top_margin + (available_height -
- config.arrow_width) / 2,
- config.arrow_width, height());
+ top_margin + (available_height - arrow.height()) / 2,
+ config.arrow_width,
+ arrow.height());
AdjustBoundsForRTLUI(&arrow_bounds);
- canvas->DrawImageInt(GetSubmenuArrowImage(IsSelected()),
- arrow_bounds.x(), arrow_bounds.y());
+ canvas->DrawImageInt(arrow, arrow_bounds.x(), arrow_bounds.y());
}
}
void MenuItemView::PaintMinorText(gfx::Canvas* canvas,
bool render_selection) {
- string16 minor_text = GetMinorText();
+ base::string16 minor_text = GetMinorText();
if (minor_text.empty())
return;
- const gfx::Font& font = GetFont();
int available_height = height() - GetTopMargin() - GetBottomMargin();
int max_accel_width =
parent_menu_item_->GetSubmenu()->max_minor_text_width();
@@ -870,16 +876,13 @@ void MenuItemView::PaintMinorText(gfx::Canvas* canvas,
flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
else
flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
- canvas->DrawStringInt(
+ canvas->DrawStringRectWithFlags(
minor_text,
- font,
+ GetFontList(),
GetNativeTheme()->GetSystemColor(render_selection ?
ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor :
ui::NativeTheme::kColorId_ButtonDisabledColor),
- accel_bounds.x(),
- accel_bounds.y(),
- accel_bounds.width(),
- accel_bounds.height(),
+ accel_bounds,
flags);
}
@@ -894,38 +897,36 @@ void MenuItemView::DestroyAllMenuHosts() {
}
}
-int MenuItemView::GetTopMargin() {
+int MenuItemView::GetTopMargin() const {
if (top_margin_ >= 0)
return top_margin_;
- MenuItemView* root = GetRootMenuItem();
+ const MenuItemView* root = GetRootMenuItem();
return root && root->has_icons_
? GetMenuConfig().item_top_margin :
GetMenuConfig().item_no_icon_top_margin;
}
-int MenuItemView::GetBottomMargin() {
+int MenuItemView::GetBottomMargin() const {
if (bottom_margin_ >= 0)
return bottom_margin_;
- MenuItemView* root = GetRootMenuItem();
+ const MenuItemView* root = GetRootMenuItem();
return root && root->has_icons_
? GetMenuConfig().item_bottom_margin :
GetMenuConfig().item_no_icon_bottom_margin;
}
-gfx::Size MenuItemView::GetChildPreferredSize() {
+gfx::Size MenuItemView::GetChildPreferredSize() const {
if (!has_children())
return gfx::Size();
- if (IsContainer()) {
- View* child = child_at(0);
- return child->GetPreferredSize();
- }
+ if (IsContainer())
+ return child_at(0)->GetPreferredSize();
int width = 0;
for (int i = 0; i < child_count(); ++i) {
- View* child = child_at(i);
+ const View* child = child_at(i);
if (icon_view_ && (icon_view_ == child))
continue;
if (i)
@@ -941,7 +942,7 @@ gfx::Size MenuItemView::GetChildPreferredSize() {
return gfx::Size(width, height);
}
-MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
+MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
gfx::Size child_size = GetChildPreferredSize();
MenuItemDimensions dimensions;
@@ -961,7 +962,7 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
return dimensions;
// Determine the length of the label text.
- const gfx::Font& font = GetFont();
+ const gfx::FontList& font_list = GetFontList();
// Get Icon margin overrides for this particular item.
const MenuDelegate* delegate = GetDelegate();
@@ -976,27 +977,30 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() {
}
int label_start = GetLabelStartForThisItem();
- int string_width = font.GetStringWidth(title_);
- if (!subtitle_.empty())
- string_width = std::max(string_width, font.GetStringWidth(subtitle_));
+ int string_width = gfx::GetStringWidth(title_, font_list);
+ if (!subtitle_.empty()) {
+ string_width = std::max(string_width,
+ gfx::GetStringWidth(subtitle_, font_list));
+ }
dimensions.standard_width = string_width + label_start +
item_right_margin_;
// Determine the length of the right-side text.
- string16 minor_text = GetMinorText();
+ base::string16 minor_text = GetMinorText();
dimensions.minor_text_width =
- minor_text.empty() ? 0 : GetFont().GetStringWidth(minor_text);
+ minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, font_list);
// Determine the height to use.
+ dimensions.height =
+ std::max(dimensions.height,
+ (subtitle_.empty() ? 0 : font_list.GetHeight()) +
+ font_list.GetHeight() + GetBottomMargin() + GetTopMargin());
dimensions.height = std::max(dimensions.height,
- (subtitle_.empty() ? 0 : font.GetHeight()) +
- font.GetHeight() + GetBottomMargin() + GetTopMargin());
- dimensions.height = std::max(dimensions.height,
- GetMenuConfig().item_min_height);
+ GetMenuConfig().item_min_height);
return dimensions;
}
-int MenuItemView::GetLabelStartForThisItem() {
+int MenuItemView::GetLabelStartForThisItem() const {
int label_start = label_start_ + left_icon_margin_ + right_icon_margin_;
if ((type_ == CHECKBOX || type_ == RADIO) && icon_view_) {
label_start += icon_view_->size().width() +
@@ -1005,10 +1009,10 @@ int MenuItemView::GetLabelStartForThisItem() {
return label_start;
}
-string16 MenuItemView::GetMinorText() {
+base::string16 MenuItemView::GetMinorText() const {
if (id() == kEmptyMenuItemViewID) {
// Don't query the delegate for menus that represent no children.
- return string16();
+ return base::string16();
}
ui::Accelerator accelerator;
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index 2d394bae2f2..4f0ea441caa 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -15,6 +15,7 @@
#include "ui/base/models/menu_separator_types.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/menu/menu_config.h"
+#include "ui/views/controls/menu/menu_types.h"
#include "ui/views/view.h"
#if defined(OS_WIN)
@@ -24,7 +25,7 @@
#endif
namespace gfx {
-class Font;
+class FontList;
}
namespace views {
@@ -83,21 +84,6 @@ class VIEWS_EXPORT MenuItemView : public View {
EMPTY
};
- // Where the menu should be anchored to for non-RTL languages. The
- // opposite position will be used if base::i18n:IsRTL() is true.
- // The BUBBLE flags are used when the menu should get enclosed by a bubble.
- // Note that BUBBLE flags should only be used with menus which have no
- // children.
- enum AnchorPosition {
- TOPLEFT,
- TOPRIGHT,
- BOTTOMCENTER,
- BUBBLE_LEFT,
- BUBBLE_RIGHT,
- BUBBLE_ABOVE,
- BUBBLE_BELOW
- };
-
// Where the menu should be drawn, above or below the bounds (when
// the bounds is non-empty). POSITION_BEST_FIT (default) positions
// the menu below the bounds unless the menu does not fit on the
@@ -132,8 +118,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Returns the preferred height of menu items. This is only valid when the
// menu is about to be shown.
@@ -143,12 +129,12 @@ class VIEWS_EXPORT MenuItemView : public View {
static int label_start() { return label_start_; }
// Returns if a given |anchor| is a bubble or not.
- static bool IsBubble(MenuItemView::AnchorPosition anchor);
+ static bool IsBubble(MenuAnchorPosition anchor);
// Returns the accessible name to be used with screen readers. Mnemonics are
// removed and the menu item accelerator text is appended.
- static string16 GetAccessibleNameForMenuItem(
- const string16& item_text, const string16& accelerator_text);
+ static base::string16 GetAccessibleNameForMenuItem(
+ const base::string16& item_text, const base::string16& accelerator_text);
// Hides and cancels the menu. This does nothing if the menu is not open.
void Cancel();
@@ -157,9 +143,9 @@ class VIEWS_EXPORT MenuItemView : public View {
// called after adding menu items if the menu may be active.
MenuItemView* AddMenuItemAt(int index,
int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style);
@@ -177,24 +163,24 @@ class VIEWS_EXPORT MenuItemView : public View {
// label The text label shown.
// type The type of item.
MenuItemView* AppendMenuItem(int item_id,
- const string16& label,
+ const base::string16& label,
Type type);
// Append a submenu to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenu(int item_id,
- const string16& label);
+ const base::string16& label);
// Append a submenu with an icon to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenuWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// This is a convenience for standard text label menu items where the label
// is provided with this call.
MenuItemView* AppendMenuItemWithLabel(int item_id,
- const string16& label);
+ const base::string16& label);
// This is a convenience for text label menu items where the label is
// provided by the delegate.
@@ -207,14 +193,14 @@ class VIEWS_EXPORT MenuItemView : public View {
// needs an icon. Calling this function forces the Menu class to draw
// the menu, instead of relying on Windows.
MenuItemView* AppendMenuItemWithIcon(int item_id,
- const string16& label,
+ const base::string16& label,
const gfx::ImageSkia& icon);
// All the AppendXXX methods funnel into this.
MenuItemView* AppendMenuItemImpl(int item_id,
- const string16& label,
- const string16& sublabel,
- const string16& minor_text,
+ const base::string16& label,
+ const base::string16& sublabel,
+ const base::string16& minor_text,
const gfx::ImageSkia& icon,
Type type,
ui::MenuSeparatorType separator_style);
@@ -234,14 +220,14 @@ class VIEWS_EXPORT MenuItemView : public View {
const MenuItemView* GetParentMenuItem() const { return parent_menu_item_; }
// Sets/Gets the title.
- void SetTitle(const string16& title);
- const string16& title() const { return title_; }
+ void SetTitle(const base::string16& title);
+ const base::string16& title() const { return title_; }
// Sets the subtitle.
- void SetSubtitle(const string16& subtitle);
+ void SetSubtitle(const base::string16& subtitle);
// Sets the minor text.
- void SetMinorText(const string16& minor_text);
+ void SetMinorText(const base::string16& minor_text);
// Returns the type of this menu.
const Type& GetType() const { return type_; }
@@ -254,7 +240,7 @@ class VIEWS_EXPORT MenuItemView : public View {
bool IsSelected() const { return selected_; }
// Sets the |tooltip| for a menu item view with |item_id| identifier.
- void SetTooltip(const string16& tooltip, int item_id);
+ void SetTooltip(const base::string16& tooltip, int item_id);
// Sets the icon for the descendant identified by item_id.
void SetIcon(const gfx::ImageSkia& icon, int item_id);
@@ -277,10 +263,10 @@ class VIEWS_EXPORT MenuItemView : public View {
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// Returns the preferred size of this item.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Return the preferred dimensions of the item in pixel.
- const MenuItemDimensions& GetDimensions();
+ const MenuItemDimensions& GetDimensions() const;
// Returns the object responsible for controlling showing the menu.
MenuController* GetMenuController();
@@ -297,7 +283,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the mnemonic for this MenuItemView, or 0 if this MenuItemView
// doesn't have a mnemonic.
- char16 GetMnemonic();
+ base::char16 GetMnemonic();
// Do we have icons? This only has effect on the top menu. Turning this on
// makes the menus slightly wider and taller.
@@ -344,11 +330,11 @@ class VIEWS_EXPORT MenuItemView : public View {
virtual const char* GetClassName() const OVERRIDE;
// Returns the preferred size (and padding) of any children.
- virtual gfx::Size GetChildPreferredSize();
+ virtual gfx::Size GetChildPreferredSize() const;
// Returns the various margins.
- int GetTopMargin();
- int GetBottomMargin();
+ int GetTopMargin() const;
+ int GetBottomMargin() const;
private:
friend class internal::MenuRunnerImpl; // For access to ~MenuItemView.
@@ -372,11 +358,11 @@ class VIEWS_EXPORT MenuItemView : public View {
bool has_mnemonics,
bool show_mnemonics);
- // Returns the flags passed to DrawStringInt.
+ // Returns the flags passed to DrawStringRect.
int GetDrawStringFlags();
- // Returns the font to use for menu text.
- const gfx::Font& GetFont();
+ // Returns the font list to use for menu text.
+ const gfx::FontList& GetFontList() const;
// If this menu item has no children a child is added showing it has no
// children. Otherwise AddEmtpyMenus is recursively invoked on child menu
@@ -403,13 +389,13 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the text that should be displayed on the end (right) of the menu
// item. This will be the accelerator (if one exists), otherwise |subtitle_|.
- string16 GetMinorText();
+ base::string16 GetMinorText() const;
// Calculates and returns the MenuItemDimensions.
- MenuItemDimensions CalculateDimensions();
+ MenuItemDimensions CalculateDimensions() const;
// Get the horizontal position at which to draw the menu item's label.
- int GetLabelStartForThisItem();
+ int GetLabelStartForThisItem() const;
// Used by MenuController to cache the menu position in use by the
// active menu.
@@ -464,13 +450,13 @@ class VIEWS_EXPORT MenuItemView : public View {
SubmenuView* submenu_;
// Title.
- string16 title_;
+ base::string16 title_;
// Subtitle/sublabel.
- string16 subtitle_;
+ base::string16 subtitle_;
// Minor text.
- string16 minor_text_;
+ base::string16 minor_text_;
// Does the title have a mnemonic? Only useful on the root menu item.
bool has_mnemonics_;
@@ -486,7 +472,7 @@ class VIEWS_EXPORT MenuItemView : public View {
View* icon_view_;
// The tooltip to show on hover for this menu item.
- string16 tooltip_;
+ base::string16 tooltip_;
// Width of a menu icon area.
static int icon_area_width_;
@@ -502,7 +488,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Cached dimensions. This is cached as text sizing calculations are quite
// costly.
- MenuItemDimensions dimensions_;
+ mutable MenuItemDimensions dimensions_;
// Removed items to be deleted in ChildrenChanged().
std::vector<View*> removed_items_;
@@ -513,8 +499,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// Horizontal icon margins in pixels, which can differ between MenuItems.
// These values will be set in the layout process.
- int left_icon_margin_;
- int right_icon_margin_;
+ mutable int left_icon_margin_;
+ mutable int right_icon_margin_;
// |menu_position_| is the requested position with respect to the bounds.
// |actual_menu_position_| is used by the controller to cache the
diff --git a/chromium/ui/views/controls/menu/menu_message_loop.h b/chromium/ui/views/controls/menu/menu_message_loop.h
new file mode 100644
index 00000000000..a435d85f402
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop.h
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+class LocatedEvent;
+}
+
+namespace views {
+
+class MenuController;
+class Widget;
+
+// Interface used by MenuController to run a nested message loop while
+// showing a menu, allowing for platform specific implementations.
+class MenuMessageLoop {
+ public:
+ virtual ~MenuMessageLoop() {}
+
+ // Create a platform specific instance.
+ static MenuMessageLoop* Create();
+
+ // Runs the platform specific bits of the message loop. If |nested_menu| is
+ // true we're being asked to run a menu from within a menu (eg a context
+ // menu).
+ virtual void Run(MenuController*, Widget* owner, bool nested_menu) = 0;
+
+ // Returns true if it is a good time to call QuitNow().
+ // Returns false otherwise, for example if a drag and drop is in progress.
+ virtual bool ShouldQuitNow() const = 0;
+
+ // Quit an earlier call to Run().
+ virtual void QuitNow() = 0;
+
+ // Repost |event| to |window|.
+ // |screen_loc| is the event's location in screen coordinates.
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) = 0;
+
+ // Clear any references to the owner widget that was passed into the previous
+ // call to Run().
+ virtual void ClearOwner() = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
new file mode 100644
index 00000000000..0d7e99aab03
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
@@ -0,0 +1,202 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_loop_aura.h"
+
+#if defined(OS_WIN)
+#include <windowsx.h>
+#endif
+
+#include "base/run_loop.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/dispatcher_client.h"
+#include "ui/wm/public/drag_drop_client.h"
+
+#if defined(OS_WIN)
+#include "ui/base/win/internal_constants.h"
+#include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
+#include "ui/views/win/hwnd_util.h"
+#else
+#include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+#endif
+
+using aura::client::ScreenPositionClient;
+
+namespace views {
+
+namespace {
+
+aura::Window* GetOwnerRootWindow(views::Widget* owner) {
+ return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
+}
+
+// ActivationChangeObserverImpl is used to observe activation changes and close
+// the menu. Additionally it listens for the root window to be destroyed and
+// cancel the menu as well.
+class ActivationChangeObserverImpl
+ : public aura::client::ActivationChangeObserver,
+ public aura::WindowObserver,
+ public ui::EventHandler {
+ public:
+ ActivationChangeObserverImpl(MenuController* controller, aura::Window* root)
+ : controller_(controller), root_(root) {
+ aura::client::GetActivationClient(root_)->AddObserver(this);
+ root_->AddObserver(this);
+ root_->AddPreTargetHandler(this);
+ }
+
+ virtual ~ActivationChangeObserverImpl() { Cleanup(); }
+
+ // aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ if (!controller_->drag_in_progress())
+ controller_->CancelAll();
+ }
+
+ // aura::WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { Cleanup(); }
+
+ // ui::EventHandler:
+ virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
+ controller_->CancelAll();
+ }
+
+ private:
+ void Cleanup() {
+ if (!root_)
+ return;
+ // The ActivationClient may have been destroyed by the time we get here.
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(root_);
+ if (client)
+ client->RemoveObserver(this);
+ root_->RemovePreTargetHandler(this);
+ root_->RemoveObserver(this);
+ root_ = NULL;
+ }
+
+ MenuController* controller_;
+ aura::Window* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
+};
+
+} // namespace
+
+// static
+MenuMessageLoop* MenuMessageLoop::Create() {
+ return new MenuMessageLoopAura;
+}
+
+MenuMessageLoopAura::MenuMessageLoopAura() : owner_(NULL) {
+}
+
+MenuMessageLoopAura::~MenuMessageLoopAura() {
+}
+
+void MenuMessageLoopAura::RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) {
+ aura::Window* root = window->GetRootWindow();
+ ScreenPositionClient* spc = aura::client::GetScreenPositionClient(root);
+ if (!spc)
+ return;
+
+ gfx::Point root_loc(screen_loc);
+ spc->ConvertPointFromScreen(root, &root_loc);
+
+ ui::MouseEvent clone(static_cast<const ui::MouseEvent&>(event));
+ clone.set_location(root_loc);
+ clone.set_root_location(root_loc);
+ root->GetHost()->dispatcher()->RepostEvent(clone);
+}
+
+void MenuMessageLoopAura::Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) {
+ // |owner_| may be NULL.
+ owner_ = owner;
+ aura::Window* root = GetOwnerRootWindow(owner_);
+ // It is possible for the same MenuMessageLoopAura to start a nested
+ // message-loop while it is already running a nested loop. So make sure the
+ // quit-closure gets reset to the outer loop's quit-closure once the innermost
+ // loop terminates.
+ base::AutoReset<base::Closure> reset_quit_closure(&message_loop_quit_,
+ base::Closure());
+
+#if defined(OS_WIN)
+ internal::MenuMessagePumpDispatcher nested_dispatcher(controller);
+ if (root) {
+ scoped_ptr<ActivationChangeObserverImpl> observer;
+ if (!nested_menu)
+ observer.reset(new ActivationChangeObserverImpl(controller, root));
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root), &nested_dispatcher);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ } else {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop(&nested_dispatcher);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+#else
+ internal::MenuEventDispatcher event_dispatcher(controller);
+ scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
+ nested_dispatcher_.Pass();
+ if (ui::PlatformEventSource::GetInstance()) {
+ nested_dispatcher_ =
+ ui::PlatformEventSource::GetInstance()->OverrideDispatcher(
+ &event_dispatcher);
+ }
+ if (root) {
+ scoped_ptr<ActivationChangeObserverImpl> observer;
+ if (!nested_menu)
+ observer.reset(new ActivationChangeObserverImpl(controller, root));
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root), NULL);
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ } else {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop;
+ message_loop_quit_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+ nested_dispatcher_ = old_dispatcher.Pass();
+#endif
+}
+
+bool MenuMessageLoopAura::ShouldQuitNow() const {
+ aura::Window* root = GetOwnerRootWindow(owner_);
+ return !aura::client::GetDragDropClient(root) ||
+ !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
+}
+
+void MenuMessageLoopAura::QuitNow() {
+ CHECK(!message_loop_quit_.is_null());
+ message_loop_quit_.Run();
+ // Restore the previous dispatcher.
+ nested_dispatcher_.reset();
+}
+
+void MenuMessageLoopAura::ClearOwner() {
+ owner_ = NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.h b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
new file mode 100644
index 00000000000..49e8a392827
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
@@ -0,0 +1,52 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
+
+namespace base {
+class MessagePumpDispatcher;
+}
+
+namespace ui {
+class ScopedEventDispatcher;
+}
+
+namespace views {
+
+class MenuMessageLoopAura : public MenuMessageLoop {
+ public:
+ MenuMessageLoopAura();
+ virtual ~MenuMessageLoopAura();
+
+ // Overridden from MenuMessageLoop:
+ virtual void Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) OVERRIDE;
+ virtual bool ShouldQuitNow() const OVERRIDE;
+ virtual void QuitNow() OVERRIDE;
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) OVERRIDE;
+ virtual void ClearOwner() OVERRIDE;
+
+ private:
+ // Owner of child windows.
+ // WARNING: this may be NULL.
+ Widget* owner_;
+
+ scoped_ptr<ui::ScopedEventDispatcher> nested_dispatcher_;
+ base::Closure message_loop_quit_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuMessageLoopAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.cc b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
new file mode 100644
index 00000000000..b1c10cca7d8
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_loop_mac.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace views {
+
+// static
+MenuMessageLoop* MenuMessageLoop::Create() {
+ return new MenuMessageLoopMac;
+}
+
+MenuMessageLoopMac::MenuMessageLoopMac() {
+}
+
+MenuMessageLoopMac::~MenuMessageLoopMac() {
+}
+
+void MenuMessageLoopMac::RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) {
+ NOTIMPLEMENTED();
+}
+
+void MenuMessageLoopMac::Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow(loop);
+ base::RunLoop run_loop;
+ run_loop.Run();
+}
+
+bool MenuMessageLoopMac::ShouldQuitNow() const {
+ return true;
+}
+
+void MenuMessageLoopMac::QuitNow() {
+ base::MessageLoop::current()->QuitNow();
+}
+
+void MenuMessageLoopMac::ClearOwner() {
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.h b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
new file mode 100644
index 00000000000..b77d263ffbb
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
+
+#include "base/compiler_specific.h"
+#include "ui/views/controls/menu/menu_message_loop.h"
+
+namespace views {
+
+class MenuMessageLoopMac : public MenuMessageLoop {
+ public:
+ MenuMessageLoopMac();
+ virtual ~MenuMessageLoopMac();
+
+ // Overridden from MenuMessageLoop:
+ virtual void Run(MenuController* controller,
+ Widget* owner,
+ bool nested_menu) OVERRIDE;
+ virtual bool ShouldQuitNow() const OVERRIDE;
+ virtual void QuitNow() OVERRIDE;
+ virtual void RepostEventToWindow(const ui::LocatedEvent& event,
+ gfx::NativeWindow window,
+ const gfx::Point& screen_loc) OVERRIDE;
+ virtual void ClearOwner() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MenuMessageLoopMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_MAC_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc
new file mode 100644
index 00000000000..8f905d029ae
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
+
+#include <windowsx.h>
+
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+
+namespace views {
+namespace internal {
+
+MenuMessagePumpDispatcher::MenuMessagePumpDispatcher(MenuController* controller)
+ : menu_controller_(controller) {}
+
+MenuMessagePumpDispatcher::~MenuMessagePumpDispatcher() {}
+
+uint32_t MenuMessagePumpDispatcher::Dispatch(const MSG& msg) {
+ DCHECK(menu_controller_->IsBlockingRun());
+
+ bool should_quit = false;
+ bool should_perform_default = true;
+ if (menu_controller_->exit_type() == MenuController::EXIT_ALL ||
+ menu_controller_->exit_type() == MenuController::EXIT_DESTROYED) {
+ should_quit = true;
+ } else {
+ // NOTE: we don't get WM_ACTIVATE or anything else interesting in here.
+ switch (msg.message) {
+ case WM_CONTEXTMENU: {
+ MenuItemView* item = menu_controller_->pending_state_.item;
+ if (item && item->GetRootMenuItem() != item) {
+ gfx::Point screen_loc(0, item->height());
+ View::ConvertPointToScreen(item, &screen_loc);
+ ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
+ if (GET_X_LPARAM(msg.lParam) == -1 && GET_Y_LPARAM(msg.lParam) == -1)
+ source_type = ui::MENU_SOURCE_KEYBOARD;
+ item->GetDelegate()->ShowContextMenu(
+ item, item->GetCommand(), screen_loc, source_type);
+ }
+ should_quit = false;
+ should_perform_default = false;
+ break;
+ }
+
+ // NOTE: focus wasn't changed when the menu was shown. As such, don't
+ // dispatch key events otherwise the focused window will get the events.
+ case WM_KEYDOWN: {
+ bool result =
+ menu_controller_->OnKeyDown(ui::KeyboardCodeFromNative(msg));
+ TranslateMessage(&msg);
+ should_perform_default = false;
+ should_quit = !result;
+ break;
+ }
+ case WM_CHAR: {
+ should_quit = menu_controller_->SelectByChar(
+ static_cast<base::char16>(msg.wParam));
+ should_perform_default = false;
+ break;
+ }
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ // We may have been shown on a system key, as such don't do anything
+ // here. If another system key is pushed we'll get a WM_SYSKEYDOWN and
+ // close the menu.
+ should_quit = false;
+ should_perform_default = false;
+ break;
+
+ case WM_CANCELMODE:
+ case WM_SYSKEYDOWN:
+ // Exit immediately on system keys.
+ menu_controller_->Cancel(MenuController::EXIT_ALL);
+ should_quit = true;
+ should_perform_default = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (should_quit || menu_controller_->exit_type() != MenuController::EXIT_NONE)
+ menu_controller_->TerminateNestedMessageLoop();
+ return should_perform_default ? POST_DISPATCH_PERFORM_DEFAULT
+ : POST_DISPATCH_NONE;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h
new file mode 100644
index 00000000000..31f1b369610
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_message_pump_dispatcher_win.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
+
+#include "base/macros.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+
+namespace views {
+
+class MenuController;
+
+namespace internal {
+
+// A message-pump dispatcher object used to dispatch events from the nested
+// message-loop initiated by the MenuController.
+class MenuMessagePumpDispatcher : public base::MessagePumpDispatcher {
+ public:
+ explicit MenuMessagePumpDispatcher(MenuController* menu_controller);
+ virtual ~MenuMessagePumpDispatcher();
+
+ private:
+ // base::MessagePumpDispatcher:
+ virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE;
+
+ MenuController* menu_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuMessagePumpDispatcher);
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_PUMP_DISPATCHER_WIN_H_
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index 07f1f403fd8..55c5d7d21d9 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -8,6 +8,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/views_delegate.h"
@@ -59,7 +60,7 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
int item_id) {
gfx::Image icon;
model->GetIconAt(model_index, &icon);
- string16 label, sublabel, minor_text;
+ base::string16 label, sublabel, minor_text;
ui::MenuSeparatorType separator_style = ui::NORMAL_SEPARATOR;
MenuItemView::Type type;
ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index);
@@ -161,7 +162,7 @@ bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source,
}
bool MenuModelAdapter::GetAccelerator(int id,
- ui::Accelerator* accelerator) {
+ ui::Accelerator* accelerator) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
@@ -171,27 +172,27 @@ bool MenuModelAdapter::GetAccelerator(int id,
return false;
}
-string16 MenuModelAdapter::GetLabel(int id) const {
+base::string16 MenuModelAdapter::GetLabel(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
return model->GetLabelAt(index);
NOTREACHED();
- return string16();
+ return base::string16();
}
-const gfx::Font* MenuModelAdapter::GetLabelFont(int id) const {
+const gfx::FontList* MenuModelAdapter::GetLabelFontList(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
- const gfx::Font* font = model->GetLabelFontAt(index);
- if (font)
- return font;
+ const gfx::FontList* font_list = model->GetLabelFontListAt(index);
+ if (font_list)
+ return font_list;
}
// This line may be reached for the empty menu item.
- return MenuDelegate::GetLabelFont(id);
+ return MenuDelegate::GetLabelFontList(id);
}
bool MenuModelAdapter::IsCommandEnabled(int id) const {
@@ -204,6 +205,16 @@ bool MenuModelAdapter::IsCommandEnabled(int id) const {
return false;
}
+bool MenuModelAdapter::IsCommandVisible(int id) const {
+ ui::MenuModel* model = menu_model_;
+ int index = 0;
+ if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
+ return model->IsVisibleAt(index);
+
+ NOTREACHED();
+ return false;
+}
+
bool MenuModelAdapter::IsItemChecked(int id) const {
ui::MenuModel* model = menu_model_;
int index = 0;
@@ -264,9 +275,6 @@ void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) {
for (int i = 0; i < item_count; ++i) {
MenuItemView* item = AppendMenuItem(menu, model, i);
- if (item)
- item->SetVisible(model->IsVisibleAt(i));
-
if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
DCHECK(item);
DCHECK_EQ(MenuItemView::SUBMENU, item->GetType());
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.h b/chromium/ui/views/controls/menu/menu_model_adapter.h
index 4db9dbe2cf9..353d010c533 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.h
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.h
@@ -67,10 +67,11 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate {
virtual bool IsTriggerableEvent(MenuItemView* source,
const ui::Event& e) OVERRIDE;
virtual bool GetAccelerator(int id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual string16 GetLabel(int id) const OVERRIDE;
- virtual const gfx::Font* GetLabelFont(int id) const OVERRIDE;
+ ui::Accelerator* accelerator) const OVERRIDE;
+ virtual base::string16 GetLabel(int id) const OVERRIDE;
+ virtual const gfx::FontList* GetLabelFontList(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
+ virtual bool IsCommandVisible(int id) const OVERRIDE;
virtual bool IsItemChecked(int id) const OVERRIDE;
virtual void SelectionChanged(MenuItemView* menu) OVERRIDE;
virtual void WillShowMenu(MenuItemView* menu) OVERRIDE;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 6ce3a376270..cba4d2fa7fb 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/controls/menu/menu_model_adapter.h"
+
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/models/menu_model_delegate.h"
#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/test/views_test_base.h"
@@ -51,7 +52,7 @@ class MenuModelBase : public ui::MenuModel {
return index + command_id_base_;
}
- virtual string16 GetLabelAt(int index) const OVERRIDE {
+ virtual base::string16 GetLabelAt(int index) const OVERRIDE {
return items_[index].label;
}
@@ -59,7 +60,7 @@ class MenuModelBase : public ui::MenuModel {
return false;
}
- virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE {
+ virtual const gfx::FontList* GetLabelFontListAt(int index) const OVERRIDE {
return NULL;
}
@@ -128,12 +129,12 @@ class MenuModelBase : public ui::MenuModel {
const std::string& item_label,
ui::MenuModel* item_submenu)
: type(item_type),
- label(ASCIIToUTF16(item_label)),
+ label(base::ASCIIToUTF16(item_label)),
submenu(item_submenu) {
}
ItemType type;
- string16 label;
+ base::string16 label;
ui::MenuModel* submenu;
};
diff --git a/chromium/ui/views/controls/menu/menu_runner.cc b/chromium/ui/views/controls/menu/menu_runner.cc
index e254dbffc55..ca36d026433 100644
--- a/chromium/ui/views/controls/menu/menu_runner.cc
+++ b/chromium/ui/views/controls/menu/menu_runner.cc
@@ -12,6 +12,7 @@
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner_handler.h"
#include "ui/views/widget/widget.h"
@@ -43,7 +44,7 @@ class MenuRunnerImpl : public internal::MenuControllerDelegate {
MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
int32 types) WARN_UNUSED_RESULT;
void Cancel();
@@ -140,12 +141,11 @@ void MenuRunnerImpl::Release() {
}
}
-MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(
- Widget* parent,
- MenuButton* button,
- const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
- int32 types) {
+MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(Widget* parent,
+ MenuButton* button,
+ const gfx::Rect& bounds,
+ MenuAnchorPosition anchor,
+ int32 types) {
closing_event_time_ = base::TimeDelta();
if (running_) {
// Ignore requests to show the menu while it's already showing. MenuItemView
@@ -186,7 +186,7 @@ MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(
controller = new MenuController(theme, !for_drop_, this);
owns_controller_ = true;
}
- controller->set_accept_on_f4((types & MenuRunner::COMBOBOX) != 0);
+ controller->set_is_combobox((types & MenuRunner::COMBOBOX) != 0);
controller_ = controller;
menu_->set_controller(controller_);
menu_->PrepareForRun(owns_controller_,
@@ -278,16 +278,6 @@ bool MenuRunnerImpl::ShouldShowMnemonics(MenuButton* button) {
return show_mnemonics;
}
-// In theory we could implement this every where, but for now we're only
-// implementing it on aura.
-#if !defined(USE_AURA)
-// static
-DisplayChangeListener* DisplayChangeListener::Create(Widget* widget,
- MenuRunner* runner) {
- return NULL;
-}
-#endif
-
} // namespace internal
MenuRunner::MenuRunner(ui::MenuModel* menu_model)
@@ -310,7 +300,7 @@ MenuItemView* MenuRunner::GetMenu() {
MenuRunner::RunResult MenuRunner::RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) {
if (runner_handler_.get()) {
@@ -331,11 +321,11 @@ MenuRunner::RunResult MenuRunner::RunMenuAt(Widget* parent,
case ui::MENU_SOURCE_NONE:
case ui::MENU_SOURCE_KEYBOARD:
case ui::MENU_SOURCE_MOUSE:
- anchor = MenuItemView::TOPLEFT;
+ anchor = MENU_ANCHOR_TOPLEFT;
break;
case ui::MENU_SOURCE_TOUCH:
case ui::MENU_SOURCE_TOUCH_EDIT_MENU:
- anchor = MenuItemView::BOTTOMCENTER;
+ anchor = MENU_ANCHOR_BOTTOMCENTER;
break;
default:
break;
diff --git a/chromium/ui/views/controls/menu/menu_runner.h b/chromium/ui/views/controls/menu/menu_runner.h
index 6b46362f18e..824afdf8d4b 100644
--- a/chromium/ui/views/controls/menu/menu_runner.h
+++ b/chromium/ui/views/controls/menu/menu_runner.h
@@ -8,7 +8,17 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/menu/menu_types.h"
+#include "ui/views/views_export.h"
+
+namespace base {
+class TimeDelta;
+}
+
+namespace gfx {
+class Rect;
+}
namespace ui {
class MenuModel;
@@ -17,6 +27,7 @@ class MenuModel;
namespace views {
class MenuButton;
+class MenuItemView;
class MenuModelAdapter;
class MenuRunnerHandler;
class Widget;
@@ -103,7 +114,7 @@ class VIEWS_EXPORT MenuRunner {
RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) WARN_UNUSED_RESULT;
diff --git a/chromium/ui/views/controls/menu/menu_runner_handler.h b/chromium/ui/views/controls/menu/menu_runner_handler.h
index 46f801af685..47d75c80fce 100644
--- a/chromium/ui/views/controls/menu/menu_runner_handler.h
+++ b/chromium/ui/views/controls/menu/menu_runner_handler.h
@@ -6,11 +6,11 @@
#define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_HANDLER_H_
#include "base/basictypes.h"
-#include "ui/views/controls/menu/menu_item_view.h"
namespace views {
class MenuButton;
+class MenuItemView;
class Widget;
// Used internally by MenuRunner to show the menu. Can be set in tests (see
@@ -21,7 +21,7 @@ class VIEWS_EXPORT MenuRunnerHandler {
virtual MenuRunner::RunResult RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition anchor,
+ MenuAnchorPosition anchor,
ui::MenuSourceType source_type,
int32 types) = 0;
};
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 7b8edbecab5..451bd1537ad 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -6,8 +6,9 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
+#include "ui/native_theme/native_theme_aura.h"
#include "ui/views/border.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -16,10 +17,6 @@
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/round_rect_painter.h"
-#if defined(USE_AURA)
-#include "ui/native_theme/native_theme_aura.h"
-#endif
-
using ui::NativeTheme;
namespace views {
@@ -43,7 +40,7 @@ class MenuScrollButton : public View {
pref_height_(MenuItemView::pref_menu_height()) {
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return gfx::Size(
host_->GetMenuItem()->GetMenuConfig().scroll_arrow_height * 2 - 1,
pref_height_);
@@ -246,7 +243,7 @@ void MenuScrollViewContainer::Layout() {
scroll_view_->Layout();
}
-gfx::Size MenuScrollViewContainer::GetPreferredSize() {
+gfx::Size MenuScrollViewContainer::GetPreferredSize() const {
gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
gfx::Insets insets = GetInsets();
prefsize.Enlarge(insets.width(), insets.height());
@@ -254,15 +251,15 @@ gfx::Size MenuScrollViewContainer::GetPreferredSize() {
}
void MenuScrollViewContainer::GetAccessibleState(
- ui::AccessibleViewState* state) {
+ ui::AXViewState* state) {
// Get the name from the submenu view.
content_view_->GetAccessibleState(state);
// Now change the role.
- state->role = ui::AccessibilityTypes::ROLE_MENUBAR;
+ state->role = ui::AX_ROLE_MENU_BAR;
// Some AT (like NVDA) will not process focus events on menu item children
// unless a parent claims to be focused.
- state->state = ui::AccessibilityTypes::STATE_FOCUSED;
+ state->AddStateFlag(ui::AX_STATE_FOCUSED);
}
void MenuScrollViewContainer::OnBoundsChanged(
@@ -284,7 +281,7 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
int padding = menu_config.corner_radius > 0 ?
kBorderPaddingDueToRoundedCorners : 0;
-#if defined(USE_AURA)
+#if defined(USE_AURA) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
if (menu_config.native_theme == ui::NativeThemeAura::instance()) {
// In case of NativeThemeAura the border gets drawn with the shadow.
// Furthermore no additional padding is wanted.
@@ -299,13 +296,14 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
int right = menu_config.menu_horizontal_border_size + padding;
if (use_border) {
- set_border(views::Border::CreateBorderPainter(
- new views::RoundRectPainter(menu_config.native_theme->GetSystemColor(
+ SetBorder(views::Border::CreateBorderPainter(
+ new views::RoundRectPainter(
+ menu_config.native_theme->GetSystemColor(
ui::NativeTheme::kColorId_MenuBorderColor),
menu_config.corner_radius),
- gfx::Insets(top, left, bottom, right)));
+ gfx::Insets(top, left, bottom, right)));
} else {
- set_border(Border::CreateEmptyBorder(top, left, bottom, right));
+ SetBorder(Border::CreateEmptyBorder(top, left, bottom, right));
}
}
@@ -313,21 +311,20 @@ void MenuScrollViewContainer::CreateBubbleBorder() {
bubble_border_ = new BubbleBorder(arrow_,
BubbleBorder::SMALL_SHADOW,
SK_ColorWHITE);
- set_border(bubble_border_);
+ SetBorder(scoped_ptr<Border>(bubble_border_));
set_background(new BubbleBackground(bubble_border_));
}
-BubbleBorder::Arrow
-MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
- MenuItemView::AnchorPosition anchor) {
+BubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
+ MenuAnchorPosition anchor) {
switch (anchor) {
- case views::MenuItemView::BUBBLE_LEFT:
+ case MENU_ANCHOR_BUBBLE_LEFT:
return BubbleBorder::RIGHT_CENTER;
- case views::MenuItemView::BUBBLE_RIGHT:
+ case MENU_ANCHOR_BUBBLE_RIGHT:
return BubbleBorder::LEFT_CENTER;
- case views::MenuItemView::BUBBLE_ABOVE:
+ case MENU_ANCHOR_BUBBLE_ABOVE:
return BubbleBorder::BOTTOM_CENTER;
- case views::MenuItemView::BUBBLE_BELOW:
+ case MENU_ANCHOR_BUBBLE_BELOW:
return BubbleBorder::TOP_CENTER;
default:
return BubbleBorder::NONE;
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.h b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
index 83baa2a3939..dc7c1acf164 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
@@ -7,7 +7,7 @@
#include "ui/views/view.h"
#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_types.h"
namespace views {
@@ -33,8 +33,8 @@ class MenuScrollViewContainer : public View {
// View overrides.
virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// View override.
@@ -47,8 +47,7 @@ class MenuScrollViewContainer : public View {
// Create the bubble border.
void CreateBubbleBorder();
- BubbleBorder::Arrow BubbleBorderTypeFromAnchor(
- MenuItemView::AnchorPosition anchor);
+ BubbleBorder::Arrow BubbleBorderTypeFromAnchor(MenuAnchorPosition anchor);
class MenuScrollView;
@@ -65,7 +64,7 @@ class MenuScrollViewContainer : public View {
// If set the currently set border is a bubble border.
BubbleBorder::Arrow arrow_;
- // The currently set border.
+ // Weak reference to the currently set border.
BubbleBorder* bubble_border_;
DISALLOW_COPY_AND_ASSIGN(MenuScrollViewContainer);
diff --git a/chromium/ui/views/controls/menu/menu_separator.h b/chromium/ui/views/controls/menu/menu_separator.h
index 4098ae8f0ae..da459e2b07a 100644
--- a/chromium/ui/views/controls/menu/menu_separator.h
+++ b/chromium/ui/views/controls/menu/menu_separator.h
@@ -21,13 +21,11 @@ class MenuSeparator : public View {
// View overrides.
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
private:
-#if defined(USE_AURA)
void OnPaintAura(gfx::Canvas* canvas);
- gfx::Size GetPreferredSizeAura();
-#endif
+ gfx::Size GetPreferredSizeAura() const;
// The type of the separator.
const ui::MenuSeparatorType type_;
diff --git a/chromium/ui/views/controls/menu/menu_separator_views.cc b/chromium/ui/views/controls/menu/menu_separator_views.cc
index affbae48966..34f85453501 100644
--- a/chromium/ui/views/controls/menu/menu_separator_views.cc
+++ b/chromium/ui/views/controls/menu/menu_separator_views.cc
@@ -23,7 +23,7 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
OnPaintAura(canvas);
}
-gfx::Size MenuSeparator::GetPreferredSize() {
+gfx::Size MenuSeparator::GetPreferredSize() const {
return GetPreferredSizeAura();
}
#endif
@@ -47,7 +47,7 @@ void MenuSeparator::OnPaintAura(gfx::Canvas* canvas) {
ui::NativeTheme::kColorId_MenuSeparatorColor));
}
-gfx::Size MenuSeparator::GetPreferredSizeAura() {
+gfx::Size MenuSeparator::GetPreferredSizeAura() const {
const MenuConfig& menu_config = parent_menu_item_->GetMenuConfig();
int height = menu_config.separator_height;
switch(type_) {
diff --git a/chromium/ui/views/controls/menu/menu_separator_win.cc b/chromium/ui/views/controls/menu/menu_separator_win.cc
index 6f95334790a..ccbcaed263e 100644
--- a/chromium/ui/views/controls/menu/menu_separator_win.cc
+++ b/chromium/ui/views/controls/menu/menu_separator_win.cc
@@ -11,24 +11,19 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/native_theme_aura.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_item_view.h"
-#if defined(USE_AURA)
-#include "ui/native_theme/native_theme_aura.h"
-#endif
-
namespace views {
void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
const MenuConfig& config = parent_menu_item_->GetMenuConfig();
-#if defined(USE_AURA)
if (config.native_theme == ui::NativeThemeAura::instance()) {
OnPaintAura(canvas);
return;
}
-#endif
int start_x = 0;
if (config.render_gutter) {
@@ -52,13 +47,11 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) {
ui::NativeTheme::kNormal, separator_bounds, extra);
}
-gfx::Size MenuSeparator::GetPreferredSize() {
+gfx::Size MenuSeparator::GetPreferredSize() const {
const MenuConfig& config = parent_menu_item_->GetMenuConfig();
-#if defined(USE_AURA)
if (config.native_theme == ui::NativeThemeAura::instance())
return GetPreferredSizeAura();
-#endif
return gfx::Size(10, // Just in case we're the only item in a menu.
config.separator_height);
diff --git a/chromium/ui/views/controls/menu/menu_types.h b/chromium/ui/views/controls/menu/menu_types.h
new file mode 100644
index 00000000000..160dd5ae3d1
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_types.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
+
+namespace views {
+
+// Where a popup menu should be anchored to for non-RTL languages. The opposite
+// position will be used if base::i18n:IsRTL() is true. The BUBBLE flags are
+// used when the menu should get enclosed by a bubble. Note that BUBBLE flags
+// should only be used with menus which have no children.
+enum MenuAnchorPosition {
+ MENU_ANCHOR_TOPLEFT,
+ MENU_ANCHOR_TOPRIGHT,
+ MENU_ANCHOR_BOTTOMCENTER,
+ MENU_ANCHOR_BUBBLE_LEFT,
+ MENU_ANCHOR_BUBBLE_RIGHT,
+ MENU_ANCHOR_BUBBLE_ABOVE,
+ MENU_ANCHOR_BUBBLE_BELOW
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_TYPES_H_
diff --git a/chromium/ui/views/controls/menu/menu_win.cc b/chromium/ui/views/controls/menu/menu_win.cc
deleted file mode 100644
index d88659ff7d4..00000000000
--- a/chromium/ui/views/controls/menu/menu_win.cc
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/menu/menu_win.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/win/window_impl.h"
-#include "ui/views/layout/layout_constants.h"
-
-namespace views {
-
-// The width of an icon, including the pixels between the icon and
-// the item label.
-const int kIconWidth = 23;
-// Margins between the top of the item and the label.
-const int kItemTopMargin = 3;
-// Margins between the bottom of the item and the label.
-const int kItemBottomMargin = 4;
-// Margins between the left of the item and the icon.
-const int kItemLeftMargin = 4;
-// The width for displaying the sub-menu arrow.
-const int kArrowWidth = 10;
-
-// Current active MenuHostWindow. If NULL, no menu is active.
-static MenuHostWindow* active_host_window = NULL;
-
-// The data of menu items needed to display.
-struct MenuWin::ItemData {
- string16 label;
- gfx::ImageSkia icon;
- bool submenu;
-};
-
-namespace {
-
-static int ChromeGetMenuItemID(HMENU hMenu, int pos) {
- // The built-in Windows GetMenuItemID doesn't work for submenus,
- // so here's our own implementation.
- MENUITEMINFO mii = {0};
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_ID;
- GetMenuItemInfo(hMenu, pos, TRUE, &mii);
- return mii.wID;
-}
-
-// MenuHostWindow -------------------------------------------------------------
-
-// MenuHostWindow is the HWND the HMENU is parented to. MenuHostWindow is used
-// to intercept right clicks on the HMENU and notify the delegate as well as
-// for drawing icons.
-//
-class MenuHostWindow : public gfx::WindowImpl {
- public:
- MenuHostWindow(MenuWin* menu, HWND parent_window) : menu_(menu) {
- int extended_style = 0;
- // If the menu needs to be created with a right-to-left UI layout, we must
- // set the appropriate RTL flags (such as WS_EX_LAYOUTRTL) property for the
- // underlying HWND.
- if (menu_->delegate()->IsRightToLeftUILayout())
- extended_style |= l10n_util::GetExtendedStyles();
- set_window_style(WS_CHILD);
- set_window_ex_style(extended_style);
- Init(parent_window, gfx::Rect());
- }
-
- ~MenuHostWindow() {
- DestroyWindow(hwnd());
- }
-
- BEGIN_MSG_MAP_EX(MenuHostWindow);
- MSG_WM_RBUTTONUP(OnRButtonUp)
- MSG_WM_MEASUREITEM(OnMeasureItem)
- MSG_WM_DRAWITEM(OnDrawItem)
- END_MSG_MAP();
-
- private:
- // NOTE: I really REALLY tried to use WM_MENURBUTTONUP, but I ran into
- // two problems in using it:
- // 1. It doesn't contain the coordinates of the mouse.
- // 2. It isn't invoked for menuitems representing a submenu that have children
- // menu items (not empty).
-
- void OnRButtonUp(UINT w_param, const CPoint& loc) {
- int id;
- if (menu_->delegate() && FindMenuIDByLocation(menu_, loc, &id))
- menu_->delegate()->ShowContextMenu(menu_, id, gfx::Point(loc), true);
- }
-
- void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* lpmis) {
- MenuWin::ItemData* data =
- reinterpret_cast<MenuWin::ItemData*>(lpmis->itemData);
- if (data != NULL) {
- gfx::Font font;
- lpmis->itemWidth = font.GetStringWidth(data->label) + kIconWidth +
- kItemLeftMargin + views::kItemLabelSpacing -
- GetSystemMetrics(SM_CXMENUCHECK);
- if (data->submenu)
- lpmis->itemWidth += kArrowWidth;
- // If the label contains an accelerator, make room for tab.
- if (data->label.find(L'\t') != string16::npos)
- lpmis->itemWidth += font.GetStringWidth(L" ");
- lpmis->itemHeight = font.GetHeight() + kItemBottomMargin + kItemTopMargin;
- } else {
- // Measure separator size.
- lpmis->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
- lpmis->itemWidth = 0;
- }
- }
-
- void OnDrawItem(UINT wParam, DRAWITEMSTRUCT* lpdis) {
- HDC hDC = lpdis->hDC;
- COLORREF prev_bg_color, prev_text_color;
-
- // Set background color and text color
- if (lpdis->itemState & ODS_SELECTED) {
- prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
- } else {
- prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_MENU));
- if (lpdis->itemState & ODS_DISABLED)
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
- else
- prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT));
- }
-
- if (lpdis->itemData) {
- MenuWin::ItemData* data =
- reinterpret_cast<MenuWin::ItemData*>(lpdis->itemData);
-
- // Draw the background.
- HBRUSH hbr = CreateSolidBrush(GetBkColor(hDC));
- FillRect(hDC, &lpdis->rcItem, hbr);
- DeleteObject(hbr);
-
- // Draw the label.
- RECT rect = lpdis->rcItem;
- rect.top += kItemTopMargin;
- // Should we add kIconWidth only when icon.width() != 0 ?
- rect.left += kItemLeftMargin + kIconWidth;
- rect.right -= views::kItemLabelSpacing;
- UINT format = DT_TOP | DT_SINGLELINE;
- // Check whether the mnemonics should be underlined.
- BOOL underline_mnemonics;
- SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
- if (!underline_mnemonics)
- format |= DT_HIDEPREFIX;
- gfx::Font font;
- HGDIOBJ old_font =
- static_cast<HFONT>(SelectObject(hDC, font.GetNativeFont()));
-
- // If an accelerator is specified (with a tab delimiting the rest of the
- // label from the accelerator), we have to justify the fist part on the
- // left and the accelerator on the right.
- // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
- // window system UI font and will not hit here.
- string16 label = data->label;
- string16 accel;
- string16::size_type tab_pos = label.find(L'\t');
- if (tab_pos != string16::npos) {
- accel = label.substr(tab_pos);
- label = label.substr(0, tab_pos);
- }
- DrawTextEx(hDC, const_cast<wchar_t*>(label.data()),
- static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
- if (!accel.empty())
- DrawTextEx(hDC, const_cast<wchar_t*>(accel.data()),
- static_cast<int>(accel.size()), &rect,
- format | DT_RIGHT, NULL);
- SelectObject(hDC, old_font);
-
- // Draw the icon after the label, otherwise it would be covered
- // by the label.
- gfx::ImageSkiaRep icon_image_rep = data->icon.GetRepresentation(1.0f);
- if (data->icon.width() != 0 && data->icon.height() != 0) {
- gfx::Canvas canvas(icon_image_rep, false);
- skia::DrawToNativeContext(
- canvas.sk_canvas(), hDC, lpdis->rcItem.left + kItemLeftMargin,
- lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top -
- data->icon.height()) / 2, NULL);
- }
-
- } else {
- // Draw the separator
- lpdis->rcItem.top += (lpdis->rcItem.bottom - lpdis->rcItem.top) / 3;
- DrawEdge(hDC, &lpdis->rcItem, EDGE_ETCHED, BF_TOP);
- }
-
- SetBkColor(hDC, prev_bg_color);
- SetTextColor(hDC, prev_text_color);
- }
-
- bool FindMenuIDByLocation(MenuWin* menu, const CPoint& loc, int* id) {
- int index = MenuItemFromPoint(NULL, menu->menu_, loc);
- if (index != -1) {
- *id = ChromeGetMenuItemID(menu->menu_, index);
- return true;
- } else {
- for (std::vector<MenuWin*>::iterator i = menu->submenus_.begin();
- i != menu->submenus_.end(); ++i) {
- if (FindMenuIDByLocation(*i, loc, id))
- return true;
- }
- }
- return false;
- }
-
- // The menu that created us.
- MenuWin* menu_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
-};
-
-} // namespace
-
-// static
-Menu* Menu::Create(Delegate* delegate,
- AnchorPoint anchor,
- gfx::NativeView parent) {
- return new MenuWin(delegate, anchor, parent);
-}
-
-// static
-Menu* Menu::GetSystemMenu(gfx::NativeWindow parent) {
- return new views::MenuWin(::GetSystemMenu(parent, FALSE));
-}
-
-MenuWin::MenuWin(Delegate* d, AnchorPoint anchor, HWND owner)
- : Menu(d, anchor),
- menu_(CreatePopupMenu()),
- owner_(owner),
- is_menu_visible_(false),
- owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL)) {
- DCHECK(delegate());
-}
-
-MenuWin::MenuWin(HMENU hmenu)
- : Menu(NULL, TOPLEFT),
- menu_(hmenu),
- owner_(NULL),
- is_menu_visible_(false),
- owner_draw_(false) {
- DCHECK(menu_);
-}
-
-MenuWin::~MenuWin() {
- STLDeleteContainerPointers(submenus_.begin(), submenus_.end());
- STLDeleteContainerPointers(item_data_.begin(), item_data_.end());
- DestroyMenu(menu_);
-}
-
-void MenuWin::AddMenuItemWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) {
- owner_draw_ = true;
- Menu::AddMenuItemWithIcon(index, item_id, label, icon);
-}
-
-Menu* MenuWin::AddSubMenuWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) {
- MenuWin* submenu = new MenuWin(this);
- submenus_.push_back(submenu);
- AddMenuItemInternal(index, item_id, label, icon, submenu->menu_, NORMAL);
- return submenu;
-}
-
-void MenuWin::AddSeparator(int index) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE;
- mii.fType = MFT_SEPARATOR;
- InsertMenuItem(menu_, index, TRUE, &mii);
-}
-
-void MenuWin::EnableMenuItemByID(int item_id, bool enabled) {
- UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
- EnableMenuItem(menu_, item_id, MF_BYCOMMAND | enable_flags);
-}
-
-void MenuWin::EnableMenuItemAt(int index, bool enabled) {
- UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
- EnableMenuItem(menu_, index, MF_BYPOSITION | enable_flags);
-}
-
-void MenuWin::SetMenuLabel(int item_id, const string16& label) {
- MENUITEMINFO mii = {0};
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STRING;
- mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
- mii.cch = static_cast<UINT>(label.size());
- SetMenuItemInfo(menu_, item_id, false, &mii);
-}
-
-bool MenuWin::SetIcon(const gfx::ImageSkia& icon, int item_id) {
- if (!owner_draw_)
- owner_draw_ = true;
-
- const int num_items = GetMenuItemCount(menu_);
- int sep_count = 0;
- for (int i = 0; i < num_items; ++i) {
- if (!(GetMenuState(menu_, i, MF_BYPOSITION) & MF_SEPARATOR)) {
- if (ChromeGetMenuItemID(menu_, i) == item_id) {
- item_data_[i - sep_count]->icon = icon;
- // When the menu is running, we use SetMenuItemInfo to let Windows
- // update the item information so that the icon being displayed
- // could change immediately.
- if (active_host_window) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE | MIIM_DATA;
- mii.fType = MFT_OWNERDRAW;
- mii.dwItemData =
- reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
- SetMenuItemInfo(menu_, item_id, false, &mii);
- }
- return true;
- }
- } else {
- ++sep_count;
- }
- }
-
- // Continue searching for the item in submenus.
- for (size_t i = 0; i < submenus_.size(); ++i) {
- if (submenus_[i]->SetIcon(icon, item_id))
- return true;
- }
-
- return false;
-}
-
-void MenuWin::RunMenuAt(int x, int y) {
- SetMenuInfo();
-
- delegate()->MenuWillShow();
-
- // NOTE: we don't use TPM_RIGHTBUTTON here as it breaks selecting by way of
- // press, drag, release. See bugs 718 and 8560.
- UINT flags =
- GetTPMAlignFlags() | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
- is_menu_visible_ = true;
- DCHECK(owner_);
- // In order for context menus on menus to work, the context menu needs to
- // share the same window as the first menu is parented to.
- bool created_host = false;
- if (!active_host_window) {
- created_host = true;
- active_host_window = new MenuHostWindow(this, owner_);
- }
- UINT selected_id =
- TrackPopupMenuEx(menu_, flags, x, y, active_host_window->hwnd(), NULL);
- if (created_host) {
- delete active_host_window;
- active_host_window = NULL;
- }
- is_menu_visible_ = false;
-
- // Execute the chosen command
- if (selected_id != 0)
- delegate()->ExecuteCommand(selected_id);
-}
-
-void MenuWin::Cancel() {
- DCHECK(is_menu_visible_);
- EndMenu();
-}
-
-int MenuWin::ItemCount() {
- return GetMenuItemCount(menu_);
-}
-
-void MenuWin::AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- MenuItemType type) {
- AddMenuItemInternal(index, item_id, label, icon, NULL, type);
-}
-
-void MenuWin::AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- HMENU submenu,
- MenuItemType type) {
- DCHECK(type != SEPARATOR) << "Call AddSeparator instead!";
-
- if (!owner_draw_ && !icon.isNull())
- owner_draw_ = true;
-
- if (label.empty() && !delegate()) {
- // No label and no delegate; don't add an empty menu.
- // It appears under some circumstance we're getting an empty label
- // (l10n_util::GetStringUTF16(IDS_TASK_MANAGER) returns ""). This shouldn't
- // happen, but I'm working over the crash here.
- NOTREACHED();
- return;
- }
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE | MIIM_ID;
- if (submenu) {
- mii.fMask |= MIIM_SUBMENU;
- mii.hSubMenu = submenu;
- }
-
- // Set the type and ID.
- if (!owner_draw_) {
- mii.fType = MFT_STRING;
- mii.fMask |= MIIM_STRING;
- } else {
- mii.fType = MFT_OWNERDRAW;
- }
-
- if (type == RADIO)
- mii.fType |= MFT_RADIOCHECK;
-
- mii.wID = item_id;
-
- // Set the item data.
- MenuWin::ItemData* data = new ItemData;
- item_data_.push_back(data);
- data->submenu = submenu != NULL;
-
- string16 actual_label(label.empty() ? delegate()->GetLabel(item_id) : label);
-
- // Find out if there is a shortcut we need to append to the label.
- ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
- if (delegate() && delegate()->GetAcceleratorInfo(item_id, &accelerator)) {
- actual_label += L'\t';
- actual_label += accelerator.GetShortcutText();
- }
- labels_.push_back(actual_label);
-
- if (owner_draw_) {
- if (icon.width() != 0 && icon.height() != 0)
- data->icon = icon;
- else
- data->icon = delegate()->GetIcon(item_id);
- } else {
- mii.dwTypeData = const_cast<wchar_t*>(labels_.back().c_str());
- }
-
- InsertMenuItem(menu_, index, TRUE, &mii);
-}
-
-MenuWin::MenuWin(MenuWin* parent)
- : Menu(parent->delegate(), parent->anchor()),
- menu_(CreatePopupMenu()),
- owner_(parent->owner_),
- is_menu_visible_(false),
- owner_draw_(parent->owner_draw_) {
-}
-
-void MenuWin::SetMenuInfo() {
- const int num_items = GetMenuItemCount(menu_);
- int sep_count = 0;
- for (int i = 0; i < num_items; ++i) {
- MENUITEMINFO mii_info;
- mii_info.cbSize = sizeof(mii_info);
- // Get the menu's original type.
- mii_info.fMask = MIIM_FTYPE;
- GetMenuItemInfo(menu_, i, MF_BYPOSITION, &mii_info);
- // Set item states.
- if (!(mii_info.fType & MF_SEPARATOR)) {
- const int id = ChromeGetMenuItemID(menu_, i);
-
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_DATA | MIIM_STRING;
- // We also need MFT_STRING for owner drawn items in order to let Windows
- // handle the accelerators for us.
- mii.fType = MFT_STRING;
- if (owner_draw_)
- mii.fType |= MFT_OWNERDRAW;
- // If the menu originally has radiocheck type, we should follow it.
- if (mii_info.fType & MFT_RADIOCHECK)
- mii.fType |= MFT_RADIOCHECK;
- mii.fState = GetStateFlagsForItemID(id);
-
- // Validate the label. If there is a contextual label, use it, otherwise
- // default to the static label
- string16 label;
- if (!delegate()->GetContextualLabel(id, &label))
- label = labels_[i - sep_count];
-
- if (owner_draw_) {
- item_data_[i - sep_count]->label = label;
- mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
- }
- mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
- mii.cch = static_cast<UINT>(label.size());
- SetMenuItemInfo(menu_, i, true, &mii);
- } else {
- // Set data for owner drawn separators. Set dwItemData NULL to indicate
- // a separator.
- if (owner_draw_) {
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_FTYPE;
- mii.fType = MFT_SEPARATOR | MFT_OWNERDRAW;
- mii.dwItemData = NULL;
- SetMenuItemInfo(menu_, i, true, &mii);
- }
- ++sep_count;
- }
- }
-
- for (size_t i = 0; i < submenus_.size(); ++i)
- submenus_[i]->SetMenuInfo();
-}
-
-UINT MenuWin::GetStateFlagsForItemID(int item_id) const {
- // Use the delegate to get enabled and checked state.
- UINT flags =
- delegate()->IsCommandEnabled(item_id) ? MFS_ENABLED : MFS_DISABLED;
-
- if (delegate()->IsItemChecked(item_id))
- flags |= MFS_CHECKED;
-
- if (delegate()->IsItemDefault(item_id))
- flags |= MFS_DEFAULT;
-
- return flags;
-}
-
-DWORD MenuWin::GetTPMAlignFlags() const {
- // The manner in which we handle the menu alignment depends on whether or not
- // the menu is displayed within a mirrored view. If the UI is mirrored, the
- // alignment needs to be fliped so that instead of aligning the menu to the
- // right of the point, we align it to the left and vice versa.
- DWORD align_flags = TPM_TOPALIGN;
- switch (anchor()) {
- case TOPLEFT:
- if (delegate()->IsRightToLeftUILayout()) {
- align_flags |= TPM_RIGHTALIGN;
- } else {
- align_flags |= TPM_LEFTALIGN;
- }
- break;
-
- case TOPRIGHT:
- if (delegate()->IsRightToLeftUILayout()) {
- align_flags |= TPM_LEFTALIGN;
- } else {
- align_flags |= TPM_RIGHTALIGN;
- }
- break;
-
- default:
- NOTREACHED();
- return 0;
- }
- return align_flags;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_win.h b/chromium/ui/views/controls/menu/menu_win.h
deleted file mode 100644
index 284f26a4f85..00000000000
--- a/chromium/ui/views/controls/menu/menu_win.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
-#define UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
-
-#include <windows.h>
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/views/controls/menu/menu.h"
-
-namespace views {
-
-namespace {
-class MenuHostWindow;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// Menu class
-//
-// A wrapper around a Win32 HMENU handle that provides convenient APIs for
-// menu construction, display and subsequent command execution.
-//
-///////////////////////////////////////////////////////////////////////////////
-class MenuWin : public Menu {
- public:
- // Construct a Menu using the specified controller to determine command
- // state.
- // delegate A Menu::Delegate implementation that provides more
- // information about the Menu presentation.
- // anchor An alignment hint for the popup menu.
- // owner The window that the menu is being brought up relative
- // to. Not actually used for anything but must not be
- // NULL.
- MenuWin(Delegate* d, AnchorPoint anchor, HWND owner);
- // Alternatively, a Menu object can be constructed wrapping an existing
- // HMENU. This can be used to use the convenience methods to insert
- // menu items and manage label string ownership. However this kind of
- // Menu object cannot use the delegate.
- explicit MenuWin(HMENU hmenu);
- virtual ~MenuWin();
-
- // Overridden from Menu:
- virtual void AddMenuItemWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) OVERRIDE;
- virtual Menu* AddSubMenuWithIcon(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon) OVERRIDE;
- virtual void AddSeparator(int index) OVERRIDE;
- virtual void EnableMenuItemByID(int item_id, bool enabled) OVERRIDE;
- virtual void EnableMenuItemAt(int index, bool enabled) OVERRIDE;
- virtual void SetMenuLabel(int item_id, const string16& label) OVERRIDE;
- virtual bool SetIcon(const gfx::ImageSkia& icon, int item_id) OVERRIDE;
- virtual void RunMenuAt(int x, int y) OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual int ItemCount() OVERRIDE;
-
- virtual HMENU GetMenuHandle() const {
- return menu_;
- }
-
- // Gets the Win32 TPM alignment flags for the specified AnchorPoint.
- DWORD GetTPMAlignFlags() const;
-
- protected:
- virtual void AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- MenuItemType type) OVERRIDE;
-
- private:
- friend class MenuHostWindow;
-
- // The data of menu items needed to display.
- struct ItemData;
-
- void AddMenuItemInternal(int index,
- int item_id,
- const string16& label,
- const gfx::ImageSkia& icon,
- HMENU submenu,
- MenuItemType type);
-
- explicit MenuWin(MenuWin* parent);
-
- // Sets menu information before displaying, including sub-menus.
- void SetMenuInfo();
-
- // Get all the state flags for the |fState| field of MENUITEMINFO for the
- // item with the specified id. |delegate| is consulted if non-NULL about
- // the state of the item in preference to |controller_|.
- UINT GetStateFlagsForItemID(int item_id) const;
-
- // The Win32 Menu Handle we wrap
- HMENU menu_;
-
- // The window that would receive WM_COMMAND messages when the user selects
- // an item from the menu.
- HWND owner_;
-
- // This list is used to store the default labels for the menu items.
- // We may use contextual labels when RunMenu is called, so we must save
- // a copy of default ones here.
- std::vector<string16> labels_;
-
- // A flag to indicate whether this menu will be drawn by the Menu class.
- // If it's true, all the menu items will be owner drawn. Otherwise,
- // all the drawing will be done by Windows.
- bool owner_draw_;
-
- // This list is to store the string labels and icons to display. It's used
- // when owner_draw_ is true. We give MENUITEMINFO pointers to these
- // structures to specify what we'd like to draw. If owner_draw_ is false,
- // we only give MENUITEMINFO pointers to the labels_.
- // The label member of the ItemData structure comes from either labels_ or
- // the GetContextualLabel.
- std::vector<ItemData*> item_data_;
-
- // Our sub-menus, if any.
- std::vector<MenuWin*> submenus_;
-
- // Whether the menu is visible.
- bool is_menu_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(MenuWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_MENU_MENU_WIN_H_
diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc
index c260af9bcce..caddd70c4a5 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -18,10 +18,11 @@
#include "ui/base/models/menu_model.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/text_utils.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_win.h"
@@ -51,7 +52,7 @@ struct NativeMenuWin::ItemData {
// The Windows API requires that whoever creates the menus must own the
// strings used for labels, and keep them around for the lifetime of the
// created menu. So be it.
- string16 label;
+ base::string16 label;
// Someone needs to own submenus, it may as well be us.
scoped_ptr<Menu2> submenu;
@@ -171,17 +172,18 @@ class NativeMenuWin::MenuHostWindow {
void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
if (data) {
- gfx::Font font;
- measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
+ gfx::FontList font_list;
+ measure_item_struct->itemWidth =
+ gfx::GetStringWidth(data->label, font_list) +
kIconWidth + kItemLeftMargin + views::kItemLabelSpacing -
GetSystemMetrics(SM_CXMENUCHECK);
if (data->submenu.get())
measure_item_struct->itemWidth += kArrowWidth;
// If the label contains an accelerator, make room for tab.
- if (data->label.find(L'\t') != string16::npos)
- measure_item_struct->itemWidth += font.GetStringWidth(L" ");
+ if (data->label.find(L'\t') != base::string16::npos)
+ measure_item_struct->itemWidth += gfx::GetStringWidth(L" ", font_list);
measure_item_struct->itemHeight =
- font.GetHeight() + kItemBottomMargin + kItemTopMargin;
+ font_list.GetHeight() + kItemBottomMargin + kItemTopMargin;
} else {
// Measure separator size.
measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
@@ -225,19 +227,19 @@ class NativeMenuWin::MenuHostWindow {
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
if (!underline_mnemonics)
format |= DT_HIDEPREFIX;
- gfx::Font font;
- HGDIOBJ old_font =
- static_cast<HFONT>(SelectObject(dc, font.GetNativeFont()));
+ gfx::FontList font_list;
+ HGDIOBJ old_font = static_cast<HFONT>(
+ SelectObject(dc, font_list.GetPrimaryFont().GetNativeFont()));
// If an accelerator is specified (with a tab delimiting the rest of the
// label from the accelerator), we have to justify the fist part on the
// left and the accelerator on the right.
// TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
// window system UI font and will not hit here.
- string16 label = data->label;
- string16 accel;
- string16::size_type tab_pos = label.find(L'\t');
- if (tab_pos != string16::npos) {
+ base::string16 label = data->label;
+ base::string16 accel;
+ base::string16::size_type tab_pos = label.find(L'\t');
+ if (tab_pos != base::string16::npos) {
accel = label.substr(tab_pos);
label = label.substr(0, tab_pos);
}
@@ -626,7 +628,7 @@ void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
mii.fType = MFT_OWNERDRAW;
ItemData* item_data = new ItemData;
- item_data->label = string16();
+ item_data->label = base::string16();
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
if (type == ui::MenuModel::TYPE_SUBMENU) {
item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
@@ -678,7 +680,7 @@ void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
void NativeMenuWin::SetMenuItemLabel(int menu_index,
int model_index,
- const string16& label) {
+ const base::string16& label) {
if (IsSeparatorItemAt(menu_index))
return;
@@ -690,8 +692,8 @@ void NativeMenuWin::SetMenuItemLabel(int menu_index,
void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
- const string16& label) {
- string16 formatted = label;
+ const base::string16& label) {
+ base::string16 formatted = label;
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
// Strip out any tabs, otherwise they get interpreted as accelerators and can
// lead to weird behavior.
diff --git a/chromium/ui/views/controls/menu/native_menu_win.h b/chromium/ui/views/controls/menu/native_menu_win.h
index ca6f37bc5c8..ce3a072e416 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.h
+++ b/chromium/ui/views/controls/menu/native_menu_win.h
@@ -74,7 +74,7 @@ class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
// Sets the label of the item at the specified index.
void SetMenuItemLabel(int menu_index,
int model_index,
- const string16& label);
+ const base::string16& label);
// Updates the local data structure with the correctly formatted version of
// |label| at the specified model_index, and adds string data to |mii| if
@@ -82,7 +82,7 @@ class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
// of the peculiarities of the Windows menu API.
void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
int model_index,
- const string16& label);
+ const base::string16& label);
// Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
// supplied alignment and the UI text direction.
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index 9184ca9abfb..a6ef56a888e 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -7,12 +7,14 @@
#include <algorithm>
#include "base/compiler_specific.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_host.h"
+#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
@@ -41,7 +43,9 @@ SubmenuView::SubmenuView(MenuItemView* parent)
max_minor_text_width_(0),
minimum_preferred_width_(0),
resize_open_menu_(false),
- scroll_animator_(new ScrollAnimator(this)) {
+ scroll_animator_(new ScrollAnimator(this)),
+ roundoff_error_(0),
+ prefix_selector_(this) {
DCHECK(parent);
// We'll delete ourselves, otherwise the ScrollView would delete us on close.
set_owned_by_client();
@@ -117,7 +121,7 @@ void SubmenuView::Layout() {
}
}
-gfx::Size SubmenuView::GetPreferredSize() {
+gfx::Size SubmenuView::GetPreferredSize() const {
if (!has_children())
return gfx::Size();
@@ -128,11 +132,11 @@ gfx::Size SubmenuView::GetPreferredSize() {
int max_simple_width = 0;
int height = 0;
for (int i = 0; i < child_count(); ++i) {
- View* child = child_at(i);
+ const View* child = child_at(i);
if (!child->visible())
continue;
if (child->id() == MenuItemView::kMenuItemViewID) {
- MenuItemView* menu = static_cast<MenuItemView*>(child);
+ const MenuItemView* menu = static_cast<const MenuItemView*>(child);
const MenuItemView::MenuItemDimensions& dimensions =
menu->GetDimensions();
max_simple_width = std::max(
@@ -162,15 +166,20 @@ gfx::Size SubmenuView::GetPreferredSize() {
height + insets.height());
}
-void SubmenuView::GetAccessibleState(ui::AccessibleViewState* state) {
+void SubmenuView::GetAccessibleState(ui::AXViewState* state) {
// Inherit most of the state from the parent menu item, except the role.
if (GetMenuItem())
GetMenuItem()->GetAccessibleState(state);
- state->role = ui::AccessibilityTypes::ROLE_MENUPOPUP;
+ state->role = ui::AX_ROLE_MENU_LIST_POPUP;
+}
+
+ui::TextInputClient* SubmenuView::GetTextInputClient() {
+ return &prefix_selector_;
}
-void SubmenuView::PaintChildren(gfx::Canvas* canvas) {
- View::PaintChildren(canvas);
+void SubmenuView::PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) {
+ View::PaintChildren(canvas, cull_set);
if (drop_item_ && drop_position_ != MenuDelegate::DROP_ON)
PaintDropIndicator(canvas, drop_item_, drop_position_);
@@ -293,6 +302,35 @@ void SubmenuView::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
+int SubmenuView::GetRowCount() {
+ return GetMenuItemCount();
+}
+
+int SubmenuView::GetSelectedRow() {
+ int row = 0;
+ for (int i = 0; i < child_count(); ++i) {
+ if (child_at(i)->id() != MenuItemView::kMenuItemViewID)
+ continue;
+
+ if (static_cast<MenuItemView*>(child_at(i))->IsSelected())
+ return row;
+
+ row++;
+ }
+
+ return -1;
+}
+
+void SubmenuView::SetSelectedRow(int row) {
+ GetMenuItem()->GetMenuController()->SetSelection(
+ GetMenuItemAt(row),
+ MenuController::SELECTION_DEFAULT);
+}
+
+base::string16 SubmenuView::GetTextForRow(int row) {
+ return GetMenuItemAt(row)->title();
+}
+
bool SubmenuView::IsShowing() {
return host_ && host_->IsMenuHostVisible();
}
@@ -313,10 +351,10 @@ void SubmenuView::ShowAt(Widget* parent,
}
GetScrollViewContainer()->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUSTART,
+ ui::AX_EVENT_MENU_START,
true);
NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUPOPUPSTART,
+ ui::AX_EVENT_MENU_POPUP_START,
true);
}
@@ -327,9 +365,9 @@ void SubmenuView::Reposition(const gfx::Rect& bounds) {
void SubmenuView::Close() {
if (host_) {
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_MENUPOPUPEND, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_MENU_POPUP_END, true);
GetScrollViewContainer()->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_MENUEND, true);
+ ui::AX_EVENT_MENU_END, true);
host_->DestroyMenuHost();
host_ = NULL;
@@ -446,7 +484,9 @@ bool SubmenuView::OnScroll(float dx, float dy) {
const gfx::Rect& vis_bounds = GetVisibleBounds();
const gfx::Rect& full_bounds = bounds();
int x = vis_bounds.x();
- int y = vis_bounds.y() - static_cast<int>(dy);
+ float y_f = vis_bounds.y() - dy - roundoff_error_;
+ int y = gfx::ToRoundedInt(y_f);
+ roundoff_error_ = y - y_f;
// clamp y to [0, full_height - vis_height)
y = std::min(y, full_bounds.height() - vis_bounds.height() - 1);
y = std::max(y, 0);
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 19e0d46ffa2..1b7d36243d2 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -10,6 +10,8 @@
#include "base/compiler_specific.h"
#include "ui/views/animation/scroll_animator.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/prefix_delegate.h"
+#include "ui/views/controls/prefix_selector.h"
#include "ui/views/view.h"
namespace views {
@@ -26,14 +28,14 @@ class MenuScrollViewContainer;
// . Forwards the appropriate events to the MenuController. This allows the
// MenuController to update the selection as the user moves the mouse around.
// . Renders the drop indicator during a drop operation.
-// . Shows and hides the window (a NativeWidgetWin) when the menu is shown on
+// . Shows and hides the window (a NativeWidget) when the menu is shown on
// screen.
//
// SubmenuView is itself contained in a MenuScrollViewContainer.
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
-class VIEWS_EXPORT SubmenuView : public View,
+class VIEWS_EXPORT SubmenuView : public PrefixDelegate,
public ScrollDelegate {
public:
// The submenu's class name.
@@ -53,13 +55,15 @@ class VIEWS_EXPORT SubmenuView : public View,
// Positions and sizes the child views. This tiles the views vertically,
// giving each child the available width.
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Override from View.
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
// Painting.
- virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
+ virtual void PaintChildren(gfx::Canvas* canvas,
+ const views::CullSet& cull_view) OVERRIDE;
// Drag and drop methods. These are forwarded to the MenuController.
virtual bool GetDropFormats(
@@ -79,6 +83,12 @@ class VIEWS_EXPORT SubmenuView : public View,
// Scrolls on menu item boundaries.
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ // Overridden from PrefixDelegate.
+ virtual int GetRowCount() OVERRIDE;
+ virtual int GetSelectedRow() OVERRIDE;
+ virtual void SetSelectedRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
+
// Returns true if the menu is showing.
bool IsShowing();
@@ -191,7 +201,7 @@ class VIEWS_EXPORT SubmenuView : public View,
MenuScrollViewContainer* scroll_view_container_;
// See description above getter.
- int max_minor_text_width_;
+ mutable int max_minor_text_width_;
// Minimum width returned in GetPreferredSize().
int minimum_preferred_width_;
@@ -202,6 +212,14 @@ class VIEWS_EXPORT SubmenuView : public View,
// The submenu's scroll animator
scoped_ptr<ScrollAnimator> scroll_animator_;
+ // Difference between current position and cumulative deltas passed to
+ // OnScroll.
+ // TODO(tdresser): This should be removed when raw pixel scrolling for views
+ // is enabled. See crbug.com/329354.
+ float roundoff_error_;
+
+ PrefixSelector prefix_selector_;
+
DISALLOW_COPY_AND_ASSIGN(SubmenuView);
};
diff --git a/chromium/ui/views/controls/message_box_view.cc b/chromium/ui/views/controls/message_box_view.cc
index 3c2cde95292..671ca6194ec 100644
--- a/chromium/ui/views/controls/message_box_view.cc
+++ b/chromium/ui/views/controls/message_box_view.cc
@@ -8,7 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/views/controls/button/checkbox.h"
@@ -36,7 +36,7 @@ const int kDefaultMessageWidth = 320;
// 001C..001E ; B # Cc [3] <control-001C>..<control-001E>
// 0085 ; B # Cc <control-0085>
// 2029 ; B # Zp PARAGRAPH SEPARATOR
-bool IsParagraphSeparator(char16 c) {
+bool IsParagraphSeparator(base::char16 c) {
return ( c == 0x000A || c == 0x000D || c == 0x001C || c == 0x001D ||
c == 0x001E || c == 0x0085 || c == 0x2029);
}
@@ -44,8 +44,8 @@ bool IsParagraphSeparator(char16 c) {
// Splits |text| into a vector of paragraphs.
// Given an example "\nabc\ndef\n\n\nhij\n", the split results should be:
// "", "abc", "def", "", "", "hij", and "".
-void SplitStringIntoParagraphs(const string16& text,
- std::vector<string16>* paragraphs) {
+void SplitStringIntoParagraphs(const base::string16& text,
+ std::vector<base::string16>* paragraphs) {
paragraphs->clear();
size_t start = 0;
@@ -65,7 +65,7 @@ namespace views {
///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, public:
-MessageBoxView::InitParams::InitParams(const string16& message)
+MessageBoxView::InitParams::InitParams(const base::string16& message)
: options(NO_OPTIONS),
message(message),
message_width(kDefaultMessageWidth),
@@ -85,8 +85,8 @@ MessageBoxView::MessageBoxView(const InitParams& params)
MessageBoxView::~MessageBoxView() {}
-string16 MessageBoxView::GetInputText() {
- return prompt_field_ ? prompt_field_->text() : string16();
+base::string16 MessageBoxView::GetInputText() {
+ return prompt_field_ ? prompt_field_->text() : base::string16();
}
bool MessageBoxView::IsCheckBoxSelected() {
@@ -101,7 +101,7 @@ void MessageBoxView::SetIcon(const gfx::ImageSkia& icon) {
ResetLayoutManager();
}
-void MessageBoxView::SetCheckBoxLabel(const string16& label) {
+void MessageBoxView::SetCheckBoxLabel(const base::string16& label) {
if (!checkbox_)
checkbox_ = new Checkbox(label);
else
@@ -115,7 +115,8 @@ void MessageBoxView::SetCheckBoxSelected(bool selected) {
checkbox_->SetChecked(selected);
}
-void MessageBoxView::SetLink(const string16& text, LinkListener* listener) {
+void MessageBoxView::SetLink(const base::string16& text,
+ LinkListener* listener) {
if (text.empty()) {
DCHECK(!listener);
delete link_;
@@ -132,8 +133,8 @@ void MessageBoxView::SetLink(const string16& text, LinkListener* listener) {
ResetLayoutManager();
}
-void MessageBoxView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_ALERT;
+void MessageBoxView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_ALERT;
}
///////////////////////////////////////////////////////////////////////////////
@@ -145,7 +146,7 @@ void MessageBoxView::ViewHierarchyChanged(
if (prompt_field_)
prompt_field_->SelectAll(true);
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
}
}
@@ -162,7 +163,7 @@ bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
return false;
ui::ScopedClipboardWriter scw(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE);
- string16 text = message_labels_[0]->text();
+ base::string16 text = message_labels_[0]->text();
for (size_t i = 1; i < message_labels_.size(); ++i)
text += message_labels_[i]->text();
scw.WriteText(text);
@@ -174,23 +175,15 @@ bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
void MessageBoxView::Init(const InitParams& params) {
if (params.options & DETECT_DIRECTIONALITY) {
- std::vector<string16> texts;
+ std::vector<base::string16> texts;
SplitStringIntoParagraphs(params.message, &texts);
- // If the text originates from a web page, its alignment is based on its
- // first character with strong directionality.
- base::i18n::TextDirection message_direction =
- base::i18n::GetFirstStrongCharacterDirection(params.message);
- gfx::HorizontalAlignment alignment =
- (message_direction == base::i18n::RIGHT_TO_LEFT) ?
- gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
for (size_t i = 0; i < texts.size(); ++i) {
Label* message_label = new Label(texts[i]);
- // Don't set multi-line to true if the text is empty, else the label will
- // have a height of 0.
+ // Avoid empty multi-line labels, which have a height of 0.
message_label->SetMultiLine(!texts[i].empty());
message_label->SetAllowCharacterBreak(true);
- message_label->set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
- message_label->SetHorizontalAlignment(alignment);
+ message_label->set_directionality_mode(gfx::DIRECTIONALITY_FROM_TEXT);
+ message_label->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
message_labels_.push_back(message_label);
}
} else {
diff --git a/chromium/ui/views/controls/message_box_view.h b/chromium/ui/views/controls/message_box_view.h
index 1d92a379be4..cb708e6013d 100644
--- a/chromium/ui/views/controls/message_box_view.h
+++ b/chromium/ui/views/controls/message_box_view.h
@@ -42,12 +42,12 @@ class VIEWS_EXPORT MessageBoxView : public View {
};
struct VIEWS_EXPORT InitParams {
- explicit InitParams(const string16& message);
+ explicit InitParams(const base::string16& message);
~InitParams();
uint16 options;
- string16 message;
- string16 default_prompt;
+ base::string16 message;
+ base::string16 default_prompt;
int message_width;
int inter_row_vertical_spacing;
};
@@ -60,7 +60,7 @@ class VIEWS_EXPORT MessageBoxView : public View {
views::Textfield* text_box() { return prompt_field_; }
// Returns user entered data in the prompt field.
- string16 GetInputText();
+ base::string16 GetInputText();
// Returns true if a checkbox is selected, false otherwise. (And false if
// the message box has no checkbox.)
@@ -73,17 +73,17 @@ class VIEWS_EXPORT MessageBoxView : public View {
// Adds a checkbox with the specified label to the message box if this is the
// first call. Otherwise, it changes the label of the current checkbox. To
// start, the message box has no checkbox until this function is called.
- void SetCheckBoxLabel(const string16& label);
+ void SetCheckBoxLabel(const base::string16& label);
// Sets the state of the check-box.
void SetCheckBoxSelected(bool selected);
// Sets the text and the listener of the link. If |text| is empty, the link
// is removed.
- void SetLink(const string16& text, LinkListener* listener);
+ void SetLink(const base::string16& text, LinkListener* listener);
// View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
protected:
// View:
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index 28b1fe3aec7..c1b230c452e 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/native/native_view_host.h"
#include "base/logging.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/native/native_view_host_wrapper.h"
@@ -16,16 +17,6 @@ namespace views {
const char NativeViewHost::kViewClassName[] = "NativeViewHost";
const char kWidgetNativeViewHostKey[] = "WidgetNativeViewHost";
-#if defined(USE_AURA)
-// Views implementation draws the focus.
-// TODO(oshima): Eliminate this flag and consolidate
-// the focus border code.
-const bool NativeViewHost::kRenderNativeControlFocus = false;
-#else
-// static
-const bool NativeViewHost::kRenderNativeControlFocus = true;
-#endif
-
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, public:
@@ -74,7 +65,7 @@ void NativeViewHost::NativeViewDestroyed() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, View overrides:
-gfx::Size NativeViewHost::GetPreferredSize() {
+gfx::Size NativeViewHost::GetPreferredSize() const {
return preferred_size_;
}
@@ -182,7 +173,7 @@ const char* NativeViewHost::GetClassName() const {
void NativeViewHost::OnFocus() {
native_wrapper_->SetFocus();
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() {
@@ -196,6 +187,10 @@ gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() {
return View::GetNativeViewAccessible();
}
+gfx::NativeCursor NativeViewHost::GetCursor(const ui::MouseEvent& event) {
+ return native_wrapper_->GetCursor(event.x(), event.y());
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, private:
@@ -226,5 +221,4 @@ void NativeViewHost::ClearFocus() {
}
}
-
} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index bdc51510550..d5dd9b59fdb 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -28,9 +28,6 @@ class VIEWS_EXPORT NativeViewHost : public View {
// The NativeViewHost's class name.
static const char kViewClassName[];
- // Should views render the focus when on native controls?
- static const bool kRenderNativeControlFocus;
-
NativeViewHost();
virtual ~NativeViewHost();
@@ -80,12 +77,13 @@ class VIEWS_EXPORT NativeViewHost : public View {
void NativeViewDestroyed();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
protected:
virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE;
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index a71e230be47..49bf733bbe2 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/widget.h"
@@ -100,6 +101,12 @@ gfx::NativeViewAccessible NativeViewHostAura::GetNativeViewAccessible() {
return NULL;
}
+gfx::NativeCursor NativeViewHostAura::GetCursor(int x, int y) {
+ if (host_->native_view())
+ return host_->native_view()->GetCursor(gfx::Point(x, y));
+ return gfx::kNullCursor;
+}
+
void NativeViewHostAura::OnWindowDestroyed(aura::Window* window) {
DCHECK(window == host_->native_view());
host_->NativeViewDestroyed();
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.h b/chromium/ui/views/controls/native/native_view_host_aura.h
index eba4b99c9fd..8ef4e455f3d 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -34,6 +34,7 @@ class VIEWS_EXPORT NativeViewHostAura : public NativeViewHostWrapper,
virtual void HideWidget() OVERRIDE;
virtual void SetFocus() OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(int x, int y) OVERRIDE;
private:
// Overridden from aura::WindowObserver:
diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
index 7653cc905c3..f6dc561f2f0 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/aura/window.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
@@ -24,6 +25,10 @@ class NativeViewHostAuraTest : public ViewsTestBase {
return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get());
}
+ Widget* toplevel() {
+ return toplevel_.get();
+ }
+
NativeViewHost* host() {
return host_.get();
}
@@ -95,4 +100,18 @@ TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
}
+// Tests that the NativeViewHost reports the cursor set on its native view.
+TEST_F(NativeViewHostAuraTest, CursorForNativeView) {
+ CreateHost();
+
+ toplevel()->SetCursor(ui::kCursorHand);
+ child()->SetCursor(ui::kCursorWait);
+ ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
+ gfx::Point(0, 0), 0, 0);
+
+ EXPECT_EQ(ui::kCursorWait, host()->GetCursor(move_event).native_type());
+
+ DestroyHost();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_mac.cc b/chromium/ui/views/controls/native/native_view_host_mac.cc
new file mode 100644
index 00000000000..53bb00b7a0e
--- /dev/null
+++ b/chromium/ui/views/controls/native/native_view_host_mac.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/native/native_view_host_wrapper.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeViewHostWrapper, public:
+
+// static
+NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
+ NativeViewHost* host) {
+ return NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_unittest.cc b/chromium/ui/views/controls/native/native_view_host_unittest.cc
index f30980bca8b..247782437a5 100644
--- a/chromium/ui/views/controls/native/native_view_host_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_unittest.cc
@@ -4,19 +4,12 @@
#include "ui/views/controls/native/native_view_host.h"
-#if defined(OS_WIN) && !defined(USE_AURA)
-#include <windows.h>
-#endif
-
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#endif
-
namespace views {
class NativeViewHostTest : public ViewsTestBase {
@@ -93,15 +86,9 @@ class NativeViewHierarchyChangedTestView : public View {
DISALLOW_COPY_AND_ASSIGN(NativeViewHierarchyChangedTestView);
};
-#if defined(USE_AURA)
aura::Window* GetNativeParent(aura::Window* window) {
return window->parent();
}
-#elif defined(OS_WIN)
-HWND GetNativeParent(HWND window) {
- return GetParent(window);
-}
-#endif
class ViewHierarchyChangedTestHost : public NativeViewHost {
public:
diff --git a/chromium/ui/views/controls/native/native_view_host_win.cc b/chromium/ui/views/controls/native/native_view_host_win.cc
deleted file mode 100644
index e7b74c3c7a1..00000000000
--- a/chromium/ui/views/controls/native/native_view_host_win.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native/native_view_host_win.h"
-
-#include <oleacc.h>
-
-#include "base/logging.h"
-#include "ui/base/win/hidden_window.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/window_impl.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/native_widget.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWin, public:
-
-NativeViewHostWin::NativeViewHostWin(NativeViewHost* host)
- : host_(host),
- installed_clip_(false) {
-}
-
-NativeViewHostWin::~NativeViewHostWin() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWin, NativeViewHostWrapper implementation:
-void NativeViewHostWin::NativeViewWillAttach() {
- // First hide the new window. We don't want anything to draw (like sub-hwnd
- // borders), when NativeViewHost changes the parent.
- ShowWindow(host_->native_view(), SW_HIDE);
-}
-
-void NativeViewHostWin::NativeViewDetaching(bool destroyed) {
- if (!destroyed) {
- if (installed_clip_)
- UninstallClip();
- Widget::ReparentNativeView(host_->native_view(), ui::GetHiddenWindow());
- }
- installed_clip_ = false;
-}
-
-void NativeViewHostWin::AddedToWidget() {
- if (!IsWindow(host_->native_view()))
- return;
- HWND parent_hwnd = GetParent(host_->native_view());
- HWND widget_hwnd = host_->GetWidget()->GetNativeView();
- if (parent_hwnd != widget_hwnd)
- SetParent(host_->native_view(), widget_hwnd);
- if (host_->IsDrawn())
- ShowWindow(host_->native_view(), SW_SHOW);
- else
- ShowWindow(host_->native_view(), SW_HIDE);
- host_->Layout();
-}
-
-void NativeViewHostWin::RemovedFromWidget() {
- if (!IsWindow(host_->native_view()))
- return;
- ShowWindow(host_->native_view(), SW_HIDE);
- SetParent(host_->native_view(), NULL);
-}
-
-void NativeViewHostWin::InstallClip(int x, int y, int w, int h) {
- HRGN clip_region = CreateRectRgn(x, y, x + w, y + h);
- // NOTE: SetWindowRgn owns the region (as well as the deleting the
- // current region), as such we don't delete the old region.
- SetWindowRgn(host_->native_view(), clip_region, TRUE);
- installed_clip_ = true;
-}
-
-bool NativeViewHostWin::HasInstalledClip() {
- return installed_clip_;
-}
-
-void NativeViewHostWin::UninstallClip() {
- SetWindowRgn(host_->native_view(), 0, TRUE);
- installed_clip_ = false;
-}
-
-void NativeViewHostWin::ShowWidget(int x, int y, int w, int h) {
- UINT swp_flags = SWP_DEFERERASE |
- SWP_NOACTIVATE |
- SWP_NOCOPYBITS |
- SWP_NOOWNERZORDER |
- SWP_NOZORDER;
- gfx::Rect bounds = gfx::win::DIPToScreenRect(gfx::Rect(x,y,w,h));
-
- // Only send the SHOWWINDOW flag if we're invisible, to avoid flashing.
- if (!IsWindowVisible(host_->native_view()))
- swp_flags = (swp_flags | SWP_SHOWWINDOW) & ~SWP_NOREDRAW;
-
- if (host_->fast_resize()) {
- // In a fast resize, we move the window and clip it with SetWindowRgn.
- RECT win_rect;
- GetWindowRect(host_->native_view(), &win_rect);
- gfx::Rect rect(win_rect);
- SetWindowPos(host_->native_view(), 0, bounds.x(), bounds.y(),
- rect.width(), rect.height(),
- swp_flags);
-
- InstallClip(0, 0, bounds.width(), bounds.height());
- } else {
- SetWindowPos(host_->native_view(), 0, bounds.x(), bounds.y(),
- bounds.width(), bounds.height(), swp_flags);
- }
-}
-
-void NativeViewHostWin::HideWidget() {
- if (!IsWindowVisible(host_->native_view()))
- return; // Currently not visible, nothing to do.
-
- // The window is currently visible, but its clipped by another view. Hide
- // it.
- SetWindowPos(host_->native_view(), 0, 0, 0, 0, 0,
- SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
- SWP_NOREDRAW | SWP_NOOWNERZORDER);
-}
-
-void NativeViewHostWin::SetFocus() {
- ::SetFocus(host_->native_view());
-}
-
-gfx::NativeViewAccessible NativeViewHostWin::GetNativeViewAccessible() {
- HWND hwnd = host_->native_view();
- if (!IsWindow(hwnd))
- return NULL;
-
- IAccessible* accessible = NULL;
- HRESULT success = ::AccessibleObjectFromWindow(
- hwnd, OBJID_CLIENT, IID_IAccessible,
- reinterpret_cast<void**>(&accessible));
-
- if (success == S_OK) {
- return accessible;
- } else {
- return NULL;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeViewHostWrapper, public:
-
-// static
-NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
- NativeViewHost* host) {
- return new NativeViewHostWin(host);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host_win.h b/chromium/ui/views/controls/native/native_view_host_win.h
deleted file mode 100644
index ea94b351ea3..00000000000
--- a/chromium/ui/views/controls/native/native_view_host_win.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
-#define UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
-
-#include "base/basictypes.h"
-#include "ui/views/controls/native/native_view_host_wrapper.h"
-
-namespace views {
-
-class NativeViewHost;
-
-// A Windows implementation of NativeViewHostWrapper
-class NativeViewHostWin : public NativeViewHostWrapper {
- public:
- explicit NativeViewHostWin(NativeViewHost* host);
- virtual ~NativeViewHostWin();
-
- // Overridden from NativeViewHostWrapper:
- virtual void NativeViewWillAttach();
- virtual void NativeViewDetaching(bool destroyed);
- virtual void AddedToWidget();
- virtual void RemovedFromWidget();
- virtual void InstallClip(int x, int y, int w, int h);
- virtual bool HasInstalledClip();
- virtual void UninstallClip();
- virtual void ShowWidget(int x, int y, int w, int h);
- virtual void HideWidget();
- virtual void SetFocus();
- virtual gfx::NativeViewAccessible GetNativeViewAccessible();
-
- private:
- // Our associated NativeViewHost.
- NativeViewHost* host_;
-
- // Have we installed a region on the gfx::NativeView used to clip to only the
- // visible portion of the gfx::NativeView ?
- bool installed_clip_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeViewHostWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_NATIVE_VIEW_HOST_WIN_H_
diff --git a/chromium/ui/views/controls/native/native_view_host_wrapper.h b/chromium/ui/views/controls/native/native_view_host_wrapper.h
index 3b3cb37fbdc..306aa0148bb 100644
--- a/chromium/ui/views/controls/native/native_view_host_wrapper.h
+++ b/chromium/ui/views/controls/native/native_view_host_wrapper.h
@@ -62,6 +62,10 @@ class VIEWS_EXPORT NativeViewHostWrapper {
// view.
virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
+ // Returns the native cursor corresponding to the point (x, y)
+ // in the native view.
+ virtual gfx::NativeCursor GetCursor(int x, int y) = 0;
+
// Creates a platform-specific instance of an object implementing this
// interface.
static NativeViewHostWrapper* CreateWrapper(NativeViewHost* host);
diff --git a/chromium/ui/views/controls/native_control.cc b/chromium/ui/views/controls/native_control.cc
deleted file mode 100644
index faebbc81f90..00000000000
--- a/chromium/ui/views/controls/native_control.cc
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native_control.h"
-
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlcrack.h>
-#include <atlframe.h>
-#include <atlmisc.h>
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/base/view_prop.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/widget.h"
-
-using ui::ViewProp;
-
-namespace views {
-
-// Maps to the NativeControl.
-static const char* const kNativeControlKey = "__NATIVE_CONTROL__";
-
-class NativeControlContainer : public CWindowImpl<NativeControlContainer,
- CWindow,
- CWinTraits<WS_CHILD | WS_CLIPSIBLINGS |
- WS_CLIPCHILDREN>> {
- public:
- explicit NativeControlContainer(NativeControl* parent)
- : parent_(parent),
- control_(NULL),
- original_handler_(NULL) {
- }
-
- void Init() {
- Create(parent_->GetWidget()->GetNativeView());
- ::ShowWindow(m_hWnd, SW_SHOW);
- }
-
- virtual ~NativeControlContainer() {
- }
-
- // NOTE: If you add a new message, be sure and verify parent_ is valid before
- // calling into parent_.
- DECLARE_FRAME_WND_CLASS(L"ChromeViewsNativeControlContainer", NULL);
- BEGIN_MSG_MAP(NativeControlContainer);
- MSG_WM_CREATE(OnCreate);
- MSG_WM_ERASEBKGND(OnEraseBkgnd);
- MSG_WM_PAINT(OnPaint);
- MSG_WM_SIZE(OnSize);
- MSG_WM_NOTIFY(OnNotify);
- MSG_WM_COMMAND(OnCommand);
- MSG_WM_DESTROY(OnDestroy);
- MSG_WM_CONTEXTMENU(OnContextMenu);
- MSG_WM_CTLCOLORBTN(OnCtlColorBtn);
- MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic)
- END_MSG_MAP();
-
- HWND GetControl() {
- return control_;
- }
-
- // Called when the parent is getting deleted. This control stays around until
- // it gets the OnFinalMessage call.
- void ResetParent() {
- parent_ = NULL;
- }
-
- void OnFinalMessage(HWND hwnd) {
- if (parent_)
- parent_->NativeControlDestroyed();
- delete this;
- }
-
- private:
- friend class NativeControl;
-
- LRESULT OnCreate(LPCREATESTRUCT create_struct) {
- control_ = parent_->CreateNativeControl(m_hWnd);
-
- // We subclass the control hwnd so we get the WM_KEYDOWN messages.
- original_handler_ = gfx::SetWindowProc(
- control_, &NativeControl::NativeControlWndProc);
- prop_.reset(new ViewProp(control_, kNativeControlKey , parent_));
-
- ::ShowWindow(control_, SW_SHOW);
- return 1;
- }
-
- LRESULT OnEraseBkgnd(HDC dc) {
- return 1;
- }
-
- void OnPaint(HDC ignore) {
- PAINTSTRUCT ps;
- HDC dc = ::BeginPaint(*this, &ps);
- ::EndPaint(*this, &ps);
- }
-
- void OnSize(int type, const CSize& sz) {
- ::MoveWindow(control_, 0, 0, sz.cx, sz.cy, TRUE);
- }
-
- LRESULT OnCommand(UINT code, int id, HWND source) {
- return parent_ ? parent_->OnCommand(code, id, source) : 0;
- }
-
- LRESULT OnNotify(int w_param, LPNMHDR l_param) {
- if (parent_)
- return parent_->OnNotify(w_param, l_param);
- else
- return 0;
- }
-
- void OnDestroy() {
- if (parent_)
- parent_->OnDestroy();
- }
-
- void OnContextMenu(HWND window, const POINT& location) {
- if (parent_)
- parent_->OnContextMenu(location);
- }
-
- // We need to find an ancestor with a non-null background, and
- // ask it for a (solid color) brush that approximates
- // the background. The caller will use this when drawing
- // the native control as a background color, particularly
- // for radiobuttons and XP style pushbuttons.
- LRESULT OnCtlColor(UINT msg, HDC dc, HWND control) {
- const View *ancestor = parent_;
- while (ancestor) {
- const Background *background = ancestor->background();
- if (background) {
- HBRUSH brush = background->GetNativeControlBrush();
- if (brush)
- return reinterpret_cast<LRESULT>(brush);
- }
- ancestor = ancestor->parent();
- }
-
- // COLOR_BTNFACE is the default for dialog box backgrounds.
- return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
- }
-
- LRESULT OnCtlColorBtn(HDC dc, HWND control) {
- return OnCtlColor(WM_CTLCOLORBTN, dc, control);
- }
-
- LRESULT OnCtlColorStatic(HDC dc, HWND control) {
- return OnCtlColor(WM_CTLCOLORSTATIC, dc, control);
- }
-
- NativeControl* parent_;
- HWND control_;
-
- // Message handler that was set before we reset it.
- WNDPROC original_handler_;
-
- scoped_ptr<ViewProp> prop_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControlContainer);
-};
-
-NativeControl::NativeControl() : hwnd_view_(NULL),
- container_(NULL),
- fixed_width_(-1),
- horizontal_alignment_(CENTER),
- fixed_height_(-1),
- vertical_alignment_(CENTER) {
- SetFocusable(true);
-}
-
-NativeControl::~NativeControl() {
- if (container_) {
- container_->ResetParent();
- ::DestroyWindow(*container_);
- }
-}
-
-void NativeControl::ValidateNativeControl() {
- if (hwnd_view_ == NULL) {
- hwnd_view_ = new NativeViewHost;
- AddChildView(hwnd_view_);
- }
-
- if (!container_ && visible()) {
- container_ = new NativeControlContainer(this);
- container_->Init();
- hwnd_view_->Attach(*container_);
- if (!enabled())
- EnableWindow(GetNativeControlHWND(), enabled());
-
- // This message ensures that the focus border is shown.
- ::SendMessage(container_->GetControl(),
- WM_CHANGEUISTATE,
- MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
- 0);
- }
-}
-
-void NativeControl::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && details.parent != this && !container_ && GetWidget()) {
- ValidateNativeControl();
- Layout();
- }
-}
-
-void NativeControl::Layout() {
- if (!container_ && GetWidget())
- ValidateNativeControl();
-
- if (hwnd_view_) {
- gfx::Rect lb = GetLocalBounds();
-
- int x = lb.x();
- int y = lb.y();
- int width = lb.width();
- int height = lb.height();
- if (fixed_width_ > 0) {
- width = std::min(fixed_width_, width);
- switch (horizontal_alignment_) {
- case LEADING:
- // Nothing to do.
- break;
- case CENTER:
- x += (lb.width() - width) / 2;
- break;
- case TRAILING:
- x = x + lb.width() - width;
- break;
- default:
- NOTREACHED();
- }
- }
-
- if (fixed_height_ > 0) {
- height = std::min(fixed_height_, height);
- switch (vertical_alignment_) {
- case LEADING:
- // Nothing to do.
- break;
- case CENTER:
- y += (lb.height() - height) / 2;
- break;
- case TRAILING:
- y = y + lb.height() - height;
- break;
- default:
- NOTREACHED();
- }
- }
-
- hwnd_view_->SetBounds(x, y, width, height);
- }
-}
-
-void NativeControl::OnContextMenu(const POINT& location) {
- if (!context_menu_controller())
- return;
-
- if (location.x == -1 && location.y == -1) {
- ShowContextMenu(GetKeyboardContextMenuLocation(),
- ui::MENU_SOURCE_KEYBOARD);
- } else {
- ShowContextMenu(gfx::Point(location), ui::MENU_SOURCE_MOUSE);
- }
-}
-
-void NativeControl::OnFocus() {
- if (container_) {
- DCHECK(container_->GetControl());
- ::SetFocus(container_->GetControl());
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
- }
-}
-
-HWND NativeControl::GetNativeControlHWND() {
- if (container_)
- return container_->GetControl();
- else
- return NULL;
-}
-
-void NativeControl::NativeControlDestroyed() {
- if (hwnd_view_)
- hwnd_view_->Detach();
- container_ = NULL;
-}
-
-void NativeControl::SetVisible(bool is_visible) {
- if (is_visible != visible()) {
- View::SetVisible(is_visible);
- if (!is_visible && container_)
- ::DestroyWindow(*container_);
- else if (is_visible && !container_)
- ValidateNativeControl();
- }
-}
-
-void NativeControl::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (GetNativeControlHWND())
- EnableWindow(GetNativeControlHWND(), enabled());
-}
-
-void NativeControl::OnPaint(gfx::Canvas* canvas) {
-}
-
-void NativeControl::VisibilityChanged(View* starting_from, bool is_visible) {
- SetVisible(is_visible);
-}
-
-void NativeControl::SetFixedWidth(int width, Alignment alignment) {
- DCHECK_GT(width, 0);
- fixed_width_ = width;
- horizontal_alignment_ = alignment;
-}
-
-void NativeControl::SetFixedHeight(int height, Alignment alignment) {
- DCHECK_GT(height, 0);
- fixed_height_ = height;
- vertical_alignment_ = alignment;
-}
-
-DWORD NativeControl::GetAdditionalExStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedStyles();
-
- return ex_style;
-}
-
-DWORD NativeControl::GetAdditionalRTLStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedTooltipStyles();
-
- return ex_style;
-}
-
-// static
-LRESULT CALLBACK NativeControl::NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- NativeControl* native_control = static_cast<NativeControl*>(
- ViewProp::GetValue(window, kNativeControlKey));
- DCHECK(native_control);
- WNDPROC original_handler = native_control->container_->original_handler_;
- DCHECK(original_handler);
-
- if (message == WM_KEYDOWN &&
- native_control->OnKeyDown(ui::KeyboardCodeForWindowsKeyCode(w_param))) {
- return 0;
- } else if (message == WM_SETFOCUS) {
- // Let the focus manager know that the focus changed.
- FocusManager* focus_manager = native_control->GetFocusManager();
- if (focus_manager) {
- focus_manager->SetFocusedView(native_control);
- } else {
- NOTREACHED();
- }
- } else if (message == WM_DESTROY) {
- gfx::SetWindowProc(window, reinterpret_cast<WNDPROC>(original_handler));
- native_control->container_->prop_.reset();
- }
-
- return CallWindowProc(reinterpret_cast<WNDPROC>(original_handler), window,
- message, w_param, l_param);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native_control.h b/chromium/ui/views/controls/native_control.h
deleted file mode 100644
index 80aa5887cf1..00000000000
--- a/chromium/ui/views/controls/native_control.h
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
-#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
-
-#include <windows.h>
-
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/views/view.h"
-
-namespace views {
-
-class NativeViewHost;
-class NativeControlContainer;
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// NativeControl is an abstract view that is used to implement views wrapping
-// native controls. Subclasses can simply implement CreateNativeControl() to
-// wrap a new kind of control
-//
-////////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT NativeControl : public View {
- public:
- enum Alignment {
- LEADING = 0,
- CENTER,
- TRAILING };
-
- NativeControl();
- virtual ~NativeControl();
-
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual void Layout();
-
- // Overridden to properly set the native control state.
- virtual void SetVisible(bool f);
- virtual void OnEnabledChanged();
-
- // Overridden to do nothing.
- virtual void OnPaint(gfx::Canvas* canvas);
-
- protected:
- friend class NativeControlContainer;
-
- // Overridden by sub-classes to create the windows control which is wrapped
- virtual HWND CreateNativeControl(HWND parent_container) = 0;
-
- // Invoked when the native control sends a WM_NOTIFY message to its parent
- virtual LRESULT OnNotify(int w_param, LPNMHDR l_param) = 0;
-
- // Invoked when the native control sends a WM_COMMAND message to its parent
- virtual LRESULT OnCommand(UINT code, int id, HWND source) { return 0; }
-
- // Invoked when the appropriate gesture for a context menu is issued.
- virtual void OnContextMenu(const POINT& location);
-
- // Overridden so to set the native focus to the native control.
- virtual void OnFocus();
-
- // Invoked when the native control sends a WM_DESTORY message to its parent.
- virtual void OnDestroy() { }
-
- // Return the native control
- virtual HWND GetNativeControlHWND();
-
- // Invoked by the native windows control when it has been destroyed. This is
- // invoked AFTER WM_DESTORY has been sent. Any window commands send to the
- // HWND will most likely fail.
- void NativeControlDestroyed();
-
- // Overridden so that the control properly reflects parent's visibility.
- virtual void VisibilityChanged(View* starting_from, bool is_visible);
-
- // Controls that have fixed sizes should call these methods to specify the
- // actual size and how they should be aligned within their parent.
- void SetFixedWidth(int width, Alignment alignment);
- void SetFixedHeight(int height, Alignment alignment);
-
- // Invoked when a key is pressed on the control.
- // Should return true if the key message was processed, false otherwise.
- virtual bool OnKeyDown(ui::KeyboardCode virtual_key_code) { return false; }
-
- // Returns additional extended style flags. When subclasses call
- // CreateWindowEx in order to create the underlying control, they must OR the
- // ExStyle parameter with the value returned by this function.
- //
- // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
- // to the HWND for views with right-to-left UI layout.
- DWORD GetAdditionalExStyle() const;
-
- // TODO(xji): we use the following temporary function as we transition the
- // various native controls to use the right set of RTL flags. This function
- // will go away (and be replaced by GetAdditionalExStyle()) once all the
- // controls are properly transitioned.
- DWORD GetAdditionalRTLStyle() const;
-
- // This variable is protected to provide subclassers direct access. However
- // subclassers should always check for NULL since this variable is only
- // initialized in ValidateNativeControl().
- NativeViewHost* hwnd_view_;
-
- // Fixed size information. -1 for a size means no fixed size.
- int fixed_width_;
- Alignment horizontal_alignment_;
- int fixed_height_;
- Alignment vertical_alignment_;
-
- private:
-
- void ValidateNativeControl();
-
- static LRESULT CALLBACK NativeControlWndProc(HWND window, UINT message,
- WPARAM w_param, LPARAM l_param);
-
- NativeControlContainer* container_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControl);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
diff --git a/chromium/ui/views/controls/native_control_win.cc b/chromium/ui/views/controls/native_control_win.cc
deleted file mode 100644
index c50411d13f5..00000000000
--- a/chromium/ui/views/controls/native_control_win.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/native_control_win.h"
-
-#include <windowsx.h>
-
-#include "base/logging.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/base/view_prop.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/widget.h"
-
-using ui::ViewProp;
-
-const char kNativeControlWinKey[] = "__NATIVE_CONTROL_WIN__";
-
-namespace views {
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, public:
-
-NativeControlWin::NativeControlWin() : original_wndproc_(NULL) {
-}
-
-NativeControlWin::~NativeControlWin() {
- HWND hwnd = native_view();
- if (hwnd) {
- // Destroy the hwnd if it still exists. Otherwise we won't have shut things
- // down correctly, leading to leaking and crashing if another message
- // comes in for the hwnd.
- Detach();
- DestroyWindow(hwnd);
- }
-}
-
-bool NativeControlWin::ProcessMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- switch (message) {
- case WM_CONTEXTMENU:
- ShowContextMenu(gfx::Point(GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)));
- *result = 0;
- return true;
- case WM_CTLCOLORBTN:
- case WM_CTLCOLORSTATIC:
- *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
- native_view());
- return true;
- }
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, View overrides:
-
-void NativeControlWin::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (native_view())
- EnableWindow(native_view(), enabled());
-}
-
-void NativeControlWin::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- // Call the base class to hide the view if we're being removed.
- NativeViewHost::ViewHierarchyChanged(details);
-
- // Create the HWND when we're added to a valid Widget. Many controls need a
- // parent HWND to function properly.
- if (details.is_add && GetWidget() && !native_view())
- CreateNativeControl();
-}
-
-void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
- // We might get called due to visibility changes at any point in the
- // hierarchy, lets check whether we are really visible or not.
- bool is_drawn = IsDrawn();
- if (!is_drawn && native_view()) {
- // We destroy the child control HWND when we become invisible because of the
- // performance cost of maintaining many HWNDs.
- HWND hwnd = native_view();
- Detach();
- DestroyWindow(hwnd);
- } else if (is_drawn && !native_view()) {
- if (GetWidget())
- CreateNativeControl();
- }
- if (is_drawn) {
- // The view becomes visible after native control is created.
- // Layout now.
- Layout();
- }
-}
-
-void NativeControlWin::OnFocus() {
- DCHECK(native_view());
- SetFocus(native_view());
-
- // Since we are being wrapped by a view, accessibility should receive
- // the super class as the focused view.
- View* parent_view = parent();
-
- // Due to some controls not behaving as expected without having
- // a native win32 control, we don't always send a native (MSAA)
- // focus notification.
- bool send_native_event =
- strcmp(parent_view->GetClassName(), Combobox::kViewClassName) &&
- parent_view->HasFocus();
-
- // Send the accessibility focus notification.
- parent_view->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, send_native_event);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, protected:
-
-void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
- if (!context_menu_controller())
- return;
-
- if (location.x() == -1 && location.y() == -1) {
- View::ShowContextMenu(GetKeyboardContextMenuLocation(),
- ui::MENU_SOURCE_KEYBOARD);
- } else {
- View::ShowContextMenu(location, ui::MENU_SOURCE_MOUSE);
- }
-}
-
-void NativeControlWin::NativeControlCreated(HWND native_control) {
- // Associate this object with the control's HWND so that NativeWidgetWin can
- // find this object when it receives messages from it.
- props_.push_back(new ViewProp(native_control, kNativeControlWinKey, this));
- props_.push_back(ChildWindowMessageProcessor::Register(native_control, this));
-
- // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages.
- original_wndproc_ = gfx::SetWindowProc(
- native_control, &NativeControlWin::NativeControlWndProc);
-
- Attach(native_control);
- // native_view() is now valid.
-
- // Update the newly created HWND with any resident enabled state.
- EnableWindow(native_view(), enabled());
-
- // This message ensures that the focus border is shown.
- SendMessage(native_view(), WM_CHANGEUISTATE,
- MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
-}
-
-DWORD NativeControlWin::GetAdditionalExStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedStyles();
-
- return ex_style;
-}
-
-DWORD NativeControlWin::GetAdditionalRTLStyle() const {
- // If the UI for the view is mirrored, we should make sure we add the
- // extended window style for a right-to-left layout so the subclass creates
- // a mirrored HWND for the underlying control.
- DWORD ex_style = 0;
- if (base::i18n::IsRTL())
- ex_style |= l10n_util::GetExtendedTooltipStyles();
-
- return ex_style;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeControlWin, private:
-
-LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) {
- View *ancestor = this;
- while (ancestor) {
- const Background* background = ancestor->background();
- if (background) {
- HBRUSH brush = background->GetNativeControlBrush();
- if (brush)
- return reinterpret_cast<LRESULT>(brush);
- }
- ancestor = ancestor->parent();
- }
-
- // COLOR_BTNFACE is the default for dialog box backgrounds.
- return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
-}
-
-// static
-LRESULT NativeControlWin::NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- NativeControlWin* native_control = reinterpret_cast<NativeControlWin*>(
- ViewProp::GetValue(window, kNativeControlWinKey));
- DCHECK(native_control);
-
- if (message == WM_KEYDOWN &&
- native_control->OnKeyDown(static_cast<int>(w_param))) {
- return 0;
- } else if (message == WM_SETFOCUS) {
- // Let the focus manager know that the focus changed.
- FocusManager* focus_manager = native_control->GetFocusManager();
- if (focus_manager) {
- focus_manager->SetFocusedView(native_control->focus_view());
- } else {
- NOTREACHED();
- }
- } else if (message == WM_DESTROY) {
- native_control->props_.clear();
- gfx::SetWindowProc(window, native_control->original_wndproc_);
- }
-
- return CallWindowProc(native_control->original_wndproc_, window, message,
- w_param, l_param);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/native_control_win.h b/chromium/ui/views/controls/native_control_win.h
deleted file mode 100644
index 3ee5681f1dc..00000000000
--- a/chromium/ui/views/controls/native_control_win.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
-#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/widget/child_window_message_processor.h"
-
-namespace ui {
-class ViewProp;
-}
-
-namespace views {
-
-// A View that hosts a native Windows control.
-class NativeControlWin : public ChildWindowMessageProcessor,
- public NativeViewHost {
- public:
- NativeControlWin();
- virtual ~NativeControlWin();
-
- // Called by our subclassed window procedure when a WM_KEYDOWN message is
- // received by the HWND created by an object derived from NativeControlWin.
- // Returns true if the key was processed, false otherwise.
- virtual bool OnKeyDown(int vkey) { return false; }
-
- // Overridden from ChildWindowMessageProcessor:
- virtual bool ProcessMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
-
- // Overridden from View:
- virtual void OnEnabledChanged() OVERRIDE;
-
- protected:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
-
- // Called by the containing NativeWidgetWin when a WM_CONTEXTMENU message is
- // received from the HWND created by an object derived from NativeControlWin.
- virtual void ShowContextMenu(const gfx::Point& location);
-
- // Called when the NativeControlWin is attached to a View hierarchy with a
- // valid Widget. The NativeControlWin should use this opportunity to create
- // its associated HWND.
- virtual void CreateNativeControl() = 0;
-
- // MUST be called by the subclass implementation of |CreateNativeControl|
- // immediately after creating the control HWND, otherwise it won't be attached
- // to the NativeViewHost and will be effectively orphaned.
- virtual void NativeControlCreated(HWND native_control);
-
- // Returns additional extended style flags. When subclasses call
- // CreateWindowEx in order to create the underlying control, they must OR the
- // ExStyle parameter with the value returned by this function.
- //
- // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
- // to the HWND for views with right-to-left UI layout.
- DWORD GetAdditionalExStyle() const;
-
- // TODO(xji): we use the following temporary function as we transition the
- // various native controls to use the right set of RTL flags. This function
- // will go away (and be replaced by GetAdditionalExStyle()) once all the
- // controls are properly transitioned.
- DWORD GetAdditionalRTLStyle() const;
-
- private:
- typedef ScopedVector<ui::ViewProp> ViewProps;
-
- // Called by the containing NativeWidgetWin when a message of type
- // WM_CTLCOLORBTN or WM_CTLCOLORSTATIC is sent from the HWND created by an
- // object derived from NativeControlWin.
- LRESULT GetControlColor(UINT message, HDC dc, HWND sender);
-
- // Our subclass window procedure for the attached control.
- static LRESULT CALLBACK NativeControlWndProc(HWND window,
- UINT message,
- WPARAM w_param,
- LPARAM l_param);
-
- // The window procedure before we subclassed.
- WNDPROC original_wndproc_;
-
- ViewProps props_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeControlWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
diff --git a/chromium/ui/views/controls/prefix_delegate.h b/chromium/ui/views/controls/prefix_delegate.h
index 41d30d43cc8..07d85989f0e 100644
--- a/chromium/ui/views/controls/prefix_delegate.h
+++ b/chromium/ui/views/controls/prefix_delegate.h
@@ -23,7 +23,7 @@ class VIEWS_EXPORT PrefixDelegate : public View {
virtual void SetSelectedRow(int row) = 0;
// Returns the item at the specified row.
- virtual string16 GetTextForRow(int row) = 0;
+ virtual base::string16 GetTextForRow(int row) = 0;
protected:
virtual ~PrefixDelegate() {}
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index d66a0346c84..c901edd2c11 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -47,12 +47,12 @@ void PrefixSelector::ConfirmCompositionText() {
void PrefixSelector::ClearCompositionText() {
}
-void PrefixSelector::InsertText(const string16& text) {
+void PrefixSelector::InsertText(const base::string16& text) {
OnTextInput(text);
}
-void PrefixSelector::InsertChar(char16 ch, int flags) {
- OnTextInput(string16(1, ch));
+void PrefixSelector::InsertChar(base::char16 ch, int flags) {
+ OnTextInput(base::string16(1, ch));
}
gfx::NativeWindow PrefixSelector::GetAttachedWindow() const {
@@ -115,7 +115,7 @@ bool PrefixSelector::DeleteRange(const gfx::Range& range) {
}
bool PrefixSelector::GetTextFromRange(const gfx::Range& range,
- string16* text) const {
+ base::string16* text) const {
return false;
}
@@ -143,7 +143,14 @@ void PrefixSelector::OnCandidateWindowUpdated() {
void PrefixSelector::OnCandidateWindowHidden() {
}
-void PrefixSelector::OnTextInput(const string16& text) {
+bool PrefixSelector::IsEditingCommandEnabled(int command_id) {
+ return false;
+}
+
+void PrefixSelector::ExecuteEditingCommand(int command_id) {
+}
+
+void PrefixSelector::OnTextInput(const base::string16& text) {
// Small hack to filter out 'tab' and 'enter' input, as the expectation is
// that they are control characters and will not affect the currently-active
// prefix.
@@ -171,9 +178,9 @@ void PrefixSelector::OnTextInput(const string16& text) {
time_of_last_key_ = now;
const int start_row = row;
- const string16 lower_text(base::i18n::ToLower(current_text_));
+ const base::string16 lower_text(base::i18n::ToLower(current_text_));
do {
- if (TextAtRowMatchesText(row, current_text_)) {
+ if (TextAtRowMatchesText(row, lower_text)) {
prefix_delegate_->SetSelectedRow(row);
return;
}
@@ -182,8 +189,8 @@ void PrefixSelector::OnTextInput(const string16& text) {
}
bool PrefixSelector::TextAtRowMatchesText(int row,
- const string16& lower_text) {
- const string16 model_text(
+ const base::string16& lower_text) {
+ const base::string16 model_text(
base::i18n::ToLower(prefix_delegate_->GetTextForRow(row)));
return (model_text.size() >= lower_text.size()) &&
(model_text.compare(0, lower_text.size(), lower_text) == 0);
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index 57f6dcfe183..255046f60df 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -29,8 +29,8 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
const ui::CompositionText& composition) OVERRIDE;
virtual void ConfirmCompositionText() OVERRIDE;
virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
virtual ui::TextInputType GetTextInputType() const OVERRIDE;
virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
@@ -45,7 +45,7 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
+ base::string16* text) const OVERRIDE;
virtual void OnInputMethodChanged() OVERRIDE;
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) OVERRIDE;
@@ -55,12 +55,15 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
virtual void OnCandidateWindowUpdated() OVERRIDE;
virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
+
private:
// Invoked when text is typed. Tries to change the selection appropriately.
- void OnTextInput(const string16& text);
+ void OnTextInput(const base::string16& text);
// Returns true if the text of the node at |row| starts with |lower_text|.
- bool TextAtRowMatchesText(int row, const string16& lower_text);
+ bool TextAtRowMatchesText(int row, const base::string16& lower_text);
// Clears |current_text_| and resets |time_of_last_key_|.
void ClearText();
@@ -70,7 +73,7 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
// Time OnTextInput() was last invoked.
base::TimeTicks time_of_last_key_;
- string16 current_text_;
+ base::string16 current_text_;
DISALLOW_COPY_AND_ASSIGN(PrefixSelector);
};
diff --git a/chromium/ui/views/controls/prefix_selector_unittest.cc b/chromium/ui/views/controls/prefix_selector_unittest.cc
index c39e6cc652a..031c0079aee 100644
--- a/chromium/ui/views/controls/prefix_selector_unittest.cc
+++ b/chromium/ui/views/controls/prefix_selector_unittest.cc
@@ -11,6 +11,8 @@
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace views {
class TestPrefixDelegate : public PrefixDelegate {
@@ -36,12 +38,12 @@ class TestPrefixDelegate : public PrefixDelegate {
selected_row_ = row;
}
- virtual string16 GetTextForRow(int row) OVERRIDE {
+ virtual base::string16 GetTextForRow(int row) OVERRIDE {
return rows_[row];
}
private:
- std::vector<string16> rows_;
+ std::vector<base::string16> rows_;
int selected_row_;
DISALLOW_COPY_AND_ASSIGN(TestPrefixDelegate);
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 087c2df9830..0d6ed17f5e0 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -11,7 +11,7 @@
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
namespace {
@@ -81,7 +81,7 @@ void FillRoundRect(gfx::Canvas* canvas,
p[1].iset(x, y + h);
}
skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
- p, colors, points, count, SkShader::kClamp_TileMode, NULL));
+ p, colors, points, count, SkShader::kClamp_TileMode));
paint.setShader(s.get());
canvas->DrawPath(path, paint);
@@ -167,22 +167,23 @@ void ProgressBar::SetValue(double value) {
}
}
-void ProgressBar::SetTooltipText(const string16& tooltip_text) {
+void ProgressBar::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
}
-bool ProgressBar::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool ProgressBar::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
DCHECK(tooltip);
*tooltip = tooltip_text_;
return !tooltip_text_.empty();
}
-void ProgressBar::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PROGRESSBAR;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
+void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
}
-gfx::Size ProgressBar::GetPreferredSize() {
+gfx::Size ProgressBar::GetPreferredSize() const {
gfx::Size pref_size(100, 11);
gfx::Insets insets = GetInsets();
pref_size.Enlarge(insets.width(), insets.height());
@@ -227,7 +228,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
kCornerRadius,
0,
&inner_path);
- canvas->ClipPath(inner_path);
+ canvas->ClipPath(inner_path, false);
const SkColor bar_colors[] = {
kBarTopColor,
@@ -299,7 +300,7 @@ void ProgressBar::OnPaint(gfx::Canvas* canvas) {
skia::RefPtr<SkShader> s =
skia::AdoptRef(SkGradientShader::CreateLinear(
p, highlight_colors, highlight_points,
- arraysize(highlight_colors), SkShader::kClamp_TileMode, NULL));
+ arraysize(highlight_colors), SkShader::kClamp_TileMode));
paint.setShader(s.get());
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
canvas->DrawRect(gfx::Rect(highlight_left, 0,
diff --git a/chromium/ui/views/controls/progress_bar.h b/chromium/ui/views/controls/progress_bar.h
index 1f3d595534c..b6d3851baaf 100644
--- a/chromium/ui/views/controls/progress_bar.h
+++ b/chromium/ui/views/controls/progress_bar.h
@@ -35,18 +35,18 @@ class VIEWS_EXPORT ProgressBar : public View {
// Sets the tooltip text. Default behavior for a progress bar is to show no
// tooltip on mouse hover. Calling this lets you set a custom tooltip. To
// revert to default behavior, call this with an empty string.
- void SetTooltipText(const string16& tooltip_text);
+ void SetTooltipText(const base::string16& tooltip_text);
// Overridden from View:
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
static const char kViewClassName[];
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -58,7 +58,7 @@ class VIEWS_EXPORT ProgressBar : public View {
double current_value_;
// Tooltip text.
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(ProgressBar);
};
diff --git a/chromium/ui/views/controls/progress_bar_unittest.cc b/chromium/ui/views/controls/progress_bar_unittest.cc
index 78df2e17d0d..b9067b20c9b 100644
--- a/chromium/ui/views/controls/progress_bar_unittest.cc
+++ b/chromium/ui/views/controls/progress_bar_unittest.cc
@@ -6,16 +6,16 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
TEST(ProgressBarTest, TooltipTextProperty) {
ProgressBar bar;
- string16 tooltip = ASCIIToUTF16("Some text");
+ base::string16 tooltip = base::ASCIIToUTF16("Some text");
EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(string16(), tooltip);
- string16 tooltip_text = ASCIIToUTF16("My progress");
+ EXPECT_EQ(base::string16(), tooltip);
+ base::string16 tooltip_text = base::ASCIIToUTF16("My progress");
bar.SetTooltipText(tooltip_text);
EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
EXPECT_EQ(tooltip_text, tooltip);
@@ -25,11 +25,11 @@ TEST(ProgressBarTest, Accessibility) {
ProgressBar bar;
bar.SetValue(62);
- ui::AccessibleViewState state;
+ ui::AXViewState state;
bar.GetAccessibleState(&state);
- EXPECT_EQ(ui::AccessibilityTypes::ROLE_PROGRESSBAR, state.role);
- EXPECT_EQ(string16(), state.name);
- EXPECT_TRUE(ui::AccessibilityTypes::STATE_READONLY & state.state);
+ EXPECT_EQ(ui::AX_ROLE_PROGRESS_INDICATOR, state.role);
+ EXPECT_EQ(base::string16(), state.name);
+ EXPECT_TRUE(state.HasStateFlag(ui::AX_STATE_READ_ONLY));
}
} // namespace views
diff --git a/chromium/ui/views/controls/resize_area.cc b/chromium/ui/views/controls/resize_area.cc
index 845f2e8d42d..8a5159f7eda 100644
--- a/chromium/ui/views/controls/resize_area.cc
+++ b/chromium/ui/views/controls/resize_area.cc
@@ -5,13 +5,11 @@
#include "ui/views/controls/resize_area.h"
#include "base/logging.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/resize_area_delegate.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -33,14 +31,8 @@ const char* ResizeArea::GetClassName() const {
}
gfx::NativeCursor ResizeArea::GetCursor(const ui::MouseEvent& event) {
- if (!enabled())
- return gfx::kNullCursor;
-#if defined(USE_AURA)
- return ui::kCursorEastWestResize;
-#elif defined(OS_WIN)
- static HCURSOR g_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
- return g_resize_cursor;
-#endif
+ return enabled() ? GetNativeEastWestResizeCursor()
+ : gfx::kNullCursor;
}
bool ResizeArea::OnMousePressed(const ui::MouseEvent& event) {
@@ -73,8 +65,8 @@ void ResizeArea::OnMouseCaptureLost() {
ReportResizeAmount(initial_position_, true);
}
-void ResizeArea::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+void ResizeArea::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SPLITTER;
}
void ResizeArea::ReportResizeAmount(int resize_amount, bool last_update) {
diff --git a/chromium/ui/views/controls/resize_area.h b/chromium/ui/views/controls/resize_area.h
index 288b912ba80..12ec310026e 100644
--- a/chromium/ui/views/controls/resize_area.h
+++ b/chromium/ui/views/controls/resize_area.h
@@ -32,7 +32,7 @@ class VIEWS_EXPORT ResizeArea : public View {
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
private:
// Report the amount the user resized by to the delegate, accounting for
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index d835c1ebdf8..51db071b71f 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -20,22 +20,16 @@ namespace {
// Subclass of ScrollView that resets the border when the theme changes.
class ScrollViewWithBorder : public views::ScrollView {
public:
- ScrollViewWithBorder() {
- SetThemeSpecificState();
- }
+ ScrollViewWithBorder() {}
// View overrides;
virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE {
- SetThemeSpecificState();
+ SetBorder(Border::CreateSolidBorder(
+ 1,
+ theme->GetSystemColor(ui::NativeTheme::kColorId_UnfocusedBorderColor)));
}
private:
- void SetThemeSpecificState() {
- set_border(Border::CreateSolidBorder(
- 1, GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_UnfocusedBorderColor)));
- }
-
DISALLOW_COPY_AND_ASSIGN(ScrollViewWithBorder);
};
@@ -116,6 +110,8 @@ ScrollView::ScrollView()
horiz_sb_(new NativeScrollBar(true)),
vert_sb_(new NativeScrollBar(false)),
resize_corner_(NULL),
+ min_height_(-1),
+ max_height_(-1),
hide_horizontal_scrollbar_(false) {
set_notify_enter_exit_on_child(true);
@@ -162,6 +158,11 @@ gfx::Rect ScrollView::GetVisibleRect() const {
contents_viewport_->width(), contents_viewport_->height());
}
+void ScrollView::ClipHeightTo(int min_height, int max_height) {
+ min_height_ = min_height;
+ max_height_ = max_height;
+}
+
int ScrollView::GetScrollBarWidth() const {
return vert_sb_ ? vert_sb_->GetLayoutSize() : 0;
}
@@ -186,7 +187,40 @@ void ScrollView::SetVerticalScrollBar(ScrollBar* vert_sb) {
vert_sb_ = vert_sb;
}
+gfx::Size ScrollView::GetPreferredSize() const {
+ if (!is_bounded())
+ return View::GetPreferredSize();
+
+ gfx::Size size = contents()->GetPreferredSize();
+ size.SetToMax(gfx::Size(size.width(), min_height_));
+ size.SetToMin(gfx::Size(size.width(), max_height_));
+ gfx::Insets insets = GetInsets();
+ size.Enlarge(insets.width(), insets.height());
+ return size;
+}
+
+int ScrollView::GetHeightForWidth(int width) const {
+ if (!is_bounded())
+ return View::GetHeightForWidth(width);
+
+ gfx::Insets insets = GetInsets();
+ width = std::max(0, width - insets.width());
+ int height = contents()->GetHeightForWidth(width) + insets.height();
+ return std::min(std::max(height, min_height_), max_height_);
+}
+
void ScrollView::Layout() {
+ if (is_bounded()) {
+ int content_width = width();
+ int content_height = contents()->GetHeightForWidth(content_width);
+ if (content_height > height()) {
+ content_width = std::max(content_width - GetScrollBarWidth(), 0);
+ content_height = contents()->GetHeightForWidth(content_width);
+ }
+ if (contents()->bounds().size() != gfx::Size(content_width, content_height))
+ contents()->SetBounds(0, 0, content_width, content_height);
+ }
+
// Most views will want to auto-fit the available space. Most of them want to
// use all available width (without overflowing) and only overflow in
// height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc.
diff --git a/chromium/ui/views/controls/scroll_view.h b/chromium/ui/views/controls/scroll_view.h
index da87ffdc753..c1c18713af0 100644
--- a/chromium/ui/views/controls/scroll_view.h
+++ b/chromium/ui/views/controls/scroll_view.h
@@ -31,6 +31,7 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
static const char kViewClassName[];
ScrollView();
+
virtual ~ScrollView();
// Creates a ScrollView with a theme specific border.
@@ -52,6 +53,13 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
hide_horizontal_scrollbar_ = visible;
}
+ // Turns this scroll view into a bounded scroll view, with a fixed height.
+ // By default, a ScrollView will stretch to fill its outer container.
+ void ClipHeightTo(int min_height, int max_height);
+
+ // Returns whether or not the ScrollView is bounded (as set by ClipHeightTo).
+ bool is_bounded() const { return max_height_ >= 0 && min_height_ >= 0; }
+
// Retrieves the width/height of scrollbars. These return 0 if the scrollbar
// has not yet been created.
int GetScrollBarWidth() const;
@@ -67,6 +75,8 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
void SetVerticalScrollBar(ScrollBar* vert_sb);
// View overrides:
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual int GetHeightForWidth(int width) const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnMouseWheel(const ui::MouseWheelEvent& e) OVERRIDE;
@@ -127,6 +137,11 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// Resize corner.
View* resize_corner_;
+ // The min and max height for the bounded scroll view. These are negative
+ // values if the view is not bounded.
+ int min_height_;
+ int max_height_;
+
// If true, never show the horizontal scrollbar (even if the contents is wider
// than the viewport).
bool hide_horizontal_scrollbar_;
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index f0bdbd5443d..8f34377553f 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -5,11 +5,17 @@
#include "ui/views/controls/scroll_view.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
+#include "ui/views/test/test_views.h"
namespace views {
namespace {
+const int kWidth = 100;
+const int kMinHeight = 50;
+const int kMaxHeight = 100;
+
// View implementation that allows setting the preferred size.
class CustomView : public View {
public:
@@ -20,7 +26,7 @@ class CustomView : public View {
PreferredSizeChanged();
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return preferred_size_;
}
@@ -148,7 +154,6 @@ TEST(ScrollViewTest, ScrollBarsWithHeader) {
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();
@@ -214,7 +219,6 @@ TEST(ScrollViewTest, HeaderScrollsWithContent) {
EXPECT_EQ("-1,0", header->bounds().origin().ToString());
}
-
// Verifies ScrollRectToVisible() on the child works.
TEST(ScrollViewTest, ScrollRectToVisible) {
ScrollView scroll_view;
@@ -237,4 +241,97 @@ TEST(ScrollViewTest, ScrollRectToVisible) {
EXPECT_EQ(-(415 - viewport_height), contents->y());
}
+// Verifies ClipHeightTo() uses the height of the content when it is between the
+// minimum and maximum height values.
+TEST(ScrollViewTest, ClipHeightToNormalContentHeight) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kNormalContentHeight = 75;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
+ scroll_view.GetPreferredSize());
+
+ 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());
+}
+
+// Verifies ClipHeightTo() uses the minimum height when the content is shorter
+// thamn the minimum height value.
+TEST(ScrollViewTest, ClipHeightToShortContentHeight) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kShortContentHeight = 10;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize());
+
+ scroll_view.SizeToPreferredSize();
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
+ scroll_view.contents()->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(ScrollViewTest, ClipHeightToTallContentHeight) {
+ ScrollView scroll_view;
+
+ // Use a scrollbar that is disabled by default, so the width of the content is
+ // not affected.
+ scroll_view.SetVerticalScrollBar(new views::OverlayScrollBar(false));
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ const int kTallContentHeight = 1000;
+ scroll_view.SetContents(
+ new views::StaticSizedView(gfx::Size(kWidth, kTallContentHeight)));
+
+ EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.GetPreferredSize());
+
+ scroll_view.SizeToPreferredSize();
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::Size(kWidth, kTallContentHeight),
+ scroll_view.contents()->size());
+ 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(ScrollViewTest, ClipHeightToScrollbarUsesWidth) {
+ ScrollView scroll_view;
+
+ scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
+
+ // Create a view that will be much taller than it is wide.
+ 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());
+
+ gfx::Size new_size(kWidth, scroll_view.GetHeightForWidth(kWidth));
+ scroll_view.SetSize(new_size);
+ scroll_view.Layout();
+
+ int scroll_bar_width = scroll_view.GetScrollBarWidth();
+ int expected_width = kWidth - scroll_bar_width;
+ 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());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
index 6271c2e1bfe..5e4d6a56fa3 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -17,6 +17,7 @@
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/scroll_view.h"
@@ -235,10 +236,19 @@ void BaseScrollBar::OnGestureEvent(ui::GestureEvent* event) {
}
if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
- if (ScrollByContentsOffset(IsHorizontal() ? event->details().scroll_x() :
- event->details().scroll_y())) {
- event->SetHandled();
+ float scroll_amount_f;
+ int scroll_amount;
+ if (IsHorizontal()) {
+ scroll_amount_f = event->details().scroll_x() - roundoff_error_.x();
+ scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+ roundoff_error_.set_x(scroll_amount - scroll_amount_f);
+ } else {
+ scroll_amount_f = event->details().scroll_y() - roundoff_error_.y();
+ scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+ roundoff_error_.set_y(scroll_amount - scroll_amount_f);
}
+ if (ScrollByContentsOffset(scroll_amount))
+ event->SetHandled();
return;
}
@@ -295,17 +305,22 @@ void BaseScrollBar::ShowContextMenuForView(View* source,
menu->AppendSeparator();
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
- if (menu_runner_->RunMenuAt(GetWidget(), NULL, gfx::Rect(p, gfx::Size()),
- views::MenuItemView::TOPLEFT, source_type, MenuRunner::HAS_MNEMONICS |
- views::MenuRunner::CONTEXT_MENU) ==
- MenuRunner::MENU_DELETED)
+ if (menu_runner_->RunMenuAt(
+ GetWidget(),
+ NULL,
+ gfx::Rect(p, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT,
+ source_type,
+ MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
+ MenuRunner::MENU_DELETED) {
return;
+ }
}
///////////////////////////////////////////////////////////////////////////////
// BaseScrollBar, Menu::Delegate implementation:
-string16 BaseScrollBar::GetLabel(int id) const {
+base::string16 BaseScrollBar::GetLabel(int id) const {
int ids_value = 0;
switch (id) {
case ScrollBarContextMenuCommand_ScrollHere:
@@ -337,7 +352,7 @@ string16 BaseScrollBar::GetLabel(int id) const {
NOTREACHED() << "Invalid BaseScrollBar Context Menu command!";
}
- return ids_value ? l10n_util::GetStringUTF16(ids_value) : string16();
+ return ids_value ? l10n_util::GetStringUTF16(ids_value) : base::string16();
}
bool BaseScrollBar::IsCommandEnabled(int id) const {
@@ -378,7 +393,8 @@ void BaseScrollBar::ExecuteCommand(int id) {
///////////////////////////////////////////////////////////////////////////////
// BaseScrollBar, ScrollBar implementation:
-void BaseScrollBar::Update(int viewport_size, int content_size,
+void BaseScrollBar::Update(int viewport_size,
+ int content_size,
int contents_scroll_offset) {
ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
@@ -394,6 +410,7 @@ void BaseScrollBar::Update(int viewport_size, int content_size,
contents_scroll_offset = 0;
if (contents_scroll_offset > content_size)
contents_scroll_offset = content_size;
+ contents_scroll_offset_ = contents_scroll_offset;
// Thumb Height and Thumb Pos.
// The height of the thumb is the ratio of the Viewport height to the
@@ -488,7 +505,7 @@ int BaseScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
}
int BaseScrollBar::CalculateContentsOffset(int thumb_position,
- bool scroll_to_middle) const {
+ bool scroll_to_middle) const {
if (scroll_to_middle)
thumb_position = thumb_position - (thumb_->GetSize() / 2);
return (thumb_position * contents_size_) / GetTrackSize();
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
index a517b6c0645..068ad4ddb6f 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
@@ -64,7 +64,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
CustomButton::ButtonState new_state);
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE = 0;
virtual void Layout() OVERRIDE = 0;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
@@ -93,7 +93,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
ui::MenuSourceType source_type) OVERRIDE;
// Menu::Delegate overrides:
- virtual string16 GetLabel(int id) const OVERRIDE;
+ virtual base::string16 GetLabel(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;
virtual void ExecuteCommand(int id) OVERRIDE;
@@ -178,6 +178,12 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
scoped_ptr<MenuRunner> menu_runner_;
scoped_ptr<ScrollAnimator> scroll_animator_;
+ // Difference between current position and cumulative deltas obtained from
+ // scroll update events.
+ // TODO(tdresser): This should be removed when raw pixel scrolling for views
+ // is enabled. See crbug.com/329354.
+ gfx::Vector2dF roundoff_error_;
+
DISALLOW_COPY_AND_ASSIGN(BaseScrollBar);
};
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
index 6eba692d626..0a765c42962 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc
@@ -35,15 +35,12 @@ void BaseScrollBarButton::OnMouseCaptureLost() {
void BaseScrollBarButton::RepeaterNotifyClick() {
// TODO(sky): See if we can convert to using |Screen| everywhere.
-#if defined(OS_WIN) && !defined(USE_AURA)
- gfx::Point cursor_point(GetMessagePos());
-#else
// TODO(scottmg): Native is wrong: http://crbug.com/133312
gfx::Point cursor_point =
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
-#endif
ui::MouseEvent event(ui::ET_MOUSE_RELEASED,
cursor_point, cursor_point,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
Button::NotifyClick(event);
}
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
index 0859fa903c1..c755441b8b4 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
@@ -44,7 +44,7 @@ class VIEWS_EXPORT BaseScrollBarThumb : public View {
int GetPosition() const;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE = 0;
protected:
// View overrides:
diff --git a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
deleted file mode 100644
index 2597cee0b78..00000000000
--- a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/scrollbar/bitmap_scroll_bar.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "grit/ui_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/views/controls/menu/menu.h"
-#include "ui/views/controls/scroll_view.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(OS_LINUX)
-#include "ui/views/screen.h"
-#endif
-
-#undef min
-#undef max
-
-namespace views {
-
-namespace {
-
-// The distance the mouse can be dragged outside the bounds of the thumb during
-// dragging before the scrollbar will snap back to its regular position.
-const int kScrollThumbDragOutSnap = 100;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// AutorepeatButton
-//
-// A button that activates on mouse pressed rather than released, and that
-// continues to fire the clicked action as the mouse button remains pressed
-// down on the button.
-//
-///////////////////////////////////////////////////////////////////////////////
-class AutorepeatButton : public ImageButton {
- public:
- explicit AutorepeatButton(ButtonListener* listener)
- : ImageButton(listener),
- repeater_(base::Bind(&AutorepeatButton::NotifyClick,
- base::Unretained(this))) {
- }
- virtual ~AutorepeatButton() {}
-
- protected:
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- Button::NotifyClick(event);
- repeater_.Start();
- return true;
- }
-
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
- OnMouseCaptureLost();
- }
-
- virtual void OnMouseCaptureLost() OVERRIDE {
- repeater_.Stop();
- }
-
- private:
- void NotifyClick() {
-#if defined(OS_WIN)
- gfx::Point cursor_point(GetMessagePos());
-#elif defined(OS_LINUX)
- gfx::Point cursor_point = gfx::Screen::GetCursorScreenPoint();
-#endif
- ui::MouseEvent event(ui::ET_MOUSE_RELEASED,
- cursor_point, cursor_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- Button::NotifyClick(event);
- }
-
- // The repeat controller that we use to repeatedly click the button when the
- // mouse button is down.
- RepeatController repeater_;
-
- DISALLOW_COPY_AND_ASSIGN(AutorepeatButton);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BitmapScrollBarThumb
-//
-// A view that acts as the thumb in the scroll bar track that the user can
-// drag to scroll the associated contents view within the viewport.
-//
-///////////////////////////////////////////////////////////////////////////////
-class BitmapScrollBarThumb : public BaseScrollBarThumb {
- public:
- explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar)
- : BaseScrollBarThumb(scroll_bar),
- scroll_bar_(scroll_bar) {
- }
- virtual ~BitmapScrollBarThumb() { }
-
- // View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
- return gfx::Size(background_image()->width(),
- start_cap_image()->height() +
- end_cap_image()->height() +
- grippy_image()->height());
- }
-
- protected:
- // View overrides:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- canvas->DrawImageInt(*start_cap_image(), 0, 0);
- int top_cap_height = start_cap_image()->height();
- int bottom_cap_height = end_cap_image()->height();
- int thumb_body_height = height() - top_cap_height - bottom_cap_height;
- canvas->TileImageInt(*background_image(), 0, top_cap_height,
- background_image()->width(), thumb_body_height);
- canvas->DrawImageInt(*end_cap_image(), 0,
- height() - bottom_cap_height);
-
- // Paint the grippy over the track.
- int grippy_x = (width() - grippy_image()->width()) / 2;
- int grippy_y = (thumb_body_height - grippy_image()->height()) / 2;
- canvas->DrawImageInt(*grippy_image(), grippy_x, grippy_y);
- }
-
- private:
- // Returns the image rendered at the start of the thumb.
- gfx::ImageSkia* start_cap_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][GetState()];
- }
-
- // Returns the image rendered at the end of the thumb.
- gfx::ImageSkia* end_cap_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][GetState()];
- }
-
- // Returns the image that is tiled in the background of the thumb between
- // the start and the end caps.
- gfx::ImageSkia* background_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][GetState()];
- }
-
- // Returns the image that is rendered in the middle of the thumb
- // transparently over the background image.
- gfx::ImageSkia* grippy_image() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY]
- [CustomButton::STATE_NORMAL];
- }
-
- // The BitmapScrollBar that owns us.
- BitmapScrollBar* scroll_bar_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb);
-};
-
-} // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, public:
-
-BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons)
- : BaseScrollBar(horizontal, new BitmapScrollBarThumb(this)),
- prev_button_(new AutorepeatButton(this)),
- next_button_(new AutorepeatButton(this)),
- show_scroll_buttons_(show_scroll_buttons) {
- if (!show_scroll_buttons_) {
- prev_button_->SetVisible(false);
- next_button_->SetVisible(false);
- }
-
- AddChildView(prev_button_);
- AddChildView(next_button_);
-
- set_context_menu_controller(this);
- prev_button_->set_context_menu_controller(this);
- next_button_->set_context_menu_controller(this);
-}
-
-void BitmapScrollBar::SetImage(ScrollBarPart part,
- CustomButton::ButtonState state,
- gfx::ImageSkia* image_skia) {
- DCHECK(part < PART_COUNT);
- DCHECK(state < CustomButton::STATE_COUNT);
- switch (part) {
- case PREV_BUTTON:
- prev_button_->SetImage(state, image_skia);
- break;
- case NEXT_BUTTON:
- next_button_->SetImage(state, image_skia);
- break;
- case THUMB_START_CAP:
- case THUMB_MIDDLE:
- case THUMB_END_CAP:
- case THUMB_GRIPPY:
- case THUMB_TRACK:
- images_[part][state] = image_skia;
- break;
- }
-}
-
-int BitmapScrollBar::GetLayoutSize() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- return IsHorizontal() ? prefsize.height() : prefsize.width();
-}
-
-gfx::Rect BitmapScrollBar::GetTrackBounds() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- if (IsHorizontal()) {
- if (!show_scroll_buttons_)
- prefsize.set_width(0);
- int new_width =
- std::max(0, width() - (prefsize.width() * 2));
- gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height());
- return track_bounds;
- }
- if (!show_scroll_buttons_)
- prefsize.set_height(0);
- gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(),
- std::max(0, height() - (prefsize.height() * 2)));
- return track_bounds;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, View implementation:
-
-gfx::Size BitmapScrollBar::GetPreferredSize() {
- // In this case, we're returning the desired width of the scrollbar and its
- // minimum allowable height.
- gfx::Size button_prefsize = prev_button_->GetPreferredSize();
- return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2);
-}
-
-void BitmapScrollBar::Layout() {
- // Size and place the two scroll buttons.
- if (show_scroll_buttons_) {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- prev_button_->SetBounds(0, 0, prefsize.width(), prefsize.height());
- prefsize = next_button_->GetPreferredSize();
- if (IsHorizontal()) {
- next_button_->SetBounds(width() - prefsize.width(), 0, prefsize.width(),
- prefsize.height());
- } else {
- next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(),
- prefsize.height());
- }
- } else {
- prev_button_->SetBounds(0, 0, 0, 0);
- next_button_->SetBounds(0, 0, 0, 0);
- }
-
- BaseScrollBarThumb* thumb = GetThumb();
- // Size and place the thumb
- gfx::Size thumb_prefsize = thumb->GetPreferredSize();
- gfx::Rect track_bounds = GetTrackBounds();
-
- // Preserve the height/width of the thumb (depending on orientation) as set
- // by the last call to |Update|, but coerce the width/height to be the
- // appropriate value for the images provided.
- if (IsHorizontal()) {
- thumb->SetBounds(thumb->x(), thumb->y(), thumb->width(),
- thumb_prefsize.height());
- } else {
- thumb->SetBounds(thumb->x(), thumb->y(), thumb_prefsize.width(),
- thumb->height());
- }
-
- // Hide the thumb if the track isn't tall enough to display even a tiny
- // thumb. The user can only use the mousewheel, scroll buttons or keyboard
- // in this scenario.
- if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) ||
- (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) {
- thumb->SetVisible(false);
- } else if (!thumb->visible()) {
- thumb->SetVisible(true);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, View implementation:
-
-void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) {
- // Paint the track.
- gfx::Rect track_bounds = GetTrackBounds();
- canvas->TileImageInt(*images_[THUMB_TRACK][GetThumbTrackState()],
- track_bounds.x(), track_bounds.y(),
- track_bounds.width(), track_bounds.height());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, ButtonListener implementation:
-
-void BitmapScrollBar::ButtonPressed(Button* sender, const ui::Event& event) {
- if (sender == prev_button_) {
- ScrollByAmount(SCROLL_PREV_LINE);
- } else if (sender == next_button_) {
- ScrollByAmount(SCROLL_NEXT_LINE);
- }
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h b/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h
deleted file mode 100644
index ac97af499cc..00000000000
--- a/chromium/ui/views/controls/scrollbar/bitmap_scroll_bar.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
-#define UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
-
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
-
-namespace views {
-
-namespace {
-class BitmapScrollBarThumb;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BitmapScrollBar
-//
-// A ScrollBar subclass that implements a scroll bar rendered using images
-// that the user provides. There are images for the up and down buttons, as
-// well as for the thumb and track. This is intended for creating UIs that
-// have customized, non-native appearances, like floating HUDs etc.
-//
-///////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT BitmapScrollBar : public BaseScrollBar,
- public ButtonListener {
- public:
- BitmapScrollBar(bool horizontal, bool show_scroll_buttons);
- virtual ~BitmapScrollBar() { }
-
- // A list of parts that the user may supply images for.
- enum ScrollBarPart {
- // The button used to represent scrolling up/left by 1 line.
- PREV_BUTTON = 0,
- // The button used to represent scrolling down/right by 1 line.
- // IMPORTANT: The code assumes the prev and next
- // buttons have equal width and equal height.
- NEXT_BUTTON,
- // The top/left segment of the thumb on the scrollbar.
- THUMB_START_CAP,
- // The tiled background image of the thumb.
- THUMB_MIDDLE,
- // The bottom/right segment of the thumb on the scrollbar.
- THUMB_END_CAP,
- // The grippy that is rendered in the center of the thumb.
- THUMB_GRIPPY,
- // The tiled background image of the thumb track.
- THUMB_TRACK,
- PART_COUNT
- };
-
- // Sets the image to be rendered for the specified part and state.
- void SetImage(ScrollBarPart part,
- CustomButton::ButtonState state,
- gfx::ImageSkia* image_skia);
-
-
- gfx::Rect GetTrackBounds() const;
-
- protected:
- // View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void Layout() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
-
- // ScrollBar overrides:
- virtual int GetLayoutSize() const OVERRIDE;
-
- // BaseButton::ButtonListener overrides:
- virtual void ButtonPressed(Button* sender,
- const ui::Event& event) OVERRIDE;
-
- private:
- // Up/Down/Left/Right buttons.
- ImageButton* prev_button_;
- ImageButton* next_button_;
-
- // The thumb needs to be able to access the part images.
- friend BitmapScrollBarThumb;
- gfx::ImageSkia* images_[PART_COUNT][CustomButton::STATE_COUNT];
-
- // True if the scroll buttons at each end of the scroll bar should be shown.
- bool show_scroll_buttons_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapScrollBar);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
diff --git a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
index f263068ecd7..b3d1e6a3c32 100644
--- a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.cc
@@ -28,7 +28,7 @@ class KennedyScrollBarThumb : public BaseScrollBarThumb {
protected:
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
private:
@@ -42,7 +42,7 @@ KennedyScrollBarThumb::KennedyScrollBarThumb(BaseScrollBar* scroll_bar)
KennedyScrollBarThumb::~KennedyScrollBarThumb() {
}
-gfx::Size KennedyScrollBarThumb::GetPreferredSize() {
+gfx::Size KennedyScrollBarThumb::GetPreferredSize() const {
return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
}
@@ -77,7 +77,7 @@ int KennedyScrollBar::GetLayoutSize() const {
return kScrollbarWidth;
}
-gfx::Size KennedyScrollBar::GetPreferredSize() {
+gfx::Size KennedyScrollBar::GetPreferredSize() const {
return GetTrackBounds().size();
}
diff --git a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
index 332948387a5..ace3fae31ec 100644
--- a/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/kennedy_scroll_bar.h
@@ -25,7 +25,7 @@ class VIEWS_EXPORT KennedyScrollBar : public BaseScrollBar {
virtual int GetLayoutSize() const OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
index 9a913709a4b..7b45dd6e052 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar.cc
@@ -9,13 +9,10 @@
#include "base/message_loop/message_loop.h"
#include "ui/events/event.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
#include "ui/views/controls/scrollbar/native_scroll_bar_wrapper.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
-#endif
-
namespace views {
// static
@@ -45,7 +42,7 @@ int NativeScrollBar::GetVerticalScrollBarWidth(
////////////////////////////////////////////////////////////////////////////////
// NativeScrollBar, View overrides:
-gfx::Size NativeScrollBar::GetPreferredSize() {
+gfx::Size NativeScrollBar::GetPreferredSize() const {
if (native_wrapper_)
return native_wrapper_->GetView()->GetPreferredSize();
return gfx::Size();
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
index 70d5a83d37a..058784d55ac 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
@@ -40,7 +40,7 @@ class VIEWS_EXPORT NativeScrollBar : public ScrollBar {
FRIEND_TEST_ALL_PREFIXES(NativeScrollBarTest, Scrolling);
// Overridden from View.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
index a8402e5c655..b4f83ccdf7b 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc
@@ -32,7 +32,7 @@ class ScrollBarButton : public BaseScrollBarButton {
ScrollBarButton(ButtonListener* listener, Type type);
virtual ~ScrollBarButton();
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE {
return "ScrollBarButton";
}
@@ -54,7 +54,7 @@ class ScrollBarThumb : public BaseScrollBarThumb {
explicit ScrollBarThumb(BaseScrollBar* scroll_bar);
virtual ~ScrollBarThumb();
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE {
return "ScrollBarThumb";
}
@@ -83,7 +83,7 @@ ScrollBarButton::ScrollBarButton(ButtonListener* listener, Type type)
ScrollBarButton::~ScrollBarButton() {
}
-gfx::Size ScrollBarButton::GetPreferredSize() {
+gfx::Size ScrollBarButton::GetPreferredSize() const {
return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
GetNativeThemeState(),
GetNativeThemeParams());
@@ -164,7 +164,7 @@ ScrollBarThumb::ScrollBarThumb(BaseScrollBar* scroll_bar)
ScrollBarThumb::~ScrollBarThumb() {
}
-gfx::Size ScrollBarThumb::GetPreferredSize() {
+gfx::Size ScrollBarThumb::GetPreferredSize() const {
return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
GetNativeThemeState(),
GetNativeThemeParams());
@@ -292,7 +292,7 @@ void NativeScrollBarViews::OnPaint(gfx::Canvas* canvas) {
GetNativeTheme()->Paint(canvas->sk_canvas(), part_, state_, bounds, params_);
}
-gfx::Size NativeScrollBarViews::GetPreferredSize() {
+gfx::Size NativeScrollBarViews::GetPreferredSize() const {
const ui::NativeTheme* theme = native_scroll_bar_->GetNativeTheme();
if (native_scroll_bar_->IsHorizontal())
return gfx::Size(0, GetHorizontalScrollBarHeight(theme));
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
index 72d1821cbbf..38dbe0b6f8e 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.h
@@ -36,7 +36,7 @@ class VIEWS_EXPORT NativeScrollBarViews : public BaseScrollBar,
// View overrides:
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// ScrollBar overrides:
diff --git a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index 176f7b9554e..1396bd1ec99 100644
--- a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -30,7 +30,7 @@ class OverlayScrollBarThumb : public BaseScrollBarThumb,
protected:
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// gfx::AnimationDelegate overrides:
@@ -44,18 +44,16 @@ class OverlayScrollBarThumb : public BaseScrollBarThumb,
OverlayScrollBarThumb::OverlayScrollBarThumb(BaseScrollBar* scroll_bar)
: BaseScrollBarThumb(scroll_bar),
animation_opacity_(0.0) {
- if (get_use_acceleration_when_possible()) {
- // This is necessary, otherwise the thumb will be rendered below the views
- // if those views paint to their own layers.
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(false);
- }
+ // This is necessary, otherwise the thumb will be rendered below the views if
+ // those views paint to their own layers.
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
}
OverlayScrollBarThumb::~OverlayScrollBarThumb() {
}
-gfx::Size OverlayScrollBarThumb::GetPreferredSize() {
+gfx::Size OverlayScrollBarThumb::GetPreferredSize() const {
return gfx::Size(kThumbMinimumSize, kThumbMinimumSize);
}
@@ -140,7 +138,7 @@ void OverlayScrollBar::OnGestureEvent(ui::GestureEvent* event) {
BaseScrollBar::OnGestureEvent(event);
}
-gfx::Size OverlayScrollBar::GetPreferredSize() {
+gfx::Size OverlayScrollBar::GetPreferredSize() const {
return gfx::Size();
}
diff --git a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
index b061da08586..428a27715c4 100644
--- a/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/overlay_scroll_bar.h
@@ -28,7 +28,7 @@ class VIEWS_EXPORT OverlayScrollBar : public BaseScrollBar {
virtual void OnMouseExitedScrollView(const ui::MouseEvent& event) OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar.cc b/chromium/ui/views/controls/scrollbar/scroll_bar.cc
index 5374d32ceef..014cf3b53fa 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar.cc
@@ -4,15 +4,15 @@
#include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
namespace views {
ScrollBar::~ScrollBar() {
}
-void ScrollBar::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SCROLLBAR;
+void ScrollBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SCROLL_BAR;
}
bool ScrollBar::IsHorizontal() const {
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar.h b/chromium/ui/views/controls/scrollbar/scroll_bar.h
index aa3800eb614..c8a31c43016 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar.h
@@ -60,7 +60,7 @@ class VIEWS_EXPORT ScrollBar : public View {
virtual ~ScrollBar();
// Overridden from View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// Returns whether this scrollbar is horizontal.
bool IsHorizontal() const;
diff --git a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
index cdf256a6207..c3c96df9b03 100644
--- a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
+++ b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
@@ -156,4 +156,15 @@ TEST_F(NativeScrollBarTest, MAYBE_ScrollBarFitsToBottom) {
scrollbar_->GetPosition());
}
+TEST_F(NativeScrollBarTest, ScrollToEndAfterShrinkAndExpand) {
+ // Scroll to the end of the content.
+ scrollbar_->Update(100, 101, 0);
+ EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
+ // Shrink and then re-exapnd the content.
+ scrollbar_->Update(100, 100, 0);
+ scrollbar_->Update(100, 101, 0);
+ // Ensure the scrollbar allows scrolling to the end.
+ EXPECT_TRUE(scrollbar_->ScrollByContentsOffset(-1));
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc
index bbac3ede9de..a8fe6da7ef3 100644
--- a/chromium/ui/views/controls/separator.cc
+++ b/chromium/ui/views/controls/separator.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/separator.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
namespace views {
@@ -28,17 +28,17 @@ Separator::~Separator() {
////////////////////////////////////////////////////////////////////////////////
// Separator, View overrides:
-gfx::Size Separator::GetPreferredSize() {
+gfx::Size Separator::GetPreferredSize() const {
if (orientation_ == HORIZONTAL)
return gfx::Size(width(), kSeparatorHeight);
return gfx::Size(kSeparatorHeight, height());
}
-void Separator::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+void Separator::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SPLITTER;
}
-void Separator::Paint(gfx::Canvas* canvas) {
+void Separator::Paint(gfx::Canvas* canvas, const views::CullSet& cull_set) {
canvas->FillRect(bounds(), kDefaultColor);
}
diff --git a/chromium/ui/views/controls/separator.h b/chromium/ui/views/controls/separator.h
index 53d10041864..6f45f8cec7f 100644
--- a/chromium/ui/views/controls/separator.h
+++ b/chromium/ui/views/controls/separator.h
@@ -28,9 +28,10 @@ class VIEWS_EXPORT Separator : public View {
virtual ~Separator();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void Paint(gfx::Canvas* canvas,
+ const views::CullSet& cull_set) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:
diff --git a/chromium/ui/views/controls/single_split_view.cc b/chromium/ui/views/controls/single_split_view.cc
index 85dab92fa5d..fe50141293c 100644
--- a/chromium/ui/views/controls/single_split_view.cc
+++ b/chromium/ui/views/controls/single_split_view.cc
@@ -5,14 +5,12 @@
#include "ui/views/controls/single_split_view.h"
#include "skia/ext/skia_utils_win.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/views/background.h"
#include "ui/views/controls/single_split_view_listener.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -62,16 +60,16 @@ const char* SingleSplitView::GetClassName() const {
return kViewClassName;
}
-void SingleSplitView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GROUPING;
+void SingleSplitView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_GROUP;
state->name = accessible_name_;
}
-gfx::Size SingleSplitView::GetPreferredSize() {
+gfx::Size SingleSplitView::GetPreferredSize() const {
int width = 0;
int height = 0;
for (int i = 0; i < 2 && i < child_count(); ++i) {
- View* view = child_at(i);
+ const View* view = child_at(i);
gfx::Size pref = view->GetPreferredSize();
if (is_horizontal_) {
width += pref.width();
@@ -91,14 +89,8 @@ gfx::Size SingleSplitView::GetPreferredSize() {
gfx::NativeCursor SingleSplitView::GetCursor(const ui::MouseEvent& event) {
if (!IsPointInDivider(event.location()))
return gfx::kNullCursor;
-#if defined(USE_AURA)
- return is_horizontal_ ?
- ui::kCursorEastWestResize : ui::kCursorNorthSouthResize;
-#elif defined(OS_WIN)
- static HCURSOR we_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
- static HCURSOR ns_resize_cursor = LoadCursor(NULL, IDC_SIZENS);
- return is_horizontal_ ? we_resize_cursor : ns_resize_cursor;
-#endif
+ return is_horizontal_ ? GetNativeEastWestResizeCursor()
+ : GetNativeNorthSouthResizeCursor();
}
int SingleSplitView::GetDividerSize() const {
@@ -148,7 +140,7 @@ void SingleSplitView::CalculateChildrenBounds(
}
}
-void SingleSplitView::SetAccessibleName(const string16& name) {
+void SingleSplitView::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
diff --git a/chromium/ui/views/controls/single_split_view.h b/chromium/ui/views/controls/single_split_view.h
index f4a336a6ef6..c03c8340e35 100644
--- a/chromium/ui/views/controls/single_split_view.h
+++ b/chromium/ui/views/controls/single_split_view.h
@@ -34,11 +34,11 @@ class VIEWS_EXPORT SingleSplitView : public View {
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// SingleSplitView's preferred size is the sum of the preferred widths
// and the max of the heights.
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Overriden to return a resize cursor when over the divider.
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
@@ -77,7 +77,7 @@ class VIEWS_EXPORT SingleSplitView : public View {
gfx::Rect* leading_bounds,
gfx::Rect* trailing_bounds) const;
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
protected:
// View overrides.
@@ -137,7 +137,7 @@ class VIEWS_EXPORT SingleSplitView : public View {
SingleSplitViewListener* listener_;
// The accessible name of this view.
- string16 accessible_name_;
+ base::string16 accessible_name_;
DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
};
diff --git a/chromium/ui/views/controls/single_split_view_listener.h b/chromium/ui/views/controls/single_split_view_listener.h
index 5c33c665214..0d589c9cfb8 100644
--- a/chromium/ui/views/controls/single_split_view_listener.h
+++ b/chromium/ui/views/controls/single_split_view_listener.h
@@ -5,13 +5,15 @@
#ifndef UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
class SingleSplitView;
// An interface implemented by objects that want to be notified when the
// splitter moves.
-class SingleSplitViewListener {
+class VIEWS_EXPORT SingleSplitViewListener {
public:
// Invoked when split handle is moved by the user. |sender|'s divider_offset
// is already set to the new value, but Layout has not happened yet.
diff --git a/chromium/ui/views/controls/single_split_view_unittest.cc b/chromium/ui/views/controls/single_split_view_unittest.cc
index f82c1b5b090..cfea48ea4ab 100644
--- a/chromium/ui/views/controls/single_split_view_unittest.cc
+++ b/chromium/ui/views/controls/single_split_view_unittest.cc
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/controls/single_split_view.h"
+
#include "base/logging.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/views/controls/single_split_view.h"
#include "ui/views/controls/single_split_view_listener.h"
-using ::testing::_;
-using ::testing::Return;
-
namespace {
static void VerifySplitViewLayout(const views::SingleSplitView& split) {
@@ -44,9 +41,21 @@ static void VerifySplitViewLayout(const views::SingleSplitView& split) {
}
}
-class MockObserver : public views::SingleSplitViewListener {
+class SingleSplitViewListenerImpl : public views::SingleSplitViewListener {
public:
- MOCK_METHOD1(SplitHandleMoved, bool(views::SingleSplitView*));
+ SingleSplitViewListenerImpl() : count_(0) {}
+
+ virtual bool SplitHandleMoved(views::SingleSplitView* sender) OVERRIDE {
+ ++count_;
+ return false;
+ }
+
+ int count() const { return count_; }
+
+ private:
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleSplitViewListenerImpl);
};
class MinimumSizedView: public views::View {
@@ -55,10 +64,10 @@ class MinimumSizedView: public views::View {
private:
gfx::Size min_size_;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
};
-gfx::Size MinimumSizedView::GetMinimumSize() {
+gfx::Size MinimumSizedView::GetMinimumSize() const {
return min_size_;
}
@@ -141,20 +150,14 @@ TEST(SingleSplitViewTest, Resize) {
}
TEST(SingleSplitViewTest, MouseDrag) {
- MockObserver observer;
const int kMinimumChildSize = 25;
MinimumSizedView *child0 =
new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
MinimumSizedView *child1 =
new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
+ SingleSplitViewListenerImpl listener;
SingleSplitView split(
- child0, child1, SingleSplitView::VERTICAL_SPLIT, &observer);
-
- ON_CALL(observer, SplitHandleMoved(_))
- .WillByDefault(Return(true));
- // SplitHandleMoved is called for two mouse moves and one mouse capture loss.
- EXPECT_CALL(observer, SplitHandleMoved(_))
- .Times(5);
+ child0, child1, SingleSplitView::VERTICAL_SPLIT, &listener);
const int kTotalSplitSize = 100;
split.SetBounds(0, 0, 10, kTotalSplitSize);
@@ -166,49 +169,53 @@ TEST(SingleSplitViewTest, MouseDrag) {
gfx::Point press_point(7, kInitialDividerOffset + kMouseOffset);
ui::MouseEvent mouse_pressed(
- ui::ET_MOUSE_PRESSED, press_point, press_point, 0);
+ ui::ET_MOUSE_PRESSED, press_point, press_point, 0, 0);
ASSERT_TRUE(split.OnMousePressed(mouse_pressed));
EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+ EXPECT_EQ(0, listener.count());
// Drag divider to the bottom.
gfx::Point drag_1_point(
5, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta);
ui::MouseEvent mouse_dragged_1(
- ui::ET_MOUSE_DRAGGED, drag_1_point, drag_1_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_1_point, drag_1_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_1));
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta, split.divider_offset());
+ EXPECT_EQ(1, listener.count());
// Drag divider to the top, beyond first child minimum size.
gfx::Point drag_2_point(
7, kMinimumChildSize - 5);
ui::MouseEvent mouse_dragged_2(
- ui::ET_MOUSE_DRAGGED, drag_2_point, drag_2_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_2_point, drag_2_point, 0,0 );
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_2));
- EXPECT_EQ(kMinimumChildSize,
- split.divider_offset());
+ EXPECT_EQ(kMinimumChildSize, split.divider_offset());
+ EXPECT_EQ(2, listener.count());
// Drag divider to the bottom, beyond second child minimum size.
gfx::Point drag_3_point(
7, kTotalSplitSize - kMinimumChildSize + 5);
ui::MouseEvent mouse_dragged_3(
- ui::ET_MOUSE_DRAGGED, drag_3_point, drag_3_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_3_point, drag_3_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_3));
EXPECT_EQ(kTotalSplitSize - kMinimumChildSize - split.GetDividerSize(),
split.divider_offset());
+ EXPECT_EQ(3, listener.count());
// Drag divider between childs' minimum sizes.
gfx::Point drag_4_point(
6, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
ui::MouseEvent mouse_dragged_4(
- ui::ET_MOUSE_DRAGGED, drag_4_point, drag_4_point, 0);
+ ui::ET_MOUSE_DRAGGED, drag_4_point, drag_4_point, 0, 0);
ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_4));
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
split.divider_offset());
+ EXPECT_EQ(4, listener.count());
gfx::Point release_point(
7, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
ui::MouseEvent mouse_released(
- ui::ET_MOUSE_RELEASED, release_point, release_point, 0);
+ ui::ET_MOUSE_RELEASED, release_point, release_point, 0, 0);
split.OnMouseReleased(mouse_released);
EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
split.divider_offset());
@@ -217,6 +224,7 @@ TEST(SingleSplitViewTest, MouseDrag) {
// This shouldn't occur after mouse release, but it's sufficient for testing.
split.OnMouseCaptureLost();
EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+ EXPECT_EQ(5, listener.count());
}
} // namespace views
diff --git a/chromium/ui/views/controls/slide_out_view.cc b/chromium/ui/views/controls/slide_out_view.cc
index d7cb3f6ef5f..d3cafecf7eb 100644
--- a/chromium/ui/views/controls/slide_out_view.cc
+++ b/chromium/ui/views/controls/slide_out_view.cc
@@ -14,10 +14,8 @@ SlideOutView::SlideOutView()
: gesture_scroll_amount_(0.f) {
// If accelerated compositing is not available, this widget tracks the
// OnSlideOut event but does not render any visible changes.
- if (get_use_acceleration_when_possible()) {
- SetPaintToLayer(true);
- SetFillsBoundsOpaquely(false);
- }
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
}
SlideOutView::~SlideOutView() {
@@ -47,13 +45,11 @@ void SlideOutView::OnGestureEvent(ui::GestureEvent* event) {
// The scroll-update events include the incremental scroll amount.
gesture_scroll_amount_ += event->details().scroll_x();
- if (get_use_acceleration_when_possible()) {
- gfx::Transform transform;
- transform.Translate(gesture_scroll_amount_, 0.0);
- layer()->SetTransform(transform);
- layer()->SetOpacity(
- 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f));
- }
+ gfx::Transform transform;
+ transform.Translate(gesture_scroll_amount_, 0.0);
+ layer()->SetTransform(transform);
+ layer()->SetOpacity(
+ 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f));
} else if (event->type() == ui::ET_GESTURE_SCROLL_END) {
const float kScrollRatioForClosingNotification = 0.5f;
@@ -70,9 +66,6 @@ void SlideOutView::OnGestureEvent(ui::GestureEvent* event) {
}
void SlideOutView::RestoreVisualState() {
- if (!get_use_acceleration_when_possible())
- return;
-
// Restore the layer state.
const int kSwipeRestoreDurationMS = 150;
ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
@@ -83,11 +76,6 @@ void SlideOutView::RestoreVisualState() {
}
void SlideOutView::SlideOutAndClose(SlideDirection direction) {
- if (!get_use_acceleration_when_possible()) {
- // No animations, so don't wait to fire the OnSlideOut event.
- OnSlideOut();
- return;
- }
const int kSwipeOutTotalDurationMS = 150;
int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity();
ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc
index 4be6f5a2d56..74e803d454b 100644
--- a/chromium/ui/views/controls/slider.cc
+++ b/chromium/ui/views/controls/slider.cc
@@ -4,6 +4,8 @@
#include "ui/views/controls/slider.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
@@ -12,7 +14,7 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/gfx/animation/slide_animation.h"
@@ -45,7 +47,7 @@ enum BorderElements {
CENTER_RIGHT,
RIGHT,
};
-}
+} // namespace
namespace views {
@@ -81,7 +83,7 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) {
value_is_valid_ = true;
if (value < 0.0)
- value = 0.0;
+ value = 0.0;
else if (value > 1.0)
value = 1.0;
if (value_ == value)
@@ -104,7 +106,7 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) {
}
if (accessibility_events_enabled_ && GetWidget()) {
NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true);
+ ui::AX_EVENT_VALUE_CHANGED, true);
}
}
@@ -167,7 +169,7 @@ void Slider::UpdateState(bool control_on) {
SchedulePaint();
}
-void Slider::SetAccessibleName(const string16& name) {
+void Slider::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
@@ -184,7 +186,7 @@ void Slider::OnPaintFocus(gfx::Canvas* canvas) {
}
}
-gfx::Size Slider::GetPreferredSize() {
+gfx::Size Slider::GetPreferredSize() const {
const int kSizeMajor = 200;
const int kSizeMinor = 40;
@@ -267,8 +269,7 @@ void Slider::OnPaint(gfx::Canvas* canvas) {
bool Slider::OnMousePressed(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
return false;
- if (listener_)
- listener_->SliderDragStarted(this);
+ OnSliderDragStarted();
PrepareForMove(event.location());
MoveButtonTo(event.location());
return true;
@@ -280,8 +281,7 @@ bool Slider::OnMouseDragged(const ui::MouseEvent& event) {
}
void Slider::OnMouseReleased(const ui::MouseEvent& event) {
- if (listener_)
- listener_->SliderDragEnded(this);
+ OnSliderDragEnded();
}
bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
@@ -305,16 +305,37 @@ bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
return false;
}
+void Slider::OnFocus() {
+ View::OnFocus();
+ SchedulePaint();
+}
+
+void Slider::OnBlur() {
+ View::OnBlur();
+ SchedulePaint();
+}
+
void Slider::OnGestureEvent(ui::GestureEvent* event) {
- if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
- event->type() == ui::ET_GESTURE_TAP_DOWN) {
- PrepareForMove(event->location());
- MoveButtonTo(event->location());
- event->SetHandled();
- } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
- event->type() == ui::ET_GESTURE_SCROLL_END) {
- MoveButtonTo(event->location());
- event->SetHandled();
+ switch (event->type()) {
+ // In a multi point gesture only the touch point will generate
+ // an ET_GESTURE_TAP_DOWN event.
+ case ui::ET_GESTURE_TAP_DOWN:
+ OnSliderDragStarted();
+ PrepareForMove(event->location());
+ // Intentional fall through to next case.
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ MoveButtonTo(event->location());
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_END:
+ MoveButtonTo(event->location());
+ event->SetHandled();
+ if (event->details().touch_points() <= 1)
+ OnSliderDragEnded();
+ break;
+ default:
+ break;
}
}
@@ -323,11 +344,21 @@ void Slider::AnimationProgressed(const gfx::Animation* animation) {
SchedulePaint();
}
-void Slider::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_SLIDER;
+void Slider::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SLIDER;
state->name = accessible_name_;
- state->value = UTF8ToUTF16(
- base::StringPrintf("%d%%", (int)(value_ * 100 + 0.5)));
+ state->value = base::UTF8ToUTF16(
+ base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5)));
+}
+
+void Slider::OnSliderDragStarted() {
+ if (listener_)
+ listener_->SliderDragStarted(this);
+}
+
+void Slider::OnSliderDragEnded() {
+ if (listener_)
+ listener_->SliderDragEnded(this);
}
} // namespace views
diff --git a/chromium/ui/views/controls/slider.h b/chromium/ui/views/controls/slider.h
index cec24c2755b..33a760bfd66 100644
--- a/chromium/ui/views/controls/slider.h
+++ b/chromium/ui/views/controls/slider.h
@@ -18,6 +18,10 @@ class SlideAnimation;
namespace views {
+namespace test {
+class SliderTestApi;
+}
+
class Slider;
enum SliderChangeReason {
@@ -57,7 +61,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Set the delta used for changing the value via keyboard.
void SetKeyboardIncrement(float increment);
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
void set_enable_accessibility_events(bool enabled) {
accessibility_events_enabled_ = enabled;
@@ -69,6 +73,8 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void UpdateState(bool control_on);
private:
+ friend class test::SliderTestApi;
+
void SetValueInternal(float value, SliderChangeReason reason);
// Should be called on the Mouse Down event. Used to calculate relative
@@ -81,14 +87,22 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void OnPaintFocus(gfx::Canvas* canvas);
+ // Notify the listener_, if not NULL, that dragging started.
+ void OnSliderDragStarted();
+
+ // Notify the listener_, if not NULL, that dragging ended.
+ void OnSliderDragEnded();
+
// views::View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
// ui::EventHandler overrides:
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
@@ -96,6 +110,10 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// gfx::AnimationDelegate overrides:
virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
+ void set_listener(SliderListener* listener) {
+ listener_ = listener;
+ }
+
SliderListener* listener_;
Orientation orientation_;
@@ -105,7 +123,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
float keyboard_increment_;
float animating_value_;
bool value_is_valid_;
- string16 accessible_name_;
+ base::string16 accessible_name_;
bool accessibility_events_enabled_;
SkColor focus_border_color_;
diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc
index 7add734ec36..da6700e0f72 100644
--- a/chromium/ui/views/controls/slider_unittest.cc
+++ b/chromium/ui/views/controls/slider_unittest.cc
@@ -4,73 +4,381 @@
#include "ui/views/controls/slider.h"
+#include <string>
+
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event.h"
+#include "ui/events/gesture_event_details.h"
+#include "ui/views/test/slider_test_api.h"
+#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
namespace {
-void ClickAt(views::View* view, int x, int y) {
- gfx::Point point(x, y);
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- view->OnMousePressed(press);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- view->OnMouseReleased(release);
+// A views::SliderListener that tracks simple event call history.
+class TestSliderListener : public views::SliderListener {
+ public:
+ TestSliderListener();
+ virtual ~TestSliderListener();
+
+ int last_event_epoch() {
+ return last_event_epoch_;
+ }
+
+ int last_drag_started_epoch() {
+ return last_drag_started_epoch_;
+ }
+
+ int last_drag_ended_epoch() {
+ return last_drag_ended_epoch_;
+ }
+
+ views::Slider* last_drag_started_sender() {
+ return last_drag_started_sender_;
+ }
+
+ views::Slider* last_drag_ended_sender() {
+ return last_drag_ended_sender_;
+ }
+
+ // Resets the state of this as if it were newly created.
+ virtual void ResetCallHistory();
+
+ // views::SliderListener:
+ virtual void SliderValueChanged(views::Slider* sender,
+ float value,
+ float old_value,
+ views::SliderChangeReason reason) OVERRIDE;
+ virtual void SliderDragStarted(views::Slider* sender) OVERRIDE;
+ virtual void SliderDragEnded(views::Slider* sender) OVERRIDE;
+
+ private:
+ // The epoch of the last event.
+ int last_event_epoch_;
+ // The epoch of the last time SliderDragStarted was called.
+ int last_drag_started_epoch_;
+ // The epoch of the last time SliderDragEnded was called.
+ int last_drag_ended_epoch_;
+ // The sender from the last SliderDragStarted call.
+ views::Slider* last_drag_started_sender_;
+ // The sender from the last SliderDragEnded call.
+ views::Slider* last_drag_ended_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSliderListener);
+};
+
+TestSliderListener::TestSliderListener()
+ : last_event_epoch_(0),
+ last_drag_started_epoch_(-1),
+ last_drag_ended_epoch_(-1),
+ last_drag_started_sender_(NULL),
+ last_drag_ended_sender_(NULL) {
+}
+
+TestSliderListener::~TestSliderListener() {
+ last_drag_started_sender_ = NULL;
+ last_drag_ended_sender_ = NULL;
+}
+
+void TestSliderListener::ResetCallHistory() {
+ last_event_epoch_ = 0;
+ last_drag_started_epoch_ = -1;
+ last_drag_ended_epoch_ = -1;
+ last_drag_started_sender_ = NULL;
+ last_drag_ended_sender_ = NULL;
+}
+
+void TestSliderListener::SliderValueChanged(views::Slider* sender,
+ float value,
+ float old_value,
+ views::SliderChangeReason reason) {
+ ++last_event_epoch_;
+}
+
+void TestSliderListener::SliderDragStarted(views::Slider* sender) {
+ last_drag_started_sender_ = sender;
+ last_drag_started_epoch_ = ++last_event_epoch_;
}
+void TestSliderListener::SliderDragEnded(views::Slider* sender) {
+ last_drag_ended_sender_ = sender;
+ last_drag_ended_epoch_ = ++last_event_epoch_;
}
+} // namespace
+
namespace views {
-TEST(SliderTest, UpdateFromClickHorizontal) {
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::HORIZONTAL));
- View* view = slider.get();
- gfx::Size size = view->GetPreferredSize();
- view->SetSize(size);
+// Base test fixture for Slider tests.
+class SliderTest : public views::ViewsTestBase {
+ public:
+ explicit SliderTest(Slider::Orientation orientation);
+ virtual ~SliderTest();
+
+ protected:
+ Slider* slider() {
+ return slider_;
+ }
+
+ TestSliderListener& slider_listener() {
+ return slider_listener_;
+ }
+
+ int max_x() {
+ return max_x_;
+ }
+
+ int max_y() {
+ return max_y_;
+ }
+
+ virtual void ClickAt(int x, int y);
+
+ // testing::Test:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ aura::test::EventGenerator* event_generator() {
+ return event_generator_.get();
+ }
- ClickAt(view, 0, 0);
- EXPECT_EQ(0.0f, slider->value());
+ private:
+ // The Slider's orientation
+ Slider::Orientation orientation_;
+ // The Slider to be tested.
+ Slider* slider_;
+ // A simple SliderListener test double.
+ TestSliderListener slider_listener_;
+ // Stores the default locale at test setup so it can be restored
+ // during test teardown.
+ std::string default_locale_;
+ // The maximum x value within the bounds of the slider.
+ int max_x_;
+ // The maximum y value within the bounds of the slider.
+ int max_y_;
+ // The widget container for the slider being tested.
+ views::Widget* widget_;
+ // An event generator.
+ scoped_ptr<aura::test::EventGenerator> event_generator_;
- ClickAt(view, view->width(), 0);
- EXPECT_EQ(1.0f, slider->value());
+ DISALLOW_COPY_AND_ASSIGN(SliderTest);
+};
+
+SliderTest::SliderTest(Slider::Orientation orientation)
+ : orientation_(orientation),
+ slider_(NULL),
+ default_locale_(""),
+ max_x_(0),
+ max_y_(0) {
+}
+
+SliderTest::~SliderTest() {
}
-TEST(SliderTest, UpdateFromClickVertical) {
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::VERTICAL));
- View* view = slider.get();
+void SliderTest::SetUp() {
+ views::ViewsTestBase::SetUp();
+
+ slider_ = new Slider(NULL, orientation_);
+ View* view = slider_;
gfx::Size size = view->GetPreferredSize();
view->SetSize(size);
+ max_x_ = size.width() - 1;
+ max_y_ = size.height() - 1;
+ default_locale_ = l10n_util::GetApplicationLocale("");
+
+ views::Widget::InitParams init_params(CreateParams(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS));
+ init_params.bounds = gfx::Rect(size);
- ClickAt(view, 0, 0);
- EXPECT_EQ(1.0f, slider->value());
+ widget_ = new views::Widget();
+ widget_->Init(init_params);
+ widget_->SetContentsView(slider_);
+ widget_->Show();
- ClickAt(view, 0, view->height());
- EXPECT_EQ(0.0f, slider->value());
+ aura::Window* native_window = widget_->GetNativeWindow();
+ event_generator_.reset(new aura::test::EventGenerator(
+ native_window->GetRootWindow()));
}
-TEST(SliderTest, UpdateFromClickRTLHorizontal) {
- std::string locale = l10n_util::GetApplicationLocale("");
+void SliderTest::TearDown() {
+ if (widget_ && !widget_->IsClosed())
+ widget_->Close();
+
+ base::i18n::SetICUDefaultLocale(default_locale_);
+
+ views::ViewsTestBase::TearDown();
+}
+
+void SliderTest::ClickAt(int x, int y) {
+ gfx::Point point(x, y);
+ event_generator_->MoveMouseTo(point);
+ event_generator_->ClickLeftButton();
+}
+
+// Test fixture for horizontally oriented slider tests.
+class HorizontalSliderTest : public SliderTest {
+ public:
+ HorizontalSliderTest();
+ virtual ~HorizontalSliderTest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest);
+};
+
+HorizontalSliderTest::HorizontalSliderTest()
+ : SliderTest(Slider::HORIZONTAL) {
+}
+
+HorizontalSliderTest::~HorizontalSliderTest() {
+}
+
+// Test fixture for vertically oriented slider tests.
+class VerticalSliderTest : public SliderTest {
+ public:
+ VerticalSliderTest();
+ virtual ~VerticalSliderTest();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VerticalSliderTest);
+};
+
+VerticalSliderTest::VerticalSliderTest()
+ : SliderTest(Slider::VERTICAL) {
+}
+
+VerticalSliderTest::~VerticalSliderTest() {
+}
+
+TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) {
+ ClickAt(0, 0);
+ EXPECT_EQ(0.0f, slider()->value());
+
+ ClickAt(max_x(), 0);
+ EXPECT_EQ(1.0f, slider()->value());
+}
+
+TEST_F(VerticalSliderTest, UpdateFromClickVertical) {
+ ClickAt(0, 0);
+ EXPECT_EQ(1.0f, slider()->value());
+
+ ClickAt(0, max_y());
+ EXPECT_EQ(0.0f, slider()->value());
+}
+
+TEST_F(HorizontalSliderTest, UpdateFromClickRTLHorizontal) {
base::i18n::SetICUDefaultLocale("he");
- scoped_ptr<Slider> slider(new Slider(NULL, Slider::HORIZONTAL));
- View* view = slider.get();
- gfx::Size size = view->GetPreferredSize();
- view->SetSize(size);
+ ClickAt(0, 0);
+ EXPECT_EQ(1.0f, slider()->value());
+
+ ClickAt(max_x(), 0);
+ EXPECT_EQ(0.0f, slider()->value());
+}
+
+// Test the slider location after a tap gesture.
+TEST_F(HorizontalSliderTest, SliderValueForTapGesture) {
+ // Tap below the minimum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(0, 0));
+ EXPECT_FLOAT_EQ(0, slider()->value());
+
+ // Tap above the maximum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(max_x(), max_y()));
+ EXPECT_FLOAT_EQ(1, slider()->value());
+
+ // Tap somwhere in the middle.
+ slider()->SetValue(0.5);
+ event_generator()->GestureTapAt(gfx::Point(0.75 * max_x(), 0.75 * max_y()));
+ EXPECT_NEAR(0.75, slider()->value(), 0.03);
+}
+
+// Test the slider location after a scroll gesture.
+TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) {
+ // Scroll below the minimum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.5 * max_x(), 0.5 * max_y()),
+ gfx::Point(0, 0),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_EQ(0, slider()->value());
+
+ // Scroll above the maximum.
+ slider()->SetValue(0.5);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.5 * max_x(), 0.5 * max_y()),
+ gfx::Point(max_x(), max_y()),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_EQ(1, slider()->value());
+
+ // Scroll somewhere in the middle.
+ slider()->SetValue(0.25);
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.25 * max_x(), 0.25 * max_y()),
+ gfx::Point(0.75 * max_x(), 0.75 * max_y()),
+ base::TimeDelta::FromMilliseconds(10),
+ 5 /* steps */);
+ EXPECT_NEAR(0.75, slider()->value(), 0.03);
+}
+
+// Verifies the correct SliderListener events are raised for a tap gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForTapGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
+
+ event_generator()->GestureTapAt(gfx::Point(0, 0));
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(2, slider_listener().last_drag_ended_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
+}
+
+// Verifies the correct SliderListener events are raised for a scroll gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForScrollGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
+
+ event_generator()->GestureScrollSequence(
+ gfx::Point(0.25 * max_x(), 0.25 * max_y()),
+ gfx::Point(0.75 * max_x(), 0.75 * max_y()),
+ base::TimeDelta::FromMilliseconds(0),
+ 5 /* steps */);
+
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_GT(slider_listener().last_drag_ended_epoch(),
+ slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
+}
- ClickAt(view, 0, 0);
- EXPECT_EQ(1.0f, slider->value());
+// Verifies the correct SliderListener events are raised for a multi
+// finger scroll gesture.
+TEST_F(HorizontalSliderTest, SliderListenerEventsForMultiFingerScrollGesture) {
+ test::SliderTestApi slider_test_api(slider());
+ slider_test_api.SetListener(&slider_listener());
- ClickAt(view, view->width(), 0);
- EXPECT_EQ(0.0f, slider->value());
+ gfx::Point points[] = {gfx::Point(0, 0.1 * max_y()),
+ gfx::Point(0, 0.2 * max_y())};
+ event_generator()->GestureMultiFingerScroll(2 /* count */, points,
+ 0 /* event_separation_time_ms */, 5 /* steps */,
+ 2 /* move_x */, 0 /* move_y */);
- // Reset locale.
- base::i18n::SetICUDefaultLocale(locale);
+ EXPECT_EQ(1, slider_listener().last_drag_started_epoch());
+ EXPECT_GT(slider_listener().last_drag_ended_epoch(),
+ slider_listener().last_drag_started_epoch());
+ EXPECT_EQ(slider(), slider_listener().last_drag_started_sender());
+ EXPECT_EQ(slider(), slider_listener().last_drag_ended_sender());
}
} // namespace views
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 96cc275c2d1..e7ee56c0b44 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/strings/string_util.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/text_elider.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/label.h"
@@ -15,17 +16,22 @@
namespace views {
+
+// Helpers --------------------------------------------------------------------
+
namespace {
// Calculates the height of a line of text. Currently returns the height of
// a label.
-int CalculateLineHeight() {
+int CalculateLineHeight(const gfx::FontList& font_list) {
Label label;
+ label.SetFontList(font_list);
return label.GetPreferredSize().height();
}
scoped_ptr<Label> CreateLabelRange(
- const string16& text,
+ const base::string16& text,
+ const gfx::FontList& font_list,
const StyledLabel::RangeStyleInfo& style_info,
views::LinkListener* link_listener) {
scoped_ptr<Label> result;
@@ -36,26 +42,27 @@ scoped_ptr<Label> CreateLabelRange(
link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0);
result.reset(link);
} else {
- Label* label = new Label(text);
- // Give the label a focus border so that its preferred size matches
- // links' preferred sizes
- label->SetHasFocusBorder(true);
-
- result.reset(label);
+ result.reset(new Label(text));
}
result->SetEnabledColor(style_info.color);
+ result->SetFontList(font_list);
if (!style_info.tooltip.empty())
result->SetTooltipText(style_info.tooltip);
- if (style_info.font_style != gfx::Font::NORMAL)
- result->SetFont(result->font().DeriveFont(0, style_info.font_style));
+ if (style_info.font_style != gfx::Font::NORMAL) {
+ result->SetFontList(
+ result->font_list().DeriveWithStyle(style_info.font_style));
+ }
- return scoped_ptr<Label>(result.release());
+ return result.Pass();
}
} // namespace
+
+// StyledLabel::RangeStyleInfo ------------------------------------------------
+
StyledLabel::RangeStyleInfo::RangeStyleInfo()
: font_style(gfx::Font::NORMAL),
color(ui::NativeTheme::instance()->GetSystemColor(
@@ -74,35 +81,49 @@ StyledLabel::RangeStyleInfo StyledLabel::RangeStyleInfo::CreateForLink() {
return result;
}
+
+// StyledLabel::StyleRange ----------------------------------------------------
+
bool StyledLabel::StyleRange::operator<(
const StyledLabel::StyleRange& other) const {
- // Intentionally reversed so the priority queue is sorted by smallest first.
- return range.start() > other.range.start();
+ return range.start() < other.range.start();
}
-StyledLabel::StyledLabel(const string16& text, StyledLabelListener* listener)
+
+// StyledLabel ----------------------------------------------------------------
+
+StyledLabel::StyledLabel(const base::string16& text,
+ StyledLabelListener* listener)
: listener_(listener),
displayed_on_background_color_set_(false),
auto_color_readability_enabled_(true) {
- TrimWhitespace(text, TRIM_TRAILING, &text_);
+ base::TrimWhitespace(text, base::TRIM_TRAILING, &text_);
}
StyledLabel::~StyledLabel() {}
-void StyledLabel::SetText(const string16& text) {
+void StyledLabel::SetText(const base::string16& text) {
text_ = text;
- style_ranges_ = std::priority_queue<StyleRange>();
+ style_ranges_.clear();
RemoveAllChildViews(true);
PreferredSizeChanged();
}
+void StyledLabel::SetBaseFontList(const gfx::FontList& font_list) {
+ font_list_ = font_list;
+ PreferredSizeChanged();
+}
+
void StyledLabel::AddStyleRange(const gfx::Range& range,
const RangeStyleInfo& style_info) {
DCHECK(!range.is_reversed());
DCHECK(!range.is_empty());
DCHECK(gfx::Range(0, text_.size()).Contains(range));
- style_ranges_.push(StyleRange(range, style_info));
+ // Insert the new range in sorted order.
+ StyleRanges new_range;
+ new_range.push_front(StyleRange(range, style_info));
+ style_ranges_.merge(new_range);
PreferredSizeChanged();
}
@@ -119,20 +140,37 @@ void StyledLabel::SetDisplayedOnBackgroundColor(SkColor color) {
gfx::Insets StyledLabel::GetInsets() const {
gfx::Insets insets = View::GetInsets();
- const gfx::Insets focus_border_padding(1, 1, 1, 1);
- insets += focus_border_padding;
+
+ // We need a focus border iff we contain a link that will have a focus border.
+ // That in turn will be true only if the link is non-empty.
+ for (StyleRanges::const_iterator i(style_ranges_.begin());
+ i != style_ranges_.end(); ++i) {
+ if (i->style_info.is_link && !i->range.is_empty()) {
+ const gfx::Insets focus_border_padding(
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding,
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding);
+ insets += focus_border_padding;
+ break;
+ }
+ }
+
return insets;
}
-int StyledLabel::GetHeightForWidth(int w) {
- if (w != calculated_size_.width())
- calculated_size_ = gfx::Size(w, CalculateAndDoLayout(w, true));
-
+int StyledLabel::GetHeightForWidth(int w) const {
+ if (w != calculated_size_.width()) {
+ // TODO(erg): Munge the const-ness of the style label. CalculateAndDoLayout
+ // doesn't actually make any changes to member variables when |dry_run| is
+ // set to true. In general, the mutating and non-mutating parts shouldn't
+ // be in the same codepath.
+ calculated_size_ =
+ const_cast<StyledLabel*>(this)->CalculateAndDoLayout(w, true);
+ }
return calculated_size_.height();
}
void StyledLabel::Layout() {
- CalculateAndDoLayout(GetLocalBounds().width(), false);
+ calculated_size_ = CalculateAndDoLayout(GetLocalBounds().width(), false);
}
void StyledLabel::PreferredSizeChanged() {
@@ -145,7 +183,7 @@ void StyledLabel::LinkClicked(Link* source, int event_flags) {
listener_->StyledLabelLinkClicked(link_targets_[source], event_flags);
}
-int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
+gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
if (!dry_run) {
RemoveAllChildViews(true);
link_targets_.clear();
@@ -153,41 +191,43 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
width -= GetInsets().width();
if (width <= 0 || text_.empty())
- return 0;
+ return gfx::Size();
- const int line_height = CalculateLineHeight();
+ const int line_height = CalculateLineHeight(font_list_);
// The index of the line we're on.
int line = 0;
// The x position (in pixels) of the line we're on, relative to content
// bounds.
int x = 0;
- string16 remaining_string = text_;
- std::priority_queue<StyleRange> style_ranges = style_ranges_;
+ base::string16 remaining_string = text_;
+ StyleRanges::const_iterator current_range = style_ranges_.begin();
// Iterate over the text, creating a bunch of labels and links and laying them
// out in the appropriate positions.
while (!remaining_string.empty()) {
// Don't put whitespace at beginning of a line with an exception for the
// first line (so the text's leading whitespace is respected).
- if (x == 0 && line > 0)
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ if (x == 0 && line > 0) {
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
+ }
gfx::Range range(gfx::Range::InvalidRange());
- if (!style_ranges.empty())
- range = style_ranges.top().range;
+ if (current_range != style_ranges_.end())
+ range = current_range->range;
const size_t position = text_.size() - remaining_string.size();
const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
- std::vector<string16> substrings;
- gfx::FontList text_font_list;
+ std::vector<base::string16> substrings;
+ gfx::FontList text_font_list = font_list_;
// If the start of the remaining text is inside a styled range, the font
// style may differ from the base font. The font specified by the range
// should be used when eliding text.
if (position >= range.start()) {
- text_font_list = text_font_list.DeriveFontListWithSizeDeltaAndStyle(
- 0, style_ranges.top().style_info.font_style);
+ text_font_list = text_font_list.DeriveWithStyle(
+ current_range->style_info.font_style);
}
gfx::ElideRectangleText(remaining_string,
text_font_list,
@@ -197,7 +237,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
&substrings);
DCHECK(!substrings.empty());
- string16 chunk = substrings[0];
+ base::string16 chunk = substrings[0];
if (chunk.empty()) {
// Nothing fits on this line. Start a new line.
// If x is 0, first line may have leading whitespace that doesn't fit in a
@@ -205,7 +245,8 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
// anything; abort.
if (x == 0) {
if (line == 0) {
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
continue;
}
break;
@@ -218,7 +259,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
scoped_ptr<Label> label;
if (position >= range.start()) {
- const RangeStyleInfo& style_info = style_ranges.top().style_info;
+ const RangeStyleInfo& style_info = current_range->style_info;
if (style_info.disable_line_wrapping && chunk.size() < range.length() &&
position == range.start() && x != 0) {
@@ -231,42 +272,44 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position));
- label = CreateLabelRange(chunk, style_info, this);
+ label = CreateLabelRange(chunk, font_list_, style_info, this);
if (style_info.is_link && !dry_run)
link_targets_[label.get()] = range;
if (position + chunk.size() >= range.end())
- style_ranges.pop();
+ ++current_range;
} else {
// This chunk is normal text.
if (position + chunk.size() > range.start())
chunk = chunk.substr(0, range.start() - position);
- label = CreateLabelRange(chunk, default_style_info_, this);
+ label = CreateLabelRange(chunk, font_list_, default_style_info_, this);
}
if (displayed_on_background_color_set_)
label->SetBackgroundColor(displayed_on_background_color_);
label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_);
- // Lay out the views to overlap by 1 pixel to compensate for their border
- // spacing. Otherwise, "<a>link</a>," will render as "link ,".
- const int overlap = 1;
+ // Calculate the size of the optional focus border, and overlap by that
+ // amount. Otherwise, "<a>link</a>," will render as "link ,".
+ gfx::Insets focus_border_insets(label->GetInsets());
+ focus_border_insets += -label->View::GetInsets();
const gfx::Size view_size = label->GetPreferredSize();
- DCHECK_EQ(line_height, view_size.height() - 2 * overlap);
+ DCHECK_EQ(line_height, view_size.height() - focus_border_insets.height());
if (!dry_run) {
label->SetBoundsRect(gfx::Rect(
- gfx::Point(GetInsets().left() + x - overlap,
- GetInsets().top() + line * line_height - overlap),
+ gfx::Point(GetInsets().left() + x - focus_border_insets.left(),
+ GetInsets().top() + line * line_height -
+ focus_border_insets.top()),
view_size));
AddChildView(label.release());
}
- x += view_size.width() - 2 * overlap;
+ x += view_size.width() - focus_border_insets.width();
remaining_string = remaining_string.substr(chunk.size());
}
- return (line + 1) * line_height + GetInsets().height();
+ return gfx::Size(width, (line + 1) * line_height + GetInsets().height());
}
} // namespace views
diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h
index adf5993a767..4c599a0d438 100644
--- a/chromium/ui/views/controls/styled_label.h
+++ b/chromium/ui/views/controls/styled_label.h
@@ -5,12 +5,13 @@
#ifndef UI_VIEWS_CONTROLS_STYLED_LABEL_H_
#define UI_VIEWS_CONTROLS_STYLED_LABEL_H_
+#include <list>
#include <map>
-#include <queue>
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/link_listener.h"
@@ -44,7 +45,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
SkColor color;
// Tooltip for the range.
- string16 tooltip;
+ base::string16 tooltip;
// If set, the whole range will be put on a single line.
bool disable_line_wrapping;
@@ -54,11 +55,15 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
};
// Note that any trailing whitespace in |text| will be trimmed.
- StyledLabel(const string16& text, StyledLabelListener* listener);
+ StyledLabel(const base::string16& text, StyledLabelListener* listener);
virtual ~StyledLabel();
// Sets the text to be displayed, and clears any previous styling.
- void SetText(const string16& text);
+ void SetText(const base::string16& text);
+
+ // Sets the fonts used by all labels. Can be augemented by styling set by
+ // AddStyleRange and SetDefaultStyle.
+ void SetBaseFontList(const gfx::FontList& font_list);
// Marks the given range within |text_| with style defined by |style_info|.
// |range| must be contained in |text_|.
@@ -82,7 +87,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// View implementation:
virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual int GetHeightForWidth(int w) OVERRIDE;
+ virtual int GetHeightForWidth(int w) const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void PreferredSizeChanged() OVERRIDE;
@@ -103,15 +108,19 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
gfx::Range range;
RangeStyleInfo style_info;
};
+ typedef std::list<StyleRange> StyleRanges;
// Calculates how to layout child views, creates them and sets their size
// and position. |width| is the horizontal space, in pixels, that the view
// has to work with. If |dry_run| is true, the view hierarchy is not touched.
- // The return value is the height in pixels.
- int CalculateAndDoLayout(int width, bool dry_run);
+ // The return value is the necessary size.
+ gfx::Size CalculateAndDoLayout(int width, bool dry_run);
// The text to display.
- string16 text_;
+ base::string16 text_;
+
+ // Fonts used to display text. Can be augmented by RangeStyleInfo.
+ gfx::FontList font_list_;
// The default style to use for any part of the text that isn't within
// a range in |style_ranges_|.
@@ -121,7 +130,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
StyledLabelListener* listener_;
// The ranges that should be linkified, sorted by start position.
- std::priority_queue<StyleRange> style_ranges_;
+ StyleRanges style_ranges_;
// A mapping from a view to the range it corresponds to in |text_|. Only views
// that correspond to ranges with is_link style set will be added to the map.
@@ -129,7 +138,7 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// This variable saves the result of the last GetHeightForWidth call in order
// to avoid repeated calculation.
- gfx::Size calculated_size_;
+ mutable gfx::Size calculated_size_;
// Background color on which the label is drawn, for auto color readability.
SkColor displayed_on_background_color_;
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index 18595edf3d5..d360aedb1b0 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -9,14 +9,19 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/border.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/styled_label_listener.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+
+using base::ASCIIToUTF16;
namespace views {
-class StyledLabelTest : public testing::Test, public StyledLabelListener {
+class StyledLabelTest : public ViewsTestBase, public StyledLabelListener {
public:
StyledLabelTest() {}
virtual ~StyledLabelTest() {}
@@ -30,6 +35,7 @@ class StyledLabelTest : public testing::Test, public StyledLabelListener {
void InitStyledLabel(const std::string& ascii_text) {
styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this));
+ styled_->set_owned_by_client();
}
int StyledLabelContentHeightForWidth(int w) {
@@ -105,7 +111,7 @@ TEST_F(StyledLabelTest, BasicWrapping) {
StyledLabelContentHeightForWidth(label_preferred_size.width()));
// Also respect the border.
- styled()->set_border(Border::CreateEmptyBorder(3, 3, 3, 3));
+ styled()->SetBorder(Border::CreateEmptyBorder(3, 3, 3, 3));
styled()->SetBounds(
0,
0,
@@ -113,15 +119,19 @@ TEST_F(StyledLabelTest, BasicWrapping) {
styled()->GetInsets().height() + 2 * label_preferred_size.height());
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(3, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(3, styled()->child_at(0)->bounds().y());
- EXPECT_EQ(styled()->bounds().height() - 3,
- styled()->child_at(1)->bounds().bottom());
+ EXPECT_EQ(3, styled()->child_at(0)->x());
+ EXPECT_EQ(3, styled()->child_at(0)->y());
+ EXPECT_EQ(styled()->height() - 3, styled()->child_at(1)->bounds().bottom());
}
TEST_F(StyledLabelTest, CreateLinks) {
const std::string text("This is a test block of text.");
InitStyledLabel(text);
+
+ // Without links, there should be no focus border.
+ EXPECT_TRUE(styled()->GetInsets().empty());
+
+ // Now let's add some links.
styled()->AddStyleRange(gfx::Range(0, 1),
StyledLabel::RangeStyleInfo::CreateForLink());
styled()->AddStyleRange(gfx::Range(1, 2),
@@ -131,9 +141,13 @@ TEST_F(StyledLabelTest, CreateLinks) {
styled()->AddStyleRange(gfx::Range(12, 13),
StyledLabel::RangeStyleInfo::CreateForLink());
+ // Now there should be a focus border because there are non-empty Links.
+ EXPECT_FALSE(styled()->GetInsets().empty());
+
+ // Verify layout creates the right number of children.
styled()->SetBounds(0, 0, 1000, 1000);
styled()->Layout();
- ASSERT_EQ(7, styled()->child_count());
+ EXPECT_EQ(7, styled()->child_count());
}
TEST_F(StyledLabelTest, DontBreakLinks) {
@@ -153,13 +167,15 @@ TEST_F(StyledLabelTest, DontBreakLinks) {
styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
+ // The label has no focus border while the link (and thus overall styled
+ // label) does, so the label should be inset by the width of the focus border.
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
}
TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) {
const std::string text("This is a test block of text, ");
- const std::string unbreakable_text("and this should not be breaked");
+ const std::string unbreakable_text("and this should not be broken");
InitStyledLabel(text + unbreakable_text);
StyledLabel::RangeStyleInfo style_info;
style_info.disable_line_wrapping = true;
@@ -177,8 +193,8 @@ TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) {
styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
}
TEST_F(StyledLabelTest, StyledRangeUnderlined) {
@@ -197,8 +213,9 @@ TEST_F(StyledLabelTest, StyledRangeUnderlined) {
ASSERT_EQ(2, styled()->child_count());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(1)->GetClassName());
- EXPECT_EQ(gfx::Font::UNDERLINE,
- static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::UNDERLINE,
+ static_cast<Label*>(styled()->child_at(1))->font_list().GetFontStyle());
}
TEST_F(StyledLabelTest, StyledRangeBold) {
@@ -215,7 +232,7 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
// and normal style.
Label label(ASCIIToUTF16(bold_text));
const gfx::Size normal_label_size = label.GetPreferredSize();
- label.SetFont(label.font().DeriveFont(0, gfx::Font::BOLD));
+ label.SetFontList(label.font_list().DeriveWithStyle(gfx::Font::BOLD));
const gfx::Size bold_label_size = label.GetPreferredSize();
ASSERT_GE(bold_label_size.width(), normal_label_size.width());
@@ -230,7 +247,7 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
StyledLabel unstyled(ASCIIToUTF16(bold_text), this);
unstyled.SetBounds(0, 0, styled_width, pref_height);
unstyled.Layout();
- ASSERT_EQ(1, unstyled.child_count());
+ EXPECT_EQ(1, unstyled.child_count());
styled()->SetBounds(0, 0, styled_width, pref_height);
styled()->Layout();
@@ -240,22 +257,25 @@ TEST_F(StyledLabelTest, StyledRangeBold) {
// The bold text should be broken up into two parts.
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(0)->GetClassName());
- EXPECT_EQ(gfx::Font::BOLD,
- static_cast<Label*>(styled()->child_at(0))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::BOLD,
+ static_cast<Label*>(styled()->child_at(0))->font_list().GetFontStyle());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(1)->GetClassName());
- EXPECT_EQ(gfx::Font::BOLD,
- static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::BOLD,
+ static_cast<Label*>(styled()->child_at(1))->font_list().GetFontStyle());
ASSERT_EQ(std::string(Label::kViewClassName),
styled()->child_at(2)->GetClassName());
- EXPECT_EQ(gfx::Font::NORMAL,
- static_cast<Label*>(styled()->child_at(2))->font().GetStyle());
+ EXPECT_EQ(
+ gfx::Font::NORMAL,
+ static_cast<Label*>(styled()->child_at(2))->font_list().GetFontStyle());
// The second bold part should start on a new line.
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
- EXPECT_EQ(styled()->child_at(1)->bounds().right() - 2,
- styled()->child_at(2)->bounds().x());
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(1)->x());
+ EXPECT_EQ(styled()->child_at(1)->bounds().right(),
+ styled()->child_at(2)->x());
}
TEST_F(StyledLabelTest, Color) {
@@ -274,16 +294,25 @@ TEST_F(StyledLabelTest, Color) {
text_red.size() + text_link.size()),
style_info_link);
+ styled()->SetBounds(0, 0, 1000, 1000);
+ styled()->Layout();
+
+ Widget* widget = new Widget();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ widget->Init(params);
+ View* container = new View();
+ widget->SetContentsView(container);
+ container->AddChildView(styled());
+
// Obtain the default text color for a label.
- Label label(ASCIIToUTF16(text));
- const SkColor kDefaultTextColor = label.enabled_color();
+ Label* label = new Label(ASCIIToUTF16(text));
+ container->AddChildView(label);
+ const SkColor kDefaultTextColor = label->enabled_color();
// Obtain the default text color for a link;
- Link link(ASCIIToUTF16(text_link));
- const SkColor kDefaultLinkColor = link.enabled_color();
-
- styled()->SetBounds(0, 0, 1000, 1000);
- styled()->Layout();
+ Link* link = new Link(ASCIIToUTF16(text_link));
+ container->AddChildView(link);
+ const SkColor kDefaultLinkColor = link->enabled_color();
EXPECT_EQ(SK_ColorRED,
static_cast<Label*>(styled()->child_at(0))->enabled_color());
@@ -291,23 +320,18 @@ TEST_F(StyledLabelTest, Color) {
static_cast<Label*>(styled()->child_at(1))->enabled_color());
EXPECT_EQ(kDefaultTextColor,
static_cast<Label*>(styled()->child_at(2))->enabled_color());
-}
-TEST_F(StyledLabelTest, ColorReadability) {
- const std::string text(
- "This is a block of text that needs color adjustment.");
- InitStyledLabel(text);
+ // Test adjusted color readability.
styled()->SetDisplayedOnBackgroundColor(SK_ColorBLACK);
-
- // Obtain the text color if it were a pure label.
- Label label(ASCIIToUTF16(text));
- label.SetBackgroundColor(SK_ColorBLACK);
-
- styled()->SetBounds(0, 0, 1000, 1000);
styled()->Layout();
+ label->SetBackgroundColor(SK_ColorBLACK);
- EXPECT_EQ(label.enabled_color(),
- static_cast<Label*>(styled()->child_at(0))->enabled_color());
+ const SkColor kAdjustedTextColor = label->enabled_color();
+ EXPECT_NE(kAdjustedTextColor, kDefaultTextColor);
+ EXPECT_EQ(kAdjustedTextColor,
+ static_cast<Label*>(styled()->child_at(2))->enabled_color());
+
+ widget->CloseNow();
}
TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
@@ -343,15 +367,18 @@ TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
EXPECT_EQ(label_preferred_size.width(), styled()->width());
ASSERT_EQ(5, styled()->child_count());
- EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
- EXPECT_EQ(styled()->child_at(0)->bounds().right() - 2,
- styled()->child_at(1)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(2)->bounds().x());
- EXPECT_EQ(styled()->child_at(2)->bounds().right() - 2,
- styled()->child_at(3)->bounds().x());
- EXPECT_EQ(0, styled()->child_at(4)->bounds().x());
-
- string16 tooltip;
+ // The labels have no focus border while the link (and thus overall styled
+ // label) does, so the labels should be inset by the width of the focus
+ // border.
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(0)->x());
+ EXPECT_EQ(styled()->child_at(0)->bounds().right(),
+ styled()->child_at(1)->x());
+ EXPECT_EQ(Label::kFocusBorderPadding, styled()->child_at(2)->x());
+ EXPECT_EQ(styled()->child_at(2)->bounds().right(),
+ styled()->child_at(3)->x());
+ EXPECT_EQ(0, styled()->child_at(4)->x());
+
+ base::string16 tooltip;
EXPECT_TRUE(
styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip));
EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
@@ -360,11 +387,29 @@ TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
}
+TEST_F(StyledLabelTest, SetBaseFontList) {
+ const std::string text("This is a test block of text.");
+ InitStyledLabel(text);
+ std::string font_name("arial");
+ gfx::Font font(font_name, 30);
+ styled()->SetBaseFontList(gfx::FontList(font));
+ Label label(ASCIIToUTF16(text), gfx::FontList(font));
+
+ styled()->SetBounds(0,
+ 0,
+ label.GetPreferredSize().width(),
+ label.GetPreferredSize().height());
+
+ // Make sure we have the same sizing as a label.
+ EXPECT_EQ(label.GetPreferredSize().height(), styled()->height());
+ EXPECT_EQ(label.GetPreferredSize().width(), styled()->width());
+}
+
TEST_F(StyledLabelTest, HandleEmptyLayout) {
- const std::string text("This is a test block of text, ");
+ const std::string text("This is a test block of text.");
InitStyledLabel(text);
styled()->Layout();
- ASSERT_EQ(0, styled()->child_count());
+ EXPECT_EQ(0, styled()->child_count());
}
-} // namespace
+} // namespace views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 3f2d5da96f5..3d181e0c8ce 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -5,10 +5,11 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "base/logging.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
#include "ui/views/layout/layout_manager.h"
@@ -33,7 +34,7 @@ const char TabbedPane::kViewClassName[] = "TabbedPane";
// The tab view shown in the tab strip.
class Tab : public View {
public:
- Tab(TabbedPane* tabbed_pane, const string16& title, View* contents);
+ Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents);
virtual ~Tab();
View* contents() const { return contents_; }
@@ -46,7 +47,7 @@ class Tab : public View {
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
private:
@@ -75,7 +76,7 @@ class TabStrip : public View {
virtual ~TabStrip();
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
@@ -85,12 +86,14 @@ class TabStrip : public View {
DISALLOW_COPY_AND_ASSIGN(TabStrip);
};
-Tab::Tab(TabbedPane* tabbed_pane, const string16& title, View* contents)
+Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents)
: tabbed_pane_(tabbed_pane),
- title_(new Label(title, gfx::Font().DeriveFont(0, gfx::Font::BOLD))),
+ title_(new Label(title,
+ ui::ResourceBundle::GetSharedInstance().GetFontList(
+ ui::ResourceBundle::BoldFont))),
tab_state_(TAB_ACTIVE),
contents_(contents) {
- // Calculate this now while the font is guaranteed to be bold.
+ // Calculate this now while the font list is guaranteed to be bold.
preferred_title_size_ = title_->GetPreferredSize();
SetState(TAB_INACTIVE);
@@ -136,7 +139,7 @@ void Tab::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
}
-gfx::Size Tab::GetPreferredSize() {
+gfx::Size Tab::GetPreferredSize() const {
gfx::Size size(preferred_title_size_);
size.Enlarge(21, 9);
const int kTabMinWidth = 54;
@@ -157,18 +160,19 @@ void Tab::SetState(TabState tab_state) {
return;
tab_state_ = tab_state;
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
switch (tab_state) {
case TAB_INACTIVE:
title_->SetEnabledColor(kTabTitleColor_Inactive);
- title_->SetFont(gfx::Font());
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
break;
case TAB_ACTIVE:
title_->SetEnabledColor(kTabTitleColor_Active);
- title_->SetFont(gfx::Font().DeriveFont(0, gfx::Font::BOLD));
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BoldFont));
break;
case TAB_HOVERED:
title_->SetEnabledColor(kTabTitleColor_Hovered);
- title_->SetFont(gfx::Font());
+ title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
break;
}
SchedulePaint();
@@ -178,7 +182,7 @@ TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {}
TabStrip::~TabStrip() {}
-gfx::Size TabStrip::GetPreferredSize() {
+gfx::Size TabStrip::GetPreferredSize() const {
gfx::Size size;
for (int i = 0; i < child_count(); ++i) {
const gfx::Size child_size = child_at(i)->GetPreferredSize();
@@ -255,12 +259,12 @@ View* TabbedPane::GetSelectedTab() {
NULL : GetTabAt(selected_tab_index())->contents();
}
-void TabbedPane::AddTab(const string16& title, View* contents) {
+void TabbedPane::AddTab(const base::string16& title, View* contents) {
AddTabAtIndex(tab_strip_->child_count(), title, contents);
}
void TabbedPane::AddTabAtIndex(int index,
- const string16& title,
+ const base::string16& title,
View* contents) {
DCHECK(index >= 0 && index <= GetTabCount());
contents->SetVisible(false);
@@ -304,7 +308,7 @@ void TabbedPane::SelectTab(Tab* tab) {
SelectTabAt(index);
}
-gfx::Size TabbedPane::GetPreferredSize() {
+gfx::Size TabbedPane::GetPreferredSize() const {
gfx::Size size;
for (int i = 0; i < contents_->child_count(); ++i)
size.SetToMax(contents_->child_at(i)->GetPreferredSize());
@@ -360,12 +364,12 @@ void TabbedPane::OnFocus() {
View* selected_tab = GetSelectedTab();
if (selected_tab) {
selected_tab->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_FOCUS, true);
+ ui::AX_EVENT_FOCUS, true);
}
}
-void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST;
+void TabbedPane::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TAB_LIST;
}
} // namespace views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
index a837464a120..83c7fefb058 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -40,12 +40,12 @@ class VIEWS_EXPORT TabbedPane : public View {
// Adds a new tab at the end of this TabbedPane with the specified |title|.
// |contents| is the view displayed when the tab is selected and is owned by
// the TabbedPane.
- void AddTab(const string16& title, View* contents);
+ void AddTab(const base::string16& title, View* contents);
// Adds a new tab at |index| with |title|. |contents| is the view displayed
// when the tab is selected and is owned by the TabbedPane. If the tabbed pane
// is currently empty, the new tab is selected.
- void AddTabAtIndex(int index, const string16& title, View* contents);
+ void AddTabAtIndex(int index, const base::string16& title, View* contents);
// Selects the tab at |index|, which must be valid.
void SelectTabAt(int index);
@@ -54,7 +54,7 @@ class VIEWS_EXPORT TabbedPane : public View {
void SelectTab(Tab* tab);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:
@@ -69,7 +69,7 @@ class VIEWS_EXPORT TabbedPane : public View {
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual void OnFocus() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
// A listener notified when tab selection changes. Weak, not owned.
TabbedPaneListener* listener_;
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
index d2607889ef1..83376f79df0 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_listener.h
@@ -5,11 +5,13 @@
#ifndef UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_LISTENER_H_
#define UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_LISTENER_H_
+#include "ui/views/views_export.h"
+
namespace views {
// An interface implemented by an object to let it know that a tabbed pane was
// selected by the user at the specified index.
-class TabbedPaneListener {
+class VIEWS_EXPORT TabbedPaneListener {
public:
// Called when the tab at |index| is selected by the user.
virtual void TabSelectedAt(int index) = 0;
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 f887a8d2ff4..f81c2a870cb 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -9,6 +9,8 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/test/views_test_base.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace {
@@ -20,7 +22,7 @@ class FixedSizeView : public View {
: size_(size) {}
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return size_;
}
diff --git a/chromium/ui/views/controls/table/table_grouper.h b/chromium/ui/views/controls/table/table_grouper.h
index d6659ac1956..ce100e4c98a 100644
--- a/chromium/ui/views/controls/table/table_grouper.h
+++ b/chromium/ui/views/controls/table/table_grouper.h
@@ -5,9 +5,11 @@
#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_GROUPER_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_GROUPER_H_
+#include "ui/views/views_export.h"
+
namespace views {
-struct GroupRange {
+struct VIEWS_EXPORT GroupRange {
int start;
int length;
};
@@ -15,7 +17,7 @@ struct GroupRange {
// TableGrouper is used by TableView to group a set of rows and treat them
// as one. Rows that fall in the same group are selected together and sorted
// together.
-class TableGrouper {
+class VIEWS_EXPORT TableGrouper {
public:
virtual void GetGroupRange(int model_index, GroupRange* range) = 0;
diff --git a/chromium/ui/views/controls/table/table_header.cc b/chromium/ui/views/controls/table/table_header.cc
index 16d28e3e010..a9d730f958e 100644
--- a/chromium/ui/views/controls/table/table_header.cc
+++ b/chromium/ui/views/controls/table/table_header.cc
@@ -5,15 +5,14 @@
#include "ui/views/controls/table/table_header.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/controls/table/table_utils.h"
#include "ui/views/controls/table/table_view.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+#include "ui/views/native_cursor.h"
namespace views {
@@ -38,15 +37,6 @@ const SkColor kSeparatorColor = SkColorSetRGB(0xAA, 0xAA, 0xAA);
// Size of the sort indicator (doesn't include padding).
const int kSortIndicatorSize = 8;
-gfx::NativeCursor GetResizeCursor() {
-#if defined(USE_AURA)
- return ui::kCursorColumnResize;
-#elif defined(OS_WIN)
- static HCURSOR g_hand_cursor = LoadCursor(NULL, IDC_SIZEWE);
- return g_hand_cursor;
-#endif
-}
-
} // namespace
// static
@@ -95,7 +85,8 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
if (width <= 0)
continue;
- const int title_width = font_.GetStringWidth(columns[i].column.title);
+ const int title_width =
+ gfx::GetStringWidth(columns[i].column.title, font_list_);
const bool paint_sort_indicator =
(columns[i].column.id == sorted_column_id &&
title_width + kSortIndicatorWidth <= width);
@@ -105,10 +96,10 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
width -= kSortIndicatorWidth;
}
- canvas->DrawStringInt(
- columns[i].column.title, font_, kTextColor,
- GetMirroredXWithWidthInView(x, width), kVerticalPadding, width,
- height() - kVerticalPadding * 2,
+ canvas->DrawStringRectWithFlags(
+ columns[i].column.title, font_list_, kTextColor,
+ gfx::Rect(GetMirroredXWithWidthInView(x, width), kVerticalPadding,
+ width, height() - kVerticalPadding * 2),
TableColumnAlignmentToCanvasAlignment(columns[i].column.alignment));
if (paint_sort_indicator) {
@@ -168,13 +159,13 @@ void TableHeader::OnPaint(gfx::Canvas* canvas) {
}
}
-gfx::Size TableHeader::GetPreferredSize() {
- return gfx::Size(1, kVerticalPadding * 2 + font_.GetHeight());
+gfx::Size TableHeader::GetPreferredSize() const {
+ return gfx::Size(1, kVerticalPadding * 2 + font_list_.GetHeight());
}
gfx::NativeCursor TableHeader::GetCursor(const ui::MouseEvent& event) {
return GetResizeColumn(GetMirroredXInView(event.x())) != -1 ?
- GetResizeCursor() : View::GetCursor(event);
+ GetNativeColumnResizeCursor() : View::GetCursor(event);
}
bool TableHeader::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/chromium/ui/views/controls/table/table_header.h b/chromium/ui/views/controls/table/table_header.h
index 2aa280d2d92..a595de949c6 100644
--- a/chromium/ui/views/controls/table/table_header.h
+++ b/chromium/ui/views/controls/table/table_header.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_HEADER_H_
#define UI_VIEWS_CONTROLS_TABLE_TABLE_HEADER_H_
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -25,12 +25,12 @@ class VIEWS_EXPORT TableHeader : public views::View {
explicit TableHeader(TableView* table);
virtual ~TableHeader();
- const gfx::Font& font() const { return font_; }
+ const gfx::FontList& font_list() const { return font_list_; }
// views::View overrides.
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
@@ -70,7 +70,7 @@ class VIEWS_EXPORT TableHeader : public views::View {
bool is_resizing() const { return resize_details_.get() != NULL; }
- const gfx::Font font_;
+ const gfx::FontList font_list_;
TableView* table_;
diff --git a/chromium/ui/views/controls/table/table_utils.cc b/chromium/ui/views/controls/table/table_utils.cc
index 1e730d0a938..393c22dbc6f 100644
--- a/chromium/ui/views/controls/table/table_utils.cc
+++ b/chromium/ui/views/controls/table/table_utils.cc
@@ -6,26 +6,28 @@
#include "base/logging.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/text_utils.h"
#include "ui/views/controls/table/table_view.h"
namespace views {
const int kUnspecifiedColumnWidth = 90;
-int WidthForContent(const gfx::Font& header_font,
- const gfx::Font& content_font,
+int WidthForContent(const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const ui::TableColumn& column,
ui::TableModel* model) {
int width = header_padding;
if (!column.title.empty())
- width = header_font.GetStringWidth(column.title) + header_padding;
+ width = gfx::GetStringWidth(column.title, header_font_list) +
+ header_padding;
for (int i = 0, row_count = model->RowCount(); i < row_count; ++i) {
const int cell_width =
- content_font.GetStringWidth(model->GetText(i, column.id));
+ gfx::GetStringWidth(model->GetText(i, column.id), content_font_list);
width = std::max(width, cell_width);
}
return width + padding;
@@ -34,8 +36,8 @@ int WidthForContent(const gfx::Font& header_font,
std::vector<int> CalculateTableColumnSizes(
int width,
int first_column_padding,
- const gfx::Font& header_font,
- const gfx::Font& content_font,
+ const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const std::vector<ui::TableColumn>& columns,
@@ -49,11 +51,12 @@ std::vector<int> CalculateTableColumnSizes(
if (column.percent > 0) {
total_percent += column.percent;
// Make sure there is at least enough room for the header.
- content_widths[i] = header_font.GetStringWidth(column.title) + padding +
- header_padding;
+ content_widths[i] = gfx::GetStringWidth(column.title, header_font_list)
+ + padding + header_padding;
} else {
- content_widths[i] = WidthForContent(header_font, content_font, padding,
- header_padding, column, model);
+ content_widths[i] = WidthForContent(header_font_list, content_font_list,
+ padding, header_padding, column,
+ model);
if (i == 0)
content_widths[i] += first_column_padding;
}
diff --git a/chromium/ui/views/controls/table/table_utils.h b/chromium/ui/views/controls/table/table_utils.h
index 3c5d4c78175..ec387102e69 100644
--- a/chromium/ui/views/controls/table/table_utils.h
+++ b/chromium/ui/views/controls/table/table_utils.h
@@ -11,7 +11,7 @@
#include "ui/views/views_export.h"
namespace gfx {
-class Font;
+class FontList;
}
namespace views {
@@ -23,23 +23,23 @@ VIEWS_EXPORT extern const int kUnspecifiedColumnWidth;
// Returns the width needed to display the contents of the specified column.
// This is used internally by CalculateTableColumnSizes() and generally not
// useful by itself. |header_padding| is padding added to the header.
-VIEWS_EXPORT int WidthForContent(const gfx::Font& header_font,
- const gfx::Font& content_font,
+VIEWS_EXPORT int WidthForContent(const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const ui::TableColumn& column,
ui::TableModel* model);
// Determines the width for each of the specified columns. |width| is the width
-// to fit the columns into. |header_font| the font used to draw the header and
-// |content_font| the header used to draw the content. |padding| is extra
-// horizontal spaced added to each cell, and |header_padding| added to the
-// width needed for the header.
+// to fit the columns into. |header_font_list| the font list used to draw the
+// header and |content_font_list| the header used to draw the content. |padding|
+// is extra horizontal spaced added to each cell, and |header_padding| added to
+// the width needed for the header.
VIEWS_EXPORT std::vector<int> CalculateTableColumnSizes(
int width,
int first_column_padding,
- const gfx::Font& header_font,
- const gfx::Font& content_font,
+ const gfx::FontList& header_font_list,
+ const gfx::FontList& content_font_list,
int padding,
int header_padding,
const std::vector<ui::TableColumn>& columns,
diff --git a/chromium/ui/views/controls/table/table_utils_unittest.cc b/chromium/ui/views/controls/table/table_utils_unittest.cc
index e6c6369d0b8..98b1fd2f786 100644
--- a/chromium/ui/views/controls/table/table_utils_unittest.cc
+++ b/chromium/ui/views/controls/table/table_utils_unittest.cc
@@ -6,7 +6,7 @@
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/table/test_table_model.h"
using ui::TableColumn;
@@ -40,17 +40,19 @@ TEST(TableUtilsTest, SetWidthHonored) {
std::vector<TableColumn> columns;
columns.push_back(CreateTableColumnWithWidth(20));
columns.push_back(CreateTableColumnWithWidth(30));
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(100, 0, font, font, 0, 0, columns, &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 100, 0, font_list, font_list, 0, 0, columns, &model));
EXPECT_EQ("20,30", IntVectorToString(result));
// Same with some padding, it should be ignored.
- result = CalculateTableColumnSizes(100, 0, font, font, 2, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 100, 0, font_list, font_list, 2, 0, columns, &model);
EXPECT_EQ("20,30", IntVectorToString(result));
// Same with not enough space, it shouldn't matter.
- result = CalculateTableColumnSizes(10, 0, font, font, 2, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 10, 0, font_list, font_list, 2, 0, columns, &model);
EXPECT_EQ("20,30", IntVectorToString(result));
}
@@ -61,11 +63,12 @@ TEST(TableUtilsTest, LastColumnGetsAllSpace) {
std::vector<TableColumn> columns;
columns.push_back(ui::TableColumn());
columns.push_back(ui::TableColumn());
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(500, 0, font, font, 0, 0, columns, &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 500, 0, font_list, font_list, 0, 0, columns, &model));
EXPECT_NE(0, result[0]);
- EXPECT_GE(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ EXPECT_GE(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(500, result[0] + result[1]);
}
@@ -77,38 +80,45 @@ TEST(TableUtilsTest, SingleResizableColumn) {
columns.push_back(ui::TableColumn());
columns.push_back(ui::TableColumn());
columns[2].percent = 1.0f;
- gfx::Font font;
- std::vector<int> result(
- CalculateTableColumnSizes(500, 0, font, font, 0, 0, columns, &model));
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ gfx::FontList font_list;
+ std::vector<int> result(CalculateTableColumnSizes(
+ 500, 0, font_list, font_list, 0, 0, columns, &model));
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(500 - result[0] - result[1], result[2]);
// The same with a slightly larger width passed in.
- result =
- CalculateTableColumnSizes(1000, 0, font, font, 0, 0, columns, &model);
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ result = CalculateTableColumnSizes(
+ 1000, 0, font_list, font_list, 0, 0, columns, &model);
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(1000 - result[0] - result[1], result[2]);
// Verify padding for the first column is honored.
- result =
- CalculateTableColumnSizes(1000, 10, font, font, 0, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ 1000, 10, font_list, font_list, 0, 0, columns, &model);
EXPECT_EQ(result[0],
- WidthForContent(font, font, 0, 0, columns[0], &model) + 10);
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model)
+ + 10);
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(1000 - result[0] - result[1], result[2]);
// Just enough space to show the first two columns. Should force last column
// to min size.
- result =
- CalculateTableColumnSizes(1000, 0, font, font, 0, 0, columns, &model);
- result = CalculateTableColumnSizes(result[0] + result[1], 0, font, font, 0, 0,
- columns, &model);
- EXPECT_EQ(result[0], WidthForContent(font, font, 0, 0, columns[0], &model));
- EXPECT_EQ(result[1], WidthForContent(font, font, 0, 0, columns[1], &model));
+ result = CalculateTableColumnSizes(
+ 1000, 0, font_list, font_list, 0, 0, columns, &model);
+ result = CalculateTableColumnSizes(
+ result[0] + result[1], 0, font_list, font_list, 0, 0, columns, &model);
+ EXPECT_EQ(result[0],
+ WidthForContent(font_list, font_list, 0, 0, columns[0], &model));
+ EXPECT_EQ(result[1],
+ WidthForContent(font_list, font_list, 0, 0, columns[1], &model));
EXPECT_EQ(kUnspecifiedColumnWidth, result[2]);
}
} // namespace views
-
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index 8a27a1f7a91..e5120d49295 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/table/table_grouper.h"
@@ -124,7 +125,7 @@ TableView::TableView(ui::TableModel* model,
table_type_(table_type),
single_selection_(single_selection),
table_view_observer_(NULL),
- row_height_(font_.GetHeight() + kTextVerticalPadding * 2),
+ row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2),
last_parent_width_(0),
layout_width_(0),
grouper_(NULL),
@@ -317,7 +318,7 @@ void TableView::Layout() {
SetBounds(x(), y(), width, height);
}
-gfx::Size TableView::GetPreferredSize() {
+gfx::Size TableView::GetPreferredSize() const {
int width = 50;
if (header_ && !visible_columns_.empty())
width = visible_columns_.back().x + visible_columns_.back().width;
@@ -404,7 +405,7 @@ void TableView::OnGestureEvent(ui::GestureEvent* event) {
}
bool TableView::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
return GetTooltipImpl(p, tooltip, NULL);
}
@@ -522,14 +523,14 @@ void TableView::OnPaint(gfx::Canvas* canvas) {
text_x += kImageSize + kTextHorizontalPadding;
}
if (text_x < cell_bounds.right() - kTextHorizontalPadding) {
- canvas->DrawStringInt(
- model_->GetText(model_index, visible_columns_[j].column.id), font_,
- is_selected ? selected_fg_color : fg_color,
- GetMirroredXWithWidthInView(text_x, cell_bounds.right() - text_x -
- kTextHorizontalPadding),
- cell_bounds.y() + kTextVerticalPadding,
- cell_bounds.right() - text_x,
- cell_bounds.height() - kTextVerticalPadding * 2,
+ canvas->DrawStringRectWithFlags(
+ model_->GetText(model_index, visible_columns_[j].column.id),
+ font_list_, is_selected ? selected_fg_color : fg_color,
+ gfx::Rect(GetMirroredXWithWidthInView(
+ text_x, cell_bounds.right() - text_x - kTextHorizontalPadding),
+ cell_bounds.y() + kTextVerticalPadding,
+ cell_bounds.right() - text_x,
+ cell_bounds.height() - kTextVerticalPadding * 2),
TableColumnAlignmentToCanvasAlignment(
visible_columns_[j].column.alignment));
}
@@ -684,7 +685,7 @@ void TableView::UpdateVisibleColumnSizes() {
first_column_padding += kGroupingIndicatorSize + kTextHorizontalPadding;
std::vector<int> sizes = views::CalculateTableColumnSizes(
- layout_width_, first_column_padding, header_->font(), font_,
+ layout_width_, first_column_padding, header_->font_list(), font_list_,
std::max(kTextHorizontalPadding, TableHeader::kHorizontalPadding) * 2,
TableHeader::kSortIndicatorWidth, columns, model_);
DCHECK_EQ(visible_columns_.size(), sizes.size());
@@ -871,7 +872,7 @@ GroupRange TableView::GetGroupRange(int model_index) const {
}
bool TableView::GetTooltipImpl(const gfx::Point& location,
- string16* tooltip,
+ base::string16* tooltip,
gfx::Point* tooltip_origin) const {
const int row = location.y() / row_height_;
if (row < 0 || row >= RowCount() || visible_columns_.empty())
@@ -883,7 +884,7 @@ bool TableView::GetTooltipImpl(const gfx::Point& location,
x > (visible_columns_[column].x + visible_columns_[column].width))
return false;
- const string16 text(model_->GetText(ViewToModel(row),
+ const base::string16 text(model_->GetText(ViewToModel(row),
visible_columns_[column].column.id));
if (text.empty())
return false;
@@ -892,7 +893,7 @@ bool TableView::GetTooltipImpl(const gfx::Point& location,
AdjustCellBoundsForText(column, &cell_bounds);
const int right = std::min(GetVisibleBounds().right(), cell_bounds.right());
if (right > cell_bounds.x() &&
- font_.GetStringWidth(text) <= (right - cell_bounds.x()))
+ gfx::GetStringWidth(text, font_list_) <= (right - cell_bounds.x()))
return false;
if (tooltip)
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index c2a94724a52..96268067c6b 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -11,7 +11,7 @@
#include "ui/base/models/list_selection_model.h"
#include "ui/base/models/table_model.h"
#include "ui/base/models/table_model_observer.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
@@ -166,12 +166,12 @@ class VIEWS_EXPORT TableView
// View overrides:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
virtual bool GetTooltipTextOrigin(const gfx::Point& p,
gfx::Point* loc) const OVERRIDE;
@@ -291,7 +291,7 @@ class VIEWS_EXPORT TableView
// sets |tooltip| and/or |tooltip_origin| as appropriate, each of which may be
// NULL.
bool GetTooltipImpl(const gfx::Point& location,
- string16* tooltip,
+ base::string16* tooltip,
gfx::Point* tooltip_origin) const;
ui::TableModel* model_;
@@ -316,7 +316,7 @@ class VIEWS_EXPORT TableView
// The selection, in terms of the model.
ui::ListSelectionModel selection_model_;
- gfx::Font font_;
+ gfx::FontList font_list_;
int row_height_;
diff --git a/chromium/ui/views/controls/table/table_view_observer.h b/chromium/ui/views/controls/table/table_view_observer.h
index 44400eee1c7..9cea2603c50 100644
--- a/chromium/ui/views/controls/table/table_view_observer.h
+++ b/chromium/ui/views/controls/table/table_view_observer.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_OBSERVER_H_
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/views_export.h"
namespace views {
@@ -13,7 +14,7 @@ class TableView;
class TableView2;
// TableViewObserver is notified about the TableView selection.
-class TableViewObserver {
+class VIEWS_EXPORT TableViewObserver {
public:
virtual ~TableViewObserver() {}
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index 4d89f3272b3..1d59358d31e 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -67,7 +67,7 @@ class TestTableModel2 : public ui::TableModel {
// ui::TableModel:
virtual int RowCount() OVERRIDE;
- virtual string16 GetText(int row, int column_id) OVERRIDE;
+ virtual base::string16 GetText(int row, int column_id) OVERRIDE;
virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
virtual int CompareValues(int row1, int row2, int column_id) OVERRIDE;
@@ -115,7 +115,7 @@ int TestTableModel2::RowCount() {
return static_cast<int>(rows_.size());
}
-string16 TestTableModel2::GetText(int row, int column_id) {
+base::string16 TestTableModel2::GetText(int row, int column_id) {
return base::IntToString16(rows_[row][column_id]);
}
@@ -175,9 +175,9 @@ class TableViewTest : public testing::Test {
virtual void SetUp() OVERRIDE {
model_.reset(new TestTableModel2);
std::vector<ui::TableColumn> columns(2);
- columns[0].title = ASCIIToUTF16("Title Column 0");
+ columns[0].title = base::ASCIIToUTF16("Title Column 0");
columns[0].sortable = true;
- columns[1].title = ASCIIToUTF16("Title Column 1");
+ columns[1].title = base::ASCIIToUTF16("Title Column 1");
columns[1].id = 1;
columns[1].sortable = true;
table_ = new TestTableView(model_.get(), columns);
@@ -191,7 +191,8 @@ class TableViewTest : public testing::Test {
const int y = row * table_->row_height();
const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(0, y),
gfx::Point(0, y),
- ui::EF_LEFT_MOUSE_BUTTON | flags);
+ ui::EF_LEFT_MOUSE_BUTTON | flags,
+ ui::EF_LEFT_MOUSE_BUTTON);
table_->OnMousePressed(pressed);
}
@@ -289,10 +290,12 @@ TEST_F(TableViewTest, Resize) {
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::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), 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::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x - 1, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ 0);
helper_->header()->OnMouseDragged(dragged);
// This should shrink the first column and pull the second column in.
@@ -378,11 +381,13 @@ TEST_F(TableViewTest, SortOnMouse) {
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::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), 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::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point(x, 0), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
helper_->header()->OnMouseReleased(release);
ASSERT_EQ(1u, table_->sort_descriptors().size());
diff --git a/chromium/ui/views/controls/table/test_table_model.cc b/chromium/ui/views/controls/table/test_table_model.cc
index c855aa163ec..6cac56cff3d 100644
--- a/chromium/ui/views/controls/table/test_table_model.cc
+++ b/chromium/ui/views/controls/table/test_table_model.cc
@@ -22,9 +22,9 @@ int TestTableModel::RowCount() {
return row_count_;
}
-string16 TestTableModel::GetText(int row, int column_id) {
- return ASCIIToUTF16(base::IntToString(row) + "x" +
- base::IntToString(column_id));
+base::string16 TestTableModel::GetText(int row, int column_id) {
+ return base::ASCIIToUTF16(base::IntToString(row) + "x" +
+ base::IntToString(column_id));
}
gfx::ImageSkia TestTableModel::GetIcon(int row) {
diff --git a/chromium/ui/views/controls/table/test_table_model.h b/chromium/ui/views/controls/table/test_table_model.h
index d093102fbe9..8338aae78a5 100644
--- a/chromium/ui/views/controls/table/test_table_model.h
+++ b/chromium/ui/views/controls/table/test_table_model.h
@@ -15,7 +15,7 @@ class TestTableModel : public ui::TableModel {
// ui::TableModel overrides:
virtual int RowCount() OVERRIDE;
- virtual string16 GetText(int row, int column_id) OVERRIDE;
+ virtual base::string16 GetText(int row, int column_id) OVERRIDE;
virtual gfx::ImageSkia GetIcon(int row) OVERRIDE;
virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views.cc b/chromium/ui/views/controls/textfield/native_textfield_views.cc
deleted file mode 100644
index f8fc36217d2..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_views.cc
+++ /dev/null
@@ -1,1545 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/textfield/native_textfield_views.h"
-
-#include <algorithm>
-#include <set>
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/i18n/case_conversion.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_strings.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/drag_utils.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_switches_util.h"
-#include "ui/compositor/layer.h"
-#include "ui/events/event.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/render_text.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/focusable_border.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_model_adapter.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/drag_utils.h"
-#include "ui/views/ime/input_method.h"
-#include "ui/views/metrics.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
-#if defined(OS_WIN) && defined(USE_AURA)
-#include "base/win/win_util.h"
-#endif
-
-namespace {
-
-void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
- DCHECK(src);
-
- gfx::Point new_origin = r->origin();
- views::View::ConvertPointToScreen(src, &new_origin);
- r->set_origin(new_origin);
-}
-
-} // namespace
-
-namespace views {
-
-const char NativeTextfieldViews::kViewClassName[] =
- "views/NativeTextfieldViews";
-
-NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
- : textfield_(parent),
- model_(new TextfieldViewsModel(this)),
- text_border_(new FocusableBorder()),
- is_cursor_visible_(false),
- is_drop_cursor_visible_(false),
- skip_input_method_cancel_composition_(false),
- initiating_drag_(false),
- cursor_timer_(this),
- aggregated_clicks_(0) {
- set_border(text_border_);
- GetRenderText()->SetFontList(textfield_->font_list());
- UpdateColorsFromTheme(GetNativeTheme());
- set_context_menu_controller(this);
- parent->set_context_menu_controller(this);
- set_drag_controller(this);
-}
-
-NativeTextfieldViews::~NativeTextfieldViews() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, View overrides:
-
-bool NativeTextfieldViews::OnMousePressed(const ui::MouseEvent& event) {
- OnBeforeUserAction();
- TrackMouseClicks(event);
-
- TextfieldController* controller = textfield_->GetController();
- if (!(controller && controller->HandleMouseEvent(textfield_, event)) &&
- !textfield_->OnMousePressed(event)) {
- HandleMousePressEvent(event);
- }
-
- OnAfterUserAction();
- touch_selection_controller_.reset();
- return true;
-}
-
-bool NativeTextfieldViews::ExceededDragThresholdFromLastClickLocation(
- const ui::MouseEvent& event) {
- return ExceededDragThreshold(event.location() - last_click_location_);
-}
-
-bool NativeTextfieldViews::OnMouseDragged(const ui::MouseEvent& event) {
- // Don't adjust the cursor on a potential drag and drop, or if the mouse
- // movement from the last mouse click does not exceed the drag threshold.
- if (initiating_drag_ || !ExceededDragThresholdFromLastClickLocation(event) ||
- !event.IsOnlyLeftMouseButton()) {
- return true;
- }
-
- OnBeforeUserAction();
- // TODO: Remove once NativeTextfield implementations are consolidated to
- // Textfield.
- if (!textfield_->OnMouseDragged(event)) {
- MoveCursorTo(event.location(), true);
- if (aggregated_clicks_ == 1) {
- model_->SelectWord();
- // Expand the selection so the initially selected word remains selected.
- gfx::Range selection = GetRenderText()->selection();
- const size_t min = std::min(selection.GetMin(),
- double_click_word_.GetMin());
- const size_t max = std::max(selection.GetMax(),
- double_click_word_.GetMax());
- const bool reversed = selection.is_reversed();
- selection.set_start(reversed ? max : min);
- selection.set_end(reversed ? min : max);
- model_->SelectRange(selection);
- }
- SchedulePaint();
- }
- OnAfterUserAction();
- return true;
-}
-
-void NativeTextfieldViews::OnMouseReleased(const ui::MouseEvent& event) {
- OnBeforeUserAction();
- // TODO: Remove once NativeTextfield implementations are consolidated to
- // Textfield.
- textfield_->OnMouseReleased(event);
- // Cancel suspected drag initiations, the user was clicking in the selection.
- if (initiating_drag_ && MoveCursorTo(event.location(), false))
- SchedulePaint();
- initiating_drag_ = false;
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::OnGestureEvent(ui::GestureEvent* event) {
- textfield_->OnGestureEvent(event);
- if (event->handled())
- return;
-
- switch (event->type()) {
- case ui::ET_GESTURE_TAP_DOWN:
- OnBeforeUserAction();
- textfield_->RequestFocus();
- // We don't deselect if the point is in the selection
- // because TAP_DOWN may turn into a LONG_PRESS.
- if (!GetRenderText()->IsPointInSelection(event->location()) &&
- MoveCursorTo(event->location(), false))
- SchedulePaint();
- OnAfterUserAction();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_SCROLL_UPDATE:
- OnBeforeUserAction();
- if (MoveCursorTo(event->location(), true))
- SchedulePaint();
- OnAfterUserAction();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_SCROLL_END:
- case ui::ET_SCROLL_FLING_START:
- CreateTouchSelectionControllerAndNotifyIt();
- event->SetHandled();
- break;
- case ui::ET_GESTURE_TAP:
- if (event->details().tap_count() == 1) {
- CreateTouchSelectionControllerAndNotifyIt();
- } else {
- OnBeforeUserAction();
- SelectAll(false);
- OnAfterUserAction();
- event->SetHandled();
- }
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- // If long press happens outside selection, select word and show context
- // menu (If touch selection is enabled, context menu is shown by the
- // |touch_selection_controller_|, hence we mark the event handled.
- // Otherwise, the regular context menu will be shown by views).
- // If long press happens in selected text and touch drag drop is enabled,
- // we will turn off touch selection (if one exists) and let views do drag
- // drop.
- if (!GetRenderText()->IsPointInSelection(event->location())) {
- OnBeforeUserAction();
- model_->SelectWord();
- touch_selection_controller_.reset(
- ui::TouchSelectionController::create(this));
- OnCaretBoundsChanged();
- SchedulePaint();
- OnAfterUserAction();
- if (touch_selection_controller_.get())
- event->SetHandled();
- } else if (switches::IsTouchDragDropEnabled()) {
- initiating_drag_ = true;
- touch_selection_controller_.reset();
- } else {
- if (!touch_selection_controller_.get())
- CreateTouchSelectionControllerAndNotifyIt();
- if (touch_selection_controller_.get())
- event->SetHandled();
- }
- return;
- case ui::ET_GESTURE_LONG_TAP:
- if (!touch_selection_controller_.get())
- CreateTouchSelectionControllerAndNotifyIt();
-
- // If touch selection is enabled, the context menu on long tap will be
- // shown by the |touch_selection_controller_|, hence we mark the event
- // handled so views does not try to show context menu on it.
- if (touch_selection_controller_.get())
- event->SetHandled();
- break;
- default:
- View::OnGestureEvent(event);
- return;
- }
- PlatformGestureEventHandling(event);
-}
-
-bool NativeTextfieldViews::OnKeyPressed(const ui::KeyEvent& event) {
- // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on
- // NativeTextfieldViews as it will never gain focus.
- NOTREACHED();
- return false;
-}
-
-bool NativeTextfieldViews::OnKeyReleased(const ui::KeyEvent& event) {
- NOTREACHED();
- return false;
-}
-
-bool NativeTextfieldViews::GetDropFormats(
- int* formats,
- std::set<OSExchangeData::CustomFormat>* custom_formats) {
- if (!textfield_->enabled() || textfield_->read_only())
- return false;
- // TODO(msw): Can we support URL, FILENAME, etc.?
- *formats = ui::OSExchangeData::STRING;
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->AppendDropFormats(formats, custom_formats);
- return true;
-}
-
-bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
- int formats;
- std::set<OSExchangeData::CustomFormat> custom_formats;
- GetDropFormats(&formats, &custom_formats);
- return textfield_->enabled() && !textfield_->read_only() &&
- data.HasAnyFormat(formats, custom_formats);
-}
-
-int NativeTextfieldViews::OnDragUpdated(const ui::DropTargetEvent& event) {
- DCHECK(CanDrop(event.data()));
-
- const gfx::Range& selection = GetRenderText()->selection();
- drop_cursor_position_ = GetRenderText()->FindCursorPosition(event.location());
- bool in_selection = !selection.is_empty() &&
- selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
- is_drop_cursor_visible_ = !in_selection;
- // TODO(msw): Pan over text when the user drags to the visible text edge.
- OnCaretBoundsChanged();
- SchedulePaint();
-
- if (initiating_drag_) {
- if (in_selection)
- return ui::DragDropTypes::DRAG_NONE;
- return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
- ui::DragDropTypes::DRAG_MOVE;
- }
- return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
-}
-
-void NativeTextfieldViews::OnDragExited() {
- is_drop_cursor_visible_ = false;
- SchedulePaint();
-}
-
-int NativeTextfieldViews::OnPerformDrop(const ui::DropTargetEvent& event) {
- DCHECK(CanDrop(event.data()));
-
- is_drop_cursor_visible_ = false;
-
- TextfieldController* controller = textfield_->GetController();
- if (controller) {
- int drag_operation = controller->OnDrop(event.data());
- if (drag_operation != ui::DragDropTypes::DRAG_NONE)
- return drag_operation;
- }
-
- DCHECK(!initiating_drag_ ||
- !GetRenderText()->IsPointInSelection(event.location()));
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
-
- gfx::SelectionModel drop_destination_model =
- GetRenderText()->FindCursorPosition(event.location());
- string16 text;
- event.data().GetString(&text);
- text = GetTextForDisplay(text);
-
- // Delete the current selection for a drag and drop within this view.
- const bool move = initiating_drag_ && !event.IsControlDown() &&
- event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
- if (move) {
- // Adjust the drop destination if it is on or after the current selection.
- size_t drop = drop_destination_model.caret_pos();
- drop -= GetSelectedRange().Intersect(gfx::Range(0, drop)).length();
- model_->DeleteSelectionAndInsertTextAt(text, drop);
- } else {
- model_->MoveCursorTo(drop_destination_model);
- // Drop always inserts text even if the textfield is not in insert mode.
- model_->InsertText(text);
- }
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
- return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
-}
-
-void NativeTextfieldViews::OnDragDone() {
- initiating_drag_ = false;
- is_drop_cursor_visible_ = false;
-}
-
-void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
- OnPaintBackground(canvas);
- PaintTextAndCursor(canvas);
- if (textfield_->draw_border())
- OnPaintBorder(canvas);
-}
-
-void NativeTextfieldViews::OnFocus() {
- NOTREACHED();
-}
-
-void NativeTextfieldViews::OnBlur() {
- NOTREACHED();
-}
-
-void NativeTextfieldViews::OnNativeThemeChanged(const ui::NativeTheme* theme) {
- UpdateColorsFromTheme(theme);
-}
-
-void NativeTextfieldViews::SelectRect(const gfx::Point& start,
- const gfx::Point& end) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return;
-
- gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
- gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
- gfx::SelectionModel selection(
- gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
- end_caret.caret_affinity());
-
- OnBeforeUserAction();
- model_->SelectSelectionModel(selection);
- OnCaretBoundsChanged();
- SchedulePaint();
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::MoveCaretTo(const gfx::Point& point) {
- SelectRect(point, point);
-}
-
-void NativeTextfieldViews::GetSelectionEndPoints(gfx::Rect* p1,
- gfx::Rect* p2) {
- gfx::RenderText* render_text = GetRenderText();
- const gfx::SelectionModel& sel = render_text->selection_model();
- gfx::SelectionModel start_sel =
- render_text->GetSelectionModelForSelectionStart();
- *p1 = render_text->GetCursorBounds(start_sel, true);
- *p2 = render_text->GetCursorBounds(sel, true);
-}
-
-gfx::Rect NativeTextfieldViews::GetBounds() {
- return bounds();
-}
-
-gfx::NativeView NativeTextfieldViews::GetNativeView() {
- return GetWidget()->GetNativeView();
-}
-
-void NativeTextfieldViews::ConvertPointToScreen(gfx::Point* point) {
- View::ConvertPointToScreen(this, point);
-}
-
-void NativeTextfieldViews::ConvertPointFromScreen(gfx::Point* point) {
- View::ConvertPointFromScreen(this, point);
-}
-
-bool NativeTextfieldViews::DrawsHandles() {
- return false;
-}
-
-void NativeTextfieldViews::OpenContextMenu(const gfx::Point& anchor) {
- touch_selection_controller_.reset();
- ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
-}
-
-gfx::NativeCursor NativeTextfieldViews::GetCursor(const ui::MouseEvent& event) {
- bool in_selection = GetRenderText()->IsPointInSelection(event.location());
- bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
- bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
-#if defined(USE_AURA)
- return text_cursor ? ui::kCursorIBeam : ui::kCursorNull;
-#elif defined(OS_WIN)
- static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
- static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
- return text_cursor ? ibeam : arrow;
-#endif
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ContextMenuController overrides:
-void NativeTextfieldViews::ShowContextMenuForView(
- View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) {
- UpdateContextMenu();
- if (context_menu_runner_->RunMenuAt(GetWidget(), NULL,
- gfx::Rect(point, gfx::Size()), views::MenuItemView::TOPLEFT,
- source_type,
- MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
- MenuRunner::MENU_DELETED)
- return;
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, views::DragController overrides:
-void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
- const gfx::Point& press_pt,
- OSExchangeData* data) {
- DCHECK_NE(ui::DragDropTypes::DRAG_NONE,
- GetDragOperationsForView(sender, press_pt));
- data->SetString(GetSelectedText());
- scoped_ptr<gfx::Canvas> canvas(
- views::GetCanvasForDragImage(textfield_->GetWidget(), size()));
- GetRenderText()->DrawSelectedTextForDrag(canvas.get());
- drag_utils::SetDragImageOnDataObject(*canvas, size(),
- press_pt.OffsetFromOrigin(),
- data);
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnWriteDragData(data);
-}
-
-int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
- const gfx::Point& p) {
- int drag_operations = ui::DragDropTypes::DRAG_COPY;
- if (!textfield_->enabled() || textfield_->IsObscured() ||
- !GetRenderText()->IsPointInSelection(p))
- drag_operations = ui::DragDropTypes::DRAG_NONE;
- else if (sender == this && !textfield_->read_only())
- drag_operations =
- ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnGetDragOperationsForTextfield(&drag_operations);
- return drag_operations;
-}
-
-bool NativeTextfieldViews::CanStartDragForView(View* sender,
- const gfx::Point& press_pt,
- const gfx::Point& p) {
- return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, NativeTextifieldWrapper overrides:
-
-string16 NativeTextfieldViews::GetText() const {
- return model_->GetText();
-}
-
-void NativeTextfieldViews::UpdateText() {
- model_->SetText(GetTextForDisplay(textfield_->text()));
- OnCaretBoundsChanged();
- SchedulePaint();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
-}
-
-void NativeTextfieldViews::AppendText(const string16& text) {
- if (text.empty())
- return;
- model_->Append(GetTextForDisplay(text));
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::InsertOrReplaceText(const string16& text) {
- if (text.empty())
- return;
- model_->InsertText(text);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-base::i18n::TextDirection NativeTextfieldViews::GetTextDirection() const {
- return GetRenderText()->GetTextDirection();
-}
-
-string16 NativeTextfieldViews::GetSelectedText() const {
- return model_->GetSelectedText();
-}
-
-void NativeTextfieldViews::SelectAll(bool reversed) {
- model_->SelectAll(reversed);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ClearSelection() {
- model_->ClearSelection();
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-void NativeTextfieldViews::UpdateBorder() {
- // By default, if a caller calls Textfield::RemoveBorder() and does not set
- // any explicit margins, they should get zero margins. But also call
- // UpdateXXXMargins() so we respect any explicitly-set margins.
- //
- // NOTE: If someday Textfield supports toggling |draw_border_| back on, we'll
- // need to update this conditional to set the insets to their default values.
- if (!textfield_->draw_border())
- text_border_->SetInsets(0, 0, 0, 0);
- UpdateHorizontalMargins();
- UpdateVerticalMargins();
-}
-
-void NativeTextfieldViews::UpdateTextColor() {
- SetColor(textfield_->GetTextColor());
-}
-
-void NativeTextfieldViews::UpdateBackgroundColor() {
- const SkColor color = textfield_->GetBackgroundColor();
- set_background(Background::CreateSolidBackground(color));
- GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::UpdateReadOnly() {
- OnTextInputTypeChanged();
-}
-
-void NativeTextfieldViews::UpdateFont() {
- GetRenderText()->SetFontList(textfield_->font_list());
- OnCaretBoundsChanged();
-}
-
-void NativeTextfieldViews::UpdateIsObscured() {
- GetRenderText()->SetObscured(textfield_->IsObscured());
- OnCaretBoundsChanged();
- SchedulePaint();
- OnTextInputTypeChanged();
-}
-
-void NativeTextfieldViews::UpdateEnabled() {
- SetEnabled(textfield_->enabled());
- SchedulePaint();
- OnTextInputTypeChanged();
-}
-
-gfx::Insets NativeTextfieldViews::CalculateInsets() {
- return GetInsets();
-}
-
-void NativeTextfieldViews::UpdateHorizontalMargins() {
- int left, right;
- if (!textfield_->GetHorizontalMargins(&left, &right))
- return;
- gfx::Insets inset = GetInsets();
- text_border_->SetInsets(inset.top(), left, inset.bottom(), right);
- OnBoundsChanged(GetBounds());
-}
-
-void NativeTextfieldViews::UpdateVerticalMargins() {
- int top, bottom;
- if (!textfield_->GetVerticalMargins(&top, &bottom))
- return;
- gfx::Insets inset = GetInsets();
- text_border_->SetInsets(top, inset.left(), bottom, inset.right());
- OnBoundsChanged(GetBounds());
-}
-
-bool NativeTextfieldViews::SetFocus() {
- return false;
-}
-
-View* NativeTextfieldViews::GetView() {
- return this;
-}
-
-gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
- NOTREACHED();
- return NULL;
-}
-
-bool NativeTextfieldViews::IsIMEComposing() const {
- return model_->HasCompositionText();
-}
-
-gfx::Range NativeTextfieldViews::GetSelectedRange() const {
- return GetRenderText()->selection();
-}
-
-void NativeTextfieldViews::SelectRange(const gfx::Range& range) {
- model_->SelectRange(range);
- OnCaretBoundsChanged();
- SchedulePaint();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
-}
-
-gfx::SelectionModel NativeTextfieldViews::GetSelectionModel() const {
- return GetRenderText()->selection_model();
-}
-
-void NativeTextfieldViews::SelectSelectionModel(
- const gfx::SelectionModel& sel) {
- model_->SelectSelectionModel(sel);
- OnCaretBoundsChanged();
- SchedulePaint();
-}
-
-size_t NativeTextfieldViews::GetCursorPosition() const {
- return model_->GetCursorPosition();
-}
-
-bool NativeTextfieldViews::GetCursorEnabled() const {
- return GetRenderText()->cursor_enabled();
-}
-
-void NativeTextfieldViews::SetCursorEnabled(bool enabled) {
- GetRenderText()->SetCursorEnabled(enabled);
-}
-
-bool NativeTextfieldViews::HandleKeyPressed(const ui::KeyEvent& e) {
- TextfieldController* controller = textfield_->GetController();
- bool handled = false;
- if (controller)
- handled = controller->HandleKeyEvent(textfield_, e);
- touch_selection_controller_.reset();
- return handled || HandleKeyEvent(e);
-}
-
-bool NativeTextfieldViews::HandleKeyReleased(const ui::KeyEvent& e) {
- return false; // crbug.com/127520
-}
-
-void NativeTextfieldViews::HandleFocus() {
- GetRenderText()->set_focused(true);
- is_cursor_visible_ = true;
- SchedulePaint();
- GetInputMethod()->OnFocus();
- OnCaretBoundsChanged();
-
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- if (caret_blink_ms != 0) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&NativeTextfieldViews::UpdateCursor,
- cursor_timer_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(caret_blink_ms));
- }
-}
-
-void NativeTextfieldViews::HandleBlur() {
- GetRenderText()->set_focused(false);
- GetInputMethod()->OnBlur();
- // Stop blinking cursor.
- cursor_timer_.InvalidateWeakPtrs();
- if (is_cursor_visible_) {
- is_cursor_visible_ = false;
- RepaintCursor();
- }
-
- touch_selection_controller_.reset();
-}
-
-ui::TextInputClient* NativeTextfieldViews::GetTextInputClient() {
- return textfield_->read_only() ? NULL : this;
-}
-
-void NativeTextfieldViews::ClearEditHistory() {
- model_->ClearEditHistory();
-}
-
-int NativeTextfieldViews::GetFontHeight() {
- return GetRenderText()->font_list().GetHeight();
-}
-
-int NativeTextfieldViews::GetTextfieldBaseline() const {
- return GetRenderText()->GetBaseline();
-}
-
-int NativeTextfieldViews::GetWidthNeededForText() const {
- return GetRenderText()->GetContentWidth() + GetInsets().width();
-}
-
-void NativeTextfieldViews::ExecuteTextCommand(int command_id) {
- ExecuteCommand(command_id, 0);
-}
-
-bool NativeTextfieldViews::HasTextBeingDragged() {
- return initiating_drag_;
-}
-
-gfx::Point NativeTextfieldViews::GetContextMenuLocation() {
- return GetCaretBounds().bottom_right();
-}
-
-/////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
-
-bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
- return true;
-}
-
-bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
- TextfieldController* controller = textfield_->GetController();
- if (controller && controller->HandlesCommand(command_id))
- return controller->IsCommandIdEnabled(command_id);
-
- bool editable = !textfield_->read_only();
- string16 result;
- switch (command_id) {
- case IDS_APP_UNDO:
- return editable && model_->CanUndo();
- case IDS_APP_CUT:
- return editable && model_->HasSelection() && !textfield_->IsObscured();
- case IDS_APP_COPY:
- return model_->HasSelection() && !textfield_->IsObscured();
- case IDS_APP_PASTE:
- ui::Clipboard::GetForCurrentThread()->ReadText(
- ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
- return editable && !result.empty();
- case IDS_APP_DELETE:
- return editable && model_->HasSelection();
- case IDS_APP_SELECT_ALL:
- return !model_->GetText().empty();
- default:
- return controller->IsCommandIdEnabled(command_id);
- }
-}
-
-bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) {
- return false;
-}
-
-bool NativeTextfieldViews::IsItemForCommandIdDynamic(int command_id) const {
- const TextfieldController* controller = textfield_->GetController();
- return controller && controller->IsItemForCommandIdDynamic(command_id);
-}
-
-string16 NativeTextfieldViews::GetLabelForCommandId(int command_id) const {
- const TextfieldController* controller = textfield_->GetController();
- return controller ? controller->GetLabelForCommandId(command_id) : string16();
-}
-
-void NativeTextfieldViews::ExecuteCommand(int command_id, int event_flags) {
- touch_selection_controller_.reset();
- if (!IsCommandIdEnabled(command_id))
- return;
-
- TextfieldController* controller = textfield_->GetController();
- if (controller && controller->HandlesCommand(command_id)) {
- controller->ExecuteCommand(command_id, 0);
- } else {
- bool text_changed = false;
- switch (command_id) {
- case IDS_APP_UNDO:
- OnBeforeUserAction();
- text_changed = model_->Undo();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_CUT:
- OnBeforeUserAction();
- text_changed = Cut();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_COPY:
- OnBeforeUserAction();
- Copy();
- OnAfterUserAction();
- break;
- case IDS_APP_PASTE:
- OnBeforeUserAction();
- text_changed = Paste();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_DELETE:
- OnBeforeUserAction();
- text_changed = model_->Delete();
- UpdateAfterChange(text_changed, text_changed);
- OnAfterUserAction();
- break;
- case IDS_APP_SELECT_ALL:
- OnBeforeUserAction();
- SelectAll(false);
- UpdateAfterChange(false, true);
- OnAfterUserAction();
- break;
- default:
- controller->ExecuteCommand(command_id, 0);
- break;
- }
- }
-}
-
-void NativeTextfieldViews::SetColor(SkColor value) {
- GetRenderText()->SetColor(value);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ApplyColor(SkColor value, const gfx::Range& range) {
- GetRenderText()->ApplyColor(value, range);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::SetStyle(gfx::TextStyle style, bool value) {
- GetRenderText()->SetStyle(style, value);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) {
- GetRenderText()->ApplyStyle(style, value, range);
- SchedulePaint();
-}
-
-void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
- // Set the RenderText display area.
- gfx::Insets insets = GetInsets();
- gfx::Rect display_rect(insets.left(),
- insets.top(),
- width() - insets.width(),
- height() - insets.height());
- GetRenderText()->SetDisplayRect(display_rect);
- OnCaretBoundsChanged();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldViews, ui::TextInputClient implementation, private:
-
-void NativeTextfieldViews::SetCompositionText(
- const ui::CompositionText& composition) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->SetCompositionText(composition);
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::ConfirmCompositionText() {
- if (!model_->HasCompositionText())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->ConfirmCompositionText();
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::ClearCompositionText() {
- if (!model_->HasCompositionText())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- model_->CancelCompositionText();
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::InsertText(const string16& text) {
- // TODO(suzhe): Filter invalid characters.
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
- return;
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- if (GetRenderText()->insert_mode())
- model_->InsertText(GetTextForDisplay(text));
- else
- model_->ReplaceText(GetTextForDisplay(text));
- skip_input_method_cancel_composition_ = false;
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-}
-
-void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
- !ShouldInsertChar(ch, flags)) {
- return;
- }
-
- OnBeforeUserAction();
- skip_input_method_cancel_composition_ = true;
- if (GetRenderText()->insert_mode())
- model_->InsertChar(ch);
- else
- model_->ReplaceChar(ch);
- skip_input_method_cancel_composition_ = false;
-
- model_->SetText(GetTextForDisplay(GetText()));
-
- UpdateAfterChange(true, true);
- OnAfterUserAction();
-
- if (textfield_->IsObscured()) {
- const base::TimeDelta& reveal_duration =
- textfield_->obscured_reveal_duration();
- if (reveal_duration != base::TimeDelta()) {
- const size_t change_offset = model_->GetCursorPosition();
- DCHECK_GT(change_offset, 0u);
- RevealObscuredChar(change_offset - 1, reveal_duration);
- }
- }
-}
-
-gfx::NativeWindow NativeTextfieldViews::GetAttachedWindow() const {
- // Imagine the following hierarchy.
- // [NativeWidget A] - FocusManager
- // [View]
- // [NativeWidget B]
- // [View]
- // [View X]
- // An important thing is that [NativeWidget A] owns Win32 input focus even
- // when [View X] is logically focused by FocusManager. As a result, an Win32
- // IME may want to interact with the native view of [NativeWidget A] rather
- // than that of [NativeWidget B]. This is why we need to call
- // GetTopLevelWidget() here.
- return GetWidget()->GetTopLevelWidget()->GetNativeView();
-}
-
-ui::TextInputType NativeTextfieldViews::GetTextInputType() const {
- return textfield_->GetTextInputType();
-}
-
-ui::TextInputMode NativeTextfieldViews::GetTextInputMode() const {
- return ui::TEXT_INPUT_MODE_DEFAULT;
-}
-
-bool NativeTextfieldViews::CanComposeInline() const {
- return true;
-}
-
-gfx::Rect NativeTextfieldViews::GetCaretBounds() const {
- // TextInputClient::GetCaretBounds is expected to return a value in screen
- // coordinates.
- gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
- ConvertRectToScreen(this, &rect);
- return rect;
-}
-
-bool NativeTextfieldViews::GetCompositionCharacterBounds(
- uint32 index,
- gfx::Rect* rect) const {
- DCHECK(rect);
- if (!HasCompositionText())
- return false;
- const gfx::Range& composition_range = GetRenderText()->GetCompositionRange();
- DCHECK(!composition_range.is_empty());
-
- size_t text_index = composition_range.start() + index;
- if (composition_range.end() <= text_index)
- return false;
- if (!GetRenderText()->IsCursorablePosition(text_index)) {
- text_index = GetRenderText()->IndexOfAdjacentGrapheme(
- text_index, gfx::CURSOR_BACKWARD);
- }
- if (text_index < composition_range.start())
- return false;
- const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
- *rect = GetRenderText()->GetCursorBounds(caret, false);
- ConvertRectToScreen(this, rect);
-
- return true;
-}
-
-bool NativeTextfieldViews::HasCompositionText() const {
- return model_->HasCompositionText();
-}
-
-bool NativeTextfieldViews::GetTextRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
-
- model_->GetTextRange(range);
- return true;
-}
-
-bool NativeTextfieldViews::GetCompositionTextRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
-
- model_->GetCompositionTextRange(range);
- return true;
-}
-
-bool NativeTextfieldViews::GetSelectionRange(gfx::Range* range) const {
- if (!ImeEditingAllowed())
- return false;
- *range = GetSelectedRange();
- return true;
-}
-
-bool NativeTextfieldViews::SetSelectionRange(const gfx::Range& range) {
- if (!ImeEditingAllowed() || !range.IsValid())
- return false;
-
- OnBeforeUserAction();
- SelectRange(range);
- OnAfterUserAction();
- return true;
-}
-
-bool NativeTextfieldViews::DeleteRange(const gfx::Range& range) {
- if (!ImeEditingAllowed() || range.is_empty())
- return false;
-
- OnBeforeUserAction();
- model_->SelectRange(range);
- if (model_->HasSelection()) {
- model_->DeleteSelection();
- UpdateAfterChange(true, true);
- }
- OnAfterUserAction();
- return true;
-}
-
-bool NativeTextfieldViews::GetTextFromRange(
- const gfx::Range& range,
- string16* text) const {
- if (!ImeEditingAllowed() || !range.IsValid())
- return false;
-
- gfx::Range text_range;
- if (!GetTextRange(&text_range) || !text_range.Contains(range))
- return false;
-
- *text = model_->GetTextFromRange(range);
- return true;
-}
-
-void NativeTextfieldViews::OnInputMethodChanged() {
- // TODO(msw): NOTIMPLEMENTED(); see http://crbug.com/140402
-}
-
-bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) {
- // Restore text directionality mode when the indicated direction matches the
- // current forced mode; otherwise, force the mode indicated. This helps users
- // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
- const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
- gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
- if (mode == GetRenderText()->directionality_mode())
- GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
- else
- GetRenderText()->SetDirectionalityMode(mode);
- SchedulePaint();
- return true;
-}
-
-void NativeTextfieldViews::ExtendSelectionAndDelete(
- size_t before,
- size_t after) {
- gfx::Range range = GetSelectedRange();
- DCHECK_GE(range.start(), before);
-
- range.set_start(range.start() - before);
- range.set_end(range.end() + after);
- gfx::Range text_range;
- if (GetTextRange(&text_range) && text_range.Contains(range))
- DeleteRange(range);
-}
-
-void NativeTextfieldViews::EnsureCaretInRect(const gfx::Rect& rect) {
-}
-
-void NativeTextfieldViews::OnCandidateWindowShown() {
-}
-
-void NativeTextfieldViews::OnCandidateWindowUpdated() {
-}
-
-void NativeTextfieldViews::OnCandidateWindowHidden() {
-}
-
-void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
- if (skip_input_method_cancel_composition_)
- return;
- DCHECK(textfield_->GetInputMethod());
- textfield_->GetInputMethod()->CancelComposition(textfield_);
-}
-
-gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
- return model_->render_text();
-}
-
-string16 NativeTextfieldViews::GetTextForDisplay(const string16& text) {
- return textfield_->style() & Textfield::STYLE_LOWERCASE ?
- base::i18n::ToLower(text) : text;
-}
-
-void NativeTextfieldViews::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
- UpdateTextColor();
- UpdateBackgroundColor();
- gfx::RenderText* render_text = GetRenderText();
- render_text->set_cursor_color(textfield_->GetTextColor());
- render_text->set_selection_color(theme->GetSystemColor(
- ui::NativeTheme::kColorId_TextfieldSelectionColor));
- render_text->set_selection_background_focused_color(theme->GetSystemColor(
- ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused));
-}
-
-void NativeTextfieldViews::UpdateCursor() {
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- is_cursor_visible_ = !is_cursor_visible_ || (caret_blink_ms == 0);
- RepaintCursor();
- if (caret_blink_ms != 0) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&NativeTextfieldViews::UpdateCursor,
- cursor_timer_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(caret_blink_ms));
- }
-}
-
-void NativeTextfieldViews::RepaintCursor() {
- gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
- r.Inset(-1, -1, -1, -1);
- SchedulePaintInRect(r);
-}
-
-void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
- TRACE_EVENT0("views", "NativeTextfieldViews::PaintTextAndCursor");
- canvas->Save();
- GetRenderText()->set_cursor_visible(!is_drop_cursor_visible_ &&
- is_cursor_visible_ && !model_->HasSelection());
- // Draw the text, cursor, and selection.
- GetRenderText()->Draw(canvas);
-
- // Draw the detached drop cursor that marks where the text will be dropped.
- if (is_drop_cursor_visible_)
- GetRenderText()->DrawCursor(canvas, drop_cursor_position_);
-
- // Draw placeholder text if needed.
- if (model_->GetText().empty() &&
- !textfield_->GetPlaceholderText().empty()) {
- canvas->DrawStringInt(
- textfield_->GetPlaceholderText(),
- GetRenderText()->GetPrimaryFont(),
- textfield_->placeholder_text_color(),
- GetRenderText()->display_rect());
- }
- canvas->Restore();
-}
-
-bool NativeTextfieldViews::HandleKeyEvent(const ui::KeyEvent& key_event) {
- // TODO(oshima): Refactor and consolidate with ExecuteCommand.
- if (key_event.type() == ui::ET_KEY_PRESSED) {
- ui::KeyboardCode key_code = key_event.key_code();
- if (key_code == ui::VKEY_TAB || key_event.IsUnicodeKeyCode())
- return false;
-
- OnBeforeUserAction();
- const bool editable = !textfield_->read_only();
- const bool readable = !textfield_->IsObscured();
- const bool shift = key_event.IsShiftDown();
- const bool control = key_event.IsControlDown();
- const bool alt = key_event.IsAltDown() || key_event.IsAltGrDown();
- bool text_changed = false;
- bool cursor_changed = false;
- switch (key_code) {
- case ui::VKEY_Z:
- if (control && !shift && !alt && editable)
- cursor_changed = text_changed = model_->Undo();
- else if (control && shift && !alt && editable)
- cursor_changed = text_changed = model_->Redo();
- break;
- case ui::VKEY_Y:
- if (control && !alt && editable)
- cursor_changed = text_changed = model_->Redo();
- break;
- case ui::VKEY_A:
- if (control && !alt) {
- model_->SelectAll(false);
- cursor_changed = true;
- }
- break;
- case ui::VKEY_X:
- if (control && !alt && editable && readable)
- cursor_changed = text_changed = Cut();
- break;
- case ui::VKEY_C:
- if (control && !alt && readable)
- Copy();
- break;
- case ui::VKEY_V:
- if (control && !alt && editable)
- cursor_changed = text_changed = Paste();
- break;
- case ui::VKEY_RIGHT:
- case ui::VKEY_LEFT: {
- // We should ignore the alt-left/right keys because alt key doesn't make
- // any special effects for them and they can be shortcut keys such like
- // forward/back of the browser history.
- if (alt)
- break;
- const gfx::Range selection_range = GetSelectedRange();
- model_->MoveCursor(
- control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK,
- (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT,
- shift);
- cursor_changed = GetSelectedRange() != selection_range;
- break;
- }
- case ui::VKEY_END:
- case ui::VKEY_HOME:
- if ((key_code == ui::VKEY_HOME) ==
- (GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT))
- model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift);
- else
- model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift);
- cursor_changed = true;
- break;
- case ui::VKEY_BACK:
- case ui::VKEY_DELETE:
- if (!editable)
- break;
- if (!model_->HasSelection()) {
- gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ?
- gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
- if (shift && control) {
- // If both shift and control are pressed, then erase up to the
- // beginning/end of the buffer in ChromeOS. In windows, do nothing.
-#if defined(OS_WIN)
- break;
-#else
- model_->MoveCursor(gfx::LINE_BREAK, direction, true);
-#endif
- } else if (control) {
- // If only control is pressed, then erase the previous/next word.
- model_->MoveCursor(gfx::WORD_BREAK, direction, true);
- }
- }
- if (key_code == ui::VKEY_BACK)
- model_->Backspace();
- else if (shift && model_->HasSelection() && readable)
- Cut();
- else
- model_->Delete();
-
- // Consume backspace and delete keys even if the edit did nothing. This
- // prevents potential unintended side-effects of further event handling.
- text_changed = true;
- break;
- case ui::VKEY_INSERT:
- if (control && !shift && readable)
- Copy();
- else if (shift && !control && editable)
- cursor_changed = text_changed = Paste();
- break;
- default:
- break;
- }
-
- // We must have input method in order to support text input.
- DCHECK(textfield_->GetInputMethod());
-
- UpdateAfterChange(text_changed, cursor_changed);
- OnAfterUserAction();
- return (text_changed || cursor_changed);
- }
- return false;
-}
-
-bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
- if (!model_->MoveCursorTo(point, select))
- return false;
- OnCaretBoundsChanged();
- return true;
-}
-
-void NativeTextfieldViews::PropagateTextChange() {
- textfield_->SyncText();
-}
-
-void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
- bool cursor_changed) {
- if (text_changed) {
- PropagateTextChange();
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
- }
- if (cursor_changed) {
- is_cursor_visible_ = true;
- RepaintCursor();
- if (!text_changed) {
- // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
- // this if only the selection changed.
- textfield_->NotifyAccessibilityEvent(
- ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
- }
- }
- if (text_changed || cursor_changed) {
- OnCaretBoundsChanged();
- SchedulePaint();
- }
-}
-
-void NativeTextfieldViews::UpdateContextMenu() {
- if (!context_menu_contents_.get()) {
- context_menu_contents_.reset(new ui::SimpleMenuModel(this));
- context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
- context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
- context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
- context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
- context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
- IDS_APP_SELECT_ALL);
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->UpdateContextMenu(context_menu_contents_.get());
-
- context_menu_delegate_.reset(
- new views::MenuModelAdapter(context_menu_contents_.get()));
- context_menu_runner_.reset(
- new MenuRunner(new views::MenuItemView(context_menu_delegate_.get())));
- }
-
- context_menu_delegate_->BuildMenu(context_menu_runner_->GetMenu());
-}
-
-void NativeTextfieldViews::OnTextInputTypeChanged() {
- // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
- if (textfield_->GetInputMethod())
- textfield_->GetInputMethod()->OnTextInputTypeChanged(textfield_);
-}
-
-void NativeTextfieldViews::OnCaretBoundsChanged() {
- // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
- if (textfield_->GetInputMethod())
- textfield_->GetInputMethod()->OnCaretBoundsChanged(textfield_);
-
- // Notify selection controller
- if (touch_selection_controller_.get())
- touch_selection_controller_->SelectionChanged();
-}
-
-void NativeTextfieldViews::OnBeforeUserAction() {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnBeforeUserAction(textfield_);
-}
-
-void NativeTextfieldViews::OnAfterUserAction() {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterUserAction(textfield_);
-}
-
-bool NativeTextfieldViews::Cut() {
- if (!textfield_->read_only() && !textfield_->IsObscured() && model_->Cut()) {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterCutOrCopy();
- return true;
- }
- return false;
-}
-
-bool NativeTextfieldViews::Copy() {
- if (!textfield_->IsObscured() && model_->Copy()) {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterCutOrCopy();
- return true;
- }
- return false;
-}
-
-bool NativeTextfieldViews::Paste() {
- if (textfield_->read_only())
- return false;
-
- const string16 original_text = GetText();
- const bool success = model_->Paste();
-
- if (success) {
- // As Paste is handled in model_->Paste(), the RenderText may contain
- // upper case characters. This is not consistent with other places
- // which keeps RenderText only containing lower case characters.
- string16 new_text = GetTextForDisplay(GetText());
- model_->SetText(new_text);
-
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->OnAfterPaste();
- }
- return success;
-}
-
-void NativeTextfieldViews::TrackMouseClicks(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton()) {
- base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
- if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
- !ExceededDragThresholdFromLastClickLocation(event)) {
- // 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.
- aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
- } else {
- aggregated_clicks_ = 0;
- }
- last_click_time_ = event.time_stamp();
- last_click_location_ = event.location();
- }
-}
-
-void NativeTextfieldViews::HandleMousePressEvent(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())
- textfield_->RequestFocus();
-
- if (!event.IsOnlyLeftMouseButton())
- return;
-
- initiating_drag_ = false;
- bool can_drag = true;
-
- switch (aggregated_clicks_) {
- case 0:
- if (can_drag && GetRenderText()->IsPointInSelection(event.location()))
- initiating_drag_ = true;
- else
- MoveCursorTo(event.location(), event.IsShiftDown());
- break;
- case 1:
- MoveCursorTo(event.location(), false);
- model_->SelectWord();
- double_click_word_ = GetRenderText()->selection();
- OnCaretBoundsChanged();
- break;
- case 2:
- model_->SelectAll(false);
- OnCaretBoundsChanged();
- break;
- default:
- NOTREACHED();
- }
- SchedulePaint();
-}
-
-bool NativeTextfieldViews::ImeEditingAllowed() const {
- // We don't allow the input method to retrieve or delete content from a
- // password field.
- ui::TextInputType t = GetTextInputType();
- return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
-}
-
-// static
-bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) {
- // Filter out all control characters, including tab and new line characters,
- // and all characters with Alt modifier. But we need to allow characters with
- // AltGr modifier.
- // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
- // flag that we don't care about.
- return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
- (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
-}
-
-void NativeTextfieldViews::CreateTouchSelectionControllerAndNotifyIt() {
- if (!touch_selection_controller_) {
- touch_selection_controller_.reset(
- ui::TouchSelectionController::create(this));
- }
- if (touch_selection_controller_)
- touch_selection_controller_->SelectionChanged();
-}
-
-void NativeTextfieldViews::PlatformGestureEventHandling(
- const ui::GestureEvent* event) {
-#if defined(OS_WIN) && defined(USE_AURA)
- if (event->type() == ui::ET_GESTURE_TAP && !textfield_->read_only())
- base::win::DisplayVirtualKeyboard();
-#endif
-}
-
-void NativeTextfieldViews::RevealObscuredChar(int index,
- const base::TimeDelta& duration) {
- GetRenderText()->SetObscuredRevealIndex(index);
- SchedulePaint();
-
- if (index != -1) {
- obscured_reveal_timer_.Start(
- FROM_HERE,
- duration,
- base::Bind(&NativeTextfieldViews::RevealObscuredChar,
- base::Unretained(this), -1, base::TimeDelta()));
- }
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views.h b/chromium/ui/views/controls/textfield/native_textfield_views.h
deleted file mode 100644
index e85f44dd1b6..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_views.h
+++ /dev/null
@@ -1,345 +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_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "base/timer/timer.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/models/simple_menu_model.h"
-#include "ui/base/touch/touch_editing_controller.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/font.h"
-#include "ui/views/border.h"
-#include "ui/views/context_menu_controller.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/drag_controller.h"
-#include "ui/views/view.h"
-
-namespace base {
-class Time;
-}
-
-namespace gfx {
-class Canvas;
-}
-
-namespace views {
-
-class FocusableBorder;
-class MenuModelAdapter;
-class MenuRunner;
-
-// A views/skia only implementation of NativeTextfieldWrapper.
-// No platform specific code is used.
-// Following features are not yet supported.
-// * BIDI/Complex script.
-// * Support surrogate pair, or maybe we should just use UTF32 internally.
-// * X selection (only if we want to support).
-// Once completed, this will replace Textfield, NativeTextfieldWin and
-// NativeTextfieldGtk.
-class VIEWS_EXPORT NativeTextfieldViews : public View,
- public ui::TouchEditable,
- public ContextMenuController,
- public DragController,
- public NativeTextfieldWrapper,
- public ui::TextInputClient,
- public TextfieldViewsModel::Delegate {
- public:
- explicit NativeTextfieldViews(Textfield* parent);
- virtual ~NativeTextfieldViews();
-
- // View overrides:
- virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
- virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
- virtual bool GetDropFormats(
- int* formats,
- std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
- virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE;
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
- virtual void OnDragExited() OVERRIDE;
- virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
- virtual void OnDragDone() OVERRIDE;
- virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
- virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
-
- // ui::TouchEditable overrides:
- virtual void SelectRect(const gfx::Point& start,
- const gfx::Point& end) OVERRIDE;
- virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
- virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
- virtual gfx::Rect GetBounds() OVERRIDE;
- virtual gfx::NativeView GetNativeView() OVERRIDE;
- virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
- virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
- virtual bool DrawsHandles() OVERRIDE;
- virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE;
-
- // ContextMenuController overrides:
- virtual void ShowContextMenuForView(View* source,
- const gfx::Point& point,
- ui::MenuSourceType source_type) OVERRIDE;
-
- // Overridden from DragController:
- virtual void WriteDragDataForView(View* sender,
- const gfx::Point& press_pt,
- ui::OSExchangeData* data) OVERRIDE;
- virtual int GetDragOperationsForView(View* sender,
- const gfx::Point& p) OVERRIDE;
- virtual bool CanStartDragForView(View* sender,
- const gfx::Point& press_pt,
- const gfx::Point& p) OVERRIDE;
-
- // NativeTextfieldWrapper overrides:
- virtual string16 GetText() const OVERRIDE;
- virtual void UpdateText() OVERRIDE;
- virtual void AppendText(const string16& text) OVERRIDE;
- virtual void InsertOrReplaceText(const string16& text) OVERRIDE;
- virtual base::i18n::TextDirection GetTextDirection() const OVERRIDE;
- virtual string16 GetSelectedText() const OVERRIDE;
- virtual void SelectAll(bool reversed) OVERRIDE;
- virtual void ClearSelection() OVERRIDE;
- virtual void UpdateBorder() OVERRIDE;
- virtual void UpdateTextColor() OVERRIDE;
- virtual void UpdateBackgroundColor() OVERRIDE;
- virtual void UpdateReadOnly() OVERRIDE;
- virtual void UpdateFont() OVERRIDE;
- virtual void UpdateIsObscured() OVERRIDE;
- virtual void UpdateEnabled() OVERRIDE;
- virtual gfx::Insets CalculateInsets() OVERRIDE;
- virtual void UpdateHorizontalMargins() OVERRIDE;
- virtual void UpdateVerticalMargins() OVERRIDE;
- virtual bool SetFocus() OVERRIDE;
- virtual View* GetView() OVERRIDE;
- virtual gfx::NativeView GetTestingHandle() const OVERRIDE;
- virtual bool IsIMEComposing() const OVERRIDE;
- virtual gfx::Range GetSelectedRange() const OVERRIDE;
- virtual void SelectRange(const gfx::Range& range) OVERRIDE;
- virtual gfx::SelectionModel GetSelectionModel() const OVERRIDE;
- virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE;
- virtual size_t GetCursorPosition() const OVERRIDE;
- virtual bool GetCursorEnabled() const OVERRIDE;
- virtual void SetCursorEnabled(bool enabled) OVERRIDE;
- virtual bool HandleKeyPressed(const ui::KeyEvent& e) OVERRIDE;
- virtual bool HandleKeyReleased(const ui::KeyEvent& e) OVERRIDE;
- virtual void HandleFocus() OVERRIDE;
- virtual void HandleBlur() OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- virtual void SetColor(SkColor value) OVERRIDE;
- virtual void ApplyColor(SkColor value, const gfx::Range& range) OVERRIDE;
- virtual void SetStyle(gfx::TextStyle style, bool value) OVERRIDE;
- virtual void ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) OVERRIDE;
- virtual void ClearEditHistory() OVERRIDE;
- virtual int GetFontHeight() OVERRIDE;
- virtual int GetTextfieldBaseline() const OVERRIDE;
- virtual int GetWidthNeededForText() const OVERRIDE;
- virtual void ExecuteTextCommand(int command_id) OVERRIDE;
- virtual bool HasTextBeingDragged() OVERRIDE;
- virtual gfx::Point GetContextMenuLocation() OVERRIDE;
-
- // ui::SimpleMenuModel::Delegate overrides
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
- virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
- virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
-
- // class name of internal
- static const char kViewClassName[];
-
- protected:
- // View override.
- virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
-
- private:
- friend class NativeTextfieldViewsTest;
- friend class TouchSelectionControllerImplTest;
-
- // Overridden from ui::TextInputClient:
- virtual void SetCompositionText(
- const ui::CompositionText& composition) OVERRIDE;
- virtual void ConfirmCompositionText() OVERRIDE;
- virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
- virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
- virtual ui::TextInputType GetTextInputType() const OVERRIDE;
- virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
- virtual bool CanComposeInline() const OVERRIDE;
- virtual gfx::Rect GetCaretBounds() const OVERRIDE;
- virtual bool GetCompositionCharacterBounds(uint32 index,
- gfx::Rect* rect) const OVERRIDE;
- virtual bool HasCompositionText() const OVERRIDE;
- virtual bool GetTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE;
- virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
- virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
- virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
- virtual void OnInputMethodChanged() OVERRIDE;
- virtual bool ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) OVERRIDE;
- virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE;
- virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE;
- virtual void OnCandidateWindowShown() OVERRIDE;
- virtual void OnCandidateWindowUpdated() OVERRIDE;
- virtual void OnCandidateWindowHidden() OVERRIDE;
-
- // Overridden from TextfieldViewsModel::Delegate:
- virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE;
-
- // Returns the TextfieldViewsModel's text/cursor/selection rendering model.
- gfx::RenderText* GetRenderText() const;
-
- // Converts |text| according to textfield style, e.g. lower case if
- // |textfield_| has STYLE_LOWERCASE style.
- string16 GetTextForDisplay(const string16& text);
-
- // Updates any colors that have not been explicitly set from the theme.
- void UpdateColorsFromTheme(const ui::NativeTheme* theme);
-
- // A callback function to periodically update the cursor state.
- void UpdateCursor();
-
- // Repaint the cursor.
- void RepaintCursor();
-
- // Update the cursor_bounds and text_offset.
- void UpdateCursorBoundsAndTextOffset(size_t cursor_pos, bool insert_mode);
-
- void PaintTextAndCursor(gfx::Canvas* canvas);
-
- // Handle the keyevent.
- bool HandleKeyEvent(const ui::KeyEvent& key_event);
-
- // Helper function to call MoveCursorTo on the TextfieldViewsModel.
- bool MoveCursorTo(const gfx::Point& point, bool select);
-
- // Utility function to inform the parent textfield (and its controller if any)
- // that the text in the textfield has changed.
- void PropagateTextChange();
-
- // Does necessary updates when the text and/or the position of the cursor
- // changed.
- void UpdateAfterChange(bool text_changed, bool cursor_changed);
-
- // Utility function to prepare the context menu.
- void UpdateContextMenu();
-
- // Convenience method to call InputMethod::OnTextInputTypeChanged();
- void OnTextInputTypeChanged();
-
- // Convenience method to call InputMethod::OnCaretBoundsChanged();
- void OnCaretBoundsChanged();
-
- // Convenience method to call TextfieldController::OnBeforeUserAction();
- void OnBeforeUserAction();
-
- // Convenience method to call TextfieldController::OnAfterUserAction();
- void OnAfterUserAction();
-
- // Calls |model_->Cut()| and notifies TextfieldController on success.
- bool Cut();
-
- // Calls |model_->Copy()| and notifies TextfieldController on success.
- bool Copy();
-
- // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged()
- // explicitly if paste succeeded.
- bool Paste();
-
- // Tracks the mouse clicks for single/double/triple clicks.
- void TrackMouseClicks(const ui::MouseEvent& event);
-
- // Handles mouse press events.
- void HandleMousePressEvent(const ui::MouseEvent& event);
-
- // Returns true if the current text input type allows access by the IME.
- bool ImeEditingAllowed() const;
-
- // Returns true if distance between |event| and |last_click_location_|
- // exceeds the drag threshold.
- bool ExceededDragThresholdFromLastClickLocation(const ui::MouseEvent& event);
-
- // Checks if a char is ok to be inserted into the textfield. The |ch| is a
- // modified character, i.e., modifiers took effect when generating this char.
- static bool ShouldInsertChar(char16 ch, int flags);
-
- void CreateTouchSelectionControllerAndNotifyIt();
-
- // Platform specific gesture event handling.
- void PlatformGestureEventHandling(const ui::GestureEvent* event);
-
- // Reveals the obscured char at |index| for the given |duration|. If |index|
- // is -1, existing revealed index will be cleared.
- void RevealObscuredChar(int index, const base::TimeDelta& duration);
-
- // The parent textfield, the owner of this object.
- Textfield* textfield_;
-
- // The text model.
- scoped_ptr<TextfieldViewsModel> model_;
-
- // The focusable border. This is always non-NULL, but may not actually be
- // drawn. If it is not drawn, then by default it's also zero-sized unless the
- // Textfield has explicitly-set margins.
- FocusableBorder* text_border_;
-
- // The textfield's text and drop cursor visibility.
- bool is_cursor_visible_;
-
- // The drop cursor is a visual cue for where dragged text will be dropped.
- bool is_drop_cursor_visible_;
- // Position of the drop cursor, if it is visible.
- gfx::SelectionModel drop_cursor_position_;
-
- // True if InputMethod::CancelComposition() should not be called.
- bool skip_input_method_cancel_composition_;
-
- // Is the user potentially dragging and dropping from this view?
- bool initiating_drag_;
-
- // A runnable method factory for callback to update the cursor.
- base::WeakPtrFactory<NativeTextfieldViews> cursor_timer_;
-
- // State variables used to track double and triple clicks.
- size_t aggregated_clicks_;
- base::TimeDelta last_click_time_;
- gfx::Point last_click_location_;
- gfx::Range double_click_word_;
-
- // Context menu and its content list for the textfield.
- scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
- scoped_ptr<views::MenuModelAdapter> context_menu_delegate_;
- scoped_ptr<views::MenuRunner> context_menu_runner_;
-
- scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
-
- // A timer to control the duration of showing the last typed char in
- // obscured text. When the timer is running, the last typed char is shown
- // and when the time expires, the last typed char is obscured.
- base::OneShotTimer<NativeTextfieldViews> obscured_reveal_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViews);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_VIEWS_H_
diff --git a/chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc b/chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc
deleted file mode 100644
index 33196ec3159..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_views_unittest.cc
+++ /dev/null
@@ -1,1992 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/textfield/native_textfield_views.h"
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/pickle.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "grit/ui_strings.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/render_text.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/ime/mock_input_method.h"
-#include "ui/views/test/test_views_delegate.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/native_widget_private.h"
-#include "ui/views/widget/widget.h"
-#include "url/gurl.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
-
-namespace {
-
-const char16 kHebrewLetterSamekh = 0x05E1;
-
-// A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults.
-class TestTextfield : public views::Textfield {
- public:
- explicit TestTextfield(StyleFlags style)
- : Textfield(style),
- key_handled_(false),
- key_received_(false) {
- }
-
- virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
- key_received_ = true;
- key_handled_ = views::Textfield::OnKeyPressed(e);
- return key_handled_;
- }
-
- virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE {
- key_received_ = true;
- key_handled_ = views::Textfield::OnKeyReleased(e);
- return key_handled_;
- }
-
- bool key_handled() const { return key_handled_; }
- bool key_received() const { return key_received_; }
-
- void clear() { key_received_ = key_handled_ = false; }
-
- private:
- bool key_handled_;
- bool key_received_;
-
- DISALLOW_COPY_AND_ASSIGN(TestTextfield);
-};
-
-// A helper class for use with ui::TextInputClient::GetTextFromRange().
-class GetTextHelper {
- public:
- GetTextHelper() {}
-
- void set_text(const string16& text) { text_ = text; }
- const string16& text() const { return text_; }
-
- private:
- string16 text_;
-
- DISALLOW_COPY_AND_ASSIGN(GetTextHelper);
-};
-
-// Convenience to make constructing a GestureEvent simpler.
-class GestureEventForTest : public ui::GestureEvent {
- public:
- GestureEventForTest(ui::EventType type, int x, int y, float delta_x,
- float delta_y)
- : GestureEvent(type, x, y, 0, base::TimeDelta(),
- ui::GestureEventDetails(type, delta_x, delta_y), 0) {
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
-};
-
-} // namespace
-
-namespace views {
-
-// TODO(oshima): Move tests that are independent of TextfieldViews to
-// textfield_unittests.cc once we move the test utility functions
-// from chrome/browser/automation/ to ui/base/test/.
-class NativeTextfieldViewsTest : public ViewsTestBase,
- public TextfieldController {
- public:
- NativeTextfieldViewsTest()
- : widget_(NULL),
- textfield_(NULL),
- textfield_view_(NULL),
- model_(NULL),
- input_method_(NULL),
- on_before_user_action_(0),
- on_after_user_action_(0) {
- }
-
- // ::testing::Test:
- virtual void SetUp() {
- ViewsTestBase::SetUp();
- }
-
- virtual void TearDown() {
- if (widget_)
- widget_->Close();
- ViewsTestBase::TearDown();
- }
-
- // TextfieldController:
- virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE {
- // Paste calls TextfieldController::ContentsChanged() explicitly even if the
- // paste action did not change the content. So |new_contents| may match
- // |last_contents_|. For more info, see http://crbug.com/79002
- last_contents_ = new_contents;
- }
-
- virtual bool HandleKeyEvent(Textfield* sender,
- const ui::KeyEvent& key_event) OVERRIDE {
- // TODO(oshima): figure out how to test the keystroke.
- return false;
- }
-
- virtual void OnBeforeUserAction(Textfield* sender) OVERRIDE {
- ++on_before_user_action_;
- }
-
- virtual void OnAfterUserAction(Textfield* sender) OVERRIDE {
- ++on_after_user_action_;
- }
-
- void InitTextfield(Textfield::StyleFlags style) {
- InitTextfields(style, 1);
- }
-
- void InitTextfields(Textfield::StyleFlags style, int count) {
- ASSERT_FALSE(textfield_);
- textfield_ = new TestTextfield(style);
- textfield_->SetController(this);
- widget_ = new Widget();
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.bounds = gfx::Rect(100, 100, 100, 100);
- widget_->Init(params);
- View* container = new View();
- widget_->SetContentsView(container);
- container->AddChildView(textfield_);
-
- textfield_view_ = static_cast<NativeTextfieldViews*>(
- textfield_->GetNativeWrapperForTesting());
- DCHECK(textfield_view_);
- textfield_view_->SetBoundsRect(params.bounds);
- textfield_->set_id(1);
-
- for (int i = 1; i < count; i++) {
- Textfield* textfield = new Textfield(style);
- container->AddChildView(textfield);
- textfield->set_id(i + 1);
- }
-
- model_ = textfield_view_->model_.get();
- model_->ClearEditHistory();
-
- input_method_ = new MockInputMethod();
- widget_->ReplaceInputMethod(input_method_);
-
- // Activate the widget and focus the textfield for input handling.
- widget_->Activate();
- textfield_->RequestFocus();
- }
-
- ui::MenuModel* GetContextMenuModel() {
- textfield_view_->UpdateContextMenu();
- return textfield_view_->context_menu_contents_.get();
- }
-
- ui::TouchSelectionController* GetTouchSelectionController() {
- return textfield_view_->touch_selection_controller_.get();
- }
-
- protected:
- void SendKeyEvent(ui::KeyboardCode key_code,
- bool alt,
- bool shift,
- bool control,
- bool caps_lock) {
- int flags = (alt ? ui::EF_ALT_DOWN : 0) |
- (shift ? ui::EF_SHIFT_DOWN : 0) |
- (control ? ui::EF_CONTROL_DOWN : 0) |
- (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0);
- ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags, false);
- input_method_->DispatchKeyEvent(event);
- }
-
- void SendKeyEvent(ui::KeyboardCode key_code, bool shift, bool control) {
- SendKeyEvent(key_code, false, shift, control, false);
- }
-
- void SendKeyEvent(ui::KeyboardCode key_code) {
- SendKeyEvent(key_code, false, false);
- }
-
- void SendKeyEvent(char16 ch) {
- if (ch < 0x80) {
- ui::KeyboardCode code =
- ch == ' ' ? ui::VKEY_SPACE :
- static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
- SendKeyEvent(code);
- } else {
- ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false);
- event.set_character(ch);
- input_method_->DispatchKeyEvent(event);
- }
- }
-
- string16 GetClipboardText() const {
- string16 text;
- ui::Clipboard::GetForCurrentThread()->
- ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
- return text;
- }
-
- void SetClipboardText(const std::string& text) {
- ui::ScopedClipboardWriter clipboard_writer(
- ui::Clipboard::GetForCurrentThread(),
- ui::CLIPBOARD_TYPE_COPY_PASTE);
- clipboard_writer.WriteText(ASCIIToUTF16(text));
- }
-
- View* GetFocusedView() {
- return widget_->GetFocusManager()->GetFocusedView();
- }
-
- int GetCursorPositionX(int cursor_pos) {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- return render_text->GetCursorBounds(
- gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x();
- }
-
- // Get the current cursor bounds.
- gfx::Rect GetCursorBounds() {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- gfx::Rect bounds = render_text->GetUpdatedCursorBounds();
- return bounds;
- }
-
- // Get the cursor bounds of |sel|.
- gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- gfx::Rect bounds = render_text->GetCursorBounds(sel, true);
- return bounds;
- }
-
- gfx::Rect GetDisplayRect() {
- return textfield_view_->GetRenderText()->display_rect();
- }
-
- // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
- // y-axis is in the middle of |bound|'s vertical range.
- void MouseClick(const gfx::Rect bound, int x_offset) {
- gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseReleased(release);
- }
-
- // This is to avoid double/triple click.
- void NonClientMouseClick() {
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT);
- textfield_view_->OnMousePressed(click);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT);
- textfield_view_->OnMouseReleased(release);
- }
-
- // Wrap for visibility in test classes.
- ui::TextInputType GetTextInputType() {
- return textfield_view_->GetTextInputType();
- }
-
- void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
- bool can_undo,
- ui::MenuModel* menu) {
- 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 */));
- EXPECT_NE(GetClipboardText().empty(), menu->IsEnabledAt(4 /* PASTE */));
- EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */));
- EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */));
- EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */));
- }
-
- // We need widget to populate wrapper class.
- Widget* widget_;
-
- TestTextfield* textfield_;
- NativeTextfieldViews* textfield_view_;
- TextfieldViewsModel* model_;
-
- // The string from Controller::ContentsChanged callback.
- string16 last_contents_;
-
- // For testing input method related behaviors.
- MockInputMethod* input_method_;
-
- // Indicates how many times OnBeforeUserAction() is called.
- int on_before_user_action_;
-
- // Indicates how many times OnAfterUserAction() is called.
- int on_after_user_action_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViewsTest);
-};
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // TextfieldController::ContentsChanged() shouldn't be called when changing
- // text programmatically.
- last_contents_.clear();
- textfield_->SetText(ASCIIToUTF16("this is"));
-
- EXPECT_STR_EQ("this is", model_->GetText());
- EXPECT_STR_EQ("this is", textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- textfield_->AppendText(ASCIIToUTF16(" a test"));
- EXPECT_STR_EQ("this is a test", model_->GetText());
- EXPECT_STR_EQ("this is a test", textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- EXPECT_EQ(string16(), textfield_->GetSelectedText());
- textfield_->SelectAll(false);
- EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) {
- // Check if |model_|'s text is properly lowercased for STYLE_LOWERCASE.
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- textfield_->SetText(ASCIIToUTF16("THIS IS"));
- EXPECT_EQ(7U, textfield_->GetCursorPosition());
-
- EXPECT_STR_EQ("this is", model_->GetText());
- EXPECT_STR_EQ("THIS IS", textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- textfield_->AppendText(ASCIIToUTF16(" A TEST"));
- EXPECT_EQ(7U, textfield_->GetCursorPosition());
- EXPECT_STR_EQ("this is a test", model_->GetText());
- EXPECT_STR_EQ("THIS IS A TEST", textfield_->text());
-
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) {
- // Check if lower case conversion works for non-ASCII characters.
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- // Zenkaku Japanese "ABCabc"
- textfield_->SetText(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"));
- EXPECT_EQ(6U, textfield_->GetCursorPosition());
- // Zenkaku Japanese "abcabc"
- EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"),
- model_->GetText());
- // Zenkaku Japanese "ABCabc"
- EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"),
- textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- // Zenkaku Japanese "XYZxyz"
- textfield_->AppendText(WideToUTF16(L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"));
- EXPECT_EQ(6U, textfield_->GetCursorPosition());
- // Zenkaku Japanese "abcabcxyzxyz"
- EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"
- L"\xFF58\xFF59\xFF5A\xFF58\xFF59\xFF5A"),
- model_->GetText());
- // Zenkaku Japanese "ABCabcXYZxyz"
- EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"
- L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"),
- textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) {
- // Check if lower case conversion honors locale properly.
- std::string locale = l10n_util::GetApplicationLocale("");
- base::i18n::SetICUDefaultLocale("tr");
-
- InitTextfield(Textfield::STYLE_LOWERCASE);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
-
- last_contents_.clear();
- // Turkish 'I' should be converted to dotless 'i' (U+0131).
- textfield_->SetText(WideToUTF16(L"I"));
- EXPECT_EQ(1U, textfield_->GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"\x0131"), model_->GetText());
- EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-
- base::i18n::SetICUDefaultLocale(locale);
-
- // On default (en) locale, 'I' should be converted to 'i'.
- textfield_->SetText(WideToUTF16(L"I"));
- EXPECT_EQ(1U, textfield_->GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"i"), model_->GetText());
- EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
-}
-
-TEST_F(NativeTextfieldViewsTest, KeyTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- // Event flags: key, alt, shift, ctrl, caps-lock.
- SendKeyEvent(ui::VKEY_T, false, true, false, false);
- SendKeyEvent(ui::VKEY_E, false, false, false, false);
- SendKeyEvent(ui::VKEY_X, false, true, false, true);
- SendKeyEvent(ui::VKEY_T, false, false, false, true);
- SendKeyEvent(ui::VKEY_1, false, true, false, false);
- SendKeyEvent(ui::VKEY_1, false, false, false, false);
- SendKeyEvent(ui::VKEY_1, false, true, false, true);
- SendKeyEvent(ui::VKEY_1, false, false, false, true);
- EXPECT_STR_EQ("TexT!1!1", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) {
- // Insert a test string in a textfield.
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("one two three"));
- SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */);
- SendKeyEvent(ui::VKEY_RIGHT, true, false);
- SendKeyEvent(ui::VKEY_RIGHT, true, false);
- SendKeyEvent(ui::VKEY_RIGHT, true, false);
-
- EXPECT_STR_EQ("one", textfield_->GetSelectedText());
-
- // Test word select.
- SendKeyEvent(ui::VKEY_RIGHT, true, true);
- EXPECT_STR_EQ("one two", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_RIGHT, true, true);
- EXPECT_STR_EQ("one two three", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_LEFT, true, true);
- EXPECT_STR_EQ("one two ", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_LEFT, true, true);
- EXPECT_STR_EQ("one ", textfield_->GetSelectedText());
-
- // Replace the selected text.
- SendKeyEvent(ui::VKEY_Z, true, false);
- SendKeyEvent(ui::VKEY_E, true, false);
- SendKeyEvent(ui::VKEY_R, true, false);
- SendKeyEvent(ui::VKEY_O, true, false);
- SendKeyEvent(ui::VKEY_SPACE, false, false);
- EXPECT_STR_EQ("ZERO two three", textfield_->text());
-
- SendKeyEvent(ui::VKEY_END, true, false);
- EXPECT_STR_EQ("two three", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_HOME, true, false);
- EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
-}
-
-TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) {
- // Insert a test string in a textfield.
- InitTextfield(Textfield::STYLE_DEFAULT);
- for (size_t i = 0; i < 10; i++)
- SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
- EXPECT_STR_EQ("abcdefghij", textfield_->text());
-
- // Test the delete and backspace keys.
- textfield_->SelectRange(gfx::Range(5));
- for (int i = 0; i < 3; i++)
- SendKeyEvent(ui::VKEY_BACK);
- EXPECT_STR_EQ("abfghij", textfield_->text());
- for (int i = 0; i < 3; i++)
- SendKeyEvent(ui::VKEY_DELETE);
- EXPECT_STR_EQ("abij", textfield_->text());
-
- // Select all and replace with "k".
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_K);
- EXPECT_STR_EQ("k", textfield_->text());
-
- // Delete the previous word from cursor.
- textfield_->SetText(ASCIIToUTF16("one two three four"));
- SendKeyEvent(ui::VKEY_END);
- SendKeyEvent(ui::VKEY_BACK, false, false, true, false);
- EXPECT_STR_EQ("one two three ", textfield_->text());
-
- // Delete text preceeding the cursor in chromeos, do nothing in windows.
- SendKeyEvent(ui::VKEY_LEFT, false, false, true, false);
- SendKeyEvent(ui::VKEY_BACK, false, true, true, false);
-#if defined(OS_WIN)
- EXPECT_STR_EQ("one two three ", textfield_->text());
-#else
- EXPECT_STR_EQ("three ", textfield_->text());
-#endif
-
- // Delete the next word from cursor.
- textfield_->SetText(ASCIIToUTF16("one two three four"));
- SendKeyEvent(ui::VKEY_HOME);
- SendKeyEvent(ui::VKEY_DELETE, false, false, true, false);
- EXPECT_STR_EQ(" two three four", textfield_->text());
-
- // Delete text following the cursor in chromeos, do nothing in windows.
- SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false);
- SendKeyEvent(ui::VKEY_DELETE, false, true, true, false);
-#if defined(OS_WIN)
- EXPECT_STR_EQ(" two three four", textfield_->text());
-#else
- EXPECT_STR_EQ(" two", textfield_->text());
-#endif
-}
-
-TEST_F(NativeTextfieldViewsTest, PasswordTest) {
- InitTextfield(Textfield::STYLE_OBSCURED);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
- EXPECT_TRUE(textfield_->enabled());
- EXPECT_TRUE(textfield_->focusable());
-
- last_contents_.clear();
- textfield_->SetText(ASCIIToUTF16("password"));
- // Ensure text() and the callback returns the actual text instead of "*".
- EXPECT_STR_EQ("password", textfield_->text());
- EXPECT_TRUE(last_contents_.empty());
- model_->SelectAll(false);
- SetClipboardText("foo");
-
- // Cut and copy should be disabled.
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
- SendKeyEvent(ui::VKEY_X, false, true);
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
- SendKeyEvent(ui::VKEY_C, false, true);
- SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("foo", string16(GetClipboardText()));
- EXPECT_STR_EQ("password", textfield_->text());
- // [Shift]+[Delete] should just delete without copying text to the clipboard.
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_DELETE, true, false);
-
- // Paste should work normally.
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
- SendKeyEvent(ui::VKEY_V, false, true);
- SendKeyEvent(ui::VKEY_INSERT, true, false);
- EXPECT_STR_EQ("foo", string16(GetClipboardText()));
- EXPECT_STR_EQ("foofoofoo", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, InputTypeSetsObscured) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-
- // Setting to TEXT_INPUT_TYPE_PASSWORD also sets obscured state of textfield.
- textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
- EXPECT_TRUE(textfield_->IsObscured());
-}
-
-TEST_F(NativeTextfieldViewsTest, ObscuredSetsInputType) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-
- textfield_->SetObscured(true);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType());
-
- textfield_->SetObscured(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-}
-
-TEST_F(NativeTextfieldViewsTest, TextInputType) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Defaults to TEXT
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType());
-
- // And can be set.
- textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType());
-
- // Readonly textfields have type NONE
- textfield_->SetReadOnly(true);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType());
-
- textfield_->SetReadOnly(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType());
-
- // As do disabled textfields
- textfield_->SetEnabled(false);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType());
-}
-
-TEST_F(NativeTextfieldViewsTest, OnKeyPressReturnValueTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Character keys will be handled by input method.
- SendKeyEvent(ui::VKEY_A);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- // Home will be handled.
- SendKeyEvent(ui::VKEY_HOME);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_TRUE(textfield_->key_handled());
- textfield_->clear();
-
- // F24, up/down key won't be handled.
- SendKeyEvent(ui::VKEY_F24);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- SendKeyEvent(ui::VKEY_UP);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- SendKeyEvent(ui::VKEY_DOWN);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- // Empty Textfield does not handle left/right.
- textfield_->SetText(string16());
- SendKeyEvent(ui::VKEY_LEFT);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- SendKeyEvent(ui::VKEY_RIGHT);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- // Add a char. Right key should not be handled when cursor is at the end.
- SendKeyEvent(ui::VKEY_B);
- SendKeyEvent(ui::VKEY_RIGHT);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-
- // First left key is handled to move cursor left to the beginning.
- SendKeyEvent(ui::VKEY_LEFT);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_TRUE(textfield_->key_handled());
- textfield_->clear();
-
- // Now left key should not be handled.
- SendKeyEvent(ui::VKEY_LEFT);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- textfield_->clear();
-}
-
-TEST_F(NativeTextfieldViewsTest, CursorMovement) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Test with trailing whitespace.
- textfield_->SetText(ASCIIToUTF16("one two hre "));
-
- // Send the cursor at the end.
- SendKeyEvent(ui::VKEY_END);
-
- // Ctrl+Left should move the cursor just before the last word.
- SendKeyEvent(ui::VKEY_LEFT, false, true);
- SendKeyEvent(ui::VKEY_T);
- EXPECT_STR_EQ("one two thre ", textfield_->text());
- EXPECT_STR_EQ("one two thre ", last_contents_);
-
- // Ctrl+Right should move the cursor to the end of the last word.
- SendKeyEvent(ui::VKEY_RIGHT, false, true);
- SendKeyEvent(ui::VKEY_E);
- EXPECT_STR_EQ("one two three ", textfield_->text());
- EXPECT_STR_EQ("one two three ", last_contents_);
-
- // Ctrl+Right again should move the cursor to the end.
- SendKeyEvent(ui::VKEY_RIGHT, false, true);
- SendKeyEvent(ui::VKEY_BACK);
- EXPECT_STR_EQ("one two three", textfield_->text());
- EXPECT_STR_EQ("one two three", last_contents_);
-
- // Test with leading whitespace.
- textfield_->SetText(ASCIIToUTF16(" ne two"));
-
- // Send the cursor at the beginning.
- SendKeyEvent(ui::VKEY_HOME);
-
- // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the
- // first word.
- SendKeyEvent(ui::VKEY_RIGHT, false, true);
- SendKeyEvent(ui::VKEY_LEFT, false, true);
- SendKeyEvent(ui::VKEY_O);
- EXPECT_STR_EQ(" one two", textfield_->text());
- EXPECT_STR_EQ(" one two", last_contents_);
-
- // Ctrl+Left to move the cursor to the beginning of the first word.
- SendKeyEvent(ui::VKEY_LEFT, false, true);
- // Ctrl+Left again should move the cursor back to the very beginning.
- SendKeyEvent(ui::VKEY_LEFT, false, true);
- SendKeyEvent(ui::VKEY_DELETE);
- EXPECT_STR_EQ("one two", textfield_->text());
- EXPECT_STR_EQ("one two", last_contents_);
-}
-
-TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) {
- InitTextfields(Textfield::STYLE_DEFAULT, 3);
- textfield_->RequestFocus();
-
- EXPECT_EQ(1, GetFocusedView()->id());
- widget_->GetFocusManager()->AdvanceFocus(false);
- EXPECT_EQ(2, GetFocusedView()->id());
- widget_->GetFocusManager()->AdvanceFocus(false);
- EXPECT_EQ(3, GetFocusedView()->id());
- // Cycle back to the first textfield.
- widget_->GetFocusManager()->AdvanceFocus(false);
- EXPECT_EQ(1, GetFocusedView()->id());
-
- widget_->GetFocusManager()->AdvanceFocus(true);
- EXPECT_EQ(3, GetFocusedView()->id());
- widget_->GetFocusManager()->AdvanceFocus(true);
- EXPECT_EQ(2, GetFocusedView()->id());
- widget_->GetFocusManager()->AdvanceFocus(true);
- EXPECT_EQ(1, GetFocusedView()->id());
- // Cycle back to the last textfield.
- widget_->GetFocusManager()->AdvanceFocus(true);
- EXPECT_EQ(3, GetFocusedView()->id());
-
- // Request focus should still work.
- textfield_->RequestFocus();
- EXPECT_EQ(1, GetFocusedView()->id());
-
- // Test if clicking on textfield view sets the focus to textfield_.
- widget_->GetFocusManager()->AdvanceFocus(true);
- EXPECT_EQ(3, GetFocusedView()->id());
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
- EXPECT_EQ(1, GetFocusedView()->id());
-}
-
-TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- EXPECT_TRUE(textfield_->context_menu_controller());
- textfield_->SetText(ASCIIToUTF16("hello world"));
- ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE);
- textfield_view_->ClearEditHistory();
- EXPECT_TRUE(GetContextMenuModel());
- VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel());
-
- textfield_->SelectAll(false);
- VerifyTextfieldContextMenuContents(true, false, GetContextMenuModel());
-
- SendKeyEvent(ui::VKEY_T);
- VerifyTextfieldContextMenuContents(false, true, GetContextMenuModel());
-
- textfield_->SelectAll(false);
- VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
-
- // Exercise the "paste enabled?" check in the verifier.
- SetClipboardText("Test");
- VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
-}
-
-TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent double_click(
- ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK);
-
- // Test for double click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
- EXPECT_TRUE(textfield_->GetSelectedText().empty());
- textfield_view_->OnMousePressed(double_click);
- textfield_view_->OnMouseReleased(release);
- EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
-
- // Test for triple click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
- EXPECT_STR_EQ("hello world", textfield_->GetSelectedText());
-
- // Another click should reset back to double click.
- textfield_view_->OnMousePressed(click);
- textfield_view_->OnMouseReleased(release);
- EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
-}
-
-TEST_F(NativeTextfieldViewsTest, DragToSelect) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
- const int kStart = GetCursorPositionX(5);
- const int kEnd = 500;
- gfx::Point start_point(kStart, 0);
- gfx::Point end_point(kEnd, 0);
- ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(),
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
- EXPECT_TRUE(textfield_->GetSelectedText().empty());
- // Check that dragging left selects the beginning of the string.
- textfield_view_->OnMouseDragged(drag_left);
- string16 text_left = textfield_->GetSelectedText();
- EXPECT_STR_EQ("hello", text_left);
- // Check that dragging right selects the rest of the string.
- textfield_view_->OnMouseDragged(drag_right);
- string16 text_right = textfield_->GetSelectedText();
- EXPECT_STR_EQ(" world", text_right);
- // Check that releasing in the same location does not alter the selection.
- textfield_view_->OnMouseReleased(release);
- EXPECT_EQ(text_right, textfield_->GetSelectedText());
- // Check that dragging from beyond the text length works too.
- textfield_view_->OnMousePressed(click_b);
- textfield_view_->OnMouseDragged(drag_left);
- textfield_view_->OnMouseReleased(release);
- EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
-}
-
-#if defined(OS_WIN)
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
-
- ui::OSExchangeData data;
- string16 string(ASCIIToUTF16("string "));
- data.SetString(string);
- int formats = 0;
- std::set<OSExchangeData::CustomFormat> custom_formats;
-
- // Ensure that disabled textfields do not accept drops.
- textfield_->SetEnabled(false);
- EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
- EXPECT_EQ(0, formats);
- EXPECT_TRUE(custom_formats.empty());
- EXPECT_FALSE(textfield_view_->CanDrop(data));
- textfield_->SetEnabled(true);
-
- // Ensure that read-only textfields do not accept drops.
- textfield_->SetReadOnly(true);
- EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
- EXPECT_EQ(0, formats);
- EXPECT_TRUE(custom_formats.empty());
- EXPECT_FALSE(textfield_view_->CanDrop(data));
- textfield_->SetReadOnly(false);
-
- // Ensure that enabled and editable textfields do accept drops.
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
- EXPECT_EQ(ui::OSExchangeData::STRING, formats);
- EXPECT_TRUE(custom_formats.empty());
- EXPECT_TRUE(textfield_view_->CanDrop(data));
- gfx::Point drop_point(GetCursorPositionX(6), 0);
- ui::DropTargetEvent drop(data, drop_point, drop_point,
- ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop));
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_view_->OnPerformDrop(drop));
- EXPECT_STR_EQ("hello string world", textfield_->text());
-
- // Ensure that textfields do not accept non-OSExchangeData::STRING types.
- ui::OSExchangeData bad_data;
- bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x")));
-#if defined(OS_WIN)
- ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType();
- bad_data.SetPickledData(fmt, Pickle());
- bad_data.SetFileContents(base::FilePath(L"x"), "x");
- bad_data.SetHtml(string16(ASCIIToUTF16("x")), GURL("x.org"));
- ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL);
- bad_data.SetDownloadFileInfo(download);
-#endif
- EXPECT_FALSE(textfield_view_->CanDrop(bad_data));
-}
-#endif
-
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello string world"));
-
- // Ensure the textfield will provide selected text for drag data.
- string16 string;
- ui::OSExchangeData data;
- const gfx::Range kStringRange(6, 12);
- textfield_->SelectRange(kStringRange);
- const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
- textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data);
- EXPECT_TRUE(data.GetString(&string));
- EXPECT_EQ(textfield_->GetSelectedText(), string);
-
- // Ensure that disabled textfields do not support drag operations.
- textfield_->SetEnabled(false);
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- textfield_->SetEnabled(true);
- // Ensure that textfields without selections do not support drag operations.
- textfield_->ClearSelection();
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- textfield_->SelectRange(kStringRange);
- // Ensure that password textfields do not support drag operations.
- textfield_->SetObscured(true);
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- textfield_->SetObscured(false);
- // Ensure that textfields only initiate drag operations inside the selection.
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(press_event);
- EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
- textfield_view_->GetDragOperationsForView(NULL, gfx::Point()));
- EXPECT_FALSE(textfield_view_->CanStartDragForView(NULL, gfx::Point(),
- gfx::Point()));
- EXPECT_EQ(ui::DragDropTypes::DRAG_COPY,
- textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
- EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, kStringPoint,
- gfx::Point()));
- // Ensure that textfields support local moves.
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
- textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint));
-}
-
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
-
- string16 string;
- ui::OSExchangeData data;
- int formats = 0;
- int operations = 0;
- std::set<OSExchangeData::CustomFormat> custom_formats;
-
- // Start dragging "ello".
- textfield_->SelectRange(gfx::Range(1, 5));
- gfx::Point point(GetCursorPositionX(3), 0);
- ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
- click_a.location(), gfx::Point()));
- operations = textfield_view_->GetDragOperationsForView(textfield_view_,
- click_a.location());
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
- operations);
- textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
- EXPECT_TRUE(data.GetString(&string));
- EXPECT_EQ(textfield_->GetSelectedText(), string);
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
- EXPECT_EQ(ui::OSExchangeData::STRING, formats);
- EXPECT_TRUE(custom_formats.empty());
-
- // Drop "ello" after "w".
- const gfx::Point kDropPoint(GetCursorPositionX(7), 0);
- EXPECT_TRUE(textfield_view_->CanDrop(data));
- ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnPerformDrop(drop_a));
- EXPECT_STR_EQ("h welloorld", textfield_->text());
- textfield_view_->OnDragDone();
-
- // Undo/Redo the drag&drop change.
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("hello world", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("hello world", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("h welloorld", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("h welloorld", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
-
- string16 string;
- ui::OSExchangeData data;
- int formats = 0;
- int operations = 0;
- std::set<OSExchangeData::CustomFormat> custom_formats;
-
- // Start dragging " worl".
- textfield_->SelectRange(gfx::Range(5, 10));
- gfx::Point point(GetCursorPositionX(7), 0);
- ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click_a);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
- click_a.location(), gfx::Point()));
- operations = textfield_view_->GetDragOperationsForView(textfield_view_,
- click_a.location());
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
- operations);
- textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
- EXPECT_TRUE(data.GetString(&string));
- EXPECT_EQ(textfield_->GetSelectedText(), string);
- EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
- EXPECT_EQ(ui::OSExchangeData::STRING, formats);
- EXPECT_TRUE(custom_formats.empty());
-
- // Drop " worl" after "h".
- EXPECT_TRUE(textfield_view_->CanDrop(data));
- gfx::Point drop_point(GetCursorPositionX(1), 0);
- ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnDragUpdated(drop_a));
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
- textfield_view_->OnPerformDrop(drop_a));
- EXPECT_STR_EQ("h worlellod", textfield_->text());
- textfield_view_->OnDragDone();
-
- // Undo/Redo the drag&drop change.
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("hello world", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("hello world", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("h worlellod", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("h worlellod", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
-
- // Start dragging "worl".
- textfield_->SelectRange(gfx::Range(6, 10));
- gfx::Point point(GetCursorPositionX(8), 0);
- ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(click);
- ui::OSExchangeData data;
- textfield_view_->WriteDragDataForView(NULL, click.location(), &data);
- EXPECT_TRUE(textfield_view_->CanDrop(data));
- // Drag the text over somewhere valid, outside the current selection.
- gfx::Point drop_point(GetCursorPositionX(2), 0);
- ui::DropTargetEvent drop(data, drop_point, drop_point,
- ui::DragDropTypes::DRAG_MOVE);
- EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_view_->OnDragUpdated(drop));
- // "Cancel" the drag, via move and release over the selection, and OnDragDone.
- gfx::Point drag_point(GetCursorPositionX(9), 0);
- ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseDragged(drag);
- textfield_view_->OnMouseReleased(release);
- textfield_view_->OnDragDone();
- EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("read only"));
- textfield_->SetReadOnly(true);
- EXPECT_TRUE(textfield_->enabled());
- EXPECT_TRUE(textfield_->focusable());
-
- SendKeyEvent(ui::VKEY_HOME);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
- SendKeyEvent(ui::VKEY_END);
- EXPECT_EQ(9U, textfield_->GetCursorPosition());
-
- SendKeyEvent(ui::VKEY_LEFT, false, false);
- EXPECT_EQ(8U, textfield_->GetCursorPosition());
- SendKeyEvent(ui::VKEY_LEFT, false, true);
- EXPECT_EQ(5U, textfield_->GetCursorPosition());
- SendKeyEvent(ui::VKEY_LEFT, true, true);
- EXPECT_EQ(0U, textfield_->GetCursorPosition());
- EXPECT_STR_EQ("read ", textfield_->GetSelectedText());
- textfield_->SelectAll(false);
- EXPECT_STR_EQ("read only", textfield_->GetSelectedText());
-
- // Cut should be disabled.
- SetClipboardText("Test");
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
- SendKeyEvent(ui::VKEY_X, false, true);
- SendKeyEvent(ui::VKEY_DELETE, true, false);
- EXPECT_STR_EQ("Test", string16(GetClipboardText()));
- EXPECT_STR_EQ("read only", textfield_->text());
-
- // Paste should be disabled.
- EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
- SendKeyEvent(ui::VKEY_V, false, true);
- SendKeyEvent(ui::VKEY_INSERT, true, false);
- EXPECT_STR_EQ("read only", textfield_->text());
-
- // Copy should work normally.
- SetClipboardText("Test");
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
- SetClipboardText("Test");
- SendKeyEvent(ui::VKEY_C, false, true);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
- SetClipboardText("Test");
- SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("read only", string16(GetClipboardText()));
-
- // SetText should work even in read only mode.
- textfield_->SetText(ASCIIToUTF16(" four five six "));
- EXPECT_STR_EQ(" four five six ", textfield_->text());
-
- textfield_->SelectAll(false);
- EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
-
- // Text field is unmodifiable and selection shouldn't change.
- SendKeyEvent(ui::VKEY_DELETE);
- EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_BACK);
- EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
- SendKeyEvent(ui::VKEY_T);
- EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
-}
-
-TEST_F(NativeTextfieldViewsTest, TextInputClientTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- ui::TextInputClient* client = textfield_->GetTextInputClient();
- EXPECT_TRUE(client);
- EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType());
-
- textfield_->SetText(ASCIIToUTF16("0123456789"));
- gfx::Range range;
- EXPECT_TRUE(client->GetTextRange(&range));
- EXPECT_EQ(0U, range.start());
- EXPECT_EQ(10U, range.end());
-
- EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4)));
- EXPECT_TRUE(client->GetSelectionRange(&range));
- EXPECT_EQ(gfx::Range(1, 4), range);
-
- // This code can't be compiled because of a bug in base::Callback.
-#if 0
- GetTextHelper helper;
- base::Callback<void(string16)> callback =
- base::Bind(&GetTextHelper::set_text, base::Unretained(&helper));
-
- EXPECT_TRUE(client->GetTextFromRange(range, callback));
- EXPECT_STR_EQ("123", helper.text());
-#endif
-
- EXPECT_TRUE(client->DeleteRange(range));
- EXPECT_STR_EQ("0456789", textfield_->text());
-
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("321");
- // Set composition through input method.
- input_method_->Clear();
- input_method_->SetCompositionTextForNextKey(composition);
- textfield_->clear();
-
- on_before_user_action_ = on_after_user_action_ = 0;
- SendKeyEvent(ui::VKEY_A);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- EXPECT_TRUE(client->HasCompositionText());
- EXPECT_TRUE(client->GetCompositionTextRange(&range));
- EXPECT_STR_EQ("0321456789", textfield_->text());
- EXPECT_EQ(gfx::Range(1, 4), range);
- EXPECT_EQ(2, on_before_user_action_);
- EXPECT_EQ(2, on_after_user_action_);
-
- input_method_->SetResultTextForNextKey(UTF8ToUTF16("123"));
- on_before_user_action_ = on_after_user_action_ = 0;
- textfield_->clear();
- SendKeyEvent(ui::VKEY_A);
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_FALSE(textfield_->key_handled());
- EXPECT_FALSE(client->HasCompositionText());
- EXPECT_FALSE(input_method_->cancel_composition_called());
- EXPECT_STR_EQ("0123456789", textfield_->text());
- EXPECT_EQ(2, on_before_user_action_);
- EXPECT_EQ(2, on_after_user_action_);
-
- input_method_->Clear();
- input_method_->SetCompositionTextForNextKey(composition);
- textfield_->clear();
- SendKeyEvent(ui::VKEY_A);
- EXPECT_TRUE(client->HasCompositionText());
- EXPECT_STR_EQ("0123321456789", textfield_->text());
-
- on_before_user_action_ = on_after_user_action_ = 0;
- textfield_->clear();
- SendKeyEvent(ui::VKEY_RIGHT);
- EXPECT_FALSE(client->HasCompositionText());
- EXPECT_TRUE(input_method_->cancel_composition_called());
- EXPECT_TRUE(textfield_->key_received());
- EXPECT_TRUE(textfield_->key_handled());
- EXPECT_STR_EQ("0123321456789", textfield_->text());
- EXPECT_EQ(8U, textfield_->GetCursorPosition());
- EXPECT_EQ(1, on_before_user_action_);
- EXPECT_EQ(1, on_after_user_action_);
-
- textfield_->clear();
- textfield_->SetText(ASCIIToUTF16("0123456789"));
- EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5)));
- client->ExtendSelectionAndDelete(4, 2);
- EXPECT_STR_EQ("0789", textfield_->text());
-
- // On{Before,After}UserAction should be called by whatever user action
- // triggers clearing or setting a selection if appropriate.
- on_before_user_action_ = on_after_user_action_ = 0;
- textfield_->clear();
- textfield_->ClearSelection();
- textfield_->SelectAll(false);
- EXPECT_EQ(0, on_before_user_action_);
- EXPECT_EQ(0, on_after_user_action_);
-
- input_method_->Clear();
- textfield_->SetReadOnly(true);
- EXPECT_TRUE(input_method_->text_input_type_changed());
- EXPECT_FALSE(textfield_->GetTextInputClient());
-
- textfield_->SetReadOnly(false);
- input_method_->Clear();
- textfield_->SetObscured(true);
- EXPECT_TRUE(input_method_->text_input_type_changed());
- EXPECT_TRUE(textfield_->GetTextInputClient());
-}
-
-TEST_F(NativeTextfieldViewsTest, UndoRedoTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- SendKeyEvent(ui::VKEY_A);
- EXPECT_STR_EQ("a", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("a", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("a", textfield_->text());
-
- // AppendText
- textfield_->AppendText(ASCIIToUTF16("b"));
- last_contents_.clear(); // AppendText doesn't call ContentsChanged.
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("a", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("ab", textfield_->text());
-
- // SetText
- SendKeyEvent(ui::VKEY_C);
- // Undo'ing append moves the cursor to the end for now.
- // no-op SetText won't add new edit. See TextfieldViewsModel::SetText
- // description.
- EXPECT_STR_EQ("abc", textfield_->text());
- textfield_->SetText(ASCIIToUTF16("abc"));
- EXPECT_STR_EQ("abc", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("abc", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("abc", textfield_->text());
- textfield_->SetText(ASCIIToUTF16("123"));
- textfield_->SetText(ASCIIToUTF16("123"));
- EXPECT_STR_EQ("123", textfield_->text());
- SendKeyEvent(ui::VKEY_END, false, false);
- SendKeyEvent(ui::VKEY_4, false, false);
- EXPECT_STR_EQ("1234", textfield_->text());
- last_contents_.clear();
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("123", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- // the insert edit "c" and set edit "123" are merged to single edit,
- // so text becomes "ab" after undo.
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("a", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("123", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("1234", textfield_->text());
-
- // Undoing to the same text shouldn't call ContentsChanged.
- SendKeyEvent(ui::VKEY_A, false, true); // select all
- SendKeyEvent(ui::VKEY_A);
- EXPECT_STR_EQ("a", textfield_->text());
- SendKeyEvent(ui::VKEY_B);
- SendKeyEvent(ui::VKEY_C);
- EXPECT_STR_EQ("abc", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("1234", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("abc", textfield_->text());
-
- // Delete/Backspace
- SendKeyEvent(ui::VKEY_BACK);
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_HOME);
- SendKeyEvent(ui::VKEY_DELETE);
- EXPECT_STR_EQ("b", textfield_->text());
- SendKeyEvent(ui::VKEY_A, false, true);
- SendKeyEvent(ui::VKEY_DELETE);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("b", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Z, false, true);
- EXPECT_STR_EQ("abc", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("ab", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("b", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("", textfield_->text());
- SendKeyEvent(ui::VKEY_Y, false, true);
- EXPECT_STR_EQ("", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, CutCopyPaste) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // Ensure IDS_APP_CUT cuts.
- textfield_->SetText(ASCIIToUTF16("123"));
- textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_view_->ExecuteCommand(IDS_APP_CUT, 0);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
- EXPECT_STR_EQ("", textfield_->text());
-
- // Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing.
- textfield_->SetText(ASCIIToUTF16("456"));
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_X, true, false, true, false);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
- EXPECT_STR_EQ("456", textfield_->text());
- SendKeyEvent(ui::VKEY_X, false, true);
- EXPECT_STR_EQ("456", string16(GetClipboardText()));
- EXPECT_STR_EQ("", textfield_->text());
-
- // Ensure [Shift]+[Delete] cuts.
- textfield_->SetText(ASCIIToUTF16("123"));
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_DELETE, true, false);
- EXPECT_STR_EQ("123", string16(GetClipboardText()));
- EXPECT_STR_EQ("", textfield_->text());
-
- // Ensure IDS_APP_COPY copies.
- textfield_->SetText(ASCIIToUTF16("789"));
- textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_view_->ExecuteCommand(IDS_APP_COPY, 0);
- EXPECT_STR_EQ("789", string16(GetClipboardText()));
-
- // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing.
- textfield_->SetText(ASCIIToUTF16("012"));
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_C, true, false, true, false);
- EXPECT_STR_EQ("789", string16(GetClipboardText()));
- SendKeyEvent(ui::VKEY_C, false, true);
- EXPECT_STR_EQ("012", string16(GetClipboardText()));
-
- // Ensure [Ctrl]+[Insert] copies.
- textfield_->SetText(ASCIIToUTF16("345"));
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_INSERT, false, true);
- EXPECT_STR_EQ("345", string16(GetClipboardText()));
- EXPECT_STR_EQ("345", textfield_->text());
-
- // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes;
- // also ensure that [Ctrl]+[Alt]+[V] does nothing.
- SetClipboardText("abc");
- textfield_->SetText(string16());
- EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0);
- EXPECT_STR_EQ("abc", textfield_->text());
- SendKeyEvent(ui::VKEY_V, false, true);
- EXPECT_STR_EQ("abcabc", textfield_->text());
- SendKeyEvent(ui::VKEY_INSERT, true, false);
- EXPECT_STR_EQ("abcabcabc", textfield_->text());
- SendKeyEvent(ui::VKEY_V, true, false, true, false);
- EXPECT_STR_EQ("abcabcabc", textfield_->text());
-
- // Ensure [Ctrl]+[Shift]+[Insert] is a no-op.
- textfield_->SelectAll(false);
- SendKeyEvent(ui::VKEY_INSERT, true, true);
- EXPECT_STR_EQ("abc", string16(GetClipboardText()));
- EXPECT_STR_EQ("abcabcabc", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, OvertypeMode) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- // Overtype mode should be disabled (no-op [Insert]).
- textfield_->SetText(ASCIIToUTF16("2"));
- SendKeyEvent(ui::VKEY_HOME);
- SendKeyEvent(ui::VKEY_INSERT);
- SendKeyEvent(ui::VKEY_1, false, false);
- EXPECT_STR_EQ("12", textfield_->text());
-}
-
-TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- // LTR-RTL string in LTR context.
- SendKeyEvent('a');
- EXPECT_STR_EQ("a", textfield_->text());
- int x = GetCursorBounds().x();
- int prev_x = x;
-
- SendKeyEvent('b');
- EXPECT_STR_EQ("ab", textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_LT(prev_x, x);
- prev_x = x;
-
- SendKeyEvent(0x05E1);
- EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
-
- SendKeyEvent(0x05E2);
- EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
-
- // Clear text.
- SendKeyEvent(ui::VKEY_A, false, true);
- SendKeyEvent('\n');
-
- // RTL-LTR string in LTR context.
- SendKeyEvent(0x05E1);
- EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(GetDisplayRect().x(), x);
- prev_x = x;
-
- SendKeyEvent(0x05E2);
- EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
-
- SendKeyEvent('a');
- EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_LT(prev_x, x);
- prev_x = x;
-
- SendKeyEvent('b');
- EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_LT(prev_x, x);
-}
-
-TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) {
- std::string locale = l10n_util::GetApplicationLocale("");
- base::i18n::SetICUDefaultLocale("he");
-
- InitTextfield(Textfield::STYLE_DEFAULT);
- // LTR-RTL string in RTL context.
- SendKeyEvent('a');
- EXPECT_STR_EQ("a", textfield_->text());
- int x = GetCursorBounds().x();
- EXPECT_EQ(GetDisplayRect().right() - 1, x);
- int prev_x = x;
-
- SendKeyEvent('b');
- EXPECT_STR_EQ("ab", textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
-
- SendKeyEvent(0x05E1);
- EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_GT(prev_x, x);
- prev_x = x;
-
- SendKeyEvent(0x05E2);
- EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_GT(prev_x, x);
-
- SendKeyEvent(ui::VKEY_A, false, true);
- SendKeyEvent('\n');
-
- // RTL-LTR string in RTL context.
- SendKeyEvent(0x05E1);
- EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
- x = GetCursorBounds().x();
- prev_x = x;
-
- SendKeyEvent(0x05E2);
- EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_GT(prev_x, x);
- prev_x = x;
-
- SendKeyEvent('a');
- EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
- prev_x = x;
-
- SendKeyEvent('b');
- EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
- x = GetCursorBounds().x();
- EXPECT_EQ(prev_x, x);
-
- // Reset locale.
- base::i18n::SetICUDefaultLocale(locale);
-}
-
-TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
- std::vector<gfx::Rect> cursor_bounds;
-
- // Save each cursor bound.
- gfx::SelectionModel sel(0, gfx::CURSOR_FORWARD);
- cursor_bounds.push_back(GetCursorBounds(sel));
-
- sel = gfx::SelectionModel(1, gfx::CURSOR_BACKWARD);
- gfx::Rect bound = GetCursorBounds(sel);
- sel = gfx::SelectionModel(1, gfx::CURSOR_FORWARD);
- EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
- cursor_bounds.push_back(bound);
-
- // Check that a cursor at the end of the Latin portion of the text is at the
- // same position as a cursor placed at the end of the RTL Hebrew portion.
- sel = gfx::SelectionModel(2, gfx::CURSOR_BACKWARD);
- bound = GetCursorBounds(sel);
- sel = gfx::SelectionModel(4, gfx::CURSOR_BACKWARD);
- EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
- cursor_bounds.push_back(bound);
-
- sel = gfx::SelectionModel(3, gfx::CURSOR_BACKWARD);
- bound = GetCursorBounds(sel);
- sel = gfx::SelectionModel(3, gfx::CURSOR_FORWARD);
- EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
- cursor_bounds.push_back(bound);
-
- sel = gfx::SelectionModel(2, gfx::CURSOR_FORWARD);
- bound = GetCursorBounds(sel);
- sel = gfx::SelectionModel(4, gfx::CURSOR_FORWARD);
- EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
- cursor_bounds.push_back(bound);
-
- // Expected cursor position when clicking left and right of each character.
- size_t cursor_pos_expected[] = {0, 1, 1, 2, 4, 3, 3, 2};
-
- int index = 0;
- for (int i = 0; i < static_cast<int>(cursor_bounds.size() - 1); ++i) {
- int half_width = (cursor_bounds[i + 1].x() - cursor_bounds[i].x()) / 2;
- MouseClick(cursor_bounds[i], half_width / 2);
- EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
-
- // To avoid trigger double click. Not using sleep() since it takes longer
- // for the test to run if using sleep().
- NonClientMouseClick();
-
- MouseClick(cursor_bounds[i + 1], - (half_width / 2));
- EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
-
- NonClientMouseClick();
- }
-}
-
-TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // LTR-RTL string in LTR context.
- textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
-
- SendKeyEvent(ui::VKEY_HOME);
- gfx::Rect bound = GetCursorBounds();
- MouseClick(bound, -10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- SendKeyEvent(ui::VKEY_END);
- bound = GetCursorBounds();
- MouseClick(bound, 10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- NonClientMouseClick();
-
- // RTL-LTR string in LTR context.
- textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
-
- SendKeyEvent(ui::VKEY_HOME);
- bound = GetCursorBounds();
- MouseClick(bound, 10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- SendKeyEvent(ui::VKEY_END);
- bound = GetCursorBounds();
- MouseClick(bound, -10);
- EXPECT_EQ(bound, GetCursorBounds());
-}
-
-TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) {
- std::string locale = l10n_util::GetApplicationLocale("");
- base::i18n::SetICUDefaultLocale("he");
-
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- // RTL-LTR string in RTL context.
- textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
- SendKeyEvent(ui::VKEY_HOME);
- gfx::Rect bound = GetCursorBounds();
- MouseClick(bound, 10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- SendKeyEvent(ui::VKEY_END);
- bound = GetCursorBounds();
- MouseClick(bound, -10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- NonClientMouseClick();
-
- // LTR-RTL string in RTL context.
- textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
- SendKeyEvent(ui::VKEY_HOME);
- bound = GetCursorBounds();
- MouseClick(bound, -10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- SendKeyEvent(ui::VKEY_END);
- bound = GetCursorBounds();
- MouseClick(bound, 10);
- EXPECT_EQ(bound, GetCursorBounds());
-
- // Reset locale.
- base::i18n::SetICUDefaultLocale(locale);
-}
-
-TEST_F(NativeTextfieldViewsTest, OverflowTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- string16 str;
- for (int i = 0; i < 500; ++i)
- SendKeyEvent('a');
- SendKeyEvent(kHebrewLetterSamekh);
- EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
-
- // Test mouse pointing.
- MouseClick(GetCursorBounds(), -1);
- EXPECT_EQ(500U, textfield_->GetCursorPosition());
-
- // Clear text.
- SendKeyEvent(ui::VKEY_A, false, true);
- SendKeyEvent('\n');
-
- for (int i = 0; i < 500; ++i)
- SendKeyEvent(kHebrewLetterSamekh);
- SendKeyEvent('a');
- EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
-
- MouseClick(GetCursorBounds(), -1);
- EXPECT_EQ(501U, textfield_->GetCursorPosition());
-}
-
-TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) {
- std::string locale = l10n_util::GetApplicationLocale("");
- base::i18n::SetICUDefaultLocale("he");
-
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- string16 str;
- for (int i = 0; i < 500; ++i)
- SendKeyEvent('a');
- SendKeyEvent(kHebrewLetterSamekh);
- EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
-
- MouseClick(GetCursorBounds(), 1);
- EXPECT_EQ(501U, textfield_->GetCursorPosition());
-
- // Clear text.
- SendKeyEvent(ui::VKEY_A, false, true);
- SendKeyEvent('\n');
-
- for (int i = 0; i < 500; ++i)
- SendKeyEvent(kHebrewLetterSamekh);
- SendKeyEvent('a');
- EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
-
- MouseClick(GetCursorBounds(), 1);
- EXPECT_EQ(500U, textfield_->GetCursorPosition());
-
- // Reset locale.
- base::i18n::SetICUDefaultLocale(locale);
-}
-
-TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- string16 str;
- const uint32 char_count = 10UL;
- ui::CompositionText composition;
- composition.text = UTF8ToUTF16("0123456789");
- ui::TextInputClient* client = textfield_->GetTextInputClient();
-
- // Return false if there is no composition text.
- gfx::Rect rect;
- EXPECT_FALSE(client->GetCompositionCharacterBounds(0, &rect));
-
- // Get each character boundary by cursor.
- gfx::Rect char_rect_in_screen_coord[char_count];
- gfx::Rect prev_cursor = GetCursorBounds();
- for (uint32 i = 0; i < char_count; ++i) {
- composition.selection = gfx::Range(0, i+1);
- client->SetCompositionText(composition);
- EXPECT_TRUE(client->HasCompositionText()) << " i=" << i;
- gfx::Rect cursor_bounds = GetCursorBounds();
- gfx::Point top_left(prev_cursor.x(), prev_cursor.y());
- gfx::Point bottom_right(cursor_bounds.x(), prev_cursor.bottom());
- views::View::ConvertPointToScreen(textfield_view_, &top_left);
- views::View::ConvertPointToScreen(textfield_view_, &bottom_right);
- char_rect_in_screen_coord[i].set_origin(top_left);
- char_rect_in_screen_coord[i].set_width(bottom_right.x() - top_left.x());
- char_rect_in_screen_coord[i].set_height(bottom_right.y() - top_left.y());
- prev_cursor = cursor_bounds;
- }
-
- for (uint32 i = 0; i < char_count; ++i) {
- gfx::Rect actual_rect;
- EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &actual_rect))
- << " i=" << i;
- EXPECT_EQ(char_rect_in_screen_coord[i], actual_rect) << " i=" << i;
- }
-
- // Return false if the index is out of range.
- EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect));
- EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect));
- EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect));
-}
-
-TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- const char16 kUtf16Chars[] = {
- // U+0020 SPACE
- 0x0020,
- // U+1F408 (CAT) as surrogate pair
- 0xd83d, 0xdc08,
- // U+5642 as Ideographic Variation Sequences
- 0x5642, 0xDB40, 0xDD00,
- // U+260E (BLACK TELEPHONE) as Emoji Variation Sequences
- 0x260E, 0xFE0F,
- // U+0020 SPACE
- 0x0020,
- };
- const size_t kUtf16CharsCount = arraysize(kUtf16Chars);
-
- ui::CompositionText composition;
- composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount);
- ui::TextInputClient* client = textfield_->GetTextInputClient();
- client->SetCompositionText(composition);
-
- // Make sure GetCompositionCharacterBounds never fails for index.
- gfx::Rect rects[kUtf16CharsCount];
- gfx::Rect prev_cursor = GetCursorBounds();
- for (uint32 i = 0; i < kUtf16CharsCount; ++i)
- EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i]));
-
- // Here we might expect the following results but it actually depends on how
- // Uniscribe or HarfBuzz treats them with given font.
- // - rects[1] == rects[2]
- // - rects[3] == rects[4] == rects[5]
- // - rects[6] == rects[7]
-}
-
-// The word we select by double clicking should remain selected regardless of
-// where we drag the mouse afterwards without releasing the left button.
-TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) {
- InitTextfield(Textfield::STYLE_DEFAULT);
-
- textfield_->SetText(ASCIIToUTF16("abc def ghi"));
-
- textfield_->SelectRange(gfx::Range(5, 5));
- const gfx::Rect middle_cursor = GetCursorBounds();
- textfield_->SelectRange(gfx::Range(0, 0));
- const gfx::Point beginning = GetCursorBounds().origin();
-
- // Double click, but do not release the left button.
- MouseClick(middle_cursor, 0);
- const gfx::Point middle(middle_cursor.x(),
- middle_cursor.y() + middle_cursor.height() / 2);
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMousePressed(press_event);
- EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange());
-
- // Drag the mouse to the beginning of the textfield.
- ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning,
- ui::EF_LEFT_MOUSE_BUTTON);
- textfield_view_->OnMouseDragged(drag_event);
- EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange());
-}
-
-// Touch selection and draggin currently only works for chromeos.
-#if defined(OS_CHROMEOS)
-TEST_F(NativeTextfieldViewsTest, TouchSelectionAndDraggingTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
- EXPECT_FALSE(GetTouchSelectionController());
- const int eventX = GetCursorPositionX(2);
- const int eventY = 0;
- CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
-
- // Tapping on the textfield should turn on the TouchSelectionController.
- GestureEventForTest tap(ui::ET_GESTURE_TAP, eventX, eventY, 1.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap);
- EXPECT_TRUE(GetTouchSelectionController());
-
- // Un-focusing the textfield should reset the TouchSelectionController
- textfield_view_->GetFocusManager()->ClearFocus();
- EXPECT_FALSE(GetTouchSelectionController());
-
- // With touch editing enabled, long press should not show context menu.
- // Instead, select word and invoke TouchSelectionController.
- GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, eventX, eventY, 0.0f,
- 0.0f);
- textfield_view_->OnGestureEvent(&tap_down);
- GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, eventX, eventY,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press);
- EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
-
- // Long pressing again in the selecting region should not do anything since
- // touch drag drop is not yet enabled.
- textfield_view_->OnGestureEvent(&tap_down);
- textfield_view_->OnGestureEvent(&long_press);
- EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
- EXPECT_TRUE(long_press.handled());
-
- // After enabling touch drag drop, long pressing in the selected region should
- // start a drag and remove TouchSelectionController.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableTouchDragDrop);
- textfield_view_->OnGestureEvent(&tap_down);
-
- // Create a new long press event since the previous one is not marked handled.
- GestureEventForTest long_press2(ui::ET_GESTURE_LONG_PRESS, eventX, eventY,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press2);
- EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
- EXPECT_FALSE(GetTouchSelectionController());
-}
-
-TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("hello world"));
- EXPECT_FALSE(GetTouchSelectionController());
-
- CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
-
- // Simulate touch-scrubbing.
- int scrubbing_start = GetCursorPositionX(1);
- int scrubbing_end = GetCursorPositionX(6);
-
- GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap_down);
-
- GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, scrubbing_start, 0,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&tap_cancel);
-
- GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, scrubbing_start,
- 0, 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_begin);
-
- GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, scrubbing_end,
- 0, scrubbing_end - scrubbing_start, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_update);
-
- GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0,
- 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&scroll_end);
-
- GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&end);
-
- // In the end, part of text should have been selected and handles should have
- // appeared.
- EXPECT_STR_EQ("ello ", textfield_->GetSelectedText());
- EXPECT_TRUE(GetTouchSelectionController());
-}
-#endif
-
-// Long_Press gesture in NativeTextfieldViews can initiate a drag and drop now.
-TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(ASCIIToUTF16("Hello string world"));
-
- // Ensure the textfield will provide selected text for drag data.
- textfield_->SelectRange(gfx::Range(6, 12));
- const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
-
- // Enable touch-drag-drop to make long press effective.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableTouchDragDrop);
-
- // Create a long press event in the selected region should start a drag.
- GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, kStringPoint.x(),
- kStringPoint.y(), 0.0f, 0.0f);
- textfield_view_->OnGestureEvent(&long_press);
- EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL,
- kStringPoint, kStringPoint));
-}
-
-TEST_F(NativeTextfieldViewsTest, GetTextfieldBaseline_FontFallbackTest) {
- InitTextfield(Textfield::STYLE_DEFAULT);
- textfield_->SetText(UTF8ToUTF16("abc"));
- const int old_baseline = textfield_->GetBaseline();
-
- // Set text which may fall back to a font which has taller baseline than
- // the default font.
- textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91"));
- const int new_baseline = textfield_->GetBaseline();
-
- // Regardless of the text, the baseline must be the same.
- EXPECT_EQ(new_baseline, old_baseline);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/textfield/native_textfield_wrapper.h b/chromium/ui/views/controls/textfield/native_textfield_wrapper.h
deleted file mode 100644
index eafd2f59dd7..00000000000
--- a/chromium/ui/views/controls/textfield/native_textfield_wrapper.h
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
-
-#include "base/i18n/rtl.h"
-#include "base/strings/string16.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/selection_model.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Insets;
-class Point;
-} // namespace gfx
-
-namespace ui {
-class KeyEvent;
-class TextInputClient;
-} // namespace ui
-
-namespace views {
-
-class Textfield;
-class View;
-
-// An interface implemented by an object that provides a platform-native
-// text field.
-class VIEWS_EXPORT NativeTextfieldWrapper {
- public:
- // The Textfield calls this when it is destroyed to clean up the wrapper
- // object.
- virtual ~NativeTextfieldWrapper() {}
-
- // Gets the text displayed in the wrapped native text field.
- virtual string16 GetText() const = 0;
-
- // Updates the text displayed with the text held by the Textfield.
- virtual void UpdateText() = 0;
-
- // Adds the specified text to the text already displayed by the wrapped native
- // text field.
- virtual void AppendText(const string16& text) = 0;
-
- // Inserts |text| at the current cursor position, replacing any selected text.
- virtual void InsertOrReplaceText(const string16& text) = 0;
-
- // Returns the text direction.
- virtual base::i18n::TextDirection GetTextDirection() const = 0;
-
- // Gets the text that is selected in the wrapped native text field.
- virtual string16 GetSelectedText() const = 0;
-
- // Select the entire text range. If |reversed| is true, the range will end at
- // the logical beginning of the text; this generally shows the leading portion
- // of text that overflows its display area.
- virtual void SelectAll(bool reversed) = 0;
-
- // Clears the selection within the edit field and sets the caret to the end.
- virtual void ClearSelection() = 0;
-
- // Updates whether there is a visible border.
- virtual void UpdateBorder() = 0;
-
- // Updates the text color used when painting the native text field.
- virtual void UpdateTextColor() = 0;
-
- // Updates the background color used when painting the native text field.
- virtual void UpdateBackgroundColor() = 0;
-
- // Updates the read-only state of the native text field.
- virtual void UpdateReadOnly() = 0;
-
- // Updates the font used to render text in the native text field.
- virtual void UpdateFont() = 0;
-
- // Updates the visibility of the text in the native text field.
- virtual void UpdateIsObscured() = 0;
-
- // Updates the enabled state of the native text field.
- virtual void UpdateEnabled() = 0;
-
- // Returns the insets for the text field.
- virtual gfx::Insets CalculateInsets() = 0;
-
- // Updates the horizontal margins for the native text field.
- virtual void UpdateHorizontalMargins() = 0;
-
- // Updates the vertical margins for the native text field.
- virtual void UpdateVerticalMargins() = 0;
-
- // Sets the focus to the text field. Returns false if the wrapper
- // didn't take focus.
- virtual bool SetFocus() = 0;
-
- // Retrieves the views::View that hosts the native control.
- virtual View* GetView() = 0;
-
- // Returns a handle to the underlying native view for testing.
- virtual gfx::NativeView GetTestingHandle() const = 0;
-
- // Returns whether or not an IME is composing text.
- virtual bool IsIMEComposing() const = 0;
-
- // Gets the selected range.
- virtual gfx::Range GetSelectedRange() const = 0;
-
- // Selects the text given by |range|.
- virtual void SelectRange(const gfx::Range& range) = 0;
-
- // Gets the selection model.
- virtual gfx::SelectionModel GetSelectionModel() const = 0;
-
- // Selects the text given by |sel|.
- virtual void SelectSelectionModel(const gfx::SelectionModel& sel) = 0;
-
- // Returns the currnet cursor position.
- virtual size_t GetCursorPosition() const = 0;
-
- // Get or set whether or not the cursor is enabled.
- virtual bool GetCursorEnabled() const = 0;
- virtual void SetCursorEnabled(bool enabled) = 0;
-
- // Following methods are to forward key/focus related events to the
- // views wrapper so that TextfieldViews can handle key inputs without
- // having focus.
-
- // Invoked when a key is pressed/release on Textfield. Subclasser
- // should return true if the event has been processed and false
- // otherwise.
- // See also View::OnKeyPressed/OnKeyReleased.
- virtual bool HandleKeyPressed(const ui::KeyEvent& e) = 0;
- virtual bool HandleKeyReleased(const ui::KeyEvent& e) = 0;
-
- // Invoked when focus is being moved from or to the Textfield.
- // See also View::OnFocus/OnBlur.
- virtual void HandleFocus() = 0;
- virtual void HandleBlur() = 0;
-
- // Returns the View's TextInputClient instance or NULL if the View doesn't
- // support text input.
- virtual ui::TextInputClient* GetTextInputClient() = 0;
-
- // Set the text colors; see the corresponding Textfield functions for details.
- virtual void SetColor(SkColor value) = 0;
- virtual void ApplyColor(SkColor value, const gfx::Range& range) = 0;
-
- // Set the text styles; see the corresponding Textfield functions for details.
- virtual void SetStyle(gfx::TextStyle style, bool value) = 0;
- virtual void ApplyStyle(gfx::TextStyle style,
- bool value,
- const gfx::Range& range) = 0;
-
- // Clears Edit history.
- virtual void ClearEditHistory() = 0;
-
- // Get the height in pixels of the first font used in this textfield.
- virtual int GetFontHeight() = 0;
-
- // Returns the baseline of the textfield. This should not take into account
- // any insets.
- virtual int GetTextfieldBaseline() const = 0;
-
- // Returns the width necessary to display the current text, including any
- // necessary space for the cursor or border/margin.
- virtual int GetWidthNeededForText() const = 0;
-
- // Performs the action associated with the specified command id. Not called
- // ExecuteCommand to avoid name clash.
- virtual void ExecuteTextCommand(int command_id) = 0;
-
- // Returns whether there is a drag operation originating from the textfield.
- virtual bool HasTextBeingDragged() = 0;
-
- // Returns the location for keyboard-triggered context menus.
- virtual gfx::Point GetContextMenuLocation() = 0;
-
- // Creates an appropriate NativeTextfieldWrapper for the platform.
- static NativeTextfieldWrapper* CreateWrapper(Textfield* field);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WRAPPER_H_
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index de590dc304c..f28f8f27e18 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -6,40 +6,235 @@
#include <string>
-#include "base/command_line.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/accessibility/accessible_view_state.h"
-#include "ui/base/ime/text_input_type.h"
+#include "base/debug/trace_event.h"
+#include "grit/ui_strings.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/insets.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/selection_model.h"
+#include "ui/gfx/screen.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/focusable_border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/controls/textfield/native_textfield_views.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/metrics.h"
+#include "ui/views/native_cursor.h"
#include "ui/views/painter.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "base/strings/utf_string_conversions.h"
+#include "ui/events/linux/text_edit_command_auralinux.h"
+#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+#endif
+
+namespace views {
+
namespace {
// Default placeholder text color.
const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
-gfx::FontList GetDefaultFontList() {
- return ResourceBundle::GetSharedInstance().GetFontList(
- ResourceBundle::BaseFont);
+const int kNoCommand = 0;
+
+void ConvertRectToScreen(const View* src, gfx::Rect* r) {
+ DCHECK(src);
+
+ gfx::Point new_origin = r->origin();
+ View::ConvertPointToScreen(src, &new_origin);
+ r->set_origin(new_origin);
}
-} // namespace
+// Get the drag selection timer delay, respecting animation scaling for testing.
+int GetDragSelectionDelay() {
+ switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
+ case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100;
+ case ui::ScopedAnimationDurationScaleMode::FAST_DURATION: return 25;
+ case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION: return 400;
+ case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION: return 0;
+ }
+ return 100;
+}
+
+// Get the default command for a given key |event| and selection state.
+int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) {
+ if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
+ return kNoCommand;
+
+ const bool shift = event.IsShiftDown();
+ const bool control = event.IsControlDown();
+ const bool alt = event.IsAltDown() || event.IsAltGrDown();
+ switch (event.key_code()) {
+ case ui::VKEY_Z:
+ if (control && !shift && !alt)
+ return IDS_APP_UNDO;
+ return (control && shift && !alt) ? IDS_APP_REDO : kNoCommand;
+ case ui::VKEY_Y:
+ return (control && !alt) ? IDS_APP_REDO : kNoCommand;
+ case ui::VKEY_A:
+ return (control && !alt) ? IDS_APP_SELECT_ALL : kNoCommand;
+ case ui::VKEY_X:
+ return (control && !alt) ? IDS_APP_CUT : kNoCommand;
+ case ui::VKEY_C:
+ return (control && !alt) ? IDS_APP_COPY : kNoCommand;
+ case ui::VKEY_V:
+ return (control && !alt) ? IDS_APP_PASTE : kNoCommand;
+ case ui::VKEY_RIGHT:
+ // Ignore alt+right, which may be a browser navigation shortcut.
+ if (alt)
+ return kNoCommand;
+ if (!shift)
+ return control ? IDS_MOVE_WORD_RIGHT : IDS_MOVE_RIGHT;
+ return control ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_RIGHT_AND_MODIFY_SELECTION;
+ case ui::VKEY_LEFT:
+ // Ignore alt+left, which may be a browser navigation shortcut.
+ if (alt)
+ return kNoCommand;
+ if (!shift)
+ return control ? IDS_MOVE_WORD_LEFT : IDS_MOVE_LEFT;
+ return control ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_LEFT_AND_MODIFY_SELECTION;
+ case ui::VKEY_HOME:
+ return shift ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_BEGINNING_OF_LINE;
+ case ui::VKEY_END:
+ return shift ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_END_OF_LINE;
+ case ui::VKEY_BACK:
+ if (!control || has_selection)
+ return IDS_DELETE_BACKWARD;
+#if defined(OS_LINUX)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift)
+ return IDS_DELETE_TO_BEGINNING_OF_LINE;
+#endif
+ return IDS_DELETE_WORD_BACKWARD;
+ case ui::VKEY_DELETE:
+ if (!control || has_selection)
+ return (shift && has_selection) ? IDS_APP_CUT : IDS_DELETE_FORWARD;
+#if defined(OS_LINUX)
+ // Only erase by line break on Linux and ChromeOS.
+ if (shift)
+ return IDS_DELETE_TO_END_OF_LINE;
+#endif
+ return IDS_DELETE_WORD_FORWARD;
+ case ui::VKEY_INSERT:
+ if (control && !shift)
+ return IDS_APP_COPY;
+ return (shift && !control) ? IDS_APP_PASTE : kNoCommand;
+ default:
+ return kNoCommand;
+ }
+}
-namespace views {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Convert a custom text edit |command| to the equivalent views command ID.
+int GetViewsCommand(const ui::TextEditCommandAuraLinux& command, bool rtl) {
+ const bool select = command.extend_selection();
+ switch (command.command_id()) {
+ case ui::TextEditCommandAuraLinux::COPY:
+ return IDS_APP_COPY;
+ case ui::TextEditCommandAuraLinux::CUT:
+ return IDS_APP_CUT;
+ case ui::TextEditCommandAuraLinux::DELETE_BACKWARD:
+ return IDS_DELETE_BACKWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_FORWARD:
+ return IDS_DELETE_FORWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_LINE:
+ case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_PARAGRAPH:
+ return IDS_DELETE_TO_BEGINNING_OF_LINE;
+ case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_LINE:
+ case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_PARAGRAPH:
+ return IDS_DELETE_TO_END_OF_LINE;
+ case ui::TextEditCommandAuraLinux::DELETE_WORD_BACKWARD:
+ return IDS_DELETE_WORD_BACKWARD;
+ case ui::TextEditCommandAuraLinux::DELETE_WORD_FORWARD:
+ return IDS_DELETE_WORD_FORWARD;
+ case ui::TextEditCommandAuraLinux::INSERT_TEXT:
+ return kNoCommand;
+ case ui::TextEditCommandAuraLinux::MOVE_BACKWARD:
+ if (rtl)
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_DOWN:
+ return IDS_MOVE_DOWN;
+ case ui::TextEditCommandAuraLinux::MOVE_FORWARD:
+ if (rtl)
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_LEFT:
+ return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_PAGE_DOWN:
+ case ui::TextEditCommandAuraLinux::MOVE_PAGE_UP:
+ return kNoCommand;
+ case ui::TextEditCommandAuraLinux::MOVE_RIGHT:
+ return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_DOCUMENT:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_LINE:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_PARAGRAPH:
+ return select ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_BEGINNING_OF_LINE;
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_DOCUMENT:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_LINE:
+ case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_PARAGRAPH:
+ return select ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
+ IDS_MOVE_TO_END_OF_LINE;
+ case ui::TextEditCommandAuraLinux::MOVE_UP:
+ return IDS_MOVE_UP;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_BACKWARD:
+ if (rtl) {
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ }
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_FORWARD:
+ if (rtl) {
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ }
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_LEFT:
+ return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_LEFT;
+ case ui::TextEditCommandAuraLinux::MOVE_WORD_RIGHT:
+ return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
+ IDS_MOVE_WORD_RIGHT;
+ case ui::TextEditCommandAuraLinux::PASTE:
+ return IDS_APP_PASTE;
+ case ui::TextEditCommandAuraLinux::SELECT_ALL:
+ return IDS_APP_SELECT_ALL;
+ case ui::TextEditCommandAuraLinux::SET_MARK:
+ case ui::TextEditCommandAuraLinux::UNSELECT:
+ case ui::TextEditCommandAuraLinux::INVALID_COMMAND:
+ return kNoCommand;
+ }
+ return kNoCommand;
+}
+#endif
+
+} // namespace
// static
const char Textfield::kViewClassName[] = "Textfield";
@@ -56,153 +251,102 @@ size_t Textfield::GetCaretBlinkMs() {
}
Textfield::Textfield()
- : native_wrapper_(NULL),
+ : model_(new TextfieldModel(this)),
controller_(NULL),
- style_(STYLE_DEFAULT),
- font_list_(GetDefaultFontList()),
read_only_(false),
default_width_in_chars_(0),
- draw_border_(true),
- text_color_(SK_ColorBLACK),
use_default_text_color_(true),
- background_color_(SK_ColorWHITE),
use_default_background_color_(true),
- horizontal_margins_were_set_(false),
- vertical_margins_were_set_(false),
- placeholder_text_color_(kDefaultPlaceholderTextColor),
- text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
- weak_ptr_factory_(this) {
- SetFocusable(true);
-
- if (ViewsDelegate::views_delegate) {
- obscured_reveal_duration_ = ViewsDelegate::views_delegate->
- GetDefaultTextfieldObscuredRevealDuration();
- }
-
- if (NativeViewHost::kRenderNativeControlFocus)
- focus_painter_ = Painter::CreateDashedFocusPainter();
-}
-
-Textfield::Textfield(StyleFlags style)
- : native_wrapper_(NULL),
- controller_(NULL),
- style_(style),
- font_list_(GetDefaultFontList()),
- read_only_(false),
- default_width_in_chars_(0),
- draw_border_(true),
+ use_default_selection_text_color_(true),
+ use_default_selection_background_color_(true),
text_color_(SK_ColorBLACK),
- use_default_text_color_(true),
background_color_(SK_ColorWHITE),
- use_default_background_color_(true),
- horizontal_margins_were_set_(false),
- vertical_margins_were_set_(false),
+ selection_text_color_(SK_ColorWHITE),
+ selection_background_color_(SK_ColorBLUE),
placeholder_text_color_(kDefaultPlaceholderTextColor),
text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
+ performing_user_action_(false),
+ skip_input_method_cancel_composition_(false),
+ cursor_visible_(false),
+ drop_cursor_visible_(false),
+ initiating_drag_(false),
+ aggregated_clicks_(0),
weak_ptr_factory_(this) {
+ set_context_menu_controller(this);
+ set_drag_controller(this);
+ SetBorder(scoped_ptr<Border>(new FocusableBorder()));
SetFocusable(true);
- if (IsObscured())
- SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
if (ViewsDelegate::views_delegate) {
- obscured_reveal_duration_ = ViewsDelegate::views_delegate->
+ password_reveal_duration_ = ViewsDelegate::views_delegate->
GetDefaultTextfieldObscuredRevealDuration();
}
-
- if (NativeViewHost::kRenderNativeControlFocus)
- focus_painter_ = Painter::CreateDashedFocusPainter();
-}
-
-Textfield::~Textfield() {
-}
-
-void Textfield::SetController(TextfieldController* controller) {
- controller_ = controller;
}
-TextfieldController* Textfield::GetController() const {
- return controller_;
-}
+Textfield::~Textfield() {}
void Textfield::SetReadOnly(bool read_only) {
// Update read-only without changing the focusable state (or active, etc.).
read_only_ = read_only;
- if (native_wrapper_) {
- native_wrapper_->UpdateReadOnly();
- native_wrapper_->UpdateTextColor();
- native_wrapper_->UpdateBackgroundColor();
- }
-}
-
-bool Textfield::IsObscured() const {
- return style_ & STYLE_OBSCURED;
-}
-
-void Textfield::SetObscured(bool obscured) {
- if (obscured) {
- style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED);
- SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- } else {
- style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED);
- SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
- }
- if (native_wrapper_)
- native_wrapper_->UpdateIsObscured();
-}
-
-ui::TextInputType Textfield::GetTextInputType() const {
- if (read_only() || !enabled())
- return ui::TEXT_INPUT_TYPE_NONE;
- return text_input_type_;
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SetColor(GetTextColor());
+ UpdateBackgroundColor();
}
void Textfield::SetTextInputType(ui::TextInputType type) {
+ GetRenderText()->SetObscured(type == ui::TEXT_INPUT_TYPE_PASSWORD);
text_input_type_ = type;
- bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD;
- if (IsObscured() != should_be_obscured)
- SetObscured(should_be_obscured);
+ OnCaretBoundsChanged();
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SchedulePaint();
}
-void Textfield::SetText(const string16& text) {
- text_ = text;
- if (native_wrapper_)
- native_wrapper_->UpdateText();
+void Textfield::SetText(const base::string16& new_text) {
+ model_->SetText(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
+ NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
}
-void Textfield::AppendText(const string16& text) {
- text_ += text;
- if (native_wrapper_)
- native_wrapper_->AppendText(text);
+void Textfield::AppendText(const base::string16& new_text) {
+ if (new_text.empty())
+ return;
+ model_->Append(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
}
-void Textfield::InsertOrReplaceText(const string16& text) {
- if (native_wrapper_) {
- native_wrapper_->InsertOrReplaceText(text);
- text_ = native_wrapper_->GetText();
- }
+void Textfield::InsertOrReplaceText(const base::string16& new_text) {
+ if (new_text.empty())
+ return;
+ model_->InsertText(new_text);
+ OnCaretBoundsChanged();
+ SchedulePaint();
}
base::i18n::TextDirection Textfield::GetTextDirection() const {
- return native_wrapper_ ?
- native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION;
+ return GetRenderText()->GetTextDirection();
}
-void Textfield::SelectAll(bool reversed) {
- if (native_wrapper_)
- native_wrapper_->SelectAll(reversed);
+base::string16 Textfield::GetSelectedText() const {
+ return model_->GetSelectedText();
}
-string16 Textfield::GetSelectedText() const {
- return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16();
+void Textfield::SelectAll(bool reversed) {
+ model_->SelectAll(reversed);
+ UpdateSelectionClipboard();
+ UpdateAfterChange(false, true);
}
-void Textfield::ClearSelection() const {
- if (native_wrapper_)
- native_wrapper_->ClearSelection();
+void Textfield::ClearSelection() {
+ model_->ClearSelection();
+ UpdateAfterChange(false, true);
}
bool Textfield::HasSelection() const {
- return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty();
+ return !GetSelectedRange().is_empty();
}
SkColor Textfield::GetTextColor() const {
@@ -217,14 +361,12 @@ SkColor Textfield::GetTextColor() const {
void Textfield::SetTextColor(SkColor color) {
text_color_ = color;
use_default_text_color_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateTextColor();
+ SetColor(color);
}
void Textfield::UseDefaultTextColor() {
use_default_text_color_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateTextColor();
+ SetColor(GetTextColor());
}
SkColor Textfield::GetBackgroundColor() const {
@@ -239,173 +381,149 @@ SkColor Textfield::GetBackgroundColor() const {
void Textfield::SetBackgroundColor(SkColor color) {
background_color_ = color;
use_default_background_color_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateBackgroundColor();
+ UpdateBackgroundColor();
}
void Textfield::UseDefaultBackgroundColor() {
use_default_background_color_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateBackgroundColor();
+ UpdateBackgroundColor();
}
-bool Textfield::GetCursorEnabled() const {
- return native_wrapper_ && native_wrapper_->GetCursorEnabled();
+SkColor Textfield::GetSelectionTextColor() const {
+ return use_default_selection_text_color_ ?
+ GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_TextfieldSelectionColor) :
+ selection_text_color_;
}
-void Textfield::SetCursorEnabled(bool enabled) {
- if (native_wrapper_)
- native_wrapper_->SetCursorEnabled(enabled);
+void Textfield::SetSelectionTextColor(SkColor color) {
+ selection_text_color_ = color;
+ use_default_selection_text_color_ = false;
+ GetRenderText()->set_selection_color(GetSelectionTextColor());
+ SchedulePaint();
}
-void Textfield::SetFontList(const gfx::FontList& font_list) {
- font_list_ = font_list;
- if (native_wrapper_)
- native_wrapper_->UpdateFont();
- PreferredSizeChanged();
+void Textfield::UseDefaultSelectionTextColor() {
+ use_default_selection_text_color_ = true;
+ GetRenderText()->set_selection_color(GetSelectionTextColor());
+ SchedulePaint();
}
-const gfx::Font& Textfield::GetPrimaryFont() const {
- return font_list_.GetPrimaryFont();
+SkColor Textfield::GetSelectionBackgroundColor() const {
+ return use_default_selection_background_color_ ?
+ GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused) :
+ selection_background_color_;
}
-void Textfield::SetFont(const gfx::Font& font) {
- SetFontList(gfx::FontList(font));
+void Textfield::SetSelectionBackgroundColor(SkColor color) {
+ selection_background_color_ = color;
+ use_default_selection_background_color_ = false;
+ GetRenderText()->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+ SchedulePaint();
}
-void Textfield::SetHorizontalMargins(int left, int right) {
- if (horizontal_margins_were_set_ &&
- left == margins_.left() && right == margins_.right()) {
- return;
- }
- margins_.Set(margins_.top(), left, margins_.bottom(), right);
- horizontal_margins_were_set_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateHorizontalMargins();
- PreferredSizeChanged();
+void Textfield::UseDefaultSelectionBackgroundColor() {
+ use_default_selection_background_color_ = true;
+ GetRenderText()->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+ SchedulePaint();
}
-void Textfield::SetVerticalMargins(int top, int bottom) {
- if (vertical_margins_were_set_ &&
- top == margins_.top() && bottom == margins_.bottom()) {
- return;
- }
- margins_.Set(top, margins_.left(), bottom, margins_.right());
- vertical_margins_were_set_ = true;
- if (native_wrapper_)
- native_wrapper_->UpdateVerticalMargins();
- PreferredSizeChanged();
+bool Textfield::GetCursorEnabled() const {
+ return GetRenderText()->cursor_enabled();
}
-void Textfield::RemoveBorder() {
- if (!draw_border_)
- return;
+void Textfield::SetCursorEnabled(bool enabled) {
+ GetRenderText()->SetCursorEnabled(enabled);
+}
+
+const gfx::FontList& Textfield::GetFontList() const {
+ return GetRenderText()->font_list();
+}
- draw_border_ = false;
- if (native_wrapper_)
- native_wrapper_->UpdateBorder();
+void Textfield::SetFontList(const gfx::FontList& font_list) {
+ GetRenderText()->SetFontList(font_list);
+ OnCaretBoundsChanged();
+ PreferredSizeChanged();
}
base::string16 Textfield::GetPlaceholderText() const {
return placeholder_text_;
}
-bool Textfield::GetHorizontalMargins(int* left, int* right) {
- if (!horizontal_margins_were_set_)
- return false;
-
- *left = margins_.left();
- *right = margins_.right();
- return true;
+gfx::HorizontalAlignment Textfield::GetHorizontalAlignment() const {
+ return GetRenderText()->horizontal_alignment();
}
-bool Textfield::GetVerticalMargins(int* top, int* bottom) {
- if (!vertical_margins_were_set_)
- return false;
-
- *top = margins_.top();
- *bottom = margins_.bottom();
- return true;
+void Textfield::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
+ GetRenderText()->SetHorizontalAlignment(alignment);
}
-void Textfield::UpdateAllProperties() {
- if (native_wrapper_) {
- native_wrapper_->UpdateText();
- native_wrapper_->UpdateTextColor();
- native_wrapper_->UpdateBackgroundColor();
- native_wrapper_->UpdateReadOnly();
- native_wrapper_->UpdateFont();
- native_wrapper_->UpdateEnabled();
- native_wrapper_->UpdateBorder();
- native_wrapper_->UpdateIsObscured();
- native_wrapper_->UpdateHorizontalMargins();
- native_wrapper_->UpdateVerticalMargins();
- }
-}
-
-void Textfield::SyncText() {
- if (native_wrapper_) {
- string16 new_text = native_wrapper_->GetText();
- if (new_text != text_) {
- text_ = new_text;
- if (controller_)
- controller_->ContentsChanged(this, text_);
- }
- }
+void Textfield::ShowImeIfNeeded() {
+ if (enabled() && !read_only())
+ GetInputMethod()->ShowImeIfNeeded();
}
bool Textfield::IsIMEComposing() const {
- return native_wrapper_ && native_wrapper_->IsIMEComposing();
+ return model_->HasCompositionText();
}
-gfx::Range Textfield::GetSelectedRange() const {
- return native_wrapper_->GetSelectedRange();
+const gfx::Range& Textfield::GetSelectedRange() const {
+ return GetRenderText()->selection();
}
void Textfield::SelectRange(const gfx::Range& range) {
- native_wrapper_->SelectRange(range);
+ model_->SelectRange(range);
+ UpdateAfterChange(false, true);
}
-gfx::SelectionModel Textfield::GetSelectionModel() const {
- return native_wrapper_->GetSelectionModel();
+const gfx::SelectionModel& Textfield::GetSelectionModel() const {
+ return GetRenderText()->selection_model();
}
void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
- native_wrapper_->SelectSelectionModel(sel);
+ model_->SelectSelectionModel(sel);
+ UpdateAfterChange(false, true);
}
size_t Textfield::GetCursorPosition() const {
- return native_wrapper_->GetCursorPosition();
+ return model_->GetCursorPosition();
}
void Textfield::SetColor(SkColor value) {
- return native_wrapper_->SetColor(value);
+ GetRenderText()->SetColor(value);
+ SchedulePaint();
}
void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
- return native_wrapper_->ApplyColor(value, range);
+ GetRenderText()->ApplyColor(value, range);
+ SchedulePaint();
}
void Textfield::SetStyle(gfx::TextStyle style, bool value) {
- return native_wrapper_->SetStyle(style, value);
+ GetRenderText()->SetStyle(style, value);
+ SchedulePaint();
}
void Textfield::ApplyStyle(gfx::TextStyle style,
bool value,
const gfx::Range& range) {
- return native_wrapper_->ApplyStyle(style, value, range);
+ GetRenderText()->ApplyStyle(style, value, range);
+ SchedulePaint();
}
void Textfield::ClearEditHistory() {
- native_wrapper_->ClearEditHistory();
+ model_->ClearEditHistory();
}
-void Textfield::SetAccessibleName(const string16& name) {
+void Textfield::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
void Textfield::ExecuteCommand(int command_id) {
- native_wrapper_->ExecuteTextCommand(command_id);
+ ExecuteCommand(command_id, ui::EF_NONE);
}
void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
@@ -413,101 +531,360 @@ void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
}
bool Textfield::HasTextBeingDragged() {
- return native_wrapper_->HasTextBeingDragged();
+ return initiating_drag_;
}
////////////////////////////////////////////////////////////////////////////////
// Textfield, View overrides:
-void Textfield::Layout() {
- if (native_wrapper_) {
- native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds());
- native_wrapper_->GetView()->Layout();
- }
+int Textfield::GetBaseline() const {
+ return GetInsets().top() + GetRenderText()->GetBaseline();
}
-int Textfield::GetBaseline() const {
- gfx::Insets insets = GetTextInsets();
- const int baseline = native_wrapper_ ?
- native_wrapper_->GetTextfieldBaseline() : font_list_.GetBaseline();
- return insets.top() + baseline;
+gfx::Size Textfield::GetPreferredSize() const {
+ const gfx::Insets& insets = GetInsets();
+ return gfx::Size(GetFontList().GetExpectedTextWidth(default_width_in_chars_) +
+ insets.width(), GetFontList().GetHeight() + insets.height());
}
-gfx::Size Textfield::GetPreferredSize() {
- gfx::Insets insets = GetTextInsets();
+const char* Textfield::GetClassName() const {
+ return kViewClassName;
+}
- const int font_height = native_wrapper_ ? native_wrapper_->GetFontHeight() :
- font_list_.GetHeight();
- return gfx::Size(
- GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_)
- + insets.width(),
- font_height + insets.height());
+gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) {
+ bool in_selection = GetRenderText()->IsPointInSelection(event.location());
+ bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
+ bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
+ return text_cursor ? GetNativeIBeamCursor() : gfx::kNullCursor;
}
-void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
- SelectAll(false);
+bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
+ TrackMouseClicks(event);
+
+ if (!controller_ || !controller_->HandleMouseEvent(this, event)) {
+ if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) {
+ RequestFocus();
+ ShowImeIfNeeded();
+ }
+
+ if (event.IsOnlyLeftMouseButton()) {
+ OnBeforeUserAction();
+ initiating_drag_ = false;
+ switch (aggregated_clicks_) {
+ case 0:
+ if (GetRenderText()->IsPointInSelection(event.location()))
+ initiating_drag_ = true;
+ else
+ MoveCursorTo(event.location(), event.IsShiftDown());
+ break;
+ case 1:
+ model_->MoveCursorTo(event.location(), false);
+ model_->SelectWord();
+ UpdateAfterChange(false, true);
+ double_click_word_ = GetRenderText()->selection();
+ break;
+ case 2:
+ SelectAll(false);
+ break;
+ default:
+ NOTREACHED();
+ }
+ OnAfterUserAction();
+ }
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (event.IsOnlyMiddleMouseButton()) {
+ if (GetRenderText()->IsPointInSelection(event.location())) {
+ OnBeforeUserAction();
+ ClearSelection();
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16());
+ OnAfterUserAction();
+ } else if(!read_only()) {
+ PasteSelectionClipboard(event);
+ }
+ }
+#endif
+ }
+
+ return true;
}
-bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
- // Skip any accelerator handling of backspace; textfields handle this key.
- // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes.
- return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode();
+bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
+ last_drag_location_ = event.location();
+
+ // Don't adjust the cursor on a potential drag and drop, or if the mouse
+ // movement from the last mouse click does not exceed the drag threshold.
+ if (initiating_drag_ || !event.IsOnlyLeftMouseButton() ||
+ !ExceededDragThreshold(last_drag_location_ - last_click_location_)) {
+ return true;
+ }
+
+ // A timer is used to continuously scroll while selecting beyond side edges.
+ if ((event.location().x() > 0 && event.location().x() < size().width()) ||
+ GetDragSelectionDelay() == 0) {
+ drag_selection_timer_.Stop();
+ SelectThroughLastDragLocation();
+ } else if (!drag_selection_timer_.IsRunning()) {
+ drag_selection_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()),
+ this, &Textfield::SelectThroughLastDragLocation);
+ }
+
+ return true;
}
-void Textfield::OnPaint(gfx::Canvas* canvas) {
- View::OnPaint(canvas);
- if (NativeViewHost::kRenderNativeControlFocus)
- Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
+void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
+ OnBeforeUserAction();
+ drag_selection_timer_.Stop();
+ // Cancel suspected drag initiations, the user was clicking in the selection.
+ if (initiating_drag_)
+ MoveCursorTo(event.location(), false);
+ initiating_drag_ = false;
+ UpdateSelectionClipboard();
+ OnAfterUserAction();
+}
+
+bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
+ bool handled = controller_ && controller_->HandleKeyEvent(this, event);
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
+ ui::GetTextEditKeyBindingsDelegate();
+ std::vector<ui::TextEditCommandAuraLinux> commands;
+ if (!handled && delegate && delegate->MatchEvent(event, &commands)) {
+ const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ for (size_t i = 0; i < commands.size(); ++i) {
+ const int command = GetViewsCommand(commands[i], rtl);
+ if (IsCommandIdEnabled(command)) {
+ ExecuteCommand(command);
+ handled = true;
+ }
+ }
+ return handled;
+ }
+#endif
+
+ const int command = GetCommandForKeyEvent(event, HasSelection());
+ if (!handled && IsCommandIdEnabled(command)) {
+ ExecuteCommand(command);
+ handled = true;
+ }
+ return handled;
+}
+
+ui::TextInputClient* Textfield::GetTextInputClient() {
+ return read_only_ ? NULL : this;
+}
+
+void Textfield::OnGestureEvent(ui::GestureEvent* event) {
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ OnBeforeUserAction();
+ RequestFocus();
+ ShowImeIfNeeded();
+
+ // We don't deselect if the point is in the selection
+ // because TAP_DOWN may turn into a LONG_PRESS.
+ if (!GetRenderText()->IsPointInSelection(event->location()))
+ MoveCursorTo(event->location(), false);
+ OnAfterUserAction();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ OnBeforeUserAction();
+ MoveCursorTo(event->location(), true);
+ OnAfterUserAction();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_SCROLL_END:
+ case ui::ET_SCROLL_FLING_START:
+ CreateTouchSelectionControllerAndNotifyIt();
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_TAP:
+ if (event->details().tap_count() == 1) {
+ CreateTouchSelectionControllerAndNotifyIt();
+ } else {
+ DestroyTouchSelection();
+ OnBeforeUserAction();
+ SelectAll(false);
+ OnAfterUserAction();
+ event->SetHandled();
+ }
+#if defined(OS_WIN)
+ if (!read_only())
+ base::win::DisplayVirtualKeyboard();
+#endif
+ break;
+ case ui::ET_GESTURE_LONG_PRESS:
+ // If long press happens outside selection, select word and show context
+ // menu (If touch selection is enabled, context menu is shown by the
+ // |touch_selection_controller_|, hence we mark the event handled.
+ // Otherwise, the regular context menu will be shown by views).
+ // If long press happens in selected text and touch drag drop is enabled,
+ // we will turn off touch selection (if one exists) and let views do drag
+ // drop.
+ if (!GetRenderText()->IsPointInSelection(event->location())) {
+ OnBeforeUserAction();
+ model_->SelectWord();
+ touch_selection_controller_.reset(
+ ui::TouchSelectionController::create(this));
+ UpdateAfterChange(false, true);
+ OnAfterUserAction();
+ if (touch_selection_controller_)
+ event->SetHandled();
+ } else if (switches::IsTouchDragDropEnabled()) {
+ initiating_drag_ = true;
+ DestroyTouchSelection();
+ } else {
+ if (!touch_selection_controller_)
+ CreateTouchSelectionControllerAndNotifyIt();
+ if (touch_selection_controller_)
+ event->SetHandled();
+ }
+ return;
+ case ui::ET_GESTURE_LONG_TAP:
+ if (!touch_selection_controller_)
+ CreateTouchSelectionControllerAndNotifyIt();
+
+ // If touch selection is enabled, the context menu on long tap will be
+ // shown by the |touch_selection_controller_|, hence we mark the event
+ // handled so views does not try to show context menu on it.
+ if (touch_selection_controller_)
+ event->SetHandled();
+ break;
+ default:
+ return;
+ }
}
-bool Textfield::OnKeyPressed(const ui::KeyEvent& e) {
- return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
+void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
+ SelectAll(false);
}
-bool Textfield::OnKeyReleased(const ui::KeyEvent& e) {
- return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
+bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Skip any accelerator handling that conflicts with custom keybindings.
+ ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
+ ui::GetTextEditKeyBindingsDelegate();
+ std::vector<ui::TextEditCommandAuraLinux> commands;
+ if (delegate && delegate->MatchEvent(event, &commands)) {
+ const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ for (size_t i = 0; i < commands.size(); ++i)
+ if (IsCommandIdEnabled(GetViewsCommand(commands[i], rtl)))
+ return true;
+ }
+#endif
+
+ // Skip backspace accelerator handling; editable textfields handle this key.
+ // Also skip processing Windows [Alt]+<num-pad digit> Unicode alt-codes.
+ const bool is_backspace = event.key_code() == ui::VKEY_BACK;
+ return (is_backspace && !read_only()) || event.IsUnicodeKeyCode();
}
-bool Textfield::OnMouseDragged(const ui::MouseEvent& e) {
- if (!e.IsOnlyRightMouseButton())
- return View::OnMouseDragged(e);
+bool Textfield::GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ if (!enabled() || read_only())
+ return false;
+ // TODO(msw): Can we support URL, FILENAME, etc.?
+ *formats = ui::OSExchangeData::STRING;
+ if (controller_)
+ controller_->AppendDropFormats(formats, custom_formats);
return true;
}
-void Textfield::OnFocus() {
- if (native_wrapper_)
- native_wrapper_->HandleFocus();
+bool Textfield::CanDrop(const OSExchangeData& data) {
+ int formats;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+ GetDropFormats(&formats, &custom_formats);
+ return enabled() && !read_only() &&
+ data.HasAnyFormat(formats, custom_formats);
+}
+
+int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
+ DCHECK(CanDrop(event.data()));
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::Range& selection = render_text->selection();
+ drop_cursor_position_ = render_text->FindCursorPosition(event.location());
+ bool in_selection = !selection.is_empty() &&
+ selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
+ drop_cursor_visible_ = !in_selection;
+ // TODO(msw): Pan over text when the user drags to the visible text edge.
+ OnCaretBoundsChanged();
+ SchedulePaint();
- // Forward the focus to the wrapper if it exists.
- if (!native_wrapper_ || !native_wrapper_->SetFocus()) {
- // If there is no wrapper or the wrapper didn't take focus, call
- // View::Focus to clear the native focus so that we still get
- // keyboard messages.
- View::OnFocus();
+ if (initiating_drag_) {
+ if (in_selection)
+ return ui::DragDropTypes::DRAG_NONE;
+ return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
+ ui::DragDropTypes::DRAG_MOVE;
}
+ return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+}
- // Border typically draws focus indicator.
+void Textfield::OnDragExited() {
+ drop_cursor_visible_ = false;
SchedulePaint();
}
-void Textfield::OnBlur() {
- if (native_wrapper_)
- native_wrapper_->HandleBlur();
+int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
+ DCHECK(CanDrop(event.data()));
+ drop_cursor_visible_ = false;
- // Border typically draws focus indicator.
- SchedulePaint();
+ if (controller_) {
+ int drag_operation = controller_->OnDrop(event.data());
+ if (drag_operation != ui::DragDropTypes::DRAG_NONE)
+ return drag_operation;
+ }
+
+ gfx::RenderText* render_text = GetRenderText();
+ DCHECK(!initiating_drag_ ||
+ !render_text->IsPointInSelection(event.location()));
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+
+ gfx::SelectionModel drop_destination_model =
+ render_text->FindCursorPosition(event.location());
+ base::string16 new_text;
+ event.data().GetString(&new_text);
+
+ // Delete the current selection for a drag and drop within this view.
+ const bool move = initiating_drag_ && !event.IsControlDown() &&
+ event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
+ if (move) {
+ // Adjust the drop destination if it is on or after the current selection.
+ size_t pos = drop_destination_model.caret_pos();
+ pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
+ model_->DeleteSelectionAndInsertTextAt(new_text, pos);
+ } else {
+ model_->MoveCursorTo(drop_destination_model);
+ // Drop always inserts text even if the textfield is not in insert mode.
+ model_->InsertText(new_text);
+ }
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+ return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
+}
+
+void Textfield::OnDragDone() {
+ initiating_drag_ = false;
+ drop_cursor_visible_ = false;
}
-void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_TEXT;
+void Textfield::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TEXT_FIELD;
state->name = accessible_name_;
if (read_only())
- state->state |= ui::AccessibilityTypes::STATE_READONLY;
- if (IsObscured())
- state->state |= ui::AccessibilityTypes::STATE_PROTECTED;
- state->value = text_;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
+ state->AddStateFlag(ui::AX_STATE_PROTECTED);
+ state->value = text();
- const gfx::Range range = native_wrapper_->GetSelectedRange();
+ const gfx::Range range = GetSelectedRange();
state->selection_start = range.start();
state->selection_end = range.end();
@@ -518,61 +895,881 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
}
}
-ui::TextInputClient* Textfield::GetTextInputClient() {
- return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL;
+void Textfield::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ GetRenderText()->SetDisplayRect(GetContentsBounds());
+ OnCaretBoundsChanged();
+}
+
+void Textfield::OnEnabledChanged() {
+ View::OnEnabledChanged();
+ if (GetInputMethod())
+ GetInputMethod()->OnTextInputTypeChanged(this);
+ SchedulePaint();
+}
+
+void Textfield::OnPaint(gfx::Canvas* canvas) {
+ OnPaintBackground(canvas);
+ PaintTextAndCursor(canvas);
+ OnPaintBorder(canvas);
+}
+
+void Textfield::OnFocus() {
+ GetRenderText()->set_focused(true);
+ cursor_visible_ = true;
+ SchedulePaint();
+ GetInputMethod()->OnFocus();
+ OnCaretBoundsChanged();
+
+ const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
+ if (caret_blink_ms != 0) {
+ cursor_repaint_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(caret_blink_ms), this,
+ &Textfield::UpdateCursor);
+ }
+
+ View::OnFocus();
+ SchedulePaint();
+}
+
+void Textfield::OnBlur() {
+ GetRenderText()->set_focused(false);
+ GetInputMethod()->OnBlur();
+ cursor_repaint_timer_.Stop();
+ if (cursor_visible_) {
+ cursor_visible_ = false;
+ RepaintCursor();
+ }
+
+ DestroyTouchSelection();
+
+ // Border typically draws focus indicator.
+ SchedulePaint();
}
gfx::Point Textfield::GetKeyboardContextMenuLocation() {
- return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() :
- View::GetKeyboardContextMenuLocation();
+ return GetCaretBounds().bottom_right();
}
-void Textfield::OnEnabledChanged() {
- View::OnEnabledChanged();
- if (native_wrapper_)
- native_wrapper_->UpdateEnabled();
+void Textfield::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ gfx::RenderText* render_text = GetRenderText();
+ render_text->SetColor(GetTextColor());
+ UpdateBackgroundColor();
+ render_text->set_cursor_color(GetTextColor());
+ render_text->set_selection_color(GetSelectionTextColor());
+ render_text->set_selection_background_focused_color(
+ GetSelectionBackgroundColor());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, TextfieldModel::Delegate overrides:
+
+void Textfield::OnCompositionTextConfirmedOrCleared() {
+ if (!skip_input_method_cancel_composition_)
+ GetInputMethod()->CancelComposition(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ContextMenuController overrides:
+
+void Textfield::ShowContextMenuForView(View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) {
+ UpdateContextMenu();
+ ignore_result(context_menu_runner_->RunMenuAt(
+ GetWidget(),
+ NULL,
+ gfx::Rect(point, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT,
+ source_type,
+ MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, DragController overrides:
+
+void Textfield::WriteDragDataForView(View* sender,
+ const gfx::Point& press_pt,
+ OSExchangeData* data) {
+ const base::string16& selected_text(GetSelectedText());
+ data->SetString(selected_text);
+ Label label(selected_text, GetFontList());
+ label.SetBackgroundColor(GetBackgroundColor());
+ label.set_subpixel_rendering_enabled(false);
+ gfx::Size size(label.GetPreferredSize());
+ gfx::NativeView native_view = GetWidget()->GetNativeView();
+ gfx::Display display = gfx::Screen::GetScreenFor(native_view)->
+ GetDisplayNearestWindow(native_view);
+ size.SetToMin(gfx::Size(display.size().width(), height()));
+ label.SetBoundsRect(gfx::Rect(size));
+ scoped_ptr<gfx::Canvas> canvas(
+ GetCanvasForDragImage(GetWidget(), label.size()));
+ label.SetEnabledColor(GetTextColor());
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Desktop Linux Aura does not yet support transparency in drag images.
+ canvas->DrawColor(GetBackgroundColor());
+#endif
+ label.Paint(canvas.get(), views::CullSet());
+ const gfx::Vector2d kOffset(-15, 0);
+ drag_utils::SetDragImageOnDataObject(*canvas, kOffset, data);
+ if (controller_)
+ controller_->OnWriteDragData(data);
+}
+
+int Textfield::GetDragOperationsForView(View* sender, const gfx::Point& p) {
+ int drag_operations = ui::DragDropTypes::DRAG_COPY;
+ if (!enabled() || text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD ||
+ !GetRenderText()->IsPointInSelection(p)) {
+ drag_operations = ui::DragDropTypes::DRAG_NONE;
+ } else if (sender == this && !read_only()) {
+ drag_operations =
+ ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
+ }
+ if (controller_)
+ controller_->OnGetDragOperationsForTextfield(&drag_operations);
+ return drag_operations;
}
-void Textfield::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && !native_wrapper_ && GetWidget()) {
- // The native wrapper's lifetime will be managed by the view hierarchy after
- // we call AddChildView.
- native_wrapper_ = NativeTextfieldWrapper::CreateWrapper(this);
- AddChildViewAt(native_wrapper_->GetView(), 0);
- Layout();
- UpdateAllProperties();
+bool Textfield::CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) {
+ return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ui::TouchEditable overrides:
+
+void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
+ gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
+ gfx::SelectionModel selection(
+ gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
+ end_caret.caret_affinity());
+
+ OnBeforeUserAction();
+ SelectSelectionModel(selection);
+ OnAfterUserAction();
+}
+
+void Textfield::MoveCaretTo(const gfx::Point& point) {
+ SelectRect(point, point);
+}
+
+void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) {
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::SelectionModel& sel = render_text->selection_model();
+ gfx::SelectionModel start_sel =
+ render_text->GetSelectionModelForSelectionStart();
+ *p1 = render_text->GetCursorBounds(start_sel, true);
+ *p2 = render_text->GetCursorBounds(sel, true);
+}
+
+gfx::Rect Textfield::GetBounds() {
+ return GetLocalBounds();
+}
+
+gfx::NativeView Textfield::GetNativeView() const {
+ return GetWidget()->GetNativeView();
+}
+
+void Textfield::ConvertPointToScreen(gfx::Point* point) {
+ View::ConvertPointToScreen(this, point);
+}
+
+void Textfield::ConvertPointFromScreen(gfx::Point* point) {
+ View::ConvertPointFromScreen(this, point);
+}
+
+bool Textfield::DrawsHandles() {
+ return false;
+}
+
+void Textfield::OpenContextMenu(const gfx::Point& anchor) {
+ DestroyTouchSelection();
+ ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
+}
+
+void Textfield::DestroyTouchSelection() {
+ touch_selection_controller_.reset();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, ui::SimpleMenuModel::Delegate overrides:
+
+bool Textfield::IsCommandIdChecked(int command_id) const {
+ return true;
+}
+
+bool Textfield::IsCommandIdEnabled(int command_id) const {
+ base::string16 result;
+ bool editable = !read_only();
+ bool readable = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD;
+ switch (command_id) {
+ case IDS_APP_UNDO:
+ return editable && model_->CanUndo();
+ case IDS_APP_REDO:
+ return editable && model_->CanRedo();
+ case IDS_APP_CUT:
+ return editable && readable && model_->HasSelection();
+ case IDS_APP_COPY:
+ return readable && model_->HasSelection();
+ case IDS_APP_PASTE:
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
+ return editable && !result.empty();
+ case IDS_APP_DELETE:
+ return editable && model_->HasSelection();
+ case IDS_APP_SELECT_ALL:
+ return !text().empty();
+ case IDS_DELETE_FORWARD:
+ case IDS_DELETE_BACKWARD:
+ case IDS_DELETE_TO_BEGINNING_OF_LINE:
+ case IDS_DELETE_TO_END_OF_LINE:
+ case IDS_DELETE_WORD_BACKWARD:
+ case IDS_DELETE_WORD_FORWARD:
+ return editable;
+ case IDS_MOVE_LEFT:
+ case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_RIGHT:
+ case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_WORD_LEFT:
+ case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_WORD_RIGHT:
+ case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
+ case IDS_MOVE_TO_BEGINNING_OF_LINE:
+ case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
+ case IDS_MOVE_TO_END_OF_LINE:
+ case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
+ return true;
+ default:
+ return false;
}
}
-const char* Textfield::GetClassName() const {
- return kViewClassName;
+bool Textfield::GetAcceleratorForCommandId(int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void Textfield::ExecuteCommand(int command_id, int event_flags) {
+ DestroyTouchSelection();
+ if (!IsCommandIdEnabled(command_id))
+ return;
+
+ bool text_changed = false;
+ bool cursor_changed = false;
+ bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
+ gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT;
+ gfx::SelectionModel selection_model = GetSelectionModel();
+
+ OnBeforeUserAction();
+ switch (command_id) {
+ case IDS_APP_UNDO:
+ text_changed = cursor_changed = model_->Undo();
+ break;
+ case IDS_APP_REDO:
+ text_changed = cursor_changed = model_->Redo();
+ break;
+ case IDS_APP_CUT:
+ text_changed = cursor_changed = Cut();
+ break;
+ case IDS_APP_COPY:
+ Copy();
+ break;
+ case IDS_APP_PASTE:
+ text_changed = cursor_changed = Paste();
+ break;
+ case IDS_APP_DELETE:
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_APP_SELECT_ALL:
+ SelectAll(false);
+ break;
+ case IDS_DELETE_BACKWARD:
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_FORWARD:
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_DELETE_TO_END_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, end, true);
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_DELETE_TO_BEGINNING_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, true);
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_WORD_BACKWARD:
+ model_->MoveCursor(gfx::WORD_BREAK, begin, true);
+ text_changed = cursor_changed = model_->Backspace();
+ break;
+ case IDS_DELETE_WORD_FORWARD:
+ model_->MoveCursor(gfx::WORD_BREAK, end, true);
+ text_changed = cursor_changed = model_->Delete();
+ break;
+ case IDS_MOVE_LEFT:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ break;
+ case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ break;
+ case IDS_MOVE_RIGHT:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ break;
+ case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ break;
+ case IDS_MOVE_WORD_LEFT:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
+ break;
+ case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ break;
+ case IDS_MOVE_WORD_RIGHT:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ break;
+ case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ break;
+ case IDS_MOVE_TO_BEGINNING_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, false);
+ break;
+ case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, true);
+ break;
+ case IDS_MOVE_TO_END_OF_LINE:
+ model_->MoveCursor(gfx::LINE_BREAK, end, false);
+ break;
+ case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, end, true);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ cursor_changed |= GetSelectionModel() != selection_model;
+ if (cursor_changed)
+ UpdateSelectionClipboard();
+ UpdateAfterChange(text_changed, cursor_changed);
+ OnAfterUserAction();
}
////////////////////////////////////////////////////////////////////////////////
-// Textfield, private:
+// Textfield, ui::TextInputClient overrides:
+
+void Textfield::SetCompositionText(const ui::CompositionText& composition) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->SetCompositionText(composition);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::ConfirmCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->ConfirmCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::ClearCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->CancelCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::InsertText(const base::string16& new_text) {
+ // TODO(suzhe): Filter invalid characters.
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (GetRenderText()->insert_mode())
+ model_->InsertText(new_text);
+ else
+ model_->ReplaceText(new_text);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void Textfield::InsertChar(base::char16 ch, int flags) {
+ const int kControlModifierMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
+ ui::EF_COMMAND_DOWN | ui::EF_ALTGR_DOWN |
+ ui::EF_MOD3_DOWN;
+
+ // Filter out all control characters, including tab and new line characters,
+ // and all characters with Alt modifier. But allow characters with the AltGr
+ // modifier. On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a
+ // different flag that we don't care about.
+ const bool should_insert_char =
+ ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
+ (flags & kControlModifierMask) != ui::EF_ALT_DOWN;
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char)
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (GetRenderText()->insert_mode())
+ model_->InsertChar(ch);
+ else
+ model_->ReplaceChar(ch);
+ skip_input_method_cancel_composition_ = false;
+
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD &&
+ password_reveal_duration_ != base::TimeDelta()) {
+ const size_t change_offset = model_->GetCursorPosition();
+ DCHECK_GT(change_offset, 0u);
+ RevealPasswordChar(change_offset - 1);
+ }
+}
+
+gfx::NativeWindow Textfield::GetAttachedWindow() const {
+ // Imagine the following hierarchy.
+ // [NativeWidget A] - FocusManager
+ // [View]
+ // [NativeWidget B]
+ // [View]
+ // [View X]
+ // An important thing is that [NativeWidget A] owns Win32 input focus even
+ // when [View X] is logically focused by FocusManager. As a result, an Win32
+ // IME may want to interact with the native view of [NativeWidget A] rather
+ // than that of [NativeWidget B]. This is why we need to call
+ // GetTopLevelWidget() here.
+ return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
+}
+
+ui::TextInputType Textfield::GetTextInputType() const {
+ if (read_only() || !enabled())
+ return ui::TEXT_INPUT_TYPE_NONE;
+ return text_input_type_;
+}
+
+ui::TextInputMode Textfield::GetTextInputMode() const {
+ return ui::TEXT_INPUT_MODE_DEFAULT;
+}
+
+bool Textfield::CanComposeInline() const {
+ return true;
+}
+
+gfx::Rect Textfield::GetCaretBounds() const {
+ gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
+ ConvertRectToScreen(this, &rect);
+ return rect;
+}
+
+bool Textfield::GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const {
+ DCHECK(rect);
+ if (!HasCompositionText())
+ return false;
+ gfx::RenderText* render_text = GetRenderText();
+ const gfx::Range& composition_range = render_text->GetCompositionRange();
+ DCHECK(!composition_range.is_empty());
+
+ size_t text_index = composition_range.start() + index;
+ if (composition_range.end() <= text_index)
+ return false;
+ if (!render_text->IsValidCursorIndex(text_index)) {
+ text_index = render_text->IndexOfAdjacentGrapheme(
+ text_index, gfx::CURSOR_BACKWARD);
+ }
+ if (text_index < composition_range.start())
+ return false;
+ const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
+ *rect = render_text->GetCursorBounds(caret, false);
+ ConvertRectToScreen(this, rect);
+ return true;
+}
+
+bool Textfield::HasCompositionText() const {
+ return model_->HasCompositionText();
+}
+
+bool Textfield::GetTextRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+
+ model_->GetTextRange(range);
+ return true;
+}
+
+bool Textfield::GetCompositionTextRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+
+ model_->GetCompositionTextRange(range);
+ return true;
+}
-gfx::Insets Textfield::GetTextInsets() const {
- gfx::Insets insets = GetInsets();
- if (draw_border_ && native_wrapper_)
- insets += native_wrapper_->CalculateInsets();
- return insets;
+bool Textfield::GetSelectionRange(gfx::Range* range) const {
+ if (!ImeEditingAllowed())
+ return false;
+ *range = GetRenderText()->selection();
+ return true;
+}
+
+bool Textfield::SetSelectionRange(const gfx::Range& range) {
+ if (!ImeEditingAllowed() || !range.IsValid())
+ return false;
+ OnBeforeUserAction();
+ SelectRange(range);
+ OnAfterUserAction();
+ return true;
+}
+
+bool Textfield::DeleteRange(const gfx::Range& range) {
+ if (!ImeEditingAllowed() || range.is_empty())
+ return false;
+
+ OnBeforeUserAction();
+ model_->SelectRange(range);
+ if (model_->HasSelection()) {
+ model_->DeleteSelection();
+ UpdateAfterChange(true, true);
+ }
+ OnAfterUserAction();
+ return true;
+}
+
+bool Textfield::GetTextFromRange(const gfx::Range& range,
+ base::string16* range_text) const {
+ if (!ImeEditingAllowed() || !range.IsValid())
+ return false;
+
+ gfx::Range text_range;
+ if (!GetTextRange(&text_range) || !text_range.Contains(range))
+ return false;
+
+ *range_text = model_->GetTextFromRange(range);
+ return true;
+}
+
+void Textfield::OnInputMethodChanged() {}
+
+bool Textfield::ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) {
+ // Restore text directionality mode when the indicated direction matches the
+ // current forced mode; otherwise, force the mode indicated. This helps users
+ // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
+ const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
+ gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
+ if (mode == GetRenderText()->directionality_mode())
+ GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
+ else
+ GetRenderText()->SetDirectionalityMode(mode);
+ SchedulePaint();
+ return true;
}
-void Textfield::AccessibilitySetValue(const string16& new_value) {
+void Textfield::ExtendSelectionAndDelete(size_t before, size_t after) {
+ gfx::Range range = GetRenderText()->selection();
+ DCHECK_GE(range.start(), before);
+
+ range.set_start(range.start() - before);
+ range.set_end(range.end() + after);
+ gfx::Range text_range;
+ if (GetTextRange(&text_range) && text_range.Contains(range))
+ DeleteRange(range);
+}
+
+void Textfield::EnsureCaretInRect(const gfx::Rect& rect) {}
+
+void Textfield::OnCandidateWindowShown() {}
+
+void Textfield::OnCandidateWindowUpdated() {}
+
+void Textfield::OnCandidateWindowHidden() {}
+
+bool Textfield::IsEditingCommandEnabled(int command_id) {
+ return IsCommandIdEnabled(command_id);
+}
+
+void Textfield::ExecuteEditingCommand(int command_id) {
+ ExecuteCommand(command_id);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, protected:
+
+gfx::RenderText* Textfield::GetRenderText() const {
+ return model_->render_text();
+}
+
+base::string16 Textfield::GetSelectionClipboardText() const {
+ base::string16 selection_clipboard_text;
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::CLIPBOARD_TYPE_SELECTION, &selection_clipboard_text);
+ return selection_clipboard_text;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, private:
+
+void Textfield::AccessibilitySetValue(const base::string16& new_value) {
if (!read_only()) {
SetText(new_value);
ClearSelection();
}
}
-////////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldWrapper, public:
+void Textfield::UpdateBackgroundColor() {
+ const SkColor color = GetBackgroundColor();
+ set_background(Background::CreateSolidBackground(color));
+ GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
+ SchedulePaint();
+}
-// static
-NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper(
- Textfield* field) {
- return new NativeTextfieldViews(field);
+void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
+ if (text_changed) {
+ if (controller_)
+ controller_->ContentsChanged(this, text());
+ NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
+ }
+ if (cursor_changed) {
+ cursor_visible_ = true;
+ RepaintCursor();
+ if (cursor_repaint_timer_.IsRunning())
+ cursor_repaint_timer_.Reset();
+ if (!text_changed) {
+ // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
+ // this if only the selection changed.
+ NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_CHANGED, true);
+ }
+ }
+ if (text_changed || cursor_changed) {
+ OnCaretBoundsChanged();
+ SchedulePaint();
+ }
+}
+
+void Textfield::UpdateCursor() {
+ const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
+ cursor_visible_ = !cursor_visible_ || (caret_blink_ms == 0);
+ RepaintCursor();
+}
+
+void Textfield::RepaintCursor() {
+ gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
+ r.Inset(-1, -1, -1, -1);
+ SchedulePaintInRect(r);
+}
+
+void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
+ TRACE_EVENT0("views", "Textfield::PaintTextAndCursor");
+ canvas->Save();
+
+ // Draw placeholder text if needed.
+ gfx::RenderText* render_text = GetRenderText();
+ if (text().empty() && !GetPlaceholderText().empty()) {
+ canvas->DrawStringRect(GetPlaceholderText(), GetFontList(),
+ placeholder_text_color(), render_text->display_rect());
+ }
+
+ // Draw the text, cursor, and selection.
+ render_text->set_cursor_visible(cursor_visible_ && !drop_cursor_visible_ &&
+ !HasSelection());
+ render_text->Draw(canvas);
+
+ // Draw the detached drop cursor that marks where the text will be dropped.
+ if (drop_cursor_visible_)
+ render_text->DrawCursor(canvas, drop_cursor_position_);
+
+ canvas->Restore();
+}
+
+void Textfield::MoveCursorTo(const gfx::Point& point, bool select) {
+ if (model_->MoveCursorTo(point, select))
+ UpdateAfterChange(false, true);
+}
+
+void Textfield::SelectThroughLastDragLocation() {
+ OnBeforeUserAction();
+ model_->MoveCursorTo(last_drag_location_, true);
+ if (aggregated_clicks_ == 1) {
+ model_->SelectWord();
+ // Expand the selection so the initially selected word remains selected.
+ gfx::Range selection = GetRenderText()->selection();
+ const size_t min = std::min(selection.GetMin(),
+ double_click_word_.GetMin());
+ const size_t max = std::max(selection.GetMax(),
+ double_click_word_.GetMax());
+ const bool reversed = selection.is_reversed();
+ selection.set_start(reversed ? max : min);
+ selection.set_end(reversed ? min : max);
+ model_->SelectRange(selection);
+ }
+ UpdateAfterChange(false, true);
+ OnAfterUserAction();
+}
+
+void Textfield::OnCaretBoundsChanged() {
+ if (GetInputMethod())
+ GetInputMethod()->OnCaretBoundsChanged(this);
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+}
+
+void Textfield::OnBeforeUserAction() {
+ DCHECK(!performing_user_action_);
+ performing_user_action_ = true;
+ if (controller_)
+ controller_->OnBeforeUserAction(this);
+}
+
+void Textfield::OnAfterUserAction() {
+ if (controller_)
+ controller_->OnAfterUserAction(this);
+ DCHECK(performing_user_action_);
+ performing_user_action_ = false;
+}
+
+bool Textfield::Cut() {
+ if (!read_only() && text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD &&
+ model_->Cut()) {
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ return true;
+ }
+ return false;
+}
+
+bool Textfield::Copy() {
+ if (text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD && model_->Copy()) {
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ return true;
+ }
+ return false;
+}
+
+bool Textfield::Paste() {
+ if (!read_only() && model_->Paste()) {
+ if (controller_)
+ controller_->OnAfterPaste();
+ return true;
+ }
+ return false;
+}
+
+void Textfield::UpdateContextMenu() {
+ if (!context_menu_contents_.get()) {
+ context_menu_contents_.reset(new ui::SimpleMenuModel(this));
+ context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
+ context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+ context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
+ IDS_APP_SELECT_ALL);
+ if (controller_)
+ controller_->UpdateContextMenu(context_menu_contents_.get());
+ }
+ context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get()));
+}
+
+void Textfield::TrackMouseClicks(const ui::MouseEvent& event) {
+ if (event.IsOnlyLeftMouseButton()) {
+ base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
+ if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
+ !ExceededDragThreshold(event.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.
+ aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
+ } else {
+ aggregated_clicks_ = 0;
+ }
+ last_click_time_ = event.time_stamp();
+ last_click_location_ = event.location();
+ }
+}
+
+bool Textfield::ImeEditingAllowed() const {
+ // Disallow input method editing of password fields.
+ ui::TextInputType t = GetTextInputType();
+ return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
+}
+
+void Textfield::RevealPasswordChar(int index) {
+ GetRenderText()->SetObscuredRevealIndex(index);
+ SchedulePaint();
+
+ if (index != -1) {
+ password_reveal_timer_.Start(FROM_HERE, password_reveal_duration_,
+ base::Bind(&Textfield::RevealPasswordChar,
+ weak_ptr_factory_.GetWeakPtr(), -1));
+ }
+}
+
+void Textfield::CreateTouchSelectionControllerAndNotifyIt() {
+ if (!touch_selection_controller_) {
+ touch_selection_controller_.reset(
+ ui::TouchSelectionController::create(this));
+ }
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+}
+
+void Textfield::UpdateSelectionClipboard() const {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (performing_user_action_ && HasSelection()) {
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText());
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_SELECTION);
+ }
+#endif
+}
+
+void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) {
+ DCHECK(event.IsOnlyMiddleMouseButton());
+ DCHECK(!read_only());
+ base::string16 selection_clipboard_text = GetSelectionClipboardText();
+ if (!selection_clipboard_text.empty()) {
+ OnBeforeUserAction();
+ gfx::Range range = GetSelectionModel().selection();
+ gfx::LogicalCursorDirection affinity = GetSelectionModel().caret_affinity();
+ const gfx::SelectionModel mouse =
+ GetRenderText()->FindCursorPosition(event.location());
+ model_->MoveCursorTo(mouse);
+ model_->InsertText(selection_clipboard_text);
+ // Update the new selection range as needed.
+ if (range.GetMin() >= mouse.caret_pos()) {
+ const size_t length = selection_clipboard_text.length();
+ range = gfx::Range(range.start() + length, range.end() + length);
+ }
+ model_->MoveCursorTo(gfx::SelectionModel(range, affinity));
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+ }
}
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 307e562c20e..e8361774a94 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -12,103 +12,77 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
+#include "base/timer/timer.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"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/base/touch/touch_editing_controller.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/font_list.h"
-#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/range/range.h"
+#include "ui/gfx/selection_model.h"
#include "ui/gfx/text_constants.h"
-#include "ui/views/controls/textfield/native_textfield_wrapper.h"
+#include "ui/views/context_menu_controller.h"
+#include "ui/views/controls/textfield/textfield_model.h"
+#include "ui/views/drag_controller.h"
#include "ui/views/view.h"
-#if !defined(OS_LINUX)
-#include "base/logging.h"
-#endif
-
-namespace gfx {
-class Range;
-class ImageSkia;
-}
-
-namespace ui {
-class TextInputClient;
-} // namespace ui
-
namespace views {
-class ImageView;
+class MenuRunner;
class Painter;
class TextfieldController;
-// This class implements a View that wraps a native text (edit) field.
-class VIEWS_EXPORT Textfield : public View {
+// A views/skia textfield implementation. No platform-specific code is used.
+class VIEWS_EXPORT Textfield : public View,
+ public TextfieldModel::Delegate,
+ public ContextMenuController,
+ public DragController,
+ public ui::TouchEditable,
+ public ui::TextInputClient {
public:
// The textfield's class name.
static const char kViewClassName[];
- enum StyleFlags {
- STYLE_DEFAULT = 0,
- STYLE_OBSCURED = 1 << 0,
- STYLE_LOWERCASE = 1 << 1
- };
-
// Returns the text cursor blink time in milliseconds, or 0 for no blinking.
static size_t GetCaretBlinkMs();
Textfield();
- explicit Textfield(StyleFlags style);
virtual ~Textfield();
- // TextfieldController accessors
- void SetController(TextfieldController* controller);
- TextfieldController* GetController() const;
+ // Set the controller for this textfield.
+ void set_controller(TextfieldController* controller) {
+ controller_ = controller;
+ }
// Gets/Sets whether or not the Textfield is read-only.
bool read_only() const { return read_only_; }
void SetReadOnly(bool read_only);
- // Gets/sets the STYLE_OBSCURED bit, controlling whether characters in this
- // Textfield are displayed as asterisks/bullets.
- bool IsObscured() const;
- void SetObscured(bool obscured);
-
- // Gets/sets the duration to reveal the last typed char when the obscured bit
- // is set. A duration of zero effectively disables the feature. Other values
- // cause the last typed char to be shown for the defined duration. Note this
- // only works with NativeTextfieldViews.
- const base::TimeDelta& obscured_reveal_duration() const {
- return obscured_reveal_duration_;
- }
- void set_obscured_reveal_duration(const base::TimeDelta& duration) {
- obscured_reveal_duration_ = duration;
- }
-
- // Gets/Sets the input type of this textfield.
- ui::TextInputType GetTextInputType() const;
+ // Sets the input type; displays only asterisks for TEXT_INPUT_TYPE_PASSWORD.
void SetTextInputType(ui::TextInputType type);
- // Gets/Sets the text currently displayed in the Textfield.
- const string16& text() const { return text_; }
+ // Gets the text currently displayed in the Textfield.
+ const base::string16& text() const { return model_->text(); }
// Sets the text currently displayed in the Textfield. This doesn't
// change the cursor position if the current cursor is within the
// new text's range, or moves the cursor to the end if the cursor is
// out of the new text's range.
- void SetText(const string16& text);
+ void SetText(const base::string16& new_text);
// Appends the given string to the previously-existing text in the field.
- void AppendText(const string16& text);
+ void AppendText(const base::string16& new_text);
- // Inserts |text| at the current cursor position, replacing any selected text.
- void InsertOrReplaceText(const string16& text);
+ // Inserts |new_text| at the cursor position, replacing any selected text.
+ void InsertOrReplaceText(const base::string16& new_text);
// Returns the text direction.
base::i18n::TextDirection GetTextDirection() const;
// Returns the text that is currently selected.
- string16 GetSelectedText() const;
+ base::string16 GetSelectedText() const;
// Select the entire text range. If |reversed| is true, the range will end at
// the logical beginning of the text; this generally shows the leading portion
@@ -116,56 +90,51 @@ class VIEWS_EXPORT Textfield : public View {
void SelectAll(bool reversed);
// Clears the selection within the edit field and sets the caret to the end.
- void ClearSelection() const;
+ void ClearSelection();
// Checks if there is any selected text.
bool HasSelection() const;
- // Accessor for |style_|.
- StyleFlags style() const { return style_; }
-
- // Gets/Sets the text color to be used when painting the Textfield.
- // Call |UseDefaultTextColor| to restore the default system color.
+ // Gets/sets the text color to be used when painting the Textfield.
+ // Call UseDefaultTextColor() to restore the default system color.
SkColor GetTextColor() const;
void SetTextColor(SkColor color);
void UseDefaultTextColor();
- // Gets/Sets the background color to be used when painting the Textfield.
- // Call |UseDefaultBackgroundColor| to restore the default system color.
+ // Gets/sets the background color to be used when painting the Textfield.
+ // Call UseDefaultBackgroundColor() to restore the default system color.
SkColor GetBackgroundColor() const;
void SetBackgroundColor(SkColor color);
void UseDefaultBackgroundColor();
+ // Gets/sets the selection text color to be used when painting the Textfield.
+ // Call UseDefaultSelectionTextColor() to restore the default system color.
+ SkColor GetSelectionTextColor() const;
+ void SetSelectionTextColor(SkColor color);
+ void UseDefaultSelectionTextColor();
+
+ // Gets/sets the selection background color to be used when painting the
+ // Textfield. Call UseDefaultSelectionBackgroundColor() to restore the default
+ // system color.
+ SkColor GetSelectionBackgroundColor() const;
+ void SetSelectionBackgroundColor(SkColor color);
+ void UseDefaultSelectionBackgroundColor();
+
// Gets/Sets whether or not the cursor is enabled.
bool GetCursorEnabled() const;
void SetCursorEnabled(bool enabled);
// Gets/Sets the fonts used when rendering the text within the Textfield.
- const gfx::FontList& font_list() const { return font_list_; }
+ const gfx::FontList& GetFontList() const;
void SetFontList(const gfx::FontList& font_list);
- const gfx::Font& GetPrimaryFont() const;
- void SetFont(const gfx::Font& font);
-
- // Sets the left and right margin (in pixels) within the text box. On Windows
- // this is accomplished by packing the left and right margin into a single
- // 32 bit number, so the left and right margins are effectively 16 bits.
- void SetHorizontalMargins(int left, int right);
-
- // Sets the top and bottom margins (in pixels) within the textfield.
- // NOTE: in most cases height could be changed instead.
- void SetVerticalMargins(int top, int bottom);
// 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;
}
- // Removes the border from the edit box, giving it a 2D look.
- bool draw_border() const { return draw_border_; }
- void RemoveBorder();
-
// Sets the text to display when empty.
- void set_placeholder_text(const string16& text) {
+ void set_placeholder_text(const base::string16& text) {
placeholder_text_ = text;
}
virtual base::string16 GetPlaceholderText() const;
@@ -175,59 +144,40 @@ class VIEWS_EXPORT Textfield : public View {
placeholder_text_color_ = color;
}
- // Getter for the horizontal margins that were set. Returns false if
- // horizontal margins weren't set.
- bool GetHorizontalMargins(int* left, int* right);
-
- // Getter for the vertical margins that were set. Returns false if vertical
- // margins weren't set.
- bool GetVerticalMargins(int* top, int* bottom);
+ // Get or set the horizontal alignment used for the button from the underlying
+ // RenderText object.
+ gfx::HorizontalAlignment GetHorizontalAlignment() const;
+ void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
- // Updates all properties on the textfield. This is invoked internally.
- // Users of Textfield never need to invoke this directly.
- void UpdateAllProperties();
-
- // Invoked by the edit control when the value changes. This method set
- // the text_ member variable to the value contained in edit control.
- // This is important because the edit control can be replaced if it has
- // been deleted during a window close.
- void SyncText();
+ // Displays a virtual keyboard or alternate input view if enabled.
+ void ShowImeIfNeeded();
// Returns whether or not an IME is composing text.
bool IsIMEComposing() const;
- // Gets the selected range. This is views-implementation only and
- // has to be called after the wrapper is created.
- // TODO(msw): Return a const reference when NativeTextfieldWin is gone.
- gfx::Range GetSelectedRange() const;
+ // Gets the selected logical text range.
+ const gfx::Range& GetSelectedRange() const;
- // Selects the text given by |range|. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Selects the specified logical text range.
void SelectRange(const gfx::Range& range);
- // Gets the selection model. This is views-implementation only and
- // has to be called after the wrapper is created.
- // TODO(msw): Return a const reference when NativeTextfieldWin is gone.
- gfx::SelectionModel GetSelectionModel() const;
+ // Gets the text selection model.
+ const gfx::SelectionModel& GetSelectionModel() const;
- // Selects the text given by |sel|. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Sets the specified text selection model.
void SelectSelectionModel(const gfx::SelectionModel& sel);
- // Returns the current cursor position. This is views-implementation
- // only and has to be called after the wrapper is created.
+ // Returns the current cursor position.
size_t GetCursorPosition() const;
// Set the text color over the entire text or a logical character range.
- // Empty and invalid ranges are ignored. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Empty and invalid ranges are ignored.
void SetColor(SkColor value);
void ApplyColor(SkColor value, const gfx::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.
- // Empty and invalid ranges are ignored. This is views-implementation only and
- // has to be called after the wrapper is created.
+ // Empty and invalid ranges are ignored.
void SetStyle(gfx::TextStyle style, bool value);
void ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range);
@@ -235,69 +185,201 @@ class VIEWS_EXPORT Textfield : public View {
void ClearEditHistory();
// Set the accessible name of the text field.
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// Performs the action associated with the specified command id.
void ExecuteCommand(int command_id);
void SetFocusPainter(scoped_ptr<Painter> focus_painter);
- // Provided only for testing:
- gfx::NativeView GetTestingHandle() const {
- return native_wrapper_ ? native_wrapper_->GetTestingHandle() : NULL;
- }
- NativeTextfieldWrapper* GetNativeWrapperForTesting() const {
- return native_wrapper_;
- }
-
// Returns whether there is a drag operation originating from the textfield.
bool HasTextBeingDragged();
- // Overridden from View:
- virtual void Layout() OVERRIDE;
+ // View overrides:
virtual int GetBaseline() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual const char* GetClassName() const OVERRIDE;
+ virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE;
- virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE;
+ virtual bool SkipDefaultKeyEventProcessing(
+ const ui::KeyEvent& event) OVERRIDE;
+ virtual bool GetDropFormats(
+ int* formats,
+ std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
+ virtual bool CanDrop(const ui::OSExchangeData& data) OVERRIDE;
+ virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragExited() OVERRIDE;
+ virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragDone() OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual void OnEnabledChanged() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE;
- virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE;
- virtual bool OnMouseDragged(const ui::MouseEvent& e) OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void OnBlur() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual gfx::Point GetKeyboardContextMenuLocation() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
+
+ // TextfieldModel::Delegate overrides:
+ virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE;
+
+ // ContextMenuController overrides:
+ virtual void ShowContextMenuForView(View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) OVERRIDE;
+
+ // DragController overrides:
+ virtual void WriteDragDataForView(View* sender,
+ const gfx::Point& press_pt,
+ ui::OSExchangeData* data) OVERRIDE;
+ virtual int GetDragOperationsForView(View* sender,
+ const gfx::Point& p) OVERRIDE;
+ virtual bool CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) OVERRIDE;
+
+ // ui::TouchEditable overrides:
+ virtual void SelectRect(const gfx::Point& start,
+ const gfx::Point& end) OVERRIDE;
+ virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
+ virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
+ virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
+ virtual bool DrawsHandles() OVERRIDE;
+ virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE;
+ virtual void DestroyTouchSelection() OVERRIDE;
+
+ // ui::SimpleMenuModel::Delegate overrides:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ // ui::TextInputClient overrides:
+ virtual void SetCompositionText(
+ const ui::CompositionText& composition) OVERRIDE;
+ virtual void ConfirmCompositionText() OVERRIDE;
+ virtual void ClearCompositionText() OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
+ virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
+ virtual ui::TextInputType GetTextInputType() const OVERRIDE;
+ virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
+ virtual bool CanComposeInline() const OVERRIDE;
+ virtual gfx::Rect GetCaretBounds() const OVERRIDE;
+ virtual bool GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const OVERRIDE;
+ virtual bool HasCompositionText() const OVERRIDE;
+ virtual bool GetTextRange(gfx::Range* range) const OVERRIDE;
+ virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE;
+ virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE;
+ virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
+ virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
+ virtual bool GetTextFromRange(const gfx::Range& range,
+ base::string16* text) const OVERRIDE;
+ virtual void OnInputMethodChanged() OVERRIDE;
+ virtual bool ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) OVERRIDE;
+ virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE;
+ virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void OnCandidateWindowShown() OVERRIDE;
+ virtual void OnCandidateWindowUpdated() OVERRIDE;
+ virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
protected:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE;
- virtual const char* GetClassName() const OVERRIDE;
+ // Returns the TextfieldModel's text/cursor/selection rendering model.
+ gfx::RenderText* GetRenderText() const;
+
+ gfx::Point last_click_location() const { return last_click_location_; }
- // The object that actually implements the native text field.
- NativeTextfieldWrapper* native_wrapper_;
+ // Get the text from the selection clipboard.
+ virtual base::string16 GetSelectionClipboardText() const;
private:
- // Returns the insets to the rectangle where text is actually painted.
- gfx::Insets GetTextInsets() const;
+ friend class TextfieldTestApi;
// Handles a request to change the value of this text field from software
// using an accessibility API (typically automation software, screen readers
// don't normally use this). Sets the value and clears the selection.
- void AccessibilitySetValue(const string16& new_value);
+ void AccessibilitySetValue(const base::string16& new_value);
- // This is the current listener for events from this Textfield.
- TextfieldController* controller_;
+ // Updates the painted background color.
+ void UpdateBackgroundColor();
+
+ // Does necessary updates when the text and/or cursor position changes.
+ void UpdateAfterChange(bool text_changed, bool cursor_changed);
+
+ // A callback function to periodically update the cursor state.
+ void UpdateCursor();
+
+ // Repaint the cursor.
+ void RepaintCursor();
+
+ void PaintTextAndCursor(gfx::Canvas* canvas);
+
+ // Helper function to call MoveCursorTo on the TextfieldModel.
+ void MoveCursorTo(const gfx::Point& point, bool select);
+
+ // Helper function to update the selection on a mouse drag.
+ void SelectThroughLastDragLocation();
+
+ // Convenience method to notify the InputMethod and TouchSelectionController.
+ void OnCaretBoundsChanged();
+
+ // Convenience method to call TextfieldController::OnBeforeUserAction();
+ void OnBeforeUserAction();
- // The mask of style options for this Textfield.
- StyleFlags style_;
+ // Convenience method to call TextfieldController::OnAfterUserAction();
+ void OnAfterUserAction();
- // The fonts used to render the text in the Textfield.
- gfx::FontList font_list_;
+ // Calls |model_->Cut()| and notifies TextfieldController on success.
+ bool Cut();
- // The text displayed in the Textfield.
- string16 text_;
+ // Calls |model_->Copy()| and notifies TextfieldController on success.
+ bool Copy();
+
+ // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged()
+ // explicitly if paste succeeded.
+ bool Paste();
+
+ // Utility function to prepare the context menu.
+ void UpdateContextMenu();
+
+ // Tracks the mouse clicks for single/double/triple clicks.
+ void TrackMouseClicks(const ui::MouseEvent& event);
+
+ // Returns true if the current text input type allows access by the IME.
+ bool ImeEditingAllowed() const;
+
+ // Reveals the password character at |index| for a set duration.
+ // If |index| is -1, the existing revealed character will be reset.
+ void RevealPasswordChar(int index);
+
+ void CreateTouchSelectionControllerAndNotifyIt();
+
+ // Updates the selection clipboard to any non-empty text selection.
+ void UpdateSelectionClipboard() const;
+
+ // Pastes the selection clipboard for the specified mouse event.
+ void PasteSelectionClipboard(const ui::MouseEvent& event);
+
+ // The text model.
+ scoped_ptr<TextfieldModel> model_;
+
+ // This is the current listener for events from this Textfield.
+ TextfieldController* controller_;
// True if this Textfield cannot accept input and is read-only.
bool read_only_;
@@ -306,48 +388,72 @@ class VIEWS_EXPORT Textfield : public View {
// This will be reported as the "desired size". Defaults to 0.
int default_width_in_chars_;
- // Whether the border is drawn.
- bool draw_border_;
-
- // Text color. Only used if |use_default_text_color_| is false.
- SkColor text_color_;
+ scoped_ptr<Painter> focus_painter_;
- // Should we use the system text color instead of |text_color_|?
+ // 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_;
-
- // Background color. Only used if |use_default_background_color_| is false.
- SkColor background_color_;
-
- // Should we use the system background color instead of |background_color_|?
bool use_default_background_color_;
-
- // Holds inner textfield margins.
- gfx::Insets margins_;
-
- // Holds whether margins were set.
- bool horizontal_margins_were_set_;
- bool vertical_margins_were_set_;
+ bool use_default_selection_text_color_;
+ bool use_default_selection_background_color_;
+ SkColor text_color_;
+ SkColor background_color_;
+ SkColor selection_text_color_;
+ SkColor selection_background_color_;
// Text to display when empty.
- string16 placeholder_text_;
+ base::string16 placeholder_text_;
// Placeholder text color.
SkColor placeholder_text_color_;
// The accessible name of the text field.
- string16 accessible_name_;
+ base::string16 accessible_name_;
// The input type of this text field.
ui::TextInputType text_input_type_;
- // The duration to reveal the last typed char for obscured textfields.
- base::TimeDelta obscured_reveal_duration_;
+ // The duration and timer to reveal the last typed password character.
+ base::TimeDelta password_reveal_duration_;
+ base::OneShotTimer<Textfield> password_reveal_timer_;
+
+ // Tracks whether a user action is being performed; i.e. OnBeforeUserAction()
+ // has been called, but OnAfterUserAction() has not yet been called.
+ bool performing_user_action_;
+
+ // True if InputMethod::CancelComposition() should not be called.
+ bool skip_input_method_cancel_composition_;
+
+ // The text editing cursor repaint timer and visibility.
+ base::RepeatingTimer<Textfield> cursor_repaint_timer_;
+ bool cursor_visible_;
+
+ // The drop cursor is a visual cue for where dragged text will be dropped.
+ bool drop_cursor_visible_;
+ gfx::SelectionModel drop_cursor_position_;
+
+ // Is the user potentially dragging and dropping from this view?
+ bool initiating_drag_;
+
+ // A timer and point used to modify the selection when dragging.
+ base::RepeatingTimer<Textfield> drag_selection_timer_;
+ gfx::Point last_drag_location_;
+
+ // State variables used to track double and triple clicks.
+ size_t aggregated_clicks_;
+ base::TimeDelta last_click_time_;
+ gfx::Point last_click_location_;
+ gfx::Range double_click_word_;
+
+ scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
+
+ // Context menu related members.
+ scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
+ scoped_ptr<views::MenuRunner> context_menu_runner_;
// Used to bind callback functions to this object.
base::WeakPtrFactory<Textfield> weak_ptr_factory_;
- scoped_ptr<Painter> focus_painter_;
-
DISALLOW_COPY_AND_ASSIGN(Textfield);
};
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.cc b/chromium/ui/views/controls/textfield/textfield_controller.cc
index 8f72be8a1c4..1d90f3c06df 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.cc
+++ b/chromium/ui/views/controls/textfield/textfield_controller.cc
@@ -23,20 +23,4 @@ int TextfieldController::OnDrop(const ui::OSExchangeData& data) {
return ui::DragDropTypes::DRAG_NONE;
}
-bool TextfieldController::IsCommandIdEnabled(int command_id) const {
- return false;
-}
-
-bool TextfieldController::IsItemForCommandIdDynamic(int command_id) const {
- return false;
-}
-
-string16 TextfieldController::GetLabelForCommandId(int command_id) const {
- return string16();
-}
-
-bool TextfieldController::HandlesCommand(int command_id) const {
- return false;
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_controller.h b/chromium/ui/views/controls/textfield/textfield_controller.h
index d72442b41ad..4a01d384f4b 100644
--- a/chromium/ui/views/controls/textfield/textfield_controller.h
+++ b/chromium/ui/views/controls/textfield/textfield_controller.h
@@ -29,7 +29,7 @@ class VIEWS_EXPORT TextfieldController {
// user. It won't be called if the text is changed by calling
// Textfield::SetText() or Textfield::AppendText().
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) {}
+ const base::string16& new_contents) {}
// This method is called to get notified about keystrokes in the edit.
// Returns true if the message was handled and should not be processed
@@ -52,7 +52,7 @@ class VIEWS_EXPORT TextfieldController {
virtual void OnAfterUserAction(Textfield* sender) {}
// Called after performing a Cut or Copy operation.
- virtual void OnAfterCutOrCopy() {}
+ virtual void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) {}
// Called after performing a Paste operation.
virtual void OnAfterPaste() {}
@@ -79,26 +79,6 @@ class VIEWS_EXPORT TextfieldController {
// Gives the controller a chance to modify the context menu contents.
virtual void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) {}
- // Returns true if the |command_id| should be enabled in the context menu.
- virtual bool IsCommandIdEnabled(int command_id) const;
-
- // Returns true if the item label for the |command_id| is dynamic in the
- // context menu.
- virtual bool IsItemForCommandIdDynamic(int command_id) const;
-
- // Returns the label string for the |coomand_id|.
- virtual string16 GetLabelForCommandId(int command_id) const;
-
- // Returns whether the controller handles the specified command. This is used
- // to handle a command the textfield would normally handle. For example, to
- // have the controller handle |IDS_APP_PASTE| override and return true if
- // |command_id| == |IDS_APP_PASTE|.
- // This is only invoked if the command is enabled.
- virtual bool HandlesCommand(int command_id) const;
-
- // Execute context menu command specified by |command_id|.
- virtual void ExecuteCommand(int command_id, int event_flag) {}
-
protected:
virtual ~TextfieldController() {}
};
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
new file mode 100644
index 00000000000..db0dc73b1b0
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -0,0 +1,771 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/textfield/textfield_model.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/gfx/range/range.h"
+#include "ui/gfx/utf16_indexing.h"
+
+namespace views {
+
+namespace internal {
+
+// Edit holds state information to undo/redo editing changes. Editing operations
+// are merged when possible, like when characters are typed in sequence. Calling
+// Commit() marks an edit as an independent operation that shouldn't be merged.
+class Edit {
+ public:
+ enum Type {
+ INSERT_EDIT,
+ DELETE_EDIT,
+ REPLACE_EDIT,
+ };
+
+ virtual ~Edit() {}
+
+ // Revert the change made by this edit in |model|.
+ void Undo(TextfieldModel* model) {
+ model->ModifyText(new_text_start_, new_text_end(),
+ old_text_, old_text_start_,
+ old_cursor_pos_);
+ }
+
+ // Apply the change of this edit to the |model|.
+ void Redo(TextfieldModel* model) {
+ model->ModifyText(old_text_start_, old_text_end(),
+ new_text_, new_text_start_,
+ new_cursor_pos_);
+ }
+
+ // Try to merge the |edit| into this edit and returns true on success. The
+ // merged edit will be deleted after redo and should not be reused.
+ bool Merge(const Edit* edit) {
+ // Don't merge if previous edit is DELETE. This happens when a
+ // user deletes characters then hits return. In this case, the
+ // delete should be treated as separate edit that can be undone
+ // and should not be merged with the replace edit.
+ if (type_ != DELETE_EDIT && edit->force_merge()) {
+ MergeReplace(edit);
+ return true;
+ }
+ return mergeable() && edit->mergeable() && DoMerge(edit);
+ }
+
+ // Commits the edit and marks as un-mergeable.
+ void Commit() { merge_type_ = DO_NOT_MERGE; }
+
+ private:
+ friend class InsertEdit;
+ friend class ReplaceEdit;
+ friend class DeleteEdit;
+
+ Edit(Type type,
+ MergeType merge_type,
+ size_t old_cursor_pos,
+ const base::string16& old_text,
+ size_t old_text_start,
+ bool delete_backward,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start)
+ : type_(type),
+ merge_type_(merge_type),
+ old_cursor_pos_(old_cursor_pos),
+ old_text_(old_text),
+ old_text_start_(old_text_start),
+ delete_backward_(delete_backward),
+ new_cursor_pos_(new_cursor_pos),
+ new_text_(new_text),
+ new_text_start_(new_text_start) {
+ }
+
+ // Each type of edit provides its own specific merge implementation.
+ virtual bool DoMerge(const Edit* edit) = 0;
+
+ Type type() const { return type_; }
+
+ // Can this edit be merged?
+ bool mergeable() const { return merge_type_ == MERGEABLE; }
+
+ // Should this edit be forcibly merged with the previous edit?
+ bool force_merge() const { return merge_type_ == FORCE_MERGE; }
+
+ // Returns the end index of the |old_text_|.
+ size_t old_text_end() const { return old_text_start_ + old_text_.length(); }
+
+ // Returns the end index of the |new_text_|.
+ size_t new_text_end() const { return new_text_start_ + new_text_.length(); }
+
+ // Merge the replace edit into the current edit. This handles the special case
+ // where an omnibox autocomplete string is set after a new character is typed.
+ void MergeReplace(const Edit* edit) {
+ CHECK_EQ(REPLACE_EDIT, edit->type_);
+ CHECK_EQ(0U, edit->old_text_start_);
+ CHECK_EQ(0U, edit->new_text_start_);
+ base::string16 old_text = edit->old_text_;
+ old_text.erase(new_text_start_, new_text_.length());
+ old_text.insert(old_text_start_, old_text_);
+ // SetText() replaces entire text. Set |old_text_| to the entire
+ // replaced text with |this| edit undone.
+ old_text_ = old_text;
+ old_text_start_ = edit->old_text_start_;
+ delete_backward_ = false;
+
+ new_text_ = edit->new_text_;
+ new_text_start_ = edit->new_text_start_;
+ merge_type_ = DO_NOT_MERGE;
+ }
+
+ Type type_;
+
+ // True if the edit can be marged.
+ MergeType merge_type_;
+ // Old cursor position.
+ size_t old_cursor_pos_;
+ // Deleted text by this edit.
+ base::string16 old_text_;
+ // The index of |old_text_|.
+ size_t old_text_start_;
+ // True if the deletion is made backward.
+ bool delete_backward_;
+ // New cursor position.
+ size_t new_cursor_pos_;
+ // Added text.
+ base::string16 new_text_;
+ // The index of |new_text_|
+ size_t new_text_start_;
+
+ DISALLOW_COPY_AND_ASSIGN(Edit);
+};
+
+class InsertEdit : public Edit {
+ public:
+ InsertEdit(bool mergeable, const base::string16& new_text, size_t at)
+ : Edit(INSERT_EDIT,
+ mergeable ? MERGEABLE : DO_NOT_MERGE,
+ at /* old cursor */,
+ base::string16(),
+ at,
+ false /* N/A */,
+ at + new_text.length() /* new cursor */,
+ new_text,
+ at) {
+ }
+
+ // Edit implementation.
+ virtual bool DoMerge(const Edit* edit) OVERRIDE {
+ if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_)
+ return false;
+ // If continuous edit, merge it.
+ // TODO(oshima): gtk splits edits between whitespace. Find out what
+ // we want to here and implement if necessary.
+ new_text_ += edit->new_text_;
+ new_cursor_pos_ = edit->new_cursor_pos_;
+ return true;
+ }
+};
+
+class ReplaceEdit : public Edit {
+ public:
+ ReplaceEdit(MergeType merge_type,
+ const base::string16& old_text,
+ size_t old_cursor_pos,
+ size_t old_text_start,
+ bool backward,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start)
+ : Edit(REPLACE_EDIT, merge_type,
+ old_cursor_pos,
+ old_text,
+ old_text_start,
+ backward,
+ new_cursor_pos,
+ new_text,
+ new_text_start) {
+ }
+
+ // Edit implementation.
+ virtual bool DoMerge(const Edit* edit) OVERRIDE {
+ if (edit->type() == DELETE_EDIT ||
+ new_text_end() != edit->old_text_start_ ||
+ edit->old_text_start_ != edit->new_text_start_)
+ return false;
+ old_text_ += edit->old_text_;
+ new_text_ += edit->new_text_;
+ new_cursor_pos_ = edit->new_cursor_pos_;
+ return true;
+ }
+};
+
+class DeleteEdit : public Edit {
+ public:
+ DeleteEdit(bool mergeable,
+ const base::string16& text,
+ size_t text_start,
+ bool backward)
+ : Edit(DELETE_EDIT,
+ mergeable ? MERGEABLE : DO_NOT_MERGE,
+ (backward ? text_start + text.length() : text_start),
+ text,
+ text_start,
+ backward,
+ text_start,
+ base::string16(),
+ text_start) {
+ }
+
+ // Edit implementation.
+ virtual bool DoMerge(const Edit* edit) OVERRIDE {
+ if (edit->type() != DELETE_EDIT)
+ return false;
+
+ if (delete_backward_) {
+ // backspace can be merged only with backspace at the same position.
+ if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
+ return false;
+ old_text_start_ = edit->old_text_start_;
+ old_text_ = edit->old_text_ + old_text_;
+ new_cursor_pos_ = edit->new_cursor_pos_;
+ } else {
+ // delete can be merged only with delete at the same position.
+ if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
+ return false;
+ old_text_ += edit->old_text_;
+ }
+ return true;
+ }
+};
+
+} // namespace internal
+
+namespace {
+
+// Returns the first segment that is visually emphasized. Usually it's used for
+// representing the target clause (on Windows). Returns an invalid range if
+// there is no such a range.
+gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
+ for (size_t i = 0; i < composition.underlines.size(); ++i) {
+ const ui::CompositionUnderline& underline = composition.underlines[i];
+ if (underline.thick)
+ return gfx::Range(underline.start_offset, underline.end_offset);
+ }
+ return gfx::Range::InvalidRange();
+}
+
+} // namespace
+
+using internal::Edit;
+using internal::DeleteEdit;
+using internal::InsertEdit;
+using internal::ReplaceEdit;
+using internal::MergeType;
+using internal::DO_NOT_MERGE;
+using internal::FORCE_MERGE;
+using internal::MERGEABLE;
+
+/////////////////////////////////////////////////////////////////
+// TextfieldModel: public
+
+TextfieldModel::Delegate::~Delegate() {}
+
+TextfieldModel::TextfieldModel(Delegate* delegate)
+ : delegate_(delegate),
+ render_text_(gfx::RenderText::CreateInstance()),
+ current_edit_(edit_history_.end()) {
+}
+
+TextfieldModel::~TextfieldModel() {
+ ClearEditHistory();
+ ClearComposition();
+}
+
+bool TextfieldModel::SetText(const base::string16& new_text) {
+ bool changed = false;
+ if (HasCompositionText()) {
+ ConfirmCompositionText();
+ changed = true;
+ }
+ if (text() != new_text) {
+ if (changed) // No need to remember composition.
+ Undo();
+ size_t old_cursor = GetCursorPosition();
+ // SetText moves the cursor to the end.
+ size_t new_cursor = new_text.length();
+ SelectAll(false);
+ // If there is a composition text, don't merge with previous edit.
+ // Otherwise, force merge the edits.
+ ExecuteAndRecordReplace(changed ? DO_NOT_MERGE : FORCE_MERGE,
+ old_cursor, new_cursor, new_text, 0U);
+ render_text_->SetCursorPosition(new_cursor);
+ }
+ ClearSelection();
+ return changed;
+}
+
+void TextfieldModel::Append(const base::string16& new_text) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ size_t save = GetCursorPosition();
+ MoveCursor(gfx::LINE_BREAK,
+ render_text_->GetVisualDirectionOfLogicalEnd(),
+ false);
+ InsertText(new_text);
+ render_text_->SetCursorPosition(save);
+ ClearSelection();
+}
+
+bool TextfieldModel::Delete() {
+ if (HasCompositionText()) {
+ // No undo/redo for composition text.
+ CancelCompositionText();
+ return true;
+ }
+ if (HasSelection()) {
+ DeleteSelection();
+ return true;
+ }
+ if (text().length() > GetCursorPosition()) {
+ size_t cursor_position = GetCursorPosition();
+ size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme(
+ cursor_position, gfx::CURSOR_FORWARD);
+ ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index),
+ true);
+ return true;
+ }
+ return false;
+}
+
+bool TextfieldModel::Backspace() {
+ if (HasCompositionText()) {
+ // No undo/redo for composition text.
+ CancelCompositionText();
+ return true;
+ }
+ if (HasSelection()) {
+ DeleteSelection();
+ return true;
+ }
+ size_t cursor_position = GetCursorPosition();
+ if (cursor_position > 0) {
+ // Delete one code point, which may be two UTF-16 words.
+ size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
+ ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true);
+ return true;
+ }
+ return false;
+}
+
+size_t TextfieldModel::GetCursorPosition() const {
+ return render_text_->cursor_position();
+}
+
+void TextfieldModel::MoveCursor(gfx::BreakType break_type,
+ gfx::VisualCursorDirection direction,
+ bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->MoveCursor(break_type, direction, select);
+}
+
+bool TextfieldModel::MoveCursorTo(const gfx::SelectionModel& cursor) {
+ if (HasCompositionText()) {
+ ConfirmCompositionText();
+ // ConfirmCompositionText() updates cursor position. Need to reflect it in
+ // the SelectionModel parameter of MoveCursorTo().
+ gfx::Range range(render_text_->selection().start(), cursor.caret_pos());
+ if (!range.is_empty())
+ return render_text_->SelectRange(range);
+ return render_text_->MoveCursorTo(
+ gfx::SelectionModel(cursor.caret_pos(), cursor.caret_affinity()));
+ }
+ return render_text_->MoveCursorTo(cursor);
+}
+
+bool TextfieldModel::MoveCursorTo(const gfx::Point& point, bool select) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ gfx::SelectionModel cursor = render_text_->FindCursorPosition(point);
+ if (select)
+ cursor.set_selection_start(render_text_->selection().start());
+ return render_text_->MoveCursorTo(cursor);
+}
+
+base::string16 TextfieldModel::GetSelectedText() const {
+ return text().substr(render_text_->selection().GetMin(),
+ render_text_->selection().length());
+}
+
+void TextfieldModel::SelectRange(const gfx::Range& range) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->SelectRange(range);
+}
+
+void TextfieldModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->MoveCursorTo(sel);
+}
+
+void TextfieldModel::SelectAll(bool reversed) {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->SelectAll(reversed);
+}
+
+void TextfieldModel::SelectWord() {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->SelectWord();
+}
+
+void TextfieldModel::ClearSelection() {
+ if (HasCompositionText())
+ ConfirmCompositionText();
+ render_text_->ClearSelection();
+}
+
+bool TextfieldModel::CanUndo() {
+ return edit_history_.size() && current_edit_ != edit_history_.end();
+}
+
+bool TextfieldModel::CanRedo() {
+ if (!edit_history_.size())
+ return false;
+ // There is no redo iff the current edit is the last element in the history.
+ EditHistory::iterator iter = current_edit_;
+ return iter == edit_history_.end() || // at the top.
+ ++iter != edit_history_.end();
+}
+
+bool TextfieldModel::Undo() {
+ if (!CanUndo())
+ return false;
+ DCHECK(!HasCompositionText());
+ if (HasCompositionText())
+ CancelCompositionText();
+
+ base::string16 old = text();
+ size_t old_cursor = GetCursorPosition();
+ (*current_edit_)->Commit();
+ (*current_edit_)->Undo(this);
+
+ if (current_edit_ == edit_history_.begin())
+ current_edit_ = edit_history_.end();
+ else
+ current_edit_--;
+ return old != text() || old_cursor != GetCursorPosition();
+}
+
+bool TextfieldModel::Redo() {
+ if (!CanRedo())
+ return false;
+ DCHECK(!HasCompositionText());
+ if (HasCompositionText())
+ CancelCompositionText();
+
+ if (current_edit_ == edit_history_.end())
+ current_edit_ = edit_history_.begin();
+ else
+ current_edit_ ++;
+ base::string16 old = text();
+ size_t old_cursor = GetCursorPosition();
+ (*current_edit_)->Redo(this);
+ return old != text() || old_cursor != GetCursorPosition();
+}
+
+bool TextfieldModel::Cut() {
+ if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
+ // A trick to let undo/redo handle cursor correctly.
+ // Undoing CUT moves the cursor to the end of the change rather
+ // than beginning, unlike Delete/Backspace.
+ // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
+ // update DeleteEdit and remove this trick.
+ const gfx::Range& selection = render_text_->selection();
+ render_text_->SelectRange(gfx::Range(selection.end(), selection.start()));
+ DeleteSelection();
+ return true;
+ }
+ return false;
+}
+
+bool TextfieldModel::Copy() {
+ if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
+ ui::ScopedClipboardWriter(
+ ui::Clipboard::GetForCurrentThread(),
+ ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
+ return true;
+ }
+ return false;
+}
+
+bool TextfieldModel::Paste() {
+ base::string16 result;
+ ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE,
+ &result);
+ if (result.empty())
+ return false;
+
+ InsertTextInternal(result, false);
+ return true;
+}
+
+bool TextfieldModel::HasSelection() const {
+ return !render_text_->selection().is_empty();
+}
+
+void TextfieldModel::DeleteSelection() {
+ DCHECK(!HasCompositionText());
+ DCHECK(HasSelection());
+ ExecuteAndRecordDelete(render_text_->selection(), false);
+}
+
+void TextfieldModel::DeleteSelectionAndInsertTextAt(
+ const base::string16& new_text,
+ size_t position) {
+ if (HasCompositionText())
+ CancelCompositionText();
+ ExecuteAndRecordReplace(DO_NOT_MERGE,
+ GetCursorPosition(),
+ position + new_text.length(),
+ new_text,
+ position);
+}
+
+base::string16 TextfieldModel::GetTextFromRange(const gfx::Range& range) const {
+ if (range.IsValid() && range.GetMin() < text().length())
+ return text().substr(range.GetMin(), range.length());
+ return base::string16();
+}
+
+void TextfieldModel::GetTextRange(gfx::Range* range) const {
+ *range = gfx::Range(0, text().length());
+}
+
+void TextfieldModel::SetCompositionText(
+ const ui::CompositionText& composition) {
+ if (HasCompositionText())
+ CancelCompositionText();
+ else if (HasSelection())
+ DeleteSelection();
+
+ if (composition.text.empty())
+ return;
+
+ size_t cursor = GetCursorPosition();
+ base::string16 new_text = text();
+ render_text_->SetText(new_text.insert(cursor, composition.text));
+ gfx::Range range(cursor, cursor + composition.text.length());
+ render_text_->SetCompositionRange(range);
+ gfx::Range emphasized_range = GetFirstEmphasizedRange(composition);
+ if (emphasized_range.IsValid()) {
+ // This is a workaround due to the lack of support in RenderText to draw
+ // a thick underline. In a composition returned from an IME, the segment
+ // emphasized by a thick underline usually represents the target clause.
+ // Because the target clause is more important than the actual selection
+ // range (or caret position) in the composition here we use a selection-like
+ // marker instead to show this range.
+ // TODO(yukawa, msw): Support thick underlines and remove this workaround.
+ render_text_->SelectRange(gfx::Range(
+ cursor + emphasized_range.GetMin(),
+ cursor + emphasized_range.GetMax()));
+ } else if (!composition.selection.is_empty()) {
+ render_text_->SelectRange(gfx::Range(
+ cursor + composition.selection.GetMin(),
+ cursor + composition.selection.GetMax()));
+ } else {
+ render_text_->SetCursorPosition(cursor + composition.selection.end());
+ }
+}
+
+void TextfieldModel::ConfirmCompositionText() {
+ DCHECK(HasCompositionText());
+ gfx::Range range = render_text_->GetCompositionRange();
+ base::string16 composition = text().substr(range.start(), range.length());
+ // TODO(oshima): current behavior on ChromeOS is a bit weird and not
+ // sure exactly how this should work. Find out and fix if necessary.
+ AddOrMergeEditHistory(new InsertEdit(false, composition, range.start()));
+ render_text_->SetCursorPosition(range.end());
+ ClearComposition();
+ if (delegate_)
+ delegate_->OnCompositionTextConfirmedOrCleared();
+}
+
+void TextfieldModel::CancelCompositionText() {
+ DCHECK(HasCompositionText());
+ gfx::Range range = render_text_->GetCompositionRange();
+ ClearComposition();
+ base::string16 new_text = text();
+ render_text_->SetText(new_text.erase(range.start(), range.length()));
+ render_text_->SetCursorPosition(range.start());
+ if (delegate_)
+ delegate_->OnCompositionTextConfirmedOrCleared();
+}
+
+void TextfieldModel::ClearComposition() {
+ render_text_->SetCompositionRange(gfx::Range::InvalidRange());
+}
+
+void TextfieldModel::GetCompositionTextRange(gfx::Range* range) const {
+ *range = gfx::Range(render_text_->GetCompositionRange());
+}
+
+bool TextfieldModel::HasCompositionText() const {
+ return !render_text_->GetCompositionRange().is_empty();
+}
+
+void TextfieldModel::ClearEditHistory() {
+ STLDeleteElements(&edit_history_);
+ current_edit_ = edit_history_.end();
+}
+
+/////////////////////////////////////////////////////////////////
+// TextfieldModel: private
+
+void TextfieldModel::InsertTextInternal(const base::string16& new_text,
+ bool mergeable) {
+ if (HasCompositionText()) {
+ CancelCompositionText();
+ ExecuteAndRecordInsert(new_text, mergeable);
+ } else if (HasSelection()) {
+ ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE,
+ new_text);
+ } else {
+ ExecuteAndRecordInsert(new_text, mergeable);
+ }
+}
+
+void TextfieldModel::ReplaceTextInternal(const base::string16& new_text,
+ bool mergeable) {
+ if (HasCompositionText()) {
+ CancelCompositionText();
+ } else if (!HasSelection()) {
+ size_t cursor = GetCursorPosition();
+ const gfx::SelectionModel& model = render_text_->selection_model();
+ // When there is no selection, the default is to replace the next grapheme
+ // with |new_text|. So, need to find the index of next grapheme first.
+ size_t next =
+ render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD);
+ if (next == model.caret_pos())
+ render_text_->MoveCursorTo(model);
+ else
+ render_text_->SelectRange(gfx::Range(next, model.caret_pos()));
+ }
+ // Edit history is recorded in InsertText.
+ InsertTextInternal(new_text, mergeable);
+}
+
+void TextfieldModel::ClearRedoHistory() {
+ if (edit_history_.begin() == edit_history_.end())
+ return;
+ if (current_edit_ == edit_history_.end()) {
+ ClearEditHistory();
+ return;
+ }
+ EditHistory::iterator delete_start = current_edit_;
+ delete_start++;
+ STLDeleteContainerPointers(delete_start, edit_history_.end());
+ edit_history_.erase(delete_start, edit_history_.end());
+}
+
+void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) {
+ size_t old_text_start = range.GetMin();
+ const base::string16 old_text = text().substr(old_text_start, range.length());
+ bool backward = range.is_reversed();
+ Edit* edit = new DeleteEdit(mergeable, old_text, old_text_start, backward);
+ bool delete_edit = AddOrMergeEditHistory(edit);
+ edit->Redo(this);
+ if (delete_edit)
+ delete edit;
+}
+
+void TextfieldModel::ExecuteAndRecordReplaceSelection(
+ MergeType merge_type,
+ const base::string16& new_text) {
+ size_t new_text_start = render_text_->selection().GetMin();
+ size_t new_cursor_pos = new_text_start + new_text.length();
+ ExecuteAndRecordReplace(merge_type,
+ GetCursorPosition(),
+ new_cursor_pos,
+ new_text,
+ new_text_start);
+}
+
+void TextfieldModel::ExecuteAndRecordReplace(MergeType merge_type,
+ size_t old_cursor_pos,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start) {
+ size_t old_text_start = render_text_->selection().GetMin();
+ bool backward = render_text_->selection().is_reversed();
+ Edit* edit = new ReplaceEdit(merge_type,
+ GetSelectedText(),
+ old_cursor_pos,
+ old_text_start,
+ backward,
+ new_cursor_pos,
+ new_text,
+ new_text_start);
+ bool delete_edit = AddOrMergeEditHistory(edit);
+ edit->Redo(this);
+ if (delete_edit)
+ delete edit;
+}
+
+void TextfieldModel::ExecuteAndRecordInsert(const base::string16& new_text,
+ bool mergeable) {
+ Edit* edit = new InsertEdit(mergeable, new_text, GetCursorPosition());
+ bool delete_edit = AddOrMergeEditHistory(edit);
+ edit->Redo(this);
+ if (delete_edit)
+ delete edit;
+}
+
+bool TextfieldModel::AddOrMergeEditHistory(Edit* edit) {
+ ClearRedoHistory();
+
+ if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) {
+ // If a current edit exists and has been merged with a new edit, don't add
+ // to the history, and return true to delete |edit| after redo.
+ return true;
+ }
+ edit_history_.push_back(edit);
+ if (current_edit_ == edit_history_.end()) {
+ // If there is no redoable edit, this is the 1st edit because RedoHistory
+ // has been already deleted.
+ DCHECK_EQ(1u, edit_history_.size());
+ current_edit_ = edit_history_.begin();
+ } else {
+ current_edit_++;
+ }
+ return false;
+}
+
+void TextfieldModel::ModifyText(size_t delete_from,
+ size_t delete_to,
+ const base::string16& new_text,
+ size_t new_text_insert_at,
+ size_t new_cursor_pos) {
+ DCHECK_LE(delete_from, delete_to);
+ base::string16 old_text = text();
+ ClearComposition();
+ if (delete_from != delete_to)
+ render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from));
+ if (!new_text.empty())
+ render_text_->SetText(old_text.insert(new_text_insert_at, new_text));
+ render_text_->SetCursorPosition(new_cursor_pos);
+ // TODO(oshima): Select text that was just undone, like Mac (but not GTK).
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_model.h b/chromium/ui/views/controls/textfield/textfield_model.h
new file mode 100644
index 00000000000..6ae3398ee46
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_model.h
@@ -0,0 +1,292 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
+
+#include <list>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/base/ime/composition_text.h"
+#include "ui/gfx/render_text.h"
+#include "ui/gfx/text_constants.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+namespace internal {
+// Internal Edit class that keeps track of edits for undo/redo.
+class Edit;
+
+// The types of merge behavior implemented by Edit operations.
+enum MergeType {
+ // The edit should not usually be merged with next edit.
+ DO_NOT_MERGE,
+ // The edit should be merged with next edit when possible.
+ MERGEABLE,
+ // The edit should be merged with the prior edit, even if marked DO_NOT_MERGE.
+ FORCE_MERGE,
+};
+
+} // namespace internal
+
+// A model that represents text content for a views::Textfield.
+// It supports editing, selection and cursor manipulation.
+class VIEWS_EXPORT TextfieldModel {
+ public:
+ // Delegate interface implemented by the textfield view class to provide
+ // additional functionalities required by the model.
+ class VIEWS_EXPORT Delegate {
+ public:
+ // Called when the current composition text is confirmed or cleared.
+ virtual void OnCompositionTextConfirmedOrCleared() = 0;
+
+ protected:
+ virtual ~Delegate();
+ };
+
+ explicit TextfieldModel(Delegate* delegate);
+ virtual ~TextfieldModel();
+
+ // Edit related methods.
+
+ const base::string16& text() const { return render_text_->text(); }
+ // Sets the text. Returns true if the text has been modified. The current
+ // composition text will be confirmed first. Setting the same text will not
+ // add edit history because it's not user visible change nor user-initiated
+ // change. This allow a client code to set the same text multiple times
+ // without worrying about messing edit history.
+ bool SetText(const base::string16& new_text);
+
+ gfx::RenderText* render_text() { return render_text_.get(); }
+
+ // Inserts given |new_text| at the current cursor position.
+ // The current composition text will be cleared.
+ void InsertText(const base::string16& new_text) {
+ InsertTextInternal(new_text, false);
+ }
+
+ // Inserts a character at the current cursor position.
+ void InsertChar(base::char16 c) {
+ InsertTextInternal(base::string16(&c, 1), true);
+ }
+
+ // Replaces characters at the current position with characters in given text.
+ // The current composition text will be cleared.
+ void ReplaceText(const base::string16& new_text) {
+ ReplaceTextInternal(new_text, false);
+ }
+
+ // Replaces the char at the current position with given character.
+ void ReplaceChar(base::char16 c) {
+ ReplaceTextInternal(base::string16(&c, 1), true);
+ }
+
+ // Appends the text.
+ // The current composition text will be confirmed.
+ void Append(const base::string16& new_text);
+
+ // Deletes the first character after the current cursor position (as if, the
+ // the user has pressed delete key in the textfield). Returns true if
+ // the deletion is successful.
+ // If there is composition text, it'll be deleted instead.
+ bool Delete();
+
+ // Deletes the first character before the current cursor position (as if, the
+ // the user has pressed backspace key in the textfield). Returns true if
+ // the removal is successful.
+ // If there is composition text, it'll be deleted instead.
+ bool Backspace();
+
+ // Cursor related methods.
+
+ // Returns the current cursor position.
+ size_t GetCursorPosition() const;
+
+ // Moves the cursor, see RenderText for additional details.
+ // The current composition text will be confirmed.
+ void MoveCursor(gfx::BreakType break_type,
+ gfx::VisualCursorDirection direction,
+ bool select);
+
+ // Updates the cursor to the specified selection model. Any composition text
+ // will be confirmed, which may alter the specified selection range start.
+ bool MoveCursorTo(const gfx::SelectionModel& cursor);
+
+ // Helper function to call MoveCursorTo on the TextfieldModel.
+ bool MoveCursorTo(const gfx::Point& point, bool select);
+
+ // Selection related methods.
+
+ // Returns the selected text.
+ base::string16 GetSelectedText() const;
+
+ // The current composition text will be confirmed. The selection starts with
+ // the range's start position, and ends with the range's end position,
+ // therefore the cursor position becomes the end position.
+ void SelectRange(const gfx::Range& range);
+
+ // The current composition text will be confirmed.
+ // render_text_'s selection model is set to |sel|.
+ void SelectSelectionModel(const gfx::SelectionModel& sel);
+
+ // Select the entire text range. If |reversed| is true, the range will end at
+ // the logical beginning of the text; this generally shows the leading portion
+ // of text that overflows its display area.
+ // The current composition text will be confirmed.
+ void SelectAll(bool reversed);
+
+ // Selects the word at which the cursor is currently positioned. If there is a
+ // non-empty selection, the selection bounds are extended to their nearest
+ // word boundaries.
+ // The current composition text will be confirmed.
+ void SelectWord();
+
+ // Clears selection.
+ // The current composition text will be confirmed.
+ void ClearSelection();
+
+ // Returns true if there is an undoable edit.
+ bool CanUndo();
+
+ // Returns true if there is an redoable edit.
+ bool CanRedo();
+
+ // Undo edit. Returns true if undo changed the text.
+ bool Undo();
+
+ // Redo edit. Returns true if redo changed the text.
+ bool Redo();
+
+ // Cuts the currently selected text and puts it to clipboard. Returns true
+ // if text has changed after cutting.
+ bool Cut();
+
+ // Copies the currently selected text and puts it to clipboard. Returns true
+ // if something was copied to the clipboard.
+ bool Copy();
+
+ // Pastes text from the clipboard at current cursor position. Returns true
+ // if any text is pasted.
+ bool Paste();
+
+ // Tells if any text is selected, even if the selection is in composition
+ // text.
+ bool HasSelection() const;
+
+ // Deletes the selected text. This method shouldn't be called with
+ // composition text.
+ void DeleteSelection();
+
+ // Deletes the selected text (if any) and insert text at given position.
+ void DeleteSelectionAndInsertTextAt(const base::string16& new_text,
+ size_t position);
+
+ // Retrieves the text content in a given range.
+ base::string16 GetTextFromRange(const gfx::Range& range) const;
+
+ // Retrieves the range containing all text in the model.
+ void GetTextRange(gfx::Range* range) const;
+
+ // Sets composition text and attributes. If there is composition text already,
+ // it'll be replaced by the new one. Otherwise, current selection will be
+ // replaced. If there is no selection, the composition text will be inserted
+ // at the insertion point.
+ // Any changes to the model except text insertion will confirm the current
+ // composition text.
+ void SetCompositionText(const ui::CompositionText& composition);
+
+ // Converts current composition text into final content.
+ void ConfirmCompositionText();
+
+ // Removes current composition text.
+ void CancelCompositionText();
+
+ // Retrieves the range of current composition text.
+ void GetCompositionTextRange(gfx::Range* range) const;
+
+ // Returns true if there is composition text.
+ bool HasCompositionText() const;
+
+ // Clears all edit history.
+ void ClearEditHistory();
+
+ private:
+ friend class internal::Edit;
+
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_BasicTest);
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_CutCopyPasteTest);
+ FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_ReplaceTest);
+
+ // Insert the given |new_text|. |mergeable| indicates if this insert operation
+ // can be merged with previous edits in the history.
+ void InsertTextInternal(const base::string16& new_text, bool mergeable);
+
+ // Replace the current text with the given |new_text|. |mergeable| indicates
+ // if this replace operation can be merged with previous edits in the history.
+ void ReplaceTextInternal(const base::string16& new_text, bool mergeable);
+
+ // Clears redo history.
+ void ClearRedoHistory();
+
+ // Executes and records edit operations.
+ void ExecuteAndRecordDelete(gfx::Range range, bool mergeable);
+ void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
+ const base::string16& new_text);
+ void ExecuteAndRecordReplace(internal::MergeType merge_type,
+ size_t old_cursor_pos,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start);
+ void ExecuteAndRecordInsert(const base::string16& new_text, bool mergeable);
+
+ // Adds or merge |edit| into edit history. Return true if the edit
+ // has been merged and must be deleted after redo.
+ bool AddOrMergeEditHistory(internal::Edit* edit);
+
+ // Modify the text buffer in following way:
+ // 1) Delete the string from |delete_from| to |delte_to|.
+ // 2) Insert the |new_text| at the index |new_text_insert_at|.
+ // Note that the index is after deletion.
+ // 3) Move the cursor to |new_cursor_pos|.
+ void ModifyText(size_t delete_from,
+ size_t delete_to,
+ const base::string16& new_text,
+ size_t new_text_insert_at,
+ size_t new_cursor_pos);
+
+ void ClearComposition();
+
+ // The TextfieldModel::Delegate instance should be provided by the owner.
+ Delegate* delegate_;
+
+ // The stylized text, cursor, selection, and the visual layout model.
+ scoped_ptr<gfx::RenderText> render_text_;
+
+ typedef std::list<internal::Edit*> EditHistory;
+ EditHistory edit_history_;
+
+ // An iterator that points to the current edit that can be undone.
+ // This iterator moves from the |end()|, meaining no edit to undo,
+ // to the last element (one before |end()|), meaning no edit to redo.
+ //
+ // There is no edit to undo (== end()) when:
+ // 1) in initial state. (nothing to undo)
+ // 2) very 1st edit is undone.
+ // 3) all edit history is removed.
+ // There is no edit to redo (== last element or no element) when:
+ // 1) in initial state. (nothing to redo)
+ // 2) new edit is added. (redo history is cleared)
+ // 3) redone all undone edits.
+ EditHistory::iterator current_edit_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldModel);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_MODEL_H_
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
new file mode 100644
index 00000000000..f3947ff0c1c
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -0,0 +1,1482 @@
+// 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 <vector>
+
+#include "base/auto_reset.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/gfx/range/range.h"
+#include "ui/gfx/render_text.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_model.h"
+#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/test/views_test_base.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(base::ASCIIToUTF16(ascii), utf16)
+
+namespace {
+
+struct WordAndCursor {
+ WordAndCursor(const wchar_t* w, size_t c) : word(w), cursor(c) {}
+
+ const wchar_t* word;
+ size_t cursor;
+};
+
+void MoveCursorTo(views::TextfieldModel& model, size_t pos) {
+ model.MoveCursorTo(gfx::SelectionModel(pos, gfx::CURSOR_FORWARD));
+}
+
+} // namespace
+
+namespace views {
+
+class TextfieldModelTest : public ViewsTestBase,
+ public TextfieldModel::Delegate {
+ public:
+ TextfieldModelTest()
+ : ViewsTestBase(),
+ composition_text_confirmed_or_cleared_(false) {
+ }
+
+ virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE {
+ composition_text_confirmed_or_cleared_ = true;
+ }
+
+ protected:
+ void ResetModel(TextfieldModel* model) const {
+ model->SetText(base::string16());
+ model->ClearEditHistory();
+ }
+
+ bool composition_text_confirmed_or_cleared_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextfieldModelTest);
+};
+
+TEST_F(TextfieldModelTest, EditString) {
+ TextfieldModel model(NULL);
+ // Append two strings.
+ model.Append(base::ASCIIToUTF16("HILL"));
+ EXPECT_STR_EQ("HILL", model.text());
+ model.Append(base::ASCIIToUTF16("WORLD"));
+ EXPECT_STR_EQ("HILLWORLD", model.text());
+
+ // Insert "E" and replace "I" with "L" to make "HELLO".
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.InsertChar('E');
+ EXPECT_STR_EQ("HEILLWORLD", model.text());
+ model.ReplaceChar('L');
+ EXPECT_STR_EQ("HELLLWORLD", model.text());
+ model.ReplaceChar('L');
+ model.ReplaceChar('O');
+ EXPECT_STR_EQ("HELLOWORLD", model.text());
+
+ // Delete 6th char "W", then delete 5th char "O".
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("HELLOORLD", model.text());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_STR_EQ("HELLORLD", model.text());
+
+ // Move the cursor to start; backspace should fail.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_FALSE(model.Backspace());
+ EXPECT_STR_EQ("HELLORLD", model.text());
+ // Move the cursor to the end; delete should fail, but backspace should work.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_FALSE(model.Delete());
+ EXPECT_STR_EQ("HELLORLD", model.text());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("HELLORL", model.text());
+
+ MoveCursorTo(model, 5);
+ model.ReplaceText(base::ASCIIToUTF16(" WOR"));
+ EXPECT_STR_EQ("HELLO WORL", model.text());
+}
+
+TEST_F(TextfieldModelTest, EditString_SimpleRTL) {
+ TextfieldModel model(NULL);
+ // Append two strings.
+ model.Append(base::WideToUTF16(L"\x05d0\x05d1\x05d2"));
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05d1\x05d2"), model.text());
+ model.Append(base::WideToUTF16(L"\x05e0\x05e1\x05e2"));
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
+
+ // Insert "\x05f0".
+ MoveCursorTo(model, 1);
+ model.InsertChar(0x05f0);
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
+
+ // Replace "\x05d1" with "\x05f1".
+ model.ReplaceChar(0x05f1);
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"),
+ model.text());
+
+ // Test Delete and backspace.
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"),
+ model.text());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_EQ(base::WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.text());
+}
+
+TEST_F(TextfieldModelTest, EditString_ComplexScript) {
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
+ bool on_windows_xp = false;
+#if defined(OS_WIN)
+ on_windows_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
+#endif
+
+ TextfieldModel model(NULL);
+
+ // Append two Hindi strings.
+ model.Append(base::WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
+ EXPECT_EQ(base::WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), model.text());
+ model.Append(base::WideToUTF16(L"\x0915\x094d\x092e\x094d"));
+ EXPECT_EQ(base::WideToUTF16(
+ L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), model.text());
+
+ if (!on_windows_xp) {
+ // Ensure the cursor cannot be placed in the middle of a grapheme.
+ MoveCursorTo(model, 1);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+
+ MoveCursorTo(model, 2);
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ model.InsertChar('a');
+ EXPECT_EQ(base::WideToUTF16(
+ L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"),
+ model.text());
+
+ // ReplaceChar will replace the whole grapheme.
+ model.ReplaceChar('b');
+ // TODO(xji): temporarily disable in platform Win since the complex script
+ // characters turned into empty square due to font regression. So, not able
+ // to test 2 characters belong to the same grapheme.
+#if defined(OS_LINUX)
+ EXPECT_EQ(base::WideToUTF16(
+ L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
+ model.text());
+#endif
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ }
+
+ // Delete should delete the whole grapheme.
+ MoveCursorTo(model, 0);
+ // TODO(xji): temporarily disable in platform Win since the complex script
+ // characters turned into empty square due to font regression. So, not able
+ // to test 2 characters belong to the same grapheme.
+#if defined(OS_LINUX)
+ EXPECT_TRUE(model.Delete());
+ EXPECT_EQ(base::WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
+ model.text());
+ MoveCursorTo(model, model.text().length());
+ EXPECT_EQ(model.text().length(), model.GetCursorPosition());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_EQ(base::WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"),
+ model.text());
+#endif
+
+ // Test cursor position and deletion for Hindi Virama.
+ model.SetText(base::WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"));
+ MoveCursorTo(model, 0);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+
+ if (!on_windows_xp) {
+ MoveCursorTo(model, 1);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ MoveCursorTo(model, 3);
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ }
+
+ // TODO(asvitkine): Temporarily disable the following check on Windows. It
+ // seems Windows treats "\x0D38\x0D4D\x0D15" as a single grapheme.
+#if !defined(OS_WIN)
+ MoveCursorTo(model, 2);
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_EQ(base::WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.text());
+#endif
+
+ model.SetText(
+ base::WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"));
+ MoveCursorTo(model, 0);
+ EXPECT_TRUE(model.Delete());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_EQ(base::WideToUTF16(L""), model.text());
+
+ // The first 2 characters are not strong directionality characters.
+ model.SetText(
+ base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_EQ(base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
+ model.text());
+}
+
+TEST_F(TextfieldModelTest, EmptyString) {
+ TextfieldModel model(NULL);
+ EXPECT_EQ(base::string16(), model.text());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+
+ EXPECT_FALSE(model.Delete());
+ EXPECT_FALSE(model.Backspace());
+}
+
+TEST_F(TextfieldModelTest, Selection) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_STR_EQ("E", model.GetSelectedText());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_STR_EQ("EL", model.GetSelectedText());
+
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_STR_EQ("H", model.GetSelectedText());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_STR_EQ("ELLO", model.GetSelectedText());
+ model.ClearSelection();
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+
+ // SelectAll(false) selects towards the end.
+ model.SelectAll(false);
+ EXPECT_STR_EQ("HELLO", model.GetSelectedText());
+ EXPECT_EQ(gfx::Range(0, 5), model.render_text()->selection());
+
+ // SelectAll(true) selects towards the beginning.
+ model.SelectAll(true);
+ EXPECT_STR_EQ("HELLO", model.GetSelectedText());
+ EXPECT_EQ(gfx::Range(5, 0), model.render_text()->selection());
+
+ // Select and move cursor.
+ model.SelectRange(gfx::Range(1U, 3U));
+ EXPECT_STR_EQ("EL", model.GetSelectedText());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.SelectRange(gfx::Range(1U, 3U));
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(3U, model.GetCursorPosition());
+
+ // Select all and move cursor.
+ model.SelectAll(false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ model.SelectAll(false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(5U, model.GetCursorPosition());
+}
+
+TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
+ // Selection is a logical operation. And it should work with the arrow
+ // keys doing visual movements, while the selection is logical between
+ // the (logical) start and end points. Selection is simply defined as
+ // the portion of text between the logical positions of the start and end
+ // caret positions.
+ TextfieldModel model(NULL);
+ // TODO(xji): temporarily disable in platform Win since the complex script
+ // characters turned into empty square due to font regression. So, not able
+ // to test 2 characters belong to the same grapheme.
+#if defined(OS_LINUX)
+ model.Append(base::WideToUTF16(
+ L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"));
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
+ EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(gfx::Range(2, 7), model.render_text()->selection());
+ EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"),
+ model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
+ EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(gfx::Range(2, 10), model.render_text()->selection());
+ EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"),
+ model.GetSelectedText());
+
+ model.ClearSelection();
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ model.SelectAll(false);
+ EXPECT_EQ(
+ base::WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"),
+ model.GetSelectedText());
+#endif
+
+ // In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is
+ // an RTL character.
+ model.SetText(base::WideToUTF16(L"a\x05E9" L"b"));
+ MoveCursorTo(model, 0);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9"), model.GetSelectedText());
+
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(base::WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText());
+
+ model.ClearSelection();
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ model.SelectAll(false);
+ EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
+}
+
+TEST_F(TextfieldModelTest, SelectionAndEdit) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL"
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("HLO", model.text());
+
+ model.Append(base::ASCIIToUTF16("ILL"));
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO"
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("HILL", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I"
+ model.InsertChar('E');
+ EXPECT_STR_EQ("HELL", model.text());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H"
+ model.ReplaceChar('B');
+ EXPECT_STR_EQ("BELL", model.text());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL"
+ model.ReplaceChar('E');
+ EXPECT_STR_EQ("BEE", model.text());
+}
+
+TEST_F(TextfieldModelTest, Word) {
+ TextfieldModel model(NULL);
+ model.Append(
+ base::ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(18U, model.GetCursorPosition());
+
+ // Should passes the non word char ','
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_EQ(23U, model.GetCursorPosition());
+ EXPECT_STR_EQ(", the", model.GetSelectedText());
+
+ // Move to the end.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
+ // Should be safe to go next word at the end.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
+ model.InsertChar('2');
+ EXPECT_EQ(19U, model.GetCursorPosition());
+
+ // Now backwards.
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); // leave 2.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_EQ(14U, model.GetCursorPosition());
+ EXPECT_STR_EQ("Life", model.GetSelectedText());
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_STR_EQ("to Life", model.GetSelectedText());
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); // Now at start.
+ EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
+ // Should be safe to go to the previous word at the beginning.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
+ model.ReplaceChar('4');
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ EXPECT_STR_EQ("42", model.text());
+}
+
+TEST_F(TextfieldModelTest, SetText) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.SetText(base::ASCIIToUTF16("GOODBYE"));
+ EXPECT_STR_EQ("GOODBYE", model.text());
+ // SetText move the cursor to the end of the new text.
+ EXPECT_EQ(7U, model.GetCursorPosition());
+ model.SelectAll(false);
+ EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(7U, model.GetCursorPosition());
+
+ model.SetText(base::ASCIIToUTF16("BYE"));
+ // Setting shorter string moves the cursor to the end of the new string.
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_EQ(base::string16(), model.GetSelectedText());
+ model.SetText(base::string16());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+}
+
+TEST_F(TextfieldModelTest, Clipboard) {
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ const base::string16 initial_clipboard_text =
+ base::ASCIIToUTF16("initial text");
+ ui::ScopedClipboardWriter(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE).
+ WriteText(initial_clipboard_text);
+
+ base::string16 clipboard_text;
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
+
+ // Cut with an empty selection should do nothing.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_FALSE(model.Cut());
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_EQ(initial_clipboard_text, clipboard_text);
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
+ EXPECT_EQ(11U, model.GetCursorPosition());
+
+ // Copy with an empty selection should do nothing.
+ model.Copy();
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_EQ(initial_clipboard_text, clipboard_text);
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
+ EXPECT_EQ(11U, model.GetCursorPosition());
+
+ // Cut on obscured (password) text should do nothing.
+ model.render_text()->SetObscured(true);
+ model.SelectAll(false);
+ EXPECT_FALSE(model.Cut());
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_EQ(initial_clipboard_text, clipboard_text);
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
+ EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
+
+ // Copy on obscured (password) text should do nothing.
+ model.SelectAll(false);
+ EXPECT_FALSE(model.Copy());
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_EQ(initial_clipboard_text, clipboard_text);
+ EXPECT_STR_EQ("HELLO WORLD", model.text());
+ EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
+
+ // Cut with non-empty selection.
+ model.render_text()->SetObscured(false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_TRUE(model.Cut());
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_STR_EQ("WORLD", clipboard_text);
+ EXPECT_STR_EQ("HELLO ", model.text());
+ EXPECT_EQ(6U, model.GetCursorPosition());
+
+ // Copy with non-empty selection.
+ model.SelectAll(false);
+ EXPECT_TRUE(model.Copy());
+ clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
+ EXPECT_STR_EQ("HELLO ", clipboard_text);
+ EXPECT_STR_EQ("HELLO ", model.text());
+ EXPECT_EQ(6U, model.GetCursorPosition());
+
+ // Test that paste works regardless of the obscured bit.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(model.Paste());
+ EXPECT_STR_EQ("HELLO HELLO ", model.text());
+ EXPECT_EQ(12U, model.GetCursorPosition());
+ model.render_text()->SetObscured(true);
+ EXPECT_TRUE(model.Paste());
+ EXPECT_STR_EQ("HELLO HELLO HELLO ", model.text());
+ EXPECT_EQ(18U, model.GetCursorPosition());
+}
+
+static void SelectWordTestVerifier(
+ const TextfieldModel& model,
+ const base::string16 &expected_selected_string,
+ size_t expected_cursor_pos) {
+ EXPECT_EQ(expected_selected_string, model.GetSelectedText());
+ EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition());
+}
+
+TEST_F(TextfieldModelTest, SelectWordTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16(" HELLO !! WO RLD "));
+
+ // Test when cursor is at the beginning.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 2U);
+
+ // Test when cursor is at the beginning of a word.
+ MoveCursorTo(model, 2);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16("HELLO"), 7U);
+
+ // Test when cursor is at the end of a word.
+ MoveCursorTo(model, 15);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 20U);
+
+ // Test when cursor is somewhere in a non-alpha-numeric fragment.
+ for (size_t cursor_pos = 8; cursor_pos < 13U; cursor_pos++) {
+ MoveCursorTo(model, cursor_pos);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" !! "), 13U);
+ }
+
+ // Test when cursor is somewhere in a whitespace fragment.
+ MoveCursorTo(model, 17);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 20U);
+
+ // Test when cursor is at the end.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 24U);
+}
+
+// TODO(xji): temporarily disable in platform Win since the complex script
+// characters and Chinese characters are turned into empty square due to font
+// regression.
+#if defined(OS_LINUX)
+TEST_F(TextfieldModelTest, SelectWordTest_MixScripts) {
+ TextfieldModel model(NULL);
+ std::vector<WordAndCursor> word_and_cursor;
+ word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
+ word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
+ word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5));
+ word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5));
+ word_and_cursor.push_back(WordAndCursor(L" ", 3));
+ word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
+ word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9));
+ word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9));
+ word_and_cursor.push_back(WordAndCursor(L" ", 10));
+ word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12));
+ word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12));
+ word_and_cursor.push_back(WordAndCursor(L"\x82B1", 13));
+ word_and_cursor.push_back(WordAndCursor(L"\x5929", 14));
+
+ // The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese.
+ model.SetText(base::WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
+ L"\x4E2D\x56FD\x82B1\x5929"));
+ for (size_t i = 0; i < word_and_cursor.size(); ++i) {
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ for (size_t j = 0; j < i; ++j)
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.SelectWord();
+ SelectWordTestVerifier(model, base::WideToUTF16(word_and_cursor[i].word),
+ word_and_cursor[i].cursor);
+ }
+}
+#endif
+
+TEST_F(TextfieldModelTest, RangeTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ gfx::Range range = model.render_text()->selection();
+ EXPECT_TRUE(range.is_empty());
+ EXPECT_EQ(0U, range.start());
+ EXPECT_EQ(0U, range.end());
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ range = model.render_text()->selection();
+ EXPECT_FALSE(range.is_empty());
+ EXPECT_FALSE(range.is_reversed());
+ EXPECT_EQ(0U, range.start());
+ EXPECT_EQ(5U, range.end());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ range = model.render_text()->selection();
+ EXPECT_FALSE(range.is_empty());
+ EXPECT_EQ(0U, range.start());
+ EXPECT_EQ(4U, range.end());
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ range = model.render_text()->selection();
+ EXPECT_TRUE(range.is_empty());
+ EXPECT_EQ(0U, range.start());
+ EXPECT_EQ(0U, range.end());
+
+ // now from the end.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ range = model.render_text()->selection();
+ EXPECT_TRUE(range.is_empty());
+ EXPECT_EQ(11U, range.start());
+ EXPECT_EQ(11U, range.end());
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ range = model.render_text()->selection();
+ EXPECT_FALSE(range.is_empty());
+ EXPECT_TRUE(range.is_reversed());
+ EXPECT_EQ(11U, range.start());
+ EXPECT_EQ(6U, range.end());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ range = model.render_text()->selection();
+ EXPECT_FALSE(range.is_empty());
+ EXPECT_TRUE(range.is_reversed());
+ EXPECT_EQ(11U, range.start());
+ EXPECT_EQ(7U, range.end());
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ range = model.render_text()->selection();
+ EXPECT_TRUE(range.is_empty());
+ EXPECT_EQ(11U, range.start());
+ EXPECT_EQ(11U, range.end());
+
+ // Select All
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ range = model.render_text()->selection();
+ EXPECT_FALSE(range.is_empty());
+ EXPECT_TRUE(range.is_reversed());
+ EXPECT_EQ(11U, range.start());
+ EXPECT_EQ(0U, range.end());
+}
+
+TEST_F(TextfieldModelTest, SelectRangeTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
+ gfx::Range range(0, 6);
+ EXPECT_FALSE(range.is_reversed());
+ model.SelectRange(range);
+ EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
+
+ range = gfx::Range(6, 1);
+ EXPECT_TRUE(range.is_reversed());
+ model.SelectRange(range);
+ EXPECT_STR_EQ("ELLO ", model.GetSelectedText());
+
+ range = gfx::Range(2, 1000);
+ EXPECT_FALSE(range.is_reversed());
+ model.SelectRange(range);
+ EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText());
+
+ range = gfx::Range(1000, 3);
+ EXPECT_TRUE(range.is_reversed());
+ model.SelectRange(range);
+ EXPECT_STR_EQ("LO WORLD", model.GetSelectedText());
+
+ range = gfx::Range(0, 0);
+ EXPECT_TRUE(range.is_empty());
+ model.SelectRange(range);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ range = gfx::Range(3, 3);
+ EXPECT_TRUE(range.is_empty());
+ model.SelectRange(range);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ range = gfx::Range(1000, 100);
+ EXPECT_FALSE(range.is_empty());
+ model.SelectRange(range);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ range = gfx::Range(1000, 1000);
+ EXPECT_TRUE(range.is_empty());
+ model.SelectRange(range);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+}
+
+TEST_F(TextfieldModelTest, SelectionTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ gfx::Range selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(0), selection);
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(0, 5), selection);
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(0, 4), selection);
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(0), selection);
+
+ // now from the end.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(11), selection);
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(11, 6), selection);
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(11, 7), selection);
+
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(11), selection);
+
+ // Select All
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ selection = model.render_text()->selection();
+ EXPECT_EQ(gfx::Range(11, 0), selection);
+}
+
+TEST_F(TextfieldModelTest, SelectSelectionModelTest) {
+ TextfieldModel model(NULL);
+ model.Append(base::ASCIIToUTF16("HELLO WORLD"));
+ model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(0, 6),
+ gfx::CURSOR_BACKWARD));
+ EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
+
+ model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(6, 1),
+ gfx::CURSOR_FORWARD));
+ EXPECT_STR_EQ("ELLO ", model.GetSelectedText());
+
+ model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(2, 1000),
+ gfx::CURSOR_BACKWARD));
+ EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText());
+
+ model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 3),
+ gfx::CURSOR_FORWARD));
+ EXPECT_STR_EQ("LO WORLD", model.GetSelectedText());
+
+ model.SelectSelectionModel(gfx::SelectionModel(0, gfx::CURSOR_FORWARD));
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ model.SelectSelectionModel(gfx::SelectionModel(3, gfx::CURSOR_FORWARD));
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 100),
+ gfx::CURSOR_FORWARD));
+ EXPECT_TRUE(model.GetSelectedText().empty());
+
+ model.SelectSelectionModel(gfx::SelectionModel(1000, gfx::CURSOR_BACKWARD));
+ EXPECT_TRUE(model.GetSelectedText().empty());
+}
+
+TEST_F(TextfieldModelTest, CompositionTextTest) {
+ TextfieldModel model(this);
+ model.Append(base::ASCIIToUTF16("1234590"));
+ model.SelectRange(gfx::Range(5, 5));
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+
+ gfx::Range range;
+ model.GetTextRange(&range);
+ EXPECT_EQ(gfx::Range(0, 7), range);
+
+ ui::CompositionText composition;
+ composition.text = base::ASCIIToUTF16("678");
+ composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
+
+ // Cursor should be at the end of composition when characters are just typed.
+ composition.selection = gfx::Range(3, 3);
+ model.SetCompositionText(composition);
+ EXPECT_TRUE(model.HasCompositionText());
+ EXPECT_FALSE(model.HasSelection());
+
+ // Cancel the composition.
+ model.CancelCompositionText();
+ composition_text_confirmed_or_cleared_ = false;
+
+ // Restart composition with targeting "67" in "678".
+ composition.selection = gfx::Range(0, 2);
+ composition.underlines.clear();
+ composition.underlines.push_back(ui::CompositionUnderline(0, 2, 0, true));
+ composition.underlines.push_back(ui::CompositionUnderline(2, 3, 0, false));
+ model.SetCompositionText(composition);
+ EXPECT_TRUE(model.HasCompositionText());
+ EXPECT_TRUE(model.HasSelection());
+ EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
+
+ model.GetTextRange(&range);
+ EXPECT_EQ(10U, range.end());
+ EXPECT_STR_EQ("1234567890", model.text());
+
+ model.GetCompositionTextRange(&range);
+ EXPECT_EQ(gfx::Range(5, 8), range);
+ // Check the composition text.
+ EXPECT_STR_EQ("456", model.GetTextFromRange(gfx::Range(3, 6)));
+ EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
+
+ EXPECT_FALSE(composition_text_confirmed_or_cleared_);
+ model.CancelCompositionText();
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_FALSE(model.HasCompositionText());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("1234567890", model.text());
+ EXPECT_TRUE(model.SetText(base::ASCIIToUTF16("1234567890")));
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("1234567890678", model.text());
+
+ model.InsertText(base::UTF8ToUTF16("-"));
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("1234567890-", model.text());
+ EXPECT_FALSE(model.HasCompositionText());
+ EXPECT_FALSE(model.HasSelection());
+
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_STR_EQ("-", model.GetSelectedText());
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("1234567890678", model.text());
+
+ model.ReplaceText(base::UTF8ToUTF16("-"));
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("1234567890-", model.text());
+ EXPECT_FALSE(model.HasCompositionText());
+ EXPECT_FALSE(model.HasSelection());
+
+ model.SetCompositionText(composition);
+ model.Append(base::UTF8ToUTF16("-"));
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("1234567890-678-", model.text());
+
+ model.SetCompositionText(composition);
+ model.Delete();
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("1234567890-678-", model.text());
+
+ model.SetCompositionText(composition);
+ model.Backspace();
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("1234567890-678-", model.text());
+
+ model.SetText(base::string16());
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("676788", model.text());
+ EXPECT_EQ(6U, model.GetCursorPosition());
+
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("676788678", model.text());
+
+ model.SetText(base::string16());
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678678", model.text());
+
+ model.SetCompositionText(composition);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678", model.text());
+
+ model.SetCompositionText(composition);
+ gfx::SelectionModel sel(
+ gfx::Range(model.render_text()->selection().start(), 0),
+ gfx::CURSOR_FORWARD);
+ model.MoveCursorTo(sel);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678678", model.text());
+
+ model.SetCompositionText(composition);
+ model.SelectRange(gfx::Range(0, 3));
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678", model.text());
+
+ model.SetCompositionText(composition);
+ model.SelectAll(false);
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678", model.text());
+
+ model.SetCompositionText(composition);
+ model.SelectWord();
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+ EXPECT_STR_EQ("678", model.text());
+
+ model.SetCompositionText(composition);
+ model.ClearSelection();
+ EXPECT_TRUE(composition_text_confirmed_or_cleared_);
+ composition_text_confirmed_or_cleared_ = false;
+
+ model.SetCompositionText(composition);
+ EXPECT_FALSE(model.Cut());
+ EXPECT_FALSE(composition_text_confirmed_or_cleared_);
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_BasicTest) {
+ TextfieldModel model(NULL);
+ model.InsertChar('a');
+ EXPECT_FALSE(model.Redo()); // There is nothing to redo.
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("a", model.text());
+
+ // Continuous inserts are treated as one edit.
+ model.InsertChar('b');
+ model.InsertChar('c');
+ EXPECT_STR_EQ("abc", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("a", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+
+ // Undoing further shouldn't change the text.
+ EXPECT_FALSE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+
+ // Redoing to the latest text.
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("a", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("abc", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+
+ // Backspace ===============================
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("ab", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("abc", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ab", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ // Continous backspaces are treated as one edit.
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("", model.text());
+ // Extra backspace shouldn't affect the history.
+ EXPECT_FALSE(model.Backspace());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ab", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("abc", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("a", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+
+ // Clear history
+ model.ClearEditHistory();
+ EXPECT_FALSE(model.Undo());
+ EXPECT_FALSE(model.Redo());
+ EXPECT_STR_EQ("a", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+
+ // Delete ===============================
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.ClearEditHistory();
+ MoveCursorTo(model, 2);
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("ABDE", model.text());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("BDE", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABDE", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABDE", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ // Continous deletes are treated as one edit.
+ EXPECT_TRUE(model.Delete());
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("AB", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABDE", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("AB", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_SetText) {
+ // This is to test the undo/redo behavior of omnibox.
+ TextfieldModel model(NULL);
+ model.InsertChar('w');
+ EXPECT_STR_EQ("w", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
+ EXPECT_EQ(14U, model.GetCursorPosition());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ model.SelectRange(gfx::Range(14, 1));
+ model.InsertChar('w');
+ EXPECT_STR_EQ("ww", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
+ model.SelectRange(gfx::Range(14, 2));
+ model.InsertChar('w');
+ EXPECT_STR_EQ("www", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
+ model.SelectRange(gfx::Range(14, 3));
+ model.InsertChar('.');
+ EXPECT_STR_EQ("www.", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
+ model.SelectRange(gfx::Range(14, 4));
+ model.InsertChar('y');
+ EXPECT_STR_EQ("www.y", model.text());
+ model.SetText(base::ASCIIToUTF16("www.youtube.com"));
+ EXPECT_STR_EQ("www.youtube.com", model.text());
+ EXPECT_EQ(15U, model.GetCursorPosition());
+
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("www.youtube.com", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_BackspaceThenSetText) {
+ // This is to test the undo/redo behavior of omnibox.
+ TextfieldModel model(NULL);
+ model.InsertChar('w');
+ EXPECT_STR_EQ("w", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.SetText(base::ASCIIToUTF16("www.google.com"));
+ EXPECT_EQ(14U, model.GetCursorPosition());
+ EXPECT_STR_EQ("www.google.com", model.text());
+ model.SetText(base::ASCIIToUTF16("www.google.com")); // Confirm the text.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_EQ(14U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("www.google.c", model.text());
+ // Autocomplete sets the text.
+ model.SetText(base::ASCIIToUTF16("www.google.com/search=www.google.c"));
+ EXPECT_STR_EQ("www.google.com/search=www.google.c", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.c", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("www.google.com", model.text());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ EXPECT_FALSE(model.Redo()); // There is nothing to redo.
+ // Test Cut.
+ model.SelectRange(gfx::Range(1, 3));
+ model.Cut();
+ EXPECT_STR_EQ("ADE", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Undo()); // There is no more to undo.
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ADE", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo()); // There is no more to redo.
+ EXPECT_STR_EQ("ADE", model.text());
+
+ model.Paste();
+ model.Paste();
+ model.Paste();
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
+ EXPECT_EQ(7U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ADE", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+
+ // Test Redo.
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ADE", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
+ EXPECT_EQ(7U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+
+ // Test using SelectRange.
+ model.SelectRange(gfx::Range(1, 3));
+ EXPECT_TRUE(model.Cut());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.SelectRange(gfx::Range(1, 1));
+ EXPECT_FALSE(model.Cut());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(model.Paste());
+ EXPECT_STR_EQ("ABCBCDEBC", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCBCDE", model.text());
+ EXPECT_EQ(7U, model.GetCursorPosition());
+ // An empty cut shouldn't create an edit.
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCBCBCDE", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+
+ // Test Copy.
+ ResetModel(&model);
+ model.SetText(base::ASCIIToUTF16("12345"));
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ model.SelectRange(gfx::Range(1, 3));
+ model.Copy(); // Copy "23".
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.Paste(); // Paste "23" into "23".
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.Paste();
+ EXPECT_STR_EQ("1232345", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ // TODO(oshima): Change the return type from bool to enum.
+ EXPECT_FALSE(model.Undo()); // No text change.
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_FALSE(model.Undo());
+ // Test Redo.
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("12345", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("12345", model.text()); // For 1st paste
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("1232345", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+ EXPECT_STR_EQ("1232345", model.text());
+
+ // Test using SelectRange.
+ model.SelectRange(gfx::Range(1, 3));
+ model.Copy();
+ EXPECT_STR_EQ("1232345", model.text());
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ EXPECT_TRUE(model.Paste());
+ EXPECT_STR_EQ("123234523", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("1232345", model.text());
+ EXPECT_EQ(7U, model.GetCursorPosition());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_CursorTest) {
+ TextfieldModel model(NULL);
+ model.InsertChar('a');
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.InsertChar('b');
+ // Moving the cursor shouldn't create a new edit.
+ EXPECT_STR_EQ("ab", model.text());
+ EXPECT_FALSE(model.Redo());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ab", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+}
+
+void RunInsertReplaceTest(TextfieldModel& model) {
+ const bool reverse = model.render_text()->selection().is_reversed();
+ model.InsertChar('1');
+ model.InsertChar('2');
+ model.InsertChar('3');
+ EXPECT_STR_EQ("a123d", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("abcd", model.text());
+ EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("abcd", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("a123d", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+}
+
+void RunOverwriteReplaceTest(TextfieldModel& model) {
+ const bool reverse = model.render_text()->selection().is_reversed();
+ model.ReplaceChar('1');
+ model.ReplaceChar('2');
+ model.ReplaceChar('3');
+ model.ReplaceChar('4');
+ EXPECT_STR_EQ("a1234", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("abcd", model.text());
+ EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Undo());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("abcd", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("a1234", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_FALSE(model.Redo());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_ReplaceTest) {
+ {
+ SCOPED_TRACE("Select forwards and insert.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SelectRange(gfx::Range(1, 3));
+ RunInsertReplaceTest(model);
+ }
+ {
+ SCOPED_TRACE("Select reversed and insert.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SelectRange(gfx::Range(3, 1));
+ RunInsertReplaceTest(model);
+ }
+ {
+ SCOPED_TRACE("Select forwards and overwrite.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SelectRange(gfx::Range(1, 3));
+ RunOverwriteReplaceTest(model);
+ }
+ {
+ SCOPED_TRACE("Select reversed and overwrite.");
+ TextfieldModel model(NULL);
+ model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SelectRange(gfx::Range(3, 1));
+ RunOverwriteReplaceTest(model);
+ }
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
+ TextfieldModel model(NULL);
+
+ ui::CompositionText composition;
+ composition.text = base::ASCIIToUTF16("abc");
+ composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
+ composition.selection = gfx::Range(2, 3);
+
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.InsertChar('x');
+ EXPECT_STR_EQ("ABCDEx", model.text());
+ EXPECT_TRUE(model.Undo()); // set composition should forget undone edit.
+ model.SetCompositionText(composition);
+ EXPECT_TRUE(model.HasCompositionText());
+ EXPECT_TRUE(model.HasSelection());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+
+ // Confirm the composition.
+ model.ConfirmCompositionText();
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_FALSE(model.Redo());
+
+ // Cancel the composition.
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("abcABCDEabc", model.text());
+ model.CancelCompositionText();
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_FALSE(model.Redo());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_FALSE(model.Redo());
+
+ // Call SetText with the same text as the result.
+ ResetModel(&model);
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ model.SetText(base::ASCIIToUTF16("ABCDEabc"));
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_FALSE(model.Redo());
+
+ // Call SetText with a different result; the composition should be forgotten.
+ ResetModel(&model);
+ model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.SetCompositionText(composition);
+ EXPECT_STR_EQ("ABCDEabc", model.text());
+ model.SetText(base::ASCIIToUTF16("1234"));
+ EXPECT_STR_EQ("1234", model.text());
+ EXPECT_TRUE(model.Undo());
+ EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_TRUE(model.Redo());
+ EXPECT_STR_EQ("1234", model.text());
+ EXPECT_FALSE(model.Redo());
+
+ // TODO(oshima): Test the behavior with an IME.
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.cc b/chromium/ui/views/controls/textfield/textfield_test_api.cc
new file mode 100644
index 00000000000..be45d24cc42
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/textfield/textfield_test_api.h"
+
+namespace views {
+
+TextfieldTestApi::TextfieldTestApi(Textfield* textfield)
+ : textfield_(textfield) {
+ DCHECK(textfield);
+}
+
+void TextfieldTestApi::UpdateContextMenu() {
+ textfield_->UpdateContextMenu();
+}
+
+gfx::RenderText* TextfieldTestApi::GetRenderText() const {
+ return textfield_->GetRenderText();
+}
+
+void TextfieldTestApi::CreateTouchSelectionControllerAndNotifyIt() {
+ textfield_->CreateTouchSelectionControllerAndNotifyIt();
+}
+
+void TextfieldTestApi::ResetTouchSelectionController() {
+ textfield_->touch_selection_controller_.reset();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.h b/chromium/ui/views/controls/textfield/textfield_test_api.h
new file mode 100644
index 00000000000..1af2ffcdf62
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
+
+#include "ui/views/controls/textfield/textfield.h"
+
+namespace views {
+
+// Helper class to access internal state of Textfield in tests.
+class TextfieldTestApi {
+ public:
+ explicit TextfieldTestApi(Textfield* textfield);
+
+ void UpdateContextMenu();
+
+ gfx::RenderText* GetRenderText() const;
+
+ void CreateTouchSelectionControllerAndNotifyIt();
+
+ void ResetTouchSelectionController();
+
+ TextfieldModel* model() const { return textfield_->model_.get(); }
+
+ ui::MenuModel* context_menu_contents() const {
+ return textfield_->context_menu_contents_.get();
+ }
+
+ ui::TouchSelectionController* touch_selection_controller() const {
+ return textfield_->touch_selection_controller_.get();
+ }
+
+ private:
+ Textfield* textfield_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldTestApi);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
new file mode 100644
index 00000000000..8a8f9ace8f5
--- /dev/null
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -0,0 +1,2012 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/textfield/textfield.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "grit/ui_strings.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/render_text.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/controls/textfield/textfield_model.h"
+#include "ui/views/controls/textfield/textfield_test_api.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/ime/mock_input_method.h"
+#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+#include "url/gurl.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+#endif
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
+
+#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
+
+namespace {
+
+const base::char16 kHebrewLetterSamekh = 0x05E1;
+
+// A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults.
+class TestTextfield : public views::Textfield {
+ public:
+ TestTextfield() : Textfield(), key_handled_(false), key_received_(false) {}
+
+ virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
+ key_received_ = true;
+ key_handled_ = views::Textfield::OnKeyPressed(e);
+ return key_handled_;
+ }
+
+ virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE {
+ key_received_ = true;
+ key_handled_ = views::Textfield::OnKeyReleased(e);
+ return key_handled_;
+ }
+
+ bool key_handled() const { return key_handled_; }
+ bool key_received() const { return key_received_; }
+
+ void clear() { key_received_ = key_handled_ = false; }
+
+ private:
+ bool key_handled_;
+ bool key_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTextfield);
+};
+
+// Convenience to make constructing a GestureEvent simpler.
+class GestureEventForTest : public ui::GestureEvent {
+ public:
+ GestureEventForTest(ui::EventType type, int x, int y, float delta_x,
+ float delta_y)
+ : GestureEvent(type, x, y, 0, base::TimeDelta(),
+ ui::GestureEventDetails(type, delta_x, delta_y), 0) {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
+};
+
+base::string16 GetClipboardText(ui::ClipboardType type) {
+ base::string16 text;
+ ui::Clipboard::GetForCurrentThread()->ReadText(type, &text);
+ return text;
+}
+
+void SetClipboardText(ui::ClipboardType type, const std::string& text) {
+ ui::ScopedClipboardWriter(ui::Clipboard::GetForCurrentThread(), type)
+ .WriteText(ASCIIToUTF16(text));
+}
+
+} // namespace
+
+namespace views {
+
+class TextfieldTest : public ViewsTestBase, public TextfieldController {
+ public:
+ TextfieldTest()
+ : widget_(NULL),
+ textfield_(NULL),
+ model_(NULL),
+ input_method_(NULL),
+ on_before_user_action_(0),
+ on_after_user_action_(0),
+ copied_to_clipboard_(ui::CLIPBOARD_TYPE_LAST) {
+ }
+
+ // ::testing::Test:
+ virtual void SetUp() {
+ ViewsTestBase::SetUp();
+ }
+
+ virtual void TearDown() {
+ if (widget_)
+ widget_->Close();
+ ViewsTestBase::TearDown();
+ }
+
+ ui::ClipboardType GetAndResetCopiedToClipboard() {
+ ui::ClipboardType clipboard_type = copied_to_clipboard_;
+ copied_to_clipboard_ = ui::CLIPBOARD_TYPE_LAST;
+ return clipboard_type;
+ }
+
+ // TextfieldController:
+ virtual void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) OVERRIDE {
+ // Paste calls TextfieldController::ContentsChanged() explicitly even if the
+ // paste action did not change the content. So |new_contents| may match
+ // |last_contents_|. For more info, see http://crbug.com/79002
+ last_contents_ = new_contents;
+ }
+
+ virtual void OnBeforeUserAction(Textfield* sender) OVERRIDE {
+ ++on_before_user_action_;
+ }
+
+ virtual void OnAfterUserAction(Textfield* sender) OVERRIDE {
+ ++on_after_user_action_;
+ }
+
+ virtual void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) OVERRIDE {
+ copied_to_clipboard_ = clipboard_type;
+ }
+
+ void InitTextfield() {
+ InitTextfields(1);
+ }
+
+ void InitTextfields(int count) {
+ ASSERT_FALSE(textfield_);
+ textfield_ = new TestTextfield();
+ textfield_->set_controller(this);
+ widget_ = new Widget();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(100, 100, 100, 100);
+ widget_->Init(params);
+ View* container = new View();
+ widget_->SetContentsView(container);
+ container->AddChildView(textfield_);
+ textfield_->SetBoundsRect(params.bounds);
+ textfield_->set_id(1);
+ test_api_.reset(new TextfieldTestApi(textfield_));
+
+ for (int i = 1; i < count; i++) {
+ Textfield* textfield = new Textfield();
+ container->AddChildView(textfield);
+ textfield->set_id(i + 1);
+ }
+
+ model_ = test_api_->model();
+ model_->ClearEditHistory();
+
+ input_method_ = new MockInputMethod();
+ widget_->ReplaceInputMethod(input_method_);
+
+ // Activate the widget and focus the textfield for input handling.
+ widget_->Activate();
+ textfield_->RequestFocus();
+ }
+
+ ui::MenuModel* GetContextMenuModel() {
+ test_api_->UpdateContextMenu();
+ return test_api_->context_menu_contents();
+ }
+
+ protected:
+ void SendKeyEvent(ui::KeyboardCode key_code,
+ bool alt,
+ bool shift,
+ bool control,
+ bool caps_lock) {
+ int flags = (alt ? ui::EF_ALT_DOWN : 0) |
+ (shift ? ui::EF_SHIFT_DOWN : 0) |
+ (control ? ui::EF_CONTROL_DOWN : 0) |
+ (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0);
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags, false);
+ input_method_->DispatchKeyEvent(event);
+ }
+
+ void SendKeyEvent(ui::KeyboardCode key_code, bool shift, bool control) {
+ SendKeyEvent(key_code, false, shift, control, false);
+ }
+
+ void SendKeyEvent(ui::KeyboardCode key_code) {
+ SendKeyEvent(key_code, false, false);
+ }
+
+ void SendKeyEvent(base::char16 ch) {
+ if (ch < 0x80) {
+ ui::KeyboardCode code =
+ ch == ' ' ? ui::VKEY_SPACE :
+ static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a');
+ SendKeyEvent(code);
+ } else {
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false);
+ event.set_character(ch);
+ input_method_->DispatchKeyEvent(event);
+ }
+ }
+
+ View* GetFocusedView() {
+ return widget_->GetFocusManager()->GetFocusedView();
+ }
+
+ int GetCursorPositionX(int cursor_pos) {
+ return test_api_->GetRenderText()->GetCursorBounds(
+ gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x();
+ }
+
+ // Get the current cursor bounds.
+ gfx::Rect GetCursorBounds() {
+ return test_api_->GetRenderText()->GetUpdatedCursorBounds();
+ }
+
+ // Get the cursor bounds of |sel|.
+ gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) {
+ return test_api_->GetRenderText()->GetCursorBounds(sel, true);
+ }
+
+ gfx::Rect GetDisplayRect() {
+ return test_api_->GetRenderText()->display_rect();
+ }
+
+ // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and
+ // y-axis is in the middle of |bound|'s vertical range.
+ void MouseClick(const gfx::Rect bound, int x_offset) {
+ gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2);
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
+ }
+
+ // This is to avoid double/triple click.
+ void NonClientMouseClick() {
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
+ }
+
+ void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
+ bool can_undo,
+ ui::MenuModel* menu) {
+ 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 */));
+ 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_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */));
+ }
+
+ // We need widget to populate wrapper class.
+ Widget* widget_;
+
+ TestTextfield* textfield_;
+ scoped_ptr<TextfieldTestApi> test_api_;
+ TextfieldModel* model_;
+
+ // The string from Controller::ContentsChanged callback.
+ base::string16 last_contents_;
+
+ // For testing input method related behaviors.
+ MockInputMethod* input_method_;
+
+ // Indicates how many times OnBeforeUserAction() is called.
+ int on_before_user_action_;
+
+ // Indicates how many times OnAfterUserAction() is called.
+ int on_after_user_action_;
+
+ private:
+ ui::ClipboardType copied_to_clipboard_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextfieldTest);
+};
+
+TEST_F(TextfieldTest, ModelChangesTest) {
+ InitTextfield();
+
+ // TextfieldController::ContentsChanged() shouldn't be called when changing
+ // text programmatically.
+ last_contents_.clear();
+ textfield_->SetText(ASCIIToUTF16("this is"));
+
+ EXPECT_STR_EQ("this is", model_->text());
+ EXPECT_STR_EQ("this is", textfield_->text());
+ EXPECT_TRUE(last_contents_.empty());
+
+ textfield_->AppendText(ASCIIToUTF16(" a test"));
+ EXPECT_STR_EQ("this is a test", model_->text());
+ EXPECT_STR_EQ("this is a test", textfield_->text());
+ EXPECT_TRUE(last_contents_.empty());
+
+ EXPECT_EQ(base::string16(), textfield_->GetSelectedText());
+ textfield_->SelectAll(false);
+ EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
+ EXPECT_TRUE(last_contents_.empty());
+}
+
+TEST_F(TextfieldTest, KeyTest) {
+ InitTextfield();
+ // Event flags: key, alt, shift, ctrl, caps-lock.
+ SendKeyEvent(ui::VKEY_T, false, true, false, false);
+ SendKeyEvent(ui::VKEY_E, false, false, false, false);
+ SendKeyEvent(ui::VKEY_X, false, true, false, true);
+ SendKeyEvent(ui::VKEY_T, false, false, false, true);
+ SendKeyEvent(ui::VKEY_1, false, true, false, false);
+ SendKeyEvent(ui::VKEY_1, false, false, false, false);
+ SendKeyEvent(ui::VKEY_1, false, true, false, true);
+ SendKeyEvent(ui::VKEY_1, false, false, false, true);
+ EXPECT_STR_EQ("TexT!1!1", textfield_->text());
+}
+
+TEST_F(TextfieldTest, ControlAndSelectTest) {
+ // Insert a test string in a textfield.
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("one two three"));
+ SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */);
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+
+ EXPECT_STR_EQ("one", textfield_->GetSelectedText());
+
+ // Test word select.
+ SendKeyEvent(ui::VKEY_RIGHT, true, true);
+ EXPECT_STR_EQ("one two", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_RIGHT, true, true);
+ EXPECT_STR_EQ("one two three", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_LEFT, true, true);
+ EXPECT_STR_EQ("one two ", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_LEFT, true, true);
+ EXPECT_STR_EQ("one ", textfield_->GetSelectedText());
+
+ // Replace the selected text.
+ SendKeyEvent(ui::VKEY_Z, true, false);
+ SendKeyEvent(ui::VKEY_E, true, false);
+ SendKeyEvent(ui::VKEY_R, true, false);
+ SendKeyEvent(ui::VKEY_O, true, false);
+ SendKeyEvent(ui::VKEY_SPACE, false, false);
+ EXPECT_STR_EQ("ZERO two three", textfield_->text());
+
+ SendKeyEvent(ui::VKEY_END, true, false);
+ EXPECT_STR_EQ("two three", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_HOME, true, false);
+ EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
+}
+
+TEST_F(TextfieldTest, InsertionDeletionTest) {
+ // Insert a test string in a textfield.
+ InitTextfield();
+ for (size_t i = 0; i < 10; i++)
+ SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i));
+ EXPECT_STR_EQ("abcdefghij", textfield_->text());
+
+ // Test the delete and backspace keys.
+ textfield_->SelectRange(gfx::Range(5));
+ for (int i = 0; i < 3; i++)
+ SendKeyEvent(ui::VKEY_BACK);
+ EXPECT_STR_EQ("abfghij", textfield_->text());
+ for (int i = 0; i < 3; i++)
+ SendKeyEvent(ui::VKEY_DELETE);
+ EXPECT_STR_EQ("abij", textfield_->text());
+
+ // Select all and replace with "k".
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_K);
+ EXPECT_STR_EQ("k", textfield_->text());
+
+ // Delete the previous word from cursor.
+ textfield_->SetText(ASCIIToUTF16("one two three four"));
+ SendKeyEvent(ui::VKEY_END);
+ SendKeyEvent(ui::VKEY_BACK, false, false, true, false);
+ EXPECT_STR_EQ("one two three ", textfield_->text());
+
+ // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
+ SendKeyEvent(ui::VKEY_LEFT, false, false, true, false);
+ SendKeyEvent(ui::VKEY_BACK, false, true, true, false);
+#if defined(OS_LINUX)
+ EXPECT_STR_EQ("three ", textfield_->text());
+#else
+ EXPECT_STR_EQ("one three ", textfield_->text());
+#endif
+
+ // Delete the next word from cursor.
+ textfield_->SetText(ASCIIToUTF16("one two three four"));
+ SendKeyEvent(ui::VKEY_HOME);
+ SendKeyEvent(ui::VKEY_DELETE, false, false, true, false);
+ EXPECT_STR_EQ(" two three four", textfield_->text());
+
+ // Delete to a line break on Linux and ChromeOS, to a word break on Windows.
+ SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false);
+ SendKeyEvent(ui::VKEY_DELETE, false, true, true, false);
+#if defined(OS_LINUX)
+ EXPECT_STR_EQ(" two", textfield_->text());
+#else
+ EXPECT_STR_EQ(" two four", textfield_->text());
+#endif
+}
+
+TEST_F(TextfieldTest, PasswordTest) {
+ InitTextfield();
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
+ EXPECT_TRUE(textfield_->enabled());
+ EXPECT_TRUE(textfield_->IsFocusable());
+
+ last_contents_.clear();
+ textfield_->SetText(ASCIIToUTF16("password"));
+ // Ensure text() and the callback returns the actual text instead of "*".
+ EXPECT_STR_EQ("password", textfield_->text());
+ EXPECT_TRUE(last_contents_.empty());
+ model_->SelectAll(false);
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "foo");
+
+ // Cut and copy should be disabled.
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ SendKeyEvent(ui::VKEY_X, false, true);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ SendKeyEvent(ui::VKEY_C, false, true);
+ SendKeyEvent(ui::VKEY_INSERT, false, true);
+ EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("password", textfield_->text());
+ // [Shift]+[Delete] should just delete without copying text to the clipboard.
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_DELETE, true, false);
+
+ // Paste should work normally.
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ SendKeyEvent(ui::VKEY_V, false, true);
+ SendKeyEvent(ui::VKEY_INSERT, true, false);
+ EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("foofoofoo", textfield_->text());
+}
+
+TEST_F(TextfieldTest, TextInputType) {
+ InitTextfield();
+
+ // Defaults to TEXT
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, textfield_->GetTextInputType());
+
+ // And can be set.
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, textfield_->GetTextInputType());
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
+
+ // Readonly textfields have type NONE
+ textfield_->SetReadOnly(true);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
+
+ textfield_->SetReadOnly(false);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
+
+ // As do disabled textfields
+ textfield_->SetEnabled(false);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType());
+
+ textfield_->SetEnabled(true);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
+}
+
+TEST_F(TextfieldTest, OnKeyPress) {
+ InitTextfield();
+
+ // Character keys are handled by the input method.
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ textfield_->clear();
+
+ // Arrow keys and home/end are handled by the textfield.
+ SendKeyEvent(ui::VKEY_LEFT);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_RIGHT);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_HOME);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_END);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ textfield_->clear();
+
+ // F24, up/down key won't be handled.
+ SendKeyEvent(ui::VKEY_F24);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_UP);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_DOWN);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ textfield_->clear();
+}
+
+// Tests that default key bindings are handled even with a delegate installed.
+TEST_F(TextfieldTest, OnKeyPressBinding) {
+ InitTextfield();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Install a TextEditKeyBindingsDelegateAuraLinux that does nothing.
+ class TestDelegate : public ui::TextEditKeyBindingsDelegateAuraLinux {
+ public:
+ TestDelegate() {}
+ virtual ~TestDelegate() {}
+
+ virtual bool MatchEvent(
+ const ui::Event& event,
+ std::vector<ui::TextEditCommandAuraLinux>* commands) OVERRIDE {
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+ };
+
+ TestDelegate delegate;
+ ui::SetTextEditKeyBindingsDelegate(&delegate);
+#endif
+
+ SendKeyEvent(ui::VKEY_A, false, false);
+ EXPECT_STR_EQ("a", textfield_->text());
+ textfield_->clear();
+
+ // Undo/Redo command keys are handled by the textfield.
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_TRUE(textfield_->text().empty());
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_Z, true, true);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_STR_EQ("a", textfield_->text());
+ textfield_->clear();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ ui::SetTextEditKeyBindingsDelegate(NULL);
+#endif
+}
+
+TEST_F(TextfieldTest, CursorMovement) {
+ InitTextfield();
+
+ // Test with trailing whitespace.
+ textfield_->SetText(ASCIIToUTF16("one two hre "));
+
+ // Send the cursor at the end.
+ SendKeyEvent(ui::VKEY_END);
+
+ // Ctrl+Left should move the cursor just before the last word.
+ SendKeyEvent(ui::VKEY_LEFT, false, true);
+ SendKeyEvent(ui::VKEY_T);
+ EXPECT_STR_EQ("one two thre ", textfield_->text());
+ EXPECT_STR_EQ("one two thre ", last_contents_);
+
+ // Ctrl+Right should move the cursor to the end of the last word.
+ SendKeyEvent(ui::VKEY_RIGHT, false, true);
+ SendKeyEvent(ui::VKEY_E);
+ EXPECT_STR_EQ("one two three ", textfield_->text());
+ EXPECT_STR_EQ("one two three ", last_contents_);
+
+ // Ctrl+Right again should move the cursor to the end.
+ SendKeyEvent(ui::VKEY_RIGHT, false, true);
+ SendKeyEvent(ui::VKEY_BACK);
+ EXPECT_STR_EQ("one two three", textfield_->text());
+ EXPECT_STR_EQ("one two three", last_contents_);
+
+ // Test with leading whitespace.
+ textfield_->SetText(ASCIIToUTF16(" ne two"));
+
+ // Send the cursor at the beginning.
+ SendKeyEvent(ui::VKEY_HOME);
+
+ // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the
+ // first word.
+ SendKeyEvent(ui::VKEY_RIGHT, false, true);
+ SendKeyEvent(ui::VKEY_LEFT, false, true);
+ SendKeyEvent(ui::VKEY_O);
+ EXPECT_STR_EQ(" one two", textfield_->text());
+ EXPECT_STR_EQ(" one two", last_contents_);
+
+ // Ctrl+Left to move the cursor to the beginning of the first word.
+ SendKeyEvent(ui::VKEY_LEFT, false, true);
+ // Ctrl+Left again should move the cursor back to the very beginning.
+ SendKeyEvent(ui::VKEY_LEFT, false, true);
+ SendKeyEvent(ui::VKEY_DELETE);
+ EXPECT_STR_EQ("one two", textfield_->text());
+ EXPECT_STR_EQ("one two", last_contents_);
+}
+
+TEST_F(TextfieldTest, FocusTraversalTest) {
+ InitTextfields(3);
+ textfield_->RequestFocus();
+
+ EXPECT_EQ(1, GetFocusedView()->id());
+ widget_->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_EQ(2, GetFocusedView()->id());
+ widget_->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_EQ(3, GetFocusedView()->id());
+ // Cycle back to the first textfield.
+ widget_->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_EQ(1, GetFocusedView()->id());
+
+ widget_->GetFocusManager()->AdvanceFocus(true);
+ EXPECT_EQ(3, GetFocusedView()->id());
+ widget_->GetFocusManager()->AdvanceFocus(true);
+ EXPECT_EQ(2, GetFocusedView()->id());
+ widget_->GetFocusManager()->AdvanceFocus(true);
+ EXPECT_EQ(1, GetFocusedView()->id());
+ // Cycle back to the last textfield.
+ widget_->GetFocusManager()->AdvanceFocus(true);
+ EXPECT_EQ(3, GetFocusedView()->id());
+
+ // Request focus should still work.
+ textfield_->RequestFocus();
+ EXPECT_EQ(1, GetFocusedView()->id());
+
+ // Test if clicking on textfield view sets the focus.
+ widget_->GetFocusManager()->AdvanceFocus(true);
+ EXPECT_EQ(3, GetFocusedView()->id());
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
+ EXPECT_EQ(1, GetFocusedView()->id());
+}
+
+TEST_F(TextfieldTest, ContextMenuDisplayTest) {
+ InitTextfield();
+ EXPECT_TRUE(textfield_->context_menu_controller());
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE);
+ textfield_->ClearEditHistory();
+ EXPECT_TRUE(GetContextMenuModel());
+ VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel());
+
+ textfield_->SelectAll(false);
+ VerifyTextfieldContextMenuContents(true, false, GetContextMenuModel());
+
+ SendKeyEvent(ui::VKEY_T);
+ VerifyTextfieldContextMenuContents(false, true, GetContextMenuModel());
+
+ textfield_->SelectAll(false);
+ VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
+
+ // Exercise the "paste enabled?" check in the verifier.
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel());
+}
+
+TEST_F(TextfieldTest, DoubleAndTripleClickTest) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent double_click(
+ ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
+ ui::EF_LEFT_MOUSE_BUTTON);
+
+ // Test for double click.
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
+ EXPECT_TRUE(textfield_->GetSelectedText().empty());
+ textfield_->OnMousePressed(double_click);
+ textfield_->OnMouseReleased(release);
+ EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
+
+ // Test for triple click.
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
+ EXPECT_STR_EQ("hello world", textfield_->GetSelectedText());
+
+ // Another click should reset back to double click.
+ textfield_->OnMousePressed(click);
+ textfield_->OnMouseReleased(release);
+ EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
+}
+
+TEST_F(TextfieldTest, DragToSelect) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ const int kStart = GetCursorPositionX(5);
+ const int kEnd = 500;
+ gfx::Point start_point(kStart, 0);
+ gfx::Point end_point(kEnd, 0);
+ ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point,
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->GetSelectedText().empty());
+ // Check that dragging left selects the beginning of the string.
+ textfield_->OnMouseDragged(drag_left);
+ base::string16 text_left = textfield_->GetSelectedText();
+ EXPECT_STR_EQ("hello", text_left);
+ // Check that dragging right selects the rest of the string.
+ textfield_->OnMouseDragged(drag_right);
+ base::string16 text_right = textfield_->GetSelectedText();
+ EXPECT_STR_EQ(" world", text_right);
+ // Check that releasing in the same location does not alter the selection.
+ textfield_->OnMouseReleased(release);
+ EXPECT_EQ(text_right, textfield_->GetSelectedText());
+ // Check that dragging from beyond the text length works too.
+ textfield_->OnMousePressed(click_b);
+ textfield_->OnMouseDragged(drag_left);
+ textfield_->OnMouseReleased(release);
+ EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
+}
+
+#if defined(OS_WIN)
+TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ ui::OSExchangeData data;
+ base::string16 string(ASCIIToUTF16("string "));
+ data.SetString(string);
+ int formats = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Ensure that disabled textfields do not accept drops.
+ textfield_->SetEnabled(false);
+ EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(0, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_FALSE(textfield_->CanDrop(data));
+ textfield_->SetEnabled(true);
+
+ // Ensure that read-only textfields do not accept drops.
+ textfield_->SetReadOnly(true);
+ EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(0, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_FALSE(textfield_->CanDrop(data));
+ textfield_->SetReadOnly(false);
+
+ // Ensure that enabled and editable textfields do accept drops.
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_TRUE(textfield_->CanDrop(data));
+ gfx::Point drop_point(GetCursorPositionX(6), 0);
+ ui::DropTargetEvent drop(data, drop_point, drop_point,
+ ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
+ textfield_->OnDragUpdated(drop));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop));
+ EXPECT_STR_EQ("hello string world", textfield_->text());
+
+ // Ensure that textfields do not accept non-OSExchangeData::STRING types.
+ ui::OSExchangeData bad_data;
+ bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x")));
+ ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType();
+ bad_data.SetPickledData(fmt, Pickle());
+ bad_data.SetFileContents(base::FilePath(L"x"), "x");
+ bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org"));
+ ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL);
+ bad_data.SetDownloadFileInfo(download);
+ EXPECT_FALSE(textfield_->CanDrop(bad_data));
+}
+#endif
+
+TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello string world"));
+
+ // Ensure the textfield will provide selected text for drag data.
+ base::string16 string;
+ ui::OSExchangeData data;
+ const gfx::Range kStringRange(6, 12);
+ textfield_->SelectRange(kStringRange);
+ const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
+ textfield_->WriteDragDataForView(NULL, kStringPoint, &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+
+ // Ensure that disabled textfields do not support drag operations.
+ textfield_->SetEnabled(false);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SetEnabled(true);
+ // Ensure that textfields without selections do not support drag operations.
+ textfield_->ClearSelection();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SelectRange(kStringRange);
+ // Ensure that password textfields do not support drag operations.
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
+ // Ensure that textfields only initiate drag operations inside the selection.
+ ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press_event);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_->GetDragOperationsForView(NULL, gfx::Point()));
+ EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(),
+ gfx::Point()));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY,
+ textfield_->GetDragOperationsForView(NULL, kStringPoint));
+ EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
+ gfx::Point()));
+ // Ensure that textfields support local moves.
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ textfield_->GetDragOperationsForView(textfield_, kStringPoint));
+}
+
+TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ base::string16 string;
+ ui::OSExchangeData data;
+ int formats = 0;
+ int operations = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Start dragging "ello".
+ textfield_->SelectRange(gfx::Range(1, 5));
+ gfx::Point point(GetCursorPositionX(3), 0);
+ ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
+ gfx::Point()));
+ operations = textfield_->GetDragOperationsForView(textfield_,
+ click_a.location());
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ operations);
+ textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+
+ // Drop "ello" after "w".
+ const gfx::Point kDropPoint(GetCursorPositionX(7), 0);
+ EXPECT_TRUE(textfield_->CanDrop(data));
+ ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
+ EXPECT_STR_EQ("h welloorld", textfield_->text());
+ textfield_->OnDragDone();
+
+ // Undo/Redo the drag&drop change.
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("hello world", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("hello world", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("h welloorld", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("h welloorld", textfield_->text());
+}
+
+TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ base::string16 string;
+ ui::OSExchangeData data;
+ int formats = 0;
+ int operations = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Start dragging " worl".
+ textfield_->SelectRange(gfx::Range(5, 10));
+ gfx::Point point(GetCursorPositionX(7), 0);
+ ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(),
+ gfx::Point()));
+ operations = textfield_->GetDragOperationsForView(textfield_,
+ click_a.location());
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ operations);
+ textfield_->WriteDragDataForView(NULL, click_a.location(), &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+ EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+
+ // Drop " worl" after "h".
+ EXPECT_TRUE(textfield_->CanDrop(data));
+ gfx::Point drop_point(GetCursorPositionX(1), 0);
+ ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
+ EXPECT_STR_EQ("h worlellod", textfield_->text());
+ textfield_->OnDragDone();
+
+ // Undo/Redo the drag&drop change.
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("hello world", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("hello world", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("h worlellod", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("h worlellod", textfield_->text());
+}
+
+TEST_F(TextfieldTest, DragAndDrop_Canceled) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ // Start dragging "worl".
+ textfield_->SelectRange(gfx::Range(6, 10));
+ gfx::Point point(GetCursorPositionX(8), 0);
+ ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(click);
+ ui::OSExchangeData data;
+ textfield_->WriteDragDataForView(NULL, click.location(), &data);
+ EXPECT_TRUE(textfield_->CanDrop(data));
+ // Drag the text over somewhere valid, outside the current selection.
+ gfx::Point drop_point(GetCursorPositionX(2), 0);
+ ui::DropTargetEvent drop(data, drop_point, drop_point,
+ ui::DragDropTypes::DRAG_MOVE);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop));
+ // "Cancel" the drag, via move and release over the selection, and OnDragDone.
+ gfx::Point drag_point(GetCursorPositionX(9), 0);
+ ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point,
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseDragged(drag);
+ textfield_->OnMouseReleased(release);
+ textfield_->OnDragDone();
+ EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text());
+}
+
+TEST_F(TextfieldTest, ReadOnlyTest) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("read only"));
+ textfield_->SetReadOnly(true);
+ EXPECT_TRUE(textfield_->enabled());
+ EXPECT_TRUE(textfield_->IsFocusable());
+
+ SendKeyEvent(ui::VKEY_HOME);
+ EXPECT_EQ(0U, textfield_->GetCursorPosition());
+ SendKeyEvent(ui::VKEY_END);
+ EXPECT_EQ(9U, textfield_->GetCursorPosition());
+
+ SendKeyEvent(ui::VKEY_LEFT, false, false);
+ EXPECT_EQ(8U, textfield_->GetCursorPosition());
+ SendKeyEvent(ui::VKEY_LEFT, false, true);
+ EXPECT_EQ(5U, textfield_->GetCursorPosition());
+ SendKeyEvent(ui::VKEY_LEFT, true, true);
+ EXPECT_EQ(0U, textfield_->GetCursorPosition());
+ EXPECT_STR_EQ("read ", textfield_->GetSelectedText());
+ textfield_->SelectAll(false);
+ EXPECT_STR_EQ("read only", textfield_->GetSelectedText());
+
+ // Cut should be disabled.
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ SendKeyEvent(ui::VKEY_X, false, true);
+ SendKeyEvent(ui::VKEY_DELETE, true, false);
+ EXPECT_STR_EQ("Test", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("read only", textfield_->text());
+
+ // Paste should be disabled.
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ SendKeyEvent(ui::VKEY_V, false, true);
+ SendKeyEvent(ui::VKEY_INSERT, true, false);
+ EXPECT_STR_EQ("read only", textfield_->text());
+
+ // Copy should work normally.
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ SendKeyEvent(ui::VKEY_C, false, true);
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test");
+ SendKeyEvent(ui::VKEY_INSERT, false, true);
+ EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+
+ // SetText should work even in read only mode.
+ textfield_->SetText(ASCIIToUTF16(" four five six "));
+ EXPECT_STR_EQ(" four five six ", textfield_->text());
+
+ textfield_->SelectAll(false);
+ EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
+
+ // Text field is unmodifiable and selection shouldn't change.
+ SendKeyEvent(ui::VKEY_DELETE);
+ EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_BACK);
+ EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
+ SendKeyEvent(ui::VKEY_T);
+ EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
+}
+
+TEST_F(TextfieldTest, TextInputClientTest) {
+ InitTextfield();
+ ui::TextInputClient* client = textfield_->GetTextInputClient();
+ EXPECT_TRUE(client);
+ EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType());
+
+ textfield_->SetText(ASCIIToUTF16("0123456789"));
+ gfx::Range range;
+ EXPECT_TRUE(client->GetTextRange(&range));
+ EXPECT_EQ(0U, range.start());
+ EXPECT_EQ(10U, range.end());
+
+ EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4)));
+ EXPECT_TRUE(client->GetSelectionRange(&range));
+ EXPECT_EQ(gfx::Range(1, 4), range);
+
+ base::string16 substring;
+ EXPECT_TRUE(client->GetTextFromRange(range, &substring));
+ EXPECT_STR_EQ("123", substring);
+
+ EXPECT_TRUE(client->DeleteRange(range));
+ EXPECT_STR_EQ("0456789", textfield_->text());
+
+ ui::CompositionText composition;
+ composition.text = UTF8ToUTF16("321");
+ // Set composition through input method.
+ input_method_->Clear();
+ input_method_->SetCompositionTextForNextKey(composition);
+ textfield_->clear();
+
+ on_before_user_action_ = on_after_user_action_ = 0;
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_TRUE(client->HasCompositionText());
+ EXPECT_TRUE(client->GetCompositionTextRange(&range));
+ EXPECT_STR_EQ("0321456789", textfield_->text());
+ EXPECT_EQ(gfx::Range(1, 4), range);
+ EXPECT_EQ(1, on_before_user_action_);
+ EXPECT_EQ(1, on_after_user_action_);
+
+ input_method_->SetResultTextForNextKey(UTF8ToUTF16("123"));
+ on_before_user_action_ = on_after_user_action_ = 0;
+ textfield_->clear();
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_FALSE(textfield_->key_handled());
+ EXPECT_FALSE(client->HasCompositionText());
+ EXPECT_FALSE(input_method_->cancel_composition_called());
+ EXPECT_STR_EQ("0123456789", textfield_->text());
+ EXPECT_EQ(1, on_before_user_action_);
+ EXPECT_EQ(1, on_after_user_action_);
+
+ input_method_->Clear();
+ input_method_->SetCompositionTextForNextKey(composition);
+ textfield_->clear();
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_TRUE(client->HasCompositionText());
+ EXPECT_STR_EQ("0123321456789", textfield_->text());
+
+ on_before_user_action_ = on_after_user_action_ = 0;
+ textfield_->clear();
+ SendKeyEvent(ui::VKEY_RIGHT);
+ EXPECT_FALSE(client->HasCompositionText());
+ EXPECT_TRUE(input_method_->cancel_composition_called());
+ EXPECT_TRUE(textfield_->key_received());
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_STR_EQ("0123321456789", textfield_->text());
+ EXPECT_EQ(8U, textfield_->GetCursorPosition());
+ EXPECT_EQ(1, on_before_user_action_);
+ EXPECT_EQ(1, on_after_user_action_);
+
+ textfield_->clear();
+ textfield_->SetText(ASCIIToUTF16("0123456789"));
+ EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5)));
+ client->ExtendSelectionAndDelete(4, 2);
+ EXPECT_STR_EQ("0789", textfield_->text());
+
+ // On{Before,After}UserAction should be called by whatever user action
+ // triggers clearing or setting a selection if appropriate.
+ on_before_user_action_ = on_after_user_action_ = 0;
+ textfield_->clear();
+ textfield_->ClearSelection();
+ textfield_->SelectAll(false);
+ EXPECT_EQ(0, on_before_user_action_);
+ EXPECT_EQ(0, on_after_user_action_);
+
+ input_method_->Clear();
+ textfield_->SetReadOnly(true);
+ EXPECT_TRUE(input_method_->text_input_type_changed());
+ EXPECT_FALSE(textfield_->GetTextInputClient());
+
+ textfield_->SetReadOnly(false);
+ input_method_->Clear();
+ textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ EXPECT_TRUE(input_method_->text_input_type_changed());
+ EXPECT_TRUE(textfield_->GetTextInputClient());
+}
+
+TEST_F(TextfieldTest, UndoRedoTest) {
+ InitTextfield();
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_STR_EQ("a", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("a", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("a", textfield_->text());
+
+ // AppendText
+ textfield_->AppendText(ASCIIToUTF16("b"));
+ last_contents_.clear(); // AppendText doesn't call ContentsChanged.
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("a", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("ab", textfield_->text());
+
+ // SetText
+ SendKeyEvent(ui::VKEY_C);
+ // Undo'ing append moves the cursor to the end for now.
+ // A no-op SetText won't add a new edit; see TextfieldModel::SetText.
+ EXPECT_STR_EQ("abc", textfield_->text());
+ textfield_->SetText(ASCIIToUTF16("abc"));
+ EXPECT_STR_EQ("abc", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("abc", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("abc", textfield_->text());
+ textfield_->SetText(ASCIIToUTF16("123"));
+ textfield_->SetText(ASCIIToUTF16("123"));
+ EXPECT_STR_EQ("123", textfield_->text());
+ SendKeyEvent(ui::VKEY_END, false, false);
+ SendKeyEvent(ui::VKEY_4, false, false);
+ EXPECT_STR_EQ("1234", textfield_->text());
+ last_contents_.clear();
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("123", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ // the insert edit "c" and set edit "123" are merged to single edit,
+ // so text becomes "ab" after undo.
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("a", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("123", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("1234", textfield_->text());
+
+ // Undoing to the same text shouldn't call ContentsChanged.
+ SendKeyEvent(ui::VKEY_A, false, true); // select all
+ SendKeyEvent(ui::VKEY_A);
+ EXPECT_STR_EQ("a", textfield_->text());
+ SendKeyEvent(ui::VKEY_B);
+ SendKeyEvent(ui::VKEY_C);
+ EXPECT_STR_EQ("abc", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("1234", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("abc", textfield_->text());
+
+ // Delete/Backspace
+ SendKeyEvent(ui::VKEY_BACK);
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_HOME);
+ SendKeyEvent(ui::VKEY_DELETE);
+ EXPECT_STR_EQ("b", textfield_->text());
+ SendKeyEvent(ui::VKEY_A, false, true);
+ SendKeyEvent(ui::VKEY_DELETE);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("b", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Z, false, true);
+ EXPECT_STR_EQ("abc", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("ab", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("b", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+ SendKeyEvent(ui::VKEY_Y, false, true);
+ EXPECT_STR_EQ("", textfield_->text());
+}
+
+TEST_F(TextfieldTest, CutCopyPaste) {
+ InitTextfield();
+
+ // Ensure IDS_APP_CUT cuts.
+ textfield_->SetText(ASCIIToUTF16("123"));
+ textfield_->SelectAll(false);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
+ textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing.
+ textfield_->SetText(ASCIIToUTF16("456"));
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_X, true, false, true, false);
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("456", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_X, false, true);
+ EXPECT_STR_EQ("456", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure [Shift]+[Delete] cuts.
+ textfield_->SetText(ASCIIToUTF16("123"));
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_DELETE, true, false);
+ EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure IDS_APP_COPY copies.
+ textfield_->SetText(ASCIIToUTF16("789"));
+ textfield_->SelectAll(false);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
+ textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing.
+ textfield_->SetText(ASCIIToUTF16("012"));
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_C, true, false, true, false);
+ EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_C, false, true);
+ EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure [Ctrl]+[Insert] copies.
+ textfield_->SetText(ASCIIToUTF16("345"));
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_INSERT, false, true);
+ EXPECT_STR_EQ("345", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("345", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard());
+
+ // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes;
+ // also ensure that [Ctrl]+[Alt]+[V] does nothing.
+ SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "abc");
+ textfield_->SetText(base::string16());
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
+ textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_STR_EQ("abc", textfield_->text());
+ SendKeyEvent(ui::VKEY_V, false, true);
+ EXPECT_STR_EQ("abcabc", textfield_->text());
+ SendKeyEvent(ui::VKEY_INSERT, true, false);
+ EXPECT_STR_EQ("abcabcabc", textfield_->text());
+ SendKeyEvent(ui::VKEY_V, true, false, true, false);
+ EXPECT_STR_EQ("abcabcabc", textfield_->text());
+
+ // Ensure [Ctrl]+[Shift]+[Insert] is a no-op.
+ textfield_->SelectAll(false);
+ SendKeyEvent(ui::VKEY_INSERT, true, true);
+ EXPECT_STR_EQ("abc", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE));
+ EXPECT_STR_EQ("abcabcabc", textfield_->text());
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+}
+
+TEST_F(TextfieldTest, OvertypeMode) {
+ InitTextfield();
+ // Overtype mode should be disabled (no-op [Insert]).
+ textfield_->SetText(ASCIIToUTF16("2"));
+ SendKeyEvent(ui::VKEY_HOME);
+ SendKeyEvent(ui::VKEY_INSERT);
+ SendKeyEvent(ui::VKEY_1, false, false);
+ EXPECT_STR_EQ("12", textfield_->text());
+}
+
+TEST_F(TextfieldTest, TextCursorDisplayTest) {
+ InitTextfield();
+ // LTR-RTL string in LTR context.
+ SendKeyEvent('a');
+ EXPECT_STR_EQ("a", textfield_->text());
+ int x = GetCursorBounds().x();
+ int prev_x = x;
+
+ SendKeyEvent('b');
+ EXPECT_STR_EQ("ab", textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_LT(prev_x, x);
+ prev_x = x;
+
+ SendKeyEvent(0x05E1);
+ EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+
+ SendKeyEvent(0x05E2);
+ EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+
+ // Clear text.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ SendKeyEvent('\n');
+
+ // RTL-LTR string in LTR context.
+ SendKeyEvent(0x05E1);
+ EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(GetDisplayRect().x(), x);
+ prev_x = x;
+
+ SendKeyEvent(0x05E2);
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+
+ SendKeyEvent('a');
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_LT(prev_x, x);
+ prev_x = x;
+
+ SendKeyEvent('b');
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_LT(prev_x, x);
+}
+
+TEST_F(TextfieldTest, TextCursorDisplayInRTLTest) {
+ std::string locale = l10n_util::GetApplicationLocale("");
+ base::i18n::SetICUDefaultLocale("he");
+
+ InitTextfield();
+ // LTR-RTL string in RTL context.
+ SendKeyEvent('a');
+ EXPECT_STR_EQ("a", textfield_->text());
+ int x = GetCursorBounds().x();
+ EXPECT_EQ(GetDisplayRect().right() - 1, x);
+ int prev_x = x;
+
+ SendKeyEvent('b');
+ EXPECT_STR_EQ("ab", textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+
+ SendKeyEvent(0x05E1);
+ EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_GT(prev_x, x);
+ prev_x = x;
+
+ SendKeyEvent(0x05E2);
+ EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_GT(prev_x, x);
+
+ SendKeyEvent(ui::VKEY_A, false, true);
+ SendKeyEvent('\n');
+
+ // RTL-LTR string in RTL context.
+ SendKeyEvent(0x05E1);
+ EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text());
+ x = GetCursorBounds().x();
+ prev_x = x;
+
+ SendKeyEvent(0x05E2);
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_GT(prev_x, x);
+ prev_x = x;
+
+ SendKeyEvent('a');
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+ prev_x = x;
+
+ SendKeyEvent('b');
+ EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text());
+ x = GetCursorBounds().x();
+ EXPECT_EQ(prev_x, x);
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+TEST_F(TextfieldTest, HitInsideTextAreaTest) {
+ InitTextfield();
+ textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
+ std::vector<gfx::Rect> cursor_bounds;
+
+ // Save each cursor bound.
+ gfx::SelectionModel sel(0, gfx::CURSOR_FORWARD);
+ cursor_bounds.push_back(GetCursorBounds(sel));
+
+ sel = gfx::SelectionModel(1, gfx::CURSOR_BACKWARD);
+ gfx::Rect bound = GetCursorBounds(sel);
+ sel = gfx::SelectionModel(1, gfx::CURSOR_FORWARD);
+ EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
+ cursor_bounds.push_back(bound);
+
+ // Check that a cursor at the end of the Latin portion of the text is at the
+ // same position as a cursor placed at the end of the RTL Hebrew portion.
+ sel = gfx::SelectionModel(2, gfx::CURSOR_BACKWARD);
+ bound = GetCursorBounds(sel);
+ sel = gfx::SelectionModel(4, gfx::CURSOR_BACKWARD);
+ EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
+ cursor_bounds.push_back(bound);
+
+ sel = gfx::SelectionModel(3, gfx::CURSOR_BACKWARD);
+ bound = GetCursorBounds(sel);
+ sel = gfx::SelectionModel(3, gfx::CURSOR_FORWARD);
+ EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
+ cursor_bounds.push_back(bound);
+
+ sel = gfx::SelectionModel(2, gfx::CURSOR_FORWARD);
+ bound = GetCursorBounds(sel);
+ sel = gfx::SelectionModel(4, gfx::CURSOR_FORWARD);
+ EXPECT_EQ(bound.x(), GetCursorBounds(sel).x());
+ cursor_bounds.push_back(bound);
+
+ // Expected cursor position when clicking left and right of each character.
+ size_t cursor_pos_expected[] = {0, 1, 1, 2, 4, 3, 3, 2};
+
+ int index = 0;
+ for (int i = 0; i < static_cast<int>(cursor_bounds.size() - 1); ++i) {
+ int half_width = (cursor_bounds[i + 1].x() - cursor_bounds[i].x()) / 2;
+ MouseClick(cursor_bounds[i], half_width / 2);
+ EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
+
+ // To avoid trigger double click. Not using sleep() since it takes longer
+ // for the test to run if using sleep().
+ NonClientMouseClick();
+
+ MouseClick(cursor_bounds[i + 1], - (half_width / 2));
+ EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition());
+
+ NonClientMouseClick();
+ }
+}
+
+TEST_F(TextfieldTest, HitOutsideTextAreaTest) {
+ InitTextfield();
+
+ // LTR-RTL string in LTR context.
+ textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
+
+ SendKeyEvent(ui::VKEY_HOME);
+ gfx::Rect bound = GetCursorBounds();
+ MouseClick(bound, -10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ SendKeyEvent(ui::VKEY_END);
+ bound = GetCursorBounds();
+ MouseClick(bound, 10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ NonClientMouseClick();
+
+ // RTL-LTR string in LTR context.
+ textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
+
+ SendKeyEvent(ui::VKEY_HOME);
+ bound = GetCursorBounds();
+ MouseClick(bound, 10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ SendKeyEvent(ui::VKEY_END);
+ bound = GetCursorBounds();
+ MouseClick(bound, -10);
+ EXPECT_EQ(bound, GetCursorBounds());
+}
+
+TEST_F(TextfieldTest, HitOutsideTextAreaInRTLTest) {
+ std::string locale = l10n_util::GetApplicationLocale("");
+ base::i18n::SetICUDefaultLocale("he");
+
+ InitTextfield();
+
+ // RTL-LTR string in RTL context.
+ textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab"));
+ SendKeyEvent(ui::VKEY_HOME);
+ gfx::Rect bound = GetCursorBounds();
+ MouseClick(bound, 10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ SendKeyEvent(ui::VKEY_END);
+ bound = GetCursorBounds();
+ MouseClick(bound, -10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ NonClientMouseClick();
+
+ // LTR-RTL string in RTL context.
+ textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2"));
+ SendKeyEvent(ui::VKEY_HOME);
+ bound = GetCursorBounds();
+ MouseClick(bound, -10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ SendKeyEvent(ui::VKEY_END);
+ bound = GetCursorBounds();
+ MouseClick(bound, 10);
+ EXPECT_EQ(bound, GetCursorBounds());
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+TEST_F(TextfieldTest, OverflowTest) {
+ InitTextfield();
+
+ base::string16 str;
+ for (int i = 0; i < 500; ++i)
+ SendKeyEvent('a');
+ SendKeyEvent(kHebrewLetterSamekh);
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ // Test mouse pointing.
+ MouseClick(GetCursorBounds(), -1);
+ EXPECT_EQ(500U, textfield_->GetCursorPosition());
+
+ // Clear text.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ SendKeyEvent('\n');
+
+ for (int i = 0; i < 500; ++i)
+ SendKeyEvent(kHebrewLetterSamekh);
+ SendKeyEvent('a');
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ MouseClick(GetCursorBounds(), -1);
+ EXPECT_EQ(501U, textfield_->GetCursorPosition());
+}
+
+TEST_F(TextfieldTest, OverflowInRTLTest) {
+ std::string locale = l10n_util::GetApplicationLocale("");
+ base::i18n::SetICUDefaultLocale("he");
+
+ InitTextfield();
+
+ base::string16 str;
+ for (int i = 0; i < 500; ++i)
+ SendKeyEvent('a');
+ SendKeyEvent(kHebrewLetterSamekh);
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ MouseClick(GetCursorBounds(), 1);
+ EXPECT_EQ(501U, textfield_->GetCursorPosition());
+
+ // Clear text.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ SendKeyEvent('\n');
+
+ for (int i = 0; i < 500; ++i)
+ SendKeyEvent(kHebrewLetterSamekh);
+ SendKeyEvent('a');
+ EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds()));
+
+ MouseClick(GetCursorBounds(), 1);
+ EXPECT_EQ(500U, textfield_->GetCursorPosition());
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+TEST_F(TextfieldTest, GetCompositionCharacterBoundsTest) {
+ InitTextfield();
+
+ base::string16 str;
+ const uint32 char_count = 10UL;
+ ui::CompositionText composition;
+ composition.text = UTF8ToUTF16("0123456789");
+ ui::TextInputClient* client = textfield_->GetTextInputClient();
+
+ // Return false if there is no composition text.
+ gfx::Rect rect;
+ EXPECT_FALSE(client->GetCompositionCharacterBounds(0, &rect));
+
+ // Get each character boundary by cursor.
+ gfx::Rect char_rect_in_screen_coord[char_count];
+ gfx::Rect prev_cursor = GetCursorBounds();
+ for (uint32 i = 0; i < char_count; ++i) {
+ composition.selection = gfx::Range(0, i+1);
+ client->SetCompositionText(composition);
+ EXPECT_TRUE(client->HasCompositionText()) << " i=" << i;
+ gfx::Rect cursor_bounds = GetCursorBounds();
+ gfx::Point top_left(prev_cursor.x(), prev_cursor.y());
+ gfx::Point bottom_right(cursor_bounds.x(), prev_cursor.bottom());
+ views::View::ConvertPointToScreen(textfield_, &top_left);
+ views::View::ConvertPointToScreen(textfield_, &bottom_right);
+ char_rect_in_screen_coord[i].set_origin(top_left);
+ char_rect_in_screen_coord[i].set_width(bottom_right.x() - top_left.x());
+ char_rect_in_screen_coord[i].set_height(bottom_right.y() - top_left.y());
+ prev_cursor = cursor_bounds;
+ }
+
+ for (uint32 i = 0; i < char_count; ++i) {
+ gfx::Rect actual_rect;
+ EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &actual_rect))
+ << " i=" << i;
+ EXPECT_EQ(char_rect_in_screen_coord[i], actual_rect) << " i=" << i;
+ }
+
+ // Return false if the index is out of range.
+ EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect));
+ EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect));
+ EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect));
+}
+
+TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) {
+ InitTextfield();
+
+ const base::char16 kUtf16Chars[] = {
+ // U+0020 SPACE
+ 0x0020,
+ // U+1F408 (CAT) as surrogate pair
+ 0xd83d, 0xdc08,
+ // U+5642 as Ideographic Variation Sequences
+ 0x5642, 0xDB40, 0xDD00,
+ // U+260E (BLACK TELEPHONE) as Emoji Variation Sequences
+ 0x260E, 0xFE0F,
+ // U+0020 SPACE
+ 0x0020,
+ };
+ const size_t kUtf16CharsCount = arraysize(kUtf16Chars);
+
+ ui::CompositionText composition;
+ composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount);
+ ui::TextInputClient* client = textfield_->GetTextInputClient();
+ client->SetCompositionText(composition);
+
+ // Make sure GetCompositionCharacterBounds never fails for index.
+ gfx::Rect rects[kUtf16CharsCount];
+ gfx::Rect prev_cursor = GetCursorBounds();
+ for (uint32 i = 0; i < kUtf16CharsCount; ++i)
+ EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i]));
+
+ // Here we might expect the following results but it actually depends on how
+ // Uniscribe or HarfBuzz treats them with given font.
+ // - rects[1] == rects[2]
+ // - rects[3] == rects[4] == rects[5]
+ // - rects[6] == rects[7]
+}
+
+// The word we select by double clicking should remain selected regardless of
+// where we drag the mouse afterwards without releasing the left button.
+TEST_F(TextfieldTest, KeepInitiallySelectedWord) {
+ InitTextfield();
+
+ textfield_->SetText(ASCIIToUTF16("abc def ghi"));
+
+ textfield_->SelectRange(gfx::Range(5, 5));
+ const gfx::Rect middle_cursor = GetCursorBounds();
+ textfield_->SelectRange(gfx::Range(0, 0));
+ const gfx::Point beginning = GetCursorBounds().origin();
+
+ // Double click, but do not release the left button.
+ MouseClick(middle_cursor, 0);
+ const gfx::Point middle(middle_cursor.x(),
+ middle_cursor.y() + middle_cursor.height() / 2);
+ ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press_event);
+ EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange());
+
+ // Drag the mouse to the beginning of the textfield.
+ ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning,
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ textfield_->OnMouseDragged(drag_event);
+ EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange());
+}
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+TEST_F(TextfieldTest, SelectionClipboard) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("0123"));
+ gfx::Point point_1(GetCursorPositionX(1), 0);
+ gfx::Point point_2(GetCursorPositionX(2), 0);
+ gfx::Point point_3(GetCursorPositionX(3), 0);
+ gfx::Point point_4(GetCursorPositionX(4), 0);
+
+ // Text selected by the mouse should be placed on the selection clipboard.
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point_1, point_1,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press);
+ ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, point_3, point_3,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseDragged(drag);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point_3, point_3,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release);
+ EXPECT_EQ(gfx::Range(1, 3), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("12", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+
+ // Select-all should update the selection clipboard.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ EXPECT_EQ(gfx::Range(0, 4), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Shift-click selection modifications should update the clipboard.
+ NonClientMouseClick();
+ ui::MouseEvent press_2(ui::ET_MOUSE_PRESSED, point_2, point_2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ press_2.set_flags(press_2.flags() | ui::EF_SHIFT_DOWN);
+ textfield_->OnMousePressed(press_2);
+ ui::MouseEvent release_2(ui::ET_MOUSE_RELEASED, point_2, point_2,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release_2);
+ EXPECT_EQ(gfx::Range(0, 2), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Shift-Left/Right should update the selection clipboard.
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+ EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_LEFT, true, false);
+ EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ SendKeyEvent(ui::VKEY_RIGHT, true, true);
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Moving the cursor without a selection should not change the clipboard.
+ SendKeyEvent(ui::VKEY_LEFT, false, false);
+ EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ // Middle clicking should paste at the mouse (not cursor) location.
+ ui::MouseEvent middle(ui::ET_MOUSE_PRESSED, point_4, point_4,
+ ui::EF_MIDDLE_MOUSE_BUTTON, ui::EF_MIDDLE_MOUSE_BUTTON);
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("01230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+
+ // Middle click pasting should adjust trailing cursors.
+ textfield_->SelectRange(gfx::Range(5, 5));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(9, 9), textfield_->GetSelectedRange());
+
+ // Middle click pasting should adjust trailing selections.
+ textfield_->SelectRange(gfx::Range(7, 9));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("0123012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(11, 13), textfield_->GetSelectedRange());
+
+ // Middle clicking in the selection should clear the clipboard and selection.
+ textfield_->SelectRange(gfx::Range(2, 6));
+ textfield_->OnMousePressed(middle);
+ EXPECT_STR_EQ("0123012301230123", textfield_->text());
+ EXPECT_EQ(gfx::Range(6, 6), textfield_->GetSelectedRange());
+ EXPECT_TRUE(GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION).empty());
+
+ // Double and triple clicking should update the clipboard contents.
+ textfield_->SetText(ASCIIToUTF16("ab cd ef"));
+ gfx::Point word(GetCursorPositionX(4), 0);
+ ui::MouseEvent press_word(ui::ET_MOUSE_PRESSED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(press_word);
+ ui::MouseEvent release_word(ui::ET_MOUSE_RELEASED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMouseReleased(release_word);
+ ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, word, word,
+ ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ textfield_->OnMousePressed(double_click);
+ textfield_->OnMouseReleased(release_word);
+ EXPECT_EQ(gfx::Range(3, 5), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("cd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+ textfield_->OnMousePressed(press_word);
+ textfield_->OnMouseReleased(release_word);
+ EXPECT_EQ(gfx::Range(0, 8), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Selecting a range of text without any user interaction should not change
+ // the clipboard content.
+ textfield_->SelectRange(gfx::Range(0, 3));
+ EXPECT_STR_EQ("ab ", textfield_->GetSelectedText());
+ EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION, "other");
+ textfield_->SelectAll(false);
+ EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+}
+#endif
+
+// Touch selection and dragging currently only works for chromeos.
+#if defined(OS_CHROMEOS)
+TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ EXPECT_FALSE(test_api_->touch_selection_controller());
+ const int x = GetCursorPositionX(2);
+ GestureEventForTest tap(ui::ET_GESTURE_TAP, x, 0, 1.0f, 0.0f);
+ GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, x, 0, 0.0f, 0.0f);
+ GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, x, 0, 0.0f, 0.0f);
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
+
+ // Tapping on the textfield should turn on the TouchSelectionController.
+ textfield_->OnGestureEvent(&tap);
+ EXPECT_TRUE(test_api_->touch_selection_controller());
+
+ // Un-focusing the textfield should reset the TouchSelectionController
+ textfield_->GetFocusManager()->ClearFocus();
+ EXPECT_FALSE(test_api_->touch_selection_controller());
+
+ // With touch editing enabled, long press should not show context menu.
+ // Instead, select word and invoke TouchSelectionController.
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
+ EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
+
+ // With touch drag drop enabled, long pressing in the selected region should
+ // start a drag and remove TouchSelectionController.
+ ASSERT_TRUE(switches::IsTouchDragDropEnabled());
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
+ EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
+ EXPECT_FALSE(test_api_->touch_selection_controller());
+
+ // After disabling touch drag drop, long pressing again in the selection
+ // region should not do anything.
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisableTouchDragDrop);
+ ASSERT_FALSE(switches::IsTouchDragDropEnabled());
+ textfield_->OnGestureEvent(&tap_down);
+ textfield_->OnGestureEvent(&long_press);
+ EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
+ EXPECT_TRUE(long_press.handled());
+}
+
+TEST_F(TextfieldTest, TouchScrubbingSelection) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ EXPECT_FALSE(test_api_->touch_selection_controller());
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
+
+ // Simulate touch-scrubbing.
+ int scrubbing_start = GetCursorPositionX(1);
+ int scrubbing_end = GetCursorPositionX(6);
+
+ GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0,
+ 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&tap_down);
+
+ GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, scrubbing_start, 0,
+ 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&tap_cancel);
+
+ GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, scrubbing_start,
+ 0, 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&scroll_begin);
+
+ GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, scrubbing_end,
+ 0, scrubbing_end - scrubbing_start, 0.0f);
+ textfield_->OnGestureEvent(&scroll_update);
+
+ GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0,
+ 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&scroll_end);
+
+ GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&end);
+
+ // In the end, part of text should have been selected and handles should have
+ // appeared.
+ EXPECT_STR_EQ("ello ", textfield_->GetSelectedText());
+ EXPECT_TRUE(test_api_->touch_selection_controller());
+}
+#endif
+
+// Long_Press gesture in Textfield can initiate a drag and drop now.
+TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("Hello string world"));
+
+ // Ensure the textfield will provide selected text for drag data.
+ textfield_->SelectRange(gfx::Range(6, 12));
+ const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
+
+ // Enable touch-drag-drop to make long press effective.
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableTouchDragDrop);
+
+ // Create a long press event in the selected region should start a drag.
+ GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, kStringPoint.x(),
+ kStringPoint.y(), 0.0f, 0.0f);
+ textfield_->OnGestureEvent(&long_press);
+ EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint,
+ kStringPoint));
+}
+
+TEST_F(TextfieldTest, GetTextfieldBaseline_FontFallbackTest) {
+ InitTextfield();
+ textfield_->SetText(UTF8ToUTF16("abc"));
+ const int old_baseline = textfield_->GetBaseline();
+
+ // Set text which may fall back to a font which has taller baseline than
+ // the default font.
+ textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91"));
+ const int new_baseline = textfield_->GetBaseline();
+
+ // Regardless of the text, the baseline must be the same.
+ EXPECT_EQ(new_baseline, old_baseline);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model.cc b/chromium/ui/views/controls/textfield/textfield_views_model.cc
deleted file mode 100644
index 222d0860644..00000000000
--- a/chromium/ui/views/controls/textfield/textfield_views_model.cc
+++ /dev/null
@@ -1,799 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/textfield/textfield_views_model.h"
-
-#include <algorithm>
-
-#include "base/i18n/break_iterator.h"
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/render_text.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/gfx/utf16_indexing.h"
-#include "ui/views/controls/textfield/textfield.h"
-
-namespace views {
-
-namespace internal {
-
-// An edit object holds enough information/state to undo/redo the
-// change. Two edits are merged when possible, for example, when
-// you type new characters in sequence. |Commit()| can be used to
-// mark an edit as an independent edit and it shouldn't be merged.
-// (For example, when you did undo/redo, or a text is appended via
-// API)
-class Edit {
- public:
- enum Type {
- INSERT_EDIT,
- DELETE_EDIT,
- REPLACE_EDIT
- };
-
- virtual ~Edit() {
- }
-
- // Revert the change made by this edit in |model|.
- void Undo(TextfieldViewsModel* model) {
- model->ModifyText(new_text_start_, new_text_end(),
- old_text_, old_text_start_,
- old_cursor_pos_);
- }
-
- // Apply the change of this edit to the |model|.
- void Redo(TextfieldViewsModel* model) {
- model->ModifyText(old_text_start_, old_text_end(),
- new_text_, new_text_start_,
- new_cursor_pos_);
- }
-
- // Try to merge the |edit| into this edit. Returns true if merge was
- // successful, or false otherwise. Merged edit will be deleted after
- // redo and should not be reused.
- bool Merge(const Edit* edit) {
- // Don't merge if previous edit is DELETE. This happens when a
- // user deletes characters then hits return. In this case, the
- // delete should be treated as separate edit that can be undone
- // and should not be merged with the replace edit.
- if (type_ != DELETE_EDIT && edit->merge_with_previous()) {
- MergeReplace(edit);
- return true;
- }
- return mergeable() && edit->mergeable() && DoMerge(edit);
- }
-
- // Commits the edit and marks as un-mergeable.
- void Commit() { merge_type_ = DO_NOT_MERGE; }
-
- private:
- friend class InsertEdit;
- friend class ReplaceEdit;
- friend class DeleteEdit;
-
- Edit(Type type,
- MergeType merge_type,
- size_t old_cursor_pos,
- const string16& old_text,
- size_t old_text_start,
- bool delete_backward,
- size_t new_cursor_pos,
- const string16& new_text,
- size_t new_text_start)
- : type_(type),
- merge_type_(merge_type),
- old_cursor_pos_(old_cursor_pos),
- old_text_(old_text),
- old_text_start_(old_text_start),
- delete_backward_(delete_backward),
- new_cursor_pos_(new_cursor_pos),
- new_text_(new_text),
- new_text_start_(new_text_start) {
- }
-
- // A template method pattern that provides specific merge
- // implementation for each type of edit.
- virtual bool DoMerge(const Edit* edit) = 0;
-
- Type type() const { return type_; }
-
- // Can this edit be merged?
- bool mergeable() const { return merge_type_ == MERGEABLE; }
-
- // Should this edit be forcibly merged with the previous edit?
- bool merge_with_previous() const {
- return merge_type_ == MERGE_WITH_PREVIOUS;
- }
-
- // Returns the end index of the |old_text_|.
- size_t old_text_end() const { return old_text_start_ + old_text_.length(); }
-
- // Returns the end index of the |new_text_|.
- size_t new_text_end() const { return new_text_start_ + new_text_.length(); }
-
- // Merge the replace edit into the current edit. This is a special case to
- // handle an omnibox setting autocomplete string after new character is
- // typed in.
- void MergeReplace(const Edit* edit) {
- CHECK_EQ(REPLACE_EDIT, edit->type_);
- CHECK_EQ(0U, edit->old_text_start_);
- CHECK_EQ(0U, edit->new_text_start_);
- string16 old_text = edit->old_text_;
- old_text.erase(new_text_start_, new_text_.length());
- old_text.insert(old_text_start_, old_text_);
- // SetText() replaces entire text. Set |old_text_| to the entire
- // replaced text with |this| edit undone.
- old_text_ = old_text;
- old_text_start_ = edit->old_text_start_;
- delete_backward_ = false;
-
- new_text_ = edit->new_text_;
- new_text_start_ = edit->new_text_start_;
- merge_type_ = DO_NOT_MERGE;
- }
-
- Type type_;
-
- // True if the edit can be marged.
- MergeType merge_type_;
- // Old cursor position.
- size_t old_cursor_pos_;
- // Deleted text by this edit.
- string16 old_text_;
- // The index of |old_text_|.
- size_t old_text_start_;
- // True if the deletion is made backward.
- bool delete_backward_;
- // New cursor position.
- size_t new_cursor_pos_;
- // Added text.
- string16 new_text_;
- // The index of |new_text_|
- size_t new_text_start_;
-
- DISALLOW_COPY_AND_ASSIGN(Edit);
-};
-
-class InsertEdit : public Edit {
- public:
- InsertEdit(bool mergeable, const string16& new_text, size_t at)
- : Edit(INSERT_EDIT,
- mergeable ? MERGEABLE : DO_NOT_MERGE,
- at /* old cursor */,
- string16(),
- at,
- false /* N/A */,
- at + new_text.length() /* new cursor */,
- new_text,
- at) {
- }
-
- // Edit implementation.
- virtual bool DoMerge(const Edit* edit) OVERRIDE {
- if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_)
- return false;
- // If continuous edit, merge it.
- // TODO(oshima): gtk splits edits between whitespace. Find out what
- // we want to here and implement if necessary.
- new_text_ += edit->new_text_;
- new_cursor_pos_ = edit->new_cursor_pos_;
- return true;
- }
-};
-
-class ReplaceEdit : public Edit {
- public:
- ReplaceEdit(MergeType merge_type,
- const string16& old_text,
- size_t old_cursor_pos,
- size_t old_text_start,
- bool backward,
- size_t new_cursor_pos,
- const string16& new_text,
- size_t new_text_start)
- : Edit(REPLACE_EDIT, merge_type,
- old_cursor_pos,
- old_text,
- old_text_start,
- backward,
- new_cursor_pos,
- new_text,
- new_text_start) {
- }
-
- // Edit implementation.
- virtual bool DoMerge(const Edit* edit) OVERRIDE {
- if (edit->type() == DELETE_EDIT ||
- new_text_end() != edit->old_text_start_ ||
- edit->old_text_start_ != edit->new_text_start_)
- return false;
- old_text_ += edit->old_text_;
- new_text_ += edit->new_text_;
- new_cursor_pos_ = edit->new_cursor_pos_;
- return true;
- }
-};
-
-class DeleteEdit : public Edit {
- public:
- DeleteEdit(bool mergeable,
- const string16& text,
- size_t text_start,
- bool backward)
- : Edit(DELETE_EDIT,
- mergeable ? MERGEABLE : DO_NOT_MERGE,
- (backward ? text_start + text.length() : text_start),
- text,
- text_start,
- backward,
- text_start,
- string16(),
- text_start) {
- }
-
- // Edit implementation.
- virtual bool DoMerge(const Edit* edit) OVERRIDE {
- if (edit->type() != DELETE_EDIT)
- return false;
-
- if (delete_backward_) {
- // backspace can be merged only with backspace at the
- // same position.
- if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
- return false;
- old_text_start_ = edit->old_text_start_;
- old_text_ = edit->old_text_ + old_text_;
- new_cursor_pos_ = edit->new_cursor_pos_;
- } else {
- // delete can be merged only with delete at the same
- // position.
- if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
- return false;
- old_text_ += edit->old_text_;
- }
- return true;
- }
-};
-
-} // namespace internal
-
-namespace {
-
-// Returns the first segment that is visually emphasized. Usually it's used for
-// representing the target clause (on Windows). Returns an invalid range if
-// there is no such a range.
-gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
- for (size_t i = 0; i < composition.underlines.size(); ++i) {
- const ui::CompositionUnderline& underline = composition.underlines[i];
- if (underline.thick)
- return gfx::Range(underline.start_offset, underline.end_offset);
- }
- return gfx::Range::InvalidRange();
-}
-
-} // namespace
-
-using internal::Edit;
-using internal::DeleteEdit;
-using internal::InsertEdit;
-using internal::ReplaceEdit;
-using internal::MergeType;
-using internal::DO_NOT_MERGE;
-using internal::MERGE_WITH_PREVIOUS;
-using internal::MERGEABLE;
-
-/////////////////////////////////////////////////////////////////
-// TextfieldViewsModel: public
-
-TextfieldViewsModel::Delegate::~Delegate() {
-}
-
-TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
- : delegate_(delegate),
- render_text_(gfx::RenderText::CreateInstance()),
- current_edit_(edit_history_.end()) {
-}
-
-TextfieldViewsModel::~TextfieldViewsModel() {
- ClearEditHistory();
- ClearComposition();
-}
-
-const string16& TextfieldViewsModel::GetText() const {
- return render_text_->text();
-}
-
-bool TextfieldViewsModel::SetText(const string16& text) {
- bool changed = false;
- if (HasCompositionText()) {
- ConfirmCompositionText();
- changed = true;
- }
- if (GetText() != text) {
- if (changed) // No need to remember composition.
- Undo();
- size_t old_cursor = GetCursorPosition();
- // SetText moves the cursor to the end.
- size_t new_cursor = text.length();
- SelectAll(false);
- // If there is a composition text, don't merge with previous edit.
- // Otherwise, force merge the edits.
- ExecuteAndRecordReplace(
- changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS,
- old_cursor,
- new_cursor,
- text,
- 0U);
- render_text_->SetCursorPosition(new_cursor);
- }
- ClearSelection();
- return changed;
-}
-
-void TextfieldViewsModel::Append(const string16& text) {
- if (HasCompositionText())
- ConfirmCompositionText();
- size_t save = GetCursorPosition();
- MoveCursor(gfx::LINE_BREAK,
- render_text_->GetVisualDirectionOfLogicalEnd(),
- false);
- InsertText(text);
- render_text_->SetCursorPosition(save);
- ClearSelection();
-}
-
-bool TextfieldViewsModel::Delete() {
- if (HasCompositionText()) {
- // No undo/redo for composition text.
- CancelCompositionText();
- return true;
- }
- if (HasSelection()) {
- DeleteSelection();
- return true;
- }
- if (GetText().length() > GetCursorPosition()) {
- size_t cursor_position = GetCursorPosition();
- size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme(
- cursor_position, gfx::CURSOR_FORWARD);
- ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index),
- true);
- return true;
- }
- return false;
-}
-
-bool TextfieldViewsModel::Backspace() {
- if (HasCompositionText()) {
- // No undo/redo for composition text.
- CancelCompositionText();
- return true;
- }
- if (HasSelection()) {
- DeleteSelection();
- return true;
- }
- size_t cursor_position = GetCursorPosition();
- if (cursor_position > 0) {
- // Delete one code point, which may be two UTF-16 words.
- size_t previous_char =
- gfx::UTF16OffsetToIndex(GetText(), cursor_position, -1);
- ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true);
- return true;
- }
- return false;
-}
-
-size_t TextfieldViewsModel::GetCursorPosition() const {
- return render_text_->cursor_position();
-}
-
-void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type,
- gfx::VisualCursorDirection direction,
- bool select) {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->MoveCursor(break_type, direction, select);
-}
-
-bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& model) {
- if (HasCompositionText()) {
- ConfirmCompositionText();
- // ConfirmCompositionText() updates cursor position. Need to reflect it in
- // the SelectionModel parameter of MoveCursorTo().
- gfx::Range range(render_text_->selection().start(), model.caret_pos());
- if (!range.is_empty())
- return render_text_->SelectRange(range);
- return render_text_->MoveCursorTo(
- gfx::SelectionModel(model.caret_pos(), model.caret_affinity()));
- }
- return render_text_->MoveCursorTo(model);
-}
-
-bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
- if (HasCompositionText())
- ConfirmCompositionText();
- return render_text_->MoveCursorTo(point, select);
-}
-
-string16 TextfieldViewsModel::GetSelectedText() const {
- return GetText().substr(render_text_->selection().GetMin(),
- render_text_->selection().length());
-}
-
-void TextfieldViewsModel::SelectRange(const gfx::Range& range) {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->SelectRange(range);
-}
-
-void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->MoveCursorTo(sel);
-}
-
-void TextfieldViewsModel::SelectAll(bool reversed) {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->SelectAll(reversed);
-}
-
-void TextfieldViewsModel::SelectWord() {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->SelectWord();
-}
-
-void TextfieldViewsModel::ClearSelection() {
- if (HasCompositionText())
- ConfirmCompositionText();
- render_text_->ClearSelection();
-}
-
-bool TextfieldViewsModel::CanUndo() {
- return edit_history_.size() && current_edit_ != edit_history_.end();
-}
-
-bool TextfieldViewsModel::CanRedo() {
- if (!edit_history_.size())
- return false;
- // There is no redo iff the current edit is the last element
- // in the history.
- EditHistory::iterator iter = current_edit_;
- return iter == edit_history_.end() || // at the top.
- ++iter != edit_history_.end();
-}
-
-bool TextfieldViewsModel::Undo() {
- if (!CanUndo())
- return false;
- DCHECK(!HasCompositionText());
- if (HasCompositionText()) // safe guard for release build.
- CancelCompositionText();
-
- string16 old = GetText();
- size_t old_cursor = GetCursorPosition();
- (*current_edit_)->Commit();
- (*current_edit_)->Undo(this);
-
- if (current_edit_ == edit_history_.begin())
- current_edit_ = edit_history_.end();
- else
- current_edit_--;
- return old != GetText() || old_cursor != GetCursorPosition();
-}
-
-bool TextfieldViewsModel::Redo() {
- if (!CanRedo())
- return false;
- DCHECK(!HasCompositionText());
- if (HasCompositionText()) // safe guard for release build.
- CancelCompositionText();
-
- if (current_edit_ == edit_history_.end())
- current_edit_ = edit_history_.begin();
- else
- current_edit_ ++;
- string16 old = GetText();
- size_t old_cursor = GetCursorPosition();
- (*current_edit_)->Redo(this);
- return old != GetText() || old_cursor != GetCursorPosition();
-}
-
-bool TextfieldViewsModel::Cut() {
- if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
- ui::ScopedClipboardWriter(
- ui::Clipboard::GetForCurrentThread(),
- ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
- // A trick to let undo/redo handle cursor correctly.
- // Undoing CUT moves the cursor to the end of the change rather
- // than beginning, unlike Delete/Backspace.
- // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
- // update DeleteEdit and remove this trick.
- const gfx::Range& selection = render_text_->selection();
- render_text_->SelectRange(gfx::Range(selection.end(), selection.start()));
- DeleteSelection();
- return true;
- }
- return false;
-}
-
-bool TextfieldViewsModel::Copy() {
- if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
- ui::ScopedClipboardWriter(
- ui::Clipboard::GetForCurrentThread(),
- ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
- return true;
- }
- return false;
-}
-
-bool TextfieldViewsModel::Paste() {
- string16 result;
- ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE,
- &result);
- if (!result.empty()) {
- InsertTextInternal(result, false);
- return true;
- }
- return false;
-}
-
-bool TextfieldViewsModel::HasSelection() const {
- return !render_text_->selection().is_empty();
-}
-
-void TextfieldViewsModel::DeleteSelection() {
- DCHECK(!HasCompositionText());
- DCHECK(HasSelection());
- ExecuteAndRecordDelete(render_text_->selection(), false);
-}
-
-void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
- const string16& text, size_t position) {
- if (HasCompositionText())
- CancelCompositionText();
- ExecuteAndRecordReplace(DO_NOT_MERGE,
- GetCursorPosition(),
- position + text.length(),
- text,
- position);
-}
-
-string16 TextfieldViewsModel::GetTextFromRange(const gfx::Range& range) const {
- if (range.IsValid() && range.GetMin() < GetText().length())
- return GetText().substr(range.GetMin(), range.length());
- return string16();
-}
-
-void TextfieldViewsModel::GetTextRange(gfx::Range* range) const {
- *range = gfx::Range(0, GetText().length());
-}
-
-void TextfieldViewsModel::SetCompositionText(
- const ui::CompositionText& composition) {
- if (HasCompositionText())
- CancelCompositionText();
- else if (HasSelection())
- DeleteSelection();
-
- if (composition.text.empty())
- return;
-
- size_t cursor = GetCursorPosition();
- string16 new_text = GetText();
- render_text_->SetText(new_text.insert(cursor, composition.text));
- gfx::Range range(cursor, cursor + composition.text.length());
- render_text_->SetCompositionRange(range);
- gfx::Range emphasized_range = GetFirstEmphasizedRange(composition);
- if (emphasized_range.IsValid()) {
- // This is a workaround due to the lack of support in RenderText to draw
- // a thick underline. In a composition returned from an IME, the segment
- // emphasized by a thick underline usually represents the target clause.
- // Because the target clause is more important than the actual selection
- // range (or caret position) in the composition here we use a selection-like
- // marker instead to show this range.
- // TODO(yukawa, msw): Support thick underline in RenderText and remove
- // this workaround.
- render_text_->SelectRange(gfx::Range(
- cursor + emphasized_range.GetMin(),
- cursor + emphasized_range.GetMax()));
- } else if (!composition.selection.is_empty()) {
- render_text_->SelectRange(gfx::Range(
- cursor + composition.selection.GetMin(),
- cursor + composition.selection.GetMax()));
- } else {
- render_text_->SetCursorPosition(cursor + composition.selection.end());
- }
-}
-
-void TextfieldViewsModel::ConfirmCompositionText() {
- DCHECK(HasCompositionText());
- gfx::Range range = render_text_->GetCompositionRange();
- string16 text = GetText().substr(range.start(), range.length());
- // TODO(oshima): current behavior on ChromeOS is a bit weird and not
- // sure exactly how this should work. Find out and fix if necessary.
- AddOrMergeEditHistory(new InsertEdit(false, text, range.start()));
- render_text_->SetCursorPosition(range.end());
- ClearComposition();
- if (delegate_)
- delegate_->OnCompositionTextConfirmedOrCleared();
-}
-
-void TextfieldViewsModel::CancelCompositionText() {
- DCHECK(HasCompositionText());
- gfx::Range range = render_text_->GetCompositionRange();
- ClearComposition();
- string16 new_text = GetText();
- render_text_->SetText(new_text.erase(range.start(), range.length()));
- render_text_->SetCursorPosition(range.start());
- if (delegate_)
- delegate_->OnCompositionTextConfirmedOrCleared();
-}
-
-void TextfieldViewsModel::ClearComposition() {
- render_text_->SetCompositionRange(gfx::Range::InvalidRange());
-}
-
-void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const {
- *range = gfx::Range(render_text_->GetCompositionRange());
-}
-
-bool TextfieldViewsModel::HasCompositionText() const {
- return !render_text_->GetCompositionRange().is_empty();
-}
-
-/////////////////////////////////////////////////////////////////
-// TextfieldViewsModel: private
-
-void TextfieldViewsModel::InsertTextInternal(const string16& text,
- bool mergeable) {
- if (HasCompositionText()) {
- CancelCompositionText();
- ExecuteAndRecordInsert(text, mergeable);
- } else if (HasSelection()) {
- ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE,
- text);
- } else {
- ExecuteAndRecordInsert(text, mergeable);
- }
-}
-
-void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
- bool mergeable) {
- if (HasCompositionText()) {
- CancelCompositionText();
- } else if (!HasSelection()) {
- size_t cursor = GetCursorPosition();
- const gfx::SelectionModel& model = render_text_->selection_model();
- // When there is no selection, the default is to replace the next grapheme
- // with |text|. So, need to find the index of next grapheme first.
- size_t next =
- render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD);
- if (next == model.caret_pos())
- render_text_->MoveCursorTo(model);
- else
- render_text_->SelectRange(gfx::Range(next, model.caret_pos()));
- }
- // Edit history is recorded in InsertText.
- InsertTextInternal(text, mergeable);
-}
-
-void TextfieldViewsModel::ClearEditHistory() {
- STLDeleteElements(&edit_history_);
- current_edit_ = edit_history_.end();
-}
-
-void TextfieldViewsModel::ClearRedoHistory() {
- if (edit_history_.begin() == edit_history_.end())
- return;
- if (current_edit_ == edit_history_.end()) {
- ClearEditHistory();
- return;
- }
- EditHistory::iterator delete_start = current_edit_;
- delete_start++;
- STLDeleteContainerPointers(delete_start, edit_history_.end());
- edit_history_.erase(delete_start, edit_history_.end());
-}
-
-void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range,
- bool mergeable) {
- size_t old_text_start = range.GetMin();
- const string16 text = GetText().substr(old_text_start, range.length());
- bool backward = range.is_reversed();
- Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
- bool delete_edit = AddOrMergeEditHistory(edit);
- edit->Redo(this);
- if (delete_edit)
- delete edit;
-}
-
-void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
- MergeType merge_type, const string16& new_text) {
- size_t new_text_start = render_text_->selection().GetMin();
- size_t new_cursor_pos = new_text_start + new_text.length();
- ExecuteAndRecordReplace(merge_type,
- GetCursorPosition(),
- new_cursor_pos,
- new_text,
- new_text_start);
-}
-
-void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
- size_t old_cursor_pos,
- size_t new_cursor_pos,
- const string16& new_text,
- size_t new_text_start) {
- size_t old_text_start = render_text_->selection().GetMin();
- bool backward = render_text_->selection().is_reversed();
- Edit* edit = new ReplaceEdit(merge_type,
- GetSelectedText(),
- old_cursor_pos,
- old_text_start,
- backward,
- new_cursor_pos,
- new_text,
- new_text_start);
- bool delete_edit = AddOrMergeEditHistory(edit);
- edit->Redo(this);
- if (delete_edit)
- delete edit;
-}
-
-void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text,
- bool mergeable) {
- Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition());
- bool delete_edit = AddOrMergeEditHistory(edit);
- edit->Redo(this);
- if (delete_edit)
- delete edit;
-}
-
-bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) {
- ClearRedoHistory();
-
- if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) {
- // If a current edit exists and has been merged with a new edit,
- // don't add to the history, and return true to delete |edit| after
- // redo.
- return true;
- }
- edit_history_.push_back(edit);
- if (current_edit_ == edit_history_.end()) {
- // If there is no redoable edit, this is the 1st edit because
- // RedoHistory has been already deleted.
- DCHECK_EQ(1u, edit_history_.size());
- current_edit_ = edit_history_.begin();
- } else {
- current_edit_++;
- }
- return false;
-}
-
-void TextfieldViewsModel::ModifyText(size_t delete_from,
- size_t delete_to,
- const string16& new_text,
- size_t new_text_insert_at,
- size_t new_cursor_pos) {
- DCHECK_LE(delete_from, delete_to);
- string16 text = GetText();
- ClearComposition();
- if (delete_from != delete_to)
- render_text_->SetText(text.erase(delete_from, delete_to - delete_from));
- if (!new_text.empty())
- render_text_->SetText(text.insert(new_text_insert_at, new_text));
- render_text_->SetCursorPosition(new_cursor_pos);
- // TODO(oshima): mac selects the text that is just undone (but gtk doesn't).
- // This looks fine feature and we may want to do the same.
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model.h b/chromium/ui/views/controls/textfield/textfield_views_model.h
deleted file mode 100644
index 1af734054a9..00000000000
--- a/chromium/ui/views/controls/textfield/textfield_views_model.h
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
-#define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
-
-#include <list>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/render_text.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Range;
-class RenderText;
-} // namespace gfx
-
-namespace views {
-
-namespace internal {
-// Internal Edit class that keeps track of edits for undo/redo.
-class Edit;
-
-// C++ doesn't allow forward decl enum, so let's define here.
-enum MergeType {
- // The edit should not be merged with next edit. It still may
- // be merged with an edit with MERGE_WITH_PREVIOUS.
- DO_NOT_MERGE,
- // The edit can be merged with next edit when possible.
- MERGEABLE,
- // Does the edit have to be merged with previous edit?
- // This forces the merge even if the previous edit is marked
- // as DO_NOT_MERGE.
- MERGE_WITH_PREVIOUS,
-};
-
-} // namespace internal
-
-// A model that represents a text content for TextfieldViews.
-// It supports editing, selection and cursor manipulation.
-class VIEWS_EXPORT TextfieldViewsModel {
- public:
- // Delegate interface implemented by the textfield view class to provided
- // additional functionalities required by the model.
- class VIEWS_EXPORT Delegate {
- public:
- // Called when the current composition text is confirmed or cleared.
- virtual void OnCompositionTextConfirmedOrCleared() = 0;
-
- protected:
- virtual ~Delegate();
- };
-
- explicit TextfieldViewsModel(Delegate* delegate);
- virtual ~TextfieldViewsModel();
-
- // Edit related methods.
-
- const string16& GetText() const;
- // Sets the text. Returns true if the text has been modified. The
- // current composition text will be confirmed first. Setting
- // the same text will not add edit history because it's not user
- // visible change nor user-initiated change. This allow a client
- // code to set the same text multiple times without worrying about
- // messing edit history.
- bool SetText(const string16& text);
-
- gfx::RenderText* render_text() { return render_text_.get(); }
-
- // Inserts given |text| at the current cursor position.
- // The current composition text will be cleared.
- void InsertText(const string16& text) {
- InsertTextInternal(text, false);
- }
-
- // Inserts a character at the current cursor position.
- void InsertChar(char16 c) {
- InsertTextInternal(string16(&c, 1), true);
- }
-
- // Replaces characters at the current position with characters in given text.
- // The current composition text will be cleared.
- void ReplaceText(const string16& text) {
- ReplaceTextInternal(text, false);
- }
-
- // Replaces the char at the current position with given character.
- void ReplaceChar(char16 c) {
- ReplaceTextInternal(string16(&c, 1), true);
- }
-
- // Appends the text.
- // The current composition text will be confirmed.
- void Append(const string16& text);
-
- // Deletes the first character after the current cursor position (as if, the
- // the user has pressed delete key in the textfield). Returns true if
- // the deletion is successful.
- // If there is composition text, it'll be deleted instead.
- bool Delete();
-
- // Deletes the first character before the current cursor position (as if, the
- // the user has pressed backspace key in the textfield). Returns true if
- // the removal is successful.
- // If there is composition text, it'll be deleted instead.
- bool Backspace();
-
- // Cursor related methods.
-
- // Returns the current cursor position.
- size_t GetCursorPosition() const;
-
- // Moves the cursor, see RenderText for additional details.
- // The current composition text will be confirmed.
- void MoveCursor(gfx::BreakType break_type,
- gfx::VisualCursorDirection direction,
- bool select);
-
- // Moves the selection to the specified selection in |selection|.
- // If there is composition text, it will be confirmed, which will update the
- // selection range, and it overrides the selection_start to which the
- // selection will move to.
- bool MoveCursorTo(const gfx::SelectionModel& selection);
-
- // Helper function to call MoveCursorTo on the TextfieldViewsModel.
- bool MoveCursorTo(const gfx::Point& point, bool select);
-
- // Selection related method
-
- // Returns the selected text.
- string16 GetSelectedText() const;
-
- // The current composition text will be confirmed. The selection starts with
- // the range's start position, and ends with the range's end position,
- // therefore the cursor position becomes the end position.
- void SelectRange(const gfx::Range& range);
-
- // The current composition text will be confirmed.
- // render_text_'s selection model is set to |sel|.
- void SelectSelectionModel(const gfx::SelectionModel& sel);
-
- // Select the entire text range. If |reversed| is true, the range will end at
- // the logical beginning of the text; this generally shows the leading portion
- // of text that overflows its display area.
- // The current composition text will be confirmed.
- void SelectAll(bool reversed);
-
- // Selects the word at which the cursor is currently positioned. If there is a
- // non-empty selection, the selection bounds are extended to their nearest
- // word boundaries.
- // The current composition text will be confirmed.
- void SelectWord();
-
- // Clears selection.
- // The current composition text will be confirmed.
- void ClearSelection();
-
- // Returns true if there is an undoable edit.
- bool CanUndo();
-
- // Returns true if there is an redoable edit.
- bool CanRedo();
-
- // Undo edit. Returns true if undo changed the text.
- bool Undo();
-
- // Redo edit. Returns true if redo changed the text.
- bool Redo();
-
- // Cuts the currently selected text and puts it to clipboard. Returns true
- // if text has changed after cutting.
- bool Cut();
-
- // Copies the currently selected text and puts it to clipboard. Returns true
- // if something was copied to the clipboard.
- bool Copy();
-
- // Pastes text from the clipboard at current cursor position. Returns true
- // if any text is pasted.
- bool Paste();
-
- // Tells if any text is selected, even if the selection is in composition
- // text.
- bool HasSelection() const;
-
- // Deletes the selected text. This method shouldn't be called with
- // composition text.
- void DeleteSelection();
-
- // Deletes the selected text (if any) and insert text at given
- // position.
- void DeleteSelectionAndInsertTextAt(
- const string16& text, size_t position);
-
- // Retrieves the text content in a given range.
- string16 GetTextFromRange(const gfx::Range& range) const;
-
- // Retrieves the range containing all text in the model.
- void GetTextRange(gfx::Range* range) const;
-
- // Sets composition text and attributes. If there is composition text already,
- // it'll be replaced by the new one. Otherwise, current selection will be
- // replaced. If there is no selection, the composition text will be inserted
- // at the insertion point.
- // Any changes to the model except text insertion will confirm the current
- // composition text.
- void SetCompositionText(const ui::CompositionText& composition);
-
- // Converts current composition text into final content.
- void ConfirmCompositionText();
-
- // Removes current composition text.
- void CancelCompositionText();
-
- // Retrieves the range of current composition text.
- void GetCompositionTextRange(gfx::Range* range) const;
-
- // Returns true if there is composition text.
- bool HasCompositionText() const;
-
- private:
- friend class NativeTextfieldViews;
- friend class NativeTextfieldViewsTest;
- friend class TextfieldViewsModelTest;
- friend class UndoRedo_BasicTest;
- friend class UndoRedo_CutCopyPasteTest;
- friend class UndoRedo_ReplaceTest;
- friend class internal::Edit;
-
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_BasicTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest);
-
- // Insert the given |text|. |mergeable| indicates if this insert
- // operation can be merged to previous edit in the edit history.
- void InsertTextInternal(const string16& text, bool mergeable);
-
- // Replace the current text with the given |text|. |mergeable|
- // indicates if this replace operation can be merged to previous
- // edit in the edit history.
- void ReplaceTextInternal(const string16& text, bool mergeable);
-
- // Clears all edit history.
- void ClearEditHistory();
-
- // Clears redo history.
- void ClearRedoHistory();
-
- // Executes and records edit operations.
- void ExecuteAndRecordDelete(gfx::Range range, bool mergeable);
- void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
- const string16& text);
- void ExecuteAndRecordReplace(internal::MergeType merge_type,
- size_t old_cursor_pos,
- size_t new_cursor_pos,
- const string16& text,
- size_t new_text_start);
- void ExecuteAndRecordInsert(const string16& text, bool mergeable);
-
- // Adds or merge |edit| into edit history. Return true if the edit
- // has been merged and must be deleted after redo.
- bool AddOrMergeEditHistory(internal::Edit* edit);
-
- // Modify the text buffer in following way:
- // 1) Delete the string from |delete_from| to |delte_to|.
- // 2) Insert the |new_text| at the index |new_text_insert_at|.
- // Note that the index is after deletion.
- // 3) Move the cursor to |new_cursor_pos|.
- void ModifyText(size_t delete_from,
- size_t delete_to,
- const string16& new_text,
- size_t new_text_insert_at,
- size_t new_cursor_pos);
-
- void ClearComposition();
-
- // Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
- // the View object.
- Delegate* delegate_;
-
- // The stylized text, cursor, selection, and the visual layout model.
- scoped_ptr<gfx::RenderText> render_text_;
-
- typedef std::list<internal::Edit*> EditHistory;
- EditHistory edit_history_;
-
- // An iterator that points to the current edit that can be undone.
- // This iterator moves from the |end()|, meaining no edit to undo,
- // to the last element (one before |end()|), meaning no edit to redo.
- // There is no edit to undo (== end()) when:
- // 1) in initial state. (nothing to undo)
- // 2) very 1st edit is undone.
- // 3) all edit history is removed.
- // There is no edit to redo (== last element or no element) when:
- // 1) in initial state. (nothing to redo)
- // 2) new edit is added. (redo history is cleared)
- // 3) redone all undone edits.
- EditHistory::iterator current_edit_;
-
- DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_VIEWS_MODEL_H_
diff --git a/chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc
deleted file mode 100644
index b23fb10b453..00000000000
--- a/chromium/ui/views/controls/textfield/textfield_views_model_unittest.cc
+++ /dev/null
@@ -1,1516 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <vector>
-
-#include "base/auto_reset.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#include "ui/gfx/range/range.h"
-#include "ui/gfx/render_text.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_views_model.h"
-#include "ui/views/test/test_views_delegate.h"
-#include "ui/views/test/views_test_base.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-#define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
-
-namespace {
-
-struct WordAndCursor {
- WordAndCursor(const wchar_t* w, size_t c) : word(w), cursor(c) {}
-
- const wchar_t* word;
- size_t cursor;
-};
-
-void MoveCursorTo(views::TextfieldViewsModel& model, size_t pos) {
- model.MoveCursorTo(gfx::SelectionModel(pos, gfx::CURSOR_FORWARD));
-}
-
-} // namespace
-
-namespace views {
-
-class TextfieldViewsModelTest : public ViewsTestBase,
- public TextfieldViewsModel::Delegate {
- public:
- TextfieldViewsModelTest()
- : ViewsTestBase(),
- composition_text_confirmed_or_cleared_(false) {
- }
-
- virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE {
- composition_text_confirmed_or_cleared_ = true;
- }
-
- protected:
- void ResetModel(TextfieldViewsModel* model) const {
- model->SetText(string16());
- model->ClearEditHistory();
- }
-
- bool composition_text_confirmed_or_cleared_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModelTest);
-};
-
-TEST_F(TextfieldViewsModelTest, EditString) {
- TextfieldViewsModel model(NULL);
- // append two strings
- model.Append(ASCIIToUTF16("HILL"));
- EXPECT_STR_EQ("HILL", model.GetText());
- model.Append(ASCIIToUTF16("WORLD"));
- EXPECT_STR_EQ("HILLWORLD", model.GetText());
-
- // Insert "E" to make hello
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.InsertChar('E');
- EXPECT_STR_EQ("HEILLWORLD", model.GetText());
- // Replace "I" with "L"
- model.ReplaceChar('L');
- EXPECT_STR_EQ("HELLLWORLD", model.GetText());
- model.ReplaceChar('L');
- model.ReplaceChar('O');
- EXPECT_STR_EQ("HELLOWORLD", model.GetText());
-
- // Delete 6th char "W", then delete 5th char O"
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HELLOORLD", model.GetText());
- EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
-
- // Move the cursor to start. backspace should fail.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_FALSE(model.Backspace());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
- // Move the cursor to the end. delete should fail.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_FALSE(model.Delete());
- EXPECT_STR_EQ("HELLORLD", model.GetText());
- // but backspace should work.
- EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HELLORL", model.GetText());
-
- MoveCursorTo(model, 5);
- model.ReplaceText(ASCIIToUTF16(" WOR"));
- EXPECT_STR_EQ("HELLO WORL", model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, EditString_SimpleRTL) {
- TextfieldViewsModel model(NULL);
- // Append two strings.
- model.Append(WideToUTF16(L"\x05d0\x05d1\x05d2"));
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.GetText());
- model.Append(WideToUTF16(L"\x05e0\x05e1\x05e2"));
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
-
- // Insert 0x05f0.
- MoveCursorTo(model, 1);
- model.InsertChar(0x05f0);
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
-
- // Replace "\x05d1" with "\x05f1".
- model.ReplaceChar(0x05f1);
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"),
- model.GetText());
-
- // Delete and backspace.
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"),
- model.GetText());
- EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) {
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
- bool on_windows_xp = false;
-#if defined(OS_WIN)
- on_windows_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
-#endif
-
- TextfieldViewsModel model(NULL);
-
- // Append two Hindi strings.
- model.Append(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
- EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"),
- model.GetText());
- model.Append(WideToUTF16(L"\x0915\x094d\x092e\x094d"));
- EXPECT_EQ(WideToUTF16(
- L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
-
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
- if (!on_windows_xp) {
- // Check it is not able to place cursor in middle of a grapheme.
- MoveCursorTo(model, 1);
- EXPECT_EQ(0U, model.GetCursorPosition());
-
- MoveCursorTo(model, 2);
- EXPECT_EQ(2U, model.GetCursorPosition());
- model.InsertChar('a');
- EXPECT_EQ(WideToUTF16(
- L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
-
- // ReplaceChar will replace the whole grapheme.
- model.ReplaceChar('b');
- // TODO(xji): temporarily disable in platform Win since the complex script
- // characters turned into empty square due to font regression. So, not able
- // to test 2 characters belong to the same grapheme.
-#if defined(OS_LINUX)
- EXPECT_EQ(WideToUTF16(
- L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
-#endif
- EXPECT_EQ(4U, model.GetCursorPosition());
- }
-
- // Delete should delete the whole grapheme.
- MoveCursorTo(model, 0);
- // TODO(xji): temporarily disable in platform Win since the complex script
- // characters turned into empty square due to font regression. So, not able
- // to test 2 characters belong to the same grapheme.
-#if defined(OS_LINUX)
- EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"),
- model.GetText());
- MoveCursorTo(model, model.GetText().length());
- EXPECT_EQ(model.GetText().length(), model.GetCursorPosition());
- EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"),
- model.GetText());
-#endif
-
- // Test cursor position and deletion for Hindi Virama.
- model.SetText(WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"));
- MoveCursorTo(model, 0);
- EXPECT_EQ(0U, model.GetCursorPosition());
-
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
- if (!on_windows_xp) {
- MoveCursorTo(model, 1);
- EXPECT_EQ(0U, model.GetCursorPosition());
- MoveCursorTo(model, 3);
- EXPECT_EQ(3U, model.GetCursorPosition());
- }
-
- // TODO(asvitkine): Temporarily disable the following check on Windows. It
- // seems Windows treats "\x0D38\x0D4D\x0D15" as a single grapheme.
-#if !defined(OS_WIN)
- MoveCursorTo(model, 2);
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.GetText());
-#endif
-
- model.SetText(WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"));
- MoveCursorTo(model, 0);
- EXPECT_TRUE(model.Delete());
- EXPECT_TRUE(model.Delete());
- EXPECT_TRUE(model.Delete());
- EXPECT_TRUE(model.Delete());
- EXPECT_EQ(WideToUTF16(L""), model.GetText());
-
- // The first 2 characters are not strong directionality characters.
- model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
- model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, EmptyString) {
- TextfieldViewsModel model(NULL);
- EXPECT_EQ(string16(), model.GetText());
- EXPECT_EQ(string16(), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(0U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(0U, model.GetCursorPosition());
-
- EXPECT_EQ(string16(), model.GetSelectedText());
-
- EXPECT_FALSE(model.Delete());
- EXPECT_FALSE(model.Backspace());
-}
-
-TEST_F(TextfieldViewsModelTest, Selection) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_STR_EQ("E", model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_STR_EQ("EL", model.GetSelectedText());
-
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_STR_EQ("H", model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_STR_EQ("ELLO", model.GetSelectedText());
- model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
-
- // SelectAll(false) selects towards the end.
- model.SelectAll(false);
- EXPECT_STR_EQ("HELLO", model.GetSelectedText());
- EXPECT_EQ(gfx::Range(0, 5), model.render_text()->selection());
-
- // SelectAll(true) selects towards the beginning.
- model.SelectAll(true);
- EXPECT_STR_EQ("HELLO", model.GetSelectedText());
- EXPECT_EQ(gfx::Range(5, 0), model.render_text()->selection());
-
- // Select and move cursor.
- model.SelectRange(gfx::Range(1U, 3U));
- EXPECT_STR_EQ("EL", model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_EQ(1U, model.GetCursorPosition());
- model.SelectRange(gfx::Range(1U, 3U));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(3U, model.GetCursorPosition());
-
- // Select all and move cursor.
- model.SelectAll(false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_EQ(0U, model.GetCursorPosition());
- model.SelectAll(false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(5U, model.GetCursorPosition());
-}
-
-TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) {
- // Selection is a logical operation. And it should work with the arrow
- // keys doing visual movements, while the selection is logical between
- // the (logical) start and end points. Selection is simply defined as
- // the portion of text between the logical positions of the start and end
- // caret positions.
- TextfieldViewsModel model(NULL);
- // TODO(xji): temporarily disable in platform Win since the complex script
- // characters turned into empty square due to font regression. So, not able
- // to test 2 characters belong to the same grapheme.
-#if defined(OS_LINUX)
- model.Append(WideToUTF16(
- L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(gfx::Range(2, 7), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"),
- model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(gfx::Range(2, 10), model.render_text()->selection());
- EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"),
- model.GetSelectedText());
-
- model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
- model.SelectAll(false);
- EXPECT_EQ(WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"),
- model.GetSelectedText());
-#endif
-
- // In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is
- // an RTL character.
- model.SetText(WideToUTF16(L"a\x05E9" L"b"));
- MoveCursorTo(model, 0);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(3U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
-
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(WideToUTF16(L"a\x05E9"), model.GetSelectedText());
-
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText());
-
- model.ClearSelection();
- EXPECT_EQ(string16(), model.GetSelectedText());
- model.SelectAll(false);
- EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
-}
-
-TEST_F(TextfieldViewsModelTest, SelectionAndEdit) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL"
- EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HLO", model.GetText());
-
- model.Append(ASCIIToUTF16("ILL"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO"
- EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HILL", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I"
- model.InsertChar('E');
- EXPECT_STR_EQ("HELL", model.GetText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H"
- model.ReplaceChar('B');
- EXPECT_STR_EQ("BELL", model.GetText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL"
- model.ReplaceChar('E');
- EXPECT_STR_EQ("BEE", model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, Word) {
- TextfieldViewsModel model(NULL);
- model.Append(
- ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(3U, model.GetCursorPosition());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(10U, model.GetCursorPosition());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(18U, model.GetCursorPosition());
-
- // Should passes the non word char ','
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_EQ(23U, model.GetCursorPosition());
- EXPECT_STR_EQ(", the", model.GetSelectedText());
-
- // Move to the end.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
- // Should be safe to go next word at the end.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
- model.InsertChar('2');
- EXPECT_EQ(19U, model.GetCursorPosition());
-
- // Now backwards.
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); // leave 2.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_STR_EQ("Life", model.GetSelectedText());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_STR_EQ("to Life", model.GetSelectedText());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); // Now at start.
- EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
- // Should be safe to go to the previous word at the beginning.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
- model.ReplaceChar('4');
- EXPECT_EQ(string16(), model.GetSelectedText());
- EXPECT_STR_EQ("42", model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, SetText) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.SetText(ASCIIToUTF16("GOODBYE"));
- EXPECT_STR_EQ("GOODBYE", model.GetText());
- // SetText move the cursor to the end of the new text.
- EXPECT_EQ(7U, model.GetCursorPosition());
- model.SelectAll(false);
- EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(7U, model.GetCursorPosition());
-
- model.SetText(ASCIIToUTF16("BYE"));
- // Setting shorter string moves the cursor to the end of the new string.
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_EQ(string16(), model.GetSelectedText());
- model.SetText(string16());
- EXPECT_EQ(0U, model.GetCursorPosition());
-}
-
-TEST_F(TextfieldViewsModelTest, Clipboard) {
- ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
- const string16 initial_clipboard_text = ASCIIToUTF16("initial text");
- ui::ScopedClipboardWriter(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE).
- WriteText(initial_clipboard_text);
-
- string16 clipboard_text;
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
-
- // Cut with an empty selection should do nothing.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_FALSE(model.Cut());
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
- EXPECT_EQ(11U, model.GetCursorPosition());
-
- // Copy with an empty selection should do nothing.
- model.Copy();
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
- EXPECT_EQ(11U, model.GetCursorPosition());
-
- // Cut on obscured (password) text should do nothing.
- model.render_text()->SetObscured(true);
- model.SelectAll(false);
- EXPECT_FALSE(model.Cut());
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
- EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
-
- // Copy on obscured text should do nothing.
- model.SelectAll(false);
- EXPECT_FALSE(model.Copy());
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_EQ(initial_clipboard_text, clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.GetText());
- EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText());
-
- // Cut with non-empty selection.
- model.render_text()->SetObscured(false);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_TRUE(model.Cut());
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_STR_EQ("WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.GetText());
- EXPECT_EQ(6U, model.GetCursorPosition());
-
- // Copy with non-empty selection.
- model.SelectAll(false);
- EXPECT_TRUE(model.Copy());
- clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
- EXPECT_STR_EQ("HELLO ", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.GetText());
- EXPECT_EQ(6U, model.GetCursorPosition());
-
- // Test that paste works regardless of the obscured bit.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("HELLO HELLO ", model.GetText());
- EXPECT_EQ(12U, model.GetCursorPosition());
- model.render_text()->SetObscured(true);
- EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("HELLO HELLO HELLO ", model.GetText());
- EXPECT_EQ(18U, model.GetCursorPosition());
-}
-
-static void SelectWordTestVerifier(const TextfieldViewsModel& model,
- const string16 &expected_selected_string, size_t expected_cursor_pos) {
- EXPECT_EQ(expected_selected_string, model.GetSelectedText());
- EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition());
-}
-
-TEST_F(TextfieldViewsModelTest, SelectWordTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16(" HELLO !! WO RLD "));
-
- // Test when cursor is at the beginning.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 2U);
-
- // Test when cursor is at the beginning of a word.
- MoveCursorTo(model, 2);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16("HELLO"), 7U);
-
- // Test when cursor is at the end of a word.
- MoveCursorTo(model, 15);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U);
-
- // Test when cursor is somewhere in a non-alpha-numeric fragment.
- for (size_t cursor_pos = 8; cursor_pos < 13U; cursor_pos++) {
- MoveCursorTo(model, cursor_pos);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" !! "), 13U);
- }
-
- // Test when cursor is somewhere in a whitespace fragment.
- MoveCursorTo(model, 17);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U);
-
- // Test when cursor is at the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.SelectWord();
- SelectWordTestVerifier(model, ASCIIToUTF16(" "), 24U);
-}
-
-// TODO(xji): temporarily disable in platform Win since the complex script
-// characters and Chinese characters are turned into empty square due to font
-// regression.
-#if defined(OS_LINUX)
-TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) {
- TextfieldViewsModel model(NULL);
- std::vector<WordAndCursor> word_and_cursor;
- word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
- word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
- word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5));
- word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5));
- word_and_cursor.push_back(WordAndCursor(L" ", 3));
- word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2));
- word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9));
- word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9));
- word_and_cursor.push_back(WordAndCursor(L" ", 10));
- word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12));
- word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12));
- word_and_cursor.push_back(WordAndCursor(L"\x82B1", 13));
- word_and_cursor.push_back(WordAndCursor(L"\x5929", 14));
-
- // The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese.
- model.SetText(WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
- L"\x4E2D\x56FD\x82B1\x5929"));
- for (size_t i = 0; i < word_and_cursor.size(); ++i) {
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- for (size_t j = 0; j < i; ++j)
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.SelectWord();
- SelectWordTestVerifier(model, WideToUTF16(word_and_cursor[i].word),
- word_and_cursor[i].cursor);
- }
-}
-#endif
-
-TEST_F(TextfieldViewsModelTest, RangeTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- gfx::Range range = model.render_text()->selection();
- EXPECT_TRUE(range.is_empty());
- EXPECT_EQ(0U, range.start());
- EXPECT_EQ(0U, range.end());
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- range = model.render_text()->selection();
- EXPECT_FALSE(range.is_empty());
- EXPECT_FALSE(range.is_reversed());
- EXPECT_EQ(0U, range.start());
- EXPECT_EQ(5U, range.end());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- range = model.render_text()->selection();
- EXPECT_FALSE(range.is_empty());
- EXPECT_EQ(0U, range.start());
- EXPECT_EQ(4U, range.end());
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- range = model.render_text()->selection();
- EXPECT_TRUE(range.is_empty());
- EXPECT_EQ(0U, range.start());
- EXPECT_EQ(0U, range.end());
-
- // now from the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- range = model.render_text()->selection();
- EXPECT_TRUE(range.is_empty());
- EXPECT_EQ(11U, range.start());
- EXPECT_EQ(11U, range.end());
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- range = model.render_text()->selection();
- EXPECT_FALSE(range.is_empty());
- EXPECT_TRUE(range.is_reversed());
- EXPECT_EQ(11U, range.start());
- EXPECT_EQ(6U, range.end());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- range = model.render_text()->selection();
- EXPECT_FALSE(range.is_empty());
- EXPECT_TRUE(range.is_reversed());
- EXPECT_EQ(11U, range.start());
- EXPECT_EQ(7U, range.end());
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- range = model.render_text()->selection();
- EXPECT_TRUE(range.is_empty());
- EXPECT_EQ(11U, range.start());
- EXPECT_EQ(11U, range.end());
-
- // Select All
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
- range = model.render_text()->selection();
- EXPECT_FALSE(range.is_empty());
- EXPECT_TRUE(range.is_reversed());
- EXPECT_EQ(11U, range.start());
- EXPECT_EQ(0U, range.end());
-}
-
-TEST_F(TextfieldViewsModelTest, SelectRangeTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
- gfx::Range range(0, 6);
- EXPECT_FALSE(range.is_reversed());
- model.SelectRange(range);
- EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
-
- range = gfx::Range(6, 1);
- EXPECT_TRUE(range.is_reversed());
- model.SelectRange(range);
- EXPECT_STR_EQ("ELLO ", model.GetSelectedText());
-
- range = gfx::Range(2, 1000);
- EXPECT_FALSE(range.is_reversed());
- model.SelectRange(range);
- EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText());
-
- range = gfx::Range(1000, 3);
- EXPECT_TRUE(range.is_reversed());
- model.SelectRange(range);
- EXPECT_STR_EQ("LO WORLD", model.GetSelectedText());
-
- range = gfx::Range(0, 0);
- EXPECT_TRUE(range.is_empty());
- model.SelectRange(range);
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- range = gfx::Range(3, 3);
- EXPECT_TRUE(range.is_empty());
- model.SelectRange(range);
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- range = gfx::Range(1000, 100);
- EXPECT_FALSE(range.is_empty());
- model.SelectRange(range);
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- range = gfx::Range(1000, 1000);
- EXPECT_TRUE(range.is_empty());
- model.SelectRange(range);
- EXPECT_TRUE(model.GetSelectedText().empty());
-}
-
-TEST_F(TextfieldViewsModelTest, SelectionTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- gfx::Range selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(0), selection);
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(0, 5), selection);
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(0, 4), selection);
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(0), selection);
-
- // now from the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(11), selection);
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(11, 6), selection);
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(11, 7), selection);
-
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(11), selection);
-
- // Select All
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
- selection = model.render_text()->selection();
- EXPECT_EQ(gfx::Range(11, 0), selection);
-}
-
-TEST_F(TextfieldViewsModelTest, SelectSelectionModelTest) {
- TextfieldViewsModel model(NULL);
- model.Append(ASCIIToUTF16("HELLO WORLD"));
- model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(0, 6),
- gfx::CURSOR_BACKWARD));
- EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
-
- model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(6, 1),
- gfx::CURSOR_FORWARD));
- EXPECT_STR_EQ("ELLO ", model.GetSelectedText());
-
- model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(2, 1000),
- gfx::CURSOR_BACKWARD));
- EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText());
-
- model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 3),
- gfx::CURSOR_FORWARD));
- EXPECT_STR_EQ("LO WORLD", model.GetSelectedText());
-
- model.SelectSelectionModel(gfx::SelectionModel(0, gfx::CURSOR_FORWARD));
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- model.SelectSelectionModel(gfx::SelectionModel(3, gfx::CURSOR_FORWARD));
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 100),
- gfx::CURSOR_FORWARD));
- EXPECT_TRUE(model.GetSelectedText().empty());
-
- model.SelectSelectionModel(gfx::SelectionModel(1000, gfx::CURSOR_BACKWARD));
- EXPECT_TRUE(model.GetSelectedText().empty());
-}
-
-TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
- TextfieldViewsModel model(this);
- model.Append(ASCIIToUTF16("1234590"));
- model.SelectRange(gfx::Range(5, 5));
- EXPECT_FALSE(model.HasSelection());
- EXPECT_EQ(5U, model.GetCursorPosition());
-
- gfx::Range range;
- model.GetTextRange(&range);
- EXPECT_EQ(gfx::Range(0, 7), range);
-
- ui::CompositionText composition;
- composition.text = ASCIIToUTF16("678");
- composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
-
- // Cursor should be at the end of composition when characters are just typed.
- composition.selection = gfx::Range(3, 3);
- model.SetCompositionText(composition);
- EXPECT_TRUE(model.HasCompositionText());
- EXPECT_FALSE(model.HasSelection());
-
- // Cancel composition
- model.CancelCompositionText();
- composition_text_confirmed_or_cleared_ = false;
-
- // Restart composition with targeting "67" in "678".
- composition.selection = gfx::Range(0, 2);
- composition.underlines.clear();
- composition.underlines.push_back(ui::CompositionUnderline(0, 2, 0, true));
- composition.underlines.push_back(ui::CompositionUnderline(2, 3, 0, false));
- model.SetCompositionText(composition);
- EXPECT_TRUE(model.HasCompositionText());
- EXPECT_TRUE(model.HasSelection());
- EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
-
- model.GetTextRange(&range);
- EXPECT_EQ(10U, range.end());
- EXPECT_STR_EQ("1234567890", model.GetText());
-
- model.GetCompositionTextRange(&range);
- EXPECT_EQ(gfx::Range(5, 8), range);
- // composition text
- EXPECT_STR_EQ("456", model.GetTextFromRange(gfx::Range(3, 6)));
- EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection());
-
- EXPECT_FALSE(composition_text_confirmed_or_cleared_);
- model.CancelCompositionText();
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_FALSE(model.HasCompositionText());
- EXPECT_FALSE(model.HasSelection());
- EXPECT_EQ(5U, model.GetCursorPosition());
-
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890", model.GetText());
- EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890")));
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
-
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.GetText());
-
- model.InsertText(UTF8ToUTF16("-"));
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.GetText());
- EXPECT_FALSE(model.HasCompositionText());
- EXPECT_FALSE(model.HasSelection());
-
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_STR_EQ("-", model.GetSelectedText());
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.GetText());
-
- model.ReplaceText(UTF8ToUTF16("-"));
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.GetText());
- EXPECT_FALSE(model.HasCompositionText());
- EXPECT_FALSE(model.HasSelection());
-
- model.SetCompositionText(composition);
- model.Append(UTF8ToUTF16("-"));
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
-
- model.SetCompositionText(composition);
- model.Delete();
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
-
- model.SetCompositionText(composition);
- model.Backspace();
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.GetText());
-
- model.SetText(string16());
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
-
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788", model.GetText());
- EXPECT_EQ(6U, model.GetCursorPosition());
-
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788678", model.GetText());
-
- model.SetText(string16());
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
-
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.GetText());
-
- model.SetCompositionText(composition);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
-
- model.SetCompositionText(composition);
- gfx::SelectionModel sel(
- gfx::Range(model.render_text()->selection().start(), 0),
- gfx::CURSOR_FORWARD);
- model.MoveCursorTo(sel);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.GetText());
-
- model.SetCompositionText(composition);
- model.SelectRange(gfx::Range(0, 3));
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
-
- model.SetCompositionText(composition);
- model.SelectAll(false);
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
-
- model.SetCompositionText(composition);
- model.SelectWord();
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.GetText());
-
- model.SetCompositionText(composition);
- model.ClearSelection();
- EXPECT_TRUE(composition_text_confirmed_or_cleared_);
- composition_text_confirmed_or_cleared_ = false;
-
- model.SetCompositionText(composition);
- EXPECT_FALSE(model.Cut());
- EXPECT_FALSE(composition_text_confirmed_or_cleared_);
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) {
- TextfieldViewsModel model(NULL);
- model.InsertChar('a');
- EXPECT_FALSE(model.Redo()); // nothing to redo
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
-
- // Continuous inserts are treated as one edit.
- model.InsertChar('b');
- model.InsertChar('c');
- EXPECT_STR_EQ("abc", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
-
- // Undoing further shouldn't change the text.
- EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
-
- // Redoing to the latest text.
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abc", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
-
- // Backspace ===============================
- EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("ab", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- // Continous backspaces are treated as one edit.
- EXPECT_TRUE(model.Backspace());
- EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("", model.GetText());
- // Extra backspace shouldn't affect the history.
- EXPECT_FALSE(model.Backspace());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ab", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
-
- // Clear history
- model.ClearEditHistory();
- EXPECT_FALSE(model.Undo());
- EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("a", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
-
- // Delete ===============================
- model.SetText(ASCIIToUTF16("ABCDE"));
- model.ClearEditHistory();
- MoveCursorTo(model, 2);
- EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("ABDE", model.GetText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("BDE", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABDE", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- // Continous deletes are treated as one edit.
- EXPECT_TRUE(model.Delete());
- EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("AB", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("AB", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) {
- // This is to test the undo/redo behavior of omnibox.
- TextfieldViewsModel model(NULL);
- model.InsertChar('w');
- EXPECT_STR_EQ("w", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(ASCIIToUTF16("www.google.com"));
- EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- model.SelectRange(gfx::Range(14, 1));
- model.InsertChar('w');
- EXPECT_STR_EQ("ww", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 2));
- model.InsertChar('w');
- EXPECT_STR_EQ("www", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 3));
- model.InsertChar('.');
- EXPECT_STR_EQ("www.", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 4));
- model.InsertChar('y');
- EXPECT_STR_EQ("www.y", model.GetText());
- model.SetText(ASCIIToUTF16("www.youtube.com"));
- EXPECT_STR_EQ("www.youtube.com", model.GetText());
- EXPECT_EQ(15U, model.GetCursorPosition());
-
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.youtube.com", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_BackspaceThenSetText) {
- // This is to test the undo/redo behavior of omnibox.
- TextfieldViewsModel model(NULL);
- model.InsertChar('w');
- EXPECT_STR_EQ("w", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(ASCIIToUTF16("www.google.com"));
- EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_STR_EQ("www.google.com", model.GetText());
- model.SetText(ASCIIToUTF16("www.google.com")); // Confirm the text.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_EQ(14U, model.GetCursorPosition());
- EXPECT_TRUE(model.Backspace());
- EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("www.google.c", model.GetText());
- // Autocomplete sets the text
- model.SetText(ASCIIToUTF16("www.google.com/search=www.google.c"));
- EXPECT_STR_EQ("www.google.com/search=www.google.c", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.c", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.GetText());
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) {
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("ABCDE"));
- EXPECT_FALSE(model.Redo()); // nothing to redo
- // Cut
- model.SelectRange(gfx::Range(1, 3));
- model.Cut();
- EXPECT_STR_EQ("ADE", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo()); // no more undo
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo()); // no more redo
- EXPECT_STR_EQ("ADE", model.GetText());
-
- model.Paste();
- model.Paste();
- model.Paste();
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
- EXPECT_EQ(7U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ADE", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText()); // Redoing SetText
- EXPECT_EQ(5U, model.GetCursorPosition());
-
- // Redo
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
- EXPECT_EQ(7U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
-
- // with SelectRange
- model.SelectRange(gfx::Range(1, 3));
- EXPECT_TRUE(model.Cut());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
- EXPECT_EQ(1U, model.GetCursorPosition());
- model.SelectRange(gfx::Range(1, 1));
- EXPECT_FALSE(model.Cut());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("ABCBCDEBC", model.GetText());
- EXPECT_EQ(9U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.GetText());
- EXPECT_EQ(7U, model.GetCursorPosition());
- // empty cut shouldn't create an edit.
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
-
- // Copy
- ResetModel(&model);
- model.SetText(ASCIIToUTF16("12345"));
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- model.SelectRange(gfx::Range(1, 3));
- model.Copy(); // Copy "23"
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- model.Paste(); // Paste "23" into "23".
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- model.Paste();
- EXPECT_STR_EQ("1232345", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- // TODO(oshima): We need to change the return type from bool to enum.
- EXPECT_FALSE(model.Undo()); // No text change.
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_FALSE(model.Undo());
- // Redo
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.GetText()); // For 1st paste
- EXPECT_EQ(3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1232345", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("1232345", model.GetText());
-
- // Test using SelectRange
- model.SelectRange(gfx::Range(1, 3));
- model.Copy();
- EXPECT_STR_EQ("1232345", model.GetText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("123234523", model.GetText());
- EXPECT_EQ(9U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("1232345", model.GetText());
- EXPECT_EQ(7U, model.GetCursorPosition());
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) {
- TextfieldViewsModel model(NULL);
- model.InsertChar('a');
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.InsertChar('b');
- // Moving the cursor shouldn't create a new edit.
- EXPECT_STR_EQ("ab", model.GetText());
- EXPECT_FALSE(model.Redo());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.GetText());
- EXPECT_EQ(2U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
-}
-
-void RunInsertReplaceTest(TextfieldViewsModel& model) {
- const bool reverse = model.render_text()->selection().is_reversed();
- model.InsertChar('1');
- model.InsertChar('2');
- model.InsertChar('3');
- EXPECT_STR_EQ("a123d", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.GetText());
- EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition()); // By SetText
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a123d", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
-}
-
-void RunOverwriteReplaceTest(TextfieldViewsModel& model) {
- const bool reverse = model.render_text()->selection().is_reversed();
- model.ReplaceChar('1');
- model.ReplaceChar('2');
- model.ReplaceChar('3');
- model.ReplaceChar('4');
- EXPECT_STR_EQ("a1234", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.GetText());
- EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_EQ(0U, model.GetCursorPosition());
- EXPECT_FALSE(model.Undo());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.GetText());
- EXPECT_EQ(4U, model.GetCursorPosition());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a1234", model.GetText());
- EXPECT_EQ(5U, model.GetCursorPosition());
- EXPECT_FALSE(model.Redo());
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_ReplaceTest) {
- // By Cursor
- {
- SCOPED_TRACE("forward & insert by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & insert by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("forward & overwrite by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunOverwriteReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & overwrite by cursor");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunOverwriteReplaceTest(model);
- }
- // By SelectRange API
- {
- SCOPED_TRACE("forward & insert by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & insert by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunInsertReplaceTest(model);
- }
- {
- SCOPED_TRACE("forward & overwrite by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(1, 3));
- RunOverwriteReplaceTest(model);
- }
- {
- SCOPED_TRACE("backward & overwrite by SelectRange");
- TextfieldViewsModel model(NULL);
- model.SetText(ASCIIToUTF16("abcd"));
- model.SelectRange(gfx::Range(3, 1));
- RunOverwriteReplaceTest(model);
- }
-}
-
-TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) {
- TextfieldViewsModel model(NULL);
-
- ui::CompositionText composition;
- composition.text = ASCIIToUTF16("abc");
- composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false));
- composition.selection = gfx::Range(2, 3);
-
- model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.InsertChar('x');
- EXPECT_STR_EQ("ABCDEx", model.GetText());
- EXPECT_TRUE(model.Undo()); // set composition should forget undone edit.
- model.SetCompositionText(composition);
- EXPECT_TRUE(model.HasCompositionText());
- EXPECT_TRUE(model.HasSelection());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
-
- // Accepting composition
- model.ConfirmCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_FALSE(model.Redo());
-
- // Canceling composition
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("abcABCDEabc", model.GetText());
- model.CancelCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_FALSE(model.Redo());
-
- // SetText with the same text as the result.
- ResetModel(&model);
- model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- model.SetText(ASCIIToUTF16("ABCDEabc"));
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- EXPECT_FALSE(model.Redo());
-
- // SetText with the different text than the result should not
- // remember composition text.
- ResetModel(&model);
- model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.GetText());
- model.SetText(ASCIIToUTF16("1234"));
- EXPECT_STR_EQ("1234", model.GetText());
- EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.GetText());
- EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1234", model.GetText());
- EXPECT_FALSE(model.Redo());
-
- // TODO(oshima): We need MockInputMethod to test the behavior with IME.
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/throbber.cc b/chromium/ui/views/controls/throbber.cc
index 25272de0536..5df35606378 100644
--- a/chromium/ui/views/controls/throbber.cc
+++ b/chromium/ui/views/controls/throbber.cc
@@ -68,7 +68,7 @@ void Throbber::Run() {
SchedulePaint();
}
-gfx::Size Throbber::GetPreferredSize() {
+gfx::Size Throbber::GetPreferredSize() const {
return gfx::Size(frames_->height(), frames_->height());
}
diff --git a/chromium/ui/views/controls/throbber.h b/chromium/ui/views/controls/throbber.h
index 8ae3895a22a..08188c39cf5 100644
--- a/chromium/ui/views/controls/throbber.h
+++ b/chromium/ui/views/controls/throbber.h
@@ -37,7 +37,7 @@ class VIEWS_EXPORT Throbber : public View {
void SetFrames(const gfx::ImageSkia* frames);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
protected:
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index 2c7bd55c396..f514fe45fcd 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -9,11 +9,12 @@
#include "base/i18n/rtl.h"
#include "base/message_loop/message_loop.h"
#include "grit/ui_resources.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/skia_util.h"
@@ -78,8 +79,7 @@ TreeView::TreeView()
editable_(true),
controller_(NULL),
root_shown_(true),
- has_custom_icons_(false),
- row_height_(font_.GetHeight() + kTextVerticalPadding * 2) {
+ row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2) {
SetFocusable(true);
closed_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
(base::i18n::IsRTL() ? IDR_FOLDER_CLOSED_RTL
@@ -158,9 +158,9 @@ void TreeView::StartEditing(TreeModelNode* node) {
// Add the editor immediately as GetPreferredSize returns the wrong thing if
// not parented.
AddChildView(editor_);
- editor_->SetFont(font_);
+ editor_->SetFontList(font_list_);
empty_editor_size_ = editor_->GetPreferredSize();
- editor_->SetController(this);
+ editor_->set_controller(this);
}
editor_->SetText(selected_node_->model_node()->GetTitle());
LayoutEditor();
@@ -245,7 +245,7 @@ void TreeView::SetSelectedNode(TreeModelNode* model_node) {
if (changed) {
// TODO(dmazzoni): Decide if EVENT_SELECTION_CHANGED is a better choice for
// sub-item selection event.
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
}
@@ -350,7 +350,7 @@ void TreeView::Layout() {
LayoutEditor();
}
-gfx::Size TreeView::GetPreferredSize() {
+gfx::Size TreeView::GetPreferredSize() const {
return preferred_size_;
}
@@ -403,14 +403,14 @@ void TreeView::ShowContextMenu(const gfx::Point& p,
View::ShowContextMenu(p, source_type);
}
-void TreeView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_OUTLINE;
- state->state = ui::AccessibilityTypes::STATE_READONLY;
+void TreeView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_TREE;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
if (!selected_node_)
return;
// Get selected item info.
- state->role = ui::AccessibilityTypes::ROLE_OUTLINEITEM;
+ state->role = ui::AX_ROLE_TREE_ITEM;
state->name = selected_node_->model_node()->GetTitle();
}
@@ -482,7 +482,7 @@ void TreeView::TreeNodeChanged(TreeModel* model, TreeModelNode* model_node) {
}
void TreeView::ContentsChanged(Textfield* sender,
- const string16& new_contents) {
+ const base::string16& new_contents) {
}
bool TreeView::HandleKeyEvent(Textfield* sender,
@@ -525,7 +525,7 @@ void TreeView::SetSelectedRow(int row) {
SetSelectedNode(GetNodeForRow(row));
}
-string16 TreeView::GetTextForRow(int row) {
+base::string16 TreeView::GetTextForRow(int row) {
return GetNodeForRow(row)->GetTitle();
}
@@ -694,7 +694,7 @@ void TreeView::ConfigureInternalNode(TreeModelNode* model_node,
void TreeView::UpdateNodeTextWidth(InternalNode* node) {
int width = 0, height = 0;
- gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_,
+ gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_list_,
&width, &height, 0, gfx::Canvas::NO_ELLIPSIS);
node->set_text_width(width);
}
@@ -729,7 +729,7 @@ void TreeView::LayoutEditor() {
row_bounds.set_width(row_bounds.width() - text_offset_);
row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding);
row_bounds.Inset(-empty_editor_size_.width() / 2,
- -(empty_editor_size_.height() - font_.GetHeight()) / 2);
+ -(empty_editor_size_.height() - font_list_.GetHeight()) / 2);
// Give a little extra space for editing.
row_bounds.set_width(row_bounds.width() + 50);
editor_->SetBoundsRect(row_bounds);
@@ -803,12 +803,14 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
}
const ui::NativeTheme::ColorId color_id =
text_color_id(HasFocus(), node == selected_node_);
- canvas->DrawStringInt(node->model_node()->GetTitle(), font_,
- GetNativeTheme()->GetSystemColor(color_id),
- text_bounds.x() + kTextHorizontalPadding,
- text_bounds.y() + kTextVerticalPadding,
- text_bounds.width() - kTextHorizontalPadding * 2,
- text_bounds.height() - kTextVerticalPadding * 2);
+ const gfx::Rect internal_bounds(
+ text_bounds.x() + kTextHorizontalPadding,
+ text_bounds.y() + kTextVerticalPadding,
+ text_bounds.width() - kTextHorizontalPadding * 2,
+ text_bounds.height() - kTextVerticalPadding * 2);
+ canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
+ GetNativeTheme()->GetSystemColor(color_id),
+ internal_bounds);
}
}
diff --git a/chromium/ui/views/controls/tree/tree_view.h b/chromium/ui/views/controls/tree/tree_view.h
index de571c789bf..3cae3b52376 100644
--- a/chromium/ui/views/controls/tree/tree_view.h
+++ b/chromium/ui/views/controls/tree/tree_view.h
@@ -11,13 +11,17 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/models/tree_node_model.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"
+namespace gfx {
+class Rect;
+} // namespace gfx
+
namespace views {
class Textfield;
@@ -117,14 +121,14 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// View overrides:
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// TreeModelObserver overrides:
@@ -141,7 +145,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// TextfieldController overrides:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE;
+ const base::string16& new_contents) OVERRIDE;
virtual bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) OVERRIDE;
@@ -155,7 +159,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
virtual int GetRowCount() OVERRIDE;
virtual int GetSelectedRow() OVERRIDE;
virtual void SetSelectedRow(int row) OVERRIDE;
- virtual string16 GetTextForRow(int row) OVERRIDE;
+ virtual base::string16 GetTextForRow(int row) OVERRIDE;
protected:
// View overrides:
@@ -370,14 +374,11 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
// Whether or not the root is shown in the tree.
bool root_shown_;
- // Did the model return a non-empty set of icons from GetIcons?
- bool has_custom_icons_;
-
// Cached preferred size.
gfx::Size preferred_size_;
- // Font used to display text.
- gfx::Font font_;
+ // Font list used to display text.
+ gfx::FontList font_list_;
// Height of each row. Based on font and some padding.
int row_height_;
diff --git a/chromium/ui/views/controls/tree/tree_view_unittest.cc b/chromium/ui/views/controls/tree/tree_view_unittest.cc
index 1864ff9a9bf..bf73da99ec1 100644
--- a/chromium/ui/views/controls/tree/tree_view_unittest.cc
+++ b/chromium/ui/views/controls/tree/tree_view_unittest.cc
@@ -17,6 +17,8 @@ using ui::TreeModel;
using ui::TreeModelNode;
using ui::TreeNode;
+using base::ASCIIToUTF16;
+
namespace views {
class TestNode : public TreeNode<TestNode> {
@@ -68,7 +70,7 @@ class TreeViewTest : public ViewsTestBase {
private:
std::string InternalNodeAsString(TreeView::InternalNode* node);
- TestNode* GetNodeByTitleImpl(TestNode* node, const string16& title);
+ TestNode* GetNodeByTitleImpl(TestNode* node, const base::string16& title);
DISALLOW_COPY_AND_ASSIGN(TreeViewTest);
};
@@ -88,12 +90,14 @@ std::string TreeViewTest::TreeViewContentsAsString() {
std::string TreeViewTest::GetSelectedNodeTitle() {
TreeModelNode* model_node = tree_.GetSelectedNode();
- return model_node ? UTF16ToASCII(model_node->GetTitle()) : std::string();
+ return model_node ? base::UTF16ToASCII(model_node->GetTitle())
+ : std::string();
}
std::string TreeViewTest::GetEditingNodeTitle() {
TreeModelNode* model_node = tree_.GetEditingNode();
- return model_node ? UTF16ToASCII(model_node->GetTitle()) : std::string();
+ return model_node ? base::UTF16ToASCII(model_node->GetTitle())
+ : std::string();
}
TestNode* TreeViewTest::GetNodeByTitle(const std::string& title) {
@@ -118,7 +122,7 @@ int TreeViewTest::GetRowCount() {
}
TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node,
- const string16& title) {
+ const base::string16& title) {
if (node->GetTitle() == title)
return node;
for (int i = 0; i < node->child_count(); ++i) {
@@ -131,7 +135,7 @@ TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node,
std::string TreeViewTest::InternalNodeAsString(
TreeView::InternalNode* node) {
- std::string result = UTF16ToASCII(node->model_node()->GetTitle());
+ std::string result = base::UTF16ToASCII(node->model_node()->GetTitle());
if (node->is_expanded() && node->child_count()) {
result += " [";
for (int i = 0; i < node->child_count(); ++i) {
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
index c1148c74e44..463ef7e3a05 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
@@ -57,13 +57,9 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
-#if defined(USE_AURA)
if (!event.os_event)
return;
const MSG& message(event.os_event->native_event());
-#else
- const MSG& message(event.os_event);
-#endif
DefWindowProc(message.hwnd, message.message, message.wParam, message.lParam);
}
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index 7f88f022f55..ffb5cbafbde 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -12,22 +12,18 @@
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
#include "ui/web_dialogs/web_dialog_ui.h"
-#if defined(USE_AURA)
-#include "ui/events/event.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/native_widget_aura.h"
-#endif
-
using content::NativeWebKeyboardEvent;
using content::WebContents;
using content::WebUIMessageHandler;
@@ -46,7 +42,6 @@ WebDialogView::WebDialogView(
WebContentsHandler* handler)
: ClientView(NULL, NULL),
WebDialogWebContentsDelegate(context, handler),
- initialized_(false),
delegate_(delegate),
web_view_(new views::WebView(context)),
is_attempting_close_dialog_(false),
@@ -71,14 +66,14 @@ content::WebContents* WebDialogView::web_contents() {
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, views::View implementation:
-gfx::Size WebDialogView::GetPreferredSize() {
+gfx::Size WebDialogView::GetPreferredSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetDialogSize(&out);
return out;
}
-gfx::Size WebDialogView::GetMinimumSize() {
+gfx::Size WebDialogView::GetMinimumSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetMinimumDialogSize(&out);
@@ -118,8 +113,7 @@ bool WebDialogView::CanClose() {
if (!is_attempting_close_dialog_) {
// Fire beforeunload event when user attempts to close the dialog.
is_attempting_close_dialog_ = true;
- web_view_->
- web_contents()->GetRenderViewHost()->FirePageBeforeUnload(false);
+ web_view_->web_contents()->DispatchBeforeUnload(false);
}
return false;
}
@@ -128,6 +122,8 @@ bool WebDialogView::CanClose() {
// WebDialogView, views::WidgetDelegate implementation:
bool WebDialogView::CanResize() const {
+ if (delegate_)
+ return delegate_->CanResizeDialog();
return true;
}
@@ -135,10 +131,10 @@ ui::ModalType WebDialogView::GetModalType() const {
return GetDialogModalType();
}
-string16 WebDialogView::GetWindowTitle() const {
+base::string16 WebDialogView::GetWindowTitle() const {
if (delegate_)
return delegate_->GetDialogTitle();
- return string16();
+ return base::string16();
}
std::string WebDialogView::GetWindowName() const {
@@ -188,7 +184,7 @@ ui::ModalType WebDialogView::GetDialogModalType() const {
return ui::MODAL_TYPE_NONE;
}
-string16 WebDialogView::GetDialogTitle() const {
+base::string16 WebDialogView::GetDialogTitle() const {
return GetWindowTitle();
}
@@ -282,23 +278,10 @@ void WebDialogView::MoveContents(WebContents* source, const gfx::Rect& pos) {
// they're all browser-specific. (This may change in the future.)
void WebDialogView::HandleKeyboardEvent(content::WebContents* source,
const NativeWebKeyboardEvent& event) {
-#if defined(USE_AURA)
if (!event.os_event)
return;
- ui::KeyEvent aura_event(event.os_event->native_event(), false);
- ui::EventHandler* event_handler =
- GetWidget()->native_widget()->GetEventHandler();
-
- DCHECK(event_handler);
- if (event_handler)
- event_handler->OnKeyEvent(&aura_event);
-#elif defined(OS_WIN)
- // Any unhandled keyboard/character messages should be defproced.
- // This allows stuff like F10, etc to work correctly.
- DefWindowProc(event.os_event.hwnd, event.os_event.message,
- event.os_event.wParam, event.os_event.lParam);
-#endif
+ GetWidget()->native_widget_private()->RepostNativeEvent(event.os_event);
}
void WebDialogView::CloseContents(WebContents* source) {
@@ -335,7 +318,8 @@ void WebDialogView::AddNewContents(content::WebContents* source,
was_blocked);
}
-void WebDialogView::LoadingStateChanged(content::WebContents* source) {
+void WebDialogView::LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) {
if (delegate_)
delegate_->OnLoadingStateChanged(source);
}
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index bb2eb395e52..2e69ad314ba 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -52,8 +52,8 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
content::WebContents* web_contents();
// Overridden from views::ClientView:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator)
OVERRIDE;
virtual void ViewHierarchyChanged(
@@ -63,7 +63,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Overridden from views::WidgetDelegate:
virtual bool CanResize() const OVERRIDE;
virtual ui::ModalType GetModalType() const OVERRIDE;
- virtual string16 GetWindowTitle() const OVERRIDE;
+ virtual base::string16 GetWindowTitle() const OVERRIDE;
virtual std::string GetWindowName() const OVERRIDE;
virtual void WindowClosing() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
@@ -75,7 +75,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Overridden from ui::WebDialogDelegate:
virtual ui::ModalType GetDialogModalType() const OVERRIDE;
- virtual string16 GetDialogTitle() const OVERRIDE;
+ virtual base::string16 GetDialogTitle() const OVERRIDE;
virtual GURL GetDialogContentURL() const OVERRIDE;
virtual void GetWebUIMessageHandlers(
std::vector<content::WebUIMessageHandler*>* handlers) const OVERRIDE;
@@ -110,7 +110,8 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
const gfx::Rect& initial_pos,
bool user_gesture,
bool* was_blocked) OVERRIDE;
- virtual void LoadingStateChanged(content::WebContents* source) OVERRIDE;
+ virtual void LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) OVERRIDE;
virtual void BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) OVERRIDE;
@@ -121,11 +122,6 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Initializes the contents of the dialog.
void InitDialog();
- // Whether the view is initialized. That is, dialog accelerators is registered
- // and FreezeUpdates property is set to prevent WM from showing the window
- // until the property is removed.
- bool initialized_;
-
// This view is a delegate to the HTML content since it needs to get notified
// about when the dialog is closing. For all other actions (besides dialog
// closing) we delegate to the creator of this view, which we keep track of
@@ -142,11 +138,11 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// beforeunload event.
bool before_unload_fired_;
- // Whether the dialog is closed from WebUI in response to a "DialogClose"
+ // Whether the dialog is closed from WebUI in response to a "dialogClose"
// message.
bool closed_via_webui_;
- // A json string returned to WebUI from a "DialogClosed" message.
+ // A json string returned to WebUI from a "dialogClose" message.
std::string dialog_close_retval_;
// Whether CloseContents() has been called.
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index f2ea02f48fb..21de7261231 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -10,10 +10,10 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#include "ipc/ipc_message.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -29,63 +29,51 @@ const char WebView::kViewClassName[] = "WebView";
// WebView, public:
WebView::WebView(content::BrowserContext* browser_context)
- : wcv_holder_(new NativeViewHost),
- web_contents_(NULL),
+ : holder_(new NativeViewHost()),
embed_fullscreen_widget_mode_enabled_(false),
is_embedding_fullscreen_widget_(false),
browser_context_(browser_context),
allow_accelerators_(false) {
- AddChildView(wcv_holder_);
+ AddChildView(holder_); // Takes ownership of |holder_|.
NativeViewAccessibility::RegisterWebView(this);
}
WebView::~WebView() {
+ SetWebContents(NULL); // Make sure all necessary tear-down takes place.
NativeViewAccessibility::UnregisterWebView(this);
}
content::WebContents* WebView::GetWebContents() {
- CreateWebContentsWithSiteInstance(NULL);
- return web_contents_;
-}
-
-void WebView::CreateWebContentsWithSiteInstance(
- content::SiteInstance* site_instance) {
- if (!web_contents_) {
- wc_owner_.reset(CreateWebContents(browser_context_, site_instance));
- web_contents_ = wc_owner_.get();
- web_contents_->SetDelegate(this);
- AttachWebContents();
+ if (!web_contents()) {
+ wc_owner_.reset(CreateWebContents(browser_context_));
+ wc_owner_->SetDelegate(this);
+ SetWebContents(wc_owner_.get());
}
+ return web_contents();
}
-void WebView::SetWebContents(content::WebContents* web_contents) {
- if (web_contents == web_contents_)
+void WebView::SetWebContents(content::WebContents* replacement) {
+ if (replacement == web_contents())
return;
DetachWebContents();
- if (wc_owner_ != web_contents)
+ WebContentsObserver::Observe(replacement);
+ // web_contents() now returns |replacement| from here onwards.
+ if (wc_owner_ != replacement)
wc_owner_.reset();
- web_contents_ = web_contents;
if (embed_fullscreen_widget_mode_enabled_) {
is_embedding_fullscreen_widget_ =
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
+ web_contents() && web_contents()->GetFullscreenRenderWidgetHostView();
} else {
- is_embedding_fullscreen_widget_ = false;
+ DCHECK(!is_embedding_fullscreen_widget_);
}
AttachWebContents();
+ NotifyMaybeTextInputClientChanged();
}
void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
- bool should_be_embedded = enable;
- if (!embed_fullscreen_widget_mode_enabled_ && enable) {
- DCHECK(!is_embedding_fullscreen_widget_);
- embed_fullscreen_widget_mode_enabled_ = true;
- should_be_embedded =
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
- } else if (embed_fullscreen_widget_mode_enabled_ && !enable) {
- embed_fullscreen_widget_mode_enabled_ = false;
- }
- if (should_be_embedded != is_embedding_fullscreen_widget_)
- ReattachForFullscreenChange(should_be_embedded);
+ DCHECK(!web_contents())
+ << "Cannot change mode while a WebContents is attached.";
+ embed_fullscreen_widget_mode_enabled_ = enable;
}
void WebView::LoadInitialURL(const GURL& url) {
@@ -95,7 +83,7 @@ void WebView::LoadInitialURL(const GURL& url) {
}
void WebView::SetFastResize(bool fast_resize) {
- wcv_holder_->set_fast_resize(fast_resize);
+ holder_->set_fast_resize(fast_resize);
}
void WebView::OnWebContentsFocused(content::WebContents* web_contents) {
@@ -116,8 +104,68 @@ const char* WebView::GetClassName() const {
return kViewClassName;
}
+ui::TextInputClient* WebView::GetTextInputClient() {
+ // This function delegates the text input handling to the underlying
+ // content::RenderWidgetHostView. So when the underlying RWHV is destroyed or
+ // replaced with another one, we have to notify the FocusManager through
+ // FocusManager::OnTextInputClientChanged() that the focused TextInputClient
+ // needs to be updated.
+ if (switches::IsTextInputFocusManagerEnabled() &&
+ web_contents() && !web_contents()->IsBeingDestroyed()) {
+ content::RenderWidgetHostView* host_view =
+ is_embedding_fullscreen_widget_ ?
+ web_contents()->GetFullscreenRenderWidgetHostView() :
+ web_contents()->GetRenderWidgetHostView();
+ if (host_view)
+ return host_view->GetTextInputClient();
+ }
+ return NULL;
+}
+
void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
- wcv_holder_->SetSize(bounds().size());
+ // In most cases, the holder is simply sized to fill this WebView's bounds.
+ // Only WebContentses that are in fullscreen mode and being screen-captured
+ // will engage the special layout/sizing behavior.
+ gfx::Rect holder_bounds(bounds().size());
+ if (!embed_fullscreen_widget_mode_enabled_ ||
+ !web_contents() ||
+ web_contents()->GetCapturerCount() == 0 ||
+ web_contents()->GetPreferredSize().IsEmpty() ||
+ !(is_embedding_fullscreen_widget_ ||
+ (web_contents()->GetDelegate() &&
+ web_contents()->GetDelegate()->
+ IsFullscreenForTabOrPending(web_contents())))) {
+ holder_->SetBoundsRect(holder_bounds);
+ return;
+ }
+
+ // Size the holder to the capture video resolution and center it. If this
+ // WebView is not large enough to contain the holder at the preferred size,
+ // scale down to fit (preserving aspect ratio).
+ const gfx::Size capture_size = web_contents()->GetPreferredSize();
+ if (capture_size.width() <= holder_bounds.width() &&
+ capture_size.height() <= holder_bounds.height()) {
+ // No scaling, just centering.
+ holder_bounds.ClampToCenteredSize(capture_size);
+ } else {
+ // Scale down, preserving aspect ratio, and center.
+ // TODO(miu): This is basically media::ComputeLetterboxRegion(), and it
+ // looks like others have written this code elsewhere. Let's considate
+ // into a shared function ui/gfx/geometry or around there.
+ const int64 x = static_cast<int64>(capture_size.width()) *
+ holder_bounds.height();
+ const int64 y = static_cast<int64>(capture_size.height()) *
+ holder_bounds.width();
+ if (y < x) {
+ holder_bounds.ClampToCenteredSize(gfx::Size(
+ holder_bounds.width(), static_cast<int>(y / capture_size.width())));
+ } else {
+ holder_bounds.ClampToCenteredSize(gfx::Size(
+ static_cast<int>(x / capture_size.height()), holder_bounds.height()));
+ }
+ }
+
+ holder_->SetBoundsRect(holder_bounds);
}
void WebView::ViewHierarchyChanged(
@@ -135,48 +183,48 @@ bool WebView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
// We'll first give the page a chance to process the key events. If it does
// not process them, they'll be returned to us and we'll treat them as
// accelerators then.
- return web_contents_ && !web_contents_->IsCrashed();
+ return web_contents() && !web_contents()->IsCrashed();
}
bool WebView::IsFocusable() const {
// We need to be focusable when our contents is not a view hierarchy, as
// clicking on the contents needs to focus us.
- return !!web_contents_;
+ return !!web_contents();
}
void WebView::OnFocus() {
- if (!web_contents_)
+ if (!web_contents())
return;
if (is_embedding_fullscreen_widget_) {
content::RenderWidgetHostView* const current_fs_view =
- web_contents_->GetFullscreenRenderWidgetHostView();
+ web_contents()->GetFullscreenRenderWidgetHostView();
if (current_fs_view)
current_fs_view->Focus();
} else {
- web_contents_->GetView()->Focus();
+ web_contents()->Focus();
}
}
void WebView::AboutToRequestFocusFromTabTraversal(bool reverse) {
- if (web_contents_)
- web_contents_->FocusThroughTabTraversal(reverse);
+ if (web_contents())
+ web_contents()->FocusThroughTabTraversal(reverse);
}
-void WebView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_GROUPING;
+void WebView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_GROUP;
}
gfx::NativeViewAccessible WebView::GetNativeViewAccessible() {
- if (web_contents_) {
+ if (web_contents()) {
content::RenderWidgetHostView* host_view =
- web_contents_->GetRenderWidgetHostView();
+ web_contents()->GetRenderWidgetHostView();
if (host_view)
return host_view->GetNativeViewAccessible();
}
return View::GetNativeViewAccessible();
}
-gfx::Size WebView::GetPreferredSize() {
+gfx::Size WebView::GetPreferredSize() const {
if (preferred_size_ == gfx::Size())
return View::GetPreferredSize();
else
@@ -189,7 +237,7 @@ gfx::Size WebView::GetPreferredSize() {
void WebView::WebContentsFocused(content::WebContents* web_contents) {
DCHECK(wc_owner_.get());
// The WebView is only the delegate of WebContentses it creates itself.
- OnWebContentsFocused(web_contents_);
+ OnWebContentsFocused(wc_owner_.get());
}
bool WebView::EmbedsFullscreenWidget() const {
@@ -200,19 +248,16 @@ bool WebView::EmbedsFullscreenWidget() const {
////////////////////////////////////////////////////////////////////////////////
// WebView, content::WebContentsObserver implementation:
+void WebView::RenderViewDeleted(content::RenderViewHost* render_view_host) {
+ NotifyMaybeTextInputClientChanged();
+}
+
void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
content::RenderViewHost* new_host) {
FocusManager* const focus_manager = GetFocusManager();
if (focus_manager && focus_manager->GetFocusedView() == this)
OnFocus();
-}
-
-void WebView::WebContentsDestroyed(content::WebContents* web_contents) {
- // We watch for destruction of WebContents that we host but do not own. If we
- // own a WebContents that is being destroyed, we're doing the destroying, so
- // we don't want to recursively tear it down while it's being torn down.
- if (!wc_owner_.get())
- SetWebContents(NULL);
+ NotifyMaybeTextInputClientChanged();
}
void WebView::DidShowFullscreenWidget(int routing_id) {
@@ -225,21 +270,27 @@ void WebView::DidDestroyFullscreenWidget(int routing_id) {
ReattachForFullscreenChange(false);
}
+void WebView::DidToggleFullscreenModeForTab(bool entered_fullscreen) {
+ if (embed_fullscreen_widget_mode_enabled_)
+ ReattachForFullscreenChange(entered_fullscreen);
+}
+
////////////////////////////////////////////////////////////////////////////////
// WebView, private:
void WebView::AttachWebContents() {
// Prevents attachment if the WebView isn't already in a Widget, or it's
// already attached.
- if (!GetWidget() || !web_contents_)
+ if (!GetWidget() || !web_contents())
return;
const gfx::NativeView view_to_attach = is_embedding_fullscreen_widget_ ?
- web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
- web_contents_->GetView()->GetNativeView();
- if (wcv_holder_->native_view() == view_to_attach)
+ web_contents()->GetFullscreenRenderWidgetHostView()->GetNativeView() :
+ web_contents()->GetNativeView();
+ OnBoundsChanged(bounds());
+ if (holder_->native_view() == view_to_attach)
return;
- wcv_holder_->Attach(view_to_attach);
+ holder_->Attach(view_to_attach);
// The view will not be focused automatically when it is attached, so we need
// to pass on focus to it if the FocusManager thinks the view is focused. Note
@@ -248,58 +299,61 @@ void WebView::AttachWebContents() {
if (focus_manager && focus_manager->GetFocusedView() == this)
OnFocus();
- WebContentsObserver::Observe(web_contents_);
-
-#if defined(OS_WIN) && defined(USE_AURA)
+#if defined(OS_WIN)
if (!is_embedding_fullscreen_widget_) {
- web_contents_->SetParentNativeViewAccessible(
+ web_contents()->SetParentNativeViewAccessible(
parent()->GetNativeViewAccessible());
}
#endif
}
void WebView::DetachWebContents() {
- if (web_contents_) {
- wcv_holder_->Detach();
+ if (web_contents()) {
+ holder_->Detach();
#if defined(OS_WIN)
- if (!is_embedding_fullscreen_widget_) {
-#if !defined(USE_AURA)
- // TODO(beng): This should either not be necessary, or be done implicitly
- // by NativeViewHostWin on Detach(). As it stands, this is needed so that
- // the of the detached contents knows to tell the renderer it's been
- // hidden.
- //
- // Moving this out of here would also mean we wouldn't be potentially
- // calling member functions on a half-destroyed WebContents.
- ShowWindow(web_contents_->GetView()->GetNativeView(), SW_HIDE);
-#else
- web_contents_->SetParentNativeViewAccessible(NULL);
-#endif
- }
+ if (!is_embedding_fullscreen_widget_)
+ web_contents()->SetParentNativeViewAccessible(NULL);
#endif
}
- WebContentsObserver::Observe(NULL);
}
void WebView::ReattachForFullscreenChange(bool enter_fullscreen) {
- DetachWebContents();
- is_embedding_fullscreen_widget_ = enter_fullscreen &&
- web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
- AttachWebContents();
+ DCHECK(embed_fullscreen_widget_mode_enabled_);
+ const bool web_contents_has_separate_fs_widget =
+ web_contents() && web_contents()->GetFullscreenRenderWidgetHostView();
+ if (is_embedding_fullscreen_widget_ || web_contents_has_separate_fs_widget) {
+ // Shutting down or starting up the embedding of the separate fullscreen
+ // widget. Need to detach and re-attach to a different native view.
+ DetachWebContents();
+ is_embedding_fullscreen_widget_ =
+ enter_fullscreen && web_contents_has_separate_fs_widget;
+ AttachWebContents();
+ } else {
+ // Entering or exiting "non-Flash" fullscreen mode, where the native view is
+ // the same. So, do not change attachment.
+ OnBoundsChanged(bounds());
+ }
+ NotifyMaybeTextInputClientChanged();
+}
+
+void WebView::NotifyMaybeTextInputClientChanged() {
+ // Update the TextInputClient as needed; see GetTextInputClient().
+ FocusManager* const focus_manager = GetFocusManager();
+ if (focus_manager)
+ focus_manager->OnTextInputClientChanged(this);
}
content::WebContents* WebView::CreateWebContents(
- content::BrowserContext* browser_context,
- content::SiteInstance* site_instance) {
+ content::BrowserContext* browser_context) {
content::WebContents* contents = NULL;
if (ViewsDelegate::views_delegate) {
contents = ViewsDelegate::views_delegate->CreateWebContents(
- browser_context, site_instance);
+ browser_context, NULL);
}
if (!contents) {
content::WebContents::CreateParams create_params(
- browser_context, site_instance);
+ browser_context, NULL);
return content::WebContents::Create(create_params);
}
diff --git a/chromium/ui/views/controls/webview/webview.gyp b/chromium/ui/views/controls/webview/webview.gyp
index 6d74ef2dfad..39d40201d80 100644
--- a/chromium/ui/views/controls/webview/webview.gyp
+++ b/chromium/ui/views/controls/webview/webview.gyp
@@ -17,9 +17,10 @@
'../../../../content/content.gyp:content_browser',
'../../../../skia/skia.gyp:skia',
'../../../../url/url.gyp:url_lib',
+ '../../../base/ui_base.gyp:ui_base',
'../../../events/events.gyp:events',
'../../../gfx/gfx.gyp:gfx',
- '../../../ui.gyp:ui',
+ '../../../gfx/gfx.gyp:gfx_geometry',
'../../../web_dialogs/web_dialogs.gyp:web_dialogs',
'../../views.gyp:views',
],
diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h
index ae789be2aaa..5cbb8874286 100644
--- a/chromium/ui/views/controls/webview/webview.h
+++ b/chromium/ui/views/controls/webview/webview.h
@@ -13,14 +13,24 @@
#include "ui/views/controls/webview/webview_export.h"
#include "ui/views/view.h"
-namespace content {
-class SiteInstance;
-}
-
namespace views {
class NativeViewHost;
+// Provides a view of a WebContents instance. WebView can be used standalone,
+// creating and displaying an internally-owned WebContents; or within a full
+// browser where the browser swaps its own WebContents instances in/out (e.g.,
+// for browser tabs).
+//
+// WebView creates and owns a single child view, a NativeViewHost, which will
+// hold and display the native view provided by a WebContents.
+//
+// EmbedFullscreenWidgetMode: When enabled, WebView will observe for WebContents
+// fullscreen changes and automatically swap the normal native view with the
+// fullscreen native view (if different). In addition, if the WebContents is
+// being screen-captured, the view will be centered within WebView, sized to
+// the aspect ratio of the capture video resolution, and scaling will be avoided
+// whenever possible.
class WEBVIEW_EXPORT WebView : public View,
public content::WebContentsDelegate,
public content::WebContentsObserver {
@@ -34,10 +44,6 @@ class WEBVIEW_EXPORT WebView : public View,
// WebView owns this implicitly created WebContents.
content::WebContents* GetWebContents();
- // Creates a WebContents if none is yet assocaited with this WebView, with the
- // specified site instance. The WebView owns this WebContents.
- void CreateWebContentsWithSiteInstance(content::SiteInstance* site_instance);
-
// WebView does not assume ownership of WebContents set via this method, only
// those it implicitly creates via GetWebContents() above.
void SetWebContents(content::WebContents* web_contents);
@@ -48,7 +54,9 @@ class WEBVIEW_EXPORT WebView : public View,
// widget or restore the normal WebContentsView.
void SetEmbedFullscreenWidgetMode(bool mode);
- content::WebContents* web_contents() { return web_contents_; }
+ content::WebContents* web_contents() const {
+ return content::WebContentsObserver::web_contents();
+ }
content::BrowserContext* browser_context() { return browser_context_; }
@@ -86,8 +94,9 @@ class WEBVIEW_EXPORT WebView : public View,
// Overridden from View:
virtual const char* GetClassName() const OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- private:
+ protected:
// Overridden from View:
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual void ViewHierarchyChanged(
@@ -97,44 +106,48 @@ class WEBVIEW_EXPORT WebView : public View,
virtual bool IsFocusable() const OVERRIDE;
virtual void OnFocus() OVERRIDE;
virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void WebContentsFocused(content::WebContents* web_contents) OVERRIDE;
virtual bool EmbedsFullscreenWidget() const OVERRIDE;
// Overridden from content::WebContentsObserver:
+ virtual void RenderViewDeleted(
+ content::RenderViewHost* render_view_host) OVERRIDE;
virtual void RenderViewHostChanged(
content::RenderViewHost* old_host,
content::RenderViewHost* new_host) OVERRIDE;
- virtual void WebContentsDestroyed(
- content::WebContents* web_contents) OVERRIDE;
virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE;
virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE;
+ virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen) OVERRIDE;
// Workaround for MSVC++ linker bug/feature that requires
// instantiation of the inline IPC::Listener methods in all translation units.
virtual void OnChannelConnected(int32 peer_id) OVERRIDE {}
virtual void OnChannelError() OVERRIDE {}
+ virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE {}
+ private:
void AttachWebContents();
void DetachWebContents();
void ReattachForFullscreenChange(bool enter_fullscreen);
+ void NotifyMaybeTextInputClientChanged();
// Create a regular or test web contents (based on whether we're running
// in a unit test or not).
content::WebContents* CreateWebContents(
- content::BrowserContext* browser_context,
- content::SiteInstance* site_instance);
+ content::BrowserContext* browser_context);
- NativeViewHost* wcv_holder_;
+ NativeViewHost* const holder_;
+ // Non-NULL if |web_contents()| was created and is owned by this WebView.
scoped_ptr<content::WebContents> wc_owner_;
- content::WebContents* web_contents_;
// When true, WebView auto-embeds fullscreen widgets as a child view.
bool embed_fullscreen_widget_mode_enabled_;
// Set to true while WebView is embedding a fullscreen widget view as a child
- // view instead of the normal WebContentsView render 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_;
content::BrowserContext* browser_context_;
bool allow_accelerators_;
diff --git a/chromium/ui/views/controls/webview/webview_interactive_uitest.cc b/chromium/ui/views/controls/webview/webview_interactive_uitest.cc
new file mode 100644
index 00000000000..f1179b83eab
--- /dev/null
+++ b/chromium/ui/views/controls/webview/webview_interactive_uitest.cc
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/webview/webview.h"
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/views/test/webview_test_helper.h"
+#include "ui/views/test/widget_test.h"
+
+namespace {
+
+class WebViewInteractiveUiTest : public views::test::WidgetTest {
+ public:
+ WebViewInteractiveUiTest()
+ : ui_thread_(content::BrowserThread::UI, base::MessageLoop::current()) {}
+
+ virtual void SetUp() OVERRIDE {
+ gfx::GLSurface::InitializeOneOffForTests();
+ WidgetTest::SetUp();
+ }
+
+ protected:
+ content::BrowserContext* browser_context() { return &browser_context_; }
+
+ private:
+ content::TestBrowserContext browser_context_;
+ views::WebViewTestHelper webview_test_helper_;
+ content::TestBrowserThread ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebViewInteractiveUiTest);
+};
+
+TEST_F(WebViewInteractiveUiTest, TextInputClientIsUpToDate) {
+ // WebViewInteractiveUiTest.TextInputClientIsUpToDate needs
+ // kEnableTextInputFocusManager flag to be enabled.
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ cmd_line->AppendSwitch(switches::kEnableTextInputFocusManager);
+
+ // Create a top level widget and a webview as its content.
+ views::Widget* widget = CreateTopLevelFramelessPlatformWidget();
+ views::WebView* webview = new views::WebView(browser_context());
+ widget->SetContentsView(webview);
+ widget->Show();
+ webview->RequestFocus();
+
+ ui::TextInputFocusManager* text_input_focus_manager =
+ ui::TextInputFocusManager::GetInstance();
+ const ui::TextInputClient* null_text_input_client = NULL;
+ EXPECT_EQ(null_text_input_client, webview->GetTextInputClient());
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(),
+ webview->GetTextInputClient());
+
+ // Case 1: Creates a new WebContents.
+ webview->GetWebContents();
+ webview->RequestFocus();
+ ui::TextInputClient* client1 = webview->GetTextInputClient();
+ EXPECT_NE(null_text_input_client, client1);
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(), client1);
+
+ // Case 2: Replaces a WebContents by SetWebContents().
+ content::WebContents::CreateParams params(browser_context());
+ scoped_ptr<content::WebContents> web_contents(
+ content::WebContents::Create(params));
+ webview->SetWebContents(web_contents.get());
+ ui::TextInputClient* client2 = webview->GetTextInputClient();
+ EXPECT_NE(null_text_input_client, client2);
+ EXPECT_EQ(text_input_focus_manager->GetFocusedTextInputClient(), client2);
+ EXPECT_NE(client1, client2);
+
+ widget->Close();
+ RunPendingMessages();
+}
+
+} // namespace
diff --git a/chromium/ui/views/controls/webview/webview_tests.gyp b/chromium/ui/views/controls/webview/webview_tests.gyp
new file mode 100644
index 00000000000..0adc5c2befc
--- /dev/null
+++ b/chromium/ui/views/controls/webview/webview_tests.gyp
@@ -0,0 +1,38 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'webview_test_support',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../../../base/base.gyp:base',
+ '../../../../content/content.gyp:content',
+ '../../../../content/content_shell_and_tests.gyp:test_support_content',
+ '../../../../ipc/ipc.gyp:test_support_ipc',
+ '../../../../skia/skia.gyp:skia',
+ '../../../../testing/gtest.gyp:gtest',
+ '../../../aura/aura.gyp:aura',
+ '../../../base/ui_base.gyp:ui_base',
+ '../../../events/events.gyp:events',
+ '../../../gfx/gfx.gyp:gfx',
+ '../../../gfx/gfx.gyp:gfx_geometry',
+ '../../views.gyp:views',
+ '../../views.gyp:views_test_support',
+ 'webview.gyp:webview',
+ ],
+ 'include_dirs': [
+ '../../../..',
+ ],
+ 'sources': [
+ '../../test/webview_test_helper.cc',
+ '../../test/webview_test_helper.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/ui/views/corewm/DEPS b/chromium/ui/views/corewm/DEPS
index 06abf634093..a2d52d61d09 100644
--- a/chromium/ui/views/corewm/DEPS
+++ b/chromium/ui/views/corewm/DEPS
@@ -1,4 +1,57 @@
-# This code should not depend on Views.
-
-"-ui/views",
-"+ui/views/views_export.h"
+# This code should not depend on Views.
+
+include_rules = [
+ "-ui/views",
+ "+ui/views/corewm",
+ "+ui/views/views_export.h",
+]
+
+# TODO: temporary, don't add more.
+specific_include_rules = {
+ "tooltip_controller.cc": [
+ "+ui/views/widget/tooltip_manager.h",
+ ],
+
+ "tooltip_aura.cc": [
+ "+ui/views/background.h",
+ "+ui/views/border.h",
+ "+ui/views/widget/widget.h",
+ ],
+
+ "desktop_capture_controller_unittest.cc": [
+ "+ui/views/test/views_test_base.h",
+ "+ui/views/view.h",
+ "+ui/views/widget/desktop_aura/desktop_native_widget_aura.h",
+ "+ui/views/widget/desktop_aura/desktop_screen_position_client.h",
+ "+ui/views/widget/root_view.h",
+ "+ui/views/widget/widget.h",
+ ],
+
+ "tooltip_controller_unittest.cc": [
+ "+ui/views/test/desktop_test_views_delegate.h",
+ "+ui/views/test/test_views_delegate.h",
+ "+ui/views/view.h",
+ "+ui/views/widget/desktop_aura/desktop_native_widget_aura.h",
+ "+ui/views/widget/desktop_aura/desktop_screen.h",
+ "+ui/views/widget/tooltip_manager.h",
+ "+ui/views/widget/widget.h",
+ ],
+
+ "tooltip_aura.h": [
+ "+ui/views/controls/label.h",
+ "+ui/views/widget/widget_observer.h",
+ ],
+
+ "tooltip_controller_test_helper.h": [
+ "+ui/views/view.h",
+ ],
+
+ "capture_controller_unittest.cc": [
+ "+ui/views/test/views_test_base.h",
+ "+ui/views/view.h",
+ "+ui/views/widget/desktop_aura/desktop_native_widget_aura.h",
+ "+ui/views/widget/desktop_aura/desktop_screen_position_client.h",
+ "+ui/views/widget/root_view.h",
+ "+ui/views/widget/widget.h",
+ ],
+}
diff --git a/chromium/ui/views/corewm/base_focus_rules.cc b/chromium/ui/views/corewm/base_focus_rules.cc
deleted file mode 100644
index 9520c749cd0..00000000000
--- a/chromium/ui/views/corewm/base_focus_rules.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/base_focus_rules.h"
-
-#include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/views/corewm/window_modality_controller.h"
-
-namespace views {
-namespace corewm {
-namespace {
-
-aura::Window* GetFocusedWindow(aura::Window* context) {
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(context);
- return focus_client ? focus_client->GetFocusedWindow() : NULL;
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// BaseFocusRules, protected:
-
-BaseFocusRules::BaseFocusRules() {
-}
-
-BaseFocusRules::~BaseFocusRules() {
-}
-
-bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
- aura::Window* window) const {
- return window->IsVisible();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BaseFocusRules, FocusRules implementation:
-
-bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
- // The window must in a valid hierarchy.
- if (!window->GetRootWindow())
- return false;
-
- // The window must exist within a container that supports activation.
- // The window cannot be blocked by a modal transient.
- return SupportsChildActivation(window->parent());
-}
-
-bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
- // It is possible to activate a NULL window, it is equivalent to clearing
- // activation.
- if (!window)
- return true;
-
- // Only toplevel windows can be activated.
- if (!IsToplevelWindow(window))
- return false;
-
- // The window must be visible.
- if (!IsWindowConsideredVisibleForActivation(window))
- return false;
-
- // The window's activation delegate must allow this window to be activated.
- if (aura::client::GetActivationDelegate(window) &&
- !aura::client::GetActivationDelegate(window)->ShouldActivate()) {
- return false;
- }
-
- // A window must be focusable to be activatable. We don't call
- // CanFocusWindow() from here because it will call back to us via
- // GetActivatableWindow().
- if (!window->CanFocus())
- return false;
-
- // The window cannot be blocked by a modal transient.
- return !GetModalTransient(window);
-}
-
-bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
- // It is possible to focus a NULL window, it is equivalent to clearing focus.
- if (!window)
- return true;
-
- // The focused window is always inside the active window, so windows that
- // aren't activatable can't contain the focused window.
- aura::Window* activatable = GetActivatableWindow(window);
- if (!activatable || !activatable->Contains(window))
- return false;
- return window->CanFocus();
-}
-
-aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
- aura::Window* parent = window->parent();
- aura::Window* child = window;
- while (parent) {
- if (IsToplevelWindow(child))
- return child;
-
- parent = parent->parent();
- child = child->parent();
- }
- return NULL;
-}
-
-aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
- aura::Window* parent = window->parent();
- aura::Window* child = window;
- while (parent) {
- if (CanActivateWindow(child))
- return child;
-
- // CanActivateWindow() above will return false if |child| is blocked by a
- // modal transient. In this case the modal is or contains the activatable
- // window. We recurse because the modal may itself be blocked by a modal
- // transient.
- aura::Window* modal_transient = GetModalTransient(child);
- if (modal_transient)
- return GetActivatableWindow(modal_transient);
-
- if (child->transient_parent()) {
- // To avoid infinite recursion, if |child| has a transient parent
- // whose own modal transient is |child| itself, just return |child|.
- aura::Window* parent_modal_transient =
- GetModalTransient(child->transient_parent());
- if (parent_modal_transient == child)
- return child;
-
- return GetActivatableWindow(child->transient_parent());
- }
-
- parent = parent->parent();
- child = child->parent();
- }
- return NULL;
-}
-
-aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
- if (CanFocusWindow(window))
- return window;
-
- // |window| may be in a hierarchy that is non-activatable, in which case we
- // need to cut over to the activatable hierarchy.
- aura::Window* activatable = GetActivatableWindow(window);
- if (!activatable) {
- // There may not be a related activatable hierarchy to cut over to, in which
- // case we try an unrelated one.
- aura::Window* toplevel = GetToplevelWindow(window);
- if (toplevel)
- activatable = GetNextActivatableWindow(toplevel);
- if (!activatable)
- return NULL;
- }
-
- if (!activatable->Contains(window)) {
- // If there's already a child window focused in the activatable hierarchy,
- // just use that (i.e. don't shift focus), otherwise we need to at least cut
- // over to the activatable hierarchy.
- aura::Window* focused = GetFocusedWindow(activatable);
- return activatable->Contains(focused) ? focused : activatable;
- }
-
- while (window && !CanFocusWindow(window))
- window = window->parent();
- return window;
-}
-
-aura::Window* BaseFocusRules::GetNextActivatableWindow(
- aura::Window* ignore) const {
- DCHECK(ignore);
-
- // Can be called from the RootWindow's destruction, which has a NULL parent.
- if (!ignore->parent())
- return NULL;
-
- // In the basic scenarios handled by BasicFocusRules, the pool of activatable
- // windows is limited to the |ignore|'s siblings.
- const aura::Window::Windows& siblings = ignore->parent()->children();
- DCHECK(!siblings.empty());
-
- for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
- rit != siblings.rend();
- ++rit) {
- aura::Window* cur = *rit;
- if (cur == ignore)
- continue;
- if (CanActivateWindow(cur))
- return cur;
- }
- return NULL;
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/base_focus_rules.h b/chromium/ui/views/corewm/base_focus_rules.h
deleted file mode 100644
index 4c564b0e798..00000000000
--- a/chromium/ui/views/corewm/base_focus_rules.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_BASE_FOCUS_RULES_H_
-#define UI_VIEWS_COREWM_BASE_FOCUS_RULES_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/views/corewm/focus_rules.h"
-
-namespace views {
-namespace corewm {
-
-// A set of basic focus and activation rules. Specializations should most likely
-// subclass this and call up to these methods rather than reimplementing them.
-class VIEWS_EXPORT BaseFocusRules : public FocusRules {
- protected:
- BaseFocusRules();
- virtual ~BaseFocusRules();
-
- // Returns true if the children of |window| can be activated.
- virtual bool SupportsChildActivation(aura::Window* window) const = 0;
-
- // Returns true if |window| is considered visible for activation purposes.
- virtual bool IsWindowConsideredVisibleForActivation(
- aura::Window* window) const;
-
- // Overridden from FocusRules:
- virtual bool IsToplevelWindow(aura::Window* window) const OVERRIDE;
- virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
- virtual bool CanFocusWindow(aura::Window* window) const OVERRIDE;
- virtual aura::Window* GetToplevelWindow(aura::Window* window) const OVERRIDE;
- virtual aura::Window* GetActivatableWindow(
- aura::Window* window) const OVERRIDE;
- virtual aura::Window* GetFocusableWindow(aura::Window* window) const OVERRIDE;
- virtual aura::Window* GetNextActivatableWindow(
- aura::Window* ignore) const OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BaseFocusRules);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_BASE_FOCUS_RULES_H_
diff --git a/chromium/ui/views/corewm/capture_controller.cc b/chromium/ui/views/corewm/capture_controller.cc
deleted file mode 100644
index 9a65e381da1..00000000000
--- a/chromium/ui/views/corewm/capture_controller.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/capture_controller.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-
-namespace views {
-namespace corewm {
-
-////////////////////////////////////////////////////////////////////////////////
-// CaptureController, public:
-
-void CaptureController::Attach(aura::Window* root) {
- DCHECK_EQ(0u, root_windows_.count(root));
- root_windows_.insert(root);
- aura::client::SetCaptureClient(root, this);
-}
-
-void CaptureController::Detach(aura::Window* root) {
- root_windows_.erase(root);
- aura::client::SetCaptureClient(root, NULL);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CaptureController, aura::client::CaptureClient implementation:
-
-void CaptureController::SetCapture(aura::Window* new_capture_window) {
- if (capture_window_ == new_capture_window)
- return;
-
- // Make sure window has a root window.
- DCHECK(!new_capture_window || new_capture_window->GetRootWindow());
- DCHECK(!capture_window_ || capture_window_->GetRootWindow());
-
- aura::Window* old_capture_window = capture_window_;
- aura::Window* old_capture_root = old_capture_window ?
- old_capture_window->GetRootWindow() : NULL;
-
- // Copy the list in case it's modified out from under us.
- RootWindows root_windows(root_windows_);
-
- // If we're actually starting capture, then cancel any touches/gestures
- // that aren't already locked to the new window, and transfer any on the
- // old capture window to the new one. When capture is released we have no
- // distinction between the touches/gestures that were in the window all
- // along (and so shouldn't be canceled) and those that got moved, so
- // just leave them all where they are.
- if (new_capture_window) {
- ui::GestureRecognizer::Get()->TransferEventsTo(old_capture_window,
- new_capture_window);
- }
-
- capture_window_ = new_capture_window;
-
- for (RootWindows::const_iterator i = root_windows.begin();
- i != root_windows.end(); ++i) {
- aura::client::CaptureDelegate* delegate = (*i)->GetDispatcher();
- delegate->UpdateCapture(old_capture_window, new_capture_window);
- }
-
- aura::Window* capture_root =
- capture_window_ ? capture_window_->GetRootWindow() : NULL;
- if (capture_root != old_capture_root) {
- if (old_capture_root) {
- aura::client::CaptureDelegate* delegate =
- old_capture_root->GetDispatcher();
- delegate->ReleaseNativeCapture();
- }
- if (capture_root) {
- aura::client::CaptureDelegate* delegate = capture_root->GetDispatcher();
- delegate->SetNativeCapture();
- }
- }
-}
-
-void CaptureController::ReleaseCapture(aura::Window* window) {
- if (capture_window_ != window)
- return;
- SetCapture(NULL);
-}
-
-aura::Window* CaptureController::GetCaptureWindow() {
- return capture_window_;
-}
-
-aura::Window* CaptureController::GetGlobalCaptureWindow() {
- return capture_window_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CaptureController, private:
-
-CaptureController::CaptureController()
- : capture_window_(NULL) {
-}
-
-CaptureController::~CaptureController() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ScopedCaptureClient:
-
-// static
-CaptureController* ScopedCaptureClient::capture_controller_ = NULL;
-
-ScopedCaptureClient::ScopedCaptureClient(aura::Window* root)
- : root_window_(root) {
- root->AddObserver(this);
- if (!capture_controller_)
- capture_controller_ = new CaptureController;
- capture_controller_->Attach(root);
-}
-
-ScopedCaptureClient::~ScopedCaptureClient() {
- Shutdown();
-}
-
-// static
-bool ScopedCaptureClient::IsActive() {
- return capture_controller_ && capture_controller_->is_active();
-}
-
-void ScopedCaptureClient::OnWindowDestroyed(aura::Window* window) {
- DCHECK_EQ(window, root_window_);
- Shutdown();
-}
-
-void ScopedCaptureClient::Shutdown() {
- if (!root_window_)
- return;
-
- root_window_->RemoveObserver(this);
- capture_controller_->Detach(root_window_);
- if (!capture_controller_->is_active()) {
- delete capture_controller_;
- capture_controller_ = NULL;
- }
- root_window_ = NULL;
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/capture_controller.h b/chromium/ui/views/corewm/capture_controller.h
deleted file mode 100644
index e7d1ffd6eca..00000000000
--- a/chromium/ui/views/corewm/capture_controller.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
-#define UI_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/window_observer.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-
-// Internal CaptureClient implementation. See ScopedCaptureClient for details.
-class VIEWS_EXPORT CaptureController : public aura::client::CaptureClient {
- public:
- // Adds |root| to the list of RootWindows notified when capture changes.
- void Attach(aura::Window* root);
-
- // Removes |root| from the list of RootWindows notified when capture changes.
- void Detach(aura::Window* root);
-
- // Returns true if this CaptureController is installed on at least one
- // RootWindow.
- bool is_active() const { return !root_windows_.empty(); }
-
- // Overridden from aura::client::CaptureClient:
- virtual void SetCapture(aura::Window* window) OVERRIDE;
- virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
- virtual aura::Window* GetCaptureWindow() OVERRIDE;
- virtual aura::Window* GetGlobalCaptureWindow() OVERRIDE;
-
- private:
- friend class ScopedCaptureClient;
- typedef std::set<aura::Window*> RootWindows;
-
- CaptureController();
- virtual ~CaptureController();
-
- // The current capture window. NULL if there is no capture window.
- aura::Window* capture_window_;
-
- // Set of RootWindows notified when capture changes.
- RootWindows root_windows_;
-
- DISALLOW_COPY_AND_ASSIGN(CaptureController);
-};
-
-// ScopedCaptureClient is responsible for creating a CaptureClient for a
-// RootWindow. Specifically it creates a single CaptureController that is shared
-// among all ScopedCaptureClients and adds the RootWindow to it.
-class VIEWS_EXPORT ScopedCaptureClient : public aura::WindowObserver {
- public:
- explicit ScopedCaptureClient(aura::Window* root);
- virtual ~ScopedCaptureClient();
-
- // Returns true if there is a CaptureController with at least one RootWindow.
- static bool IsActive();
-
- aura::client::CaptureClient* capture_client() {
- return capture_controller_;
- }
-
- // Overridden from aura::WindowObserver:
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
-
- private:
- // Invoked from destructor and OnWindowDestroyed() to cleanup.
- void Shutdown();
-
- // The single CaptureController instance.
- static CaptureController* capture_controller_;
-
- // RootWindow this ScopedCaptureClient was create for.
- aura::Window* root_window_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCaptureClient);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
diff --git a/chromium/ui/views/corewm/capture_controller_unittest.cc b/chromium/ui/views/corewm/capture_controller_unittest.cc
index 558a4030f51..ffece4a89ab 100644
--- a/chromium/ui/views/corewm/capture_controller_unittest.cc
+++ b/chromium/ui/views/corewm/capture_controller_unittest.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/corewm/capture_controller.h"
+#include "ui/wm/core/capture_controller.h"
#include "base/logging.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/views/test/views_test_base.h"
@@ -32,25 +32,21 @@ class CaptureControllerTest : public aura::test::AuraTestBase {
virtual void SetUp() OVERRIDE {
AuraTestBase::SetUp();
- capture_controller_.reset(new corewm::ScopedCaptureClient(root_window()));
+ capture_controller_.reset(new wm::ScopedCaptureClient(root_window()));
- second_root_.reset(new aura::RootWindow(
- aura::RootWindow::CreateParams(gfx::Rect(0, 0, 800, 600))));
- second_root_->Init();
- second_root_->window()->Show();
- second_root_->SetHostSize(gfx::Size(800, 600));
+ second_host_.reset(aura::WindowTreeHost::Create(gfx::Rect(0, 0, 800, 600)));
+ second_host_->InitHost();
+ second_host_->window()->Show();
+ second_host_->SetBounds(gfx::Rect(800, 600));
second_capture_controller_.reset(
- new corewm::ScopedCaptureClient(second_root_->window()));
+ new wm::ScopedCaptureClient(second_host_->window()));
#if !defined(OS_CHROMEOS)
- desktop_position_client_.reset(new DesktopScreenPositionClient());
- aura::client::SetScreenPositionClient(root_window(),
- desktop_position_client_.get());
-
- second_desktop_position_client_.reset(new DesktopScreenPositionClient());
- aura::client::SetScreenPositionClient(
- second_root_->window(),
- second_desktop_position_client_.get());
+ desktop_position_client_.reset(
+ new DesktopScreenPositionClient(root_window()));
+
+ second_desktop_position_client_.reset(
+ new DesktopScreenPositionClient(second_host_->window()));
#endif
}
@@ -63,7 +59,7 @@ class CaptureControllerTest : public aura::test::AuraTestBase {
second_capture_controller_.reset();
// Kill any active compositors before we hit the compositor shutdown paths.
- second_root_.reset();
+ second_host_.reset();
#if !defined(OS_CHROMEOS)
desktop_position_client_.reset();
@@ -81,9 +77,9 @@ class CaptureControllerTest : public aura::test::AuraTestBase {
return second_capture_controller_->capture_client()->GetCaptureWindow();
}
- scoped_ptr<corewm::ScopedCaptureClient> capture_controller_;
- scoped_ptr<aura::RootWindow> second_root_;
- scoped_ptr<corewm::ScopedCaptureClient> second_capture_controller_;
+ scoped_ptr<wm::ScopedCaptureClient> capture_controller_;
+ scoped_ptr<aura::WindowTreeHost> second_host_;
+ scoped_ptr<wm::ScopedCaptureClient> second_capture_controller_;
#if !defined(OS_CHROMEOS)
scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client_;
scoped_ptr<aura::client::ScreenPositionClient>
@@ -96,50 +92,50 @@ class CaptureControllerTest : public aura::test::AuraTestBase {
// Makes sure that internal details that are set on mouse down (such as
// mouse_pressed_handler()) are cleared when another root window takes capture.
TEST_F(CaptureControllerTest, ResetMouseEventHandlerOnCapture) {
- // Create a window inside the RootWindow.
+ // Create a window inside the WindowEventDispatcher.
scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
- // Make a synthesized mouse down event. Ensure that the RootWindow will
- // dispatch further mouse events to |w1|.
+ // Make a synthesized mouse down event. Ensure that the WindowEventDispatcher
+ // will dispatch further mouse events to |w1|.
ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5),
- gfx::Point(5, 5), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(
- &mouse_pressed_event);
- EXPECT_EQ(w1.get(), dispatcher()->mouse_pressed_handler());
+ gfx::Point(5, 5), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
+ EXPECT_EQ(w1.get(), host()->dispatcher()->mouse_pressed_handler());
- // Build a window in the second RootWindow.
+ // Build a window in the second WindowEventDispatcher.
scoped_ptr<aura::Window> w2(
- CreateNormalWindow(2, second_root_->window(), NULL));
+ CreateNormalWindow(2, second_host_->window(), NULL));
// The act of having the second window take capture should clear out mouse
- // pressed handler in the first RootWindow.
+ // pressed handler in the first WindowEventDispatcher.
w2->SetCapture();
- EXPECT_EQ(NULL, dispatcher()->mouse_pressed_handler());
+ EXPECT_EQ(NULL, host()->dispatcher()->mouse_pressed_handler());
}
// Makes sure that when one window gets capture, it forces the release on the
// other. This is needed has to be handled explicitly on Linux, and is a sanity
// check on Windows.
TEST_F(CaptureControllerTest, ResetOtherWindowCaptureOnCapture) {
- // Create a window inside the RootWindow.
+ // Create a window inside the WindowEventDispatcher.
scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
w1->SetCapture();
// Both capture clients should return the same capture window.
EXPECT_EQ(w1.get(), GetCaptureWindow());
EXPECT_EQ(w1.get(), GetSecondCaptureWindow());
- // Build a window in the second RootWindow and give it capture. Both capture
- // clients should return the same capture window.
+ // Build a window in the second WindowEventDispatcher and give it capture.
+ // Both capture clients should return the same capture window.
scoped_ptr<aura::Window> w2(
- CreateNormalWindow(2, second_root_->window(), NULL));
+ CreateNormalWindow(2, second_host_->window(), NULL));
w2->SetCapture();
EXPECT_EQ(w2.get(), GetCaptureWindow());
EXPECT_EQ(w2.get(), GetSecondCaptureWindow());
}
-// Verifies the touch target for the RootWindow gets reset on releasing capture.
+// Verifies the touch target for the WindowEventDispatcher gets reset on
+// releasing capture.
TEST_F(CaptureControllerTest, TouchTargetResetOnCaptureChange) {
- // Create a window inside the RootWindow.
+ // Create a window inside the WindowEventDispatcher.
scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
aura::test::EventGenerator event_generator1(root_window());
event_generator1.PressTouch();
@@ -148,17 +144,17 @@ TEST_F(CaptureControllerTest, TouchTargetResetOnCaptureChange) {
EXPECT_EQ(w1.get(), GetCaptureWindow());
EXPECT_EQ(w1.get(), GetSecondCaptureWindow());
- // Build a window in the second RootWindow and give it capture. Both capture
- // clients should return the same capture window.
+ // Build a window in the second WindowEventDispatcher and give it capture.
+ // Both capture clients should return the same capture window.
scoped_ptr<aura::Window> w2(
- CreateNormalWindow(2, second_root_->window(), NULL));
+ CreateNormalWindow(2, second_host_->window(), NULL));
w2->SetCapture();
EXPECT_EQ(w2.get(), GetCaptureWindow());
EXPECT_EQ(w2.get(), GetSecondCaptureWindow());
// Release capture on the window. Releasing capture should reset the touch
- // target of the first RootWindow (as it no longer contains the capture
- // target).
+ // target of the first WindowEventDispatcher (as it no longer contains the
+ // capture target).
w2->ReleaseCapture();
EXPECT_EQ(static_cast<aura::Window*>(NULL), GetCaptureWindow());
EXPECT_EQ(static_cast<aura::Window*>(NULL), GetSecondCaptureWindow());
diff --git a/chromium/ui/views/corewm/compound_event_filter.cc b/chromium/ui/views/corewm/compound_event_filter.cc
deleted file mode 100644
index efeca5cad2a..00000000000
--- a/chromium/ui/views/corewm/compound_event_filter.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/compound_event_filter.h"
-
-#include "base/containers/hash_tables.h"
-#include "base/logging.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/aura/window_tracker.h"
-#include "ui/base/hit_test.h"
-#include "ui/events/event.h"
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) {
-#if defined(OS_CHROMEOS)
- // All alt and control key commands are ignored.
- if (event.IsAltDown() || event.IsControlDown())
- return false;
-
- static bool inited = false;
- static base::hash_set<int32> ignored_keys;
- if (!inited) {
- // Modifiers.
- ignored_keys.insert(ui::VKEY_SHIFT);
- ignored_keys.insert(ui::VKEY_CONTROL);
- ignored_keys.insert(ui::VKEY_MENU);
-
- // Search key == VKEY_LWIN.
- ignored_keys.insert(ui::VKEY_LWIN);
-
- // Function keys.
- for (int key = ui::VKEY_F1; key <= ui::VKEY_F24; ++key)
- ignored_keys.insert(key);
-
- // Media keys.
- for (int key = ui::VKEY_BROWSER_BACK; key <= ui::VKEY_MEDIA_LAUNCH_APP2;
- ++key) {
- ignored_keys.insert(key);
- }
-
-#if defined(OS_POSIX)
- ignored_keys.insert(ui::VKEY_WLAN);
- ignored_keys.insert(ui::VKEY_POWER);
- ignored_keys.insert(ui::VKEY_BRIGHTNESS_DOWN);
- ignored_keys.insert(ui::VKEY_BRIGHTNESS_UP);
- ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_DOWN);
- ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_UP);
-#endif
-
- inited = true;
- }
-
- if (ignored_keys.count(event.key_code()) > 0)
- return false;
-
- return true;
-#else // !defined(OS_CHROMEOS)
- return false;
-#endif // defined(OS_CHROMEOS)
-}
-
-// Returns true if the cursor should be hidden on touch events.
-bool ShouldHideCursorOnTouch() {
-#if defined(OS_CHROMEOS)
- return true;
-#else
- // Not necessary on windows as windows does it for us. If we do need this
- // funcionality on linux (non-chromeos) we need to make sure
- // CompoundEventFilter shows on the right root (it currently doesn't always).
- return false;
-#endif
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// CompoundEventFilter, public:
-
-CompoundEventFilter::CompoundEventFilter() {
-}
-
-CompoundEventFilter::~CompoundEventFilter() {
- // Additional filters are not owned by CompoundEventFilter and they
- // should all be removed when running here. |handlers_| has
- // check_empty == true and will DCHECK failure if it is not empty.
-}
-
-// static
-gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
- int window_component) {
- switch (window_component) {
- case HTBOTTOM:
- return ui::kCursorSouthResize;
- case HTBOTTOMLEFT:
- return ui::kCursorSouthWestResize;
- case HTBOTTOMRIGHT:
- return ui::kCursorSouthEastResize;
- case HTLEFT:
- return ui::kCursorWestResize;
- case HTRIGHT:
- return ui::kCursorEastResize;
- case HTTOP:
- return ui::kCursorNorthResize;
- case HTTOPLEFT:
- return ui::kCursorNorthWestResize;
- case HTTOPRIGHT:
- return ui::kCursorNorthEastResize;
- default:
- return ui::kCursorNull;
- }
-}
-
-void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
- handlers_.AddObserver(handler);
-}
-
-void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
- handlers_.RemoveObserver(handler);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CompoundEventFilter, private:
-
-void CompoundEventFilter::UpdateCursor(aura::Window* target,
- ui::MouseEvent* event) {
- // If drag and drop is in progress, let the drag drop client set the cursor
- // instead of setting the cursor here.
- aura::Window* root_window = target->GetRootWindow();
- aura::client::DragDropClient* drag_drop_client =
- aura::client::GetDragDropClient(root_window);
- if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
- return;
-
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root_window);
- if (cursor_client) {
- gfx::NativeCursor cursor = target->GetCursor(event->location());
- if (event->flags() & ui::EF_IS_NON_CLIENT) {
- int window_component =
- target->delegate()->GetNonClientComponent(event->location());
- cursor = CursorForWindowComponent(window_component);
- }
-
- cursor_client->SetCursor(cursor);
- }
-}
-
-void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
- if (handlers_.might_have_observers()) {
- ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
- ui::EventHandler* handler;
- while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
- handler->OnKeyEvent(event);
- }
-}
-
-void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
- if (handlers_.might_have_observers()) {
- ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
- ui::EventHandler* handler;
- while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
- handler->OnMouseEvent(event);
- }
-}
-
-void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
- if (handlers_.might_have_observers()) {
- ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
- ui::EventHandler* handler;
- while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
- handler->OnTouchEvent(event);
- }
-}
-
-void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
- ui::Event* event,
- bool show) {
- if (event->flags() & ui::EF_IS_SYNTHESIZED)
- return;
-
- aura::client::CursorClient* client =
- aura::client::GetCursorClient(target->GetRootWindow());
- if (!client)
- return;
-
- if (show)
- client->ShowCursor();
- else
- client->HideCursor();
-}
-
-void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
- ui::Event* event,
- bool enable) {
- if (event->flags() & ui::EF_IS_SYNTHESIZED)
- return;
- aura::client::CursorClient* client =
- aura::client::GetCursorClient(target->GetRootWindow());
- if (!client)
- return;
-
- if (enable)
- client->EnableMouseEvents();
- else
- client->DisableMouseEvents();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CompoundEventFilter, ui::EventHandler implementation:
-
-void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
- if (ShouldHideCursorOnKeyEvent(*event)) {
- SetCursorVisibilityOnEvent(
- static_cast<aura::Window*>(event->target()), event, false);
- }
-
- FilterKeyEvent(event);
-}
-
-void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
- aura::Window* window = static_cast<aura::Window*>(event->target());
- aura::WindowTracker window_tracker;
- window_tracker.Add(window);
-
- // We must always update the cursor, otherwise the cursor can get stuck if an
- // event filter registered with us consumes the event.
- // It should also update the cursor for clicking and wheels for ChromeOS boot.
- // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
- // operation will show the cursor.
- // We also update the cursor for mouse enter in case a mouse cursor is sent to
- // outside of the root window and moved back for some reasons (e.g. running on
- // on Desktop for testing, or a bug in pointer barrier).
- if (event->type() == ui::ET_MOUSE_ENTERED ||
- event->type() == ui::ET_MOUSE_MOVED ||
- event->type() == ui::ET_MOUSE_PRESSED ||
- event->type() == ui::ET_MOUSEWHEEL) {
- SetMouseEventsEnableStateOnEvent(window, event, true);
- SetCursorVisibilityOnEvent(window, event, true);
- UpdateCursor(window, event);
- }
-
- FilterMouseEvent(event);
-}
-
-void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
-}
-
-void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
- FilterTouchEvent(event);
- if (ShouldHideCursorOnTouch() && !event->handled() &&
- event->type() == ui::ET_TOUCH_PRESSED &&
- !aura::Env::GetInstance()->IsMouseButtonDown()) {
- SetMouseEventsEnableStateOnEvent(
- static_cast<aura::Window*>(event->target()), event, false);
- }
-}
-
-void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
- if (handlers_.might_have_observers()) {
- ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
- ui::EventHandler* handler;
- while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
- handler->OnGestureEvent(event);
- }
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/compound_event_filter.h b/chromium/ui/views/corewm/compound_event_filter.h
deleted file mode 100644
index 7f724c35e06..00000000000
--- a/chromium/ui/views/corewm/compound_event_filter.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_COMPOUND_EVENT_FILTER_H_
-#define UI_VIEWS_COREWM_COMPOUND_EVENT_FILTER_H_
-
-#include "base/compiler_specific.h"
-#include "base/observer_list.h"
-#include "ui/events/event.h"
-#include "ui/events/event_handler.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace aura {
-class CursorManager;
-class RootWindow;
-}
-
-namespace ui {
-class GestureEvent;
-class KeyEvent;
-class LocatedEvent;
-class MouseEvent;
-class TouchEvent;
-}
-
-namespace views {
-namespace corewm {
-
-// CompoundEventFilter gets all events first and can provide actions to those
-// events. It implements global features such as click to activate a window and
-// cursor change when moving mouse.
-// Additional event filters can be added to CompoundEventFilter. Events will
-// pass through those additional filters in their addition order and could be
-// consumed by any of those filters. If an event is consumed by a filter, the
-// rest of the filter(s) and CompoundEventFilter will not see the consumed
-// event.
-class VIEWS_EXPORT CompoundEventFilter : public ui::EventHandler {
- public:
- CompoundEventFilter();
- virtual ~CompoundEventFilter();
-
- // Returns the cursor for the specified component.
- static gfx::NativeCursor CursorForWindowComponent(int window_component);
-
- // Adds/removes additional event filters. This does not take ownership of
- // the EventHandler.
- // NOTE: These handlers are deprecated. Use env::AddPreTargetEventHandler etc.
- // instead.
- void AddHandler(ui::EventHandler* filter);
- void RemoveHandler(ui::EventHandler* filter);
-
- private:
- // Updates the cursor if the target provides a custom one, and provides
- // default resize cursors for window edges.
- void UpdateCursor(aura::Window* target, ui::MouseEvent* event);
-
- // Dispatches event to additional filters.
- void FilterKeyEvent(ui::KeyEvent* event);
- void FilterMouseEvent(ui::MouseEvent* event);
- void FilterTouchEvent(ui::TouchEvent* event);
-
- // Sets the visibility of the cursor if the event is not synthesized.
- void SetCursorVisibilityOnEvent(aura::Window* target,
- ui::Event* event,
- bool show);
-
- // Enables or disables mouse events if the event is not synthesized.
- void SetMouseEventsEnableStateOnEvent(aura::Window* target,
- ui::Event* event,
- bool enable);
-
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
- // Additional pre-target event handlers.
- ObserverList<ui::EventHandler, true> handlers_;
-
- // True if the cursur was hidden by the filter.
- bool cursor_hidden_by_filter_;
-
- DISALLOW_COPY_AND_ASSIGN(CompoundEventFilter);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_COMPOUND_EVENT_FILTER_H_
diff --git a/chromium/ui/views/corewm/compound_event_filter_unittest.cc b/chromium/ui/views/corewm/compound_event_filter_unittest.cc
deleted file mode 100644
index 6b852e4cd55..00000000000
--- a/chromium/ui/views/corewm/compound_event_filter_unittest.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/compound_event_filter.h"
-
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/test/test_cursor_client.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-
-namespace {
-
-#if defined(OS_CHROMEOS)
-base::TimeDelta GetTime() {
- return ui::EventTimeForNow();
-}
-#endif // defined(OS_CHROMEOS)
-
-}
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-// An event filter that consumes all gesture events.
-class ConsumeGestureEventFilter : public ui::EventHandler {
- public:
- ConsumeGestureEventFilter() {}
- virtual ~ConsumeGestureEventFilter() {}
-
- private:
- // Overridden from ui::EventHandler:
- virtual void OnGestureEvent(ui::GestureEvent* e) OVERRIDE {
- e->StopPropagation();
- }
-
- DISALLOW_COPY_AND_ASSIGN(ConsumeGestureEventFilter);
-};
-
-} // namespace
-
-typedef aura::test::AuraTestBase CompoundEventFilterTest;
-
-#if defined(OS_CHROMEOS)
-// A keypress only hides the cursor on ChromeOS (crbug.com/304296).
-TEST_F(CompoundEventFilterTest, CursorVisibilityChange) {
- scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
- aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
- aura::test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
- gfx::Rect(5, 5, 100, 100), root_window()));
- window->Show();
- window->SetCapture();
-
- aura::test::TestCursorClient cursor_client(root_window());
-
- // Send key event to hide the cursor.
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
- dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(&key);
- EXPECT_FALSE(cursor_client.IsCursorVisible());
-
- // Synthesized mouse event should not show the cursor.
- ui::MouseEvent enter(ui::ET_MOUSE_ENTERED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- enter.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&enter);
- EXPECT_FALSE(cursor_client.IsCursorVisible());
-
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- move.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&move);
- EXPECT_FALSE(cursor_client.IsCursorVisible());
-
- ui::MouseEvent real_move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&real_move);
- EXPECT_TRUE(cursor_client.IsCursorVisible());
-
- // Send key event to hide the cursor again.
- dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(&key);
- EXPECT_FALSE(cursor_client.IsCursorVisible());
-
- // Mouse synthesized exit event should not show the cursor.
- ui::MouseEvent exit(ui::ET_MOUSE_EXITED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- exit.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&exit);
- EXPECT_FALSE(cursor_client.IsCursorVisible());
-}
-
-TEST_F(CompoundEventFilterTest, TouchHidesCursor) {
- scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
- aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
- aura::test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
- gfx::Rect(5, 5, 100, 100), root_window()));
- window->Show();
- window->SetCapture();
-
- aura::test::TestCursorClient cursor_client(root_window());
-
- ui::MouseEvent mouse0(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse0);
- EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
-
- // This press is required for the GestureRecognizer to associate a target
- // with kTouchId
- ui::TouchEvent press0(
- ui::ET_TOUCH_PRESSED, gfx::Point(90, 90), 1, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press0);
- EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
-
- ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 1, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move);
- EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
-
- ui::TouchEvent release(
- ui::ET_TOUCH_RELEASED, gfx::Point(10, 10), 1, GetTime());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
- EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
-
- ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
- gfx::Point(10, 10), 0);
- // Move the cursor again. The cursor should be visible.
- dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse1);
- EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
-
- // Now activate the window and press on it again.
- ui::TouchEvent press1(
- ui::ET_TOUCH_PRESSED, gfx::Point(90, 90), 1, GetTime());
- aura::client::GetActivationClient(
- root_window())->ActivateWindow(window.get());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1);
- EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
- aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
-}
-#endif // defined(OS_CHROMEOS)
-
-// Tests that if an event filter consumes a gesture, then it doesn't focus the
-// window.
-TEST_F(CompoundEventFilterTest, FilterConsumedGesture) {
- scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
- scoped_ptr<ui::EventHandler> gesure_handler(new ConsumeGestureEventFilter);
- compound_filter->AddHandler(gesure_handler.get());
- aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
- aura::test::TestWindowDelegate delegate;
- DCHECK(root_window());
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
- gfx::Rect(5, 5, 100, 100), root_window()));
- window->Show();
-
- EXPECT_TRUE(window->CanFocus());
- EXPECT_FALSE(window->HasFocus());
-
- // Tap on the window should not focus it since the filter will be consuming
- // the gestures.
- aura::test::EventGenerator generator(root_window(), gfx::Point(50, 50));
- generator.PressTouch();
- EXPECT_FALSE(window->HasFocus());
-
- compound_filter->RemoveHandler(gesure_handler.get());
- aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
-}
-
-// Verifies we don't attempt to hide the mouse when the mouse is down and a
-// touch event comes in.
-TEST_F(CompoundEventFilterTest, DontHideWhenMouseDown) {
- aura::test::EventGenerator event_generator(root_window());
-
- scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
- aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
- aura::test::TestWindowDelegate delegate;
- scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
- gfx::Rect(5, 5, 100, 100), root_window()));
- window->Show();
-
- aura::test::TestCursorClient cursor_client(root_window());
-
- // Move and press the mouse over the window.
- event_generator.MoveMouseTo(10, 10);
- EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
- event_generator.PressLeftButton();
- EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
- EXPECT_TRUE(aura::Env::GetInstance()->IsMouseButtonDown());
-
- // Do a touch event. As the mouse button is down this should not disable mouse
- // events.
- event_generator.PressTouch();
- EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
- aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/corewm_switches.cc b/chromium/ui/views/corewm/corewm_switches.cc
deleted file mode 100644
index 8f0dd82a6a9..00000000000
--- a/chromium/ui/views/corewm/corewm_switches.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/corewm_switches.h"
-
-#include "base/command_line.h"
-
-namespace views {
-namespace corewm {
-namespace switches {
-
-const char kNoDropShadows[] = "aura-no-shadows";
-
-// If present animations are disabled.
-const char kWindowAnimationsDisabled[] =
- "views-corewm-window-animations-disabled";
-
-} // namespace switches
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/corewm_switches.h b/chromium/ui/views/corewm/corewm_switches.h
deleted file mode 100644
index 63c5251745d..00000000000
--- a/chromium/ui/views/corewm/corewm_switches.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_COREWM_SWITCHES_H_
-#define UI_VIEWS_COREWM_COREWM_SWITCHES_H_
-
-#include "build/build_config.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-namespace switches {
-
-// Note: If you add a switch, consider if it needs to be copied to a subsequent
-// command line if the process executes a new copy of itself. (For example,
-// see chromeos::LoginUtil::GetOffTheRecordCommandLine().)
-
-// Please keep alphabetized.
-VIEWS_EXPORT extern const char kNoDropShadows[];
-VIEWS_EXPORT extern const char kWindowAnimationsDisabled[];
-
-} // namespace switches
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_COREWM_SWITCHES_H_
diff --git a/chromium/ui/views/corewm/cursor_height_provider_win.cc b/chromium/ui/views/corewm/cursor_height_provider_win.cc
new file mode 100644
index 00000000000..97ed7a3465e
--- /dev/null
+++ b/chromium/ui/views/corewm/cursor_height_provider_win.cc
@@ -0,0 +1,146 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/corewm/cursor_height_provider_win.h"
+
+#include <windows.h>
+#include <algorithm>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_hdc.h"
+
+namespace {
+typedef scoped_ptr<uint32_t> PixelData;
+typedef std::map<HCURSOR, int> HeightStorage;
+
+const uint32_t kBitsPeruint32 = sizeof(uint32_t) * 8;
+// All bits are 1 for transparent portion of monochromatic mask.
+const uint32_t kTransparentMask = 0xffffffff;
+// This is height of default pointer arrow in Windows 7.
+const int kDefaultHeight = 20;
+// Masks are monochromatic.
+const size_t kNumberOfColors = 2;
+const size_t KHeaderAndPalette =
+ sizeof(BITMAPINFOHEADER) + kNumberOfColors * sizeof(RGBQUAD);
+
+static HeightStorage* cached_heights = NULL;
+
+// Extracts the pixel data of provided bitmap
+PixelData GetBitmapData(HBITMAP handle, const BITMAPINFO& info, HDC hdc) {
+ PixelData data;
+ // Masks are monochromatic.
+ DCHECK_EQ(info.bmiHeader.biBitCount, 1);
+ if (info.bmiHeader.biBitCount != 1)
+ return data.Pass();
+
+ // When getting pixel data palette is appended to memory pointed by
+ // BITMAPINFO passed so allocate additional memory to store additional data.
+ scoped_ptr<BITMAPINFO> header(
+ reinterpret_cast<BITMAPINFO*>(new char[KHeaderAndPalette]));
+ memcpy(header.get(), &(info.bmiHeader), sizeof(info.bmiHeader));
+
+ data.reset(new uint32_t[info.bmiHeader.biSizeImage / sizeof(uint32_t)]);
+
+ int result = GetDIBits(hdc,
+ handle,
+ 0,
+ info.bmiHeader.biHeight,
+ data.get(),
+ header.get(),
+ DIB_RGB_COLORS);
+
+ if (result == 0)
+ data.reset();
+
+ return data.Pass();
+}
+
+// Checks if the specifed row is transparent in provided bitmap.
+bool IsRowTransparent(const PixelData& data,
+ const uint32_t row_size,
+ const uint32_t last_byte_mask,
+ const uint32_t y) {
+ // Set the padding bits to 1 to make mask matching easier.
+ *(data.get() + (y + 1) * row_size - 1) |= last_byte_mask;
+ for (uint32_t i = y * row_size; i < (y + 1) * row_size; ++i) {
+ if (*(data.get() + i) != kTransparentMask)
+ return false;
+ }
+ return true;
+}
+
+// Gets the vertical offset between specified cursor's hotpoint and it's bottom.
+//
+// Gets the cursor image data and extract cursor's visible height.
+// Based on that get's what should be the vertical offset between cursor's
+// hot point and the tooltip.
+int CalculateCursorHeight(HCURSOR cursor_handle) {
+ base::win::ScopedGetDC hdc(NULL);
+
+ ICONINFO icon = {0};
+ GetIconInfo(cursor_handle, &icon);
+
+ BITMAPINFO bitmap_info = {0};
+ bitmap_info.bmiHeader.biSize = sizeof(bitmap_info.bmiHeader);
+ if (GetDIBits(hdc, icon.hbmMask, 0, 0, NULL, &bitmap_info, DIB_RGB_COLORS) ==
+ 0)
+ return kDefaultHeight;
+
+ // Rows are padded to full DWORDs. OR with this mask will set them to 1
+ // to simplify matching with |transparent_mask|.
+ uint32_t last_byte_mask = ~0;
+ const unsigned char bits_to_shift = sizeof(last_byte_mask) * 8 -
+ (bitmap_info.bmiHeader.biWidth % kBitsPeruint32);
+ if (bits_to_shift != kBitsPeruint32)
+ last_byte_mask = (last_byte_mask << bits_to_shift);
+ else
+ last_byte_mask = 0;
+
+ const uint32_t row_size =
+ (bitmap_info.bmiHeader.biWidth + kBitsPeruint32 - 1) / kBitsPeruint32;
+ PixelData data(GetBitmapData(icon.hbmMask, bitmap_info, hdc));
+ if (data == NULL)
+ return kDefaultHeight;
+
+ const int cursor_height = GetSystemMetrics(SM_CYCURSOR);
+ // Crash data seems to indicate cursor_height may be bigger than the bitmap.
+ int i = std::max(0, static_cast<int>(bitmap_info.bmiHeader.biHeight) -
+ cursor_height);
+ for (; i < bitmap_info.bmiHeader.biHeight; ++i) {
+ if (!IsRowTransparent(data, row_size, last_byte_mask, i)) {
+ i--;
+ break;
+ }
+ }
+ return bitmap_info.bmiHeader.biHeight - i - icon.yHotspot;
+}
+
+} // namespace
+
+namespace views {
+namespace corewm {
+
+int GetCurrentCursorVisibleHeight() {
+ CURSORINFO cursor = {0};
+ cursor.cbSize = sizeof(cursor);
+ GetCursorInfo(&cursor);
+
+ if (cached_heights == NULL)
+ cached_heights = new HeightStorage;
+
+ HeightStorage::const_iterator cached_height =
+ cached_heights->find(cursor.hCursor);
+ if (cached_height != cached_heights->end())
+ return cached_height->second;
+
+ const int height = CalculateCursorHeight(cursor.hCursor);
+ (*cached_heights)[cursor.hCursor] = height;
+
+ return height;
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/chromium/ui/views/corewm/cursor_height_provider_win.h b/chromium/ui/views/corewm/cursor_height_provider_win.h
new file mode 100644
index 00000000000..c93134491f2
--- /dev/null
+++ b/chromium/ui/views/corewm/cursor_height_provider_win.h
@@ -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.
+
+#ifndef UI_VIEWS_COREWM_CURSOR_HEIGHT_PROVIDER_WIN_H_
+#define UI_VIEWS_COREWM_CURSOR_HEIGHT_PROVIDER_WIN_H_
+
+namespace views {
+namespace corewm {
+
+// Gets the visible height of current cursor.
+//
+// The height is offset between cursor's hot point and it's
+// bottom edge, derived from first non-transparent row of cursor's mask.
+
+int GetCurrentCursorVisibleHeight();
+
+} // namespace corewm
+} // namespace views
+
+#endif // UI_VIEWS_COREWM_CURSOR_HEIGHT_PROVIDER_WIN_H_
diff --git a/chromium/ui/views/corewm/cursor_manager.cc b/chromium/ui/views/corewm/cursor_manager.cc
deleted file mode 100644
index 2335fdd1cbf..00000000000
--- a/chromium/ui/views/corewm/cursor_manager.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/cursor_manager.h"
-
-#include "base/logging.h"
-#include "ui/aura/client/cursor_client_observer.h"
-#include "ui/views/corewm/native_cursor_manager.h"
-#include "ui/views/corewm/native_cursor_manager_delegate.h"
-
-namespace views {
-namespace corewm {
-
-namespace internal {
-
-// Represents the cursor state which is composed of cursor type, visibility, and
-// mouse events enable state. When mouse events are disabled, the cursor is
-// always invisible.
-class CursorState {
- public:
- CursorState()
- : cursor_(ui::kCursorNone),
- visible_(true),
- scale_(1.f),
- cursor_set_(ui::CURSOR_SET_NORMAL),
- mouse_events_enabled_(true),
- visible_on_mouse_events_enabled_(true) {
- }
-
- gfx::NativeCursor cursor() const { return cursor_; }
- void set_cursor(gfx::NativeCursor cursor) { cursor_ = cursor; }
-
- bool visible() const { return visible_; }
- void SetVisible(bool visible) {
- if (mouse_events_enabled_)
- visible_ = visible;
- // Ignores the call when mouse events disabled.
- }
-
- float scale() const { return scale_; }
- void set_scale(float scale) {
- scale_ = scale;
- }
-
- ui::CursorSetType cursor_set() const { return cursor_set_; }
- void set_cursor_set(ui::CursorSetType cursor_set) {
- cursor_set_ = cursor_set;
- }
-
- bool mouse_events_enabled() const { return mouse_events_enabled_; }
- void SetMouseEventsEnabled(bool enabled) {
- if (mouse_events_enabled_ == enabled)
- return;
- mouse_events_enabled_ = enabled;
-
- // Restores the visibility when mouse events are enabled.
- if (enabled) {
- visible_ = visible_on_mouse_events_enabled_;
- } else {
- visible_on_mouse_events_enabled_ = visible_;
- visible_ = false;
- }
- }
-
- private:
- gfx::NativeCursor cursor_;
- bool visible_;
- float scale_;
- ui::CursorSetType cursor_set_;
- bool mouse_events_enabled_;
-
- // The visibility to set when mouse events are enabled.
- bool visible_on_mouse_events_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorState);
-};
-
-} // namespace internal
-
-CursorManager::CursorManager(scoped_ptr<NativeCursorManager> delegate)
- : delegate_(delegate.Pass()),
- cursor_lock_count_(0),
- current_state_(new internal::CursorState),
- state_on_unlock_(new internal::CursorState) {
-}
-
-CursorManager::~CursorManager() {
-}
-
-void CursorManager::SetCursor(gfx::NativeCursor cursor) {
- state_on_unlock_->set_cursor(cursor);
- if (cursor_lock_count_ == 0 &&
- GetCursor() != state_on_unlock_->cursor()) {
- delegate_->SetCursor(state_on_unlock_->cursor(), this);
- }
-}
-
-gfx::NativeCursor CursorManager::GetCursor() const {
- return current_state_->cursor();
-}
-
-void CursorManager::ShowCursor() {
- state_on_unlock_->SetVisible(true);
- if (cursor_lock_count_ == 0 &&
- IsCursorVisible() != state_on_unlock_->visible()) {
- delegate_->SetVisibility(state_on_unlock_->visible(), this);
- FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
- OnCursorVisibilityChanged(true));
- }
-}
-
-void CursorManager::HideCursor() {
- state_on_unlock_->SetVisible(false);
- if (cursor_lock_count_ == 0 &&
- IsCursorVisible() != state_on_unlock_->visible()) {
- delegate_->SetVisibility(state_on_unlock_->visible(), this);
- FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
- OnCursorVisibilityChanged(false));
- }
-}
-
-bool CursorManager::IsCursorVisible() const {
- return current_state_->visible();
-}
-
-void CursorManager::SetScale(float scale) {
- state_on_unlock_->set_scale(scale);
- if (GetScale() != state_on_unlock_->scale())
- delegate_->SetScale(state_on_unlock_->scale(), this);
-}
-
-float CursorManager::GetScale() const {
- return current_state_->scale();
-}
-
-void CursorManager::SetCursorSet(ui::CursorSetType cursor_set) {
- state_on_unlock_->set_cursor_set(cursor_set);
- if (GetCursorSet() != state_on_unlock_->cursor_set())
- delegate_->SetCursorSet(state_on_unlock_->cursor_set(), this);
-}
-
-ui::CursorSetType CursorManager::GetCursorSet() const {
- return current_state_->cursor_set();
-}
-
-void CursorManager::EnableMouseEvents() {
- state_on_unlock_->SetMouseEventsEnabled(true);
- if (cursor_lock_count_ == 0 &&
- IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
- delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
- this);
- }
-}
-
-void CursorManager::DisableMouseEvents() {
- state_on_unlock_->SetMouseEventsEnabled(false);
- if (cursor_lock_count_ == 0 &&
- IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
- delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
- this);
- }
-}
-
-bool CursorManager::IsMouseEventsEnabled() const {
- return current_state_->mouse_events_enabled();
-}
-
-void CursorManager::SetDisplay(const gfx::Display& display) {
- delegate_->SetDisplay(display, this);
-}
-
-void CursorManager::LockCursor() {
- cursor_lock_count_++;
-}
-
-void CursorManager::UnlockCursor() {
- cursor_lock_count_--;
- DCHECK_GE(cursor_lock_count_, 0);
- if (cursor_lock_count_ > 0)
- return;
-
- if (GetCursor() != state_on_unlock_->cursor()) {
- delegate_->SetCursor(state_on_unlock_->cursor(), this);
- }
- if (IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
- delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
- this);
- }
- if (IsCursorVisible() != state_on_unlock_->visible()) {
- delegate_->SetVisibility(state_on_unlock_->visible(),
- this);
- }
-}
-
-bool CursorManager::IsCursorLocked() const {
- return cursor_lock_count_ > 0;
-}
-
-void CursorManager::AddObserver(
- aura::client::CursorClientObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void CursorManager::RemoveObserver(
- aura::client::CursorClientObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void CursorManager::CommitCursor(gfx::NativeCursor cursor) {
- current_state_->set_cursor(cursor);
-}
-
-void CursorManager::CommitVisibility(bool visible) {
- // TODO(tdanderson): Find a better place for this so we don't
- // notify the observers more than is necessary.
- FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
- OnCursorVisibilityChanged(visible));
- current_state_->SetVisible(visible);
-}
-
-void CursorManager::CommitScale(float scale) {
- current_state_->set_scale(scale);
-}
-
-void CursorManager::CommitCursorSet(ui::CursorSetType cursor_set) {
- current_state_->set_cursor_set(cursor_set);
-}
-
-void CursorManager::CommitMouseEventsEnabled(bool enabled) {
- current_state_->SetMouseEventsEnabled(enabled);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/cursor_manager.h b/chromium/ui/views/corewm/cursor_manager.h
deleted file mode 100644
index 29f890ae6bd..00000000000
--- a/chromium/ui/views/corewm/cursor_manager.h
+++ /dev/null
@@ -1,92 +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_VIEWS_COREWM_CURSOR_MANAGER_H_
-#define UI_VIEWS_COREWM_CURSOR_MANAGER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/views/corewm/native_cursor_manager_delegate.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Display;
-}
-
-namespace views {
-namespace corewm {
-
-namespace internal {
-class CursorState;
-}
-
-class NativeCursorManager;
-
-// This class receives requests to change cursor properties, as well as
-// requests to queue any further changes until a later time. It sends changes
-// to the NativeCursorManager, which communicates back to us when these changes
-// were made through the NativeCursorManagerDelegate interface.
-class VIEWS_EXPORT CursorManager : public aura::client::CursorClient,
- public NativeCursorManagerDelegate {
- public:
- CursorManager(scoped_ptr<NativeCursorManager> delegate);
- virtual ~CursorManager();
-
- // Overridden from aura::client::CursorClient:
- virtual void SetCursor(gfx::NativeCursor) OVERRIDE;
- virtual gfx::NativeCursor GetCursor() const OVERRIDE;
- virtual void ShowCursor() OVERRIDE;
- virtual void HideCursor() OVERRIDE;
- virtual bool IsCursorVisible() const OVERRIDE;
- virtual void SetScale(float scale) OVERRIDE;
- virtual float GetScale() const OVERRIDE;
- virtual void SetCursorSet(ui::CursorSetType cursor_set) OVERRIDE;
- virtual ui::CursorSetType GetCursorSet() const OVERRIDE;
- virtual void EnableMouseEvents() OVERRIDE;
- virtual void DisableMouseEvents() OVERRIDE;
- virtual bool IsMouseEventsEnabled() const OVERRIDE;
- virtual void SetDisplay(const gfx::Display& display) OVERRIDE;
- virtual void LockCursor() OVERRIDE;
- virtual void UnlockCursor() OVERRIDE;
- virtual bool IsCursorLocked() const OVERRIDE;
- virtual void AddObserver(
- aura::client::CursorClientObserver* observer) OVERRIDE;
- virtual void RemoveObserver(
- aura::client::CursorClientObserver* observer) OVERRIDE;
-
- private:
- // Overridden from NativeCursorManagerDelegate:
- virtual void CommitCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual void CommitVisibility(bool visible) OVERRIDE;
- virtual void CommitScale(float scale) OVERRIDE;
- virtual void CommitCursorSet(ui::CursorSetType cursor_set) OVERRIDE;
- virtual void CommitMouseEventsEnabled(bool enabled) OVERRIDE;
-
- scoped_ptr<NativeCursorManager> delegate_;
-
- // Number of times LockCursor() has been invoked without a corresponding
- // UnlockCursor().
- int cursor_lock_count_;
-
- // The current state of the cursor.
- scoped_ptr<internal::CursorState> current_state_;
-
- // The cursor state to restore when the cursor is unlocked.
- scoped_ptr<internal::CursorState> state_on_unlock_;
-
- ObserverList<aura::client::CursorClientObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorManager);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_CURSOR_MANAGER_H_
diff --git a/chromium/ui/views/corewm/cursor_manager_unittest.cc b/chromium/ui/views/corewm/cursor_manager_unittest.cc
deleted file mode 100644
index a9c507782a5..00000000000
--- a/chromium/ui/views/corewm/cursor_manager_unittest.cc
+++ /dev/null
@@ -1,353 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/cursor_manager.h"
-
-#include "ui/aura/client/cursor_client_observer.h"
-#include "ui/views/corewm/native_cursor_manager.h"
-#include "ui/views/test/views_test_base.h"
-
-namespace {
-
-class TestingCursorManager : public views::corewm::NativeCursorManager {
- public:
- // Overridden from views::corewm::NativeCursorManager:
- virtual void SetDisplay(
- const gfx::Display& display,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {}
-
- virtual void SetCursor(
- gfx::NativeCursor cursor,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {
- delegate->CommitCursor(cursor);
- }
-
- virtual void SetVisibility(
- bool visible,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {
- delegate->CommitVisibility(visible);
- }
-
- virtual void SetMouseEventsEnabled(
- bool enabled,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {
- delegate->CommitMouseEventsEnabled(enabled);
- }
-
- virtual void SetCursorSet(
- ui::CursorSetType cursor_set,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {
- delegate->CommitCursorSet(cursor_set);
- }
-
- virtual void SetScale(
- float scale,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE {
- delegate->CommitScale(scale);
- }
-};
-
-} // namespace
-
-class CursorManagerTest : public views::ViewsTestBase {
- protected:
- CursorManagerTest()
- : delegate_(new TestingCursorManager),
- cursor_manager_(scoped_ptr<views::corewm::NativeCursorManager>(
- delegate_)) {
- }
-
- TestingCursorManager* delegate_;
- views::corewm::CursorManager cursor_manager_;
-};
-
-class TestingCursorClientObserver : public aura::client::CursorClientObserver {
- public:
- TestingCursorClientObserver()
- : cursor_visibility_(false),
- did_visibility_change_(false) {}
- void reset() { cursor_visibility_ = did_visibility_change_ = false; }
- bool is_cursor_visible() const { return cursor_visibility_; }
- bool did_visibility_change() const { return did_visibility_change_; }
-
- // Overridden from aura::client::CursorClientObserver:
- virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE {
- cursor_visibility_ = is_visible;
- did_visibility_change_ = true;
- }
-
- private:
- bool cursor_visibility_;
- bool did_visibility_change_;
-
- DISALLOW_COPY_AND_ASSIGN(TestingCursorClientObserver);
-};
-
-TEST_F(CursorManagerTest, ShowHideCursor) {
- cursor_manager_.SetCursor(ui::kCursorCopy);
- EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
-
- cursor_manager_.ShowCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- cursor_manager_.HideCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- // The current cursor does not change even when the cursor is not shown.
- EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
-
- // Check if cursor visibility is locked.
- cursor_manager_.LockCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- cursor_manager_.ShowCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
-
- cursor_manager_.LockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- cursor_manager_.HideCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
-
- // Checks setting visiblity while cursor is locked does not affect the
- // subsequent uses of UnlockCursor.
- cursor_manager_.LockCursor();
- cursor_manager_.HideCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
-
- cursor_manager_.ShowCursor();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
-
- cursor_manager_.LockCursor();
- cursor_manager_.ShowCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
-
- cursor_manager_.HideCursor();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
-}
-
-// Verifies that LockCursor/UnlockCursor work correctly with
-// EnableMouseEvents and DisableMouseEvents
-TEST_F(CursorManagerTest, EnableDisableMouseEvents) {
- cursor_manager_.SetCursor(ui::kCursorCopy);
- EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
-
- cursor_manager_.EnableMouseEvents();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- // The current cursor does not change even when the cursor is not shown.
- EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
-
- // Check if cursor enable state is locked.
- cursor_manager_.LockCursor();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.EnableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.LockCursor();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.DisableMouseEvents();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-
- // Checks enabling cursor while cursor is locked does not affect the
- // subsequent uses of UnlockCursor.
- cursor_manager_.LockCursor();
- cursor_manager_.DisableMouseEvents();
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.LockCursor();
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.DisableMouseEvents();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-}
-
-TEST_F(CursorManagerTest, SetCursorSet) {
- EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-
- cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
- EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-
- cursor_manager_.SetCursorSet(ui::CURSOR_SET_LARGE);
- EXPECT_EQ(ui::CURSOR_SET_LARGE, cursor_manager_.GetCursorSet());
-
- cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
- EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-}
-
-TEST_F(CursorManagerTest, SetScale) {
- EXPECT_EQ(1.f, cursor_manager_.GetScale());
- cursor_manager_.SetScale(2.f);
- EXPECT_EQ(2.f, cursor_manager_.GetScale());
-
- // Cusror scale does change even while cursor is locked.
- cursor_manager_.LockCursor();
- EXPECT_EQ(2.f, cursor_manager_.GetScale());
- cursor_manager_.SetScale(2.5f);
- EXPECT_EQ(2.5f, cursor_manager_.GetScale());
- cursor_manager_.UnlockCursor();
-
- EXPECT_EQ(2.5f, cursor_manager_.GetScale());
- cursor_manager_.SetScale(1.f);
- EXPECT_EQ(1.f, cursor_manager_.GetScale());
-}
-
-TEST_F(CursorManagerTest, IsMouseEventsEnabled) {
- cursor_manager_.EnableMouseEvents();
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-}
-
-// Verifies that the mouse events enable state changes correctly when
-// ShowCursor/HideCursor and EnableMouseEvents/DisableMouseEvents are used
-// together.
-TEST_F(CursorManagerTest, ShowAndEnable) {
- // Changing the visibility of the cursor does not affect the enable state.
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.ShowCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.HideCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.ShowCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- // When mouse events are disabled, it also gets invisible.
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-
- // When mouse events are enabled, it restores the visibility state.
- cursor_manager_.EnableMouseEvents();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.ShowCursor();
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.EnableMouseEvents();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- cursor_manager_.HideCursor();
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.EnableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
-
- // When mouse events are disabled, ShowCursor is ignored.
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.ShowCursor();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
- cursor_manager_.DisableMouseEvents();
- EXPECT_FALSE(cursor_manager_.IsCursorVisible());
- EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
-}
-
-// Verifies that calling DisableMouseEvents multiple times in a row makes no
-// difference compared with calling it once.
-// This is a regression test for http://crbug.com/169404.
-TEST_F(CursorManagerTest, MultipleDisableMouseEvents) {
- cursor_manager_.DisableMouseEvents();
- cursor_manager_.DisableMouseEvents();
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
-}
-
-// Verifies that calling EnableMouseEvents multiple times in a row makes no
-// difference compared with calling it once.
-TEST_F(CursorManagerTest, MultipleEnableMouseEvents) {
- cursor_manager_.DisableMouseEvents();
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.EnableMouseEvents();
- cursor_manager_.LockCursor();
- cursor_manager_.UnlockCursor();
- EXPECT_TRUE(cursor_manager_.IsCursorVisible());
-}
-
-TEST_F(CursorManagerTest, TestCursorClientObserver) {
- // Add two observers. Both should have OnCursorVisibilityChanged()
- // invoked when the visibility of the cursor changes.
- TestingCursorClientObserver observer_a;
- TestingCursorClientObserver observer_b;
- cursor_manager_.AddObserver(&observer_a);
- cursor_manager_.AddObserver(&observer_b);
-
- // Initial state before any events have been sent.
- observer_a.reset();
- observer_b.reset();
- EXPECT_FALSE(observer_a.did_visibility_change());
- EXPECT_FALSE(observer_b.did_visibility_change());
- EXPECT_FALSE(observer_a.is_cursor_visible());
- EXPECT_FALSE(observer_b.is_cursor_visible());
-
- // Hide the cursor using HideCursor().
- cursor_manager_.HideCursor();
- EXPECT_TRUE(observer_a.did_visibility_change());
- EXPECT_TRUE(observer_b.did_visibility_change());
- EXPECT_FALSE(observer_a.is_cursor_visible());
- EXPECT_FALSE(observer_b.is_cursor_visible());
-
- // Show the cursor using ShowCursor().
- observer_a.reset();
- observer_b.reset();
- cursor_manager_.ShowCursor();
- EXPECT_TRUE(observer_a.did_visibility_change());
- EXPECT_TRUE(observer_b.did_visibility_change());
- EXPECT_TRUE(observer_a.is_cursor_visible());
- EXPECT_TRUE(observer_b.is_cursor_visible());
-
- // Remove observer_b. Its OnCursorVisibilityChanged() should
- // not be invoked past this point.
- cursor_manager_.RemoveObserver(&observer_b);
-
- // Hide the cursor using HideCursor().
- observer_a.reset();
- observer_b.reset();
- cursor_manager_.HideCursor();
- EXPECT_TRUE(observer_a.did_visibility_change());
- EXPECT_FALSE(observer_b.did_visibility_change());
- EXPECT_FALSE(observer_a.is_cursor_visible());
-
- // Show the cursor using ShowCursor().
- observer_a.reset();
- observer_b.reset();
- cursor_manager_.ShowCursor();
- EXPECT_TRUE(observer_a.did_visibility_change());
- EXPECT_FALSE(observer_b.did_visibility_change());
- EXPECT_TRUE(observer_a.is_cursor_visible());
-}
diff --git a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
index c655ec8081c..8807aafdd6e 100644
--- a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
+++ b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
@@ -2,14 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/corewm/capture_controller.h"
+#include "ui/wm/core/capture_controller.h"
#include "base/logging.h"
+#include "base/path_service.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
#include "ui/events/event.h"
+#include "ui/gl/gl_surface.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -22,7 +27,22 @@
namespace views {
-typedef ViewsTestBase DesktopCaptureControllerTest;
+class DesktopCaptureControllerTest : public ViewsTestBase {
+ public:
+ DesktopCaptureControllerTest() {}
+ virtual ~DesktopCaptureControllerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ gfx::GLSurface::InitializeOneOffForTests();
+ base::FilePath pak_dir;
+ PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::FilePath pak_file;
+ pak_file = pak_dir.Append(FILE_PATH_LITERAL("ui_test.pak"));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
+
+ ViewsTestBase::SetUp();
+ }
+};
// This class provides functionality to verify whether the View instance
// received the gesture event.
@@ -72,13 +92,16 @@ TEST_F(DesktopCaptureControllerTest, ResetMouseHandlers) {
generator1.MoveMouseToCenterOf(w1->GetNativeView());
generator1.PressLeftButton();
EXPECT_FALSE(w1->HasCapture());
- aura::RootWindow* w1_root = w1->GetNativeView()->GetDispatcher();
- EXPECT_TRUE(w1_root->mouse_pressed_handler() != NULL);
- EXPECT_TRUE(w1_root->mouse_moved_handler() != NULL);
+ aura::WindowEventDispatcher* w1_dispatcher =
+ w1->GetNativeView()->GetHost()->dispatcher();
+ EXPECT_TRUE(w1_dispatcher->mouse_pressed_handler() != NULL);
+ EXPECT_TRUE(w1_dispatcher->mouse_moved_handler() != NULL);
w2->SetCapture(w2->GetRootView());
EXPECT_TRUE(w2->HasCapture());
- EXPECT_TRUE(w1_root->mouse_pressed_handler() == NULL);
- EXPECT_TRUE(w1_root->mouse_moved_handler() == NULL);
+ EXPECT_TRUE(w1_dispatcher->mouse_pressed_handler() == NULL);
+ EXPECT_TRUE(w1_dispatcher->mouse_moved_handler() == NULL);
+ w2->ReleaseCapture();
+ RunPendingMessages();
}
// Tests aura::Window capture and whether gesture events are sent to the window
@@ -93,8 +116,8 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
scoped_ptr<Widget> widget1(new Widget());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- scoped_ptr<corewm::ScopedCaptureClient> scoped_capture_client(
- new corewm::ScopedCaptureClient(params.context->GetRootWindow()));
+ scoped_ptr<wm::ScopedCaptureClient> scoped_capture_client(
+ new wm::ScopedCaptureClient(params.context->GetRootWindow()));
aura::client::CaptureClient* capture_client =
scoped_capture_client->capture_client();
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
@@ -103,7 +126,8 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
internal::RootView* root1 =
static_cast<internal::RootView*>(widget1->GetRootView());
- desktop_position_client1.reset(new DesktopScreenPositionClient());
+ desktop_position_client1.reset(
+ new DesktopScreenPositionClient(params.context->GetRootWindow()));
aura::client::SetScreenPositionClient(
widget1->GetNativeView()->GetRootWindow(),
desktop_position_client1.get());
@@ -122,10 +146,12 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
internal::RootView* root2 =
static_cast<internal::RootView*>(widget2->GetRootView());
- desktop_position_client2.reset(new DesktopScreenPositionClient());
+ desktop_position_client2.reset(
+ new DesktopScreenPositionClient(params.context->GetRootWindow()));
aura::client::SetScreenPositionClient(
widget2->GetNativeView()->GetRootWindow(),
desktop_position_client2.get());
+ ui::EventDispatchDetails details;
DesktopViewInputTest* v2 = new DesktopViewInputTest();
v2->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
@@ -146,7 +172,10 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS,
0.0f, 0.0f), 0);
- root1->DispatchGestureEvent(&g1);
+ details = root1->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_TRUE(v1->received_gesture_event());
EXPECT_FALSE(v2->received_gesture_event());
v1->Reset();
@@ -158,7 +187,10 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
EXPECT_TRUE(widget2->GetNativeView()->HasCapture());
EXPECT_EQ(capture_client->GetCaptureWindow(), widget2->GetNativeView());
- root2->DispatchGestureEvent(&g1);
+ details = root2->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_TRUE(v2->received_gesture_event());
EXPECT_FALSE(v1->received_gesture_event());
diff --git a/chromium/ui/views/corewm/focus_controller.cc b/chromium/ui/views/corewm/focus_controller.cc
deleted file mode 100644
index 17add8417fb..00000000000
--- a/chromium/ui/views/corewm/focus_controller.cc
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/focus_controller.h"
-
-#include "base/auto_reset.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window_tracker.h"
-#include "ui/events/event.h"
-#include "ui/views/corewm/focus_rules.h"
-
-namespace views {
-namespace corewm {
-namespace {
-
-// When a modal window is activated, we bring its entire transient parent chain
-// to the front. This function must be called before the modal transient is
-// stacked at the top to ensure correct stacking order.
-void StackTransientParentsBelowModalWindow(aura::Window* window) {
- if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
- return;
-
- aura::Window* transient_parent = window->transient_parent();
- while (transient_parent) {
- transient_parent->parent()->StackChildAtTop(transient_parent);
- transient_parent = transient_parent->transient_parent();
- }
-}
-
-// Stack's |window|'s layer above |relative_to|'s layer.
-void StackWindowLayerAbove(aura::Window* window, aura::Window* relative_to) {
- // Stack |window| above the last transient child of |relative_to| that shares
- // the same parent.
- const aura::Window::Windows& window_transients(
- relative_to->transient_children());
- for (aura::Window::Windows::const_iterator i = window_transients.begin();
- i != window_transients.end(); ++i) {
- aura::Window* transient = *i;
- if (transient->parent() == relative_to->parent())
- relative_to = transient;
- }
- if (window != relative_to) {
- window->layer()->parent()->StackAbove(window->layer(),
- relative_to->layer());
- }
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, public:
-
-FocusController::FocusController(FocusRules* rules)
- : active_window_(NULL),
- focused_window_(NULL),
- updating_focus_(false),
- updating_activation_(false),
- rules_(rules),
- observer_manager_(this) {
- DCHECK(rules);
-}
-
-FocusController::~FocusController() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, aura::client::ActivationClient implementation:
-
-void FocusController::AddObserver(
- aura::client::ActivationChangeObserver* observer) {
- activation_observers_.AddObserver(observer);
-}
-
-void FocusController::RemoveObserver(
- aura::client::ActivationChangeObserver* observer) {
- activation_observers_.RemoveObserver(observer);
-}
-
-void FocusController::ActivateWindow(aura::Window* window) {
- FocusWindow(window);
-}
-
-void FocusController::DeactivateWindow(aura::Window* window) {
- if (window)
- FocusWindow(rules_->GetNextActivatableWindow(window));
-}
-
-aura::Window* FocusController::GetActiveWindow() {
- return active_window_;
-}
-
-aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
- return rules_->GetActivatableWindow(window);
-}
-
-aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
- return rules_->GetToplevelWindow(window);
-}
-
-bool FocusController::OnWillFocusWindow(aura::Window* window,
- const ui::Event* event) {
- NOTREACHED();
- return false;
-}
-
-bool FocusController::CanActivateWindow(aura::Window* window) const {
- return rules_->CanActivateWindow(window);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, aura::client::FocusClient implementation:
-
-void FocusController::AddObserver(
- aura::client::FocusChangeObserver* observer) {
- focus_observers_.AddObserver(observer);
-}
-
-void FocusController::RemoveObserver(
- aura::client::FocusChangeObserver* observer) {
- focus_observers_.RemoveObserver(observer);
-}
-
-void FocusController::FocusWindow(aura::Window* window) {
- if (window &&
- (window->Contains(focused_window_) || window->Contains(active_window_))) {
- return;
- }
-
- // We should not be messing with the focus if the window has capture, unless
- // no has focus.
- if (window && (aura::client::GetCaptureWindow(window) == window) &&
- focused_window_) {
- return;
- }
-
- // Focusing a window also activates its containing activatable window. Note
- // that the rules could redirect activation activation and/or focus.
- aura::Window* focusable = rules_->GetFocusableWindow(window);
- aura::Window* activatable =
- focusable ? rules_->GetActivatableWindow(focusable) : NULL;
-
- // We need valid focusable/activatable windows in the event we're not clearing
- // focus. "Clearing focus" is inferred by whether or not |window| passed to
- // this function is non-NULL.
- if (window && (!focusable || !activatable))
- return;
- DCHECK((focusable && activatable) || !window);
-
- // Activation change observers may change the focused window. If this happens
- // we must not adjust the focus below since this will clobber that change.
- aura::Window* last_focused_window = focused_window_;
- if (!updating_activation_)
- SetActiveWindow(window, activatable);
-
- // If the window's ActivationChangeObserver shifted focus to a valid window,
- // we don't want to focus the window we thought would be focused by default.
- bool activation_changed_focus = last_focused_window != focused_window_;
- if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
- if (active_window_ && focusable)
- DCHECK(active_window_->Contains(focusable));
- SetFocusedWindow(focusable);
- }
-}
-
-void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
- DCHECK(window);
- if (!active_window_)
- return;
- if (!active_window_->Contains(window))
- return;
- SetFocusedWindow(window);
-}
-
-aura::Window* FocusController::GetFocusedWindow() {
- return focused_window_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, ui::EventHandler implementation:
-void FocusController::OnKeyEvent(ui::KeyEvent* event) {
-}
-
-void FocusController::OnMouseEvent(ui::MouseEvent* event) {
- if (event->type() == ui::ET_MOUSE_PRESSED)
- WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
-}
-
-void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
-}
-
-void FocusController::OnTouchEvent(ui::TouchEvent* event) {
-}
-
-void FocusController::OnGestureEvent(ui::GestureEvent* event) {
- if (event->type() == ui::ET_GESTURE_BEGIN &&
- event->details().touch_points() == 1) {
- WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, aura::WindowObserver implementation:
-
-void FocusController::OnWindowVisibilityChanged(aura::Window* window,
- bool visible) {
- if (!visible) {
- WindowLostFocusFromDispositionChange(window, window->parent());
- // Despite the focus change, we need to keep the window being hidden
- // stacked above the new window so it stays open on top as it animates away.
- aura::Window* next_window = GetActiveWindow();
- if (next_window && next_window->parent() == window->parent())
- StackWindowLayerAbove(window, next_window);
- }
-}
-
-void FocusController::OnWindowDestroying(aura::Window* window) {
- WindowLostFocusFromDispositionChange(window, window->parent());
-}
-
-void FocusController::OnWindowHierarchyChanging(
- const HierarchyChangeParams& params) {
- if (params.receiver == active_window_ &&
- params.target->Contains(params.receiver) && (!params.new_parent ||
- aura::client::GetFocusClient(params.new_parent) !=
- aura::client::GetFocusClient(params.receiver))) {
- WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
- }
-}
-
-void FocusController::OnWindowHierarchyChanged(
- const HierarchyChangeParams& params) {
- if (params.receiver == focused_window_ &&
- params.target->Contains(params.receiver) && (!params.new_parent ||
- aura::client::GetFocusClient(params.new_parent) !=
- aura::client::GetFocusClient(params.receiver))) {
- WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FocusController, private:
-
-void FocusController::SetFocusedWindow(aura::Window* window) {
- if (updating_focus_ || window == focused_window_)
- return;
- DCHECK(rules_->CanFocusWindow(window));
- if (window)
- DCHECK_EQ(window, rules_->GetFocusableWindow(window));
-
- base::AutoReset<bool> updating_focus(&updating_focus_, true);
- aura::Window* lost_focus = focused_window_;
- if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
- focused_window_ != active_window_) {
- observer_manager_.Remove(focused_window_);
- }
- focused_window_ = window;
- if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
- observer_manager_.Add(focused_window_);
-
- FOR_EACH_OBSERVER(aura::client::FocusChangeObserver,
- focus_observers_,
- OnWindowFocused(focused_window_, lost_focus));
- aura::client::FocusChangeObserver* observer =
- aura::client::GetFocusChangeObserver(lost_focus);
- if (observer)
- observer->OnWindowFocused(focused_window_, lost_focus);
- observer = aura::client::GetFocusChangeObserver(focused_window_);
- if (observer)
- observer->OnWindowFocused(focused_window_, lost_focus);
-}
-
-void FocusController::SetActiveWindow(aura::Window* requested_window,
- aura::Window* window) {
- if (updating_activation_)
- return;
-
- if (window == active_window_) {
- if (requested_window) {
- FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
- activation_observers_,
- OnAttemptToReactivateWindow(requested_window,
- active_window_));
- }
- return;
- }
-
- DCHECK(rules_->CanActivateWindow(window));
- if (window)
- DCHECK_EQ(window, rules_->GetActivatableWindow(window));
-
- base::AutoReset<bool> updating_activation(&updating_activation_, true);
- aura::Window* lost_activation = active_window_;
- // Allow for the window losing activation to be deleted during dispatch. If
- // it is deleted pass NULL to observers instead of a deleted window.
- aura::WindowTracker window_tracker;
- if (lost_activation)
- window_tracker.Add(lost_activation);
- if (active_window_ && observer_manager_.IsObserving(active_window_) &&
- focused_window_ != active_window_) {
- observer_manager_.Remove(active_window_);
- }
- active_window_ = window;
- if (active_window_ && !observer_manager_.IsObserving(active_window_))
- observer_manager_.Add(active_window_);
- if (active_window_) {
- StackTransientParentsBelowModalWindow(active_window_);
- active_window_->parent()->StackChildAtTop(active_window_);
- }
-
- aura::client::ActivationChangeObserver* observer = NULL;
- if (window_tracker.Contains(lost_activation)) {
- observer = aura::client::GetActivationChangeObserver(lost_activation);
- if (observer)
- observer->OnWindowActivated(active_window_, lost_activation);
- }
- observer = aura::client::GetActivationChangeObserver(active_window_);
- if (observer) {
- observer->OnWindowActivated(
- active_window_,
- window_tracker.Contains(lost_activation) ? lost_activation : NULL);
- }
- FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
- activation_observers_,
- OnWindowActivated(active_window_,
- window_tracker.Contains(lost_activation) ?
- lost_activation : NULL));
-}
-
-void FocusController::WindowLostFocusFromDispositionChange(
- aura::Window* window,
- aura::Window* next) {
- // A window's modality state will interfere with focus restoration during its
- // destruction.
- window->ClearProperty(aura::client::kModalKey);
- // TODO(beng): See if this function can be replaced by a call to
- // FocusWindow().
- // Activation adjustments are handled first in the event of a disposition
- // changed. If an activation change is necessary, focus is reset as part of
- // that process so there's no point in updating focus independently.
- if (window == active_window_) {
- aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
- SetActiveWindow(NULL, next_activatable);
- if (!(active_window_ && active_window_->Contains(focused_window_)))
- SetFocusedWindow(next_activatable);
- } else if (window->Contains(focused_window_)) {
- // Active window isn't changing, but focused window might be.
- SetFocusedWindow(rules_->GetFocusableWindow(next));
- }
-}
-
-void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
- // Only focus |window| if it or any of its parents can be focused. Otherwise
- // FocusWindow() will focus the topmost window, which may not be the
- // currently focused one.
- if (rules_->CanFocusWindow(GetToplevelWindow(window)))
- FocusWindow(window);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/focus_controller.h b/chromium/ui/views/corewm/focus_controller.h
deleted file mode 100644
index 1dc69b78219..00000000000
--- a/chromium/ui/views/corewm/focus_controller.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_FOCUS_CONTROLLER_H_
-#define UI_VIEWS_COREWM_FOCUS_CONTROLLER_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "base/scoped_observer.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/window_observer.h"
-#include "ui/events/event_handler.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-
-class FocusRules;
-
-// FocusController handles focus and activation changes for an environment
-// encompassing one or more RootWindows. Within an environment there can be
-// only one focused and one active window at a time. When focus or activation
-// changes notifications are sent using the
-// aura::client::Focus/ActivationChangeObserver interfaces.
-// Changes to focus and activation can be from three sources:
-// . the Aura Client API (implemented here in aura::client::ActivationClient).
-// (The FocusController must be set as the ActivationClient implementation
-// for all RootWindows).
-// . input events (implemented here in ui::EventHandler).
-// (The FocusController must be registered as a pre-target handler for
-// the applicable environment owner, either a RootWindow or another type).
-// . Window disposition changes (implemented here in aura::WindowObserver).
-// (The FocusController registers itself as an observer of the active and
-// focused windows).
-class VIEWS_EXPORT FocusController : public aura::client::ActivationClient,
- public aura::client::FocusClient,
- public ui::EventHandler,
- public aura::WindowObserver {
- public:
- // |rules| cannot be NULL.
- explicit FocusController(FocusRules* rules);
- virtual ~FocusController();
-
- private:
- // Overridden from aura::client::ActivationClient:
- virtual void AddObserver(
- aura::client::ActivationChangeObserver* observer) OVERRIDE;
- virtual void RemoveObserver(
- aura::client::ActivationChangeObserver* observer) OVERRIDE;
- virtual void ActivateWindow(aura::Window* window) OVERRIDE;
- virtual void DeactivateWindow(aura::Window* window) OVERRIDE;
- virtual aura::Window* GetActiveWindow() OVERRIDE;
- virtual aura::Window* GetActivatableWindow(aura::Window* window) OVERRIDE;
- virtual aura::Window* GetToplevelWindow(aura::Window* window) OVERRIDE;
- virtual bool OnWillFocusWindow(aura::Window* window,
- const ui::Event* event) OVERRIDE;
- virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
-
- // Overridden from aura::client::FocusClient:
- virtual void AddObserver(
- aura::client::FocusChangeObserver* observer) OVERRIDE;
- virtual void RemoveObserver(
- aura::client::FocusChangeObserver* observer) OVERRIDE;
- virtual void FocusWindow(aura::Window* window) OVERRIDE;
- virtual void ResetFocusWithinActiveWindow(aura::Window* window) OVERRIDE;
- virtual aura::Window* GetFocusedWindow() OVERRIDE;
-
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
- // Overridden from aura::WindowObserver:
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE;
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
- virtual void OnWindowHierarchyChanging(
- const HierarchyChangeParams& params) OVERRIDE;
- virtual void OnWindowHierarchyChanged(
- const HierarchyChangeParams& params) OVERRIDE;
-
- // Internal implementation that sets the focused window, fires events etc.
- // This function must be called with a valid focusable window.
- void SetFocusedWindow(aura::Window* window);
-
- // Internal implementation that sets the active window, fires events etc.
- // This function must be called with a valid |activatable_window|.
- // |requested window| refers to the window that was passed in to an external
- // request (e.g. FocusWindow or ActivateWindow). It may be NULL, e.g. if
- // SetActiveWindow was not called by an external request. |activatable_window|
- // refers to the actual window to be activated, which may be different.
- void SetActiveWindow(aura::Window* requested_window,
- aura::Window* activatable_window);
-
- // Called when a window's disposition changed such that it and its hierarchy
- // are no longer focusable/activatable. |next| is a valid window that is used
- // as a starting point for finding a window to focus next based on rules.
- void WindowLostFocusFromDispositionChange(aura::Window* window,
- aura::Window* next);
-
- // Called when an attempt is made to focus or activate a window via an input
- // event targeted at that window. Rules determine the best focusable window
- // for the input window.
- void WindowFocusedFromInputEvent(aura::Window* window);
-
- aura::Window* active_window_;
- aura::Window* focused_window_;
-
- bool updating_focus_;
- bool updating_activation_;
-
- scoped_ptr<FocusRules> rules_;
-
- ObserverList<aura::client::ActivationChangeObserver> activation_observers_;
- ObserverList<aura::client::FocusChangeObserver> focus_observers_;
-
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusController);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_FOCUS_CONTROLLER_H_
diff --git a/chromium/ui/views/corewm/focus_controller_unittest.cc b/chromium/ui/views/corewm/focus_controller_unittest.cc
deleted file mode 100644
index cfccd056c97..00000000000
--- a/chromium/ui/views/corewm/focus_controller_unittest.cc
+++ /dev/null
@@ -1,1110 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/focus_controller.h"
-
-#include <map>
-
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/default_capture_client.h"
-#include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tracker.h"
-#include "ui/events/event_handler.h"
-#include "ui/views/corewm/base_focus_rules.h"
-
-namespace views {
-namespace corewm {
-
-class FocusNotificationObserver : public aura::client::ActivationChangeObserver,
- public aura::client::FocusChangeObserver {
- public:
- FocusNotificationObserver()
- : activation_changed_count_(0),
- focus_changed_count_(0),
- reactivation_count_(0),
- reactivation_requested_window_(NULL),
- reactivation_actual_window_(NULL) {}
- virtual ~FocusNotificationObserver() {}
-
- void ExpectCounts(int activation_changed_count, int focus_changed_count) {
- EXPECT_EQ(activation_changed_count, activation_changed_count_);
- EXPECT_EQ(focus_changed_count, focus_changed_count_);
- }
- int reactivation_count() const {
- return reactivation_count_;
- }
- aura::Window* reactivation_requested_window() const {
- return reactivation_requested_window_;
- }
- aura::Window* reactivation_actual_window() const {
- return reactivation_actual_window_;
- }
-
- private:
- // Overridden from aura::client::ActivationChangeObserver:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- ++activation_changed_count_;
- }
- virtual void OnAttemptToReactivateWindow(
- aura::Window* request_active,
- aura::Window* actual_active) OVERRIDE {
- ++reactivation_count_;
- reactivation_requested_window_ = request_active;
- reactivation_actual_window_ = actual_active;
- }
-
- // Overridden from aura::client::FocusChangeObserver:
- virtual void OnWindowFocused(aura::Window* gained_focus,
- aura::Window* lost_focus) OVERRIDE {
- ++focus_changed_count_;
- }
-
- int activation_changed_count_;
- int focus_changed_count_;
- int reactivation_count_;
- aura::Window* reactivation_requested_window_;
- aura::Window* reactivation_actual_window_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusNotificationObserver);
-};
-
-// ActivationChangeObserver that keeps a vector of all the windows that lost
-// active.
-class RecordingActivationChangeObserver
- : public aura::client::ActivationChangeObserver {
- public:
- explicit RecordingActivationChangeObserver(aura::Window* root)
- : root_(root) {
- aura::client::GetActivationClient(root_)->AddObserver(this);
- }
- virtual ~RecordingActivationChangeObserver() {
- aura::client::GetActivationClient(root_)->RemoveObserver(this);
- }
-
- // Each time we get OnWindowActivated() the |lost_active| parameter is
- // added here.
- const std::vector<aura::Window*>& lost() const { return lost_; }
-
- // Overridden from aura::client::ActivationChangeObserver:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- lost_.push_back(lost_active);
- }
-
- private:
- aura::Window* root_;
- std::vector<aura::Window*> lost_;
-
- DISALLOW_COPY_AND_ASSIGN(RecordingActivationChangeObserver);
-};
-
-// ActivationChangeObserver that deletes the window losing activation.
-class DeleteOnLoseActivationChangeObserver
- : public aura::client::ActivationChangeObserver {
- public:
- explicit DeleteOnLoseActivationChangeObserver(aura::Window* window)
- : root_(window->GetRootWindow()),
- window_(window) {
- aura::client::GetActivationClient(root_)->AddObserver(this);
- }
- virtual ~DeleteOnLoseActivationChangeObserver() {
- aura::client::GetActivationClient(root_)->RemoveObserver(this);
- }
-
- bool did_delete() const { return window_ == NULL; }
-
- // Overridden from aura::client::ActivationChangeObserver:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- if (window_ && lost_active == window_) {
- window_ = NULL;
- delete lost_active;
- }
- }
-
- private:
- aura::Window* root_;
- aura::Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(DeleteOnLoseActivationChangeObserver);
-};
-
-class ScopedFocusNotificationObserver : public FocusNotificationObserver {
- public:
- ScopedFocusNotificationObserver(aura::Window* root_window)
- : root_window_(root_window) {
- aura::client::GetActivationClient(root_window_)->AddObserver(this);
- aura::client::GetFocusClient(root_window_)->AddObserver(this);
- }
- virtual ~ScopedFocusNotificationObserver() {
- aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
- aura::client::GetFocusClient(root_window_)->RemoveObserver(this);
- }
-
- private:
- aura::Window* root_window_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedFocusNotificationObserver);
-};
-
-class ScopedTargetFocusNotificationObserver : public FocusNotificationObserver {
- public:
- ScopedTargetFocusNotificationObserver(aura::Window* root_window, int id)
- : target_(root_window->GetChildById(id)) {
- aura::client::SetActivationChangeObserver(target_, this);
- aura::client::SetFocusChangeObserver(target_, this);
- tracker_.Add(target_);
- }
- virtual ~ScopedTargetFocusNotificationObserver() {
- if (tracker_.Contains(target_)) {
- aura::client::SetActivationChangeObserver(target_, NULL);
- aura::client::SetFocusChangeObserver(target_, NULL);
- }
- }
-
- private:
- aura::Window* target_;
- aura::WindowTracker tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedTargetFocusNotificationObserver);
-};
-
-class FocusShiftingActivationObserver
- : public aura::client::ActivationChangeObserver {
- public:
- explicit FocusShiftingActivationObserver(aura::Window* activated_window)
- : activated_window_(activated_window),
- shift_focus_to_(NULL) {}
- virtual ~FocusShiftingActivationObserver() {}
-
- void set_shift_focus_to(aura::Window* shift_focus_to) {
- shift_focus_to_ = shift_focus_to;
- }
-
- private:
- // Overridden from aura::client::ActivationChangeObserver:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE {
- // Shift focus to a child. This should prevent the default focusing from
- // occurring in FocusController::FocusWindow().
- if (gained_active == activated_window_) {
- aura::client::FocusClient* client =
- aura::client::GetFocusClient(gained_active);
- client->FocusWindow(shift_focus_to_);
- }
- }
-
- aura::Window* activated_window_;
- aura::Window* shift_focus_to_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusShiftingActivationObserver);
-};
-
-// BaseFocusRules subclass that allows basic overrides of focus/activation to
-// be tested. This is intended more as a test that the override system works at
-// all, rather than as an exhaustive set of use cases, those should be covered
-// in tests for those FocusRules implementations.
-class TestFocusRules : public BaseFocusRules {
- public:
- TestFocusRules() : focus_restriction_(NULL) {}
-
- // Restricts focus and activation to this window and its child hierarchy.
- void set_focus_restriction(aura::Window* focus_restriction) {
- focus_restriction_ = focus_restriction;
- }
-
- // Overridden from BaseFocusRules:
- virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE {
- // In FocusControllerTests, only the RootWindow has activatable children.
- return window->GetRootWindow() == window;
- }
- virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE {
- // Restricting focus to a non-activatable child window means the activatable
- // parent outside the focus restriction is activatable.
- bool can_activate =
- CanFocusOrActivate(window) || window->Contains(focus_restriction_);
- return can_activate ? BaseFocusRules::CanActivateWindow(window) : false;
- }
- virtual bool CanFocusWindow(aura::Window* window) const OVERRIDE {
- return CanFocusOrActivate(window) ?
- BaseFocusRules::CanFocusWindow(window) : false;
- }
- virtual aura::Window* GetActivatableWindow(
- aura::Window* window) const OVERRIDE {
- return BaseFocusRules::GetActivatableWindow(
- CanFocusOrActivate(window) ? window : focus_restriction_);
- }
- virtual aura::Window* GetFocusableWindow(
- aura::Window* window) const OVERRIDE {
- return BaseFocusRules::GetFocusableWindow(
- CanFocusOrActivate(window) ? window : focus_restriction_);
- }
- virtual aura::Window* GetNextActivatableWindow(
- aura::Window* ignore) const OVERRIDE {
- aura::Window* next_activatable =
- BaseFocusRules::GetNextActivatableWindow(ignore);
- return CanFocusOrActivate(next_activatable) ?
- next_activatable : GetActivatableWindow(focus_restriction_);
- }
-
- private:
- bool CanFocusOrActivate(aura::Window* window) const {
- return !focus_restriction_ || focus_restriction_->Contains(window);
- }
-
- aura::Window* focus_restriction_;
-
- DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
-};
-
-// Common infrastructure shared by all FocusController test types.
-class FocusControllerTestBase : public aura::test::AuraTestBase {
- protected:
- FocusControllerTestBase() {}
-
- // Overridden from aura::test::AuraTestBase:
- virtual void SetUp() OVERRIDE {
- // FocusController registers itself as an Env observer so it can catch all
- // window initializations, including the root_window()'s, so we create it
- // before allowing the base setup.
- test_focus_rules_ = new TestFocusRules;
- focus_controller_.reset(new FocusController(test_focus_rules_));
- aura::test::AuraTestBase::SetUp();
- root_window()->AddPreTargetHandler(focus_controller_.get());
- aura::client::SetFocusClient(root_window(), focus_controller_.get());
- aura::client::SetActivationClient(root_window(), focus_controller_.get());
-
- // Hierarchy used by all tests:
- // root_window
- // +-- w1
- // | +-- w11
- // | +-- w12
- // +-- w2
- // | +-- w21
- // | +-- w211
- // +-- w3
- aura::Window* w1 = aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 1,
- gfx::Rect(0, 0, 50, 50), root_window());
- aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 11,
- gfx::Rect(5, 5, 10, 10), w1);
- aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 12,
- gfx::Rect(15, 15, 10, 10), w1);
- aura::Window* w2 = aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 2,
- gfx::Rect(75, 75, 50, 50), root_window());
- aura::Window* w21 = aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 21,
- gfx::Rect(5, 5, 10, 10), w2);
- aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 211,
- gfx::Rect(1, 1, 5, 5), w21);
- aura::test::CreateTestWindowWithDelegate(
- aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 3,
- gfx::Rect(125, 125, 50, 50), root_window());
- }
- virtual void TearDown() OVERRIDE {
- root_window()->RemovePreTargetHandler(focus_controller_.get());
- aura::test::AuraTestBase::TearDown();
- test_focus_rules_ = NULL; // Owned by FocusController.
- focus_controller_.reset();
- }
-
- void FocusWindow(aura::Window* window) {
- aura::client::GetFocusClient(root_window())->FocusWindow(window);
- }
- aura::Window* GetFocusedWindow() {
- return aura::client::GetFocusClient(root_window())->GetFocusedWindow();
- }
- int GetFocusedWindowId() {
- aura::Window* focused_window = GetFocusedWindow();
- return focused_window ? focused_window->id() : -1;
- }
- void ActivateWindow(aura::Window* window) {
- aura::client::GetActivationClient(root_window())->ActivateWindow(window);
- }
- void DeactivateWindow(aura::Window* window) {
- aura::client::GetActivationClient(root_window())->DeactivateWindow(window);
- }
- aura::Window* GetActiveWindow() {
- return aura::client::GetActivationClient(root_window())->GetActiveWindow();
- }
- int GetActiveWindowId() {
- aura::Window* active_window = GetActiveWindow();
- return active_window ? active_window->id() : -1;
- }
-
- TestFocusRules* test_focus_rules() { return test_focus_rules_; }
-
- // Test functions.
- virtual void BasicFocus() = 0;
- virtual void BasicActivation() = 0;
- virtual void FocusEvents() = 0;
- virtual void DuplicateFocusEvents() {}
- virtual void ActivationEvents() = 0;
- virtual void ReactivationEvents() {}
- virtual void DuplicateActivationEvents() {}
- virtual void ShiftFocusWithinActiveWindow() {}
- virtual void ShiftFocusToChildOfInactiveWindow() {}
- virtual void ShiftFocusToParentOfFocusedWindow() {}
- virtual void FocusRulesOverride() = 0;
- virtual void ActivationRulesOverride() = 0;
- virtual void ShiftFocusOnActivation() {}
- virtual void ShiftFocusOnActivationDueToHide() {}
- virtual void NoShiftActiveOnActivation() {}
- virtual void NoFocusChangeOnClickOnCaptureWindow() {}
- virtual void ChangeFocusWhenNothingFocusedAndCaptured() {}
- virtual void DontPassDeletedWindow() {}
-
- private:
- scoped_ptr<FocusController> focus_controller_;
- TestFocusRules* test_focus_rules_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerTestBase);
-};
-
-// Test base for tests where focus is directly set to a target window.
-class FocusControllerDirectTestBase : public FocusControllerTestBase {
- protected:
- FocusControllerDirectTestBase() {}
-
- // Different test types shift focus in different ways.
- virtual void FocusWindowDirect(aura::Window* window) = 0;
- virtual void ActivateWindowDirect(aura::Window* window) = 0;
- virtual void DeactivateWindowDirect(aura::Window* window) = 0;
-
- // Input events do not change focus if the window can not be focused.
- virtual bool IsInputEvent() = 0;
-
- void FocusWindowById(int id) {
- aura::Window* window = root_window()->GetChildById(id);
- DCHECK(window);
- FocusWindowDirect(window);
- }
- void ActivateWindowById(int id) {
- aura::Window* window = root_window()->GetChildById(id);
- DCHECK(window);
- ActivateWindowDirect(window);
- }
-
- // Overridden from FocusControllerTestBase:
- virtual void BasicFocus() OVERRIDE {
- EXPECT_EQ(NULL, GetFocusedWindow());
- FocusWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
- FocusWindowById(2);
- EXPECT_EQ(2, GetFocusedWindowId());
- }
- virtual void BasicActivation() OVERRIDE {
- EXPECT_EQ(NULL, GetActiveWindow());
- ActivateWindowById(1);
- EXPECT_EQ(1, GetActiveWindowId());
- ActivateWindowById(2);
- EXPECT_EQ(2, GetActiveWindowId());
- // Verify that attempting to deactivate NULL does not crash and does not
- // change activation.
- DeactivateWindow(NULL);
- EXPECT_EQ(2, GetActiveWindowId());
- DeactivateWindow(GetActiveWindow());
- EXPECT_EQ(1, GetActiveWindowId());
- }
- virtual void FocusEvents() OVERRIDE {
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
- ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
-
- root_observer.ExpectCounts(0, 0);
- observer1.ExpectCounts(0, 0);
- observer2.ExpectCounts(0, 0);
-
- FocusWindowById(1);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
- observer2.ExpectCounts(0, 0);
-
- FocusWindowById(2);
- root_observer.ExpectCounts(2, 2);
- observer1.ExpectCounts(2, 2);
- observer2.ExpectCounts(1, 1);
- }
- virtual void DuplicateFocusEvents() OVERRIDE {
- // Focusing an existing focused window should not resend focus events.
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
-
- root_observer.ExpectCounts(0, 0);
- observer1.ExpectCounts(0, 0);
-
- FocusWindowById(1);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
-
- FocusWindowById(1);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
- }
- virtual void ActivationEvents() OVERRIDE {
- ActivateWindowById(1);
-
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
- ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
-
- root_observer.ExpectCounts(0, 0);
- observer1.ExpectCounts(0, 0);
- observer2.ExpectCounts(0, 0);
-
- ActivateWindowById(2);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
- observer2.ExpectCounts(1, 1);
- }
- virtual void ReactivationEvents() OVERRIDE {
- ActivateWindowById(1);
- ScopedFocusNotificationObserver root_observer(root_window());
- EXPECT_EQ(0, root_observer.reactivation_count());
- root_window()->GetChildById(2)->Hide();
- // When we attempt to activate "2", which cannot be activated because it
- // is not visible, "1" will be reactivated.
- ActivateWindowById(2);
- EXPECT_EQ(1, root_observer.reactivation_count());
- EXPECT_EQ(root_window()->GetChildById(2),
- root_observer.reactivation_requested_window());
- EXPECT_EQ(root_window()->GetChildById(1),
- root_observer.reactivation_actual_window());
- }
- virtual void DuplicateActivationEvents() OVERRIDE {
- // Activating an existing active window should not resend activation events.
- ActivateWindowById(1);
-
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
- ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
-
- root_observer.ExpectCounts(0, 0);
- observer1.ExpectCounts(0, 0);
- observer2.ExpectCounts(0, 0);
-
- ActivateWindowById(2);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
- observer2.ExpectCounts(1, 1);
-
- ActivateWindowById(2);
- root_observer.ExpectCounts(1, 1);
- observer1.ExpectCounts(1, 1);
- observer2.ExpectCounts(1, 1);
- }
- virtual void ShiftFocusWithinActiveWindow() OVERRIDE {
- ActivateWindowById(1);
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
- FocusWindowById(11);
- EXPECT_EQ(11, GetFocusedWindowId());
- FocusWindowById(12);
- EXPECT_EQ(12, GetFocusedWindowId());
- }
- virtual void ShiftFocusToChildOfInactiveWindow() OVERRIDE {
- ActivateWindowById(2);
- EXPECT_EQ(2, GetActiveWindowId());
- EXPECT_EQ(2, GetFocusedWindowId());
- FocusWindowById(11);
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(11, GetFocusedWindowId());
- }
- virtual void ShiftFocusToParentOfFocusedWindow() OVERRIDE {
- ActivateWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
- FocusWindowById(11);
- EXPECT_EQ(11, GetFocusedWindowId());
- FocusWindowById(1);
- // Focus should _not_ shift to the parent of the already-focused window.
- EXPECT_EQ(11, GetFocusedWindowId());
- }
- virtual void FocusRulesOverride() OVERRIDE {
- EXPECT_EQ(NULL, GetFocusedWindow());
- FocusWindowById(11);
- EXPECT_EQ(11, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(root_window()->GetChildById(211));
- FocusWindowById(12);
- // Input events leave focus unchanged; direct API calls will change focus
- // to the restricted window.
- int focused_window = IsInputEvent() ? 11 : 211;
- EXPECT_EQ(focused_window, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(NULL);
- FocusWindowById(12);
- EXPECT_EQ(12, GetFocusedWindowId());
- }
- virtual void ActivationRulesOverride() OVERRIDE {
- ActivateWindowById(1);
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
-
- aura::Window* w3 = root_window()->GetChildById(3);
- test_focus_rules()->set_focus_restriction(w3);
-
- ActivateWindowById(2);
- // Input events leave activation unchanged; direct API calls will activate
- // the restricted window.
- int active_window = IsInputEvent() ? 1 : 3;
- EXPECT_EQ(active_window, GetActiveWindowId());
- EXPECT_EQ(active_window, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(NULL);
- ActivateWindowById(2);
- EXPECT_EQ(2, GetActiveWindowId());
- EXPECT_EQ(2, GetFocusedWindowId());
- }
- virtual void ShiftFocusOnActivation() OVERRIDE {
- // When a window is activated, by default that window is also focused.
- // An ActivationChangeObserver may shift focus to another window within the
- // same activatable window.
- ActivateWindowById(2);
- EXPECT_EQ(2, GetFocusedWindowId());
- ActivateWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
-
- ActivateWindowById(2);
-
- aura::Window* target = root_window()->GetChildById(1);
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(root_window());
-
- scoped_ptr<FocusShiftingActivationObserver> observer(
- new FocusShiftingActivationObserver(target));
- observer->set_shift_focus_to(target->GetChildById(11));
- client->AddObserver(observer.get());
-
- ActivateWindowById(1);
-
- // w1's ActivationChangeObserver shifted focus to this child, pre-empting
- // FocusController's default setting.
- EXPECT_EQ(11, GetFocusedWindowId());
-
- ActivateWindowById(2);
- EXPECT_EQ(2, GetFocusedWindowId());
-
- // Simulate a focus reset by the ActivationChangeObserver. This should
- // trigger the default setting in FocusController.
- observer->set_shift_focus_to(NULL);
- ActivateWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
-
- client->RemoveObserver(observer.get());
-
- ActivateWindowById(2);
- EXPECT_EQ(2, GetFocusedWindowId());
- ActivateWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
- }
- virtual void ShiftFocusOnActivationDueToHide() OVERRIDE {
- // Similar to ShiftFocusOnActivation except the activation change is
- // triggered by hiding the active window.
- ActivateWindowById(1);
- EXPECT_EQ(1, GetFocusedWindowId());
-
- // Removes window 3 as candidate for next activatable window.
- root_window()->GetChildById(3)->Hide();
- EXPECT_EQ(1, GetFocusedWindowId());
-
- aura::Window* target = root_window()->GetChildById(2);
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(root_window());
-
- scoped_ptr<FocusShiftingActivationObserver> observer(
- new FocusShiftingActivationObserver(target));
- observer->set_shift_focus_to(target->GetChildById(21));
- client->AddObserver(observer.get());
-
- // Hide the active window.
- root_window()->GetChildById(1)->Hide();
-
- EXPECT_EQ(21, GetFocusedWindowId());
-
- client->RemoveObserver(observer.get());
- }
- virtual void NoShiftActiveOnActivation() OVERRIDE {
- // When a window is activated, we need to prevent any change to activation
- // from being made in response to an activation change notification.
- }
-
- virtual void NoFocusChangeOnClickOnCaptureWindow() OVERRIDE {
- scoped_ptr<aura::client::DefaultCaptureClient> capture_client(
- new aura::client::DefaultCaptureClient(root_window()));
- // Clicking on a window which has capture should not cause a focus change
- // to the window. This test verifies whether that is indeed the case.
- ActivateWindowById(1);
-
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
-
- aura::Window* w2 = root_window()->GetChildById(2);
- aura::client::GetCaptureClient(root_window())->SetCapture(w2);
- aura::test::EventGenerator generator(root_window(), w2);
- generator.ClickLeftButton();
-
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
- aura::client::GetCaptureClient(root_window())->ReleaseCapture(w2);
- }
-
- // Verifies focus change is honored while capture held.
- virtual void ChangeFocusWhenNothingFocusedAndCaptured() OVERRIDE {
- scoped_ptr<aura::client::DefaultCaptureClient> capture_client(
- new aura::client::DefaultCaptureClient(root_window()));
- aura::Window* w1 = root_window()->GetChildById(1);
- aura::client::GetCaptureClient(root_window())->SetCapture(w1);
-
- EXPECT_EQ(-1, GetActiveWindowId());
- EXPECT_EQ(-1, GetFocusedWindowId());
-
- FocusWindowById(1);
-
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
-
- aura::client::GetCaptureClient(root_window())->ReleaseCapture(w1);
- }
-
- // Verfies if a window that loses activation is deleted during observer
- // notification we don't pass the deleted window to other observers.
- virtual void DontPassDeletedWindow() OVERRIDE {
- FocusWindowById(1);
-
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
-
- DeleteOnLoseActivationChangeObserver observer1(
- root_window()->GetChildById(1));
- RecordingActivationChangeObserver observer2(root_window());
-
- FocusWindowById(2);
-
- EXPECT_EQ(2, GetActiveWindowId());
- EXPECT_EQ(2, GetFocusedWindowId());
-
- EXPECT_TRUE(observer1.did_delete());
- ASSERT_EQ(1u, observer2.lost().size());
- EXPECT_TRUE(observer2.lost()[0] == NULL);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerDirectTestBase);
-};
-
-// Focus and Activation changes via aura::client::ActivationClient API.
-class FocusControllerApiTest : public FocusControllerDirectTestBase {
- public:
- FocusControllerApiTest() {}
-
- private:
- // Overridden from FocusControllerTestBase:
- virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
- FocusWindow(window);
- }
- virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
- ActivateWindow(window);
- }
- virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
- DeactivateWindow(window);
- }
- virtual bool IsInputEvent() OVERRIDE { return false; }
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerApiTest);
-};
-
-// Focus and Activation changes via input events.
-class FocusControllerMouseEventTest : public FocusControllerDirectTestBase {
- public:
- FocusControllerMouseEventTest() {}
-
- private:
- // Overridden from FocusControllerTestBase:
- virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
- aura::test::EventGenerator generator(root_window(), window);
- generator.ClickLeftButton();
- }
- virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
- aura::test::EventGenerator generator(root_window(), window);
- generator.ClickLeftButton();
- }
- virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
- aura::Window* next_activatable =
- test_focus_rules()->GetNextActivatableWindow(window);
- aura::test::EventGenerator generator(root_window(), next_activatable);
- generator.ClickLeftButton();
- }
- virtual bool IsInputEvent() OVERRIDE { return true; }
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerMouseEventTest);
-};
-
-class FocusControllerGestureEventTest : public FocusControllerDirectTestBase {
- public:
- FocusControllerGestureEventTest() {}
-
- private:
- // Overridden from FocusControllerTestBase:
- virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
- aura::test::EventGenerator generator(root_window(), window);
- generator.GestureTapAt(window->bounds().CenterPoint());
- }
- virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
- aura::test::EventGenerator generator(root_window(), window);
- generator.GestureTapAt(window->bounds().CenterPoint());
- }
- virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
- aura::Window* next_activatable =
- test_focus_rules()->GetNextActivatableWindow(window);
- aura::test::EventGenerator generator(root_window(), next_activatable);
- generator.GestureTapAt(window->bounds().CenterPoint());
- }
- virtual bool IsInputEvent() OVERRIDE { return true; }
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerGestureEventTest);
-};
-
-// Test base for tests where focus is implicitly set to a window as the result
-// of a disposition change to the focused window or the hierarchy that contains
-// it.
-class FocusControllerImplicitTestBase : public FocusControllerTestBase {
- protected:
- explicit FocusControllerImplicitTestBase(bool parent) : parent_(parent) {}
-
- aura::Window* GetDispositionWindow(aura::Window* window) {
- return parent_ ? window->parent() : window;
- }
-
- // Change the disposition of |window| in such a way as it will lose focus.
- virtual void ChangeWindowDisposition(aura::Window* window) = 0;
-
- // Allow each disposition change test to add additional post-disposition
- // change expectations.
- virtual void PostDispostionChangeExpectations() {}
-
- // Overridden from FocusControllerTestBase:
- virtual void BasicFocus() OVERRIDE {
- EXPECT_EQ(NULL, GetFocusedWindow());
-
- aura::Window* w211 = root_window()->GetChildById(211);
- FocusWindow(w211);
- EXPECT_EQ(211, GetFocusedWindowId());
-
- ChangeWindowDisposition(w211);
- // BasicFocusRules passes focus to the parent.
- EXPECT_EQ(parent_ ? 2 : 21, GetFocusedWindowId());
- }
- virtual void BasicActivation() OVERRIDE {
- DCHECK(!parent_) << "Activation tests don't support parent changes.";
-
- EXPECT_EQ(NULL, GetActiveWindow());
-
- aura::Window* w2 = root_window()->GetChildById(2);
- ActivateWindow(w2);
- EXPECT_EQ(2, GetActiveWindowId());
-
- ChangeWindowDisposition(w2);
- EXPECT_EQ(3, GetActiveWindowId());
- PostDispostionChangeExpectations();
- }
- virtual void FocusEvents() OVERRIDE {
- aura::Window* w211 = root_window()->GetChildById(211);
- FocusWindow(w211);
-
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer211(root_window(), 211);
- root_observer.ExpectCounts(0, 0);
- observer211.ExpectCounts(0, 0);
-
- ChangeWindowDisposition(w211);
- root_observer.ExpectCounts(0, 1);
- observer211.ExpectCounts(0, 1);
- }
- virtual void ActivationEvents() OVERRIDE {
- DCHECK(!parent_) << "Activation tests don't support parent changes.";
-
- aura::Window* w2 = root_window()->GetChildById(2);
- ActivateWindow(w2);
-
- ScopedFocusNotificationObserver root_observer(root_window());
- ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
- ScopedTargetFocusNotificationObserver observer3(root_window(), 3);
- root_observer.ExpectCounts(0, 0);
- observer2.ExpectCounts(0, 0);
- observer3.ExpectCounts(0, 0);
-
- ChangeWindowDisposition(w2);
- root_observer.ExpectCounts(1, 1);
- observer2.ExpectCounts(1, 1);
- observer3.ExpectCounts(1, 1);
- }
- virtual void FocusRulesOverride() OVERRIDE {
- EXPECT_EQ(NULL, GetFocusedWindow());
- aura::Window* w211 = root_window()->GetChildById(211);
- FocusWindow(w211);
- EXPECT_EQ(211, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(root_window()->GetChildById(11));
- ChangeWindowDisposition(w211);
- // Normally, focus would shift to the parent (w21) but the override shifts
- // it to 11.
- EXPECT_EQ(11, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(NULL);
- }
- virtual void ActivationRulesOverride() OVERRIDE {
- DCHECK(!parent_) << "Activation tests don't support parent changes.";
-
- aura::Window* w1 = root_window()->GetChildById(1);
- ActivateWindow(w1);
-
- EXPECT_EQ(1, GetActiveWindowId());
- EXPECT_EQ(1, GetFocusedWindowId());
-
- aura::Window* w3 = root_window()->GetChildById(3);
- test_focus_rules()->set_focus_restriction(w3);
-
- // Normally, activation/focus would move to w2, but since we have a focus
- // restriction, it should move to w3 instead.
- ChangeWindowDisposition(w1);
- EXPECT_EQ(3, GetActiveWindowId());
- EXPECT_EQ(3, GetFocusedWindowId());
-
- test_focus_rules()->set_focus_restriction(NULL);
- ActivateWindow(root_window()->GetChildById(2));
- EXPECT_EQ(2, GetActiveWindowId());
- EXPECT_EQ(2, GetFocusedWindowId());
- }
-
- private:
- // When true, the disposition change occurs to the parent of the window
- // instead of to the window. This verifies that changes occurring in the
- // hierarchy that contains the window affect the window's focus.
- bool parent_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerImplicitTestBase);
-};
-
-// Focus and Activation changes in response to window visibility changes.
-class FocusControllerHideTest : public FocusControllerImplicitTestBase {
- public:
- FocusControllerHideTest() : FocusControllerImplicitTestBase(false) {}
-
- protected:
- FocusControllerHideTest(bool parent)
- : FocusControllerImplicitTestBase(parent) {}
-
- // Overridden from FocusControllerImplicitTestBase:
- virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
- GetDispositionWindow(window)->Hide();
- }
- virtual void PostDispostionChangeExpectations() OVERRIDE {
- // BasicActivation() starts with the stacking order: 1, 2, 3 (3 topmost)
- // and then activates 2. After 2 is hidden in ChangeWindowDisposition
- // above, 3 is activated, but code in
- // FocusController::OnWindowVisibilityChanging keeps 2's layer above 3's
- // until a hide animation completes (e.g. a fade-out transition).
- aura::Window* w2 = root_window()->GetChildById(2);
- aura::Window* w3 = root_window()->GetChildById(3);
-
- // W2 was hidden, but its layer should still be stacked above W3's.
- typedef std::vector<ui::Layer*> Layers;
- const Layers& children = w3->parent()->layer()->children();
- Layers::const_iterator w3_iter =
- std::find(children.begin(), children.end(), w3->layer());
- Layers::const_iterator w2_iter =
- std::find(children.begin(), children.end(), w2->layer());
- EXPECT_TRUE(w2_iter > w3_iter);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerHideTest);
-};
-
-// Focus and Activation changes in response to window parent visibility
-// changes.
-class FocusControllerParentHideTest : public FocusControllerHideTest {
- public:
- FocusControllerParentHideTest() : FocusControllerHideTest(true) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerParentHideTest);
-};
-
-// Focus and Activation changes in response to window destruction.
-class FocusControllerDestructionTest : public FocusControllerImplicitTestBase {
- public:
- FocusControllerDestructionTest() : FocusControllerImplicitTestBase(false) {}
-
- protected:
- FocusControllerDestructionTest(bool parent)
- : FocusControllerImplicitTestBase(parent) {}
-
- // Overridden from FocusControllerImplicitTestBase:
- virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
- delete GetDispositionWindow(window);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerDestructionTest);
-};
-
-// Focus and Activation changes in response to window parent destruction.
-class FocusControllerParentDestructionTest
- : public FocusControllerDestructionTest {
- public:
- FocusControllerParentDestructionTest()
- : FocusControllerDestructionTest(true) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerParentDestructionTest);
-};
-
-// Focus and Activation changes in response to window removal.
-class FocusControllerRemovalTest : public FocusControllerImplicitTestBase {
- public:
- FocusControllerRemovalTest() : FocusControllerImplicitTestBase(false) {}
-
- protected:
- FocusControllerRemovalTest(bool parent)
- : FocusControllerImplicitTestBase(parent) {}
-
- // Overridden from FocusControllerImplicitTestBase:
- virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
- aura::Window* disposition_window = GetDispositionWindow(window);
- disposition_window->parent()->RemoveChild(disposition_window);
- window_owner_.reset(disposition_window);
- }
- virtual void TearDown() OVERRIDE {
- window_owner_.reset();
- FocusControllerImplicitTestBase::TearDown();
- }
-
- private:
- scoped_ptr<aura::Window> window_owner_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusControllerRemovalTest);
-};
-
-// Focus and Activation changes in response to window parent removal.
-class FocusControllerParentRemovalTest : public FocusControllerRemovalTest {
- public:
- FocusControllerParentRemovalTest() : FocusControllerRemovalTest(true) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusControllerParentRemovalTest);
-};
-
-
-#define FOCUS_CONTROLLER_TEST(TESTCLASS, TESTNAME) \
- TEST_F(TESTCLASS, TESTNAME) { TESTNAME(); }
-
-// Runs direct focus change tests (input events and API calls).
-#define DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerApiTest, TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerGestureEventTest, TESTNAME)
-
-// Runs implicit focus change tests for disposition changes to target.
-#define IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerHideTest, TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerDestructionTest, TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerRemovalTest, TESTNAME)
-
-// Runs implicit focus change tests for disposition changes to target's parent
-// hierarchy.
-#define IMPLICIT_FOCUS_CHANGE_PARENT_TESTS(TESTNAME) \
- /* TODO(beng): parent destruction tests are not supported at
- present due to workspace manager issues. \
- FOCUS_CONTROLLER_TEST(FocusControllerParentDestructionTest, TESTNAME) */ \
- FOCUS_CONTROLLER_TEST(FocusControllerParentHideTest, TESTNAME) \
- FOCUS_CONTROLLER_TEST(FocusControllerParentRemovalTest, TESTNAME)
-
-// Runs all implicit focus change tests (changes to the target and target's
-// parent hierarchy)
-#define IMPLICIT_FOCUS_CHANGE_TESTS(TESTNAME) \
- IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME) \
- IMPLICIT_FOCUS_CHANGE_PARENT_TESTS(TESTNAME)
-
-// Runs all possible focus change tests.
-#define ALL_FOCUS_TESTS(TESTNAME) \
- DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
- IMPLICIT_FOCUS_CHANGE_TESTS(TESTNAME)
-
-// Runs focus change tests that apply only to the target. For example,
-// implicit activation changes caused by window disposition changes do not
-// occur when changes to the containing hierarchy happen.
-#define TARGET_FOCUS_TESTS(TESTNAME) \
- DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
- IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME)
-
-// - Focuses a window, verifies that focus changed.
-ALL_FOCUS_TESTS(BasicFocus);
-
-// - Activates a window, verifies that activation changed.
-TARGET_FOCUS_TESTS(BasicActivation);
-
-// - Focuses a window, verifies that focus events were dispatched.
-ALL_FOCUS_TESTS(FocusEvents);
-
-// - Focuses or activates a window multiple times, verifies that events are only
-// dispatched when focus/activation actually changes.
-DIRECT_FOCUS_CHANGE_TESTS(DuplicateFocusEvents);
-DIRECT_FOCUS_CHANGE_TESTS(DuplicateActivationEvents);
-
-// - Activates a window, verifies that activation events were dispatched.
-TARGET_FOCUS_TESTS(ActivationEvents);
-
-// - Attempts to active a hidden window, verifies that current window is
-// attempted to be reactivated and the appropriate event dispatched.
-FOCUS_CONTROLLER_TEST(FocusControllerApiTest, ReactivationEvents);
-
-// - Input events/API calls shift focus between focusable windows within the
-// active window.
-DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusWithinActiveWindow);
-
-// - Input events/API calls to a child window of an inactive window shifts
-// activation to the activatable parent and focuses the child.
-DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToChildOfInactiveWindow);
-
-// - Input events/API calls to focus the parent of the focused window do not
-// shift focus away from the child.
-DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToParentOfFocusedWindow);
-
-// - Verifies that FocusRules determine what can be focused.
-ALL_FOCUS_TESTS(FocusRulesOverride);
-
-// - Verifies that FocusRules determine what can be activated.
-TARGET_FOCUS_TESTS(ActivationRulesOverride);
-
-// - Verifies that attempts to change focus or activation from a focus or
-// activation change observer are ignored.
-DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivation);
-DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivationDueToHide);
-DIRECT_FOCUS_CHANGE_TESTS(NoShiftActiveOnActivation);
-
-// Clicking on a window which has capture should not result in a focus change.
-DIRECT_FOCUS_CHANGE_TESTS(NoFocusChangeOnClickOnCaptureWindow);
-
-FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
- ChangeFocusWhenNothingFocusedAndCaptured);
-
-// See description above DontPassDeletedWindow() for details.
-FOCUS_CONTROLLER_TEST(FocusControllerApiTest, DontPassDeletedWindow);
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/focus_rules.h b/chromium/ui/views/corewm/focus_rules.h
deleted file mode 100644
index 559a2385432..00000000000
--- a/chromium/ui/views/corewm/focus_rules.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_FOCUS_RULES_H_
-#define UI_VIEWS_COREWM_FOCUS_RULES_H_
-
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-}
-
-namespace views {
-namespace corewm {
-
-// Implemented by an object that establishes the rules about what can be
-// focused or activated.
-class VIEWS_EXPORT FocusRules {
- public:
- virtual ~FocusRules() {}
-
- // Returns true if |window| is a toplevel window. Whether or not a window
- // is considered toplevel is determined by a similar set of rules that
- // govern activation and focus. Not all toplevel windows are activatable,
- // call CanActivateWindow() to determine if a window can be activated.
- virtual bool IsToplevelWindow(aura::Window* window) const = 0;
- // Returns true if |window| can be activated or focused.
- virtual bool CanActivateWindow(aura::Window* window) const = 0;
- // For CanFocusWindow(), NULL is supported, because NULL is a valid focusable
- // window (in the case of clearing focus).
- virtual bool CanFocusWindow(aura::Window* window) const = 0;
-
- // Returns the toplevel window containing |window|. Not all toplevel windows
- // are activatable, call GetActivatableWindow() instead to return the
- // activatable window, which might be in a different hierarchy.
- // Will return NULL if |window| is not contained by a window considered to be
- // a toplevel window.
- virtual aura::Window* GetToplevelWindow(aura::Window* window) const = 0;
- // Returns the activatable or focusable window given an attempt to activate or
- // focus |window|. Some possible scenarios (not intended to be exhaustive):
- // - |window| is a child of a non-focusable window and so focus must be set
- // according to rules defined by the delegate, e.g. to a parent.
- // - |window| is an activatable window that is the transient parent of a modal
- // window, so attempts to activate |window| should result in the modal
- // transient being activated instead.
- // These methods may return NULL if they are unable to find an activatable
- // or focusable window given |window|.
- virtual aura::Window* GetActivatableWindow(aura::Window* window) const = 0;
- virtual aura::Window* GetFocusableWindow(aura::Window* window) const = 0;
-
- // Returns the next window to activate in the event that |ignore| is no longer
- // activatable. This function is called when something is happening to
- // |ignore| that means it can no longer have focus or activation, including
- // but not limited to:
- // - it or its parent hierarchy is being hidden, or removed from the
- // RootWindow.
- // - it is being destroyed.
- // - it is being explicitly deactivated.
- // |ignore| cannot be NULL.
- virtual aura::Window* GetNextActivatableWindow(
- aura::Window* ignore) const = 0;
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_FOCUS_RULES_H_
diff --git a/chromium/ui/views/corewm/image_grid.cc b/chromium/ui/views/corewm/image_grid.cc
deleted file mode 100644
index 29c775773c7..00000000000
--- a/chromium/ui/views/corewm/image_grid.cc
+++ /dev/null
@@ -1,308 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/image_grid.h"
-
-#include <algorithm>
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkXfermode.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/transform.h"
-
-using std::max;
-using std::min;
-
-namespace views {
-namespace corewm {
-
-gfx::RectF ImageGrid::TestAPI::GetTransformedLayerBounds(
- const ui::Layer& layer) {
- gfx::RectF bounds = layer.bounds();
- layer.transform().TransformRect(&bounds);
- return bounds;
-}
-
-ImageGrid::ImageGrid()
- : layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)),
- top_image_height_(0),
- bottom_image_height_(0),
- left_image_width_(0),
- right_image_width_(0),
- base_top_row_height_(0),
- base_bottom_row_height_(0),
- base_left_column_width_(0),
- base_right_column_width_(0) {
-}
-
-ImageGrid::~ImageGrid() {
-}
-
-void ImageGrid::SetImages(const gfx::Image* top_left_image,
- const gfx::Image* top_image,
- const gfx::Image* top_right_image,
- const gfx::Image* left_image,
- const gfx::Image* center_image,
- const gfx::Image* right_image,
- const gfx::Image* bottom_left_image,
- const gfx::Image* bottom_image,
- const gfx::Image* bottom_right_image) {
- SetImage(top_left_image, &top_left_layer_, &top_left_painter_);
- SetImage(top_image, &top_layer_, &top_painter_);
- SetImage(top_right_image, &top_right_layer_, &top_right_painter_);
- SetImage(left_image, &left_layer_, &left_painter_);
- SetImage(center_image, &center_layer_, &center_painter_);
- SetImage(right_image, &right_layer_, &right_painter_);
- SetImage(bottom_left_image, &bottom_left_layer_, &bottom_left_painter_);
- SetImage(bottom_image, &bottom_layer_, &bottom_painter_);
- SetImage(bottom_right_image, &bottom_right_layer_, &bottom_right_painter_);
-
- top_image_height_ = GetImageSize(top_image).height();
- bottom_image_height_ = GetImageSize(bottom_image).height();
- left_image_width_ = GetImageSize(left_image).width();
- right_image_width_ = GetImageSize(right_image).width();
-
- base_top_row_height_ = max(GetImageSize(top_left_image).height(),
- max(GetImageSize(top_image).height(),
- GetImageSize(top_right_image).height()));
- base_bottom_row_height_ = max(GetImageSize(bottom_left_image).height(),
- max(GetImageSize(bottom_image).height(),
- GetImageSize(bottom_right_image).height()));
- base_left_column_width_ = max(GetImageSize(top_left_image).width(),
- max(GetImageSize(left_image).width(),
- GetImageSize(bottom_left_image).width()));
- base_right_column_width_ = max(GetImageSize(top_right_image).width(),
- max(GetImageSize(right_image).width(),
- GetImageSize(bottom_right_image).width()));
-
- // Invalidate previous |size_| so calls to SetSize() will recompute it.
- size_.SetSize(0, 0);
-}
-
-void ImageGrid::SetSize(const gfx::Size& size) {
- if (size_ == size)
- return;
-
- size_ = size;
-
- gfx::Rect updated_bounds = layer_->bounds();
- updated_bounds.set_size(size);
- layer_->SetBounds(updated_bounds);
-
- // Calculate the available amount of space for corner images on all sides of
- // the grid. If the images don't fit, we need to clip them.
- const int left = min(base_left_column_width_, size_.width() / 2);
- const int right = min(base_right_column_width_, size_.width() - left);
- const int top = min(base_top_row_height_, size_.height() / 2);
- const int bottom = min(base_bottom_row_height_, size_.height() - top);
-
- // The remaining space goes to the center image.
- int center_width = std::max(size.width() - left - right, 0);
- int center_height = std::max(size.height() - top - bottom, 0);
-
- // At non-integer scale factors, the ratio of dimensions in DIP is not
- // necessarily the same as the ratio in physical pixels due to rounding. Set
- // the transform on each of the layers based on dimensions in pixels.
- gfx::Size center_size_in_pixels = gfx::ToFlooredSize(gfx::ScaleSize(
- gfx::Size(center_width, center_height), layer_->device_scale_factor()));
-
- if (top_layer_.get()) {
- if (center_width > 0) {
- gfx::Transform transform;
- transform.Translate(left, 0);
- ScaleWidth(center_size_in_pixels, top_layer_.get(), transform);
- top_layer_->SetTransform(transform);
- }
- top_layer_->SetVisible(center_width > 0);
- }
- if (bottom_layer_.get()) {
- if (center_width > 0) {
- gfx::Transform transform;
- transform.Translate(
- left, size.height() - bottom_layer_->bounds().height());
- ScaleWidth(center_size_in_pixels, bottom_layer_.get(), transform);
- bottom_layer_->SetTransform(transform);
- }
- bottom_layer_->SetVisible(center_width > 0);
- }
- if (left_layer_.get()) {
- if (center_height > 0) {
- gfx::Transform transform;
- transform.Translate(0, top);
- ScaleHeight(center_size_in_pixels, left_layer_.get(), transform);
- left_layer_->SetTransform(transform);
- }
- left_layer_->SetVisible(center_height > 0);
- }
- if (right_layer_.get()) {
- if (center_height > 0) {
- gfx::Transform transform;
- transform.Translate(
- size.width() - right_layer_->bounds().width(), top);
- ScaleHeight(center_size_in_pixels, right_layer_.get(), transform);
- right_layer_->SetTransform(transform);
- }
- right_layer_->SetVisible(center_height > 0);
- }
-
- if (top_left_layer_.get()) {
- // No transformation needed; it should be at (0, 0) and unscaled.
- top_left_painter_->SetClipRect(
- LayerExceedsSize(top_left_layer_.get(), gfx::Size(left, top)) ?
- gfx::Rect(gfx::Rect(0, 0, left, top)) :
- gfx::Rect(),
- top_left_layer_.get());
- }
- if (top_right_layer_.get()) {
- gfx::Transform transform;
- transform.Translate(size.width() - top_right_layer_->bounds().width(), 0.0);
- top_right_layer_->SetTransform(transform);
- top_right_painter_->SetClipRect(
- LayerExceedsSize(top_right_layer_.get(), gfx::Size(right, top)) ?
- gfx::Rect(top_right_layer_->bounds().width() - right, 0,
- right, top) :
- gfx::Rect(),
- top_right_layer_.get());
- }
- if (bottom_left_layer_.get()) {
- gfx::Transform transform;
- transform.Translate(
- 0.0, size.height() - bottom_left_layer_->bounds().height());
- bottom_left_layer_->SetTransform(transform);
- bottom_left_painter_->SetClipRect(
- LayerExceedsSize(bottom_left_layer_.get(), gfx::Size(left, bottom)) ?
- gfx::Rect(0, bottom_left_layer_->bounds().height() - bottom,
- left, bottom) :
- gfx::Rect(),
- bottom_left_layer_.get());
- }
- if (bottom_right_layer_.get()) {
- gfx::Transform transform;
- transform.Translate(
- size.width() - bottom_right_layer_->bounds().width(),
- size.height() - bottom_right_layer_->bounds().height());
- bottom_right_layer_->SetTransform(transform);
- bottom_right_painter_->SetClipRect(
- LayerExceedsSize(bottom_right_layer_.get(), gfx::Size(right, bottom)) ?
- gfx::Rect(bottom_right_layer_->bounds().width() - right,
- bottom_right_layer_->bounds().height() - bottom,
- right, bottom) :
- gfx::Rect(),
- bottom_right_layer_.get());
- }
-
- if (center_layer_.get()) {
- if (center_width > 0 && center_height > 0) {
- gfx::Transform transform;
- transform.Translate(left, top);
- transform.Scale(center_width / center_layer_->bounds().width(),
- center_height / center_layer_->bounds().height());
- center_layer_->SetTransform(transform);
- }
- center_layer_->SetVisible(center_width > 0 && center_height > 0);
- }
-}
-
-void ImageGrid::SetContentBounds(const gfx::Rect& content_bounds) {
-
- SetSize(gfx::Size(
- content_bounds.width() + left_image_width_ + right_image_width_,
- content_bounds.height() + top_image_height_ +
- bottom_image_height_));
- layer_->SetBounds(
- gfx::Rect(content_bounds.x() - left_image_width_,
- content_bounds.y() - top_image_height_,
- layer_->bounds().width(),
- layer_->bounds().height()));
-}
-
-void ImageGrid::ImagePainter::SetClipRect(const gfx::Rect& clip_rect,
- ui::Layer* layer) {
- if (clip_rect != clip_rect_) {
- clip_rect_ = clip_rect;
- layer->SchedulePaint(layer->bounds());
- }
-}
-
-void ImageGrid::ImagePainter::OnPaintLayer(gfx::Canvas* canvas) {
- if (!clip_rect_.IsEmpty())
- canvas->ClipRect(clip_rect_);
- canvas->DrawImageInt(*(image_->ToImageSkia()), 0, 0);
-}
-
-void ImageGrid::ImagePainter::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
- // Redrawing will take care of scale factor change.
-}
-
-base::Closure ImageGrid::ImagePainter::PrepareForLayerBoundsChange() {
- return base::Closure();
-}
-
-// static
-gfx::Size ImageGrid::GetImageSize(const gfx::Image* image) {
- return image ?
- gfx::Size(image->ToImageSkia()->width(), image->ToImageSkia()->height()) :
- gfx::Size();
-}
-
-// static
-bool ImageGrid::LayerExceedsSize(const ui::Layer* layer,
- const gfx::Size& size) {
- return layer->bounds().width() > size.width() ||
- layer->bounds().height() > size.height();
-}
-
-void ImageGrid::SetImage(const gfx::Image* image,
- scoped_ptr<ui::Layer>* layer_ptr,
- scoped_ptr<ImagePainter>* painter_ptr) {
- // Clean out old layers and painters.
- if (layer_ptr->get())
- layer_->Remove(layer_ptr->get());
- layer_ptr->reset();
- painter_ptr->reset();
-
- // If we're not using an image, we're done.
- if (!image)
- return;
-
- // Set up the new layer and painter.
- layer_ptr->reset(new ui::Layer(ui::LAYER_TEXTURED));
-
- const gfx::Size size = GetImageSize(image);
- layer_ptr->get()->SetBounds(gfx::Rect(0, 0, size.width(), size.height()));
-
- painter_ptr->reset(new ImagePainter(image));
- layer_ptr->get()->set_delegate(painter_ptr->get());
- layer_ptr->get()->SetFillsBoundsOpaquely(false);
- layer_ptr->get()->SetVisible(true);
- layer_->Add(layer_ptr->get());
-}
-
-void ImageGrid::ScaleWidth(gfx::Size center,
- ui::Layer* layer,
- gfx::Transform& transform) {
- int layer_width = ConvertSizeToPixel(layer,
- layer->bounds().size()).width();
- float scale = static_cast<float>(center.width()) / layer_width;
- transform.Scale(scale, 1.0);
-}
-
-void ImageGrid::ScaleHeight(gfx::Size center,
- ui::Layer* layer,
- gfx::Transform& transform) {
- int layer_height = ConvertSizeToPixel(layer,
- layer->bounds().size()).height();
- float scale = static_cast<float>(center.height()) / layer_height;
- transform.Scale(1.0, scale);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/image_grid.h b/chromium/ui/views/corewm/image_grid.h
deleted file mode 100644
index 51b1b56ee62..00000000000
--- a/chromium/ui/views/corewm/image_grid.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_IMAGE_GRID_H_
-#define UI_VIEWS_COREWM_IMAGE_GRID_H_
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_delegate.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Image;
-} // namespace gfx
-
-namespace views {
-namespace corewm {
-
-// An ImageGrid is a 3x3 array of ui::Layers, each containing an image.
-//
-// As the grid is resized, its images fill the requested space:
-// - corner images are not scaled
-// - top and bottom images are scaled horizontally
-// - left and right images are scaled vertically
-// - the center image is scaled in both directions
-//
-// If one of the non-center images is smaller than the largest images in its
-// row or column, it will be aligned with the outside of the grid. For
-// example, given 4x4 top-left and top-right images and a 1x2 top images:
-//
-// +--------+---------------------+--------+
-// | | top | |
-// | top- +---------------------+ top- +
-// | left | | right |
-// +----+---+ +---+----+
-// | | | |
-// ...
-//
-// This may seem odd at first, but it lets ImageGrid be used to draw shadows
-// with curved corners that extend inwards beyond a window's borders. In the
-// below example, the top-left corner image is overlaid on top of the window's
-// top-left corner:
-//
-// +---------+-----------------------
-// | ..xxx|XXXXXXXXXXXXXXXXXX
-// | .xXXXXX|XXXXXXXXXXXXXXXXXX_____
-// | .xXX | ^ window's top edge
-// | .xXX |
-// +---------+
-// | xXX|
-// | xXX|< window's left edge
-// | xXX|
-// ...
-//
-class VIEWS_EXPORT ImageGrid {
- public:
- // Helper class for use by tests.
- class VIEWS_EXPORT TestAPI {
- public:
- TestAPI(ImageGrid* grid) : grid_(grid) {}
-
- gfx::Rect top_left_clip_rect() const {
- return grid_->top_left_painter_->clip_rect_;
- }
- gfx::Rect top_right_clip_rect() const {
- return grid_->top_right_painter_->clip_rect_;
- }
- gfx::Rect bottom_left_clip_rect() const {
- return grid_->bottom_left_painter_->clip_rect_;
- }
- gfx::Rect bottom_right_clip_rect() const {
- return grid_->bottom_right_painter_->clip_rect_;
- }
-
- // Returns |layer|'s bounds after applying the layer's current transform.
- gfx::RectF GetTransformedLayerBounds(const ui::Layer& layer);
-
- private:
- ImageGrid* grid_; // not owned
-
- DISALLOW_COPY_AND_ASSIGN(TestAPI);
- };
-
- ImageGrid();
- ~ImageGrid();
-
- ui::Layer* layer() { return layer_.get(); }
- int top_image_height() const { return top_image_height_; }
- int bottom_image_height() const { return bottom_image_height_; }
- int left_image_width() const { return left_image_width_; }
- int right_image_width() const { return right_image_width_; }
-
- // Visible to allow independent layer animations and for testing.
- ui::Layer* top_left_layer() const { return top_left_layer_.get(); }
- ui::Layer* top_layer() const { return top_layer_.get(); }
- ui::Layer* top_right_layer() const { return top_right_layer_.get(); }
- ui::Layer* left_layer() const { return left_layer_.get(); }
- ui::Layer* center_layer() const { return center_layer_.get(); }
- ui::Layer* right_layer() const { return right_layer_.get(); }
- ui::Layer* bottom_left_layer() const { return bottom_left_layer_.get(); }
- ui::Layer* bottom_layer() const { return bottom_layer_.get(); }
- ui::Layer* bottom_right_layer() const { return bottom_right_layer_.get(); }
-
- // Sets the grid to display the passed-in images (any of which can be NULL).
- // Ownership of the images remains with the caller. May be called more than
- // once to switch images.
- void SetImages(const gfx::Image* top_left_image,
- const gfx::Image* top_image,
- const gfx::Image* top_right_image,
- const gfx::Image* left_image,
- const gfx::Image* center_image,
- const gfx::Image* right_image,
- const gfx::Image* bottom_left_image,
- const gfx::Image* bottom_image,
- const gfx::Image* bottom_right_image);
-
- void SetSize(const gfx::Size& size);
-
- // Sets the grid to a position and size such that the inner edges of the top,
- // bottom, left and right images will be flush with |content_bounds_in_dip|.
- void SetContentBounds(const gfx::Rect& content_bounds_in_dip);
-
- private:
- // Delegate responsible for painting a specific image on a layer.
- class ImagePainter : public ui::LayerDelegate {
- public:
- ImagePainter(const gfx::Image* image) : image_(image) {}
- virtual ~ImagePainter() {}
-
- // Clips |layer| to |clip_rect|. Triggers a repaint if the clipping
- // rectangle has changed. An empty rectangle disables clipping.
- void SetClipRect(const gfx::Rect& clip_rect, ui::Layer* layer);
-
- // ui::LayerDelegate implementation:
- virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE;
-
- private:
- friend class TestAPI;
-
- const gfx::Image* image_; // not owned
-
- gfx::Rect clip_rect_;
-
- DISALLOW_COPY_AND_ASSIGN(ImagePainter);
- };
-
- // Returns the dimensions of |image| if non-NULL or gfx::Size(0, 0) otherwise.
- static gfx::Size GetImageSize(const gfx::Image* image);
-
- // Returns true if |layer|'s bounds don't fit within |size|.
- static bool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size);
-
- // Sets |layer_ptr| and |painter_ptr| to display |image| and adds the
- // passed-in layer to |layer_|. If image is NULL resets |layer_ptr| and
- // |painter_ptr| and removes any existing layer from |layer_|.
- void SetImage(const gfx::Image* image,
- scoped_ptr<ui::Layer>* layer_ptr,
- scoped_ptr<ImagePainter>* painter_ptr);
-
- // Sets the scaling for the transform applied to a layer. The left, top,
- // right and bottom layers are stretched to the height or width of the
- // center image.
- void ScaleWidth(gfx::Size center,
- ui::Layer* layer,
- gfx::Transform& transform);
- void ScaleHeight(gfx::Size center,
- ui::Layer* layer,
- gfx::Transform& transform);
-
- // Layer that contains all of the image layers.
- scoped_ptr<ui::Layer> layer_;
-
- // The grid's dimensions.
- gfx::Size size_;
-
- // Heights and widths of the images displayed by |top_layer_|,
- // |bottom_layer_|, |left_layer_|, and |right_layer_|.
- int top_image_height_;
- int bottom_image_height_;
- int left_image_width_;
- int right_image_width_;
-
- // Heights of the tallest images in the top and bottom rows and the widest
- // images in the left and right columns. Note that we may have less actual
- // space than this available if the images are large and |size_| is small.
- int base_top_row_height_;
- int base_bottom_row_height_;
- int base_left_column_width_;
- int base_right_column_width_;
-
- // Layers used to display the various images. Children of |layer_|.
- // Positions for which no images were supplied are NULL.
- scoped_ptr<ui::Layer> top_left_layer_;
- scoped_ptr<ui::Layer> top_layer_;
- scoped_ptr<ui::Layer> top_right_layer_;
- scoped_ptr<ui::Layer> left_layer_;
- scoped_ptr<ui::Layer> center_layer_;
- scoped_ptr<ui::Layer> right_layer_;
- scoped_ptr<ui::Layer> bottom_left_layer_;
- scoped_ptr<ui::Layer> bottom_layer_;
- scoped_ptr<ui::Layer> bottom_right_layer_;
-
- // Delegates responsible for painting the above layers.
- // Positions for which no images were supplied are NULL.
- scoped_ptr<ImagePainter> top_left_painter_;
- scoped_ptr<ImagePainter> top_painter_;
- scoped_ptr<ImagePainter> top_right_painter_;
- scoped_ptr<ImagePainter> left_painter_;
- scoped_ptr<ImagePainter> center_painter_;
- scoped_ptr<ImagePainter> right_painter_;
- scoped_ptr<ImagePainter> bottom_left_painter_;
- scoped_ptr<ImagePainter> bottom_painter_;
- scoped_ptr<ImagePainter> bottom_right_painter_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageGrid);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_IMAGE_GRID_H_
diff --git a/chromium/ui/views/corewm/image_grid_unittest.cc b/chromium/ui/views/corewm/image_grid_unittest.cc
deleted file mode 100644
index 4b5508d733d..00000000000
--- a/chromium/ui/views/corewm/image_grid_unittest.cc
+++ /dev/null
@@ -1,341 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/views/corewm/image_grid.h"
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-// Creates a gfx::Image with the requested dimensions.
-gfx::Image* CreateImage(const gfx::Size& size) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
- return new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
-}
-
-} // namespace
-
-typedef ViewsTestBase ImageGridTest;
-
-// Test that an ImageGrid's layers are transformed correctly when SetSize() is
-// called.
-TEST_F(ImageGridTest, Basic) {
- // Size of the images around the grid's border.
- const int kBorder = 2;
-
- scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
- scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
- scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
- scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
-
- ImageGrid grid;
- grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
- image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
- image_BxB.get(), image_1xB.get(), image_BxB.get());
-
- ImageGrid::TestAPI test_api(&grid);
- ASSERT_TRUE(grid.top_left_layer() != NULL);
- ASSERT_TRUE(grid.top_layer() != NULL);
- ASSERT_TRUE(grid.top_right_layer() != NULL);
- ASSERT_TRUE(grid.left_layer() != NULL);
- ASSERT_TRUE(grid.center_layer() != NULL);
- ASSERT_TRUE(grid.right_layer() != NULL);
- ASSERT_TRUE(grid.bottom_left_layer() != NULL);
- ASSERT_TRUE(grid.bottom_layer() != NULL);
- ASSERT_TRUE(grid.bottom_right_layer() != NULL);
-
- const gfx::Size size(20, 30);
- grid.SetSize(size);
-
- // The top-left layer should be flush with the top-left corner and unscaled.
- EXPECT_EQ(gfx::RectF(0, 0, kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.top_left_layer()).ToString());
-
- // The top layer should be flush with the top edge and stretched horizontally
- // between the two top corners.
- EXPECT_EQ(gfx::RectF(
- kBorder, 0, size.width() - 2 * kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.top_layer()).ToString());
-
- // The top-right layer should be flush with the top-right corner and unscaled.
- EXPECT_EQ(gfx::RectF(size.width() - kBorder, 0, kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.top_right_layer()).ToString());
-
- // The left layer should be flush with the left edge and stretched vertically
- // between the two left corners.
- EXPECT_EQ(gfx::RectF(
- 0, kBorder, kBorder, size.height() - 2 * kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.left_layer()).ToString());
-
- // The center layer should fill the space in the middle of the grid.
- EXPECT_EQ(gfx::RectF(
- kBorder, kBorder, size.width() - 2 * kBorder,
- size.height() - 2 * kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.center_layer()).ToString());
-
- // The right layer should be flush with the right edge and stretched
- // vertically between the two right corners.
- EXPECT_EQ(gfx::RectF(
- size.width() - kBorder, kBorder,
- kBorder, size.height() - 2 * kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.right_layer()).ToString());
-
- // The bottom-left layer should be flush with the bottom-left corner and
- // unscaled.
- EXPECT_EQ(gfx::RectF(0, size.height() - kBorder, kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.bottom_left_layer()).ToString());
-
- // The bottom layer should be flush with the bottom edge and stretched
- // horizontally between the two bottom corners.
- EXPECT_EQ(gfx::RectF(
- kBorder, size.height() - kBorder,
- size.width() - 2 * kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.bottom_layer()).ToString());
-
- // The bottom-right layer should be flush with the bottom-right corner and
- // unscaled.
- EXPECT_EQ(gfx::RectF(
- size.width() - kBorder, size.height() - kBorder,
- kBorder, kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.bottom_right_layer()).ToString());
-}
-
-// Test that an ImageGrid's layers are transformed correctly when
-// SetContentBounds() is called.
-TEST_F(ImageGridTest, SetContentBounds) {
- // Size of the images around the grid's border.
- const int kBorder = 2;
-
- scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
- scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
- scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
- scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
-
- ImageGrid grid;
- grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
- image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
- image_BxB.get(), image_1xB.get(), image_BxB.get());
-
- ImageGrid::TestAPI test_api(&grid);
-
- const gfx::Point origin(5, 10);
- const gfx::Size size(20, 30);
- grid.SetContentBounds(gfx::Rect(origin, size));
-
- // The master layer is positioned above the top-left corner of the content
- // bounds and has height/width that contain the grid and bounds.
- EXPECT_EQ(gfx::RectF(origin.x() - kBorder,
- origin.y() - kBorder,
- size.width() + 2 * kBorder,
- size.height() + 2 * kBorder).ToString(),
- test_api.GetTransformedLayerBounds(*grid.layer()).ToString());
-}
-
-// Check that we don't crash if only a single image is supplied.
-TEST_F(ImageGridTest, SingleImage) {
- const int kBorder = 1;
- scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
-
- ImageGrid grid;
- grid.SetImages(NULL, image.get(), NULL,
- NULL, NULL, NULL,
- NULL, NULL, NULL);
-
- ImageGrid::TestAPI test_api(&grid);
- EXPECT_TRUE(grid.top_left_layer() == NULL);
- ASSERT_TRUE(grid.top_layer() != NULL);
- EXPECT_TRUE(grid.top_right_layer() == NULL);
- EXPECT_TRUE(grid.left_layer() == NULL);
- EXPECT_TRUE(grid.center_layer() == NULL);
- EXPECT_TRUE(grid.right_layer() == NULL);
- EXPECT_TRUE(grid.bottom_left_layer() == NULL);
- EXPECT_TRUE(grid.bottom_layer() == NULL);
- EXPECT_TRUE(grid.bottom_right_layer() == NULL);
-
- const gfx::Size kSize(10, 10);
- grid.SetSize(kSize);
-
- // The top layer should be scaled horizontally across the entire width, but it
- // shouldn't be scaled vertically.
- EXPECT_EQ(gfx::RectF(0, 0, kSize.width(), kBorder).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.top_layer()).ToString());
-}
-
-// Check that we don't crash when we reset existing images to NULL and
-// reset NULL images to new ones.
-TEST_F(ImageGridTest, ResetImages) {
- const int kBorder = 1;
- scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
-
- ImageGrid grid;
- grid.SetImages(NULL, image.get(), NULL,
- NULL, NULL, NULL,
- NULL, NULL, NULL);
-
- // Only the top edge has a layer.
- ImageGrid::TestAPI test_api(&grid);
- ASSERT_TRUE(grid.top_left_layer() == NULL);
- ASSERT_FALSE(grid.top_layer() == NULL);
- ASSERT_TRUE(grid.top_right_layer() == NULL);
- ASSERT_TRUE(grid.left_layer() == NULL);
- ASSERT_TRUE(grid.center_layer() == NULL);
- ASSERT_TRUE(grid.right_layer() == NULL);
- ASSERT_TRUE(grid.bottom_left_layer() == NULL);
- ASSERT_TRUE(grid.bottom_layer() == NULL);
- ASSERT_TRUE(grid.bottom_right_layer() == NULL);
-
- grid.SetImages(NULL, NULL, NULL,
- NULL, NULL, NULL,
- NULL, image.get(), NULL);
-
- // Now only the bottom edge has a layer.
- ASSERT_TRUE(grid.top_left_layer() == NULL);
- ASSERT_TRUE(grid.top_layer() == NULL);
- ASSERT_TRUE(grid.top_right_layer() == NULL);
- ASSERT_TRUE(grid.left_layer() == NULL);
- ASSERT_TRUE(grid.center_layer() == NULL);
- ASSERT_TRUE(grid.right_layer() == NULL);
- ASSERT_TRUE(grid.bottom_left_layer() == NULL);
- ASSERT_FALSE(grid.bottom_layer() == NULL);
- ASSERT_TRUE(grid.bottom_right_layer() == NULL);
-}
-
-// Test that side (top, left, right, bottom) layers that are narrower than their
-// adjacent corner layers stay pinned to the outside edges instead of getting
-// moved inwards or scaled. This exercises the scenario used for shadows.
-TEST_F(ImageGridTest, SmallerSides) {
- const int kCorner = 2;
- const int kEdge = 1;
-
- scoped_ptr<gfx::Image> top_left_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
- scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> top_right_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
- scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
-
- ImageGrid grid;
- grid.SetImages(top_left_image.get(), top_image.get(), top_right_image.get(),
- left_image.get(), NULL, right_image.get(),
- NULL, NULL, NULL);
- ImageGrid::TestAPI test_api(&grid);
-
- const gfx::Size kSize(20, 30);
- grid.SetSize(kSize);
-
- // The top layer should be flush with the top edge and stretched horizontally
- // between the two top corners.
- EXPECT_EQ(gfx::RectF(
- kCorner, 0, kSize.width() - 2 * kCorner, kEdge).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.top_layer()).ToString());
-
- // The left layer should be flush with the left edge and stretched vertically
- // between the top left corner and the bottom.
- EXPECT_EQ(gfx::RectF(
- 0, kCorner, kEdge, kSize.height() - kCorner).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.left_layer()).ToString());
-
- // The right layer should be flush with the right edge and stretched
- // vertically between the top right corner and the bottom.
- EXPECT_EQ(gfx::RectF(
- kSize.width() - kEdge, kCorner,
- kEdge, kSize.height() - kCorner).ToString(),
- test_api.GetTransformedLayerBounds(
- *grid.right_layer()).ToString());
-}
-
-// Test that we hide or clip layers as needed when the grid is assigned a small
-// size.
-TEST_F(ImageGridTest, TooSmall) {
- const int kCorner = 5;
- const int kCenter = 3;
- const int kEdge = 3;
-
- scoped_ptr<gfx::Image> top_left_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
- scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> top_right_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
- scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> center_image(CreateImage(gfx::Size(kCenter, kCenter)));
- scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> bottom_left_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
- scoped_ptr<gfx::Image> bottom_image(CreateImage(gfx::Size(kEdge, kEdge)));
- scoped_ptr<gfx::Image> bottom_right_image(
- CreateImage(gfx::Size(kCorner, kCorner)));
-
- ImageGrid grid;
- grid.SetImages(
- top_left_image.get(), top_image.get(), top_right_image.get(),
- left_image.get(), center_image.get(), right_image.get(),
- bottom_left_image.get(), bottom_image.get(), bottom_right_image.get());
- ImageGrid::TestAPI test_api(&grid);
-
- // Set a size that's smaller than the combined (unscaled) corner images.
- const gfx::Size kSmallSize(kCorner + kCorner - 3, kCorner + kCorner - 5);
- grid.SetSize(kSmallSize);
-
- // The scalable images around the sides and in the center should be hidden.
- EXPECT_FALSE(grid.top_layer()->visible());
- EXPECT_FALSE(grid.bottom_layer()->visible());
- EXPECT_FALSE(grid.left_layer()->visible());
- EXPECT_FALSE(grid.right_layer()->visible());
- EXPECT_FALSE(grid.center_layer()->visible());
-
- // The corner images' clip rects should sum to the expected size.
- EXPECT_EQ(kSmallSize.width(),
- test_api.top_left_clip_rect().width() +
- test_api.top_right_clip_rect().width());
- EXPECT_EQ(kSmallSize.width(),
- test_api.bottom_left_clip_rect().width() +
- test_api.bottom_right_clip_rect().width());
- EXPECT_EQ(kSmallSize.height(),
- test_api.top_left_clip_rect().height() +
- test_api.bottom_left_clip_rect().height());
- EXPECT_EQ(kSmallSize.height(),
- test_api.top_right_clip_rect().height() +
- test_api.bottom_right_clip_rect().height());
-
- // Resize the grid to be large enough to show all images.
- const gfx::Size kLargeSize(kCorner + kCorner + kCenter,
- kCorner + kCorner + kCenter);
- grid.SetSize(kLargeSize);
-
- // The scalable images should be visible now.
- EXPECT_TRUE(grid.top_layer()->visible());
- EXPECT_TRUE(grid.bottom_layer()->visible());
- EXPECT_TRUE(grid.left_layer()->visible());
- EXPECT_TRUE(grid.right_layer()->visible());
- EXPECT_TRUE(grid.center_layer()->visible());
-
- // We shouldn't be clipping the corner images anymore.
- EXPECT_TRUE(test_api.top_left_clip_rect().IsEmpty());
- EXPECT_TRUE(test_api.top_right_clip_rect().IsEmpty());
- EXPECT_TRUE(test_api.bottom_left_clip_rect().IsEmpty());
- EXPECT_TRUE(test_api.bottom_right_clip_rect().IsEmpty());
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/input_method_event_filter.cc b/chromium/ui/views/corewm/input_method_event_filter.cc
deleted file mode 100644
index 8e9ead8e1d9..00000000000
--- a/chromium/ui/views/corewm/input_method_event_filter.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/input_method_event_filter.h"
-
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_factory.h"
-#include "ui/events/event.h"
-
-namespace views {
-namespace corewm {
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, public:
-
-InputMethodEventFilter::InputMethodEventFilter(gfx::AcceleratedWidget widget)
- : input_method_(ui::CreateInputMethod(this, widget)),
- target_dispatcher_(NULL) {
- // TODO(yusukes): Check if the root window is currently focused and pass the
- // result to Init().
- input_method_->Init(true);
-}
-
-InputMethodEventFilter::~InputMethodEventFilter() {
-}
-
-void InputMethodEventFilter::SetInputMethodPropertyInRootWindow(
- aura::Window* root_window) {
- root_window->SetProperty(aura::client::kRootWindowInputMethodKey,
- input_method_.get());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, EventFilter implementation:
-
-void InputMethodEventFilter::OnKeyEvent(ui::KeyEvent* event) {
- const ui::EventType type = event->type();
- if (type == ui::ET_TRANSLATED_KEY_PRESS ||
- type == ui::ET_TRANSLATED_KEY_RELEASE) {
- // The |event| is already handled by this object, change the type of the
- // event to ui::ET_KEY_* and pass it to the next filter.
- static_cast<ui::TranslatedKeyEvent*>(event)->ConvertToKeyEvent();
- } else {
- // If the focused window is changed, all requests to IME will be
- // discarded so it's safe to update the target_dispatcher_ here.
- aura::Window* target = static_cast<aura::Window*>(event->target());
- target_dispatcher_ = target->GetRootWindow()->GetDispatcher();
- DCHECK(target_dispatcher_);
- if (input_method_->DispatchKeyEvent(*event))
- event->StopPropagation();
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, ui::InputMethodDelegate implementation:
-
-bool InputMethodEventFilter::DispatchKeyEventPostIME(
- const base::NativeEvent& event) {
-#if defined(OS_WIN)
- DCHECK(event.message != WM_CHAR);
-#endif
- ui::TranslatedKeyEvent aura_event(event, false /* is_char */);
- return target_dispatcher_->AsRootWindowHostDelegate()->OnHostKeyEvent(
- &aura_event);
-}
-
-bool InputMethodEventFilter::DispatchFabricatedKeyEventPostIME(
- ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) {
- ui::TranslatedKeyEvent aura_event(type == ui::ET_KEY_PRESSED, key_code,
- flags);
- return target_dispatcher_->AsRootWindowHostDelegate()->OnHostKeyEvent(
- &aura_event);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/input_method_event_filter.h b/chromium/ui/views/corewm/input_method_event_filter.h
deleted file mode 100644
index 902244c8865..00000000000
--- a/chromium/ui/views/corewm/input_method_event_filter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_INPUT_METHOD_EVENT_FILTER_H_
-#define UI_VIEWS_COREWM_INPUT_METHOD_EVENT_FILTER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/window.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/events/event_handler.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class InputMethod;
-}
-
-namespace views {
-namespace corewm {
-
-// An event filter that forwards a KeyEvent to a system IME, and dispatches a
-// TranslatedKeyEvent to the root window as needed.
-class VIEWS_EXPORT InputMethodEventFilter
- : public ui::EventHandler,
- public ui::internal::InputMethodDelegate {
- public:
- explicit InputMethodEventFilter(gfx::AcceleratedWidget widget);
- virtual ~InputMethodEventFilter();
-
- void SetInputMethodPropertyInRootWindow(aura::Window* root_window);
-
- ui::InputMethod* input_method() const { return input_method_.get(); }
-
- private:
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
-
- // Overridden from ui::internal::InputMethodDelegate.
- virtual bool DispatchKeyEventPostIME(const base::NativeEvent& event) OVERRIDE;
- virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
- ui::KeyboardCode key_code,
- int flags) OVERRIDE;
-
- scoped_ptr<ui::InputMethod> input_method_;
-
- // The target dispatcher that will receive translated key events from the IME.
- aura::WindowEventDispatcher* target_dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilter);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_INPUT_METHOD_EVENT_FILTER_H_
diff --git a/chromium/ui/views/corewm/input_method_event_filter_unittest.cc b/chromium/ui/views/corewm/input_method_event_filter_unittest.cc
deleted file mode 100644
index 2c95dc44e82..00000000000
--- a/chromium/ui/views/corewm/input_method_event_filter_unittest.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/input_method_event_filter.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/views/corewm/compound_event_filter.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/test/test_event_handler.h"
-#include "ui/aura/test/test_windows.h"
-
-#if !defined(OS_WIN) && !defined(USE_X11)
-// On platforms except Windows and X11, aura::test::EventGenerator::PressKey
-// generates a key event without native_event(), which is not supported by
-// ui::MockInputMethod.
-#define TestInputMethodKeyEventPropagation \
-DISABLED_TestInputMethodKeyEventPropagation
-#endif
-
-namespace views {
-namespace corewm {
-
-typedef aura::test::AuraTestBase InputMethodEventFilterTest;
-
-TEST_F(InputMethodEventFilterTest, TestInputMethodProperty) {
- CompoundEventFilter* root_filter = new CompoundEventFilter;
- root_window()->SetEventFilter(root_filter);
-
- InputMethodEventFilter input_method_event_filter(
- dispatcher()->host()->GetAcceleratedWidget());
- root_filter->AddHandler(&input_method_event_filter);
-
- // Tests if InputMethodEventFilter adds a window property on its
- // construction.
- EXPECT_TRUE(root_window()->GetProperty(
- aura::client::kRootWindowInputMethodKey));
-
- root_filter->RemoveHandler(&input_method_event_filter);
-}
-
-// Tests if InputMethodEventFilter dispatches a ui::ET_TRANSLATED_KEY_* event to
-// the root window.
-TEST_F(InputMethodEventFilterTest, TestInputMethodKeyEventPropagation) {
- CompoundEventFilter* root_filter = new CompoundEventFilter;
- root_window()->SetEventFilter(root_filter);
-
- // Add the InputMethodEventFilter before the TestEventFilter.
- InputMethodEventFilter input_method_event_filter(
- dispatcher()->host()->GetAcceleratedWidget());
- root_filter->AddHandler(&input_method_event_filter);
-
- // Add TestEventFilter to the RootWindow.
- aura::test::TestEventHandler test_filter;
- root_filter->AddHandler(&test_filter);
-
- // We need an active window. Otherwise, the root window will not forward a key
- // event to event filters.
- aura::test::TestWindowDelegate test_delegate;
- scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
- &test_delegate,
- -1,
- gfx::Rect(),
- root_window()));
- aura::client::GetActivationClient(root_window())->ActivateWindow(
- window.get());
-
- // Send a fake key event to the root window. InputMethodEventFilter, which is
- // automatically set up by AshTestBase, consumes it and sends a new
- // ui::ET_TRANSLATED_KEY_* event to the root window, which will be consumed by
- // the test event filter.
- aura::test::EventGenerator generator(root_window());
- EXPECT_EQ(0, test_filter.num_key_events());
- generator.PressKey(ui::VKEY_SPACE, 0);
- EXPECT_EQ(1, test_filter.num_key_events());
- generator.ReleaseKey(ui::VKEY_SPACE, 0);
- EXPECT_EQ(2, test_filter.num_key_events());
-
- root_filter->RemoveHandler(&input_method_event_filter);
- root_filter->RemoveHandler(&test_filter);
-
- // Reset window before |test_delegate| gets deleted.
- window.reset();
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/native_cursor_manager.h b/chromium/ui/views/corewm/native_cursor_manager.h
deleted file mode 100644
index 75e4c8580a5..00000000000
--- a/chromium/ui/views/corewm/native_cursor_manager.h
+++ /dev/null
@@ -1,67 +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_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_H_
-#define UI_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_H_
-
-#include "base/strings/string16.h"
-#include "ui/views/corewm/native_cursor_manager_delegate.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Display;
-}
-
-namespace views {
-namespace corewm {
-
-// Interface where platforms such as Ash or Desktop aura are notified of
-// requested changes to cursor state. When requested, implementer should tell
-// the CursorManager of any actual state changes performed through the
-// delegate.
-class VIEWS_EXPORT NativeCursorManager {
- public:
- virtual ~NativeCursorManager() {}
-
- // A request to set the screen DPI. Can cause changes in the current cursor.
- virtual void SetDisplay(
- const gfx::Display& display,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-
- // A request to set the cursor to |cursor|. At minimum, implementer should
- // call NativeCursorManagerDelegate::CommitCursor() with whatever cursor is
- // actually used.
- virtual void SetCursor(
- gfx::NativeCursor cursor,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-
- // A request to set the visibility of the cursor. At minimum, implementer
- // should call NativeCursorManagerDelegate::CommitVisibility() with whatever
- // the visibility is.
- virtual void SetVisibility(
- bool visible,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-
- // A request to set the scale of the cursor icon.
- virtual void SetScale(
- float scale,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-
- // A request to set the scale of the cursor icon.
- virtual void SetCursorSet(
- ui::CursorSetType cursor_set,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-
- // A request to set whether mouse events are disabled. At minimum,
- // implementer should call NativeCursorManagerDelegate::
- // CommitMouseEventsEnabled() with whether mouse events are actually enabled.
- virtual void SetMouseEventsEnabled(
- bool enabled,
- views::corewm::NativeCursorManagerDelegate* delegate) = 0;
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_H_
diff --git a/chromium/ui/views/corewm/native_cursor_manager_delegate.h b/chromium/ui/views/corewm/native_cursor_manager_delegate.h
deleted file mode 100644
index 491ab47b1b4..00000000000
--- a/chromium/ui/views/corewm/native_cursor_manager_delegate.h
+++ /dev/null
@@ -1,36 +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_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_DELEGATE_H_
-#define UI_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_DELEGATE_H_
-
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-
-// The non-public interface that CursorManager exposes to its users. This
-// gives accessors to all the current state, and mutators to all the current
-// state.
-class VIEWS_EXPORT NativeCursorManagerDelegate {
- public:
- virtual ~NativeCursorManagerDelegate() {}
-
- // TODO(tdanderson): Possibly remove this interface.
- virtual gfx::NativeCursor GetCursor() const = 0;
- virtual bool IsCursorVisible() const = 0;
-
- virtual void CommitCursor(gfx::NativeCursor cursor) = 0;
- virtual void CommitVisibility(bool visible) = 0;
- virtual void CommitScale(float scale) = 0;
- virtual void CommitCursorSet(ui::CursorSetType cursor_set) = 0;
- virtual void CommitMouseEventsEnabled(bool enabled) = 0;
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_NATIVE_CURSOR_MANAGER_DELEGATE_H_
diff --git a/chromium/ui/views/corewm/shadow.cc b/chromium/ui/views/corewm/shadow.cc
deleted file mode 100644
index 4411c8d5637..00000000000
--- a/chromium/ui/views/corewm/shadow.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/shadow.h"
-
-#include "grit/ui_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/views/corewm/image_grid.h"
-
-namespace {
-
-// Shadow opacity for different styles.
-const float kActiveShadowOpacity = 1.0f;
-const float kInactiveShadowOpacity = 0.2f;
-const float kSmallShadowOpacity = 1.0f;
-
-// Interior inset for different styles.
-const int kActiveInteriorInset = 0;
-const int kInactiveInteriorInset = 0;
-const int kSmallInteriorInset = 5;
-
-// Duration for opacity animation in milliseconds.
-const int kShadowAnimationDurationMs = 100;
-
-float GetOpacityForStyle(views::corewm::Shadow::Style style) {
- switch (style) {
- case views::corewm::Shadow::STYLE_ACTIVE:
- return kActiveShadowOpacity;
- case views::corewm::Shadow::STYLE_INACTIVE:
- return kInactiveShadowOpacity;
- case views::corewm::Shadow::STYLE_SMALL:
- return kSmallShadowOpacity;
- }
- return 1.0f;
-}
-
-int GetInteriorInsetForStyle(views::corewm::Shadow::Style style) {
- switch (style) {
- case views::corewm::Shadow::STYLE_ACTIVE:
- return kActiveInteriorInset;
- case views::corewm::Shadow::STYLE_INACTIVE:
- return kInactiveInteriorInset;
- case views::corewm::Shadow::STYLE_SMALL:
- return kSmallInteriorInset;
- }
- return 0;
-}
-
-} // namespace
-
-namespace views {
-namespace corewm {
-
-Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) {
-}
-
-Shadow::~Shadow() {
-}
-
-void Shadow::Init(Style style) {
- style_ = style;
- image_grid_.reset(new ImageGrid);
- UpdateImagesForStyle();
- image_grid_->layer()->set_name("Shadow");
- image_grid_->layer()->SetOpacity(GetOpacityForStyle(style_));
-}
-
-void Shadow::SetContentBounds(const gfx::Rect& content_bounds) {
- content_bounds_ = content_bounds;
- UpdateImageGridBounds();
-}
-
-ui::Layer* Shadow::layer() const {
- return image_grid_->layer();
-}
-
-void Shadow::SetStyle(Style style) {
- if (style_ == style)
- return;
-
- Style old_style = style_;
- style_ = style;
-
- // Stop waiting for any as yet unfinished implicit animations.
- StopObservingImplicitAnimations();
-
- // If we're switching to or from the small style, don't bother with
- // animations.
- if (style == STYLE_SMALL || old_style == STYLE_SMALL) {
- UpdateImagesForStyle();
- image_grid_->layer()->SetOpacity(GetOpacityForStyle(style));
- return;
- }
-
- // If we're becoming active, switch images now. Because the inactive image
- // has a very low opacity the switch isn't noticeable and this approach
- // allows us to use only a single set of shadow images at a time.
- if (style == STYLE_ACTIVE) {
- UpdateImagesForStyle();
- // Opacity was baked into inactive image, start opacity low to match.
- image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
- }
-
- {
- // Property sets within this scope will be implicitly animated.
- ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
- settings.AddObserver(this);
- settings.SetTransitionDuration(
- base::TimeDelta::FromMilliseconds(kShadowAnimationDurationMs));
- switch (style_) {
- case STYLE_ACTIVE:
- image_grid_->layer()->SetOpacity(kActiveShadowOpacity);
- break;
- case STYLE_INACTIVE:
- image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
- break;
- default:
- NOTREACHED() << "Unhandled style " << style_;
- break;
- }
- }
-}
-
-void Shadow::OnImplicitAnimationsCompleted() {
- // If we just finished going inactive, switch images. This doesn't cause
- // a visual pop because the inactive image opacity is so low.
- if (style_ == STYLE_INACTIVE) {
- UpdateImagesForStyle();
- // Opacity is baked into inactive image, so set fully opaque.
- image_grid_->layer()->SetOpacity(1.0f);
- }
-}
-
-void Shadow::UpdateImagesForStyle() {
- ResourceBundle& res = ResourceBundle::GetSharedInstance();
- switch (style_) {
- case STYLE_ACTIVE:
- image_grid_->SetImages(
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_LEFT),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_LEFT),
- NULL,
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_RIGHT),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM),
- &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT));
- break;
- case STYLE_INACTIVE:
- image_grid_->SetImages(
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_LEFT),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_LEFT),
- NULL,
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_RIGHT),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM),
- &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT));
- break;
- case STYLE_SMALL:
- image_grid_->SetImages(
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT),
- NULL,
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM),
- &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT));
- break;
- default:
- NOTREACHED() << "Unhandled style " << style_;
- break;
- }
-
- // Update interior inset for style.
- interior_inset_ = GetInteriorInsetForStyle(style_);
-
- // Image sizes may have changed.
- UpdateImageGridBounds();
-}
-
-void Shadow::UpdateImageGridBounds() {
- // Update bounds based on content bounds and image sizes.
- gfx::Rect image_grid_bounds = content_bounds_;
- image_grid_bounds.Inset(interior_inset_, interior_inset_);
- image_grid_->SetContentBounds(image_grid_bounds);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/shadow.h b/chromium/ui/views/corewm/shadow.h
deleted file mode 100644
index 794ba3dbeaa..00000000000
--- a/chromium/ui/views/corewm/shadow.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_SHADOW_H_
-#define UI_VIEWS_COREWM_SHADOW_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/compositor/layer_animation_observer.h"
-#include "ui/gfx/rect.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class Layer;
-} // namespace ui
-
-namespace views {
-namespace corewm {
-
-class ImageGrid;
-
-// Simple class that draws a drop shadow around content at given bounds.
-class VIEWS_EXPORT Shadow : public ui::ImplicitAnimationObserver {
- public:
- enum Style {
- // Active windows have more opaque shadows, shifted down to make the window
- // appear "higher".
- STYLE_ACTIVE,
-
- // Inactive windows have less opaque shadows.
- STYLE_INACTIVE,
-
- // Small windows like tooltips and context menus have lighter, smaller
- // shadows.
- STYLE_SMALL,
- };
-
- Shadow();
- virtual ~Shadow();
-
- void Init(Style style);
-
- // Returns |image_grid_|'s ui::Layer. This is exposed so it can be added to
- // the same layer as the content and stacked below it. SetContentBounds()
- // should be used to adjust the shadow's size and position (rather than
- // applying transformations to this layer).
- ui::Layer* layer() const;
-
- const gfx::Rect& content_bounds() const { return content_bounds_; }
- Style style() const { return style_; }
-
- // Moves and resizes |image_grid_| to frame |content_bounds|.
- void SetContentBounds(const gfx::Rect& content_bounds);
-
- // Sets the shadow's style, animating opacity as necessary.
- void SetStyle(Style style);
-
- // ui::ImplicitAnimationObserver overrides:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE;
-
- private:
- // Updates the |image_grid_| images to the current |style_|.
- void UpdateImagesForStyle();
-
- // Updates the |image_grid_| bounds based on its image sizes and the
- // current |content_bounds_|.
- void UpdateImageGridBounds();
-
- // The current style, set when the transition animation starts.
- Style style_;
-
- scoped_ptr<ImageGrid> image_grid_;
-
- // Bounds of the content that the shadow encloses.
- gfx::Rect content_bounds_;
-
- // The interior inset of the shadow images. The content bounds of the image
- // grid should be set to |content_bounds_| inset by this amount.
- int interior_inset_;
-
- DISALLOW_COPY_AND_ASSIGN(Shadow);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_SHADOW_H_
diff --git a/chromium/ui/views/corewm/shadow_controller.cc b/chromium/ui/views/corewm/shadow_controller.cc
deleted file mode 100644
index 49307d8e2d2..00000000000
--- a/chromium/ui/views/corewm/shadow_controller.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/shadow_controller.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/memory/linked_ptr.h"
-#include "base/scoped_observer.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/env_observer.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/compositor/layer.h"
-#include "ui/views/corewm/shadow.h"
-#include "ui/views/corewm/shadow_types.h"
-
-using std::make_pair;
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-ShadowType GetShadowTypeFromWindow(aura::Window* window) {
- switch (window->type()) {
- case aura::client::WINDOW_TYPE_NORMAL:
- case aura::client::WINDOW_TYPE_PANEL:
- case aura::client::WINDOW_TYPE_MENU:
- case aura::client::WINDOW_TYPE_TOOLTIP:
- return SHADOW_TYPE_RECTANGULAR;
- default:
- break;
- }
- return SHADOW_TYPE_NONE;
-}
-
-bool ShouldUseSmallShadowForWindow(aura::Window* window) {
- switch (window->type()) {
- case aura::client::WINDOW_TYPE_MENU:
- case aura::client::WINDOW_TYPE_TOOLTIP:
- return true;
- default:
- break;
- }
- return false;
-}
-
-// Returns the shadow style to be applied to |losing_active| when it is losing
-// active to |gaining_active|. |gaining_active| may be of a type that hides when
-// inactive, and as such we do not want to render |losing_active| as inactive.
-Shadow::Style GetShadowStyleForWindowLosingActive(
- aura::Window* losing_active,
- aura::Window* gaining_active) {
- if (gaining_active && aura::client::GetHideOnDeactivate(gaining_active)) {
- aura::Window::Windows::const_iterator it =
- std::find(losing_active->transient_children().begin(),
- losing_active->transient_children().end(),
- gaining_active);
- if (it != losing_active->transient_children().end())
- return Shadow::STYLE_ACTIVE;
- }
- return Shadow::STYLE_INACTIVE;
-}
-
-} // namespace
-
-// ShadowController::Impl ------------------------------------------------------
-
-// Real implementation of the ShadowController. ShadowController observes
-// ActivationChangeObserver, which are per ActivationClient, where as there is
-// only a single Impl (as it observes all window creation by way of an
-// EnvObserver).
-class ShadowController::Impl :
- public aura::EnvObserver,
- public aura::WindowObserver,
- public base::RefCounted<Impl> {
- public:
- // Returns the singleton instance, destroyed when there are no more refs.
- static Impl* GetInstance();
-
- // aura::EnvObserver override:
- virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
-
- // aura::WindowObserver overrides:
- virtual void OnWindowPropertyChanged(
- aura::Window* window, const void* key, intptr_t old) OVERRIDE;
- virtual void OnWindowBoundsChanged(
- aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
-
- private:
- friend class base::RefCounted<Impl>;
- friend class ShadowController;
- friend class ShadowController::TestApi;
-
- typedef std::map<aura::Window*, linked_ptr<Shadow> > WindowShadowMap;
-
- Impl();
- virtual ~Impl();
-
- // Forwarded from ShadowController.
- void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active);
-
- // Checks if |window| is visible and contains a property requesting a shadow.
- bool ShouldShowShadowForWindow(aura::Window* window) const;
-
- // Returns |window|'s shadow from |window_shadows_|, or NULL if no shadow
- // exists.
- Shadow* GetShadowForWindow(aura::Window* window);
-
- // Updates the shadow styles for windows when activation changes.
- void HandleWindowActivationChange(aura::Window* gaining_active,
- aura::Window* losing_active);
-
- // Shows or hides |window|'s shadow as needed (creating the shadow if
- // necessary).
- void HandlePossibleShadowVisibilityChange(aura::Window* window);
-
- // Creates a new shadow for |window| and stores it in |window_shadows_|. The
- // shadow's bounds are initialized and it is added to the window's layer.
- void CreateShadowForWindow(aura::Window* window);
-
- WindowShadowMap window_shadows_;
-
- ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
-
- static Impl* instance_;
-
- DISALLOW_COPY_AND_ASSIGN(Impl);
-};
-
-// static
-ShadowController::Impl* ShadowController::Impl::instance_ = NULL;
-
-// static
-ShadowController::Impl* ShadowController::Impl::GetInstance() {
- if (!instance_)
- instance_ = new Impl();
- return instance_;
-}
-
-void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
- observer_manager_.Add(window);
- SetShadowType(window, GetShadowTypeFromWindow(window));
- HandlePossibleShadowVisibilityChange(window);
-}
-
-void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window,
- const void* key,
- intptr_t old) {
- if (key == kShadowTypeKey) {
- HandlePossibleShadowVisibilityChange(window);
- return;
- }
-}
-
-void ShadowController::Impl::OnWindowBoundsChanged(
- aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- Shadow* shadow = GetShadowForWindow(window);
- if (shadow)
- shadow->SetContentBounds(gfx::Rect(new_bounds.size()));
-}
-
-void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) {
- window_shadows_.erase(window);
- observer_manager_.Remove(window);
-}
-
-void ShadowController::Impl::OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) {
- if (gained_active) {
- Shadow* shadow = GetShadowForWindow(gained_active);
- if (shadow && !ShouldUseSmallShadowForWindow(gained_active))
- shadow->SetStyle(Shadow::STYLE_ACTIVE);
- }
- if (lost_active) {
- Shadow* shadow = GetShadowForWindow(lost_active);
- if (shadow && !ShouldUseSmallShadowForWindow(lost_active)) {
- shadow->SetStyle(GetShadowStyleForWindowLosingActive(lost_active,
- gained_active));
- }
- }
-}
-
-bool ShadowController::Impl::ShouldShowShadowForWindow(
- aura::Window* window) const {
- const ShadowType type = GetShadowType(window);
- switch (type) {
- case SHADOW_TYPE_NONE:
- return false;
- case SHADOW_TYPE_RECTANGULAR:
- return true;
- default:
- NOTREACHED() << "Unknown shadow type " << type;
- return false;
- }
-}
-
-Shadow* ShadowController::Impl::GetShadowForWindow(aura::Window* window) {
- WindowShadowMap::const_iterator it = window_shadows_.find(window);
- return it != window_shadows_.end() ? it->second.get() : NULL;
-}
-
-void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
- aura::Window* window) {
- const bool should_show = ShouldShowShadowForWindow(window);
- Shadow* shadow = GetShadowForWindow(window);
- if (shadow)
- shadow->layer()->SetVisible(should_show);
- else if (should_show && !shadow)
- CreateShadowForWindow(window);
-}
-
-void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
- linked_ptr<Shadow> shadow(new Shadow());
- window_shadows_.insert(make_pair(window, shadow));
-
- shadow->Init(ShouldUseSmallShadowForWindow(window) ?
- Shadow::STYLE_SMALL : Shadow::STYLE_ACTIVE);
- shadow->SetContentBounds(gfx::Rect(window->bounds().size()));
- shadow->layer()->SetVisible(ShouldShowShadowForWindow(window));
- window->layer()->Add(shadow->layer());
-}
-
-ShadowController::Impl::Impl()
- : observer_manager_(this) {
- aura::Env::GetInstance()->AddObserver(this);
-}
-
-ShadowController::Impl::~Impl() {
- DCHECK_EQ(instance_, this);
- aura::Env::GetInstance()->RemoveObserver(this);
- instance_ = NULL;
-}
-
-// ShadowController ------------------------------------------------------------
-
-ShadowController::ShadowController(
- aura::client::ActivationClient* activation_client)
- : activation_client_(activation_client),
- impl_(Impl::GetInstance()) {
- // Watch for window activation changes.
- activation_client_->AddObserver(this);
-}
-
-ShadowController::~ShadowController() {
- activation_client_->RemoveObserver(this);
-}
-
-void ShadowController::OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) {
- impl_->OnWindowActivated(gained_active, lost_active);
-}
-
-// ShadowController::TestApi ---------------------------------------------------
-
-Shadow* ShadowController::TestApi::GetShadowForWindow(aura::Window* window) {
- return controller_->impl_->GetShadowForWindow(window);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/shadow_controller.h b/chromium/ui/views/corewm/shadow_controller.h
deleted file mode 100644
index 2a7e29c88e5..00000000000
--- a/chromium/ui/views/corewm/shadow_controller.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_SHADOW_CONTROLLER_H_
-#define UI_VIEWS_COREWM_SHADOW_CONTROLLER_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-namespace client {
-class ActivationClient;
-}
-}
-namespace gfx {
-class Rect;
-}
-
-namespace views {
-namespace corewm {
-
-class Shadow;
-
-// ShadowController observes changes to windows and creates and updates drop
-// shadows as needed. ShadowController itself is light weight and per
-// ActivationClient. ShadowController delegates to its implementation class,
-// which observes all window creation.
-class VIEWS_EXPORT ShadowController :
- public aura::client::ActivationChangeObserver {
- public:
- class VIEWS_EXPORT TestApi {
- public:
- explicit TestApi(ShadowController* controller) : controller_(controller) {}
- ~TestApi() {}
-
- Shadow* GetShadowForWindow(aura::Window* window);
-
- private:
- ShadowController* controller_; // not owned
-
- DISALLOW_COPY_AND_ASSIGN(TestApi);
- };
-
- explicit ShadowController(aura::client::ActivationClient* activation_client);
- virtual ~ShadowController();
-
- // aura::client::ActivationChangeObserver overrides:
- virtual void OnWindowActivated(aura::Window* gained_active,
- aura::Window* lost_active) OVERRIDE;
-
- private:
- class Impl;
-
- aura::client::ActivationClient* activation_client_;
-
- scoped_refptr<Impl> impl_;
-
- DISALLOW_COPY_AND_ASSIGN(ShadowController);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_SHADOW_CONTROLLER_H_
diff --git a/chromium/ui/views/corewm/shadow_controller_unittest.cc b/chromium/ui/views/corewm/shadow_controller_unittest.cc
deleted file mode 100644
index 4140f7d83fb..00000000000
--- a/chromium/ui/views/corewm/shadow_controller_unittest.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/shadow_controller.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/views/corewm/shadow.h"
-#include "ui/views/corewm/shadow_types.h"
-
-namespace views {
-namespace corewm {
-
-class ShadowControllerTest : public aura::test::AuraTestBase {
- public:
- ShadowControllerTest() {}
- virtual ~ShadowControllerTest() {}
-
- virtual void SetUp() OVERRIDE {
- AuraTestBase::SetUp();
- aura::client::ActivationClient* activation_client =
- aura::client::GetActivationClient(root_window());
- shadow_controller_.reset(new ShadowController(activation_client));
- }
- virtual void TearDown() OVERRIDE {
- shadow_controller_.reset();
- AuraTestBase::TearDown();
- }
-
- protected:
- ShadowController* shadow_controller() { return shadow_controller_.get(); }
-
- void ActivateWindow(aura::Window* window) {
- DCHECK(window);
- DCHECK(window->GetRootWindow());
- aura::client::GetActivationClient(window->GetRootWindow())->ActivateWindow(
- window);
- }
-
- private:
- scoped_ptr<ShadowController> shadow_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(ShadowControllerTest);
-};
-
-// Tests that various methods in Window update the Shadow object as expected.
-TEST_F(ShadowControllerTest, Shadow) {
- scoped_ptr<aura::Window> window(new aura::Window(NULL));
- window->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_TEXTURED);
- ParentWindow(window.get());
-
- // We should create the shadow before the window is visible (the shadow's
- // layer won't get drawn yet since it's a child of the window's layer).
- ShadowController::TestApi api(shadow_controller());
- const Shadow* shadow = api.GetShadowForWindow(window.get());
- ASSERT_TRUE(shadow != NULL);
- EXPECT_TRUE(shadow->layer()->visible());
-
- // The shadow should remain visible after window visibility changes.
- window->Show();
- EXPECT_TRUE(shadow->layer()->visible());
- window->Hide();
- EXPECT_TRUE(shadow->layer()->visible());
-
- // If the shadow is disabled, it should be hidden.
- SetShadowType(window.get(), SHADOW_TYPE_NONE);
- window->Show();
- EXPECT_FALSE(shadow->layer()->visible());
- SetShadowType(window.get(), SHADOW_TYPE_RECTANGULAR);
- EXPECT_TRUE(shadow->layer()->visible());
-
- // The shadow's layer should be a child of the window's layer.
- EXPECT_EQ(window->layer(), shadow->layer()->parent());
-
- window->parent()->RemoveChild(window.get());
- aura::Window* window_ptr = window.get();
- window.reset();
- EXPECT_TRUE(api.GetShadowForWindow(window_ptr) == NULL);
-}
-
-// Tests that the window's shadow's bounds are updated correctly.
-TEST_F(ShadowControllerTest, ShadowBounds) {
- scoped_ptr<aura::Window> window(new aura::Window(NULL));
- window->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_TEXTURED);
- ParentWindow(window.get());
- window->Show();
-
- const gfx::Rect kOldBounds(20, 30, 400, 300);
- window->SetBounds(kOldBounds);
-
- // 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).
- SetShadowType(window.get(), SHADOW_TYPE_RECTANGULAR);
- ShadowController::TestApi api(shadow_controller());
- const Shadow* shadow = api.GetShadowForWindow(window.get());
- ASSERT_TRUE(shadow != NULL);
- EXPECT_EQ(gfx::Rect(kOldBounds.size()).ToString(),
- shadow->content_bounds().ToString());
-
- // When we change the window's bounds, the shadow's should be updated too.
- gfx::Rect kNewBounds(50, 60, 500, 400);
- window->SetBounds(kNewBounds);
- EXPECT_EQ(gfx::Rect(kNewBounds.size()).ToString(),
- shadow->content_bounds().ToString());
-}
-
-// Tests that activating a window changes the shadow style.
-TEST_F(ShadowControllerTest, ShadowStyle) {
- ShadowController::TestApi api(shadow_controller());
-
- scoped_ptr<aura::Window> window1(new aura::Window(NULL));
- window1->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window1->Init(ui::LAYER_TEXTURED);
- ParentWindow(window1.get());
- window1->SetBounds(gfx::Rect(10, 20, 300, 400));
- window1->Show();
- ActivateWindow(window1.get());
-
- // window1 is active, so style should have active appearance.
- Shadow* shadow1 = api.GetShadowForWindow(window1.get());
- ASSERT_TRUE(shadow1 != NULL);
- EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
-
- // Create another window and activate it.
- scoped_ptr<aura::Window> window2(new aura::Window(NULL));
- window2->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window2->Init(ui::LAYER_TEXTURED);
- ParentWindow(window2.get());
- window2->SetBounds(gfx::Rect(11, 21, 301, 401));
- window2->Show();
- ActivateWindow(window2.get());
-
- // window1 is now inactive, so shadow should go inactive.
- Shadow* shadow2 = api.GetShadowForWindow(window2.get());
- ASSERT_TRUE(shadow2 != NULL);
- EXPECT_EQ(Shadow::STYLE_INACTIVE, shadow1->style());
- EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow2->style());
-}
-
-// Tests that we use smaller shadows for tooltips and menus.
-TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) {
- ShadowController::TestApi api(shadow_controller());
-
- scoped_ptr<aura::Window> tooltip_window(new aura::Window(NULL));
- tooltip_window->SetType(aura::client::WINDOW_TYPE_TOOLTIP);
- tooltip_window->Init(ui::LAYER_TEXTURED);
- ParentWindow(tooltip_window.get());
- tooltip_window->SetBounds(gfx::Rect(10, 20, 300, 400));
- tooltip_window->Show();
-
- Shadow* tooltip_shadow = api.GetShadowForWindow(tooltip_window.get());
- ASSERT_TRUE(tooltip_shadow != NULL);
- EXPECT_EQ(Shadow::STYLE_SMALL, tooltip_shadow->style());
-
- scoped_ptr<aura::Window> menu_window(new aura::Window(NULL));
- menu_window->SetType(aura::client::WINDOW_TYPE_MENU);
- menu_window->Init(ui::LAYER_TEXTURED);
- ParentWindow(menu_window.get());
- menu_window->SetBounds(gfx::Rect(10, 20, 300, 400));
- menu_window->Show();
-
- Shadow* menu_shadow = api.GetShadowForWindow(tooltip_window.get());
- ASSERT_TRUE(menu_shadow != NULL);
- EXPECT_EQ(Shadow::STYLE_SMALL, menu_shadow->style());
-}
-
-// http://crbug.com/120210 - transient parents of certain types of transients
-// should not lose their shadow when they lose activation to the transient.
-TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) {
- ShadowController::TestApi api(shadow_controller());
-
- scoped_ptr<aura::Window> window1(new aura::Window(NULL));
- window1->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window1->Init(ui::LAYER_TEXTURED);
- ParentWindow(window1.get());
- window1->SetBounds(gfx::Rect(10, 20, 300, 400));
- window1->Show();
- ActivateWindow(window1.get());
-
- // window1 is active, so style should have active appearance.
- Shadow* shadow1 = api.GetShadowForWindow(window1.get());
- ASSERT_TRUE(shadow1 != NULL);
- EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
-
- // Create a window that is transient to window1, and that has the 'hide on
- // deactivate' property set. Upon activation, window1 should still have an
- // active shadow.
- scoped_ptr<aura::Window> window2(new aura::Window(NULL));
- window2->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window2->Init(ui::LAYER_TEXTURED);
- ParentWindow(window2.get());
- window2->SetBounds(gfx::Rect(11, 21, 301, 401));
- window1->AddTransientChild(window2.get());
- aura::client::SetHideOnDeactivate(window2.get(), true);
- window2->Show();
- ActivateWindow(window2.get());
-
- // window1 is now inactive, but its shadow should still appear active.
- EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/shadow_types.cc b/chromium/ui/views/corewm/shadow_types.cc
deleted file mode 100644
index 1e3a937028f..00000000000
--- a/chromium/ui/views/corewm/shadow_types.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/shadow_types.h"
-
-#include "ui/aura/window_property.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::ShadowType);
-
-namespace views {
-namespace corewm {
-
-void SetShadowType(aura::Window* window, ShadowType shadow_type) {
- window->SetProperty(kShadowTypeKey, shadow_type);
-}
-
-ShadowType GetShadowType(aura::Window* window) {
- return window->GetProperty(kShadowTypeKey);
-}
-
-DEFINE_WINDOW_PROPERTY_KEY(ShadowType, kShadowTypeKey, SHADOW_TYPE_NONE);
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/shadow_types.h b/chromium/ui/views/corewm/shadow_types.h
deleted file mode 100644
index 046ad705a3a..00000000000
--- a/chromium/ui/views/corewm/shadow_types.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_SHADOW_TYPES_H_
-#define UI_VIEWS_COREWM_SHADOW_TYPES_H_
-
-#include "ui/aura/window.h"
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-}
-
-namespace views {
-namespace corewm {
-
-// Different types of drop shadows that can be drawn under a window by the
-// shell. Used as a value for the kShadowTypeKey property.
-enum ShadowType {
- // Starts at 0 due to the cast in GetShadowType().
- SHADOW_TYPE_NONE = 0,
- SHADOW_TYPE_RECTANGULAR,
-};
-
-VIEWS_EXPORT void SetShadowType(aura::Window* window, ShadowType shadow_type);
-VIEWS_EXPORT ShadowType GetShadowType(aura::Window* window);
-
-// A property key describing the drop shadow that should be displayed under the
-// window. If unset, no shadow is displayed.
-extern const aura::WindowProperty<ShadowType>* const kShadowTypeKey;
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_SHADOW_TYPES_H_
diff --git a/chromium/ui/views/corewm/tooltip.h b/chromium/ui/views/corewm/tooltip.h
index f714ac9a57c..7fb15bc32ca 100644
--- a/chromium/ui/views/corewm/tooltip.h
+++ b/chromium/ui/views/corewm/tooltip.h
@@ -27,7 +27,7 @@ class VIEWS_EXPORT Tooltip {
// Updates the text on the tooltip and resizes to fit.
virtual void SetText(aura::Window* window,
- const string16& tooltip_text,
+ const base::string16& tooltip_text,
const gfx::Point& location) = 0;
// Shows the tooltip at the specified location (in screen coordinates).
diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc
index 7c11bd80bbc..f9f41b93722 100644
--- a/chromium/ui/views/corewm/tooltip_aura.cc
+++ b/chromium/ui/views/corewm/tooltip_aura.cc
@@ -4,23 +4,20 @@
#include "ui/views/corewm/tooltip_aura.h"
-#include "base/command_line.h"
#include "base/strings/string_split.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/text_elider.h"
+#include "ui/gfx/text_utils.h"
+#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
-#include "ui/views/corewm/corewm_switches.h"
#include "ui/views/widget/widget.h"
namespace {
-const SkColor kTooltipBackground = 0xFFFFFFCC;
-const SkColor kTooltipBorder = 0xFF646450;
-const int kTooltipBorderWidth = 1;
const int kTooltipHorizontalPadding = 3;
// Max visual tooltip width. If a tooltip is greater than this width, it will
@@ -53,13 +50,6 @@ views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
return widget;
}
-gfx::Font GetDefaultFont() {
- // TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure
- // out a way to merge.
- return ui::ResourceBundle::GetSharedInstance().GetFont(
- ui::ResourceBundle::BaseFont);
-}
-
} // namespace
namespace views {
@@ -69,13 +59,6 @@ TooltipAura::TooltipAura(gfx::ScreenType screen_type)
: screen_type_(screen_type),
widget_(NULL),
tooltip_window_(NULL) {
- label_.set_background(
- views::Background::CreateSolidBackground(kTooltipBackground));
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDropShadows)) {
- label_.set_border(
- views::Border::CreateSolidBorder(kTooltipBorderWidth,
- kTooltipBorder));
- }
label_.set_owned_by_client();
label_.SetMultiLine(true);
}
@@ -85,8 +68,9 @@ TooltipAura::~TooltipAura() {
}
// static
-void TooltipAura::TrimTooltipToFit(int max_width,
- string16* text,
+void TooltipAura::TrimTooltipToFit(const gfx::FontList& font_list,
+ int max_width,
+ base::string16* text,
int* width,
int* line_count) {
*width = 0;
@@ -95,27 +79,26 @@ void TooltipAura::TrimTooltipToFit(int max_width,
// Determine the available width for the tooltip.
int available_width = std::min(kTooltipMaxWidthPixels, max_width);
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
base::SplitString(*text, '\n', &lines);
- std::vector<string16> result_lines;
+ std::vector<base::string16> result_lines;
// Format each line to fit.
- gfx::Font font = GetDefaultFont();
- for (std::vector<string16>::iterator l = lines.begin(); l != lines.end();
- ++l) {
+ for (std::vector<base::string16>::iterator l = lines.begin();
+ l != lines.end(); ++l) {
// We break the line at word boundaries, then stuff as many words as we can
// in the available width to the current line, and move the remaining words
// to a new line.
- std::vector<string16> words;
+ std::vector<base::string16> words;
base::SplitStringDontTrim(*l, ' ', &words);
int current_width = 0;
- string16 line;
- for (std::vector<string16>::iterator w = words.begin(); w != words.end();
- ++w) {
- string16 word = *w;
+ base::string16 line;
+ for (std::vector<base::string16>::iterator w = words.begin();
+ w != words.end(); ++w) {
+ base::string16 word = *w;
if (w + 1 != words.end())
word.push_back(' ');
- int word_width = font.GetStringWidth(word);
+ int word_width = gfx::GetStringWidth(word, font_list);
if (current_width + word_width > available_width) {
// Current width will exceed the available width. Must start a new line.
if (!line.empty())
@@ -139,19 +122,19 @@ void TooltipAura::TrimTooltipToFit(int max_width,
*line_count = result_lines.size();
// Flatten the result.
- string16 result;
- for (std::vector<string16>::iterator l = result_lines.begin();
+ base::string16 result;
+ for (std::vector<base::string16>::iterator l = result_lines.begin();
l != result_lines.end(); ++l) {
if (!result.empty())
result.push_back('\n');
- int line_width = font.GetStringWidth(*l);
+ int line_width = gfx::GetStringWidth(*l, font_list);
// Since we only break at word boundaries, it could happen that due to some
// very long word, line_width is greater than the available_width. In such
// case, we simply truncate at available_width and add ellipses at the end.
if (line_width > available_width) {
*width = available_width;
- result.append(gfx::ElideText(*l, font, available_width,
- gfx::ELIDE_AT_END));
+ result.append(gfx::ElideText(*l, font_list, available_width,
+ gfx::ELIDE_TAIL));
} else {
*width = std::max(*width, line_width);
result.append(*l);
@@ -163,25 +146,9 @@ void TooltipAura::TrimTooltipToFit(int max_width,
int TooltipAura::GetMaxWidth(const gfx::Point& location) const {
// TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure
// out a way to merge.
- gfx::Rect display_bounds = GetBoundsForTooltip(location);
- return (display_bounds.width() + 1) / 2;
-}
-
-gfx::Rect TooltipAura::GetBoundsForTooltip(
- const gfx::Point& origin) const {
- DCHECK(tooltip_window_);
- gfx::Rect widget_bounds;
- // For Desktop aura we constrain the tooltip to the bounds of the Widget
- // (which comes from the RootWindow).
- if (screen_type_ == gfx::SCREEN_TYPE_NATIVE &&
- gfx::SCREEN_TYPE_NATIVE != gfx::SCREEN_TYPE_ALTERNATE) {
- widget_bounds = tooltip_window_->GetDispatcher()->host()->GetBounds();
- }
gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_);
- gfx::Rect bounds(screen->GetDisplayNearestPoint(origin).bounds());
- if (!widget_bounds.IsEmpty())
- bounds.Intersect(widget_bounds);
- return bounds;
+ gfx::Rect display_bounds(screen->GetDisplayNearestPoint(location).bounds());
+ return (display_bounds.width() + 1) / 2;
}
void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
@@ -191,7 +158,8 @@ void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
tooltip_height);
tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY);
- gfx::Rect display_bounds = GetBoundsForTooltip(mouse_pos);
+ gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_);
+ gfx::Rect display_bounds(screen->GetDisplayNearestPoint(mouse_pos).bounds());
// If tooltip is out of bounds on the x axis, we simply shift it
// horizontally by the offset.
@@ -209,22 +177,6 @@ void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
widget_->SetBounds(tooltip_rect);
}
-void TooltipAura::CreateWidget() {
- if (widget_) {
- // If the window for which the tooltip is being displayed changes and if the
- // tooltip window and the tooltip widget belong to different rootwindows
- // then we need to recreate the tooltip widget under the active root window
- // hierarchy to get it to display.
- if (widget_->GetNativeWindow()->GetRootWindow() ==
- tooltip_window_->GetRootWindow())
- return;
- DestroyWidget();
- }
- widget_ = CreateTooltipWidget(tooltip_window_);
- widget_->SetContentsView(&label_);
- widget_->AddObserver(this);
-}
-
void TooltipAura::DestroyWidget() {
if (widget_) {
widget_->RemoveObserver(this);
@@ -234,29 +186,43 @@ void TooltipAura::DestroyWidget() {
}
void TooltipAura::SetText(aura::Window* window,
- const string16& tooltip_text,
+ const base::string16& tooltip_text,
const gfx::Point& location) {
tooltip_window_ = window;
int max_width, line_count;
- string16 trimmed_text(tooltip_text);
- TrimTooltipToFit(
- GetMaxWidth(location), &trimmed_text, &max_width, &line_count);
+ base::string16 trimmed_text(tooltip_text);
+ TrimTooltipToFit(label_.font_list(), GetMaxWidth(location), &trimmed_text,
+ &max_width, &line_count);
label_.SetText(trimmed_text);
int width = max_width + 2 * kTooltipHorizontalPadding;
int height = label_.GetHeightForWidth(max_width) +
2 * kTooltipVerticalPadding;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDropShadows)) {
- width += 2 * kTooltipBorderWidth;
- height += 2 * kTooltipBorderWidth;
+
+ if (!widget_) {
+ widget_ = CreateTooltipWidget(tooltip_window_);
+ widget_->SetContentsView(&label_);
+ widget_->AddObserver(this);
}
- CreateWidget();
+
SetTooltipBounds(location, width, height);
+
+ ui::NativeTheme* native_theme = widget_->GetNativeTheme();
+ label_.set_background(
+ views::Background::CreateSolidBackground(
+ native_theme->GetSystemColor(
+ ui::NativeTheme::kColorId_TooltipBackground)));
+
+ label_.SetAutoColorReadabilityEnabled(false);
+ label_.SetEnabledColor(native_theme->GetSystemColor(
+ ui::NativeTheme::kColorId_TooltipText));
}
void TooltipAura::Show() {
- if (widget_)
+ if (widget_) {
widget_->Show();
+ widget_->StackAtTop();
+ }
}
void TooltipAura::Hide() {
diff --git a/chromium/ui/views/corewm/tooltip_aura.h b/chromium/ui/views/corewm/tooltip_aura.h
index 97f3737aa8e..ead119f5d95 100644
--- a/chromium/ui/views/corewm/tooltip_aura.h
+++ b/chromium/ui/views/corewm/tooltip_aura.h
@@ -10,6 +10,10 @@
#include "ui/views/corewm/tooltip.h"
#include "ui/views/widget/widget_observer.h"
+namespace gfx {
+class FontList;
+} // namespace gfx
+
namespace views {
class Widget;
@@ -24,11 +28,11 @@ class VIEWS_EXPORT TooltipAura : public Tooltip, public WidgetObserver {
// Trims the tooltip to fit in the width |max_width|, setting |text| to the
// clipped result, |width| to the width (in pixels) of the clipped text
- // and |line_count| to the number of lines of text in the tooltip. |x| and |y|
- // give the location of the tooltip in screen coordinates. |max_width| comes
- // from GetMaxWidth().
- static void TrimTooltipToFit(int max_width,
- string16* text,
+ // and |line_count| to the number of lines of text in the tooltip. |font_list|
+ // is used to layout |text|. |max_width| comes from GetMaxWidth().
+ static void TrimTooltipToFit(const gfx::FontList& font_list,
+ int max_width,
+ base::string16* text,
int* width,
int* line_count);
@@ -36,24 +40,18 @@ class VIEWS_EXPORT TooltipAura : public Tooltip, public WidgetObserver {
// Returns the max width of the tooltip when shown at the specified location.
int GetMaxWidth(const gfx::Point& location) const;
- // Returns the bounds to fit the tooltip in.
- gfx::Rect GetBoundsForTooltip(const gfx::Point& origin) const;
-
// Adjusts the bounds given by the arguments to fit inside the desktop
// and applies the adjusted bounds to the label_.
void SetTooltipBounds(const gfx::Point& mouse_pos,
int tooltip_width,
int tooltip_height);
- // Makes sure |widget_| is valid, creating as necessary.
- void CreateWidget();
-
// Destroys |widget_|.
void DestroyWidget();
// Tooltip:
virtual void SetText(aura::Window* window,
- const string16& tooltip_text,
+ const base::string16& tooltip_text,
const gfx::Point& location) OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
diff --git a/chromium/ui/views/corewm/tooltip_aura_unittest.cc b/chromium/ui/views/corewm/tooltip_aura_unittest.cc
index 75814abcad8..1e8981ad791 100644
--- a/chromium/ui/views/corewm/tooltip_aura_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_aura_unittest.cc
@@ -5,43 +5,44 @@
#include "ui/views/corewm/tooltip_aura.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/test/aura_test_base.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/text_elider.h"
-#include "ui/views/test/views_test_base.h"
+#include "ui/gfx/text_utils.h"
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
namespace views {
namespace corewm {
-typedef ViewsTestBase TooltipAuraTest;
-
-// TODO(sky): clean this up.
-gfx::Font GetDefaultFont() {
- return ui::ResourceBundle::GetSharedInstance().GetFont(
- ui::ResourceBundle::BaseFont);
-}
+typedef aura::test::AuraTestBase TooltipAuraTest;
TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
+ const gfx::FontList font_list;
const int max_width = 4000;
- string16 tooltip;
+ base::string16 tooltip;
int width, line_count, expect_lines;
int max_pixel_width = 400; // copied from constants in tooltip_controller.cc
int max_lines = 10; // copied from constants in tooltip_controller.cc
- gfx::Font font = GetDefaultFont();
size_t tooltip_len;
// Error in computed size vs. expected size should not be greater than the
// size of the longest word.
- int error_in_pixel_width = font.GetStringWidth(ASCIIToUTF16("tooltip"));
+ int error_in_pixel_width = gfx::GetStringWidth(ASCIIToUTF16("tooltip"),
+ font_list);
// Long tooltips should wrap to next line
tooltip.clear();
width = line_count = -1;
expect_lines = 3;
- for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;)
+ for (; gfx::GetStringWidth(tooltip, font_list) <=
+ (expect_lines - 1) * max_pixel_width;)
tooltip.append(ASCIIToUTF16("This is part of the tooltip"));
tooltip_len = tooltip.length();
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width);
EXPECT_EQ(expect_lines, line_count);
EXPECT_EQ(tooltip_len + expect_lines - 1, tooltip.length());
@@ -50,9 +51,11 @@ TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
tooltip.clear();
width = line_count = -1;
expect_lines = 13;
- for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;)
+ for (; gfx::GetStringWidth(tooltip, font_list) <=
+ (expect_lines - 1) * max_pixel_width;)
tooltip.append(ASCIIToUTF16("This is part of the tooltip"));
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width);
EXPECT_EQ(max_lines, line_count);
@@ -60,11 +63,13 @@ TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
tooltip.clear();
width = line_count = -1;
expect_lines = 4;
- for (; font.GetStringWidth(tooltip) <= (expect_lines - 2) * max_pixel_width;)
+ for (; gfx::GetStringWidth(tooltip, font_list) <=
+ (expect_lines - 2) * max_pixel_width;)
tooltip.append(ASCIIToUTF16("This is part of the tooltip"));
tooltip.insert(tooltip.length() / 2, ASCIIToUTF16("\n"));
tooltip_len = tooltip.length();
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width);
EXPECT_EQ(expect_lines, line_count);
// We may have inserted the line break above near a space which will get
@@ -76,19 +81,23 @@ TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
tooltip.clear();
width = line_count = -1;
tooltip = UTF8ToUTF16(std::string('a', max_pixel_width));
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
EXPECT_NEAR(max_pixel_width, width, 5);
EXPECT_EQ(1, line_count);
- EXPECT_EQ(gfx::ElideText(UTF8ToUTF16(std::string('a', max_pixel_width)), font,
- max_pixel_width, gfx::ELIDE_AT_END), tooltip);
+ EXPECT_EQ(gfx::ElideText(UTF8ToUTF16(std::string('a', max_pixel_width)),
+ font_list, max_pixel_width, gfx::ELIDE_TAIL),
+ tooltip);
#endif
// Normal small tooltip should stay as is.
tooltip.clear();
width = line_count = -1;
tooltip = ASCIIToUTF16("Small Tooltip");
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
- EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tooltip")), width);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
+ EXPECT_EQ(gfx::GetStringWidth(ASCIIToUTF16("Small Tooltip"), font_list),
+ width);
EXPECT_EQ(1, line_count);
EXPECT_EQ(ASCIIToUTF16("Small Tooltip"), tooltip);
@@ -96,10 +105,13 @@ TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
tooltip.clear();
width = line_count = -1;
tooltip = ASCIIToUTF16("Multi line\nTooltip");
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
- int expected_width = font.GetStringWidth(ASCIIToUTF16("Multi line"));
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
+ int expected_width = gfx::GetStringWidth(ASCIIToUTF16("Multi line"),
+ font_list);
expected_width = std::max(expected_width,
- font.GetStringWidth(ASCIIToUTF16("Tooltip")));
+ gfx::GetStringWidth(ASCIIToUTF16("Tooltip"),
+ font_list));
EXPECT_EQ(expected_width, width);
EXPECT_EQ(2, line_count);
EXPECT_EQ(ASCIIToUTF16("Multi line\nTooltip"), tooltip);
@@ -108,8 +120,10 @@ TEST_F(TooltipAuraTest, TrimTooltipToFitTests) {
tooltip.clear();
width = line_count = -1;
tooltip = ASCIIToUTF16("Small Tool t\tip");
- TooltipAura::TrimTooltipToFit(max_width, &tooltip, &width, &line_count);
- EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tool t\tip")), width);
+ TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width,
+ &line_count);
+ EXPECT_EQ(gfx::GetStringWidth(ASCIIToUTF16("Small Tool t\tip"), font_list),
+ width);
EXPECT_EQ(1, line_count);
EXPECT_EQ(ASCIIToUTF16("Small Tool t\tip"), tooltip);
}
diff --git a/chromium/ui/views/corewm/tooltip_controller.cc b/chromium/ui/views/corewm/tooltip_controller.cc
index b411688397d..b1ffc1c7de8 100644
--- a/chromium/ui/views/corewm/tooltip_controller.cc
+++ b/chromium/ui/views/corewm/tooltip_controller.cc
@@ -10,7 +10,6 @@
#include "base/time/time.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
@@ -20,6 +19,7 @@
#include "ui/gfx/screen.h"
#include "ui/views/corewm/tooltip.h"
#include "ui/views/widget/tooltip_manager.h"
+#include "ui/wm/public/drag_drop_client.h"
namespace views {
namespace corewm {
@@ -115,6 +115,7 @@ aura::Window* GetTooltipTarget(const ui::MouseEvent& event,
TooltipController::TooltipController(scoped_ptr<Tooltip> tooltip)
: tooltip_window_(NULL),
+ tooltip_id_(NULL),
tooltip_window_at_mouse_press_(NULL),
tooltip_(tooltip.Pass()),
tooltips_enabled_(true) {
@@ -133,6 +134,18 @@ void TooltipController::UpdateTooltip(aura::Window* target) {
if (tooltip_window_ == target && tooltip_->IsVisible())
UpdateIfRequired();
+ // Reset |tooltip_window_at_mouse_press_| if the moving within the same window
+ // but over a region that has different tooltip text. By resetting
+ // |tooltip_window_at_mouse_press_| we ensure the next time the timer fires
+ // we'll requery for the tooltip text.
+ // This handles the case of clicking on a view, moving within the same window
+ // but over a different view, than back to the original.
+ if (tooltip_window_at_mouse_press_ &&
+ target == tooltip_window_at_mouse_press_ &&
+ aura::client::GetTooltipText(target) != tooltip_text_at_mouse_press_) {
+ tooltip_window_at_mouse_press_ = NULL;
+ }
+
// If we had stopped the tooltip timer for some reason, we must restart it if
// there is a change in the tooltip.
if (!tooltip_timer_.IsRunning()) {
@@ -174,14 +187,15 @@ void TooltipController::OnMouseEvent(ui::MouseEvent* event) {
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_DRAGGED: {
curr_mouse_loc_ = event->location();
- aura::Window* target = GetTooltipTarget(*event, &curr_mouse_loc_);
- if (tooltip_window_ != target) {
- if (tooltip_window_)
- tooltip_window_->RemoveObserver(this);
- tooltip_window_ = target;
- if (tooltip_window_)
- tooltip_window_->AddObserver(this);
+ aura::Window* target = NULL;
+ // Avoid a call to gfx::Screen::GetWindowAtScreenPoint() since it can be
+ // very expensive on X11 in cases when the tooltip is hidden anyway.
+ if (tooltips_enabled_ &&
+ !aura::Env::GetInstance()->IsMouseButtonDown() &&
+ !IsDragDropInProgress()) {
+ target = GetTooltipTarget(*event, &curr_mouse_loc_);
}
+ SetTooltipWindow(target);
if (tooltip_timer_.IsRunning())
tooltip_timer_.Reset();
@@ -214,13 +228,12 @@ void TooltipController::OnTouchEvent(ui::TouchEvent* event) {
// touch events.
// Hide the tooltip for touch events.
tooltip_->Hide();
- if (tooltip_window_)
- tooltip_window_->RemoveObserver(this);
- tooltip_window_ = NULL;
+ SetTooltipWindow(NULL);
}
void TooltipController::OnCancelMode(ui::CancelModeEvent* event) {
tooltip_->Hide();
+ SetTooltipWindow(NULL);
}
void TooltipController::OnWindowDestroyed(aura::Window* window) {
@@ -255,7 +268,7 @@ void TooltipController::UpdateIfRequired() {
return;
}
- string16 tooltip_text;
+ base::string16 tooltip_text;
if (tooltip_window_)
tooltip_text = aura::client::GetTooltipText(tooltip_window_);
@@ -270,12 +283,19 @@ void TooltipController::UpdateIfRequired() {
tooltip_window_at_mouse_press_ = NULL;
}
+ // If the uniqueness indicator is different from the previously encountered
+ // one, we should force tooltip update
+ const void* tooltip_id = aura::client::GetTooltipId(tooltip_window_);
+ bool ids_differ = false;
+ ids_differ = tooltip_id_ != tooltip_id;
+ tooltip_id_ = tooltip_id;
+
// We add the !tooltip_->IsVisible() below because when we come here from
// TooltipTimerFired(), the tooltip_text may not have changed but we still
// want to update the tooltip because the timer has fired.
// If we come here from UpdateTooltip(), we have already checked for tooltip
// visibility and this check below will have no effect.
- if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible()) {
+ if (tooltip_text_ != tooltip_text || !tooltip_->IsVisible() || ids_differ) {
tooltip_shown_timer_.Stop();
tooltip_text_ = tooltip_text;
base::string16 trimmed_text(tooltip_text_);
@@ -283,13 +303,14 @@ void TooltipController::UpdateIfRequired() {
// If the string consists entirely of whitespace, then don't both showing it
// (an empty tooltip is useless).
base::string16 whitespace_removed_text;
- TrimWhitespace(trimmed_text, TRIM_ALL, &whitespace_removed_text);
+ base::TrimWhitespace(trimmed_text, base::TRIM_ALL,
+ &whitespace_removed_text);
if (whitespace_removed_text.empty()) {
tooltip_->Hide();
} else {
gfx::Point widget_loc = curr_mouse_loc_ +
tooltip_window_->GetBoundsInScreen().OffsetFromOrigin();
- tooltip_->SetText(tooltip_window_, trimmed_text, widget_loc);
+ tooltip_->SetText(tooltip_window_, whitespace_removed_text, widget_loc);
tooltip_->Show();
int timeout = GetTooltipShownTimeout();
if (timeout > 0) {
@@ -333,5 +354,15 @@ int TooltipController::GetTooltipShownTimeout() {
return it->second;
}
+void TooltipController::SetTooltipWindow(aura::Window* target) {
+ if (tooltip_window_ == target)
+ return;
+ if (tooltip_window_)
+ tooltip_window_->RemoveObserver(this);
+ tooltip_window_ = target;
+ if (tooltip_window_)
+ tooltip_window_->AddObserver(this);
+}
+
} // namespace corewm
} // namespace views
diff --git a/chromium/ui/views/corewm/tooltip_controller.h b/chromium/ui/views/corewm/tooltip_controller.h
index 66b6a3224c7..e0453341f00 100644
--- a/chromium/ui/views/corewm/tooltip_controller.h
+++ b/chromium/ui/views/corewm/tooltip_controller.h
@@ -10,11 +10,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/timer/timer.h"
-#include "ui/aura/client/tooltip_client.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/point.h"
#include "ui/views/views_export.h"
+#include "ui/wm/public/tooltip_client.h"
namespace aura {
class Window;
@@ -61,7 +61,7 @@ class VIEWS_EXPORT TooltipController : public aura::client::TooltipClient,
void TooltipShownTimerFired();
// Updates the tooltip if required (if there is any change in the tooltip
- // text or the aura::Window.
+ // text, tooltip id or the aura::Window).
void UpdateIfRequired();
// Only used in tests.
@@ -74,8 +74,14 @@ class VIEWS_EXPORT TooltipController : public aura::client::TooltipClient,
int GetTooltipShownTimeout();
+ // Sets tooltip window to |target| if it is different from existing window.
+ // Calls RemoveObserver on the existing window if it is not NULL.
+ // Calls AddObserver on the new window if it is not NULL.
+ void SetTooltipWindow(aura::Window* target);
+
aura::Window* tooltip_window_;
base::string16 tooltip_text_;
+ const void* tooltip_id_;
// These fields are for tracking state when the user presses a mouse button.
aura::Window* tooltip_window_at_mouse_press_;
diff --git a/chromium/ui/views/corewm/tooltip_controller_test_helper.cc b/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
index 4794a6e73e4..f96b08dc50a 100644
--- a/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
@@ -19,7 +19,7 @@ TooltipControllerTestHelper::TooltipControllerTestHelper(
TooltipControllerTestHelper::~TooltipControllerTestHelper() {
}
-string16 TooltipControllerTestHelper::GetTooltipText() {
+base::string16 TooltipControllerTestHelper::GetTooltipText() {
return controller_->tooltip_text_;
}
@@ -55,7 +55,7 @@ TooltipTestView::~TooltipTestView() {
}
bool TooltipTestView::GetTooltipText(const gfx::Point& p,
- string16* tooltip) const {
+ base::string16* tooltip) const {
*tooltip = tooltip_text_;
return true;
}
diff --git a/chromium/ui/views/corewm/tooltip_controller_test_helper.h b/chromium/ui/views/corewm/tooltip_controller_test_helper.h
index 58386200000..4451ff35fec 100644
--- a/chromium/ui/views/corewm/tooltip_controller_test_helper.h
+++ b/chromium/ui/views/corewm/tooltip_controller_test_helper.h
@@ -31,7 +31,7 @@ class TooltipControllerTestHelper {
TooltipController* controller() { return controller_; }
// These are mostly cover methods for TooltipController private methods.
- string16 GetTooltipText();
+ base::string16 GetTooltipText();
aura::Window* GetTooltipWindow();
void FireTooltipTimer();
bool IsTooltipTimerRunning();
@@ -51,14 +51,16 @@ class TooltipTestView : public views::View {
TooltipTestView();
virtual ~TooltipTestView();
- void set_tooltip_text(string16 tooltip_text) { tooltip_text_ = tooltip_text; }
+ void set_tooltip_text(base::string16 tooltip_text) {
+ tooltip_text_ = tooltip_text;
+ }
// Overridden from views::View
virtual bool GetTooltipText(const gfx::Point& p,
- string16* tooltip) const OVERRIDE;
+ base::string16* tooltip) const OVERRIDE;
private:
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(TooltipTestView);
};
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index 6ebf4b9f828..e3487ae854b 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -7,14 +7,13 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/tooltip_client.h"
-#include "ui/aura/client/window_types.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/font.h"
#include "ui/gfx/point.h"
@@ -23,9 +22,15 @@
#include "ui/gfx/text_elider.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/corewm/tooltip_controller_test_helper.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/views/test/test_views_delegate.h"
#include "ui/views/view.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/core/default_activation_client.h"
+#include "ui/wm/core/wm_state.h"
+#include "ui/wm/public/tooltip_client.h"
+#include "ui/wm/public/window_types.h"
#if defined(OS_WIN)
#include "ui/base/win/scoped_ole_initializer.h"
@@ -36,6 +41,8 @@
#include "ui/views/widget/desktop_aura/desktop_screen.h"
#endif
+using base::ASCIIToUTF16;
+
namespace views {
namespace corewm {
namespace test {
@@ -72,7 +79,14 @@ class TooltipControllerTest : public aura::test::AuraTestBase {
virtual ~TooltipControllerTest() {}
virtual void SetUp() OVERRIDE {
+#if defined(OS_CHROMEOS)
+ views_delegate_.reset(new TestViewsDelegate);
+#else
+ views_delegate_.reset(new DesktopTestViewsDelegate);
+#endif
+
aura::test::AuraTestBase::SetUp();
+ new wm::DefaultActivationClient(root_window());
#if defined(OS_CHROMEOS)
controller_.reset(new TooltipController(
scoped_ptr<views::corewm::Tooltip>(
@@ -100,6 +114,7 @@ class TooltipControllerTest : public aura::test::AuraTestBase {
helper_.reset();
widget_.reset();
aura::test::AuraTestBase::TearDown();
+ views_delegate_.reset();
}
protected:
@@ -126,6 +141,9 @@ class TooltipControllerTest : public aura::test::AuraTestBase {
private:
scoped_ptr<TooltipController> controller_;
+
+ scoped_ptr<views::TestViewsDelegate> views_delegate_;
+
#if defined(OS_WIN)
ui::ScopedOleInitializer ole_initializer_;
#endif
@@ -135,15 +153,15 @@ class TooltipControllerTest : public aura::test::AuraTestBase {
TEST_F(TooltipControllerTest, ViewTooltip) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
generator_->MoveMouseToCenterOf(GetWindow());
EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint(
generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
// Fire tooltip timer so tooltip becomes visible.
@@ -160,7 +178,7 @@ TEST_F(TooltipControllerTest, ViewTooltip) {
TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
PrepareSecondView();
@@ -176,7 +194,7 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
EXPECT_TRUE(helper_->IsTooltipVisible());
EXPECT_EQ(window, root_window->GetEventHandlerForPoint(
generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -186,7 +204,7 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
EXPECT_FALSE(helper_->IsTooltipVisible());
EXPECT_EQ(window, root_window->GetEventHandlerForPoint(
generator_->current_location()));
- string16 expected_tooltip; // = ""
+ base::string16 expected_tooltip; // = ""
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -195,11 +213,11 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
TEST_F(TooltipControllerTest, EnableOrDisableTooltips) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint());
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
// Fire tooltip timer so tooltip becomes visible.
helper_->FireTooltipTimer();
@@ -221,7 +239,7 @@ TEST_F(TooltipControllerTest, EnableOrDisableTooltips) {
// Verifies tooltip isn't shown if tooltip text consists entirely of whitespace.
TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
view_->set_tooltip_text(ASCIIToUTF16(" "));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint());
@@ -232,7 +250,7 @@ TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
TooltipTestView* view2 = PrepareSecondView();
@@ -261,7 +279,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
EXPECT_EQ(window,
GetRootWindow()->GetEventHandlerForPoint(
generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -273,7 +291,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
helper_->FireTooltipTimer();
EXPECT_TRUE(helper_->IsTooltipVisible());
EXPECT_TRUE(helper_->IsTooltipShownTimerRunning());
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -281,7 +299,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
TooltipTestView* view2 = PrepareSecondView();
@@ -309,7 +327,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
EXPECT_EQ(window, GetRootWindow()->GetEventHandlerForPoint(
generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -321,7 +339,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
helper_->FireTooltipTimer();
EXPECT_TRUE(helper_->IsTooltipVisible());
EXPECT_TRUE(helper_->IsTooltipShownTimerRunning());
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
EXPECT_EQ(window, helper_->GetTooltipWindow());
@@ -331,9 +349,9 @@ TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
TEST_F(TooltipControllerTest, HideOnExit) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
generator_->MoveMouseToCenterOf(GetWindow());
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
// Fire tooltip timer so tooltip becomes visible.
@@ -344,6 +362,44 @@ TEST_F(TooltipControllerTest, HideOnExit) {
EXPECT_FALSE(helper_->IsTooltipVisible());
}
+TEST_F(TooltipControllerTest, ReshowOnClickAfterEnterExit) {
+ // Owned by |view_|.
+ TooltipTestView* v1 = new TooltipTestView;
+ TooltipTestView* v2 = new TooltipTestView;
+ view_->AddChildView(v1);
+ view_->AddChildView(v2);
+ gfx::Rect view_bounds(view_->GetLocalBounds());
+ view_bounds.set_height(view_bounds.height() / 2);
+ v1->SetBoundsRect(view_bounds);
+ view_bounds.set_y(view_bounds.height());
+ v2->SetBoundsRect(view_bounds);
+ const base::string16 v1_tt(ASCIIToUTF16("v1"));
+ const base::string16 v2_tt(ASCIIToUTF16("v2"));
+ v1->set_tooltip_text(v1_tt);
+ v2->set_tooltip_text(v2_tt);
+
+ gfx::Point v1_point(1, 1);
+ View::ConvertPointToWidget(v1, &v1_point);
+ generator_->MoveMouseRelativeTo(GetWindow(), v1_point);
+
+ // Fire tooltip timer so tooltip becomes visible.
+ helper_->FireTooltipTimer();
+ EXPECT_TRUE(helper_->IsTooltipVisible());
+ EXPECT_EQ(v1_tt, helper_->GetTooltipText());
+
+ // Press the mouse, move to v2 and back to v1.
+ generator_->ClickLeftButton();
+
+ gfx::Point v2_point(1, 1);
+ View::ConvertPointToWidget(v2, &v2_point);
+ generator_->MoveMouseRelativeTo(GetWindow(), v2_point);
+ generator_->MoveMouseRelativeTo(GetWindow(), v1_point);
+
+ helper_->FireTooltipTimer();
+ EXPECT_TRUE(helper_->IsTooltipVisible());
+ EXPECT_EQ(v1_tt, helper_->GetTooltipText());
+}
+
namespace {
// Returns the index of |window| in its parent's children.
@@ -419,11 +475,12 @@ class TooltipControllerCaptureTest : public TooltipControllerTest {
// Verifies when capture is released the TooltipController resets state.
TEST_F(TooltipControllerCaptureTest, CloseOnCaptureLost) {
view_->GetWidget()->SetCapture(view_);
+ RunAllPendingInMessageLoop();
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
generator_->MoveMouseToCenterOf(GetWindow());
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
// Fire tooltip timer so tooltip becomes visible.
@@ -444,8 +501,8 @@ TEST_F(TooltipControllerCaptureTest, CloseOnCaptureLost) {
#endif
// Verifies the correct window is found for tooltips when there is a capture.
TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) {
- const string16 tooltip_text(ASCIIToUTF16("1"));
- const string16 tooltip_text2(ASCIIToUTF16("2"));
+ const base::string16 tooltip_text(ASCIIToUTF16("1"));
+ const base::string16 tooltip_text2(ASCIIToUTF16("2"));
widget_->SetBounds(gfx::Rect(0, 0, 200, 200));
view_->set_tooltip_text(tooltip_text);
@@ -490,120 +547,285 @@ TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) {
widget2.reset();
}
-#if !defined(OS_CHROMEOS)
-// This test creates two top level windows and verifies that the tooltip
-// displays correctly when mouse moves are dispatched to these windows.
-// Additionally it also verifies that the tooltip is reparented to the new
-// window when mouse moves are dispatched to it.
-TEST_F(TooltipControllerTest, TooltipsInMultipleRootWindows) {
- view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text For RootWindow1"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
- EXPECT_EQ(NULL, helper_->GetTooltipWindow());
+namespace {
- aura::Window* window = GetWindow();
- aura::Window* root_window = GetRootWindow();
+class TestTooltip : public Tooltip {
+ public:
+ TestTooltip() : is_visible_(false) {}
+ virtual ~TestTooltip() {}
- // Fire tooltip timer so tooltip becomes visible.
- generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint());
- helper_->FireTooltipTimer();
- EXPECT_TRUE(helper_->IsTooltipVisible());
- for (int i = 0; i < 49; ++i) {
- generator_->MoveMouseBy(1, 0);
- EXPECT_TRUE(helper_->IsTooltipVisible());
- EXPECT_EQ(window, root_window->GetEventHandlerForPoint(
- generator_->current_location()));
- string16 expected_tooltip =
- ASCIIToUTF16("Tooltip Text For RootWindow1");
- EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window));
- EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
- EXPECT_EQ(window, helper_->GetTooltipWindow());
+ const base::string16& tooltip_text() const { return tooltip_text_; }
+
+ // Tooltip:
+ virtual void SetText(aura::Window* window,
+ const base::string16& tooltip_text,
+ const gfx::Point& location) OVERRIDE {
+ tooltip_text_ = tooltip_text;
+ location_ = location;
+ }
+ virtual void Show() OVERRIDE {
+ is_visible_ = true;
}
+ virtual void Hide() OVERRIDE {
+ is_visible_ = false;
+ }
+ virtual bool IsVisible() OVERRIDE {
+ return is_visible_;
+ }
+ const gfx::Point& location() { return location_; }
+
+ private:
+ bool is_visible_;
+ base::string16 tooltip_text_;
+ gfx::Point location_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTooltip);
+};
+
+} // namespace
+
+// Use for tests that don't depend upon views.
+class TooltipControllerTest2 : public aura::test::AuraTestBase {
+ public:
+ TooltipControllerTest2() : test_tooltip_(new TestTooltip) {}
+ virtual ~TooltipControllerTest2() {}
+
+ virtual void SetUp() OVERRIDE {
+ wm_state_.reset(new wm::WMState);
+ aura::test::AuraTestBase::SetUp();
+ new wm::DefaultActivationClient(root_window());
+ controller_.reset(new TooltipController(
+ scoped_ptr<corewm::Tooltip>(test_tooltip_)));
+ root_window()->AddPreTargetHandler(controller_.get());
+ SetTooltipClient(root_window(), controller_.get());
+ helper_.reset(new TooltipControllerTestHelper(controller_.get()));
+ generator_.reset(new aura::test::EventGenerator(root_window()));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ root_window()->RemovePreTargetHandler(controller_.get());
+ aura::client::SetTooltipClient(root_window(), NULL);
+ controller_.reset();
+ generator_.reset();
+ helper_.reset();
+ aura::test::AuraTestBase::TearDown();
+ wm_state_.reset();
+ }
+
+ protected:
+ // Owned by |controller_|.
+ TestTooltip* test_tooltip_;
+ scoped_ptr<TooltipControllerTestHelper> helper_;
+ scoped_ptr<aura::test::EventGenerator> generator_;
+
+ private:
+ scoped_ptr<TooltipController> controller_;
+ scoped_ptr<wm::WMState> wm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2);
+};
+
+TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) {
+ aura::test::TestWindowDelegate test_delegate;
+ scoped_ptr<aura::Window> window(
+ CreateNormalWindow(100, root_window(), &test_delegate));
+ window->SetBounds(gfx::Rect(0, 0, 300, 300));
+ base::string16 tooltip_text(ASCIIToUTF16(" \nx "));
+ aura::client::SetTooltipText(window.get(), &tooltip_text);
+ generator_->MoveMouseToCenterOf(window.get());
+ helper_->FireTooltipTimer();
+ EXPECT_EQ(ASCIIToUTF16("x"), test_tooltip_->tooltip_text());
+}
+
+// Verifies that tooltip is hidden and tooltip window closed upon cancel mode.
+TEST_F(TooltipControllerTest2, CloseOnCancelMode) {
+ aura::test::TestWindowDelegate test_delegate;
+ scoped_ptr<aura::Window> window(
+ CreateNormalWindow(100, root_window(), &test_delegate));
+ window->SetBounds(gfx::Rect(0, 0, 300, 300));
+ base::string16 tooltip_text(ASCIIToUTF16("Tooltip Text"));
+ aura::client::SetTooltipText(window.get(), &tooltip_text);
+ generator_->MoveMouseToCenterOf(window.get());
- views::Widget* widget2 = CreateWidget(NULL);
- widget2->SetContentsView(new View);
- TooltipTestView* view2 = new TooltipTestView;
- widget2->GetContentsView()->AddChildView(view2);
- view2->SetBoundsRect(widget2->GetContentsView()->GetLocalBounds());
- helper_.reset(new TooltipControllerTestHelper(
- GetController(widget2)));
- generator_.reset(new aura::test::EventGenerator(
- widget2->GetNativeWindow()->GetRootWindow()));
- view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text For RootWindow2"));
-
- aura::Window* window2 = widget2->GetNativeWindow();
- aura::Window* root_window2 =
- widget2->GetNativeWindow()->GetRootWindow();
// Fire tooltip timer so tooltip becomes visible.
- generator_->MoveMouseRelativeTo(window2, view2->bounds().CenterPoint());
helper_->FireTooltipTimer();
+ EXPECT_TRUE(helper_->IsTooltipVisible());
- EXPECT_NE(root_window, root_window2);
- EXPECT_NE(window, window2);
+ // Send OnCancelMode event and verify that tooltip becomes invisible and
+ // the tooltip window is closed.
+ ui::CancelModeEvent event;
+ helper_->controller()->OnCancelMode(&event);
+ EXPECT_FALSE(helper_->IsTooltipVisible());
+ EXPECT_TRUE(helper_->GetTooltipWindow() == NULL);
+}
- for (int i = 0; i < 49; ++i) {
- generator_->MoveMouseBy(1, 0);
- EXPECT_TRUE(helper_->IsTooltipVisible());
- EXPECT_EQ(window2, root_window2->GetEventHandlerForPoint(
- generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text For RootWindow2");
- EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window2));
- EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
- EXPECT_EQ(window2, helper_->GetTooltipWindow());
+// Use for tests that need both views and a TestTooltip.
+class TooltipControllerTest3 : public aura::test::AuraTestBase {
+ public:
+ TooltipControllerTest3() : test_tooltip_(new TestTooltip) {}
+ virtual ~TooltipControllerTest3() {}
+
+ virtual void SetUp() OVERRIDE {
+ wm_state_.reset(new wm::WMState);
+ aura::test::AuraTestBase::SetUp();
+ new wm::DefaultActivationClient(root_window());
+
+ widget_.reset(CreateWidget(root_window()));
+ widget_->SetContentsView(new View);
+ view_ = new TooltipTestView;
+ widget_->GetContentsView()->AddChildView(view_);
+ view_->SetBoundsRect(widget_->GetContentsView()->GetLocalBounds());
+
+ generator_.reset(new aura::test::EventGenerator(GetRootWindow()));
+ controller_.reset(new TooltipController(
+ scoped_ptr<views::corewm::Tooltip>(test_tooltip_)));
+ GetRootWindow()->RemovePreTargetHandler(
+ static_cast<TooltipController*>(aura::client::GetTooltipClient(
+ widget_->GetNativeWindow()->GetRootWindow())));
+ GetRootWindow()->AddPreTargetHandler(controller_.get());
+ helper_.reset(new TooltipControllerTestHelper(controller_.get()));
+ SetTooltipClient(GetRootWindow(), controller_.get());
}
- bool tooltip_reparented = false;
- for (size_t i = 0; i < root_window2->children().size(); ++i) {
- if (root_window2->children()[i]->type() ==
- aura::client::WINDOW_TYPE_TOOLTIP) {
- tooltip_reparented = true;
- break;
- }
+ virtual void TearDown() OVERRIDE {
+ GetRootWindow()->RemovePreTargetHandler(controller_.get());
+ aura::client::SetTooltipClient(GetRootWindow(), NULL);
+
+ controller_.reset();
+ generator_.reset();
+ helper_.reset();
+ widget_.reset();
+ aura::test::AuraTestBase::TearDown();
+ wm_state_.reset();
}
- EXPECT_TRUE(tooltip_reparented);
- widget2->Close();
-}
-// This test validates whether the tooltip after becoming visible stays at the
-// top of the ZOrder in its root window after activation changes.
-TEST_F(TooltipControllerTest, TooltipAtTopOfZOrderAfterActivation) {
- view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
- EXPECT_EQ(NULL, helper_->GetTooltipWindow());
- generator_->MoveMouseToCenterOf(GetWindow());
+ aura::Window* GetWindow() { return widget_->GetNativeWindow(); }
- EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint(
- generator_->current_location()));
- string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
- EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
- EXPECT_EQ(string16(), helper_->GetTooltipText());
- EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
+ protected:
+ // Owned by |controller_|.
+ TestTooltip* test_tooltip_;
+ scoped_ptr<TooltipControllerTestHelper> helper_;
+ scoped_ptr<aura::test::EventGenerator> generator_;
+ scoped_ptr<views::Widget> widget_;
+ TooltipTestView* view_;
- // Fire tooltip timer so tooltip becomes visible.
+ private:
+ scoped_ptr<TooltipController> controller_;
+ scoped_ptr<wm::WMState> wm_state_;
+
+#if defined(OS_WIN)
+ ui::ScopedOleInitializer ole_initializer_;
+#endif
+
+ aura::Window* GetRootWindow() { return GetWindow()->GetRootWindow(); }
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest3);
+};
+
+TEST_F(TooltipControllerTest3, TooltipPositionChangesOnTwoViewsWithSameLabel) {
+ // Owned by |view_|.
+ // These two views have the same tooltip text
+ TooltipTestView* v1 = new TooltipTestView;
+ TooltipTestView* v2 = new TooltipTestView;
+ // v1_1 is a view inside v1 that has an identical tooltip text to that of v1
+ // and v2
+ TooltipTestView* v1_1 = new TooltipTestView;
+ // v2_1 is a view inside v2 that has an identical tooltip text to that of v1
+ // and v2
+ TooltipTestView* v2_1 = new TooltipTestView;
+ // v2_2 is a view inside v2 with the tooltip text different from all the
+ // others
+ TooltipTestView* v2_2 = new TooltipTestView;
+
+ // Setup all the views' relations
+ view_->AddChildView(v1);
+ view_->AddChildView(v2);
+ v1->AddChildView(v1_1);
+ v2->AddChildView(v2_1);
+ v2->AddChildView(v2_2);
+ const base::string16 reference_string(
+ base::ASCIIToUTF16("Identical Tooltip Text"));
+ const base::string16 alternative_string(
+ base::ASCIIToUTF16("Another Shrubbery"));
+ v1->set_tooltip_text(reference_string);
+ v2->set_tooltip_text(reference_string);
+ v1_1->set_tooltip_text(reference_string);
+ v2_1->set_tooltip_text(reference_string);
+ v2_2->set_tooltip_text(alternative_string);
+
+ // Set views' bounds
+ gfx::Rect view_bounds(view_->GetLocalBounds());
+ view_bounds.set_height(view_bounds.height() / 2);
+ v1->SetBoundsRect(view_bounds);
+ v1_1->SetBounds(0, 0, 3, 3);
+ view_bounds.set_y(view_bounds.height());
+ v2->SetBoundsRect(view_bounds);
+ v2_2->SetBounds(view_bounds.width() - 3, view_bounds.height() - 3, 3, 3);
+ v2_1->SetBounds(0, 0, 3, 3);
+
+ // Test whether a toolbar appears on v1
+ gfx::Point center = v1->bounds().CenterPoint();
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
helper_->FireTooltipTimer();
+ EXPECT_TRUE(helper_->IsTooltipVisible());
+ EXPECT_EQ(reference_string, helper_->GetTooltipText());
+ gfx::Point tooltip_bounds1 = test_tooltip_->location();
+ // Test whether the toolbar changes position on mouse over v2
+ center = v2->bounds().CenterPoint();
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
+ helper_->FireTooltipTimer();
EXPECT_TRUE(helper_->IsTooltipVisible());
- generator_->MoveMouseBy(1, 0);
+ EXPECT_EQ(reference_string, helper_->GetTooltipText());
+ gfx::Point tooltip_bounds2 = test_tooltip_->location();
+
+ EXPECT_NE(tooltip_bounds1, gfx::Point());
+ EXPECT_NE(tooltip_bounds2, gfx::Point());
+ EXPECT_NE(tooltip_bounds1, tooltip_bounds2);
+
+ // Test if the toolbar does not change position on encountering a contained
+ // view with the same tooltip text
+ center = v2_1->GetLocalBounds().CenterPoint();
+ views::View::ConvertPointToTarget(v2_1, view_, &center);
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
+ helper_->FireTooltipTimer();
+ gfx::Point tooltip_bounds2_1 = test_tooltip_->location();
+ EXPECT_NE(tooltip_bounds2, tooltip_bounds2_1);
EXPECT_TRUE(helper_->IsTooltipVisible());
- EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow()));
- EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
- EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow());
+ EXPECT_EQ(reference_string, helper_->GetTooltipText());
+
+ // Test if the toolbar changes position on encountering a contained
+ // view with a different tooltip text
+ center = v2_2->GetLocalBounds().CenterPoint();
+ views::View::ConvertPointToTarget(v2_2, view_, &center);
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
+ helper_->FireTooltipTimer();
+ gfx::Point tooltip_bounds2_2 = test_tooltip_->location();
- // Fake activation loss and gain in the native widget. This should cause a
- // ZOrder change which should not affect the position of the tooltip.
- DesktopNativeWidgetAura* native_widget =
- static_cast<DesktopNativeWidgetAura*>(widget_->native_widget());
- EXPECT_TRUE(native_widget != NULL);
+ EXPECT_NE(tooltip_bounds2_1, tooltip_bounds2_2);
+ EXPECT_TRUE(helper_->IsTooltipVisible());
+ EXPECT_EQ(alternative_string, helper_->GetTooltipText());
- native_widget->HandleActivationChanged(false);
- native_widget->HandleActivationChanged(true);
+ // Test if moving from a view that is contained by a larger view, both with
+ // the same tooltip text, does not change tooltip's position.
+ center = v1_1->GetLocalBounds().CenterPoint();
+ views::View::ConvertPointToTarget(v1_1, view_, &center);
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
+ helper_->FireTooltipTimer();
+ gfx::Point tooltip_bounds1_1 = test_tooltip_->location();
- EXPECT_EQ(
- widget_->GetNativeWindow()->GetRootWindow()->children().back()->type(),
- aura::client::WINDOW_TYPE_TOOLTIP);
-}
+ EXPECT_TRUE(helper_->IsTooltipVisible());
+ EXPECT_EQ(reference_string, helper_->GetTooltipText());
-#endif
+ center = v1->bounds().CenterPoint();
+ generator_->MoveMouseRelativeTo(GetWindow(), center);
+ helper_->FireTooltipTimer();
+ tooltip_bounds1 = test_tooltip_->location();
+
+ EXPECT_NE(tooltip_bounds1_1, tooltip_bounds1);
+ EXPECT_EQ(reference_string, helper_->GetTooltipText());
+}
} // namespace test
} // namespace corewm
diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc
index 10341d61635..4d2a4badb0e 100644
--- a/chromium/ui/views/corewm/tooltip_win.cc
+++ b/chromium/ui/views/corewm/tooltip_win.cc
@@ -12,6 +12,8 @@
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/win/dpi.h"
+#include "ui/views/corewm/cursor_height_provider_win.h"
namespace views {
namespace corewm {
@@ -63,7 +65,7 @@ bool TooltipWin::EnsureTooltipWindow() {
TOOLTIPS_CLASS, NULL, TTS_NOPREFIX | WS_POPUP, 0, 0, 0, 0,
parent_hwnd_, NULL, NULL, NULL);
if (!tooltip_hwnd_) {
- LOG_GETLASTERROR(WARNING) << "tooltip creation failed, disabling tooltips";
+ PLOG(WARNING) << "tooltip creation failed, disabling tooltips";
return false;
}
@@ -76,20 +78,19 @@ bool TooltipWin::EnsureTooltipWindow() {
void TooltipWin::PositionTooltip() {
// This code only runs for non-metro, so GetNativeScreen() is fine.
- gfx::Display display(
- gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(location_));
+ gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_);
+ const int cursoroffset = GetCurrentCursorVisibleHeight();
+ screen_point.Offset(0, cursoroffset);
DWORD tooltip_size = SendMessage(tooltip_hwnd_, TTM_GETBUBBLESIZE, 0,
reinterpret_cast<LPARAM>(&toolinfo_));
- // 20 accounts for visible cursor size. I tried using SM_CYCURSOR but that's
- // way too big (32 on win7 default).
- // TODO(sky): figure out the right way to determine offset.
- const int initial_y = location_.y();
- gfx::Rect tooltip_bounds(location_.x(), initial_y + 20,
- LOWORD(tooltip_size), HIWORD(tooltip_size));
- tooltip_bounds.AdjustToFit(display.work_area());
- if (tooltip_bounds.y() < initial_y)
- tooltip_bounds.set_y(initial_y - tooltip_bounds.height() - 2);
+ const gfx::Size size(LOWORD(tooltip_size), HIWORD(tooltip_size));
+
+ const gfx::Display display(
+ gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point));
+
+ gfx::Rect tooltip_bounds(screen_point, size);
+ tooltip_bounds.AdjustToFit(gfx::win::DIPToScreenRect(display.work_area()));
SetWindowPos(tooltip_hwnd_, NULL, tooltip_bounds.x(), tooltip_bounds.y(), 0,
0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
@@ -116,8 +117,9 @@ void TooltipWin::SetText(aura::Window* window,
reinterpret_cast<LPARAM>(&toolinfo_));
// This code only runs for non-metro, so GetNativeScreen() is fine.
+ const gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_);
gfx::Display display(
- gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(location_));
+ gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(screen_point));
const gfx::Rect monitor_bounds = display.bounds();
int max_width = (monitor_bounds.width() + 1) / 2;
SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, max_width);
@@ -134,7 +136,7 @@ void TooltipWin::Show() {
}
void TooltipWin::Hide() {
- if (!EnsureTooltipWindow())
+ if (!tooltip_hwnd_)
return;
SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, FALSE,
diff --git a/chromium/ui/views/corewm/tooltip_win.h b/chromium/ui/views/corewm/tooltip_win.h
index e454aac8773..b031a3204eb 100644
--- a/chromium/ui/views/corewm/tooltip_win.h
+++ b/chromium/ui/views/corewm/tooltip_win.h
@@ -24,7 +24,7 @@ class VIEWS_EXPORT TooltipWin : public Tooltip {
explicit TooltipWin(HWND parent);
virtual ~TooltipWin();
- // HandleNotify() is forwarded from DesktopRootWindowHostWin to keep the
+ // HandleNotify() is forwarded from DesktopWindowTreeHostWin to keep the
// native tooltip in sync.
bool HandleNotify(int w_param, NMHDR* l_param, LRESULT* l_result);
diff --git a/chromium/ui/views/corewm/transient_window_stacking_client.cc b/chromium/ui/views/corewm/transient_window_stacking_client.cc
deleted file mode 100644
index 6a4f8ab25cb..00000000000
--- a/chromium/ui/views/corewm/transient_window_stacking_client.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/transient_window_stacking_client.h"
-
-#include <algorithm>
-
-using aura::Window;
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-// Populates |ancestors| with all transient ancestors of |window| that are
-// siblings of |window|. Returns true if any ancestors were found, false if not.
-bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) {
- Window* parent = window->parent();
- for (; window; window = window->transient_parent()) {
- if (window->parent() == parent)
- ancestors->push_back(window);
- }
- return (!ancestors->empty());
-}
-
-// Replaces |window1| and |window2| with their possible transient ancestors that
-// are still siblings (have a common transient parent). |window1| and |window2|
-// are not modified if such ancestors cannot be found.
-void FindCommonTransientAncestor(Window** window1, Window** window2) {
- DCHECK(window1);
- DCHECK(window2);
- DCHECK(*window1);
- DCHECK(*window2);
- // Assemble chains of ancestors of both windows.
- Window::Windows ancestors1;
- Window::Windows ancestors2;
- if (!GetAllTransientAncestors(*window1, &ancestors1) ||
- !GetAllTransientAncestors(*window2, &ancestors2)) {
- return;
- }
- // Walk the two chains backwards and look for the first difference.
- Window::Windows::const_reverse_iterator it1 = ancestors1.rbegin();
- Window::Windows::const_reverse_iterator it2 = ancestors2.rbegin();
- for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
- if (*it1 != *it2) {
- *window1 = *it1;
- *window2 = *it2;
- break;
- }
- }
-}
-
-// Returns true if |window| has |ancestor| as a transient ancestor. A transient
-// ancestor is found by following the transient parent chain of the window.
-bool HasTransientAncestor(const Window* window, const Window* ancestor) {
- if (window->transient_parent() == ancestor)
- return true;
- return window->transient_parent() ?
- HasTransientAncestor(window->transient_parent(), ancestor) : false;
-}
-
-} // namespace
-
-TransientWindowStackingClient::TransientWindowStackingClient() {
-}
-
-TransientWindowStackingClient::~TransientWindowStackingClient() {
-}
-
-void TransientWindowStackingClient::AdjustStacking(
- Window** child,
- Window** target,
- Window::StackDirection* direction) {
- // For windows that have transient children stack the transient ancestors that
- // are siblings. This prevents one transient group from being inserted in the
- // middle of another.
- FindCommonTransientAncestor(child, target);
-
- // When stacking above skip to the topmost transient descendant of the target.
- if (*direction == Window::STACK_ABOVE &&
- !HasTransientAncestor(*child, *target)) {
- const Window::Windows& siblings((*child)->parent()->children());
- size_t target_i =
- std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
- while (target_i + 1 < siblings.size() &&
- HasTransientAncestor(siblings[target_i + 1], *target)) {
- ++target_i;
- }
- *target = siblings[target_i];
- }
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/transient_window_stacking_client.h b/chromium/ui/views/corewm/transient_window_stacking_client.h
deleted file mode 100644
index 19358362bcb..00000000000
--- a/chromium/ui/views/corewm/transient_window_stacking_client.h
+++ /dev/null
@@ -1,32 +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_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
-#define UI_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
-
-#include "ui/aura/client/window_stacking_client.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-
-class VIEWS_EXPORT TransientWindowStackingClient
- : public aura::client::WindowStackingClient {
- public:
- TransientWindowStackingClient();
- virtual ~TransientWindowStackingClient();
-
- // WindowStackingClient:
- virtual void AdjustStacking(aura::Window** child,
- aura::Window** target,
- aura::Window::StackDirection* direction) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClient);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
diff --git a/chromium/ui/views/corewm/transient_window_stacking_client_unittest.cc b/chromium/ui/views/corewm/transient_window_stacking_client_unittest.cc
deleted file mode 100644
index a84b832e596..00000000000
--- a/chromium/ui/views/corewm/transient_window_stacking_client_unittest.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/transient_window_stacking_client.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_windows.h"
-
-using aura::test::ChildWindowIDsAsString;
-using aura::test::CreateTestWindowWithId;
-using aura::Window;
-
-namespace views {
-namespace corewm {
-
-class TransientWindowStackingClientTest : public aura::test::AuraTestBase {
- public:
- TransientWindowStackingClientTest() {}
- virtual ~TransientWindowStackingClientTest() {}
-
- virtual void SetUp() OVERRIDE {
- AuraTestBase::SetUp();
- aura::client::SetWindowStackingClient(new TransientWindowStackingClient);
- }
-
- virtual void TearDown() OVERRIDE {
- aura::client::SetWindowStackingClient(NULL);
- AuraTestBase::TearDown();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClientTest);
-};
-
-// Tests that transient children are stacked as a unit when using stack above.
-TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupAbove) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- Window* w11 = CreateTestWindowWithId(11, parent.get());
- scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
- Window* w21 = CreateTestWindowWithId(21, parent.get());
- Window* w211 = CreateTestWindowWithId(211, parent.get());
- Window* w212 = CreateTestWindowWithId(212, parent.get());
- Window* w213 = CreateTestWindowWithId(213, parent.get());
- Window* w22 = CreateTestWindowWithId(22, parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- w1->AddTransientChild(w11); // w11 is now owned by w1.
- w2->AddTransientChild(w21); // w21 is now owned by w2.
- w2->AddTransientChild(w22); // w22 is now owned by w2.
- w21->AddTransientChild(w211); // w211 is now owned by w21.
- w21->AddTransientChild(w212); // w212 is now owned by w21.
- w21->AddTransientChild(w213); // w213 is now owned by w21.
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtTop(w2.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w2.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w21, w1.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w21, w22);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w21);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w213, w21);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent above its transient child.
- parent->StackChildAbove(w21, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAbove(w2.get(), w1.get());
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w213);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
-// Tests that transient children are stacked as a unit when using stack below.
-TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- Window* w11 = CreateTestWindowWithId(11, parent.get());
- scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
- Window* w21 = CreateTestWindowWithId(21, parent.get());
- Window* w211 = CreateTestWindowWithId(211, parent.get());
- Window* w212 = CreateTestWindowWithId(212, parent.get());
- Window* w213 = CreateTestWindowWithId(213, parent.get());
- Window* w22 = CreateTestWindowWithId(22, parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- w1->AddTransientChild(w11); // w11 is now owned by w1.
- w2->AddTransientChild(w21); // w21 is now owned by w2.
- w2->AddTransientChild(w22); // w22 is now owned by w2.
- w21->AddTransientChild(w211); // w211 is now owned by w21.
- w21->AddTransientChild(w212); // w212 is now owned by w21.
- w21->AddTransientChild(w213); // w213 is now owned by w21.
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
- // This also tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtBottom(w2.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAtBottom(w1.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w21, w1.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w11, w2.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w22, w21);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w21, w11);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w213, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent below its transient child.
- parent->StackChildBelow(w21, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w1.get(), w2.get());
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w213, w11);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/visibility_controller.cc b/chromium/ui/views/corewm/visibility_controller.cc
deleted file mode 100644
index 4542f41c669..00000000000
--- a/chromium/ui/views/corewm/visibility_controller.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/visibility_controller.h"
-
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-#include "ui/compositor/layer.h"
-#include "ui/views/corewm/window_animations.h"
-
-namespace views {
-namespace corewm {
-
-namespace {
-
-// Property set on all windows whose child windows' visibility changes are
-// animated.
-DEFINE_WINDOW_PROPERTY_KEY(
- bool, kChildWindowVisibilityChangesAnimatedKey, false);
-
-bool ShouldAnimateWindow(aura::Window* window) {
- return window->parent() && window->parent()->GetProperty(
- kChildWindowVisibilityChangesAnimatedKey);
-}
-
-} // namespace
-
-VisibilityController::VisibilityController() {
-}
-
-VisibilityController::~VisibilityController() {
-}
-
-bool VisibilityController::CallAnimateOnChildWindowVisibilityChanged(
- aura::Window* window,
- bool visible) {
- return AnimateOnChildWindowVisibilityChanged(window, visible);
-}
-
-void VisibilityController::UpdateLayerVisibility(aura::Window* window,
- bool visible) {
- bool animated = window->type() != aura::client::WINDOW_TYPE_CONTROL &&
- window->type() != aura::client::WINDOW_TYPE_UNKNOWN &&
- ShouldAnimateWindow(window);
- animated = animated &&
- CallAnimateOnChildWindowVisibilityChanged(window, visible);
-
- if (!visible) {
- // For window hiding animation, we want to check if the window is already
- // animating, and not do SetVisible(false) if it is.
- // TODO(vollick): remove this.
- animated = animated || (window->layer()->GetAnimator()->
- IsAnimatingProperty(ui::LayerAnimationElement::OPACITY) &&
- window->layer()->GetTargetOpacity() == 0.0f);
- }
-
- // When a window is made visible, we always make its layer visible
- // immediately. When a window is hidden, the layer must be left visible and
- // only made not visible once the animation is complete.
- if (!animated || visible)
- window->layer()->SetVisible(visible);
-}
-
-SuspendChildWindowVisibilityAnimations::SuspendChildWindowVisibilityAnimations(
- aura::Window* window)
- : window_(window),
- original_enabled_(window->GetProperty(
- kChildWindowVisibilityChangesAnimatedKey)) {
- window_->ClearProperty(kChildWindowVisibilityChangesAnimatedKey);
-}
-
-SuspendChildWindowVisibilityAnimations::
- ~SuspendChildWindowVisibilityAnimations() {
- if (original_enabled_)
- window_->SetProperty(kChildWindowVisibilityChangesAnimatedKey, true);
- else
- window_->ClearProperty(kChildWindowVisibilityChangesAnimatedKey);
-}
-
-void SetChildWindowVisibilityChangesAnimated(aura::Window* window) {
- window->SetProperty(kChildWindowVisibilityChangesAnimatedKey, true);
-}
-
-} // namespace corewm
-} // namespace views
-
diff --git a/chromium/ui/views/corewm/visibility_controller.h b/chromium/ui/views/corewm/visibility_controller.h
deleted file mode 100644
index ec489822f66..00000000000
--- a/chromium/ui/views/corewm/visibility_controller.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_VISIBILITY_CONTROLLER_H_
-#define UI_VIEWS_COREWM_VISIBILITY_CONTROLLER_H_
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "ui/aura/client/visibility_client.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-namespace corewm {
-
-class VIEWS_EXPORT VisibilityController
- : public aura::client::VisibilityClient {
- public:
- VisibilityController();
- virtual ~VisibilityController();
-
- protected:
- // Subclasses override if they want to call a different implementation of
- // this function.
- // TODO(beng): potentially replace by an actual window animator class in
- // window_animations.h.
- virtual bool CallAnimateOnChildWindowVisibilityChanged(aura::Window* window,
- bool visible);
-
- private:
- // Overridden from aura::client::VisibilityClient:
- virtual void UpdateLayerVisibility(aura::Window* window,
- bool visible) OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(VisibilityController);
-};
-
-// Suspends the animations for visibility changes during the lifetime of an
-// instance of this class.
-//
-// Example:
-//
-// void ViewName::UnanimatedAction() {
-// SuspendChildWindowVisibilityAnimations suspend(parent);
-// // Perform unanimated action here.
-// // ...
-// // When the method finishes, visibility animations will return to their
-// // previous state.
-// }
-//
-class VIEWS_EXPORT SuspendChildWindowVisibilityAnimations {
- public:
- // Suspend visibility animations of child windows.
- explicit SuspendChildWindowVisibilityAnimations(aura::Window* window);
-
- // Restore visibility animations to their original state.
- ~SuspendChildWindowVisibilityAnimations();
-
- private:
- // The window to manage.
- aura::Window* window_;
-
- // Whether the visibility animations on child windows were originally enabled.
- const bool original_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(SuspendChildWindowVisibilityAnimations);
-};
-
-// Tells |window| to animate visibility changes to its children.
-void VIEWS_EXPORT SetChildWindowVisibilityChangesAnimated(aura::Window* window);
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_VISIBILITY_CONTROLLER_H_
diff --git a/chromium/ui/views/corewm/visibility_controller_unittest.cc b/chromium/ui/views/corewm/visibility_controller_unittest.cc
deleted file mode 100644
index 222d7af61e8..00000000000
--- a/chromium/ui/views/corewm/visibility_controller_unittest.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/visibility_controller.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_animation_duration_scale_mode.h"
-
-namespace views {
-namespace corewm {
-
-typedef aura::test::AuraTestBase VisibilityControllerTest;
-
-// Hiding a window in an animatable container should not hide the window's layer
-// immediately.
-TEST_F(VisibilityControllerTest, AnimateHideDoesntHideWindowLayer) {
- // We cannot disable animations for this test.
- ui::ScopedAnimationDurationScaleMode normal_duration_mode(
- ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
-
- VisibilityController controller;
- aura::client::SetVisibilityClient(root_window(), &controller);
-
- SetChildWindowVisibilityChangesAnimated(root_window());
-
- aura::test::TestWindowDelegate d;
- scoped_ptr<aura::Window> animatable(
- aura::test::CreateTestWindowWithDelegate(
- &d, -2, gfx::Rect(0, 0, 50, 50), root_window()));
- scoped_ptr<aura::Window> non_animatable(
- aura::test::CreateTestWindowWithDelegateAndType(
- &d, aura::client::WINDOW_TYPE_CONTROL, -3, gfx::Rect(51, 51, 50, 50),
- root_window()));
- EXPECT_TRUE(animatable->IsVisible());
- EXPECT_TRUE(animatable->layer()->visible());
- animatable->Hide();
- EXPECT_FALSE(animatable->IsVisible());
- EXPECT_TRUE(animatable->layer()->visible());
-
- EXPECT_TRUE(non_animatable->IsVisible());
- EXPECT_TRUE(non_animatable->layer()->visible());
- non_animatable->Hide();
- EXPECT_FALSE(non_animatable->IsVisible());
- EXPECT_FALSE(non_animatable->layer()->visible());
-
- aura::client::SetVisibilityClient(root_window(), NULL);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/window_animations.cc b/chromium/ui/views/corewm/window_animations.cc
deleted file mode 100644
index 736f4bba822..00000000000
--- a/chromium/ui/views/corewm/window_animations.cc
+++ /dev/null
@@ -1,573 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/window_animations.h"
-
-#include <math.h>
-
-#include <algorithm>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "base/time/time.h"
-#include "ui/aura/client/animation_host.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/aura/window_observer.h"
-#include "ui/aura/window_property.h"
-#include "ui/compositor/compositor_observer.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_observer.h"
-#include "ui/compositor/layer_animation_sequence.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/interpolated_transform.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector3d_f.h"
-#include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/window_util.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(int)
-DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::WindowVisibilityAnimationType)
-DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::WindowVisibilityAnimationTransition)
-DECLARE_WINDOW_PROPERTY_TYPE(float)
-DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(VIEWS_EXPORT, bool)
-
-using aura::Window;
-using base::TimeDelta;
-using ui::Layer;
-
-namespace views {
-namespace corewm {
-namespace {
-const float kWindowAnimation_Vertical_TranslateY = 15.f;
-} // namespace
-
-DEFINE_WINDOW_PROPERTY_KEY(int,
- kWindowVisibilityAnimationTypeKey,
- WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
-DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0);
-DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition,
- kWindowVisibilityAnimationTransitionKey,
- ANIMATE_BOTH);
-DEFINE_WINDOW_PROPERTY_KEY(float,
- kWindowVisibilityAnimationVerticalPositionKey,
- kWindowAnimation_Vertical_TranslateY);
-
-namespace {
-
-const int kDefaultAnimationDurationForMenuMS = 150;
-
-const float kWindowAnimation_HideOpacity = 0.f;
-const float kWindowAnimation_ShowOpacity = 1.f;
-const float kWindowAnimation_TranslateFactor = 0.5f;
-const float kWindowAnimation_ScaleFactor = .95f;
-
-const int kWindowAnimation_Rotate_DurationMS = 180;
-const int kWindowAnimation_Rotate_OpacityDurationPercent = 90;
-const float kWindowAnimation_Rotate_TranslateY = -20.f;
-const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f;
-const float kWindowAnimation_Rotate_DegreesX = 5.f;
-const float kWindowAnimation_Rotate_ScaleFactor = .99f;
-
-const float kWindowAnimation_Bounce_Scale = 1.02f;
-const int kWindowAnimation_Bounce_DurationMS = 180;
-const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40;
-
-base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) {
- int duration =
- window->GetProperty(kWindowVisibilityAnimationDurationKey);
- if (duration == 0 && window->type() == aura::client::WINDOW_TYPE_MENU) {
- return base::TimeDelta::FromMilliseconds(
- kDefaultAnimationDurationForMenuMS);
- }
- return TimeDelta::FromInternalValue(duration);
-}
-
-// Gets/sets the WindowVisibilityAnimationType associated with a window.
-// TODO(beng): redundant/fold into method on public api?
-int GetWindowVisibilityAnimationType(aura::Window* window) {
- int type = window->GetProperty(kWindowVisibilityAnimationTypeKey);
- if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) {
- return (window->type() == aura::client::WINDOW_TYPE_MENU ||
- window->type() == aura::client::WINDOW_TYPE_TOOLTIP) ?
- WINDOW_VISIBILITY_ANIMATION_TYPE_FADE :
- WINDOW_VISIBILITY_ANIMATION_TYPE_DROP;
- }
- return type;
-}
-
-// Observes a hide animation.
-// A window can be hidden for a variety of reasons. Sometimes, Hide() will be
-// called and life is simple. Sometimes, the window is actually bound to a
-// views::Widget and that Widget is closed, and life is a little more
-// complicated. When a Widget is closed the aura::Window* is actually not
-// destroyed immediately - it is actually just immediately hidden and then
-// destroyed when the stack unwinds. To handle this case, we start the hide
-// animation immediately when the window is hidden, then when the window is
-// subsequently destroyed this object acquires ownership of the window's layer,
-// so that it can continue animating it until the animation completes.
-// Regardless of whether or not the window is destroyed, this object deletes
-// itself when the animation completes.
-class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver,
- public aura::WindowObserver {
- public:
- explicit HidingWindowAnimationObserver(aura::Window* window)
- : window_(window) {
- window_->AddObserver(this);
- }
- virtual ~HidingWindowAnimationObserver() {
- STLDeleteElements(&layers_);
- }
-
- private:
- // Overridden from ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE {
- // Window may have been destroyed by this point.
- if (window_) {
- aura::client::AnimationHost* animation_host =
- aura::client::GetAnimationHost(window_);
- if (animation_host)
- animation_host->OnWindowHidingAnimationCompleted();
- window_->RemoveObserver(this);
- }
- delete this;
- }
-
- // Overridden from aura::WindowObserver:
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- DCHECK_EQ(window, window_);
- DCHECK(layers_.empty());
- AcquireAllLayers(window_);
-
- // If the Widget has views with layers, then it is necessary to take
- // ownership of those layers too.
- views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_);
- const views::Widget* const_widget = widget;
- if (widget && const_widget->GetRootView() && widget->GetContentsView())
- AcquireAllViewLayers(widget->GetContentsView());
- window_->RemoveObserver(this);
- window_ = NULL;
- }
-
- void AcquireAllLayers(aura::Window* window) {
- ui::Layer* layer = window->AcquireLayer();
- DCHECK(layer);
- layers_.push_back(layer);
- for (aura::Window::Windows::const_iterator it = window->children().begin();
- it != window->children().end();
- ++it)
- AcquireAllLayers(*it);
- }
-
- void AcquireAllViewLayers(views::View* view) {
- for (int i = 0; i < view->child_count(); ++i)
- AcquireAllViewLayers(view->child_at(i));
- if (view->layer()) {
- ui::Layer* layer = view->RecreateLayer();
- if (layer) {
- layer->SuppressPaint();
- layers_.push_back(layer);
- }
- }
- }
-
- aura::Window* window_;
- std::vector<ui::Layer*> layers_;
-
- DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver);
-};
-
-void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) {
- const Layer* root = layer;
- while (root->parent())
- root = root->parent();
- layer->GetTargetTransformRelativeTo(root, transform);
-}
-
-gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer,
- const gfx::Transform& transform) {
- gfx::Transform in_world = transform;
- GetTransformRelativeToRoot(layer, &in_world);
-
- gfx::RectF transformed = layer->bounds();
- in_world.TransformRect(&transformed);
-
- return gfx::ToEnclosingRect(transformed);
-}
-
-// Augment the host window so that the enclosing bounds of the full
-// animation will fit inside of it.
-void AugmentWindowSize(aura::Window* window,
- const gfx::Transform& end_transform) {
- aura::client::AnimationHost* animation_host =
- aura::client::GetAnimationHost(window);
- if (!animation_host)
- return;
-
- const gfx::Rect& world_at_start = window->bounds();
- gfx::Rect world_at_end =
- GetLayerWorldBoundsAfterTransform(window->layer(), end_transform);
- gfx::Rect union_in_window_space =
- gfx::UnionRects(world_at_start, world_at_end);
-
- // Calculate the top left and bottom right deltas to be added to the window
- // bounds.
- gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(),
- world_at_start.y() - union_in_window_space.y());
-
- gfx::Vector2d bottom_right_delta(
- union_in_window_space.x() + union_in_window_space.width() -
- (world_at_start.x() + world_at_start.width()),
- union_in_window_space.y() + union_in_window_space.height() -
- (world_at_start.y() + world_at_start.height()));
-
- DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 &&
- bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0);
-
- animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta);
-}
-
-// Shows a window using an animation, animating its opacity from 0.f to 1.f,
-// its visibility to true, and its transform from |start_transform| to
-// |end_transform|.
-void AnimateShowWindowCommon(aura::Window* window,
- const gfx::Transform& start_transform,
- const gfx::Transform& end_transform) {
- window->layer()->set_delegate(window);
-
- AugmentWindowSize(window, end_transform);
-
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- window->layer()->SetTransform(start_transform);
- window->layer()->SetVisible(true);
-
- {
- // Property sets within this scope will be implicitly animated.
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window);
- if (duration.ToInternalValue() > 0)
- settings.SetTransitionDuration(duration);
-
- window->layer()->SetTransform(end_transform);
- window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
- }
-}
-
-// Hides a window using an animation, animating its opacity from 1.f to 0.f,
-// its visibility to false, and its transform to |end_transform|.
-void AnimateHideWindowCommon(aura::Window* window,
- const gfx::Transform& end_transform) {
- AugmentWindowSize(window, end_transform);
- window->layer()->set_delegate(NULL);
-
- // Property sets within this scope will be implicitly animated.
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- settings.AddObserver(new HidingWindowAnimationObserver(window));
-
- base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window);
- if (duration.ToInternalValue() > 0)
- settings.SetTransitionDuration(duration);
-
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- window->layer()->SetTransform(end_transform);
- window->layer()->SetVisible(false);
-}
-
-static gfx::Transform GetScaleForWindow(aura::Window* window) {
- gfx::Rect bounds = window->bounds();
- gfx::Transform scale = gfx::GetScaleTransform(
- gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(),
- kWindowAnimation_TranslateFactor * bounds.height()),
- kWindowAnimation_ScaleFactor);
- return scale;
-}
-
-// Show/Hide windows using a shrink animation.
-void AnimateShowWindow_Drop(aura::Window* window) {
- AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform());
-}
-
-void AnimateHideWindow_Drop(aura::Window* window) {
- AnimateHideWindowCommon(window, GetScaleForWindow(window));
-}
-
-// Show/Hide windows using a vertical Glenimation.
-void AnimateShowWindow_Vertical(aura::Window* window) {
- gfx::Transform transform;
- transform.Translate(0, window->GetProperty(
- kWindowVisibilityAnimationVerticalPositionKey));
- AnimateShowWindowCommon(window, transform, gfx::Transform());
-}
-
-void AnimateHideWindow_Vertical(aura::Window* window) {
- gfx::Transform transform;
- transform.Translate(0, window->GetProperty(
- kWindowVisibilityAnimationVerticalPositionKey));
- AnimateHideWindowCommon(window, transform);
-}
-
-// Show/Hide windows using a fade.
-void AnimateShowWindow_Fade(aura::Window* window) {
- AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform());
-}
-
-void AnimateHideWindow_Fade(aura::Window* window) {
- AnimateHideWindowCommon(window, gfx::Transform());
-}
-
-ui::LayerAnimationElement* CreateGrowShrinkElement(
- aura::Window* window, bool grow) {
- scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale(
- gfx::Point3F(kWindowAnimation_Bounce_Scale,
- kWindowAnimation_Bounce_Scale,
- 1),
- gfx::Point3F(1, 1, 1)));
- scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
- new ui::InterpolatedTransformAboutPivot(
- gfx::Point(window->bounds().width() * 0.5,
- window->bounds().height() * 0.5),
- scale.release()));
- scale_about_pivot->SetReversed(grow);
- scoped_ptr<ui::LayerAnimationElement> transition(
- ui::LayerAnimationElement::CreateInterpolatedTransformElement(
- scale_about_pivot.release(),
- base::TimeDelta::FromMilliseconds(
- kWindowAnimation_Bounce_DurationMS *
- kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100)));
- transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
- return transition.release();
-}
-
-void AnimateBounce(aura::Window* window) {
- ui::ScopedLayerAnimationSettings scoped_settings(
- window->layer()->GetAnimator());
- scoped_settings.SetPreemptionStrategy(
- ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
- window->layer()->set_delegate(window);
- scoped_ptr<ui::LayerAnimationSequence> sequence(
- new ui::LayerAnimationSequence);
- sequence->AddElement(CreateGrowShrinkElement(window, true));
- ui::LayerAnimationElement::AnimatableProperties paused_properties;
- paused_properties.insert(ui::LayerAnimationElement::BOUNDS);
- sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
- paused_properties,
- base::TimeDelta::FromMilliseconds(
- kWindowAnimation_Bounce_DurationMS *
- (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) /
- 100)));
- sequence->AddElement(CreateGrowShrinkElement(window, false));
- window->layer()->GetAnimator()->StartAnimation(sequence.release());
-}
-
-void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
- window->layer()->set_delegate(window);
- if (show)
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
-
- base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
- kWindowAnimation_Rotate_DurationMS);
-
- if (!show) {
- new HidingWindowAnimationObserver(window);
- window->layer()->GetAnimator()->SchedulePauseForProperties(
- duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100,
- ui::LayerAnimationElement::OPACITY,
- -1);
- }
- scoped_ptr<ui::LayerAnimationElement> opacity(
- ui::LayerAnimationElement::CreateOpacityElement(
- show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity,
- duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100));
- opacity->set_tween_type(gfx::Tween::EASE_IN_OUT);
- window->layer()->GetAnimator()->ScheduleAnimation(
- new ui::LayerAnimationSequence(opacity.release()));
-
- float xcenter = window->bounds().width() * 0.5;
-
- gfx::Transform transform;
- transform.Translate(xcenter, 0);
- transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth);
- transform.Translate(-xcenter, 0);
- scoped_ptr<ui::InterpolatedTransform> perspective(
- new ui::InterpolatedConstantTransform(transform));
-
- scoped_ptr<ui::InterpolatedTransform> scale(
- new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor));
- scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
- new ui::InterpolatedTransformAboutPivot(
- gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY),
- scale.release()));
-
- scoped_ptr<ui::InterpolatedTransform> translation(
- new ui::InterpolatedTranslation(gfx::Point(), gfx::Point(
- 0, kWindowAnimation_Rotate_TranslateY)));
-
- scoped_ptr<ui::InterpolatedTransform> rotation(
- new ui::InterpolatedAxisAngleRotation(
- gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX));
-
- scale_about_pivot->SetChild(perspective.release());
- translation->SetChild(scale_about_pivot.release());
- rotation->SetChild(translation.release());
- rotation->SetReversed(show);
-
- scoped_ptr<ui::LayerAnimationElement> transition(
- ui::LayerAnimationElement::CreateInterpolatedTransformElement(
- rotation.release(), duration));
-
- window->layer()->GetAnimator()->ScheduleAnimation(
- new ui::LayerAnimationSequence(transition.release()));
-}
-
-void AnimateShowWindow_Rotate(aura::Window* window) {
- AddLayerAnimationsForRotate(window, true);
-}
-
-void AnimateHideWindow_Rotate(aura::Window* window) {
- AddLayerAnimationsForRotate(window, false);
-}
-
-bool AnimateShowWindow(aura::Window* window) {
- if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
- if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
- // Since hide animation may have changed opacity and transform,
- // reset them to show the window.
- window->layer()->set_delegate(window);
- window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
- window->layer()->SetTransform(gfx::Transform());
- }
- return false;
- }
-
- switch (GetWindowVisibilityAnimationType(window)) {
- case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
- AnimateShowWindow_Drop(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
- AnimateShowWindow_Vertical(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
- AnimateShowWindow_Fade(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
- AnimateShowWindow_Rotate(window);
- return true;
- default:
- return false;
- }
-}
-
-bool AnimateHideWindow(aura::Window* window) {
- if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
- if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
- // Since show animation may have changed opacity and transform,
- // reset them, though the change should be hidden.
- window->layer()->set_delegate(NULL);
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- window->layer()->SetTransform(gfx::Transform());
- }
- return false;
- }
-
- switch (GetWindowVisibilityAnimationType(window)) {
- case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
- AnimateHideWindow_Drop(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
- AnimateHideWindow_Vertical(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
- AnimateHideWindow_Fade(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
- AnimateHideWindow_Rotate(window);
- return true;
- default:
- return false;
- }
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// External interface
-
-void SetWindowVisibilityAnimationType(aura::Window* window, int type) {
- window->SetProperty(kWindowVisibilityAnimationTypeKey, type);
-}
-
-int GetWindowVisibilityAnimationType(aura::Window* window) {
- return window->GetProperty(kWindowVisibilityAnimationTypeKey);
-}
-
-void SetWindowVisibilityAnimationTransition(
- aura::Window* window,
- WindowVisibilityAnimationTransition transition) {
- window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition);
-}
-
-bool HasWindowVisibilityAnimationTransition(
- aura::Window* window,
- WindowVisibilityAnimationTransition transition) {
- WindowVisibilityAnimationTransition prop = window->GetProperty(
- kWindowVisibilityAnimationTransitionKey);
- return (prop & transition) != 0;
-}
-
-void SetWindowVisibilityAnimationDuration(aura::Window* window,
- const TimeDelta& duration) {
- window->SetProperty(kWindowVisibilityAnimationDurationKey,
- static_cast<int>(duration.ToInternalValue()));
-}
-
-void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window,
- float position) {
- window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position);
-}
-
-ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver(
- aura::Window* window) {
- return new HidingWindowAnimationObserver(window);
-}
-
-bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
- if (WindowAnimationsDisabled(window))
- return false;
- if (visible)
- return AnimateShowWindow(window);
- // Don't start hiding the window again if it's already being hidden.
- return window->layer()->GetTargetOpacity() != 0.0f &&
- AnimateHideWindow(window);
-}
-
-bool AnimateWindow(aura::Window* window, WindowAnimationType type) {
- switch (type) {
- case WINDOW_ANIMATION_TYPE_BOUNCE:
- AnimateBounce(window);
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool WindowAnimationsDisabled(aura::Window* window) {
- return (window &&
- window->GetProperty(aura::client::kAnimationsDisabledKey)) ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kWindowAnimationsDisabled);
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/window_animations.h b/chromium/ui/views/corewm/window_animations.h
deleted file mode 100644
index 996c215dc89..00000000000
--- a/chromium/ui/views/corewm/window_animations.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_WINDOW_ANIMATIONS_H_
-#define UI_VIEWS_COREWM_WINDOW_ANIMATIONS_H_
-
-#include <vector>
-
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-}
-namespace base {
-class TimeDelta;
-}
-namespace gfx {
-class Rect;
-}
-namespace ui {
-class ImplicitAnimationObserver;
-class Layer;
-class LayerAnimationSequence;
-}
-
-namespace views {
-namespace corewm {
-
-// A variety of canned animations for window transitions.
-enum WindowVisibilityAnimationType {
- WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT = 0, // Default. Lets the system
- // decide based on window
- // type.
- WINDOW_VISIBILITY_ANIMATION_TYPE_DROP, // Window shrinks in.
- WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL, // Vertical Glenimation.
- WINDOW_VISIBILITY_ANIMATION_TYPE_FADE, // Fades in/out.
- WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE, // Window rotates in.
-
- // Downstream library animations start above this point.
- WINDOW_VISIBILITY_ANIMATION_MAX
-};
-
-// Canned animations that take effect once but don't have a symmetric pair as
-// visibility animations do.
-enum WindowAnimationType {
- WINDOW_ANIMATION_TYPE_BOUNCE = 0, // Window scales up and down.
-};
-
-// Type of visibility change transition that a window should animate.
-// Default behavior is to animate both show and hide.
-enum WindowVisibilityAnimationTransition {
- ANIMATE_SHOW = 0x1,
- ANIMATE_HIDE = 0x2,
- ANIMATE_BOTH = ANIMATE_SHOW | ANIMATE_HIDE,
- ANIMATE_NONE = 0x4,
-};
-
-// These two methods use int for type rather than WindowVisibilityAnimationType
-// since downstream libraries can extend the set of animations.
-VIEWS_EXPORT void SetWindowVisibilityAnimationType(aura::Window* window,
- int type);
-VIEWS_EXPORT int GetWindowVisibilityAnimationType(aura::Window* window);
-
-VIEWS_EXPORT void SetWindowVisibilityAnimationTransition(
- aura::Window* window,
- WindowVisibilityAnimationTransition transition);
-
-VIEWS_EXPORT bool HasWindowVisibilityAnimationTransition(
- aura::Window* window,
- WindowVisibilityAnimationTransition transition);
-
-VIEWS_EXPORT void SetWindowVisibilityAnimationDuration(
- aura::Window* window,
- const base::TimeDelta& duration);
-
-VIEWS_EXPORT void SetWindowVisibilityAnimationVerticalPosition(
- aura::Window* window,
- float position);
-
-// Creates an ImplicitAnimationObserver that takes ownership of the layers
-// associated with a Window so that the animation can continue after the Window
-// has been destroyed.
-// The returned object deletes itself when the animations are done.
-VIEWS_EXPORT ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver(
- aura::Window* window);
-
-// Returns false if the |window| didn't animate.
-VIEWS_EXPORT bool AnimateOnChildWindowVisibilityChanged(aura::Window* window,
- bool visible);
-VIEWS_EXPORT bool AnimateWindow(aura::Window* window, WindowAnimationType type);
-
-// Returns true if window animations are disabled for |window|. Window
-// animations are enabled by default. If |window| is NULL, this just checks
-// if the global flag disabling window animations is present.
-VIEWS_EXPORT bool WindowAnimationsDisabled(aura::Window* window);
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_WINDOW_ANIMATIONS_H_
diff --git a/chromium/ui/views/corewm/window_animations_unittest.cc b/chromium/ui/views/corewm/window_animations_unittest.cc
deleted file mode 100644
index 89d48c6ce8d..00000000000
--- a/chromium/ui/views/corewm/window_animations_unittest.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/window_animations.h"
-
-#include "base/time/time.h"
-#include "ui/aura/client/animation_host.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/compositor/scoped_animation_duration_scale_mode.h"
-#include "ui/gfx/animation/animation_container_element.h"
-#include "ui/gfx/vector2d.h"
-
-using aura::Window;
-using ui::Layer;
-
-namespace views {
-namespace corewm {
-
-class WindowAnimationsTest : public aura::test::AuraTestBase {
- public:
- WindowAnimationsTest() {}
-
- virtual void TearDown() OVERRIDE {
- AuraTestBase::TearDown();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
-};
-
-TEST_F(WindowAnimationsTest, LayerTargetVisibility) {
- scoped_ptr<aura::Window> window(
- aura::test::CreateTestWindowWithId(0, NULL));
-
- // Layer target visibility changes according to Show/Hide.
- window->Show();
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
- window->Hide();
- EXPECT_FALSE(window->layer()->GetTargetVisibility());
- window->Show();
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
-}
-
-TEST_F(WindowAnimationsTest, LayerTargetVisibility_AnimateShow) {
- // Tests if opacity and transform are reset when only show animation is
- // enabled. See also LayerTargetVisibility_AnimateHide.
- // Since the window is not visible after Hide() is called, opacity and
- // transform shouldn't matter in case of ANIMATE_SHOW, but we reset them
- // to keep consistency.
-
- scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
- SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_SHOW);
-
- // Layer target visibility and opacity change according to Show/Hide.
- window->Show();
- AnimateOnChildWindowVisibilityChanged(window.get(), true);
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(1, window->layer()->opacity());
-
- window->Hide();
- AnimateOnChildWindowVisibilityChanged(window.get(), false);
- EXPECT_FALSE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(0, window->layer()->opacity());
- EXPECT_EQ(gfx::Transform(), window->layer()->transform());
-
- window->Show();
- AnimateOnChildWindowVisibilityChanged(window.get(), true);
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(1, window->layer()->opacity());
-}
-
-TEST_F(WindowAnimationsTest, LayerTargetVisibility_AnimateHide) {
- // Tests if opacity and transform are reset when only hide animation is
- // enabled. Hide animation changes opacity and transform in addition to
- // visibility, so we need to reset not only visibility but also opacity
- // and transform to show the window.
-
- scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
- SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_HIDE);
-
- // Layer target visibility and opacity change according to Show/Hide.
- window->Show();
- AnimateOnChildWindowVisibilityChanged(window.get(), true);
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(1, window->layer()->opacity());
- EXPECT_EQ(gfx::Transform(), window->layer()->transform());
-
- window->Hide();
- AnimateOnChildWindowVisibilityChanged(window.get(), false);
- EXPECT_FALSE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(0, window->layer()->opacity());
-
- window->Show();
- AnimateOnChildWindowVisibilityChanged(window.get(), true);
- EXPECT_TRUE(window->layer()->GetTargetVisibility());
- EXPECT_EQ(1, window->layer()->opacity());
- EXPECT_EQ(gfx::Transform(), window->layer()->transform());
-}
-
-// A simple AnimationHost implementation for the NotifyHideCompleted test.
-class NotifyHideCompletedAnimationHost : public aura::client::AnimationHost {
- public:
- NotifyHideCompletedAnimationHost() : hide_completed_(false) {}
- virtual ~NotifyHideCompletedAnimationHost() {}
-
- // Overridden from TestWindowDelegate:
- virtual void OnWindowHidingAnimationCompleted() OVERRIDE {
- hide_completed_ = true;
- }
-
- virtual void SetHostTransitionOffsets(
- const gfx::Vector2d& top_left,
- const gfx::Vector2d& bottom_right) OVERRIDE {}
-
- bool hide_completed() const { return hide_completed_; }
-
- private:
- bool hide_completed_;
-
- DISALLOW_COPY_AND_ASSIGN(NotifyHideCompletedAnimationHost);
-};
-
-TEST_F(WindowAnimationsTest, NotifyHideCompleted) {
- NotifyHideCompletedAnimationHost animation_host;
- scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
- aura::client::SetAnimationHost(window.get(), &animation_host);
- views::corewm::SetWindowVisibilityAnimationType(
- window.get(), WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
- AnimateOnChildWindowVisibilityChanged(window.get(), true);
- EXPECT_TRUE(window->layer()->visible());
-
- EXPECT_FALSE(animation_host.hide_completed());
- AnimateOnChildWindowVisibilityChanged(window.get(), false);
- EXPECT_TRUE(animation_host.hide_completed());
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/window_modality_controller.cc b/chromium/ui/views/corewm/window_modality_controller.cc
deleted file mode 100644
index b52a9d6ad8c..00000000000
--- a/chromium/ui/views/corewm/window_modality_controller.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/window_modality_controller.h"
-
-#include <algorithm>
-
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/ui_base_types.h"
-#include "ui/events/event.h"
-#include "ui/events/event_target.h"
-#include "ui/events/gestures/gesture_recognizer.h"
-#include "ui/views/corewm/window_animations.h"
-#include "ui/views/corewm/window_util.h"
-
-namespace views {
-namespace corewm {
-
-// Transient child's modal parent.
-extern const aura::WindowProperty<aura::Window*>* const kModalParentKey;
-DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kModalParentKey, NULL);
-
-namespace {
-
-bool HasAncestor(aura::Window* window, aura::Window* ancestor) {
- if (!window)
- return false;
- if (window == ancestor)
- return true;
- return HasAncestor(window->parent(), ancestor);
-}
-
-bool TransientChildIsWindowModal(aura::Window* window) {
- return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW;
-}
-
-bool TransientChildIsSystemModal(aura::Window* window) {
- return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
-}
-
-bool TransientChildIsChildModal(aura::Window* window) {
- return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_CHILD;
-}
-
-aura::Window* GetModalParent(aura::Window* window) {
- return window->GetProperty(kModalParentKey);
-}
-
-bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
- return transient->IsVisible() &&
- (TransientChildIsWindowModal(transient) ||
- TransientChildIsSystemModal(transient) ||
- (TransientChildIsChildModal(transient) &&
- (HasAncestor(original, GetModalParent(transient)))));
-}
-
-aura::Window* GetModalTransientChild(
- aura::Window* activatable,
- aura::Window* original) {
- aura::Window::Windows::const_iterator it;
- for (it = activatable->transient_children().begin();
- it != activatable->transient_children().end();
- ++it) {
- aura::Window* transient = *it;
- if (IsModalTransientChild(transient, original)) {
- return transient->transient_children().empty() ?
- transient : GetModalTransientChild(transient, original);
- }
- }
- return NULL;
-}
-
-} // namespace
-
-void SetModalParent(aura::Window* child, aura::Window* parent) {
- child->SetProperty(kModalParentKey, parent);
-}
-
-aura::Window* GetModalTransient(aura::Window* window) {
- if (!window)
- return NULL;
-
- // We always want to check the for the transient child of the toplevel window.
- aura::Window* toplevel = GetToplevelWindow(window);
- if (!toplevel)
- return NULL;
-
- return GetModalTransientChild(toplevel, window);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowModalityController, public:
-
-WindowModalityController::WindowModalityController(
- ui::EventTarget* event_target)
- : event_target_(event_target) {
- aura::Env::GetInstance()->AddObserver(this);
- DCHECK(event_target->IsPreTargetListEmpty());
- event_target_->AddPreTargetHandler(this);
-}
-
-WindowModalityController::~WindowModalityController() {
- event_target_->RemovePreTargetHandler(this);
- aura::Env::GetInstance()->RemoveObserver(this);
- for (size_t i = 0; i < windows_.size(); ++i)
- windows_[i]->RemoveObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowModalityController, aura::EventFilter implementation:
-
-void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
- aura::Window* target = static_cast<aura::Window*>(event->target());
- if (GetModalTransient(target))
- event->SetHandled();
-}
-
-void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
- aura::Window* target = static_cast<aura::Window*>(event->target());
- if (ProcessLocatedEvent(target, event))
- event->SetHandled();
-}
-
-void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
- aura::Window* target = static_cast<aura::Window*>(event->target());
- if (ProcessLocatedEvent(target, event))
- event->SetHandled();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowModalityController, aura::EnvObserver implementation:
-
-void WindowModalityController::OnWindowInitialized(aura::Window* window) {
- windows_.push_back(window);
- window->AddObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowModalityController, aura::WindowObserver implementation:
-
-void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
- const void* key,
- intptr_t old) {
- // In tests, we sometimes create the modality relationship after a window is
- // visible.
- if (key == aura::client::kModalKey &&
- window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
- window->IsVisible()) {
- ActivateWindow(window);
- ui::GestureRecognizer::Get()->TransferEventsTo(
- window->transient_parent(), NULL);
- }
-}
-
-void WindowModalityController::OnWindowVisibilityChanged(
- aura::Window* window,
- bool visible) {
- if (visible && window->GetProperty(aura::client::kModalKey) !=
- ui::MODAL_TYPE_NONE) {
- ui::GestureRecognizer::Get()->TransferEventsTo(
- window->transient_parent(), NULL);
- // Make sure no other window has capture, otherwise |window| won't get mouse
- // events.
- aura::Window* capture_window = aura::client::GetCaptureWindow(window);
- if (capture_window)
- capture_window->ReleaseCapture();
- }
-}
-
-void WindowModalityController::OnWindowDestroyed(aura::Window* window) {
- windows_.erase(std::find(windows_.begin(), windows_.end(), window));
- window->RemoveObserver(this);
-}
-
-bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
- ui::LocatedEvent* event) {
- if (event->handled())
- return false;
- aura::Window* modal_transient_child = GetModalTransient(target);
- if (modal_transient_child && (event->type() == ui::ET_MOUSE_PRESSED ||
- event->type() == ui::ET_TOUCH_PRESSED)) {
- AnimateWindow(modal_transient_child, WINDOW_ANIMATION_TYPE_BOUNCE);
- }
- if (event->type() == ui::ET_TOUCH_CANCELLED)
- return false;
- return !!modal_transient_child;
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/window_modality_controller.h b/chromium/ui/views/corewm/window_modality_controller.h
deleted file mode 100644
index 88150a54253..00000000000
--- a/chromium/ui/views/corewm/window_modality_controller.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_WINDOW_MODALITY_CONTROLLER_H_
-#define UI_VIEWS_COREWM_WINDOW_MODALITY_CONTROLLER_H_
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "ui/aura/env_observer.h"
-#include "ui/aura/window_observer.h"
-#include "ui/events/event_handler.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class EventTarget;
-class LocatedEvent;
-}
-
-namespace views {
-namespace corewm {
-
-// Sets the modal parent for the child.
-VIEWS_EXPORT void SetModalParent(aura::Window* child, aura::Window* parent);
-
-// Returns the modal transient child of |window|, or NULL if |window| does not
-// have any modal transient children.
-VIEWS_EXPORT aura::Window* GetModalTransient(aura::Window* window);
-
-// WindowModalityController is an event filter that consumes events sent to
-// windows that are the transient parents of window-modal windows. This filter
-// must be added to the CompoundEventFilter so that activation works properly.
-class VIEWS_EXPORT WindowModalityController : public ui::EventHandler,
- public aura::EnvObserver,
- public aura::WindowObserver {
- public:
- explicit WindowModalityController(ui::EventTarget* event_target);
- virtual ~WindowModalityController();
-
- // Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
-
- // Overridden from aura::EnvObserver:
- virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
-
- // Overridden from aura::WindowObserver:
- virtual void OnWindowPropertyChanged(aura::Window* window,
- const void* key,
- intptr_t old) OVERRIDE;
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
-
- private:
- // Processes a mouse/touch event, and returns true if the event should be
- // consumed.
- bool ProcessLocatedEvent(aura::Window* target,
- ui::LocatedEvent* event);
-
- std::vector<aura::Window*> windows_;
-
- ui::EventTarget* event_target_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowModalityController);
-};
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_WINDOW_MODALITY_CONTROLLER_H_
diff --git a/chromium/ui/views/corewm/window_util.cc b/chromium/ui/views/corewm/window_util.cc
deleted file mode 100644
index eaee174d738..00000000000
--- a/chromium/ui/views/corewm/window_util.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/window_util.h"
-
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-
-namespace {
-
-// Helper method for RecreateWindowLayers() which adds all the existing layers
-// for |view| and its descendants to |parent_layer|. New layers are created for
-// |view| (if it previously had a layer) and any descendants which previously
-// had layers. The new layers are blank, so nothing has been painted to them
-// yet. Returns true if this method added at least one layer to |parent_layer|.
-bool RecreateViewLayers(ui::Layer* parent_layer, views::View* view) {
- bool recreated_layer = false;
- if (view->layer()) {
- ui::Layer* layer = view->RecreateLayer();
- if (layer) {
- layer->SuppressPaint();
- parent_layer->Add(layer);
- parent_layer = layer;
- recreated_layer = true;
- }
- }
- for (int i = 0; i < view->child_count(); ++i)
- recreated_layer |= RecreateViewLayers(parent_layer, view->child_at(i));
-
- return recreated_layer;
-}
-
-} // namespace
-
-namespace views {
-namespace corewm {
-
-void ActivateWindow(aura::Window* window) {
- DCHECK(window);
- DCHECK(window->GetRootWindow());
- aura::client::GetActivationClient(window->GetRootWindow())->ActivateWindow(
- window);
-}
-
-void DeactivateWindow(aura::Window* window) {
- DCHECK(window);
- DCHECK(window->GetRootWindow());
- aura::client::GetActivationClient(window->GetRootWindow())->DeactivateWindow(
- window);
-}
-
-bool IsActiveWindow(aura::Window* window) {
- DCHECK(window);
- if (!window->GetRootWindow())
- return false;
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(window->GetRootWindow());
- return client && client->GetActiveWindow() == window;
-}
-
-bool CanActivateWindow(aura::Window* window) {
- DCHECK(window);
- if (!window->GetRootWindow())
- return false;
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(window->GetRootWindow());
- return client && client->CanActivateWindow(window);
-}
-
-aura::Window* GetActivatableWindow(aura::Window* window) {
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(window->GetRootWindow());
- return client ? client->GetActivatableWindow(window) : NULL;
-}
-
-aura::Window* GetToplevelWindow(aura::Window* window) {
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(window->GetRootWindow());
- return client ? client->GetToplevelWindow(window) : NULL;
-}
-
-void DeepDeleteLayers(ui::Layer* layer) {
- std::vector<ui::Layer*> children = layer->children();
- for (std::vector<ui::Layer*>::const_iterator it = children.begin();
- it != children.end();
- ++it) {
- ui::Layer* child = *it;
- DeepDeleteLayers(child);
- }
- delete layer;
-}
-
-ui::Layer* RecreateWindowLayers(aura::Window* window, bool set_bounds) {
- const gfx::Rect bounds = window->bounds();
- ui::Layer* old_layer = window->RecreateLayer();
- DCHECK(old_layer);
-
- // Cache the order of |window|'s child layers. If |window| belongs to a widget
- // and the widget has both child windows and child views with layers,
- // |initial_layer_order| is used to determine the relative order.
- std::vector<ui::Layer*> initial_layer_order = window->layer()->children();
-
- // Recreate the layers for any child windows of |window|.
- for (aura::Window::Windows::const_iterator it = window->children().begin();
- it != window->children().end();
- ++it) {
- old_layer->Add(RecreateWindowLayers(*it, set_bounds));
- }
-
- // Recreate the layers for any child views of |widget|.
- bool has_view_layers = false;
- views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
- if (widget && widget->GetRootView())
- has_view_layers = RecreateViewLayers(old_layer, widget->GetRootView());
-
- if (has_view_layers && !window->children().empty()) {
- // RecreateViewLayers() added the view layers above the window layers in
- // z-order. The window layers and the view layers may have been originally
- // intermingled. Reorder |old_layer|'s children based on the initial
- // order.
- for (size_t i = 0; i < initial_layer_order.size(); ++i) {
- ui::Layer* layer = initial_layer_order[i];
- std::vector<ui::Layer*>::const_iterator it = std::find(
- old_layer->children().begin(), old_layer->children().end(), layer);
- if (it != old_layer->children().end())
- old_layer->StackAtTop(layer);
- }
- }
-
- if (set_bounds)
- window->SetBounds(bounds);
- return old_layer;
-}
-
-} // namespace corewm
-} // namespace views
diff --git a/chromium/ui/views/corewm/window_util.h b/chromium/ui/views/corewm/window_util.h
deleted file mode 100644
index 01a3ea43f06..00000000000
--- a/chromium/ui/views/corewm/window_util.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COREWM_WINDOW_UTIL_H_
-#define UI_VIEWS_COREWM_WINDOW_UTIL_H_
-
-#include "base/compiler_specific.h"
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ui {
-class Layer;
-}
-
-namespace views {
-namespace corewm {
-
-VIEWS_EXPORT void ActivateWindow(aura::Window* window);
-VIEWS_EXPORT void DeactivateWindow(aura::Window* window);
-VIEWS_EXPORT bool IsActiveWindow(aura::Window* window);
-VIEWS_EXPORT bool CanActivateWindow(aura::Window* window);
-
-// Retrieves the activatable window for |window|. The ActivationClient makes
-// this determination.
-VIEWS_EXPORT aura::Window* GetActivatableWindow(aura::Window* window);
-
-// Retrieves the toplevel window for |window|. The ActivationClient makes this
-// determination.
-VIEWS_EXPORT aura::Window* GetToplevelWindow(aura::Window* window);
-
-// Deletes |layer| and all its child layers.
-VIEWS_EXPORT void DeepDeleteLayers(ui::Layer* layer);
-
-// Returns the existing Layer for |window| (and all its descendants) and creates
-// a new layer for |window| and all its descendants. This is intended for
-// animations that want to animate between the existing visuals and a new window
-// state. The caller owns the return value.
-//
-// As a result of this |window| has freshly created layers, meaning the layers
-// are all empty (nothing has been painted to them) and are sized to 0x0. Soon
-// after this call you need to reset the bounds of the window. Or, you can pass
-// true as the second argument to let the function do that.
-VIEWS_EXPORT ui::Layer* RecreateWindowLayers(aura::Window* window,
- bool set_bounds) WARN_UNUSED_RESULT;
-
-} // namespace corewm
-} // namespace views
-
-#endif // UI_VIEWS_COREWM_WINDOW_UTIL_H_
diff --git a/chromium/ui/views/corewm/window_util_unittest.cc b/chromium/ui/views/corewm/window_util_unittest.cc
deleted file mode 100644
index fdf3a46fa2f..00000000000
--- a/chromium/ui/views/corewm/window_util_unittest.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/corewm/window_util.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/test/test_layers.h"
-#include "ui/views/view_constants_aura.h"
-#include "ui/views/widget/widget.h"
-
-class WindowUtilTest : public aura::test::AuraTestBase {
- public:
- WindowUtilTest() {
- }
-
- virtual ~WindowUtilTest() {
- }
-
- // Creates a widget of TYPE_CONTROL.
- // The caller takes ownership of the returned widget.
- views::Widget* CreateControlWidget(
- aura::Window* parent,
- const gfx::Rect& bounds) const WARN_UNUSED_RESULT {
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
- params.parent = parent;
- params.bounds = bounds;
- views::Widget* widget = new views::Widget();
- widget->Init(params);
- return widget;
- }
-
- // Returns a view with a layer with the passed in |bounds| and |layer_name|.
- // The caller takes ownership of the returned view.
- views::View* CreateViewWithLayer(
- const gfx::Rect& bounds,
- const char* layer_name) const WARN_UNUSED_RESULT {
- views::View* view = new views::View();
- view->SetBoundsRect(bounds);
- view->SetPaintToLayer(true);
- view->layer()->set_name(layer_name);
- return view;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WindowUtilTest);
-};
-
-// Test that RecreateWindowLayers() recreates the layers for all child windows
-// and all child views and that the z-order of the recreated layers matches that
-// of the original layers.
-// Test hierarchy:
-// w1
-// +-- v1
-// +-- v2 (no layer)
-// +-- v3 (no layer)
-// +-- v4
-// +-- w2
-// +-- v5
-// +-- v6
-// +-- v7
-TEST_F(WindowUtilTest, RecreateWindowLayers) {
- views::Widget* w1 = CreateControlWidget(root_window(),
- gfx::Rect(0, 0, 100, 100));
- w1->GetNativeView()->layer()->set_name("w1");
-
- views::View* v2 = new views::View();
- v2->SetBounds(0, 1, 100, 101);
- views::View* v3 = new views::View();
- v3->SetBounds(0, 2, 100, 102);
- views::View* w2_host_view = new views::View();
-
- w1->GetRootView()->AddChildView(CreateViewWithLayer(
- gfx::Rect(0, 3, 100, 103), "v1"));
- w1->GetRootView()->AddChildView(v2);
- v2->AddChildView(v3);
- v2->AddChildView(CreateViewWithLayer(gfx::Rect(0, 4, 100, 104), "v4"));
-
- w1->GetRootView()->AddChildView(w2_host_view);
- w1->GetRootView()->AddChildView(CreateViewWithLayer(
- gfx::Rect(0, 4, 100, 104), "v7"));
-
- views::Widget* w2 = CreateControlWidget(w1->GetNativeView(),
- gfx::Rect(0, 5, 100, 105));
- w2->GetNativeView()->layer()->set_name("w2");
- w2->GetNativeView()->SetProperty(views::kHostViewKey, w2_host_view);
-
- views::View* v5 = CreateViewWithLayer(gfx::Rect(0, 6, 100, 106), "v5");
- w2->GetRootView()->AddChildView(v5);
- v5->AddChildView(CreateViewWithLayer(gfx::Rect(0, 7, 100, 107), "v6"));
-
- // Test the initial order of the layers.
- ui::Layer* w1_layer = w1->GetNativeView()->layer();
- ASSERT_EQ("w1", w1_layer->name());
- ASSERT_EQ("v1 v4 w2 v7", ui::test::ChildLayerNamesAsString(*w1_layer));
- ui::Layer* w2_layer = w1_layer->children()[2];
- ASSERT_EQ("v5", ui::test::ChildLayerNamesAsString(*w2_layer));
- ui::Layer* v5_layer = w2_layer->children()[0];
- ASSERT_EQ("v6", ui::test::ChildLayerNamesAsString(*v5_layer));
-
- w1_layer = views::corewm::RecreateWindowLayers(w1->GetNativeView(), false);
-
- // The order of the layers returned by RecreateWindowLayers() should match the
- // order of the layers prior to calling RecreateWindowLayers().
- ASSERT_EQ("w1", w1_layer->name());
- ASSERT_EQ("v1 v4 w2 v7", ui::test::ChildLayerNamesAsString(*w1_layer));
- w2_layer = w1_layer->children()[2];
- ASSERT_EQ("v5", ui::test::ChildLayerNamesAsString(*w2_layer));
- v5_layer = w2_layer->children()[0];
- ASSERT_EQ("v6", ui::test::ChildLayerNamesAsString(*v5_layer));
-
- views::corewm::DeepDeleteLayers(w1_layer);
- // The views and the widgets are destroyed when AuraTestHelper::TearDown()
- // destroys root_window().
-}
diff --git a/chromium/ui/views/cull_set.cc b/chromium/ui/views/cull_set.cc
new file mode 100644
index 00000000000..65566e0b362
--- /dev/null
+++ b/chromium/ui/views/cull_set.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/cull_set.h"
+
+namespace views {
+
+CullSet::CullSet() {
+}
+
+CullSet::~CullSet() {
+}
+
+CullSet::CullSet(scoped_ptr<base::hash_set<intptr_t> > cull_set)
+ : cull_set_(cull_set.Pass()) {
+}
+
+bool CullSet::ShouldPaint(const View* view) const {
+ if (cull_set_)
+ return (cull_set_->count(reinterpret_cast<intptr_t>(view)) > 0);
+
+ return true;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/cull_set.h b/chromium/ui/views/cull_set.h
new file mode 100644
index 00000000000..03f7cff86ee
--- /dev/null
+++ b/chromium/ui/views/cull_set.h
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CULL_SET_H_
+#define UI_VIEWS_CULL_SET_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class View;
+
+// A CullSet defines a set of View pointers which have been possibly culled
+// from painting or other bounds-checking operations. It wraps a set of
+// pointers to views, or NULL if no such set is available.
+class VIEWS_EXPORT CullSet {
+ public:
+ // Default constructor builds a CullSet that will always return true for
+ // ShouldPaint().
+ CullSet();
+ ~CullSet();
+
+ // Wraps a set of pointers to Views, as might be provided by
+ // gfx::RTree::Query(), that intersect the damage rect and therefore need
+ // to be painted. CullSet takes ownership of the provided pointer.
+ CullSet(scoped_ptr<base::hash_set<intptr_t> > cull_set);
+
+ // Returns true if |view| needs to be painted.
+ bool ShouldPaint(const View* view) const;
+
+ private:
+ friend class BoundsTreeTestView;
+
+ // The set of Views that collided with the query rectangle provided to the
+ // RTree data structure, or NULL if one is not available.
+ scoped_ptr<base::hash_set<intptr_t> > cull_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(CullSet);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CULL_SET_H_
diff --git a/chromium/ui/views/debug_utils.cc b/chromium/ui/views/debug_utils.cc
index 536a6f6abf5..12b4759b33d 100644
--- a/chromium/ui/views/debug_utils.cc
+++ b/chromium/ui/views/debug_utils.cc
@@ -4,7 +4,7 @@
#include "ui/views/debug_utils.h"
-#include <iostream>
+#include <ostream>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
@@ -18,7 +18,7 @@ void PrintViewHierarchyImp(const View* view,
int ind = indent;
while (ind-- > 0)
*out << L' ';
- *out << UTF8ToWide(view->GetClassName());
+ *out << base::UTF8ToWide(view->GetClassName());
*out << L' ';
*out << view->id();
*out << L' ';
@@ -38,7 +38,7 @@ void PrintFocusHierarchyImp(const View* view,
int ind = indent;
while (ind-- > 0)
*out << L' ';
- *out << UTF8ToWide(view->GetClassName());
+ *out << base::UTF8ToWide(view->GetClassName());
*out << L' ';
*out << view->id();
*out << L' ';
diff --git a/chromium/ui/views/drag_utils.cc b/chromium/ui/views/drag_utils.cc
index 0b9c31775a2..0fd5e5e91c8 100644
--- a/chromium/ui/views/drag_utils.cc
+++ b/chromium/ui/views/drag_utils.cc
@@ -5,26 +5,15 @@
#include "ui/views/drag_utils.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/size.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/size.h"
#include "ui/views/widget/widget.h"
-#elif defined(OS_WIN)
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/drag_source_win.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-#else
-#error
-#endif
+
+namespace {
float GetDeviceScaleForNativeView(views::Widget* widget) {
float device_scale = 1.0f;
-#if defined(USE_AURA)
// The following code should work on other platforms as well. But we do not
// yet care about device scale factor on other platforms. So to keep drag and
// drop behavior on other platforms un-touched, we wrap this in the #if guard.
@@ -34,34 +23,12 @@ float GetDeviceScaleForNativeView(views::Widget* widget) {
GetDisplayNearestWindow(view);
device_scale = display.device_scale_factor();
}
-#endif
return device_scale;
}
-namespace views {
+} // namespace
-void RunShellDrag(gfx::NativeView view,
- const ui::OSExchangeData& data,
- const gfx::Point& location,
- int operation,
- ui::DragDropTypes::DragEventSource source) {
-#if defined(USE_AURA)
- gfx::Point root_location(location);
- aura::Window* root_window = view->GetRootWindow();
- aura::Window::ConvertPointToTarget(view, root_window, &root_location);
- if (aura::client::GetDragDropClient(root_window)) {
- aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
- data, root_window, view, root_location, operation, source);
- }
-#elif defined(OS_WIN)
- scoped_refptr<ui::DragSourceWin> drag_source(new ui::DragSourceWin);
- DWORD effects;
- DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data),
- drag_source,
- ui::DragDropTypes::DragOperationToDropEffect(operation),
- &effects);
-#endif
-}
+namespace views {
gfx::Canvas* GetCanvasForDragImage(views::Widget* widget,
const gfx::Size& canvas_size) {
diff --git a/chromium/ui/views/drag_utils_aura.cc b/chromium/ui/views/drag_utils_aura.cc
new file mode 100644
index 00000000000..cb64199a2a6
--- /dev/null
+++ b/chromium/ui/views/drag_utils_aura.cc
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/drag_utils.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/wm/public/drag_drop_client.h"
+
+namespace views {
+
+void RunShellDrag(gfx::NativeView view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ gfx::Point root_location(location);
+ aura::Window* root_window = view->GetRootWindow();
+ aura::Window::ConvertPointToTarget(view, root_window, &root_location);
+ if (aura::client::GetDragDropClient(root_window)) {
+ aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
+ data, root_window, view, root_location, operation, source);
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/event_utils.h b/chromium/ui/views/event_utils.h
deleted file mode 100644
index 095487b1525..00000000000
--- a/chromium/ui/views/event_utils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_EVENT_UTILS_H_
-#define UI_VIEWS_EVENT_UTILS_H_
-
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class LocatedEvent;
-}
-
-namespace views {
-
-// Reposts a located event natively. Returns false when |event| could not be
-// reposted. |event| should be in screen coordinates. |window| is the target
-// window that the event will be forwarded to. Only some events are supported.
-VIEWS_EXPORT bool RepostLocatedEvent(gfx::NativeWindow window,
- const ui::LocatedEvent& event);
-
-#if defined(OS_WIN) && defined(USE_AURA)
-// Reposts a located event to the HWND passed in.
-VIEWS_EXPORT bool RepostLocatedEventWin(HWND window,
- const ui::LocatedEvent& event);
-#endif
-
-} // namespace views
-
-#endif // UI_VIEWS_EVENT_UTILS_H_
diff --git a/chromium/ui/views/event_utils_aura.cc b/chromium/ui/views/event_utils_aura.cc
deleted file mode 100644
index e3d07d9f310..00000000000
--- a/chromium/ui/views/event_utils_aura.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/event_utils.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/events/event.h"
-#include "ui/gfx/point.h"
-#include "ui/views/views_delegate.h"
-
-using aura::client::ScreenPositionClient;
-
-namespace views {
-
-bool RepostLocatedEvent(gfx::NativeWindow window,
- const ui::LocatedEvent& event) {
- if (!window)
- return false;
-
-#if defined(OS_WIN)
- if (ViewsDelegate::views_delegate &&
- !ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
- return RepostLocatedEventWin(
- window->GetDispatcher()->host()->GetAcceleratedWidget(), event);
- }
-#endif
- aura::Window* root_window = window->GetRootWindow();
-
- gfx::Point root_loc(event.location());
- ScreenPositionClient* spc =
- aura::client::GetScreenPositionClient(root_window);
- if (!spc)
- return false;
-
- spc->ConvertPointFromScreen(root_window, &root_loc);
-
- scoped_ptr<ui::LocatedEvent> relocated;
- if (event.IsMouseEvent()) {
- const ui::MouseEvent& orig = static_cast<const ui::MouseEvent&>(event);
- relocated.reset(new ui::MouseEvent(orig));
- } else if (event.IsGestureEvent()) {
- // TODO(rbyers): Gesture event repost is tricky to get right
- // crbug.com/170987.
- return false;
- } else {
- NOTREACHED();
- return false;
- }
- relocated->set_location(root_loc);
- relocated->set_root_location(root_loc);
-
- root_window->GetDispatcher()->RepostEvent(*relocated);
- return true;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/event_utils_win.cc b/chromium/ui/views/event_utils_win.cc
deleted file mode 100644
index 3e908889dfa..00000000000
--- a/chromium/ui/views/event_utils_win.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/event_utils.h"
-
-#include <windowsx.h>
-
-#include "base/logging.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/gfx/point.h"
-
-namespace views {
-
-#if defined(USE_AURA)
-bool RepostLocatedEventWin(HWND window,
- const ui::LocatedEvent& event) {
-#else
-bool RepostLocatedEvent(gfx::NativeWindow window
- const ui::LocatedEvent& event) {
-#endif
- if (!window)
- return false;
-
- // Determine whether the click was in the client area or not.
- // NOTE: WM_NCHITTEST coordinates are relative to the screen.
- const gfx::Point screen_loc = event.location();
- LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0,
- MAKELPARAM(screen_loc.x(),
- screen_loc.y()));
- const bool in_client_area = nc_hit_result == HTCLIENT;
-
- // TODO(sky): this isn't right. The event to generate should correspond with
- // the event we just got. MouseEvent only tells us what is down, which may
- // differ. Need to add ability to get changed button from MouseEvent.
- int event_type;
- int flags = event.flags();
- if (flags & ui::EF_LEFT_MOUSE_BUTTON) {
- event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
- } else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) {
- event_type = in_client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN;
- } else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) {
- event_type = in_client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN;
- } else {
- NOTREACHED();
- return false;
- }
-
- int window_x = screen_loc.x();
- int window_y = screen_loc.y();
- if (in_client_area) {
- POINT pt = {window_x, window_y};
- ScreenToClient(window, &pt);
- window_x = pt.x;
- window_y = pt.y;
- }
-
- WPARAM target = in_client_area ? event.native_event().wParam : nc_hit_result;
- PostMessage(window, event_type, target, MAKELPARAM(window_x, window_y));
- return true;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/examples/DEPS b/chromium/ui/views/examples/DEPS
index 1108a456a1a..06e440bbb91 100644
--- a/chromium/ui/views/examples/DEPS
+++ b/chromium/ui/views/examples/DEPS
@@ -2,4 +2,6 @@ include_rules = [
"+content/public",
"+content/shell",
"+sandbox",
+ "+ui/gl/gl_surface.h", # To initialize GL bindings.
+ "+ui/views_content_client",
]
diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc
index 6869b4634a1..49a60e59d9e 100644
--- a/chromium/ui/views/examples/bubble_example.cc
+++ b/chromium/ui/views/examples/bubble_example.cc
@@ -11,6 +11,8 @@
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -26,7 +28,7 @@ BubbleBorder::Arrow arrows[] = {
BubbleBorder::BOTTOM_LEFT, BubbleBorder::LEFT_BOTTOM,
BubbleBorder::LEFT_CENTER, BubbleBorder::LEFT_TOP };
-string16 GetArrowName(BubbleBorder::Arrow arrow) {
+base::string16 GetArrowName(BubbleBorder::Arrow arrow) {
switch (arrow) {
case BubbleBorder::TOP_LEFT: return ASCIIToUTF16("TOP_LEFT");
case BubbleBorder::TOP_RIGHT: return ASCIIToUTF16("TOP_RIGHT");
@@ -81,8 +83,6 @@ void BubbleExample::CreateExampleView(View* container) {
container->AddChildView(align_to_edge_);
persistent_ = new LabelButton(this, ASCIIToUTF16("Persistent"));
container->AddChildView(persistent_);
- fade_in_ = new LabelButton(this, ASCIIToUTF16("Fade In"));
- container->AddChildView(fade_in_);
}
void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
@@ -105,19 +105,14 @@ void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
else if (sender == small_shadow_)
bubble->set_shadow(BubbleBorder::SMALL_SHADOW);
- if (sender == persistent_) {
+ if (sender == persistent_)
bubble->set_close_on_deactivate(false);
- bubble->set_move_with_anchor(true);
- }
BubbleDelegateView::CreateBubble(bubble);
if (sender == align_to_edge_)
bubble->SetAlignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
- if (sender == fade_in_)
- bubble->StartFade(true);
- else
- bubble->GetWidget()->Show();
+ bubble->GetWidget()->Show();
}
} // namespace examples
diff --git a/chromium/ui/views/examples/bubble_example.h b/chromium/ui/views/examples/bubble_example.h
index fd0008e6ed9..d9ad66de6b0 100644
--- a/chromium/ui/views/examples/bubble_example.h
+++ b/chromium/ui/views/examples/bubble_example.h
@@ -12,15 +12,17 @@ namespace views {
namespace examples {
// A Bubble example.
-class BubbleExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT BubbleExample : public ExampleBase,
+ public ButtonListener {
public:
BubbleExample();
virtual ~BubbleExample();
- // Overridden from ExampleBase.
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
Button* no_shadow_;
@@ -28,7 +30,6 @@ class BubbleExample : public ExampleBase, public ButtonListener {
Button* small_shadow_;
Button* align_to_edge_;
Button* persistent_;
- Button* fade_in_;
DISALLOW_COPY_AND_ASSIGN(BubbleExample);
};
diff --git a/chromium/ui/views/examples/button_example.cc b/chromium/ui/views/examples/button_example.cc
index a791559982a..f5ea950c887 100644
--- a/chromium/ui/views/examples/button_example.cc
+++ b/chromium/ui/views/examples/button_example.cc
@@ -16,6 +16,8 @@
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+
namespace {
const char kLabelButton[] = "Label Button";
const char kTextButton[] = "Text Button";
@@ -73,8 +75,6 @@ void ButtonExample::CreateExampleView(View* container) {
rb.GetImageNamed(IDR_CLOSE_H).ToImageSkia());
image_button_->SetImage(ImageButton::STATE_PRESSED,
rb.GetImageNamed(IDR_CLOSE_P).ToImageSkia());
- image_button_->SetOverlayImage(rb.GetImageNamed(
- IDR_MENU_CHECK).ToImageSkia());
container->AddChildView(image_button_);
}
@@ -124,10 +124,13 @@ void ButtonExample::TextButtonPressed(const ui::Event& event) {
text_button_->text().length() < 50 ? kLongText : kTextButton));
} else {
use_native_theme_border_ = !use_native_theme_border_;
- if (use_native_theme_border_)
- text_button_->set_border(new TextButtonNativeThemeBorder(text_button_));
- else
- text_button_->set_border(new TextButtonDefaultBorder());
+ if (use_native_theme_border_) {
+ text_button_->SetBorder(scoped_ptr<views::Border>(
+ new TextButtonNativeThemeBorder(text_button_)));
+ } else {
+ text_button_->SetBorder(
+ scoped_ptr<views::Border>(new TextButtonDefaultBorder()));
+ }
}
} else if (event.IsAltDown()) {
text_button_->SetIsDefault(!text_button_->is_default());
@@ -161,7 +164,7 @@ void ButtonExample::LabelButtonPressed(const ui::Event& event) {
}
} else if (event.IsShiftDown()) {
if (event.IsAltDown()) {
- label_button_->SetFocusable(!label_button_->focusable());
+ label_button_->SetFocusable(!label_button_->IsFocusable());
} else {
label_button_->SetStyle(static_cast<Button::ButtonStyle>(
(label_button_->style() + 1) % Button::STYLE_COUNT));
diff --git a/chromium/ui/views/examples/button_example.h b/chromium/ui/views/examples/button_example.h
index 6f23a0be1c1..d195faa6820 100644
--- a/chromium/ui/views/examples/button_example.h
+++ b/chromium/ui/views/examples/button_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_BUTTON_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_BUTTON_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/text_button.h"
#include "ui/views/examples/example_base.h"
@@ -18,19 +17,20 @@ class LabelButton;
namespace examples {
// ButtonExample simply counts the number of clicks.
-class ButtonExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT ButtonExample : public ExampleBase,
+ public ButtonListener {
public:
ButtonExample();
virtual ~ButtonExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
void TextButtonPressed(const ui::Event& event);
void LabelButtonPressed(const ui::Event& event);
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
// Example buttons.
diff --git a/chromium/ui/views/examples/checkbox_example.cc b/chromium/ui/views/examples/checkbox_example.cc
index cfe930fd0ca..b25dd8e8d86 100644
--- a/chromium/ui/views/examples/checkbox_example.cc
+++ b/chromium/ui/views/examples/checkbox_example.cc
@@ -20,7 +20,7 @@ CheckboxExample::~CheckboxExample() {
}
void CheckboxExample::CreateExampleView(View* container) {
- button_ = new Checkbox(ASCIIToUTF16("Checkbox"));
+ button_ = new Checkbox(base::ASCIIToUTF16("Checkbox"));
button_->set_listener(this);
container->SetLayoutManager(new FillLayout);
container->AddChildView(button_);
diff --git a/chromium/ui/views/examples/checkbox_example.h b/chromium/ui/views/examples/checkbox_example.h
index 1b0e52f5a3a..a5a8964513e 100644
--- a/chromium/ui/views/examples/checkbox_example.h
+++ b/chromium/ui/views/examples/checkbox_example.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_CHECKBOX_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_CHECKBOX_EXAMPLE_H_
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/examples/example_base.h"
@@ -15,7 +15,8 @@ class Checkbox;
namespace examples {
// CheckboxExample exercises a Checkbox control.
-class CheckboxExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT CheckboxExample : public ExampleBase,
+ public ButtonListener {
public:
CheckboxExample();
virtual ~CheckboxExample();
diff --git a/chromium/ui/views/examples/combobox_example.cc b/chromium/ui/views/examples/combobox_example.cc
index 4c2a1b8cc26..ed07379b605 100644
--- a/chromium/ui/views/examples/combobox_example.cc
+++ b/chromium/ui/views/examples/combobox_example.cc
@@ -22,8 +22,8 @@ int ComboboxModelExample::GetItemCount() const {
return 10;
}
-string16 ComboboxModelExample::GetItemAt(int index) {
- return UTF8ToUTF16(base::StringPrintf("Item %d", index));
+base::string16 ComboboxModelExample::GetItemAt(int index) {
+ return base::UTF8ToUTF16(base::StringPrintf("Item %d", index));
}
ComboboxExample::ComboboxExample() : ExampleBase("Combo Box"), combobox_(NULL) {
@@ -44,9 +44,9 @@ void ComboboxExample::CreateExampleView(View* container) {
container->AddChildView(combobox_);
}
-void ComboboxExample::OnSelectedIndexChanged(Combobox* combobox) {
+void ComboboxExample::OnPerformAction(Combobox* combobox) {
DCHECK_EQ(combobox_, combobox);
- PrintStatus("Selected: %s", UTF16ToUTF8(combobox_model_.GetItemAt(
+ PrintStatus("Selected: %s", base::UTF16ToUTF8(combobox_model_.GetItemAt(
combobox->selected_index())).c_str());
}
diff --git a/chromium/ui/views/examples/combobox_example.h b/chromium/ui/views/examples/combobox_example.h
index 263782d54e3..89ccff2e986 100644
--- a/chromium/ui/views/examples/combobox_example.h
+++ b/chromium/ui/views/examples/combobox_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_COMBOBOX_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_COMBOBOX_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/base/models/combobox_model.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/examples/example_base.h"
@@ -15,30 +14,31 @@ namespace views {
namespace examples {
// A combobox model implementation that generates a list of "Item <index>".
-class ComboboxModelExample : public ui::ComboboxModel {
+class VIEWS_EXAMPLES_EXPORT ComboboxModelExample : public ui::ComboboxModel {
public:
ComboboxModelExample();
virtual ~ComboboxModelExample();
- // Overridden from ui::ComboboxModel:
+ // ui::ComboboxModel:
virtual int GetItemCount() const OVERRIDE;
- virtual string16 GetItemAt(int index) OVERRIDE;
+ virtual base::string16 GetItemAt(int index) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(ComboboxModelExample);
};
-class ComboboxExample : public ExampleBase, public ComboboxListener {
+class VIEWS_EXAMPLES_EXPORT ComboboxExample : public ExampleBase,
+ public ComboboxListener {
public:
ComboboxExample();
virtual ~ComboboxExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE;
+ // ComboboxListener:
+ virtual void OnPerformAction(Combobox* combobox) OVERRIDE;
ComboboxModelExample combobox_model_;
Combobox* combobox_;
diff --git a/chromium/ui/views/examples/content_client/DEPS b/chromium/ui/views/examples/content_client/DEPS
deleted file mode 100644
index f71262e800a..00000000000
--- a/chromium/ui/views/examples/content_client/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+content/public",
- "+content/shell",
-]
diff --git a/chromium/ui/views/examples/content_client/examples_browser_main_parts.cc b/chromium/ui/views/examples/content_client/examples_browser_main_parts.cc
deleted file mode 100644
index e270d6fef12..00000000000
--- a/chromium/ui/views/examples/content_client/examples_browser_main_parts.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/examples/content_client/examples_browser_main_parts.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "content/public/common/content_switches.h"
-#include "content/shell/browser/shell_browser_context.h"
-#include "ui/base/ime/input_method_initializer.h"
-#include "ui/views/examples/examples_window_with_content.h"
-#include "ui/views/focus/accelerator_handler.h"
-#include "ui/views/test/desktop_test_views_delegate.h"
-#include "url/gurl.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/widget/desktop_aura/desktop_screen.h"
-#include "ui/views/widget/native_widget_aura.h"
-#endif
-
-#if defined(OS_CHROMEOS)
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_screen.h"
-#include "ui/aura/window.h"
-#include "ui/wm/test/wm_test_helper.h"
-#endif
-
-namespace views {
-namespace examples {
-
-ExamplesBrowserMainParts::ExamplesBrowserMainParts(
- const content::MainFunctionParams& parameters) {
-}
-
-ExamplesBrowserMainParts::~ExamplesBrowserMainParts() {
-}
-
-void ExamplesBrowserMainParts::PreMainMessageLoopRun() {
- ui::InitializeInputMethodForTesting();
- browser_context_.reset(new content::ShellBrowserContext(false, NULL));
-
- gfx::NativeView window_context = NULL;
-#if defined(OS_CHROMEOS)
- gfx::Screen::SetScreenInstance(
- gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
- // Set up basic pieces of views::corewm.
- wm_test_helper_.reset(new wm::WMTestHelper(gfx::Size(800, 600)));
- // Ensure the X window gets mapped.
- wm_test_helper_->root_window()->host()->Show();
- // Ensure Aura knows where to open new windows.
- window_context = wm_test_helper_->root_window()->window();
-#elif defined(USE_AURA)
- aura::Env::CreateInstance();
- gfx::Screen::SetScreenInstance(
- gfx::SCREEN_TYPE_NATIVE, CreateDesktopScreen());
-#endif
- views_delegate_.reset(new DesktopTestViewsDelegate);
-
- ShowExamplesWindowWithContent(
- QUIT_ON_CLOSE, browser_context_.get(), window_context);
-}
-
-void ExamplesBrowserMainParts::PostMainMessageLoopRun() {
- browser_context_.reset();
-#if defined(OS_CHROMEOS)
- wm_test_helper_.reset();
-#endif
- views_delegate_.reset();
-#if defined(USE_AURA)
- aura::Env::DeleteInstance();
-#endif
-}
-
-bool ExamplesBrowserMainParts::MainMessageLoopRun(int* result_code) {
- // xxx: Hax here because this kills event handling.
-#if !defined(USE_AURA)
- AcceleratorHandler accelerator_handler;
- base::RunLoop run_loop(&accelerator_handler);
-#else
- base::RunLoop run_loop;
-#endif
- run_loop.Run();
- return true;
-}
-
-} // namespace examples
-} // namespace views
diff --git a/chromium/ui/views/examples/content_client/examples_browser_main_parts.h b/chromium/ui/views/examples/content_client/examples_browser_main_parts.h
deleted file mode 100644
index c3e3172c6d5..00000000000
--- a/chromium/ui/views/examples/content_client/examples_browser_main_parts.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_BROWSER_MAIN_PARTS_H_
-#define UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_BROWSER_MAIN_PARTS_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/browser_main_parts.h"
-
-namespace content {
-class ShellBrowserContext;
-struct MainFunctionParams;
-}
-
-namespace wm {
-class WMTestHelper;
-}
-
-namespace views {
-class ViewsDelegate;
-
-namespace examples {
-
-class ExamplesBrowserMainParts : public content::BrowserMainParts {
- public:
- explicit ExamplesBrowserMainParts(
- const content::MainFunctionParams& parameters);
- virtual ~ExamplesBrowserMainParts();
-
- // Overridden from content::BrowserMainParts:
- virtual void PreMainMessageLoopRun() OVERRIDE;
- virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
- virtual void PostMainMessageLoopRun() OVERRIDE;
-
- content::ShellBrowserContext* browser_context() {
- return browser_context_.get();
- }
-
- private:
- scoped_ptr<content::ShellBrowserContext> browser_context_;
-
- scoped_ptr<ViewsDelegate> views_delegate_;
-
-#if defined(OS_CHROMEOS)
- // Enable a minimal set of views::corewm to be initialized.
- scoped_ptr<wm::WMTestHelper> wm_test_helper_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(ExamplesBrowserMainParts);
-};
-
-} // namespace examples
-} // namespace views
-
-#endif // UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_BROWSER_MAIN_PARTS_H_
diff --git a/chromium/ui/views/examples/content_client/examples_content_browser_client.cc b/chromium/ui/views/examples/content_client/examples_content_browser_client.cc
deleted file mode 100644
index 8a4ebc862e9..00000000000
--- a/chromium/ui/views/examples/content_client/examples_content_browser_client.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/examples/content_client/examples_content_browser_client.h"
-
-#include "content/shell/browser/shell_browser_context.h"
-#include "ui/views/examples/content_client/examples_browser_main_parts.h"
-
-namespace views {
-namespace examples {
-
-ExamplesContentBrowserClient::ExamplesContentBrowserClient()
- : examples_browser_main_parts_(NULL) {
-}
-
-ExamplesContentBrowserClient::~ExamplesContentBrowserClient() {
-}
-
-content::BrowserMainParts* ExamplesContentBrowserClient::CreateBrowserMainParts(
- const content::MainFunctionParams& parameters) {
- examples_browser_main_parts_ = new ExamplesBrowserMainParts(parameters);
- return examples_browser_main_parts_;
-}
-
-net::URLRequestContextGetter*
-ExamplesContentBrowserClient::CreateRequestContext(
- content::BrowserContext* content_browser_context,
- content::ProtocolHandlerMap* protocol_handlers) {
- content::ShellBrowserContext* shell_context =
- examples_browser_main_parts_->browser_context();
- return shell_context->CreateRequestContext(protocol_handlers);
-}
-
-} // namespace examples
-} // namespace views
diff --git a/chromium/ui/views/examples/content_client/examples_content_browser_client.h b/chromium/ui/views/examples/content_client/examples_content_browser_client.h
deleted file mode 100644
index b49d2c0528e..00000000000
--- a/chromium/ui/views/examples/content_client/examples_content_browser_client.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_CONTENT_BROWSER_CLIENT_H_
-#define UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_CONTENT_BROWSER_CLIENT_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/content_browser_client.h"
-
-namespace content {
-class ShellBrowserContext;
-}
-
-namespace views {
-namespace examples {
-
-class ExamplesBrowserMainParts;
-
-class ExamplesContentBrowserClient : public content::ContentBrowserClient {
- public:
- ExamplesContentBrowserClient();
- virtual ~ExamplesContentBrowserClient();
-
- // Overridden from content::ContentBrowserClient:
- virtual content::BrowserMainParts* CreateBrowserMainParts(
- const content::MainFunctionParams& parameters) OVERRIDE;
- virtual net::URLRequestContextGetter* CreateRequestContext(
- content::BrowserContext* browser_context,
- content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
-
- private:
- ExamplesBrowserMainParts* examples_browser_main_parts_;
-
- DISALLOW_COPY_AND_ASSIGN(ExamplesContentBrowserClient);
-};
-
-} // namespace examples
-} // namespace views
-
-#endif // UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_CONTENT_BROWSER_CLIENT_H_
diff --git a/chromium/ui/views/examples/content_client/examples_main.cc b/chromium/ui/views/examples/content_client/examples_main.cc
deleted file mode 100644
index bb2b059b71e..00000000000
--- a/chromium/ui/views/examples/content_client/examples_main.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/public/app/content_main.h"
-#include "sandbox/win/src/sandbox_types.h"
-#include "ui/views/examples/content_client/examples_main_delegate.h"
-
-#if defined(OS_WIN)
-#include "content/public/app/startup_helper_win.h"
-#endif
-
-#if defined(OS_WIN)
-int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
- sandbox::SandboxInterfaceInfo sandbox_info = {0};
- content::InitializeSandboxInfo(&sandbox_info);
- views::examples::ExamplesMainDelegate delegate;
- return content::ContentMain(instance, &sandbox_info, &delegate);
-}
-#else
-int main(int argc, const char** argv) {
- views::examples::ExamplesMainDelegate delegate;
- return content::ContentMain(argc, argv, &delegate);
-}
-#endif
diff --git a/chromium/ui/views/examples/content_client/examples_main_delegate.cc b/chromium/ui/views/examples/content_client/examples_main_delegate.cc
deleted file mode 100644
index aabd289d868..00000000000
--- a/chromium/ui/views/examples/content_client/examples_main_delegate.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/examples/content_client/examples_main_delegate.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "content/public/common/content_switches.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/views/examples/content_client/examples_content_browser_client.h"
-
-#if defined(OS_WIN)
-#include "base/logging_win.h"
-#endif
-
-namespace views {
-namespace examples {
-namespace {
-
-#if defined(OS_WIN)
-// {83FAC8EE-7A0E-4dbb-A3F6-6F500D7CAB1A}
-const GUID kViewsExamplesProviderName =
- { 0x83fac8ee, 0x7a0e, 0x4dbb,
- { 0xa3, 0xf6, 0x6f, 0x50, 0xd, 0x7c, 0xab, 0x1a } };
-#endif
-
-} // namespace
-
-ExamplesMainDelegate::ExamplesMainDelegate() {
-}
-
-ExamplesMainDelegate::~ExamplesMainDelegate() {
-}
-
-bool ExamplesMainDelegate::BasicStartupComplete(int* exit_code) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- std::string process_type =
- command_line.GetSwitchValueASCII(switches::kProcessType);
-
- content::SetContentClient(&content_client_);
-
- logging::LoggingSettings settings;
- settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
- bool success = logging::InitLogging(settings);
- CHECK(success);
-#if defined(OS_WIN)
- logging::LogEventProvider::Initialize(kViewsExamplesProviderName);
-#endif
-
- return false;
-}
-
-void ExamplesMainDelegate::PreSandboxStartup() {
- InitializeResourceBundle();
-}
-
-content::ContentBrowserClient*
- ExamplesMainDelegate::CreateContentBrowserClient() {
- browser_client_.reset(new ExamplesContentBrowserClient);
- return browser_client_.get();
-}
-
-void ExamplesMainDelegate::InitializeResourceBundle() {
- base::FilePath pak_dir;
- PathService::Get(base::DIR_MODULE, &pak_dir);
-
- base::FilePath pak_file;
- pak_file = pak_dir.Append(FILE_PATH_LITERAL("ui_test.pak"));
-
- ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
-}
-
-} // namespace examples
-} // namespace views
diff --git a/chromium/ui/views/examples/content_client/examples_main_delegate.h b/chromium/ui/views/examples/content_client/examples_main_delegate.h
deleted file mode 100644
index e8cb493f613..00000000000
--- a/chromium/ui/views/examples/content_client/examples_main_delegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_MAIN_DELEGATE_H_
-#define UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_MAIN_DELEGATE_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/app/content_main_delegate.h"
-#include "content/shell/common/shell_content_client.h"
-
-namespace views {
-namespace examples {
-
-class ExamplesContentBrowserClient;
-
-class ExamplesMainDelegate : public content::ContentMainDelegate {
- public:
- ExamplesMainDelegate();
- virtual ~ExamplesMainDelegate();
-
- // content::ContentMainDelegate implementation
- virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
- virtual void PreSandboxStartup() OVERRIDE;
- virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
-
- private:
- void InitializeResourceBundle();
-
- scoped_ptr<ExamplesContentBrowserClient> browser_client_;
- content::ShellContentClient content_client_;
-
- DISALLOW_COPY_AND_ASSIGN(ExamplesMainDelegate);
-};
-
-} // namespace examples
-} // namespace views
-
-#endif // UI_VIEWS_EXAMPLES_CONTENT_CLIENT_EXAMPLES_MAIN_DELEGATE_H_
diff --git a/chromium/ui/views/examples/double_split_view_example.cc b/chromium/ui/views/examples/double_split_view_example.cc
index fb1f099a1f9..8ff40df66a8 100644
--- a/chromium/ui/views/examples/double_split_view_example.cc
+++ b/chromium/ui/views/examples/double_split_view_example.cc
@@ -21,8 +21,8 @@ class SplittedView : public View {
void SetColor(SkColor from, SkColor to);
- // Overridden from View.
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ // View:
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(SplittedView);
@@ -39,7 +39,7 @@ void SplittedView::SetColor(SkColor from, SkColor to) {
set_background(Background::CreateVerticalGradientBackground(from, to));
}
-gfx::Size SplittedView::GetMinimumSize() {
+gfx::Size SplittedView::GetMinimumSize() const {
return gfx::Size(10, 10);
}
diff --git a/chromium/ui/views/examples/double_split_view_example.h b/chromium/ui/views/examples/double_split_view_example.h
index 7fbae46b212..fe37c792657 100644
--- a/chromium/ui/views/examples/double_split_view_example.h
+++ b/chromium/ui/views/examples/double_split_view_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_DOUBLE_SPLIT_VIEW_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_DOUBLE_SPLIT_VIEW_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/examples/example_base.h"
namespace views {
@@ -14,12 +13,12 @@ class SingleSplitView;
namespace examples {
-class DoubleSplitViewExample : public ExampleBase {
+class VIEWS_EXAMPLES_EXPORT DoubleSplitViewExample : public ExampleBase {
public:
DoubleSplitViewExample();
virtual ~DoubleSplitViewExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
diff --git a/chromium/ui/views/examples/example_base.cc b/chromium/ui/views/examples/example_base.cc
index 66a6c854c4a..a06fc1dcfea 100644
--- a/chromium/ui/views/examples/example_base.cc
+++ b/chromium/ui/views/examples/example_base.cc
@@ -6,7 +6,6 @@
#include <stdarg.h>
-#include "base/compiler_specific.h"
#include "base/strings/stringprintf.h"
#include "ui/views/view.h"
@@ -28,7 +27,7 @@ class ContainerView : public View {
}
private:
- // Overridden from View:
+ // View:
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE {
View::ViewHierarchyChanged(details);
diff --git a/chromium/ui/views/examples/example_base.h b/chromium/ui/views/examples/example_base.h
index a17cc0d0f91..f841eb920b1 100644
--- a/chromium/ui/views/examples/example_base.h
+++ b/chromium/ui/views/examples/example_base.h
@@ -7,14 +7,15 @@
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "ui/views/examples/views_examples_export.h"
namespace views {
class View;
namespace examples {
-class ExampleBase {
+class VIEWS_EXAMPLES_EXPORT ExampleBase {
public:
virtual ~ExampleBase();
diff --git a/chromium/ui/views/examples/example_combobox_model.cc b/chromium/ui/views/examples/example_combobox_model.cc
index 255ef15af96..a1160e7bb0e 100644
--- a/chromium/ui/views/examples/example_combobox_model.cc
+++ b/chromium/ui/views/examples/example_combobox_model.cc
@@ -20,8 +20,8 @@ int ExampleComboboxModel::GetItemCount() const {
return count_;
}
-string16 ExampleComboboxModel::GetItemAt(int index) {
- return ASCIIToUTF16(strings_[index]);
+base::string16 ExampleComboboxModel::GetItemAt(int index) {
+ return base::ASCIIToUTF16(strings_[index]);
}
} // namespace examples
diff --git a/chromium/ui/views/examples/example_combobox_model.h b/chromium/ui/views/examples/example_combobox_model.h
index 74262d8b90f..3b233323ef5 100644
--- a/chromium/ui/views/examples/example_combobox_model.h
+++ b/chromium/ui/views/examples/example_combobox_model.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_EXAMPLE_COMBOBOX_MODEL_H_
#define UI_VIEWS_EXAMPLES_EXAMPLE_COMBOBOX_MODEL_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/base/models/combobox_model.h"
namespace views {
@@ -17,9 +16,9 @@ class ExampleComboboxModel : public ui::ComboboxModel {
ExampleComboboxModel(const char** strings, int count);
virtual ~ExampleComboboxModel();
- // Overridden from ui::ComboboxModel:
+ // ui::ComboboxModel:
virtual int GetItemCount() const OVERRIDE;
- virtual string16 GetItemAt(int index) OVERRIDE;
+ virtual base::string16 GetItemAt(int index) OVERRIDE;
private:
const char** strings_;
diff --git a/chromium/ui/views/examples/examples.gyp b/chromium/ui/views/examples/examples.gyp
new file mode 100644
index 00000000000..4cf3a1bcf6b
--- /dev/null
+++ b/chromium/ui/views/examples/examples.gyp
@@ -0,0 +1,187 @@
+# 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.
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'views_examples_lib',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../skia/skia.gyp:skia',
+ '../../../third_party/icu/icu.gyp:icui18n',
+ '../../../third_party/icu/icu.gyp:icuuc',
+ '../../base/ui_base.gyp:ui_base',
+ '../../events/events.gyp:events',
+ '../../gfx/gfx.gyp:gfx',
+ '../../gfx/gfx.gyp:gfx_geometry',
+ '../../resources/ui_resources.gyp:ui_resources',
+ '../../resources/ui_resources.gyp:ui_test_pak',
+ '../views.gyp:views',
+ ],
+ 'include_dirs': [
+ '../../..',
+ ],
+ 'defines': [
+ 'VIEWS_EXAMPLES_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'bubble_example.cc',
+ 'bubble_example.h',
+ 'button_example.cc',
+ 'button_example.h',
+ 'checkbox_example.cc',
+ 'checkbox_example.h',
+ 'combobox_example.cc',
+ 'combobox_example.h',
+ 'double_split_view_example.cc',
+ 'double_split_view_example.h',
+ 'example_base.cc',
+ 'example_base.h',
+ 'example_combobox_model.cc',
+ 'example_combobox_model.h',
+ 'examples_window.cc',
+ 'examples_window.h',
+ 'label_example.cc',
+ 'label_example.h',
+ 'link_example.cc',
+ 'link_example.h',
+ 'message_box_example.cc',
+ 'message_box_example.h',
+ 'menu_example.cc',
+ 'menu_example.h',
+ 'multiline_example.cc',
+ 'multiline_example.h',
+ 'progress_bar_example.cc',
+ 'progress_bar_example.h',
+ 'radio_button_example.cc',
+ 'radio_button_example.h',
+ 'scroll_view_example.cc',
+ 'scroll_view_example.h',
+ 'single_split_view_example.cc',
+ 'single_split_view_example.h',
+ 'slider_example.cc',
+ 'slider_example.h',
+ 'tabbed_pane_example.cc',
+ 'tabbed_pane_example.h',
+ 'table_example.cc',
+ 'table_example.h',
+ 'text_example.cc',
+ 'text_example.h',
+ 'textfield_example.cc',
+ 'textfield_example.h',
+ 'throbber_example.cc',
+ 'throbber_example.h',
+ 'tree_view_example.cc',
+ 'tree_view_example.h',
+ 'views_examples_export.h',
+ 'widget_example.cc',
+ 'widget_example.h',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'include_dirs': [
+ '../../../third_party/wtl/include',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ }],
+ ['use_aura==1', {
+ 'dependencies': [
+ '../../aura/aura.gyp:aura',
+ ],
+ }],
+ ],
+ }, # target_name: views_examples_lib
+ {
+ 'target_name': 'views_examples_exe',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../base/base.gyp:base_i18n',
+ '../../base/ui_base.gyp:ui_base',
+ '../../compositor/compositor.gyp:compositor',
+ '../../compositor/compositor.gyp:compositor_test_support',
+ '../../gfx/gfx.gyp:gfx',
+ '../../resources/ui_resources.gyp:ui_test_pak',
+ '../views.gyp:views',
+ '../views.gyp:views_test_support',
+ 'views_examples_lib',
+ ],
+ 'sources': [
+ 'examples_main.cc',
+ ],
+ 'conditions': [
+ ['use_aura==1', {
+ 'dependencies': [
+ '../../aura/aura.gyp:aura',
+ ],
+ }],
+ ],
+ }, # target_name: views_examples_exe
+ {
+ 'target_name': 'views_examples_with_content_lib',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../content/content.gyp:content',
+ '../../../skia/skia.gyp:skia',
+ '../../../url/url.gyp:url_lib',
+ '../../events/events.gyp:events',
+ '../controls/webview/webview.gyp:webview',
+ '../views.gyp:views',
+ 'views_examples_lib',
+ ],
+ 'defines': [
+ 'VIEWS_EXAMPLES_WITH_CONTENT_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'examples_window_with_content.cc',
+ 'examples_window_with_content.h',
+ 'views_examples_with_content_export.h',
+ 'webview_example.cc',
+ 'webview_example.h',
+ ],
+ }, # target_name: views_examples_with_content_lib
+ {
+ 'target_name': 'views_examples_with_content_exe',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../content/content.gyp:content',
+ '../../views_content_client/views_content_client.gyp:views_content_client',
+ 'views_examples_with_content_lib',
+ ],
+ 'sources': [
+ '../../../content/app/startup_helper_win.cc',
+ 'examples_with_content_main_exe.cc',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [
+ '-limm32.lib',
+ '-loleacc.lib',
+ ]
+ },
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'AdditionalManifestFiles': [
+ 'views_examples.exe.manifest',
+ ],
+ },
+ 'VCLinkerTool': {
+ 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
+ },
+ },
+ 'dependencies': [
+ '../../../sandbox/sandbox.gyp:sandbox',
+ ],
+ }],
+ ],
+ }, # target_name: views_examples_with_content_exe
+ ],
+}
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index 28864c477c8..4dc9fbec153 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -4,16 +4,94 @@
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
+#include "ui/aura/env.h"
+#include "ui/base/ime/input_method_initializer.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/compositor/test/in_process_context_factory.h"
+#include "ui/gfx/screen.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/views/examples/example_base.h"
+#include "ui/views/examples/examples_window.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/wm/core/wm_state.h"
+
+#if !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#endif
+
+#if defined(OS_WIN)
+#include "ui/base/win/scoped_ole_initializer.h"
+#endif
+
+#if defined(USE_X11)
+#include "ui/gfx/x/x11_connection.h"
+#endif
int main(int argc, char** argv) {
- base::AtExitManager at_exit;
+#if defined(OS_WIN)
+ ui::ScopedOleInitializer ole_initializer_;
+#endif
+
CommandLine::Init(argc, argv);
- base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+ base::AtExitManager at_exit;
+
+#if defined(USE_X11)
+ // This demo uses InProcessContextFactory which uses X on a separate Gpu
+ // thread.
+ gfx::InitializeThreadedX11();
+#endif
+
+ gfx::GLSurface::InitializeOneOff();
+
+ // The ContextFactory must exist before any Compositors are created.
+ scoped_ptr<ui::InProcessContextFactory> context_factory(
+ new ui::InProcessContextFactory());
+
+ base::MessageLoopForUI message_loop;
+
+ base::i18n::InitializeICU();
+
+ ui::RegisterPathProvider();
+
+ base::FilePath ui_test_pak_path;
+ DCHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
+
+ aura::Env::CreateInstance(true);
+ aura::Env::GetInstance()->set_context_factory(context_factory.get());
+
+ ui::InitializeInputMethodForTesting();
+
+ {
+ views::DesktopTestViewsDelegate views_delegate;
+ wm::WMState wm_state;
+
+#if !defined(OS_CHROMEOS)
+ scoped_ptr<gfx::Screen> desktop_screen(views::CreateDesktopScreen());
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
+ desktop_screen.get());
+#endif
+
+ views::examples::ShowExamplesWindow(
+ views::examples::QUIT_ON_CLOSE,
+ NULL,
+ scoped_ptr<ScopedVector<views::examples::ExampleBase> >());
+
+ base::RunLoop().Run();
+
+ ui::ResourceBundle::CleanupSharedInstance();
+ }
+
+ ui::ShutdownInputMethod();
- base::RunLoop().Run();
+ aura::Env::DeleteInstance();
return 0;
}
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index 041199286d1..55474440723 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -4,6 +4,7 @@
#include "ui/views/examples/examples_window.h"
+#include <algorithm>
#include <string>
#include "base/memory/scoped_vector.h"
@@ -43,26 +44,76 @@
namespace views {
namespace examples {
+typedef scoped_ptr<ScopedVector<ExampleBase> > ScopedExamples;
+
+namespace {
+
+// Creates the default set of examples. Caller owns the result.
+ScopedExamples CreateExamples() {
+ ScopedExamples examples(new ScopedVector<ExampleBase>);
+ examples->push_back(new BubbleExample);
+ examples->push_back(new ButtonExample);
+ examples->push_back(new CheckboxExample);
+ examples->push_back(new ComboboxExample);
+ examples->push_back(new DoubleSplitViewExample);
+ examples->push_back(new LabelExample);
+ examples->push_back(new LinkExample);
+ examples->push_back(new MenuExample);
+ examples->push_back(new MessageBoxExample);
+ examples->push_back(new MultilineExample);
+ examples->push_back(new ProgressBarExample);
+ examples->push_back(new RadioButtonExample);
+ examples->push_back(new ScrollViewExample);
+ examples->push_back(new SingleSplitViewExample);
+ examples->push_back(new SliderExample);
+ examples->push_back(new TabbedPaneExample);
+ examples->push_back(new TableExample);
+ examples->push_back(new TextExample);
+ examples->push_back(new TextfieldExample);
+ examples->push_back(new ThrobberExample);
+ examples->push_back(new TreeViewExample);
+ examples->push_back(new WidgetExample);
+ return examples.Pass();
+}
+
+struct ExampleTitleCompare {
+ bool operator() (ExampleBase* a, ExampleBase* b) {
+ return a->example_title() < b->example_title();
+ }
+};
+
+ScopedExamples GetExamplesToShow(ScopedExamples extra) {
+ ScopedExamples examples(CreateExamples());
+ if (extra.get()) {
+ examples->insert(examples->end(), extra->begin(), extra->end());
+ extra->weak_clear();
+ }
+ std::sort(examples->begin(), examples->end(), ExampleTitleCompare());
+ return examples.Pass();
+}
+
+} // namespace
+
// Model for the examples that are being added via AddExample().
class ComboboxModelExampleList : public ui::ComboboxModel {
public:
ComboboxModelExampleList() {}
virtual ~ComboboxModelExampleList() {}
- // Overridden from ui::ComboboxModel:
+ void SetExamples(ScopedExamples examples) {
+ example_list_.swap(*examples);
+ }
+
+ // ui::ComboboxModel:
virtual int GetItemCount() const OVERRIDE { return example_list_.size(); }
- virtual string16 GetItemAt(int index) OVERRIDE {
- return UTF8ToUTF16(example_list_[index]->example_title());
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
+ return base::UTF8ToUTF16(example_list_[index]->example_title());
}
View* GetItemViewAt(int index) {
return example_list_[index]->example_view();
}
- void AddExample(ExampleBase* example) {
- example_list_.push_back(example);
- }
-
private:
ScopedVector<ExampleBase> example_list_;
@@ -72,14 +123,40 @@ class ComboboxModelExampleList : public ui::ComboboxModel {
class ExamplesWindowContents : public WidgetDelegateView,
public ComboboxListener {
public:
- ExamplesWindowContents(Operation operation)
+ ExamplesWindowContents(Operation operation, ScopedExamples examples)
: combobox_(new Combobox(&combobox_model_)),
example_shown_(new View),
status_label_(new Label),
operation_(operation) {
instance_ = this;
combobox_->set_listener(this);
+ combobox_model_.SetExamples(examples.Pass());
+ combobox_->ModelChanged();
+
+ set_background(Background::CreateStandardPanelBackground());
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+ ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddPaddingColumn(0, 5);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 5);
+ layout->AddPaddingRow(0, 5);
+ layout->StartRow(0 /* no expand */, 0);
+ layout->AddView(combobox_);
+
+ if (combobox_model_.GetItemCount() > 0) {
+ layout->StartRow(1, 0);
+ example_shown_->SetLayoutManager(new FillLayout());
+ example_shown_->AddChildView(combobox_model_.GetItemViewAt(0));
+ layout->AddView(example_shown_);
+ }
+
+ layout->StartRow(0 /* no expand */, 0);
+ layout->AddView(status_label_);
+ layout->AddPaddingRow(0, 5);
}
+
virtual ~ExamplesWindowContents() {
// Delete |combobox_| first as it references |combobox_model_|.
delete combobox_;
@@ -88,17 +165,17 @@ class ExamplesWindowContents : public WidgetDelegateView,
// Prints a message in the status area, at the bottom of the window.
void SetStatus(const std::string& status) {
- status_label_->SetText(UTF8ToUTF16(status));
+ status_label_->SetText(base::UTF8ToUTF16(status));
}
static ExamplesWindowContents* instance() { return instance_; }
private:
- // Overridden from WidgetDelegateView:
+ // WidgetDelegateView:
virtual bool CanResize() const OVERRIDE { return true; }
virtual bool CanMaximize() const OVERRIDE { return true; }
- virtual string16 GetWindowTitle() const OVERRIDE {
- return ASCIIToUTF16("Views Examples");
+ virtual base::string16 GetWindowTitle() const OVERRIDE {
+ return base::ASCIIToUTF16("Views Examples");
}
virtual View* GetContentsView() OVERRIDE { return this; }
virtual void WindowClosing() OVERRIDE {
@@ -107,15 +184,8 @@ class ExamplesWindowContents : public WidgetDelegateView,
base::MessageLoopForUI::current()->Quit();
}
- // Overridden from View:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE {
- if (details.is_add && details.child == this)
- InitExamplesWindow();
- }
-
- // Overridden from ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE {
+ // ComboboxListener:
+ virtual void OnPerformAction(Combobox* combobox) OVERRIDE {
DCHECK_EQ(combobox, combobox_);
DCHECK(combobox->selected_index() < combobox_model_.GetItemCount());
example_shown_->RemoveAllChildViews(false);
@@ -126,61 +196,6 @@ class ExamplesWindowContents : public WidgetDelegateView,
Layout();
}
- // Creates the layout within the examples window.
- void InitExamplesWindow() {
- AddExamples();
-
- set_background(Background::CreateStandardPanelBackground());
- GridLayout* layout = new GridLayout(this);
- SetLayoutManager(layout);
- ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddPaddingColumn(0, 5);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- column_set->AddPaddingColumn(0, 5);
- layout->AddPaddingRow(0, 5);
- layout->StartRow(0 /* no expand */, 0);
- layout->AddView(combobox_);
-
- if (combobox_model_.GetItemCount() > 0) {
- layout->StartRow(1, 0);
- example_shown_->SetLayoutManager(new FillLayout());
- example_shown_->AddChildView(combobox_model_.GetItemViewAt(0));
- layout->AddView(example_shown_);
- }
-
- layout->StartRow(0 /* no expand */, 0);
- layout->AddView(status_label_);
- layout->AddPaddingRow(0, 5);
- }
-
- // Adds all the individual examples to the combobox model.
- void AddExamples() {
- // Please keep this list in alphabetical order!
- combobox_model_.AddExample(new BubbleExample);
- combobox_model_.AddExample(new ButtonExample);
- combobox_model_.AddExample(new CheckboxExample);
- combobox_model_.AddExample(new ComboboxExample);
- combobox_model_.AddExample(new DoubleSplitViewExample);
- combobox_model_.AddExample(new LabelExample);
- combobox_model_.AddExample(new LinkExample);
- combobox_model_.AddExample(new MenuExample);
- combobox_model_.AddExample(new MessageBoxExample);
- combobox_model_.AddExample(new MultilineExample);
- combobox_model_.AddExample(new ProgressBarExample);
- combobox_model_.AddExample(new RadioButtonExample);
- combobox_model_.AddExample(new ScrollViewExample);
- combobox_model_.AddExample(new SingleSplitViewExample);
- combobox_model_.AddExample(new SliderExample);
- combobox_model_.AddExample(new TabbedPaneExample);
- combobox_model_.AddExample(new TableExample);
- combobox_model_.AddExample(new TextExample);
- combobox_model_.AddExample(new TextfieldExample);
- combobox_model_.AddExample(new ThrobberExample);
- combobox_model_.AddExample(new TreeViewExample);
- combobox_model_.AddExample(new WidgetExample);
- }
-
static ExamplesWindowContents* instance_;
ComboboxModelExampleList combobox_model_;
Combobox* combobox_;
@@ -194,12 +209,21 @@ class ExamplesWindowContents : public WidgetDelegateView,
// static
ExamplesWindowContents* ExamplesWindowContents::instance_ = NULL;
-void ShowExamplesWindow(Operation operation) {
+void ShowExamplesWindow(Operation operation,
+ gfx::NativeView window_context,
+ ScopedExamples extra_examples) {
if (ExamplesWindowContents::instance()) {
ExamplesWindowContents::instance()->GetWidget()->Activate();
} else {
- Widget::CreateWindowWithBounds(new ExamplesWindowContents(operation),
- gfx::Rect(0, 0, 850, 300))->Show();
+ ScopedExamples examples(GetExamplesToShow(extra_examples.Pass()));
+ Widget* widget = new Widget;
+ Widget::InitParams params;
+ params.delegate = new ExamplesWindowContents(operation, examples.Pass());
+ params.context = window_context;
+ params.bounds = gfx::Rect(0, 0, 850, 300);
+ params.remove_standard_frame = true;
+ widget->Init(params);
+ widget->Show();
}
}
diff --git a/chromium/ui/views/examples/examples_window.h b/chromium/ui/views/examples/examples_window.h
index 94139db4d09..89222ef84a0 100644
--- a/chromium/ui/views/examples/examples_window.h
+++ b/chromium/ui/views/examples/examples_window.h
@@ -5,18 +5,32 @@
#ifndef UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_H_
#define UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_H_
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/views/examples/views_examples_export.h"
+namespace aura {
+class Window;
+}
+
namespace views {
namespace examples {
+class ExampleBase;
+
enum Operation {
DO_NOTHING_ON_CLOSE = 0,
QUIT_ON_CLOSE,
};
-// Shows a window with the views examples in it.
-VIEWS_EXAMPLES_EXPORT void ShowExamplesWindow(Operation operation);
+// Shows a window with the views examples in it. |extra_examples| contains any
+// additional examples to add. |window_context| is used to determine where the
+// window should be created (see |Widget::InitParams::context| for details).
+VIEWS_EXAMPLES_EXPORT void ShowExamplesWindow(
+ Operation operation,
+ gfx::NativeView window_context,
+ scoped_ptr<ScopedVector<ExampleBase> > extra_examples);
} // namespace examples
} // namespace views
diff --git a/chromium/ui/views/examples/examples_window_with_content.cc b/chromium/ui/views/examples/examples_window_with_content.cc
index 3e4e4bd357f..66342ca0e5b 100644
--- a/chromium/ui/views/examples/examples_window_with_content.cc
+++ b/chromium/ui/views/examples/examples_window_with_content.cc
@@ -4,221 +4,19 @@
#include "ui/views/examples/examples_window_with_content.h"
-#include <string>
-
-#include "base/memory/scoped_vector.h"
-#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_context.h"
-#include "ui/base/models/combobox_model.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/examples/bubble_example.h"
-#include "ui/views/examples/button_example.h"
-#include "ui/views/examples/checkbox_example.h"
-#include "ui/views/examples/combobox_example.h"
-#include "ui/views/examples/double_split_view_example.h"
-#include "ui/views/examples/label_example.h"
-#include "ui/views/examples/link_example.h"
-#include "ui/views/examples/menu_example.h"
-#include "ui/views/examples/message_box_example.h"
-#include "ui/views/examples/multiline_example.h"
-#include "ui/views/examples/progress_bar_example.h"
-#include "ui/views/examples/radio_button_example.h"
-#include "ui/views/examples/scroll_view_example.h"
-#include "ui/views/examples/single_split_view_example.h"
-#include "ui/views/examples/slider_example.h"
-#include "ui/views/examples/tabbed_pane_example.h"
-#include "ui/views/examples/table_example.h"
-#include "ui/views/examples/text_example.h"
-#include "ui/views/examples/textfield_example.h"
-#include "ui/views/examples/throbber_example.h"
-#include "ui/views/examples/tree_view_example.h"
#include "ui/views/examples/webview_example.h"
-#include "ui/views/examples/widget_example.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/grid_layout.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
namespace views {
namespace examples {
-// Model for the examples that are being added via AddExample().
-class ComboboxModelExampleList : public ui::ComboboxModel {
- public:
- ComboboxModelExampleList() {}
- virtual ~ComboboxModelExampleList() {}
-
- // Overridden from ui::ComboboxModel:
- virtual int GetItemCount() const OVERRIDE { return example_list_.size(); }
- virtual string16 GetItemAt(int index) OVERRIDE {
- return UTF8ToUTF16(example_list_[index]->example_title());
- }
-
- View* GetItemViewAt(int index) {
- return example_list_[index]->example_view();
- }
-
- void AddExample(ExampleBase* example) {
- example_list_.push_back(example);
- }
-
- private:
- ScopedVector<ExampleBase> example_list_;
-
- DISALLOW_COPY_AND_ASSIGN(ComboboxModelExampleList);
-};
-
-class ExamplesWindowContents : public WidgetDelegateView,
- public ComboboxListener {
- public:
- ExamplesWindowContents(Operation operation,
- content::BrowserContext* browser_context)
- : combobox_(new Combobox(&combobox_model_)),
- example_shown_(new View),
- status_label_(new Label),
- operation_(operation),
- browser_context_(browser_context) {
- instance_ = this;
- combobox_->set_listener(this);
- }
- virtual ~ExamplesWindowContents() {
- // Delete |combobox_| first as it references |combobox_model_|.
- delete combobox_;
- combobox_ = NULL;
- }
-
- // Prints a message in the status area, at the bottom of the window.
- void SetStatus(const std::string& status) {
- status_label_->SetText(UTF8ToUTF16(status));
- }
-
- static ExamplesWindowContents* instance() { return instance_; }
-
- private:
- // Overridden from WidgetDelegateView:
- virtual bool CanResize() const OVERRIDE { return true; }
- virtual bool CanMaximize() const OVERRIDE { return true; }
- virtual string16 GetWindowTitle() const OVERRIDE {
- return ASCIIToUTF16("Views Examples");
- }
- virtual View* GetContentsView() OVERRIDE { return this; }
- virtual void WindowClosing() OVERRIDE {
- instance_ = NULL;
- if (operation_ == QUIT_ON_CLOSE)
- base::MessageLoopForUI::current()->Quit();
- }
-
- // Overridden from View:
- virtual void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) OVERRIDE {
- if (details.is_add && details.child == this)
- InitExamplesWindow();
- }
-
- // Overridden from ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE {
- DCHECK_EQ(combobox, combobox_);
- DCHECK(combobox->selected_index() < combobox_model_.GetItemCount());
- example_shown_->RemoveAllChildViews(false);
- example_shown_->AddChildView(combobox_model_.GetItemViewAt(
- combobox->selected_index()));
- SetStatus(std::string());
- Layout();
- SchedulePaint();
- }
-
- // Creates the layout within the examples window.
- void InitExamplesWindow() {
- AddExamples();
-
- set_background(Background::CreateStandardPanelBackground());
- GridLayout* layout = new GridLayout(this);
- SetLayoutManager(layout);
- ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddPaddingColumn(0, 5);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- column_set->AddPaddingColumn(0, 5);
- layout->AddPaddingRow(0, 5);
- layout->StartRow(0 /* no expand */, 0);
- layout->AddView(combobox_);
-
- if (combobox_model_.GetItemCount() > 0) {
- layout->StartRow(1, 0);
- example_shown_->SetLayoutManager(new FillLayout());
- example_shown_->AddChildView(combobox_model_.GetItemViewAt(0));
- layout->AddView(example_shown_);
- }
-
- layout->StartRow(0 /* no expand */, 0);
- layout->AddView(status_label_);
- layout->AddPaddingRow(0, 5);
- }
-
- // Adds all the individual examples to the combobox model.
- void AddExamples() {
- // Please keep this list in alphabetical order!
- combobox_model_.AddExample(new BubbleExample);
- combobox_model_.AddExample(new ButtonExample);
- combobox_model_.AddExample(new CheckboxExample);
- combobox_model_.AddExample(new ComboboxExample);
- combobox_model_.AddExample(new DoubleSplitViewExample);
- combobox_model_.AddExample(new LabelExample);
- combobox_model_.AddExample(new LinkExample);
- combobox_model_.AddExample(new MenuExample);
- combobox_model_.AddExample(new MessageBoxExample);
- combobox_model_.AddExample(new MultilineExample);
- combobox_model_.AddExample(new ProgressBarExample);
- combobox_model_.AddExample(new RadioButtonExample);
- combobox_model_.AddExample(new ScrollViewExample);
- combobox_model_.AddExample(new SingleSplitViewExample);
- combobox_model_.AddExample(new SliderExample);
- combobox_model_.AddExample(new TabbedPaneExample);
- combobox_model_.AddExample(new TableExample);
- combobox_model_.AddExample(new TextExample);
- combobox_model_.AddExample(new TextfieldExample);
- combobox_model_.AddExample(new ThrobberExample);
- combobox_model_.AddExample(new TreeViewExample);
- combobox_model_.AddExample(new WebViewExample(browser_context_));
- combobox_model_.AddExample(new WidgetExample);
- }
-
- static ExamplesWindowContents* instance_;
- ComboboxModelExampleList combobox_model_;
- Combobox* combobox_;
- View* example_shown_;
- Label* status_label_;
- const Operation operation_;
- content::BrowserContext* browser_context_;
-
- DISALLOW_COPY_AND_ASSIGN(ExamplesWindowContents);
-};
-
-// static
-ExamplesWindowContents* ExamplesWindowContents::instance_ = NULL;
-
void ShowExamplesWindowWithContent(Operation operation,
content::BrowserContext* browser_context,
gfx::NativeView window_context) {
- if (ExamplesWindowContents::instance()) {
- ExamplesWindowContents::instance()->GetWidget()->Activate();
- } else {
- Widget* widget = new Widget;
- Widget::InitParams params;
- params.delegate = new ExamplesWindowContents(operation, browser_context);
- params.context = window_context;
- params.bounds = gfx::Rect(0, 0, 850, 300);
- params.top_level = true;
- widget->Init(params);
- widget->Show();
- }
-}
-
-void LogStatus(const std::string& string) {
- ExamplesWindowContents::instance()->SetStatus(string);
+ scoped_ptr<ScopedVector<ExampleBase> > extra_examples(
+ new ScopedVector<ExampleBase>);
+ extra_examples->push_back(new WebViewExample(browser_context));
+ ShowExamplesWindow(operation, window_context, extra_examples.Pass());
}
} // namespace examples
diff --git a/chromium/ui/views/examples/examples_window_with_content.h b/chromium/ui/views/examples/examples_window_with_content.h
index 907d3075a28..407fd2eeb7e 100644
--- a/chromium/ui/views/examples/examples_window_with_content.h
+++ b/chromium/ui/views/examples/examples_window_with_content.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_WITH_CONTENT_H_
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/examples/examples_window.h"
#include "ui/views/examples/views_examples_with_content_export.h"
namespace content {
@@ -15,11 +16,6 @@ class BrowserContext;
namespace views {
namespace examples {
-enum Operation {
- DO_NOTHING_ON_CLOSE = 0,
- QUIT_ON_CLOSE,
-};
-
// Shows a window with the views examples in it.
VIEWS_EXAMPLES_WITH_CONTENT_EXPORT void ShowExamplesWindowWithContent(
Operation operation,
diff --git a/chromium/ui/views/examples/examples_with_content_main_exe.cc b/chromium/ui/views/examples/examples_with_content_main_exe.cc
new file mode 100644
index 00000000000..8df1dec30ab
--- /dev/null
+++ b/chromium/ui/views/examples/examples_with_content_main_exe.cc
@@ -0,0 +1,49 @@
+// 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 "base/bind.h"
+#include "content/public/browser/browser_context.h"
+#include "ui/views/examples/examples_window_with_content.h"
+#include "ui/views_content_client/views_content_client.h"
+
+#if defined(OS_WIN)
+#include "content/public/app/startup_helper_win.h"
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+namespace {
+
+void ShowContentExampleWindow(content::BrowserContext* browser_context,
+ gfx::NativeView window_context) {
+ views::examples::ShowExamplesWindowWithContent(views::examples::QUIT_ON_CLOSE,
+ browser_context,
+ window_context);
+
+ // These lines serve no purpose other than to introduce an explicit content
+ // dependency. If the main executable doesn't have this dependency, the linker
+ // has more flexibility to reorder library dependencies in a shared component
+ // build. On linux, this can cause libc to appear before libcontent in the
+ // dlsym search path, which breaks (usually valid) assumptions made in
+ // sandbox::InitLibcUrandomOverrides(). See http://crbug.com/374712.
+ if (!browser_context) {
+ content::BrowserContext::SaveSessionState(NULL);
+ NOTREACHED();
+ }
+}
+
+} // namespace
+
+#if defined(OS_WIN)
+int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
+ sandbox::SandboxInterfaceInfo sandbox_info = {0};
+ content::InitializeSandboxInfo(&sandbox_info);
+ ui::ViewsContentClient views_content_client(instance, &sandbox_info);
+#else
+int main(int argc, const char** argv) {
+ ui::ViewsContentClient views_content_client(argc, argv);
+#endif
+
+ views_content_client.set_task(base::Bind(&ShowContentExampleWindow));
+ return views_content_client.RunMain();
+}
diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc
index d970bf1a2d5..4dea806e4d4 100644
--- a/chromium/ui/views/examples/label_example.cc
+++ b/chromium/ui/views/examples/label_example.cc
@@ -10,6 +10,9 @@
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+using base::WideToUTF16;
+
namespace views {
namespace examples {
@@ -18,24 +21,20 @@ namespace {
// A Label with a constrained preferred size to demonstrate eliding or wrapping.
class PreferredSizeLabel : public Label {
public:
- PreferredSizeLabel();
- virtual ~PreferredSizeLabel();
+ PreferredSizeLabel() : Label() {
+ SetBorder(Border::CreateSolidBorder(2, SK_ColorCYAN));
+ }
+ virtual ~PreferredSizeLabel() {}
- // Overridden from Label:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ // Label:
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
+ return gfx::Size(100, 40);
+ }
private:
DISALLOW_COPY_AND_ASSIGN(PreferredSizeLabel);
};
-PreferredSizeLabel::PreferredSizeLabel() : Label() {
- set_border(Border::CreateSolidBorder(2, SK_ColorCYAN));
-}
-
-PreferredSizeLabel::~PreferredSizeLabel() {}
-
-gfx::Size PreferredSizeLabel::GetPreferredSize() { return gfx::Size(100, 40); }
-
} // namespace
LabelExample::LabelExample() : ExampleBase("Label") {}
@@ -63,10 +62,12 @@ void LabelExample::CreateExampleView(View* container) {
label->SetEnabledColor(SK_ColorBLUE);
container->AddChildView(label);
- label = new Label(ASCIIToUTF16("A Courier-18 label with a shadow."));
- label->SetFont(gfx::Font("Courier", 18));
- label->SetShadowColors(SK_ColorGRAY, SK_ColorLTGRAY);
- label->SetShadowOffset(1, 1);
+ label = new Label(ASCIIToUTF16("A Courier-18 label with shadows."));
+ label->SetFontList(gfx::FontList("Courier, 18px"));
+ gfx::ShadowValues shadows(1, gfx::ShadowValue(gfx::Point(), 1, SK_ColorRED));
+ gfx::ShadowValue shadow(gfx::Point(2, 2), 0, SK_ColorGRAY);
+ shadows.push_back(shadow);
+ label->set_shadows(shadows);
container->AddChildView(label);
label = new PreferredSizeLabel();
@@ -75,10 +76,20 @@ void LabelExample::CreateExampleView(View* container) {
container->AddChildView(label);
label = new PreferredSizeLabel();
+ label->SetElideBehavior(gfx::FADE_TAIL);
+ label->SetText(ASCIIToUTF16("Some long labels will fade, rather than elide, "
+ "if the text's width exceeds the label's available width."));
+ container->AddChildView(label);
+
+ label = new PreferredSizeLabel();
label->SetText(ASCIIToUTF16("A multi-line label will wrap onto subsequent "
"lines if the text's width exceeds the label's available width."));
label->SetMultiLine(true);
container->AddChildView(label);
+
+ label = new Label(WideToUTF16(L"Password!"));
+ label->SetObscured(true);
+ container->AddChildView(label);
}
} // namespace examples
diff --git a/chromium/ui/views/examples/label_example.h b/chromium/ui/views/examples/label_example.h
index 0f7eeae92f1..8b7cfe782f5 100644
--- a/chromium/ui/views/examples/label_example.h
+++ b/chromium/ui/views/examples/label_example.h
@@ -5,19 +5,18 @@
#ifndef UI_VIEWS_EXAMPLES_LABEL_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_LABEL_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/examples/example_base.h"
namespace views {
namespace examples {
-class LabelExample : public ExampleBase {
+class VIEWS_EXAMPLES_EXPORT LabelExample : public ExampleBase {
public:
LabelExample();
virtual ~LabelExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
diff --git a/chromium/ui/views/examples/link_example.cc b/chromium/ui/views/examples/link_example.cc
index a28c5d579e5..3795c8c9832 100644
--- a/chromium/ui/views/examples/link_example.cc
+++ b/chromium/ui/views/examples/link_example.cc
@@ -19,7 +19,7 @@ LinkExample::~LinkExample() {
}
void LinkExample::CreateExampleView(View* container) {
- link_ = new Link(ASCIIToUTF16("Click me!"));
+ link_ = new Link(base::ASCIIToUTF16("Click me!"));
link_->set_listener(this);
container->SetLayoutManager(new FillLayout);
diff --git a/chromium/ui/views/examples/link_example.h b/chromium/ui/views/examples/link_example.h
index ac969c43a0c..fd6e9245318 100644
--- a/chromium/ui/views/examples/link_example.h
+++ b/chromium/ui/views/examples/link_example.h
@@ -5,24 +5,24 @@
#ifndef UI_VIEWS_EXAMPLES_LINK_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_LINK_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/link_listener.h"
#include "ui/views/examples/example_base.h"
namespace views {
namespace examples {
-class LinkExample : public ExampleBase, public LinkListener {
+class VIEWS_EXAMPLES_EXPORT LinkExample : public ExampleBase,
+ public LinkListener {
public:
LinkExample();
virtual ~LinkExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from LinkListener:
+ // LinkListener:
virtual void LinkClicked(Link* source, int event_flags) OVERRIDE;
Link* link_;
diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc
index 307a6ca794e..742cfffa4b2 100644
--- a/chromium/ui/views/examples/menu_example.cc
+++ b/chromium/ui/views/examples/menu_example.cc
@@ -15,6 +15,8 @@
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -25,7 +27,7 @@ class ExampleMenuModel : public ui::SimpleMenuModel,
public:
ExampleMenuModel();
- // Overridden from ui::SimpleMenuModel::Delegate:
+ // ui::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
virtual bool GetAcceleratorForCommandId(
@@ -58,11 +60,11 @@ class ExampleMenuModel : public ui::SimpleMenuModel,
class ExampleMenuButton : public MenuButton, public MenuButtonListener {
public:
- explicit ExampleMenuButton(const string16& test);
+ explicit ExampleMenuButton(const base::string16& test);
virtual ~ExampleMenuButton();
private:
- // Overridden from MenuButtonListener:
+ // MenuButtonListener:
virtual void OnMenuButtonClicked(View* source,
const gfx::Point& point) OVERRIDE;
@@ -126,24 +128,24 @@ bool ExampleMenuModel::GetAcceleratorForCommandId(
void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) {
case COMMAND_DO_SOMETHING: {
- LOG(INFO) << "Done something";
+ VLOG(0) << "Done something";
break;
}
// Radio items.
case COMMAND_SELECT_ASCII: {
current_encoding_command_id_ = COMMAND_SELECT_ASCII;
- LOG(INFO) << "Selected ASCII";
+ VLOG(0) << "Selected ASCII";
break;
}
case COMMAND_SELECT_UTF8: {
current_encoding_command_id_ = COMMAND_SELECT_UTF8;
- LOG(INFO) << "Selected UTF-8";
+ VLOG(0) << "Selected UTF-8";
break;
}
case COMMAND_SELECT_UTF16: {
current_encoding_command_id_ = COMMAND_SELECT_UTF16;
- LOG(INFO) << "Selected UTF-16";
+ VLOG(0) << "Selected UTF-16";
break;
}
@@ -176,7 +178,7 @@ void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
// ExampleMenuButton -----------------------------------------------------------
-ExampleMenuButton::ExampleMenuButton(const string16& test)
+ExampleMenuButton::ExampleMenuButton(const base::string16& test)
: MenuButton(NULL, test, this, true) {
}
@@ -187,11 +189,15 @@ void ExampleMenuButton::OnMenuButtonClicked(View* source,
const gfx::Point& point) {
menu_runner_.reset(new MenuRunner(GetMenuModel()));
- if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), this,
- gfx::Rect(point, gfx::Size()), MenuItemView::TOPRIGHT,
- ui::MENU_SOURCE_NONE, MenuRunner::HAS_MNEMONICS) ==
- MenuRunner::MENU_DELETED)
+ if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
+ this,
+ gfx::Rect(point, gfx::Size()),
+ MENU_ANCHOR_TOPRIGHT,
+ ui::MENU_SOURCE_NONE,
+ MenuRunner::HAS_MNEMONICS) ==
+ MenuRunner::MENU_DELETED) {
return;
+ }
}
ui::SimpleMenuModel* ExampleMenuButton::GetMenuModel() {
diff --git a/chromium/ui/views/examples/menu_example.h b/chromium/ui/views/examples/menu_example.h
index 40c9b23d6e0..3ed5d37e7a4 100644
--- a/chromium/ui/views/examples/menu_example.h
+++ b/chromium/ui/views/examples/menu_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_MENU_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_MENU_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/examples/example_base.h"
namespace views {
@@ -14,12 +13,12 @@ namespace examples {
// MenuExample demonstrates how to use the MenuModelAdapter and MenuRunner
// classes.
-class MenuExample : public ExampleBase {
+class VIEWS_EXAMPLES_EXPORT MenuExample : public ExampleBase {
public:
MenuExample();
virtual ~MenuExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
diff --git a/chromium/ui/views/examples/message_box_example.cc b/chromium/ui/views/examples/message_box_example.cc
index 2563525f325..cb9e924fbf6 100644
--- a/chromium/ui/views/examples/message_box_example.cc
+++ b/chromium/ui/views/examples/message_box_example.cc
@@ -10,6 +10,8 @@
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
diff --git a/chromium/ui/views/examples/message_box_example.h b/chromium/ui/views/examples/message_box_example.h
index 4d5277805eb..692ae22255a 100644
--- a/chromium/ui/views/examples/message_box_example.h
+++ b/chromium/ui/views/examples/message_box_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/examples/example_base.h"
@@ -18,16 +17,17 @@ class MessageBoxView;
namespace examples {
// A MessageBoxView example. This tests some of checkbox features as well.
-class MessageBoxExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT MessageBoxExample : public ExampleBase,
+ public ButtonListener {
public:
MessageBoxExample();
virtual ~MessageBoxExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
// The MessageBoxView to be tested.
diff --git a/chromium/ui/views/examples/multiline_example.cc b/chromium/ui/views/examples/multiline_example.cc
index b1923846386..e0a3b152b54 100644
--- a/chromium/ui/views/examples/multiline_example.cc
+++ b/chromium/ui/views/examples/multiline_example.cc
@@ -9,14 +9,27 @@
#include "ui/gfx/render_text.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
+#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
+namespace {
+
+gfx::Range ClampRange(gfx::Range range, size_t max) {
+ range.set_start(std::min(range.start(), max));
+ range.set_end(std::min(range.end(), max));
+ return range;
+}
+
+} // namespace
+
// A simple View that hosts a RenderText object.
class MultilineExample::RenderTextView : public View {
public:
@@ -24,7 +37,7 @@ class MultilineExample::RenderTextView : public View {
render_text_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
render_text_->SetColor(SK_ColorBLACK);
render_text_->SetMultiline(true);
- set_border(Border::CreateSolidBorder(2, SK_ColorGRAY));
+ SetBorder(Border::CreateSolidBorder(2, SK_ColorGRAY));
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
@@ -32,7 +45,7 @@ class MultilineExample::RenderTextView : public View {
render_text_->Draw(canvas);
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
// Turn off multiline mode to get the single-line text size, which is the
// preferred size for this view.
render_text_->SetMultiline(false);
@@ -43,7 +56,7 @@ class MultilineExample::RenderTextView : public View {
return size;
}
- virtual int GetHeightForWidth(int w) OVERRIDE {
+ virtual int GetHeightForWidth(int w) const OVERRIDE {
// TODO(ckocagil): Why does this happen?
if (w == 0)
return View::GetHeightForWidth(w);
@@ -56,19 +69,22 @@ class MultilineExample::RenderTextView : public View {
return height;
}
- void SetText(const string16& new_contents) {
+ void SetText(const base::string16& new_contents) {
// Color and style the text inside |test_range| to test colors and styles.
- gfx::Range test_range(1, 21);
- test_range.set_start(std::min(test_range.start(), new_contents.length()));
- test_range.set_end(std::min(test_range.end(), new_contents.length()));
+ const size_t range_max = new_contents.length();
+ gfx::Range color_range = ClampRange(gfx::Range(1, 21), range_max);
+ gfx::Range bold_range = ClampRange(gfx::Range(4, 10), range_max);
+ gfx::Range italic_range = ClampRange(gfx::Range(7, 13), range_max);
render_text_->SetText(new_contents);
render_text_->SetColor(SK_ColorBLACK);
- render_text_->ApplyColor(0xFFFF0000, test_range);
+ render_text_->ApplyColor(0xFFFF0000, color_range);
render_text_->SetStyle(gfx::DIAGONAL_STRIKE, false);
- render_text_->ApplyStyle(gfx::DIAGONAL_STRIKE, true, test_range);
+ render_text_->ApplyStyle(gfx::DIAGONAL_STRIKE, true, color_range);
render_text_->SetStyle(gfx::UNDERLINE, false);
- render_text_->ApplyStyle(gfx::UNDERLINE, true, test_range);
+ render_text_->ApplyStyle(gfx::UNDERLINE, true, color_range);
+ render_text_->ApplyStyle(gfx::BOLD, true, bold_range);
+ render_text_->ApplyStyle(gfx::ITALIC, true, italic_range);
InvalidateLayout();
}
@@ -96,16 +112,17 @@ MultilineExample::~MultilineExample() {
}
void MultilineExample::CreateExampleView(View* container) {
- const char kTestString[] = "test string asdf 1234 test string asdf 1234 "
- "test string asdf 1234 test string asdf 1234";
+ const base::string16 kTestString = base::WideToUTF16(L"qwerty"
+ L"\x627\x644\x631\x626\x64A\x633\x64A\x629"
+ L"asdfgh");
render_text_view_ = new RenderTextView();
- render_text_view_->SetText(ASCIIToUTF16(kTestString));
+ render_text_view_->SetText(kTestString);
label_ = new Label();
- label_->SetText(ASCIIToUTF16(kTestString));
+ label_->SetText(kTestString);
label_->SetMultiLine(true);
- label_->set_border(Border::CreateSolidBorder(2, SK_ColorCYAN));
+ label_->SetBorder(Border::CreateSolidBorder(2, SK_ColorCYAN));
label_checkbox_ = new Checkbox(ASCIIToUTF16("views::Label:"));
label_checkbox_->SetChecked(true);
@@ -113,8 +130,8 @@ void MultilineExample::CreateExampleView(View* container) {
label_checkbox_->set_request_focus_on_press(false);
textfield_ = new Textfield();
- textfield_->SetController(this);
- textfield_->SetText(ASCIIToUTF16(kTestString));
+ textfield_->set_controller(this);
+ textfield_->SetText(kTestString);
GridLayout* layout = new GridLayout(container);
container->SetLayoutManager(layout);
@@ -139,7 +156,7 @@ void MultilineExample::CreateExampleView(View* container) {
}
void MultilineExample::ContentsChanged(Textfield* sender,
- const string16& new_contents) {
+ const base::string16& new_contents) {
render_text_view_->SetText(new_contents);
if (label_checkbox_->checked())
label_->SetText(new_contents);
@@ -154,7 +171,8 @@ bool MultilineExample::HandleKeyEvent(Textfield* sender,
void MultilineExample::ButtonPressed(Button* sender, const ui::Event& event) {
DCHECK_EQ(sender, label_checkbox_);
- label_->SetText(label_checkbox_->checked() ? textfield_->text() : string16());
+ label_->SetText(label_checkbox_->checked() ? textfield_->text() :
+ base::string16());
container()->Layout();
container()->SchedulePaint();
}
diff --git a/chromium/ui/views/examples/multiline_example.h b/chromium/ui/views/examples/multiline_example.h
index 2757c4ac933..7231c66bce7 100644
--- a/chromium/ui/views/examples/multiline_example.h
+++ b/chromium/ui/views/examples/multiline_example.h
@@ -5,22 +5,22 @@
#ifndef UI_VIEWS_EXAMPLES_MULTILINE_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_MULTILINE_EXAMPLE_H_
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "ui/views/controls/button/checkbox.h"
+#include "base/macros.h"
+#include "ui/views/controls/button/button.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/examples/example_base.h"
namespace views {
+class Checkbox;
class Label;
namespace examples {
// An example that compares the multiline rendering of different controls.
-class MultilineExample : public ExampleBase,
- public TextfieldController,
- public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT MultilineExample : public ExampleBase,
+ public TextfieldController,
+ public ButtonListener {
public:
MultilineExample();
virtual ~MultilineExample();
@@ -36,7 +36,7 @@ class MultilineExample : public ExampleBase,
// TextfieldController:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE;
+ const base::string16& new_contents) OVERRIDE;
virtual bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) OVERRIDE;
diff --git a/chromium/ui/views/examples/progress_bar_example.cc b/chromium/ui/views/examples/progress_bar_example.cc
index ce29ecd0fa2..8a860f212af 100644
--- a/chromium/ui/views/examples/progress_bar_example.cc
+++ b/chromium/ui/views/examples/progress_bar_example.cc
@@ -51,11 +51,11 @@ void ProgressBarExample::CreateExampleView(View* container) {
0, GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
- minus_button_ = new LabelButton(this, ASCIIToUTF16("-"));
+ minus_button_ = new LabelButton(this, base::ASCIIToUTF16("-"));
layout->AddView(minus_button_);
progress_bar_ = new ProgressBar();
layout->AddView(progress_bar_);
- plus_button_ = new LabelButton(this, ASCIIToUTF16("+"));
+ plus_button_ = new LabelButton(this, base::ASCIIToUTF16("+"));
layout->AddView(plus_button_);
}
diff --git a/chromium/ui/views/examples/progress_bar_example.h b/chromium/ui/views/examples/progress_bar_example.h
index 92d0e9f1670..8533b7ac3cb 100644
--- a/chromium/ui/views/examples/progress_bar_example.h
+++ b/chromium/ui/views/examples/progress_bar_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_PROGRESS_BAR_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_PROGRESS_BAR_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/examples/example_base.h"
@@ -15,16 +14,17 @@ class ProgressBar;
namespace examples {
-class ProgressBarExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT ProgressBarExample : public ExampleBase,
+ public ButtonListener {
public:
ProgressBarExample();
virtual ~ProgressBarExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* button, const ui::Event& event) OVERRIDE;
Button* minus_button_;
diff --git a/chromium/ui/views/examples/radio_button_example.cc b/chromium/ui/views/examples/radio_button_example.cc
index 72a844e0f5f..5e3c7dd4a3c 100644
--- a/chromium/ui/views/examples/radio_button_example.cc
+++ b/chromium/ui/views/examples/radio_button_example.cc
@@ -23,13 +23,13 @@ RadioButtonExample::~RadioButtonExample() {
}
void RadioButtonExample::CreateExampleView(View* container) {
- select_ = new LabelButton(this, ASCIIToUTF16("Select"));
- status_ = new LabelButton(this, ASCIIToUTF16("Show Status"));
+ select_ = new LabelButton(this, base::ASCIIToUTF16("Select"));
+ status_ = new LabelButton(this, base::ASCIIToUTF16("Show Status"));
int group = 1;
for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
radio_buttons_[i] = new RadioButton(
- UTF8ToUTF16(base::StringPrintf(
+ base::UTF8ToUTF16(base::StringPrintf(
"Radio %d in group %d", static_cast<int>(i) + 1, group)),
group);
radio_buttons_[i]->set_listener(this);
diff --git a/chromium/ui/views/examples/radio_button_example.h b/chromium/ui/views/examples/radio_button_example.h
index ed8ddf4cf99..cc1452215e0 100644
--- a/chromium/ui/views/examples/radio_button_example.h
+++ b/chromium/ui/views/examples/radio_button_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/examples/example_base.h"
@@ -19,16 +18,17 @@ class RadioButton;
namespace examples {
-class RadioButtonExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT RadioButtonExample : public ExampleBase,
+ public ButtonListener {
public:
RadioButtonExample();
virtual ~RadioButtonExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
// Group of 3 radio buttons.
diff --git a/chromium/ui/views/examples/scroll_view_example.cc b/chromium/ui/views/examples/scroll_view_example.cc
index 38b18fc5e7f..127442fb7df 100644
--- a/chromium/ui/views/examples/scroll_view_example.cc
+++ b/chromium/ui/views/examples/scroll_view_example.cc
@@ -12,6 +12,8 @@
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -25,7 +27,7 @@ class ScrollViewExample::ScrollableView : public View {
AddChildView(new RadioButton(ASCIIToUTF16("Radio Button"), 0));
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return gfx::Size(width(), height());
}
diff --git a/chromium/ui/views/examples/scroll_view_example.h b/chromium/ui/views/examples/scroll_view_example.h
index e180bc0b4b5..d850b01df4e 100644
--- a/chromium/ui/views/examples/scroll_view_example.h
+++ b/chromium/ui/views/examples/scroll_view_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/examples/example_base.h"
@@ -19,16 +18,17 @@ class LabelButton;
namespace examples {
-class ScrollViewExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT ScrollViewExample : public ExampleBase,
+ public ButtonListener {
public:
ScrollViewExample();
virtual ~ScrollViewExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
// Control buttons to change the size of scrollable and jump to
diff --git a/chromium/ui/views/examples/single_split_view_example.cc b/chromium/ui/views/examples/single_split_view_example.cc
index 97fb36b7980..7e390b51064 100644
--- a/chromium/ui/views/examples/single_split_view_example.cc
+++ b/chromium/ui/views/examples/single_split_view_example.cc
@@ -21,9 +21,9 @@ class SplittedView : public View {
void SetColor(SkColor from, SkColor to);
private:
- // Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ // View:
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(SplittedView);
@@ -40,11 +40,11 @@ void SplittedView::SetColor(SkColor from, SkColor to) {
set_background(Background::CreateVerticalGradientBackground(from, to));
}
-gfx::Size SplittedView::GetPreferredSize() {
+gfx::Size SplittedView::GetPreferredSize() const {
return gfx::Size(width(), height());
}
-gfx::Size SplittedView::GetMinimumSize() {
+gfx::Size SplittedView::GetMinimumSize() const {
return gfx::Size(10, 10);
}
diff --git a/chromium/ui/views/examples/single_split_view_example.h b/chromium/ui/views/examples/single_split_view_example.h
index 0c157cc87b9..603482c2288 100644
--- a/chromium/ui/views/examples/single_split_view_example.h
+++ b/chromium/ui/views/examples/single_split_view_example.h
@@ -5,24 +5,25 @@
#ifndef UI_VIEWS_EXAMPLES_SINGLE_SPLIT_VIEW_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_SINGLE_SPLIT_VIEW_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/single_split_view_listener.h"
#include "ui/views/examples/example_base.h"
namespace views {
namespace examples {
-class SingleSplitViewExample : public ExampleBase,
- public SingleSplitViewListener {
+class VIEWS_EXAMPLES_EXPORT SingleSplitViewExample
+ : public ExampleBase,
+ public SingleSplitViewListener {
public:
SingleSplitViewExample();
virtual ~SingleSplitViewExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
+ // SingleSplitViewListener:
virtual bool SplitHandleMoved(SingleSplitView* sender) OVERRIDE;
SingleSplitView* single_split_view_;
diff --git a/chromium/ui/views/examples/slider_example.cc b/chromium/ui/views/examples/slider_example.cc
index 8ae4d6bc423..89f78568e23 100644
--- a/chromium/ui/views/examples/slider_example.cc
+++ b/chromium/ui/views/examples/slider_example.cc
@@ -37,7 +37,7 @@ void SliderExample::SliderValueChanged(Slider* sender,
float value,
float old_value,
SliderChangeReason reason) {
- label_->SetText(ASCIIToUTF16(base::StringPrintf("%.3lf", value)));
+ label_->SetText(base::ASCIIToUTF16(base::StringPrintf("%.3lf", value)));
}
} // namespace examples
diff --git a/chromium/ui/views/examples/slider_example.h b/chromium/ui/views/examples/slider_example.h
index 8e909394467..32950f9ad36 100644
--- a/chromium/ui/views/examples/slider_example.h
+++ b/chromium/ui/views/examples/slider_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_SLIDER_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_SLIDER_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/slider.h"
#include "ui/views/examples/example_base.h"
@@ -15,16 +14,17 @@ class Label;
namespace examples {
-class SliderExample : public ExampleBase, public SliderListener {
+class VIEWS_EXAMPLES_EXPORT SliderExample : public ExampleBase,
+ public SliderListener {
public:
SliderExample();
virtual ~SliderExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
- // Overridden from SliderListener:
+ // SliderListener:
virtual void SliderValueChanged(Slider* sender,
float value,
float old_value,
diff --git a/chromium/ui/views/examples/tabbed_pane_example.cc b/chromium/ui/views/examples/tabbed_pane_example.cc
index f0f6691ef87..087c77bf0df 100644
--- a/chromium/ui/views/examples/tabbed_pane_example.cc
+++ b/chromium/ui/views/examples/tabbed_pane_example.cc
@@ -9,6 +9,8 @@
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/layout/grid_layout.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -57,7 +59,7 @@ void TabbedPaneExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == add_) {
AddButton("Added");
} else if (sender == add_at_) {
- const string16 label = ASCIIToUTF16("Added at 1");
+ const base::string16 label = ASCIIToUTF16("Added at 1");
tabbed_pane_->AddTabAtIndex(1, label, new LabelButton(NULL, label));
} else if (sender == select_at_) {
if (tabbed_pane_->GetTabCount() > 1)
diff --git a/chromium/ui/views/examples/tabbed_pane_example.h b/chromium/ui/views/examples/tabbed_pane_example.h
index 9a198269294..f23f6b34d7f 100644
--- a/chromium/ui/views/examples/tabbed_pane_example.h
+++ b/chromium/ui/views/examples/tabbed_pane_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
#include "ui/views/examples/example_base.h"
@@ -19,9 +18,9 @@ class TabbedPane;
namespace examples {
// A TabbedPane example tests adding and selecting tabs.
-class TabbedPaneExample : public ExampleBase,
- public ButtonListener,
- public TabbedPaneListener {
+class VIEWS_EXAMPLES_EXPORT TabbedPaneExample : public ExampleBase,
+ public ButtonListener,
+ public TabbedPaneListener {
public:
TabbedPaneExample();
virtual ~TabbedPaneExample();
diff --git a/chromium/ui/views/examples/table_example.cc b/chromium/ui/views/examples/table_example.cc
index 87032c7160a..5c9eebfd2ed 100644
--- a/chromium/ui/views/examples/table_example.cc
+++ b/chromium/ui/views/examples/table_example.cc
@@ -14,6 +14,8 @@
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/layout/grid_layout.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -107,9 +109,9 @@ int TableExample::RowCount() {
return 10;
}
-string16 TableExample::GetText(int row, int column_id) {
+base::string16 TableExample::GetText(int row, int column_id) {
if (row == -1)
- return string16();
+ return base::string16();
const char* const cells[5][4] = {
{ "Orange", "Orange", "South america", "$5" },
@@ -143,14 +145,14 @@ void TableExample::GetGroupRange(int model_index, GroupRange* range) {
void TableExample::OnSelectionChanged() {
PrintStatus("Selected: %s",
- UTF16ToASCII(GetText(table_->selection_model().active(),
- 0)).c_str());
+ base::UTF16ToASCII(GetText(table_->selection_model().active(),
+ 0)).c_str());
}
void TableExample::OnDoubleClick() {
PrintStatus("Double Click: %s",
- UTF16ToASCII(GetText(table_->selection_model().active(),
- 0)).c_str());
+ base::UTF16ToASCII(GetText(table_->selection_model().active(),
+ 0)).c_str());
}
void TableExample::OnMiddleClick() {}
diff --git a/chromium/ui/views/examples/table_example.h b/chromium/ui/views/examples/table_example.h
index d715a107a2b..06ac3c01a68 100644
--- a/chromium/ui/views/examples/table_example.h
+++ b/chromium/ui/views/examples/table_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/models/table_model.h"
#include "ui/views/controls/button/button.h"
@@ -27,11 +26,11 @@ class TableView;
namespace examples {
-class TableExample : public ExampleBase,
- public ui::TableModel,
- public TableGrouper,
- public TableViewObserver,
- public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT TableExample : public ExampleBase,
+ public ui::TableModel,
+ public TableGrouper,
+ public TableViewObserver,
+ public ButtonListener {
public:
TableExample();
virtual ~TableExample();
@@ -41,7 +40,7 @@ class TableExample : public ExampleBase,
// ui::TableModel:
virtual int RowCount() OVERRIDE;
- virtual string16 GetText(int row, int column_id) OVERRIDE;
+ virtual base::string16 GetText(int row, int column_id) OVERRIDE;
virtual gfx::ImageSkia GetIcon(int row) OVERRIDE;
virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
diff --git a/chromium/ui/views/examples/text_example.cc b/chromium/ui/views/examples/text_example.cc
index ec43ac15b99..2682e73bd14 100644
--- a/chromium/ui/views/examples/text_example.cc
+++ b/chromium/ui/views/examples/text_example.cc
@@ -24,48 +24,31 @@ namespace {
// Number of columns in the view layout.
const int kNumColumns = 10;
-const char kShortText[] = "Batman";
-const char kMediumText[] = "The quick brown fox jumps over the lazy dog.";
+const char kShortText[] = "The quick brown fox jumps over the lazy dog.";
const char kLongText[] =
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
- "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
- "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
+ "commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate "
+ "velit esse cillum dolore eu fugiat nulla pariatur.\n\nExcepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
"mollit anim id est laborum.";
const char kAmpersandText[] =
"The quick && &brown fo&x jumps over the lazy dog.";
-const char kNewlineText[] =
- "The quick \nbrown fox jumps\n\n over the lazy dog.";
-
-const char* kTextExamples[] = {
- "Short",
- "Medium",
- "Long",
- "Ampersands",
- "Newlines",
-};
-
-const char* kElidingBehaviors[] = {
- "Ellipsis",
- "None",
- "Fade Tail",
- "Fade Head",
-};
-
-const char* kPrefixOptions[] = {
- "Default",
- "Show",
- "Hide",
-};
-
-const char* kHorizontalAligments[] = {
- "Default",
- "Left",
- "Center",
- "Right",
-};
+const wchar_t kRightToLeftText[] =
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd! "
+ L"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd!";
+
+const char* kTextExamples[] = { "Short", "Long", "Ampersands", "RTL Hebrew", };
+const char* kElideBehaviors[] = { "Elide", "Truncate", "Fade", };
+const char* kPrefixOptions[] = { "Default", "Show", "Hide", };
+const char* kHorizontalAligments[] = { "Default", "Left", "Center", "Right", };
// Toggles bit |flag| on |flags| based on state of |checkbox|.
void SetFlagFromCheckbox(Checkbox* checkbox, int* flags, int flag) {
@@ -77,91 +60,67 @@ void SetFlagFromCheckbox(Checkbox* checkbox, int* flags, int flag) {
} // namespace
-// TextExample's content view, which is responsible for drawing a string with
-// the specified style.
+// TextExample's content view, which draws stylized string.
class TextExample::TextExampleView : public View {
public:
TextExampleView()
- : text_(ASCIIToUTF16(kShortText)),
- text_flags_(0),
+ : text_(base::ASCIIToUTF16(kShortText)),
+ flags_(0),
halo_(false),
- fade_(false),
- fade_mode_(gfx::Canvas::TruncateFadeTail) {
+ elide_(gfx::TRUNCATE) {
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
View::OnPaint(canvas);
const gfx::Rect bounds = GetContentsBounds();
-
- if (fade_) {
- canvas->DrawFadeTruncatingStringRect(text_, fade_mode_, font_list_,
- SK_ColorDKGRAY, bounds);
+ const SkColor color = SK_ColorDKGRAY;
+ if (elide_ == gfx::FADE_TAIL) {
+ canvas->DrawFadedString(text_, font_list_, color, bounds, flags_);
} else if (halo_) {
- canvas->DrawStringRectWithHalo(text_, font_list_, SK_ColorDKGRAY,
- SK_ColorWHITE, bounds, text_flags_);
+ canvas->DrawStringRectWithHalo(text_, font_list_, color, SK_ColorYELLOW,
+ bounds, flags_);
} else {
- canvas->DrawStringRectWithFlags(text_, font_list_, SK_ColorDKGRAY, bounds,
- text_flags_);
+ canvas->DrawStringRectWithFlags(text_, font_list_, color, bounds, flags_);
}
}
- int text_flags() const { return text_flags_; }
- void set_text_flags(int text_flags) { text_flags_ = text_flags; }
-
- const string16& text() const { return text_; }
- void set_text(const string16& text) { text_ = text; }
-
- bool halo() const { return halo_; }
+ int flags() const { return flags_; }
+ void set_flags(int flags) { flags_ = flags; }
+ void set_text(const base::string16& text) { text_ = text; }
void set_halo(bool halo) { halo_ = halo; }
+ void set_elide(gfx::ElideBehavior elide) { elide_ = elide; }
- bool fade() const { return fade_; }
- void set_fade(bool fade) { fade_ = fade; }
-
- gfx::Canvas::TruncateFadeMode fade_mode() const { return fade_mode_; }
- void set_fade_mode(gfx::Canvas::TruncateFadeMode mode) { fade_mode_ = mode; }
-
- int GetFontStyle() const {
- return font_list_.GetFontStyle();
- }
- void SetFontStyle(int style) {
- font_list_ = font_list_.DeriveFontList(style);
- }
+ int GetStyle() const { return font_list_.GetFontStyle(); }
+ void SetStyle(int style) { font_list_ = font_list_.DeriveWithStyle(style); }
private:
// The font used for drawing the text.
gfx::FontList font_list_;
// The text to draw.
- string16 text_;
+ base::string16 text_;
- // Text flags for passing to |DrawStringInt()|.
- int text_flags_;
+ // Text flags for passing to |DrawStringRect()|.
+ int flags_;
- // If |true|, specifies to call |DrawStringWithHalo()| instead of
- // |DrawStringInt()|.
+ // A flag to draw a halo around the text.
bool halo_;
- // If |true|, specifies to call |DrawFadeTruncatingString()| instead of
- // |DrawStringInt()|.
- bool fade_;
-
- // If |fade_| is |true|, fade mode parameter to |DrawFadeTruncatingString()|.
- gfx::Canvas::TruncateFadeMode fade_mode_;
+ // The eliding, fading, or truncating behavior.
+ gfx::ElideBehavior elide_;
DISALLOW_COPY_AND_ASSIGN(TextExampleView);
};
-TextExample::TextExample() : ExampleBase("Text Styles") {
-}
+TextExample::TextExample() : ExampleBase("Text Styles") {}
TextExample::~TextExample() {
- // Remove all the views first as some reference models in
- // |example_combobox_model_|.
+ // Remove the views first as some reference combobox models.
container()->RemoveAllChildViews(true);
}
Checkbox* TextExample::AddCheckbox(GridLayout* layout, const char* name) {
- Checkbox* checkbox = new Checkbox(ASCIIToUTF16(name));
+ Checkbox* checkbox = new Checkbox(base::ASCIIToUTF16(name));
checkbox->set_listener(this);
layout->AddView(checkbox);
return checkbox;
@@ -172,11 +131,10 @@ Combobox* TextExample::AddCombobox(GridLayout* layout,
const char** strings,
int count) {
layout->StartRow(0, 0);
- layout->AddView(new Label(ASCIIToUTF16(name)));
- ExampleComboboxModel* combobox_model = new ExampleComboboxModel(strings,
- count);
- example_combobox_model_.push_back(combobox_model);
- Combobox* combobox = new Combobox(combobox_model);
+ layout->AddView(new Label(base::ASCIIToUTF16(name)));
+ ExampleComboboxModel* model = new ExampleComboboxModel(strings, count);
+ example_combobox_model_.push_back(model);
+ Combobox* combobox = new Combobox(model);
combobox->SetSelectedIndex(0);
combobox->set_listener(this);
layout->AddView(combobox, kNumColumns - 1, 1);
@@ -185,11 +143,9 @@ Combobox* TextExample::AddCombobox(GridLayout* layout,
void TextExample::CreateExampleView(View* container) {
text_view_ = new TextExampleView;
- text_view_->set_border(Border::CreateSolidBorder(1, SK_ColorGRAY));
-
+ text_view_->SetBorder(Border::CreateSolidBorder(1, SK_ColorGRAY));
GridLayout* layout = new GridLayout(container);
container->SetLayoutManager(layout);
-
layout->AddPaddingRow(0, 8);
ColumnSet* column_set = layout->AddColumnSet(0);
@@ -201,33 +157,24 @@ void TextExample::CreateExampleView(View* container) {
0.1f, GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, 8);
- h_align_cb_ = AddCombobox(layout,
- "H-Align",
- kHorizontalAligments,
+ h_align_cb_ = AddCombobox(layout, "H-Align", kHorizontalAligments,
arraysize(kHorizontalAligments));
- eliding_cb_ = AddCombobox(layout,
- "Eliding",
- kElidingBehaviors,
- arraysize(kElidingBehaviors));
- prefix_cb_ = AddCombobox(layout,
- "Prefix",
- kPrefixOptions,
+ eliding_cb_ = AddCombobox(layout, "Eliding", kElideBehaviors,
+ arraysize(kElideBehaviors));
+ prefix_cb_ = AddCombobox(layout, "Prefix", kPrefixOptions,
arraysize(kPrefixOptions));
- text_cb_ = AddCombobox(layout,
- "Example Text",
- kTextExamples,
+ text_cb_ = AddCombobox(layout, "Example Text", kTextExamples,
arraysize(kTextExamples));
layout->StartRow(0, 0);
multiline_checkbox_ = AddCheckbox(layout, "Multiline");
break_checkbox_ = AddCheckbox(layout, "Character Break");
- halo_checkbox_ = AddCheckbox(layout, "Text Halo");
+ halo_checkbox_ = AddCheckbox(layout, "Halo");
bold_checkbox_ = AddCheckbox(layout, "Bold");
italic_checkbox_ = AddCheckbox(layout, "Italic");
underline_checkbox_ = AddCheckbox(layout, "Underline");
- layout->AddPaddingRow(0, 32);
-
+ layout->AddPaddingRow(0, 20);
column_set = layout->AddColumnSet(1);
column_set->AddPaddingColumn(0, 16);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL,
@@ -235,94 +182,83 @@ void TextExample::CreateExampleView(View* container) {
column_set->AddPaddingColumn(0, 16);
layout->StartRow(1, 1);
layout->AddView(text_view_);
-
layout->AddPaddingRow(0, 8);
}
void TextExample::ButtonPressed(Button* button, const ui::Event& event) {
- int flags = text_view_->text_flags();
- int style = text_view_->GetFontStyle();
+ int flags = text_view_->flags();
+ int style = text_view_->GetStyle();
SetFlagFromCheckbox(multiline_checkbox_, &flags, gfx::Canvas::MULTI_LINE);
SetFlagFromCheckbox(break_checkbox_, &flags, gfx::Canvas::CHARACTER_BREAK);
SetFlagFromCheckbox(bold_checkbox_, &style, gfx::Font::BOLD);
SetFlagFromCheckbox(italic_checkbox_, &style, gfx::Font::ITALIC);
SetFlagFromCheckbox(underline_checkbox_, &style, gfx::Font::UNDERLINE);
text_view_->set_halo(halo_checkbox_->checked());
- text_view_->set_text_flags(flags);
- text_view_->SetFontStyle(style);
+ text_view_->set_flags(flags);
+ text_view_->SetStyle(style);
text_view_->SchedulePaint();
}
-void TextExample::OnSelectedIndexChanged(Combobox* combobox) {
- int text_flags = text_view_->text_flags();
+void TextExample::OnPerformAction(Combobox* combobox) {
+ int flags = text_view_->flags();
if (combobox == h_align_cb_) {
- text_flags &= ~(gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::TEXT_ALIGN_CENTER |
- gfx::Canvas::TEXT_ALIGN_RIGHT);
+ flags &= ~(gfx::Canvas::TEXT_ALIGN_LEFT |
+ gfx::Canvas::TEXT_ALIGN_CENTER |
+ gfx::Canvas::TEXT_ALIGN_RIGHT);
switch (combobox->selected_index()) {
case 0:
break;
case 1:
- text_flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
+ flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
break;
case 2:
- text_flags |= gfx::Canvas::TEXT_ALIGN_CENTER;
+ flags |= gfx::Canvas::TEXT_ALIGN_CENTER;
break;
case 3:
- text_flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
+ flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
break;
}
} else if (combobox == text_cb_) {
switch (combobox->selected_index()) {
case 0:
- text_view_->set_text(ASCIIToUTF16(kShortText));
+ text_view_->set_text(base::ASCIIToUTF16(kShortText));
break;
case 1:
- text_view_->set_text(ASCIIToUTF16(kMediumText));
+ text_view_->set_text(base::ASCIIToUTF16(kLongText));
break;
case 2:
- text_view_->set_text(ASCIIToUTF16(kLongText));
+ text_view_->set_text(base::ASCIIToUTF16(kAmpersandText));
break;
case 3:
- text_view_->set_text(ASCIIToUTF16(kAmpersandText));
- break;
- case 4:
- text_view_->set_text(ASCIIToUTF16(kNewlineText));
+ text_view_->set_text(base::WideToUTF16(kRightToLeftText));
break;
}
} else if (combobox == eliding_cb_) {
switch (combobox->selected_index()) {
case 0:
- text_flags &= ~gfx::Canvas::NO_ELLIPSIS;
- text_view_->set_fade(false);
+ text_view_->set_elide(gfx::ELIDE_TAIL);
break;
case 1:
- text_flags |= gfx::Canvas::NO_ELLIPSIS;
- text_view_->set_fade(false);
+ text_view_->set_elide(gfx::TRUNCATE);
break;
case 2:
- text_view_->set_fade_mode(gfx::Canvas::TruncateFadeTail);
- text_view_->set_fade(true);
- break;
- case 3:
- text_view_->set_fade_mode(gfx::Canvas::TruncateFadeHead);
- text_view_->set_fade(true);
+ text_view_->set_elide(gfx::FADE_TAIL);
break;
}
} else if (combobox == prefix_cb_) {
- text_flags &= ~(gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX);
+ flags &= ~(gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX);
switch (combobox->selected_index()) {
case 0:
break;
case 1:
- text_flags |= gfx::Canvas::SHOW_PREFIX;
+ flags |= gfx::Canvas::SHOW_PREFIX;
break;
case 2:
- text_flags |= gfx::Canvas::HIDE_PREFIX;
+ flags |= gfx::Canvas::HIDE_PREFIX;
break;
}
}
- text_view_->set_text_flags(text_flags);
+ text_view_->set_flags(flags);
text_view_->SchedulePaint();
}
diff --git a/chromium/ui/views/examples/text_example.h b/chromium/ui/views/examples/text_example.h
index 007f5194522..18ebaabdd74 100644
--- a/chromium/ui/views/examples/text_example.h
+++ b/chromium/ui/views/examples/text_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_TEXT_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_TEXT_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
@@ -20,14 +19,14 @@ namespace examples {
class ExampleComboboxModel;
-class TextExample : public ExampleBase,
- public ButtonListener,
- public ComboboxListener {
+class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
+ public ButtonListener,
+ public ComboboxListener {
public:
TextExample();
virtual ~TextExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
@@ -40,11 +39,11 @@ class TextExample : public ExampleBase,
const char** strings,
int count);
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* button, const ui::Event& event) OVERRIDE;
- // Overridden from ComboboxListener:
- virtual void OnSelectedIndexChanged(Combobox* combobox) OVERRIDE;
+ // ComboboxListener:
+ virtual void OnPerformAction(Combobox* combobox) OVERRIDE;
class TextExampleView;
// The content of the scroll view.
diff --git a/chromium/ui/views/examples/textfield_example.cc b/chromium/ui/views/examples/textfield_example.cc
index ec18cf74a5b..7dae434f353 100644
--- a/chromium/ui/views/examples/textfield_example.cc
+++ b/chromium/ui/views/examples/textfield_example.cc
@@ -14,6 +14,9 @@
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using base::ASCIIToUTF16;
+using base::UTF16ToUTF8;
+
namespace views {
namespace examples {
@@ -34,7 +37,8 @@ TextfieldExample::~TextfieldExample() {
void TextfieldExample::CreateExampleView(View* container) {
name_ = new Textfield();
- password_ = new Textfield(Textfield::STYLE_OBSCURED);
+ password_ = new Textfield();
+ password_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
password_->set_placeholder_text(ASCIIToUTF16("password"));
read_only_ = new Textfield();
read_only_->SetReadOnly(true);
@@ -44,8 +48,8 @@ void TextfieldExample::CreateExampleView(View* container) {
append_ = new LabelButton(this, ASCIIToUTF16("Append"));
set_ = new LabelButton(this, ASCIIToUTF16("Set"));
set_style_ = new LabelButton(this, ASCIIToUTF16("Set Styles"));
- name_->SetController(this);
- password_->SetController(this);
+ name_->set_controller(this);
+ password_->set_controller(this);
GridLayout* layout = new GridLayout(container);
container->SetLayoutManager(layout);
@@ -77,7 +81,7 @@ void TextfieldExample::CreateExampleView(View* container) {
}
void TextfieldExample::ContentsChanged(Textfield* sender,
- const string16& new_contents) {
+ const base::string16& new_contents) {
if (sender == name_) {
PrintStatus("Name [%s]", UTF16ToUTF8(new_contents).c_str());
} else if (sender == password_) {
@@ -102,7 +106,7 @@ void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == show_password_) {
PrintStatus("Password [%s]", UTF16ToUTF8(password_->text()).c_str());
} else if (sender == clear_all_) {
- string16 empty;
+ base::string16 empty;
name_->SetText(empty);
password_->SetText(empty);
read_only_->SetText(empty);
diff --git a/chromium/ui/views/examples/textfield_example.h b/chromium/ui/views/examples/textfield_example.h
index b363c6ede7b..db5e1998299 100644
--- a/chromium/ui/views/examples/textfield_example.h
+++ b/chromium/ui/views/examples/textfield_example.h
@@ -7,9 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/examples/example_base.h"
@@ -21,9 +19,9 @@ class LabelButton;
namespace examples {
// TextfieldExample mimics login screen.
-class TextfieldExample : public ExampleBase,
- public TextfieldController,
- public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT TextfieldExample : public ExampleBase,
+ public TextfieldController,
+ public ButtonListener {
public:
TextfieldExample();
virtual ~TextfieldExample();
@@ -34,7 +32,7 @@ class TextfieldExample : public ExampleBase,
private:
// TextfieldController:
virtual void ContentsChanged(Textfield* sender,
- const string16& new_contents) OVERRIDE;
+ const base::string16& new_contents) OVERRIDE;
virtual bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) OVERRIDE;
virtual bool HandleMouseEvent(Textfield* sender,
diff --git a/chromium/ui/views/examples/throbber_example.cc b/chromium/ui/views/examples/throbber_example.cc
index ccc3c794432..7bd18a246cb 100644
--- a/chromium/ui/views/examples/throbber_example.cc
+++ b/chromium/ui/views/examples/throbber_example.cc
@@ -25,7 +25,7 @@ class ThrobberView : public View {
throbber_->Start();
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return gfx::Size(width(), height());
}
diff --git a/chromium/ui/views/examples/throbber_example.h b/chromium/ui/views/examples/throbber_example.h
index 646ab691f79..3c4f9c0beb2 100644
--- a/chromium/ui/views/examples/throbber_example.h
+++ b/chromium/ui/views/examples/throbber_example.h
@@ -5,19 +5,18 @@
#ifndef UI_VIEWS_EXAMPLES_THROBBER_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_THROBBER_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/examples/example_base.h"
namespace views {
namespace examples {
-class ThrobberExample : public ExampleBase {
+class VIEWS_EXAMPLES_EXPORT ThrobberExample : public ExampleBase {
public:
ThrobberExample();
virtual ~ThrobberExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
diff --git a/chromium/ui/views/examples/tree_view_example.cc b/chromium/ui/views/examples/tree_view_example.cc
index 6dfc5585974..2f6cc4cedf3 100644
--- a/chromium/ui/views/examples/tree_view_example.cc
+++ b/chromium/ui/views/examples/tree_view_example.cc
@@ -11,6 +11,8 @@
#include "ui/views/controls/tree/tree_view.h"
#include "ui/views/layout/grid_layout.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -130,10 +132,14 @@ void TreeViewExample::ShowContextMenuForView(View* source,
context_menu_model.AddItem(ID_REMOVE, ASCIIToUTF16("Remove"));
context_menu_model.AddItem(ID_ADD, ASCIIToUTF16("Add"));
context_menu_runner_.reset(new MenuRunner(&context_menu_model));
- if (context_menu_runner_->RunMenuAt(source->GetWidget(), NULL,
- gfx::Rect(point, gfx::Size()), MenuItemView::TOPLEFT, source_type, 0) ==
- MenuRunner::MENU_DELETED)
+ if (context_menu_runner_->RunMenuAt(source->GetWidget(),
+ NULL,
+ gfx::Rect(point, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT,
+ source_type,
+ 0) == MenuRunner::MENU_DELETED) {
return;
+ }
}
bool TreeViewExample::IsCommandIdChecked(int command_id) const {
diff --git a/chromium/ui/views/examples/tree_view_example.h b/chromium/ui/views/examples/tree_view_example.h
index ffac4dd66fa..55af17f7d08 100644
--- a/chromium/ui/views/examples/tree_view_example.h
+++ b/chromium/ui/views/examples/tree_view_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_TREE_VIEW_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_TREE_VIEW_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/models/tree_node_model.h"
#include "ui/views/context_menu_controller.h"
@@ -21,11 +20,12 @@ class TreeView;
namespace examples {
-class TreeViewExample : public ExampleBase,
- public ButtonListener,
- public TreeViewController,
- public ContextMenuController,
- public ui::SimpleMenuModel::Delegate {
+class VIEWS_EXAMPLES_EXPORT TreeViewExample
+ : public ExampleBase,
+ public ButtonListener,
+ public TreeViewController,
+ public ContextMenuController,
+ public ui::SimpleMenuModel::Delegate {
public:
TreeViewExample();
virtual ~TreeViewExample();
diff --git a/chromium/ui/views/examples/webview_example.cc b/chromium/ui/views/examples/webview_example.cc
index 5a2d89d3904..feae6b977f9 100644
--- a/chromium/ui/views/examples/webview_example.cc
+++ b/chromium/ui/views/examples/webview_example.cc
@@ -6,7 +6,6 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
@@ -28,7 +27,7 @@ void WebViewExample::CreateExampleView(View* container) {
container->AddChildView(webview_);
webview_->LoadInitialURL(GURL("http://www.google.com/"));
- webview_->web_contents()->GetView()->Focus();
+ webview_->web_contents()->Focus();
}
} // namespace examples
diff --git a/chromium/ui/views/examples/webview_example.h b/chromium/ui/views/examples/webview_example.h
index bc4e45918ef..3e35fe94a77 100644
--- a/chromium/ui/views/examples/webview_example.h
+++ b/chromium/ui/views/examples/webview_example.h
@@ -5,8 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_WEBVIEW_EXAMPLE_H_
#define UI_VIEWS_EXAMPLES_WEBVIEW_EXAMPLE_H_
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/examples/example_base.h"
namespace content {
@@ -23,7 +22,7 @@ class WebViewExample : public ExampleBase {
explicit WebViewExample(content::BrowserContext* browser_context);
virtual ~WebViewExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
diff --git a/chromium/ui/views/examples/widget_example.cc b/chromium/ui/views/examples/widget_example.cc
index 0d42a65ae6b..1109a5ad4c4 100644
--- a/chromium/ui/views/examples/widget_example.cc
+++ b/chromium/ui/views/examples/widget_example.cc
@@ -13,6 +13,8 @@
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace examples {
@@ -22,7 +24,7 @@ class DialogExample : public DialogDelegateView {
public:
DialogExample();
virtual ~DialogExample();
- virtual string16 GetWindowTitle() const OVERRIDE;
+ virtual base::string16 GetWindowTitle() const OVERRIDE;
virtual View* CreateExtraView() OVERRIDE;
virtual View* CreateTitlebarExtraView() OVERRIDE;
virtual View* CreateFootnoteView() OVERRIDE;
@@ -36,13 +38,13 @@ DialogExample::DialogExample() {
DialogExample::~DialogExample() {}
-string16 DialogExample::GetWindowTitle() const {
+base::string16 DialogExample::GetWindowTitle() const {
return ASCIIToUTF16("Dialog Widget Example");
}
View* DialogExample::CreateExtraView() {
LabelButton* button = new LabelButton(NULL, ASCIIToUTF16("Extra button!"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
return button;
}
diff --git a/chromium/ui/views/examples/widget_example.h b/chromium/ui/views/examples/widget_example.h
index 7c3085e02e8..ff08d70790f 100644
--- a/chromium/ui/views/examples/widget_example.h
+++ b/chromium/ui/views/examples/widget_example.h
@@ -7,8 +7,7 @@
#include <string>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/examples/example_base.h"
#include "ui/views/widget/widget.h"
@@ -17,12 +16,13 @@ namespace views {
namespace examples {
// WidgetExample demonstrates how to create a popup widget.
-class WidgetExample : public ExampleBase, public ButtonListener {
+class VIEWS_EXAMPLES_EXPORT WidgetExample : public ExampleBase,
+ public ButtonListener {
public:
WidgetExample();
virtual ~WidgetExample();
- // Overridden from ExampleBase:
+ // ExampleBase:
virtual void CreateExampleView(View* container) OVERRIDE;
private:
@@ -40,7 +40,7 @@ class WidgetExample : public ExampleBase, public ButtonListener {
// Construct a Widget for |sender|, initialize with |params|, and call Show().
void ShowWidget(View* sender, Widget::InitParams params);
- // Overridden from ButtonListener:
+ // ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(WidgetExample);
diff --git a/chromium/ui/views/focus/accelerator_handler.h b/chromium/ui/views/focus/accelerator_handler.h
deleted file mode 100644
index 29f353e697c..00000000000
--- a/chromium/ui/views/focus/accelerator_handler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
-#define UI_VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
-
-#include "build/build_config.h"
-
-#include <set>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-
-#if defined(USE_AURA) && defined(USE_X11)
-// Dispatch an XEvent to the RootView. Return true if the event was dispatched
-// and handled, false otherwise.
-bool VIEWS_EXPORT DispatchXEvent(XEvent* xevent);
-#endif // USE_AURA && USE_X11
-
-// This class delegates the key messages to the associated FocusManager class
-// for the window that is receiving these messages for accelerator processing.
-class VIEWS_EXPORT AcceleratorHandler : public base::MessageLoop::Dispatcher {
- public:
- AcceleratorHandler();
-
- // Dispatcher method. This returns true if an accelerator was processed by the
- // focus manager
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- private:
-#if defined(OS_WIN)
- // The keys currently pressed and consumed by the FocusManager.
- std::set<WPARAM> pressed_keys_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(AcceleratorHandler);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
diff --git a/chromium/ui/views/focus/accelerator_handler_aura.cc b/chromium/ui/views/focus/accelerator_handler_aura.cc
deleted file mode 100644
index 8daa0f394e9..00000000000
--- a/chromium/ui/views/focus/accelerator_handler_aura.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/focus/accelerator_handler.h"
-
-namespace views {
-
-AcceleratorHandler::AcceleratorHandler() {
-}
-
-bool AcceleratorHandler::Dispatch(const base::NativeEvent& event) {
-#if defined(OS_WIN)
- TranslateMessage(&event);
- DispatchMessage(&event);
-#endif // defined(OS_WIN)
- return true;
-}
-
-#if defined(USE_X11)
-bool DispatchXEvent(XEvent* xev) {
- return false;
-}
-#endif // defined(USE_X11)
-
-} // namespace views
diff --git a/chromium/ui/views/focus/accelerator_handler_win.cc b/chromium/ui/views/focus/accelerator_handler_win.cc
deleted file mode 100644
index ea82daed717..00000000000
--- a/chromium/ui/views/focus/accelerator_handler_win.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/focus/accelerator_handler.h"
-
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-AcceleratorHandler::AcceleratorHandler() {
-}
-
-bool AcceleratorHandler::Dispatch(const base::NativeEvent& msg) {
- if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
- Widget* widget = Widget::GetTopLevelWidgetForNativeView(msg.hwnd);
- FocusManager* focus_manager = widget ? widget->GetFocusManager() : NULL;
- if (focus_manager) {
- switch (msg.message) {
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN: {
- ui::KeyEvent event(msg, false);
- if (!focus_manager->OnKeyEvent(event)) {
- // Record that this key is pressed so we can remember not to
- // translate and dispatch the associated WM_KEYUP.
- pressed_keys_.insert(msg.wParam);
- return true;
- }
- break;
- }
- case WM_KEYUP:
- case WM_SYSKEYUP: {
- std::set<WPARAM>::iterator iter = pressed_keys_.find(msg.wParam);
- if (iter != pressed_keys_.end()) {
- // Don't translate/dispatch the KEYUP since we have eaten the
- // associated KEYDOWN.
- pressed_keys_.erase(iter);
- return true;
- }
- break;
- }
- }
- }
- }
-
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- return true;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc
index f52712e6234..4808b4422cb 100644
--- a/chromium/ui/views/focus/focus_manager.cc
+++ b/chromium/ui/views/focus/focus_manager.cc
@@ -11,6 +11,10 @@
#include "base/logging.h"
#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/focus/focus_manager_delegate.h"
@@ -64,6 +68,7 @@ bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
modifiers |= ui::EF_ALT_DOWN;
ui::Accelerator accelerator(event.key_code(), modifiers);
accelerator.set_type(event.type());
+ accelerator.set_is_repeat(event.IsRepeat());
if (event.type() == ui::ET_KEY_PRESSED) {
// If the focused view wants to process the key event as is, let it be.
@@ -75,20 +80,10 @@ bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
// Note that we don't do focus traversal if the root window is not part of
// the active window hierarchy as this would mean we have no focused view
// and would focus the first focusable view.
-#if defined(OS_WIN) && !defined(USE_AURA)
- HWND top_window = widget_->GetNativeView();
- HWND active_window = ::GetActiveWindow();
- if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
- IsTabTraversalKeyEvent(event)) {
- AdvanceFocus(event.IsShiftDown());
- return false;
- }
-#else
if (IsTabTraversalKeyEvent(event)) {
AdvanceFocus(event.IsShiftDown());
return false;
}
-#endif
if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
return false;
@@ -319,8 +314,13 @@ View* FocusManager::GetNextFocusableView(View* original_starting_view,
void FocusManager::SetFocusedViewWithReason(
View* view, FocusChangeReason reason) {
- if (focused_view_ == view)
+ if (focused_view_ == view) {
+ // In the case that the widget lost the focus and gained it back without
+ // changing the focused view, we have to make the text input client focused.
+ // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
+ FocusTextInputClient(focused_view_);
return;
+ }
base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
// Update the reason for the focus change (since this is checked by
@@ -331,14 +331,18 @@ void FocusManager::SetFocusedViewWithReason(
View* old_focused_view = focused_view_;
focused_view_ = view;
- if (old_focused_view)
+ if (old_focused_view) {
old_focused_view->Blur();
+ BlurTextInputClient(old_focused_view);
+ }
// Also make |focused_view_| the stored focus view. This way the stored focus
// view is remembered if focus changes are requested prior to a show or while
// hidden.
SetStoredFocusView(focused_view_);
- if (focused_view_)
+ if (focused_view_) {
+ FocusTextInputClient(focused_view_);
focused_view_->Focus();
+ }
FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
OnDidChangeFocus(old_focused_view, focused_view_));
@@ -437,6 +441,46 @@ void FocusManager::ClearStoredFocusedView() {
SetStoredFocusView(NULL);
}
+void FocusManager::OnTextInputClientChanged(View* view) {
+ if (view == focused_view_)
+ FocusTextInputClient(view);
+}
+
+void FocusManager::FocusTextInputClient(View* view) {
+ if (!switches::IsTextInputFocusManagerEnabled())
+ return;
+
+ // If the widget is not active, do not steal the text input focus.
+ if (!widget_->IsActive())
+ return;
+
+ ui::TextInputClient* text_input_client =
+ view ? view->GetTextInputClient() : NULL;
+ ui::TextInputFocusManager::GetInstance()->
+ FocusTextInputClient(text_input_client);
+ ui::InputMethod* input_method = widget_->GetHostInputMethod();
+ if (input_method) {
+ input_method->OnTextInputTypeChanged(text_input_client);
+ input_method->OnCaretBoundsChanged(text_input_client);
+ }
+}
+
+void FocusManager::BlurTextInputClient(View* view) {
+ if (!switches::IsTextInputFocusManagerEnabled())
+ return;
+
+ ui::TextInputClient* text_input_client =
+ view ? view->GetTextInputClient() : NULL;
+ if (text_input_client && text_input_client->HasCompositionText()) {
+ text_input_client->ConfirmCompositionText();
+ ui::InputMethod* input_method = widget_->GetHostInputMethod();
+ if (input_method && input_method->GetTextInputClient() == text_input_client)
+ input_method->CancelComposition(text_input_client);
+ }
+ ui::TextInputFocusManager::GetInstance()->
+ BlurTextInputClient(text_input_client);
+}
+
// Find the next (previous if reverse is true) focusable view for the specified
// FocusTraversable, starting at the specified view, traversing down the
// FocusTraversable hierarchy.
diff --git a/chromium/ui/views/focus/focus_manager.h b/chromium/ui/views/focus/focus_manager.h
index 7d7c7dc16e0..ebdc2a3d88e 100644
--- a/chromium/ui/views/focus/focus_manager.h
+++ b/chromium/ui/views/focus/focus_manager.h
@@ -72,8 +72,8 @@
// is FocusTraversable.
namespace ui {
-class AcceleratorTarget;
class AcceleratorManager;
+class AcceleratorTarget;
class EventHandler;
class KeyEvent;
}
@@ -213,6 +213,15 @@ class VIEWS_EXPORT FocusManager {
// Returns true if in the process of changing the focused view.
bool is_changing_focus() const { return is_changing_focus_; }
+ // Changes the text input focus to |view->GetTextInputClient()| iff |view|
+ // is focused. Views must call this method when their internal
+ // TextInputClient instance changes.
+ void OnTextInputClientChanged(View* view);
+
+ // Moves the text input focus into/out from |view|.
+ void FocusTextInputClient(View* view);
+ void BlurTextInputClient(View* view);
+
// Disable shortcut handling.
static void set_shortcut_handling_suspended(bool suspended) {
shortcut_handling_suspended_ = suspended;
diff --git a/chromium/ui/views/focus/focus_manager_test.cc b/chromium/ui/views/focus/focus_manager_test.cc
index 528f345ce63..6debc794dff 100644
--- a/chromium/ui/views/focus/focus_manager_test.cc
+++ b/chromium/ui/views/focus/focus_manager_test.cc
@@ -100,24 +100,6 @@ void FocusManagerTest::SetAccessiblePanes(const std::vector<View*>& panes) {
accessible_panes_ = panes;
}
-#if defined(OS_WIN) && !defined(USE_AURA)
-void FocusManagerTest::SimulateActivateWindow() {
- SendMessage(GetWidget()->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
-}
-
-void FocusManagerTest::SimulateDeactivateWindow() {
- SendMessage(GetWidget()->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL);
-}
-
-void FocusManagerTest::PostKeyDown(ui::KeyboardCode key_code) {
- PostMessage(GetWidget()->GetNativeView(), WM_KEYDOWN, key_code, 0);
-}
-
-void FocusManagerTest::PostKeyUp(ui::KeyboardCode key_code) {
- PostMessage(GetWidget()->GetNativeView(), WM_KEYUP, key_code, 0);
-}
-#endif
-
////////////////////////////////////////////////////////////////////////////////
// TestFocusChangeListener
diff --git a/chromium/ui/views/focus/focus_manager_test.h b/chromium/ui/views/focus/focus_manager_test.h
index 4afbf4f7758..e54138673b0 100644
--- a/chromium/ui/views/focus/focus_manager_test.h
+++ b/chromium/ui/views/focus/focus_manager_test.h
@@ -43,15 +43,6 @@ class FocusManagerTest : public ViewsTestBase, public WidgetDelegate {
// For testing FocusManager::RotatePaneFocus().
void SetAccessiblePanes(const std::vector<View*>& panes);
-#if defined(OS_WIN) && !defined(USE_AURA)
- // Mocks activating/deactivating the window.
- void SimulateActivateWindow();
- void SimulateDeactivateWindow();
-
- void PostKeyDown(ui::KeyboardCode key_code);
- void PostKeyUp(ui::KeyboardCode key_code);
-#endif
-
private:
View* contents_view_;
FocusChangeListener* focus_change_listener_;
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index fcb82b7f310..3513e2b70a7 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -2,38 +2,29 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/focus/focus_manager.h"
+
#include <utility>
#include <vector>
+#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window.h"
#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/accessible_pane_view.h"
#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/focus/focus_manager_test.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/window.h"
-#endif
-
namespace views {
-void FocusNativeView(gfx::NativeView view) {
-#if defined(USE_AURA)
- aura::client::GetFocusClient(view)->FocusWindow(view);
-#elif defined(OS_WIN)
- SetFocus(view);
-#else
-#error
-#endif
-}
-
enum FocusTestEventType {
ON_FOCUS = 0,
ON_BLUR
@@ -67,6 +58,8 @@ class SimpleTestView : public View {
private:
std::vector<FocusTestEvent>* event_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleTestView);
};
// Tests that the appropriate Focus related methods are called when a View
@@ -149,14 +142,14 @@ TEST_F(FocusManagerTest, WidgetFocusChangeListener) {
widget_listener.ClearFocusChanges();
gfx::NativeView native_view1 = widget1->GetNativeView();
- FocusNativeView(native_view1);
+ aura::client::GetFocusClient(native_view1)->FocusWindow(native_view1);
ASSERT_EQ(2, static_cast<int>(widget_listener.focus_changes().size()));
EXPECT_EQ(native_view1, widget_listener.focus_changes()[0].second);
EXPECT_EQ(native_view1, widget_listener.focus_changes()[1].second);
widget_listener.ClearFocusChanges();
gfx::NativeView native_view2 = widget2->GetNativeView();
- FocusNativeView(native_view2);
+ aura::client::GetFocusClient(native_view2)->FocusWindow(native_view2);
ASSERT_EQ(2, static_cast<int>(widget_listener.focus_changes().size()));
EXPECT_EQ(NativeViewPair(native_view1, native_view2),
widget_listener.focus_changes()[0]);
@@ -164,26 +157,6 @@ TEST_F(FocusManagerTest, WidgetFocusChangeListener) {
widget_listener.focus_changes()[1]);
}
-#if !defined(USE_AURA)
-class TestTextfield : public Textfield {
- public:
- TestTextfield() {}
- virtual gfx::NativeView TestGetNativeControlView() {
- return native_wrapper_->GetTestingHandle();
- }
-};
-
-// Tests that NativeControls do set the focused View appropriately on the
-// FocusManager.
-TEST_F(FocusManagerTest, DISABLED_FocusNativeControls) {
- TestTextfield* textfield = new TestTextfield();
- GetContentsView()->AddChildView(textfield);
- // Simulate the native view getting the native focus (such as by user click).
- FocusNativeView(textfield->TestGetNativeControlView());
- EXPECT_EQ(textfield, GetFocusManager()->GetFocusedView());
-}
-#endif
-
// Counts accelerator calls.
class TestAcceleratorTarget : public ui::AcceleratorTarget {
public:
@@ -537,10 +510,11 @@ class FocusManagerDtorTest : public FocusManagerTest {
class LabelButtonDtorTracked : public LabelButton {
public:
- LabelButtonDtorTracked(const string16& text, DtorTrackVector* dtor_tracker)
+ LabelButtonDtorTracked(const base::string16& text,
+ DtorTrackVector* dtor_tracker)
: LabelButton(NULL, text),
dtor_tracker_(dtor_tracker) {
- SetStyle(STYLE_NATIVE_TEXTBUTTON);
+ SetStyle(STYLE_BUTTON);
};
virtual ~LabelButtonDtorTracked() {
dtor_tracker_->push_back("LabelButtonDtorTracked");
@@ -586,25 +560,6 @@ class FocusManagerDtorTest : public FocusManagerTest {
DtorTrackVector dtor_tracker_;
};
-#if !defined(USE_AURA)
-TEST_F(FocusManagerDtorTest, FocusManagerDestructedLast) {
- // Setup views hierarchy.
- GetContentsView()->AddChildView(new TestTextfield());
- GetContentsView()->AddChildView(new LabelButtonDtorTracked(
- ASCIIToUTF16("button"), &dtor_tracker_));
-
- // Close the window.
- GetWidget()->Close();
- RunPendingMessages();
-
- // Test window, button and focus manager should all be destructed.
- ASSERT_EQ(3, static_cast<int>(dtor_tracker_.size()));
-
- // Focus manager should be the last one to destruct.
- ASSERT_STREQ("FocusManagerDtorTracked", dtor_tracker_[2].c_str());
-}
-#endif
-
namespace {
class FocusInAboutToRequestFocusFromTabTraversalView : public View {
@@ -819,16 +774,72 @@ TEST_F(FocusManagerTest, StoreFocusedView) {
View view;
GetFocusManager()->SetFocusedView(&view);
GetFocusManager()->StoreFocusedView(false);
+ EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
EXPECT_TRUE(GetFocusManager()->RestoreFocusedView());
EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView());
// Repeat with |true|.
GetFocusManager()->SetFocusedView(&view);
GetFocusManager()->StoreFocusedView(true);
+ EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
EXPECT_TRUE(GetFocusManager()->RestoreFocusedView());
EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView());
}
+class TextInputTestView : public View {
+ public:
+ TextInputTestView() {}
+
+ virtual ui::TextInputClient* GetTextInputClient() OVERRIDE {
+ return &text_input_client_;
+ }
+
+ private:
+ ui::DummyTextInputClient text_input_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextInputTestView);
+};
+
+TEST_F(FocusManagerTest, TextInputClient) {
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ cmd_line->AppendSwitch(switches::kEnableTextInputFocusManager);
+
+ View* view = new TextInputTestView;
+ ui::TextInputClient* text_input_client = view->GetTextInputClient();
+ view->SetFocusable(true);
+ GetContentsView()->AddChildView(view);
+ ui::TextInputFocusManager* text_input_focus_manager =
+ ui::TextInputFocusManager::GetInstance();
+
+ GetFocusManager()->SetFocusedView(view);
+ EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ GetFocusManager()->StoreFocusedView(false);
+ EXPECT_TRUE(GetFocusManager()->RestoreFocusedView());
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+
+ // Repeat with |true|.
+ GetFocusManager()->SetFocusedView(view);
+ EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ GetFocusManager()->StoreFocusedView(true);
+ EXPECT_TRUE(GetFocusManager()->RestoreFocusedView());
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+
+ // Focus the view twice in a row.
+ GetFocusManager()->SetFocusedView(view);
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL);
+ GetFocusManager()->SetFocusedView(view);
+ EXPECT_EQ(text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+}
+
namespace {
// Trivial WidgetDelegate implementation that allows setting return value of
diff --git a/chromium/ui/views/focus/focus_manager_unittest_win.cc b/chromium/ui/views/focus/focus_manager_unittest_win.cc
deleted file mode 100644
index 267a8b78df3..00000000000
--- a/chromium/ui/views/focus/focus_manager_unittest_win.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/focus/focus_manager.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/run_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/events/event.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/focus/accelerator_handler.h"
-#include "ui/views/focus/focus_manager_test.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-namespace {
-
-class MessageTrackingView : public View {
- public:
- MessageTrackingView() : accelerator_pressed_(false) {
- }
-
- void Reset() {
- accelerator_pressed_ = false;
- keys_pressed_.clear();
- keys_released_.clear();
- }
-
- const std::vector<ui::KeyboardCode>& keys_pressed() const {
- return keys_pressed_;
- }
-
- const std::vector<ui::KeyboardCode>& keys_released() const {
- return keys_released_;
- }
-
- bool accelerator_pressed() const {
- return accelerator_pressed_;
- }
-
- // Overridden from View:
- virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
- keys_pressed_.push_back(e.key_code());
- return true;
- }
- virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE {
- keys_released_.push_back(e.key_code());
- return true;
- }
- virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
- accelerator_pressed_ = true;
- return true;
- }
-
- private:
- bool accelerator_pressed_;
- std::vector<ui::KeyboardCode> keys_pressed_;
- std::vector<ui::KeyboardCode> keys_released_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageTrackingView);
-};
-
-} // namespace
-
-// Test that when activating/deactivating the top window, the focus is stored/
-// restored properly.
-TEST_F(FocusManagerTest, FocusStoreRestore) {
- // Simulate an activate, otherwise the deactivate isn't going to do anything.
- SimulateActivateWindow();
-
- LabelButton* button = new LabelButton(NULL, ASCIIToUTF16("Press me"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
- View* view = new View();
- view->SetFocusable(true);
-
- GetContentsView()->AddChildView(button);
- button->SetBounds(10, 10, 200, 30);
- GetContentsView()->AddChildView(view);
- RunPendingMessages();
-
- TestFocusChangeListener listener;
- AddFocusChangeListener(&listener);
-
- view->RequestFocus();
- RunPendingMessages();
-
- // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
- views::View* null_view = NULL;
-
- // Deacivate the window, it should store its focus.
- SimulateDeactivateWindow();
- EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
- ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
- EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
- EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view));
- listener.ClearFocusChanges();
-
- // Reactivate, focus should come-back to the previously focused view.
- SimulateActivateWindow();
- EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
- ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
- EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
- listener.ClearFocusChanges();
-
- // Same test with a NativeControl.
- button->RequestFocus();
- SimulateDeactivateWindow();
- EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
- ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
- EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button));
- EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view));
- listener.ClearFocusChanges();
-
- SimulateActivateWindow();
- EXPECT_EQ(button, GetFocusManager()->GetFocusedView());
- ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
- EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button));
- listener.ClearFocusChanges();
-
- /*
- // Now test that while the window is inactive we can change the focused view
- // (we do that in several places).
- SimulateDeactivateWindow();
- // TODO: would have to mock the window being inactive (with a TestWidgetWin
- // that would return false on IsActive()).
- GetFocusManager()->SetFocusedView(view);
- ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
-
- EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
- ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
- EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view));
- EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view));
- */
-}
-
-// Test that the focus manager is created successfully for the first view
-// window parented to a native dialog.
-TEST_F(FocusManagerTest, CreationForNativeRoot) {
- // Create a window class.
- WNDCLASSEX class_ex;
- memset(&class_ex, 0, sizeof(class_ex));
- class_ex.cbSize = sizeof(WNDCLASSEX);
- class_ex.lpfnWndProc = &DefWindowProc;
- class_ex.lpszClassName = L"TestWindow";
- ATOM atom = RegisterClassEx(&class_ex);
- ASSERT_TRUE(atom);
-
- // Create a native dialog window.
- HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL,
- WS_OVERLAPPEDWINDOW, 0, 0, 200, 200,
- NULL, NULL, NULL, NULL);
- ASSERT_TRUE(hwnd);
-
- // Create a view window parented to native dialog.
- scoped_ptr<Widget> widget1(new Widget);
- Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = hwnd;
- params.bounds = gfx::Rect(0, 0, 100, 100);
- params.top_level = true; // This is top level in views hierarchy.
- widget1->Init(params);
-
- // Get the focus manager directly from the first window. Should exist
- // because the first window is the root widget.
- views::FocusManager* focus_manager1 = widget1->GetFocusManager();
- EXPECT_TRUE(focus_manager1);
-
- // Create another view window parented to the first view window.
- scoped_ptr<Widget> widget2(new Widget);
- params.parent = widget1->GetNativeView();
- params.top_level = false; // This is child widget.
- widget2->Init(params);
-
- // Access the shared focus manager directly from the second window.
- views::FocusManager* focus_manager2 = widget2->GetFocusManager();
- EXPECT_EQ(focus_manager2, focus_manager1);
-
- // Access the shared focus manager indirectly from the first window handle.
- gfx::NativeWindow native_window = widget1->GetNativeWindow();
- views::Widget* widget =
- views::Widget::GetWidgetForNativeWindow(native_window);
- EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
-
- // Access the shared focus manager indirectly from the second window handle.
- native_window = widget2->GetNativeWindow();
- widget = views::Widget::GetWidgetForNativeWindow(native_window);
- EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
-
- // Access the shared focus manager indirectly from the first view handle.
- gfx::NativeView native_view = widget1->GetNativeView();
- widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
- EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
-
- // Access the shared focus manager indirectly from the second view handle.
- native_view = widget2->GetNativeView();
- widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
- EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
-
- DestroyWindow(hwnd);
-}
-
-// Tests that the keyup messages are eaten for accelerators.
-// Windows-only, Windows is the only platform that handles accelerators in
-// AcceleratorHandler. NativeWidgetAura::OnKeyEvent handles them in other
-// configurations.
-TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) {
- FocusManager* focus_manager = GetFocusManager();
- MessageTrackingView* mtv = new MessageTrackingView();
- mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, ui::EF_NONE));
- mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, ui::EF_NONE));
- GetContentsView()->AddChildView(mtv);
- focus_manager->SetFocusedView(mtv);
-
- // First send a non-accelerator key sequence.
- PostKeyDown(ui::VKEY_9);
- PostKeyUp(ui::VKEY_9);
- AcceleratorHandler accelerator_handler;
- scoped_ptr<base::RunLoop> run_loop(new base::RunLoop(&accelerator_handler));
- run_loop->RunUntilIdle();
- // Make sure we get a key-up and key-down.
- ASSERT_EQ(1U, mtv->keys_pressed().size());
- EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
- ASSERT_EQ(1U, mtv->keys_released().size());
- EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
- EXPECT_FALSE(mtv->accelerator_pressed());
- mtv->Reset();
-
- // Same thing with repeat and more than one key at once.
- PostKeyDown(ui::VKEY_9);
- PostKeyDown(ui::VKEY_9);
- PostKeyDown(ui::VKEY_8);
- PostKeyDown(ui::VKEY_9);
- PostKeyDown(ui::VKEY_7);
- PostKeyUp(ui::VKEY_9);
- PostKeyUp(ui::VKEY_7);
- PostKeyUp(ui::VKEY_8);
- run_loop.reset(new base::RunLoop(&accelerator_handler));
- run_loop->RunUntilIdle();
- // Make sure we get a key-up and key-down.
- ASSERT_EQ(5U, mtv->keys_pressed().size());
- EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
- EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]);
- EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]);
- EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]);
- EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]);
- ASSERT_EQ(3U, mtv->keys_released().size());
- EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
- EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]);
- EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]);
- EXPECT_FALSE(mtv->accelerator_pressed());
- mtv->Reset();
-
- // Now send an accelerator key sequence.
- PostKeyDown(ui::VKEY_0);
- PostKeyUp(ui::VKEY_0);
- run_loop.reset(new base::RunLoop(&accelerator_handler));
- run_loop->RunUntilIdle();
- EXPECT_TRUE(mtv->keys_pressed().empty());
- EXPECT_TRUE(mtv->keys_released().empty());
- EXPECT_TRUE(mtv->accelerator_pressed());
- mtv->Reset();
-
- // Same thing with repeat and more than one key at once.
- PostKeyDown(ui::VKEY_0);
- PostKeyDown(ui::VKEY_1);
- PostKeyDown(ui::VKEY_1);
- PostKeyDown(ui::VKEY_0);
- PostKeyDown(ui::VKEY_0);
- PostKeyUp(ui::VKEY_1);
- PostKeyUp(ui::VKEY_0);
- run_loop.reset(new base::RunLoop(&accelerator_handler));
- run_loop->RunUntilIdle();
- EXPECT_TRUE(mtv->keys_pressed().empty());
- EXPECT_TRUE(mtv->keys_released().empty());
- EXPECT_TRUE(mtv->accelerator_pressed());
- mtv->Reset();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/focus/focus_traversal_unittest.cc b/chromium/ui/views/focus/focus_traversal_unittest.cc
index c3e8159a5fa..6f0ba34ecb2 100644
--- a/chromium/ui/views/focus/focus_traversal_unittest.cc
+++ b/chromium/ui/views/focus/focus_traversal_unittest.cc
@@ -20,11 +20,12 @@
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/focus/focus_manager_test.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
+using base::ASCIIToUTF16;
+
namespace views {
namespace {
@@ -89,7 +90,7 @@ class DummyComboboxModel : public ui::ComboboxModel {
public:
// Overridden from ui::ComboboxModel:
virtual int GetItemCount() const OVERRIDE { return 10; }
- virtual string16 GetItemAt(int index) OVERRIDE {
+ virtual base::string16 GetItemAt(int index) OVERRIDE {
return ASCIIToUTF16("Item ") + base::IntToString16(index);
}
};
@@ -157,11 +158,7 @@ class BorderView : public NativeViewHost {
if (!widget_) {
widget_ = new Widget;
Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
-#if defined(OS_WIN) || defined(USE_AURA)
params.parent = details.parent->GetWidget()->GetNativeView();
-#else
- NOTREACHED();
-#endif
widget_->Init(params);
widget_->SetFocusTraversableParentView(this);
widget_->SetContentsView(child_);
@@ -294,7 +291,7 @@ void FocusTraversalTest::InitContentView() {
cb->set_id(kTopCheckBoxID);
left_container_ = new PaneView();
- left_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK));
+ left_container_->SetBorder(Border::CreateSolidBorder(1, SK_ColorBLACK));
left_container_->set_background(
Background::CreateSolidBackground(240, 240, 240));
left_container_->set_id(kLeftContainerID);
@@ -361,7 +358,7 @@ void FocusTraversalTest::InitContentView() {
y += label_height + gap_between_labels;
LabelButton* button = new LabelButton(NULL, ASCIIToUTF16("Click me"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
button->SetBounds(label_x, y + 10, 80, 30);
button->set_id(kFruitButtonID);
left_container_->AddChildView(button);
@@ -379,7 +376,7 @@ void FocusTraversalTest::InitContentView() {
left_container_->AddChildView(combobox);
right_container_ = new PaneView();
- right_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK));
+ right_container_->SetBorder(Border::CreateSolidBorder(1, SK_ColorBLACK));
right_container_->set_background(
Background::CreateSolidBackground(240, 240, 240));
right_container_->set_id(kRightContainerID);
@@ -410,7 +407,7 @@ void FocusTraversalTest::InitContentView() {
y += radio_button_height + gap_between_radio_buttons;
View* inner_container = new View();
- inner_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK));
+ inner_container->SetBorder(Border::CreateSolidBorder(1, SK_ColorBLACK));
inner_container->set_background(
Background::CreateSolidBackground(230, 230, 230));
inner_container->set_id(kInnerContainerID);
@@ -457,7 +454,7 @@ void FocusTraversalTest::InitContentView() {
y = 250;
int width = 60;
button = new LabelButton(NULL, ASCIIToUTF16("OK"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
button->set_id(kOKButtonID);
button->SetIsDefault(true);
@@ -465,13 +462,13 @@ void FocusTraversalTest::InitContentView() {
button->SetBounds(150, y, width, 30);
button = new LabelButton(NULL, ASCIIToUTF16("Cancel"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
button->set_id(kCancelButtonID);
GetContentsView()->AddChildView(button);
button->SetBounds(220, y, width, 30);
button = new LabelButton(NULL, ASCIIToUTF16("Help"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
button->set_id(kHelpButtonID);
GetContentsView()->AddChildView(button);
button->SetBounds(290, y, width, 30);
@@ -525,7 +522,7 @@ void FocusTraversalTest::InitContentView() {
text_field->set_id(kSearchTextfieldID);
button = new LabelButton(NULL, ASCIIToUTF16("Search"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
contents->AddChildView(button);
button->SetBounds(112, 5, 60, 30);
button->set_id(kSearchButtonID);
@@ -549,12 +546,12 @@ void FocusTraversalTest::InitContentView() {
contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE));
contents->set_id(kThumbnailContainerID);
button = new LabelButton(NULL, ASCIIToUTF16("Star"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
contents->AddChildView(button);
button->SetBounds(5, 5, 50, 30);
button->set_id(kThumbnailStarID);
button = new LabelButton(NULL, ASCIIToUTF16("SuperStar"));
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
contents->AddChildView(button);
button->SetBounds(60, 5, 100, 30);
button->set_id(kThumbnailSuperStarID);
@@ -579,9 +576,6 @@ TEST_F(FocusTraversalTest, NormalTraversal) {
kSearchTextfieldID, kSearchButtonID, kHelpLinkID,
kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID };
- // Uncomment the following line to manually test the UI of this test.
- // base::RunLoop(new AcceleratorHandler()).Run();
-
// Let's traverse the whole focus hierarchy (several times, to make sure it
// loops OK).
GetFocusManager()->ClearFocus();
@@ -631,9 +625,6 @@ TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) {
v->SetEnabled(false);
}
- // Uncomment the following line to manually test the UI of this test.
- // base::RunLoop(new AcceleratorHandler()).Run();
-
View* focused_view;
// Let's do one traversal (several times, to make sure it loops ok).
GetFocusManager()->ClearFocus();
@@ -682,9 +673,6 @@ TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) {
v->SetVisible(false);
}
- // Uncomment the following line to manually test the UI of this test.
- // base::RunLoop(new AcceleratorHandler()).Run();
-
View* focused_view;
// Let's do one traversal (several times, to make sure it loops ok).
GetFocusManager()->ClearFocus();
diff --git a/chromium/ui/views/focus/view_storage.h b/chromium/ui/views/focus/view_storage.h
index 629aec1cbb9..5e36f3c5e9b 100644
--- a/chromium/ui/views/focus/view_storage.h
+++ b/chromium/ui/views/focus/view_storage.h
@@ -17,7 +17,7 @@ template <typename T> struct DefaultSingletonTraits;
// used for example in the FocusManager to store/restore focused views when the
// main window becomes active/inactive.
// It automatically removes a view from the storage if the view is removed from
-// the tree hierarchy.
+// the tree hierarchy or when the view is destroyed, which ever comes first.
//
// To use it, you first need to create a view storage id that can then be used
// to store/retrieve views.
diff --git a/chromium/ui/views/ime/OWNERS b/chromium/ui/views/ime/OWNERS
index 60ba2b38ade..9f6409afd85 100644
--- a/chromium/ui/views/ime/OWNERS
+++ b/chromium/ui/views/ime/OWNERS
@@ -1,2 +1,6 @@
+# primary reviewer
+yukishiino@chromium.org
+
+# backup reviewers.
+mukai@chromium.org
nona@chromium.org
-penghuang@chromium.org
diff --git a/chromium/ui/views/ime/input_method.h b/chromium/ui/views/ime/input_method.h
index f4e8a482285..ffb5ae9c02f 100644
--- a/chromium/ui/views/ime/input_method.h
+++ b/chromium/ui/views/ime/input_method.h
@@ -34,7 +34,7 @@ class Widget;
// designed to be bound to top-level Widgets.
class VIEWS_EXPORT InputMethod {
public:
- // TODO(yukawa): Move these typedef into ime_constants.h or somewhere.
+
#if defined(OS_WIN)
typedef LRESULT NativeEventResult;
#else
@@ -94,10 +94,6 @@ class VIEWS_EXPORT InputMethod {
// tag, or an empty string if the input method cannot provide it.
virtual std::string GetInputLocale() = 0;
- // Returns the text direction of current keyboard layout or input method, or
- // base::i18n::UNKNOWN_DIRECTION if the input method cannot provide it.
- virtual base::i18n::TextDirection GetInputTextDirection() = 0;
-
// Returns true if the input method is ready to process keyboard events and
// generate composition or text results. It is not necessary to notify
// inactive input methods of caret bounds or text input type changes.
@@ -118,6 +114,9 @@ class VIEWS_EXPORT InputMethod {
// of IME popups is not supported.
virtual bool IsCandidatePopupOpen() const = 0;
+ // Displays an on screen keyboard if enabled.
+ virtual void ShowImeIfNeeded() = 0;
+
// Returns true if the input method is a mock instance used for testing.
virtual bool IsMock() const = 0;
diff --git a/chromium/ui/views/ime/input_method_bridge.cc b/chromium/ui/views/ime/input_method_bridge.cc
index f2e00ce03e1..97b040056ad 100644
--- a/chromium/ui/views/ime/input_method_bridge.cc
+++ b/chromium/ui/views/ime/input_method_bridge.cc
@@ -33,6 +33,7 @@ class InputMethodBridge::HostObserver : public ui::InputMethodObserver {
const ui::TextInputClient* client) OVERRIDE {}
virtual void OnInputMethodDestroyed(
const ui::InputMethod* input_method) OVERRIDE;
+ virtual void OnShowImeIfNeeded() OVERRIDE {}
private:
InputMethodBridge* bridge_;
@@ -159,12 +160,6 @@ std::string InputMethodBridge::GetInputLocale() {
return host_->GetInputLocale();
}
-base::i18n::TextDirection InputMethodBridge::GetInputTextDirection() {
- DCHECK(host_);
-
- return host_->GetInputTextDirection();
-}
-
bool InputMethodBridge::IsActive() {
DCHECK(host_);
@@ -177,8 +172,13 @@ bool InputMethodBridge::IsCandidatePopupOpen() const {
return host_->IsCandidatePopupOpen();
}
+void InputMethodBridge::ShowImeIfNeeded() {
+ DCHECK(host_);
+ host_->ShowImeIfNeeded();
+}
+
// Overridden from TextInputClient. Forward an event from the system-wide IME
-// to the text input |client|, which is e.g. views::NativeTextfieldViews.
+// to the text input |client|, which is e.g. views::Textfield.
void InputMethodBridge::SetCompositionText(
const ui::CompositionText& composition) {
TextInputClient* client = GetTextInputClient();
@@ -198,13 +198,13 @@ void InputMethodBridge::ClearCompositionText() {
client->ClearCompositionText();
}
-void InputMethodBridge::InsertText(const string16& text) {
+void InputMethodBridge::InsertText(const base::string16& text) {
TextInputClient* client = GetTextInputClient();
if (client)
client->InsertText(text);
}
-void InputMethodBridge::InsertChar(char16 ch, int flags) {
+void InputMethodBridge::InsertChar(base::char16 ch, int flags) {
TextInputClient* client = GetTextInputClient();
if (client)
client->InsertChar(ch, flags);
@@ -280,7 +280,7 @@ bool InputMethodBridge::DeleteRange(const gfx::Range& range) {
}
bool InputMethodBridge::GetTextFromRange(const gfx::Range& range,
- string16* text) const {
+ base::string16* text) const {
TextInputClient* client = GetTextInputClient();
return client ? client->GetTextFromRange(range, text) : false;
}
@@ -319,6 +319,13 @@ void InputMethodBridge::OnCandidateWindowUpdated() {
void InputMethodBridge::OnCandidateWindowHidden() {
}
+bool InputMethodBridge::IsEditingCommandEnabled(int command_id) {
+ return false;
+}
+
+void InputMethodBridge::ExecuteEditingCommand(int command_id) {
+}
+
// Overridden from FocusChangeListener.
void InputMethodBridge::OnWillChangeFocus(View* focused_before, View* focused) {
if (HasCompositionText()) {
diff --git a/chromium/ui/views/ime/input_method_bridge.h b/chromium/ui/views/ime/input_method_bridge.h
index 5e28a034b99..cdabecd7903 100644
--- a/chromium/ui/views/ime/input_method_bridge.h
+++ b/chromium/ui/views/ime/input_method_bridge.h
@@ -45,17 +45,17 @@ class InputMethodBridge : public InputMethodBase,
virtual void CancelComposition(View* view) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
// Overridden from TextInputClient:
virtual void SetCompositionText(
const ui::CompositionText& composition) OVERRIDE;
virtual void ConfirmCompositionText() OVERRIDE;
virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const string16& text) OVERRIDE;
- virtual void InsertChar(char16 ch, int flags) OVERRIDE;
+ virtual void InsertText(const base::string16& text) OVERRIDE;
+ virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
virtual ui::TextInputType GetTextInputType() const OVERRIDE;
virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
@@ -70,7 +70,7 @@ class InputMethodBridge : public InputMethodBase,
virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
virtual bool GetTextFromRange(const gfx::Range& range,
- string16* text) const OVERRIDE;
+ base::string16* text) const OVERRIDE;
virtual void OnInputMethodChanged() OVERRIDE;
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) OVERRIDE;
@@ -79,6 +79,8 @@ class InputMethodBridge : public InputMethodBase,
virtual void OnCandidateWindowShown() OVERRIDE;
virtual void OnCandidateWindowUpdated() OVERRIDE;
virtual void OnCandidateWindowHidden() OVERRIDE;
+ virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
+ virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
// Overridden from FocusChangeListener.
virtual void OnWillChangeFocus(View* focused_before, View* focused) OVERRIDE;
diff --git a/chromium/ui/views/ime/mock_input_method.cc b/chromium/ui/views/ime/mock_input_method.cc
index b04dafbfa63..ccc054db498 100644
--- a/chromium/ui/views/ime/mock_input_method.cc
+++ b/chromium/ui/views/ime/mock_input_method.cc
@@ -22,7 +22,6 @@ MockInputMethod::MockInputMethod()
cancel_composition_called_(false),
input_locale_changed_(false),
locale_("en-US"),
- direction_(base::i18n::LEFT_TO_RIGHT),
active_(true) {
}
@@ -35,7 +34,6 @@ MockInputMethod::MockInputMethod(internal::InputMethodDelegate* delegate)
cancel_composition_called_(false),
input_locale_changed_(false),
locale_("en-US"),
- direction_(base::i18n::LEFT_TO_RIGHT),
active_(true) {
SetDelegate(delegate);
}
@@ -90,7 +88,7 @@ void MockInputMethod::DispatchKeyEvent(const ui::KeyEvent& key) {
client->ClearCompositionText();
}
} else if (key.type() == ui::ET_KEY_PRESSED) {
- char16 ch = key.GetCharacter();
+ base::char16 ch = key.GetCharacter();
client->InsertChar(ch, key.flags());
}
}
@@ -124,10 +122,6 @@ std::string MockInputMethod::GetInputLocale() {
return locale_;
}
-base::i18n::TextDirection MockInputMethod::GetInputTextDirection() {
- return direction_;
-}
-
bool MockInputMethod::IsActive() {
return active_;
}
@@ -136,6 +130,9 @@ bool MockInputMethod::IsCandidatePopupOpen() const {
return false;
}
+void MockInputMethod::ShowImeIfNeeded() {
+}
+
bool MockInputMethod::IsMock() const {
return true;
}
@@ -159,7 +156,7 @@ void MockInputMethod::SetCompositionTextForNextKey(
composition_ = composition;
}
-void MockInputMethod::SetResultTextForNextKey(const string16& result) {
+void MockInputMethod::SetResultTextForNextKey(const base::string16& result) {
result_text_ = result;
}
@@ -170,14 +167,6 @@ void MockInputMethod::SetInputLocale(const std::string& locale) {
}
}
-void MockInputMethod::SetInputTextDirection(
- base::i18n::TextDirection direction) {
- if (direction_ != direction) {
- direction_ = direction;
- OnInputMethodChanged();
- }
-}
-
void MockInputMethod::SetActive(bool active) {
if (active_ != active) {
active_ = active;
diff --git a/chromium/ui/views/ime/mock_input_method.h b/chromium/ui/views/ime/mock_input_method.h
index fad5315d5fb..013742cff1c 100644
--- a/chromium/ui/views/ime/mock_input_method.h
+++ b/chromium/ui/views/ime/mock_input_method.h
@@ -34,9 +34,9 @@ class VIEWS_EXPORT MockInputMethod : public InputMethodBase {
virtual void CancelComposition(View* view) OVERRIDE;
virtual void OnInputLocaleChanged() OVERRIDE;
virtual std::string GetInputLocale() OVERRIDE;
- virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
virtual bool IsActive() OVERRIDE;
virtual bool IsCandidatePopupOpen() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
virtual bool IsMock() const OVERRIDE;
bool focus_changed() const { return focus_changed_; }
@@ -52,10 +52,9 @@ class VIEWS_EXPORT MockInputMethod : public InputMethodBase {
void Clear();
void SetCompositionTextForNextKey(const ui::CompositionText& composition);
- void SetResultTextForNextKey(const string16& result);
+ void SetResultTextForNextKey(const base::string16& result);
void SetInputLocale(const std::string& locale);
- void SetInputTextDirection(base::i18n::TextDirection direction);
void SetActive(bool active);
private:
@@ -75,7 +74,7 @@ class VIEWS_EXPORT MockInputMethod : public InputMethodBase {
// Result text for the next key event. It'll be cleared automatically after
// dispatching the next key event.
- string16 result_text_;
+ base::string16 result_text_;
// Record call state of corresponding methods. They will be set to false
// automatically before dispatching a key event.
@@ -88,7 +87,6 @@ class VIEWS_EXPORT MockInputMethod : public InputMethodBase {
// To mock corresponding input method prooperties.
std::string locale_;
- base::i18n::TextDirection direction_;
bool active_;
DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
diff --git a/chromium/ui/views/ime/null_input_method.cc b/chromium/ui/views/ime/null_input_method.cc
new file mode 100644
index 00000000000..666d6cfba39
--- /dev/null
+++ b/chromium/ui/views/ime/null_input_method.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/ime/null_input_method.h"
+
+namespace views {
+
+NullInputMethod::NullInputMethod() {}
+
+void NullInputMethod::SetDelegate(
+ internal::InputMethodDelegate* /* delegate */) {}
+
+void NullInputMethod::Init(Widget* /* widget */) {}
+
+void NullInputMethod::OnFocus() {}
+
+void NullInputMethod::OnBlur() {}
+
+bool NullInputMethod::OnUntranslatedIMEMessage(
+ const base::NativeEvent& /* event */,
+ NativeEventResult* /* result */) {
+ return false;
+}
+
+void NullInputMethod::DispatchKeyEvent(const ui::KeyEvent& /* key */) {}
+
+void NullInputMethod::OnTextInputTypeChanged(View* /* view */) {}
+
+void NullInputMethod::OnCaretBoundsChanged(View* /* view */) {}
+
+void NullInputMethod::CancelComposition(View* /* view */) {}
+
+void NullInputMethod::OnInputLocaleChanged() {}
+
+std::string NullInputMethod::GetInputLocale() {
+ return std::string();
+}
+
+bool NullInputMethod::IsActive() {
+ return false;
+}
+
+ui::TextInputClient* NullInputMethod::GetTextInputClient() const {
+ return NULL;
+}
+
+ui::TextInputType NullInputMethod::GetTextInputType() const {
+ return ui::TEXT_INPUT_TYPE_NONE;
+}
+
+bool NullInputMethod::IsCandidatePopupOpen() const {
+ return false;
+}
+
+void NullInputMethod::ShowImeIfNeeded() {}
+
+bool NullInputMethod::IsMock() const {
+ return false;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/ime/null_input_method.h b/chromium/ui/views/ime/null_input_method.h
new file mode 100644
index 00000000000..49234d3d551
--- /dev/null
+++ b/chromium/ui/views/ime/null_input_method.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_IME_NULL_INPUT_METHOD_H_
+#define UI_VIEWS_IME_NULL_INPUT_METHOD_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "ui/views/ime/input_method.h"
+
+namespace views {
+
+// An implementation of views::InputMethod which does nothing.
+//
+// We're working on removing views::InputMethod{,Base,Bridge} and going to use
+// only ui::InputMethod. Use this class instead of views::InputMethodBridge
+// with ui::TextInputFocusManager to effectively eliminate the
+// views::InputMethod layer.
+class NullInputMethod : public InputMethod {
+ public:
+ NullInputMethod();
+
+ // Overridden from InputMethod:
+ virtual void SetDelegate(internal::InputMethodDelegate* delegate) OVERRIDE;
+ virtual void Init(Widget* widget) OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
+ NativeEventResult* result) OVERRIDE;
+ virtual void DispatchKeyEvent(const ui::KeyEvent& key) OVERRIDE;
+ virtual void OnTextInputTypeChanged(View* view) OVERRIDE;
+ virtual void OnCaretBoundsChanged(View* view) OVERRIDE;
+ virtual void CancelComposition(View* view) OVERRIDE;
+ virtual void OnInputLocaleChanged() OVERRIDE;
+ virtual std::string GetInputLocale() OVERRIDE;
+ virtual bool IsActive() OVERRIDE;
+ virtual ui::TextInputClient* GetTextInputClient() const OVERRIDE;
+ virtual ui::TextInputType GetTextInputType() const OVERRIDE;
+ virtual bool IsCandidatePopupOpen() const OVERRIDE;
+ virtual void ShowImeIfNeeded() OVERRIDE;
+ virtual bool IsMock() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NullInputMethod);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_IME_NULL_INPUT_METHOD_H_
diff --git a/chromium/ui/views/layout/box_layout.cc b/chromium/ui/views/layout/box_layout.cc
index c11479678a9..c33264c5eeb 100644
--- a/chromium/ui/views/layout/box_layout.cc
+++ b/chromium/ui/views/layout/box_layout.cc
@@ -19,7 +19,7 @@ BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
inside_border_vertical_spacing,
inside_border_horizontal_spacing),
between_child_spacing_(between_child_spacing),
- spread_blank_space_(false) {
+ main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START) {
}
BoxLayout::~BoxLayout() {
@@ -29,38 +29,55 @@ void BoxLayout::Layout(View* host) {
gfx::Rect child_area(host->GetLocalBounds());
child_area.Inset(host->GetInsets());
child_area.Inset(inside_border_insets_);
- int x = child_area.x();
- int y = child_area.y();
int padding = 0;
- if (spread_blank_space_) {
- int total = 0;
- int visible = 0;
+ if (main_axis_alignment_ != MAIN_AXIS_ALIGNMENT_START) {
+ int total_main_axis_size = 0;
+ int num_visible = 0;
for (int i = 0; i < host->child_count(); ++i) {
View* child = host->child_at(i);
if (!child->visible())
continue;
if (orientation_ == kHorizontal) {
- total += child->GetPreferredSize().width() + between_child_spacing_;
+ total_main_axis_size +=
+ child->GetPreferredSize().width() + between_child_spacing_;
} else {
- total += child->GetHeightForWidth(child_area.width()) +
- between_child_spacing_;
+ total_main_axis_size += child->GetHeightForWidth(child_area.width()) +
+ between_child_spacing_;
}
- ++visible;
+ ++num_visible;
}
- if (visible) {
- total -= between_child_spacing_;
- if (orientation_ == kHorizontal)
- padding = (child_area.width() - total) / visible;
- else
- padding = (child_area.height() - total) / visible;
-
- if (padding < 0)
- padding = 0;
+ if (num_visible) {
+ total_main_axis_size -= between_child_spacing_;
+ int free_space = MainAxisSize(child_area) - total_main_axis_size;
+ int position = MainAxisPosition(child_area);
+ int size = MainAxisSize(child_area);
+ switch (main_axis_alignment_) {
+ case MAIN_AXIS_ALIGNMENT_FILL:
+ padding = std::max(free_space / num_visible, 0);
+ break;
+ case MAIN_AXIS_ALIGNMENT_CENTER:
+ position += free_space / 2;
+ size = total_main_axis_size;
+ break;
+ case MAIN_AXIS_ALIGNMENT_END:
+ position += free_space;
+ size = total_main_axis_size;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ gfx::Rect new_child_area(child_area);
+ SetMainAxisPosition(position, &new_child_area);
+ SetMainAxisSize(size, &new_child_area);
+ child_area.Intersect(new_child_area);
}
}
+ int x = child_area.x();
+ int y = child_area.y();
for (int i = 0; i < host->child_count(); ++i) {
View* child = host->child_at(i);
if (child->visible()) {
@@ -81,12 +98,12 @@ void BoxLayout::Layout(View* host) {
}
}
-gfx::Size BoxLayout::GetPreferredSize(View* host) {
+gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
// Calculate the child views' preferred width.
int width = 0;
if (orientation_ == kVertical) {
for (int i = 0; i < host->child_count(); ++i) {
- View* child = host->child_at(i);
+ const View* child = host->child_at(i);
if (!child->visible())
continue;
@@ -97,13 +114,35 @@ gfx::Size BoxLayout::GetPreferredSize(View* host) {
return GetPreferredSizeForChildWidth(host, width);
}
-int BoxLayout::GetPreferredHeightForWidth(View* host, int width) {
+int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
int child_width = width - NonChildSize(host).width();
return GetPreferredSizeForChildWidth(host, child_width).height();
}
-gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host,
- int child_area_width) {
+int BoxLayout::MainAxisSize(const gfx::Rect& child_area) const {
+ return orientation_ == kHorizontal ? child_area.width() : child_area.height();
+}
+
+int BoxLayout::MainAxisPosition(const gfx::Rect& child_area) const {
+ return orientation_ == kHorizontal ? child_area.x() : child_area.y();
+}
+
+void BoxLayout::SetMainAxisSize(int size, gfx::Rect* child_area) const {
+ if (orientation_ == kHorizontal)
+ child_area->set_width(size);
+ else
+ child_area->set_height(size);
+}
+
+void BoxLayout::SetMainAxisPosition(int position, gfx::Rect* child_area) const {
+ if (orientation_ == kHorizontal)
+ child_area->set_x(position);
+ else
+ child_area->set_y(position);
+}
+
+gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host,
+ int child_area_width) const {
gfx::Rect child_area_bounds;
if (orientation_ == kHorizontal) {
@@ -112,7 +151,7 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host,
// TODO(estade): fix this if it ever becomes a problem.
int position = 0;
for (int i = 0; i < host->child_count(); ++i) {
- View* child = host->child_at(i);
+ const View* child = host->child_at(i);
if (!child->visible())
continue;
@@ -127,7 +166,7 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host,
} else {
int height = 0;
for (int i = 0; i < host->child_count(); ++i) {
- View* child = host->child_at(i);
+ const View* child = host->child_at(i);
if (!child->visible())
continue;
@@ -147,7 +186,7 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host,
child_area_bounds.height() + non_child_size.height());
}
-gfx::Size BoxLayout::NonChildSize(View* host) {
+gfx::Size BoxLayout::NonChildSize(const View* host) const {
gfx::Insets insets(host->GetInsets());
return gfx::Size(insets.width() + inside_border_insets_.width(),
insets.height() + inside_border_insets_.height());
diff --git a/chromium/ui/views/layout/box_layout.h b/chromium/ui/views/layout/box_layout.h
index 7670d8cb05e..e1d22ac91a2 100644
--- a/chromium/ui/views/layout/box_layout.h
+++ b/chromium/ui/views/layout/box_layout.h
@@ -11,6 +11,7 @@
#include "ui/views/layout/layout_manager.h"
namespace gfx {
+class Rect;
class Size;
}
@@ -30,6 +31,25 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
kVertical,
};
+ // This specifies where along the main axis the children should be laid out.
+ // e.g. a horizontal layout of MAIN_AXIS_ALIGNMENT_END will result in the
+ // child views being right-aligned.
+ enum MainAxisAlignment {
+ MAIN_AXIS_ALIGNMENT_START,
+ MAIN_AXIS_ALIGNMENT_CENTER,
+ MAIN_AXIS_ALIGNMENT_END,
+
+ // This distributes extra space among the child views. This increases the
+ // size of child views along the main axis rather than the space between
+ // them.
+ MAIN_AXIS_ALIGNMENT_FILL,
+ // TODO(calamity): Add MAIN_AXIS_ALIGNMENT_JUSTIFY which spreads blank space
+ // in-between the child views.
+ };
+
+ // TODO(calamity): Add CrossAxisAlignment property to allow cross axis
+ // alignment.
+
// Use |inside_border_horizontal_spacing| and
// |inside_border_vertical_spacing| to add additional space between the child
// view area and the host view border. |between_child_spacing| controls the
@@ -40,22 +60,36 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
int between_child_spacing);
virtual ~BoxLayout();
- void set_spread_blank_space(bool spread) {
- spread_blank_space_ = spread;
+ void set_main_axis_alignment(MainAxisAlignment main_axis_alignment) {
+ main_axis_alignment_ = main_axis_alignment;
+ }
+
+ void set_inside_border_insets(const gfx::Insets& insets) {
+ inside_border_insets_ = insets;
}
// Overridden from views::LayoutManager:
virtual void Layout(View* host) OVERRIDE;
- virtual gfx::Size GetPreferredSize(View* host) OVERRIDE;
- virtual int GetPreferredHeightForWidth(View* host, int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize(const View* host) const OVERRIDE;
+ virtual int GetPreferredHeightForWidth(const View* host,
+ int width) const OVERRIDE;
private:
+ // Returns the size and position along the main axis of |child_area|.
+ int MainAxisSize(const gfx::Rect& child_area) const;
+ int MainAxisPosition(const gfx::Rect& child_area) const;
+
+ // Sets the size and position along the main axis of |child_area|.
+ void SetMainAxisSize(int size, gfx::Rect* child_area) const;
+ void SetMainAxisPosition(int position, gfx::Rect* child_area) const;
+
// The preferred size for the dialog given the width of the child area.
- gfx::Size GetPreferredSizeForChildWidth(View* host, int child_area_width);
+ gfx::Size GetPreferredSizeForChildWidth(const View* host,
+ int child_area_width) const;
// The amount of space the layout requires in addition to any space for the
// child views.
- gfx::Size NonChildSize(View* host);
+ gfx::Size NonChildSize(const View* host) const;
const Orientation orientation_;
@@ -65,9 +99,9 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
// Spacing to put in between child views.
const int between_child_spacing_;
- // Whether the available extra space should be distributed among the child
- // views.
- bool spread_blank_space_;
+ // The alignment of children in the main axis. This is
+ // MAIN_AXIS_ALIGNMENT_START by default.
+ MainAxisAlignment main_axis_alignment_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BoxLayout);
};
diff --git a/chromium/ui/views/layout/box_layout_unittest.cc b/chromium/ui/views/layout/box_layout_unittest.cc
index 2c12090685e..42f8f4272c6 100644
--- a/chromium/ui/views/layout/box_layout_unittest.cc
+++ b/chromium/ui/views/layout/box_layout_unittest.cc
@@ -55,6 +55,27 @@ TEST_F(BoxLayoutTest, AlignmentVertical) {
EXPECT_EQ(gfx::Rect(0, 10, 20, 10), v2->bounds());
}
+TEST_F(BoxLayoutTest, SetInsideBorderInsets) {
+ layout_.reset(new BoxLayout(BoxLayout::kHorizontal, 10, 20, 0));
+ View* v1 = new StaticSizedView(gfx::Size(10, 20));
+ host_->AddChildView(v1);
+ View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+ EXPECT_EQ(gfx::Size(40, 60), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 40, 60);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 20, 10, 20), v1->bounds());
+ EXPECT_EQ(gfx::Rect(20, 20, 10, 20), v2->bounds());
+
+ layout_->set_inside_border_insets(
+ gfx::Insets(5, 10, 15, 20));
+ EXPECT_EQ(gfx::Size(50, 40), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 50, 40);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 5, 10, 20), v1->bounds());
+ EXPECT_EQ(gfx::Rect(20, 5, 10, 20), v2->bounds());
+}
+
TEST_F(BoxLayoutTest, Spacing) {
layout_.reset(new BoxLayout(BoxLayout::kHorizontal, 7, 7, 8));
View* v1 = new StaticSizedView(gfx::Size(10, 20));
@@ -75,6 +96,25 @@ TEST_F(BoxLayoutTest, Overflow) {
View* v2 = new StaticSizedView(gfx::Size(10, 20));
host_->AddChildView(v2);
host_->SetBounds(0, 0, 10, 10);
+
+ // Overflows by positioning views at the start and truncating anything that
+ // doesn't fit.
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+
+ // All values of main axis alignment should overflow in the same manner.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
layout_->Layout(host_.get());
EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
@@ -102,9 +142,9 @@ TEST_F(BoxLayoutTest, InvisibleChild) {
EXPECT_EQ(gfx::Rect(10, 10, 10, 10), v2->bounds());
}
-TEST_F(BoxLayoutTest, DistributeEmptySpace) {
+TEST_F(BoxLayoutTest, MainAxisAlignmentFill) {
layout_.reset(new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10));
- layout_->set_spread_blank_space(true);
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_FILL);
View* v1 = new StaticSizedView(gfx::Size(20, 20));
host_->AddChildView(v1);
@@ -156,4 +196,74 @@ TEST_F(BoxLayoutTest, EmptyPreferredSize) {
}
}
+TEST_F(BoxLayoutTest, MainAxisAlignmentHorizontal) {
+ layout_.reset(new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10));
+
+ View* v1 = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(v1);
+ View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+
+ host_->SetBounds(0, 0, 100, 40);
+
+ // Align children to the horizontal start by default.
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(40, 10, 10, 20).ToString(), v2->bounds().ToString());
+
+ // Ensure same results for MAIN_AXIS_ALIGNMENT_START.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(40, 10, 10, 20).ToString(), v2->bounds().ToString());
+
+ // Aligns children to the center horizontally.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(30, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(60, 10, 10, 20).ToString(), v2->bounds().ToString());
+
+ // Aligns children to the end of the host horizontally, accounting for the
+ // inside border spacing.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(50, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(80, 10, 10, 20).ToString(), v2->bounds().ToString());
+}
+
+TEST_F(BoxLayoutTest, MainAxisAlignmentVertical) {
+ layout_.reset(new BoxLayout(BoxLayout::kVertical, 10, 10, 10));
+
+ View* v1 = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(v1);
+ View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+
+ host_->SetBounds(0, 0, 40, 100);
+
+ // Align children to the vertical start by default.
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(10, 40, 20, 10).ToString(), v2->bounds().ToString());
+
+ // Ensure same results for MAIN_AXIS_ALIGNMENT_START.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(10, 40, 20, 10).ToString(), v2->bounds().ToString());
+
+ // Aligns children to the center vertically.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 30, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(10, 60, 20, 10).ToString(), v2->bounds().ToString());
+
+ // Aligns children to the end of the host vertically, accounting for the
+ // inside border spacing.
+ layout_->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 50, 20, 20).ToString(), v1->bounds().ToString());
+ EXPECT_EQ(gfx::Rect(10, 80, 20, 10).ToString(), v2->bounds().ToString());
+}
+
} // namespace views
diff --git a/chromium/ui/views/layout/fill_layout.cc b/chromium/ui/views/layout/fill_layout.cc
index 54893671f58..21375461210 100644
--- a/chromium/ui/views/layout/fill_layout.cc
+++ b/chromium/ui/views/layout/fill_layout.cc
@@ -20,7 +20,7 @@ void FillLayout::Layout(View* host) {
frame_view->SetBoundsRect(host->GetContentsBounds());
}
-gfx::Size FillLayout::GetPreferredSize(View* host) {
+gfx::Size FillLayout::GetPreferredSize(const View* host) const {
if (!host->has_children())
return gfx::Size();
DCHECK_EQ(1, host->child_count());
@@ -29,7 +29,7 @@ gfx::Size FillLayout::GetPreferredSize(View* host) {
return rect.size();
}
-int FillLayout::GetPreferredHeightForWidth(View* host, int width) {
+int FillLayout::GetPreferredHeightForWidth(const View* host, int width) const {
if (!host->has_children())
return 0;
DCHECK_EQ(1, host->child_count());
diff --git a/chromium/ui/views/layout/fill_layout.h b/chromium/ui/views/layout/fill_layout.h
index 67c7f831457..f50bde0c6c7 100644
--- a/chromium/ui/views/layout/fill_layout.h
+++ b/chromium/ui/views/layout/fill_layout.h
@@ -25,8 +25,9 @@ class VIEWS_EXPORT FillLayout : public LayoutManager {
// Overridden from LayoutManager:
virtual void Layout(View* host) OVERRIDE;
- virtual gfx::Size GetPreferredSize(View* host) OVERRIDE;
- virtual int GetPreferredHeightForWidth(View* host, int width) OVERRIDE;
+ virtual gfx::Size GetPreferredSize(const View* host) const OVERRIDE;
+ virtual int GetPreferredHeightForWidth(const View* host,
+ int width) const OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(FillLayout);
diff --git a/chromium/ui/views/layout/grid_layout.cc b/chromium/ui/views/layout/grid_layout.cc
index e4bf19d47c8..7ab81083c34 100644
--- a/chromium/ui/views/layout/grid_layout.cc
+++ b/chromium/ui/views/layout/grid_layout.cc
@@ -57,7 +57,8 @@ class LayoutElement {
for (typename std::vector<T*>::iterator i = elements->begin();
i != elements->end(); ++i) {
total_percent += (*i)->ResizePercent();
- resize_count++;
+ if ((*i)->ResizePercent() > 0)
+ resize_count++;
}
if (total_percent == 0) {
// None of the elements are resizable, return.
@@ -161,7 +162,6 @@ class Column : public LayoutElement {
GridLayout::SizeType size_type,
int fixed_width,
int min_width,
- size_t index,
bool is_padding)
: LayoutElement(resize_percent),
h_align_(h_align),
@@ -170,7 +170,6 @@ class Column : public LayoutElement {
same_size_column_(-1),
fixed_width_(fixed_width),
min_width_(min_width),
- index_(index),
is_padding_(is_padding),
master_column_(NULL) {}
@@ -200,9 +199,6 @@ class Column : public LayoutElement {
const int fixed_width_;
const int min_width_;
- // Index of this column in the ColumnSet.
- const size_t index_;
-
const bool is_padding_;
// If multiple columns have their sizes linked, one is the
@@ -263,10 +259,8 @@ void Column::AdjustSize(int size) {
class Row : public LayoutElement {
public:
- Row(bool fixed_height, int height, float resize_percent,
- ColumnSet* column_set)
+ Row(int height, float resize_percent, ColumnSet* column_set)
: LayoutElement(resize_percent),
- fixed_height_(fixed_height),
height_(height),
column_set_(column_set),
max_ascent_(0),
@@ -300,7 +294,6 @@ class Row : public LayoutElement {
}
private:
- const bool fixed_height_;
const int height_;
// The column set used for this row; null for padding rows.
ColumnSet* column_set_;
@@ -421,17 +414,16 @@ void ColumnSet::AddColumn(GridLayout::Alignment h_align,
int min_width,
bool is_padding) {
Column* column = new Column(h_align, v_align, resize_percent, size_type,
- fixed_width, min_width, columns_.size(),
- is_padding);
+ fixed_width, min_width, is_padding);
columns_.push_back(column);
}
void ColumnSet::AddViewState(ViewState* view_state) {
// view_states are ordered by column_span (in ascending order).
- std::vector<ViewState*>::iterator i = lower_bound(view_states_.begin(),
- view_states_.end(),
- view_state,
- CompareByColumnSpan);
+ std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
+ view_states_.end(),
+ view_state,
+ CompareByColumnSpan);
view_states_.insert(i, view_state);
}
@@ -503,8 +495,8 @@ void ColumnSet::AccumulateMasterColumns() {
Column* column = *i;
Column* master_column = column->GetLastMasterColumn();
if (master_column &&
- find(master_columns_.begin(), master_columns_.end(),
- master_column) == master_columns_.end()) {
+ std::find(master_columns_.begin(), master_columns_.end(),
+ master_column) == master_columns_.end()) {
master_columns_.push_back(master_column);
}
// At this point, GetLastMasterColumn may not == master_column
@@ -717,11 +709,11 @@ void GridLayout::StartRowWithPadding(float vertical_resize, int column_set_id,
void GridLayout::StartRow(float vertical_resize, int column_set_id) {
ColumnSet* column_set = GetColumnSet(column_set_id);
DCHECK(column_set);
- AddRow(new Row(false, 0, vertical_resize, column_set));
+ AddRow(new Row(0, vertical_resize, column_set));
}
void GridLayout::AddPaddingRow(float vertical_resize, int pixel_count) {
- AddRow(new Row(true, pixel_count, vertical_resize, NULL));
+ AddRow(new Row(pixel_count, vertical_resize, NULL));
}
void GridLayout::SkipColumns(int col_count) {
@@ -836,7 +828,7 @@ void GridLayout::Layout(View* host) {
}
}
-gfx::Size GridLayout::GetPreferredSize(View* host) {
+gfx::Size GridLayout::GetPreferredSize(const View* host) const {
DCHECK(host_ == host);
gfx::Size out;
SizeRowsAndColumns(false, 0, 0, &out);
@@ -845,7 +837,7 @@ gfx::Size GridLayout::GetPreferredSize(View* host) {
return out;
}
-int GridLayout::GetPreferredHeightForWidth(View* host, int width) {
+int GridLayout::GetPreferredHeightForWidth(const View* host, int width) const {
DCHECK(host_ == host);
gfx::Size pref;
SizeRowsAndColumns(false, width, 0, &pref);
@@ -853,7 +845,7 @@ int GridLayout::GetPreferredHeightForWidth(View* host, int width) {
}
void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
- gfx::Size* pref) {
+ gfx::Size* pref) const {
// Make sure the master columns have been calculated.
CalculateMasterColumnsIfNecessary();
pref->SetSize(0, 0);
@@ -958,7 +950,7 @@ void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
}
}
-void GridLayout::CalculateMasterColumnsIfNecessary() {
+void GridLayout::CalculateMasterColumnsIfNecessary() const {
if (!calculated_master_columns_) {
calculated_master_columns_ = true;
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
@@ -980,10 +972,10 @@ void GridLayout::AddViewState(ViewState* view_state) {
next_column_ += view_state->col_span;
current_row_col_set_->AddViewState(view_state);
// view_states are ordered by row_span (in ascending order).
- std::vector<ViewState*>::iterator i = lower_bound(view_states_.begin(),
- view_states_.end(),
- view_state,
- CompareByRowSpan);
+ std::vector<ViewState*>::iterator i = std::lower_bound(view_states_.begin(),
+ view_states_.end(),
+ view_state,
+ CompareByRowSpan);
view_states_.insert(i, view_state);
SkipPaddingColumns();
}
@@ -1003,14 +995,14 @@ void GridLayout::AddRow(Row* row) {
SkipPaddingColumns();
}
-void GridLayout::UpdateRemainingHeightFromRows(ViewState* view_state) {
+void GridLayout::UpdateRemainingHeightFromRows(ViewState* view_state) const {
for (int i = 0, start_row = view_state->start_row;
i < view_state->row_span; ++i) {
view_state->remaining_height -= rows_[i + start_row]->Size();
}
}
-void GridLayout::DistributeRemainingHeight(ViewState* view_state) {
+void GridLayout::DistributeRemainingHeight(ViewState* view_state) const {
int height = view_state->remaining_height;
if (height <= 0)
return;
diff --git a/chromium/ui/views/layout/grid_layout.h b/chromium/ui/views/layout/grid_layout.h
index f026eb7915f..ea578c8ad57 100644
--- a/chromium/ui/views/layout/grid_layout.h
+++ b/chromium/ui/views/layout/grid_layout.h
@@ -178,9 +178,10 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
virtual void Layout(View* host) OVERRIDE;
// Returns the preferred size for the GridLayout.
- virtual gfx::Size GetPreferredSize(View* host) OVERRIDE;
+ virtual gfx::Size GetPreferredSize(const View* host) const OVERRIDE;
- virtual int GetPreferredHeightForWidth(View* host, int width) OVERRIDE;
+ virtual int GetPreferredHeightForWidth(const View* host,
+ int width) const OVERRIDE;
void set_minimum_size(const gfx::Size& size) { minimum_size_ = size; }
@@ -189,11 +190,14 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
// they both call into this method. This sizes the Columns/Rows as
// appropriate. If layout is true, width/height give the width/height the
// of the host, otherwise they are ignored.
- void SizeRowsAndColumns(bool layout, int width, int height, gfx::Size* pref);
+ void SizeRowsAndColumns(bool layout,
+ int width,
+ int height,
+ gfx::Size* pref) const;
// Calculates the master columns of all the column sets. See Column for
// a description of what a master column is.
- void CalculateMasterColumnsIfNecessary();
+ void CalculateMasterColumnsIfNecessary() const;
// This is called internally from AddView. It adds the ViewState to the
// appropriate structures, and updates internal fields such as next_column_.
@@ -205,12 +209,12 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
// As the name says, updates the remaining_height of the ViewState for
// all Rows the supplied ViewState touches.
- void UpdateRemainingHeightFromRows(ViewState* state);
+ void UpdateRemainingHeightFromRows(ViewState* state) const;
// If the view state's remaining height is > 0, it is distributed among
// the rows the view state touches. This is used during layout to make
// sure the Rows can accommodate a view.
- void DistributeRemainingHeight(ViewState* state);
+ void DistributeRemainingHeight(ViewState* state) const;
// Advances next_column_ past any padding columns.
void SkipPaddingColumns();
@@ -222,7 +226,7 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
View* const host_;
// Whether or not we've calculated the master/linked columns.
- bool calculated_master_columns_;
+ mutable bool calculated_master_columns_;
// Used to verify a view isn't added with a row span that expands into
// another column structure.
@@ -244,13 +248,13 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
bool adding_view_;
// ViewStates. This is ordered by row_span in ascending order.
- std::vector<ViewState*> view_states_;
+ mutable std::vector<ViewState*> view_states_;
// ColumnSets.
- std::vector<ColumnSet*> column_sets_;
+ mutable std::vector<ColumnSet*> column_sets_;
// Rows.
- std::vector<Row*> rows_;
+ mutable std::vector<Row*> rows_;
// Minimum preferred size.
gfx::Size minimum_size_;
@@ -267,10 +271,11 @@ class VIEWS_EXPORT ColumnSet {
// Adds a column for padding. When adding views, padding columns are
// automatically skipped. For example, if you create a column set with
- // two columns separated by a padding column, the first AddView automatically
+ // two columns separated by a padding column, the second AddView automatically
// skips past the padding column. That is, to add two views, do:
// layout->AddView(v1); layout->AddView(v2);, not:
// layout->AddView(v1); layout->SkipColumns(1); layout->AddView(v2);
+ // See class description for details on |resize_percent|.
void AddPaddingColumn(float resize_percent, int width);
// Adds a column. The alignment gives the default alignment for views added
@@ -282,6 +287,7 @@ class VIEWS_EXPORT ColumnSet {
// made as wide as the widest views in each column, even if extra space is
// provided. In other words, GridLayout does not automatically resize views
// unless the column is marked as resizable.
+ // See class description for details on |resize_percent|.
void AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
diff --git a/chromium/ui/views/layout/grid_layout_unittest.cc b/chromium/ui/views/layout/grid_layout_unittest.cc
index 71988d870b6..ea7d231f04b 100644
--- a/chromium/ui/views/layout/grid_layout_unittest.cc
+++ b/chromium/ui/views/layout/grid_layout_unittest.cc
@@ -24,7 +24,7 @@ class SettableSizeView : public View {
pref_ = pref;
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return pref_;
}
@@ -39,11 +39,11 @@ class FlexibleView : public View {
circumference_ = circumference;
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
return gfx::Size(0, circumference_ / 2);
}
- virtual int GetHeightForWidth(int width) OVERRIDE {
+ virtual int GetHeightForWidth(int width) const OVERRIDE {
return std::max(0, circumference_ / 2 - width);
}
@@ -346,6 +346,33 @@ TEST_F(GridLayoutTest, HorizontalResizeTest2) {
RemoveAll();
}
+// Tests that space leftover due to rounding is distributed to the last
+// resizable column.
+TEST_F(GridLayoutTest, HorizontalResizeTest3) {
+ SettableSizeView v1(gfx::Size(10, 10));
+ SettableSizeView v2(gfx::Size(10, 10));
+ SettableSizeView v3(gfx::Size(10, 10));
+ ColumnSet* c1 = layout.AddColumnSet(0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING,
+ 1, GridLayout::USE_PREF, 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING,
+ 1, GridLayout::USE_PREF, 0, 0);
+ c1->AddColumn(GridLayout::TRAILING, GridLayout::LEADING,
+ 0, GridLayout::USE_PREF, 0, 0);
+ layout.StartRow(0, 0);
+ layout.AddView(&v1);
+ layout.AddView(&v2);
+ layout.AddView(&v3);
+
+ host.SetBounds(0, 0, 31, 10);
+ layout.Layout(&host);
+ ExpectViewBoundsEquals(0, 0, 10, 10, &v1);
+ ExpectViewBoundsEquals(10, 0, 11, 10, &v2);
+ ExpectViewBoundsEquals(21, 0, 10, 10, &v3);
+
+ RemoveAll();
+}
+
TEST_F(GridLayoutTest, TestVerticalResize1) {
SettableSizeView v1(gfx::Size(50, 20));
SettableSizeView v2(gfx::Size(10, 10));
diff --git a/chromium/ui/views/layout/layout_manager.cc b/chromium/ui/views/layout/layout_manager.cc
index 188cc6f14fc..9a79ce75832 100644
--- a/chromium/ui/views/layout/layout_manager.cc
+++ b/chromium/ui/views/layout/layout_manager.cc
@@ -17,7 +17,8 @@ void LayoutManager::Installed(View* host) {
void LayoutManager::Uninstalled(View* host) {
}
-int LayoutManager::GetPreferredHeightForWidth(View* host, int width) {
+int LayoutManager::GetPreferredHeightForWidth(const View* host,
+ int width) const {
return GetPreferredSize(host).height();
}
diff --git a/chromium/ui/views/layout/layout_manager.h b/chromium/ui/views/layout/layout_manager.h
index f678e721179..d10e09ed381 100644
--- a/chromium/ui/views/layout/layout_manager.h
+++ b/chromium/ui/views/layout/layout_manager.h
@@ -42,11 +42,11 @@ class VIEWS_EXPORT LayoutManager {
// Return the preferred size which is the size required to give each
// children their respective preferred size.
- virtual gfx::Size GetPreferredSize(View* host) = 0;
+ virtual gfx::Size GetPreferredSize(const View* host) const = 0;
// Returns the preferred height for the specified width. The default
// implementation returns the value from GetPreferredSize.
- virtual int GetPreferredHeightForWidth(View* host, int width);
+ virtual int GetPreferredHeightForWidth(const View* host, int width) const;
// Notification that a view has been added.
virtual void ViewAdded(View* host, View* view);
diff --git a/chromium/ui/views/linux_ui/linux_ui.cc b/chromium/ui/views/linux_ui/linux_ui.cc
index 6a35040f4f8..63c74020c19 100644
--- a/chromium/ui/views/linux_ui/linux_ui.cc
+++ b/chromium/ui/views/linux_ui/linux_ui.cc
@@ -5,6 +5,7 @@
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+#include "ui/gfx/linux_font_delegate.h"
#include "ui/shell_dialogs/linux_shell_dialog.h"
namespace {
@@ -19,7 +20,9 @@ void LinuxUI::SetInstance(LinuxUI* instance) {
delete g_linux_ui;
g_linux_ui = instance;
LinuxInputMethodContextFactory::SetInstance(instance);
+ LinuxFontDelegate::SetInstance(instance);
LinuxShellDialog::SetInstance(instance);
+ ui::SetTextEditKeyBindingsDelegate(instance);
}
LinuxUI* LinuxUI::instance() {
diff --git a/chromium/ui/views/linux_ui/linux_ui.gyp b/chromium/ui/views/linux_ui/linux_ui.gyp
index 1f87a1a01ee..5ba78e52baf 100644
--- a/chromium/ui/views/linux_ui/linux_ui.gyp
+++ b/chromium/ui/views/linux_ui/linux_ui.gyp
@@ -14,9 +14,9 @@
'../../base/base.gyp:base',
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../../skia/skia.gyp:skia',
+ '../base/ui_base.gyp:ui_base',
'../native_theme/native_theme.gyp:native_theme',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
],
'defines': [
'LINUX_UI_IMPLEMENTATION',
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index 152b364282d..b5466f57ef5 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -5,15 +5,25 @@
#ifndef UI_VIEWS_LINUX_UI_LINUX_UI_H_
#define UI_VIEWS_LINUX_UI_LINUX_UI_H_
+#include <string>
+
+#include "base/callback.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
+#include "ui/gfx/linux_font_delegate.h"
#include "ui/shell_dialogs/linux_shell_dialog.h"
+#include "ui/views/controls/button/button.h"
#include "ui/views/linux_ui/status_icon_linux.h"
#include "ui/views/views_export.h"
// The main entrypoint into Linux toolkit specific code. GTK code should only
// be executed behind this interface.
+namespace aura {
+class Window;
+}
+
namespace gfx {
class Image;
}
@@ -23,6 +33,10 @@ class NativeTheme;
}
namespace views {
+class Border;
+class LabelButton;
+class LabelButtonBorder;
+class View;
class WindowButtonOrderObserver;
// Adapter class with targets to render like different toolkits. Set by any
@@ -33,8 +47,22 @@ class WindowButtonOrderObserver;
// complex method that pokes around with dlopen against a libuigtk2.so, a
// liuigtk3.so, etc.
class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
- public ui::LinuxShellDialog {
+ public gfx::LinuxFontDelegate,
+ public ui::LinuxShellDialog,
+ public ui::TextEditKeyBindingsDelegateAuraLinux {
public:
+ // Describes the window management actions that could be taken in response to
+ // a middle click in the non client area.
+ enum NonClientMiddleClickAction {
+ MIDDLE_CLICK_ACTION_NONE,
+ MIDDLE_CLICK_ACTION_LOWER,
+ MIDDLE_CLICK_ACTION_MINIMIZE,
+ MIDDLE_CLICK_ACTION_TOGGLE_MAXIMIZE
+ };
+
+ typedef base::Callback<ui::NativeTheme*(aura::Window* window)>
+ NativeThemeGetter;
+
virtual ~LinuxUI() {}
// Sets the dynamically loaded singleton that draws the desktop native UI.
@@ -67,9 +95,10 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
// Returns a NativeTheme that will provide system colors and draw system
// style widgets.
- virtual ui::NativeTheme* GetNativeTheme() const = 0;
+ virtual ui::NativeTheme* GetNativeTheme(aura::Window* window) const = 0;
- virtual void SetUseSystemTheme(bool use_system_theme) = 0;
+ // Used to set an override NativeTheme.
+ virtual void SetNativeThemeOverride(const NativeThemeGetter& callback) = 0;
// Returns whether we should be using the native theme provided by this
// object by default.
@@ -86,7 +115,7 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
// Create a native status icon.
virtual scoped_ptr<StatusIconLinux> CreateLinuxStatusIcon(
const gfx::ImageSkia& image,
- const string16& tool_tip) const = 0;
+ const base::string16& tool_tip) const = 0;
// Returns the icon for a given content type from the icon theme.
// TODO(davidben): Add an observer for the theme changing, so we can drop the
@@ -94,6 +123,11 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
virtual gfx::Image GetIconForContentType(
const std::string& content_type, int size) const = 0;
+ // Builds a Border which paints the native button style.
+ virtual scoped_ptr<Border> CreateNativeBorder(
+ views::LabelButton* owning_button,
+ scoped_ptr<views::LabelButtonBorder> border) = 0;
+
// Notifies the observer about changes about how window buttons should be
// laid out. If the order is anything other than the default min,max,close on
// the right, will immediately send a button change event to the observer.
@@ -106,6 +140,16 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
// Determines whether the user's window manager is Unity.
virtual bool UnityIsRunning() = 0;
+
+ // What action we should take when the user middle clicks on non-client
+ // area. The default is lowering the window.
+ virtual NonClientMiddleClickAction GetNonClientMiddleClickAction() = 0;
+
+ // Notifies the window manager that start up has completed.
+ // Normally Chromium opens a new window on startup and GTK does this
+ // automatically. In case Chromium does not open a new window on startup,
+ // e.g. an existing browser window already exists, this should be called.
+ virtual void NotifyWindowManagerStartupComplete() = 0;
};
} // namespace views
diff --git a/chromium/ui/views/linux_ui/status_icon_linux.h b/chromium/ui/views/linux_ui/status_icon_linux.h
index 5ed8be21a7e..b7ed3c72295 100644
--- a/chromium/ui/views/linux_ui/status_icon_linux.h
+++ b/chromium/ui/views/linux_ui/status_icon_linux.h
@@ -38,7 +38,7 @@ class VIEWS_EXPORT StatusIconLinux {
virtual void SetImage(const gfx::ImageSkia& image) = 0;
virtual void SetPressedImage(const gfx::ImageSkia& image) = 0;
- virtual void SetToolTip(const string16& tool_tip) = 0;
+ virtual void SetToolTip(const base::string16& tool_tip) = 0;
// Invoked after a call to SetContextMenu() to let the platform-specific
// subclass update the native context menu based on the new model. The
diff --git a/chromium/ui/views/linux_ui/window_button_order_provider.cc b/chromium/ui/views/linux_ui/window_button_order_provider.cc
new file mode 100644
index 00000000000..903247883b8
--- /dev/null
+++ b/chromium/ui/views/linux_ui/window_button_order_provider.cc
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/window/window_button_order_provider.h"
+
+#include "ui/views/linux_ui/linux_ui.h"
+#include "ui/views/linux_ui/window_button_order_observer.h"
+
+namespace views {
+
+namespace {
+
+class WindowButtonOrderObserverDelegate : public WindowButtonOrderProvider,
+ public WindowButtonOrderObserver {
+ public:
+ WindowButtonOrderObserverDelegate();
+ virtual ~WindowButtonOrderObserverDelegate();
+
+ // WindowButtonOrderObserver:
+ virtual void OnWindowButtonOrderingChange(
+ const std::vector<views::FrameButton>& leading_buttons,
+ const std::vector<views::FrameButton>& trailing_buttons) OVERRIDE;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WindowButtonOrderObserverDelegate);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowButtonOrderObserverDelegate, public:
+
+WindowButtonOrderObserverDelegate::WindowButtonOrderObserverDelegate() {
+ views::LinuxUI* ui = views::LinuxUI::instance();
+ if (ui)
+ ui->AddWindowButtonOrderObserver(this);
+}
+
+WindowButtonOrderObserverDelegate::~WindowButtonOrderObserverDelegate() {
+ views::LinuxUI* ui = views::LinuxUI::instance();
+ if (ui)
+ ui->RemoveWindowButtonOrderObserver(this);
+}
+
+void WindowButtonOrderObserverDelegate::OnWindowButtonOrderingChange(
+ const std::vector<views::FrameButton>& leading_buttons,
+ const std::vector<views::FrameButton>& trailing_buttons) {
+ SetWindowButtonOrder(leading_buttons, trailing_buttons);
+}
+
+} // namespace
+
+// static
+WindowButtonOrderProvider* WindowButtonOrderProvider::instance_ = NULL;
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowButtonOrderProvider, public:
+
+// static
+WindowButtonOrderProvider* WindowButtonOrderProvider::GetInstance() {
+ if (!instance_)
+ instance_ = new WindowButtonOrderObserverDelegate;
+ return instance_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowButtonOrderProvider, protected:
+
+WindowButtonOrderProvider::WindowButtonOrderProvider() {
+ trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
+ trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
+ trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
+}
+
+WindowButtonOrderProvider::~WindowButtonOrderProvider() {
+}
+
+void WindowButtonOrderProvider::SetWindowButtonOrder(
+ const std::vector<views::FrameButton>& leading_buttons,
+ const std::vector<views::FrameButton>& trailing_buttons) {
+ leading_buttons_ = leading_buttons;
+ trailing_buttons_ = trailing_buttons;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/masked_view_targeter.cc b/chromium/ui/views/masked_view_targeter.cc
new file mode 100644
index 00000000000..112df676808
--- /dev/null
+++ b/chromium/ui/views/masked_view_targeter.cc
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/masked_view_targeter.h"
+
+#include "ui/gfx/path.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+MaskedViewTargeter::MaskedViewTargeter(View* masked_view)
+ : masked_view_(masked_view) {
+}
+
+MaskedViewTargeter::~MaskedViewTargeter() {
+}
+
+bool MaskedViewTargeter::EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ View* view = static_cast<View*>(target);
+ if (view == masked_view_) {
+ gfx::Path mask;
+ if (!GetHitTestMask(view, &mask))
+ return ViewTargeter::EventLocationInsideBounds(view, event);
+
+ gfx::Size size = view->bounds().size();
+ SkRegion clip_region;
+ clip_region.setRect(0, 0, size.width(), size.height());
+
+ gfx::RectF bounds_f = ViewTargeter::BoundsForEvent(event);
+ if (view->parent())
+ View::ConvertRectToTarget(view->parent(), view, &bounds_f);
+ gfx::Rect bounds = gfx::ToEnclosingRect(bounds_f);
+
+ SkRegion mask_region;
+ return mask_region.setPath(mask, clip_region) &&
+ mask_region.intersects(RectToSkIRect(bounds));
+ }
+
+ return ViewTargeter::EventLocationInsideBounds(view, event);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/masked_view_targeter.h b/chromium/ui/views/masked_view_targeter.h
new file mode 100644
index 00000000000..df155b915de
--- /dev/null
+++ b/chromium/ui/views/masked_view_targeter.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_MASKED_VIEW_TARGETER_H_
+#define UI_VIEWS_MASKED_VIEW_TARGETER_H_
+
+#include "ui/views/view_targeter.h"
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Path;
+}
+
+namespace views {
+
+// Derived classes of MaskedViewTargeter are used to define custom-shaped
+// hit test regions for a View used in event targeting.
+// TODO(tdanderson|sadrul): Some refactoring opportunities may be possible
+// between this class and MaskedWindowTargeter.
+class VIEWS_EXPORT MaskedViewTargeter : public ViewTargeter {
+ public:
+ explicit MaskedViewTargeter(View* masked_view);
+ virtual ~MaskedViewTargeter();
+
+ // Sets the hit-test mask for |view| in |mask| (in |view|'s local
+ // coordinate system). Returns whether a valid mask has been set in |mask|.
+ virtual bool GetHitTestMask(const View* view, gfx::Path* mask) const = 0;
+
+ protected:
+ const View* masked_view() const { return masked_view_; }
+
+ // ui::EventTargeter:
+ virtual bool EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+
+ private:
+ View* masked_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaskedViewTargeter);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MASKED_VIEW_TARGETER_H_
diff --git a/chromium/ui/views/metrics_aura.cc b/chromium/ui/views/metrics_aura.cc
index 03aa832f01e..046baa892ca 100644
--- a/chromium/ui/views/metrics_aura.cc
+++ b/chromium/ui/views/metrics_aura.cc
@@ -11,7 +11,6 @@
namespace {
// Default double click interval in milliseconds.
-// Same as what gtk uses.
const int kDefaultDoubleClickInterval = 500;
} // namespace
diff --git a/chromium/ui/views/metrics_mac.cc b/chromium/ui/views/metrics_mac.cc
new file mode 100644
index 00000000000..3a399d19463
--- /dev/null
+++ b/chromium/ui/views/metrics_mac.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/metrics.h"
+
+namespace {
+
+// Default double click interval in milliseconds.
+// Same as what gtk uses.
+const int kDefaultDoubleClickInterval = 500;
+
+} // namespace
+
+namespace views {
+
+int GetDoubleClickInterval() {
+ return kDefaultDoubleClickInterval;
+}
+
+int GetMenuShowDelay() {
+ return 0;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/metrics_win.cc b/chromium/ui/views/metrics_win.cc
deleted file mode 100644
index 3e04446b3eb..00000000000
--- a/chromium/ui/views/metrics_win.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/metrics.h"
-
-#include <windows.h>
-
-namespace views {
-
-int GetDoubleClickInterval() {
- return ::GetDoubleClickTime();
-}
-
-int GetMenuShowDelay() {
- static DWORD delay = 0;
- if (!delay && !SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &delay, 0))
- delay = kDefaultMenuShowDelay;
- return delay;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mouse_watcher.cc b/chromium/ui/views/mouse_watcher.cc
deleted file mode 100644
index bee59848dba..00000000000
--- a/chromium/ui/views/mouse_watcher.cc
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/mouse_watcher.h"
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/event_types.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/event_utils.h"
-#include "ui/gfx/screen.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/events/event.h"
-#include "ui/events/event_handler.h"
-#endif
-
-namespace views {
-
-// Amount of time between when the mouse moves outside the Host's zone and when
-// the listener is notified.
-const int kNotifyListenerTimeMs = 300;
-
-#if defined(OS_WIN) && !defined(USE_AURA)
-class MouseWatcher::Observer : public base::MessageLoopForUI::Observer {
- public:
- explicit Observer(MouseWatcher* mouse_watcher)
- : mouse_watcher_(mouse_watcher),
- notify_listener_factory_(this) {
- base::MessageLoopForUI::current()->AddObserver(this);
- }
-
- virtual ~Observer() {
- base::MessageLoopForUI::current()->RemoveObserver(this);
- }
-
- // MessageLoop::Observer implementation:
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE {
- return base::EVENT_CONTINUE;
- }
-
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
- // We spy on three different Windows messages here to see if the mouse has
- // moved out of the bounds of the current view. The messages are:
- //
- // WM_MOUSEMOVE:
- // For when the mouse moves from the view into the rest of the browser UI,
- // i.e. within the bounds of the same windows HWND.
- // WM_MOUSELEAVE:
- // For when the mouse moves out of the bounds of the view's HWND.
- // WM_NCMOUSELEAVE:
- // For notification when the mouse leaves the _non-client_ area.
- //
- switch (event.message) {
- case WM_MOUSEMOVE:
- HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_MOVE);
- break;
- case WM_MOUSELEAVE:
- case WM_NCMOUSELEAVE:
- HandleGlobalMouseMoveEvent(MouseWatcherHost::MOUSE_EXIT);
- break;
- }
- }
-
- private:
- MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); }
-
- // Called from the message loop observer when a mouse movement has occurred.
- void HandleGlobalMouseMoveEvent(MouseWatcherHost::MouseEventType event_type) {
- bool contained = host()->Contains(
- // TODO(scottmg): Native is wrong http://crbug.com/133312
- gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(),
- event_type);
- if (!contained) {
- // Mouse moved outside the host's zone, start a timer to notify the
- // listener.
- if (!notify_listener_factory_.HasWeakPtrs()) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&Observer::NotifyListener,
- notify_listener_factory_.GetWeakPtr()),
- event_type == MouseWatcherHost::MOUSE_MOVE
- ? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)
- : mouse_watcher_->notify_on_exit_time_);
- }
- } else {
- // Mouse moved quickly out of the host and then into it again, so cancel
- // the timer.
- notify_listener_factory_.InvalidateWeakPtrs();
- }
- }
-
- void NotifyListener() {
- mouse_watcher_->NotifyListener();
- // WARNING: we've been deleted.
- }
-
- private:
- MouseWatcher* mouse_watcher_;
-
- // A factory that is used to construct a delayed callback to the listener.
- base::WeakPtrFactory<Observer> notify_listener_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(Observer);
-};
-#else
-class MouseWatcher::Observer : public ui::EventHandler {
- public:
- explicit Observer(MouseWatcher* mouse_watcher)
- : mouse_watcher_(mouse_watcher),
- notify_listener_factory_(this) {
- aura::Env::GetInstance()->AddPreTargetHandler(this);
- }
-
- virtual ~Observer() {
- aura::Env::GetInstance()->RemovePreTargetHandler(this);
- }
-
- // ui::EventHandler implementation:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
- switch (event->type()) {
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED:
- HandleMouseEvent(MouseWatcherHost::MOUSE_MOVE);
- break;
- case ui::ET_MOUSE_EXITED:
- HandleMouseEvent(MouseWatcherHost::MOUSE_EXIT);
- break;
- default:
- break;
- }
- }
-
- private:
- MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); }
-
- // Called when a mouse event we're interested is seen.
- void HandleMouseEvent(MouseWatcherHost::MouseEventType event_type) {
- // It's safe to use last_mouse_location() here as this function is invoked
- // during event dispatching.
- if (!host()->Contains(aura::Env::GetInstance()->last_mouse_location(),
- event_type)) {
- // Mouse moved outside the host's zone, start a timer to notify the
- // listener.
- if (!notify_listener_factory_.HasWeakPtrs()) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&Observer::NotifyListener,
- notify_listener_factory_.GetWeakPtr()),
- event_type == MouseWatcherHost::MOUSE_MOVE
- ? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)
- : mouse_watcher_->notify_on_exit_time_);
- }
- } else {
- // Mouse moved quickly out of the host and then into it again, so cancel
- // the timer.
- notify_listener_factory_.InvalidateWeakPtrs();
- }
- }
-
- void NotifyListener() {
- mouse_watcher_->NotifyListener();
- // WARNING: we've been deleted.
- }
-
- private:
- MouseWatcher* mouse_watcher_;
-
- // A factory that is used to construct a delayed callback to the listener.
- base::WeakPtrFactory<Observer> notify_listener_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(Observer);
-};
-#endif
-
-MouseWatcherListener::~MouseWatcherListener() {
-}
-
-MouseWatcherHost::~MouseWatcherHost() {
-}
-
-MouseWatcher::MouseWatcher(MouseWatcherHost* host,
- MouseWatcherListener* listener)
- : host_(host),
- listener_(listener),
- notify_on_exit_time_(base::TimeDelta::FromMilliseconds(
- kNotifyListenerTimeMs)) {
-}
-
-MouseWatcher::~MouseWatcher() {
-}
-
-void MouseWatcher::Start() {
- if (!is_observing())
- observer_.reset(new Observer(this));
-}
-
-void MouseWatcher::Stop() {
- observer_.reset(NULL);
-}
-
-void MouseWatcher::NotifyListener() {
- observer_.reset(NULL);
- listener_->MouseMovedOutOfHost();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mouse_watcher_aura.cc b/chromium/ui/views/mouse_watcher_aura.cc
new file mode 100644
index 00000000000..3793f0e9671
--- /dev/null
+++ b/chromium/ui/views/mouse_watcher_aura.cc
@@ -0,0 +1,125 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/mouse_watcher.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/event_types.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/screen.h"
+
+namespace views {
+
+// Amount of time between when the mouse moves outside the Host's zone and when
+// the listener is notified.
+const int kNotifyListenerTimeMs = 300;
+
+class MouseWatcher::Observer : public ui::EventHandler {
+ public:
+ explicit Observer(MouseWatcher* mouse_watcher)
+ : mouse_watcher_(mouse_watcher),
+ notify_listener_factory_(this) {
+ aura::Env::GetInstance()->AddPreTargetHandler(this);
+ }
+
+ virtual ~Observer() {
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ }
+
+ // ui::EventHandler implementation:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ switch (event->type()) {
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ HandleMouseEvent(MouseWatcherHost::MOUSE_MOVE);
+ break;
+ case ui::ET_MOUSE_EXITED:
+ HandleMouseEvent(MouseWatcherHost::MOUSE_EXIT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private:
+ MouseWatcherHost* host() const { return mouse_watcher_->host_.get(); }
+
+ // Called when a mouse event we're interested is seen.
+ void HandleMouseEvent(MouseWatcherHost::MouseEventType event_type) {
+ // It's safe to use last_mouse_location() here as this function is invoked
+ // during event dispatching.
+ if (!host()->Contains(aura::Env::GetInstance()->last_mouse_location(),
+ event_type)) {
+ // Mouse moved outside the host's zone, start a timer to notify the
+ // listener.
+ if (!notify_listener_factory_.HasWeakPtrs()) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&Observer::NotifyListener,
+ notify_listener_factory_.GetWeakPtr()),
+ event_type == MouseWatcherHost::MOUSE_MOVE
+ ? base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)
+ : mouse_watcher_->notify_on_exit_time_);
+ }
+ } else {
+ // Mouse moved quickly out of the host and then into it again, so cancel
+ // the timer.
+ notify_listener_factory_.InvalidateWeakPtrs();
+ }
+ }
+
+ void NotifyListener() {
+ mouse_watcher_->NotifyListener();
+ // WARNING: we've been deleted.
+ }
+
+ private:
+ MouseWatcher* mouse_watcher_;
+
+ // A factory that is used to construct a delayed callback to the listener.
+ base::WeakPtrFactory<Observer> notify_listener_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+};
+
+MouseWatcherListener::~MouseWatcherListener() {
+}
+
+MouseWatcherHost::~MouseWatcherHost() {
+}
+
+MouseWatcher::MouseWatcher(MouseWatcherHost* host,
+ MouseWatcherListener* listener)
+ : host_(host),
+ listener_(listener),
+ notify_on_exit_time_(base::TimeDelta::FromMilliseconds(
+ kNotifyListenerTimeMs)) {
+}
+
+MouseWatcher::~MouseWatcher() {
+}
+
+void MouseWatcher::Start() {
+ if (!is_observing())
+ observer_.reset(new Observer(this));
+}
+
+void MouseWatcher::Stop() {
+ observer_.reset(NULL);
+}
+
+void MouseWatcher::NotifyListener() {
+ observer_.reset(NULL);
+ listener_->MouseMovedOutOfHost();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/native_cursor.h b/chromium/ui/views/native_cursor.h
new file mode 100644
index 00000000000..81f6e213ae2
--- /dev/null
+++ b/chromium/ui/views/native_cursor.h
@@ -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.
+
+#ifndef UI_VIEWS_NATIVE_CURSOR_H_
+#define UI_VIEWS_NATIVE_CURSOR_H_
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+VIEWS_EXPORT gfx::NativeCursor GetNativeIBeamCursor();
+VIEWS_EXPORT gfx::NativeCursor GetNativeHandCursor();
+VIEWS_EXPORT gfx::NativeCursor GetNativeColumnResizeCursor();
+VIEWS_EXPORT gfx::NativeCursor GetNativeEastWestResizeCursor();
+VIEWS_EXPORT gfx::NativeCursor GetNativeNorthSouthResizeCursor();
+
+} // namespace views
+
+#endif // UI_VIEWS_NATIVE_CURSOR_H_
diff --git a/chromium/ui/views/native_cursor_aura.cc b/chromium/ui/views/native_cursor_aura.cc
new file mode 100644
index 00000000000..cafe684aa0b
--- /dev/null
+++ b/chromium/ui/views/native_cursor_aura.cc
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/native_cursor.h"
+
+#include "ui/base/cursor/cursor.h"
+
+namespace views {
+
+gfx::NativeCursor GetNativeIBeamCursor() {
+ return ui::kCursorIBeam;
+}
+
+gfx::NativeCursor GetNativeHandCursor() {
+ return ui::kCursorHand;
+}
+
+gfx::NativeCursor GetNativeColumnResizeCursor() {
+ return ui::kCursorColumnResize;
+}
+
+gfx::NativeCursor GetNativeEastWestResizeCursor() {
+ return ui::kCursorEastWestResize;
+}
+
+gfx::NativeCursor GetNativeNorthSouthResizeCursor() {
+ return ui::kCursorNorthSouthResize;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/native_cursor_mac.mm b/chromium/ui/views/native_cursor_mac.mm
new file mode 100644
index 00000000000..967484deb72
--- /dev/null
+++ b/chromium/ui/views/native_cursor_mac.mm
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/native_cursor.h"
+
+#include <Cocoa/Cocoa.h>
+
+namespace views {
+
+gfx::NativeCursor GetNativeIBeamCursor() {
+ return [NSCursor IBeamCursor];
+}
+
+gfx::NativeCursor GetNativeArrowCursor() {
+ return [NSCursor arrowCursor];
+}
+
+gfx::NativeCursor GetNativeHandCursor() {
+ return [NSCursor pointingHandCursor];
+}
+
+gfx::NativeCursor GetNativeColumnResizeCursor() {
+ return [NSCursor resizeLeftRightCursor];
+}
+
+gfx::NativeCursor GetNativeEastWestResizeCursor() {
+ NOTIMPLEMENTED();
+ // TODO(tapted): This is the wrong cursor. Fetch the right one from WebCursor
+ // or ResourceBundle or CoreCursor private API.
+ return [NSCursor resizeLeftRightCursor];
+}
+
+gfx::NativeCursor GetNativeNorthSouthResizeCursor() {
+ NOTIMPLEMENTED();
+ return [NSCursor resizeUpDownCursor];
+}
+
+} // namespace views
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index b6a2e7d4c6f..ed0e65f7f85 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -13,6 +13,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/insets.h"
+#include "ui/gfx/nine_image_painter.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/views/view.h"
@@ -150,7 +151,7 @@ void GradientPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
p[1].iset(0, size.height());
skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
- p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode, NULL));
+ p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode));
paint.setStyle(SkPaint::kFill_Style);
paint.setShader(s.get());
@@ -173,117 +174,34 @@ class VIEWS_EXPORT ImagePainter : public Painter {
virtual ~ImagePainter();
- // Returns true if the images are empty.
- bool IsEmpty() const;
-
// Painter:
virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE;
private:
- // Stretches the given image over the specified canvas area.
- static void Fill(gfx::Canvas* c,
- const gfx::ImageSkia& i,
- int x,
- int y,
- int w,
- int h);
-
- // Images are numbered as depicted below.
- // ____________________
- // |__i0__|__i1__|__i2__|
- // |__i3__|__i4__|__i5__|
- // |__i6__|__i7__|__i8__|
- gfx::ImageSkia images_[9];
+ scoped_ptr<gfx::NineImagePainter> nine_painter_;
DISALLOW_COPY_AND_ASSIGN(ImagePainter);
};
-ImagePainter::ImagePainter(const int image_ids[]) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- for (size_t i = 0; i < 9; ++i)
- if (image_ids[i] != 0)
- images_[i] = *rb.GetImageSkiaNamed(image_ids[i]);
+ImagePainter::ImagePainter(const int image_ids[])
+ : nine_painter_(ui::CreateNineImagePainter(image_ids)) {
}
ImagePainter::ImagePainter(const gfx::ImageSkia& image,
- const gfx::Insets& insets) {
- DCHECK_GE(image.width(), insets.width());
- DCHECK_GE(image.height(), insets.height());
-
- // Extract subsets of the original image to match the |images_| format.
- const int x[] =
- { 0, insets.left(), image.width() - insets.right(), image.width() };
- const int y[] =
- { 0, insets.top(), image.height() - insets.bottom(), image.height() };
-
- for (size_t j = 0; j < 3; ++j) {
- for (size_t i = 0; i < 3; ++i) {
- images_[i + j * 3] = gfx::ImageSkiaOperations::ExtractSubset(image,
- gfx::Rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j]));
- }
- }
+ const gfx::Insets& insets)
+ : nine_painter_(new gfx::NineImagePainter(image, insets)) {
}
ImagePainter::~ImagePainter() {
}
-bool ImagePainter::IsEmpty() const {
- return images_[0].isNull();
-}
-
gfx::Size ImagePainter::GetMinimumSize() const {
- return IsEmpty() ? gfx::Size() : gfx::Size(
- images_[0].width() + images_[1].width() + images_[2].width(),
- images_[0].height() + images_[3].height() + images_[6].height());
+ return nine_painter_->GetMinimumSize();
}
void ImagePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
- if (IsEmpty())
- return;
-
- // In case the corners and edges don't all have the same width/height, we draw
- // the center first, and extend it out in all directions to the edges of the
- // images with the smallest widths/heights. This way there will be no
- // unpainted areas, though some corners or edges might overlap the center.
- int w = size.width();
- int i0w = images_[0].width();
- int i2w = images_[2].width();
- int i3w = images_[3].width();
- int i5w = images_[5].width();
- int i6w = images_[6].width();
- int i8w = images_[8].width();
- int i4x = std::min(std::min(i0w, i3w), i6w);
- int i4w = w - i4x - std::min(std::min(i2w, i5w), i8w);
- int h = size.height();
- int i0h = images_[0].height();
- int i1h = images_[1].height();
- int i2h = images_[2].height();
- int i6h = images_[6].height();
- int i7h = images_[7].height();
- int i8h = images_[8].height();
- int i4y = std::min(std::min(i0h, i1h), i2h);
- int i4h = h - i4y - std::min(std::min(i6h, i7h), i8h);
- if (!images_[4].isNull())
- Fill(canvas, images_[4], i4x, i4y, i4w, i4h);
- canvas->DrawImageInt(images_[0], 0, 0);
- Fill(canvas, images_[1], i0w, 0, w - i0w - i2w, i1h);
- canvas->DrawImageInt(images_[2], w - i2w, 0);
- Fill(canvas, images_[3], 0, i0h, i3w, h - i0h - i6h);
- Fill(canvas, images_[5], w - i5w, i2h, i5w, h - i2h - i8h);
- canvas->DrawImageInt(images_[6], 0, h - i6h);
- Fill(canvas, images_[7], i6w, h - i7h, w - i6w - i8w, i7h);
- canvas->DrawImageInt(images_[8], w - i8w, h - i8h);
-}
-
-// static
-void ImagePainter::Fill(gfx::Canvas* c,
- const gfx::ImageSkia& i,
- int x,
- int y,
- int w,
- int h) {
- c->DrawImageInt(i, 0, 0, i.width(), i.height(), x, y, w, h, false);
+ nine_painter_->Paint(canvas, gfx::Rect(size));
}
} // namespace
diff --git a/chromium/ui/views/painter.h b/chromium/ui/views/painter.h
index 3799e91e86c..6efd281f11a 100644
--- a/chromium/ui/views/painter.h
+++ b/chromium/ui/views/painter.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/nine_image_painter_factory.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -19,11 +20,6 @@ class Rect;
class Size;
}
-// A macro to define arrays of IDR constants used with CreateImageGridPainter.
-#define IMAGE_GRID(x) { x ## _TOP_LEFT, x ## _TOP, x ## _TOP_RIGHT, \
- x ## _LEFT, x ## _CENTER, x ## _RIGHT, \
- x ## _BOTTOM_LEFT, x ## _BOTTOM, x ## _BOTTOM_RIGHT, }
-
namespace views {
class View;
diff --git a/chromium/ui/views/run_all_unittests.cc b/chromium/ui/views/run_all_unittests.cc
index 499d339c5f9..e5d7b9d61f0 100644
--- a/chromium/ui/views/run_all_unittests.cc
+++ b/chromium/ui/views/run_all_unittests.cc
@@ -8,8 +8,10 @@
#include "base/path_service.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
+#include "ui/gl/gl_surface.h"
class ViewTestSuite : public base::TestSuite {
public:
@@ -18,15 +20,12 @@ class ViewTestSuite : public base::TestSuite {
protected:
virtual void Initialize() OVERRIDE {
base::TestSuite::Initialize();
+ gfx::GLSurface::InitializeOneOffForTests();
ui::RegisterPathProvider();
- base::FilePath pak_dir;
- PathService::Get(base::DIR_MODULE, &pak_dir);
-
- base::FilePath pak_file;
- pak_file = pak_dir.Append(FILE_PATH_LITERAL("ui_test.pak"));
-
- ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
+ base::FilePath ui_test_pak_path;
+ ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
}
virtual void Shutdown() OVERRIDE {
diff --git a/chromium/ui/views/touchui/touch_editing_menu.cc b/chromium/ui/views/touchui/touch_editing_menu.cc
index dec91139093..b17039c9727 100644
--- a/chromium/ui/views/touchui/touch_editing_menu.cc
+++ b/chromium/ui/views/touchui/touch_editing_menu.cc
@@ -9,6 +9,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/bubble/bubble_border.h"
@@ -38,11 +39,11 @@ namespace views {
TouchEditingMenuView::TouchEditingMenuView(
TouchEditingMenuController* controller,
- gfx::Rect anchor_rect,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size,
gfx::NativeView context)
: BubbleDelegateView(NULL, views::BubbleBorder::BOTTOM_CENTER),
controller_(controller) {
- SetAnchorRect(anchor_rect);
set_shadow(views::BubbleBorder::SMALL_SHADOW);
set_parent_window(context);
set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin));
@@ -52,6 +53,16 @@ TouchEditingMenuView::TouchEditingMenuView(
SetLayoutManager(new BoxLayout(BoxLayout::kHorizontal, 0, 0,
kSpacingBetweenButtons));
CreateButtons();
+
+ // After buttons are created, check if there is enough room between handles to
+ // show the menu and adjust anchor rect properly if needed, just in case the
+ // menu is needed to be shown under the selection.
+ gfx::Rect adjusted_anchor_rect(anchor_rect);
+ int menu_width = GetPreferredSize().width();
+ if (menu_width > anchor_rect.width() - handle_image_size.width())
+ adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
+ SetAnchorRect(adjusted_anchor_rect);
+
views::BubbleDelegateView::CreateBubble(this);
GetWidget()->Show();
}
@@ -62,12 +73,15 @@ TouchEditingMenuView::~TouchEditingMenuView() {
// static
TouchEditingMenuView* TouchEditingMenuView::Create(
TouchEditingMenuController* controller,
- gfx::Rect anchor_rect,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size,
gfx::NativeView context) {
if (controller) {
for (size_t i = 0; i < arraysize(kMenuCommands); i++) {
- if (controller->IsCommandIdEnabled(kMenuCommands[i]))
- return new TouchEditingMenuView(controller, anchor_rect, context);
+ if (controller->IsCommandIdEnabled(kMenuCommands[i])) {
+ return new TouchEditingMenuView(controller, anchor_rect,
+ handle_image_size, context);
+ }
}
}
return NULL;
@@ -121,25 +135,27 @@ void TouchEditingMenuView::CreateButtons() {
// Finally, add ellipses button.
AddChildView(CreateButton(
- UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
+ base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
Layout();
}
-Button* TouchEditingMenuView::CreateButton(const string16& title, int tag) {
- string16 label = gfx::RemoveAcceleratorChar(title, '&', NULL, NULL);
+Button* TouchEditingMenuView::CreateButton(const base::string16& title,
+ int tag) {
+ base::string16 label = gfx::RemoveAcceleratorChar(title, '&', NULL, NULL);
LabelButton* button = new LabelButton(this, label);
button->SetFocusable(true);
button->set_request_focus_on_press(false);
- gfx::Font font = ui::ResourceBundle::GetSharedInstance().GetFont(
- ui::ResourceBundle::SmallFont);
+ const gfx::FontList& font_list =
+ ui::ResourceBundle::GetSharedInstance().GetFontList(
+ ui::ResourceBundle::SmallFont);
scoped_ptr<LabelButtonBorder> button_border(
new LabelButtonBorder(button->style()));
- int v_border = (kMenuButtonHeight - font.GetHeight()) / 2;
- int h_border = (kMenuButtonWidth - font.GetStringWidth(label)) / 2;
+ int v_border = (kMenuButtonHeight - font_list.GetHeight()) / 2;
+ int h_border = (kMenuButtonWidth - gfx::GetStringWidth(label, font_list)) / 2;
button_border->set_insets(
gfx::Insets(v_border, h_border, v_border, h_border));
- button->set_border(button_border.release());
- button->SetFont(font);
+ button->SetBorder(button_border.PassAs<Border>());
+ button->SetFontList(font_list);
button->set_tag(tag);
return button;
}
diff --git a/chromium/ui/views/touchui/touch_editing_menu.h b/chromium/ui/views/touchui/touch_editing_menu.h
index 5dfeaef373a..19f0d34a664 100644
--- a/chromium/ui/views/touchui/touch_editing_menu.h
+++ b/chromium/ui/views/touchui/touch_editing_menu.h
@@ -45,14 +45,16 @@ class VIEWS_EXPORT TouchEditingMenuView : public BubbleDelegateView,
// If there are no actions available for the menu, returns NULL. Otherwise,
// returns a new instance of TouchEditingMenuView.
static TouchEditingMenuView* Create(TouchEditingMenuController* controller,
- gfx::Rect anchor_rect,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size,
gfx::NativeView context);
void Close();
private:
TouchEditingMenuView(TouchEditingMenuController* controller,
- gfx::Rect anchor_rect,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size,
gfx::NativeView context);
// views::WidgetDelegate overrides:
@@ -69,7 +71,7 @@ class VIEWS_EXPORT TouchEditingMenuView : public BubbleDelegateView,
void CreateButtons();
// Helper method to create a single button.
- Button* CreateButton(const string16& title, int tag);
+ Button* CreateButton(const base::string16& title, int tag);
TouchEditingMenuController* controller_;
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 41720be7033..3e005a64ea6 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -7,16 +7,19 @@
#include "base/time/time.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size.h"
-#include "ui/views/corewm/shadow_types.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/core/masked_window_targeter.h"
+#include "ui/wm/core/window_animations.h"
namespace {
@@ -56,21 +59,27 @@ const int kSelectionHandleVertPadding = 20;
const int kContextMenuTimoutMs = 200;
+const int kSelectionHandleQuickFadeDurationMs = 50;
+
+// Minimum height for selection handle bar. If the bar height is going to be
+// less than this value, handle will not be shown.
+const int kSelectionHandleBarMinHeight = 5;
+// Maximum amount that selection handle bar can stick out of client view's
+// boundaries.
+const int kSelectionHandleBarBottomAllowance = 3;
+
// Creates a widget to host SelectionHandleView.
views::Widget* CreateTouchSelectionPopupWidget(
gfx::NativeView context,
views::WidgetDelegate* widget_delegate) {
views::Widget* widget = new views::Widget;
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_TOOLTIP);
- params.can_activate = false;
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+ params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.context = context;
+ params.parent = context;
params.delegate = widget_delegate;
widget->Init(params);
-#if defined(USE_AURA)
- SetShadowType(widget->GetNativeView(), views::corewm::SHADOW_TYPE_NONE);
-#endif
return widget;
}
@@ -97,8 +106,8 @@ gfx::Rect Union(const gfx::Rect& r1, const gfx::Rect& r2) {
return gfx::Rect(rx, ry, rr - rx, rb - ry);
}
-// Convenience method to convert a |rect| from screen to the |client|'s
-// coordinate system.
+// Convenience methods to convert a |rect| from screen to the |client|'s
+// coordinate system and vice versa.
// Note that this is not quite correct because it does not take into account
// transforms such as rotation and scaling. This should be in TouchEditable.
// TODO(varunjain): Fix this.
@@ -107,29 +116,57 @@ gfx::Rect ConvertFromScreen(ui::TouchEditable* client, const gfx::Rect& rect) {
client->ConvertPointFromScreen(&origin);
return gfx::Rect(origin, rect.size());
}
+gfx::Rect ConvertToScreen(ui::TouchEditable* client, const gfx::Rect& rect) {
+ gfx::Point origin = rect.origin();
+ client->ConvertPointToScreen(&origin);
+ return gfx::Rect(origin, rect.size());
+}
} // namespace
namespace views {
+typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView;
+
+class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter {
+ public:
+ TouchHandleWindowTargeter(aura::Window* window,
+ EditingHandleView* handle_view);
+
+ virtual ~TouchHandleWindowTargeter() {}
+
+ private:
+ // wm::MaskedWindowTargeter:
+ virtual bool GetHitTestMask(aura::Window* window,
+ gfx::Path* mask) const OVERRIDE;
+
+ EditingHandleView* handle_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter);
+};
+
// A View that displays the text selection handle.
class TouchSelectionControllerImpl::EditingHandleView
: public views::WidgetDelegateView {
public:
- explicit EditingHandleView(TouchSelectionControllerImpl* controller,
- gfx::NativeView context)
+ EditingHandleView(TouchSelectionControllerImpl* controller,
+ gfx::NativeView context)
: controller_(controller),
drag_offset_(0),
draw_invisible_(false) {
widget_.reset(CreateTouchSelectionPopupWidget(context, this));
widget_->SetContentsView(this);
- widget_->SetAlwaysOnTop(true);
+
+ aura::Window* window = widget_->GetNativeWindow();
+ window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
+ new TouchHandleWindowTargeter(window, this)));
// We are owned by the TouchSelectionController.
set_owned_by_client();
}
virtual ~EditingHandleView() {
+ SetWidgetVisible(false, false);
}
// Overridden from views::WidgetDelegateView:
@@ -193,7 +230,7 @@ class TouchSelectionControllerImpl::EditingHandleView
}
}
- virtual gfx::Size GetPreferredSize() OVERRIDE {
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
gfx::Size image_size = GetHandleImageSize();
return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
image_size.height() + selection_rect_.height() +
@@ -204,9 +241,13 @@ class TouchSelectionControllerImpl::EditingHandleView
return widget_->IsVisible();
}
- void SetWidgetVisible(bool visible) {
+ void SetWidgetVisible(bool visible, bool quick) {
if (widget_->IsVisible() == visible)
return;
+ wm::SetWindowVisibilityAnimationDuration(
+ widget_->GetNativeView(),
+ base::TimeDelta::FromMilliseconds(
+ quick ? kSelectionHandleQuickFadeDurationMs : 0));
if (visible)
widget_->Show();
else
@@ -235,6 +276,8 @@ class TouchSelectionControllerImpl::EditingHandleView
SchedulePaint();
}
+ const gfx::Rect& selection_rect() const { return selection_rect_; }
+
private:
scoped_ptr<Widget> widget_;
TouchSelectionControllerImpl* controller_;
@@ -254,6 +297,24 @@ class TouchSelectionControllerImpl::EditingHandleView
DISALLOW_COPY_AND_ASSIGN(EditingHandleView);
};
+TouchHandleWindowTargeter::TouchHandleWindowTargeter(
+ aura::Window* window,
+ EditingHandleView* handle_view)
+ : wm::MaskedWindowTargeter(window),
+ handle_view_(handle_view) {
+}
+
+bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window,
+ gfx::Path* mask) const {
+ const gfx::Rect& selection_rect = handle_view_->selection_rect();
+ gfx::Size image_size = GetHandleImageSize();
+ mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect.height()),
+ SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
+ SkIntToScalar(selection_rect.height() + image_size.height() +
+ kSelectionHandleVertPadding));
+ return true;
+}
+
TouchSelectionControllerImpl::TouchSelectionControllerImpl(
ui::TouchEditable* client_view)
: client_view_(client_view),
@@ -270,10 +331,12 @@ TouchSelectionControllerImpl::TouchSelectionControllerImpl(
client_view_->GetNativeView());
if (client_widget_)
client_widget_->AddObserver(this);
+ aura::Env::GetInstance()->AddPreTargetHandler(this);
}
TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
HideContextMenu();
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
if (client_widget_)
client_widget_->RemoveObserver(this);
}
@@ -281,21 +344,26 @@ TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
void TouchSelectionControllerImpl::SelectionChanged() {
gfx::Rect r1, r2;
client_view_->GetSelectionEndPoints(&r1, &r2);
- gfx::Point screen_pos_1(r1.origin());
- client_view_->ConvertPointToScreen(&screen_pos_1);
- gfx::Point screen_pos_2(r2.origin());
- client_view_->ConvertPointToScreen(&screen_pos_2);
- gfx::Rect screen_rect_1(screen_pos_1, r1.size());
- gfx::Rect screen_rect_2(screen_pos_2, r2.size());
- if (screen_rect_1 == selection_end_point_1_ &&
- screen_rect_2 == selection_end_point_2_)
+ gfx::Rect screen_rect_1 = ConvertToScreen(client_view_, r1);
+ gfx::Rect screen_rect_2 = ConvertToScreen(client_view_, r2);
+ gfx::Rect client_bounds = client_view_->GetBounds();
+ if (r1.y() < client_bounds.y())
+ r1.Inset(0, client_bounds.y() - r1.y(), 0, 0);
+ if (r2.y() < client_bounds.y())
+ r2.Inset(0, client_bounds.y() - r2.y(), 0, 0);
+ gfx::Rect screen_rect_1_clipped = ConvertToScreen(client_view_, r1);
+ gfx::Rect screen_rect_2_clipped = ConvertToScreen(client_view_, r2);
+ if (screen_rect_1_clipped == selection_end_point_1_clipped_ &&
+ screen_rect_2_clipped == selection_end_point_2_clipped_)
return;
selection_end_point_1_ = screen_rect_1;
selection_end_point_2_ = screen_rect_2;
+ selection_end_point_1_clipped_ = screen_rect_1_clipped;
+ selection_end_point_2_clipped_ = screen_rect_2_clipped;
if (client_view_->DrawsHandles()) {
- UpdateContextMenu(r1.origin(), r2.origin());
+ UpdateContextMenu();
return;
}
if (dragging_handle_) {
@@ -306,14 +374,14 @@ void TouchSelectionControllerImpl::SelectionChanged() {
// If the new location of this handle is out of client view, its widget
// should not get hidden, since it should still receive touch events.
// Hence, we are not using |SetHandleSelectionRect()| method here.
- dragging_handle_->SetSelectionRectInScreen(screen_rect_2);
+ dragging_handle_->SetSelectionRectInScreen(screen_rect_2_clipped);
// Temporary fix for selection handle going outside a window. On a webpage,
// the page should scroll if the selection handle is dragged outside the
// window. That does not happen currently. So we just hide the handle for
// now.
// TODO(varunjain): Fix this: crbug.com/269003
- dragging_handle_->SetDrawInvisible(!client_view_->GetBounds().Contains(r2));
+ dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(r2));
if (dragging_handle_ != cursor_handle_.get()) {
// The non-dragging-handle might have recently become visible.
@@ -324,23 +392,27 @@ void TouchSelectionControllerImpl::SelectionChanged() {
// selection and the other handle to the start of selection.
selection_end_point_1_ = screen_rect_2;
selection_end_point_2_ = screen_rect_1;
+ selection_end_point_1_clipped_ = screen_rect_2_clipped;
+ selection_end_point_2_clipped_ = screen_rect_1_clipped;
}
- SetHandleSelectionRect(non_dragging_handle, r1, screen_rect_1);
+ SetHandleSelectionRect(non_dragging_handle, r1, screen_rect_1_clipped);
}
} else {
- UpdateContextMenu(r1.origin(), r2.origin());
+ UpdateContextMenu();
// Check if there is any selection at all.
- if (screen_pos_1 == screen_pos_2) {
- selection_handle_1_->SetWidgetVisible(false);
- selection_handle_2_->SetWidgetVisible(false);
- SetHandleSelectionRect(cursor_handle_.get(), r1, screen_rect_1);
+ if (screen_rect_1.origin() == screen_rect_2.origin()) {
+ selection_handle_1_->SetWidgetVisible(false, false);
+ selection_handle_2_->SetWidgetVisible(false, false);
+ SetHandleSelectionRect(cursor_handle_.get(), r1, screen_rect_1_clipped);
return;
}
- cursor_handle_->SetWidgetVisible(false);
- SetHandleSelectionRect(selection_handle_1_.get(), r1, screen_rect_1);
- SetHandleSelectionRect(selection_handle_2_.get(), r2, screen_rect_2);
+ cursor_handle_->SetWidgetVisible(false, false);
+ SetHandleSelectionRect(selection_handle_1_.get(), r1,
+ screen_rect_1_clipped);
+ SetHandleSelectionRect(selection_handle_2_.get(), r2,
+ screen_rect_2_clipped);
}
}
@@ -348,6 +420,12 @@ bool TouchSelectionControllerImpl::IsHandleDragInProgress() {
return !!dragging_handle_;
}
+void TouchSelectionControllerImpl::HideHandles(bool quick) {
+ selection_handle_1_->SetWidgetVisible(false, quick);
+ selection_handle_2_->SetWidgetVisible(false, quick);
+ cursor_handle_->SetWidgetVisible(false, quick);
+}
+
void TouchSelectionControllerImpl::SetDraggingHandle(
EditingHandleView* handle) {
dragging_handle_ = handle;
@@ -397,11 +475,20 @@ void TouchSelectionControllerImpl::SetHandleSelectionRect(
EditingHandleView* handle,
const gfx::Rect& rect,
const gfx::Rect& rect_in_screen) {
- handle->SetWidgetVisible(client_view_->GetBounds().Contains(rect));
+ handle->SetWidgetVisible(ShouldShowHandleFor(rect), false);
if (handle->IsWidgetVisible())
handle->SetSelectionRectInScreen(rect_in_screen);
}
+bool TouchSelectionControllerImpl::ShouldShowHandleFor(
+ const gfx::Rect& rect) const {
+ if (rect.height() < kSelectionHandleBarMinHeight)
+ return false;
+ gfx::Rect bounds = client_view_->GetBounds();
+ bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance);
+ return bounds.Contains(rect);
+}
+
bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const {
return client_view_->IsCommandIdEnabled(command_id);
}
@@ -438,16 +525,31 @@ void TouchSelectionControllerImpl::OnWidgetBoundsChanged(
SelectionChanged();
}
+void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
+ client_view_->DestroyTouchSelection();
+}
+
+void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
+ aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
+ client_view_->GetNativeView()->GetRootWindow());
+ if (!cursor_client || cursor_client->IsMouseEventsEnabled())
+ client_view_->DestroyTouchSelection();
+}
+
+void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
+ client_view_->DestroyTouchSelection();
+}
+
void TouchSelectionControllerImpl::ContextMenuTimerFired() {
// Get selection end points in client_view's space.
gfx::Rect end_rect_1_in_screen;
gfx::Rect end_rect_2_in_screen;
if (cursor_handle_->IsWidgetVisible()) {
- end_rect_1_in_screen = selection_end_point_1_;
+ end_rect_1_in_screen = selection_end_point_1_clipped_;
end_rect_2_in_screen = end_rect_1_in_screen;
} else {
- end_rect_1_in_screen = selection_end_point_1_;
- end_rect_2_in_screen = selection_end_point_2_;
+ end_rect_1_in_screen = selection_end_point_1_clipped_;
+ end_rect_2_in_screen = selection_end_point_2_clipped_;
}
// Convert from screen to client.
@@ -458,19 +560,19 @@ void TouchSelectionControllerImpl::ContextMenuTimerFired() {
// in the middle of the end points on the top. Else, we show it above the
// visible handle. If no handle is visible, we do not show the menu.
gfx::Rect menu_anchor;
- gfx::Rect client_bounds = client_view_->GetBounds();
- if (client_bounds.Contains(end_rect_1) &&
- client_bounds.Contains(end_rect_2))
+ if (ShouldShowHandleFor(end_rect_1) &&
+ ShouldShowHandleFor(end_rect_2))
menu_anchor = Union(end_rect_1_in_screen,end_rect_2_in_screen);
- else if (client_bounds.Contains(end_rect_1))
+ else if (ShouldShowHandleFor(end_rect_1))
menu_anchor = end_rect_1_in_screen;
- else if (client_bounds.Contains(end_rect_2))
+ else if (ShouldShowHandleFor(end_rect_2))
menu_anchor = end_rect_2_in_screen;
else
return;
DCHECK(!context_menu_);
context_menu_ = TouchEditingMenuView::Create(this, menu_anchor,
+ GetHandleImageSize(),
client_view_->GetNativeView());
}
@@ -484,8 +586,7 @@ void TouchSelectionControllerImpl::StartContextMenuTimer() {
&TouchSelectionControllerImpl::ContextMenuTimerFired);
}
-void TouchSelectionControllerImpl::UpdateContextMenu(const gfx::Point& p1,
- const gfx::Point& p2) {
+void TouchSelectionControllerImpl::UpdateContextMenu() {
// Hide context menu to be shown when the timer fires.
HideContextMenu();
StartContextMenuTimer();
@@ -498,6 +599,10 @@ void TouchSelectionControllerImpl::HideContextMenu() {
context_menu_timer_.Stop();
}
+gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() {
+ return cursor_handle_->GetWidget()->GetNativeView();
+}
+
gfx::Point TouchSelectionControllerImpl::GetSelectionHandle1Position() {
return selection_handle_1_->GetScreenPosition();
}
@@ -522,14 +627,4 @@ bool TouchSelectionControllerImpl::IsCursorHandleVisible() {
return cursor_handle_->IsWidgetVisible();
}
-ViewsTouchSelectionControllerFactory::ViewsTouchSelectionControllerFactory() {
-}
-
-ui::TouchSelectionController* ViewsTouchSelectionControllerFactory::create(
- ui::TouchEditable* client_view) {
- if (switches::IsTouchEditingEnabled())
- return new views::TouchSelectionControllerImpl(client_view);
- return NULL;
-}
-
} // namespace views
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.h b/chromium/ui/views/touchui/touch_selection_controller_impl.h
index dc9babe9d34..04076af2e8f 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.h
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.h
@@ -14,13 +14,20 @@
namespace views {
+namespace test {
+class WidgetTestInteractive;
+}
+
// Touch specific implementation of TouchSelectionController. Responsible for
// displaying selection handles and menu elements relevant in a touch interface.
class VIEWS_EXPORT TouchSelectionControllerImpl
: public ui::TouchSelectionController,
public TouchEditingMenuController,
- public WidgetObserver {
+ public WidgetObserver,
+ public ui::EventHandler {
public:
+ class EditingHandleView;
+
// Use TextSelectionController::create().
explicit TouchSelectionControllerImpl(
ui::TouchEditable* client_view);
@@ -30,10 +37,11 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
// TextSelectionController.
virtual void SelectionChanged() OVERRIDE;
virtual bool IsHandleDragInProgress() OVERRIDE;
+ virtual void HideHandles(bool quick) OVERRIDE;
private:
friend class TouchSelectionControllerImplTest;
- class EditingHandleView;
+ friend class test::WidgetTestInteractive;
void SetDraggingHandle(EditingHandleView* handle);
@@ -50,6 +58,10 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
void SetHandleSelectionRect(EditingHandleView* handle, const gfx::Rect& rect,
const gfx::Rect& rect_in_screen);
+ // Checks if handle should be shown for a selection end-point at |rect|.
+ // |rect| should be the clipped version of the selection end-point.
+ bool ShouldShowHandleFor(const gfx::Rect& rect) const;
+
// Overridden from TouchEditingMenuController.
virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
@@ -63,18 +75,24 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
virtual void OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) OVERRIDE;
+ // Overriden from ui::EventHandler.
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+
// Time to show context menu.
void ContextMenuTimerFired();
void StartContextMenuTimer();
// Convenience method to update the position/visibility of the context menu.
- void UpdateContextMenu(const gfx::Point& p1, const gfx::Point& p2);
+ void UpdateContextMenu();
// Convenience method for hiding context menu.
void HideContextMenu();
// Convenience methods for testing.
+ gfx::NativeView GetCursorHandleNativeView();
gfx::Point GetSelectionHandle1Position();
gfx::Point GetSelectionHandle2Position();
gfx::Point GetCursorHandlePosition();
@@ -104,20 +122,13 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
// position of handles which might be invalid when handles are hidden.
gfx::Rect selection_end_point_1_;
gfx::Rect selection_end_point_2_;
+ // Selection end points, clipped to client view's boundaries.
+ gfx::Rect selection_end_point_1_clipped_;
+ gfx::Rect selection_end_point_2_clipped_;
DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerImpl);
};
-class VIEWS_EXPORT ViewsTouchSelectionControllerFactory
- : public ui::TouchSelectionControllerFactory {
- public:
- ViewsTouchSelectionControllerFactory();
-
- // Overridden from ui::TouchSelectionControllerFactory.
- virtual ui::TouchSelectionController* create(
- ui::TouchEditable* client_view) OVERRIDE;
-};
-
} // namespace views
#endif // UI_UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index 54c997223c2..8f21e3729bc 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -5,27 +5,44 @@
#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/touch/touch_editing_controller.h"
#include "ui/base/ui_base_switches.h"
+#include "ui/gfx/canvas.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/render_text.h"
-#include "ui/views/controls/textfield/native_textfield_views.h"
#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/touchui/touch_selection_controller_impl.h"
+#include "ui/views/views_touch_selection_controller_factory.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/window.h"
-#endif
+using base::ASCIIToUTF16;
+using base::UTF16ToUTF8;
+using base::WideToUTF16;
namespace {
// Should match kSelectionHandlePadding in touch_selection_controller.
const int kPadding = 10;
+// Should match kSelectionHandleBarMinHeight in touch_selection_controller.
+const int kBarMinHeight = 5;
+
+// Should match kSelectionHandleBarBottomAllowance in
+// touch_selection_controller.
+const int kBarBottomAllowance = 3;
+
+// Should match kMenuButtonWidth in touch_editing_menu.
+const int kMenuButtonWidth = 63;
+
+// Should match size of kMenuCommands array in touch_editing_menu.
+const int kMenuCommandCount = 3;
+
gfx::Image* GetHandleImage() {
static gfx::Image* handle_image = NULL;
if (!handle_image) {
@@ -45,9 +62,9 @@ namespace views {
class TouchSelectionControllerImplTest : public ViewsTestBase {
public:
TouchSelectionControllerImplTest()
- : widget_(NULL),
+ : textfield_widget_(NULL),
+ widget_(NULL),
textfield_(NULL),
- textfield_view_(NULL),
views_tsc_factory_(new ViewsTouchSelectionControllerFactory) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableTouchEditing);
@@ -59,42 +76,68 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
}
virtual void TearDown() {
- if (widget_)
+ if (textfield_widget_ && !textfield_widget_->IsClosed())
+ textfield_widget_->Close();
+ if (widget_ && !widget_->IsClosed())
widget_->Close();
ViewsTestBase::TearDown();
}
void CreateTextfield() {
textfield_ = new Textfield();
- widget_ = new Widget;
+ textfield_widget_ = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.bounds = gfx::Rect(0, 0, 200, 200);
- widget_->Init(params);
+ textfield_widget_->Init(params);
View* container = new View();
- widget_->SetContentsView(container);
+ textfield_widget_->SetContentsView(container);
container->AddChildView(textfield_);
- textfield_view_ = static_cast<NativeTextfieldViews*>(
- textfield_->GetNativeWrapperForTesting());
- textfield_->SetBoundsRect(params.bounds);
- textfield_view_->SetBoundsRect(params.bounds);
+ textfield_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
textfield_->set_id(1);
- widget_->Show();
+ textfield_widget_->Show();
- DCHECK(textfield_view_);
textfield_->RequestFocus();
+
+ textfield_test_api_.reset(new TextfieldTestApi(textfield_));
+ }
+
+ void CreateWidget() {
+ widget_ = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget_->Init(params);
+ widget_->Show();
}
protected:
+ static bool IsCursorHandleVisibleFor(
+ ui::TouchSelectionController* controller) {
+ TouchSelectionControllerImpl* impl =
+ static_cast<TouchSelectionControllerImpl*>(controller);
+ return impl->IsCursorHandleVisible();
+ }
+
+ gfx::Rect GetCursorRect(const gfx::SelectionModel& sel) {
+ return textfield_test_api_->GetRenderText()->GetCursorBounds(sel, true);
+ }
+
gfx::Point GetCursorPosition(const gfx::SelectionModel& sel) {
- gfx::RenderText* render_text = textfield_view_->GetRenderText();
- gfx::Rect cursor_bounds = render_text->GetCursorBounds(sel, true);
+ gfx::Rect cursor_bounds = GetCursorRect(sel);
return gfx::Point(cursor_bounds.x(), cursor_bounds.y());
}
TouchSelectionControllerImpl* GetSelectionController() {
return static_cast<TouchSelectionControllerImpl*>(
- textfield_view_->touch_selection_controller_.get());
+ textfield_test_api_->touch_selection_controller());
+ }
+
+ void StartTouchEditing() {
+ textfield_test_api_->CreateTouchSelectionControllerAndNotifyIt();
+ }
+
+ void EndTouchEditing() {
+ textfield_test_api_->ResetTouchSelectionController();
}
void SimulateSelectionHandleDrag(gfx::Point p, int selection_handle) {
@@ -114,6 +157,10 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
controller->dragging_handle_ = NULL;
}
+ gfx::NativeView GetCursorHandleNativeView() {
+ return GetSelectionController()->GetCursorHandleNativeView();
+ }
+
gfx::Point GetSelectionHandle1Position() {
return GetSelectionController()->GetSelectionHandle1Position();
}
@@ -139,13 +186,23 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
}
gfx::RenderText* GetRenderText() {
- return textfield_view_->GetRenderText();
+ return textfield_test_api_->GetRenderText();
}
+ gfx::Point GetCursorHandleDragPoint() {
+ gfx::Point point = GetCursorHandlePosition();
+ const gfx::SelectionModel& sel = textfield_->GetSelectionModel();
+ int cursor_height = GetCursorRect(sel).height();
+ point.Offset(GetHandleImageSize().width() / 2 + kPadding,
+ GetHandleImageSize().height() / 2 + cursor_height);
+ return point;
+ }
+
+ Widget* textfield_widget_;
Widget* widget_;
Textfield* textfield_;
- NativeTextfieldViews* textfield_view_;
+ scoped_ptr<TextfieldTestApi> textfield_test_api_;
scoped_ptr<ViewsTouchSelectionControllerFactory> views_tsc_factory_;
private:
@@ -158,7 +215,7 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
// handle 1's position is matched against the start of selection or the end.
#define VERIFY_HANDLE_POSITIONS(cursor_at_selection_handle_1) \
{ \
- gfx::SelectionModel sel = textfield_view_->GetSelectionModel(); \
+ gfx::SelectionModel sel = textfield_->GetSelectionModel(); \
if (textfield_->HasSelection()) { \
EXPECT_TRUE(IsSelectionHandle1Visible()); \
EXPECT_TRUE(IsSelectionHandle2Visible()); \
@@ -197,7 +254,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) {
// Tap the textfield to invoke touch selection.
ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0);
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
// Test selecting a range.
textfield_->SelectRange(gfx::Range(3, 7));
@@ -212,13 +269,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) {
VERIFY_HANDLE_POSITIONS(false);
// Test with lost focus.
- widget_->GetFocusManager()->ClearFocus();
+ textfield_widget_->GetFocusManager()->ClearFocus();
EXPECT_FALSE(GetSelectionController());
// Test with focus re-gained.
- widget_->GetFocusManager()->SetFocusedView(textfield_);
+ textfield_widget_->GetFocusManager()->SetFocusedView(textfield_);
EXPECT_FALSE(GetSelectionController());
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
VERIFY_HANDLE_POSITIONS(false);
}
@@ -229,7 +286,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) {
// Tap the textfield to invoke touch selection.
ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0);
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
// Test cursor at run boundary and with empty selection.
textfield_->SelectSelectionModel(
@@ -277,15 +334,15 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) {
// Tap the textfield to invoke touch selection.
ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0);
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
textfield_->SelectRange(gfx::Range(3, 7));
EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "tfie");
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 2 to right by 3 chars.
- const gfx::Font& font = textfield_->GetPrimaryFont();
- int x = font.GetStringWidth(ASCIIToUTF16("ld "));
+ const gfx::FontList& font_list = textfield_->GetFontList();
+ int x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("ld "), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 2);
EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "tfield ");
VERIFY_HANDLE_POSITIONS(false);
@@ -297,13 +354,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) {
VERIFY_HANDLE_POSITIONS(true);
// Drag selection handle 1 across selection handle 2.
- x = font.GetStringWidth(ASCIIToUTF16("textfield with "));
+ x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("textfield with "), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 1);
EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "with ");
VERIFY_HANDLE_POSITIONS(true);
// Drag selection handle 2 across selection handle 1.
- x = font.GetStringWidth(ASCIIToUTF16("with selected "));
+ x = gfx::Canvas::GetStringWidth(ASCIIToUTF16("with selected "), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 2);
EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "selected ");
VERIFY_HANDLE_POSITIONS(false);
@@ -315,7 +372,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
// Tap the textfield to invoke touch selection.
ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0);
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
// Select [c] from left to right.
textfield_->SelectRange(gfx::Range(2, 3));
@@ -323,14 +380,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 2 to right by 1 char.
- const gfx::Font& font = textfield_->GetPrimaryFont();
- int x = font.GetStringWidth(WideToUTF16(L"\x05e3"));
+ const gfx::FontList& font_list = textfield_->GetFontList();
+ int x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e3"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 2);
EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 1 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"b"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"b"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1);
EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
@@ -341,13 +398,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 1 to right by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"\x05e3"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e3"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 1);
EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
// Drag selection handle 2 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"b"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"b"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2);
EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
@@ -366,14 +423,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
Need further investigation on whether this is a bug in Pango and how to
work around it.
// Drag selection handle 2 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"\x05e2"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2);
EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
*/
// Drag selection handle 1 to right by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"d"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"d"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 1);
EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3" L"d"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
@@ -385,14 +442,14 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
/* TODO(xji): see detail of above commented out test case.
// Drag selection handle 1 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"\x05e2"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1);
EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
*/
// Drag selection handle 2 to right by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"d"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"d"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 2);
EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3" L"d"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
@@ -403,13 +460,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 2 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"c"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"c"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2);
EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 1 to right by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"\x05e2"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 1);
EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
@@ -420,13 +477,13 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) {
VERIFY_HANDLE_POSITIONS(false);
// Drag selection handle 1 to left by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"c"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"c"), font_list);
SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1);
EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(true);
// Drag selection handle 2 to right by 1 char.
- x = font.GetStringWidth(WideToUTF16(L"\x05e2"));
+ x = gfx::Canvas::GetStringWidth(WideToUTF16(L"\x05e2"), font_list);
SimulateSelectionHandleDrag(gfx::Point(x, 0), 2);
EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText());
VERIFY_HANDLE_POSITIONS(false);
@@ -444,7 +501,7 @@ TEST_F(TouchSelectionControllerImplTest,
// Tap the textfield to invoke selection.
ui::GestureEvent tap(ui::ET_GESTURE_TAP, 0, 0, 0, base::TimeDelta(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP, 1.0f, 0.0f), 0);
- textfield_view_->OnGestureEvent(&tap);
+ textfield_->OnGestureEvent(&tap);
// Select some text such that one handle is hidden.
textfield_->SelectRange(gfx::Range(10, textfield_text.length()));
@@ -467,9 +524,8 @@ TEST_F(TouchSelectionControllerImplTest,
}
}
-#if defined(USE_AURA)
TEST_F(TouchSelectionControllerImplTest,
- DoubleTapInTextfieldWithCursorHandleShouldSelectWord) {
+ DoubleTapInTextfieldWithCursorHandleShouldSelectText) {
CreateTextfield();
textfield_->SetText(ASCIIToUTF16("some text"));
aura::test::EventGenerator generator(
@@ -490,8 +546,302 @@ TEST_F(TouchSelectionControllerImplTest,
generator.GestureTapAt(cursor_pos);
generator.GestureTapAt(cursor_pos);
EXPECT_TRUE(textfield_->HasSelection());
- VERIFY_HANDLE_POSITIONS(false);
}
-#endif
+
+// A simple implementation of TouchEditable that allows faking cursor position
+// inside its boundaries.
+class TestTouchEditable : public ui::TouchEditable {
+ public:
+ explicit TestTouchEditable(aura::Window* window)
+ : window_(window) {
+ DCHECK(window);
+ }
+
+ void set_bounds(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+ }
+
+ void set_cursor_rect(const gfx::Rect& cursor_rect) {
+ cursor_rect_ = cursor_rect;
+ }
+
+ virtual ~TestTouchEditable() {}
+
+ private:
+ // Overridden from ui::TouchEditable.
+ virtual void SelectRect(
+ const gfx::Point& start, const gfx::Point& end) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE {
+ *p1 = *p2 = cursor_rect_;
+ }
+ virtual gfx::Rect GetBounds() OVERRIDE {
+ return gfx::Rect(bounds_.size());
+ }
+ virtual gfx::NativeView GetNativeView() const OVERRIDE {
+ return window_;
+ }
+ virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE {
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window_->GetRootWindow());
+ if (screen_position_client)
+ screen_position_client->ConvertPointToScreen(window_, point);
+ }
+ virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE {
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window_->GetRootWindow());
+ if (screen_position_client)
+ screen_position_client->ConvertPointFromScreen(window_, point);
+ }
+ virtual bool DrawsHandles() OVERRIDE {
+ return false;
+ }
+ virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void DestroyTouchSelection() OVERRIDE {
+ NOTREACHED();
+ }
+
+ // Overridden from ui::SimpleMenuModel::Delegate.
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
+ NOTREACHED();
+ }
+
+ aura::Window* window_;
+
+ // Boundaries of the client view.
+ gfx::Rect bounds_;
+
+ // Cursor position inside the client view.
+ gfx::Rect cursor_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTouchEditable);
+};
+
+// Tests if the touch editing handle is shown or hidden properly according to
+// the cursor position relative to the client boundaries.
+TEST_F(TouchSelectionControllerImplTest,
+ VisibilityOfHandleRegardingClientBounds) {
+ CreateWidget();
+
+ TestTouchEditable touch_editable(widget_->GetNativeView());
+ scoped_ptr<ui::TouchSelectionController> touch_selection_controller(
+ ui::TouchSelectionController::create(&touch_editable));
+
+ touch_editable.set_bounds(gfx::Rect(0, 0, 100, 20));
+
+ // Put the cursor completely inside the client bounds. Handle should be
+ // visible.
+ touch_editable.set_cursor_rect(gfx::Rect(2, 0, 1, 20));
+ touch_selection_controller->SelectionChanged();
+ EXPECT_TRUE(IsCursorHandleVisibleFor(touch_selection_controller.get()));
+
+ // Move the cursor up such that |kBarMinHeight| pixels are still in the client
+ // bounds. Handle should still be visible.
+ touch_editable.set_cursor_rect(gfx::Rect(2, kBarMinHeight - 20, 1, 20));
+ touch_selection_controller->SelectionChanged();
+ EXPECT_TRUE(IsCursorHandleVisibleFor(touch_selection_controller.get()));
+
+ // Move the cursor up such that less than |kBarMinHeight| pixels are in the
+ // client bounds. Handle should be hidden.
+ touch_editable.set_cursor_rect(gfx::Rect(2, kBarMinHeight - 20 - 1, 1, 20));
+ touch_selection_controller->SelectionChanged();
+ EXPECT_FALSE(IsCursorHandleVisibleFor(touch_selection_controller.get()));
+
+ // Move the Cursor down such that |kBarBottomAllowance| pixels are out of the
+ // client bounds. Handle should be visible.
+ touch_editable.set_cursor_rect(gfx::Rect(2, kBarBottomAllowance, 1, 20));
+ touch_selection_controller->SelectionChanged();
+ EXPECT_TRUE(IsCursorHandleVisibleFor(touch_selection_controller.get()));
+
+ // Move the cursor down such that more than |kBarBottomAllowance| pixels are
+ // out of the client bounds. Handle should be hidden.
+ touch_editable.set_cursor_rect(gfx::Rect(2, kBarBottomAllowance + 1, 1, 20));
+ touch_selection_controller->SelectionChanged();
+ EXPECT_FALSE(IsCursorHandleVisibleFor(touch_selection_controller.get()));
+
+ touch_selection_controller.reset();
+}
+
+TEST_F(TouchSelectionControllerImplTest, HandlesStackAboveParent) {
+ ui::EventTarget* root = GetContext();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+
+ // Create the first window containing a Views::Textfield.
+ CreateTextfield();
+ aura::Window* window1 = textfield_widget_->GetNativeView();
+
+ // Start touch editing, check that the handle is above the first window, and
+ // end touch editing.
+ StartTouchEditing();
+ gfx::Point test_point = GetCursorHandleDragPoint();
+ ui::MouseEvent test_event1(ui::ET_MOUSE_MOVED, test_point, test_point,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(GetCursorHandleNativeView(),
+ targeter->FindTargetForEvent(root, &test_event1));
+ EndTouchEditing();
+
+ // Create the second (empty) window over the first one.
+ CreateWidget();
+ aura::Window* window2 = widget_->GetNativeView();
+
+ // Start touch editing (in the first window) and check that the handle is not
+ // above the second window.
+ StartTouchEditing();
+ ui::MouseEvent test_event2(ui::ET_MOUSE_MOVED, test_point, test_point,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(window2, targeter->FindTargetForEvent(root, &test_event2));
+
+ // Move the first window to top and check that the handle is kept above the
+ // first window.
+ window1->GetRootWindow()->StackChildAtTop(window1);
+ ui::MouseEvent test_event3(ui::ET_MOUSE_MOVED, test_point, test_point,
+ ui::EF_NONE, ui::EF_NONE);
+ EXPECT_EQ(GetCursorHandleNativeView(),
+ targeter->FindTargetForEvent(root, &test_event3));
+}
+
+// A simple implementation of TouchEditingMenuController that enables all
+// available commands.
+class TestTouchEditingMenuController : public TouchEditingMenuController {
+ public:
+ TestTouchEditingMenuController() {}
+ virtual ~TestTouchEditingMenuController() {}
+
+ // Overriden from TouchEditingMenuController.
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
+ // Return true, since we want the menu to have all |kMenuCommandCount|
+ // available commands.
+ return true;
+ }
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void OpenContextMenu() OVERRIDE {
+ NOTREACHED();
+ }
+ virtual void OnMenuClosed(TouchEditingMenuView* menu) OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestTouchEditingMenuController);
+};
+
+// Tests if anchor rect for touch editing quick menu is adjusted correctly based
+// on the distance of handles.
+TEST_F(TouchSelectionControllerImplTest, QuickMenuAdjustsAnchorRect) {
+ CreateWidget();
+ aura::Window* window = widget_->GetNativeView();
+
+ scoped_ptr<TestTouchEditingMenuController> quick_menu_controller(
+ new TestTouchEditingMenuController());
+
+ // Some arbitrary size for touch editing handle image.
+ gfx::Size handle_image_size(10, 10);
+
+ // Calculate the width of quick menu. In addition to |kMenuCommandCount|
+ // commands, there is an item for ellipsis.
+ int quick_menu_width = (kMenuCommandCount + 1) * kMenuButtonWidth +
+ kMenuCommandCount;
+
+ // Set anchor rect's width a bit smaller than the quick menu width plus handle
+ // image width and check that anchor rect's height is adjusted.
+ gfx::Rect anchor_rect(
+ 0, 0, quick_menu_width + handle_image_size.width() - 10, 20);
+ TouchEditingMenuView* quick_menu(TouchEditingMenuView::Create(
+ quick_menu_controller.get(), anchor_rect, handle_image_size, window));
+ anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
+ EXPECT_EQ(anchor_rect.ToString(), quick_menu->GetAnchorRect().ToString());
+
+ // Set anchor rect's width a bit greater than the quick menu width plus handle
+ // image width and check that anchor rect's height is not adjusted.
+ anchor_rect =
+ gfx::Rect(0, 0, quick_menu_width + handle_image_size.width() + 10, 20);
+ quick_menu = TouchEditingMenuView::Create(
+ quick_menu_controller.get(), anchor_rect, handle_image_size, window);
+ EXPECT_EQ(anchor_rect.ToString(), quick_menu->GetAnchorRect().ToString());
+
+ // Close the widget, hence quick menus, before quick menu controller goes out
+ // of scope.
+ widget_->CloseNow();
+ widget_ = NULL;
+}
+
+TEST_F(TouchSelectionControllerImplTest, MouseEventDeactivatesTouchSelection) {
+ CreateTextfield();
+ EXPECT_FALSE(GetSelectionController());
+
+ aura::test::EventGenerator generator(
+ textfield_widget_->GetNativeView()->GetRootWindow());
+
+ generator.set_current_location(gfx::Point(5, 5));
+ RunPendingMessages();
+
+ // Start touch editing; then move mouse over the textfield and ensure it
+ // deactivates touch selection.
+ StartTouchEditing();
+ EXPECT_TRUE(GetSelectionController());
+ generator.MoveMouseTo(gfx::Point(5, 10));
+ RunPendingMessages();
+ EXPECT_FALSE(GetSelectionController());
+
+ generator.MoveMouseTo(gfx::Point(5, 50));
+ RunPendingMessages();
+
+ // Start touch editing; then move mouse out of the textfield, but inside the
+ // winow and ensure it deactivates touch selection.
+ StartTouchEditing();
+ EXPECT_TRUE(GetSelectionController());
+ generator.MoveMouseTo(gfx::Point(5, 55));
+ RunPendingMessages();
+ EXPECT_FALSE(GetSelectionController());
+
+ generator.MoveMouseTo(gfx::Point(5, 500));
+ RunPendingMessages();
+
+ // Start touch editing; then move mouse out of the textfield and window and
+ // ensure it deactivates touch selection.
+ StartTouchEditing();
+ EXPECT_TRUE(GetSelectionController());
+ generator.MoveMouseTo(5, 505);
+ RunPendingMessages();
+ EXPECT_FALSE(GetSelectionController());
+}
+
+TEST_F(TouchSelectionControllerImplTest, KeyEventDeactivatesTouchSelection) {
+ CreateTextfield();
+ EXPECT_FALSE(GetSelectionController());
+
+ aura::test::EventGenerator generator(
+ textfield_widget_->GetNativeView()->GetRootWindow());
+
+ RunPendingMessages();
+
+ // Start touch editing; then press a key and ensure it deactivates touch
+ // selection.
+ StartTouchEditing();
+ EXPECT_TRUE(GetSelectionController());
+ generator.PressKey(ui::VKEY_A, 0);
+ RunPendingMessages();
+ EXPECT_FALSE(GetSelectionController());
+}
} // namespace views
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index 40ad7cce2d9..c8ebd0abb67 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -16,9 +16,9 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkRect.h"
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/ui_base_switches_util.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
@@ -39,6 +39,7 @@
#include "ui/views/border.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/drag_controller.h"
+#include "ui/views/focus/view_storage.h"
#include "ui/views/layout/layout_manager.h"
#include "ui/views/rect_based_targeting_utils.h"
#include "ui/views/views_delegate.h"
@@ -47,24 +48,12 @@
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
#if defined(OS_WIN)
#include "base/win/scoped_gdi_object.h"
#endif
namespace {
-// Whether to use accelerated compositing when necessary (e.g. when a view has a
-// transformation).
-#if defined(USE_AURA)
-bool use_acceleration_when_possible = true;
-#else
-bool use_acceleration_when_possible = false;
-#endif
-
#if defined(OS_WIN)
const bool kContextMenuOnMousePress = false;
#else
@@ -76,6 +65,14 @@ const bool kContextMenuOnMousePress = true;
// rect-based targeting algorithm.
static const float kRectTargetOverlap = 0.6f;
+// Default horizontal drag threshold in pixels.
+// Same as what gtk uses.
+const int kDefaultHorizontalDragThreshold = 8;
+
+// Default vertical drag threshold in pixels.
+// Same as what gtk uses.
+const int kDefaultVerticalDragThreshold = 8;
+
// Returns the top view in |view|'s hierarchy.
const views::View* GetHierarchyRoot(const views::View* view) {
const views::View* root = view;
@@ -90,54 +87,6 @@ namespace views {
namespace internal {
-// This event handler receives events in the post-target phase and takes care of
-// the following:
-// - Generates context menu, or initiates drag-and-drop, from gesture events.
-class PostEventDispatchHandler : public ui::EventHandler {
- public:
- explicit PostEventDispatchHandler(View* owner)
- : owner_(owner),
- touch_dnd_enabled_(switches::IsTouchDragDropEnabled()) {
- }
- virtual ~PostEventDispatchHandler() {}
-
- private:
- // Overridden from ui::EventHandler:
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
- DCHECK_EQ(ui::EP_POSTTARGET, event->phase());
- if (event->handled())
- return;
-
- if (touch_dnd_enabled_) {
- if (event->type() == ui::ET_GESTURE_LONG_PRESS &&
- (!owner_->drag_controller() ||
- owner_->drag_controller()->CanStartDragForView(
- owner_, event->location(), event->location()))) {
- if (owner_->DoDrag(*event, event->location(),
- ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)) {
- event->StopPropagation();
- return;
- }
- }
- }
-
- if (owner_->context_menu_controller() &&
- (event->type() == ui::ET_GESTURE_LONG_PRESS ||
- event->type() == ui::ET_GESTURE_LONG_TAP ||
- event->type() == ui::ET_GESTURE_TWO_FINGER_TAP)) {
- gfx::Point location(event->location());
- View::ConvertPointToScreen(owner_, &location);
- owner_->ShowContextMenu(location, ui::MENU_SOURCE_TOUCH);
- event->StopPropagation();
- }
- }
-
- View* owner_;
- bool touch_dnd_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler);
-};
-
} // namespace internal
// static
@@ -160,6 +109,7 @@ View::View()
enabled_(true),
notify_enter_exit_on_child_(false),
registered_for_visible_bounds_notification_(false),
+ root_bounds_dirty_(true),
clip_insets_(0, 0, 0, 0),
needs_layout_(true),
flip_canvas_on_paint_for_rtl_ui_(false),
@@ -172,15 +122,15 @@ View::View()
accessibility_focusable_(false),
context_menu_controller_(NULL),
drag_controller_(NULL),
- post_dispatch_handler_(new internal::PostEventDispatchHandler(this)),
native_view_accessibility_(NULL) {
- AddPostTargetHandler(post_dispatch_handler_.get());
}
View::~View() {
if (parent_)
parent_->RemoveChildView(this);
+ ViewStorage::GetInstance()->ViewRemoved(this);
+
for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
(*i)->parent_ = NULL;
if (!(*i)->owned_by_client_)
@@ -217,8 +167,9 @@ void View::AddChildViewAt(View* view, int index) {
// If |view| has a parent, remove it from its parent.
View* parent = view->parent_;
- const ui::NativeTheme* old_theme = view->GetNativeTheme();
+ ui::NativeTheme* old_theme = NULL;
if (parent) {
+ old_theme = view->GetNativeTheme();
if (parent == this) {
ReorderChildView(view, index);
return;
@@ -233,6 +184,16 @@ void View::AddChildViewAt(View* view, int index) {
view->parent_ = this;
children_.insert(children_.begin() + index, view);
+ // Instruct the view to recompute its root bounds on next Paint().
+ view->SetRootBoundsDirty(true);
+
+ views::Widget* widget = GetWidget();
+ if (widget) {
+ const ui::NativeTheme* new_theme = view->GetNativeTheme();
+ if (new_theme != old_theme)
+ view->PropagateNativeThemeChanged(new_theme);
+ }
+
ViewHierarchyChangedDetails details(true, this, view, parent);
for (View* v = this; v; v = v->parent_)
@@ -240,19 +201,16 @@ void View::AddChildViewAt(View* view, int index) {
view->PropagateAddNotifications(details);
UpdateTooltip();
- views::Widget* widget = GetWidget();
if (widget) {
RegisterChildrenForVisibleBoundsNotification(view);
- const ui::NativeTheme* new_theme = widget->GetNativeTheme();
- if (new_theme != old_theme)
- PropagateNativeThemeChanged(new_theme);
+ if (view->visible())
+ view->SchedulePaint();
}
if (layout_manager_.get())
layout_manager_->ViewAdded(this, view);
- if (use_acceleration_when_possible)
- ReorderLayers();
+ ReorderLayers();
// Make sure the visibility of the child layers are correct.
// If any of the parent View is hidden, then the layers of the subtree
@@ -286,8 +244,7 @@ void View::ReorderChildView(View* view, int index) {
InitFocusSiblings(view, index);
children_.insert(children_.begin() + index, view);
- if (use_acceleration_when_possible)
- ReorderLayers();
+ ReorderLayers();
}
void View::RemoveChildView(View* view) {
@@ -416,7 +373,7 @@ gfx::Rect View::GetBoundsInScreen() const {
return gfx::Rect(origin, size());
}
-gfx::Size View::GetPreferredSize() {
+gfx::Size View::GetPreferredSize() const {
if (layout_manager_.get())
return layout_manager_->GetPreferredSize(this);
return gfx::Size();
@@ -432,15 +389,15 @@ void View::SizeToPreferredSize() {
SetBounds(x(), y(), prefsize.width(), prefsize.height());
}
-gfx::Size View::GetMinimumSize() {
+gfx::Size View::GetMinimumSize() const {
return GetPreferredSize();
}
-gfx::Size View::GetMaximumSize() {
+gfx::Size View::GetMaximumSize() const {
return gfx::Size();
}
-int View::GetHeightForWidth(int w) {
+int View::GetHeightForWidth(int w) const {
if (layout_manager_.get())
return layout_manager_->GetPreferredHeightForWidth(this, w);
return GetPreferredSize().height();
@@ -508,6 +465,31 @@ void View::SetTransform(const gfx::Transform& transform) {
}
void View::SetPaintToLayer(bool paint_to_layer) {
+ if (paint_to_layer_ == paint_to_layer)
+ return;
+
+ // If this is a change in state we will also need to update bounds trees.
+ if (paint_to_layer) {
+ // Gaining a layer means becoming a paint root. We must remove ourselves
+ // from our old paint root, if we had one. Traverse up view tree to find old
+ // paint root.
+ View* old_paint_root = parent_;
+ while (old_paint_root && !old_paint_root->IsPaintRoot())
+ old_paint_root = old_paint_root->parent_;
+
+ // Remove our and our children's bounds from the old tree. This will also
+ // mark all of our bounds as dirty.
+ if (old_paint_root && old_paint_root->bounds_tree_)
+ RemoveRootBounds(old_paint_root->bounds_tree_.get());
+
+ } else {
+ // Losing a layer means we are no longer a paint root, so delete our
+ // bounds tree and mark ourselves as dirty for future insertion into our
+ // new paint root's bounds tree.
+ bounds_tree_.reset();
+ SetRootBoundsDirty(true);
+ }
+
paint_to_layer_ = paint_to_layer;
if (paint_to_layer_ && !layer()) {
CreateLayer();
@@ -516,16 +498,6 @@ void View::SetPaintToLayer(bool paint_to_layer) {
}
}
-ui::Layer* View::RecreateLayer() {
- ui::Layer* layer = AcquireLayer();
- if (!layer)
- return NULL;
-
- CreateLayer();
- layer_->set_scale_content(layer->scale_content());
- return layer;
-}
-
// RTL positioning -------------------------------------------------------------
gfx::Rect View::GetMirroredBounds() const {
@@ -606,14 +578,19 @@ const char* View::GetClassName() const {
return kViewClassName;
}
-View* View::GetAncestorWithClassName(const std::string& name) {
- for (View* view = this; view; view = view->parent_) {
+const View* View::GetAncestorWithClassName(const std::string& name) const {
+ for (const View* view = this; view; view = view->parent_) {
if (!strcmp(view->GetClassName(), name.c_str()))
return view;
}
return NULL;
}
+View* View::GetAncestorWithClassName(const std::string& name) {
+ return const_cast<View*>(const_cast<const View*>(this)->
+ GetAncestorWithClassName(name));
+}
+
const View* View::GetViewByID(int id) const {
if (id == id_)
return const_cast<View*>(this);
@@ -773,40 +750,73 @@ void View::SchedulePaintInRect(const gfx::Rect& rect) {
}
}
-void View::Paint(gfx::Canvas* canvas) {
- TRACE_EVENT1("views", "View::Paint", "class", GetClassName());
+void View::Paint(gfx::Canvas* canvas, const CullSet& cull_set) {
+ // The cull_set may allow us to skip painting without canvas construction or
+ // even canvas rect intersection.
+ if (cull_set.ShouldPaint(this)) {
+ TRACE_EVENT1("views", "View::Paint", "class", GetClassName());
- gfx::ScopedCanvas scoped_canvas(canvas);
+ gfx::ScopedCanvas scoped_canvas(canvas);
- // Paint this View and its children, setting the clip rect to the bounds
- // of this View and translating the origin to the local bounds' top left
- // point.
- //
- // Note that the X (or left) position we pass to ClipRectInt takes into
- // consideration whether or not the view uses a right-to-left layout so that
- // we paint our view in its mirrored position if need be.
- gfx::Rect clip_rect = bounds();
- clip_rect.Inset(clip_insets_);
- if (parent_)
- clip_rect.set_x(parent_->GetMirroredXForRect(clip_rect));
- if (!canvas->ClipRect(clip_rect))
- return;
+ // Paint this View and its children, setting the clip rect to the bounds
+ // of this View and translating the origin to the local bounds' top left
+ // point.
+ //
+ // Note that the X (or left) position we pass to ClipRectInt takes into
+ // consideration whether or not the view uses a right-to-left layout so that
+ // we paint our view in its mirrored position if need be.
+ gfx::Rect clip_rect = bounds();
+ clip_rect.Inset(clip_insets_);
+ if (parent_)
+ clip_rect.set_x(parent_->GetMirroredXForRect(clip_rect));
+ canvas->ClipRect(clip_rect);
+ if (canvas->IsClipEmpty())
+ return;
+
+ // Non-empty clip, translate the graphics such that 0,0 corresponds to where
+ // this view is located (related to its parent).
+ canvas->Translate(GetMirroredPosition().OffsetFromOrigin());
+ canvas->Transform(GetTransform());
- // Non-empty clip, translate the graphics such that 0,0 corresponds to
- // where this view is located (related to its parent).
- canvas->Translate(GetMirroredPosition().OffsetFromOrigin());
- canvas->Transform(GetTransform());
+ // If we are a paint root, we need to construct our own CullSet object for
+ // propagation to our children.
+ if (IsPaintRoot()) {
+ if (!bounds_tree_)
+ bounds_tree_.reset(new BoundsTree(2, 5));
- PaintCommon(canvas);
+ // Recompute our bounds tree as needed.
+ UpdateRootBounds(bounds_tree_.get(), gfx::Vector2d());
+
+ // Grab the clip rect from the supplied canvas to use as the query rect.
+ gfx::Rect canvas_bounds;
+ if (!canvas->GetClipBounds(&canvas_bounds)) {
+ NOTREACHED() << "Failed to get clip bounds from the canvas!";
+ return;
+ }
+
+ // Now query our bounds_tree_ for a set of damaged views that intersect
+ // our canvas bounds.
+ scoped_ptr<base::hash_set<intptr_t> > damaged_views(
+ new base::hash_set<intptr_t>());
+ bounds_tree_->AppendIntersectingRecords(
+ canvas_bounds, damaged_views.get());
+ // Construct a CullSet to wrap the damaged views set, it will delete it
+ // for us on scope exit.
+ CullSet paint_root_cull_set(damaged_views.Pass());
+ // Paint all descendents using our new cull set.
+ PaintCommon(canvas, paint_root_cull_set);
+ } else {
+ // Not a paint root, so we can proceed as normal.
+ PaintCommon(canvas, cull_set);
+ }
+ }
}
void View::set_background(Background* b) {
background_.reset(b);
}
-void View::set_border(Border* b) {
- border_.reset(b);
-}
+void View::SetBorder(scoped_ptr<Border> b) { border_ = b.Pass(); }
ui::ThemeProvider* View::GetThemeProvider() const {
const Widget* widget = GetWidget();
@@ -818,18 +828,6 @@ const ui::NativeTheme* View::GetNativeTheme() const {
return widget ? widget->GetNativeTheme() : ui::NativeTheme::instance();
}
-// Accelerated Painting --------------------------------------------------------
-
-// static
-void View::set_use_acceleration_when_possible(bool use) {
- use_acceleration_when_possible = use;
-}
-
-// static
-bool View::get_use_acceleration_when_possible() {
- return use_acceleration_when_possible;
-}
-
// Input -----------------------------------------------------------------------
View* View::GetEventHandlerForPoint(const gfx::Point& point) {
@@ -852,6 +850,9 @@ View* View::GetEventHandlerForRect(const gfx::Rect& rect) {
for (int i = child_count() - 1; i >= 0; --i) {
View* child = child_at(i);
+ if (!child->CanProcessEventsWithinSubtree())
+ continue;
+
// Ignore any children which are invisible or do not intersect |rect|.
if (!child->visible())
continue;
@@ -907,8 +908,12 @@ View* View::GetEventHandlerForRect(const gfx::Rect& rect) {
return rect_view ? rect_view : point_view;
}
+bool View::CanProcessEventsWithinSubtree() const {
+ return true;
+}
+
View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
- if (!HitTestPoint(point))
+ if (!HitTestPoint(point) || !CanProcessEventsWithinSubtree())
return NULL;
// Walk the child Views recursively looking for the View that most
@@ -929,16 +934,11 @@ View* View::GetTooltipHandlerForPoint(const gfx::Point& point) {
gfx::NativeCursor View::GetCursor(const ui::MouseEvent& event) {
#if defined(OS_WIN)
-#if defined(USE_AURA)
static ui::Cursor arrow;
if (!arrow.platform())
arrow.SetPlatformCursor(LoadCursor(NULL, IDC_ARROW));
return arrow;
#else
- static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
- return arrow;
-#endif
-#else
return gfx::kNullCursor;
#endif
}
@@ -955,18 +955,11 @@ bool View::HitTestRect(const gfx::Rect& rect) const {
if (!views::UsePointBasedTargeting(rect))
source = HIT_TEST_SOURCE_TOUCH;
GetHitTestMask(source, &mask);
-#if defined(USE_AURA)
- // TODO: should we use this every where?
SkRegion clip_region;
clip_region.setRect(0, 0, width(), height());
SkRegion mask_region;
return mask_region.setPath(mask, clip_region) &&
mask_region.intersects(RectToSkIRect(rect));
-#elif defined(OS_WIN)
- base::win::ScopedRegion rgn(mask.CreateNativeRegion());
- const RECT r(rect.ToRECT());
- return RectInRegion(rgn, &r) != 0;
-#endif
}
// No mask, but inside our bounds.
return true;
@@ -1070,6 +1063,8 @@ void View::OnMouseEvent(ui::MouseEvent* event) {
break;
case ui::ET_MOUSE_ENTERED:
+ if (event->flags() & ui::EF_TOUCH_ACCESSIBILITY)
+ NotifyAccessibilityEvent(ui::AX_EVENT_HOVER, true);
OnMouseEntered(*event);
break;
@@ -1086,6 +1081,7 @@ void View::OnScrollEvent(ui::ScrollEvent* event) {
}
void View::OnTouchEvent(ui::TouchEvent* event) {
+ NOTREACHED() << "Views should not receive touch events.";
}
void View::OnGestureEvent(ui::GestureEvent* event) {
@@ -1105,6 +1101,13 @@ const InputMethod* View::GetInputMethod() const {
return widget ? widget->GetInputMethod() : NULL;
}
+scoped_ptr<ui::EventTargeter>
+View::SetEventTargeter(scoped_ptr<ui::EventTargeter> targeter) {
+ scoped_ptr<ui::EventTargeter> old_targeter = targeter_.Pass();
+ targeter_ = targeter.Pass();
+ return old_targeter.Pass();
+}
+
bool View::CanAcceptEvent(const ui::Event& event) {
return IsDrawn();
}
@@ -1119,7 +1122,16 @@ scoped_ptr<ui::EventTargetIterator> View::GetChildIterator() const {
}
ui::EventTargeter* View::GetEventTargeter() {
- return NULL;
+ return targeter_.get();
+}
+
+const ui::EventTargeter* View::GetEventTargeter() const {
+ return targeter_.get();
+}
+
+void View::ConvertEventToTarget(ui::EventTarget* target,
+ ui::LocatedEvent* event) {
+ event->ConvertLocationToTarget(this, static_cast<View*>(target));
}
// Accelerators ----------------------------------------------------------------
@@ -1252,7 +1264,7 @@ FocusTraversable* View::GetPaneFocusTraversable() {
// Tooltips --------------------------------------------------------------------
-bool View::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+bool View::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const {
return false;
}
@@ -1326,12 +1338,12 @@ gfx::NativeViewAccessible View::GetNativeViewAccessible() {
}
void View::NotifyAccessibilityEvent(
- ui::AccessibilityTypes::Event event_type,
+ ui::AXEvent event_type,
bool send_native_event) {
if (ViewsDelegate::views_delegate)
ViewsDelegate::views_delegate->NotifyAccessibilityEvent(this, event_type);
- if (send_native_event) {
+ if (send_native_event && GetWidget()) {
if (!native_view_accessibility_)
native_view_accessibility_ = NativeViewAccessibility::Create(this);
if (native_view_accessibility_)
@@ -1402,11 +1414,11 @@ void View::NativeViewHierarchyChanged() {
// Painting --------------------------------------------------------------------
-void View::PaintChildren(gfx::Canvas* canvas) {
+void View::PaintChildren(gfx::Canvas* canvas, const CullSet& cull_set) {
TRACE_EVENT1("views", "View::PaintChildren", "class", GetClassName());
for (int i = 0, count = child_count(); i < count; ++i)
if (!child_at(i)->layer())
- child_at(i)->Paint(canvas);
+ child_at(i)->Paint(canvas, cull_set);
}
void View::OnPaint(gfx::Canvas* canvas) {
@@ -1433,6 +1445,10 @@ void View::OnPaintBorder(gfx::Canvas* canvas) {
}
}
+bool View::IsPaintRoot() {
+ return paint_to_layer_ || !parent_;
+}
+
// Accelerated Painting --------------------------------------------------------
void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
@@ -1484,8 +1500,6 @@ void View::MoveLayerToParent(ui::Layer* parent_layer,
}
void View::UpdateLayerVisibility() {
- if (!use_acceleration_when_possible)
- return;
bool visible = visible_;
for (const View* v = parent_; visible && v && !v->layer(); v = v->parent_)
visible = v->visible();
@@ -1517,7 +1531,7 @@ void View::UpdateChildLayerBounds(const gfx::Vector2d& offset) {
void View::OnPaintLayer(gfx::Canvas* canvas) {
if (!layer() || !layer()->fills_bounds_opaquely())
canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
- PaintCommon(canvas);
+ PaintCommon(canvas, CullSet());
}
void View::OnDeviceScaleFactorChanged(float device_scale_factor) {
@@ -1562,7 +1576,7 @@ void View::ReorderChildLayers(ui::Layer* parent_layer) {
// Iterate backwards through the children so that a child with a layer
// which is further to the back is stacked above one which is further to
// the front.
- for (Views::const_reverse_iterator it(children_.rbegin());
+ for (Views::reverse_iterator it(children_.rbegin());
it != children_.rend(); ++it) {
(*it)->ReorderChildLayers(parent_layer);
}
@@ -1597,7 +1611,7 @@ void View::OnFocus() {
// TODO(beng): Investigate whether it's possible for us to move this to
// Focus().
// Notify assistive technologies of the focus change.
- NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
}
void View::OnBlur() {
@@ -1648,6 +1662,18 @@ bool View::InDrag() {
return widget ? widget->dragged_view() == this : false;
}
+int View::GetHorizontalDragThreshold() {
+ // TODO(jennyz): This value may need to be adjusted for different platforms
+ // and for different display density.
+ return kDefaultHorizontalDragThreshold;
+}
+
+int View::GetVerticalDragThreshold() {
+ // TODO(jennyz): This value may need to be adjusted for different platforms
+ // and for different display density.
+ return kDefaultVerticalDragThreshold;
+}
+
// Debugging -------------------------------------------------------------------
#if !defined(NDEBUG)
@@ -1722,7 +1748,7 @@ std::string View::DoPrintViewGraph(bool first, View* view_with_children) {
if (!parent_)
result.append(", shape=box");
if (layer()) {
- if (layer()->texture())
+ if (layer()->has_external_content())
result.append(", color=green");
else
result.append(", color=red");
@@ -1753,7 +1779,6 @@ std::string View::DoPrintViewGraph(bool first, View* view_with_children) {
return result;
}
-
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -1790,7 +1815,7 @@ void View::SchedulePaintBoundsChanged(SchedulePaintType type) {
}
}
-void View::PaintCommon(gfx::Canvas* canvas) {
+void View::PaintCommon(gfx::Canvas* canvas, const CullSet& cull_set) {
if (!visible_)
return;
@@ -1809,7 +1834,7 @@ void View::PaintCommon(gfx::Canvas* canvas) {
OnPaint(canvas);
}
- PaintChildren(canvas);
+ PaintChildren(canvas, cull_set);
}
// Tree operations -------------------------------------------------------------
@@ -1820,6 +1845,7 @@ void View::DoRemoveChildView(View* view,
bool delete_removed_view,
View* new_parent) {
DCHECK(view);
+
const Views::iterator i(std::find(children_.begin(), children_.end(), view));
scoped_ptr<View> view_to_be_deleted;
if (i != children_.end()) {
@@ -1833,8 +1859,19 @@ void View::DoRemoveChildView(View* view,
next_focusable->previous_focusable_view_ = prev_focusable;
}
- if (GetWidget())
+ if (GetWidget()) {
UnregisterChildrenForVisibleBoundsNotification(view);
+ if (view->visible())
+ view->SchedulePaint();
+ GetWidget()->NotifyWillRemoveView(view);
+ }
+
+ // Remove the bounds of this child and any of its descendants from our
+ // paint root bounds tree.
+ BoundsTree* bounds_tree = GetBoundsTreeFromPaintRoot();
+ if (bounds_tree)
+ view->RemoveRootBounds(bounds_tree);
+
view->PropagateRemoveNotifications(this, new_parent);
view->parent_ = NULL;
view->UpdateLayerVisibility();
@@ -1898,11 +1935,9 @@ void View::ViewHierarchyChangedImpl(
// Make sure the layers belonging to the subtree rooted at |child| get
// removed from layers that do not belong in the same subtree.
OrphanLayers();
- if (use_acceleration_when_possible) {
- Widget* widget = GetWidget();
- if (widget)
- widget->UpdateRootLayers();
- }
+ Widget* widget = GetWidget();
+ if (widget)
+ widget->UpdateRootLayers();
}
ViewHierarchyChanged(details);
@@ -1928,6 +1963,12 @@ void View::VisibilityChangedImpl(View* starting_from, bool is_visible) {
}
void View::BoundsChanged(const gfx::Rect& previous_bounds) {
+ // Mark our bounds as dirty for the paint root, also see if we need to
+ // recompute our children's bounds due to origin change.
+ bool origin_changed =
+ previous_bounds.OffsetFromOrigin() != bounds_.OffsetFromOrigin();
+ SetRootBoundsDirty(origin_changed);
+
if (visible_) {
// Paint the new bounds.
SchedulePaintBoundsChanged(
@@ -1935,28 +1976,18 @@ void View::BoundsChanged(const gfx::Rect& previous_bounds) {
SCHEDULE_PAINT_SIZE_CHANGED);
}
- if (use_acceleration_when_possible) {
- if (layer()) {
- if (parent_) {
- SetLayerBounds(GetLocalBounds() +
- gfx::Vector2d(GetMirroredX(), y()) +
- parent_->CalculateOffsetToAncestorWithLayer(NULL));
- } else {
- SetLayerBounds(bounds_);
- }
- // TODO(beng): this seems redundant with the SchedulePaint at the top of
- // this function. explore collapsing.
- if (previous_bounds.size() != bounds_.size() &&
- !layer()->layer_updated_externally()) {
- // If our bounds have changed then we need to update the complete
- // texture.
- layer()->SchedulePaint(GetLocalBounds());
- }
+ if (layer()) {
+ if (parent_) {
+ SetLayerBounds(GetLocalBounds() +
+ gfx::Vector2d(GetMirroredX(), y()) +
+ parent_->CalculateOffsetToAncestorWithLayer(NULL));
} else {
- // If our bounds have changed, then any descendant layer bounds may
- // have changed. Update them accordingly.
- UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL));
+ SetLayerBounds(bounds_);
}
+ } else {
+ // If our bounds have changed, then any descendant layer bounds may have
+ // changed. Update them accordingly.
+ UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL));
}
OnBoundsChanged(previous_bounds);
@@ -2034,6 +2065,69 @@ void View::SetLayerBounds(const gfx::Rect& bounds) {
layer()->SetBounds(bounds);
}
+void View::SetRootBoundsDirty(bool origin_changed) {
+ root_bounds_dirty_ = true;
+
+ if (origin_changed) {
+ // Inform our children that their root bounds are dirty, as their relative
+ // coordinates in paint root space have changed since ours have changed.
+ for (Views::const_iterator i(children_.begin()); i != children_.end();
+ ++i) {
+ if (!(*i)->IsPaintRoot())
+ (*i)->SetRootBoundsDirty(origin_changed);
+ }
+ }
+}
+
+void View::UpdateRootBounds(BoundsTree* tree, const gfx::Vector2d& offset) {
+ // No need to recompute bounds if we haven't flagged ours as dirty.
+ TRACE_EVENT1("views", "View::UpdateRootBounds", "class", GetClassName());
+
+ // Add our own offset to the provided offset, for our own bounds update and
+ // for propagation to our children if needed.
+ gfx::Vector2d view_offset = offset + GetMirroredBounds().OffsetFromOrigin();
+
+ // If our bounds have changed we must re-insert our new bounds to the tree.
+ if (root_bounds_dirty_) {
+ root_bounds_dirty_ = false;
+ gfx::Rect bounds(
+ view_offset.x(), view_offset.y(), bounds_.width(), bounds_.height());
+ tree->Insert(bounds, reinterpret_cast<intptr_t>(this));
+ }
+
+ // Update our children's bounds if needed.
+ for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
+ // We don't descend in to layer views for bounds recomputation, as they
+ // manage their own RTree as paint roots.
+ if (!(*i)->IsPaintRoot())
+ (*i)->UpdateRootBounds(tree, view_offset);
+ }
+}
+
+void View::RemoveRootBounds(BoundsTree* tree) {
+ tree->Remove(reinterpret_cast<intptr_t>(this));
+
+ root_bounds_dirty_ = true;
+
+ for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
+ if (!(*i)->IsPaintRoot())
+ (*i)->RemoveRootBounds(tree);
+ }
+}
+
+View::BoundsTree* View::GetBoundsTreeFromPaintRoot() {
+ BoundsTree* bounds_tree = bounds_tree_.get();
+ View* paint_root = this;
+ while (!bounds_tree && !paint_root->IsPaintRoot()) {
+ // Assumption is that if IsPaintRoot() is false then parent_ is valid.
+ DCHECK(paint_root);
+ paint_root = paint_root->parent_;
+ bounds_tree = paint_root->bounds_tree_.get();
+ }
+
+ return bounds_tree;
+}
+
// Transformations -------------------------------------------------------------
bool View::GetTransformRelativeTo(const View* ancestor,
@@ -2101,11 +2195,10 @@ void View::CreateLayer() {
for (int i = 0, count = child_count(); i < count; ++i)
child_at(i)->UpdateChildLayerVisibility(true);
- layer_ = new ui::Layer();
- layer_owner_.reset(layer_);
- layer_->set_delegate(this);
+ SetLayer(new ui::Layer());
+ layer()->set_delegate(this);
#if !defined(NDEBUG)
- layer_->set_name(GetClassName());
+ layer()->set_name(GetClassName());
#endif
UpdateParentLayers();
@@ -2146,11 +2239,11 @@ void View::OrphanLayers() {
}
void View::ReparentLayer(const gfx::Vector2d& offset, ui::Layer* parent_layer) {
- layer_->SetBounds(GetLocalBounds() + offset);
+ layer()->SetBounds(GetLocalBounds() + offset);
DCHECK_NE(layer(), parent_layer);
if (parent_layer)
parent_layer->Add(layer());
- layer_->SchedulePaint(GetLocalBounds());
+ layer()->SchedulePaint(GetLocalBounds());
MoveLayerToParent(layer(), gfx::Point());
}
@@ -2163,8 +2256,7 @@ void View::DestroyLayer() {
new_parent->Add(children[i]);
}
- layer_ = NULL;
- layer_owner_.reset();
+ LayerOwner::DestroyLayer();
if (new_parent)
ReorderLayers();
@@ -2189,6 +2281,15 @@ bool View::ProcessMousePressed(const ui::MouseEvent& event) {
context_menu_controller_ : 0;
View::DragInfo* drag_info = GetDragInfo();
+ // TODO(sky): for debugging 360238.
+ int storage_id = 0;
+ if (event.IsOnlyRightMouseButton() && context_menu_controller &&
+ kContextMenuOnMousePress && HitTestPoint(event.location())) {
+ ViewStorage* view_storage = ViewStorage::GetInstance();
+ storage_id = view_storage->CreateStorageID();
+ view_storage->StoreView(storage_id, this);
+ }
+
const bool enabled = enabled_;
const bool result = OnMousePressed(event);
@@ -2201,6 +2302,8 @@ bool View::ProcessMousePressed(const ui::MouseEvent& event) {
// from mouse pressed.
gfx::Point location(event.location());
if (HitTestPoint(location)) {
+ if (storage_id != 0)
+ CHECK_EQ(this, ViewStorage::GetInstance()->RetrieveView(storage_id));
ConvertPointToScreen(this, &location);
ShowContextMenu(location, ui::MENU_SOURCE_MOUSE);
return true;
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index dd298edc0a7..93cbd481ddb 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -16,8 +16,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accessibility/accessibility_types.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
@@ -26,10 +26,13 @@
#include "ui/compositor/layer_owner.h"
#include "ui/events/event.h"
#include "ui/events/event_target.h"
+#include "ui/events/event_targeter.h"
+#include "ui/gfx/geometry/r_tree.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"
+#include "ui/views/cull_set.h"
#include "ui/views/views_export.h"
#if defined(OS_WIN)
@@ -46,7 +49,7 @@ class Transform;
}
namespace ui {
-struct AccessibleViewState;
+struct AXViewState;
class Compositor;
class Layer;
class NativeTheme;
@@ -70,6 +73,7 @@ class ScrollView;
class Widget;
namespace internal {
+class PreEventDispatchHandler;
class PostEventDispatchHandler;
class RootView;
}
@@ -106,8 +110,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
public:
typedef std::vector<View*> Views;
- // TODO(tdanderson,sadrul): Becomes obsolete with the refactoring of the
- // event targeting logic for views and windows.
+ // TODO(tdanderson): Becomes obsolete with the refactoring of the event
+ // targeting logic for views and windows. See
+ // crbug.com/355425.
// Specifies the source of the region used in a hit test.
// HIT_TEST_SOURCE_MOUSE indicates the hit test is being performed with a
// single point and HIT_TEST_SOURCE_TOUCH indicates the hit test is being
@@ -260,24 +265,24 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual int GetBaseline() const;
// Get the size the View would like to be, if enough space were available.
- virtual gfx::Size GetPreferredSize();
+ virtual gfx::Size GetPreferredSize() const;
// Convenience method that sizes this view to its preferred size.
void SizeToPreferredSize();
// Gets the minimum size of the view. View's implementation invokes
// GetPreferredSize.
- virtual gfx::Size GetMinimumSize();
+ virtual gfx::Size GetMinimumSize() const;
// Gets the maximum size of the view. Currently only used for sizing shell
// windows.
- virtual gfx::Size GetMaximumSize();
+ virtual gfx::Size GetMaximumSize() const;
// Return the height necessary to display this view with the provided width.
// View's implementation returns the value from getPreferredSize.cy.
// Override if your View's preferred height depends upon the width (such
// as with Labels).
- virtual int GetHeightForWidth(int w);
+ virtual int GetHeightForWidth(int w) const;
// Set whether this view is visible. Painting is scheduled as needed.
virtual void SetVisible(bool visible);
@@ -323,13 +328,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Compositor.
void SetPaintToLayer(bool paint_to_layer);
- // Recreates a layer for the view and returns the old layer. After this call,
- // the View no longer has a pointer to the old layer (so it won't be able to
- // update the old layer or destroy it). The caller must free the returned
- // layer.
- // Returns NULL and does not recreate layer if view does not own its layer.
- ui::Layer* RecreateLayer() WARN_UNUSED_RESULT;
-
// RTL positioning -----------------------------------------------------------
// Methods for accessing the bounds and position of the view, relative to its
@@ -408,6 +406,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Returns the first ancestor, starting at this, whose class name is |name|.
// Returns null if no ancestor has the class name |name|.
+ const View* GetAncestorWithClassName(const std::string& name) const;
View* GetAncestorWithClassName(const std::string& name);
// Recursively descends the view tree starting at this view, and returns
@@ -505,7 +504,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// for View coordinates and language direction as required, allows the View
// to paint itself via the various OnPaint*() event handlers and then paints
// the hierarchy beneath it.
- virtual void Paint(gfx::Canvas* canvas);
+ virtual void Paint(gfx::Canvas* canvas, const CullSet& cull_set);
// The background object is owned by this object and may be NULL.
void set_background(Background* b);
@@ -513,12 +512,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
Background* background() { return background_.get(); }
// The border object is owned by this object and may be NULL.
- void set_border(Border* b);
+ virtual void SetBorder(scoped_ptr<Border> b);
const Border* border() const { return border_.get(); }
Border* border() { return border_.get(); }
// Get the theme provider from the parent widget.
- virtual ui::ThemeProvider* GetThemeProvider() const;
+ ui::ThemeProvider* GetThemeProvider() const;
// Returns the NativeTheme to use for this View. This calls through to
// GetNativeTheme() on the Widget this View is in. If this View is not in a
@@ -557,16 +556,15 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
flip_canvas_on_paint_for_rtl_ui_ = enable;
}
- // Accelerated painting ------------------------------------------------------
-
- // Enable/Disable accelerated compositing.
- static void set_use_acceleration_when_possible(bool use);
- static bool get_use_acceleration_when_possible();
-
// Input ---------------------------------------------------------------------
// The points, rects, mouse locations, and touch locations in the following
// functions are in the view's coordinates, except for a RootView.
+ // TODO(tdanderson): GetEventHandlerForPoint() and GetEventHandlerForRect()
+ // will be removed once their logic is moved into
+ // ViewTargeter and its derived classes. See
+ // crbug.com/355425.
+
// Convenience functions which calls into GetEventHandler() with
// a 1x1 rect centered at |point|.
View* GetEventHandlerForPoint(const gfx::Point& point);
@@ -592,6 +590,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// the cursor is a shared resource.
virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event);
+ // TODO(tdanderson): HitTestPoint() and HitTestRect() will be removed once
+ // their logic is moved into ViewTargeter and its
+ // derived classes. See crbug.com/355425.
+
// A convenience function which calls HitTestRect() with a rect of size
// 1x1 and an origin of |point|.
bool HitTestPoint(const gfx::Point& point) const;
@@ -599,6 +601,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Tests whether |rect| intersects this view's bounds.
virtual bool HitTestRect(const gfx::Rect& rect) const;
+ // Returns true if this view or any of its descendants are permitted to
+ // be the target of an event.
+ virtual bool CanProcessEventsWithinSubtree() const;
+
// Returns true if the mouse cursor is over |view| and mouse events are
// enabled.
bool IsMouseHovered();
@@ -713,17 +719,26 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual InputMethod* GetInputMethod();
virtual const InputMethod* GetInputMethod() const;
+ // Sets a new event-targeter for the view, and returns the previous
+ // event-targeter.
+ scoped_ptr<ui::EventTargeter> SetEventTargeter(
+ scoped_ptr<ui::EventTargeter> targeter);
+
// Overridden from ui::EventTarget:
virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE;
virtual ui::EventTarget* GetParentTarget() OVERRIDE;
virtual scoped_ptr<ui::EventTargetIterator> GetChildIterator() const OVERRIDE;
virtual ui::EventTargeter* GetEventTargeter() OVERRIDE;
+ virtual void ConvertEventToTarget(ui::EventTarget* target,
+ ui::LocatedEvent* event) OVERRIDE;
+
+ const ui::EventTargeter* GetEventTargeter() const;
// Overridden from ui::EventHandler:
virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE FINAL;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
// Accelerators --------------------------------------------------------------
@@ -773,9 +788,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// not get the focus.
void SetFocusable(bool focusable);
- // Returns true if this view is capable of taking focus.
- bool focusable() const { return focusable_ && enabled_ && visible_; }
-
// Returns true if this view is |focusable_|, |enabled_| and drawn.
virtual bool IsFocusable() const;
@@ -833,7 +845,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Any time the tooltip text that a View is displaying changes, it must
// invoke TooltipTextChanged.
// |p| provides the coordinates of the mouse (relative to this view).
- virtual bool GetTooltipText(const gfx::Point& p, string16* tooltip) const;
+ virtual bool GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const;
// Returns the location (relative to this View) for the text on the tooltip
// to display. If false is returned (the default), the tooltip is placed at
@@ -936,7 +949,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Accessibility -------------------------------------------------------------
// Modifies |state| to reflect the current accessible state of this view.
- virtual void GetAccessibleState(ui::AccessibleViewState* state) { }
+ virtual void GetAccessibleState(ui::AXViewState* state) { }
// Returns an instance of the native accessibility interface for this view.
virtual gfx::NativeViewAccessible GetNativeViewAccessible();
@@ -947,7 +960,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// cases where the view is a native control that's already sending a
// native accessibility event and the duplicate event would cause
// problems.
- void NotifyAccessibilityEvent(ui::AccessibilityTypes::Event event_type,
+ void NotifyAccessibilityEvent(ui::AXEvent event_type,
bool send_native_event);
// Scrolling -----------------------------------------------------------------
@@ -1036,6 +1049,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// changed. The default implementation calls SchedulePaint() on this View.
virtual void OnEnabledChanged();
+ bool needs_layout() const { return needs_layout_; }
+
// Tree operations -----------------------------------------------------------
// This method is invoked when the tree changes.
@@ -1069,7 +1084,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Responsible for calling Paint() on child Views. Override to control the
// order child Views are painted.
- virtual void PaintChildren(gfx::Canvas* canvas);
+ virtual void PaintChildren(gfx::Canvas* canvas, const CullSet& cull_set);
// Override to provide rendering in any part of the View's bounds. Typically
// this is the "contents" of the view. If you override this method you will
@@ -1084,6 +1099,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Override to paint a border not specified by SetBorder().
virtual void OnPaintBorder(gfx::Canvas* canvas);
+ // Returns true if this View is the root for paint events, and should
+ // therefore maintain a |bounds_tree_| member and use it for paint damage rect
+ // calculations.
+ virtual bool IsPaintRoot();
+
// Accelerated painting ------------------------------------------------------
// Returns the offset from this view to the nearest ancestor with a layer. If
@@ -1141,6 +1161,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Focus ---------------------------------------------------------------------
+ // Returns last value passed to SetFocusable(). Use IsFocusable() to determine
+ // if a view can take focus right now.
+ bool focusable() const { return focusable_; }
+
// Override to be notified when focus has changed either to or from this View.
virtual void OnFocus();
virtual void OnBlur();
@@ -1218,11 +1242,14 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
#endif
private:
+ friend class internal::PreEventDispatchHandler;
friend class internal::PostEventDispatchHandler;
friend class internal::RootView;
friend class FocusManager;
friend class Widget;
+ typedef gfx::RTree<intptr_t> BoundsTree;
+
// Painting -----------------------------------------------------------------
enum SchedulePaintType {
@@ -1239,7 +1266,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Common Paint() code shared by accelerated and non-accelerated code paths to
// invoke OnPaint() on the View.
- void PaintCommon(gfx::Canvas* canvas);
+ void PaintCommon(gfx::Canvas* canvas, const CullSet& cull_set);
// Tree operations -----------------------------------------------------------
@@ -1308,6 +1335,25 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Sets the layer's bounds given in DIP coordinates.
void SetLayerBounds(const gfx::Rect& bounds_in_dip);
+ // Sets the bit indicating that the cached bounds for this object within the
+ // root view bounds tree are no longer valid. If |origin_changed| is true sets
+ // the same bit for all of our children as well.
+ void SetRootBoundsDirty(bool origin_changed);
+
+ // If needed, updates the bounds rectangle in paint root coordinate space
+ // in the supplied RTree. Recurses to children for recomputation as well.
+ void UpdateRootBounds(BoundsTree* bounds_tree, const gfx::Vector2d& offset);
+
+ // Remove self and all children from the supplied bounds tree. This is used,
+ // for example, when a view gets a layer and therefore becomes paint root. It
+ // needs to remove all references to itself and its children from any previous
+ // paint root that may have been tracking it.
+ void RemoveRootBounds(BoundsTree* bounds_tree);
+
+ // Traverse up the View hierarchy to the first ancestor that is a paint root
+ // and return a pointer to its |bounds_tree_| or NULL if no tree is found.
+ BoundsTree* GetBoundsTreeFromPaintRoot();
+
// Transformations -----------------------------------------------------------
// Returns in |transform| the transform to get from coordinates of |ancestor|
@@ -1480,6 +1526,15 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// List of descendants wanting notification when their visible bounds change.
scoped_ptr<Views> descendants_to_notify_;
+ // True if the bounds on this object have changed since the last time the
+ // paint root view constructed the spatial database.
+ bool root_bounds_dirty_;
+
+ // If this View IsPaintRoot() then this will be a pointer to a spatial data
+ // structure where we will keep the bounding boxes of all our children, for
+ // efficient paint damage rectangle intersection.
+ scoped_ptr<BoundsTree> bounds_tree_;
+
// Transformations -----------------------------------------------------------
// Clipping parameters. skia transformation matrix does not give us clipping.
@@ -1551,7 +1606,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Input --------------------------------------------------------------------
- scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_;
+ scoped_ptr<ui::EventTargeter> targeter_;
// Accessibility -------------------------------------------------------------
diff --git a/chromium/ui/views/view_aura.cc b/chromium/ui/views/view_aura.cc
deleted file mode 100644
index 006f1da2840..00000000000
--- a/chromium/ui/views/view_aura.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/view.h"
-
-namespace {
-
-// Default horizontal drag threshold in pixels.
-// Same as what gtk uses.
-const int kDefaultHorizontalDragThreshold = 8;
-
-// Default vertical drag threshold in pixels.
-// Same as what gtk uses.
-const int kDefaultVerticalDragThreshold = 8;
-
-} // namespace
-
-namespace views {
-
-int View::GetHorizontalDragThreshold() {
- // TODO(jennyz): This value may need to be adjusted for different platforms
- // and for different display density.
- return kDefaultHorizontalDragThreshold;
-}
-
-int View::GetVerticalDragThreshold() {
- // TODO(jennyz): This value may need to be adjusted for different platforms
- // and for different display density.
- return kDefaultVerticalDragThreshold;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/view_constants_aura.cc b/chromium/ui/views/view_constants_aura.cc
index 977050fb4e8..caf964a3119 100644
--- a/chromium/ui/views/view_constants_aura.cc
+++ b/chromium/ui/views/view_constants_aura.cc
@@ -13,4 +13,6 @@ namespace views {
DEFINE_WINDOW_PROPERTY_KEY(views::View*, kHostViewKey, NULL);
+DEFINE_WINDOW_PROPERTY_KEY(bool, kDesktopRootWindow, false);
+
} // namespace views
diff --git a/chromium/ui/views/view_constants_aura.h b/chromium/ui/views/view_constants_aura.h
index e0d718d2e85..1ca28207617 100644
--- a/chromium/ui/views/view_constants_aura.h
+++ b/chromium/ui/views/view_constants_aura.h
@@ -17,6 +17,10 @@ class View;
// have the same parent widget as the window on which the property is set.
VIEWS_EXPORT extern const aura::WindowProperty<View*>* const kHostViewKey;
+// A property key to indicate if a window is a desktop root window or not.
+// This property is currently set during creation of desktop root window.
+VIEWS_EXPORT extern const aura::WindowProperty<bool>* const kDesktopRootWindow;
+
} // namespace views
#endif // UI_VIEWS_VIEW_CONSTANTS_AURA_H_
diff --git a/chromium/ui/views/view_model.cc b/chromium/ui/views/view_model.cc
index 5f492f5380d..a0a75496450 100644
--- a/chromium/ui/views/view_model.cc
+++ b/chromium/ui/views/view_model.cc
@@ -33,6 +33,11 @@ void ViewModel::Remove(int index) {
}
void ViewModel::Move(int index, int target_index) {
+ DCHECK_LT(index, static_cast<int>(entries_.size()));
+ DCHECK_GE(index, 0);
+ DCHECK_LT(target_index, static_cast<int>(entries_.size()));
+ DCHECK_GE(target_index, 0);
+
if (index == target_index)
return;
Entry entry(entries_[index]);
diff --git a/chromium/ui/views/view_targeter.cc b/chromium/ui/views/view_targeter.cc
new file mode 100644
index 00000000000..31babfb88c0
--- /dev/null
+++ b/chromium/ui/views/view_targeter.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/view_targeter.h"
+
+#include "ui/events/event_target.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+ViewTargeter::ViewTargeter() {}
+ViewTargeter::~ViewTargeter() {}
+
+gfx::RectF ViewTargeter::BoundsForEvent(const ui::LocatedEvent& event) const {
+ gfx::RectF event_bounds(event.location_f(), gfx::SizeF(1, 1));
+ if (event.IsGestureEvent()) {
+ const ui::GestureEvent& gesture =
+ static_cast<const ui::GestureEvent&>(event);
+ event_bounds = gesture.details().bounding_box_f();
+ }
+
+ return event_bounds;
+}
+
+ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) {
+ View* view = static_cast<View*>(root);
+ if (event->IsKeyEvent())
+ return FindTargetForKeyEvent(view, *static_cast<ui::KeyEvent*>(event));
+ else if (event->IsScrollEvent())
+ return EventTargeter::FindTargetForEvent(root, event);
+
+ NOTREACHED() << "ViewTargeter does not yet support this event type.";
+ return NULL;
+}
+
+ui::EventTarget* ViewTargeter::FindNextBestTarget(
+ ui::EventTarget* previous_target,
+ ui::Event* event) {
+ return previous_target->GetParentTarget();
+}
+
+bool ViewTargeter::SubtreeCanAcceptEvent(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ views::View* view = static_cast<views::View*>(target);
+ if (!view->visible())
+ return false;
+
+ if (!view->CanProcessEventsWithinSubtree())
+ return false;
+
+ return true;
+}
+
+bool ViewTargeter::EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ views::View* view = static_cast<views::View*>(target);
+ gfx::Rect rect(event.location(), gfx::Size(1, 1));
+ gfx::RectF rect_in_view_coords_f(rect);
+ if (view->parent())
+ View::ConvertRectToTarget(view->parent(), view, &rect_in_view_coords_f);
+ gfx::Rect rect_in_view_coords = gfx::ToEnclosingRect(rect_in_view_coords_f);
+
+ // TODO(tdanderson): Don't call into HitTestRect() directly here.
+ // See crbug.com/370579.
+ return view->HitTestRect(rect_in_view_coords);
+}
+
+View* ViewTargeter::FindTargetForKeyEvent(View* view, const ui::KeyEvent& key) {
+ if (view->GetFocusManager())
+ return view->GetFocusManager()->GetFocusedView();
+ return NULL;
+}
+
+} // namespace aura
diff --git a/chromium/ui/views/view_targeter.h b/chromium/ui/views/view_targeter.h
new file mode 100644
index 00000000000..8273a8aabc4
--- /dev/null
+++ b/chromium/ui/views/view_targeter.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_VIEW_TARGETER_H_
+#define UI_VIEWS_VIEW_TARGETER_H_
+
+#include "ui/events/event_targeter.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class View;
+
+// Contains the logic used to determine the View to which an
+// event should be dispatched. A ViewTargeter (or one of its
+// derived classes) is installed on a View to specify the
+// targeting behaviour to be used for the subtree rooted at
+// that View.
+class VIEWS_EXPORT ViewTargeter : public ui::EventTargeter {
+ public:
+ ViewTargeter();
+ virtual ~ViewTargeter();
+
+ protected:
+ // Returns the location of |event| represented as a rect. If |event| is
+ // a gesture event, its bounding box is returned. Otherwise, a 1x1 rect
+ // having its origin at the location of |event| is returned.
+ gfx::RectF BoundsForEvent(const ui::LocatedEvent& event) const;
+
+ // ui::EventTargeter:
+ virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) OVERRIDE;
+ virtual ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
+ ui::Event* event) OVERRIDE;
+ virtual bool SubtreeCanAcceptEvent(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+ virtual bool EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+
+ private:
+ View* FindTargetForKeyEvent(View* view, const ui::KeyEvent& key);
+
+ DISALLOW_COPY_AND_ASSIGN(ViewTargeter);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_VIEW_TARGETER_H_
diff --git a/chromium/ui/views/view_targeter_unittest.cc b/chromium/ui/views/view_targeter_unittest.cc
new file mode 100644
index 00000000000..54a28b13a32
--- /dev/null
+++ b/chromium/ui/views/view_targeter_unittest.cc
@@ -0,0 +1,386 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/view_targeter.h"
+
+#include "ui/events/event_targeter.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/path.h"
+#include "ui/views/masked_view_targeter.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/root_view.h"
+
+namespace views {
+
+// A class used to define a triangular-shaped hit test mask on a View.
+class TestMaskedViewTargeter : public MaskedViewTargeter {
+ public:
+ explicit TestMaskedViewTargeter(View* masked_view)
+ : MaskedViewTargeter(masked_view) {}
+ virtual ~TestMaskedViewTargeter() {}
+
+ private:
+ virtual bool GetHitTestMask(const View* view,
+ gfx::Path* mask) const OVERRIDE {
+ SkScalar w = SkIntToScalar(view->width());
+ SkScalar h = SkIntToScalar(view->height());
+
+ // Create a triangular mask within the bounds of |view|.
+ mask->moveTo(w / 2, 0);
+ mask->lineTo(w, h);
+ mask->lineTo(0, h);
+ mask->close();
+
+ return true;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestMaskedViewTargeter);
+};
+
+// A derived class of View used for testing purposes.
+class TestingView : public View {
+ public:
+ TestingView() : can_process_events_within_subtree_(true) {}
+ virtual ~TestingView() {}
+
+ // Reset all test state.
+ void Reset() { can_process_events_within_subtree_ = true; }
+
+ void set_can_process_events_within_subtree(bool can_process) {
+ can_process_events_within_subtree_ = can_process;
+ }
+
+ // View:
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE {
+ return can_process_events_within_subtree_;
+ }
+
+ private:
+ // Value to return from CanProcessEventsWithinSubtree().
+ bool can_process_events_within_subtree_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingView);
+};
+
+namespace test {
+
+typedef ViewsTestBase ViewTargeterTest;
+
+// Verifies that the the functions ViewTargeter::FindTargetForEvent()
+// and ViewTargeter::FindNextBestTarget() are implemented correctly
+// for key events.
+TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(init_params);
+
+ View* content = new View;
+ View* child = new View;
+ View* grandchild = new View;
+
+ widget.SetContentsView(content);
+ content->AddChildView(child);
+ child->AddChildView(grandchild);
+
+ grandchild->SetFocusable(true);
+ grandchild->RequestFocus();
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
+ ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
+
+ // The focused view should be the initial target of the event.
+ ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
+ &key_event);
+ EXPECT_EQ(grandchild, static_cast<View*>(current_target));
+
+ // Verify that FindNextBestTarget() will return the parent view of the
+ // argument (and NULL if the argument has no parent view).
+ current_target = targeter->FindNextBestTarget(grandchild, &key_event);
+ EXPECT_EQ(child, static_cast<View*>(current_target));
+ current_target = targeter->FindNextBestTarget(child, &key_event);
+ EXPECT_EQ(content, static_cast<View*>(current_target));
+ current_target = targeter->FindNextBestTarget(content, &key_event);
+ EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
+ current_target = targeter->FindNextBestTarget(widget.GetRootView(),
+ &key_event);
+ EXPECT_EQ(NULL, static_cast<View*>(current_target));
+}
+
+// Verifies that the the functions ViewTargeter::FindTargetForEvent()
+// and ViewTargeter::FindNextBestTarget() are implemented correctly
+// for scroll events.
+TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget.Init(init_params);
+
+ // The coordinates used for SetBounds() are in the parent coordinate space.
+ View* content = new View;
+ content->SetBounds(0, 0, 100, 100);
+ View* child = new View;
+ child->SetBounds(50, 50, 20, 20);
+ View* grandchild = new View;
+ grandchild->SetBounds(0, 0, 5, 5);
+
+ widget.SetContentsView(content);
+ content->AddChildView(child);
+ child->AddChildView(grandchild);
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
+ // The event falls within the bounds of |child| and |content| but not
+ // |grandchild|, so |child| should be the initial target for the event.
+ ui::ScrollEvent scroll(ui::ET_SCROLL,
+ gfx::Point(60, 60),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 3,
+ 0, 3,
+ 2);
+ ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
+ &scroll);
+ EXPECT_EQ(child, static_cast<View*>(current_target));
+
+ // Verify that FindNextBestTarget() will return the parent view of the
+ // argument (and NULL if the argument has no parent view).
+ current_target = targeter->FindNextBestTarget(child, &scroll);
+ EXPECT_EQ(content, static_cast<View*>(current_target));
+ current_target = targeter->FindNextBestTarget(content, &scroll);
+ EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
+ current_target = targeter->FindNextBestTarget(widget.GetRootView(),
+ &scroll);
+ EXPECT_EQ(NULL, static_cast<View*>(current_target));
+
+ // The event falls outside of the original specified bounds of |content|,
+ // |child|, and |grandchild|. But since |content| is the contents view,
+ // and contents views are resized to fill the entire area of the root
+ // view, the event's initial target should still be |content|.
+ scroll = ui::ScrollEvent(ui::ET_SCROLL,
+ gfx::Point(150, 150),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 3,
+ 0, 3,
+ 2);
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(content, static_cast<View*>(current_target));
+}
+
+// Tests the basic functionality of the method
+// ViewTargeter::SubtreeShouldBeExploredForEvent().
+TEST_F(ViewTargeterTest, SubtreeShouldBeExploredForEvent) {
+ Widget 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);
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
+ // The coordinates used for SetBounds() are in the parent coordinate space.
+ View v1, v2, v3;
+ v1.SetBounds(0, 0, 300, 300);
+ v2.SetBounds(100, 100, 100, 100);
+ v3.SetBounds(0, 0, 10, 10);
+ v3.SetVisible(false);
+ root_view->AddChildView(&v1);
+ v1.AddChildView(&v2);
+ v2.AddChildView(&v3);
+
+ // Note that the coordinates used below are in |v1|'s coordinate space,
+ // and that SubtreeShouldBeExploredForEvent() expects the event location
+ // to be in the coordinate space of the target's parent. |v1| and
+ // its parent share a common coordinate space.
+
+ // Event located within |v1| only.
+ gfx::Point point(10, 10);
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, point, point,
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
+ v1.ConvertEventToTarget(&v2, &event);
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
+
+ // Event located within |v1| and |v2| only.
+ event.set_location(gfx::Point(150, 150));
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
+ v1.ConvertEventToTarget(&v2, &event);
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
+
+ // Event located within |v1|, |v2|, and |v3|. Note that |v3| is not
+ // visible, so it cannot handle the event.
+ event.set_location(gfx::Point(105, 105));
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
+ v1.ConvertEventToTarget(&v2, &event);
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
+
+ // Event located outside the bounds of all views.
+ event.set_location(gfx::Point(400, 400));
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
+ v1.ConvertEventToTarget(&v2, &event);
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
+
+ // TODO(tdanderson): Move the hit-testing unit tests out of view_unittest
+ // and into here. See crbug.com/355425.
+}
+
+// Tests that FindTargetForEvent() returns the correct target when some
+// views in the view tree return false when CanProcessEventsWithinSubtree()
+// is called on them.
+TEST_F(ViewTargeterTest, CanProcessEventsWithinSubtree) {
+ Widget 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);
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
+ // The coordinates used for SetBounds() are in the parent coordinate space.
+ TestingView v1, v2, v3;
+ v1.SetBounds(0, 0, 300, 300);
+ v2.SetBounds(100, 100, 100, 100);
+ v3.SetBounds(0, 0, 10, 10);
+ root_view->AddChildView(&v1);
+ v1.AddChildView(&v2);
+ v2.AddChildView(&v3);
+
+ // Note that the coordinates used below are in the coordinate space of
+ // the root view.
+
+ // Define |scroll| to be (105, 105) (in the coordinate space of the root
+ // view). This is located within all of |v1|, |v2|, and |v3|.
+ gfx::Point scroll_point(105, 105);
+ ui::ScrollEvent scroll(
+ ui::ET_SCROLL, scroll_point, ui::EventTimeForNow(), 0, 0, 3, 0, 3, 2);
+
+ // If CanProcessEventsWithinSubtree() returns true for each view,
+ // |scroll| should be targeted at the deepest view in the hierarchy,
+ // which is |v3|.
+ ui::EventTarget* current_target =
+ targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&v3, current_target);
+
+ // If CanProcessEventsWithinSubtree() returns |false| when called
+ // on |v3|, then |v3| cannot be the target of |scroll| (this should
+ // instead be |v2|). Note we need to reset the location of |scroll|
+ // because it may have been mutated by the previous call to
+ // FindTargetForEvent().
+ scroll.set_location(scroll_point);
+ v3.set_can_process_events_within_subtree(false);
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&v2, current_target);
+
+ // If CanProcessEventsWithinSubtree() returns |false| when called
+ // on |v2|, then neither |v2| nor |v3| can be the target of |scroll|
+ // (this should instead be |v1|).
+ scroll.set_location(scroll_point);
+ v3.Reset();
+ v2.set_can_process_events_within_subtree(false);
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&v1, current_target);
+
+ // If CanProcessEventsWithinSubtree() returns |false| when called
+ // on |v1|, then none of |v1|, |v2| or |v3| can be the target of |scroll|
+ // (this should instead be the root view itself).
+ scroll.set_location(scroll_point);
+ v2.Reset();
+ v1.set_can_process_events_within_subtree(false);
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(root_view, current_target);
+
+ // TODO(tdanderson): We should also test that targeting works correctly
+ // with gestures. See crbug.com/375822.
+}
+
+// Tests that FindTargetForEvent() returns the correct target when some
+// views in the view tree have a MaskedViewTargeter installed, i.e.,
+// they have a custom-shaped hit test mask.
+TEST_F(ViewTargeterTest, MaskedViewTargeter) {
+ Widget 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);
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
+ // The coordinates used for SetBounds() are in the parent coordinate space.
+ View masked_view, unmasked_view, masked_child;
+ masked_view.SetBounds(0, 0, 200, 200);
+ unmasked_view.SetBounds(300, 0, 300, 300);
+ masked_child.SetBounds(0, 0, 100, 100);
+ root_view->AddChildView(&masked_view);
+ root_view->AddChildView(&unmasked_view);
+ unmasked_view.AddChildView(&masked_child);
+
+ // Install event targeters of type TestMaskedViewTargeter on the two masked
+ // views to define their hit test masks.
+ ui::EventTargeter* masked_targeter = new TestMaskedViewTargeter(&masked_view);
+ masked_view.SetEventTargeter(make_scoped_ptr(masked_targeter));
+ masked_targeter = new TestMaskedViewTargeter(&masked_child);
+ masked_child.SetEventTargeter(make_scoped_ptr(masked_targeter));
+
+ // Note that the coordinates used below are in the coordinate space of
+ // the root view.
+
+ // Event located within the hit test mask of |masked_view|.
+ ui::ScrollEvent scroll(ui::ET_SCROLL,
+ gfx::Point(100, 190),
+ ui::EventTimeForNow(),
+ 0,
+ 0,
+ 3,
+ 0,
+ 3,
+ 2);
+ ui::EventTarget* current_target =
+ targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&masked_view, static_cast<View*>(current_target));
+
+ // Event located outside the hit test mask of |masked_view|.
+ scroll.set_location(gfx::Point(10, 10));
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(root_view, static_cast<View*>(current_target));
+
+ // Event located within the hit test mask of |masked_child|.
+ scroll.set_location(gfx::Point(350, 3));
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&masked_child, static_cast<View*>(current_target));
+
+ // Event located within the hit test mask of |masked_child|.
+ scroll.set_location(gfx::Point(300, 12));
+ current_target = targeter->FindTargetForEvent(root_view, &scroll);
+ EXPECT_EQ(&unmasked_view, static_cast<View*>(current_target));
+
+ // TODO(tdanderson): We should also test that targeting of masked views
+ // works correctly with gestures. See crbug.com/375822.
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index 77601b20eef..a8639bcdd0d 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -9,14 +9,15 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_strings.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/path.h"
@@ -25,7 +26,6 @@
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
@@ -35,15 +35,7 @@
#include "ui/views/window/dialog_client_view.h"
#include "ui/views/window/dialog_delegate.h"
-#if defined(OS_WIN)
-#include "ui/views/test/test_views_delegate.h"
-#endif
-#if defined(USE_AURA)
-#include "ui/aura/root_window.h"
-#include "ui/events/gestures/gesture_recognizer.h"
-#endif
-
-using ::testing::_;
+using base::ASCIIToUTF16;
namespace {
@@ -205,7 +197,11 @@ typedef ViewsTestBase ViewTest;
// A derived class for testing purpose.
class TestView : public View {
public:
- TestView() : View(), delete_on_pressed_(false), in_touch_sequence_(false) {}
+ TestView()
+ : View(),
+ delete_on_pressed_(false),
+ native_theme_(NULL),
+ can_process_events_within_subtree_(true) {}
virtual ~TestView() {}
// Reset all test state
@@ -215,12 +211,11 @@ class TestView : public View {
location_.SetPoint(0, 0);
received_mouse_enter_ = false;
received_mouse_exit_ = false;
- last_touch_event_type_ = 0;
- last_touch_event_was_handled_ = false;
last_gesture_event_type_ = 0;
last_gesture_event_was_handled_ = false;
last_clip_.setEmpty();
accelerator_count_map_.clear();
+ can_process_events_within_subtree_ = true;
}
// Exposed as public for testing.
@@ -232,6 +227,16 @@ class TestView : public View {
views::View::Blur();
}
+ bool focusable() const { return View::focusable(); }
+
+ void set_can_process_events_within_subtree(bool can_process) {
+ can_process_events_within_subtree_ = can_process;
+ }
+
+ virtual bool CanProcessEventsWithinSubtree() const OVERRIDE {
+ return can_process_events_within_subtree_;
+ }
+
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
@@ -239,14 +244,16 @@ class TestView : public View {
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
// Ignores GestureEvent by default.
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void Paint(gfx::Canvas* canvas, const CullSet& cull_set) OVERRIDE;
virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* native_theme)
+ OVERRIDE;
+
// OnBoundsChanged.
bool did_change_bounds_;
gfx::Rect new_bounds_;
@@ -265,26 +272,17 @@ class TestView : public View {
int last_gesture_event_type_;
bool last_gesture_event_was_handled_;
- // TouchEvent.
- int last_touch_event_type_;
- bool last_touch_event_was_handled_;
- bool in_touch_sequence_;
-
// Painting.
SkRect last_clip_;
// Accelerators.
std::map<ui::Accelerator, int> accelerator_count_map_;
-};
-// A view subclass that ignores all touch events for testing purposes.
-class TestViewIgnoreTouch : public TestView {
- public:
- TestViewIgnoreTouch() : TestView() {}
- virtual ~TestViewIgnoreTouch() {}
+ // Native theme.
+ const ui::NativeTheme* native_theme_;
- private:
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ // Value to return from CanProcessEventsWithinSubtree().
+ bool can_process_events_within_subtree_;
};
// A view subclass that consumes all Gesture events for testing purposes.
@@ -412,7 +410,7 @@ TEST_F(ViewTest, MouseEvent) {
gfx::Point p1(110, 120);
ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(pressed);
EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED);
EXPECT_EQ(v2->location_.x(), 10);
@@ -425,7 +423,7 @@ TEST_F(ViewTest, MouseEvent) {
v2->Reset();
gfx::Point p2(50, 40);
ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, p2, p2,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
root->OnMouseDragged(dragged);
EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED);
EXPECT_EQ(v2->location_.x(), -50);
@@ -436,7 +434,8 @@ TEST_F(ViewTest, MouseEvent) {
// Releasted event out of bounds. Should still go to v2
v1->Reset();
v2->Reset();
- ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0,
+ 0);
root->OnMouseDragged(released);
EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED);
EXPECT_EQ(v2->location_.x(), -100);
@@ -471,7 +470,7 @@ TEST_F(ViewTest, DeleteOnPressed) {
v2->delete_on_pressed_ = true;
gfx::Point point(110, 120);
ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(pressed);
EXPECT_EQ(0, v1->child_count());
@@ -479,129 +478,8 @@ TEST_F(ViewTest, DeleteOnPressed) {
}
////////////////////////////////////////////////////////////////////////////////
-// TouchEvent
+// GestureEvent
////////////////////////////////////////////////////////////////////////////////
-void TestView::OnTouchEvent(ui::TouchEvent* event) {
- last_touch_event_type_ = event->type();
- location_.SetPoint(event->x(), event->y());
- if (!in_touch_sequence_) {
- if (event->type() == ui::ET_TOUCH_PRESSED) {
- in_touch_sequence_ = true;
- event->StopPropagation();
- return;
- }
- } else {
- if (event->type() == ui::ET_TOUCH_RELEASED) {
- in_touch_sequence_ = false;
- event->SetHandled();
- return;
- }
- event->StopPropagation();
- return;
- }
-
- if (last_touch_event_was_handled_)
- event->StopPropagation();
-}
-
-void TestViewIgnoreTouch::OnTouchEvent(ui::TouchEvent* event) {
-}
-
-TEST_F(ViewTest, TouchEvent) {
- TestView* v1 = new TestView();
- v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
-
- TestView* v2 = new TestView();
- v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
-
- TestView* v3 = new TestViewIgnoreTouch();
- v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
-
- scoped_ptr<Widget> widget(new Widget());
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget->Init(params);
- internal::RootView* root =
- static_cast<internal::RootView*>(widget->GetRootView());
-
- root->AddChildView(v1);
- v1->AddChildView(v2);
- v2->AddChildView(v3);
-
- // |v3| completely obscures |v2|, but all the touch events on |v3| should
- // reach |v2| because |v3| doesn't process any touch events.
-
- // Make sure if none of the views handle the touch event, the gesture manager
- // does.
- v1->Reset();
- v2->Reset();
-
- ui::TouchEvent unhandled(ui::ET_TOUCH_MOVED,
- gfx::Point(400, 400),
- 0, /* no flags */
- 0, /* first finger touch */
- base::TimeDelta(),
- 1.0, 0.0, 1.0, 0.0);
- root->DispatchTouchEvent(&unhandled);
-
- EXPECT_EQ(v1->last_touch_event_type_, 0);
- EXPECT_EQ(v2->last_touch_event_type_, 0);
-
- // Test press, drag, release touch sequence.
- v1->Reset();
- v2->Reset();
-
- ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
- gfx::Point(110, 120),
- 0, /* no flags */
- 0, /* first finger touch */
- base::TimeDelta(),
- 1.0, 0.0, 1.0, 0.0);
- v2->last_touch_event_was_handled_ = true;
- root->DispatchTouchEvent(&pressed);
-
- EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_PRESSED);
- EXPECT_EQ(v2->location_.x(), 10);
- EXPECT_EQ(v2->location_.y(), 20);
- // Make sure v1 did not receive the event
- EXPECT_EQ(v1->last_touch_event_type_, 0);
-
- // Drag event out of bounds. Should still go to v2
- v1->Reset();
- v2->Reset();
- ui::TouchEvent dragged(ui::ET_TOUCH_MOVED,
- gfx::Point(50, 40),
- 0, /* no flags */
- 0, /* first finger touch */
- base::TimeDelta(),
- 1.0, 0.0, 1.0, 0.0);
-
- root->DispatchTouchEvent(&dragged);
- EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_MOVED);
- EXPECT_EQ(v2->location_.x(), -50);
- EXPECT_EQ(v2->location_.y(), -60);
- // Make sure v1 did not receive the event
- EXPECT_EQ(v1->last_touch_event_type_, 0);
-
- // Released event out of bounds. Should still go to v2
- v1->Reset();
- v2->Reset();
- ui::TouchEvent released(ui::ET_TOUCH_RELEASED, gfx::Point(),
- 0, /* no flags */
- 0, /* first finger */
- base::TimeDelta(),
- 1.0, 0.0, 1.0, 0.0);
- v2->last_touch_event_was_handled_ = true;
- root->DispatchTouchEvent(&released);
- EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_RELEASED);
- EXPECT_EQ(v2->location_.x(), -100);
- EXPECT_EQ(v2->location_.y(), -100);
- // Make sure v1 did not receive the event
- EXPECT_EQ(v1->last_touch_event_type_, 0);
-
- widget->CloseNow();
-}
void TestView::OnGestureEvent(ui::GestureEvent* event) {
}
@@ -624,6 +502,7 @@ TEST_F(ViewTest, GestureEvent) {
widget->Init(params);
internal::RootView* root =
static_cast<internal::RootView*>(widget->GetRootView());
+ ui::EventDispatchDetails details;
root->AddChildView(v1);
v1->AddChildView(v2);
@@ -640,14 +519,19 @@ TEST_F(ViewTest, GestureEvent) {
// Gesture on |v3|
GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0);
- root->DispatchGestureEvent(&g1);
+ details = root->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
EXPECT_EQ(gfx::Point(10, 10), v2->location_);
EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
// Simulate an up so that RootView is no longer targetting |v3|.
GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0);
- root->DispatchGestureEvent(&g1_up);
+ details = root->OnEventFromSource(&g1_up);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
v1->Reset();
v2->Reset();
@@ -655,7 +539,10 @@ TEST_F(ViewTest, GestureEvent) {
// Gesture on |v1|
GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0);
- root->DispatchGestureEvent(&g2);
+ details = root->OnEventFromSource(&g2);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
EXPECT_EQ(gfx::Point(80, 80), v1->location_);
EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
@@ -664,7 +551,10 @@ TEST_F(ViewTest, GestureEvent) {
// to |v1| as that is the view the touch was initially down on.
v1->last_gesture_event_type_ = ui::ET_UNKNOWN;
v3->last_gesture_event_type_ = ui::ET_UNKNOWN;
- root->DispatchGestureEvent(&g1);
+ details = root->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_);
EXPECT_EQ("110,110", v1->location_.ToString());
@@ -690,6 +580,7 @@ TEST_F(ViewTest, ScrollGestureEvent) {
widget->Init(params);
internal::RootView* root =
static_cast<internal::RootView*>(widget->GetRootView());
+ ui::EventDispatchDetails details;
root->AddChildView(v1);
v1->AddChildView(v2);
@@ -706,7 +597,10 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// Gesture on |v3|
GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0);
- root->DispatchGestureEvent(&g1);
+ details = root->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
EXPECT_EQ(gfx::Point(10, 10), v2->location_);
EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
@@ -717,7 +611,10 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// since it does not process scroll-gesture events, these events should reach
// |v1|.
GestureEventForTest gscroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 115, 115, 0);
- root->DispatchGestureEvent(&gscroll_begin);
+ details = root->OnEventFromSource(&gscroll_begin);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
EXPECT_EQ(ui::ET_GESTURE_SCROLL_BEGIN, v1->last_gesture_event_type_);
v1->Reset();
@@ -726,19 +623,28 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// default gesture handler, and not |v1| (even though it is the view under the
// point, and is the scroll event handler).
GestureEventForTest second_tap(ui::ET_GESTURE_TAP, 70, 70, 0);
- root->DispatchGestureEvent(&second_tap);
+ details = root->OnEventFromSource(&second_tap);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
v2->Reset();
GestureEventForTest gscroll_end(ui::ET_GESTURE_SCROLL_END, 50, 50, 0);
- root->DispatchGestureEvent(&gscroll_end);
+ details = root->OnEventFromSource(&gscroll_end);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_SCROLL_END, v1->last_gesture_event_type_);
v1->Reset();
// Simulate an up so that RootView is no longer targetting |v3|.
GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0);
- root->DispatchGestureEvent(&g1_up);
+ details = root->OnEventFromSource(&g1_up);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_END, v2->last_gesture_event_type_);
v1->Reset();
@@ -747,7 +653,10 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// Gesture on |v1|
GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0);
- root->DispatchGestureEvent(&g2);
+ details = root->OnEventFromSource(&g2);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
EXPECT_EQ(gfx::Point(80, 80), v1->location_);
EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
@@ -756,7 +665,10 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// to |v1| as that is the view the touch was initially down on.
v1->last_gesture_event_type_ = ui::ET_UNKNOWN;
v3->last_gesture_event_type_ = ui::ET_UNKNOWN;
- root->DispatchGestureEvent(&g1);
+ details = root->OnEventFromSource(&g1);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_FALSE(details.target_destroyed);
+
EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_);
EXPECT_EQ("110,110", v1->location_.ToString());
@@ -768,7 +680,7 @@ TEST_F(ViewTest, ScrollGestureEvent) {
// Painting
////////////////////////////////////////////////////////////////////////////////
-void TestView::Paint(gfx::Canvas* canvas) {
+void TestView::Paint(gfx::Canvas* canvas, const CullSet& cull_set) {
canvas->sk_canvas()->getClipBounds(&last_clip_);
}
@@ -784,66 +696,6 @@ void CheckRect(const SkRect& check_rect, const SkRect& target_rect) {
EXPECT_EQ(target_rect.fBottom, check_rect.fBottom);
}
-/* This test is disabled because it is flakey on some systems.
-TEST_F(ViewTest, DISABLED_Painting) {
- // Determine if InvalidateRect generates an empty paint rectangle.
- EmptyWindow paint_window(CRect(50, 50, 650, 650));
- paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL,
- RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
- bool empty_paint = paint_window.empty_paint();
-
- NativeWidgetWin window;
- window.set_delete_on_destroy(false);
- window.set_window_style(WS_OVERLAPPEDWINDOW);
- window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL);
- View* root = window.GetRootView();
-
- TestView* v1 = new TestView();
- v1->SetBoundsRect(gfx::Rect(0, 0, 650, 650));
- root->AddChildView(v1);
-
- TestView* v2 = new TestView();
- v2->SetBoundsRect(gfx::Rect(10, 10, 80, 80));
- v1->AddChildView(v2);
-
- TestView* v3 = new TestView();
- v3->SetBoundsRect(gfx::Rect(10, 10, 60, 60));
- v2->AddChildView(v3);
-
- TestView* v4 = new TestView();
- v4->SetBoundsRect(gfx::Rect(10, 200, 100, 100));
- v1->AddChildView(v4);
-
- // Make sure to paint current rects
- PaintRootView(root, empty_paint);
-
-
- v1->Reset();
- v2->Reset();
- v3->Reset();
- v4->Reset();
- v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10));
- PaintRootView(root, empty_paint);
-
- SkRect tmp_rect;
-
- tmp_rect.iset(10, 10, 20, 20);
- CheckRect(v3->last_clip_, tmp_rect);
-
- tmp_rect.iset(20, 20, 30, 30);
- CheckRect(v2->last_clip_, tmp_rect);
-
- tmp_rect.iset(30, 30, 40, 40);
- CheckRect(v1->last_clip_, tmp_rect);
-
- // Make sure v4 was not painted
- tmp_rect.setEmpty();
- CheckRect(v4->last_clip_, tmp_rect);
-
- window.DestroyWindow();
-}
-*/
-
TEST_F(ViewTest, RemoveNotification) {
ViewStorage* vs = ViewStorage::GetInstance();
Widget* widget = new Widget;
@@ -1370,6 +1222,163 @@ TEST_F(ViewTest, GetEventHandlerForRect) {
widget->CloseNow();
}
+// Tests that GetEventHandlerForRect() and GetTooltipHandlerForPoint() behave
+// as expected when different views in the view hierarchy return false
+// when CanProcessEventsWithinSubtree() is called.
+TEST_F(ViewTest, CanProcessEventsWithinSubtree) {
+ Widget* widget = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ widget->Init(params);
+ View* root_view = widget->GetRootView();
+ root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
+
+ // Have this hierarchy of views (the coords here are in the coordinate
+ // space of the root view):
+ // v (0, 0, 100, 100)
+ // - v_child (0, 0, 20, 30)
+ // - v_grandchild (5, 5, 5, 15)
+
+ TestView* v = new TestView;
+ v->SetBounds(0, 0, 100, 100);
+ root_view->AddChildView(v);
+ v->set_notify_enter_exit_on_child(true);
+
+ TestView* v_child = new TestView;
+ v_child->SetBounds(0, 0, 20, 30);
+ v->AddChildView(v_child);
+
+ TestView* v_grandchild = new TestView;
+ v_grandchild->SetBounds(5, 5, 5, 15);
+ v_child->AddChildView(v_grandchild);
+
+ v->Reset();
+ v_child->Reset();
+ v_grandchild->Reset();
+
+ // Define rects and points within the views in the hierarchy.
+ gfx::Rect rect_in_v_grandchild(7, 7, 3, 3);
+ gfx::Point point_in_v_grandchild(rect_in_v_grandchild.origin());
+ gfx::Rect rect_in_v_child(12, 3, 5, 5);
+ gfx::Point point_in_v_child(rect_in_v_child.origin());
+ gfx::Rect rect_in_v(50, 50, 25, 30);
+ gfx::Point point_in_v(rect_in_v.origin());
+
+ // When all three views return true when CanProcessEventsWithinSubtree()
+ // is called, targeting should behave as expected.
+
+ View* result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
+ EXPECT_EQ(v_grandchild, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
+ EXPECT_EQ(v_grandchild, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+
+ // When |v_grandchild| returns false when CanProcessEventsWithinSubtree()
+ // is called, then |v_grandchild| cannot be returned as a target.
+
+ v_grandchild->set_can_process_events_within_subtree(false);
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
+ EXPECT_EQ(v_child, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
+ EXPECT_EQ(v, result_view);
+
+ // When |v_grandchild| returns false when CanProcessEventsWithinSubtree()
+ // is called, then NULL should be returned as a target if we call
+ // GetTooltipHandlerForPoint() with |v_grandchild| as the root of the
+ // views tree. Note that the location must be in the coordinate space
+ // of the root view (|v_grandchild| in this case), so use (1, 1).
+
+ result_view = v_grandchild;
+ result_view = v_grandchild->GetTooltipHandlerForPoint(gfx::Point(1, 1));
+ EXPECT_EQ(NULL, result_view);
+ result_view = NULL;
+
+ // When |v_child| returns false when CanProcessEventsWithinSubtree()
+ // is called, then neither |v_child| nor |v_grandchild| can be returned
+ // as a target (|v| should be returned as the target for each case).
+
+ v_grandchild->Reset();
+ v_child->set_can_process_events_within_subtree(false);
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
+ EXPECT_EQ(v, result_view);
+ result_view = NULL;
+
+ // When |v| returns false when CanProcessEventsWithinSubtree()
+ // is called, then none of |v|, |v_child|, and |v_grandchild| can be returned
+ // as a target (|root_view| should be returned as the target for each case).
+
+ v_child->Reset();
+ v->set_can_process_events_within_subtree(false);
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
+ EXPECT_EQ(root_view, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
+ EXPECT_EQ(root_view, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
+ EXPECT_EQ(root_view, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
+ EXPECT_EQ(root_view, result_view);
+ result_view = NULL;
+
+ result_view = root_view->GetEventHandlerForRect(rect_in_v);
+ EXPECT_EQ(root_view, result_view);
+ result_view = NULL;
+ result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
+ EXPECT_EQ(root_view, result_view);
+}
+
TEST_F(ViewTest, NotifyEnterExitOnChild) {
Widget* widget = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
@@ -1425,7 +1434,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Move the mouse in v111.
gfx::Point p1(6, 6);
- ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, 0);
+ ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, 0, 0);
root_view->OnMouseMoved(move1);
EXPECT_TRUE(v111->received_mouse_enter_);
EXPECT_FALSE(v11->last_mouse_event_type_);
@@ -1436,7 +1445,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Now, move into v121.
gfx::Point p2(65, 21);
- ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, 0);
+ ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, 0, 0);
root_view->OnMouseMoved(move2);
EXPECT_TRUE(v111->received_mouse_exit_);
EXPECT_TRUE(v121->received_mouse_enter_);
@@ -1447,7 +1456,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Now, move into v11.
gfx::Point p3(1, 1);
- ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, 0);
+ ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, 0, 0);
root_view->OnMouseMoved(move3);
EXPECT_TRUE(v121->received_mouse_exit_);
EXPECT_TRUE(v11->received_mouse_enter_);
@@ -1458,7 +1467,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Move to v21.
gfx::Point p4(121, 15);
- ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, 0);
+ ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, 0, 0);
root_view->OnMouseMoved(move4);
EXPECT_TRUE(v21->received_mouse_enter_);
EXPECT_FALSE(v2->last_mouse_event_type_);
@@ -1471,7 +1480,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Move to v1.
gfx::Point p5(21, 0);
- ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, 0);
+ ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, 0, 0);
root_view->OnMouseMoved(move5);
EXPECT_TRUE(v21->received_mouse_exit_);
EXPECT_TRUE(v1->received_mouse_enter_);
@@ -1481,7 +1490,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// Now, move into v11.
gfx::Point p6(15, 15);
- ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, 0);
+ ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, 0, 0);
root_view->OnMouseMoved(mouse6);
EXPECT_TRUE(v11->received_mouse_enter_);
EXPECT_FALSE(v1->last_mouse_event_type_);
@@ -1493,7 +1502,7 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
// and the mouse remains inside |v1| the whole time, it receives another ENTER
// when the mouse leaves v11.
gfx::Point p7(21, 0);
- ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, 0);
+ ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, 0, 0);
root_view->OnMouseMoved(mouse7);
EXPECT_TRUE(v11->received_mouse_exit_);
EXPECT_FALSE(v1->received_mouse_enter_);
@@ -1502,10 +1511,10 @@ TEST_F(ViewTest, NotifyEnterExitOnChild) {
}
TEST_F(ViewTest, Textfield) {
- const string16 kText = ASCIIToUTF16("Reality is that which, when you stop "
- "believing it, doesn't go away.");
- const string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!");
- const string16 kEmptyString;
+ const base::string16 kText = ASCIIToUTF16(
+ "Reality is that which, when you stop believing it, doesn't go away.");
+ const base::string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!");
+ const base::string16 kEmptyString;
Widget* widget = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
@@ -1521,7 +1530,7 @@ TEST_F(ViewTest, Textfield) {
EXPECT_EQ(kText, textfield->text());
textfield->AppendText(kExtraText);
EXPECT_EQ(kText + kExtraText, textfield->text());
- textfield->SetText(string16());
+ textfield->SetText(base::string16());
EXPECT_EQ(kEmptyString, textfield->text());
// Test selection related methods.
@@ -1537,9 +1546,10 @@ TEST_F(ViewTest, Textfield) {
// Tests that the Textfield view respond appropiately to cut/copy/paste.
TEST_F(ViewTest, TextfieldCutCopyPaste) {
- const string16 kNormalText = ASCIIToUTF16("Normal");
- const string16 kReadOnlyText = ASCIIToUTF16("Read only");
- const string16 kPasswordText = ASCIIToUTF16("Password! ** Secret stuff **");
+ const base::string16 kNormalText = ASCIIToUTF16("Normal");
+ const base::string16 kReadOnlyText = ASCIIToUTF16("Read only");
+ const base::string16 kPasswordText =
+ ASCIIToUTF16("Password! ** Secret stuff **");
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
@@ -1552,7 +1562,8 @@ TEST_F(ViewTest, TextfieldCutCopyPaste) {
Textfield* normal = new Textfield();
Textfield* read_only = new Textfield();
read_only->SetReadOnly(true);
- Textfield* password = new Textfield(Textfield::STYLE_OBSCURED);
+ Textfield* password = new Textfield();
+ password->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
root_view->AddChildView(normal);
root_view->AddChildView(read_only);
@@ -1568,7 +1579,7 @@ TEST_F(ViewTest, TextfieldCutCopyPaste) {
normal->SelectAll(false);
normal->ExecuteCommand(IDS_APP_CUT);
- string16 result;
+ base::string16 result;
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
EXPECT_EQ(kNormalText, result);
normal->SetText(kNormalText); // Let's revert to the original content.
@@ -1641,7 +1652,9 @@ bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) {
return true;
}
-#if defined(OS_WIN) && !defined(USE_AURA)
+// TODO: these tests were initially commented out when getting aura to
+// run. Figure out if still valuable and either nuke or fix.
+#if 0
TEST_F(ViewTest, ActivateAccelerator) {
// Register a keyboard accelerator before the view is added to a window.
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
@@ -1706,9 +1719,7 @@ TEST_F(ViewTest, ActivateAccelerator) {
widget->CloseNow();
}
-#endif
-#if defined(OS_WIN) && !defined(USE_AURA)
TEST_F(ViewTest, HiddenViewWithAccelerator) {
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
TestView* view = new TestView();
@@ -1736,9 +1747,7 @@ TEST_F(ViewTest, HiddenViewWithAccelerator) {
widget->CloseNow();
}
-#endif
-#if defined(OS_WIN) && !defined(USE_AURA)
TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) {
ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
TestView* view = new TestView();
@@ -1770,9 +1779,7 @@ TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) {
widget->CloseNow();
}
-#endif
-#if defined(OS_WIN) && !defined(USE_AURA)
////////////////////////////////////////////////////////////////////////////////
// Mouse-wheel message rerouting
////////////////////////////////////////////////////////////////////////////////
@@ -1849,20 +1856,10 @@ TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) {
WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
EXPECT_EQ(20, scroll_view->GetVisibleRect().y());
- // Then the text-field.
- ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
- WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
- EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
-
- // Ensure we don't scroll when the mouse is not over that window.
- ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
- WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50));
- EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
-
window1->CloseNow();
window2->CloseNow();
}
-#endif
+#endif // 0
////////////////////////////////////////////////////////////////////////////////
// Native view hierachy
@@ -2030,14 +2027,15 @@ TEST_F(ViewTest, TransformEvent) {
gfx::Point p1(110, 210);
ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(pressed);
EXPECT_EQ(0, v1->last_mouse_event_type_);
EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
EXPECT_EQ(190, v2->location_.x());
EXPECT_EQ(10, v2->location_.y());
- ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0,
+ 0);
root->OnMouseReleased(released);
// Now rotate |v2| inside |v1| clockwise.
@@ -2054,7 +2052,7 @@ TEST_F(ViewTest, TransformEvent) {
gfx::Point point2(110, 320);
ui::MouseEvent p2(ui::ET_MOUSE_PRESSED, point2, point2,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(p2);
EXPECT_EQ(0, v1->last_mouse_event_type_);
EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
@@ -2090,7 +2088,7 @@ TEST_F(ViewTest, TransformEvent) {
gfx::Point point(112, 110);
ui::MouseEvent p3(ui::ET_MOUSE_PRESSED, point, point,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(p3);
EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
@@ -2129,7 +2127,7 @@ TEST_F(ViewTest, TransformEvent) {
gfx::Point point3(124, 125);
ui::MouseEvent p4(ui::ET_MOUSE_PRESSED, point3, point3,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
root->OnMousePressed(p4);
EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
@@ -2299,6 +2297,39 @@ TEST_F(ViewTest, SetBoundsSameBoundsDoesntSchedulePaint) {
EXPECT_TRUE(view.scheduled_paint_rects_.empty());
}
+// Verifies AddChildView() and RemoveChildView() schedule appropriate paints.
+TEST_F(ViewTest, AddAndRemoveSchedulePaints) {
+ gfx::Rect viewport_bounds(0, 0, 100, 100);
+
+ // We have to put the View hierarchy into a Widget or no paints will be
+ // scheduled.
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = viewport_bounds;
+ widget->Init(params);
+ widget->GetRootView()->SetBoundsRect(viewport_bounds);
+
+ TestView* parent_view = new TestView;
+ widget->SetContentsView(parent_view);
+ parent_view->SetBoundsRect(viewport_bounds);
+ parent_view->scheduled_paint_rects_.clear();
+
+ View* child_view = new View;
+ child_view->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
+ parent_view->AddChildView(child_view);
+ ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size());
+ EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front());
+
+ parent_view->scheduled_paint_rects_.clear();
+ parent_view->RemoveChildView(child_view);
+ scoped_ptr<View> child_deleter(child_view);
+ ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size());
+ EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front());
+
+ widget->CloseNow();
+}
+
// Tests conversion methods with a transform.
TEST_F(ViewTest, ConversionsWithTransform) {
TestView top_view;
@@ -2992,8 +3023,6 @@ TEST_F(ViewTest, AddExistingChild) {
// Layers
////////////////////////////////////////////////////////////////////////////////
-#if defined(USE_AURA)
-
namespace {
// Test implementation of LayerAnimator.
@@ -3027,7 +3056,7 @@ void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) {
class ViewLayerTest : public ViewsTestBase {
public:
- ViewLayerTest() : widget_(NULL), old_use_acceleration_(false) {}
+ ViewLayerTest() : widget_(NULL) {}
virtual ~ViewLayerTest() {
}
@@ -3039,9 +3068,6 @@ class ViewLayerTest : public ViewsTestBase {
virtual void SetUp() OVERRIDE {
ViewTest::SetUp();
- old_use_acceleration_ = View::get_use_acceleration_when_possible();
- View::set_use_acceleration_when_possible(true);
-
widget_ = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.bounds = gfx::Rect(50, 50, 200, 200);
@@ -3051,7 +3077,6 @@ class ViewLayerTest : public ViewsTestBase {
}
virtual void TearDown() OVERRIDE {
- View::set_use_acceleration_when_possible(old_use_acceleration_);
widget_->CloseNow();
ViewsTestBase::TearDown();
}
@@ -3060,7 +3085,6 @@ class ViewLayerTest : public ViewsTestBase {
private:
Widget* widget_;
- bool old_use_acceleration_;
};
@@ -3506,17 +3530,6 @@ TEST_F(ViewLayerTest, AcquireLayer) {
c1.reset();
}
-// Verify that new layer scales content only if the old layer does.
-TEST_F(ViewLayerTest, RecreateLayerScaling) {
- scoped_ptr<View> v(new View());
- v->SetPaintToLayer(true);
- // Set to non default value.
- v->layer()->set_scale_content(false);
- scoped_ptr<ui::Layer> old_layer(v->RecreateLayer());
- ui::Layer* new_layer = v->layer();
- EXPECT_FALSE(new_layer->scale_content());
-}
-
// Verify the z-order of the layers as a result of calling RecreateLayer().
TEST_F(ViewLayerTest, RecreateLayerZOrder) {
scoped_ptr<View> v(new View());
@@ -3537,13 +3550,13 @@ TEST_F(ViewLayerTest, RecreateLayerZOrder) {
scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
- // Test the new layer order. |v1_old_layer| should be above the layers
+ // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|.
// for |v1| and |v2|.
const std::vector<ui::Layer*>& child_layers_post = v->layer()->children();
ASSERT_EQ(3u, child_layers_post.size());
EXPECT_EQ(v1->layer(), child_layers_post[0]);
- EXPECT_EQ(v2->layer(), child_layers_post[1]);
- EXPECT_EQ(v1_old_layer, child_layers_post[2]);
+ EXPECT_EQ(v1_old_layer, child_layers_post[1]);
+ EXPECT_EQ(v2->layer(), child_layers_post[2]);
}
// Verify the z-order of the layers as a result of calling RecreateLayer when
@@ -3569,15 +3582,393 @@ TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
- // Test the new layer order. |v1_old_layer| should be above the layers
- // for |v1| and |v2|.
+ // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|.
const std::vector<ui::Layer*>& child_layers_post = root_layer->children();
ASSERT_EQ(3u, child_layers_post.size());
EXPECT_EQ(v1->layer(), child_layers_post[0]);
- EXPECT_EQ(v2->layer(), child_layers_post[1]);
- EXPECT_EQ(v1_old_layer, child_layers_post[2]);
+ EXPECT_EQ(v1_old_layer, child_layers_post[1]);
+ EXPECT_EQ(v2->layer(), child_layers_post[2]);
+}
+
+// Verifies RecreateLayer() moves all Layers over, even those that don't have
+// a View.
+TEST_F(ViewLayerTest, RecreateLayerMovesNonViewChildren) {
+ View v;
+ v.SetPaintToLayer(true);
+ View child;
+ child.SetPaintToLayer(true);
+ v.AddChildView(&child);
+ ASSERT_TRUE(v.layer() != NULL);
+ ASSERT_EQ(1u, v.layer()->children().size());
+ EXPECT_EQ(v.layer()->children()[0], child.layer());
+
+ ui::Layer layer(ui::LAYER_NOT_DRAWN);
+ v.layer()->Add(&layer);
+ v.layer()->StackAtBottom(&layer);
+
+ scoped_ptr<ui::Layer> old_layer(v.RecreateLayer());
+
+ // All children should be moved from old layer to new layer.
+ ASSERT_TRUE(old_layer.get() != NULL);
+ EXPECT_TRUE(old_layer->children().empty());
+
+ // And new layer should have the two children.
+ ASSERT_TRUE(v.layer() != NULL);
+ ASSERT_EQ(2u, v.layer()->children().size());
+ EXPECT_EQ(v.layer()->children()[0], &layer);
+ EXPECT_EQ(v.layer()->children()[1], child.layer());
+}
+
+class BoundsTreeTestView : public View {
+ public:
+ BoundsTreeTestView() {}
+
+ virtual void PaintChildren(gfx::Canvas* canvas,
+ const CullSet& cull_set) OVERRIDE {
+ // Save out a copy of the cull_set before calling the base implementation.
+ last_cull_set_.clear();
+ if (cull_set.cull_set_) {
+ for (base::hash_set<intptr_t>::iterator it = cull_set.cull_set_->begin();
+ it != cull_set.cull_set_->end();
+ ++it) {
+ last_cull_set_.insert(reinterpret_cast<View*>(*it));
+ }
+ }
+ View::PaintChildren(canvas, cull_set);
+ }
+
+ std::set<View*> last_cull_set_;
+};
+
+TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) {
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ View* v1 = new View();
+ v1->SetBoundsRect(gfx::Rect(10, 15, 150, 151));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View();
+ v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50));
+ v1->AddChildView(v2);
+
+ // Schedule a full-view paint to get everyone's rectangles updated.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Now we have test_view - v1 - v2. Damage to only test_view should only
+ // return root_view and test_view.
+ test_view->SchedulePaintInRect(gfx::Rect(0, 0, 1, 1));
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(2U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+
+ // Damage to v1 only should only return root_view, test_view, and v1.
+ test_view->SchedulePaintInRect(gfx::Rect(11, 16, 1, 1));
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(3U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+
+ // A Damage rect inside v2 should get all 3 views back in the |last_cull_set_|
+ // on call to TestView::Paint(), along with the widget root view.
+ test_view->SchedulePaintInRect(gfx::Rect(31, 49, 1, 1));
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(4U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2));
}
-#endif // USE_AURA
+TEST_F(ViewLayerTest, BoundsTreeWithRTL) {
+ std::string locale = l10n_util::GetApplicationLocale(std::string());
+ base::i18n::SetICUDefaultLocale("ar");
+
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ // Add child views, which should be in RTL coordinate space of parent view.
+ View* v1 = new View;
+ v1->SetBoundsRect(gfx::Rect(10, 12, 25, 26));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v2->SetBoundsRect(gfx::Rect(5, 6, 7, 8));
+ v1->AddChildView(v2);
+
+ // Schedule a full-view paint to get everyone's rectangles updated.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Damage to the right side of the parent view should touch both child views.
+ gfx::Rect rtl_damage(test_view->bounds().width() - 16, 18, 1, 1);
+ test_view->SchedulePaintInRect(rtl_damage);
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(4U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2));
+
+ // Damage to the left side of the parent view should only touch the
+ // container views.
+ gfx::Rect ltr_damage(16, 18, 1, 1);
+ test_view->SchedulePaintInRect(ltr_damage);
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(2U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+TEST_F(ViewLayerTest, BoundsTreeSetBoundsChangesCullSet) {
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ View* v1 = new View;
+ v1->SetBoundsRect(gfx::Rect(5, 6, 100, 101));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50));
+ v1->AddChildView(v2);
+
+ // Schedule a full-view paint to get everyone's rectangles updated.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Move v1 to a new origin out of the way of our next query.
+ v1->SetBoundsRect(gfx::Rect(50, 60, 100, 101));
+ // The move will force a repaint.
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Schedule a paint with damage rect where v1 used to be.
+ test_view->SchedulePaintInRect(gfx::Rect(5, 6, 10, 11));
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Should only have picked up root_view and test_view.
+ EXPECT_EQ(2U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+}
+
+TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) {
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ View* v1 = new View;
+ v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4));
+ v1->AddChildView(v2);
+
+ // Schedule a full-view paint to get everyone's rectangles updated.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Set v1 to paint to its own layer, it should remove itself from the
+ // test_view heiarchy and no longer intersect with damage rects in that cull
+ // set.
+ v1->SetPaintToLayer(true);
+
+ // Schedule another full-view paint.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ // v1 and v2 should no longer be present in the test_view cull_set.
+ EXPECT_EQ(2U, test_view->last_cull_set_.size());
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v2));
+
+ // Now set v1 back to not painting to a layer.
+ v1->SetPaintToLayer(false);
+ // Schedule another full-view paint.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ // We should be back to the full cull set including v1 and v2.
+ EXPECT_EQ(4U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2));
+}
+
+TEST_F(ViewLayerTest, BoundsTreeRemoveChildRemovesBounds) {
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ View* v1 = new View;
+ v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4));
+ v1->AddChildView(v2);
+
+ // Schedule a full-view paint to get everyone's rectangles updated.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Now remove v1 from the root view.
+ test_view->RemoveChildView(v1);
+
+ // Schedule another full-view paint.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ // v1 and v2 should no longer be present in the test_view cull_set.
+ EXPECT_EQ(2U, test_view->last_cull_set_.size());
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v2));
+
+ // View v1 and v2 are no longer part of view hierarchy and therefore won't be
+ // deleted with that hierarchy.
+ delete v1;
+}
+
+TEST_F(ViewLayerTest, BoundsTreeMoveViewMovesBounds) {
+ BoundsTreeTestView* test_view = new BoundsTreeTestView;
+ widget()->SetContentsView(test_view);
+
+ // Build hierarchy v1 - v2 - v3.
+ View* v1 = new View;
+ v1->SetBoundsRect(gfx::Rect(20, 30, 150, 160));
+ test_view->AddChildView(v1);
+
+ View* v2 = new View;
+ v2->SetBoundsRect(gfx::Rect(5, 10, 40, 50));
+ v1->AddChildView(v2);
+
+ View* v3 = new View;
+ v3->SetBoundsRect(gfx::Rect(1, 2, 3, 4));
+ v2->AddChildView(v3);
+
+ // Schedule a full-view paint and ensure all views are present in the cull.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+ EXPECT_EQ(5U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v3));
+
+ // Build an unrelated view hierarchy and move v2 in to it.
+ scoped_ptr<Widget> test_widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(10, 10, 500, 500);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ test_widget->Init(params);
+ test_widget->Show();
+ BoundsTreeTestView* widget_view = new BoundsTreeTestView;
+ test_widget->SetContentsView(widget_view);
+ widget_view->AddChildView(v2);
+
+ // Now schedule full-view paints in both widgets.
+ test_view->SchedulePaintInRect(test_view->bounds());
+ widget_view->SchedulePaintInRect(widget_view->bounds());
+ GetRootLayer()->GetCompositor()->ScheduleDraw();
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
+
+ // Only v1 should be present in the first cull set.
+ EXPECT_EQ(3U, test_view->last_cull_set_.size());
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView()));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view));
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1));
+
+ // We should find v2 and v3 in the widget_view cull_set.
+ EXPECT_EQ(4U, widget_view->last_cull_set_.size());
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(test_widget->GetRootView()));
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(widget_view));
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(v2));
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(v3));
+}
+
+TEST_F(ViewTest, FocusableAssertions) {
+ // View subclasses may change insets based on whether they are focusable,
+ // which effects the preferred size. To avoid preferred size changing around
+ // these Views need to key off the last value set to SetFocusable(), not
+ // whether the View is focusable right now. For this reason it's important
+ // that focusable() return the last value passed to SetFocusable and not
+ // whether the View is focusable right now.
+ TestView view;
+ view.SetFocusable(true);
+ EXPECT_TRUE(view.focusable());
+ view.SetEnabled(false);
+ EXPECT_TRUE(view.focusable());
+ view.SetFocusable(false);
+ EXPECT_FALSE(view.focusable());
+}
+
+// Verifies when a view is deleted it is removed from ViewStorage.
+TEST_F(ViewTest, UpdateViewStorageOnDelete) {
+ ViewStorage* view_storage = ViewStorage::GetInstance();
+ const int storage_id = view_storage->CreateStorageID();
+ {
+ View view;
+ view_storage->StoreView(storage_id, &view);
+ }
+ EXPECT_TRUE(view_storage->RetrieveView(storage_id) == NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeTheme
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::OnNativeThemeChanged(const ui::NativeTheme* native_theme) {
+ native_theme_ = native_theme;
+}
+
+TEST_F(ViewTest, OnNativeThemeChanged) {
+ TestView* test_view = new TestView();
+ EXPECT_FALSE(test_view->native_theme_);
+ TestView* test_view_child = new TestView();
+ EXPECT_FALSE(test_view_child->native_theme_);
+
+ // Child view added before the widget hierarchy exists should get the
+ // new native theme notification.
+ test_view->AddChildView(test_view_child);
+
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ widget->GetRootView()->AddChildView(test_view);
+ EXPECT_TRUE(test_view->native_theme_);
+ EXPECT_EQ(widget->GetNativeTheme(), test_view->native_theme_);
+ EXPECT_TRUE(test_view_child->native_theme_);
+ EXPECT_EQ(widget->GetNativeTheme(), test_view_child->native_theme_);
+
+ // Child view added after the widget hierarchy exists should also get the
+ // notification.
+ TestView* test_view_child_2 = new TestView();
+ test_view->AddChildView(test_view_child_2);
+ EXPECT_TRUE(test_view_child_2->native_theme_);
+ EXPECT_EQ(widget->GetNativeTheme(), test_view_child_2->native_theme_);
+
+ widget->CloseNow();
+}
} // namespace views
diff --git a/chromium/ui/views/view_unittest_aura.cc b/chromium/ui/views/view_unittest_aura.cc
new file mode 100644
index 00000000000..5b649101050
--- /dev/null
+++ b/chromium/ui/views/view_unittest_aura.cc
@@ -0,0 +1,160 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/view.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_tree_owner.h"
+#include "ui/compositor/test/test_layers.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view_constants_aura.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/window_util.h"
+
+namespace views {
+
+namespace {
+
+// Creates a widget of TYPE_CONTROL.
+// The caller takes ownership of the returned widget.
+Widget* CreateControlWidget(aura::Window* parent, const gfx::Rect& bounds) {
+ Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
+ params.parent = parent;
+ params.bounds = bounds;
+ Widget* widget = new Widget();
+ widget->Init(params);
+ return widget;
+}
+
+// Returns a view with a layer with the passed in |bounds| and |layer_name|.
+// The caller takes ownership of the returned view.
+View* CreateViewWithLayer(const gfx::Rect& bounds, const char* layer_name) {
+ View* view = new View();
+ view->SetBoundsRect(bounds);
+ view->SetPaintToLayer(true);
+ view->layer()->set_name(layer_name);
+ return view;
+}
+
+} // namespace
+
+typedef ViewsTestBase ViewAuraTest;
+
+// Test that wm::RecreateLayers() recreates the layers for all child windows and
+// all child views and that the z-order of the recreated layers matches that of
+// the original layers.
+// Test hierarchy:
+// w1
+// +-- v1
+// +-- v2 (no layer)
+// +-- v3 (no layer)
+// +-- v4
+// +-- w2
+// +-- v5
+// +-- v6
+// +-- v7
+// +-- v8
+// +-- v9
+TEST_F(ViewAuraTest, RecreateLayersWithWindows) {
+ Widget* w1 = CreateControlWidget(GetContext(), gfx::Rect(0, 0, 100, 100));
+ w1->GetNativeView()->layer()->set_name("w1");
+
+ View* v2 = new View();
+ v2->SetBounds(0, 1, 100, 101);
+ View* v3 = new View();
+ v3->SetBounds(0, 2, 100, 102);
+ View* w2_host_view = new View();
+
+ View* v1 = CreateViewWithLayer(gfx::Rect(0, 3, 100, 103), "v1");
+ ui::Layer* v1_layer = v1->layer();
+ w1->GetRootView()->AddChildView(v1);
+ w1->GetRootView()->AddChildView(v2);
+ v2->AddChildView(v3);
+ View* v4 = CreateViewWithLayer(gfx::Rect(0, 4, 100, 104), "v4");
+ ui::Layer* v4_layer = v4->layer();
+ v2->AddChildView(v4);
+
+ w1->GetRootView()->AddChildView(w2_host_view);
+ View* v7 = CreateViewWithLayer(gfx::Rect(0, 4, 100, 104), "v7");
+ ui::Layer* v7_layer = v7->layer();
+ w1->GetRootView()->AddChildView(v7);
+
+ View* v8 = CreateViewWithLayer(gfx::Rect(0, 4, 100, 104), "v8");
+ ui::Layer* v8_layer = v8->layer();
+ v7->AddChildView(v8);
+
+ View* v9 = CreateViewWithLayer(gfx::Rect(0, 4, 100, 104), "v9");
+ ui::Layer* v9_layer = v9->layer();
+ v7->AddChildView(v9);
+
+ Widget* w2 =
+ CreateControlWidget(w1->GetNativeView(), gfx::Rect(0, 5, 100, 105));
+ w2->GetNativeView()->layer()->set_name("w2");
+ w2->GetNativeView()->SetProperty(kHostViewKey, w2_host_view);
+
+ View* v5 = CreateViewWithLayer(gfx::Rect(0, 6, 100, 106), "v5");
+ w2->GetRootView()->AddChildView(v5);
+ View* v6 = CreateViewWithLayer(gfx::Rect(0, 7, 100, 107), "v6");
+ ui::Layer* v6_layer = v6->layer();
+ v5->AddChildView(v6);
+
+ // Test the initial order of the layers.
+ ui::Layer* w1_layer = w1->GetNativeView()->layer();
+ ASSERT_EQ("w1", w1_layer->name());
+ ASSERT_EQ("v1 v4 w2 v7", ui::test::ChildLayerNamesAsString(*w1_layer));
+ ui::Layer* w2_layer = w1_layer->children()[2];
+ ASSERT_EQ("v5", ui::test::ChildLayerNamesAsString(*w2_layer));
+ ui::Layer* v5_layer = w2_layer->children()[0];
+ ASSERT_EQ("v6", ui::test::ChildLayerNamesAsString(*v5_layer));
+
+ {
+ scoped_ptr<ui::LayerTreeOwner> cloned_owner(
+ wm::RecreateLayers(w1->GetNativeView()));
+ EXPECT_EQ(w1_layer, cloned_owner->root());
+ EXPECT_NE(w1_layer, w1->GetNativeView()->layer());
+
+ // The old layers should still exist and have the same hierarchy.
+ ASSERT_EQ("w1", w1_layer->name());
+ ASSERT_EQ("v1 v4 w2 v7", ui::test::ChildLayerNamesAsString(*w1_layer));
+ ASSERT_EQ("v5", ui::test::ChildLayerNamesAsString(*w2_layer));
+ ASSERT_EQ("v6", ui::test::ChildLayerNamesAsString(*v5_layer));
+ EXPECT_EQ("v8 v9", ui::test::ChildLayerNamesAsString(*v7_layer));
+
+ ASSERT_EQ(4u, w1_layer->children().size());
+ EXPECT_EQ(v1_layer, w1_layer->children()[0]);
+ EXPECT_EQ(v4_layer, w1_layer->children()[1]);
+ EXPECT_EQ(w2_layer, w1_layer->children()[2]);
+ EXPECT_EQ(v7_layer, w1_layer->children()[3]);
+
+ ASSERT_EQ(1u, w2_layer->children().size());
+ EXPECT_EQ(v5_layer, w2_layer->children()[0]);
+
+ ASSERT_EQ(1u, v5_layer->children().size());
+ EXPECT_EQ(v6_layer, v5_layer->children()[0]);
+
+ ASSERT_EQ(0u, v6_layer->children().size());
+
+ EXPECT_EQ(2u, v7_layer->children().size());
+ EXPECT_EQ(v8_layer, v7_layer->children()[0]);
+ EXPECT_EQ(v9_layer, v7_layer->children()[1]);
+
+ // The cloned layers should have the same hierarchy as old.
+ ui::Layer* w1_new_layer = w1->GetNativeView()->layer();
+ EXPECT_EQ("w1", w1_new_layer->name());
+ ASSERT_EQ("v1 v4 w2 v7", ui::test::ChildLayerNamesAsString(*w1_new_layer));
+ ui::Layer* w2_new_layer = w1_new_layer->children()[2];
+ ASSERT_EQ("v5", ui::test::ChildLayerNamesAsString(*w2_new_layer));
+ ui::Layer* v5_new_layer = w2_new_layer->children()[0];
+ ASSERT_EQ("v6", ui::test::ChildLayerNamesAsString(*v5_new_layer));
+ ui::Layer* v7_new_layer = w1_new_layer->children()[3];
+ ASSERT_EQ("v8 v9", ui::test::ChildLayerNamesAsString(*v7_new_layer));
+ }
+ // The views and the widgets are destroyed when AuraTestHelper::TearDown()
+ // destroys root_window().
+}
+
+} // namespace views
diff --git a/chromium/ui/views/view_win.cc b/chromium/ui/views/view_win.cc
deleted file mode 100644
index 183a7758cc3..00000000000
--- a/chromium/ui/views/view_win.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/view.h"
-
-// Necessary to define oleacc GUID's.
-#include <windows.h>
-#include <initguid.h>
-#include <oleacc.h>
-
-namespace views {
-
-int View::GetHorizontalDragThreshold() {
- static int threshold = -1;
- if (threshold == -1)
- threshold = GetSystemMetrics(SM_CXDRAG) / 2;
- return threshold;
-}
-
-int View::GetVerticalDragThreshold() {
- static int threshold = -1;
- if (threshold == -1)
- threshold = GetSystemMetrics(SM_CYDRAG) / 2;
- return threshold;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/views.gyp b/chromium/ui/views/views.gyp
index af835c22b96..646bb2fcb20 100644
--- a/chromium/ui/views/views.gyp
+++ b/chromium/ui/views/views.gyp
@@ -8,11 +8,16 @@
'target_defaults': {
'conditions': [
['use_aura==1', {
- 'sources/': [ ['exclude', '_win\\.(h|cc)$'] ],
- 'dependencies': [ '../aura/aura.gyp:aura', ],
- }],
- ['OS!="linux" or chromeos==1', {
- 'sources/': [ ['exclude', '_linux\\.(h|cc)$'] ],
+ 'dependencies': [
+ '../aura/aura.gyp:aura',
+ '../wm/wm.gyp:wm',
+ ],
+ }, { # use_aura==0
+ 'sources/': [
+ ['exclude', '^corewm/'],
+ ['exclude', '^touchui/'],
+ ['exclude', '^widget/desktop_aura/']
+ ]
}],
],
},
@@ -28,20 +33,36 @@
'../../third_party/icu/icu.gyp:icui18n',
'../../third_party/icu/icu.gyp:icuuc',
'../../url/url.gyp:url_lib',
- '../base/strings/ui_strings.gyp:ui_strings',
+ '../accessibility/accessibility.gyp:accessibility',
+ '../accessibility/accessibility.gyp:ax_gen',
+ '../base/ui_base.gyp:ui_base',
'../compositor/compositor.gyp:compositor',
'../events/events.gyp:events',
'../events/events.gyp:events_base',
+ '../events/platform/events_platform.gyp:events_platform',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../native_theme/native_theme.gyp:native_theme',
'../resources/ui_resources.gyp:ui_resources',
- '../ui.gyp:ui',
+ '../strings/ui_strings.gyp:ui_strings',
+ ],
+ 'export_dependent_settings': [
+ '../accessibility/accessibility.gyp:ax_gen',
],
'defines': [
'VIEWS_IMPLEMENTATION',
],
'sources': [
# All .cc, .h under views, except unittests
+ 'accessibility/ax_aura_obj_cache.cc',
+ 'accessibility/ax_aura_obj_cache.h',
+ 'accessibility/ax_aura_obj_wrapper.h',
+ 'accessibility/ax_view_obj_wrapper.cc',
+ 'accessibility/ax_view_obj_wrapper.h',
+ 'accessibility/ax_widget_obj_wrapper.cc',
+ 'accessibility/ax_widget_obj_wrapper.h',
+ 'accessibility/ax_window_obj_wrapper.cc',
+ 'accessibility/ax_window_obj_wrapper.h',
'accessibility/native_view_accessibility.cc',
'accessibility/native_view_accessibility.h',
'accessibility/native_view_accessibility_win.cc',
@@ -62,10 +83,16 @@
'bubble/bubble_delegate.h',
'bubble/bubble_frame_view.cc',
'bubble/bubble_frame_view.h',
+ 'bubble/bubble_window_targeter.cc',
+ 'bubble/bubble_window_targeter.h',
'bubble/tray_bubble_view.cc',
'bubble/tray_bubble_view.h',
'button_drag_utils.cc',
'button_drag_utils.h',
+ 'cocoa/bridged_content_view.h',
+ 'cocoa/bridged_content_view.mm',
+ 'cocoa/bridged_native_widget.h',
+ 'cocoa/bridged_native_widget.mm',
'color_chooser/color_chooser_listener.h',
'color_chooser/color_chooser_view.cc',
'color_chooser/color_chooser_view.h',
@@ -108,21 +135,30 @@
'controls/link.h',
'controls/link_listener.h',
'controls/menu/display_change_listener_aura.cc',
+ 'controls/menu/display_change_listener_mac.cc',
'controls/menu/menu.cc',
'controls/menu/menu.h',
'controls/menu/menu_2.cc',
'controls/menu/menu_2.h',
'controls/menu/menu_config.cc',
'controls/menu/menu_config.h',
- 'controls/menu/menu_config_views.cc',
+ 'controls/menu/menu_config_aura.cc',
+ 'controls/menu/menu_config_mac.cc',
'controls/menu/menu_config_win.cc',
'controls/menu/menu_controller.cc',
'controls/menu/menu_controller.h',
- 'controls/menu/menu_controller_aura.cc',
'controls/menu/menu_controller_delegate.h',
- 'controls/menu/menu_controller_win.cc',
+ 'controls/menu/menu_event_dispatcher_linux.cc',
+ 'controls/menu/menu_event_dispatcher_linux.h',
'controls/menu/menu_delegate.cc',
'controls/menu/menu_delegate.h',
+ 'controls/menu/menu_message_pump_dispatcher_win.cc',
+ 'controls/menu/menu_message_pump_dispatcher_win.h',
+ 'controls/menu/menu_message_loop.h',
+ 'controls/menu/menu_message_loop_aura.cc',
+ 'controls/menu/menu_message_loop_aura.h',
+ 'controls/menu/menu_message_loop_mac.cc',
+ 'controls/menu/menu_message_loop_mac.h',
'controls/menu/menu_host.cc',
'controls/menu/menu_host.h',
'controls/menu/menu_host_root_view.cc',
@@ -142,8 +178,7 @@
'controls/menu/menu_separator.h',
'controls/menu/menu_separator_views.cc',
'controls/menu/menu_separator_win.cc',
- 'controls/menu/menu_win.cc',
- 'controls/menu/menu_win.h',
+ 'controls/menu/menu_types.h',
'controls/menu/menu_wrapper.h',
'controls/menu/native_menu_win.cc',
'controls/menu/native_menu_win.h',
@@ -153,16 +188,11 @@
'controls/menu/submenu_view.h',
'controls/message_box_view.cc',
'controls/message_box_view.h',
- 'controls/native_control.cc',
- 'controls/native_control.h',
- 'controls/native_control_win.cc',
- 'controls/native_control_win.h',
'controls/native/native_view_host.cc',
'controls/native/native_view_host.h',
'controls/native/native_view_host_aura.cc',
'controls/native/native_view_host_aura.h',
- 'controls/native/native_view_host_win.cc',
- 'controls/native/native_view_host_win.h',
+ 'controls/native/native_view_host_mac.cc',
'controls/prefix_delegate.h',
'controls/prefix_selector.cc',
'controls/prefix_selector.h',
@@ -179,8 +209,6 @@
'controls/scrollbar/base_scroll_bar_button.h',
'controls/scrollbar/base_scroll_bar_thumb.cc',
'controls/scrollbar/base_scroll_bar_thumb.h',
- 'controls/scrollbar/bitmap_scroll_bar.cc',
- 'controls/scrollbar/bitmap_scroll_bar.h',
'controls/scrollbar/kennedy_scroll_bar.cc',
'controls/scrollbar/kennedy_scroll_bar.h',
'controls/scrollbar/native_scroll_bar_views.cc',
@@ -215,46 +243,20 @@
'controls/table/table_view.h',
'controls/table/table_view_observer.h',
'controls/table/table_view_row_background_painter.h',
- 'controls/textfield/native_textfield_views.cc',
- 'controls/textfield/native_textfield_views.h',
- 'controls/textfield/native_textfield_wrapper.h',
'controls/textfield/textfield.cc',
'controls/textfield/textfield.h',
'controls/textfield/textfield_controller.cc',
'controls/textfield/textfield_controller.h',
- 'controls/textfield/textfield_views_model.cc',
- 'controls/textfield/textfield_views_model.h',
+ 'controls/textfield/textfield_model.cc',
+ 'controls/textfield/textfield_model.h',
'controls/throbber.cc',
'controls/throbber.h',
'controls/tree/tree_view.cc',
'controls/tree/tree_view.h',
'controls/tree/tree_view_controller.cc',
'controls/tree/tree_view_controller.h',
- 'corewm/base_focus_rules.cc',
- 'corewm/base_focus_rules.h',
- 'corewm/capture_controller.cc',
- 'corewm/capture_controller.h',
- 'corewm/compound_event_filter.cc',
- 'corewm/compound_event_filter.h',
- 'corewm/corewm_switches.cc',
- 'corewm/corewm_switches.h',
- 'corewm/cursor_manager.cc',
- 'corewm/cursor_manager.h',
- 'corewm/focus_controller.cc',
- 'corewm/focus_controller.h',
- 'corewm/focus_rules.h',
- 'corewm/image_grid.cc',
- 'corewm/image_grid.h',
- 'corewm/input_method_event_filter.cc',
- 'corewm/input_method_event_filter.h',
- 'corewm/native_cursor_manager.h',
- 'corewm/native_cursor_manager_delegate.h',
- 'corewm/shadow.cc',
- 'corewm/shadow.h',
- 'corewm/shadow_controller.cc',
- 'corewm/shadow_controller.h',
- 'corewm/shadow_types.cc',
- 'corewm/shadow_types.h',
+ 'corewm/cursor_height_provider_win.cc',
+ 'corewm/cursor_height_provider_win.h',
'corewm/tooltip.h',
'corewm/tooltip_aura.cc',
'corewm/tooltip_aura.h',
@@ -262,27 +264,14 @@
'corewm/tooltip_controller.h',
'corewm/tooltip_win.cc',
'corewm/tooltip_win.h',
- 'corewm/transient_window_stacking_client.cc',
- 'corewm/transient_window_stacking_client.h',
- 'corewm/visibility_controller.cc',
- 'corewm/visibility_controller.h',
- 'corewm/window_animations.cc',
- 'corewm/window_animations.h',
- 'corewm/window_modality_controller.cc',
- 'corewm/window_modality_controller.h',
- 'corewm/window_util.cc',
- 'corewm/window_util.h',
+ 'cull_set.cc',
+ 'cull_set.h',
'debug_utils.cc',
'debug_utils.h',
'drag_controller.h',
'drag_utils.cc',
'drag_utils.h',
- 'event_utils.h',
- 'event_utils_aura.cc',
- 'event_utils_win.cc',
- 'focus/accelerator_handler.h',
- 'focus/accelerator_handler_aura.cc',
- 'focus/accelerator_handler_win.cc',
+ 'drag_utils_aura.cc',
'focus/external_focus_tracker.cc',
'focus/external_focus_tracker.h',
'focus/focus_manager.cc',
@@ -296,14 +285,16 @@
'focus/view_storage.h',
'focus/widget_focus_manager.cc',
'focus/widget_focus_manager.h',
+ 'ime/input_method.h',
'ime/input_method_base.cc',
'ime/input_method_base.h',
'ime/input_method_bridge.cc',
'ime/input_method_bridge.h',
'ime/input_method_delegate.h',
- 'ime/input_method.h',
'ime/mock_input_method.cc',
'ime/mock_input_method.h',
+ 'ime/null_input_method.cc',
+ 'ime/null_input_method.h',
'layout/box_layout.cc',
'layout/box_layout.h',
'layout/fill_layout.cc',
@@ -318,15 +309,21 @@
'linux_ui/status_icon_linux.h',
'linux_ui/status_icon_linux.cc',
'linux_ui/window_button_order_observer.h',
+ 'linux_ui/window_button_order_provider.cc',
+ 'masked_view_targeter.cc',
+ 'masked_view_targeter.h',
'metrics.cc',
'metrics.h',
'metrics_aura.cc',
- 'metrics_win.cc',
+ 'metrics_mac.cc',
'mouse_constants.h',
- 'mouse_watcher.cc',
'mouse_watcher.h',
+ 'mouse_watcher_aura.cc',
'mouse_watcher_view_host.cc',
'mouse_watcher_view_host.h',
+ 'native_cursor.h',
+ 'native_cursor_aura.cc',
+ 'native_cursor_mac.mm',
'native_theme_delegate.h',
'painter.cc',
'painter.h',
@@ -344,7 +341,6 @@
'touchui/touch_selection_controller_impl.h',
'view.cc',
'view.h',
- 'view_aura.cc',
'view_constants.cc',
'view_constants.h',
'view_constants_aura.cc',
@@ -353,15 +349,15 @@
'view_model.h',
'view_model_utils.cc',
'view_model_utils.h',
- 'view_win.cc',
+ 'view_targeter.cc',
+ 'view_targeter.h',
'views_switches.cc',
'views_switches.h',
'views_delegate.cc',
'views_delegate.h',
- 'widget/aero_tooltip_manager.cc',
- 'widget/aero_tooltip_manager.h',
- 'widget/child_window_message_processor.cc',
- 'widget/child_window_message_processor.h',
+ 'views_touch_selection_controller_factory.h',
+ 'views_touch_selection_controller_factory_aura.cc',
+ 'views_touch_selection_controller_factory_mac.cc',
'widget/desktop_aura/desktop_capture_client.cc',
'widget/desktop_aura/desktop_capture_client.h',
'widget/desktop_aura/desktop_cursor_loader_updater.h',
@@ -386,12 +382,12 @@
'widget/desktop_aura/desktop_native_cursor_manager.h',
'widget/desktop_aura/desktop_native_widget_aura.cc',
'widget/desktop_aura/desktop_native_widget_aura.h',
- 'widget/desktop_aura/desktop_root_window_host.h',
- 'widget/desktop_aura/desktop_root_window_host_ozone.cc',
- 'widget/desktop_aura/desktop_root_window_host_win.cc',
- 'widget/desktop_aura/desktop_root_window_host_win.h',
- 'widget/desktop_aura/desktop_root_window_host_x11.cc',
- 'widget/desktop_aura/desktop_root_window_host_x11.h',
+ 'widget/desktop_aura/desktop_window_tree_host.h',
+ 'widget/desktop_aura/desktop_window_tree_host_ozone.cc',
+ 'widget/desktop_aura/desktop_window_tree_host_win.cc',
+ 'widget/desktop_aura/desktop_window_tree_host_win.h',
+ 'widget/desktop_aura/desktop_window_tree_host_x11.cc',
+ 'widget/desktop_aura/desktop_window_tree_host_x11.h',
'widget/desktop_aura/desktop_screen.h',
'widget/desktop_aura/desktop_screen_ozone.cc',
'widget/desktop_aura/desktop_screen_position_client.cc',
@@ -404,6 +400,10 @@
'widget/desktop_aura/x11_desktop_handler.h',
'widget/desktop_aura/x11_desktop_window_move_client.cc',
'widget/desktop_aura/x11_desktop_window_move_client.h',
+ 'widget/desktop_aura/x11_scoped_capture.cc',
+ 'widget/desktop_aura/x11_scoped_capture.h',
+ 'widget/desktop_aura/x11_topmost_window_finder.cc',
+ 'widget/desktop_aura/x11_topmost_window_finder.h',
'widget/desktop_aura/x11_whole_screen_move_loop.cc',
'widget/desktop_aura/x11_whole_screen_move_loop.h',
'widget/desktop_aura/x11_whole_screen_move_loop_delegate.h',
@@ -411,8 +411,6 @@
'widget/desktop_aura/x11_window_event_filter.h',
'widget/drop_helper.cc',
'widget/drop_helper.h',
- 'widget/drop_target_win.cc',
- 'widget/drop_target_win.h',
'widget/root_view.cc',
'widget/root_view.h',
'widget/monitor_win.cc',
@@ -421,13 +419,11 @@
'widget/native_widget_aura.cc',
'widget/native_widget_aura.h',
'widget/native_widget_delegate.h',
+ 'widget/native_widget_mac.h',
+ 'widget/native_widget_mac.mm',
'widget/native_widget_private.h',
- 'widget/native_widget_win.cc',
- 'widget/native_widget_win.h',
'widget/tooltip_manager_aura.cc',
'widget/tooltip_manager_aura.h',
- 'widget/tooltip_manager_win.cc',
- 'widget/tooltip_manager_win.h',
'widget/tooltip_manager.cc',
'widget/tooltip_manager.h',
'widget/widget.cc',
@@ -441,10 +437,9 @@
'widget/widget_hwnd_utils.cc',
'widget/widget_hwnd_utils.h',
'widget/widget_observer.h',
+ 'widget/widget_removals_observer.h',
'widget/window_reorderer.cc',
'widget/window_reorderer.h',
- 'win/appbar.cc',
- 'win/appbar.h',
'win/fullscreen_handler.cc',
'win/fullscreen_handler.h',
'win/hwnd_message_handler.cc',
@@ -452,7 +447,6 @@
'win/hwnd_message_handler_delegate.h',
'win/hwnd_util.h',
'win/hwnd_util_aurawin.cc',
- 'win/hwnd_util_win.cc',
'win/scoped_fullscreen_visibility.cc',
'win/scoped_fullscreen_visibility.h',
'window/client_view.cc',
@@ -470,6 +464,8 @@
'window/native_frame_view.h',
'window/non_client_view.cc',
'window/non_client_view.h',
+ 'window/window_button_order_provider.cc',
+ 'window/window_button_order_provider.h',
'window/window_resources.h',
'window/window_shape.cc',
'window/window_shape.h',
@@ -478,53 +474,6 @@
'../../third_party/wtl/include',
],
'conditions': [
- ['use_aura==1', {
- 'sources!': [
- 'controls/native_control.cc',
- 'controls/native_control.h',
- 'controls/scrollbar/bitmap_scroll_bar.cc',
- 'controls/scrollbar/bitmap_scroll_bar.h',
- 'controls/table/table_view_observer.h',
- 'widget/aero_tooltip_manager.cc',
- 'widget/aero_tooltip_manager.h',
- 'widget/child_window_message_processor.cc',
- 'widget/child_window_message_processor.h',
- 'widget/tooltip_manager_win.cc',
- 'widget/tooltip_manager_win.h',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'sources/': [
- ['include', 'controls/menu/menu_insertion_delegate_win.h'],
- ['include', 'controls/menu/native_menu_win.cc'],
- ['include', 'controls/menu/native_menu_win.h'],
- ['include', 'corewm/tooltip_win.cc'],
- ['include', 'corewm/tooltip_win.h'],
- ['include', 'event_utils_win.cc'],
- ['include', 'widget/desktop_aura/desktop_screen_win.cc'],
- ['include', 'widget/desktop_aura/desktop_drag_drop_client_win.cc'],
- ['include', 'widget/desktop_aura/desktop_drop_target_win.cc'],
- ['include', 'widget/desktop_aura/desktop_root_window_host_win.cc'],
- ['include', 'widget/monitor_win.cc'],
- ['include', 'widget/monitor_win.h'],
- ['include', 'win/appbar.cc'],
- ['include', 'win/appbar.h'],
- ],
- }],
- ],
- }],
- ['use_aura==0', {
- 'sources/': [
- ['exclude', 'corewm'],
- ['exclude', 'widget/desktop_aura'],
- ['exclude', 'widget/window_reorderer.h'],
- ['exclude', 'widget/window_reorderer.cc'],
- ],
- 'sources!': [
- 'widget/widget_aura_utils.cc',
- 'widget/widget_aura_utils.h',
- ],
- }],
['chromeos==1', {
'sources/': [
['exclude', 'widget/desktop_aura'],
@@ -536,24 +485,18 @@
'bubble/tray_bubble_view.h',
],
}],
- ['use_aura==0 and OS=="win"', {
- 'sources!': [
- 'controls/menu/menu_config_views.cc',
- 'controls/menu/menu_separator_views.cc',
- ],
- }],
- ['use_aura==1 and OS=="win"', {
- 'sources/': [
- ['include', 'controls/menu/menu_config_win.cc'],
- ['include', 'controls/menu/menu_separator_win.cc'],
- ['include', 'accessibility/native_view_accessibility_win.cc'],
- ['include', 'accessibility/native_view_accessibility_win.h'],
+ ['chromeos==0 and use_x11==1', {
+ 'dependencies': [
+ '../display/display.gyp:display_util',
],
}],
['OS=="linux" and chromeos==0', {
'dependencies': [
'../shell_dialogs/shell_dialogs.gyp:shell_dialogs',
],
+ 'sources!': [
+ 'window/window_button_order_provider.cc',
+ ],
}, { # OS=="linux" and chromeos==0
'sources/': [
['exclude', 'linux_ui'],
@@ -604,6 +547,34 @@
'../ozone/ozone.gyp:ozone',
],
}],
+ ['use_x11==1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:xrandr',
+ '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
+ ],
+ }],
+ ['use_aura==0', {
+ 'sources!': [
+ 'accessibility/ax_aura_obj_cache.cc',
+ 'accessibility/ax_aura_obj_cache.h',
+ 'accessibility/ax_aura_obj_wrapper.h',
+ 'accessibility/ax_view_obj_wrapper.cc',
+ 'accessibility/ax_view_obj_wrapper.h',
+ 'accessibility/ax_widget_obj_wrapper.cc',
+ 'accessibility/ax_widget_obj_wrapper.h',
+ 'accessibility/ax_window_obj_wrapper.cc',
+ 'accessibility/ax_window_obj_wrapper.h',
+ 'bubble/bubble_window_targeter.cc',
+ 'bubble/bubble_window_targeter.h',
+ 'bubble/tray_bubble_view.cc',
+ 'bubble/tray_bubble_view.h',
+ 'mouse_watcher_view_host.cc',
+ 'mouse_watcher_view_host.h',
+ 'widget/window_reorderer.cc',
+ 'widget/window_reorderer.h',
+ ],
+ }],
],
}, # target_name: views
{
@@ -614,38 +585,52 @@
'../../ipc/ipc.gyp:test_support_ipc',
'../../skia/skia.gyp:skia',
'../../testing/gtest.gyp:gtest',
+ '../base/ui_base.gyp:ui_base',
+ '../compositor/compositor.gyp:compositor',
'../events/events.gyp:events',
+ '../events/platform/events_platform.gyp:events_platform',
'../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
+ '../gfx/gfx.gyp:gfx_geometry',
'views',
],
'include_dirs': [
'..',
],
'sources': [
+ 'controls/textfield/textfield_test_api.cc',
+ 'controls/textfield/textfield_test_api.h',
'corewm/tooltip_controller_test_helper.cc',
'corewm/tooltip_controller_test_helper.h',
'test/capture_tracking_view.cc',
'test/capture_tracking_view.h',
- 'test/child_modal_window.cc',
- 'test/child_modal_window.h',
- 'test/desktop_test_views_delegate.cc',
'test/desktop_test_views_delegate.h',
+ 'test/desktop_test_views_delegate_aura.cc',
+ 'test/desktop_test_views_delegate_mac.mm',
'test/menu_runner_test_api.cc',
'test/menu_runner_test_api.h',
+ 'test/slider_test_api.cc',
+ 'test/slider_test_api.h',
'test/test_views.cc',
'test/test_views.h',
- 'test/test_views_delegate.cc',
'test/test_views_delegate.h',
+ 'test/test_views_delegate_aura.cc',
+ 'test/test_views_delegate_mac.mm',
'test/test_widget_observer.cc',
'test/test_widget_observer.h',
'test/ui_controls_factory_desktop_aurax11.cc',
'test/ui_controls_factory_desktop_aurax11.h',
'test/views_test_base.cc',
'test/views_test_base.h',
+ 'test/views_test_helper.cc',
+ 'test/views_test_helper.h',
+ 'test/views_test_helper_aura.cc',
+ 'test/views_test_helper_aura.h',
'test/widget_test.cc',
'test/widget_test.h',
- 'widget/root_view_test_helper.h',
+ 'test/widget_test_aura.cc',
+ 'test/widget_test_mac.mm',
+ 'test/x11_property_change_waiter.cc',
+ 'test/x11_property_change_waiter.h',
],
'conditions': [
['chromeos==1', {
@@ -657,44 +642,11 @@
['use_aura==1', {
'dependencies': [
'../aura/aura.gyp:aura_test_support',
- '../compositor/compositor.gyp:compositor',
- ],
- }, { # use_aura==0
- 'sources!': [
- 'corewm/tooltip_controller_test_helper.cc',
- 'corewm/tooltip_controller_test_helper.h',
- 'test/child_modal_window.cc',
- 'test/child_modal_window.h',
],
}],
],
}, # target_name: views_test_support
{
- 'target_name': 'views_with_content_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../content/content.gyp:content',
- '../../content/content_shell_and_tests.gyp:test_support_content',
- '../../ipc/ipc.gyp:test_support_ipc',
- '../../skia/skia.gyp:skia',
- '../../testing/gtest.gyp:gtest',
- '../events/events.gyp:events',
- '../gfx/gfx.gyp:gfx',
- '../ui.gyp:ui',
- 'controls/webview/webview.gyp:webview',
- 'views_test_support',
- 'views',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'test/webview_test_helper.cc',
- 'test/webview_test_helper.h',
- ],
- }, # target_name: views_with_content_test_support
- {
'target_name': 'views_unittests',
'type': 'executable',
'dependencies': [
@@ -702,20 +654,22 @@
'../../base/base.gyp:base_i18n',
'../../base/base.gyp:test_support_base',
'../../skia/skia.gyp:skia',
- '../../testing/gmock.gyp:gmock',
'../../testing/gtest.gyp:gtest',
'../../third_party/icu/icu.gyp:icui18n',
'../../third_party/icu/icu.gyp:icuuc',
'../../url/url.gyp:url_lib',
- '../base/strings/ui_strings.gyp:ui_strings',
+ '../accessibility/accessibility.gyp:accessibility',
+ '../base/ui_base.gyp:ui_base',
+ '../base/ui_base.gyp:ui_base_test_support',
'../compositor/compositor.gyp:compositor',
'../compositor/compositor.gyp:compositor_test_support',
'../events/events.gyp:events',
+ '../events/events.gyp:events_base',
'../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
'../resources/ui_resources.gyp:ui_resources',
'../resources/ui_resources.gyp:ui_test_pak',
- '../ui.gyp:ui',
- '../ui_unittests.gyp:ui_test_support',
+ '../strings/ui_strings.gyp:ui_strings',
'views',
'views_test_support',
],
@@ -729,12 +683,17 @@
'bubble/bubble_border_unittest.cc',
'bubble/bubble_delegate_unittest.cc',
'bubble/bubble_frame_view_unittest.cc',
+ 'bubble/bubble_window_targeter_unittest.cc',
+ 'cocoa/bridged_native_widget_unittest.mm',
+ 'controls/button/blue_button_unittest.cc',
'controls/button/custom_button_unittest.cc',
'controls/button/image_button_unittest.cc',
'controls/button/label_button_unittest.cc',
+ 'controls/button/menu_button_unittest.cc',
'controls/combobox/combobox_unittest.cc',
'controls/label_unittest.cc',
'controls/menu/menu_model_adapter_unittest.cc',
+ 'controls/menu/menu_controller_unittest.cc',
'controls/native/native_view_host_aura_unittest.cc',
'controls/native/native_view_host_unittest.cc',
'controls/prefix_selector_unittest.cc',
@@ -749,26 +708,15 @@
'controls/table/table_view_unittest.cc',
'controls/table/test_table_model.cc',
'controls/table/test_table_model.h',
- 'controls/textfield/native_textfield_views_unittest.cc',
- 'controls/textfield/textfield_views_model_unittest.cc',
+ 'controls/textfield/textfield_unittest.cc',
+ 'controls/textfield/textfield_model_unittest.cc',
'controls/tree/tree_view_unittest.cc',
'corewm/capture_controller_unittest.cc',
- 'corewm/compound_event_filter_unittest.cc',
- 'corewm/cursor_manager_unittest.cc',
- 'corewm/focus_controller_unittest.cc',
- 'corewm/image_grid_unittest.cc',
- 'corewm/input_method_event_filter_unittest.cc',
- 'corewm/shadow_controller_unittest.cc',
'corewm/tooltip_aura_unittest.cc',
'corewm/tooltip_controller_unittest.cc',
- 'corewm/transient_window_stacking_client_unittest.cc',
- 'corewm/visibility_controller_unittest.cc',
- 'corewm/window_animations_unittest.cc',
- 'corewm/window_util_unittest.cc',
'focus/focus_manager_test.h',
'focus/focus_manager_test.cc',
'focus/focus_manager_unittest.cc',
- 'focus/focus_manager_unittest_win.cc',
'focus/focus_traversal_unittest.cc',
'ime/input_method_bridge_unittest.cc',
'layout/box_layout_unittest.cc',
@@ -778,32 +726,36 @@
'touchui/touch_selection_controller_impl_unittest.cc',
'view_model_unittest.cc',
'view_model_utils_unittest.cc',
+ 'view_targeter_unittest.cc',
'view_unittest.cc',
+ 'view_unittest_aura.cc',
+ 'widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc',
+ 'widget/desktop_aura/desktop_focus_rules_unittest.cc',
'widget/desktop_aura/desktop_native_widget_aura_unittest.cc',
- 'widget/desktop_aura/desktop_root_window_host_win_unittest.cc',
'widget/desktop_aura/desktop_screen_x11_unittest.cc',
'widget/desktop_aura/desktop_screen_position_client_unittest.cc',
+ 'widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc',
+ 'widget/desktop_aura/x11_topmost_window_finder_unittest.cc',
'widget/native_widget_aura_unittest.cc',
'widget/native_widget_unittest.cc',
- 'widget/native_widget_win_unittest.cc',
'widget/root_view_unittest.cc',
'widget/widget_unittest.cc',
'widget/window_reorderer_unittest.cc',
+ 'window/custom_frame_view_unittest.cc',
'window/dialog_client_view_unittest.cc',
'window/dialog_delegate_unittest.cc',
],
'conditions': [
- ['chromeos==0', {
- 'sources!': [
- 'touchui/touch_selection_controller_impl_unittest.cc',
- ],
- }, { # use_chromeos==1
+ ['chromeos==1', {
'sources/': [
['exclude', 'ime/input_method_bridge_unittest.cc'],
['exclude', 'widget/desktop_aura'],
],
}],
['OS=="win"', {
+ 'dependencies': [
+ '../../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
+ ],
'link_settings': {
'libraries': [
'-limm32.lib',
@@ -814,35 +766,30 @@
'include_dirs': [
'../third_party/wtl/include',
],
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'AdditionalManifestFiles': [
+ '$(ProjectDir)\\test\\views_unittest.manifest',
+ ],
+ },
+ },
}],
['OS=="win" and win_use_allocator_shim==1', {
'dependencies': [
'../../base/allocator/allocator.gyp:allocator',
],
}],
- ['OS=="linux" and linux_use_tcmalloc==1', {
+ ['OS=="linux" and use_allocator!="none"', {
# See http://crbug.com/162998#c4 for why this is needed.
'dependencies': [
'../../base/allocator/allocator.gyp:allocator',
],
}],
- [ 'use_aura==1', {
+ ['use_x11==1', {
'dependencies': [
- '../aura/aura.gyp:aura_test_support',
- ],
- 'sources!': [
- 'widget/native_widget_win_unittest.cc',
- ],
- }, { # use_aura==0
- 'sources!': [
- 'controls/native/native_view_host_aura_unittest.cc',
- 'widget/native_widget_aura_unittest.cc',
- ],
- 'sources/': [
- ['exclude', 'corewm'],
- ['exclude', 'ime/input_method_bridge_unittest.cc'],
- ['exclude', 'widget/desktop_aura'],
- ['exclude', 'widget/window_reorderer_unittest.cc']
+ '../../build/linux/system.gyp:x11',
+ '../../build/linux/system.gyp:xext',
+ '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
],
}],
['use_ozone==1', {
@@ -850,268 +797,31 @@
'corewm/capture_controller_unittest.cc',
],
}],
- # Native tooltip class doesn't run well from unit tests.
- ['use_aura==1 and OS=="win"', {
- 'sources!': [
- 'corewm/tooltip_controller_unittest.cc',
- ],
- }],
- ],
- }, # target_name: views_unittests
- {
- 'target_name': 'views_examples_lib',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../skia/skia.gyp:skia',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../events/events.gyp:events',
- '../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../resources/ui_resources.gyp:ui_test_pak',
- '../ui.gyp:ui',
- 'views',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'VIEWS_EXAMPLES_IMPLEMENTATION',
- ],
- 'sources': [
- 'examples/bubble_example.cc',
- 'examples/bubble_example.h',
- 'examples/button_example.cc',
- 'examples/button_example.h',
- 'examples/checkbox_example.cc',
- 'examples/checkbox_example.h',
- 'examples/combobox_example.cc',
- 'examples/combobox_example.h',
- 'examples/double_split_view_example.cc',
- 'examples/double_split_view_example.h',
- 'examples/example_base.cc',
- 'examples/example_base.h',
- 'examples/example_combobox_model.cc',
- 'examples/example_combobox_model.h',
- 'examples/examples_window.cc',
- 'examples/examples_window.h',
- 'examples/label_example.cc',
- 'examples/label_example.h',
- 'examples/link_example.cc',
- 'examples/link_example.h',
- 'examples/message_box_example.cc',
- 'examples/message_box_example.h',
- 'examples/menu_example.cc',
- 'examples/menu_example.h',
- 'examples/multiline_example.cc',
- 'examples/multiline_example.h',
- 'examples/progress_bar_example.cc',
- 'examples/progress_bar_example.h',
- 'examples/radio_button_example.cc',
- 'examples/radio_button_example.h',
- 'examples/scroll_view_example.cc',
- 'examples/scroll_view_example.h',
- 'examples/single_split_view_example.cc',
- 'examples/single_split_view_example.h',
- 'examples/slider_example.cc',
- 'examples/slider_example.h',
- 'examples/tabbed_pane_example.cc',
- 'examples/tabbed_pane_example.h',
- 'examples/table_example.cc',
- 'examples/table_example.h',
- 'examples/text_example.cc',
- 'examples/text_example.h',
- 'examples/textfield_example.cc',
- 'examples/textfield_example.h',
- 'examples/throbber_example.cc',
- 'examples/throbber_example.h',
- 'examples/tree_view_example.cc',
- 'examples/tree_view_example.h',
- 'examples/views_examples_export.h',
- 'examples/widget_example.cc',
- 'examples/widget_example.h',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'include_dirs': [
- '../third_party/wtl/include',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }],
- ],
- }, # target_name: views_examples_lib
- {
- 'target_name': 'views_examples_exe',
- 'type': 'executable',
- 'dependencies': [
- '../../base/base.gyp:base',
- ],
- 'sources': [
- 'examples/examples_main.cc',
- ],
- }, # target_name: views_examples_exe
- {
- 'target_name': 'views_examples_with_content_lib',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../content/content.gyp:content',
- '../../skia/skia.gyp:skia',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../../url/url.gyp:url_lib',
- '../events/events.gyp:events',
- '../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../resources/ui_resources.gyp:ui_test_pak',
- '../ui.gyp:ui',
- 'controls/webview/webview.gyp:webview',
- 'views',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'VIEWS_EXAMPLES_WITH_CONTENT_IMPLEMENTATION',
- ],
- 'sources': [
- 'examples/bubble_example.cc',
- 'examples/bubble_example.h',
- 'examples/button_example.cc',
- 'examples/button_example.h',
- 'examples/checkbox_example.cc',
- 'examples/checkbox_example.h',
- 'examples/combobox_example.cc',
- 'examples/combobox_example.h',
- 'examples/double_split_view_example.cc',
- 'examples/double_split_view_example.h',
- 'examples/example_base.cc',
- 'examples/example_base.h',
- 'examples/example_combobox_model.cc',
- 'examples/example_combobox_model.h',
- 'examples/examples_window_with_content.cc',
- 'examples/examples_window_with_content.h',
- 'examples/label_example.cc',
- 'examples/label_example.h',
- 'examples/link_example.cc',
- 'examples/link_example.h',
- 'examples/message_box_example.cc',
- 'examples/message_box_example.h',
- 'examples/menu_example.cc',
- 'examples/menu_example.h',
- 'examples/multiline_example.cc',
- 'examples/multiline_example.h',
- 'examples/progress_bar_example.cc',
- 'examples/progress_bar_example.h',
- 'examples/radio_button_example.cc',
- 'examples/radio_button_example.h',
- 'examples/scroll_view_example.cc',
- 'examples/scroll_view_example.h',
- 'examples/single_split_view_example.cc',
- 'examples/single_split_view_example.h',
- 'examples/slider_example.cc',
- 'examples/slider_example.h',
- 'examples/tabbed_pane_example.cc',
- 'examples/tabbed_pane_example.h',
- 'examples/table_example.cc',
- 'examples/table_example.h',
- 'examples/text_example.cc',
- 'examples/text_example.h',
- 'examples/textfield_example.cc',
- 'examples/textfield_example.h',
- 'examples/throbber_example.cc',
- 'examples/throbber_example.h',
- 'examples/tree_view_example.cc',
- 'examples/tree_view_example.h',
- 'examples/views_examples_with_content_export.h',
- 'examples/webview_example.cc',
- 'examples/webview_example.h',
- 'examples/widget_example.cc',
- 'examples/widget_example.h',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'include_dirs': [
- '../third_party/wtl/include',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }],
- ],
- }, # target_name: views_examples_with_content_lib
- {
- 'target_name': 'views_examples_with_content_exe',
- 'type': 'executable',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../content/content.gyp:content',
- '../../content/content_shell_and_tests.gyp:content_shell_lib',
- '../../content/content_shell_and_tests.gyp:test_support_content',
- '../../skia/skia.gyp:skia',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../events/events.gyp:events',
- '../gfx/gfx.gyp:gfx',
- '../resources/ui_resources.gyp:ui_resources',
- '../resources/ui_resources.gyp:ui_test_pak',
- '../ui.gyp:ui',
- '../wm/wm.gyp:wm_test_support',
- 'views',
- 'views_examples_with_content_lib',
- 'views_test_support'
- ],
- 'include_dirs': [
- '../..',
- ],
- 'sources': [
- '../../content/app/startup_helper_win.cc',
- 'examples/content_client/examples_browser_main_parts.cc',
- 'examples/content_client/examples_browser_main_parts.h',
- 'examples/content_client/examples_content_browser_client.cc',
- 'examples/content_client/examples_content_browser_client.h',
- 'examples/content_client/examples_main_delegate.cc',
- 'examples/content_client/examples_main_delegate.h',
- 'examples/content_client/examples_main.cc',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'link_settings': {
- 'libraries': [
- '-limm32.lib',
- '-loleacc.lib',
- ]
- },
- 'msvs_settings': {
- 'VCManifestTool': {
- 'AdditionalManifestFiles': [
- 'examples\\views_examples.exe.manifest',
- ],
- },
- 'VCLinkerTool': {
- 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
- },
- },
+ ['use_aura==1', {
'dependencies': [
- '../../sandbox/sandbox.gyp:sandbox',
+ '../aura/aura.gyp:aura_test_support',
],
}],
- ['use_aura==1', {
+ ['use_x11==1', {
'dependencies': [
- '../compositor/compositor.gyp:compositor',
+ '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
],
}],
- ['OS=="win"', {
- 'sources/': [
- # This is needed because the aura rule strips it from the default
- # sources list.
- ['include', '^../../content/app/startup_helper_win.cc'],
- ],
+ ['OS=="mac"', {
+ # views_unittests not yet compiling on Mac. http://crbug.com/378134
+ 'sources!': [
+ 'bubble/bubble_window_targeter_unittest.cc',
+ 'controls/button/custom_button_unittest.cc',
+ 'controls/button/menu_button_unittest.cc',
+ 'controls/native/native_view_host_unittest.cc',
+ 'controls/menu/menu_controller_unittest.cc',
+ 'ime/input_method_bridge_unittest.cc',
+ 'focus/focus_manager_unittest.cc',
+ 'widget/window_reorderer_unittest.cc',
+ 'widget/widget_unittest.cc',
+ ]
}],
],
- }, # target_name: views_examples_with_content_exe
+ }, # target_name: views_unittests
],
}
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index 20cb88f9359..c1c7ca6bd44 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -4,12 +4,12 @@
#include "ui/views/views_delegate.h"
-#include "ui/views/touchui/touch_selection_controller_impl.h"
+#include "ui/views/views_touch_selection_controller_factory.h"
namespace views {
ViewsDelegate::ViewsDelegate()
- : views_tsc_factory_(new views::ViewsTouchSelectionControllerFactory) {
+ : views_tsc_factory_(new ViewsTouchSelectionControllerFactory) {
ui::TouchSelectionControllerFactory::SetInstance(views_tsc_factory_.get());
}
@@ -17,4 +17,81 @@ ViewsDelegate::~ViewsDelegate() {
ui::TouchSelectionControllerFactory::SetInstance(NULL);
}
+void ViewsDelegate::SaveWindowPlacement(const Widget* widget,
+ const std::string& window_name,
+ const gfx::Rect& bounds,
+ ui::WindowShowState show_state) {
+}
+
+bool ViewsDelegate::GetSavedWindowPlacement(
+ const Widget* widget,
+ const std::string& window_name,
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ return false;
+}
+
+void ViewsDelegate::NotifyAccessibilityEvent(View* view,
+ ui::AXEvent event_type) {
+}
+
+void ViewsDelegate::NotifyMenuItemFocused(const base::string16& menu_name,
+ const base::string16& menu_item_name,
+ int item_index,
+ int item_count,
+ bool has_submenu) {
+}
+
+#if defined(OS_WIN)
+HICON ViewsDelegate::GetDefaultWindowIcon() const {
+ return NULL;
+}
+
+bool ViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const {
+ return false;
+}
+#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const {
+ return NULL;
+}
+#endif
+
+NonClientFrameView* ViewsDelegate::CreateDefaultNonClientFrameView(
+ Widget* widget) {
+ return NULL;
+}
+
+void ViewsDelegate::AddRef() {
+}
+
+void ViewsDelegate::ReleaseRef() {
+}
+
+content::WebContents* ViewsDelegate::CreateWebContents(
+ content::BrowserContext* browser_context,
+ content::SiteInstance* site_instance) {
+ return NULL;
+}
+
+base::TimeDelta ViewsDelegate::GetDefaultTextfieldObscuredRevealDuration() {
+ return base::TimeDelta();
+}
+
+bool ViewsDelegate::WindowManagerProvidesTitleBar(bool maximized) {
+ return false;
+}
+
+#if defined(USE_AURA)
+ui::ContextFactory* ViewsDelegate::GetContextFactory() {
+ return NULL;
+}
+#endif
+
+#if defined(OS_WIN)
+int ViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor,
+ const base::Closure& callback) {
+ return EDGE_BOTTOM;
+}
+#endif
+
} // namespace views
diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h
index 85fa50b5aa5..0175c8ba201 100644
--- a/chromium/ui/views/views_delegate.h
+++ b/chromium/ui/views/views_delegate.h
@@ -12,7 +12,7 @@
#endif
#include "base/strings/string16.h"
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
@@ -33,6 +33,10 @@ class ImageSkia;
class Rect;
}
+namespace ui {
+class ContextFactory;
+}
+
namespace views {
class NativeWidget;
@@ -52,11 +56,16 @@ class NativeWidgetDelegate;
// implementation.
class VIEWS_EXPORT ViewsDelegate {
public:
- // The active ViewsDelegate used by the views system.
- static ViewsDelegate* views_delegate;
+#if defined(OS_WIN)
+ enum AppbarAutohideEdge {
+ EDGE_TOP = 1 << 0,
+ EDGE_LEFT = 1 << 1,
+ EDGE_BOTTOM = 1 << 2,
+ EDGE_RIGHT = 1 << 3,
+ };
+#endif
ViewsDelegate();
-
virtual ~ViewsDelegate();
// Saves the position, size and "show" state for the window with the
@@ -64,68 +73,86 @@ class VIEWS_EXPORT ViewsDelegate {
virtual void SaveWindowPlacement(const Widget* widget,
const std::string& window_name,
const gfx::Rect& bounds,
- ui::WindowShowState show_state) = 0;
+ ui::WindowShowState show_state);
// Retrieves the saved position and size and "show" state for the window with
// the specified name.
- virtual bool GetSavedWindowPlacement(
- const Widget* widget,
- const std::string& window_name,
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const = 0;
+ virtual bool GetSavedWindowPlacement(const Widget* widget,
+ const std::string& window_name,
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const;
- virtual void NotifyAccessibilityEvent(
- View* view,
- ui::AccessibilityTypes::Event event_type) = 0;
+ virtual void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type);
// For accessibility, notify the delegate that a menu item was focused
// so that alternate feedback (speech / magnified text) can be provided.
- virtual void NotifyMenuItemFocused(const string16& menu_name,
- const string16& menu_item_name,
+ virtual void NotifyMenuItemFocused(const base::string16& menu_name,
+ const base::string16& menu_item_name,
int item_index,
int item_count,
- bool has_submenu) = 0;
+ bool has_submenu);
#if defined(OS_WIN)
// Retrieves the default window icon to use for windows if none is specified.
- virtual HICON GetDefaultWindowIcon() const = 0;
+ virtual HICON GetDefaultWindowIcon() const;
// Returns true if the window passed in is in the Windows 8 metro
// environment.
- virtual bool IsWindowInMetro(gfx::NativeWindow window) const = 0;
+ virtual bool IsWindowInMetro(gfx::NativeWindow window) const;
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
- virtual gfx::ImageSkia* GetDefaultWindowIcon() const = 0;
+ virtual gfx::ImageSkia* GetDefaultWindowIcon() const;
#endif
// Creates a default NonClientFrameView to be used for windows that don't
// specify their own. If this function returns NULL, the
// views::CustomFrameView type will be used.
- virtual NonClientFrameView* CreateDefaultNonClientFrameView(
- Widget* widget) = 0;
-
- // Returns whether the embedding app wants windows to be created with the
- // views::Widget marked as transparent. For example, an app may wish to
- // apply transparent window frames in the NonClientFrameView.
- virtual bool UseTransparentWindows() const = 0;
+ virtual NonClientFrameView* CreateDefaultNonClientFrameView(Widget* widget);
// AddRef/ReleaseRef are invoked while a menu is visible. They are used to
// ensure we don't attempt to exit while a menu is showing.
- virtual void AddRef() = 0;
- virtual void ReleaseRef() = 0;
+ virtual void AddRef();
+ virtual void ReleaseRef();
// Creates a web contents. This will return NULL unless overriden.
virtual content::WebContents* CreateWebContents(
content::BrowserContext* browser_context,
- content::SiteInstance* site_instance) = 0;
+ content::SiteInstance* site_instance);
// Gives the platform a chance to modify the properties of a Widget.
virtual void OnBeforeWidgetInit(Widget::InitParams* params,
internal::NativeWidgetDelegate* delegate) = 0;
// Returns the default obscured text reveal duration.
- virtual base::TimeDelta GetDefaultTextfieldObscuredRevealDuration() = 0;
+ virtual base::TimeDelta GetDefaultTextfieldObscuredRevealDuration();
+
+ // Returns true if the operating system's window manager will always provide a
+ // title bar with caption buttons (ignoring the setting to
+ // |remove_standard_frame| in InitParams). If |maximized|, this applies to
+ // maximized windows; otherwise to restored windows.
+ virtual bool WindowManagerProvidesTitleBar(bool maximized);
+
+#if defined(USE_AURA)
+ // Returns the context factory for new windows.
+ virtual ui::ContextFactory* GetContextFactory();
+#endif
+
+#if defined(OS_WIN)
+ // Starts a query for the appbar autohide edges of the specified monitor and
+ // returns the current value. If the query finds the edges have changed from
+ // the current value, |callback| is subsequently invoked. If the edges have
+ // not changed, |callback| is never run.
+ //
+ // The return value is a bitmask of AppbarAutohideEdge.
+ virtual int GetAppbarAutohideEdges(HMONITOR monitor,
+ const base::Closure& callback);
+#endif
+
+ // The active ViewsDelegate used by the views system.
+ static ViewsDelegate* views_delegate;
private:
scoped_ptr<ViewsTouchSelectionControllerFactory> views_tsc_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsDelegate);
};
} // namespace views
diff --git a/chromium/ui/views/views_switches.cc b/chromium/ui/views/views_switches.cc
index c62e83d1d8b..342deeec600 100644
--- a/chromium/ui/views/views_switches.cc
+++ b/chromium/ui/views/views_switches.cc
@@ -16,6 +16,15 @@ namespace switches {
const char kDisableViewsRectBasedTargeting[] =
"disable-views-rect-based-targeting";
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+// When enabled, tries to get a transparent X11 visual so that we can have
+// per-pixel alpha in windows.
+//
+// TODO(erg): Remove this switch once we've stabilized the code
+// path. http://crbug.com/369209
+const char kEnableTransparentVisuals[] = "enable-transparent-visuals";
+#endif
+
bool IsRectBasedTargetingEnabled() {
#if defined(OS_CHROMEOS) || defined(OS_WIN)
return !CommandLine::ForCurrentProcess()->
diff --git a/chromium/ui/views/views_switches.h b/chromium/ui/views/views_switches.h
index 9e5029476ef..0fb09db6632 100644
--- a/chromium/ui/views/views_switches.h
+++ b/chromium/ui/views/views_switches.h
@@ -15,6 +15,10 @@ namespace switches {
// Please keep alphabetized.
VIEWS_EXPORT extern const char kDisableViewsRectBasedTargeting[];
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+VIEWS_EXPORT extern const char kEnableTransparentVisuals[];
+#endif
+
// Returns true if rect-based targeting in views should be used.
VIEWS_EXPORT bool IsRectBasedTargetingEnabled();
diff --git a/chromium/ui/views/views_touch_selection_controller_factory.h b/chromium/ui/views/views_touch_selection_controller_factory.h
new file mode 100644
index 00000000000..6b02c1e8d42
--- /dev/null
+++ b/chromium/ui/views/views_touch_selection_controller_factory.h
@@ -0,0 +1,25 @@
+// 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_UI_VIEWS_VIEWS_TOUCH_SELECTION_CONTROLLER_FACTORY_H_
+#define UI_UI_VIEWS_VIEWS_TOUCH_SELECTION_CONTROLLER_FACTORY_H_
+
+#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class VIEWS_EXPORT ViewsTouchSelectionControllerFactory
+ : public ui::TouchSelectionControllerFactory {
+ public:
+ ViewsTouchSelectionControllerFactory();
+
+ // Overridden from ui::TouchSelectionControllerFactory.
+ virtual ui::TouchSelectionController* create(
+ ui::TouchEditable* client_view) OVERRIDE;
+};
+
+} // namespace views
+
+#endif // UI_UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
diff --git a/chromium/ui/views/views_touch_selection_controller_factory_aura.cc b/chromium/ui/views/views_touch_selection_controller_factory_aura.cc
new file mode 100644
index 00000000000..a28da03a2e4
--- /dev/null
+++ b/chromium/ui/views/views_touch_selection_controller_factory_aura.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/views_touch_selection_controller_factory.h"
+
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/views/touchui/touch_selection_controller_impl.h"
+
+namespace views {
+
+ViewsTouchSelectionControllerFactory::ViewsTouchSelectionControllerFactory() {
+}
+
+ui::TouchSelectionController* ViewsTouchSelectionControllerFactory::create(
+ ui::TouchEditable* client_view) {
+ if (switches::IsTouchEditingEnabled())
+ return new views::TouchSelectionControllerImpl(client_view);
+ return NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/views_touch_selection_controller_factory_mac.cc b/chromium/ui/views/views_touch_selection_controller_factory_mac.cc
new file mode 100644
index 00000000000..b4866154e11
--- /dev/null
+++ b/chromium/ui/views/views_touch_selection_controller_factory_mac.cc
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/views_touch_selection_controller_factory.h"
+
+namespace views {
+
+ViewsTouchSelectionControllerFactory::ViewsTouchSelectionControllerFactory() {
+}
+
+ui::TouchSelectionController* ViewsTouchSelectionControllerFactory::create(
+ ui::TouchEditable* client_view) {
+ return NULL;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/aero_tooltip_manager.cc b/chromium/ui/views/widget/aero_tooltip_manager.cc
deleted file mode 100644
index 8e1f600b0d5..00000000000
--- a/chromium/ui/views/widget/aero_tooltip_manager.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/aero_tooltip_manager.h"
-
-#include <windows.h>
-#include <commctrl.h>
-#include <shlobj.h>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/hwnd_util.h"
-
-namespace views {
-
-///////////////////////////////////////////////////////////////////////////////
-// AeroTooltipManager, public:
-
-AeroTooltipManager::AeroTooltipManager(Widget* widget)
- : TooltipManagerWin(widget),
- initial_delay_(0) {
-}
-
-AeroTooltipManager::~AeroTooltipManager() {
- if (initial_timer_)
- initial_timer_->Disown();
-}
-
-void AeroTooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
- if (u_msg == WM_MOUSELEAVE) {
- last_mouse_pos_.SetPoint(-1, -1);
- UpdateTooltip();
- return;
- }
-
- if (initial_timer_)
- initial_timer_->Disown();
-
- if (u_msg == WM_MOUSEMOVE || u_msg == WM_NCMOUSEMOVE) {
- gfx::Point mouse_pos_in_pixels(l_param);
- gfx::Point mouse_pos = gfx::win::ScreenToDIPPoint(mouse_pos_in_pixels);
- if (u_msg == WM_NCMOUSEMOVE) {
- // NC message coordinates are in screen coordinates.
- POINT temp = mouse_pos_in_pixels.ToPOINT();
- ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1);
- mouse_pos_in_pixels.SetPoint(temp.x, temp.y);
- mouse_pos = gfx::win::ScreenToDIPPoint(mouse_pos_in_pixels);
- }
- if (last_mouse_pos_ != mouse_pos) {
- last_mouse_pos_ = mouse_pos;
- UpdateTooltip(mouse_pos);
- }
-
- // Delay opening of the tooltip just in case the user moves their
- // mouse to another control. We defer this from Init because we get
- // zero if we query it too soon.
- if (!initial_delay_) {
- initial_delay_ = static_cast<int>(
- ::SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_INITIAL, 0));
- }
- initial_timer_ = new InitialTimer(this);
- initial_timer_->Start(initial_delay_);
- } else {
- // Hide the tooltip and cancel any timers.
- ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, false, (LPARAM)&toolinfo_);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// AeroTooltipManager, private:
-
-void AeroTooltipManager::OnTimer() {
- initial_timer_ = NULL;
-
- POINT pt = last_mouse_pos_.ToPOINT();
- ::ClientToScreen(GetParent(), &pt);
-
- // Set the position and visibility.
- if (!tooltip_showing_) {
- ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
- ::SendMessage(tooltip_hwnd_, TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));
- ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, true, (LPARAM)&toolinfo_);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// AeroTooltipManager::InitialTimer
-
-AeroTooltipManager::InitialTimer::InitialTimer(AeroTooltipManager* manager)
- : manager_(manager) {
-}
-
-void AeroTooltipManager::InitialTimer::Start(int time) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&InitialTimer::Execute, this),
- base::TimeDelta::FromMilliseconds(time));
-}
-
-void AeroTooltipManager::InitialTimer::Disown() {
- manager_ = NULL;
-}
-
-void AeroTooltipManager::InitialTimer::Execute() {
- if (manager_)
- manager_->OnTimer();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/aero_tooltip_manager.h b/chromium/ui/views/widget/aero_tooltip_manager.h
deleted file mode 100644
index 0f9db20faa4..00000000000
--- a/chromium/ui/views/widget/aero_tooltip_manager.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
-#define UI_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
-
-#include "base/memory/ref_counted.h"
-#include "ui/views/widget/tooltip_manager_win.h"
-
-namespace views {
-
-///////////////////////////////////////////////////////////////////////////////
-// AeroTooltipManager
-//
-// Default Windows tooltips are broken when using our custom window frame
-// - as soon as the tooltip receives a WM_MOUSEMOVE event, it starts spewing
-// NCHITTEST messages at its parent window (us). These messages have random
-// x/y coordinates and can't be ignored, as the DwmDefWindowProc uses
-// NCHITTEST messages to determine how to highlight the caption buttons
-// (the buttons then flicker as the hit tests sent by the user's mouse
-// trigger different effects to those sent by the tooltip).
-//
-// So instead, we have to partially implement tooltips ourselves using
-// TTF_TRACKed tooltips.
-//
-// TODO(glen): Resolve this with Microsoft.
-class AeroTooltipManager : public TooltipManagerWin {
- public:
- explicit AeroTooltipManager(Widget* widget);
- virtual ~AeroTooltipManager();
-
- virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
-
- private:
- void OnTimer();
-
- class InitialTimer : public base::RefCounted<InitialTimer> {
- public:
- explicit InitialTimer(AeroTooltipManager* manager);
- void Start(int time);
- void Disown();
- void Execute();
-
- private:
- friend class base::RefCounted<InitialTimer>;
-
- ~InitialTimer() {}
-
- AeroTooltipManager* manager_;
- };
-
- int initial_delay_;
- scoped_refptr<InitialTimer> initial_timer_;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
diff --git a/chromium/ui/views/widget/child_window_message_processor.cc b/chromium/ui/views/widget/child_window_message_processor.cc
deleted file mode 100644
index dc497560093..00000000000
--- a/chromium/ui/views/widget/child_window_message_processor.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/child_window_message_processor.h"
-
-#include "base/logging.h"
-#include "ui/base/view_prop.h"
-
-namespace views {
-
-static const char* const kChildWindowKey = "__CHILD_WINDOW_MESSAGE_PROCESSOR__";
-
-// static
-ui::ViewProp* ChildWindowMessageProcessor::Register(
- HWND hwnd,
- ChildWindowMessageProcessor* processor) {
- DCHECK(processor);
- return new ui::ViewProp(hwnd, kChildWindowKey, processor);
-}
-
-// static
-ChildWindowMessageProcessor* ChildWindowMessageProcessor::Get(HWND hwnd) {
- return reinterpret_cast<ChildWindowMessageProcessor*>(
- ui::ViewProp::GetValue(hwnd, kChildWindowKey));
-}
-
-} // namespace
diff --git a/chromium/ui/views/widget/child_window_message_processor.h b/chromium/ui/views/widget/child_window_message_processor.h
deleted file mode 100644
index 112d9d835d4..00000000000
--- a/chromium/ui/views/widget/child_window_message_processor.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
-#define UI_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
-
-#include <windows.h>
-
-namespace ui {
-class ViewProp;
-}
-
-namespace views {
-
-// Windows sends a handful of messages to the parent window rather than the
-// window itself. For example, selection changes of a rich edit (EN_SELCHANGE)
-// are sent to the parent, not the window. Typically such message are best
-// dealt with by the window rather than the parent. NativeWidgetWin allows for
-// registering a ChildWindowMessageProcessor to handle such messages.
-class ChildWindowMessageProcessor {
- public:
- // Registers |processor| for |hwnd|. The caller takes ownership of the
- // returned object.
- static ui::ViewProp* Register(HWND hwnd,
- ChildWindowMessageProcessor* processor);
-
- // Returns the ChildWindowMessageProcessor for |hwnd|, NULL if there isn't
- // one.
- static ChildWindowMessageProcessor* Get(HWND hwnd);
-
- // Invoked for any messages that are sent to the parent and originated from
- // the HWND this ChildWindowMessageProcessor was registered for. Returns true
- // if the message was handled with a valid result in |result|. Returns false
- // if the message was not handled.
- virtual bool ProcessMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) = 0;
-
- protected:
- virtual ~ChildWindowMessageProcessor() {}
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_CHILD_WINDOW_MESSAGE_PROCESSOR_H_
diff --git a/chromium/ui/views/widget/desktop_aura/OWNERS b/chromium/ui/views/widget/desktop_aura/OWNERS
index 89630b157dd..c216dcda9de 100644
--- a/chromium/ui/views/widget/desktop_aura/OWNERS
+++ b/chromium/ui/views/widget/desktop_aura/OWNERS
@@ -1,5 +1,2 @@
# Elliot is the owner of all the X11 stuff.
-per-file *x11.cc=erg@chromium.org
-per-file *x11.h=erg@chromium.org
-per-file x11*=erg@chromium.org
-per-file x11*=erg@chromium.org
+per-file *x11*=erg@chromium.org
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
index 33054fe006d..fe9090d24a2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -4,8 +4,9 @@
#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
namespace views {
@@ -52,7 +53,7 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
capture_window_ = new_capture_window;
- aura::client::CaptureDelegate* delegate = root_->GetDispatcher();
+ aura::client::CaptureDelegate* delegate = root_->GetHost()->dispatcher();
delegate->UpdateCapture(old_capture_window, new_capture_window);
// Initiate native capture updating.
@@ -67,7 +68,8 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
for (CaptureClients::iterator i = capture_clients.begin();
i != capture_clients.end(); ++i) {
if (*i != this) {
- aura::client::CaptureDelegate* delegate = (*i)->root_->GetDispatcher();
+ aura::client::CaptureDelegate* delegate =
+ (*i)->root_->GetHost()->dispatcher();
delegate->OnOtherRootGotCapture();
}
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
index 599b625b26f..ff116bc81a0 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
@@ -33,7 +33,7 @@ class VIEWS_EXPORT DesktopCursorLoaderUpdater {
static scoped_ptr<DesktopCursorLoaderUpdater> Create();
// Called when a CursorLoader is created.
- virtual void OnCreate(aura::RootWindow* window,
+ virtual void OnCreate(float device_scale_factor,
ui::CursorLoader* loader) = 0;
// Called when the display has changed (as we may need to reload the cursor
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
index 80d99d1094b..63290b31343 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/cursor/cursor_loader.h"
#include "ui/base/cursor/cursors_aura.h"
#include "ui/gfx/display.h"
@@ -53,9 +53,9 @@ DesktopCursorLoaderUpdaterAuraLinux::DesktopCursorLoaderUpdaterAuraLinux() {}
DesktopCursorLoaderUpdaterAuraLinux::~DesktopCursorLoaderUpdaterAuraLinux() {}
void DesktopCursorLoaderUpdaterAuraLinux::OnCreate(
- aura::RootWindow* window,
+ float device_scale_factor,
ui::CursorLoader* loader) {
- LoadImageCursors(window->compositor()->device_scale_factor(), loader);
+ LoadImageCursors(device_scale_factor, loader);
}
void DesktopCursorLoaderUpdaterAuraLinux::OnDisplayUpdated(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
index 02db2b2773e..c367518ca08 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
@@ -17,7 +17,7 @@ class DesktopCursorLoaderUpdaterAuraLinux : public DesktopCursorLoaderUpdater {
virtual ~DesktopCursorLoaderUpdaterAuraLinux();
// Overridden from DesktopCursorLoaderUpdater:
- virtual void OnCreate(aura::RootWindow* window,
+ virtual void OnCreate(float device_scale_factor,
ui::CursorLoader* loader) OVERRIDE;
virtual void OnDisplayUpdated(const gfx::Display& display,
ui::CursorLoader* loader) OVERRIDE;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc
index bd4ba0229aa..4b8ca2db08d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.cc
@@ -4,31 +4,30 @@
#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+#include "base/auto_reset.h"
+#include "base/bind.h"
#include "base/run_loop.h"
namespace views {
-DesktopDispatcherClient::DesktopDispatcherClient() {}
-
-DesktopDispatcherClient::~DesktopDispatcherClient() {}
+DesktopDispatcherClient::DesktopDispatcherClient() {
+}
-void DesktopDispatcherClient::RunWithDispatcher(
- base::MessageLoop::Dispatcher* nested_dispatcher,
- aura::Window* associated_window,
- bool nestable_tasks_allowed) {
- // TODO(erg): This class has been copypastad from
- // ash/accelerators/nested_dispatcher_controller.cc. I have left my changes
- // commented out because I don't entirely understand the implications of the
- // change.
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
- bool did_allow_task_nesting = loop->NestableTasksAllowed();
- loop->SetNestableTasksAllowed(nestable_tasks_allowed);
+DesktopDispatcherClient::~DesktopDispatcherClient() {
+}
- // DefaultAcceleratorDispatcher dispatcher(nested_dispatcher,
- // associated_window);
- base::RunLoop run_loop(nested_dispatcher);
- run_loop.Run();
- loop->SetNestableTasksAllowed(did_allow_task_nesting);
+void DesktopDispatcherClient::PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) {
+#if defined(OS_WIN)
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop(dispatcher));
+#else
+ scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
+#endif
+ *quit_closure = run_loop->QuitClosure();
+ *run_closure =
+ base::Bind(&base::RunLoop::Run, base::Owned(run_loop.release()));
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h
index 5e7a517cc71..284e81cacda 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_dispatcher_client.h
@@ -6,8 +6,9 @@
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DISPATCHER_CLIENT_H_
#include "base/basictypes.h"
-#include "ui/aura/client/dispatcher_client.h"
+#include "base/callback.h"
#include "ui/views/views_export.h"
+#include "ui/wm/public/dispatcher_client.h"
namespace views {
@@ -18,9 +19,10 @@ class VIEWS_EXPORT DesktopDispatcherClient
DesktopDispatcherClient();
virtual ~DesktopDispatcherClient();
- virtual void RunWithDispatcher(base::MessageLoop::Dispatcher* dispatcher,
- aura::Window* associated_window,
- bool nestable_tasks_allowed) OVERRIDE;
+ virtual void PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DesktopDispatcherClient);
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 59e46f93245..d8a76e66559 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
@@ -9,18 +9,20 @@
#include "base/event_types.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/client/drag_drop_delegate.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_source.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
+#include "ui/wm/public/drag_drop_client.h"
+#include "ui/wm/public/drag_drop_delegate.h"
using aura::client::DragDropDelegate;
using ui::OSExchangeData;
@@ -35,19 +37,23 @@ const int kWantFurtherPosEvents = 2;
const char kXdndActionCopy[] = "XdndActionCopy";
const char kXdndActionMove[] = "XdndActionMove";
const char kXdndActionLink[] = "XdndActionLink";
+const char kXdndActionDirectSave[] = "XdndActionDirectSave";
const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER";
const char kXdndSelection[] = "XdndSelection";
+const char kXdndDirectSave0[] = "XdndDirectSave0";
const char* kAtomsToCache[] = {
kChromiumDragReciever,
"XdndActionAsk",
kXdndActionCopy,
+ kXdndActionDirectSave,
kXdndActionLink,
"XdndActionList",
kXdndActionMove,
"XdndActionPrivate",
"XdndAware",
+ kXdndDirectSave0,
"XdndDrop",
"XdndEnter",
"XdndFinished",
@@ -57,88 +63,32 @@ const char* kAtomsToCache[] = {
kXdndSelection,
"XdndStatus",
"XdndTypeList",
+ ui::Clipboard::kMimeTypeText,
NULL
};
+// The time to wait for the target to respond after the user has released the
+// mouse button before ending the move loop.
+const int kEndMoveLoopTimeoutMs = 1000;
+
+// The time to wait since sending the last XdndPosition message before
+// reprocessing the most recent mouse move event in case that the window
+// stacking order has changed and |source_current_window_| needs to be updated.
+const int kRepeatMouseMoveTimeoutMs = 350;
+
static base::LazyInstance<
std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
g_live_client_map = LAZY_INSTANCE_INITIALIZER;
-// Helper class to FindWindowFor which looks for a drag target under the
-// cursor.
-class DragTargetWindowFinder : public ui::EnumerateWindowsDelegate {
- public:
- DragTargetWindowFinder(XID ignored_icon_window,
- gfx::Point screen_loc)
- : ignored_icon_window_(ignored_icon_window),
- output_window_(None),
- screen_loc_(screen_loc) {
- ui::EnumerateTopLevelWindows(this);
- }
-
- virtual ~DragTargetWindowFinder() {}
-
- XID window() const { return output_window_; }
-
- protected:
- virtual bool ShouldStopIterating(XID window) OVERRIDE {
- if (window == ignored_icon_window_)
- return false;
-
- if (!ui::IsWindowVisible(window))
- return false;
-
- if (!ui::WindowContainsPoint(window, screen_loc_))
- return false;
-
- if (ui::PropertyExists(window, "WM_STATE")) {
- output_window_ = window;
- return true;
- }
-
- return false;
- }
-
- private:
- XID ignored_icon_window_;
- XID output_window_;
- gfx::Point screen_loc_;
-
- DISALLOW_COPY_AND_ASSIGN(DragTargetWindowFinder);
-};
-
-// Returns the topmost X11 window at |screen_point| if it is advertising that
-// is supports the Xdnd protocol. Will return the window under the pointer as
-// |mouse_window|. If there's a Xdnd aware window, it will be returned in
-// |dest_window|.
-void FindWindowFor(const gfx::Point& screen_point,
- ::Window* mouse_window, ::Window* dest_window) {
- DragTargetWindowFinder finder(None, screen_point);
- *mouse_window = finder.window();
- *dest_window = None;
-
- if (finder.window() == None)
- return;
-
- // Figure out which window we should test as XdndAware. If mouse_window has
- // XdndProxy, it will set that proxy on target, and if not, |target|'s
- // original value will remain.
- XID target = *mouse_window;
- ui::GetXIDProperty(*mouse_window, "XdndProxy", &target);
-
- int version;
- if (ui::GetIntProperty(target, "XdndAware", &version) &&
- version >= kMinXdndVersion) {
- *dest_window = target;
- }
-}
-
} // namespace
namespace views {
-class DesktopDragDropClientAuraX11::X11DragContext :
- public base::MessageLoop::Dispatcher {
+DesktopDragDropClientAuraX11*
+DesktopDragDropClientAuraX11::g_current_drag_drop_client = NULL;
+
+class DesktopDragDropClientAuraX11::X11DragContext
+ : public ui::PlatformEventDispatcher {
public:
X11DragContext(ui::X11AtomCache* atom_cache,
::Window local_window,
@@ -150,6 +100,7 @@ class DesktopDragDropClientAuraX11::X11DragContext :
// message. If we have that data already, dispatch immediately. Otherwise,
// delay dispatching until we do.
void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client,
+ ::Atom suggested_action,
::Window source_window,
const gfx::Point& screen_point);
@@ -173,8 +124,13 @@ class DesktopDragDropClientAuraX11::X11DragContext :
int GetDragOperation() const;
private:
- // Overridden from MessageLoop::Dispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // Masks the X11 atom |xdnd_operation|'s views representation onto
+ // |drag_operation|.
+ void MaskOpeartion(::Atom xdnd_operation, int* drag_operation) const;
+
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
// The atom cache owned by our parent.
ui::X11AtomCache* atom_cache_;
@@ -202,6 +158,10 @@ class DesktopDragDropClientAuraX11::X11DragContext :
// haven't fetched and put in |fetched_targets_| yet.
std::vector<Atom> unfetched_targets_;
+ // XdndPosition messages have a suggested action. Qt applications exclusively
+ // use this, instead of the XdndActionList which is backed by |actions_|.
+ Atom suggested_action_;
+
// Possible actions.
std::vector<Atom> actions_;
@@ -216,7 +176,8 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
local_window_(local_window),
source_window_(event.data.l[0]),
drag_drop_client_(NULL),
- waiting_to_handle_position_(false) {
+ waiting_to_handle_position_(false),
+ suggested_action_(None) {
bool get_types = ((event.data.l[1] & 1) != 0);
if (get_types) {
@@ -239,8 +200,7 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
if (!client) {
// The window doesn't have a DesktopDragDropClientAuraX11, that means it's
// created by some other process. Listen for messages on it.
- base::MessagePumpX11::Current()->AddDispatcherForWindow(
- this, source_window_);
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
XSelectInput(gfx::GetXDisplay(), source_window_, PropertyChangeMask);
// We must perform a full sync here because we could be racing
@@ -258,20 +218,17 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
}
DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() {
- DesktopDragDropClientAuraX11* client =
- DesktopDragDropClientAuraX11::GetForWindow(source_window_);
- if (!client) {
- // Unsubscribe from message events.
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
- source_window_);
- }
+ // Unsubscribe from message events.
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
DesktopDragDropClientAuraX11* client,
+ ::Atom suggested_action,
::Window source_window,
const gfx::Point& screen_point) {
DCHECK_EQ(source_window_, source_window);
+ suggested_action_ = suggested_action;
if (!unfetched_targets_.empty()) {
// We have unfetched targets. That means we need to pause the handling of
@@ -301,7 +258,11 @@ void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
const XSelectionEvent& event) {
- DCHECK(waiting_to_handle_position_);
+ if (!waiting_to_handle_position_) {
+ // A misbehaved window may send SelectionNotify without us requesting data
+ // via XConvertSelection().
+ return;
+ }
DCHECK(drag_drop_client_);
DCHECK_EQ(event.property, atom_cache_->GetAtom(kChromiumDragReciever));
@@ -345,24 +306,38 @@ int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
for (std::vector<Atom>::const_iterator it = actions_.begin();
it != actions_.end(); ++it) {
- if (*it == atom_cache_->GetAtom(kXdndActionCopy))
- drag_operation |= ui::DragDropTypes::DRAG_COPY;
- else if (*it == atom_cache_->GetAtom(kXdndActionMove))
- drag_operation |= ui::DragDropTypes::DRAG_MOVE;
- else if (*it == atom_cache_->GetAtom(kXdndActionLink))
- drag_operation |= ui::DragDropTypes::DRAG_LINK;
+ MaskOpeartion(*it, &drag_operation);
}
+ MaskOpeartion(suggested_action_, &drag_operation);
+
return drag_operation;
}
-bool DesktopDragDropClientAuraX11::X11DragContext::Dispatch(
- const base::NativeEvent& event) {
+void DesktopDragDropClientAuraX11::X11DragContext::MaskOpeartion(
+ ::Atom xdnd_operation,
+ int* drag_operation) const {
+ if (xdnd_operation == atom_cache_->GetAtom(kXdndActionCopy))
+ *drag_operation |= ui::DragDropTypes::DRAG_COPY;
+ else if (xdnd_operation == atom_cache_->GetAtom(kXdndActionMove))
+ *drag_operation |= ui::DragDropTypes::DRAG_MOVE;
+ else if (xdnd_operation == atom_cache_->GetAtom(kXdndActionLink))
+ *drag_operation |= ui::DragDropTypes::DRAG_LINK;
+}
+
+bool DesktopDragDropClientAuraX11::X11DragContext::CanDispatchEvent(
+ const ui::PlatformEvent& event) {
+ return event->xany.window == source_window_;
+}
+
+uint32_t DesktopDragDropClientAuraX11::X11DragContext::DispatchEvent(
+ const ui::PlatformEvent& event) {
if (event->type == PropertyNotify &&
event->xproperty.atom == atom_cache_->GetAtom("XdndActionList")) {
ReadActions();
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
}
- return true;
+ return ui::POST_DISPATCH_NONE;
}
///////////////////////////////////////////////////////////////////////////////
@@ -378,17 +353,20 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
xwindow_(xwindow),
atom_cache_(xdisplay_, kAtomsToCache),
target_window_(NULL),
+ waiting_on_status_(false),
+ status_received_since_enter_(false),
source_provider_(NULL),
source_current_window_(None),
- drag_drop_in_progress_(false),
+ source_state_(SOURCE_STATE_OTHER),
drag_operation_(0),
- resulting_operation_(0),
+ negotiated_operation_(ui::DragDropTypes::DRAG_NONE),
grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorGrabbing)),
copy_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorCopy)),
- move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)) {
- DCHECK(g_live_client_map.Get().find(xwindow) ==
- g_live_client_map.Get().end());
- g_live_client_map.Get().insert(std::make_pair(xwindow, this));
+ move_grab_cursor_(cursor_manager->GetInitializedCursor(ui::kCursorMove)),
+ weak_ptr_factory_(this) {
+ // Some tests change the DesktopDragDropClientAuraX11 associated with an
+ // |xwindow|.
+ g_live_client_map.Get()[xwindow] = this;
// Mark that we are aware of drag and drop concepts.
unsigned long xdnd_version = kMinXdndVersion;
@@ -399,6 +377,10 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() {
g_live_client_map.Get().erase(xwindow_);
+ // Make sure that all observers are unregistered from source and target
+ // windows. This may be necessary when the parent native widget gets destroyed
+ // while a drag operation is in progress.
+ NotifyDragLeave();
}
// static
@@ -446,6 +428,7 @@ void DesktopDragDropClientAuraX11::OnXdndPosition(
unsigned long source_window = event.data.l[0];
int x_root_window = event.data.l[2] >> 16;
int y_root_window = event.data.l[2] & 0xffff;
+ ::Atom suggested_action = event.data.l[4];
if (!target_current_context_.get()) {
NOTREACHED();
@@ -455,7 +438,8 @@ void DesktopDragDropClientAuraX11::OnXdndPosition(
// If we already have all the data from this drag, we complete it
// immediately.
target_current_context_->OnStartXdndPositionMessage(
- this, source_window, gfx::Point(x_root_window, y_root_window));
+ this, suggested_action, source_window,
+ gfx::Point(x_root_window, y_root_window));
}
void DesktopDragDropClientAuraX11::OnXdndStatus(
@@ -463,14 +447,37 @@ void DesktopDragDropClientAuraX11::OnXdndStatus(
DVLOG(1) << "XdndStatus";
unsigned long source_window = event.data.l[0];
- int drag_operation = ui::DragDropTypes::DRAG_NONE;
+
+ if (source_window != source_current_window_)
+ return;
+
+ if (source_state_ != SOURCE_STATE_PENDING_DROP &&
+ source_state_ != SOURCE_STATE_OTHER) {
+ return;
+ }
+
+ waiting_on_status_ = false;
+ status_received_since_enter_ = true;
+
if (event.data.l[1] & 1) {
::Atom atom_operation = event.data.l[4];
- negotiated_operation_[source_window] = atom_operation;
- drag_operation = AtomToDragOperation(atom_operation);
+ negotiated_operation_ = AtomToDragOperation(atom_operation);
+ } else {
+ negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;
+ }
+
+ if (source_state_ == SOURCE_STATE_PENDING_DROP) {
+ // We were waiting on the status message so we could send the XdndDrop.
+ if (negotiated_operation_ == ui::DragDropTypes::DRAG_NONE) {
+ move_loop_.EndMoveLoop();
+ return;
+ }
+ source_state_ = SOURCE_STATE_DROPPED;
+ SendXdndDrop(source_window);
+ return;
}
- switch (drag_operation) {
+ switch (negotiated_operation_) {
case ui::DragDropTypes::DRAG_COPY:
move_loop_.UpdateCursor(copy_grab_cursor_);
break;
@@ -488,31 +495,31 @@ void DesktopDragDropClientAuraX11::OnXdndStatus(
// the spec) the other side must handle further position messages within
// it. GTK+ doesn't bother with this, so neither should we.
- waiting_on_status_.erase(source_window);
-
- if (ContainsKey(pending_drop_, source_window)) {
- // We were waiting on the status message so we could send the XdndDrop.
- SendXdndDrop(source_window);
- return;
- }
-
- NextPositionMap::iterator it = next_position_message_.find(source_window);
- if (it != next_position_message_.end()) {
+ if (next_position_message_.get()) {
// We were waiting on the status message so we could send off the next
// position message we queued up.
- gfx::Point p = it->second.first;
- unsigned long time = it->second.second;
- next_position_message_.erase(it);
+ gfx::Point p = next_position_message_->first;
+ unsigned long event_time = next_position_message_->second;
+ next_position_message_.reset();
- SendXdndPosition(source_window, p, time);
+ SendXdndPosition(source_window, p, event_time);
}
}
void DesktopDragDropClientAuraX11::OnXdndFinished(
const XClientMessageEvent& event) {
DVLOG(1) << "XdndFinished";
- resulting_operation_ = AtomToDragOperation(
- negotiated_operation_[event.data.l[0]]);
+ unsigned long source_window = event.data.l[0];
+ if (source_current_window_ != source_window)
+ return;
+
+ // Clear |negotiated_operation_| if the drag was rejected.
+ if ((event.data.l[1] & 1) == 0)
+ negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;
+
+ // Clear |source_current_window_| to avoid sending XdndLeave upon ending the
+ // move loop.
+ source_current_window_ = None;
move_loop_.EndMoveLoop();
}
@@ -555,12 +562,12 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
void DesktopDragDropClientAuraX11::OnSelectionNotify(
const XSelectionEvent& xselection) {
- if (!target_current_context_) {
- NOTIMPLEMENTED();
- return;
- }
+ if (target_current_context_)
+ target_current_context_->OnSelectionNotify(xselection);
- target_current_context_->OnSelectionNotify(xselection);
+ // ICCCM requires us to delete the property passed into SelectionNotify.
+ if (xselection.property != None)
+ XDeleteProperty(xdisplay_, xwindow_, xselection.property);
}
int DesktopDragDropClientAuraX11::StartDragAndDrop(
@@ -571,9 +578,14 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
int operation,
ui::DragDropTypes::DragEventSource source) {
source_current_window_ = None;
- drag_drop_in_progress_ = true;
+ DCHECK(!g_current_drag_drop_client);
+ g_current_drag_drop_client = this;
+ waiting_on_status_ = false;
+ next_position_message_.reset();
+ status_received_since_enter_ = false;
+ source_state_ = SOURCE_STATE_OTHER;
drag_operation_ = operation;
- resulting_operation_ = ui::DragDropTypes::DRAG_NONE;
+ negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;
const ui::OSExchangeData::Provider* provider = &data.provider();
source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>(
@@ -582,22 +594,41 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
source_provider_->TakeOwnershipOfSelection();
std::vector< ::Atom> actions = GetOfferedDragOperations();
+ if (!source_provider_->file_contents_name().empty()) {
+ actions.push_back(atom_cache_.GetAtom(kXdndActionDirectSave));
+ ui::SetStringProperty(
+ xwindow_,
+ atom_cache_.GetAtom(kXdndDirectSave0),
+ atom_cache_.GetAtom(ui::Clipboard::kMimeTypeText),
+ source_provider_->file_contents_name().AsUTF8Unsafe());
+ }
ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
+ // It is possible for the DesktopWindowTreeHostX11 to be destroyed during the
+ // move loop, which would also destroy this drag-client. So keep track of
+ // whether it is alive after the drag ends.
+ base::WeakPtr<DesktopDragDropClientAuraX11> alive(
+ weak_ptr_factory_.GetWeakPtr());
+
// Windows has a specific method, DoDragDrop(), which performs the entire
// drag. We have to emulate this, so we spin off a nested runloop which will
// track all cursor movement and reroute events to a specific handler.
move_loop_.SetDragImage(source_provider_->GetDragImage(),
source_provider_->GetDragImageOffset());
move_loop_.RunMoveLoop(source_window, grab_cursor_);
- move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF());
- source_provider_ = NULL;
- drag_drop_in_progress_ = false;
- drag_operation_ = 0;
- XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
+ if (alive) {
+ move_loop_.SetDragImage(gfx::ImageSkia(), gfx::Vector2dF());
+
+ source_provider_ = NULL;
+ g_current_drag_drop_client = NULL;
+ drag_operation_ = 0;
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0));
- return resulting_operation_;
+ return negotiated_operation_;
+ }
+ return ui::DragDropTypes::DRAG_NONE;
}
void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target,
@@ -615,7 +646,7 @@ void DesktopDragDropClientAuraX11::DragCancel() {
}
bool DesktopDragDropClientAuraX11::IsDragDropInProgress() {
- return drag_drop_in_progress_;
+ return !!g_current_drag_drop_client;
}
void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
@@ -624,61 +655,170 @@ void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) {
}
void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) {
- gfx::Point screen_point(event->x_root, event->y_root);
-
- // Find the current window the cursor is over.
- ::Window mouse_window = None;
- ::Window dest_window = None;
- FindWindowFor(screen_point, &mouse_window, &dest_window);
-
- if (source_current_window_ != dest_window) {
- if (source_current_window_ != None)
- SendXdndLeave(source_current_window_);
+ repeat_mouse_move_timer_.Stop();
+ ProcessMouseMove(gfx::Point(event->x_root, event->y_root), event->time);
+}
- source_current_window_ = dest_window;
+void DesktopDragDropClientAuraX11::OnMouseReleased() {
+ repeat_mouse_move_timer_.Stop();
- if (source_current_window_ != None) {
- negotiated_operation_.erase(source_current_window_);
- SendXdndEnter(source_current_window_);
- }
+ if (source_state_ != SOURCE_STATE_OTHER) {
+ // The user has previously released the mouse and is clicking in
+ // frustration.
+ move_loop_.EndMoveLoop();
+ return;
}
if (source_current_window_ != None) {
- if (ContainsKey(waiting_on_status_, dest_window)) {
- next_position_message_[dest_window] =
- std::make_pair(screen_point, event->time);
- } else {
- SendXdndPosition(dest_window, screen_point, event->time);
- }
- }
-}
+ if (waiting_on_status_) {
+ if (status_received_since_enter_) {
+ // If we are waiting for an XdndStatus message, we need to wait for it
+ // to complete.
+ source_state_ = SOURCE_STATE_PENDING_DROP;
+
+ // Start timer to end the move loop if the target takes too long to send
+ // the XdndStatus and XdndFinished messages.
+ StartEndMoveLoopTimer();
+ return;
+ }
-void DesktopDragDropClientAuraX11::OnMouseReleased() {
- if (source_current_window_ != None) {
- if (ContainsKey(waiting_on_status_, source_current_window_)) {
- // If we are waiting for an XdndStatus message, we need to wait for it to
- // complete.
- pending_drop_.insert(source_current_window_);
+ move_loop_.EndMoveLoop();
return;
}
- std::map< ::Window, ::Atom>::iterator it =
- negotiated_operation_.find(source_current_window_);
- if (it != negotiated_operation_.end() && it->second != None) {
+ if (negotiated_operation_ != ui::DragDropTypes::DRAG_NONE) {
+ // Start timer to end the move loop if the target takes too long to send
+ // an XdndFinished message. It is important that StartEndMoveLoopTimer()
+ // is called before SendXdndDrop() because SendXdndDrop()
+ // sends XdndFinished synchronously if the drop target is a Chrome
+ // window.
+ StartEndMoveLoopTimer();
+
// We have negotiated an action with the other end.
+ source_state_ = SOURCE_STATE_DROPPED;
SendXdndDrop(source_current_window_);
return;
}
-
- SendXdndLeave(source_current_window_);
- source_current_window_ = None;
}
move_loop_.EndMoveLoop();
}
void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
+ if (source_current_window_ != None) {
+ SendXdndLeave(source_current_window_);
+ source_current_window_ = None;
+ }
target_current_context_.reset();
+ repeat_mouse_move_timer_.Stop();
+ end_move_loop_timer_.Stop();
+}
+
+XID DesktopDragDropClientAuraX11::FindWindowFor(
+ const gfx::Point& screen_point) {
+ views::X11TopmostWindowFinder finder;
+ ::Window target = finder.FindWindowAt(screen_point);
+
+ if (target == None)
+ return None;
+
+ // Figure out which window we should test as XdndAware. If |target| has
+ // XdndProxy, it will set that proxy on target, and if not, |target|'s
+ // original value will remain.
+ ui::GetXIDProperty(target, "XdndProxy", &target);
+
+ int version;
+ if (ui::GetIntProperty(target, "XdndAware", &version) &&
+ version >= kMinXdndVersion) {
+ return target;
+ }
+ return None;
+}
+
+void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
+ XEvent* xev) {
+ DCHECK_EQ(ClientMessage, xev->type);
+
+ // Don't send messages to the X11 message queue if we can help it.
+ DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid);
+ if (short_circuit) {
+ Atom message_type = xev->xclient.message_type;
+ if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ short_circuit->OnXdndEnter(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ short_circuit->OnXdndLeave(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ short_circuit->OnXdndPosition(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ short_circuit->OnXdndStatus(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ short_circuit->OnXdndFinished(xev->xclient);
+ return;
+ } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ short_circuit->OnXdndDrop(xev->xclient);
+ return;
+ }
+ }
+
+ // I don't understand why the GTK+ code is doing what it's doing here. It
+ // goes out of its way to send the XEvent so that it receives a callback on
+ // success or failure, and when it fails, it then sends an internal
+ // GdkEvent about the failed drag. (And sending this message doesn't appear
+ // to go through normal xlib machinery, but instead passes through the low
+ // level xProto (the x11 wire format) that I don't understand.
+ //
+ // I'm unsure if I have to jump through those hoops, or if XSendEvent is
+ // sufficient.
+ XSendEvent(xdisplay_, xid, False, 0, xev);
+}
+
+void DesktopDragDropClientAuraX11::ProcessMouseMove(
+ const gfx::Point& screen_point,
+ unsigned long event_time) {
+ if (source_state_ != SOURCE_STATE_OTHER)
+ return;
+
+ // Find the current window the cursor is over.
+ ::Window dest_window = FindWindowFor(screen_point);
+
+ if (source_current_window_ != dest_window) {
+ if (source_current_window_ != None)
+ SendXdndLeave(source_current_window_);
+
+ source_current_window_ = dest_window;
+ waiting_on_status_ = false;
+ next_position_message_.reset();
+ status_received_since_enter_ = false;
+ negotiated_operation_ = ui::DragDropTypes::DRAG_NONE;
+
+ if (source_current_window_ != None)
+ SendXdndEnter(source_current_window_);
+ }
+
+ if (source_current_window_ != None) {
+ if (waiting_on_status_) {
+ next_position_message_.reset(
+ new std::pair<gfx::Point, unsigned long>(screen_point, event_time));
+ } else {
+ SendXdndPosition(dest_window, screen_point, event_time);
+ }
+ }
+}
+
+void DesktopDragDropClientAuraX11::StartEndMoveLoopTimer() {
+ end_move_loop_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(
+ kEndMoveLoopTimeoutMs),
+ this,
+ &DesktopDragDropClientAuraX11::EndMoveLoop);
+}
+
+void DesktopDragDropClientAuraX11::EndMoveLoop() {
+ move_loop_.EndMoveLoop();
}
void DesktopDragDropClientAuraX11::DragTranslate(
@@ -687,8 +827,7 @@ void DesktopDragDropClientAuraX11::DragTranslate(
scoped_ptr<ui::DropTargetEvent>* event,
aura::client::DragDropDelegate** delegate) {
gfx::Point root_location = root_window_location;
- root_window_->GetDispatcher()->host()->ConvertPointFromNativeScreen(
- &root_location);
+ root_window_->GetHost()->ConvertPointFromNativeScreen(&root_location);
aura::Window* target_window =
root_window_->GetEventHandlerForPoint(root_location);
bool target_window_changed = false;
@@ -747,7 +886,8 @@ void DesktopDragDropClientAuraX11::NotifyDragLeave() {
return None;
}
-int DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) {
+ui::DragDropTypes::DragOperation
+DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) {
if (atom == atom_cache_.GetAtom(kXdndActionCopy))
return ui::DragDropTypes::DRAG_COPY;
if (atom == atom_cache_.GetAtom(kXdndActionMove))
@@ -834,12 +974,6 @@ void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
}
void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) {
- // If we're sending a leave message, don't wait for status messages anymore.
- waiting_on_status_.erase(dest_window);
- NextPositionMap::iterator it = next_position_message_.find(dest_window);
- if (it != next_position_message_.end())
- next_position_message_.erase(it);
-
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.message_type = atom_cache_.GetAtom("XdndLeave");
@@ -856,8 +990,8 @@ void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) {
void DesktopDragDropClientAuraX11::SendXdndPosition(
::Window dest_window,
const gfx::Point& screen_point,
- unsigned long time) {
- waiting_on_status_.insert(dest_window);
+ unsigned long event_time) {
+ waiting_on_status_ = true;
XEvent xev;
xev.xclient.type = ClientMessage;
@@ -867,9 +1001,20 @@ void DesktopDragDropClientAuraX11::SendXdndPosition(
xev.xclient.data.l[0] = xwindow_;
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y();
- xev.xclient.data.l[3] = time;
+ xev.xclient.data.l[3] = event_time;
xev.xclient.data.l[4] = DragOperationToAtom(drag_operation_);
SendXClientEvent(dest_window, &xev);
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html and
+ // the Xdnd protocol both recommend that drag events should be sent
+ // periodically.
+ repeat_mouse_move_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kRepeatMouseMoveTimeoutMs),
+ base::Bind(&DesktopDragDropClientAuraX11::ProcessMouseMove,
+ base::Unretained(this),
+ screen_point,
+ event_time));
}
void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
@@ -886,45 +1031,4 @@ void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
SendXClientEvent(dest_window, &xev);
}
-void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
- XEvent* xev) {
- DCHECK_EQ(ClientMessage, xev->type);
-
- // Don't send messages to the X11 message queue if we can help it.
- DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid);
- if (short_circuit) {
- Atom message_type = xev->xclient.message_type;
- if (message_type == atom_cache_.GetAtom("XdndEnter")) {
- short_circuit->OnXdndEnter(xev->xclient);
- return;
- } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
- short_circuit->OnXdndLeave(xev->xclient);
- return;
- } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
- short_circuit->OnXdndPosition(xev->xclient);
- return;
- } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
- short_circuit->OnXdndStatus(xev->xclient);
- return;
- } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
- short_circuit->OnXdndFinished(xev->xclient);
- return;
- } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
- short_circuit->OnXdndDrop(xev->xclient);
- return;
- }
- }
-
- // I don't understand why the GTK+ code is doing what it's doing here. It
- // goes out of its way to send the XEvent so that it receives a callback on
- // success or failure, and when it fails, it then sends an internal
- // GdkEvent about the failed drag. (And sending this message doesn't appear
- // to go through normal xlib machinery, but instead passes through the low
- // level xProto (the x11 wire format) that I don't understand.
- //
- // I'm unsure if I have to jump through those hoops, or if XSendEvent is
- // sufficient.
- XSendEvent(xdisplay_, xid, False, 0, xev);
-}
-
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index 8e8711e5fa3..30f3aa022e1 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -9,16 +9,18 @@
#include <X11/Xlib.h>
#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/drag_drop_client.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/gfx/point.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
+#include "ui/wm/public/drag_drop_client.h"
namespace aura {
namespace client {
@@ -42,7 +44,7 @@ namespace views {
class DesktopNativeCursorManager;
// Implements drag and drop on X11 for aura. On one side, this class takes raw
-// X11 events forwarded from DesktopRootWindowHostLinux, while on the other, it
+// X11 events forwarded from DesktopWindowTreeHostLinux, while on the other, it
// handles the views drag events.
class VIEWS_EXPORT DesktopDragDropClientAuraX11
: public aura::client::DragDropClient,
@@ -95,9 +97,43 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
virtual void OnMouseReleased() OVERRIDE;
virtual void OnMoveLoopEnded() OVERRIDE;
+ protected:
+ // The following methods are virtual for the sake of testing.
+
+ // Finds the topmost X11 window at |screen_point| and returns it if it is
+ // Xdnd aware. Returns NULL otherwise.
+ virtual ::Window FindWindowFor(const gfx::Point& screen_point);
+
+ // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
+ // server.
+ virtual void SendXClientEvent(::Window xid, XEvent* xev);
+
private:
- typedef std::map< ::Window, std::pair<gfx::Point, unsigned long> >
- NextPositionMap;
+ enum SourceState {
+ // |source_current_window_| will receive a drop once we receive an
+ // XdndStatus from it.
+ SOURCE_STATE_PENDING_DROP,
+
+ // The move looped will be ended once we receive XdndFinished from
+ // |source_current_window_|. We should not send XdndPosition to
+ // |source_current_window_| while in this state.
+ SOURCE_STATE_DROPPED,
+
+ // There is no drag in progress or there is a drag in progress and the
+ // user has not yet released the mouse.
+ SOURCE_STATE_OTHER,
+ };
+
+ // Processes a mouse move at |screen_point|.
+ void ProcessMouseMove(const gfx::Point& screen_point,
+ unsigned long event_time);
+
+ // Start timer to end the move loop if the target is too slow to respond after
+ // the mouse is released.
+ void StartEndMoveLoopTimer();
+
+ // Ends the move loop.
+ void EndMoveLoop();
// When we receive an position x11 message, we need to translate that into
// the underlying aura::Window representation, as moves internal to the X11
@@ -116,7 +152,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
::Atom DragOperationToAtom(int drag_operation);
// Converts a single action atom to a drag operation.
- int AtomToDragOperation(::Atom atom);
+ ui::DragDropTypes::DragOperation AtomToDragOperation(::Atom atom);
// During the blocking StartDragAndDrop() call, this converts the views-style
// |drag_operation_| bitfield into a vector of Atoms to offer to other
@@ -138,13 +174,9 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
void SendXdndLeave(::Window dest_window);
void SendXdndPosition(::Window dest_window,
const gfx::Point& screen_point,
- unsigned long time);
+ unsigned long event_time);
void SendXdndDrop(::Window dest_window);
- // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
- // server.
- void SendXClientEvent(::Window xid, XEvent* xev);
-
// A nested message loop that notifies this object of events through the
// X11WholeScreenMoveLoopDelegate interface.
X11WholeScreenMoveLoop move_loop_;
@@ -175,46 +207,53 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// In the Xdnd protocol, we aren't supposed to send another XdndPosition
// message until we have received a confirming XdndStatus message.
- std::set< ::Window> waiting_on_status_;
+ bool waiting_on_status_;
// If we would send an XdndPosition message while we're waiting for an
// XdndStatus response, we need to cache the latest details we'd send.
- NextPositionMap next_position_message_;
+ scoped_ptr<std::pair<gfx::Point, unsigned long> > next_position_message_;
+
+ // Reprocesses the most recent mouse move event if the mouse has not moved
+ // in a while in case the window stacking order has changed and
+ // |source_current_window_| needs to be updated.
+ base::OneShotTimer<DesktopDragDropClientAuraX11> repeat_mouse_move_timer_;
+
+ // When the mouse is released, we need to wait for the last XdndStatus message
+ // only if we have previously received a status message from
+ // |source_current_window_|.
+ bool status_received_since_enter_;
// Source side information.
ui::OSExchangeDataProviderAuraX11 const* source_provider_;
::Window source_current_window_;
+ SourceState source_state_;
- bool drag_drop_in_progress_;
+ // The current drag-drop client that has an active operation. Since we have
+ // multiple root windows and multiple DesktopDragDropClientAuraX11 instances
+ // it is important to maintain only one drag and drop operation at any time.
+ static DesktopDragDropClientAuraX11* g_current_drag_drop_client;
// The operation bitfield as requested by StartDragAndDrop.
int drag_operation_;
- // The operation performed. Is initialized to None at the start of
- // StartDragAndDrop(), and is set only during the asynchronous XdndFinished
- // message.
- int resulting_operation_;
-
- // This window will be receiving a drop as soon as we receive an XdndStatus
- // from it.
- std::set< ::Window> pending_drop_;
-
// We offer the other window a list of possible operations,
// XdndActionsList. This is the requested action from the other window. This
- // is None if we haven't sent out an XdndPosition message yet, haven't yet
- // received an XdndStatus or if the other window has told us that there's no
- // action that we can agree on.
- //
- // This is a map instead of a simple variable because of the case where we
- // put an XdndLeave in the queue at roughly the same time that the other
- // window responds to an XdndStatus.
- std::map< ::Window, ::Atom> negotiated_operation_;
+ // is DRAG_NONE if we haven't sent out an XdndPosition message yet, haven't
+ // yet received an XdndStatus or if the other window has told us that there's
+ // no action that we can agree on.
+ ui::DragDropTypes::DragOperation negotiated_operation_;
+
+ // Ends the move loop if the target is too slow to respond after the mouse is
+ // released.
+ base::OneShotTimer<DesktopDragDropClientAuraX11> end_move_loop_timer_;
// We use these cursors while dragging.
gfx::NativeCursor grab_cursor_;
gfx::NativeCursor copy_grab_cursor_;
gfx::NativeCursor move_grab_cursor_;
+ base::WeakPtrFactory<DesktopDragDropClientAuraX11> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
new file mode 100644
index 00000000000..4286d1873a5
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -0,0 +1,679 @@
+// 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 <map>
+#include <vector>
+
+// Include views_test_base.h first because the definition of None in X.h
+// conflicts with the definition of None in gtest-type-util.h
+#include "ui/views/test/views_test_base.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_types.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget.h"
+
+#include <X11/Xlib.h>
+
+namespace views {
+
+namespace {
+
+const char* kAtomsToCache[] = {
+ "XdndActionCopy",
+ "XdndDrop",
+ "XdndEnter",
+ "XdndFinished",
+ "XdndLeave",
+ "XdndPosition",
+ "XdndStatus",
+ "XdndTypeList",
+ NULL
+};
+
+class TestDragDropClient;
+
+// Collects messages which would otherwise be sent to |xid_| via
+// SendXClientEvent().
+class ClientMessageEventCollector {
+ public:
+ ClientMessageEventCollector(::Window xid, TestDragDropClient* client);
+ virtual ~ClientMessageEventCollector();
+
+ // Returns true if |events_| is non-empty.
+ bool HasEvents() const {
+ return !events_.empty();
+ }
+
+ // Pops all of |events_| and returns the popped events in the order that they
+ // were on the stack
+ std::vector<XClientMessageEvent> PopAllEvents();
+
+ // Adds |event| to the stack.
+ void RecordEvent(const XClientMessageEvent& event);
+
+ private:
+ ::Window xid_;
+
+ // Not owned.
+ TestDragDropClient* client_;
+
+ std::vector<XClientMessageEvent> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector);
+};
+
+// Implementation of DesktopDragDropClientAuraX11 which works with a fake
+// |DesktopDragDropClientAuraX11::source_current_window_|.
+class TestDragDropClient : public DesktopDragDropClientAuraX11 {
+ public:
+ // The location in screen coordinates used for the synthetic mouse moves
+ // generated in SetTopmostXWindowAndMoveMouse().
+ static const int kMouseMoveX;
+ static const int kMouseMoveY;
+
+ TestDragDropClient(aura::Window* window,
+ DesktopNativeCursorManager* cursor_manager);
+ virtual ~TestDragDropClient();
+
+ // Returns the XID of the window which initiated the drag.
+ ::Window source_xwindow() {
+ return source_xid_;
+ }
+
+ // Returns the Atom with |name|.
+ Atom GetAtom(const char* name);
+
+ // Returns true if the event's message has |type|.
+ bool MessageHasType(const XClientMessageEvent& event,
+ const char* type);
+
+ // Sets |collector| to collect XClientMessageEvents which would otherwise
+ // have been sent to the drop target window.
+ void SetEventCollectorFor(::Window xid,
+ ClientMessageEventCollector* collector);
+
+ // Builds an XdndStatus message and sends it to
+ // DesktopDragDropClientAuraX11.
+ void OnStatus(XID target_window,
+ bool will_accept_drop,
+ ::Atom accepted_action);
+
+ // Builds an XdndFinished message and sends it to
+ // DesktopDragDropClientAuraX11.
+ void OnFinished(XID target_window,
+ bool accepted_drop,
+ ::Atom performed_action);
+
+ // Sets |xid| as the topmost window at the current mouse position and
+ // generates a synthetic mouse move.
+ void SetTopmostXWindowAndMoveMouse(::Window xid);
+
+ // Returns true if the move loop is running.
+ bool IsMoveLoopRunning();
+
+ // DesktopDragDropClientAuraX11:
+ virtual int StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void OnMoveLoopEnded() OVERRIDE;
+
+ private:
+ // DesktopDragDropClientAuraX11:
+ virtual ::Window FindWindowFor(const gfx::Point& screen_point) OVERRIDE;
+ virtual void SendXClientEvent(::Window xid, XEvent* event) OVERRIDE;
+
+ // The XID of the window which initiated the drag.
+ ::Window source_xid_;
+
+ // The XID of the window which is simulated to be the topmost window at the
+ // current mouse position.
+ ::Window target_xid_;
+
+ // Whether the move loop is running.
+ bool move_loop_running_;
+
+ // Map of ::Windows to the collector which intercepts XClientMessageEvents
+ // for that window.
+ std::map< ::Window, ClientMessageEventCollector*> collectors_;
+
+ ui::X11AtomCache atom_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientMessageEventCollector
+
+ClientMessageEventCollector::ClientMessageEventCollector(
+ ::Window xid,
+ TestDragDropClient* client)
+ : xid_(xid),
+ client_(client) {
+ client->SetEventCollectorFor(xid, this);
+}
+
+ClientMessageEventCollector::~ClientMessageEventCollector() {
+ client_->SetEventCollectorFor(xid_, NULL);
+}
+
+std::vector<XClientMessageEvent> ClientMessageEventCollector::PopAllEvents() {
+ std::vector<XClientMessageEvent> to_return;
+ to_return.swap(events_);
+ return to_return;
+}
+
+void ClientMessageEventCollector::RecordEvent(
+ const XClientMessageEvent& event) {
+ events_.push_back(event);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TestDragDropClient
+
+// static
+const int TestDragDropClient::kMouseMoveX = 100;
+
+// static
+const int TestDragDropClient::kMouseMoveY = 200;
+
+TestDragDropClient::TestDragDropClient(
+ aura::Window* window,
+ DesktopNativeCursorManager* cursor_manager)
+ : DesktopDragDropClientAuraX11(window,
+ cursor_manager,
+ gfx::GetXDisplay(),
+ window->GetHost()->GetAcceleratedWidget()),
+ source_xid_(window->GetHost()->GetAcceleratedWidget()),
+ target_xid_(None),
+ move_loop_running_(false),
+ atom_cache_(gfx::GetXDisplay(), kAtomsToCache) {
+}
+
+TestDragDropClient::~TestDragDropClient() {
+}
+
+Atom TestDragDropClient::GetAtom(const char* name) {
+ return atom_cache_.GetAtom(name);
+}
+
+bool TestDragDropClient::MessageHasType(const XClientMessageEvent& event,
+ const char* type) {
+ return event.message_type == atom_cache_.GetAtom(type);
+}
+
+void TestDragDropClient::SetEventCollectorFor(
+ ::Window xid,
+ ClientMessageEventCollector* collector) {
+ if (collector)
+ collectors_[xid] = collector;
+ else
+ collectors_.erase(xid);
+}
+
+void TestDragDropClient::OnStatus(XID target_window,
+ bool will_accept_drop,
+ ::Atom accepted_action) {
+ XClientMessageEvent event;
+ event.message_type = atom_cache_.GetAtom("XdndStatus");
+ event.format = 32;
+ event.window = source_xid_;
+ event.data.l[0] = target_window;
+ event.data.l[1] = will_accept_drop ? 1 : 0;
+ event.data.l[2] = 0;
+ event.data.l[3] = 0;
+ event.data.l[4] = accepted_action;
+ OnXdndStatus(event);
+}
+
+void TestDragDropClient::OnFinished(XID target_window,
+ bool accepted_drop,
+ ::Atom performed_action) {
+ XClientMessageEvent event;
+ event.message_type = atom_cache_.GetAtom("XdndFinished");
+ event.format = 32;
+ event.window = source_xid_;
+ event.data.l[0] = target_window;
+ event.data.l[1] = accepted_drop ? 1 : 0;
+ event.data.l[2] = performed_action;
+ event.data.l[3] = 0;
+ event.data.l[4] = 0;
+ OnXdndFinished(event);
+}
+
+void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
+ target_xid_ = xid;
+
+ XMotionEvent event;
+ event.time = CurrentTime;
+ event.x_root = kMouseMoveX;
+ event.y_root = kMouseMoveY;
+ OnMouseMovement(&event);
+}
+
+bool TestDragDropClient::IsMoveLoopRunning() {
+ return move_loop_running_;
+}
+
+int TestDragDropClient::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ move_loop_running_ = true;
+ return DesktopDragDropClientAuraX11::StartDragAndDrop(data, root_window,
+ source_window, root_location, operation, source);
+}
+
+void TestDragDropClient::OnMoveLoopEnded() {
+ DesktopDragDropClientAuraX11::OnMoveLoopEnded();
+ move_loop_running_ = false;
+}
+
+::Window TestDragDropClient::FindWindowFor(const gfx::Point& screen_point) {
+ return target_xid_;
+}
+
+void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
+ std::map< ::Window, ClientMessageEventCollector*>::iterator it =
+ collectors_.find(xid);
+ if (it != collectors_.end())
+ it->second->RecordEvent(event->xclient);
+}
+
+} // namespace
+
+class DesktopDragDropClientAuraX11Test : public ViewsTestBase {
+ public:
+ DesktopDragDropClientAuraX11Test() {
+ }
+
+ virtual ~DesktopDragDropClientAuraX11Test() {
+ }
+
+ int StartDragAndDrop() {
+ ui::OSExchangeData data;
+ data.SetString(base::ASCIIToUTF16("Test"));
+
+ return client_->StartDragAndDrop(
+ data,
+ widget_->GetNativeWindow()->GetRootWindow(),
+ widget_->GetNativeWindow(),
+ gfx::Point(),
+ ui::DragDropTypes::DRAG_COPY,
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+ }
+
+ // ViewsTestBase:
+ virtual void SetUp() OVERRIDE {
+ ViewsTestBase::SetUp();
+
+ // Create widget to initiate the drags.
+ widget_.reset(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(widget_.get());
+ params.bounds = gfx::Rect(100, 100);
+ widget_->Init(params);
+ widget_->Show();
+
+ cursor_manager_.reset(new DesktopNativeCursorManager(
+ DesktopCursorLoaderUpdater::Create()));
+
+ client_.reset(new TestDragDropClient(widget_->GetNativeWindow(),
+ cursor_manager_.get()));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ client_.reset();
+ cursor_manager_.reset();
+ widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ TestDragDropClient* client() {
+ return client_.get();
+ }
+
+ private:
+ scoped_ptr<TestDragDropClient> client_;
+ scoped_ptr<DesktopNativeCursorManager> cursor_manager_;
+
+ // The widget used to initiate drags.
+ scoped_ptr<Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test);
+};
+
+namespace {
+
+void BasicStep2(TestDragDropClient* client, XID toplevel) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ // XdndEnter should have been sent to |toplevel| before the XdndPosition
+ // message.
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<XID>(events[0].data.l[0]));
+ EXPECT_EQ(1, events[0].data.l[1] & 1);
+ std::vector<Atom> targets;
+ ui::GetAtomArrayProperty(client->source_xwindow(), "XdndTypeList", &targets);
+ EXPECT_FALSE(targets.empty());
+
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<XID>(events[0].data.l[0]));
+ const long kCoords =
+ TestDragDropClient::kMouseMoveX << 16 | TestDragDropClient::kMouseMoveY;
+ EXPECT_EQ(kCoords, events[1].data.l[2]);
+ EXPECT_EQ(client->GetAtom("XdndActionCopy"),
+ static_cast<Atom>(events[1].data.l[4]));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+
+ // Because there is no unprocessed XdndPosition, the drag drop client should
+ // send XdndDrop immediately after the mouse is released.
+ client->OnMouseReleased();
+
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+ EXPECT_EQ(client->source_xwindow(),
+ static_cast<XID>(events[0].data.l[0]));
+
+ // Send XdndFinished to indicate that the drag drop client can cleanup any
+ // data related to this drag. The move loop should end only after the
+ // XdndFinished message was received.
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+void BasicStep3(TestDragDropClient* client, XID toplevel) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ // We have not received an XdndStatus ack for the second XdndPosition message.
+ // Test that sending XdndDrop is delayed till the XdndStatus ack is received.
+ client->OnMouseReleased();
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+TEST_F(DesktopDragDropClientAuraX11Test, Basic) {
+ XID toplevel = 1;
+
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&BasicStep2,
+ client(),
+ toplevel));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+
+ // Do another drag and drop to test that the data is properly cleaned up as a
+ // result of the XdndFinished message.
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&BasicStep3,
+ client(),
+ toplevel));
+ result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void TargetDoesNotRespondStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ XID toplevel = 1;
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that we do not wait for the target to send XdndStatus if we have not
+// received any XdndStatus messages at all from the target. The Unity
+// DNDCollectionWindow is an example of an XdndAware target which does not
+// respond to XdndPosition messages at all.
+TEST_F(DesktopDragDropClientAuraX11Test, TargetDoesNotRespond) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&TargetDoesNotRespondStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+}
+
+namespace {
+
+void QueuePositionStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ XID toplevel = 1;
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->OnMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that XdndPosition messages are queued till the pending XdndPosition
+// message is acked via an XdndStatus message.
+TEST_F(DesktopDragDropClientAuraX11Test, QueuePosition) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&QueuePositionStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void TargetChangesStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ XID toplevel1 = 1;
+ ClientMessageEventCollector collector1(toplevel1, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel1);
+
+ std::vector<XClientMessageEvent> events1 = collector1.PopAllEvents();
+ ASSERT_EQ(2u, events1.size());
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events1[1], "XdndPosition"));
+
+ XID toplevel2 = 2;
+ ClientMessageEventCollector collector2(toplevel2, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel2);
+
+ // It is possible for |toplevel1| to send XdndStatus after the source has sent
+ // XdndLeave but before |toplevel1| has received the XdndLeave message. The
+ // XdndStatus message should be ignored.
+ client->OnStatus(toplevel1, true, client->GetAtom("XdndActionCopy"));
+ events1 = collector1.PopAllEvents();
+ ASSERT_EQ(1u, events1.size());
+ EXPECT_TRUE(client->MessageHasType(events1[0], "XdndLeave"));
+
+ std::vector<XClientMessageEvent> events2 = collector2.PopAllEvents();
+ ASSERT_EQ(2u, events2.size());
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events2[1], "XdndPosition"));
+
+ client->OnStatus(toplevel2, true, client->GetAtom("XdndActionCopy"));
+ client->OnMouseReleased();
+ events2 = collector2.PopAllEvents();
+ ASSERT_EQ(1u, events2.size());
+ EXPECT_TRUE(client->MessageHasType(events2[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel2, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test the behavior when the target changes during a drag.
+TEST_F(DesktopDragDropClientAuraX11Test, TargetChanges) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&TargetChangesStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+namespace {
+
+void RejectAfterMouseReleaseStep2(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ XID toplevel = 1;
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ // Send another mouse move such that there is a pending XdndPosition.
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndPosition"));
+
+ client->OnMouseReleased();
+ // Reject the drop.
+ client->OnStatus(toplevel, false, None);
+
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndLeave"));
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+void RejectAfterMouseReleaseStep3(TestDragDropClient* client) {
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+
+ XID toplevel = 2;
+ ClientMessageEventCollector collector(toplevel, client);
+ client->SetTopmostXWindowAndMoveMouse(toplevel);
+
+ std::vector<XClientMessageEvent> events = collector.PopAllEvents();
+ ASSERT_EQ(2u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndEnter"));
+ EXPECT_TRUE(client->MessageHasType(events[1], "XdndPosition"));
+
+ client->OnStatus(toplevel, true, client->GetAtom("XdndActionCopy"));
+ EXPECT_FALSE(collector.HasEvents());
+
+ client->OnMouseReleased();
+ events = collector.PopAllEvents();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(client->MessageHasType(events[0], "XdndDrop"));
+
+ EXPECT_TRUE(client->IsMoveLoopRunning());
+ client->OnFinished(toplevel, false, None);
+ EXPECT_FALSE(client->IsMoveLoopRunning());
+}
+
+} // namespace
+
+// Test that the source sends XdndLeave instead of XdndDrop if the drag
+// operation is rejected after the mouse is released.
+TEST_F(DesktopDragDropClientAuraX11Test, RejectAfterMouseRelease) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RejectAfterMouseReleaseStep2, client()));
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+
+ // Repeat the test but reject the drop in the XdndFinished message instead.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RejectAfterMouseReleaseStep3, client()));
+ result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, result);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
index 5669f31a1fb..26431c1159f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc
@@ -9,8 +9,7 @@
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
-#include "ui/views/widget/drop_target_win.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace views {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
index 042a5a8a3c3..a8051ca8693 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h
@@ -7,15 +7,14 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
-#include "ui/aura/client/drag_drop_client.h"
#include "ui/views/views_export.h"
+#include "ui/wm/public/drag_drop_client.h"
namespace ui {
class DragSourceWin;
}
namespace views {
-class DesktopDragDragSourceWin;
class DesktopDropTargetWin;
class VIEWS_EXPORT DesktopDragDropClientWin
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 57c81d58628..1369b62eb79 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
@@ -5,14 +5,14 @@
#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
#include "base/win/win_util.h"
-#include "ui/aura/client/drag_drop_client.h"
-#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#include "ui/events/event_constants.h"
+#include "ui/wm/public/drag_drop_client.h"
+#include "ui/wm/public/drag_drop_delegate.h"
using aura::client::DragDropDelegate;
using ui::OSExchangeData;
@@ -96,7 +96,7 @@ void DesktopDropTargetWin::Translate(
DragDropDelegate** delegate) {
gfx::Point location(position.x, position.y);
gfx::Point root_location = location;
- root_window_->GetDispatcher()->host()->ConvertPointFromNativeScreen(
+ root_window_->GetHost()->ConvertPointFromNativeScreen(
&root_location);
aura::Window* target_window =
root_window_->GetEventHandlerForPoint(root_location);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h
index 113fd75ce23..9e11ff68cf1 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h
@@ -23,7 +23,7 @@ class OSExchangeData;
namespace views {
// DesktopDropTargetWin takes care of managing drag and drop for
-// DesktopRootWindowHostWin. It converts Windows OLE drop messages into
+// DesktopWindowTreeHostWin. It converts Windows OLE drop messages into
// aura::client::DragDropDelegate calls.
class DesktopDropTargetWin : public ui::DropTargetWin,
public aura::WindowObserver {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h
index e557d3bdb7a..2af191b445f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h
@@ -9,11 +9,12 @@
namespace gfx {
class Rect;
+class Screen;
}
namespace views {
class DesktopNativeWidgetAura;
-class DesktopRootWindowHost;
+class DesktopWindowTreeHost;
namespace internal {
class NativeWidgetDelegate;
@@ -30,12 +31,16 @@ class VIEWS_EXPORT DesktopFactoryOzone {
// Sets the implementation delegate. Ownership is retained by the caller.
static void SetInstance(DesktopFactoryOzone* impl);
- // Delegates implementation of DesktopRootWindowHost::Create externally to
+ // Delegates implementation of DesktopWindowTreeHost::Create externally to
// Ozone implementation.
- virtual DesktopRootWindowHost* CreateRootWindowHost(
+ virtual DesktopWindowTreeHost* CreateWindowTreeHost(
internal::NativeWidgetDelegate* native_widget_delegate,
DesktopNativeWidgetAura* desktop_native_widget_aura) = 0;
+ // Delegates implementation of DesktopScreen externally to
+ // Ozone implementation.
+ virtual gfx::Screen* CreateDesktopScreen() = 0;
+
private:
static DesktopFactoryOzone* impl_; // not owned
};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
index 475facf10cf..1d7d40c5e3d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -4,8 +4,8 @@
#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
namespace views {
@@ -14,6 +14,14 @@ DesktopFocusRules::DesktopFocusRules(aura::Window* content_window)
DesktopFocusRules::~DesktopFocusRules() {}
+bool DesktopFocusRules::CanActivateWindow(aura::Window* window) const {
+ if (!BaseFocusRules::CanActivateWindow(window))
+ return false;
+ // Never activate a window that is not a child of the root window. Transients
+ // spanning different DesktopNativeWidgetAuras may trigger this.
+ return !window || content_window_->GetRootWindow()->Contains(window);
+}
+
bool DesktopFocusRules::SupportsChildActivation(aura::Window* window) const {
// In Desktop-Aura, only the content_window or children of the RootWindow are
// activatable.
@@ -32,7 +40,7 @@ bool DesktopFocusRules::IsWindowConsideredVisibleForActivation(
aura::Window* DesktopFocusRules::GetToplevelWindow(
aura::Window* window) const {
aura::Window* top_level_window =
- corewm::BaseFocusRules::GetToplevelWindow(window);
+ wm::BaseFocusRules::GetToplevelWindow(window);
// In Desktop-Aura, only the content_window or children of the RootWindow are
// considered as top level windows.
if (top_level_window == content_window_->parent())
@@ -43,7 +51,7 @@ aura::Window* DesktopFocusRules::GetToplevelWindow(
aura::Window* DesktopFocusRules::GetNextActivatableWindow(
aura::Window* window) const {
aura::Window* next_activatable_window =
- corewm::BaseFocusRules::GetNextActivatableWindow(window);
+ wm::BaseFocusRules::GetNextActivatableWindow(window);
// In Desktop-Aura the content_window_'s parent is a dummy window and thus
// should never be activated. We should return the content_window_ if it
// can be activated in this case.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
index fff8116b18e..e096e80998d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
@@ -5,17 +5,18 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_FOCUS_RULES_H_
#define UI_VIEWS_WIDGET_DESKTOP_FOCUS_RULES_H_
-#include "ui/views/corewm/base_focus_rules.h"
+#include "ui/wm/core/base_focus_rules.h"
namespace views {
-class DesktopFocusRules : public corewm::BaseFocusRules {
+class DesktopFocusRules : public wm::BaseFocusRules {
public:
explicit DesktopFocusRules(aura::Window* content_window);
virtual ~DesktopFocusRules();
private:
- // Overridden from corewm::BaseFocusRules:
+ // Overridden from wm::BaseFocusRules:
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE;
virtual bool IsWindowConsideredVisibleForActivation(
aura::Window* window) const OVERRIDE;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
new file mode 100644
index 00000000000..39eda7dcb47
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_layer_type.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/window_util.h"
+
+namespace views {
+
+namespace {
+
+scoped_ptr<Widget> CreateDesktopWidget() {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = Widget::InitParams(
+ Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(widget.get());
+ widget->Init(params);
+ return widget.Pass();
+}
+
+} // namespace
+
+typedef ViewsTestBase DesktopFocusRulesTest;
+
+// Verifies we don't attempt to activate a window in another widget.
+TEST_F(DesktopFocusRulesTest, DontFocusWindowsInOtherHierarchies) {
+ // Two widgets (each with a DesktopNativeWidgetAura). |w2| has a child Window
+ // |w2_child| that is not focusable. |w2_child|'s has a transient parent in
+ // |w1|.
+ scoped_ptr<views::Widget> w1(CreateDesktopWidget());
+ scoped_ptr<views::Widget> w2(CreateDesktopWidget());
+ aura::test::TestWindowDelegate w2_child_delegate;
+ w2_child_delegate.set_can_focus(false);
+ aura::Window* w2_child = new aura::Window(&w2_child_delegate);
+ w2_child->Init(aura::WINDOW_LAYER_SOLID_COLOR);
+ w2->GetNativeView()->AddChild(w2_child);
+ wm::AddTransientChild(w1->GetNativeView(), w2_child);
+ aura::client::GetFocusClient(w2->GetNativeView())->FocusWindow(w2_child);
+ aura::Window* focused =
+ aura::client::GetFocusClient(w2->GetNativeView())->GetFocusedWindow();
+ EXPECT_TRUE((focused == NULL) || w2->GetNativeView()->Contains(focused));
+ wm::RemoveTransientChild(w1->GetNativeView(), w2_child);
+ w1.reset();
+ w2.reset();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index 911f7753361..187aa6e612f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -4,20 +4,19 @@
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor_loader.h"
#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
namespace views {
DesktopNativeCursorManager::DesktopNativeCursorManager(
- aura::RootWindow* window,
scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater)
- : root_window_(window),
- cursor_loader_updater_(cursor_loader_updater.Pass()),
+ : cursor_loader_updater_(cursor_loader_updater.Pass()),
cursor_loader_(ui::CursorLoader::Create()) {
if (cursor_loader_updater_.get())
- cursor_loader_updater_->OnCreate(root_window_, cursor_loader_.get());
+ cursor_loader_updater_->OnCreate(1.0f, cursor_loader_.get());
}
DesktopNativeCursorManager::~DesktopNativeCursorManager() {
@@ -29,11 +28,20 @@ gfx::NativeCursor DesktopNativeCursorManager::GetInitializedCursor(int type) {
return cursor;
}
+void DesktopNativeCursorManager::AddHost(aura::WindowTreeHost* host) {
+ hosts_.insert(host);
+}
+
+void DesktopNativeCursorManager::RemoveHost(aura::WindowTreeHost* host) {
+ hosts_.erase(host);
+}
+
void DesktopNativeCursorManager::SetDisplay(
const gfx::Display& display,
- views::corewm::NativeCursorManagerDelegate* delegate) {
+ wm::NativeCursorManagerDelegate* delegate) {
cursor_loader_->UnloadAll();
- cursor_loader_->set_display(display);
+ cursor_loader_->set_rotation(display.rotation());
+ cursor_loader_->set_scale(display.device_scale_factor());
if (cursor_loader_updater_.get())
cursor_loader_updater_->OnDisplayUpdated(display, cursor_loader_.get());
@@ -43,18 +51,20 @@ void DesktopNativeCursorManager::SetDisplay(
void DesktopNativeCursorManager::SetCursor(
gfx::NativeCursor cursor,
- views::corewm::NativeCursorManagerDelegate* delegate) {
+ wm::NativeCursorManagerDelegate* delegate) {
gfx::NativeCursor new_cursor = cursor;
cursor_loader_->SetPlatformCursor(&new_cursor);
delegate->CommitCursor(new_cursor);
- if (delegate->IsCursorVisible())
- root_window_->SetCursor(new_cursor);
+ if (delegate->IsCursorVisible()) {
+ for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ (*i)->SetCursor(new_cursor);
+ }
}
void DesktopNativeCursorManager::SetVisibility(
bool visible,
- views::corewm::NativeCursorManagerDelegate* delegate) {
+ wm::NativeCursorManagerDelegate* delegate) {
delegate->CommitVisibility(visible);
if (visible) {
@@ -62,27 +72,23 @@ void DesktopNativeCursorManager::SetVisibility(
} else {
gfx::NativeCursor invisible_cursor(ui::kCursorNone);
cursor_loader_->SetPlatformCursor(&invisible_cursor);
- root_window_->SetCursor(invisible_cursor);
+ for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ (*i)->SetCursor(invisible_cursor);
}
- root_window_->OnCursorVisibilityChanged(visible);
+ for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ (*i)->OnCursorVisibilityChanged(visible);
}
void DesktopNativeCursorManager::SetCursorSet(
ui::CursorSetType cursor_set,
- views::corewm::NativeCursorManagerDelegate* delegate) {
- NOTIMPLEMENTED();
-}
-
-void DesktopNativeCursorManager::SetScale(
- float scale,
- views::corewm::NativeCursorManagerDelegate* delegate) {
+ wm::NativeCursorManagerDelegate* delegate) {
NOTIMPLEMENTED();
}
void DesktopNativeCursorManager::SetMouseEventsEnabled(
bool enabled,
- views::corewm::NativeCursorManagerDelegate* delegate) {
+ wm::NativeCursorManagerDelegate* delegate) {
delegate->CommitMouseEventsEnabled(enabled);
// TODO(erg): In the ash version, we set the last mouse location on Env. I'm
@@ -90,7 +96,8 @@ void DesktopNativeCursorManager::SetMouseEventsEnabled(
SetVisibility(delegate->IsCursorVisible(), delegate);
- root_window_->OnMouseEventsEnableStateChanged(enabled);
+ for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ (*i)->dispatcher()->OnMouseEventsEnableStateChanged(enabled);
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
index 563131d92cc..ee156348774 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -5,61 +5,69 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
+#include <set>
+
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/views/corewm/native_cursor_manager.h"
#include "ui/views/views_export.h"
+#include "ui/wm/core/native_cursor_manager.h"
namespace aura {
-class RootWindow;
+class WindowTreeHost;
}
namespace ui {
class CursorLoader;
}
-namespace views {
-class DesktopCursorLoaderUpdater;
-
-namespace corewm {
+namespace wm {
class NativeCursorManagerDelegate;
}
-// A NativeCursorManager that interacts with only one RootWindow. (Unlike the
-// one in ash, which interacts with all the RootWindows that ash knows about.)
+namespace views {
+class DesktopCursorLoaderUpdater;
+
+// A NativeCursorManager that performs the desktop-specific setting of cursor
+// state. Similar to AshNativeCursorManager, it also communicates these changes
+// to all root windows.
class VIEWS_EXPORT DesktopNativeCursorManager
- : public views::corewm::NativeCursorManager {
+ : public wm::NativeCursorManager {
public:
DesktopNativeCursorManager(
- aura::RootWindow* window,
scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater);
virtual ~DesktopNativeCursorManager();
// Builds a cursor and sets the internal platform representation.
gfx::NativeCursor GetInitializedCursor(int type);
+ // Adds |host| to the set |hosts_|.
+ void AddHost(aura::WindowTreeHost* host);
+
+ // Removes |host| from the set |hosts_|.
+ void RemoveHost(aura::WindowTreeHost* host);
+
private:
- // Overridden from views::corewm::NativeCursorManager:
+ // Overridden from wm::NativeCursorManager:
virtual void SetDisplay(
const gfx::Display& display,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE;
virtual void SetCursor(
gfx::NativeCursor cursor,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE;
virtual void SetVisibility(
bool visible,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE;
virtual void SetCursorSet(
ui::CursorSetType cursor_set,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
- virtual void SetScale(
- float scale,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE;
virtual void SetMouseEventsEnabled(
bool enabled,
- views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE;
+
+ // The set of hosts to notify of changes in cursor state.
+ typedef std::set<aura::WindowTreeHost*> Hosts;
+ Hosts hosts_;
- aura::RootWindow* root_window_;
scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater_;
scoped_ptr<ui::CursorLoader> cursor_loader_;
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 6ae83df66bb..e461fd9e7f2 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,18 +6,16 @@
#include "base/bind.h"
#include "base/debug/trace_event.h"
-#include "ui/aura/client/activation_client.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_property.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/display.h"
@@ -25,29 +23,20 @@
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
#include "ui/native_theme/native_theme.h"
-#include "ui/views/corewm/compound_event_filter.h"
-#include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/cursor_manager.h"
-#include "ui/views/corewm/focus_controller.h"
-#include "ui/views/corewm/input_method_event_filter.h"
-#include "ui/views/corewm/native_cursor_manager.h"
-#include "ui/views/corewm/shadow_controller.h"
-#include "ui/views/corewm/shadow_types.h"
#include "ui/views/corewm/tooltip.h"
#include "ui/views/corewm/tooltip_controller.h"
-#include "ui/views/corewm/visibility_controller.h"
-#include "ui/views/corewm/window_modality_controller.h"
#include "ui/views/drag_utils.h"
-#include "ui/views/ime/input_method.h"
#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/ime/null_input_method.h"
+#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
#include "ui/views/widget/desktop_aura/desktop_event_client.h"
#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/root_view.h"
@@ -56,8 +45,21 @@
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/window_reorderer.h"
+#include "ui/views/window/native_frame_view.h"
+#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/core/cursor_manager.h"
+#include "ui/wm/core/focus_controller.h"
+#include "ui/wm/core/input_method_event_filter.h"
+#include "ui/wm/core/native_cursor_manager.h"
+#include "ui/wm/core/shadow_controller.h"
+#include "ui/wm/core/shadow_types.h"
+#include "ui/wm/core/visibility_controller.h"
+#include "ui/wm/core/window_modality_controller.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/drag_drop_client.h"
#if defined(OS_WIN)
+#include "ui/base/win/shell.h"
#include "ui/gfx/win/dpi.h"
#endif
@@ -79,7 +81,8 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
// becomes the parent of the child window passed in.
static aura::Window* CreateParentWindow(aura::Window* child_window,
const gfx::Rect& bounds,
- bool full_screen) {
+ bool full_screen,
+ bool root_is_always_on_top) {
// This instance will get deleted when the widget is destroyed.
DesktopNativeWidgetTopLevelHandler* top_level_handler =
new DesktopNativeWidgetTopLevelHandler;
@@ -91,8 +94,12 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
Widget::InitParams::TYPE_POPUP;
init_params.bounds = bounds;
init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
- init_params.layer_type = ui::LAYER_NOT_DRAWN;
- init_params.can_activate = full_screen;
+ init_params.layer_type = aura::WINDOW_LAYER_NOT_DRAWN;
+ init_params.activatable = full_screen ?
+ Widget::InitParams::ACTIVATABLE_YES :
+ Widget::InitParams::ACTIVATABLE_NO;
+ init_params.keep_on_top = root_is_always_on_top;
+
// This widget instance will get deleted when the window is
// destroyed.
top_level_handler->top_level_widget_ = new Widget();
@@ -171,10 +178,17 @@ class DesktopNativeWidgetAuraWindowTreeClient :
const gfx::Rect& bounds) OVERRIDE {
bool is_fullscreen = window->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_FULLSCREEN;
- bool is_menu = window->type() == aura::client::WINDOW_TYPE_MENU;
+ bool is_menu = window->type() == ui::wm::WINDOW_TYPE_MENU;
+
if (is_fullscreen || is_menu) {
+ bool root_is_always_on_top = false;
+ internal::NativeWidgetPrivate* native_widget =
+ DesktopNativeWidgetAura::ForWindow(root_window_);
+ if (native_widget)
+ root_is_always_on_top = native_widget->IsAlwaysOnTop();
+
return DesktopNativeWidgetTopLevelHandler::CreateParentWindow(
- window, bounds, is_fullscreen);
+ window, bounds, is_fullscreen, root_is_always_on_top);
}
return root_window_;
}
@@ -207,15 +221,38 @@ class FocusManagerEventHandler : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(FocusManagerEventHandler);
};
+class RootWindowDestructionObserver : public aura::WindowObserver {
+ public:
+ explicit RootWindowDestructionObserver(DesktopNativeWidgetAura* parent)
+ : parent_(parent) {}
+ virtual ~RootWindowDestructionObserver() {}
+
+ private:
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ parent_->RootWindowDestroyed();
+ window->RemoveObserver(this);
+ delete this;
+ }
+
+ DesktopNativeWidgetAura* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowDestructionObserver);
+};
+
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, public:
+int DesktopNativeWidgetAura::cursor_reference_count_ = 0;
+DesktopNativeCursorManager* DesktopNativeWidgetAura::native_cursor_manager_ =
+ NULL;
+wm::CursorManager* DesktopNativeWidgetAura::cursor_manager_ = NULL;
+
DesktopNativeWidgetAura::DesktopNativeWidgetAura(
internal::NativeWidgetDelegate* delegate)
- : ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
+ : desktop_window_tree_host_(NULL),
+ ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
close_widget_factory_(this),
- can_activate_(true),
- desktop_root_window_host_(NULL),
content_window_container_(NULL),
content_window_(new aura::Window(this)),
native_widget_delegate_(delegate),
@@ -223,7 +260,6 @@ DesktopNativeWidgetAura::DesktopNativeWidgetAura(
restore_focus_on_activate_(false),
cursor_(gfx::kNullCursor),
widget_type_(Widget::InitParams::TYPE_WINDOW) {
- content_window_->SetProperty(kDesktopNativeWidgetAuraKey, this);
aura::client::SetFocusChangeObserver(content_window_, this);
aura::client::SetActivationChangeObserver(content_window_, this);
}
@@ -243,48 +279,50 @@ DesktopNativeWidgetAura* DesktopNativeWidgetAura::ForWindow(
void DesktopNativeWidgetAura::OnHostClosed() {
// Don't invoke Widget::OnNativeWidgetDestroying(), its done by
- // DesktopRootWindowHost.
+ // DesktopWindowTreeHost.
// The WindowModalityController is at the front of the event pretarget
// handler list. We destroy it first to preserve order symantics.
if (window_modality_controller_)
window_modality_controller_.reset();
- // Make sure we don't have capture. Otherwise CaptureController and RootWindow
- // are left referencing a deleted Window.
+ // Make sure we don't have capture. Otherwise CaptureController and
+ // WindowEventDispatcher are left referencing a deleted Window.
{
aura::Window* capture_window = capture_client_->GetCaptureWindow();
- if (capture_window && root_window_->window()->Contains(capture_window))
+ if (capture_window && host_->window()->Contains(capture_window))
capture_window->ReleaseCapture();
}
- // DesktopRootWindowHost owns the ActivationController which ShadowController
+ // DesktopWindowTreeHost owns the ActivationController which ShadowController
// references. Make sure we destroy ShadowController early on.
shadow_controller_.reset();
tooltip_manager_.reset();
- root_window_->window()->RemovePreTargetHandler(tooltip_controller_.get());
- aura::client::SetTooltipClient(root_window_->window(), NULL);
- tooltip_controller_.reset();
+ if (tooltip_controller_.get()) {
+ host_->window()->RemovePreTargetHandler(tooltip_controller_.get());
+ aura::client::SetTooltipClient(host_->window(), NULL);
+ tooltip_controller_.reset();
+ }
root_window_event_filter_->RemoveHandler(input_method_event_filter_.get());
- window_tree_client_.reset(); // Uses root_window_ at destruction.
+ window_tree_client_.reset(); // Uses host_->dispatcher() at destruction.
- capture_client_.reset(); // Uses root_window_ at destruction.
+ capture_client_.reset(); // Uses host_->dispatcher() at destruction.
// FocusController uses |content_window_|. Destroy it now so that we don't
// have to worry about the possibility of FocusController attempting to use
// |content_window_| after it's been destroyed but before all child windows
// have been destroyed.
- root_window_->window()->RemovePreTargetHandler(focus_client_.get());
- aura::client::SetFocusClient(root_window_->window(), NULL);
- aura::client::SetActivationClient(root_window_->window(), NULL);
+ host_->window()->RemovePreTargetHandler(focus_client_.get());
+ aura::client::SetFocusClient(host_->window(), NULL);
+ aura::client::SetActivationClient(host_->window(), NULL);
focus_client_.reset();
- root_window_->RemoveRootWindowObserver(this);
- root_window_.reset(); // Uses input_method_event_filter_ at destruction.
- // RootWindow owns |desktop_root_window_host_|.
- desktop_root_window_host_ = NULL;
+ host_->RemoveObserver(this);
+ host_.reset(); // Uses input_method_event_filter_ at destruction.
+ // WindowEventDispatcher owns |desktop_window_tree_host_|.
+ desktop_window_tree_host_ = NULL;
content_window_ = NULL;
native_widget_delegate_->OnNativeWidgetDestroyed();
@@ -292,30 +330,36 @@ void DesktopNativeWidgetAura::OnHostClosed() {
delete this;
}
-void DesktopNativeWidgetAura::OnDesktopRootWindowHostDestroyed(
- aura::RootWindow* root) {
- // |root_window_| is still valid, but DesktopRootWindowHost is nearly
- // destroyed. Do cleanup here of members DesktopRootWindowHost may also use.
- aura::client::SetDispatcherClient(root->window(), NULL);
+void DesktopNativeWidgetAura::OnDesktopWindowTreeHostDestroyed(
+ aura::WindowTreeHost* host) {
+ // |dispatcher_| is still valid, but DesktopWindowTreeHost is nearly
+ // destroyed. Do cleanup here of members DesktopWindowTreeHost may also use.
+ aura::client::SetDispatcherClient(host->window(), NULL);
dispatcher_client_.reset();
- aura::client::SetCursorClient(root->window(), NULL);
- cursor_client_.reset();
+ // We explicitly do NOT clear the cursor client property. Since the cursor
+ // manager is a singleton, it can outlive any window hierarchy, and it's
+ // important that objects attached to this destroying window hierarchy have
+ // an opportunity to deregister their observers from the cursor manager.
+ // They may want to do this when they are notified that they're being
+ // removed from the window hierarchy, which happens soon after this
+ // function when DesktopWindowTreeHost* calls DestroyDispatcher().
+ native_cursor_manager_->RemoveHost(host);
- aura::client::SetScreenPositionClient(root->window(), NULL);
+ aura::client::SetScreenPositionClient(host->window(), NULL);
position_client_.reset();
- aura::client::SetDragDropClient(root->window(), NULL);
+ aura::client::SetDragDropClient(host->window(), NULL);
drag_drop_client_.reset();
- aura::client::SetEventClient(root->window(), NULL);
+ aura::client::SetEventClient(host->window(), NULL);
event_client_.reset();
}
void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
native_widget_delegate_->OnNativeWidgetActivationChanged(active);
aura::client::ActivationClient* activation_client =
- aura::client::GetActivationClient(root_window_->window());
+ aura::client::GetActivationClient(host_->window());
if (!activation_client)
return;
if (active) {
@@ -361,142 +405,155 @@ void DesktopNativeWidgetAura::InitNativeWidget(
}
content_window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
content_window_->Init(params.layer_type);
- corewm::SetShadowType(content_window_, corewm::SHADOW_TYPE_NONE);
+ wm::SetShadowType(content_window_, wm::SHADOW_TYPE_NONE);
content_window_container_ = new aura::Window(NULL);
- content_window_container_->Init(ui::LAYER_NOT_DRAWN);
+ content_window_container_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
content_window_container_->Show();
content_window_container_->AddChild(content_window_);
- desktop_root_window_host_ = params.desktop_root_window_host ?
- params.desktop_root_window_host :
- DesktopRootWindowHost::Create(native_widget_delegate_, this);
- aura::RootWindow::CreateParams rw_params(params.bounds);
- desktop_root_window_host_->Init(content_window_, params, &rw_params);
+ desktop_window_tree_host_ = params.desktop_window_tree_host ?
+ params.desktop_window_tree_host :
+ DesktopWindowTreeHost::Create(native_widget_delegate_, this);
+ host_.reset(desktop_window_tree_host_->AsWindowTreeHost());
+ desktop_window_tree_host_->Init(content_window_, params);
+
+ // Mark this window as Desktop root window.
+ host_->window()->SetProperty(views::kDesktopRootWindow, true);
+
+ host_->InitHost();
+ host_->window()->AddChild(content_window_container_);
+ host_->window()->SetProperty(kDesktopNativeWidgetAuraKey, this);
- root_window_.reset(new aura::RootWindow(rw_params));
- root_window_->Init();
- root_window_->window()->AddChild(content_window_container_);
+ host_->window()->AddObserver(new RootWindowDestructionObserver(this));
// The WindowsModalityController event filter should be at the head of the
// pre target handlers list. This ensures that it handles input events first
// when modal windows are at the top of the Zorder.
if (widget_type_ == Widget::InitParams::TYPE_WINDOW)
window_modality_controller_.reset(
- new views::corewm::WindowModalityController(root_window_->window()));
+ new wm::WindowModalityController(host_->window()));
// |root_window_event_filter_| must be created before
- // OnRootWindowHostCreated() is invoked.
+ // OnWindowTreeHostCreated() is invoked.
// CEF sets focus to the window the user clicks down on.
// TODO(beng): see if we can't do this some other way. CEF seems a heavy-
// handed way of accomplishing focus.
- // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow.
- root_window_event_filter_ = new corewm::CompoundEventFilter;
- // Pass ownership of the filter to the root_window.
- root_window_->window()->SetEventFilter(root_window_event_filter_);
+ // No event filter for aura::Env. Create CompoundEventFilter per
+ // WindowEventDispatcher.
+ root_window_event_filter_.reset(new wm::CompoundEventFilter);
+ host_->window()->AddPreTargetHandler(root_window_event_filter_.get());
+
+ // The host's dispatcher must be added to |native_cursor_manager_| before
+ // OnNativeWidgetCreated() is called.
+ cursor_reference_count_++;
+ if (!native_cursor_manager_) {
+ native_cursor_manager_ = new DesktopNativeCursorManager(
+ DesktopCursorLoaderUpdater::Create());
+ }
+ if (!cursor_manager_) {
+ cursor_manager_ = new wm::CursorManager(
+ scoped_ptr<wm::NativeCursorManager>(native_cursor_manager_));
+ }
+ native_cursor_manager_->AddHost(host());
+ aura::client::SetCursorClient(host_->window(), cursor_manager_);
- desktop_root_window_host_->OnRootWindowCreated(root_window_.get(), params);
+ desktop_window_tree_host_->OnNativeWidgetCreated(params);
UpdateWindowTransparency();
- capture_client_.reset(new DesktopCaptureClient(root_window_->window()));
+ capture_client_.reset(new DesktopCaptureClient(host_->window()));
- corewm::FocusController* focus_controller =
- new corewm::FocusController(new DesktopFocusRules(content_window_));
+ wm::FocusController* focus_controller =
+ new wm::FocusController(new DesktopFocusRules(content_window_));
focus_client_.reset(focus_controller);
- aura::client::SetFocusClient(root_window_->window(), focus_controller);
- aura::client::SetActivationClient(root_window_->window(), focus_controller);
- root_window_->window()->AddPreTargetHandler(focus_controller);
+ aura::client::SetFocusClient(host_->window(), focus_controller);
+ aura::client::SetActivationClient(host_->window(), focus_controller);
+ host_->window()->AddPreTargetHandler(focus_controller);
dispatcher_client_.reset(new DesktopDispatcherClient);
- aura::client::SetDispatcherClient(root_window_->window(),
+ aura::client::SetDispatcherClient(host_->window(),
dispatcher_client_.get());
- DesktopNativeCursorManager* desktop_native_cursor_manager =
- new views::DesktopNativeCursorManager(
- root_window_.get(),
- DesktopCursorLoaderUpdater::Create());
- cursor_client_.reset(
- new views::corewm::CursorManager(
- scoped_ptr<corewm::NativeCursorManager>(
- desktop_native_cursor_manager)));
- aura::client::SetCursorClient(root_window_->window(), cursor_client_.get());
-
- position_client_.reset(new DesktopScreenPositionClient());
- aura::client::SetScreenPositionClient(root_window_->window(),
- position_client_.get());
+ position_client_.reset(new DesktopScreenPositionClient(host_->window()));
InstallInputMethodEventFilter();
- drag_drop_client_ = desktop_root_window_host_->CreateDragDropClient(
- desktop_native_cursor_manager);
- aura::client::SetDragDropClient(root_window_->window(),
+ drag_drop_client_ = desktop_window_tree_host_->CreateDragDropClient(
+ native_cursor_manager_);
+ aura::client::SetDragDropClient(host_->window(),
drag_drop_client_.get());
static_cast<aura::client::FocusClient*>(focus_client_.get())->
FocusWindow(content_window_);
- OnRootWindowHostResized(root_window_.get());
+ OnHostResized(host());
- root_window_->AddRootWindowObserver(this);
+ host_->AddObserver(this);
window_tree_client_.reset(
- new DesktopNativeWidgetAuraWindowTreeClient(root_window_->window()));
- drop_helper_.reset(new DropHelper(
- static_cast<internal::RootView*>(GetWidget()->GetRootView())));
+ new DesktopNativeWidgetAuraWindowTreeClient(host_->window()));
+ drop_helper_.reset(new DropHelper(GetWidget()->GetRootView()));
aura::client::SetDragDropDelegate(content_window_, this);
- tooltip_manager_.reset(new TooltipManagerAura(GetWidget()));
-
- tooltip_controller_.reset(
- new corewm::TooltipController(
- desktop_root_window_host_->CreateTooltip()));
- aura::client::SetTooltipClient(root_window_->window(),
- tooltip_controller_.get());
- root_window_->window()->AddPreTargetHandler(tooltip_controller_.get());
+ if (params.type != Widget::InitParams::TYPE_TOOLTIP) {
+ tooltip_manager_.reset(new TooltipManagerAura(GetWidget()));
+ tooltip_controller_.reset(
+ new corewm::TooltipController(
+ desktop_window_tree_host_->CreateTooltip()));
+ aura::client::SetTooltipClient(host_->window(),
+ tooltip_controller_.get());
+ host_->window()->AddPreTargetHandler(tooltip_controller_.get());
+ }
if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) {
- visibility_controller_.reset(new views::corewm::VisibilityController);
- aura::client::SetVisibilityClient(root_window_->window(),
+ visibility_controller_.reset(new wm::VisibilityController);
+ aura::client::SetVisibilityClient(host_->window(),
visibility_controller_.get());
- views::corewm::SetChildWindowVisibilityChangesAnimated(
- root_window_->window());
- views::corewm::SetChildWindowVisibilityChangesAnimated(
+ wm::SetChildWindowVisibilityChangesAnimated(host_->window());
+ wm::SetChildWindowVisibilityChangesAnimated(
content_window_container_);
}
if (params.type == Widget::InitParams::TYPE_WINDOW) {
focus_manager_event_handler_.reset(new FocusManagerEventHandler(this));
- root_window_->window()->AddPreTargetHandler(
- focus_manager_event_handler_.get());
+ host_->window()->AddPreTargetHandler(focus_manager_event_handler_.get());
}
event_client_.reset(new DesktopEventClient);
- aura::client::SetEventClient(root_window_->window(), event_client_.get());
+ aura::client::SetEventClient(host_->window(), event_client_.get());
aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
aura::client::SetActivationDelegate(content_window_, this);
- shadow_controller_.reset(
- new corewm::ShadowController(
- aura::client::GetActivationClient(root_window_->window())));
+ shadow_controller_.reset(new wm::ShadowController(
+ aura::client::GetActivationClient(host_->window())));
+
+ content_window_->SetProperty(aura::client::kCanMaximizeKey,
+ GetWidget()->widget_delegate()->CanMaximize());
+ content_window_->SetProperty(aura::client::kCanResizeKey,
+ GetWidget()->widget_delegate()->CanResize());
window_reorderer_.reset(new WindowReorderer(content_window_,
GetWidget()->GetRootView()));
}
NonClientFrameView* DesktopNativeWidgetAura::CreateNonClientFrameView() {
- return desktop_root_window_host_->CreateNonClientFrameView();
+ return ShouldUseNativeFrame() ? new NativeFrameView(GetWidget()) : NULL;
}
bool DesktopNativeWidgetAura::ShouldUseNativeFrame() const {
- return desktop_root_window_host_->ShouldUseNativeFrame();
+ return desktop_window_tree_host_->ShouldUseNativeFrame();
+}
+
+bool DesktopNativeWidgetAura::ShouldWindowContentsBeTransparent() const {
+ return desktop_window_tree_host_->ShouldWindowContentsBeTransparent();
}
void DesktopNativeWidgetAura::FrameTypeChanged() {
- desktop_root_window_host_->FrameTypeChanged();
+ desktop_window_tree_host_->FrameTypeChanged();
UpdateWindowTransparency();
}
@@ -538,6 +595,8 @@ void DesktopNativeWidgetAura::ReorderNativeViews() {
}
void DesktopNativeWidgetAura::ViewRemoved(View* view) {
+ DCHECK(drop_helper_.get() != NULL);
+ drop_helper_->ResetTargetViewIfEquals(view);
}
void DesktopNativeWidgetAura::SetNativeWindowProperty(const char* name,
@@ -571,10 +630,13 @@ void DesktopNativeWidgetAura::ReleaseCapture() {
bool DesktopNativeWidgetAura::HasCapture() const {
return content_window_ && content_window_->HasCapture() &&
- desktop_root_window_host_->HasCapture();
+ desktop_window_tree_host_->HasCapture();
}
InputMethod* DesktopNativeWidgetAura::CreateInputMethod() {
+ if (switches::IsTextInputFocusManagerEnabled())
+ return new NullInputMethod();
+
ui::InputMethod* host = input_method_event_filter_->input_method();
return new InputMethodBridge(this, host, false);
}
@@ -584,50 +646,54 @@ internal::InputMethodDelegate*
return this;
}
+ui::InputMethod* DesktopNativeWidgetAura::GetHostInputMethod() {
+ return input_method_event_filter_->input_method();
+}
+
void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) {
if (content_window_)
- desktop_root_window_host_->CenterWindow(size);
+ desktop_window_tree_host_->CenterWindow(size);
}
void DesktopNativeWidgetAura::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* maximized) const {
if (content_window_)
- desktop_root_window_host_->GetWindowPlacement(bounds, maximized);
+ desktop_window_tree_host_->GetWindowPlacement(bounds, maximized);
}
-bool DesktopNativeWidgetAura::SetWindowTitle(const string16& title) {
+bool DesktopNativeWidgetAura::SetWindowTitle(const base::string16& title) {
if (!content_window_)
return false;
- return desktop_root_window_host_->SetWindowTitle(title);
+ return desktop_window_tree_host_->SetWindowTitle(title);
}
void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
if (content_window_)
- desktop_root_window_host_->SetWindowIcons(window_icon, app_icon);
+ desktop_window_tree_host_->SetWindowIcons(window_icon, app_icon);
}
void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
// 99% of the time, we should not be asked to create a
// DesktopNativeWidgetAura that is modal. We only support window modal
// dialogs on the same lines as non AURA.
- desktop_root_window_host_->InitModalType(modal_type);
+ desktop_window_tree_host_->InitModalType(modal_type);
}
gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const {
return content_window_ ?
- desktop_root_window_host_->GetWindowBoundsInScreen() : gfx::Rect();
+ desktop_window_tree_host_->GetWindowBoundsInScreen() : gfx::Rect();
}
gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const {
return content_window_ ?
- desktop_root_window_host_->GetClientAreaBoundsInScreen() : gfx::Rect();
+ desktop_window_tree_host_->GetClientAreaBoundsInScreen() : gfx::Rect();
}
gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const {
return content_window_ ?
- desktop_root_window_host_->GetRestoredBounds() : gfx::Rect();
+ desktop_window_tree_host_->GetRestoredBounds() : gfx::Rect();
}
void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
@@ -636,9 +702,9 @@ void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
// TODO(ananta)
// This code by default scales the bounds rectangle by 1.
// We could probably get rid of this and similar logic from
- // the DesktopNativeWidgetAura::OnRootWindowHostResized function.
+ // the DesktopNativeWidgetAura::OnWindowTreeHostResized function.
float scale = 1;
- aura::Window* root = root_window_->window();
+ aura::Window* root = host_->window();
if (root) {
scale = gfx::Screen::GetScreenFor(root)->
GetDisplayNearestWindow(root).device_scale_factor();
@@ -646,12 +712,12 @@ void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
gfx::Rect bounds_in_pixels(
gfx::ToCeiledPoint(gfx::ScalePoint(bounds.origin(), scale)),
gfx::ToFlooredSize(gfx::ScaleSize(bounds.size(), scale)));
- desktop_root_window_host_->AsRootWindowHost()->SetBounds(bounds_in_pixels);
+ desktop_window_tree_host_->AsWindowTreeHost()->SetBounds(bounds_in_pixels);
}
void DesktopNativeWidgetAura::SetSize(const gfx::Size& size) {
if (content_window_)
- desktop_root_window_host_->SetSize(size);
+ desktop_window_tree_host_->SetSize(size);
}
void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
@@ -659,7 +725,7 @@ void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
void DesktopNativeWidgetAura::StackAtTop() {
if (content_window_)
- desktop_root_window_host_->StackAtTop();
+ desktop_window_tree_host_->StackAtTop();
}
void DesktopNativeWidgetAura::StackBelow(gfx::NativeView native_view) {
@@ -667,7 +733,7 @@ void DesktopNativeWidgetAura::StackBelow(gfx::NativeView native_view) {
void DesktopNativeWidgetAura::SetShape(gfx::NativeRegion shape) {
if (content_window_)
- desktop_root_window_host_->SetShape(shape);
+ desktop_window_tree_host_->SetShape(shape);
}
void DesktopNativeWidgetAura::Close() {
@@ -677,25 +743,25 @@ void DesktopNativeWidgetAura::Close() {
content_window_->SuppressPaint();
content_window_->Hide();
- desktop_root_window_host_->Close();
+ desktop_window_tree_host_->Close();
}
void DesktopNativeWidgetAura::CloseNow() {
if (content_window_)
- desktop_root_window_host_->CloseNow();
+ desktop_window_tree_host_->CloseNow();
}
void DesktopNativeWidgetAura::Show() {
if (!content_window_)
return;
- desktop_root_window_host_->AsRootWindowHost()->Show();
+ desktop_window_tree_host_->AsWindowTreeHost()->Show();
content_window_->Show();
}
void DesktopNativeWidgetAura::Hide() {
if (!content_window_)
return;
- desktop_root_window_host_->AsRootWindowHost()->Hide();
+ desktop_window_tree_host_->AsWindowTreeHost()->Hide();
content_window_->Hide();
}
@@ -703,79 +769,84 @@ void DesktopNativeWidgetAura::ShowMaximizedWithBounds(
const gfx::Rect& restored_bounds) {
if (!content_window_)
return;
- desktop_root_window_host_->ShowMaximizedWithBounds(restored_bounds);
+ desktop_window_tree_host_->ShowMaximizedWithBounds(restored_bounds);
content_window_->Show();
}
void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
if (!content_window_)
return;
- desktop_root_window_host_->ShowWindowWithState(state);
+ desktop_window_tree_host_->ShowWindowWithState(state);
content_window_->Show();
}
bool DesktopNativeWidgetAura::IsVisible() const {
- return content_window_ && desktop_root_window_host_->IsVisible();
+ return content_window_ && desktop_window_tree_host_->IsVisible();
}
void DesktopNativeWidgetAura::Activate() {
if (content_window_)
- desktop_root_window_host_->Activate();
+ desktop_window_tree_host_->Activate();
}
void DesktopNativeWidgetAura::Deactivate() {
if (content_window_)
- desktop_root_window_host_->Deactivate();
+ desktop_window_tree_host_->Deactivate();
}
bool DesktopNativeWidgetAura::IsActive() const {
- return content_window_ && desktop_root_window_host_->IsActive();
+ return content_window_ && desktop_window_tree_host_->IsActive();
}
void DesktopNativeWidgetAura::SetAlwaysOnTop(bool always_on_top) {
if (content_window_)
- desktop_root_window_host_->SetAlwaysOnTop(always_on_top);
+ desktop_window_tree_host_->SetAlwaysOnTop(always_on_top);
}
bool DesktopNativeWidgetAura::IsAlwaysOnTop() const {
- return content_window_ && desktop_root_window_host_->IsAlwaysOnTop();
+ return content_window_ && desktop_window_tree_host_->IsAlwaysOnTop();
+}
+
+void DesktopNativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
+ if (content_window_)
+ desktop_window_tree_host_->SetVisibleOnAllWorkspaces(always_visible);
}
void DesktopNativeWidgetAura::Maximize() {
if (content_window_)
- desktop_root_window_host_->Maximize();
+ desktop_window_tree_host_->Maximize();
}
void DesktopNativeWidgetAura::Minimize() {
if (content_window_)
- desktop_root_window_host_->Minimize();
+ desktop_window_tree_host_->Minimize();
}
bool DesktopNativeWidgetAura::IsMaximized() const {
- return content_window_ && desktop_root_window_host_->IsMaximized();
+ return content_window_ && desktop_window_tree_host_->IsMaximized();
}
bool DesktopNativeWidgetAura::IsMinimized() const {
- return content_window_ && desktop_root_window_host_->IsMinimized();
+ return content_window_ && desktop_window_tree_host_->IsMinimized();
}
void DesktopNativeWidgetAura::Restore() {
if (content_window_)
- desktop_root_window_host_->Restore();
+ desktop_window_tree_host_->Restore();
}
void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) {
if (content_window_)
- desktop_root_window_host_->SetFullscreen(fullscreen);
+ desktop_window_tree_host_->SetFullscreen(fullscreen);
}
bool DesktopNativeWidgetAura::IsFullscreen() const {
- return content_window_ && desktop_root_window_host_->IsFullscreen();
+ return content_window_ && desktop_window_tree_host_->IsFullscreen();
}
void DesktopNativeWidgetAura::SetOpacity(unsigned char opacity) {
if (content_window_)
- desktop_root_window_host_->SetOpacity(opacity);
+ desktop_window_tree_host_->SetOpacity(opacity);
}
void DesktopNativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
@@ -783,7 +854,7 @@ void DesktopNativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) {
if (content_window_)
- desktop_root_window_host_->FlashFrame(flash_frame);
+ desktop_window_tree_host_->FlashFrame(flash_frame);
}
void DesktopNativeWidgetAura::RunShellDrag(
@@ -803,7 +874,7 @@ void DesktopNativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
cursor_ = cursor;
aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root_window_->window());
+ aura::client::GetCursorClient(host_->window());
if (cursor_client)
cursor_client->SetCursor(cursor);
}
@@ -812,12 +883,12 @@ bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const {
if (!content_window_)
return false;
aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root_window_->window());
+ aura::client::GetCursorClient(host_->window());
return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
}
void DesktopNativeWidgetAura::ClearNativeFocus() {
- desktop_root_window_host_->ClearNativeFocus();
+ desktop_window_tree_host_->ClearNativeFocus();
if (ShouldActivate()) {
aura::client::GetFocusClient(content_window_)->
@@ -826,8 +897,8 @@ void DesktopNativeWidgetAura::ClearNativeFocus() {
}
gfx::Rect DesktopNativeWidgetAura::GetWorkAreaBoundsInScreen() const {
- return desktop_root_window_host_ ?
- desktop_root_window_host_->GetWorkAreaBoundsInScreen() : gfx::Rect();
+ return desktop_window_tree_host_ ?
+ desktop_window_tree_host_->GetWorkAreaBoundsInScreen() : gfx::Rect();
}
Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop(
@@ -836,28 +907,37 @@ Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop(
Widget::MoveLoopEscapeBehavior escape_behavior) {
if (!content_window_)
return Widget::MOVE_LOOP_CANCELED;
- return desktop_root_window_host_->RunMoveLoop(drag_offset, source,
+ return desktop_window_tree_host_->RunMoveLoop(drag_offset, source,
escape_behavior);
}
void DesktopNativeWidgetAura::EndMoveLoop() {
if (content_window_)
- desktop_root_window_host_->EndMoveLoop();
+ desktop_window_tree_host_->EndMoveLoop();
}
void DesktopNativeWidgetAura::SetVisibilityChangedAnimationsEnabled(
bool value) {
if (content_window_)
- desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value);
+ desktop_window_tree_host_->SetVisibilityChangedAnimationsEnabled(value);
}
ui::NativeTheme* DesktopNativeWidgetAura::GetNativeTheme() const {
- return DesktopRootWindowHost::GetNativeTheme(content_window_);
+ return DesktopWindowTreeHost::GetNativeTheme(content_window_);
}
void DesktopNativeWidgetAura::OnRootViewLayout() const {
if (content_window_)
- desktop_root_window_host_->OnRootViewLayout();
+ desktop_window_tree_host_->OnRootViewLayout();
+}
+
+bool DesktopNativeWidgetAura::IsTranslucentWindowOpacitySupported() const {
+ return content_window_ &&
+ desktop_window_tree_host_->IsTranslucentWindowOpacitySupported();
+}
+
+void DesktopNativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) {
+ OnEvent(native_event);
}
////////////////////////////////////////////////////////////////////////////////
@@ -904,13 +984,13 @@ void DesktopNativeWidgetAura::OnDeviceScaleFactorChanged(
float device_scale_factor) {
}
-void DesktopNativeWidgetAura::OnWindowDestroying() {
+void DesktopNativeWidgetAura::OnWindowDestroying(aura::Window* window) {
// Cleanup happens in OnHostClosed().
}
-void DesktopNativeWidgetAura::OnWindowDestroyed() {
+void DesktopNativeWidgetAura::OnWindowDestroyed(aura::Window* window) {
// Cleanup happens in OnHostClosed(). We own |content_window_| (indirectly by
- // way of |root_window_|) so there should be no need to do any processing
+ // way of |dispatcher_|) so there should be no need to do any processing
// here.
}
@@ -925,9 +1005,6 @@ void DesktopNativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
native_widget_delegate_->GetHitTestMask(mask);
}
-void DesktopNativeWidgetAura::DidRecreateLayer(ui::Layer* old_layer,
- ui::Layer* new_layer) {}
-
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, ui::EventHandler implementation:
@@ -978,10 +1055,6 @@ void DesktopNativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) {
}
}
-void DesktopNativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) {
- native_widget_delegate_->OnTouchEvent(event);
-}
-
void DesktopNativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
native_widget_delegate_->OnGestureEvent(event);
}
@@ -990,7 +1063,7 @@ void DesktopNativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
// DesktopNativeWidgetAura, aura::client::ActivationDelegate implementation:
bool DesktopNativeWidgetAura::ShouldActivate() const {
- return can_activate_ && native_widget_delegate_->CanActivate();
+ return native_widget_delegate_->CanActivate();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1000,10 +1073,6 @@ bool DesktopNativeWidgetAura::ShouldActivate() const {
void DesktopNativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
aura::Window* lost_active) {
DCHECK(content_window_ == gained_active || content_window_ == lost_active);
- if ((content_window_ == gained_active || content_window_ == lost_active) &&
- IsVisible() && GetWidget()->non_client_view()) {
- GetWidget()->non_client_view()->SchedulePaint();
- }
if (gained_active == content_window_ && restore_focus_on_activate_) {
restore_focus_on_activate_ = false;
GetWidget()->GetFocusManager()->RestoreFocusedView();
@@ -1021,19 +1090,18 @@ void DesktopNativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
if (content_window_ == gained_focus) {
- desktop_root_window_host_->OnNativeWidgetFocus();
+ desktop_window_tree_host_->OnNativeWidgetFocus();
native_widget_delegate_->OnNativeFocus(lost_focus);
// If focus is moving from a descendant Window to |content_window_| then
- // native activation hasn't changed. We still need to inform the InputMethod
- // we've been focused though.
+ // native activation hasn't changed. Still, the InputMethod must be informed
+ // of the Window focus change.
InputMethod* input_method = GetWidget()->GetInputMethod();
if (input_method)
input_method->OnFocus();
} else if (content_window_ == lost_focus) {
- desktop_root_window_host_->OnNativeWidgetBlur();
- native_widget_delegate_->OnNativeBlur(
- aura::client::GetFocusClient(content_window_)->GetFocusedWindow());
+ desktop_window_tree_host_->OnNativeWidgetBlur();
+ native_widget_delegate_->OnNativeBlur(gained_focus);
}
}
@@ -1078,22 +1146,21 @@ int DesktopNativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
}
////////////////////////////////////////////////////////////////////////////////
-// DesktopNativeWidgetAura, aura::RootWindowObserver implementation:
+// DesktopNativeWidgetAura, aura::WindowTreeHostObserver implementation:
-void DesktopNativeWidgetAura::OnRootWindowHostCloseRequested(
- const aura::RootWindow* root) {
- Close();
+void DesktopNativeWidgetAura::OnHostCloseRequested(
+ const aura::WindowTreeHost* host) {
+ GetWidget()->Close();
}
-void DesktopNativeWidgetAura::OnRootWindowHostResized(
- const aura::RootWindow* root) {
+void DesktopNativeWidgetAura::OnHostResized(const aura::WindowTreeHost* host) {
// Don't update the bounds of the child layers when animating closed. If we
// did it would force a paint, which we don't want. We don't want the paint
// as we can't assume any of the children are valid.
- if (desktop_root_window_host_->IsAnimatingClosed())
+ if (desktop_window_tree_host_->IsAnimatingClosed())
return;
- gfx::Rect new_bounds = gfx::Rect(root->window()->bounds().size());
+ gfx::Rect new_bounds = gfx::Rect(host->window()->bounds().size());
content_window_->SetBounds(new_bounds);
// Can be NULL at start.
if (content_window_container_)
@@ -1101,34 +1168,45 @@ void DesktopNativeWidgetAura::OnRootWindowHostResized(
native_widget_delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
}
-void DesktopNativeWidgetAura::OnRootWindowHostMoved(
- const aura::RootWindow* root,
- const gfx::Point& new_origin) {
- TRACE_EVENT1("views", "DesktopNativeWidgetAura::OnRootWindowHostMoved",
+void DesktopNativeWidgetAura::OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) {
+ TRACE_EVENT1("views", "DesktopNativeWidgetAura::OnHostMoved",
"new_origin", new_origin.ToString());
native_widget_delegate_->OnNativeWidgetMove();
}
////////////////////////////////////////////////////////////////////////////////
-// DesktopNativeWidgetAura, NativeWidget implementation:
-
-ui::EventHandler* DesktopNativeWidgetAura::GetEventHandler() {
- return this;
-}
+// DesktopNativeWidgetAura, private:
void DesktopNativeWidgetAura::InstallInputMethodEventFilter() {
DCHECK(!input_method_event_filter_.get());
- input_method_event_filter_.reset(new corewm::InputMethodEventFilter(
- root_window_->host()->GetAcceleratedWidget()));
+ input_method_event_filter_.reset(new wm::InputMethodEventFilter(
+ host_->GetAcceleratedWidget()));
input_method_event_filter_->SetInputMethodPropertyInRootWindow(
- root_window_->window());
+ host_->window());
root_window_event_filter_->AddHandler(input_method_event_filter_.get());
}
void DesktopNativeWidgetAura::UpdateWindowTransparency() {
- content_window_->SetTransparent(ShouldUseNativeFrame());
+ content_window_->SetTransparent(
+ desktop_window_tree_host_->ShouldWindowContentsBeTransparent());
+ // Regardless of transparency or not, this root content window will always
+ // fill its bounds completely, so set this flag to true to avoid an
+ // unecessary clear before update.
+ content_window_->SetFillsBoundsCompletely(true);
+}
+
+void DesktopNativeWidgetAura::RootWindowDestroyed() {
+ cursor_reference_count_--;
+ if (cursor_reference_count_ == 0) {
+ // We are the last DesktopNativeWidgetAura instance, and we are responsible
+ // for cleaning up |cursor_manager_|.
+ delete cursor_manager_;
+ native_cursor_manager_ = NULL;
+ cursor_manager_ = NULL;
+ }
}
} // namespace views
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 639210f3f4f..16a56d951bc 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
@@ -6,18 +6,20 @@
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_
#include "base/memory/weak_ptr.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/root_window_observer.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_tree_host_observer.h"
#include "ui/base/cursor/cursor.h"
#include "ui/views/ime/input_method_delegate.h"
#include "ui/views/widget/native_widget_private.h"
+#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_delegate.h"
+#include "ui/wm/public/drag_drop_delegate.h"
namespace aura {
-class RootWindow;
+class WindowEventDispatcher;
+class WindowTreeHost;
namespace client {
class DragDropClient;
class FocusClient;
@@ -26,23 +28,25 @@ class WindowTreeClient;
}
}
-namespace views {
-
-namespace corewm {
+namespace wm {
class CompoundEventFilter;
class CursorManager;
class FocusController;
class InputMethodEventFilter;
class ShadowController;
-class TooltipController;
class VisibilityController;
class WindowModalityController;
}
+namespace views {
+namespace corewm {
+class TooltipController;
+}
class DesktopCaptureClient;
class DesktopDispatcherClient;
class DesktopEventClient;
-class DesktopRootWindowHost;
+class DesktopNativeCursorManager;
+class DesktopWindowTreeHost;
class DropHelper;
class FocusManagerEventHandler;
class TooltipManagerAura;
@@ -56,31 +60,34 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
public aura::client::FocusChangeObserver,
public views::internal::InputMethodDelegate,
public aura::client::DragDropDelegate,
- public aura::RootWindowObserver {
+ public aura::WindowTreeHostObserver {
public:
explicit DesktopNativeWidgetAura(internal::NativeWidgetDelegate* delegate);
virtual ~DesktopNativeWidgetAura();
- // Maps from window to DesktopNativeWidgetAura.
+ // Maps from window to DesktopNativeWidgetAura. |window| must be a root
+ // window.
static DesktopNativeWidgetAura* ForWindow(aura::Window* window);
- // Called by our DesktopRootWindowHost after it has deleted native resources;
+ // Called by our DesktopWindowTreeHost after it has deleted native resources;
// this is the signal that we should start our shutdown.
virtual void OnHostClosed();
- // Called from ~DesktopRootWindowHost. This takes the RootWindow as by the
- // time we get here |root_window_| is NULL.
- virtual void OnDesktopRootWindowHostDestroyed(aura::RootWindow* root);
+ // TODO(beng): remove this method and replace with an implementation of
+ // WindowDestroying() that takes the window being destroyed.
+ // Called from ~DesktopWindowTreeHost. This takes the WindowEventDispatcher
+ // as by the time we get here |dispatcher_| is NULL.
+ virtual void OnDesktopWindowTreeHostDestroyed(aura::WindowTreeHost* host);
- corewm::InputMethodEventFilter* input_method_event_filter() {
+ wm::InputMethodEventFilter* input_method_event_filter() {
return input_method_event_filter_.get();
}
- corewm::CompoundEventFilter* root_window_event_filter() {
- return root_window_event_filter_;
+ wm::CompoundEventFilter* root_window_event_filter() {
+ return root_window_event_filter_.get();
+ }
+ aura::WindowTreeHost* host() {
+ return host_.get();
}
-
- // Overridden from NativeWidget:
- virtual ui::EventHandler* GetEventHandler() OVERRIDE;
// Ensures that the correct window is activated/deactivated based on whether
// we are being activated/deactivated.
@@ -91,6 +98,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual bool ShouldWindowContentsBeTransparent() const OVERRIDE;
virtual void FrameTypeChanged() OVERRIDE;
virtual Widget* GetWidget() OVERRIDE;
virtual const Widget* GetWidget() const OVERRIDE;
@@ -110,11 +118,12 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual bool HasCapture() const OVERRIDE;
virtual InputMethod* CreateInputMethod() OVERRIDE;
virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual ui::InputMethod* GetHostInputMethod() OVERRIDE;
virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
virtual void GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* maximized) const OVERRIDE;
- virtual bool SetWindowTitle(const string16& title) OVERRIDE;
+ virtual bool SetWindowTitle(const base::string16& title) OVERRIDE;
virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) OVERRIDE;
virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
@@ -140,6 +149,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual bool IsActive() const OVERRIDE;
virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
virtual bool IsAlwaysOnTop() const OVERRIDE;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
virtual bool IsMaximized() const OVERRIDE;
@@ -168,6 +178,8 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
virtual void OnRootViewLayout() const OVERRIDE;
+ virtual bool IsTranslucentWindowOpacitySupported() const OVERRIDE;
+ virtual void RepostNativeEvent(gfx::NativeEvent native_event) OVERRIDE;
// Overridden from aura::WindowDelegate:
virtual gfx::Size GetMinimumSize() const OVERRIDE;
@@ -183,19 +195,16 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual void OnCaptureLost() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void OnWindowDestroying() OVERRIDE;
- virtual void OnWindowDestroyed() OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
virtual bool HasHitTestMask() const OVERRIDE;
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
- virtual void DidRecreateLayer(ui::Layer* old_layer,
- ui::Layer* new_layer) OVERRIDE;
// Overridden from ui::EventHandler:
virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
// Overridden from aura::client::ActivationDelegate:
@@ -218,15 +227,15 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual void OnDragExited() OVERRIDE;
virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
- // Overridden from aura::RootWindowObserver:
- virtual void OnRootWindowHostCloseRequested(
- const aura::RootWindow* root) OVERRIDE;
- virtual void OnRootWindowHostResized(const aura::RootWindow* root) OVERRIDE;
- virtual void OnRootWindowHostMoved(const aura::RootWindow* root,
- const gfx::Point& new_origin) OVERRIDE;
+ // Overridden from aura::WindowTreeHostObserver:
+ virtual void OnHostCloseRequested(const aura::WindowTreeHost* host) OVERRIDE;
+ virtual void OnHostResized(const aura::WindowTreeHost* host) OVERRIDE;
+ virtual void OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) OVERRIDE;
private:
friend class FocusManagerEventHandler;
+ friend class RootWindowDestructionObserver;
// Installs the input method filter.
void InstallInputMethodEventFilter();
@@ -235,25 +244,20 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
// window is only set as transparent when the glass frame is in use.
void UpdateWindowTransparency();
+ void RootWindowDestroyed();
+
+ scoped_ptr<aura::WindowTreeHost> host_;
+ DesktopWindowTreeHost* desktop_window_tree_host_;
+
// See class documentation for Widget in widget.h for a note about ownership.
Widget::InitParams::Ownership ownership_;
scoped_ptr<DesktopCaptureClient> capture_client_;
- // The NativeWidget owns the RootWindow. Required because the RootWindow owns
- // its RootWindowHost, so DesktopRootWindowHost can't own it.
- scoped_ptr<aura::RootWindow> root_window_;
-
// The following factory is used for calls to close the NativeWidgetAura
// instance.
base::WeakPtrFactory<DesktopNativeWidgetAura> close_widget_factory_;
- // Can we be made active?
- bool can_activate_;
-
- // Ownership passed to RootWindow on Init.
- DesktopRootWindowHost* desktop_root_window_host_;
-
// Child of the root, contains |content_window_|.
aura::Window* content_window_container_;
@@ -264,9 +268,8 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
internal::NativeWidgetDelegate* native_widget_delegate_;
- scoped_ptr<corewm::FocusController> focus_client_;
+ scoped_ptr<wm::FocusController> focus_client_;
scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
- scoped_ptr<views::corewm::CursorManager> cursor_client_;
scoped_ptr<aura::client::ScreenPositionClient> position_client_;
scoped_ptr<aura::client::DragDropClient> drag_drop_client_;
scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
@@ -274,9 +277,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
scoped_ptr<FocusManagerEventHandler> focus_manager_event_handler_;
// Toplevel event filter which dispatches to other event filters.
- corewm::CompoundEventFilter* root_window_event_filter_;
+ scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_;
- scoped_ptr<corewm::InputMethodEventFilter> input_method_event_filter_;
+ scoped_ptr<wm::InputMethodEventFilter> input_method_event_filter_;
scoped_ptr<DropHelper> drop_helper_;
int last_drop_operation_;
@@ -284,17 +287,25 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
scoped_ptr<corewm::TooltipController> tooltip_controller_;
scoped_ptr<TooltipManagerAura> tooltip_manager_;
- scoped_ptr<views::corewm::VisibilityController> visibility_controller_;
+ scoped_ptr<wm::VisibilityController> visibility_controller_;
- scoped_ptr<views::corewm::WindowModalityController>
+ scoped_ptr<wm::WindowModalityController>
window_modality_controller_;
- // See comments in OnLostActive().
bool restore_focus_on_activate_;
gfx::NativeCursor cursor_;
-
- scoped_ptr<corewm::ShadowController> shadow_controller_;
+ // We must manually reference count the number of users of |cursor_manager_|
+ // because the cursors created by |cursor_manager_| are shared among the
+ // DNWAs. We can't just stuff this in a LazyInstance because we need to
+ // destroy this as the last DNWA happens; we can't put it off until
+ // (potentially) after we tear down the X11 connection because that's a
+ // crash.
+ static int cursor_reference_count_;
+ static wm::CursorManager* cursor_manager_;
+ static views::DesktopNativeCursorManager* native_cursor_manager_;
+
+ scoped_ptr<wm::ShadowController> shadow_controller_;
// Reorders child windows of |window_| associated with a view based on the
// order of the associated views in the widget's view hierarchy.
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 6a011cab955..f52fe91a7b6 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
@@ -4,13 +4,21 @@
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/aura/root_window.h"
+#include "base/bind.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/public/dispatcher_client.h"
namespace views {
+namespace test {
typedef ViewsTestBase DesktopNativeWidgetAuraTest;
@@ -27,12 +35,21 @@ TEST_F(DesktopNativeWidgetAuraTest, CreateWithParentNotInRootWindow) {
widget.Init(params);
}
-// Verifies that the AURA windows making up a widget instance have the correct
+// Verifies that the Aura windows making up a widget instance have the correct
// bounds after the widget is resized.
TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowSizeTest) {
Widget widget;
+
+ // On Linux we test this with popup windows because the WM may ignore the size
+ // suggestion for normal windows.
+#if defined(OS_LINUX)
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+#else
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+#endif
+
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.native_widget = new DesktopNativeWidgetAura(&widget);
widget.Init(init_params);
@@ -68,6 +85,97 @@ TEST_F(DesktopNativeWidgetAuraTest, NativeViewInitiallyHidden) {
EXPECT_FALSE(widget.GetNativeView()->IsVisible());
}
+// Verify that the cursor state is shared between two native widgets.
+TEST_F(DesktopNativeWidgetAuraTest, GlobalCursorState) {
+ // Create two native widgets, each owning different root windows.
+ Widget widget_a;
+ Widget::InitParams init_params_a =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params_a.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ DesktopNativeWidgetAura* desktop_native_widget_aura_a =
+ new DesktopNativeWidgetAura(&widget_a);
+ init_params_a.native_widget = desktop_native_widget_aura_a;
+ widget_a.Init(init_params_a);
+
+ Widget widget_b;
+ Widget::InitParams init_params_b =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params_b.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ DesktopNativeWidgetAura* desktop_native_widget_aura_b =
+ new DesktopNativeWidgetAura(&widget_b);
+ init_params_b.native_widget = desktop_native_widget_aura_b;
+ widget_b.Init(init_params_b);
+
+ aura::client::CursorClient* cursor_client_a = aura::client::GetCursorClient(
+ desktop_native_widget_aura_a->host()->window());
+ aura::client::CursorClient* cursor_client_b = aura::client::GetCursorClient(
+ desktop_native_widget_aura_b->host()->window());
+
+ // Verify the cursor can be locked using one client and unlocked using
+ // another.
+ EXPECT_FALSE(cursor_client_a->IsCursorLocked());
+ EXPECT_FALSE(cursor_client_b->IsCursorLocked());
+
+ cursor_client_a->LockCursor();
+ EXPECT_TRUE(cursor_client_a->IsCursorLocked());
+ EXPECT_TRUE(cursor_client_b->IsCursorLocked());
+
+ cursor_client_b->UnlockCursor();
+ EXPECT_FALSE(cursor_client_a->IsCursorLocked());
+ EXPECT_FALSE(cursor_client_b->IsCursorLocked());
+
+ // Verify that mouse events can be disabled using one client and then
+ // re-enabled using another. Note that disabling mouse events should also
+ // have the side effect of making the cursor invisible.
+ EXPECT_TRUE(cursor_client_a->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_b->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
+ EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
+
+ cursor_client_b->DisableMouseEvents();
+ EXPECT_FALSE(cursor_client_a->IsCursorVisible());
+ EXPECT_FALSE(cursor_client_b->IsCursorVisible());
+ EXPECT_FALSE(cursor_client_a->IsMouseEventsEnabled());
+ EXPECT_FALSE(cursor_client_b->IsMouseEventsEnabled());
+
+ cursor_client_a->EnableMouseEvents();
+ EXPECT_TRUE(cursor_client_a->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_b->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
+ EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
+
+ // Verify that setting the cursor using one cursor client
+ // will set it for all root windows.
+ EXPECT_EQ(ui::kCursorNone, cursor_client_a->GetCursor().native_type());
+ EXPECT_EQ(ui::kCursorNone, cursor_client_b->GetCursor().native_type());
+
+ cursor_client_b->SetCursor(ui::kCursorPointer);
+ EXPECT_EQ(ui::kCursorPointer, cursor_client_a->GetCursor().native_type());
+ EXPECT_EQ(ui::kCursorPointer, cursor_client_b->GetCursor().native_type());
+
+ // Verify that hiding the cursor using one cursor client will
+ // hide it for all root windows. Note that hiding the cursor
+ // should not disable mouse events.
+ cursor_client_a->HideCursor();
+ EXPECT_FALSE(cursor_client_a->IsCursorVisible());
+ EXPECT_FALSE(cursor_client_b->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
+ EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
+
+ // Verify that the visibility state cannot be changed using one
+ // cursor client when the cursor was locked using another.
+ cursor_client_b->LockCursor();
+ cursor_client_a->ShowCursor();
+ EXPECT_FALSE(cursor_client_a->IsCursorVisible());
+ EXPECT_FALSE(cursor_client_b->IsCursorVisible());
+
+ // Verify the cursor becomes visible on unlock (since a request
+ // to make it visible was queued up while the cursor was locked).
+ cursor_client_b->UnlockCursor();
+ EXPECT_TRUE(cursor_client_a->IsCursorVisible());
+ EXPECT_TRUE(cursor_client_b->IsCursorVisible());
+}
+
// Verifies FocusController doesn't attempt to access |content_window_| during
// destruction. Previously the FocusController was destroyed after the window.
// This could be problematic as FocusController references |content_window_| and
@@ -94,4 +202,198 @@ TEST_F(DesktopNativeWidgetAuraTest, DontAccessContentWindowDuringDestruction) {
}
}
+void QuitNestedLoopAndCloseWidget(scoped_ptr<Widget> widget,
+ base::Closure* quit_runloop) {
+ quit_runloop->Run();
+}
+
+// Verifies that a widget can be destroyed when running a nested message-loop.
+TEST_F(DesktopNativeWidgetAuraTest, WidgetCanBeDestroyedFromNestedLoop) {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(widget.get());
+ widget->Init(params);
+ widget->Show();
+
+ aura::Window* window = widget->GetNativeView();
+ aura::Window* root = window->GetRootWindow();
+ aura::client::DispatcherClient* client =
+ aura::client::GetDispatcherClient(root);
+
+ // Post a task that terminates the nested loop and destroyes the widget. This
+ // task will be executed from the nested loop initiated with the call to
+ // |RunWithDispatcher()| below.
+ aura::client::DispatcherRunLoop run_loop(client, NULL);
+ base::Closure quit_runloop = run_loop.QuitClosure();
+ message_loop()->PostTask(FROM_HERE,
+ base::Bind(&QuitNestedLoopAndCloseWidget,
+ base::Passed(&widget),
+ base::Unretained(&quit_runloop)));
+ run_loop.Run();
+}
+
+// This class provides functionality to create fullscreen and top level popup
+// windows. It additionally tests whether the destruction of these windows
+// occurs correctly in desktop AURA without crashing.
+// It provides facilities to test the following cases:-
+// 1. Child window destroyed which should lead to the destruction of the
+// parent.
+// 2. Parent window destroyed which should lead to the child being destroyed.
+class DesktopAuraTopLevelWindowTest
+ : public views::TestViewsDelegate,
+ public aura::WindowObserver {
+ public:
+ DesktopAuraTopLevelWindowTest()
+ : top_level_widget_(NULL),
+ owned_window_(NULL),
+ owner_destroyed_(false),
+ owned_window_destroyed_(false) {}
+
+ virtual ~DesktopAuraTopLevelWindowTest() {
+ EXPECT_TRUE(owner_destroyed_);
+ EXPECT_TRUE(owned_window_destroyed_);
+ top_level_widget_ = NULL;
+ owned_window_ = NULL;
+ }
+
+ // views::TestViewsDelegate overrides.
+ virtual void OnBeforeWidgetInit(
+ Widget::InitParams* params,
+ internal::NativeWidgetDelegate* delegate) OVERRIDE {
+ if (!params->native_widget)
+ params->native_widget = new views::DesktopNativeWidgetAura(delegate);
+ }
+
+ void CreateTopLevelWindow(const gfx::Rect& bounds, bool fullscreen) {
+ Widget::InitParams init_params;
+ init_params.type = Widget::InitParams::TYPE_WINDOW;
+ init_params.bounds = bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.layer_type = aura::WINDOW_LAYER_NOT_DRAWN;
+ init_params.accept_events = fullscreen;
+
+ widget_.Init(init_params);
+
+ owned_window_ = new aura::Window(&child_window_delegate_);
+ owned_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ owned_window_->SetName("TestTopLevelWindow");
+ if (fullscreen) {
+ owned_window_->SetProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_FULLSCREEN);
+ } else {
+ owned_window_->SetType(ui::wm::WINDOW_TYPE_MENU);
+ }
+ owned_window_->Init(aura::WINDOW_LAYER_TEXTURED);
+ aura::client::ParentWindowWithContext(
+ owned_window_,
+ widget_.GetNativeView()->GetRootWindow(),
+ gfx::Rect(0, 0, 1900, 1600));
+ owned_window_->Show();
+ owned_window_->AddObserver(this);
+
+ ASSERT_TRUE(owned_window_->parent() != NULL);
+ owned_window_->parent()->AddObserver(this);
+
+ top_level_widget_ =
+ views::Widget::GetWidgetForNativeView(owned_window_->parent());
+ ASSERT_TRUE(top_level_widget_ != NULL);
+ }
+
+ void DestroyOwnedWindow() {
+ ASSERT_TRUE(owned_window_ != NULL);
+ delete owned_window_;
+ }
+
+ void DestroyOwnerWindow() {
+ ASSERT_TRUE(top_level_widget_ != NULL);
+ top_level_widget_->CloseNow();
+ }
+
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ window->RemoveObserver(this);
+ if (window == owned_window_) {
+ owned_window_destroyed_ = true;
+ } else if (window == top_level_widget_->GetNativeView()) {
+ owner_destroyed_ = true;
+ } else {
+ ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
+ }
+ }
+
+ aura::Window* owned_window() {
+ return owned_window_;
+ }
+
+ views::Widget* top_level_widget() {
+ return top_level_widget_;
+ }
+
+ private:
+ views::Widget widget_;
+ views::Widget* top_level_widget_;
+ aura::Window* owned_window_;
+ bool owner_destroyed_;
+ bool owned_window_destroyed_;
+ aura::test::TestWindowDelegate child_window_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest);
+};
+
+typedef WidgetTest DesktopAuraWidgetTest;
+
+TEST_F(DesktopAuraWidgetTest, FullscreenWindowDestroyedBeforeOwnerTest) {
+ ViewsDelegate::views_delegate = NULL;
+ DesktopAuraTopLevelWindowTest fullscreen_window;
+ ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
+ gfx::Rect(0, 0, 200, 200), true));
+
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnedWindow());
+ RunPendingMessages();
+}
+
+TEST_F(DesktopAuraWidgetTest, FullscreenWindowOwnerDestroyed) {
+ ViewsDelegate::views_delegate = NULL;
+
+ DesktopAuraTopLevelWindowTest fullscreen_window;
+ ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
+ gfx::Rect(0, 0, 200, 200), true));
+
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnerWindow());
+ RunPendingMessages();
+}
+
+TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupTest) {
+ ViewsDelegate::views_delegate = NULL;
+ DesktopAuraTopLevelWindowTest popup_window;
+ ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
+ gfx::Rect(0, 0, 200, 200), false));
+
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
+ RunPendingMessages();
+}
+
+// This test validates that when a top level owned popup Aura window is
+// resized, the widget is resized as well.
+TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupResizeTest) {
+ ViewsDelegate::views_delegate = NULL;
+ DesktopAuraTopLevelWindowTest popup_window;
+ ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
+ gfx::Rect(0, 0, 200, 200), false));
+
+ gfx::Rect new_size(0, 0, 400, 400);
+ popup_window.owned_window()->SetBounds(new_size);
+
+ EXPECT_EQ(popup_window.top_level_widget()->GetNativeView()->bounds().size(),
+ new_size.size());
+ RunPendingMessages();
+ ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
+ RunPendingMessages();
+}
+
+} // namespace test
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h
deleted file mode 100644
index c66cee9254c..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host.h
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/root_window.h"
-#include "ui/base/ui_base_types.h"
-#include "ui/views/views_export.h"
-#include "ui/views/widget/widget.h"
-
-namespace aura {
-class RootWindowHost;
-class Window;
-
-namespace client {
-class DragDropClient;
-}
-}
-
-namespace gfx {
-class ImageSkia;
-class Rect;
-}
-
-namespace ui {
-class NativeTheme;
-}
-
-namespace views {
-namespace corewm {
-
-class Tooltip;
-}
-
-namespace internal {
-class NativeWidgetDelegate;
-}
-
-class DesktopNativeCursorManager;
-class DesktopNativeWidgetAura;
-
-class VIEWS_EXPORT DesktopRootWindowHost {
- public:
- virtual ~DesktopRootWindowHost() {}
-
- static DesktopRootWindowHost* Create(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura);
-
- // Return the NativeTheme to use for |window|. WARNING: |window| may be NULL.
- static ui::NativeTheme* GetNativeTheme(aura::Window* window);
-
- // Sets up resources needed before the RootWindow has been created.
- virtual void Init(aura::Window* content_window,
- const Widget::InitParams& params,
- aura::RootWindow::CreateParams* rw_create_params) = 0;
-
- // Invoked once the RootWindow has been created. Caller owns the RootWindow.
- virtual void OnRootWindowCreated(aura::RootWindow* root,
- const Widget::InitParams& params) = 0;
-
- // Creates and returns the Tooltip implementation to use. Return value is
- // owned by DesktopNativeWidgetAura and lives as long as
- // DesktopRootWindowHost.
- virtual scoped_ptr<corewm::Tooltip> CreateTooltip() = 0;
-
- // Creates and returns the DragDropClient implementation to use. Return value
- // is owned by DesktopNativeWidgetAura and lives as long as
- // DesktopRootWindowHost.
- virtual scoped_ptr<aura::client::DragDropClient> CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) = 0;
-
- virtual void Close() = 0;
- virtual void CloseNow() = 0;
-
- virtual aura::RootWindowHost* AsRootWindowHost() = 0;
-
- virtual void ShowWindowWithState(ui::WindowShowState show_state) = 0;
- virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
-
- virtual bool IsVisible() const = 0;
-
- virtual void SetSize(const gfx::Size& size) = 0;
- virtual void StackAtTop() = 0;
- virtual void CenterWindow(const gfx::Size& size) = 0;
- virtual void GetWindowPlacement(gfx::Rect* bounds,
- ui::WindowShowState* show_state) const = 0;
- virtual gfx::Rect GetWindowBoundsInScreen() const = 0;
- virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0;
- virtual gfx::Rect GetRestoredBounds() const = 0;
-
- virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
-
- // Sets the shape of the root window. If |native_region| is NULL then the
- // window reverts to rectangular. Takes ownership of |native_region|.
- virtual void SetShape(gfx::NativeRegion native_region) = 0;
-
- virtual void Activate() = 0;
- virtual void Deactivate() = 0;
- virtual bool IsActive() const = 0;
- virtual void Maximize() = 0;
- virtual void Minimize() = 0;
- virtual void Restore() = 0;
- virtual bool IsMaximized() const = 0;
- virtual bool IsMinimized() const = 0;
-
- virtual bool HasCapture() const = 0;
-
- virtual void SetAlwaysOnTop(bool always_on_top) = 0;
- virtual bool IsAlwaysOnTop() const = 0;
-
- // Returns true if the title changed.
- virtual bool SetWindowTitle(const string16& title) = 0;
-
- virtual void ClearNativeFocus() = 0;
-
- virtual Widget::MoveLoopResult RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) = 0;
- virtual void EndMoveLoop() = 0;
-
- virtual void SetVisibilityChangedAnimationsEnabled(bool value) = 0;
-
- virtual bool ShouldUseNativeFrame() = 0;
- virtual void FrameTypeChanged() = 0;
- virtual NonClientFrameView* CreateNonClientFrameView() = 0;
-
- virtual void SetFullscreen(bool fullscreen) = 0;
- virtual bool IsFullscreen() const = 0;
-
- virtual void SetOpacity(unsigned char opacity) = 0;
-
- virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
- const gfx::ImageSkia& app_icon) = 0;
-
- virtual void InitModalType(ui::ModalType modal_type) = 0;
-
- virtual void FlashFrame(bool flash_frame) = 0;
-
- virtual void OnRootViewLayout() const = 0;
-
- // Called when the DesktopNativeWidgetAura's aura::Window is focused and
- // blurred.
- virtual void OnNativeWidgetFocus() = 0;
- virtual void OnNativeWidgetBlur() = 0;
-
- // Returns true if the Widget was closed but is still showing because of
- // animations.
- virtual bool IsAnimatingClosed() const = 0;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h
deleted file mode 100644
index f430b38c20d..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
-
-#include "ui/views/views_export.h"
-
-namespace views {
-
-// Allows for the observation of lower level window events.
-class VIEWS_EXPORT DesktopRootWindowHostObserverX11 {
- public:
- virtual ~DesktopRootWindowHostObserverX11() {}
-
- // Called after we receive a MapNotify event (the X11 server has allocated
- // resources for it).
- virtual void OnWindowMapped(unsigned long xid) = 0;
-
- // Called after we receive an UnmapNotify event (the X11 server has freed
- // resources for it).
- virtual void OnWindowUnmapped(unsigned long xid) = 0;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_OBSERVER_X11_H_
-
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc
deleted file mode 100644
index ffca2a6337c..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_ozone.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/aura/window_tree_host.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
-#include "ui/views/widget/desktop_aura/desktop_factory_ozone.h"
-
-namespace views {
-
-DesktopRootWindowHost* DesktopRootWindowHost::Create(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura) {
- DesktopFactoryOzone* d_factory = DesktopFactoryOzone::GetInstance();
-
- return d_factory->CreateRootWindowHost(native_widget_delegate,
- desktop_native_widget_aura);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
deleted file mode 100644
index 938a05b2c4b..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
+++ /dev/null
@@ -1,992 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
-
-#include "base/win/metro.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/cursor/cursor_loader_win.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/win/tsf_bridge.h"
-#include "ui/base/win/shell.h"
-#include "ui/compositor/compositor_constants.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/path_win.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/native_theme/native_theme_aura.h"
-#include "ui/native_theme/native_theme_win.h"
-#include "ui/views/corewm/compound_event_filter.h"
-#include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/input_method_event_filter.h"
-#include "ui/views/corewm/tooltip_win.h"
-#include "ui/views/corewm/window_animations.h"
-#include "ui/views/ime/input_method_bridge.h"
-#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
-#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
-#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/widget/widget_hwnd_utils.h"
-#include "ui/views/win/fullscreen_handler.h"
-#include "ui/views/win/hwnd_message_handler.h"
-#include "ui/views/window/native_frame_view.h"
-
-namespace views {
-
-namespace {
-
-gfx::Size GetExpandedWindowSize(DWORD window_style, gfx::Size size) {
- if (!(window_style & WS_EX_COMPOSITED) || !ui::win::IsAeroGlassEnabled())
- return size;
-
- // Some AMD drivers can't display windows that are less than 64x64 pixels,
- // so expand them to be at least that size. http://crbug.com/286609
- gfx::Size expanded(std::max(size.width(), 64), std::max(size.height(), 64));
- return expanded;
-}
-
-void InsetBottomRight(gfx::Rect* rect, gfx::Vector2d vector) {
- rect->Inset(0, 0, vector.x(), vector.y());
-}
-
-} // namespace
-
-DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kContentWindowForRootWindow, NULL);
-
-// Identifies the DesktopRootWindowHostWin associated with the RootWindow.
-DEFINE_WINDOW_PROPERTY_KEY(DesktopRootWindowHostWin*, kDesktopRootWindowHostKey,
- NULL);
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, public:
-
-DesktopRootWindowHostWin::DesktopRootWindowHostWin(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura)
- : root_window_(NULL),
- 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),
- has_non_client_view_(false),
- tooltip_(NULL),
- is_cursor_visible_(true) {
-}
-
-DesktopRootWindowHostWin::~DesktopRootWindowHostWin() {
- // WARNING: |content_window_| has been destroyed by the time we get here.
- desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(
- root_window_);
-}
-
-// static
-aura::Window* DesktopRootWindowHostWin::GetContentWindowForHWND(HWND hwnd) {
- aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(hwnd);
- return root ? root->window()->GetProperty(kContentWindowForRootWindow) : NULL;
-}
-
-// static
-ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
- // Use NativeThemeWin for windows shown on the desktop, those not on the
- // desktop come from Ash and get NativeThemeAura.
- aura::WindowEventDispatcher* dispatcher =
- window ? window->GetDispatcher() : NULL;
- if (dispatcher) {
- HWND host_hwnd = dispatcher->host()->GetAcceleratedWidget();
- if (host_hwnd &&
- DesktopRootWindowHostWin::GetContentWindowForHWND(host_hwnd)) {
- return ui::NativeThemeWin::instance();
- }
- }
- return ui::NativeThemeAura::instance();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, DesktopRootWindowHost implementation:
-
-void DesktopRootWindowHostWin::Init(
- aura::Window* content_window,
- const Widget::InitParams& params,
- aura::RootWindow::CreateParams* rw_create_params) {
- // TODO(beng): SetInitParams().
- content_window_ = content_window;
-
- aura::client::SetAnimationHost(content_window_, this);
-
- ConfigureWindowStyles(message_handler_.get(), params,
- GetWidget()->widget_delegate(),
- native_widget_delegate_);
-
- HWND parent_hwnd = NULL;
- if (params.parent && params.parent->GetDispatcher()) {
- parent_hwnd =
- params.parent->GetDispatcher()->host()->GetAcceleratedWidget();
- }
-
- message_handler_->set_remove_standard_frame(params.remove_standard_frame);
-
- has_non_client_view_ = Widget::RequiresNonClientView(params.type);
-
- if (params.type == Widget::InitParams::TYPE_MENU) {
- ::SetProp(GetAcceleratedWidget(),
- kForceSoftwareCompositor,
- reinterpret_cast<HANDLE>(true));
- }
-
- gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
- message_handler_->Init(parent_hwnd, pixel_bounds);
-
- rw_create_params->host = this;
-}
-
-void DesktopRootWindowHostWin::OnRootWindowCreated(
- aura::RootWindow* root,
- const Widget::InitParams& params) {
- root_window_ = root;
-
- root_window_->window()->SetProperty(kContentWindowForRootWindow,
- content_window_);
- root_window_->window()->SetProperty(kDesktopRootWindowHostKey, this);
-
- should_animate_window_close_ =
- content_window_->type() != aura::client::WINDOW_TYPE_NORMAL &&
- !views::corewm::WindowAnimationsDisabled(content_window_);
-
-// TODO this is not invoked *after* Init(), but should be ok.
- SetWindowTransparency();
-}
-
-scoped_ptr<corewm::Tooltip> DesktopRootWindowHostWin::CreateTooltip() {
- DCHECK(!tooltip_);
- tooltip_ = new corewm::TooltipWin(GetAcceleratedWidget());
- return scoped_ptr<corewm::Tooltip>(tooltip_);
-}
-
-scoped_ptr<aura::client::DragDropClient>
-DesktopRootWindowHostWin::CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) {
- drag_drop_client_ = new DesktopDragDropClientWin(root_window_->window(),
- GetHWND());
- return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
-}
-
-void DesktopRootWindowHostWin::Close() {
- // TODO(beng): Move this entire branch to DNWA so it can be shared with X11.
- if (should_animate_window_close_) {
- pending_close_ = true;
- const bool is_animating =
- content_window_->layer()->GetAnimator()->IsAnimatingProperty(
- ui::LayerAnimationElement::VISIBILITY);
- // Animation may not start for a number of reasons.
- if (!is_animating)
- message_handler_->Close();
- // else case, OnWindowHidingAnimationCompleted does the actual Close.
- } else {
- message_handler_->Close();
- }
-}
-
-void DesktopRootWindowHostWin::CloseNow() {
- message_handler_->CloseNow();
-}
-
-aura::RootWindowHost* DesktopRootWindowHostWin::AsRootWindowHost() {
- return this;
-}
-
-void DesktopRootWindowHostWin::ShowWindowWithState(
- ui::WindowShowState show_state) {
- message_handler_->ShowWindowWithState(show_state);
-}
-
-void DesktopRootWindowHostWin::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds);
- message_handler_->ShowMaximizedWithBounds(pixel_bounds);
-}
-
-bool DesktopRootWindowHostWin::IsVisible() const {
- return message_handler_->IsVisible();
-}
-
-void DesktopRootWindowHostWin::SetSize(const gfx::Size& size) {
- gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
- gfx::Size expanded = GetExpandedWindowSize(
- message_handler_->window_ex_style(), size_in_pixels);
- window_enlargement_ =
- gfx::Vector2d(expanded.width() - size_in_pixels.width(),
- expanded.height() - size_in_pixels.height());
- message_handler_->SetSize(expanded);
-}
-
-void DesktopRootWindowHostWin::StackAtTop() {
- message_handler_->StackAtTop();
-}
-
-void DesktopRootWindowHostWin::CenterWindow(const gfx::Size& size) {
- gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
- gfx::Size expanded_size;
- expanded_size = GetExpandedWindowSize(message_handler_->window_ex_style(),
- size_in_pixels);
- window_enlargement_ =
- gfx::Vector2d(expanded_size.width() - size_in_pixels.width(),
- expanded_size.height() - size_in_pixels.height());
- message_handler_->CenterWindow(expanded_size);
-}
-
-void DesktopRootWindowHostWin::GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const {
- message_handler_->GetWindowPlacement(bounds, show_state);
- InsetBottomRight(bounds, window_enlargement_);
- *bounds = gfx::win::ScreenToDIPRect(*bounds);
-}
-
-gfx::Rect DesktopRootWindowHostWin::GetWindowBoundsInScreen() const {
- gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen();
- InsetBottomRight(&pixel_bounds, window_enlargement_);
- return gfx::win::ScreenToDIPRect(pixel_bounds);
-}
-
-gfx::Rect DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() const {
- gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen();
- InsetBottomRight(&pixel_bounds, window_enlargement_);
- return gfx::win::ScreenToDIPRect(pixel_bounds);
-}
-
-gfx::Rect DesktopRootWindowHostWin::GetRestoredBounds() const {
- gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds();
- InsetBottomRight(&pixel_bounds, window_enlargement_);
- return gfx::win::ScreenToDIPRect(pixel_bounds);
-}
-
-gfx::Rect DesktopRootWindowHostWin::GetWorkAreaBoundsInScreen() const {
- MONITORINFO monitor_info;
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(MonitorFromWindow(message_handler_->hwnd(),
- MONITOR_DEFAULTTONEAREST),
- &monitor_info);
- gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork);
- return gfx::win::ScreenToDIPRect(pixel_bounds);
-}
-
-void DesktopRootWindowHostWin::SetShape(gfx::NativeRegion native_region) {
- if (native_region) {
- message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*native_region));
- } else {
- message_handler_->SetRegion(NULL);
- }
-
- delete native_region;
-}
-
-void DesktopRootWindowHostWin::Activate() {
- message_handler_->Activate();
-}
-
-void DesktopRootWindowHostWin::Deactivate() {
- message_handler_->Deactivate();
-}
-
-bool DesktopRootWindowHostWin::IsActive() const {
- return message_handler_->IsActive();
-}
-
-void DesktopRootWindowHostWin::Maximize() {
- message_handler_->Maximize();
-}
-
-void DesktopRootWindowHostWin::Minimize() {
- message_handler_->Minimize();
-}
-
-void DesktopRootWindowHostWin::Restore() {
- message_handler_->Restore();
-}
-
-bool DesktopRootWindowHostWin::IsMaximized() const {
- return message_handler_->IsMaximized();
-}
-
-bool DesktopRootWindowHostWin::IsMinimized() const {
- return message_handler_->IsMinimized();
-}
-
-bool DesktopRootWindowHostWin::HasCapture() const {
- return message_handler_->HasCapture();
-}
-
-void DesktopRootWindowHostWin::SetAlwaysOnTop(bool always_on_top) {
- message_handler_->SetAlwaysOnTop(always_on_top);
-}
-
-bool DesktopRootWindowHostWin::IsAlwaysOnTop() const {
- return message_handler_->IsAlwaysOnTop();
-}
-
-bool DesktopRootWindowHostWin::SetWindowTitle(const string16& title) {
- return message_handler_->SetTitle(title);
-}
-
-void DesktopRootWindowHostWin::ClearNativeFocus() {
- message_handler_->ClearNativeFocus();
-}
-
-Widget::MoveLoopResult DesktopRootWindowHostWin::RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) {
- const bool hide_on_escape =
- escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE;
- return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ?
- Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
-}
-
-void DesktopRootWindowHostWin::EndMoveLoop() {
- message_handler_->EndMoveLoop();
-}
-
-void DesktopRootWindowHostWin::SetVisibilityChangedAnimationsEnabled(
- bool value) {
- message_handler_->SetVisibilityChangedAnimationsEnabled(value);
- content_window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
-}
-
-bool DesktopRootWindowHostWin::ShouldUseNativeFrame() {
- return ui::win::IsAeroGlassEnabled();
-}
-
-void DesktopRootWindowHostWin::FrameTypeChanged() {
- message_handler_->FrameTypeChanged();
- SetWindowTransparency();
-}
-
-NonClientFrameView* DesktopRootWindowHostWin::CreateNonClientFrameView() {
- return GetWidget()->ShouldUseNativeFrame() ?
- new NativeFrameView(GetWidget()) : NULL;
-}
-
-void DesktopRootWindowHostWin::SetFullscreen(bool fullscreen) {
- message_handler_->fullscreen_handler()->SetFullscreen(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())
- content_window_->Show();
- SetWindowTransparency();
-}
-
-bool DesktopRootWindowHostWin::IsFullscreen() const {
- return message_handler_->fullscreen_handler()->fullscreen();
-}
-
-void DesktopRootWindowHostWin::SetOpacity(unsigned char opacity) {
- message_handler_->SetOpacity(static_cast<BYTE>(opacity));
- content_window_->layer()->SetOpacity(opacity / 255.0);
-}
-
-void DesktopRootWindowHostWin::SetWindowIcons(
- const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
- message_handler_->SetWindowIcons(window_icon, app_icon);
-}
-
-void DesktopRootWindowHostWin::InitModalType(ui::ModalType modal_type) {
- message_handler_->InitModalType(modal_type);
-}
-
-void DesktopRootWindowHostWin::FlashFrame(bool flash_frame) {
- message_handler_->FlashFrame(flash_frame);
-}
-
-void DesktopRootWindowHostWin::OnRootViewLayout() const {
-}
-
-void DesktopRootWindowHostWin::OnNativeWidgetFocus() {
- // HWNDMessageHandler will perform the proper updating on its own.
-}
-
-void DesktopRootWindowHostWin::OnNativeWidgetBlur() {
-}
-
-bool DesktopRootWindowHostWin::IsAnimatingClosed() const {
- return pending_close_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, RootWindowHost implementation:
-
-aura::RootWindow* DesktopRootWindowHostWin::GetRootWindow() {
- return root_window_;
-}
-
-gfx::AcceleratedWidget DesktopRootWindowHostWin::GetAcceleratedWidget() {
- return message_handler_->hwnd();
-}
-
-void DesktopRootWindowHostWin::Show() {
- message_handler_->Show();
-}
-
-void DesktopRootWindowHostWin::Hide() {
- if (!pending_close_)
- message_handler_->Hide();
-}
-
-void DesktopRootWindowHostWin::ToggleFullScreen() {
- SetWindowTransparency();
-}
-
-// GetBounds and SetBounds work in pixel coordinates, whereas other get/set
-// methods work in DIP.
-
-gfx::Rect DesktopRootWindowHostWin::GetBounds() const {
- gfx::Rect bounds(message_handler_->GetClientAreaBounds());
- // If the window bounds were expanded we need to return the original bounds
- // To achieve this we do the reverse of the expansion, i.e. add the
- // window_expansion_top_left_delta_ to the origin and subtract the
- // window_expansion_bottom_right_delta_ from the width and height.
- gfx::Rect without_expansion(
- bounds.x() + window_expansion_top_left_delta_.x(),
- bounds.y() + window_expansion_top_left_delta_.y(),
- bounds.width() - window_expansion_bottom_right_delta_.x() -
- window_enlargement_.x(),
- bounds.height() - window_expansion_bottom_right_delta_.y() -
- window_enlargement_.y());
- return without_expansion;
-}
-
-void DesktopRootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
- // If the window bounds have to be expanded we need to subtract the
- // window_expansion_top_left_delta_ from the origin and add the
- // window_expansion_bottom_right_delta_ to the width and height
- gfx::Size old_hwnd_size(message_handler_->GetClientAreaBounds().size());
- gfx::Size old_content_size = GetBounds().size();
-
- gfx::Rect expanded(
- bounds.x() - window_expansion_top_left_delta_.x(),
- bounds.y() - window_expansion_top_left_delta_.y(),
- bounds.width() + window_expansion_bottom_right_delta_.x(),
- bounds.height() + window_expansion_bottom_right_delta_.y());
-
- gfx::Rect new_expanded(
- expanded.origin(),
- GetExpandedWindowSize(message_handler_->window_ex_style(),
- expanded.size()));
- window_enlargement_ =
- gfx::Vector2d(new_expanded.width() - expanded.width(),
- new_expanded.height() - expanded.height());
- message_handler_->SetBounds(new_expanded);
-
- // The client area size may have changed even though the window bounds have
- // not, if the window bounds were expanded to 64 pixels both times.
- if (old_hwnd_size == new_expanded.size() && old_content_size != bounds.size())
- HandleClientSizeChanged(new_expanded.size());
-}
-
-gfx::Insets DesktopRootWindowHostWin::GetInsets() const {
- return gfx::Insets();
-}
-
-void DesktopRootWindowHostWin::SetInsets(const gfx::Insets& insets) {
-}
-
-gfx::Point DesktopRootWindowHostWin::GetLocationOnNativeScreen() const {
- return GetBounds().origin();
-}
-
-void DesktopRootWindowHostWin::SetCapture() {
- message_handler_->SetCapture();
-}
-
-void DesktopRootWindowHostWin::ReleaseCapture() {
- message_handler_->ReleaseCapture();
-}
-
-void DesktopRootWindowHostWin::SetCursor(gfx::NativeCursor cursor) {
- ui::CursorLoaderWin cursor_loader;
- cursor_loader.SetPlatformCursor(&cursor);
-
- message_handler_->SetCursor(cursor.platform());
-}
-
-bool DesktopRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root_window_->window());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
- *location_return = gfx::Point(0, 0);
- return false;
- }
- POINT pt = {0};
- ::GetCursorPos(&pt);
- *location_return =
- gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y));
- return true;
-}
-
-bool DesktopRootWindowHostWin::ConfineCursorToRootWindow() {
- RECT window_rect = root_window_->window()->GetBoundsInScreen().ToRECT();
- ::ClipCursor(&window_rect);
- return true;
-}
-
-void DesktopRootWindowHostWin::UnConfineCursor() {
- ::ClipCursor(NULL);
-}
-
-void DesktopRootWindowHostWin::OnCursorVisibilityChanged(bool show) {
- if (is_cursor_visible_ == show)
- return;
- is_cursor_visible_ = show;
- ::ShowCursor(!!show);
-}
-
-void DesktopRootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
- POINT cursor_location = location.ToPOINT();
- ::ClientToScreen(GetHWND(), &cursor_location);
- ::SetCursorPos(cursor_location.x, cursor_location.y);
-}
-
-void DesktopRootWindowHostWin::PostNativeEvent(
- const base::NativeEvent& native_event) {
-}
-
-void DesktopRootWindowHostWin::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
-}
-
-void DesktopRootWindowHostWin::PrepareForShutdown() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, aura::AnimationHost implementation:
-
-void DesktopRootWindowHostWin::SetHostTransitionOffsets(
- const gfx::Vector2d& top_left_delta,
- const gfx::Vector2d& bottom_right_delta) {
- gfx::Rect bounds_without_expansion = GetBounds();
- window_expansion_top_left_delta_ = top_left_delta;
- window_expansion_bottom_right_delta_ = bottom_right_delta;
- SetBounds(bounds_without_expansion);
-}
-
-void DesktopRootWindowHostWin::OnWindowHidingAnimationCompleted() {
- if (pending_close_)
- message_handler_->Close();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, HWNDMessageHandlerDelegate implementation:
-
-bool DesktopRootWindowHostWin::IsWidgetWindow() const {
- return has_non_client_view_;
-}
-
-bool DesktopRootWindowHostWin::IsUsingCustomFrame() const {
- return !GetWidget()->ShouldUseNativeFrame();
-}
-
-void DesktopRootWindowHostWin::SchedulePaint() {
- GetWidget()->GetRootView()->SchedulePaint();
-}
-
-void DesktopRootWindowHostWin::EnableInactiveRendering() {
- native_widget_delegate_->EnableInactiveRendering();
-}
-
-bool DesktopRootWindowHostWin::IsInactiveRenderingDisabled() {
- return native_widget_delegate_->IsInactiveRenderingDisabled();
-}
-
-bool DesktopRootWindowHostWin::CanResize() const {
- return GetWidget()->widget_delegate()->CanResize();
-}
-
-bool DesktopRootWindowHostWin::CanMaximize() const {
- return GetWidget()->widget_delegate()->CanMaximize();
-}
-
-bool DesktopRootWindowHostWin::CanActivate() const {
- if (IsModalWindowActive())
- return true;
- return native_widget_delegate_->CanActivate();
-}
-
-bool DesktopRootWindowHostWin::WidgetSizeIsClientSize() const {
- const Widget* widget = GetWidget()->GetTopLevelWidget();
- return IsMaximized() || (widget && widget->ShouldUseNativeFrame());
-}
-
-bool DesktopRootWindowHostWin::CanSaveFocus() const {
- return GetWidget()->is_top_level();
-}
-
-void DesktopRootWindowHostWin::SaveFocusOnDeactivate() {
- GetWidget()->GetFocusManager()->StoreFocusedView(true);
-}
-
-void DesktopRootWindowHostWin::RestoreFocusOnActivate() {
- RestoreFocusOnEnable();
-}
-
-void DesktopRootWindowHostWin::RestoreFocusOnEnable() {
- GetWidget()->GetFocusManager()->RestoreFocusedView();
-}
-
-bool DesktopRootWindowHostWin::IsModal() const {
- return native_widget_delegate_->IsModal();
-}
-
-int DesktopRootWindowHostWin::GetInitialShowState() const {
- return SW_SHOWNORMAL;
-}
-
-bool DesktopRootWindowHostWin::WillProcessWorkAreaChange() const {
- return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
-}
-
-int DesktopRootWindowHostWin::GetNonClientComponent(
- const gfx::Point& point) const {
- gfx::Point dip_position = gfx::win::ScreenToDIPPoint(point);
- return native_widget_delegate_->GetNonClientComponent(dip_position);
-}
-
-void DesktopRootWindowHostWin::GetWindowMask(const gfx::Size& size,
- gfx::Path* path) {
- if (GetWidget()->non_client_view()) {
- GetWidget()->non_client_view()->GetWindowMask(size, path);
- } else if (!window_enlargement_.IsZero()) {
- gfx::Rect bounds(WidgetSizeIsClientSize()
- ? message_handler_->GetClientAreaBoundsInScreen()
- : message_handler_->GetWindowBoundsInScreen());
- InsetBottomRight(&bounds, window_enlargement_);
- path->addRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
- }
-}
-
-bool DesktopRootWindowHostWin::GetClientAreaInsets(gfx::Insets* insets) const {
- return false;
-}
-
-void DesktopRootWindowHostWin::GetMinMaxSize(gfx::Size* min_size,
- gfx::Size* max_size) const {
- *min_size = native_widget_delegate_->GetMinimumSize();
- *max_size = native_widget_delegate_->GetMaximumSize();
-}
-
-gfx::Size DesktopRootWindowHostWin::GetRootViewSize() const {
- return GetWidget()->GetRootView()->size();
-}
-
-void DesktopRootWindowHostWin::ResetWindowControls() {
- GetWidget()->non_client_view()->ResetWindowControls();
-}
-
-void DesktopRootWindowHostWin::PaintLayeredWindow(gfx::Canvas* canvas) {
- GetWidget()->GetRootView()->Paint(canvas);
-}
-
-gfx::NativeViewAccessible DesktopRootWindowHostWin::GetNativeViewAccessible() {
- return GetWidget()->GetRootView()->GetNativeViewAccessible();
-}
-
-InputMethod* DesktopRootWindowHostWin::GetInputMethod() {
- return GetWidget()->GetInputMethodDirect();
-}
-
-bool DesktopRootWindowHostWin::ShouldHandleSystemCommands() const {
- return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
-}
-
-void DesktopRootWindowHostWin::HandleAppDeactivated() {
- native_widget_delegate_->EnableInactiveRendering();
-}
-
-void DesktopRootWindowHostWin::HandleActivationChanged(bool active) {
- // This can be invoked from HWNDMessageHandler::Init(), at which point we're
- // not in a good state and need to ignore it.
- if (!delegate_)
- return;
-
- if (active)
- delegate_->OnHostActivated();
- desktop_native_widget_aura_->HandleActivationChanged(active);
-}
-
-bool DesktopRootWindowHostWin::HandleAppCommand(short command) {
- // We treat APPCOMMAND ids as an extension of our command namespace, and just
- // let the delegate figure out what to do...
- return GetWidget()->widget_delegate() &&
- GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
-}
-
-void DesktopRootWindowHostWin::HandleCancelMode() {
- delegate_->OnHostCancelMode();
-}
-
-void DesktopRootWindowHostWin::HandleCaptureLost() {
- delegate_->OnHostLostWindowCapture();
- native_widget_delegate_->OnMouseCaptureLost();
-}
-
-void DesktopRootWindowHostWin::HandleClose() {
- GetWidget()->Close();
-}
-
-bool DesktopRootWindowHostWin::HandleCommand(int command) {
- return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
-}
-
-void DesktopRootWindowHostWin::HandleAccelerator(
- const ui::Accelerator& accelerator) {
- GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
-}
-
-void DesktopRootWindowHostWin::HandleCreate() {
- // TODO(beng): moar
- NOTIMPLEMENTED();
-
- native_widget_delegate_->OnNativeWidgetCreated(true);
-
- // 1. Window property association
- // 2. MouseWheel.
-}
-
-void DesktopRootWindowHostWin::HandleDestroying() {
- drag_drop_client_->OnNativeWidgetDestroying(GetHWND());
- native_widget_delegate_->OnNativeWidgetDestroying();
-}
-
-void DesktopRootWindowHostWin::HandleDestroyed() {
- desktop_native_widget_aura_->OnHostClosed();
-}
-
-bool DesktopRootWindowHostWin::HandleInitialFocus() {
- return GetWidget()->SetInitialFocus();
-}
-
-void DesktopRootWindowHostWin::HandleDisplayChange() {
- GetWidget()->widget_delegate()->OnDisplayChanged();
-}
-
-void DesktopRootWindowHostWin::HandleBeginWMSizeMove() {
- native_widget_delegate_->OnNativeWidgetBeginUserBoundsChange();
-}
-
-void DesktopRootWindowHostWin::HandleEndWMSizeMove() {
- native_widget_delegate_->OnNativeWidgetEndUserBoundsChange();
-}
-
-void DesktopRootWindowHostWin::HandleMove() {
- native_widget_delegate_->OnNativeWidgetMove();
- if (delegate_)
- delegate_->OnHostMoved(GetBounds().origin());
-}
-
-void DesktopRootWindowHostWin::HandleWorkAreaChanged() {
- GetWidget()->widget_delegate()->OnWorkAreaChanged();
-}
-
-void DesktopRootWindowHostWin::HandleVisibilityChanging(bool visible) {
- native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible);
-}
-
-void DesktopRootWindowHostWin::HandleVisibilityChanged(bool visible) {
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
-}
-
-void DesktopRootWindowHostWin::HandleClientSizeChanged(
- const gfx::Size& new_size) {
- if (delegate_)
- delegate_->OnHostResized(new_size);
-}
-
-void DesktopRootWindowHostWin::HandleFrameChanged() {
- SetWindowTransparency();
- // Replace the frame and layout the contents.
- GetWidget()->non_client_view()->UpdateFrame();
-}
-
-void DesktopRootWindowHostWin::HandleNativeFocus(HWND last_focused_window) {
- // TODO(beng): inform the native_widget_delegate_.
- InputMethod* input_method = GetInputMethod();
- if (input_method)
- input_method->OnFocus();
-}
-
-void DesktopRootWindowHostWin::HandleNativeBlur(HWND focused_window) {
- // TODO(beng): inform the native_widget_delegate_.
- InputMethod* input_method = GetInputMethod();
- if (input_method)
- input_method->OnBlur();
-}
-
-bool DesktopRootWindowHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
- if (base::win::IsTSFAwareRequired() && event.IsAnyButton())
- ui::TSFBridge::GetInstance()->CancelComposition();
- return delegate_->OnHostMouseEvent(const_cast<ui::MouseEvent*>(&event));
-}
-
-bool DesktopRootWindowHostWin::HandleKeyEvent(const ui::KeyEvent& event) {
- return false;
-}
-
-bool DesktopRootWindowHostWin::HandleUntranslatedKeyEvent(
- const ui::KeyEvent& event) {
- ui::KeyEvent duplicate_event(event);
- return delegate_->OnHostKeyEvent(&duplicate_event);
-}
-
-void DesktopRootWindowHostWin::HandleTouchEvent(
- const ui::TouchEvent& event) {
- // HWNDMessageHandler asynchronously processes touch events. Because of this
- // it's possible for the aura::RootWindow to have been destroyed by the time
- // we attempt to process them.
- if (!GetWidget()->GetNativeView())
- return;
-
- // Currently we assume the window that has capture gets touch events too.
- aura::RootWindow* root =
- aura::RootWindow::GetForAcceleratedWidget(GetCapture());
- if (root) {
- DesktopRootWindowHostWin* target =
- root->window()->GetProperty(kDesktopRootWindowHostKey);
- if (target && target->HasCapture() && target != this) {
- POINT target_location(event.location().ToPOINT());
- ClientToScreen(GetHWND(), &target_location);
- ScreenToClient(target->GetHWND(), &target_location);
- 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());
- target->delegate_->OnHostTouchEvent(&target_event);
- return;
- }
- }
- delegate_->OnHostTouchEvent(
- const_cast<ui::TouchEvent*>(&event));
-}
-
-bool DesktopRootWindowHostWin::HandleIMEMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- MSG msg = {};
- msg.hwnd = GetHWND();
- msg.message = message;
- msg.wParam = w_param;
- msg.lParam = l_param;
- return desktop_native_widget_aura_->input_method_event_filter()->
- input_method()->OnUntranslatedIMEMessage(msg, result);
-}
-
-void DesktopRootWindowHostWin::HandleInputLanguageChange(
- DWORD character_set,
- HKL input_language_id) {
- desktop_native_widget_aura_->input_method_event_filter()->
- input_method()->OnInputLocaleChanged();
-}
-
-bool DesktopRootWindowHostWin::HandlePaintAccelerated(
- const gfx::Rect& invalid_rect) {
- return native_widget_delegate_->OnNativeWidgetPaintAccelerated(invalid_rect);
-}
-
-void DesktopRootWindowHostWin::HandlePaint(gfx::Canvas* canvas) {
- delegate_->OnHostPaint(gfx::Rect());
-}
-
-bool DesktopRootWindowHostWin::HandleTooltipNotify(int w_param,
- NMHDR* l_param,
- LRESULT* l_result) {
- return tooltip_ && tooltip_->HandleNotify(w_param, l_param, l_result);
-}
-
-void DesktopRootWindowHostWin::HandleTooltipMouseMove(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- // TooltipWin implementation doesn't need this.
- // TODO(sky): remove from HWNDMessageHandler once non-aura path nuked.
-}
-
-bool DesktopRootWindowHostWin::PreHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- return false;
-}
-
-void DesktopRootWindowHostWin::PostHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
-}
-
-bool DesktopRootWindowHostWin::HandleScrollEvent(
- const ui::ScrollEvent& event) {
- return delegate_->OnHostScrollEvent(const_cast<ui::ScrollEvent*>(&event));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostWin, private:
-
-Widget* DesktopRootWindowHostWin::GetWidget() {
- return native_widget_delegate_->AsWidget();
-}
-
-const Widget* DesktopRootWindowHostWin::GetWidget() const {
- return native_widget_delegate_->AsWidget();
-}
-
-HWND DesktopRootWindowHostWin::GetHWND() const {
- return message_handler_->hwnd();
-}
-
-void DesktopRootWindowHostWin::SetWindowTransparency() {
- bool transparent = ShouldUseNativeFrame() && !IsFullscreen();
- root_window_->compositor()->SetHostHasTransparentBackground(transparent);
- root_window_->window()->SetTransparent(transparent);
- content_window_->SetTransparent(transparent);
-}
-
-bool DesktopRootWindowHostWin::IsModalWindowActive() const {
- // This function can get called during window creation which occurs before
- // root_window_ has been created.
- if (!root_window_)
- return false;
-
- aura::Window::Windows::const_iterator index;
- for (index = root_window_->window()->children().begin();
- index != root_window_->window()->children().end();
- ++index) {
- if ((*index)->GetProperty(aura::client::kModalKey) !=
- ui:: MODAL_TYPE_NONE && (*index)->TargetVisibility())
- return true;
- }
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHost, public:
-
-// static
-DesktopRootWindowHost* DesktopRootWindowHost::Create(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura) {
- return new DesktopRootWindowHostWin(native_widget_delegate,
- desktop_native_widget_aura);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
deleted file mode 100644
index e4ed8eaeb8f..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win.h
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
-
-#include "ui/aura/client/animation_host.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/views/views_export.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
-#include "ui/views/win/hwnd_message_handler_delegate.h"
-
-namespace aura {
-namespace client {
-class DragDropClient;
-class FocusClient;
-}
-}
-
-namespace views {
-class DesktopCursorClient;
-class DesktopDragDropClientWin;
-class HWNDMessageHandler;
-
-namespace corewm {
-class TooltipWin;
-}
-
-class VIEWS_EXPORT DesktopRootWindowHostWin
- : public DesktopRootWindowHost,
- public aura::client::AnimationHost,
- public aura::RootWindowHost,
- public HWNDMessageHandlerDelegate {
- public:
- DesktopRootWindowHostWin(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura);
- virtual ~DesktopRootWindowHostWin();
-
- // A way of converting an HWND into a content window.
- static aura::Window* GetContentWindowForHWND(HWND hwnd);
-
- protected:
- // Overridden from DesktopRootWindowHost:
- virtual void Init(aura::Window* content_window,
- const Widget::InitParams& params,
- aura::RootWindow::CreateParams* rw_create_params) OVERRIDE;
- virtual void OnRootWindowCreated(aura::RootWindow* root,
- const Widget::InitParams& params) OVERRIDE;
- virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
- virtual scoped_ptr<aura::client::DragDropClient>
- CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
- virtual void Close() OVERRIDE;
- virtual void CloseNow() OVERRIDE;
- virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
- virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
- virtual void ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) OVERRIDE;
- virtual bool IsVisible() const OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void StackAtTop() OVERRIDE;
- virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
- virtual void GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const OVERRIDE;
- virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
- virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
- virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
- virtual void Activate() OVERRIDE;
- virtual void Deactivate() OVERRIDE;
- virtual bool IsActive() const OVERRIDE;
- virtual void Maximize() OVERRIDE;
- virtual void Minimize() OVERRIDE;
- virtual void Restore() OVERRIDE;
- virtual bool IsMaximized() const OVERRIDE;
- virtual bool IsMinimized() const OVERRIDE;
- virtual bool HasCapture() const OVERRIDE;
- virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
- virtual bool IsAlwaysOnTop() const OVERRIDE;
- virtual bool SetWindowTitle(const string16& title) OVERRIDE;
- virtual void ClearNativeFocus() OVERRIDE;
- virtual Widget::MoveLoopResult RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
- virtual void EndMoveLoop() OVERRIDE;
- virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
- virtual bool ShouldUseNativeFrame() OVERRIDE;
- virtual void FrameTypeChanged() OVERRIDE;
- virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
- virtual void SetFullscreen(bool fullscreen) OVERRIDE;
- virtual bool IsFullscreen() const OVERRIDE;
- virtual void SetOpacity(unsigned char opacity) OVERRIDE;
- virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
- const gfx::ImageSkia& app_icon) OVERRIDE;
- virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
- virtual void FlashFrame(bool flash_frame) OVERRIDE;
- virtual void OnRootViewLayout() const OVERRIDE;
- virtual void OnNativeWidgetFocus() OVERRIDE;
- virtual void OnNativeWidgetBlur() OVERRIDE;
- virtual bool IsAnimatingClosed() const OVERRIDE;
-
- // Overridden from aura::RootWindowHost:
- virtual aura::RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
- // Overridden from aura::client::AnimationHost
- virtual void SetHostTransitionOffsets(
- const gfx::Vector2d& top_left_delta,
- const gfx::Vector2d& bottom_right_delta) OVERRIDE;
- virtual void OnWindowHidingAnimationCompleted() OVERRIDE;
-
- // Overridden from HWNDMessageHandlerDelegate:
- virtual bool IsWidgetWindow() const OVERRIDE;
- virtual bool IsUsingCustomFrame() const OVERRIDE;
- virtual void SchedulePaint() OVERRIDE;
- virtual void EnableInactiveRendering() OVERRIDE;
- virtual bool IsInactiveRenderingDisabled() OVERRIDE;
- virtual bool CanResize() const OVERRIDE;
- virtual bool CanMaximize() const OVERRIDE;
- virtual bool CanActivate() const OVERRIDE;
- virtual bool WidgetSizeIsClientSize() const OVERRIDE;
- virtual bool CanSaveFocus() const OVERRIDE;
- virtual void SaveFocusOnDeactivate() OVERRIDE;
- virtual void RestoreFocusOnActivate() OVERRIDE;
- virtual void RestoreFocusOnEnable() OVERRIDE;
- virtual bool IsModal() const OVERRIDE;
- virtual int GetInitialShowState() const OVERRIDE;
- virtual bool WillProcessWorkAreaChange() const OVERRIDE;
- virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
- virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
- virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
- virtual void GetMinMaxSize(gfx::Size* min_size,
- gfx::Size* max_size) const OVERRIDE;
- virtual gfx::Size GetRootViewSize() const OVERRIDE;
- virtual void ResetWindowControls() OVERRIDE;
- virtual void PaintLayeredWindow(gfx::Canvas* canvas) OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual bool ShouldHandleSystemCommands() const OVERRIDE;
- virtual InputMethod* GetInputMethod() OVERRIDE;
- virtual void HandleAppDeactivated() OVERRIDE;
- virtual void HandleActivationChanged(bool active) OVERRIDE;
- virtual bool HandleAppCommand(short command) OVERRIDE;
- virtual void HandleCancelMode() OVERRIDE;
- virtual void HandleCaptureLost() OVERRIDE;
- virtual void HandleClose() OVERRIDE;
- virtual bool HandleCommand(int command) OVERRIDE;
- virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
- virtual void HandleCreate() OVERRIDE;
- virtual void HandleDestroying() OVERRIDE;
- virtual void HandleDestroyed() OVERRIDE;
- virtual bool HandleInitialFocus() OVERRIDE;
- virtual void HandleDisplayChange() OVERRIDE;
- virtual void HandleBeginWMSizeMove() OVERRIDE;
- virtual void HandleEndWMSizeMove() OVERRIDE;
- virtual void HandleMove() OVERRIDE;
- virtual void HandleWorkAreaChanged() OVERRIDE;
- virtual void HandleVisibilityChanging(bool visible) OVERRIDE;
- virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
- virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
- virtual void HandleFrameChanged() OVERRIDE;
- virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE;
- virtual void HandleNativeBlur(HWND focused_window) OVERRIDE;
- virtual bool HandleMouseEvent(const ui::MouseEvent& event) OVERRIDE;
- virtual bool HandleKeyEvent(const ui::KeyEvent& event) OVERRIDE;
- virtual bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
- virtual void HandleTouchEvent(const ui::TouchEvent& event) OVERRIDE;
- virtual bool HandleIMEMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
- virtual void HandleInputLanguageChange(DWORD character_set,
- HKL input_language_id) OVERRIDE;
- virtual bool HandlePaintAccelerated(const gfx::Rect& invalid_rect) OVERRIDE;
- virtual void HandlePaint(gfx::Canvas* canvas) OVERRIDE;
- virtual bool HandleTooltipNotify(int w_param,
- NMHDR* l_param,
- LRESULT* l_result) OVERRIDE;
- virtual void HandleTooltipMouseMove(UINT message,
- WPARAM w_param,
- LPARAM l_param) OVERRIDE;
- virtual bool PreHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
- virtual void PostHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param) OVERRIDE;
- virtual bool HandleScrollEvent(const ui::ScrollEvent& event) OVERRIDE;
-
- Widget* GetWidget();
- const Widget* GetWidget() const;
- HWND GetHWND() const;
-
- private:
- void SetWindowTransparency();
-
- // Returns true if a modal window is active in the current root window chain.
- bool IsModalWindowActive() const;
-
- // We are owned by the RootWindow, but we have to have a back pointer to it.
- aura::RootWindow* root_window_;
-
- scoped_ptr<HWNDMessageHandler> message_handler_;
- scoped_ptr<aura::client::FocusClient> focus_client_;
-
- // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
- // instead of providing this route back to Widget.
- internal::NativeWidgetDelegate* native_widget_delegate_;
-
- DesktopNativeWidgetAura* desktop_native_widget_aura_;
-
- aura::Window* content_window_;
-
- // Owned by DesktopNativeWidgetAura.
- DesktopDragDropClientWin* drag_drop_client_;
-
- // When certain windows are being shown, we augment the window size
- // temporarily for animation. The following two members contain the top left
- // and bottom right offsets which are used to enlarge the window.
- gfx::Vector2d window_expansion_top_left_delta_;
- gfx::Vector2d window_expansion_bottom_right_delta_;
-
- // Windows are enlarged to be at least 64x64 pixels, so keep track of the
- // extra added here.
- gfx::Vector2d window_enlargement_;
-
- // Whether the window close should be converted to a hide, and then actually
- // closed on the completion of the hide animation. This is cached because
- // the property is set on the contained window which has a shorter lifetime.
- bool should_animate_window_close_;
-
- // When Close()d and animations are being applied to this window, the close
- // of the window needs to be deferred to when the close animation is
- // completed. This variable indicates that a Close was converted to a Hide,
- // so that when the Hide is completed the host window should be closed.
- bool pending_close_;
-
- // True if the widget is going to have a non_client_view. We cache this value
- // rather than asking the Widget for the non_client_view so that we know at
- // Init time, before the Widget has created the NonClientView.
- bool has_non_client_view_;
-
- // Owned by TooltipController, but we need to forward events to it so we keep
- // a reference.
- corewm::TooltipWin* tooltip_;
-
- // State of the cursor.
- bool is_cursor_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(DesktopRootWindowHostWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_WIN_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win_unittest.cc
deleted file mode 100644
index a002f10fdf2..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_win_unittest.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-typedef ViewsTestBase DesktopRootWindowHostWinTest;
-
-namespace {
-
-// See description above SaveFocusOnDeactivateFromHandleCreate.
-class TestDesktopRootWindowHostWin : public DesktopRootWindowHostWin {
- public:
- TestDesktopRootWindowHostWin(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura)
- : DesktopRootWindowHostWin(native_widget_delegate,
- desktop_native_widget_aura) {}
- virtual ~TestDesktopRootWindowHostWin() {}
-
- // DesktopRootWindowHostWin overrides:
- virtual void HandleCreate() OVERRIDE {
- DesktopRootWindowHostWin::HandleCreate();
- SaveFocusOnDeactivate();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestDesktopRootWindowHostWin);
-};
-
-} // namespace
-
-// Verifies if SaveFocusOnDeactivate() is invoked from
-// DesktopRootWindowHostWin::HandleCreate we don't crash.
-TEST_F(DesktopRootWindowHostWinTest, SaveFocusOnDeactivateFromHandleCreate) {
- Widget widget;
- Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
- params.bounds = gfx::Rect(0, 0, 200, 200);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- DesktopNativeWidgetAura* desktop_native_widget_aura =
- new DesktopNativeWidgetAura(&widget);
- params.native_widget = desktop_native_widget_aura;
- params.desktop_root_window_host = new TestDesktopRootWindowHostWin(
- &widget, desktop_native_widget_aura);
- widget.Init(params);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
deleted file mode 100644
index 545e0cde550..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
+++ /dev/null
@@ -1,1544 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
-
-#include <X11/extensions/shape.h>
-#include <X11/extensions/XInput2.h>
-#include <X11/Xatom.h>
-#include <X11/Xregion.h>
-#include <X11/Xutil.h>
-
-#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_pump_x11.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/client/user_action_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/x/device_data_manager.h"
-#include "ui/events/x/device_list_cache_x.h"
-#include "ui/events/x/touch_factory_x11.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_rep.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/path_x11.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/views/corewm/compound_event_filter.h"
-#include "ui/views/corewm/corewm_switches.h"
-#include "ui/views/corewm/tooltip_aura.h"
-#include "ui/views/ime/input_method.h"
-#include "ui/views/linux_ui/linux_ui.h"
-#include "ui/views/views_delegate.h"
-#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
-#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
-#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
-#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
-#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
-#include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
-
-namespace views {
-
-DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
- NULL;
-std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
-
-DEFINE_WINDOW_PROPERTY_KEY(
- aura::Window*, kViewsWindowForRootWindow, NULL);
-
-DEFINE_WINDOW_PROPERTY_KEY(
- DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
-
-namespace {
-
-// Standard Linux mouse buttons for going back and forward.
-const int kBackMouseButton = 8;
-const int kForwardMouseButton = 9;
-
-// Constants that are part of EWMH.
-const int k_NET_WM_STATE_ADD = 1;
-const int k_NET_WM_STATE_REMOVE = 0;
-
-const char* kAtomsToCache[] = {
- "UTF8_STRING",
- "WM_DELETE_WINDOW",
- "WM_PROTOCOLS",
- "WM_S0",
- "_NET_WM_ICON",
- "_NET_WM_NAME",
- "_NET_WM_PID",
- "_NET_WM_PING",
- "_NET_WM_STATE",
- "_NET_WM_STATE_ABOVE",
- "_NET_WM_STATE_FULLSCREEN",
- "_NET_WM_STATE_HIDDEN",
- "_NET_WM_STATE_MAXIMIZED_HORZ",
- "_NET_WM_STATE_MAXIMIZED_VERT",
- "_NET_WM_STATE_SKIP_TASKBAR",
- "_NET_WM_WINDOW_OPACITY",
- "_NET_WM_WINDOW_TYPE",
- "_NET_WM_WINDOW_TYPE_DND",
- "_NET_WM_WINDOW_TYPE_MENU",
- "_NET_WM_WINDOW_TYPE_NORMAL",
- "_NET_WM_WINDOW_TYPE_NOTIFICATION",
- "_NET_WM_WINDOW_TYPE_TOOLTIP",
- "XdndActionAsk",
- "XdndActionCopy"
- "XdndActionLink",
- "XdndActionList",
- "XdndActionMove",
- "XdndActionPrivate",
- "XdndAware",
- "XdndDrop",
- "XdndEnter",
- "XdndFinished",
- "XdndLeave",
- "XdndPosition",
- "XdndProxy", // Proxy windows?
- "XdndSelection",
- "XdndStatus",
- "XdndTypeList",
- NULL
-};
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, public:
-
-DesktopRootWindowHostX11::DesktopRootWindowHostX11(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura)
- : close_widget_factory_(this),
- xdisplay_(gfx::GetXDisplay()),
- xwindow_(0),
- x_root_window_(DefaultRootWindow(xdisplay_)),
- atom_cache_(xdisplay_, kAtomsToCache),
- window_mapped_(false),
- is_fullscreen_(false),
- is_always_on_top_(false),
- root_window_(NULL),
- drag_drop_client_(NULL),
- current_cursor_(ui::kCursorNull),
- native_widget_delegate_(native_widget_delegate),
- desktop_native_widget_aura_(desktop_native_widget_aura),
- content_window_(NULL),
- window_parent_(NULL),
- custom_window_shape_(NULL) {
-}
-
-DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
- root_window_->window()->ClearProperty(kHostForRootWindow);
- aura::client::SetWindowMoveClient(root_window_->window(), NULL);
- desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_);
- if (custom_window_shape_)
- XDestroyRegion(custom_window_shape_);
-}
-
-// static
-aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
- aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
- return root ? root->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
-}
-
-// static
-DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
- aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
- return root ? root->window()->GetProperty(kHostForRootWindow) : NULL;
-}
-
-// static
-std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
- std::vector<aura::Window*> windows(open_windows().size());
- std::transform(open_windows().begin(),
- open_windows().end(),
- windows.begin(),
- GetContentWindowForXID);
- return windows;
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetX11RootWindowBounds() const {
- return bounds_;
-}
-
-void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
- bool active) {
- if (active) {
- delegate_->OnHostActivated();
- open_windows().remove(xwindow_);
- open_windows().insert(open_windows().begin(), xwindow_);
- }
-
- desktop_native_widget_aura_->HandleActivationChanged(active);
-
- native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
-}
-
-void DesktopRootWindowHostX11::AddObserver(
- views::DesktopRootWindowHostObserverX11* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void DesktopRootWindowHostX11::RemoveObserver(
- views::DesktopRootWindowHostObserverX11* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-void DesktopRootWindowHostX11::CleanUpWindowList() {
- delete open_windows_;
- open_windows_ = NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
-
-void DesktopRootWindowHostX11::Init(
- aura::Window* content_window,
- const Widget::InitParams& params,
- aura::RootWindow::CreateParams* rw_create_params) {
- content_window_ = content_window;
-
- // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
- // whether we should be proxying requests to another DRWHL.
-
- // In some situations, views tries to make a zero sized window, and that
- // makes us crash. Make sure we have valid sizes.
- Widget::InitParams sanitized_params = params;
- if (sanitized_params.bounds.width() == 0)
- sanitized_params.bounds.set_width(100);
- if (sanitized_params.bounds.height() == 0)
- sanitized_params.bounds.set_height(100);
-
- InitX11Window(sanitized_params);
-
- rw_create_params->initial_bounds = bounds_;
- rw_create_params->host = this;
-}
-
-void DesktopRootWindowHostX11::OnRootWindowCreated(
- aura::RootWindow* root,
- const Widget::InitParams& params) {
- root_window_ = root;
-
- root_window_->window()->SetProperty(kViewsWindowForRootWindow,
- content_window_);
- root_window_->window()->SetProperty(kHostForRootWindow, this);
- delegate_ = root_window_;
-
- // If we're given a parent, we need to mark ourselves as transient to another
- // window. Otherwise activation gets screwy.
- gfx::NativeView parent = params.parent;
- if (!params.child && params.parent)
- parent->AddTransientChild(content_window_);
-
- // Ensure that the X11DesktopHandler exists so that it dispatches activation
- // messages to us.
- X11DesktopHandler::get();
-
- // TODO(erg): Unify this code once the other consumer goes away.
- x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_, this));
- x11_window_event_filter_->SetUseHostWindowBorders(false);
- desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
- x11_window_event_filter_.get());
-
- x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
- aura::client::SetWindowMoveClient(root_window_->window(),
- x11_window_move_client_.get());
-
- native_widget_delegate_->OnNativeWidgetCreated(true);
-}
-
-scoped_ptr<corewm::Tooltip> DesktopRootWindowHostX11::CreateTooltip() {
- return scoped_ptr<corewm::Tooltip>(
- new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
-}
-
-scoped_ptr<aura::client::DragDropClient>
-DesktopRootWindowHostX11::CreateDragDropClient(
- DesktopNativeCursorManager* cursor_manager) {
- drag_drop_client_ = new DesktopDragDropClientAuraX11(
- root_window_->window(), cursor_manager, xdisplay_, xwindow_);
- return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
-}
-
-void DesktopRootWindowHostX11::Close() {
- // TODO(erg): Might need to do additional hiding tasks here.
-
- if (!close_widget_factory_.HasWeakPtrs()) {
- // And we delay the close so that if we are called from an ATL callback,
- // we don't destroy the window before the callback returned (as the caller
- // may delete ourselves on destroy and the ATL callback would still
- // dereference us when the callback returns).
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DesktopRootWindowHostX11::CloseNow,
- close_widget_factory_.GetWeakPtr()));
- }
-}
-
-void DesktopRootWindowHostX11::CloseNow() {
- if (xwindow_ == None)
- return;
-
- native_widget_delegate_->OnNativeWidgetDestroying();
-
- // If we have children, close them. Use a copy for iteration because they'll
- // remove themselves.
- std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_;
- for (std::set<DesktopRootWindowHostX11*>::iterator it =
- window_children_copy.begin(); it != window_children_copy.end();
- ++it) {
- (*it)->CloseNow();
- }
- DCHECK(window_children_.empty());
-
- // If we have a parent, remove ourselves from its children list.
- if (window_parent_) {
- window_parent_->window_children_.erase(this);
- window_parent_ = NULL;
- }
-
- // Remove the event listeners we've installed. We need to remove these
- // because otherwise we get assert during ~RootWindow().
- desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
- x11_window_event_filter_.get());
-
- open_windows().remove(xwindow_);
- // Actually free our native resources.
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
- XDestroyWindow(xdisplay_, xwindow_);
- xwindow_ = None;
-
- desktop_native_widget_aura_->OnHostClosed();
-}
-
-aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
- return this;
-}
-
-void DesktopRootWindowHostX11::ShowWindowWithState(
- ui::WindowShowState show_state) {
- if (show_state != ui::SHOW_STATE_DEFAULT &&
- show_state != ui::SHOW_STATE_NORMAL) {
- // Only forwarding to Show().
- NOTIMPLEMENTED();
- }
-
- Show();
-}
-
-void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- restored_bounds_ = restored_bounds;
- Maximize();
- Show();
-}
-
-bool DesktopRootWindowHostX11::IsVisible() const {
- return window_mapped_;
-}
-
-void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
- // TODO(erg):
- NOTIMPLEMENTED();
-}
-
-void DesktopRootWindowHostX11::StackAtTop() {
- XRaiseWindow(xdisplay_, xwindow_);
-}
-
-void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
- gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
-
- // If |window_|'s transient parent bounds are big enough to contain |size|,
- // use them instead.
- if (content_window_->transient_parent()) {
- gfx::Rect transient_parent_rect =
- content_window_->transient_parent()->GetBoundsInScreen();
- if (transient_parent_rect.height() >= size.height() &&
- transient_parent_rect.width() >= size.width()) {
- parent_bounds = transient_parent_rect;
- }
- }
-
- gfx::Rect window_bounds(
- parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
- parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
- size.width(),
- size.height());
- // Don't size the window bigger than the parent, otherwise the user may not be
- // able to close or move it.
- window_bounds.AdjustToFit(parent_bounds);
-
- SetBounds(window_bounds);
-}
-
-void DesktopRootWindowHostX11::GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const {
- *bounds = bounds_;
-
- if (IsFullscreen()) {
- *show_state = ui::SHOW_STATE_FULLSCREEN;
- } else if (IsMinimized()) {
- *show_state = ui::SHOW_STATE_MINIMIZED;
- } else if (IsMaximized()) {
- *show_state = ui::SHOW_STATE_MAXIMIZED;
- } else if (!IsActive()) {
- *show_state = ui::SHOW_STATE_INACTIVE;
- } else {
- *show_state = ui::SHOW_STATE_NORMAL;
- }
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
- return bounds_;
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
- // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
- // needed for View::ConvertPointToScreen() to work
- // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
- // asks windows what it thinks the client rect is.
- //
- // Attempts to calculate the rect by asking the NonClientFrameView what it
- // thought its GetBoundsForClientView() were broke combobox drop down
- // placement.
- return bounds_;
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
- // We can't reliably track the restored bounds of a window, but we can get
- // the 90% case down. When *chrome* is the process that requests maximizing
- // or restoring bounds, we can record the current bounds before we request
- // maximization, and clear it when we detect a state change.
- if (!restored_bounds_.IsEmpty())
- return restored_bounds_;
-
- return GetWindowBoundsInScreen();
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
- std::vector<int> value;
- if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
- value.size() >= 4) {
- return gfx::Rect(value[0], value[1], value[2], value[3]);
- }
-
- // Fetch the geometry of the root window.
- Window root;
- int x, y;
- unsigned int width, height;
- unsigned int border_width, depth;
- if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
- &width, &height, &border_width, &depth)) {
- NOTIMPLEMENTED();
- return gfx::Rect(0, 0, 10, 10);
- }
-
- return gfx::Rect(x, y, width, height);
-}
-
-void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
- if (custom_window_shape_)
- XDestroyRegion(custom_window_shape_);
- custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
- ResetWindowRegion();
- delete native_region;
-}
-
-void DesktopRootWindowHostX11::Activate() {
- X11DesktopHandler::get()->ActivateWindow(xwindow_);
- native_widget_delegate_->AsWidget()->SetInitialFocus();
-}
-
-void DesktopRootWindowHostX11::Deactivate() {
- // Deactivating a window means activating nothing.
- X11DesktopHandler::get()->ActivateWindow(None);
-}
-
-bool DesktopRootWindowHostX11::IsActive() const {
- return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
-}
-
-void DesktopRootWindowHostX11::Maximize() {
- // When we're the process requesting the maximizing, we can accurately keep
- // track of our restored bounds instead of relying on the heuristics that are
- // in the PropertyNotify and ConfigureNotify handlers.
- restored_bounds_ = bounds_;
-
- SetWMSpecState(true,
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
-}
-
-void DesktopRootWindowHostX11::Minimize() {
- XIconifyWindow(xdisplay_, xwindow_, 0);
-}
-
-void DesktopRootWindowHostX11::Restore() {
- SetWMSpecState(false,
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
- atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
-}
-
-bool DesktopRootWindowHostX11::IsMaximized() const {
- return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
- HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
-}
-
-bool DesktopRootWindowHostX11::IsMinimized() const {
- return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
-}
-
-
-bool DesktopRootWindowHostX11::HasCapture() const {
- return g_current_capture == this;
-}
-
-void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
- is_always_on_top_ = always_on_top;
- SetWMSpecState(always_on_top,
- atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
- None);
-}
-
-bool DesktopRootWindowHostX11::IsAlwaysOnTop() const {
- return is_always_on_top_;
-}
-
-bool DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
- if (window_title_ == title)
- return false;
- window_title_ = title;
- std::string utf8str = UTF16ToUTF8(title);
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_NAME"),
- atom_cache_.GetAtom("UTF8_STRING"),
- 8,
- PropModeReplace,
- reinterpret_cast<const unsigned char*>(utf8str.c_str()),
- utf8str.size());
- // TODO(erg): This is technically wrong. So XStoreName and friends expect
- // this in Host Portable Character Encoding instead of UTF-8, which I believe
- // is Compound Text. This shouldn't matter 90% of the time since this is the
- // fallback to the UTF8 property above.
- XStoreName(xdisplay_, xwindow_, utf8str.c_str());
- return true;
-}
-
-void DesktopRootWindowHostX11::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
- // 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_);
- }
-}
-
-Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) {
- aura::client::WindowMoveSource window_move_source =
- source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
- aura::client::WINDOW_MOVE_SOURCE_MOUSE :
- aura::client::WINDOW_MOVE_SOURCE_TOUCH;
- if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
- window_move_source) == aura::client::MOVE_SUCCESSFUL)
- return Widget::MOVE_LOOP_SUCCESSFUL;
-
- return Widget::MOVE_LOOP_CANCELED;
-}
-
-void DesktopRootWindowHostX11::EndMoveLoop() {
- x11_window_move_client_->EndMoveLoop();
-}
-
-void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
- bool value) {
- // Much like the previous NativeWidgetGtk, we don't have anything to do here.
-}
-
-bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
- return false;
-}
-
-void DesktopRootWindowHostX11::FrameTypeChanged() {
- // Replace the frame and layout the contents. Even though we don't have a
- // swapable glass frame like on Windows, we still replace the frame because
- // the button assets don't update otherwise.
- native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
-}
-
-NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
- return NULL;
-}
-
-void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
- is_fullscreen_ = fullscreen;
- SetWMSpecState(fullscreen,
- atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
- None);
-}
-
-bool DesktopRootWindowHostX11::IsFullscreen() const {
- return is_fullscreen_;
-}
-
-void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
- // X server opacity is in terms of 32 bit unsigned int space, and counts from
- // the opposite direction.
- // XChangeProperty() expects "cardinality" to be long.
- unsigned long cardinality = opacity * 0x1010101;
-
- if (cardinality == 0xffffffff) {
- XDeleteProperty(xdisplay_, xwindow_,
- atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
- } else {
- XChangeProperty(xdisplay_, xwindow_,
- atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
- XA_CARDINAL, 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&cardinality), 1);
- }
-}
-
-void DesktopRootWindowHostX11::SetWindowIcons(
- const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
- // TODO(erg): The way we handle icons across different versions of chrome
- // could be substantially improved. The Windows version does its own thing
- // and only sometimes comes down this code path. The icon stuff in
- // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
- // coded to be given two images instead of an arbitrary collection of images
- // so that we can pass to the WM.
- //
- // All of this could be made much, much better.
- std::vector<unsigned long> data;
-
- if (window_icon.HasRepresentation(1.0f))
- SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
-
- if (app_icon.HasRepresentation(1.0f))
- SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
-
- if (data.empty())
- XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
- else
- ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
-}
-
-void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
- switch (modal_type) {
- case ui::MODAL_TYPE_NONE:
- break;
- default:
- // TODO(erg): Figure out under what situations |modal_type| isn't
- // none. The comment in desktop_native_widget_aura.cc suggests that this
- // is rare.
- NOTIMPLEMENTED();
- }
-}
-
-void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
- // TODO(erg):
- NOTIMPLEMENTED();
-}
-
-void DesktopRootWindowHostX11::OnRootViewLayout() const {
- if (!window_mapped_)
- return;
-
- XSizeHints hints;
- long supplied_return;
- XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
-
- gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
- if (minimum.IsEmpty()) {
- hints.flags &= ~PMinSize;
- } else {
- hints.flags |= PMinSize;
- hints.min_width = minimum.width();
- hints.min_height = minimum.height();
- }
-
- gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
- if (maximum.IsEmpty()) {
- hints.flags &= ~PMaxSize;
- } else {
- hints.flags |= PMaxSize;
- hints.max_width = maximum.width();
- hints.max_height = maximum.height();
- }
-
- XSetWMNormalHints(xdisplay_, xwindow_, &hints);
-}
-
-void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
- native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
-}
-
-void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
- if (xwindow_)
- native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
-}
-
-bool DesktopRootWindowHostX11::IsAnimatingClosed() const {
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, aura::RootWindowHost implementation:
-
-aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
- return root_window_;
-}
-
-gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
- return xwindow_;
-}
-
-void DesktopRootWindowHostX11::Show() {
- if (!window_mapped_) {
- // Before we map the window, set size hints. Otherwise, some window managers
- // will ignore toplevel XMoveWindow commands.
- XSizeHints size_hints;
- size_hints.flags = PPosition;
- size_hints.x = bounds_.x();
- size_hints.y = bounds_.y();
- XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
-
- XMapWindow(xdisplay_, xwindow_);
-
- // We now block until our window is mapped. Some X11 APIs will crash and
- // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
- // asynchronous.
- base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
- window_mapped_ = true;
- }
-
- native_widget_delegate_->AsWidget()->SetInitialFocus();
-}
-
-void DesktopRootWindowHostX11::Hide() {
- if (window_mapped_) {
- XWithdrawWindow(xdisplay_, xwindow_, 0);
- window_mapped_ = false;
- }
-}
-
-void DesktopRootWindowHostX11::ToggleFullScreen() {
- NOTIMPLEMENTED();
-}
-
-gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
- return bounds_;
-}
-
-void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
- bool origin_changed = bounds_.origin() != bounds.origin();
- bool size_changed = bounds_.size() != bounds.size();
- XWindowChanges changes = {0};
- unsigned value_mask = 0;
-
- if (size_changed) {
- // X11 will send an XError at our process if have a 0 sized window.
- DCHECK_GT(bounds.width(), 0);
- DCHECK_GT(bounds.height(), 0);
-
- changes.width = bounds.width();
- changes.height = bounds.height();
- value_mask |= CWHeight | CWWidth;
- }
-
- if (origin_changed) {
- changes.x = bounds.x();
- changes.y = bounds.y();
- value_mask |= CWX | CWY;
- }
- if (value_mask)
- XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
-
- // Assume that the resize will go through as requested, which should be the
- // case if we're running without a window manager. If there's a window
- // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
- // (possibly synthetic) ConfigureNotify about the actual size and correct
- // |bounds_| later.
- bounds_ = bounds;
-
- if (origin_changed)
- native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
- if (size_changed)
- delegate_->OnHostResized(bounds.size());
- else
- delegate_->OnHostPaint(gfx::Rect(bounds.size()));
-}
-
-gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
- return gfx::Insets();
-}
-
-void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
-}
-
-gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
- return bounds_.origin();
-}
-
-void DesktopRootWindowHostX11::SetCapture() {
- // This is vaguely based on the old NativeWidgetGtk implementation.
- //
- // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
- // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
- // a grab that wasn't the X11 pointer grab, but was instead a manual
- // redirection of the event. (You need to drop into GDK if you want to
- // perform a raw X11 grab).
-
- if (g_current_capture)
- g_current_capture->OnCaptureReleased();
-
- g_current_capture = this;
-
- // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
- // pointer grab when our NativeWidget is of type Menu. However, things work
- // without it. Clicking inside a chrome window causes a release capture, and
- // clicking outside causes an activation change. Since previous attempts at
- // using XPointerGrab() to implement this have locked my X server, I'm going
- // to skip this for now.
-}
-
-void DesktopRootWindowHostX11::ReleaseCapture() {
- if (g_current_capture)
- g_current_capture->OnCaptureReleased();
-}
-
-void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
- XDefineCursor(xdisplay_, xwindow_, cursor.platform());
-}
-
-bool DesktopRootWindowHostX11::QueryMouseLocation(
- gfx::Point* location_return) {
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(GetRootWindow()->window());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
- *location_return = gfx::Point(0, 0);
- return false;
- }
-
- ::Window root_return, child_return;
- int root_x_return, root_y_return, win_x_return, win_y_return;
- unsigned int mask_return;
- XQueryPointer(xdisplay_,
- xwindow_,
- &root_return,
- &child_return,
- &root_x_return, &root_y_return,
- &win_x_return, &win_y_return,
- &mask_return);
- *location_return = gfx::Point(
- std::max(0, std::min(bounds_.width(), win_x_return)),
- std::max(0, std::min(bounds_.height(), win_y_return)));
- return (win_x_return >= 0 && win_x_return < bounds_.width() &&
- win_y_return >= 0 && win_y_return < bounds_.height());
-}
-
-bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
- NOTIMPLEMENTED();
- return false;
-}
-
-void DesktopRootWindowHostX11::UnConfineCursor() {
- NOTIMPLEMENTED();
-}
-
-void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
- // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
- // the same tap-to-click disabling here that chromeos does.
-}
-
-void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
- XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
- bounds_.x() + location.x(), bounds_.y() + location.y());
-}
-
-void DesktopRootWindowHostX11::PostNativeEvent(
- const base::NativeEvent& native_event) {
- DCHECK(xwindow_);
- DCHECK(xdisplay_);
- XEvent xevent = *native_event;
- xevent.xany.display = xdisplay_;
- xevent.xany.window = xwindow_;
-
- switch (xevent.type) {
- case EnterNotify:
- case LeaveNotify:
- case MotionNotify:
- case KeyPress:
- case KeyRelease:
- case ButtonPress:
- case ButtonRelease: {
- // The fields used below are in the same place for all of events
- // above. Using xmotion from XEvent's unions to avoid repeating
- // the code.
- xevent.xmotion.root = x_root_window_;
- xevent.xmotion.time = CurrentTime;
-
- gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
- ConvertPointToNativeScreen(&point);
- xevent.xmotion.x_root = point.x();
- xevent.xmotion.y_root = point.y();
- }
- default:
- break;
- }
- XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
-}
-
-void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
- float device_scale_factor) {
-}
-
-void DesktopRootWindowHostX11::PrepareForShutdown() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, private:
-
-void DesktopRootWindowHostX11::InitX11Window(
- const Widget::InitParams& params) {
- unsigned long attribute_mask = CWBackPixmap;
- XSetWindowAttributes swa;
- memset(&swa, 0, sizeof(swa));
- swa.background_pixmap = None;
-
- ::Atom window_type;
- switch (params.type) {
- case Widget::InitParams::TYPE_MENU:
- swa.override_redirect = True;
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
- break;
- case Widget::InitParams::TYPE_TOOLTIP:
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
- break;
- case Widget::InitParams::TYPE_POPUP:
- swa.override_redirect = True;
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
- break;
- case Widget::InitParams::TYPE_DRAG:
- swa.override_redirect = True;
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
- break;
- default:
- window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
- break;
- }
- if (swa.override_redirect)
- attribute_mask |= CWOverrideRedirect;
-
- bounds_ = params.bounds;
- xwindow_ = XCreateWindow(
- xdisplay_, x_root_window_,
- bounds_.x(), bounds_.y(),
- bounds_.width(), bounds_.height(),
- 0, // border width
- CopyFromParent, // depth
- InputOutput,
- CopyFromParent, // visual
- attribute_mask,
- &swa);
- base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
- open_windows().push_back(xwindow_);
-
- // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
-
- long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
- KeyPressMask | KeyReleaseMask |
- EnterWindowMask | LeaveWindowMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask | PropertyChangeMask |
- PointerMotionMask;
- XSelectInput(xdisplay_, xwindow_, event_mask);
- XFlush(xdisplay_);
-
- if (ui::IsXInput2Available())
- ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
-
- // TODO(erg): We currently only request window deletion events. We also
- // should listen for activation events and anything else that GTK+ listens
- // for, and do something useful.
- ::Atom protocols[2];
- protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
- protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
- XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
-
- // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
- // the desktop environment.
- XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
-
- // Likewise, the X server needs to know this window's pid so it knows which
- // program to kill if the window hangs.
- // XChangeProperty() expects "pid" to be long.
- COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
- long pid = getpid();
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_PID"),
- XA_CARDINAL,
- 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&pid), 1);
-
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
- XA_ATOM,
- 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&window_type), 1);
-
- // List of window state properties (_NET_WM_STATE) to set, if any.
- std::vector< ::Atom> state_atom_list;
-
- // Remove popup windows from taskbar.
- if (params.type == Widget::InitParams::TYPE_POPUP ||
- params.type == Widget::InitParams::TYPE_BUBBLE) {
- state_atom_list.push_back(
- atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
- }
-
- // If the window should stay on top of other windows, add the
- // _NET_WM_STATE_ABOVE property.
- is_always_on_top_ = params.keep_on_top;
- if (is_always_on_top_)
- state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
-
- // Setting _NET_WM_STATE by sending a message to the root_window (with
- // SetWMSpecState) has no effect here since the window has not yet been
- // mapped. So we manually change the state.
- if (!state_atom_list.empty()) {
- ui::SetAtomArrayProperty(xwindow_,
- "_NET_WM_STATE",
- "ATOM",
- state_atom_list);
- }
-
- if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
- ui::SetWindowClassHint(
- xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
- }
- if (!params.wm_role_name.empty() ||
- params.type == Widget::InitParams::TYPE_POPUP) {
- const char kX11WindowRolePopup[] = "popup";
- ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
- std::string(kX11WindowRolePopup) : params.wm_role_name);
- }
-
- // If we have a parent, record the parent/child relationship. We use this
- // data during destruction to make sure that when we try to close a parent
- // window, we also destroy all child windows.
- if (params.parent && params.parent->GetDispatcher()) {
- XID parent_xid =
- params.parent->GetDispatcher()->host()->GetAcceleratedWidget();
- window_parent_ = GetHostForXID(parent_xid);
- DCHECK(window_parent_);
- window_parent_->window_children_.insert(this);
- }
-
- // If we have a delegate which is providing a default window icon, use that
- // icon.
- gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
- ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
- if (window_icon) {
- SetWindowIcons(gfx::ImageSkia(), *window_icon);
- }
-}
-
-bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
- // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
- // of WM_Sn selections (where n is a screen number).
- return XGetSelectionOwner(
- xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
-}
-
-void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
- ::Atom state1,
- ::Atom state2) {
- XEvent xclient;
- memset(&xclient, 0, sizeof(xclient));
- xclient.type = ClientMessage;
- xclient.xclient.window = xwindow_;
- xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
- xclient.xclient.format = 32;
- xclient.xclient.data.l[0] =
- enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
- xclient.xclient.data.l[1] = state1;
- xclient.xclient.data.l[2] = state2;
- xclient.xclient.data.l[3] = 1;
- xclient.xclient.data.l[4] = 0;
-
- XSendEvent(xdisplay_, x_root_window_, False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- &xclient);
-}
-
-bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
- return window_properties_.find(atom_cache_.GetAtom(property)) !=
- window_properties_.end();
-}
-
-void DesktopRootWindowHostX11::OnCaptureReleased() {
- g_current_capture = NULL;
- delegate_->OnHostLostWindowCapture();
- native_widget_delegate_->OnMouseCaptureLost();
-}
-
-void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
- if (!g_current_capture || g_current_capture == this) {
- delegate_->OnHostMouseEvent(event);
- } else {
- // Another DesktopRootWindowHostX11 has installed itself as
- // capture. Translate the event's location and dispatch to the other.
- event->ConvertLocationToTarget(root_window_->window(),
- g_current_capture->root_window_->window());
- g_current_capture->delegate_->OnHostMouseEvent(event);
- }
-}
-
-void DesktopRootWindowHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
- if (g_current_capture && g_current_capture != this &&
- event->type() == ui::ET_TOUCH_PRESSED) {
- event->ConvertLocationToTarget(root_window_->window(),
- g_current_capture->root_window_->window());
- g_current_capture->delegate_->OnHostTouchEvent(event);
- } else {
- delegate_->OnHostTouchEvent(event);
- }
-}
-
-void DesktopRootWindowHostX11::ResetWindowRegion() {
- // If a custom window shape was supplied then apply it.
- if (custom_window_shape_) {
- XShapeCombineRegion(
- xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false);
- return;
- }
-
- if (!IsMaximized()) {
- gfx::Path window_mask;
- views::Widget* widget = native_widget_delegate_->AsWidget();
- if (widget->non_client_view()) {
- // Some frame views define a custom (non-rectangular) window mask. If
- // so, use it to define the window shape. If not, fall through.
- widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
- if (window_mask.countPoints() > 0) {
- Region region = gfx::CreateRegionFromSkPath(window_mask);
- XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
- 0, 0, region, false);
- XDestroyRegion(region);
- return;
- }
- }
- }
-
- // If we didn't set the shape for any reason, reset the shaping information
- // by ShapeSet-ing with our bounds rect.
- XRectangle r = { 0, 0, static_cast<unsigned short>(bounds_.width()),
- static_cast<unsigned short>(bounds_.height()) };
- XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding,
- 0, 0, &r, 1, ShapeSet, YXBanded);
-}
-
-void DesktopRootWindowHostX11::SerializeImageRepresentation(
- const gfx::ImageSkiaRep& rep,
- std::vector<unsigned long>* data) {
- int width = rep.GetWidth();
- data->push_back(width);
-
- int height = rep.GetHeight();
- data->push_back(height);
-
- const SkBitmap& bitmap = rep.sk_bitmap();
- SkAutoLockPixels locker(bitmap);
-
- for (int y = 0; y < height; ++y)
- for (int x = 0; x < width; ++x)
- data->push_back(bitmap.getColor(x, y));
-}
-
-std::list<XID>& DesktopRootWindowHostX11::open_windows() {
- if (!open_windows_)
- open_windows_ = new std::list<XID>();
- return *open_windows_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
-
-bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
- XEvent* xev = event;
-
- TRACE_EVENT1("views", "DesktopRootWindowHostX11::Dispatch",
- "event->type", event->type);
-
- // May want to factor CheckXEventForConsistency(xev); into a common location
- // since it is called here.
- switch (xev->type) {
- case EnterNotify:
- case LeaveNotify: {
- if (!g_current_capture)
- X11DesktopHandler::get()->ProcessXEvent(xev);
- ui::MouseEvent mouse_event(xev);
- DispatchMouseEvent(&mouse_event);
- break;
- }
- case Expose: {
- gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
- xev->xexpose.width, xev->xexpose.height);
- delegate_->OnHostPaint(damage_rect);
- break;
- }
- case KeyPress: {
- ui::KeyEvent keydown_event(xev, false);
- delegate_->OnHostKeyEvent(&keydown_event);
- break;
- }
- case KeyRelease: {
- ui::KeyEvent keyup_event(xev, false);
- delegate_->OnHostKeyEvent(&keyup_event);
- break;
- }
- case ButtonPress: {
- if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
- static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
- aura::client::UserActionClient* gesture_client =
- aura::client::GetUserActionClient(root_window_->window());
- if (gesture_client) {
- gesture_client->OnUserAction(
- static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
- aura::client::UserActionClient::BACK :
- aura::client::UserActionClient::FORWARD);
- }
- break;
- }
- } // fallthrough
- case ButtonRelease: {
- ui::EventType event_type = ui::EventTypeFromNative(xev);
- switch (event_type) {
- case ui::ET_MOUSEWHEEL: {
- ui::MouseWheelEvent mouseev(xev);
- DispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED: {
- ui::MouseEvent mouseev(xev);
- DispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_UNKNOWN:
- // No event is created for X11-release events for mouse-wheel buttons.
- break;
- default:
- NOTREACHED() << event_type;
- }
- break;
- }
- case FocusOut:
- if (xev->xfocus.mode != NotifyGrab) {
- ReleaseCapture();
- delegate_->OnHostLostWindowCapture();
- } else {
- delegate_->OnHostLostMouseGrab();
- }
- break;
- case ConfigureNotify: {
- DCHECK_EQ(xwindow_, xev->xconfigure.window);
- DCHECK_EQ(xwindow_, xev->xconfigure.event);
- // It's possible that the X window may be resized by some other means than
- // from within aura (e.g. the X window manager can change the size). Make
- // sure the root window size is maintained properly.
- int translated_x = xev->xconfigure.x;
- int translated_y = xev->xconfigure.y;
- if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
- Window unused;
- XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
- 0, 0, &translated_x, &translated_y, &unused);
- }
- gfx::Rect bounds(translated_x, translated_y,
- xev->xconfigure.width, xev->xconfigure.height);
- bool size_changed = bounds_.size() != bounds.size();
- bool origin_changed = bounds_.origin() != bounds.origin();
- previous_bounds_ = bounds_;
- bounds_ = bounds;
- if (size_changed)
- delegate_->OnHostResized(bounds.size());
- if (origin_changed)
- delegate_->OnHostMoved(bounds_.origin());
- ResetWindowRegion();
- break;
- }
- case GenericEvent: {
- ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
- if (!factory->ShouldProcessXI2Event(xev))
- break;
-
- ui::EventType type = ui::EventTypeFromNative(xev);
- XEvent last_event;
- int num_coalesced = 0;
-
- switch (type) {
- case ui::ET_TOUCH_MOVED:
- num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
- if (num_coalesced > 0)
- xev = &last_event;
- // fallthrough
- case ui::ET_TOUCH_PRESSED:
- case ui::ET_TOUCH_RELEASED: {
- ui::TouchEvent touchev(xev);
- DispatchTouchEvent(&touchev);
- break;
- }
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED:
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- case ui::ET_MOUSE_ENTERED:
- case ui::ET_MOUSE_EXITED: {
- if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
- // If this is a motion event, we want to coalesce all pending motion
- // events that are at the top of the queue.
- num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
- if (num_coalesced > 0)
- xev = &last_event;
- } else if (type == ui::ET_MOUSE_PRESSED) {
- XIDeviceEvent* xievent =
- static_cast<XIDeviceEvent*>(xev->xcookie.data);
- int button = xievent->detail;
- if (button == kBackMouseButton || button == kForwardMouseButton) {
- aura::client::UserActionClient* gesture_client =
- aura::client::GetUserActionClient(
- delegate_->AsRootWindow()->window());
- if (gesture_client) {
- bool reverse_direction =
- ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
- gesture_client->OnUserAction(
- (button == kBackMouseButton && !reverse_direction) ||
- (button == kForwardMouseButton && reverse_direction) ?
- aura::client::UserActionClient::BACK :
- aura::client::UserActionClient::FORWARD);
- }
- break;
- }
- } else if (type == ui::ET_MOUSE_RELEASED) {
- XIDeviceEvent* xievent =
- static_cast<XIDeviceEvent*>(xev->xcookie.data);
- int button = xievent->detail;
- if (button == kBackMouseButton || button == kForwardMouseButton) {
- // We've already passed the back/forward mouse down to the user
- // action client; we want to swallow the corresponding release.
- break;
- }
- }
- ui::MouseEvent mouseev(xev);
- DispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_MOUSEWHEEL: {
- ui::MouseWheelEvent mouseev(xev);
- DispatchMouseEvent(&mouseev);
- break;
- }
- case ui::ET_SCROLL_FLING_START:
- case ui::ET_SCROLL_FLING_CANCEL:
- case ui::ET_SCROLL: {
- ui::ScrollEvent scrollev(xev);
- delegate_->OnHostScrollEvent(&scrollev);
- break;
- }
- case ui::ET_UNKNOWN:
- break;
- default:
- NOTREACHED();
- }
-
- // If we coalesced an event we need to free its cookie.
- if (num_coalesced > 0)
- XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
- break;
- }
- case MapNotify: {
- FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
- observer_list_,
- OnWindowMapped(xwindow_));
- break;
- }
- case UnmapNotify: {
- FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
- observer_list_,
- OnWindowUnmapped(xwindow_));
- break;
- }
- case ClientMessage: {
- Atom message_type = xev->xclient.message_type;
- if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
- Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
- if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
- // We have received a close message from the window manager.
- root_window_->OnRootWindowHostCloseRequested();
- } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
- XEvent reply_event = *xev;
- reply_event.xclient.window = x_root_window_;
-
- XSendEvent(xdisplay_,
- reply_event.xclient.window,
- False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- &reply_event);
- }
- } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
- drag_drop_client_->OnXdndEnter(xev->xclient);
- } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
- drag_drop_client_->OnXdndLeave(xev->xclient);
- } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
- drag_drop_client_->OnXdndPosition(xev->xclient);
- } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
- drag_drop_client_->OnXdndStatus(xev->xclient);
- } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
- drag_drop_client_->OnXdndFinished(xev->xclient);
- } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
- drag_drop_client_->OnXdndDrop(xev->xclient);
- }
- break;
- }
- case MappingNotify: {
- switch (xev->xmapping.request) {
- case MappingModifier:
- case MappingKeyboard:
- XRefreshKeyboardMapping(&xev->xmapping);
- root_window_->OnKeyboardMappingChanged();
- break;
- case MappingPointer:
- ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
- break;
- default:
- NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
- break;
- }
- break;
- }
- case MotionNotify: {
- // Discard all but the most recent motion event that targets the same
- // window with unchanged state.
- XEvent last_event;
- while (XPending(xev->xany.display)) {
- XEvent next_event;
- XPeekEvent(xev->xany.display, &next_event);
- if (next_event.type == MotionNotify &&
- next_event.xmotion.window == xev->xmotion.window &&
- next_event.xmotion.subwindow == xev->xmotion.subwindow &&
- next_event.xmotion.state == xev->xmotion.state) {
- XNextEvent(xev->xany.display, &last_event);
- xev = &last_event;
- } else {
- break;
- }
- }
-
- ui::MouseEvent mouseev(xev);
- DispatchMouseEvent(&mouseev);
- break;
- }
- case PropertyNotify: {
- // Get our new window property state if the WM has told us its changed.
- ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
-
- std::vector< ::Atom> atom_list;
- if (xev->xproperty.atom == state &&
- ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
- window_properties_.clear();
- std::copy(atom_list.begin(), atom_list.end(),
- inserter(window_properties_, window_properties_.begin()));
-
- if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
- // If we have restored bounds, but WM_STATE no longer claims to be
- // maximized, we should clear our restored bounds.
- restored_bounds_ = gfx::Rect();
- } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
- // The request that we become maximized originated from a different
- // process. |bounds_| already contains our maximized bounds. Do a
- // best effort attempt to get restored bounds by setting it to our
- // previously set bounds (and if we get this wrong, we aren't any
- // worse off since we'd otherwise be returning our maximized bounds).
- restored_bounds_ = previous_bounds_;
- }
-
- is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
- is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
-
- // Now that we have different window properties, we may need to
- // relayout the window. (The windows code doesn't need this because
- // their window change is synchronous.)
- //
- // TODO(erg): While this does work, there's a quick flash showing the
- // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
- // those parts of the UI because we receive the sizing event from the
- // window manager before we receive the event that changes the
- // fullscreen state. Unsure what to do about that.
- Widget* widget = native_widget_delegate_->AsWidget();
- NonClientView* non_client_view = widget->non_client_view();
- // non_client_view may be NULL, especially during creation.
- if (non_client_view) {
- non_client_view->client_view()->InvalidateLayout();
- non_client_view->InvalidateLayout();
- }
- widget->GetRootView()->Layout();
- }
- break;
- }
- case SelectionNotify: {
- drag_drop_client_->OnSelectionNotify(xev->xselection);
- break;
- }
- }
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHost, public:
-
-// static
-DesktopRootWindowHost* DesktopRootWindowHost::Create(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura) {
- return new DesktopRootWindowHostX11(native_widget_delegate,
- desktop_native_widget_aura);
-}
-
-// static
-ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
- const views::LinuxUI* linux_ui = views::LinuxUI::instance();
- if (linux_ui) {
- ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
- if (native_theme)
- return native_theme;
- }
-
- return ui::NativeTheme::instance();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
deleted file mode 100644
index 76a0821a6de..00000000000
--- a/chromium/ui/views/widget/desktop_aura/desktop_root_window_host_x11.h
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
-
-#include <X11/extensions/shape.h>
-#include <X11/Xlib.h>
-
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
-
-#include "base/basictypes.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/cursor/cursor_loader_x11.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/views/views_export.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
-
-namespace gfx {
-class ImageSkia;
-class ImageSkiaRep;
-}
-
-namespace views {
-class DesktopDragDropClientAuraX11;
-class DesktopDispatcherClient;
-class DesktopRootWindowHostObserverX11;
-class X11DesktopWindowMoveClient;
-class X11WindowEventFilter;
-
-class VIEWS_EXPORT DesktopRootWindowHostX11 :
- public DesktopRootWindowHost,
- public aura::RootWindowHost,
- public base::MessageLoop::Dispatcher {
- public:
- DesktopRootWindowHostX11(
- internal::NativeWidgetDelegate* native_widget_delegate,
- DesktopNativeWidgetAura* desktop_native_widget_aura);
- virtual ~DesktopRootWindowHostX11();
-
- // A way of converting an X11 |xid| host window into a |content_window_|.
- static aura::Window* GetContentWindowForXID(XID xid);
-
- // A way of converting an X11 |xid| host window into this object.
- static DesktopRootWindowHostX11* GetHostForXID(XID xid);
-
- // Get all open top-level windows. This includes windows that may not be
- // visible. This list is sorted in their stacking order, i.e. the first window
- // is the topmost window.
- static std::vector<aura::Window*> GetAllOpenWindows();
-
- // Returns the current bounds in terms of the X11 Root Window.
- gfx::Rect GetX11RootWindowBounds() const;
-
- // Called by X11DesktopHandler to notify us that the native windowing system
- // has changed our activation.
- void HandleNativeWidgetActivationChanged(bool active);
-
- void AddObserver(views::DesktopRootWindowHostObserverX11* observer);
- void RemoveObserver(views::DesktopRootWindowHostObserverX11* observer);
-
- // Deallocates the internal list of open windows.
- static void CleanUpWindowList();
-
- protected:
- // Overridden from DesktopRootWindowHost:
- virtual void Init(aura::Window* content_window,
- const Widget::InitParams& params,
- aura::RootWindow::CreateParams* rw_create_params) OVERRIDE;
- virtual void OnRootWindowCreated(aura::RootWindow* root,
- const Widget::InitParams& params) OVERRIDE;
- virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
- virtual scoped_ptr<aura::client::DragDropClient>
- CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
- virtual void Close() OVERRIDE;
- virtual void CloseNow() OVERRIDE;
- virtual aura::RootWindowHost* AsRootWindowHost() OVERRIDE;
- virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
- virtual void ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) OVERRIDE;
- virtual bool IsVisible() const OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void StackAtTop() OVERRIDE;
- virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
- virtual void GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const OVERRIDE;
- virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
- virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
- virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
- virtual void Activate() OVERRIDE;
- virtual void Deactivate() OVERRIDE;
- virtual bool IsActive() const OVERRIDE;
- virtual void Maximize() OVERRIDE;
- virtual void Minimize() OVERRIDE;
- virtual void Restore() OVERRIDE;
- virtual bool IsMaximized() const OVERRIDE;
- virtual bool IsMinimized() const OVERRIDE;
- virtual bool HasCapture() const OVERRIDE;
- virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
- virtual bool IsAlwaysOnTop() const OVERRIDE;
- virtual bool SetWindowTitle(const string16& title) OVERRIDE;
- virtual void ClearNativeFocus() OVERRIDE;
- virtual Widget::MoveLoopResult RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
- virtual void EndMoveLoop() OVERRIDE;
- virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
- virtual bool ShouldUseNativeFrame() OVERRIDE;
- virtual void FrameTypeChanged() OVERRIDE;
- virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
- virtual void SetFullscreen(bool fullscreen) OVERRIDE;
- virtual bool IsFullscreen() const OVERRIDE;
- virtual void SetOpacity(unsigned char opacity) OVERRIDE;
- virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
- const gfx::ImageSkia& app_icon) OVERRIDE;
- virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
- virtual void FlashFrame(bool flash_frame) OVERRIDE;
- virtual void OnRootViewLayout() const OVERRIDE;
- virtual void OnNativeWidgetFocus() OVERRIDE;
- virtual void OnNativeWidgetBlur() OVERRIDE;
- virtual bool IsAnimatingClosed() const OVERRIDE;
-
- // Overridden from aura::RootWindowHost:
- virtual aura::RootWindow* GetRootWindow() OVERRIDE;
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ToggleFullScreen() OVERRIDE;
- virtual gfx::Rect GetBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual gfx::Insets GetInsets() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE;
- virtual bool ConfineCursorToRootWindow() OVERRIDE;
- virtual void UnConfineCursor() OVERRIDE;
- virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
- virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
- virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void PrepareForShutdown() OVERRIDE;
-
-private:
- // Initializes our X11 surface to draw on. This method performs all
- // initialization related to talking to the X11 server.
- void InitX11Window(const Widget::InitParams& params);
-
- // Creates an aura::RootWindow to contain the |content_window|, along with
- // all aura client objects that direct behavior.
- aura::RootWindow* InitRootWindow(const Widget::InitParams& params);
-
- // Returns true if there's an X window manager present... in most cases. Some
- // window managers (notably, ion3) don't implement enough of ICCCM for us to
- // detect that they're there.
- bool IsWindowManagerPresent();
-
- // Sends a message to the x11 window manager, enabling or disabling the
- // states |state1| and |state2|.
- void SetWMSpecState(bool enabled, ::Atom state1, ::Atom state2);
-
- // Checks if the window manager has set a specific state.
- bool HasWMSpecProperty(const char* property) const;
-
- // Called when another DRWHL takes capture, or when capture is released
- // entirely.
- void OnCaptureReleased();
-
- // Dispatches a mouse event, taking mouse capture into account. If a
- // different host has capture, we translate the event to its coordinate space
- // and dispatch it to that host instead.
- void DispatchMouseEvent(ui::MouseEvent* event);
-
- // Dispatches a touch event, taking capture into account. If a different host
- // has capture, then touch-press events are translated to its coordinate space
- // and dispatched to that host instead.
- void DispatchTouchEvent(ui::TouchEvent* event);
-
- // Resets the window region for the current widget bounds if necessary.
- void ResetWindowRegion();
-
- // Serializes an image to the format used by _NET_WM_ICON.
- void SerializeImageRepresentation(const gfx::ImageSkiaRep& rep,
- std::vector<unsigned long>* data);
-
- // See comment for variable open_windows_.
- static std::list<XID>& open_windows();
-
- // Overridden from Dispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
- base::WeakPtrFactory<DesktopRootWindowHostX11> close_widget_factory_;
-
- // X11 things
- // The display and the native X window hosting the root window.
- XDisplay* xdisplay_;
- ::Window xwindow_;
-
- // The native root window.
- ::Window x_root_window_;
-
- ui::X11AtomCache atom_cache_;
-
- // Is the window mapped to the screen?
- bool window_mapped_;
-
- // The bounds of |xwindow_|.
- gfx::Rect bounds_;
-
- // Whenever the bounds are set, we keep the previous set of bounds around so
- // we can have a better chance of getting the real |restored_bounds_|. Window
- // managers tend to send a Configure message with the maximized bounds, and
- // then set the window maximized property. (We don't rely on this for when we
- // request that the window be maximized, only when we detect that some other
- // process has requested that we become the maximized window.)
- gfx::Rect previous_bounds_;
-
- // The bounds of our window before we were maximized.
- gfx::Rect restored_bounds_;
-
- // The window manager state bits.
- std::set< ::Atom> window_properties_;
-
- // Local flag for fullscreen state to avoid a state mismatch between
- // server and local window_properties_ during app-initiated fullscreen.
- bool is_fullscreen_;
-
- // True if the window should stay on top of most other windows.
- bool is_always_on_top_;
-
- // We are owned by the RootWindow, but we have to have a back pointer to it.
- aura::RootWindow* root_window_;
-
- scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
-
- DesktopDragDropClientAuraX11* drag_drop_client_;
-
- // Current Aura cursor.
- gfx::NativeCursor current_cursor_;
-
- scoped_ptr<X11WindowEventFilter> x11_window_event_filter_;
- scoped_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
-
- // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
- // instead of providing this route back to Widget.
- internal::NativeWidgetDelegate* native_widget_delegate_;
-
- 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().
- DesktopRootWindowHostX11* window_parent_;
- std::set<DesktopRootWindowHostX11*> window_children_;
-
- ObserverList<DesktopRootWindowHostObserverX11> observer_list_;
-
- // Copy of custom window shape specified via SetShape(), if any.
- ::Region custom_window_shape_;
-
- // The current root window host that has capture. While X11 has something
- // like Windows SetCapture()/ReleaseCapture(), it is entirely implicit and
- // there are no notifications when this changes. We need to track this so we
- // can notify widgets when they have lost capture, which controls a bunch of
- // things in views like hiding menus.
- static DesktopRootWindowHostX11* g_current_capture;
-
- // A list of all (top-level) windows that have been created but not yet
- // destroyed.
- static std::list<XID>* open_windows_;
-
- string16 window_title_;
-
- DISALLOW_COPY_AND_ASSIGN(DesktopRootWindowHostX11);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_ROOT_WINDOW_HOST_X11_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen.h b/chromium/ui/views/widget/desktop_aura/desktop_screen.h
index ad66bd41575..2db961d2d95 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen.h
@@ -14,7 +14,7 @@ class Screen;
namespace views {
// Creates a Screen that represents the screen of the environment that hosts
-// a RootWindowHost. Caller owns the result.
+// a WindowTreeHost. Caller owns the result.
VIEWS_EXPORT gfx::Screen* CreateDesktopScreen();
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
index 4d7f9a1b739..9708ad88bfc 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
@@ -4,14 +4,12 @@
#include "ui/views/widget/desktop_aura/desktop_screen.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-#include "ui/ozone/ozone_platform.h"
+#include "ui/views/widget/desktop_aura/desktop_factory_ozone.h"
namespace views {
gfx::Screen* CreateDesktopScreen() {
- ui::OzonePlatform::Initialize();
- return gfx::SurfaceFactoryOzone::GetInstance()->CreateDesktopScreen();
+ return DesktopFactoryOzone::GetInstance()->CreateDesktopScreen();
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
index a16b24b6427..96deaf4205c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/gfx/display.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/screen.h"
@@ -15,20 +15,17 @@ namespace views {
namespace {
gfx::Point GetOrigin(const aura::Window* root_window) {
- gfx::Point origin_in_pixels =
- root_window->GetDispatcher()->host()->GetBounds().origin();
+ gfx::Point origin_in_pixels = root_window->GetHost()->GetBounds().origin();
aura::Window* window = const_cast<aura::Window*>(root_window);
float scale = gfx::Screen::GetScreenFor(window)->
GetDisplayNearestWindow(window).device_scale_factor();
- return gfx::ToFlooredPoint(
- gfx::ScalePoint(origin_in_pixels, 1 / scale));
+ return gfx::ToFlooredPoint(gfx::ScalePoint(origin_in_pixels, 1 / scale));
}
// Returns true if bounds passed to window are treated as though they are in
// screen coordinates.
bool PositionWindowInScreenCoordinates(aura::Window* window) {
- if (window->type() == aura::client::WINDOW_TYPE_POPUP ||
- window->type() == aura::client::WINDOW_TYPE_TOOLTIP)
+ if (window->type() == ui::wm::WINDOW_TYPE_POPUP)
return true;
Widget* widget = Widget::GetWidgetForNativeView(window);
@@ -37,14 +34,19 @@ bool PositionWindowInScreenCoordinates(aura::Window* window) {
} // namespace
-DesktopScreenPositionClient::DesktopScreenPositionClient() {
+DesktopScreenPositionClient::DesktopScreenPositionClient(
+ aura::Window* root_window)
+ : root_window_(root_window) {
+ aura::client::SetScreenPositionClient(root_window_, this);
}
DesktopScreenPositionClient::~DesktopScreenPositionClient() {
+ aura::client::SetScreenPositionClient(root_window_, NULL);
}
void DesktopScreenPositionClient::ConvertPointToScreen(
- const aura::Window* window, gfx::Point* point) {
+ const aura::Window* window,
+ gfx::Point* point) {
const aura::Window* root_window = window->GetRootWindow();
aura::Window::ConvertPointToTarget(window, root_window, point);
gfx::Point origin = GetOrigin(root_window);
@@ -52,26 +54,33 @@ void DesktopScreenPositionClient::ConvertPointToScreen(
}
void DesktopScreenPositionClient::ConvertPointFromScreen(
- const aura::Window* window, gfx::Point* point) {
+ const aura::Window* window,
+ gfx::Point* point) {
const aura::Window* root_window = window->GetRootWindow();
gfx::Point origin = GetOrigin(root_window);
point->Offset(-origin.x(), -origin.y());
aura::Window::ConvertPointToTarget(root_window, window, point);
}
-void DesktopScreenPositionClient::ConvertHostPointToScreen(
- aura::Window* window, gfx::Point* point) {
+void DesktopScreenPositionClient::ConvertHostPointToScreen(aura::Window* window,
+ gfx::Point* point) {
aura::Window* root_window = window->GetRootWindow();
ConvertPointToScreen(root_window, point);
}
-void DesktopScreenPositionClient::SetBounds(
- aura::Window* window,
- const gfx::Rect& bounds,
- const gfx::Display& display) {
+void DesktopScreenPositionClient::SetBounds(aura::Window* window,
+ const gfx::Rect& bounds,
+ const gfx::Display& display) {
// TODO: Use the 3rd parameter, |display|.
aura::Window* root = window->GetRootWindow();
+ // This method assumes that |window| does not have an associated
+ // DesktopNativeWidgetAura.
+ internal::NativeWidgetPrivate* desktop_native_widget =
+ DesktopNativeWidgetAura::ForWindow(root);
+ DCHECK(!desktop_native_widget ||
+ desktop_native_widget->GetNativeView() != window);
+
if (PositionWindowInScreenCoordinates(window)) {
// The caller expects windows we consider "embedded" to be placed in the
// screen coordinate system. So we need to offset the root window's
@@ -86,14 +95,7 @@ void DesktopScreenPositionClient::SetBounds(
return;
}
- DesktopNativeWidgetAura* desktop_native_widget =
- DesktopNativeWidgetAura::ForWindow(window);
- if (desktop_native_widget) {
- root->GetDispatcher()->SetHostBounds(bounds);
- // Setting bounds of root resizes |window|.
- } else {
- window->SetBounds(bounds);
- }
+ window->SetBounds(bounds);
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h
index da8ad402ea7..222c2a1a4ea 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h
@@ -15,7 +15,7 @@ namespace views {
class VIEWS_EXPORT DesktopScreenPositionClient
: public aura::client::ScreenPositionClient {
public:
- DesktopScreenPositionClient();
+ explicit DesktopScreenPositionClient(aura::Window* root_window);
virtual ~DesktopScreenPositionClient();
// aura::client::ScreenPositionClient overrides:
@@ -28,6 +28,11 @@ class VIEWS_EXPORT DesktopScreenPositionClient
virtual void SetBounds(aura::Window* window,
const gfx::Rect& bounds,
const gfx::Display& display) OVERRIDE;
+
+ private:
+ aura::Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopScreenPositionClient);
};
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
index bb1cd8b08ac..ac30d1ee700 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
@@ -15,21 +15,17 @@ typedef ViewsTestBase DesktopScreenPositionClientTest;
// DesktopNativeWidgetAura is positioned correctly.
TEST_F(DesktopScreenPositionClientTest, PositionDialog) {
Widget parent_widget;
- Widget::InitParams init_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- init_params.bounds = gfx::Rect(10, 11, 200, 200);
- init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
- parent_widget.Init(init_params);
- // parent_widget.Show();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(10, 11, 200, 200);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
+ parent_widget.Init(params);
// Owned by |dialog|.
DialogDelegateView* dialog_delegate_view = new DialogDelegateView;
// Owned by |parent_widget|.
Widget* dialog = DialogDelegate::CreateDialogWidget(
- dialog_delegate_view,
- NULL,
- parent_widget.GetNativeView());
+ dialog_delegate_view, NULL, parent_widget.GetNativeView());
dialog->SetBounds(gfx::Rect(11, 12, 200, 200));
EXPECT_EQ("11,12", dialog->GetWindowBoundsInScreen().origin().ToString());
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
index 86823a04d3a..c5edf76c687 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -5,12 +5,12 @@
#include "ui/views/widget/desktop_aura/desktop_screen_win.h"
#include "base/logging.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/gfx/display.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace {
@@ -54,13 +54,13 @@ gfx::Display DesktopScreenWin::GetDisplayMatching(
}
HWND DesktopScreenWin::GetHWNDFromNativeView(gfx::NativeView window) const {
- aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
- return dispatcher ? dispatcher->host()->GetAcceleratedWidget() : NULL;
+ aura::WindowTreeHost* host = window->GetHost();
+ return host ? host->GetAcceleratedWidget() : NULL;
}
gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
return (::IsWindow(hwnd)) ?
- DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd) : NULL;
+ DesktopWindowTreeHostWin::GetContentWindowForHWND(hwnd) : NULL;
}
////////////////////////////////////////////////////////////////////////////////
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 332b81c59ce..76db7948117 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -12,19 +12,21 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
-#include "base/x11/edid_parser_x11.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/layout.h"
-#include "ui/base/x/x11_util.h"
+#include "ui/display/util/display_util.h"
+#include "ui/display/util/x11/edid_parser_x11.h"
+#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/display.h"
#include "ui/gfx/display_observer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/x/x11_types.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
namespace {
@@ -32,6 +34,7 @@ namespace {
// in |Dispatch()|.
const int64 kConfigureDelayMs = 500;
+// TODO(oshima): Consider using gtk-xft-dpi instead.
float GetDeviceScaleFactor(int screen_pixels, int screen_mm) {
const int kCSSDefaultDPI = 96;
const float kInchInMm = 25.4f;
@@ -40,7 +43,7 @@ float GetDeviceScaleFactor(int screen_pixels, int screen_mm) {
float screen_dpi = screen_pixels / screen_inches;
float scale = screen_dpi / kCSSDefaultDPI;
- return ui::GetImageScale(ui::GetSupportedScaleFactor(scale));
+ return ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale));
}
std::vector<gfx::Display> GetFallbackDisplayList() {
@@ -48,14 +51,14 @@ std::vector<gfx::Display> GetFallbackDisplayList() {
::Screen* screen = DefaultScreenOfDisplay(display);
int width = WidthOfScreen(screen);
int height = HeightOfScreen(screen);
- int mm_width = WidthMMOfScreen(screen);
- int mm_height = HeightMMOfScreen(screen);
+ gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
gfx::Rect bounds_in_pixels(0, 0, width, height);
gfx::Display gfx_display(0, bounds_in_pixels);
if (!gfx::Display::HasForceDeviceScaleFactor() &&
- !ui::IsXDisplaySizeBlackListed(mm_width, mm_height)) {
- float device_scale_factor = GetDeviceScaleFactor(width, mm_width);
+ !ui::IsDisplaySizeBlackListed(physical_size)) {
+ float device_scale_factor = GetDeviceScaleFactor(
+ width, physical_size.width());
DCHECK_LE(1.0f, device_scale_factor);
gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
}
@@ -71,7 +74,7 @@ namespace views {
// DesktopScreenX11, public:
DesktopScreenX11::DesktopScreenX11()
- : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
+ : xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
has_xrandr_(false),
xrandr_event_base_(0) {
@@ -88,10 +91,13 @@ DesktopScreenX11::DesktopScreenX11()
int error_base_ignored = 0;
XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
- base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
XRRSelectInput(xdisplay_,
x_root_window_,
- RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
+ RRScreenChangeNotifyMask |
+ RROutputChangeNotifyMask |
+ RRCrtcChangeNotifyMask);
displays_ = BuildDisplaysFromXRandRInfo();
} else {
@@ -100,18 +106,22 @@ DesktopScreenX11::DesktopScreenX11()
}
DesktopScreenX11::~DesktopScreenX11() {
- if (has_xrandr_)
- base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
+ if (has_xrandr_ && ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void DesktopScreenX11::ProcessDisplayChange(
const std::vector<gfx::Display>& incoming) {
- std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
- for (; cur_it != displays_.end(); ++cur_it) {
+ std::vector<gfx::Display> old_displays = displays_;
+ displays_ = incoming;
+
+ typedef std::vector<gfx::Display>::const_iterator DisplayIt;
+ std::vector<gfx::Display>::const_iterator old_it = old_displays.begin();
+ for (; old_it != old_displays.end(); ++old_it) {
bool found = false;
- for (std::vector<gfx::Display>::const_iterator incoming_it =
- incoming.begin(); incoming_it != incoming.end(); ++incoming_it) {
- if (cur_it->id() == incoming_it->id()) {
+ for (std::vector<gfx::Display>::const_iterator new_it =
+ displays_.begin(); new_it != displays_.end(); ++new_it) {
+ if (old_it->id() == new_it->id()) {
found = true;
break;
}
@@ -119,33 +129,47 @@ void DesktopScreenX11::ProcessDisplayChange(
if (!found) {
FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
- OnDisplayRemoved(*cur_it));
+ OnDisplayRemoved(*old_it));
}
}
- std::vector<gfx::Display>::const_iterator incoming_it = incoming.begin();
- for (; incoming_it != incoming.end(); ++incoming_it) {
+ std::vector<gfx::Display>::const_iterator new_it = displays_.begin();
+ for (; new_it != displays_.end(); ++new_it) {
bool found = false;
- for (std::vector<gfx::Display>::const_iterator cur_it = displays_.begin();
- cur_it != displays_.end(); ++cur_it) {
- if (incoming_it->id() == cur_it->id()) {
- if (incoming_it->bounds() != cur_it->bounds()) {
- FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
- OnDisplayBoundsChanged(*incoming_it));
- }
+ for (std::vector<gfx::Display>::const_iterator old_it =
+ old_displays.begin(); old_it != old_displays.end(); ++old_it) {
+ if (new_it->id() != old_it->id())
+ continue;
- found = true;
- break;
+ uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
+
+ if (new_it->bounds() != old_it->bounds())
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
+
+ if (new_it->rotation() != old_it->rotation())
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
+
+ if (new_it->work_area() != old_it->work_area())
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+
+ if (new_it->device_scale_factor() != old_it->device_scale_factor())
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+
+ if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
+ FOR_EACH_OBSERVER(gfx::DisplayObserver,
+ observer_list_,
+ OnDisplayMetricsChanged(*new_it, metrics));
}
+
+ found = true;
+ break;
}
if (!found) {
FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
- OnDisplayAdded(*incoming_it));
+ OnDisplayAdded(*new_it));
}
}
-
- displays_ = incoming;
}
////////////////////////////////////////////////////////////////////////////////
@@ -182,16 +206,8 @@ gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() {
gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
const gfx::Point& point) {
- std::vector<aura::Window*> windows =
- DesktopRootWindowHostX11::GetAllOpenWindows();
-
- for (std::vector<aura::Window*>::const_iterator it = windows.begin();
- it != windows.end(); ++it) {
- if ((*it)->GetBoundsInScreen().Contains(point))
- return *it;
- }
-
- return NULL;
+ X11TopmostWindowFinder finder;
+ return finder.FindLocalProcessWindowAt(point, std::set<aura::Window*>());
}
int DesktopScreenX11::GetNumDisplays() const {
@@ -207,16 +223,16 @@ gfx::Display DesktopScreenX11::GetDisplayNearestWindow(
// Getting screen bounds here safely is hard.
//
// You'd think we'd be able to just call window->GetBoundsInScreen(), but we
- // can't because |window| (and the associated RootWindow*) can be partially
- // initialized at this point; RootWindow initializations call through into
- // GetDisplayNearestWindow(). But the X11 resources are created before we
- // create the aura::RootWindow. So we ask what the DRWHX11 believes the
- // window bounds are instead of going through the aura::Window's screen
- // bounds.
- aura::WindowEventDispatcher* dispatcher = window->GetDispatcher();
- if (dispatcher) {
- DesktopRootWindowHostX11* rwh = DesktopRootWindowHostX11::GetHostForXID(
- dispatcher->host()->GetAcceleratedWidget());
+ // can't because |window| (and the associated WindowEventDispatcher*) can be
+ // partially initialized at this point; WindowEventDispatcher initializations
+ // call through into GetDisplayNearestWindow(). But the X11 resources are
+ // created before we create the aura::WindowEventDispatcher. So we ask what
+ // the DRWHX11 believes the window bounds are instead of going through the
+ // aura::Window's screen bounds.
+ aura::WindowTreeHost* host = window->GetHost();
+ if (host) {
+ DesktopWindowTreeHostX11* rwh = DesktopWindowTreeHostX11::GetHostForXID(
+ host->GetAcceleratedWidget());
if (rwh)
return GetDisplayMatching(rwh->GetX11RootWindowBounds());
}
@@ -264,7 +280,12 @@ void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
observer_list_.RemoveObserver(observer);
}
-bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) {
+bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return event->type - xrandr_event_base_ == RRScreenChangeNotify ||
+ event->type - xrandr_event_base_ == RRNotify;
+}
+
+uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) {
if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
// Pass the event through to xlib.
XRRUpdateConfiguration(event);
@@ -281,9 +302,11 @@ bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) {
this,
&DesktopScreenX11::ConfigureTimerFired);
}
+ } else {
+ NOTREACHED();
}
- return true;
+ return ui::POST_DISPATCH_NONE;
}
////////////////////////////////////////////////////////////////////////////////
@@ -291,7 +314,7 @@ bool DesktopScreenX11::Dispatch(const base::NativeEvent& event) {
DesktopScreenX11::DesktopScreenX11(
const std::vector<gfx::Display>& test_displays)
- : xdisplay_(base::MessagePumpX11::GetDefaultXDisplay()),
+ : xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
has_xrandr_(false),
xrandr_event_base_(0),
@@ -334,7 +357,7 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
output_info->crtc);
int64 display_id = -1;
- if (!base::GetDisplayId(output_id, i, &display_id)) {
+ if (!ui::GetDisplayId(output_id, static_cast<uint8>(i), &display_id)) {
// It isn't ideal, but if we can't parse the EDID data, fallback on the
// display number.
display_id = i;
@@ -344,8 +367,8 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
gfx::Display display(display_id, crtc_bounds);
if (!gfx::Display::HasForceDeviceScaleFactor()) {
- if (i == 0 && !ui::IsXDisplaySizeBlackListed(output_info->mm_width,
- output_info->mm_height)) {
+ if (i == 0 && !ui::IsDisplaySizeBlackListed(
+ gfx::Size(output_info->mm_width, output_info->mm_height))) {
// As per display scale factor is not supported right now,
// the primary display's scale factor is always used.
device_scale_factor = GetDeviceScaleFactor(crtc->width,
@@ -361,6 +384,21 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
display.set_work_area(intersection);
}
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ display.set_rotation(gfx::Display::ROTATE_0);
+ break;
+ case RR_Rotate_90:
+ display.set_rotation(gfx::Display::ROTATE_90);
+ break;
+ case RR_Rotate_180:
+ display.set_rotation(gfx::Display::ROTATE_180);
+ break;
+ case RR_Rotate_270:
+ display.set_rotation(gfx::Display::ROTATE_270);
+ break;
+ }
+
displays.push_back(display);
XRRFreeCrtcInfo(crtc);
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 1b9a8320a36..a5b2a17dd83 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -5,9 +5,9 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_
-#include "base/message_loop/message_pump_dispatcher.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/screen.h"
#include "ui/views/views_export.h"
@@ -24,7 +24,7 @@ class DesktopScreenX11Test;
// Our singleton screen implementation that talks to xrandr.
class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen,
- public base::MessagePumpDispatcher {
+ public ui::PlatformEventDispatcher {
public:
DesktopScreenX11();
@@ -52,8 +52,9 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen,
virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE;
virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE;
- // Overridden from MessagePumpDispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
private:
friend class DesktopScreenX11Test;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
index 55ce07069fb..c9e7159a53f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
@@ -4,12 +4,47 @@
#include "ui/views/widget/desktop_aura/desktop_screen_x11.h"
-#include "base/message_loop/message_loop.h"
+#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/x/x11_util.h"
#include "ui/gfx/display_observer.h"
+#include "ui/gfx/x/x11_types.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+
+namespace {
+
+// Class which allows for the designation of non-client component targets of
+// hit tests.
+class TestDesktopNativeWidgetAura : public views::DesktopNativeWidgetAura {
+ public:
+ explicit TestDesktopNativeWidgetAura(
+ views::internal::NativeWidgetDelegate* delegate)
+ : views::DesktopNativeWidgetAura(delegate) {}
+ virtual ~TestDesktopNativeWidgetAura() {}
+
+ void set_window_component(int window_component) {
+ window_component_ = window_component;
+ }
+
+ // DesktopNativeWidgetAura:
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
+ return window_component_;
+ }
+
+ private:
+ int window_component_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDesktopNativeWidgetAura);
+};
+
+} // namespace
namespace views {
@@ -50,23 +85,26 @@ class DesktopScreenX11Test : public views::ViewsTestBase,
removed_display_.clear();
}
- Widget* BuildTopLevelDesktopWidget(const gfx::Rect& bounds) {
+ Widget* BuildTopLevelDesktopWidget(const gfx::Rect& bounds,
+ bool use_test_native_widget) {
Widget* toplevel = new Widget;
Widget::InitParams toplevel_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
- toplevel_params.native_widget =
- new views::DesktopNativeWidgetAura(toplevel);
+ if (use_test_native_widget) {
+ toplevel_params.native_widget =
+ new TestDesktopNativeWidgetAura(toplevel);
+ } else {
+ toplevel_params.native_widget =
+ new views::DesktopNativeWidgetAura(toplevel);
+ }
toplevel_params.bounds = bounds;
+ toplevel_params.remove_standard_frame = true;
toplevel->Init(toplevel_params);
return toplevel;
}
private:
// Overridden from gfx::DisplayObserver:
- virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE {
- changed_display_.push_back(display);
- }
-
virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE {
added_display_.push_back(new_display);
}
@@ -75,6 +113,11 @@ class DesktopScreenX11Test : public views::ViewsTestBase,
removed_display_.push_back(old_display);
}
+ virtual void OnDisplayMetricsChanged(const gfx::Display& display,
+ uint32_t metrics) OVERRIDE {
+ changed_display_.push_back(display);
+ }
+
scoped_ptr<DesktopScreenX11> screen_;
DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11Test);
@@ -198,32 +241,6 @@ TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) {
EXPECT_EQ(kFirstDisplay, screen()->GetPrimaryDisplay().id());
}
-TEST_F(DesktopScreenX11Test, GetWindowAtScreenPoint) {
- Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10));
- Widget* window_two = BuildTopLevelDesktopWidget(gfx::Rect(50, 50, 10, 10));
- Widget* window_three = BuildTopLevelDesktopWidget(gfx::Rect(15, 15, 20, 20));
-
- // Make sure the internal state of DesktopRootWindowHostX11 is set up
- // correctly.
- ASSERT_EQ(3u, DesktopRootWindowHostX11::GetAllOpenWindows().size());
-
- EXPECT_EQ(window_one->GetNativeWindow(),
- screen()->GetWindowAtScreenPoint(gfx::Point(15, 15)));
- EXPECT_EQ(window_two->GetNativeWindow(),
- screen()->GetWindowAtScreenPoint(gfx::Point(55, 55)));
- EXPECT_EQ(NULL,
- screen()->GetWindowAtScreenPoint(gfx::Point(100, 100)));
-
- // Bring the third window in front. It overlaps with the first window.
- // Hit-testing on the intersecting region should give the third window.
- window_three->Activate();
- EXPECT_EQ(window_three->GetNativeWindow(),
- screen()->GetWindowAtScreenPoint(gfx::Point(15, 15)));
-
- window_one->CloseNow();
- window_two->CloseNow();
-}
-
TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
// Set up a two monitor situation.
std::vector<gfx::Display> displays;
@@ -232,8 +249,10 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays);
- Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10));
- Widget* window_two = BuildTopLevelDesktopWidget(gfx::Rect(650, 50, 10, 10));
+ Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10),
+ false);
+ Widget* window_two = BuildTopLevelDesktopWidget(gfx::Rect(650, 50, 10, 10),
+ false);
EXPECT_EQ(
kFirstDisplay,
@@ -246,4 +265,183 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
window_two->CloseNow();
}
+// Tests that the window is maximized in response to a double click event.
+TEST_F(DesktopScreenX11Test, DoubleClickHeaderMaximizes) {
+ if (!ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")))
+ return;
+
+ Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
+ widget->Show();
+ TestDesktopNativeWidgetAura* native_widget =
+ static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
+ native_widget->set_window_component(HTCAPTION);
+
+ aura::Window* window = widget->GetNativeWindow();
+ window->SetProperty(aura::client::kCanMaximizeKey, true);
+
+ // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
+ DesktopWindowTreeHost* rwh =
+ DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
+ GetAcceleratedWidget());
+
+ aura::test::EventGenerator generator(window);
+ generator.ClickLeftButton();
+ generator.DoubleClickLeftButton();
+ RunPendingMessages();
+ EXPECT_TRUE(rwh->IsMaximized());
+
+ widget->CloseNow();
+}
+
+// Tests that the window does not maximize in response to a double click event,
+// if the first click was to a different target component than that of the
+// second click.
+TEST_F(DesktopScreenX11Test, DoubleClickTwoDifferentTargetsDoesntMaximizes) {
+ Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
+ widget->Show();
+ TestDesktopNativeWidgetAura* native_widget =
+ static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
+
+ aura::Window* window = widget->GetNativeWindow();
+ window->SetProperty(aura::client::kCanMaximizeKey, true);
+
+ // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
+ DesktopWindowTreeHost* rwh =
+ DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
+ GetAcceleratedWidget());
+
+ aura::test::EventGenerator generator(window);
+ native_widget->set_window_component(HTCLIENT);
+ generator.ClickLeftButton();
+ native_widget->set_window_component(HTCAPTION);
+ generator.DoubleClickLeftButton();
+ RunPendingMessages();
+ EXPECT_FALSE(rwh->IsMaximized());
+
+ widget->CloseNow();
+}
+
+// Tests that the window does not maximize in response to a double click event,
+// if the double click was interrupted by a right click.
+TEST_F(DesktopScreenX11Test, RightClickDuringDoubleClickDoesntMaximize) {
+ Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
+ widget->Show();
+ TestDesktopNativeWidgetAura* native_widget =
+ static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
+
+ aura::Window* window = widget->GetNativeWindow();
+ window->SetProperty(aura::client::kCanMaximizeKey, true);
+
+ // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
+ DesktopWindowTreeHost* rwh = static_cast<DesktopWindowTreeHost*>(
+ DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
+ GetAcceleratedWidget()));
+
+ aura::test::EventGenerator generator(window);
+ native_widget->set_window_component(HTCLIENT);
+ generator.ClickLeftButton();
+ native_widget->set_window_component(HTCAPTION);
+ generator.PressRightButton();
+ generator.ReleaseRightButton();
+ EXPECT_FALSE(rwh->IsMaximized());
+ generator.DoubleClickLeftButton();
+ RunPendingMessages();
+ EXPECT_FALSE(rwh->IsMaximized());
+
+ widget->CloseNow();
+}
+
+// Test that rotating the displays notifies the DisplayObservers.
+TEST_F(DesktopScreenX11Test, RotationChange) {
+ std::vector<gfx::Display> displays;
+ displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
+ displays.push_back(
+ gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
+ screen()->ProcessDisplayChange(displays);
+ ResetDisplayChanges();
+
+ displays[0].set_rotation(gfx::Display::ROTATE_90);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(1u, changed_display_.size());
+
+ displays[1].set_rotation(gfx::Display::ROTATE_90);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[0].set_rotation(gfx::Display::ROTATE_270);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(3u, changed_display_.size());
+
+ displays[0].set_rotation(gfx::Display::ROTATE_270);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(3u, changed_display_.size());
+
+ displays[0].set_rotation(gfx::Display::ROTATE_0);
+ displays[1].set_rotation(gfx::Display::ROTATE_0);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(5u, changed_display_.size());
+}
+
+// Test that changing the displays workarea notifies the DisplayObservers.
+TEST_F(DesktopScreenX11Test, WorkareaChange) {
+ std::vector<gfx::Display> displays;
+ displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
+ displays.push_back(
+ gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
+ screen()->ProcessDisplayChange(displays);
+ ResetDisplayChanges();
+
+ displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(1u, changed_display_.size());
+
+ displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[0].set_work_area(gfx::Rect(0, 0, 640, 480));
+ displays[1].set_work_area(gfx::Rect(640, 0, 1024, 768));
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(4u, changed_display_.size());
+}
+
+// Test that changing the device scale factor notifies the DisplayObservers.
+TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) {
+ std::vector<gfx::Display> displays;
+ displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
+ displays.push_back(
+ gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
+ screen()->ProcessDisplayChange(displays);
+ ResetDisplayChanges();
+
+ displays[0].set_device_scale_factor(2.5f);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(1u, changed_display_.size());
+
+ displays[1].set_device_scale_factor(2.5f);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[0].set_device_scale_factor(2.5f);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[1].set_device_scale_factor(2.5f);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+ displays[0].set_device_scale_factor(1.f);
+ displays[1].set_device_scale_factor(1.f);
+ screen()->ProcessDisplayChange(displays);
+ EXPECT_EQ(4u, changed_display_.size());
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
new file mode 100644
index 00000000000..9ccb67225a1
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura {
+class WindowTreeHost;
+class Window;
+
+namespace client {
+class DragDropClient;
+}
+}
+
+namespace gfx {
+class ImageSkia;
+class Rect;
+}
+
+namespace ui {
+class NativeTheme;
+}
+
+namespace views {
+namespace corewm {
+class Tooltip;
+}
+
+namespace internal {
+class NativeWidgetDelegate;
+}
+
+class DesktopNativeCursorManager;
+class DesktopNativeWidgetAura;
+
+class VIEWS_EXPORT DesktopWindowTreeHost {
+ public:
+ virtual ~DesktopWindowTreeHost() {}
+
+ static DesktopWindowTreeHost* Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura);
+
+ // Return the NativeTheme to use for |window|. WARNING: |window| may be NULL.
+ static ui::NativeTheme* GetNativeTheme(aura::Window* window);
+
+ // Sets up resources needed before the WindowEventDispatcher has been created.
+ virtual void Init(aura::Window* content_window,
+ const Widget::InitParams& params) = 0;
+
+ // Invoked once the DesktopNativeWidgetAura has been created.
+ virtual void OnNativeWidgetCreated(const Widget::InitParams& params) = 0;
+
+ // Creates and returns the Tooltip implementation to use. Return value is
+ // owned by DesktopNativeWidgetAura and lives as long as
+ // DesktopWindowTreeHost.
+ virtual scoped_ptr<corewm::Tooltip> CreateTooltip() = 0;
+
+ // Creates and returns the DragDropClient implementation to use. Return value
+ // is owned by DesktopNativeWidgetAura and lives as long as
+ // DesktopWindowTreeHost.
+ virtual scoped_ptr<aura::client::DragDropClient> CreateDragDropClient(
+ DesktopNativeCursorManager* cursor_manager) = 0;
+
+ virtual void Close() = 0;
+ virtual void CloseNow() = 0;
+
+ virtual aura::WindowTreeHost* AsWindowTreeHost() = 0;
+
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) = 0;
+ virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
+
+ virtual bool IsVisible() const = 0;
+
+ virtual void SetSize(const gfx::Size& size) = 0;
+ virtual void StackAtTop() = 0;
+ virtual void CenterWindow(const gfx::Size& size) = 0;
+ virtual void GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const = 0;
+ virtual gfx::Rect GetWindowBoundsInScreen() const = 0;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0;
+ virtual gfx::Rect GetRestoredBounds() const = 0;
+
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
+
+ // Sets the shape of the root window. If |native_region| is NULL then the
+ // window reverts to rectangular. Takes ownership of |native_region|.
+ virtual void SetShape(gfx::NativeRegion native_region) = 0;
+
+ virtual void Activate() = 0;
+ virtual void Deactivate() = 0;
+ virtual bool IsActive() const = 0;
+ virtual void Maximize() = 0;
+ virtual void Minimize() = 0;
+ virtual void Restore() = 0;
+ virtual bool IsMaximized() const = 0;
+ virtual bool IsMinimized() const = 0;
+
+ virtual bool HasCapture() const = 0;
+
+ virtual void SetAlwaysOnTop(bool always_on_top) = 0;
+ virtual bool IsAlwaysOnTop() const = 0;
+
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) = 0;
+
+ // Returns true if the title changed.
+ virtual bool SetWindowTitle(const base::string16& title) = 0;
+
+ virtual void ClearNativeFocus() = 0;
+
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) = 0;
+ virtual void EndMoveLoop() = 0;
+
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) = 0;
+
+ // Determines whether the window should use native title bar and borders.
+ virtual bool ShouldUseNativeFrame() const = 0;
+ // Determines whether the window contents should be rendered transparently
+ // (for example, so that they can overhang onto the window title bar).
+ virtual bool ShouldWindowContentsBeTransparent() const = 0;
+ virtual void FrameTypeChanged() = 0;
+
+ virtual void SetFullscreen(bool fullscreen) = 0;
+ virtual bool IsFullscreen() const = 0;
+
+ virtual void SetOpacity(unsigned char opacity) = 0;
+
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) = 0;
+
+ virtual void InitModalType(ui::ModalType modal_type) = 0;
+
+ virtual void FlashFrame(bool flash_frame) = 0;
+
+ virtual void OnRootViewLayout() const = 0;
+
+ // Called when the DesktopNativeWidgetAura's aura::Window is focused and
+ // blurred.
+ virtual void OnNativeWidgetFocus() = 0;
+ virtual void OnNativeWidgetBlur() = 0;
+
+ // Returns true if the Widget was closed but is still showing because of
+ // animations.
+ virtual bool IsAnimatingClosed() const = 0;
+
+ // Returns true if the Widget supports translucency.
+ virtual bool IsTranslucentWindowOpacitySupported() const = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h
new file mode 100644
index 00000000000..544f20527aa
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_
+
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// Allows for the observation of lower level window events.
+class VIEWS_EXPORT DesktopWindowTreeHostObserverX11 {
+ public:
+ virtual ~DesktopWindowTreeHostObserverX11() {}
+
+ // Called after we receive a MapNotify event (the X11 server has allocated
+ // resources for it).
+ virtual void OnWindowMapped(unsigned long xid) = 0;
+
+ // Called after we receive an UnmapNotify event (the X11 server has freed
+ // resources for it).
+ virtual void OnWindowUnmapped(unsigned long xid) = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_OBSERVER_X11_H_
+
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_ozone.cc
new file mode 100644
index 00000000000..1a78a9ab57e
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_ozone.cc
@@ -0,0 +1,20 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/window_tree_host.h"
+#include "ui/views/widget/desktop_aura/desktop_factory_ozone.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+
+namespace views {
+
+DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura) {
+ DesktopFactoryOzone* d_factory = DesktopFactoryOzone::GetInstance();
+
+ return d_factory->CreateWindowTreeHost(native_widget_delegate,
+ desktop_native_widget_aura);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
new file mode 100644
index 00000000000..63475267815
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -0,0 +1,960 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
+
+#include "base/win/metro.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/cursor/cursor_loader_win.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/win/shell.h"
+#include "ui/compositor/compositor_constants.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/path_win.h"
+#include "ui/gfx/vector2d.h"
+#include "ui/gfx/win/dpi.h"
+#include "ui/native_theme/native_theme_aura.h"
+#include "ui/native_theme/native_theme_win.h"
+#include "ui/views/corewm/tooltip_win.h"
+#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_hwnd_utils.h"
+#include "ui/views/win/fullscreen_handler.h"
+#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/core/input_method_event_filter.h"
+#include "ui/wm/core/window_animations.h"
+#include "ui/wm/public/scoped_tooltip_disabler.h"
+
+namespace views {
+
+namespace {
+
+gfx::Size GetExpandedWindowSize(DWORD window_style, gfx::Size size) {
+ if (!(window_style & WS_EX_COMPOSITED) || !ui::win::IsAeroGlassEnabled())
+ return size;
+
+ // Some AMD drivers can't display windows that are less than 64x64 pixels,
+ // so expand them to be at least that size. http://crbug.com/286609
+ gfx::Size expanded(std::max(size.width(), 64), std::max(size.height(), 64));
+ return expanded;
+}
+
+void InsetBottomRight(gfx::Rect* rect, gfx::Vector2d vector) {
+ rect->Inset(0, 0, vector.x(), vector.y());
+}
+
+} // namespace
+
+DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kContentWindowForRootWindow, NULL);
+
+// Identifies the DesktopWindowTreeHostWin associated with the
+// WindowEventDispatcher.
+DEFINE_WINDOW_PROPERTY_KEY(DesktopWindowTreeHostWin*, kDesktopWindowTreeHostKey,
+ NULL);
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, public:
+
+bool DesktopWindowTreeHostWin::is_cursor_visible_ = true;
+
+DesktopWindowTreeHostWin::DesktopWindowTreeHostWin(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura)
+ : 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),
+ has_non_client_view_(false),
+ tooltip_(NULL) {
+}
+
+DesktopWindowTreeHostWin::~DesktopWindowTreeHostWin() {
+ // WARNING: |content_window_| has been destroyed by the time we get here.
+ desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
+ DestroyDispatcher();
+}
+
+// static
+aura::Window* DesktopWindowTreeHostWin::GetContentWindowForHWND(HWND hwnd) {
+ aura::WindowTreeHost* host =
+ aura::WindowTreeHost::GetForAcceleratedWidget(hwnd);
+ return host ? host->window()->GetProperty(kContentWindowForRootWindow) : NULL;
+}
+
+// static
+ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
+ // Use NativeThemeWin for windows shown on the desktop, those not on the
+ // desktop come from Ash and get NativeThemeAura.
+ aura::WindowTreeHost* host = window ? window->GetHost() : NULL;
+ if (host) {
+ HWND host_hwnd = host->GetAcceleratedWidget();
+ if (host_hwnd &&
+ DesktopWindowTreeHostWin::GetContentWindowForHWND(host_hwnd)) {
+ return ui::NativeThemeWin::instance();
+ }
+ }
+ return ui::NativeThemeAura::instance();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, DesktopWindowTreeHost implementation:
+
+void DesktopWindowTreeHostWin::Init(aura::Window* content_window,
+ const Widget::InitParams& params) {
+ // TODO(beng): SetInitParams().
+ content_window_ = content_window;
+
+ aura::client::SetAnimationHost(content_window_, this);
+
+ ConfigureWindowStyles(message_handler_.get(), params,
+ GetWidget()->widget_delegate(),
+ native_widget_delegate_);
+
+ HWND parent_hwnd = NULL;
+ if (params.parent && params.parent->GetHost())
+ parent_hwnd = params.parent->GetHost()->GetAcceleratedWidget();
+
+ message_handler_->set_remove_standard_frame(params.remove_standard_frame);
+
+ has_non_client_view_ = Widget::RequiresNonClientView(params.type);
+
+ gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
+ message_handler_->Init(parent_hwnd, pixel_bounds);
+ if (params.type == Widget::InitParams::TYPE_MENU) {
+ ::SetProp(GetAcceleratedWidget(),
+ kForceSoftwareCompositor,
+ reinterpret_cast<HANDLE>(true));
+ }
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+void DesktopWindowTreeHostWin::OnNativeWidgetCreated(
+ const Widget::InitParams& params) {
+ // The cursor is not necessarily visible when the root window is created.
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window());
+ if (cursor_client)
+ is_cursor_visible_ = cursor_client->IsCursorVisible();
+
+ window()->SetProperty(kContentWindowForRootWindow, content_window_);
+ window()->SetProperty(kDesktopWindowTreeHostKey, this);
+
+ should_animate_window_close_ =
+ content_window_->type() != ui::wm::WINDOW_TYPE_NORMAL &&
+ !wm::WindowAnimationsDisabled(content_window_);
+
+// TODO this is not invoked *after* Init(), but should be ok.
+ SetWindowTransparency();
+}
+
+scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() {
+ DCHECK(!tooltip_);
+ tooltip_ = new corewm::TooltipWin(GetAcceleratedWidget());
+ return scoped_ptr<corewm::Tooltip>(tooltip_);
+}
+
+scoped_ptr<aura::client::DragDropClient>
+DesktopWindowTreeHostWin::CreateDragDropClient(
+ DesktopNativeCursorManager* cursor_manager) {
+ drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND());
+ return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
+}
+
+void DesktopWindowTreeHostWin::Close() {
+ // TODO(beng): Move this entire branch to DNWA so it can be shared with X11.
+ if (should_animate_window_close_) {
+ pending_close_ = true;
+ const bool is_animating =
+ content_window_->layer()->GetAnimator()->IsAnimatingProperty(
+ ui::LayerAnimationElement::VISIBILITY);
+ // Animation may not start for a number of reasons.
+ if (!is_animating)
+ message_handler_->Close();
+ // else case, OnWindowHidingAnimationCompleted does the actual Close.
+ } else {
+ message_handler_->Close();
+ }
+}
+
+void DesktopWindowTreeHostWin::CloseNow() {
+ message_handler_->CloseNow();
+}
+
+aura::WindowTreeHost* DesktopWindowTreeHostWin::AsWindowTreeHost() {
+ return this;
+}
+
+void DesktopWindowTreeHostWin::ShowWindowWithState(
+ ui::WindowShowState show_state) {
+ message_handler_->ShowWindowWithState(show_state);
+}
+
+void DesktopWindowTreeHostWin::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds);
+ message_handler_->ShowMaximizedWithBounds(pixel_bounds);
+}
+
+bool DesktopWindowTreeHostWin::IsVisible() const {
+ return message_handler_->IsVisible();
+}
+
+void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) {
+ gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
+ gfx::Size expanded = GetExpandedWindowSize(
+ message_handler_->window_ex_style(), size_in_pixels);
+ window_enlargement_ =
+ gfx::Vector2d(expanded.width() - size_in_pixels.width(),
+ expanded.height() - size_in_pixels.height());
+ message_handler_->SetSize(expanded);
+}
+
+void DesktopWindowTreeHostWin::StackAtTop() {
+ message_handler_->StackAtTop();
+}
+
+void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) {
+ gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
+ gfx::Size expanded_size;
+ expanded_size = GetExpandedWindowSize(message_handler_->window_ex_style(),
+ size_in_pixels);
+ window_enlargement_ =
+ gfx::Vector2d(expanded_size.width() - size_in_pixels.width(),
+ expanded_size.height() - size_in_pixels.height());
+ message_handler_->CenterWindow(expanded_size);
+}
+
+void DesktopWindowTreeHostWin::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ message_handler_->GetWindowPlacement(bounds, show_state);
+ InsetBottomRight(bounds, window_enlargement_);
+ *bounds = gfx::win::ScreenToDIPRect(*bounds);
+}
+
+gfx::Rect DesktopWindowTreeHostWin::GetWindowBoundsInScreen() const {
+ gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen();
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
+ return gfx::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() const {
+ gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen();
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
+ return gfx::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopWindowTreeHostWin::GetRestoredBounds() const {
+ gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds();
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
+ return gfx::win::ScreenToDIPRect(pixel_bounds);
+}
+
+gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const {
+ MONITORINFO monitor_info;
+ monitor_info.cbSize = sizeof(monitor_info);
+ GetMonitorInfo(MonitorFromWindow(message_handler_->hwnd(),
+ MONITOR_DEFAULTTONEAREST),
+ &monitor_info);
+ gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork);
+ return gfx::win::ScreenToDIPRect(pixel_bounds);
+}
+
+void DesktopWindowTreeHostWin::SetShape(gfx::NativeRegion native_region) {
+ if (native_region) {
+ message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*native_region));
+ } else {
+ message_handler_->SetRegion(NULL);
+ }
+
+ delete native_region;
+}
+
+void DesktopWindowTreeHostWin::Activate() {
+ message_handler_->Activate();
+}
+
+void DesktopWindowTreeHostWin::Deactivate() {
+ message_handler_->Deactivate();
+}
+
+bool DesktopWindowTreeHostWin::IsActive() const {
+ return message_handler_->IsActive();
+}
+
+void DesktopWindowTreeHostWin::Maximize() {
+ message_handler_->Maximize();
+}
+
+void DesktopWindowTreeHostWin::Minimize() {
+ message_handler_->Minimize();
+}
+
+void DesktopWindowTreeHostWin::Restore() {
+ message_handler_->Restore();
+}
+
+bool DesktopWindowTreeHostWin::IsMaximized() const {
+ return message_handler_->IsMaximized();
+}
+
+bool DesktopWindowTreeHostWin::IsMinimized() const {
+ return message_handler_->IsMinimized();
+}
+
+bool DesktopWindowTreeHostWin::HasCapture() const {
+ return message_handler_->HasCapture();
+}
+
+void DesktopWindowTreeHostWin::SetAlwaysOnTop(bool always_on_top) {
+ message_handler_->SetAlwaysOnTop(always_on_top);
+}
+
+bool DesktopWindowTreeHostWin::IsAlwaysOnTop() const {
+ return message_handler_->IsAlwaysOnTop();
+}
+
+void DesktopWindowTreeHostWin::SetVisibleOnAllWorkspaces(bool always_visible) {
+ // Windows does not have the concept of workspaces.
+}
+
+bool DesktopWindowTreeHostWin::SetWindowTitle(const base::string16& title) {
+ return message_handler_->SetTitle(title);
+}
+
+void DesktopWindowTreeHostWin::ClearNativeFocus() {
+ message_handler_->ClearNativeFocus();
+}
+
+Widget::MoveLoopResult DesktopWindowTreeHostWin::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) {
+ const bool hide_on_escape =
+ escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE;
+ return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ?
+ Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
+}
+
+void DesktopWindowTreeHostWin::EndMoveLoop() {
+ message_handler_->EndMoveLoop();
+}
+
+void DesktopWindowTreeHostWin::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ message_handler_->SetVisibilityChangedAnimationsEnabled(value);
+ content_window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
+}
+
+bool DesktopWindowTreeHostWin::ShouldUseNativeFrame() const {
+ return IsTranslucentWindowOpacitySupported();
+}
+
+bool DesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent() const {
+ // If the window has a native frame, we assume it is an Aero Glass window, and
+ // is therefore transparent. Note: This is not equivalent to calling
+ // IsAeroGlassEnabled, because ShouldUseNativeFrame is overridden in a
+ // subclass.
+ return ShouldUseNativeFrame();
+}
+
+void DesktopWindowTreeHostWin::FrameTypeChanged() {
+ message_handler_->FrameTypeChanged();
+ SetWindowTransparency();
+}
+
+void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) {
+ message_handler_->fullscreen_handler()->SetFullscreen(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())
+ content_window_->Show();
+ SetWindowTransparency();
+}
+
+bool DesktopWindowTreeHostWin::IsFullscreen() const {
+ return message_handler_->fullscreen_handler()->fullscreen();
+}
+
+void DesktopWindowTreeHostWin::SetOpacity(unsigned char opacity) {
+ message_handler_->SetOpacity(static_cast<BYTE>(opacity));
+ content_window_->layer()->SetOpacity(opacity / 255.0);
+}
+
+void DesktopWindowTreeHostWin::SetWindowIcons(
+ const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
+ message_handler_->SetWindowIcons(window_icon, app_icon);
+}
+
+void DesktopWindowTreeHostWin::InitModalType(ui::ModalType modal_type) {
+ message_handler_->InitModalType(modal_type);
+}
+
+void DesktopWindowTreeHostWin::FlashFrame(bool flash_frame) {
+ message_handler_->FlashFrame(flash_frame);
+}
+
+void DesktopWindowTreeHostWin::OnRootViewLayout() const {
+}
+
+void DesktopWindowTreeHostWin::OnNativeWidgetFocus() {
+ // HWNDMessageHandler will perform the proper updating on its own.
+}
+
+void DesktopWindowTreeHostWin::OnNativeWidgetBlur() {
+}
+
+bool DesktopWindowTreeHostWin::IsAnimatingClosed() const {
+ return pending_close_;
+}
+
+bool DesktopWindowTreeHostWin::IsTranslucentWindowOpacitySupported() const {
+ return ui::win::IsAeroGlassEnabled();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, WindowTreeHost implementation:
+
+ui::EventSource* DesktopWindowTreeHostWin::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget DesktopWindowTreeHostWin::GetAcceleratedWidget() {
+ return message_handler_->hwnd();
+}
+
+void DesktopWindowTreeHostWin::Show() {
+ message_handler_->Show();
+}
+
+void DesktopWindowTreeHostWin::Hide() {
+ if (!pending_close_)
+ message_handler_->Hide();
+}
+
+// GetBounds and SetBounds work in pixel coordinates, whereas other get/set
+// methods work in DIP.
+
+gfx::Rect DesktopWindowTreeHostWin::GetBounds() const {
+ gfx::Rect bounds(message_handler_->GetClientAreaBounds());
+ // If the window bounds were expanded we need to return the original bounds
+ // To achieve this we do the reverse of the expansion, i.e. add the
+ // window_expansion_top_left_delta_ to the origin and subtract the
+ // window_expansion_bottom_right_delta_ from the width and height.
+ gfx::Rect without_expansion(
+ bounds.x() + window_expansion_top_left_delta_.x(),
+ bounds.y() + window_expansion_top_left_delta_.y(),
+ bounds.width() - window_expansion_bottom_right_delta_.x() -
+ window_enlargement_.x(),
+ bounds.height() - window_expansion_bottom_right_delta_.y() -
+ window_enlargement_.y());
+ return without_expansion;
+}
+
+void DesktopWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) {
+ // If the window bounds have to be expanded we need to subtract the
+ // window_expansion_top_left_delta_ from the origin and add the
+ // window_expansion_bottom_right_delta_ to the width and height
+ gfx::Size old_hwnd_size(message_handler_->GetClientAreaBounds().size());
+ gfx::Size old_content_size = GetBounds().size();
+
+ gfx::Rect expanded(
+ bounds.x() - window_expansion_top_left_delta_.x(),
+ bounds.y() - window_expansion_top_left_delta_.y(),
+ bounds.width() + window_expansion_bottom_right_delta_.x(),
+ bounds.height() + window_expansion_bottom_right_delta_.y());
+
+ gfx::Rect new_expanded(
+ expanded.origin(),
+ GetExpandedWindowSize(message_handler_->window_ex_style(),
+ expanded.size()));
+ window_enlargement_ =
+ gfx::Vector2d(new_expanded.width() - expanded.width(),
+ new_expanded.height() - expanded.height());
+ message_handler_->SetBounds(new_expanded, old_content_size != bounds.size());
+}
+
+gfx::Point DesktopWindowTreeHostWin::GetLocationOnNativeScreen() const {
+ return GetBounds().origin();
+}
+
+void DesktopWindowTreeHostWin::SetCapture() {
+ message_handler_->SetCapture();
+}
+
+void DesktopWindowTreeHostWin::ReleaseCapture() {
+ message_handler_->ReleaseCapture();
+}
+
+void DesktopWindowTreeHostWin::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+}
+
+void DesktopWindowTreeHostWin::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) {
+ ui::CursorLoaderWin cursor_loader;
+ cursor_loader.SetPlatformCursor(&cursor);
+
+ message_handler_->SetCursor(cursor.platform());
+}
+
+void DesktopWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
+ if (is_cursor_visible_ == show)
+ return;
+ is_cursor_visible_ = show;
+ ::ShowCursor(!!show);
+}
+
+void DesktopWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) {
+ POINT cursor_location = location.ToPOINT();
+ ::ClientToScreen(GetHWND(), &cursor_location);
+ ::SetCursorPos(cursor_location.x, cursor_location.y);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, ui::EventSource implementation:
+
+ui::EventProcessor* DesktopWindowTreeHostWin::GetEventProcessor() {
+ return dispatcher();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, aura::AnimationHost implementation:
+
+void DesktopWindowTreeHostWin::SetHostTransitionOffsets(
+ const gfx::Vector2d& top_left_delta,
+ const gfx::Vector2d& bottom_right_delta) {
+ gfx::Rect bounds_without_expansion = GetBounds();
+ window_expansion_top_left_delta_ = top_left_delta;
+ window_expansion_bottom_right_delta_ = bottom_right_delta;
+ SetBounds(bounds_without_expansion);
+}
+
+void DesktopWindowTreeHostWin::OnWindowHidingAnimationCompleted() {
+ if (pending_close_)
+ message_handler_->Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, HWNDMessageHandlerDelegate implementation:
+
+bool DesktopWindowTreeHostWin::IsWidgetWindow() const {
+ return has_non_client_view_;
+}
+
+bool DesktopWindowTreeHostWin::IsUsingCustomFrame() const {
+ return !GetWidget()->ShouldUseNativeFrame();
+}
+
+void DesktopWindowTreeHostWin::SchedulePaint() {
+ GetWidget()->GetRootView()->SchedulePaint();
+}
+
+void DesktopWindowTreeHostWin::EnableInactiveRendering() {
+ native_widget_delegate_->EnableInactiveRendering();
+}
+
+bool DesktopWindowTreeHostWin::IsInactiveRenderingDisabled() {
+ return native_widget_delegate_->IsInactiveRenderingDisabled();
+}
+
+bool DesktopWindowTreeHostWin::CanResize() const {
+ return GetWidget()->widget_delegate()->CanResize();
+}
+
+bool DesktopWindowTreeHostWin::CanMaximize() const {
+ return GetWidget()->widget_delegate()->CanMaximize();
+}
+
+bool DesktopWindowTreeHostWin::CanActivate() const {
+ if (IsModalWindowActive())
+ return true;
+ return native_widget_delegate_->CanActivate();
+}
+
+bool DesktopWindowTreeHostWin::WidgetSizeIsClientSize() const {
+ const Widget* widget = GetWidget()->GetTopLevelWidget();
+ return IsMaximized() || (widget && widget->ShouldUseNativeFrame());
+}
+
+bool DesktopWindowTreeHostWin::IsModal() const {
+ return native_widget_delegate_->IsModal();
+}
+
+int DesktopWindowTreeHostWin::GetInitialShowState() const {
+ return CanActivate() ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
+}
+
+bool DesktopWindowTreeHostWin::WillProcessWorkAreaChange() const {
+ return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
+}
+
+int DesktopWindowTreeHostWin::GetNonClientComponent(
+ const gfx::Point& point) const {
+ gfx::Point dip_position = gfx::win::ScreenToDIPPoint(point);
+ return native_widget_delegate_->GetNonClientComponent(dip_position);
+}
+
+void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size,
+ gfx::Path* path) {
+ if (GetWidget()->non_client_view()) {
+ GetWidget()->non_client_view()->GetWindowMask(size, path);
+ } else if (!window_enlargement_.IsZero()) {
+ gfx::Rect bounds(WidgetSizeIsClientSize()
+ ? message_handler_->GetClientAreaBoundsInScreen()
+ : message_handler_->GetWindowBoundsInScreen());
+ InsetBottomRight(&bounds, window_enlargement_);
+ path->addRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
+ }
+}
+
+bool DesktopWindowTreeHostWin::GetClientAreaInsets(gfx::Insets* insets) const {
+ return false;
+}
+
+void DesktopWindowTreeHostWin::GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const {
+ *min_size = native_widget_delegate_->GetMinimumSize();
+ *max_size = native_widget_delegate_->GetMaximumSize();
+}
+
+gfx::Size DesktopWindowTreeHostWin::GetRootViewSize() const {
+ return GetWidget()->GetRootView()->size();
+}
+
+void DesktopWindowTreeHostWin::ResetWindowControls() {
+ GetWidget()->non_client_view()->ResetWindowControls();
+}
+
+void DesktopWindowTreeHostWin::PaintLayeredWindow(gfx::Canvas* canvas) {
+ GetWidget()->GetRootView()->Paint(canvas, views::CullSet());
+}
+
+gfx::NativeViewAccessible DesktopWindowTreeHostWin::GetNativeViewAccessible() {
+ return GetWidget()->GetRootView()->GetNativeViewAccessible();
+}
+
+InputMethod* DesktopWindowTreeHostWin::GetInputMethod() {
+ return GetWidget()->GetInputMethodDirect();
+}
+
+bool DesktopWindowTreeHostWin::ShouldHandleSystemCommands() const {
+ return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
+}
+
+void DesktopWindowTreeHostWin::HandleAppDeactivated() {
+ native_widget_delegate_->EnableInactiveRendering();
+}
+
+void DesktopWindowTreeHostWin::HandleActivationChanged(bool active) {
+ // This can be invoked from HWNDMessageHandler::Init(), at which point we're
+ // not in a good state and need to ignore it.
+ // TODO(beng): Do we need this still now the host owns the dispatcher?
+ if (!dispatcher())
+ return;
+
+ if (active)
+ OnHostActivated();
+ desktop_native_widget_aura_->HandleActivationChanged(active);
+}
+
+bool DesktopWindowTreeHostWin::HandleAppCommand(short command) {
+ // We treat APPCOMMAND ids as an extension of our command namespace, and just
+ // let the delegate figure out what to do...
+ return GetWidget()->widget_delegate() &&
+ GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void DesktopWindowTreeHostWin::HandleCancelMode() {
+ dispatcher()->DispatchCancelModeEvent();
+}
+
+void DesktopWindowTreeHostWin::HandleCaptureLost() {
+ OnHostLostWindowCapture();
+ native_widget_delegate_->OnMouseCaptureLost();
+}
+
+void DesktopWindowTreeHostWin::HandleClose() {
+ GetWidget()->Close();
+}
+
+bool DesktopWindowTreeHostWin::HandleCommand(int command) {
+ return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
+}
+
+void DesktopWindowTreeHostWin::HandleAccelerator(
+ const ui::Accelerator& accelerator) {
+ GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
+}
+
+void DesktopWindowTreeHostWin::HandleCreate() {
+ native_widget_delegate_->OnNativeWidgetCreated(true);
+}
+
+void DesktopWindowTreeHostWin::HandleDestroying() {
+ drag_drop_client_->OnNativeWidgetDestroying(GetHWND());
+ native_widget_delegate_->OnNativeWidgetDestroying();
+
+ // Destroy the compositor before destroying the HWND since shutdown
+ // may try to swap to the window.
+ DestroyCompositor();
+}
+
+void DesktopWindowTreeHostWin::HandleDestroyed() {
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+bool DesktopWindowTreeHostWin::HandleInitialFocus(
+ ui::WindowShowState show_state) {
+ return GetWidget()->SetInitialFocus(show_state);
+}
+
+void DesktopWindowTreeHostWin::HandleDisplayChange() {
+ GetWidget()->widget_delegate()->OnDisplayChanged();
+}
+
+void DesktopWindowTreeHostWin::HandleBeginWMSizeMove() {
+ native_widget_delegate_->OnNativeWidgetBeginUserBoundsChange();
+}
+
+void DesktopWindowTreeHostWin::HandleEndWMSizeMove() {
+ native_widget_delegate_->OnNativeWidgetEndUserBoundsChange();
+}
+
+void DesktopWindowTreeHostWin::HandleMove() {
+ native_widget_delegate_->OnNativeWidgetMove();
+ OnHostMoved(GetBounds().origin());
+}
+
+void DesktopWindowTreeHostWin::HandleWorkAreaChanged() {
+ GetWidget()->widget_delegate()->OnWorkAreaChanged();
+}
+
+void DesktopWindowTreeHostWin::HandleVisibilityChanging(bool visible) {
+ native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible);
+}
+
+void DesktopWindowTreeHostWin::HandleVisibilityChanged(bool visible) {
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
+}
+
+void DesktopWindowTreeHostWin::HandleClientSizeChanged(
+ const gfx::Size& new_size) {
+ if (dispatcher())
+ OnHostResized(new_size);
+}
+
+void DesktopWindowTreeHostWin::HandleFrameChanged() {
+ SetWindowTransparency();
+ // Replace the frame and layout the contents.
+ GetWidget()->non_client_view()->UpdateFrame();
+}
+
+void DesktopWindowTreeHostWin::HandleNativeFocus(HWND last_focused_window) {
+ // TODO(beng): inform the native_widget_delegate_.
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnFocus();
+}
+
+void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
+ // TODO(beng): inform the native_widget_delegate_.
+ InputMethod* input_method = GetInputMethod();
+ if (input_method)
+ input_method->OnBlur();
+}
+
+bool DesktopWindowTreeHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
+ SendEventToProcessor(const_cast<ui::MouseEvent*>(&event));
+ return event.handled();
+}
+
+bool DesktopWindowTreeHostWin::HandleKeyEvent(const ui::KeyEvent& event) {
+ return false;
+}
+
+bool DesktopWindowTreeHostWin::HandleUntranslatedKeyEvent(
+ const ui::KeyEvent& event) {
+ ui::KeyEvent duplicate_event(event);
+ SendEventToProcessor(&duplicate_event);
+ return duplicate_event.handled();
+}
+
+void DesktopWindowTreeHostWin::HandleTouchEvent(
+ const 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.
+ if (!GetWidget()->GetNativeView())
+ return;
+
+ // Currently we assume the window that has capture gets touch events too.
+ aura::WindowTreeHost* host =
+ aura::WindowTreeHost::GetForAcceleratedWidget(GetCapture());
+ if (host) {
+ DesktopWindowTreeHostWin* target =
+ host->window()->GetProperty(kDesktopWindowTreeHostKey);
+ if (target && target->HasCapture() && target != this) {
+ POINT target_location(event.location().ToPOINT());
+ ClientToScreen(GetHWND(), &target_location);
+ ScreenToClient(target->GetHWND(), &target_location);
+ 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());
+ target->SendEventToProcessor(&target_event);
+ return;
+ }
+ }
+ SendEventToProcessor(const_cast<ui::TouchEvent*>(&event));
+}
+
+bool DesktopWindowTreeHostWin::HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ MSG msg = {};
+ msg.hwnd = GetHWND();
+ msg.message = message;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ return desktop_native_widget_aura_->input_method_event_filter()->
+ input_method()->OnUntranslatedIMEMessage(msg, result);
+}
+
+void DesktopWindowTreeHostWin::HandleInputLanguageChange(
+ DWORD character_set,
+ HKL input_language_id) {
+ desktop_native_widget_aura_->input_method_event_filter()->
+ input_method()->OnInputLocaleChanged();
+}
+
+bool DesktopWindowTreeHostWin::HandlePaintAccelerated(
+ const gfx::Rect& invalid_rect) {
+ return native_widget_delegate_->OnNativeWidgetPaintAccelerated(invalid_rect);
+}
+
+void DesktopWindowTreeHostWin::HandlePaint(gfx::Canvas* canvas) {
+ // It appears possible to get WM_PAINT after WM_DESTROY.
+ if (compositor())
+ compositor()->ScheduleRedrawRect(gfx::Rect());
+}
+
+bool DesktopWindowTreeHostWin::HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) {
+ return tooltip_ && tooltip_->HandleNotify(w_param, l_param, l_result);
+}
+
+void DesktopWindowTreeHostWin::HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // TooltipWin implementation doesn't need this.
+ // TODO(sky): remove from HWNDMessageHandler once non-aura path nuked.
+}
+
+void DesktopWindowTreeHostWin::HandleMenuLoop(bool in_menu_loop) {
+ if (in_menu_loop) {
+ tooltip_disabler_.reset(
+ new aura::client::ScopedTooltipDisabler(window()));
+ } else {
+ tooltip_disabler_.reset();
+ }
+}
+
+bool DesktopWindowTreeHostWin::PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) {
+ return false;
+}
+
+void DesktopWindowTreeHostWin::PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+}
+
+bool DesktopWindowTreeHostWin::HandleScrollEvent(
+ const ui::ScrollEvent& event) {
+ SendEventToProcessor(const_cast<ui::ScrollEvent*>(&event));
+ return event.handled();
+}
+
+void DesktopWindowTreeHostWin::HandleWindowSizeChanging() {
+ if (compositor())
+ compositor()->FinishAllRendering();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostWin, private:
+
+Widget* DesktopWindowTreeHostWin::GetWidget() {
+ return native_widget_delegate_->AsWidget();
+}
+
+const Widget* DesktopWindowTreeHostWin::GetWidget() const {
+ return native_widget_delegate_->AsWidget();
+}
+
+HWND DesktopWindowTreeHostWin::GetHWND() const {
+ return message_handler_->hwnd();
+}
+
+void DesktopWindowTreeHostWin::SetWindowTransparency() {
+ bool transparent = ShouldUseNativeFrame() && !IsFullscreen();
+ compositor()->SetHostHasTransparentBackground(transparent);
+ window()->SetTransparent(transparent);
+ content_window_->SetTransparent(transparent);
+}
+
+bool DesktopWindowTreeHostWin::IsModalWindowActive() const {
+ // This function can get called during window creation which occurs before
+ // dispatcher() has been created.
+ if (!dispatcher())
+ return false;
+
+ aura::Window::Windows::const_iterator index;
+ for (index = window()->children().begin();
+ index != window()->children().end();
+ ++index) {
+ if ((*index)->GetProperty(aura::client::kModalKey) !=
+ ui:: MODAL_TYPE_NONE && (*index)->TargetVisibility())
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHost, public:
+
+// static
+DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura) {
+ return new DesktopWindowTreeHostWin(native_widget_delegate,
+ desktop_native_widget_aura);
+}
+
+} // namespace views
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
new file mode 100644
index 00000000000..225365f5b14
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -0,0 +1,276 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_WIN_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_WIN_H_
+
+#include "ui/aura/window_tree_host.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+#include "ui/views/win/hwnd_message_handler_delegate.h"
+#include "ui/wm/public/animation_host.h"
+
+namespace aura {
+namespace client {
+class DragDropClient;
+class FocusClient;
+class ScopedTooltipDisabler;
+}
+}
+
+namespace views {
+class DesktopCursorClient;
+class DesktopDragDropClientWin;
+class HWNDMessageHandler;
+
+namespace corewm {
+class TooltipWin;
+}
+
+class VIEWS_EXPORT DesktopWindowTreeHostWin
+ : public DesktopWindowTreeHost,
+ public aura::client::AnimationHost,
+ public aura::WindowTreeHost,
+ public ui::EventSource,
+ public HWNDMessageHandlerDelegate {
+ public:
+ DesktopWindowTreeHostWin(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura);
+ virtual ~DesktopWindowTreeHostWin();
+
+ // A way of converting an HWND into a content window.
+ static aura::Window* GetContentWindowForHWND(HWND hwnd);
+
+ protected:
+ // Overridden from DesktopWindowTreeHost:
+ virtual void Init(aura::Window* content_window,
+ const Widget::InitParams& params) OVERRIDE;
+ virtual void OnNativeWidgetCreated(const Widget::InitParams& params) OVERRIDE;
+ virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
+ virtual scoped_ptr<aura::client::DragDropClient>
+ CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual aura::WindowTreeHost* AsWindowTreeHost() OVERRIDE;
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual bool IsAlwaysOnTop() const OVERRIDE;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
+ virtual bool SetWindowTitle(const base::string16& title) OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual bool ShouldWindowContentsBeTransparent() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void OnRootViewLayout() const OVERRIDE;
+ virtual void OnNativeWidgetFocus() OVERRIDE;
+ virtual void OnNativeWidgetBlur() OVERRIDE;
+ virtual bool IsAnimatingClosed() const OVERRIDE;
+ virtual bool IsTranslucentWindowOpacitySupported() const OVERRIDE;
+
+ // Overridden from aura::WindowTreeHost:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+
+ // Overridden frm ui::EventSource
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ // Overridden from aura::client::AnimationHost
+ virtual void SetHostTransitionOffsets(
+ const gfx::Vector2d& top_left_delta,
+ const gfx::Vector2d& bottom_right_delta) OVERRIDE;
+ virtual void OnWindowHidingAnimationCompleted() OVERRIDE;
+
+ // Overridden from HWNDMessageHandlerDelegate:
+ virtual bool IsWidgetWindow() const OVERRIDE;
+ virtual bool IsUsingCustomFrame() const OVERRIDE;
+ virtual void SchedulePaint() OVERRIDE;
+ virtual void EnableInactiveRendering() OVERRIDE;
+ virtual bool IsInactiveRenderingDisabled() OVERRIDE;
+ virtual bool CanResize() const OVERRIDE;
+ virtual bool CanMaximize() const OVERRIDE;
+ virtual bool CanActivate() const OVERRIDE;
+ virtual bool WidgetSizeIsClientSize() const OVERRIDE;
+ virtual bool IsModal() const OVERRIDE;
+ virtual int GetInitialShowState() const OVERRIDE;
+ virtual bool WillProcessWorkAreaChange() const OVERRIDE;
+ virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
+ virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
+ virtual void GetMinMaxSize(gfx::Size* min_size,
+ gfx::Size* max_size) const OVERRIDE;
+ virtual gfx::Size GetRootViewSize() const OVERRIDE;
+ virtual void ResetWindowControls() OVERRIDE;
+ virtual void PaintLayeredWindow(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ virtual bool ShouldHandleSystemCommands() const OVERRIDE;
+ virtual InputMethod* GetInputMethod() OVERRIDE;
+ virtual void HandleAppDeactivated() OVERRIDE;
+ virtual void HandleActivationChanged(bool active) OVERRIDE;
+ virtual bool HandleAppCommand(short command) OVERRIDE;
+ virtual void HandleCancelMode() OVERRIDE;
+ virtual void HandleCaptureLost() OVERRIDE;
+ virtual void HandleClose() OVERRIDE;
+ virtual bool HandleCommand(int command) OVERRIDE;
+ virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
+ virtual void HandleCreate() OVERRIDE;
+ virtual void HandleDestroying() OVERRIDE;
+ virtual void HandleDestroyed() OVERRIDE;
+ virtual bool HandleInitialFocus(ui::WindowShowState show_state) OVERRIDE;
+ virtual void HandleDisplayChange() OVERRIDE;
+ virtual void HandleBeginWMSizeMove() OVERRIDE;
+ virtual void HandleEndWMSizeMove() OVERRIDE;
+ virtual void HandleMove() OVERRIDE;
+ virtual void HandleWorkAreaChanged() OVERRIDE;
+ virtual void HandleVisibilityChanging(bool visible) OVERRIDE;
+ virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
+ virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
+ virtual void HandleFrameChanged() OVERRIDE;
+ virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE;
+ virtual void HandleNativeBlur(HWND focused_window) OVERRIDE;
+ virtual bool HandleMouseEvent(const ui::MouseEvent& event) OVERRIDE;
+ virtual bool HandleKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
+ virtual void HandleTouchEvent(const ui::TouchEvent& event) OVERRIDE;
+ virtual bool HandleIMEMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void HandleInputLanguageChange(DWORD character_set,
+ HKL input_language_id) OVERRIDE;
+ virtual bool HandlePaintAccelerated(const gfx::Rect& invalid_rect) OVERRIDE;
+ virtual void HandlePaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual bool HandleTooltipNotify(int w_param,
+ NMHDR* l_param,
+ LRESULT* l_result) OVERRIDE;
+ virtual void HandleTooltipMouseMove(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual void HandleMenuLoop(bool in_menu_loop) OVERRIDE;
+ virtual bool PreHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* result) OVERRIDE;
+ virtual void PostHandleMSG(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual bool HandleScrollEvent(const ui::ScrollEvent& event) OVERRIDE;
+ virtual void HandleWindowSizeChanging() OVERRIDE;
+
+ Widget* GetWidget();
+ const Widget* GetWidget() const;
+ HWND GetHWND() const;
+
+ private:
+ void SetWindowTransparency();
+
+ // Returns true if a modal window is active in the current root window chain.
+ bool IsModalWindowActive() const;
+
+ scoped_ptr<HWNDMessageHandler> message_handler_;
+ scoped_ptr<aura::client::FocusClient> focus_client_;
+
+ // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
+ // instead of providing this route back to Widget.
+ internal::NativeWidgetDelegate* native_widget_delegate_;
+
+ DesktopNativeWidgetAura* desktop_native_widget_aura_;
+
+ aura::Window* content_window_;
+
+ // Owned by DesktopNativeWidgetAura.
+ DesktopDragDropClientWin* drag_drop_client_;
+
+ // When certain windows are being shown, we augment the window size
+ // temporarily for animation. The following two members contain the top left
+ // and bottom right offsets which are used to enlarge the window.
+ gfx::Vector2d window_expansion_top_left_delta_;
+ gfx::Vector2d window_expansion_bottom_right_delta_;
+
+ // Windows are enlarged to be at least 64x64 pixels, so keep track of the
+ // extra added here.
+ gfx::Vector2d window_enlargement_;
+
+ // Whether the window close should be converted to a hide, and then actually
+ // closed on the completion of the hide animation. This is cached because
+ // the property is set on the contained window which has a shorter lifetime.
+ bool should_animate_window_close_;
+
+ // When Close()d and animations are being applied to this window, the close
+ // of the window needs to be deferred to when the close animation is
+ // completed. This variable indicates that a Close was converted to a Hide,
+ // so that when the Hide is completed the host window should be closed.
+ bool pending_close_;
+
+ // True if the widget is going to have a non_client_view. We cache this value
+ // rather than asking the Widget for the non_client_view so that we know at
+ // Init time, before the Widget has created the NonClientView.
+ bool has_non_client_view_;
+
+ // Owned by TooltipController, but we need to forward events to it so we keep
+ // a reference.
+ corewm::TooltipWin* tooltip_;
+
+ // Visibility of the cursor. On Windows we can have multiple root windows and
+ // the implementation of ::ShowCursor() is based on a counter, so making this
+ // member static ensures that ::ShowCursor() is always called exactly once
+ // whenever the cursor visibility state changes.
+ static bool is_cursor_visible_;
+
+ scoped_ptr<aura::client::ScopedTooltipDisabler> tooltip_disabler_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostWin);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_WIN_H_
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
new file mode 100644
index 00000000000..9a96e53c283
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -0,0 +1,1838 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+
+#include <X11/extensions/shape.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/Xatom.h>
+#include <X11/Xregion.h>
+#include <X11/Xutil.h>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/events/x/device_data_manager.h"
+#include "ui/events/x/device_list_cache_x.h"
+#include "ui/events/x/touch_factory_x11.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/path_x11.h"
+#include "ui/gfx/screen.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/corewm/tooltip_aura.h"
+#include "ui/views/ime/input_method.h"
+#include "ui/views/linux_ui/linux_ui.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/views_switches.h"
+#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
+#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
+#include "ui/views/widget/desktop_aura/x11_scoped_capture.h"
+#include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
+#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/core/window_util.h"
+
+namespace views {
+
+DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
+ NULL;
+std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
+
+DEFINE_WINDOW_PROPERTY_KEY(
+ aura::Window*, kViewsWindowForRootWindow, NULL);
+
+DEFINE_WINDOW_PROPERTY_KEY(
+ DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
+
+namespace {
+
+// Constants that are part of EWMH.
+const int k_NET_WM_STATE_ADD = 1;
+const int k_NET_WM_STATE_REMOVE = 0;
+
+// Special value of the _NET_WM_DESKTOP property which indicates that the window
+// should appear on all desktops.
+const int kAllDesktops = 0xFFFFFFFF;
+
+const char* kAtomsToCache[] = {
+ "UTF8_STRING",
+ "WM_DELETE_WINDOW",
+ "WM_PROTOCOLS",
+ "_NET_FRAME_EXTENTS",
+ "_NET_WM_CM_S0",
+ "_NET_WM_DESKTOP",
+ "_NET_WM_ICON",
+ "_NET_WM_NAME",
+ "_NET_WM_PID",
+ "_NET_WM_PING",
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_FULLSCREEN",
+ "_NET_WM_STATE_HIDDEN",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_STATE_STICKY",
+ "_NET_WM_USER_TIME",
+ "_NET_WM_WINDOW_OPACITY",
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_WINDOW_TYPE_DND",
+ "_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+ "_NET_WM_WINDOW_TYPE_TOOLTIP",
+ "XdndActionAsk",
+ "XdndActionCopy"
+ "XdndActionLink",
+ "XdndActionList",
+ "XdndActionMove",
+ "XdndActionPrivate",
+ "XdndAware",
+ "XdndDrop",
+ "XdndEnter",
+ "XdndFinished",
+ "XdndLeave",
+ "XdndPosition",
+ "XdndProxy", // Proxy windows?
+ "XdndSelection",
+ "XdndStatus",
+ "XdndTypeList",
+ NULL
+};
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, public:
+
+DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura)
+ : close_widget_factory_(this),
+ xdisplay_(gfx::GetXDisplay()),
+ xwindow_(0),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ atom_cache_(xdisplay_, kAtomsToCache),
+ window_mapped_(false),
+ is_fullscreen_(false),
+ is_always_on_top_(false),
+ use_native_frame_(false),
+ use_argb_visual_(false),
+ drag_drop_client_(NULL),
+ current_cursor_(ui::kCursorNull),
+ native_widget_delegate_(native_widget_delegate),
+ desktop_native_widget_aura_(desktop_native_widget_aura),
+ content_window_(NULL),
+ window_parent_(NULL),
+ window_shape_(NULL),
+ custom_window_shape_(false),
+ urgency_hint_set_(false) {
+}
+
+DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
+ window()->ClearProperty(kHostForRootWindow);
+ aura::client::SetWindowMoveClient(window(), NULL);
+ desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
+ if (window_shape_)
+ XDestroyRegion(window_shape_);
+ DestroyDispatcher();
+}
+
+// static
+aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
+ aura::WindowTreeHost* host =
+ aura::WindowTreeHost::GetForAcceleratedWidget(xid);
+ return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
+}
+
+// static
+DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
+ aura::WindowTreeHost* host =
+ aura::WindowTreeHost::GetForAcceleratedWidget(xid);
+ return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
+}
+
+// static
+std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
+ std::vector<aura::Window*> windows(open_windows().size());
+ std::transform(open_windows().begin(),
+ open_windows().end(),
+ windows.begin(),
+ GetContentWindowForXID);
+ return windows;
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
+ return bounds_;
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
+ gfx::Rect outer_bounds(bounds_);
+ outer_bounds.Inset(-native_window_frame_borders_);
+ return outer_bounds;
+}
+
+::Region DesktopWindowTreeHostX11::GetWindowShape() const {
+ return window_shape_;
+}
+
+void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
+ bool active) {
+ if (active) {
+ FlashFrame(false);
+ OnHostActivated();
+ open_windows().remove(xwindow_);
+ open_windows().insert(open_windows().begin(), xwindow_);
+ }
+
+ desktop_native_widget_aura_->HandleActivationChanged(active);
+
+ native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+}
+
+void DesktopWindowTreeHostX11::AddObserver(
+ views::DesktopWindowTreeHostObserverX11* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void DesktopWindowTreeHostX11::RemoveObserver(
+ views::DesktopWindowTreeHostObserverX11* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
+ scoped_ptr<ui::EventHandler> handler) {
+ wm::CompoundEventFilter* compound_event_filter =
+ desktop_native_widget_aura_->root_window_event_filter();
+ if (x11_non_client_event_filter_)
+ compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get());
+ compound_event_filter->AddHandler(handler.get());
+ x11_non_client_event_filter_ = handler.Pass();
+}
+
+void DesktopWindowTreeHostX11::CleanUpWindowList() {
+ delete open_windows_;
+ open_windows_ = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
+
+void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
+ const Widget::InitParams& params) {
+ content_window_ = content_window;
+
+ // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
+ // whether we should be proxying requests to another DRWHL.
+
+ // In some situations, views tries to make a zero sized window, and that
+ // makes us crash. Make sure we have valid sizes.
+ Widget::InitParams sanitized_params = params;
+ if (sanitized_params.bounds.width() == 0)
+ sanitized_params.bounds.set_width(100);
+ if (sanitized_params.bounds.height() == 0)
+ sanitized_params.bounds.set_height(100);
+
+ InitX11Window(sanitized_params);
+}
+
+void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
+ const Widget::InitParams& params) {
+ window()->SetProperty(kViewsWindowForRootWindow, content_window_);
+ window()->SetProperty(kHostForRootWindow, this);
+
+ // Ensure that the X11DesktopHandler exists so that it dispatches activation
+ // messages to us.
+ X11DesktopHandler::get();
+
+ // TODO(erg): Unify this code once the other consumer goes away.
+ SwapNonClientEventHandler(
+ scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass());
+ SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
+ !params.remove_standard_frame);
+
+ x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
+ aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
+
+ SetWindowTransparency();
+
+ native_widget_delegate_->OnNativeWidgetCreated(true);
+}
+
+scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
+ return scoped_ptr<corewm::Tooltip>(
+ new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
+}
+
+scoped_ptr<aura::client::DragDropClient>
+DesktopWindowTreeHostX11::CreateDragDropClient(
+ DesktopNativeCursorManager* cursor_manager) {
+ drag_drop_client_ = new DesktopDragDropClientAuraX11(
+ window(), cursor_manager, xdisplay_, xwindow_);
+ return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
+}
+
+void DesktopWindowTreeHostX11::Close() {
+ // TODO(erg): Might need to do additional hiding tasks here.
+ delayed_resize_task_.Cancel();
+
+ if (!close_widget_factory_.HasWeakPtrs()) {
+ // And we delay the close so that if we are called from an ATL callback,
+ // we don't destroy the window before the callback returned (as the caller
+ // may delete ourselves on destroy and the ATL callback would still
+ // dereference us when the callback returns).
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&DesktopWindowTreeHostX11::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
+ }
+}
+
+void DesktopWindowTreeHostX11::CloseNow() {
+ if (xwindow_ == None)
+ return;
+
+ x11_capture_.reset();
+ native_widget_delegate_->OnNativeWidgetDestroying();
+
+ // If we have children, close them. Use a copy for iteration because they'll
+ // remove themselves.
+ std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
+ for (std::set<DesktopWindowTreeHostX11*>::iterator it =
+ window_children_copy.begin(); it != window_children_copy.end();
+ ++it) {
+ (*it)->CloseNow();
+ }
+ DCHECK(window_children_.empty());
+
+ // If we have a parent, remove ourselves from its children list.
+ if (window_parent_) {
+ window_parent_->window_children_.erase(this);
+ window_parent_ = NULL;
+ }
+
+ // Remove the event listeners we've installed. We need to remove these
+ // because otherwise we get assert during ~WindowEventDispatcher().
+ desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
+ x11_non_client_event_filter_.get());
+ x11_non_client_event_filter_.reset();
+
+ // Destroy the compositor before destroying the |xwindow_| since shutdown
+ // may try to swap, and the swap without a window causes an X error, which
+ // causes a crash with in-process renderer.
+ DestroyCompositor();
+
+ open_windows().remove(xwindow_);
+ // Actually free our native resources.
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ XDestroyWindow(xdisplay_, xwindow_);
+ xwindow_ = None;
+
+ desktop_native_widget_aura_->OnHostClosed();
+}
+
+aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
+ return this;
+}
+
+void DesktopWindowTreeHostX11::ShowWindowWithState(
+ ui::WindowShowState show_state) {
+ if (!window_mapped_)
+ MapWindow(show_state);
+
+ if (show_state == ui::SHOW_STATE_NORMAL ||
+ show_state == ui::SHOW_STATE_MAXIMIZED) {
+ // Note: XFCE ignores a maximize hint given before mapping the window.
+ if (show_state == ui::SHOW_STATE_MAXIMIZED)
+ Maximize();
+ Activate();
+ }
+
+ native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
+}
+
+void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
+ // Enforce |restored_bounds_| since calling Maximize() could have reset it.
+ restored_bounds_ = restored_bounds;
+}
+
+bool DesktopWindowTreeHostX11::IsVisible() const {
+ return window_mapped_;
+}
+
+void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) {
+ bool size_changed = bounds_.size() != size;
+ XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
+ bounds_.set_size(size);
+ if (size_changed) {
+ OnHostResized(size);
+ ResetWindowRegion();
+ }
+}
+
+void DesktopWindowTreeHostX11::StackAtTop() {
+ XRaiseWindow(xdisplay_, xwindow_);
+}
+
+void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
+ gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
+
+ // If |window_|'s transient parent bounds are big enough to contain |size|,
+ // use them instead.
+ if (wm::GetTransientParent(content_window_)) {
+ gfx::Rect transient_parent_rect =
+ wm::GetTransientParent(content_window_)->GetBoundsInScreen();
+ if (transient_parent_rect.height() >= size.height() &&
+ transient_parent_rect.width() >= size.width()) {
+ parent_bounds = transient_parent_rect;
+ }
+ }
+
+ gfx::Rect window_bounds(
+ parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
+ parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
+ size.width(),
+ size.height());
+ // Don't size the window bigger than the parent, otherwise the user may not be
+ // able to close or move it.
+ window_bounds.AdjustToFit(parent_bounds);
+
+ SetBounds(window_bounds);
+}
+
+void DesktopWindowTreeHostX11::GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
+ *bounds = GetRestoredBounds();
+
+ if (IsFullscreen()) {
+ *show_state = ui::SHOW_STATE_FULLSCREEN;
+ } else if (IsMinimized()) {
+ *show_state = ui::SHOW_STATE_MINIMIZED;
+ } else if (IsMaximized()) {
+ *show_state = ui::SHOW_STATE_MAXIMIZED;
+ } else if (!IsActive()) {
+ *show_state = ui::SHOW_STATE_INACTIVE;
+ } else {
+ *show_state = ui::SHOW_STATE_NORMAL;
+ }
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
+ return bounds_;
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
+ // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
+ // needed for View::ConvertPointToScreen() to work
+ // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
+ // asks windows what it thinks the client rect is.
+ //
+ // Attempts to calculate the rect by asking the NonClientFrameView what it
+ // thought its GetBoundsForClientView() were broke combobox drop down
+ // placement.
+ return bounds_;
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
+ // We can't reliably track the restored bounds of a window, but we can get
+ // the 90% case down. When *chrome* is the process that requests maximizing
+ // or restoring bounds, we can record the current bounds before we request
+ // maximization, and clear it when we detect a state change.
+ if (!restored_bounds_.IsEmpty())
+ return restored_bounds_;
+
+ return GetWindowBoundsInScreen();
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
+ std::vector<int> value;
+ if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
+ value.size() >= 4) {
+ return gfx::Rect(value[0], value[1], value[2], value[3]);
+ }
+
+ // Fetch the geometry of the root window.
+ Window root;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width, depth;
+ if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
+ &width, &height, &border_width, &depth)) {
+ NOTIMPLEMENTED();
+ return gfx::Rect(0, 0, 10, 10);
+ }
+
+ return gfx::Rect(x, y, width, height);
+}
+
+void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
+ if (window_shape_)
+ XDestroyRegion(window_shape_);
+ custom_window_shape_ = true;
+ window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
+ ResetWindowRegion();
+ delete native_region;
+}
+
+void DesktopWindowTreeHostX11::Activate() {
+ if (!window_mapped_)
+ return;
+
+ X11DesktopHandler::get()->ActivateWindow(xwindow_);
+}
+
+void DesktopWindowTreeHostX11::Deactivate() {
+ if (!IsActive())
+ return;
+
+ x11_capture_.reset();
+ XLowerWindow(xdisplay_, xwindow_);
+}
+
+bool DesktopWindowTreeHostX11::IsActive() const {
+ return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
+}
+
+void DesktopWindowTreeHostX11::Maximize() {
+ // When we are in the process of requesting to maximize a window, we can
+ // accurately keep track of our restored bounds instead of relying on the
+ // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
+ restored_bounds_ = bounds_;
+
+ SetWMSpecState(true,
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ if (IsMinimized())
+ ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+}
+
+void DesktopWindowTreeHostX11::Minimize() {
+ x11_capture_.reset();
+ XIconifyWindow(xdisplay_, xwindow_, 0);
+}
+
+void DesktopWindowTreeHostX11::Restore() {
+ SetWMSpecState(false,
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
+ atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ if (IsMinimized())
+ ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+}
+
+bool DesktopWindowTreeHostX11::IsMaximized() const {
+ return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
+ HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
+}
+
+bool DesktopWindowTreeHostX11::IsMinimized() const {
+ return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
+}
+
+bool DesktopWindowTreeHostX11::HasCapture() const {
+ return g_current_capture == this;
+}
+
+void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
+ is_always_on_top_ = always_on_top;
+ SetWMSpecState(always_on_top,
+ atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
+ None);
+}
+
+bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
+ return is_always_on_top_;
+}
+
+void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
+ SetWMSpecState(always_visible,
+ atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
+ None);
+
+ int new_desktop = 0;
+ if (always_visible) {
+ new_desktop = kAllDesktops;
+ } else {
+ if (!ui::GetCurrentDesktop(&new_desktop))
+ return;
+ }
+
+ XEvent xevent;
+ memset (&xevent, 0, sizeof (xevent));
+ xevent.type = ClientMessage;
+ xevent.xclient.window = xwindow_;
+ xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP");
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = new_desktop;
+ xevent.xclient.data.l[1] = 0;
+ xevent.xclient.data.l[2] = 0;
+ xevent.xclient.data.l[3] = 0;
+ xevent.xclient.data.l[4] = 0;
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xevent);
+}
+
+bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
+ if (window_title_ == title)
+ return false;
+ window_title_ = title;
+ std::string utf8str = base::UTF16ToUTF8(title);
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_NAME"),
+ atom_cache_.GetAtom("UTF8_STRING"),
+ 8,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(utf8str.c_str()),
+ utf8str.size());
+ // TODO(erg): This is technically wrong. So XStoreName and friends expect
+ // this in Host Portable Character Encoding instead of UTF-8, which I believe
+ // is Compound Text. This shouldn't matter 90% of the time since this is the
+ // fallback to the UTF8 property above.
+ XStoreName(xdisplay_, xwindow_, utf8str.c_str());
+ return true;
+}
+
+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
+ // 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_);
+ }
+}
+
+Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) {
+ aura::client::WindowMoveSource window_move_source =
+ source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE :
+ aura::client::WINDOW_MOVE_SOURCE_TOUCH;
+ if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
+ window_move_source) == aura::client::MOVE_SUCCESSFUL)
+ return Widget::MOVE_LOOP_SUCCESSFUL;
+
+ return Widget::MOVE_LOOP_CANCELED;
+}
+
+void DesktopWindowTreeHostX11::EndMoveLoop() {
+ x11_window_move_client_->EndMoveLoop();
+}
+
+void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
+ bool value) {
+ // Much like the previous NativeWidgetGtk, we don't have anything to do here.
+}
+
+bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
+ return use_native_frame_;
+}
+
+bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
+ return false;
+}
+
+void DesktopWindowTreeHostX11::FrameTypeChanged() {
+ Widget::FrameType new_type =
+ native_widget_delegate_->AsWidget()->frame_type();
+ if (new_type == Widget::FRAME_TYPE_DEFAULT) {
+ // The default is determined by Widget::InitParams::remove_standard_frame
+ // and does not change.
+ return;
+ }
+
+ SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
+ // Replace the frame and layout the contents. Even though we don't have a
+ // swapable glass frame like on Windows, we still replace the frame because
+ // the button assets don't update otherwise.
+ native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
+}
+
+void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
+ if (is_fullscreen_ == fullscreen)
+ return;
+ is_fullscreen_ = fullscreen;
+ SetWMSpecState(fullscreen,
+ atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
+ None);
+ // Try to guess the size we will have after the switch to/from fullscreen:
+ // - (may) avoid transient states
+ // - works around Flash content which expects to have the size updated
+ // synchronously.
+ // See https://crbug.com/361408
+ if (fullscreen) {
+ restored_bounds_ = bounds_;
+ const gfx::Display display =
+ gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
+ bounds_ = display.bounds();
+ } else {
+ bounds_ = restored_bounds_;
+ }
+ OnHostMoved(bounds_.origin());
+ OnHostResized(bounds_.size());
+
+ if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) {
+ Relayout();
+ ResetWindowRegion();
+ }
+ // Else: the widget will be relaid out either when the window bounds change or
+ // when |xwindow_|'s fullscreen state changes.
+}
+
+bool DesktopWindowTreeHostX11::IsFullscreen() const {
+ return is_fullscreen_;
+}
+
+void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
+ // X server opacity is in terms of 32 bit unsigned int space, and counts from
+ // the opposite direction.
+ // XChangeProperty() expects "cardinality" to be long.
+ unsigned long cardinality = opacity * 0x1010101;
+
+ if (cardinality == 0xffffffff) {
+ XDeleteProperty(xdisplay_, xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
+ } else {
+ XChangeProperty(xdisplay_, xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
+ XA_CARDINAL, 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&cardinality), 1);
+ }
+}
+
+void DesktopWindowTreeHostX11::SetWindowIcons(
+ const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
+ // TODO(erg): The way we handle icons across different versions of chrome
+ // could be substantially improved. The Windows version does its own thing
+ // and only sometimes comes down this code path. The icon stuff in
+ // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
+ // coded to be given two images instead of an arbitrary collection of images
+ // so that we can pass to the WM.
+ //
+ // All of this could be made much, much better.
+ std::vector<unsigned long> data;
+
+ if (window_icon.HasRepresentation(1.0f))
+ SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
+
+ if (app_icon.HasRepresentation(1.0f))
+ SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
+
+ if (data.empty())
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
+ else
+ ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
+}
+
+void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
+ switch (modal_type) {
+ case ui::MODAL_TYPE_NONE:
+ break;
+ default:
+ // TODO(erg): Figure out under what situations |modal_type| isn't
+ // none. The comment in desktop_native_widget_aura.cc suggests that this
+ // is rare.
+ NOTIMPLEMENTED();
+ }
+}
+
+void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
+ if (urgency_hint_set_ == flash_frame)
+ return;
+
+ XWMHints* hints = XGetWMHints(xdisplay_, xwindow_);
+ if (!hints) {
+ // The window hasn't had its hints set yet.
+ hints = XAllocWMHints();
+ }
+
+ if (flash_frame)
+ hints->flags |= XUrgencyHint;
+ else
+ hints->flags &= ~XUrgencyHint;
+
+ XSetWMHints(xdisplay_, xwindow_, hints);
+ XFree(hints);
+
+ urgency_hint_set_ = flash_frame;
+}
+
+void DesktopWindowTreeHostX11::OnRootViewLayout() const {
+ if (!window_mapped_)
+ return;
+
+ XSizeHints hints;
+ long supplied_return;
+ XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
+
+ gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
+ if (minimum.IsEmpty()) {
+ hints.flags &= ~PMinSize;
+ } else {
+ hints.flags |= PMinSize;
+ hints.min_width = minimum.width();
+ hints.min_height = minimum.height();
+ }
+
+ gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
+ if (maximum.IsEmpty()) {
+ hints.flags &= ~PMaxSize;
+ } else {
+ hints.flags |= PMaxSize;
+ hints.max_width = maximum.width();
+ hints.max_height = maximum.height();
+ }
+
+ XSetWMNormalHints(xdisplay_, xwindow_, &hints);
+}
+
+void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
+ native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
+}
+
+void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
+ if (xwindow_) {
+ x11_capture_.reset();
+ native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
+ }
+}
+
+bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
+ return false;
+}
+
+bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
+
+ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
+ return xwindow_;
+}
+
+void DesktopWindowTreeHostX11::Show() {
+ ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
+}
+
+void DesktopWindowTreeHostX11::Hide() {
+ if (window_mapped_) {
+ XWithdrawWindow(xdisplay_, xwindow_, 0);
+ window_mapped_ = false;
+ }
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
+}
+
+gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
+ return bounds_;
+}
+
+void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bool size_changed = bounds_.size() != bounds.size();
+ XWindowChanges changes = {0};
+ unsigned value_mask = 0;
+
+ if (size_changed) {
+ // X11 will send an XError at our process if have a 0 sized window.
+ DCHECK_GT(bounds.width(), 0);
+ DCHECK_GT(bounds.height(), 0);
+
+ changes.width = bounds.width();
+ changes.height = bounds.height();
+ value_mask |= CWHeight | CWWidth;
+ }
+
+ if (origin_changed) {
+ changes.x = bounds.x();
+ changes.y = bounds.y();
+ value_mask |= CWX | CWY;
+ }
+ if (value_mask)
+ XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
+
+ // Assume that the resize will go through as requested, which should be the
+ // case if we're running without a window manager. If there's a window
+ // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
+ // (possibly synthetic) ConfigureNotify about the actual size and correct
+ // |bounds_| later.
+ bounds_ = bounds;
+
+ if (origin_changed)
+ native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
+ if (size_changed) {
+ OnHostResized(bounds.size());
+ ResetWindowRegion();
+ }
+}
+
+gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
+ return bounds_.origin();
+}
+
+void DesktopWindowTreeHostX11::SetCapture() {
+ // This is vaguely based on the old NativeWidgetGtk implementation.
+ //
+ // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
+ // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
+ // a grab that wasn't the X11 pointer grab, but was instead a manual
+ // redirection of the event. (You need to drop into GDK if you want to
+ // perform a raw X11 grab).
+
+ if (g_current_capture)
+ g_current_capture->OnCaptureReleased();
+
+ g_current_capture = this;
+ x11_capture_.reset(new X11ScopedCapture(xwindow_));
+}
+
+void DesktopWindowTreeHostX11::ReleaseCapture() {
+ if (g_current_capture == this)
+ g_current_capture->OnCaptureReleased();
+}
+
+void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
+ XDefineCursor(xdisplay_, xwindow_, cursor.platform());
+}
+
+void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
+ XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
+ bounds_.x() + location.x(), bounds_.y() + location.y());
+}
+
+void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
+ // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
+ // the same tap-to-click disabling here that chromeos does.
+}
+
+void DesktopWindowTreeHostX11::PostNativeEvent(
+ const base::NativeEvent& native_event) {
+ DCHECK(xwindow_);
+ DCHECK(xdisplay_);
+ XEvent xevent = *native_event;
+ xevent.xany.display = xdisplay_;
+ xevent.xany.window = xwindow_;
+
+ switch (xevent.type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease: {
+ // The fields used below are in the same place for all of events
+ // above. Using xmotion from XEvent's unions to avoid repeating
+ // the code.
+ xevent.xmotion.root = x_root_window_;
+ xevent.xmotion.time = CurrentTime;
+
+ gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
+ ConvertPointToNativeScreen(&point);
+ xevent.xmotion.x_root = point.x();
+ xevent.xmotion.y_root = point.y();
+ }
+ default:
+ break;
+ }
+ XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
+}
+
+void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, ui::EventSource implementation:
+
+ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
+ return dispatcher();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, private:
+
+void DesktopWindowTreeHostX11::InitX11Window(
+ const Widget::InitParams& params) {
+ unsigned long attribute_mask = CWBackPixmap;
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.background_pixmap = None;
+
+ ::Atom window_type;
+ switch (params.type) {
+ case Widget::InitParams::TYPE_MENU:
+ swa.override_redirect = True;
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
+ break;
+ case Widget::InitParams::TYPE_TOOLTIP:
+ swa.override_redirect = True;
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
+ break;
+ case Widget::InitParams::TYPE_POPUP:
+ swa.override_redirect = True;
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
+ break;
+ case Widget::InitParams::TYPE_DRAG:
+ swa.override_redirect = True;
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
+ break;
+ default:
+ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
+ break;
+ }
+ if (swa.override_redirect)
+ attribute_mask |= CWOverrideRedirect;
+
+ // Detect whether we're running inside a compositing manager. If so, try to
+ // use the ARGB visual. Otherwise, just use our parent's visual.
+ Visual* visual = CopyFromParent;
+ int depth = CopyFromParent;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTransparentVisuals) &&
+ XGetSelectionOwner(xdisplay_,
+ atom_cache_.GetAtom("_NET_WM_CM_S0")) != None) {
+ Visual* rgba_visual = GetARGBVisual();
+ if (rgba_visual) {
+ visual = rgba_visual;
+ depth = 32;
+
+ attribute_mask |= CWColormap;
+ swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual,
+ AllocNone);
+
+ // x.org will BadMatch if we don't set a border when the depth isn't the
+ // same as the parent depth.
+ attribute_mask |= CWBorderPixel;
+ swa.border_pixel = 0;
+
+ use_argb_visual_ = true;
+ }
+ }
+
+ bounds_ = params.bounds;
+ xwindow_ = XCreateWindow(
+ xdisplay_, x_root_window_,
+ bounds_.x(), bounds_.y(),
+ bounds_.width(), bounds_.height(),
+ 0, // border width
+ depth,
+ InputOutput,
+ visual,
+ attribute_mask,
+ &swa);
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ open_windows().push_back(xwindow_);
+
+ // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
+
+ long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
+ KeyPressMask | KeyReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask | PropertyChangeMask |
+ PointerMotionMask;
+ XSelectInput(xdisplay_, xwindow_, event_mask);
+ XFlush(xdisplay_);
+
+ if (ui::IsXInput2Available())
+ ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
+
+ // TODO(erg): We currently only request window deletion events. We also
+ // should listen for activation events and anything else that GTK+ listens
+ // for, and do something useful.
+ ::Atom protocols[2];
+ protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
+ protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
+ XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
+
+ // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
+ // the desktop environment.
+ XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+
+ // Likewise, the X server needs to know this window's pid so it knows which
+ // program to kill if the window hangs.
+ // XChangeProperty() expects "pid" to be long.
+ COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
+ long pid = getpid();
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_PID"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&pid), 1);
+
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(&window_type), 1);
+
+ // List of window state properties (_NET_WM_STATE) to set, if any.
+ std::vector< ::Atom> state_atom_list;
+
+ // Remove popup windows from taskbar unless overridden.
+ if ((params.type == Widget::InitParams::TYPE_POPUP ||
+ params.type == Widget::InitParams::TYPE_BUBBLE) &&
+ !params.force_show_in_taskbar) {
+ state_atom_list.push_back(
+ atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
+ }
+
+ // If the window should stay on top of other windows, add the
+ // _NET_WM_STATE_ABOVE property.
+ is_always_on_top_ = params.keep_on_top;
+ if (is_always_on_top_)
+ state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
+
+ if (params.visible_on_all_workspaces) {
+ state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
+ ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
+ }
+
+ // Setting _NET_WM_STATE by sending a message to the root_window (with
+ // SetWMSpecState) has no effect here since the window has not yet been
+ // mapped. So we manually change the state.
+ if (!state_atom_list.empty()) {
+ ui::SetAtomArrayProperty(xwindow_,
+ "_NET_WM_STATE",
+ "ATOM",
+ state_atom_list);
+ }
+
+ if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
+ ui::SetWindowClassHint(
+ xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
+ }
+ if (!params.wm_role_name.empty() ||
+ params.type == Widget::InitParams::TYPE_POPUP) {
+ const char kX11WindowRolePopup[] = "popup";
+ ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
+ std::string(kX11WindowRolePopup) : params.wm_role_name);
+ }
+
+ if (params.remove_standard_frame) {
+ // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
+ // fullscreen on the window when it matches the desktop size.
+ ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
+ ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
+ }
+
+ // If we have a parent, record the parent/child relationship. We use this
+ // data during destruction to make sure that when we try to close a parent
+ // window, we also destroy all child windows.
+ if (params.parent && params.parent->GetHost()) {
+ XID parent_xid =
+ params.parent->GetHost()->GetAcceleratedWidget();
+ window_parent_ = GetHostForXID(parent_xid);
+ DCHECK(window_parent_);
+ window_parent_->window_children_.insert(this);
+ }
+
+ // If we have a delegate which is providing a default window icon, use that
+ // icon.
+ gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
+ ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
+ if (window_icon) {
+ SetWindowIcons(gfx::ImageSkia(), *window_icon);
+ }
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+void DesktopWindowTreeHostX11::OnWMStateUpdated() {
+ std::vector< ::Atom> atom_list;
+ if (!ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list))
+ return;
+
+ bool was_minimized = IsMinimized();
+
+ window_properties_.clear();
+ std::copy(atom_list.begin(), atom_list.end(),
+ inserter(window_properties_, window_properties_.begin()));
+
+ // Propagate the window minimization information to the content window, so
+ // the render side can update its visibility properly. OnWMStateUpdated() is
+ // called by PropertyNofify event from DispatchEvent() when the browser is
+ // minimized or shown from minimized state. On Windows, this is realized by
+ // calling OnHostResized() with an empty size. In particular,
+ // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
+ // window is minimized. On Linux, returning empty size in GetBounds() or
+ // SetBounds() does not work.
+ bool is_minimized = IsMinimized();
+ if (is_minimized != was_minimized) {
+ if (is_minimized)
+ content_window_->Hide();
+ else
+ content_window_->Show();
+ }
+
+ if (restored_bounds_.IsEmpty()) {
+ DCHECK(!IsFullscreen());
+ if (IsMaximized()) {
+ // The request that we become maximized originated from a different
+ // process. |bounds_| already contains our maximized bounds. Do a best
+ // effort attempt to get restored bounds by setting it to our previously
+ // set bounds (and if we get this wrong, we aren't any worse off since
+ // we'd otherwise be returning our maximized bounds).
+ restored_bounds_ = previous_bounds_;
+ }
+ } else if (!IsMaximized() && !IsFullscreen()) {
+ // If we have restored bounds, but WM_STATE no longer claims to be
+ // maximized or fullscreen, we should clear our restored bounds.
+ restored_bounds_ = gfx::Rect();
+ }
+
+ // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
+ // a result of pressing a window manager accelerator key). Chrome does not
+ // handle window manager initiated fullscreen. In particular, Chrome needs to
+ // do preprocessing before the x window's fullscreen state is toggled.
+
+ is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
+
+ // Now that we have different window properties, we may need to relayout the
+ // window. (The windows code doesn't need this because their window change is
+ // synchronous.)
+ Relayout();
+ ResetWindowRegion();
+}
+
+void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
+ std::vector<int> insets;
+ if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
+ insets.size() == 4) {
+ // |insets| are returned in the order: [left, right, top, bottom].
+ native_window_frame_borders_ = gfx::Insets(
+ insets[2],
+ insets[0],
+ insets[3],
+ insets[1]);
+ } else {
+ native_window_frame_borders_ = gfx::Insets();
+ }
+}
+
+void DesktopWindowTreeHostX11::UpdateWMUserTime(
+ const ui::PlatformEvent& event) {
+ if (!IsActive())
+ return;
+
+ ui::EventType type = ui::EventTypeFromNative(event);
+ if (type == ui::ET_MOUSE_PRESSED ||
+ type == ui::ET_KEY_PRESSED ||
+ type == ui::ET_TOUCH_PRESSED) {
+ unsigned long wm_user_time_ms = static_cast<unsigned long>(
+ ui::EventTimeFromNative(event).InMilliseconds());
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_USER_TIME"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
+ 1);
+ X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
+ }
+}
+
+void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
+ ::Atom state1,
+ ::Atom state2) {
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = xwindow_;
+ xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] =
+ enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
+ xclient.xclient.data.l[1] = state1;
+ xclient.xclient.data.l[2] = state2;
+ xclient.xclient.data.l[3] = 1;
+ xclient.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xclient);
+}
+
+bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
+ return window_properties_.find(atom_cache_.GetAtom(property)) !=
+ window_properties_.end();
+}
+
+void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
+ use_native_frame_ = use_native_frame;
+ ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
+ ResetWindowRegion();
+}
+
+void DesktopWindowTreeHostX11::OnCaptureReleased() {
+ x11_capture_.reset();
+ g_current_capture = NULL;
+ OnHostLostWindowCapture();
+ native_widget_delegate_->OnMouseCaptureLost();
+}
+
+void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
+ // In Windows, the native events sent to chrome are separated into client
+ // and non-client versions of events, which we record on our LocatedEvent
+ // structures. On X11, we emulate the concept of non-client. Before we pass
+ // this event to the cross platform event handling framework, we need to
+ // make sure it is appropriately marked as non-client if it's in the non
+ // client area, or otherwise, we can get into a state where the a window is
+ // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
+ // despite the mouse button being released.
+ //
+ // We can't do this later in the dispatch process because we share that
+ // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
+ // events, since ash doesn't expect this bit to be set, because it's never
+ // been set before. (This works on ash on Windows because none of the mouse
+ // 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()) {
+ int flags = event->flags();
+ int hit_test_code =
+ 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);
+ }
+
+ // While we unset the urgency hint when we gain focus, we also must remove it
+ // on mouse clicks because we can call FlashFrame() on an active window.
+ if (event->IsAnyButton() || event->IsMouseWheelEvent())
+ FlashFrame(false);
+
+ if (!g_current_capture || g_current_capture == this) {
+ SendEventToProcessor(event);
+ } else {
+ // Another DesktopWindowTreeHostX11 has installed itself as
+ // capture. Translate the event's location and dispatch to the other.
+ event->ConvertLocationToTarget(window(), g_current_capture->window());
+ g_current_capture->SendEventToProcessor(event);
+ }
+}
+
+void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
+ if (g_current_capture && g_current_capture != this &&
+ event->type() == ui::ET_TOUCH_PRESSED) {
+ event->ConvertLocationToTarget(window(), g_current_capture->window());
+ g_current_capture->SendEventToProcessor(event);
+ } else {
+ SendEventToProcessor(event);
+ }
+}
+
+void DesktopWindowTreeHostX11::ResetWindowRegion() {
+ // If a custom window shape was supplied then apply it.
+ if (custom_window_shape_) {
+ XShapeCombineRegion(
+ xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false);
+ return;
+ }
+
+ if (window_shape_)
+ XDestroyRegion(window_shape_);
+ window_shape_ = NULL;
+
+ if (!IsMaximized() && !IsFullscreen()) {
+ gfx::Path window_mask;
+ views::Widget* widget = native_widget_delegate_->AsWidget();
+ if (widget->non_client_view()) {
+ // Some frame views define a custom (non-rectangular) window mask. If
+ // so, use it to define the window shape. If not, fall through.
+ widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
+ if (window_mask.countPoints() > 0) {
+ window_shape_ = gfx::CreateRegionFromSkPath(window_mask);
+ XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
+ 0, 0, window_shape_, false);
+ return;
+ }
+ }
+ }
+
+ // If we didn't set the shape for any reason, reset the shaping information.
+ // How this is done depends on the border style, due to quirks and bugs in
+ // various window managers.
+ if (ShouldUseNativeFrame()) {
+ // If the window has system borders, the mask must be set to null (not a
+ // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
+ // not put borders on a window with a custom shape.
+ XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
+ } else {
+ // Conversely, if the window does not have system borders, the mask must be
+ // manually set to a rectangle that covers the whole window (not null). This
+ // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
+ // shape causes the hint to disable system borders to be ignored (resulting
+ // in a double border).
+ XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
+ static_cast<unsigned short>(bounds_.height())};
+ XShapeCombineRectangles(
+ xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
+ }
+}
+
+void DesktopWindowTreeHostX11::SerializeImageRepresentation(
+ const gfx::ImageSkiaRep& rep,
+ std::vector<unsigned long>* data) {
+ int width = rep.GetWidth();
+ data->push_back(width);
+
+ int height = rep.GetHeight();
+ data->push_back(height);
+
+ const SkBitmap& bitmap = rep.sk_bitmap();
+ SkAutoLockPixels locker(bitmap);
+
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ data->push_back(bitmap.getColor(x, y));
+}
+
+Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
+ XVisualInfo visual_template;
+ visual_template.screen = 0;
+ Visual* to_return = NULL;
+
+ int visuals_len;
+ XVisualInfo* visual_list = XGetVisualInfo(xdisplay_,
+ VisualScreenMask,
+ &visual_template, &visuals_len);
+ for (int i = 0; i < visuals_len; ++i) {
+ // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
+ // gdkvisual-x11.cc, they look for this specific visual and use it for all
+ // their alpha channel using needs.
+ //
+ // TODO(erg): While the following does find a valid visual, some GL drivers
+ // don't believe that this has an alpha channel. According to marcheu@,
+ // this should work on open source driver though. (It doesn't work with
+ // NVidia's binaries currently.) http://crbug.com/369209
+ if (visual_list[i].depth == 32 &&
+ visual_list[i].visual->red_mask == 0xff0000 &&
+ visual_list[i].visual->green_mask == 0x00ff00 &&
+ visual_list[i].visual->blue_mask == 0x0000ff) {
+ to_return = visual_list[i].visual;
+ break;
+ }
+ }
+
+ if (visual_list)
+ XFree(visual_list);
+
+ return to_return;
+}
+
+std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
+ if (!open_windows_)
+ open_windows_ = new std::list<XID>();
+ return *open_windows_;
+}
+
+void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
+ if (show_state != ui::SHOW_STATE_DEFAULT &&
+ show_state != ui::SHOW_STATE_NORMAL &&
+ show_state != ui::SHOW_STATE_INACTIVE) {
+ // It will behave like SHOW_STATE_NORMAL.
+ NOTIMPLEMENTED();
+ }
+
+ // Before we map the window, set size hints. Otherwise, some window managers
+ // will ignore toplevel XMoveWindow commands.
+ XSizeHints size_hints;
+ size_hints.flags = PPosition;
+ size_hints.x = bounds_.x();
+ size_hints.y = bounds_.y();
+ XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
+
+ // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
+ // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
+ // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
+ unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
+ 0 : X11DesktopHandler::get()->wm_user_time_ms();
+ if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
+ XChangeProperty(xdisplay_,
+ xwindow_,
+ atom_cache_.GetAtom("_NET_WM_USER_TIME"),
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
+ 1);
+ }
+
+ XMapWindow(xdisplay_, xwindow_);
+
+ // We now block until our window is mapped. Some X11 APIs will crash and
+ // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
+ // asynchronous.
+ if (ui::X11EventSource::GetInstance())
+ ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
+ window_mapped_ = true;
+}
+
+void DesktopWindowTreeHostX11::SetWindowTransparency() {
+ compositor()->SetHostHasTransparentBackground(use_argb_visual_);
+ window()->SetTransparent(use_argb_visual_);
+ content_window_->SetTransparent(use_argb_visual_);
+}
+
+void DesktopWindowTreeHostX11::Relayout() {
+ Widget* widget = native_widget_delegate_->AsWidget();
+ NonClientView* non_client_view = widget->non_client_view();
+ // non_client_view may be NULL, especially during creation.
+ if (non_client_view) {
+ non_client_view->client_view()->InvalidateLayout();
+ non_client_view->InvalidateLayout();
+ }
+ widget->GetRootView()->Layout();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
+
+bool DesktopWindowTreeHostX11::CanDispatchEvent(
+ const ui::PlatformEvent& event) {
+ return event->xany.window == xwindow_ ||
+ (event->type == GenericEvent &&
+ static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
+}
+
+uint32_t DesktopWindowTreeHostX11::DispatchEvent(
+ const ui::PlatformEvent& event) {
+ XEvent* xev = event;
+
+ TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
+ "event->type", event->type);
+
+ UpdateWMUserTime(event);
+
+ // May want to factor CheckXEventForConsistency(xev); into a common location
+ // since it is called here.
+ switch (xev->type) {
+ case EnterNotify:
+ case LeaveNotify: {
+ // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
+ // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
+ // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
+ // necessary. crbug.com/385716
+ if (xev->xcrossing.detail == NotifyInferior)
+ break;
+
+ ui::MouseEvent mouse_event(xev);
+ DispatchMouseEvent(&mouse_event);
+ break;
+ }
+ case Expose: {
+ gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
+ xev->xexpose.width, xev->xexpose.height);
+ compositor()->ScheduleRedrawRect(damage_rect);
+ break;
+ }
+ case KeyPress: {
+ ui::KeyEvent keydown_event(xev, false);
+ SendEventToProcessor(&keydown_event);
+ break;
+ }
+ case KeyRelease: {
+ ui::KeyEvent keyup_event(xev, false);
+ SendEventToProcessor(&keyup_event);
+ break;
+ }
+ case ButtonPress:
+ case ButtonRelease: {
+ ui::EventType event_type = ui::EventTypeFromNative(xev);
+ switch (event_type) {
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED: {
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_UNKNOWN:
+ // No event is created for X11-release events for mouse-wheel buttons.
+ break;
+ default:
+ NOTREACHED() << event_type;
+ }
+ break;
+ }
+ case FocusOut:
+ if (xev->xfocus.mode != NotifyGrab) {
+ ReleaseCapture();
+ OnHostLostWindowCapture();
+ X11DesktopHandler::get()->ProcessXEvent(xev);
+ } else {
+ dispatcher()->OnHostLostMouseGrab();
+ }
+ break;
+ case FocusIn:
+ X11DesktopHandler::get()->ProcessXEvent(xev);
+ break;
+ case ConfigureNotify: {
+ DCHECK_EQ(xwindow_, xev->xconfigure.window);
+ DCHECK_EQ(xwindow_, xev->xconfigure.event);
+ // It's possible that the X window may be resized by some other means than
+ // from within aura (e.g. the X window manager can change the size). Make
+ // sure the root window size is maintained properly.
+ int translated_x = xev->xconfigure.x;
+ int translated_y = xev->xconfigure.y;
+ if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
+ Window unused;
+ XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
+ 0, 0, &translated_x, &translated_y, &unused);
+ }
+ gfx::Rect bounds(translated_x, translated_y,
+ xev->xconfigure.width, xev->xconfigure.height);
+ bool size_changed = bounds_.size() != bounds.size();
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ previous_bounds_ = bounds_;
+ bounds_ = bounds;
+
+ if (origin_changed)
+ OnHostMoved(bounds_.origin());
+
+ if (size_changed) {
+ delayed_resize_task_.Reset(base::Bind(
+ &DesktopWindowTreeHostX11::DelayedResize,
+ close_widget_factory_.GetWeakPtr(),
+ bounds.size()));
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, delayed_resize_task_.callback());
+ }
+ break;
+ }
+ case GenericEvent: {
+ ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
+ if (!factory->ShouldProcessXI2Event(xev))
+ break;
+
+ ui::EventType type = ui::EventTypeFromNative(xev);
+ XEvent last_event;
+ int num_coalesced = 0;
+
+ switch (type) {
+ case ui::ET_TOUCH_MOVED:
+ num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
+ if (num_coalesced > 0)
+ xev = &last_event;
+ // fallthrough
+ case ui::ET_TOUCH_PRESSED:
+ case ui::ET_TOUCH_RELEASED: {
+ ui::TouchEvent touchev(xev);
+ DispatchTouchEvent(&touchev);
+ break;
+ }
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_ENTERED:
+ case ui::ET_MOUSE_EXITED: {
+ if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
+ // If this is a motion event, we want to coalesce all pending motion
+ // events that are at the top of the queue.
+ num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
+ if (num_coalesced > 0)
+ xev = &last_event;
+ }
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_MOUSEWHEEL: {
+ ui::MouseWheelEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case ui::ET_SCROLL_FLING_START:
+ case ui::ET_SCROLL_FLING_CANCEL:
+ case ui::ET_SCROLL: {
+ ui::ScrollEvent scrollev(xev);
+ SendEventToProcessor(&scrollev);
+ break;
+ }
+ case ui::ET_UNKNOWN:
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // If we coalesced an event we need to free its cookie.
+ if (num_coalesced > 0)
+ XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
+ break;
+ }
+ case MapNotify: {
+ FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
+ observer_list_,
+ OnWindowMapped(xwindow_));
+ break;
+ }
+ case UnmapNotify: {
+ FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
+ observer_list_,
+ OnWindowUnmapped(xwindow_));
+ break;
+ }
+ case ClientMessage: {
+ Atom message_type = xev->xclient.message_type;
+ if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
+ Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
+ if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
+ // We have received a close message from the window manager.
+ OnHostCloseRequested();
+ } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
+ XEvent reply_event = *xev;
+ reply_event.xclient.window = x_root_window_;
+
+ XSendEvent(xdisplay_,
+ reply_event.xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &reply_event);
+ }
+ } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ drag_drop_client_->OnXdndEnter(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ drag_drop_client_->OnXdndLeave(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ drag_drop_client_->OnXdndPosition(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ drag_drop_client_->OnXdndStatus(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ drag_drop_client_->OnXdndFinished(xev->xclient);
+ } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ drag_drop_client_->OnXdndDrop(xev->xclient);
+ }
+ break;
+ }
+ case MappingNotify: {
+ switch (xev->xmapping.request) {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping(&xev->xmapping);
+ break;
+ case MappingPointer:
+ ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
+ break;
+ default:
+ NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
+ break;
+ }
+ break;
+ }
+ case MotionNotify: {
+ // Discard all but the most recent motion event that targets the same
+ // window with unchanged state.
+ XEvent last_event;
+ while (XPending(xev->xany.display)) {
+ XEvent next_event;
+ XPeekEvent(xev->xany.display, &next_event);
+ if (next_event.type == MotionNotify &&
+ next_event.xmotion.window == xev->xmotion.window &&
+ next_event.xmotion.subwindow == xev->xmotion.subwindow &&
+ next_event.xmotion.state == xev->xmotion.state) {
+ XNextEvent(xev->xany.display, &last_event);
+ xev = &last_event;
+ } else {
+ break;
+ }
+ }
+
+ ui::MouseEvent mouseev(xev);
+ DispatchMouseEvent(&mouseev);
+ break;
+ }
+ case PropertyNotify: {
+ ::Atom changed_atom = xev->xproperty.atom;
+ if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
+ OnWMStateUpdated();
+ else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
+ OnFrameExtentsUpdated();
+ break;
+ }
+ case SelectionNotify: {
+ drag_drop_client_->OnSelectionNotify(xev->xselection);
+ break;
+ }
+ }
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+}
+
+void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size) {
+ OnHostResized(size);
+ ResetWindowRegion();
+ delayed_resize_task_.Cancel();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopWindowTreeHost, public:
+
+// static
+DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura) {
+ return new DesktopWindowTreeHostX11(native_widget_delegate,
+ desktop_native_widget_aura);
+}
+
+// static
+ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
+ const views::LinuxUI* linux_ui = views::LinuxUI::instance();
+ if (linux_ui) {
+ ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
+ if (native_theme)
+ return native_theme;
+ }
+
+ return ui::NativeTheme::instance();
+}
+
+} // namespace views
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
new file mode 100644
index 00000000000..a67a1516820
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -0,0 +1,345 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_X11_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_X11_H_
+
+#include <X11/extensions/shape.h>
+#include <X11/Xlib.h>
+
+#include "base/basictypes.h"
+#include "base/cancelable_callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/cursor/cursor_loader_x11.h"
+#include "ui/events/event_source.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+
+namespace gfx {
+class ImageSkia;
+class ImageSkiaRep;
+}
+
+namespace ui {
+class EventHandler;
+}
+
+namespace views {
+class DesktopDragDropClientAuraX11;
+class DesktopDispatcherClient;
+class DesktopWindowTreeHostObserverX11;
+class X11DesktopWindowMoveClient;
+class X11ScopedCapture;
+class X11WindowEventFilter;
+
+class VIEWS_EXPORT DesktopWindowTreeHostX11
+ : public DesktopWindowTreeHost,
+ public aura::WindowTreeHost,
+ public ui::EventSource,
+ public ui::PlatformEventDispatcher {
+ public:
+ DesktopWindowTreeHostX11(
+ internal::NativeWidgetDelegate* native_widget_delegate,
+ DesktopNativeWidgetAura* desktop_native_widget_aura);
+ virtual ~DesktopWindowTreeHostX11();
+
+ // A way of converting an X11 |xid| host window into a |content_window_|.
+ static aura::Window* GetContentWindowForXID(XID xid);
+
+ // A way of converting an X11 |xid| host window into this object.
+ static DesktopWindowTreeHostX11* GetHostForXID(XID xid);
+
+ // Get all open top-level windows. This includes windows that may not be
+ // visible. This list is sorted in their stacking order, i.e. the first window
+ // is the topmost window.
+ static std::vector<aura::Window*> GetAllOpenWindows();
+
+ // Returns the current bounds in terms of the X11 Root Window.
+ gfx::Rect GetX11RootWindowBounds() const;
+
+ // Returns the current bounds in terms of the X11 Root Window including the
+ // borders provided by the window manager (if any).
+ gfx::Rect GetX11RootWindowOuterBounds() const;
+
+ // Returns the window shape if the window is not rectangular. Returns NULL
+ // otherwise.
+ ::Region GetWindowShape() const;
+
+ // Called by X11DesktopHandler to notify us that the native windowing system
+ // has changed our activation.
+ void HandleNativeWidgetActivationChanged(bool active);
+
+ void AddObserver(views::DesktopWindowTreeHostObserverX11* observer);
+ void RemoveObserver(views::DesktopWindowTreeHostObserverX11* observer);
+
+ // Swaps the current handler for events in the non client view with |handler|.
+ void SwapNonClientEventHandler(scoped_ptr<ui::EventHandler> handler);
+
+ // Deallocates the internal list of open windows.
+ static void CleanUpWindowList();
+
+ protected:
+ // Overridden from DesktopWindowTreeHost:
+ virtual void Init(aura::Window* content_window,
+ const Widget::InitParams& params) OVERRIDE;
+ virtual void OnNativeWidgetCreated(const Widget::InitParams& params) OVERRIDE;
+ virtual scoped_ptr<corewm::Tooltip> CreateTooltip() OVERRIDE;
+ virtual scoped_ptr<aura::client::DragDropClient>
+ CreateDragDropClient(DesktopNativeCursorManager* cursor_manager) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual aura::WindowTreeHost* AsWindowTreeHost() OVERRIDE;
+ virtual void ShowWindowWithState(ui::WindowShowState show_state) OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion native_region) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual bool IsAlwaysOnTop() const OVERRIDE;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
+ virtual bool SetWindowTitle(const base::string16& title) OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual bool ShouldWindowContentsBeTransparent() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void OnRootViewLayout() const OVERRIDE;
+ virtual void OnNativeWidgetFocus() OVERRIDE;
+ virtual void OnNativeWidgetBlur() OVERRIDE;
+ virtual bool IsAnimatingClosed() const OVERRIDE;
+ virtual bool IsTranslucentWindowOpacitySupported() const OVERRIDE;
+
+ // Overridden from aura::WindowTreeHost:
+ virtual ui::EventSource* GetEventSource() OVERRIDE;
+ virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual gfx::Rect GetBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE;
+ virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE;
+ virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE;
+
+ // Overridden frm ui::EventSource
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
+
+ private:
+ // Initializes our X11 surface to draw on. This method performs all
+ // initialization related to talking to the X11 server.
+ void InitX11Window(const Widget::InitParams& params);
+
+ // 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);
+
+ // Called when |xwindow_|'s _NET_WM_STATE property is updated.
+ void OnWMStateUpdated();
+
+ // Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
+ void OnFrameExtentsUpdated();
+
+ // Updates |xwindow_|'s _NET_WM_USER_TIME if |xwindow_| is active.
+ void UpdateWMUserTime(const ui::PlatformEvent& event);
+
+ // Sends a message to the x11 window manager, enabling or disabling the
+ // states |state1| and |state2|.
+ void SetWMSpecState(bool enabled, ::Atom state1, ::Atom state2);
+
+ // Checks if the window manager has set a specific state.
+ bool HasWMSpecProperty(const char* property) const;
+
+ // Sets whether the window's borders are provided by the window manager.
+ void SetUseNativeFrame(bool use_native_frame);
+
+ // Called when another DRWHL takes capture, or when capture is released
+ // entirely.
+ void OnCaptureReleased();
+
+ // Dispatches a mouse event, taking mouse capture into account. If a
+ // different host has capture, we translate the event to its coordinate space
+ // and dispatch it to that host instead.
+ void DispatchMouseEvent(ui::MouseEvent* event);
+
+ // Dispatches a touch event, taking capture into account. If a different host
+ // has capture, then touch-press events are translated to its coordinate space
+ // and dispatched to that host instead.
+ void DispatchTouchEvent(ui::TouchEvent* event);
+
+ // Resets the window region for the current widget bounds if necessary.
+ void ResetWindowRegion();
+
+ // Serializes an image to the format used by _NET_WM_ICON.
+ void SerializeImageRepresentation(const gfx::ImageSkiaRep& rep,
+ std::vector<unsigned long>* data);
+
+ // Returns an 8888 ARGB visual. Can return NULL if there is no matching
+ // visual on this display.
+ Visual* GetARGBVisual();
+
+ // See comment for variable open_windows_.
+ static std::list<XID>& open_windows();
+
+ // Map the window (shows it) taking into account the given |show_state|.
+ void MapWindow(ui::WindowShowState show_state);
+
+ void SetWindowTransparency();
+
+ // Relayout the widget's client and non-client views.
+ void Relayout();
+
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+
+ void DelayedResize(const gfx::Size& size);
+
+ base::WeakPtrFactory<DesktopWindowTreeHostX11> close_widget_factory_;
+
+ // X11 things
+ // The display and the native X window hosting the root window.
+ XDisplay* xdisplay_;
+ ::Window xwindow_;
+
+ // The native root window.
+ ::Window x_root_window_;
+
+ ui::X11AtomCache atom_cache_;
+
+ // Is the window mapped to the screen?
+ bool window_mapped_;
+
+ // The bounds of |xwindow_|.
+ gfx::Rect bounds_;
+
+ // Whenever the bounds are set, we keep the previous set of bounds around so
+ // we can have a better chance of getting the real |restored_bounds_|. Window
+ // managers tend to send a Configure message with the maximized bounds, and
+ // then set the window maximized property. (We don't rely on this for when we
+ // request that the window be maximized, only when we detect that some other
+ // process has requested that we become the maximized window.)
+ gfx::Rect previous_bounds_;
+
+ // The bounds of our window before we were maximized.
+ gfx::Rect restored_bounds_;
+
+ // The window manager state bits.
+ std::set< ::Atom> window_properties_;
+
+ // Whether |xwindow_| was requested to be fullscreen via SetFullscreen().
+ bool is_fullscreen_;
+
+ // True if the window should stay on top of most other windows.
+ bool is_always_on_top_;
+
+ // True if the window has title-bar / borders provided by the window manager.
+ bool use_native_frame_;
+
+ // Whether we used an ARGB visual for our window.
+ bool use_argb_visual_;
+
+ scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
+
+ DesktopDragDropClientAuraX11* drag_drop_client_;
+
+ // Current Aura cursor.
+ gfx::NativeCursor current_cursor_;
+
+ scoped_ptr<ui::EventHandler> x11_non_client_event_filter_;
+ scoped_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
+
+ // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura
+ // instead of providing this route back to Widget.
+ internal::NativeWidgetDelegate* native_widget_delegate_;
+
+ 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_;
+ std::set<DesktopWindowTreeHostX11*> window_children_;
+
+ ObserverList<DesktopWindowTreeHostObserverX11> observer_list_;
+
+ // The window shape if the window is non-rectangular.
+ ::Region window_shape_;
+
+ // Whether |window_shape_| was set via SetShape().
+ bool custom_window_shape_;
+
+ // The size of the window manager provided borders (if any).
+ gfx::Insets native_window_frame_borders_;
+
+ // The current root window host that has capture. While X11 has something
+ // like Windows SetCapture()/ReleaseCapture(), it is entirely implicit and
+ // there are no notifications when this changes. We need to track this so we
+ // can notify widgets when they have lost capture, which controls a bunch of
+ // things in views like hiding menus.
+ static DesktopWindowTreeHostX11* g_current_capture;
+
+ // A list of all (top-level) windows that have been created but not yet
+ // destroyed.
+ static std::list<XID>* open_windows_;
+
+ scoped_ptr<X11ScopedCapture> x11_capture_;
+
+ base::string16 window_title_;
+
+ // Whether we currently are flashing our frame. This feature is implemented
+ // by setting the urgency hint with the window manager, which can draw
+ // attention to the window or completely ignore the hint. We stop flashing
+ // the frame when |xwindow_| gains focus or handles a mouse button event.
+ bool urgency_hint_set_;
+
+ base::CancelableCallback<void()> delayed_resize_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_X11_H_
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
new file mode 100644
index 00000000000..8a66c6e0327
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -0,0 +1,448 @@
+// 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 <vector>
+
+#include <X11/extensions/shape.h>
+#include <X11/Xlib.h>
+
+// Get rid of X11 macros which conflict with gtest.
+#undef Bool
+#undef None
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/test/x11_property_change_waiter.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/non_client_view.h"
+
+namespace views {
+
+namespace {
+
+// Blocks till the window state hint, |hint|, is set or unset.
+class WMStateWaiter : public X11PropertyChangeWaiter {
+ public:
+ WMStateWaiter(XID window,
+ const char* hint,
+ bool wait_till_set)
+ : X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
+ hint_(hint),
+ wait_till_set_(wait_till_set) {
+
+ const char* kAtomsToCache[] = {
+ hint,
+ NULL
+ };
+ atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
+ }
+
+ virtual ~WMStateWaiter() {
+ }
+
+ private:
+ // X11PropertyChangeWaiter:
+ virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
+ std::vector<Atom> hints;
+ if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &hints)) {
+ std::vector<Atom>::iterator it = std::find(
+ hints.begin(),
+ hints.end(),
+ atom_cache_->GetAtom(hint_));
+ bool hint_set = (it != hints.end());
+ return hint_set != wait_till_set_;
+ }
+ return true;
+ }
+
+ scoped_ptr<ui::X11AtomCache> atom_cache_;
+
+ // The name of the hint to wait to get set or unset.
+ const char* hint_;
+
+ // Whether we are waiting for |hint| to be set or unset.
+ bool wait_till_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(WMStateWaiter);
+};
+
+// A NonClientFrameView with a window mask with the bottom right corner cut out.
+class ShapedNonClientFrameView : public NonClientFrameView {
+ public:
+ explicit ShapedNonClientFrameView() {
+ }
+
+ virtual ~ShapedNonClientFrameView() {
+ }
+
+ // NonClientFrameView:
+ virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
+ return bounds();
+ }
+ virtual gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const OVERRIDE {
+ return client_bounds;
+ }
+ virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
+ return HTNOWHERE;
+ }
+ virtual void GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) OVERRIDE {
+ int right = size.width();
+ int bottom = size.height();
+
+ window_mask->moveTo(0, 0);
+ window_mask->lineTo(0, bottom);
+ window_mask->lineTo(right, bottom);
+ window_mask->lineTo(right, 10);
+ window_mask->lineTo(right - 10, 10);
+ window_mask->lineTo(right - 10, 0);
+ window_mask->close();
+ }
+ virtual void ResetWindowControls() OVERRIDE {
+ }
+ virtual void UpdateWindowIcon() OVERRIDE {
+ }
+ virtual void UpdateWindowTitle() OVERRIDE {
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShapedNonClientFrameView);
+};
+
+class ShapedWidgetDelegate : public WidgetDelegateView {
+ public:
+ ShapedWidgetDelegate() {
+ }
+
+ virtual ~ShapedWidgetDelegate() {
+ }
+
+ // WidgetDelegateView:
+ virtual NonClientFrameView* CreateNonClientFrameView(
+ Widget* widget) OVERRIDE {
+ return new ShapedNonClientFrameView;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShapedWidgetDelegate);
+};
+
+// Creates a widget of size 100x100.
+scoped_ptr<Widget> CreateWidget(WidgetDelegate* delegate) {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.delegate = delegate;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.remove_standard_frame = true;
+ params.native_widget = new DesktopNativeWidgetAura(widget.get());
+ params.bounds = gfx::Rect(100, 100, 100, 100);
+ widget->Init(params);
+ return widget.Pass();
+}
+
+// Returns the list of rectangles which describe |xid|'s bounding region via the
+// X shape extension.
+std::vector<gfx::Rect> GetShapeRects(XID xid) {
+ int dummy;
+ int shape_rects_size;
+ XRectangle* shape_rects = XShapeGetRectangles(gfx::GetXDisplay(),
+ xid,
+ ShapeBounding,
+ &shape_rects_size,
+ &dummy);
+
+ std::vector<gfx::Rect> shape_vector;
+ for (int i = 0; i < shape_rects_size; ++i) {
+ shape_vector.push_back(gfx::Rect(
+ shape_rects[i].x,
+ shape_rects[i].y,
+ shape_rects[i].width,
+ shape_rects[i].height));
+ }
+ XFree(shape_rects);
+ return shape_vector;
+}
+
+// Returns true if one of |rects| contains point (x,y).
+bool ShapeRectContainsPoint(const std::vector<gfx::Rect>& shape_rects,
+ int x,
+ int y) {
+ gfx::Point point(x, y);
+ for (size_t i = 0; i < shape_rects.size(); ++i) {
+ if (shape_rects[i].Contains(point))
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+class DesktopWindowTreeHostX11Test : public ViewsTestBase {
+ public:
+ DesktopWindowTreeHostX11Test() {
+ }
+ virtual ~DesktopWindowTreeHostX11Test() {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ViewsTestBase::SetUp();
+
+ // Make X11 synchronous for our display connection. This does not force the
+ // window manager to behave synchronously.
+ XSynchronize(gfx::GetXDisplay(), True);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ XSynchronize(gfx::GetXDisplay(), False);
+ ViewsTestBase::TearDown();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
+};
+
+// Tests that the shape is properly set on the x window.
+TEST_F(DesktopWindowTreeHostX11Test, Shape) {
+ if (!ui::IsShapeExtensionAvailable())
+ return;
+
+ // 1) Test setting the window shape via the NonClientFrameView. This technique
+ // is used to get rounded corners on Chrome windows when not using the native
+ // window frame.
+ scoped_ptr<Widget> widget1 = CreateWidget(new ShapedWidgetDelegate());
+ widget1->Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ std::vector<gfx::Rect> shape_rects = GetShapeRects(xid1);
+ ASSERT_FALSE(shape_rects.empty());
+
+ // The widget was supposed to be 100x100, but the WM might have ignored this
+ // suggestion.
+ int widget_width = widget1->GetWindowBoundsInScreen().width();
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 15, 5));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, widget_width - 5, 15));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, widget_width + 5, 15));
+
+ // Changing widget's size should update the shape.
+ widget1->SetBounds(gfx::Rect(100, 100, 200, 200));
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ if (widget1->GetWindowBoundsInScreen().width() == 200) {
+ shape_rects = GetShapeRects(xid1);
+ ASSERT_FALSE(shape_rects.empty());
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 85, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 185, 5));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 195, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 195, 15));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 205, 15));
+ }
+
+ if (ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"))) {
+ // The shape should be changed to a rectangle which fills the entire screen
+ // when |widget1| is maximized.
+ {
+ WMStateWaiter waiter(xid1, "_NET_WM_STATE_MAXIMIZED_VERT", true);
+ widget1->Maximize();
+ waiter.Wait();
+ }
+
+ // xvfb does not support Xrandr so we cannot check the maximized window's
+ // bounds.
+ gfx::Rect maximized_bounds;
+ ui::GetWindowRect(xid1, &maximized_bounds);
+
+ shape_rects = GetShapeRects(xid1);
+ ASSERT_FALSE(shape_rects.empty());
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects,
+ maximized_bounds.width() - 1,
+ 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects,
+ maximized_bounds.width() - 1,
+ 15));
+ }
+
+ // 2) Test setting the window shape via Widget::SetShape().
+ gfx::Path shape2;
+ shape2.moveTo(10, 0);
+ shape2.lineTo(10, 10);
+ shape2.lineTo(0, 10);
+ shape2.lineTo(0, 100);
+ shape2.lineTo(100, 100);
+ shape2.lineTo(100, 0);
+ shape2.close();
+
+ scoped_ptr<Widget> widget2(CreateWidget(NULL));
+ widget2->Show();
+ widget2->SetShape(shape2.CreateNativeRegion());
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ XID xid2 = widget2->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ shape_rects = GetShapeRects(xid2);
+ ASSERT_FALSE(shape_rects.empty());
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
+
+ // Changing the widget's size should not affect the shape.
+ widget2->SetBounds(gfx::Rect(100, 100, 200, 200));
+ shape_rects = GetShapeRects(xid2);
+ ASSERT_FALSE(shape_rects.empty());
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 5, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 15, 5));
+ EXPECT_TRUE(ShapeRectContainsPoint(shape_rects, 95, 15));
+ EXPECT_FALSE(ShapeRectContainsPoint(shape_rects, 105, 15));
+}
+
+// Test that the widget ignores changes in fullscreen state initiated by the
+// window manager (e.g. via a window manager accelerator key).
+TEST_F(DesktopWindowTreeHostX11Test, WindowManagerTogglesFullscreen) {
+ if (!ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_FULLSCREEN")))
+ return;
+
+ scoped_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
+ XID xid = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ widget->Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
+ {
+ WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", true);
+ widget->SetFullscreen(true);
+ waiter.Wait();
+ }
+ EXPECT_TRUE(widget->IsFullscreen());
+
+ // Emulate the window manager exiting fullscreen via a window manager
+ // accelerator key. It should not affect the widget's fullscreen state.
+ {
+ const char* kAtomsToCache[] = {
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_FULLSCREEN",
+ NULL
+ };
+ Display* display = gfx::GetXDisplay();
+ ui::X11AtomCache atom_cache(display, kAtomsToCache);
+
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = xid;
+ xclient.xclient.message_type = atom_cache.GetAtom("_NET_WM_STATE");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] = 0;
+ xclient.xclient.data.l[1] = atom_cache.GetAtom("_NET_WM_STATE_FULLSCREEN");
+ xclient.xclient.data.l[2] = 0;
+ xclient.xclient.data.l[3] = 1;
+ xclient.xclient.data.l[4] = 0;
+ XSendEvent(display, DefaultRootWindow(display), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xclient);
+
+ WMStateWaiter waiter(xid, "_NET_WM_STATE_FULLSCREEN", false);
+ waiter.Wait();
+ }
+ EXPECT_TRUE(widget->IsFullscreen());
+
+ // Calling Widget::SetFullscreen(false) should clear the widget's fullscreen
+ // state and clean things up.
+ widget->SetFullscreen(false);
+ EXPECT_FALSE(widget->IsFullscreen());
+ EXPECT_EQ(initial_bounds.ToString(),
+ widget->GetWindowBoundsInScreen().ToString());
+}
+
+// Tests that the minimization information is propagated to the content window.
+TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
+ Widget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(params);
+ widget.Show();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ XID xid = widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ Display* display = gfx::GetXDisplay();
+
+ // Minimize by sending _NET_WM_STATE_HIDDEN
+ {
+ const char* kAtomsToCache[] = {
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_HIDDEN",
+ NULL
+ };
+
+ ui::X11AtomCache atom_cache(display, kAtomsToCache);
+
+ std::vector< ::Atom> atom_list;
+ atom_list.push_back(atom_cache.GetAtom("_NET_WM_STATE_HIDDEN"));
+ ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(xevent));
+ xevent.type = PropertyNotify;
+ xevent.xproperty.type = PropertyNotify;
+ xevent.xproperty.send_event = 1;
+ xevent.xproperty.display = display;
+ xevent.xproperty.window = xid;
+ xevent.xproperty.atom = atom_cache.GetAtom("_NET_WM_STATE");
+ xevent.xproperty.state = 0;
+ XSendEvent(display, DefaultRootWindow(display), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xevent);
+
+ WMStateWaiter waiter(xid, "_NET_WM_STATE_HIDDEN", true);
+ waiter.Wait();
+ }
+ EXPECT_FALSE(widget.GetNativeWindow()->IsVisible());
+
+ // Show from minimized by sending _NET_WM_STATE_FOCUSED
+ {
+ const char* kAtomsToCache[] = {
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_FOCUSED",
+ NULL
+ };
+
+ ui::X11AtomCache atom_cache(display, kAtomsToCache);
+
+ std::vector< ::Atom> atom_list;
+ atom_list.push_back(atom_cache.GetAtom("_NET_WM_STATE_FOCUSED"));
+ ui::SetAtomArrayProperty(xid, "_NET_WM_STATE", "ATOM", atom_list);
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(xevent));
+ xevent.type = PropertyNotify;
+ xevent.xproperty.type = PropertyNotify;
+ xevent.xproperty.send_event = 1;
+ xevent.xproperty.display = display;
+ xevent.xproperty.window = xid;
+ xevent.xproperty.atom = atom_cache.GetAtom("_NET_WM_STATE");
+ xevent.xproperty.state = 0;
+ XSendEvent(display, DefaultRootWindow(display), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xevent);
+
+ WMStateWaiter waiter(xid, "_NET_WM_STATE_FOCUSED", true);
+ waiter.Wait();
+ }
+ EXPECT_TRUE(widget.GetNativeWindow()->IsVisible());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
index 0cfe040cbdf..d43b853093b 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
@@ -9,19 +9,18 @@
#include "base/message_loop/message_loop.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util.h"
-
-#if !defined(OS_CHROMEOS)
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11_error_tracker.h"
#include "ui/views/ime/input_method.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
-#endif
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
namespace {
const char* kAtomsToCache[] = {
"_NET_ACTIVE_WINDOW",
- "_NET_SUPPORTED",
NULL
};
@@ -43,10 +42,12 @@ X11DesktopHandler* X11DesktopHandler::get() {
X11DesktopHandler::X11DesktopHandler()
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
+ wm_user_time_ms_(0),
current_window_(None),
atom_cache_(xdisplay_, kAtomsToCache),
wm_supports_active_window_(false) {
- base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
aura::Env::GetInstance()->AddObserver(this);
XWindowAttributes attr;
@@ -55,22 +56,16 @@ X11DesktopHandler::X11DesktopHandler()
attr.your_event_mask | PropertyChangeMask |
StructureNotifyMask | SubstructureNotifyMask);
- std::vector<Atom> atoms;
- if (ui::GetAtomArrayProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &atoms)) {
- Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
- for (std::vector<Atom>::iterator iter = atoms.begin(); iter != atoms.end();
- ++iter) {
- if (*(iter) == active_window) {
- wm_supports_active_window_ = true;
- break;
- }
- }
- }
+ ::Window active_window;
+ wm_supports_active_window_ =
+ ui::GetXIDProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &active_window) &&
+ active_window;
}
X11DesktopHandler::~X11DesktopHandler() {
aura::Env::GetInstance()->RemoveObserver(this);
- base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
+ if (ui::PlatformEventSource::GetInstance())
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
void X11DesktopHandler::ActivateWindow(::Window window) {
@@ -84,7 +79,7 @@ void X11DesktopHandler::ActivateWindow(::Window window) {
xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
xclient.xclient.format = 32;
xclient.xclient.data.l[0] = 1; // Specified we are an app.
- xclient.xclient.data.l[1] = CurrentTime;
+ xclient.xclient.data.l[1] = wm_user_time_ms_;
xclient.xclient.data.l[2] = None;
xclient.xclient.data.l[3] = 0;
xclient.xclient.data.l[4] = 0;
@@ -94,6 +89,12 @@ void X11DesktopHandler::ActivateWindow(::Window window) {
&xclient);
} else {
XRaiseWindow(xdisplay_, window);
+
+ // XRaiseWindow will not give input focus to the window. We now need to ask
+ // the X server to do that. Note that the call will raise an X error if the
+ // window is not mapped.
+ XSetInputFocus(xdisplay_, window, RevertToParent, CurrentTime);
+
OnActiveWindowChanged(window);
}
}
@@ -102,16 +103,14 @@ bool X11DesktopHandler::IsActiveWindow(::Window window) const {
return window == current_window_;
}
-void X11DesktopHandler::ProcessXEvent(const base::NativeEvent& event) {
+void X11DesktopHandler::ProcessXEvent(XEvent* event) {
switch (event->type) {
- case EnterNotify:
- if (event->xcrossing.focus == True &&
- current_window_ != event->xcrossing.window)
- OnActiveWindowChanged(event->xcrossing.window);
+ case FocusIn:
+ if (current_window_ != event->xfocus.window)
+ OnActiveWindowChanged(event->xfocus.window);
break;
- case LeaveNotify:
- if (event->xcrossing.focus == False &&
- current_window_ == event->xcrossing.window)
+ case FocusOut:
+ if (current_window_ == event->xfocus.window)
OnActiveWindowChanged(None);
break;
default:
@@ -119,25 +118,53 @@ void X11DesktopHandler::ProcessXEvent(const base::NativeEvent& event) {
}
}
-bool X11DesktopHandler::Dispatch(const base::NativeEvent& event) {
- // Check for a change to the active window.
+bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return event->type == CreateNotify || event->type == DestroyNotify ||
+ (event->type == PropertyNotify &&
+ event->xproperty.window == x_root_window_);
+}
+
+uint32_t X11DesktopHandler::DispatchEvent(const ui::PlatformEvent& event) {
switch (event->type) {
case PropertyNotify: {
- ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
-
- if (event->xproperty.window == x_root_window_ &&
- event->xproperty.atom == active_window) {
- int window;
- if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
+ // Check for a change to the active window.
+ CHECK_EQ(x_root_window_, event->xproperty.window);
+ ::Atom active_window_atom = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
+ if (event->xproperty.atom == active_window_atom) {
+ ::Window window;
+ if (ui::GetXIDProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
window) {
- OnActiveWindowChanged(static_cast< ::Window>(window));
+ OnActiveWindowChanged(window);
}
}
break;
}
+
+ // Menus created by Chrome can be drag and drop targets. Since they are
+ // direct children of the screen root window and have override_redirect
+ // we cannot use regular _NET_CLIENT_LIST_STACKING property to find them
+ // and use a separate cache to keep track of them.
+ // TODO(varkha): Implement caching of all top level X windows and their
+ // coordinates and stacking order to eliminate repeated calls to X server
+ // during mouse movement, drag and shaping events.
+ case CreateNotify: {
+ // The window might be destroyed if the message pump haven't gotten a
+ // chance to run but we can safely ignore the X error.
+ gfx::X11ErrorTracker error_tracker;
+ XCreateWindowEvent *xcwe = &event->xcreatewindow;
+ ui::XMenuList::GetInstance()->MaybeRegisterMenu(xcwe->window);
+ break;
+ }
+ case DestroyNotify: {
+ XDestroyWindowEvent *xdwe = &event->xdestroywindow;
+ ui::XMenuList::GetInstance()->MaybeUnregisterMenu(xdwe->window);
+ break;
+ }
+ default:
+ NOTREACHED();
}
- return true;
+ return ui::POST_DISPATCH_NONE;
}
void X11DesktopHandler::OnWindowInitialized(aura::Window* window) {
@@ -151,17 +178,18 @@ void X11DesktopHandler::OnWillDestroyEnv() {
void X11DesktopHandler::OnActiveWindowChanged(::Window xid) {
if (current_window_ == xid)
return;
- DesktopRootWindowHostX11* old_host =
- views::DesktopRootWindowHostX11::GetHostForXID(current_window_);
+ DesktopWindowTreeHostX11* old_host =
+ views::DesktopWindowTreeHostX11::GetHostForXID(current_window_);
if (old_host)
old_host->HandleNativeWidgetActivationChanged(false);
- DesktopRootWindowHostX11* new_host =
- views::DesktopRootWindowHostX11::GetHostForXID(xid);
+ // Update the current window ID to effectively change the active widget.
+ current_window_ = xid;
+
+ DesktopWindowTreeHostX11* new_host =
+ views::DesktopWindowTreeHostX11::GetHostForXID(xid);
if (new_host)
new_host->HandleNativeWidgetActivationChanged(true);
-
- current_window_ = xid;
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
index 3399b401cf1..56b2084e7a5 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -9,8 +9,10 @@
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow
-#include "base/message_loop/message_loop.h"
+#include <vector>
+
#include "ui/aura/env_observer.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/views/views_export.h"
@@ -22,13 +24,23 @@ namespace views {
// A singleton that owns global objects related to the desktop and listens for
// X11 events on the X11 root window. Destroys itself when aura::Env is
// deleted.
-class VIEWS_EXPORT X11DesktopHandler : public base::MessageLoop::Dispatcher,
+class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher,
public aura::EnvObserver {
public:
// Returns the singleton handler.
static X11DesktopHandler* get();
+ // Gets/sets the X11 server time of the most recent mouse click, touch or
+ // key press on a Chrome window.
+ int wm_user_time_ms() const {
+ return wm_user_time_ms_;
+ }
+ void set_wm_user_time_ms(unsigned long time_ms) {
+ wm_user_time_ms_ = time_ms;
+ }
+
// Sends a request to the window manager to activate |window|.
+ // This method should only be called if the window is already mapped.
void ActivateWindow(::Window window);
// Checks if the current active window is |window|.
@@ -37,10 +49,11 @@ class VIEWS_EXPORT X11DesktopHandler : public base::MessageLoop::Dispatcher,
// Processes activation/focus related events. Some of these events are
// dispatched to the X11 window dispatcher, and not to the X11 root-window
// dispatcher. The window dispatcher sends these events to here.
- void ProcessXEvent(const base::NativeEvent& event);
+ void ProcessXEvent(XEvent* event);
- // Overridden from MessageLoop::Dispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // ui::PlatformEventDispatcher
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
// Overridden from aura::EnvObserver:
virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
@@ -59,6 +72,10 @@ class VIEWS_EXPORT X11DesktopHandler : public base::MessageLoop::Dispatcher,
// The native root window.
::Window x_root_window_;
+ // The X11 server time of the most recent mouse click, touch, or key press
+ // on a Chrome window.
+ unsigned long wm_user_time_ms_;
+
// The activated window.
::Window current_window_;
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
index a79d365ebc7..195d102a587 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
@@ -5,45 +5,22 @@
#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
#include <X11/Xlib.h>
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
#include "base/debug/stack_trace.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
#include "ui/gfx/screen.h"
-namespace {
-
-// Delay moving the window.
-//
-// When we receive a mouse move event, we have to have it processed in a
-// different run through the message pump because moving the window will
-// otherwise prevent tasks from running.
-//
-// This constant was derived with playing with builds of chrome; it has no
-// theoretical justification.
-//
-// TODO(erg): This helps with the performance of dragging windows, but it
-// doesn't really solve the hard problems, which is that various calls to X11,
-// such as XQueryPointer, ui::IsWindowVisible() and ui::WindowContainsPoint()
-// take a while to get replies and block in the process. I've seen all of the
-// above take as long as 20ms to respond.
-const int kMoveDelay = 3;
-
-} // namespace
-
namespace views {
X11DesktopWindowMoveClient::X11DesktopWindowMoveClient()
: move_loop_(this),
- root_window_(NULL) {
+ host_(NULL) {
}
X11DesktopWindowMoveClient::~X11DesktopWindowMoveClient() {}
@@ -51,15 +28,7 @@ X11DesktopWindowMoveClient::~X11DesktopWindowMoveClient() {}
void X11DesktopWindowMoveClient::OnMouseMovement(XMotionEvent* event) {
gfx::Point cursor_point(event->x_root, event->y_root);
gfx::Point system_loc = cursor_point - window_offset_;
-
- gfx::Rect target_rect(system_loc, root_window_->host()->GetBounds().size());
-
- window_move_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kMoveDelay),
- base::Bind(&X11DesktopWindowMoveClient::SetHostBounds,
- base::Unretained(this),
- target_rect));
+ host_->SetBounds(gfx::Rect(system_loc, host_->GetBounds().size()));
}
void X11DesktopWindowMoveClient::OnMouseReleased() {
@@ -67,33 +36,25 @@ void X11DesktopWindowMoveClient::OnMouseReleased() {
}
void X11DesktopWindowMoveClient::OnMoveLoopEnded() {
- root_window_ = NULL;
+ host_ = NULL;
}
////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostLinux, aura::client::WindowMoveClient implementation:
+// DesktopWindowTreeHostLinux, aura::client::WindowMoveClient implementation:
aura::client::WindowMoveResult X11DesktopWindowMoveClient::RunMoveLoop(
aura::Window* source,
const gfx::Vector2d& drag_offset,
aura::client::WindowMoveSource move_source) {
window_offset_ = drag_offset;
- root_window_ = source->GetDispatcher();
+ host_ = source->GetHost();
- bool success = move_loop_.RunMoveLoop(source, root_window_->last_cursor());
+ bool success = move_loop_.RunMoveLoop(source, host_->last_cursor());
return success ? aura::client::MOVE_SUCCESSFUL : aura::client::MOVE_CANCELED;
}
void X11DesktopWindowMoveClient::EndMoveLoop() {
- window_move_timer_.Stop();
move_loop_.EndMoveLoop();
}
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostLinux, private:
-
-void X11DesktopWindowMoveClient::SetHostBounds(const gfx::Rect& rect) {
- root_window_->SetHostBounds(rect);
-}
-
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
index 3be6a63c325..44bdd91ff70 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
@@ -7,25 +7,17 @@
#include <X11/Xlib.h>
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
-
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
-#include "base/timer/timer.h"
-#include "ui/aura/client/window_move_client.h"
#include "ui/gfx/point.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
+#include "ui/wm/public/window_move_client.h"
namespace aura {
-class RootWindow;
-}
-
-namespace gfx {
-class Rect;
+class WindowTreeHost;
}
namespace views {
@@ -51,21 +43,16 @@ class VIEWS_EXPORT X11DesktopWindowMoveClient :
virtual void EndMoveLoop() OVERRIDE;
private:
- // Callback from |window_move_timer_|.
- void SetHostBounds(const gfx::Rect& rect);
-
X11WholeScreenMoveLoop move_loop_;
// We need to keep track of this so we can actually move it when reacting to
// mouse events.
- aura::RootWindow* root_window_;
+ aura::WindowTreeHost* host_;
// Our cursor offset from the top left window origin when the drag
// started. Used to calculate the window's new bounds relative to the current
// location of the cursor.
gfx::Vector2d window_offset_;
-
- base::OneShotTimer<X11DesktopWindowMoveClient> window_move_timer_;
};
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.cc b/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.cc
new file mode 100644
index 00000000000..b48bb5005ba
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.cc
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_scoped_capture.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include "ui/gfx/x/x11_types.h"
+
+namespace views {
+
+X11ScopedCapture::X11ScopedCapture(XID window)
+ : captured_(false) {
+ // TODO(sad): Use XI2 API instead.
+ unsigned int event_mask = PointerMotionMask | ButtonReleaseMask |
+ ButtonPressMask;
+ int status = XGrabPointer(gfx::GetXDisplay(), window, True, event_mask,
+ GrabModeAsync, GrabModeAsync, None, None,
+ CurrentTime);
+ captured_ = status == GrabSuccess;
+}
+
+X11ScopedCapture::~X11ScopedCapture() {
+ if (captured_) {
+ XUngrabPointer(gfx::GetXDisplay(), CurrentTime);
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.h b/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.h
new file mode 100644
index 00000000000..cd744c86451
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_scoped_capture.h
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_SCOPED_CAPTURE_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_SCOPED_CAPTURE_H_
+
+#include "base/basictypes.h"
+
+typedef unsigned long XID;
+
+namespace views {
+
+// Grabs X11 input on a window., i.e. all subsequent mouse events are dispatched
+// to the window, while the capture is active.
+class X11ScopedCapture {
+ public:
+ explicit X11ScopedCapture(XID window);
+ virtual ~X11ScopedCapture();
+
+ private:
+ bool captured_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11ScopedCapture);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_SCOPED_CAPTURE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
new file mode 100644
index 00000000000..d59b46cf379
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
@@ -0,0 +1,97 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
+
+#include <X11/Xutil.h>
+
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/window.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+
+namespace views {
+
+X11TopmostWindowFinder::X11TopmostWindowFinder() : toplevel_(None) {
+}
+
+X11TopmostWindowFinder::~X11TopmostWindowFinder() {
+}
+
+aura::Window* X11TopmostWindowFinder::FindLocalProcessWindowAt(
+ const gfx::Point& screen_loc,
+ const std::set<aura::Window*>& ignore) {
+ screen_loc_ = screen_loc;
+ ignore_ = ignore;
+
+ std::vector<aura::Window*> local_process_windows =
+ DesktopWindowTreeHostX11::GetAllOpenWindows();
+ bool found_local_process_window = false;
+ for (size_t i = 0; i < local_process_windows.size(); ++i) {
+ if (ShouldStopIteratingAtLocalProcessWindow(local_process_windows[i])) {
+ found_local_process_window = true;
+ break;
+ }
+ }
+ if (!found_local_process_window)
+ return NULL;
+
+ ui::EnumerateTopLevelWindows(this);
+ return DesktopWindowTreeHostX11::GetContentWindowForXID(toplevel_);
+}
+
+XID X11TopmostWindowFinder::FindWindowAt(const gfx::Point& screen_loc) {
+ screen_loc_ = screen_loc;
+ ui::EnumerateTopLevelWindows(this);
+ return toplevel_;
+}
+
+bool X11TopmostWindowFinder::ShouldStopIterating(XID xid) {
+ if (!ui::IsWindowVisible(xid))
+ return false;
+
+ aura::Window* window =
+ views::DesktopWindowTreeHostX11::GetContentWindowForXID(xid);
+ if (window) {
+ if (ShouldStopIteratingAtLocalProcessWindow(window)) {
+ toplevel_ = xid;
+ return true;
+ }
+ return false;
+ }
+
+ if (ui::WindowContainsPoint(xid, screen_loc_)) {
+ toplevel_ = xid;
+ return true;
+ }
+ return false;
+}
+
+bool X11TopmostWindowFinder::ShouldStopIteratingAtLocalProcessWindow(
+ aura::Window* window) {
+ if (ignore_.find(window) != ignore_.end())
+ return false;
+
+ // Currently |window|->IsVisible() always returns true.
+ // TODO(pkotwicz): Fix this. crbug.com/353038
+ if (!window->IsVisible())
+ return false;
+
+ DesktopWindowTreeHostX11* host =
+ DesktopWindowTreeHostX11::GetHostForXID(
+ window->GetHost()->GetAcceleratedWidget());
+ if (!host->GetX11RootWindowOuterBounds().Contains(screen_loc_))
+ return false;
+
+ ::Region shape = host->GetWindowShape();
+ if (!shape)
+ return true;
+
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window->GetRootWindow());
+ gfx::Point window_loc(screen_loc_);
+ screen_position_client->ConvertPointFromScreen(window, &window_loc);
+ return XPointInRegion(shape, window_loc.x(), window_loc.y()) == True;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h
new file mode 100644
index 00000000000..cf8498abe50
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
+
+#include <set>
+
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/point.h"
+#include "ui/views/views_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+
+// Utility class for finding the topmost window at a given screen position.
+class VIEWS_EXPORT X11TopmostWindowFinder
+ : public ui::EnumerateWindowsDelegate {
+ public:
+ X11TopmostWindowFinder();
+ virtual ~X11TopmostWindowFinder();
+
+ // Returns the topmost window at |screen_loc|, ignoring the windows in
+ // |ignore|. Returns NULL if the topmost window at |screen_loc| does not
+ // belong to Chrome.
+ aura::Window* FindLocalProcessWindowAt(const gfx::Point& screen_loc,
+ const std::set<aura::Window*>& ignore);
+
+ // Returns the topmost window at |screen_loc|.
+ XID FindWindowAt(const gfx::Point& screen_loc);
+
+ private:
+ // ui::EnumerateWindowsDelegate:
+ virtual bool ShouldStopIterating(XID xid) OVERRIDE;
+
+ // Returns true if |window| does not not belong to |ignore|, is visible and
+ // contains |screen_loc_|.
+ bool ShouldStopIteratingAtLocalProcessWindow(aura::Window* window);
+
+ gfx::Point screen_loc_;
+ std::set<aura::Window*> ignore_;
+ XID toplevel_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinder);
+};
+
+} // namespace
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_unittest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_unittest.cc
new file mode 100644
index 00000000000..ea9544528f8
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_unittest.cc
@@ -0,0 +1,389 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
+
+#include <algorithm>
+#include <vector>
+#include <X11/extensions/shape.h>
+#include <X11/Xlib.h>
+#include <X11/Xregion.h>
+
+// Get rid of X11 macros which conflict with gtest.
+#undef Bool
+#undef None
+
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/path_x11.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/test/x11_property_change_waiter.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+// Waits till |window| is minimized.
+class MinimizeWaiter : public X11PropertyChangeWaiter {
+ public:
+ explicit MinimizeWaiter(XID window)
+ : X11PropertyChangeWaiter(window, "_NET_WM_STATE") {
+ const char* kAtomsToCache[] = { "_NET_WM_STATE_HIDDEN", NULL };
+ atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
+ }
+
+ virtual ~MinimizeWaiter() {
+ }
+
+ private:
+ // X11PropertyChangeWaiter:
+ virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
+ std::vector<Atom> wm_states;
+ if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
+ std::vector<Atom>::iterator it = std::find(
+ wm_states.begin(),
+ wm_states.end(),
+ atom_cache_->GetAtom("_NET_WM_STATE_HIDDEN"));
+ return it == wm_states.end();
+ }
+ return true;
+ }
+
+ scoped_ptr<ui::X11AtomCache> atom_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(MinimizeWaiter);
+};
+
+// Waits till |_NET_CLIENT_LIST_STACKING| is updated to include
+// |expected_windows|.
+class StackingClientListWaiter : public X11PropertyChangeWaiter {
+ public:
+ StackingClientListWaiter(XID* expected_windows, size_t count)
+ : X11PropertyChangeWaiter(ui::GetX11RootWindow(),
+ "_NET_CLIENT_LIST_STACKING"),
+ expected_windows_(expected_windows, expected_windows + count) {
+ }
+
+ virtual ~StackingClientListWaiter() {
+ }
+
+ // X11PropertyChangeWaiter:
+ virtual void Wait() OVERRIDE {
+ // StackingClientListWaiter may be created after
+ // _NET_CLIENT_LIST_STACKING already contains |expected_windows|.
+ if (!ShouldKeepOnWaiting(NULL))
+ return;
+
+ X11PropertyChangeWaiter::Wait();
+ }
+
+ private:
+ // X11PropertyChangeWaiter:
+ virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
+ std::vector<XID> stack;
+ ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
+ for (size_t i = 0; i < expected_windows_.size(); ++i) {
+ std::vector<XID>::iterator it = std::find(
+ stack.begin(), stack.end(), expected_windows_[i]);
+ if (it == stack.end())
+ return true;
+ }
+ return false;
+ }
+
+ std::vector<XID> expected_windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackingClientListWaiter);
+};
+
+} // namespace
+
+class X11TopmostWindowFinderTest : public ViewsTestBase {
+ public:
+ X11TopmostWindowFinderTest() {
+ }
+
+ virtual ~X11TopmostWindowFinderTest() {
+ }
+
+ // Creates and shows a Widget with |bounds|. The caller takes ownership of
+ // the returned widget.
+ scoped_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) {
+ scoped_ptr<Widget> toplevel(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(toplevel.get());
+ params.bounds = bounds;
+ params.remove_standard_frame = true;
+ toplevel->Init(params);
+ toplevel->Show();
+ return toplevel.Pass();
+ }
+
+ // Creates and shows an X window with |bounds|.
+ XID CreateAndShowXWindow(const gfx::Rect& bounds) {
+ XID root = DefaultRootWindow(xdisplay());
+ XID xid = XCreateSimpleWindow(xdisplay(),
+ root,
+ 0, 0, 1, 1,
+ 0, // border_width
+ 0, // border
+ 0); // background
+
+ ui::SetUseOSWindowFrame(xid, false);
+ ShowAndSetXWindowBounds(xid, bounds);
+ return xid;
+ }
+
+ // Shows |xid| and sets its bounds.
+ void ShowAndSetXWindowBounds(XID xid, const gfx::Rect& bounds) {
+ XMapWindow(xdisplay(), xid);
+
+ XWindowChanges changes = {0};
+ changes.x = bounds.x();
+ changes.y = bounds.y();
+ changes.width = bounds.width();
+ changes.height = bounds.height();
+ XConfigureWindow(xdisplay(),
+ xid,
+ CWX | CWY | CWWidth | CWHeight,
+ &changes);
+ }
+
+ Display* xdisplay() {
+ return gfx::GetXDisplay();
+ }
+
+ // Returns the topmost X window at the passed in screen position.
+ XID FindTopmostXWindowAt(int screen_x, int screen_y) {
+ X11TopmostWindowFinder finder;
+ return finder.FindWindowAt(gfx::Point(screen_x, screen_y));
+ }
+
+ // Returns the topmost aura::Window at the passed in screen position. Returns
+ // NULL if the topmost window does not have an associated aura::Window.
+ aura::Window* FindTopmostLocalProcessWindowAt(int screen_x, int screen_y) {
+ X11TopmostWindowFinder finder;
+ return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
+ std::set<aura::Window*>());
+ }
+
+ // Returns the topmost aura::Window at the passed in screen position ignoring
+ // |ignore_window|. Returns NULL if the topmost window does not have an
+ // associated aura::Window.
+ aura::Window* FindTopmostLocalProcessWindowWithIgnore(
+ int screen_x,
+ int screen_y,
+ aura::Window* ignore_window) {
+ std::set<aura::Window*> ignore;
+ ignore.insert(ignore_window);
+ X11TopmostWindowFinder finder;
+ return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
+ ignore);
+ }
+
+ // ViewsTestBase:
+ virtual void SetUp() OVERRIDE {
+ ViewsTestBase::SetUp();
+
+ // Make X11 synchronous for our display connection. This does not force the
+ // window manager to behave synchronously.
+ XSynchronize(xdisplay(), True);
+
+ // Ensure that the X11DesktopHandler exists. The X11DesktopHandler is
+ // necessary to properly track menu windows.
+ X11DesktopHandler::get();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ XSynchronize(xdisplay(), False);
+ ViewsTestBase::TearDown();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinderTest);
+};
+
+TEST_F(X11TopmostWindowFinderTest, Basic) {
+ // Avoid positioning test windows at 0x0 because window managers often have a
+ // panel/launcher along one of the screen edges and do not allow windows to
+ // position themselves to overlap the panel/launcher.
+ scoped_ptr<Widget> widget1(
+ CreateAndShowWidget(gfx::Rect(100, 100, 200, 100)));
+ aura::Window* window1 = widget1->GetNativeWindow();
+ XID xid1 = window1->GetHost()->GetAcceleratedWidget();
+
+ XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200));
+
+ scoped_ptr<Widget> widget3(
+ CreateAndShowWidget(gfx::Rect(100, 190, 200, 110)));
+ aura::Window* window3 = widget3->GetNativeWindow();
+ XID xid3 = window3->GetHost()->GetAcceleratedWidget();
+
+ XID xids[] = { xid1, xid2, xid3 };
+ StackingClientListWaiter waiter(xids, arraysize(xids));
+ waiter.Wait();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
+ EXPECT_EQ(window1, FindTopmostLocalProcessWindowAt(150, 150));
+
+ EXPECT_EQ(xid2, FindTopmostXWindowAt(250, 150));
+ EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(250, 150));
+
+ EXPECT_EQ(xid3, FindTopmostXWindowAt(250, 250));
+ EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(250, 250));
+
+ EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 250));
+ EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 250));
+
+ EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 195));
+ EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 195));
+
+ EXPECT_NE(xid1, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_NE(xid2, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_NE(xid3, FindTopmostXWindowAt(1000, 1000));
+ EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(1000, 1000));
+
+ EXPECT_EQ(window1,
+ FindTopmostLocalProcessWindowWithIgnore(150, 150, window3));
+ EXPECT_EQ(NULL,
+ FindTopmostLocalProcessWindowWithIgnore(250, 250, window3));
+ EXPECT_EQ(NULL,
+ FindTopmostLocalProcessWindowWithIgnore(150, 250, window3));
+ EXPECT_EQ(window1,
+ FindTopmostLocalProcessWindowWithIgnore(150, 195, window3));
+
+ XDestroyWindow(xdisplay(), xid2);
+}
+
+// Test that the minimized state is properly handled.
+TEST_F(X11TopmostWindowFinderTest, Minimized) {
+ scoped_ptr<Widget> widget1(
+ CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
+ aura::Window* window1 = widget1->GetNativeWindow();
+ XID xid1 = window1->GetHost()->GetAcceleratedWidget();
+ XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
+
+ XID xids[] = { xid1, xid2 };
+ StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ stack_waiter.Wait();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
+ {
+ MinimizeWaiter minimize_waiter(xid1);
+ XIconifyWindow(xdisplay(), xid1, 0);
+ minimize_waiter.Wait();
+ }
+ EXPECT_NE(xid1, FindTopmostXWindowAt(150, 150));
+ EXPECT_NE(xid2, FindTopmostXWindowAt(150, 150));
+
+ // Repeat test for an X window which does not belong to a views::Widget
+ // because the code path is different.
+ EXPECT_EQ(xid2, FindTopmostXWindowAt(350, 150));
+ {
+ MinimizeWaiter minimize_waiter(xid2);
+ XIconifyWindow(xdisplay(), xid2, 0);
+ minimize_waiter.Wait();
+ }
+ EXPECT_NE(xid1, FindTopmostXWindowAt(350, 150));
+ EXPECT_NE(xid2, FindTopmostXWindowAt(350, 150));
+
+ XDestroyWindow(xdisplay(), xid2);
+}
+
+// Test that non-rectangular windows are properly handled.
+TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
+ if (!ui::IsShapeExtensionAvailable())
+ return;
+
+ scoped_ptr<Widget> widget1(
+ CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
+ XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ SkRegion* skregion1 = new SkRegion;
+ skregion1->op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
+ skregion1->op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
+ // Widget takes ownership of |skregion1|.
+ widget1->SetShape(skregion1);
+
+ SkRegion skregion2;
+ skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
+ skregion2.op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
+ XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
+ REGION* region2 = gfx::CreateRegionFromSkRegion(skregion2);
+ XShapeCombineRegion(xdisplay(), xid2, ShapeBounding, 0, 0, region2,
+ false);
+ XDestroyRegion(region2);
+
+ XID xids[] = { xid1, xid2 };
+ StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ stack_waiter.Wait();
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ EXPECT_EQ(xid1, FindTopmostXWindowAt(105, 120));
+ EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105));
+ EXPECT_NE(xid2, FindTopmostXWindowAt(105, 105));
+
+ // Repeat test for an X window which does not belong to a views::Widget
+ // because the code path is different.
+ EXPECT_EQ(xid2, FindTopmostXWindowAt(305, 120));
+ EXPECT_NE(xid1, FindTopmostXWindowAt(305, 105));
+ EXPECT_NE(xid2, FindTopmostXWindowAt(305, 105));
+
+ XDestroyWindow(xdisplay(), xid2);
+}
+
+// Test that the TopmostWindowFinder finds windows which belong to menus
+// (which may or may not belong to Chrome).
+TEST_F(X11TopmostWindowFinderTest, Menu) {
+ XID xid = CreateAndShowXWindow(gfx::Rect(100, 100, 100, 100));
+
+ XID root = DefaultRootWindow(xdisplay());
+ XSetWindowAttributes swa;
+ swa.override_redirect = True;
+ XID menu_xid = XCreateWindow(xdisplay(),
+ root,
+ 0, 0, 1, 1,
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWOverrideRedirect,
+ &swa);
+ {
+ const char* kAtomsToCache[] = { "_NET_WM_WINDOW_TYPE_MENU", NULL };
+ ui::X11AtomCache atom_cache(gfx::GetXDisplay(), kAtomsToCache);
+ ui::SetAtomProperty(menu_xid,
+ "_NET_WM_WINDOW_TYPE",
+ "ATOM",
+ atom_cache.GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
+ }
+ ui::SetUseOSWindowFrame(menu_xid, false);
+ ShowAndSetXWindowBounds(menu_xid, gfx::Rect(140, 110, 100, 100));
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ // |menu_xid| is never added to _NET_CLIENT_LIST_STACKING.
+ XID xids[] = { xid };
+ StackingClientListWaiter stack_waiter(xids, arraysize(xids));
+ stack_waiter.Wait();
+
+ EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110));
+ EXPECT_EQ(menu_xid, FindTopmostXWindowAt(150, 120));
+ EXPECT_EQ(menu_xid, FindTopmostXWindowAt(210, 120));
+
+ XDestroyWindow(xdisplay(), xid);
+ XDestroyWindow(xdisplay(), menu_xid);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 20c061bd670..6c0b3c6b9e7 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -8,16 +8,20 @@
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow
-#include "base/debug/stack_trace.h"
+#include "base/bind.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/image_view.h"
@@ -27,9 +31,14 @@ namespace views {
namespace {
+// The minimum alpha before we declare a pixel transparent when searching in
+// our source image.
+const uint32 kMinAlpha = 32;
+const unsigned char kDragWidgetOpacity = 0xc0;
+
class ScopedCapturer {
public:
- explicit ScopedCapturer(aura::RootWindowHost* host)
+ explicit ScopedCapturer(aura::WindowTreeHost* host)
: host_(host) {
host_->SetCapture();
}
@@ -39,7 +48,7 @@ class ScopedCapturer {
}
private:
- aura::RootWindowHost* host_;
+ aura::WindowTreeHost* host_;
DISALLOW_COPY_AND_ASSIGN(ScopedCapturer);
};
@@ -50,15 +59,42 @@ X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(
X11WholeScreenMoveLoopDelegate* delegate)
: delegate_(delegate),
in_move_loop_(false),
- grab_input_window_(None) {
+ should_reset_mouse_flags_(false),
+ grab_input_window_(None),
+ canceled_(false),
+ has_grab_(false),
+ weak_factory_(this) {
+ last_xmotion_.type = LASTEvent;
}
X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}
+void X11WholeScreenMoveLoop::DispatchMouseMovement() {
+ if (!weak_factory_.HasWeakPtrs())
+ return;
+ weak_factory_.InvalidateWeakPtrs();
+ DCHECK_EQ(MotionNotify, last_xmotion_.type);
+ delegate_->OnMouseMovement(&last_xmotion_);
+ last_xmotion_.type = LASTEvent;
+}
+
////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation:
+// DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation:
+
+bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
+ return in_move_loop_;
+}
-bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
+uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
+ // This method processes all events for the grab_input_window_ as well as
+ // mouse events for all windows while the move loop is active - even before
+ // the grab is granted by X. This allows mouse notification events that were
+ // sent after the capture was requested but before the capture was granted
+ // to be dispatched. It is especially important to process the mouse release
+ // event that should have stopped the drag even if that mouse release happened
+ // before the grab was granted.
+ if (!in_move_loop_)
+ return ui::POST_DISPATCH_PERFORM_DEFAULT;
XEvent* xev = event;
// Note: the escape key is handled in the tab drag controller, which has
@@ -70,70 +106,152 @@ bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
gfx::Point location = gfx::ToFlooredPoint(
screen->GetCursorScreenPoint() - drag_offset_);
drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size()));
+ drag_widget_->StackAtTop();
}
- delegate_->OnMouseMovement(&xev->xmotion);
- break;
+ last_xmotion_ = xev->xmotion;
+ if (!weak_factory_.HasWeakPtrs()) {
+ // Post a task to dispatch mouse movement event when control returns to
+ // the message loop. This allows smoother dragging since the events are
+ // dispatched without waiting for the drag widget updates.
+ base::MessageLoopForUI::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement,
+ weak_factory_.GetWeakPtr()));
+ }
+ return ui::POST_DISPATCH_NONE;
}
case ButtonRelease: {
if (xev->xbutton.button == Button1) {
// Assume that drags are being done with the left mouse button. Only
// break the drag if the left mouse button was released.
+ DispatchMouseMovement();
delegate_->OnMouseReleased();
}
+ return ui::POST_DISPATCH_NONE;
+ }
+ case KeyPress: {
+ if (ui::KeyboardCodeFromXKeyEvent(xev) == ui::VKEY_ESCAPE) {
+ canceled_ = true;
+ EndMoveLoop();
+ return ui::POST_DISPATCH_NONE;
+ }
break;
}
+ case FocusOut: {
+ if (xev->xfocus.mode != NotifyGrab)
+ has_grab_ = false;
+ break;
+ }
+ case GenericEvent: {
+ ui::EventType type = ui::EventTypeFromNative(xev);
+ switch (type) {
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_RELEASED: {
+ XEvent xevent = {0};
+ if (type == ui::ET_MOUSE_RELEASED) {
+ xevent.type = ButtonRelease;
+ xevent.xbutton.button = ui::EventButtonFromNative(xev);
+ } else {
+ xevent.type = MotionNotify;
+ }
+ xevent.xany.display = xev->xgeneric.display;
+ xevent.xany.window = grab_input_window_;
+ // The fields used below are in the same place for all of events
+ // above. Using xmotion from XEvent's unions to avoid repeating
+ // the code.
+ xevent.xmotion.root = DefaultRootWindow(xev->xgeneric.display);
+ xevent.xmotion.time = ui::EventTimeFromNative(xev).InMilliseconds();
+ gfx::Point point(ui::EventSystemLocationFromNative(xev));
+ xevent.xmotion.x_root = point.x();
+ xevent.xmotion.y_root = point.y();
+ DispatchEvent(&xevent);
+ return ui::POST_DISPATCH_NONE;
+ }
+ default:
+ break;
+ }
+ }
}
- return true;
+ return (event->xany.window == grab_input_window_) ?
+ ui::POST_DISPATCH_NONE : ui::POST_DISPATCH_PERFORM_DEFAULT;
}
-////////////////////////////////////////////////////////////////////////////////
-// DesktopRootWindowHostLinux, aura::client::WindowMoveClient implementation:
-
bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
gfx::NativeCursor cursor) {
- // Start a capture on the host, so that it continues to receive events during
- // the drag.
- ScopedCapturer capturer(source->GetDispatcher()->host());
-
DCHECK(!in_move_loop_); // Can only handle one nested loop at a time.
- in_move_loop_ = true;
- XDisplay* display = gfx::GetXDisplay();
+ // Start a capture on the host, so that it continues to receive events during
+ // the drag. This may be second time we are capturing the mouse events - the
+ // first being when a mouse is first pressed. That first capture needs to be
+ // released before the call to GrabPointerAndKeyboard below, otherwise it may
+ // get released while we still need the pointer grab, which is why we restrict
+ // the scope here.
+ {
+ ScopedCapturer capturer(source->GetHost());
+
+ grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay());
+ // Releasing ScopedCapturer ensures that any other instance of
+ // X11ScopedCapture will not prematurely release grab that will be acquired
+ // below.
+ }
+ // TODO(varkha): Consider integrating GrabPointerAndKeyboard with
+ // ScopedCapturer to avoid possibility of logically keeping multiple grabs.
+ if (!GrabPointerAndKeyboard(cursor)) {
+ XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
+ return false;
+ }
- grab_input_window_ = CreateDragInputWindow(display);
- if (!drag_image_.isNull())
+ scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
+ nested_dispatcher_.Pass();
+ nested_dispatcher_ =
+ ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this);
+ if (!drag_image_.isNull() && CheckIfIconValid())
CreateDragImageWindow();
- base::MessagePumpX11::Current()->AddDispatcherForWindow(
- this, grab_input_window_);
-
- if (!GrabPointerWithCursor(cursor))
- return false;
// We are handling a mouse drag outside of the aura::RootWindow system. We
// must manually make aura think that the mouse button is pressed so that we
// don't draw extraneous tooltips.
- aura::Env::GetInstance()->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
+ aura::Env* env = aura::Env::GetInstance();
+ if (!env->IsMouseButtonDown()) {
+ env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
+ should_reset_mouse_flags_ = true;
+ }
+ in_move_loop_ = true;
+ canceled_ = false;
base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
- base::RunLoop run_loop(aura::Env::GetInstance()->GetDispatcher());
+ base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
- return true;
+ nested_dispatcher_ = old_dispatcher.Pass();
+ return !canceled_;
}
void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
- DCHECK(in_move_loop_);
- GrabPointerWithCursor(cursor);
+ if (in_move_loop_) {
+ // If we're still in the move loop, regrab the pointer with the updated
+ // cursor. Note: we can be called from handling an XdndStatus message after
+ // EndMoveLoop() was called, but before we return from the nested RunLoop.
+ GrabPointerAndKeyboard(cursor);
+ }
}
void X11WholeScreenMoveLoop::EndMoveLoop() {
if (!in_move_loop_)
return;
+ // Prevent DispatchMouseMovement from dispatching any posted motion event.
+ weak_factory_.InvalidateWeakPtrs();
+ last_xmotion_.type = LASTEvent;
+
// We undo our emulated mouse click from RunMoveLoop();
- aura::Env::GetInstance()->set_mouse_button_flags(0);
+ if (should_reset_mouse_flags_) {
+ aura::Env::GetInstance()->set_mouse_button_flags(0);
+ should_reset_mouse_flags_ = false;
+ }
// TODO(erg): Is this ungrab the cause of having to click to give input focus
// on drawn out windows? Not ungrabbing here screws the X server until I kill
@@ -141,13 +259,18 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
// Ungrab before we let go of the window.
XDisplay* display = gfx::GetXDisplay();
- XUngrabPointer(display, CurrentTime);
+ // Only ungrab pointer if capture was not switched to another window.
+ if (has_grab_) {
+ XUngrabPointer(display, CurrentTime);
+ XUngrabKeyboard(display, CurrentTime);
+ }
- base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
- grab_input_window_);
+ // Restore the previous dispatcher.
+ nested_dispatcher_.reset();
drag_widget_.reset();
delegate_->OnMoveLoopEnded();
XDestroyWindow(display, grab_input_window_);
+ grab_input_window_ = None;
in_move_loop_ = false;
quit_closure_.Run();
@@ -162,9 +285,10 @@ void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image,
drag_offset_.set_y(0.f);
}
-bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
+bool X11WholeScreenMoveLoop::GrabPointerAndKeyboard(gfx::NativeCursor cursor) {
XDisplay* display = gfx::GetXDisplay();
XGrabServer(display);
+
XUngrabPointer(display, CurrentTime);
int ret = XGrabPointer(
display,
@@ -176,14 +300,28 @@ bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
None,
cursor.platform(),
CurrentTime);
- XUngrabServer(display);
if (ret != GrabSuccess) {
- DLOG(ERROR) << "Grabbing new tab for dragging failed: "
+ DLOG(ERROR) << "Grabbing pointer for dragging failed: "
<< ui::GetX11ErrorString(display, ret);
- return false;
+ } else {
+ has_grab_ = true;
+ XUngrabKeyboard(display, CurrentTime);
+ ret = XGrabKeyboard(
+ display,
+ grab_input_window_,
+ False,
+ GrabModeAsync,
+ GrabModeAsync,
+ CurrentTime);
+ if (ret != GrabSuccess) {
+ DLOG(ERROR) << "Grabbing keyboard for dragging failed: "
+ << ui::GetX11ErrorString(display, ret);
+ }
}
- return true;
+ XUngrabServer(display);
+ XFlush(display);
+ return ret == GrabSuccess;
}
Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
@@ -196,7 +334,7 @@ Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
- StructureNotifyMask;
+ KeyPressMask | KeyReleaseMask | StructureNotifyMask;
swa.override_redirect = True;
Window window = XCreateWindow(display,
DefaultRootWindow(display),
@@ -204,7 +342,7 @@ Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
0, CopyFromParent, InputOnly, CopyFromParent,
attribute_mask, &swa);
XMapRaised(display, window);
- base::MessagePumpX11::Current()->BlockUntilWindowMapped(window);
+ ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window);
return window;
}
@@ -221,17 +359,35 @@ void X11WholeScreenMoveLoop::CreateDragImageWindow() {
widget->set_focus_on_creation(false);
widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
widget->Init(params);
+ widget->SetOpacity(kDragWidgetOpacity);
widget->GetNativeWindow()->SetName("DragWindow");
ImageView* image = new ImageView();
image->SetImage(drag_image_);
image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
widget->SetContentsView(image);
-
widget->Show();
widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);
drag_widget_.reset(widget);
}
+bool X11WholeScreenMoveLoop::CheckIfIconValid() {
+ // Because we need a GL context per window, we do a quick check so that we
+ // don't make another context if the window would just be displaying a mostly
+ // transparent image.
+ const SkBitmap* in_bitmap = drag_image_.bitmap();
+ SkAutoLockPixels in_lock(*in_bitmap);
+ for (int y = 0; y < in_bitmap->height(); ++y) {
+ uint32* in_row = in_bitmap->getAddr32(0, y);
+
+ for (int x = 0; x < in_bitmap->width(); ++x) {
+ if (SkColorGetA(in_row[x]) > kMinAlpha)
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
index c0c25466647..cf3665ecac6 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
@@ -5,8 +5,10 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
+#include "base/callback.h"
#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/vector2d_f.h"
@@ -18,23 +20,29 @@ namespace aura {
class Window;
}
+namespace ui {
+class ScopedEventDispatcher;
+}
+
namespace views {
class Widget;
// Runs a nested message loop and grabs the mouse. This is used to implement
// dragging.
-class X11WholeScreenMoveLoop : public base::MessageLoop::Dispatcher {
+class X11WholeScreenMoveLoop : public ui::PlatformEventDispatcher {
public:
explicit X11WholeScreenMoveLoop(X11WholeScreenMoveLoopDelegate* delegate);
virtual ~X11WholeScreenMoveLoop();
- // Overridden from base::MessageLoop::Dispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
+ // ui:::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
// Runs the nested message loop. While the mouse is grabbed, use |cursor| as
- // the mouse cursor. Returns true if there we were able to grab the pointer
- // and run the move loop.
+ // the mouse cursor. Returns true if the move-loop is completed successfully.
+ // If the pointer-grab fails, or the move-loop is canceled by the user (e.g.
+ // by pressing escape), then returns false.
bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor);
// Updates the cursor while the move loop is running.
@@ -47,9 +55,9 @@ class X11WholeScreenMoveLoop : public base::MessageLoop::Dispatcher {
void SetDragImage(const gfx::ImageSkia& image, gfx::Vector2dF offset);
private:
- // Grabs the pointer, setting the mouse cursor to |cursor|. Returns true if
- // the grab was successful.
- bool GrabPointerWithCursor(gfx::NativeCursor cursor);
+ // Grabs the pointer and keyboard, setting the mouse cursor to |cursor|.
+ // Returns true if the grab was successful.
+ bool GrabPointerAndKeyboard(gfx::NativeCursor cursor);
// Creates an input-only window to be used during the drag.
Window CreateDragInputWindow(XDisplay* display);
@@ -57,10 +65,20 @@ class X11WholeScreenMoveLoop : public base::MessageLoop::Dispatcher {
// Creates a window to show the drag image during the drag.
void CreateDragImageWindow();
+ // Checks to see if |in_image| is an image that has any visible regions
+ // (defined as having a pixel with alpha > 32). If so, return true.
+ bool CheckIfIconValid();
+
+ // Dispatch mouse movement event to |delegate_| in a posted task.
+ void DispatchMouseMovement();
+
X11WholeScreenMoveLoopDelegate* delegate_;
// Are we running a nested message loop from RunMoveLoop()?
bool in_move_loop_;
+ scoped_ptr<ui::ScopedEventDispatcher> nested_dispatcher_;
+
+ bool should_reset_mouse_flags_;
// An invisible InputOnly window . We create this window so we can track the
// cursor wherever it goes on screen during a drag, since normal windows
@@ -69,11 +87,20 @@ class X11WholeScreenMoveLoop : public base::MessageLoop::Dispatcher {
base::Closure quit_closure_;
+ // Keeps track of whether the move-loop is cancled by the user (e.g. by
+ // pressing escape).
+ bool canceled_;
+
+ // Keeps track of whether we still have a pointer grab at the end of the loop.
+ bool has_grab_;
+
// A Widget is created during the drag if there is an image available to be
// used during the drag.
scoped_ptr<Widget> drag_widget_;
gfx::ImageSkia drag_image_;
gfx::Vector2dF drag_offset_;
+ XMotionEvent last_xmotion_;
+ base::WeakPtrFactory<X11WholeScreenMoveLoop> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(X11WholeScreenMoveLoop);
};
diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
index 3f415f0050d..ab992c66806 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
@@ -9,15 +9,20 @@
#include <X11/Xatom.h>
#include <X11/Xlib.h>
-#include "ui/aura/root_window.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
#include "ui/gfx/x/x11_types.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#include "ui/views/linux_ui/linux_ui.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/native_widget_aura.h"
+#include "ui/views/widget/widget.h"
namespace {
@@ -33,24 +38,7 @@ const int k_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
const int k_NET_WM_MOVERESIZE_SIZE_LEFT = 7;
const int k_NET_WM_MOVERESIZE_MOVE = 8;
-// This data structure represents additional hints that we send to the window
-// manager and has a direct lineage back to Motif, which defined this de facto
-// standard. This struct doesn't seem 64-bit safe though, but it's what GDK
-// does.
-typedef struct {
- unsigned long flags;
- unsigned long functions;
- unsigned long decorations;
- long input_mode;
- unsigned long status;
-} MotifWmHints;
-
-// The bitflag in |flags| in MotifWmHints that signals that the reader should
-// pay attention to the value in |decorations|.
-const unsigned long kHintsDecorations = (1L << 1);
-
const char* kAtomsToCache[] = {
- "_MOTIF_WM_HINTS",
"_NET_WM_MOVERESIZE",
NULL
};
@@ -60,70 +48,134 @@ const char* kAtomsToCache[] = {
namespace views {
X11WindowEventFilter::X11WindowEventFilter(
- aura::RootWindow* root_window,
- DesktopRootWindowHost* root_window_host)
+ DesktopWindowTreeHost* window_tree_host)
: xdisplay_(gfx::GetXDisplay()),
- xwindow_(root_window->host()->GetAcceleratedWidget()),
+ xwindow_(window_tree_host->AsWindowTreeHost()->GetAcceleratedWidget()),
x_root_window_(DefaultRootWindow(xdisplay_)),
atom_cache_(xdisplay_, kAtomsToCache),
- root_window_host_(root_window_host),
- is_active_(false) {
+ window_tree_host_(window_tree_host),
+ is_active_(false),
+ click_component_(HTNOWHERE) {
}
X11WindowEventFilter::~X11WindowEventFilter() {
}
-void X11WindowEventFilter::SetUseHostWindowBorders(bool use_os_border) {
- MotifWmHints motif_hints;
- memset(&motif_hints, 0, sizeof(motif_hints));
- motif_hints.flags = kHintsDecorations;
- motif_hints.decorations = use_os_border ? 1 : 0;
-
- ::Atom hint_atom = atom_cache_.GetAtom("_MOTIF_WM_HINTS");
- XChangeProperty(gfx::GetXDisplay(),
- xwindow_,
- hint_atom,
- hint_atom,
- 32,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(&motif_hints),
- sizeof(MotifWmHints)/sizeof(long));
-}
-
void X11WindowEventFilter::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() != ui::ET_MOUSE_PRESSED)
return;
- if (!event->IsLeftMouseButton())
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ if (!target->delegate())
return;
- aura::Window* target = static_cast<aura::Window*>(event->target());
+ int previous_click_component = HTNOWHERE;
int component =
target->delegate()->GetNonClientComponent(event->location());
- if (component == HTCLIENT)
- return;
+ if (event->IsLeftMouseButton()) {
+ previous_click_component = click_component_;
+ click_component_ = component;
+ }
+
+ if (component == HTCAPTION) {
+ OnClickedCaption(event, previous_click_component);
+ } else if (component == HTMAXBUTTON) {
+ OnClickedMaximizeButton(event);
+ } else {
+ // Get the |x_root_window_| location out of the native event.
+ if (event->IsLeftMouseButton() && event->native_event()) {
+ const gfx::Point x_root_location =
+ ui::EventSystemLocationFromNative(event->native_event());
+ if (target->GetProperty(aura::client::kCanResizeKey) &&
+ DispatchHostWindowDragMovement(component, x_root_location)) {
+ event->StopPropagation();
+ }
+ }
+ }
+}
+
+void X11WindowEventFilter::OnClickedCaption(ui::MouseEvent* event,
+ int previous_click_component) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+
+ if (event->IsMiddleMouseButton()) {
+ LinuxUI::NonClientMiddleClickAction action =
+ LinuxUI::MIDDLE_CLICK_ACTION_LOWER;
+ LinuxUI* linux_ui = LinuxUI::instance();
+ if (linux_ui)
+ action = linux_ui->GetNonClientMiddleClickAction();
+
+ switch (action) {
+ case LinuxUI::MIDDLE_CLICK_ACTION_NONE:
+ break;
+ case LinuxUI::MIDDLE_CLICK_ACTION_LOWER:
+ XLowerWindow(xdisplay_, xwindow_);
+ break;
+ case LinuxUI::MIDDLE_CLICK_ACTION_MINIMIZE:
+ window_tree_host_->Minimize();
+ break;
+ case LinuxUI::MIDDLE_CLICK_ACTION_TOGGLE_MAXIMIZE:
+ if (target->GetProperty(aura::client::kCanMaximizeKey))
+ ToggleMaximizedState();
+ break;
+ }
- if (event->flags() & ui::EF_IS_DOUBLE_CLICK && component == HTCAPTION) {
- // Our event is a double click in the caption area. We are responsible for
- // dispatching this as a minimize/maximize on X11 (Windows converts this to
- // min/max events for us).
- if (root_window_host_->IsMaximized())
- root_window_host_->Restore();
- else
- root_window_host_->Maximize();
event->SetHandled();
return;
}
+ if (event->IsLeftMouseButton() && event->flags() & ui::EF_IS_DOUBLE_CLICK) {
+ click_component_ = HTNOWHERE;
+ if (target->GetProperty(aura::client::kCanMaximizeKey) &&
+ previous_click_component == HTCAPTION) {
+ // Our event is a double click in the caption area in a window that can be
+ // maximized. We are responsible for dispatching this as a minimize/
+ // maximize on X11 (Windows converts this to min/max events for us).
+ ToggleMaximizedState();
+ event->SetHandled();
+ return;
+ }
+ }
+
// Get the |x_root_window_| location out of the native event.
- if (event->native_event()) {
+ if (event->IsLeftMouseButton() && event->native_event()) {
const gfx::Point x_root_location =
ui::EventSystemLocationFromNative(event->native_event());
- if (DispatchHostWindowDragMovement(component, x_root_location))
+ if (DispatchHostWindowDragMovement(HTCAPTION, x_root_location))
event->StopPropagation();
}
}
+void X11WindowEventFilter::OnClickedMaximizeButton(ui::MouseEvent* event) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ views::Widget* widget = views::Widget::GetWidgetForNativeView(target);
+ if (!widget)
+ return;
+
+ gfx::Screen* screen = gfx::Screen::GetNativeScreen();
+ gfx::Rect display_work_area =
+ screen->GetDisplayNearestWindow(target).work_area();
+ gfx::Rect bounds = widget->GetWindowBoundsInScreen();
+ if (event->IsMiddleMouseButton()) {
+ bounds.set_y(display_work_area.y());
+ bounds.set_height(display_work_area.height());
+ widget->SetBounds(bounds);
+ event->StopPropagation();
+ } else if (event->IsRightMouseButton()) {
+ bounds.set_x(display_work_area.x());
+ bounds.set_width(display_work_area.width());
+ widget->SetBounds(bounds);
+ event->StopPropagation();
+ }
+}
+
+void X11WindowEventFilter::ToggleMaximizedState() {
+ if (window_tree_host_->IsMaximized())
+ window_tree_host_->Restore();
+ else
+ window_tree_host_->Maximize();
+}
+
bool X11WindowEventFilter::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& screen_location) {
diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h
index d172958cc8f..920733f154f 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.h
@@ -6,8 +6,6 @@
#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WINDOW_EVENT_FILTER_H_
#include <X11/Xlib.h>
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
@@ -17,7 +15,6 @@
#include "ui/views/views_export.h"
namespace aura {
-class RootWindow;
class Window;
}
@@ -26,23 +23,28 @@ class Point;
}
namespace views {
-class DesktopRootWindowHost;
+class DesktopWindowTreeHost;
class NativeWidgetAura;
// An EventFilter that sets properties on X11 windows.
class VIEWS_EXPORT X11WindowEventFilter : public ui::EventHandler {
public:
- X11WindowEventFilter(aura::RootWindow* root_window,
- DesktopRootWindowHost* root_window_host);
+ explicit X11WindowEventFilter(DesktopWindowTreeHost* window_tree_host);
virtual ~X11WindowEventFilter();
- // Changes whether borders are shown on this |root_window|.
- void SetUseHostWindowBorders(bool use_os_border);
-
// Overridden from ui::EventHandler:
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
private:
+ // Called when the user clicked the caption area.
+ void OnClickedCaption(ui::MouseEvent* event,
+ int previous_click_component);
+
+ // Called when the user clicked the maximize button.
+ void OnClickedMaximizeButton(ui::MouseEvent* event);
+
+ void ToggleMaximizedState();
+
// Dispatches a _NET_WM_MOVERESIZE message to the window manager to tell it
// to act as if a border or titlebar drag occurred.
bool DispatchHostWindowDragMovement(int hittest,
@@ -57,11 +59,18 @@ class VIEWS_EXPORT X11WindowEventFilter : public ui::EventHandler {
ui::X11AtomCache atom_cache_;
- DesktopRootWindowHost* root_window_host_;
+ DesktopWindowTreeHost* window_tree_host_;
// True if |xwindow_| is the current _NET_ACTIVE_WINDOW.
bool is_active_;
+ // The non-client component for the target of a MouseEvent. Mouse events can
+ // be destructive to the window tree, which can cause the component of a
+ // ui::EF_IS_DOUBLE_CLICK event to no longer be the same as that of the
+ // initial click. Acting on a double click should only occur for matching
+ // components.
+ int click_component_;
+
DISALLOW_COPY_AND_ASSIGN(X11WindowEventFilter);
};
diff --git a/chromium/ui/views/widget/drop_target_win.cc b/chromium/ui/views/widget/drop_target_win.cc
deleted file mode 100644
index 56b0be1aef1..00000000000
--- a/chromium/ui/views/widget/drop_target_win.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/drop_target_win.h"
-
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-#include "ui/gfx/point.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-
-using ui::OSExchangeData;
-using ui::OSExchangeDataProviderWin;
-
-namespace views {
-
-DropTargetWin::DropTargetWin(internal::RootView* root_view)
- : ui::DropTargetWin(root_view->GetWidget()->GetNativeView()),
- helper_(root_view) {
-}
-
-DropTargetWin::~DropTargetWin() {
-}
-
-void DropTargetWin::ResetTargetViewIfEquals(View* view) {
- helper_.ResetTargetViewIfEquals(view);
-}
-
-DWORD DropTargetWin::OnDragOver(IDataObject* data_object,
- DWORD key_state,
- POINT cursor_position,
- DWORD effect) {
- gfx::Point root_view_location(cursor_position.x, cursor_position.y);
- View::ConvertPointFromScreen(helper_.root_view(), &root_view_location);
- OSExchangeData data(new OSExchangeDataProviderWin(data_object));
- int drop_operation =
- helper_.OnDragOver(data, root_view_location,
- ui::DragDropTypes::DropEffectToDragOperation(effect));
- return ui::DragDropTypes::DragOperationToDropEffect(drop_operation);
-}
-
-void DropTargetWin::OnDragLeave(IDataObject* data_object) {
- helper_.OnDragExit();
-}
-
-DWORD DropTargetWin::OnDrop(IDataObject* data_object,
- DWORD key_state,
- POINT cursor_position,
- DWORD effect) {
- gfx::Point root_view_location(cursor_position.x, cursor_position.y);
- View::ConvertPointFromScreen(helper_.root_view(), &root_view_location);
-
- OSExchangeData data(new OSExchangeDataProviderWin(data_object));
- int drop_operation = ui::DragDropTypes::DropEffectToDragOperation(effect);
- drop_operation = helper_.OnDragOver(data, root_view_location,
- drop_operation);
- drop_operation = helper_.OnDrop(data, root_view_location, drop_operation);
- return ui::DragDropTypes::DragOperationToDropEffect(drop_operation);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/drop_target_win.h b/chromium/ui/views/widget/drop_target_win.h
deleted file mode 100644
index 742675122df..00000000000
--- a/chromium/ui/views/widget/drop_target_win.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DROP_TARGET_WIN_H_
-#define UI_VIEWS_WIDGET_DROP_TARGET_WIN_H_
-
-#include "ui/base/dragdrop/drop_target_win.h"
-#include "ui/views/widget/drop_helper.h"
-
-namespace views {
-
-class View;
-namespace internal {
-class RootView;
-}
-
-// DropTargetWin takes care of managing drag and drop for NativeWidgetWin. It
-// converts Windows OLE drop messages into Views drop messages.
-//
-// DropTargetWin uses DropHelper to manage the appropriate view to target
-// drop messages at.
-class DropTargetWin : public ui::DropTargetWin {
- public:
- explicit DropTargetWin(internal::RootView* root_view);
- virtual ~DropTargetWin();
-
- // If a drag and drop is underway and view is the current drop target, the
- // drop target is set to null.
- // This is invoked when a View is removed from the RootView to make sure
- // we don't target a view that was removed during dnd.
- void ResetTargetViewIfEquals(View* view);
-
- protected:
- virtual DWORD OnDragOver(IDataObject* data_object,
- DWORD key_state,
- POINT cursor_position,
- DWORD effect);
-
- virtual void OnDragLeave(IDataObject* data_object);
-
- virtual DWORD OnDrop(IDataObject* data_object,
- DWORD key_state,
- POINT cursor_position,
- DWORD effect);
-
- private:
- views::DropHelper helper_;
-
- DISALLOW_COPY_AND_ASSIGN(DropTargetWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DROP_TARGET_WIN_H_
diff --git a/chromium/ui/views/widget/monitor_win.cc b/chromium/ui/views/widget/monitor_win.cc
index 1292692d9f3..1220671beb8 100644
--- a/chromium/ui/views/widget/monitor_win.cc
+++ b/chromium/ui/views/widget/monitor_win.cc
@@ -4,10 +4,9 @@
#include "ui/views/widget/monitor_win.h"
-#include <shellapi.h>
+#include <windows.h>
#include "base/logging.h"
-#include "base/win/win_util.h"
#include "ui/gfx/rect.h"
namespace views {
@@ -16,24 +15,12 @@ gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) {
RECT p_rect = rect.ToRECT();
HMONITOR monitor = MonitorFromRect(&p_rect, MONITOR_DEFAULTTONEAREST);
if (monitor) {
- MONITORINFO mi = {0};
- mi.cbSize = sizeof(mi);
- base::win::GetMonitorInfoWrapper(monitor, &mi);
+ MONITORINFO mi = { sizeof(MONITORINFO) };
+ GetMonitorInfo(monitor, &mi);
return gfx::Rect(mi.rcWork);
}
NOTREACHED();
return gfx::Rect();
}
-HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor) {
- // NOTE: this may be invoked on a background thread.
- APPBARDATA taskbar_data = { sizeof(APPBARDATA), NULL, 0, edge };
- HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR,
- &taskbar_data));
- return (::IsWindow(taskbar) && (monitor != NULL) &&
- (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) &&
- (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST)) ?
- taskbar : NULL;
-}
-
} // namespace views
diff --git a/chromium/ui/views/widget/monitor_win.h b/chromium/ui/views/widget/monitor_win.h
index 87bdc4e00c2..ef4d3dde613 100644
--- a/chromium/ui/views/widget/monitor_win.h
+++ b/chromium/ui/views/widget/monitor_win.h
@@ -5,8 +5,6 @@
#ifndef UI_VIEWS_WIDGET_MONITOR_WIN_H_
#define UI_VIEWS_WIDGET_MONITOR_WIN_H_
-#include <windows.h>
-
#include "ui/views/views_export.h"
namespace gfx {
@@ -19,14 +17,6 @@ namespace views {
// intersection with the specified rectangle.
VIEWS_EXPORT gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect);
-// Returns the always-on-top auto-hiding taskbar for edge |edge| (one of
-// ABE_LEFT, TOP, RIGHT, or BOTTOM) of monitor |monitor|. NULL is returned
-// if nothing is found.
-//
-// WARNING: this function spawns a nested message loop. Use Appbar instead if
-// possible.
-VIEWS_EXPORT HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor);
-
} // namespace views
#endif // UI_VIEWS_WIDGET_MONITOR_WIN_H_
diff --git a/chromium/ui/views/widget/native_widget.h b/chromium/ui/views/widget/native_widget.h
index 39255ffc9c1..d01265f81f8 100644
--- a/chromium/ui/views/widget/native_widget.h
+++ b/chromium/ui/views/widget/native_widget.h
@@ -7,10 +7,6 @@
#include "ui/views/widget/widget.h"
-namespace ui {
-class EventHandler;
-}
-
namespace views {
namespace internal {
class NativeWidgetPrivate;
@@ -30,9 +26,6 @@ class VIEWS_EXPORT NativeWidget {
public:
virtual ~NativeWidget() {}
- // Retrieves the event handler
- virtual ui::EventHandler* GetEventHandler() = 0;
-
private:
friend class Widget;
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index ffedac5c15a..150a1a42527 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -7,32 +7,28 @@
#include "base/bind.h"
#include "base/strings/string_util.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/aura/client/activation_client.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/window_move_client.h"
#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/client/window_types.h"
#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/screen.h"
#include "ui/native_theme/native_theme_aura.h"
-#include "ui/views/corewm/window_util.h"
#include "ui/views/drag_utils.h"
#include "ui/views/ime/input_method_bridge.h"
+#include "ui/views/ime/null_input_method.h"
#include "ui/views/views_delegate.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/root_view.h"
@@ -40,20 +36,27 @@
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/window_reorderer.h"
+#include "ui/wm/core/shadow_types.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/drag_drop_client.h"
+#include "ui/wm/public/window_move_client.h"
+#include "ui/wm/public/window_types.h"
#if defined(OS_WIN)
#include "base/win/scoped_gdi_object.h"
#include "base/win/win_util.h"
#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
#endif
#if defined(USE_X11) && !defined(OS_CHROMEOS)
-#include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#endif
#if !defined(OS_CHROMEOS)
-#include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#endif
namespace views {
@@ -74,7 +77,6 @@ NativeWidgetAura::NativeWidgetAura(internal::NativeWidgetDelegate* delegate)
window_(new aura::Window(this)),
ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
close_widget_factory_(this),
- can_activate_(true),
destroying_(false),
cursor_(gfx::kNullCursor),
saved_window_state_(ui::SHOW_STATE_DEFAULT) {
@@ -83,19 +85,6 @@ NativeWidgetAura::NativeWidgetAura(internal::NativeWidgetDelegate* delegate)
}
// static
-gfx::Font NativeWidgetAura::GetWindowTitleFont() {
-#if defined(OS_WIN)
- NONCLIENTMETRICS ncm;
- base::win::GetNonClientMetrics(&ncm);
- l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
- base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
- return gfx::Font(caption_font);
-#else
- return gfx::Font();
-#endif
-}
-
-// static
void NativeWidgetAura::RegisterNativeWidgetForWindow(
internal::NativeWidgetPrivate* native_widget,
aura::Window* window) {
@@ -120,6 +109,10 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
window_->SetTransparent(
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW);
window_->Init(params.layer_type);
+ if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_NONE)
+ SetShadowType(window_, wm::SHADOW_TYPE_NONE);
+ else if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP)
+ SetShadowType(window_, wm::SHADOW_TYPE_RECTANGULAR);
if (params.type == Widget::InitParams::TYPE_CONTROL)
window_->Show();
@@ -131,8 +124,8 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
if (!params.child) {
// Set up the transient child before the window is added. This way the
// LayoutManager knows the window has a transient parent.
- if (parent && parent->type() != aura::client::WINDOW_TYPE_UNKNOWN) {
- parent->AddTransientChild(window_);
+ if (parent && parent->type() != ui::wm::WINDOW_TYPE_UNKNOWN) {
+ wm::AddTransientChild(parent, window_);
if (!context)
context = parent;
parent = NULL;
@@ -150,6 +143,13 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
}
}
+ // Set properties before addeing to the parent so that its layout manager
+ // sees the correct values.
+ window_->SetProperty(aura::client::kCanMaximizeKey,
+ GetWidget()->widget_delegate()->CanMaximize());
+ window_->SetProperty(aura::client::kCanResizeKey,
+ GetWidget()->widget_delegate()->CanResize());
+
if (parent) {
parent->AddChild(window_);
} else {
@@ -165,9 +165,6 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
else
SetBounds(window_bounds);
window_->set_ignore_events(!params.accept_events);
- can_activate_ = params.can_activate &&
- params.type != Widget::InitParams::TYPE_CONTROL &&
- params.type != Widget::InitParams::TYPE_TOOLTIP;
DCHECK(GetWidget()->GetRootView());
if (params.type != Widget::InitParams::TYPE_TOOLTIP)
tooltip_manager_.reset(new views::TooltipManagerAura(GetWidget()));
@@ -180,11 +177,6 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
aura::client::SetActivationDelegate(window_, this);
- window_->SetProperty(aura::client::kCanMaximizeKey,
- GetWidget()->widget_delegate()->CanMaximize());
- window_->SetProperty(aura::client::kCanResizeKey,
- GetWidget()->widget_delegate()->CanResize());
-
window_reorderer_.reset(new WindowReorderer(window_,
GetWidget()->GetRootView()));
}
@@ -198,6 +190,10 @@ bool NativeWidgetAura::ShouldUseNativeFrame() const {
return false;
}
+bool NativeWidgetAura::ShouldWindowContentsBeTransparent() const {
+ return false;
+}
+
void NativeWidgetAura::FrameTypeChanged() {
// This is called when the Theme has changed; forward the event to the root
// widget.
@@ -277,6 +273,10 @@ bool NativeWidgetAura::HasCapture() const {
InputMethod* NativeWidgetAura::CreateInputMethod() {
if (!window_)
return NULL;
+
+ if (switches::IsTextInputFocusManagerEnabled())
+ return new NullInputMethod();
+
aura::Window* root_window = window_->GetRootWindow();
ui::InputMethod* host =
root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
@@ -287,6 +287,11 @@ internal::InputMethodDelegate* NativeWidgetAura::GetInputMethodDelegate() {
return this;
}
+ui::InputMethod* NativeWidgetAura::GetHostInputMethod() {
+ aura::Window* root_window = window_->GetRootWindow();
+ return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+}
+
void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
if (!window_)
return;
@@ -311,9 +316,9 @@ void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
// If |window_|'s transient parent's bounds are big enough to fit it, then we
// center it with respect to the transient parent.
- if (window_->transient_parent()) {
- gfx::Rect transient_parent_rect = window_->transient_parent()->
- GetBoundsInRootWindow();
+ if (wm::GetTransientParent(window_)) {
+ gfx::Rect transient_parent_rect =
+ wm::GetTransientParent(window_)->GetBoundsInRootWindow();
transient_parent_rect.Intersect(work_area);
if (transient_parent_rect.height() >= size.height() &&
transient_parent_rect.width() >= size.width())
@@ -346,7 +351,7 @@ void NativeWidgetAura::GetWindowPlacement(
ui::SHOW_STATE_DEFAULT;
}
-bool NativeWidgetAura::SetWindowTitle(const string16& title) {
+bool NativeWidgetAura::SetWindowTitle(const base::string16& title) {
if (!window_)
return false;
if (window_->title() == title)
@@ -462,7 +467,7 @@ void NativeWidgetAura::CloseNow() {
}
void NativeWidgetAura::Show() {
- ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
+ ShowWithWindowState(ui::SHOW_STATE_NORMAL);
}
void NativeWidgetAura::Hide() {
@@ -483,17 +488,13 @@ void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
window_->SetProperty(aura::client::kShowStateKey, state);
window_->Show();
- if (can_activate_) {
+ if (delegate_->CanActivate()) {
if (state != ui::SHOW_STATE_INACTIVE)
Activate();
// SetInitialFocus() should be always be called, even for
- // SHOW_STATE_INACTIVE. When a frameless modal dialog is created by
- // a widget of TYPE_WINDOW_FRAMELESS, Widget::Show() will call into
- // this function with the window state SHOW_STATE_INACTIVE,
- // SetInitialFoucs() has to be called so that the dialog can get focus.
- // This also matches NativeWidgetWin which invokes SetInitialFocus
- // regardless of show state.
- SetInitialFocus();
+ // SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
+ // do the right thing.
+ SetInitialFocus(state);
}
}
@@ -523,7 +524,7 @@ void NativeWidgetAura::Deactivate() {
}
bool NativeWidgetAura::IsActive() const {
- return window_ && corewm::IsActiveWindow(window_);
+ return window_ && wm::IsActiveWindow(window_);
}
void NativeWidgetAura::SetAlwaysOnTop(bool on_top) {
@@ -535,6 +536,10 @@ bool NativeWidgetAura::IsAlwaysOnTop() const {
return window_ && window_->GetProperty(aura::client::kAlwaysOnTopKey);
}
+void NativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
+ // Not implemented on chromeos or for child widgets.
+}
+
void NativeWidgetAura::Maximize() {
if (window_)
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
@@ -642,27 +647,32 @@ Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop(
Widget::MoveLoopEscapeBehavior escape_behavior) {
// |escape_behavior| is only needed on windows when running the native message
// loop.
- if (window_ && window_->parent() &&
- aura::client::GetWindowMoveClient(window_->parent())) {
- SetCapture();
- aura::client::WindowMoveSource window_move_source =
- source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
- aura::client::WINDOW_MOVE_SOURCE_MOUSE :
- aura::client::WINDOW_MOVE_SOURCE_TOUCH;
- if (aura::client::GetWindowMoveClient(window_->parent())->RunMoveLoop(
- window_, drag_offset, window_move_source) ==
- aura::client::MOVE_SUCCESSFUL) {
- return Widget::MOVE_LOOP_SUCCESSFUL;
- }
+ if (!window_ || !window_->GetRootWindow())
+ return Widget::MOVE_LOOP_CANCELED;
+ aura::client::WindowMoveClient* move_client =
+ aura::client::GetWindowMoveClient(window_->GetRootWindow());
+ if (!move_client)
+ return Widget::MOVE_LOOP_CANCELED;
+
+ SetCapture();
+ aura::client::WindowMoveSource window_move_source =
+ source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE :
+ aura::client::WINDOW_MOVE_SOURCE_TOUCH;
+ if (move_client->RunMoveLoop(window_, drag_offset, window_move_source) ==
+ aura::client::MOVE_SUCCESSFUL) {
+ return Widget::MOVE_LOOP_SUCCESSFUL;
}
return Widget::MOVE_LOOP_CANCELED;
}
void NativeWidgetAura::EndMoveLoop() {
- if (window_ && window_->parent() &&
- aura::client::GetWindowMoveClient(window_->parent())) {
- aura::client::GetWindowMoveClient(window_->parent())->EndMoveLoop();
- }
+ if (!window_ || !window_->GetRootWindow())
+ return;
+ aura::client::WindowMoveClient* move_client =
+ aura::client::GetWindowMoveClient(window_->GetRootWindow());
+ if (move_client)
+ move_client->EndMoveLoop();
}
void NativeWidgetAura::SetVisibilityChangedAnimationsEnabled(bool value) {
@@ -672,7 +682,7 @@ void NativeWidgetAura::SetVisibilityChangedAnimationsEnabled(bool value) {
ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const {
#if !defined(OS_CHROMEOS)
- return DesktopRootWindowHost::GetNativeTheme(window_);
+ return DesktopWindowTreeHost::GetNativeTheme(window_);
#else
return ui::NativeThemeAura::instance();
#endif
@@ -681,6 +691,14 @@ ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const {
void NativeWidgetAura::OnRootViewLayout() const {
}
+bool NativeWidgetAura::IsTranslucentWindowOpacitySupported() const {
+ return true;
+}
+
+void NativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) {
+ OnEvent(native_event);
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, views::InputMethodDelegate implementation:
@@ -700,13 +718,22 @@ gfx::Size NativeWidgetAura::GetMinimumSize() const {
}
gfx::Size NativeWidgetAura::GetMaximumSize() const {
+ // If a window have a maximum size, the window should not be
+ // maximizable.
+ DCHECK(delegate_->GetMaximumSize().IsEmpty() ||
+ !window_->GetProperty(aura::client::kCanMaximizeKey));
return delegate_->GetMaximumSize();
}
void NativeWidgetAura::OnBoundsChanged(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- if (old_bounds.origin() != new_bounds.origin())
+ // Assume that if the old bounds was completely empty a move happened. This
+ // handles the case of a maximize animation acquiring the layer (acquiring a
+ // layer results in clearing the bounds).
+ if (old_bounds.origin() != new_bounds.origin() ||
+ (old_bounds == gfx::Rect(0, 0, 0, 0) && !new_bounds.IsEmpty())) {
delegate_->OnNativeWidgetMove();
+ }
if (old_bounds.size() != new_bounds.size())
delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
}
@@ -755,7 +782,7 @@ bool NativeWidgetAura::ShouldDescendIntoChildForEventHandling(
}
bool NativeWidgetAura::CanFocus() {
- return can_activate_;
+ return ShouldActivate();
}
void NativeWidgetAura::OnCaptureLost() {
@@ -770,14 +797,14 @@ void NativeWidgetAura::OnDeviceScaleFactorChanged(float device_scale_factor) {
// Repainting with new scale factor will paint the content at the right scale.
}
-void NativeWidgetAura::OnWindowDestroying() {
+void NativeWidgetAura::OnWindowDestroying(aura::Window* window) {
delegate_->OnNativeWidgetDestroying();
// If the aura::Window is destroyed, we can no longer show tooltips.
tooltip_manager_.reset();
}
-void NativeWidgetAura::OnWindowDestroyed() {
+void NativeWidgetAura::OnWindowDestroyed(aura::Window* window) {
window_ = NULL;
delegate_->OnNativeWidgetDestroyed();
if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
@@ -797,10 +824,6 @@ void NativeWidgetAura::GetHitTestMask(gfx::Path* mask) const {
delegate_->GetHitTestMask(mask);
}
-void NativeWidgetAura::DidRecreateLayer(ui::Layer *old_layer,
- ui::Layer *new_layer) {
-}
-
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, ui::EventHandler implementation:
@@ -818,6 +841,12 @@ void NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) {
if (!window_->IsVisible())
return;
GetWidget()->GetInputMethod()->DispatchKeyEvent(*event);
+ if (switches::IsTextInputFocusManagerEnabled()) {
+ FocusManager* focus_manager = GetWidget()->GetFocusManager();
+ delegate_->OnKeyEvent(event);
+ if (!event->handled() && focus_manager)
+ focus_manager->OnKeyEvent(*event);
+ }
event->SetHandled();
}
@@ -840,12 +869,6 @@ void NativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) {
delegate_->OnScrollEvent(event);
}
-void NativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) {
- DCHECK(window_);
- DCHECK(window_->IsVisible() || event->IsEndingEvent());
- delegate_->OnTouchEvent(event);
-}
-
void NativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
DCHECK(window_);
DCHECK(window_->IsVisible() || event->IsEndingEvent());
@@ -856,7 +879,7 @@ void NativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
// NativeWidgetAura, aura::client::ActivationDelegate implementation:
bool NativeWidgetAura::ShouldActivate() const {
- return can_activate_ && delegate_->CanActivate();
+ return delegate_->CanActivate();
}
////////////////////////////////////////////////////////////////////////////////
@@ -872,8 +895,6 @@ void NativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
GetWidget()->GetFocusManager()->StoreFocusedView(true);
}
delegate_->OnNativeWidgetActivationChanged(window_ == gained_active);
- if (IsVisible() && GetWidget()->non_client_view())
- GetWidget()->non_client_view()->SchedulePaint();
}
////////////////////////////////////////////////////////////////////////////////
@@ -902,9 +923,7 @@ void NativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
DCHECK_EQ(ownership_, Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
}
- aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
- if (client) // NULL during destruction of aura::Window.
- delegate_->OnNativeBlur(client->GetFocusedWindow());
+ delegate_->OnNativeBlur(gained_focus);
}
}
@@ -936,13 +955,6 @@ int NativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
}
////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetAura, NativeWidget implementation:
-
-ui::EventHandler* NativeWidgetAura::GetEventHandler() {
- return this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, protected:
NativeWidgetAura::~NativeWidgetAura() {
@@ -956,20 +968,15 @@ NativeWidgetAura::~NativeWidgetAura() {
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, private:
-void NativeWidgetAura::SetInitialFocus() {
+void NativeWidgetAura::SetInitialFocus(ui::WindowShowState show_state) {
// The window does not get keyboard messages unless we focus it.
- if (!GetWidget()->SetInitialFocus())
+ if (!GetWidget()->SetInitialFocus(show_state))
window_->Focus();
}
////////////////////////////////////////////////////////////////////////////////
// Widget, public:
-// static
-void Widget::NotifyLocaleChanged() {
- // Deliberately not implemented.
-}
-
namespace {
#if defined(OS_WIN) || (defined(USE_X11) && !defined(OS_CHROMEOS))
void CloseWindow(aura::Window* window) {
@@ -988,7 +995,7 @@ void CloseWindow(aura::Window* window) {
#if defined(OS_WIN)
BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
aura::Window* root_window =
- DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd);
+ DesktopWindowTreeHostWin::GetContentWindowForHWND(hwnd);
CloseWindow(root_window);
return TRUE;
}
@@ -1003,9 +1010,9 @@ void Widget::CloseAllSecondaryWidgets() {
#if defined(USE_X11) && !defined(OS_CHROMEOS)
std::vector<aura::Window*> open_windows =
- DesktopRootWindowHostX11::GetAllOpenWindows();
+ DesktopWindowTreeHostX11::GetAllOpenWindows();
std::for_each(open_windows.begin(), open_windows.end(), CloseWindow);
- DesktopRootWindowHostX11::CleanUpWindowList();
+ DesktopWindowTreeHostX11::CleanUpWindowList();
#endif
}
@@ -1076,7 +1083,7 @@ void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
Widget::Widgets* owned) {
const aura::Window::Windows& transient_children =
- native_view->transient_children();
+ wm::GetTransientChildren(native_view);
for (aura::Window::Windows::const_iterator i = transient_children.begin();
i != transient_children.end(); ++i) {
NativeWidgetPrivate* native_widget = static_cast<NativeWidgetPrivate*>(
@@ -1142,5 +1149,18 @@ bool NativeWidgetPrivate::IsTouchDown() {
return aura::Env::GetInstance()->is_touch_down();
}
+// static
+gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
+#if defined(OS_WIN)
+ NONCLIENTMETRICS ncm;
+ base::win::GetNonClientMetrics(&ncm);
+ l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
+ base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
+ return gfx::FontList(gfx::Font(caption_font));
+#else
+ return gfx::FontList();
+#endif
+}
+
} // namespace internal
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index c79c003f995..dd6fafe8381 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -7,9 +7,6 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/window_delegate.h"
#include "ui/base/cursor/cursor.h"
@@ -17,12 +14,15 @@
#include "ui/views/ime/input_method_delegate.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/native_widget_private.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_delegate.h"
+#include "ui/wm/public/drag_drop_delegate.h"
namespace aura {
class Window;
}
namespace gfx {
-class Font;
+class FontList;
}
namespace views {
@@ -42,10 +42,6 @@ class VIEWS_EXPORT NativeWidgetAura
public:
explicit NativeWidgetAura(internal::NativeWidgetDelegate* delegate);
- // TODO(beng): Find a better place for this, and the similar method on
- // NativeWidgetWin.
- static gfx::Font GetWindowTitleFont();
-
// Called internally by NativeWidgetAura and DesktopNativeWidgetAura to
// associate |native_widget| with |window|.
static void RegisterNativeWidgetForWindow(
@@ -56,6 +52,7 @@ class VIEWS_EXPORT NativeWidgetAura
virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual bool ShouldWindowContentsBeTransparent() const OVERRIDE;
virtual void FrameTypeChanged() OVERRIDE;
virtual Widget* GetWidget() OVERRIDE;
virtual const Widget* GetWidget() const OVERRIDE;
@@ -75,11 +72,12 @@ class VIEWS_EXPORT NativeWidgetAura
virtual bool HasCapture() const OVERRIDE;
virtual InputMethod* CreateInputMethod() OVERRIDE;
virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual ui::InputMethod* GetHostInputMethod() OVERRIDE;
virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
virtual void GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* maximized) const OVERRIDE;
- virtual bool SetWindowTitle(const string16& title) OVERRIDE;
+ virtual bool SetWindowTitle(const base::string16& title) OVERRIDE;
virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) OVERRIDE;
virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
@@ -105,6 +103,7 @@ class VIEWS_EXPORT NativeWidgetAura
virtual bool IsActive() const OVERRIDE;
virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
virtual bool IsAlwaysOnTop() const OVERRIDE;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
virtual bool IsMaximized() const OVERRIDE;
@@ -133,6 +132,8 @@ class VIEWS_EXPORT NativeWidgetAura
virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
virtual void OnRootViewLayout() const OVERRIDE;
+ virtual bool IsTranslucentWindowOpacitySupported() const OVERRIDE;
+ virtual void RepostNativeEvent(gfx::NativeEvent native_event) OVERRIDE;
// Overridden from views::InputMethodDelegate:
virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE;
@@ -151,19 +152,16 @@ class VIEWS_EXPORT NativeWidgetAura
virtual void OnCaptureLost() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void OnWindowDestroying() OVERRIDE;
- virtual void OnWindowDestroyed() OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
virtual bool HasHitTestMask() const OVERRIDE;
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
- virtual void DidRecreateLayer(ui::Layer* old_layer,
- ui::Layer* new_layer) OVERRIDE;
// Overridden from ui::EventHandler:
virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
// Overridden from aura::client::ActivationDelegate:
@@ -183,9 +181,6 @@ class VIEWS_EXPORT NativeWidgetAura
virtual void OnDragExited() OVERRIDE;
virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
- // Overridden from NativeWidget:
- virtual ui::EventHandler* GetEventHandler() OVERRIDE;
-
protected:
virtual ~NativeWidgetAura();
@@ -194,7 +189,7 @@ class VIEWS_EXPORT NativeWidgetAura
private:
class ActiveWindowObserver;
- void SetInitialFocus();
+ void SetInitialFocus(ui::WindowShowState show_state);
internal::NativeWidgetDelegate* delegate_;
@@ -210,9 +205,6 @@ class VIEWS_EXPORT NativeWidgetAura
// instance.
base::WeakPtrFactory<NativeWidgetAura> close_widget_factory_;
- // Can we be made active?
- bool can_activate_;
-
// Are we in the destructor?
bool destroying_;
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index f0f34c76cbd..3c6d3cc49ad 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -12,14 +12,16 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_helper.h"
+#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
#include "ui/gfx/screen.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/wm/core/default_activation_client.h"
namespace views {
namespace {
@@ -32,40 +34,29 @@ NativeWidgetAura* Init(aura::Window* parent, Widget* widget) {
return static_cast<NativeWidgetAura*>(widget->native_widget());
}
-class NativeWidgetAuraTest : public testing::Test {
+class NativeWidgetAuraTest : public aura::test::AuraTestBase {
public:
NativeWidgetAuraTest() {}
virtual ~NativeWidgetAuraTest() {}
// testing::Test overrides:
virtual void SetUp() OVERRIDE {
- aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
- aura_test_helper_->SetUp();
- root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
- dispatcher()->SetHostSize(gfx::Size(640, 480));
+ AuraTestBase::SetUp();
+ new wm::DefaultActivationClient(root_window());
+ host()->SetBounds(gfx::Rect(640, 480));
}
- virtual void TearDown() OVERRIDE {
- message_loop_.RunUntilIdle();
- aura_test_helper_->TearDown();
- }
-
- protected:
- aura::Window* root_window() { return aura_test_helper_->root_window(); }
- aura::RootWindow* dispatcher() { return aura_test_helper_->dispatcher(); }
private:
- base::MessageLoopForUI message_loop_;
- scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
-
DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest);
};
TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
- // Make a parent window larger than the host represented by rootwindow.
+ // Make a parent window larger than the host represented by
+ // WindowEventDispatcher.
scoped_ptr<aura::Window> parent(new aura::Window(NULL));
- parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->SetBounds(gfx::Rect(0, 0, 1024, 800));
- scoped_ptr<Widget> widget(new Widget());
+ scoped_ptr<Widget> widget(new Widget());
NativeWidgetAura* window = Init(parent.get(), widget.get());
window->CenterWindow(gfx::Size(100, 100));
@@ -77,9 +68,10 @@ TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
}
TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) {
- // Make a parent window smaller than the host represented by rootwindow.
+ // Make a parent window smaller than the host represented by
+ // WindowEventDispatcher.
scoped_ptr<aura::Window> parent(new aura::Window(NULL));
- parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->SetBounds(gfx::Rect(0, 0, 480, 320));
scoped_ptr<Widget> widget(new Widget());
NativeWidgetAura* window = Init(parent.get(), widget.get());
@@ -94,10 +86,10 @@ TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) {
// Verifies CenterWindow() constrains to parent size.
TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
- // Make a parent window smaller than the host represented by rootwindow and
- // offset it slightly from the origin.
+ // Make a parent window smaller than the host represented by
+ // WindowEventDispatcher and offset it slightly from the origin.
scoped_ptr<aura::Window> parent(new aura::Window(NULL));
- parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->SetBounds(gfx::Rect(20, 40, 480, 320));
scoped_ptr<Widget> widget(new Widget());
NativeWidgetAura* window = Init(parent.get(), widget.get());
@@ -108,30 +100,39 @@ TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
widget->CloseNow();
}
+class TestLayoutManagerBase : public aura::LayoutManager {
+ public:
+ TestLayoutManagerBase() {}
+ virtual ~TestLayoutManagerBase() {}
+
+ // aura::LayoutManager:
+ virtual void OnWindowResized() OVERRIDE {}
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
+ virtual void OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) OVERRIDE {}
+ virtual void SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestLayoutManagerBase);
+};
+
// Used by ShowMaximizedDoesntBounceAround. See it for details.
-class TestLayoutManager : public aura::LayoutManager {
+class MaximizeLayoutManager : public TestLayoutManagerBase {
public:
- TestLayoutManager() {}
+ MaximizeLayoutManager() {}
+ virtual ~MaximizeLayoutManager() {}
- virtual void OnWindowResized() OVERRIDE {
- }
+ private:
+ // aura::LayoutManager:
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
// This simulates what happens when adding a maximized window.
SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300));
}
- virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
- }
- virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
- }
- virtual void OnChildWindowVisibilityChanged(aura::Window* child,
- bool visible) OVERRIDE {
- }
- virtual void SetChildBounds(aura::Window* child,
- const gfx::Rect& requested_bounds) OVERRIDE {
- }
- private:
- DISALLOW_COPY_AND_ASSIGN(TestLayoutManager);
+ DISALLOW_COPY_AND_ASSIGN(MaximizeLayoutManager);
};
// This simulates BrowserView, which creates a custom RootView so that
@@ -168,7 +169,7 @@ class TestWidget : public views::Widget {
// leads to noticable flashes.
TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
- root_window()->SetLayoutManager(new TestLayoutManager);
+ root_window()->SetLayoutManager(new MaximizeLayoutManager);
scoped_ptr<TestWidget> widget(new TestWidget());
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
@@ -181,6 +182,70 @@ TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
widget->CloseNow();
}
+class PropertyTestLayoutManager : public TestLayoutManagerBase {
+ public:
+ PropertyTestLayoutManager() : added_(false) {}
+ virtual ~PropertyTestLayoutManager() {}
+
+ bool added() const { return added_; }
+
+ private:
+ // aura::LayoutManager:
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
+ EXPECT_TRUE(child->GetProperty(aura::client::kCanMaximizeKey));
+ EXPECT_TRUE(child->GetProperty(aura::client::kCanResizeKey));
+ added_ = true;
+ }
+
+ bool added_;
+
+ DISALLOW_COPY_AND_ASSIGN(PropertyTestLayoutManager);
+};
+
+class PropertyTestWidgetDelegate : public views::WidgetDelegate {
+ public:
+ explicit PropertyTestWidgetDelegate(Widget* widget) : widget_(widget) {}
+ virtual ~PropertyTestWidgetDelegate() {}
+
+ private:
+ // views::WidgetDelegate:
+ virtual bool CanMaximize() const OVERRIDE {
+ return true;
+ }
+ virtual bool CanResize() const OVERRIDE {
+ return true;
+ }
+ virtual void DeleteDelegate() OVERRIDE {
+ delete this;
+ }
+ virtual Widget* GetWidget() OVERRIDE {
+ return widget_;
+ }
+ virtual const Widget* GetWidget() const OVERRIDE {
+ return widget_;
+ }
+
+ Widget* widget_;
+ DISALLOW_COPY_AND_ASSIGN(PropertyTestWidgetDelegate);
+};
+
+// Verifies that the kCanMaximizeKey/kCanReizeKey have the correct
+// value when added to the layout manager.
+TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) {
+ root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
+ PropertyTestLayoutManager* layout_manager = new PropertyTestLayoutManager();
+ root_window()->SetLayoutManager(layout_manager);
+ scoped_ptr<TestWidget> widget(new TestWidget());
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.delegate = new PropertyTestWidgetDelegate(widget.get());
+ params.parent = NULL;
+ params.context = root_window();
+ widget->Init(params);
+ EXPECT_TRUE(layout_manager->added());
+ widget->CloseNow();
+}
+
TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
// Create a widget.
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
@@ -198,8 +263,6 @@ TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
EXPECT_EQ(400, client_bounds.height());
}
-namespace {
-
// View subclass that tracks whether it has gotten a gesture event.
class GestureTrackingView : public views::View {
public:
@@ -235,8 +298,6 @@ class GestureTrackingView : public views::View {
DISALLOW_COPY_AND_ASSIGN(GestureTrackingView);
};
-} // namespace
-
// Verifies a capture isn't set on touch press and that the view that gets
// the press gets the release.
TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
@@ -256,9 +317,11 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
widget->SetContentsView(view);
widget->Show();
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
- base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1, ui::EventTimeForNow());
+ ui::EventDispatchDetails details =
+ event_processor()->OnEventFromSource(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
// Both views should get the press.
EXPECT_TRUE(view->got_gesture_event());
EXPECT_TRUE(child->got_gesture_event());
@@ -269,9 +332,10 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
// Release touch. Only |view| should get the release since that it consumed
// the press.
- ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1,
- base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
+ ui::TouchEvent release(
+ ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1, ui::EventTimeForNow());
+ details = event_processor()->OnEventFromSource(&release);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(view->got_gesture_event());
EXPECT_FALSE(child->got_gesture_event());
view->clear_got_gesture_event();
@@ -281,39 +345,6 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
widget->Close();
}
-TEST_F(NativeWidgetAuraTest, ReleaseCaptureOnTouchRelease) {
- GestureTrackingView* view = new GestureTrackingView();
- scoped_ptr<TestWidget> widget(new TestWidget());
- Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.context = root_window();
- params.bounds = gfx::Rect(0, 0, 100, 200);
- widget->Init(params);
- widget->SetContentsView(view);
- widget->Show();
-
- ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
- base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
- EXPECT_TRUE(view->got_gesture_event());
- view->clear_got_gesture_event();
- // Set the capture.
- widget->SetCapture(view);
- EXPECT_TRUE(widget->HasCapture());
-
- // Generate a release, this should trigger releasing capture.
- ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(41, 51), 1,
- base::TimeDelta());
- dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
- EXPECT_TRUE(view->got_gesture_event());
- view->clear_got_gesture_event();
- EXPECT_FALSE(widget->HasCapture());
-
- // Work around for bug in NativeWidgetAura.
- // TODO: fix bug and remove this.
- widget->Close();
-}
-
// Verifies views with layers are targeted for events properly.
TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
// Create two widgets: |parent| and |child|. |child| is a child of |parent|.
@@ -399,15 +430,53 @@ TEST_F(NativeWidgetAuraTest, FlashFrame) {
TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) {
scoped_ptr<aura::Window> parent(new aura::Window(NULL));
- parent->Init(ui::LAYER_NOT_DRAWN);
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
parent->SetBounds(gfx::Rect(0, 0, 480, 320));
scoped_ptr<Widget> widget(new Widget());
- NativeWidgetAura* window = Init(parent.get(), widget.get());
- window->Show();
- window->Close();
+ Init(parent.get(), widget.get());
+ widget->Show();
+ widget->Close();
base::MessageLoop::current()->RunUntilIdle();
widget->GetNativeTheme(); // Shouldn't crash.
}
+// Used to track calls to WidgetDelegate::OnWidgetMove().
+class MoveTestWidgetDelegate : public WidgetDelegateView {
+ public:
+ MoveTestWidgetDelegate() : got_move_(false) {}
+ virtual ~MoveTestWidgetDelegate() {}
+
+ void ClearGotMove() { got_move_ = false; }
+ bool got_move() const { return got_move_; }
+
+ // WidgetDelegate overrides:
+ virtual void OnWidgetMove() OVERRIDE { got_move_ = true; }
+
+ private:
+ bool got_move_;
+
+ DISALLOW_COPY_AND_ASSIGN(MoveTestWidgetDelegate);
+};
+
+// This test simulates what happens when a window is normally maximized. That
+// is, it's layer is acquired for animation then the window is maximized.
+// Acquiring the layer resets the bounds of the window. This test verifies the
+// Widget is still notified correctly of a move in this case.
+TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) {
+ // |delegate| deletes itself when the widget is destroyed.
+ MoveTestWidgetDelegate* delegate = new MoveTestWidgetDelegate;
+ Widget* widget =
+ Widget::CreateWindowWithContextAndBounds(delegate,
+ root_window(),
+ gfx::Rect(10, 10, 100, 200));
+ widget->Show();
+ delegate->ClearGotMove();
+ // Simulate a maximize with animation.
+ delete widget->GetNativeView()->RecreateLayer().release();
+ widget->SetBounds(gfx::Rect(0, 0, 500, 500));
+ EXPECT_TRUE(delegate->got_move());
+ widget->CloseNow();
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h
index 914b575f30d..c18b5fc8015 100644
--- a/chromium/ui/views/widget/native_widget_delegate.h
+++ b/chromium/ui/views/widget/native_widget_delegate.h
@@ -80,10 +80,10 @@ class VIEWS_EXPORT NativeWidgetDelegate {
virtual void OnNativeWidgetDestroyed() = 0;
// Returns the smallest size the window can be resized to by the user.
- virtual gfx::Size GetMinimumSize() = 0;
+ virtual gfx::Size GetMinimumSize() const = 0;
// Returns the largest size the window can be resized to by the user.
- virtual gfx::Size GetMaximumSize() = 0;
+ virtual gfx::Size GetMaximumSize() const = 0;
// Called when the NativeWidget changed position.
virtual void OnNativeWidgetMove() = 0;
@@ -116,7 +116,6 @@ class VIEWS_EXPORT NativeWidgetDelegate {
virtual void OnMouseEvent(ui::MouseEvent* event) = 0;
virtual void OnMouseCaptureLost() = 0;
- virtual void OnTouchEvent(ui::TouchEvent* event) = 0;
virtual void OnScrollEvent(ui::ScrollEvent* event) = 0;
virtual void OnGestureEvent(ui::GestureEvent* event) = 0;
@@ -140,6 +139,14 @@ class VIEWS_EXPORT NativeWidgetDelegate {
//
virtual Widget* AsWidget() = 0;
virtual const Widget* AsWidget() const = 0;
+
+ // Sets-up the focus manager with the view that should have focus when the
+ // window is shown the first time. It takes the intended |show_state| of the
+ // window in order to decide whether the window should be focused now or
+ // later. Returns true if the initial focus has been set or the window should
+ // not set the initial focus, or false if the caller should set the initial
+ // focus (if any).
+ virtual bool SetInitialFocus(ui::WindowShowState show_state) = 0;
};
} // namespace internal
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
new file mode 100644
index 00000000000..64cb9a3bea8
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -0,0 +1,117 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
+#define UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/widget/native_widget_private.h"
+
+namespace views {
+
+class BridgedNativeWidget;
+
+class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
+ public:
+ NativeWidgetMac(internal::NativeWidgetDelegate* delegate);
+ virtual ~NativeWidgetMac();
+
+ protected:
+ // internal::NativeWidgetPrivate:
+ virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
+ virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
+ virtual bool ShouldUseNativeFrame() const OVERRIDE;
+ virtual bool ShouldWindowContentsBeTransparent() const OVERRIDE;
+ virtual void FrameTypeChanged() OVERRIDE;
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
+ virtual Widget* GetTopLevelWidget() OVERRIDE;
+ virtual const ui::Compositor* GetCompositor() const OVERRIDE;
+ virtual ui::Compositor* GetCompositor() OVERRIDE;
+ virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
+ virtual void ViewRemoved(View* view) OVERRIDE;
+ virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
+ virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
+ virtual TooltipManager* GetTooltipManager() const OVERRIDE;
+ virtual void SetCapture() OVERRIDE;
+ virtual void ReleaseCapture() OVERRIDE;
+ virtual bool HasCapture() const OVERRIDE;
+ virtual InputMethod* CreateInputMethod() OVERRIDE;
+ virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
+ virtual ui::InputMethod* GetHostInputMethod() OVERRIDE;
+ virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
+ virtual void GetWindowPlacement(
+ gfx::Rect* bounds,
+ ui::WindowShowState* maximized) const OVERRIDE;
+ virtual bool SetWindowTitle(const base::string16& title) OVERRIDE;
+ virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) OVERRIDE;
+ virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
+ virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+ virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void StackAbove(gfx::NativeView native_view) OVERRIDE;
+ virtual void StackAtTop() OVERRIDE;
+ virtual void StackBelow(gfx::NativeView native_view) OVERRIDE;
+ virtual void SetShape(gfx::NativeRegion shape) OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void CloseNow() OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Hide() OVERRIDE;
+ virtual void ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) OVERRIDE;
+ virtual void ShowWithWindowState(ui::WindowShowState state) OVERRIDE;
+ virtual bool IsVisible() const OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Deactivate() OVERRIDE;
+ virtual bool IsActive() const OVERRIDE;
+ virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
+ virtual bool IsAlwaysOnTop() const OVERRIDE;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
+ virtual void Maximize() OVERRIDE;
+ virtual void Minimize() OVERRIDE;
+ virtual bool IsMaximized() const OVERRIDE;
+ virtual bool IsMinimized() const OVERRIDE;
+ virtual void Restore() OVERRIDE;
+ virtual void SetFullscreen(bool fullscreen) OVERRIDE;
+ virtual bool IsFullscreen() const OVERRIDE;
+ virtual void SetOpacity(unsigned char opacity) OVERRIDE;
+ virtual void SetUseDragFrame(bool use_drag_frame) OVERRIDE;
+ virtual void FlashFrame(bool flash_frame) OVERRIDE;
+ virtual void RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) OVERRIDE;
+ virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual bool IsMouseEventsEnabled() const OVERRIDE;
+ virtual void ClearNativeFocus() OVERRIDE;
+ virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
+ virtual Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
+ virtual void EndMoveLoop() OVERRIDE;
+ virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
+ virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
+ virtual void OnRootViewLayout() const OVERRIDE;
+ virtual bool IsTranslucentWindowOpacitySupported() const OVERRIDE;
+ virtual void RepostNativeEvent(gfx::NativeEvent native_event) OVERRIDE;
+
+ private:
+ internal::NativeWidgetDelegate* delegate_;
+ scoped_ptr<BridgedNativeWidget> bridge_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
new file mode 100644
index 00000000000..37545b974cf
--- /dev/null
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -0,0 +1,448 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/native_widget_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/gfx/font_list.h"
+#include "ui/native_theme/native_theme.h"
+#import "ui/views/cocoa/bridged_content_view.h"
+#import "ui/views/cocoa/bridged_native_widget.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetMac, public:
+
+NativeWidgetMac::NativeWidgetMac(internal::NativeWidgetDelegate* delegate)
+ : delegate_(delegate), bridge_(new BridgedNativeWidget) {
+}
+
+NativeWidgetMac::~NativeWidgetMac() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetMac, internal::NativeWidgetPrivate implementation:
+
+void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
+ // TODO(tapted): Convert position into Cocoa's flipped coordinate space.
+ NSRect content_rect =
+ NSMakeRect(0, 0, params.bounds.width(), params.bounds.height());
+ // TODO(tapted): Determine a good initial style mask from |params|.
+ NSInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask;
+ base::scoped_nsobject<NSWindow> window(
+ [[NSWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ bridge_->Init(window);
+}
+
+NonClientFrameView* NativeWidgetMac::CreateNonClientFrameView() {
+ return NULL;
+}
+
+bool NativeWidgetMac::ShouldUseNativeFrame() const {
+ return false;
+}
+
+bool NativeWidgetMac::ShouldWindowContentsBeTransparent() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeWidgetMac::FrameTypeChanged() {
+ NOTIMPLEMENTED();
+}
+
+Widget* NativeWidgetMac::GetWidget() {
+ return delegate_->AsWidget();
+}
+
+const Widget* NativeWidgetMac::GetWidget() const {
+ return delegate_->AsWidget();
+}
+
+gfx::NativeView NativeWidgetMac::GetNativeView() const {
+ return bridge_->ns_view();
+}
+
+gfx::NativeWindow NativeWidgetMac::GetNativeWindow() const {
+ return bridge_->ns_window();
+}
+
+Widget* NativeWidgetMac::GetTopLevelWidget() {
+ NOTIMPLEMENTED();
+ return GetWidget();
+}
+
+const ui::Compositor* NativeWidgetMac::GetCompositor() const {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+ui::Compositor* NativeWidgetMac::GetCompositor() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+ui::Layer* NativeWidgetMac::GetLayer() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void NativeWidgetMac::ReorderNativeViews() {
+ bridge_->SetRootView(GetWidget()->GetRootView());
+}
+
+void NativeWidgetMac::ViewRemoved(View* view) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetNativeWindowProperty(const char* name, void* value) {
+ NOTIMPLEMENTED();
+}
+
+void* NativeWidgetMac::GetNativeWindowProperty(const char* name) const {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+TooltipManager* NativeWidgetMac::GetTooltipManager() const {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void NativeWidgetMac::SetCapture() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::ReleaseCapture() {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::HasCapture() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+InputMethod* NativeWidgetMac::CreateInputMethod() {
+ return bridge_->CreateInputMethod();
+}
+
+internal::InputMethodDelegate* NativeWidgetMac::GetInputMethodDelegate() {
+ return bridge_.get();
+}
+
+ui::InputMethod* NativeWidgetMac::GetHostInputMethod() {
+ return bridge_->GetHostInputMethod();
+}
+
+void NativeWidgetMac::CenterWindow(const gfx::Size& size) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* maximized) const {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::SetWindowTitle(const base::string16& title) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeWidgetMac::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::InitModalType(ui::ModalType modal_type) {
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect NativeWidgetMac::GetWindowBoundsInScreen() const {
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
+gfx::Rect NativeWidgetMac::GetClientAreaBoundsInScreen() const {
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
+gfx::Rect NativeWidgetMac::GetRestoredBounds() const {
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
+void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetSize(const gfx::Size& size) {
+ [bridge_->ns_window() setContentSize:NSMakeSize(size.width(), size.height())];
+}
+
+void NativeWidgetMac::StackAbove(gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::StackAtTop() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::StackBelow(gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetShape(gfx::NativeRegion shape) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Close() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::CloseNow() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Show() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Hide() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::ShowMaximizedWithBounds(
+ const gfx::Rect& restored_bounds) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::ShowWithWindowState(ui::WindowShowState state) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsVisible() const {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+void NativeWidgetMac::Activate() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Deactivate() {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsActive() const {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+void NativeWidgetMac::SetAlwaysOnTop(bool always_on_top) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsAlwaysOnTop() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeWidgetMac::SetVisibleOnAllWorkspaces(bool always_visible) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Maximize() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::Minimize() {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsMaximized() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool NativeWidgetMac::IsMinimized() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeWidgetMac::Restore() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetFullscreen(bool fullscreen) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsFullscreen() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void NativeWidgetMac::SetOpacity(unsigned char opacity) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetUseDragFrame(bool use_drag_frame) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::FlashFrame(bool flash_frame) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
+ // TODO(tapted): This should use setNeedsDisplayInRect:, once the coordinate
+ // system of |rect| has been converted.
+ [bridge_->ns_view() setNeedsDisplay:YES];
+}
+
+void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsMouseEventsEnabled() const {
+ NOTIMPLEMENTED();
+ return true;
+}
+
+void NativeWidgetMac::ClearNativeFocus() {
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect NativeWidgetMac::GetWorkAreaBoundsInScreen() const {
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
+Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) {
+ NOTIMPLEMENTED();
+ return Widget::MOVE_LOOP_CANCELED;
+}
+
+void NativeWidgetMac::EndMoveLoop() {
+ NOTIMPLEMENTED();
+}
+
+void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {
+ NOTIMPLEMENTED();
+}
+
+ui::NativeTheme* NativeWidgetMac::GetNativeTheme() const {
+ return ui::NativeTheme::instance();
+}
+
+void NativeWidgetMac::OnRootViewLayout() const {
+ NOTIMPLEMENTED();
+}
+
+bool NativeWidgetMac::IsTranslucentWindowOpacitySupported() const {
+ return false;
+}
+
+void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) {
+ NOTIMPLEMENTED();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+bool Widget::ConvertRect(const Widget* source,
+ const Widget* target,
+ gfx::Rect* rect) {
+ return false;
+}
+
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// internal::NativeWidgetPrivate, public:
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
+ internal::NativeWidgetDelegate* delegate) {
+ return new NativeWidgetMac(delegate);
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
+ gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
+ gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
+ Widget::Widgets* children) {
+ NOTIMPLEMENTED();
+}
+
+// static
+void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
+ Widget::Widgets* owned) {
+ NOTIMPLEMENTED();
+}
+
+// static
+void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
+ gfx::NativeView new_parent) {
+ NOTIMPLEMENTED();
+}
+
+// static
+bool NativeWidgetPrivate::IsMouseButtonDown() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+// static
+bool NativeWidgetPrivate::IsTouchDown() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+// static
+gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
+ NOTIMPLEMENTED();
+ return gfx::FontList();
+}
+
+} // namespace internal
+} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h
index 2cee9533a6b..8c9233a3ff8 100644
--- a/chromium/ui/views/widget/native_widget_private.h
+++ b/chromium/ui/views/widget/native_widget_private.h
@@ -8,15 +8,16 @@
#include "base/strings/string16.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/views/ime/input_method_delegate.h"
#include "ui/views/widget/native_widget.h"
namespace gfx {
+class FontList;
class ImageSkia;
class Rect;
}
namespace ui {
+class InputMethod;
class NativeTheme;
class OSExchangeData;
}
@@ -25,6 +26,7 @@ namespace views {
class InputMethod;
class TooltipManager;
namespace internal {
+class InputMethodDelegate;
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetPrivate interface
@@ -72,6 +74,8 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
// Returns true if any touch device is currently down.
static bool IsTouchDown();
+ static gfx::FontList GetWindowTitleFontList();
+
// Initializes the NativeWidget.
virtual void InitNativeWidget(const Widget::InitParams& params) = 0;
@@ -80,6 +84,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual NonClientFrameView* CreateNonClientFrameView() = 0;
virtual bool ShouldUseNativeFrame() const = 0;
+ virtual bool ShouldWindowContentsBeTransparent() const = 0;
virtual void FrameTypeChanged() = 0;
// Returns the Widget associated with this NativeWidget. This function is
@@ -141,6 +146,10 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
// Returns the InputMethodDelegate for this native widget.
virtual InputMethodDelegate* GetInputMethodDelegate() = 0;
+ // Returns the ui::InputMethod for this native widget.
+ // TODO(yukishiino): Rename this method to GetInputMethod once we remove
+ // views::InputMethod.
+ virtual ui::InputMethod* GetHostInputMethod() = 0;
// Centers the window and sizes it to the specified size.
virtual void CenterWindow(const gfx::Size& size) = 0;
@@ -152,7 +161,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
ui::WindowShowState* show_state) const = 0;
// Sets the NativeWindow title. Returns true if the title changed.
- virtual bool SetWindowTitle(const string16& title) = 0;
+ virtual bool SetWindowTitle(const base::string16& title) = 0;
// Sets the Window icons. |window_icon| is a 16x16 icon suitable for use in
// a title bar. |app_icon| is a larger size for use in the host environment
@@ -189,6 +198,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual bool IsActive() const = 0;
virtual void SetAlwaysOnTop(bool always_on_top) = 0;
virtual bool IsAlwaysOnTop() const = 0;
+ virtual void SetVisibleOnAllWorkspaces(bool always_visible) = 0;
virtual void Maximize() = 0;
virtual void Minimize() = 0;
virtual bool IsMaximized() const = 0;
@@ -217,10 +227,13 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SetVisibilityChangedAnimationsEnabled(bool value) = 0;
virtual ui::NativeTheme* GetNativeTheme() const = 0;
virtual void OnRootViewLayout() const = 0;
+ virtual bool IsTranslucentWindowOpacitySupported() const = 0;
+
+ // Repost an unhandled event to the native widget for default OS processing.
+ virtual void RepostNativeEvent(gfx::NativeEvent native_event) = 0;
// Overridden from NativeWidget:
virtual internal::NativeWidgetPrivate* AsNativeWidgetPrivate() OVERRIDE;
- virtual ui::EventHandler* GetEventHandler() = 0;
};
} // namespace internal
diff --git a/chromium/ui/views/widget/native_widget_unittest.cc b/chromium/ui/views/widget/native_widget_unittest.cc
index 133f8be04a5..9002e9da8f1 100644
--- a/chromium/ui/views/widget/native_widget_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_unittest.cc
@@ -42,7 +42,6 @@ class NativeWidgetTest : public ViewsTestBase {
Widget* widget = new Widget;
Widget::InitParams params = CreateParams(type);
params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
- params.child = false; // Implicitly set to true by ctor with TYPE_CONTROL.
params.bounds = gfx::Rect(10, 10, 200, 200);
widget->Init(params);
return widget->native_widget_private();
diff --git a/chromium/ui/views/widget/native_widget_win.cc b/chromium/ui/views/widget/native_widget_win.cc
deleted file mode 100644
index 3f992e8d894..00000000000
--- a/chromium/ui/views/widget/native_widget_win.cc
+++ /dev/null
@@ -1,1068 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/native_widget_win.h"
-
-#include <dwmapi.h>
-#include <shellapi.h>
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/strings/string_util.h"
-#include "base/win/scoped_gdi_object.h"
-#include "base/win/win_util.h"
-#include "base/win/windows_version.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/drag_source_win.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
-#include "ui/base/ime/input_method_factory.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/base/theme_provider.h"
-#include "ui/base/view_prop.h"
-#include "ui/base/win/mouse_wheel_util.h"
-#include "ui/base/win/shell.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_code_conversion_win.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/native_theme/native_theme.h"
-#include "ui/views/controls/native_control_win.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/drag_utils.h"
-#include "ui/views/focus/accelerator_handler.h"
-#include "ui/views/focus/view_storage.h"
-#include "ui/views/focus/widget_focus_manager.h"
-#include "ui/views/ime/input_method_bridge.h"
-#include "ui/views/widget/aero_tooltip_manager.h"
-#include "ui/views/widget/drop_target_win.h"
-#include "ui/views/widget/monitor_win.h"
-#include "ui/views/widget/native_widget_delegate.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/widget/widget_hwnd_utils.h"
-#include "ui/views/win/fullscreen_handler.h"
-#include "ui/views/win/hwnd_message_handler.h"
-#include "ui/views/window/native_frame_view.h"
-
-#pragma comment(lib, "dwmapi.lib")
-
-using ui::ViewProp;
-
-namespace views {
-
-namespace {
-
-// Enumeration callback for NativeWidget::GetAllChildWidgets() and
-// NativeWidget::GetAllOwnedWidgets. Adds any HWNDs that correspond to
-// Widgets to a set.
-BOOL CALLBACK EnumerateNativeWidgets(HWND hwnd, LPARAM l_param) {
- Widget* widget = Widget::GetWidgetForNativeView(hwnd);
- if (widget) {
- Widget::Widgets* widgets = reinterpret_cast<Widget::Widgets*>(l_param);
- widgets->insert(widget);
- }
- return TRUE;
-}
-
-// Links the HWND to its NativeWidget.
-const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
-
-const int kDragFrameWindowAlpha = 200;
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, public:
-
-NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate)
- : delegate_(delegate),
- ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
- drag_frame_saved_window_style_(0),
- drag_frame_saved_window_ex_style_(0),
- has_non_client_view_(false),
- message_handler_(new HWNDMessageHandler(this)) {
-}
-
-NativeWidgetWin::~NativeWidgetWin() {
- if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
- delete delegate_;
- else
- CloseNow();
- message_handler_.reset();
-}
-
-// static
-gfx::Font NativeWidgetWin::GetWindowTitleFont() {
- NONCLIENTMETRICS ncm;
- base::win::GetNonClientMetrics(&ncm);
- l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
- base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
- return gfx::Font(caption_font);
-}
-
-void NativeWidgetWin::Show(int show_state) {
- message_handler_->Show(show_state);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, NativeWidget implementation:
-
-void NativeWidgetWin::InitNativeWidget(const Widget::InitParams& params) {
- gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
- Widget::InitParams params_in_pixel(params);
- params_in_pixel.bounds = pixel_bounds;
- SetInitParams(params_in_pixel);
- message_handler_->Init(params.parent, pixel_bounds);
-}
-
-NonClientFrameView* NativeWidgetWin::CreateNonClientFrameView() {
- return GetWidget()->ShouldUseNativeFrame() ?
- new NativeFrameView(GetWidget()) : NULL;
-}
-
-bool NativeWidgetWin::ShouldUseNativeFrame() const {
- return ui::win::IsAeroGlassEnabled();
-}
-
-void NativeWidgetWin::FrameTypeChanged() {
- message_handler_->FrameTypeChanged();
-}
-
-Widget* NativeWidgetWin::GetWidget() {
- return delegate_->AsWidget();
-}
-
-const Widget* NativeWidgetWin::GetWidget() const {
- return delegate_->AsWidget();
-}
-
-gfx::NativeView NativeWidgetWin::GetNativeView() const {
- return message_handler_->hwnd();
-}
-
-gfx::NativeWindow NativeWidgetWin::GetNativeWindow() const {
- return message_handler_->hwnd();
-}
-
-Widget* NativeWidgetWin::GetTopLevelWidget() {
- NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView());
- return native_widget ? native_widget->GetWidget() : NULL;
-}
-
-const ui::Compositor* NativeWidgetWin::GetCompositor() const {
- return NULL;
-}
-
-ui::Compositor* NativeWidgetWin::GetCompositor() {
- return NULL;
-}
-
-ui::Layer* NativeWidgetWin::GetLayer() {
- return NULL;
-}
-
-void NativeWidgetWin::ReorderNativeViews() {
-}
-
-void NativeWidgetWin::ViewRemoved(View* view) {
- if (drop_target_.get())
- drop_target_->ResetTargetViewIfEquals(view);
-}
-
-void NativeWidgetWin::SetNativeWindowProperty(const char* name, void* value) {
- // Remove the existing property (if any).
- for (ViewProps::iterator i = props_.begin(); i != props_.end(); ++i) {
- if ((*i)->Key() == name) {
- props_.erase(i);
- break;
- }
- }
-
- if (value)
- props_.push_back(new ViewProp(GetNativeView(), name, value));
-}
-
-void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const {
- return ViewProp::GetValue(GetNativeView(), name);
-}
-
-TooltipManager* NativeWidgetWin::GetTooltipManager() const {
- return tooltip_manager_.get();
-}
-
-void NativeWidgetWin::SetCapture() {
- message_handler_->SetCapture();
-}
-
-void NativeWidgetWin::ReleaseCapture() {
- message_handler_->ReleaseCapture();
-}
-
-bool NativeWidgetWin::HasCapture() const {
- return message_handler_->HasCapture();
-}
-
-InputMethod* NativeWidgetWin::CreateInputMethod() {
- return new InputMethodBridge(GetMessageHandler(), ui::GetSharedInputMethod(),
- true);
-}
-
-internal::InputMethodDelegate* NativeWidgetWin::GetInputMethodDelegate() {
- return message_handler_.get();
-}
-
-void NativeWidgetWin::CenterWindow(const gfx::Size& size) {
- gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
- message_handler_->CenterWindow(size_in_pixels);
-}
-
-void NativeWidgetWin::GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const {
- message_handler_->GetWindowPlacement(bounds, show_state);
- *bounds = gfx::win::ScreenToDIPRect(*bounds);
-}
-
-bool NativeWidgetWin::SetWindowTitle(const string16& title) {
- return message_handler_->SetTitle(title);
-}
-
-void NativeWidgetWin::SetWindowIcons(const gfx::ImageSkia& window_icon,
- const gfx::ImageSkia& app_icon) {
- message_handler_->SetWindowIcons(window_icon, app_icon);
-}
-
-void NativeWidgetWin::InitModalType(ui::ModalType modal_type) {
- message_handler_->InitModalType(modal_type);
-}
-
-gfx::Rect NativeWidgetWin::GetWindowBoundsInScreen() const {
- gfx::Rect bounds_in_pixels = message_handler_->GetWindowBoundsInScreen();
- return gfx::win::ScreenToDIPRect(bounds_in_pixels);
-}
-
-gfx::Rect NativeWidgetWin::GetClientAreaBoundsInScreen() const {
- gfx::Rect bounds_in_pixels = message_handler_->GetClientAreaBoundsInScreen();
- return gfx::win::ScreenToDIPRect(bounds_in_pixels);
-}
-
-gfx::Rect NativeWidgetWin::GetRestoredBounds() const {
- gfx::Rect bounds_in_pixels = message_handler_->GetRestoredBounds();
- return gfx::win::ScreenToDIPRect(bounds_in_pixels);
-}
-
-void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) {
- float scale = gfx::win::GetDeviceScaleFactor();
- gfx::Rect bounds_in_pixels(
- gfx::ToCeiledPoint(gfx::ScalePoint(bounds.origin(), scale)),
- gfx::ToFlooredSize(gfx::ScaleSize(bounds.size(), scale)));
- message_handler_->SetBounds(bounds_in_pixels);
-}
-
-void NativeWidgetWin::SetSize(const gfx::Size& size) {
- message_handler_->SetSize(size);
-}
-
-void NativeWidgetWin::StackAbove(gfx::NativeView native_view) {
- message_handler_->StackAbove(native_view);
-}
-
-void NativeWidgetWin::StackAtTop() {
- message_handler_->StackAtTop();
-}
-
-void NativeWidgetWin::StackBelow(gfx::NativeView native_view) {
- NOTIMPLEMENTED();
-}
-
-void NativeWidgetWin::SetShape(gfx::NativeRegion region) {
- message_handler_->SetRegion(region);
-}
-
-void NativeWidgetWin::Close() {
- message_handler_->Close();
-}
-
-void NativeWidgetWin::CloseNow() {
- message_handler_->CloseNow();
-}
-
-void NativeWidgetWin::Show() {
- message_handler_->Show();
-}
-
-void NativeWidgetWin::Hide() {
- message_handler_->Hide();
-}
-
-void NativeWidgetWin::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds);
- message_handler_->ShowMaximizedWithBounds(pixel_bounds);
-}
-
-void NativeWidgetWin::ShowWithWindowState(ui::WindowShowState show_state) {
- message_handler_->ShowWindowWithState(show_state);
-}
-
-bool NativeWidgetWin::IsVisible() const {
- return message_handler_->IsVisible();
-}
-
-void NativeWidgetWin::Activate() {
- message_handler_->Activate();
-}
-
-void NativeWidgetWin::Deactivate() {
- message_handler_->Deactivate();
-}
-
-bool NativeWidgetWin::IsActive() const {
- return message_handler_->IsActive();
-}
-
-void NativeWidgetWin::SetAlwaysOnTop(bool on_top) {
- message_handler_->SetAlwaysOnTop(on_top);
-}
-
-bool NativeWidgetWin::IsAlwaysOnTop() const {
- return message_handler_->IsAlwaysOnTop();
-}
-
-void NativeWidgetWin::Maximize() {
- message_handler_->Maximize();
-}
-
-void NativeWidgetWin::Minimize() {
- message_handler_->Minimize();
-}
-
-bool NativeWidgetWin::IsMaximized() const {
- return message_handler_->IsMaximized();
-}
-
-bool NativeWidgetWin::IsMinimized() const {
- return message_handler_->IsMinimized();
-}
-
-void NativeWidgetWin::Restore() {
- message_handler_->Restore();
-}
-
-void NativeWidgetWin::SetFullscreen(bool fullscreen) {
- message_handler_->fullscreen_handler()->SetFullscreen(fullscreen);
-}
-
-void NativeWidgetWin::SetMetroSnapFullscreen(bool metro_snap) {
- message_handler_->fullscreen_handler()->SetMetroSnap(metro_snap);
-}
-
-bool NativeWidgetWin::IsFullscreen() const {
- return message_handler_->fullscreen_handler()->fullscreen();
-}
-
-bool NativeWidgetWin::IsInMetroSnapMode() const {
- return message_handler_->fullscreen_handler()->metro_snap();
-}
-
-void NativeWidgetWin::SetCanUpdateLayeredWindow(bool can_update) {
- message_handler_->set_can_update_layered_window(can_update);
-}
-
-void NativeWidgetWin::SetOpacity(unsigned char opacity) {
- message_handler_->SetOpacity(static_cast<BYTE>(opacity));
- GetWidget()->GetRootView()->SchedulePaint();
-}
-
-void NativeWidgetWin::SetUseDragFrame(bool use_drag_frame) {
- if (use_drag_frame) {
- // Make the frame slightly transparent during the drag operation.
- drag_frame_saved_window_style_ = GetWindowLong(GetNativeView(), GWL_STYLE);
- drag_frame_saved_window_ex_style_ =
- GetWindowLong(GetNativeView(), GWL_EXSTYLE);
- SetWindowLong(GetNativeView(), GWL_EXSTYLE,
- drag_frame_saved_window_ex_style_ | WS_EX_LAYERED);
- // Remove the captions tyle so the window doesn't have window controls for a
- // more "transparent" look.
- SetWindowLong(GetNativeView(), GWL_STYLE,
- drag_frame_saved_window_style_ & ~WS_CAPTION);
- SetLayeredWindowAttributes(GetNativeView(), RGB(0xFF, 0xFF, 0xFF),
- kDragFrameWindowAlpha, LWA_ALPHA);
- } else {
- SetWindowLong(GetNativeView(), GWL_STYLE, drag_frame_saved_window_style_);
- SetWindowLong(GetNativeView(), GWL_EXSTYLE,
- drag_frame_saved_window_ex_style_);
- }
-}
-
-void NativeWidgetWin::FlashFrame(bool flash) {
- message_handler_->FlashFrame(flash);
-}
-
-void NativeWidgetWin::RunShellDrag(View* view,
- const ui::OSExchangeData& data,
- const gfx::Point& location,
- int operation,
- ui::DragDropTypes::DragEventSource source) {
- views::RunShellDrag(NULL, data, location, operation, source);
-}
-
-void NativeWidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
- gfx::Rect pixel_rect = gfx::win::DIPToScreenRect(rect);
- message_handler_->SchedulePaintInRect(pixel_rect);
-}
-
-void NativeWidgetWin::SetCursor(gfx::NativeCursor cursor) {
- message_handler_->SetCursor(cursor);
-}
-
-bool NativeWidgetWin::IsMouseEventsEnabled() const {
- return true;
-}
-
-void NativeWidgetWin::ClearNativeFocus() {
- message_handler_->ClearNativeFocus();
-}
-
-gfx::Rect NativeWidgetWin::GetWorkAreaBoundsInScreen() const {
- return gfx::win::ScreenToDIPRect(
- gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
- GetNativeView()).work_area());
-}
-
-Widget::MoveLoopResult NativeWidgetWin::RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) {
- const bool hide_on_escape =
- escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE;
- return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ?
- Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
-}
-
-void NativeWidgetWin::EndMoveLoop() {
- message_handler_->EndMoveLoop();
-}
-
-void NativeWidgetWin::SetVisibilityChangedAnimationsEnabled(bool value) {
- message_handler_->SetVisibilityChangedAnimationsEnabled(value);
-}
-
-ui::NativeTheme* NativeWidgetWin::GetNativeTheme() const {
- return ui::NativeTheme::instance();
-}
-
-void NativeWidgetWin::OnRootViewLayout() const {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, NativeWidget implementation:
-
-ui::EventHandler* NativeWidgetWin::GetEventHandler() {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, protected:
-
-void NativeWidgetWin::OnFinalMessage(HWND window) {
- // We don't destroy props in WM_DESTROY as we may still get messages after
- // WM_DESTROY that assume the properties are still valid (such as WM_CLOSE).
- props_.clear();
- delegate_->OnNativeWidgetDestroyed();
- if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
- delete this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, protected:
-
-HWNDMessageHandler* NativeWidgetWin::GetMessageHandler() {
- return message_handler_.get();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, HWNDMessageHandlerDelegate implementation:
-
-bool NativeWidgetWin::IsWidgetWindow() const {
- // We don't NULL check GetWidget()->non_client_view() here because this
- // function can be called before the widget is fully constructed.
- return has_non_client_view_;
-}
-
-bool NativeWidgetWin::IsUsingCustomFrame() const {
- return !GetWidget()->ShouldUseNativeFrame();
-}
-
-void NativeWidgetWin::SchedulePaint() {
- GetWidget()->GetRootView()->SchedulePaint();
-}
-
-void NativeWidgetWin::EnableInactiveRendering() {
- delegate_->EnableInactiveRendering();
-}
-
-bool NativeWidgetWin::IsInactiveRenderingDisabled() {
- return delegate_->IsInactiveRenderingDisabled();
-}
-
-bool NativeWidgetWin::CanResize() const {
- return GetWidget()->widget_delegate()->CanResize();
-}
-
-bool NativeWidgetWin::CanMaximize() const {
- return GetWidget()->widget_delegate()->CanMaximize();
-}
-
-bool NativeWidgetWin::CanActivate() const {
- return delegate_->CanActivate();
-}
-
-bool NativeWidgetWin::WidgetSizeIsClientSize() const {
- const Widget* widget = GetWidget()->GetTopLevelWidget();
- return IsZoomed(GetNativeView()) ||
- (widget && widget->ShouldUseNativeFrame());
-}
-
-bool NativeWidgetWin::CanSaveFocus() const {
- return GetWidget()->is_top_level();
-}
-
-void NativeWidgetWin::SaveFocusOnDeactivate() {
- GetWidget()->GetFocusManager()->StoreFocusedView(true);
-}
-
-void NativeWidgetWin::RestoreFocusOnActivate() {
- // Mysteriously, this only appears to be needed support restoration of focus
- // to a child hwnd when restoring its top level window from the minimized
- // state. If we don't do this, then ::SetFocus() to that child HWND returns
- // ERROR_INVALID_PARAMETER, despite both HWNDs being of the same thread.
- // See http://crbug.com/125976 and
- // chrome/browser/ui/views/native_widget_win_interactive_uitest.cc .
- {
- // Since this is a synthetic reset, we don't need to tell anyone about it.
- AutoNativeNotificationDisabler disabler;
- GetWidget()->GetFocusManager()->ClearFocus();
- }
- RestoreFocusOnEnable();
-}
-
-void NativeWidgetWin::RestoreFocusOnEnable() {
- GetWidget()->GetFocusManager()->RestoreFocusedView();
-}
-
-bool NativeWidgetWin::IsModal() const {
- return delegate_->IsModal();
-}
-
-int NativeWidgetWin::GetInitialShowState() const {
- return SW_SHOWNORMAL;
-}
-
-bool NativeWidgetWin::WillProcessWorkAreaChange() const {
- return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
-}
-
-int NativeWidgetWin::GetNonClientComponent(const gfx::Point& point) const {
- gfx::Point point_in_dip = gfx::win::ScreenToDIPPoint(point);
- return delegate_->GetNonClientComponent(point_in_dip);
-}
-
-void NativeWidgetWin::GetWindowMask(const gfx::Size& size, gfx::Path* path) {
- if (GetWidget()->non_client_view())
- GetWidget()->non_client_view()->GetWindowMask(size, path);
-}
-
-bool NativeWidgetWin::GetClientAreaInsets(gfx::Insets* insets) const {
- return false;
-}
-
-void NativeWidgetWin::GetMinMaxSize(gfx::Size* min_size,
- gfx::Size* max_size) const {
- *min_size = gfx::win::ScreenToDIPSize(delegate_->GetMinimumSize());
- *max_size = gfx::win::ScreenToDIPSize(delegate_->GetMaximumSize());
-}
-
-gfx::Size NativeWidgetWin::GetRootViewSize() const {
- gfx::Size pixel_size = GetWidget()->GetRootView()->size();
- return gfx::win::ScreenToDIPSize(pixel_size);
-}
-
-void NativeWidgetWin::ResetWindowControls() {
- GetWidget()->non_client_view()->ResetWindowControls();
-}
-
-void NativeWidgetWin::PaintLayeredWindow(gfx::Canvas* canvas) {
- GetWidget()->GetRootView()->Paint(canvas);
-}
-
-InputMethod* NativeWidgetWin::GetInputMethod() {
- return GetWidget()->GetInputMethodDirect();
-}
-
-gfx::NativeViewAccessible NativeWidgetWin::GetNativeViewAccessible() {
- return GetWidget()->GetRootView()->GetNativeViewAccessible();
-}
-
-bool NativeWidgetWin::ShouldHandleSystemCommands() const {
- return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
-}
-
-void NativeWidgetWin::HandleAppDeactivated() {
- if (IsInactiveRenderingDisabled()) {
- delegate_->EnableInactiveRendering();
- } else {
- // TODO(pkotwicz): Remove need for SchedulePaint(). crbug.com/165841
- View* non_client_view = GetWidget()->non_client_view();
- if (non_client_view)
- non_client_view->SchedulePaint();
- }
-}
-
-void NativeWidgetWin::HandleActivationChanged(bool active) {
- delegate_->OnNativeWidgetActivationChanged(active);
-}
-
-bool NativeWidgetWin::HandleAppCommand(short command) {
- // We treat APPCOMMAND ids as an extension of our command namespace, and just
- // let the delegate figure out what to do...
- return GetWidget()->widget_delegate() &&
- GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
-}
-
-void NativeWidgetWin::HandleCancelMode() {
-}
-
-void NativeWidgetWin::HandleCaptureLost() {
- delegate_->OnMouseCaptureLost();
-}
-
-void NativeWidgetWin::HandleClose() {
- GetWidget()->Close();
-}
-
-bool NativeWidgetWin::HandleCommand(int command) {
- return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
-}
-
-void NativeWidgetWin::HandleAccelerator(const ui::Accelerator& accelerator) {
- GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
-}
-
-void NativeWidgetWin::HandleCreate() {
- // TODO(beng): much of this could/should maybe move to HWNDMessageHandler.
-
- SetNativeWindowProperty(kNativeWidgetKey, this);
- CHECK_EQ(this, GetNativeWidgetForNativeView(GetNativeView()));
-
- props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(GetNativeView()));
-
- drop_target_ = new DropTargetWin(
- static_cast<internal::RootView*>(GetWidget()->GetRootView()));
-
- // Windows special DWM window frame requires a special tooltip manager so
- // that window controls in Chrome windows don't flicker when you move your
- // mouse over them. See comment in aero_tooltip_manager.h.
- Widget* widget = GetWidget()->GetTopLevelWidget();
- if (widget && widget->ShouldUseNativeFrame()) {
- tooltip_manager_.reset(new AeroTooltipManager(GetWidget()));
- } else {
- tooltip_manager_.reset(new TooltipManagerWin(GetWidget()));
- }
- if (!tooltip_manager_->Init()) {
- // There was a problem creating the TooltipManager. Common error is 127.
- // See 82193 for details.
- LOG_GETLASTERROR(WARNING) << "tooltip creation failed, disabling tooltips";
- tooltip_manager_.reset();
- }
-
- delegate_->OnNativeWidgetCreated(true);
-}
-
-void NativeWidgetWin::HandleDestroying() {
- delegate_->OnNativeWidgetDestroying();
- if (drop_target_.get()) {
- RevokeDragDrop(GetNativeView());
- drop_target_ = NULL;
- }
-}
-
-void NativeWidgetWin::HandleDestroyed() {
- OnFinalMessage(GetNativeView());
-}
-
-bool NativeWidgetWin::HandleInitialFocus() {
- return GetWidget()->SetInitialFocus();
-}
-
-void NativeWidgetWin::HandleDisplayChange() {
- GetWidget()->widget_delegate()->OnDisplayChanged();
-}
-
-void NativeWidgetWin::HandleBeginWMSizeMove() {
- delegate_->OnNativeWidgetBeginUserBoundsChange();
-}
-
-void NativeWidgetWin::HandleEndWMSizeMove() {
- delegate_->OnNativeWidgetEndUserBoundsChange();
-}
-
-void NativeWidgetWin::HandleMove() {
- delegate_->OnNativeWidgetMove();
-}
-
-void NativeWidgetWin::HandleWorkAreaChanged() {
- GetWidget()->widget_delegate()->OnWorkAreaChanged();
-}
-
-void NativeWidgetWin::HandleVisibilityChanging(bool visible) {
- delegate_->OnNativeWidgetVisibilityChanging(visible);
-}
-
-void NativeWidgetWin::HandleVisibilityChanged(bool visible) {
- delegate_->OnNativeWidgetVisibilityChanged(visible);
-}
-
-void NativeWidgetWin::HandleClientSizeChanged(const gfx::Size& new_size) {
- gfx::Size size_in_dip = gfx::win::ScreenToDIPSize(new_size);
- delegate_->OnNativeWidgetSizeChanged(size_in_dip);
-}
-
-void NativeWidgetWin::HandleFrameChanged() {
- // Replace the frame and layout the contents.
- GetWidget()->non_client_view()->UpdateFrame();
-}
-
-void NativeWidgetWin::HandleNativeFocus(HWND last_focused_window) {
- delegate_->OnNativeFocus(last_focused_window);
- InputMethod* input_method = GetInputMethod();
- if (input_method)
- input_method->OnFocus();
-}
-
-void NativeWidgetWin::HandleNativeBlur(HWND focused_window) {
- delegate_->OnNativeBlur(focused_window);
- InputMethod* input_method = GetInputMethod();
- if (input_method)
- input_method->OnBlur();
-}
-
-bool NativeWidgetWin::HandleMouseEvent(const ui::MouseEvent& event) {
- static gfx::Transform scale_transform(
- 1/gfx::win::GetDeviceScaleFactor(), 0.0,
- 0.0, 1/gfx::win::GetDeviceScaleFactor(),
- 0.0, 0.0);
- if (event.IsMouseWheelEvent()) {
- ui::MouseWheelEvent dpi_event(
- static_cast<const ui::MouseWheelEvent&>(event));
- dpi_event.UpdateForRootTransform(scale_transform);
- delegate_->OnMouseEvent(&dpi_event);
- return dpi_event.handled();
- } else if (event.IsMouseEvent()) {
- ui::MouseEvent dpi_event(event);
- if (!(dpi_event.flags() & ui::EF_IS_NON_CLIENT))
- dpi_event.UpdateForRootTransform(scale_transform);
- delegate_->OnMouseEvent(&dpi_event);
- return dpi_event.handled();
- }
- NOTREACHED();
- return false;
-}
-
-bool NativeWidgetWin::HandleKeyEvent(const ui::KeyEvent& event) {
- delegate_->OnKeyEvent(const_cast<ui::KeyEvent*>(&event));
- return event.handled();
-}
-
-bool NativeWidgetWin::HandleUntranslatedKeyEvent(const ui::KeyEvent& event) {
- InputMethod* input_method = GetInputMethod();
- if (input_method)
- input_method->DispatchKeyEvent(event);
- return !!input_method;
-}
-
-void NativeWidgetWin::HandleTouchEvent(const ui::TouchEvent& event) {
- NOTREACHED() << "Touch events are not supported";
-}
-
-bool NativeWidgetWin::HandleIMEMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- InputMethod* input_method = GetInputMethod();
- if (!input_method || input_method->IsMock()) {
- *result = 0;
- return false;
- }
-
- MSG msg = {};
- msg.hwnd = message_handler_->hwnd();
- msg.message = message;
- msg.wParam = w_param;
- msg.lParam = l_param;
- return input_method->OnUntranslatedIMEMessage(msg, result);
-}
-
-void NativeWidgetWin::HandleInputLanguageChange(DWORD character_set,
- HKL input_language_id) {
- InputMethod* input_method = GetInputMethod();
- if (input_method && !input_method->IsMock()) {
- input_method->OnInputLocaleChanged();
- }
-}
-
-bool NativeWidgetWin::HandlePaintAccelerated(const gfx::Rect& invalid_rect) {
- gfx::Rect dpi_rect = gfx::win::ScreenToDIPRect(invalid_rect);
- return delegate_->OnNativeWidgetPaintAccelerated(dpi_rect);
-}
-
-void NativeWidgetWin::HandlePaint(gfx::Canvas* canvas) {
- delegate_->OnNativeWidgetPaint(canvas);
-}
-
-bool NativeWidgetWin::HandleTooltipNotify(int w_param,
- NMHDR* l_param,
- LRESULT* l_result) {
- // We can be sent this message before the tooltip manager is created, if a
- // subclass overrides OnCreate and creates some kind of Windows control there
- // that sends WM_NOTIFY messages.
- if (tooltip_manager_.get()) {
- bool handled;
- *l_result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
- return handled;
- }
- return false;
-}
-
-void NativeWidgetWin::HandleTooltipMouseMove(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
- if (tooltip_manager_.get())
- tooltip_manager_->OnMouse(message, w_param, l_param);
-}
-
-bool NativeWidgetWin::PreHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) {
- return false;
-}
-
-void NativeWidgetWin::PostHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param) {
-}
-
-bool NativeWidgetWin::HandleScrollEvent(const ui::ScrollEvent& event) {
- delegate_->OnScrollEvent(const_cast<ui::ScrollEvent*>(&event));
- return event.handled();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeWidgetWin, private:
-
-void NativeWidgetWin::SetInitParams(const Widget::InitParams& params) {
- // Set non-style attributes.
- ownership_ = params.ownership;
-
- ConfigureWindowStyles(message_handler_.get(), params,
- GetWidget()->widget_delegate(), delegate_);
-
- has_non_client_view_ = Widget::RequiresNonClientView(params.type);
- message_handler_->set_remove_standard_frame(params.remove_standard_frame);
- message_handler_->set_use_system_default_icon(params.use_system_default_icon);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Widget, public:
-
-// static
-void Widget::NotifyLocaleChanged() {
- NOTIMPLEMENTED();
-}
-
-namespace {
-BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
- Widget* widget = Widget::GetWidgetForNativeView(hwnd);
- if (widget && widget->is_secondary_widget())
- widget->Close();
- return TRUE;
-}
-} // namespace
-
-// static
-void Widget::CloseAllSecondaryWidgets() {
- EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
-}
-
-bool Widget::ConvertRect(const Widget* source,
- const Widget* target,
- gfx::Rect* rect) {
- DCHECK(source);
- DCHECK(target);
- DCHECK(rect);
-
- HWND source_hwnd = source->GetNativeView();
- HWND target_hwnd = target->GetNativeView();
- if (source_hwnd == target_hwnd)
- return true;
-
- RECT win_rect = gfx::win::DIPToScreenRect(*rect).ToRECT();
- if (::MapWindowPoints(source_hwnd, target_hwnd,
- reinterpret_cast<LPPOINT>(&win_rect),
- sizeof(RECT)/sizeof(POINT))) {
- *rect = gfx::win::ScreenToDIPRect(gfx::Rect(win_rect));
- return true;
- }
- return false;
-}
-
-namespace internal {
-
-////////////////////////////////////////////////////////////////////////////////
-// internal::NativeWidgetPrivate, public:
-
-// static
-NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
- internal::NativeWidgetDelegate* delegate) {
- return new NativeWidgetWin(delegate);
-}
-
-// static
-NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
- gfx::NativeView native_view) {
- return reinterpret_cast<NativeWidgetWin*>(
- ViewProp::GetValue(native_view, kNativeWidgetKey));
-}
-
-// static
-NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
- gfx::NativeWindow native_window) {
- return GetNativeWidgetForNativeView(native_window);
-}
-
-// static
-NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
- gfx::NativeView native_view) {
- if (!native_view)
- return NULL;
-
- // First, check if the top-level window is a Widget.
- HWND root = ::GetAncestor(native_view, GA_ROOT);
- if (!root)
- return NULL;
-
- NativeWidgetPrivate* widget = GetNativeWidgetForNativeView(root);
- if (widget)
- return widget;
-
- // Second, try to locate the last Widget window in the parent hierarchy.
- HWND parent_hwnd = native_view;
- // If we fail to find the native widget pointer for the root then it probably
- // means that the root belongs to a different process in which case we walk up
- // the native view chain looking for a parent window which corresponds to a
- // valid native widget. We only do this if we fail to find the native widget
- // for the current native view which means it is being destroyed.
- if (!widget && !GetNativeWidgetForNativeView(native_view)) {
- parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
- if (!parent_hwnd)
- return NULL;
- }
- NativeWidgetPrivate* parent_widget;
- do {
- parent_widget = GetNativeWidgetForNativeView(parent_hwnd);
- if (parent_widget) {
- widget = parent_widget;
- parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
- }
- } while (parent_hwnd != NULL && parent_widget != NULL);
-
- return widget;
-}
-
-// static
-void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
- Widget::Widgets* children) {
- if (!native_view)
- return;
-
- Widget* widget = Widget::GetWidgetForNativeView(native_view);
- if (widget)
- children->insert(widget);
- EnumChildWindows(native_view, EnumerateNativeWidgets,
- reinterpret_cast<LPARAM>(children));
-}
-
-// static
-void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
- Widget::Widgets* owned) {
- if (!native_view)
- return;
-
- Widget::Widgets all;
- EnumWindows(EnumerateNativeWidgets, reinterpret_cast<LPARAM>(&all));
- for (Widget::Widgets::const_iterator iter = all.begin();
- iter != all.end(); ++iter) {
- if (native_view == GetWindow((*iter)->GetNativeView(), GW_OWNER))
- owned->insert(*iter);
- }
-}
-
-// static
-void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
- gfx::NativeView new_parent) {
- if (!native_view)
- return;
-
- HWND previous_parent = ::GetParent(native_view);
- if (previous_parent == new_parent)
- return;
-
- Widget::Widgets widgets;
- GetAllChildWidgets(native_view, &widgets);
-
- // First notify all the widgets that they are being disassociated
- // from their previous parent.
- for (Widget::Widgets::iterator it = widgets.begin();
- it != widgets.end(); ++it) {
- (*it)->NotifyNativeViewHierarchyWillChange();
- }
-
- ::SetParent(native_view, new_parent);
-
- // And now, notify them that they have a brand new parent.
- for (Widget::Widgets::iterator it = widgets.begin();
- it != widgets.end(); ++it) {
- (*it)->NotifyNativeViewHierarchyChanged();
- }
-}
-
-// static
-bool NativeWidgetPrivate::IsMouseButtonDown() {
- return (GetKeyState(VK_LBUTTON) & 0x80) ||
- (GetKeyState(VK_RBUTTON) & 0x80) ||
- (GetKeyState(VK_MBUTTON) & 0x80) ||
- (GetKeyState(VK_XBUTTON1) & 0x80) ||
- (GetKeyState(VK_XBUTTON2) & 0x80);
-}
-
-// static
-bool NativeWidgetPrivate::IsTouchDown() {
- // This currently isn't necessary because we're not generating touch events on
- // windows. When we do, this will need to be updated.
- return false;
-}
-
-} // namespace internal
-
-} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_win.h b/chromium/ui/views/widget/native_widget_win.h
deleted file mode 100644
index 31bee8b8828..00000000000
--- a/chromium/ui/views/widget/native_widget_win.h
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
-#define UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/win_util.h"
-#include "ui/gfx/win/window_impl.h"
-#include "ui/views/widget/native_widget_private.h"
-#include "ui/views/win/hwnd_message_handler_delegate.h"
-
-namespace ui {
-class Compositor;
-class ViewProp;
-}
-
-namespace gfx {
-class Canvas;
-class Font;
-class Rect;
-}
-
-namespace views {
-
-class DropTargetWin;
-class HWNDMessageHandler;
-class InputMethodDelegate;
-class RootView;
-class TooltipManagerWin;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// NativeWidgetWin
-// A Widget for a views hierarchy used to represent anything that can be
-// contained within an HWND, e.g. a control, a window, etc. Specializations
-// suitable for specific tasks, e.g. top level window, are derived from this.
-//
-// This Widget contains a RootView which owns the hierarchy of views within it.
-// As long as views are part of this tree, they will be deleted automatically
-// when the RootView is destroyed. If you remove a view from the tree, you are
-// then responsible for cleaning up after it.
-//
-///////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT NativeWidgetWin : public internal::NativeWidgetPrivate,
- public HWNDMessageHandlerDelegate {
- public:
- explicit NativeWidgetWin(internal::NativeWidgetDelegate* delegate);
- virtual ~NativeWidgetWin();
-
- // Returns the system set window title font.
- static gfx::Font GetWindowTitleFont();
-
- // Show the window with the specified show command.
- void Show(int show_state);
-
- // Places the window in a pseudo-fullscreen mode where it looks and acts as
- // like a fullscreen window except that it remains within the boundaries
- // of the metro snap divider.
- void SetMetroSnapFullscreen(bool metro_snap);
- bool IsInMetroSnapMode() const;
-
- void SetCanUpdateLayeredWindow(bool can_update);
-
- // Overridden from internal::NativeWidgetPrivate:
- virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
- virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
- virtual bool ShouldUseNativeFrame() const OVERRIDE;
- virtual void FrameTypeChanged() OVERRIDE;
- virtual Widget* GetWidget() OVERRIDE;
- virtual const Widget* GetWidget() const OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
- virtual Widget* GetTopLevelWidget() OVERRIDE;
- virtual const ui::Compositor* GetCompositor() const OVERRIDE;
- virtual ui::Compositor* GetCompositor() OVERRIDE;
- virtual ui::Layer* GetLayer() OVERRIDE;
- virtual void ReorderNativeViews() OVERRIDE;
- virtual void ViewRemoved(View* view) OVERRIDE;
- virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
- virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
- virtual TooltipManager* GetTooltipManager() const OVERRIDE;
- virtual void SetCapture() OVERRIDE;
- virtual void ReleaseCapture() OVERRIDE;
- virtual bool HasCapture() const OVERRIDE;
- virtual InputMethod* CreateInputMethod() OVERRIDE;
- virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE;
- virtual void CenterWindow(const gfx::Size& size) OVERRIDE;
- virtual void GetWindowPlacement(
- gfx::Rect* bounds,
- ui::WindowShowState* show_state) const OVERRIDE;
- virtual bool SetWindowTitle(const string16& title) OVERRIDE;
- virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
- const gfx::ImageSkia& app_icon) OVERRIDE;
- virtual void InitModalType(ui::ModalType modal_type) OVERRIDE;
- virtual gfx::Rect GetWindowBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetClientAreaBoundsInScreen() const OVERRIDE;
- virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
- virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void StackAbove(gfx::NativeView native_view) OVERRIDE;
- virtual void StackAtTop() OVERRIDE;
- virtual void StackBelow(gfx::NativeView native_view) OVERRIDE;
- virtual void SetShape(gfx::NativeRegion shape) OVERRIDE;
- virtual void Close() OVERRIDE;
- virtual void CloseNow() OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) OVERRIDE;
- virtual void ShowWithWindowState(ui::WindowShowState show_state) OVERRIDE;
- virtual bool IsVisible() const OVERRIDE;
- virtual void Activate() OVERRIDE;
- virtual void Deactivate() OVERRIDE;
- virtual bool IsActive() const OVERRIDE;
- virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE;
- virtual bool IsAlwaysOnTop() const OVERRIDE;
- virtual void Maximize() OVERRIDE;
- virtual void Minimize() OVERRIDE;
- virtual bool IsMaximized() const OVERRIDE;
- virtual bool IsMinimized() const OVERRIDE;
- virtual void Restore() OVERRIDE;
- virtual void SetFullscreen(bool fullscreen) OVERRIDE;
- virtual bool IsFullscreen() const OVERRIDE;
- virtual void SetOpacity(unsigned char opacity) OVERRIDE;
- virtual void SetUseDragFrame(bool use_drag_frame) OVERRIDE;
- virtual void FlashFrame(bool flash) OVERRIDE;
- virtual void RunShellDrag(View* view,
- const ui::OSExchangeData& data,
- const gfx::Point& location,
- int operation,
- ui::DragDropTypes::DragEventSource source) OVERRIDE;
- virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
- virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
- virtual bool IsMouseEventsEnabled() const OVERRIDE;
- virtual void ClearNativeFocus() OVERRIDE;
- virtual gfx::Rect GetWorkAreaBoundsInScreen() const OVERRIDE;
- virtual Widget::MoveLoopResult RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) OVERRIDE;
- virtual void EndMoveLoop() OVERRIDE;
- virtual void SetVisibilityChangedAnimationsEnabled(bool value) OVERRIDE;
- virtual ui::NativeTheme* GetNativeTheme() const OVERRIDE;
- virtual void OnRootViewLayout() const OVERRIDE;
-
- // Overridden from NativeWidget:
- virtual ui::EventHandler* GetEventHandler() OVERRIDE;
-
- protected:
- // Deletes this window as it is destroyed, override to provide different
- // behavior.
- virtual void OnFinalMessage(HWND window);
-
- HWNDMessageHandler* GetMessageHandler();
-
- // Overridden from HWNDMessageHandlerDelegate:
- virtual bool IsWidgetWindow() const OVERRIDE;
- virtual bool IsUsingCustomFrame() const OVERRIDE;
- virtual void SchedulePaint() OVERRIDE;
- virtual void EnableInactiveRendering() OVERRIDE;
- virtual bool IsInactiveRenderingDisabled() OVERRIDE;
- virtual bool CanResize() const OVERRIDE;
- virtual bool CanMaximize() const OVERRIDE;
- virtual bool CanActivate() const OVERRIDE;
- virtual bool WidgetSizeIsClientSize() const OVERRIDE;
- virtual bool CanSaveFocus() const OVERRIDE;
- virtual void SaveFocusOnDeactivate() OVERRIDE;
- virtual void RestoreFocusOnActivate() OVERRIDE;
- virtual void RestoreFocusOnEnable() OVERRIDE;
- virtual bool IsModal() const OVERRIDE;
- virtual int GetInitialShowState() const OVERRIDE;
- virtual bool WillProcessWorkAreaChange() const OVERRIDE;
- virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
- virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
- virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
- virtual void GetMinMaxSize(gfx::Size* min_size,
- gfx::Size* max_size) const OVERRIDE;
- virtual gfx::Size GetRootViewSize() const OVERRIDE;
- virtual void ResetWindowControls() OVERRIDE;
- virtual void PaintLayeredWindow(gfx::Canvas* canvas) OVERRIDE;
- virtual InputMethod* GetInputMethod() OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual bool ShouldHandleSystemCommands() const OVERRIDE;
- virtual void HandleAppDeactivated() OVERRIDE;
- virtual void HandleActivationChanged(bool active) OVERRIDE;
- virtual bool HandleAppCommand(short command) OVERRIDE;
- virtual void HandleCancelMode() OVERRIDE;
- virtual void HandleCaptureLost() OVERRIDE;
- virtual void HandleClose() OVERRIDE;
- virtual bool HandleCommand(int command) OVERRIDE;
- virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
- virtual void HandleCreate() OVERRIDE;
- virtual void HandleDestroying() OVERRIDE;
- virtual void HandleDestroyed() OVERRIDE;
- virtual bool HandleInitialFocus() OVERRIDE;
- virtual void HandleDisplayChange() OVERRIDE;
- virtual void HandleBeginWMSizeMove() OVERRIDE;
- virtual void HandleEndWMSizeMove() OVERRIDE;
- virtual void HandleMove() OVERRIDE;
- virtual void HandleWorkAreaChanged() OVERRIDE;
- virtual void HandleVisibilityChanging(bool visible) OVERRIDE;
- virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
- virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
- virtual void HandleFrameChanged() OVERRIDE;
- virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE;
- virtual void HandleNativeBlur(HWND focused_window) OVERRIDE;
- virtual bool HandleMouseEvent(const ui::MouseEvent& event) OVERRIDE;
- virtual bool HandleKeyEvent(const ui::KeyEvent& event) OVERRIDE;
- virtual bool HandleUntranslatedKeyEvent(const ui::KeyEvent& event) OVERRIDE;
- virtual void HandleTouchEvent(const ui::TouchEvent& event) OVERRIDE;
- virtual bool HandleIMEMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
- virtual void HandleInputLanguageChange(DWORD character_set,
- HKL input_language_id) OVERRIDE;
- virtual bool HandlePaintAccelerated(const gfx::Rect& invalid_rect) OVERRIDE;
- virtual void HandlePaint(gfx::Canvas* canvas) OVERRIDE;
- virtual bool HandleTooltipNotify(int w_param,
- NMHDR* l_param,
- LRESULT* l_result) OVERRIDE;
- virtual void HandleTooltipMouseMove(UINT message,
- WPARAM w_param,
- LPARAM l_param) OVERRIDE;
- virtual bool PreHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* result) OVERRIDE;
- virtual void PostHandleMSG(UINT message,
- WPARAM w_param,
- LPARAM l_param) OVERRIDE;
- virtual bool HandleScrollEvent(const ui::ScrollEvent& event) OVERRIDE;
-
- // The TooltipManager. This is NULL if there is a problem creating the
- // underlying tooltip window.
- // WARNING: RootView's destructor calls into the TooltipManager. As such, this
- // must be destroyed AFTER root_view_.
- scoped_ptr<TooltipManagerWin> tooltip_manager_;
-
- scoped_refptr<DropTargetWin> drop_target_;
-
- private:
- typedef ScopedVector<ui::ViewProp> ViewProps;
-
- void SetInitParams(const Widget::InitParams& params);
-
- // A delegate implementation that handles events received here.
- // See class documentation for Widget in widget.h for a note about ownership.
- internal::NativeWidgetDelegate* delegate_;
-
- // See class documentation for Widget in widget.h for a note about ownership.
- Widget::InitParams::Ownership ownership_;
-
- ViewProps props_;
-
- // The window styles before we modified them for the drag frame appearance.
- DWORD drag_frame_saved_window_style_;
- DWORD drag_frame_saved_window_ex_style_;
-
- // True if the widget is going to have a non_client_view. We cache this value
- // rather than asking the Widget for the non_client_view so that we know at
- // Init time, before the Widget has created the NonClientView.
- bool has_non_client_view_;
-
- scoped_ptr<HWNDMessageHandler> message_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeWidgetWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
diff --git a/chromium/ui/views/widget/native_widget_win_unittest.cc b/chromium/ui/views/widget/native_widget_win_unittest.cc
deleted file mode 100644
index 6a84ca06d70..00000000000
--- a/chromium/ui/views/widget/native_widget_win_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/native_widget_win.h"
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/win/scoped_ole_initializer.h"
-
-namespace views {
-namespace {
-
-class NativeWidgetWinTest : public testing::Test {
- public:
- NativeWidgetWinTest() {}
- ~NativeWidgetWinTest() {}
-
- virtual void TearDown() {
- // Flush the message loop because we have pending release tasks
- // and these tasks if un-executed would upset Valgrind.
- RunPendingMessages();
- }
-
- // Create a simple widget win. The caller is responsible for taking ownership
- // of the returned value.
- NativeWidgetWin* CreateNativeWidgetWin();
-
- void RunPendingMessages() {
- message_loop_.RunUntilIdle();
- }
-
- private:
- base::MessageLoopForUI message_loop_;
- ui::ScopedOleInitializer ole_initializer_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeWidgetWinTest);
-};
-
-NativeWidgetWin* NativeWidgetWinTest::CreateNativeWidgetWin() {
- scoped_ptr<Widget> widget(new Widget);
- Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget->Init(params);
- return static_cast<NativeWidgetWin*>(widget.release()->native_widget());
-}
-
-TEST_F(NativeWidgetWinTest, ZoomWindow) {
- scoped_ptr<NativeWidgetWin> window(CreateNativeWidgetWin());
- ShowWindow(window->GetNativeView(), SW_HIDE);
- EXPECT_FALSE(window->IsActive());
- ShowWindow(window->GetNativeView(), SW_MAXIMIZE);
- EXPECT_TRUE(IsZoomed(window->GetNativeView()));
- window->CloseNow();
-}
-
-TEST_F(NativeWidgetWinTest, SetBoundsForZoomedWindow) {
- scoped_ptr<NativeWidgetWin> window(CreateNativeWidgetWin());
- ShowWindow(window->GetNativeView(), SW_MAXIMIZE);
- EXPECT_TRUE(IsZoomed(window->GetNativeView()));
-
- // Create another window, so that it will be active.
- scoped_ptr<NativeWidgetWin> window2(CreateNativeWidgetWin());
- ShowWindow(window2->GetNativeView(), SW_MAXIMIZE);
- EXPECT_TRUE(window2->IsActive());
- EXPECT_FALSE(window->IsActive());
-
- // Verify that setting the bounds of a zoomed window will unzoom it and not
- // cause it to be activated.
- window->SetBounds(gfx::Rect(50, 50, 650, 650));
- EXPECT_FALSE(IsZoomed(window->GetNativeView()));
- EXPECT_FALSE(window->IsActive());
-
- // Cleanup.
- window->CloseNow();
- window2->CloseNow();
-}
-
-} // namespace
-} // namespace views
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
index c825998d914..b41e16cb1b9 100644
--- a/chromium/ui/views/widget/root_view.cc
+++ b/chromium/ui/views/widget/root_view.cc
@@ -8,22 +8,23 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/ui_base_switches_util.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
+#include "ui/views/drag_controller.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view_targeter.h"
#include "ui/views/views_switches.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/widget/widget_deletion_observer.h"
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
+typedef ui::EventDispatchDetails DispatchDetails;
namespace views {
namespace internal {
@@ -51,6 +52,95 @@ class MouseEnterExitEvent : public ui::MouseEvent {
} // namespace
+// This event handler receives events in the pre-target phase and takes care of
+// the following:
+// - Shows keyboard-triggered context menus.
+class PreEventDispatchHandler : public ui::EventHandler {
+ public:
+ explicit PreEventDispatchHandler(View* owner)
+ : owner_(owner) {
+ }
+ virtual ~PreEventDispatchHandler() {}
+
+ private:
+ // ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ CHECK_EQ(ui::EP_PRETARGET, event->phase());
+ if (event->handled())
+ return;
+
+ View* v = NULL;
+ if (owner_->GetFocusManager()) // Can be NULL in unittests.
+ v = owner_->GetFocusManager()->GetFocusedView();
+
+ // 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()))) {
+ // Clamp the menu location within the visible bounds of each ancestor view
+ // to avoid showing the menu over a completely different view or window.
+ gfx::Point location = v->GetKeyboardContextMenuLocation();
+ for (View* parent = v->parent(); parent; parent = parent->parent()) {
+ const gfx::Rect& parent_bounds = parent->GetBoundsInScreen();
+ location.SetToMax(parent_bounds.origin());
+ location.SetToMin(parent_bounds.bottom_right());
+ }
+ v->ShowContextMenu(location, ui::MENU_SOURCE_KEYBOARD);
+ event->StopPropagation();
+ }
+ }
+
+ View* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler);
+};
+
+// This event handler receives events in the post-target phase and takes care of
+// the following:
+// - Generates context menu, or initiates drag-and-drop, from gesture events.
+class PostEventDispatchHandler : public ui::EventHandler {
+ public:
+ PostEventDispatchHandler()
+ : touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) {
+ }
+ virtual ~PostEventDispatchHandler() {}
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ DCHECK_EQ(ui::EP_POSTTARGET, event->phase());
+ if (event->handled())
+ return;
+
+ View* target = static_cast<View*>(event->target());
+ gfx::Point location = event->location();
+ if (touch_dnd_enabled_ &&
+ event->type() == ui::ET_GESTURE_LONG_PRESS &&
+ (!target->drag_controller() ||
+ target->drag_controller()->CanStartDragForView(
+ target, location, location))) {
+ if (target->DoDrag(*event, location,
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)) {
+ event->StopPropagation();
+ return;
+ }
+ }
+
+ if (target->context_menu_controller() &&
+ (event->type() == ui::ET_GESTURE_LONG_PRESS ||
+ event->type() == ui::ET_GESTURE_LONG_TAP ||
+ event->type() == ui::ET_GESTURE_TWO_FINGER_TAP)) {
+ gfx::Point screen_location(location);
+ View::ConvertPointToScreen(target, &screen_location);
+ target->ShowContextMenu(screen_location, ui::MENU_SOURCE_TOUCH);
+ event->StopPropagation();
+ }
+ }
+
+ bool touch_dnd_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler);
+};
+
// static
const char RootView::kViewClassName[] = "RootView";
@@ -68,13 +158,18 @@ RootView::RootView(Widget* widget)
last_mouse_event_flags_(0),
last_mouse_event_x_(-1),
last_mouse_event_y_(-1),
- touch_pressed_handler_(NULL),
gesture_handler_(NULL),
scroll_gesture_handler_(NULL),
+ pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)),
+ post_dispatch_handler_(new internal::PostEventDispatchHandler),
focus_search_(this, false, false),
focus_traversable_parent_(NULL),
focus_traversable_parent_view_(NULL),
- event_dispatch_target_(NULL) {
+ event_dispatch_target_(NULL),
+ old_dispatch_target_(NULL) {
+ AddPreTargetHandler(pre_dispatch_handler_.get());
+ AddPostTargetHandler(post_dispatch_handler_.get());
+ SetEventTargeter(scoped_ptr<ui::EventTargeter>(new ViewTargeter()));
}
RootView::~RootView() {
@@ -111,232 +206,6 @@ void RootView::NotifyNativeViewHierarchyChanged() {
PropagateNativeViewHierarchyChanged();
}
-// Input -----------------------------------------------------------------------
-
-void RootView::DispatchKeyEvent(ui::KeyEvent* event) {
- View* v = NULL;
- if (GetFocusManager()) // NULL in unittests.
- v = GetFocusManager()->GetFocusedView();
- // Special case to handle right-click context menus triggered by the
- // keyboard.
- if (v && v->enabled() && ((event->key_code() == ui::VKEY_APPS) ||
- (event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) {
- // Showing the context menu outside the visible bounds may result in a
- // context menu appearing over a completely different window. Constrain
- // location to visible bounds so this doesn't happen.
- gfx::Rect visible_bounds(v->ConvertRectToWidget(v->GetVisibleBounds()));
- visible_bounds.Offset(
- widget_->GetClientAreaBoundsInScreen().OffsetFromOrigin());
- gfx::Rect keyboard_loc(v->GetKeyboardContextMenuLocation(),
- gfx::Size(1, 1));
- keyboard_loc.AdjustToFit(visible_bounds);
- v->ShowContextMenu(keyboard_loc.origin(), ui::MENU_SOURCE_KEYBOARD);
- event->StopPropagation();
- return;
- }
-
- DispatchKeyEventStartAt(v, event);
-}
-
-void RootView::DispatchScrollEvent(ui::ScrollEvent* event) {
- for (View* v = GetEventHandlerForPoint(event->location());
- v && v != this && !event->stopped_propagation(); v = v->parent()) {
- DispatchEventToTarget(v, event);
- }
-
- if (event->handled() || event->type() != ui::ET_SCROLL)
- return;
-
- // Convert unprocessed scroll events into mouse-wheel events.
- ui::MouseWheelEvent wheel(*event);
- if (OnMouseWheel(wheel))
- event->SetHandled();
-}
-
-void RootView::DispatchTouchEvent(ui::TouchEvent* event) {
- // TODO: this looks all wrong. On a TOUCH_PRESSED we should figure out the
- // view and target that view with all touches with the same id until the
- // release (or keep it if captured).
-
- // If touch_pressed_handler_ is non null, we are currently processing
- // a touch down on the screen situation. In that case we send the
- // event to touch_pressed_handler_
-
- if (touch_pressed_handler_) {
- ui::TouchEvent touch_event(*event, static_cast<View*>(this),
- touch_pressed_handler_);
- DispatchEventToTarget(touch_pressed_handler_, &touch_event);
- if (touch_event.handled())
- event->SetHandled();
- if (touch_event.stopped_propagation())
- event->StopPropagation();
- return;
- }
-
- // Walk up the tree until we find a view that wants the touch event.
- for (touch_pressed_handler_ = GetEventHandlerForPoint(event->location());
- touch_pressed_handler_ && (touch_pressed_handler_ != this);
- touch_pressed_handler_ = touch_pressed_handler_->parent()) {
- if (!touch_pressed_handler_->enabled()) {
- // Disabled views eat events but are treated as not handled.
- break;
- }
-
- // See if this view wants to handle the touch
- ui::TouchEvent touch_event(*event, static_cast<View*>(this),
- touch_pressed_handler_);
- DispatchEventToTarget(touch_pressed_handler_, &touch_event);
- if (touch_event.handled())
- event->SetHandled();
- if (touch_event.stopped_propagation())
- event->StopPropagation();
-
- // The view could have removed itself from the tree when handling
- // OnTouchEvent(). So handle as per OnMousePressed. NB: we
- // assume that the RootView itself cannot be so removed.
- if (!touch_pressed_handler_)
- break;
-
- // The touch event wasn't processed. Go up the view hierarchy and dispatch
- // the touch event.
- if (!event->handled())
- continue;
-
- // If a View consumed the event, that means future touch-events should go to
- // that View. If the event wasn't consumed, then reset the handler.
- if (!event->stopped_propagation())
- touch_pressed_handler_ = NULL;
-
- return;
- }
-
- // Reset touch_pressed_handler_ to indicate that no processing is occurring.
- touch_pressed_handler_ = NULL;
-
- return;
-}
-
-void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
- if (gesture_handler_) {
- // |gesture_handler_| (or |scroll_gesture_handler_|) can be deleted during
- // processing.
- View* handler = scroll_gesture_handler_ &&
- (event->IsScrollGestureEvent() || event->IsFlingScrollEvent()) ?
- scroll_gesture_handler_ : gesture_handler_;
- ui::GestureEvent handler_event(*event, static_cast<View*>(this), handler);
- DispatchEventToTarget(handler, &handler_event);
-
- if (event->type() == ui::ET_GESTURE_END &&
- event->details().touch_points() <= 1) {
- // In case a drag was in progress, reset all the handlers. Otherwise, just
- // reset the gesture handler.
- if (gesture_handler_ == mouse_pressed_handler_)
- SetMouseHandler(NULL);
- else
- gesture_handler_ = NULL;
- }
-
- if (scroll_gesture_handler_ &&
- (event->type() == ui::ET_GESTURE_SCROLL_END ||
- event->type() == ui::ET_SCROLL_FLING_START)) {
- scroll_gesture_handler_ = NULL;
- }
-
- if (handler_event.stopped_propagation()) {
- event->StopPropagation();
- return;
- } else if (handler_event.handled()) {
- event->SetHandled();
- return;
- }
-
- if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN &&
- !scroll_gesture_handler_) {
- // Some view started processing gesture events, however it does not
- // process scroll-gesture events. In such case, we allow the event to
- // bubble up, and install a different scroll-gesture handler different
- // from the default gesture handler.
- for (scroll_gesture_handler_ = gesture_handler_->parent();
- scroll_gesture_handler_ && scroll_gesture_handler_ != this;
- scroll_gesture_handler_ = scroll_gesture_handler_->parent()) {
- ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
- scroll_gesture_handler_);
- DispatchEventToTarget(scroll_gesture_handler_, &gesture_event);
- if (gesture_event.stopped_propagation()) {
- event->StopPropagation();
- return;
- } else if (gesture_event.handled()) {
- event->SetHandled();
- return;
- }
- }
- scroll_gesture_handler_ = NULL;
- }
-
- return;
- }
-
- // If there was no handler for a SCROLL_BEGIN event, then subsequent scroll
- // events are not dispatched to any views.
- switch (event->type()) {
- case ui::ET_GESTURE_SCROLL_UPDATE:
- case ui::ET_GESTURE_SCROLL_END:
- case ui::ET_SCROLL_FLING_START:
- return;
- default:
- break;
- }
-
- View* gesture_handler = NULL;
- if (views::switches::IsRectBasedTargetingEnabled() &&
- !event->details().bounding_box().IsEmpty()) {
- // TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
- // once crbug.com/313392 is resolved.
- gfx::Rect touch_rect(event->details().bounding_box());
- touch_rect.set_origin(event->location());
- touch_rect.Offset(-touch_rect.width() / 2, -touch_rect.height() / 2);
- gesture_handler = GetEventHandlerForRect(touch_rect);
- } else {
- gesture_handler = GetEventHandlerForPoint(event->location());
- }
-
- // Walk up the tree until we find a view that wants the gesture event.
- for (gesture_handler_ = gesture_handler;
- gesture_handler_ && (gesture_handler_ != this);
- gesture_handler_ = gesture_handler_->parent()) {
- if (!gesture_handler_->enabled()) {
- // Disabled views eat events but are treated as not handled.
- return;
- }
-
- // See if this view wants to handle the Gesture.
- ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
- gesture_handler_);
- DispatchEventToTarget(gesture_handler_, &gesture_event);
-
- // The view could have removed itself from the tree when handling
- // OnGestureEvent(). So handle as per OnMousePressed. NB: we
- // assume that the RootView itself cannot be so removed.
- if (!gesture_handler_)
- return;
-
- if (gesture_event.handled()) {
- if (gesture_event.type() == ui::ET_GESTURE_SCROLL_BEGIN)
- scroll_gesture_handler_ = gesture_handler_;
- if (gesture_event.stopped_propagation())
- event->StopPropagation();
- else
- event->SetHandled();
- return;
- }
-
- // The gesture event wasn't processed. Go up the view hierarchy and
- // dispatch the gesture event.
- }
-
- gesture_handler_ = NULL;
-}
-
// Focus -----------------------------------------------------------------------
void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
@@ -374,6 +243,35 @@ View* RootView::GetFocusTraversableParentView() {
}
////////////////////////////////////////////////////////////////////////////////
+// RootView, ui::EventProcessor overrides:
+
+ui::EventTarget* RootView::GetRootTarget() {
+ return this;
+}
+
+ui::EventDispatchDetails RootView::OnEventFromSource(ui::Event* event) {
+ // TODO(tdanderson): Replace the calls to Dispatch*Event() with calls to
+ // EventProcessor::OnEventFromSource() once the code for
+ // that event type has been refactored, and then
+ // eventually remove this function altogether. See
+ // crbug.com/348083.
+ if (event->IsKeyEvent())
+ return EventProcessor::OnEventFromSource(event);
+ else if (event->IsScrollEvent())
+ return EventProcessor::OnEventFromSource(event);
+ else if (event->IsTouchEvent())
+ NOTREACHED() << "Touch events should not be sent to RootView.";
+ else if (event->IsGestureEvent())
+ DispatchGestureEvent(static_cast<ui::GestureEvent*>(event));
+ else if (event->IsMouseEvent())
+ NOTREACHED() << "Should not be called with a MouseEvent.";
+ else
+ NOTREACHED() << "Invalid event type.";
+
+ return DispatchDetails();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// RootView, View overrides:
const Widget* RootView::GetWidget() const {
@@ -419,7 +317,10 @@ bool RootView::OnMousePressed(const ui::MouseEvent& event) {
ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
mouse_pressed_handler_);
drag_info_.Reset();
- DispatchEventToTarget(mouse_pressed_handler_, &mouse_pressed_event);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
+ if (dispatch_details.dispatcher_destroyed)
+ return true;
return true;
}
DCHECK(!explicit_mouse_handler_);
@@ -447,12 +348,10 @@ bool RootView::OnMousePressed(const ui::MouseEvent& event) {
mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK);
drag_info_.Reset();
- {
- WidgetDeletionObserver widget_deletion_observer(widget_);
- DispatchEventToTarget(mouse_pressed_handler_, &mouse_pressed_event);
- if (!widget_deletion_observer.IsWidgetAlive())
- return mouse_pressed_event.handled();
- }
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
+ if (dispatch_details.dispatcher_destroyed)
+ return mouse_pressed_event.handled();
// The view could have removed itself from the tree when handling
// OnMousePressed(). In this case, the removal notification will have
@@ -495,7 +394,10 @@ bool RootView::OnMouseDragged(const ui::MouseEvent& event) {
ui::MouseEvent mouse_event(event, static_cast<View*>(this),
mouse_pressed_handler_);
- DispatchEventToTarget(mouse_pressed_handler_, &mouse_event);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_pressed_handler_, &mouse_event);
+ if (dispatch_details.dispatcher_destroyed)
+ return false;
}
return false;
}
@@ -510,8 +412,10 @@ void RootView::OnMouseReleased(const ui::MouseEvent& event) {
// configure state such that we're done first, then call View.
View* mouse_pressed_handler = mouse_pressed_handler_;
SetMouseHandler(NULL);
- DispatchEventToTarget(mouse_pressed_handler, &mouse_released);
- // WARNING: we may have been deleted.
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_pressed_handler, &mouse_released);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
}
}
@@ -524,7 +428,8 @@ void RootView::OnMouseCaptureLost() {
gfx::Point last_point(last_mouse_event_x_, last_mouse_event_y_);
ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED,
last_point, last_point,
- last_mouse_event_flags_);
+ last_mouse_event_flags_,
+ 0);
UpdateCursor(release_event);
}
// We allow the view to delete us from OnMouseCaptureLost. As such,
@@ -554,7 +459,12 @@ void RootView::OnMouseMoved(const ui::MouseEvent& event) {
(!mouse_move_handler_->notify_enter_exit_on_child() ||
!mouse_move_handler_->Contains(v))) {
MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED);
- DispatchEventToTarget(mouse_move_handler_, &exit);
+ exit.ConvertLocationToTarget(static_cast<View*>(this),
+ mouse_move_handler_);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_move_handler_, &exit);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
mouse_move_handler_, v);
}
@@ -565,19 +475,28 @@ void RootView::OnMouseMoved(const ui::MouseEvent& event) {
MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED);
entered.ConvertLocationToTarget(static_cast<View*>(this),
mouse_move_handler_);
- DispatchEventToTarget(mouse_move_handler_, &entered);
- NotifyEnterExitOfDescendant(entered, ui::ET_MOUSE_ENTERED, v,
- old_handler);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_move_handler_, &entered);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
+ NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_ENTERED,
+ mouse_move_handler_, old_handler);
}
}
ui::MouseEvent moved_event(event, static_cast<View*>(this),
mouse_move_handler_);
mouse_move_handler_->OnMouseMoved(moved_event);
+ // TODO(tdanderson): It may be possible to avoid setting the cursor twice
+ // (once here and once from CompoundEventFilter) on a
+ // mousemove. See crbug.com/351469.
if (!(moved_event.flags() & ui::EF_IS_NON_CLIENT))
widget_->SetCursor(mouse_move_handler_->GetCursor(moved_event));
} else if (mouse_move_handler_ != NULL) {
MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
- DispatchEventToTarget(mouse_move_handler_, &exited);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_move_handler_, &exited);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
mouse_move_handler_, v);
// On Aura the non-client area extends slightly outside the root view for
@@ -592,7 +511,10 @@ void RootView::OnMouseMoved(const ui::MouseEvent& event) {
void RootView::OnMouseExited(const ui::MouseEvent& event) {
if (mouse_move_handler_ != NULL) {
MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
- DispatchEventToTarget(mouse_move_handler_, &exited);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(mouse_move_handler_, &exited);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
mouse_move_handler_, NULL);
mouse_move_handler_ = NULL;
@@ -601,8 +523,14 @@ void RootView::OnMouseExited(const ui::MouseEvent& event) {
bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
for (View* v = GetEventHandlerForPoint(event.location());
- v && v != this && !event.handled(); v = v->parent())
- DispatchEventToTarget(v, const_cast<ui::MouseWheelEvent*>(&event));
+ v && v != this && !event.handled(); v = v->parent()) {
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(v, const_cast<ui::MouseWheelEvent*>(&event));
+ if (dispatch_details.dispatcher_destroyed ||
+ dispatch_details.target_destroyed) {
+ return event.handled();
+ }
+ }
return event.handled();
}
@@ -615,7 +543,7 @@ void RootView::SetMouseHandler(View* new_mh) {
drag_info_.Reset();
}
-void RootView::GetAccessibleState(ui::AccessibleViewState* state) {
+void RootView::GetAccessibleState(ui::AXViewState* state) {
state->name = widget_->widget_delegate()->GetAccessibleWindowTitle();
state->role = widget_->widget_delegate()->GetAccessibleWindowRole();
}
@@ -628,6 +556,142 @@ void RootView::UpdateParentLayer() {
////////////////////////////////////////////////////////////////////////////////
// RootView, protected:
+void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
+ if (gesture_handler_) {
+ // |gesture_handler_| (or |scroll_gesture_handler_|) can be deleted during
+ // processing.
+ View* handler = scroll_gesture_handler_ &&
+ (event->IsScrollGestureEvent() || event->IsFlingScrollEvent()) ?
+ scroll_gesture_handler_ : gesture_handler_;
+ ui::GestureEvent handler_event(*event, static_cast<View*>(this), handler);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(handler, &handler_event);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
+
+ if (event->type() == ui::ET_GESTURE_END &&
+ event->details().touch_points() <= 1) {
+ // In case a drag was in progress, reset all the handlers. Otherwise, just
+ // reset the gesture handler.
+ if (gesture_handler_ == mouse_pressed_handler_)
+ SetMouseHandler(NULL);
+ else
+ gesture_handler_ = NULL;
+ }
+
+ if (scroll_gesture_handler_ &&
+ (event->type() == ui::ET_GESTURE_SCROLL_END ||
+ event->type() == ui::ET_SCROLL_FLING_START)) {
+ scroll_gesture_handler_ = NULL;
+ }
+
+ if (handler_event.stopped_propagation()) {
+ event->StopPropagation();
+ return;
+ } else if (handler_event.handled()) {
+ event->SetHandled();
+ return;
+ }
+
+ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN &&
+ !scroll_gesture_handler_) {
+ // Some view started processing gesture events, however it does not
+ // process scroll-gesture events. In such case, we allow the event to
+ // bubble up, and install a different scroll-gesture handler different
+ // from the default gesture handler.
+ for (scroll_gesture_handler_ = gesture_handler_->parent();
+ scroll_gesture_handler_ && scroll_gesture_handler_ != this;
+ scroll_gesture_handler_ = scroll_gesture_handler_->parent()) {
+ ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
+ scroll_gesture_handler_);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(scroll_gesture_handler_, &gesture_event);
+ if (gesture_event.stopped_propagation()) {
+ event->StopPropagation();
+ return;
+ } else if (gesture_event.handled()) {
+ event->SetHandled();
+ return;
+ } else if (dispatch_details.dispatcher_destroyed ||
+ dispatch_details.target_destroyed) {
+ return;
+ }
+ }
+ scroll_gesture_handler_ = NULL;
+ }
+
+ return;
+ }
+
+ // If there was no handler for a SCROLL_BEGIN event, then subsequent scroll
+ // events are not dispatched to any views.
+ switch (event->type()) {
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ case ui::ET_GESTURE_SCROLL_END:
+ case ui::ET_SCROLL_FLING_START:
+ return;
+ default:
+ break;
+ }
+
+ View* gesture_handler = NULL;
+ if (views::switches::IsRectBasedTargetingEnabled() &&
+ !event->details().bounding_box().IsEmpty()) {
+ // TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
+ // once crbug.com/313392 is resolved.
+ gfx::Rect touch_rect(event->details().bounding_box());
+ touch_rect.set_origin(event->location());
+ touch_rect.Offset(-touch_rect.width() / 2, -touch_rect.height() / 2);
+ gesture_handler = GetEventHandlerForRect(touch_rect);
+ } else {
+ gesture_handler = GetEventHandlerForPoint(event->location());
+ }
+
+ // Walk up the tree until we find a view that wants the gesture event.
+ for (gesture_handler_ = gesture_handler;
+ gesture_handler_ && (gesture_handler_ != this);
+ gesture_handler_ = gesture_handler_->parent()) {
+ if (!gesture_handler_->enabled()) {
+ // Disabled views eat events but are treated as not handled.
+ return;
+ }
+
+ // See if this view wants to handle the Gesture.
+ ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
+ gesture_handler_);
+ ui::EventDispatchDetails dispatch_details =
+ DispatchEvent(gesture_handler_, &gesture_event);
+ if (dispatch_details.dispatcher_destroyed)
+ return;
+
+ // The view could have removed itself from the tree when handling
+ // OnGestureEvent(). So handle as per OnMousePressed. NB: we
+ // assume that the RootView itself cannot be so removed.
+ if (!gesture_handler_)
+ return;
+
+ if (gesture_event.handled()) {
+ if (gesture_event.type() == ui::ET_GESTURE_SCROLL_BEGIN)
+ scroll_gesture_handler_ = gesture_handler_;
+ if (gesture_event.stopped_propagation())
+ event->StopPropagation();
+ else
+ event->SetHandled();
+ // Last ui::ET_GESTURE_END should not set the gesture_handler_.
+ if (gesture_event.type() == ui::ET_GESTURE_END &&
+ event->details().touch_points() <= 1) {
+ gesture_handler_ = NULL;
+ }
+ return;
+ }
+
+ // The gesture event wasn't processed. Go up the view hierarchy and
+ // dispatch the gesture event.
+ }
+
+ gesture_handler_ = NULL;
+}
+
void RootView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
widget_->ViewHierarchyChanged(details);
@@ -637,14 +701,14 @@ void RootView::ViewHierarchyChanged(
mouse_pressed_handler_ = NULL;
if (mouse_move_handler_ == details.child)
mouse_move_handler_ = NULL;
- if (touch_pressed_handler_ == details.child)
- touch_pressed_handler_ = NULL;
if (gesture_handler_ == details.child)
gesture_handler_ = NULL;
if (scroll_gesture_handler_ == details.child)
scroll_gesture_handler_ = NULL;
if (event_dispatch_target_ == details.child)
event_dispatch_target_ = NULL;
+ if (old_dispatch_target_ == details.child)
+ old_dispatch_target_ = NULL;
}
}
@@ -656,10 +720,10 @@ void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) {
explicit_mouse_handler_ = false;
mouse_pressed_handler_ = NULL;
mouse_move_handler_ = NULL;
- touch_pressed_handler_ = NULL;
gesture_handler_ = NULL;
scroll_gesture_handler_ = NULL;
event_dispatch_target_ = NULL;
+ old_dispatch_target_ = NULL;
}
}
@@ -701,14 +765,6 @@ void RootView::SetMouseLocationAndFlags(const ui::MouseEvent& event) {
last_mouse_event_y_ = event.y();
}
-void RootView::DispatchEventToTarget(View* target, ui::Event* event) {
- View* old_target = event_dispatch_target_;
- event_dispatch_target_ = target;
- ui::EventDispatchDetails details = DispatchEvent(target, event);
- if (!details.dispatcher_destroyed)
- event_dispatch_target_ = old_target;
-}
-
void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent& event,
ui::EventType type,
View* view,
@@ -722,20 +778,11 @@ void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent& event,
// of the callbacks can mark the event as handled, and that would cause
// incorrect event dispatch.
MouseEnterExitEvent notify_event(event, type);
- DispatchEventToTarget(p, &notify_event);
- }
-}
-
-
-void RootView::DispatchKeyEventStartAt(View* view, ui::KeyEvent* event) {
- if (event->handled() || !view)
- return;
-
- for (; view && view != this; view = view->parent()) {
- DispatchEventToTarget(view, event);
- // Do this check here rather than in the if as |view| may have been deleted.
- if (event->handled())
+ ui::EventDispatchDetails dispatch_details = DispatchEvent(p, &notify_event);
+ if (dispatch_details.dispatcher_destroyed ||
+ dispatch_details.target_destroyed) {
return;
+ }
}
}
@@ -743,5 +790,28 @@ bool RootView::CanDispatchToTarget(ui::EventTarget* target) {
return event_dispatch_target_ == target;
}
+ui::EventDispatchDetails RootView::PreDispatchEvent(ui::EventTarget* target,
+ ui::Event* event) {
+ old_dispatch_target_ = event_dispatch_target_;
+ event_dispatch_target_ = static_cast<View*>(target);
+ return DispatchDetails();
+}
+
+ui::EventDispatchDetails RootView::PostDispatchEvent(ui::EventTarget* target,
+ const ui::Event& event) {
+ DispatchDetails details;
+ if (target != event_dispatch_target_)
+ details.target_destroyed = true;
+
+ event_dispatch_target_ = old_dispatch_target_;
+ old_dispatch_target_ = NULL;
+
+#ifndef NDEBUG
+ DCHECK(!event_dispatch_target_ || Contains(event_dispatch_target_));
+#endif
+
+ return details;
+}
+
} // namespace internal
} // namespace views
diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h
index 6ab367bd992..75788234b9b 100644
--- a/chromium/ui/views/widget/root_view.h
+++ b/chromium/ui/views/widget/root_view.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/memory/ref_counted.h"
-#include "ui/events/event_dispatcher.h"
+#include "ui/events/event_processor.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/focus_search.h"
#include "ui/views/view.h"
@@ -16,7 +16,6 @@
namespace views {
namespace test {
-class RootViewTestHelper;
class WidgetTest;
}
@@ -25,6 +24,7 @@ class Widget;
// This is a views-internal API and should not be used externally.
// Widget exposes this object as a View*.
namespace internal {
+class PreEventDispatchHandler;
////////////////////////////////////////////////////////////////////////////////
// RootView class
@@ -45,7 +45,7 @@ namespace internal {
//
class VIEWS_EXPORT RootView : public View,
public FocusTraversable,
- public ui::EventDispatcherDelegate {
+ public ui::EventProcessor {
public:
static const char kViewClassName[];
@@ -63,16 +63,6 @@ class VIEWS_EXPORT RootView : public View,
// Called when parent of the host changed.
void NotifyNativeViewHierarchyChanged();
- // Input ---------------------------------------------------------------------
-
- // Process a key event. Send the event to the focused view and up the focus
- // path, and finally to the default keyboard handler, until someone consumes
- // it. Returns whether anyone consumed the event.
- void DispatchKeyEvent(ui::KeyEvent* event);
- void DispatchScrollEvent(ui::ScrollEvent* event);
- void DispatchTouchEvent(ui::TouchEvent* event);
- virtual void DispatchGestureEvent(ui::GestureEvent* event);
-
// Focus ---------------------------------------------------------------------
// Used to set the FocusTraversable parent after the view has been created
@@ -97,6 +87,10 @@ class VIEWS_EXPORT RootView : public View,
virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
virtual View* GetFocusTraversableParentView() OVERRIDE;
+ // Overridden from ui::EventProcessor:
+ virtual ui::EventTarget* GetRootTarget() OVERRIDE;
+ virtual ui::EventDispatchDetails OnEventFromSource(ui::Event* event) OVERRIDE;
+
// Overridden from View:
virtual const Widget* GetWidget() const OVERRIDE;
virtual Widget* GetWidget() OVERRIDE;
@@ -112,10 +106,15 @@ class VIEWS_EXPORT RootView : public View,
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseWheel(const ui::MouseWheelEvent& event) OVERRIDE;
virtual void SetMouseHandler(View* new_mouse_handler) OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void UpdateParentLayer() OVERRIDE;
protected:
+ // TODO(tdanderson): Remove RootView::DispatchGestureEvent() once
+ // its targeting and dispatch logic has been moved
+ // elsewhere. See crbug.com/348083.
+ virtual void DispatchGestureEvent(ui::GestureEvent* event);
+
// Overridden from View:
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
@@ -128,7 +127,6 @@ class VIEWS_EXPORT RootView : public View,
private:
friend class ::views::View;
friend class ::views::Widget;
- friend class ::views::test::RootViewTestHelper;
friend class ::views::test::WidgetTest;
// Input ---------------------------------------------------------------------
@@ -145,8 +143,6 @@ class VIEWS_EXPORT RootView : public View,
// be applied to the point prior to calling this).
void SetMouseLocationAndFlags(const ui::MouseEvent& event);
- void DispatchEventToTarget(View* target, ui::Event* event);
-
// |view| is the view receiving |event|. This function sends the event to all
// the Views up the hierarchy that has |notify_enter_exit_on_child_| flag
// turned on, but does not contain |sibling|.
@@ -155,15 +151,14 @@ class VIEWS_EXPORT RootView : public View,
View* view,
View* sibling);
- // Dispatches the KeyEvent to |view| and ancestors until the event is
- // handled.
- void DispatchKeyEventStartAt(View* view, ui::KeyEvent* event);
-
// Overridden from ui::EventDispatcherDelegate:
virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE;
+ virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target,
+ ui::Event* event) OVERRIDE;
+ virtual ui::EventDispatchDetails PostDispatchEvent(
+ ui::EventTarget* target, const ui::Event& event) OVERRIDE;
//////////////////////////////////////////////////////////////////////////////
-
// Tree operations -----------------------------------------------------------
// The host Widget
@@ -190,9 +185,6 @@ class VIEWS_EXPORT RootView : public View,
int last_mouse_event_x_;
int last_mouse_event_y_;
- // The view currently handling touch events.
- View* touch_pressed_handler_;
-
// The view currently handling gesture events. When set, this handler receives
// all gesture events, except when there is an event handler for the specific
// gesture (e.g. scroll).
@@ -201,6 +193,9 @@ class VIEWS_EXPORT RootView : public View,
// The view currently handling scroll gesture events.
View* scroll_gesture_handler_;
+ scoped_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_;
+ scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_;
+
// Focus ---------------------------------------------------------------------
// The focus search algorithm.
@@ -217,6 +212,7 @@ class VIEWS_EXPORT RootView : public View,
View* focus_traversable_parent_view_;
View* event_dispatch_target_;
+ View* old_dispatch_target_;
// Drag and drop -------------------------------------------------------------
diff --git a/chromium/ui/views/widget/root_view_test_helper.h b/chromium/ui/views/widget/root_view_test_helper.h
deleted file mode 100644
index a26396730b2..00000000000
--- a/chromium/ui/views/widget/root_view_test_helper.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_ROOT_VIEW_TEST_HELPER_H_
-#define UI_VIEWS_WIDGET_ROOT_VIEW_TEST_HELPER_H_
-
-#include "ui/views/widget/root_view.h"
-
-namespace views {
-namespace test {
-
-class RootViewTestHelper {
- public:
- explicit RootViewTestHelper(internal::RootView* root_view)
- : root_view_(root_view) {
- }
- ~RootViewTestHelper() {}
-
- void DispatchKeyEventStartAt(View* view, ui::KeyEvent* event) {
- root_view_->DispatchKeyEventStartAt(view, event);
- }
-
- private:
- internal::RootView* root_view_;
-
- DISALLOW_COPY_AND_ASSIGN(RootViewTestHelper);
-};
-
-} // namespace test
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_ROOT_VIEW_TEST_HELPER_H_
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index ebe20d65346..9def7726fdd 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -2,8 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/widget/root_view.h"
+
+#include "ui/events/event_targeter.h"
+#include "ui/views/context_menu_controller.h"
#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/root_view_test_helper.h"
+#include "ui/views/view_targeter.h"
+#include "ui/views/widget/root_view.h"
namespace views {
namespace test {
@@ -28,7 +33,8 @@ class DeleteOnKeyEventView : public View {
DISALLOW_COPY_AND_ASSIGN(DeleteOnKeyEventView);
};
-// Verifies deleting a View in OnKeyPressed() doesn't crash.
+// Verifies deleting a View in OnKeyPressed() doesn't crash and that the
+// target is marked as destroyed in the returned EventDispatchDetails.
TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) {
Widget widget;
Widget::InitParams init_params =
@@ -44,12 +50,194 @@ TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) {
View* child = new DeleteOnKeyEventView(&got_key_event);
content->AddChildView(child);
+ // Give focus to |child| so that it will be the target of the key event.
+ child->SetFocusable(true);
+ child->RequestFocus();
+
+ ui::EventTargeter* targeter = new ViewTargeter();
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+ root_view->SetEventTargeter(make_scoped_ptr(targeter));
+
ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0, false);
- RootViewTestHelper test_helper(
- static_cast<internal::RootView*>(widget.GetRootView()));
- test_helper.DispatchKeyEventStartAt(child, &key_event);
+ ui::EventDispatchDetails details = root_view->OnEventFromSource(&key_event);
+ EXPECT_TRUE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(got_key_event);
}
+// Tracks whether a context menu is shown.
+class TestContextMenuController : public ContextMenuController {
+ public:
+ TestContextMenuController()
+ : show_context_menu_calls_(0),
+ menu_source_view_(NULL),
+ menu_source_type_(ui::MENU_SOURCE_NONE) {
+ }
+ virtual ~TestContextMenuController() {}
+
+ int show_context_menu_calls() const { return show_context_menu_calls_; }
+ View* menu_source_view() const { return menu_source_view_; }
+ ui::MenuSourceType menu_source_type() const { return menu_source_type_; }
+
+ void Reset() {
+ show_context_menu_calls_ = 0;
+ menu_source_view_ = NULL;
+ menu_source_type_ = ui::MENU_SOURCE_NONE;
+ }
+
+ // ContextMenuController:
+ virtual void ShowContextMenuForView(
+ View* source,
+ const gfx::Point& point,
+ ui::MenuSourceType source_type) OVERRIDE {
+ show_context_menu_calls_++;
+ menu_source_view_ = source;
+ menu_source_type_ = source_type;
+ }
+
+ private:
+ int show_context_menu_calls_;
+ View* menu_source_view_;
+ ui::MenuSourceType menu_source_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestContextMenuController);
+};
+
+// 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) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(init_params);
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+
+ TestContextMenuController controller;
+ View* focused_view = new View;
+ focused_view->set_context_menu_controller(&controller);
+ widget.SetContentsView(focused_view);
+ focused_view->SetFocusable(true);
+ focused_view->RequestFocus();
+
+ // No context menu should be shown for a keypress of 'A'.
+ ui::KeyEvent nomenu_key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
+ ui::EventDispatchDetails details =
+ root_view->OnEventFromSource(&nomenu_key_event);
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(0, controller.show_context_menu_calls());
+ EXPECT_EQ(NULL, controller.menu_source_view());
+ EXPECT_EQ(ui::MENU_SOURCE_NONE, controller.menu_source_type());
+ controller.Reset();
+
+ // A context menu should be shown for a keypress of Shift+F10.
+ ui::KeyEvent menu_key_event(
+ ui::ET_KEY_PRESSED, ui::VKEY_F10, ui::EF_SHIFT_DOWN, false);
+ details = root_view->OnEventFromSource(&menu_key_event);
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(1, controller.show_context_menu_calls());
+ EXPECT_EQ(focused_view, controller.menu_source_view());
+ EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
+ controller.Reset();
+
+ // A context menu should be shown for a keypress of VKEY_APPS.
+ ui::KeyEvent menu_key_event2(ui::ET_KEY_PRESSED, ui::VKEY_APPS, 0, false);
+ details = root_view->OnEventFromSource(&menu_key_event2);
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(1, controller.show_context_menu_calls());
+ EXPECT_EQ(focused_view, controller.menu_source_view());
+ EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
+ controller.Reset();
+}
+
+// View which handles all gesture events.
+class GestureHandlingView : public View {
+ public:
+ GestureHandlingView() {
+ }
+
+ virtual ~GestureHandlingView() {
+ }
+
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ event->SetHandled();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GestureHandlingView);
+};
+
+// Tests that context menus are shown for long press by the post-target handler
+// installed on the RootView only if the event is targetted at a view which can
+// show a context menu.
+TEST_F(RootViewTest, ContextMenuFromLongPress) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.bounds = gfx::Rect(100,100);
+ widget.Init(init_params);
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget.GetRootView());
+
+ // Create a view capable of showing the context menu with two children one of
+ // which handles all gesture events (e.g. a button).
+ TestContextMenuController controller;
+ View* parent_view = new View;
+ parent_view->set_context_menu_controller(&controller);
+ widget.SetContentsView(parent_view);
+
+ View* gesture_handling_child_view = new GestureHandlingView;
+ gesture_handling_child_view->SetBoundsRect(gfx::Rect(10,10));
+ parent_view->AddChildView(gesture_handling_child_view);
+
+ View* other_child_view = new View;
+ other_child_view->SetBoundsRect(gfx::Rect(20, 0, 10,10));
+ parent_view->AddChildView(other_child_view);
+
+ // |parent_view| should not show a context menu as a result of a long press on
+ // |gesture_handling_child_view|.
+ ui::GestureEvent begin1(ui::ET_GESTURE_BEGIN, 5, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
+ ui::EventDispatchDetails details = root_view->OnEventFromSource(&begin1);
+
+ ui::GestureEvent long_press1(ui::ET_GESTURE_LONG_PRESS, 5, 5, 0,
+ base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS, 0, 0), 1);
+ details = root_view->OnEventFromSource(&long_press1);
+
+ ui::GestureEvent end1(ui::ET_GESTURE_END, 5, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ details = root_view->OnEventFromSource(&end1);
+
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(0, controller.show_context_menu_calls());
+
+ // |parent_view| should show a context menu as a result of a long press on
+ // |other_child_view|.
+ ui::GestureEvent begin2(ui::ET_GESTURE_BEGIN, 25, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
+ details = root_view->OnEventFromSource(&begin2);
+
+ ui::GestureEvent long_press2(ui::ET_GESTURE_LONG_PRESS, 25, 5, 0,
+ base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS, 0, 0), 1);
+ details = root_view->OnEventFromSource(&long_press2);
+
+ ui::GestureEvent end2(ui::ET_GESTURE_END, 25, 5, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ details = root_view->OnEventFromSource(&end2);
+
+ EXPECT_FALSE(details.target_destroyed);
+ EXPECT_FALSE(details.dispatcher_destroyed);
+ EXPECT_EQ(1, controller.show_context_menu_calls());
+}
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/widget/tooltip_manager_aura.cc b/chromium/ui/views/widget/tooltip_manager_aura.cc
index 173597939c9..99ae9e6be57 100644
--- a/chromium/ui/views/widget/tooltip_manager_aura.cc
+++ b/chromium/ui/views/widget/tooltip_manager_aura.cc
@@ -6,12 +6,13 @@
#include "base/logging.h"
#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/client/tooltip_client.h"
-#include "ui/aura/root_window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/public/tooltip_client.h"
namespace views {
@@ -49,7 +50,7 @@ void TooltipManagerAura::UpdateTooltipManagerForCapture(Widget* source) {
return;
gfx::Point screen_loc(
- root_window->GetDispatcher()->GetLastMouseLocationInRoot());
+ root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot());
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root_window);
if (!screen_position_client)
@@ -91,7 +92,7 @@ void TooltipManagerAura::UpdateTooltip() {
aura::Window* root_window = GetWindow()->GetRootWindow();
if (aura::client::GetTooltipClient(root_window)) {
gfx::Point view_point =
- root_window->GetDispatcher()->GetLastMouseLocationInRoot();
+ root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
aura::Window::ConvertPointToTarget(root_window, GetWindow(), &view_point);
View* view = GetViewUnderPoint(view_point);
UpdateTooltipForTarget(view, view_point, root_window);
@@ -102,7 +103,7 @@ void TooltipManagerAura::TooltipTextChanged(View* view) {
aura::Window* root_window = GetWindow()->GetRootWindow();
if (aura::client::GetTooltipClient(root_window)) {
gfx::Point view_point =
- root_window->GetDispatcher()->GetLastMouseLocationInRoot();
+ root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
aura::Window::ConvertPointToTarget(root_window, GetWindow(), &view_point);
View* target = GetViewUnderPoint(view_point);
if (target != view)
@@ -124,7 +125,7 @@ void TooltipManagerAura::UpdateTooltipForTarget(View* target,
if (target) {
gfx::Point view_point = point;
View::ConvertPointFromWidget(target, &view_point);
- string16 new_tooltip_text;
+ base::string16 new_tooltip_text;
if (!target->GetTooltipText(view_point, &new_tooltip_text))
tooltip_text_.clear();
else
@@ -132,6 +133,9 @@ void TooltipManagerAura::UpdateTooltipForTarget(View* target,
} else {
tooltip_text_.clear();
}
+
+ aura::client::SetTooltipId(GetWindow(), target);
+
aura::client::GetTooltipClient(root_window)->UpdateTooltip(GetWindow());
}
diff --git a/chromium/ui/views/widget/tooltip_manager_aura.h b/chromium/ui/views/widget/tooltip_manager_aura.h
index ed69c6d79b9..e723299060b 100644
--- a/chromium/ui/views/widget/tooltip_manager_aura.h
+++ b/chromium/ui/views/widget/tooltip_manager_aura.h
@@ -52,7 +52,7 @@ class TooltipManagerAura : public TooltipManager {
aura::Window* GetWindow();
Widget* widget_;
- string16 tooltip_text_;
+ base::string16 tooltip_text_;
DISALLOW_COPY_AND_ASSIGN(TooltipManagerAura);
};
diff --git a/chromium/ui/views/widget/tooltip_manager_win.cc b/chromium/ui/views/widget/tooltip_manager_win.cc
deleted file mode 100644
index f9965f9cc37..00000000000
--- a/chromium/ui/views/widget/tooltip_manager_win.cc
+++ /dev/null
@@ -1,357 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/tooltip_manager_win.h"
-
-#include <windowsx.h>
-
-#include <limits>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/i18n/rtl.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/win/scoped_hdc.h"
-#include "base/win/scoped_select_object.h"
-#include "ui/base/l10n/l10n_util_win.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/text_elider.h"
-#include "ui/gfx/text_utils.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/gfx/win/scoped_set_map_mode.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/monitor_win.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-namespace {
-
-static int tooltip_height_ = 0;
-
-// Maximum number of lines we allow in the tooltip.
-const size_t kMaxLines = 6;
-
-// Trims the tooltip to fit, setting |text| to the clipped result, |max_width|
-// to the width (in pixels) of the clipped text and |line_count| to the number
-// of lines of text in the tooltip. |available_width| gives the space available
-// for the tooltip.
-void TrimTooltipToFit(const gfx::FontList& font_list,
- int available_width,
- base::string16* text,
- int* max_width,
- int* line_count) {
- *max_width = 0;
- *line_count = 0;
-
- TooltipManager::TrimTooltipText(text);
-
- // Split the string into at most kMaxLines lines.
- std::vector<base::string16> lines;
- base::SplitString(*text, '\n', &lines);
- if (lines.size() > kMaxLines)
- lines.resize(kMaxLines);
- *line_count = static_cast<int>(lines.size());
-
- // Format each line to fit.
- base::string16 result;
- for (std::vector<base::string16>::iterator i = lines.begin();
- i != lines.end(); ++i) {
- base::string16 elided_text =
- gfx::ElideText(*i, font_list, available_width, gfx::ELIDE_AT_END);
- *max_width = std::max(*max_width,
- gfx::GetStringWidth(elided_text, font_list));
- if (!result.empty())
- result.push_back('\n');
- result.append(elided_text);
- }
- *text = result;
-}
-
-} // namespace
-
-// static
-int TooltipManager::GetTooltipHeight() {
- DCHECK_GT(tooltip_height_, 0);
- return tooltip_height_;
-}
-
-static gfx::Font DetermineDefaultFont() {
- HWND window = CreateWindowEx(
- WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
- TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
- if (!window)
- return gfx::Font();
- HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
- gfx::Font font = hfont ? gfx::Font(hfont) : gfx::Font();
- DestroyWindow(window);
- return font;
-}
-
-TooltipManagerWin::TooltipManagerWin(Widget* widget)
- : widget_(widget),
- tooltip_hwnd_(NULL),
- last_mouse_pos_(-1, -1),
- tooltip_showing_(false),
- last_tooltip_view_(NULL),
- last_view_out_of_sync_(false),
- tooltip_width_(0) {
- DCHECK(widget);
- DCHECK(widget->GetNativeView());
-}
-
-TooltipManagerWin::~TooltipManagerWin() {
- if (tooltip_hwnd_)
- DestroyWindow(tooltip_hwnd_);
-}
-
-bool TooltipManagerWin::Init() {
- DCHECK(!tooltip_hwnd_);
- // Create the tooltip control.
- tooltip_hwnd_ = CreateWindowEx(
- WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
- TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
- GetParent(), NULL, NULL, NULL);
- if (!tooltip_hwnd_)
- return false;
-
- l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
-
- // This effectively turns off clipping of tooltips. We need this otherwise
- // multi-line text (\r\n) won't work right. The size doesn't really matter
- // (just as long as its bigger than the monitor's width) as we clip to the
- // screen size before rendering.
- SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
- std::numeric_limits<int16>::max());
-
- // Add one tool that is used for all tooltips.
- toolinfo_.cbSize = sizeof(toolinfo_);
- toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
- toolinfo_.hwnd = GetParent();
- toolinfo_.uId = reinterpret_cast<UINT_PTR>(GetParent());
- // Setting this tells windows to call GetParent() back (using a WM_NOTIFY
- // message) for the actual tooltip contents.
- toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
- toolinfo_.lpReserved = NULL;
- SetRectEmpty(&toolinfo_.rect);
- SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
- return true;
-}
-
-gfx::NativeView TooltipManagerWin::GetParent() {
- return widget_->GetNativeView();
-}
-
-const gfx::FontList& TooltipManagerWin::GetFontList() const {
- static gfx::FontList* font_list = NULL;
- if (!font_list)
- font_list = new gfx::FontList(DetermineDefaultFont());
- return *font_list;
-}
-
-void TooltipManagerWin::UpdateTooltip() {
- // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
- // This doesn't update the view under the mouse immediately as it may cause
- // timing problems.
- last_view_out_of_sync_ = true;
- last_tooltip_view_ = NULL;
- // Hide the tooltip.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-}
-
-void TooltipManagerWin::TooltipTextChanged(View* view) {
- if (view == last_tooltip_view_)
- UpdateTooltip(last_mouse_pos_);
-}
-
-LRESULT TooltipManagerWin::OnNotify(int w_param,
- NMHDR* l_param,
- bool* handled) {
- *handled = false;
- if (l_param->hwndFrom != tooltip_hwnd_)
- return 0;
-
- switch (l_param->code) {
- case TTN_GETDISPINFO: {
- if (last_view_out_of_sync_) {
- // View under the mouse is out of sync, determine it now.
- View* root_view = widget_->GetRootView();
- last_tooltip_view_ =
- root_view->GetTooltipHandlerForPoint(last_mouse_pos_);
- last_view_out_of_sync_ = false;
- }
- // Tooltip control is asking for the tooltip to display.
- NMTTDISPINFOW* tooltip_info =
- reinterpret_cast<NMTTDISPINFOW*>(l_param);
- // Initialize the string, if we have a valid tooltip the string will
- // get reset below.
- tooltip_info->szText[0] = TEXT('\0');
- tooltip_text_.clear();
- tooltip_info->lpszText = NULL;
- clipped_text_.clear();
- if (last_tooltip_view_ != NULL) {
- tooltip_text_.clear();
- // Mouse is over a View, ask the View for its tooltip.
- gfx::Point view_loc = last_mouse_pos_;
- View::ConvertPointToTarget(widget_->GetRootView(),
- last_tooltip_view_, &view_loc);
- if (last_tooltip_view_->GetTooltipText(view_loc, &tooltip_text_) &&
- !tooltip_text_.empty()) {
- // View has a valid tip, copy it into TOOLTIPINFO.
- clipped_text_ = tooltip_text_;
- gfx::Point screen_loc = last_mouse_pos_;
- View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
- TrimTooltipToFit(
- GetFontList(),
- GetMaxWidth(screen_loc.x(), screen_loc.y(),
- widget_->GetNativeView()),
- &clipped_text_, &tooltip_width_, &line_count_);
- // Adjust the clipped tooltip text for locale direction.
- base::i18n::AdjustStringForLocaleDirection(&clipped_text_);
- tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
- } else {
- tooltip_text_.clear();
- }
- }
- *handled = true;
- return 0;
- }
- case TTN_POP:
- tooltip_showing_ = false;
- *handled = true;
- return 0;
- case TTN_SHOW: {
- *handled = true;
- tooltip_showing_ = true;
- // The tooltip is about to show, allow the view to position it
- gfx::Point text_origin;
- if (tooltip_height_ == 0)
- tooltip_height_ = CalcTooltipHeight();
- gfx::Point view_loc = last_mouse_pos_;
- View::ConvertPointToTarget(widget_->GetRootView(),
- last_tooltip_view_, &view_loc);
- if (last_tooltip_view_->GetTooltipTextOrigin(view_loc, &text_origin) &&
- SetTooltipPosition(text_origin.x(), text_origin.y())) {
- // Return true, otherwise the rectangle we specified is ignored.
- return TRUE;
- }
- return 0;
- }
- default:
- // Fall through.
- break;
- }
- return 0;
-}
-
-bool TooltipManagerWin::SetTooltipPosition(int text_x, int text_y) {
- // NOTE: this really only tests that the y location fits on screen, but that
- // is good enough for our usage.
-
- // Calculate the bounds the tooltip will get.
- gfx::Point view_loc;
- View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
- view_loc = gfx::win::DIPToScreenPoint(view_loc);
- RECT bounds = { view_loc.x() + text_x,
- view_loc.y() + text_y,
- view_loc.x() + text_x + tooltip_width_,
- view_loc.y() + line_count_ * GetTooltipHeight() };
- SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
-
- // Make sure the rectangle completely fits on the current monitor. If it
- // doesn't, return false so that windows positions the tooltip at the
- // default location.
- gfx::Rect monitor_bounds =
- views::GetMonitorBoundsForRect(gfx::Rect(bounds.left, bounds.right,
- 0, 0));
- if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
- return false;
- }
-
- ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
- return true;
-}
-
-int TooltipManagerWin::CalcTooltipHeight() {
- // Ask the tooltip for its font.
- int height;
- HFONT hfont = reinterpret_cast<HFONT>(
- SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
- if (hfont != NULL) {
- base::win::ScopedGetDC dc(tooltip_hwnd_);
- base::win::ScopedSelectObject font(dc, hfont);
- gfx::ScopedSetMapMode mode(dc, MM_TEXT);
- TEXTMETRIC font_metrics;
- GetTextMetrics(dc, &font_metrics);
- height = font_metrics.tmHeight;
- } else {
- // Tooltip is using the system font. Use gfx::Font, which should pick
- // up the system font.
- height = gfx::Font().GetHeight();
- }
- // Get the margins from the tooltip
- RECT tooltip_margin;
- SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
- return height + tooltip_margin.top + tooltip_margin.bottom;
-}
-
-void TooltipManagerWin::UpdateTooltip(const gfx::Point& mouse_pos) {
- View* root_view = widget_->GetRootView();
- View* view = root_view->GetTooltipHandlerForPoint(mouse_pos);
- if (view != last_tooltip_view_) {
- // NOTE: This *must* be sent regardless of the visibility of the tooltip.
- // It triggers Windows to ask for the tooltip again.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- last_tooltip_view_ = view;
- } else if (last_tooltip_view_ != NULL) {
- // Tooltip is showing, and mouse is over the same view. See if the tooltip
- // text has changed.
- gfx::Point view_point = mouse_pos;
- View::ConvertPointToTarget(root_view, last_tooltip_view_, &view_point);
- string16 new_tooltip_text;
- bool has_tooltip_text =
- last_tooltip_view_->GetTooltipText(view_point, &new_tooltip_text);
- if (!has_tooltip_text || (new_tooltip_text != tooltip_text_)) {
- // The text has changed, hide the popup.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- if (has_tooltip_text && !new_tooltip_text.empty() && tooltip_showing_) {
- // New text is valid, show the popup.
- SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
- }
- }
- }
-}
-
-void TooltipManagerWin::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
- gfx::Point mouse_pos_in_pixels(l_param);
- gfx::Point mouse_pos = gfx::win::ScreenToDIPPoint(mouse_pos_in_pixels);
-
- if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
- // NC message coordinates are in screen coordinates.
- POINT temp = mouse_pos_in_pixels.ToPOINT();
- ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1);
- mouse_pos_in_pixels.SetPoint(temp.x, temp.y);
- mouse_pos = gfx::win::ScreenToDIPPoint(mouse_pos_in_pixels);
- }
-
- if (u_msg != WM_MOUSEMOVE || last_mouse_pos_ != mouse_pos) {
- last_mouse_pos_ = mouse_pos;
- UpdateTooltip(mouse_pos);
- }
- // Forward the message onto the tooltip.
- MSG msg;
- msg.hwnd = GetParent();
- msg.message = u_msg;
- msg.wParam = w_param;
- msg.lParam = l_param;
- SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/tooltip_manager_win.h b/chromium/ui/views/widget/tooltip_manager_win.h
deleted file mode 100644
index e12dfbb2859..00000000000
--- a/chromium/ui/views/widget/tooltip_manager_win.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
-#define UI_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
-
-#include <windows.h>
-#include <commctrl.h>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/point.h"
-#include "ui/views/widget/tooltip_manager.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace views {
-
-class View;
-class Widget;
-
-// TooltipManager implementation for Windows.
-//
-// This class is intended to be used by NativeWidgetWin. To use this, you must
-// do the following:
-// Add the following to your MSG_MAP:
-//
-// MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
-// MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
-// MSG_WM_NOTIFY(OnNotify)
-//
-// With the following implementations:
-// LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
-// BOOL& handled) {
-// tooltip_manager_->OnMouse(u_msg, w_param, l_param);
-// handled = FALSE;
-// return 0;
-// }
-//
-// LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
-// bool handled;
-// LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
-// SetMsgHandled(handled);
-// return result;
-// }
-//
-// And of course you'll need to create the TooltipManager!
-//
-// Lastly, you'll need to override GetTooltipManager.
-//
-// See NativeWidgetWin for an example of this in action.
-class TooltipManagerWin : public TooltipManager {
- public:
- // Creates a TooltipManager for the specified Widget and parent window.
- explicit TooltipManagerWin(Widget* widget);
- virtual ~TooltipManagerWin();
-
- // Initializes the TooltipManager returning whether initialization was
- // successful. If this returns false the TooltipManager should be destroyed
- // and not used.
- bool Init();
-
- // TooltipManager:
- virtual const gfx::FontList& TooltipManagerWin::GetFontList() const OVERRIDE;
- virtual void UpdateTooltip() OVERRIDE;
- virtual void TooltipTextChanged(View* view) OVERRIDE;
-
- // Message handlers. These forward to the tooltip control.
- virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
- LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
-
- protected:
- // Returns the Widget we're showing tooltips for.
- gfx::NativeView GetParent();
-
- // Updates the tooltip for the specified location.
- void UpdateTooltip(const gfx::Point& location);
-
- // Tooltip control window.
- HWND tooltip_hwnd_;
-
- // Tooltip information.
- TOOLINFO toolinfo_;
-
- // Last location of the mouse. This is in the coordinates of the rootview.
- gfx::Point last_mouse_pos_;
-
- // Whether or not the tooltip is showing.
- bool tooltip_showing_;
-
- private:
- // Sets the tooltip position based on the x/y position of the text. If the
- // tooltip fits, true is returned.
- bool SetTooltipPosition(int text_x, int text_y);
-
- // Calculates the preferred height for tooltips. This always returns a
- // positive value.
- int CalcTooltipHeight();
-
- // Hosting Widget.
- Widget* widget_;
-
- // The View the mouse is under. This is null if the mouse isn't under a
- // View.
- View* last_tooltip_view_;
-
- // Whether or not the view under the mouse needs to be refreshed. If this
- // is true, when the tooltip is asked for the view under the mouse is
- // refreshed.
- bool last_view_out_of_sync_;
-
- // Text for tooltip from the view.
- string16 tooltip_text_;
-
- // The clipped tooltip.
- string16 clipped_text_;
-
- // Number of lines in the tooltip.
- int line_count_;
-
- // Width of the last tooltip.
- int tooltip_width_;
-
- DISALLOW_COPY_AND_ASSIGN(TooltipManagerWin);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_TOOLTIP_MANAGER_WIN_H_
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index b050ae60ef4..3f4a1707fbc 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/cursor/cursor.h"
#include "ui/base/default_theme_provider.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_font_util.h"
@@ -15,6 +16,7 @@
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
+#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/focus/focus_manager.h"
@@ -29,13 +31,10 @@
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_deletion_observer.h"
#include "ui/views/widget/widget_observer.h"
+#include "ui/views/widget/widget_removals_observer.h"
#include "ui/views/window/custom_frame_view.h"
#include "ui/views/window/dialog_delegate.h"
-#if defined(USE_AURA)
-#include "ui/base/cursor/cursor.h"
-#endif
-
namespace views {
namespace {
@@ -70,11 +69,7 @@ NativeWidget* CreateNativeWidget(NativeWidget* native_widget,
// WidgetDelegate is supplied.
class DefaultWidgetDelegate : public WidgetDelegate {
public:
- DefaultWidgetDelegate(Widget* widget, const Widget::InitParams& params)
- : widget_(widget),
- can_activate_(!params.child &&
- params.type != Widget::InitParams::TYPE_POPUP &&
- params.type != Widget::InitParams::TYPE_DRAG) {
+ explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) {
}
virtual ~DefaultWidgetDelegate() {}
@@ -88,9 +83,6 @@ class DefaultWidgetDelegate : public WidgetDelegate {
virtual const Widget* GetWidget() const OVERRIDE {
return widget_;
}
- virtual bool CanActivate() const OVERRIDE {
- return can_activate_;
- }
virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
// In most situations where a Widget is used without a delegate the Widget
// is used as a container, so that we want focus to advance to the top-level
@@ -100,7 +92,6 @@ class DefaultWidgetDelegate : public WidgetDelegate {
private:
Widget* widget_;
- bool can_activate_;
DISALLOW_COPY_AND_ASSIGN(DefaultWidgetDelegate);
};
@@ -112,52 +103,48 @@ Widget::InitParams::InitParams()
: type(TYPE_WINDOW),
delegate(NULL),
child(false),
- opacity((ViewsDelegate::views_delegate &&
- ViewsDelegate::views_delegate->UseTransparentWindows()) ?
- TRANSLUCENT_WINDOW : INFER_OPACITY),
+ opacity(INFER_OPACITY),
accept_events(true),
- can_activate(true),
+ activatable(ACTIVATABLE_DEFAULT),
keep_on_top(false),
+ visible_on_all_workspaces(false),
ownership(NATIVE_WIDGET_OWNS_WIDGET),
mirror_origin_in_rtl(false),
- has_dropshadow(false),
+ shadow_type(SHADOW_TYPE_DEFAULT),
remove_standard_frame(false),
use_system_default_icon(false),
show_state(ui::SHOW_STATE_DEFAULT),
double_buffer(false),
parent(NULL),
native_widget(NULL),
- desktop_root_window_host(NULL),
- top_level(false),
- layer_type(ui::LAYER_TEXTURED),
- context(NULL) {
+ desktop_window_tree_host(NULL),
+ layer_type(aura::WINDOW_LAYER_TEXTURED),
+ context(NULL),
+ force_show_in_taskbar(false) {
}
Widget::InitParams::InitParams(Type type)
: type(type),
delegate(NULL),
- child(type == TYPE_CONTROL),
- opacity(((type == TYPE_WINDOW || type == TYPE_PANEL) &&
- ViewsDelegate::views_delegate &&
- ViewsDelegate::views_delegate->UseTransparentWindows()) ?
- TRANSLUCENT_WINDOW : INFER_OPACITY),
+ child(false),
+ opacity(INFER_OPACITY),
accept_events(true),
- can_activate(type != TYPE_POPUP && type != TYPE_MENU &&
- type != TYPE_DRAG),
+ activatable(ACTIVATABLE_DEFAULT),
keep_on_top(type == TYPE_MENU || type == TYPE_DRAG),
+ visible_on_all_workspaces(false),
ownership(NATIVE_WIDGET_OWNS_WIDGET),
mirror_origin_in_rtl(false),
- has_dropshadow(false),
+ shadow_type(SHADOW_TYPE_DEFAULT),
remove_standard_frame(false),
use_system_default_icon(false),
show_state(ui::SHOW_STATE_DEFAULT),
double_buffer(false),
parent(NULL),
native_widget(NULL),
- desktop_root_window_host(NULL),
- top_level(false),
- layer_type(ui::LAYER_TEXTURED),
- context(NULL) {
+ desktop_window_tree_host(NULL),
+ layer_type(aura::WINDOW_LAYER_TEXTURED),
+ context(NULL),
+ force_show_in_taskbar(false) {
}
Widget::InitParams::~InitParams() {
@@ -186,7 +173,8 @@ Widget::Widget()
last_mouse_event_was_move_(false),
auto_release_capture_(true),
root_layers_dirty_(false),
- movement_disabled_(false) {
+ movement_disabled_(false),
+ observer_manager_(this) {
}
Widget::~Widget() {
@@ -212,20 +200,19 @@ Widget* Widget::CreateWindowWithBounds(WidgetDelegate* delegate,
Widget::InitParams params;
params.bounds = bounds;
params.delegate = delegate;
- params.top_level = true;
widget->Init(params);
return widget;
}
// static
Widget* Widget::CreateWindowWithParent(WidgetDelegate* delegate,
- gfx::NativeWindow parent) {
+ gfx::NativeView parent) {
return CreateWindowWithParentAndBounds(delegate, parent, gfx::Rect());
}
// static
Widget* Widget::CreateWindowWithParentAndBounds(WidgetDelegate* delegate,
- gfx::NativeWindow parent,
+ gfx::NativeView parent,
const gfx::Rect& bounds) {
Widget* widget = new Widget;
Widget::InitParams params;
@@ -256,24 +243,6 @@ Widget* Widget::CreateWindowWithContextAndBounds(WidgetDelegate* delegate,
}
// static
-Widget* Widget::CreateWindowAsFramelessChild(WidgetDelegate* widget_delegate,
- gfx::NativeView parent) {
- views::Widget* widget = new views::Widget;
-
- views::Widget::InitParams params;
- params.delegate = widget_delegate;
- params.child = true;
- params.parent = parent;
- params.remove_standard_frame = true;
-#if defined(USE_AURA)
- params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-#endif
-
- widget->Init(params);
- return widget;
-}
-
-// static
Widget* Widget::GetWidgetForNativeView(gfx::NativeView native_view) {
internal::NativeWidgetPrivate* native_widget =
internal::NativeWidgetPrivate::GetNativeWidgetForNativeView(native_view);
@@ -344,29 +313,39 @@ void Widget::Init(const InitParams& in_params) {
TRACE_EVENT0("views", "Widget::Init");
InitParams params = in_params;
- is_top_level_ = params.top_level ||
- (!params.child &&
- params.type != InitParams::TYPE_CONTROL &&
- params.type != InitParams::TYPE_TOOLTIP);
- params.top_level = is_top_level_;
- if (params.opacity == InitParams::INFER_OPACITY) {
-#if defined(OS_WIN) && defined(USE_AURA)
- // By default, make all top-level windows but the main window transparent
- // initially so that they can be made to fade in.
- if (is_top_level_ && params.type != InitParams::TYPE_WINDOW)
- params.opacity = InitParams::TRANSLUCENT_WINDOW;
- else
- params.opacity = InitParams::OPAQUE_WINDOW;
-#else
- params.opacity = InitParams::OPAQUE_WINDOW;
-#endif
- }
+ params.child |= (params.type == InitParams::TYPE_CONTROL);
+ is_top_level_ = !params.child;
+
+ if (params.opacity == views::Widget::InitParams::INFER_OPACITY &&
+ params.type != views::Widget::InitParams::TYPE_WINDOW &&
+ params.type != views::Widget::InitParams::TYPE_PANEL)
+ params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
if (ViewsDelegate::views_delegate)
ViewsDelegate::views_delegate->OnBeforeWidgetInit(&params, this);
+ if (params.opacity == views::Widget::InitParams::INFER_OPACITY)
+ params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
+
+ bool can_activate = false;
+ if (params.activatable != InitParams::ACTIVATABLE_DEFAULT) {
+ can_activate = (params.activatable == InitParams::ACTIVATABLE_YES);
+ } else if (params.type != InitParams::TYPE_CONTROL &&
+ params.type != InitParams::TYPE_POPUP &&
+ params.type != InitParams::TYPE_MENU &&
+ params.type != InitParams::TYPE_TOOLTIP &&
+ params.type != InitParams::TYPE_DRAG) {
+ can_activate = true;
+ params.activatable = InitParams::ACTIVATABLE_YES;
+ } else {
+ can_activate = false;
+ params.activatable = InitParams::ACTIVATABLE_NO;
+ }
+
widget_delegate_ = params.delegate ?
- params.delegate : new DefaultWidgetDelegate(this, params);
+ params.delegate : new DefaultWidgetDelegate(this);
+ widget_delegate_->set_can_activate(can_activate);
+
ownership_ = params.ownership;
native_widget_ = CreateNativeWidget(params.native_widget, this)->
AsNativeWidgetPrivate();
@@ -388,6 +367,7 @@ void Widget::Init(const InitParams& in_params) {
// Initialize the window's title before setting the window's initial bounds;
// the frame view's preferred height may depend on the presence of a title.
UpdateWindowTitle();
+ non_client_view_->ResetWindowControls();
SetInitialBounds(params.bounds);
if (params.show_state == ui::SHOW_STATE_MAXIMIZED)
Maximize();
@@ -397,6 +377,9 @@ void Widget::Init(const InitParams& in_params) {
SetContentsView(params.delegate->GetContentsView());
SetInitialBoundsForFramelessWindow(params.bounds);
}
+ // This must come after SetContentsView() or it might not be able to find
+ // the correct NativeTheme (on Linux). See http://crbug.com/384492
+ observer_manager_.Add(GetNativeTheme());
native_widget_initialized_ = true;
}
@@ -422,7 +405,19 @@ bool Widget::HasObserver(WidgetObserver* observer) {
return observers_.HasObserver(observer);
}
-bool Widget::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
+void Widget::AddRemovalsObserver(WidgetRemovalsObserver* observer) {
+ removals_observers_.AddObserver(observer);
+}
+
+void Widget::RemoveRemovalsObserver(WidgetRemovalsObserver* observer) {
+ removals_observers_.RemoveObserver(observer);
+}
+
+bool Widget::HasRemovalsObserver(WidgetRemovalsObserver* observer) {
+ return removals_observers_.HasObserver(observer);
+}
+
+bool Widget::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) const {
return false;
}
@@ -451,6 +446,12 @@ void Widget::NotifyNativeViewHierarchyChanged() {
root_view_->NotifyNativeViewHierarchyChanged();
}
+void Widget::NotifyWillRemoveView(View* view) {
+ FOR_EACH_OBSERVER(WidgetRemovalsObserver,
+ removals_observers_,
+ OnWillRemoveView(this, view));
+}
+
// Converted methods (see header) ----------------------------------------------
Widget* Widget::GetTopLevelWidget() {
@@ -616,7 +617,9 @@ void Widget::Show() {
// it is subsequently shown after being hidden.
saved_show_state_ = ui::SHOW_STATE_NORMAL;
} else {
- native_widget_->Show();
+ CanActivate()
+ ? native_widget_->Show()
+ : native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
}
}
@@ -661,6 +664,10 @@ bool Widget::IsAlwaysOnTop() const {
return native_widget_->IsAlwaysOnTop();
}
+void Widget::SetVisibleOnAllWorkspaces(bool always_visible) {
+ native_widget_->SetVisibleOnAllWorkspaces(always_visible);
+}
+
void Widget::Maximize() {
native_widget_->Maximize();
}
@@ -770,6 +777,10 @@ const InputMethod* Widget::GetInputMethod() const {
}
}
+ui::InputMethod* Widget::GetHostInputMethod() {
+ return native_widget_private()->GetHostInputMethod();
+}
+
void Widget::RunShellDrag(View* view,
const ui::OSExchangeData& data,
const gfx::Point& location,
@@ -811,7 +822,7 @@ void Widget::UpdateWindowTitle() {
// Update the native frame's text. We do this regardless of whether or not
// the native frame is being used, since this also updates the taskbar, etc.
- string16 window_title = widget_delegate_->GetWindowTitle();
+ base::string16 window_title = widget_delegate_->GetWindowTitle();
base::i18n::AdjustStringForLocaleDirection(&window_title);
if (!native_widget_->SetWindowTitle(window_title))
return;
@@ -876,6 +887,10 @@ bool Widget::ShouldUseNativeFrame() const {
return native_widget_->ShouldUseNativeFrame();
}
+bool Widget::ShouldWindowContentsBeTransparent() const {
+ return native_widget_->ShouldWindowContentsBeTransparent();
+}
+
void Widget::DebugToggleFrameType() {
if (frame_type_ == FRAME_TYPE_DEFAULT) {
frame_type_ = ShouldUseNativeFrame() ? FRAME_TYPE_FORCE_CUSTOM :
@@ -949,20 +964,6 @@ const TooltipManager* Widget::GetTooltipManager() const {
return native_widget_->GetTooltipManager();
}
-bool Widget::SetInitialFocus() {
- View* v = widget_delegate_->GetInitiallyFocusedView();
- if (!focus_on_creation_) {
- // If not focusing the window now, tell the focus manager which view to
- // focus when the window is restored.
- if (v)
- focus_manager_->SetStoredFocusView(v);
- return true;
- }
- if (v)
- v->RequestFocus();
- return !!v;
-}
-
gfx::Rect Widget::GetWorkAreaBoundsInScreen() const {
return native_widget_->GetWorkAreaBoundsInScreen();
}
@@ -972,7 +973,7 @@ void Widget::SynthesizeMouseMoveEvent() {
ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED,
last_mouse_event_position_,
last_mouse_event_position_,
- ui::EF_IS_SYNTHESIZED);
+ ui::EF_IS_SYNTHESIZED, 0);
root_view_->OnMouseMoved(mouse_event);
}
@@ -980,6 +981,10 @@ void Widget::OnRootViewLayout() {
native_widget_->OnRootViewLayout();
}
+bool Widget::IsTranslucentWindowOpacitySupported() const {
+ return native_widget_->IsTranslucentWindowOpacitySupported();
+}
+
void Widget::OnOwnerClosing() {
}
@@ -1015,6 +1020,22 @@ void Widget::OnNativeWidgetActivationChanged(bool active) {
FOR_EACH_OBSERVER(WidgetObserver, observers_,
OnWidgetActivationChanged(this, active));
+
+ // During window creation, the widget gets focused without activation, and in
+ // that case, the focus manager cannot set the appropriate text input client
+ // because the widget is not active. Thus we have to notify the focus manager
+ // not only when the focus changes but also when the widget gets activated.
+ // See crbug.com/377479 for details.
+ views::FocusManager* focus_manager = GetFocusManager();
+ if (focus_manager) {
+ if (active)
+ focus_manager->FocusTextInputClient(focus_manager->GetFocusedView());
+ else
+ focus_manager->BlurTextInputClient(focus_manager->GetFocusedView());
+ }
+
+ if (IsVisible() && non_client_view())
+ non_client_view()->frame_view()->SchedulePaint();
}
void Widget::OnNativeFocus(gfx::NativeView old_focused_view) {
@@ -1069,24 +1090,37 @@ void Widget::OnNativeWidgetDestroyed() {
native_widget_destroyed_ = true;
}
-gfx::Size Widget::GetMinimumSize() {
+gfx::Size Widget::GetMinimumSize() const {
return non_client_view_ ? non_client_view_->GetMinimumSize() : gfx::Size();
}
-gfx::Size Widget::GetMaximumSize() {
+gfx::Size Widget::GetMaximumSize() const {
return non_client_view_ ? non_client_view_->GetMaximumSize() : gfx::Size();
}
void Widget::OnNativeWidgetMove() {
widget_delegate_->OnWidgetMove();
+ View* root = GetRootView();
+ if (root && root->GetFocusManager()) {
+ View* focused_view = root->GetFocusManager()->GetFocusedView();
+ if (focused_view && focused_view->GetInputMethod())
+ focused_view->GetInputMethod()->OnCaretBoundsChanged(focused_view);
+ }
FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetBoundsChanged(
this,
GetWindowBoundsInScreen()));
}
void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) {
- root_view_->SetSize(new_size);
-
+ View* root = GetRootView();
+ if (root) {
+ root->SetSize(new_size);
+ if (root->GetFocusManager()) {
+ View* focused_view = GetRootView()->GetFocusManager()->GetFocusedView();
+ if (focused_view && focused_view->GetInputMethod())
+ focused_view->GetInputMethod()->OnCaretBoundsChanged(focused_view);
+ }
+ }
// Size changed notifications can fire prior to full initialization
// i.e. during session restore. Avoid saving session state during these
// startup procedures.
@@ -1123,7 +1157,7 @@ void Widget::OnNativeWidgetPaint(gfx::Canvas* canvas) {
// On Linux Aura, we can get here during Init() because of the
// SetInitialBounds call.
if (native_widget_initialized_)
- GetRootView()->Paint(canvas);
+ GetRootView()->Paint(canvas, CullSet());
}
int Widget::GetNonClientComponent(const gfx::Point& point) {
@@ -1138,10 +1172,12 @@ int Widget::GetNonClientComponent(const gfx::Point& point) {
}
void Widget::OnKeyEvent(ui::KeyEvent* event) {
- static_cast<internal::RootView*>(GetRootView())->
- DispatchKeyEvent(event);
+ SendEventToProcessor(event);
}
+// TODO(tdanderson): We should not be calling the OnMouse*() functions on
+// RootView from anywhere in Widget. Use
+// SendEventToProcessor() instead. See crbug.com/348087.
void Widget::OnMouseEvent(ui::MouseEvent* event) {
View* root_view = GetRootView();
switch (event->type()) {
@@ -1172,6 +1208,7 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
}
return;
}
+
case ui::ET_MOUSE_RELEASED:
last_mouse_event_was_move_ = false;
is_mouse_button_pressed_ = false;
@@ -1183,6 +1220,7 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0)
event->SetHandled();
return;
+
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_DRAGGED:
if (native_widget_->HasCapture() && is_mouse_button_pressed_) {
@@ -1197,20 +1235,22 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
root_view->OnMouseMoved(*event);
}
return;
+
case ui::ET_MOUSE_EXITED:
last_mouse_event_was_move_ = false;
if (root_view)
root_view->OnMouseExited(*event);
return;
+
case ui::ET_MOUSEWHEEL:
if (root_view && root_view->OnMouseWheel(
static_cast<const ui::MouseWheelEvent&>(*event)))
event->SetHandled();
return;
+
default:
return;
}
- event->SetHandled();
}
void Widget::OnMouseCaptureLost() {
@@ -1223,14 +1263,15 @@ void Widget::OnMouseCaptureLost() {
is_mouse_button_pressed_ = false;
}
-void Widget::OnTouchEvent(ui::TouchEvent* event) {
- static_cast<internal::RootView*>(GetRootView())->
- DispatchTouchEvent(event);
-}
-
void Widget::OnScrollEvent(ui::ScrollEvent* event) {
- static_cast<internal::RootView*>(GetRootView())->
- DispatchScrollEvent(event);
+ ui::ScrollEvent event_copy(*event);
+ SendEventToProcessor(&event_copy);
+
+ // Convert unhandled ui::ET_SCROLL events into ui::ET_MOUSEWHEEL events.
+ if (!event_copy.handled() && event_copy.type() == ui::ET_SCROLL) {
+ ui::MouseWheelEvent wheel(*event);
+ OnMouseEvent(&wheel);
+ }
}
void Widget::OnGestureEvent(ui::GestureEvent* event) {
@@ -1243,17 +1284,14 @@ void Widget::OnGestureEvent(ui::GestureEvent* event) {
break;
case ui::ET_GESTURE_END:
- if (event->details().touch_points() == 1) {
+ if (event->details().touch_points() == 1)
is_touch_down_ = false;
- if (auto_release_capture_)
- ReleaseCapture();
- }
break;
default:
break;
}
- static_cast<internal::RootView*>(GetRootView())->DispatchGestureEvent(event);
+ SendEventToProcessor(event);
}
bool Widget::ExecuteCommand(int command_id) {
@@ -1290,6 +1328,27 @@ const Widget* Widget::AsWidget() const {
return this;
}
+bool Widget::SetInitialFocus(ui::WindowShowState show_state) {
+ View* v = widget_delegate_->GetInitiallyFocusedView();
+ if (!focus_on_creation_ || show_state == ui::SHOW_STATE_INACTIVE ||
+ show_state == ui::SHOW_STATE_MINIMIZED) {
+ // If not focusing the window now, tell the focus manager which view to
+ // focus when the window is restored.
+ if (v)
+ focus_manager_->SetStoredFocusView(v);
+ return true;
+ }
+ if (v)
+ v->RequestFocus();
+ return !!v;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, ui::EventSource implementation:
+ui::EventProcessor* Widget::GetEventProcessor() {
+ return root_view_.get();
+}
+
////////////////////////////////////////////////////////////////////////////////
// Widget, FocusTraversable implementation:
@@ -1312,6 +1371,21 @@ View* Widget::GetFocusTraversableParentView() {
}
////////////////////////////////////////////////////////////////////////////////
+// Widget, ui::NativeThemeObserver implementation:
+
+void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+ DCHECK(observer_manager_.IsObserving(observed_theme));
+
+ ui::NativeTheme* current_native_theme = GetNativeTheme();
+ if (!observer_manager_.IsObserving(current_native_theme)) {
+ observer_manager_.RemoveAll();
+ observer_manager_.Add(current_native_theme);
+ }
+
+ root_view_->PropagateNativeThemeChanged(current_native_theme);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Widget, protected:
internal::RootView* Widget::CreateRootView() {
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index ce14d7c5bff..c76633b282f 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -12,10 +12,13 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/window_layer_type.h"
#include "ui/base/ui_base_types.h"
-#include "ui/compositor/layer_type.h"
+#include "ui/events/event_source.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
+#include "ui/native_theme/native_theme_observer.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/window/client_view.h"
@@ -44,6 +47,7 @@ namespace ui {
class Accelerator;
class Compositor;
class DefaultThemeProvider;
+class InputMethod;
class Layer;
class NativeTheme;
class OSExchangeData;
@@ -52,7 +56,7 @@ class ThemeProvider;
namespace views {
-class DesktopRootWindowHost;
+class DesktopWindowTreeHost;
class InputMethod;
class NativeWidget;
class NonClientFrameView;
@@ -60,6 +64,7 @@ class TooltipManager;
class View;
class WidgetDelegate;
class WidgetObserver;
+class WidgetRemovalsObserver;
namespace internal {
class NativeWidgetPrivate;
@@ -92,7 +97,9 @@ class RootView;
// destructor).
//
class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
- public FocusTraversable {
+ public ui::EventSource,
+ public FocusTraversable,
+ public ui::NativeThemeObserver {
public:
typedef std::set<Widget*> Widgets;
@@ -155,6 +162,14 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
TRANSLUCENT_WINDOW,
};
+ enum Activatable {
+ // Infer whether the window should be activatable from the window type.
+ ACTIVATABLE_DEFAULT,
+
+ ACTIVATABLE_YES,
+ ACTIVATABLE_NO
+ };
+
enum Ownership {
// Default. Creator is not responsible for managing the lifetime of the
// Widget, it is destroyed when the corresponding NativeWidget is
@@ -165,33 +180,42 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
WIDGET_OWNS_NATIVE_WIDGET
};
+ enum ShadowType {
+ SHADOW_TYPE_DEFAULT, // Use default shadow setting. It will be one of
+ // the settings below depending on InitParams::type
+ // and the native widget's type.
+ SHADOW_TYPE_NONE, // Don't draw any shadow.
+ SHADOW_TYPE_DROP, // Draw a drop shadow that emphasizes Z-order
+ // relationship to other windows.
+ };
+
InitParams();
explicit InitParams(Type type);
~InitParams();
- // Will return the first of the following that isn't NULL: the native view,
- // |parent|, |context|.
- gfx::NativeView GetContext() const;
-
Type type;
// If NULL, a default implementation will be constructed.
WidgetDelegate* delegate;
bool child;
// If TRANSLUCENT_WINDOW, the widget may be fully or partially transparent.
+ // Translucent windows may not always be supported. Use
+ // IsTranslucentWindowOpacitySupported to determine if translucent windows
+ // are supported.
// If OPAQUE_WINDOW, we can perform optimizations based on the widget being
// fully opaque. Defaults to TRANSLUCENT_WINDOW if
// ViewsDelegate::UseTransparentWindows(). Defaults to OPAQUE_WINDOW for
// non-window widgets.
WindowOpacity opacity;
bool accept_events;
- bool can_activate;
+ Activatable activatable;
bool keep_on_top;
+ bool visible_on_all_workspaces;
Ownership ownership;
bool mirror_origin_in_rtl;
- bool has_dropshadow;
- // Only used by Windows. Specifies that the system default caption and icon
- // should not be rendered, and that the client area should be equivalent to
- // the window area.
+ ShadowType shadow_type;
+ // Specifies that the system default caption and icon should not be
+ // rendered, and that the client area should be equivalent to the window
+ // area. Only used on some platforms (Windows and Linux).
bool remove_standard_frame;
// Only used by ShellWindow on Windows. Specifies that the default icon of
// packaged app should be the system default icon.
@@ -209,18 +233,14 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// When set, this value is used as the Widget's NativeWidget implementation.
// The Widget will not construct a default one. Default is NULL.
NativeWidget* native_widget;
- // Aura-only. Provides a DesktopRootWindowHost implementation to use instead
+ // Aura-only. Provides a DesktopWindowTreeHost implementation to use instead
// of the default one.
// TODO(beng): Figure out if there's a better way to expose this, e.g. get
// rid of NW subclasses and do this all via message handling.
- DesktopRootWindowHost* desktop_root_window_host;
- // Whether this window is intended to be a toplevel window with no
- // attachment to any other window. (This may be a transient window if
- // |parent| is set.)
- bool top_level;
+ DesktopWindowTreeHost* desktop_window_tree_host;
// Only used by NativeWidgetAura. Specifies the type of layer for the
- // aura::Window. Default is LAYER_TEXTURED.
- ui::LayerType layer_type;
+ // aura::Window. Default is WINDOW_LAYER_TEXTURED.
+ aura::WindowLayerType layer_type;
// Only used by Aura. Provides a context window whose RootWindow is
// consulted during widget creation to determine where in the Window
// hierarchy this widget should be placed. (This is separate from |parent|;
@@ -229,6 +249,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// where it wants your window placed.) NULL is not allowed if you are using
// aura.
gfx::NativeView 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).
+ bool force_show_in_taskbar;
// Only used by X11, for root level windows. Specifies the res_name and
// res_class fields, respectively, of the WM_CLASS window property. Controls
// window grouping and desktop file matching in Linux window managers.
@@ -253,9 +276,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Creates a decorated window Widget with the specified properties.
static Widget* CreateWindowWithParent(WidgetDelegate* delegate,
- gfx::NativeWindow parent);
+ gfx::NativeView parent);
static Widget* CreateWindowWithParentAndBounds(WidgetDelegate* delegate,
- gfx::NativeWindow parent,
+ gfx::NativeView parent,
const gfx::Rect& bounds);
// Creates a decorated window Widget in the same desktop context as |context|.
@@ -265,15 +288,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
gfx::NativeView context,
const gfx::Rect& bounds);
- // Creates an undecorated child window Widget parented to |parent|.
- static Widget* CreateWindowAsFramelessChild(WidgetDelegate* widget_delegate,
- gfx::NativeView parent);
-
- // Enumerates all windows pertaining to us and notifies their
- // view hierarchies that the locale has changed.
- // TODO(beng): remove post-Aurafication of ChromeOS.
- static void NotifyLocaleChanged();
-
// Closes all Widgets that aren't identified as "secondary widgets". Called
// during application shutdown when the last non-secondary widget is closed.
static void CloseAllSecondaryWidgets();
@@ -341,9 +355,14 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
void RemoveObserver(WidgetObserver* observer);
bool HasObserver(WidgetObserver* observer);
+ // Add/remove removals observer.
+ void AddRemovalsObserver(WidgetRemovalsObserver* observer);
+ void RemoveRemovalsObserver(WidgetRemovalsObserver* observer);
+ bool HasRemovalsObserver(WidgetRemovalsObserver* observer);
+
// Returns the accelerator given a command id. Returns false if there is
// no accelerator associated with a given id, which is a common condition.
- virtual bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator);
+ virtual bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator) const;
// Forwarded from the RootView so that the widget can do any cleanup.
void ViewHierarchyChanged(const View::ViewHierarchyChangedDetails& details);
@@ -356,6 +375,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// about the change.
void NotifyNativeViewHierarchyChanged();
+ // Called immediately before removing |view| from this widget.
+ void NotifyWillRemoveView(View* view);
+
// Returns the top level widget in a hierarchy (see is_top_level() for
// the definition of top level widget.) Will return NULL if called
// before the widget is attached to the top level widget's hierarchy.
@@ -434,8 +456,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// set to true after Close() has been invoked on the NativeWidget.
bool IsClosed() const;
- // Shows or hides the widget, without changing activation state.
+ // Shows the widget. The widget is activated if during initialization the
+ // can_activate flag in the InitParams structure is set to true.
virtual void Show();
+ // Hides the widget.
void Hide();
// Like Show(), but does not activate the window.
@@ -464,6 +488,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// in the windowing system.
bool IsAlwaysOnTop() const;
+ // Sets the widget to be visible on all work spaces.
+ void SetVisibleOnAllWorkspaces(bool always_visible);
+
// Maximizes/minimizes/restores the window.
void Maximize();
void Minimize();
@@ -527,6 +554,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
InputMethod* GetInputMethod();
const InputMethod* GetInputMethod() const;
+ // Returns the ui::InputMethod for this widget.
+ // TODO(yukishiino): Rename this method to GetInputMethod once we remove
+ // views::InputMethod.
+ ui::InputMethod* GetHostInputMethod();
+
// Starts a drag operation for the specified view. This blocks until the drag
// operation completes. |view| can be NULL.
// If the view is non-NULL it can be accessed during the drag by calling
@@ -595,6 +627,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Whether we should be using a native frame.
bool ShouldUseNativeFrame() const;
+ // Determines whether the window contents should be rendered transparently
+ // (for example, so that they can overhang onto the window title bar).
+ bool ShouldWindowContentsBeTransparent() const;
+
// Forces the frame into the alternate frame type (custom or native) depending
// on its current state.
void DebugToggleFrameType();
@@ -668,12 +704,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
TooltipManager* GetTooltipManager();
const TooltipManager* GetTooltipManager() const;
- // Sets-up the focus manager with the view that should have focus when the
- // window is shown the first time. Returns true if the initial focus has been
- // set or the widget should not set the initial focus, or false if the caller
- // should set the initial focus (if any).
- bool SetInitialFocus();
-
void set_focus_on_creation(bool focus_on_creation) {
focus_on_creation_ = focus_on_creation;
}
@@ -699,6 +729,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// window sizing information to the window server on some platforms.
void OnRootViewLayout();
+ // Whether the widget supports translucency.
+ bool IsTranslucentWindowOpacitySupported() const;
+
// Notification that our owner is closing.
// NOTE: this is not invoked for aura as it's currently not needed there.
// Under aura menus close by way of activation getting reset when the owner
@@ -719,8 +752,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
virtual void OnNativeWidgetCreated(bool desktop_widget) OVERRIDE;
virtual void OnNativeWidgetDestroying() OVERRIDE;
virtual void OnNativeWidgetDestroyed() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
virtual void OnNativeWidgetMove() OVERRIDE;
virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE;
virtual void OnNativeWidgetBeginUserBoundsChange() OVERRIDE;
@@ -733,7 +766,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
virtual bool ExecuteCommand(int command_id) OVERRIDE;
@@ -743,12 +775,19 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
virtual Widget* AsWidget() OVERRIDE;
virtual const Widget* AsWidget() const OVERRIDE;
+ virtual bool SetInitialFocus(ui::WindowShowState show_state) OVERRIDE;
+
+ // Overridden from ui::EventSource:
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE;
// Overridden from FocusTraversable:
virtual FocusSearch* GetFocusSearch() OVERRIDE;
virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
virtual View* GetFocusTraversableParentView() OVERRIDE;
+ // Overridden from ui::NativeThemeObserver:
+ virtual void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) OVERRIDE;
+
protected:
// Creates the RootView to be used within this Widget. Subclasses may override
// to create custom RootViews that do specialized event processing.
@@ -762,7 +801,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
private:
friend class ComboboxTest;
- friend class NativeTextfieldViewsTest;
+ friend class TextfieldTest;
// Sets the value of |disable_inactive_rendering_|. If the value changes,
// both the NonClientView and WidgetDelegate are notified.
@@ -795,6 +834,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
ObserverList<WidgetObserver> observers_;
+ ObserverList<WidgetRemovalsObserver> removals_observers_;
+
// Non-owned pointer to the Widget's delegate. If a NULL delegate is supplied
// to Init() a default WidgetDelegate is created.
WidgetDelegate* widget_delegate_;
@@ -892,6 +933,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// disabled.
bool movement_disabled_;
+ ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver> observer_manager_;
+
DISALLOW_COPY_AND_ASSIGN(Widget);
};
diff --git a/chromium/ui/views/widget/widget_aura_utils.cc b/chromium/ui/views/widget/widget_aura_utils.cc
index 348f828ff8f..be284a8af81 100644
--- a/chromium/ui/views/widget/widget_aura_utils.cc
+++ b/chromium/ui/views/widget/widget_aura_utils.cc
@@ -8,27 +8,27 @@
namespace views {
-aura::client::WindowType GetAuraWindowTypeForWidgetType(
+ui::wm::WindowType GetAuraWindowTypeForWidgetType(
Widget::InitParams::Type type) {
switch (type) {
case Widget::InitParams::TYPE_WINDOW:
- return aura::client::WINDOW_TYPE_NORMAL;
+ return ui::wm::WINDOW_TYPE_NORMAL;
case Widget::InitParams::TYPE_PANEL:
- return aura::client::WINDOW_TYPE_PANEL;
+ return ui::wm::WINDOW_TYPE_PANEL;
case Widget::InitParams::TYPE_CONTROL:
- return aura::client::WINDOW_TYPE_CONTROL;
+ return ui::wm::WINDOW_TYPE_CONTROL;
case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
case Widget::InitParams::TYPE_POPUP:
case Widget::InitParams::TYPE_BUBBLE:
case Widget::InitParams::TYPE_DRAG:
- return aura::client::WINDOW_TYPE_POPUP;
+ return ui::wm::WINDOW_TYPE_POPUP;
case Widget::InitParams::TYPE_MENU:
- return aura::client::WINDOW_TYPE_MENU;
+ return ui::wm::WINDOW_TYPE_MENU;
case Widget::InitParams::TYPE_TOOLTIP:
- return aura::client::WINDOW_TYPE_TOOLTIP;
+ return ui::wm::WINDOW_TYPE_TOOLTIP;
default:
NOTREACHED() << "Unhandled widget type " << type;
- return aura::client::WINDOW_TYPE_UNKNOWN;
+ return ui::wm::WINDOW_TYPE_UNKNOWN;
}
}
diff --git a/chromium/ui/views/widget/widget_aura_utils.h b/chromium/ui/views/widget/widget_aura_utils.h
index 8f0bfcc0358..4b16de48cab 100644
--- a/chromium/ui/views/widget/widget_aura_utils.h
+++ b/chromium/ui/views/widget/widget_aura_utils.h
@@ -5,14 +5,14 @@
#ifndef UI_VIEWS_WIDGET_WIDGET_AURA_UTILS_H_
#define UI_VIEWS_WIDGET_WIDGET_AURA_UTILS_H_
-#include "ui/aura/client/window_types.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/public/window_types.h"
// Functions shared by native_widget_aura.cc and desktop_native_widget_aura.cc:
namespace views {
-aura::client::WindowType GetAuraWindowTypeForWidgetType(
+ui::wm::WindowType GetAuraWindowTypeForWidgetType(
Widget::InitParams::Type type);
} // namespace views
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index fbace27c316..7e1f67e19c3 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -17,7 +17,9 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// WidgetDelegate:
-WidgetDelegate::WidgetDelegate() : default_contents_view_(NULL) {
+WidgetDelegate::WidgetDelegate()
+ : default_contents_view_(NULL),
+ can_activate_(true) {
}
void WidgetDelegate::OnWidgetMove() {
@@ -50,23 +52,23 @@ bool WidgetDelegate::CanMaximize() const {
}
bool WidgetDelegate::CanActivate() const {
- return true;
+ return can_activate_;
}
ui::ModalType WidgetDelegate::GetModalType() const {
return ui::MODAL_TYPE_NONE;
}
-ui::AccessibilityTypes::Role WidgetDelegate::GetAccessibleWindowRole() const {
- return ui::AccessibilityTypes::ROLE_WINDOW;
+ui::AXRole WidgetDelegate::GetAccessibleWindowRole() const {
+ return ui::AX_ROLE_WINDOW;
}
-string16 WidgetDelegate::GetAccessibleWindowTitle() const {
+base::string16 WidgetDelegate::GetAccessibleWindowTitle() const {
return GetWindowTitle();
}
-string16 WidgetDelegate::GetWindowTitle() const {
- return string16();
+base::string16 WidgetDelegate::GetWindowTitle() const {
+ return base::string16();
}
bool WidgetDelegate::ShouldShowWindowTitle() const {
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 16e29a8b338..b9903096c14 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/view.h"
@@ -30,6 +30,11 @@ class VIEWS_EXPORT WidgetDelegate {
public:
WidgetDelegate();
+ // Sets the return value of CanActivate(). Default is true.
+ void set_can_activate(bool can_activate) {
+ can_activate_ = can_activate;
+ }
+
// Called whenever the widget's position changes.
virtual void OnWidgetMove();
@@ -60,13 +65,13 @@ class VIEWS_EXPORT WidgetDelegate {
// ui::MODAL_TYPE_NONE (not modal).
virtual ui::ModalType GetModalType() const;
- virtual ui::AccessibilityTypes::Role GetAccessibleWindowRole() const;
+ virtual ui::AXRole GetAccessibleWindowRole() const;
// Returns the title to be read with screen readers.
- virtual string16 GetAccessibleWindowTitle() const;
+ virtual base::string16 GetAccessibleWindowTitle() const;
// Returns the text to be displayed in the window title.
- virtual string16 GetWindowTitle() const;
+ virtual base::string16 GetWindowTitle() const;
// Returns true if the window should show a title in the title bar.
virtual bool ShouldShowWindowTitle() const;
@@ -181,6 +186,8 @@ class VIEWS_EXPORT WidgetDelegate {
private:
View* default_contents_view_;
+ bool can_activate_;
+
DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
};
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc
index 53588c25e5e..ac313bb74c8 100644
--- a/chromium/ui/views/widget/widget_hwnd_utils.cc
+++ b/chromium/ui/views/widget/widget_hwnd_utils.cc
@@ -41,7 +41,8 @@ void CalculateWindowStylesFromInitParams(
*style |= WS_MINIMIZE;
if (!params.accept_events)
*ex_style |= WS_EX_TRANSPARENT;
- if (!params.can_activate)
+ DCHECK_NE(Widget::InitParams::ACTIVATABLE_DEFAULT, params.activatable);
+ if (params.activatable == Widget::InitParams::ACTIVATABLE_NO)
*ex_style |= WS_EX_NOACTIVATE;
if (params.keep_on_top)
*ex_style |= WS_EX_TOPMOST;
@@ -62,14 +63,10 @@ void CalculateWindowStylesFromInitParams(
// 5- When the window is created but before it is presented, call
// DwmExtendFrameIntoClientArea passing -1 as the margins.
if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) {
-#if defined(USE_AURA)
if (ui::win::IsAeroGlassEnabled())
*ex_style |= WS_EX_COMPOSITED;
-#else
- *ex_style |= WS_EX_LAYERED;
-#endif
}
- if (params.has_dropshadow) {
+ if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP) {
*class_style |= (base::win::GetVersion() < base::win::VERSION_XP) ?
0 : CS_DROPSHADOW;
}
@@ -122,10 +119,13 @@ void CalculateWindowStylesFromInitParams(
case Widget::InitParams::TYPE_BUBBLE:
*style |= WS_POPUP;
*style |= WS_CLIPCHILDREN;
+ if (!params.force_show_in_taskbar)
+ *ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_POPUP:
*style |= WS_POPUP;
- *ex_style |= WS_EX_TOOLWINDOW;
+ if (!params.force_show_in_taskbar)
+ *ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_MENU:
*style |= WS_POPUP;
diff --git a/chromium/ui/views/widget/widget_hwnd_utils.h b/chromium/ui/views/widget/widget_hwnd_utils.h
index 2808bab0d48..09ee0abe138 100644
--- a/chromium/ui/views/widget/widget_hwnd_utils.h
+++ b/chromium/ui/views/widget/widget_hwnd_utils.h
@@ -9,7 +9,8 @@
#include "ui/views/widget/widget.h"
-// Functions shared by native_widget_win.cc and desktop_root_window_host_win.cc:
+// Functions shared by hwnd_message_handler.cc and
+// desktop_window_tree_host_win.cc:
namespace views {
class HWNDMessageHandler;
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 30d44a3c9d7..45026a9eb1e 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -4,21 +4,31 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/events/event_processor.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/touchui/touch_selection_controller_impl.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
+#include "ui/wm/public/activation_client.h"
-#if defined(USE_AURA)
-#include "ui/aura/client/activation_client.h"
-#include "ui/aura/client/focus_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#endif
-
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
@@ -134,9 +144,6 @@ class NestedLoopCaptureView : public View {
base::MessageLoop::ScopedNestableTaskAllower allow(loop);
base::RunLoop run_loop;
-#if defined(USE_AURA)
- run_loop.set_dispatcher(aura::Env::GetInstance()->GetDispatcher());
-#endif
run_loop.Run();
return true;
}
@@ -148,8 +155,39 @@ class NestedLoopCaptureView : public View {
} // namespace
-#if defined(OS_WIN) && defined(USE_AURA)
-// Tests whether activation and focus change works correctly in Windows AURA.
+class WidgetTestInteractive : public WidgetTest {
+ public:
+ WidgetTestInteractive() {}
+ virtual ~WidgetTestInteractive() {}
+
+ virtual void SetUp() OVERRIDE {
+ gfx::GLSurface::InitializeOneOffForTests();
+ base::FilePath pak_dir;
+ PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::FilePath pak_file;
+ pak_file = pak_dir.Append(FILE_PATH_LITERAL("ui_test.pak"));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
+ WidgetTest::SetUp();
+ }
+
+ protected:
+ static void ShowQuickMenuImmediately(
+ TouchSelectionControllerImpl* controller) {
+ DCHECK(controller);
+ if (controller->context_menu_timer_.IsRunning()) {
+ controller->context_menu_timer_.Stop();
+ controller->ContextMenuTimerFired();
+ }
+ }
+
+ static bool IsQuickMenuVisible(TouchSelectionControllerImpl* controller) {
+ DCHECK(controller);
+ return controller->context_menu_ && controller->context_menu_->visible();
+ }
+};
+
+#if defined(OS_WIN)
+// Tests whether activation and focus change works correctly in Windows.
// We test the following:-
// 1. If the active aura window is correctly set when a top level widget is
// created.
@@ -157,9 +195,8 @@ class NestedLoopCaptureView : public View {
// another top level widget is created and focused.
// 3. On focusing the native platform window for widget 1, the active aura
// window for widget 1 should be set and that for widget 2 should reset.
-// TODO(ananta)
-// Discuss with erg on how to write this test for linux x11 aura.
-TEST_F(WidgetTest, DesktopNativeWidgetAuraActivationAndFocusTest) {
+// TODO(ananta): Discuss with erg on how to write this test for linux x11 aura.
+TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) {
// Create widget 1 and expect the active window to be its window.
View* contents_view1 = new View;
contents_view1->SetFocusable(true);
@@ -195,7 +232,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraActivationAndFocusTest) {
aura::Window* root_window2 = widget2.GetNativeView()->GetRootWindow();
contents_view2->RequestFocus();
::SetActiveWindow(
- root_window2->GetDispatcher()->host()->GetAcceleratedWidget());
+ root_window2->GetHost()->GetAcceleratedWidget());
aura::client::ActivationClient* activation_client2 =
aura::client::GetActivationClient(root_window2);
@@ -208,14 +245,14 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraActivationAndFocusTest) {
// window.
contents_view1->RequestFocus();
::SetActiveWindow(
- root_window1->GetDispatcher()->host()->GetAcceleratedWidget());
+ root_window1->GetHost()->GetAcceleratedWidget());
EXPECT_EQ(activation_client2->GetActiveWindow(),
reinterpret_cast<aura::Window*>(NULL));
EXPECT_EQ(activation_client1->GetActiveWindow(), widget1.GetNativeView());
}
#endif
-TEST_F(WidgetTest, CaptureAutoReset) {
+TEST_F(WidgetTestInteractive, CaptureAutoReset) {
Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
View* container = new View;
toplevel->SetContentsView(container);
@@ -227,7 +264,7 @@ TEST_F(WidgetTest, CaptureAutoReset) {
// By default, mouse release removes capture.
gfx::Point click_location(45, 15);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
toplevel->OnMouseEvent(&release);
EXPECT_FALSE(toplevel->HasCapture());
@@ -244,7 +281,7 @@ TEST_F(WidgetTest, CaptureAutoReset) {
RunPendingMessages();
}
-TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
+TEST_F(WidgetTestInteractive, ResetCaptureOnGestureEnd) {
Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
View* container = new View;
toplevel->SetContentsView(container);
@@ -274,9 +311,9 @@ TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
gfx::Point click_location(45, 15);
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
EXPECT_TRUE(toplevel->HasCapture());
@@ -300,7 +337,7 @@ TEST_F(WidgetTest, ResetCaptureOnGestureEnd) {
// Checks that if a mouse-press triggers a capture on a different widget (which
// consumes the mouse-release event), then the target of the press does not have
// capture.
-TEST_F(WidgetTest, DisableCaptureWidgetFromMousePress) {
+TEST_F(WidgetTestInteractive, DisableCaptureWidgetFromMousePress) {
// The test creates two widgets: |first| and |second|.
// The View in |first| makes |second| visible, sets capture on it, and starts
// a nested loop (like a menu does). The View in |second| terminates the
@@ -327,9 +364,10 @@ TEST_F(WidgetTest, DisableCaptureWidgetFromMousePress) {
base::Owned(new ui::MouseEvent(ui::ET_MOUSE_RELEASED,
location,
location,
+ ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON))));
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
first->OnMouseEvent(&press);
EXPECT_FALSE(first->HasCapture());
first->Close();
@@ -338,7 +376,7 @@ TEST_F(WidgetTest, DisableCaptureWidgetFromMousePress) {
// Tests some grab/ungrab events.
// TODO(estade): can this be enabled now that this is an interactive ui test?
-TEST_F(WidgetTest, DISABLED_GrabUngrab) {
+TEST_F(WidgetTestInteractive, DISABLED_GrabUngrab) {
Widget* toplevel = CreateTopLevelPlatformWidget();
Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
@@ -361,7 +399,7 @@ TEST_F(WidgetTest, DISABLED_GrabUngrab) {
// Click on child1
gfx::Point p1(45, 45);
ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
toplevel->OnMouseEvent(&pressed);
EXPECT_TRUE(toplevel->HasCapture());
@@ -369,7 +407,7 @@ TEST_F(WidgetTest, DISABLED_GrabUngrab) {
EXPECT_FALSE(child2->HasCapture());
ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
toplevel->OnMouseEvent(&released);
EXPECT_FALSE(toplevel->HasCapture());
@@ -381,7 +419,7 @@ TEST_F(WidgetTest, DISABLED_GrabUngrab) {
// Click on child2
gfx::Point p2(315, 45);
ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
toplevel->OnMouseEvent(&pressed2);
EXPECT_TRUE(pressed2.handled());
EXPECT_TRUE(toplevel->HasCapture());
@@ -389,7 +427,7 @@ TEST_F(WidgetTest, DISABLED_GrabUngrab) {
EXPECT_FALSE(child1->HasCapture());
ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
toplevel->OnMouseEvent(&released2);
EXPECT_FALSE(toplevel->HasCapture());
EXPECT_FALSE(child1->HasCapture());
@@ -400,7 +438,7 @@ TEST_F(WidgetTest, DISABLED_GrabUngrab) {
// Tests mouse move outside of the window into the "resize controller" and back
// will still generate an OnMouseEntered and OnMouseExited event..
-TEST_F(WidgetTest, CheckResizeControllerEvents) {
+TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
Widget* toplevel = CreateTopLevelPlatformWidget();
toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
@@ -414,21 +452,24 @@ TEST_F(WidgetTest, CheckResizeControllerEvents) {
// Move to an outside position.
gfx::Point p1(200, 200);
- ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE);
+ ui::MouseEvent moved_out(ui::ET_MOUSE_MOVED, p1, p1, ui::EF_NONE,
+ ui::EF_NONE);
toplevel->OnMouseEvent(&moved_out);
EXPECT_EQ(0, view->EnteredCalls());
EXPECT_EQ(0, view->ExitedCalls());
// Move onto the active view.
gfx::Point p2(95, 95);
- ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE);
+ ui::MouseEvent moved_over(ui::ET_MOUSE_MOVED, p2, p2, ui::EF_NONE,
+ ui::EF_NONE);
toplevel->OnMouseEvent(&moved_over);
EXPECT_EQ(1, view->EnteredCalls());
EXPECT_EQ(0, view->ExitedCalls());
// Move onto the outer resizing border.
gfx::Point p3(102, 95);
- ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE);
+ ui::MouseEvent moved_resizer(ui::ET_MOUSE_MOVED, p3, p3, ui::EF_NONE,
+ ui::EF_NONE);
toplevel->OnMouseEvent(&moved_resizer);
EXPECT_EQ(0, view->EnteredCalls());
EXPECT_EQ(1, view->ExitedCalls());
@@ -443,8 +484,92 @@ TEST_F(WidgetTest, CheckResizeControllerEvents) {
toplevel->CloseNow();
}
+// Test view focus restoration when a widget is deactivated and re-activated.
+TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
+ Widget* widget1 = CreateTopLevelPlatformWidget();
+ View* view1 = new View;
+ view1->SetFocusable(true);
+ widget1->GetContentsView()->AddChildView(view1);
+
+ Widget* widget2 = CreateTopLevelPlatformWidget();
+ View* view2a = new View;
+ View* view2b = new View;
+ view2a->SetFocusable(true);
+ view2b->SetFocusable(true);
+ widget2->GetContentsView()->AddChildView(view2a);
+ widget2->GetContentsView()->AddChildView(view2b);
+
+ widget1->Show();
+ EXPECT_TRUE(widget1->IsActive());
+ view1->RequestFocus();
+ EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
+
+ widget2->Show();
+ EXPECT_TRUE(widget2->IsActive());
+ EXPECT_FALSE(widget1->IsActive());
+ EXPECT_EQ(NULL, widget1->GetFocusManager()->GetFocusedView());
+ view2a->RequestFocus();
+ EXPECT_EQ(view2a, widget2->GetFocusManager()->GetFocusedView());
+ view2b->RequestFocus();
+ EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
+
+ widget1->Activate();
+ EXPECT_TRUE(widget1->IsActive());
+ EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
+ EXPECT_FALSE(widget2->IsActive());
+ EXPECT_EQ(NULL, widget2->GetFocusManager()->GetFocusedView());
+
+ widget2->Activate();
+ EXPECT_TRUE(widget2->IsActive());
+ EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
+ EXPECT_FALSE(widget1->IsActive());
+ EXPECT_EQ(NULL, widget1->GetFocusManager()->GetFocusedView());
+
+ widget1->CloseNow();
+ widget2->CloseNow();
+}
+
#if defined(OS_WIN)
+// Test view focus retention when a widget's HWND is disabled and re-enabled.
+TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
+ Widget* widget = CreateTopLevelFramelessPlatformWidget();
+ widget->SetContentsView(new View);
+ for (size_t i = 0; i < 2; ++i) {
+ widget->GetContentsView()->AddChildView(new View);
+ widget->GetContentsView()->child_at(i)->SetFocusable(true);
+ }
+
+ widget->Show();
+ const HWND hwnd = HWNDForWidget(widget);
+ EXPECT_TRUE(::IsWindow(hwnd));
+ EXPECT_TRUE(::IsWindowEnabled(hwnd));
+ EXPECT_EQ(hwnd, ::GetActiveWindow());
+
+ for (int i = 0; i < widget->GetContentsView()->child_count(); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Child view %d", i));
+ View* view = widget->GetContentsView()->child_at(i);
+
+ view->RequestFocus();
+ EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
+ EXPECT_FALSE(::EnableWindow(hwnd, FALSE));
+ EXPECT_FALSE(::IsWindowEnabled(hwnd));
+
+ // Oddly, disabling the HWND leaves it active with the focus unchanged.
+ EXPECT_EQ(hwnd, ::GetActiveWindow());
+ EXPECT_TRUE(widget->IsActive());
+ EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
+
+ EXPECT_TRUE(::EnableWindow(hwnd, TRUE));
+ EXPECT_TRUE(::IsWindowEnabled(hwnd));
+ EXPECT_EQ(hwnd, ::GetActiveWindow());
+ EXPECT_TRUE(widget->IsActive());
+ EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
+ }
+
+ widget->CloseNow();
+}
+
// This class subclasses the Widget class to listen for activation change
// notifications and provides accessors to return information as to whether
// the widget is active. We need this to ensure that users of the widget
@@ -473,23 +598,19 @@ class WidgetActivationTest : public Widget {
// Tests whether the widget only becomes active when the underlying window
// is really active.
-TEST_F(WidgetTest, WidgetNotActivatedOnFakeActivationMessages) {
+TEST_F(WidgetTestInteractive, WidgetNotActivatedOnFakeActivationMessages) {
WidgetActivationTest widget1;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-#if defined(USE_AURA)
init_params.native_widget = new DesktopNativeWidgetAura(&widget1);
-#endif
init_params.bounds = gfx::Rect(0, 0, 200, 200);
widget1.Init(init_params);
widget1.Show();
EXPECT_EQ(true, widget1.active());
WidgetActivationTest widget2;
-#if defined(USE_AURA)
init_params.native_widget = new DesktopNativeWidgetAura(&widget2);
-#endif
widget2.Init(init_params);
widget2.Show();
EXPECT_EQ(true, widget2.active());
@@ -508,7 +629,7 @@ TEST_F(WidgetTest, WidgetNotActivatedOnFakeActivationMessages) {
}
#endif
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
// Provides functionality to create a window modal dialog.
class ModalDialogDelegate : public DialogDelegateView {
public:
@@ -527,9 +648,8 @@ class ModalDialogDelegate : public DialogDelegateView {
};
// Tests whether the focused window is set correctly when a modal window is
-// created and destroyed. When it is destroyed it should focus the owner
-// window.
-TEST_F(WidgetTest, WindowModalWindowDestroyedActivationTest) {
+// created and destroyed. When it is destroyed it should focus the owner window.
+TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
// Create a top level widget.
Widget top_level_widget;
Widget::InitParams init_params =
@@ -566,7 +686,7 @@ TEST_F(WidgetTest, WindowModalWindowDestroyedActivationTest) {
}
// Test that when opening a system-modal window, capture is released.
-TEST_F(WidgetTest, SystemModalWindowReleasesCapture) {
+TEST_F(WidgetTestInteractive, SystemModalWindowReleasesCapture) {
// Create a top level widget.
Widget top_level_widget;
Widget::InitParams init_params =
@@ -604,6 +724,59 @@ TEST_F(WidgetTest, SystemModalWindowReleasesCapture) {
#endif
+TEST_F(WidgetTestInteractive, CanActivateFlagIsHonored) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.activatable = Widget::InitParams::ACTIVATABLE_NO;
+#if !defined(OS_CHROMEOS)
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+#endif // !defined(OS_CHROMEOS)
+ widget.Init(init_params);
+
+ widget.Show();
+ EXPECT_FALSE(widget.IsActive());
+}
+
+// Test that touch selection quick menu is not activated when opened.
+TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
+#if defined(OS_WIN)
+ views_delegate().set_use_desktop_native_widgets(true);
+#endif // !defined(OS_WIN)
+
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ init_params.bounds = gfx::Rect(0, 0, 200, 200);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(init_params);
+
+ Textfield* textfield = new Textfield;
+ textfield->SetBounds(0, 0, 200, 20);
+ textfield->SetText(base::ASCIIToUTF16("some text"));
+ widget.GetRootView()->AddChildView(textfield);
+
+ widget.Show();
+ textfield->RequestFocus();
+ textfield->SelectAll(true);
+ TextfieldTestApi textfield_test_api(textfield);
+
+ RunPendingMessages();
+
+ aura::test::EventGenerator generator(widget.GetNativeView()->GetRootWindow());
+ generator.GestureTapAt(gfx::Point(10, 10));
+ ShowQuickMenuImmediately(static_cast<TouchSelectionControllerImpl*>(
+ textfield_test_api.touch_selection_controller()));
+
+ EXPECT_TRUE(textfield->HasFocus());
+ EXPECT_TRUE(widget.IsActive());
+ EXPECT_TRUE(IsQuickMenuVisible(static_cast<TouchSelectionControllerImpl*>(
+ textfield_test_api.touch_selection_controller())));
+}
+
namespace {
// Used to veirfy OnMouseCaptureLost() has been invoked.
@@ -640,6 +813,16 @@ class WidgetCaptureTest : public ViewsTestBase {
virtual ~WidgetCaptureTest() {
}
+ virtual void SetUp() OVERRIDE {
+ gfx::GLSurface::InitializeOneOffForTests();
+ base::FilePath pak_dir;
+ PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::FilePath pak_file;
+ pak_file = pak_dir.Append(FILE_PATH_LITERAL("ui_test.pak"));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
+ ViewsTestBase::SetUp();
+ }
+
// Verifies Widget::SetCapture() results in updating native capture along with
// invoking the right Widget function.
void TestCapture(bool use_desktop_native_widget) {
@@ -686,7 +869,7 @@ class WidgetCaptureTest : public ViewsTestBase {
private:
NativeWidget* CreateNativeWidget(bool create_desktop_native_widget,
Widget* widget) {
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (create_desktop_native_widget)
return new DesktopNativeWidgetAura(widget);
#endif
@@ -701,14 +884,14 @@ TEST_F(WidgetCaptureTest, Capture) {
TestCapture(false);
}
-#if defined(USE_AURA) && !defined(OS_LINUX)
+#if !defined(OS_LINUX)
// See description in TestCapture(). Creates DesktopNativeWidget.
TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) {
TestCapture(true);
}
#endif
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
namespace {
// Used to veirfy OnMouseEvent() has been invoked.
@@ -737,7 +920,7 @@ class MouseEventTrackingWidget : public Widget {
} // namespace
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// TODO(erg): linux_aura bringup: http://crbug.com/163931
#define MAYBE_MouseEventDispatchedToRightWindow \
DISABLED_MouseEventDispatchedToRightWindow
@@ -775,9 +958,10 @@ TEST_F(WidgetCaptureTest, MAYBE_MouseEventDispatchedToRightWindow) {
// Send a mouse event to the RootWindow associated with |widget1|. Even though
// |widget2| has capture, |widget1| should still get the event.
ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
- ui::EF_NONE);
- widget1.GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate()->
- OnHostMouseEvent(&mouse_event);
+ ui::EF_NONE, ui::EF_NONE);
+ ui::EventDispatchDetails details = widget1.GetNativeWindow()->
+ GetHost()->event_processor()->OnEventFromSource(&mouse_event);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(widget1.GetAndClearGotMouseEvent());
EXPECT_FALSE(widget2.GetAndClearGotMouseEvent());
}
diff --git a/chromium/ui/views/widget/widget_observer.h b/chromium/ui/views/widget/widget_observer.h
index fc13afae682..2cad7142e25 100644
--- a/chromium/ui/views/widget/widget_observer.h
+++ b/chromium/ui/views/widget/widget_observer.h
@@ -14,6 +14,7 @@ class Rect;
namespace views {
class Widget;
+class View;
// Observers can listen to various events on the Widgets.
class VIEWS_EXPORT WidgetObserver {
diff --git a/chromium/ui/views/widget/widget_removals_observer.h b/chromium/ui/views/widget/widget_removals_observer.h
new file mode 100644
index 00000000000..e62acab36a4
--- /dev/null
+++ b/chromium/ui/views/widget/widget_removals_observer.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_WIDGET_REMOVALS_OBSERVER_H_
+#define UI_VIEWS_WIDGET_WIDGET_REMOVALS_OBSERVER_H_
+
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class Widget;
+class View;
+
+// |WidgetRemovalsObserver| complements |WidgetObserver| with additional
+// notifications. These include events occurring during tear down like view
+// removal. For this reason, it is recommended that subclasses not also inherit
+// from |View|.
+class VIEWS_EXPORT WidgetRemovalsObserver {
+ public:
+ // Called immediately before a descendant view of |widget| is removed.
+ virtual void OnWillRemoveView(Widget* widget, View* view) {}
+
+ protected:
+ virtual ~WidgetRemovalsObserver() {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_REMOVALS_OBSERVER_H_
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index a243eb5f2ac..d6062067a33 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -12,7 +12,12 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/point.h"
@@ -23,23 +28,10 @@
#include "ui/views/views_delegate.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_deletion_observer.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/window/native_frame_view.h"
-#if defined(USE_AURA)
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/window.h"
-#include "ui/views/widget/native_widget_aura.h"
-#if !defined(OS_CHROMEOS)
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#endif
-#elif defined(OS_WIN)
-#include "ui/views/widget/native_widget_win.h"
-#endif
-
#if defined(OS_WIN)
#include "ui/views/win/hwnd_util.h"
#endif
@@ -72,9 +64,6 @@ class EventCountView : public View {
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
RecordEvent(*event);
}
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
- RecordEvent(*event);
- }
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
RecordEvent(*event);
}
@@ -90,7 +79,7 @@ class EventCountView : public View {
};
// A view that keeps track of the events it receives, and consumes all scroll
-// gesture events.
+// gesture events and ui::ET_SCROLL events.
class ScrollableEventCountView : public EventCountView {
public:
ScrollableEventCountView() {}
@@ -112,6 +101,12 @@ class ScrollableEventCountView : public EventCountView {
}
}
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
+ EventCountView::OnScrollEvent(event);
+ if (event->type() == ui::ET_SCROLL)
+ event->SetHandled();
+ }
+
DISALLOW_COPY_AND_ASSIGN(ScrollableEventCountView);
};
@@ -123,7 +118,7 @@ class MinimumSizeFrameView : public NativeFrameView {
private:
// Overridden from View:
- virtual gfx::Size GetMinimumSize() OVERRIDE {
+ virtual gfx::Size GetMinimumSize() const OVERRIDE {
return gfx::Size(300, 400);
}
@@ -162,34 +157,47 @@ class EventCountHandler : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(EventCountHandler);
};
+// Class that closes the widget (which ends up deleting it immediately) when the
+// appropriate event is received.
+class CloseWidgetView : public View {
+ public:
+ explicit CloseWidgetView(ui::EventType event_type)
+ : event_type_(event_type) {
+ }
+
+ // ui::EventHandler override:
+ virtual void OnEvent(ui::Event* event) OVERRIDE {
+ if (event->type() == event_type_) {
+ // Go through NativeWidgetPrivate to simulate what happens if the OS
+ // deletes the NativeWindow out from under us.
+ GetWidget()->native_widget_private()->CloseNow();
+ } else {
+ View::OnEvent(event);
+ if (!event->IsTouchEvent())
+ event->SetHandled();
+ }
+ }
+
+ private:
+ const ui::EventType event_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
+};
+
ui::WindowShowState GetWidgetShowState(const Widget* widget) {
// Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement
// because the former is implemented on all platforms but the latter is not.
return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN :
widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED :
widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED :
- ui::SHOW_STATE_NORMAL;
+ widget->IsActive() ? ui::SHOW_STATE_NORMAL :
+ ui::SHOW_STATE_INACTIVE;
}
TEST_F(WidgetTest, WidgetInitParams) {
- ASSERT_FALSE(views_delegate().UseTransparentWindows());
-
// Widgets are not transparent by default.
Widget::InitParams init1;
EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity);
-
- // Non-window widgets are not transparent either.
- Widget::InitParams init2(Widget::InitParams::TYPE_MENU);
- EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init2.opacity);
-
- // A ViewsDelegate can set windows transparent by default.
- views_delegate().SetUseTransparentWindows(true);
- Widget::InitParams init3;
- EXPECT_EQ(Widget::InitParams::TRANSLUCENT_WINDOW, init3.opacity);
-
- // Non-window widgets stay opaque.
- Widget::InitParams init4(Widget::InitParams::TYPE_MENU);
- EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init4.opacity);
}
////////////////////////////////////////////////////////////////////////////////
@@ -259,32 +267,6 @@ TEST_F(WidgetTest, Visibility) {
// |child| should be automatically destroyed with |toplevel|.
}
-#if defined(OS_WIN) && !defined(USE_AURA)
-// On Windows, it is possible to have child window that are TYPE_POPUP. Unlike
-// regular child windows, these should be created as hidden and must be shown
-// explicitly.
-TEST_F(WidgetTest, Visibility_ChildPopup) {
- Widget* toplevel = CreateTopLevelPlatformWidget();
- Widget* child_popup = CreateChildPopupPlatformWidget(
- toplevel->GetNativeView());
-
- EXPECT_FALSE(toplevel->IsVisible());
- EXPECT_FALSE(child_popup->IsVisible());
-
- toplevel->Show();
-
- EXPECT_TRUE(toplevel->IsVisible());
- EXPECT_FALSE(child_popup->IsVisible());
-
- child_popup->Show();
-
- EXPECT_TRUE(child_popup->IsVisible());
-
- toplevel->CloseNow();
- // |child_popup| should be automatically destroyed with |toplevel|.
-}
-#endif
-
////////////////////////////////////////////////////////////////////////////////
// Widget ownership tests.
//
@@ -323,11 +305,11 @@ struct OwnershipTestState {
// A platform NativeWidget subclass that updates a bag of state when it is
// destroyed.
-class OwnershipTestNativeWidget : public NativeWidgetPlatform {
+class OwnershipTestNativeWidget : public PlatformNativeWidget {
public:
OwnershipTestNativeWidget(internal::NativeWidgetDelegate* delegate,
OwnershipTestState* state)
- : NativeWidgetPlatform(delegate),
+ : PlatformNativeWidget(delegate),
state_(state) {
}
virtual ~OwnershipTestNativeWidget() {
@@ -342,21 +324,21 @@ class OwnershipTestNativeWidget : public NativeWidgetPlatform {
// A views NativeWidget subclass that updates a bag of state when it is
// destroyed.
-class OwnershipTestNativeWidgetPlatform : public NativeWidgetPlatformForTest {
+class OwnershipTestNativeWidgetAura : public NativeWidgetCapture {
public:
- OwnershipTestNativeWidgetPlatform(internal::NativeWidgetDelegate* delegate,
- OwnershipTestState* state)
- : NativeWidgetPlatformForTest(delegate),
+ OwnershipTestNativeWidgetAura(internal::NativeWidgetDelegate* delegate,
+ OwnershipTestState* state)
+ : NativeWidgetCapture(delegate),
state_(state) {
}
- virtual ~OwnershipTestNativeWidgetPlatform() {
+ virtual ~OwnershipTestNativeWidgetAura() {
state_->native_widget_deleted = true;
}
private:
OwnershipTestState* state_;
- DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetPlatform);
+ DISALLOW_COPY_AND_ASSIGN(OwnershipTestNativeWidgetAura);
};
// A Widget subclass that updates a bag of state when it is destroyed.
@@ -381,7 +363,7 @@ TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
@@ -402,7 +384,7 @@ TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
@@ -427,7 +409,7 @@ TEST_F(WidgetOwnershipTest,
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.parent = toplevel->GetNativeView();
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
@@ -457,7 +439,7 @@ TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
widget->Init(params);
// Now destroy the native widget.
@@ -476,7 +458,7 @@ TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
@@ -500,15 +482,11 @@ TEST_F(WidgetOwnershipTest,
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
widget->Init(params);
// Now simulate a destroy of the platform native widget from the OS:
-#if defined(USE_AURA)
- delete widget->GetNativeView();
-#elif defined(OS_WIN)
- DestroyWindow(widget->GetNativeView());
-#endif
+ SimulateNativeDestroy(widget);
EXPECT_TRUE(state.widget_deleted);
EXPECT_TRUE(state.native_widget_deleted);
@@ -525,7 +503,7 @@ TEST_F(WidgetOwnershipTest,
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
@@ -551,7 +529,7 @@ TEST_F(WidgetOwnershipTest,
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget, &state);
+ new OwnershipTestNativeWidgetAura(widget, &state);
params.parent = toplevel->GetNativeView();
widget->Init(params);
@@ -577,7 +555,7 @@ TEST_F(WidgetOwnershipTest,
scoped_ptr<Widget> widget(new OwnershipTestWidget(&state));
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget =
- new OwnershipTestNativeWidgetPlatform(widget.get(), &state);
+ new OwnershipTestNativeWidgetAura(widget.get(), &state);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = delegate_view;
widget->Init(params);
@@ -614,7 +592,6 @@ class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
widget->StackAtTop();
widget->IsClosed();
widget->Close();
- widget->Show();
widget->Hide();
widget->Activate();
widget->Deactivate();
@@ -646,11 +623,7 @@ class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
widget->ReleaseCapture();
widget->HasCapture();
widget->GetWorkAreaBoundsInScreen();
- // These three crash with NativeWidgetWin, so I'm assuming we don't need
- // them to work for the other NativeWidget impls.
- // widget->CenterWindow(gfx::Size(50, 60));
- // widget->GetRestoredBounds();
- // widget->ShowInactive();
+ widget->IsTranslucentWindowOpacitySupported();
}
private:
@@ -668,11 +641,11 @@ TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
widget.native_widget_private()->CloseNow();
InvokeWidgetMethods(&widget);
}
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
{
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
- params.native_widget = new DesktopNativeWidgetAura(&widget);
+ params.native_widget = new PlatformDesktopNativeWidget(&widget);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.Show();
@@ -852,7 +825,7 @@ TEST_F(WidgetObserverTest, WidgetBoundsChanged) {
EXPECT_EQ(child2, widget_bounds_changed());
}
-#if !defined(USE_AURA) && defined(OS_WIN)
+#if defined(false)
// Aura needs shell to maximize/fullscreen window.
// NativeWidgetGtk doesn't implement GetRestoredBounds.
TEST_F(WidgetTest, GetRestoredBounds) {
@@ -892,26 +865,21 @@ TEST_F(WidgetTest, ExitFullscreenRestoreState) {
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
toplevel->SetFullscreen(true);
- while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
- RunPendingMessages();
+ EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
toplevel->SetFullscreen(false);
- while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
- RunPendingMessages();
+ EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
// And it should still be in normal state after getting out of full screen.
EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
// Now, make it maximized.
toplevel->Maximize();
- while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_MAXIMIZED)
- RunPendingMessages();
+ EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
toplevel->SetFullscreen(true);
- while (GetWidgetShowState(toplevel) != ui::SHOW_STATE_FULLSCREEN)
- RunPendingMessages();
+ EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
toplevel->SetFullscreen(false);
- while (GetWidgetShowState(toplevel) == ui::SHOW_STATE_FULLSCREEN)
- RunPendingMessages();
+ EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
// And it stays maximized after getting out of full screen.
EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
@@ -921,7 +889,6 @@ TEST_F(WidgetTest, ExitFullscreenRestoreState) {
RunPendingMessages();
}
-#if defined(USE_AURA)
// The key-event propagation from Widget happens differently on aura and
// non-aura systems because of the difference in IME. So this test works only on
// aura.
@@ -930,7 +897,7 @@ TEST_F(WidgetTest, KeyboardInputEvent) {
View* container = toplevel->client_view();
Textfield* textfield = new Textfield();
- textfield->SetText(ASCIIToUTF16("some text"));
+ textfield->SetText(base::ASCIIToUTF16("some text"));
container->AddChildView(textfield);
toplevel->Show();
textfield->RequestFocus();
@@ -959,7 +926,7 @@ TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
#if !defined(OS_CHROMEOS)
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
#endif
widget.Init(init_params);
widget.SetContentsView(contents_view);
@@ -985,6 +952,36 @@ TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) {
EXPECT_TRUE(contents_view->HasFocus());
}
+class TestBubbleDelegateView : public BubbleDelegateView {
+ public:
+ TestBubbleDelegateView(View* anchor)
+ : BubbleDelegateView(anchor, BubbleBorder::NONE),
+ reset_controls_called_(false) {}
+ virtual ~TestBubbleDelegateView() {}
+
+ virtual bool ShouldShowCloseButton() const OVERRIDE {
+ reset_controls_called_ = true;
+ return true;
+ }
+
+ mutable bool reset_controls_called_;
+};
+
+TEST_F(WidgetTest, BubbleControlsResetOnInit) {
+ Widget* anchor = CreateTopLevelPlatformWidget();
+ anchor->Show();
+
+ TestBubbleDelegateView* bubble_delegate =
+ new TestBubbleDelegateView(anchor->client_view());
+ Widget* bubble_widget(BubbleDelegateView::CreateBubble(bubble_delegate));
+ EXPECT_TRUE(bubble_delegate->reset_controls_called_);
+ bubble_widget->Show();
+ bubble_widget->CloseNow();
+
+ anchor->Hide();
+ anchor->CloseNow();
+}
+
// Desktop native widget Aura tests are for non Chrome OS platforms.
#if !defined(OS_CHROMEOS)
// Test to ensure that after minimize, view width is set to zero.
@@ -997,7 +994,7 @@ TEST_F(WidgetTest, TestViewWidthAfterMinimizingWidget) {
gfx::Rect initial_bounds(0, 0, 300, 400);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
widget.Init(init_params);
NonClientView* non_client_view = widget.non_client_view();
NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
@@ -1051,7 +1048,7 @@ class DesktopAuraTestValidPaintWidget : public views::Widget {
bool received_paint_while_hidden_;
};
-TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
+TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterCloseTest) {
View* contents_view = new View;
contents_view->SetFocusable(true);
DesktopAuraTestValidPaintWidget widget;
@@ -1059,7 +1056,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
widget.Init(init_params);
widget.SetContentsView(contents_view);
widget.Show();
@@ -1071,7 +1068,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterCloseTest) {
EXPECT_FALSE(widget.received_paint_while_hidden());
}
-TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
+TEST_F(WidgetTest, DesktopNativeWidgetNoPaintAfterHideTest) {
View* contents_view = new View;
contents_view->SetFocusable(true);
DesktopAuraTestValidPaintWidget widget;
@@ -1079,7 +1076,7 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
widget.Init(init_params);
widget.SetContentsView(contents_view);
widget.Show();
@@ -1092,170 +1089,6 @@ TEST_F(WidgetTest, DesktopNativeWidgetAuraNoPaintAfterHideTest) {
widget.Close();
}
-// This class provides functionality to create fullscreen and top level popup
-// windows. It additionally tests whether the destruction of these windows
-// occurs correctly in desktop AURA without crashing.
-// It provides facilities to test the following cases:-
-// 1. Child window destroyed which should lead to the destruction of the
-// parent.
-// 2. Parent window destroyed which should lead to the child being destroyed.
-class DesktopAuraTopLevelWindowTest
- : public views::TestViewsDelegate,
- public aura::WindowObserver {
- public:
- DesktopAuraTopLevelWindowTest()
- : top_level_widget_(NULL),
- owned_window_(NULL),
- owner_destroyed_(false),
- owned_window_destroyed_(false) {}
-
- virtual ~DesktopAuraTopLevelWindowTest() {
- EXPECT_TRUE(owner_destroyed_);
- EXPECT_TRUE(owned_window_destroyed_);
- top_level_widget_ = NULL;
- owned_window_ = NULL;
- }
-
- // views::TestViewsDelegate overrides.
- virtual void OnBeforeWidgetInit(
- Widget::InitParams* params,
- internal::NativeWidgetDelegate* delegate) OVERRIDE {
- if (!params->native_widget)
- params->native_widget = new views::DesktopNativeWidgetAura(delegate);
- }
-
- void CreateTopLevelWindow(const gfx::Rect& bounds, bool fullscreen) {
- Widget::InitParams init_params;
- init_params.type = Widget::InitParams::TYPE_WINDOW;
- init_params.bounds = bounds;
- init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.layer_type = ui::LAYER_NOT_DRAWN;
- init_params.accept_events = fullscreen;
-
- widget_.Init(init_params);
-
- owned_window_ = new aura::Window(&child_window_delegate_);
- owned_window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
- owned_window_->SetName("TestTopLevelWindow");
- if (fullscreen) {
- owned_window_->SetProperty(aura::client::kShowStateKey,
- ui::SHOW_STATE_FULLSCREEN);
- } else {
- owned_window_->SetType(aura::client::WINDOW_TYPE_MENU);
- }
- owned_window_->Init(ui::LAYER_TEXTURED);
- aura::client::ParentWindowWithContext(
- owned_window_,
- widget_.GetNativeView()->GetRootWindow(),
- gfx::Rect(0, 0, 1900, 1600));
- owned_window_->Show();
- owned_window_->AddObserver(this);
-
- ASSERT_TRUE(owned_window_->parent() != NULL);
- owned_window_->parent()->AddObserver(this);
-
- top_level_widget_ =
- views::Widget::GetWidgetForNativeView(owned_window_->parent());
- ASSERT_TRUE(top_level_widget_ != NULL);
- }
-
- void DestroyOwnedWindow() {
- ASSERT_TRUE(owned_window_ != NULL);
- delete owned_window_;
- }
-
- void DestroyOwnerWindow() {
- ASSERT_TRUE(top_level_widget_ != NULL);
- top_level_widget_->CloseNow();
- }
-
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- window->RemoveObserver(this);
- if (window == owned_window_) {
- owned_window_destroyed_ = true;
- } else if (window == top_level_widget_->GetNativeView()) {
- owner_destroyed_ = true;
- } else {
- ADD_FAILURE() << "Unexpected window destroyed callback: " << window;
- }
- }
-
- aura::Window* owned_window() {
- return owned_window_;
- }
-
- views::Widget* top_level_widget() {
- return top_level_widget_;
- }
-
- private:
- views::Widget widget_;
- views::Widget* top_level_widget_;
- aura::Window* owned_window_;
- bool owner_destroyed_;
- bool owned_window_destroyed_;
- aura::test::TestWindowDelegate child_window_delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(DesktopAuraTopLevelWindowTest);
-};
-
-TEST_F(WidgetTest, DesktopAuraFullscreenWindowDestroyedBeforeOwnerTest) {
- ViewsDelegate::views_delegate = NULL;
- DesktopAuraTopLevelWindowTest fullscreen_window;
- ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
- gfx::Rect(0, 0, 200, 200), true));
-
- RunPendingMessages();
- ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnedWindow());
- RunPendingMessages();
-}
-
-TEST_F(WidgetTest, DesktopAuraFullscreenWindowOwnerDestroyed) {
- ViewsDelegate::views_delegate = NULL;
-
- DesktopAuraTopLevelWindowTest fullscreen_window;
- ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
- gfx::Rect(0, 0, 200, 200), true));
-
- RunPendingMessages();
- ASSERT_NO_FATAL_FAILURE(fullscreen_window.DestroyOwnerWindow());
- RunPendingMessages();
-}
-
-TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupTest) {
- ViewsDelegate::views_delegate = NULL;
- DesktopAuraTopLevelWindowTest popup_window;
- ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
- gfx::Rect(0, 0, 200, 200), false));
-
- RunPendingMessages();
- ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
- RunPendingMessages();
-}
-
-#if defined(OS_WIN)
-// TODO(ananta)
-// Fix this test to work on Linux Aura. Need to implement the
-// views::DesktopRootWindowHostX11::SetSize function
-// This test validates that when a top level owned popup Aura window is
-// resized, the widget is resized as well.
-TEST_F(WidgetTest, DesktopAuraTopLevelOwnedPopupResizeTest) {
- ViewsDelegate::views_delegate = NULL;
- DesktopAuraTopLevelWindowTest popup_window;
- ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
- gfx::Rect(0, 0, 200, 200), false));
-
- gfx::Rect new_size(0, 0, 400, 400);
- popup_window.owned_window()->SetBounds(new_size);
-
- EXPECT_EQ(popup_window.top_level_widget()->GetNativeView()->bounds().size(),
- new_size.size());
- RunPendingMessages();
- ASSERT_NO_FATAL_FAILURE(popup_window.DestroyOwnedWindow());
- RunPendingMessages();
-}
-#endif
-
// Test to ensure that the aura Window's visiblity state is set to visible if
// the underlying widget is hidden and then shown.
TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
@@ -1267,16 +1100,16 @@ TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
gfx::Rect initial_bounds(0, 0, 300, 400);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(&widget);
widget.Init(init_params);
NonClientView* non_client_view = widget.non_client_view();
NonClientFrameView* frame_view = new MinimumSizeFrameView(&widget);
non_client_view->SetFrameView(frame_view);
widget.Hide();
- EXPECT_FALSE(widget.GetNativeView()->IsVisible());
+ EXPECT_FALSE(IsNativeWindowVisible(widget.GetNativeWindow()));
widget.Show();
- EXPECT_TRUE(widget.GetNativeView()->IsVisible());
+ EXPECT_TRUE(IsNativeWindowVisible(widget.GetNativeWindow()));
}
// The following code verifies we can correctly destroy a Widget from a mouse
@@ -1284,84 +1117,38 @@ TEST_F(WidgetTest, TestWindowVisibilityAfterHide) {
// nested message loops from such events, nor has the code ever really dealt
// with this situation.
-// Class that closes the widget (which ends up deleting it immediately) when the
-// appropriate event is received.
-class CloseWidgetView : public View {
- public:
- explicit CloseWidgetView(ui::EventType event_type)
- : event_type_(event_type) {
- }
-
- // View overrides:
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMousePressed(event);
- return true;
- }
- virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseDragged(event);
- return true;
- }
- virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseReleased(event);
- }
- virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseMoved(event);
- }
- virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
- if (!CloseWidget(event))
- View::OnMouseEntered(event);
- }
-
- private:
- bool CloseWidget(const ui::LocatedEvent& event) {
- if (event.type() == event_type_) {
- // Go through NativeWidgetPrivate to simulate what happens if the OS
- // deletes the NativeWindow out from under us.
- GetWidget()->native_widget_private()->CloseNow();
- return true;
- }
- return false;
- }
-
- const ui::EventType event_type_;
-
- DISALLOW_COPY_AND_ASSIGN(CloseWidgetView);
-};
-
// Generates two moves (first generates enter, second real move), a press, drag
// and release stopping at |last_event_type|.
void GenerateMouseEvents(Widget* widget, ui::EventType last_event_type) {
const gfx::Rect screen_bounds(widget->GetWindowBoundsInScreen());
ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, screen_bounds.CenterPoint(),
- screen_bounds.CenterPoint(), 0);
- aura::RootWindowHostDelegate* rwhd =
- widget->GetNativeWindow()->GetDispatcher()->AsRootWindowHostDelegate();
- rwhd->OnHostMouseEvent(&move_event);
- if (last_event_type == ui::ET_MOUSE_ENTERED)
+ screen_bounds.CenterPoint(), 0, 0);
+ ui::EventProcessor* dispatcher = WidgetTest::GetEventProcessor(widget);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move_event);
+ if (last_event_type == ui::ET_MOUSE_ENTERED || details.dispatcher_destroyed)
return;
- rwhd->OnHostMouseEvent(&move_event);
- if (last_event_type == ui::ET_MOUSE_MOVED)
+ details = dispatcher->OnEventFromSource(&move_event);
+ if (last_event_type == ui::ET_MOUSE_MOVED || details.dispatcher_destroyed)
return;
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, screen_bounds.CenterPoint(),
- screen_bounds.CenterPoint(), 0);
- rwhd->OnHostMouseEvent(&press_event);
- if (last_event_type == ui::ET_MOUSE_PRESSED)
+ screen_bounds.CenterPoint(), 0, 0);
+ details = dispatcher->OnEventFromSource(&press_event);
+ if (last_event_type == ui::ET_MOUSE_PRESSED || details.dispatcher_destroyed)
return;
gfx::Point end_point(screen_bounds.CenterPoint());
end_point.Offset(1, 1);
- ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0);
- rwhd->OnHostMouseEvent(&drag_event);
- if (last_event_type == ui::ET_MOUSE_DRAGGED)
+ ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, end_point, end_point, 0, 0);
+ details = dispatcher->OnEventFromSource(&drag_event);
+ if (last_event_type == ui::ET_MOUSE_DRAGGED || details.dispatcher_destroyed)
return;
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0);
- rwhd->OnHostMouseEvent(&release_event);
+ ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, end_point, end_point, 0,
+ 0);
+ details = dispatcher->OnEventFromSource(&release_event);
+ if (details.dispatcher_destroyed)
+ return;
}
// Creates a widget and invokes GenerateMouseEvents() with |last_event_type|.
@@ -1371,7 +1158,7 @@ void RunCloseWidgetDuringDispatchTest(WidgetTest* test,
Widget* widget = new Widget;
Widget::InitParams params =
test->CreateParams(Widget::InitParams::TYPE_POPUP);
- params.native_widget = new DesktopNativeWidgetAura(widget);
+ params.native_widget = new PlatformDesktopNativeWidget(widget);
params.bounds = gfx::Rect(0, 0, 50, 100);
widget->Init(params);
widget->SetContentsView(new CloseWidgetView(last_event_type));
@@ -1430,8 +1217,6 @@ TEST_F(WidgetTest, WheelEventsFromScrollEventTarget) {
widget->CloseNow();
}
-#endif // defined(USE_AURA)
-
// Tests that if a scroll-begin gesture is not handled, then subsequent scroll
// events are not dispatched to any view.
TEST_F(WidgetTest, GestureScrollEventDispatching) {
@@ -1493,13 +1278,15 @@ TEST_F(WidgetTest, GestureScrollEventDispatching) {
}
// Tests that event-handlers installed on the RootView get triggered correctly.
+// TODO(tdanderson): Clean up this test as part of crbug.com/355680.
TEST_F(WidgetTest, EventHandlersOnRootView) {
Widget* widget = CreateTopLevelNativeWidget();
View* root_view = widget->GetRootView();
- EventCountView* view = new EventCountView;
+ scoped_ptr<EventCountView> view(new EventCountView());
+ view->set_owned_by_client();
view->SetBounds(0, 0, 20, 20);
- root_view->AddChildView(view);
+ root_view->AddChildView(view.get());
EventCountHandler h1;
root_view->AddPreTargetHandler(&h1);
@@ -1510,16 +1297,6 @@ TEST_F(WidgetTest, EventHandlersOnRootView) {
widget->SetBounds(gfx::Rect(0, 0, 100, 100));
widget->Show();
- ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
- gfx::Point(10, 10),
- 0, 0,
- ui::EventTimeForNow(),
- 1.0, 0.0, 1.0, 0.0);
- widget->OnTouchEvent(&pressed);
- EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_PRESSED));
- EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_PRESSED));
- EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_PRESSED));
-
ui::GestureEvent begin(ui::ET_GESTURE_BEGIN,
5, 5, 0, ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0, 0), 1);
@@ -1531,16 +1308,6 @@ TEST_F(WidgetTest, EventHandlersOnRootView) {
EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_BEGIN));
EXPECT_EQ(1, h2.GetEventCount(ui::ET_GESTURE_BEGIN));
- ui::TouchEvent released(ui::ET_TOUCH_RELEASED,
- gfx::Point(10, 10),
- 0, 0,
- ui::EventTimeForNow(),
- 1.0, 0.0, 1.0, 0.0);
- widget->OnTouchEvent(&released);
- EXPECT_EQ(1, h1.GetEventCount(ui::ET_TOUCH_RELEASED));
- EXPECT_EQ(1, view->GetEventCount(ui::ET_TOUCH_RELEASED));
- EXPECT_EQ(1, h2.GetEventCount(ui::ET_TOUCH_RELEASED));
-
widget->OnGestureEvent(&end);
EXPECT_EQ(1, h1.GetEventCount(ui::ET_GESTURE_END));
EXPECT_EQ(1, view->GetEventCount(ui::ET_GESTURE_END));
@@ -1554,9 +1321,67 @@ TEST_F(WidgetTest, EventHandlersOnRootView) {
0, 20,
2);
widget->OnScrollEvent(&scroll);
- EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL));
EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL));
- EXPECT_EQ(1, h2.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL));
+
+ // Unhandled scroll events are turned into wheel events and re-dispatched.
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(1, h2.GetEventCount(ui::ET_MOUSEWHEEL));
+
+ h1.ResetCounts();
+ view->ResetCounts();
+ h2.ResetCounts();
+
+ ui::ScrollEvent fling(ui::ET_SCROLL_FLING_START,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&fling);
+ EXPECT_EQ(2, h1.GetEventCount(ui::ET_SCROLL_FLING_START));
+ EXPECT_EQ(1, view->GetEventCount(ui::ET_SCROLL_FLING_START));
+ EXPECT_EQ(2, h2.GetEventCount(ui::ET_SCROLL_FLING_START));
+
+ // Unhandled scroll events which are not of type ui::ET_SCROLL should not
+ // be turned into wheel events and re-dispatched.
+ EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
+
+ h1.ResetCounts();
+ view->ResetCounts();
+ h2.ResetCounts();
+
+ // Replace the child of |root_view| with a ScrollableEventCountView so that
+ // ui::ET_SCROLL events are marked as handled at the target phase.
+ root_view->RemoveChildView(view.get());
+ ScrollableEventCountView* scroll_view = new ScrollableEventCountView;
+ scroll_view->SetBounds(0, 0, 20, 20);
+ root_view->AddChildView(scroll_view);
+
+ ui::ScrollEvent consumed_scroll(ui::ET_SCROLL,
+ gfx::Point(5, 5),
+ ui::EventTimeForNow(),
+ 0,
+ 0, 20,
+ 0, 20,
+ 2);
+ widget->OnScrollEvent(&consumed_scroll);
+
+ // The event is handled at the target phase and should not reach the
+ // post-target handler.
+ EXPECT_EQ(1, h1.GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(1, scroll_view->GetEventCount(ui::ET_SCROLL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_SCROLL));
+
+ // Handled scroll events are not turned into wheel events and re-dispatched.
+ EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, scroll_view->GetEventCount(ui::ET_MOUSEWHEEL));
+ EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
widget->CloseNow();
}
@@ -1574,7 +1399,7 @@ TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
gfx::Point cursor_location(5, 5);
ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EF_NONE);
+ ui::EF_NONE, ui::EF_NONE);
widget->OnMouseEvent(&move);
EXPECT_EQ(1, v1->GetEventCount(ui::ET_MOUSE_ENTERED));
@@ -1621,8 +1446,8 @@ TEST_F(WidgetTest, SingleWindowClosing) {
CreateParams(Widget::InitParams::TYPE_WINDOW);
init_params.bounds = gfx::Rect(0, 0, 200, 200);
init_params.delegate = delegate.get();
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
- init_params.native_widget = new DesktopNativeWidgetAura(widget);
+#if !defined(OS_CHROMEOS)
+ init_params.native_widget = new PlatformDesktopNativeWidget(widget);
#endif
widget->Init(init_params);
EXPECT_EQ(0, delegate->count());
@@ -1638,9 +1463,9 @@ class WidgetWindowTitleTest : public WidgetTest {
CreateParams(Widget::InitParams::TYPE_WINDOW);
widget->Init(init_params);
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (desktop_native_widget)
- init_params.native_widget = new DesktopNativeWidgetAura(widget);
+ init_params.native_widget = new PlatformDesktopNativeWidget(widget);
#else
DCHECK(!desktop_native_widget)
<< "DesktopNativeWidget does not exist on non-Aura or on ChromeOS.";
@@ -1649,10 +1474,10 @@ class WidgetWindowTitleTest : public WidgetTest {
internal::NativeWidgetPrivate* native_widget =
widget->native_widget_private();
- string16 empty;
- string16 s1(UTF8ToUTF16("Title1"));
- string16 s2(UTF8ToUTF16("Title2"));
- string16 s3(UTF8ToUTF16("TitleLong"));
+ base::string16 empty;
+ base::string16 s1(base::UTF8ToUTF16("Title1"));
+ base::string16 s2(base::UTF8ToUTF16("Title2"));
+ base::string16 s3(base::UTF8ToUTF16("TitleLong"));
// The widget starts with no title, setting empty should not change
// anything.
@@ -1679,85 +1504,50 @@ TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_NativeWidget) {
}
// DesktopNativeWidget does not exist on non-Aura or on ChromeOS.
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
// Override to use a DesktopNativeWidget.
bool desktop_native_widget = true;
RunTest(desktop_native_widget);
}
-#endif // USE_AURA && !OS_CHROMEOS
+#endif // !OS_CHROMEOS
-// Used by SetTopLevelCorrectly to track calls to OnBeforeWidgetInit().
-class VerifyTopLevelDelegate : public TestViewsDelegate {
- public:
- VerifyTopLevelDelegate()
- : on_before_init_called_(false),
- is_top_level_(false) {
- }
-
- bool on_before_init_called() const { return on_before_init_called_; }
- bool is_top_level() const { return is_top_level_; }
-
- virtual void OnBeforeWidgetInit(
- Widget::InitParams* params,
- internal::NativeWidgetDelegate* delegate) OVERRIDE {
- on_before_init_called_ = true;
- is_top_level_ = params->top_level;
- }
-
- private:
- bool on_before_init_called_;
- bool is_top_level_;
-
- DISALLOW_COPY_AND_ASSIGN(VerifyTopLevelDelegate);
-};
-
-// Verifies |top_level| is correctly passed to
-// ViewsDelegate::OnBeforeWidgetInit().
-TEST_F(WidgetTest, SetTopLevelCorrectly) {
- set_views_delegate(NULL);
- VerifyTopLevelDelegate* delegate = new VerifyTopLevelDelegate;
- set_views_delegate(delegate); // ViewsTestBase takes ownership.
- scoped_ptr<Widget> widget(new Widget);
+TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
+ Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
- EXPECT_TRUE(delegate->on_before_init_called());
- EXPECT_TRUE(delegate->is_top_level());
-}
-// A scumbag View that deletes its owning widget OnMousePressed.
-class WidgetDeleterView : public View {
- public:
- WidgetDeleterView() : View() {}
+ widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
- // Overridden from View.
- virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
- delete GetWidget();
- return true;
- }
+ widget->SetSize(gfx::Size(100, 100));
+ widget->Show();
- private:
- DISALLOW_COPY_AND_ASSIGN(WidgetDeleterView);
-};
+ aura::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
-TEST_F(WidgetTest, TestWidgetDeletedInOnMousePressed) {
+ WidgetDeletionObserver deletion_observer(widget);
+ generator.ClickLeftButton();
+ EXPECT_FALSE(deletion_observer.IsWidgetAlive());
+
+ // Yay we did not crash!
+}
+
+TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
- widget->SetContentsView(new WidgetDeleterView);
+ widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
widget->SetSize(gfx::Size(100, 100));
widget->Show();
- gfx::Point click_location(45, 15);
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
- ui::EF_LEFT_MOUSE_BUTTON);
- widget->OnMouseEvent(&press);
+ aura::test::EventGenerator generator(GetContext());
+
+ WidgetDeletionObserver deletion_observer(widget);
+ generator.GestureTapAt(widget->GetWindowBoundsInScreen().CenterPoint());
+ EXPECT_FALSE(deletion_observer.IsWidgetAlive());
// Yay we did not crash!
}
@@ -1794,9 +1584,9 @@ bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params,
Widget::InitParams params(in_params);
// Deletes itself when the Widget is destroyed.
params.delegate = new GetNativeThemeFromDestructorView;
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (is_first_run) {
- params.native_widget = new DesktopNativeWidgetAura(widget);
+ params.native_widget = new PlatformDesktopNativeWidget(widget);
needs_second_run = true;
}
#endif
@@ -1843,8 +1633,8 @@ TEST_F(WidgetTest, CloseDestroys) {
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_MENU);
params.opacity = Widget::InitParams::OPAQUE_WINDOW;
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
- params.native_widget = new DesktopNativeWidgetAura(widget);
+#if !defined(OS_CHROMEOS)
+ params.native_widget = new PlatformDesktopNativeWidget(widget);
#endif
widget->Init(params);
widget->Show();
@@ -1860,6 +1650,24 @@ TEST_F(WidgetTest, CloseDestroys) {
}
}
+// Tests that killing a widget while animating it does not crash.
+TEST_F(WidgetTest, CloseWidgetWhileAnimating) {
+ scoped_ptr<Widget> widget(new Widget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+
+ // Normal animations for tests have ZERO_DURATION, make sure we are actually
+ // animating the movement.
+ ui::ScopedAnimationDurationScaleMode animation_scale_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::ScopedLayerAnimationSettings animation_settings(
+ widget->GetLayer()->GetAnimator());
+ widget->Show();
+ // Animate the bounds change.
+ widget->SetBounds(gfx::Rect(0, 0, 200, 200));
+}
+
// A view that consumes mouse-pressed event and gesture-tap-down events.
class RootViewTestView : public View {
public:
@@ -1899,7 +1707,7 @@ TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
EXPECT_EQ(NULL, GetMousePressedHandler(root_view));
gfx::Point click_location(45, 15);
ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
- ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
widget->OnMouseEvent(&press);
EXPECT_EQ(view, GetMousePressedHandler(root_view));
widget->Hide();
@@ -1909,7 +1717,7 @@ TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
widget->Show();
EXPECT_EQ(NULL, GetMouseMoveHandler(root_view));
gfx::Point move_location(45, 15);
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0);
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, move_location, move_location, 0, 0);
widget->OnMouseEvent(&move);
EXPECT_EQ(view, GetMouseMoveHandler(root_view));
widget->Hide();
@@ -1934,6 +1742,33 @@ TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
widget->Close();
}
+class GestureEndConsumerView : public View {
+ private:
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ if (event->type() == ui::ET_GESTURE_END)
+ event->SetHandled();
+ }
+};
+
+TEST_F(WidgetTest, GestureHandlerNotSetOnGestureEnd) {
+ Widget* widget = CreateTopLevelNativeWidget();
+ widget->SetBounds(gfx::Rect(0, 0, 300, 300));
+ View* view = new GestureEndConsumerView();
+ view->SetBounds(0, 0, 300, 300);
+ internal::RootView* root_view =
+ static_cast<internal::RootView*>(widget->GetRootView());
+ root_view->AddChildView(view);
+
+ widget->Show();
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+ ui::GestureEvent end(ui::ET_GESTURE_END, 15, 15, 0, base::TimeDelta(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END, 0, 0), 1);
+ widget->OnGestureEvent(&end);
+ EXPECT_EQ(NULL, GetGestureHandler(root_view));
+
+ widget->Close();
+}
+
// Test the result of Widget::GetAllChildWidgets().
TEST_F(WidgetTest, GetAllChildWidgets) {
// Create the following widget hierarchy:
@@ -2001,9 +1836,9 @@ class WidgetChildDestructionTest : public WidgetTest {
Widget* top_level = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (top_level_has_desktop_native_widget_aura)
- params.native_widget = new DesktopNativeWidgetAura(top_level);
+ params.native_widget = new PlatformDesktopNativeWidget(top_level);
#endif
top_level->Init(params);
top_level->GetRootView()->AddChildView(
@@ -2014,9 +1849,9 @@ class WidgetChildDestructionTest : public WidgetTest {
Widget::InitParams child_params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
child_params.parent = top_level->GetNativeView();
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
if (child_has_desktop_native_widget_aura)
- child_params.native_widget = new DesktopNativeWidgetAura(child);
+ child_params.native_widget = new PlatformDesktopNativeWidget(child);
#endif
child->Init(child_params);
child->GetRootView()->AddChildView(
@@ -2036,7 +1871,7 @@ class WidgetChildDestructionTest : public WidgetTest {
DISALLOW_COPY_AND_ASSIGN(WidgetChildDestructionTest);
};
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
// See description of RunDestroyChildWidgetsTest(). Parent uses
// DesktopNativeWidgetAura.
TEST_F(WidgetChildDestructionTest,
@@ -2050,14 +1885,14 @@ TEST_F(WidgetChildDestructionTest,
DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) {
RunDestroyChildWidgetsTest(true, true);
}
-#endif
+#endif // !defined(OS_CHROMEOS)
// See description of RunDestroyChildWidgetsTest().
TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) {
RunDestroyChildWidgetsTest(false, false);
}
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
// Provides functionality to create a window modal dialog.
class ModalDialogDelegate : public DialogDelegateView {
public:
@@ -2084,7 +1919,8 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
gfx::Rect initial_bounds(0, 0, 500, 500);
init_params.bounds = initial_bounds;
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
+ init_params.native_widget =
+ new PlatformDesktopNativeWidget(&top_level_widget);
top_level_widget.Init(init_params);
top_level_widget.Show();
EXPECT_TRUE(top_level_widget.IsVisible());
@@ -2098,9 +1934,11 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
ui::MouseEvent move_main(ui::ET_MOUSE_MOVED,
cursor_location_main,
cursor_location_main,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&move_main);
+ ui::EventDispatchDetails details =
+ GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED));
widget_view->ResetCounts();
@@ -2112,7 +1950,7 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate;
Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
- dialog_delegate, NULL, top_level_widget.GetNativeWindow());
+ dialog_delegate, NULL, top_level_widget.GetNativeView());
modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
EventCountView* dialog_widget_view = new EventCountView();
dialog_widget_view->SetBounds(0, 0, 50, 50);
@@ -2124,9 +1962,11 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
ui::MouseEvent mouse_down_dialog(ui::ET_MOUSE_PRESSED,
cursor_location_dialog,
cursor_location_dialog,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_dialog);
+ details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
+ &mouse_down_dialog);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED));
// Send a mouse move message to the main window. It should not be received by
@@ -2135,16 +1975,17 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED,
cursor_location_main2,
cursor_location_main2,
+ ui::EF_NONE,
ui::EF_NONE);
- top_level_widget.GetNativeView()->GetDispatcher()->
- AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse_down_main);
+ details = GetEventProcessor(&top_level_widget)->OnEventFromSource(
+ &mouse_down_main);
+ ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED));
modal_dialog_widget->CloseNow();
top_level_widget.CloseNow();
}
-#if defined(USE_AURA)
// Verifies nativeview visbility matches that of Widget visibility when
// SetFullscreen is invoked.
TEST_F(WidgetTest, FullscreenStatePropagated) {
@@ -2159,23 +2000,23 @@ TEST_F(WidgetTest, FullscreenStatePropagated) {
top_level_widget.Init(init_params);
top_level_widget.SetFullscreen(true);
EXPECT_EQ(top_level_widget.IsVisible(),
- top_level_widget.GetNativeView()->IsVisible());
+ IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
top_level_widget.CloseNow();
}
#if !defined(OS_CHROMEOS)
{
Widget top_level_widget;
- init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget);
+ init_params.native_widget =
+ new PlatformDesktopNativeWidget(&top_level_widget);
top_level_widget.Init(init_params);
top_level_widget.SetFullscreen(true);
EXPECT_EQ(top_level_widget.IsVisible(),
- top_level_widget.GetNativeView()->IsVisible());
+ IsNativeWindowVisible(top_level_widget.GetNativeWindow()));
top_level_widget.CloseNow();
}
#endif
}
-#endif
#if defined(OS_WIN)
@@ -2268,8 +2109,67 @@ TEST_F(WidgetTest, WindowModalityActivationTest) {
modal_dialog_widget->CloseNow();
top_level_widget.CloseNow();
}
-#endif
-#endif
+#endif // defined(OS_WIN)
+#endif // !defined(OS_CHROMEOS)
+
+TEST_F(WidgetTest, ShowCreatesActiveWindow) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowInactive) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->ShowInactive();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowInactiveAfterShow) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->Show();
+ widget->ShowInactive();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+TEST_F(WidgetTest, ShowAfterShowInactive) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+
+ widget->ShowInactive();
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+}
+
+#if !defined(OS_CHROMEOS)
+TEST_F(WidgetTest, InactiveWidgetDoesNotGrabActivation) {
+ Widget* widget = CreateTopLevelPlatformWidget();
+ widget->Show();
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ Widget widget2;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.native_widget = new PlatformDesktopNativeWidget(&widget2);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget2.Init(params);
+ widget2.Show();
+
+ EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
+ EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+
+ widget->CloseNow();
+ widget2.CloseNow();
+}
+#endif // !defined(OS_CHROMEOS)
namespace {
@@ -2359,7 +2259,7 @@ TEST_F(WidgetTest, IsActiveFromDestroy) {
Widget parent_widget;
Widget::InitParams parent_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
- parent_params.native_widget = new DesktopNativeWidgetAura(&parent_widget);
+ parent_params.native_widget = new PlatformDesktopNativeWidget(&parent_widget);
parent_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
parent_widget.Init(parent_params);
parent_widget.Show();
@@ -2375,7 +2275,7 @@ TEST_F(WidgetTest, IsActiveFromDestroy) {
parent_widget.CloseNow();
}
-#endif
+#endif // !defined(OS_CHROMEOS)
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc
index 1d9566c916e..67cf246e73a 100644
--- a/chromium/ui/views/widget/window_reorderer_unittest.cc
+++ b/chromium/ui/views/widget/window_reorderer_unittest.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/test/test_layers.h"
#include "ui/views/view.h"
diff --git a/chromium/ui/views/win/DEPS b/chromium/ui/views/win/DEPS
index 2365859be11..8cab1708ab1 100644
--- a/chromium/ui/views/win/DEPS
+++ b/chromium/ui/views/win/DEPS
@@ -19,9 +19,7 @@ include_rules = [
"+ui/views/ime/input_method_delegate.h",
"+ui/views/views_delegate.h",
"+ui/views/views_export.h",
- "+ui/views/widget/child_window_message_processor.h",
"+ui/views/widget/monitor_win.h",
- "+ui/views/widget/native_widget_win.h",
"+ui/views/widget/widget_hwnd_utils.h",
"+ui/views/win",
]
diff --git a/chromium/ui/views/win/appbar.cc b/chromium/ui/views/win/appbar.cc
deleted file mode 100644
index 92151d47756..00000000000
--- a/chromium/ui/views/win/appbar.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/win/appbar.h"
-
-#include <shellapi.h>
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/threading/worker_pool.h"
-#include "base/win/scoped_com_initializer.h"
-#include "ui/views/widget/monitor_win.h"
-
-namespace views {
-
-namespace {
-
-void GetEdgesOnWorkerThread(HMONITOR monitor, int* edge) {
- base::win::ScopedCOMInitializer com_initializer;
- *edge = 0;
- if (GetTopmostAutoHideTaskbarForEdge(ABE_LEFT, monitor))
- *edge = Appbar::EDGE_LEFT;
- if (GetTopmostAutoHideTaskbarForEdge(ABE_TOP, monitor))
- *edge = Appbar::EDGE_TOP;
- if (GetTopmostAutoHideTaskbarForEdge(ABE_RIGHT, monitor))
- *edge = Appbar::EDGE_RIGHT;
- if (GetTopmostAutoHideTaskbarForEdge(ABE_BOTTOM, monitor))
- *edge = Appbar::EDGE_BOTTOM;
-}
-
-}
-
-// static
-Appbar* Appbar::instance() {
- static Appbar* appbar = NULL;
- if (!appbar)
- appbar = new Appbar();
- return appbar;
-}
-
-int Appbar::GetAutohideEdges(HMONITOR monitor, const base::Closure& callback) {
- // Initialize the map with EDGE_BOTTOM. This is important, as if we return an
- // initial value of 0 (no auto-hide edges) then we'll go fullscreen and
- // windows will automatically remove WS_EX_TOPMOST from the appbar resulting
- // in us thinking there is no auto-hide edges. By returning at least one edge
- // we don't initially go fullscreen until we figure out the real auto-hide
- // edges.
- if (edge_map_.find(monitor) == edge_map_.end())
- edge_map_[monitor] = Appbar::EDGE_BOTTOM;
- if (!in_callback_) {
- int* edge = new int;
- base::WorkerPool::PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GetEdgesOnWorkerThread,
- monitor,
- base::Unretained(edge)),
- base::Bind(&Appbar::OnGotEdges,
- weak_factory_.GetWeakPtr(),
- callback,
- monitor,
- edge_map_[monitor],
- base::Owned(edge)),
- false);
- }
- return edge_map_[monitor];
-}
-
-Appbar::Appbar() : weak_factory_(this), in_callback_(false) {
-}
-
-Appbar::~Appbar() {
-}
-
-void Appbar::OnGotEdges(const base::Closure& callback,
- HMONITOR monitor,
- int returned_edges,
- int* edges) {
- edge_map_[monitor] = *edges;
- if (returned_edges == *edges)
- return;
-
- base::AutoReset<bool> in_callback_setter(&in_callback_, true);
- callback.Run();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/win/appbar.h b/chromium/ui/views/win/appbar.h
deleted file mode 100644
index 4c24c192548..00000000000
--- a/chromium/ui/views/win/appbar.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIN_APPBAR_H_
-#define UI_VIEWS_WIN_APPBAR_H_
-
-#include <map>
-
-#include <windows.h>
-
-#include "base/basictypes.h"
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-
-namespace views {
-
-// Appbar provides an API to query for the edges of the monitor that have an
-// autohide bar.
-// NOTE: querying is done on a separate thread as it spawns a nested message
-// loop. The nested message loop is particularly problematic here as it's
-// possible for the nested message loop to run during window creation and
-// startup time (WM_NCCALCSIZE is called at creation time).
-class Appbar {
- public:
- enum Edge {
- EDGE_TOP = 1 << 0,
- EDGE_LEFT = 1 << 1,
- EDGE_BOTTOM = 1 << 2,
- EDGE_RIGHT = 1 << 3,
- };
-
- // Returns the singleton instance.
- static Appbar* instance();
-
- // Starts a query for the autohide edges of the specified monitor and returns
- // the current value. If the edges have changed |callback| is subsequently
- // invoked. If the edges have not changed |callback| is never run.
- //
- // Return value is a bitmask of Edges.
- int GetAutohideEdges(HMONITOR monitor, const base::Closure& callback);
-
- private:
- typedef std::map<HMONITOR, int> EdgeMap;
-
- Appbar();
- ~Appbar();
-
- // Callback on main thread with the edges. |returned_edges| is the value that
- // was returned from the call to GetAutohideEdges() that initiated the lookup.
- void OnGotEdges(const base::Closure& callback,
- HMONITOR monitor,
- int returned_edges,
- int* edges);
-
- EdgeMap edge_map_;
-
- base::WeakPtrFactory<Appbar> weak_factory_;
-
- // If true we're in the process of notifying a callback. When true we do not
- // start a new query.
- bool in_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(Appbar);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIN_APPBAR_H_
-
diff --git a/chromium/ui/views/win/fullscreen_handler.cc b/chromium/ui/views/win/fullscreen_handler.cc
index 2fe8ceaf2b5..a6f51567856 100644
--- a/chromium/ui/views/win/fullscreen_handler.cc
+++ b/chromium/ui/views/win/fullscreen_handler.cc
@@ -76,8 +76,8 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen, bool for_metro) {
if (!for_metro) {
MONITORINFO monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(
- MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST), &monitor_info);
+ GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST),
+ &monitor_info);
gfx::Rect window_rect(monitor_info.rcMonitor);
SetWindowPos(hwnd_, NULL, window_rect.x(), window_rect.y(),
window_rect.width(), window_rect.height(),
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index ab43f1224ff..adbe4fabe69 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -5,6 +5,7 @@
#include "ui/views/win/hwnd_message_handler.h"
#include <dwmapi.h>
+#include <oleacc.h>
#include <shellapi.h>
#include <wtsapi32.h>
#pragma comment(lib, "wtsapi32.lib")
@@ -14,6 +15,8 @@
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "ui/base/touch/touch_enabled.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/win/internal_constants.h"
#include "ui/base/win/lock_state.h"
#include "ui/base/win/mouse_wheel_util.h"
#include "ui/base/win/shell.h"
@@ -34,18 +37,11 @@
#include "ui/native_theme/native_theme_win.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/monitor_win.h"
-#include "ui/views/widget/native_widget_win.h"
#include "ui/views/widget/widget_hwnd_utils.h"
-#include "ui/views/win/appbar.h"
#include "ui/views/win/fullscreen_handler.h"
#include "ui/views/win/hwnd_message_handler_delegate.h"
#include "ui/views/win/scoped_fullscreen_visibility.h"
-#if !defined(USE_AURA)
-#include "ui/views/accessibility/native_view_accessibility_win.h"
-#include "ui/views/widget/child_window_message_processor.h"
-#endif
-
namespace views {
namespace {
@@ -186,7 +182,7 @@ bool GetMonitorAndRects(const RECT& rect,
return false;
MONITORINFO monitor_info = { 0 };
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(*monitor, &monitor_info);
+ GetMonitorInfo(*monitor, &monitor_info);
*monitor_rect = gfx::Rect(monitor_info.rcMonitor);
*work_area = gfx::Rect(monitor_info.rcWork);
return true;
@@ -197,19 +193,6 @@ struct FindOwnedWindowsData {
std::vector<Widget*> owned_widgets;
};
-BOOL CALLBACK FindOwnedWindowsCallback(HWND hwnd, LPARAM param) {
- // TODO(beng): resolve wrt aura.
-#if !defined(USE_AURA)
- FindOwnedWindowsData* data = reinterpret_cast<FindOwnedWindowsData*>(param);
- if (GetWindow(hwnd, GW_OWNER) == data->window) {
- Widget* widget = Widget::GetWidgetForNativeView(hwnd);
- if (widget)
- data->owned_widgets.push_back(widget);
- }
-#endif
- return TRUE;
-}
-
// Enables or disables the menu item for the specified command and menu.
void EnableMenuItemByCommand(HMENU menu, UINT command, bool enabled) {
UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
@@ -251,54 +234,6 @@ static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
return TRUE;
}
-#if !defined(USE_AURA)
-
-// Get the source HWND of the specified message. Depending on the message, the
-// source HWND is encoded in either the WPARAM or the LPARAM value.
-HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) {
- // Each of the following messages can be sent by a child HWND and must be
- // forwarded to its associated NativeControlWin for handling.
- switch (message) {
- case WM_NOTIFY:
- return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
- case WM_COMMAND:
- return reinterpret_cast<HWND>(l_param);
- case WM_CONTEXTMENU:
- return reinterpret_cast<HWND>(w_param);
- case WM_CTLCOLORBTN:
- case WM_CTLCOLORSTATIC:
- return reinterpret_cast<HWND>(l_param);
- }
- return NULL;
-}
-
-// Some messages may be sent to us by a child HWND. If this is the case, this
-// function will forward those messages on to the object associated with the
-// source HWND and return true, in which case the window procedure must not do
-// any further processing of the message. If there is no associated
-// ChildWindowMessageProcessor, the return value will be false and the WndProc
-// can continue processing the message normally. |l_result| contains the result
-// of the message processing by the control and must be returned by the WndProc
-// if the return value is true.
-bool ProcessChildWindowMessage(UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* l_result) {
- *l_result = 0;
-
- HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
- if (IsWindow(control_hwnd)) {
- ChildWindowMessageProcessor* processor =
- ChildWindowMessageProcessor::Get(control_hwnd);
- if (processor)
- return processor->ProcessMessage(message, w_param, l_param, l_result);
- }
-
- return false;
-}
-
-#endif
-
// The thickness of an auto-hide taskbar in pixels.
const int kAutoHideTaskbarThicknessPx = 2;
@@ -318,6 +253,15 @@ void AddScrollStylesToWindow(HWND window) {
}
}
+const int kTouchDownContextResetTimeout = 500;
+
+// Windows does not flag synthesized mouse messages from touch in all cases.
+// This causes us grief as we don't want to process touch and mouse messages
+// concurrently. Hack as per msdn is to check if the time difference between
+// the touch message and the mouse move is within 500 ms and at the same
+// location as the cursor.
+const int kSynthesizedMouseTouchMessagesTimeDifference = 500;
+
} // namespace
// A scoping class that prevents a window from being able to redraw in response
@@ -387,6 +331,8 @@ class HWNDMessageHandler::ScopedRedrawLock {
////////////////////////////////////////////////////////////////////////////////
// HWNDMessageHandler, public:
+long HWNDMessageHandler::last_touch_message_time_ = 0;
+
HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
: delegate_(delegate),
fullscreen_handler_(new FullscreenHandler),
@@ -394,7 +340,6 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
waiting_for_close_now_(false),
remove_standard_frame_(false),
use_system_default_icon_(false),
- restore_focus_when_enabled_(false),
restored_enabled_(false),
current_cursor_(NULL),
previous_cursor_(NULL),
@@ -407,10 +352,14 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
layered_alpha_(255),
waiting_for_redraw_layered_window_contents_(false),
is_first_nccalc_(true),
+ menu_depth_(0),
autohide_factory_(this),
id_generator_(0),
needs_scroll_styles_(false),
- in_size_loop_(false) {
+ in_size_loop_(false),
+ touch_down_contexts_(0),
+ last_mouse_hwheel_time_(0),
+ msg_handled_(FALSE) {
}
HWNDMessageHandler::~HWNDMessageHandler() {
@@ -427,8 +376,9 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
// Create the window.
WindowImpl::Init(parent, bounds);
-
-#if defined(USE_AURA)
+ // TODO(ananta)
+ // Remove the scrolling hack code once we have scrolling working well.
+#if defined(ENABLE_SCROLL_HACK)
// Certain trackpad drivers on Windows have bugs where in they don't generate
// WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
// unless there is an entry for Chrome with the class name of the Window.
@@ -448,6 +398,10 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
}
}
#endif
+
+ prop_window_target_.reset(new ui::ViewProp(hwnd(),
+ ui::WindowEventTarget::kWin32InputEventTarget,
+ static_cast<ui::WindowEventTarget*>(this)));
}
void HWNDMessageHandler::InitModalType(ui::ModalType modal_type) {
@@ -549,7 +503,7 @@ void HWNDMessageHandler::GetWindowPlacement(
} else {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
- const bool succeeded = base::win::GetMonitorInfoWrapper(
+ const bool succeeded = GetMonitorInfo(
MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi) != 0;
DCHECK(succeeded);
@@ -571,13 +525,24 @@ void HWNDMessageHandler::GetWindowPlacement(
}
}
-void HWNDMessageHandler::SetBounds(const gfx::Rect& bounds_in_pixels) {
+void HWNDMessageHandler::SetBounds(const gfx::Rect& bounds_in_pixels,
+ bool force_size_changed) {
LONG style = GetWindowLong(hwnd(), GWL_STYLE);
if (style & WS_MAXIMIZE)
SetWindowLong(hwnd(), GWL_STYLE, style & ~WS_MAXIMIZE);
+
+ gfx::Size old_size = GetClientAreaBounds().size();
SetWindowPos(hwnd(), NULL, bounds_in_pixels.x(), bounds_in_pixels.y(),
bounds_in_pixels.width(), bounds_in_pixels.height(),
SWP_NOACTIVATE | SWP_NOZORDER);
+
+ // If HWND size is not changed, we will not receive standard size change
+ // notifications. If |force_size_changed| is |true|, we should pretend size is
+ // changed.
+ if (old_size == bounds_in_pixels.size() && force_size_changed) {
+ delegate_->HandleClientSizeChanged(GetClientAreaBounds().size());
+ ResetWindowRegion(false, true);
+ }
}
void HWNDMessageHandler::SetSize(const gfx::Size& size) {
@@ -609,8 +574,14 @@ void HWNDMessageHandler::StackAtTop() {
}
void HWNDMessageHandler::Show() {
- if (IsWindow(hwnd()))
- ShowWindowWithState(ui::SHOW_STATE_INACTIVE);
+ if (IsWindow(hwnd())) {
+ if (!(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) &&
+ !(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
+ ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+ } else {
+ ShowWindowWithState(ui::SHOW_STATE_INACTIVE);
+ }
+ }
}
void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
@@ -630,30 +601,28 @@ void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
native_show_state = delegate_->GetInitialShowState();
break;
}
- Show(native_show_state);
-}
-void HWNDMessageHandler::Show(int show_state) {
- ShowWindow(hwnd(), show_state);
+ ShowWindow(hwnd(), native_show_state);
// When launched from certain programs like bash and Windows Live Messenger,
// show_state is set to SW_HIDE, so we need to correct that condition. We
// don't just change show_state to SW_SHOWNORMAL because MSDN says we must
// always first call ShowWindow with the specified value from STARTUPINFO,
// otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead,
// we call ShowWindow again in this case.
- if (show_state == SW_HIDE) {
- show_state = SW_SHOWNORMAL;
- ShowWindow(hwnd(), show_state);
+ if (native_show_state == SW_HIDE) {
+ native_show_state = SW_SHOWNORMAL;
+ ShowWindow(hwnd(), native_show_state);
}
// We need to explicitly activate the window if we've been shown with a state
// that should activate, because if we're opened from a desktop shortcut while
// an existing window is already running it doesn't seem to be enough to use
// one of these flags to activate the window.
- if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED)
+ if (native_show_state == SW_SHOWNORMAL ||
+ native_show_state == SW_SHOWMAXIMIZED)
Activate();
- if (!delegate_->HandleInitialFocus())
+ if (!delegate_->HandleInitialFocus(show_state))
SetInitialFocus();
}
@@ -674,9 +643,6 @@ void HWNDMessageHandler::Hide() {
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0,
SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
-
- if (!GetParent(hwnd()))
- NotifyOwnedWindowsParentClosing();
}
}
@@ -740,12 +706,11 @@ bool HWNDMessageHandler::RunMoveLoop(const gfx::Vector2d& drag_offset,
bool hide_on_escape) {
ReleaseCapture();
MoveLoopMouseWatcher watcher(this, hide_on_escape);
-#if defined(USE_AURA)
// In Aura, we handle touch events asynchronously. So we need to allow nested
// tasks while in windows move loop.
base::MessageLoop::ScopedNestableTaskAllower allow_nested(
base::MessageLoop::current());
-#endif
+
SendMessage(hwnd(), WM_SYSCOMMAND, SC_MOVE | 0x0002, GetMessagePos());
// Windows doesn't appear to offer a way to determine whether the user
// canceled the move or not. We assume if the user released the mouse it was
@@ -804,8 +769,8 @@ void HWNDMessageHandler::SetVisibilityChangedAnimationsEnabled(bool enabled) {
}
}
-bool HWNDMessageHandler::SetTitle(const string16& title) {
- string16 current_title;
+bool HWNDMessageHandler::SetTitle(const base::string16& title) {
+ base::string16 current_title;
size_t len_with_null = GetWindowTextLength(hwnd()) + 1;
if (len_with_null == 1 && title.length() == 0)
return false;
@@ -831,6 +796,7 @@ void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
void HWNDMessageHandler::FrameTypeChanged() {
// Called when the frame type could possibly be changing (theme change or
// DWM composition change).
+ UpdateDwmNcRenderingPolicy();
// Don't redraw the window here, because we need to hide and show the window
// which will also trigger a redraw.
@@ -849,8 +815,9 @@ void HWNDMessageHandler::FrameTypeChanged() {
UINT flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW);
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW);
-
- UpdateWindow(hwnd());
+ // Invalidate the window to force a paint. There may be child windows which
+ // could resize in this context. Don't paint right away.
+ ::InvalidateRect(hwnd(), NULL, FALSE);
}
// WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want
@@ -937,14 +904,6 @@ LRESULT HWNDMessageHandler::OnWndProc(UINT message,
if (delegate_ && delegate_->PreHandleMSG(message, w_param, l_param, &result))
return result;
-#if !defined(USE_AURA)
- // First allow messages sent by child controls to be processed directly by
- // their associated views. If such a view is present, it will handle the
- // message *instead of* this NativeWidgetWin.
- if (ProcessChildWindowMessage(message, w_param, l_param, &result))
- return result;
-#endif
-
// Otherwise we handle everything else.
// NOTE: We inline ProcessWindowMessage() as 'this' may be destroyed during
// dispatch and ProcessWindowMessage() doesn't deal with that well.
@@ -963,40 +922,48 @@ LRESULT HWNDMessageHandler::OnWndProc(UINT message,
if (!::IsWindow(window))
return result;
- if (delegate_)
+ if (delegate_) {
delegate_->PostHandleMSG(message, w_param, l_param);
- if (message == WM_NCDESTROY) {
-#if !defined(USE_AURA)
- base::MessageLoopForUI::current()->RemoveObserver(this);
-#endif
- if (delegate_)
+ if (message == WM_NCDESTROY)
delegate_->HandleDestroyed();
}
- // Only top level widget should store/restore focus.
- if (message == WM_ACTIVATE && delegate_->CanSaveFocus())
+ if (message == WM_ACTIVATE && IsTopLevelWindow(window))
PostProcessActivateMessage(LOWORD(w_param), !!HIWORD(w_param));
-
- if (message == WM_ENABLE && restore_focus_when_enabled_) {
- // This path should be executed only for top level as
- // restore_focus_when_enabled_ is set in PostProcessActivateMessage.
- DCHECK(delegate_->CanSaveFocus());
- restore_focus_when_enabled_ = false;
- delegate_->RestoreFocusOnEnable();
- }
return result;
}
-////////////////////////////////////////////////////////////////////////////////
-// HWNDMessageHandler, MessageLoopForUI::Observer implementation:
+LRESULT HWNDMessageHandler::HandleMouseMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // Don't track forwarded mouse messages. We expect the caller to track the
+ // mouse.
+ return HandleMouseEventInternal(message, w_param, l_param, false);
+}
+
+LRESULT HWNDMessageHandler::HandleTouchMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return OnTouchEvent(message, w_param, l_param);
+}
+
+LRESULT HWNDMessageHandler::HandleKeyboardMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return OnKeyEvent(message, w_param, l_param);
+}
-base::EventStatus HWNDMessageHandler::WillProcessEvent(
- const base::NativeEvent& event) {
- return base::EVENT_CONTINUE;
+LRESULT HWNDMessageHandler::HandleScrollMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return OnScrollMessage(message, w_param, l_param);
}
-void HWNDMessageHandler::DidProcessEvent(const base::NativeEvent& event) {
- RedrawInvalidRect();
+LRESULT HWNDMessageHandler::HandleNcHitTestMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return OnNCHitTest(
+ gfx::Point(CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param)));
}
////////////////////////////////////////////////////////////////////////////////
@@ -1004,10 +971,12 @@ void HWNDMessageHandler::DidProcessEvent(const base::NativeEvent& event) {
int HWNDMessageHandler::GetAppbarAutohideEdges(HMONITOR monitor) {
autohide_factory_.InvalidateWeakPtrs();
- return Appbar::instance()->GetAutohideEdges(
- monitor,
- base::Bind(&HWNDMessageHandler::OnAppbarAutohideEdgesChanged,
- autohide_factory_.GetWeakPtr()));
+ return ViewsDelegate::views_delegate ?
+ ViewsDelegate::views_delegate->GetAppbarAutohideEdges(
+ monitor,
+ base::Bind(&HWNDMessageHandler::OnAppbarAutohideEdgesChanged,
+ autohide_factory_.GetWeakPtr())) :
+ ViewsDelegate::EDGE_BOTTOM;
}
void HWNDMessageHandler::OnAppbarAutohideEdgesChanged() {
@@ -1029,33 +998,10 @@ void HWNDMessageHandler::SetInitialFocus() {
void HWNDMessageHandler::PostProcessActivateMessage(int activation_state,
bool minimized) {
- DCHECK(delegate_->CanSaveFocus());
-
- bool active = activation_state != WA_INACTIVE && !minimized;
+ DCHECK(IsTopLevelWindow(hwnd()));
+ const bool active = activation_state != WA_INACTIVE && !minimized;
if (delegate_->CanActivate())
delegate_->HandleActivationChanged(active);
-
- if (!active) {
- // We might get activated/inactivated without being enabled, so we need to
- // clear restore_focus_when_enabled_.
- restore_focus_when_enabled_ = false;
- delegate_->SaveFocusOnDeactivate();
- } else {
- // We must restore the focus after the message has been DefProc'ed as it
- // does set the focus to the last focused HWND.
- // Note that if the window is not enabled, we cannot restore the focus as
- // calling ::SetFocus on a child of the non-enabled top-window would fail.
- // This is the case when showing a modal dialog (such as 'open file',
- // 'print'...) from a different thread.
- // In that case we delay the focus restoration to when the window is enabled
- // again.
- if (!IsWindowEnabled(hwnd())) {
- DCHECK(!restore_focus_when_enabled_);
- restore_focus_when_enabled_ = true;
- return;
- }
- delegate_->RestoreFocusOnActivate();
- }
}
void HWNDMessageHandler::RestoreEnabledIfNecessary() {
@@ -1153,7 +1099,7 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
HRGN current_rgn = CreateRectRgn(0, 0, 0, 0);
int current_rgn_result = GetWindowRgn(hwnd(), current_rgn);
- CRect window_rect;
+ RECT window_rect;
GetWindowRect(hwnd(), &window_rect);
HRGN new_region;
if (custom_window_region_) {
@@ -1163,14 +1109,15 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof mi;
- base::win::GetMonitorInfoWrapper(monitor, &mi);
- CRect work_rect = mi.rcWork;
- work_rect.OffsetRect(-window_rect.left, -window_rect.top);
+ GetMonitorInfo(monitor, &mi);
+ RECT work_rect = mi.rcWork;
+ OffsetRect(&work_rect, -window_rect.left, -window_rect.top);
new_region = CreateRectRgnIndirect(&work_rect);
} else {
gfx::Path window_mask;
- delegate_->GetWindowMask(
- gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask);
+ delegate_->GetWindowMask(gfx::Size(window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top),
+ &window_mask);
new_region = gfx::CreateHRGNFromSkPath(window_mask);
}
@@ -1187,8 +1134,11 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
void HWNDMessageHandler::UpdateDwmNcRenderingPolicy() {
if (base::win::GetVersion() < base::win::VERSION_VISTA)
return;
- DWMNCRENDERINGPOLICY policy = custom_window_region_ ? DWMNCRP_DISABLED
- : DWMNCRP_USEWINDOWSTYLE;
+
+ DWMNCRENDERINGPOLICY policy =
+ custom_window_region_ || delegate_->IsUsingCustomFrame() ?
+ DWMNCRP_DISABLED : DWMNCRP_ENABLED;
+
DwmSetWindowAttribute(hwnd(), DWMWA_NCRENDERING_POLICY,
&policy, sizeof(DWMNCRENDERINGPOLICY));
}
@@ -1206,15 +1156,6 @@ LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message,
return result;
}
-void HWNDMessageHandler::NotifyOwnedWindowsParentClosing() {
- FindOwnedWindowsData data;
- data.window = hwnd();
- EnumThreadWindows(GetCurrentThreadId(), FindOwnedWindowsCallback,
- reinterpret_cast<LPARAM>(&data));
- for (size_t i = 0; i < data.owned_widgets.size(); ++i)
- data.owned_widgets[i]->OnOwnerClosing();
-}
-
void HWNDMessageHandler::LockUpdates(bool force) {
// We skip locked updates when Aero is on for two reasons:
// 1. Because it isn't necessary
@@ -1236,28 +1177,13 @@ void HWNDMessageHandler::UnlockUpdates(bool force) {
}
}
-void HWNDMessageHandler::RedrawInvalidRect() {
-// TODO(cpu): Remove the caller and this class as a message loop observer
-// because we don't need agressive repaints via RDW_UPDATENOW in Aura. The
-// general tracking bug for repaint issues is 177115.
-#if !defined(USE_AURA)
- if (!use_layered_buffer_) {
- RECT r = { 0, 0, 0, 0 };
- if (GetUpdateRect(hwnd(), &r, FALSE) && !IsRectEmpty(&r)) {
- RedrawWindow(hwnd(), &r, NULL,
- RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
- }
- }
-#endif
-}
-
void HWNDMessageHandler::RedrawLayeredWindowContents() {
waiting_for_redraw_layered_window_contents_ = false;
if (invalid_rect_.IsEmpty())
return;
// We need to clip to the dirty rect ourselves.
- layered_window_contents_->sk_canvas()->save(SkCanvas::kClip_SaveFlag);
+ layered_window_contents_->sk_canvas()->save();
double scale = gfx::win::GetDeviceScaleFactor();
layered_window_contents_->sk_canvas()->scale(
SkScalar(scale),SkScalar(scale));
@@ -1347,7 +1273,6 @@ void HWNDMessageHandler::OnCommand(UINT notification_code,
LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
use_layered_buffer_ = !!(window_ex_style() & WS_EX_LAYERED);
-#if defined(USE_AURA)
if (window_ex_style() & WS_EX_COMPOSITED) {
if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
// This is part of the magic to emulate layered windows with Aura
@@ -1356,7 +1281,6 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
DwmExtendFrameIntoClientArea(hwnd(), &margins);
}
}
-#endif
fullscreen_handler_->set_hwnd(hwnd());
@@ -1385,14 +1309,6 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
// creation time.
ClientAreaSizeChanged();
-#if !defined(USE_AURA)
- // We need to add ourselves as a message loop observer so that we can repaint
- // aggressively if the contents of our window become invalid. Unfortunately
- // WM_PAINT messages are starved and we get flickery redrawing when resizing
- // if we do not do this.
- base::MessageLoopForUI::current()->AddObserver(this);
-#endif
-
delegate_->HandleCreate();
WTSRegisterSessionNotification(hwnd(), NOTIFY_FOR_THIS_SESSION);
@@ -1407,7 +1323,7 @@ void HWNDMessageHandler::OnDestroy() {
}
void HWNDMessageHandler::OnDisplayChange(UINT bits_per_pixel,
- const CSize& screen_size) {
+ const gfx::Size& screen_size) {
delegate_->HandleDisplayChange();
}
@@ -1423,6 +1339,11 @@ LRESULT HWNDMessageHandler::OnDwmCompositionChanged(UINT msg,
return 0;
}
+void HWNDMessageHandler::OnEnterMenuLoop(BOOL from_track_popup_menu) {
+ if (menu_depth_++ == 0)
+ delegate_->HandleMenuLoop(true);
+}
+
void HWNDMessageHandler::OnEnterSizeMove() {
// Please refer to the comments in the OnSize function about the scrollbar
// hack.
@@ -1440,6 +1361,12 @@ LRESULT HWNDMessageHandler::OnEraseBkgnd(HDC dc) {
return 1;
}
+void HWNDMessageHandler::OnExitMenuLoop(BOOL is_shortcut_menu) {
+ if (--menu_depth_ == 0)
+ delegate_->HandleMenuLoop(false);
+ DCHECK_GE(0, menu_depth_);
+}
+
void HWNDMessageHandler::OnExitSizeMove() {
delegate_->HandleEndWMSizeMove();
SetMsgHandled(FALSE);
@@ -1460,13 +1387,16 @@ void HWNDMessageHandler::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
// Add the native frame border size to the minimum and maximum size if the
// view reports its size as the client size.
if (delegate_->WidgetSizeIsClientSize()) {
- CRect client_rect, window_rect;
+ RECT client_rect, window_rect;
GetClientRect(hwnd(), &client_rect);
GetWindowRect(hwnd(), &window_rect);
- window_rect -= client_rect;
- min_window_size.Enlarge(window_rect.Width(), window_rect.Height());
- if (!max_window_size.IsEmpty())
- max_window_size.Enlarge(window_rect.Width(), window_rect.Height());
+ CR_DEFLATE_RECT(&window_rect, &client_rect);
+ min_window_size.Enlarge(window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top);
+ if (!max_window_size.IsEmpty()) {
+ max_window_size.Enlarge(window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top);
+ }
}
minmax_info->ptMinTrackSize.x = min_window_size.width();
minmax_info->ptMinTrackSize.y = min_window_size.height();
@@ -1486,8 +1416,12 @@ LRESULT HWNDMessageHandler::OnGetObject(UINT message,
LPARAM l_param) {
LRESULT reference_result = static_cast<LRESULT>(0L);
+ // Only the lower 32 bits of l_param are valid when checking the object id
+ // because it sometimes gets sign-extended incorrectly (but not always).
+ DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(l_param));
+
// Accessibility readers will send an OBJID_CLIENT message
- if (OBJID_CLIENT == l_param) {
+ if (OBJID_CLIENT == obj_id) {
// Retrieve MSAA dispatch object for the root view.
base::win::ScopedComPtr<IAccessible> root(
delegate_->GetNativeViewAccessible());
@@ -1516,13 +1450,21 @@ void HWNDMessageHandler::OnInitMenu(HMENU menu) {
bool is_restored = !is_fullscreen && !is_minimized && !is_maximized;
ScopedRedrawLock lock(this);
- EnableMenuItemByCommand(menu, SC_RESTORE, is_minimized || is_maximized);
+ EnableMenuItemByCommand(menu, SC_RESTORE, delegate_->CanResize() &&
+ (is_minimized || is_maximized));
EnableMenuItemByCommand(menu, SC_MOVE, is_restored);
EnableMenuItemByCommand(menu, SC_SIZE, delegate_->CanResize() && is_restored);
EnableMenuItemByCommand(menu, SC_MAXIMIZE, delegate_->CanMaximize() &&
!is_fullscreen && !is_maximized);
+ // TODO: unfortunately, WidgetDelegate does not declare CanMinimize() and some
+ // code depends on this check, see http://crbug.com/341010.
EnableMenuItemByCommand(menu, SC_MINIMIZE, delegate_->CanMaximize() &&
!is_minimized);
+
+ if (is_maximized && delegate_->CanResize())
+ ::SetMenuDefaultItem(menu, SC_RESTORE, FALSE);
+ else if (!is_maximized && delegate_->CanMaximize())
+ ::SetMenuDefaultItem(menu, SC_MAXIMIZE, FALSE);
}
void HWNDMessageHandler::OnInputLangChange(DWORD character_set,
@@ -1548,7 +1490,11 @@ void HWNDMessageHandler::OnKillFocus(HWND focused_window) {
LRESULT HWNDMessageHandler::OnMouseActivate(UINT message,
WPARAM w_param,
LPARAM l_param) {
-#if defined(USE_AURA)
+ // Please refer to the comments in the header for the touch_down_contexts_
+ // member for the if statement below.
+ if (touch_down_contexts_)
+ return MA_NOACTIVATE;
+
// On Windows, if we select the menu item by touch and if the window at the
// location is another window on the same thread, that window gets a
// WM_MOUSEACTIVATE message and ends up activating itself, which is not
@@ -1556,8 +1502,8 @@ LRESULT HWNDMessageHandler::OnMouseActivate(UINT message,
// current cursor location. We check for this property in our
// WM_MOUSEACTIVATE handler and don't activate the window if the property is
// set.
- if (::GetProp(hwnd(), kIgnoreTouchMouseActivateForWindow)) {
- ::RemoveProp(hwnd(), kIgnoreTouchMouseActivateForWindow);
+ if (::GetProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow)) {
+ ::RemoveProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow);
return MA_NOACTIVATE;
}
// A child window activation should be treated as if we lost activation.
@@ -1567,7 +1513,7 @@ LRESULT HWNDMessageHandler::OnMouseActivate(UINT message,
HWND child = ::RealChildWindowFromPoint(hwnd(), cursor_pos);
if (::IsWindow(child) && child != hwnd() && ::IsWindowVisible(child))
PostProcessActivateMessage(WA_INACTIVE, false);
-#endif
+
// TODO(beng): resolve this with the GetWindowLong() check on the subsequent
// line.
if (delegate_->IsWidgetWindow())
@@ -1581,120 +1527,10 @@ LRESULT HWNDMessageHandler::OnMouseActivate(UINT message,
LRESULT HWNDMessageHandler::OnMouseRange(UINT message,
WPARAM w_param,
LPARAM l_param) {
-#if defined(USE_AURA)
- if (!touch_ids_.empty())
- return 0;
- // We handle touch events on Windows Aura. Windows generates synthesized
- // mouse messages in response to touch which we should ignore. However touch
- // messages are only received for the client area. We need to ignore the
- // synthesized mouse messages for all points in the client area and places
- // which return HTNOWHERE.
- if (ui::IsMouseEventFromTouch(message)) {
- LPARAM l_param_ht = l_param;
- // For mouse events (except wheel events), location is in window coordinates
- // and should be converted to screen coordinates for WM_NCHITTEST.
- if (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) {
- CPoint screen_point(l_param_ht);
- MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
- l_param_ht = MAKELPARAM(screen_point.x, screen_point.y);
- }
- LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht);
- if (hittest == HTCLIENT || hittest == HTNOWHERE)
- return 0;
- }
-#endif
- if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) {
- is_right_mouse_pressed_on_caption_ = false;
- ReleaseCapture();
- // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu()
- // expect screen coordinates.
- CPoint screen_point(l_param);
- MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
- w_param = SendMessage(hwnd(), WM_NCHITTEST, 0,
- MAKELPARAM(screen_point.x, screen_point.y));
- if (w_param == HTCAPTION || w_param == HTSYSMENU) {
- gfx::ShowSystemMenuAtPoint(hwnd(), gfx::Point(screen_point));
- return 0;
- }
- } else if (message == WM_NCLBUTTONDOWN && delegate_->IsUsingCustomFrame()) {
- switch (w_param) {
- case HTCLOSE:
- case HTMINBUTTON:
- case HTMAXBUTTON: {
- // When the mouse is pressed down in these specific non-client areas,
- // we need to tell the RootView to send the mouse pressed event (which
- // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
- // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
- // sent by the applicable button's ButtonListener. We _have_ to do this
- // way rather than letting Windows just send the syscommand itself (as
- // would happen if we never did this dance) because for some insane
- // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
- // window control button appearance, in the Windows classic style, over
- // our view! Ick! By handling this message we prevent Windows from
- // doing this undesirable thing, but that means we need to roll the
- // sys-command handling ourselves.
- // Combine |w_param| with common key state message flags.
- w_param |= base::win::IsCtrlPressed() ? MK_CONTROL : 0;
- w_param |= base::win::IsShiftPressed() ? MK_SHIFT : 0;
- }
- }
- } else if (message == WM_NCRBUTTONDOWN &&
- (w_param == HTCAPTION || w_param == HTSYSMENU)) {
- is_right_mouse_pressed_on_caption_ = true;
- // We SetCapture() to ensure we only show the menu when the button
- // down and up are both on the caption. Note: this causes the button up to
- // be WM_RBUTTONUP instead of WM_NCRBUTTONUP.
- SetCapture();
- }
-
- MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime(),
- { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } };
- ui::MouseEvent event(msg);
- if (!touch_ids_.empty() || ui::IsMouseEventFromTouch(message))
- event.set_flags(event.flags() | ui::EF_FROM_TOUCH);
-
- if (!(event.flags() & ui::EF_IS_NON_CLIENT))
- delegate_->HandleTooltipMouseMove(message, w_param, l_param);
-
- if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture()) {
- // Windows only fires WM_MOUSELEAVE events if the application begins
- // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
- // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
- TrackMouseEvents((message == WM_NCMOUSEMOVE) ?
- TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
- } else if (event.type() == ui::ET_MOUSE_EXITED) {
- // Reset our tracking flags so future mouse movement over this
- // NativeWidgetWin results in a new tracking session. Fall through for
- // OnMouseEvent.
- active_mouse_tracking_flags_ = 0;
- } else if (event.type() == ui::ET_MOUSEWHEEL) {
- // 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;
- }
-
- // 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);
- if (!ref.get())
- return 0;
- if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU &&
- delegate_->IsUsingCustomFrame()) {
- // TODO(msw): Eliminate undesired painting, or re-evaluate this workaround.
- // DefWindowProc for WM_NCLBUTTONDOWN does weird non-client painting, so we
- // need to call it inside a ScopedRedrawLock. This may cause other negative
- // side-effects (ex/ stifling non-client mouse releases).
- DefWindowProcWithRedrawLock(message, w_param, l_param);
- handled = true;
- }
-
- if (ref.get())
- SetMsgHandled(handled);
- return 0;
+ return HandleMouseEventInternal(message, w_param, l_param, true);
}
-void HWNDMessageHandler::OnMove(const CPoint& point) {
+void HWNDMessageHandler::OnMove(const gfx::Point& point) {
delegate_->HandleMove();
SetMsgHandled(FALSE);
}
@@ -1814,9 +1650,9 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
}
}
const int autohide_edges = GetAppbarAutohideEdges(monitor);
- if (autohide_edges & Appbar::EDGE_LEFT)
+ if (autohide_edges & ViewsDelegate::EDGE_LEFT)
client_rect->left += kAutoHideTaskbarThicknessPx;
- if (autohide_edges & Appbar::EDGE_TOP) {
+ if (autohide_edges & ViewsDelegate::EDGE_TOP) {
if (!delegate_->IsUsingCustomFrame()) {
// Tricky bit. Due to a bug in DwmDefWindowProc()'s handling of
// WM_NCHITTEST, having any nonclient area atop the window causes the
@@ -1832,9 +1668,9 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
client_rect->top += kAutoHideTaskbarThicknessPx;
}
}
- if (autohide_edges & Appbar::EDGE_RIGHT)
+ if (autohide_edges & ViewsDelegate::EDGE_RIGHT)
client_rect->right -= kAutoHideTaskbarThicknessPx;
- if (autohide_edges & Appbar::EDGE_BOTTOM)
+ if (autohide_edges & ViewsDelegate::EDGE_BOTTOM)
client_rect->bottom -= kAutoHideTaskbarThicknessPx;
// We cannot return WVR_REDRAW when there is nonclient area, or Windows
@@ -1855,7 +1691,7 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
return mode ? WVR_REDRAW : 0;
}
-LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
+LRESULT HWNDMessageHandler::OnNCHitTest(const gfx::Point& point) {
if (!delegate_->IsWidgetWindow()) {
SetMsgHandled(FALSE);
return 0;
@@ -1866,14 +1702,14 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
if (!remove_standard_frame_ && !delegate_->IsUsingCustomFrame()) {
LRESULT result;
if (DwmDefWindowProc(hwnd(), WM_NCHITTEST, 0,
- MAKELPARAM(point.x, point.y), &result)) {
+ MAKELPARAM(point.x(), point.y()), &result)) {
return result;
}
}
// First, give the NonClientView a chance to test the point to see if it
// provides any of the non-client area.
- POINT temp = point;
+ POINT temp = { point.x(), point.y() };
MapWindowPoints(HWND_DESKTOP, hwnd(), &temp, 1);
int component = delegate_->GetNonClientComponent(gfx::Point(temp));
if (component != HTNOWHERE)
@@ -1881,9 +1717,8 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
// Otherwise, we let Windows do all the native frame non-client handling for
// us.
-#if defined(USE_AURA)
LRESULT hit_test_code = DefWindowProc(hwnd(), WM_NCHITTEST, 0,
- MAKELPARAM(point.x, point.y));
+ MAKELPARAM(point.x(), point.y()));
if (needs_scroll_styles_) {
switch (hit_test_code) {
// If we faked the WS_VSCROLL and WS_HSCROLL styles for this window, then
@@ -1916,8 +1751,8 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
window_rect.left = window_rect.right - scroll_width;
window_rect.top = window_rect.bottom - scroll_height;
POINT pt;
- pt.x = point.x;
- pt.y = point.y;
+ pt.x = point.x();
+ pt.y = point.y();
if (::PtInRect(&window_rect, pt))
hit_test_code = HTCLIENT;
break;
@@ -1928,9 +1763,6 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
}
}
return hit_test_code;
-#else
- SetMsgHandled(FALSE);
-#endif
}
void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
@@ -1945,11 +1777,12 @@ void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
// We have an NC region and need to paint it. We expand the NC region to
// include the dirty region of the root view. This is done to minimize
// paints.
- CRect window_rect;
+ RECT window_rect;
GetWindowRect(hwnd(), &window_rect);
gfx::Size root_view_size = delegate_->GetRootViewSize();
- if (gfx::Size(window_rect.Width(), window_rect.Height()) != root_view_size) {
+ if (gfx::Size(window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top) != root_view_size) {
// If the size of the window differs from the size of the root view it
// means we're being asked to paint before we've gotten a WM_SIZE. This can
// happen when the user is interactively resizing the window. To avoid
@@ -1959,10 +1792,13 @@ void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
return;
}
- CRect dirty_region;
+ RECT dirty_region;
// A value of 1 indicates paint all.
if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
- dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
+ dirty_region.left = 0;
+ dirty_region.top = 0;
+ dirty_region.right = window_rect.right - window_rect.left;
+ dirty_region.bottom = window_rect.bottom - window_rect.top;
} else {
RECT rgn_bounding_box;
GetRgnBox(rgn, &rgn_bounding_box);
@@ -1991,8 +1827,8 @@ void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
// The root view has a region that needs to be painted. Include it in the
// region we're going to paint.
- CRect old_paint_region_crect = old_paint_region.ToRECT();
- CRect tmp = dirty_region;
+ RECT old_paint_region_crect = old_paint_region.ToRECT();
+ RECT tmp = dirty_region;
UnionRect(&dirty_region, &tmp, &old_paint_region_crect);
}
@@ -2002,9 +1838,12 @@ void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
// the following in a block to force paint to occur so that we can release
// the dc.
if (!delegate_->HandlePaintAccelerated(gfx::Rect(dirty_region))) {
- gfx::CanvasSkiaPaint canvas(dc, true, dirty_region.left,
- dirty_region.top, dirty_region.Width(),
- dirty_region.Height());
+ gfx::CanvasSkiaPaint canvas(dc,
+ true,
+ dirty_region.left,
+ dirty_region.top,
+ dirty_region.right - dirty_region.left,
+ dirty_region.bottom - dirty_region.top);
delegate_->HandlePaint(&canvas);
}
@@ -2050,13 +1889,7 @@ void HWNDMessageHandler::OnPaint(HDC dc) {
// Try to paint accelerated first.
if (!IsRectEmpty(&ps.rcPaint) &&
!delegate_->HandlePaintAccelerated(gfx::Rect(ps.rcPaint))) {
-#if defined(USE_AURA)
delegate_->HandlePaint(NULL);
-#else
- scoped_ptr<gfx::CanvasSkiaPaint> canvas(
- new gfx::CanvasSkiaPaint(hwnd(), display_dc, ps));
- delegate_->HandlePaint(canvas.get());
-#endif
}
EndPaint(hwnd(), &ps);
@@ -2120,6 +1953,9 @@ LRESULT HWNDMessageHandler::OnSetCursor(UINT message,
case HTCLIENT:
SetCursor(current_cursor_);
return 1;
+ case LOWORD(HTERROR): // Use HTERROR's LOWORD value for valid comparison.
+ SetMsgHandled(FALSE);
+ break;
default:
// Use the default value, IDC_ARROW.
break;
@@ -2160,13 +1996,12 @@ void HWNDMessageHandler::OnSettingChange(UINT flags, const wchar_t* section) {
}
}
-void HWNDMessageHandler::OnSize(UINT param, const CSize& size) {
+void HWNDMessageHandler::OnSize(UINT param, const gfx::Size& size) {
RedrawWindow(hwnd(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
// ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
// invoked OnSize we ensure the RootView has been laid out.
ResetWindowRegion(false, true);
-#if defined(USE_AURA)
// We add the WS_VSCROLL and WS_HSCROLL styles to top level windows to ensure
// that legacy trackpad/trackpoint drivers generate the WM_VSCROLL and
// WM_HSCROLL messages and scrolling works.
@@ -2179,11 +2014,10 @@ void HWNDMessageHandler::OnSize(UINT param, const CSize& size) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&AddScrollStylesToWindow, hwnd()));
}
-#endif
}
void HWNDMessageHandler::OnSysCommand(UINT notification_code,
- const CPoint& point) {
+ const gfx::Point& point) {
if (!delegate_->ShouldHandleSystemCommands())
return;
@@ -2214,7 +2048,7 @@ void HWNDMessageHandler::OnSysCommand(UINT notification_code,
// Handle SC_KEYMENU, which means that the user has pressed the ALT
// key and released it, so we should focus the menu bar.
- if ((notification_code & sc_mask) == SC_KEYMENU && point.x == 0) {
+ if ((notification_code & sc_mask) == SC_KEYMENU && point.x() == 0) {
int modifiers = ui::EF_NONE;
if (base::win::IsShiftPressed())
modifiers |= ui::EF_SHIFT_DOWN;
@@ -2234,8 +2068,11 @@ void HWNDMessageHandler::OnSysCommand(UINT notification_code,
// with the mouse/touch/keyboard, we flag as being in a size loop.
if ((notification_code & sc_mask) == SC_SIZE)
in_size_loop_ = true;
+ base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
DefWindowProc(hwnd(), WM_SYSCOMMAND, notification_code,
- MAKELPARAM(point.x, point.y));
+ MAKELPARAM(point.x(), point.y()));
+ if (!ref.get())
+ return;
in_size_loop_ = false;
}
}
@@ -2248,22 +2085,44 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
WPARAM w_param,
LPARAM l_param) {
// Handle touch events only on Aura for now.
-#if !defined(USE_AURA)
- SetMsgHandled(FALSE);
- return 0;
-#endif
int num_points = LOWORD(w_param);
scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param),
num_points, input.get(),
sizeof(TOUCHINPUT))) {
+ int flags = ui::GetModifiersFromKeyState();
TouchEvents touch_events;
for (int i = 0; i < num_points; ++i) {
+ POINT point;
+ point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
+ point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
+
+ if (base::win::GetVersion() == base::win::VERSION_WIN7) {
+ // Windows 7 sends touch events for touches in the non-client area,
+ // whereas Windows 8 does not. In order to unify the behaviour, always
+ // ignore touch events in the non-client area.
+ LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
+ LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht);
+
+ if (hittest != HTCLIENT)
+ return 0;
+ }
+
+ ScreenToClient(hwnd(), &point);
+
+ last_touch_message_time_ = ::GetMessageTime();
+
ui::EventType touch_event_type = ui::ET_UNKNOWN;
if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
touch_ids_.insert(input[i].dwID);
touch_event_type = ui::ET_TOUCH_PRESSED;
+ touch_down_contexts_++;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&HWNDMessageHandler::ResetTouchDownContext,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kTouchDownContextResetTimeout));
} else if (input[i].dwFlags & TOUCHEVENTF_UP) {
touch_ids_.erase(input[i].dwID);
touch_event_type = ui::ET_TOUCH_RELEASED;
@@ -2271,19 +2130,27 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
touch_event_type = ui::ET_TOUCH_MOVED;
}
if (touch_event_type != ui::ET_UNKNOWN) {
- POINT point;
- point.x = TOUCH_COORD_TO_PIXEL(input[i].x) /
- gfx::win::GetUndocumentedDPITouchScale();
- point.y = TOUCH_COORD_TO_PIXEL(input[i].y) /
- gfx::win::GetUndocumentedDPITouchScale();
-
- ScreenToClient(hwnd(), &point);
-
- ui::TouchEvent event(
- touch_event_type,
- gfx::Point(point.x, point.y),
- id_generator_.GetGeneratedID(input[i].dwID),
- base::TimeDelta::FromMilliseconds(input[i].dwTime));
+ base::TimeTicks now;
+ // input[i].dwTime doesn't necessarily relate to the system time at all,
+ // so use base::TimeTicks::HighResNow() if possible, or
+ // base::TimeTicks::Now() otherwise.
+ if (base::TimeTicks::IsHighResNowFastAndReliable())
+ now = base::TimeTicks::HighResNow();
+ else
+ now = base::TimeTicks::Now();
+ ui::TouchEvent event(touch_event_type,
+ gfx::Point(point.x, point.y),
+ id_generator_.GetGeneratedID(input[i].dwID),
+ now - base::TimeTicks());
+ event.set_flags(flags);
+ event.latency()->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ 0,
+ 0,
+ base::TimeTicks::FromInternalValue(
+ event.time_stamp().ToInternalValue()),
+ 1);
+
touch_events.push_back(event);
if (touch_event_type == ui::ET_TOUCH_RELEASED)
id_generator_.ReleaseNumber(input[i].dwID);
@@ -2314,7 +2181,7 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW);
}
} else if (!GetParent(hwnd())) {
- CRect window_rect;
+ RECT window_rect;
HMONITOR monitor;
gfx::Rect monitor_rect, work_area;
if (GetWindowRect(hwnd(), &window_rect) &&
@@ -2368,6 +2235,9 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
}
}
+ if (DidClientAreaSizeChange(window_pos))
+ delegate_->HandleWindowSizeChanging();
+
if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) {
// Prevent the window from being made visible if we've been asked to do so.
// See comment in header as to why we might want this.
@@ -2404,4 +2274,158 @@ void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) {
delegate_->HandleTouchEvent(touch_events[i]);
}
+void HWNDMessageHandler::ResetTouchDownContext() {
+ touch_down_contexts_--;
+}
+
+LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool track_mouse) {
+ if (!touch_ids_.empty())
+ return 0;
+ // We handle touch events on Windows Aura. Windows generates synthesized
+ // mouse messages in response to touch which we should ignore. However touch
+ // messages are only received for the client area. We need to ignore the
+ // synthesized mouse messages for all points in the client area and places
+ // which return HTNOWHERE.
+ if (ui::IsMouseEventFromTouch(message)) {
+ LPARAM l_param_ht = l_param;
+ // For mouse events (except wheel events), location is in window coordinates
+ // and should be converted to screen coordinates for WM_NCHITTEST.
+ if (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) {
+ POINT screen_point = CR_POINT_INITIALIZER_FROM_LPARAM(l_param_ht);
+ MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
+ l_param_ht = MAKELPARAM(screen_point.x, screen_point.y);
+ }
+ LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht);
+ if (hittest == HTCLIENT || hittest == HTNOWHERE)
+ return 0;
+ }
+
+ // Certain logitech drivers send the WM_MOUSEHWHEEL message to the parent
+ // followed by WM_MOUSEWHEEL messages to the child window causing a vertical
+ // scroll. We treat these WM_MOUSEWHEEL messages as WM_MOUSEHWHEEL
+ // messages.
+ if (message == WM_MOUSEHWHEEL)
+ last_mouse_hwheel_time_ = ::GetMessageTime();
+
+ if (message == WM_MOUSEWHEEL &&
+ ::GetMessageTime() == last_mouse_hwheel_time_) {
+ message = WM_MOUSEHWHEEL;
+ }
+
+ if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) {
+ is_right_mouse_pressed_on_caption_ = false;
+ ReleaseCapture();
+ // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu()
+ // expect screen coordinates.
+ POINT screen_point = CR_POINT_INITIALIZER_FROM_LPARAM(l_param);
+ MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
+ w_param = SendMessage(hwnd(), WM_NCHITTEST, 0,
+ MAKELPARAM(screen_point.x, screen_point.y));
+ if (w_param == HTCAPTION || w_param == HTSYSMENU) {
+ gfx::ShowSystemMenuAtPoint(hwnd(), gfx::Point(screen_point));
+ return 0;
+ }
+ } else if (message == WM_NCLBUTTONDOWN && delegate_->IsUsingCustomFrame()) {
+ switch (w_param) {
+ case HTCLOSE:
+ case HTMINBUTTON:
+ case HTMAXBUTTON: {
+ // When the mouse is pressed down in these specific non-client areas,
+ // we need to tell the RootView to send the mouse pressed event (which
+ // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
+ // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
+ // sent by the applicable button's ButtonListener. We _have_ to do this
+ // way rather than letting Windows just send the syscommand itself (as
+ // would happen if we never did this dance) because for some insane
+ // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
+ // window control button appearance, in the Windows classic style, over
+ // our view! Ick! By handling this message we prevent Windows from
+ // doing this undesirable thing, but that means we need to roll the
+ // sys-command handling ourselves.
+ // Combine |w_param| with common key state message flags.
+ w_param |= base::win::IsCtrlPressed() ? MK_CONTROL : 0;
+ w_param |= base::win::IsShiftPressed() ? MK_SHIFT : 0;
+ }
+ }
+ } else if (message == WM_NCRBUTTONDOWN &&
+ (w_param == HTCAPTION || w_param == HTSYSMENU)) {
+ is_right_mouse_pressed_on_caption_ = true;
+ // We SetCapture() to ensure we only show the menu when the button
+ // down and up are both on the caption. Note: this causes the button up to
+ // be WM_RBUTTONUP instead of WM_NCRBUTTONUP.
+ SetCapture();
+ }
+ long message_time = GetMessageTime();
+ MSG msg = { hwnd(), message, w_param, l_param, message_time,
+ { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } };
+ ui::MouseEvent event(msg);
+ if (IsSynthesizedMouseMessage(message, message_time, l_param))
+ event.set_flags(event.flags() | ui::EF_FROM_TOUCH);
+
+ if (!(event.flags() & ui::EF_IS_NON_CLIENT))
+ delegate_->HandleTooltipMouseMove(message, w_param, l_param);
+
+ if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture() && track_mouse) {
+ // Windows only fires WM_MOUSELEAVE events if the application begins
+ // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
+ // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
+ TrackMouseEvents((message == WM_NCMOUSEMOVE) ?
+ TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
+ } else if (event.type() == ui::ET_MOUSE_EXITED) {
+ // Reset our tracking flags so future mouse movement over this
+ // NativeWidget results in a new tracking session. Fall through for
+ // OnMouseEvent.
+ active_mouse_tracking_flags_ = 0;
+ } else if (event.type() == ui::ET_MOUSEWHEEL) {
+ // 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;
+ }
+
+ // 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);
+ if (!ref.get())
+ return 0;
+ if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU &&
+ delegate_->IsUsingCustomFrame()) {
+ // TODO(msw): Eliminate undesired painting, or re-evaluate this workaround.
+ // DefWindowProc for WM_NCLBUTTONDOWN does weird non-client painting, so we
+ // need to call it inside a ScopedRedrawLock. This may cause other negative
+ // side-effects (ex/ stifling non-client mouse releases).
+ DefWindowProcWithRedrawLock(message, w_param, l_param);
+ handled = true;
+ }
+
+ if (ref.get())
+ SetMsgHandled(handled);
+ return 0;
+}
+
+bool HWNDMessageHandler::IsSynthesizedMouseMessage(unsigned int message,
+ int message_time,
+ LPARAM l_param) {
+ if (ui::IsMouseEventFromTouch(message))
+ return true;
+ // Ignore mouse messages which occur at the same location as the current
+ // cursor position and within a time difference of 500 ms from the last
+ // touch message.
+ if (last_touch_message_time_ && message_time >= last_touch_message_time_ &&
+ ((message_time - last_touch_message_time_) <=
+ kSynthesizedMouseTouchMessagesTimeDifference)) {
+ POINT mouse_location = CR_POINT_INITIALIZER_FROM_LPARAM(l_param);
+ ::ClientToScreen(hwnd(), &mouse_location);
+ POINT cursor_pos = {0};
+ ::GetCursorPos(&cursor_pos);
+ if (memcmp(&cursor_pos, &mouse_location, sizeof(POINT)))
+ return false;
+ return true;
+ }
+ return false;
+}
+
} // namespace views
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 5aacd7819d8..fbc05813ca0 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -6,9 +6,6 @@
#define UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_
#include <windows.h>
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlmisc.h>
#include <set>
#include <vector>
@@ -17,12 +14,12 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/win_util.h"
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/base/ui_base_types.h"
+#include "ui/base/win/window_event_target.h"
#include "ui/events/event.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/sequential_id_generator.h"
@@ -36,6 +33,10 @@ class ImageSkia;
class Insets;
}
+namespace ui {
+class ViewProp;
+}
+
namespace views {
class FullscreenHandler;
@@ -77,10 +78,12 @@ const int WM_NCUAHDRAWFRAME = 0xAF;
LPARAM l_param, \
LRESULT& l_result, \
DWORD msg_map_id = 0) { \
+ base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); \
BOOL old_msg_handled = msg_handled_; \
BOOL ret = _ProcessWindowMessage(hwnd, msg, w_param, l_param, l_result, \
msg_map_id); \
- msg_handled_ = old_msg_handled; \
+ if (ref.get()) \
+ msg_handled_ = old_msg_handled; \
return ret; \
} \
BOOL _ProcessWindowMessage(HWND hWnd, \
@@ -103,13 +106,13 @@ const int WM_NCUAHDRAWFRAME = 0xAF;
// An object that handles messages for a HWND that implements the views
// "Custom Frame" look. The purpose of this class is to isolate the windows-
// specific message handling from the code that wraps it. It is intended to be
-// used by both a views::NativeWidget and an aura::RootWindowHost
+// used by both a views::NativeWidget and an aura::WindowTreeHost
// implementation.
// TODO(beng): This object should eventually *become* the WindowImpl.
class VIEWS_EXPORT HWNDMessageHandler :
public gfx::WindowImpl,
public internal::InputMethodDelegate,
- public base::MessageLoopForUI::Observer {
+ public ui::WindowEventTarget {
public:
explicit HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate);
~HWNDMessageHandler();
@@ -129,7 +132,10 @@ class VIEWS_EXPORT HWNDMessageHandler :
void GetWindowPlacement(gfx::Rect* bounds,
ui::WindowShowState* show_state) const;
- void SetBounds(const gfx::Rect& bounds_in_pixels);
+ // Sets the bounds of the HWND to |bounds_in_pixels|. If the HWND size is not
+ // changed, |force_size_changed| determines if we should pretend it is.
+ void SetBounds(const gfx::Rect& bounds_in_pixels, bool force_size_changed);
+
void SetSize(const gfx::Size& size);
void CenterWindow(const gfx::Size& size);
@@ -140,8 +146,6 @@ class VIEWS_EXPORT HWNDMessageHandler :
void Show();
void ShowWindowWithState(ui::WindowShowState show_state);
- // TODO(beng): distinguish from ShowWindowWithState().
- void Show(int show_state);
void ShowMaximizedWithBounds(const gfx::Rect& bounds);
void Hide();
@@ -179,7 +183,7 @@ class VIEWS_EXPORT HWNDMessageHandler :
void SetVisibilityChangedAnimationsEnabled(bool enabled);
// Returns true if the title changed.
- bool SetTitle(const string16& title);
+ bool SetTitle(const base::string16& title);
void SetCursor(HCURSOR cursor);
@@ -211,16 +215,32 @@ class VIEWS_EXPORT HWNDMessageHandler :
WPARAM w_param,
LPARAM l_param) OVERRIDE;
- // Overridden from MessageLoopForUI::Observer:
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE;
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
+ // Overridden from WindowEventTarget
+ virtual LRESULT HandleMouseMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual LRESULT HandleKeyboardMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+ virtual LRESULT HandleTouchMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+
+ virtual LRESULT HandleScrollMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
+
+ virtual LRESULT HandleNcHitTestMessage(unsigned int message,
+ WPARAM w_param,
+ LPARAM l_param) OVERRIDE;
- // Returns the auto-hide edges of the appbar. See Appbar::GetAutohideEdges()
- // for details. If the edges change OnAppbarAutohideEdgesChanged() is called.
+ // Returns the auto-hide edges of the appbar. See
+ // ViewsDelegate::GetAppbarAutohideEdges() for details. If the edges change,
+ // OnAppbarAutohideEdgesChanged() is called.
int GetAppbarAutohideEdges(HMONITOR monitor);
- // Callback if the autohide edges have changed. See Appbar for details.
+ // Callback if the autohide edges have changed. See
+ // ViewsDelegate::GetAppbarAutohideEdges() for details.
void OnAppbarAutohideEdgesChanged();
// Can be called after the delegate has had the opportunity to set focus and
@@ -267,9 +287,6 @@ class VIEWS_EXPORT HWNDMessageHandler :
WPARAM w_param,
LPARAM l_param);
- // Notifies any owned windows that we're closing.
- void NotifyOwnedWindowsParentClosing();
-
// Lock or unlock the window from being able to redraw itself in response to
// updates to its invalid region.
class ScopedRedrawLock;
@@ -279,9 +296,6 @@ class VIEWS_EXPORT HWNDMessageHandler :
// Stops ignoring SetWindowPos() requests (see below).
void StopIgnoringPosChanges() { ignore_window_pos_changes_ = false; }
- // Synchronously paints the invalid contents of the Widget.
- void RedrawInvalidRect();
-
// Synchronously updates the invalid contents of the Widget. Valid for
// layered windows only.
void RedrawLayeredWindowContents();
@@ -294,90 +308,92 @@ class VIEWS_EXPORT HWNDMessageHandler :
BEGIN_SAFE_MSG_MAP_EX(HWNDMessageHandler)
// Range handlers must go first!
- MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
- MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
+ CR_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+ CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE,
+ WM_NCXBUTTONDBLCLK,
+ OnMouseRange)
// CustomFrameWindow hacks
- MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
- MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
+ CR_MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
+ CR_MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
// Vista and newer
- MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
+ CR_MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
// Non-atlcrack.h handlers
- MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
+ CR_MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
// Mouse events.
- MESSAGE_HANDLER_EX(WM_MOUSEACTIVATE, OnMouseActivate)
- MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseRange)
- MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseRange)
- MESSAGE_HANDLER_EX(WM_SETCURSOR, OnSetCursor);
+ CR_MESSAGE_HANDLER_EX(WM_MOUSEACTIVATE, OnMouseActivate)
+ CR_MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseRange)
+ CR_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseRange)
+ CR_MESSAGE_HANDLER_EX(WM_SETCURSOR, OnSetCursor);
// Key events.
- MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
- MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
+ CR_MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
// IME Events.
- MESSAGE_HANDLER_EX(WM_IME_SETCONTEXT, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_IME_REQUEST, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_CHAR, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_SYSCHAR, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_DEADCHAR, OnImeMessages)
- MESSAGE_HANDLER_EX(WM_SYSDEADCHAR, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_SETCONTEXT, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_REQUEST, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_CHAR, OnImeMessages)
+ CR_MESSAGE_HANDLER_EX(WM_SYSCHAR, OnImeMessages)
// Scroll events
- MESSAGE_HANDLER_EX(WM_VSCROLL, OnScrollMessage)
- MESSAGE_HANDLER_EX(WM_HSCROLL, OnScrollMessage)
+ CR_MESSAGE_HANDLER_EX(WM_VSCROLL, OnScrollMessage)
+ CR_MESSAGE_HANDLER_EX(WM_HSCROLL, OnScrollMessage)
// Touch Events.
- MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent)
+ CR_MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent)
// Uses the general handler macro since the specific handler macro
// MSG_WM_NCACTIVATE would convert WPARAM type to BOOL type. The high
// word of WPARAM could be set when the window is minimized or restored.
- MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate)
+ CR_MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate)
// This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
- MSG_WM_ACTIVATEAPP(OnActivateApp)
- MSG_WM_APPCOMMAND(OnAppCommand)
- MSG_WM_CANCELMODE(OnCancelMode)
- MSG_WM_CAPTURECHANGED(OnCaptureChanged)
- MSG_WM_CLOSE(OnClose)
- MSG_WM_COMMAND(OnCommand)
- MSG_WM_CREATE(OnCreate)
- MSG_WM_DESTROY(OnDestroy)
- MSG_WM_DISPLAYCHANGE(OnDisplayChange)
- MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
- MSG_WM_ERASEBKGND(OnEraseBkgnd)
- MSG_WM_EXITSIZEMOVE(OnExitSizeMove)
- MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
- MSG_WM_INITMENU(OnInitMenu)
- MSG_WM_INPUTLANGCHANGE(OnInputLangChange)
- MSG_WM_KILLFOCUS(OnKillFocus)
- MSG_WM_MOVE(OnMove)
- MSG_WM_MOVING(OnMoving)
- MSG_WM_NCCALCSIZE(OnNCCalcSize)
- MSG_WM_NCHITTEST(OnNCHitTest)
- MSG_WM_NCPAINT(OnNCPaint)
- MSG_WM_NOTIFY(OnNotify)
- MSG_WM_PAINT(OnPaint)
- MSG_WM_SETFOCUS(OnSetFocus)
- MSG_WM_SETICON(OnSetIcon)
- MSG_WM_SETTEXT(OnSetText)
- MSG_WM_SETTINGCHANGE(OnSettingChange)
- MSG_WM_SIZE(OnSize)
- MSG_WM_SYSCOMMAND(OnSysCommand)
- MSG_WM_THEMECHANGED(OnThemeChanged)
- MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
- MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
- MSG_WM_WTSSESSION_CHANGE(OnSessionChange)
- END_MSG_MAP()
+ CR_MSG_WM_ACTIVATEAPP(OnActivateApp)
+ CR_MSG_WM_APPCOMMAND(OnAppCommand)
+ CR_MSG_WM_CANCELMODE(OnCancelMode)
+ CR_MSG_WM_CAPTURECHANGED(OnCaptureChanged)
+ CR_MSG_WM_CLOSE(OnClose)
+ CR_MSG_WM_COMMAND(OnCommand)
+ CR_MSG_WM_CREATE(OnCreate)
+ CR_MSG_WM_DESTROY(OnDestroy)
+ CR_MSG_WM_DISPLAYCHANGE(OnDisplayChange)
+ CR_MSG_WM_ENTERMENULOOP(OnEnterMenuLoop)
+ CR_MSG_WM_EXITMENULOOP(OnExitMenuLoop)
+ CR_MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
+ CR_MSG_WM_ERASEBKGND(OnEraseBkgnd)
+ CR_MSG_WM_EXITSIZEMOVE(OnExitSizeMove)
+ CR_MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
+ CR_MSG_WM_INITMENU(OnInitMenu)
+ CR_MSG_WM_INPUTLANGCHANGE(OnInputLangChange)
+ CR_MSG_WM_KILLFOCUS(OnKillFocus)
+ CR_MSG_WM_MOVE(OnMove)
+ CR_MSG_WM_MOVING(OnMoving)
+ CR_MSG_WM_NCCALCSIZE(OnNCCalcSize)
+ CR_MSG_WM_NCHITTEST(OnNCHitTest)
+ CR_MSG_WM_NCPAINT(OnNCPaint)
+ CR_MSG_WM_NOTIFY(OnNotify)
+ CR_MSG_WM_PAINT(OnPaint)
+ CR_MSG_WM_SETFOCUS(OnSetFocus)
+ CR_MSG_WM_SETICON(OnSetIcon)
+ CR_MSG_WM_SETTEXT(OnSetText)
+ CR_MSG_WM_SETTINGCHANGE(OnSettingChange)
+ CR_MSG_WM_SIZE(OnSize)
+ CR_MSG_WM_SYSCOMMAND(OnSysCommand)
+ CR_MSG_WM_THEMECHANGED(OnThemeChanged)
+ CR_MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+ CR_MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
+ CR_MSG_WM_WTSSESSION_CHANGE(OnSessionChange)
+ CR_END_MSG_MAP()
// Message Handlers.
// This list is in _ALPHABETICAL_ order!
@@ -393,10 +409,12 @@ class VIEWS_EXPORT HWNDMessageHandler :
void OnCommand(UINT notification_code, int command, HWND window);
LRESULT OnCreate(CREATESTRUCT* create_struct);
void OnDestroy();
- void OnDisplayChange(UINT bits_per_pixel, const CSize& screen_size);
+ void OnDisplayChange(UINT bits_per_pixel, const gfx::Size& screen_size);
LRESULT OnDwmCompositionChanged(UINT msg, WPARAM w_param, LPARAM l_param);
+ void OnEnterMenuLoop(BOOL from_track_popup_menu);
void OnEnterSizeMove();
LRESULT OnEraseBkgnd(HDC dc);
+ void OnExitMenuLoop(BOOL is_shortcut_menu);
void OnExitSizeMove();
void OnGetMinMaxInfo(MINMAXINFO* minmax_info);
LRESULT OnGetObject(UINT message, WPARAM w_param, LPARAM l_param);
@@ -407,11 +425,11 @@ class VIEWS_EXPORT HWNDMessageHandler :
void OnKillFocus(HWND focused_window);
LRESULT OnMouseActivate(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
- void OnMove(const CPoint& point);
+ void OnMove(const gfx::Point& point);
void OnMoving(UINT param, const RECT* new_bounds);
LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param);
- LRESULT OnNCHitTest(const CPoint& point);
+ LRESULT OnNCHitTest(const gfx::Point& point);
void OnNCPaint(HRGN rgn);
LRESULT OnNCUAHDrawCaption(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnNCUAHDrawFrame(UINT message, WPARAM w_param, LPARAM l_param);
@@ -425,8 +443,8 @@ class VIEWS_EXPORT HWNDMessageHandler :
LRESULT OnSetIcon(UINT size_type, HICON new_icon);
LRESULT OnSetText(const wchar_t* text);
void OnSettingChange(UINT flags, const wchar_t* section);
- void OnSize(UINT param, const CSize& size);
- void OnSysCommand(UINT notification_code, const CPoint& point);
+ void OnSize(UINT param, const gfx::Size& size);
+ void OnSysCommand(UINT notification_code, const gfx::Point& point);
void OnThemeChanged();
LRESULT OnTouchEvent(UINT message, WPARAM w_param, LPARAM l_param);
void OnWindowPosChanging(WINDOWPOS* window_pos);
@@ -438,6 +456,28 @@ class VIEWS_EXPORT HWNDMessageHandler :
// of a touch event.
void HandleTouchEvents(const TouchEvents& touch_events);
+ // Resets the flag which indicates that we are in the context of a touch down
+ // event.
+ void ResetTouchDownContext();
+
+ // Helper to handle mouse events.
+ // The |message|, |w_param|, |l_param| parameters identify the Windows mouse
+ // message and its parameters respectively.
+ // The |track_mouse| parameter indicates if we should track the mouse.
+ LRESULT HandleMouseEventInternal(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ bool track_mouse);
+
+ // Returns true if the mouse message passed in is an OS synthesized mouse
+ // message.
+ // |message| identifies the mouse message.
+ // |message_time| is the time when the message occurred.
+ // |l_param| indicates the location of the mouse message.
+ bool IsSynthesizedMouseMessage(unsigned int message,
+ int message_time,
+ LPARAM l_param);
+
HWNDMessageHandlerDelegate* delegate_;
scoped_ptr<FullscreenHandler> fullscreen_handler_;
@@ -449,10 +489,6 @@ class VIEWS_EXPORT HWNDMessageHandler :
bool use_system_default_icon_;
- // Whether the focus should be restored next time we get enabled. Needed to
- // restore focus correctly when Windows modal dialogs are displayed.
- bool restore_focus_when_enabled_;
-
// Whether all ancestors have been enabled. This is only used if is_modal_ is
// true.
bool restored_enabled_;
@@ -535,6 +571,9 @@ class VIEWS_EXPORT HWNDMessageHandler :
// Copy of custom window region specified via SetRegion(), if any.
base::win::ScopedRegion custom_window_region_;
+ // If > 0 indicates a menu is running (we're showing a native menu).
+ int menu_depth_;
+
// A factory used to lookup appbar autohide edges.
base::WeakPtrFactory<HWNDMessageHandler> autohide_factory_;
@@ -547,14 +586,30 @@ class VIEWS_EXPORT HWNDMessageHandler :
// Set to true if we are in the context of a sizing operation.
bool in_size_loop_;
+ // Stores a pointer to the WindowEventTarget interface implemented by this
+ // class. Allows callers to retrieve the interface pointer.
+ scoped_ptr<ui::ViewProp> prop_window_target_;
+
+ // Number of active touch down contexts. This is incremented on touch down
+ // events and decremented later using a delayed task.
+ // We need this to ignore WM_MOUSEACTIVATE messages generated in response to
+ // touch input. This is fine because activation still works correctly via
+ // native SetFocus calls invoked in the views code.
+ int touch_down_contexts_;
+
+ // Time the last touch message was received. Used to flag mouse messages
+ // synthesized by Windows for touch which are not flagged by the OS as
+ // synthesized mouse messages. For more information please refer to
+ // the IsMouseEventFromTouch function.
+ static long last_touch_message_time_;
+
+ // Time the last WM_MOUSEHWHEEL message is received. Please refer to the
+ // HandleMouseEventInternal function as to why this is needed.
+ long last_mouse_hwheel_time_;
+
DISALLOW_COPY_AND_ASSIGN(HWNDMessageHandler);
};
-// This window property if set on the window does not activate the window for a
-// touch based WM_MOUSEACTIVATE message.
-const wchar_t kIgnoreTouchMouseActivateForWindow[] =
- L"Chrome.IgnoreMouseActivate";
-
} // namespace views
#endif // UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index e932d30c5e8..e17bf78eaa6 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -25,7 +25,6 @@ class TouchEvent;
namespace views {
class InputMethod;
-class NativeWidgetWin;
// Implemented by the object that uses the HWNDMessageHandler to handle
// notifications from the underlying HWND and service requests for data.
@@ -47,13 +46,6 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
virtual bool WidgetSizeIsClientSize() const = 0;
- // Returns true if the delegate has a focus saving mechanism that should be
- // used when the window is activated and deactivated.
- virtual bool CanSaveFocus() const = 0;
- virtual void SaveFocusOnDeactivate() = 0;
- virtual void RestoreFocusOnActivate() = 0;
- virtual void RestoreFocusOnEnable() = 0;
-
// Returns true if the delegate represents a modal window.
virtual bool IsModal() const = 0;
@@ -137,7 +129,7 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Called when the HWND is to be focused for the first time. This is called
// when the window is shown for the first time. Returns true if the delegate
// set focus and no default processing should be done by the message handler.
- virtual bool HandleInitialFocus() = 0;
+ virtual bool HandleInitialFocus(ui::WindowShowState show_state) = 0;
// Called when display settings are adjusted on the system.
virtual void HandleDisplayChange() = 0;
@@ -217,6 +209,9 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
WPARAM w_param,
LPARAM l_param) = 0;
+ // Invoked on entering/exiting a menu loop.
+ virtual void HandleMenuLoop(bool in_menu_loop) = 0;
+
// Catch-all message handling and filtering. Called before
// HWNDMessageHandler's built-in handling, which may pre-empt some
// expectations in Views/Aura if messages are consumed. Returns true if the
@@ -238,6 +233,9 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// handled by the delegate.
virtual bool HandleScrollEvent(const ui::ScrollEvent& event) = 0;
+ // Called when the window size is about to change.
+ virtual void HandleWindowSizeChanging() = 0;
+
protected:
virtual ~HWNDMessageHandlerDelegate() {}
};
diff --git a/chromium/ui/views/win/hwnd_util_aurawin.cc b/chromium/ui/views/win/hwnd_util_aurawin.cc
index 9fc6f10d816..37dca58f774 100644
--- a/chromium/ui/views/win/hwnd_util_aurawin.cc
+++ b/chromium/ui/views/win/hwnd_util_aurawin.cc
@@ -4,8 +4,8 @@
#include "ui/views/win/hwnd_util.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -20,21 +20,20 @@ HWND HWNDForWidget(const Widget* widget) {
HWND HWNDForNativeView(const gfx::NativeView view) {
return view && view->GetRootWindow() ?
- view->GetDispatcher()->host()->GetAcceleratedWidget() : NULL;
+ view->GetHost()->GetAcceleratedWidget() : NULL;
}
HWND HWNDForNativeWindow(const gfx::NativeWindow window) {
return window && window->GetRootWindow() ?
- window->GetDispatcher()->host()->GetAcceleratedWidget() : NULL;
+ window->GetHost()->GetAcceleratedWidget() : NULL;
}
gfx::Rect GetWindowBoundsForClientBounds(View* view,
const gfx::Rect& client_bounds) {
DCHECK(view);
- aura::WindowEventDispatcher* dispatcher =
- view->GetWidget()->GetNativeWindow()->GetDispatcher();
- if (dispatcher) {
- HWND hwnd = dispatcher->host()->GetAcceleratedWidget();
+ aura::WindowTreeHost* host = view->GetWidget()->GetNativeWindow()->GetHost();
+ if (host) {
+ HWND hwnd = host->GetAcceleratedWidget();
RECT rect = client_bounds.ToRECT();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
diff --git a/chromium/ui/views/win/hwnd_util_win.cc b/chromium/ui/views/win/hwnd_util_win.cc
deleted file mode 100644
index abc05f8ec84..00000000000
--- a/chromium/ui/views/win/hwnd_util_win.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/win/hwnd_util.h"
-
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-HWND HWNDForView(const View* view) {
- return view->GetWidget() ? HWNDForWidget(view->GetWidget()) : NULL;
-}
-
-// Returns the HWND associated with the specified widget.
-HWND HWNDForWidget(const Widget* widget) {
- return widget->GetNativeView();
-}
-
-HWND HWNDForNativeView(const gfx::NativeView view) {
- return view;
-}
-
-HWND HWNDForNativeWindow(const gfx::NativeWindow window) {
- return window;
-}
-
-gfx::Rect GetWindowBoundsForClientBounds(View* view,
- const gfx::Rect& client_bounds) {
- DCHECK(view);
- HWND hwnd = view->GetWidget()->GetNativeWindow();
- RECT rect = client_bounds.ToRECT();
- DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
- DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
- AdjustWindowRectEx(&rect, style, FALSE, ex_style);
- return gfx::Rect(rect);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/window/client_view.cc b/chromium/ui/views/window/client_view.cc
index 7edc5f4d5b9..fb7d89fed18 100644
--- a/chromium/ui/views/window/client_view.cc
+++ b/chromium/ui/views/window/client_view.cc
@@ -5,7 +5,7 @@
#include "ui/views/window/client_view.h"
#include "base/logging.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/hit_test.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -45,19 +45,19 @@ void ClientView::WidgetClosing() {
///////////////////////////////////////////////////////////////////////////////
// ClientView, View overrides:
-gfx::Size ClientView::GetPreferredSize() {
+gfx::Size ClientView::GetPreferredSize() const {
// |contents_view_| is allowed to be NULL up until the point where this view
// is attached to a Container.
return contents_view_ ? contents_view_->GetPreferredSize() : gfx::Size();
}
-gfx::Size ClientView::GetMaximumSize() {
+gfx::Size ClientView::GetMaximumSize() const {
// |contents_view_| is allowed to be NULL up until the point where this view
// is attached to a Container.
return contents_view_ ? contents_view_->GetMaximumSize() : gfx::Size();
}
-gfx::Size ClientView::GetMinimumSize() {
+gfx::Size ClientView::GetMinimumSize() const {
// |contents_view_| is allowed to be NULL up until the point where this view
// is attached to a Container.
return contents_view_ ? contents_view_->GetMinimumSize() : gfx::Size();
@@ -74,8 +74,8 @@ const char* ClientView::GetClassName() const {
return kViewClassName;
}
-void ClientView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_CLIENT;
+void ClientView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_CLIENT;
}
void ClientView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
diff --git a/chromium/ui/views/window/client_view.h b/chromium/ui/views/window/client_view.h
index 8c890d70b7c..5a329aad567 100644
--- a/chromium/ui/views/window/client_view.h
+++ b/chromium/ui/views/window/client_view.h
@@ -57,15 +57,15 @@ class VIEWS_EXPORT ClientView : public View {
virtual int NonClientHitTest(const gfx::Point& point);
// Overridden from View:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
protected:
// Overridden from View:
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index bb27dc60ca5..a3fb3f7c96c 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -5,6 +5,7 @@
#include "ui/views/window/custom_frame_view.h"
#include <algorithm>
+#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "grit/ui_resources.h"
@@ -16,21 +17,19 @@
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
+#include "ui/gfx/rect.h"
#include "ui/views/color_constants.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/frame_background.h"
+#include "ui/views/window/window_button_order_provider.h"
#include "ui/views/window/window_resources.h"
#include "ui/views/window/window_shape.h"
-#if defined(USE_AURA)
-#include "ui/views/widget/native_widget_aura.h"
-#elif defined(OS_WIN)
-#include "ui/views/widget/native_widget_win.h"
-#endif
-
namespace views {
namespace {
@@ -65,19 +64,17 @@ const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201);
const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228);
#endif
-const gfx::Font& GetTitleFont() {
- static gfx::Font* title_font = NULL;
- if (!title_font) {
-#if defined(USE_AURA)
- title_font = new gfx::Font(NativeWidgetAura::GetWindowTitleFont());
-#elif defined(OS_WIN)
- title_font = new gfx::Font(NativeWidgetWin::GetWindowTitleFont());
-#elif defined(OS_LINUX)
- // TODO(ben): need to resolve what font this is.
- title_font = new gfx::Font();
-#endif
- }
- return *title_font;
+const gfx::FontList& GetTitleFontList() {
+ static const gfx::FontList title_font_list =
+ internal::NativeWidgetPrivate::GetWindowTitleFontList();
+ return title_font_list;
+}
+
+void LayoutButton(ImageButton* button, const gfx::Rect& bounds) {
+ button->SetVisible(true);
+ button->SetImageAlignment(ImageButton::ALIGN_LEFT,
+ ImageButton::ALIGN_BOTTOM);
+ button->SetBoundsRect(bounds);
}
} // namespace
@@ -93,7 +90,9 @@ CustomFrameView::CustomFrameView()
restore_button_(NULL),
close_button_(NULL),
should_show_maximize_button_(false),
- frame_background_(new FrameBackground()) {
+ frame_background_(new FrameBackground()),
+ minimum_title_bar_x_(0),
+ maximum_title_bar_x_(-1) {
}
CustomFrameView::~CustomFrameView() {
@@ -102,19 +101,12 @@ CustomFrameView::~CustomFrameView() {
void CustomFrameView::Init(Widget* frame) {
frame_ = frame;
- close_button_ = new ImageButton(this);
- close_button_->SetAccessibleName(
- l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
-
- // Close button images will be set in LayoutWindowControls().
- AddChildView(close_button_);
-
+ close_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_CLOSE,
+ IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P);
minimize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MINIMIZE,
IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P);
-
maximize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MAXIMIZE,
IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P);
-
restore_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_RESTORE,
IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P);
@@ -137,8 +129,8 @@ gfx::Rect CustomFrameView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
int top_height = NonClientTopBorderHeight();
int border_thickness = NonClientBorderThickness();
- return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
- std::max(0, client_bounds.y() - top_height),
+ return gfx::Rect(client_bounds.x() - border_thickness,
+ client_bounds.y() - top_height,
client_bounds.width() + (2 * border_thickness),
client_bounds.height() + top_height + border_thickness);
}
@@ -186,7 +178,7 @@ int CustomFrameView::NonClientHitTest(const gfx::Point& point) {
void CustomFrameView::GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) {
DCHECK(window_mask);
- if (frame_->IsMaximized())
+ if (frame_->IsMaximized() || !ShouldShowTitleBarAndBorder())
return;
GetDefaultWindowMask(size, window_mask);
@@ -205,13 +197,17 @@ void CustomFrameView::UpdateWindowIcon() {
}
void CustomFrameView::UpdateWindowTitle() {
- SchedulePaintInRect(title_bounds_);
+ if (frame_->widget_delegate()->ShouldShowWindowTitle())
+ SchedulePaintInRect(title_bounds_);
}
///////////////////////////////////////////////////////////////////////////////
// CustomFrameView, View overrides:
void CustomFrameView::OnPaint(gfx::Canvas* canvas) {
+ if (!ShouldShowTitleBarAndBorder())
+ return;
+
if (frame_->IsMaximized())
PaintMaximizedFrameBorder(canvas);
else
@@ -222,22 +218,25 @@ void CustomFrameView::OnPaint(gfx::Canvas* canvas) {
}
void CustomFrameView::Layout() {
- LayoutWindowControls();
- LayoutTitleBar();
+ if (ShouldShowTitleBarAndBorder()) {
+ LayoutWindowControls();
+ LayoutTitleBar();
+ }
+
LayoutClientView();
}
-gfx::Size CustomFrameView::GetPreferredSize() {
+gfx::Size CustomFrameView::GetPreferredSize() const {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
}
-gfx::Size CustomFrameView::GetMinimumSize() {
+gfx::Size CustomFrameView::GetMinimumSize() const {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetMinimumSize())).size();
}
-gfx::Size CustomFrameView::GetMaximumSize() {
+gfx::Size CustomFrameView::GetMaximumSize() const {
gfx::Size max_size = frame_->client_view()->GetMaximumSize();
gfx::Size converted_size =
frame_->non_client_view()->GetWindowBoundsForClientBounds(
@@ -282,7 +281,11 @@ int CustomFrameView::NonClientTopBorderHeight() const {
int CustomFrameView::CaptionButtonY() const {
// Maximized buttons start at window top so that even if their images aren't
// drawn flush with the screen edge, they still obey Fitts' Law.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ return FrameBorderThickness();
+#else
return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
+#endif
}
int CustomFrameView::TitlebarBottomThickness() const {
@@ -296,7 +299,7 @@ int CustomFrameView::IconSize() const {
// size are increased.
return GetSystemMetrics(SM_CYSMICON);
#else
- return std::max(GetTitleFont().GetHeight(), kIconMinimumSize);
+ return std::max(GetTitleFontList().GetHeight(), kIconMinimumSize);
#endif
}
@@ -320,11 +323,24 @@ gfx::Rect CustomFrameView::IconBounds() const {
// 3D edge (or nothing at all, for maximized windows) above; hence the +1.
int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
- return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
+ return gfx::Rect(frame_thickness + kIconLeftSpacing + minimum_title_bar_x_,
+ y, size, size);
+}
+
+bool CustomFrameView::ShouldShowTitleBarAndBorder() const {
+ if (frame_->IsFullscreen())
+ return false;
+
+ if (ViewsDelegate::views_delegate) {
+ return !ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar(
+ frame_->IsMaximized());
+ }
+
+ return true;
}
bool CustomFrameView::ShouldShowClientEdge() const {
- return !frame_->IsMaximized();
+ return !frame_->IsMaximized() && ShouldShowTitleBarAndBorder();
}
void CustomFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
@@ -374,13 +390,13 @@ void CustomFrameView::PaintTitleBar(gfx::Canvas* canvas) {
// It seems like in some conditions we can be asked to paint after the window
// that contains us is WM_DESTROYed. At this point, our delegate is NULL. The
// correct long term fix may be to shut down the RootView in WM_DESTROY.
- if (!delegate)
+ if (!delegate || !delegate->ShouldShowWindowTitle())
return;
- canvas->DrawStringInt(delegate->GetWindowTitle(), GetTitleFont(),
- SK_ColorWHITE, GetMirroredXForRect(title_bounds_),
- title_bounds_.y(), title_bounds_.width(),
- title_bounds_.height());
+ gfx::Rect rect = title_bounds_;
+ rect.set_x(GetMirroredXForRect(title_bounds_));
+ canvas->DrawStringRect(delegate->GetWindowTitle(), GetTitleFontList(),
+ SK_ColorWHITE, rect);
}
void CustomFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
@@ -462,70 +478,68 @@ const gfx::ImageSkia* CustomFrameView::GetFrameImage() const {
}
void CustomFrameView::LayoutWindowControls() {
- close_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
- ImageButton::ALIGN_BOTTOM);
+ minimum_title_bar_x_ = 0;
+ maximum_title_bar_x_ = width();
+
+ if (bounds().IsEmpty())
+ return;
+
int caption_y = CaptionButtonY();
bool is_maximized = frame_->IsMaximized();
// There should always be the same number of non-shadow pixels visible to the
- // side of the caption buttons. In maximized mode we extend the rightmost
- // button to the screen corner to obey Fitts' Law.
- int right_extra_width = is_maximized ?
+ // side of the caption buttons. In maximized mode we extend the edge button
+ // to the screen corner to obey Fitts' Law.
+ int extra_width = is_maximized ?
(kFrameBorderThickness - kFrameShadowThickness) : 0;
- gfx::Size close_button_size = close_button_->GetPreferredSize();
- close_button_->SetBounds(width() - FrameBorderThickness() -
- right_extra_width - close_button_size.width(), caption_y,
- close_button_size.width() + right_extra_width,
- close_button_size.height());
-
- // When the window is restored, we show a maximized button; otherwise, we show
- // a restore button.
+ int next_button_x = FrameBorderThickness();
+
bool is_restored = !is_maximized && !frame_->IsMinimized();
ImageButton* invisible_button = is_restored ? restore_button_
: maximize_button_;
invisible_button->SetVisible(false);
- ImageButton* visible_button = is_restored ? maximize_button_
- : restore_button_;
- FramePartImage normal_part, hot_part, pushed_part;
- int next_button_x;
- if (should_show_maximize_button_) {
- visible_button->SetVisible(true);
- visible_button->SetImageAlignment(ImageButton::ALIGN_LEFT,
- ImageButton::ALIGN_BOTTOM);
- gfx::Size visible_button_size = visible_button->GetPreferredSize();
- visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
- caption_y, visible_button_size.width(),
- visible_button_size.height());
- next_button_x = visible_button->x();
- } else {
- visible_button->SetVisible(false);
- next_button_x = close_button_->x();
+ WindowButtonOrderProvider* button_order =
+ WindowButtonOrderProvider::GetInstance();
+ const std::vector<views::FrameButton>& leading_buttons =
+ button_order->leading_buttons();
+ const std::vector<views::FrameButton>& trailing_buttons =
+ button_order->trailing_buttons();
+
+ ImageButton* button = NULL;
+ for (std::vector<views::FrameButton>::const_iterator it =
+ leading_buttons.begin(); it != leading_buttons.end(); ++it) {
+ button = GetImageButton(*it);
+ if (!button)
+ continue;
+ gfx::Rect target_bounds(gfx::Point(next_button_x, caption_y),
+ button->GetPreferredSize());
+ if (it == leading_buttons.begin())
+ target_bounds.set_width(target_bounds.width() + extra_width);
+ LayoutButton(button, target_bounds);
+ next_button_x += button->width();
+ minimum_title_bar_x_ = std::min(width(), next_button_x);
}
- minimize_button_->SetVisible(true);
- minimize_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
- ImageButton::ALIGN_BOTTOM);
- gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
- minimize_button_->SetBounds(
- next_button_x - minimize_button_size.width(), caption_y,
- minimize_button_size.width(),
- minimize_button_size.height());
-
- normal_part = IDR_CLOSE;
- hot_part = IDR_CLOSE_H;
- pushed_part = IDR_CLOSE_P;
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
- close_button_->SetImage(CustomButton::STATE_NORMAL,
- rb.GetImageNamed(normal_part).ToImageSkia());
- close_button_->SetImage(CustomButton::STATE_HOVERED,
- rb.GetImageNamed(hot_part).ToImageSkia());
- close_button_->SetImage(CustomButton::STATE_PRESSED,
- rb.GetImageNamed(pushed_part).ToImageSkia());
+ // Trailing buttions are laid out in a RTL fashion
+ next_button_x = width() - FrameBorderThickness();
+ for (std::vector<views::FrameButton>::const_reverse_iterator it =
+ trailing_buttons.rbegin(); it != trailing_buttons.rend(); ++it) {
+ button = GetImageButton(*it);
+ if (!button)
+ continue;
+ gfx::Rect target_bounds(gfx::Point(next_button_x, caption_y),
+ button->GetPreferredSize());
+ if (it == trailing_buttons.rbegin())
+ target_bounds.set_width(target_bounds.width() + extra_width);
+ target_bounds.Offset(-target_bounds.width(), 0);
+ LayoutButton(button, target_bounds);
+ next_button_x = button->x();
+ maximum_title_bar_x_ = std::max(minimum_title_bar_x_, next_button_x);
+ }
}
void CustomFrameView::LayoutTitleBar() {
+ DCHECK_GE(maximum_title_bar_x_, 0);
// The window title position is calculated based on the icon position, even
// when there is no icon.
gfx::Rect icon_bounds(IconBounds());
@@ -533,10 +547,13 @@ void CustomFrameView::LayoutTitleBar() {
if (show_window_icon)
window_icon_->SetBoundsRect(icon_bounds);
+ if (!frame_->widget_delegate()->ShouldShowWindowTitle())
+ return;
+
// The offset between the window left edge and the title text.
int title_x = show_window_icon ? icon_bounds.right() + kTitleIconOffsetX
: icon_bounds.x();
- int title_height = GetTitleFont().GetHeight();
+ int title_height = GetTitleFontList().GetHeight();
// We bias the title position so that when the difference between the icon and
// title heights is odd, the extra pixel of the title is above the vertical
// midline rather than below. This compensates for how the icon is already
@@ -544,11 +561,16 @@ void CustomFrameView::LayoutTitleBar() {
// title from overlapping the 3D edge at the bottom of the titlebar.
title_bounds_.SetRect(title_x,
icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
- std::max(0, minimize_button_->x() - kTitleCaptionSpacing -
+ std::max(0, maximum_title_bar_x_ - kTitleCaptionSpacing -
title_x), title_height);
}
void CustomFrameView::LayoutClientView() {
+ if (!ShouldShowTitleBarAndBorder()) {
+ client_view_bounds_ = bounds();
+ return;
+ }
+
int top_height = NonClientTopBorderHeight();
int border_thickness = NonClientBorderThickness();
client_view_bounds_.SetRect(border_thickness, top_height,
@@ -574,4 +596,31 @@ ImageButton* CustomFrameView::InitWindowCaptionButton(
return button;
}
+ImageButton* CustomFrameView::GetImageButton(views::FrameButton frame_button) {
+ ImageButton* button = NULL;
+ switch (frame_button) {
+ case views::FRAME_BUTTON_MINIMIZE: {
+ button = minimize_button_;
+ break;
+ }
+ case views::FRAME_BUTTON_MAXIMIZE: {
+ bool is_restored = !frame_->IsMaximized() && !frame_->IsMinimized();
+ button = is_restored ? maximize_button_ : restore_button_;
+ if (!should_show_maximize_button_) {
+ // If we should not show the maximize/restore button, then we return
+ // NULL as we don't want this button to become visible and to be laid
+ // out.
+ button->SetVisible(false);
+ return NULL;
+ }
+ break;
+ }
+ case views::FRAME_BUTTON_CLOSE: {
+ button = close_button_;
+ break;
+ }
+ }
+ return button;
+}
+
} // namespace views
diff --git a/chromium/ui/views/window/custom_frame_view.h b/chromium/ui/views/window/custom_frame_view.h
index 8c96df7fc9f..fe5a3e4c7bd 100644
--- a/chromium/ui/views/window/custom_frame_view.h
+++ b/chromium/ui/views/window/custom_frame_view.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/button/button.h"
+#include "ui/views/window/frame_buttons.h"
#include "ui/views/window/non_client_view.h"
namespace gfx {
@@ -29,8 +30,8 @@ class Widget;
// rendering the non-standard window caption, border, and controls.
//
////////////////////////////////////////////////////////////////////////////////
-class CustomFrameView : public NonClientFrameView,
- public ButtonListener {
+class VIEWS_EXPORT CustomFrameView : public NonClientFrameView,
+ public ButtonListener {
public:
CustomFrameView();
virtual ~CustomFrameView();
@@ -51,14 +52,16 @@ class CustomFrameView : public NonClientFrameView,
// Overridden from View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
// Overridden from ButtonListener:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
private:
+ friend class CustomFrameViewTest;
+
// Returns the thickness of the border that makes up the window frame edges.
// This does not include any client edge.
int FrameBorderThickness() const;
@@ -86,6 +89,10 @@ class CustomFrameView : public NonClientFrameView,
// there was one).
gfx::Rect IconBounds() const;
+ // Returns true if the title bar, caption buttons, and frame border should be
+ // drawn. If false, the client view occupies the full area of this view.
+ bool ShouldShowTitleBarAndBorder() const;
+
// Returns true if the client edge should be drawn. This is true if
// the window is not maximized.
bool ShouldShowClientEdge() const;
@@ -100,8 +107,13 @@ class CustomFrameView : public NonClientFrameView,
SkColor GetFrameColor() const;
const gfx::ImageSkia* GetFrameImage() const;
- // Layout various sub-components of this view.
+ // Performs the layout for the window control buttons based on the
+ // configuration specified in WindowButtonOrderProvider. The sizing and
+ // positions of the buttons affects LayoutTitleBar, call this beforehand.
void LayoutWindowControls();
+
+ // Calculations depend on the positions of the window controls. Always call
+ // LayoutWindowControls beforehand.
void LayoutTitleBar();
void LayoutClientView();
@@ -112,6 +124,10 @@ class CustomFrameView : public NonClientFrameView,
int hot_image_id,
int pushed_image_id);
+ // Returns the window caption button for the given FrameButton type, if it
+ // should be visible. Otherwise NULL.
+ ImageButton* GetImageButton(views::FrameButton button);
+
// The bounds of the client view, in this view's coordinates.
gfx::Rect client_view_bounds_;
@@ -136,6 +152,11 @@ class CustomFrameView : public NonClientFrameView,
// Background painter for the window frame.
scoped_ptr<FrameBackground> frame_background_;
+ // The horizontal boundaries for the title bar to layout within. Restricted
+ // by the space used by the leading and trailing buttons.
+ int minimum_title_bar_x_;
+ int maximum_title_bar_x_;
+
DISALLOW_COPY_AND_ASSIGN(CustomFrameView);
};
diff --git a/chromium/ui/views/window/custom_frame_view_unittest.cc b/chromium/ui/views/window/custom_frame_view_unittest.cc
new file mode 100644
index 00000000000..26711190214
--- /dev/null
+++ b/chromium/ui/views/window/custom_frame_view_unittest.cc
@@ -0,0 +1,252 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/window/custom_frame_view.h"
+
+#include <vector>
+
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/window_button_order_provider.h"
+
+namespace views {
+
+namespace {
+
+// Allows for the control of whether or not the widget can maximize or not.
+// This can be set after initial setup in order to allow testing of both forms
+// of delegates. By default this can maximize.
+class MaximizeStateControlDelegate : public WidgetDelegateView {
+ public:
+ MaximizeStateControlDelegate() : can_maximize_(true) {}
+ virtual ~MaximizeStateControlDelegate() {}
+
+ void set_can_maximize(bool can_maximize) {
+ can_maximize_ = can_maximize;
+ }
+
+ // WidgetDelegate:
+ virtual bool CanMaximize() const OVERRIDE { return can_maximize_; }
+
+ private:
+ bool can_maximize_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaximizeStateControlDelegate);
+};
+
+} // namespace
+
+class CustomFrameViewTest : public ViewsTestBase {
+ public:
+ CustomFrameViewTest() {}
+ virtual ~CustomFrameViewTest() {}
+
+ CustomFrameView* custom_frame_view() {
+ return custom_frame_view_;
+ }
+
+ MaximizeStateControlDelegate* maximize_state_control_delegate() {
+ return maximize_state_control_delegate_;
+ }
+
+ Widget* widget() {
+ return widget_;
+ }
+
+ // ViewsTestBase:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ protected:
+ const std::vector<views::FrameButton>& leading_buttons() {
+ return WindowButtonOrderProvider::GetInstance()->leading_buttons();
+ }
+
+ const std::vector<views::FrameButton>& trailing_buttons() {
+ return WindowButtonOrderProvider::GetInstance()->trailing_buttons();
+ }
+
+ ImageButton* minimize_button() {
+ return custom_frame_view_->minimize_button_;
+ }
+
+ ImageButton* maximize_button() {
+ return custom_frame_view_->maximize_button_;
+ }
+
+ ImageButton* restore_button() {
+ return custom_frame_view_->restore_button_;
+ }
+
+ ImageButton* close_button() {
+ return custom_frame_view_->close_button_;
+ }
+
+ gfx::Rect title_bounds() {
+ return custom_frame_view_->title_bounds_;
+ }
+
+ void SetWindowButtonOrder(
+ const std::vector<views::FrameButton> leading_buttons,
+ const std::vector<views::FrameButton> trailing_buttons);
+
+ private:
+ // Parent container for |custom_frame_view_|
+ Widget* widget_;
+
+ // Owned by |widget_|
+ CustomFrameView* custom_frame_view_;
+
+ // Delegate of |widget_| which controls maximizing
+ MaximizeStateControlDelegate* maximize_state_control_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomFrameViewTest);
+};
+
+void CustomFrameViewTest::SetUp() {
+ ViewsTestBase::SetUp();
+
+ maximize_state_control_delegate_ = new MaximizeStateControlDelegate;
+ widget_ = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.delegate = maximize_state_control_delegate_;
+ params.remove_standard_frame = true;
+ widget_->Init(params);
+
+ custom_frame_view_ = new CustomFrameView;
+ widget_->non_client_view()->SetFrameView(custom_frame_view_);
+}
+
+void CustomFrameViewTest::TearDown() {
+ widget_->CloseNow();
+
+ ViewsTestBase::TearDown();
+}
+
+void CustomFrameViewTest::SetWindowButtonOrder(
+ const std::vector<views::FrameButton> leading_buttons,
+ const std::vector<views::FrameButton> trailing_buttons) {
+ WindowButtonOrderProvider::GetInstance()->
+ SetWindowButtonOrder(leading_buttons, trailing_buttons);
+}
+
+// Tests that there is a default button ordering before initialization causes
+// a configuration file check.
+TEST_F(CustomFrameViewTest, DefaultButtons) {
+ const std::vector<views::FrameButton>& trailing = trailing_buttons();
+ EXPECT_EQ(trailing.size(), 3u);
+ EXPECT_TRUE(leading_buttons().empty());
+ EXPECT_EQ(trailing[0], FRAME_BUTTON_MINIMIZE);
+ EXPECT_EQ(trailing[1], FRAME_BUTTON_MAXIMIZE);
+ EXPECT_EQ(trailing[2], FRAME_BUTTON_CLOSE);
+}
+
+// Tests that layout places the buttons in order, that the restore button is
+// hidden and the buttons are placed after the title.
+TEST_F(CustomFrameViewTest, DefaultButtonLayout) {
+ Widget* parent = widget();
+ CustomFrameView* view = custom_frame_view();
+ view->Init(parent);
+ parent->SetBounds(gfx::Rect(0, 0, 300, 100));
+ parent->Show();
+
+ EXPECT_LT(minimize_button()->x(), maximize_button()->x());
+ EXPECT_LT(maximize_button()->x(), close_button()->x());
+ EXPECT_FALSE(restore_button()->visible());
+
+ EXPECT_GT(minimize_button()->x(),
+ title_bounds().x() + title_bounds().width());
+}
+
+// Tests that setting the buttons to leading places them before the title.
+TEST_F(CustomFrameViewTest, LeadingButtonLayout) {
+ Widget* parent = widget();
+ CustomFrameView* view = custom_frame_view();
+
+ std::vector<views::FrameButton> leading;
+ leading.push_back(views::FRAME_BUTTON_CLOSE);
+ leading.push_back(views::FRAME_BUTTON_MINIMIZE);
+ leading.push_back(views::FRAME_BUTTON_MAXIMIZE);
+
+ std::vector<views::FrameButton> trailing;
+
+ SetWindowButtonOrder(leading, trailing);
+
+ view->Init(parent);
+ parent->SetBounds(gfx::Rect(0, 0, 300, 100));
+ parent->Show();
+ EXPECT_LT(close_button()->x(), minimize_button()->x());
+ EXPECT_LT(minimize_button()->x(), maximize_button()->x());
+ EXPECT_FALSE(restore_button()->visible());
+ EXPECT_LT(maximize_button()->x() + maximize_button()->width(),
+ title_bounds().x());
+}
+
+// Tests that layouts occuring while maximized swap the maximize button for the
+// restore button
+TEST_F(CustomFrameViewTest, MaximizeRevealsRestoreButton) {
+ Widget* parent = widget();
+ CustomFrameView* view = custom_frame_view();
+ view->Init(parent);
+ parent->SetBounds(gfx::Rect(0, 0, 300, 100));
+ parent->Show();
+
+ ASSERT_FALSE(restore_button()->visible());
+ ASSERT_TRUE(maximize_button()->visible());
+
+ parent->Maximize();
+ view->Layout();
+
+ EXPECT_TRUE(restore_button()->visible());
+ EXPECT_FALSE(maximize_button()->visible());
+}
+
+// Tests that when the parent cannot maximize that the maximize button is not
+// visible
+TEST_F(CustomFrameViewTest, CannotMaximizeHidesButton) {
+ Widget* parent = widget();
+ CustomFrameView* view = custom_frame_view();
+ MaximizeStateControlDelegate* delegate = maximize_state_control_delegate();
+ delegate->set_can_maximize(false);
+
+ view->Init(parent);
+ parent->SetBounds(gfx::Rect(0, 0, 300, 100));
+ parent->Show();
+
+ EXPECT_FALSE(restore_button()->visible());
+ EXPECT_FALSE(maximize_button()->visible());
+}
+
+// Tests that when maximized that the edge button has an increased width.
+TEST_F(CustomFrameViewTest, LargerEdgeButtonsWhenMaximized) {
+ Widget* parent = widget();
+ CustomFrameView* view = custom_frame_view();
+
+ // Custom ordering to have a button on each edge.
+ std::vector<views::FrameButton> leading;
+ leading.push_back(views::FRAME_BUTTON_CLOSE);
+ leading.push_back(views::FRAME_BUTTON_MAXIMIZE);
+ std::vector<views::FrameButton> trailing;
+ trailing.push_back(views::FRAME_BUTTON_MINIMIZE);
+ SetWindowButtonOrder(leading, trailing);
+
+ view->Init(parent);
+ parent->SetBounds(gfx::Rect(0, 0, 300, 100));
+ parent->Show();
+
+ gfx::Rect close_button_initial_bounds = close_button()->bounds();
+ gfx::Rect minimize_button_initial_bounds = minimize_button()->bounds();
+
+ parent->Maximize();
+ view->Layout();
+
+ EXPECT_GT(close_button()->bounds().width(),
+ close_button_initial_bounds.width());
+ EXPECT_GT(minimize_button()->bounds().width(),
+ minimize_button_initial_bounds.width());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index bfb870ed50b..172ca0fde3d 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -22,12 +22,30 @@ namespace {
// conflict with other groups that could be in the dialog content.
const int kButtonGroup = 6666;
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+const bool kIsOkButtonOnLeftSide = true;
+#else
+const bool kIsOkButtonOnLeftSide = false;
+#endif
+
// Returns true if the given view should be shown (i.e. exists and is
// visible).
bool ShouldShow(View* view) {
return view && view->visible();
}
+// Do the layout for a button.
+void LayoutButton(LabelButton* button, gfx::Rect* row_bounds) {
+ if (!button)
+ return;
+
+ const gfx::Size size = button->GetPreferredSize();
+ row_bounds->set_width(row_bounds->width() - size.width());
+ button->SetBounds(row_bounds->right(), row_bounds->y(),
+ size.width(), row_bounds->height());
+ row_bounds->set_width(row_bounds->width() - kRelatedButtonHSpacing);
+}
+
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -157,7 +175,7 @@ void DialogClientView::OnDidChangeFocus(View* focused_before,
////////////////////////////////////////////////////////////////////////////////
// DialogClientView, View overrides:
-gfx::Size DialogClientView::GetPreferredSize() {
+gfx::Size DialogClientView::GetPreferredSize() const {
// Initialize the size to fit the buttons and extra view row.
gfx::Size size(
(ok_button_ ? ok_button_->GetPreferredSize().width() : 0) +
@@ -213,19 +231,12 @@ void DialogClientView::Layout() {
const int height = GetButtonsAndExtraViewRowHeight();
gfx::Rect row_bounds(bounds.x(), bounds.bottom() - height,
bounds.width(), height);
- if (cancel_button_) {
- const gfx::Size size = cancel_button_->GetPreferredSize();
- row_bounds.set_width(row_bounds.width() - size.width());
- cancel_button_->SetBounds(row_bounds.right(), row_bounds.y(),
- size.width(), height);
- row_bounds.set_width(row_bounds.width() - kRelatedButtonHSpacing);
- }
- if (ok_button_) {
- const gfx::Size size = ok_button_->GetPreferredSize();
- row_bounds.set_width(row_bounds.width() - size.width());
- ok_button_->SetBounds(row_bounds.right(), row_bounds.y(),
- size.width(), height);
- row_bounds.set_width(row_bounds.width() - kRelatedButtonHSpacing);
+ if (kIsOkButtonOnLeftSide) {
+ LayoutButton(cancel_button_, &row_bounds);
+ LayoutButton(ok_button_, &row_bounds);
+ } else {
+ LayoutButton(ok_button_, &row_bounds);
+ LayoutButton(cancel_button_, &row_bounds);
}
if (extra_view_) {
row_bounds.set_width(std::min(row_bounds.width(),
@@ -254,13 +265,6 @@ void DialogClientView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
ClientView::ViewHierarchyChanged(details);
if (details.is_add && details.child == this) {
- // The old dialog style needs an explicit background color, while the new
- // dialog style simply inherits the bubble's frame view color.
- const DialogDelegate* dialog = GetDialogDelegate();
- if (dialog && !dialog->UseNewStyleForThisDialog())
- set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
- GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
-
focus_manager_ = GetFocusManager();
if (focus_manager_)
GetFocusManager()->AddFocusChangeListener(this);
@@ -293,6 +297,17 @@ void DialogClientView::NativeViewHierarchyChanged() {
}
}
+void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ // The old dialog style needs an explicit background color, while the new
+ // dialog style simply inherits the bubble's frame view color.
+ const DialogDelegate* dialog = GetDialogDelegate();
+
+ if (dialog && !dialog->UseNewStyleForThisDialog()) {
+ set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// DialogClientView, ButtonListener implementation:
@@ -359,7 +374,7 @@ void DialogClientView::ChildVisibilityChanged(View* child) {
// DialogClientView, private:
LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
- const string16 title = GetDialogDelegate()->GetDialogButtonLabel(type);
+ const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type);
LabelButton* button = NULL;
if (GetDialogDelegate()->UseNewStyleForThisDialog() &&
GetDialogDelegate()->GetDefaultDialogButton() == type &&
@@ -367,7 +382,7 @@ LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
button = new BlueButton(this, title);
} else {
button = new LabelButton(this, title);
- button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
+ button->SetStyle(Button::STYLE_BUTTON);
}
button->SetFocusable(true);
diff --git a/chromium/ui/views/window/dialog_client_view.h b/chromium/ui/views/window/dialog_client_view.h
index d780806094c..1e8ced11c77 100644
--- a/chromium/ui/views/window/dialog_client_view.h
+++ b/chromium/ui/views/window/dialog_client_view.h
@@ -57,12 +57,13 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
View* focused_now) OVERRIDE;
// View implementation:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual void NativeViewHierarchyChanged() OVERRIDE;
+ virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
// ButtonListener implementation:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE;
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index cb5374acf55..5ec29a216a9 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -14,8 +14,8 @@
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_client_view.h"
-#if defined(USE_AURA)
-#include "ui/views/corewm/shadow_types.h"
+#if defined(OS_WIN)
+#include "ui/base/win/shell.h"
#endif
namespace views {
@@ -23,23 +23,42 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// DialogDelegate:
+DialogDelegate::DialogDelegate() : supports_new_style_(true) {
+}
+
DialogDelegate::~DialogDelegate() {
}
// static
-Widget* DialogDelegate::CreateDialogWidget(DialogDelegate* dialog,
- gfx::NativeWindow context,
- gfx::NativeWindow parent) {
+Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate,
+ gfx::NativeView context,
+ gfx::NativeView parent) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params;
- params.delegate = dialog;
+ params.delegate = delegate;
+ DialogDelegate* dialog = delegate->AsDialogDelegate();
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // The new style doesn't support unparented dialogs on Linux desktop.
+ if (dialog)
+ dialog->supports_new_style_ &= parent != NULL;
+#elif defined(OS_WIN)
+ // The new style doesn't support unparented dialogs on Windows Classic themes.
+ if (dialog && !ui::win::IsAeroGlassEnabled())
+ dialog->supports_new_style_ &= parent != NULL;
+#endif
+
if (!dialog || dialog->UseNewStyleForThisDialog()) {
params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
params.remove_standard_frame = true;
+ // The bubble frame includes its own shadow; remove any native shadowing.
+ params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
}
params.context = context;
params.parent = parent;
- params.top_level = true;
+ // Web-modal (ui::MODAL_TYPE_CHILD) dialogs with parents are marked as child
+ // widgets to prevent top-level window behavior (independent movement, etc).
+ params.child = parent && (delegate->GetModalType() == ui::MODAL_TYPE_CHILD);
widget->Init(params);
return widget;
}
@@ -154,43 +173,22 @@ NonClientFrameView* DialogDelegate::CreateNonClientFrameView(Widget* widget) {
// static
NonClientFrameView* DialogDelegate::CreateDialogFrameView(Widget* widget) {
- return CreateDialogFrameView(widget, false);
-}
-
-// static
-NonClientFrameView* DialogDelegate::CreateDialogFrameView(
- Widget* widget,
- bool force_opaque_border) {
BubbleFrameView* frame = new BubbleFrameView(gfx::Insets());
- const SkColor color = widget->GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_DialogBackground);
- if (force_opaque_border) {
- frame->SetBubbleBorder(new BubbleBorder(
- BubbleBorder::NONE,
- BubbleBorder::NO_SHADOW_OPAQUE_BORDER,
- color));
- } else {
- frame->SetBubbleBorder(new BubbleBorder(BubbleBorder::FLOAT,
- BubbleBorder::SMALL_SHADOW,
- color));
- }
+ scoped_ptr<BubbleBorder> border(new BubbleBorder(
+ BubbleBorder::FLOAT, BubbleBorder::SMALL_SHADOW, SK_ColorRED));
+ border->set_use_theme_background_color(true);
+ frame->SetBubbleBorder(border.Pass());
DialogDelegate* delegate = widget->widget_delegate()->AsDialogDelegate();
if (delegate) {
View* titlebar_view = delegate->CreateTitlebarExtraView();
if (titlebar_view)
frame->SetTitlebarExtraView(titlebar_view);
}
- if (force_opaque_border)
- widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
-#if defined(USE_AURA)
- // TODO(msw): Add a matching shadow type and remove the bubble frame border?
- corewm::SetShadowType(widget->GetNativeWindow(), corewm::SHADOW_TYPE_NONE);
-#endif
return frame;
}
bool DialogDelegate::UseNewStyleForThisDialog() const {
- return true;
+ return supports_new_style_;
}
const DialogClientView* DialogDelegate::GetDialogClientView() const {
@@ -201,8 +199,8 @@ DialogClientView* DialogDelegate::GetDialogClientView() {
return GetWidget()->client_view()->AsDialogClientView();
}
-ui::AccessibilityTypes::Role DialogDelegate::GetAccessibleWindowRole() const {
- return ui::AccessibilityTypes::ROLE_DIALOG;
+ui::AXRole DialogDelegate::GetAccessibleWindowRole() const {
+ return ui::AX_ROLE_DIALOG;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index 8e8948de427..91fff1e51fb 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -7,7 +7,7 @@
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
-#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/accessibility/ax_enums.h"
#include "ui/base/models/dialog_model.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/widget/widget_delegate.h"
@@ -29,12 +29,13 @@ class DialogClientView;
class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
public WidgetDelegate {
public:
+ DialogDelegate();
virtual ~DialogDelegate();
- // Create a |dialog| window Widget with the specified |context| or |parent|.
- static Widget* CreateDialogWidget(DialogDelegate* dialog,
- gfx::NativeWindow context,
- gfx::NativeWindow parent);
+ // Create a dialog widget with the specified |context| or |parent|.
+ static Widget* CreateDialogWidget(WidgetDelegate* delegate,
+ gfx::NativeView context,
+ gfx::NativeView parent);
// Override this function to display an extra view adjacent to the buttons.
// Overrides may construct the view; this will only be called once per dialog.
@@ -91,14 +92,6 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
// Create a frame view using the new dialog style.
static NonClientFrameView* CreateDialogFrameView(Widget* widget);
- // The semi-transparent border and shadow of the new style frame view does not
- // work on child windows under Views/Win32. This is a kludge to get a
- // reasonable-looking opaque border for the dialog. Note that this does not
- // support arrows.
- //
- // TODO(wittman): Remove once WinAura is in place.
- static NonClientFrameView* CreateDialogFrameView(Widget* widget,
- bool force_opaque_border);
// Returns whether this particular dialog should use the new dialog style.
virtual bool UseNewStyleForThisDialog() const;
@@ -113,7 +106,11 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
protected:
// Overridden from WidgetDelegate:
- virtual ui::AccessibilityTypes::Role GetAccessibleWindowRole() const OVERRIDE;
+ virtual ui::AXRole GetAccessibleWindowRole() const OVERRIDE;
+
+ private:
+ // A flag indicating whether this dialog supports the new style.
+ bool supports_new_style_;
};
// A DialogDelegate implementation that is-a View. Used to override GetWidget()
diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc
index f56073affac..fedb6983eb2 100644
--- a/chromium/ui/views/window/dialog_delegate_unittest.cc
+++ b/chromium/ui/views/window/dialog_delegate_unittest.cc
@@ -37,8 +37,11 @@ class TestDialog : public DialogDelegateView, public ButtonListener {
}
// DialogDelegateView overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(200, 200); }
- virtual string16 GetWindowTitle() const OVERRIDE { return title_; }
+ virtual gfx::Size GetPreferredSize() const OVERRIDE {
+ return gfx::Size(200, 200);
+ }
+ virtual base::string16 GetWindowTitle() const OVERRIDE { return title_; }
+ virtual bool UseNewStyleForThisDialog() const OVERRIDE { return true; }
// ButtonListener override:
virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE {
@@ -73,7 +76,7 @@ class TestDialog : public DialogDelegateView, public ButtonListener {
GetWidget()->Close();
}
- void set_title(const string16& title) { title_ = title; }
+ void set_title(const base::string16& title) { title_ = title; }
private:
bool canceled_;
@@ -81,7 +84,7 @@ class TestDialog : public DialogDelegateView, public ButtonListener {
// Prevent the dialog from closing, for repeated ok and cancel button clicks.
bool closeable_;
Button* last_pressed_button_;
- string16 title_;
+ base::string16 title_;
DISALLOW_COPY_AND_ASSIGN(TestDialog);
};
@@ -121,21 +124,21 @@ TEST_F(DialogTest, DefaultButtons) {
dialog()->PressEnterAndCheckStates(ok_button);
// Focus another button in the dialog, it should become the default.
- LabelButton* button_1 = new LabelButton(dialog(), string16());
+ LabelButton* button_1 = new LabelButton(dialog(), base::string16());
client_view->AddChildView(button_1);
client_view->OnWillChangeFocus(ok_button, button_1);
EXPECT_TRUE(button_1->is_default());
dialog()->PressEnterAndCheckStates(button_1);
// Focus a Checkbox (not a push button), OK should become the default again.
- Checkbox* checkbox = new Checkbox(string16());
+ Checkbox* checkbox = new Checkbox(base::string16());
client_view->AddChildView(checkbox);
client_view->OnWillChangeFocus(button_1, checkbox);
EXPECT_FALSE(button_1->is_default());
dialog()->PressEnterAndCheckStates(ok_button);
// Focus yet another button in the dialog, it should become the default.
- LabelButton* button_2 = new LabelButton(dialog(), string16());
+ LabelButton* button_2 = new LabelButton(dialog(), base::string16());
client_view->AddChildView(button_2);
client_view->OnWillChangeFocus(checkbox, button_2);
EXPECT_FALSE(button_1->is_default());
@@ -205,21 +208,22 @@ TEST_F(DialogTest, HitTest) {
}
}
-TEST_F(DialogTest, InitialBoundsAccommodateTitle) {
- TestDialog* titled_dialog(new TestDialog());
- titled_dialog->set_title(ASCIIToUTF16("Title"));
- DialogDelegate::CreateDialogWidget(titled_dialog, GetContext(), NULL);
+TEST_F(DialogTest, BoundsAccommodateTitle) {
+ TestDialog* dialog2(new TestDialog());
+ dialog2->set_title(base::ASCIIToUTF16("Title"));
+ DialogDelegate::CreateDialogWidget(dialog2, GetContext(), NULL);
// Titled dialogs have taller initial frame bounds than untitled dialogs.
- EXPECT_GT(titled_dialog->GetWidget()->GetWindowBoundsInScreen().height(),
- dialog()->GetWidget()->GetWindowBoundsInScreen().height());
+ View* frame1 = dialog()->GetWidget()->non_client_view()->frame_view();
+ View* frame2 = dialog2->GetWidget()->non_client_view()->frame_view();
+ EXPECT_LT(frame1->GetPreferredSize().height(),
+ frame2->GetPreferredSize().height());
- // Giving the default test dialog a title will make the bounds the same.
- dialog()->set_title(ASCIIToUTF16("Title"));
+ // Giving the default test dialog a title will yield the same bounds.
+ dialog()->set_title(base::ASCIIToUTF16("Title"));
dialog()->GetWidget()->UpdateWindowTitle();
- View* frame = dialog()->GetWidget()->non_client_view()->frame_view();
- EXPECT_EQ(titled_dialog->GetWidget()->GetWindowBoundsInScreen().height(),
- frame->GetPreferredSize().height());
+ EXPECT_EQ(frame1->GetPreferredSize().height(),
+ frame2->GetPreferredSize().height());
}
} // namespace views
diff --git a/chromium/ui/views/window/frame_background.cc b/chromium/ui/views/window/frame_background.cc
index 111ac257814..f9e8293c0db 100644
--- a/chromium/ui/views/window/frame_background.cc
+++ b/chromium/ui/views/window/frame_background.cc
@@ -26,10 +26,7 @@ FrameBackground::FrameBackground()
top_right_corner_(NULL),
bottom_left_corner_(NULL),
bottom_right_corner_(NULL),
- maximized_top_left_(NULL),
- maximized_top_right_(NULL),
- maximized_top_offset_(0),
- theme_background_y_(0) {
+ maximized_top_inset_(0) {
}
FrameBackground::~FrameBackground() {
@@ -124,41 +121,25 @@ void FrameBackground::PaintRestored(gfx::Canvas* canvas, View* view) const {
}
void FrameBackground::PaintMaximized(gfx::Canvas* canvas, View* view) const {
- // We will be painting from top_offset to top_offset + theme_frame_height. If
- // this is less than top_area_height_, we need to paint the frame color
- // to fill in the area beneath the image.
- // TODO(jamescook): I'm not sure this is correct, as it doesn't seem to fully
- // account for the top_offset, but this is how it worked before.
- int theme_frame_bottom = maximized_top_offset_ + theme_image_->height();
+ // We will be painting from -|maximized_top_inset_| to
+ // -|maximized_top_inset_| + |theme_image_|->height(). If this is less than
+ // |top_area_height_|, we need to paint the frame color to fill in the area
+ // beneath the image.
+ int theme_frame_bottom = -maximized_top_inset_ + theme_image_->height();
if (top_area_height_ > theme_frame_bottom) {
canvas->FillRect(gfx::Rect(0, 0, view->width(), top_area_height_),
frame_color_);
}
- int left_offset = 0;
- int right_offset = 0;
-
- // Draw top-left and top-right corners to give maximized ChromeOS windows
- // a rounded appearance.
- if (maximized_top_left_ || maximized_top_right_) {
- // If we have either a left or right we should have both.
- DCHECK(maximized_top_left_ && maximized_top_right_);
- left_offset = maximized_top_left_->width();
- right_offset = maximized_top_right_->width();
- canvas->DrawImageInt(*maximized_top_left_, 0, 0);
- canvas->DrawImageInt(*maximized_top_right_,
- view->width() - right_offset, 0);
- }
-
// Draw the theme frame.
canvas->TileImageInt(*theme_image_,
- left_offset,
- maximized_top_offset_,
- view->width() - (left_offset + right_offset),
+ 0,
+ -maximized_top_inset_,
+ view->width(),
theme_image_->height());
// Draw the theme frame overlay, if available.
if (theme_overlay_image_)
- canvas->DrawImageInt(*theme_overlay_image_, 0, theme_background_y_);
+ canvas->DrawImageInt(*theme_overlay_image_, 0, -maximized_top_inset_);
}
void FrameBackground::PaintFrameColor(gfx::Canvas* canvas, View* view) const {
diff --git a/chromium/ui/views/window/frame_background.h b/chromium/ui/views/window/frame_background.h
index b8684f61399..bdabf51f72e 100644
--- a/chromium/ui/views/window/frame_background.h
+++ b/chromium/ui/views/window/frame_background.h
@@ -44,11 +44,8 @@ class VIEWS_EXPORT FrameBackground {
// which must extend behind the tab strip.
void set_top_area_height(int height) { top_area_height_ = height; }
- // Only used if we have an overlay image for the theme.
- void set_theme_background_y(int y) { theme_background_y_ = y; }
-
- // Vertical offset for theme image when drawing maximized.
- void set_maximized_top_offset(int offset) { maximized_top_offset_ = offset; }
+ // Vertical inset for theme image when drawing maximized.
+ void set_maximized_top_inset(int inset) { maximized_top_inset_ = inset; }
// Sets images used when drawing the sides of the frame.
// Caller owns the memory.
@@ -94,12 +91,8 @@ class VIEWS_EXPORT FrameBackground {
const gfx::ImageSkia* bottom_left_corner_;
const gfx::ImageSkia* bottom_right_corner_;
- // Attributes for maximized window painting.
- // TODO(jamescook): Remove all these.
- gfx::ImageSkia* maximized_top_left_;
- gfx::ImageSkia* maximized_top_right_;
- int maximized_top_offset_;
- int theme_background_y_;
+ // Vertical inset for theme image when drawing maximized.
+ int maximized_top_inset_;
DISALLOW_COPY_AND_ASSIGN(FrameBackground);
};
diff --git a/chromium/ui/views/window/native_frame_view.cc b/chromium/ui/views/window/native_frame_view.cc
index 1cbafabe57b..1ffbcdbb02b 100644
--- a/chromium/ui/views/window/native_frame_view.cc
+++ b/chromium/ui/views/window/native_frame_view.cc
@@ -16,6 +16,9 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// NativeFrameView, public:
+// static
+const char NativeFrameView::kViewClassName[] = "NativeFrameView";
+
NativeFrameView::NativeFrameView(Widget* frame)
: NonClientFrameView(),
frame_(frame) {
@@ -37,8 +40,12 @@ gfx::Rect NativeFrameView::GetWindowBoundsForClientBounds(
return views::GetWindowBoundsForClientBounds(
static_cast<View*>(const_cast<NativeFrameView*>(this)), client_bounds);
#else
- // TODO(sad):
- return client_bounds;
+ // Enforce minimum size (1, 1) in case that |client_bounds| is passed with
+ // empty size.
+ gfx::Rect window_bounds = client_bounds;
+ if (window_bounds.IsEmpty())
+ window_bounds.set_size(gfx::Size(1,1));
+ return window_bounds;
#endif
}
@@ -63,20 +70,30 @@ void NativeFrameView::UpdateWindowTitle() {
// Nothing to do.
}
-// Returns the client size. On Windows, this is the expected behavior for
-// native frames (see |NativeWidgetWin::WidgetSizeIsClientSize()|), while other
-// platforms currently always return client bounds from
-// |GetWindowBoundsForClientBounds()|.
-gfx::Size NativeFrameView::GetPreferredSize() {
- return frame_->client_view()->GetPreferredSize();
+gfx::Size NativeFrameView::GetPreferredSize() const {
+ gfx::Size client_preferred_size = frame_->client_view()->GetPreferredSize();
+#if defined(OS_WIN)
+ // Returns the client size. On Windows, this is the expected behavior for
+ // native frames (see |NativeWidgetWin::WidgetSizeIsClientSize()|), while
+ // other platforms currently always return client bounds from
+ // |GetWindowBoundsForClientBounds()|.
+ return client_preferred_size;
+#else
+ return frame_->non_client_view()->GetWindowBoundsForClientBounds(
+ gfx::Rect(client_preferred_size)).size();
+#endif
}
-gfx::Size NativeFrameView::GetMinimumSize() {
+gfx::Size NativeFrameView::GetMinimumSize() const {
return frame_->client_view()->GetMinimumSize();
}
-gfx::Size NativeFrameView::GetMaximumSize() {
+gfx::Size NativeFrameView::GetMaximumSize() const {
return frame_->client_view()->GetMaximumSize();
}
+const char* NativeFrameView::GetClassName() const {
+ return kViewClassName;
+}
+
} // namespace views
diff --git a/chromium/ui/views/window/native_frame_view.h b/chromium/ui/views/window/native_frame_view.h
index 378e354bf79..154453d3eba 100644
--- a/chromium/ui/views/window/native_frame_view.h
+++ b/chromium/ui/views/window/native_frame_view.h
@@ -13,6 +13,8 @@ class Widget;
class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
public:
+ static const char kViewClassName[];
+
explicit NativeFrameView(Widget* frame);
virtual ~NativeFrameView();
@@ -28,9 +30,10 @@ class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
virtual void UpdateWindowTitle() OVERRIDE;
// View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
+ virtual const char* GetClassName() const OVERRIDE;
private:
// Our containing frame.
diff --git a/chromium/ui/views/window/non_client_view.cc b/chromium/ui/views/window/non_client_view.cc
index f7cd70e5cd3..e4068dba177 100644
--- a/chromium/ui/views/window/non_client_view.cc
+++ b/chromium/ui/views/window/non_client_view.cc
@@ -4,7 +4,7 @@
#include "ui/views/window/non_client_view.h"
-#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/accessibility/ax_view_state.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/views/rect_based_targeting_utils.h"
@@ -127,14 +127,14 @@ void NonClientView::LayoutFrameView() {
frame_view_->Layout();
}
-void NonClientView::SetAccessibleName(const string16& name) {
+void NonClientView::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
////////////////////////////////////////////////////////////////////////////////
// NonClientView, View overrides:
-gfx::Size NonClientView::GetPreferredSize() {
+gfx::Size NonClientView::GetPreferredSize() const {
// TODO(pkasting): This should probably be made to look similar to
// GetMinimumSize() below. This will require implementing GetPreferredSize()
// better in the various frame views.
@@ -142,11 +142,11 @@ gfx::Size NonClientView::GetPreferredSize() {
return GetWindowBoundsForClientBounds(client_bounds).size();
}
-gfx::Size NonClientView::GetMinimumSize() {
+gfx::Size NonClientView::GetMinimumSize() const {
return frame_view_->GetMinimumSize();
}
-gfx::Size NonClientView::GetMaximumSize() {
+gfx::Size NonClientView::GetMaximumSize() const {
return frame_view_->GetMaximumSize();
}
@@ -177,8 +177,8 @@ void NonClientView::ViewHierarchyChanged(
}
}
-void NonClientView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_CLIENT;
+void NonClientView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_CLIENT;
state->name = accessible_name_;
}
@@ -186,8 +186,8 @@ const char* NonClientView::GetClassName() const {
return kViewClassName;
}
-views::View* NonClientView::GetEventHandlerForRect(const gfx::Rect& rect) {
- if (!views::UsePointBasedTargeting(rect))
+View* NonClientView::GetEventHandlerForRect(const gfx::Rect& rect) {
+ if (!UsePointBasedTargeting(rect))
return View::GetEventHandlerForRect(rect);
// Because of the z-ordering of our child views (the client view is positioned
@@ -212,7 +212,7 @@ views::View* NonClientView::GetEventHandlerForRect(const gfx::Rect& rect) {
return View::GetEventHandlerForRect(rect);
}
-views::View* NonClientView::GetTooltipHandlerForPoint(const gfx::Point& point) {
+View* NonClientView::GetTooltipHandlerForPoint(const gfx::Point& point) {
// The same logic as for |GetEventHandlerForRect()| applies here.
if (frame_view_->parent() == this) {
// During the reset of the frame_view_ it's possible to be in this code
@@ -220,7 +220,7 @@ views::View* NonClientView::GetTooltipHandlerForPoint(const gfx::Point& point) {
// removed from the NonClientView.
gfx::Point point_in_child_coords(point);
View::ConvertPointToTarget(this, frame_view_.get(), &point_in_child_coords);
- views::View* handler =
+ View* handler =
frame_view_->GetTooltipHandlerForPoint(point_in_child_coords);
if (handler)
return handler;
@@ -232,12 +232,23 @@ views::View* NonClientView::GetTooltipHandlerForPoint(const gfx::Point& point) {
////////////////////////////////////////////////////////////////////////////////
// NonClientFrameView, public:
+NonClientFrameView::~NonClientFrameView() {
+}
+
void NonClientFrameView::SetInactiveRenderingDisabled(bool disable) {
- if (paint_as_active_ == disable)
+ if (inactive_rendering_disabled_ == disable)
return;
- paint_as_active_ = disable;
- ShouldPaintAsActiveChanged();
+ bool should_paint_as_active_old = ShouldPaintAsActive();
+ inactive_rendering_disabled_ = disable;
+
+ // The widget schedules a paint when the activation changes.
+ if (should_paint_as_active_old != ShouldPaintAsActive())
+ SchedulePaint();
+}
+
+bool NonClientFrameView::ShouldPaintAsActive() const {
+ return inactive_rendering_disabled_ || GetWidget()->IsActive();
}
int NonClientFrameView::GetHTComponentForFrame(const gfx::Point& point,
@@ -301,16 +312,8 @@ bool NonClientFrameView::HitTestRect(const gfx::Rect& rect) const {
////////////////////////////////////////////////////////////////////////////////
// NonClientFrameView, protected:
-bool NonClientFrameView::ShouldPaintAsActive() const {
- return GetWidget()->IsActive() || paint_as_active_;
-}
-
-void NonClientFrameView::ShouldPaintAsActiveChanged() {
- SchedulePaint();
-}
-
-void NonClientFrameView::GetAccessibleState(ui::AccessibleViewState* state) {
- state->role = ui::AccessibilityTypes::ROLE_CLIENT;
+void NonClientFrameView::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_CLIENT;
}
const char* NonClientFrameView::GetClassName() const {
@@ -322,4 +325,7 @@ void NonClientFrameView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
// FrameView when it is itself laid out, see comment in NonClientView::Layout.
}
+NonClientFrameView::NonClientFrameView() : inactive_rendering_disabled_(false) {
+}
+
} // namespace views
diff --git a/chromium/ui/views/window/non_client_view.h b/chromium/ui/views/window/non_client_view.h
index 2c3b1d9fe49..77181426418 100644
--- a/chromium/ui/views/window/non_client_view.h
+++ b/chromium/ui/views/window/non_client_view.h
@@ -37,12 +37,18 @@ class VIEWS_EXPORT NonClientFrameView : public View {
kClientEdgeThickness = 1,
};
+ virtual ~NonClientFrameView();
+
// Sets whether the window should be rendered as active regardless of the
// actual active state. Used when bubbles become active to make their parent
// appear active. A value of true makes the window render as active always,
// false gives normal behavior.
void SetInactiveRenderingDisabled(bool disable);
+ // Used to determine if the frame should be painted as active. Keyed off the
+ // window's actual active state and |inactive_rendering_disabled_|.
+ bool ShouldPaintAsActive() const;
+
// Helper for non-client view implementations to determine which area of the
// window border the specified |point| falls within. The other parameters are
// the size of the sizing edges, and whether or not the window can be
@@ -74,28 +80,18 @@ class VIEWS_EXPORT NonClientFrameView : public View {
// Overridden from View:
virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
protected:
virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
- NonClientFrameView() : paint_as_active_(false) {}
-
- // Used to determine if the frame should be painted as active. Keyed off the
- // window's actual active state and the override, see
- // SetInactiveRenderingDisabled() above.
- bool ShouldPaintAsActive() const;
-
- // Invoked from SetInactiveRenderingDisabled(). This implementation invokes
- // SchedulesPaint as necessary.
- virtual void ShouldPaintAsActiveChanged();
+ NonClientFrameView();
private:
- // True when the non-client view should always be rendered as if the window
- // were active, regardless of whether or not the top level window actually
- // is active.
- bool paint_as_active_;
+ // Prevents the non-client frame view from being rendered as inactive when
+ // true.
+ bool inactive_rendering_disabled_;
};
////////////////////////////////////////////////////////////////////////////////
@@ -166,8 +162,6 @@ class VIEWS_EXPORT NonClientView : public View {
// Prevents the window from being rendered as deactivated when |disable| is
// true, until called with |disable| false. Used when a sub-window is to be
// shown that shouldn't visually de-activate the window.
- // Subclasses can override this to perform additional actions when this value
- // changes.
void SetInactiveRenderingDisabled(bool disable);
// Returns the bounds of the window required to display the content area at
@@ -208,14 +202,14 @@ class VIEWS_EXPORT NonClientView : public View {
void LayoutFrameView();
// Set the accessible name of this view.
- void SetAccessibleName(const string16& name);
+ void SetAccessibleName(const base::string16& name);
// NonClientView, View overrides:
- virtual gfx::Size GetPreferredSize() OVERRIDE;
- virtual gfx::Size GetMinimumSize() OVERRIDE;
- virtual gfx::Size GetMaximumSize() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() const OVERRIDE;
+ virtual gfx::Size GetMinimumSize() const OVERRIDE;
+ virtual gfx::Size GetMaximumSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
virtual views::View* GetEventHandlerForRect(const gfx::Rect& rect) OVERRIDE;
@@ -243,7 +237,7 @@ class VIEWS_EXPORT NonClientView : public View {
View* overlay_view_;
// The accessible name of this view.
- string16 accessible_name_;
+ base::string16 accessible_name_;
DISALLOW_COPY_AND_ASSIGN(NonClientView);
};
diff --git a/chromium/ui/views/window/window_button_order_provider.cc b/chromium/ui/views/window/window_button_order_provider.cc
new file mode 100644
index 00000000000..b1ac70e4727
--- /dev/null
+++ b/chromium/ui/views/window/window_button_order_provider.cc
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/window/window_button_order_provider.h"
+
+namespace views {
+
+// static
+WindowButtonOrderProvider* WindowButtonOrderProvider::instance_ = NULL;
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowButtonOrderProvider, public:
+
+// static
+WindowButtonOrderProvider* WindowButtonOrderProvider::GetInstance() {
+ if (!instance_)
+ instance_ = new WindowButtonOrderProvider;
+ return instance_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowButtonOrderProvider, protected:
+
+WindowButtonOrderProvider::WindowButtonOrderProvider() {
+ trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
+ trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
+ trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
+}
+
+WindowButtonOrderProvider::~WindowButtonOrderProvider() {
+}
+
+void WindowButtonOrderProvider::SetWindowButtonOrder(
+ const std::vector<views::FrameButton>& leading_buttons,
+ const std::vector<views::FrameButton>& trailing_buttons) {
+ leading_buttons_ = leading_buttons;
+ trailing_buttons_ = trailing_buttons;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/window/window_button_order_provider.h b/chromium/ui/views/window/window_button_order_provider.h
new file mode 100644
index 00000000000..f50a49f0fb7
--- /dev/null
+++ b/chromium/ui/views/window/window_button_order_provider.h
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
+#define UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/views/views_export.h"
+#include "ui/views/window/frame_buttons.h"
+
+namespace views {
+
+// Stores the ordering of window control buttons. Provides a default ordering
+// of |FRAME_BUTTON_MINIMZE|, |FRAME_BUTTON_MAXIMIZE|, |FRAME_BUTTON_CLOSE|,
+// where all controls are on the trailing end of a window.
+//
+// On Linux users can provide configuration files to control the ordering. This
+// configuration is checked and overrides the defaults.
+class VIEWS_EXPORT WindowButtonOrderProvider {
+ public:
+ static WindowButtonOrderProvider* GetInstance();
+
+ const std::vector<views::FrameButton>& leading_buttons() const {
+ return leading_buttons_;
+ }
+
+ const std::vector<views::FrameButton>& trailing_buttons() const {
+ return trailing_buttons_;
+ }
+
+ void SetWindowButtonOrder(
+ const std::vector<views::FrameButton>& leading_buttons,
+ const std::vector<views::FrameButton>& trailing_buttons);
+
+ protected:
+ WindowButtonOrderProvider();
+ virtual ~WindowButtonOrderProvider();
+
+ private:
+ static WindowButtonOrderProvider* instance_;
+
+ // Layout arrangement of the window caption buttons. On linux these will be
+ // set via a WindowButtonOrderObserver. On other platforms a default
+ // arrangement of a trailing minimize, maximize, close, will be set.
+ std::vector<views::FrameButton> leading_buttons_;
+ std::vector<views::FrameButton> trailing_buttons_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowButtonOrderProvider);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_WINDOW_BUTTON_ORDER_PROVIDER_H_
diff --git a/chromium/ui/views_content_client/DEPS b/chromium/ui/views_content_client/DEPS
new file mode 100644
index 00000000000..59d317e6842
--- /dev/null
+++ b/chromium/ui/views_content_client/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+content/public",
+ "+content/shell",
+ "+ui/aura",
+ "+ui/base",
+ "+ui/gfx",
+ "+ui/views",
+ "+ui/wm",
+]
diff --git a/chromium/ui/views_content_client/README.chromium b/chromium/ui/views_content_client/README.chromium
new file mode 100644
index 00000000000..3df233e4587
--- /dev/null
+++ b/chromium/ui/views_content_client/README.chromium
@@ -0,0 +1,3 @@
+This directory contains a content client for standalone views apps. It sets up
+the multiprocess runtime environment for rendering web content, and establishes
+the required environment for running a toolkit-views application.
diff --git a/chromium/ui/views_content_client/views_content_browser_client.cc b/chromium/ui/views_content_client/views_content_browser_client.cc
new file mode 100644
index 00000000000..4bc3786e65e
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_browser_client.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_content_client/views_content_browser_client.h"
+
+#include "content/shell/browser/shell_browser_context.h"
+#include "ui/views_content_client/views_content_client_main_parts.h"
+
+namespace ui {
+
+ViewsContentBrowserClient::ViewsContentBrowserClient(
+ ViewsContentClient* views_content_client)
+ : views_content_main_parts_(NULL),
+ views_content_client_(views_content_client) {
+}
+
+ViewsContentBrowserClient::~ViewsContentBrowserClient() {
+}
+
+content::BrowserMainParts* ViewsContentBrowserClient::CreateBrowserMainParts(
+ const content::MainFunctionParams& parameters) {
+ views_content_main_parts_ =
+ ViewsContentClientMainParts::Create(parameters, views_content_client_);
+ return views_content_main_parts_;
+}
+
+net::URLRequestContextGetter*
+ViewsContentBrowserClient::CreateRequestContext(
+ content::BrowserContext* content_browser_context,
+ content::ProtocolHandlerMap* protocol_handlers,
+ content::URLRequestInterceptorScopedVector request_interceptors) {
+ content::ShellBrowserContext* shell_context =
+ views_content_main_parts_->browser_context();
+ return shell_context->CreateRequestContext(protocol_handlers,
+ request_interceptors.Pass());
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_browser_client.h b/chromium/ui/views_content_client/views_content_browser_client.h
new file mode 100644
index 00000000000..f01cd3acb31
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_browser_client.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_BROWSER_CLIENT_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_BROWSER_CLIENT_H_
+
+#include "base/macros.h"
+#include "content/public/browser/content_browser_client.h"
+
+namespace content {
+class ShellBrowserContext;
+}
+
+namespace ui {
+
+class ViewsContentClient;
+class ViewsContentClientMainParts;
+
+class ViewsContentBrowserClient : public content::ContentBrowserClient {
+ public:
+ explicit ViewsContentBrowserClient(
+ ViewsContentClient* views_content_client);
+ virtual ~ViewsContentBrowserClient();
+
+ // content::ContentBrowserClient:
+ virtual content::BrowserMainParts* CreateBrowserMainParts(
+ const content::MainFunctionParams& parameters) OVERRIDE;
+ virtual net::URLRequestContextGetter* CreateRequestContext(
+ content::BrowserContext* browser_context,
+ content::ProtocolHandlerMap* protocol_handlers,
+ content::URLRequestInterceptorScopedVector request_interceptors) OVERRIDE;
+
+ private:
+ ViewsContentClientMainParts* views_content_main_parts_;
+ ViewsContentClient* views_content_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentBrowserClient);
+};
+
+} // namespace ui
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_BROWSER_CLIENT_H_
diff --git a/chromium/ui/views_content_client/views_content_client.cc b/chromium/ui/views_content_client/views_content_client.cc
new file mode 100644
index 00000000000..95af7dc8c60
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client.cc
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_content_client/views_content_client.h"
+
+#include "content/public/app/content_main.h"
+#include "ui/views_content_client/views_content_main_delegate.h"
+
+namespace ui {
+
+#if defined(OS_WIN)
+ViewsContentClient::ViewsContentClient(
+ HINSTANCE instance, sandbox::SandboxInterfaceInfo* sandbox_info)
+ : instance_(instance), sandbox_info_(sandbox_info) {
+}
+#else
+ViewsContentClient::ViewsContentClient(int argc, const char** argv)
+ : argc_(argc), argv_(argv) {
+}
+#endif
+
+ViewsContentClient::~ViewsContentClient() {
+}
+
+int ViewsContentClient::RunMain() {
+ ViewsContentMainDelegate delegate(this);
+ content::ContentMainParams params(&delegate);
+
+#if defined(OS_WIN)
+ params.instance = instance_;
+ params.sandbox_info = sandbox_info_;
+#else
+ params.argc = argc_;
+ params.argv = argv_;
+#endif
+
+ return content::ContentMain(params);
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_client.gyp b/chromium/ui/views_content_client/views_content_client.gyp
new file mode 100644
index 00000000000..1773c2af63d
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client.gyp
@@ -0,0 +1,60 @@
+# 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.
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'views_content_client',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:base_i18n',
+ '../../content/content.gyp:content',
+ '../../content/content_shell_and_tests.gyp:content_shell_lib',
+ '../../third_party/icu/icu.gyp:icui18n',
+ '../../third_party/icu/icu.gyp:icuuc',
+ '../base/ui_base.gyp:ui_base',
+ '../events/events.gyp:events',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../resources/ui_resources.gyp:ui_resources',
+ '../resources/ui_resources.gyp:ui_test_pak',
+ '../views/views.gyp:views',
+ '../views/views.gyp:views_test_support',
+ ],
+ 'defines': [
+ 'VIEWS_CONTENT_CLIENT_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'views_content_browser_client.cc',
+ 'views_content_browser_client.h',
+ 'views_content_client.cc',
+ 'views_content_client.h',
+ 'views_content_client_export.h',
+ 'views_content_client_main_parts.cc',
+ 'views_content_client_main_parts.h',
+ 'views_content_client_main_parts_aura.cc',
+ 'views_content_client_main_parts_aura.h',
+ 'views_content_client_main_parts_chromeos.cc',
+ 'views_content_client_main_parts_desktop_aura.cc',
+ 'views_content_client_main_parts_mac.mm',
+ 'views_content_main_delegate.cc',
+ ],
+ 'conditions': [
+ ['use_aura==1', {
+ 'dependencies': [
+ '../aura/aura.gyp:aura',
+ ],
+ }], # use_aura==1
+ ['chromeos==1', {
+ 'sources!': [
+ 'views_content_client_main_parts_desktop_aura.cc',
+ ]
+ }], # chromeos==1
+ ],
+ }, # target_name: views_content_client
+ ],
+}
diff --git a/chromium/ui/views_content_client/views_content_client.h b/chromium/ui/views_content_client/views_content_client.h
new file mode 100644
index 00000000000..04289462a1f
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client.h
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views_content_client/views_content_client_export.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace sandbox {
+struct SandboxInterfaceInfo;
+}
+
+namespace ui {
+
+// Creates a multiprocess views runtime for running an example application.
+//
+// Sample usage:
+//
+// void InitMyApp(content::BrowserContext* browser_context,
+// gfx::NativeView window_context) {
+// // Create desired windows and views here. Runs on the UI thread.
+// }
+//
+// #if defined(OS_WIN)
+// int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
+// sandbox::SandboxInterfaceInfo sandbox_info = {0};
+// content::InitializeSandboxInfo(&sandbox_info);
+// ui::ViewsContentClient params(instance, &sandbox_info);
+// #else
+// int main(int argc, const char** argv) {
+// ui::ViewsContentClient params(argc, argv);
+// #endif
+//
+// params.set_task(base::Bind(&InitMyApp));
+// return params.RunMain();
+// }
+class VIEWS_CONTENT_CLIENT_EXPORT ViewsContentClient {
+ public:
+ typedef base::Callback<
+ void(content::BrowserContext* browser_context,
+ gfx::NativeView window_context)> Task;
+
+#if defined(OS_WIN)
+ ViewsContentClient(HINSTANCE instance,
+ sandbox::SandboxInterfaceInfo* sandbox_info);
+#else
+ ViewsContentClient(int argc, const char** argv);
+#endif
+
+ ~ViewsContentClient();
+
+ // Runs content::ContentMain() using the ExamplesMainDelegate.
+ int RunMain();
+
+ // The task to run at the end of BrowserMainParts::PreMainMessageLoopRun().
+ // Ignored if this is not the main process.
+ void set_task(const Task& task) { task_ = task; }
+ const Task& task() const { return task_; }
+
+ private:
+#if defined(OS_WIN)
+ HINSTANCE instance_;
+ sandbox::SandboxInterfaceInfo* sandbox_info_;
+#else
+ int argc_;
+ const char** argv_;
+#endif
+ Task task_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClient);
+};
+
+} // namespace ui
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_H_
diff --git a/chromium/ui/views_content_client/views_content_client_export.h b/chromium/ui/views_content_client/views_content_client_export.h
new file mode 100644
index 00000000000..fafa52ee0ec
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_export.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_EXPORT_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_EXPORT_H_
+
+// Defines VIEWS_CONTENT_CLIENT_EXPORT so that functionality implemented by the
+// views_content_client module can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(VIEWS_CONTENT_CLIENT_IMPLEMENTATION)
+#define VIEWS_CONTENT_CLIENT_EXPORT __declspec(dllexport)
+#else
+#define VIEWS_CONTENT_CLIENT_EXPORT __declspec(dllimport)
+#endif // defined(VIEWS_CONTENT_CLIENT_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(VIEWS_CONTENT_CLIENT_IMPLEMENTATION)
+#define VIEWS_CONTENT_CLIENT_EXPORT __attribute__((visibility("default")))
+#else
+#define VIEWS_CONTENT_CLIENT_EXPORT
+#endif
+#endif // defined(VIEWS_CONTENT_CLIENT_IMPLEMENTATION)
+
+#else // defined(COMPONENT_BUILD)
+#define VIEWS_CONTENT_CLIENT_EXPORT
+#endif
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_EXPORT_H_
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts.cc b/chromium/ui/views_content_client/views_content_client_main_parts.cc
new file mode 100644
index 00000000000..d51ceb243e9
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts.cc
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_content_client/views_content_client_main_parts.h"
+
+#include "base/run_loop.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "ui/base/ime/input_method_initializer.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+
+namespace ui {
+
+ViewsContentClientMainParts::ViewsContentClientMainParts(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client)
+ : views_content_client_(views_content_client) {
+}
+
+ViewsContentClientMainParts::~ViewsContentClientMainParts() {
+}
+
+void ViewsContentClientMainParts::PreMainMessageLoopRun() {
+ ui::InitializeInputMethodForTesting();
+ browser_context_.reset(new content::ShellBrowserContext(false, NULL));
+ views_delegate_.reset(new views::DesktopTestViewsDelegate);
+}
+
+void ViewsContentClientMainParts::PostMainMessageLoopRun() {
+ browser_context_.reset();
+ views_delegate_.reset();
+}
+
+bool ViewsContentClientMainParts::MainMessageLoopRun(int* result_code) {
+ base::RunLoop run_loop;
+ run_loop.Run();
+ return true;
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts.h b/chromium/ui/views_content_client/views_content_client_main_parts.h
new file mode 100644
index 00000000000..113e352953b
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_main_parts.h"
+
+namespace content {
+class ShellBrowserContext;
+struct MainFunctionParams;
+}
+
+namespace views {
+class ViewsDelegate;
+}
+
+namespace ui {
+
+class ViewsContentClient;
+
+class ViewsContentClientMainParts : public content::BrowserMainParts {
+ public:
+ // Platform-specific create function.
+ static ViewsContentClientMainParts* Create(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+
+ virtual ~ViewsContentClientMainParts();
+
+ // content::BrowserMainParts:
+ virtual void PreMainMessageLoopRun() OVERRIDE;
+ virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
+ virtual void PostMainMessageLoopRun() OVERRIDE;
+
+ content::ShellBrowserContext* browser_context() {
+ return browser_context_.get();
+ }
+
+ ViewsContentClient* views_content_client() {
+ return views_content_client_;
+ }
+
+ protected:
+ ViewsContentClientMainParts(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+
+ private:
+ scoped_ptr<content::ShellBrowserContext> browser_context_;
+
+ scoped_ptr<views::ViewsDelegate> views_delegate_;
+
+ ViewsContentClient* views_content_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainParts);
+};
+
+} // namespace ui
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_H_
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc b/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc
new file mode 100644
index 00000000000..5e1c69a295b
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_aura.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_content_client/views_content_client_main_parts_aura.h"
+
+#include "ui/aura/env.h"
+#include "ui/wm/core/wm_state.h"
+
+namespace ui {
+
+ViewsContentClientMainPartsAura::ViewsContentClientMainPartsAura(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client)
+ : ViewsContentClientMainParts(content_params, views_content_client) {
+}
+
+ViewsContentClientMainPartsAura::~ViewsContentClientMainPartsAura() {
+}
+
+void ViewsContentClientMainPartsAura::ToolkitInitialized() {
+ ViewsContentClientMainParts::ToolkitInitialized();
+
+ wm_state_.reset(new ::wm::WMState);
+}
+
+void ViewsContentClientMainPartsAura::PostMainMessageLoopRun() {
+ aura::Env::DeleteInstance();
+
+ ViewsContentClientMainParts::PostMainMessageLoopRun();
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_aura.h b/chromium/ui/views_content_client/views_content_client_main_parts_aura.h
new file mode 100644
index 00000000000..06b273a50bb
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_aura.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_AURA_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_AURA_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/views_content_client/views_content_client_main_parts.h"
+
+namespace wm {
+class WMState;
+}
+
+namespace ui {
+
+class ViewsContentClientMainPartsAura : public ViewsContentClientMainParts {
+ protected:
+ ViewsContentClientMainPartsAura(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+ virtual ~ViewsContentClientMainPartsAura();
+
+ // content::BrowserMainParts:
+ virtual void ToolkitInitialized() OVERRIDE;
+ virtual void PostMainMessageLoopRun() OVERRIDE;
+
+ private:
+ scoped_ptr< ::wm::WMState> wm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainPartsAura);
+};
+
+} // namespace ui
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_CLIENT_MAIN_PARTS_AURA_H_
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_chromeos.cc b/chromium/ui/views_content_client/views_content_client_main_parts_chromeos.cc
new file mode 100644
index 00000000000..b1ba000db33
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_chromeos.cc
@@ -0,0 +1,102 @@
+// 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 "content/public/browser/context_factory.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/screen.h"
+#include "ui/views_content_client/views_content_client.h"
+#include "ui/views_content_client/views_content_client_main_parts_aura.h"
+#include "ui/wm/core/nested_accelerator_controller.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+#include "ui/wm/test/wm_test_helper.h"
+
+namespace ui {
+
+namespace {
+
+// A dummy version of the delegate usually provided by the Ash Shell.
+class NestedAcceleratorDelegate : public ::wm::NestedAcceleratorDelegate {
+ public:
+ NestedAcceleratorDelegate() {}
+ virtual ~NestedAcceleratorDelegate() {}
+
+ // ::wm::NestedAcceleratorDelegate:
+ virtual Result ProcessAccelerator(
+ const ui::Accelerator& accelerator) OVERRIDE {
+ return RESULT_NOT_PROCESSED;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDelegate);
+};
+
+class ViewsContentClientMainPartsChromeOS
+ : public ViewsContentClientMainPartsAura {
+ public:
+ ViewsContentClientMainPartsChromeOS(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+ virtual ~ViewsContentClientMainPartsChromeOS() {}
+
+ // content::BrowserMainParts:
+ virtual void PreMainMessageLoopRun() OVERRIDE;
+ virtual void PostMainMessageLoopRun() OVERRIDE;
+
+ private:
+ // Enable a minimal set of views::corewm to be initialized.
+ scoped_ptr< ::wm::WMTestHelper> wm_test_helper_;
+ scoped_ptr< ::wm::NestedAcceleratorController> nested_accelerator_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainPartsChromeOS);
+};
+
+ViewsContentClientMainPartsChromeOS::ViewsContentClientMainPartsChromeOS(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client)
+ : ViewsContentClientMainPartsAura(content_params, views_content_client) {
+}
+
+void ViewsContentClientMainPartsChromeOS::PreMainMessageLoopRun() {
+ ViewsContentClientMainPartsAura::PreMainMessageLoopRun();
+
+ gfx::Size host_size(800, 600);
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
+ aura::TestScreen::Create(host_size));
+ // Set up basic pieces of views::corewm.
+ wm_test_helper_.reset(
+ new ::wm::WMTestHelper(host_size, content::GetContextFactory()));
+ // Ensure the X window gets mapped.
+ wm_test_helper_->host()->Show();
+
+ // Ensure Aura knows where to open new windows.
+ aura::Window* root_window = wm_test_helper_->host()->window();
+ views_content_client()->task().Run(browser_context(), root_window);
+
+ nested_accelerator_controller_.reset(
+ new ::wm::NestedAcceleratorController(new NestedAcceleratorDelegate));
+ aura::client::SetDispatcherClient(root_window,
+ nested_accelerator_controller_.get());
+}
+
+void ViewsContentClientMainPartsChromeOS::PostMainMessageLoopRun() {
+ aura::client::SetDispatcherClient(wm_test_helper_->host()->window(), NULL);
+ nested_accelerator_controller_.reset();
+ wm_test_helper_.reset();
+
+ ViewsContentClientMainPartsAura::PostMainMessageLoopRun();
+}
+
+} // namespace
+
+// static
+ViewsContentClientMainParts* ViewsContentClientMainParts::Create(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client) {
+ return new ViewsContentClientMainPartsChromeOS(
+ content_params, views_content_client);
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc b/chromium/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc
new file mode 100644
index 00000000000..ec8b75bed2e
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc
@@ -0,0 +1,57 @@
+// 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 "content/shell/browser/shell_browser_context.h"
+#include "ui/aura/env.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views_content_client/views_content_client.h"
+#include "ui/views_content_client/views_content_client_main_parts_aura.h"
+
+namespace ui {
+
+namespace {
+
+class ViewsContentClientMainPartsDesktopAura
+ : public ViewsContentClientMainPartsAura {
+ public:
+ ViewsContentClientMainPartsDesktopAura(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+ virtual ~ViewsContentClientMainPartsDesktopAura() {}
+
+ // content::BrowserMainParts:
+ virtual void PreMainMessageLoopRun() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainPartsDesktopAura);
+};
+
+ViewsContentClientMainPartsDesktopAura::ViewsContentClientMainPartsDesktopAura(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client)
+ : ViewsContentClientMainPartsAura(content_params, views_content_client) {
+}
+
+void ViewsContentClientMainPartsDesktopAura::PreMainMessageLoopRun() {
+ ViewsContentClientMainPartsAura::PreMainMessageLoopRun();
+
+ aura::Env::CreateInstance(true);
+ gfx::Screen::SetScreenInstance(
+ gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
+
+ views_content_client()->task().Run(browser_context(), NULL);
+}
+
+} // namespace
+
+// static
+ViewsContentClientMainParts* ViewsContentClientMainParts::Create(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client) {
+ return new ViewsContentClientMainPartsDesktopAura(
+ content_params, views_content_client);
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm b/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm
new file mode 100644
index 00000000000..8d2f12bcf8c
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_client_main_parts_mac.mm
@@ -0,0 +1,55 @@
+// 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 "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/common/content_paths.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "ui/views_content_client/views_content_client.h"
+#include "ui/views_content_client/views_content_client_main_parts.h"
+
+namespace ui {
+
+namespace {
+
+class ViewsContentClientMainPartsMac : public ViewsContentClientMainParts {
+ public:
+ ViewsContentClientMainPartsMac(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client);
+ virtual ~ViewsContentClientMainPartsMac() {}
+
+ // content::BrowserMainParts:
+ virtual void PreMainMessageLoopRun() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainPartsMac);
+};
+
+ViewsContentClientMainPartsMac::ViewsContentClientMainPartsMac(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client)
+ : ViewsContentClientMainParts(content_params, views_content_client) {
+ // Cache the child process path to avoid triggering an AssertIOAllowed.
+ base::FilePath child_process_exe;
+ PathService::Get(content::CHILD_PROCESS_EXE, &child_process_exe);
+}
+
+void ViewsContentClientMainPartsMac::PreMainMessageLoopRun() {
+ ViewsContentClientMainParts::PreMainMessageLoopRun();
+
+ views_content_client()->task().Run(browser_context(), NULL);
+}
+
+} // namespace
+
+// static
+ViewsContentClientMainParts* ViewsContentClientMainParts::Create(
+ const content::MainFunctionParams& content_params,
+ ViewsContentClient* views_content_client) {
+ return
+ new ViewsContentClientMainPartsMac(content_params, views_content_client);
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_main_delegate.cc b/chromium/ui/views_content_client/views_content_main_delegate.cc
new file mode 100644
index 00000000000..1fb3a6913e1
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_main_delegate.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views_content_client/views_content_main_delegate.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "content/public/common/content_switches.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/views_content_client/views_content_browser_client.h"
+
+#if defined(OS_WIN)
+#include "base/logging_win.h"
+#endif
+
+namespace ui {
+namespace {
+
+#if defined(OS_WIN)
+// {83FAC8EE-7A0E-4dbb-A3F6-6F500D7CAB1A}
+const GUID kViewsContentClientProviderName =
+ { 0x83fac8ee, 0x7a0e, 0x4dbb,
+ { 0xa3, 0xf6, 0x6f, 0x50, 0xd, 0x7c, 0xab, 0x1a } };
+#endif
+
+} // namespace
+
+ViewsContentMainDelegate::ViewsContentMainDelegate(
+ ViewsContentClient* views_content_client)
+ : views_content_client_(views_content_client) {
+}
+
+ViewsContentMainDelegate::~ViewsContentMainDelegate() {
+}
+
+bool ViewsContentMainDelegate::BasicStartupComplete(int* exit_code) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ std::string process_type =
+ command_line.GetSwitchValueASCII(switches::kProcessType);
+
+ content::SetContentClient(&content_client_);
+
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ bool success = logging::InitLogging(settings);
+ CHECK(success);
+#if defined(OS_WIN)
+ logging::LogEventProvider::Initialize(kViewsContentClientProviderName);
+#endif
+
+ return false;
+}
+
+void ViewsContentMainDelegate::PreSandboxStartup() {
+ base::FilePath ui_test_pak_path;
+ DCHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
+
+ // Load content resources to provide, e.g., sandbox configuration data on Mac.
+ base::FilePath content_resources_pak_path;
+ PathService::Get(base::DIR_MODULE, &content_resources_pak_path);
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ content_resources_pak_path.AppendASCII("content_resources.pak"),
+ ui::SCALE_FACTOR_100P);
+}
+
+content::ContentBrowserClient*
+ ViewsContentMainDelegate::CreateContentBrowserClient() {
+ browser_client_.reset(new ViewsContentBrowserClient(views_content_client_));
+ return browser_client_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/views_content_client/views_content_main_delegate.h b/chromium/ui/views_content_client/views_content_main_delegate.h
new file mode 100644
index 00000000000..f56eece6e31
--- /dev/null
+++ b/chromium/ui/views_content_client/views_content_main_delegate.h
@@ -0,0 +1,38 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_MAIN_DELEGATE_H_
+#define UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_MAIN_DELEGATE_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/app/content_main_delegate.h"
+#include "content/shell/common/shell_content_client.h"
+
+namespace ui {
+
+class ViewsContentBrowserClient;
+class ViewsContentClient;
+
+class ViewsContentMainDelegate : public content::ContentMainDelegate {
+ public:
+ explicit ViewsContentMainDelegate(ViewsContentClient* views_content_client);
+ virtual ~ViewsContentMainDelegate();
+
+ // content::ContentMainDelegate implementation
+ virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
+ virtual void PreSandboxStartup() OVERRIDE;
+ virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
+
+ private:
+ scoped_ptr<ViewsContentBrowserClient> browser_client_;
+ content::ShellContentClient content_client_;
+ ViewsContentClient* views_content_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewsContentMainDelegate);
+};
+
+} // namespace ui
+
+#endif // UI_VIEWS_CONTENT_CLIENT_VIEWS_CONTENT_MAIN_DELEGATE_H_
diff --git a/chromium/ui/web_dialogs/DEPS b/chromium/ui/web_dialogs/DEPS
index a2fe7393ea4..fb76c164df9 100644
--- a/chromium/ui/web_dialogs/DEPS
+++ b/chromium/ui/web_dialogs/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+content/public",
+ "+third_party/WebKit/public/web/WebInputEvent.h",
"+ui/base",
"+ui/gfx",
]
diff --git a/chromium/ui/web_dialogs/web_dialog_delegate.cc b/chromium/ui/web_dialogs/web_dialog_delegate.cc
index d3688e04cbe..e1191f6382d 100644
--- a/chromium/ui/web_dialogs/web_dialog_delegate.cc
+++ b/chromium/ui/web_dialogs/web_dialog_delegate.cc
@@ -18,6 +18,10 @@ bool WebDialogDelegate::CanCloseDialog() const {
return true;
}
+bool WebDialogDelegate::CanResizeDialog() const {
+ return true;
+}
+
void WebDialogDelegate::OnDialogCloseFromWebUI(
const std::string& json_retval) {
OnDialogClosed(json_retval);
diff --git a/chromium/ui/web_dialogs/web_dialog_delegate.h b/chromium/ui/web_dialogs/web_dialog_delegate.h
index 2bd772f018e..ccfd26ef982 100644
--- a/chromium/ui/web_dialogs/web_dialog_delegate.h
+++ b/chromium/ui/web_dialogs/web_dialog_delegate.h
@@ -69,6 +69,10 @@ class WEB_DIALOGS_EXPORT WebDialogDelegate {
// agreement, etc.
virtual bool CanCloseDialog() const;
+ // Returns true if the dialog can ever be resized. Default implementation
+ // returns |true|.
+ virtual bool CanResizeDialog() const;
+
// A callback to notify the delegate that |source|'s loading state has
// changed.
virtual void OnLoadingStateChanged(content::WebContents* source) {}
@@ -86,7 +90,7 @@ class WEB_DIALOGS_EXPORT WebDialogDelegate {
virtual void OnDialogClosed(const std::string& json_retval) = 0;
// A callback to notify the delegate that the dialog is being closed in
- // response to a "DialogClose" message from WebUI.
+ // response to a "dialogClose" message from WebUI.
virtual void OnDialogCloseFromWebUI(const std::string& json_retval);
// A callback to notify the delegate that the contents have gone
diff --git a/chromium/ui/web_dialogs/web_dialog_ui.cc b/chromium/ui/web_dialogs/web_dialog_ui.cc
index 6c978c2a717..161af45c044 100644
--- a/chromium/ui/web_dialogs/web_dialog_ui.cc
+++ b/chromium/ui/web_dialogs/web_dialog_ui.cc
@@ -79,7 +79,7 @@ WebDialogDelegate* WebDialogUI::GetDelegate(
void WebDialogUI::RenderViewCreated(RenderViewHost* render_view_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",
+ web_ui()->RegisterMessageCallback("dialogClose",
base::Bind(&WebDialogUI::OnDialogClosed, base::Unretained(this)));
// Pass the arguments to the renderer supplied by the delegate.
@@ -102,7 +102,7 @@ void WebDialogUI::RenderViewCreated(RenderViewHost* render_view_host) {
delegate->OnDialogShown(web_ui(), render_view_host);
}
-void WebDialogUI::OnDialogClosed(const ListValue* args) {
+void WebDialogUI::OnDialogClosed(const base::ListValue* args) {
WebDialogDelegate* delegate = GetDelegate(web_ui()->GetWebContents());
if (delegate) {
std::string json_retval;
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 4a3f0dff2df..ea0006ae79d 100644
--- a/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc
+++ b/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "content/public/browser/web_contents.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
using content::BrowserContext;
using content::OpenURLParams;
@@ -55,4 +56,13 @@ bool WebDialogWebContentsDelegate::IsPopupOrPanel(
return true;
}
+bool WebDialogWebContentsDelegate::PreHandleGestureEvent(
+ WebContents* source,
+ const blink::WebGestureEvent& event) {
+ // Disable pinch zooming.
+ return event.type == blink::WebGestureEvent::GesturePinchBegin ||
+ event.type == blink::WebGestureEvent::GesturePinchUpdate ||
+ event.type == blink::WebGestureEvent::GesturePinchEnd;
+}
+
} // namespace ui
diff --git a/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.h b/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.h
index 65d514ae3b7..50b4a65858b 100644
--- a/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.h
+++ b/chromium/ui/web_dialogs/web_dialog_web_contents_delegate.h
@@ -56,7 +56,6 @@ class WEB_DIALOGS_EXPORT WebDialogWebContentsDelegate
virtual content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) OVERRIDE;
-
virtual void AddNewContents(content::WebContents* source,
content::WebContents* new_contents,
WindowOpenDisposition disposition,
@@ -65,6 +64,9 @@ class WEB_DIALOGS_EXPORT WebDialogWebContentsDelegate
bool* was_blocked) OVERRIDE;
virtual bool IsPopupOrPanel(
const content::WebContents* source) const OVERRIDE;
+ virtual bool PreHandleGestureEvent(
+ content::WebContents* source,
+ const blink::WebGestureEvent& event) OVERRIDE;
private:
// Weak pointer. Always an original profile.
diff --git a/chromium/ui/webui/DEPS b/chromium/ui/webui/DEPS
index e781c4af1f8..69b82adcf09 100644
--- a/chromium/ui/webui/DEPS
+++ b/chromium/ui/webui/DEPS
@@ -1,6 +1,4 @@
include_rules = [
- "+grit/app_locale_settings.h",
- "+grit/webui_resources.h",
"+net",
"+ui/base",
"+ui/gfx",
diff --git a/chromium/ui/webui/OWNERS b/chromium/ui/webui/OWNERS
index 56e1ae76197..29391dbffa7 100644
--- a/chromium/ui/webui/OWNERS
+++ b/chromium/ui/webui/OWNERS
@@ -7,6 +7,3 @@ jhawkins@chromium.org
nkostylev@chromium.org
pam@chromium.org
xiyuan@chromium.org
-
-# temporarily for refactoring. http://crbug.com/169170
-jam@chromium.org
diff --git a/chromium/ui/webui/resources/BUILD.gn b/chromium/ui/webui/resources/BUILD.gn
new file mode 100644
index 00000000000..7b0001bb374
--- /dev/null
+++ b/chromium/ui/webui/resources/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//tools/grit/grit_rule.gni")
+
+grit("resources") {
+ output_name = "webui_resources"
+ source = "webui_resources.grd"
+}
diff --git a/chromium/ui/webui/resources/css/bubble_button.css b/chromium/ui/webui/resources/css/bubble_button.css
index 5f37ed20706..f12fc6e29be 100644
--- a/chromium/ui/webui/resources/css/bubble_button.css
+++ b/chromium/ui/webui/resources/css/bubble_button.css
@@ -4,6 +4,7 @@
*/
.bubble-button {
+ -webkit-margin-start: 4px;
display: inline-block;
height: 0;
line-height: 1;
@@ -15,6 +16,6 @@
background-size: 16px;
height: 16px;
position: relative;
- top: -8px;
+ top: -9px;
width: 16px;
}
diff --git a/chromium/ui/webui/resources/css/chrome_shared.css b/chromium/ui/webui/resources/css/chrome_shared.css
index 3f1ebbd05bc..c5dc338bf8d 100644
--- a/chromium/ui/webui/resources/css/chrome_shared.css
+++ b/chromium/ui/webui/resources/css/chrome_shared.css
@@ -6,7 +6,7 @@
* chrome:// pages. */
@import url("widgets.css");
-<if expr="pp_ifdef('chromeos')">
+<if expr="chromeos">
@import url("chromeos/ui_account_tweaks.css");
</if>
diff --git a/chromium/ui/webui/resources/css/overlay.css b/chromium/ui/webui/resources/css/overlay.css
index 5bf914cff52..6623e870332 100644
--- a/chromium/ui/webui/resources/css/overlay.css
+++ b/chromium/ui/webui/resources/css/overlay.css
@@ -7,6 +7,8 @@
-webkit-box-align: center;
-webkit-box-orient: vertical;
-webkit-box-pack: center;
+ /* TODO(dbeam): remove perspective when http://crbug.com/374970 is fixed. */
+ -webkit-perspective: 1px;
-webkit-transition: 200ms opacity;
background-color: rgba(255, 255, 255, 0.75);
bottom: 0;
diff --git a/chromium/ui/webui/resources/css/table.css b/chromium/ui/webui/resources/css/table.css
index 92581978295..1d59b7a9e05 100644
--- a/chromium/ui/webui/resources/css/table.css
+++ b/chromium/ui/webui/resources/css/table.css
@@ -6,17 +6,17 @@ html.col-resize * {
cursor: col-resize !important;
}
-.table[hasElementFocus] > list > [lead] {
+.table[has-element-focus] > list > [lead] {
border-color: hsl(214, 91%, 65%);
z-index: 2;
}
-.table[hasElementFocus] > list > [selected] {
+.table[has-element-focus] > list > [selected] {
background-color: hsl(214,91%,89%);
border-color: hsl(214, 91%, 65%);
}
-.table[hasElementFocus] > list > [lead][selected],
+.table[has-element-focus] > list > [lead][selected],
list > [selected]:hover {
background-color: hsl(214, 91%, 87%);
border-color: hsl(214, 91%, 65%);
diff --git a/chromium/ui/webui/resources/images/1.5x/laptop.png b/chromium/ui/webui/resources/images/1.5x/laptop.png
deleted file mode 100644
index c830440341c..00000000000
--- a/chromium/ui/webui/resources/images/1.5x/laptop.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/1.5x/phone.png b/chromium/ui/webui/resources/images/1.5x/phone.png
deleted file mode 100644
index 6120860d761..00000000000
--- a/chromium/ui/webui/resources/images/1.5x/phone.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/1.5x/tablet.png b/chromium/ui/webui/resources/images/1.5x/tablet.png
deleted file mode 100644
index 7ecb245ef94..00000000000
--- a/chromium/ui/webui/resources/images/1.5x/tablet.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/2x/apps/button_butter_bar_close_pressed.png b/chromium/ui/webui/resources/images/2x/apps/button_butter_bar_close_pressed.png
index 861a31e061c..6a93b4e5f12 100644
--- a/chromium/ui/webui/resources/images/2x/apps/button_butter_bar_close_pressed.png
+++ b/chromium/ui/webui/resources/images/2x/apps/button_butter_bar_close_pressed.png
Binary files differ
diff --git a/chromium/ui/webui/resources/images/2x/laptop.png b/chromium/ui/webui/resources/images/2x/laptop.png
deleted file mode 100644
index b979bb836b9..00000000000
--- a/chromium/ui/webui/resources/images/2x/laptop.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/2x/phone.png b/chromium/ui/webui/resources/images/2x/phone.png
deleted file mode 100644
index 7e9860a2cdd..00000000000
--- a/chromium/ui/webui/resources/images/2x/phone.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/2x/tablet.png b/chromium/ui/webui/resources/images/2x/tablet.png
deleted file mode 100644
index 0549ac88829..00000000000
--- a/chromium/ui/webui/resources/images/2x/tablet.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/apps/button_butter_bar_close_hover.png b/chromium/ui/webui/resources/images/apps/button_butter_bar_close_hover.png
index f28de8c18f7..906436343a4 100644
--- a/chromium/ui/webui/resources/images/apps/button_butter_bar_close_hover.png
+++ b/chromium/ui/webui/resources/images/apps/button_butter_bar_close_hover.png
Binary files differ
diff --git a/chromium/ui/webui/resources/images/gear.png b/chromium/ui/webui/resources/images/gear.png
index 1640c82b42d..7733e94a484 100644
--- a/chromium/ui/webui/resources/images/gear.png
+++ b/chromium/ui/webui/resources/images/gear.png
Binary files differ
diff --git a/chromium/ui/webui/resources/images/laptop.png b/chromium/ui/webui/resources/images/laptop.png
deleted file mode 100644
index 4ffd683d5d0..00000000000
--- a/chromium/ui/webui/resources/images/laptop.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/phone.png b/chromium/ui/webui/resources/images/phone.png
deleted file mode 100644
index aa37449ae86..00000000000
--- a/chromium/ui/webui/resources/images/phone.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/images/plus.png b/chromium/ui/webui/resources/images/plus.png
index 49e1fd0b09b..a3d8a72e308 100644
--- a/chromium/ui/webui/resources/images/plus.png
+++ b/chromium/ui/webui/resources/images/plus.png
Binary files differ
diff --git a/chromium/ui/webui/resources/images/tablet.png b/chromium/ui/webui/resources/images/tablet.png
deleted file mode 100644
index 3b123d6ebc3..00000000000
--- a/chromium/ui/webui/resources/images/tablet.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/webui/resources/js/cr/promise.js b/chromium/ui/webui/resources/js/cr/promise.js
deleted file mode 100644
index f0681c123c9..00000000000
--- a/chromium/ui/webui/resources/js/cr/promise.js
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview This implementes a future promise class.
- */
-
-cr.define('cr', function() {
-
- /**
- * Sentinel used to mark a value as pending.
- * @const
- */
- var PENDING_VALUE = {};
-
- /**
- * Creates a future promise.
- * @param {*=} opt_value The value to set the promise to. If set completes
- * the promise immediately.
- * @constructor
- */
- function Promise(opt_value) {
- /**
- * An array of the callbacks.
- * @type {!Array.<!Function>}
- * @private
- */
- this.callbacks_ = [];
-
- if (arguments.length > 0)
- this.value = opt_value;
- }
-
- Promise.prototype = {
- /**
- * The current value.
- * @type {*}
- * @private
- */
- value_: PENDING_VALUE,
-
- /**
- * The value of the future promise. Accessing this before the promise has
- * been fulfilled will throw an error. If this is set to an exception
- * accessing this will throw as well.
- * @type {*}
- */
- get value() {
- return this.done ? this.value_ : undefined;
- },
- set value(value) {
- if (!this.done) {
- this.value_ = value;
- for (var i = 0; i < this.callbacks_.length; i++) {
- this.callbacks_[i].call(null, value);
- }
- this.callbacks_.length = 0;
- }
- },
-
- /**
- * Whether the future promise has been fulfilled.
- * @type {boolean}
- */
- get done() {
- return this.value_ !== PENDING_VALUE;
- },
-
- /**
- * Adds a listener to the future promise. The function will be called when
- * the promise is fulfilled. If the promise is already fullfilled this will
- * never call the function.
- * @param {!Function} fun The function to call.
- */
- addListener: function(fun) {
- if (this.done)
- fun(this.value);
- else
- this.callbacks_.push(fun);
- },
-
- /**
- * Removes a previously added listener from the future promise.
- * @param {!Function} fun The function to remove.
- */
- removeListener: function(fun) {
- var i = this.callbacks_.indexOf(fun);
- if (i >= 0)
- this.callbacks_.splice(i, 1);
- },
-
- /**
- * If the promise is done then this returns the string representation of
- * the value.
- * @return {string} The string representation of the promise.
- * @override
- */
- toString: function() {
- if (this.done)
- return String(this.value);
- else
- return '[object Promise]';
- },
-
- /**
- * Override to allow arithmetic.
- * @override
- */
- valueOf: function() {
- return this.value;
- }
- };
-
- /**
- * When a future promise is done call {@code fun}. This also calls the
- * function if the promise has already been fulfilled.
- * @param {!Promise} p The promise.
- * @param {!Function} fun The function to call when the promise is fulfilled.
- */
- Promise.when = function(p, fun) {
- p.addListener(fun);
- };
-
- /**
- * Creates a new promise the will be fulfilled after {@code t} ms.
- * @param {number} t The time to wait before the promise is fulfilled.
- * @param {*=} opt_value The value to return after the wait.
- * @return {!Promise} The new future promise.
- */
- Promise.wait = function(t, opt_value) {
- var p = new Promise;
- window.setTimeout(function() {
- p.value = opt_value;
- }, t);
- return p;
- };
-
- /**
- * Creates a new future promise that is fulfilled when any of the promises are
- * fulfilled. The value of the returned promise will be the value of the first
- * fulfilled promise.
- * @param {...!Promise} var_args The promises used to build up the new
- * promise.
- * @return {!Promise} The new promise that will be fulfilled when any of the
- * passed in promises are fulfilled.
- */
- Promise.any = function(var_args) {
- var p = new Promise;
- function f(v) {
- p.value = v;
- }
- for (var i = 0; i < arguments.length; i++) {
- arguments[i].addListener(f);
- }
- return p;
- };
-
- /**
- * Creates a new future promise that is fulfilled when all of the promises are
- * fulfilled. The value of the returned promise is an array of the values of
- * the promises passed in.
- * @param {...!Promise} var_args The promises used to build up the new
- * promise.
- * @return {!Promise} The promise that wraps all the promises in the array.
- */
- Promise.all = function(var_args) {
- var p = new Promise;
- var args = Array.prototype.slice.call(arguments);
- var count = args.length;
- if (!count) {
- p.value = [];
- return p;
- }
-
- function f(v) {
- count--;
- if (!count) {
- p.value = args.map(function(argP) {
- return argP.value;
- });
- }
- }
-
- // Do not use count here since count may be decremented in the call to
- // addListener if the promise is already done.
- for (var i = 0; i < args.length; i++) {
- args[i].addListener(f);
- }
-
- return p;
- };
-
- /**
- * Wraps an event in a future promise.
- * @param {!EventTarget} target The object that dispatches the event.
- * @param {string} type The type of the event.
- * @param {boolean=} opt_useCapture Whether to listen to the capture phase or
- * the bubble phase.
- * @return {!Promise} The promise that will be fulfilled when the event is
- * dispatched.
- */
- Promise.event = function(target, type, opt_useCapture) {
- var p = new Promise;
- target.addEventListener(type, function(e) {
- p.value = e;
- }, opt_useCapture);
- return p;
- };
-
- return {
- Promise: Promise
- };
-});
diff --git a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
index fdbdca932dd..f8d649ccb27 100644
--- a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
+++ b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js
@@ -213,6 +213,24 @@ cr.define('cr.ui', function() {
},
/**
+ * Updates the existing item with the new item.
+ *
+ * The existing item and the new item are regarded as the same item and the
+ * permutation tracks these indexes.
+ *
+ * @param {*} oldItem Old item that is contained in the model. If the item
+ * is not found in the model, the method call is just ignored.
+ * @param {*} newItem New item.
+ */
+ replaceItem: function(oldItem, newItem) {
+ var index = this.indexOf(oldItem);
+ if (index < 0)
+ return;
+ this.array_[this.indexes_[index]] = newItem;
+ this.updateIndex(index);
+ },
+
+ /**
* Use this to update a given item in the array. This does not remove and
* reinsert a new item.
* This dispatches a change event.
@@ -220,13 +238,28 @@ cr.define('cr.ui', function() {
* @param {number} index The index of the item to update.
*/
updateIndex: function(index) {
- if (index < 0 || index >= this.length)
- throw Error('Invalid index, ' + index);
+ this.updateIndexes([index]);
+ },
- // TODO(arv): Maybe unify splice and change events?
- var e = new Event('change');
- e.index = index;
- this.dispatchEvent(e);
+ /**
+ * Notifies of update of the items in the array. This does not remove and
+ * reinsert new items.
+ * This dispatches one or more change events.
+ * This runs sort after updating.
+ * @param {Array.<number>} indexes The index list of items to update.
+ */
+ updateIndexes: function(indexes) {
+ var isIndexesValid = indexes.every(function(index) {
+ return 0 <= index && index < this.length;
+ }, this);
+ if (!isIndexesValid)
+ throw Error('Invalid index, ' + indexes[i]);
+
+ for (var i = 0; i < indexes.length; i++) {
+ var e = new Event('change');
+ e.index = indexes[i];
+ this.dispatchEvent(e);
+ }
if (this.sortStatus.field) {
var status = this.sortStatus;
diff --git a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
index 1a23019c054..710856b1528 100644
--- a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -50,6 +50,7 @@ cr.define('cr.ui', function() {
var win = doc.defaultView;
this.showingEvents_.add(doc, 'keydown', this, true);
this.showingEvents_.add(doc, 'mousedown', this, true);
+ this.showingEvents_.add(doc, 'touchstart', this, true);
this.showingEvents_.add(doc, 'focus', this);
this.showingEvents_.add(win, 'popstate', this);
this.showingEvents_.add(win, 'resize', this);
@@ -155,6 +156,12 @@ cr.define('cr.ui', function() {
else
e.preventDefault();
break;
+
+ case 'touchstart':
+ if (!this.menu.contains(e.target))
+ this.hideMenu();
+ break;
+
case 'keydown':
// keyIdentifier does not report 'Esc' correctly
if (e.keyCode == 27 /* Esc */) {
diff --git a/chromium/ui/webui/resources/js/cr/ui/dialogs.js b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
index ee9125fb7a8..3a3456fbca7 100644
--- a/chromium/ui/webui/resources/js/cr/ui/dialogs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
@@ -66,22 +66,22 @@ cr.define('cr.ui.dialogs', function() {
this.text_.className = 'cr-dialog-text';
this.frame_.appendChild(this.text_);
- var buttons = doc.createElement('div');
- buttons.className = 'cr-dialog-buttons';
- this.frame_.appendChild(buttons);
+ this.buttons = doc.createElement('div');
+ this.buttons.className = 'cr-dialog-buttons';
+ this.frame_.appendChild(this.buttons);
this.okButton_ = doc.createElement('button');
this.okButton_.className = 'cr-dialog-ok';
this.okButton_.textContent = BaseDialog.OK_LABEL;
this.okButton_.addEventListener('click', this.onOkClick_.bind(this));
- buttons.appendChild(this.okButton_);
+ this.buttons.appendChild(this.okButton_);
this.cancelButton_ = doc.createElement('button');
this.cancelButton_.className = 'cr-dialog-cancel';
this.cancelButton_.textContent = BaseDialog.CANCEL_LABEL;
this.cancelButton_.addEventListener('click',
this.onCancelClick_.bind(this));
- buttons.appendChild(this.cancelButton_);
+ this.buttons.appendChild(this.cancelButton_);
this.initialFocusElement_ = this.okButton_;
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_manager.js b/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
index ff8fe491a80..ae5f3c8f6e7 100644
--- a/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
+++ b/chromium/ui/webui/resources/js/cr/ui/focus_manager.js
@@ -218,6 +218,8 @@ cr.define('cr.ui', function() {
*/
FocusManager.disableMouseFocusOnButtons = function() {
document.addEventListener('mousedown', function(event) {
+ if (event.defaultPrevented)
+ return;
var node = event.target;
var tagName = node.tagName;
if (tagName != 'BUTTON' && tagName != 'INPUT') {
diff --git a/chromium/ui/webui/resources/js/cr/ui/list.js b/chromium/ui/webui/resources/js/cr/ui/list.js
index 1dc38b6dc2f..91df98de534 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list.js
@@ -314,6 +314,7 @@ cr.define('cr.ui', function() {
this.addEventListener('dblclick', this.handleDoubleClick_);
this.addEventListener('mousedown', handleMouseDown);
+ this.addEventListener('dragstart', handleDragStart, true);
this.addEventListener('mouseup', this.handlePointerDownUp_);
this.addEventListener('keydown', this.handleKeyDown);
this.addEventListener('focus', this.handleElementFocus_, true);
@@ -631,6 +632,7 @@ cr.define('cr.ui', function() {
}
}
this.cachedItems_ = newCachedItems;
+ this.pinnedItem_ = null;
var newCachedItemHeights = {};
for (var index in this.cachedItemHeights_) {
@@ -1120,14 +1122,11 @@ cr.define('cr.ui', function() {
// We don't set the lead or selected properties until after adding all
// items, in case they force relayout in response to these events.
- var listItem = null;
if (leadIndex != -1 && this.cachedItems_[leadIndex])
this.cachedItems_[leadIndex].lead = true;
for (var y = firstIndex; y < lastIndex; y++) {
- if (sm.getIndexSelected(y))
- this.cachedItems_[y].selected = true;
- else if (y != leadIndex)
- listItem = this.cachedItems_[y];
+ if (sm.getIndexSelected(y) != this.cachedItems_[y].selected)
+ this.cachedItems_[y].selected = !this.cachedItems_[y].selected;
}
this.firstIndex_ = firstIndex;
@@ -1305,6 +1304,28 @@ cr.define('cr.ui', function() {
}
/**
+ * Dragstart event handler.
+ * If there is an item at starting position of drag operation and the item
+ * is not selected, select it.
+ * @this {List}
+ * @param {MouseEvent} e The event object for 'dragstart'.
+ */
+ function handleDragStart(e) {
+ var element = e.target.ownerDocument.elementFromPoint(e.clientX, e.clientY);
+ var listItem = this.getListItemAncestor(element);
+ if (!listItem)
+ return;
+
+ var index = this.getIndexOfListItem(listItem);
+ if (index == -1)
+ return;
+
+ var isAlreadySelected = this.selectionModel_.getIndexSelected(index);
+ if (!isAlreadySelected)
+ this.selectionModel_.selectedIndex = index;
+ }
+
+ /**
* Check if |start| or its ancestor under |root| is focusable.
* This is a helper for handleMouseDown.
* @param {!Element} start An element which we start to check.
diff --git a/chromium/ui/webui/resources/js/cr/ui/overlay.js b/chromium/ui/webui/resources/js/cr/ui/overlay.js
index 5c0acb2d3dd..67be7598ff7 100644
--- a/chromium/ui/webui/resources/js/cr/ui/overlay.js
+++ b/chromium/ui/webui/resources/js/cr/ui/overlay.js
@@ -80,7 +80,8 @@ cr.define('cr.ui.overlay', function() {
* height.
*/
function setMaxHeightAllPages() {
- var pages = document.querySelectorAll('.overlay .page');
+ var pages = document.querySelectorAll(
+ '.overlay .page:not(.not-resizable)');
var maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px';
for (var i = 0; i < pages.length; i++)
diff --git a/chromium/ui/webui/resources/js/cr/ui/tree.js b/chromium/ui/webui/resources/js/cr/ui/tree.js
index 3c12715d55d..04f978ebf72 100644
--- a/chromium/ui/webui/resources/js/cr/ui/tree.js
+++ b/chromium/ui/webui/resources/js/cr/ui/tree.js
@@ -201,9 +201,13 @@ cr.define('cr.ui', function() {
if (oldSelectedItem)
oldSelectedItem.selected = false;
- if (item)
+ if (item) {
item.selected = true;
-
+ if (item.id)
+ this.setAttribute('aria-activedescendant', item.id);
+ } else {
+ this.removeAttribute('aria-activedescendant');
+ }
cr.dispatchSimpleEvent(this, 'change');
}
},
@@ -231,6 +235,14 @@ cr.define('cr.ui', function() {
cr.defineProperty(Tree, 'iconVisibility', cr.PropertyKind.ATTR);
/**
+ * Incremental counter for an auto generated ID of the tree item. This will
+ * be incremented per element, so each element never share same ID.
+ *
+ * @type {number}
+ */
+ var treeItemAutoGeneratedIdCounter = 0;
+
+ /**
* This is used as a blueprint for new tree item elements.
* @type {!HTMLElement}
*/
@@ -253,7 +265,9 @@ cr.define('cr.ui', function() {
* @extends {HTMLElement}
*/
var TreeItem = cr.ui.define(function() {
- return treeItemProto.cloneNode(true);
+ var treeItem = treeItemProto.cloneNode(true);
+ treeItem.id = 'tree-item-autogen-id-' + treeItemAutoGeneratedIdCounter++;
+ return treeItem;
});
TreeItem.prototype = {
diff --git a/chromium/ui/webui/resources/js/util.js b/chromium/ui/webui/resources/js/util.js
index caf421e3851..8bf3059bed1 100644
--- a/chromium/ui/webui/resources/js/util.js
+++ b/chromium/ui/webui/resources/js/util.js
@@ -21,6 +21,25 @@ function $(id) {
}
/**
+ * Add an accessible message to the page that will be announced to
+ * users who have spoken feedback on, but will be invisible to all
+ * other users. It's removed right away so it doesn't clutter the DOM.
+ * @param {string} msg The text to be pronounced.
+ */
+function announceAccessibleMessage(msg) {
+ var element = document.createElement('div');
+ element.setAttribute('aria-live', 'polite');
+ element.style.position = 'relative';
+ element.style.left = '-9999px';
+ element.style.height = '0px';
+ element.innerText = msg;
+ document.body.appendChild(element);
+ window.setTimeout(function() {
+ document.body.removeChild(element);
+ }, 0);
+}
+
+/**
* Calls chrome.send with a callback and restores the original afterwards.
* @param {string} name The name of the message to send.
* @param {!Array} params The parameters to send.
@@ -75,6 +94,21 @@ function url(s) {
}
/**
+ * Returns the URL of the image, or an image set of URLs for the profile avatar.
+ * Default avatars have resources available for multiple scalefactors, whereas
+ * the GAIA profile image only comes in one size.
+
+ * @param {string} url The path of the image.
+ * @return {string} The url, or an image set of URLs of the avatar image.
+ */
+function getProfileAvatarIcon(path) {
+ var chromeThemePath = 'chrome://theme';
+ var isDefaultAvatar =
+ (path.slice(0, chromeThemePath.length) == chromeThemePath);
+ return isDefaultAvatar ? imageset(path + '@scalefactorx'): url(path);
+}
+
+/**
* Generates a CSS -webkit-image-set for a chrome:// url.
* An entry in the image set is added for each of getSupportedScaleFactors().
* The scale-factor-specific url is generated by replacing the first instance of
@@ -381,3 +415,31 @@ function scrollLeftForDocument(doc) {
function setScrollLeftForDocument(doc, value) {
doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
}
+
+/**
+ * Replaces '&', '<', '>', '"', and ''' characters with their HTML encoding.
+ * @param {string} original The original string.
+ * @return {string} The string with all the characters mentioned above replaced.
+ */
+function HTMLEscape(original) {
+ return original.replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;')
+ .replace(/'/g, '&#39;');
+}
+
+/**
+ * Shortens the provided string (if necessary) to a string of length at most
+ * |maxLength|.
+ * @param {string} original The original string.
+ * @param {number} maxLength The maximum length allowed for the string.
+ * @return {string} The original string if its length does not exceed
+ * |maxLength|. Otherwise the first |maxLength| - 1 characters with '...'
+ * appended.
+ */
+function elide(original, maxLength) {
+ if (original.length <= maxLength)
+ return original;
+ return original.substring(0, maxLength - 1) + '\u2026';
+}
diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd
index 7cc6c7c47d1..0df44239b0b 100644
--- a/chromium/ui/webui/resources/webui_resources.grd
+++ b/chromium/ui/webui/resources/webui_resources.grd
@@ -253,8 +253,6 @@ without changes to the corresponding grd file. -->
file="js/cr/event_target.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_CR_LINK_CONTROLLER"
file="js/cr/link_controller.js" type="chrome_html" />
- <structure name="IDR_WEBUI_JS_CR_PROMISE"
- file="js/cr/promise.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_CR_UI"
file="js/cr/ui.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_CR_UI_ALERT_OVERLAY"
@@ -343,19 +341,9 @@ without changes to the corresponding grd file. -->
file="js/cr/ui/touch_handler.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_EVENT_TRACKER"
file="js/event_tracker.js" type="chrome_html" />
- <structure name="IDR_WEBUI_JS_I18N_PROCESS"
- file="js/i18n_process.js" type="chrome_html" />
- <structure name="IDR_WEBUI_JS_I18N_TEMPLATE"
- file="js/i18n_template.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_I18N_TEMPLATE_NO_PROCESS"
file="js/i18n_template_no_process.js"
type="chrome_html" />
- <structure name="IDR_WEBUI_JS_I18N_TEMPLATE2"
- file="js/i18n_template2.js" type="chrome_html"
- flattenhtml="true" />
- <structure name="IDR_WEBUI_JS_JSTEMPLATE_COMPILED"
- file="js/jstemplate_compiled.js" type="chrome_html"
- flattenhtml="true" />
<structure name="IDR_WEBUI_JS_LOAD_TIME_DATA"
file="js/load_time_data.js" type="chrome_html" />
<structure name="IDR_WEBUI_JS_LOCAL_STRINGS"
@@ -368,7 +356,7 @@ without changes to the corresponding grd file. -->
file="js/util.js" type="chrome_html" flattenhtml="true" />
<structure name="IDR_WEBUI_JS_WEBUI_RESOURCE_TEST"
file="js/webui_resource_test.js" type="chrome_html" />
- <if expr="pp_ifdef('chromeos')">
+ <if expr="chromeos">
<structure name="IDR_WEBUI_CSS_UI_ACCOUNT_TWEAKS"
file="css/chromeos/ui_account_tweaks.css"
type="chrome_html" />
diff --git a/chromium/ui/wm/DEPS b/chromium/ui/wm/DEPS
new file mode 100644
index 00000000000..62fe7e28bef
--- /dev/null
+++ b/chromium/ui/wm/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+ui/aura",
+ "+ui/events",
+ "+ui/gfx",
+]
diff --git a/chromium/ui/wm/core/DEPS b/chromium/ui/wm/core/DEPS
new file mode 100644
index 00000000000..ddcff7e29ff
--- /dev/null
+++ b/chromium/ui/wm/core/DEPS
@@ -0,0 +1,16 @@
+include_rules = [
+ "+grit/ui_resources.h",
+ "+ui/aura",
+ "+ui/base/accelerators",
+ "+ui/base/cursor",
+ "+ui/base/hit_test.h",
+ "+ui/base/ime",
+ "+ui/base/resource",
+ "+ui/base/ui_base_switches_util.h",
+ "+ui/base/ui_base_types.h",
+ "+ui/compositor",
+ "+ui/events",
+ "+ui/gfx",
+ "+ui/views/views_export.h",
+ "+third_party/skia",
+]
diff --git a/chromium/ui/wm/core/accelerator_delegate.h b/chromium/ui/wm/core/accelerator_delegate.h
new file mode 100644
index 00000000000..886d7dba445
--- /dev/null
+++ b/chromium/ui/wm/core/accelerator_delegate.h
@@ -0,0 +1,33 @@
+// 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_WM_CORE_ACCELERATOR_DELEGATE_H_
+#define UI_WM_CORE_ACCELERATOR_DELEGATE_H_
+
+namespace ui {
+class Accelerator;
+class KeyEvent;
+}
+
+namespace wm {
+
+class AcceleratorDelegate {
+ public:
+ virtual ~AcceleratorDelegate() {}
+
+ // Type of keys that triggers accelerators.
+ enum KeyType {
+ KEY_TYPE_SYSTEM,
+ KEY_TYPE_OTHER,
+ };
+
+ // Return true if the |accelerator| has been processed.
+ virtual bool ProcessAccelerator(const ui::KeyEvent& event,
+ const ui::Accelerator& accelerator,
+ KeyType key_type) = 0;
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_ACCELERATOR_DELEGATE_H_
diff --git a/chromium/ui/wm/core/accelerator_filter.cc b/chromium/ui/wm/core/accelerator_filter.cc
new file mode 100644
index 00000000000..51c6106d91e
--- /dev/null
+++ b/chromium/ui/wm/core/accelerator_filter.cc
@@ -0,0 +1,80 @@
+// 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/wm/core/accelerator_filter.h"
+
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event.h"
+#include "ui/wm/core/accelerator_delegate.h"
+
+namespace wm {
+namespace {
+
+// Returns true if |key_code| is a key usually handled directly by the shell.
+bool IsSystemKey(ui::KeyboardCode key_code) {
+#if defined(OS_CHROMEOS)
+ switch (key_code) {
+ case ui::VKEY_MEDIA_LAUNCH_APP2: // Fullscreen button.
+ case ui::VKEY_MEDIA_LAUNCH_APP1: // Overview button.
+ case ui::VKEY_BRIGHTNESS_DOWN:
+ case ui::VKEY_BRIGHTNESS_UP:
+ case ui::VKEY_KBD_BRIGHTNESS_DOWN:
+ case ui::VKEY_KBD_BRIGHTNESS_UP:
+ case ui::VKEY_VOLUME_MUTE:
+ case ui::VKEY_VOLUME_DOWN:
+ case ui::VKEY_VOLUME_UP:
+ return true;
+ default:
+ return false;
+ }
+#endif // defined(OS_CHROMEOS)
+ return false;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorFilter, public:
+
+AcceleratorFilter::AcceleratorFilter(scoped_ptr<AcceleratorDelegate> delegate)
+ : delegate_(delegate.Pass()) {
+}
+
+AcceleratorFilter::~AcceleratorFilter() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorFilter, EventFilter implementation:
+
+void AcceleratorFilter::OnKeyEvent(ui::KeyEvent* event) {
+ const ui::EventType type = event->type();
+ DCHECK(event->target());
+ if ((type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
+ event->is_char() || !event->target()) {
+ return;
+ }
+
+ ui::Accelerator accelerator = CreateAcceleratorFromKeyEvent(*event);
+
+ AcceleratorDelegate::KeyType key_type =
+ IsSystemKey(event->key_code()) ? AcceleratorDelegate::KEY_TYPE_SYSTEM
+ : AcceleratorDelegate::KEY_TYPE_OTHER;
+
+ if (delegate_->ProcessAccelerator(*event, accelerator, key_type))
+ event->StopPropagation();
+}
+
+ui::Accelerator CreateAcceleratorFromKeyEvent(const ui::KeyEvent& key_event) {
+ const int kModifierFlagMask =
+ (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN);
+
+ ui::Accelerator accelerator(key_event.key_code(),
+ key_event.flags() & kModifierFlagMask);
+ if (key_event.type() == ui::ET_KEY_RELEASED)
+ accelerator.set_type(ui::ET_KEY_RELEASED);
+ accelerator.set_is_repeat(key_event.IsRepeat());
+ return accelerator;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/accelerator_filter.h b/chromium/ui/wm/core/accelerator_filter.h
new file mode 100644
index 00000000000..4e5295e098b
--- /dev/null
+++ b/chromium/ui/wm/core/accelerator_filter.h
@@ -0,0 +1,40 @@
+// 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_WM_CORE_ACCELERATOR_FILTER_H_
+#define UI_WM_CORE_ACCELERATOR_FILTER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/wm_export.h"
+
+namespace ui {
+class Accelerator;
+}
+
+namespace wm {
+class AcceleratorDelegate;
+
+// AcceleratorFilter filters key events for AcceleratorControler handling global
+// keyboard accelerators.
+class WM_EXPORT AcceleratorFilter : public ui::EventHandler {
+ public:
+ AcceleratorFilter(scoped_ptr<AcceleratorDelegate> delegate);
+ virtual ~AcceleratorFilter();
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+
+ private:
+ scoped_ptr<AcceleratorDelegate> delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(AcceleratorFilter);
+};
+
+ui::Accelerator CreateAcceleratorFromKeyEvent(const ui::KeyEvent& key_event);
+
+} // namespace wm
+
+#endif // UI_WM_CORE_ACCELERATOR_FILTER_H_
diff --git a/chromium/ui/wm/core/base_focus_rules.cc b/chromium/ui/wm/core/base_focus_rules.cc
new file mode 100644
index 00000000000..e7160b7b3fe
--- /dev/null
+++ b/chromium/ui/wm/core/base_focus_rules.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/base_focus_rules.h"
+
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/wm/core/window_modality_controller.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/activation_delegate.h"
+
+namespace wm {
+namespace {
+
+aura::Window* GetFocusedWindow(aura::Window* context) {
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(context);
+ return focus_client ? focus_client->GetFocusedWindow() : NULL;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// BaseFocusRules, protected:
+
+BaseFocusRules::BaseFocusRules() {
+}
+
+BaseFocusRules::~BaseFocusRules() {
+}
+
+bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
+ aura::Window* window) const {
+ return window->IsVisible();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BaseFocusRules, FocusRules implementation:
+
+bool BaseFocusRules::IsToplevelWindow(aura::Window* window) const {
+ // The window must in a valid hierarchy.
+ if (!window->GetRootWindow())
+ return false;
+
+ // The window must exist within a container that supports activation.
+ // The window cannot be blocked by a modal transient.
+ return SupportsChildActivation(window->parent());
+}
+
+bool BaseFocusRules::CanActivateWindow(aura::Window* window) const {
+ // It is possible to activate a NULL window, it is equivalent to clearing
+ // activation.
+ if (!window)
+ return true;
+
+ // Only toplevel windows can be activated.
+ if (!IsToplevelWindow(window))
+ return false;
+
+ // The window must be visible.
+ if (!IsWindowConsideredVisibleForActivation(window))
+ return false;
+
+ // The window's activation delegate must allow this window to be activated.
+ if (aura::client::GetActivationDelegate(window) &&
+ !aura::client::GetActivationDelegate(window)->ShouldActivate()) {
+ return false;
+ }
+
+ // A window must be focusable to be activatable. We don't call
+ // CanFocusWindow() from here because it will call back to us via
+ // GetActivatableWindow().
+ if (!window->CanFocus())
+ return false;
+
+ // The window cannot be blocked by a modal transient.
+ return !GetModalTransient(window);
+}
+
+bool BaseFocusRules::CanFocusWindow(aura::Window* window) const {
+ // It is possible to focus a NULL window, it is equivalent to clearing focus.
+ if (!window)
+ return true;
+
+ // The focused window is always inside the active window, so windows that
+ // aren't activatable can't contain the focused window.
+ aura::Window* activatable = GetActivatableWindow(window);
+ if (!activatable || !activatable->Contains(window))
+ return false;
+ return window->CanFocus();
+}
+
+aura::Window* BaseFocusRules::GetToplevelWindow(aura::Window* window) const {
+ aura::Window* parent = window->parent();
+ aura::Window* child = window;
+ while (parent) {
+ if (IsToplevelWindow(child))
+ return child;
+
+ parent = parent->parent();
+ child = child->parent();
+ }
+ return NULL;
+}
+
+aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
+ aura::Window* parent = window->parent();
+ aura::Window* child = window;
+ while (parent) {
+ if (CanActivateWindow(child))
+ return child;
+
+ // CanActivateWindow() above will return false if |child| is blocked by a
+ // modal transient. In this case the modal is or contains the activatable
+ // window. We recurse because the modal may itself be blocked by a modal
+ // transient.
+ aura::Window* modal_transient = GetModalTransient(child);
+ if (modal_transient)
+ return GetActivatableWindow(modal_transient);
+
+ if (wm::GetTransientParent(child)) {
+ // To avoid infinite recursion, if |child| has a transient parent
+ // whose own modal transient is |child| itself, just return |child|.
+ aura::Window* parent_modal_transient =
+ GetModalTransient(wm::GetTransientParent(child));
+ if (parent_modal_transient == child)
+ return child;
+
+ return GetActivatableWindow(wm::GetTransientParent(child));
+ }
+
+ parent = parent->parent();
+ child = child->parent();
+ }
+ return NULL;
+}
+
+aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const {
+ if (CanFocusWindow(window))
+ return window;
+
+ // |window| may be in a hierarchy that is non-activatable, in which case we
+ // need to cut over to the activatable hierarchy.
+ aura::Window* activatable = GetActivatableWindow(window);
+ if (!activatable) {
+ // There may not be a related activatable hierarchy to cut over to, in which
+ // case we try an unrelated one.
+ aura::Window* toplevel = GetToplevelWindow(window);
+ if (toplevel)
+ activatable = GetNextActivatableWindow(toplevel);
+ if (!activatable)
+ return NULL;
+ }
+
+ if (!activatable->Contains(window)) {
+ // If there's already a child window focused in the activatable hierarchy,
+ // just use that (i.e. don't shift focus), otherwise we need to at least cut
+ // over to the activatable hierarchy.
+ aura::Window* focused = GetFocusedWindow(activatable);
+ return activatable->Contains(focused) ? focused : activatable;
+ }
+
+ while (window && !CanFocusWindow(window))
+ window = window->parent();
+ return window;
+}
+
+aura::Window* BaseFocusRules::GetNextActivatableWindow(
+ aura::Window* ignore) const {
+ DCHECK(ignore);
+
+ // Can be called from the RootWindow's destruction, which has a NULL parent.
+ if (!ignore->parent())
+ return NULL;
+
+ // In the basic scenarios handled by BasicFocusRules, the pool of activatable
+ // windows is limited to the |ignore|'s siblings.
+ const aura::Window::Windows& siblings = ignore->parent()->children();
+ DCHECK(!siblings.empty());
+
+ for (aura::Window::Windows::const_reverse_iterator rit = siblings.rbegin();
+ rit != siblings.rend();
+ ++rit) {
+ aura::Window* cur = *rit;
+ if (cur == ignore)
+ continue;
+ if (CanActivateWindow(cur))
+ return cur;
+ }
+ return NULL;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/base_focus_rules.h b/chromium/ui/wm/core/base_focus_rules.h
new file mode 100644
index 00000000000..07dfb65fbc9
--- /dev/null
+++ b/chromium/ui/wm/core/base_focus_rules.h
@@ -0,0 +1,45 @@
+// 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_WM_CORE_BASE_FOCUS_RULES_H_
+#define UI_WM_CORE_BASE_FOCUS_RULES_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/wm/core/focus_rules.h"
+
+namespace wm {
+
+// A set of basic focus and activation rules. Specializations should most likely
+// subclass this and call up to these methods rather than reimplementing them.
+class WM_EXPORT BaseFocusRules : public FocusRules {
+ protected:
+ BaseFocusRules();
+ virtual ~BaseFocusRules();
+
+ // Returns true if the children of |window| can be activated.
+ virtual bool SupportsChildActivation(aura::Window* window) const = 0;
+
+ // Returns true if |window| is considered visible for activation purposes.
+ virtual bool IsWindowConsideredVisibleForActivation(
+ aura::Window* window) const;
+
+ // Overridden from FocusRules:
+ virtual bool IsToplevelWindow(aura::Window* window) const OVERRIDE;
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
+ virtual bool CanFocusWindow(aura::Window* window) const OVERRIDE;
+ virtual aura::Window* GetToplevelWindow(aura::Window* window) const OVERRIDE;
+ virtual aura::Window* GetActivatableWindow(
+ aura::Window* window) const OVERRIDE;
+ virtual aura::Window* GetFocusableWindow(aura::Window* window) const OVERRIDE;
+ virtual aura::Window* GetNextActivatableWindow(
+ aura::Window* ignore) const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BaseFocusRules);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_BASE_FOCUS_RULES_H_
diff --git a/chromium/ui/wm/core/capture_controller.cc b/chromium/ui/wm/core/capture_controller.cc
new file mode 100644
index 00000000000..b3d8620c05e
--- /dev/null
+++ b/chromium/ui/wm/core/capture_controller.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/capture_controller.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+
+namespace wm {
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, public:
+
+void CaptureController::Attach(aura::Window* root) {
+ DCHECK_EQ(0u, root_windows_.count(root));
+ root_windows_.insert(root);
+ aura::client::SetCaptureClient(root, this);
+}
+
+void CaptureController::Detach(aura::Window* root) {
+ root_windows_.erase(root);
+ aura::client::SetCaptureClient(root, NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, aura::client::CaptureClient implementation:
+
+void CaptureController::SetCapture(aura::Window* new_capture_window) {
+ if (capture_window_ == new_capture_window)
+ return;
+
+ // Make sure window has a root window.
+ DCHECK(!new_capture_window || new_capture_window->GetRootWindow());
+ DCHECK(!capture_window_ || capture_window_->GetRootWindow());
+
+ aura::Window* old_capture_window = capture_window_;
+ aura::Window* old_capture_root = old_capture_window ?
+ old_capture_window->GetRootWindow() : NULL;
+
+ // Copy the list in case it's modified out from under us.
+ RootWindows root_windows(root_windows_);
+
+ // If we're actually starting capture, then cancel any touches/gestures
+ // that aren't already locked to the new window, and transfer any on the
+ // old capture window to the new one. When capture is released we have no
+ // distinction between the touches/gestures that were in the window all
+ // along (and so shouldn't be canceled) and those that got moved, so
+ // just leave them all where they are.
+ if (new_capture_window) {
+ ui::GestureRecognizer::Get()->TransferEventsTo(old_capture_window,
+ new_capture_window);
+ }
+
+ capture_window_ = new_capture_window;
+
+ for (RootWindows::const_iterator i = root_windows.begin();
+ i != root_windows.end(); ++i) {
+ aura::client::CaptureDelegate* delegate = (*i)->GetHost()->dispatcher();
+ delegate->UpdateCapture(old_capture_window, new_capture_window);
+ }
+
+ aura::Window* capture_root =
+ capture_window_ ? capture_window_->GetRootWindow() : NULL;
+ if (capture_root != old_capture_root) {
+ if (old_capture_root) {
+ aura::client::CaptureDelegate* delegate =
+ old_capture_root->GetHost()->dispatcher();
+ delegate->ReleaseNativeCapture();
+ }
+ if (capture_root) {
+ aura::client::CaptureDelegate* delegate =
+ capture_root->GetHost()->dispatcher();
+ delegate->SetNativeCapture();
+ }
+ }
+}
+
+void CaptureController::ReleaseCapture(aura::Window* window) {
+ if (capture_window_ != window)
+ return;
+ SetCapture(NULL);
+}
+
+aura::Window* CaptureController::GetCaptureWindow() {
+ return capture_window_;
+}
+
+aura::Window* CaptureController::GetGlobalCaptureWindow() {
+ return capture_window_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, private:
+
+CaptureController::CaptureController()
+ : capture_window_(NULL) {
+}
+
+CaptureController::~CaptureController() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScopedCaptureClient:
+
+// static
+CaptureController* ScopedCaptureClient::capture_controller_ = NULL;
+
+ScopedCaptureClient::ScopedCaptureClient(aura::Window* root)
+ : root_window_(root) {
+ root->AddObserver(this);
+ if (!capture_controller_)
+ capture_controller_ = new CaptureController;
+ capture_controller_->Attach(root);
+}
+
+ScopedCaptureClient::~ScopedCaptureClient() {
+ Shutdown();
+}
+
+// static
+bool ScopedCaptureClient::IsActive() {
+ return capture_controller_ && capture_controller_->is_active();
+}
+
+void ScopedCaptureClient::OnWindowDestroyed(aura::Window* window) {
+ DCHECK_EQ(window, root_window_);
+ Shutdown();
+}
+
+void ScopedCaptureClient::Shutdown() {
+ if (!root_window_)
+ return;
+
+ root_window_->RemoveObserver(this);
+ capture_controller_->Detach(root_window_);
+ if (!capture_controller_->is_active()) {
+ delete capture_controller_;
+ capture_controller_ = NULL;
+ }
+ root_window_ = NULL;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/capture_controller.h b/chromium/ui/wm/core/capture_controller.h
new file mode 100644
index 00000000000..d8028183e29
--- /dev/null
+++ b/chromium/ui/wm/core/capture_controller.h
@@ -0,0 +1,86 @@
+// 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_WM_CORE_CAPTURE_CONTROLLER_H_
+#define UI_WM_CORE_CAPTURE_CONTROLLER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/window_observer.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+// Internal CaptureClient implementation. See ScopedCaptureClient for details.
+class WM_EXPORT CaptureController : public aura::client::CaptureClient {
+ public:
+ // Adds |root| to the list of RootWindows notified when capture changes.
+ void Attach(aura::Window* root);
+
+ // Removes |root| from the list of RootWindows notified when capture changes.
+ void Detach(aura::Window* root);
+
+ // Returns true if this CaptureController is installed on at least one
+ // RootWindow.
+ bool is_active() const { return !root_windows_.empty(); }
+
+ // Overridden from aura::client::CaptureClient:
+ virtual void SetCapture(aura::Window* window) OVERRIDE;
+ virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetCaptureWindow() OVERRIDE;
+ virtual aura::Window* GetGlobalCaptureWindow() OVERRIDE;
+
+ private:
+ friend class ScopedCaptureClient;
+ typedef std::set<aura::Window*> RootWindows;
+
+ CaptureController();
+ virtual ~CaptureController();
+
+ // The current capture window. NULL if there is no capture window.
+ aura::Window* capture_window_;
+
+ // Set of RootWindows notified when capture changes.
+ RootWindows root_windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(CaptureController);
+};
+
+// ScopedCaptureClient is responsible for creating a CaptureClient for a
+// RootWindow. Specifically it creates a single CaptureController that is shared
+// among all ScopedCaptureClients and adds the RootWindow to it.
+class WM_EXPORT ScopedCaptureClient : public aura::WindowObserver {
+ public:
+ explicit ScopedCaptureClient(aura::Window* root);
+ virtual ~ScopedCaptureClient();
+
+ // Returns true if there is a CaptureController with at least one RootWindow.
+ static bool IsActive();
+
+ aura::client::CaptureClient* capture_client() {
+ return capture_controller_;
+ }
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+ // Invoked from destructor and OnWindowDestroyed() to cleanup.
+ void Shutdown();
+
+ // The single CaptureController instance.
+ static CaptureController* capture_controller_;
+
+ // RootWindow this ScopedCaptureClient was create for.
+ aura::Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCaptureClient);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_CAPTURE_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/compound_event_filter.cc b/chromium/ui/wm/core/compound_event_filter.cc
new file mode 100644
index 00000000000..d1f652c02f6
--- /dev/null
+++ b/chromium/ui/wm/core/compound_event_filter.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/compound_event_filter.h"
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/base/hit_test.h"
+#include "ui/events/event.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/drag_drop_client.h"
+
+#if defined(OS_CHROMEOS) && defined(USE_X11)
+#include "ui/events/x/touch_factory_x11.h"
+#endif
+
+namespace wm {
+
+namespace {
+
+// Returns true if the cursor should be hidden on touch events.
+// TODO(tdanderson|rsadam): Move this function into CursorClient.
+bool ShouldHideCursorOnTouch(const ui::TouchEvent& event) {
+#if defined(OS_WIN)
+ return true;
+#elif defined(OS_CHROMEOS)
+#if defined(USE_X11)
+ int device_id = event.source_device_id();
+ if (device_id >= 0 &&
+ !ui::TouchFactory::GetInstance()->IsMultiTouchDevice(device_id)) {
+ // If the touch event is coming from a mouse-device (i.e. not a real
+ // touch-device), then do not hide the cursor.
+ return false;
+ }
+#endif // defined(USE_X11)
+ return true;
+#else
+ // Linux Aura does not hide the cursor on touch by default.
+ // TODO(tdanderson): Change this if having consistency across
+ // all platforms which use Aura is desired.
+ return false;
+#endif
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// CompoundEventFilter, public:
+
+CompoundEventFilter::CompoundEventFilter() {
+}
+
+CompoundEventFilter::~CompoundEventFilter() {
+ // Additional filters are not owned by CompoundEventFilter and they
+ // should all be removed when running here. |handlers_| has
+ // check_empty == true and will DCHECK failure if it is not empty.
+}
+
+// static
+gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
+ int window_component) {
+ switch (window_component) {
+ case HTBOTTOM:
+ return ui::kCursorSouthResize;
+ case HTBOTTOMLEFT:
+ return ui::kCursorSouthWestResize;
+ case HTBOTTOMRIGHT:
+ return ui::kCursorSouthEastResize;
+ case HTLEFT:
+ return ui::kCursorWestResize;
+ case HTRIGHT:
+ return ui::kCursorEastResize;
+ case HTTOP:
+ return ui::kCursorNorthResize;
+ case HTTOPLEFT:
+ return ui::kCursorNorthWestResize;
+ case HTTOPRIGHT:
+ return ui::kCursorNorthEastResize;
+ default:
+ return ui::kCursorNull;
+ }
+}
+
+void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
+ handlers_.AddObserver(handler);
+}
+
+void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
+ handlers_.RemoveObserver(handler);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CompoundEventFilter, private:
+
+void CompoundEventFilter::UpdateCursor(aura::Window* target,
+ ui::MouseEvent* event) {
+ // If drag and drop is in progress, let the drag drop client set the cursor
+ // instead of setting the cursor here.
+ aura::Window* root_window = target->GetRootWindow();
+ aura::client::DragDropClient* drag_drop_client =
+ aura::client::GetDragDropClient(root_window);
+ if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
+ return;
+
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(root_window);
+ if (cursor_client) {
+ gfx::NativeCursor cursor = target->GetCursor(event->location());
+ if ((event->flags() & ui::EF_IS_NON_CLIENT)) {
+ if (target->delegate()) {
+ int window_component =
+ target->delegate()->GetNonClientComponent(event->location());
+ cursor = CursorForWindowComponent(window_component);
+ } else {
+ // Allow the OS to handle non client cursors if we don't have a
+ // a delegate to handle the non client hittest.
+ return;
+ }
+ }
+ cursor_client->SetCursor(cursor);
+ }
+}
+
+void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
+ if (handlers_.might_have_observers()) {
+ ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
+ ui::EventHandler* handler;
+ while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
+ handler->OnKeyEvent(event);
+ }
+}
+
+void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
+ if (handlers_.might_have_observers()) {
+ ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
+ ui::EventHandler* handler;
+ while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
+ handler->OnMouseEvent(event);
+ }
+}
+
+void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
+ if (handlers_.might_have_observers()) {
+ ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
+ ui::EventHandler* handler;
+ while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
+ handler->OnTouchEvent(event);
+ }
+}
+
+void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
+ ui::Event* event,
+ bool show) {
+ if (event->flags() & ui::EF_IS_SYNTHESIZED)
+ return;
+
+ aura::client::CursorClient* client =
+ aura::client::GetCursorClient(target->GetRootWindow());
+ if (!client)
+ return;
+
+ if (show)
+ client->ShowCursor();
+ else
+ client->HideCursor();
+}
+
+void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
+ ui::Event* event,
+ bool enable) {
+ if (event->flags() & ui::EF_IS_SYNTHESIZED)
+ return;
+ aura::client::CursorClient* client =
+ aura::client::GetCursorClient(target->GetRootWindow());
+ if (!client)
+ return;
+
+ if (enable)
+ client->EnableMouseEvents();
+ else
+ client->DisableMouseEvents();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CompoundEventFilter, ui::EventHandler implementation:
+
+void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ aura::client::CursorClient* client =
+ aura::client::GetCursorClient(target->GetRootWindow());
+ if (client && client->ShouldHideCursorOnKeyEvent(*event))
+ SetCursorVisibilityOnEvent(target, event, false);
+
+ FilterKeyEvent(event);
+}
+
+void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
+ aura::Window* window = static_cast<aura::Window*>(event->target());
+ aura::WindowTracker window_tracker;
+ window_tracker.Add(window);
+
+ // We must always update the cursor, otherwise the cursor can get stuck if an
+ // event filter registered with us consumes the event.
+ // It should also update the cursor for clicking and wheels for ChromeOS boot.
+ // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
+ // operation will show the cursor.
+ // We also update the cursor for mouse enter in case a mouse cursor is sent to
+ // outside of the root window and moved back for some reasons (e.g. running on
+ // on Desktop for testing, or a bug in pointer barrier).
+ if (!(event->flags() & ui::EF_FROM_TOUCH) &&
+ (event->type() == ui::ET_MOUSE_ENTERED ||
+ event->type() == ui::ET_MOUSE_MOVED ||
+ event->type() == ui::ET_MOUSE_PRESSED ||
+ event->type() == ui::ET_MOUSEWHEEL)) {
+ SetMouseEventsEnableStateOnEvent(window, event, true);
+ SetCursorVisibilityOnEvent(window, event, true);
+ UpdateCursor(window, event);
+ }
+
+ FilterMouseEvent(event);
+}
+
+void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
+}
+
+void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
+ FilterTouchEvent(event);
+ if (!event->handled() && event->type() == ui::ET_TOUCH_PRESSED &&
+ ShouldHideCursorOnTouch(*event) &&
+ !aura::Env::GetInstance()->IsMouseButtonDown()) {
+ SetMouseEventsEnableStateOnEvent(
+ static_cast<aura::Window*>(event->target()), event, false);
+ }
+}
+
+void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
+ if (handlers_.might_have_observers()) {
+ ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
+ ui::EventHandler* handler;
+ while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
+ handler->OnGestureEvent(event);
+ }
+
+#if defined(OS_WIN)
+ // A Win8 edge swipe event is a special event that does not have location
+ // information associated with it, and is not preceeded by an ET_TOUCH_PRESSED
+ // event. So we treat it specially here.
+ if (!event->handled() && event->type() == ui::ET_GESTURE_WIN8_EDGE_SWIPE &&
+ !aura::Env::GetInstance()->IsMouseButtonDown()) {
+ SetMouseEventsEnableStateOnEvent(
+ static_cast<aura::Window*>(event->target()), event, false);
+ }
+#endif
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/compound_event_filter.h b/chromium/ui/wm/core/compound_event_filter.h
new file mode 100644
index 00000000000..ab4fdf83d06
--- /dev/null
+++ b/chromium/ui/wm/core/compound_event_filter.h
@@ -0,0 +1,93 @@
+// 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_WM_CORE_COMPOUND_EVENT_FILTER_H_
+#define UI_WM_CORE_COMPOUND_EVENT_FILTER_H_
+
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class CursorManager;
+class RootWindow;
+}
+
+namespace ui {
+class GestureEvent;
+class KeyEvent;
+class LocatedEvent;
+class MouseEvent;
+class TouchEvent;
+}
+
+namespace wm {
+
+// TODO(beng): This class should die. AddEventHandler() on the root Window
+// should be used instead.
+// CompoundEventFilter gets all events first and can provide actions to those
+// events. It implements global features such as click to activate a window and
+// cursor change when moving mouse.
+// Additional event filters can be added to CompoundEventFilter. Events will
+// pass through those additional filters in their addition order and could be
+// consumed by any of those filters. If an event is consumed by a filter, the
+// rest of the filter(s) and CompoundEventFilter will not see the consumed
+// event.
+class WM_EXPORT CompoundEventFilter : public ui::EventHandler {
+ public:
+ CompoundEventFilter();
+ virtual ~CompoundEventFilter();
+
+ // Returns the cursor for the specified component.
+ static gfx::NativeCursor CursorForWindowComponent(int window_component);
+
+ // Adds/removes additional event filters. This does not take ownership of
+ // the EventHandler.
+ // NOTE: These handlers are deprecated. Use env::AddPreTargetEventHandler etc.
+ // instead.
+ void AddHandler(ui::EventHandler* filter);
+ void RemoveHandler(ui::EventHandler* filter);
+
+ private:
+ // Updates the cursor if the target provides a custom one, and provides
+ // default resize cursors for window edges.
+ void UpdateCursor(aura::Window* target, ui::MouseEvent* event);
+
+ // Dispatches event to additional filters.
+ void FilterKeyEvent(ui::KeyEvent* event);
+ void FilterMouseEvent(ui::MouseEvent* event);
+ void FilterTouchEvent(ui::TouchEvent* event);
+
+ // Sets the visibility of the cursor if the event is not synthesized.
+ void SetCursorVisibilityOnEvent(aura::Window* target,
+ ui::Event* event,
+ bool show);
+
+ // Enables or disables mouse events if the event is not synthesized.
+ void SetMouseEventsEnableStateOnEvent(aura::Window* target,
+ ui::Event* event,
+ bool enable);
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ // Additional pre-target event handlers.
+ ObserverList<ui::EventHandler, true> handlers_;
+
+ // True if the cursur was hidden by the filter.
+ bool cursor_hidden_by_filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompoundEventFilter);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_COMPOUND_EVENT_FILTER_H_
diff --git a/chromium/ui/wm/core/compound_event_filter_unittest.cc b/chromium/ui/wm/core/compound_event_filter_unittest.cc
new file mode 100644
index 00000000000..afd3bcb5bd8
--- /dev/null
+++ b/chromium/ui/wm/core/compound_event_filter_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/compound_event_filter.h"
+
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_cursor_client.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/wm/core/default_activation_client.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace {
+
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+base::TimeDelta GetTime() {
+ return ui::EventTimeForNow();
+}
+#endif // defined(OS_CHROMEOS) || defined(OS_WIN)
+
+}
+
+namespace wm {
+
+namespace {
+
+// An event filter that consumes all gesture events.
+class ConsumeGestureEventFilter : public ui::EventHandler {
+ public:
+ ConsumeGestureEventFilter() {}
+ virtual ~ConsumeGestureEventFilter() {}
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnGestureEvent(ui::GestureEvent* e) OVERRIDE {
+ e->StopPropagation();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ConsumeGestureEventFilter);
+};
+
+} // namespace
+
+typedef aura::test::AuraTestBase CompoundEventFilterTest;
+
+#if defined(OS_CHROMEOS)
+// A keypress only hides the cursor on ChromeOS (crbug.com/304296).
+TEST_F(CompoundEventFilterTest, CursorVisibilityChange) {
+ scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
+ aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
+ gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+ window->SetCapture();
+
+ aura::test::TestCursorClient cursor_client(root_window());
+
+ // Send key event to hide the cursor.
+ ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
+ DispatchEventUsingWindowDispatcher(&key);
+ EXPECT_FALSE(cursor_client.IsCursorVisible());
+
+ // Synthesized mouse event should not show the cursor.
+ ui::MouseEvent enter(ui::ET_MOUSE_ENTERED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ enter.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
+ DispatchEventUsingWindowDispatcher(&enter);
+ EXPECT_FALSE(cursor_client.IsCursorVisible());
+
+ ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ move.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
+ DispatchEventUsingWindowDispatcher(&move);
+ EXPECT_FALSE(cursor_client.IsCursorVisible());
+
+ // A real mouse event should show the cursor.
+ ui::MouseEvent real_move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ DispatchEventUsingWindowDispatcher(&real_move);
+ EXPECT_TRUE(cursor_client.IsCursorVisible());
+
+ // Disallow hiding the cursor on keypress.
+ cursor_client.set_should_hide_cursor_on_key_event(false);
+ key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
+ DispatchEventUsingWindowDispatcher(&key);
+ EXPECT_TRUE(cursor_client.IsCursorVisible());
+
+ // Allow hiding the cursor on keypress.
+ cursor_client.set_should_hide_cursor_on_key_event(true);
+ key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
+ DispatchEventUsingWindowDispatcher(&key);
+ EXPECT_FALSE(cursor_client.IsCursorVisible());
+
+ // Mouse synthesized exit event should not show the cursor.
+ ui::MouseEvent exit(ui::ET_MOUSE_EXITED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ exit.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED);
+ DispatchEventUsingWindowDispatcher(&exit);
+ EXPECT_FALSE(cursor_client.IsCursorVisible());
+
+ aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
+}
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+// Touch visually hides the cursor on ChromeOS and Windows.
+TEST_F(CompoundEventFilterTest, TouchHidesCursor) {
+ new wm::DefaultActivationClient(root_window());
+ scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
+ aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
+ gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+ window->SetCapture();
+
+ aura::test::TestCursorClient cursor_client(root_window());
+
+ ui::MouseEvent mouse0(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ DispatchEventUsingWindowDispatcher(&mouse0);
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+
+ // This press is required for the GestureRecognizer to associate a target
+ // with kTouchId
+ ui::TouchEvent press0(
+ ui::ET_TOUCH_PRESSED, gfx::Point(90, 90), 1, GetTime());
+ DispatchEventUsingWindowDispatcher(&press0);
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+
+ ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 1, GetTime());
+ DispatchEventUsingWindowDispatcher(&move);
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+
+ ui::TouchEvent release(
+ ui::ET_TOUCH_RELEASED, gfx::Point(10, 10), 1, GetTime());
+ DispatchEventUsingWindowDispatcher(&release);
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+
+ ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ // Move the cursor again. The cursor should be visible.
+ DispatchEventUsingWindowDispatcher(&mouse1);
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+
+ // Now activate the window and press on it again.
+ ui::TouchEvent press1(
+ ui::ET_TOUCH_PRESSED, gfx::Point(90, 90), 1, GetTime());
+ aura::client::GetActivationClient(
+ root_window())->ActivateWindow(window.get());
+ DispatchEventUsingWindowDispatcher(&press1);
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+ aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
+}
+#endif // defined(OS_CHROMEOS) || defined(OS_WIN)
+
+// Tests that if an event filter consumes a gesture, then it doesn't focus the
+// window.
+TEST_F(CompoundEventFilterTest, FilterConsumedGesture) {
+ scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
+ scoped_ptr<ui::EventHandler> gesure_handler(new ConsumeGestureEventFilter);
+ compound_filter->AddHandler(gesure_handler.get());
+ aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
+ aura::test::TestWindowDelegate delegate;
+ DCHECK(root_window());
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
+ gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+
+ EXPECT_TRUE(window->CanFocus());
+ EXPECT_FALSE(window->HasFocus());
+
+ // Tap on the window should not focus it since the filter will be consuming
+ // the gestures.
+ aura::test::EventGenerator generator(root_window(), gfx::Point(50, 50));
+ generator.PressTouch();
+ EXPECT_FALSE(window->HasFocus());
+
+ compound_filter->RemoveHandler(gesure_handler.get());
+ aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
+}
+
+// Verifies we don't attempt to hide the mouse when the mouse is down and a
+// touch event comes in.
+TEST_F(CompoundEventFilterTest, DontHideWhenMouseDown) {
+ aura::test::EventGenerator event_generator(root_window());
+
+ scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
+ aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
+ gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+
+ aura::test::TestCursorClient cursor_client(root_window());
+
+ // Move and press the mouse over the window.
+ event_generator.MoveMouseTo(10, 10);
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+ event_generator.PressLeftButton();
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+ EXPECT_TRUE(aura::Env::GetInstance()->IsMouseButtonDown());
+
+ // Do a touch event. As the mouse button is down this should not disable mouse
+ // events.
+ event_generator.PressTouch();
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+ aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
+}
+
+#if defined(OS_WIN)
+// Windows synthesizes mouse messages for touch events. We should not be
+// showing the cursor when we receive such messages.
+TEST_F(CompoundEventFilterTest, DontShowCursorOnMouseMovesFromTouch) {
+ scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
+ aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(&delegate, 1234,
+ gfx::Rect(5, 5, 100, 100), root_window()));
+ window->Show();
+ window->SetCapture();
+
+ aura::test::TestCursorClient cursor_client(root_window());
+ cursor_client.DisableMouseEvents();
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+
+ ui::MouseEvent mouse0(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+ gfx::Point(10, 10), 0, 0);
+ mouse0.set_flags(mouse0.flags() | ui::EF_FROM_TOUCH);
+
+ DispatchEventUsingWindowDispatcher(&mouse0);
+ EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
+
+ mouse0.set_flags(mouse0.flags() & ~ui::EF_FROM_TOUCH);
+ DispatchEventUsingWindowDispatcher(&mouse0);
+ EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());
+
+ aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
+}
+#endif
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/cursor_manager.cc b/chromium/ui/wm/core/cursor_manager.cc
new file mode 100644
index 00000000000..e9f988566a3
--- /dev/null
+++ b/chromium/ui/wm/core/cursor_manager.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/cursor_manager.h"
+
+#include "base/logging.h"
+#include "ui/aura/client/cursor_client_observer.h"
+#include "ui/wm/core/native_cursor_manager.h"
+#include "ui/wm/core/native_cursor_manager_delegate.h"
+
+namespace wm {
+
+namespace internal {
+
+// Represents the cursor state which is composed of cursor type, visibility, and
+// mouse events enable state. When mouse events are disabled, the cursor is
+// always invisible.
+class CursorState {
+ public:
+ CursorState()
+ : cursor_(ui::kCursorNone),
+ visible_(true),
+ cursor_set_(ui::CURSOR_SET_NORMAL),
+ mouse_events_enabled_(true),
+ visible_on_mouse_events_enabled_(true) {
+ }
+
+ gfx::NativeCursor cursor() const { return cursor_; }
+ void set_cursor(gfx::NativeCursor cursor) { cursor_ = cursor; }
+
+ bool visible() const { return visible_; }
+ void SetVisible(bool visible) {
+ if (mouse_events_enabled_)
+ visible_ = visible;
+ // Ignores the call when mouse events disabled.
+ }
+
+ ui::CursorSetType cursor_set() const { return cursor_set_; }
+ void set_cursor_set(ui::CursorSetType cursor_set) {
+ cursor_set_ = cursor_set;
+ }
+
+ bool mouse_events_enabled() const { return mouse_events_enabled_; }
+ void SetMouseEventsEnabled(bool enabled) {
+ if (mouse_events_enabled_ == enabled)
+ return;
+ mouse_events_enabled_ = enabled;
+
+ // Restores the visibility when mouse events are enabled.
+ if (enabled) {
+ visible_ = visible_on_mouse_events_enabled_;
+ } else {
+ visible_on_mouse_events_enabled_ = visible_;
+ visible_ = false;
+ }
+ }
+
+ private:
+ gfx::NativeCursor cursor_;
+ bool visible_;
+ ui::CursorSetType cursor_set_;
+ bool mouse_events_enabled_;
+
+ // The visibility to set when mouse events are enabled.
+ bool visible_on_mouse_events_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorState);
+};
+
+} // namespace internal
+
+CursorManager::CursorManager(scoped_ptr<NativeCursorManager> delegate)
+ : delegate_(delegate.Pass()),
+ cursor_lock_count_(0),
+ current_state_(new internal::CursorState),
+ state_on_unlock_(new internal::CursorState) {
+}
+
+CursorManager::~CursorManager() {
+}
+
+void CursorManager::SetCursor(gfx::NativeCursor cursor) {
+ state_on_unlock_->set_cursor(cursor);
+ if (cursor_lock_count_ == 0 &&
+ GetCursor() != state_on_unlock_->cursor()) {
+ delegate_->SetCursor(state_on_unlock_->cursor(), this);
+ }
+}
+
+gfx::NativeCursor CursorManager::GetCursor() const {
+ return current_state_->cursor();
+}
+
+void CursorManager::ShowCursor() {
+ state_on_unlock_->SetVisible(true);
+ if (cursor_lock_count_ == 0 &&
+ IsCursorVisible() != state_on_unlock_->visible()) {
+ delegate_->SetVisibility(state_on_unlock_->visible(), this);
+ FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
+ OnCursorVisibilityChanged(true));
+ }
+}
+
+void CursorManager::HideCursor() {
+ state_on_unlock_->SetVisible(false);
+ if (cursor_lock_count_ == 0 &&
+ IsCursorVisible() != state_on_unlock_->visible()) {
+ delegate_->SetVisibility(state_on_unlock_->visible(), this);
+ FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
+ OnCursorVisibilityChanged(false));
+ }
+}
+
+bool CursorManager::IsCursorVisible() const {
+ return current_state_->visible();
+}
+
+void CursorManager::SetCursorSet(ui::CursorSetType cursor_set) {
+ state_on_unlock_->set_cursor_set(cursor_set);
+ if (GetCursorSet() != state_on_unlock_->cursor_set())
+ delegate_->SetCursorSet(state_on_unlock_->cursor_set(), this);
+}
+
+ui::CursorSetType CursorManager::GetCursorSet() const {
+ return current_state_->cursor_set();
+}
+
+void CursorManager::EnableMouseEvents() {
+ state_on_unlock_->SetMouseEventsEnabled(true);
+ if (cursor_lock_count_ == 0 &&
+ IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
+ delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
+ this);
+ }
+}
+
+void CursorManager::DisableMouseEvents() {
+ state_on_unlock_->SetMouseEventsEnabled(false);
+ if (cursor_lock_count_ == 0 &&
+ IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
+ delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
+ this);
+ }
+}
+
+bool CursorManager::IsMouseEventsEnabled() const {
+ return current_state_->mouse_events_enabled();
+}
+
+void CursorManager::SetDisplay(const gfx::Display& display) {
+ delegate_->SetDisplay(display, this);
+}
+
+void CursorManager::LockCursor() {
+ cursor_lock_count_++;
+}
+
+void CursorManager::UnlockCursor() {
+ cursor_lock_count_--;
+ DCHECK_GE(cursor_lock_count_, 0);
+ if (cursor_lock_count_ > 0)
+ return;
+
+ if (GetCursor() != state_on_unlock_->cursor()) {
+ delegate_->SetCursor(state_on_unlock_->cursor(), this);
+ }
+ if (IsMouseEventsEnabled() != state_on_unlock_->mouse_events_enabled()) {
+ delegate_->SetMouseEventsEnabled(state_on_unlock_->mouse_events_enabled(),
+ this);
+ }
+ if (IsCursorVisible() != state_on_unlock_->visible()) {
+ delegate_->SetVisibility(state_on_unlock_->visible(),
+ this);
+ }
+}
+
+bool CursorManager::IsCursorLocked() const {
+ return cursor_lock_count_ > 0;
+}
+
+void CursorManager::AddObserver(
+ aura::client::CursorClientObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CursorManager::RemoveObserver(
+ aura::client::CursorClientObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool CursorManager::ShouldHideCursorOnKeyEvent(
+ const ui::KeyEvent& event) const {
+ return false;
+}
+
+void CursorManager::CommitCursor(gfx::NativeCursor cursor) {
+ current_state_->set_cursor(cursor);
+}
+
+void CursorManager::CommitVisibility(bool visible) {
+ // TODO(tdanderson): Find a better place for this so we don't
+ // notify the observers more than is necessary.
+ FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_,
+ OnCursorVisibilityChanged(visible));
+ current_state_->SetVisible(visible);
+}
+
+void CursorManager::CommitCursorSet(ui::CursorSetType cursor_set) {
+ current_state_->set_cursor_set(cursor_set);
+}
+
+void CursorManager::CommitMouseEventsEnabled(bool enabled) {
+ current_state_->SetMouseEventsEnabled(enabled);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/cursor_manager.h b/chromium/ui/wm/core/cursor_manager.h
new file mode 100644
index 00000000000..f60ef14174c
--- /dev/null
+++ b/chromium/ui/wm/core/cursor_manager.h
@@ -0,0 +1,93 @@
+// 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_WM_CORE_CURSOR_MANAGER_H_
+#define UI_WM_CORE_CURSOR_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+#include "ui/wm/core/native_cursor_manager_delegate.h"
+#include "ui/wm/wm_export.h"
+
+namespace gfx {
+class Display;
+}
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace wm {
+
+namespace internal {
+class CursorState;
+}
+
+class NativeCursorManager;
+
+// This class receives requests to change cursor properties, as well as
+// requests to queue any further changes until a later time. It sends changes
+// to the NativeCursorManager, which communicates back to us when these changes
+// were made through the NativeCursorManagerDelegate interface.
+class WM_EXPORT CursorManager : public aura::client::CursorClient,
+ public NativeCursorManagerDelegate {
+ public:
+ explicit CursorManager(scoped_ptr<NativeCursorManager> delegate);
+ virtual ~CursorManager();
+
+ // Overridden from aura::client::CursorClient:
+ virtual void SetCursor(gfx::NativeCursor) OVERRIDE;
+ virtual gfx::NativeCursor GetCursor() const OVERRIDE;
+ virtual void ShowCursor() OVERRIDE;
+ virtual void HideCursor() OVERRIDE;
+ virtual bool IsCursorVisible() const OVERRIDE;
+ virtual void SetCursorSet(ui::CursorSetType cursor_set) OVERRIDE;
+ virtual ui::CursorSetType GetCursorSet() const OVERRIDE;
+ virtual void EnableMouseEvents() OVERRIDE;
+ virtual void DisableMouseEvents() OVERRIDE;
+ virtual bool IsMouseEventsEnabled() const OVERRIDE;
+ virtual void SetDisplay(const gfx::Display& display) OVERRIDE;
+ virtual void LockCursor() OVERRIDE;
+ virtual void UnlockCursor() OVERRIDE;
+ virtual bool IsCursorLocked() const OVERRIDE;
+ virtual void AddObserver(
+ aura::client::CursorClientObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ aura::client::CursorClientObserver* observer) OVERRIDE;
+ virtual bool ShouldHideCursorOnKeyEvent(
+ const ui::KeyEvent& event) const OVERRIDE;
+
+ private:
+ // Overridden from NativeCursorManagerDelegate:
+ virtual void CommitCursor(gfx::NativeCursor cursor) OVERRIDE;
+ virtual void CommitVisibility(bool visible) OVERRIDE;
+ virtual void CommitCursorSet(ui::CursorSetType cursor_set) OVERRIDE;
+ virtual void CommitMouseEventsEnabled(bool enabled) OVERRIDE;
+
+ scoped_ptr<NativeCursorManager> delegate_;
+
+ // Number of times LockCursor() has been invoked without a corresponding
+ // UnlockCursor().
+ int cursor_lock_count_;
+
+ // The current state of the cursor.
+ scoped_ptr<internal::CursorState> current_state_;
+
+ // The cursor state to restore when the cursor is unlocked.
+ scoped_ptr<internal::CursorState> state_on_unlock_;
+
+ ObserverList<aura::client::CursorClientObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorManager);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_CURSOR_MANAGER_H_
diff --git a/chromium/ui/wm/core/cursor_manager_unittest.cc b/chromium/ui/wm/core/cursor_manager_unittest.cc
new file mode 100644
index 00000000000..58c3b174d80
--- /dev/null
+++ b/chromium/ui/wm/core/cursor_manager_unittest.cc
@@ -0,0 +1,330 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/cursor_manager.h"
+
+#include "ui/aura/client/cursor_client_observer.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/wm/core/native_cursor_manager.h"
+
+namespace {
+
+class TestingCursorManager : public wm::NativeCursorManager {
+ public:
+ // Overridden from wm::NativeCursorManager:
+ virtual void SetDisplay(
+ const gfx::Display& display,
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE {}
+
+ virtual void SetCursor(
+ gfx::NativeCursor cursor,
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE {
+ delegate->CommitCursor(cursor);
+ }
+
+ virtual void SetVisibility(
+ bool visible,
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE {
+ delegate->CommitVisibility(visible);
+ }
+
+ virtual void SetMouseEventsEnabled(
+ bool enabled,
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE {
+ delegate->CommitMouseEventsEnabled(enabled);
+ }
+
+ virtual void SetCursorSet(
+ ui::CursorSetType cursor_set,
+ wm::NativeCursorManagerDelegate* delegate) OVERRIDE {
+ delegate->CommitCursorSet(cursor_set);
+ }
+};
+
+} // namespace
+
+class CursorManagerTest : public aura::test::AuraTestBase {
+ protected:
+ CursorManagerTest()
+ : delegate_(new TestingCursorManager),
+ cursor_manager_(scoped_ptr<wm::NativeCursorManager>(
+ delegate_)) {
+ }
+
+ TestingCursorManager* delegate_;
+ wm::CursorManager cursor_manager_;
+};
+
+class TestingCursorClientObserver : public aura::client::CursorClientObserver {
+ public:
+ TestingCursorClientObserver()
+ : cursor_visibility_(false),
+ did_visibility_change_(false) {}
+ void reset() { cursor_visibility_ = did_visibility_change_ = false; }
+ bool is_cursor_visible() const { return cursor_visibility_; }
+ bool did_visibility_change() const { return did_visibility_change_; }
+
+ // Overridden from aura::client::CursorClientObserver:
+ virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE {
+ cursor_visibility_ = is_visible;
+ did_visibility_change_ = true;
+ }
+
+ private:
+ bool cursor_visibility_;
+ bool did_visibility_change_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingCursorClientObserver);
+};
+
+TEST_F(CursorManagerTest, ShowHideCursor) {
+ cursor_manager_.SetCursor(ui::kCursorCopy);
+ EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
+
+ cursor_manager_.ShowCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.HideCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ // The current cursor does not change even when the cursor is not shown.
+ EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
+
+ // Check if cursor visibility is locked.
+ cursor_manager_.LockCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.ShowCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+
+ cursor_manager_.LockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.HideCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+
+ // Checks setting visiblity while cursor is locked does not affect the
+ // subsequent uses of UnlockCursor.
+ cursor_manager_.LockCursor();
+ cursor_manager_.HideCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+
+ cursor_manager_.ShowCursor();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+
+ cursor_manager_.LockCursor();
+ cursor_manager_.ShowCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+
+ cursor_manager_.HideCursor();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+}
+
+// Verifies that LockCursor/UnlockCursor work correctly with
+// EnableMouseEvents and DisableMouseEvents
+TEST_F(CursorManagerTest, EnableDisableMouseEvents) {
+ cursor_manager_.SetCursor(ui::kCursorCopy);
+ EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
+
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ // The current cursor does not change even when the cursor is not shown.
+ EXPECT_EQ(ui::kCursorCopy, cursor_manager_.GetCursor().native_type());
+
+ // Check if cursor enable state is locked.
+ cursor_manager_.LockCursor();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.LockCursor();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+
+ // Checks enabling cursor while cursor is locked does not affect the
+ // subsequent uses of UnlockCursor.
+ cursor_manager_.LockCursor();
+ cursor_manager_.DisableMouseEvents();
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.LockCursor();
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.DisableMouseEvents();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+}
+
+TEST_F(CursorManagerTest, SetCursorSet) {
+ EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
+
+ cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
+ EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
+
+ cursor_manager_.SetCursorSet(ui::CURSOR_SET_LARGE);
+ EXPECT_EQ(ui::CURSOR_SET_LARGE, cursor_manager_.GetCursorSet());
+
+ cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
+ EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
+}
+
+TEST_F(CursorManagerTest, IsMouseEventsEnabled) {
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+}
+
+// Verifies that the mouse events enable state changes correctly when
+// ShowCursor/HideCursor and EnableMouseEvents/DisableMouseEvents are used
+// together.
+TEST_F(CursorManagerTest, ShowAndEnable) {
+ // Changing the visibility of the cursor does not affect the enable state.
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.ShowCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.HideCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.ShowCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ // When mouse events are disabled, it also gets invisible.
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+
+ // When mouse events are enabled, it restores the visibility state.
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.ShowCursor();
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ cursor_manager_.HideCursor();
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.EnableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_TRUE(cursor_manager_.IsMouseEventsEnabled());
+
+ // When mouse events are disabled, ShowCursor is ignored.
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.ShowCursor();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+ cursor_manager_.DisableMouseEvents();
+ EXPECT_FALSE(cursor_manager_.IsCursorVisible());
+ EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
+}
+
+// Verifies that calling DisableMouseEvents multiple times in a row makes no
+// difference compared with calling it once.
+// This is a regression test for http://crbug.com/169404.
+TEST_F(CursorManagerTest, MultipleDisableMouseEvents) {
+ cursor_manager_.DisableMouseEvents();
+ cursor_manager_.DisableMouseEvents();
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+}
+
+// Verifies that calling EnableMouseEvents multiple times in a row makes no
+// difference compared with calling it once.
+TEST_F(CursorManagerTest, MultipleEnableMouseEvents) {
+ cursor_manager_.DisableMouseEvents();
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.EnableMouseEvents();
+ cursor_manager_.LockCursor();
+ cursor_manager_.UnlockCursor();
+ EXPECT_TRUE(cursor_manager_.IsCursorVisible());
+}
+
+TEST_F(CursorManagerTest, TestCursorClientObserver) {
+ // Add two observers. Both should have OnCursorVisibilityChanged()
+ // invoked when the visibility of the cursor changes.
+ TestingCursorClientObserver observer_a;
+ TestingCursorClientObserver observer_b;
+ cursor_manager_.AddObserver(&observer_a);
+ cursor_manager_.AddObserver(&observer_b);
+
+ // Initial state before any events have been sent.
+ observer_a.reset();
+ observer_b.reset();
+ EXPECT_FALSE(observer_a.did_visibility_change());
+ EXPECT_FALSE(observer_b.did_visibility_change());
+ EXPECT_FALSE(observer_a.is_cursor_visible());
+ EXPECT_FALSE(observer_b.is_cursor_visible());
+
+ // Hide the cursor using HideCursor().
+ cursor_manager_.HideCursor();
+ EXPECT_TRUE(observer_a.did_visibility_change());
+ EXPECT_TRUE(observer_b.did_visibility_change());
+ EXPECT_FALSE(observer_a.is_cursor_visible());
+ EXPECT_FALSE(observer_b.is_cursor_visible());
+
+ // Show the cursor using ShowCursor().
+ observer_a.reset();
+ observer_b.reset();
+ cursor_manager_.ShowCursor();
+ EXPECT_TRUE(observer_a.did_visibility_change());
+ EXPECT_TRUE(observer_b.did_visibility_change());
+ EXPECT_TRUE(observer_a.is_cursor_visible());
+ EXPECT_TRUE(observer_b.is_cursor_visible());
+
+ // Remove observer_b. Its OnCursorVisibilityChanged() should
+ // not be invoked past this point.
+ cursor_manager_.RemoveObserver(&observer_b);
+
+ // Hide the cursor using HideCursor().
+ observer_a.reset();
+ observer_b.reset();
+ cursor_manager_.HideCursor();
+ EXPECT_TRUE(observer_a.did_visibility_change());
+ EXPECT_FALSE(observer_b.did_visibility_change());
+ EXPECT_FALSE(observer_a.is_cursor_visible());
+
+ // Show the cursor using ShowCursor().
+ observer_a.reset();
+ observer_b.reset();
+ cursor_manager_.ShowCursor();
+ EXPECT_TRUE(observer_a.did_visibility_change());
+ EXPECT_FALSE(observer_b.did_visibility_change());
+ EXPECT_TRUE(observer_a.is_cursor_visible());
+}
diff --git a/chromium/ui/wm/core/default_activation_client.cc b/chromium/ui/wm/core/default_activation_client.cc
new file mode 100644
index 00000000000..222c9acb4cb
--- /dev/null
+++ b/chromium/ui/wm/core/default_activation_client.cc
@@ -0,0 +1,157 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/default_activation_client.h"
+
+#include "ui/aura/window.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_delegate.h"
+
+namespace wm {
+
+// Takes care of observing root window destruction & destroying the client.
+class DefaultActivationClient::Deleter : public aura::WindowObserver {
+ public:
+ Deleter(DefaultActivationClient* client, aura::Window* root_window)
+ : client_(client),
+ root_window_(root_window) {
+ root_window_->AddObserver(this);
+ }
+
+ private:
+ virtual ~Deleter() {}
+
+ // Overridden from WindowObserver:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ DCHECK_EQ(window, root_window_);
+ root_window_->RemoveObserver(this);
+ delete client_;
+ delete this;
+ }
+
+ DefaultActivationClient* client_;
+ aura::Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(Deleter);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultActivationClient, public:
+
+DefaultActivationClient::DefaultActivationClient(aura::Window* root_window)
+ : last_active_(NULL) {
+ aura::client::SetActivationClient(root_window, this);
+ new Deleter(this, root_window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultActivationClient, client::ActivationClient implementation:
+
+void DefaultActivationClient::AddObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DefaultActivationClient::RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void DefaultActivationClient::ActivateWindow(aura::Window* window) {
+ aura::Window* last_active = GetActiveWindow();
+ if (last_active == window)
+ return;
+
+ last_active_ = last_active;
+ RemoveActiveWindow(window);
+ active_windows_.push_back(window);
+ window->parent()->StackChildAtTop(window);
+ window->AddObserver(this);
+
+ FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
+ observers_,
+ OnWindowActivated(window, last_active));
+
+ aura::client::ActivationChangeObserver* observer =
+ aura::client::GetActivationChangeObserver(last_active);
+ if (observer)
+ observer->OnWindowActivated(window, last_active);
+ observer = aura::client::GetActivationChangeObserver(window);
+ if (observer)
+ observer->OnWindowActivated(window, last_active);
+}
+
+void DefaultActivationClient::DeactivateWindow(aura::Window* window) {
+ aura::client::ActivationChangeObserver* observer =
+ aura::client::GetActivationChangeObserver(window);
+ if (observer)
+ observer->OnWindowActivated(NULL, window);
+ if (last_active_)
+ ActivateWindow(last_active_);
+}
+
+aura::Window* DefaultActivationClient::GetActiveWindow() {
+ if (active_windows_.empty())
+ return NULL;
+ return active_windows_.back();
+}
+
+aura::Window* DefaultActivationClient::GetActivatableWindow(
+ aura::Window* window) {
+ return NULL;
+}
+
+aura::Window* DefaultActivationClient::GetToplevelWindow(aura::Window* window) {
+ return NULL;
+}
+
+bool DefaultActivationClient::OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) {
+ return true;
+}
+
+bool DefaultActivationClient::CanActivateWindow(aura::Window* window) const {
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultActivationClient, aura::WindowObserver implementation:
+
+void DefaultActivationClient::OnWindowDestroyed(aura::Window* window) {
+ if (window == last_active_)
+ last_active_ = NULL;
+
+ if (window == GetActiveWindow()) {
+ active_windows_.pop_back();
+ aura::Window* next_active = GetActiveWindow();
+ if (next_active && aura::client::GetActivationChangeObserver(next_active)) {
+ aura::client::GetActivationChangeObserver(next_active)->OnWindowActivated(
+ next_active, NULL);
+ }
+ return;
+ }
+
+ RemoveActiveWindow(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultActivationClient, private:
+
+DefaultActivationClient::~DefaultActivationClient() {
+ for (unsigned int i = 0; i < active_windows_.size(); ++i) {
+ active_windows_[i]->RemoveObserver(this);
+ }
+}
+
+void DefaultActivationClient::RemoveActiveWindow(aura::Window* window) {
+ for (unsigned int i = 0; i < active_windows_.size(); ++i) {
+ if (active_windows_[i] == window) {
+ active_windows_.erase(active_windows_.begin() + i);
+ window->RemoveObserver(this);
+ return;
+ }
+ }
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/default_activation_client.h b/chromium/ui/wm/core/default_activation_client.h
new file mode 100644
index 00000000000..3b6bffc3196
--- /dev/null
+++ b/chromium/ui/wm/core/default_activation_client.h
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_WM_CORE_DEFAULT_ACTIVATION_CLIENT_H_
+#define UI_WM_CORE_DEFAULT_ACTIVATION_CLIENT_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/observer_list.h"
+#include "ui/aura/window_observer.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+namespace client {
+class ActivationChangeObserver;
+}
+}
+
+namespace wm {
+
+// Simple ActivationClient implementation for use by tests and other targets
+// that just need basic behavior (e.g. activate windows whenever requested,
+// restack windows at the top when they're activated, etc.). This object deletes
+// itself when the root window it is associated with is destroyed.
+class WM_EXPORT DefaultActivationClient : public aura::client::ActivationClient,
+ public aura::WindowObserver {
+ public:
+ explicit DefaultActivationClient(aura::Window* root_window);
+
+ // Overridden from aura::client::ActivationClient:
+ virtual void AddObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void ActivateWindow(aura::Window* window) OVERRIDE;
+ virtual void DeactivateWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetActiveWindow() OVERRIDE;
+ virtual aura::Window* GetActivatableWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetToplevelWindow(aura::Window* window) OVERRIDE;
+ virtual bool OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) OVERRIDE;
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
+
+ // Overridden from WindowObserver:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+ class Deleter;
+
+ virtual ~DefaultActivationClient();
+ void RemoveActiveWindow(aura::Window* window);
+
+ // This class explicitly does NOT store the active window in a window property
+ // to make sure that ActivationChangeObserver is not treated as part of the
+ // aura API. Assumptions to that end will cause tests that use this client to
+ // fail.
+ std::vector<aura::Window*> active_windows_;
+
+ // The window which was active before the currently active one.
+ aura::Window* last_active_;
+
+ ObserverList<aura::client::ActivationChangeObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultActivationClient);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_DEFAULT_ACTIVATION_CLIENT_H_
diff --git a/chromium/ui/wm/core/easy_resize_window_targeter.cc b/chromium/ui/wm/core/easy_resize_window_targeter.cc
new file mode 100644
index 00000000000..445028cbf92
--- /dev/null
+++ b/chromium/ui/wm/core/easy_resize_window_targeter.cc
@@ -0,0 +1,62 @@
+// 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/wm/core/easy_resize_window_targeter.h"
+
+#include "ui/aura/window.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/wm/public/transient_window_client.h"
+
+namespace wm {
+
+EasyResizeWindowTargeter::EasyResizeWindowTargeter(
+ aura::Window* container,
+ const gfx::Insets& mouse_extend,
+ const gfx::Insets& touch_extend)
+ : container_(container),
+ mouse_extend_(mouse_extend),
+ touch_extend_(touch_extend) {
+}
+
+EasyResizeWindowTargeter::~EasyResizeWindowTargeter() {
+}
+
+bool EasyResizeWindowTargeter::EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ aura::Window* window = static_cast<aura::Window*>(target);
+ if (ShouldUseExtendedBounds(window)) {
+ // Note that |event|'s location is in |window|'s parent's coordinate system,
+ // so convert it to |window|'s coordinate system first.
+ gfx::Point point = event.location();
+ if (window->parent())
+ aura::Window::ConvertPointToTarget(window->parent(), window, &point);
+
+ gfx::Rect bounds(window->bounds().size());
+ if (event.IsTouchEvent() || event.IsGestureEvent())
+ bounds.Inset(touch_extend_);
+ else
+ bounds.Inset(mouse_extend_);
+
+ return bounds.Contains(point);
+ }
+ return WindowTargeter::EventLocationInsideBounds(window, event);
+}
+
+bool EasyResizeWindowTargeter::ShouldUseExtendedBounds(
+ const aura::Window* window) const {
+ // Use the extended bounds only for immediate child windows of |container_|.
+ // Use the default targetter otherwise.
+ if (window->parent() != container_)
+ return false;
+
+ aura::client::TransientWindowClient* transient_window_client =
+ aura::client::GetTransientWindowClient();
+ return !transient_window_client ||
+ !transient_window_client->GetTransientParent(window) ||
+ transient_window_client->GetTransientParent(window) == container_;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/easy_resize_window_targeter.h b/chromium/ui/wm/core/easy_resize_window_targeter.h
new file mode 100644
index 00000000000..35b9eb2b865
--- /dev/null
+++ b/chromium/ui/wm/core/easy_resize_window_targeter.h
@@ -0,0 +1,53 @@
+// 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_WM_CORE_EASY_RESIZE_WINDOW_TARGETER_H_
+#define UI_WM_CORE_EASY_RESIZE_WINDOW_TARGETER_H_
+
+#include "ui/aura/window_targeter.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+// An EventTargeter for a container window that uses a slightly larger
+// hit-target region for easier resize.
+class WM_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter {
+ public:
+ // |container| window is the owner of this targeter.
+ EasyResizeWindowTargeter(aura::Window* container,
+ const gfx::Insets& mouse_extend,
+ const gfx::Insets& touch_extend);
+
+ virtual ~EasyResizeWindowTargeter();
+
+ protected:
+ void set_mouse_extend(const gfx::Insets& mouse_extend) {
+ mouse_extend_ = mouse_extend;
+ }
+
+ void set_touch_extend(const gfx::Insets& touch_extend) {
+ touch_extend_ = touch_extend;
+ }
+
+ // ui::EventTargeter:
+ virtual bool EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+
+ private:
+ // Returns true if the hit testing (EventLocationInsideBounds()) should use
+ // the extended bounds.
+ bool ShouldUseExtendedBounds(const aura::Window* window) const;
+
+ aura::Window* container_;
+ gfx::Insets mouse_extend_;
+ gfx::Insets touch_extend_;
+
+ DISALLOW_COPY_AND_ASSIGN(EasyResizeWindowTargeter);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_EASY_RESIZE_WINDOW_TARGETER_H_
diff --git a/chromium/ui/wm/core/focus_controller.cc b/chromium/ui/wm/core/focus_controller.cc
new file mode 100644
index 00000000000..1534e402e19
--- /dev/null
+++ b/chromium/ui/wm/core/focus_controller.cc
@@ -0,0 +1,368 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/focus_controller.h"
+
+#include "base/auto_reset.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/events/event.h"
+#include "ui/wm/core/focus_rules.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace wm {
+namespace {
+
+// When a modal window is activated, we bring its entire transient parent chain
+// to the front. This function must be called before the modal transient is
+// stacked at the top to ensure correct stacking order.
+void StackTransientParentsBelowModalWindow(aura::Window* window) {
+ if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
+ return;
+
+ aura::Window* transient_parent = wm::GetTransientParent(window);
+ while (transient_parent) {
+ transient_parent->parent()->StackChildAtTop(transient_parent);
+ transient_parent = wm::GetTransientParent(transient_parent);
+ }
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, public:
+
+FocusController::FocusController(FocusRules* rules)
+ : active_window_(NULL),
+ focused_window_(NULL),
+ updating_focus_(false),
+ updating_activation_(false),
+ rules_(rules),
+ observer_manager_(this) {
+ DCHECK(rules);
+}
+
+FocusController::~FocusController() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, aura::client::ActivationClient implementation:
+
+void FocusController::AddObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ activation_observers_.AddObserver(observer);
+}
+
+void FocusController::RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) {
+ activation_observers_.RemoveObserver(observer);
+}
+
+void FocusController::ActivateWindow(aura::Window* window) {
+ FocusWindow(window);
+}
+
+void FocusController::DeactivateWindow(aura::Window* window) {
+ if (window)
+ FocusWindow(rules_->GetNextActivatableWindow(window));
+}
+
+aura::Window* FocusController::GetActiveWindow() {
+ return active_window_;
+}
+
+aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
+ return rules_->GetActivatableWindow(window);
+}
+
+aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
+ return rules_->GetToplevelWindow(window);
+}
+
+bool FocusController::OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) {
+ NOTREACHED();
+ return false;
+}
+
+bool FocusController::CanActivateWindow(aura::Window* window) const {
+ return rules_->CanActivateWindow(window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, aura::client::FocusClient implementation:
+
+void FocusController::AddObserver(
+ aura::client::FocusChangeObserver* observer) {
+ focus_observers_.AddObserver(observer);
+}
+
+void FocusController::RemoveObserver(
+ aura::client::FocusChangeObserver* observer) {
+ focus_observers_.RemoveObserver(observer);
+}
+
+void FocusController::FocusWindow(aura::Window* window) {
+ if (window &&
+ (window->Contains(focused_window_) || window->Contains(active_window_))) {
+ return;
+ }
+
+ // We should not be messing with the focus if the window has capture, unless
+ // no has focus.
+ if (window && (aura::client::GetCaptureWindow(window) == window) &&
+ focused_window_) {
+ return;
+ }
+
+ // Focusing a window also activates its containing activatable window. Note
+ // that the rules could redirect activation activation and/or focus.
+ aura::Window* focusable = rules_->GetFocusableWindow(window);
+ aura::Window* activatable =
+ focusable ? rules_->GetActivatableWindow(focusable) : NULL;
+
+ // We need valid focusable/activatable windows in the event we're not clearing
+ // focus. "Clearing focus" is inferred by whether or not |window| passed to
+ // this function is non-NULL.
+ if (window && (!focusable || !activatable))
+ return;
+ DCHECK((focusable && activatable) || !window);
+
+ // Activation change observers may change the focused window. If this happens
+ // we must not adjust the focus below since this will clobber that change.
+ aura::Window* last_focused_window = focused_window_;
+ if (!updating_activation_)
+ SetActiveWindow(window, activatable);
+
+ // If the window's ActivationChangeObserver shifted focus to a valid window,
+ // we don't want to focus the window we thought would be focused by default.
+ bool activation_changed_focus = last_focused_window != focused_window_;
+ if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
+ if (active_window_ && focusable)
+ DCHECK(active_window_->Contains(focusable));
+ SetFocusedWindow(focusable);
+ }
+}
+
+void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
+ DCHECK(window);
+ if (!active_window_)
+ return;
+ if (!active_window_->Contains(window))
+ return;
+ SetFocusedWindow(window);
+}
+
+aura::Window* FocusController::GetFocusedWindow() {
+ return focused_window_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, ui::EventHandler implementation:
+void FocusController::OnKeyEvent(ui::KeyEvent* event) {
+}
+
+void FocusController::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
+ WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
+}
+
+void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
+}
+
+void FocusController::OnTouchEvent(ui::TouchEvent* event) {
+}
+
+void FocusController::OnGestureEvent(ui::GestureEvent* event) {
+ if (event->type() == ui::ET_GESTURE_BEGIN &&
+ event->details().touch_points() == 1 &&
+ !event->handled()) {
+ WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, aura::WindowObserver implementation:
+
+void FocusController::OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) {
+ if (!visible)
+ WindowLostFocusFromDispositionChange(window, window->parent());
+}
+
+void FocusController::OnWindowDestroying(aura::Window* window) {
+ WindowLostFocusFromDispositionChange(window, window->parent());
+}
+
+void FocusController::OnWindowHierarchyChanging(
+ const HierarchyChangeParams& params) {
+ if (params.receiver == active_window_ &&
+ params.target->Contains(params.receiver) && (!params.new_parent ||
+ aura::client::GetFocusClient(params.new_parent) !=
+ aura::client::GetFocusClient(params.receiver))) {
+ WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
+ }
+}
+
+void FocusController::OnWindowHierarchyChanged(
+ const HierarchyChangeParams& params) {
+ if (params.receiver == focused_window_ &&
+ params.target->Contains(params.receiver) && (!params.new_parent ||
+ aura::client::GetFocusClient(params.new_parent) !=
+ aura::client::GetFocusClient(params.receiver))) {
+ WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusController, private:
+
+void FocusController::SetFocusedWindow(aura::Window* window) {
+ if (updating_focus_ || window == focused_window_)
+ return;
+ DCHECK(rules_->CanFocusWindow(window));
+ if (window)
+ DCHECK_EQ(window, rules_->GetFocusableWindow(window));
+
+ base::AutoReset<bool> updating_focus(&updating_focus_, true);
+ aura::Window* lost_focus = focused_window_;
+
+ // |window| is going to get the focus, so reset the text input client.
+ // OnWindowFocused() may set a proper text input client if the implementation
+ // supports text input.
+ ui::TextInputFocusManager* text_input_focus_manager =
+ ui::TextInputFocusManager::GetInstance();
+ if (window)
+ text_input_focus_manager->FocusTextInputClient(NULL);
+
+ // Allow for the window losing focus to be deleted during dispatch. If it is
+ // deleted pass NULL to observers instead of a deleted window.
+ aura::WindowTracker window_tracker;
+ if (lost_focus)
+ window_tracker.Add(lost_focus);
+ if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
+ focused_window_ != active_window_) {
+ observer_manager_.Remove(focused_window_);
+ }
+ focused_window_ = window;
+ if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
+ observer_manager_.Add(focused_window_);
+
+ FOR_EACH_OBSERVER(aura::client::FocusChangeObserver,
+ focus_observers_,
+ OnWindowFocused(focused_window_,
+ window_tracker.Contains(lost_focus) ?
+ lost_focus : NULL));
+ if (window_tracker.Contains(lost_focus)) {
+ aura::client::FocusChangeObserver* observer =
+ aura::client::GetFocusChangeObserver(lost_focus);
+ if (observer)
+ observer->OnWindowFocused(focused_window_, lost_focus);
+ }
+ aura::client::FocusChangeObserver* observer =
+ aura::client::GetFocusChangeObserver(focused_window_);
+ if (observer) {
+ observer->OnWindowFocused(
+ focused_window_,
+ window_tracker.Contains(lost_focus) ? lost_focus : NULL);
+ }
+
+ // Ensure that the text input client is reset when the window loses the focus.
+ if (!window)
+ text_input_focus_manager->FocusTextInputClient(NULL);
+}
+
+void FocusController::SetActiveWindow(aura::Window* requested_window,
+ aura::Window* window) {
+ if (updating_activation_)
+ return;
+
+ if (window == active_window_) {
+ if (requested_window) {
+ FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
+ activation_observers_,
+ OnAttemptToReactivateWindow(requested_window,
+ active_window_));
+ }
+ return;
+ }
+
+ DCHECK(rules_->CanActivateWindow(window));
+ if (window)
+ DCHECK_EQ(window, rules_->GetActivatableWindow(window));
+
+ base::AutoReset<bool> updating_activation(&updating_activation_, true);
+ aura::Window* lost_activation = active_window_;
+ // Allow for the window losing activation to be deleted during dispatch. If
+ // it is deleted pass NULL to observers instead of a deleted window.
+ aura::WindowTracker window_tracker;
+ if (lost_activation)
+ window_tracker.Add(lost_activation);
+ if (active_window_ && observer_manager_.IsObserving(active_window_) &&
+ focused_window_ != active_window_) {
+ observer_manager_.Remove(active_window_);
+ }
+ active_window_ = window;
+ if (active_window_ && !observer_manager_.IsObserving(active_window_))
+ observer_manager_.Add(active_window_);
+ if (active_window_) {
+ StackTransientParentsBelowModalWindow(active_window_);
+ active_window_->parent()->StackChildAtTop(active_window_);
+ }
+
+ aura::client::ActivationChangeObserver* observer = NULL;
+ if (window_tracker.Contains(lost_activation)) {
+ observer = aura::client::GetActivationChangeObserver(lost_activation);
+ if (observer)
+ observer->OnWindowActivated(active_window_, lost_activation);
+ }
+ observer = aura::client::GetActivationChangeObserver(active_window_);
+ if (observer) {
+ observer->OnWindowActivated(
+ active_window_,
+ window_tracker.Contains(lost_activation) ? lost_activation : NULL);
+ }
+ FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
+ activation_observers_,
+ OnWindowActivated(active_window_,
+ window_tracker.Contains(lost_activation) ?
+ lost_activation : NULL));
+}
+
+void FocusController::WindowLostFocusFromDispositionChange(
+ aura::Window* window,
+ aura::Window* next) {
+ // A window's modality state will interfere with focus restoration during its
+ // destruction.
+ window->ClearProperty(aura::client::kModalKey);
+ // TODO(beng): See if this function can be replaced by a call to
+ // FocusWindow().
+ // Activation adjustments are handled first in the event of a disposition
+ // changed. If an activation change is necessary, focus is reset as part of
+ // that process so there's no point in updating focus independently.
+ if (window == active_window_) {
+ aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
+ SetActiveWindow(NULL, next_activatable);
+ if (!(active_window_ && active_window_->Contains(focused_window_)))
+ SetFocusedWindow(next_activatable);
+ } else if (window->Contains(focused_window_)) {
+ // Active window isn't changing, but focused window might be.
+ SetFocusedWindow(rules_->GetFocusableWindow(next));
+ }
+}
+
+void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
+ // Only focus |window| if it or any of its parents can be focused. Otherwise
+ // FocusWindow() will focus the topmost window, which may not be the
+ // currently focused one.
+ if (rules_->CanFocusWindow(GetToplevelWindow(window)))
+ FocusWindow(window);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/focus_controller.h b/chromium/ui/wm/core/focus_controller.h
new file mode 100644
index 00000000000..3366ea0c18f
--- /dev/null
+++ b/chromium/ui/wm/core/focus_controller.h
@@ -0,0 +1,128 @@
+// 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_WM_CORE_FOCUS_CONTROLLER_H_
+#define UI_WM_CORE_FOCUS_CONTROLLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class FocusRules;
+
+// FocusController handles focus and activation changes for an environment
+// encompassing one or more RootWindows. Within an environment there can be
+// only one focused and one active window at a time. When focus or activation
+// changes notifications are sent using the
+// aura::client::Focus/ActivationChangeObserver interfaces.
+// Changes to focus and activation can be from three sources:
+// . the Aura Client API (implemented here in aura::client::ActivationClient).
+// (The FocusController must be set as the ActivationClient implementation
+// for all RootWindows).
+// . input events (implemented here in ui::EventHandler).
+// (The FocusController must be registered as a pre-target handler for
+// the applicable environment owner, either a RootWindow or another type).
+// . Window disposition changes (implemented here in aura::WindowObserver).
+// (The FocusController registers itself as an observer of the active and
+// focused windows).
+class WM_EXPORT FocusController : public aura::client::ActivationClient,
+ public aura::client::FocusClient,
+ public ui::EventHandler,
+ public aura::WindowObserver {
+ public:
+ // |rules| cannot be NULL.
+ explicit FocusController(FocusRules* rules);
+ virtual ~FocusController();
+
+ private:
+ // Overridden from aura::client::ActivationClient:
+ virtual void AddObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ aura::client::ActivationChangeObserver* observer) OVERRIDE;
+ virtual void ActivateWindow(aura::Window* window) OVERRIDE;
+ virtual void DeactivateWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetActiveWindow() OVERRIDE;
+ virtual aura::Window* GetActivatableWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetToplevelWindow(aura::Window* window) OVERRIDE;
+ virtual bool OnWillFocusWindow(aura::Window* window,
+ const ui::Event* event) OVERRIDE;
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE;
+
+ // Overridden from aura::client::FocusClient:
+ virtual void AddObserver(
+ aura::client::FocusChangeObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(
+ aura::client::FocusChangeObserver* observer) OVERRIDE;
+ virtual void FocusWindow(aura::Window* window) OVERRIDE;
+ virtual void ResetFocusWithinActiveWindow(aura::Window* window) OVERRIDE;
+ virtual aura::Window* GetFocusedWindow() OVERRIDE;
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+ virtual void OnWindowHierarchyChanging(
+ const HierarchyChangeParams& params) OVERRIDE;
+ virtual void OnWindowHierarchyChanged(
+ const HierarchyChangeParams& params) OVERRIDE;
+
+ // Internal implementation that sets the focused window, fires events etc.
+ // This function must be called with a valid focusable window.
+ void SetFocusedWindow(aura::Window* window);
+
+ // Internal implementation that sets the active window, fires events etc.
+ // This function must be called with a valid |activatable_window|.
+ // |requested window| refers to the window that was passed in to an external
+ // request (e.g. FocusWindow or ActivateWindow). It may be NULL, e.g. if
+ // SetActiveWindow was not called by an external request. |activatable_window|
+ // refers to the actual window to be activated, which may be different.
+ void SetActiveWindow(aura::Window* requested_window,
+ aura::Window* activatable_window);
+
+ // Called when a window's disposition changed such that it and its hierarchy
+ // are no longer focusable/activatable. |next| is a valid window that is used
+ // as a starting point for finding a window to focus next based on rules.
+ void WindowLostFocusFromDispositionChange(aura::Window* window,
+ aura::Window* next);
+
+ // Called when an attempt is made to focus or activate a window via an input
+ // event targeted at that window. Rules determine the best focusable window
+ // for the input window.
+ void WindowFocusedFromInputEvent(aura::Window* window);
+
+ aura::Window* active_window_;
+ aura::Window* focused_window_;
+
+ bool updating_focus_;
+ bool updating_activation_;
+
+ scoped_ptr<FocusRules> rules_;
+
+ ObserverList<aura::client::ActivationChangeObserver> activation_observers_;
+ ObserverList<aura::client::FocusChangeObserver> focus_observers_;
+
+ ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusController);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_FOCUS_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/focus_controller_unittest.cc b/chromium/ui/wm/core/focus_controller_unittest.cc
new file mode 100644
index 00000000000..5d65943d1b4
--- /dev/null
+++ b/chromium/ui/wm/core/focus_controller_unittest.cc
@@ -0,0 +1,1285 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/focus_controller.h"
+
+#include <map>
+
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/default_capture_client.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/core/base_focus_rules.h"
+#include "ui/wm/core/wm_state.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace wm {
+
+class FocusNotificationObserver : public aura::client::ActivationChangeObserver,
+ public aura::client::FocusChangeObserver {
+ public:
+ FocusNotificationObserver()
+ : activation_changed_count_(0),
+ focus_changed_count_(0),
+ reactivation_count_(0),
+ reactivation_requested_window_(NULL),
+ reactivation_actual_window_(NULL) {}
+ virtual ~FocusNotificationObserver() {}
+
+ void ExpectCounts(int activation_changed_count, int focus_changed_count) {
+ EXPECT_EQ(activation_changed_count, activation_changed_count_);
+ EXPECT_EQ(focus_changed_count, focus_changed_count_);
+ }
+ int reactivation_count() const {
+ return reactivation_count_;
+ }
+ aura::Window* reactivation_requested_window() const {
+ return reactivation_requested_window_;
+ }
+ aura::Window* reactivation_actual_window() const {
+ return reactivation_actual_window_;
+ }
+
+ private:
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ ++activation_changed_count_;
+ }
+ virtual void OnAttemptToReactivateWindow(
+ aura::Window* request_active,
+ aura::Window* actual_active) OVERRIDE {
+ ++reactivation_count_;
+ reactivation_requested_window_ = request_active;
+ reactivation_actual_window_ = actual_active;
+ }
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE {
+ ++focus_changed_count_;
+ }
+
+ int activation_changed_count_;
+ int focus_changed_count_;
+ int reactivation_count_;
+ aura::Window* reactivation_requested_window_;
+ aura::Window* reactivation_actual_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusNotificationObserver);
+};
+
+class WindowDeleter {
+ public:
+ virtual aura::Window* GetDeletedWindow() = 0;
+
+ protected:
+ virtual ~WindowDeleter() {}
+};
+
+// ActivationChangeObserver and FocusChangeObserver that keeps track of whether
+// it was notified about activation changes or focus changes with a deleted
+// window.
+class RecordingActivationAndFocusChangeObserver
+ : public aura::client::ActivationChangeObserver,
+ public aura::client::FocusChangeObserver {
+ public:
+ RecordingActivationAndFocusChangeObserver(aura::Window* root,
+ WindowDeleter* deleter)
+ : root_(root),
+ deleter_(deleter),
+ was_notified_with_deleted_window_(false) {
+ aura::client::GetActivationClient(root_)->AddObserver(this);
+ aura::client::GetFocusClient(root_)->AddObserver(this);
+ }
+ virtual ~RecordingActivationAndFocusChangeObserver() {
+ aura::client::GetActivationClient(root_)->RemoveObserver(this);
+ aura::client::GetFocusClient(root_)->RemoveObserver(this);
+ }
+
+ bool was_notified_with_deleted_window() const {
+ return was_notified_with_deleted_window_;
+ }
+
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ if (lost_active && lost_active == deleter_->GetDeletedWindow())
+ was_notified_with_deleted_window_ = true;
+ }
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE {
+ if (lost_focus && lost_focus == deleter_->GetDeletedWindow())
+ was_notified_with_deleted_window_ = true;
+ }
+
+ private:
+ aura::Window* root_;
+
+ // Not owned.
+ WindowDeleter* deleter_;
+
+ // Whether the observer was notified about the loss of activation or the
+ // loss of focus with a window already deleted by |deleter_| as the
+ // |lost_active| or |lost_focus| parameter.
+ bool was_notified_with_deleted_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordingActivationAndFocusChangeObserver);
+};
+
+// ActivationChangeObserver that deletes the window losing activation.
+class DeleteOnLoseActivationChangeObserver :
+ public aura::client::ActivationChangeObserver,
+ public WindowDeleter {
+ public:
+ explicit DeleteOnLoseActivationChangeObserver(aura::Window* window)
+ : root_(window->GetRootWindow()),
+ window_(window),
+ did_delete_(false) {
+ aura::client::GetActivationClient(root_)->AddObserver(this);
+ }
+ virtual ~DeleteOnLoseActivationChangeObserver() {
+ aura::client::GetActivationClient(root_)->RemoveObserver(this);
+ }
+
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ if (window_ && lost_active == window_) {
+ delete lost_active;
+ did_delete_ = true;
+ }
+ }
+
+ // Overridden from WindowDeleter:
+ virtual aura::Window* GetDeletedWindow() OVERRIDE {
+ return did_delete_ ? window_ : NULL;
+ }
+
+ private:
+ aura::Window* root_;
+ aura::Window* window_;
+ bool did_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteOnLoseActivationChangeObserver);
+};
+
+// FocusChangeObserver that deletes the window losing focus.
+class DeleteOnLoseFocusChangeObserver
+ : public aura::client::FocusChangeObserver,
+ public WindowDeleter {
+ public:
+ explicit DeleteOnLoseFocusChangeObserver(aura::Window* window)
+ : root_(window->GetRootWindow()),
+ window_(window),
+ did_delete_(false) {
+ aura::client::GetFocusClient(root_)->AddObserver(this);
+ }
+ virtual ~DeleteOnLoseFocusChangeObserver() {
+ aura::client::GetFocusClient(root_)->RemoveObserver(this);
+ }
+
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE {
+ if (window_ && lost_focus == window_) {
+ delete lost_focus;
+ did_delete_ = true;
+ }
+ }
+
+ // Overridden from WindowDeleter:
+ virtual aura::Window* GetDeletedWindow() OVERRIDE {
+ return did_delete_ ? window_ : NULL;
+ }
+
+ private:
+ aura::Window* root_;
+ aura::Window* window_;
+ bool did_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteOnLoseFocusChangeObserver);
+};
+
+class ScopedFocusNotificationObserver : public FocusNotificationObserver {
+ public:
+ ScopedFocusNotificationObserver(aura::Window* root_window)
+ : root_window_(root_window) {
+ aura::client::GetActivationClient(root_window_)->AddObserver(this);
+ aura::client::GetFocusClient(root_window_)->AddObserver(this);
+ }
+ virtual ~ScopedFocusNotificationObserver() {
+ aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
+ aura::client::GetFocusClient(root_window_)->RemoveObserver(this);
+ }
+
+ private:
+ aura::Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFocusNotificationObserver);
+};
+
+class ScopedTargetFocusNotificationObserver : public FocusNotificationObserver {
+ public:
+ ScopedTargetFocusNotificationObserver(aura::Window* root_window, int id)
+ : target_(root_window->GetChildById(id)) {
+ aura::client::SetActivationChangeObserver(target_, this);
+ aura::client::SetFocusChangeObserver(target_, this);
+ tracker_.Add(target_);
+ }
+ virtual ~ScopedTargetFocusNotificationObserver() {
+ if (tracker_.Contains(target_)) {
+ aura::client::SetActivationChangeObserver(target_, NULL);
+ aura::client::SetFocusChangeObserver(target_, NULL);
+ }
+ }
+
+ private:
+ aura::Window* target_;
+ aura::WindowTracker tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTargetFocusNotificationObserver);
+};
+
+class ScopedFocusedTextInputClientChanger
+ : public ScopedFocusNotificationObserver {
+ public:
+ ScopedFocusedTextInputClientChanger(aura::Window* root_window,
+ ui::TextInputClient* text_input_client)
+ : ScopedFocusNotificationObserver(root_window),
+ text_input_client_(text_input_client) {}
+
+ private:
+ // Overridden from aura::client::FocusChangeObserver:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) OVERRIDE {
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(
+ text_input_client_);
+ }
+
+ ui::TextInputClient* text_input_client_;
+};
+
+// Used to fake the handling of events in the pre-target phase.
+class SimpleEventHandler : public ui::EventHandler {
+ public:
+ SimpleEventHandler() {}
+ virtual ~SimpleEventHandler() {}
+
+ // Overridden from ui::EventHandler:
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ event->SetHandled();
+ }
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ event->SetHandled();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SimpleEventHandler);
+};
+
+class FocusShiftingActivationObserver
+ : public aura::client::ActivationChangeObserver {
+ public:
+ explicit FocusShiftingActivationObserver(aura::Window* activated_window)
+ : activated_window_(activated_window),
+ shift_focus_to_(NULL) {}
+ virtual ~FocusShiftingActivationObserver() {}
+
+ void set_shift_focus_to(aura::Window* shift_focus_to) {
+ shift_focus_to_ = shift_focus_to;
+ }
+
+ private:
+ // Overridden from aura::client::ActivationChangeObserver:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE {
+ // Shift focus to a child. This should prevent the default focusing from
+ // occurring in FocusController::FocusWindow().
+ if (gained_active == activated_window_) {
+ aura::client::FocusClient* client =
+ aura::client::GetFocusClient(gained_active);
+ client->FocusWindow(shift_focus_to_);
+ }
+ }
+
+ aura::Window* activated_window_;
+ aura::Window* shift_focus_to_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusShiftingActivationObserver);
+};
+
+// BaseFocusRules subclass that allows basic overrides of focus/activation to
+// be tested. This is intended more as a test that the override system works at
+// all, rather than as an exhaustive set of use cases, those should be covered
+// in tests for those FocusRules implementations.
+class TestFocusRules : public BaseFocusRules {
+ public:
+ TestFocusRules() : focus_restriction_(NULL) {}
+
+ // Restricts focus and activation to this window and its child hierarchy.
+ void set_focus_restriction(aura::Window* focus_restriction) {
+ focus_restriction_ = focus_restriction;
+ }
+
+ // Overridden from BaseFocusRules:
+ virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE {
+ // In FocusControllerTests, only the RootWindow has activatable children.
+ return window->GetRootWindow() == window;
+ }
+ virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE {
+ // Restricting focus to a non-activatable child window means the activatable
+ // parent outside the focus restriction is activatable.
+ bool can_activate =
+ CanFocusOrActivate(window) || window->Contains(focus_restriction_);
+ return can_activate ? BaseFocusRules::CanActivateWindow(window) : false;
+ }
+ virtual bool CanFocusWindow(aura::Window* window) const OVERRIDE {
+ return CanFocusOrActivate(window) ?
+ BaseFocusRules::CanFocusWindow(window) : false;
+ }
+ virtual aura::Window* GetActivatableWindow(
+ aura::Window* window) const OVERRIDE {
+ return BaseFocusRules::GetActivatableWindow(
+ CanFocusOrActivate(window) ? window : focus_restriction_);
+ }
+ virtual aura::Window* GetFocusableWindow(
+ aura::Window* window) const OVERRIDE {
+ return BaseFocusRules::GetFocusableWindow(
+ CanFocusOrActivate(window) ? window : focus_restriction_);
+ }
+ virtual aura::Window* GetNextActivatableWindow(
+ aura::Window* ignore) const OVERRIDE {
+ aura::Window* next_activatable =
+ BaseFocusRules::GetNextActivatableWindow(ignore);
+ return CanFocusOrActivate(next_activatable) ?
+ next_activatable : GetActivatableWindow(focus_restriction_);
+ }
+
+ private:
+ bool CanFocusOrActivate(aura::Window* window) const {
+ return !focus_restriction_ || focus_restriction_->Contains(window);
+ }
+
+ aura::Window* focus_restriction_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
+};
+
+// Common infrastructure shared by all FocusController test types.
+class FocusControllerTestBase : public aura::test::AuraTestBase {
+ protected:
+ FocusControllerTestBase() {}
+
+ // Overridden from aura::test::AuraTestBase:
+ virtual void SetUp() OVERRIDE {
+ wm_state_.reset(new wm::WMState);
+ // FocusController registers itself as an Env observer so it can catch all
+ // window initializations, including the root_window()'s, so we create it
+ // before allowing the base setup.
+ test_focus_rules_ = new TestFocusRules;
+ focus_controller_.reset(new FocusController(test_focus_rules_));
+ aura::test::AuraTestBase::SetUp();
+ root_window()->AddPreTargetHandler(focus_controller_.get());
+ aura::client::SetFocusClient(root_window(), focus_controller_.get());
+ aura::client::SetActivationClient(root_window(), focus_controller_.get());
+
+ // Hierarchy used by all tests:
+ // root_window
+ // +-- w1
+ // | +-- w11
+ // | +-- w12
+ // +-- w2
+ // | +-- w21
+ // | +-- w211
+ // +-- w3
+ aura::Window* w1 = aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 1,
+ gfx::Rect(0, 0, 50, 50), root_window());
+ aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 11,
+ gfx::Rect(5, 5, 10, 10), w1);
+ aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 12,
+ gfx::Rect(15, 15, 10, 10), w1);
+ aura::Window* w2 = aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 2,
+ gfx::Rect(75, 75, 50, 50), root_window());
+ aura::Window* w21 = aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 21,
+ gfx::Rect(5, 5, 10, 10), w2);
+ aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 211,
+ gfx::Rect(1, 1, 5, 5), w21);
+ aura::test::CreateTestWindowWithDelegate(
+ aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), 3,
+ gfx::Rect(125, 125, 50, 50), root_window());
+ }
+ virtual void TearDown() OVERRIDE {
+ root_window()->RemovePreTargetHandler(focus_controller_.get());
+ aura::test::AuraTestBase::TearDown();
+ test_focus_rules_ = NULL; // Owned by FocusController.
+ focus_controller_.reset();
+ wm_state_.reset();
+ }
+
+ void FocusWindow(aura::Window* window) {
+ aura::client::GetFocusClient(root_window())->FocusWindow(window);
+ }
+ aura::Window* GetFocusedWindow() {
+ return aura::client::GetFocusClient(root_window())->GetFocusedWindow();
+ }
+ int GetFocusedWindowId() {
+ aura::Window* focused_window = GetFocusedWindow();
+ return focused_window ? focused_window->id() : -1;
+ }
+ void ActivateWindow(aura::Window* window) {
+ aura::client::GetActivationClient(root_window())->ActivateWindow(window);
+ }
+ void DeactivateWindow(aura::Window* window) {
+ aura::client::GetActivationClient(root_window())->DeactivateWindow(window);
+ }
+ aura::Window* GetActiveWindow() {
+ return aura::client::GetActivationClient(root_window())->GetActiveWindow();
+ }
+ int GetActiveWindowId() {
+ aura::Window* active_window = GetActiveWindow();
+ return active_window ? active_window->id() : -1;
+ }
+
+ TestFocusRules* test_focus_rules() { return test_focus_rules_; }
+
+ // Test functions.
+ virtual void BasicFocus() = 0;
+ virtual void BasicActivation() = 0;
+ virtual void FocusEvents() = 0;
+ virtual void DuplicateFocusEvents() {}
+ virtual void ActivationEvents() = 0;
+ virtual void ReactivationEvents() {}
+ virtual void DuplicateActivationEvents() {}
+ virtual void ShiftFocusWithinActiveWindow() {}
+ virtual void ShiftFocusToChildOfInactiveWindow() {}
+ virtual void ShiftFocusToParentOfFocusedWindow() {}
+ virtual void FocusRulesOverride() = 0;
+ virtual void ActivationRulesOverride() = 0;
+ virtual void ShiftFocusOnActivation() {}
+ virtual void ShiftFocusOnActivationDueToHide() {}
+ virtual void NoShiftActiveOnActivation() {}
+ virtual void NoFocusChangeOnClickOnCaptureWindow() {}
+ virtual void ChangeFocusWhenNothingFocusedAndCaptured() {}
+ virtual void DontPassDeletedWindow() {}
+ virtual void FocusedTextInputClient() {}
+
+ private:
+ scoped_ptr<FocusController> focus_controller_;
+ TestFocusRules* test_focus_rules_;
+ scoped_ptr<wm::WMState> wm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerTestBase);
+};
+
+// Test base for tests where focus is directly set to a target window.
+class FocusControllerDirectTestBase : public FocusControllerTestBase {
+ protected:
+ FocusControllerDirectTestBase() {}
+
+ // Different test types shift focus in different ways.
+ virtual void FocusWindowDirect(aura::Window* window) = 0;
+ virtual void ActivateWindowDirect(aura::Window* window) = 0;
+ virtual void DeactivateWindowDirect(aura::Window* window) = 0;
+
+ // Input events do not change focus if the window can not be focused.
+ virtual bool IsInputEvent() = 0;
+
+ void FocusWindowById(int id) {
+ aura::Window* window = root_window()->GetChildById(id);
+ DCHECK(window);
+ FocusWindowDirect(window);
+ }
+ void ActivateWindowById(int id) {
+ aura::Window* window = root_window()->GetChildById(id);
+ DCHECK(window);
+ ActivateWindowDirect(window);
+ }
+
+ // Overridden from FocusControllerTestBase:
+ virtual void BasicFocus() OVERRIDE {
+ EXPECT_EQ(NULL, GetFocusedWindow());
+ FocusWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+ FocusWindowById(2);
+ EXPECT_EQ(2, GetFocusedWindowId());
+ }
+ virtual void BasicActivation() OVERRIDE {
+ EXPECT_EQ(NULL, GetActiveWindow());
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetActiveWindowId());
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetActiveWindowId());
+ // Verify that attempting to deactivate NULL does not crash and does not
+ // change activation.
+ DeactivateWindow(NULL);
+ EXPECT_EQ(2, GetActiveWindowId());
+ DeactivateWindow(GetActiveWindow());
+ EXPECT_EQ(1, GetActiveWindowId());
+ }
+ virtual void FocusEvents() OVERRIDE {
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
+ ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
+
+ root_observer.ExpectCounts(0, 0);
+ observer1.ExpectCounts(0, 0);
+ observer2.ExpectCounts(0, 0);
+
+ FocusWindowById(1);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+ observer2.ExpectCounts(0, 0);
+
+ FocusWindowById(2);
+ root_observer.ExpectCounts(2, 2);
+ observer1.ExpectCounts(2, 2);
+ observer2.ExpectCounts(1, 1);
+ }
+ virtual void DuplicateFocusEvents() OVERRIDE {
+ // Focusing an existing focused window should not resend focus events.
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
+
+ root_observer.ExpectCounts(0, 0);
+ observer1.ExpectCounts(0, 0);
+
+ FocusWindowById(1);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+
+ FocusWindowById(1);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+ }
+ virtual void ActivationEvents() OVERRIDE {
+ ActivateWindowById(1);
+
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
+ ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
+
+ root_observer.ExpectCounts(0, 0);
+ observer1.ExpectCounts(0, 0);
+ observer2.ExpectCounts(0, 0);
+
+ ActivateWindowById(2);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+ observer2.ExpectCounts(1, 1);
+ }
+ virtual void ReactivationEvents() OVERRIDE {
+ ActivateWindowById(1);
+ ScopedFocusNotificationObserver root_observer(root_window());
+ EXPECT_EQ(0, root_observer.reactivation_count());
+ root_window()->GetChildById(2)->Hide();
+ // When we attempt to activate "2", which cannot be activated because it
+ // is not visible, "1" will be reactivated.
+ ActivateWindowById(2);
+ EXPECT_EQ(1, root_observer.reactivation_count());
+ EXPECT_EQ(root_window()->GetChildById(2),
+ root_observer.reactivation_requested_window());
+ EXPECT_EQ(root_window()->GetChildById(1),
+ root_observer.reactivation_actual_window());
+ }
+ virtual void DuplicateActivationEvents() OVERRIDE {
+ // Activating an existing active window should not resend activation events.
+ ActivateWindowById(1);
+
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer1(root_window(), 1);
+ ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
+
+ root_observer.ExpectCounts(0, 0);
+ observer1.ExpectCounts(0, 0);
+ observer2.ExpectCounts(0, 0);
+
+ ActivateWindowById(2);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+ observer2.ExpectCounts(1, 1);
+
+ ActivateWindowById(2);
+ root_observer.ExpectCounts(1, 1);
+ observer1.ExpectCounts(1, 1);
+ observer2.ExpectCounts(1, 1);
+ }
+ virtual void ShiftFocusWithinActiveWindow() OVERRIDE {
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+ FocusWindowById(11);
+ EXPECT_EQ(11, GetFocusedWindowId());
+ FocusWindowById(12);
+ EXPECT_EQ(12, GetFocusedWindowId());
+ }
+ virtual void ShiftFocusToChildOfInactiveWindow() OVERRIDE {
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetActiveWindowId());
+ EXPECT_EQ(2, GetFocusedWindowId());
+ FocusWindowById(11);
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(11, GetFocusedWindowId());
+ }
+ virtual void ShiftFocusToParentOfFocusedWindow() OVERRIDE {
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+ FocusWindowById(11);
+ EXPECT_EQ(11, GetFocusedWindowId());
+ FocusWindowById(1);
+ // Focus should _not_ shift to the parent of the already-focused window.
+ EXPECT_EQ(11, GetFocusedWindowId());
+ }
+ virtual void FocusRulesOverride() OVERRIDE {
+ EXPECT_EQ(NULL, GetFocusedWindow());
+ FocusWindowById(11);
+ EXPECT_EQ(11, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(root_window()->GetChildById(211));
+ FocusWindowById(12);
+ // Input events leave focus unchanged; direct API calls will change focus
+ // to the restricted window.
+ int focused_window = IsInputEvent() ? 11 : 211;
+ EXPECT_EQ(focused_window, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(NULL);
+ FocusWindowById(12);
+ EXPECT_EQ(12, GetFocusedWindowId());
+ }
+ virtual void ActivationRulesOverride() OVERRIDE {
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ aura::Window* w3 = root_window()->GetChildById(3);
+ test_focus_rules()->set_focus_restriction(w3);
+
+ ActivateWindowById(2);
+ // Input events leave activation unchanged; direct API calls will activate
+ // the restricted window.
+ int active_window = IsInputEvent() ? 1 : 3;
+ EXPECT_EQ(active_window, GetActiveWindowId());
+ EXPECT_EQ(active_window, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(NULL);
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetActiveWindowId());
+ EXPECT_EQ(2, GetFocusedWindowId());
+ }
+ virtual void ShiftFocusOnActivation() OVERRIDE {
+ // When a window is activated, by default that window is also focused.
+ // An ActivationChangeObserver may shift focus to another window within the
+ // same activatable window.
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetFocusedWindowId());
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ ActivateWindowById(2);
+
+ aura::Window* target = root_window()->GetChildById(1);
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(root_window());
+
+ scoped_ptr<FocusShiftingActivationObserver> observer(
+ new FocusShiftingActivationObserver(target));
+ observer->set_shift_focus_to(target->GetChildById(11));
+ client->AddObserver(observer.get());
+
+ ActivateWindowById(1);
+
+ // w1's ActivationChangeObserver shifted focus to this child, pre-empting
+ // FocusController's default setting.
+ EXPECT_EQ(11, GetFocusedWindowId());
+
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetFocusedWindowId());
+
+ // Simulate a focus reset by the ActivationChangeObserver. This should
+ // trigger the default setting in FocusController.
+ observer->set_shift_focus_to(NULL);
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ client->RemoveObserver(observer.get());
+
+ ActivateWindowById(2);
+ EXPECT_EQ(2, GetFocusedWindowId());
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+ }
+ virtual void ShiftFocusOnActivationDueToHide() OVERRIDE {
+ // Similar to ShiftFocusOnActivation except the activation change is
+ // triggered by hiding the active window.
+ ActivateWindowById(1);
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ // Removes window 3 as candidate for next activatable window.
+ root_window()->GetChildById(3)->Hide();
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ aura::Window* target = root_window()->GetChildById(2);
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(root_window());
+
+ scoped_ptr<FocusShiftingActivationObserver> observer(
+ new FocusShiftingActivationObserver(target));
+ observer->set_shift_focus_to(target->GetChildById(21));
+ client->AddObserver(observer.get());
+
+ // Hide the active window.
+ root_window()->GetChildById(1)->Hide();
+
+ EXPECT_EQ(21, GetFocusedWindowId());
+
+ client->RemoveObserver(observer.get());
+ }
+ virtual void NoShiftActiveOnActivation() OVERRIDE {
+ // When a window is activated, we need to prevent any change to activation
+ // from being made in response to an activation change notification.
+ }
+
+ virtual void NoFocusChangeOnClickOnCaptureWindow() OVERRIDE {
+ scoped_ptr<aura::client::DefaultCaptureClient> capture_client(
+ new aura::client::DefaultCaptureClient(root_window()));
+ // Clicking on a window which has capture should not cause a focus change
+ // to the window. This test verifies whether that is indeed the case.
+ ActivateWindowById(1);
+
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ aura::Window* w2 = root_window()->GetChildById(2);
+ aura::client::GetCaptureClient(root_window())->SetCapture(w2);
+ aura::test::EventGenerator generator(root_window(), w2);
+ generator.ClickLeftButton();
+
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+ aura::client::GetCaptureClient(root_window())->ReleaseCapture(w2);
+ }
+
+ // Verifies focus change is honored while capture held.
+ virtual void ChangeFocusWhenNothingFocusedAndCaptured() OVERRIDE {
+ scoped_ptr<aura::client::DefaultCaptureClient> capture_client(
+ new aura::client::DefaultCaptureClient(root_window()));
+ aura::Window* w1 = root_window()->GetChildById(1);
+ aura::client::GetCaptureClient(root_window())->SetCapture(w1);
+
+ EXPECT_EQ(-1, GetActiveWindowId());
+ EXPECT_EQ(-1, GetFocusedWindowId());
+
+ FocusWindowById(1);
+
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ aura::client::GetCaptureClient(root_window())->ReleaseCapture(w1);
+ }
+
+ // Verifies if a window that loses activation or focus is deleted during
+ // observer notification we don't pass the deleted window to other observers.
+ virtual void DontPassDeletedWindow() OVERRIDE {
+ FocusWindowById(1);
+
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ {
+ aura::Window* to_delete = root_window()->GetChildById(1);
+ DeleteOnLoseActivationChangeObserver observer1(to_delete);
+ RecordingActivationAndFocusChangeObserver observer2(root_window(),
+ &observer1);
+
+ FocusWindowById(2);
+
+ EXPECT_EQ(2, GetActiveWindowId());
+ EXPECT_EQ(2, GetFocusedWindowId());
+
+ EXPECT_EQ(to_delete, observer1.GetDeletedWindow());
+ EXPECT_FALSE(observer2.was_notified_with_deleted_window());
+ }
+
+ {
+ aura::Window* to_delete = root_window()->GetChildById(2);
+ DeleteOnLoseFocusChangeObserver observer1(to_delete);
+ RecordingActivationAndFocusChangeObserver observer2(root_window(),
+ &observer1);
+
+ FocusWindowById(3);
+
+ EXPECT_EQ(3, GetActiveWindowId());
+ EXPECT_EQ(3, GetFocusedWindowId());
+
+ EXPECT_EQ(to_delete, observer1.GetDeletedWindow());
+ EXPECT_FALSE(observer2.was_notified_with_deleted_window());
+ }
+ }
+
+ // Verifies if the focused text input client is cleared when a window gains
+ // or loses the focus.
+ virtual void FocusedTextInputClient() OVERRIDE {
+ ui::TextInputFocusManager* text_input_focus_manager =
+ ui::TextInputFocusManager::GetInstance();
+ ui::DummyTextInputClient text_input_client;
+ ui::TextInputClient* null_text_input_client = NULL;
+
+ EXPECT_EQ(null_text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+
+ text_input_focus_manager->FocusTextInputClient(&text_input_client);
+ EXPECT_EQ(&text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ FocusWindowById(1);
+ // The focused text input client gets cleared when a window gets focused
+ // unless any of observers sets the focused text input client.
+ EXPECT_EQ(null_text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+
+ ScopedFocusedTextInputClientChanger text_input_focus_changer(
+ root_window(), &text_input_client);
+ EXPECT_EQ(null_text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ FocusWindowById(2);
+ // |text_input_focus_changer| sets the focused text input client.
+ EXPECT_EQ(&text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+
+ FocusWindow(NULL);
+ // The focused text input client gets cleared when a window loses the focus.
+ EXPECT_EQ(null_text_input_client,
+ text_input_focus_manager->GetFocusedTextInputClient());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerDirectTestBase);
+};
+
+// Focus and Activation changes via aura::client::ActivationClient API.
+class FocusControllerApiTest : public FocusControllerDirectTestBase {
+ public:
+ FocusControllerApiTest() {}
+
+ private:
+ // Overridden from FocusControllerTestBase:
+ virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
+ FocusWindow(window);
+ }
+ virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
+ ActivateWindow(window);
+ }
+ virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
+ DeactivateWindow(window);
+ }
+ virtual bool IsInputEvent() OVERRIDE { return false; }
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerApiTest);
+};
+
+// Focus and Activation changes via input events.
+class FocusControllerMouseEventTest : public FocusControllerDirectTestBase {
+ public:
+ FocusControllerMouseEventTest() {}
+
+ // Tests that a handled mouse or gesture event does not trigger a window
+ // activation.
+ void IgnoreHandledEvent() {
+ EXPECT_EQ(NULL, GetActiveWindow());
+ aura::Window* w1 = root_window()->GetChildById(1);
+ SimpleEventHandler handler;
+ root_window()->PrependPreTargetHandler(&handler);
+ aura::test::EventGenerator generator(root_window(), w1);
+ generator.ClickLeftButton();
+ EXPECT_EQ(NULL, GetActiveWindow());
+ generator.GestureTapAt(w1->bounds().CenterPoint());
+ EXPECT_EQ(NULL, GetActiveWindow());
+ root_window()->RemovePreTargetHandler(&handler);
+ generator.ClickLeftButton();
+ EXPECT_EQ(1, GetActiveWindowId());
+ }
+
+ private:
+ // Overridden from FocusControllerTestBase:
+ virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
+ aura::test::EventGenerator generator(root_window(), window);
+ generator.ClickLeftButton();
+ }
+ virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
+ aura::test::EventGenerator generator(root_window(), window);
+ generator.ClickLeftButton();
+ }
+ virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
+ aura::Window* next_activatable =
+ test_focus_rules()->GetNextActivatableWindow(window);
+ aura::test::EventGenerator generator(root_window(), next_activatable);
+ generator.ClickLeftButton();
+ }
+ virtual bool IsInputEvent() OVERRIDE { return true; }
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerMouseEventTest);
+};
+
+class FocusControllerGestureEventTest : public FocusControllerDirectTestBase {
+ public:
+ FocusControllerGestureEventTest() {}
+
+ private:
+ // Overridden from FocusControllerTestBase:
+ virtual void FocusWindowDirect(aura::Window* window) OVERRIDE {
+ aura::test::EventGenerator generator(root_window(), window);
+ generator.GestureTapAt(window->bounds().CenterPoint());
+ }
+ virtual void ActivateWindowDirect(aura::Window* window) OVERRIDE {
+ aura::test::EventGenerator generator(root_window(), window);
+ generator.GestureTapAt(window->bounds().CenterPoint());
+ }
+ virtual void DeactivateWindowDirect(aura::Window* window) OVERRIDE {
+ aura::Window* next_activatable =
+ test_focus_rules()->GetNextActivatableWindow(window);
+ aura::test::EventGenerator generator(root_window(), next_activatable);
+ generator.GestureTapAt(window->bounds().CenterPoint());
+ }
+ virtual bool IsInputEvent() OVERRIDE { return true; }
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerGestureEventTest);
+};
+
+// Test base for tests where focus is implicitly set to a window as the result
+// of a disposition change to the focused window or the hierarchy that contains
+// it.
+class FocusControllerImplicitTestBase : public FocusControllerTestBase {
+ protected:
+ explicit FocusControllerImplicitTestBase(bool parent) : parent_(parent) {}
+
+ aura::Window* GetDispositionWindow(aura::Window* window) {
+ return parent_ ? window->parent() : window;
+ }
+
+ // Change the disposition of |window| in such a way as it will lose focus.
+ virtual void ChangeWindowDisposition(aura::Window* window) = 0;
+
+ // Allow each disposition change test to add additional post-disposition
+ // change expectations.
+ virtual void PostDispostionChangeExpectations() {}
+
+ // Overridden from FocusControllerTestBase:
+ virtual void BasicFocus() OVERRIDE {
+ EXPECT_EQ(NULL, GetFocusedWindow());
+
+ aura::Window* w211 = root_window()->GetChildById(211);
+ FocusWindow(w211);
+ EXPECT_EQ(211, GetFocusedWindowId());
+
+ ChangeWindowDisposition(w211);
+ // BasicFocusRules passes focus to the parent.
+ EXPECT_EQ(parent_ ? 2 : 21, GetFocusedWindowId());
+ }
+ virtual void BasicActivation() OVERRIDE {
+ DCHECK(!parent_) << "Activation tests don't support parent changes.";
+
+ EXPECT_EQ(NULL, GetActiveWindow());
+
+ aura::Window* w2 = root_window()->GetChildById(2);
+ ActivateWindow(w2);
+ EXPECT_EQ(2, GetActiveWindowId());
+
+ ChangeWindowDisposition(w2);
+ EXPECT_EQ(3, GetActiveWindowId());
+ PostDispostionChangeExpectations();
+ }
+ virtual void FocusEvents() OVERRIDE {
+ aura::Window* w211 = root_window()->GetChildById(211);
+ FocusWindow(w211);
+
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer211(root_window(), 211);
+ root_observer.ExpectCounts(0, 0);
+ observer211.ExpectCounts(0, 0);
+
+ ChangeWindowDisposition(w211);
+ root_observer.ExpectCounts(0, 1);
+ observer211.ExpectCounts(0, 1);
+ }
+ virtual void ActivationEvents() OVERRIDE {
+ DCHECK(!parent_) << "Activation tests don't support parent changes.";
+
+ aura::Window* w2 = root_window()->GetChildById(2);
+ ActivateWindow(w2);
+
+ ScopedFocusNotificationObserver root_observer(root_window());
+ ScopedTargetFocusNotificationObserver observer2(root_window(), 2);
+ ScopedTargetFocusNotificationObserver observer3(root_window(), 3);
+ root_observer.ExpectCounts(0, 0);
+ observer2.ExpectCounts(0, 0);
+ observer3.ExpectCounts(0, 0);
+
+ ChangeWindowDisposition(w2);
+ root_observer.ExpectCounts(1, 1);
+ observer2.ExpectCounts(1, 1);
+ observer3.ExpectCounts(1, 1);
+ }
+ virtual void FocusRulesOverride() OVERRIDE {
+ EXPECT_EQ(NULL, GetFocusedWindow());
+ aura::Window* w211 = root_window()->GetChildById(211);
+ FocusWindow(w211);
+ EXPECT_EQ(211, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(root_window()->GetChildById(11));
+ ChangeWindowDisposition(w211);
+ // Normally, focus would shift to the parent (w21) but the override shifts
+ // it to 11.
+ EXPECT_EQ(11, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(NULL);
+ }
+ virtual void ActivationRulesOverride() OVERRIDE {
+ DCHECK(!parent_) << "Activation tests don't support parent changes.";
+
+ aura::Window* w1 = root_window()->GetChildById(1);
+ ActivateWindow(w1);
+
+ EXPECT_EQ(1, GetActiveWindowId());
+ EXPECT_EQ(1, GetFocusedWindowId());
+
+ aura::Window* w3 = root_window()->GetChildById(3);
+ test_focus_rules()->set_focus_restriction(w3);
+
+ // Normally, activation/focus would move to w2, but since we have a focus
+ // restriction, it should move to w3 instead.
+ ChangeWindowDisposition(w1);
+ EXPECT_EQ(3, GetActiveWindowId());
+ EXPECT_EQ(3, GetFocusedWindowId());
+
+ test_focus_rules()->set_focus_restriction(NULL);
+ ActivateWindow(root_window()->GetChildById(2));
+ EXPECT_EQ(2, GetActiveWindowId());
+ EXPECT_EQ(2, GetFocusedWindowId());
+ }
+
+ private:
+ // When true, the disposition change occurs to the parent of the window
+ // instead of to the window. This verifies that changes occurring in the
+ // hierarchy that contains the window affect the window's focus.
+ bool parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerImplicitTestBase);
+};
+
+// Focus and Activation changes in response to window visibility changes.
+class FocusControllerHideTest : public FocusControllerImplicitTestBase {
+ public:
+ FocusControllerHideTest() : FocusControllerImplicitTestBase(false) {}
+
+ protected:
+ FocusControllerHideTest(bool parent)
+ : FocusControllerImplicitTestBase(parent) {}
+
+ // Overridden from FocusControllerImplicitTestBase:
+ virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
+ GetDispositionWindow(window)->Hide();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerHideTest);
+};
+
+// Focus and Activation changes in response to window parent visibility
+// changes.
+class FocusControllerParentHideTest : public FocusControllerHideTest {
+ public:
+ FocusControllerParentHideTest() : FocusControllerHideTest(true) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerParentHideTest);
+};
+
+// Focus and Activation changes in response to window destruction.
+class FocusControllerDestructionTest : public FocusControllerImplicitTestBase {
+ public:
+ FocusControllerDestructionTest() : FocusControllerImplicitTestBase(false) {}
+
+ protected:
+ FocusControllerDestructionTest(bool parent)
+ : FocusControllerImplicitTestBase(parent) {}
+
+ // Overridden from FocusControllerImplicitTestBase:
+ virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
+ delete GetDispositionWindow(window);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerDestructionTest);
+};
+
+// Focus and Activation changes in response to window parent destruction.
+class FocusControllerParentDestructionTest
+ : public FocusControllerDestructionTest {
+ public:
+ FocusControllerParentDestructionTest()
+ : FocusControllerDestructionTest(true) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerParentDestructionTest);
+};
+
+// Focus and Activation changes in response to window removal.
+class FocusControllerRemovalTest : public FocusControllerImplicitTestBase {
+ public:
+ FocusControllerRemovalTest() : FocusControllerImplicitTestBase(false) {}
+
+ protected:
+ FocusControllerRemovalTest(bool parent)
+ : FocusControllerImplicitTestBase(parent) {}
+
+ // Overridden from FocusControllerImplicitTestBase:
+ virtual void ChangeWindowDisposition(aura::Window* window) OVERRIDE {
+ aura::Window* disposition_window = GetDispositionWindow(window);
+ disposition_window->parent()->RemoveChild(disposition_window);
+ window_owner_.reset(disposition_window);
+ }
+ virtual void TearDown() OVERRIDE {
+ window_owner_.reset();
+ FocusControllerImplicitTestBase::TearDown();
+ }
+
+ private:
+ scoped_ptr<aura::Window> window_owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerRemovalTest);
+};
+
+// Focus and Activation changes in response to window parent removal.
+class FocusControllerParentRemovalTest : public FocusControllerRemovalTest {
+ public:
+ FocusControllerParentRemovalTest() : FocusControllerRemovalTest(true) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FocusControllerParentRemovalTest);
+};
+
+
+#define FOCUS_CONTROLLER_TEST(TESTCLASS, TESTNAME) \
+ TEST_F(TESTCLASS, TESTNAME) { TESTNAME(); }
+
+// Runs direct focus change tests (input events and API calls).
+#define DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerApiTest, TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerGestureEventTest, TESTNAME)
+
+// Runs implicit focus change tests for disposition changes to target.
+#define IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerHideTest, TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerDestructionTest, TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerRemovalTest, TESTNAME)
+
+// Runs implicit focus change tests for disposition changes to target's parent
+// hierarchy.
+#define IMPLICIT_FOCUS_CHANGE_PARENT_TESTS(TESTNAME) \
+ /* TODO(beng): parent destruction tests are not supported at
+ present due to workspace manager issues. \
+ FOCUS_CONTROLLER_TEST(FocusControllerParentDestructionTest, TESTNAME) */ \
+ FOCUS_CONTROLLER_TEST(FocusControllerParentHideTest, TESTNAME) \
+ FOCUS_CONTROLLER_TEST(FocusControllerParentRemovalTest, TESTNAME)
+
+// Runs all implicit focus change tests (changes to the target and target's
+// parent hierarchy)
+#define IMPLICIT_FOCUS_CHANGE_TESTS(TESTNAME) \
+ IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME) \
+ IMPLICIT_FOCUS_CHANGE_PARENT_TESTS(TESTNAME)
+
+// Runs all possible focus change tests.
+#define ALL_FOCUS_TESTS(TESTNAME) \
+ DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
+ IMPLICIT_FOCUS_CHANGE_TESTS(TESTNAME)
+
+// Runs focus change tests that apply only to the target. For example,
+// implicit activation changes caused by window disposition changes do not
+// occur when changes to the containing hierarchy happen.
+#define TARGET_FOCUS_TESTS(TESTNAME) \
+ DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
+ IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME)
+
+// - Focuses a window, verifies that focus changed.
+ALL_FOCUS_TESTS(BasicFocus);
+
+// - Activates a window, verifies that activation changed.
+TARGET_FOCUS_TESTS(BasicActivation);
+
+// - Focuses a window, verifies that focus events were dispatched.
+ALL_FOCUS_TESTS(FocusEvents);
+
+// - Focuses or activates a window multiple times, verifies that events are only
+// dispatched when focus/activation actually changes.
+DIRECT_FOCUS_CHANGE_TESTS(DuplicateFocusEvents);
+DIRECT_FOCUS_CHANGE_TESTS(DuplicateActivationEvents);
+
+// - Activates a window, verifies that activation events were dispatched.
+TARGET_FOCUS_TESTS(ActivationEvents);
+
+// - Attempts to active a hidden window, verifies that current window is
+// attempted to be reactivated and the appropriate event dispatched.
+FOCUS_CONTROLLER_TEST(FocusControllerApiTest, ReactivationEvents);
+
+// - Input events/API calls shift focus between focusable windows within the
+// active window.
+DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusWithinActiveWindow);
+
+// - Input events/API calls to a child window of an inactive window shifts
+// activation to the activatable parent and focuses the child.
+DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToChildOfInactiveWindow);
+
+// - Input events/API calls to focus the parent of the focused window do not
+// shift focus away from the child.
+DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToParentOfFocusedWindow);
+
+// - Verifies that FocusRules determine what can be focused.
+ALL_FOCUS_TESTS(FocusRulesOverride);
+
+// - Verifies that FocusRules determine what can be activated.
+TARGET_FOCUS_TESTS(ActivationRulesOverride);
+
+// - Verifies that attempts to change focus or activation from a focus or
+// activation change observer are ignored.
+DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivation);
+DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivationDueToHide);
+DIRECT_FOCUS_CHANGE_TESTS(NoShiftActiveOnActivation);
+
+// Clicking on a window which has capture should not result in a focus change.
+DIRECT_FOCUS_CHANGE_TESTS(NoFocusChangeOnClickOnCaptureWindow);
+
+FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
+ ChangeFocusWhenNothingFocusedAndCaptured);
+
+// See description above DontPassDeletedWindow() for details.
+FOCUS_CONTROLLER_TEST(FocusControllerApiTest, DontPassDeletedWindow);
+
+// - Verifies that the focused text input client is cleard when the window focus
+// changes.
+ALL_FOCUS_TESTS(FocusedTextInputClient);
+
+// If a mouse event was handled, it should not activate a window.
+FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, IgnoreHandledEvent);
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/focus_rules.h b/chromium/ui/wm/core/focus_rules.h
new file mode 100644
index 00000000000..cb9a4ddbd8f
--- /dev/null
+++ b/chromium/ui/wm/core/focus_rules.h
@@ -0,0 +1,66 @@
+// 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_WM_CORE_FOCUS_RULES_H_
+#define UI_WM_CORE_FOCUS_RULES_H_
+
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace wm {
+
+// Implemented by an object that establishes the rules about what can be
+// focused or activated.
+class WM_EXPORT FocusRules {
+ public:
+ virtual ~FocusRules() {}
+
+ // Returns true if |window| is a toplevel window. Whether or not a window
+ // is considered toplevel is determined by a similar set of rules that
+ // govern activation and focus. Not all toplevel windows are activatable,
+ // call CanActivateWindow() to determine if a window can be activated.
+ virtual bool IsToplevelWindow(aura::Window* window) const = 0;
+ // Returns true if |window| can be activated or focused.
+ virtual bool CanActivateWindow(aura::Window* window) const = 0;
+ // For CanFocusWindow(), NULL is supported, because NULL is a valid focusable
+ // window (in the case of clearing focus).
+ virtual bool CanFocusWindow(aura::Window* window) const = 0;
+
+ // Returns the toplevel window containing |window|. Not all toplevel windows
+ // are activatable, call GetActivatableWindow() instead to return the
+ // activatable window, which might be in a different hierarchy.
+ // Will return NULL if |window| is not contained by a window considered to be
+ // a toplevel window.
+ virtual aura::Window* GetToplevelWindow(aura::Window* window) const = 0;
+ // Returns the activatable or focusable window given an attempt to activate or
+ // focus |window|. Some possible scenarios (not intended to be exhaustive):
+ // - |window| is a child of a non-focusable window and so focus must be set
+ // according to rules defined by the delegate, e.g. to a parent.
+ // - |window| is an activatable window that is the transient parent of a modal
+ // window, so attempts to activate |window| should result in the modal
+ // transient being activated instead.
+ // These methods may return NULL if they are unable to find an activatable
+ // or focusable window given |window|.
+ virtual aura::Window* GetActivatableWindow(aura::Window* window) const = 0;
+ virtual aura::Window* GetFocusableWindow(aura::Window* window) const = 0;
+
+ // Returns the next window to activate in the event that |ignore| is no longer
+ // activatable. This function is called when something is happening to
+ // |ignore| that means it can no longer have focus or activation, including
+ // but not limited to:
+ // - it or its parent hierarchy is being hidden, or removed from the
+ // RootWindow.
+ // - it is being destroyed.
+ // - it is being explicitly deactivated.
+ // |ignore| cannot be NULL.
+ virtual aura::Window* GetNextActivatableWindow(
+ aura::Window* ignore) const = 0;
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_FOCUS_RULES_H_
diff --git a/chromium/ui/wm/core/image_grid.cc b/chromium/ui/wm/core/image_grid.cc
new file mode 100644
index 00000000000..db41628ea38
--- /dev/null
+++ b/chromium/ui/wm/core/image_grid.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/image_grid.h"
+
+#include <algorithm>
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/transform.h"
+
+using std::max;
+using std::min;
+
+namespace wm {
+namespace {
+
+// Sets the scaling for the transform applied to a layer. The left, top,
+// right and bottom layers are stretched to the height or width of the
+// center image.
+
+void ScaleWidth(gfx::Size center, ui::Layer* layer, gfx::Transform& transform) {
+ float layer_width = layer->bounds().width() * layer->device_scale_factor();
+ float scale = static_cast<float>(center.width()) / layer_width;
+ transform.Scale(scale, 1.0);
+}
+
+void ScaleHeight(gfx::Size center,
+ ui::Layer* layer,
+ gfx::Transform& transform) {
+ float layer_height = layer->bounds().height() * layer->device_scale_factor();
+ float scale = static_cast<float>(center.height()) / layer_height;
+ transform.Scale(1.0, scale);
+}
+
+// Returns the dimensions of |image| if non-NULL or gfx::Size(0, 0) otherwise.
+gfx::Size GetImageSize(const gfx::Image* image) {
+ return image ? gfx::Size(image->ToImageSkia()->width(),
+ image->ToImageSkia()->height())
+ : gfx::Size();
+}
+
+// Returns true if |layer|'s bounds don't fit within |size|.
+bool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size) {
+ return layer->bounds().width() > size.width() ||
+ layer->bounds().height() > size.height();
+}
+
+} // namespace
+
+gfx::RectF ImageGrid::TestAPI::GetTransformedLayerBounds(
+ const ui::Layer& layer) {
+ gfx::RectF bounds = layer.bounds();
+ layer.transform().TransformRect(&bounds);
+ return bounds;
+}
+
+ImageGrid::ImageGrid()
+ : layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)),
+ top_image_height_(0),
+ bottom_image_height_(0),
+ left_image_width_(0),
+ right_image_width_(0),
+ base_top_row_height_(0),
+ base_bottom_row_height_(0),
+ base_left_column_width_(0),
+ base_right_column_width_(0) {
+}
+
+ImageGrid::~ImageGrid() {
+}
+
+void ImageGrid::SetImages(const gfx::Image* top_left_image,
+ const gfx::Image* top_image,
+ const gfx::Image* top_right_image,
+ const gfx::Image* left_image,
+ const gfx::Image* center_image,
+ const gfx::Image* right_image,
+ const gfx::Image* bottom_left_image,
+ const gfx::Image* bottom_image,
+ const gfx::Image* bottom_right_image) {
+ SetImage(top_left_image, &top_left_layer_, &top_left_painter_, NONE);
+ SetImage(top_image, &top_layer_, &top_painter_, HORIZONTAL);
+ SetImage(top_right_image, &top_right_layer_, &top_right_painter_, NONE);
+ SetImage(left_image, &left_layer_, &left_painter_, VERTICAL);
+ SetImage(center_image, &center_layer_, &center_painter_, NONE);
+ SetImage(right_image, &right_layer_, &right_painter_, VERTICAL);
+ SetImage(bottom_left_image, &bottom_left_layer_, &bottom_left_painter_, NONE);
+ SetImage(bottom_image, &bottom_layer_, &bottom_painter_, HORIZONTAL);
+ SetImage(
+ bottom_right_image, &bottom_right_layer_, &bottom_right_painter_, NONE);
+
+ top_image_height_ = GetImageSize(top_image).height();
+ bottom_image_height_ = GetImageSize(bottom_image).height();
+ left_image_width_ = GetImageSize(left_image).width();
+ right_image_width_ = GetImageSize(right_image).width();
+
+ base_top_row_height_ = max(GetImageSize(top_left_image).height(),
+ max(GetImageSize(top_image).height(),
+ GetImageSize(top_right_image).height()));
+ base_bottom_row_height_ = max(GetImageSize(bottom_left_image).height(),
+ max(GetImageSize(bottom_image).height(),
+ GetImageSize(bottom_right_image).height()));
+ base_left_column_width_ = max(GetImageSize(top_left_image).width(),
+ max(GetImageSize(left_image).width(),
+ GetImageSize(bottom_left_image).width()));
+ base_right_column_width_ = max(GetImageSize(top_right_image).width(),
+ max(GetImageSize(right_image).width(),
+ GetImageSize(bottom_right_image).width()));
+
+ // Invalidate previous |size_| so calls to SetSize() will recompute it.
+ size_.SetSize(0, 0);
+}
+
+void ImageGrid::SetSize(const gfx::Size& size) {
+ if (size_ == size)
+ return;
+
+ size_ = size;
+
+ gfx::Rect updated_bounds = layer_->bounds();
+ updated_bounds.set_size(size);
+ layer_->SetBounds(updated_bounds);
+
+ // Calculate the available amount of space for corner images on all sides of
+ // the grid. If the images don't fit, we need to clip them.
+ const int left = min(base_left_column_width_, size_.width() / 2);
+ const int right = min(base_right_column_width_, size_.width() - left);
+ const int top = min(base_top_row_height_, size_.height() / 2);
+ const int bottom = min(base_bottom_row_height_, size_.height() - top);
+
+ // The remaining space goes to the center image.
+ int center_width = std::max(size.width() - left - right, 0);
+ int center_height = std::max(size.height() - top - bottom, 0);
+
+ // At non-integer scale factors, the ratio of dimensions in DIP is not
+ // necessarily the same as the ratio in physical pixels due to rounding. Set
+ // the transform on each of the layers based on dimensions in pixels.
+ gfx::Size center_size_in_pixels = gfx::ToFlooredSize(gfx::ScaleSize(
+ gfx::Size(center_width, center_height), layer_->device_scale_factor()));
+
+ if (top_layer_.get()) {
+ if (center_width > 0) {
+ gfx::Transform transform;
+ transform.Translate(left, 0);
+ ScaleWidth(center_size_in_pixels, top_layer_.get(), transform);
+ top_layer_->SetTransform(transform);
+ }
+ top_layer_->SetVisible(center_width > 0);
+ }
+ if (bottom_layer_.get()) {
+ if (center_width > 0) {
+ gfx::Transform transform;
+ transform.Translate(
+ left, size.height() - bottom_layer_->bounds().height());
+ ScaleWidth(center_size_in_pixels, bottom_layer_.get(), transform);
+ bottom_layer_->SetTransform(transform);
+ }
+ bottom_layer_->SetVisible(center_width > 0);
+ }
+ if (left_layer_.get()) {
+ if (center_height > 0) {
+ gfx::Transform transform;
+ transform.Translate(0, top);
+ ScaleHeight(center_size_in_pixels, left_layer_.get(), transform);
+ left_layer_->SetTransform(transform);
+ }
+ left_layer_->SetVisible(center_height > 0);
+ }
+ if (right_layer_.get()) {
+ if (center_height > 0) {
+ gfx::Transform transform;
+ transform.Translate(
+ size.width() - right_layer_->bounds().width(), top);
+ ScaleHeight(center_size_in_pixels, right_layer_.get(), transform);
+ right_layer_->SetTransform(transform);
+ }
+ right_layer_->SetVisible(center_height > 0);
+ }
+
+ if (top_left_layer_.get()) {
+ // No transformation needed; it should be at (0, 0) and unscaled.
+ top_left_painter_->SetClipRect(
+ LayerExceedsSize(top_left_layer_.get(), gfx::Size(left, top)) ?
+ gfx::Rect(gfx::Rect(0, 0, left, top)) :
+ gfx::Rect(),
+ top_left_layer_.get());
+ }
+ if (top_right_layer_.get()) {
+ gfx::Transform transform;
+ transform.Translate(size.width() - top_right_layer_->bounds().width(), 0.0);
+ top_right_layer_->SetTransform(transform);
+ top_right_painter_->SetClipRect(
+ LayerExceedsSize(top_right_layer_.get(), gfx::Size(right, top)) ?
+ gfx::Rect(top_right_layer_->bounds().width() - right, 0,
+ right, top) :
+ gfx::Rect(),
+ top_right_layer_.get());
+ }
+ if (bottom_left_layer_.get()) {
+ gfx::Transform transform;
+ transform.Translate(
+ 0.0, size.height() - bottom_left_layer_->bounds().height());
+ bottom_left_layer_->SetTransform(transform);
+ bottom_left_painter_->SetClipRect(
+ LayerExceedsSize(bottom_left_layer_.get(), gfx::Size(left, bottom)) ?
+ gfx::Rect(0, bottom_left_layer_->bounds().height() - bottom,
+ left, bottom) :
+ gfx::Rect(),
+ bottom_left_layer_.get());
+ }
+ if (bottom_right_layer_.get()) {
+ gfx::Transform transform;
+ transform.Translate(
+ size.width() - bottom_right_layer_->bounds().width(),
+ size.height() - bottom_right_layer_->bounds().height());
+ bottom_right_layer_->SetTransform(transform);
+ bottom_right_painter_->SetClipRect(
+ LayerExceedsSize(bottom_right_layer_.get(), gfx::Size(right, bottom)) ?
+ gfx::Rect(bottom_right_layer_->bounds().width() - right,
+ bottom_right_layer_->bounds().height() - bottom,
+ right, bottom) :
+ gfx::Rect(),
+ bottom_right_layer_.get());
+ }
+
+ if (center_layer_.get()) {
+ if (center_width > 0 && center_height > 0) {
+ gfx::Transform transform;
+ transform.Translate(left, top);
+ transform.Scale(center_width / center_layer_->bounds().width(),
+ center_height / center_layer_->bounds().height());
+ center_layer_->SetTransform(transform);
+ }
+ center_layer_->SetVisible(center_width > 0 && center_height > 0);
+ }
+}
+
+void ImageGrid::SetContentBounds(const gfx::Rect& content_bounds) {
+
+ SetSize(gfx::Size(
+ content_bounds.width() + left_image_width_ + right_image_width_,
+ content_bounds.height() + top_image_height_ +
+ bottom_image_height_));
+ layer_->SetBounds(
+ gfx::Rect(content_bounds.x() - left_image_width_,
+ content_bounds.y() - top_image_height_,
+ layer_->bounds().width(),
+ layer_->bounds().height()));
+}
+
+void ImageGrid::ImagePainter::SetClipRect(const gfx::Rect& clip_rect,
+ ui::Layer* layer) {
+ if (clip_rect != clip_rect_) {
+ clip_rect_ = clip_rect;
+ layer->SchedulePaint(layer->bounds());
+ }
+}
+
+void ImageGrid::ImagePainter::OnPaintLayer(gfx::Canvas* canvas) {
+ if (!clip_rect_.IsEmpty())
+ canvas->ClipRect(clip_rect_);
+ canvas->DrawImageInt(image_, 0, 0);
+}
+
+void ImageGrid::ImagePainter::OnDeviceScaleFactorChanged(
+ float device_scale_factor) {
+ // Redrawing will take care of scale factor change.
+}
+
+base::Closure ImageGrid::ImagePainter::PrepareForLayerBoundsChange() {
+ return base::Closure();
+}
+
+void ImageGrid::SetImage(const gfx::Image* image,
+ scoped_ptr<ui::Layer>* layer_ptr,
+ scoped_ptr<ImagePainter>* painter_ptr,
+ ImageType type) {
+ // Minimum width (for HORIZONTAL) or height (for VERTICAL) of the
+ // |image| so that layers are scaled property if the device scale
+ // factor is non integral.
+ const int kMinimumSize = 20;
+
+ // Clean out old layers and painters.
+ if (layer_ptr->get())
+ layer_->Remove(layer_ptr->get());
+ layer_ptr->reset();
+ painter_ptr->reset();
+
+ // If we're not using an image, we're done.
+ if (!image)
+ return;
+
+ gfx::ImageSkia image_skia = image->AsImageSkia();
+ switch (type) {
+ case HORIZONTAL:
+ if (image_skia.width() < kMinimumSize) {
+ image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
+ image_skia,
+ skia::ImageOperations::RESIZE_GOOD,
+ gfx::Size(kMinimumSize, image_skia.height()));
+ }
+ break;
+ case VERTICAL:
+ if (image_skia.height() < kMinimumSize) {
+ image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
+ image_skia,
+ skia::ImageOperations::RESIZE_GOOD,
+ gfx::Size(image_skia.width(), kMinimumSize));
+ }
+ break;
+ case NONE:
+ break;
+ }
+
+ // Set up the new layer and painter.
+ layer_ptr->reset(new ui::Layer(ui::LAYER_TEXTURED));
+
+ const gfx::Size size = image_skia.size();
+ layer_ptr->get()->SetBounds(gfx::Rect(0, 0, size.width(), size.height()));
+
+ painter_ptr->reset(new ImagePainter(image_skia));
+ layer_ptr->get()->set_delegate(painter_ptr->get());
+ layer_ptr->get()->SetFillsBoundsOpaquely(false);
+ layer_ptr->get()->SetVisible(true);
+ layer_->Add(layer_ptr->get());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/image_grid.h b/chromium/ui/wm/core/image_grid.h
new file mode 100644
index 00000000000..987ee26c726
--- /dev/null
+++ b/chromium/ui/wm/core/image_grid.h
@@ -0,0 +1,221 @@
+// 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_WM_CORE_IMAGE_GRID_H_
+#define UI_WM_CORE_IMAGE_GRID_H_
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_delegate.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+#include "ui/wm/wm_export.h"
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace wm {
+
+// An ImageGrid is a 3x3 array of ui::Layers, each containing an image.
+//
+// As the grid is resized, its images fill the requested space:
+// - corner images are not scaled
+// - top and bottom images are scaled horizontally
+// - left and right images are scaled vertically
+// - the center image is scaled in both directions
+//
+// If one of the non-center images is smaller than the largest images in its
+// row or column, it will be aligned with the outside of the grid. For
+// example, given 4x4 top-left and top-right images and a 1x2 top images:
+//
+// +--------+---------------------+--------+
+// | | top | |
+// | top- +---------------------+ top- +
+// | left | | right |
+// +----+---+ +---+----+
+// | | | |
+// ...
+//
+// This may seem odd at first, but it lets ImageGrid be used to draw shadows
+// with curved corners that extend inwards beyond a window's borders. In the
+// below example, the top-left corner image is overlaid on top of the window's
+// top-left corner:
+//
+// +---------+-----------------------
+// | ..xxx|XXXXXXXXXXXXXXXXXX
+// | .xXXXXX|XXXXXXXXXXXXXXXXXX_____
+// | .xXX | ^ window's top edge
+// | .xXX |
+// +---------+
+// | xXX|
+// | xXX|< window's left edge
+// | xXX|
+// ...
+//
+class WM_EXPORT ImageGrid {
+ public:
+ // Helper class for use by tests.
+ class WM_EXPORT TestAPI {
+ public:
+ TestAPI(ImageGrid* grid) : grid_(grid) {}
+
+ gfx::Rect top_left_clip_rect() const {
+ return grid_->top_left_painter_->clip_rect_;
+ }
+ gfx::Rect top_right_clip_rect() const {
+ return grid_->top_right_painter_->clip_rect_;
+ }
+ gfx::Rect bottom_left_clip_rect() const {
+ return grid_->bottom_left_painter_->clip_rect_;
+ }
+ gfx::Rect bottom_right_clip_rect() const {
+ return grid_->bottom_right_painter_->clip_rect_;
+ }
+
+ // Returns |layer|'s bounds after applying the layer's current transform.
+ gfx::RectF GetTransformedLayerBounds(const ui::Layer& layer);
+
+ private:
+ ImageGrid* grid_; // not owned
+
+ DISALLOW_COPY_AND_ASSIGN(TestAPI);
+ };
+
+ ImageGrid();
+ ~ImageGrid();
+
+ ui::Layer* layer() { return layer_.get(); }
+ int top_image_height() const { return top_image_height_; }
+ int bottom_image_height() const { return bottom_image_height_; }
+ int left_image_width() const { return left_image_width_; }
+ int right_image_width() const { return right_image_width_; }
+
+ // Visible to allow independent layer animations and for testing.
+ ui::Layer* top_left_layer() const { return top_left_layer_.get(); }
+ ui::Layer* top_layer() const { return top_layer_.get(); }
+ ui::Layer* top_right_layer() const { return top_right_layer_.get(); }
+ ui::Layer* left_layer() const { return left_layer_.get(); }
+ ui::Layer* center_layer() const { return center_layer_.get(); }
+ ui::Layer* right_layer() const { return right_layer_.get(); }
+ ui::Layer* bottom_left_layer() const { return bottom_left_layer_.get(); }
+ ui::Layer* bottom_layer() const { return bottom_layer_.get(); }
+ ui::Layer* bottom_right_layer() const { return bottom_right_layer_.get(); }
+
+ // Sets the grid to display the passed-in images (any of which can be NULL).
+ // Ownership of the images remains with the caller. May be called more than
+ // once to switch images.
+ void SetImages(const gfx::Image* top_left_image,
+ const gfx::Image* top_image,
+ const gfx::Image* top_right_image,
+ const gfx::Image* left_image,
+ const gfx::Image* center_image,
+ const gfx::Image* right_image,
+ const gfx::Image* bottom_left_image,
+ const gfx::Image* bottom_image,
+ const gfx::Image* bottom_right_image);
+
+ void SetSize(const gfx::Size& size);
+
+ // Sets the grid to a position and size such that the inner edges of the top,
+ // bottom, left and right images will be flush with |content_bounds_in_dip|.
+ void SetContentBounds(const gfx::Rect& content_bounds_in_dip);
+
+ private:
+ // Delegate responsible for painting a specific image on a layer.
+ class ImagePainter : public ui::LayerDelegate {
+ public:
+ ImagePainter(const gfx::ImageSkia& image) : image_(image) {}
+ virtual ~ImagePainter() {}
+
+ // Clips |layer| to |clip_rect|. Triggers a repaint if the clipping
+ // rectangle has changed. An empty rectangle disables clipping.
+ void SetClipRect(const gfx::Rect& clip_rect, ui::Layer* layer);
+
+ // ui::LayerDelegate implementation:
+ virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
+ virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
+ virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE;
+
+ private:
+ friend class TestAPI;
+
+ const gfx::ImageSkia image_;
+
+ gfx::Rect clip_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImagePainter);
+ };
+
+ enum ImageType {
+ HORIZONTAL,
+ VERTICAL,
+ NONE,
+ };
+
+ // Sets |layer_ptr| and |painter_ptr| to display |image| and adds the
+ // passed-in layer to |layer_|. If image is NULL resets |layer_ptr| and
+ // |painter_ptr| and removes any existing layer from |layer_|.
+ // If |type| is either HORIZONTAL or VERTICAL, it may resize the image to
+ // guarantee that it has minimum size in order for scaling work properly
+ // with fractional device scale factors. crbug.com/376519.
+ void SetImage(const gfx::Image* image,
+ scoped_ptr<ui::Layer>* layer_ptr,
+ scoped_ptr<ImagePainter>* painter_ptr,
+ ImageType type);
+
+ // Layer that contains all of the image layers.
+ scoped_ptr<ui::Layer> layer_;
+
+ // The grid's dimensions.
+ gfx::Size size_;
+
+ // Heights and widths of the images displayed by |top_layer_|,
+ // |bottom_layer_|, |left_layer_|, and |right_layer_|.
+ int top_image_height_;
+ int bottom_image_height_;
+ int left_image_width_;
+ int right_image_width_;
+
+ // Heights of the tallest images in the top and bottom rows and the widest
+ // images in the left and right columns. Note that we may have less actual
+ // space than this available if the images are large and |size_| is small.
+ int base_top_row_height_;
+ int base_bottom_row_height_;
+ int base_left_column_width_;
+ int base_right_column_width_;
+
+ // Layers used to display the various images. Children of |layer_|.
+ // Positions for which no images were supplied are NULL.
+ scoped_ptr<ui::Layer> top_left_layer_;
+ scoped_ptr<ui::Layer> top_layer_;
+ scoped_ptr<ui::Layer> top_right_layer_;
+ scoped_ptr<ui::Layer> left_layer_;
+ scoped_ptr<ui::Layer> center_layer_;
+ scoped_ptr<ui::Layer> right_layer_;
+ scoped_ptr<ui::Layer> bottom_left_layer_;
+ scoped_ptr<ui::Layer> bottom_layer_;
+ scoped_ptr<ui::Layer> bottom_right_layer_;
+
+ // Delegates responsible for painting the above layers.
+ // Positions for which no images were supplied are NULL.
+ scoped_ptr<ImagePainter> top_left_painter_;
+ scoped_ptr<ImagePainter> top_painter_;
+ scoped_ptr<ImagePainter> top_right_painter_;
+ scoped_ptr<ImagePainter> left_painter_;
+ scoped_ptr<ImagePainter> center_painter_;
+ scoped_ptr<ImagePainter> right_painter_;
+ scoped_ptr<ImagePainter> bottom_left_painter_;
+ scoped_ptr<ImagePainter> bottom_painter_;
+ scoped_ptr<ImagePainter> bottom_right_painter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageGrid);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_IMAGE_GRID_H_
diff --git a/chromium/ui/wm/core/image_grid_unittest.cc b/chromium/ui/wm/core/image_grid_unittest.cc
new file mode 100644
index 00000000000..4b413e44af0
--- /dev/null
+++ b/chromium/ui/wm/core/image_grid_unittest.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/image_grid.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace wm {
+
+namespace {
+
+// Creates a gfx::Image with the requested dimensions.
+gfx::Image* CreateImage(const gfx::Size& size) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
+ return new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
+}
+
+} // namespace
+
+typedef aura::test::AuraTestBase ImageGridTest;
+
+// Test that an ImageGrid's layers are transformed correctly when SetSize() is
+// called.
+TEST_F(ImageGridTest, Basic) {
+ // Size of the images around the grid's border.
+ const int kBorder = 2;
+
+ scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
+ scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
+ scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
+ scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
+
+ ImageGrid grid;
+ grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
+ image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
+ image_BxB.get(), image_1xB.get(), image_BxB.get());
+
+ ImageGrid::TestAPI test_api(&grid);
+ ASSERT_TRUE(grid.top_left_layer() != NULL);
+ ASSERT_TRUE(grid.top_layer() != NULL);
+ ASSERT_TRUE(grid.top_right_layer() != NULL);
+ ASSERT_TRUE(grid.left_layer() != NULL);
+ ASSERT_TRUE(grid.center_layer() != NULL);
+ ASSERT_TRUE(grid.right_layer() != NULL);
+ ASSERT_TRUE(grid.bottom_left_layer() != NULL);
+ ASSERT_TRUE(grid.bottom_layer() != NULL);
+ ASSERT_TRUE(grid.bottom_right_layer() != NULL);
+
+ const gfx::Size size(20, 30);
+ grid.SetSize(size);
+
+ // The top-left layer should be flush with the top-left corner and unscaled.
+ EXPECT_EQ(gfx::RectF(0, 0, kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.top_left_layer()).ToString());
+
+ // The top layer should be flush with the top edge and stretched horizontally
+ // between the two top corners.
+ EXPECT_EQ(gfx::RectF(
+ kBorder, 0, size.width() - 2 * kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.top_layer()).ToString());
+
+ // The top-right layer should be flush with the top-right corner and unscaled.
+ EXPECT_EQ(gfx::RectF(size.width() - kBorder, 0, kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.top_right_layer()).ToString());
+
+ // The left layer should be flush with the left edge and stretched vertically
+ // between the two left corners.
+ EXPECT_EQ(gfx::RectF(
+ 0, kBorder, kBorder, size.height() - 2 * kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.left_layer()).ToString());
+
+ // The center layer should fill the space in the middle of the grid.
+ EXPECT_EQ(gfx::RectF(
+ kBorder, kBorder, size.width() - 2 * kBorder,
+ size.height() - 2 * kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.center_layer()).ToString());
+
+ // The right layer should be flush with the right edge and stretched
+ // vertically between the two right corners.
+ EXPECT_EQ(gfx::RectF(
+ size.width() - kBorder, kBorder,
+ kBorder, size.height() - 2 * kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.right_layer()).ToString());
+
+ // The bottom-left layer should be flush with the bottom-left corner and
+ // unscaled.
+ EXPECT_EQ(gfx::RectF(0, size.height() - kBorder, kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.bottom_left_layer()).ToString());
+
+ // The bottom layer should be flush with the bottom edge and stretched
+ // horizontally between the two bottom corners.
+ EXPECT_EQ(gfx::RectF(
+ kBorder, size.height() - kBorder,
+ size.width() - 2 * kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.bottom_layer()).ToString());
+
+ // The bottom-right layer should be flush with the bottom-right corner and
+ // unscaled.
+ EXPECT_EQ(gfx::RectF(
+ size.width() - kBorder, size.height() - kBorder,
+ kBorder, kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.bottom_right_layer()).ToString());
+}
+
+// Test that an ImageGrid's layers are transformed correctly when
+// SetContentBounds() is called.
+TEST_F(ImageGridTest, SetContentBounds) {
+ // Size of the images around the grid's border.
+ const int kBorder = 2;
+
+ scoped_ptr<gfx::Image> image_1x1(CreateImage(gfx::Size(1, 1)));
+ scoped_ptr<gfx::Image> image_1xB(CreateImage(gfx::Size(1, kBorder)));
+ scoped_ptr<gfx::Image> image_Bx1(CreateImage(gfx::Size(kBorder, 1)));
+ scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder)));
+
+ ImageGrid grid;
+ grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(),
+ image_Bx1.get(), image_1x1.get(), image_Bx1.get(),
+ image_BxB.get(), image_1xB.get(), image_BxB.get());
+
+ ImageGrid::TestAPI test_api(&grid);
+
+ const gfx::Point origin(5, 10);
+ const gfx::Size size(20, 30);
+ grid.SetContentBounds(gfx::Rect(origin, size));
+
+ // The master layer is positioned above the top-left corner of the content
+ // bounds and has height/width that contain the grid and bounds.
+ EXPECT_EQ(gfx::RectF(origin.x() - kBorder,
+ origin.y() - kBorder,
+ size.width() + 2 * kBorder,
+ size.height() + 2 * kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(*grid.layer()).ToString());
+}
+
+// Check that we don't crash if only a single image is supplied.
+TEST_F(ImageGridTest, SingleImage) {
+ const int kBorder = 1;
+ scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
+
+ ImageGrid grid;
+ grid.SetImages(NULL, image.get(), NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+
+ ImageGrid::TestAPI test_api(&grid);
+ EXPECT_TRUE(grid.top_left_layer() == NULL);
+ ASSERT_TRUE(grid.top_layer() != NULL);
+ EXPECT_TRUE(grid.top_right_layer() == NULL);
+ EXPECT_TRUE(grid.left_layer() == NULL);
+ EXPECT_TRUE(grid.center_layer() == NULL);
+ EXPECT_TRUE(grid.right_layer() == NULL);
+ EXPECT_TRUE(grid.bottom_left_layer() == NULL);
+ EXPECT_TRUE(grid.bottom_layer() == NULL);
+ EXPECT_TRUE(grid.bottom_right_layer() == NULL);
+
+ const gfx::Size kSize(10, 10);
+ grid.SetSize(kSize);
+
+ // The top layer should be scaled horizontally across the entire width, but it
+ // shouldn't be scaled vertically.
+ EXPECT_EQ(gfx::RectF(0, 0, kSize.width(), kBorder).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.top_layer()).ToString());
+}
+
+// Check that we don't crash when we reset existing images to NULL and
+// reset NULL images to new ones.
+TEST_F(ImageGridTest, ResetImages) {
+ const int kBorder = 1;
+ scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder)));
+
+ ImageGrid grid;
+ grid.SetImages(NULL, image.get(), NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+
+ // Only the top edge has a layer.
+ ImageGrid::TestAPI test_api(&grid);
+ ASSERT_TRUE(grid.top_left_layer() == NULL);
+ ASSERT_FALSE(grid.top_layer() == NULL);
+ ASSERT_TRUE(grid.top_right_layer() == NULL);
+ ASSERT_TRUE(grid.left_layer() == NULL);
+ ASSERT_TRUE(grid.center_layer() == NULL);
+ ASSERT_TRUE(grid.right_layer() == NULL);
+ ASSERT_TRUE(grid.bottom_left_layer() == NULL);
+ ASSERT_TRUE(grid.bottom_layer() == NULL);
+ ASSERT_TRUE(grid.bottom_right_layer() == NULL);
+
+ grid.SetImages(NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, image.get(), NULL);
+
+ // Now only the bottom edge has a layer.
+ ASSERT_TRUE(grid.top_left_layer() == NULL);
+ ASSERT_TRUE(grid.top_layer() == NULL);
+ ASSERT_TRUE(grid.top_right_layer() == NULL);
+ ASSERT_TRUE(grid.left_layer() == NULL);
+ ASSERT_TRUE(grid.center_layer() == NULL);
+ ASSERT_TRUE(grid.right_layer() == NULL);
+ ASSERT_TRUE(grid.bottom_left_layer() == NULL);
+ ASSERT_FALSE(grid.bottom_layer() == NULL);
+ ASSERT_TRUE(grid.bottom_right_layer() == NULL);
+}
+
+// Test that side (top, left, right, bottom) layers that are narrower than their
+// adjacent corner layers stay pinned to the outside edges instead of getting
+// moved inwards or scaled. This exercises the scenario used for shadows.
+TEST_F(ImageGridTest, SmallerSides) {
+ const int kCorner = 2;
+ const int kEdge = 1;
+
+ scoped_ptr<gfx::Image> top_left_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+ scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> top_right_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+ scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
+
+ ImageGrid grid;
+ grid.SetImages(top_left_image.get(), top_image.get(), top_right_image.get(),
+ left_image.get(), NULL, right_image.get(),
+ NULL, NULL, NULL);
+ ImageGrid::TestAPI test_api(&grid);
+
+ const gfx::Size kSize(20, 30);
+ grid.SetSize(kSize);
+
+ // The top layer should be flush with the top edge and stretched horizontally
+ // between the two top corners.
+ EXPECT_EQ(gfx::RectF(
+ kCorner, 0, kSize.width() - 2 * kCorner, kEdge).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.top_layer()).ToString());
+
+ // The left layer should be flush with the left edge and stretched vertically
+ // between the top left corner and the bottom.
+ EXPECT_EQ(gfx::RectF(
+ 0, kCorner, kEdge, kSize.height() - kCorner).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.left_layer()).ToString());
+
+ // The right layer should be flush with the right edge and stretched
+ // vertically between the top right corner and the bottom.
+ EXPECT_EQ(gfx::RectF(
+ kSize.width() - kEdge, kCorner,
+ kEdge, kSize.height() - kCorner).ToString(),
+ test_api.GetTransformedLayerBounds(
+ *grid.right_layer()).ToString());
+}
+
+// Test that we hide or clip layers as needed when the grid is assigned a small
+// size.
+TEST_F(ImageGridTest, TooSmall) {
+ const int kCorner = 5;
+ const int kCenter = 3;
+ const int kEdge = 3;
+
+ scoped_ptr<gfx::Image> top_left_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+ scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> top_right_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+ scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> center_image(CreateImage(gfx::Size(kCenter, kCenter)));
+ scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> bottom_left_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+ scoped_ptr<gfx::Image> bottom_image(CreateImage(gfx::Size(kEdge, kEdge)));
+ scoped_ptr<gfx::Image> bottom_right_image(
+ CreateImage(gfx::Size(kCorner, kCorner)));
+
+ ImageGrid grid;
+ grid.SetImages(
+ top_left_image.get(), top_image.get(), top_right_image.get(),
+ left_image.get(), center_image.get(), right_image.get(),
+ bottom_left_image.get(), bottom_image.get(), bottom_right_image.get());
+ ImageGrid::TestAPI test_api(&grid);
+
+ // Set a size that's smaller than the combined (unscaled) corner images.
+ const gfx::Size kSmallSize(kCorner + kCorner - 3, kCorner + kCorner - 5);
+ grid.SetSize(kSmallSize);
+
+ // The scalable images around the sides and in the center should be hidden.
+ EXPECT_FALSE(grid.top_layer()->visible());
+ EXPECT_FALSE(grid.bottom_layer()->visible());
+ EXPECT_FALSE(grid.left_layer()->visible());
+ EXPECT_FALSE(grid.right_layer()->visible());
+ EXPECT_FALSE(grid.center_layer()->visible());
+
+ // The corner images' clip rects should sum to the expected size.
+ EXPECT_EQ(kSmallSize.width(),
+ test_api.top_left_clip_rect().width() +
+ test_api.top_right_clip_rect().width());
+ EXPECT_EQ(kSmallSize.width(),
+ test_api.bottom_left_clip_rect().width() +
+ test_api.bottom_right_clip_rect().width());
+ EXPECT_EQ(kSmallSize.height(),
+ test_api.top_left_clip_rect().height() +
+ test_api.bottom_left_clip_rect().height());
+ EXPECT_EQ(kSmallSize.height(),
+ test_api.top_right_clip_rect().height() +
+ test_api.bottom_right_clip_rect().height());
+
+ // Resize the grid to be large enough to show all images.
+ const gfx::Size kLargeSize(kCorner + kCorner + kCenter,
+ kCorner + kCorner + kCenter);
+ grid.SetSize(kLargeSize);
+
+ // The scalable images should be visible now.
+ EXPECT_TRUE(grid.top_layer()->visible());
+ EXPECT_TRUE(grid.bottom_layer()->visible());
+ EXPECT_TRUE(grid.left_layer()->visible());
+ EXPECT_TRUE(grid.right_layer()->visible());
+ EXPECT_TRUE(grid.center_layer()->visible());
+
+ // We shouldn't be clipping the corner images anymore.
+ EXPECT_TRUE(test_api.top_left_clip_rect().IsEmpty());
+ EXPECT_TRUE(test_api.top_right_clip_rect().IsEmpty());
+ EXPECT_TRUE(test_api.bottom_left_clip_rect().IsEmpty());
+ EXPECT_TRUE(test_api.bottom_right_clip_rect().IsEmpty());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/input_method_event_filter.cc b/chromium/ui/wm/core/input_method_event_filter.cc
new file mode 100644
index 00000000000..3488e4adb8c
--- /dev/null
+++ b/chromium/ui/wm/core/input_method_event_filter.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/input_method_event_filter.h"
+
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event.h"
+#include "ui/events/event_processor.h"
+
+namespace wm {
+
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodEventFilter, public:
+
+InputMethodEventFilter::InputMethodEventFilter(gfx::AcceleratedWidget widget)
+ : input_method_(ui::CreateInputMethod(this, widget)) {
+ // TODO(yusukes): Check if the root window is currently focused and pass the
+ // result to Init().
+ input_method_->Init(true);
+}
+
+InputMethodEventFilter::~InputMethodEventFilter() {
+}
+
+void InputMethodEventFilter::SetInputMethodPropertyInRootWindow(
+ aura::Window* root_window) {
+ root_window->SetProperty(aura::client::kRootWindowInputMethodKey,
+ input_method_.get());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodEventFilter, EventFilter implementation:
+
+void InputMethodEventFilter::OnKeyEvent(ui::KeyEvent* event) {
+ // We're processing key events as follows (details are simplified).
+ //
+ // At the beginning, key events have a ET_KEY_{PRESSED,RELEASED} event type,
+ // and they're passed from step 1 through step 3.
+ // 1. EventProcessor::OnEventFromSource()
+ // 2. InputMethodEventFilter::OnKeyEvent()
+ // 3. InputMethod::DispatchKeyEvent()
+ // where InputMethod may call DispatchKeyEventPostIME() if IME didn't consume
+ // the key event. Otherwise, step 4 through step 6 are skipped and we fall
+ // down to step 7 directly.
+ // 4. InputMethodEventFilter::DispatchKeyEventPostIME()
+ // where the key event is marked as TRANSLATED and the event type becomes
+ // ET_TRANSLATED_KEY_{PRESS,RELEASE}. Then, we dispatch the event again from
+ // the beginning.
+ // 5. EventProcessor::OnEventFromSource() [second time]
+ // 6. InputMethodEventFilter::OnKeyEvent() [second time]
+ // where we know that the event was already processed once by IME and
+ // re-dispatched, we don't pass the event to IME again. Instead we unmark the
+ // event as not translated (as same as the original state), and let the event
+ // dispatcher continue to dispatch the event to the rest event handlers.
+ // 7. EventHandler::OnKeyEvent()
+ if (event->IsTranslated()) {
+ // The |event| was already processed by IME, so we don't pass the event to
+ // IME again. Just let the event dispatcher continue to dispatch the event.
+ event->SetTranslated(false);
+ } else {
+ if (input_method_->DispatchKeyEvent(*event))
+ event->StopPropagation();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodEventFilter, ui::InputMethodDelegate implementation:
+
+bool InputMethodEventFilter::DispatchKeyEventPostIME(
+ const ui::KeyEvent& event) {
+#if defined(OS_WIN)
+ DCHECK(!event.HasNativeEvent() || event.native_event().message != WM_CHAR);
+#endif
+ // Since the underlying IME didn't consume the key event, we're going to
+ // dispatch the event again from the beginning of the tree of event targets.
+ // This time we have to skip dispatching the event to the IME, we mark the
+ // event as TRANSLATED so we can distinguish this event as a second time
+ // dispatched event.
+ // For the target where to dispatch the event, always tries the current
+ // focused text input client's attached window. And fallback to the target
+ // carried by event.
+ aura::Window* target_window = NULL;
+ ui::TextInputClient* input = input_method_->GetTextInputClient();
+ if (input)
+ target_window = input->GetAttachedWindow();
+ if (!target_window)
+ target_window = static_cast<aura::Window*>(event.target());
+ if (!target_window)
+ return false;
+ ui::EventProcessor* target_dispatcher =
+ target_window->GetRootWindow()->GetHost()->event_processor();
+ ui::KeyEvent aura_event(event);
+ aura_event.SetTranslated(true);
+ ui::EventDispatchDetails details =
+ target_dispatcher->OnEventFromSource(&aura_event);
+ CHECK(!details.dispatcher_destroyed);
+ return aura_event.handled();
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/input_method_event_filter.h b/chromium/ui/wm/core/input_method_event_filter.h
new file mode 100644
index 00000000000..af823089b13
--- /dev/null
+++ b/chromium/ui/wm/core/input_method_event_filter.h
@@ -0,0 +1,50 @@
+// 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_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
+#define UI_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/ime/input_method_delegate.h"
+#include "ui/events/event_handler.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/wm/wm_export.h"
+
+namespace ui {
+class EventProcessor;
+class InputMethod;
+}
+
+namespace wm {
+
+// An event filter that forwards a KeyEvent to a system IME, and dispatches a
+// TranslatedKeyEvent to the root window as needed.
+class WM_EXPORT InputMethodEventFilter
+ : public ui::EventHandler,
+ public ui::internal::InputMethodDelegate {
+ public:
+ explicit InputMethodEventFilter(gfx::AcceleratedWidget widget);
+ virtual ~InputMethodEventFilter();
+
+ void SetInputMethodPropertyInRootWindow(aura::Window* root_window);
+
+ ui::InputMethod* input_method() const { return input_method_.get(); }
+
+ private:
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+
+ // Overridden from ui::internal::InputMethodDelegate:
+ virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) OVERRIDE;
+
+ scoped_ptr<ui::InputMethod> input_method_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilter);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
diff --git a/chromium/ui/wm/core/input_method_event_filter_unittest.cc b/chromium/ui/wm/core/input_method_event_filter_unittest.cc
new file mode 100644
index 00000000000..50c1fbc0c55
--- /dev/null
+++ b/chromium/ui/wm/core/input_method_event_filter_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/input_method_event_filter.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/text_input_focus_manager.h"
+#include "ui/base/ui_base_switches_util.h"
+#include "ui/events/test/test_event_handler.h"
+#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/core/default_activation_client.h"
+#include "ui/wm/public/activation_client.h"
+
+#if !defined(OS_WIN) && !defined(USE_X11)
+// On platforms except Windows and X11, aura::test::EventGenerator::PressKey
+// generates a key event without native_event(), which is not supported by
+// ui::MockInputMethod.
+#define TestInputMethodKeyEventPropagation \
+DISABLED_TestInputMethodKeyEventPropagation
+#endif
+
+namespace wm {
+
+class TestTextInputClient : public ui::DummyTextInputClient {
+ public:
+ explicit TestTextInputClient(aura::Window* window) : window_(window) {}
+
+ virtual aura::Window* GetAttachedWindow() const OVERRIDE { return window_; }
+
+ private:
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
+};
+
+class InputMethodEventFilterTest : public aura::test::AuraTestBase {
+ public:
+ InputMethodEventFilterTest() {}
+ virtual ~InputMethodEventFilterTest() {}
+
+ // testing::Test overrides:
+ virtual void SetUp() OVERRIDE {
+ aura::test::AuraTestBase::SetUp();
+
+ root_window()->AddPreTargetHandler(&root_filter_);
+ input_method_event_filter_.reset(
+ new InputMethodEventFilter(host()->GetAcceleratedWidget()));
+ input_method_event_filter_->SetInputMethodPropertyInRootWindow(
+ root_window());
+ root_filter_.AddHandler(input_method_event_filter_.get());
+ root_filter_.AddHandler(&test_filter_);
+
+ test_window_.reset(aura::test::CreateTestWindowWithDelegate(
+ &test_window_delegate_, -1, gfx::Rect(), root_window()));
+ test_input_client_.reset(new TestTextInputClient(test_window_.get()));
+
+ input_method_event_filter_->input_method()->SetFocusedTextInputClient(
+ test_input_client_.get());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ test_window_.reset();
+ root_filter_.RemoveHandler(&test_filter_);
+ root_filter_.RemoveHandler(input_method_event_filter_.get());
+ root_window()->RemovePreTargetHandler(&root_filter_);
+
+ input_method_event_filter_.reset();
+ test_input_client_.reset();
+ aura::test::AuraTestBase::TearDown();
+ }
+
+ protected:
+ CompoundEventFilter root_filter_;
+ ui::test::TestEventHandler test_filter_;
+ scoped_ptr<InputMethodEventFilter> input_method_event_filter_;
+ aura::test::TestWindowDelegate test_window_delegate_;
+ scoped_ptr<aura::Window> test_window_;
+ scoped_ptr<TestTextInputClient> test_input_client_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilterTest);
+};
+
+TEST_F(InputMethodEventFilterTest, TestInputMethodProperty) {
+ // Tests if InputMethodEventFilter adds a window property on its
+ // construction.
+ EXPECT_TRUE(root_window()->GetProperty(
+ aura::client::kRootWindowInputMethodKey));
+}
+
+// Tests if InputMethodEventFilter dispatches a ui::ET_TRANSLATED_KEY_* event to
+// the root window.
+TEST_F(InputMethodEventFilterTest, TestInputMethodKeyEventPropagation) {
+ // Send a fake key event to the root window. InputMethodEventFilter, which is
+ // automatically set up by AshTestBase, consumes it and sends a new
+ // ui::ET_TRANSLATED_KEY_* event to the root window, which will be consumed by
+ // the test event filter.
+ aura::test::EventGenerator generator(root_window());
+ EXPECT_EQ(0, test_filter_.num_key_events());
+ generator.PressKey(ui::VKEY_SPACE, 0);
+ EXPECT_EQ(1, test_filter_.num_key_events());
+ generator.ReleaseKey(ui::VKEY_SPACE, 0);
+ EXPECT_EQ(2, test_filter_.num_key_events());
+}
+
+TEST_F(InputMethodEventFilterTest, TestEventDispatching) {
+ ui::KeyEvent evt(ui::ET_KEY_PRESSED,
+ ui::VKEY_PROCESSKEY,
+ ui::EF_IME_FABRICATED_KEY,
+ false);
+ // Calls DispatchKeyEventPostIME() without a focused text input client.
+ if (switches::IsTextInputFocusManagerEnabled())
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL);
+ else
+ input_method_event_filter_->input_method()->SetFocusedTextInputClient(NULL);
+ input_method_event_filter_->input_method()->DispatchKeyEvent(evt);
+ // Verifies 0 key event happened because InputMethodEventFilter::
+ // DispatchKeyEventPostIME() returns false.
+ EXPECT_EQ(0, test_filter_.num_key_events());
+
+ // Calls DispatchKeyEventPostIME() with a focused text input client.
+ if (switches::IsTextInputFocusManagerEnabled()) {
+ ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(
+ test_input_client_.get());
+ } else {
+ input_method_event_filter_->input_method()->SetFocusedTextInputClient(
+ test_input_client_.get());
+ }
+ input_method_event_filter_->input_method()->DispatchKeyEvent(evt);
+ // Verifies 1 key event happened because InputMethodEventFilter::
+ // DispatchKeyEventPostIME() returns true.
+ EXPECT_EQ(1, test_filter_.num_key_events());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/masked_window_targeter.cc b/chromium/ui/wm/core/masked_window_targeter.cc
new file mode 100644
index 00000000000..5cbdb1993b1
--- /dev/null
+++ b/chromium/ui/wm/core/masked_window_targeter.cc
@@ -0,0 +1,43 @@
+// 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/wm/core/masked_window_targeter.h"
+
+#include "ui/aura/window.h"
+#include "ui/gfx/path.h"
+
+namespace wm {
+
+MaskedWindowTargeter::MaskedWindowTargeter(aura::Window* masked_window)
+ : masked_window_(masked_window) {
+}
+
+MaskedWindowTargeter::~MaskedWindowTargeter() {}
+
+bool MaskedWindowTargeter::EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const {
+ aura::Window* window = static_cast<aura::Window*>(target);
+ if (window == masked_window_) {
+ gfx::Path mask;
+ if (!GetHitTestMask(window, &mask))
+ return WindowTargeter::EventLocationInsideBounds(window, event);
+
+ gfx::Size size = window->bounds().size();
+ SkRegion clip_region;
+ clip_region.setRect(0, 0, size.width(), size.height());
+
+ gfx::Point point = event.location();
+ if (window->parent())
+ aura::Window::ConvertPointToTarget(window->parent(), window, &point);
+
+ SkRegion mask_region;
+ return mask_region.setPath(mask, clip_region) &&
+ mask_region.contains(point.x(), point.y());
+ }
+
+ return WindowTargeter::EventLocationInsideBounds(window, event);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/masked_window_targeter.h b/chromium/ui/wm/core/masked_window_targeter.h
new file mode 100644
index 00000000000..61bb3b1eeb4
--- /dev/null
+++ b/chromium/ui/wm/core/masked_window_targeter.h
@@ -0,0 +1,40 @@
+// 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_WM_CORE_MASKED_WINDOW_TARGETER_H_
+#define UI_WM_CORE_MASKED_WINDOW_TARGETER_H_
+
+#include "ui/aura/window_targeter.h"
+#include "ui/wm/wm_export.h"
+
+namespace gfx {
+class Path;
+}
+
+namespace wm {
+
+class WM_EXPORT MaskedWindowTargeter : public aura::WindowTargeter {
+ public:
+ explicit MaskedWindowTargeter(aura::Window* masked_window);
+ virtual ~MaskedWindowTargeter();
+
+ protected:
+ // Sets the hit-test mask for |window| in |mask| (in |window|'s local
+ // coordinate system). Returns whether a valid mask has been set in |mask|.
+ virtual bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const = 0;
+
+ // ui::EventTargeter:
+ virtual bool EventLocationInsideBounds(
+ ui::EventTarget* target,
+ const ui::LocatedEvent& event) const OVERRIDE;
+
+ private:
+ aura::Window* masked_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaskedWindowTargeter);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_MASKED_WINDOW_TARGETER_H_
diff --git a/chromium/ui/wm/core/native_cursor_manager.h b/chromium/ui/wm/core/native_cursor_manager.h
new file mode 100644
index 00000000000..de16ef8ce2d
--- /dev/null
+++ b/chromium/ui/wm/core/native_cursor_manager.h
@@ -0,0 +1,61 @@
+// 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_WM_CORE_NATIVE_CURSOR_MANAGER_H_
+#define UI_WM_CORE_NATIVE_CURSOR_MANAGER_H_
+
+#include "base/strings/string16.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/wm/core/native_cursor_manager_delegate.h"
+#include "ui/wm/wm_export.h"
+
+namespace gfx {
+class Display;
+}
+
+namespace wm {
+
+// Interface where platforms such as Ash or Desktop aura are notified of
+// requested changes to cursor state. When requested, implementer should tell
+// the CursorManager of any actual state changes performed through the
+// delegate.
+class WM_EXPORT NativeCursorManager {
+ public:
+ virtual ~NativeCursorManager() {}
+
+ // A request to set the screen DPI. Can cause changes in the current cursor.
+ virtual void SetDisplay(
+ const gfx::Display& display,
+ NativeCursorManagerDelegate* delegate) = 0;
+
+ // A request to set the cursor to |cursor|. At minimum, implementer should
+ // call NativeCursorManagerDelegate::CommitCursor() with whatever cursor is
+ // actually used.
+ virtual void SetCursor(
+ gfx::NativeCursor cursor,
+ NativeCursorManagerDelegate* delegate) = 0;
+
+ // A request to set the visibility of the cursor. At minimum, implementer
+ // should call NativeCursorManagerDelegate::CommitVisibility() with whatever
+ // the visibility is.
+ virtual void SetVisibility(
+ bool visible,
+ NativeCursorManagerDelegate* delegate) = 0;
+
+ // A request to set the cursor set.
+ virtual void SetCursorSet(
+ ui::CursorSetType cursor_set,
+ NativeCursorManagerDelegate* delegate) = 0;
+
+ // A request to set whether mouse events are disabled. At minimum,
+ // implementer should call NativeCursorManagerDelegate::
+ // CommitMouseEventsEnabled() with whether mouse events are actually enabled.
+ virtual void SetMouseEventsEnabled(
+ bool enabled,
+ NativeCursorManagerDelegate* delegate) = 0;
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_NATIVE_CURSOR_MANAGER_H_
diff --git a/chromium/ui/wm/core/native_cursor_manager_delegate.h b/chromium/ui/wm/core/native_cursor_manager_delegate.h
new file mode 100644
index 00000000000..1393b2cd4b4
--- /dev/null
+++ b/chromium/ui/wm/core/native_cursor_manager_delegate.h
@@ -0,0 +1,33 @@
+// 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_WM_CORE_NATIVE_CURSOR_MANAGER_DELEGATE_H_
+#define UI_WM_CORE_NATIVE_CURSOR_MANAGER_DELEGATE_H_
+
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+// The non-public interface that CursorManager exposes to its users. This
+// gives accessors to all the current state, and mutators to all the current
+// state.
+class WM_EXPORT NativeCursorManagerDelegate {
+ public:
+ virtual ~NativeCursorManagerDelegate() {}
+
+ // TODO(tdanderson): Possibly remove this interface.
+ virtual gfx::NativeCursor GetCursor() const = 0;
+ virtual bool IsCursorVisible() const = 0;
+
+ virtual void CommitCursor(gfx::NativeCursor cursor) = 0;
+ virtual void CommitVisibility(bool visible) = 0;
+ virtual void CommitCursorSet(ui::CursorSetType cursor_set) = 0;
+ virtual void CommitMouseEventsEnabled(bool enabled) = 0;
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_NATIVE_CURSOR_MANAGER_DELEGATE_H_
diff --git a/chromium/ui/wm/core/nested_accelerator_controller.cc b/chromium/ui/wm/core/nested_accelerator_controller.cc
new file mode 100644
index 00000000000..e4ace4f777a
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_controller.cc
@@ -0,0 +1,57 @@
+// 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/wm/core/nested_accelerator_controller.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+#include "ui/wm/core/nested_accelerator_dispatcher.h"
+
+namespace wm {
+
+NestedAcceleratorController::NestedAcceleratorController(
+ NestedAcceleratorDelegate* delegate)
+ : dispatcher_delegate_(delegate) {
+ DCHECK(delegate);
+}
+
+NestedAcceleratorController::~NestedAcceleratorController() {
+}
+
+void NestedAcceleratorController::PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* nested_dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) {
+ scoped_ptr<NestedAcceleratorDispatcher> old_accelerator_dispatcher =
+ accelerator_dispatcher_.Pass();
+ accelerator_dispatcher_ = NestedAcceleratorDispatcher::Create(
+ dispatcher_delegate_.get(), nested_dispatcher);
+
+ scoped_ptr<base::RunLoop> run_loop = accelerator_dispatcher_->CreateRunLoop();
+ *quit_closure =
+ base::Bind(&NestedAcceleratorController::QuitNestedMessageLoop,
+ base::Unretained(this),
+ run_loop->QuitClosure());
+ *run_closure = base::Bind(&NestedAcceleratorController::RunNestedMessageLoop,
+ base::Unretained(this),
+ base::Passed(&run_loop),
+ base::Passed(&old_accelerator_dispatcher));
+}
+
+void NestedAcceleratorController::RunNestedMessageLoop(
+ scoped_ptr<base::RunLoop> run_loop,
+ scoped_ptr<NestedAcceleratorDispatcher> old_accelerator_dispatcher) {
+ run_loop->Run();
+ accelerator_dispatcher_ = old_accelerator_dispatcher.Pass();
+}
+
+void NestedAcceleratorController::QuitNestedMessageLoop(
+ const base::Closure& quit_runloop) {
+ quit_runloop.Run();
+ accelerator_dispatcher_.reset();
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/nested_accelerator_controller.h b/chromium/ui/wm/core/nested_accelerator_controller.h
new file mode 100644
index 00000000000..2826d72ea27
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_controller.h
@@ -0,0 +1,47 @@
+// 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_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_
+#define UI_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_
+
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/wm/public/dispatcher_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class NestedAcceleratorDelegate;
+class NestedAcceleratorDispatcher;
+
+// Creates a dispatcher which wraps another dispatcher.
+// The outer dispatcher runs first and performs ash specific handling.
+// If it does not consume the event it forwards the event to the nested
+// dispatcher.
+class WM_EXPORT NestedAcceleratorController
+ : public aura::client::DispatcherClient {
+ public:
+ explicit NestedAcceleratorController(NestedAcceleratorDelegate* delegate);
+ virtual ~NestedAcceleratorController();
+
+ // aura::client::DispatcherClient:
+ virtual void PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) OVERRIDE;
+
+ private:
+ void RunNestedMessageLoop(scoped_ptr<base::RunLoop> run_loop,
+ scoped_ptr<NestedAcceleratorDispatcher> dispatcher);
+ void QuitNestedMessageLoop(const base::Closure& quit_runloop);
+
+ scoped_ptr<NestedAcceleratorDispatcher> accelerator_dispatcher_;
+ scoped_ptr<NestedAcceleratorDelegate> dispatcher_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorController);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/nested_accelerator_controller_unittest.cc b/chromium/ui/wm/core/nested_accelerator_controller_unittest.cc
new file mode 100644
index 00000000000..9fa394ef5f6
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_controller_unittest.cc
@@ -0,0 +1,205 @@
+// 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/wm/core/nested_accelerator_controller.h"
+
+#include "base/bind.h"
+#include "base/event_types.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/accelerator_manager.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+#include "ui/wm/public/dispatcher_client.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#include "ui/events/test/events_test_utils_x11.h"
+#endif // USE_X11
+
+namespace wm {
+namespace test {
+
+namespace {
+
+class MockDispatcher : public ui::PlatformEventDispatcher {
+ public:
+ MockDispatcher() : num_key_events_dispatched_(0) {}
+
+ int num_key_events_dispatched() { return num_key_events_dispatched_; }
+
+ private:
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
+ return true;
+ }
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
+ if (ui::EventTypeFromNative(event) == ui::ET_KEY_RELEASED)
+ num_key_events_dispatched_++;
+ return ui::POST_DISPATCH_NONE;
+ }
+
+ int num_key_events_dispatched_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDispatcher);
+};
+
+class TestTarget : public ui::AcceleratorTarget {
+ public:
+ TestTarget() : accelerator_pressed_count_(0) {}
+ virtual ~TestTarget() {}
+
+ int accelerator_pressed_count() const { return accelerator_pressed_count_; }
+
+ // Overridden from ui::AcceleratorTarget:
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
+ accelerator_pressed_count_++;
+ return true;
+ }
+ virtual bool CanHandleAccelerators() const OVERRIDE { return true; }
+
+ private:
+ int accelerator_pressed_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTarget);
+};
+
+void DispatchKeyReleaseA(aura::Window* root_window) {
+// Sending both keydown and keyup is necessary here because the accelerator
+// manager only checks a keyup event following a keydown event. See
+// ShouldHandle() in ui/base/accelerators/accelerator_manager.cc for details.
+#if defined(OS_WIN)
+ MSG native_event_down = {NULL, WM_KEYDOWN, ui::VKEY_A, 0};
+ aura::WindowTreeHost* host = root_window->GetHost();
+ host->PostNativeEvent(native_event_down);
+ MSG native_event_up = {NULL, WM_KEYUP, ui::VKEY_A, 0};
+ host->PostNativeEvent(native_event_up);
+#elif defined(USE_X11)
+ ui::ScopedXI2Event native_event;
+ native_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0);
+ aura::WindowTreeHost* host = root_window->GetHost();
+ host->PostNativeEvent(native_event);
+ native_event.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, 0);
+ host->PostNativeEvent(native_event);
+#endif
+ // Make sure the inner message-loop terminates after dispatching the events.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::MessageLoop::current()->QuitClosure());
+}
+
+class MockNestedAcceleratorDelegate : public NestedAcceleratorDelegate {
+ public:
+ MockNestedAcceleratorDelegate()
+ : accelerator_manager_(new ui::AcceleratorManager) {}
+ virtual ~MockNestedAcceleratorDelegate() {}
+
+ // NestedAcceleratorDelegate:
+ virtual Result ProcessAccelerator(
+ const ui::Accelerator& accelerator) OVERRIDE {
+ return accelerator_manager_->Process(accelerator) ?
+ RESULT_PROCESSED : RESULT_NOT_PROCESSED;
+ }
+
+ void Register(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) {
+ accelerator_manager_->Register(
+ accelerator, ui::AcceleratorManager::kNormalPriority, target);
+ }
+
+ private:
+ scoped_ptr<ui::AcceleratorManager> accelerator_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockNestedAcceleratorDelegate);
+};
+
+class NestedAcceleratorTest : public aura::test::AuraTestBase {
+ public:
+ NestedAcceleratorTest() {}
+ virtual ~NestedAcceleratorTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ delegate_ = new MockNestedAcceleratorDelegate();
+ nested_accelerator_controller_.reset(
+ new NestedAcceleratorController(delegate_));
+ aura::client::SetDispatcherClient(root_window(),
+ nested_accelerator_controller_.get());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ aura::client::SetDispatcherClient(root_window(), NULL);
+ AuraTestBase::TearDown();
+ delegate_ = NULL;
+ nested_accelerator_controller_.reset();
+ }
+
+ MockNestedAcceleratorDelegate* delegate() { return delegate_; }
+
+ private:
+ scoped_ptr<NestedAcceleratorController> nested_accelerator_controller_;
+ MockNestedAcceleratorDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorTest);
+};
+
+} // namespace
+
+// Aura window above lock screen in z order.
+TEST_F(NestedAcceleratorTest, AssociatedWindowAboveLockScreen) {
+ // TODO(oshima|sadrul): remove when Win implements PES.
+ if (!ui::PlatformEventSource::GetInstance())
+ return;
+ MockDispatcher inner_dispatcher;
+ scoped_ptr<aura::Window> mock_lock_container(
+ CreateNormalWindow(0, root_window(), NULL));
+ aura::test::CreateTestWindowWithId(1, mock_lock_container.get());
+
+ scoped_ptr<aura::Window> associated_window(
+ CreateNormalWindow(2, root_window(), NULL));
+ EXPECT_TRUE(aura::test::WindowIsAbove(associated_window.get(),
+ mock_lock_container.get()));
+
+ DispatchKeyReleaseA(root_window());
+ scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher =
+ ui::PlatformEventSource::GetInstance()->OverrideDispatcher(
+ &inner_dispatcher);
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root_window()), NULL);
+ run_loop.Run();
+ EXPECT_EQ(1, inner_dispatcher.num_key_events_dispatched());
+}
+
+// Test that the nested dispatcher handles accelerators.
+TEST_F(NestedAcceleratorTest, AcceleratorsHandled) {
+ // TODO(oshima|sadrul): remove when Win implements PES.
+ if (!ui::PlatformEventSource::GetInstance())
+ return;
+ MockDispatcher inner_dispatcher;
+ ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE);
+ accelerator.set_type(ui::ET_KEY_RELEASED);
+ TestTarget target;
+ delegate()->Register(accelerator, &target);
+
+ DispatchKeyReleaseA(root_window());
+ scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher =
+ ui::PlatformEventSource::GetInstance()->OverrideDispatcher(
+ &inner_dispatcher);
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(root_window()), NULL);
+ run_loop.Run();
+ EXPECT_EQ(0, inner_dispatcher.num_key_events_dispatched());
+ EXPECT_EQ(1, target.accelerator_pressed_count());
+}
+
+} // namespace test
+} // namespace wm
diff --git a/chromium/ui/wm/core/nested_accelerator_delegate.h b/chromium/ui/wm/core/nested_accelerator_delegate.h
new file mode 100644
index 00000000000..4b13c0d882b
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_delegate.h
@@ -0,0 +1,34 @@
+// 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_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_
+#define UI_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_
+
+namespace ui {
+class Accelerator;
+}
+
+namespace wm {
+
+// A delegate interface that implements the behavior of nested accelerator
+// handling.
+class NestedAcceleratorDelegate {
+ public:
+ enum Result {
+ RESULT_PROCESSED,
+ RESULT_NOT_PROCESSED,
+ // The key event should be ignored now and instead be reposted so that
+ // next event loop.
+ RESULT_PROCESS_LATER,
+ };
+
+ virtual ~NestedAcceleratorDelegate() {}
+
+ // Attempts to process the |accelerator|.
+ virtual Result ProcessAccelerator(const ui::Accelerator& accelerator) = 0;
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_
diff --git a/chromium/ui/wm/core/nested_accelerator_dispatcher.cc b/chromium/ui/wm/core/nested_accelerator_dispatcher.cc
new file mode 100644
index 00000000000..d37c93c796f
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_dispatcher.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/wm/core/nested_accelerator_dispatcher.h"
+
+#include "base/logging.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+
+namespace wm {
+
+NestedAcceleratorDispatcher::NestedAcceleratorDispatcher(
+ NestedAcceleratorDelegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate);
+}
+
+NestedAcceleratorDispatcher::~NestedAcceleratorDispatcher() {
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/nested_accelerator_dispatcher.h b/chromium/ui/wm/core/nested_accelerator_dispatcher.h
new file mode 100644
index 00000000000..df5dd0862d9
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_dispatcher.h
@@ -0,0 +1,55 @@
+// 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_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_
+#define UI_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/wm/wm_export.h"
+
+namespace base {
+class MessagePumpDispatcher;
+class RunLoop;
+}
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace wm {
+
+class NestedAcceleratorDelegate;
+
+// Dispatcher for handling accelerators from menu.
+//
+// Wraps a nested dispatcher to which control is passed if no accelerator key
+// has been pressed. If the nested dispatcher is NULL, then the control is
+// passed back to the default dispatcher.
+// TODO(pkotwicz): Add support for a |nested_dispatcher| which sends
+// events to a system IME.
+class WM_EXPORT NestedAcceleratorDispatcher {
+ public:
+ virtual ~NestedAcceleratorDispatcher();
+
+ static scoped_ptr<NestedAcceleratorDispatcher> Create(
+ NestedAcceleratorDelegate* dispatcher_delegate,
+ base::MessagePumpDispatcher* nested_dispatcher);
+
+ // Creates a base::RunLoop object to run a nested message loop.
+ virtual scoped_ptr<base::RunLoop> CreateRunLoop() = 0;
+
+ protected:
+ explicit NestedAcceleratorDispatcher(NestedAcceleratorDelegate* delegate);
+
+ NestedAcceleratorDelegate*
+ delegate_; // Owned by NestedAcceleratorController.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcher);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_
diff --git a/chromium/ui/wm/core/nested_accelerator_dispatcher_linux.cc b/chromium/ui/wm/core/nested_accelerator_dispatcher_linux.cc
new file mode 100644
index 00000000000..12340b66a7b
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_dispatcher_linux.cc
@@ -0,0 +1,104 @@
+// 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/wm/core/nested_accelerator_dispatcher.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/scoped_event_dispatcher.h"
+#include "ui/wm/core/accelerator_filter.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#endif
+
+namespace wm {
+
+namespace {
+
+#if defined(USE_OZONE)
+bool IsKeyEvent(const base::NativeEvent& native_event) {
+ const ui::KeyEvent* event = static_cast<const ui::KeyEvent*>(native_event);
+ return event->IsKeyEvent();
+}
+#elif defined(USE_X11)
+bool IsKeyEvent(const XEvent* xev) {
+ return xev->type == KeyPress || xev->type == KeyRelease;
+}
+#else
+#error Unknown build platform: you should have either use_ozone or use_x11.
+#endif
+
+scoped_ptr<ui::ScopedEventDispatcher> OverrideDispatcher(
+ ui::PlatformEventDispatcher* dispatcher) {
+ ui::PlatformEventSource* source = ui::PlatformEventSource::GetInstance();
+ return source ? source->OverrideDispatcher(dispatcher)
+ : scoped_ptr<ui::ScopedEventDispatcher>();
+}
+
+} // namespace
+
+class NestedAcceleratorDispatcherLinux : public NestedAcceleratorDispatcher,
+ public ui::PlatformEventDispatcher {
+ public:
+ explicit NestedAcceleratorDispatcherLinux(NestedAcceleratorDelegate* delegate)
+ : NestedAcceleratorDispatcher(delegate),
+ restore_dispatcher_(OverrideDispatcher(this)) {}
+
+ virtual ~NestedAcceleratorDispatcherLinux() {}
+
+ private:
+ // AcceleratorDispatcher:
+ virtual scoped_ptr<base::RunLoop> CreateRunLoop() OVERRIDE {
+ return scoped_ptr<base::RunLoop>(new base::RunLoop());
+ }
+
+ // ui::PlatformEventDispatcher:
+ virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
+ return true;
+ }
+
+ virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE {
+ if (IsKeyEvent(event)) {
+ ui::KeyEvent key_event(event, false);
+ ui::Accelerator accelerator = CreateAcceleratorFromKeyEvent(key_event);
+
+ switch (delegate_->ProcessAccelerator(accelerator)) {
+ case NestedAcceleratorDelegate::RESULT_PROCESS_LATER:
+#if defined(USE_X11)
+ XPutBackEvent(event->xany.display, event);
+#else
+ NOTIMPLEMENTED();
+#endif
+ return ui::POST_DISPATCH_NONE;
+ case NestedAcceleratorDelegate::RESULT_PROCESSED:
+ return ui::POST_DISPATCH_NONE;
+ case NestedAcceleratorDelegate::RESULT_NOT_PROCESSED:
+ break;
+ }
+ }
+ ui::PlatformEventDispatcher* prev = *restore_dispatcher_;
+
+ return prev ? prev->DispatchEvent(event)
+ : ui::POST_DISPATCH_PERFORM_DEFAULT;
+ }
+
+ scoped_ptr<ui::ScopedEventDispatcher> restore_dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcherLinux);
+};
+
+scoped_ptr<NestedAcceleratorDispatcher> NestedAcceleratorDispatcher::Create(
+ NestedAcceleratorDelegate* delegate,
+ base::MessagePumpDispatcher* nested_dispatcher) {
+ return scoped_ptr<NestedAcceleratorDispatcher>(
+ new NestedAcceleratorDispatcherLinux(delegate));
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/nested_accelerator_dispatcher_win.cc b/chromium/ui/wm/core/nested_accelerator_dispatcher_win.cc
new file mode 100644
index 00000000000..a810bb9d88e
--- /dev/null
+++ b/chromium/ui/wm/core/nested_accelerator_dispatcher_win.cc
@@ -0,0 +1,74 @@
+// 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/wm/core/nested_accelerator_dispatcher.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/run_loop.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event.h"
+#include "ui/wm/core/accelerator_filter.h"
+#include "ui/wm/core/nested_accelerator_delegate.h"
+
+using base::MessagePumpDispatcher;
+
+namespace wm {
+
+namespace {
+
+bool IsKeyEvent(const MSG& msg) {
+ return msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
+ msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP;
+}
+
+} // namespace
+
+class NestedAcceleratorDispatcherWin : public NestedAcceleratorDispatcher,
+ public MessagePumpDispatcher {
+ public:
+ NestedAcceleratorDispatcherWin(NestedAcceleratorDelegate* delegate,
+ MessagePumpDispatcher* nested)
+ : NestedAcceleratorDispatcher(delegate), nested_dispatcher_(nested) {}
+ virtual ~NestedAcceleratorDispatcherWin() {}
+
+ private:
+ // NestedAcceleratorDispatcher:
+ virtual scoped_ptr<base::RunLoop> CreateRunLoop() OVERRIDE {
+ return scoped_ptr<base::RunLoop>(new base::RunLoop(this));
+ }
+
+ // MessagePumpDispatcher:
+ virtual uint32_t Dispatch(const MSG& event) OVERRIDE {
+ if (IsKeyEvent(event)) {
+ ui::KeyEvent key_event(event, false);
+ ui::Accelerator accelerator = CreateAcceleratorFromKeyEvent(key_event);
+
+ switch (delegate_->ProcessAccelerator(accelerator)) {
+ case NestedAcceleratorDelegate::RESULT_PROCESS_LATER:
+ return POST_DISPATCH_QUIT_LOOP;
+ case NestedAcceleratorDelegate::RESULT_PROCESSED:
+ return POST_DISPATCH_NONE;
+ case NestedAcceleratorDelegate::RESULT_NOT_PROCESSED:
+ break;
+ }
+ }
+
+ return nested_dispatcher_ ? nested_dispatcher_->Dispatch(event)
+ : POST_DISPATCH_PERFORM_DEFAULT;
+ }
+
+ MessagePumpDispatcher* nested_dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcherWin);
+};
+
+scoped_ptr<NestedAcceleratorDispatcher> NestedAcceleratorDispatcher::Create(
+ NestedAcceleratorDelegate* delegate,
+ MessagePumpDispatcher* nested_dispatcher) {
+ return scoped_ptr<NestedAcceleratorDispatcher>(
+ new NestedAcceleratorDispatcherWin(delegate, nested_dispatcher));
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/shadow.cc b/chromium/ui/wm/core/shadow.cc
new file mode 100644
index 00000000000..1eb0ac6b4e3
--- /dev/null
+++ b/chromium/ui/wm/core/shadow.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/shadow.h"
+
+#include "grit/ui_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/wm/core/image_grid.h"
+
+namespace {
+
+// Shadow opacity for different styles.
+const float kActiveShadowOpacity = 1.0f;
+const float kInactiveShadowOpacity = 0.2f;
+const float kSmallShadowOpacity = 1.0f;
+
+// Interior inset for different styles.
+const int kActiveInteriorInset = 0;
+const int kInactiveInteriorInset = 0;
+const int kSmallInteriorInset = 5;
+
+// Duration for opacity animation in milliseconds.
+const int kShadowAnimationDurationMs = 100;
+
+float GetOpacityForStyle(wm::Shadow::Style style) {
+ switch (style) {
+ case wm::Shadow::STYLE_ACTIVE:
+ return kActiveShadowOpacity;
+ case wm::Shadow::STYLE_INACTIVE:
+ return kInactiveShadowOpacity;
+ case wm::Shadow::STYLE_SMALL:
+ return kSmallShadowOpacity;
+ }
+ return 1.0f;
+}
+
+int GetInteriorInsetForStyle(wm::Shadow::Style style) {
+ switch (style) {
+ case wm::Shadow::STYLE_ACTIVE:
+ return kActiveInteriorInset;
+ case wm::Shadow::STYLE_INACTIVE:
+ return kInactiveInteriorInset;
+ case wm::Shadow::STYLE_SMALL:
+ return kSmallInteriorInset;
+ }
+ return 0;
+}
+
+} // namespace
+
+namespace wm {
+
+Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) {
+}
+
+Shadow::~Shadow() {
+}
+
+void Shadow::Init(Style style) {
+ style_ = style;
+ image_grid_.reset(new ImageGrid);
+ UpdateImagesForStyle();
+ image_grid_->layer()->set_name("Shadow");
+ image_grid_->layer()->SetOpacity(GetOpacityForStyle(style_));
+}
+
+void Shadow::SetContentBounds(const gfx::Rect& content_bounds) {
+ content_bounds_ = content_bounds;
+ UpdateImageGridBounds();
+}
+
+ui::Layer* Shadow::layer() const {
+ return image_grid_->layer();
+}
+
+void Shadow::SetStyle(Style style) {
+ if (style_ == style)
+ return;
+
+ Style old_style = style_;
+ style_ = style;
+
+ // Stop waiting for any as yet unfinished implicit animations.
+ StopObservingImplicitAnimations();
+
+ // If we're switching to or from the small style, don't bother with
+ // animations.
+ if (style == STYLE_SMALL || old_style == STYLE_SMALL) {
+ UpdateImagesForStyle();
+ image_grid_->layer()->SetOpacity(GetOpacityForStyle(style));
+ return;
+ }
+
+ // If we're becoming active, switch images now. Because the inactive image
+ // has a very low opacity the switch isn't noticeable and this approach
+ // allows us to use only a single set of shadow images at a time.
+ if (style == STYLE_ACTIVE) {
+ UpdateImagesForStyle();
+ // Opacity was baked into inactive image, start opacity low to match.
+ image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
+ }
+
+ {
+ // Property sets within this scope will be implicitly animated.
+ ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
+ settings.AddObserver(this);
+ settings.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kShadowAnimationDurationMs));
+ switch (style_) {
+ case STYLE_ACTIVE:
+ image_grid_->layer()->SetOpacity(kActiveShadowOpacity);
+ break;
+ case STYLE_INACTIVE:
+ image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
+ break;
+ default:
+ NOTREACHED() << "Unhandled style " << style_;
+ break;
+ }
+ }
+}
+
+void Shadow::OnImplicitAnimationsCompleted() {
+ // If we just finished going inactive, switch images. This doesn't cause
+ // a visual pop because the inactive image opacity is so low.
+ if (style_ == STYLE_INACTIVE) {
+ UpdateImagesForStyle();
+ // Opacity is baked into inactive image, so set fully opaque.
+ image_grid_->layer()->SetOpacity(1.0f);
+ }
+}
+
+void Shadow::UpdateImagesForStyle() {
+ ResourceBundle& res = ResourceBundle::GetSharedInstance();
+ switch (style_) {
+ case STYLE_ACTIVE:
+ image_grid_->SetImages(
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_LEFT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_LEFT),
+ NULL,
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_RIGHT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM),
+ &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT));
+ break;
+ case STYLE_INACTIVE:
+ image_grid_->SetImages(
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_LEFT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_LEFT),
+ NULL,
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_RIGHT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM),
+ &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT));
+ break;
+ case STYLE_SMALL:
+ image_grid_->SetImages(
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT),
+ NULL,
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM),
+ &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT));
+ break;
+ default:
+ NOTREACHED() << "Unhandled style " << style_;
+ break;
+ }
+
+ // Update interior inset for style.
+ interior_inset_ = GetInteriorInsetForStyle(style_);
+
+ // Image sizes may have changed.
+ UpdateImageGridBounds();
+}
+
+void Shadow::UpdateImageGridBounds() {
+ // Update bounds based on content bounds and image sizes.
+ gfx::Rect image_grid_bounds = content_bounds_;
+ image_grid_bounds.Inset(interior_inset_, interior_inset_);
+ image_grid_->SetContentBounds(image_grid_bounds);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/shadow.h b/chromium/ui/wm/core/shadow.h
new file mode 100644
index 00000000000..c153ecf158e
--- /dev/null
+++ b/chromium/ui/wm/core/shadow.h
@@ -0,0 +1,86 @@
+// 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_WM_CORE_SHADOW_H_
+#define UI_WM_CORE_SHADOW_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/gfx/rect.h"
+#include "ui/wm/wm_export.h"
+
+namespace ui {
+class Layer;
+} // namespace ui
+
+namespace wm {
+
+class ImageGrid;
+
+// Simple class that draws a drop shadow around content at given bounds.
+class WM_EXPORT Shadow : public ui::ImplicitAnimationObserver {
+ public:
+ enum Style {
+ // Active windows have more opaque shadows, shifted down to make the window
+ // appear "higher".
+ STYLE_ACTIVE,
+
+ // Inactive windows have less opaque shadows.
+ STYLE_INACTIVE,
+
+ // Small windows like tooltips and context menus have lighter, smaller
+ // shadows.
+ STYLE_SMALL,
+ };
+
+ Shadow();
+ virtual ~Shadow();
+
+ void Init(Style style);
+
+ // Returns |image_grid_|'s ui::Layer. This is exposed so it can be added to
+ // the same layer as the content and stacked below it. SetContentBounds()
+ // should be used to adjust the shadow's size and position (rather than
+ // applying transformations to this layer).
+ ui::Layer* layer() const;
+
+ const gfx::Rect& content_bounds() const { return content_bounds_; }
+ Style style() const { return style_; }
+
+ // Moves and resizes |image_grid_| to frame |content_bounds|.
+ void SetContentBounds(const gfx::Rect& content_bounds);
+
+ // Sets the shadow's style, animating opacity as necessary.
+ void SetStyle(Style style);
+
+ // ui::ImplicitAnimationObserver overrides:
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE;
+
+ private:
+ // Updates the |image_grid_| images to the current |style_|.
+ void UpdateImagesForStyle();
+
+ // Updates the |image_grid_| bounds based on its image sizes and the
+ // current |content_bounds_|.
+ void UpdateImageGridBounds();
+
+ // The current style, set when the transition animation starts.
+ Style style_;
+
+ scoped_ptr<ImageGrid> image_grid_;
+
+ // Bounds of the content that the shadow encloses.
+ gfx::Rect content_bounds_;
+
+ // The interior inset of the shadow images. The content bounds of the image
+ // grid should be set to |content_bounds_| inset by this amount.
+ int interior_inset_;
+
+ DISALLOW_COPY_AND_ASSIGN(Shadow);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_SHADOW_H_
diff --git a/chromium/ui/wm/core/shadow_controller.cc b/chromium/ui/wm/core/shadow_controller.cc
new file mode 100644
index 00000000000..c809389fadb
--- /dev/null
+++ b/chromium/ui/wm/core/shadow_controller.cc
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/shadow_controller.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/env.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_observer.h"
+#include "ui/compositor/layer.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"
+
+using std::make_pair;
+
+namespace wm {
+
+namespace {
+
+ShadowType GetShadowTypeFromWindow(aura::Window* window) {
+ switch (window->type()) {
+ case ui::wm::WINDOW_TYPE_NORMAL:
+ case ui::wm::WINDOW_TYPE_PANEL:
+ case ui::wm::WINDOW_TYPE_MENU:
+ case ui::wm::WINDOW_TYPE_TOOLTIP:
+ return SHADOW_TYPE_RECTANGULAR;
+ default:
+ break;
+ }
+ return SHADOW_TYPE_NONE;
+}
+
+bool ShouldUseSmallShadowForWindow(aura::Window* window) {
+ switch (window->type()) {
+ case ui::wm::WINDOW_TYPE_MENU:
+ case ui::wm::WINDOW_TYPE_TOOLTIP:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+// Returns the shadow style to be applied to |losing_active| when it is losing
+// active to |gaining_active|. |gaining_active| may be of a type that hides when
+// inactive, and as such we do not want to render |losing_active| as inactive.
+Shadow::Style GetShadowStyleForWindowLosingActive(
+ aura::Window* losing_active,
+ aura::Window* gaining_active) {
+ if (gaining_active && aura::client::GetHideOnDeactivate(gaining_active)) {
+ aura::Window::Windows::const_iterator it =
+ std::find(GetTransientChildren(losing_active).begin(),
+ GetTransientChildren(losing_active).end(),
+ gaining_active);
+ if (it != GetTransientChildren(losing_active).end())
+ return Shadow::STYLE_ACTIVE;
+ }
+ return Shadow::STYLE_INACTIVE;
+}
+
+} // namespace
+
+// ShadowController::Impl ------------------------------------------------------
+
+// Real implementation of the ShadowController. ShadowController observes
+// ActivationChangeObserver, which are per ActivationClient, where as there is
+// only a single Impl (as it observes all window creation by way of an
+// EnvObserver).
+class ShadowController::Impl :
+ public aura::EnvObserver,
+ public aura::WindowObserver,
+ public base::RefCounted<Impl> {
+ public:
+ // Returns the singleton instance, destroyed when there are no more refs.
+ static Impl* GetInstance();
+
+ // aura::EnvObserver override:
+ virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
+
+ // aura::WindowObserver overrides:
+ virtual void OnWindowPropertyChanged(
+ aura::Window* window, const void* key, intptr_t old) OVERRIDE;
+ virtual void OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+ friend class base::RefCounted<Impl>;
+ friend class ShadowController;
+ friend class ShadowController::TestApi;
+
+ typedef std::map<aura::Window*, linked_ptr<Shadow> > WindowShadowMap;
+
+ Impl();
+ virtual ~Impl();
+
+ // Forwarded from ShadowController.
+ void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active);
+
+ // Checks if |window| is visible and contains a property requesting a shadow.
+ bool ShouldShowShadowForWindow(aura::Window* window) const;
+
+ // Returns |window|'s shadow from |window_shadows_|, or NULL if no shadow
+ // exists.
+ Shadow* GetShadowForWindow(aura::Window* window);
+
+ // Updates the shadow styles for windows when activation changes.
+ void HandleWindowActivationChange(aura::Window* gaining_active,
+ aura::Window* losing_active);
+
+ // Shows or hides |window|'s shadow as needed (creating the shadow if
+ // necessary).
+ void HandlePossibleShadowVisibilityChange(aura::Window* window);
+
+ // Creates a new shadow for |window| and stores it in |window_shadows_|. The
+ // shadow's bounds are initialized and it is added to the window's layer.
+ void CreateShadowForWindow(aura::Window* window);
+
+ WindowShadowMap window_shadows_;
+
+ ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
+
+ static Impl* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(Impl);
+};
+
+// static
+ShadowController::Impl* ShadowController::Impl::instance_ = NULL;
+
+// static
+ShadowController::Impl* ShadowController::Impl::GetInstance() {
+ if (!instance_)
+ instance_ = new Impl();
+ return instance_;
+}
+
+void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
+ observer_manager_.Add(window);
+ SetShadowType(window, GetShadowTypeFromWindow(window));
+ HandlePossibleShadowVisibilityChange(window);
+}
+
+void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) {
+ if (key == kShadowTypeKey) {
+ HandlePossibleShadowVisibilityChange(window);
+ return;
+ }
+}
+
+void ShadowController::Impl::OnWindowBoundsChanged(
+ aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) {
+ Shadow* shadow = GetShadowForWindow(window);
+ if (shadow)
+ shadow->SetContentBounds(gfx::Rect(new_bounds.size()));
+}
+
+void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) {
+ window_shadows_.erase(window);
+ observer_manager_.Remove(window);
+}
+
+void ShadowController::Impl::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ if (gained_active) {
+ Shadow* shadow = GetShadowForWindow(gained_active);
+ if (shadow && !ShouldUseSmallShadowForWindow(gained_active))
+ shadow->SetStyle(Shadow::STYLE_ACTIVE);
+ }
+ if (lost_active) {
+ Shadow* shadow = GetShadowForWindow(lost_active);
+ if (shadow && !ShouldUseSmallShadowForWindow(lost_active)) {
+ shadow->SetStyle(GetShadowStyleForWindowLosingActive(lost_active,
+ gained_active));
+ }
+ }
+}
+
+bool ShadowController::Impl::ShouldShowShadowForWindow(
+ aura::Window* window) const {
+ const ShadowType type = GetShadowType(window);
+ switch (type) {
+ case SHADOW_TYPE_NONE:
+ return false;
+ case SHADOW_TYPE_RECTANGULAR:
+ return true;
+ default:
+ NOTREACHED() << "Unknown shadow type " << type;
+ return false;
+ }
+}
+
+Shadow* ShadowController::Impl::GetShadowForWindow(aura::Window* window) {
+ WindowShadowMap::const_iterator it = window_shadows_.find(window);
+ return it != window_shadows_.end() ? it->second.get() : NULL;
+}
+
+void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
+ aura::Window* window) {
+ const bool should_show = ShouldShowShadowForWindow(window);
+ Shadow* shadow = GetShadowForWindow(window);
+ if (shadow)
+ shadow->layer()->SetVisible(should_show);
+ else if (should_show && !shadow)
+ CreateShadowForWindow(window);
+}
+
+void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
+ linked_ptr<Shadow> shadow(new Shadow());
+ window_shadows_.insert(make_pair(window, shadow));
+
+ shadow->Init(ShouldUseSmallShadowForWindow(window) ?
+ Shadow::STYLE_SMALL : Shadow::STYLE_ACTIVE);
+ shadow->SetContentBounds(gfx::Rect(window->bounds().size()));
+ shadow->layer()->SetVisible(ShouldShowShadowForWindow(window));
+ window->layer()->Add(shadow->layer());
+}
+
+ShadowController::Impl::Impl()
+ : observer_manager_(this) {
+ aura::Env::GetInstance()->AddObserver(this);
+}
+
+ShadowController::Impl::~Impl() {
+ DCHECK_EQ(instance_, this);
+ aura::Env::GetInstance()->RemoveObserver(this);
+ instance_ = NULL;
+}
+
+// ShadowController ------------------------------------------------------------
+
+ShadowController::ShadowController(
+ aura::client::ActivationClient* activation_client)
+ : activation_client_(activation_client),
+ impl_(Impl::GetInstance()) {
+ // Watch for window activation changes.
+ activation_client_->AddObserver(this);
+}
+
+ShadowController::~ShadowController() {
+ activation_client_->RemoveObserver(this);
+}
+
+void ShadowController::OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ impl_->OnWindowActivated(gained_active, lost_active);
+}
+
+// ShadowController::TestApi ---------------------------------------------------
+
+Shadow* ShadowController::TestApi::GetShadowForWindow(aura::Window* window) {
+ return controller_->impl_->GetShadowForWindow(window);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/shadow_controller.h b/chromium/ui/wm/core/shadow_controller.h
new file mode 100644
index 00000000000..c84689453f3
--- /dev/null
+++ b/chromium/ui/wm/core/shadow_controller.h
@@ -0,0 +1,69 @@
+// 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_WM_CORE_SHADOW_CONTROLLER_H_
+#define UI_WM_CORE_SHADOW_CONTROLLER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "ui/wm/public/activation_change_observer.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+namespace client {
+class ActivationClient;
+}
+}
+namespace gfx {
+class Rect;
+}
+
+namespace wm {
+
+class Shadow;
+
+// ShadowController observes changes to windows and creates and updates drop
+// shadows as needed. ShadowController itself is light weight and per
+// ActivationClient. ShadowController delegates to its implementation class,
+// which observes all window creation.
+class WM_EXPORT ShadowController :
+ public aura::client::ActivationChangeObserver {
+ public:
+ class WM_EXPORT TestApi {
+ public:
+ explicit TestApi(ShadowController* controller) : controller_(controller) {}
+ ~TestApi() {}
+
+ Shadow* GetShadowForWindow(aura::Window* window);
+
+ private:
+ ShadowController* controller_; // not owned
+
+ DISALLOW_COPY_AND_ASSIGN(TestApi);
+ };
+
+ explicit ShadowController(aura::client::ActivationClient* activation_client);
+ virtual ~ShadowController();
+
+ // aura::client::ActivationChangeObserver overrides:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) OVERRIDE;
+
+ private:
+ class Impl;
+
+ aura::client::ActivationClient* activation_client_;
+
+ scoped_refptr<Impl> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShadowController);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_SHADOW_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/shadow_controller_unittest.cc b/chromium/ui/wm/core/shadow_controller_unittest.cc
new file mode 100644
index 00000000000..d82d015f1a0
--- /dev/null
+++ b/chromium/ui/wm/core/shadow_controller_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/shadow_controller.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/compositor/layer.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/core/wm_state.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace wm {
+
+class ShadowControllerTest : public aura::test::AuraTestBase {
+ public:
+ ShadowControllerTest() {}
+ virtual ~ShadowControllerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ wm_state_.reset(new wm::WMState);
+ AuraTestBase::SetUp();
+ new wm::DefaultActivationClient(root_window());
+ aura::client::ActivationClient* activation_client =
+ aura::client::GetActivationClient(root_window());
+ shadow_controller_.reset(new ShadowController(activation_client));
+ }
+ virtual void TearDown() OVERRIDE {
+ shadow_controller_.reset();
+ AuraTestBase::TearDown();
+ wm_state_.reset();
+ }
+
+ protected:
+ ShadowController* shadow_controller() { return shadow_controller_.get(); }
+
+ void ActivateWindow(aura::Window* window) {
+ DCHECK(window);
+ DCHECK(window->GetRootWindow());
+ aura::client::GetActivationClient(window->GetRootWindow())->ActivateWindow(
+ window);
+ }
+
+ private:
+ scoped_ptr<ShadowController> shadow_controller_;
+ scoped_ptr<wm::WMState> wm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShadowControllerTest);
+};
+
+// Tests that various methods in Window update the Shadow object as expected.
+TEST_F(ShadowControllerTest, Shadow) {
+ scoped_ptr<aura::Window> window(new aura::Window(NULL));
+ window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window.get());
+
+ // We should create the shadow before the window is visible (the shadow's
+ // layer won't get drawn yet since it's a child of the window's layer).
+ ShadowController::TestApi api(shadow_controller());
+ const Shadow* shadow = api.GetShadowForWindow(window.get());
+ ASSERT_TRUE(shadow != NULL);
+ EXPECT_TRUE(shadow->layer()->visible());
+
+ // The shadow should remain visible after window visibility changes.
+ window->Show();
+ EXPECT_TRUE(shadow->layer()->visible());
+ window->Hide();
+ EXPECT_TRUE(shadow->layer()->visible());
+
+ // If the shadow is disabled, it should be hidden.
+ SetShadowType(window.get(), SHADOW_TYPE_NONE);
+ window->Show();
+ EXPECT_FALSE(shadow->layer()->visible());
+ SetShadowType(window.get(), SHADOW_TYPE_RECTANGULAR);
+ EXPECT_TRUE(shadow->layer()->visible());
+
+ // The shadow's layer should be a child of the window's layer.
+ EXPECT_EQ(window->layer(), shadow->layer()->parent());
+
+ window->parent()->RemoveChild(window.get());
+ aura::Window* window_ptr = window.get();
+ window.reset();
+ EXPECT_TRUE(api.GetShadowForWindow(window_ptr) == NULL);
+}
+
+// Tests that the window's shadow's bounds are updated correctly.
+TEST_F(ShadowControllerTest, ShadowBounds) {
+ scoped_ptr<aura::Window> window(new aura::Window(NULL));
+ window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window.get());
+ window->Show();
+
+ const gfx::Rect kOldBounds(20, 30, 400, 300);
+ window->SetBounds(kOldBounds);
+
+ // 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).
+ SetShadowType(window.get(), SHADOW_TYPE_RECTANGULAR);
+ ShadowController::TestApi api(shadow_controller());
+ const Shadow* shadow = api.GetShadowForWindow(window.get());
+ ASSERT_TRUE(shadow != NULL);
+ EXPECT_EQ(gfx::Rect(kOldBounds.size()).ToString(),
+ shadow->content_bounds().ToString());
+
+ // When we change the window's bounds, the shadow's should be updated too.
+ gfx::Rect kNewBounds(50, 60, 500, 400);
+ window->SetBounds(kNewBounds);
+ EXPECT_EQ(gfx::Rect(kNewBounds.size()).ToString(),
+ shadow->content_bounds().ToString());
+}
+
+// Tests that activating a window changes the shadow style.
+TEST_F(ShadowControllerTest, ShadowStyle) {
+ ShadowController::TestApi api(shadow_controller());
+
+ scoped_ptr<aura::Window> window1(new aura::Window(NULL));
+ window1->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window1->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window1.get());
+ window1->SetBounds(gfx::Rect(10, 20, 300, 400));
+ window1->Show();
+ ActivateWindow(window1.get());
+
+ // window1 is active, so style should have active appearance.
+ Shadow* shadow1 = api.GetShadowForWindow(window1.get());
+ ASSERT_TRUE(shadow1 != NULL);
+ EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
+
+ // Create another window and activate it.
+ scoped_ptr<aura::Window> window2(new aura::Window(NULL));
+ window2->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window2->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window2.get());
+ window2->SetBounds(gfx::Rect(11, 21, 301, 401));
+ window2->Show();
+ ActivateWindow(window2.get());
+
+ // window1 is now inactive, so shadow should go inactive.
+ Shadow* shadow2 = api.GetShadowForWindow(window2.get());
+ ASSERT_TRUE(shadow2 != NULL);
+ EXPECT_EQ(Shadow::STYLE_INACTIVE, shadow1->style());
+ EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow2->style());
+}
+
+// Tests that we use smaller shadows for tooltips and menus.
+TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) {
+ ShadowController::TestApi api(shadow_controller());
+
+ scoped_ptr<aura::Window> tooltip_window(new aura::Window(NULL));
+ tooltip_window->SetType(ui::wm::WINDOW_TYPE_TOOLTIP);
+ tooltip_window->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(tooltip_window.get());
+ tooltip_window->SetBounds(gfx::Rect(10, 20, 300, 400));
+ tooltip_window->Show();
+
+ Shadow* tooltip_shadow = api.GetShadowForWindow(tooltip_window.get());
+ ASSERT_TRUE(tooltip_shadow != NULL);
+ EXPECT_EQ(Shadow::STYLE_SMALL, tooltip_shadow->style());
+
+ scoped_ptr<aura::Window> menu_window(new aura::Window(NULL));
+ menu_window->SetType(ui::wm::WINDOW_TYPE_MENU);
+ menu_window->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(menu_window.get());
+ menu_window->SetBounds(gfx::Rect(10, 20, 300, 400));
+ menu_window->Show();
+
+ Shadow* menu_shadow = api.GetShadowForWindow(tooltip_window.get());
+ ASSERT_TRUE(menu_shadow != NULL);
+ EXPECT_EQ(Shadow::STYLE_SMALL, menu_shadow->style());
+}
+
+// http://crbug.com/120210 - transient parents of certain types of transients
+// should not lose their shadow when they lose activation to the transient.
+TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) {
+ ShadowController::TestApi api(shadow_controller());
+
+ scoped_ptr<aura::Window> window1(new aura::Window(NULL));
+ window1->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window1->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window1.get());
+ window1->SetBounds(gfx::Rect(10, 20, 300, 400));
+ window1->Show();
+ ActivateWindow(window1.get());
+
+ // window1 is active, so style should have active appearance.
+ Shadow* shadow1 = api.GetShadowForWindow(window1.get());
+ ASSERT_TRUE(shadow1 != NULL);
+ EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
+
+ // Create a window that is transient to window1, and that has the 'hide on
+ // deactivate' property set. Upon activation, window1 should still have an
+ // active shadow.
+ scoped_ptr<aura::Window> window2(new aura::Window(NULL));
+ window2->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window2->Init(aura::WINDOW_LAYER_TEXTURED);
+ ParentWindow(window2.get());
+ window2->SetBounds(gfx::Rect(11, 21, 301, 401));
+ AddTransientChild(window1.get(), window2.get());
+ aura::client::SetHideOnDeactivate(window2.get(), true);
+ window2->Show();
+ ActivateWindow(window2.get());
+
+ // window1 is now inactive, but its shadow should still appear active.
+ EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/shadow_types.cc b/chromium/ui/wm/core/shadow_types.cc
new file mode 100644
index 00000000000..a7afe89b50d
--- /dev/null
+++ b/chromium/ui/wm/core/shadow_types.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/shadow_types.h"
+
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(wm::ShadowType);
+
+namespace wm {
+
+void SetShadowType(aura::Window* window, ShadowType shadow_type) {
+ window->SetProperty(kShadowTypeKey, shadow_type);
+}
+
+ShadowType GetShadowType(aura::Window* window) {
+ return window->GetProperty(kShadowTypeKey);
+}
+
+DEFINE_WINDOW_PROPERTY_KEY(ShadowType, kShadowTypeKey, SHADOW_TYPE_NONE);
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/shadow_types.h b/chromium/ui/wm/core/shadow_types.h
new file mode 100644
index 00000000000..1198a43b16c
--- /dev/null
+++ b/chromium/ui/wm/core/shadow_types.h
@@ -0,0 +1,34 @@
+// 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_WM_CORE_SHADOW_TYPES_H_
+#define UI_WM_CORE_SHADOW_TYPES_H_
+
+#include "ui/aura/window.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace wm {
+
+// Different types of drop shadows that can be drawn under a window by the
+// shell. Used as a value for the kShadowTypeKey property.
+enum ShadowType {
+ // Starts at 0 due to the cast in GetShadowType().
+ SHADOW_TYPE_NONE = 0,
+ SHADOW_TYPE_RECTANGULAR,
+};
+
+WM_EXPORT void SetShadowType(aura::Window* window, ShadowType shadow_type);
+WM_EXPORT ShadowType GetShadowType(aura::Window* window);
+
+// A property key describing the drop shadow that should be displayed under the
+// window. If unset, no shadow is displayed.
+extern const aura::WindowProperty<ShadowType>* const kShadowTypeKey;
+
+} // namespace wm
+
+#endif // UI_WM_CORE_SHADOW_TYPES_H_
diff --git a/chromium/ui/wm/core/transient_window_controller.cc b/chromium/ui/wm/core/transient_window_controller.cc
new file mode 100644
index 00000000000..bb1945c09b2
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_controller.cc
@@ -0,0 +1,40 @@
+// 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/wm/core/transient_window_controller.h"
+
+#include "ui/wm/core/transient_window_manager.h"
+
+namespace wm {
+
+TransientWindowController::TransientWindowController() {
+}
+
+TransientWindowController::~TransientWindowController() {
+}
+
+void TransientWindowController::AddTransientChild(aura::Window* parent,
+ aura::Window* child) {
+ TransientWindowManager::Get(parent)->AddTransientChild(child);
+}
+
+void TransientWindowController::RemoveTransientChild(aura::Window* parent,
+ aura::Window* child) {
+ TransientWindowManager::Get(parent)->RemoveTransientChild(child);
+}
+
+aura::Window* TransientWindowController::GetTransientParent(
+ aura::Window* window) {
+ return const_cast<aura::Window*>(GetTransientParent(
+ const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* TransientWindowController::GetTransientParent(
+ const aura::Window* window) {
+ const TransientWindowManager* window_manager =
+ TransientWindowManager::Get(window);
+ return window_manager ? window_manager->transient_parent() : NULL;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/transient_window_controller.h b/chromium/ui/wm/core/transient_window_controller.h
new file mode 100644
index 00000000000..8638824ae36
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_controller.h
@@ -0,0 +1,36 @@
+// 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_WM_CORE_TRANSIENT_WINDOW_CONTROLLER_H_
+#define UI_WM_CORE_TRANSIENT_WINDOW_CONTROLLER_H_
+
+#include "ui/wm/public/transient_window_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+// TransientWindowClient implementation. Uses TransientWindowManager to handle
+// tracking transient per window.
+class WM_EXPORT TransientWindowController
+ : public aura::client::TransientWindowClient {
+ public:
+ TransientWindowController();
+ virtual ~TransientWindowController();
+
+ // TransientWindowClient:
+ virtual void AddTransientChild(aura::Window* parent,
+ aura::Window* child) OVERRIDE;
+ virtual void RemoveTransientChild(aura::Window* parent,
+ aura::Window* child) OVERRIDE;
+ virtual aura::Window* GetTransientParent(aura::Window* window) OVERRIDE;
+ virtual const aura::Window* GetTransientParent(
+ const aura::Window* window) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowController);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_TRANSIENT_WINDOW_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/transient_window_manager.cc b/chromium/ui/wm/core/transient_window_manager.cc
new file mode 100644
index 00000000000..120af84786c
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_manager.cc
@@ -0,0 +1,182 @@
+// 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/wm/core/transient_window_manager.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "base/auto_reset.h"
+#include "base/stl_util.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+#include "ui/wm/core/transient_window_observer.h"
+#include "ui/wm/core/transient_window_stacking_client.h"
+#include "ui/wm/core/window_util.h"
+
+using aura::Window;
+
+namespace wm {
+
+DEFINE_OWNED_WINDOW_PROPERTY_KEY(TransientWindowManager, kPropertyKey, NULL);
+
+TransientWindowManager::~TransientWindowManager() {
+}
+
+// static
+TransientWindowManager* TransientWindowManager::Get(Window* window) {
+ TransientWindowManager* manager = window->GetProperty(kPropertyKey);
+ if (!manager) {
+ manager = new TransientWindowManager(window);
+ window->SetProperty(kPropertyKey, manager);
+ }
+ return manager;
+}
+
+// static
+const TransientWindowManager* TransientWindowManager::Get(
+ const Window* window) {
+ return window->GetProperty(kPropertyKey);
+}
+
+void TransientWindowManager::AddObserver(TransientWindowObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void TransientWindowManager::RemoveObserver(TransientWindowObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void TransientWindowManager::AddTransientChild(Window* child) {
+ // TransientWindowStackingClient does the stacking of transient windows. If it
+ // isn't installed stacking is going to be wrong.
+ DCHECK(TransientWindowStackingClient::instance_);
+
+ TransientWindowManager* child_manager = Get(child);
+ if (child_manager->transient_parent_)
+ Get(child_manager->transient_parent_)->RemoveTransientChild(child);
+ DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
+ child) == transient_children_.end());
+ transient_children_.push_back(child);
+ child_manager->transient_parent_ = window_;
+
+ // Restack |child| properly above its transient parent, if they share the same
+ // parent.
+ if (child->parent() == window_->parent())
+ RestackTransientDescendants();
+
+ FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
+ OnTransientChildAdded(window_, child));
+}
+
+void TransientWindowManager::RemoveTransientChild(Window* child) {
+ Windows::iterator i =
+ std::find(transient_children_.begin(), transient_children_.end(), child);
+ DCHECK(i != transient_children_.end());
+ transient_children_.erase(i);
+ TransientWindowManager* child_manager = Get(child);
+ DCHECK_EQ(window_, child_manager->transient_parent_);
+ child_manager->transient_parent_ = NULL;
+
+ // If |child| and its former transient parent share the same parent, |child|
+ // should be restacked properly so it is not among transient children of its
+ // former parent, anymore.
+ if (window_->parent() == child->parent())
+ RestackTransientDescendants();
+
+ FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
+ OnTransientChildRemoved(window_, child));
+}
+
+bool TransientWindowManager::IsStackingTransient(
+ const aura::Window* target) const {
+ return stacking_target_ == target;
+}
+
+TransientWindowManager::TransientWindowManager(Window* window)
+ : window_(window),
+ transient_parent_(NULL),
+ stacking_target_(NULL) {
+ window_->AddObserver(this);
+}
+
+void TransientWindowManager::RestackTransientDescendants() {
+ Window* parent = window_->parent();
+ if (!parent)
+ return;
+
+ // Stack any transient children that share the same parent to be in front of
+ // |window_|. The existing stacking order is preserved by iterating backwards
+ // and always stacking on top.
+ Window::Windows children(parent->children());
+ for (Window::Windows::reverse_iterator it = children.rbegin();
+ it != children.rend(); ++it) {
+ if ((*it) != window_ && HasTransientAncestor(*it, window_)) {
+ TransientWindowManager* descendant_manager = Get(*it);
+ base::AutoReset<Window*> resetter(
+ &descendant_manager->stacking_target_,
+ window_);
+ parent->StackChildAbove((*it), window_);
+ }
+ }
+}
+
+void TransientWindowManager::OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) {
+ DCHECK_EQ(window_, window);
+ // Stack |window| properly if it is transient child of a sibling.
+ Window* transient_parent = wm::GetTransientParent(window);
+ if (transient_parent && transient_parent->parent() == parent) {
+ TransientWindowManager* transient_parent_manager =
+ Get(transient_parent);
+ transient_parent_manager->RestackTransientDescendants();
+ }
+}
+
+void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
+ bool visible) {
+ // TODO(sky): move handling of becoming visible here.
+ if (!visible) {
+ std::for_each(transient_children_.begin(), transient_children_.end(),
+ std::mem_fun(&Window::Hide));
+ }
+}
+
+void TransientWindowManager::OnWindowStackingChanged(Window* window) {
+ DCHECK_EQ(window_, window);
+
+ // Do nothing if we initiated the stacking change.
+ const TransientWindowManager* transient_manager =
+ Get(static_cast<const Window*>(window));
+ if (transient_manager && transient_manager->stacking_target_) {
+ Windows::const_iterator window_i = std::find(
+ window->parent()->children().begin(),
+ window->parent()->children().end(),
+ window);
+ DCHECK(window_i != window->parent()->children().end());
+ if (window_i != window->parent()->children().begin() &&
+ (*(window_i - 1) == transient_manager->stacking_target_))
+ return;
+ }
+
+ RestackTransientDescendants();
+}
+
+void TransientWindowManager::OnWindowDestroying(Window* window) {
+ // Removes ourselves from our transient parent (if it hasn't been done by the
+ // RootWindow).
+ if (transient_parent_) {
+ TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
+ window_);
+ }
+
+ // Destroy transient children, only after we've removed ourselves from our
+ // parent, as destroying an active transient child may otherwise attempt to
+ // refocus us.
+ Windows transient_children(transient_children_);
+ STLDeleteElements(&transient_children);
+ DCHECK(transient_children_.empty());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/transient_window_manager.h b/chromium/ui/wm/core/transient_window_manager.h
new file mode 100644
index 00000000000..7d37679f924
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_manager.h
@@ -0,0 +1,91 @@
+// 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_WM_CORE_TRANSIENT_WINDOW_MANAGER_H_
+#define UI_WM_CORE_TRANSIENT_WINDOW_MANAGER_H_
+
+#include <vector>
+
+#include "base/observer_list.h"
+#include "ui/aura/window_observer.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class TransientWindowObserver;
+
+// TransientWindowManager manages the set of transient children for a window
+// along with the transient parent. Transient children get the following
+// behavior:
+// . The transient parent destroys any transient children when it is
+// destroyed. This means a transient child is destroyed if either its parent
+// or transient parent is destroyed.
+// . If a transient child and its transient parent share the same parent, then
+// transient children are always ordered above the transient parent.
+// Transient windows are typically used for popups and menus.
+// TODO(sky): when we nuke TransientWindowClient rename this to
+// TransientWindowController.
+class WM_EXPORT TransientWindowManager : public aura::WindowObserver {
+ public:
+ typedef std::vector<aura::Window*> Windows;
+
+ virtual ~TransientWindowManager();
+
+ // Returns the TransientWindowManager for |window|. This never returns NULL.
+ static TransientWindowManager* Get(aura::Window* window);
+
+ // Returns the TransientWindowManager for |window| only if it already exists.
+ // WARNING: this may return NULL.
+ static const TransientWindowManager* Get(const aura::Window* window);
+
+ void AddObserver(TransientWindowObserver* observer);
+ void RemoveObserver(TransientWindowObserver* observer);
+
+ // Adds or removes a transient child.
+ void AddTransientChild(aura::Window* child);
+ void RemoveTransientChild(aura::Window* child);
+
+ const Windows& transient_children() const { return transient_children_; }
+
+ aura::Window* transient_parent() { return transient_parent_; }
+ const aura::Window* transient_parent() const { return transient_parent_; }
+
+ // Returns true if in the process of stacking |window_| on top of |target|.
+ // That is, when the stacking order of a window changes
+ // (OnWindowStackingChanged()) the transients may get restacked as well. This
+ // function can be used to detect if TransientWindowManager is in the process
+ // of stacking a transient as the result of window stacking changing.
+ bool IsStackingTransient(const aura::Window* target) const;
+
+ private:
+ explicit TransientWindowManager(aura::Window* window);
+
+ // Stacks transient descendants of this window that are its siblings just
+ // above it.
+ void RestackTransientDescendants();
+
+ // WindowObserver:
+ virtual void OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) OVERRIDE;
+ virtual void OnWindowVisibilityChanging(aura::Window* window,
+ bool visible) OVERRIDE;
+ virtual void OnWindowStackingChanged(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ aura::Window* window_;
+ aura::Window* transient_parent_;
+ Windows transient_children_;
+
+ // If non-null we're actively restacking transient as the result of a
+ // transient ancestor changing.
+ aura::Window* stacking_target_;
+
+ ObserverList<TransientWindowObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowManager);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_TRANSIENT_WINDOW_MANAGER_H_
diff --git a/chromium/ui/wm/core/transient_window_manager_unittest.cc b/chromium/ui/wm/core/transient_window_manager_unittest.cc
new file mode 100644
index 00000000000..05b8e88e4de
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_manager_unittest.cc
@@ -0,0 +1,666 @@
+// 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/wm/core/transient_window_manager.h"
+
+#include "ui/aura/client/visibility_client.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/layout_manager.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/wm/core/transient_window_observer.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/core/wm_state.h"
+
+using aura::Window;
+
+using aura::test::ChildWindowIDsAsString;
+using aura::test::CreateTestWindowWithId;
+
+namespace wm {
+
+class TestTransientWindowObserver : public TransientWindowObserver {
+ public:
+ TestTransientWindowObserver() : add_count_(0), remove_count_(0) {
+ }
+
+ virtual ~TestTransientWindowObserver() {
+ }
+
+ int add_count() const { return add_count_; }
+ int remove_count() const { return remove_count_; }
+
+ // TransientWindowObserver overrides:
+ virtual void OnTransientChildAdded(Window* window,
+ Window* transient) OVERRIDE {
+ add_count_++;
+ }
+ virtual void OnTransientChildRemoved(Window* window,
+ Window* transient) OVERRIDE {
+ remove_count_++;
+ }
+
+ private:
+ int add_count_;
+ int remove_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTransientWindowObserver);
+};
+
+class TransientWindowManagerTest : public aura::test::AuraTestBase {
+ public:
+ TransientWindowManagerTest() {}
+ virtual ~TransientWindowManagerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ wm_state_.reset(new wm::WMState);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ wm_state_.reset();
+ AuraTestBase::TearDown();
+ }
+
+ protected:
+ // Creates a transient window that is transient to |parent|.
+ Window* CreateTransientChild(int id, Window* parent) {
+ Window* window = new Window(NULL);
+ window->set_id(id);
+ window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window->Init(aura::WINDOW_LAYER_TEXTURED);
+ AddTransientChild(parent, window);
+ aura::client::ParentWindowWithContext(window, root_window(), gfx::Rect());
+ return window;
+ }
+
+ private:
+ scoped_ptr<wm::WMState> wm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowManagerTest);
+};
+
+// Various assertions for transient children.
+TEST_F(TransientWindowManagerTest, TransientChildren) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
+ Window* w2 = CreateTestWindowWithId(2, parent.get());
+ // w2 is now owned by w1.
+ AddTransientChild(w1.get(), w2);
+ // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
+ parent->StackChildAtTop(w1.get());
+ ASSERT_EQ(3u, parent->children().size());
+ EXPECT_EQ(w2, parent->children().back());
+
+ // Destroy w1, which should also destroy w3 (since it's a transient child).
+ w1.reset();
+ w2 = NULL;
+ ASSERT_EQ(1u, parent->children().size());
+ EXPECT_EQ(w3.get(), parent->children()[0]);
+
+ w1.reset(CreateTestWindowWithId(4, parent.get()));
+ w2 = CreateTestWindowWithId(5, w3.get());
+ AddTransientChild(w1.get(), w2);
+ parent->StackChildAtTop(w3.get());
+ // Stack w1 at the top (end), this shouldn't affect w2 since it has a
+ // different parent.
+ parent->StackChildAtTop(w1.get());
+ ASSERT_EQ(2u, parent->children().size());
+ EXPECT_EQ(w3.get(), parent->children()[0]);
+ EXPECT_EQ(w1.get(), parent->children()[1]);
+
+ // Hiding parent should hide transient children.
+ EXPECT_TRUE(w2->IsVisible());
+ w1->Hide();
+ EXPECT_FALSE(w2->IsVisible());
+}
+
+// Tests that transient children are stacked as a unit when using stack above.
+TEST_F(TransientWindowManagerTest, TransientChildrenGroupAbove) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ // w11 is now owned by w1.
+ AddTransientChild(w1.get(), w11);
+ // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w21);
+ // w22 is now owned by w2.
+ AddTransientChild(w2.get(), w22);
+ // w211 is now owned by w21.
+ AddTransientChild(w21, w211);
+ // w212 is now owned by w21.
+ AddTransientChild(w21, w212);
+ // w213 is now owned by w21.
+ AddTransientChild(w21, w213);
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
+ parent->StackChildAtTop(w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtTop(w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w22);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w213, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent above its transient child.
+ parent->StackChildAbove(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAbove(w2.get(), w1.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w213);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient children are stacked as a unit when using stack below.
+TEST_F(TransientWindowManagerTest, TransientChildrenGroupBelow) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ // w11 is now owned by w1.
+ AddTransientChild(w1.get(), w11);
+ // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w21);
+ // w22 is now owned by w2.
+ AddTransientChild(w2.get(), w22);
+ // w211 is now owned by w21.
+ AddTransientChild(w21, w211);
+ // w212 is now owned by w21.
+ AddTransientChild(w21, w212);
+ // w213 is now owned by w21.
+ AddTransientChild(w21, w213);
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
+ // This also tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtBottom(w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAtBottom(w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w11, w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w22, w21);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent below its transient child.
+ parent->StackChildBelow(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w1.get(), w2.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient windows are stacked properly when created.
+TEST_F(TransientWindowManagerTest, StackUponCreation) {
+ scoped_ptr<Window> window0(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+
+ scoped_ptr<Window> window2(CreateTransientChild(2, window0.get()));
+ EXPECT_EQ("0 2 1", ChildWindowIDsAsString(root_window()));
+}
+
+// Tests that windows are restacked properly after a call to AddTransientChild()
+// or RemoveTransientChild().
+TEST_F(TransientWindowManagerTest, RestackUponAddOrRemoveTransientChild) {
+ scoped_ptr<Window> windows[4];
+ for (int i = 0; i < 4; i++)
+ windows[i].reset(CreateTestWindowWithId(i, root_window()));
+ EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(root_window()));
+
+ AddTransientChild(windows[0].get(), windows[2].get());
+ EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(root_window()));
+
+ AddTransientChild(windows[0].get(), windows[3].get());
+ EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(root_window()));
+
+ RemoveTransientChild(windows[0].get(), windows[2].get());
+ EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
+
+ RemoveTransientChild(windows[0].get(), windows[3].get());
+ EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(root_window()));
+}
+
+namespace {
+
+// Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
+// OnWindowDestroyed() is invoked so that destruction order can be verified.
+class DestroyedTrackingDelegate : public aura::test::TestWindowDelegate {
+ public:
+ explicit DestroyedTrackingDelegate(const std::string& name,
+ std::vector<std::string>* results)
+ : name_(name),
+ results_(results) {}
+
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ results_->push_back(name_);
+ }
+
+ private:
+ const std::string name_;
+ std::vector<std::string>* results_;
+
+ DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
+};
+
+} // namespace
+
+// Verifies the delegate is notified of destruction after transients are
+// destroyed.
+TEST_F(TransientWindowManagerTest, NotifyDelegateAfterDeletingTransients) {
+ std::vector<std::string> destruction_order;
+
+ DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
+ scoped_ptr<Window> parent(new Window(&parent_delegate));
+ parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+
+ DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
+ Window* transient = new Window(&transient_delegate); // Owned by |parent|.
+ transient->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+ AddTransientChild(parent.get(), transient);
+ parent.reset();
+
+ ASSERT_EQ(2u, destruction_order.size());
+ EXPECT_EQ("transient", destruction_order[0]);
+ EXPECT_EQ("parent", destruction_order[1]);
+}
+
+TEST_F(TransientWindowManagerTest, StackTransientsWhoseLayersHaveNoDelegate) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
+
+ EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
+
+ // Remove the delegates of a couple of transients, as if they are closing
+ // and animating out.
+ window11->layer()->set_delegate(NULL);
+ window13->layer()->set_delegate(NULL);
+
+ // Move window1 to the front. All transients should move with it, and their
+ // order should be preserved.
+ root_window()->StackChildAtTop(window1.get());
+
+ EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
+}
+
+TEST_F(TransientWindowManagerTest,
+ StackTransientsLayersRelativeToOtherTransients) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+
+ EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
+
+ // Stack 11 above 12.
+ root_window()->StackChildAbove(window11.get(), window12.get());
+ EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(root_window()));
+
+ // Stack 13 below 12.
+ root_window()->StackChildBelow(window13.get(), window12.get());
+ EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(root_window()));
+
+ // Stack 11 above 1.
+ root_window()->StackChildAbove(window11.get(), window1.get());
+ EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(root_window()));
+
+ // Stack 12 below 13.
+ root_window()->StackChildBelow(window12.get(), window13.get());
+ EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window()));
+}
+
+TEST_F(TransientWindowManagerTest,
+ StackTransientsLayersRelativeToOtherTransientsNoLayerDelegate) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
+
+ EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
+
+ window1->layer()->set_delegate(NULL);
+
+ // Stack 1 at top.
+ root_window()->StackChildAtTop(window1.get());
+ EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
+}
+
+class StackingMadrigalLayoutManager : public aura::LayoutManager {
+ public:
+ explicit StackingMadrigalLayoutManager(Window* root_window)
+ : root_window_(root_window) {
+ root_window_->SetLayoutManager(this);
+ }
+ virtual ~StackingMadrigalLayoutManager() {
+ }
+
+ private:
+ // Overridden from LayoutManager:
+ virtual void OnWindowResized() OVERRIDE {}
+ virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {}
+ virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {}
+ virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {}
+ virtual void OnChildWindowVisibilityChanged(Window* child,
+ bool visible) OVERRIDE {
+ Window::Windows::const_iterator it = root_window_->children().begin();
+ Window* last_window = NULL;
+ for (; it != root_window_->children().end(); ++it) {
+ if (*it == child && last_window) {
+ if (!visible)
+ root_window_->StackChildAbove(last_window, *it);
+ else
+ root_window_->StackChildAbove(*it, last_window);
+ break;
+ }
+ last_window = *it;
+ }
+ }
+ virtual void SetChildBounds(Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE {
+ SetChildBoundsDirect(child, requested_bounds);
+ }
+
+ Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
+};
+
+class StackingMadrigalVisibilityClient : public aura::client::VisibilityClient {
+ public:
+ explicit StackingMadrigalVisibilityClient(Window* root_window)
+ : ignored_window_(NULL) {
+ aura::client::SetVisibilityClient(root_window, this);
+ }
+ virtual ~StackingMadrigalVisibilityClient() {
+ }
+
+ void set_ignored_window(Window* ignored_window) {
+ ignored_window_ = ignored_window;
+ }
+
+ private:
+ // Overridden from client::VisibilityClient:
+ virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
+ if (!visible) {
+ if (window == ignored_window_)
+ window->layer()->set_delegate(NULL);
+ else
+ window->layer()->SetVisible(visible);
+ } else {
+ window->layer()->SetVisible(visible);
+ }
+ }
+
+ Window* ignored_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
+};
+
+// This test attempts to reconstruct a circumstance that can happen when the
+// aura client attempts to manipulate the visibility and delegate of a layer
+// independent of window visibility.
+// A use case is where the client attempts to keep a window visible onscreen
+// even after code has called Hide() on the window. The use case for this would
+// be that window hides are animated (e.g. the window fades out). To prevent
+// spurious updating the client code may also clear window's layer's delegate,
+// so that the window cannot attempt to paint or update it further. The window
+// uses the presence of a NULL layer delegate as a signal in stacking to note
+// that the window is being manipulated by such a use case and its stacking
+// should not be adjusted.
+// One issue that can arise when a window opens two transient children, and the
+// first is hidden. Subsequent attempts to activate the transient parent can
+// result in the transient parent being stacked above the second transient
+// child. A fix is made to Window::StackAbove to prevent this, and this test
+// verifies this fix.
+TEST_F(TransientWindowManagerTest, StackingMadrigal) {
+ new StackingMadrigalLayoutManager(root_window());
+ StackingMadrigalVisibilityClient visibility_client(root_window());
+
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+
+ visibility_client.set_ignored_window(window11.get());
+
+ window11->Show();
+ window11->Hide();
+
+ // As a transient, window11 should still be stacked above window1, even when
+ // hidden.
+ EXPECT_TRUE(aura::test::WindowIsAbove(window11.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window11.get(), window1.get()));
+
+ // A new transient should still be above window1. It will appear behind
+ // window11 because we don't stack windows on top of targets with NULL
+ // delegates.
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ window12->Show();
+
+ EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
+
+ // In earlier versions of the StackChildAbove() method, attempting to stack
+ // window1 above window12 at this point would actually restack the layers
+ // resulting in window12's layer being below window1's layer (though the
+ // windows themselves would still be correctly stacked, so events would pass
+ // through.)
+ root_window()->StackChildAbove(window1.get(), window12.get());
+
+ // Both window12 and its layer should be stacked above window1.
+ EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
+}
+
+// Test for an issue where attempting to stack a primary window on top of a
+// transient with a NULL layer delegate causes that primary window to be moved,
+// but the layer order not changed to match. http://crbug.com/112562
+TEST_F(TransientWindowManagerTest, StackOverClosingTransient) {
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
+ scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
+
+ // Both windows and layers are stacked in creation order.
+ Window* root = root_window();
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], transient1.get());
+ EXPECT_EQ(root->children()[2], window2.get());
+ EXPECT_EQ(root->children()[3], transient2.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient1->layer());
+ EXPECT_EQ(root->layer()->children()[2], window2->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient2->layer());
+ EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window()));
+
+ // This brings window1 and its transient to the front.
+ root->StackChildAtTop(window1.get());
+ EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window()));
+
+ EXPECT_EQ(root->children()[0], window2.get());
+ EXPECT_EQ(root->children()[1], transient2.get());
+ EXPECT_EQ(root->children()[2], window1.get());
+ EXPECT_EQ(root->children()[3], transient1.get());
+ EXPECT_EQ(root->layer()->children()[0], window2->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[2], window1->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient1->layer());
+
+ // Pretend we're closing the top-most transient, then bring window2 to the
+ // front. This mimics activating a browser window while the status bubble
+ // is fading out. The transient should stay topmost.
+ transient1->layer()->set_delegate(NULL);
+ root->StackChildAtTop(window2.get());
+
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], transient1.get());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient1->layer());
+
+ // Close the transient. Remaining windows are stable.
+ transient1.reset();
+
+ ASSERT_EQ(3u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ ASSERT_EQ(3u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+
+ // Open another window on top.
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+
+ // Pretend we're closing the topmost non-transient window, then bring
+ // window2 to the top. It should not move.
+ window3->layer()->set_delegate(NULL);
+ root->StackChildAtTop(window2.get());
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+
+ // Bring window1 to the top. It should move ahead of window2, but not
+ // ahead of window3 (with NULL delegate).
+ root->StackChildAtTop(window1.get());
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window2.get());
+ EXPECT_EQ(root->children()[1], transient2.get());
+ EXPECT_EQ(root->children()[2], window1.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window2->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[2], window1->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+}
+
+// Verifies TransientWindowObserver is notified appropriately.
+TEST_F(TransientWindowManagerTest, TransientWindowObserverNotified) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+
+ TestTransientWindowObserver test_observer;
+ TransientWindowManager::Get(parent.get())->AddObserver(&test_observer);
+
+ AddTransientChild(parent.get(), w1.get());
+ EXPECT_EQ(1, test_observer.add_count());
+ EXPECT_EQ(0, test_observer.remove_count());
+
+ RemoveTransientChild(parent.get(), w1.get());
+ EXPECT_EQ(1, test_observer.add_count());
+ EXPECT_EQ(1, test_observer.remove_count());
+
+ TransientWindowManager::Get(parent.get())->RemoveObserver(&test_observer);
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/transient_window_observer.h b/chromium/ui/wm/core/transient_window_observer.h
new file mode 100644
index 00000000000..aff5af5e2ef
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_observer.h
@@ -0,0 +1,32 @@
+// 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_WM_CORE_TRANSIENT_WINDOW_OBSERVER_H_
+#define UI_WM_CORE_TRANSIENT_WINDOW_OBSERVER_H_
+
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace wm {
+
+class WM_EXPORT TransientWindowObserver {
+ public:
+ // Called when a transient child is added to |window|.
+ virtual void OnTransientChildAdded(aura::Window* window,
+ aura::Window* transient) = 0;
+
+ // Called when a transient child is removed from |window|.
+ virtual void OnTransientChildRemoved(aura::Window* window,
+ aura::Window* transient) = 0;
+
+ protected:
+ virtual ~TransientWindowObserver() {}
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_TRANSIENT_WINDOW_OBSERVER_H_
diff --git a/chromium/ui/wm/core/transient_window_stacking_client.cc b/chromium/ui/wm/core/transient_window_stacking_client.cc
new file mode 100644
index 00000000000..f8dc42c51f0
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_stacking_client.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/transient_window_stacking_client.h"
+
+#include <algorithm>
+
+#include "ui/wm/core/transient_window_manager.h"
+#include "ui/wm/core/window_util.h"
+
+using aura::Window;
+
+namespace wm {
+
+namespace {
+
+// Populates |ancestors| with all transient ancestors of |window| that are
+// siblings of |window|. Returns true if any ancestors were found, false if not.
+bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) {
+ Window* parent = window->parent();
+ for (; window; window = GetTransientParent(window)) {
+ if (window->parent() == parent)
+ ancestors->push_back(window);
+ }
+ return (!ancestors->empty());
+}
+
+// Replaces |window1| and |window2| with their possible transient ancestors that
+// are still siblings (have a common transient parent). |window1| and |window2|
+// are not modified if such ancestors cannot be found.
+void FindCommonTransientAncestor(Window** window1, Window** window2) {
+ DCHECK(window1);
+ DCHECK(window2);
+ DCHECK(*window1);
+ DCHECK(*window2);
+ // Assemble chains of ancestors of both windows.
+ Window::Windows ancestors1;
+ Window::Windows ancestors2;
+ if (!GetAllTransientAncestors(*window1, &ancestors1) ||
+ !GetAllTransientAncestors(*window2, &ancestors2)) {
+ return;
+ }
+ // Walk the two chains backwards and look for the first difference.
+ Window::Windows::reverse_iterator it1 = ancestors1.rbegin();
+ Window::Windows::reverse_iterator it2 = ancestors2.rbegin();
+ for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
+ if (*it1 != *it2) {
+ *window1 = *it1;
+ *window2 = *it2;
+ break;
+ }
+ }
+}
+
+// Adjusts |target| so that we don't attempt to stack on top of a window with a
+// NULL delegate.
+void SkipNullDelegates(Window::StackDirection direction, Window** target) {
+ const Window::Windows& children((*target)->parent()->children());
+ size_t target_i =
+ std::find(children.begin(), children.end(), *target) -
+ children.begin();
+
+ // By convention we don't stack on top of windows with layers with NULL
+ // delegates. Walk backward to find a valid target window. See tests
+ // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient
+ // for an explanation of this.
+ while (target_i > 0) {
+ const size_t index = direction == Window::STACK_ABOVE ?
+ target_i : target_i - 1;
+ if (!children[index]->layer() ||
+ children[index]->layer()->delegate() != NULL)
+ break;
+ --target_i;
+ }
+ *target = children[target_i];
+}
+
+} // namespace
+
+// static
+TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL;
+
+TransientWindowStackingClient::TransientWindowStackingClient() {
+ instance_ = this;
+}
+
+TransientWindowStackingClient::~TransientWindowStackingClient() {
+ if (instance_ == this)
+ instance_ = NULL;
+}
+
+bool TransientWindowStackingClient::AdjustStacking(
+ Window** child,
+ Window** target,
+ Window::StackDirection* direction) {
+ const TransientWindowManager* transient_manager =
+ TransientWindowManager::Get(static_cast<const Window*>(*child));
+ if (transient_manager && transient_manager->IsStackingTransient(*target))
+ return true;
+
+ // For windows that have transient children stack the transient ancestors that
+ // are siblings. This prevents one transient group from being inserted in the
+ // middle of another.
+ FindCommonTransientAncestor(child, target);
+
+ // When stacking above skip to the topmost transient descendant of the target.
+ if (*direction == Window::STACK_ABOVE &&
+ !HasTransientAncestor(*child, *target)) {
+ const Window::Windows& siblings((*child)->parent()->children());
+ size_t target_i =
+ std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
+ while (target_i + 1 < siblings.size() &&
+ HasTransientAncestor(siblings[target_i + 1], *target)) {
+ ++target_i;
+ }
+ *target = siblings[target_i];
+ }
+
+ SkipNullDelegates(*direction, target);
+
+ // If we couldn't find a valid target position, don't move anything.
+ if (*direction == Window::STACK_ABOVE &&
+ ((*target)->layer() && (*target)->layer()->delegate() == NULL)) {
+ return false;
+ }
+
+ return *child != *target;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/transient_window_stacking_client.h b/chromium/ui/wm/core/transient_window_stacking_client.h
new file mode 100644
index 00000000000..4ab4aea1742
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_stacking_client.h
@@ -0,0 +1,37 @@
+// 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_WM_CORE_TRANSIENT_WINDOW_STACKING_CLIENT_H_
+#define UI_WM_CORE_TRANSIENT_WINDOW_STACKING_CLIENT_H_
+
+#include "ui/aura/client/window_stacking_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class TransientWindowManager;
+
+class WM_EXPORT TransientWindowStackingClient
+ : public aura::client::WindowStackingClient {
+ public:
+ TransientWindowStackingClient();
+ virtual ~TransientWindowStackingClient();
+
+ // WindowStackingClient:
+ virtual bool AdjustStacking(aura::Window** child,
+ aura::Window** target,
+ aura::Window::StackDirection* direction) OVERRIDE;
+
+ private:
+ // Purely for DCHECKs.
+ friend class TransientWindowManager;
+
+ static TransientWindowStackingClient* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClient);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_TRANSIENT_WINDOW_STACKING_CLIENT_H_
diff --git a/chromium/ui/wm/core/transient_window_stacking_client_unittest.cc b/chromium/ui/wm/core/transient_window_stacking_client_unittest.cc
new file mode 100644
index 00000000000..c5d3bd05319
--- /dev/null
+++ b/chromium/ui/wm/core/transient_window_stacking_client_unittest.cc
@@ -0,0 +1,215 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/transient_window_stacking_client.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/compositor/test/test_layers.h"
+#include "ui/wm/core/window_util.h"
+
+using aura::test::ChildWindowIDsAsString;
+using aura::test::CreateTestWindowWithId;
+using aura::Window;
+
+namespace wm {
+
+class TransientWindowStackingClientTest : public aura::test::AuraTestBase {
+ public:
+ TransientWindowStackingClientTest() {}
+ virtual ~TransientWindowStackingClientTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ client_.reset(new TransientWindowStackingClient);
+ aura::client::SetWindowStackingClient(client_.get());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ aura::client::SetWindowStackingClient(NULL);
+ AuraTestBase::TearDown();
+ }
+
+ private:
+ scoped_ptr<TransientWindowStackingClient> client_;
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClientTest);
+};
+
+// Tests that transient children are stacked as a unit when using stack above.
+TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupAbove) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ AddTransientChild(w1.get(), w11); // w11 is now owned by w1.
+ AddTransientChild(w2.get(), w21); // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w22); // w22 is now owned by w2.
+ AddTransientChild(w21, w211); // w211 is now owned by w21.
+ AddTransientChild(w21, w212); // w212 is now owned by w21.
+ AddTransientChild(w21, w213); // w213 is now owned by w21.
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
+ parent->StackChildAtTop(w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtTop(w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w22);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w213, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent above its transient child.
+ parent->StackChildAbove(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAbove(w2.get(), w1.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w213);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient children are stacked as a unit when using stack below.
+TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ AddTransientChild(w1.get(), w11); // w11 is now owned by w1.
+ AddTransientChild(w2.get(), w21); // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w22); // w22 is now owned by w2.
+ AddTransientChild(w21, w211); // w211 is now owned by w21.
+ AddTransientChild(w21, w212); // w212 is now owned by w21.
+ AddTransientChild(w21, w213); // w213 is now owned by w21.
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
+ // This also tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtBottom(w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAtBottom(w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w11, w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w22, w21);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent below its transient child.
+ parent->StackChildBelow(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w1.get(), w2.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+TEST_F(TransientWindowStackingClientTest,
+ StackWindowsWhoseLayersHaveNoDelegate) {
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ window1->layer()->set_name("1");
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
+ window2->layer()->set_name("2");
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
+ window3->layer()->set_name("3");
+
+ // This brings |window1| (and its layer) to the front.
+ root_window()->StackChildAbove(window1.get(), window3.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // Since |window1| does not have a delegate, |window2| should not move in
+ // front of it, nor should its layer.
+ window1->layer()->set_delegate(NULL);
+ root_window()->StackChildAbove(window2.get(), window1.get());
+ EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("3 2 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // It should still be possible to stack |window3| immediately below |window1|.
+ root_window()->StackChildBelow(window3.get(), window1.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // Since neither |window3| nor |window1| have a delegate, |window2| should
+ // not move in front of either.
+ window3->layer()->set_delegate(NULL);
+ root_window()->StackChildBelow(window2.get(), window1.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/user_activity_detector.cc b/chromium/ui/wm/core/user_activity_detector.cc
new file mode 100644
index 00000000000..56bf563b3d0
--- /dev/null
+++ b/chromium/ui/wm/core/user_activity_detector.cc
@@ -0,0 +1,112 @@
+// 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/wm/core/user_activity_detector.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "ui/events/event.h"
+#include "ui/wm/core/user_activity_observer.h"
+
+namespace wm {
+
+namespace {
+
+// Returns a string describing |event|.
+std::string GetEventDebugString(const ui::Event* event) {
+ std::string details = base::StringPrintf(
+ "type=%d name=%s flags=%d time=%" PRId64,
+ event->type(), event->name().c_str(), event->flags(),
+ event->time_stamp().InMilliseconds());
+
+ if (event->IsKeyEvent()) {
+ details += base::StringPrintf(" key_code=%d",
+ static_cast<const ui::KeyEvent*>(event)->key_code());
+ } else if (event->IsMouseEvent() || event->IsTouchEvent() ||
+ event->IsGestureEvent()) {
+ details += base::StringPrintf(" location=%s",
+ static_cast<const ui::LocatedEvent*>(
+ event)->location().ToString().c_str());
+ }
+
+ return details;
+}
+
+} // namespace
+
+const int UserActivityDetector::kNotifyIntervalMs = 200;
+
+// Too low and mouse events generated at the tail end of reconfiguration
+// will be reported as user activity and turn the screen back on; too high
+// and we'll ignore legitimate activity.
+const int UserActivityDetector::kDisplayPowerChangeIgnoreMouseMs = 1000;
+
+UserActivityDetector::UserActivityDetector() {
+}
+
+UserActivityDetector::~UserActivityDetector() {
+}
+
+bool UserActivityDetector::HasObserver(UserActivityObserver* observer) const {
+ return observers_.HasObserver(observer);
+}
+
+void UserActivityDetector::AddObserver(UserActivityObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void UserActivityDetector::RemoveObserver(UserActivityObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void UserActivityDetector::OnDisplayPowerChanging() {
+ honor_mouse_events_time_ = GetCurrentTime() +
+ base::TimeDelta::FromMilliseconds(kDisplayPowerChangeIgnoreMouseMs);
+}
+
+void UserActivityDetector::OnKeyEvent(ui::KeyEvent* event) {
+ HandleActivity(event);
+}
+
+void UserActivityDetector::OnMouseEvent(ui::MouseEvent* event) {
+ if (event->flags() & ui::EF_IS_SYNTHESIZED)
+ return;
+ if (!honor_mouse_events_time_.is_null() &&
+ GetCurrentTime() < honor_mouse_events_time_)
+ return;
+
+ HandleActivity(event);
+}
+
+void UserActivityDetector::OnScrollEvent(ui::ScrollEvent* event) {
+ HandleActivity(event);
+}
+
+void UserActivityDetector::OnTouchEvent(ui::TouchEvent* event) {
+ HandleActivity(event);
+}
+
+void UserActivityDetector::OnGestureEvent(ui::GestureEvent* event) {
+ HandleActivity(event);
+}
+
+base::TimeTicks UserActivityDetector::GetCurrentTime() const {
+ return !now_for_test_.is_null() ? now_for_test_ : base::TimeTicks::Now();
+}
+
+void UserActivityDetector::HandleActivity(const ui::Event* event) {
+ base::TimeTicks now = GetCurrentTime();
+ last_activity_time_ = now;
+ if (last_observer_notification_time_.is_null() ||
+ (now - last_observer_notification_time_).InMillisecondsF() >=
+ kNotifyIntervalMs) {
+ if (VLOG_IS_ON(1))
+ VLOG(1) << "Reporting user activity: " << GetEventDebugString(event);
+ FOR_EACH_OBSERVER(UserActivityObserver, observers_, OnUserActivity(event));
+ last_observer_notification_time_ = now;
+ }
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/user_activity_detector.h b/chromium/ui/wm/core/user_activity_detector.h
new file mode 100644
index 00000000000..851f07ac325
--- /dev/null
+++ b/chromium/ui/wm/core/user_activity_detector.h
@@ -0,0 +1,81 @@
+// 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_WM_CORE_USER_ACTIVITY_DETECTOR_H_
+#define UI_WM_CORE_USER_ACTIVITY_DETECTOR_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class UserActivityObserver;
+
+// Watches for input events and notifies observers that the user is active.
+class WM_EXPORT UserActivityDetector : public ui::EventHandler {
+ public:
+ // Minimum amount of time between notifications to observers.
+ static const int kNotifyIntervalMs;
+
+ // Amount of time that mouse events should be ignored after notification
+ // is received that displays' power states are being changed.
+ static const int kDisplayPowerChangeIgnoreMouseMs;
+
+ UserActivityDetector();
+ virtual ~UserActivityDetector();
+
+ base::TimeTicks last_activity_time() const { return last_activity_time_; }
+
+ void set_now_for_test(base::TimeTicks now) { now_for_test_ = now; }
+
+ bool HasObserver(UserActivityObserver* observer) const;
+ void AddObserver(UserActivityObserver* observer);
+ void RemoveObserver(UserActivityObserver* observer);
+
+ // Called when displays are about to be turned on or off.
+ void OnDisplayPowerChanging();
+
+ // ui::EventHandler implementation.
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+
+ private:
+ // Returns |now_for_test_| if set or base::TimeTicks::Now() otherwise.
+ base::TimeTicks GetCurrentTime() const;
+
+ // Updates |last_activity_time_|. Additionally notifies observers and
+ // updates |last_observer_notification_time_| if enough time has passed
+ // since the last notification.
+ void HandleActivity(const ui::Event* event);
+
+ ObserverList<UserActivityObserver> observers_;
+
+ // Last time at which user activity was observed.
+ base::TimeTicks last_activity_time_;
+
+ // Last time at which we notified observers that the user was active.
+ base::TimeTicks last_observer_notification_time_;
+
+ // If set, used when the current time is needed. This can be set by tests to
+ // simulate the passage of time.
+ base::TimeTicks now_for_test_;
+
+ // If set, mouse events will be ignored until this time is reached. This
+ // is to avoid reporting mouse events that occur when displays are turned
+ // on or off as user activity.
+ base::TimeTicks honor_mouse_events_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserActivityDetector);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_USER_ACTIVITY_DETECTOR_H_
diff --git a/chromium/ui/wm/core/user_activity_detector_unittest.cc b/chromium/ui/wm/core/user_activity_detector_unittest.cc
new file mode 100644
index 00000000000..8ff14b4154f
--- /dev/null
+++ b/chromium/ui/wm/core/user_activity_detector_unittest.cc
@@ -0,0 +1,200 @@
+// 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/wm/core/user_activity_detector.h"
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/point.h"
+#include "ui/wm/core/user_activity_observer.h"
+
+namespace wm {
+
+// Implementation that just counts the number of times we've been told that the
+// user is active.
+class TestUserActivityObserver : public UserActivityObserver {
+ public:
+ TestUserActivityObserver() : num_invocations_(0) {}
+
+ int num_invocations() const { return num_invocations_; }
+ void reset_stats() { num_invocations_ = 0; }
+
+ // UserActivityObserver implementation.
+ virtual void OnUserActivity(const ui::Event* event) OVERRIDE {
+ num_invocations_++;
+ }
+
+ private:
+ // Number of times that OnUserActivity() has been called.
+ int num_invocations_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestUserActivityObserver);
+};
+
+class UserActivityDetectorTest : public aura::test::AuraTestBase {
+ public:
+ UserActivityDetectorTest() {}
+ virtual ~UserActivityDetectorTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ observer_.reset(new TestUserActivityObserver);
+ detector_.reset(new UserActivityDetector);
+ detector_->AddObserver(observer_.get());
+
+ now_ = base::TimeTicks::Now();
+ detector_->set_now_for_test(now_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ detector_->RemoveObserver(observer_.get());
+ AuraTestBase::TearDown();
+ }
+
+ protected:
+ // Move |detector_|'s idea of the current time forward by |delta|.
+ void AdvanceTime(base::TimeDelta delta) {
+ now_ += delta;
+ detector_->set_now_for_test(now_);
+ }
+
+ scoped_ptr<UserActivityDetector> detector_;
+ scoped_ptr<TestUserActivityObserver> observer_;
+
+ base::TimeTicks now_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UserActivityDetectorTest);
+};
+
+// Checks that the observer is notified in response to different types of input
+// events.
+TEST_F(UserActivityDetectorTest, Basic) {
+ ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false);
+ detector_->OnKeyEvent(&key_event);
+ EXPECT_FALSE(key_event.handled());
+ EXPECT_EQ(now_.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+
+ base::TimeDelta advance_delta = base::TimeDelta::FromMilliseconds(
+ UserActivityDetector::kNotifyIntervalMs);
+ AdvanceTime(advance_delta);
+ ui::MouseEvent mouse_event(
+ ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), ui::EF_NONE, ui::EF_NONE);
+ detector_->OnMouseEvent(&mouse_event);
+ EXPECT_FALSE(mouse_event.handled());
+ EXPECT_EQ(now_.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+
+ base::TimeTicks time_before_ignore = now_;
+
+ // Temporarily ignore mouse events when displays are turned on or off.
+ detector_->OnDisplayPowerChanging();
+ detector_->OnMouseEvent(&mouse_event);
+ EXPECT_FALSE(mouse_event.handled());
+ EXPECT_EQ(time_before_ignore.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(0, observer_->num_invocations());
+ observer_->reset_stats();
+
+ const base::TimeDelta kIgnoreMouseTime =
+ base::TimeDelta::FromMilliseconds(
+ UserActivityDetector::kDisplayPowerChangeIgnoreMouseMs);
+ AdvanceTime(kIgnoreMouseTime / 2);
+ detector_->OnMouseEvent(&mouse_event);
+ EXPECT_FALSE(mouse_event.handled());
+ EXPECT_EQ(time_before_ignore.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(0, observer_->num_invocations());
+ observer_->reset_stats();
+
+ // After enough time has passed, mouse events should be reported again.
+ AdvanceTime(std::max(kIgnoreMouseTime, advance_delta));
+ detector_->OnMouseEvent(&mouse_event);
+ EXPECT_FALSE(mouse_event.handled());
+ EXPECT_EQ(now_.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+
+ AdvanceTime(advance_delta);
+ ui::TouchEvent touch_event(
+ ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta());
+ detector_->OnTouchEvent(&touch_event);
+ EXPECT_FALSE(touch_event.handled());
+ EXPECT_EQ(now_.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+
+ AdvanceTime(advance_delta);
+ ui::GestureEvent gesture_event(
+ ui::ET_GESTURE_TAP, 0, 0, ui::EF_NONE,
+ base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000),
+ ui::GestureEventDetails(ui::ET_GESTURE_TAP, 0, 0), 0U);
+ detector_->OnGestureEvent(&gesture_event);
+ EXPECT_FALSE(gesture_event.handled());
+ EXPECT_EQ(now_.ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+}
+
+// Checks that observers aren't notified too frequently.
+TEST_F(UserActivityDetectorTest, RateLimitNotifications) {
+ // The observer should be notified about a key event.
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false);
+ detector_->OnKeyEvent(&event);
+ EXPECT_FALSE(event.handled());
+ EXPECT_EQ(1, observer_->num_invocations());
+ observer_->reset_stats();
+
+ // It shouldn't be notified if a second event occurs in the same instant in
+ // time.
+ detector_->OnKeyEvent(&event);
+ EXPECT_FALSE(event.handled());
+ EXPECT_EQ(0, observer_->num_invocations());
+ observer_->reset_stats();
+
+ // Advance the time, but not quite enough for another notification to be sent.
+ AdvanceTime(
+ base::TimeDelta::FromMilliseconds(
+ UserActivityDetector::kNotifyIntervalMs - 100));
+ detector_->OnKeyEvent(&event);
+ EXPECT_FALSE(event.handled());
+ EXPECT_EQ(0, observer_->num_invocations());
+ observer_->reset_stats();
+
+ // Advance time by the notification interval, definitely moving out of the
+ // rate limit. This should let us trigger another notification.
+ AdvanceTime(base::TimeDelta::FromMilliseconds(
+ UserActivityDetector::kNotifyIntervalMs));
+
+ detector_->OnKeyEvent(&event);
+ EXPECT_FALSE(event.handled());
+ EXPECT_EQ(1, observer_->num_invocations());
+}
+
+// Checks that the detector ignores synthetic mouse events.
+TEST_F(UserActivityDetectorTest, IgnoreSyntheticMouseEvents) {
+ ui::MouseEvent mouse_event(
+ ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), ui::EF_IS_SYNTHESIZED,
+ ui::EF_NONE);
+ detector_->OnMouseEvent(&mouse_event);
+ EXPECT_FALSE(mouse_event.handled());
+ EXPECT_EQ(base::TimeTicks().ToInternalValue(),
+ detector_->last_activity_time().ToInternalValue());
+ EXPECT_EQ(0, observer_->num_invocations());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/user_activity_observer.h b/chromium/ui/wm/core/user_activity_observer.h
new file mode 100644
index 00000000000..0fb35a61f06
--- /dev/null
+++ b/chromium/ui/wm/core/user_activity_observer.h
@@ -0,0 +1,35 @@
+// 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_WM_CORE_USER_ACTIVITY_OBSERVER_H_
+#define UI_WM_CORE_USER_ACTIVITY_OBSERVER_H_
+
+#include "base/basictypes.h"
+#include "ui/wm/wm_export.h"
+
+namespace ui {
+class Event;
+}
+
+namespace wm {
+
+// Interface for classes that want to be notified about user activity.
+// Implementations should register themselves with UserActivityDetector.
+class WM_EXPORT UserActivityObserver {
+ public:
+ // Invoked periodically while the user is active (i.e. generating input
+ // events). |event| is the event that triggered the notification; it may
+ // be NULL in some cases (e.g. testing or synthetic invocations).
+ virtual void OnUserActivity(const ui::Event* event) = 0;
+
+ protected:
+ UserActivityObserver() {}
+ virtual ~UserActivityObserver() {}
+
+ DISALLOW_COPY_AND_ASSIGN(UserActivityObserver);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_USER_ACTIVITY_OBSERVER_H_
diff --git a/chromium/ui/wm/core/visibility_controller.cc b/chromium/ui/wm/core/visibility_controller.cc
new file mode 100644
index 00000000000..fc187a94902
--- /dev/null
+++ b/chromium/ui/wm/core/visibility_controller.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/visibility_controller.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+#include "ui/compositor/layer.h"
+#include "ui/wm/core/window_animations.h"
+
+namespace wm {
+
+namespace {
+
+// Property set on all windows whose child windows' visibility changes are
+// animated.
+DEFINE_WINDOW_PROPERTY_KEY(
+ bool, kChildWindowVisibilityChangesAnimatedKey, false);
+
+bool ShouldAnimateWindow(aura::Window* window) {
+ return window->parent() && window->parent()->GetProperty(
+ kChildWindowVisibilityChangesAnimatedKey);
+}
+
+} // namespace
+
+VisibilityController::VisibilityController() {
+}
+
+VisibilityController::~VisibilityController() {
+}
+
+bool VisibilityController::CallAnimateOnChildWindowVisibilityChanged(
+ aura::Window* window,
+ bool visible) {
+ return AnimateOnChildWindowVisibilityChanged(window, visible);
+}
+
+void VisibilityController::UpdateLayerVisibility(aura::Window* window,
+ bool visible) {
+ bool animated = window->type() != ui::wm::WINDOW_TYPE_CONTROL &&
+ window->type() != ui::wm::WINDOW_TYPE_UNKNOWN &&
+ ShouldAnimateWindow(window);
+ animated = animated &&
+ CallAnimateOnChildWindowVisibilityChanged(window, visible);
+
+ // If we're already in the process of hiding don't do anything. Otherwise we
+ // may end up prematurely canceling the animation.
+ // This does not check opacity as when fading out a visibility change should
+ // also be scheduled (to do otherwise would mean the window can not be seen,
+ // opacity is 0, yet the window is marked as visible) (see CL 132903003).
+ // TODO(vollick): remove this.
+ if (!visible &&
+ window->layer()->GetAnimator()->IsAnimatingProperty(
+ ui::LayerAnimationElement::VISIBILITY) &&
+ !window->layer()->GetTargetVisibility()) {
+ return;
+ }
+
+ // When a window is made visible, we always make its layer visible
+ // immediately. When a window is hidden, the layer must be left visible and
+ // only made not visible once the animation is complete.
+ if (!animated || visible)
+ window->layer()->SetVisible(visible);
+}
+
+SuspendChildWindowVisibilityAnimations::SuspendChildWindowVisibilityAnimations(
+ aura::Window* window)
+ : window_(window),
+ original_enabled_(window->GetProperty(
+ kChildWindowVisibilityChangesAnimatedKey)) {
+ window_->ClearProperty(kChildWindowVisibilityChangesAnimatedKey);
+}
+
+SuspendChildWindowVisibilityAnimations::
+ ~SuspendChildWindowVisibilityAnimations() {
+ if (original_enabled_)
+ window_->SetProperty(kChildWindowVisibilityChangesAnimatedKey, true);
+ else
+ window_->ClearProperty(kChildWindowVisibilityChangesAnimatedKey);
+}
+
+void SetChildWindowVisibilityChangesAnimated(aura::Window* window) {
+ window->SetProperty(kChildWindowVisibilityChangesAnimatedKey, true);
+}
+
+} // namespace wm
+
diff --git a/chromium/ui/wm/core/visibility_controller.h b/chromium/ui/wm/core/visibility_controller.h
new file mode 100644
index 00000000000..47ae9910c7d
--- /dev/null
+++ b/chromium/ui/wm/core/visibility_controller.h
@@ -0,0 +1,74 @@
+// 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_WM_CORE_VISIBILITY_CONTROLLER_H_
+#define UI_WM_CORE_VISIBILITY_CONTROLLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "ui/aura/client/visibility_client.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class WM_EXPORT VisibilityController
+ : public aura::client::VisibilityClient {
+ public:
+ VisibilityController();
+ virtual ~VisibilityController();
+
+ protected:
+ // Subclasses override if they want to call a different implementation of
+ // this function.
+ // TODO(beng): potentially replace by an actual window animator class in
+ // window_animations.h.
+ virtual bool CallAnimateOnChildWindowVisibilityChanged(aura::Window* window,
+ bool visible);
+
+ private:
+ // Overridden from aura::client::VisibilityClient:
+ virtual void UpdateLayerVisibility(aura::Window* window,
+ bool visible) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(VisibilityController);
+};
+
+// Suspends the animations for visibility changes during the lifetime of an
+// instance of this class.
+//
+// Example:
+//
+// void ViewName::UnanimatedAction() {
+// SuspendChildWindowVisibilityAnimations suspend(parent);
+// // Perform unanimated action here.
+// // ...
+// // When the method finishes, visibility animations will return to their
+// // previous state.
+// }
+//
+class WM_EXPORT SuspendChildWindowVisibilityAnimations {
+ public:
+ // Suspend visibility animations of child windows.
+ explicit SuspendChildWindowVisibilityAnimations(aura::Window* window);
+
+ // Restore visibility animations to their original state.
+ ~SuspendChildWindowVisibilityAnimations();
+
+ private:
+ // The window to manage.
+ aura::Window* window_;
+
+ // Whether the visibility animations on child windows were originally enabled.
+ const bool original_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(SuspendChildWindowVisibilityAnimations);
+};
+
+// Tells |window| to animate visibility changes to its children.
+void WM_EXPORT SetChildWindowVisibilityChangesAnimated(
+ aura::Window* window);
+
+} // namespace wm
+
+#endif // UI_WM_CORE_VISIBILITY_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/visibility_controller_unittest.cc b/chromium/ui/wm/core/visibility_controller_unittest.cc
new file mode 100644
index 00000000000..5825d49530c
--- /dev/null
+++ b/chromium/ui/wm/core/visibility_controller_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/visibility_controller.h"
+
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+
+namespace wm {
+
+typedef aura::test::AuraTestBase VisibilityControllerTest;
+
+// Check that a transparency change to 0 will not cause a hide call to be
+// ignored.
+TEST_F(VisibilityControllerTest, AnimateTransparencyToZeroAndHideHides) {
+ // We cannot disable animations for this test.
+ ui::ScopedAnimationDurationScaleMode normal_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+
+ VisibilityController controller;
+ aura::client::SetVisibilityClient(root_window(), &controller);
+
+ SetChildWindowVisibilityChangesAnimated(root_window());
+
+ aura::test::TestWindowDelegate d;
+ scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
+ &d, -2, gfx::Rect(0, 0, 50, 50), root_window()));
+ ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
+ settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(5));
+
+ EXPECT_TRUE(window->layer()->visible());
+ EXPECT_TRUE(window->IsVisible());
+
+ window->layer()->SetOpacity(0.0);
+ EXPECT_TRUE(window->layer()->visible());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->layer()->GetAnimator()->
+ IsAnimatingProperty(ui::LayerAnimationElement::OPACITY));
+ EXPECT_EQ(0.0f, window->layer()->GetTargetOpacity());
+
+ // Check that the visibility is correct after the hide animation has finished.
+ window->Hide();
+ window->layer()->GetAnimator()->StopAnimating();
+ EXPECT_FALSE(window->layer()->visible());
+ EXPECT_FALSE(window->IsVisible());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/window_animations.cc b/chromium/ui/wm/core/window_animations.cc
new file mode 100644
index 00000000000..a79db3a15d6
--- /dev/null
+++ b/chromium/ui/wm/core/window_animations.cc
@@ -0,0 +1,658 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/window_animations.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_property.h"
+#include "ui/compositor/compositor_observer.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/layer_tree_owner.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/animation/animation.h"
+#include "ui/gfx/interpolated_transform.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/vector2d.h"
+#include "ui/gfx/vector3d_f.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/core/wm_core_switches.h"
+#include "ui/wm/public/animation_host.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(int)
+DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationType)
+DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationTransition)
+DECLARE_WINDOW_PROPERTY_TYPE(float)
+DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(WM_EXPORT, bool)
+
+namespace wm {
+namespace {
+const float kWindowAnimation_Vertical_TranslateY = 15.f;
+
+// A base class for hiding animation observer which has two roles:
+// 1) Notifies AnimationHost at the end of hiding animation.
+// 2) Detaches the window's layers for hiding animation and deletes
+// them upon completion of the animation. This is necessary to a)
+// ensure that the animation continues in the event of the window being
+// deleted, and b) to ensure that the animation is visible even if the
+// window gets restacked below other windows when focus or activation
+// changes.
+// The subclass will determine when the animation is completed.
+class HidingWindowAnimationObserverBase : public aura::WindowObserver {
+ public:
+ HidingWindowAnimationObserverBase(aura::Window* window) : window_(window) {
+ window_->AddObserver(this);
+ }
+ virtual ~HidingWindowAnimationObserverBase() {
+ if (window_)
+ window_->RemoveObserver(this);
+ }
+
+ // aura::WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ DCHECK_EQ(window, window_);
+ WindowInvalid();
+ }
+
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ DCHECK_EQ(window, window_);
+ WindowInvalid();
+ }
+
+ // Detach the current layers and create new layers for |window_|.
+ // Stack the original layers above |window_| and its transient
+ // children. If the window has transient children, the original
+ // layers will be moved above the top most transient child so that
+ // activation change does not put the window above the animating
+ // layer.
+ void DetachAndRecreateLayers() {
+ layer_owner_ = RecreateLayers(window_);
+ if (window_->parent()) {
+ const aura::Window::Windows& transient_children =
+ GetTransientChildren(window_);
+ aura::Window::Windows::const_iterator iter =
+ std::find(window_->parent()->children().begin(),
+ window_->parent()->children().end(),
+ window_);
+ DCHECK(iter != window_->parent()->children().end());
+ aura::Window* topmost_transient_child = NULL;
+ for (++iter; iter != window_->parent()->children().end(); ++iter) {
+ if (std::find(transient_children.begin(),
+ transient_children.end(),
+ *iter) != transient_children.end()) {
+ topmost_transient_child = *iter;
+ }
+ }
+ if (topmost_transient_child) {
+ window_->parent()->layer()->StackAbove(
+ layer_owner_->root(), topmost_transient_child->layer());
+ }
+ }
+ }
+
+ protected:
+ // Invoked when the hiding animation is completed. It will delete
+ // 'this', and no operation should be made on this object after this
+ // point.
+ void OnAnimationCompleted() {
+ // Window may have been destroyed by this point.
+ if (window_) {
+ aura::client::AnimationHost* animation_host =
+ aura::client::GetAnimationHost(window_);
+ if (animation_host)
+ animation_host->OnWindowHidingAnimationCompleted();
+ window_->RemoveObserver(this);
+ }
+ delete this;
+ }
+
+ private:
+ // Invoked when the window is destroyed (or destroying).
+ void WindowInvalid() {
+ layer_owner_->root()->SuppressPaint();
+
+ window_->RemoveObserver(this);
+ window_ = NULL;
+ }
+
+ aura::Window* window_;
+
+ // The owner of detached layers.
+ scoped_ptr<ui::LayerTreeOwner> layer_owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserverBase);
+};
+
+} // namespace
+
+DEFINE_WINDOW_PROPERTY_KEY(int,
+ kWindowVisibilityAnimationTypeKey,
+ WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
+DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0);
+DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition,
+ kWindowVisibilityAnimationTransitionKey,
+ ANIMATE_BOTH);
+DEFINE_WINDOW_PROPERTY_KEY(float,
+ kWindowVisibilityAnimationVerticalPositionKey,
+ kWindowAnimation_Vertical_TranslateY);
+
+// A HidingWindowAnimationObserver that deletes observer and detached
+// layers upon the completion of the implicit animation.
+class ImplicitHidingWindowAnimationObserver
+ : public HidingWindowAnimationObserverBase,
+ public ui::ImplicitAnimationObserver {
+ public:
+ ImplicitHidingWindowAnimationObserver(
+ aura::Window* window,
+ ui::ScopedLayerAnimationSettings* settings);
+ virtual ~ImplicitHidingWindowAnimationObserver() {}
+
+ // ui::ImplicitAnimationObserver:
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ImplicitHidingWindowAnimationObserver);
+};
+
+namespace {
+
+const int kDefaultAnimationDurationForMenuMS = 150;
+
+const float kWindowAnimation_HideOpacity = 0.f;
+const float kWindowAnimation_ShowOpacity = 1.f;
+const float kWindowAnimation_TranslateFactor = 0.5f;
+const float kWindowAnimation_ScaleFactor = .95f;
+
+const int kWindowAnimation_Rotate_DurationMS = 180;
+const int kWindowAnimation_Rotate_OpacityDurationPercent = 90;
+const float kWindowAnimation_Rotate_TranslateY = -20.f;
+const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f;
+const float kWindowAnimation_Rotate_DegreesX = 5.f;
+const float kWindowAnimation_Rotate_ScaleFactor = .99f;
+
+const float kWindowAnimation_Bounce_Scale = 1.02f;
+const int kWindowAnimation_Bounce_DurationMS = 180;
+const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40;
+
+base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window) {
+ int duration =
+ window.GetProperty(kWindowVisibilityAnimationDurationKey);
+ if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) {
+ return base::TimeDelta::FromMilliseconds(
+ kDefaultAnimationDurationForMenuMS);
+ }
+ return base::TimeDelta::FromInternalValue(duration);
+}
+
+// Gets/sets the WindowVisibilityAnimationType associated with a window.
+// TODO(beng): redundant/fold into method on public api?
+int GetWindowVisibilityAnimationType(aura::Window* window) {
+ int type = window->GetProperty(kWindowVisibilityAnimationTypeKey);
+ if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) {
+ return (window->type() == ui::wm::WINDOW_TYPE_MENU ||
+ window->type() == ui::wm::WINDOW_TYPE_TOOLTIP)
+ ? WINDOW_VISIBILITY_ANIMATION_TYPE_FADE
+ : WINDOW_VISIBILITY_ANIMATION_TYPE_DROP;
+ }
+ return type;
+}
+
+void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) {
+ const ui::Layer* root = layer;
+ while (root->parent())
+ root = root->parent();
+ layer->GetTargetTransformRelativeTo(root, transform);
+}
+
+gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer,
+ const gfx::Transform& transform) {
+ gfx::Transform in_world = transform;
+ GetTransformRelativeToRoot(layer, &in_world);
+
+ gfx::RectF transformed = layer->bounds();
+ in_world.TransformRect(&transformed);
+
+ return gfx::ToEnclosingRect(transformed);
+}
+
+// Augment the host window so that the enclosing bounds of the full
+// animation will fit inside of it.
+void AugmentWindowSize(aura::Window* window,
+ const gfx::Transform& end_transform) {
+ aura::client::AnimationHost* animation_host =
+ aura::client::GetAnimationHost(window);
+ if (!animation_host)
+ return;
+
+ const gfx::Rect& world_at_start = window->bounds();
+ gfx::Rect world_at_end =
+ GetLayerWorldBoundsAfterTransform(window->layer(), end_transform);
+ gfx::Rect union_in_window_space =
+ gfx::UnionRects(world_at_start, world_at_end);
+
+ // Calculate the top left and bottom right deltas to be added to the window
+ // bounds.
+ gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(),
+ world_at_start.y() - union_in_window_space.y());
+
+ gfx::Vector2d bottom_right_delta(
+ union_in_window_space.x() + union_in_window_space.width() -
+ (world_at_start.x() + world_at_start.width()),
+ union_in_window_space.y() + union_in_window_space.height() -
+ (world_at_start.y() + world_at_start.height()));
+
+ DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 &&
+ bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0);
+
+ animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta);
+}
+
+// Shows a window using an animation, animating its opacity from 0.f to 1.f,
+// its visibility to true, and its transform from |start_transform| to
+// |end_transform|.
+void AnimateShowWindowCommon(aura::Window* window,
+ const gfx::Transform& start_transform,
+ const gfx::Transform& end_transform) {
+ AugmentWindowSize(window, end_transform);
+
+ window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
+ window->layer()->SetTransform(start_transform);
+ window->layer()->SetVisible(true);
+
+ {
+ // Property sets within this scope will be implicitly animated.
+ ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
+ base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
+ if (duration.ToInternalValue() > 0)
+ settings.SetTransitionDuration(duration);
+
+ window->layer()->SetTransform(end_transform);
+ window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
+ }
+}
+
+// Hides a window using an animation, animating its opacity from 1.f to 0.f,
+// its visibility to false, and its transform to |end_transform|.
+void AnimateHideWindowCommon(aura::Window* window,
+ const gfx::Transform& end_transform) {
+ AugmentWindowSize(window, end_transform);
+
+ // Property sets within this scope will be implicitly animated.
+ ScopedHidingAnimationSettings hiding_settings(window);
+ base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
+ if (duration.ToInternalValue() > 0)
+ hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);
+
+ window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
+ window->layer()->SetTransform(end_transform);
+ window->layer()->SetVisible(false);
+}
+
+static gfx::Transform GetScaleForWindow(aura::Window* window) {
+ gfx::Rect bounds = window->bounds();
+ gfx::Transform scale = gfx::GetScaleTransform(
+ gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(),
+ kWindowAnimation_TranslateFactor * bounds.height()),
+ kWindowAnimation_ScaleFactor);
+ return scale;
+}
+
+// Show/Hide windows using a shrink animation.
+void AnimateShowWindow_Drop(aura::Window* window) {
+ AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform());
+}
+
+void AnimateHideWindow_Drop(aura::Window* window) {
+ AnimateHideWindowCommon(window, GetScaleForWindow(window));
+}
+
+// Show/Hide windows using a vertical Glenimation.
+void AnimateShowWindow_Vertical(aura::Window* window) {
+ gfx::Transform transform;
+ transform.Translate(0, window->GetProperty(
+ kWindowVisibilityAnimationVerticalPositionKey));
+ AnimateShowWindowCommon(window, transform, gfx::Transform());
+}
+
+void AnimateHideWindow_Vertical(aura::Window* window) {
+ gfx::Transform transform;
+ transform.Translate(0, window->GetProperty(
+ kWindowVisibilityAnimationVerticalPositionKey));
+ AnimateHideWindowCommon(window, transform);
+}
+
+// Show/Hide windows using a fade.
+void AnimateShowWindow_Fade(aura::Window* window) {
+ AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform());
+}
+
+void AnimateHideWindow_Fade(aura::Window* window) {
+ AnimateHideWindowCommon(window, gfx::Transform());
+}
+
+ui::LayerAnimationElement* CreateGrowShrinkElement(
+ aura::Window* window, bool grow) {
+ scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale(
+ gfx::Point3F(kWindowAnimation_Bounce_Scale,
+ kWindowAnimation_Bounce_Scale,
+ 1),
+ gfx::Point3F(1, 1, 1)));
+ scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
+ new ui::InterpolatedTransformAboutPivot(
+ gfx::Point(window->bounds().width() * 0.5,
+ window->bounds().height() * 0.5),
+ scale.release()));
+ scale_about_pivot->SetReversed(grow);
+ scoped_ptr<ui::LayerAnimationElement> transition(
+ ui::LayerAnimationElement::CreateInterpolatedTransformElement(
+ scale_about_pivot.release(),
+ base::TimeDelta::FromMilliseconds(
+ kWindowAnimation_Bounce_DurationMS *
+ kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100)));
+ transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
+ return transition.release();
+}
+
+void AnimateBounce(aura::Window* window) {
+ ui::ScopedLayerAnimationSettings scoped_settings(
+ window->layer()->GetAnimator());
+ scoped_settings.SetPreemptionStrategy(
+ ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+ scoped_ptr<ui::LayerAnimationSequence> sequence(
+ new ui::LayerAnimationSequence);
+ sequence->AddElement(CreateGrowShrinkElement(window, true));
+ sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
+ ui::LayerAnimationElement::BOUNDS,
+ base::TimeDelta::FromMilliseconds(
+ kWindowAnimation_Bounce_DurationMS *
+ (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) /
+ 100)));
+ sequence->AddElement(CreateGrowShrinkElement(window, false));
+ window->layer()->GetAnimator()->StartAnimation(sequence.release());
+}
+
+// A HidingWindowAnimationObserver that deletes observer and detached
+// layers when the last_sequence has been completed or aborted.
+class RotateHidingWindowAnimationObserver
+ : public HidingWindowAnimationObserverBase,
+ public ui::LayerAnimationObserver {
+ public:
+ RotateHidingWindowAnimationObserver(aura::Window* window)
+ : HidingWindowAnimationObserverBase(window), last_sequence_(NULL) {}
+ virtual ~RotateHidingWindowAnimationObserver() {}
+
+ void set_last_sequence(ui::LayerAnimationSequence* last_sequence) {
+ last_sequence_ = last_sequence;
+ }
+
+ // ui::LayerAnimationObserver:
+ virtual void OnLayerAnimationEnded(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {
+ if (last_sequence_ == sequence)
+ OnAnimationCompleted();
+ }
+ virtual void OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {
+ if (last_sequence_ == sequence)
+ OnAnimationCompleted();
+ }
+ virtual void OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) OVERRIDE {}
+
+ private:
+ ui::LayerAnimationSequence* last_sequence_;
+
+ DISALLOW_COPY_AND_ASSIGN(RotateHidingWindowAnimationObserver);
+};
+
+void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
+ if (show)
+ window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
+
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
+ kWindowAnimation_Rotate_DurationMS);
+
+ RotateHidingWindowAnimationObserver* observer = NULL;
+
+ if (!show) {
+ observer = new RotateHidingWindowAnimationObserver(window);
+ window->layer()->GetAnimator()->SchedulePauseForProperties(
+ duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100,
+ ui::LayerAnimationElement::OPACITY);
+ }
+ scoped_ptr<ui::LayerAnimationElement> opacity(
+ ui::LayerAnimationElement::CreateOpacityElement(
+ show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity,
+ duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100));
+ opacity->set_tween_type(gfx::Tween::EASE_IN_OUT);
+ window->layer()->GetAnimator()->ScheduleAnimation(
+ new ui::LayerAnimationSequence(opacity.release()));
+
+ float xcenter = window->bounds().width() * 0.5;
+
+ gfx::Transform transform;
+ transform.Translate(xcenter, 0);
+ transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth);
+ transform.Translate(-xcenter, 0);
+ scoped_ptr<ui::InterpolatedTransform> perspective(
+ new ui::InterpolatedConstantTransform(transform));
+
+ scoped_ptr<ui::InterpolatedTransform> scale(
+ new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor));
+ scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
+ new ui::InterpolatedTransformAboutPivot(
+ gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY),
+ scale.release()));
+
+ scoped_ptr<ui::InterpolatedTransform> translation(
+ new ui::InterpolatedTranslation(gfx::Point(), gfx::Point(
+ 0, kWindowAnimation_Rotate_TranslateY)));
+
+ scoped_ptr<ui::InterpolatedTransform> rotation(
+ new ui::InterpolatedAxisAngleRotation(
+ gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX));
+
+ scale_about_pivot->SetChild(perspective.release());
+ translation->SetChild(scale_about_pivot.release());
+ rotation->SetChild(translation.release());
+ rotation->SetReversed(show);
+
+ scoped_ptr<ui::LayerAnimationElement> transition(
+ ui::LayerAnimationElement::CreateInterpolatedTransformElement(
+ rotation.release(), duration));
+ ui::LayerAnimationSequence* last_sequence =
+ new ui::LayerAnimationSequence(transition.release());
+ window->layer()->GetAnimator()->ScheduleAnimation(last_sequence);
+ if (observer) {
+ observer->set_last_sequence(last_sequence);
+ observer->DetachAndRecreateLayers();
+ }
+}
+
+void AnimateShowWindow_Rotate(aura::Window* window) {
+ AddLayerAnimationsForRotate(window, true);
+}
+
+void AnimateHideWindow_Rotate(aura::Window* window) {
+ AddLayerAnimationsForRotate(window, false);
+}
+
+bool AnimateShowWindow(aura::Window* window) {
+ if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
+ if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
+ // Since hide animation may have changed opacity and transform,
+ // reset them to show the window.
+ window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
+ window->layer()->SetTransform(gfx::Transform());
+ }
+ return false;
+ }
+
+ switch (GetWindowVisibilityAnimationType(window)) {
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
+ AnimateShowWindow_Drop(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
+ AnimateShowWindow_Vertical(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
+ AnimateShowWindow_Fade(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
+ AnimateShowWindow_Rotate(window);
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AnimateHideWindow(aura::Window* window) {
+ if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
+ if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
+ // Since show animation may have changed opacity and transform,
+ // reset them, though the change should be hidden.
+ window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
+ window->layer()->SetTransform(gfx::Transform());
+ }
+ return false;
+ }
+
+ switch (GetWindowVisibilityAnimationType(window)) {
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
+ AnimateHideWindow_Drop(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
+ AnimateHideWindow_Vertical(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
+ AnimateHideWindow_Fade(window);
+ return true;
+ case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
+ AnimateHideWindow_Rotate(window);
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ImplicitHidingWindowAnimationObserver
+
+ImplicitHidingWindowAnimationObserver::ImplicitHidingWindowAnimationObserver(
+ aura::Window* window,
+ ui::ScopedLayerAnimationSettings* settings)
+ : HidingWindowAnimationObserverBase(window) {
+ settings->AddObserver(this);
+}
+
+void ImplicitHidingWindowAnimationObserver::OnImplicitAnimationsCompleted() {
+ OnAnimationCompleted();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScopedHidingAnimationSettings
+
+ScopedHidingAnimationSettings::ScopedHidingAnimationSettings(
+ aura::Window* window)
+ : layer_animation_settings_(window->layer()->GetAnimator()),
+ observer_(new ImplicitHidingWindowAnimationObserver(
+ window,
+ &layer_animation_settings_)) {
+}
+
+ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() {
+ observer_->DetachAndRecreateLayers();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// External interface
+
+void SetWindowVisibilityAnimationType(aura::Window* window, int type) {
+ window->SetProperty(kWindowVisibilityAnimationTypeKey, type);
+}
+
+int GetWindowVisibilityAnimationType(aura::Window* window) {
+ return window->GetProperty(kWindowVisibilityAnimationTypeKey);
+}
+
+void SetWindowVisibilityAnimationTransition(
+ aura::Window* window,
+ WindowVisibilityAnimationTransition transition) {
+ window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition);
+}
+
+bool HasWindowVisibilityAnimationTransition(
+ aura::Window* window,
+ WindowVisibilityAnimationTransition transition) {
+ WindowVisibilityAnimationTransition prop = window->GetProperty(
+ kWindowVisibilityAnimationTransitionKey);
+ return (prop & transition) != 0;
+}
+
+void SetWindowVisibilityAnimationDuration(aura::Window* window,
+ const base::TimeDelta& duration) {
+ window->SetProperty(kWindowVisibilityAnimationDurationKey,
+ static_cast<int>(duration.ToInternalValue()));
+}
+
+base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window) {
+ return base::TimeDelta::FromInternalValue(
+ window.GetProperty(kWindowVisibilityAnimationDurationKey));
+}
+
+void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window,
+ float position) {
+ window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position);
+}
+
+bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
+ if (WindowAnimationsDisabled(window))
+ return false;
+ if (visible)
+ return AnimateShowWindow(window);
+ // Don't start hiding the window again if it's already being hidden.
+ return window->layer()->GetTargetOpacity() != 0.0f &&
+ AnimateHideWindow(window);
+}
+
+bool AnimateWindow(aura::Window* window, WindowAnimationType type) {
+ switch (type) {
+ case WINDOW_ANIMATION_TYPE_BOUNCE:
+ AnimateBounce(window);
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool WindowAnimationsDisabled(aura::Window* window) {
+ return (!gfx::Animation::ShouldRenderRichAnimation() || (window &&
+ window->GetProperty(aura::client::kAnimationsDisabledKey)) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kWindowAnimationsDisabled));
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/window_animations.h b/chromium/ui/wm/core/window_animations.h
new file mode 100644
index 00000000000..422167e35d7
--- /dev/null
+++ b/chromium/ui/wm/core/window_animations.h
@@ -0,0 +1,117 @@
+// 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_WM_CORE_WINDOW_ANIMATIONS_H_
+#define UI_WM_CORE_WINDOW_ANIMATIONS_H_
+
+#include <vector>
+
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+}
+namespace base {
+class TimeDelta;
+}
+namespace gfx {
+class Rect;
+}
+namespace ui {
+class ImplicitAnimationObserver;
+class Layer;
+class LayerAnimationSequence;
+}
+
+namespace wm {
+
+// A variety of canned animations for window transitions.
+enum WindowVisibilityAnimationType {
+ WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT = 0, // Default. Lets the system
+ // decide based on window
+ // type.
+ WINDOW_VISIBILITY_ANIMATION_TYPE_DROP, // Window shrinks in.
+ WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL, // Vertical Glenimation.
+ WINDOW_VISIBILITY_ANIMATION_TYPE_FADE, // Fades in/out.
+ WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE, // Window rotates in.
+
+ // Downstream library animations start above this point.
+ WINDOW_VISIBILITY_ANIMATION_MAX
+};
+
+// Canned animations that take effect once but don't have a symmetric pair as
+// visibility animations do.
+enum WindowAnimationType {
+ WINDOW_ANIMATION_TYPE_BOUNCE = 0, // Window scales up and down.
+};
+
+// Type of visibility change transition that a window should animate.
+// Default behavior is to animate both show and hide.
+enum WindowVisibilityAnimationTransition {
+ ANIMATE_SHOW = 0x1,
+ ANIMATE_HIDE = 0x2,
+ ANIMATE_BOTH = ANIMATE_SHOW | ANIMATE_HIDE,
+ ANIMATE_NONE = 0x4,
+};
+
+// These two methods use int for type rather than WindowVisibilityAnimationType
+// since downstream libraries can extend the set of animations.
+WM_EXPORT void SetWindowVisibilityAnimationType(aura::Window* window, int type);
+WM_EXPORT int GetWindowVisibilityAnimationType(aura::Window* window);
+
+WM_EXPORT void SetWindowVisibilityAnimationTransition(
+ aura::Window* window,
+ WindowVisibilityAnimationTransition transition);
+
+WM_EXPORT bool HasWindowVisibilityAnimationTransition(
+ aura::Window* window,
+ WindowVisibilityAnimationTransition transition);
+
+WM_EXPORT void SetWindowVisibilityAnimationDuration(
+ aura::Window* window,
+ const base::TimeDelta& duration);
+
+WM_EXPORT base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window);
+
+WM_EXPORT void SetWindowVisibilityAnimationVerticalPosition(
+ aura::Window* window,
+ float position);
+
+class ImplicitHidingWindowAnimationObserver;
+// A wrapper of ui::ScopedLayerAnimationSettings for implicit hiding animations.
+// Use this to ensure that the hiding animation is visible even after
+// the window is deleted or deactivated, instead of using
+// ui::ScopedLayerAnimationSettings directly.
+class WM_EXPORT ScopedHidingAnimationSettings {
+ public:
+ explicit ScopedHidingAnimationSettings(aura::Window* window);
+ ~ScopedHidingAnimationSettings();
+
+ // Returns the wrapped ScopedLayeAnimationSettings instance.
+ ui::ScopedLayerAnimationSettings* layer_animation_settings() {
+ return &layer_animation_settings_;
+ }
+
+ private:
+ ui::ScopedLayerAnimationSettings layer_animation_settings_;
+ ImplicitHidingWindowAnimationObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedHidingAnimationSettings);
+};
+
+// Returns false if the |window| didn't animate.
+WM_EXPORT bool AnimateOnChildWindowVisibilityChanged(aura::Window* window,
+ bool visible);
+WM_EXPORT bool AnimateWindow(aura::Window* window, WindowAnimationType type);
+
+// Returns true if window animations are disabled for |window|. Window
+// animations are enabled by default. If |window| is NULL, this just checks
+// if the global flag disabling window animations is present.
+WM_EXPORT bool WindowAnimationsDisabled(aura::Window* window);
+
+} // namespace wm
+
+#endif // UI_WM_CORE_WINDOW_ANIMATIONS_H_
diff --git a/chromium/ui/wm/core/window_animations_unittest.cc b/chromium/ui/wm/core/window_animations_unittest.cc
new file mode 100644
index 00000000000..5968bf32440
--- /dev/null
+++ b/chromium/ui/wm/core/window_animations_unittest.cc
@@ -0,0 +1,291 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/window_animations.h"
+
+#include "base/time/time.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/gfx/animation/animation_container_element.h"
+#include "ui/gfx/vector2d.h"
+#include "ui/wm/core/transient_window_manager.h"
+#include "ui/wm/core/transient_window_stacking_client.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/animation_host.h"
+
+using aura::Window;
+using ui::Layer;
+
+namespace wm {
+namespace {
+
+template<typename T>int GetZPosition(const T* child) {
+ const T* parent = child->parent();
+ const std::vector<T*> children = parent->children();
+ typename std::vector<T*>::const_iterator iter =
+ std::find(children.begin(), children.end(), child);
+ DCHECK(iter != children.end());
+ return iter - children.begin();
+}
+
+int GetWindowZPosition(const aura::Window* child) {
+ return GetZPosition<aura::Window>(child);
+}
+
+int GetLayerZPosition(const ui::Layer* child) {
+ return GetZPosition<ui::Layer>(child);
+}
+
+} // namespace
+
+class WindowAnimationsTest : public aura::test::AuraTestBase {
+ public:
+ WindowAnimationsTest() {}
+
+ virtual void TearDown() OVERRIDE {
+ AuraTestBase::TearDown();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
+};
+
+TEST_F(WindowAnimationsTest, LayerTargetVisibility) {
+ scoped_ptr<aura::Window> window(
+ aura::test::CreateTestWindowWithId(0, NULL));
+
+ // Layer target visibility changes according to Show/Hide.
+ window->Show();
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+ window->Hide();
+ EXPECT_FALSE(window->layer()->GetTargetVisibility());
+ window->Show();
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+}
+
+TEST_F(WindowAnimationsTest, LayerTargetVisibility_AnimateShow) {
+ // Tests if opacity and transform are reset when only show animation is
+ // enabled. See also LayerTargetVisibility_AnimateHide.
+ // Since the window is not visible after Hide() is called, opacity and
+ // transform shouldn't matter in case of ANIMATE_SHOW, but we reset them
+ // to keep consistency.
+
+ scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
+ SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_SHOW);
+
+ // Layer target visibility and opacity change according to Show/Hide.
+ window->Show();
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(1, window->layer()->opacity());
+
+ window->Hide();
+ AnimateOnChildWindowVisibilityChanged(window.get(), false);
+ EXPECT_FALSE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(0, window->layer()->opacity());
+ EXPECT_EQ(gfx::Transform(), window->layer()->transform());
+
+ window->Show();
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(1, window->layer()->opacity());
+}
+
+TEST_F(WindowAnimationsTest, LayerTargetVisibility_AnimateHide) {
+ // Tests if opacity and transform are reset when only hide animation is
+ // enabled. Hide animation changes opacity and transform in addition to
+ // visibility, so we need to reset not only visibility but also opacity
+ // and transform to show the window.
+
+ scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
+ SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_HIDE);
+
+ // Layer target visibility and opacity change according to Show/Hide.
+ window->Show();
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(1, window->layer()->opacity());
+ EXPECT_EQ(gfx::Transform(), window->layer()->transform());
+
+ window->Hide();
+ AnimateOnChildWindowVisibilityChanged(window.get(), false);
+ EXPECT_FALSE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(0, window->layer()->opacity());
+
+ window->Show();
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ EXPECT_TRUE(window->layer()->GetTargetVisibility());
+ EXPECT_EQ(1, window->layer()->opacity());
+ EXPECT_EQ(gfx::Transform(), window->layer()->transform());
+}
+
+TEST_F(WindowAnimationsTest, HideAnimationDetachLayers) {
+ scoped_ptr<aura::Window> parent(aura::test::CreateTestWindowWithId(0, NULL));
+
+ scoped_ptr<aura::Window> other(
+ aura::test::CreateTestWindowWithId(1, parent.get()));
+
+ scoped_ptr<aura::Window> animating_window(
+ aura::test::CreateTestWindowWithId(2, parent.get()));
+ SetWindowVisibilityAnimationTransition(animating_window.get(), ANIMATE_HIDE);
+
+ EXPECT_EQ(0, GetWindowZPosition(other.get()));
+ EXPECT_EQ(1, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(0, GetLayerZPosition(other->layer()));
+ EXPECT_EQ(1, GetLayerZPosition(animating_window->layer()));
+
+ {
+ ui::ScopedAnimationDurationScaleMode scale_mode(
+ ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
+ ui::Layer* animating_layer = animating_window->layer();
+
+ animating_window->Hide();
+ EXPECT_TRUE(AnimateOnChildWindowVisibilityChanged(
+ animating_window.get(), false));
+ EXPECT_TRUE(animating_layer->GetAnimator()->is_animating());
+ EXPECT_FALSE(animating_layer->delegate());
+
+ // Make sure the Hide animation create another layer, and both are in
+ // the parent layer.
+ EXPECT_NE(animating_window->layer(), animating_layer);
+ EXPECT_TRUE(
+ std::find(parent->layer()->children().begin(),
+ parent->layer()->children().end(),
+ animating_layer) !=
+ parent->layer()->children().end());
+ EXPECT_TRUE(
+ std::find(parent->layer()->children().begin(),
+ parent->layer()->children().end(),
+ animating_window->layer()) !=
+ parent->layer()->children().end());
+ // Current layer must be already hidden.
+ EXPECT_FALSE(animating_window->layer()->visible());
+
+ EXPECT_EQ(1, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(1, GetLayerZPosition(animating_window->layer()));
+ EXPECT_EQ(2, GetLayerZPosition(animating_layer));
+
+ parent->StackChildAtTop(other.get());
+ EXPECT_EQ(0, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(1, GetWindowZPosition(other.get()));
+
+ EXPECT_EQ(0, GetLayerZPosition(animating_window->layer()));
+ EXPECT_EQ(1, GetLayerZPosition(other->layer()));
+ // Make sure the animating layer is on top.
+ EXPECT_EQ(2, GetLayerZPosition(animating_layer));
+
+ // Animating layer must be gone
+ animating_layer->GetAnimator()->StopAnimating();
+ EXPECT_TRUE(
+ std::find(parent->layer()->children().begin(),
+ parent->layer()->children().end(),
+ animating_layer) ==
+ parent->layer()->children().end());
+ }
+}
+
+TEST_F(WindowAnimationsTest, HideAnimationDetachLayersWithTransientChildren) {
+ TransientWindowStackingClient transient_stacking_client;
+
+ scoped_ptr<aura::Window> parent(aura::test::CreateTestWindowWithId(0, NULL));
+
+ scoped_ptr<aura::Window> other(
+ aura::test::CreateTestWindowWithId(1, parent.get()));
+
+ scoped_ptr<aura::Window> animating_window(
+ aura::test::CreateTestWindowWithId(2, parent.get()));
+ SetWindowVisibilityAnimationTransition(animating_window.get(), ANIMATE_HIDE);
+
+ scoped_ptr<aura::Window> transient1(
+ aura::test::CreateTestWindowWithId(3, parent.get()));
+ scoped_ptr<aura::Window> transient2(
+ aura::test::CreateTestWindowWithId(4, parent.get()));
+
+ TransientWindowManager::Get(animating_window.get());
+ AddTransientChild(animating_window.get(), transient1.get());
+ AddTransientChild(animating_window.get(), transient2.get());
+
+ EXPECT_EQ(0, GetWindowZPosition(other.get()));
+ EXPECT_EQ(1, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(2, GetWindowZPosition(transient1.get()));
+ EXPECT_EQ(3, GetWindowZPosition(transient2.get()));
+
+ {
+ ui::ScopedAnimationDurationScaleMode scale_mode(
+ ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
+ ui::Layer* animating_layer = animating_window->layer();
+
+ animating_window->Hide();
+ EXPECT_TRUE(AnimateOnChildWindowVisibilityChanged(
+ animating_window.get(), false));
+ EXPECT_TRUE(animating_layer->GetAnimator()->is_animating());
+ EXPECT_FALSE(animating_layer->delegate());
+
+ EXPECT_EQ(1, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(2, GetWindowZPosition(transient1.get()));
+ EXPECT_EQ(3, GetWindowZPosition(transient2.get()));
+
+ EXPECT_EQ(1, GetLayerZPosition(animating_window->layer()));
+ EXPECT_EQ(2, GetLayerZPosition(transient1->layer()));
+ EXPECT_EQ(3, GetLayerZPosition(transient2->layer()));
+ EXPECT_EQ(4, GetLayerZPosition(animating_layer));
+
+ parent->StackChildAtTop(other.get());
+
+ EXPECT_EQ(0, GetWindowZPosition(animating_window.get()));
+ EXPECT_EQ(1, GetWindowZPosition(transient1.get()));
+ EXPECT_EQ(2, GetWindowZPosition(transient2.get()));
+ EXPECT_EQ(3, GetWindowZPosition(other.get()));
+
+ EXPECT_EQ(0, GetLayerZPosition(animating_window->layer()));
+ EXPECT_EQ(1, GetLayerZPosition(transient1->layer()));
+ EXPECT_EQ(2, GetLayerZPosition(transient2->layer()));
+ EXPECT_EQ(3, GetLayerZPosition(other->layer()));
+ // Make sure the animating layer is on top of all windows.
+ EXPECT_EQ(4, GetLayerZPosition(animating_layer));
+ }
+}
+
+// A simple AnimationHost implementation for the NotifyHideCompleted test.
+class NotifyHideCompletedAnimationHost : public aura::client::AnimationHost {
+ public:
+ NotifyHideCompletedAnimationHost() : hide_completed_(false) {}
+ virtual ~NotifyHideCompletedAnimationHost() {}
+
+ // Overridden from TestWindowDelegate:
+ virtual void OnWindowHidingAnimationCompleted() OVERRIDE {
+ hide_completed_ = true;
+ }
+
+ virtual void SetHostTransitionOffsets(
+ const gfx::Vector2d& top_left,
+ const gfx::Vector2d& bottom_right) OVERRIDE {}
+
+ bool hide_completed() const { return hide_completed_; }
+
+ private:
+ bool hide_completed_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotifyHideCompletedAnimationHost);
+};
+
+TEST_F(WindowAnimationsTest, NotifyHideCompleted) {
+ NotifyHideCompletedAnimationHost animation_host;
+ scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL));
+ aura::client::SetAnimationHost(window.get(), &animation_host);
+ wm::SetWindowVisibilityAnimationType(
+ window.get(), WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+ AnimateOnChildWindowVisibilityChanged(window.get(), true);
+ EXPECT_TRUE(window->layer()->visible());
+
+ EXPECT_FALSE(animation_host.hide_completed());
+ AnimateOnChildWindowVisibilityChanged(window.get(), false);
+ EXPECT_TRUE(animation_host.hide_completed());
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/window_modality_controller.cc b/chromium/ui/wm/core/window_modality_controller.cc
new file mode 100644
index 00000000000..1df375b439a
--- /dev/null
+++ b/chromium/ui/wm/core/window_modality_controller.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/window_modality_controller.h"
+
+#include <algorithm>
+
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_property.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/events/event.h"
+#include "ui/events/event_target.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/wm/core/window_animations.h"
+#include "ui/wm/core/window_util.h"
+
+namespace wm {
+
+// Transient child's modal parent.
+extern const aura::WindowProperty<aura::Window*>* const kModalParentKey;
+DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kModalParentKey, NULL);
+
+namespace {
+
+bool HasAncestor(aura::Window* window, aura::Window* ancestor) {
+ if (!window)
+ return false;
+ if (window == ancestor)
+ return true;
+ return HasAncestor(window->parent(), ancestor);
+}
+
+bool TransientChildIsWindowModal(aura::Window* window) {
+ return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW;
+}
+
+bool TransientChildIsSystemModal(aura::Window* window) {
+ return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
+}
+
+bool TransientChildIsChildModal(aura::Window* window) {
+ return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_CHILD;
+}
+
+aura::Window* GetModalParent(aura::Window* window) {
+ return window->GetProperty(kModalParentKey);
+}
+
+bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
+ return transient->IsVisible() &&
+ (TransientChildIsWindowModal(transient) ||
+ TransientChildIsSystemModal(transient) ||
+ (TransientChildIsChildModal(transient) &&
+ (HasAncestor(original, GetModalParent(transient)))));
+}
+
+aura::Window* GetModalTransientChild(
+ aura::Window* activatable,
+ aura::Window* original) {
+ for (aura::Window::Windows::const_iterator it =
+ GetTransientChildren(activatable).begin();
+ it != GetTransientChildren(activatable).end();
+ ++it) {
+ aura::Window* transient = *it;
+ if (IsModalTransientChild(transient, original)) {
+ return GetTransientChildren(transient).empty() ?
+ transient : GetModalTransientChild(transient, original);
+ }
+ }
+ return NULL;
+}
+
+} // namespace
+
+void SetModalParent(aura::Window* child, aura::Window* parent) {
+ child->SetProperty(kModalParentKey, parent);
+}
+
+aura::Window* GetModalTransient(aura::Window* window) {
+ if (!window)
+ return NULL;
+
+ // We always want to check the for the transient child of the toplevel window.
+ aura::Window* toplevel = GetToplevelWindow(window);
+ if (!toplevel)
+ return NULL;
+
+ return GetModalTransientChild(toplevel, window);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowModalityController, public:
+
+WindowModalityController::WindowModalityController(
+ ui::EventTarget* event_target)
+ : event_target_(event_target) {
+ aura::Env::GetInstance()->AddObserver(this);
+ DCHECK(event_target->IsPreTargetListEmpty());
+ event_target_->AddPreTargetHandler(this);
+}
+
+WindowModalityController::~WindowModalityController() {
+ event_target_->RemovePreTargetHandler(this);
+ aura::Env::GetInstance()->RemoveObserver(this);
+ for (size_t i = 0; i < windows_.size(); ++i)
+ windows_[i]->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowModalityController, aura::EventFilter implementation:
+
+void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ if (GetModalTransient(target))
+ event->SetHandled();
+}
+
+void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ if (ProcessLocatedEvent(target, event))
+ event->SetHandled();
+}
+
+void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ if (ProcessLocatedEvent(target, event))
+ event->SetHandled();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowModalityController, aura::EnvObserver implementation:
+
+void WindowModalityController::OnWindowInitialized(aura::Window* window) {
+ windows_.push_back(window);
+ window->AddObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowModalityController, aura::WindowObserver implementation:
+
+void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) {
+ // In tests, we sometimes create the modality relationship after a window is
+ // visible.
+ if (key == aura::client::kModalKey &&
+ window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
+ window->IsVisible()) {
+ ActivateWindow(window);
+ ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window),
+ NULL);
+ }
+}
+
+void WindowModalityController::OnWindowVisibilityChanged(
+ aura::Window* window,
+ bool visible) {
+ if (visible && window->GetProperty(aura::client::kModalKey) !=
+ ui::MODAL_TYPE_NONE) {
+ ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window),
+ NULL);
+ // Make sure no other window has capture, otherwise |window| won't get mouse
+ // events.
+ aura::Window* capture_window = aura::client::GetCaptureWindow(window);
+ if (capture_window)
+ capture_window->ReleaseCapture();
+ }
+}
+
+void WindowModalityController::OnWindowDestroyed(aura::Window* window) {
+ windows_.erase(std::find(windows_.begin(), windows_.end(), window));
+ window->RemoveObserver(this);
+}
+
+bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
+ ui::LocatedEvent* event) {
+ if (event->handled())
+ return false;
+ aura::Window* modal_transient_child = GetModalTransient(target);
+ if (modal_transient_child && (event->type() == ui::ET_MOUSE_PRESSED ||
+ event->type() == ui::ET_TOUCH_PRESSED)) {
+ // Activate top window if transient child window is window modal.
+ if (TransientChildIsWindowModal(modal_transient_child)) {
+ aura::Window* toplevel = GetToplevelWindow(target);
+ DCHECK(toplevel);
+ ActivateWindow(toplevel);
+ }
+
+ AnimateWindow(modal_transient_child, WINDOW_ANIMATION_TYPE_BOUNCE);
+ }
+ if (event->type() == ui::ET_TOUCH_CANCELLED)
+ return false;
+ return !!modal_transient_child;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/window_modality_controller.h b/chromium/ui/wm/core/window_modality_controller.h
new file mode 100644
index 00000000000..4d52c2190ba
--- /dev/null
+++ b/chromium/ui/wm/core/window_modality_controller.h
@@ -0,0 +1,71 @@
+// 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_WM_CORE_WINDOW_MODALITY_CONTROLLER_H_
+#define UI_WM_CORE_WINDOW_MODALITY_CONTROLLER_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/wm_export.h"
+
+namespace ui {
+class EventTarget;
+class LocatedEvent;
+}
+
+namespace wm {
+
+// Sets the modal parent for the child.
+WM_EXPORT void SetModalParent(aura::Window* child, aura::Window* parent);
+
+// Returns the modal transient child of |window|, or NULL if |window| does not
+// have any modal transient children.
+WM_EXPORT aura::Window* GetModalTransient(aura::Window* window);
+
+// WindowModalityController is an event filter that consumes events sent to
+// windows that are the transient parents of window-modal windows. This filter
+// must be added to the CompoundEventFilter so that activation works properly.
+class WM_EXPORT WindowModalityController : public ui::EventHandler,
+ public aura::EnvObserver,
+ public aura::WindowObserver {
+ public:
+ explicit WindowModalityController(ui::EventTarget* event_target);
+ virtual ~WindowModalityController();
+
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+
+ // Overridden from aura::EnvObserver:
+ virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
+
+ // Overridden from aura::WindowObserver:
+ virtual void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) OVERRIDE;
+ virtual void OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+ // Processes a mouse/touch event, and returns true if the event should be
+ // consumed.
+ bool ProcessLocatedEvent(aura::Window* target,
+ ui::LocatedEvent* event);
+
+ std::vector<aura::Window*> windows_;
+
+ ui::EventTarget* event_target_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowModalityController);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_WINDOW_MODALITY_CONTROLLER_H_
diff --git a/chromium/ui/wm/core/window_util.cc b/chromium/ui/wm/core/window_util.cc
new file mode 100644
index 00000000000..6d8cdc97ba0
--- /dev/null
+++ b/chromium/ui/wm/core/window_util.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/window_util.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_tree_owner.h"
+#include "ui/wm/core/transient_window_manager.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace {
+
+// Invokes RecreateLayer() on all the children of |to_clone|, adding the newly
+// cloned children to |parent|.
+//
+// WARNING: It is assumed that |parent| is ultimately owned by a LayerTreeOwner.
+void CloneChildren(ui::Layer* to_clone, ui::Layer* parent) {
+ typedef std::vector<ui::Layer*> Layers;
+ // Make a copy of the children since RecreateLayer() mutates it.
+ Layers children(to_clone->children());
+ for (Layers::const_iterator i = children.begin(); i != children.end(); ++i) {
+ ui::LayerOwner* owner = (*i)->owner();
+ ui::Layer* old_layer = owner ? owner->RecreateLayer().release() : NULL;
+ if (old_layer) {
+ parent->Add(old_layer);
+ // RecreateLayer() moves the existing children to the new layer. Create a
+ // copy of those.
+ CloneChildren(owner->layer(), old_layer);
+ }
+ }
+}
+
+} // namespace
+
+namespace wm {
+
+void ActivateWindow(aura::Window* window) {
+ DCHECK(window);
+ DCHECK(window->GetRootWindow());
+ aura::client::GetActivationClient(window->GetRootWindow())->ActivateWindow(
+ window);
+}
+
+void DeactivateWindow(aura::Window* window) {
+ DCHECK(window);
+ DCHECK(window->GetRootWindow());
+ aura::client::GetActivationClient(window->GetRootWindow())->DeactivateWindow(
+ window);
+}
+
+bool IsActiveWindow(aura::Window* window) {
+ DCHECK(window);
+ if (!window->GetRootWindow())
+ return false;
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(window->GetRootWindow());
+ return client && client->GetActiveWindow() == window;
+}
+
+bool CanActivateWindow(aura::Window* window) {
+ DCHECK(window);
+ if (!window->GetRootWindow())
+ return false;
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(window->GetRootWindow());
+ return client && client->CanActivateWindow(window);
+}
+
+aura::Window* GetActivatableWindow(aura::Window* window) {
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(window->GetRootWindow());
+ return client ? client->GetActivatableWindow(window) : NULL;
+}
+
+aura::Window* GetToplevelWindow(aura::Window* window) {
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(window->GetRootWindow());
+ return client ? client->GetToplevelWindow(window) : NULL;
+}
+
+scoped_ptr<ui::LayerTreeOwner> RecreateLayers(ui::LayerOwner* root) {
+ scoped_ptr<ui::LayerTreeOwner> old_layer(
+ new ui::LayerTreeOwner(root->RecreateLayer().release()));
+ if (old_layer->root())
+ CloneChildren(root->layer(), old_layer->root());
+ return old_layer.Pass();
+}
+
+aura::Window* GetTransientParent(aura::Window* window) {
+ return const_cast<aura::Window*>(GetTransientParent(
+ const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* GetTransientParent(const aura::Window* window) {
+ const TransientWindowManager* manager = TransientWindowManager::Get(window);
+ return manager ? manager->transient_parent() : NULL;
+}
+
+const std::vector<aura::Window*>& GetTransientChildren(
+ const aura::Window* window) {
+ const TransientWindowManager* manager = TransientWindowManager::Get(window);
+ if (manager)
+ return manager->transient_children();
+
+ static std::vector<aura::Window*>* shared = new std::vector<aura::Window*>;
+ return *shared;
+}
+
+void AddTransientChild(aura::Window* parent, aura::Window* child) {
+ TransientWindowManager::Get(parent)->AddTransientChild(child);
+}
+
+void RemoveTransientChild(aura::Window* parent, aura::Window* child) {
+ TransientWindowManager::Get(parent)->RemoveTransientChild(child);
+}
+
+bool HasTransientAncestor(const aura::Window* window,
+ const aura::Window* ancestor) {
+ const aura::Window* transient_parent = GetTransientParent(window);
+ if (transient_parent == ancestor)
+ return true;
+ return transient_parent ?
+ HasTransientAncestor(transient_parent, ancestor) : false;
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/window_util.h b/chromium/ui/wm/core/window_util.h
new file mode 100644
index 00000000000..78f2ffbf112
--- /dev/null
+++ b/chromium/ui/wm/core/window_util.h
@@ -0,0 +1,67 @@
+// 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_WM_CORE_WINDOW_UTIL_H_
+#define UI_WM_CORE_WINDOW_UTIL_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/wm/wm_export.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class Layer;
+class LayerOwner;
+class LayerTreeOwner;
+}
+
+namespace wm {
+
+WM_EXPORT void ActivateWindow(aura::Window* window);
+WM_EXPORT void DeactivateWindow(aura::Window* window);
+WM_EXPORT bool IsActiveWindow(aura::Window* window);
+WM_EXPORT bool CanActivateWindow(aura::Window* window);
+
+// Retrieves the activatable window for |window|. The ActivationClient makes
+// this determination.
+WM_EXPORT aura::Window* GetActivatableWindow(aura::Window* window);
+
+// Retrieves the toplevel window for |window|. The ActivationClient makes this
+// determination.
+WM_EXPORT aura::Window* GetToplevelWindow(aura::Window* window);
+
+// Returns the existing Layer for |root| (and all its descendants) and creates
+// a new layer for |root| and all its descendants. This is intended for
+// animations that want to animate between the existing visuals and a new state.
+//
+// As a result of this |root| has freshly created layers, meaning the layers
+// have not yet been painted to.
+WM_EXPORT scoped_ptr<ui::LayerTreeOwner> RecreateLayers(
+ ui::LayerOwner* root);
+
+// Convenience functions that get the TransientWindowManager for the window and
+// redirect appropriately. These are preferable to calling functions on
+// TransientWindowManager as they handle the appropriate NULL checks.
+WM_EXPORT aura::Window* GetTransientParent(aura::Window* window);
+WM_EXPORT const aura::Window* GetTransientParent(
+ const aura::Window* window);
+WM_EXPORT const std::vector<aura::Window*>& GetTransientChildren(
+ const aura::Window* window);
+WM_EXPORT void AddTransientChild(aura::Window* parent, aura::Window* child);
+WM_EXPORT void RemoveTransientChild(aura::Window* parent, aura::Window* child);
+
+// Returns true if |window| has |ancestor| as a transient ancestor. A transient
+// ancestor is found by following the transient parent chain of the window.
+WM_EXPORT bool HasTransientAncestor(const aura::Window* window,
+ const aura::Window* ancestor);
+
+} // namespace wm
+
+#endif // UI_WM_CORE_WINDOW_UTIL_H_
diff --git a/chromium/ui/wm/core/window_util_unittest.cc b/chromium/ui/wm/core/window_util_unittest.cc
new file mode 100644
index 00000000000..35be2259179
--- /dev/null
+++ b/chromium/ui/wm/core/window_util_unittest.cc
@@ -0,0 +1,52 @@
+// 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/wm/core/window_util.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_tree_owner.h"
+
+namespace wm {
+
+typedef aura::test::AuraTestBase WindowUtilTest;
+
+// Test if the recreate layers does not recreate layers that have
+// already been acquired.
+TEST_F(WindowUtilTest, RecreateLayers) {
+ scoped_ptr<aura::Window> window1(
+ aura::test::CreateTestWindowWithId(0, NULL));
+ scoped_ptr<aura::Window> window11(
+ aura::test::CreateTestWindowWithId(1, window1.get()));
+ scoped_ptr<aura::Window> window12(
+ aura::test::CreateTestWindowWithId(2, window1.get()));
+
+ ASSERT_EQ(2u, window1->layer()->children().size());
+
+ scoped_ptr<ui::Layer> acquired(window11->AcquireLayer());
+ EXPECT_TRUE(acquired.get());
+ EXPECT_EQ(acquired.get(), window11->layer());
+
+ scoped_ptr<ui::LayerTreeOwner> tree =
+ wm::RecreateLayers(window1.get());
+
+ // The detached layer should not have the layer that has
+ // already been detached.
+ ASSERT_EQ(1u, tree->root()->children().size());
+ // Child layer is new instance.
+ EXPECT_NE(window11->layer(), tree->root()->children()[0]);
+ EXPECT_NE(window12->layer(), tree->root()->children()[0]);
+
+ // The original window should have both.
+ ASSERT_EQ(2u, window1->layer()->children().size());
+ EXPECT_EQ(window11->layer(), window1->layer()->children()[0]);
+ EXPECT_EQ(window12->layer(), window1->layer()->children()[1]);
+
+ // Delete the window before the acquired layer is deleted.
+ window11.reset();
+}
+} // namespace wm
diff --git a/chromium/ui/wm/core/wm_core_switches.cc b/chromium/ui/wm/core/wm_core_switches.cc
new file mode 100644
index 00000000000..12fbfcca9df
--- /dev/null
+++ b/chromium/ui/wm/core/wm_core_switches.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/wm_core_switches.h"
+
+#include "base/command_line.h"
+
+namespace wm {
+namespace switches {
+
+// If present animations are disabled.
+const char kWindowAnimationsDisabled[] = "wm-window-animations-disabled";
+
+} // namespace switches
+} // namespace wm
diff --git a/chromium/ui/wm/core/wm_core_switches.h b/chromium/ui/wm/core/wm_core_switches.h
new file mode 100644
index 00000000000..05658d6abbb
--- /dev/null
+++ b/chromium/ui/wm/core/wm_core_switches.h
@@ -0,0 +1,24 @@
+// 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_WM_CORE_WM_CORE_SWITCHES_H_
+#define UI_WM_CORE_WM_CORE_SWITCHES_H_
+
+#include "build/build_config.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+namespace switches {
+
+// Note: If you add a switch, consider if it needs to be copied to a subsequent
+// command line if the process executes a new copy of itself. (For example,
+// see chromeos::LoginUtil::GetOffTheRecordCommandLine().)
+
+// Please keep alphabetized.
+WM_EXPORT extern const char kWindowAnimationsDisabled[];
+
+} // namespace switches
+} // namespace wm
+
+#endif // UI_WM_CORE_WM_CORE_SWITCHES_H_
diff --git a/chromium/ui/wm/core/wm_state.cc b/chromium/ui/wm/core/wm_state.cc
new file mode 100644
index 00000000000..6d580863394
--- /dev/null
+++ b/chromium/ui/wm/core/wm_state.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/core/wm_state.h"
+
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/wm/core/transient_window_controller.h"
+#include "ui/wm/core/transient_window_stacking_client.h"
+
+namespace wm {
+
+WMState::WMState()
+ : window_stacking_client_(new TransientWindowStackingClient),
+ transient_window_client_(new TransientWindowController) {
+ aura::client::SetWindowStackingClient(window_stacking_client_.get());
+ aura::client::SetTransientWindowClient(transient_window_client_.get());
+}
+
+WMState::~WMState() {
+ if (aura::client::GetWindowStackingClient() == window_stacking_client_.get())
+ aura::client::SetWindowStackingClient(NULL);
+
+ if (aura::client::GetTransientWindowClient() ==
+ transient_window_client_.get()) {
+ aura::client::SetTransientWindowClient(NULL);
+ }
+}
+
+} // namespace wm
diff --git a/chromium/ui/wm/core/wm_state.h b/chromium/ui/wm/core/wm_state.h
new file mode 100644
index 00000000000..289c9dac5b5
--- /dev/null
+++ b/chromium/ui/wm/core/wm_state.h
@@ -0,0 +1,32 @@
+// 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_WM_CORE_WM_STATE_H_
+#define UI_WM_CORE_WM_STATE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/wm/wm_export.h"
+
+namespace wm {
+
+class TransientWindowController;
+class TransientWindowStackingClient;
+
+// Installs state needed by the window manager.
+class WM_EXPORT WMState {
+ public:
+ WMState();
+ ~WMState();
+
+ // WindowStackingClient:
+ private:
+ scoped_ptr<TransientWindowStackingClient> window_stacking_client_;
+ scoped_ptr<TransientWindowController> transient_window_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(WMState);
+};
+
+} // namespace wm
+
+#endif // UI_WM_CORE_WM_STATE_H_
diff --git a/chromium/ui/wm/public/DEPS b/chromium/ui/wm/public/DEPS
new file mode 100644
index 00000000000..1e9f2486d35
--- /dev/null
+++ b/chromium/ui/wm/public/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+ui/base/dragdrop/drag_drop_types.h",
+]
+
+specific_include_rules = {
+ "drag_drop_client.h": [
+ "+ui/base/dragdrop/drag_drop_types.h",
+ ],
+}
diff --git a/chromium/ui/wm/public/activation_change_observer.cc b/chromium/ui/wm/public/activation_change_observer.cc
new file mode 100644
index 00000000000..7fcbb7ae836
--- /dev/null
+++ b/chromium/ui/wm/public/activation_change_observer.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/activation_change_observer.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationChangeObserver*)
+
+namespace aura {
+namespace client {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ ActivationChangeObserver*, kActivationChangeObserverKey, NULL);
+
+void SetActivationChangeObserver(
+ Window* window,
+ ActivationChangeObserver* observer) {
+ window->SetProperty(kActivationChangeObserverKey, observer);
+}
+
+ActivationChangeObserver* GetActivationChangeObserver(Window* window) {
+ return window ? window->GetProperty(kActivationChangeObserverKey) : NULL;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/activation_change_observer.h b/chromium/ui/wm/public/activation_change_observer.h
new file mode 100644
index 00000000000..68d5b8a742a
--- /dev/null
+++ b/chromium/ui/wm/public/activation_change_observer.h
@@ -0,0 +1,45 @@
+// 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_WM_PUBLIC_ACTIVATION_CHANGE_OBSERVER_H_
+#define UI_WM_PUBLIC_ACTIVATION_CHANGE_OBSERVER_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+class Window;
+
+namespace client {
+
+class AURA_EXPORT ActivationChangeObserver {
+ public:
+ // Called when |active| gains focus, or there is no active window
+ // (|active| is NULL in this case.) |old_active| refers to the
+ // previous active window or NULL if there was no previously active
+ // window.
+ virtual void OnWindowActivated(Window* gained_active,
+ Window* lost_active) = 0;
+
+ // Called when during window activation the currently active window is
+ // selected for activation. This can happen when a window requested for
+ // activation cannot be activated because a system modal window is active.
+ virtual void OnAttemptToReactivateWindow(aura::Window* request_active,
+ aura::Window* actual_active) {}
+
+ protected:
+ virtual ~ActivationChangeObserver() {}
+};
+
+// Gets/Sets the ActivationChangeObserver for a specific window. This observer
+// is notified after the ActivationClient notifies all registered observers.
+AURA_EXPORT void SetActivationChangeObserver(
+ Window* window,
+ ActivationChangeObserver* observer);
+AURA_EXPORT ActivationChangeObserver* GetActivationChangeObserver(
+ Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_ACTIVATION_CHANGE_OBSERVER_H_
diff --git a/chromium/ui/wm/public/activation_client.cc b/chromium/ui/wm/public/activation_client.cc
new file mode 100644
index 00000000000..6a475541e66
--- /dev/null
+++ b/chromium/ui/wm/public/activation_client.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/activation_client.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, aura::Window*)
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationClient*)
+
+namespace aura {
+namespace client {
+
+DEFINE_WINDOW_PROPERTY_KEY(
+ ActivationClient*, kRootWindowActivationClientKey, NULL);
+DEFINE_WINDOW_PROPERTY_KEY(bool, kHideOnDeactivate, false);
+
+void SetActivationClient(Window* root_window, ActivationClient* client) {
+ root_window->SetProperty(kRootWindowActivationClientKey, client);
+}
+
+ActivationClient* GetActivationClient(Window* root_window) {
+ return root_window ?
+ root_window->GetProperty(kRootWindowActivationClientKey) : NULL;
+}
+
+void SetHideOnDeactivate(Window* window, bool hide_on_deactivate) {
+ window->SetProperty(kHideOnDeactivate, hide_on_deactivate);
+}
+
+bool GetHideOnDeactivate(Window* window) {
+ return window->GetProperty(kHideOnDeactivate);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/activation_client.h b/chromium/ui/wm/public/activation_client.h
new file mode 100644
index 00000000000..fc351319bc2
--- /dev/null
+++ b/chromium/ui/wm/public/activation_client.h
@@ -0,0 +1,77 @@
+// 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_WM_PUBLIC_ACTIVATION_CLIENT_H_
+#define UI_WM_PUBLIC_ACTIVATION_CLIENT_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace ui {
+class Event;
+}
+
+namespace aura {
+class Window;
+
+namespace client {
+class ActivationChangeObserver;
+
+// An interface implemented by an object that manages window activation.
+class AURA_EXPORT ActivationClient {
+ public:
+ // Adds/Removes ActivationChangeObservers.
+ virtual void AddObserver(ActivationChangeObserver* observer) = 0;
+ virtual void RemoveObserver(ActivationChangeObserver* observer) = 0;
+
+ // Activates |window|. If |window| is NULL, nothing happens.
+ virtual void ActivateWindow(Window* window) = 0;
+
+ // Deactivates |window|. What (if anything) is activated next is up to the
+ // client. If |window| is NULL, nothing happens.
+ virtual void DeactivateWindow(Window* window) = 0;
+
+ // Retrieves the active window, or NULL if there is none.
+ virtual Window* GetActiveWindow() = 0;
+
+ // Retrieves the activatable window for |window|, or NULL if there is none.
+ // Note that this is often but not always the toplevel window (see
+ // GetToplevelWindow() below), as the toplevel window may not be activatable
+ // (for example it may be blocked by a modal transient, or some other
+ // condition).
+ virtual Window* GetActivatableWindow(Window* window) = 0;
+
+ // Retrieves the toplevel window for |window|, or NULL if there is none.
+ virtual Window* GetToplevelWindow(Window* window) = 0;
+
+ // Invoked prior to |window| getting focus as a result of the |event|. |event|
+ // may be NULL. Returning false blocks |window| from getting focus.
+ virtual bool OnWillFocusWindow(Window* window, const ui::Event* event) = 0;
+
+ // Returns true if |window| can be activated, false otherwise. If |window| has
+ // a modal child it can not be activated.
+ virtual bool CanActivateWindow(Window* window) const = 0;
+
+ protected:
+ virtual ~ActivationClient() {}
+};
+
+// Sets/Gets the activation client on the root Window.
+AURA_EXPORT void SetActivationClient(Window* root_window,
+ ActivationClient* client);
+AURA_EXPORT ActivationClient* GetActivationClient(Window* root_window);
+
+// Some types of transient window are only visible when active.
+// The transient parents of these windows may have visual appearance properties
+// that differ from transient parents that can be deactivated.
+// The presence of this property implies these traits.
+// TODO(beng): currently the UI framework (views) implements the actual
+// close-on-deactivate component of this feature but it should be
+// possible to implement in the aura client.
+AURA_EXPORT void SetHideOnDeactivate(Window* window, bool hide_on_deactivate);
+AURA_EXPORT bool GetHideOnDeactivate(Window* window);
+
+} // namespace clients
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_ACTIVATION_CLIENT_H_
diff --git a/chromium/ui/wm/public/activation_delegate.cc b/chromium/ui/wm/public/activation_delegate.cc
new file mode 100644
index 00000000000..2a9bbc951d7
--- /dev/null
+++ b/chromium/ui/wm/public/activation_delegate.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/activation_delegate.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationDelegate*)
+
+namespace aura {
+namespace client {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ ActivationDelegate*, kActivationDelegateKey, NULL);
+
+void SetActivationDelegate(Window* window, ActivationDelegate* delegate) {
+ window->SetProperty(kActivationDelegateKey, delegate);
+}
+
+ActivationDelegate* GetActivationDelegate(Window* window) {
+ return window->GetProperty(kActivationDelegateKey);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/activation_delegate.h b/chromium/ui/wm/public/activation_delegate.h
new file mode 100644
index 00000000000..3c5b3aeb87c
--- /dev/null
+++ b/chromium/ui/wm/public/activation_delegate.h
@@ -0,0 +1,37 @@
+// 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_WM_PUBLIC_ACTIVATION_DELEGATE_H_
+#define UI_WM_PUBLIC_ACTIVATION_DELEGATE_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace ui {
+class Event;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+// An interface implemented by an object that configures and responds to changes
+// to a window's activation state.
+class AURA_EXPORT ActivationDelegate {
+ public:
+ // Returns true if the window should be activated.
+ virtual bool ShouldActivate() const = 0;
+
+ protected:
+ virtual ~ActivationDelegate() {}
+};
+
+// Sets/Gets the ActivationDelegate on the Window. No ownership changes.
+AURA_EXPORT void SetActivationDelegate(Window* window,
+ ActivationDelegate* delegate);
+AURA_EXPORT ActivationDelegate* GetActivationDelegate(Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_ACTIVATION_DELEGATE_H_
diff --git a/chromium/ui/wm/public/animation_host.cc b/chromium/ui/wm/public/animation_host.cc
new file mode 100644
index 00000000000..0d90f9c6a6b
--- /dev/null
+++ b/chromium/ui/wm/public/animation_host.cc
@@ -0,0 +1,28 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/animation_host.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::AnimationHost*)
+
+namespace aura {
+namespace client {
+
+DEFINE_WINDOW_PROPERTY_KEY(AnimationHost*, kRootWindowAnimationHostKey, NULL);
+
+void SetAnimationHost(Window* window, AnimationHost* animation_host) {
+ DCHECK(window);
+ window->SetProperty(kRootWindowAnimationHostKey, animation_host);
+}
+
+AnimationHost* GetAnimationHost(Window* window) {
+ DCHECK(window);
+ return window->GetProperty(kRootWindowAnimationHostKey);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/animation_host.h b/chromium/ui/wm/public/animation_host.h
new file mode 100644
index 00000000000..71f9f4d72b6
--- /dev/null
+++ b/chromium/ui/wm/public/animation_host.h
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_WM_PUBLIC_ANIMATION_HOST_H_
+#define UI_WM_PUBLIC_ANIMATION_HOST_H_
+
+#include "base/compiler_specific.h"
+#include "ui/aura/aura_export.h"
+
+namespace gfx {
+class Vector2d;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+// Interface for top level window host of animation. Communicates additional
+// bounds required for animation as well as animation completion for deferring
+// window closes on hide.
+class AURA_EXPORT AnimationHost {
+ public:
+ // Ensure the host window is at least this large so that transitions have
+ // sufficient space.
+ // The |top_left_delta| parameter contains the offset to be subtracted from
+ // the window bounds for the top left corner.
+ // The |bottom_right_delta| parameter contains the offset to be added to the
+ // window bounds for the bottom right.
+ virtual void SetHostTransitionOffsets(
+ const gfx::Vector2d& top_left_delta,
+ const gfx::Vector2d& bottom_right_delta) = 0;
+
+ // Called after the window has faded out on a hide.
+ virtual void OnWindowHidingAnimationCompleted() = 0;
+
+ protected:
+ virtual ~AnimationHost() {}
+};
+
+AURA_EXPORT void SetAnimationHost(Window* window,
+ AnimationHost* animation_host);
+AURA_EXPORT AnimationHost* GetAnimationHost(Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_ANIMATION_HOST_H_
diff --git a/chromium/ui/wm/public/dispatcher_client.cc b/chromium/ui/wm/public/dispatcher_client.cc
new file mode 100644
index 00000000000..e3be7ca848b
--- /dev/null
+++ b/chromium/ui/wm/public/dispatcher_client.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/dispatcher_client.h"
+
+#include "base/callback.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DispatcherClient*);
+
+namespace aura {
+namespace client {
+
+DispatcherRunLoop::DispatcherRunLoop(DispatcherClient* client,
+ base::MessagePumpDispatcher* dispatcher) {
+ client->PrepareNestedLoopClosures(dispatcher, &run_closure_, &quit_closure_);
+}
+
+DispatcherRunLoop::~DispatcherRunLoop() {
+}
+
+void DispatcherRunLoop::Run() {
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
+ run_closure_.Run();
+}
+
+base::Closure DispatcherRunLoop::QuitClosure() {
+ return quit_closure_;
+}
+
+void DispatcherRunLoop::Quit() {
+ quit_closure_.Run();
+}
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(DispatcherClient*, kDispatcherClientKey, NULL);
+
+void SetDispatcherClient(Window* root_window, DispatcherClient* client) {
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ root_window->SetProperty(kDispatcherClientKey, client);
+}
+
+DispatcherClient* GetDispatcherClient(Window* root_window) {
+ if (root_window)
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ return root_window ? root_window->GetProperty(kDispatcherClientKey) : NULL;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/dispatcher_client.h b/chromium/ui/wm/public/dispatcher_client.h
new file mode 100644
index 00000000000..a301e92dd55
--- /dev/null
+++ b/chromium/ui/wm/public/dispatcher_client.h
@@ -0,0 +1,59 @@
+// 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_WM_PUBLIC_DISPATCHER_CLIENT_H_
+#define UI_WM_PUBLIC_DISPATCHER_CLIENT_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+class Window;
+namespace client {
+
+class DispatcherClient;
+
+// A base::RunLoop like object for running a nested message-loop with a
+// specified DispatcherClient and a MessagePumpDispatcher.
+class AURA_EXPORT DispatcherRunLoop {
+ public:
+ DispatcherRunLoop(DispatcherClient* client,
+ base::MessagePumpDispatcher* dispatcher);
+ ~DispatcherRunLoop();
+
+ void Run();
+ base::Closure QuitClosure();
+ void Quit();
+
+ private:
+ base::Closure run_closure_;
+ base::Closure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(DispatcherRunLoop);
+};
+
+// An interface implemented by an object which handles nested dispatchers.
+class AURA_EXPORT DispatcherClient {
+ public:
+ virtual ~DispatcherClient() {}
+
+ protected:
+ friend class DispatcherRunLoop;
+
+ virtual void PrepareNestedLoopClosures(
+ base::MessagePumpDispatcher* dispatcher,
+ base::Closure* run_closure,
+ base::Closure* quit_closure) = 0;
+};
+
+AURA_EXPORT void SetDispatcherClient(Window* root_window,
+ DispatcherClient* client);
+AURA_EXPORT DispatcherClient* GetDispatcherClient(Window* root_window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_DISPATCHER_CLIENT_H_
diff --git a/chromium/ui/wm/public/drag_drop_client.cc b/chromium/ui/wm/public/drag_drop_client.cc
new file mode 100644
index 00000000000..c452f9e0318
--- /dev/null
+++ b/chromium/ui/wm/public/drag_drop_client.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/drag_drop_client.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropClient*)
+
+namespace aura {
+namespace client {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ DragDropClient*, kRootWindowDragDropClientKey, NULL);
+
+void SetDragDropClient(Window* root_window, DragDropClient* client) {
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ root_window->SetProperty(kRootWindowDragDropClientKey, client);
+}
+
+DragDropClient* GetDragDropClient(Window* root_window) {
+ if (root_window)
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ return root_window ?
+ root_window->GetProperty(kRootWindowDragDropClientKey) : NULL;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/drag_drop_client.h b/chromium/ui/wm/public/drag_drop_client.h
new file mode 100644
index 00000000000..62a2355b105
--- /dev/null
+++ b/chromium/ui/wm/public/drag_drop_client.h
@@ -0,0 +1,62 @@
+// 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_WM_PUBLIC_DRAG_DROP_CLIENT_H_
+#define UI_WM_PUBLIC_DRAG_DROP_CLIENT_H_
+
+#include "ui/aura/aura_export.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+class LocatedEvent;
+class OSExchangeData;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+// An interface implemented by an object that controls a drag and drop session.
+class AURA_EXPORT DragDropClient {
+ public:
+ virtual ~DragDropClient() {}
+
+ // Initiates a drag and drop session. Returns the drag operation that was
+ // applied at the end of the drag drop session. |root_location| is in the
+ // root Window's coordinate system.
+ virtual int StartDragAndDrop(const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) = 0;
+
+ // Called when mouse is dragged during a drag and drop.
+ virtual void DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) = 0;
+
+ // Called when mouse is released during a drag and drop.
+ virtual void Drop(aura::Window* target,
+ const ui::LocatedEvent& event) = 0;
+
+ // Called when a drag and drop session is cancelled.
+ virtual void DragCancel() = 0;
+
+ // Returns true if a drag and drop session is in progress.
+ virtual bool IsDragDropInProgress() = 0;
+};
+
+AURA_EXPORT void SetDragDropClient(Window* root_window,
+ DragDropClient* client);
+AURA_EXPORT DragDropClient* GetDragDropClient(Window* root_window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_DRAG_DROP_CLIENT_H_
diff --git a/chromium/ui/wm/public/drag_drop_delegate.cc b/chromium/ui/wm/public/drag_drop_delegate.cc
new file mode 100644
index 00000000000..6380f963fbf
--- /dev/null
+++ b/chromium/ui/wm/public/drag_drop_delegate.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/drag_drop_delegate.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropDelegate*)
+
+namespace aura {
+namespace client {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ DragDropDelegate*, kDragDropDelegateKey, NULL);
+
+void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) {
+ window->SetProperty(kDragDropDelegateKey, delegate);
+}
+
+DragDropDelegate* GetDragDropDelegate(Window* window) {
+ return window->GetProperty(kDragDropDelegateKey);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/drag_drop_delegate.h b/chromium/ui/wm/public/drag_drop_delegate.h
new file mode 100644
index 00000000000..50f6c267686
--- /dev/null
+++ b/chromium/ui/wm/public/drag_drop_delegate.h
@@ -0,0 +1,51 @@
+// 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_WM_PUBLIC_DRAG_DROP_DELEGATE_H_
+#define UI_WM_PUBLIC_DRAG_DROP_DELEGATE_H_
+
+#include "ui/aura/aura_export.h"
+
+namespace ui {
+class DropTargetEvent;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+// Delegate interface for drag and drop actions on aura::Window.
+class AURA_EXPORT DragDropDelegate {
+ public:
+ // OnDragEntered is invoked when the mouse enters this window during a drag &
+ // drop session. This is immediately followed by an invocation of
+ // OnDragUpdated, and eventually one of OnDragExited or OnPerformDrop.
+ virtual void OnDragEntered(const ui::DropTargetEvent& event) = 0;
+
+ // Invoked during a drag and drop session while the mouse is over the window.
+ // This should return a bitmask of the DragDropTypes::DragOperation supported
+ // based on the location of the event. Return 0 to indicate the drop should
+ // not be accepted.
+ virtual int OnDragUpdated(const ui::DropTargetEvent& event) = 0;
+
+ // Invoked during a drag and drop session when the mouse exits the window, or
+ // when the drag session was canceled and the mouse was over the window.
+ virtual void OnDragExited() = 0;
+
+ // Invoked during a drag and drop session when OnDragUpdated returns a valid
+ // operation and the user release the mouse.
+ virtual int OnPerformDrop(const ui::DropTargetEvent& event) = 0;
+
+ protected:
+ virtual ~DragDropDelegate() {}
+};
+
+AURA_EXPORT void SetDragDropDelegate(Window* window,
+ DragDropDelegate* delegate);
+AURA_EXPORT DragDropDelegate* GetDragDropDelegate(Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_DRAG_DROP_DELEGATE_H_
diff --git a/chromium/ui/wm/public/scoped_tooltip_disabler.cc b/chromium/ui/wm/public/scoped_tooltip_disabler.cc
new file mode 100644
index 00000000000..45a39ca6a9e
--- /dev/null
+++ b/chromium/ui/wm/public/scoped_tooltip_disabler.cc
@@ -0,0 +1,43 @@
+// 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/wm/public/scoped_tooltip_disabler.h"
+
+#include "ui/aura/window.h"
+#include "ui/wm/public/tooltip_client.h"
+
+namespace aura {
+namespace client {
+
+ScopedTooltipDisabler::ScopedTooltipDisabler(aura::Window* window)
+ : root_(window ? window->GetRootWindow() : NULL) {
+ if (root_) {
+ root_->AddObserver(this);
+ TooltipClient* client = GetTooltipClient(root_);
+ if (client)
+ client->SetTooltipsEnabled(false);
+ }
+}
+
+ScopedTooltipDisabler::~ScopedTooltipDisabler() {
+ EnableTooltips();
+}
+
+void ScopedTooltipDisabler::EnableTooltips() {
+ if (!root_)
+ return;
+ TooltipClient* client = GetTooltipClient(root_);
+ if (client)
+ client->SetTooltipsEnabled(true);
+ root_->RemoveObserver(this);
+ root_ = NULL;
+}
+
+void ScopedTooltipDisabler::OnWindowDestroying(aura::Window* window) {
+ EnableTooltips();
+}
+
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/scoped_tooltip_disabler.h b/chromium/ui/wm/public/scoped_tooltip_disabler.h
new file mode 100644
index 00000000000..0fd3e113eee
--- /dev/null
+++ b/chromium/ui/wm/public/scoped_tooltip_disabler.h
@@ -0,0 +1,39 @@
+// 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_WM_PUBLIC_SCOPED_TOOLTIP_DISABLER_H_
+#define UI_WM_PUBLIC_SCOPED_TOOLTIP_DISABLER_H_
+
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+namespace client {
+
+// Use to temporarily disable tooltips.
+class AURA_EXPORT ScopedTooltipDisabler : aura::WindowObserver {
+ public:
+ // Disables tooltips on |window| (does nothing if |window| is NULL). Tooltips
+ // are reenabled from the destructor when there are no most outstanding
+ // ScopedTooltipDisablers for |window|.
+ explicit ScopedTooltipDisabler(aura::Window* window);
+ virtual ~ScopedTooltipDisabler();
+
+ private:
+ // Reenables the tooltips on the TooltipClient.
+ void EnableTooltips();
+
+ // aura::WindowObserver:
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // The RootWindow to disable Tooltips on; NULL if the Window passed to the
+ // constructor was not in a root or the root has been destroyed.
+ aura::Window* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTooltipDisabler);
+};
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_SCOPED_TOOLTIP_DISABLER_H_
diff --git a/chromium/ui/wm/public/tooltip_client.cc b/chromium/ui/wm/public/tooltip_client.cc
new file mode 100644
index 00000000000..844cca51d1b
--- /dev/null
+++ b/chromium/ui/wm/public/tooltip_client.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/tooltip_client.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::TooltipClient*)
+DECLARE_WINDOW_PROPERTY_TYPE(base::string16*)
+DECLARE_WINDOW_PROPERTY_TYPE(void**)
+
+namespace aura {
+namespace client {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ TooltipClient*, kRootWindowTooltipClientKey, NULL);
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(base::string16*, kTooltipTextKey, NULL);
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(void*, kTooltipIdKey, NULL);
+
+void SetTooltipClient(Window* root_window, TooltipClient* client) {
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ root_window->SetProperty(kRootWindowTooltipClientKey, client);
+}
+
+TooltipClient* GetTooltipClient(Window* root_window) {
+ if (root_window)
+ DCHECK_EQ(root_window->GetRootWindow(), root_window);
+ return root_window ?
+ root_window->GetProperty(kRootWindowTooltipClientKey) : NULL;
+}
+
+void SetTooltipText(Window* window, base::string16* tooltip_text) {
+ window->SetProperty(kTooltipTextKey, tooltip_text);
+}
+
+void SetTooltipId(Window* window, void* id) {
+ window->SetProperty(kTooltipIdKey, id);
+}
+
+const base::string16 GetTooltipText(Window* window) {
+ base::string16* string_ptr = window->GetProperty(kTooltipTextKey);
+ return string_ptr ? *string_ptr : base::string16();
+}
+
+const void* GetTooltipId(Window* window) {
+ return window->GetProperty(kTooltipIdKey);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/tooltip_client.h b/chromium/ui/wm/public/tooltip_client.h
new file mode 100644
index 00000000000..f2b97cdd0f4
--- /dev/null
+++ b/chromium/ui/wm/public/tooltip_client.h
@@ -0,0 +1,51 @@
+// 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_WM_PUBLIC_TOOLTIP_CLIENT_H_
+#define UI_WM_PUBLIC_TOOLTIP_CLIENT_H_
+
+#include "ui/aura/aura_export.h"
+#include "ui/gfx/font.h"
+
+namespace aura {
+class Window;
+namespace client {
+
+class ScopedTooltipDisabler;
+
+class AURA_EXPORT TooltipClient {
+ public:
+ // Informs the shell tooltip manager of change in tooltip for window |target|.
+ virtual void UpdateTooltip(Window* target) = 0;
+
+ // Sets the time after which the tooltip is hidden for Window |target|. If
+ // |timeout_in_ms| is <= 0, the tooltip is shown indefinitely.
+ virtual void SetTooltipShownTimeout(Window* target, int timeout_in_ms) = 0;
+
+ protected:
+ // Enables/Disables tooltips. This is treated as a reference count. Consumers
+ // must use ScopedTooltipDisabler to enable/disabled tooltips.
+ virtual void SetTooltipsEnabled(bool enable) = 0;
+
+ private:
+ friend class ScopedTooltipDisabler;
+};
+
+AURA_EXPORT void SetTooltipClient(Window* root_window,
+ TooltipClient* client);
+AURA_EXPORT TooltipClient* GetTooltipClient(Window* root_window);
+
+// Sets the text for the tooltip. The id is used to determine uniqueness when
+// the text does not change. For example, if the tooltip text does not change,
+// but the id does then the position of the tooltip is updated.
+AURA_EXPORT void SetTooltipText(Window* window,
+ base::string16* tooltip_text);
+AURA_EXPORT void SetTooltipId(Window* window, void* id);
+AURA_EXPORT const base::string16 GetTooltipText(Window* window);
+AURA_EXPORT const void* GetTooltipId(Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_TOOLTIP_CLIENT_H_
diff --git a/chromium/ui/wm/public/transient_window_client.cc b/chromium/ui/wm/public/transient_window_client.cc
new file mode 100644
index 00000000000..aab8e518c5f
--- /dev/null
+++ b/chromium/ui/wm/public/transient_window_client.cc
@@ -0,0 +1,25 @@
+// 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/wm/public/transient_window_client.h"
+
+namespace aura {
+namespace client {
+
+namespace {
+
+TransientWindowClient* instance = NULL;
+
+} // namespace
+
+void SetTransientWindowClient(TransientWindowClient* client) {
+ instance = client;
+}
+
+TransientWindowClient* GetTransientWindowClient() {
+ return instance;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/transient_window_client.h b/chromium/ui/wm/public/transient_window_client.h
new file mode 100644
index 00000000000..2086100b88f
--- /dev/null
+++ b/chromium/ui/wm/public/transient_window_client.h
@@ -0,0 +1,47 @@
+// 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_WM_PUBLIC_TRANSIENT_WINDOW_CLIENT_H_
+#define UI_WM_PUBLIC_TRANSIENT_WINDOW_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+
+class Window;
+
+namespace client {
+
+// TransientWindowClient is used to add or remove transient windows. Transient
+// children get the following behavior:
+// . The transient parent destroys any transient children when it is
+// destroyed. This means a transient child is destroyed if either its parent
+// or transient parent is destroyed.
+// . If a transient child and its transient parent share the same parent, then
+// transient children are always ordered above the transient parent.
+// Transient windows are typically used for popups and menus.
+// TODO(sky): nuke this class and replace with calls to TransientWindowManager.
+// This is temporary until we start moving to ui/wm.
+class AURA_EXPORT TransientWindowClient {
+ public:
+ virtual void AddTransientChild(Window* parent, Window* child) = 0;
+ virtual void RemoveTransientChild(Window* parent, Window* child) = 0;
+ virtual Window* GetTransientParent(Window* window) = 0;
+ virtual const Window* GetTransientParent(const Window* window) = 0;
+
+ protected:
+ virtual ~TransientWindowClient() {}
+};
+
+// Sets/gets the TransientWindowClient. This does *not* take ownership of
+// |client|. It is assumed the caller will invoke SetTransientWindowClient(NULL)
+// before deleting |client|.
+AURA_EXPORT void SetTransientWindowClient(TransientWindowClient* client);
+AURA_EXPORT TransientWindowClient* GetTransientWindowClient();
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_TRANSIENT_WINDOW_CLIENT_H_
diff --git a/chromium/ui/wm/public/window_move_client.cc b/chromium/ui/wm/public/window_move_client.cc
new file mode 100644
index 00000000000..44ccca965c6
--- /dev/null
+++ b/chromium/ui/wm/public/window_move_client.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/wm/public/window_move_client.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+
+DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowMoveClient*)
+
+namespace aura {
+namespace client {
+
+// A property key to store a client that handles window moves.
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(
+ WindowMoveClient*, kWindowMoveClientKey, NULL);
+
+void SetWindowMoveClient(Window* window, WindowMoveClient* client) {
+ window->SetProperty(kWindowMoveClientKey, client);
+}
+
+WindowMoveClient* GetWindowMoveClient(Window* window) {
+ return window->GetProperty(kWindowMoveClientKey);
+}
+
+} // namespace client
+} // namespace aura
diff --git a/chromium/ui/wm/public/window_move_client.h b/chromium/ui/wm/public/window_move_client.h
new file mode 100644
index 00000000000..b8943d3eb37
--- /dev/null
+++ b/chromium/ui/wm/public/window_move_client.h
@@ -0,0 +1,56 @@
+// 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_WM_PUBLIC_WINDOW_MOVE_CLIENT_H_
+#define UI_WM_PUBLIC_WINDOW_MOVE_CLIENT_H_
+
+#include "ui/aura/aura_export.h"
+#include "ui/gfx/vector2d.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace aura {
+class Window;
+namespace client {
+
+enum WindowMoveResult {
+ MOVE_SUCCESSFUL, // Moving window was successful.
+ MOVE_CANCELED // Moving window was canceled.
+};
+
+enum WindowMoveSource {
+ WINDOW_MOVE_SOURCE_MOUSE,
+ WINDOW_MOVE_SOURCE_TOUCH,
+};
+
+// An interface implemented by an object that manages programatically keyed
+// window moving.
+class AURA_EXPORT WindowMoveClient {
+ public:
+ // Starts a nested message loop for moving the window. |drag_offset| is the
+ // offset from the window origin to the cursor when the drag was started.
+ // Returns MOVE_SUCCESSFUL if the move has completed successfully, or
+ // MOVE_CANCELED otherwise.
+ virtual WindowMoveResult RunMoveLoop(Window* window,
+ const gfx::Vector2d& drag_offset,
+ WindowMoveSource source) = 0;
+
+ // Ends a previously started move loop.
+ virtual void EndMoveLoop() = 0;
+
+ protected:
+ virtual ~WindowMoveClient() {}
+};
+
+// Sets/Gets the activation client for the specified window.
+AURA_EXPORT void SetWindowMoveClient(Window* window,
+ WindowMoveClient* client);
+AURA_EXPORT WindowMoveClient* GetWindowMoveClient(Window* window);
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_WM_PUBLIC_WINDOW_MOVE_CLIENT_H_
diff --git a/chromium/ui/wm/public/window_types.h b/chromium/ui/wm/public/window_types.h
new file mode 100644
index 00000000000..8a9f8b9f6b2
--- /dev/null
+++ b/chromium/ui/wm/public/window_types.h
@@ -0,0 +1,36 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_WM_PUBLIC_WINDOW_TYPES_H_
+#define UI_WM_PUBLIC_WINDOW_TYPES_H_
+
+namespace ui {
+namespace wm {
+
+// This isn't a property because it can't change after the window has been
+// initialized.
+enum WindowType {
+ WINDOW_TYPE_UNKNOWN = 0,
+
+ // Regular windows that should be laid out by the client.
+ WINDOW_TYPE_NORMAL,
+
+ // Miscellaneous windows that should not be laid out by the shell.
+ WINDOW_TYPE_POPUP,
+
+ // A window intended as a control. Not laid out by the shell.
+ WINDOW_TYPE_CONTROL,
+
+ // Always on top windows aligned to bottom right of screen.
+ WINDOW_TYPE_PANEL,
+
+ WINDOW_TYPE_MENU,
+
+ WINDOW_TYPE_TOOLTIP,
+};
+
+} // namespace wm
+} // namespace ui
+
+#endif // UI_WM_PUBLIC_WINDOW_TYPES_H_
diff --git a/chromium/ui/wm/wm.gyp b/chromium/ui/wm/wm.gyp
index 4a681c11fbb..10f1883c4e1 100644
--- a/chromium/ui/wm/wm.gyp
+++ b/chromium/ui/wm/wm.gyp
@@ -8,17 +8,140 @@
},
'targets': [
{
+ 'target_name': 'wm',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../aura/aura.gyp:aura',
+ '../compositor/compositor.gyp:compositor',
+ '../events/events.gyp:events',
+ '../events/events.gyp:events_base',
+ '../gfx/gfx.gyp:gfx_geometry',
+ '../gfx/gfx.gyp:gfx',
+ '../resources/ui_resources.gyp:ui_resources',
+ '../base/ui_base.gyp:ui_base',
+ ],
+ 'defines': [
+ 'WM_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'core/accelerator_delegate.h',
+ 'core/accelerator_filter.cc',
+ 'core/accelerator_filter.h',
+ 'core/base_focus_rules.h',
+ 'core/base_focus_rules.cc',
+ 'core/base_focus_rules.h',
+ 'core/capture_controller.cc',
+ 'core/capture_controller.h',
+ 'core/compound_event_filter.cc',
+ 'core/compound_event_filter.h',
+ 'core/cursor_manager.cc',
+ 'core/cursor_manager.h',
+ 'core/default_activation_client.cc',
+ 'core/default_activation_client.h',
+ 'core/easy_resize_window_targeter.cc',
+ 'core/easy_resize_window_targeter.h',
+ 'core/focus_controller.cc',
+ 'core/focus_controller.h',
+ 'core/focus_rules.h',
+ 'core/image_grid.cc',
+ 'core/image_grid.h',
+ 'core/input_method_event_filter.cc',
+ 'core/input_method_event_filter.h',
+ 'core/masked_window_targeter.cc',
+ 'core/masked_window_targeter.h',
+ 'core/native_cursor_manager.h',
+ 'core/native_cursor_manager_delegate.h',
+ 'core/nested_accelerator_dispatcher_linux.cc',
+ 'core/nested_accelerator_dispatcher_win.cc',
+ 'core/nested_accelerator_dispatcher.cc',
+ 'core/nested_accelerator_dispatcher.h',
+ 'core/nested_accelerator_delegate.h',
+ 'core/nested_accelerator_controller.cc',
+ 'core/nested_accelerator_controller.h',
+ 'core/shadow.cc',
+ 'core/shadow.h',
+ 'core/shadow_controller.cc',
+ 'core/shadow_controller.h',
+ 'core/shadow_types.cc',
+ 'core/shadow_types.h',
+ 'core/transient_window_controller.cc',
+ 'core/transient_window_controller.h',
+ 'core/transient_window_manager.cc',
+ 'core/transient_window_manager.h',
+ 'core/transient_window_observer.h',
+ 'core/transient_window_stacking_client.cc',
+ 'core/transient_window_stacking_client.h',
+ 'core/user_activity_detector.cc',
+ 'core/user_activity_detector.h',
+ 'core/user_activity_observer.h',
+ 'core/visibility_controller.cc',
+ 'core/visibility_controller.h',
+ 'core/window_animations.cc',
+ 'core/window_animations.h',
+ 'core/window_modality_controller.cc',
+ 'core/window_modality_controller.h',
+ 'core/window_util.cc',
+ 'core/window_util.h',
+ 'core/wm_core_switches.cc',
+ 'core/wm_core_switches.h',
+ 'core/wm_state.cc',
+ 'core/wm_state.h',
+ 'public/window_types.h',
+ 'wm_export.h',
+ ],
+ },
+ {
'target_name': 'wm_test_support',
'type': 'static_library',
'dependencies': [
'../../skia/skia.gyp:skia',
'../aura/aura.gyp:aura',
- '../views/views.gyp:views',
+ '../base/ui_base.gyp:ui_base',
+ '../events/events.gyp:events',
+ '../events/events.gyp:events_base',
],
'sources': [
'test/wm_test_helper.cc',
'test/wm_test_helper.h',
],
},
+ {
+ 'target_name': 'wm_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ '../aura/aura.gyp:aura',
+ '../aura/aura.gyp:aura_test_support',
+ '../base/ui_base.gyp:ui_base',
+ '../compositor/compositor.gyp:compositor',
+ '../events/events.gyp:events',
+ '../events/events.gyp:events_base',
+ '../gfx/gfx.gyp:gfx',
+ '../gfx/gfx.gyp:gfx_geometry',
+ 'wm',
+ 'wm_test_support',
+ ],
+ 'sources': [
+ 'test/run_all_unittests.cc',
+ 'core/compound_event_filter_unittest.cc',
+ 'core/cursor_manager_unittest.cc',
+ 'core/focus_controller_unittest.cc',
+ 'core/input_method_event_filter_unittest.cc',
+ 'core/image_grid_unittest.cc',
+ 'core/nested_accelerator_controller_unittest.cc',
+ 'core/shadow_controller_unittest.cc',
+ 'core/transient_window_manager_unittest.cc',
+ 'core/transient_window_stacking_client_unittest.cc',
+ 'core/user_activity_detector_unittest.cc',
+ 'core/visibility_controller_unittest.cc',
+ 'core/window_animations_unittest.cc',
+ 'core/window_util_unittest.cc',
+ ],
+ },
],
}
diff --git a/chromium/ui/wm/wm_export.h b/chromium/ui/wm/wm_export.h
new file mode 100644
index 00000000000..461d6934adb
--- /dev/null
+++ b/chromium/ui/wm/wm_export.h
@@ -0,0 +1,32 @@
+// 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_WM_WM_EXPORT_H_
+#define UI_WM_WM_EXPORT_H_
+
+// Defines WM_EXPORT so that functionality implemented by the WM module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(WM_IMPLEMENTATION)
+#define WM_EXPORT __declspec(dllexport)
+#else
+#define WM_EXPORT __declspec(dllimport)
+#endif // defined(WM_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(WM_IMPLEMENTATION)
+#define WM_EXPORT __attribute__((visibility("default")))
+#else
+#define WM_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define WM_EXPORT
+#endif
+
+#endif // UI_WM_WM_EXPORT_H_